summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS8
-rw-r--r--Documentation/ABI/testing/sysfs-driver-st12
-rw-r--r--Documentation/DocBook/device-drivers.tmpl84
-rw-r--r--Documentation/DocBook/media/Makefile6
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml2
-rw-r--r--Documentation/DocBook/media/dvb/examples.xml2
-rw-r--r--Documentation/DocBook/media/dvb/intro.xml2
-rw-r--r--Documentation/DocBook/media/v4l/capture.c.xml2
-rw-r--r--Documentation/DocBook/media/v4l/compat.xml2
-rw-r--r--Documentation/DocBook/media/v4l/io.xml10
-rw-r--r--Documentation/DocBook/media/v4l/v4l2.xml10
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-create-bufs.xml30
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enumstd.xml2
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml28
-rw-r--r--Documentation/DocBook/media_api.tmpl6
-rw-r--r--Documentation/IPMI.txt7
-rw-r--r--Documentation/RCU/Design/Requirements/2013-08-is-it-dead.pngbin0 -> 100825 bytes
-rw-r--r--Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg374
-rw-r--r--Documentation/RCU/Design/Requirements/RCUApplicability.svg237
-rw-r--r--Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg639
-rw-r--r--Documentation/RCU/Design/Requirements/Requirements.html2897
-rw-r--r--Documentation/RCU/Design/Requirements/Requirements.htmlx2741
-rwxr-xr-xDocumentation/RCU/Design/htmlqqz.sh108
-rw-r--r--Documentation/SubmittingPatches15
-rw-r--r--Documentation/acpi/i2c-muxes.txt58
-rw-r--r--Documentation/arm/Samsung/Bootloader-interface.txt5
-rw-r--r--Documentation/arm/keystone/Overview.txt18
-rw-r--r--Documentation/arm/keystone/knav-qmss.txt56
-rw-r--r--Documentation/arm/sunxi/README2
-rw-r--r--Documentation/arm64/silicon-errata.txt58
-rw-r--r--Documentation/block/null_blk.txt3
-rw-r--r--Documentation/device-mapper/verity.txt40
-rw-r--r--Documentation/devicetree/bindings/arm/amlogic.txt10
-rw-r--r--Documentation/devicetree/bindings/arm/apm/scu.txt17
-rw-r--r--Documentation/devicetree/bindings/arm/arm,scpi.txt188
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt162
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/brcm,nsp.txt34
-rw-r--r--Documentation/devicetree/bindings/arm/coherency-fabric.txt5
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt2
-rw-r--r--Documentation/devicetree/bindings/arm/fsl.txt16
-rw-r--r--Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/keystone/keystone.txt20
-rw-r--r--Documentation/devicetree/bindings/arm/l2c2x0.txt (renamed from Documentation/devicetree/bindings/arm/l2cc.txt)24
-rw-r--r--Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt20
-rw-r--r--Documentation/devicetree/bindings/arm/pmu.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/psci.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip.txt11
-rw-r--r--Documentation/devicetree/bindings/arm/samsung-boards.txt27
-rw-r--r--Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt69
-rw-r--r--Documentation/devicetree/bindings/arm/shmobile.txt10
-rw-r--r--Documentation/devicetree/bindings/arm/sunxi.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/uniphier/cache-uniphier.txt60
-rw-r--r--Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt4
-rw-r--r--Documentation/devicetree/bindings/ata/sata_rcar.txt1
-rw-r--r--Documentation/devicetree/bindings/board/fsl-board.txt (renamed from Documentation/devicetree/bindings/powerpc/fsl/board.txt)14
-rw-r--r--Documentation/devicetree/bindings/bus/sunxi-rsb.txt47
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,gcc.txt4
-rw-r--r--Documentation/devicetree/bindings/clock/qcom,mmcc.txt4
-rw-r--r--Documentation/devicetree/bindings/dma/ti-edma.txt10
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt8
-rw-r--r--Documentation/devicetree/bindings/hwmon/pwm-fan.txt29
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-davinci.txt6
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-imx.txt9
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-rcar.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt25
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-uniphier.txt25
-rw-r--r--Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt2
-rw-r--r--Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt34
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt (renamed from Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt)2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt1
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt74
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt16
-rw-r--r--Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt2
-rw-r--r--Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt20
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt8
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt6
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt4
-rw-r--r--Documentation/devicetree/bindings/mips/img/xilfpga.txt83
-rw-r--r--Documentation/devicetree/bindings/mmc/renesas,mmcif.txt1
-rw-r--r--Documentation/devicetree/bindings/mtd/partition.txt7
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt7
-rw-r--r--Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt6
-rw-r--r--Documentation/devicetree/bindings/pci/arm,juno-r1-pcie.txt10
-rw-r--r--Documentation/devicetree/bindings/pci/plda,xpressrich3-axi.txt12
-rw-r--r--Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt3
-rw-r--r--Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt (renamed from Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt)9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt80
-rw-r--r--Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt110
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt9
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt199
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt1
-rw-r--r--Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt3
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt1
-rw-r--r--Documentation/devicetree/bindings/power/pd-samsung.txt (renamed from Documentation/devicetree/bindings/arm/exynos/power_domain.txt)5
-rw-r--r--Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt20
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-berlin.txt17
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt42
-rw-r--r--Documentation/devicetree/bindings/pwm/pwm-sun4i.txt2
-rw-r--r--Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt26
-rw-r--r--Documentation/devicetree/bindings/soc/mediatek/scpsys.txt10
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt57
-rw-r--r--Documentation/devicetree/bindings/soc/rockchip/power_domain.txt46
-rw-r--r--Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt1
-rw-r--r--Documentation/devicetree/bindings/sound/ak4554.txt (renamed from Documentation/devicetree/bindings/sound/ak4554.c)0
-rw-r--r--Documentation/devicetree/bindings/thermal/rockchip-thermal.txt15
-rw-r--r--Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt14
-rw-r--r--Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt8
-rw-r--r--Documentation/devicetree/bindings/ufs/ufs-qcom.txt58
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt11
-rw-r--r--Documentation/devicetree/bindings/usb/dwc3.txt3
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt3
-rw-r--r--Documentation/dontdiff1
-rw-r--r--Documentation/dvb/README.dvb-usb4
-rw-r--r--Documentation/dvb/faq.txt2
-rwxr-xr-xDocumentation/dvb/get_dvb_firmware22
-rw-r--r--Documentation/dvb/readme.txt10
-rw-r--r--Documentation/edac.txt10
-rw-r--r--Documentation/email-clients.txt36
-rw-r--r--Documentation/features/seccomp/seccomp-filter/arch-support.txt2
-rw-r--r--Documentation/features/time/irq-time-acct/arch-support.txt2
-rw-r--r--Documentation/filesystems/Locking6
-rw-r--r--Documentation/filesystems/Makefile2
-rw-r--r--Documentation/filesystems/configfs/Makefile3
-rw-r--r--Documentation/filesystems/configfs/configfs.txt38
-rw-r--r--Documentation/filesystems/configfs/configfs_example_explicit.c483
-rw-r--r--Documentation/filesystems/overlayfs.txt3
-rw-r--r--Documentation/filesystems/porting17
-rw-r--r--Documentation/filesystems/proc.txt22
-rw-r--r--Documentation/filesystems/vfs.txt21
-rw-r--r--Documentation/hwmon/htu2146
-rw-r--r--Documentation/hwmon/ltc381561
-rw-r--r--Documentation/hwmon/scpi-hwmon33
-rw-r--r--Documentation/i2c/busses/i2c-i8013
-rw-r--r--Documentation/kbuild/Kconfig.recursion-issue-0157
-rw-r--r--Documentation/kbuild/Kconfig.recursion-issue-0263
-rw-r--r--Documentation/kbuild/Kconfig.select-break33
-rw-r--r--Documentation/kbuild/kconfig-language.txt161
-rw-r--r--Documentation/kernel-parameters.txt50
-rw-r--r--Documentation/leds/leds-class.txt13
-rw-r--r--Documentation/memory-barriers.txt12
-rw-r--r--Documentation/networking/can.txt2
-rw-r--r--Documentation/networking/e100.txt14
-rw-r--r--Documentation/networking/filter.txt6
-rw-r--r--Documentation/networking/ip-sysctl.txt2
-rw-r--r--Documentation/nvdimm/nvdimm.txt49
-rw-r--r--Documentation/printk-formats.txt6
-rw-r--r--Documentation/scsi/st.txt4
-rw-r--r--Documentation/spi/pxa2xx6
-rw-r--r--Documentation/sysctl/kernel.txt15
-rwxr-xr-xDocumentation/target/tcm_mod_builder.py17
-rw-r--r--Documentation/trace/events-msr.txt37
-rw-r--r--Documentation/trace/postprocess/decode_msr.py37
-rw-r--r--Documentation/video4linux/API.html2
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx4
-rw-r--r--Documentation/video4linux/fimc.txt6
-rw-r--r--Documentation/video4linux/omap4_camera.txt2
-rw-r--r--Documentation/video4linux/si4713.txt2
-rw-r--r--Documentation/video4linux/v4l2-pci-skeleton.c13
-rw-r--r--Documentation/virtual/kvm/api.txt41
-rw-r--r--Documentation/virtual/kvm/devices/vm.txt3
-rw-r--r--Documentation/virtual/kvm/mmu.txt4
-rw-r--r--MAINTAINERS402
-rw-r--r--Makefile6
-rw-r--r--arch/arc/Kconfig1
-rw-r--r--arch/arc/Makefile2
-rw-r--r--arch/arc/boot/dts/axs10x_mb.dtsi1
-rw-r--r--arch/arc/boot/dts/nsim_hs.dts3
-rw-r--r--arch/arc/configs/axs101_defconfig2
-rw-r--r--arch/arc/configs/axs103_defconfig2
-rw-r--r--arch/arc/configs/axs103_smp_defconfig2
-rw-r--r--arch/arc/configs/nsim_hs_defconfig2
-rw-r--r--arch/arc/configs/nsim_hs_smp_defconfig2
-rw-r--r--arch/arc/configs/nsimosci_hs_defconfig2
-rw-r--r--arch/arc/configs/nsimosci_hs_smp_defconfig2
-rw-r--r--arch/arc/configs/vdk_hs38_defconfig2
-rw-r--r--arch/arc/configs/vdk_hs38_smp_defconfig2
-rw-r--r--arch/arc/include/asm/cache.h2
-rw-r--r--arch/arc/include/asm/irqflags-arcv2.h3
-rw-r--r--arch/arc/include/asm/irqflags-compact.h2
-rw-r--r--arch/arc/include/asm/mach_desc.h4
-rw-r--r--arch/arc/include/asm/processor.h4
-rw-r--r--arch/arc/include/asm/smp.h4
-rw-r--r--arch/arc/include/asm/unwind.h4
-rw-r--r--arch/arc/kernel/ctx_sw.c2
-rw-r--r--arch/arc/kernel/ctx_sw_asm.S3
-rw-r--r--arch/arc/kernel/entry-arcv2.S19
-rw-r--r--arch/arc/kernel/entry-compact.S29
-rw-r--r--arch/arc/kernel/entry.S17
-rw-r--r--arch/arc/kernel/intc-arcv2.c15
-rw-r--r--arch/arc/kernel/irq.c33
-rw-r--r--arch/arc/kernel/mcip.c2
-rw-r--r--arch/arc/kernel/perf_event.c32
-rw-r--r--arch/arc/kernel/process.c9
-rw-r--r--arch/arc/kernel/setup.c1
-rw-r--r--arch/arc/kernel/smp.c8
-rw-r--r--arch/arc/kernel/unwind.c94
-rw-r--r--arch/arc/lib/memcpy-archs.S52
-rw-r--r--arch/arc/mm/highmem.c4
-rw-r--r--arch/arc/mm/init.c4
-rw-r--r--arch/arc/mm/tlb.c4
-rw-r--r--arch/arc/mm/tlbex.S6
-rw-r--r--arch/arc/plat-sim/platform.c1
-rw-r--r--arch/arm/Kconfig103
-rw-r--r--arch/arm/Kconfig.debug44
-rw-r--r--arch/arm/boot/compressed/Makefile4
-rw-r--r--arch/arm/boot/compressed/efi-header.S130
-rw-r--r--arch/arm/boot/compressed/head.S54
-rw-r--r--arch/arm/boot/compressed/vmlinux.lds.S7
-rw-r--r--arch/arm/boot/dts/Makefile57
-rw-r--r--arch/arm/boot/dts/am335x-base0033.dts48
-rw-r--r--arch/arm/boot/dts/am335x-bone-common.dtsi3
-rw-r--r--arch/arm/boot/dts/am335x-bonegreen.dts53
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts2
-rw-r--r--arch/arm/boot/dts/am335x-evmsk.dts2
-rw-r--r--arch/arm/boot/dts/am335x-igep0033.dtsi40
-rw-r--r--arch/arm/boot/dts/am335x-phycore-som.dtsi36
-rw-r--r--arch/arm/boot/dts/am335x-wega.dtsi13
-rw-r--r--arch/arm/boot/dts/am4372.dtsi4
-rw-r--r--arch/arm/boot/dts/am437x-gp-evm.dts31
-rw-r--r--arch/arm/boot/dts/am437x-idk-evm.dts2
-rw-r--r--arch/arm/boot/dts/am437x-sk-evm.dts2
-rw-r--r--arch/arm/boot/dts/am43x-epos-evm.dts2
-rw-r--r--arch/arm/boot/dts/am43xx-clocks.dtsi8
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts118
-rw-r--r--arch/arm/boot/dts/animeo_ip.dts6
-rw-r--r--arch/arm/boot/dts/armada-370-db.dts3
-rw-r--r--arch/arm/boot/dts/armada-370-dlink-dns327l.dts3
-rw-r--r--arch/arm/boot/dts/armada-370-mirabox.dts7
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn102.dts9
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn104.dts9
-rw-r--r--arch/arm/boot/dts/armada-370-rd.dts3
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-nas-2bay.dts36
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts133
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi231
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-personal-cloud-2bay.dts51
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-personal-cloud.dts37
-rw-r--r--arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi178
-rw-r--r--arch/arm/boot/dts/armada-370-synology-ds213j.dts3
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi37
-rw-r--r--arch/arm/boot/dts/armada-375-db.dts4
-rw-r--r--arch/arm/boot/dts/armada-375.dtsi33
-rw-r--r--arch/arm/boot/dts/armada-385-db-ap.dts4
-rw-r--r--arch/arm/boot/dts/armada-385-linksys.dtsi4
-rw-r--r--arch/arm/boot/dts/armada-388-db.dts4
-rw-r--r--arch/arm/boot/dts/armada-388-gp.dts19
-rw-r--r--arch/arm/boot/dts/armada-388-rd.dts4
-rw-r--r--arch/arm/boot/dts/armada-38x.dtsi34
-rw-r--r--arch/arm/boot/dts/armada-xp-axpwifiap.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-db.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-gp.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-linksys-mamba.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-matrix.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-netgear-rn2120.dts90
-rw-r--r--arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp-synology-ds414.dts4
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi35
-rw-r--r--arch/arm/boot/dts/at91-foxg20.dts2
-rw-r--r--arch/arm/boot/dts/at91-kizbox.dts13
-rw-r--r--arch/arm/boot/dts/at91-kizbox2.dts6
-rw-r--r--arch/arm/boot/dts/at91-kizboxmini.dts4
-rw-r--r--arch/arm/boot/dts/at91-qil_a9260.dts2
-rw-r--r--arch/arm/boot/dts/at91-sama5d2_xplained.dts234
-rw-r--r--arch/arm/boot/dts/at91-sama5d3_xplained.dts4
-rw-r--r--arch/arm/boot/dts/at91-sama5d4_xplained.dts14
-rw-r--r--arch/arm/boot/dts/at91-sama5d4ek.dts39
-rw-r--r--arch/arm/boot/dts/at91rm9200.dtsi8
-rw-r--r--arch/arm/boot/dts/at91rm9200ek.dts9
-rw-r--r--arch/arm/boot/dts/at91sam9260.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9261.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9261ek.dts19
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9263ek.dts13
-rw-r--r--arch/arm/boot/dts/at91sam9g20ek_common.dtsi13
-rw-r--r--arch/arm/boot/dts/at91sam9g45.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9m10g45ek.dts15
-rw-r--r--arch/arm/boot/dts/at91sam9n12.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9n12ek.dts19
-rw-r--r--arch/arm/boot/dts/at91sam9rl.dtsi2
-rw-r--r--arch/arm/boot/dts/at91sam9rlek.dts13
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi5
-rw-r--r--arch/arm/boot/dts/at91sam9x5cm.dtsi11
-rw-r--r--arch/arm/boot/dts/at91sam9x5ek.dtsi8
-rw-r--r--arch/arm/boot/dts/axp209.dtsi5
-rw-r--r--arch/arm/boot/dts/axp22x.dtsi143
-rw-r--r--arch/arm/boot/dts/bcm-cygnus.dtsi334
-rw-r--r--arch/arm/boot/dts/bcm-nsp.dtsi119
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-a-plus.dts30
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts23
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts8
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi4
-rw-r--r--arch/arm/boot/dts/bcm2835.dtsi64
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6250.dts11
-rw-r--r--arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts1
-rw-r--r--arch/arm/boot/dts/bcm4709-netgear-r7000.dts106
-rw-r--r--arch/arm/boot/dts/bcm7445.dtsi84
-rw-r--r--arch/arm/boot/dts/bcm911360_entphn.dts28
-rw-r--r--arch/arm/boot/dts/bcm911360k.dts9
-rw-r--r--arch/arm/boot/dts/bcm958300k.dts44
-rw-r--r--arch/arm/boot/dts/bcm958305k.dts40
-rw-r--r--arch/arm/boot/dts/bcm958625k.dts57
-rw-r--r--arch/arm/boot/dts/bcm9hmidc.dtsi42
-rw-r--r--arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts3
-rw-r--r--arch/arm/boot/dts/berlin2.dtsi23
-rw-r--r--arch/arm/boot/dts/berlin2cd-google-chromecast.dts3
-rw-r--r--arch/arm/boot/dts/berlin2cd.dtsi20
-rw-r--r--arch/arm/boot/dts/berlin2q-marvell-dmp.dts3
-rw-r--r--arch/arm/boot/dts/berlin2q.dtsi31
-rw-r--r--arch/arm/boot/dts/cx92755.dtsi7
-rw-r--r--arch/arm/boot/dts/cx92755_equinox.dts9
-rw-r--r--arch/arm/boot/dts/dm816x.dtsi8
-rw-r--r--arch/arm/boot/dts/dove.dtsi17
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts222
-rw-r--r--arch/arm/boot/dts/dra7.dtsi60
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts162
-rw-r--r--arch/arm/boot/dts/dra72x.dtsi21
-rw-r--r--arch/arm/boot/dts/dra74x.dtsi51
-rw-r--r--arch/arm/boot/dts/efm32gg-dk3750.dts8
-rw-r--r--arch/arm/boot/dts/efm32gg.dtsi32
-rw-r--r--arch/arm/boot/dts/exynos3250-monk.dts9
-rw-r--r--arch/arm/boot/dts/exynos3250-rinato.dts11
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi8
-rw-r--r--arch/arm/boot/dts/exynos4210-origen.dts15
-rw-r--r--arch/arm/boot/dts/exynos4210-smdkv310.dts3
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts31
-rw-r--r--arch/arm/boot/dts/exynos4210-universal_c210.dts44
-rw-r--r--arch/arm/boot/dts/exynos4412-odroid-common.dtsi27
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidu3.dts45
-rw-r--r--arch/arm/boot/dts/exynos4412-odroidx.dts8
-rw-r--r--arch/arm/boot/dts/exynos4412-origen.dts15
-rw-r--r--arch/arm/boot/dts/exynos4412-tiny4412.dts9
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts140
-rw-r--r--arch/arm/boot/dts/exynos5250-arndale.dts8
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts16
-rw-r--r--arch/arm/boot/dts/exynos5250-snow-common.dtsi684
-rw-r--r--arch/arm/boot/dts/exynos5250-snow-rev5.dts47
-rw-r--r--arch/arm/boot/dts/exynos5250-snow.dts671
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5420-arndale-octa.dts3
-rw-r--r--arch/arm/boot/dts/exynos5420-peach-pit.dts9
-rw-r--r--arch/arm/boot/dts/exynos5420-smdk5420.dts14
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi61
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi102
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts51
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu3.dts51
-rw-r--r--arch/arm/boot/dts/exynos5422-odroidxu4.dts48
-rw-r--r--arch/arm/boot/dts/exynos5440-ssdk5440.dts5
-rw-r--r--arch/arm/boot/dts/exynos5800-peach-pi.dts9
-rw-r--r--arch/arm/boot/dts/hi3620-hi4511.dts3
-rw-r--r--arch/arm/boot/dts/hisi-x5hd2-dkb.dts2
-rw-r--r--arch/arm/boot/dts/imx23.dtsi6
-rw-r--r--arch/arm/boot/dts/imx27.dtsi16
-rw-r--r--arch/arm/boot/dts/imx28-evk.dts2
-rw-r--r--arch/arm/boot/dts/imx28-m28evk.dts2
-rw-r--r--arch/arm/boot/dts/imx28.dtsi6
-rw-r--r--arch/arm/boot/dts/imx31.dtsi2
-rw-r--r--arch/arm/boot/dts/imx35.dtsi2
-rw-r--r--arch/arm/boot/dts/imx50-evk.dts2
-rw-r--r--arch/arm/boot/dts/imx53-smd.dts2
-rw-r--r--arch/arm/boot/dts/imx6dl-nit6xlite.dts49
-rw-r--r--arch/arm/boot/dts/imx6dl-nitrogen6x.dts44
-rw-r--r--arch/arm/boot/dts/imx6dl-rex-basic.dts2
-rw-r--r--arch/arm/boot/dts/imx6dl-sabrelite.dts40
-rw-r--r--arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts2
-rw-r--r--arch/arm/boot/dts/imx6q-gw5400-a.dts4
-rw-r--r--arch/arm/boot/dts/imx6q-nitrogen6_max.dts53
-rw-r--r--arch/arm/boot/dts/imx6q-nitrogen6x.dts44
-rw-r--r--arch/arm/boot/dts/imx6q-rex-pro.dts2
-rw-r--r--arch/arm/boot/dts/imx6q-sabrelite.dts40
-rw-r--r--arch/arm/boot/dts/imx6qdl-aristainetos.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw51xx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw52xx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw53xx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw54xx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi630
-rw-r--r--arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi873
-rw-r--r--arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi189
-rw-r--r--arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi6
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabreauto.dtsi8
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabrelite.dtsi118
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabresd.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi12
-rw-r--r--arch/arm/boot/dts/imx6sl-evk.dts2
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi21
-rw-r--r--arch/arm/boot/dts/imx6sx-sdb-reva.dts4
-rw-r--r--arch/arm/boot/dts/imx6sx-sdb.dts4
-rw-r--r--arch/arm/boot/dts/imx6sx-sdb.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6ul-14x14-evk.dts22
-rw-r--r--arch/arm/boot/dts/imx6ul.dtsi29
-rw-r--r--arch/arm/boot/dts/imx7d-pinfunc.h122
-rw-r--r--arch/arm/boot/dts/imx7d-sdb.dts100
-rw-r--r--arch/arm/boot/dts/imx7d.dtsi165
-rw-r--r--arch/arm/boot/dts/k2e-evm.dts2
-rw-r--r--arch/arm/boot/dts/k2e-netcp.dtsi23
-rw-r--r--arch/arm/boot/dts/k2e.dtsi3
-rw-r--r--arch/arm/boot/dts/k2hk-evm.dts2
-rw-r--r--arch/arm/boot/dts/k2hk-netcp.dtsi24
-rw-r--r--arch/arm/boot/dts/k2hk.dtsi3
-rw-r--r--arch/arm/boot/dts/k2l-evm.dts2
-rw-r--r--arch/arm/boot/dts/k2l-netcp.dtsi25
-rw-r--r--arch/arm/boot/dts/k2l.dtsi3
-rw-r--r--arch/arm/boot/dts/keystone.dtsi7
-rw-r--r--arch/arm/boot/dts/kirkwood-ts219.dtsi2
-rw-r--r--arch/arm/boot/dts/kirkwood.dtsi29
-rw-r--r--arch/arm/boot/dts/lpc18xx.dtsi134
-rw-r--r--arch/arm/boot/dts/lpc4350-hitex-eval.dts175
-rw-r--r--arch/arm/boot/dts/lpc4357-ea4357-devkit.dts95
-rw-r--r--arch/arm/boot/dts/ls1021a-twr.dts13
-rw-r--r--arch/arm/boot/dts/ls1021a.dtsi44
-rw-r--r--arch/arm/boot/dts/meson8b-mxq.dts67
-rw-r--r--arch/arm/boot/dts/meson8b-odroidc1.dts67
-rw-r--r--arch/arm/boot/dts/meson8b.dtsi186
-rw-r--r--arch/arm/boot/dts/mt8127.dtsi27
-rw-r--r--arch/arm/boot/dts/mt8135-evbp1.dts23
-rw-r--r--arch/arm/boot/dts/mt8135.dtsi27
-rw-r--r--arch/arm/boot/dts/nspire.dtsi2
-rw-r--r--arch/arm/boot/dts/omap2420-n8x0-common.dtsi6
-rw-r--r--arch/arm/boot/dts/omap3-beagle-xm.dts2
-rw-r--r--arch/arm/boot/dts/omap3-beagle.dts2
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-evm-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi10
-rw-r--r--arch/arm/boot/dts/omap3-gta04a5.dts2
-rw-r--r--arch/arm/boot/dts/omap3-igep.dtsi70
-rw-r--r--arch/arm/boot/dts/omap3-igep0020-common.dtsi60
-rw-r--r--arch/arm/boot/dts/omap3-igep0020-rev-f.dts2
-rw-r--r--arch/arm/boot/dts/omap3-igep0020.dts11
-rw-r--r--arch/arm/boot/dts/omap3-igep0030-common.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-igep0030-rev-g.dts2
-rw-r--r--arch/arm/boot/dts/omap3-igep0030.dts2
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts2
-rw-r--r--arch/arm/boot/dts/omap3-lilly-a83x.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-lilly-dbb056.dts4
-rw-r--r--arch/arm/boot/dts/omap3-n950-n9.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-base.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-pandora-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-tao3530.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-zoom3.dts2
-rw-r--r--arch/arm/boot/dts/omap4-duovero-parlor.dts4
-rw-r--r--arch/arm/boot/dts/omap4-panda-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap4-sdp.dts6
-rw-r--r--arch/arm/boot/dts/omap4-var-som-om44-wlan.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4-var-som-om44.dtsi2
-rw-r--r--arch/arm/boot/dts/omap4460.dtsi2
-rw-r--r--arch/arm/boot/dts/omap5-board-common.dtsi655
-rw-r--r--arch/arm/boot/dts/omap5-cm-t54.dts2
-rw-r--r--arch/arm/boot/dts/omap5-igep0050.dts54
-rw-r--r--arch/arm/boot/dts/omap5-uevm.dts618
-rw-r--r--arch/arm/boot/dts/orion5x.dtsi22
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts48
-rw-r--r--arch/arm/boot/dts/qcom-apq8064-ifc6410.dts60
-rw-r--r--arch/arm/boot/dts/qcom-apq8064.dtsi43
-rw-r--r--arch/arm/boot/dts/qcom-apq8084.dtsi1
-rw-r--r--arch/arm/boot/dts/qcom-msm8974.dtsi95
-rw-r--r--arch/arm/boot/dts/qcom-pm8941.dtsi24
-rw-r--r--arch/arm/boot/dts/r8a7778-bockw-reference.dts139
-rw-r--r--arch/arm/boot/dts/r8a7778.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7779-marzen.dts6
-rw-r--r--arch/arm/boot/dts/r8a7790-lager.dts16
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7791-koelsch.dts9
-rw-r--r--arch/arm/boot/dts/r8a7791-porter.dts282
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi2
-rw-r--r--arch/arm/boot/dts/r8a7794-silk.dts114
-rw-r--r--arch/arm/boot/dts/r8a7794.dtsi326
-rw-r--r--arch/arm/boot/dts/r8a77xx-aa121td01-panel.dtsi41
-rw-r--r--arch/arm/boot/dts/rk3066a-bqcurie2.dts2
-rw-r--r--arch/arm/boot/dts/rk3066a-marsboard.dts8
-rw-r--r--arch/arm/boot/dts/rk3066a-rayeager.dts2
-rw-r--r--arch/arm/boot/dts/rk3188-radxarock.dts21
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi20
-rw-r--r--arch/arm/boot/dts/rk3288-firefly.dtsi55
-rw-r--r--arch/arm/boot/dts/rk3288-popmetal.dts85
-rw-r--r--arch/arm/boot/dts/rk3288-rock2-som.dtsi277
-rw-r--r--arch/arm/boot/dts/rk3288-rock2-square.dts167
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-jaq.dts176
-rw-r--r--arch/arm/boot/dts/rk3288-veyron-minnie.dts4
-rw-r--r--arch/arm/boot/dts/rk3288-veyron.dtsi12
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi144
-rw-r--r--arch/arm/boot/dts/s3c2416.dtsi2
-rw-r--r--arch/arm/boot/dts/s5pv210-aquila.dts2
-rw-r--r--arch/arm/boot/dts/s5pv210-goni.dts4
-rw-r--r--arch/arm/boot/dts/sama5d2-pinfunc.h880
-rw-r--r--arch/arm/boot/dts/sama5d2.dtsi154
-rw-r--r--arch/arm/boot/dts/sama5d3.dtsi5
-rw-r--r--arch/arm/boot/dts/sama5d35ek.dts2
-rw-r--r--arch/arm/boot/dts/sama5d3_mci2.dtsi6
-rw-r--r--arch/arm/boot/dts/sama5d3xmb.dtsi2
-rw-r--r--arch/arm/boot/dts/sama5d4.dtsi51
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g.dts2
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi135
-rw-r--r--arch/arm/boot/dts/socfpga_arria10.dtsi8
-rw-r--r--arch/arm/boot/dts/socfpga_arria10_socdk.dtsi27
-rw-r--r--arch/arm/boot/dts/ste-nomadik-stn8815.dtsi6
-rw-r--r--arch/arm/boot/dts/stih407-b2120.dts1
-rw-r--r--arch/arm/boot/dts/stih407-family.dtsi74
-rw-r--r--arch/arm/boot/dts/stih407-pinctrl.dtsi390
-rw-r--r--arch/arm/boot/dts/stih407.dtsi13
-rw-r--r--arch/arm/boot/dts/stih410-b2120.dts25
-rw-r--r--arch/arm/boot/dts/stih410.dtsi23
-rw-r--r--arch/arm/boot/dts/stih418-b2199.dts8
-rw-r--r--arch/arm/boot/dts/stih418-clock.dtsi2
-rw-r--r--arch/arm/boot/dts/stih418.dtsi6
-rw-r--r--arch/arm/boot/dts/stihxxx-b2120.dtsi60
-rw-r--r--arch/arm/boot/dts/sun4i-a10-a1000.dts4
-rw-r--r--arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts12
-rw-r--r--arch/arm/boot/dts/sun4i-a10-cubieboard.dts4
-rw-r--r--arch/arm/boot/dts/sun4i-a10-gemei-g9.dts11
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet1.dts226
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet97fv2.dts117
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts227
-rw-r--r--arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts15
-rw-r--r--arch/arm/boot/dts/sun4i-a10-marsboard.dts23
-rw-r--r--arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts12
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pcduino.dts58
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pcduino2.dts78
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts199
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi31
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts159
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts2
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts224
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi35
-rw-r--r--arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts227
-rw-r--r--arch/arm/boot/dts/sun5i-a13-q8-tablet.dts60
-rw-r--r--arch/arm/boot/dts/sun5i-a13.dtsi10
-rw-r--r--arch/arm/boot/dts/sun5i-q8-common.dtsi180
-rw-r--r--arch/arm/boot/dts/sun5i-r8-chip.dts218
-rw-r--r--arch/arm/boot/dts/sun5i-r8.dtsi59
-rw-r--r--arch/arm/boot/dts/sun5i.dtsi52
-rw-r--r--arch/arm/boot/dts/sun6i-a31-colombus.dts36
-rw-r--r--arch/arm/boot/dts/sun6i-a31-hummingbird.dts132
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi31
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-primo81.dts256
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi140
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-sina31s.dts153
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts194
-rw-r--r--arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts134
-rw-r--r--arch/arm/boot/dts/sun7i-a20-bananapi.dts74
-rw-r--r--arch/arm/boot/dts/sun7i-a20-cubieboard2.dts23
-rw-r--r--arch/arm/boot/dts/sun7i-a20-cubietruck.dts4
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts198
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts12
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts47
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts6
-rw-r--r--arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts29
-rw-r--r--arch/arm/boot/dts/sun7i-a20-orangepi.dts29
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts65
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3.dts54
-rw-r--r--arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts33
-rw-r--r--arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts226
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi39
-rw-r--r--arch/arm/boot/dts/sun8i-a23-a33.dtsi70
-rw-r--r--arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts145
l---------[-rw-r--r--]arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts55
l---------[-rw-r--r--]arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts137
-rw-r--r--arch/arm/boot/dts/sun8i-a23-q8-tablet.dts65
-rw-r--r--arch/arm/boot/dts/sun8i-a23.dtsi25
l---------[-rw-r--r--]arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts89
l---------[-rw-r--r--]arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts134
-rw-r--r--arch/arm/boot/dts/sun8i-a33-q8-tablet.dts65
-rw-r--r--arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts4
-rw-r--r--arch/arm/boot/dts/sun8i-a33.dtsi45
-rw-r--r--arch/arm/boot/dts/sun8i-q8-common.dtsi101
-rw-r--r--arch/arm/boot/dts/sun9i-a80.dtsi2
-rw-r--r--arch/arm/boot/dts/sunxi-q8-common.dtsi83
-rw-r--r--arch/arm/boot/dts/tegra124-nyan.dtsi15
-rw-r--r--arch/arm/boot/dts/tegra124.dtsi20
-rw-r--r--arch/arm/boot/dts/tegra20.dtsi4
-rw-r--r--arch/arm/boot/dts/tegra30-apalis-eval.dts13
-rw-r--r--arch/arm/boot/dts/tegra30-apalis.dtsi214
-rw-r--r--arch/arm/boot/dts/tegra30-colibri-eval-v3.dts9
-rw-r--r--arch/arm/boot/dts/tegra30-colibri.dtsi196
-rw-r--r--arch/arm/boot/dts/tegra30.dtsi10
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts8
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld4.dtsi20
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts8
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts8
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro4.dtsi21
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-pro5.dtsi34
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts8
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld3.dtsi21
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts8
-rw-r--r--arch/arm/boot/dts/uniphier-ph1-sld8.dtsi20
-rw-r--r--arch/arm/boot/dts/uniphier-proxstream2-gentil.dts78
-rw-r--r--arch/arm/boot/dts/uniphier-proxstream2-vodka.dts78
-rw-r--r--arch/arm/boot/dts/uniphier-proxstream2.dtsi23
-rw-r--r--arch/arm/boot/dts/usb_a9260_common.dtsi2
-rw-r--r--arch/arm/boot/dts/usb_a9263.dts2
-rw-r--r--arch/arm/boot/dts/versatile-ab.dts10
-rw-r--r--arch/arm/boot/dts/versatile-pb.dts20
-rw-r--r--arch/arm/boot/dts/vf-colibri.dtsi39
-rw-r--r--arch/arm/boot/dts/vf500-colibri-eval-v3.dts5
-rw-r--r--arch/arm/boot/dts/vf500-colibri.dtsi47
-rw-r--r--arch/arm/boot/dts/vf610-colibri.dtsi5
-rw-r--r--arch/arm/boot/dts/vf610-twr.dts47
-rw-r--r--arch/arm/boot/dts/vf610.dtsi2
-rw-r--r--arch/arm/boot/dts/vfxxx.dtsi25
-rw-r--r--arch/arm/boot/dts/wm8650.dtsi9
-rw-r--r--arch/arm/boot/dts/wm8750.dtsi2
-rw-r--r--arch/arm/configs/at91_dt_defconfig16
-rw-r--r--arch/arm/configs/bockw_defconfig133
-rw-r--r--arch/arm/configs/exynos_defconfig18
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig2
-rw-r--r--arch/arm/configs/keystone_defconfig54
-rw-r--r--arch/arm/configs/lpc18xx_defconfig26
-rw-r--r--arch/arm/configs/multi_v7_defconfig49
-rw-r--r--arch/arm/configs/mvebu_v7_defconfig9
-rw-r--r--arch/arm/configs/qcom_defconfig8
-rw-r--r--arch/arm/configs/sama5_defconfig17
-rw-r--r--arch/arm/configs/shmobile_defconfig4
-rw-r--r--arch/arm/configs/socfpga_defconfig2
-rw-r--r--arch/arm/configs/sunxi_defconfig5
-rw-r--r--arch/arm/configs/tegra_defconfig10
-rw-r--r--arch/arm/include/asm/Kbuild1
-rw-r--r--arch/arm/include/asm/arch_gicv3.h1
-rw-r--r--arch/arm/include/asm/bug.h5
-rw-r--r--arch/arm/include/asm/cpuidle.h2
-rw-r--r--arch/arm/include/asm/efi.h83
-rw-r--r--arch/arm/include/asm/fixmap.h29
-rw-r--r--arch/arm/include/asm/hardirq.h2
-rw-r--r--arch/arm/include/asm/hardware/cache-uniphier.h46
-rw-r--r--arch/arm/include/asm/irq.h5
-rw-r--r--arch/arm/include/asm/kvm_arm.h34
-rw-r--r--arch/arm/include/asm/kvm_emulate.h12
-rw-r--r--arch/arm/include/asm/kvm_host.h6
-rw-r--r--arch/arm/include/asm/kvm_mmu.h5
-rw-r--r--arch/arm/include/asm/mach/map.h2
-rw-r--r--arch/arm/include/asm/mmu_context.h2
-rw-r--r--arch/arm/include/asm/paravirt.h20
-rw-r--r--arch/arm/include/asm/psci.h2
-rw-r--r--arch/arm/include/asm/setup.h6
-rw-r--r--arch/arm/include/asm/uaccess.h4
-rw-r--r--arch/arm/include/asm/xen/hypercall.h7
-rw-r--r--arch/arm/include/asm/xen/interface.h3
-rw-r--r--arch/arm/include/debug/at91.S18
-rw-r--r--arch/arm/include/uapi/asm/unistd.h1
-rw-r--r--arch/arm/kernel/Makefile6
-rw-r--r--arch/arm/kernel/armksyms.c6
-rw-r--r--arch/arm/kernel/atags.h6
-rw-r--r--arch/arm/kernel/bios32.c19
-rw-r--r--arch/arm/kernel/calls.S1
-rw-r--r--arch/arm/kernel/cpuidle.c2
-rw-r--r--arch/arm/kernel/efi.c38
-rw-r--r--arch/arm/kernel/entry-v7m.S2
-rw-r--r--arch/arm/kernel/irq.c3
-rw-r--r--arch/arm/kernel/paravirt.c (renamed from arch/arm64/kernel/psci-call.S)23
-rw-r--r--arch/arm/kernel/perf_event_v7.c321
-rw-r--r--arch/arm/kernel/pj4-cp0.c4
-rw-r--r--arch/arm/kernel/process.c33
-rw-r--r--arch/arm/kernel/psci_smp.c4
-rw-r--r--arch/arm/kernel/setup.c77
-rw-r--r--arch/arm/kernel/smccc-call.S62
-rw-r--r--arch/arm/kernel/smp.c17
-rw-r--r--arch/arm/kernel/swp_emulate.c6
-rw-r--r--arch/arm/kernel/sys_oabi-compat.c73
-rw-r--r--arch/arm/kernel/vdso.c2
-rw-r--r--arch/arm/kvm/arm.c47
-rw-r--r--arch/arm/kvm/emulate.c74
-rw-r--r--arch/arm/kvm/guest.c6
-rw-r--r--arch/arm/kvm/handle_exit.c3
-rw-r--r--arch/arm/kvm/mmio.c8
-rw-r--r--arch/arm/kvm/mmu.c21
-rw-r--r--arch/arm/kvm/psci.c20
-rw-r--r--arch/arm/lib/lib1funcs.S8
-rw-r--r--arch/arm/lib/uaccess_with_memcpy.c29
-rw-r--r--arch/arm/mach-at91/Kconfig6
-rw-r--r--arch/arm/mach-at91/pm.c7
-rw-r--r--arch/arm/mach-at91/pm_suspend.S2
-rw-r--r--arch/arm/mach-bcm/Kconfig15
-rw-r--r--arch/arm/mach-bcm/Makefile5
-rw-r--r--arch/arm/mach-bcm/bcm_nsp.c25
-rw-r--r--arch/arm/mach-bcm/brcmstb.c9
-rw-r--r--arch/arm/mach-berlin/berlin.c6
-rw-r--r--arch/arm/mach-berlin/platsmp.c38
-rw-r--r--arch/arm/mach-cns3xxx/pcie.c71
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c2
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c6
-rw-r--r--arch/arm/mach-davinci/board-dm646x-evm.c4
-rw-r--r--arch/arm/mach-davinci/clock.c16
-rw-r--r--arch/arm/mach-digicolor/Kconfig3
-rw-r--r--arch/arm/mach-dove/include/mach/entry-macro.S4
-rw-r--r--arch/arm/mach-exynos/Kconfig1
-rw-r--r--arch/arm/mach-exynos/pmu.c6
-rw-r--r--arch/arm/mach-exynos/suspend.c3
-rw-r--r--arch/arm/mach-imx/common.h1
-rw-r--r--arch/arm/mach-imx/devices/devices-common.h4
-rw-r--r--arch/arm/mach-imx/gpc.c9
-rw-r--r--arch/arm/mach-imx/mach-imx6ul.c9
-rw-r--r--arch/arm/mach-imx/mach-imx7d.c74
-rw-r--r--arch/arm/mach-imx/pm-imx6.c46
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S3
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/io.h12
-rw-r--r--arch/arm/mach-keystone/keystone.c3
-rw-r--r--arch/arm/mach-mediatek/Makefile3
-rw-r--r--arch/arm/mach-mediatek/mediatek.c27
-rw-r--r--arch/arm/mach-mediatek/platsmp.c141
-rw-r--r--arch/arm/mach-meson/Kconfig5
-rw-r--r--arch/arm/mach-meson/meson.c1
-rw-r--r--arch/arm/mach-mvebu/board-v7.c35
-rw-r--r--arch/arm/mach-mvebu/coherency.c60
-rw-r--r--arch/arm/mach-mvebu/pmsu.c33
-rw-r--r--arch/arm/mach-omap1/Kconfig7
-rw-r--r--arch/arm/mach-omap1/Makefile1
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c296
-rw-r--r--arch/arm/mach-omap1/include/mach/board-voiceblue.h19
-rw-r--r--arch/arm/mach-omap1/include/mach/camera.h2
-rw-r--r--arch/arm/mach-omap2/Kconfig5
-rw-r--r--arch/arm/mach-omap2/Makefile3
-rw-r--r--arch/arm/mach-omap2/board-generic.c24
-rw-r--r--arch/arm/mach-omap2/board-ldp.c2
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c4
-rw-r--r--arch/arm/mach-omap2/board-rx51.c2
-rw-r--r--arch/arm/mach-omap2/clkt34xx_dpll3m2.c122
-rw-r--r--arch/arm/mach-omap2/common.h3
-rw-r--r--arch/arm/mach-omap2/devices.c53
-rw-r--r--arch/arm/mach-omap2/devices.h19
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c14
-rw-r--r--arch/arm/mach-omap2/id.c30
-rw-r--r--arch/arm/mach-omap2/omap-hotplug.c2
-rw-r--r--arch/arm/mach-omap2/omap-smp.c6
-rw-r--r--arch/arm/mach-omap2/omap-wakeupgen.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c66
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h3
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c20
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c29
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c10
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_54xx_data.c3
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c82
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_81xx_data.c3
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c29
-rw-r--r--arch/arm/mach-omap2/pm34xx.c4
-rw-r--r--arch/arm/mach-omap2/pm44xx.c2
-rw-r--r--arch/arm/mach-omap2/powerdomains3xxx_data.c2
-rw-r--r--arch/arm/mach-omap2/soc.h195
-rw-r--r--arch/arm/mach-omap2/sram.c25
-rw-r--r--arch/arm/mach-omap2/sram.h14
-rw-r--r--arch/arm/mach-omap2/sram34xx.S346
-rw-r--r--arch/arm/mach-omap2/timer.c168
-rw-r--r--arch/arm/mach-omap2/vc.c4
-rw-r--r--arch/arm/mach-orion5x/Kconfig3
-rw-r--r--arch/arm/mach-orion5x/dns323-setup.c53
-rw-r--r--arch/arm/mach-orion5x/include/mach/entry-macro.S2
-rw-r--r--arch/arm/mach-orion5x/tsx09-common.c49
-rw-r--r--arch/arm/mach-prima2/hotplug.c2
-rw-r--r--arch/arm/mach-pxa/cm-x300.c9
-rw-r--r--arch/arm/mach-pxa/colibri-pxa270-income.c9
-rw-r--r--arch/arm/mach-pxa/devices.c22
-rw-r--r--arch/arm/mach-pxa/em-x270.c2
-rw-r--r--arch/arm/mach-pxa/ezx.c16
-rw-r--r--arch/arm/mach-pxa/hx4700.c3
-rw-r--r--arch/arm/mach-pxa/icontrol.c2
-rw-r--r--arch/arm/mach-pxa/include/mach/magician.h70
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa27x.h2
-rw-r--r--arch/arm/mach-pxa/lpd270.c9
-rw-r--r--arch/arm/mach-pxa/magician.c680
-rw-r--r--arch/arm/mach-pxa/mainstone.c19
-rw-r--r--arch/arm/mach-pxa/mioa701.c13
-rw-r--r--arch/arm/mach-pxa/palm27x.c9
-rw-r--r--arch/arm/mach-pxa/palmtc.c9
-rw-r--r--arch/arm/mach-pxa/palmte2.c9
-rw-r--r--arch/arm/mach-pxa/palmtreo.c2
-rw-r--r--arch/arm/mach-pxa/palmz72.c2
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c13
-rw-r--r--arch/arm/mach-pxa/pxa27x.c2
-rw-r--r--arch/arm/mach-pxa/raumfeld.c21
-rw-r--r--arch/arm/mach-pxa/tavorevb.c13
-rw-r--r--arch/arm/mach-pxa/viper.c9
-rw-r--r--arch/arm/mach-pxa/z2.c15
-rw-r--r--arch/arm/mach-pxa/zylonite.c9
-rw-r--r--arch/arm/mach-qcom/platsmp.c2
-rw-r--r--arch/arm/mach-realview/hotplug.c2
-rw-r--r--arch/arm/mach-s3c24xx/mach-h1940.c10
-rw-r--r--arch/arm/mach-s3c24xx/mach-rx1950.c8
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c2
-rw-r--r--arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c2
-rw-r--r--arch/arm/mach-s3c64xx/dev-backlight.c4
-rw-r--r--arch/arm/mach-s3c64xx/mach-crag6410.c9
-rw-r--r--arch/arm/mach-s3c64xx/mach-hmt.c9
-rw-r--r--arch/arm/mach-s3c64xx/mach-smartq.c9
-rw-r--r--arch/arm/mach-s3c64xx/mach-smdk6410.c8
-rw-r--r--arch/arm/mach-shmobile/Kconfig73
-rw-r--r--arch/arm/mach-shmobile/Makefile14
-rw-r--r--arch/arm/mach-shmobile/Makefile.boot12
-rw-r--r--arch/arm/mach-shmobile/board-bockw-reference.c86
-rw-r--r--arch/arm/mach-shmobile/board-bockw.c737
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7778.c342
-rw-r--r--arch/arm/mach-shmobile/clock.c47
-rw-r--r--arch/arm/mach-shmobile/clock.h42
-rw-r--r--arch/arm/mach-shmobile/common.h5
-rw-r--r--arch/arm/mach-shmobile/console.c27
-rw-r--r--arch/arm/mach-shmobile/intc.h295
-rw-r--r--arch/arm/mach-shmobile/platsmp-apmu.c4
-rw-r--r--arch/arm/mach-shmobile/pm-r8a7779.c99
-rw-r--r--arch/arm/mach-shmobile/pm-rmobile.c39
-rw-r--r--arch/arm/mach-shmobile/pm-rmobile.h9
-rw-r--r--arch/arm/mach-shmobile/r8a7778.h78
-rw-r--r--arch/arm/mach-shmobile/r8a7779.h8
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7778.c563
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7793.c2
-rw-r--r--arch/arm/mach-shmobile/sh-gpio.h29
-rw-r--r--arch/arm/mach-shmobile/timer.c21
-rw-r--r--arch/arm/mach-spear/hotplug.c2
-rw-r--r--arch/arm/mach-sti/Kconfig1
-rw-r--r--arch/arm/mach-sunxi/sunxi.c3
-rw-r--r--arch/arm/mach-tegra/board-paz00.c4
-rw-r--r--arch/arm/mach-tegra/hotplug.c2
-rw-r--r--arch/arm/mach-uniphier/Makefile2
-rw-r--r--arch/arm/mach-uniphier/headsmp.S43
-rw-r--r--arch/arm/mach-uniphier/platsmp.c185
-rw-r--r--arch/arm/mach-ux500/Kconfig1
-rw-r--r--arch/arm/mach-ux500/hotplug.c2
-rw-r--r--arch/arm/mach-vexpress/hotplug.c2
-rw-r--r--arch/arm/mach-zx/Kconfig2
-rw-r--r--arch/arm/mm/Kconfig10
-rw-r--r--arch/arm/mm/Makefile1
-rw-r--r--arch/arm/mm/cache-l2x0.c33
-rw-r--r--arch/arm/mm/cache-uniphier.c544
-rw-r--r--arch/arm/mm/context.c38
-rw-r--r--arch/arm/mm/dma-mapping.c2
-rw-r--r--arch/arm/mm/init.c97
-rw-r--r--arch/arm/mm/ioremap.c9
-rw-r--r--arch/arm/mm/mmu.c130
-rw-r--r--arch/arm/mm/proc-v7.S27
-rw-r--r--arch/arm/mm/proc-v7m.S14
-rw-r--r--arch/arm/net/bpf_jit_32.c21
-rw-r--r--arch/arm/plat-samsung/devs.c2
-rw-r--r--arch/arm/xen/enlighten.c95
-rw-r--r--arch/arm/xen/hypercall.S1
-rw-r--r--arch/arm64/Kconfig49
-rw-r--r--arch/arm64/Kconfig.debug4
-rw-r--r--arch/arm64/Kconfig.platforms12
-rw-r--r--arch/arm64/boot/dts/Makefile1
-rw-r--r--arch/arm64/boot/dts/altera/Makefile5
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi358
-rw-r--r--arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts39
-rw-r--r--arch/arm64/boot/dts/apm/Makefile1
-rw-r--r--arch/arm64/boot/dts/apm/apm-merlin.dts72
-rw-r--r--arch/arm64/boot/dts/apm/apm-mustang.dts12
-rw-r--r--arch/arm64/boot/dts/apm/apm-shadowcat.dtsi271
-rw-r--r--arch/arm64/boot/dts/apm/apm-storm.dtsi17
-rw-r--r--arch/arm64/boot/dts/arm/juno-base.dtsi59
-rw-r--r--arch/arm64/boot/dts/arm/juno-motherboard.dtsi15
-rw-r--r--arch/arm64/boot/dts/arm/juno-r1.dts52
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts32
-rw-r--r--arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts2
l---------arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi1
-rw-r--r--arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi103
-rw-r--r--arch/arm64/boot/dts/exynos/exynos7.dtsi7
-rw-r--r--arch/arm64/boot/dts/freescale/Makefile4
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts204
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts166
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts (renamed from arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts)25
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi520
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi163
-rw-r--r--arch/arm64/boot/dts/hisilicon/Makefile2
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts7
-rw-r--r--arch/arm64/boot/dts/hisilicon/hi6220.dtsi43
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05-d02.dts36
-rw-r--r--arch/arm64/boot/dts/hisilicon/hip05.dtsi271
-rw-r--r--arch/arm64/boot/dts/marvell/Makefile1
-rw-r--r--arch/arm64/boot/dts/marvell/berlin4ct-stb.dts66
-rw-r--r--arch/arm64/boot/dts/marvell/berlin4ct.dtsi120
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173-evb.dts18
-rw-r--r--arch/arm64/boot/dts/mediatek/mt8173.dtsi62
-rw-r--r--arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi30
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916-pins.dtsi76
-rw-r--r--arch/arm64/boot/dts/qcom/msm8916.dtsi47
-rw-r--r--arch/arm64/configs/defconfig15
-rw-r--r--arch/arm64/crypto/aes-ce-cipher.c2
-rw-r--r--arch/arm64/include/asm/alternative.h1
-rw-r--r--arch/arm64/include/asm/arch_gicv3.h1
-rw-r--r--arch/arm64/include/asm/assembler.h11
-rw-r--r--arch/arm64/include/asm/atomic_ll_sc.h2
-rw-r--r--arch/arm64/include/asm/atomic_lse.h2
-rw-r--r--arch/arm64/include/asm/barrier.h16
-rw-r--r--arch/arm64/include/asm/cacheflush.h1
-rw-r--r--arch/arm64/include/asm/cmpxchg.h1
-rw-r--r--arch/arm64/include/asm/compat.h3
-rw-r--r--arch/arm64/include/asm/cpufeature.h25
-rw-r--r--arch/arm64/include/asm/dma-mapping.h13
-rw-r--r--arch/arm64/include/asm/efi.h9
-rw-r--r--arch/arm64/include/asm/ftrace.h2
-rw-r--r--arch/arm64/include/asm/hugetlb.h44
-rw-r--r--arch/arm64/include/asm/hw_breakpoint.h6
-rw-r--r--arch/arm64/include/asm/irq.h50
-rw-r--r--arch/arm64/include/asm/kvm_arm.h3
-rw-r--r--arch/arm64/include/asm/kvm_asm.h76
-rw-r--r--arch/arm64/include/asm/kvm_emulate.h19
-rw-r--r--arch/arm64/include/asm/kvm_host.h87
-rw-r--r--arch/arm64/include/asm/kvm_mmio.h1
-rw-r--r--arch/arm64/include/asm/kvm_mmu.h9
-rw-r--r--arch/arm64/include/asm/mmu_context.h2
-rw-r--r--arch/arm64/include/asm/paravirt.h20
-rw-r--r--arch/arm64/include/asm/pgtable-hwdef.h18
-rw-r--r--arch/arm64/include/asm/pgtable.h37
-rw-r--r--arch/arm64/include/asm/shmparam.h2
-rw-r--r--arch/arm64/include/asm/spinlock.h23
-rw-r--r--arch/arm64/include/asm/stacktrace.h9
-rw-r--r--arch/arm64/include/asm/sysreg.h21
-rw-r--r--arch/arm64/include/asm/thread_info.h10
-rw-r--r--arch/arm64/include/uapi/asm/kvm.h2
-rw-r--r--arch/arm64/kernel/Makefile5
-rw-r--r--arch/arm64/kernel/alternative.c6
-rw-r--r--arch/arm64/kernel/arm64ksyms.c5
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c6
-rw-r--r--arch/arm64/kernel/asm-offsets.c43
-rw-r--r--arch/arm64/kernel/cpu_errata.c9
-rw-r--r--arch/arm64/kernel/cpufeature.c48
-rw-r--r--arch/arm64/kernel/cpuinfo.c5
-rw-r--r--arch/arm64/kernel/efi.c329
-rw-r--r--arch/arm64/kernel/entry.S69
-rw-r--r--arch/arm64/kernel/fpsimd.c2
-rw-r--r--arch/arm64/kernel/ftrace.c27
-rw-r--r--arch/arm64/kernel/head.S20
-rw-r--r--arch/arm64/kernel/irq.c3
-rw-r--r--arch/arm64/kernel/module.c71
-rw-r--r--arch/arm64/kernel/paravirt.c25
-rw-r--r--arch/arm64/kernel/perf_callchain.c5
-rw-r--r--arch/arm64/kernel/perf_event.c263
-rw-r--r--arch/arm64/kernel/process.c5
-rw-r--r--arch/arm64/kernel/psci.c14
-rw-r--r--arch/arm64/kernel/ptrace.c6
-rw-r--r--arch/arm64/kernel/return_address.c5
-rw-r--r--arch/arm64/kernel/sleep.S3
-rw-r--r--arch/arm64/kernel/smccc-call.S43
-rw-r--r--arch/arm64/kernel/smp.c2
-rw-r--r--arch/arm64/kernel/stacktrace.c75
-rw-r--r--arch/arm64/kernel/suspend.c12
-rw-r--r--arch/arm64/kernel/time.c5
-rw-r--r--arch/arm64/kernel/traps.c52
-rw-r--r--arch/arm64/kernel/vdso/Makefile3
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S12
-rw-r--r--arch/arm64/kvm/Makefile3
-rw-r--r--arch/arm64/kvm/guest.c10
-rw-r--r--arch/arm64/kvm/handle_exit.c6
-rw-r--r--arch/arm64/kvm/hyp-init.S9
-rw-r--r--arch/arm64/kvm/hyp.S1071
-rw-r--r--arch/arm64/kvm/hyp/Makefile14
-rw-r--r--arch/arm64/kvm/hyp/debug-sr.c140
-rw-r--r--arch/arm64/kvm/hyp/entry.S160
-rw-r--r--arch/arm64/kvm/hyp/fpsimd.S (renamed from arch/arm/kernel/psci-call.S)32
-rw-r--r--arch/arm64/kvm/hyp/hyp-entry.S212
-rw-r--r--arch/arm64/kvm/hyp/hyp.h90
-rw-r--r--arch/arm64/kvm/hyp/switch.c175
-rw-r--r--arch/arm64/kvm/hyp/sysreg-sr.c138
-rw-r--r--arch/arm64/kvm/hyp/timer-sr.c71
-rw-r--r--arch/arm64/kvm/hyp/tlb.c80
-rw-r--r--arch/arm64/kvm/hyp/vgic-v2-sr.c84
-rw-r--r--arch/arm64/kvm/hyp/vgic-v3-sr.c228
-rw-r--r--arch/arm64/kvm/inject_fault.c2
-rw-r--r--arch/arm64/kvm/sys_regs.c168
-rw-r--r--arch/arm64/kvm/sys_regs.h8
-rw-r--r--arch/arm64/kvm/sys_regs_generic_v8.c4
-rw-r--r--arch/arm64/kvm/vgic-v2-switch.S134
-rw-r--r--arch/arm64/kvm/vgic-v3-switch.S269
-rw-r--r--arch/arm64/mm/cache.S28
-rw-r--r--arch/arm64/mm/context.c38
-rw-r--r--arch/arm64/mm/copypage.c3
-rw-r--r--arch/arm64/mm/dma-mapping.c39
-rw-r--r--arch/arm64/mm/fault.c28
-rw-r--r--arch/arm64/mm/flush.c33
-rw-r--r--arch/arm64/mm/hugetlbpage.c274
-rw-r--r--arch/arm64/mm/init.c9
-rw-r--r--arch/arm64/mm/mmu.c114
-rw-r--r--arch/arm64/mm/pgd.c12
-rw-r--r--arch/arm64/mm/proc-macros.S22
-rw-r--r--arch/arm64/mm/proc.S4
-rw-r--r--arch/arm64/net/bpf_jit.h3
-rw-r--r--arch/arm64/net/bpf_jit_comp.c139
-rw-r--r--arch/arm64/xen/hypercall.S1
-rw-r--r--arch/blackfin/include/asm/cmpxchg.h1
-rw-r--r--arch/blackfin/include/asm/uaccess.h6
-rw-r--r--arch/blackfin/kernel/perf_event.c2
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c2
-rw-r--r--arch/blackfin/mach-bf609/boards/ezkit.c6
-rw-r--r--arch/c6x/include/asm/Kbuild1
-rw-r--r--arch/c6x/include/asm/clkdev.h22
-rw-r--r--arch/c6x/include/asm/cmpxchg.h2
-rw-r--r--arch/frv/include/asm/cmpxchg.h2
-rw-r--r--arch/h8300/Kconfig2
-rw-r--r--arch/h8300/Makefile2
-rw-r--r--arch/h8300/boot/compressed/Makefile5
-rw-r--r--arch/h8300/boot/compressed/head.S4
-rw-r--r--arch/h8300/boot/compressed/misc.c7
-rw-r--r--arch/h8300/boot/compressed/vmlinux.lds2
-rw-r--r--arch/h8300/boot/dts/edosk2674.dts6
-rw-r--r--arch/h8300/include/asm/io.h47
-rw-r--r--arch/h8300/include/asm/thread_info.h14
-rw-r--r--arch/h8300/kernel/setup.c10
-rw-r--r--arch/h8300/kernel/vmlinux.lds.S4
-rw-r--r--arch/ia64/include/asm/barrier.h2
-rw-r--r--arch/ia64/include/asm/percpu.h2
-rw-r--r--arch/ia64/include/asm/unistd.h2
-rw-r--r--arch/ia64/include/uapi/asm/unistd.h1
-rw-r--r--arch/ia64/kernel/entry.S1
-rw-r--r--arch/m32r/include/asm/Kbuild1
-rw-r--r--arch/m32r/include/asm/io.h10
-rw-r--r--arch/m68k/atari/config.c4
-rw-r--r--arch/m68k/coldfire/gpio.c2
-rw-r--r--arch/m68k/coldfire/m54xx.c2
-rw-r--r--arch/m68k/configs/amiga_defconfig4
-rw-r--r--arch/m68k/configs/apollo_defconfig5
-rw-r--r--arch/m68k/configs/atari_defconfig4
-rw-r--r--arch/m68k/configs/bvme6000_defconfig4
-rw-r--r--arch/m68k/configs/hp300_defconfig5
-rw-r--r--arch/m68k/configs/mac_defconfig5
-rw-r--r--arch/m68k/configs/multi_defconfig5
-rw-r--r--arch/m68k/configs/mvme147_defconfig4
-rw-r--r--arch/m68k/configs/mvme16x_defconfig4
-rw-r--r--arch/m68k/configs/q40_defconfig5
-rw-r--r--arch/m68k/configs/sun3_defconfig5
-rw-r--r--arch/m68k/configs/sun3x_defconfig5
-rw-r--r--arch/m68k/emu/nfblock.c3
-rw-r--r--arch/m68k/include/asm/mac_psc.h1
-rw-r--r--arch/m68k/include/asm/page.h3
-rw-r--r--arch/m68k/include/asm/uaccess_no.h4
-rw-r--r--arch/m68k/include/asm/unistd.h2
-rw-r--r--arch/m68k/include/uapi/asm/unistd.h1
-rw-r--r--arch/m68k/kernel/setup_no.c9
-rw-r--r--arch/m68k/kernel/syscalltable.S1
-rw-r--r--arch/m68k/mac/macints.c6
-rw-r--r--arch/m68k/mac/psc.c7
-rw-r--r--arch/m68k/mm/motorola.c2
-rw-r--r--arch/m68k/sun3/config.c6
-rw-r--r--arch/metag/include/asm/irq.h8
-rw-r--r--arch/metag/kernel/smp.c2
-rw-r--r--arch/microblaze/kernel/dma.c3
-rw-r--r--arch/mips/Kbuild1
-rw-r--r--arch/mips/Kbuild.platforms1
-rw-r--r--arch/mips/Kconfig88
-rw-r--r--arch/mips/Kconfig.debug72
-rw-r--r--arch/mips/Makefile4
-rw-r--r--arch/mips/ath79/setup.c7
-rw-r--r--arch/mips/bcm47xx/setup.c19
-rw-r--r--arch/mips/bcm47xx/sprom.c46
-rw-r--r--arch/mips/bcm63xx/boards/board_bcm963xx.c14
-rw-r--r--arch/mips/bcm63xx/cpu.c12
-rw-r--r--arch/mips/bcm63xx/dev-pcmcia.c2
-rw-r--r--arch/mips/bcm63xx/irq.c2
-rw-r--r--arch/mips/bcm63xx/setup.c8
-rw-r--r--arch/mips/bcm63xx/timer.c2
-rw-r--r--arch/mips/bmips/setup.c1
-rw-r--r--arch/mips/boot/dts/Makefile1
-rw-r--r--arch/mips/boot/dts/brcm/bcm6328.dtsi1
-rw-r--r--arch/mips/boot/dts/brcm/bcm7125.dtsi1
-rw-r--r--arch/mips/boot/dts/brcm/bcm7346.dtsi115
-rw-r--r--arch/mips/boot/dts/brcm/bcm7358.dtsi63
-rw-r--r--arch/mips/boot/dts/brcm/bcm7360.dtsi63
-rw-r--r--arch/mips/boot/dts/brcm/bcm7362.dtsi95
-rw-r--r--arch/mips/boot/dts/brcm/bcm7420.dtsi1
-rw-r--r--arch/mips/boot/dts/brcm/bcm7425.dtsi43
-rw-r--r--arch/mips/boot/dts/brcm/bcm7435.dtsi1
-rw-r--r--arch/mips/boot/dts/brcm/bcm97346dbsmb.dts28
-rw-r--r--arch/mips/boot/dts/brcm/bcm97358svmb.dts16
-rw-r--r--arch/mips/boot/dts/brcm/bcm97360svmb.dts16
-rw-r--r--arch/mips/boot/dts/brcm/bcm97362svmb.dts20
-rw-r--r--arch/mips/boot/dts/mti/malta.dts4
-rw-r--r--arch/mips/boot/dts/qca/ar9132.dtsi2
-rw-r--r--arch/mips/boot/dts/xilfpga/Makefile9
-rw-r--r--arch/mips/boot/dts/xilfpga/microAptiv.dtsi21
-rw-r--r--arch/mips/boot/dts/xilfpga/nexys4ddr.dts46
-rw-r--r--arch/mips/cavium-octeon/setup.c11
-rw-r--r--arch/mips/configs/bigsur_defconfig12
-rw-r--r--arch/mips/configs/bmips_be_defconfig3
-rw-r--r--arch/mips/configs/bmips_stb_defconfig3
-rw-r--r--arch/mips/configs/capcella_defconfig6
-rw-r--r--arch/mips/configs/e55_defconfig6
-rw-r--r--arch/mips/configs/fuloong2e_defconfig14
-rw-r--r--arch/mips/configs/lasat_defconfig10
-rw-r--r--arch/mips/configs/lemote2f_defconfig11
-rw-r--r--arch/mips/configs/malta_defconfig6
-rw-r--r--arch/mips/configs/malta_kvm_defconfig16
-rw-r--r--arch/mips/configs/malta_kvm_guest_defconfig16
-rw-r--r--arch/mips/configs/malta_qemu_32r6_defconfig11
-rw-r--r--arch/mips/configs/maltaaprp_defconfig11
-rw-r--r--arch/mips/configs/maltasmvp_eva_defconfig11
-rw-r--r--arch/mips/configs/maltaup_defconfig11
-rw-r--r--arch/mips/configs/maltaup_xpa_defconfig16
-rw-r--r--arch/mips/configs/mpc30x_defconfig6
-rw-r--r--arch/mips/configs/xilfpga_defconfig40
-rw-r--r--arch/mips/include/asm/abi.h5
-rw-r--r--arch/mips/include/asm/atomic.h2
-rw-r--r--arch/mips/include/asm/bcache.h27
-rw-r--r--arch/mips/include/asm/cdmm.h11
-rw-r--r--arch/mips/include/asm/clocksource.h29
-rw-r--r--arch/mips/include/asm/compat.h62
-rw-r--r--arch/mips/include/asm/cpu-features.h6
-rw-r--r--arch/mips/include/asm/debug.h22
-rw-r--r--arch/mips/include/asm/elf.h7
-rw-r--r--arch/mips/include/asm/fw/fw.h16
-rw-r--r--arch/mips/include/asm/mach-bcm47xx/bcm47xx.h5
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h14
-rw-r--r--arch/mips/include/asm/mach-malta/malta-dtshim.h29
-rw-r--r--arch/mips/include/asm/mach-ralink/mt7620.h8
-rw-r--r--arch/mips/include/asm/mach-ralink/ralink_regs.h17
-rw-r--r--arch/mips/include/asm/mach-ralink/rt305x.h21
-rw-r--r--arch/mips/include/asm/mach-xilfpga/irq.h18
-rw-r--r--arch/mips/include/asm/mips-cm.h78
-rw-r--r--arch/mips/include/asm/mips-cpc.h3
-rw-r--r--arch/mips/include/asm/mipsregs.h18
-rw-r--r--arch/mips/include/asm/page.h5
-rw-r--r--arch/mips/include/asm/processor.h8
-rw-r--r--arch/mips/include/asm/uaccess.h52
-rw-r--r--arch/mips/include/asm/vdso.h139
-rw-r--r--arch/mips/include/uapi/asm/Kbuild2
-rw-r--r--arch/mips/include/uapi/asm/auxvec.h17
-rw-r--r--arch/mips/jz4740/board-qi_lb60.c13
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/cps-vec-ns16550.S202
-rw-r--r--arch/mips/kernel/cps-vec.S46
-rw-r--r--arch/mips/kernel/cpu-probe.c3
-rw-r--r--arch/mips/kernel/csrc-r4k.c44
-rw-r--r--arch/mips/kernel/idle.c17
-rw-r--r--arch/mips/kernel/mips-cm.c114
-rw-r--r--arch/mips/kernel/mips-cpc.c6
-rw-r--r--arch/mips/kernel/mips-r2-to-r6-emul.c2
-rw-r--r--arch/mips/kernel/mips_ksyms.c2
-rw-r--r--arch/mips/kernel/segment.c2
-rw-r--r--arch/mips/kernel/setup.c29
-rw-r--r--arch/mips/kernel/signal.c12
-rw-r--r--arch/mips/kernel/signal32.c7
-rw-r--r--arch/mips/kernel/signal_n32.c5
-rw-r--r--arch/mips/kernel/smp-cps.c35
-rw-r--r--arch/mips/kernel/smp-gic.c2
-rw-r--r--arch/mips/kernel/spinlock_test.c4
-rw-r--r--arch/mips/kernel/stacktrace.c27
-rw-r--r--arch/mips/kernel/traps.c11
-rw-r--r--arch/mips/kernel/unaligned.c2
-rw-r--r--arch/mips/kernel/vdso.c207
-rw-r--r--arch/mips/kernel/vmlinux.lds.S15
-rw-r--r--arch/mips/kvm/emulate.c2
-rw-r--r--arch/mips/kvm/locore.S24
-rw-r--r--arch/mips/kvm/mips.c5
-rw-r--r--arch/mips/lantiq/clk.c17
-rw-r--r--arch/mips/lantiq/clk.h13
-rw-r--r--arch/mips/lantiq/irq.c8
-rw-r--r--arch/mips/lantiq/prom.c2
-rw-r--r--arch/mips/lantiq/xway/clk.c180
-rw-r--r--arch/mips/lantiq/xway/prom.c35
-rw-r--r--arch/mips/lantiq/xway/reset.c196
-rw-r--r--arch/mips/lantiq/xway/sysctrl.c301
-rw-r--r--arch/mips/lasat/picvue_proc.c18
-rw-r--r--arch/mips/lib/Makefile2
-rw-r--r--arch/mips/lib/bswapdi.c15
-rw-r--r--arch/mips/lib/bswapsi.c11
-rw-r--r--arch/mips/lib/memset.S2
-rw-r--r--arch/mips/loongson64/Kconfig5
-rw-r--r--arch/mips/loongson64/common/Makefile2
-rw-r--r--arch/mips/loongson64/lemote-2f/Makefile2
-rw-r--r--arch/mips/math-emu/me-debugfs.c2
-rw-r--r--arch/mips/mm/Makefile1
-rw-r--r--arch/mips/mm/dma-default.c2
-rw-r--r--arch/mips/mm/sc-debugfs.c81
-rw-r--r--arch/mips/mm/sc-mips.c65
-rw-r--r--arch/mips/mm/tlbex.c97
-rw-r--r--arch/mips/mti-malta/Makefile15
-rw-r--r--arch/mips/mti-malta/malta-dtshim.c162
-rw-r--r--arch/mips/mti-malta/malta-init.c1
-rw-r--r--arch/mips/mti-malta/malta-memory.c131
-rw-r--r--arch/mips/mti-malta/malta-setup.c5
-rw-r--r--arch/mips/net/bpf_jit.c16
-rw-r--r--arch/mips/netlogic/xlp/dt.c1
-rw-r--r--arch/mips/pci/pci-rt2880.c5
-rw-r--r--arch/mips/pci/pci-rt3883.c6
-rw-r--r--arch/mips/pistachio/init.c1
-rw-r--r--arch/mips/pmcs-msp71xx/msp_setup.c5
-rw-r--r--arch/mips/ralink/cevt-rt3352.c2
-rw-r--r--arch/mips/ralink/early_printk.c26
-rw-r--r--arch/mips/ralink/mt7620.c63
-rw-r--r--arch/mips/ralink/of.c2
-rw-r--r--arch/mips/ralink/prom.c5
-rw-r--r--arch/mips/ralink/reset.c13
-rw-r--r--arch/mips/ralink/rt288x.c1
-rw-r--r--arch/mips/ralink/rt305x.c13
-rw-r--r--arch/mips/ralink/rt3883.c2
-rw-r--r--arch/mips/sni/reset.c8
-rw-r--r--arch/mips/vdso/.gitignore4
-rw-r--r--arch/mips/vdso/Makefile160
-rw-r--r--arch/mips/vdso/elf.S68
-rw-r--r--arch/mips/vdso/genvdso.c293
-rw-r--r--arch/mips/vdso/genvdso.h187
-rw-r--r--arch/mips/vdso/gettimeofday.c232
-rw-r--r--arch/mips/vdso/sigreturn.S49
-rw-r--r--arch/mips/vdso/vdso.h89
-rw-r--r--arch/mips/vdso/vdso.lds.S105
-rw-r--r--arch/mips/xilfpga/Kconfig9
-rw-r--r--arch/mips/xilfpga/Makefile7
-rw-r--r--arch/mips/xilfpga/Platform3
-rw-r--r--arch/mips/xilfpga/init.c57
-rw-r--r--arch/mips/xilfpga/intc.c25
-rw-r--r--arch/mips/xilfpga/time.c41
-rw-r--r--arch/mn10300/Kconfig4
-rw-r--r--arch/mn10300/include/asm/uaccess.h15
-rw-r--r--arch/nios2/mm/cacheflush.c24
-rw-r--r--arch/parisc/Kconfig3
-rw-r--r--arch/parisc/include/asm/hugetlb.h85
-rw-r--r--arch/parisc/include/asm/page.h13
-rw-r--r--arch/parisc/include/asm/pgalloc.h2
-rw-r--r--arch/parisc/include/asm/pgtable.h27
-rw-r--r--arch/parisc/include/asm/processor.h27
-rw-r--r--arch/parisc/include/uapi/asm/mman.h10
-rw-r--r--arch/parisc/include/uapi/asm/unistd.h3
-rw-r--r--arch/parisc/kernel/asm-offsets.c8
-rw-r--r--arch/parisc/kernel/entry.S56
-rw-r--r--arch/parisc/kernel/head.S4
-rw-r--r--arch/parisc/kernel/pci.c18
-rw-r--r--arch/parisc/kernel/setup.c14
-rw-r--r--arch/parisc/kernel/signal.c64
-rw-r--r--arch/parisc/kernel/syscall.S4
-rw-r--r--arch/parisc/kernel/syscall_table.S1
-rw-r--r--arch/parisc/kernel/traps.c35
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S9
-rw-r--r--arch/parisc/mm/Makefile1
-rw-r--r--arch/parisc/mm/hugetlbpage.c161
-rw-r--r--arch/parisc/mm/init.c40
-rw-r--r--arch/powerpc/boot/dts/sbc8641d.dts8
-rw-r--r--arch/powerpc/include/asm/barrier.h2
-rw-r--r--arch/powerpc/include/asm/kvm_host.h4
-rw-r--r--arch/powerpc/include/asm/reg.h1
-rw-r--r--arch/powerpc/include/asm/systbl.h25
-rw-r--r--arch/powerpc/include/asm/uaccess.h15
-rw-r--r--arch/powerpc/include/asm/unistd.h2
-rw-r--r--arch/powerpc/include/uapi/asm/unistd.h13
-rw-r--r--arch/powerpc/kernel/eeh_driver.c14
-rw-r--r--arch/powerpc/kernel/nvram_64.c19
-rw-r--r--arch/powerpc/kernel/process.c18
-rw-r--r--arch/powerpc/kernel/signal_32.c14
-rw-r--r--arch/powerpc/kernel/signal_64.c4
-rw-r--r--arch/powerpc/kvm/book3s_hv.c18
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S20
-rw-r--r--arch/powerpc/kvm/book3s_pr.c4
-rw-r--r--arch/powerpc/net/bpf_jit_comp.c13
-rw-r--r--arch/powerpc/platforms/powernv/opal-irqchip.c64
-rw-r--r--arch/powerpc/platforms/powernv/opal.c2
-rw-r--r--arch/powerpc/sysdev/axonram.c5
-rw-r--r--arch/powerpc/sysdev/fsl_pci.c28
-rw-r--r--arch/powerpc/sysdev/fsl_pci.h9
-rw-r--r--arch/s390/include/asm/barrier.h2
-rw-r--r--arch/s390/include/asm/cio.h1
-rw-r--r--arch/s390/include/asm/elf.h20
-rw-r--r--arch/s390/include/asm/ipl.h3
-rw-r--r--arch/s390/include/asm/kvm_host.h57
-rw-r--r--arch/s390/include/asm/pci_dma.h4
-rw-r--r--arch/s390/include/asm/sclp.h8
-rw-r--r--arch/s390/include/asm/trace/diag.h6
-rw-r--r--arch/s390/include/uapi/asm/kvm.h5
-rw-r--r--arch/s390/include/uapi/asm/unistd.h19
-rw-r--r--arch/s390/kernel/compat_wrapper.c1
-rw-r--r--arch/s390/kernel/diag.c4
-rw-r--r--arch/s390/kernel/dis.c17
-rw-r--r--arch/s390/kernel/head.S95
-rw-r--r--arch/s390/kernel/ipl.c65
-rw-r--r--arch/s390/kernel/process.c6
-rw-r--r--arch/s390/kernel/processor.c6
-rw-r--r--arch/s390/kernel/sclp.c2
-rw-r--r--arch/s390/kernel/setup.c12
-rw-r--r--arch/s390/kernel/syscalls.S1
-rw-r--r--arch/s390/kernel/trace.c6
-rw-r--r--arch/s390/kvm/diag.c11
-rw-r--r--arch/s390/kvm/gaccess.c38
-rw-r--r--arch/s390/kvm/intercept.c7
-rw-r--r--arch/s390/kvm/interrupt.c140
-rw-r--r--arch/s390/kvm/kvm-s390.c306
-rw-r--r--arch/s390/kvm/kvm-s390.h7
-rw-r--r--arch/s390/kvm/priv.c2
-rw-r--r--arch/s390/kvm/sigp.c8
-rw-r--r--arch/s390/kvm/trace-s390.h6
-rw-r--r--arch/s390/mm/init.c30
-rw-r--r--arch/s390/mm/mmap.c60
-rw-r--r--arch/s390/mm/pgtable.c4
-rw-r--r--arch/s390/pci/pci_dma.c87
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c6
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c10
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c4
-rw-r--r--arch/sh/boards/mach-migor/setup.c6
-rw-r--r--arch/sh/boards/mach-se/7724/setup.c6
-rw-r--r--arch/sh/include/uapi/asm/unistd_64.h2
-rw-r--r--arch/sh/kernel/perf_event.c2
-rw-r--r--arch/sparc/include/asm/elf_64.h1
-rw-r--r--arch/sparc/include/asm/uaccess_32.h65
-rw-r--r--arch/sparc/include/asm/uaccess_64.h40
-rw-r--r--arch/sparc/include/uapi/asm/unistd.h7
-rw-r--r--arch/sparc/kernel/head_64.S13
-rw-r--r--arch/sparc/kernel/mdesc.c20
-rw-r--r--arch/sparc/kernel/perf_event.c13
-rw-r--r--arch/sparc/kernel/rtrap_64.S8
-rw-r--r--arch/sparc/kernel/setup_64.c9
-rw-r--r--arch/sparc/kernel/systbls_32.S19
-rw-r--r--arch/sparc/kernel/systbls_64.S18
-rw-r--r--arch/sparc/lib/NG2copy_from_user.S8
-rw-r--r--arch/sparc/lib/NG2copy_to_user.S8
-rw-r--r--arch/sparc/lib/NG2memcpy.S118
-rw-r--r--arch/sparc/lib/NG4copy_from_user.S8
-rw-r--r--arch/sparc/lib/NG4copy_to_user.S8
-rw-r--r--arch/sparc/lib/NG4memcpy.S40
-rw-r--r--arch/sparc/lib/U1copy_from_user.S8
-rw-r--r--arch/sparc/lib/U1copy_to_user.S8
-rw-r--r--arch/sparc/lib/U1memcpy.S48
-rw-r--r--arch/sparc/lib/U3copy_from_user.S8
-rw-r--r--arch/sparc/lib/U3copy_to_user.S8
-rw-r--r--arch/sparc/lib/U3memcpy.S86
-rw-r--r--arch/sparc/net/bpf_jit_comp.c17
-rw-r--r--arch/tile/Kconfig11
-rw-r--r--arch/tile/include/asm/cmpxchg.h2
-rw-r--r--arch/tile/include/asm/page.h8
-rw-r--r--arch/tile/kernel/perf_event.c2
-rw-r--r--arch/um/Kconfig.common1
-rw-r--r--arch/um/Kconfig.um16
-rw-r--r--arch/um/drivers/hostaudio_kern.c10
-rw-r--r--arch/um/drivers/mconsole_kern.c14
-rw-r--r--arch/um/drivers/net_kern.c17
-rw-r--r--arch/um/drivers/net_user.c10
-rw-r--r--arch/um/drivers/ubd_kern.c27
-rw-r--r--arch/um/include/asm/hardirq.h23
-rw-r--r--arch/um/include/asm/ptrace-generic.h2
-rw-r--r--arch/um/include/asm/syscall-generic.h138
-rw-r--r--arch/um/include/asm/thread_info.h2
-rw-r--r--arch/um/include/shared/os.h20
-rw-r--r--arch/um/include/shared/skas/stub-data.h7
-rw-r--r--arch/um/include/shared/timer-internal.h13
-rw-r--r--arch/um/kernel/process.c8
-rw-r--r--arch/um/kernel/signal.c2
-rw-r--r--arch/um/kernel/skas/clone.c6
-rw-r--r--arch/um/kernel/skas/mmu.c3
-rw-r--r--arch/um/kernel/skas/syscall.c40
-rw-r--r--arch/um/kernel/time.c73
-rw-r--r--arch/um/kernel/tlb.c16
-rw-r--r--arch/um/os-Linux/file.c19
-rw-r--r--arch/um/os-Linux/internal.h1
-rw-r--r--arch/um/os-Linux/main.c7
-rw-r--r--arch/um/os-Linux/mem.c17
-rw-r--r--arch/um/os-Linux/process.c6
-rw-r--r--arch/um/os-Linux/signal.c55
-rw-r--r--arch/um/os-Linux/skas/process.c48
-rw-r--r--arch/um/os-Linux/start_up.c2
-rw-r--r--arch/um/os-Linux/time.c249
-rw-r--r--arch/unicore32/kernel/puv3-nb0916.c10
-rw-r--r--arch/x86/Kconfig19
-rw-r--r--arch/x86/Kconfig.debug2
-rw-r--r--arch/x86/boot/boot.h1
-rw-r--r--arch/x86/boot/video-mode.c2
-rw-r--r--arch/x86/boot/video.c2
-rw-r--r--arch/x86/crypto/chacha20_glue.c2
-rw-r--r--arch/x86/crypto/crc32c-intel_glue.c2
-rw-r--r--arch/x86/entry/calling.h15
-rw-r--r--arch/x86/entry/common.c6
-rw-r--r--arch/x86/entry/entry_32.S15
-rw-r--r--arch/x86/entry/entry_64.S27
-rw-r--r--arch/x86/entry/entry_64_compat.S40
-rw-r--r--arch/x86/entry/syscalls/syscall_32.tbl1
-rw-r--r--arch/x86/entry/syscalls/syscall_64.tbl1
-rw-r--r--arch/x86/entry/vdso/vclock_gettime.c151
-rw-r--r--arch/x86/entry/vdso/vdso-layout.lds.S3
-rw-r--r--arch/x86/entry/vdso/vdso2c.c3
-rw-r--r--arch/x86/entry/vdso/vdso32/system_call.S54
-rw-r--r--arch/x86/entry/vdso/vma.c14
-rw-r--r--arch/x86/include/asm/apic.h6
-rw-r--r--arch/x86/include/asm/atomic.h1
-rw-r--r--arch/x86/include/asm/atomic64_32.h1
-rw-r--r--arch/x86/include/asm/calgary.h2
-rw-r--r--arch/x86/include/asm/cmpxchg_32.h2
-rw-r--r--arch/x86/include/asm/cmpxchg_64.h2
-rw-r--r--arch/x86/include/asm/cpu.h3
-rw-r--r--arch/x86/include/asm/cpufeature.h116
-rw-r--r--arch/x86/include/asm/fixmap.h5
-rw-r--r--arch/x86/include/asm/fpu/internal.h173
-rw-r--r--arch/x86/include/asm/i8259.h1
-rw-r--r--arch/x86/include/asm/intel_pt.h10
-rw-r--r--arch/x86/include/asm/ipi.h2
-rw-r--r--arch/x86/include/asm/jump_label.h63
-rw-r--r--arch/x86/include/asm/kvm_host.h102
-rw-r--r--arch/x86/include/asm/microcode.h39
-rw-r--r--arch/x86/include/asm/msi.h6
-rw-r--r--arch/x86/include/asm/msr-index.h4
-rw-r--r--arch/x86/include/asm/msr-trace.h57
-rw-r--r--arch/x86/include/asm/msr.h43
-rw-r--r--arch/x86/include/asm/page_types.h22
-rw-r--r--arch/x86/include/asm/paravirt.h44
-rw-r--r--arch/x86/include/asm/paravirt_types.h40
-rw-r--r--arch/x86/include/asm/pgtable.h15
-rw-r--r--arch/x86/include/asm/pgtable_types.h14
-rw-r--r--arch/x86/include/asm/processor.h1
-rw-r--r--arch/x86/include/asm/pvclock.h14
-rw-r--r--arch/x86/include/asm/qspinlock_paravirt.h59
-rw-r--r--arch/x86/include/asm/reboot.h1
-rw-r--r--arch/x86/include/asm/smp.h12
-rw-r--r--arch/x86/include/asm/suspend_32.h1
-rw-r--r--arch/x86/include/asm/suspend_64.h1
-rw-r--r--arch/x86/include/asm/uaccess.h9
-rw-r--r--arch/x86/include/asm/vdso.h1
-rw-r--r--arch/x86/include/asm/vmx.h3
-rw-r--r--arch/x86/include/asm/x86_init.h3
-rw-r--r--arch/x86/include/asm/xen/hypercall.h6
-rw-r--r--arch/x86/include/asm/xor_32.h2
-rw-r--r--arch/x86/include/uapi/asm/hyperv.h92
-rw-r--r--arch/x86/include/uapi/asm/mce.h2
-rw-r--r--arch/x86/include/uapi/asm/svm.h1
-rw-r--r--arch/x86/kernel/apic/apic.c45
-rw-r--r--arch/x86/kernel/apic/apic_flat_64.c19
-rw-r--r--arch/x86/kernel/apic/apic_noop.c2
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c7
-rw-r--r--arch/x86/kernel/apic/bigsmp_32.c10
-rw-r--r--arch/x86/kernel/apic/ipi.c18
-rw-r--r--arch/x86/kernel/apic/msi.c8
-rw-r--r--arch/x86/kernel/apic/probe_32.c1
-rw-r--r--arch/x86/kernel/apic/vector.c8
-rw-r--r--arch/x86/kernel/apic/x2apic_cluster.c9
-rw-r--r--arch/x86/kernel/apic/x2apic_phys.c9
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c1
-rw-r--r--arch/x86/kernel/asm-offsets.c3
-rw-r--r--arch/x86/kernel/asm-offsets_64.c1
-rw-r--r--arch/x86/kernel/cpu/amd.c21
-rw-r--r--arch/x86/kernel/cpu/centaur.c2
-rw-r--r--arch/x86/kernel/cpu/common.c68
-rw-r--r--arch/x86/kernel/cpu/intel.c4
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c6
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c93
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c13
-rw-r--r--arch/x86/kernel/cpu/microcode/intel.c16
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c11
-rw-r--r--arch/x86/kernel/cpu/mtrr/generic.c2
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event.c38
-rw-r--r--arch/x86/kernel/cpu/perf_event.h26
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd.c6
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_uncore.c11
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel.c117
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_cqm.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c39
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_lbr.c46
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_pt.c9
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_rapl.c31
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.c17
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore.h3
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c2
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c635
-rw-r--r--arch/x86/kernel/cpu/rdrand.c25
-rw-r--r--arch/x86/kernel/cpu/scattered.c20
-rw-r--r--arch/x86/kernel/cpu/transmeta.c4
-rw-r--r--arch/x86/kernel/cpuid.c24
-rw-r--r--arch/x86/kernel/crash.c11
-rw-r--r--arch/x86/kernel/fpu/init.c21
-rw-r--r--arch/x86/kernel/fpu/signal.c11
-rw-r--r--arch/x86/kernel/fpu/xstate.c5
-rw-r--r--arch/x86/kernel/head_64.S8
-rw-r--r--arch/x86/kernel/hw_breakpoint.c6
-rw-r--r--arch/x86/kernel/i8259.c29
-rw-r--r--arch/x86/kernel/irq_work.c2
-rw-r--r--arch/x86/kernel/kvmclock.c11
-rw-r--r--arch/x86/kernel/mcount_64.S6
-rw-r--r--arch/x86/kernel/msr.c24
-rw-r--r--arch/x86/kernel/nmi.c32
-rw-r--r--arch/x86/kernel/paravirt.c36
-rw-r--r--arch/x86/kernel/paravirt_patch_32.c2
-rw-r--r--arch/x86/kernel/paravirt_patch_64.c3
-rw-r--r--arch/x86/kernel/pci-calgary_64.c4
-rw-r--r--arch/x86/kernel/pci-swiotlb.c2
-rw-r--r--arch/x86/kernel/pmem.c12
-rw-r--r--arch/x86/kernel/process_64.c2
-rw-r--r--arch/x86/kernel/ptrace.c15
-rw-r--r--arch/x86/kernel/pvclock.c24
-rw-r--r--arch/x86/kernel/reboot.c30
-rw-r--r--arch/x86/kernel/rtc.c3
-rw-r--r--arch/x86/kernel/setup.c6
-rw-r--r--arch/x86/kernel/signal.c17
-rw-r--r--arch/x86/kernel/smp.c4
-rw-r--r--arch/x86/kernel/smpboot.c18
-rw-r--r--arch/x86/kernel/tsc.c2
-rw-r--r--arch/x86/kernel/verify_cpu.S12
-rw-r--r--arch/x86/kernel/vm86_32.c4
-rw-r--r--arch/x86/kernel/x86_init.c1
-rw-r--r--arch/x86/kvm/cpuid.h42
-rw-r--r--arch/x86/kvm/hyperv.c708
-rw-r--r--arch/x86/kvm/hyperv.h55
-rw-r--r--arch/x86/kvm/i8254.c1
-rw-r--r--arch/x86/kvm/ioapic.c4
-rw-r--r--arch/x86/kvm/ioapic.h7
-rw-r--r--arch/x86/kvm/irq.c2
-rw-r--r--arch/x86/kvm/irq_comm.c41
-rw-r--r--arch/x86/kvm/lapic.c44
-rw-r--r--arch/x86/kvm/lapic.h9
-rw-r--r--arch/x86/kvm/mmu.c417
-rw-r--r--arch/x86/kvm/mmu.h6
-rw-r--r--arch/x86/kvm/mmu_audit.c15
-rw-r--r--arch/x86/kvm/mtrr.c25
-rw-r--r--arch/x86/kvm/paging_tmpl.h23
-rw-r--r--arch/x86/kvm/svm.c198
-rw-r--r--arch/x86/kvm/trace.h265
-rw-r--r--arch/x86/kvm/vmx.c277
-rw-r--r--arch/x86/kvm/x86.c343
-rw-r--r--arch/x86/lguest/boot.c2
-rw-r--r--arch/x86/lib/Makefile2
-rw-r--r--arch/x86/lib/cpu.c35
-rw-r--r--arch/x86/lib/msr.c26
-rw-r--r--arch/x86/mm/Makefile1
-rw-r--r--arch/x86/mm/debug_pagetables.c46
-rw-r--r--arch/x86/mm/dump_pagetables.c53
-rw-r--r--arch/x86/mm/init.c4
-rw-r--r--arch/x86/mm/init_64.c4
-rw-r--r--arch/x86/mm/ioremap.c4
-rw-r--r--arch/x86/mm/mpx.c53
-rw-r--r--arch/x86/mm/pageattr.c10
-rw-r--r--arch/x86/mm/pat.c12
-rw-r--r--arch/x86/mm/pat_rbtree.c52
-rw-r--r--arch/x86/mm/pgtable.c7
-rw-r--r--arch/x86/mm/setup_nx.c4
-rw-r--r--arch/x86/mm/srat.c2
-rw-r--r--arch/x86/pci/bus_numa.c13
-rw-r--r--arch/x86/platform/uv/uv_nmi.c1
-rw-r--r--arch/x86/power/cpu.c92
-rw-r--r--arch/x86/um/Makefile2
-rw-r--r--arch/x86/um/asm/syscall.h1
-rw-r--r--arch/x86/um/ptrace_32.c8
-rw-r--r--arch/x86/um/signal.c18
-rw-r--r--arch/x86/um/stub_32.S1
-rw-r--r--arch/x86/um/stub_64.S18
-rw-r--r--arch/x86/xen/apic.c2
-rw-r--r--arch/x86/xen/enlighten.c26
-rw-r--r--arch/x86/xen/mmu.c10
-rw-r--r--arch/x86/xen/suspend.c24
-rw-r--r--arch/x86/xen/time.c115
-rw-r--r--arch/x86/xen/xen-asm_32.S14
-rw-r--r--arch/x86/xen/xen-asm_64.S19
-rw-r--r--arch/x86/xen/xen-ops.h3
-rw-r--r--arch/xtensa/platforms/iss/simdisk.c15
-rw-r--r--block/blk-cgroup.c6
-rw-r--r--block/blk-core.c123
-rw-r--r--block/blk-merge.c35
-rw-r--r--block/blk-mq-sysfs.c10
-rw-r--r--block/blk-mq.c75
-rw-r--r--block/blk-mq.h1
-rw-r--r--block/blk-settings.c36
-rw-r--r--block/blk-sysfs.c38
-rw-r--r--block/blk-timeout.c8
-rw-r--r--block/blk.h2
-rw-r--r--block/noop-iosched.c10
-rw-r--r--block/partition-generic.c2
-rw-r--r--block/partitions/mac.c10
-rw-r--r--crypto/ablkcipher.c2
-rw-r--r--crypto/algif_aead.c4
-rw-r--r--crypto/algif_hash.c12
-rw-r--r--crypto/algif_skcipher.c67
-rw-r--r--crypto/asymmetric_keys/x509_cert_parser.c12
-rw-r--r--crypto/async_tx/async_memcpy.c2
-rw-r--r--crypto/async_tx/async_pq.c4
-rw-r--r--crypto/async_tx/async_raid6_recov.c4
-rw-r--r--crypto/async_tx/async_xor.c4
-rw-r--r--crypto/blkcipher.c2
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acpi/Kconfig4
-rw-r--r--drivers/acpi/acpi_platform.c7
-rw-r--r--drivers/acpi/acpi_video.c78
-rw-r--r--drivers/acpi/cppc_acpi.c2
-rw-r--r--drivers/acpi/device_sysfs.c2
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/glue.c8
-rw-r--r--drivers/acpi/nfit.c331
-rw-r--r--drivers/acpi/nfit.h5
-rw-r--r--drivers/acpi/pci_root.c7
-rw-r--r--drivers/acpi/processor_driver.c3
-rw-r--r--drivers/acpi/sbshc.c48
-rw-r--r--drivers/acpi/scan.c42
-rw-r--r--drivers/acpi/thermal.c12
-rw-r--r--drivers/acpi/video_detect.c9
-rw-r--r--drivers/ata/Kconfig2
-rw-r--r--drivers/ata/ahci.c89
-rw-r--r--drivers/ata/ahci.h27
-rw-r--r--drivers/ata/ahci_brcmstb.c61
-rw-r--r--drivers/ata/ahci_mvebu.c5
-rw-r--r--drivers/ata/ahci_qoriq.c31
-rw-r--r--drivers/ata/libahci.c55
-rw-r--r--drivers/ata/libata-core.c20
-rw-r--r--drivers/ata/libata-eh.c8
-rw-r--r--drivers/ata/libata-scsi.c3
-rw-r--r--drivers/ata/sata_fsl.c3
-rw-r--r--drivers/ata/sata_rcar.c19
-rw-r--r--drivers/ata/sata_sil.c3
-rw-r--r--drivers/ata/sata_sx4.c2
-rw-r--r--drivers/base/component.c281
-rw-r--r--drivers/base/devres.c19
-rw-r--r--drivers/base/memory.c4
-rw-r--r--drivers/base/platform-msi.c256
-rw-r--r--drivers/base/platform.c20
-rw-r--r--drivers/base/power/clock_ops.c6
-rw-r--r--drivers/base/power/domain.c57
-rw-r--r--drivers/base/power/domain_governor.c3
-rw-r--r--drivers/base/power/opp/core.c48
-rw-r--r--drivers/base/power/opp/cpu.c13
-rw-r--r--drivers/base/power/opp/opp.h3
-rw-r--r--drivers/base/power/wakeirq.c6
-rw-r--r--drivers/base/property.c32
-rw-r--r--drivers/base/regmap/regcache-flat.c2
-rw-r--r--drivers/base/regmap/regcache-lzo.c6
-rw-r--r--drivers/base/regmap/regcache-rbtree.c18
-rw-r--r--drivers/base/regmap/regcache.c41
-rw-r--r--drivers/base/regmap/regmap-debugfs.c69
-rw-r--r--drivers/base/regmap/regmap-irq.c113
-rw-r--r--drivers/base/regmap/regmap-mmio.c66
-rw-r--r--drivers/base/regmap/regmap.c118
-rw-r--r--drivers/block/brd.c8
-rw-r--r--drivers/block/cciss.c14
-rw-r--r--drivers/block/drbd/drbd_int.h2
-rw-r--r--drivers/block/drbd/drbd_req.c3
-rw-r--r--drivers/block/mtip32xx/mtip32xx.c29
-rw-r--r--drivers/block/nbd.c1
-rw-r--r--drivers/block/null_blk.c317
-rw-r--r--drivers/block/pktcdvd.c9
-rw-r--r--drivers/block/ps3vram.c6
-rw-r--r--drivers/block/rbd.c110
-rw-r--r--drivers/block/rsxx/core.c11
-rw-r--r--drivers/block/rsxx/dev.c5
-rw-r--r--drivers/block/umem.c4
-rw-r--r--drivers/block/xen-blkback/blkback.c15
-rw-r--r--drivers/block/xen-blkback/common.h8
-rw-r--r--drivers/block/zram/zram_drv.c5
-rw-r--r--drivers/bluetooth/btusb.c6
-rw-r--r--drivers/bus/Kconfig11
-rw-r--r--drivers/bus/Makefile1
-rw-r--r--drivers/bus/omap-ocp2scp.c2
-rw-r--r--drivers/bus/sunxi-rsb.c783
-rw-r--r--drivers/cdrom/cdrom.c10
-rw-r--r--drivers/char/generic_nvram.c21
-rw-r--r--drivers/char/hw_random/via-rng.c5
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c90
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c8
-rw-r--r--drivers/char/mbcs.c28
-rw-r--r--drivers/char/nvram.c18
-rw-r--r--drivers/char/nwflash.c31
-rw-r--r--drivers/char/tpm/tpm-chip.c20
-rw-r--r--drivers/char/tpm/tpm2-cmd.c15
-rw-r--r--drivers/char/tpm/tpm_of.c3
-rw-r--r--drivers/char/tpm/tpm_tis.c8
-rw-r--r--drivers/clk/Kconfig10
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/berlin/bg2q.c14
-rw-r--r--drivers/clk/clk-gpio.c33
-rw-r--r--drivers/clk/clk-qoriq.c4
-rw-r--r--drivers/clk/clk-scpi.c326
-rw-r--r--drivers/clk/h8300/clk-div.c6
-rw-r--r--drivers/clk/imx/clk-pllv1.c14
-rw-r--r--drivers/clk/imx/clk-pllv2.c9
-rw-r--r--drivers/clk/imx/clk-vf610.c8
-rw-r--r--drivers/clk/mmp/clk-mmp2.c1
-rw-r--r--drivers/clk/mmp/clk-pxa168.c1
-rw-r--r--drivers/clk/mmp/clk-pxa910.c1
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c14
-rw-r--r--drivers/clk/shmobile/clk-mstp.c4
-rw-r--r--drivers/clk/sunxi/clk-a10-pll2.c23
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c1
-rw-r--r--drivers/clk/ti/clk-816x.c2
-rw-r--r--drivers/clk/ti/clkt_dpll.c4
-rw-r--r--drivers/clk/ti/divider.c16
-rw-r--r--drivers/clk/ti/fapll.c4
-rw-r--r--drivers/clk/ti/mux.c15
-rw-r--r--drivers/clocksource/Kconfig141
-rw-r--r--drivers/clocksource/Makefile3
-rw-r--r--drivers/clocksource/acpi_pm.c27
-rw-r--r--drivers/clocksource/arm_global_timer.c21
-rw-r--r--drivers/clocksource/dw_apb_timer.c46
-rw-r--r--drivers/clocksource/dw_apb_timer_of.c16
-rw-r--r--drivers/clocksource/fsl_ftm_timer.c4
-rw-r--r--drivers/clocksource/h8300_timer16.c222
-rw-r--r--drivers/clocksource/h8300_timer8.c264
-rw-r--r--drivers/clocksource/h8300_tpu.c159
-rw-r--r--drivers/clocksource/mips-gic-timer.c7
-rw-r--r--drivers/clocksource/mmio.c2
-rw-r--r--drivers/clocksource/mtk_timer.c20
-rw-r--r--drivers/clocksource/rockchip_timer.c23
-rw-r--r--drivers/clocksource/tango_xtal.c18
-rw-r--r--drivers/clocksource/tcb_clksrc.c12
-rw-r--r--drivers/clocksource/tegra20_timer.c3
-rw-r--r--drivers/clocksource/time-lpc32xx.c4
-rw-r--r--drivers/clocksource/time-pistachio.c2
-rw-r--r--drivers/clocksource/timer-atmel-st.c31
-rw-r--r--drivers/clocksource/timer-sun5i.c16
-rw-r--r--drivers/clocksource/timer-ti-32k.c126
-rw-r--r--drivers/clocksource/vt8500_timer.c1
-rw-r--r--drivers/connector/connector.c11
-rw-r--r--drivers/cpufreq/Kconfig.arm13
-rw-r--r--drivers/cpufreq/Kconfig.x861
-rw-r--r--drivers/cpufreq/Makefile1
-rw-r--r--drivers/cpufreq/arm_big_little.c22
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c6
-rw-r--r--drivers/cpufreq/cpufreq.c21
-rw-r--r--drivers/cpufreq/cpufreq_governor.c33
-rw-r--r--drivers/cpufreq/intel_pstate.c332
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c2
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c4
-rw-r--r--drivers/cpufreq/scpi-cpufreq.c124
-rw-r--r--drivers/crypto/ccp/ccp-platform.c15
-rw-r--r--drivers/crypto/nx/nx-aes-ccm.c2
-rw-r--r--drivers/crypto/nx/nx-aes-gcm.c3
-rw-r--r--drivers/crypto/padlock-aes.c2
-rw-r--r--drivers/crypto/padlock-sha.c2
-rw-r--r--drivers/crypto/qat/qat_common/adf_ctl_drv.c2
-rw-r--r--drivers/crypto/talitos.c2
-rw-r--r--drivers/dma/at_hdmac.c20
-rw-r--r--drivers/dma/at_hdmac_regs.h6
-rw-r--r--drivers/dma/at_xdmac.c29
-rw-r--r--drivers/dma/bcm2835-dma.c78
-rw-r--r--drivers/dma/edma.c57
-rw-r--r--drivers/dma/imx-sdma.c2
-rw-r--r--drivers/dma/sh/usb-dmac.c11
-rw-r--r--drivers/dma/xgene-dma.c4
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/edac_device.c41
-rw-r--r--drivers/edac/edac_device_sysfs.c11
-rw-r--r--drivers/edac/edac_mc.c29
-rw-r--r--drivers/edac/edac_mc_sysfs.c37
-rw-r--r--drivers/edac/edac_module.c52
-rw-r--r--drivers/edac/edac_module.h10
-rw-r--r--drivers/edac/edac_pci.c70
-rw-r--r--drivers/edac/edac_pci_sysfs.c16
-rw-r--r--drivers/edac/edac_stub.c41
-rw-r--r--drivers/edac/i5100_edac.c4
-rw-r--r--drivers/edac/mpc85xx_edac.c54
-rw-r--r--drivers/edac/mv64x60_edac.c39
-rw-r--r--drivers/edac/sb_edac.c1071
-rw-r--r--drivers/edac/wq.c42
-rw-r--r--drivers/firewire/ohci.c5
-rw-r--r--drivers/firmware/Kconfig29
-rw-r--r--drivers/firmware/Makefile4
-rw-r--r--drivers/firmware/arm_scpi.c771
-rw-r--r--drivers/firmware/dmi_scan.c6
-rw-r--r--drivers/firmware/efi/Makefile4
-rw-r--r--drivers/firmware/efi/arm-init.c209
-rw-r--r--drivers/firmware/efi/arm-runtime.c135
-rw-r--r--drivers/firmware/efi/efi.c2
-rw-r--r--drivers/firmware/efi/libstub/Makefile13
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c4
-rw-r--r--drivers/firmware/efi/libstub/arm32-stub.c85
-rw-r--r--drivers/firmware/psci.c131
-rw-r--r--drivers/firmware/qcom_scm-32.c6
-rw-r--r--drivers/firmware/raspberrypi.c260
-rw-r--r--drivers/fpga/fpga-mgr.c13
-rw-r--r--drivers/gpio/gpio-74xx-mmio.c7
-rw-r--r--drivers/gpio/gpio-ath79.c2
-rw-r--r--drivers/gpio/gpio-generic.c4
-rw-r--r--drivers/gpio/gpio-omap.c2
-rw-r--r--drivers/gpio/gpio-palmas.c2
-rw-r--r--drivers/gpio/gpio-syscon.c6
-rw-r--r--drivers/gpio/gpio-tegra.c105
-rw-r--r--drivers/gpio/gpiolib.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu.h129
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c228
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_display.c108
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c101
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c51
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c4
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c48
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.c1
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_object.h7
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c3
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c30
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c2
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c10
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h94
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c23
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c172
-rw-r--r--drivers/gpu/drm/amd/amdgpu/ci_dpm.c8
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v10_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v11_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/dce_v8_0.c5
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c302
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c13
-rw-r--r--drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c11
-rw-r--r--drivers/gpu/drm/amd/amdgpu/vce_v3_0.c24
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c33
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h24
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.c151
-rw-r--r--drivers/gpu/drm/amd/scheduler/gpu_scheduler.h11
-rw-r--r--drivers/gpu/drm/amd/scheduler/sched_fence.c23
-rw-r--r--drivers/gpu/drm/ast/ast_drv.h1
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c7
-rw-r--r--drivers/gpu/drm/ast/ast_main.c1
-rw-r--r--drivers/gpu/drm/ast/ast_mode.c2
-rw-r--r--drivers/gpu/drm/drm_atomic.c61
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c29
-rw-r--r--drivers/gpu/drm/drm_drv.c5
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c51
-rw-r--r--drivers/gpu/drm/drm_fops.c84
-rw-r--r--drivers/gpu/drm/drm_irq.c64
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c3
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c3
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c2
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h33
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c131
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_fence.c36
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c1
-rw-r--r--drivers/gpu/drm/i915/i915_params.c5
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c31
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c75
-rw-r--r--drivers/gpu/drm/i915/intel_display.c172
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c51
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h5
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c19
-rw-r--r--drivers/gpu/drm/i915/intel_i2c.c6
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c15
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c34
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c7
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h3
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c1
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c63
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.c9
-rw-r--r--drivers/gpu/drm/imx/ipuv3-plane.h2
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c4
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_cursor.c11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/device.h1
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_acpi.c1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c19
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c7
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_usif.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h344
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h344
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h344
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h308
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h474
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c5
-rw-r--r--drivers/gpu/drm/radeon/cik.c11
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c5
-rw-r--r--drivers/gpu/drm/radeon/r100.c12
-rw-r--r--drivers/gpu/drm/radeon/r600.c2
-rw-r--r--drivers/gpu/drm/radeon/radeon.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_agp.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c21
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c106
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c50
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h5
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c15
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c7
-rw-r--r--drivers/gpu/drm/radeon/radeon_vce.c100
-rw-r--r--drivers/gpu/drm/radeon/rs600.c2
-rw-r--r--drivers/gpu/drm/radeon/rs690.c10
-rw-r--r--drivers/gpu/drm/radeon/rv730_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c4
-rw-r--r--drivers/gpu/drm/radeon/si.c5
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c2
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c81
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c43
-rw-r--r--drivers/gpu/drm/sti/Kconfig8
-rw-r--r--drivers/gpu/drm/sti/Makefile21
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.c4
-rw-r--r--drivers/gpu/drm/sti/sti_compositor.c4
-rw-r--r--drivers/gpu/drm/sti/sti_crtc.c45
-rw-r--r--drivers/gpu/drm/sti/sti_drv.c33
-rw-r--r--drivers/gpu/drm/sti/sti_drv.h9
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c7
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c7
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c69
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c306
-rw-r--r--drivers/gpu/drm/sti/sti_mixer.c14
-rw-r--r--drivers/gpu/drm/sti/sti_plane.c3
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c2
-rw-r--r--drivers/gpu/drm/sti/sti_vtac.c2
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.c22
-rw-r--r--drivers/gpu/drm/sti/sti_vtg.h4
-rw-r--r--drivers/gpu/drm/ttm/ttm_lock.c2
-rw-r--r--drivers/gpu/drm/vc4/Kconfig3
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c9
-rw-r--r--drivers/gpu/drm/vc4/vc4_drv.c1
-rw-r--r--drivers/gpu/drm/vc4/vc4_hvs.c8
-rw-r--r--drivers/gpu/drm/vc4/vc4_plane.c18
-rw-r--r--drivers/gpu/drm/virtio/virtgpu_display.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.c1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_drv.h1
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.c64
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_kms.h7
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c2
-rw-r--r--drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c2
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c69
-rw-r--r--drivers/gpu/ipu-v3/ipu-cpmem.c2
-rw-r--r--drivers/gpu/vga/vgaarb.c13
-rw-r--r--drivers/hid/hid-ids.h6
-rw-r--r--drivers/hid/hid-lg.c5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c10
-rw-r--r--drivers/hid/wacom_wac.c5
-rw-r--r--drivers/hv/hyperv_vmbus.h88
-rw-r--r--drivers/hwmon/Kconfig21
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/applesmc.c2
-rw-r--r--drivers/hwmon/fam15h_power.c7
-rw-r--r--drivers/hwmon/htu21.c174
-rw-r--r--drivers/hwmon/ibmaem.c12
-rw-r--r--drivers/hwmon/nct6683.c89
-rw-r--r--drivers/hwmon/nct6775.c11
-rw-r--r--drivers/hwmon/pmbus/Kconfig10
-rw-r--r--drivers/hwmon/pmbus/Makefile1
-rw-r--r--drivers/hwmon/pmbus/ltc3815.c215
-rw-r--r--drivers/hwmon/scpi-hwmon.c289
-rw-r--r--drivers/hwmon/tmp102.c16
-rw-r--r--drivers/hwtracing/stm/policy.c105
-rw-r--r--drivers/i2c/busses/Kconfig25
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-at91.c82
-rw-r--r--drivers/i2c/busses/i2c-au1550.c60
-rw-r--r--drivers/i2c/busses/i2c-davinci.c19
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c80
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h11
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c33
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c87
-rw-r--r--drivers/i2c/busses/i2c-i801.c22
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c1
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c73
-rw-r--r--drivers/i2c/busses/i2c-imx.c74
-rw-r--r--drivers/i2c/busses/i2c-ismt.c80
-rw-r--r--drivers/i2c/busses/i2c-meson.c1
-rw-r--r--drivers/i2c/busses/i2c-mt65xx.c16
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c27
-rw-r--r--drivers/i2c/busses/i2c-ocores.c31
-rw-r--r--drivers/i2c/busses/i2c-pnx.c7
-rw-r--r--drivers/i2c/busses/i2c-pxa.c41
-rw-r--r--drivers/i2c/busses/i2c-rcar.c28
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c3
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c1
-rw-r--r--drivers/i2c/busses/i2c-sirf.c26
-rw-r--r--drivers/i2c/busses/i2c-st.c2
-rw-r--r--drivers/i2c/busses/i2c-stu300.c1
-rw-r--r--drivers/i2c/busses/i2c-tegra.c1
-rw-r--r--drivers/i2c/busses/i2c-uniphier-f.c584
-rw-r--r--drivers/i2c/busses/i2c-uniphier.c441
-rw-r--r--drivers/i2c/busses/i2c-xiic.c4
-rw-r--r--drivers/i2c/i2c-core.c84
-rw-r--r--drivers/i2c/i2c-dev.c23
-rw-r--r--drivers/i2c/i2c-mux.c8
-rw-r--r--drivers/iio/adc/ad7793.c2
-rw-r--r--drivers/iio/adc/qcom-spmi-vadc.c4
-rw-r--r--drivers/iio/adc/vf610_adc.c22
-rw-r--r--drivers/iio/adc/xilinx-xadc-core.c1
-rw-r--r--drivers/iio/dac/ad5064.c91
-rw-r--r--drivers/iio/humidity/si7020.c8
-rw-r--r--drivers/iio/industrialio-buffer.c2
-rw-r--r--drivers/iio/industrialio-core.c2
-rw-r--r--drivers/iio/light/apds9960.c1
-rw-r--r--drivers/iio/proximity/pulsedlight-lidar-lite-v2.c6
-rw-r--r--drivers/infiniband/core/cma.c21
-rw-r--r--drivers/infiniband/core/mad.c5
-rw-r--r--drivers/infiniband/core/sa_query.c32
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c27
-rw-r--r--drivers/infiniband/core/verbs.c43
-rw-r--r--drivers/infiniband/hw/mlx4/main.c2
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c19
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c13
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c14
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h10
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c49
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h4
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c57
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h49
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_qsfp.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.h2
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c2
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c13
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c53
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h5
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c78
-rw-r--r--drivers/input/joystick/db9.c1
-rw-r--r--drivers/input/joystick/gamecon.c1
-rw-r--r--drivers/input/joystick/turbografx.c1
-rw-r--r--drivers/input/joystick/walkera0701.c1
-rw-r--r--drivers/input/misc/arizona-haptics.c3
-rw-r--r--drivers/input/mouse/elan_i2c_core.c3
-rw-r--r--drivers/input/mouse/elantech.c7
-rw-r--r--drivers/input/serio/parkbd.c3
-rw-r--r--drivers/input/tablet/aiptek.c9
-rw-r--r--drivers/input/touchscreen/Kconfig17
-rw-r--r--drivers/input/touchscreen/Makefile2
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c34
-rw-r--r--drivers/input/touchscreen/elants_i2c.c21
-rw-r--r--drivers/input/touchscreen/sur40.c13
-rw-r--r--drivers/input/touchscreen/tsc2004.c83
-rw-r--r--drivers/input/touchscreen/tsc2005.c714
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c665
-rw-r--r--drivers/input/touchscreen/tsc200x-core.h78
-rw-r--r--drivers/iommu/amd_iommu_v2.c20
-rw-r--r--drivers/iommu/dma-iommu.c11
-rw-r--r--drivers/iommu/intel-iommu.c4
-rw-r--r--drivers/iommu/intel-svm.c20
-rw-r--r--drivers/iommu/intel_irq_remapping.c2
-rw-r--r--drivers/iommu/iommu.c2
-rw-r--r--drivers/iommu/ipmmu-vmsa.c2
-rw-r--r--drivers/iommu/s390-iommu.c23
-rw-r--r--drivers/irqchip/Kconfig19
-rw-r--r--drivers/irqchip/Makefile3
-rw-r--r--drivers/irqchip/irq-bcm2836.c55
-rw-r--r--drivers/irqchip/irq-gic-common.c13
-rw-r--r--drivers/irqchip/irq-gic-realview.c43
-rw-r--r--drivers/irqchip/irq-gic-v2m.c165
-rw-r--r--drivers/irqchip/irq-gic.c102
-rw-r--r--drivers/irqchip/irq-mbigen.c297
-rw-r--r--drivers/irqchip/irq-mips-gic.c14
-rw-r--r--drivers/irqchip/irq-omap-intc.c28
-rw-r--r--drivers/irqchip/irq-renesas-h8300h.c8
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c96
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c13
-rw-r--r--drivers/irqchip/irq-ts4800.c163
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c5
-rw-r--r--drivers/irqchip/irq-zevio.c3
-rw-r--r--drivers/isdn/gigaset/ser-gigaset.c23
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c7
-rw-r--r--drivers/isdn/hisax/config.c2
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c2
-rw-r--r--drivers/isdn/hisax/q931.c6
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/leds/led-class-flash.c8
-rw-r--r--drivers/leds/led-class.c11
-rw-r--r--drivers/leds/led-core.c120
-rw-r--r--drivers/leds/led-triggers.c28
-rw-r--r--drivers/leds/leds-88pm860x.c23
-rw-r--r--drivers/leds/leds-aat1290.c59
-rw-r--r--drivers/leds/leds-adp5520.c26
-rw-r--r--drivers/leds/leds-bcm6328.c63
-rw-r--r--drivers/leds/leds-bcm6358.c37
-rw-r--r--drivers/leds/leds-bd2802.c39
-rw-r--r--drivers/leds/leds-blinkm.c87
-rw-r--r--drivers/leds/leds-da903x.c46
-rw-r--r--drivers/leds/leds-da9052.c39
-rw-r--r--drivers/leds/leds-dac124s085.c38
-rw-r--r--drivers/leds/leds-gpio.c62
-rw-r--r--drivers/leds/leds-ipaq-micro.c6
-rw-r--r--drivers/leds/leds-ktd2692.c50
-rw-r--r--drivers/leds/leds-lm3533.c30
-rw-r--r--drivers/leds/leds-lm355x.c85
-rw-r--r--drivers/leds/leds-lm3642.c73
-rw-r--r--drivers/leds/leds-lp3944.c32
-rw-r--r--drivers/leds/leds-lp5521.c11
-rw-r--r--drivers/leds/leds-lp5523.c10
-rw-r--r--drivers/leds/leds-lp5562.c11
-rw-r--r--drivers/leds/leds-lp55xx-common.c12
-rw-r--r--drivers/leds/leds-lp55xx-common.h6
-rw-r--r--drivers/leds/leds-lp8501.c11
-rw-r--r--drivers/leds/leds-lp8788.c48
-rw-r--r--drivers/leds/leds-lp8860.c27
-rw-r--r--drivers/leds/leds-lt3593.c33
-rw-r--r--drivers/leds/leds-max77693.c58
-rw-r--r--drivers/leds/leds-max8997.c1
-rw-r--r--drivers/leds/leds-mc13783.c35
-rw-r--r--drivers/leds/leds-ns2.c31
-rw-r--r--drivers/leds/leds-pca9532.c28
-rw-r--r--drivers/leds/leds-pca955x.c39
-rw-r--r--drivers/leds/leds-pca963x.c80
-rw-r--r--drivers/leds/leds-powernv.c18
-rw-r--r--drivers/leds/leds-pwm.c39
-rw-r--r--drivers/leds/leds-regulator.c46
-rw-r--r--drivers/leds/leds-sunfire.c23
-rw-r--r--drivers/leds/leds-syscon.c18
-rw-r--r--drivers/leds/leds-tlc591xx.c31
-rw-r--r--drivers/leds/leds-wm831x-status.c25
-rw-r--r--drivers/leds/leds-wm8350.c64
-rw-r--r--drivers/leds/leds.h27
-rw-r--r--drivers/leds/trigger/ledtrig-backlight.c8
-rw-r--r--drivers/leds/trigger/ledtrig-cpu.c26
-rw-r--r--drivers/leds/trigger/ledtrig-default-on.c2
-rw-r--r--drivers/leds/trigger/ledtrig-gpio.c6
-rw-r--r--drivers/leds/trigger/ledtrig-heartbeat.c4
-rw-r--r--drivers/leds/trigger/ledtrig-ide-disk.c14
-rw-r--r--drivers/leds/trigger/ledtrig-oneshot.c6
-rw-r--r--drivers/leds/trigger/ledtrig-transient.c10
-rw-r--r--drivers/lightnvm/Kconfig1
-rw-r--r--drivers/lightnvm/core.c158
-rw-r--r--drivers/lightnvm/gennvm.c105
-rw-r--r--drivers/lightnvm/gennvm.h2
-rw-r--r--drivers/lightnvm/rrpc.c66
-rw-r--r--drivers/md/Kconfig22
-rw-r--r--drivers/md/Makefile5
-rw-r--r--drivers/md/bcache/request.c11
-rw-r--r--drivers/md/bcache/util.c2
-rw-r--r--drivers/md/dm-bufio.c46
-rw-r--r--drivers/md/dm-cache-target.c3
-rw-r--r--drivers/md/dm-crypt.c22
-rw-r--r--drivers/md/dm-exception-store.h2
-rw-r--r--drivers/md/dm-io.c4
-rw-r--r--drivers/md/dm-mpath.c30
-rw-r--r--drivers/md/dm-snap-persistent.c5
-rw-r--r--drivers/md/dm-snap-transient.c4
-rw-r--r--drivers/md/dm-snap.c26
-rw-r--r--drivers/md/dm-thin-metadata.c148
-rw-r--r--drivers/md/dm-thin.c14
-rw-r--r--drivers/md/dm-verity-fec.c818
-rw-r--r--drivers/md/dm-verity-fec.h152
-rw-r--r--drivers/md/dm-verity-target.c (renamed from drivers/md/dm-verity.c)602
-rw-r--r--drivers/md/dm-verity.h129
-rw-r--r--drivers/md/dm.c13
-rw-r--r--drivers/md/md.c41
-rw-r--r--drivers/md/md.h8
-rw-r--r--drivers/md/persistent-data/Kconfig9
-rw-r--r--drivers/md/persistent-data/dm-block-manager.c11
-rw-r--r--drivers/md/persistent-data/dm-btree.c118
-rw-r--r--drivers/md/persistent-data/dm-btree.h14
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c29
-rw-r--r--drivers/md/raid10.c4
-rw-r--r--drivers/media/Kconfig4
-rw-r--r--drivers/media/common/cx2341x.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_fops.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_hlp.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_i2c.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c2
-rw-r--r--drivers/media/common/siano/smsir.h2
-rw-r--r--drivers/media/dvb-core/demux.h67
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c27
-rw-r--r--drivers/media/dvb-core/dvb_frontend.h221
-rw-r--r--drivers/media/dvb-frontends/Kconfig2
-rw-r--r--drivers/media/dvb-frontends/au8522_common.c10
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c14
-rw-r--r--drivers/media/dvb-frontends/au8522_dig.c16
-rw-r--r--drivers/media/dvb-frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb-frontends/bsbe1-d01a.h2
-rw-r--r--drivers/media/dvb-frontends/bsbe1.h2
-rw-r--r--drivers/media/dvb-frontends/bsru6.h2
-rw-r--r--drivers/media/dvb-frontends/isl6405.c2
-rw-r--r--drivers/media/dvb-frontends/isl6405.h2
-rw-r--r--drivers/media/dvb-frontends/isl6421.c2
-rw-r--r--drivers/media/dvb-frontends/isl6421.h2
-rw-r--r--drivers/media/dvb-frontends/lnbp21.c2
-rw-r--r--drivers/media/dvb-frontends/lnbp21.h2
-rw-r--r--drivers/media/dvb-frontends/lnbp22.c2
-rw-r--r--drivers/media/dvb-frontends/lnbp22.h2
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c21
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c4
-rw-r--r--drivers/media/dvb-frontends/si2165.c351
-rw-r--r--drivers/media/dvb-frontends/stb6100.c76
-rw-r--r--drivers/media/dvb-frontends/stb6100.h1
-rw-r--r--drivers/media/dvb-frontends/stb6100_cfg.h37
-rw-r--r--drivers/media/dvb-frontends/stb6100_proc.h43
-rw-r--r--drivers/media/dvb-frontends/tda665x.c183
-rw-r--r--drivers/media/dvb-frontends/tda8261.c125
-rw-r--r--drivers/media/dvb-frontends/tda8261_cfg.h37
-rw-r--r--drivers/media/dvb-frontends/tdhd1.h2
-rw-r--r--drivers/media/i2c/Kconfig10
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/ad9389b.c2
-rw-r--r--drivers/media/i2c/adp1653.c2
-rw-r--r--drivers/media/i2c/adv7180.c2
-rw-r--r--drivers/media/i2c/adv7183.c2
-rw-r--r--drivers/media/i2c/adv7343.c2
-rw-r--r--drivers/media/i2c/adv7393.c2
-rw-r--r--drivers/media/i2c/adv7511.c4
-rw-r--r--drivers/media/i2c/adv7604.c8
-rw-r--r--drivers/media/i2c/adv7842.c8
-rw-r--r--drivers/media/i2c/ak881x.c2
-rw-r--r--drivers/media/i2c/as3645a.c2
-rw-r--r--drivers/media/i2c/bt819.c2
-rw-r--r--drivers/media/i2c/cs3308.c138
-rw-r--r--drivers/media/i2c/cx25840/cx25840-audio.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c117
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.h1
-rw-r--r--drivers/media/i2c/cx25840/cx25840-firmware.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-vbi.c34
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c2
-rw-r--r--drivers/media/i2c/lm3560.c2
-rw-r--r--drivers/media/i2c/lm3646.c2
-rw-r--r--drivers/media/i2c/m52790.c2
-rw-r--r--drivers/media/i2c/m5mols/m5mols_capture.c4
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c2
-rw-r--r--drivers/media/i2c/msp3400-driver.c4
-rw-r--r--drivers/media/i2c/msp3400-driver.h2
-rw-r--r--drivers/media/i2c/msp3400-kthreads.c2
-rw-r--r--drivers/media/i2c/mt9m032.c4
-rw-r--r--drivers/media/i2c/mt9p031.c4
-rw-r--r--drivers/media/i2c/mt9t001.c4
-rw-r--r--drivers/media/i2c/mt9v011.c4
-rw-r--r--drivers/media/i2c/mt9v032.c4
-rw-r--r--drivers/media/i2c/noon010pc30.c2
-rw-r--r--drivers/media/i2c/ov2659.c4
-rw-r--r--drivers/media/i2c/ov7670.c2
-rw-r--r--drivers/media/i2c/ov9650.c2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-core.c2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c2
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-spi.c1
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h2
-rw-r--r--drivers/media/i2c/s5k4ecgx.c2
-rw-r--r--drivers/media/i2c/s5k6aa.c2
-rw-r--r--drivers/media/i2c/saa6588.c2
-rw-r--r--drivers/media/i2c/saa7115.c2
-rw-r--r--drivers/media/i2c/saa7127.c2
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h2
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c2
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c4
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c2
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c2
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c2
-rw-r--r--drivers/media/i2c/sr030pc30.c2
-rw-r--r--drivers/media/i2c/tc358743.c6
-rw-r--r--drivers/media/i2c/ths7303.c2
-rw-r--r--drivers/media/i2c/tvaudio.c2
-rw-r--r--drivers/media/i2c/tvp514x.c2
-rw-r--r--drivers/media/i2c/tvp5150.c2
-rw-r--r--drivers/media/i2c/tvp7002.c2
-rw-r--r--drivers/media/i2c/uda1342.c2
-rw-r--r--drivers/media/i2c/upd64031a.c2
-rw-r--r--drivers/media/i2c/upd64083.c2
-rw-r--r--drivers/media/i2c/wm8775.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c4
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c6
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h4
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c6
-rw-r--r--drivers/media/pci/cobalt/cobalt-irq.c4
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c18
-rw-r--r--drivers/media/pci/cx18/cx18-cards.c2
-rw-r--r--drivers/media/pci/cx18/cx18-controls.c2
-rw-r--r--drivers/media/pci/cx18/cx18-controls.h2
-rw-r--r--drivers/media/pci/cx18/cx18-driver.h2
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c4
-rw-r--r--drivers/media/pci/cx18/cx23418.h2
-rw-r--r--drivers/media/pci/cx23885/Kconfig1
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c116
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c16
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c8
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c5
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c49
-rw-r--r--drivers/media/pci/cx23885/cx23885.h9
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c3
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c14
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c6
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c4
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c3
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c2
-rw-r--r--drivers/media/pci/cx88/cx88-video.c8
-rw-r--r--drivers/media/pci/cx88/cx88.h6
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c4
-rw-r--r--drivers/media/pci/dm1105/dm1105.c1
-rw-r--r--drivers/media/pci/dt3155/dt3155.c13
-rw-r--r--drivers/media/pci/ivtv/ivtv-cards.c12
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.h2
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c8
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.h4
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-firmware.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-i2c.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c10
-rw-r--r--drivers/media/pci/ivtv/ivtv-routing.c8
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_core.c5
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c6
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134.h4
-rw-r--r--drivers/media/pci/saa7146/hexium_gemini.c2
-rw-r--r--drivers/media/pci/saa7146/hexium_orion.c2
-rw-r--r--drivers/media/pci/saa7146/mxb.c4
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2.c4
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c4
-rw-r--r--drivers/media/pci/ttpci/av7110.c6
-rw-r--r--drivers/media/pci/ttpci/av7110.h2
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c11
-rw-r--r--drivers/media/pci/ttpci/av7110_av.h3
-rw-r--r--drivers/media/pci/ttpci/av7110_ca.c2
-rw-r--r--drivers/media/pci/ttpci/av7110_hw.c2
-rw-r--r--drivers/media/pci/ttpci/av7110_v4l.c2
-rw-r--r--drivers/media/pci/ttpci/budget-av.c4
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c2
-rw-r--r--drivers/media/pci/ttpci/budget-core.c2
-rw-r--r--drivers/media/pci/ttpci/budget-patch.c2
-rw-r--r--drivers/media/pci/ttpci/budget.c2
-rw-r--r--drivers/media/pci/ttpci/budget.h2
-rw-r--r--drivers/media/pci/tw68/tw68-core.c4
-rw-r--r--drivers/media/pci/tw68/tw68-video.c22
-rw-r--r--drivers/media/pci/zoran/zoran_card.c2
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c19
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c14
-rw-r--r--drivers/media/platform/coda/coda-bit.c8
-rw-r--r--drivers/media/platform/coda/coda-common.c25
-rw-r--r--drivers/media/platform/coda/coda-jpeg.c26
-rw-r--r--drivers/media/platform/coda/coda.h4
-rw-r--r--drivers/media/platform/davinci/Kconfig6
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c15
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c19
-rw-r--r--drivers/media/platform/davinci/vpif_display.c19
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c5
-rw-r--r--drivers/media/platform/exynos4-is/common.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c33
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c35
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c35
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c2
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h2
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c2
-rw-r--r--drivers/media/platform/m2m-deinterlace.c3
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c17
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c2
-rw-r--r--drivers/media/platform/mx2_emmaprp.c3
-rw-r--r--drivers/media/platform/omap/omap_vout_vrfb.c10
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c3
-rw-r--r--drivers/media/platform/rcar_jpu.c40
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c35
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.h2
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.h2
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c4
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c103
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h14
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c16
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c39
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.h2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c47
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.h2
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h507
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c94
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c121
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c4
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c2
-rw-r--r--drivers/media/platform/s5p-tv/sii9234_drv.c2
-rw-r--r--drivers/media/platform/sh_veu.c33
-rw-r--r--drivers/media/platform/sh_vou.c15
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c168
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.h10
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c12
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c44
-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/rcar_vin.c119
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c45
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c6
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c25
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c2
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c14
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c16
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c2
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c3
-rw-r--r--drivers/media/platform/timblogiw.c2
-rw-r--r--drivers/media/platform/via-camera.c2
-rw-r--r--drivers/media/platform/vim2m.c15
-rw-r--r--drivers/media/platform/vivid/vivid-core.h3
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c35
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-cap.c6
-rw-r--r--drivers/media/platform/vivid/vivid-kthread-out.c8
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c6
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c8
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.c2
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c34
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c30
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c53
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c14
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c4
-rw-r--r--drivers/media/radio/radio-maxiradio.c4
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c4
-rw-r--r--drivers/media/radio/radio-shark.c4
-rw-r--r--drivers/media/radio/radio-shark2.c2
-rw-r--r--drivers/media/radio/radio-si476x.c2
-rw-r--r--drivers/media/radio/radio-tea5777.h2
-rw-r--r--drivers/media/radio/radio-timb.c2
-rw-r--r--drivers/media/radio/si4713/radio-usb-si4713.c2
-rw-r--r--drivers/media/radio/si4713/si4713.h2
-rw-r--r--drivers/media/radio/tea575x.c2
-rw-r--r--drivers/media/rc/Kconfig3
-rw-r--r--drivers/media/rc/gpio-ir-recv.c24
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c3
-rw-r--r--drivers/media/rc/ir-lirc-codec.c1
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c3
-rw-r--r--drivers/media/rc/ir-nec-decoder.c3
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c3
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c5
-rw-r--r--drivers/media/rc/ir-rx51.c2
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c3
-rw-r--r--drivers/media/rc/ir-sharp-decoder.c7
-rw-r--r--drivers/media/rc/ir-sony-decoder.c4
-rw-r--r--drivers/media/rc/ir-xmp-decoder.c3
-rw-r--r--drivers/media/rc/nuvoton-cir.c156
-rw-r--r--drivers/media/rc/nuvoton-cir.h28
-rw-r--r--drivers/media/rc/rc-core-priv.h71
-rw-r--r--drivers/media/rc/rc-ir-raw.c41
-rw-r--r--drivers/media/rc/rc-main.c88
-rw-r--r--drivers/media/rc/st_rc.c14
-rw-r--r--drivers/media/rc/streamzap.c19
-rw-r--r--drivers/media/rc/sunxi-cir.c2
-rw-r--r--drivers/media/tuners/max2165.c2
-rw-r--r--drivers/media/tuners/mt2063.c1
-rw-r--r--drivers/media/tuners/si2157.c1
-rw-r--r--drivers/media/usb/airspy/airspy.c6
-rw-r--r--drivers/media/usb/as102/as102_fw.c1
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c14
-rw-r--r--drivers/media/usb/au0828/au0828-video.c14
-rw-r--r--drivers/media/usb/cpia2/cpia2_usb.c3
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c26
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c10
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c15
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c8
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c7
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig2
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h4
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c16
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig2
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c18
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c15
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c20
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c23
-rw-r--r--drivers/media/usb/em28xx/em28xx.h2
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c2
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c6
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c3
-rw-r--r--drivers/media/usb/gspca/ov534.c9
-rw-r--r--drivers/media/usb/gspca/topro.c6
-rw-r--r--drivers/media/usb/hackrf/hackrf.c19
-rw-r--r--drivers/media/usb/hdpvr/hdpvr-video.c2
-rw-r--r--drivers/media/usb/hdpvr/hdpvr.h2
-rw-r--r--drivers/media/usb/msi2500/msi2500.c1
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c16
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c2
-rw-r--r--drivers/media/usb/pwc/pwc-if.c5
-rw-r--r--drivers/media/usb/s2255/s2255drv.c4
-rw-r--r--drivers/media/usb/stk1160/stk1160-core.c2
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c4
-rw-r--r--drivers/media/usb/stk1160/stk1160-video.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c2
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c11
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c2
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c25
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c3
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c3
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c14
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c20
-rw-r--r--drivers/media/usb/uvc/uvc_video.c17
-rw-r--r--drivers/media/v4l2-core/v4l2-clk.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c77
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c21
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c16
-rw-r--r--drivers/media/v4l2-core/v4l2-flash-led-class.c8
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c14
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c926
-rw-r--r--drivers/media/v4l2-core/videobuf2-internal.h161
-rw-r--r--drivers/media/v4l2-core/videobuf2-v4l2.c703
-rw-r--r--drivers/memory/fsl_ifc.c1
-rw-r--r--drivers/memory/pl172.c26
-rw-r--r--drivers/message/fusion/mptctl.c4
-rw-r--r--drivers/message/fusion/mptsas.c1
-rw-r--r--drivers/mfd/timberdale.c4
-rw-r--r--drivers/misc/atmel_tclib.c4
-rw-r--r--drivers/misc/cxl/native.c2
-rw-r--r--drivers/misc/spear13xx_pcie_gadget.c216
-rw-r--r--drivers/mmc/card/block.c22
-rw-r--r--drivers/mmc/core/bus.c2
-rw-r--r--drivers/mmc/core/core.c85
-rw-r--r--drivers/mmc/core/core.h8
-rw-r--r--drivers/mmc/core/host.c11
-rw-r--r--drivers/mmc/core/mmc.c116
-rw-r--r--drivers/mmc/core/mmc_ops.c9
-rw-r--r--drivers/mmc/core/pwrseq.h2
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c2
-rw-r--r--drivers/mmc/core/pwrseq_simple.c2
-rw-r--r--drivers/mmc/core/sd.c17
-rw-r--r--drivers/mmc/core/sdio.c2
-rw-r--r--drivers/mmc/core/sdio_bus.c1
-rw-r--r--drivers/mmc/host/Kconfig2
-rw-r--r--drivers/mmc/host/atmel-mci-regs.h171
-rw-r--r--drivers/mmc/host/atmel-mci.c165
-rw-r--r--drivers/mmc/host/cb710-mmc.h3
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c2
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c8
-rw-r--r--drivers/mmc/host/dw_mmc.c21
-rw-r--r--drivers/mmc/host/mtk-sd.c11
-rw-r--r--drivers/mmc/host/mvsdio.c58
-rw-r--r--drivers/mmc/host/of_mmc_spi.c4
-rw-r--r--drivers/mmc/host/omap_hsmmc.c6
-rw-r--r--drivers/mmc/host/pxamci.c2
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c7
-rw-r--r--drivers/mmc/host/sdhci-of-at91.c75
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c10
-rw-r--r--drivers/mmc/host/sdhci-pci-core.c6
-rw-r--r--drivers/mmc/host/sdhci-pltfm.c3
-rw-r--r--drivers/mmc/host/sdhci-tegra.c178
-rw-r--r--drivers/mmc/host/sdhci.c124
-rw-r--r--drivers/mmc/host/sdhci.h21
-rw-r--r--drivers/mmc/host/sh_mmcif.c84
-rw-r--r--drivers/mmc/host/usdhi6rol0.c3
-rw-r--r--drivers/mtd/maps/pcmciamtd.c28
-rw-r--r--drivers/mtd/mtdcore.c26
-rw-r--r--drivers/mtd/nand/jz4740_nand.c1
-rw-r--r--drivers/mtd/nand/nand_base.c2
-rw-r--r--drivers/mtd/ofpart.c12
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c10
-rw-r--r--drivers/mtd/ubi/attach.c4
-rw-r--r--drivers/mtd/ubi/cdev.c2
-rw-r--r--drivers/mtd/ubi/debug.c2
-rw-r--r--drivers/mtd/ubi/eba.c2
-rw-r--r--drivers/mtd/ubi/fastmap-wl.c29
-rw-r--r--drivers/mtd/ubi/fastmap.c4
-rw-r--r--drivers/mtd/ubi/io.c2
-rw-r--r--drivers/mtd/ubi/ubi-media.h2
-rw-r--r--drivers/mtd/ubi/wl.c53
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/caif/caif_spi.c7
-rw-r--r--drivers/net/can/bfin_can.c2
-rw-r--r--drivers/net/can/c_can/c_can.c7
-rw-r--r--drivers/net/can/cc770/cc770.c2
-rw-r--r--drivers/net/can/flexcan.c4
-rw-r--r--drivers/net/can/janz-ican3.c1
-rw-r--r--drivers/net/can/m_can/m_can.c7
-rw-r--r--drivers/net/can/pch_can.c3
-rw-r--r--drivers/net/can/rcar_can.c11
-rw-r--r--drivers/net/can/sja1000/sja1000.c4
-rw-r--r--drivers/net/can/sun4i_can.c1
-rw-r--r--drivers/net/can/ti_hecc.c7
-rw-r--r--drivers/net/can/usb/ems_usb.c1
-rw-r--r--drivers/net/can/usb/esd_usb2.c1
-rw-r--r--drivers/net/can/usb/kvaser_usb.c5
-rw-r--r--drivers/net/can/usb/usb_8dev.c4
-rw-r--r--drivers/net/can/xilinx_can.c9
-rw-r--r--drivers/net/dsa/mv88e6060.c114
-rw-r--r--drivers/net/dsa/mv88e6060.h111
-rw-r--r--drivers/net/dsa/mv88e6171.c2
-rw-r--r--drivers/net/dsa/mv88e6352.c2
-rw-r--r--drivers/net/dsa/mv88e6xxx.c42
-rw-r--r--drivers/net/dsa/mv88e6xxx.h2
-rw-r--r--drivers/net/ethernet/Kconfig2
-rw-r--r--drivers/net/ethernet/Makefile2
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c5
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c4
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c8
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c49
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.h1
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c70
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.h4
-rw-r--r--drivers/net/ethernet/atheros/alx/main.c2
-rw-r--r--drivers/net/ethernet/atheros/alx/reg.h1
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c7
-rw-r--r--drivers/net/ethernet/aurora/Kconfig21
-rw-r--r--drivers/net/ethernet/aurora/Makefile1
-rw-r--r--drivers/net/ethernet/aurora/nb8800.c1552
-rw-r--r--drivers/net/ethernet/aurora/nb8800.h316
-rw-r--r--drivers/net/ethernet/broadcom/Kconfig1
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c22
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c6
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.c118
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt.h32
-rw-r--r--drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c49
-rw-r--r--drivers/net/ethernet/cadence/macb.c4
-rw-r--r--drivers/net/ethernet/cadence/macb.h5
-rw-r--r--drivers/net/ethernet/cavium/liquidio/lio_main.c2
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic.h5
-rw-r--r--drivers/net/ethernet/cavium/thunder/nic_main.c22
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c16
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_main.c14
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.c2
-rw-r--r--drivers/net/ethernet/cavium/thunder/nicvf_queues.h2
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.c28
-rw-r--r--drivers/net/ethernet/cavium/thunder/thunder_bgx.h2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c4
-rw-r--r--drivers/net/ethernet/dec/tulip/tulip_core.c9
-rw-r--r--drivers/net/ethernet/dec/tulip/winbond-840.c2
-rw-r--r--drivers/net/ethernet/dlink/Kconfig5
-rw-r--r--drivers/net/ethernet/dlink/dl2k.c55
-rw-r--r--drivers/net/ethernet/dlink/dl2k.h15
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h2
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c19
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c10
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.c36
-rw-r--r--drivers/net/ethernet/emulex/benet/be_roce.h4
-rw-r--r--drivers/net/ethernet/ezchip/nps_enet.c30
-rw-r--r--drivers/net/ethernet/freescale/Kconfig3
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/mac-fcc.c2
-rw-r--r--drivers/net/ethernet/freescale/fsl_pq_mdio.c2
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c14
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h1
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ptp.c2
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig3
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c49
-rw-r--r--drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h11
-rw-r--r--drivers/net/ethernet/icplus/Kconfig13
-rw-r--r--drivers/net/ethernet/icplus/Makefile5
-rw-r--r--drivers/net/ethernet/icplus/ipg.c2300
-rw-r--r--drivers/net/ethernet/icplus/ipg.h748
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c4
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.c6
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c11
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_adminq.c6
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c10
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c3
-rw-r--r--drivers/net/ethernet/marvell/Kconfig1
-rw-r--r--drivers/net/ethernet/marvell/mvneta.c35
-rw-r--r--drivers/net/ethernet/marvell/mvpp2.c52
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c44
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en.h10
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_main.c50
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/en_tx.c76
-rw-r--r--drivers/net/ethernet/natsemi/natsemi.c12
-rw-r--r--drivers/net/ethernet/nxp/lpc_eth.c2
-rw-r--r--drivers/net/ethernet/qlogic/Kconfig1
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed.h3
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_dev.c67
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_int.c38
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_int.h15
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_main.c56
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_reg_addr.h4
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_sp.h8
-rw-r--r--drivers/net/ethernet/qlogic/qed/qed_spq.c63
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c5
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c6
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c3
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c5
-rw-r--r--drivers/net/ethernet/qualcomm/qca_spi.c5
-rw-r--r--drivers/net/ethernet/realtek/r8169.c6
-rw-r--r--drivers/net/ethernet/renesas/ravb_main.c19
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c164
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h58
-rw-r--r--drivers/net/ethernet/sfc/ef10.c24
-rw-r--r--drivers/net/ethernet/sfc/efx.c10
-rw-r--r--drivers/net/ethernet/sfc/efx.h5
-rw-r--r--drivers/net/ethernet/sfc/farch.c2
-rw-r--r--drivers/net/ethernet/sfc/txc43128_phy.c2
-rw-r--r--drivers/net/ethernet/smsc/smsc911x.c17
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c10
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c6
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c18
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c28
-rw-r--r--drivers/net/ethernet/synopsys/dwc_eth_qos.c3
-rw-r--r--drivers/net/ethernet/ti/cpsw-common.c3
-rw-r--r--drivers/net/ethernet/ti/cpsw.c62
-rw-r--r--drivers/net/ethernet/via/via-velocity.c24
-rw-r--r--drivers/net/fjes/fjes_hw.c6
-rw-r--r--drivers/net/geneve.c12
-rw-r--r--drivers/net/hamradio/6pack.c12
-rw-r--r--drivers/net/hamradio/mkiss.c9
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c14
-rw-r--r--drivers/net/macvlan.c2
-rw-r--r--drivers/net/macvtap.c9
-rw-r--r--drivers/net/netconsole.c271
-rw-r--r--drivers/net/phy/at803x.c4
-rw-r--r--drivers/net/phy/broadcom.c2
-rw-r--r--drivers/net/phy/marvell.c16
-rw-r--r--drivers/net/phy/mdio-mux.c7
-rw-r--r--drivers/net/phy/micrel.c13
-rw-r--r--drivers/net/phy/phy.c6
-rw-r--r--drivers/net/phy/vitesse.c16
-rw-r--r--drivers/net/ppp/pppoe.c14
-rw-r--r--drivers/net/ppp/pptp.c6
-rw-r--r--drivers/net/tun.c4
-rw-r--r--drivers/net/usb/cdc_ether.c5
-rw-r--r--drivers/net/usb/cdc_mbim.c28
-rw-r--r--drivers/net/usb/cdc_ncm.c67
-rw-r--r--drivers/net/usb/kaweth.c6
-rw-r--r--drivers/net/usb/qmi_wwan.c23
-rw-r--r--drivers/net/usb/r8152.c31
-rw-r--r--drivers/net/usb/usbnet.c6
-rw-r--r--drivers/net/veth.c6
-rw-r--r--drivers/net/virtio_net.c34
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c78
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
-rw-r--r--drivers/net/vrf.c21
-rw-r--r--drivers/net/vxlan.c75
-rw-r--r--drivers/net/wan/hdlc_fr.c10
-rw-r--r--drivers/net/wan/x25_asy.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c49
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h17
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c2
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c53
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c47
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c11
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c97
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h4
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c19
-rw-r--r--drivers/net/wireless/libertas/debugfs.c181
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c82
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c2
-rw-r--r--drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c17
-rw-r--r--drivers/net/xen-netback/netback.c34
-rw-r--r--drivers/nfc/nfcmrvl/Kconfig2
-rw-r--r--drivers/nfc/nfcmrvl/fw_dnld.c12
-rw-r--r--drivers/nfc/nfcmrvl/main.c15
-rw-r--r--drivers/nfc/nfcmrvl/uart.c26
-rw-r--r--drivers/nvdimm/blk.c3
-rw-r--r--drivers/nvdimm/btt.c3
-rw-r--r--drivers/nvdimm/e820.c15
-rw-r--r--drivers/nvdimm/pmem.c46
-rw-r--r--drivers/nvme/host/Makefile3
-rw-r--r--drivers/nvme/host/lightnvm.c187
-rw-r--r--drivers/nvme/host/nvme.h14
-rw-r--r--drivers/nvme/host/pci.c118
-rw-r--r--drivers/of/address.c5
-rw-r--r--drivers/of/fdt.c7
-rw-r--r--drivers/of/irq.c3
-rw-r--r--drivers/of/of_pci.c20
-rw-r--r--drivers/of/of_reserved_mem.c19
-rw-r--r--drivers/parisc/ccio-dma.c2
-rw-r--r--drivers/parisc/iommu-helpers.h15
-rw-r--r--drivers/pci/host/Kconfig1
-rw-r--r--drivers/pci/host/pcie-altera.c23
-rw-r--r--drivers/pci/host/pcie-designware.c1
-rw-r--r--drivers/pci/host/pcie-hisi.c8
-rw-r--r--drivers/pci/msi.c8
-rw-r--r--drivers/pci/pci-acpi.c42
-rw-r--r--drivers/pci/pci-driver.c16
-rw-r--r--drivers/pci/pci-sysfs.c5
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/probe.c34
-rw-r--r--drivers/perf/arm_pmu.c15
-rw-r--r--drivers/phy/Kconfig1
-rw-r--r--drivers/phy/phy-bcm-cygnus-pcie.c16
-rw-r--r--drivers/phy/phy-berlin-sata.c20
-rw-r--r--drivers/phy/phy-brcmstb-sata.c17
-rw-r--r--drivers/phy/phy-core.c21
-rw-r--r--drivers/phy/phy-miphy28lp.c16
-rw-r--r--drivers/phy/phy-miphy365x.c16
-rw-r--r--drivers/phy/phy-mt65xx-usb3.c20
-rw-r--r--drivers/phy/phy-rockchip-usb.c17
-rw-r--r--drivers/pinctrl/Kconfig7
-rw-r--r--drivers/pinctrl/Makefile7
-rw-r--r--drivers/pinctrl/bcm/Kconfig48
-rw-r--r--drivers/pinctrl/bcm/Makefile3
-rw-r--r--drivers/pinctrl/bcm/pinctrl-bcm2835.c15
-rw-r--r--drivers/pinctrl/bcm/pinctrl-iproc-gpio.c (renamed from drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c)358
-rw-r--r--drivers/pinctrl/bcm/pinctrl-nsp-gpio.c749
-rw-r--r--drivers/pinctrl/berlin/Makefile2
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx1-core.c8
-rw-r--r--drivers/pinctrl/freescale/pinctrl-vf610.c2
-rw-r--r--drivers/pinctrl/intel/pinctrl-broxton.c1
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.c41
-rw-r--r--drivers/pinctrl/intel/pinctrl-intel.h3
-rw-r--r--drivers/pinctrl/intel/pinctrl-sunrisepoint.c1
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8127.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8135.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mt8173.c2
-rw-r--r--drivers/pinctrl/mediatek/pinctrl-mtk-common.c39
-rw-r--r--drivers/pinctrl/mvebu/Makefile2
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-mvebu.c29
-rw-r--r--drivers/pinctrl/pinconf-generic.c1
-rw-r--r--drivers/pinctrl/pinctrl-adi2.c24
-rw-r--r--drivers/pinctrl/pinctrl-at91-pio4.c17
-rw-r--r--drivers/pinctrl/pinctrl-at91.c14
-rw-r--r--drivers/pinctrl/pinctrl-lantiq.h8
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c58
-rw-r--r--drivers/pinctrl/pinctrl-single.c5
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c4
-rw-r--r--drivers/pinctrl/pinctrl-tegra.c1
-rw-r--r--drivers/pinctrl/pinctrl-xway.c1187
-rw-r--r--drivers/pinctrl/pxa/Kconfig17
-rw-r--r--drivers/pinctrl/pxa/Makefile2
-rw-r--r--drivers/pinctrl/pxa/pinctrl-pxa27x.c566
-rw-r--r--drivers/pinctrl/pxa/pinctrl-pxa2xx.c436
-rw-r--r--drivers/pinctrl/pxa/pinctrl-pxa2xx.h92
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8996.c1942
-rw-r--r--drivers/pinctrl/qcom/pinctrl-qdf2xxx.c14
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c15
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c14
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c21
-rw-r--r--drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c21
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c103
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c2
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.h1
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-emev2.c136
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7740.c2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7778.c22
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7779.c62
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c58
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c167
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7794.c86
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7795.c1505
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh73a0.c548
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7734.c35
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c4
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h74
-rw-r--r--drivers/pinctrl/sirf/pinctrl-atlas7.c134
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c8
-rw-r--r--drivers/pinctrl/spear/Makefile2
-rw-r--r--drivers/pinctrl/sunxi/Kconfig9
-rw-r--r--drivers/pinctrl/sunxi/Makefile2
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c515
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c181
-rw-r--r--drivers/pinctrl/uniphier/Kconfig23
-rw-r--r--drivers/platform/chrome/Kconfig5
-rw-r--r--drivers/platform/chrome/Makefile3
-rw-r--r--drivers/platform/chrome/chromeos_laptop.c4
-rw-r--r--drivers/platform/chrome/cros_ec_dev.c7
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c31
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c21
-rw-r--r--drivers/platform/chrome/cros_ec_vbc.c137
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/asus-wmi.c4
-rw-r--r--drivers/platform/x86/ideapad-laptop.c49
-rw-r--r--drivers/platform/x86/intel_menlow.c8
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c3
-rw-r--r--drivers/powercap/intel_rapl.c7
-rw-r--r--drivers/pwm/Kconfig49
-rw-r--r--drivers/pwm/Makefile4
-rw-r--r--drivers/pwm/core.c37
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c4
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c26
-rw-r--r--drivers/pwm/pwm-berlin.c219
-rw-r--r--drivers/pwm/pwm-brcmstb.c343
-rw-r--r--drivers/pwm/pwm-lpss-pci.c37
-rw-r--r--drivers/pwm/pwm-lpss-platform.c7
-rw-r--r--drivers/pwm/pwm-lpss.c62
-rw-r--r--drivers/pwm/pwm-lpss.h2
-rw-r--r--drivers/pwm/pwm-mtk-disp.c243
-rw-r--r--drivers/pwm/pwm-pca9685.c20
-rw-r--r--drivers/pwm/pwm-rcar.c274
-rw-r--r--drivers/pwm/pwm-sun4i.c27
-rw-r--r--drivers/pwm/sysfs.c75
-rw-r--r--drivers/remoteproc/remoteproc_core.c2
-rw-r--r--drivers/remoteproc/remoteproc_debugfs.c2
-rw-r--r--drivers/rtc/rtc-da9063.c19
-rw-r--r--drivers/rtc/rtc-ds1307.c44
-rw-r--r--drivers/rtc/rtc-rk808.c48
-rw-r--r--drivers/s390/block/dcssblk.c8
-rw-r--r--drivers/s390/block/xpram.c5
-rw-r--r--drivers/s390/char/sclp_early.c16
-rw-r--r--drivers/s390/char/vmcp.c11
-rw-r--r--drivers/s390/char/vmur.c15
-rw-r--r--drivers/s390/char/zcore.c13
-rw-r--r--drivers/s390/cio/chsc.c37
-rw-r--r--drivers/s390/cio/chsc.h15
-rw-r--r--drivers/s390/cio/cio.c14
-rw-r--r--drivers/s390/cio/css.c5
-rw-r--r--drivers/s390/crypto/Makefile7
-rw-r--r--drivers/s390/crypto/ap_bus.c10
-rw-r--r--drivers/s390/crypto/zcrypt_api.c10
-rw-r--r--drivers/s390/crypto/zcrypt_api.h1
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype50.c1
-rw-r--r--drivers/s390/crypto/zcrypt_msgtype6.c3
-rw-r--r--drivers/s390/virtio/virtio_ccw.c62
-rw-r--r--drivers/sbus/char/openprom.c13
-rw-r--r--drivers/scsi/53c700.c11
-rw-r--r--drivers/scsi/FlashPoint.c2
-rw-r--r--drivers/scsi/Kconfig3
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/aacraid/aachba.c265
-rw-r--r--drivers/scsi/aacraid/aacraid.h20
-rw-r--r--drivers/scsi/aacraid/comminit.c147
-rw-r--r--drivers/scsi/aacraid/commsup.c113
-rw-r--r--drivers/scsi/aacraid/linit.c152
-rw-r--r--drivers/scsi/aacraid/rx.c1
-rw-r--r--drivers/scsi/aacraid/sa.c1
-rw-r--r--drivers/scsi/aacraid/src.c64
-rw-r--r--drivers/scsi/advansys.c8
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c1
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c3
-rw-r--r--drivers/scsi/be2iscsi/be_main.c64
-rw-r--r--drivers/scsi/be2iscsi/be_main.h7
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c24
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h7
-rw-r--r--drivers/scsi/bfa/bfad_im.c2
-rw-r--r--drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h6
-rw-r--r--drivers/scsi/bnx2fc/Kconfig5
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc.h9
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_constants.h6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_debug.c6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_debug.h6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_els.c10
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c26
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_hwi.c6
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c106
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_tgt.c12
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c2
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c1
-rw-r--r--drivers/scsi/esp_scsi.c1
-rw-r--r--drivers/scsi/fcoe/fcoe.c4
-rw-r--r--drivers/scsi/fnic/fnic_main.c8
-rw-r--r--drivers/scsi/hosts.c18
-rw-r--r--drivers/scsi/hpsa.c1346
-rw-r--r--drivers/scsi/hpsa.h47
-rw-r--r--drivers/scsi/hpsa_cmd.h30
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c1
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c10
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.h1
-rw-r--r--drivers/scsi/ipr.c154
-rw-r--r--drivers/scsi/ipr.h22
-rw-r--r--drivers/scsi/isci/init.c5
-rw-r--r--drivers/scsi/libfc/fc_npiv.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c3
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h62
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c466
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c28
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c404
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h36
-rw-r--r--drivers/scsi/mpt2sas/Kconfig67
-rw-r--r--drivers/scsi/mpt2sas/Makefile7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h1170
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h3068
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h461
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h1708
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h366
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_sas.h288
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h481
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_type.h61
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c4899
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h1235
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c1527
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c3101
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h419
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h182
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c8855
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c2173
-rw-r--r--drivers/scsi/mpt3sas/Kconfig27
-rw-r--r--drivers/scsi/mpt3sas/Makefile3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c668
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h233
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c42
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c259
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.h6
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_debug.h16
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c1556
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c18
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_warpdrive.c344
-rw-r--r--drivers/scsi/mvsas/mv_init.c7
-rw-r--r--drivers/scsi/mvumi.c10
-rw-r--r--drivers/scsi/pm8001/pm8001_defs.h2
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c216
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h6
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c34
-rw-r--r--drivers/scsi/pmcraid.c6
-rw-r--r--drivers/scsi/qla2xxx/qla_nx.c3
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c1
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c153
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c8
-rw-r--r--drivers/scsi/scsi.c27
-rw-r--r--drivers/scsi/scsi_debug.c9
-rw-r--r--drivers/scsi/scsi_pm.c20
-rw-r--r--drivers/scsi/scsi_scan.c18
-rw-r--r--drivers/scsi/scsi_sysfs.c50
-rw-r--r--drivers/scsi/sd.c73
-rw-r--r--drivers/scsi/sd.h1
-rw-r--r--drivers/scsi/ses.c30
-rw-r--r--drivers/scsi/sg.c8
-rw-r--r--drivers/scsi/snic/snic_main.c10
-rw-r--r--drivers/scsi/st.c35
-rw-r--r--drivers/scsi/stex.c21
-rw-r--r--drivers/scsi/storvsc_drv.c294
-rw-r--r--drivers/scsi/ufs/Kconfig2
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c905
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h68
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c98
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.h41
-rw-r--r--drivers/scsi/ufs/ufshcd.c130
-rw-r--r--drivers/scsi/ufs/ufshcd.h149
-rw-r--r--drivers/sh/pm_runtime.c2
-rw-r--r--drivers/soc/Kconfig2
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/brcmstb/Kconfig9
-rw-r--r--drivers/soc/brcmstb/Makefile1
-rw-r--r--drivers/soc/brcmstb/biuctrl.c116
-rw-r--r--drivers/soc/brcmstb/common.c33
-rw-r--r--drivers/soc/mediatek/Kconfig1
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c10
-rw-r--r--drivers/soc/mediatek/mtk-scpsys.c83
-rw-r--r--drivers/soc/qcom/Kconfig17
-rw-r--r--drivers/soc/qcom/smd-rpm.c68
-rw-r--r--drivers/soc/qcom/smd.c296
-rw-r--r--drivers/soc/qcom/smem.c368
-rw-r--r--drivers/soc/qcom/spm.c10
-rw-r--r--drivers/soc/rockchip/Kconfig18
-rw-r--r--drivers/soc/rockchip/Makefile4
-rw-r--r--drivers/soc/rockchip/pm_domains.c490
-rw-r--r--drivers/soc/ti/knav_qmss.h3
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c14
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c69
-rw-r--r--drivers/spi/spi-bcm63xx.c4
-rw-r--r--drivers/spi/spi-fsl-dspi.c12
-rw-r--r--drivers/spi/spi-mt65xx.c26
-rw-r--r--drivers/spi/spi-pl022.c28
-rw-r--r--drivers/spi/spi.c4
-rw-r--r--drivers/spi/spidev.c2
-rw-r--r--drivers/staging/android/ion/ion_chunk_heap.c4
-rw-r--r--drivers/staging/iio/Kconfig3
-rw-r--r--drivers/staging/iio/adc/lpc32xx_adc.c4
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c2
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h1
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c17
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c2
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h4
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c5
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c26
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c4
-rw-r--r--drivers/staging/lustre/lustre/obdecho/echo_client.c20
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/Kconfig2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c5
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c7
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c4
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c2
-rw-r--r--drivers/staging/media/lirc/lirc_parallel.c35
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c20
-rw-r--r--drivers/staging/media/lirc/lirc_serial.c50
-rw-r--r--drivers/staging/media/omap4iss/Kconfig2
-rw-r--r--drivers/staging/media/omap4iss/iss.c4
-rw-r--r--drivers/staging/media/omap4iss/iss.h2
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c6
-rw-r--r--drivers/staging/media/omap4iss/iss_csiphy.h2
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c4
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c3
-rw-r--r--drivers/staging/wilc1000/coreconfigurator.c48
-rw-r--r--drivers/target/iscsi/iscsi_target.c13
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c791
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c1
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c10
-rw-r--r--drivers/target/iscsi/iscsi_target_stat.c666
-rw-r--r--drivers/target/loopback/tcm_loop.c61
-rw-r--r--drivers/target/sbp/sbp_target.c87
-rw-r--r--drivers/target/target_core_configfs.c1209
-rw-r--r--drivers/target/target_core_fabric_configfs.c275
-rw-r--r--drivers/target/target_core_internal.h3
-rw-r--r--drivers/target/target_core_sbc.c17
-rw-r--r--drivers/target/target_core_stat.c920
-rw-r--r--drivers/target/target_core_tmr.c7
-rw-r--r--drivers/target/target_core_transport.c26
-rw-r--r--drivers/target/target_core_user.c4
-rw-r--r--drivers/target/tcm_fc/tfc_cmd.c1
-rw-r--r--drivers/target/tcm_fc/tfc_conf.c44
-rw-r--r--drivers/target/tcm_fc/tfc_io.c1
-rw-r--r--drivers/target/tcm_fc/tfc_sess.c1
-rw-r--r--drivers/thermal/Kconfig19
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/armada_thermal.c6
-rw-r--r--drivers/thermal/cpu_cooling.c8
-rw-r--r--drivers/thermal/devfreq_cooling.c573
-rw-r--r--drivers/thermal/imx_thermal.c75
-rw-r--r--drivers/thermal/of-thermal.c2
-rw-r--r--drivers/thermal/power_allocator.c24
-rw-r--r--drivers/thermal/rcar_thermal.c49
-rw-r--r--drivers/thermal/rockchip_thermal.c353
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c68
-rw-r--r--drivers/thermal/ti-soc-thermal/Kconfig15
-rw-r--r--drivers/thermal/ti-soc-thermal/Makefile1
-rw-r--r--drivers/thermal/ti-soc-thermal/omap3-thermal-data.c176
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.c14
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-bandgap.h11
-rw-r--r--drivers/tty/n_tty.c24
-rw-r--r--drivers/tty/serial/8250/8250_fsl.c1
-rw-r--r--drivers/tty/serial/8250/8250_uniphier.c8
-rw-r--r--drivers/tty/serial/8250/Kconfig1
-rw-r--r--drivers/tty/serial/Kconfig2
-rw-r--r--drivers/tty/serial/bcm63xx_uart.c2
-rw-r--r--drivers/tty/serial/earlycon.c2
-rw-r--r--drivers/tty/serial/etraxfs-uart.c2
-rw-r--r--drivers/tty/serial/sh-sci.c2
-rw-r--r--drivers/tty/serial/sunhv.c12
-rw-r--r--drivers/tty/sysrq.c6
-rw-r--r--drivers/tty/tty_audit.c2
-rw-r--r--drivers/tty/tty_buffer.c2
-rw-r--r--drivers/tty/tty_io.c4
-rw-r--r--drivers/tty/tty_ioctl.c4
-rw-r--r--drivers/tty/tty_ldisc.c2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_imx.c142
-rw-r--r--drivers/usb/chipidea/debug.c2
-rw-r--r--drivers/usb/chipidea/udc.c17
-rw-r--r--drivers/usb/chipidea/usbmisc_imx.c10
-rw-r--r--drivers/usb/class/cdc-acm.c5
-rw-r--r--drivers/usb/class/usblp.c2
-rw-r--r--drivers/usb/core/Kconfig3
-rw-r--r--drivers/usb/core/config.c3
-rw-r--r--drivers/usb/core/devices.c26
-rw-r--r--drivers/usb/core/devio.c26
-rw-r--r--drivers/usb/core/hub.c44
-rw-r--r--drivers/usb/core/port.c4
-rw-r--r--drivers/usb/core/quirks.c9
-rw-r--r--drivers/usb/dwc2/hcd.c9
-rw-r--r--drivers/usb/dwc2/platform.c84
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c4
-rw-r--r--drivers/usb/dwc3/gadget.c25
-rw-r--r--drivers/usb/gadget/configfs.c295
-rw-r--r--drivers/usb/gadget/function/f_acm.c26
-rw-r--r--drivers/usb/gadget/function/f_ecm.c8
-rw-r--r--drivers/usb/gadget/function/f_eem.c8
-rw-r--r--drivers/usb/gadget/function/f_fs.c6
-rw-r--r--drivers/usb/gadget/function/f_hid.c34
-rw-r--r--drivers/usb/gadget/function/f_loopback.c33
-rw-r--r--drivers/usb/gadget/function/f_mass_storage.c119
-rw-r--r--drivers/usb/gadget/function/f_midi.c40
-rw-r--r--drivers/usb/gadget/function/f_ncm.c8
-rw-r--r--drivers/usb/gadget/function/f_obex.c26
-rw-r--r--drivers/usb/gadget/function/f_phonet.c25
-rw-r--r--drivers/usb/gadget/function/f_printer.c30
-rw-r--r--drivers/usb/gadget/function/f_rndis.c8
-rw-r--r--drivers/usb/gadget/function/f_serial.c26
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c83
-rw-r--r--drivers/usb/gadget/function/f_subset.c8
-rw-r--r--drivers/usb/gadget/function/f_uac1.c39
-rw-r--r--drivers/usb/gadget/function/f_uac2.c28
-rw-r--r--drivers/usb/gadget/function/u_ether_configfs.h44
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c387
-rw-r--r--drivers/usb/gadget/function/uvc_queue.c4
-rw-r--r--drivers/usb/gadget/legacy/tcm_usb_gadget.c44
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c3
-rw-r--r--drivers/usb/host/ohci-at91.c11
-rw-r--r--drivers/usb/host/uhci-debug.c23
-rw-r--r--drivers/usb/host/whci/qset.c4
-rw-r--r--drivers/usb/host/xhci-hub.c62
-rw-r--r--drivers/usb/host/xhci-pci.c8
-rw-r--r--drivers/usb/host/xhci-ring.c35
-rw-r--r--drivers/usb/host/xhci.c18
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c16
-rw-r--r--drivers/usb/musb/Kconfig2
-rw-r--r--drivers/usb/musb/musb_core.c20
-rw-r--r--drivers/usb/musb/musb_host.c22
-rw-r--r--drivers/usb/phy/Kconfig4
-rw-r--r--drivers/usb/phy/phy-msm-usb.c6
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c12
-rw-r--r--drivers/usb/phy/phy-omap-otg.c2
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c11
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/ipaq.c3
-rw-r--r--drivers/usb/serial/option.c11
-rw-r--r--drivers/usb/serial/qcserial.c94
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c2
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.h4
-rw-r--r--drivers/usb/serial/usb-serial-simple.c1
-rw-r--r--drivers/usb/storage/uas.c9
-rw-r--r--drivers/usb/storage/unusual_devs.h2
-rw-r--r--drivers/usb/storage/unusual_uas.h2
-rw-r--r--drivers/vfio/pci/vfio_pci.c2
-rw-r--r--drivers/vfio/pci/vfio_pci_config.c74
-rw-r--r--drivers/vfio/platform/Makefile6
-rw-r--r--drivers/vfio/platform/reset/Kconfig8
-rw-r--r--drivers/vfio/platform/reset/Makefile2
-rw-r--r--drivers/vfio/platform/reset/vfio_platform_amdxgbe.c127
-rw-r--r--drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c19
-rw-r--r--drivers/vfio/platform/vfio_amba.c1
-rw-r--r--drivers/vfio/platform/vfio_platform.c2
-rw-r--r--drivers/vfio/platform/vfio_platform_common.c152
-rw-r--r--drivers/vfio/platform/vfio_platform_irq.c1
-rw-r--r--drivers/vfio/platform/vfio_platform_private.h40
-rw-r--r--drivers/vfio/vfio.c40
-rw-r--r--drivers/vfio/vfio_iommu_type1.c15
-rw-r--r--drivers/vhost/scsi.c41
-rw-r--r--drivers/vhost/vhost.c8
-rw-r--r--drivers/video/fbdev/fsl-diu-fb.c13
-rw-r--r--drivers/video/fbdev/omap2/dss/venc.c12
-rw-r--r--drivers/virtio/virtio.c1
-rw-r--r--drivers/virtio/virtio_ring.c48
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/mtk_wdt.c1
-rw-r--r--drivers/watchdog/omap_wdt.c2
-rw-r--r--drivers/watchdog/pnx4008_wdt.c8
-rw-r--r--drivers/watchdog/tegra_wdt.c4
-rw-r--r--drivers/watchdog/w83977f_wdt.c2
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/acpi.c2
-rw-r--r--drivers/xen/efi.c30
-rw-r--r--drivers/xen/events/events_base.c5
-rw-r--r--drivers/xen/events/events_fifo.c23
-rw-r--r--drivers/xen/evtchn.c123
-rw-r--r--drivers/xen/gntdev.c207
-rw-r--r--drivers/xen/grant-table.c4
-rw-r--r--drivers/xen/pcpu.c8
-rw-r--r--drivers/xen/time.c88
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c2
-rw-r--r--drivers/xen/xen-acpi-pad.c4
-rw-r--r--drivers/xen/xen-acpi-processor.c8
-rw-r--r--drivers/xen/xen-pciback/pciback.h1
-rw-r--r--drivers/xen/xen-pciback/pciback_ops.c75
-rw-r--r--drivers/xen/xen-pciback/xenbus.c4
-rw-r--r--drivers/xen/xen-scsiback.c34
-rw-r--r--drivers/xen/xenfs/xensyms.c4
-rw-r--r--firmware/WHENCE2
-rw-r--r--fs/9p/Makefile5
-rw-r--r--fs/9p/acl.c83
-rw-r--r--fs/9p/cache.c8
-rw-r--r--fs/9p/cache.h1
-rw-r--r--fs/9p/v9fs.h2
-rw-r--r--fs/9p/vfs_inode.c30
-rw-r--r--fs/9p/vfs_inode_dotl.c21
-rw-r--r--fs/9p/xattr.c38
-rw-r--r--fs/9p/xattr.h3
-rw-r--r--fs/9p/xattr_security.c80
-rw-r--r--fs/9p/xattr_trusted.c80
-rw-r--r--fs/9p/xattr_user.c80
-rw-r--r--fs/Kconfig16
-rw-r--r--fs/adfs/adfs.h6
-rw-r--r--fs/adfs/dir.c6
-rw-r--r--fs/adfs/dir_f.c2
-rw-r--r--fs/adfs/dir_fplus.c2
-rw-r--r--fs/affs/affs.h2
-rw-r--r--fs/affs/amigaffs.c13
-rw-r--r--fs/affs/inode.c1
-rw-r--r--fs/affs/namei.c1
-rw-r--r--fs/affs/super.c2
-rw-r--r--fs/affs/symlink.c9
-rw-r--r--fs/afs/inode.c1
-rw-r--r--fs/afs/proc.c25
-rw-r--r--fs/autofs4/symlink.c14
-rw-r--r--fs/bad_inode.c2
-rw-r--r--fs/befs/linuxvfs.c40
-rw-r--r--fs/binfmt_elf.c22
-rw-r--r--fs/binfmt_elf_fdpic.c15
-rw-r--r--fs/block_dev.c52
-rw-r--r--fs/btrfs/acl.c8
-rw-r--r--fs/btrfs/backref.c2
-rw-r--r--fs/btrfs/ctree.h12
-rw-r--r--fs/btrfs/disk-io.c5
-rw-r--r--fs/btrfs/extent-tree.c144
-rw-r--r--fs/btrfs/file.c47
-rw-r--r--fs/btrfs/free-space-cache.c10
-rw-r--r--fs/btrfs/inode.c107
-rw-r--r--fs/btrfs/ioctl.c186
-rw-r--r--fs/btrfs/qgroup.c18
-rw-r--r--fs/btrfs/scrub.c241
-rw-r--r--fs/btrfs/super.c4
-rw-r--r--fs/btrfs/tests/free-space-tests.c4
-rw-r--r--fs/btrfs/transaction.c33
-rw-r--r--fs/btrfs/transaction.h6
-rw-r--r--fs/btrfs/volumes.c33
-rw-r--r--fs/btrfs/volumes.h2
-rw-r--r--fs/btrfs/xattr.c170
-rw-r--r--fs/btrfs/xattr.h2
-rw-r--r--fs/buffer.c45
-rw-r--r--fs/cachefiles/daemon.c12
-rw-r--r--fs/cachefiles/namei.c2
-rw-r--r--fs/cachefiles/rdwr.c75
-rw-r--r--fs/ceph/acl.c16
-rw-r--r--fs/ceph/cache.c2
-rw-r--r--fs/ceph/caps.c76
-rw-r--r--fs/ceph/file.c87
-rw-r--r--fs/ceph/inode.c3
-rw-r--r--fs/ceph/mds_client.c57
-rw-r--r--fs/ceph/mds_client.h3
-rw-r--r--fs/ceph/super.h1
-rw-r--r--fs/cifs/cifsfs.c80
-rw-r--r--fs/cifs/cifsfs.h6
-rw-r--r--fs/cifs/cifsglob.h8
-rw-r--r--fs/cifs/connect.c78
-rw-r--r--fs/cifs/inode.c6
-rw-r--r--fs/cifs/ioctl.c123
-rw-r--r--fs/cifs/link.c10
-rw-r--r--fs/cifs/smb2file.c19
-rw-r--r--fs/cifs/smb2ops.c10
-rw-r--r--fs/cifs/smb2pdu.c123
-rw-r--r--fs/cifs/smb2pdu.h45
-rw-r--r--fs/cifs/smbfsctl.h2
-rw-r--r--fs/cifs/xattr.c16
-rw-r--r--fs/coda/cnode.c5
-rw-r--r--fs/coda/symlink.c4
-rw-r--r--fs/compat.c21
-rw-r--r--fs/compat_ioctl.c271
-rw-r--r--fs/configfs/dir.c110
-rw-r--r--fs/configfs/file.c12
-rw-r--r--fs/configfs/symlink.c22
-rw-r--r--fs/coredump.c8
-rw-r--r--fs/cramfs/inode.c1
-rw-r--r--fs/dax.c20
-rw-r--r--fs/dcache.c16
-rw-r--r--fs/debugfs/inode.c6
-rw-r--r--fs/direct-io.c25
-rw-r--r--fs/dlm/config.c288
-rw-r--r--fs/dlm/lowcomms.c4
-rw-r--r--fs/dlm/user.c11
-rw-r--r--fs/ecryptfs/inode.c21
-rw-r--r--fs/efs/inode.c1
-rw-r--r--fs/efs/symlink.c4
-rw-r--r--fs/exec.c4
-rw-r--r--fs/exofs/inode.c6
-rw-r--r--fs/exofs/namei.c1
-rw-r--r--fs/ext2/inode.c1
-rw-r--r--fs/ext2/namei.c1
-rw-r--r--fs/ext2/super.c2
-rw-r--r--fs/ext2/symlink.c5
-rw-r--r--fs/ext2/xattr.c22
-rw-r--r--fs/ext2/xattr_security.c30
-rw-r--r--fs/ext2/xattr_trusted.c32
-rw-r--r--fs/ext2/xattr_user.c32
-rw-r--r--fs/ext4/crypto.c2
-rw-r--r--fs/ext4/ext4.h51
-rw-r--r--fs/ext4/inode.c5
-rw-r--r--fs/ext4/namei.c1
-rw-r--r--fs/ext4/page-io.c5
-rw-r--r--fs/ext4/super.c6
-rw-r--r--fs/ext4/symlink.c31
-rw-r--r--fs/ext4/sysfs.c2
-rw-r--r--fs/ext4/xattr.c24
-rw-r--r--fs/ext4/xattr_security.c31
-rw-r--r--fs/ext4/xattr_trusted.c32
-rw-r--r--fs/ext4/xattr_user.c32
-rw-r--r--fs/f2fs/debug.c6
-rw-r--r--fs/f2fs/f2fs.h6
-rw-r--r--fs/f2fs/inode.c1
-rw-r--r--fs/f2fs/namei.c31
-rw-r--r--fs/f2fs/xattr.c122
-rw-r--r--fs/f2fs/xattr.h2
-rw-r--r--fs/fat/dir.c16
-rw-r--r--fs/fcntl.c3
-rw-r--r--fs/file.c6
-rw-r--r--fs/freevxfs/vxfs_inode.c1
-rw-r--r--fs/fscache/netfs.c38
-rw-r--r--fs/fscache/page.c2
-rw-r--r--fs/fuse/cuse.c2
-rw-r--r--fs/fuse/dir.c17
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/gfs2/acl.c4
-rw-r--r--fs/gfs2/acl.h2
-rw-r--r--fs/gfs2/inode.c19
-rw-r--r--fs/gfs2/ops_fstype.c4
-rw-r--r--fs/gfs2/xattr.c63
-rw-r--r--fs/gfs2/xattr.h1
-rw-r--r--fs/hfs/mdb.c4
-rw-r--r--fs/hfsplus/inode.c2
-rw-r--r--fs/hfsplus/posix_acl.c8
-rw-r--r--fs/hfsplus/xattr.c33
-rw-r--r--fs/hfsplus/xattr_security.c21
-rw-r--r--fs/hfsplus/xattr_trusted.c21
-rw-r--r--fs/hfsplus/xattr_user.c21
-rw-r--r--fs/hostfs/hostfs_kern.c26
-rw-r--r--fs/hpfs/inode.c1
-rw-r--r--fs/hpfs/map.c2
-rw-r--r--fs/hpfs/namei.c5
-rw-r--r--fs/hugetlbfs/inode.c66
-rw-r--r--fs/inode.c8
-rw-r--r--fs/internal.h9
-rw-r--r--fs/ioctl.c71
-rw-r--r--fs/isofs/inode.c1
-rw-r--r--fs/isofs/rock.c4
-rw-r--r--fs/jbd2/transaction.c18
-rw-r--r--fs/jffs2/security.c30
-rw-r--r--fs/jffs2/symlink.c2
-rw-r--r--fs/jffs2/xattr.c25
-rw-r--r--fs/jffs2/xattr_trusted.c26
-rw-r--r--fs/jffs2/xattr_user.c28
-rw-r--r--fs/jfs/acl.c8
-rw-r--r--fs/jfs/inode.c1
-rw-r--r--fs/jfs/jfs_logmgr.c9
-rw-r--r--fs/jfs/namei.c1
-rw-r--r--fs/jfs/symlink.c5
-rw-r--r--fs/kernfs/inode.c4
-rw-r--r--fs/kernfs/symlink.c24
-rw-r--r--fs/libfs.c22
-rw-r--r--fs/lockd/host.c8
-rw-r--r--fs/lockd/mon.c125
-rw-r--r--fs/lockd/netns.h4
-rw-r--r--fs/lockd/svc.c2
-rw-r--r--fs/lockd/svc4proc.c2
-rw-r--r--fs/lockd/svcproc.c2
-rw-r--r--fs/locks.c160
-rw-r--r--fs/logfs/dir.c9
-rw-r--r--fs/logfs/inode.c3
-rw-r--r--fs/logfs/logfs.h5
-rw-r--r--fs/logfs/readwrite.c4
-rw-r--r--fs/logfs/segment.c2
-rw-r--r--fs/minix/inode.c4
-rw-r--r--fs/minix/itree_v1.c9
-rw-r--r--fs/minix/itree_v2.c9
-rw-r--r--fs/namei.c327
-rw-r--r--fs/namespace.c49
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/ioctl.c2
-rw-r--r--fs/nfs/inode.c43
-rw-r--r--fs/nfs/internal.h2
-rw-r--r--fs/nfs/nfs3acl.c4
-rw-r--r--fs/nfs/nfs42proc.c3
-rw-r--r--fs/nfs/nfs4client.c2
-rw-r--r--fs/nfs/nfs4file.c120
-rw-r--r--fs/nfs/nfs4proc.c97
-rw-r--r--fs/nfs/nfs4xdr.c1
-rw-r--r--fs/nfs/objlayout/objio_osd.c5
-rw-r--r--fs/nfs/pagelist.c2
-rw-r--r--fs/nfs/pnfs.c60
-rw-r--r--fs/nfs/symlink.c39
-rw-r--r--fs/nfsd/nfs3xdr.c6
-rw-r--r--fs/nfsd/nfs4layouts.c34
-rw-r--r--fs/nfsd/nfs4proc.c67
-rw-r--r--fs/nfsd/nfs4state.c270
-rw-r--r--fs/nfsd/nfs4xdr.c29
-rw-r--r--fs/nfsd/nfscache.c32
-rw-r--r--fs/nfsd/nfsfh.c5
-rw-r--r--fs/nfsd/nfsfh.h20
-rw-r--r--fs/nfsd/state.h47
-rw-r--r--fs/nfsd/trace.c2
-rw-r--r--fs/nfsd/trace.h2
-rw-r--r--fs/nfsd/vfs.c35
-rw-r--r--fs/nfsd/vfs.h6
-rw-r--r--fs/nfsd/xdr4.h12
-rw-r--r--fs/nilfs2/file.c2
-rw-r--r--fs/nilfs2/inode.c1
-rw-r--r--fs/nilfs2/namei.c4
-rw-r--r--fs/nilfs2/super.c6
-rw-r--r--fs/ocfs2/cluster/heartbeat.c205
-rw-r--r--fs/ocfs2/cluster/nodemanager.c281
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c2
-rw-r--r--fs/ocfs2/inode.c1
-rw-r--r--fs/ocfs2/locks.c5
-rw-r--r--fs/ocfs2/namei.c3
-rw-r--r--fs/ocfs2/resize.c15
-rw-r--r--fs/ocfs2/symlink.c3
-rw-r--r--fs/ocfs2/xattr.c195
-rw-r--r--fs/open.c5
-rw-r--r--fs/overlayfs/copy_up.c23
-rw-r--r--fs/overlayfs/inode.c72
-rw-r--r--fs/overlayfs/overlayfs.h3
-rw-r--r--fs/pipe.c18
-rw-r--r--fs/posix_acl.c43
-rw-r--r--fs/proc/base.c42
-rw-r--r--fs/proc/fd.c1
-rw-r--r--fs/proc/inode.c21
-rw-r--r--fs/proc/namespaces.c10
-rw-r--r--fs/proc/self.c18
-rw-r--r--fs/proc/thread_self.c19
-rw-r--r--fs/proc_namespace.c27
-rw-r--r--fs/qnx4/inode.c1
-rw-r--r--fs/qnx6/inode.c1
-rw-r--r--fs/ramfs/inode.c1
-rw-r--r--fs/read_write.c341
-rw-r--r--fs/reiserfs/inode.c1
-rw-r--r--fs/reiserfs/journal.c24
-rw-r--r--fs/reiserfs/namei.c4
-rw-r--r--fs/reiserfs/prints.c9
-rw-r--r--fs/reiserfs/procfs.c5
-rw-r--r--fs/reiserfs/xattr.c22
-rw-r--r--fs/reiserfs/xattr_acl.c8
-rw-r--r--fs/reiserfs/xattr_security.c23
-rw-r--r--fs/reiserfs/xattr_trusted.c22
-rw-r--r--fs/reiserfs/xattr_user.c21
-rw-r--r--fs/romfs/super.c1
-rw-r--r--fs/select.c6
-rw-r--r--fs/splice.c16
-rw-r--r--fs/squashfs/inode.c2
-rw-r--r--fs/squashfs/super.c7
-rw-r--r--fs/squashfs/symlink.c3
-rw-r--r--fs/squashfs/xattr.c86
-rw-r--r--fs/super.c4
-rw-r--r--fs/sysfs/group.c17
-rw-r--r--fs/sysv/inode.c15
-rw-r--r--fs/ubifs/Kconfig15
-rw-r--r--fs/ubifs/debug.c8
-rw-r--r--fs/ubifs/dir.c11
-rw-r--r--fs/ubifs/file.c52
-rw-r--r--fs/ubifs/lpt.c6
-rw-r--r--fs/ubifs/misc.h9
-rw-r--r--fs/ubifs/recovery.c8
-rw-r--r--fs/ubifs/super.c13
-rw-r--r--fs/ubifs/tnc.c3
-rw-r--r--fs/ubifs/ubifs.h8
-rw-r--r--fs/ubifs/xattr.c52
-rw-r--r--fs/udf/inode.c3
-rw-r--r--fs/udf/namei.c8
-rw-r--r--fs/udf/symlink.c4
-rw-r--r--fs/udf/udfdecl.h1
-rw-r--r--fs/ufs/Makefile2
-rw-r--r--fs/ufs/inode.c5
-rw-r--r--fs/ufs/namei.c5
-rw-r--r--fs/ufs/symlink.c42
-rw-r--r--fs/ufs/ufs.h4
-rw-r--r--fs/xattr.c232
-rw-r--r--fs/xfs/Makefile2
-rw-r--r--fs/xfs/kmem.c10
-rw-r--r--fs/xfs/libxfs/xfs_alloc.c30
-rw-r--r--fs/xfs/libxfs/xfs_alloc.h8
-rw-r--r--fs/xfs/libxfs/xfs_attr.c6
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.c3
-rw-r--r--fs/xfs/libxfs/xfs_attr_remote.c2
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c65
-rw-r--r--fs/xfs/libxfs/xfs_bmap.h13
-rw-r--r--fs/xfs/libxfs/xfs_btree.c21
-rw-r--r--fs/xfs/libxfs/xfs_btree.h39
-rw-r--r--fs/xfs/libxfs/xfs_da_btree.c4
-rw-r--r--fs/xfs/libxfs/xfs_dir2.c6
-rw-r--r--fs/xfs/libxfs/xfs_dir2_block.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_data.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_leaf.c3
-rw-r--r--fs/xfs/libxfs/xfs_dir2_node.c3
-rw-r--r--fs/xfs/libxfs/xfs_format.h18
-rw-r--r--fs/xfs/libxfs/xfs_fs.h10
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c10
-rw-r--r--fs/xfs/libxfs/xfs_sb.c10
-rw-r--r--fs/xfs/libxfs/xfs_symlink_remote.c7
-rw-r--r--fs/xfs/xfs_acl.c37
-rw-r--r--fs/xfs/xfs_acl.h8
-rw-r--r--fs/xfs/xfs_aops.c119
-rw-r--r--fs/xfs/xfs_aops.h3
-rw-r--r--fs/xfs/xfs_attr_list.c2
-rw-r--r--fs/xfs/xfs_bmap_util.c38
-rw-r--r--fs/xfs/xfs_buf.c29
-rw-r--r--fs/xfs/xfs_dir2_readdir.c2
-rw-r--r--fs/xfs/xfs_dquot.c14
-rw-r--r--fs/xfs/xfs_file.c116
-rw-r--r--fs/xfs/xfs_icache.c18
-rw-r--r--fs/xfs/xfs_inode.c8
-rw-r--r--fs/xfs/xfs_inode_item.c1
-rw-r--r--fs/xfs/xfs_inode_item.h1
-rw-r--r--fs/xfs/xfs_ioctl.c23
-rw-r--r--fs/xfs/xfs_ioctl32.c2
-rw-r--r--fs/xfs/xfs_iomap.c70
-rw-r--r--fs/xfs/xfs_iops.c18
-rw-r--r--fs/xfs/xfs_linux.h7
-rw-r--r--fs/xfs/xfs_log.c93
-rw-r--r--fs/xfs/xfs_log.h1
-rw-r--r--fs/xfs/xfs_log_priv.h51
-rw-r--r--fs/xfs/xfs_log_recover.c14
-rw-r--r--fs/xfs/xfs_message.c7
-rw-r--r--fs/xfs/xfs_mount.c21
-rw-r--r--fs/xfs/xfs_mount.h5
-rw-r--r--fs/xfs/xfs_pnfs.c5
-rw-r--r--fs/xfs/xfs_qm.c14
-rw-r--r--fs/xfs/xfs_stats.c93
-rw-r--r--fs/xfs/xfs_stats.h36
-rw-r--r--fs/xfs/xfs_super.c57
-rw-r--r--fs/xfs/xfs_sysctl.c15
-rw-r--r--fs/xfs/xfs_sysfs.c185
-rw-r--r--fs/xfs/xfs_sysfs.h1
-rw-r--r--fs/xfs/xfs_trace.h2
-rw-r--r--fs/xfs/xfs_trans.c6
-rw-r--r--fs/xfs/xfs_trans_ail.c13
-rw-r--r--fs/xfs/xfs_trans_inode.c9
-rw-r--r--fs/xfs/xfs_xattr.c184
-rw-r--r--include/acpi/acpi_bus.h36
-rw-r--r--include/asm-generic/barrier.h2
-rw-r--r--include/asm-generic/pci-dma-compat.h6
-rw-r--r--include/asm-generic/pgtable.h10
-rw-r--r--include/asm-generic/qspinlock.h9
-rw-r--r--include/asm-generic/tlb.h2
-rw-r--r--include/asm-generic/uaccess.h10
-rw-r--r--include/clocksource/arm_arch_timer.h6
-rw-r--r--include/drm/drmP.h10
-rw-r--r--include/drm/drm_atomic.h3
-rw-r--r--include/dt-bindings/clock/berlin2q.h1
-rw-r--r--include/dt-bindings/clock/exynos5250.h4
-rw-r--r--include/dt-bindings/power/rk3288-power.h31
-rw-r--r--include/kvm/arm_vgic.h8
-rw-r--r--include/linux/acpi.h16
-rw-r--r--include/linux/arm-smccc.h104
-rw-r--r--include/linux/atmel_tc.h1
-rw-r--r--include/linux/bitops.h2
-rw-r--r--include/linux/blk-mq.h10
-rw-r--r--include/linux/blk_types.h24
-rw-r--r--include/linux/blkdev.h13
-rw-r--r--include/linux/bootmem.h4
-rw-r--r--include/linux/bpf.h5
-rw-r--r--include/linux/buffer_head.h2
-rw-r--r--include/linux/ceph/libceph.h4
-rw-r--r--include/linux/ceph/messenger.h16
-rw-r--r--include/linux/cgroup-defs.h13
-rw-r--r--include/linux/cgroup.h47
-rw-r--r--include/linux/clocksource.h16
-rw-r--r--include/linux/compiler.h17
-rw-r--r--include/linux/component.h33
-rw-r--r--include/linux/configfs.h107
-rw-r--r--include/linux/context_tracking.h16
-rw-r--r--include/linux/context_tracking_state.h4
-rw-r--r--include/linux/cpufreq.h1
-rw-r--r--include/linux/delayed_call.h34
-rw-r--r--include/linux/devfreq_cooling.h81
-rw-r--r--include/linux/device.h16
-rw-r--r--include/linux/dns_resolver.h2
-rw-r--r--include/linux/edac.h8
-rw-r--r--include/linux/enclosure.h4
-rw-r--r--include/linux/filter.h19
-rw-r--r--include/linux/fs.h148
-rw-r--r--include/linux/fsl/edac.h8
-rw-r--r--include/linux/ftrace.h1
-rw-r--r--include/linux/gfp.h2
-rw-r--r--include/linux/hugetlb.h2
-rw-r--r--include/linux/i2c-ocores.h1
-rw-r--r--include/linux/i2c/i2c-rcar.h10
-rw-r--r--include/linux/init_task.h2
-rw-r--r--include/linux/interrupt.h1
-rw-r--r--include/linux/ipv6.h2
-rw-r--r--include/linux/irqchip/arm-gic-v3.h1
-rw-r--r--include/linux/irqchip/arm-gic.h13
-rw-r--r--include/linux/irqchip/mips-gic.h17
-rw-r--r--include/linux/irqdesc.h6
-rw-r--r--include/linux/irqdomain.h13
-rw-r--r--include/linux/jump_label.h2
-rw-r--r--include/linux/kernel.h28
-rw-r--r--include/linux/kexec.h2
-rw-r--r--include/linux/kmemleak.h2
-rw-r--r--include/linux/kref.h33
-rw-r--r--include/linux/kvm_host.h78
-rw-r--r--include/linux/kvm_para.h6
-rw-r--r--include/linux/leds.h29
-rw-r--r--include/linux/libata.h2
-rw-r--r--include/linux/lightnvm.h199
-rw-r--r--include/linux/list.h14
-rw-r--r--include/linux/list_bl.h2
-rw-r--r--include/linux/list_nulls.h2
-rw-r--r--include/linux/lockd/lockd.h10
-rw-r--r--include/linux/lockdep.h2
-rw-r--r--include/linux/marvell_phy.h1
-rw-r--r--include/linux/math64.h80
-rw-r--r--include/linux/memblock.h8
-rw-r--r--include/linux/mfd/cros_ec.h1
-rw-r--r--include/linux/mfd/syscon/imx7-iomuxc-gpr.h47
-rw-r--r--include/linux/mfd/wm8350/pmic.h1
-rw-r--r--include/linux/mlx4/device.h11
-rw-r--r--include/linux/mlx5/mlx5_ifc.h24
-rw-r--r--include/linux/mmc/dw_mmc.h12
-rw-r--r--include/linux/mmc/host.h6
-rw-r--r--include/linux/mmdebug.h1
-rw-r--r--include/linux/msi.h18
-rw-r--r--include/linux/mtd/spi-nor.h2
-rw-r--r--include/linux/namei.h1
-rw-r--r--include/linux/net.h13
-rw-r--r--include/linux/netdevice.h36
-rw-r--r--include/linux/netfilter/ipset/ip_set.h2
-rw-r--r--include/linux/netfilter/nfnetlink.h2
-rw-r--r--include/linux/netfilter_ingress.h13
-rw-r--r--include/linux/nfs4.h4
-rw-r--r--include/linux/nfs_fs.h1
-rw-r--r--include/linux/nfs_xdr.h1
-rw-r--r--include/linux/of.h4
-rw-r--r--include/linux/of_address.h7
-rw-r--r--include/linux/of_dma.h2
-rw-r--r--include/linux/of_irq.h19
-rw-r--r--include/linux/of_pci.h3
-rw-r--r--include/linux/pci.h19
-rw-r--r--include/linux/percpu-refcount.h2
-rw-r--r--include/linux/percpu.h6
-rw-r--r--include/linux/perf/arm_pmu.h2
-rw-r--r--include/linux/perf_event.h6
-rw-r--r--include/linux/platform_data/atmel.h8
-rw-r--r--include/linux/platform_data/camera-rcar.h25
-rw-r--r--include/linux/platform_data/edma.h2
-rw-r--r--include/linux/platform_data/irq-renesas-intc-irqpin.h29
-rw-r--r--include/linux/platform_data/media/camera-mx2.h (renamed from include/linux/platform_data/camera-mx2.h)0
-rw-r--r--include/linux/platform_data/media/camera-mx3.h (renamed from include/linux/platform_data/camera-mx3.h)0
-rw-r--r--include/linux/platform_data/media/camera-pxa.h (renamed from include/linux/platform_data/camera-pxa.h)0
-rw-r--r--include/linux/platform_data/media/coda.h (renamed from include/linux/platform_data/coda.h)0
-rw-r--r--include/linux/platform_data/media/gpio-ir-recv.h (renamed from include/media/gpio-ir-recv.h)1
-rw-r--r--include/linux/platform_data/media/ir-rx51.h (renamed from include/media/ir-rx51.h)0
-rw-r--r--include/linux/platform_data/media/mmp-camera.h (renamed from include/media/mmp-camera.h)0
-rw-r--r--include/linux/platform_data/media/omap1_camera.h (renamed from include/media/omap1_camera.h)0
-rw-r--r--include/linux/platform_data/media/omap4iss.h (renamed from include/media/omap4iss.h)0
-rw-r--r--include/linux/platform_data/media/s5p_hdmi.h (renamed from include/media/s5p_hdmi.h)1
-rw-r--r--include/linux/platform_data/media/si4713.h (renamed from include/media/si4713.h)2
-rw-r--r--include/linux/platform_data/media/sii9234.h (renamed from include/media/sii9234.h)0
-rw-r--r--include/linux/platform_data/media/soc_camera_platform.h (renamed from include/media/soc_camera_platform.h)0
-rw-r--r--include/linux/platform_data/media/timb_radio.h (renamed from include/media/timb_radio.h)0
-rw-r--r--include/linux/platform_data/media/timb_video.h (renamed from include/media/timb_video.h)0
-rw-r--r--include/linux/platform_data/mmc-mvsdio.h18
-rw-r--r--include/linux/platform_device.h1
-rw-r--r--include/linux/pmem.h26
-rw-r--r--include/linux/posix_acl_xattr.h6
-rw-r--r--include/linux/property.h10
-rw-r--r--include/linux/proportions.h2
-rw-r--r--include/linux/psci.h2
-rw-r--r--include/linux/pwm.h3
-rw-r--r--include/linux/qcom_scm.h2
-rw-r--r--include/linux/qed/common_hsi.h2
-rw-r--r--include/linux/qed/qed_chain.h3
-rw-r--r--include/linux/rculist.h105
-rw-r--r--include/linux/rcupdate.h21
-rw-r--r--include/linux/rcutiny.h8
-rw-r--r--include/linux/rcutree.h4
-rw-r--r--include/linux/regmap.h18
-rw-r--r--include/linux/rhashtable.h18
-rw-r--r--include/linux/sched.h44
-rw-r--r--include/linux/sched_clock.h12
-rw-r--r--include/linux/scpi_protocol.h78
-rw-r--r--include/linux/signal.h1
-rw-r--r--include/linux/slab.h45
-rw-r--r--include/linux/soc/brcmstb/brcmstb.h10
-rw-r--r--include/linux/soc/qcom/smd.h11
-rw-r--r--include/linux/soc/qcom/smem.h2
-rw-r--r--include/linux/spi/pxa2xx_spi.h1
-rw-r--r--include/linux/stop_machine.h13
-rw-r--r--include/linux/string.h1
-rw-r--r--include/linux/sunrpc/cache.h16
-rw-r--r--include/linux/sunxi-rsb.h105
-rw-r--r--include/linux/syscalls.h5
-rw-r--r--include/linux/sysfs.h18
-rw-r--r--include/linux/tcp.h7
-rw-r--r--include/linux/thermal.h11
-rw-r--r--include/linux/time.h26
-rw-r--r--include/linux/tracepoint-defs.h27
-rw-r--r--include/linux/tracepoint.h20
-rw-r--r--include/linux/tty.h6
-rw-r--r--include/linux/types.h2
-rw-r--r--include/linux/uio.h4
-rw-r--r--include/linux/uprobes.h2
-rw-r--r--include/linux/usb/cdc_ncm.h1
-rw-r--r--include/linux/usb/gadget_configfs.h19
-rw-r--r--include/linux/usb/quirks.h3
-rw-r--r--include/linux/videodev2.h2
-rw-r--r--include/linux/vmstat.h6
-rw-r--r--include/linux/vtime.h25
-rw-r--r--include/linux/wait.h40
-rw-r--r--include/linux/workqueue.h6
-rw-r--r--include/linux/xattr.h32
-rw-r--r--include/media/drv-intf/cx2341x.h (renamed from include/media/cx2341x.h)0
-rw-r--r--include/media/drv-intf/cx25840.h (renamed from include/media/cx25840.h)0
-rw-r--r--include/media/drv-intf/exynos-fimc.h (renamed from include/media/exynos-fimc.h)0
-rw-r--r--include/media/drv-intf/msp3400.h (renamed from include/media/msp3400.h)1
-rw-r--r--include/media/drv-intf/s3c_camif.h (renamed from include/media/s3c_camif.h)0
-rw-r--r--include/media/drv-intf/saa7146.h (renamed from include/media/saa7146.h)0
-rw-r--r--include/media/drv-intf/saa7146_vv.h (renamed from include/media/saa7146_vv.h)2
-rw-r--r--include/media/drv-intf/sh_mobile_ceu.h (renamed from include/media/sh_mobile_ceu.h)0
-rw-r--r--include/media/drv-intf/sh_mobile_csi2.h (renamed from include/media/sh_mobile_csi2.h)0
-rw-r--r--include/media/drv-intf/sh_vou.h (renamed from include/media/sh_vou.h)0
-rw-r--r--include/media/drv-intf/si476x.h (renamed from include/media/si476x.h)2
-rw-r--r--include/media/drv-intf/soc_mediabus.h (renamed from include/media/soc_mediabus.h)0
-rw-r--r--include/media/drv-intf/tea575x.h (renamed from include/media/tea575x.h)2
-rw-r--r--include/media/i2c/ad9389b.h (renamed from include/media/ad9389b.h)0
-rw-r--r--include/media/i2c/adp1653.h (renamed from include/media/adp1653.h)2
-rw-r--r--include/media/i2c/adv7183.h (renamed from include/media/adv7183.h)0
-rw-r--r--include/media/i2c/adv7343.h (renamed from include/media/adv7343.h)0
-rw-r--r--include/media/i2c/adv7393.h (renamed from include/media/adv7393.h)0
-rw-r--r--include/media/i2c/adv7511.h (renamed from include/media/adv7511.h)0
-rw-r--r--include/media/i2c/adv7604.h (renamed from include/media/adv7604.h)0
-rw-r--r--include/media/i2c/adv7842.h (renamed from include/media/adv7842.h)0
-rw-r--r--include/media/i2c/ak881x.h (renamed from include/media/ak881x.h)0
-rw-r--r--include/media/i2c/as3645a.h (renamed from include/media/as3645a.h)2
-rw-r--r--include/media/i2c/bt819.h (renamed from include/media/bt819.h)0
-rw-r--r--include/media/i2c/cs5345.h (renamed from include/media/cs5345.h)0
-rw-r--r--include/media/i2c/cs53l32a.h (renamed from include/media/cs53l32a.h)0
-rw-r--r--include/media/i2c/ir-kbd-i2c.h (renamed from include/media/ir-kbd-i2c.h)0
-rw-r--r--include/media/i2c/lm3560.h (renamed from include/media/lm3560.h)2
-rw-r--r--include/media/i2c/lm3646.h (renamed from include/media/lm3646.h)2
-rw-r--r--include/media/i2c/m52790.h (renamed from include/media/m52790.h)0
-rw-r--r--include/media/i2c/m5mols.h (renamed from include/media/m5mols.h)0
-rw-r--r--include/media/i2c/mt9m032.h (renamed from include/media/mt9m032.h)0
-rw-r--r--include/media/i2c/mt9p031.h (renamed from include/media/mt9p031.h)0
-rw-r--r--include/media/i2c/mt9t001.h (renamed from include/media/mt9t001.h)0
-rw-r--r--include/media/i2c/mt9t112.h (renamed from include/media/mt9t112.h)0
-rw-r--r--include/media/i2c/mt9v011.h (renamed from include/media/mt9v011.h)0
-rw-r--r--include/media/i2c/mt9v022.h (renamed from include/media/mt9v022.h)0
-rw-r--r--include/media/i2c/mt9v032.h (renamed from include/media/mt9v032.h)0
-rw-r--r--include/media/i2c/noon010pc30.h (renamed from include/media/noon010pc30.h)0
-rw-r--r--include/media/i2c/ov2659.h (renamed from include/media/ov2659.h)0
-rw-r--r--include/media/i2c/ov7670.h (renamed from include/media/ov7670.h)0
-rw-r--r--include/media/i2c/ov772x.h (renamed from include/media/ov772x.h)0
-rw-r--r--include/media/i2c/ov9650.h (renamed from include/media/ov9650.h)0
-rw-r--r--include/media/i2c/rj54n1cb0c.h (renamed from include/media/rj54n1cb0c.h)0
-rw-r--r--include/media/i2c/s5c73m3.h (renamed from include/media/s5c73m3.h)0
-rw-r--r--include/media/i2c/s5k4ecgx.h (renamed from include/media/s5k4ecgx.h)0
-rw-r--r--include/media/i2c/s5k6aa.h (renamed from include/media/s5k6aa.h)0
-rw-r--r--include/media/i2c/saa6588.h (renamed from include/media/saa6588.h)0
-rw-r--r--include/media/i2c/saa7115.h (renamed from include/media/saa7115.h)1
-rw-r--r--include/media/i2c/saa7127.h (renamed from include/media/saa7127.h)1
-rw-r--r--include/media/i2c/smiapp.h (renamed from include/media/smiapp.h)2
-rw-r--r--include/media/i2c/sr030pc30.h (renamed from include/media/sr030pc30.h)0
-rw-r--r--include/media/i2c/tc358743.h (renamed from include/media/tc358743.h)0
-rw-r--r--include/media/i2c/ths7303.h (renamed from include/media/ths7303.h)0
-rw-r--r--include/media/i2c/tvaudio.h (renamed from include/media/tvaudio.h)0
-rw-r--r--include/media/i2c/tvp514x.h (renamed from include/media/tvp514x.h)0
-rw-r--r--include/media/i2c/tvp5150.h (renamed from include/media/tvp5150.h)1
-rw-r--r--include/media/i2c/tvp7002.h (renamed from include/media/tvp7002.h)0
-rw-r--r--include/media/i2c/tw9910.h (renamed from include/media/tw9910.h)0
-rw-r--r--include/media/i2c/uda1342.h (renamed from include/media/uda1342.h)0
-rw-r--r--include/media/i2c/upd64031a.h (renamed from include/media/upd64031a.h)0
-rw-r--r--include/media/i2c/upd64083.h (renamed from include/media/upd64083.h)0
-rw-r--r--include/media/i2c/wm8775.h (renamed from include/media/wm8775.h)0
-rw-r--r--include/media/lirc.h169
-rw-r--r--include/media/rc-core.h1
-rw-r--r--include/media/rc-map.h40
-rw-r--r--include/media/v4l2-clk.h5
-rw-r--r--include/media/v4l2-dv-timings.h25
-rw-r--r--include/media/videobuf2-core.h108
-rw-r--r--include/media/videobuf2-v4l2.h40
-rw-r--r--include/net/af_unix.h1
-rw-r--r--include/net/bluetooth/l2cap.h2
-rw-r--r--include/net/dst.h33
-rw-r--r--include/net/dst_metadata.h3
-rw-r--r--include/net/inet_sock.h31
-rw-r--r--include/net/inetpeer.h1
-rw-r--r--include/net/ip6_fib.h3
-rw-r--r--include/net/ip6_route.h17
-rw-r--r--include/net/ip6_tunnel.h3
-rw-r--r--include/net/ip_tunnels.h3
-rw-r--r--include/net/ipv6.h22
-rw-r--r--include/net/l3mdev.h16
-rw-r--r--include/net/mac80211.h6
-rw-r--r--include/net/ndisc.h3
-rw-r--r--include/net/netfilter/nf_tables.h16
-rw-r--r--include/net/route.h7
-rw-r--r--include/net/sch_generic.h3
-rw-r--r--include/net/sctp/structs.h17
-rw-r--r--include/net/sock.h64
-rw-r--r--include/net/switchdev.h2
-rw-r--r--include/net/vxlan.h2
-rw-r--r--include/net/xfrm.h25
-rw-r--r--include/rdma/ib_mad.h2
-rw-r--r--include/rdma/ib_verbs.h1
-rw-r--r--include/scsi/scsi_host.h8
-rw-r--r--include/scsi/scsi_tcq.h95
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h120
-rw-r--r--include/soc/brcmstb/common.h15
-rw-r--r--include/sound/hda_register.h3
-rw-r--r--include/sound/soc-dapm.h1
-rw-r--r--include/sound/soc.h2
-rw-r--r--include/target/configfs_macros.h147
-rw-r--r--include/target/target_core_base.h62
-rw-r--r--include/target/target_core_fabric_configfs.h122
-rw-r--r--include/trace/events/filelock.h77
-rw-r--r--include/trace/events/thermal.h53
-rw-r--r--include/trace/events/v4l2.h4
-rw-r--r--include/trace/events/vb2.h7
-rw-r--r--include/uapi/asm-generic/unistd.h4
-rw-r--r--include/uapi/drm/drm_fourcc.h4
-rw-r--r--include/uapi/linux/Kbuild1
-rw-r--r--include/uapi/linux/dvb/video.h1
-rw-r--r--include/uapi/linux/fs.h39
-rw-r--r--include/uapi/linux/i2c-dev.h4
-rw-r--r--include/uapi/linux/kvm.h26
-rw-r--r--include/uapi/linux/lirc.h168
-rw-r--r--include/uapi/linux/nfs.h11
-rw-r--r--include/uapi/linux/openvswitch.h2
-rw-r--r--include/uapi/linux/perf_event.h6
-rw-r--r--include/uapi/linux/psci.h18
-rw-r--r--include/uapi/linux/usb/video.h1
-rw-r--r--include/uapi/linux/v4l2-controls.h6
-rw-r--r--include/uapi/linux/videodev2.h14
-rw-r--r--include/uapi/xen/gntdev.h50
-rw-r--r--include/video/imx-ipu-v3.h1
-rw-r--r--include/xen/interface/io/ring.h14
-rw-r--r--include/xen/interface/platform.h18
-rw-r--r--include/xen/interface/xen.h2
-rw-r--r--include/xen/xen-ops.h5
-rw-r--r--init/Kconfig7
-rw-r--r--init/main.c2
-rw-r--r--kernel/bpf/arraymap.c10
-rw-r--r--kernel/bpf/hashtab.c34
-rw-r--r--kernel/bpf/inode.c6
-rw-r--r--kernel/bpf/syscall.c40
-rw-r--r--kernel/bpf/verifier.c3
-rw-r--r--kernel/cgroup.c99
-rw-r--r--kernel/cgroup_freezer.c23
-rw-r--r--kernel/cgroup_pids.c77
-rw-r--r--kernel/context_tracking.c84
-rw-r--r--kernel/cpuset.c33
-rw-r--r--kernel/events/callchain.c2
-rw-r--r--kernel/events/core.c416
-rw-r--r--kernel/events/ring_buffer.c2
-rw-r--r--kernel/events/uprobes.c2
-rw-r--r--kernel/fork.c14
-rw-r--r--kernel/futex.c83
-rw-r--r--kernel/irq/chip.c9
-rw-r--r--kernel/irq/internals.h5
-rw-r--r--kernel/irq/irqdesc.c19
-rw-r--r--kernel/irq/irqdomain.c12
-rw-r--r--kernel/irq/manage.c31
-rw-r--r--kernel/irq/msi.c58
-rw-r--r--kernel/irq/pm.c3
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/irq_work.c2
-rw-r--r--kernel/jump_label.c2
-rw-r--r--kernel/kexec_core.c30
-rw-r--r--kernel/ksysfs.c26
-rw-r--r--kernel/livepatch/core.c6
-rw-r--r--kernel/locking/lockdep.c2
-rw-r--r--kernel/locking/lockdep_proc.c2
-rw-r--r--kernel/locking/osq_lock.c8
-rw-r--r--kernel/locking/qspinlock.c82
-rw-r--r--kernel/locking/qspinlock_paravirt.h252
-rw-r--r--kernel/locking/qspinlock_stat.h300
-rw-r--r--kernel/memremap.c16
-rw-r--r--kernel/module.c6
-rw-r--r--kernel/panic.c38
-rw-r--r--kernel/pid.c4
-rw-r--r--kernel/rcu/rcutorture.c24
-rw-r--r--kernel/rcu/srcu.c2
-rw-r--r--kernel/rcu/tree.c313
-rw-r--r--kernel/rcu/tree.h61
-rw-r--r--kernel/rcu/tree_plugin.h66
-rw-r--r--kernel/rcu/tree_trace.c39
-rw-r--r--kernel/rcu/update.c22
-rw-r--r--kernel/sched/auto_group.c2
-rw-r--r--kernel/sched/clock.c4
-rw-r--r--kernel/sched/core.c225
-rw-r--r--kernel/sched/cputime.c78
-rw-r--r--kernel/sched/deadline.c59
-rw-r--r--kernel/sched/fair.c318
-rw-r--r--kernel/sched/idle_task.c1
-rw-r--r--kernel/sched/rt.c2
-rw-r--r--kernel/sched/sched.h73
-rw-r--r--kernel/sched/wait.c28
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/stop_machine.c88
-rw-r--r--kernel/sys_ni.c1
-rw-r--r--kernel/sysctl.c79
-rw-r--r--kernel/time/alarmtimer.c17
-rw-r--r--kernel/time/clocksource.c4
-rw-r--r--kernel/time/ntp.c44
-rw-r--r--kernel/time/ntp_internal.h2
-rw-r--r--kernel/time/posix-clock.c4
-rw-r--r--kernel/time/tick-sched.c36
-rw-r--r--kernel/time/timekeeping.c49
-rw-r--r--kernel/time/timekeeping_internal.h8
-rw-r--r--kernel/time/timer.c22
-rw-r--r--kernel/trace/Kconfig2
-rw-r--r--kernel/trace/blktrace.c12
-rw-r--r--kernel/trace/ring_buffer.c17
-rw-r--r--kernel/trace/trace.c16
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_event_perf.c2
-rw-r--r--kernel/trace/trace_events.c44
-rw-r--r--kernel/trace/trace_events_trigger.c15
-rw-r--r--kernel/trace/trace_functions_graph.c6
-rw-r--r--kernel/trace/trace_printk.c1
-rw-r--r--kernel/user_namespace.c21
-rw-r--r--kernel/watchdog.c20
-rw-r--r--kernel/workqueue.c220
-rw-r--r--lib/Kconfig.debug14
-rw-r--r--lib/atomic64_test.c124
-rw-r--r--lib/btree.c2
-rw-r--r--lib/dma-debug.c4
-rw-r--r--lib/dynamic_debug.c11
-rw-r--r--lib/iov_iter.c11
-rw-r--r--lib/list_debug.c2
-rw-r--r--lib/proportions.c2
-rw-r--r--lib/rhashtable.c70
-rw-r--r--lib/string.c2
-rw-r--r--lib/test_bpf.c30
-rw-r--r--lib/vsprintf.c29
-rw-r--r--mm/backing-dev.c19
-rw-r--r--mm/bootmem.c1
-rw-r--r--mm/huge_memory.c4
-rw-r--r--mm/hugetlb.c31
-rw-r--r--mm/kasan/kasan.c2
-rw-r--r--mm/memblock.c28
-rw-r--r--mm/memcontrol.c109
-rw-r--r--mm/memory.c8
-rw-r--r--mm/memory_hotplug.c31
-rw-r--r--mm/mremap.c4
-rw-r--r--mm/nobootmem.c1
-rw-r--r--mm/oom_kill.c2
-rw-r--r--mm/page-writeback.c6
-rw-r--r--mm/page_alloc.c10
-rw-r--r--mm/shmem.c215
-rw-r--r--mm/slab.c2
-rw-r--r--mm/slab.h2
-rw-r--r--mm/slab_common.c6
-rw-r--r--mm/slob.c2
-rw-r--r--mm/slub.c304
-rw-r--r--mm/util.c31
-rw-r--r--mm/vmalloc.c5
-rw-r--r--mm/vmstat.c18
-rw-r--r--mm/zswap.c6
-rw-r--r--net/8021q/vlan_core.c4
-rw-r--r--net/9p/trans_virtio.c16
-rw-r--r--net/ax25/af_ax25.c3
-rw-r--r--net/batman-adv/distributed-arp-table.c5
-rw-r--r--net/batman-adv/routing.c19
-rw-r--r--net/batman-adv/translation-table.c16
-rw-r--r--net/bluetooth/af_bluetooth.c6
-rw-r--r--net/bluetooth/hci_core.c17
-rw-r--r--net/bluetooth/l2cap_core.c20
-rw-r--r--net/bluetooth/sco.c3
-rw-r--r--net/bluetooth/smp.c7
-rw-r--r--net/bridge/br_stp.c15
-rw-r--r--net/bridge/br_stp_if.c9
-rw-r--r--net/caif/caif_socket.c4
-rw-r--r--net/ceph/auth_x.c36
-rw-r--r--net/ceph/ceph_common.c18
-rw-r--r--net/ceph/crypto.h4
-rw-r--r--net/ceph/messenger.c88
-rw-r--r--net/ceph/osd_client.c34
-rw-r--r--net/core/datagram.c2
-rw-r--r--net/core/dev.c25
-rw-r--r--net/core/dst.c3
-rw-r--r--net/core/neighbour.c6
-rw-r--r--net/core/netclassid_cgroup.c28
-rw-r--r--net/core/netprio_cgroup.c9
-rw-r--r--net/core/rtnetlink.c274
-rw-r--r--net/core/scm.c2
-rw-r--r--net/core/skbuff.c6
-rw-r--r--net/core/sock.c19
-rw-r--r--net/core/stream.c6
-rw-r--r--net/dccp/ipv6.c37
-rw-r--r--net/dccp/proto.c3
-rw-r--r--net/decnet/af_decnet.c11
-rw-r--r--net/dns_resolver/dns_query.c2
-rw-r--r--net/hsr/hsr_device.c2
-rw-r--r--net/ipv4/af_inet.c3
-rw-r--r--net/ipv4/fib_frontend.c9
-rw-r--r--net/ipv4/fib_semantics.c13
-rw-r--r--net/ipv4/fou.c3
-rw-r--r--net/ipv4/igmp.c17
-rw-r--r--net/ipv4/inet_connection_sock.c4
-rw-r--r--net/ipv4/ip_sockglue.c45
-rw-r--r--net/ipv4/ipip.c3
-rw-r--r--net/ipv4/ipmr.c23
-rw-r--r--net/ipv4/netfilter/Kconfig1
-rw-r--r--net/ipv4/netfilter/nf_defrag_ipv4.c5
-rw-r--r--net/ipv4/netfilter/nf_nat_pptp.c2
-rw-r--r--net/ipv4/raw.c15
-rw-r--r--net/ipv4/sysctl_net_ipv4.c4
-rw-r--r--net/ipv4/tcp.c28
-rw-r--r--net/ipv4/tcp_diag.c2
-rw-r--r--net/ipv4/tcp_input.c26
-rw-r--r--net/ipv4/tcp_ipv4.c24
-rw-r--r--net/ipv4/tcp_minisocks.c3
-rw-r--r--net/ipv4/tcp_output.c23
-rw-r--r--net/ipv4/tcp_timer.c14
-rw-r--r--net/ipv4/udp.c8
-rw-r--r--net/ipv4/xfrm4_policy.c46
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/addrlabel.c2
-rw-r--r--net/ipv6/af_inet6.c18
-rw-r--r--net/ipv6/datagram.c4
-rw-r--r--net/ipv6/exthdrs.c3
-rw-r--r--net/ipv6/icmp.c14
-rw-r--r--net/ipv6/inet6_connection_sock.c21
-rw-r--r--net/ipv6/ip6_gre.c8
-rw-r--r--net/ipv6/ip6_tunnel.c2
-rw-r--r--net/ipv6/ip6mr.c19
-rw-r--r--net/ipv6/ipv6_sockglue.c33
-rw-r--r--net/ipv6/mcast.c2
-rw-r--r--net/ipv6/ndisc.c14
-rw-r--r--net/ipv6/netfilter/Kconfig1
-rw-r--r--net/ipv6/netfilter/nf_conntrack_reasm.c5
-rw-r--r--net/ipv6/raw.c8
-rw-r--r--net/ipv6/reassembly.c10
-rw-r--r--net/ipv6/route.c24
-rw-r--r--net/ipv6/syncookies.c2
-rw-r--r--net/ipv6/tcp_ipv6.c74
-rw-r--r--net/ipv6/udp.c8
-rw-r--r--net/ipv6/xfrm6_policy.c53
-rw-r--r--net/irda/af_irda.c3
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/l2tp/l2tp_ip6.c8
-rw-r--r--net/mac80211/agg-tx.c3
-rw-r--r--net/mac80211/cfg.c11
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/iface.c5
-rw-r--r--net/mac80211/main.c3
-rw-r--r--net/mac80211/mesh_pathtbl.c8
-rw-r--r--net/mac80211/mlme.c17
-rw-r--r--net/mac80211/rx.c3
-rw-r--r--net/mac80211/scan.c9
-rw-r--r--net/mac80211/util.c113
-rw-r--r--net/mac80211/vht.c10
-rw-r--r--net/mpls/af_mpls.c43
-rw-r--r--net/mpls/mpls_iptunnel.c4
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_gen.h17
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ip.c14
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_ipmac.c64
-rw-r--r--net/netfilter/ipset/ip_set_bitmap_port.c18
-rw-r--r--net/netfilter/ipset/ip_set_core.c14
-rw-r--r--net/netfilter/ipset/ip_set_hash_gen.h26
-rw-r--r--net/netfilter/ipset/ip_set_list_set.c5
-rw-r--r--net/netfilter/ipvs/ip_vs_core.c16
-rw-r--r--net/netfilter/nf_nat_redirect.c2
-rw-r--r--net/netfilter/nf_tables_api.c99
-rw-r--r--net/netfilter/nf_tables_netdev.c2
-rw-r--r--net/netfilter/nfnetlink.c6
-rw-r--r--net/netfilter/nfnetlink_log.c2
-rw-r--r--net/netfilter/nfnetlink_queue.c9
-rw-r--r--net/netfilter/nft_counter.c49
-rw-r--r--net/netfilter/nft_ct.c1
-rw-r--r--net/netfilter/nft_dynset.c5
-rw-r--r--net/netfilter/nft_meta.c36
-rw-r--r--net/netfilter/xt_TEE.c6
-rw-r--r--net/netfilter/xt_owner.c6
-rw-r--r--net/nfc/llcp_sock.c2
-rw-r--r--net/openvswitch/conntrack.c22
-rw-r--r--net/openvswitch/dp_notify.c2
-rw-r--r--net/openvswitch/flow_netlink.c5
-rw-r--r--net/openvswitch/vport-geneve.c1
-rw-r--r--net/openvswitch/vport-gre.c1
-rw-r--r--net/openvswitch/vport-netdev.c8
-rw-r--r--net/openvswitch/vport.c8
-rw-r--r--net/openvswitch/vport.h8
-rw-r--r--net/packet/af_packet.c176
-rw-r--r--net/rds/connection.c6
-rw-r--r--net/rds/send.c4
-rw-r--r--net/rfkill/core.c6
-rw-r--r--net/rxrpc/ar-ack.c4
-rw-r--r--net/rxrpc/ar-key.c24
-rw-r--r--net/rxrpc/ar-output.c2
-rw-r--r--net/sched/cls_flow.c15
-rw-r--r--net/sched/em_meta.c138
-rw-r--r--net/sched/sch_api.c25
-rw-r--r--net/sched/sch_generic.c6
-rw-r--r--net/sched/sch_mq.c4
-rw-r--r--net/sched/sch_mqprio.c4
-rw-r--r--net/sctp/auth.c4
-rw-r--r--net/sctp/ipv6.c24
-rw-r--r--net/sctp/outqueue.c2
-rw-r--r--net/sctp/sm_make_chunk.c4
-rw-r--r--net/sctp/sm_statefuns.c9
-rw-r--r--net/sctp/socket.c65
-rw-r--r--net/socket.c23
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c13
-rw-r--r--net/sunrpc/cache.c53
-rw-r--r--net/sunrpc/sched.c6
-rw-r--r--net/sunrpc/svc.c13
-rw-r--r--net/sunrpc/svcsock.c40
-rw-r--r--net/sunrpc/xprtsock.c14
-rw-r--r--net/tipc/link.c2
-rw-r--r--net/tipc/socket.c10
-rw-r--r--net/tipc/udp_media.c7
-rw-r--r--net/unix/af_unix.c371
-rw-r--r--net/vmw_vsock/vmci_transport.c2
-rw-r--r--net/wireless/nl80211.c5
-rw-r--r--net/wireless/reg.c5
-rw-r--r--net/xfrm/xfrm_policy.c88
-rw-r--r--samples/Kconfig6
-rw-r--r--samples/Makefile3
-rw-r--r--samples/bpf/Makefile7
-rw-r--r--samples/configfs/Makefile2
-rw-r--r--samples/configfs/configfs_sample.c (renamed from Documentation/filesystems/configfs/configfs_example_macros.c)140
-rwxr-xr-xscripts/coccicheck2
-rw-r--r--scripts/coccinelle/free/ifnullfree.cocci26
-rw-r--r--scripts/coccinelle/iterators/device_node_continue.cocci100
-rw-r--r--scripts/coccinelle/misc/compare_const_fl.cocci171
-rw-r--r--scripts/coccinelle/misc/of_table.cocci33
-rw-r--r--scripts/coccinelle/misc/simple_return.cocci180
-rw-r--r--scripts/coccinelle/null/deref_null.cocci4
-rw-r--r--scripts/coccinelle/tests/odd_ptr_err.cocci120
-rw-r--r--scripts/kconfig/Makefile56
-rw-r--r--scripts/kconfig/expr.c2
-rwxr-xr-xscripts/kconfig/merge_config.sh18
-rw-r--r--scripts/kconfig/qconf.cc688
-rw-r--r--scripts/kconfig/qconf.h150
-rw-r--r--scripts/kconfig/symbol.c2
-rwxr-xr-xscripts/kernel-doc2
-rwxr-xr-xscripts/ld-version.sh4
-rwxr-xr-xscripts/link-vmlinux.sh2
-rwxr-xr-xscripts/package/builddeb11
-rw-r--r--scripts/recordmcount.c137
-rwxr-xr-xscripts/tags.sh2
-rw-r--r--security/integrity/iint.c11
-rw-r--r--security/keys/encrypted-keys/encrypted.c2
-rw-r--r--security/keys/keyctl.c18
-rw-r--r--security/keys/trusted.c5
-rw-r--r--security/keys/user_defined.c5
-rw-r--r--security/selinux/hooks.c6
-rw-r--r--security/selinux/netlabel.c2
-rw-r--r--security/selinux/selinuxfs.c114
-rw-r--r--security/selinux/ss/conditional.c4
-rw-r--r--security/smack/smack_lsm.c2
-rw-r--r--security/smack/smack_netfilter.c11
-rw-r--r--security/smack/smackfs.c114
-rw-r--r--security/tomoyo/securityfs_if.c11
-rw-r--r--sound/firewire/Kconfig1
-rw-r--r--sound/firewire/dice/dice.c4
-rw-r--r--sound/pci/Kconfig24
-rw-r--r--sound/pci/ctxfi/ctamixer.c6
-rw-r--r--sound/pci/ctxfi/ctamixer.h2
-rw-r--r--sound/pci/ctxfi/ctdaio.c10
-rw-r--r--sound/pci/ctxfi/ctdaio.h4
-rw-r--r--sound/pci/ctxfi/ctresource.c2
-rw-r--r--sound/pci/ctxfi/ctresource.h2
-rw-r--r--sound/pci/ctxfi/ctsrc.c6
-rw-r--r--sound/pci/ctxfi/ctsrc.h4
-rw-r--r--sound/pci/es1968.c4
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/hda_intel.c64
-rw-r--r--sound/pci/hda/hda_jack.c18
-rw-r--r--sound/pci/hda/hda_jack.h2
-rw-r--r--sound/pci/hda/patch_ca0132.c3
-rw-r--r--sound/pci/hda/patch_conexant.c5
-rw-r--r--sound/pci/hda/patch_hdmi.c19
-rw-r--r--sound/pci/hda/patch_realtek.c197
-rw-r--r--sound/pci/hda/patch_sigmatel.c45
-rw-r--r--sound/pci/rme96.c41
-rw-r--r--sound/soc/codecs/arizona.c18
-rw-r--r--sound/soc/codecs/es8328.c41
-rw-r--r--sound/soc/codecs/es8328.h1
-rw-r--r--sound/soc/codecs/nau8825.c31
-rw-r--r--sound/soc/codecs/rl6231.c6
-rw-r--r--sound/soc/codecs/rt5645.c65
-rw-r--r--sound/soc/codecs/rt5645.h4
-rw-r--r--sound/soc/codecs/rt5670.h12
-rw-r--r--sound/soc/codecs/rt5677.c100
-rw-r--r--sound/soc/codecs/sgtl5000.c1
-rw-r--r--sound/soc/codecs/wm8960.c2
-rw-r--r--sound/soc/codecs/wm8962.c4
-rw-r--r--sound/soc/codecs/wm8974.c1
-rw-r--r--sound/soc/davinci/davinci-mcasp.c16
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl_sai.c21
-rw-r--r--sound/soc/intel/Kconfig2
-rw-r--r--sound/soc/intel/skylake/skl-topology.c2
-rw-r--r--sound/soc/intel/skylake/skl.c4
-rw-r--r--sound/soc/intel/skylake/skl.h2
-rw-r--r--sound/soc/rockchip/rockchip_spdif.c8
-rw-r--r--sound/soc/rockchip/rockchip_spdif.h8
-rw-r--r--sound/soc/sh/rcar/gen.c2
-rw-r--r--sound/soc/sh/rcar/src.c7
-rw-r--r--sound/soc/soc-core.c6
-rw-r--r--sound/soc/soc-dapm.c7
-rw-r--r--sound/soc/soc-ops.c2
-rw-r--r--sound/soc/soc-topology.c3
-rw-r--r--sound/soc/sti/uniperif_player.c9
-rw-r--r--sound/soc/sti/uniperif_reader.c3
-rw-r--r--sound/soc/sunxi/sun4i-codec.c27
-rw-r--r--sound/sound_core.c2
-rw-r--r--sound/usb/midi.c46
-rw-r--r--sound/usb/mixer.c2
-rw-r--r--sound/usb/mixer_maps.c12
-rw-r--r--sound/usb/mixer_quirks.c37
-rw-r--r--sound/usb/mixer_quirks.h4
-rw-r--r--sound/usb/quirks-table.h11
-rw-r--r--sound/usb/quirks.c3
-rw-r--r--sound/usb/usbaudio.h1
-rw-r--r--tools/Makefile13
-rw-r--r--tools/build/Makefile2
-rw-r--r--tools/build/Makefile.feature44
-rw-r--r--tools/build/Makefile.include2
-rw-r--r--tools/build/feature/Makefile93
-rw-r--r--tools/include/linux/bitmap.h (renamed from tools/perf/util/include/linux/bitmap.h)2
-rw-r--r--tools/include/linux/list.h1
-rw-r--r--tools/include/linux/string.h15
-rw-r--r--tools/lib/bitmap.c (renamed from tools/perf/util/bitmap.c)0
-rw-r--r--tools/lib/bpf/.gitignore2
-rw-r--r--tools/lib/bpf/Makefile16
-rw-r--r--tools/lib/bpf/bpf.c14
-rw-r--r--tools/lib/bpf/bpf.h2
-rw-r--r--tools/lib/bpf/libbpf.c583
-rw-r--r--tools/lib/bpf/libbpf.h111
-rw-r--r--tools/lib/find_bit.c84
-rw-r--r--tools/lib/lockdep/common.c2
-rw-r--r--tools/lib/lockdep/include/liblockdep/common.h2
-rw-r--r--tools/lib/lockdep/uinclude/linux/compiler.h2
-rw-r--r--tools/lib/lockdep/uinclude/linux/lockdep.h3
-rw-r--r--tools/lib/string.c89
-rw-r--r--tools/lib/subcmd/Build7
-rw-r--r--tools/lib/subcmd/Makefile48
-rw-r--r--tools/lib/subcmd/exec-cmd.c209
-rw-r--r--tools/lib/subcmd/exec-cmd.h16
-rw-r--r--tools/lib/subcmd/help.c (renamed from tools/perf/util/help.c)179
-rw-r--r--tools/lib/subcmd/help.h (renamed from tools/perf/util/help.h)13
-rw-r--r--tools/lib/subcmd/pager.c (renamed from tools/perf/util/pager.c)23
-rw-r--r--tools/lib/subcmd/pager.h9
-rw-r--r--tools/lib/subcmd/parse-options.c (renamed from tools/perf/util/parse-options.c)250
-rw-r--r--tools/lib/subcmd/parse-options.h (renamed from tools/perf/util/parse-options.h)26
-rw-r--r--tools/lib/subcmd/run-command.c (renamed from tools/perf/util/run-command.c)24
-rw-r--r--tools/lib/subcmd/run-command.h (renamed from tools/perf/util/run-command.h)12
-rw-r--r--tools/lib/subcmd/sigchain.c (renamed from tools/perf/util/sigchain.c)3
-rw-r--r--tools/lib/subcmd/sigchain.h (renamed from tools/perf/util/sigchain.h)6
-rw-r--r--tools/lib/subcmd/subcmd-config.c11
-rw-r--r--tools/lib/subcmd/subcmd-config.h14
-rw-r--r--tools/lib/subcmd/subcmd-util.h91
-rw-r--r--tools/lib/traceevent/event-parse.c134
-rw-r--r--tools/lib/traceevent/event-parse.h4
-rw-r--r--tools/lib/util/find_next_bit.c89
-rw-r--r--tools/net/Makefile7
-rw-r--r--tools/perf/Build8
-rw-r--r--tools/perf/Documentation/perf-config.txt103
-rw-r--r--tools/perf/Documentation/perf-evlist.txt3
-rw-r--r--tools/perf/Documentation/perf-record.txt24
-rw-r--r--tools/perf/Documentation/perf-report.txt41
-rw-r--r--tools/perf/Documentation/perf-stat.txt34
-rw-r--r--tools/perf/Documentation/perf-top.txt3
-rw-r--r--tools/perf/Documentation/perf-trace.txt1
-rw-r--r--tools/perf/Documentation/tips.txt14
-rw-r--r--tools/perf/MANIFEST7
-rw-r--r--tools/perf/Makefile2
-rw-r--r--tools/perf/Makefile.perf44
-rw-r--r--tools/perf/arch/x86/include/arch-tests.h8
-rw-r--r--tools/perf/arch/x86/tests/insn-x86.c2
-rw-r--r--tools/perf/arch/x86/tests/intel-cqm.c4
-rw-r--r--tools/perf/arch/x86/tests/perf-time-to-tsc.c3
-rw-r--r--tools/perf/arch/x86/tests/rdpmc.c2
-rw-r--r--tools/perf/arch/x86/util/Build1
-rw-r--r--tools/perf/arch/x86/util/intel-bts.c4
-rw-r--r--tools/perf/arch/x86/util/intel-pt.c6
-rw-r--r--tools/perf/bench/futex-hash.c2
-rw-r--r--tools/perf/bench/futex-lock-pi.c2
-rw-r--r--tools/perf/bench/futex-requeue.c2
-rw-r--r--tools/perf/bench/futex-wake-parallel.c2
-rw-r--r--tools/perf/bench/futex-wake.c2
-rw-r--r--tools/perf/bench/mem-functions.c2
-rw-r--r--tools/perf/bench/numa.c2
-rw-r--r--tools/perf/bench/sched-messaging.c2
-rw-r--r--tools/perf/bench/sched-pipe.c2
-rw-r--r--tools/perf/builtin-annotate.c44
-rw-r--r--tools/perf/builtin-bench.c2
-rw-r--r--tools/perf/builtin-buildid-cache.c2
-rw-r--r--tools/perf/builtin-buildid-list.c4
-rw-r--r--tools/perf/builtin-config.c66
-rw-r--r--tools/perf/builtin-data.c2
-rw-r--r--tools/perf/builtin-diff.c15
-rw-r--r--tools/perf/builtin-evlist.c13
-rw-r--r--tools/perf/builtin-help.c10
-rw-r--r--tools/perf/builtin-inject.c3
-rw-r--r--tools/perf/builtin-kmem.c2
-rw-r--r--tools/perf/builtin-kvm.c5
-rw-r--r--tools/perf/builtin-list.c2
-rw-r--r--tools/perf/builtin-lock.c2
-rw-r--r--tools/perf/builtin-mem.c2
-rw-r--r--tools/perf/builtin-probe.c17
-rw-r--r--tools/perf/builtin-record.c48
-rw-r--r--tools/perf/builtin-report.c58
-rw-r--r--tools/perf/builtin-sched.c7
-rw-r--r--tools/perf/builtin-script.c245
-rw-r--r--tools/perf/builtin-stat.c891
-rw-r--r--tools/perf/builtin-timechart.c2
-rw-r--r--tools/perf/builtin-top.c75
-rw-r--r--tools/perf/builtin-trace.c4
-rw-r--r--tools/perf/builtin-version.c10
-rw-r--r--tools/perf/builtin.h1
-rw-r--r--tools/perf/command-list.txt3
-rw-r--r--tools/perf/config/Makefile24
-rw-r--r--tools/perf/config/utilities.mak19
-rw-r--r--tools/perf/perf.c24
-rw-r--r--tools/perf/scripts/python/stat-cpi.py77
-rw-r--r--tools/perf/tests/.gitignore3
-rw-r--r--tools/perf/tests/Build27
-rw-r--r--tools/perf/tests/attr.c9
-rw-r--r--tools/perf/tests/bp_signal.c2
-rw-r--r--tools/perf/tests/bp_signal_overflow.c2
-rw-r--r--tools/perf/tests/bpf-script-example.c4
-rw-r--r--tools/perf/tests/bpf-script-test-kbuild.c21
-rw-r--r--tools/perf/tests/bpf-script-test-prologue.c35
-rw-r--r--tools/perf/tests/bpf.c262
-rw-r--r--tools/perf/tests/builtin-test.c147
-rw-r--r--tools/perf/tests/code-reading.c24
-rw-r--r--tools/perf/tests/cpumap.c88
-rw-r--r--tools/perf/tests/dso-data.c6
-rw-r--r--tools/perf/tests/dwarf-unwind.c37
-rw-r--r--tools/perf/tests/event_update.c117
-rw-r--r--tools/perf/tests/evsel-roundtrip-name.c5
-rw-r--r--tools/perf/tests/evsel-tp-sched.c2
-rw-r--r--tools/perf/tests/fdarray.c4
-rw-r--r--tools/perf/tests/hists_common.c6
-rw-r--r--tools/perf/tests/hists_cumulate.c10
-rw-r--r--tools/perf/tests/hists_filter.c4
-rw-r--r--tools/perf/tests/hists_link.c10
-rw-r--r--tools/perf/tests/hists_output.c12
-rw-r--r--tools/perf/tests/keep-tracking.c9
-rw-r--r--tools/perf/tests/kmod-path.c2
-rw-r--r--tools/perf/tests/llvm.c143
-rw-r--r--tools/perf/tests/llvm.h20
-rw-r--r--tools/perf/tests/make8
-rw-r--r--tools/perf/tests/mmap-basic.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c8
-rw-r--r--tools/perf/tests/openat-syscall-all-cpus.c2
-rw-r--r--tools/perf/tests/openat-syscall-tp-fields.c2
-rw-r--r--tools/perf/tests/openat-syscall.c2
-rw-r--r--tools/perf/tests/parse-events.c2
-rw-r--r--tools/perf/tests/parse-no-sample-id-all.c2
-rw-r--r--tools/perf/tests/perf-record.c8
-rw-r--r--tools/perf/tests/pmu.c2
-rw-r--r--tools/perf/tests/python-use.c3
-rw-r--r--tools/perf/tests/sample-parsing.c2
-rw-r--r--tools/perf/tests/stat.c111
-rw-r--r--tools/perf/tests/sw-clock.c2
-rw-r--r--tools/perf/tests/switch-tracking.c12
-rw-r--r--tools/perf/tests/task-exit.c2
-rw-r--r--tools/perf/tests/tests.h94
-rw-r--r--tools/perf/tests/thread-map.c45
-rw-r--r--tools/perf/tests/thread-mg-share.c2
-rw-r--r--tools/perf/tests/topology.c2
-rw-r--r--tools/perf/tests/vmlinux-kallsyms.c2
-rw-r--r--tools/perf/ui/browser.c2
-rw-r--r--tools/perf/ui/browsers/hists.c342
-rw-r--r--tools/perf/ui/gtk/hists.c152
-rw-r--r--tools/perf/ui/hist.c14
-rw-r--r--tools/perf/ui/stdio/hist.c100
-rw-r--r--tools/perf/util/Build28
-rw-r--r--tools/perf/util/annotate.c44
-rw-r--r--tools/perf/util/auxtrace.c2
-rw-r--r--tools/perf/util/bpf-loader.c574
-rw-r--r--tools/perf/util/bpf-loader.h37
-rw-r--r--tools/perf/util/bpf-prologue.c455
-rw-r--r--tools/perf/util/bpf-prologue.h34
-rw-r--r--tools/perf/util/build-id.c3
-rw-r--r--tools/perf/util/cache.h14
-rw-r--r--tools/perf/util/callchain.c164
-rw-r--r--tools/perf/util/callchain.h30
-rw-r--r--tools/perf/util/cgroup.c2
-rw-r--r--tools/perf/util/color.c2
-rw-r--r--tools/perf/util/config.c2
-rw-r--r--tools/perf/util/cpumap.c51
-rw-r--r--tools/perf/util/cpumap.h1
-rw-r--r--tools/perf/util/data-convert-bt.c2
-rw-r--r--tools/perf/util/dso.c19
-rw-r--r--tools/perf/util/dso.h1
-rw-r--r--tools/perf/util/env.c9
-rw-r--r--tools/perf/util/environment.c8
-rw-r--r--tools/perf/util/event.c308
-rw-r--r--tools/perf/util/event.h150
-rw-r--r--tools/perf/util/evlist.c112
-rw-r--r--tools/perf/util/evlist.h10
-rw-r--r--tools/perf/util/evsel.c53
-rw-r--r--tools/perf/util/evsel.h4
-rw-r--r--tools/perf/util/exec_cmd.c148
-rw-r--r--tools/perf/util/exec_cmd.h12
-rwxr-xr-xtools/perf/util/generate-cmdlist.sh15
-rw-r--r--tools/perf/util/header.c207
-rw-r--r--tools/perf/util/header.h17
-rw-r--r--tools/perf/util/help-unknown-cmd.c103
-rw-r--r--tools/perf/util/help-unknown-cmd.h0
-rw-r--r--tools/perf/util/hist.c118
-rw-r--r--tools/perf/util/hist.h24
-rw-r--r--tools/perf/util/include/linux/string.h3
-rw-r--r--tools/perf/util/intel-pt.c4
-rw-r--r--tools/perf/util/llvm-utils.c54
-rw-r--r--tools/perf/util/machine.c75
-rw-r--r--tools/perf/util/map.c17
-rw-r--r--tools/perf/util/parse-branch-options.c2
-rw-r--r--tools/perf/util/parse-events.c21
-rw-r--r--tools/perf/util/parse-regs-options.c2
-rw-r--r--tools/perf/util/path.c18
-rw-r--r--tools/perf/util/pmu.c1
-rw-r--r--tools/perf/util/probe-event.c13
-rw-r--r--tools/perf/util/probe-file.c6
-rw-r--r--tools/perf/util/probe-finder.c30
-rw-r--r--tools/perf/util/python-ext-sources2
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c115
-rw-r--r--tools/perf/util/session.c208
-rw-r--r--tools/perf/util/session.h2
-rw-r--r--tools/perf/util/sort.c601
-rw-r--r--tools/perf/util/sort.h14
-rw-r--r--tools/perf/util/stat-shadow.c5
-rw-r--r--tools/perf/util/stat.c62
-rw-r--r--tools/perf/util/stat.h10
-rw-r--r--tools/perf/util/string.c16
-rw-r--r--tools/perf/util/symbol-elf.c9
-rw-r--r--tools/perf/util/symbol.c100
-rw-r--r--tools/perf/util/symbol.h5
-rw-r--r--tools/perf/util/term.c35
-rw-r--r--tools/perf/util/term.h10
-rw-r--r--tools/perf/util/thread.c10
-rw-r--r--tools/perf/util/thread_map.c28
-rw-r--r--tools/perf/util/thread_map.h3
-rw-r--r--tools/perf/util/tool.h8
-rw-r--r--tools/perf/util/trace-event.h4
-rw-r--r--tools/perf/util/unwind-libdw.c63
-rw-r--r--tools/perf/util/unwind-libdw.h2
-rw-r--r--tools/perf/util/unwind-libunwind.c80
-rw-r--r--tools/perf/util/util.c97
-rw-r--r--tools/perf/util/util.h28
-rw-r--r--tools/power/cpupower/debug/i386/dump_psb.c2
-rw-r--r--tools/power/cpupower/man/cpupower-idle-set.14
-rw-r--r--tools/power/cpupower/utils/cpufreq-info.c30
-rw-r--r--tools/power/cpupower/utils/cpufreq-set.c10
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c4
-rw-r--r--tools/power/cpupower/utils/cpuidle-set.c33
-rw-r--r--tools/power/cpupower/utils/cpupower-info.c4
-rw-r--r--tools/power/cpupower/utils/cpupower-set.c2
-rw-r--r--tools/power/cpupower/utils/helpers/topology.c23
-rw-r--r--tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c9
-rw-r--r--tools/power/x86/turbostat/turbostat.c36
-rw-r--r--tools/testing/nvdimm/test/nfit.c215
-rw-r--r--tools/testing/selftests/Makefile4
-rw-r--r--tools/testing/selftests/breakpoints/Makefile2
-rw-r--r--tools/testing/selftests/efivarfs/.gitignore2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc2
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc14
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc2
-rw-r--r--tools/testing/selftests/futex/README2
-rw-r--r--tools/testing/selftests/memfd/Makefile12
-rw-r--r--tools/testing/selftests/memfd/memfd_test.c3
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/memfd/run_fuse_test.sh0
-rw-r--r--tools/testing/selftests/mqueue/mq_open_tests.c1
-rw-r--r--tools/testing/selftests/mqueue/mq_perf_tests.c1
-rw-r--r--tools/testing/selftests/pstore/Makefile15
-rwxr-xr-xtools/testing/selftests/pstore/common_tests83
-rwxr-xr-xtools/testing/selftests/pstore/pstore_crash_test30
-rwxr-xr-xtools/testing/selftests/pstore/pstore_post_reboot_tests77
-rwxr-xr-xtools/testing/selftests/pstore/pstore_tests30
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh9
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh22
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/parse-console.sh41
-rw-r--r--tools/testing/selftests/rcutorture/doc/TINY_RCU.txt1
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt4
-rw-r--r--tools/testing/selftests/seccomp/seccomp_bpf.c147
-rwxr-xr-x[-rw-r--r--]tools/testing/selftests/static_keys/test_static_keys.sh0
-rw-r--r--tools/testing/selftests/timers/clocksource-switch.c2
-rw-r--r--tools/testing/selftests/timers/nanosleep.c1
-rw-r--r--tools/testing/selftests/vm/mlock2-tests.c5
-rwxr-xr-xtools/testing/selftests/vm/run_vmtests15
-rw-r--r--tools/thermal/tmon/Makefile3
-rw-r--r--tools/virtio/linux/kernel.h6
-rw-r--r--tools/virtio/linux/virtio.h6
-rw-r--r--tools/virtio/linux/virtio_config.h20
-rw-r--r--tools/vm/page-types.c1
-rw-r--r--virt/kvm/arm/arch_timer.c28
-rw-r--r--virt/kvm/arm/vgic-v3.c11
-rw-r--r--virt/kvm/arm/vgic.c52
-rw-r--r--virt/kvm/async_pf.c3
-rw-r--r--virt/kvm/irqchip.c7
-rw-r--r--virt/kvm/kvm_main.c46
4540 files changed, 125794 insertions, 85411 deletions
diff --git a/CREDITS b/CREDITS
index 8207cc6..af67a84 100644
--- a/CREDITS
+++ b/CREDITS
@@ -1507,6 +1507,14 @@ S: 312/107 Canberra Avenue
S: Griffith, ACT 2603
S: Australia
+N: Andreas Herrmann
+E: herrmann.der.user@gmail.com
+E: herrmann.der.user@googlemail.com
+D: Key developer of x86/AMD64
+D: Author of AMD family 15h processor power monitoring driver
+D: Maintainer of AMD Athlon 64 and Opteron processor frequency driver
+S: Germany
+
N: Sebastian Hetze
E: she@lunetix.de
D: German Linux Documentation,
diff --git a/Documentation/ABI/testing/sysfs-driver-st b/Documentation/ABI/testing/sysfs-driver-st
new file mode 100644
index 0000000..ba5d770
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-driver-st
@@ -0,0 +1,12 @@
+What: /sys/bus/scsi/drivers/st/debug_flag
+Date: October 2015
+Kernel Version: ?.?
+Contact: shane.seymour@hpe.com
+Description:
+ This file allows you to turn debug output from the st driver
+ off if you write a '0' to the file or on if you write a '1'.
+ Note that debug output requires that the module be compiled
+ with the #define DEBUG set to a non-zero value (this is the
+ default). If DEBUG is set to 0 then this file will not
+ appear in sysfs as its presence is conditional upon debug
+ output support being compiled into the module.
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
index 42a2d85..7b3fcc5 100644
--- a/Documentation/DocBook/device-drivers.tmpl
+++ b/Documentation/DocBook/device-drivers.tmpl
@@ -238,78 +238,26 @@ X!Isound/sound_firmware.c
!Iinclude/media/videobuf2-memops.h
</sect1>
<sect1><title>Digital TV (DVB) devices</title>
-!Idrivers/media/dvb-core/dvb_ca_en50221.h
-!Idrivers/media/dvb-core/dvb_frontend.h
+ <sect1><title>Digital TV Common functions</title>
!Idrivers/media/dvb-core/dvb_math.h
!Idrivers/media/dvb-core/dvb_ringbuffer.h
!Idrivers/media/dvb-core/dvbdev.h
- <sect1><title>Digital TV Demux API</title>
- <para>The kernel demux API defines a driver-internal interface for
- registering low-level, hardware specific driver to a hardware
- independent demux layer. It is only of interest for Digital TV
- device driver writers. The header file for this API is named
- <constant>demux.h</constant> and located in
- <constant>drivers/media/dvb-core</constant>.</para>
-
- <para>The demux API should be implemented for each demux in the
- system. It is used to select the TS source of a demux and to manage
- the demux resources. When the demux client allocates a resource via
- the demux API, it receives a pointer to the API of that
- resource.</para>
- <para>Each demux receives its TS input from a DVB front-end or from
- memory, as set via this demux API. In a system with more than one
- front-end, the API can be used to select one of the DVB front-ends
- as a TS source for a demux, unless this is fixed in the HW platform.
- The demux API only controls front-ends regarding to their connections
- with demuxes; the APIs used to set the other front-end parameters,
- such as tuning, are not defined in this document.</para>
- <para>The functions that implement the abstract interface demux should
- be defined static or module private and registered to the Demux
- core for external access. It is not necessary to implement every
- function in the struct <constant>dmx_demux</constant>. For example,
- a demux interface might support Section filtering, but not PES
- filtering. The API client is expected to check the value of any
- function pointer before calling the function: the value of NULL means
- that the &#8220;function is not available&#8221;.</para>
- <para>Whenever the functions of the demux API modify shared data,
- the possibilities of lost update and race condition problems should
- be addressed, e.g. by protecting parts of code with mutexes.</para>
- <para>Note that functions called from a bottom half context must not
- sleep. Even a simple memory allocation without using GFP_ATOMIC can
- result in a kernel thread being put to sleep if swapping is needed.
- For example, the Linux kernel calls the functions of a network device
- interface from a bottom half context. Thus, if a demux API function
- is called from network device code, the function must not sleep.
- </para>
- </sect1>
-
- <section id="demux_callback_api">
- <title>Demux Callback API</title>
- <para>This kernel-space API comprises the callback functions that
- deliver filtered data to the demux client. Unlike the other DVB
- kABIs, these functions are provided by the client and called from
- the demux code.</para>
- <para>The function pointers of this abstract interface are not
- packed into a structure as in the other demux APIs, because the
- callback functions are registered and used independent of each
- other. As an example, it is possible for the API client to provide
- several callback functions for receiving TS packets and no
- callbacks for PES packets or sections.</para>
- <para>The functions that implement the callback API need not be
- re-entrant: when a demux driver calls one of these functions,
- the driver is not allowed to call the function again before
- the original call returns. If a callback is triggered by a
- hardware interrupt, it is recommended to use the Linux
- &#8220;bottom half&#8221; mechanism or start a tasklet instead of
- making the callback function call directly from a hardware
- interrupt.</para>
- <para>This mechanism is implemented by
- <link linkend='API-dmx-ts-cb'>dmx_ts_cb()</link> and
- <link linkend='API-dmx-section-cb'>dmx_section_cb()</link>.</para>
- </section>
-
+ </sect1>
+ <sect1><title>Digital TV Frontend kABI</title>
+!Pdrivers/media/dvb-core/dvb_frontend.h Digital TV Frontend
+!Idrivers/media/dvb-core/dvb_frontend.h
+ </sect1>
+ <sect1><title>Digital TV Demux kABI</title>
+!Pdrivers/media/dvb-core/demux.h Digital TV Demux
+ <sect1><title>Demux Callback API</title>
+!Pdrivers/media/dvb-core/demux.h Demux Callback
+ </sect1>
!Idrivers/media/dvb-core/demux.h
- </sect1>
+ </sect1>
+ <sect1><title>Digital TV Conditional Access kABI</title>
+!Idrivers/media/dvb-core/dvb_ca_en50221.h
+ </sect1>
+ </sect1>
<sect1><title>Remote Controller devices</title>
!Iinclude/media/rc-core.h
!Iinclude/media/lirc_dev.h
diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 08527e7..2840ff4 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -199,8 +199,10 @@ DVB_DOCUMENTED = \
#
install_media_images = \
- $(Q)-mkdir $(MEDIA_OBJ_DIR)/media_api; \
- cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api
+ $(Q)if [ "x$(findstring media_api.xml,$(DOCBOOKS))" != "x" ]; then \
+ mkdir -p $(MEDIA_OBJ_DIR)/media_api; \
+ cp $(OBJIMGFILES) $(MEDIA_SRC_DIR)/*.svg $(MEDIA_SRC_DIR)/v4l/*.svg $(MEDIA_OBJ_DIR)/media_api; \
+ fi
$(MEDIA_OBJ_DIR)/%: $(MEDIA_SRC_DIR)/%.b64
$(Q)base64 -d $< >$@
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 08227d4..e579ae5 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -76,7 +76,7 @@ int main(void)
<para>NOTE: While it is possible to directly call the Kernel code like the
above example, it is strongly recommended to use
- <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
+ <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>,
as it provides abstraction to work with the supported digital TV standards
and provides methods for usual operations like program scanning and to
read/write channel descriptor files.</para>
diff --git a/Documentation/DocBook/media/dvb/examples.xml b/Documentation/DocBook/media/dvb/examples.xml
index c9f68c7..837fb3b 100644
--- a/Documentation/DocBook/media/dvb/examples.xml
+++ b/Documentation/DocBook/media/dvb/examples.xml
@@ -3,7 +3,7 @@
</para>
<para>NOTE: This section is out of date, and the code below won't even
compile. Please refer to the
- <ulink url="http://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
+ <ulink url="https://linuxtv.org/docs/libdvbv5/index.html">libdvbv5</ulink>
for updated/recommended examples.
</para>
diff --git a/Documentation/DocBook/media/dvb/intro.xml b/Documentation/DocBook/media/dvb/intro.xml
index 51db156..b5b701f 100644
--- a/Documentation/DocBook/media/dvb/intro.xml
+++ b/Documentation/DocBook/media/dvb/intro.xml
@@ -32,7 +32,7 @@ and filtering several section and PES data streams at the same time.
new standard Linux DVB API. As a commitment to the development of
terminals based on open standards, Nokia and Convergence made it
available to all Linux developers and published it on
-<ulink url="http://www.linuxtv.org/" /> in September 2000.
+<ulink url="https://linuxtv.org" /> in September 2000.
Convergence is the maintainer of the Linux DVB API. Together with the
LinuxTV community (i.e. you, the reader of this document), the Linux DVB
API will be constantly reviewed and improved. With the Linux driver for
diff --git a/Documentation/DocBook/media/v4l/capture.c.xml b/Documentation/DocBook/media/v4l/capture.c.xml
index 1c5c49a..22126a9 100644
--- a/Documentation/DocBook/media/v4l/capture.c.xml
+++ b/Documentation/DocBook/media/v4l/capture.c.xml
@@ -5,7 +5,7 @@
* This program can be used and distributed without restrictions.
*
* This program is provided with the V4L2 API
- * see http://linuxtv.org/docs.php for more information
+ * see https://linuxtv.org/docs.php for more information
*/
#include &lt;stdio.h&gt;
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index 5701a08..5399e89 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2666,7 +2666,7 @@ is useful to display images captured with V4L2 devices.</para>
<para>V4L2 does not support digital terrestrial, cable or
satellite broadcast. A separate project aiming at digital receivers
exists. You can find its homepage at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>. The Linux DVB API
+url="https://linuxtv.org">https://linuxtv.org</ulink>. The Linux DVB API
has no connection to the V4L2 API except that drivers for hybrid
hardware may support both.</para>
</section>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index da65403..144158b 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -699,7 +699,7 @@ linkend="v4l2-buf-type" /></entry>
buffer. It depends on the negotiated data format and may change with
each buffer for compressed variable size data like JPEG images.
Drivers must set this field when <structfield>type</structfield>
-refers to an input stream, applications when it refers to an output stream.
+refers to a capture stream, applications when it refers to an output stream.
If the application sets this to 0 for an output stream, then
<structfield>bytesused</structfield> will be set to the size of the
buffer (see the <structfield>length</structfield> field of this struct) by
@@ -720,14 +720,14 @@ linkend="buffer-flags" />.</entry>
<entry>Indicates the field order of the image in the
buffer, see <xref linkend="v4l2-field" />. This field is not used when
the buffer contains VBI data. Drivers must set it when
-<structfield>type</structfield> refers to an input stream,
+<structfield>type</structfield> refers to a capture stream,
applications when it refers to an output stream.</entry>
</row>
<row>
<entry>struct timeval</entry>
<entry><structfield>timestamp</structfield></entry>
<entry></entry>
- <entry><para>For input streams this is time when the first data
+ <entry><para>For capture streams this is time when the first data
byte was captured, as returned by the
<function>clock_gettime()</function> function for the relevant
clock id; see <constant>V4L2_BUF_FLAG_TIMESTAMP_*</constant> in
@@ -866,7 +866,7 @@ must set this to 0.</entry>
<entry></entry>
<entry>The number of bytes occupied by data in the plane
(its payload). Drivers must set this field when <structfield>type</structfield>
- refers to an input stream, applications when it refers to an output stream.
+ refers to a capture stream, applications when it refers to an output stream.
If the application sets this to 0 for an output stream, then
<structfield>bytesused</structfield> will be set to the size of the
plane (see the <structfield>length</structfield> field of this struct)
@@ -919,7 +919,7 @@ must set this to 0.</entry>
<entry></entry>
<entry>Offset in bytes to video data in the plane.
Drivers must set this field when <structfield>type</structfield>
- refers to an input stream, applications when it refers to an output stream.
+ refers to a capture stream, applications when it refers to an output stream.
Note that data_offset is included in <structfield>bytesused</structfield>.
So the size of the image in the plane is
<structfield>bytesused</structfield>-<structfield>data_offset</structfield> at
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index 7e61643..42e626d 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -152,6 +152,16 @@ structs, ioctls) must be noted in more detail in the history chapter
(compat.xml), along with the possible impact on existing drivers and
applications. -->
<revision>
+ <revnumber>4.5</revnumber>
+ <date>2015-10-29</date>
+ <authorinitials>rr</authorinitials>
+ <revremark>Extend vidioc-g-ext-ctrls;. Replace ctrl_class with a new
+union with ctrl_class and which. Which is used to select the current value of
+the control or the default value.
+ </revremark>
+ </revision>
+
+ <revision>
<revnumber>4.4</revnumber>
<date>2015-05-26</date>
<authorinitials>ap</authorinitials>
diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
index 8ffe74f..d81fa0d 100644
--- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml
@@ -58,7 +58,7 @@
<para>This ioctl is used to create buffers for <link linkend="mmap">memory
mapped</link> or <link linkend="userp">user pointer</link> or <link
linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
-addition to the <constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter
+addition to the &VIDIOC-REQBUFS; ioctl, when a tighter
control over buffers is required. This ioctl can be called multiple times to
create buffers of different sizes.</para>
@@ -71,30 +71,28 @@ zeroed.</para>
<para>The <structfield>format</structfield> field specifies the image format
that the buffers must be able to handle. The application has to fill in this
-&v4l2-format;. Usually this will be done using the
-<constant>VIDIOC_TRY_FMT</constant> or <constant>VIDIOC_G_FMT</constant> ioctl()
-to ensure that the requested format is supported by the driver. Unsupported
-formats will result in an error.</para>
+&v4l2-format;. Usually this will be done using the &VIDIOC-TRY-FMT; or &VIDIOC-G-FMT; ioctls
+to ensure that the requested format is supported by the driver.
+Based on the format's <structfield>type</structfield> field the requested buffer
+size (for single-planar) or plane sizes (for multi-planar formats) will be
+used for the allocated buffers. The driver may return an error if the size(s)
+are not supported by the hardware (usually because they are too small).</para>
<para>The buffers created by this ioctl will have as minimum size the size
-defined by the <structfield>format.pix.sizeimage</structfield> field. If the
+defined by the <structfield>format.pix.sizeimage</structfield> field (or the
+corresponding fields for other format types). Usually if the
<structfield>format.pix.sizeimage</structfield> field is less than the minimum
-required for the given format, then <structfield>sizeimage</structfield> will be
-increased by the driver to that minimum to allocate the buffers. If it is
-larger, then the value will be used as-is. The same applies to the
-<structfield>sizeimage</structfield> field of the
-<structname>v4l2_plane_pix_format</structname> structure in the case of
-multiplanar formats.</para>
+required for the given format, then an error will be returned since drivers will
+typically not allow this. If it is larger, then the value will be used as-is.
+In other words, the driver may reject the requested size, but if it is accepted
+the driver will use it unchanged.</para>
<para>When the ioctl is called with a pointer to this structure the driver
will attempt to allocate up to the requested number of buffers and store the
actual number allocated and the starting index in the
<structfield>count</structfield> and the <structfield>index</structfield> fields
respectively. On return <structfield>count</structfield> can be smaller than
-the number requested. The driver may also increase buffer sizes if required,
-however, it will not update <structfield>sizeimage</structfield> field values.
-The user has to use <constant>VIDIOC_QUERYBUF</constant> to retrieve that
-information.</para>
+the number requested.</para>
<table pgwide="1" frame="none" id="v4l2-create-buffers">
<title>struct <structname>v4l2_create_buffers</structname></title>
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
index 4c4603c..f14a3bb 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-chip-info.xml
@@ -99,7 +99,7 @@ if the driver supports writing registers to the device.</para>
<para>We recommended the <application>v4l2-dbg</application>
utility over calling this ioctl directly. It is available from the
LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+url="https://linuxtv.org/repo/">https://linuxtv.org/repo/</ulink> for
access instructions.</para>
<!-- Note for convenience vidioc-dbg-g-register.sgml
diff --git a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
index 3d038e7..5877f68 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dbg-g-register.xml
@@ -117,7 +117,7 @@ However when a driver supports these ioctls it must also support
<para>We recommended the <application>v4l2-dbg</application>
utility over calling these ioctls directly. It is available from the
LinuxTV v4l-dvb repository; see <ulink
-url="http://linuxtv.org/repo/">http://linuxtv.org/repo/</ulink> for
+url="https://linuxtv.org/repo/">https://linuxtv.org/repo/</ulink> for
access instructions.</para>
<!-- Note for convenience vidioc-dbg-g-chip-info.sgml
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml
index 8065099..f18454e 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enumstd.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enumstd.xml
@@ -198,7 +198,7 @@ video4linux-list@redhat.com on 17 Oct 2002
<constant>V4L2_STD_ATSC_16_VSB</constant> are U.S. terrestrial digital
TV standards. Presently the V4L2 API does not support digital TV. See
also the Linux DVB API at <ulink
-url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
<para><programlisting>
#define V4L2_STD_PAL_BG (V4L2_STD_PAL_B |\
V4L2_STD_PAL_B1 |\
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index 842536a..eb82f7e 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -61,7 +61,7 @@ must belong to the same control class.</para>
<para>Applications must always fill in the
<structfield>count</structfield>,
-<structfield>ctrl_class</structfield>,
+<structfield>which</structfield>,
<structfield>controls</structfield> and
<structfield>reserved</structfield> fields of &v4l2-ext-controls;, and
initialize the &v4l2-ext-control; array pointed to by the
@@ -109,7 +109,7 @@ the driver whether wrong values are automatically adjusted to a valid
value or if an error is returned.</para>
<para>When the <structfield>id</structfield> or
-<structfield>ctrl_class</structfield> is invalid drivers return an
+<structfield>which</structfield> is invalid drivers return an
&EINVAL;. When the value is out of bounds drivers can choose to take
the closest valid value or return an &ERANGE;, whatever seems more
appropriate. In the first case the new value is set in
@@ -223,7 +223,12 @@ Valid if <constant>V4L2_CTRL_FLAG_HAS_PAYLOAD</constant> is set for this control
<tgroup cols="3">
&cs-str;
<tbody valign="top">
+ <row>
+ <entry>union</entry>
+ <entry>(anonymous)</entry>
+ </row>
<row>
+ <entry></entry>
<entry>__u32</entry>
<entry><structfield>ctrl_class</structfield></entry>
<entry>The control class to which all controls belong, see
@@ -235,6 +240,23 @@ with a <structfield>count</structfield> of 0. If that succeeds, then the driver
supports this feature.</entry>
</row>
<row>
+ <entry></entry>
+ <entry>__u32</entry>
+ <entry><structfield>which</structfield></entry>
+ <entry><para>Which value of the control to get/set/try. <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
+will return the current value of the control and <constant>V4L2_CTRL_WHICH_DEF_VAL</constant> will
+return the default value of the control. Please note that you can only get the default value of the
+control, you cannot set or try it.</para>
+<para>For backwards compatibility you can also use a control class here (see
+<xref linkend="ctrl-class" />). In that case all controls have to belong to that
+control class. This usage is deprecated, instead just use <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.
+There are some very old drivers that do not yet support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>
+and that require a control class here. You can test for such drivers by setting ctrl_class to
+<constant>V4L2_CTRL_WHICH_CUR_VAL</constant> and calling VIDIOC_TRY_EXT_CTRLS with a count of 0.
+If that fails, then the driver does not support <constant>V4L2_CTRL_WHICH_CUR_VAL</constant>.</para>
+</entry>
+ </row>
+ <row>
<entry>__u32</entry>
<entry><structfield>count</structfield></entry>
<entry>The number of controls in the controls array. May
@@ -390,7 +412,7 @@ These controls are described in <xref linkend="rf-tuner-controls" />.</entry>
<listitem>
<para>The &v4l2-ext-control; <structfield>id</structfield>
is invalid, the &v4l2-ext-controls;
-<structfield>ctrl_class</structfield> is invalid, or the &v4l2-ext-control;
+<structfield>which</structfield> is invalid, or the &v4l2-ext-control;
<structfield>value</structfield> was inappropriate (e.g. the given menu
index is not supported by the driver). This error code is
also returned by the <constant>VIDIOC_S_EXT_CTRLS</constant> and
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 9203703..7b77e0f 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -19,10 +19,10 @@
<!ENTITY cs-def "<colspec colname='c1' colwidth='3*' /><colspec colname='c2' colwidth='1*' /><colspec colname='c3' colwidth='4*' /><spanspec spanname='hspan' namest='c1' nameend='c3' />">
<!-- Video for Linux mailing list address. -->
-<!ENTITY v4l-ml "<ulink url='http://www.linuxtv.org/lists.php'>http://www.linuxtv.org/lists.php</ulink>">
+<!ENTITY v4l-ml "<ulink url='https://linuxtv.org/lists.php'>https://linuxtv.org/lists.php</ulink>">
<!-- LinuxTV v4l-dvb repository. -->
-<!ENTITY v4l-dvb "<ulink url='http://linuxtv.org/repo/'>http://linuxtv.org/repo/</ulink>">
+<!ENTITY v4l-dvb "<ulink url='https://linuxtv.org/repo/'>https://linuxtv.org/repo/</ulink>">
<!ENTITY dash-ent-8 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
<!ENTITY dash-ent-10 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
<!ENTITY dash-ent-12 "<entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry><entry>-</entry>">
@@ -91,7 +91,7 @@
components, like mixers, PCM capture, PCM playback, etc, which
are controlled via ALSA API.</para>
<para>For additional information and for the latest development code,
- see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
+ see: <ulink url="https://linuxtv.org">https://linuxtv.org</ulink>.</para>
<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
</preface>
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 31d1d65..c0d8788 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -587,7 +587,7 @@ used to control it:
modprobe ipmi_watchdog timeout=<t> pretimeout=<t> action=<action type>
preaction=<preaction type> preop=<preop type> start_now=x
- nowayout=x ifnum_to_use=n
+ nowayout=x ifnum_to_use=n panic_wdt_timeout=<t>
ifnum_to_use specifies which interface the watchdog timer should use.
The default is -1, which means to pick the first one registered.
@@ -597,7 +597,9 @@ is the amount of seconds before the reset that the pre-timeout panic will
occur (if pretimeout is zero, then pretimeout will not be enabled). Note
that the pretimeout is the time before the final timeout. So if the
timeout is 50 seconds and the pretimeout is 10 seconds, then the pretimeout
-will occur in 40 second (10 seconds before the timeout).
+will occur in 40 second (10 seconds before the timeout). The panic_wdt_timeout
+is the value of timeout which is set on kernel panic, in order to let actions
+such as kdump to occur during panic.
The action may be "reset", "power_cycle", or "power_off", and
specifies what to do when the timer times out, and defaults to
@@ -634,6 +636,7 @@ for configuring the watchdog:
ipmi_watchdog.preop=<preop type>
ipmi_watchdog.start_now=x
ipmi_watchdog.nowayout=x
+ ipmi_watchdog.panic_wdt_timeout=<t>
The options are the same as the module parameter options.
diff --git a/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png b/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png
new file mode 100644
index 0000000..7496a55
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/2013-08-is-it-dead.png
Binary files differ
diff --git a/Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg b/Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg
new file mode 100644
index 0000000..4b4014f
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/GPpartitionReaders1.svg
@@ -0,0 +1,374 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="447.99197"
+ height="428.19299"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="GPpartitionReaders1.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3792"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lstart"
+ style="overflow:visible">
+ <path
+ id="path3789"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(1.1,0,0,1.1,1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.6184291"
+ inkscape:cx="223.99599"
+ inkscape:cy="214.0965"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="979"
+ inkscape:window-height="836"
+ inkscape:window-x="571"
+ inkscape:window-y="335"
+ inkscape:window-maximized="0"
+ fit-margin-top="5"
+ fit-margin-left="5"
+ fit-margin-right="5"
+ fit-margin-bottom="5" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-28.441125,-185.60612)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot2985"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
+ id="flowRegion2987"><rect
+ id="rect2989"
+ width="82.85714"
+ height="11.428572"
+ x="240"
+ y="492.36218" /></flowRegion><flowPara
+ id="flowPara2991"></flowPara></flowRoot> <g
+ id="g4433"
+ transform="translate(2,0)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2993"
+ y="-261.66608"
+ x="412.12299"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ xml:space="preserve"
+ transform="matrix(0,1,-1,0,0,0)"><tspan
+ y="-261.66608"
+ x="412.12299"
+ id="tspan2995"
+ sodipodi:role="line">synchronize_rcu()</tspan></text>
+ <g
+ id="g4417"
+ transform="matrix(0,1,-1,0,730.90257,222.4928)">
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+ d="m 97.580736,477.4048 183.140664,0"
+ id="path2997"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 96.752718,465.38398 0,22.62742"
+ id="path4397"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 281.54942,465.38397 0,22.62742"
+ id="path4397-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.04738"
+ y="268.18076"
+ id="text4429"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431"
+ x="112.04738"
+ y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.04738"
+ y="439.13766"
+ id="text4441"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4443"
+ x="112.04738"
+ y="439.13766">WRITE_ONCE(b, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="255.60869"
+ y="309.29346"
+ id="text4445"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4447"
+ x="255.60869"
+ y="309.29346">r1 = READ_ONCE(a);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="255.14423"
+ y="520.61786"
+ id="text4449"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4451"
+ x="255.14423"
+ y="520.61786">WRITE_ONCE(c, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="384.71124"
+ id="text4453"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4455"
+ x="396.10254"
+ y="384.71124">r2 = READ_ONCE(b);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="582.13617"
+ id="text4457"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4459"
+ x="396.10254"
+ y="582.13617">r3 = READ_ONCE(c);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.08231"
+ y="213.91006"
+ id="text4461"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463"
+ x="112.08231"
+ y="213.91006">thread0()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="252.34512"
+ y="213.91006"
+ id="text4461-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-0"
+ x="252.34512"
+ y="213.91006">thread1()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.42557"
+ y="213.91006"
+ id="text4461-2"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-2"
+ x="396.42557"
+ y="213.91006">thread2()</tspan></text>
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect4495"
+ width="436.28488"
+ height="416.4859"
+ x="34.648232"
+ y="191.10612" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 183.14066,191.10612 0,417.193 -0.70711,0"
+ id="path4497"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 325.13867,191.10612 0,417.193 -0.70711,0"
+ id="path4497-5"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="111.75929"
+ y="251.53981"
+ id="text4429-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9"
+ x="111.75929"
+ y="251.53981">rcu_read_lock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="367.91556"
+ id="text4429-8-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4"
+ x="396.10254"
+ y="367.91556">rcu_read_lock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="597.40289"
+ id="text4429-8-9-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-4"
+ x="396.10254"
+ y="597.40289">rcu_read_unlock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="111.75929"
+ y="453.15311"
+ id="text4429-8-9-3-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-4-6"
+ x="111.75929"
+ y="453.15311">rcu_read_unlock();</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 33.941125,227.87568 436.284885,0 0,0.7071"
+ id="path4608"
+ inkscape:connector-curvature="0" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="394.94427"
+ y="345.66351"
+ id="text4648"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650"
+ x="394.94427"
+ y="345.66351">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(36.441125,199.60612)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.11968"
+ y="475.77856"
+ id="text4648-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-4"
+ x="112.11968"
+ y="475.77856">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-7"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(-246.38346,329.72117)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-7-7"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(-103.65246,202.90878)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="254.85066"
+ y="348.96619"
+ id="text4648-4-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-4-5"
+ x="254.85066"
+ y="348.96619">QS</tspan></text>
+ </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/RCUApplicability.svg b/Documentation/RCU/Design/Requirements/RCUApplicability.svg
new file mode 100644
index 0000000..ebcbeee
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/RCUApplicability.svg
@@ -0,0 +1,237 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Creator: fig2dev Version 3.2 Patchlevel 5d -->
+
+<!-- CreationDate: Tue Mar 4 18:34:25 2014 -->
+
+<!-- Magnification: 3.000 -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1089.1382"
+ height="668.21368"
+ viewBox="-2121 -36 14554.634 8876.4061"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="RCUApplicability.svg">
+ <metadata
+ id="metadata40">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <defs
+ id="defs38" />
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="849"
+ inkscape:window-height="639"
+ id="namedview36"
+ showgrid="false"
+ inkscape:zoom="0.51326165"
+ inkscape:cx="544.56912"
+ inkscape:cy="334.10686"
+ inkscape:window-x="149"
+ inkscape:window-y="448"
+ inkscape:window-maximized="0"
+ inkscape:current-layer="g4"
+ fit-margin-top="5"
+ fit-margin-left="5"
+ fit-margin-right="5"
+ fit-margin-bottom="5" />
+ <g
+ style="fill:none;stroke-width:0.025in"
+ id="g4"
+ transform="translate(-2043.6828,14.791398)">
+ <!-- Line: box -->
+ <rect
+ x="0"
+ y="0"
+ width="14400"
+ height="8775"
+ rx="0"
+ style="fill:#ffa1a1;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+ id="rect6" />
+ <!-- Line: box -->
+ <rect
+ x="1350"
+ y="0"
+ width="11700"
+ height="6075"
+ rx="0"
+ style="fill:#ffff00;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+ id="rect8" />
+ <!-- Line: box -->
+ <rect
+ x="2700"
+ y="0"
+ width="9000"
+ height="4275"
+ rx="0"
+ style="fill:#00ff00;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+ id="rect10" />
+ <!-- Line: box -->
+ <rect
+ x="4050"
+ y="0"
+ width="6300"
+ height="2475"
+ rx="0"
+ style="fill:#87cfff;stroke:#000000;stroke-width:21;stroke-linecap:butt;stroke-linejoin:miter"
+ id="rect12" />
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="900"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text14"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3017">Read-Mostly, Stale &amp;</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="1350"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text16"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3019">Inconsistent Data OK</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="1800"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text18"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3021">(RCU Works Great!!!)</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="3825"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text20"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3023">(RCU Works Well)</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="3375"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text22"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3025">Read-Mostly, Need Consistent Data</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="5175"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text24"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3027">Read-Write, Need Consistent Data</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="6975"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text26"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ sodipodi:linespacing="125%">Update-Mostly, Need Consistent Data</text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="5625"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text28"
+ sodipodi:linespacing="125%"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"><tspan
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ id="tspan3029">(RCU Might Be OK...)</tspan></text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="7875"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text30"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ sodipodi:linespacing="125%">(1) Provide Existence Guarantees For Update-Friendly Mechanisms</text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="8325"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text32"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ sodipodi:linespacing="125%">(2) Provide Wait-Free Read-Side Primitives for Real-Time Use)</text>
+ <!-- Text -->
+ <text
+ xml:space="preserve"
+ x="7200"
+ y="7425"
+ font-style="normal"
+ font-weight="normal"
+ font-size="324"
+ id="text34"
+ style="font-size:427.63009644px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;font-family:Nimbus Sans L;-inkscape-font-specification:Nimbus Sans L"
+ sodipodi:linespacing="125%">(RCU is Very Unlikely to be the Right Tool For The Job, But it Can:</text>
+ </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg b/Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg
new file mode 100644
index 0000000..48cd162
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/ReadersPartitionGP1.svg
@@ -0,0 +1,639 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="735.25"
+ height="516.21875"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.48.3.1 r9886"
+ sodipodi:docname="ReadersPartitionGP1.svg">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend"
+ style="overflow:visible">
+ <path
+ id="path3792"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lstart"
+ style="overflow:visible">
+ <path
+ id="path3789"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(1.1,0,0,1.1,1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lstart-4"
+ style="overflow:visible">
+ <path
+ id="path3789-9"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(1.1,0,0,1.1,1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow2Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow2Lend-4"
+ style="overflow:visible">
+ <path
+ id="path3792-4"
+ style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
+ d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
+ transform="matrix(-1.1,0,0,-1.1,-1.1,0)"
+ inkscape:connector-curvature="0" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.3670394"
+ inkscape:cx="367.26465"
+ inkscape:cy="258.46182"
+ inkscape:document-units="px"
+ inkscape:current-layer="g4433-6"
+ showgrid="false"
+ inkscape:window-width="1351"
+ inkscape:window-height="836"
+ inkscape:window-x="438"
+ inkscape:window-y="335"
+ inkscape:window-maximized="0"
+ fit-margin-top="5"
+ fit-margin-left="5"
+ fit-margin-right="5"
+ fit-margin-bottom="5" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-29.15625,-185.59375)">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot2985"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"><flowRegion
+ id="flowRegion2987"><rect
+ id="rect2989"
+ width="82.85714"
+ height="11.428572"
+ x="240"
+ y="492.36218" /></flowRegion><flowPara
+ id="flowPara2991" /></flowRoot> <g
+ id="g4433"
+ transform="translate(2,-12)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2993"
+ y="-261.66608"
+ x="436.12299"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ xml:space="preserve"
+ transform="matrix(0,1,-1,0,0,0)"><tspan
+ y="-261.66608"
+ x="436.12299"
+ id="tspan2995"
+ sodipodi:role="line">synchronize_rcu()</tspan></text>
+ <g
+ id="g4417"
+ transform="matrix(0,1,-1,0,730.90257,222.4928)">
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+ d="M 97.580736,477.4048 327.57913,476.09759"
+ id="path2997"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 96.752718,465.38398 0,22.62742"
+ id="path4397"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 328.40703,465.38397 0,22.62742"
+ id="path4397-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.04738"
+ y="268.18076"
+ id="text4429"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431"
+ x="112.04738"
+ y="268.18076">WRITE_ONCE(a, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.04738"
+ y="487.13766"
+ id="text4441"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4443"
+ x="112.04738"
+ y="487.13766">WRITE_ONCE(b, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="255.60869"
+ y="297.29346"
+ id="text4445"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4447"
+ x="255.60869"
+ y="297.29346">r1 = READ_ONCE(a);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="255.14423"
+ y="554.61786"
+ id="text4449"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4451"
+ x="255.14423"
+ y="554.61786">WRITE_ONCE(c, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="370.71124"
+ id="text4453"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4455"
+ x="396.10254"
+ y="370.71124">WRITE_ONCE(d, 1);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="572.13617"
+ id="text4457"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4459"
+ x="396.10254"
+ y="572.13617">r2 = READ_ONCE(c);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.08231"
+ y="213.91006"
+ id="text4461"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463"
+ x="112.08231"
+ y="213.91006">thread0()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="252.34512"
+ y="213.91006"
+ id="text4461-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-0"
+ x="252.34512"
+ y="213.91006">thread1()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.42557"
+ y="213.91006"
+ id="text4461-2"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-2"
+ x="396.42557"
+ y="213.91006">thread2()</tspan></text>
+ <rect
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect4495"
+ width="724.25244"
+ height="505.21201"
+ x="34.648232"
+ y="191.10612" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 183.14066,191.10612 0,504.24243"
+ id="path4497"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 325.13867,191.10612 0,504.24243"
+ id="path4497-5"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="111.75929"
+ y="251.53981"
+ id="text4429-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9"
+ x="111.75929"
+ y="251.53981">rcu_read_lock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="353.91556"
+ id="text4429-8-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4"
+ x="396.10254"
+ y="353.91556">rcu_read_lock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="396.10254"
+ y="587.40289"
+ id="text4429-8-9-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-4"
+ x="396.10254"
+ y="587.40289">rcu_read_unlock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="111.75929"
+ y="501.15311"
+ id="text4429-8-9-3-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-4-6"
+ x="111.75929"
+ y="501.15311">rcu_read_unlock();</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 33.941125,227.87568 724.941765,0"
+ id="path4608"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="394.94427"
+ y="331.66351"
+ id="text4648"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650"
+ x="394.94427"
+ y="331.66351">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(36.441125,185.60612)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="112.11968"
+ y="523.77856"
+ id="text4648-4"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-4"
+ x="112.11968"
+ y="523.77856">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-7"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(-246.38346,377.72117)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-7-7"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(-103.65246,190.90878)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="254.85066"
+ y="336.96619"
+ id="text4648-4-3"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-4-5"
+ x="254.85066"
+ y="336.96619">QS</tspan></text>
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 470.93311,190.39903 0,504.24243"
+ id="path4497-5-6"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ d="m 616.22755,190.38323 0,504.24243"
+ id="path4497-5-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <g
+ id="g4433-6"
+ transform="translate(288.0964,78.32827)">
+ <text
+ sodipodi:linespacing="125%"
+ id="text2993-7"
+ y="-261.66608"
+ x="440.12299"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ xml:space="preserve"
+ transform="matrix(0,1,-1,0,0,0)"><tspan
+ y="-261.66608"
+ x="440.12299"
+ id="tspan2995-1"
+ sodipodi:role="line">synchronize_rcu()</tspan></text>
+ <g
+ id="g4417-1"
+ transform="matrix(0,1,-1,0,730.90257,222.4928)">
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#Arrow2Lstart);marker-end:url(#Arrow2Lend)"
+ d="M 97.580736,477.4048 328.5624,477.07246"
+ id="path2997-2"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 96.752718,465.38398 0,22.62742"
+ id="path4397-3"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 329.39039,465.38397 0,22.62742"
+ id="path4397-5-4"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cc" />
+ </g>
+ </g>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="541.70508"
+ y="387.6217"
+ id="text4445-0"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4447-5"
+ x="541.70508"
+ y="387.6217">r3 = READ_ONCE(d);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="541.2406"
+ y="646.94611"
+ id="text4449-6"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4451-6"
+ x="541.2406"
+ y="646.94611">WRITE_ONCE(e, 1);</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-7-7-5"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(182.44393,281.23704)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="540.94702"
+ y="427.29443"
+ id="text4648-4-3-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-4-5-7"
+ x="540.94702"
+ y="427.29443">QS</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="686.27747"
+ y="461.83929"
+ id="text4453-7"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4455-1"
+ x="686.27747"
+ y="461.83929">r4 = READ_ONCE(b);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="686.27747"
+ y="669.26422"
+ id="text4457-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4459-2"
+ x="686.27747"
+ y="669.26422">r5 = READ_ONCE(e);</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="686.27747"
+ y="445.04358"
+ id="text4429-8-9-33"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-2"
+ x="686.27747"
+ y="445.04358">rcu_read_lock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="686.27747"
+ y="684.53094"
+ id="text4429-8-9-3-8"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4431-9-4-4-5"
+ x="686.27747"
+ y="684.53094">rcu_read_unlock();</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="685.11914"
+ y="422.79153"
+ id="text4648-9"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-7"
+ x="685.11914"
+ y="422.79153">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-8"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(326.61602,276.73415)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="397.85934"
+ y="609.59003"
+ id="text4648-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-77"
+ x="397.85934"
+ y="609.59003">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-80"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(39.356201,463.53264)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="256.75986"
+ y="586.99133"
+ id="text4648-5-2"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4650-77-7"
+ x="256.75986"
+ y="586.99133">QS</tspan></text>
+ <path
+ sodipodi:type="arc"
+ style="fill:none;stroke:#000000;stroke-width:1;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="path4652-80-5"
+ sodipodi:cx="358.85669"
+ sodipodi:cy="142.87541"
+ sodipodi:rx="10.960155"
+ sodipodi:ry="10.253048"
+ d="m 358.86939,132.62237 a 10.960155,10.253048 0 1 1 -0.0228,0"
+ transform="translate(-101.74328,440.93395)"
+ sodipodi:start="4.7135481"
+ sodipodi:end="10.994651"
+ sodipodi:open="true" />
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="546.22791"
+ y="213.91006"
+ id="text4461-2-5"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-2-6"
+ x="546.22791"
+ y="213.91006">thread3()</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Symbol;-inkscape-font-specification:Symbol"
+ x="684.00067"
+ y="213.91006"
+ id="text4461-2-1"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan4463-2-0"
+ x="684.00067"
+ y="213.91006">thread4()</tspan></text>
+ </g>
+</svg>
diff --git a/Documentation/RCU/Design/Requirements/Requirements.html b/Documentation/RCU/Design/Requirements/Requirements.html
new file mode 100644
index 0000000..a725f99
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/Requirements.html
@@ -0,0 +1,2897 @@
+<!-- DO NOT HAND EDIT. -->
+<!-- Instead, edit Documentation/RCU/Design/Requirements/Requirements.htmlx and run 'sh htmlqqz.sh Documentation/RCU/Design/Requirements/Requirements' -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+ <html>
+ <head><title>A Tour Through RCU's Requirements [LWN.net]</title>
+ <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+
+<h1>A Tour Through RCU's Requirements</h1>
+
+<p>Copyright IBM Corporation, 2015</p>
+<p>Author: Paul E.&nbsp;McKenney</p>
+<p><i>The initial version of this document appeared in the
+<a href="https://lwn.net/">LWN</a> articles
+<a href="https://lwn.net/Articles/652156/">here</a>,
+<a href="https://lwn.net/Articles/652677/">here</a>, and
+<a href="https://lwn.net/Articles/653326/">here</a>.</i></p>
+
+<h2>Introduction</h2>
+
+<p>
+Read-copy update (RCU) is a synchronization mechanism that is often
+used as a replacement for reader-writer locking.
+RCU is unusual in that updaters do not block readers,
+which means that RCU's read-side primitives can be exceedingly fast
+and scalable.
+In addition, updaters can make useful forward progress concurrently
+with readers.
+However, all this concurrency between RCU readers and updaters does raise
+the question of exactly what RCU readers are doing, which in turn
+raises the question of exactly what RCU's requirements are.
+
+<p>
+This document therefore summarizes RCU's requirements, and can be thought
+of as an informal, high-level specification for RCU.
+It is important to understand that RCU's specification is primarily
+empirical in nature;
+in fact, I learned about many of these requirements the hard way.
+This situation might cause some consternation, however, not only
+has this learning process been a lot of fun, but it has also been
+a great privilege to work with so many people willing to apply
+technologies in interesting new ways.
+
+<p>
+All that aside, here are the categories of currently known RCU requirements:
+</p>
+
+<ol>
+<li> <a href="#Fundamental Requirements">
+ Fundamental Requirements</a>
+<li> <a href="#Fundamental Non-Requirements">Fundamental Non-Requirements</a>
+<li> <a href="#Parallelism Facts of Life">
+ Parallelism Facts of Life</a>
+<li> <a href="#Quality-of-Implementation Requirements">
+ Quality-of-Implementation Requirements</a>
+<li> <a href="#Linux Kernel Complications">
+ Linux Kernel Complications</a>
+<li> <a href="#Software-Engineering Requirements">
+ Software-Engineering Requirements</a>
+<li> <a href="#Other RCU Flavors">
+ Other RCU Flavors</a>
+<li> <a href="#Possible Future Changes">
+ Possible Future Changes</a>
+</ol>
+
+<p>
+This is followed by a <a href="#Summary">summary</a>,
+which is in turn followed by the inevitable
+<a href="#Answers to Quick Quizzes">answers to the quick quizzes</a>.
+
+<h2><a name="Fundamental Requirements">Fundamental Requirements</a></h2>
+
+<p>
+RCU's fundamental requirements are the closest thing RCU has to hard
+mathematical requirements.
+These are:
+
+<ol>
+<li> <a href="#Grace-Period Guarantee">
+ Grace-Period Guarantee</a>
+<li> <a href="#Publish-Subscribe Guarantee">
+ Publish-Subscribe Guarantee</a>
+<li> <a href="#Memory-Barrier Guarantees">
+ Memory-Barrier Guarantees</a>
+<li> <a href="#RCU Primitives Guaranteed to Execute Unconditionally">
+ RCU Primitives Guaranteed to Execute Unconditionally</a>
+<li> <a href="#Guaranteed Read-to-Write Upgrade">
+ Guaranteed Read-to-Write Upgrade</a>
+</ol>
+
+<h3><a name="Grace-Period Guarantee">Grace-Period Guarantee</a></h3>
+
+<p>
+RCU's grace-period guarantee is unusual in being premeditated:
+Jack Slingwine and I had this guarantee firmly in mind when we started
+work on RCU (then called &ldquo;rclock&rdquo;) in the early 1990s.
+That said, the past two decades of experience with RCU have produced
+a much more detailed understanding of this guarantee.
+
+<p>
+RCU's grace-period guarantee allows updaters to wait for the completion
+of all pre-existing RCU read-side critical sections.
+An RCU read-side critical section
+begins with the marker <tt>rcu_read_lock()</tt> and ends with
+the marker <tt>rcu_read_unlock()</tt>.
+These markers may be nested, and RCU treats a nested set as one
+big RCU read-side critical section.
+Production-quality implementations of <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> are extremely lightweight, and in
+fact have exactly zero overhead in Linux kernels built for production
+use with <tt>CONFIG_PREEMPT=n</tt>.
+
+<p>
+This guarantee allows ordering to be enforced with extremely low
+overhead to readers, for example:
+
+<blockquote>
+<pre>
+ 1 int x, y;
+ 2
+ 3 void thread0(void)
+ 4 {
+ 5 rcu_read_lock();
+ 6 r1 = READ_ONCE(x);
+ 7 r2 = READ_ONCE(y);
+ 8 rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13 WRITE_ONCE(x, 1);
+14 synchronize_rcu();
+15 WRITE_ONCE(y, 1);
+16 }
+</pre>
+</blockquote>
+
+<p>
+Because the <tt>synchronize_rcu()</tt> on line&nbsp;14 waits for
+all pre-existing readers, any instance of <tt>thread0()</tt> that
+loads a value of zero from <tt>x</tt> must complete before
+<tt>thread1()</tt> stores to <tt>y</tt>, so that instance must
+also load a value of zero from <tt>y</tt>.
+Similarly, any instance of <tt>thread0()</tt> that loads a value of
+one from <tt>y</tt> must have started after the
+<tt>synchronize_rcu()</tt> started, and must therefore also load
+a value of one from <tt>x</tt>.
+Therefore, the outcome:
+<blockquote>
+<pre>
+(r1 == 0 &amp;&amp; r2 == 1)
+</pre>
+</blockquote>
+cannot happen.
+
+<p><a name="Quick Quiz 1"><b>Quick Quiz 1</b>:</a>
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+<br><a href="#qq1answer">Answer</a>
+
+<p>
+This scenario resembles one of the first uses of RCU in
+<a href="https://en.wikipedia.org/wiki/DYNIX">DYNIX/ptx</a>,
+which managed a distributed lock manager's transition into
+a state suitable for handling recovery from node failure,
+more or less as follows:
+
+<blockquote>
+<pre>
+ 1 #define STATE_NORMAL 0
+ 2 #define STATE_WANT_RECOVERY 1
+ 3 #define STATE_RECOVERING 2
+ 4 #define STATE_WANT_NORMAL 3
+ 5
+ 6 int state = STATE_NORMAL;
+ 7
+ 8 void do_something_dlm(void)
+ 9 {
+10 int state_snap;
+11
+12 rcu_read_lock();
+13 state_snap = READ_ONCE(state);
+14 if (state_snap == STATE_NORMAL)
+15 do_something();
+16 else
+17 do_something_carefully();
+18 rcu_read_unlock();
+19 }
+20
+21 void start_recovery(void)
+22 {
+23 WRITE_ONCE(state, STATE_WANT_RECOVERY);
+24 synchronize_rcu();
+25 WRITE_ONCE(state, STATE_RECOVERING);
+26 recovery();
+27 WRITE_ONCE(state, STATE_WANT_NORMAL);
+28 synchronize_rcu();
+29 WRITE_ONCE(state, STATE_NORMAL);
+30 }
+</pre>
+</blockquote>
+
+<p>
+The RCU read-side critical section in <tt>do_something_dlm()</tt>
+works with the <tt>synchronize_rcu()</tt> in <tt>start_recovery()</tt>
+to guarantee that <tt>do_something()</tt> never runs concurrently
+with <tt>recovery()</tt>, but with little or no synchronization
+overhead in <tt>do_something_dlm()</tt>.
+
+<p><a name="Quick Quiz 2"><b>Quick Quiz 2</b>:</a>
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+<br><a href="#qq2answer">Answer</a>
+
+<p>
+In order to avoid fatal problems such as deadlocks,
+an RCU read-side critical section must not contain calls to
+<tt>synchronize_rcu()</tt>.
+Similarly, an RCU read-side critical section must not
+contain anything that waits, directly or indirectly, on completion of
+an invocation of <tt>synchronize_rcu()</tt>.
+
+<p>
+Although RCU's grace-period guarantee is useful in and of itself, with
+<a href="https://lwn.net/Articles/573497/">quite a few use cases</a>,
+it would be good to be able to use RCU to coordinate read-side
+access to linked data structures.
+For this, the grace-period guarantee is not sufficient, as can
+be seen in function <tt>add_gp_buggy()</tt> below.
+We will look at the reader's code later, but in the meantime, just think of
+the reader as locklessly picking up the <tt>gp</tt> pointer,
+and, if the value loaded is non-<tt>NULL</tt>, locklessly accessing the
+<tt>-&gt;a</tt> and <tt>-&gt;b</tt> fields.
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 p-&gt;a = a;
+12 p-&gt;b = a;
+13 gp = p; /* ORDERING BUG */
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The problem is that both the compiler and weakly ordered CPUs are within
+their rights to reorder this code as follows:
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy_optimized(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+<b>11 gp = p; /* ORDERING BUG */
+12 p-&gt;a = a;
+13 p-&gt;b = a;</b>
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+If an RCU reader fetches <tt>gp</tt> just after
+<tt>add_gp_buggy_optimized</tt> executes line&nbsp;11,
+it will see garbage in the <tt>-&gt;a</tt> and <tt>-&gt;b</tt>
+fields.
+And this is but one of many ways in which compiler and hardware optimizations
+could cause trouble.
+Therefore, we clearly need some way to prevent the compiler and the CPU from
+reordering in this manner, which brings us to the publish-subscribe
+guarantee discussed in the next section.
+
+<h3><a name="Publish-Subscribe Guarantee">Publish/Subscribe Guarantee</a></h3>
+
+<p>
+RCU's publish-subscribe guarantee allows data to be inserted
+into a linked data structure without disrupting RCU readers.
+The updater uses <tt>rcu_assign_pointer()</tt> to insert the
+new data, and readers use <tt>rcu_dereference()</tt> to
+access data, whether new or old.
+The following shows an example of insertion:
+
+<blockquote>
+<pre>
+ 1 bool add_gp(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 p-&gt;a = a;
+12 p-&gt;b = a;
+13 rcu_assign_pointer(gp, p);
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_assign_pointer()</tt> on line&nbsp;13 is conceptually
+equivalent to a simple assignment statement, but also guarantees
+that its assignment will
+happen after the two assignments in lines&nbsp;11 and&nbsp;12,
+similar to the C11 <tt>memory_order_release</tt> store operation.
+It also prevents any number of &ldquo;interesting&rdquo; compiler
+optimizations, for example, the use of <tt>gp</tt> as a scratch
+location immediately preceding the assignment.
+
+<p><a name="Quick Quiz 3"><b>Quick Quiz 3</b>:</a>
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+<br><a href="#qq3answer">Answer</a>
+
+<p>
+It is tempting to assume that the reader need not do anything special
+to control its accesses to the RCU-protected data,
+as shown in <tt>do_something_gp_buggy()</tt> below:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 p = gp; /* OPTIMIZATIONS GALORE!!! */
+ 5 if (p) {
+ 6 do_something(p-&gt;a, p-&gt;b);
+ 7 rcu_read_unlock();
+ 8 return true;
+ 9 }
+10 rcu_read_unlock();
+11 return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+However, this temptation must be resisted because there are a
+surprisingly large number of ways that the compiler
+(to say nothing of
+<a href="https://h71000.www7.hp.com/wizard/wiz_2637.html">DEC Alpha CPUs</a>)
+can trip this code up.
+For but one example, if the compiler were short of registers, it
+might choose to refetch from <tt>gp</tt> rather than keeping
+a separate copy in <tt>p</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy_optimized(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 if (gp) { /* OPTIMIZATIONS GALORE!!! */
+<b> 5 do_something(gp-&gt;a, gp-&gt;b);</b>
+ 6 rcu_read_unlock();
+ 7 return true;
+ 8 }
+ 9 rcu_read_unlock();
+10 return false;
+11 }
+</pre>
+</blockquote>
+
+<p>
+If this function ran concurrently with a series of updates that
+replaced the current structure with a new one,
+the fetches of <tt>gp-&gt;a</tt>
+and <tt>gp-&gt;b</tt> might well come from two different structures,
+which could cause serious confusion.
+To prevent this (and much else besides), <tt>do_something_gp()</tt> uses
+<tt>rcu_dereference()</tt> to fetch from <tt>gp</tt>:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 p = rcu_dereference(gp);
+ 5 if (p) {
+ 6 do_something(p-&gt;a, p-&gt;b);
+ 7 rcu_read_unlock();
+ 8 return true;
+ 9 }
+10 rcu_read_unlock();
+11 return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_dereference()</tt> uses volatile casts and (for DEC Alpha)
+memory barriers in the Linux kernel.
+Should a
+<a href="http://www.rdrop.com/users/paulmck/RCU/consume.2015.07.13a.pdf">high-quality implementation of C11 <tt>memory_order_consume</tt> [PDF]</a>
+ever appear, then <tt>rcu_dereference()</tt> could be implemented
+as a <tt>memory_order_consume</tt> load.
+Regardless of the exact implementation, a pointer fetched by
+<tt>rcu_dereference()</tt> may not be used outside of the
+outermost RCU read-side critical section containing that
+<tt>rcu_dereference()</tt>, unless protection of
+the corresponding data element has been passed from RCU to some
+other synchronization mechanism, most commonly locking or
+<a href="https://www.kernel.org/doc/Documentation/RCU/rcuref.txt">reference counting</a>.
+
+<p>
+In short, updaters use <tt>rcu_assign_pointer()</tt> and readers
+use <tt>rcu_dereference()</tt>, and these two RCU API elements
+work together to ensure that readers have a consistent view of
+newly added data elements.
+
+<p>
+Of course, it is also necessary to remove elements from RCU-protected
+data structures, for example, using the following process:
+
+<ol>
+<li> Remove the data element from the enclosing structure.
+<li> Wait for all pre-existing RCU read-side critical sections
+ to complete (because only pre-existing readers can possibly have
+ a reference to the newly removed data element).
+<li> At this point, only the updater has a reference to the
+ newly removed data element, so it can safely reclaim
+ the data element, for example, by passing it to <tt>kfree()</tt>.
+</ol>
+
+This process is implemented by <tt>remove_gp_synchronous()</tt>:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_synchronous(void)
+ 2 {
+ 3 struct foo *p;
+ 4
+ 5 spin_lock(&amp;gp_lock);
+ 6 p = rcu_access_pointer(gp);
+ 7 if (!p) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 rcu_assign_pointer(gp, NULL);
+12 spin_unlock(&amp;gp_lock);
+13 synchronize_rcu();
+14 kfree(p);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+This function is straightforward, with line&nbsp;13 waiting for a grace
+period before line&nbsp;14 frees the old data element.
+This waiting ensures that readers will reach line&nbsp;7 of
+<tt>do_something_gp()</tt> before the data element referenced by
+<tt>p</tt> is freed.
+The <tt>rcu_access_pointer()</tt> on line&nbsp;6 is similar to
+<tt>rcu_dereference()</tt>, except that:
+
+<ol>
+<li> The value returned by <tt>rcu_access_pointer()</tt>
+ cannot be dereferenced.
+ If you want to access the value pointed to as well as
+ the pointer itself, use <tt>rcu_dereference()</tt>
+ instead of <tt>rcu_access_pointer()</tt>.
+<li> The call to <tt>rcu_access_pointer()</tt> need not be
+ protected.
+ In contrast, <tt>rcu_dereference()</tt> must either be
+ within an RCU read-side critical section or in a code
+ segment where the pointer cannot change, for example, in
+ code protected by the corresponding update-side lock.
+</ol>
+
+<p><a name="Quick Quiz 4"><b>Quick Quiz 4</b>:</a>
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+<br><a href="#qq4answer">Answer</a>
+
+<p>
+In short, RCU's publish-subscribe guarantee is provided by the combination
+of <tt>rcu_assign_pointer()</tt> and <tt>rcu_dereference()</tt>.
+This guarantee allows data elements to be safely added to RCU-protected
+linked data structures without disrupting RCU readers.
+This guarantee can be used in combination with the grace-period
+guarantee to also allow data elements to be removed from RCU-protected
+linked data structures, again without disrupting RCU readers.
+
+<p>
+This guarantee was only partially premeditated.
+DYNIX/ptx used an explicit memory barrier for publication, but had nothing
+resembling <tt>rcu_dereference()</tt> for subscription, nor did it
+have anything resembling the <tt>smp_read_barrier_depends()</tt>
+that was later subsumed into <tt>rcu_dereference()</tt>.
+The need for these operations made itself known quite suddenly at a
+late-1990s meeting with the DEC Alpha architects, back in the days when
+DEC was still a free-standing company.
+It took the Alpha architects a good hour to convince me that any sort
+of barrier would ever be needed, and it then took me a good <i>two</i> hours
+to convince them that their documentation did not make this point clear.
+More recent work with the C and C++ standards committees have provided
+much education on tricks and traps from the compiler.
+In short, compilers were much less tricky in the early 1990s, but in
+2015, don't even think about omitting <tt>rcu_dereference()</tt>!
+
+<h3><a name="Memory-Barrier Guarantees">Memory-Barrier Guarantees</a></h3>
+
+<p>
+The previous section's simple linked-data-structure scenario clearly
+demonstrates the need for RCU's stringent memory-ordering guarantees on
+systems with more than one CPU:
+
+<ol>
+<li> Each CPU that has an RCU read-side critical section that
+ begins before <tt>synchronize_rcu()</tt> starts is
+ guaranteed to execute a full memory barrier between the time
+ that the RCU read-side critical section ends and the time that
+ <tt>synchronize_rcu()</tt> returns.
+ Without this guarantee, a pre-existing RCU read-side critical section
+ might hold a reference to the newly removed <tt>struct foo</tt>
+ after the <tt>kfree()</tt> on line&nbsp;14 of
+ <tt>remove_gp_synchronous()</tt>.
+<li> Each CPU that has an RCU read-side critical section that ends
+ after <tt>synchronize_rcu()</tt> returns is guaranteed
+ to execute a full memory barrier between the time that
+ <tt>synchronize_rcu()</tt> begins and the time that the RCU
+ read-side critical section begins.
+ Without this guarantee, a later RCU read-side critical section
+ running after the <tt>kfree()</tt> on line&nbsp;14 of
+ <tt>remove_gp_synchronous()</tt> might
+ later run <tt>do_something_gp()</tt> and find the
+ newly deleted <tt>struct foo</tt>.
+<li> If the task invoking <tt>synchronize_rcu()</tt> remains
+ on a given CPU, then that CPU is guaranteed to execute a full
+ memory barrier sometime during the execution of
+ <tt>synchronize_rcu()</tt>.
+ This guarantee ensures that the <tt>kfree()</tt> on
+ line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+ execute after the removal on line&nbsp;11.
+<li> If the task invoking <tt>synchronize_rcu()</tt> migrates
+ among a group of CPUs during that invocation, then each of the
+ CPUs in that group is guaranteed to execute a full memory barrier
+ sometime during the execution of <tt>synchronize_rcu()</tt>.
+ This guarantee also ensures that the <tt>kfree()</tt> on
+ line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+ execute after the removal on
+ line&nbsp;11, but also in the case where the thread executing the
+ <tt>synchronize_rcu()</tt> migrates in the meantime.
+</ol>
+
+<p><a name="Quick Quiz 5"><b>Quick Quiz 5</b>:</a>
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+<br><a href="#qq5answer">Answer</a>
+
+<p><a name="Quick Quiz 6"><b>Quick Quiz 6</b>:</a>
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+<br><a href="#qq6answer">Answer</a>
+
+<p>
+Note that these memory-barrier requirements do not replace the fundamental
+RCU requirement that a grace period wait for all pre-existing readers.
+On the contrary, the memory barriers called out in this section must operate in
+such a way as to <i>enforce</i> this fundamental requirement.
+Of course, different implementations enforce this requirement in different
+ways, but enforce it they must.
+
+<h3><a name="RCU Primitives Guaranteed to Execute Unconditionally">RCU Primitives Guaranteed to Execute Unconditionally</a></h3>
+
+<p>
+The common-case RCU primitives are unconditional.
+They are invoked, they do their job, and they return, with no possibility
+of error, and no need to retry.
+This is a key RCU design philosophy.
+
+<p>
+However, this philosophy is pragmatic rather than pigheaded.
+If someone comes up with a good justification for a particular conditional
+RCU primitive, it might well be implemented and added.
+After all, this guarantee was reverse-engineered, not premeditated.
+The unconditional nature of the RCU primitives was initially an
+accident of implementation, and later experience with synchronization
+primitives with conditional primitives caused me to elevate this
+accident to a guarantee.
+Therefore, the justification for adding a conditional primitive to
+RCU would need to be based on detailed and compelling use cases.
+
+<h3><a name="Guaranteed Read-to-Write Upgrade">Guaranteed Read-to-Write Upgrade</a></h3>
+
+<p>
+As far as RCU is concerned, it is always possible to carry out an
+update within an RCU read-side critical section.
+For example, that RCU read-side critical section might search for
+a given data element, and then might acquire the update-side
+spinlock in order to update that element, all while remaining
+in that RCU read-side critical section.
+Of course, it is necessary to exit the RCU read-side critical section
+before invoking <tt>synchronize_rcu()</tt>, however, this
+inconvenience can be avoided through use of the
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt> API members
+described later in this document.
+
+<p><a name="Quick Quiz 7"><b>Quick Quiz 7</b>:</a>
+But how does the upgrade-to-write operation exclude other readers?
+<br><a href="#qq7answer">Answer</a>
+
+<p>
+This guarantee allows lookup code to be shared between read-side
+and update-side code, and was premeditated, appearing in the earliest
+DYNIX/ptx RCU documentation.
+
+<h2><a name="Fundamental Non-Requirements">Fundamental Non-Requirements</a></h2>
+
+<p>
+RCU provides extremely lightweight readers, and its read-side guarantees,
+though quite useful, are correspondingly lightweight.
+It is therefore all too easy to assume that RCU is guaranteeing more
+than it really is.
+Of course, the list of things that RCU does not guarantee is infinitely
+long, however, the following sections list a few non-guarantees that
+have caused confusion.
+Except where otherwise noted, these non-guarantees were premeditated.
+
+<ol>
+<li> <a href="#Readers Impose Minimal Ordering">
+ Readers Impose Minimal Ordering</a>
+<li> <a href="#Readers Do Not Exclude Updaters">
+ Readers Do Not Exclude Updaters</a>
+<li> <a href="#Updaters Only Wait For Old Readers">
+ Updaters Only Wait For Old Readers</a>
+<li> <a href="#Grace Periods Don't Partition Read-Side Critical Sections">
+ Grace Periods Don't Partition Read-Side Critical Sections</a>
+<li> <a href="#Read-Side Critical Sections Don't Partition Grace Periods">
+ Read-Side Critical Sections Don't Partition Grace Periods</a>
+<li> <a href="#Disabling Preemption Does Not Block Grace Periods">
+ Disabling Preemption Does Not Block Grace Periods</a>
+</ol>
+
+<h3><a name="Readers Impose Minimal Ordering">Readers Impose Minimal Ordering</a></h3>
+
+<p>
+Reader-side markers such as <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> provide absolutely no ordering guarantees
+except through their interaction with the grace-period APIs such as
+<tt>synchronize_rcu()</tt>.
+To see this, consider the following pair of threads:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(x, 1);
+ 5 rcu_read_unlock();
+ 6 rcu_read_lock();
+ 7 WRITE_ONCE(y, 1);
+ 8 rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13 rcu_read_lock();
+14 r1 = READ_ONCE(y);
+15 rcu_read_unlock();
+16 rcu_read_lock();
+17 r2 = READ_ONCE(x);
+18 rcu_read_unlock();
+19 }
+</pre>
+</blockquote>
+
+<p>
+After <tt>thread0()</tt> and <tt>thread1()</tt> execute
+concurrently, it is quite possible to have
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0)
+</pre>
+</blockquote>
+
+(that is, <tt>y</tt> appears to have been assigned before <tt>x</tt>),
+which would not be possible if <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> had much in the way of ordering
+properties.
+But they do not, so the CPU is within its rights
+to do significant reordering.
+This is by design: Any significant ordering constraints would slow down
+these fast-path APIs.
+
+<p><a name="Quick Quiz 8"><b>Quick Quiz 8</b>:</a>
+Can't the compiler also reorder this code?
+<br><a href="#qq8answer">Answer</a>
+
+<h3><a name="Readers Do Not Exclude Updaters">Readers Do Not Exclude Updaters</a></h3>
+
+<p>
+Neither <tt>rcu_read_lock()</tt> nor <tt>rcu_read_unlock()</tt>
+exclude updates.
+All they do is to prevent grace periods from ending.
+The following example illustrates this:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 r1 = READ_ONCE(y);
+ 5 if (r1) {
+ 6 do_something_with_nonzero_x();
+ 7 r2 = READ_ONCE(x);
+ 8 WARN_ON(!r2); /* BUG!!! */
+ 9 }
+10 rcu_read_unlock();
+11 }
+12
+13 void thread1(void)
+14 {
+15 spin_lock(&amp;my_lock);
+16 WRITE_ONCE(x, 1);
+17 WRITE_ONCE(y, 1);
+18 spin_unlock(&amp;my_lock);
+19 }
+</pre>
+</blockquote>
+
+<p>
+If the <tt>thread0()</tt> function's <tt>rcu_read_lock()</tt>
+excluded the <tt>thread1()</tt> function's update,
+the <tt>WARN_ON()</tt> could never fire.
+But the fact is that <tt>rcu_read_lock()</tt> does not exclude
+much of anything aside from subsequent grace periods, of which
+<tt>thread1()</tt> has none, so the
+<tt>WARN_ON()</tt> can and does fire.
+
+<h3><a name="Updaters Only Wait For Old Readers">Updaters Only Wait For Old Readers</a></h3>
+
+<p>
+It might be tempting to assume that after <tt>synchronize_rcu()</tt>
+completes, there are no readers executing.
+This temptation must be avoided because
+new readers can start immediately after <tt>synchronize_rcu()</tt>
+starts, and <tt>synchronize_rcu()</tt> is under no
+obligation to wait for these new readers.
+
+<p><a name="Quick Quiz 9"><b>Quick Quiz 9</b>:</a>
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+<br><a href="#qq9answer">Answer</a>
+
+<h3><a name="Grace Periods Don't Partition Read-Side Critical Sections">
+Grace Periods Don't Partition Read-Side Critical Sections</a></h3>
+
+<p>
+It is tempting to assume that if any part of one RCU read-side critical
+section precedes a given grace period, and if any part of another RCU
+read-side critical section follows that same grace period, then all of
+the first RCU read-side critical section must precede all of the second.
+However, this just isn't the case: A single grace period does not
+partition the set of RCU read-side critical sections.
+An example of this situation can be illustrated as follows, where
+<tt>x</tt>, <tt>y</tt>, and <tt>z</tt> are initially all zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 rcu_read_lock();
+19 r2 = READ_ONCE(b);
+20 r3 = READ_ONCE(c);
+21 rcu_read_unlock();
+22 }
+</pre>
+</blockquote>
+
+<p>
+It turns out that the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0 &amp;&amp; r3 == 1)
+</pre>
+</blockquote>
+
+is entirely possible.
+The following figure show how this can happen, with each circled
+<tt>QS</tt> indicating the point at which RCU recorded a
+<i>quiescent state</i> for each thread, that is, a state in which
+RCU knows that the thread cannot be in the midst of an RCU read-side
+critical section that started before the current grace period:
+
+<p><img src="GPpartitionReaders1.svg" alt="GPpartitionReaders1.svg" width="60%"></p>
+
+<p>
+If it is necessary to partition RCU read-side critical sections in this
+manner, it is necessary to use two grace periods, where the first
+grace period is known to end before the second grace period starts:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 r2 = READ_ONCE(c);
+19 synchronize_rcu();
+20 WRITE_ONCE(d, 1);
+21 }
+22
+23 void thread3(void)
+24 {
+25 rcu_read_lock();
+26 r3 = READ_ONCE(b);
+27 r4 = READ_ONCE(d);
+28 rcu_read_unlock();
+29 }
+</pre>
+</blockquote>
+
+<p>
+Here, if <tt>(r1 == 1)</tt>, then
+<tt>thread0()</tt>'s write to <tt>b</tt> must happen
+before the end of <tt>thread1()</tt>'s grace period.
+If in addition <tt>(r4 == 1)</tt>, then
+<tt>thread3()</tt>'s read from <tt>b</tt> must happen
+after the beginning of <tt>thread2()</tt>'s grace period.
+If it is also the case that <tt>(r2 == 1)</tt>, then the
+end of <tt>thread1()</tt>'s grace period must precede the
+beginning of <tt>thread2()</tt>'s grace period.
+This mean that the two RCU read-side critical sections cannot overlap,
+guaranteeing that <tt>(r3 == 1)</tt>.
+As a result, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 0 &amp;&amp; r4 == 1)
+</pre>
+</blockquote>
+
+cannot happen.
+
+<p>
+This non-requirement was also non-premeditated, but became apparent
+when studying RCU's interaction with memory ordering.
+
+<h3><a name="Read-Side Critical Sections Don't Partition Grace Periods">
+Read-Side Critical Sections Don't Partition Grace Periods</a></h3>
+
+<p>
+It is also tempting to assume that if an RCU read-side critical section
+happens between a pair of grace periods, then those grace periods cannot
+overlap.
+However, this temptation leads nowhere good, as can be illustrated by
+the following, with all variables initially zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 rcu_read_lock();
+19 WRITE_ONCE(d, 1);
+20 r2 = READ_ONCE(c);
+21 rcu_read_unlock();
+22 }
+23
+24 void thread3(void)
+25 {
+26 r3 = READ_ONCE(d);
+27 synchronize_rcu();
+28 WRITE_ONCE(e, 1);
+29 }
+30
+31 void thread4(void)
+32 {
+33 rcu_read_lock();
+34 r4 = READ_ONCE(b);
+35 r5 = READ_ONCE(e);
+36 rcu_read_unlock();
+37 }
+</pre>
+</blockquote>
+
+<p>
+In this case, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 1 &amp;&amp; r4 == 0 &amp&amp; r5 == 1)
+</pre>
+</blockquote>
+
+is entirely possible, as illustrated below:
+
+<p><img src="ReadersPartitionGP1.svg" alt="ReadersPartitionGP1.svg" width="100%"></p>
+
+<p>
+Again, an RCU read-side critical section can overlap almost all of a
+given grace period, just so long as it does not overlap the entire
+grace period.
+As a result, an RCU read-side critical section cannot partition a pair
+of RCU grace periods.
+
+<p><a name="Quick Quiz 10"><b>Quick Quiz 10</b>:</a>
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+<br><a href="#qq10answer">Answer</a>
+
+<h3><a name="Disabling Preemption Does Not Block Grace Periods">
+Disabling Preemption Does Not Block Grace Periods</a></h3>
+
+<p>
+There was a time when disabling preemption on any given CPU would block
+subsequent grace periods.
+However, this was an accident of implementation and is not a requirement.
+And in the current Linux-kernel implementation, disabling preemption
+on a given CPU in fact does not block grace periods, as Oleg Nesterov
+<a href="https://lkml.kernel.org/g/20150614193825.GA19582@redhat.com">demonstrated</a>.
+
+<p>
+If you need a preempt-disable region to block grace periods, you need to add
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>, for example
+as follows:
+
+<blockquote>
+<pre>
+ 1 preempt_disable();
+ 2 rcu_read_lock();
+ 3 do_something();
+ 4 rcu_read_unlock();
+ 5 preempt_enable();
+ 6
+ 7 /* Spinlocks implicitly disable preemption. */
+ 8 spin_lock(&amp;mylock);
+ 9 rcu_read_lock();
+10 do_something();
+11 rcu_read_unlock();
+12 spin_unlock(&amp;mylock);
+</pre>
+</blockquote>
+
+<p>
+In theory, you could enter the RCU read-side critical section first,
+but it is more efficient to keep the entire RCU read-side critical
+section contained in the preempt-disable region as shown above.
+Of course, RCU read-side critical sections that extend outside of
+preempt-disable regions will work correctly, but such critical sections
+can be preempted, which forces <tt>rcu_read_unlock()</tt> to do
+more work.
+And no, this is <i>not</i> an invitation to enclose all of your RCU
+read-side critical sections within preempt-disable regions, because
+doing so would degrade real-time response.
+
+<p>
+This non-requirement appeared with preemptible RCU.
+If you need a grace period that waits on non-preemptible code regions, use
+<a href="#Sched Flavor">RCU-sched</a>.
+
+<h2><a name="Parallelism Facts of Life">Parallelism Facts of Life</a></h2>
+
+<p>
+These parallelism facts of life are by no means specific to RCU, but
+the RCU implementation must abide by them.
+They therefore bear repeating:
+
+<ol>
+<li> Any CPU or task may be delayed at any time,
+ and any attempts to avoid these delays by disabling
+ preemption, interrupts, or whatever are completely futile.
+ This is most obvious in preemptible user-level
+ environments and in virtualized environments (where
+ a given guest OS's VCPUs can be preempted at any time by
+ the underlying hypervisor), but can also happen in bare-metal
+ environments due to ECC errors, NMIs, and other hardware
+ events.
+ Although a delay of more than about 20 seconds can result
+ in splats, the RCU implementation is obligated to use
+ algorithms that can tolerate extremely long delays, but where
+ &ldquo;extremely long&rdquo; is not long enough to allow
+ wrap-around when incrementing a 64-bit counter.
+<li> Both the compiler and the CPU can reorder memory accesses.
+ Where it matters, RCU must use compiler directives and
+ memory-barrier instructions to preserve ordering.
+<li> Conflicting writes to memory locations in any given cache line
+ will result in expensive cache misses.
+ Greater numbers of concurrent writes and more-frequent
+ concurrent writes will result in more dramatic slowdowns.
+ RCU is therefore obligated to use algorithms that have
+ sufficient locality to avoid significant performance and
+ scalability problems.
+<li> As a rough rule of thumb, only one CPU's worth of processing
+ may be carried out under the protection of any given exclusive
+ lock.
+ RCU must therefore use scalable locking designs.
+<li> Counters are finite, especially on 32-bit systems.
+ RCU's use of counters must therefore tolerate counter wrap,
+ or be designed such that counter wrap would take way more
+ time than a single system is likely to run.
+ An uptime of ten years is quite possible, a runtime
+ of a century much less so.
+ As an example of the latter, RCU's dyntick-idle nesting counter
+ allows 54 bits for interrupt nesting level (this counter
+ is 64 bits even on a 32-bit system).
+ Overflowing this counter requires 2<sup>54</sup>
+ half-interrupts on a given CPU without that CPU ever going idle.
+ If a half-interrupt happened every microsecond, it would take
+ 570 years of runtime to overflow this counter, which is currently
+ believed to be an acceptably long time.
+<li> Linux systems can have thousands of CPUs running a single
+ Linux kernel in a single shared-memory environment.
+ RCU must therefore pay close attention to high-end scalability.
+</ol>
+
+<p>
+This last parallelism fact of life means that RCU must pay special
+attention to the preceding facts of life.
+The idea that Linux might scale to systems with thousands of CPUs would
+have been met with some skepticism in the 1990s, but these requirements
+would have otherwise have been unsurprising, even in the early 1990s.
+
+<h2><a name="Quality-of-Implementation Requirements">Quality-of-Implementation Requirements</a></h2>
+
+<p>
+These sections list quality-of-implementation requirements.
+Although an RCU implementation that ignores these requirements could
+still be used, it would likely be subject to limitations that would
+make it inappropriate for industrial-strength production use.
+Classes of quality-of-implementation requirements are as follows:
+
+<ol>
+<li> <a href="#Specialization">Specialization</a>
+<li> <a href="#Performance and Scalability">Performance and Scalability</a>
+<li> <a href="#Composability">Composability</a>
+<li> <a href="#Corner Cases">Corner Cases</a>
+</ol>
+
+<p>
+These classes is covered in the following sections.
+
+<h3><a name="Specialization">Specialization</a></h3>
+
+<p>
+RCU is and always has been intended primarily for read-mostly situations, as
+illustrated by the following figure.
+This means that RCU's read-side primitives are optimized, often at the
+expense of its update-side primitives.
+
+<p><img src="RCUApplicability.svg" alt="RCUApplicability.svg" width="70%"></p>
+
+<p>
+This focus on read-mostly situations means that RCU must interoperate
+with other synchronization primitives.
+For example, the <tt>add_gp()</tt> and <tt>remove_gp_synchronous()</tt>
+examples discussed earlier use RCU to protect readers and locking to
+coordinate updaters.
+However, the need extends much farther, requiring that a variety of
+synchronization primitives be legal within RCU read-side critical sections,
+including spinlocks, sequence locks, atomic operations, reference
+counters, and memory barriers.
+
+<p><a name="Quick Quiz 11"><b>Quick Quiz 11</b>:</a>
+What about sleeping locks?
+<br><a href="#qq11answer">Answer</a>
+
+<p>
+It often comes as a surprise that many algorithms do not require a
+consistent view of data, but many can function in that mode,
+with network routing being the poster child.
+Internet routing algorithms take significant time to propagate
+updates, so that by the time an update arrives at a given system,
+that system has been sending network traffic the wrong way for
+a considerable length of time.
+Having a few threads continue to send traffic the wrong way for a
+few more milliseconds is clearly not a problem: In the worst case,
+TCP retransmissions will eventually get the data where it needs to go.
+In general, when tracking the state of the universe outside of the
+computer, some level of inconsistency must be tolerated due to
+speed-of-light delays if nothing else.
+
+<p>
+Furthermore, uncertainty about external state is inherent in many cases.
+For example, a pair of veternarians might use heartbeat to determine
+whether or not a given cat was alive.
+But how long should they wait after the last heartbeat to decide that
+the cat is in fact dead?
+Waiting less than 400 milliseconds makes no sense because this would
+mean that a relaxed cat would be considered to cycle between death
+and life more than 100 times per minute.
+Moreover, just as with human beings, a cat's heart might stop for
+some period of time, so the exact wait period is a judgment call.
+One of our pair of veternarians might wait 30 seconds before pronouncing
+the cat dead, while the other might insist on waiting a full minute.
+The two veternarians would then disagree on the state of the cat during
+the final 30 seconds of the minute following the last heartbeat, as
+fancifully illustrated below:
+
+<p><img src="2013-08-is-it-dead.png" alt="2013-08-is-it-dead.png" width="431"></p>
+
+<p>
+Interestingly enough, this same situation applies to hardware.
+When push comes to shove, how do we tell whether or not some
+external server has failed?
+We send messages to it periodically, and declare it failed if we
+don't receive a response within a given period of time.
+Policy decisions can usually tolerate short
+periods of inconsistency.
+The policy was decided some time ago, and is only now being put into
+effect, so a few milliseconds of delay is normally inconsequential.
+
+<p>
+However, there are algorithms that absolutely must see consistent data.
+For example, the translation between a user-level SystemV semaphore
+ID to the corresponding in-kernel data structure is protected by RCU,
+but it is absolutely forbidden to update a semaphore that has just been
+removed.
+In the Linux kernel, this need for consistency is accommodated by acquiring
+spinlocks located in the in-kernel data structure from within
+the RCU read-side critical section, and this is indicated by the
+green box in the figure above.
+Many other techniques may be used, and are in fact used within the
+Linux kernel.
+
+<p>
+In short, RCU is not required to maintain consistency, and other
+mechanisms may be used in concert with RCU when consistency is required.
+RCU's specialization allows it to do its job extremely well, and its
+ability to interoperate with other synchronization mechanisms allows
+the right mix of synchronization tools to be used for a given job.
+
+<h3><a name="Performance and Scalability">Performance and Scalability</a></h3>
+
+<p>
+Energy efficiency is a critical component of performance today,
+and Linux-kernel RCU implementations must therefore avoid unnecessarily
+awakening idle CPUs.
+I cannot claim that this requirement was premeditated.
+In fact, I learned of it during a telephone conversation in which I
+was given &ldquo;frank and open&rdquo; feedback on the importance
+of energy efficiency in battery-powered systems and on specific
+energy-efficiency shortcomings of the Linux-kernel RCU implementation.
+In my experience, the battery-powered embedded community will consider
+any unnecessary wakeups to be extremely unfriendly acts.
+So much so that mere Linux-kernel-mailing-list posts are
+insufficient to vent their ire.
+
+<p>
+Memory consumption is not particularly important for in most
+situations, and has become decreasingly
+so as memory sizes have expanded and memory
+costs have plummeted.
+However, as I learned from Matt Mackall's
+<a href="http://elinux.org/Linux_Tiny-FAQ">bloatwatch</a>
+efforts, memory footprint is critically important on single-CPU systems with
+non-preemptible (<tt>CONFIG_PREEMPT=n</tt>) kernels, and thus
+<a href="https://lkml.kernel.org/g/20090113221724.GA15307@linux.vnet.ibm.com">tiny RCU</a>
+was born.
+Josh Triplett has since taken over the small-memory banner with his
+<a href="https://tiny.wiki.kernel.org/">Linux kernel tinification</a>
+project, which resulted in
+<a href="#Sleepable RCU">SRCU</a>
+becoming optional for those kernels not needing it.
+
+<p>
+The remaining performance requirements are, for the most part,
+unsurprising.
+For example, in keeping with RCU's read-side specialization,
+<tt>rcu_dereference()</tt> should have negligible overhead (for
+example, suppression of a few minor compiler optimizations).
+Similarly, in non-preemptible environments, <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have exactly zero overhead.
+
+<p>
+In preemptible environments, in the case where the RCU read-side
+critical section was not preempted (as will be the case for the
+highest-priority real-time process), <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have minimal overhead.
+In particular, they should not contain atomic read-modify-write
+operations, memory-barrier instructions, preemption disabling,
+interrupt disabling, or backwards branches.
+However, in the case where the RCU read-side critical section was preempted,
+<tt>rcu_read_unlock()</tt> may acquire spinlocks and disable interrupts.
+This is why it is better to nest an RCU read-side critical section
+within a preempt-disable region than vice versa, at least in cases
+where that critical section is short enough to avoid unduly degrading
+real-time latencies.
+
+<p>
+The <tt>synchronize_rcu()</tt> grace-period-wait primitive is
+optimized for throughput.
+It may therefore incur several milliseconds of latency in addition to
+the duration of the longest RCU read-side critical section.
+On the other hand, multiple concurrent invocations of
+<tt>synchronize_rcu()</tt> are required to use batching optimizations
+so that they can be satisfied by a single underlying grace-period-wait
+operation.
+For example, in the Linux kernel, it is not unusual for a single
+grace-period-wait operation to serve more than
+<a href="https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response">1,000 separate invocations</a>
+of <tt>synchronize_rcu()</tt>, thus amortizing the per-invocation
+overhead down to nearly zero.
+However, the grace-period optimization is also required to avoid
+measurable degradation of real-time scheduling and interrupt latencies.
+
+<p>
+In some cases, the multi-millisecond <tt>synchronize_rcu()</tt>
+latencies are unacceptable.
+In these cases, <tt>synchronize_rcu_expedited()</tt> may be used
+instead, reducing the grace-period latency down to a few tens of
+microseconds on small systems, at least in cases where the RCU read-side
+critical sections are short.
+There are currently no special latency requirements for
+<tt>synchronize_rcu_expedited()</tt> on large systems, but,
+consistent with the empirical nature of the RCU specification,
+that is subject to change.
+However, there most definitely are scalability requirements:
+A storm of <tt>synchronize_rcu_expedited()</tt> invocations on 4096
+CPUs should at least make reasonable forward progress.
+In return for its shorter latencies, <tt>synchronize_rcu_expedited()</tt>
+is permitted to impose modest degradation of real-time latency
+on non-idle online CPUs.
+That said, it will likely be necessary to take further steps to reduce this
+degradation, hopefully to roughly that of a scheduling-clock interrupt.
+
+<p>
+There are a number of situations where even
+<tt>synchronize_rcu_expedited()</tt>'s reduced grace-period
+latency is unacceptable.
+In these situations, the asynchronous <tt>call_rcu()</tt> can be
+used in place of <tt>synchronize_rcu()</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2 int a;
+ 3 int b;
+ 4 struct rcu_head rh;
+ 5 };
+ 6
+ 7 static void remove_gp_cb(struct rcu_head *rhp)
+ 8 {
+ 9 struct foo *p = container_of(rhp, struct foo, rh);
+10
+11 kfree(p);
+12 }
+13
+14 bool remove_gp_asynchronous(void)
+15 {
+16 struct foo *p;
+17
+18 spin_lock(&amp;gp_lock);
+19 p = rcu_dereference(gp);
+20 if (!p) {
+21 spin_unlock(&amp;gp_lock);
+22 return false;
+23 }
+24 rcu_assign_pointer(gp, NULL);
+25 call_rcu(&amp;p-&gt;rh, remove_gp_cb);
+26 spin_unlock(&amp;gp_lock);
+27 return true;
+28 }
+</pre>
+</blockquote>
+
+<p>
+A definition of <tt>struct foo</tt> is finally needed, and appears
+on lines&nbsp;1-5.
+The function <tt>remove_gp_cb()</tt> is passed to <tt>call_rcu()</tt>
+on line&nbsp;25, and will be invoked after the end of a subsequent
+grace period.
+This gets the same effect as <tt>remove_gp_synchronous()</tt>,
+but without forcing the updater to wait for a grace period to elapse.
+The <tt>call_rcu()</tt> function may be used in a number of
+situations where neither <tt>synchronize_rcu()</tt> nor
+<tt>synchronize_rcu_expedited()</tt> would be legal,
+including within preempt-disable code, <tt>local_bh_disable()</tt> code,
+interrupt-disable code, and interrupt handlers.
+However, even <tt>call_rcu()</tt> is illegal within NMI handlers.
+The callback function (<tt>remove_gp_cb()</tt> in this case) will be
+executed within softirq (software interrupt) environment within the
+Linux kernel,
+either within a real softirq handler or under the protection
+of <tt>local_bh_disable()</tt>.
+In both the Linux kernel and in userspace, it is bad practice to
+write an RCU callback function that takes too long.
+Long-running operations should be relegated to separate threads or
+(in the Linux kernel) workqueues.
+
+<p><a name="Quick Quiz 12"><b>Quick Quiz 12</b>:</a>
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+<br><a href="#qq12answer">Answer</a>
+
+<p>
+However, all that <tt>remove_gp_cb()</tt> is doing is
+invoking <tt>kfree()</tt> on the data element.
+This is a common idiom, and is supported by <tt>kfree_rcu()</tt>,
+which allows &ldquo;fire and forget&rdquo; operation as shown below:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2 int a;
+ 3 int b;
+ 4 struct rcu_head rh;
+ 5 };
+ 6
+ 7 bool remove_gp_faf(void)
+ 8 {
+ 9 struct foo *p;
+10
+11 spin_lock(&amp;gp_lock);
+12 p = rcu_dereference(gp);
+13 if (!p) {
+14 spin_unlock(&amp;gp_lock);
+15 return false;
+16 }
+17 rcu_assign_pointer(gp, NULL);
+18 kfree_rcu(p, rh);
+19 spin_unlock(&amp;gp_lock);
+20 return true;
+21 }
+</pre>
+</blockquote>
+
+<p>
+Note that <tt>remove_gp_faf()</tt> simply invokes
+<tt>kfree_rcu()</tt> and proceeds, without any need to pay any
+further attention to the subsequent grace period and <tt>kfree()</tt>.
+It is permissible to invoke <tt>kfree_rcu()</tt> from the same
+environments as for <tt>call_rcu()</tt>.
+Interestingly enough, DYNIX/ptx had the equivalents of
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>, but not
+<tt>synchronize_rcu()</tt>.
+This was due to the fact that RCU was not heavily used within DYNIX/ptx,
+so the very few places that needed something like
+<tt>synchronize_rcu()</tt> simply open-coded it.
+
+<p><a name="Quick Quiz 13"><b>Quick Quiz 13</b>:</a>
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+<br><a href="#qq13answer">Answer</a>
+
+<p>
+But what if the updater must wait for the completion of code to be
+executed after the end of the grace period, but has other tasks
+that can be carried out in the meantime?
+The polling-style <tt>get_state_synchronize_rcu()</tt> and
+<tt>cond_synchronize_rcu()</tt> functions may be used for this
+purpose, as shown below:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_poll(void)
+ 2 {
+ 3 struct foo *p;
+ 4 unsigned long s;
+ 5
+ 6 spin_lock(&amp;gp_lock);
+ 7 p = rcu_access_pointer(gp);
+ 8 if (!p) {
+ 9 spin_unlock(&amp;gp_lock);
+10 return false;
+11 }
+12 rcu_assign_pointer(gp, NULL);
+13 spin_unlock(&amp;gp_lock);
+14 s = get_state_synchronize_rcu();
+15 do_something_while_waiting();
+16 cond_synchronize_rcu(s);
+17 kfree(p);
+18 return true;
+19 }
+</pre>
+</blockquote>
+
+<p>
+On line&nbsp;14, <tt>get_state_synchronize_rcu()</tt> obtains a
+&ldquo;cookie&rdquo; from RCU,
+then line&nbsp;15 carries out other tasks,
+and finally, line&nbsp;16 returns immediately if a grace period has
+elapsed in the meantime, but otherwise waits as required.
+The need for <tt>get_state_synchronize_rcu</tt> and
+<tt>cond_synchronize_rcu()</tt> has appeared quite recently,
+so it is too early to tell whether they will stand the test of time.
+
+<p>
+RCU thus provides a range of tools to allow updaters to strike the
+required tradeoff between latency, flexibility and CPU overhead.
+
+<h3><a name="Composability">Composability</a></h3>
+
+<p>
+Composability has received much attention in recent years, perhaps in part
+due to the collision of multicore hardware with object-oriented techniques
+designed in single-threaded environments for single-threaded use.
+And in theory, RCU read-side critical sections may be composed, and in
+fact may be nested arbitrarily deeply.
+In practice, as with all real-world implementations of composable
+constructs, there are limitations.
+
+<p>
+Implementations of RCU for which <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> generate no code, such as
+Linux-kernel RCU when <tt>CONFIG_PREEMPT=n</tt>, can be
+nested arbitrarily deeply.
+After all, there is no overhead.
+Except that if all these instances of <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> are visible to the compiler,
+compilation will eventually fail due to exhausting memory,
+mass storage, or user patience, whichever comes first.
+If the nesting is not visible to the compiler, as is the case with
+mutually recursive functions each in its own translation unit,
+stack overflow will result.
+If the nesting takes the form of loops, either the control variable
+will overflow or (in the Linux kernel) you will get an RCU CPU stall warning.
+Nevertheless, this class of RCU implementations is one
+of the most composable constructs in existence.
+
+<p>
+RCU implementations that explicitly track nesting depth
+are limited by the nesting-depth counter.
+For example, the Linux kernel's preemptible RCU limits nesting to
+<tt>INT_MAX</tt>.
+This should suffice for almost all practical purposes.
+That said, a consecutive pair of RCU read-side critical sections
+between which there is an operation that waits for a grace period
+cannot be enclosed in another RCU read-side critical section.
+This is because it is not legal to wait for a grace period within
+an RCU read-side critical section: To do so would result either
+in deadlock or
+in RCU implicitly splitting the enclosing RCU read-side critical
+section, neither of which is conducive to a long-lived and prosperous
+kernel.
+
+<p>
+It is worth noting that RCU is not alone in limiting composability.
+For example, many transactional-memory implementations prohibit
+composing a pair of transactions separated by an irrevocable
+operation (for example, a network receive operation).
+For another example, lock-based critical sections can be composed
+surprisingly freely, but only if deadlock is avoided.
+
+<p>
+In short, although RCU read-side critical sections are highly composable,
+care is required in some situations, just as is the case for any other
+composable synchronization mechanism.
+
+<h3><a name="Corner Cases">Corner Cases</a></h3>
+
+<p>
+A given RCU workload might have an endless and intense stream of
+RCU read-side critical sections, perhaps even so intense that there
+was never a point in time during which there was not at least one
+RCU read-side critical section in flight.
+RCU cannot allow this situation to block grace periods: As long as
+all the RCU read-side critical sections are finite, grace periods
+must also be finite.
+
+<p>
+That said, preemptible RCU implementations could potentially result
+in RCU read-side critical sections being preempted for long durations,
+which has the effect of creating a long-duration RCU read-side
+critical section.
+This situation can arise only in heavily loaded systems, but systems using
+real-time priorities are of course more vulnerable.
+Therefore, RCU priority boosting is provided to help deal with this
+case.
+That said, the exact requirements on RCU priority boosting will likely
+evolve as more experience accumulates.
+
+<p>
+Other workloads might have very high update rates.
+Although one can argue that such workloads should instead use
+something other than RCU, the fact remains that RCU must
+handle such workloads gracefully.
+This requirement is another factor driving batching of grace periods,
+but it is also the driving force behind the checks for large numbers
+of queued RCU callbacks in the <tt>call_rcu()</tt> code path.
+Finally, high update rates should not delay RCU read-side critical
+sections, although some read-side delays can occur when using
+<tt>synchronize_rcu_expedited()</tt>, courtesy of this function's use
+of <tt>try_stop_cpus()</tt>.
+(In the future, <tt>synchronize_rcu_expedited()</tt> will be
+converted to use lighter-weight inter-processor interrupts (IPIs),
+but this will still disturb readers, though to a much smaller degree.)
+
+<p>
+Although all three of these corner cases were understood in the early
+1990s, a simple user-level test consisting of <tt>close(open(path))</tt>
+in a tight loop
+in the early 2000s suddenly provided a much deeper appreciation of the
+high-update-rate corner case.
+This test also motivated addition of some RCU code to react to high update
+rates, for example, if a given CPU finds itself with more than 10,000
+RCU callbacks queued, it will cause RCU to take evasive action by
+more aggressively starting grace periods and more aggressively forcing
+completion of grace-period processing.
+This evasive action causes the grace period to complete more quickly,
+but at the cost of restricting RCU's batching optimizations, thus
+increasing the CPU overhead incurred by that grace period.
+
+<h2><a name="Software-Engineering Requirements">
+Software-Engineering Requirements</a></h2>
+
+<p>
+Between Murphy's Law and &ldquo;To err is human&rdquo;, it is necessary to
+guard against mishaps and misuse:
+
+<ol>
+<li> It is all too easy to forget to use <tt>rcu_read_lock()</tt>
+ everywhere that it is needed, so kernels built with
+ <tt>CONFIG_PROVE_RCU=y</tt> will spat if
+ <tt>rcu_dereference()</tt> is used outside of an
+ RCU read-side critical section.
+ Update-side code can use <tt>rcu_dereference_protected()</tt>,
+ which takes a
+ <a href="https://lwn.net/Articles/371986/">lockdep expression</a>
+ to indicate what is providing the protection.
+ If the indicated protection is not provided, a lockdep splat
+ is emitted.
+
+ <p>
+ Code shared between readers and updaters can use
+ <tt>rcu_dereference_check()</tt>, which also takes a
+ lockdep expression, and emits a lockdep splat if neither
+ <tt>rcu_read_lock()</tt> nor the indicated protection
+ is in place.
+ In addition, <tt>rcu_dereference_raw()</tt> is used in those
+ (hopefully rare) cases where the required protection cannot
+ be easily described.
+ Finally, <tt>rcu_read_lock_held()</tt> is provided to
+ allow a function to verify that it has been invoked within
+ an RCU read-side critical section.
+ I was made aware of this set of requirements shortly after Thomas
+ Gleixner audited a number of RCU uses.
+<li> A given function might wish to check for RCU-related preconditions
+ upon entry, before using any other RCU API.
+ The <tt>rcu_lockdep_assert()</tt> does this job,
+ asserting the expression in kernels having lockdep enabled
+ and doing nothing otherwise.
+<li> It is also easy to forget to use <tt>rcu_assign_pointer()</tt>
+ and <tt>rcu_dereference()</tt>, perhaps (incorrectly)
+ substituting a simple assignment.
+ To catch this sort of error, a given RCU-protected pointer may be
+ tagged with <tt>__rcu</tt>, after which running sparse
+ with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt> will complain
+ about simple-assignment accesses to that pointer.
+ Arnd Bergmann made me aware of this requirement, and also
+ supplied the needed
+ <a href="https://lwn.net/Articles/376011/">patch series</a>.
+<li> Kernels built with <tt>CONFIG_DEBUG_OBJECTS_RCU_HEAD=y</tt>
+ will splat if a data element is passed to <tt>call_rcu()</tt>
+ twice in a row, without a grace period in between.
+ (This error is similar to a double free.)
+ The corresponding <tt>rcu_head</tt> structures that are
+ dynamically allocated are automatically tracked, but
+ <tt>rcu_head</tt> structures allocated on the stack
+ must be initialized with <tt>init_rcu_head_on_stack()</tt>
+ and cleaned up with <tt>destroy_rcu_head_on_stack()</tt>.
+ Similarly, statically allocated non-stack <tt>rcu_head</tt>
+ structures must be initialized with <tt>init_rcu_head()</tt>
+ and cleaned up with <tt>destroy_rcu_head()</tt>.
+ Mathieu Desnoyers made me aware of this requirement, and also
+ supplied the needed
+ <a href="https://lkml.kernel.org/g/20100319013024.GA28456@Krystal">patch</a>.
+<li> An infinite loop in an RCU read-side critical section will
+ eventually trigger an RCU CPU stall warning splat, with
+ the duration of &ldquo;eventually&rdquo; being controlled by the
+ <tt>RCU_CPU_STALL_TIMEOUT</tt> <tt>Kconfig</tt> option, or,
+ alternatively, by the
+ <tt>rcupdate.rcu_cpu_stall_timeout</tt> boot/sysfs
+ parameter.
+ However, RCU is not obligated to produce this splat
+ unless there is a grace period waiting on that particular
+ RCU read-side critical section.
+ <p>
+ Some extreme workloads might intentionally delay
+ RCU grace periods, and systems running those workloads can
+ be booted with <tt>rcupdate.rcu_cpu_stall_suppress</tt>
+ to suppress the splats.
+ This kernel parameter may also be set via <tt>sysfs</tt>.
+ Furthermore, RCU CPU stall warnings are counter-productive
+ during sysrq dumps and during panics.
+ RCU therefore supplies the <tt>rcu_sysrq_start()</tt> and
+ <tt>rcu_sysrq_end()</tt> API members to be called before
+ and after long sysrq dumps.
+ RCU also supplies the <tt>rcu_panic()</tt> notifier that is
+ automatically invoked at the beginning of a panic to suppress
+ further RCU CPU stall warnings.
+
+ <p>
+ This requirement made itself known in the early 1990s, pretty
+ much the first time that it was necessary to debug a CPU stall.
+ That said, the initial implementation in DYNIX/ptx was quite
+ generic in comparison with that of Linux.
+<li> Although it would be very good to detect pointers leaking out
+ of RCU read-side critical sections, there is currently no
+ good way of doing this.
+ One complication is the need to distinguish between pointers
+ leaking and pointers that have been handed off from RCU to
+ some other synchronization mechanism, for example, reference
+ counting.
+<li> In kernels built with <tt>CONFIG_RCU_TRACE=y</tt>, RCU-related
+ information is provided via both debugfs and event tracing.
+<li> Open-coded use of <tt>rcu_assign_pointer()</tt> and
+ <tt>rcu_dereference()</tt> to create typical linked
+ data structures can be surprisingly error-prone.
+ Therefore, RCU-protected
+ <a href="https://lwn.net/Articles/609973/#RCU List APIs">linked lists</a>
+ and, more recently, RCU-protected
+ <a href="https://lwn.net/Articles/612100/">hash tables</a>
+ are available.
+ Many other special-purpose RCU-protected data structures are
+ available in the Linux kernel and the userspace RCU library.
+<li> Some linked structures are created at compile time, but still
+ require <tt>__rcu</tt> checking.
+ The <tt>RCU_POINTER_INITIALIZER()</tt> macro serves this
+ purpose.
+<li> It is not necessary to use <tt>rcu_assign_pointer()</tt>
+ when creating linked structures that are to be published via
+ a single external pointer.
+ The <tt>RCU_INIT_POINTER()</tt> macro is provided for
+ this task and also for assigning <tt>NULL</tt> pointers
+ at runtime.
+</ol>
+
+<p>
+This not a hard-and-fast list: RCU's diagnostic capabilities will
+continue to be guided by the number and type of usage bugs found
+in real-world RCU usage.
+
+<h2><a name="Linux Kernel Complications">Linux Kernel Complications</a></h2>
+
+<p>
+The Linux kernel provides an interesting environment for all kinds of
+software, including RCU.
+Some of the relevant points of interest are as follows:
+
+<ol>
+<li> <a href="#Configuration">Configuration</a>.
+<li> <a href="#Firmware Interface">Firmware Interface</a>.
+<li> <a href="#Early Boot">Early Boot</a>.
+<li> <a href="#Interrupts and NMIs">
+ Interrupts and non-maskable interrupts (NMIs)</a>.
+<li> <a href="#Loadable Modules">Loadable Modules</a>.
+<li> <a href="#Hotplug CPU">Hotplug CPU</a>.
+<li> <a href="#Scheduler and RCU">Scheduler and RCU</a>.
+<li> <a href="#Tracing and RCU">Tracing and RCU</a>.
+<li> <a href="#Energy Efficiency">Energy Efficiency</a>.
+<li> <a href="#Memory Efficiency">Memory Efficiency</a>.
+<li> <a href="#Performance, Scalability, Response Time, and Reliability">
+ Performance, Scalability, Response Time, and Reliability</a>.
+</ol>
+
+<p>
+This list is probably incomplete, but it does give a feel for the
+most notable Linux-kernel complications.
+Each of the following sections covers one of the above topics.
+
+<h3><a name="Configuration">Configuration</a></h3>
+
+<p>
+RCU's goal is automatic configuration, so that almost nobody
+needs to worry about RCU's <tt>Kconfig</tt> options.
+And for almost all users, RCU does in fact work well
+&ldquo;out of the box.&rdquo;
+
+<p>
+However, there are specialized use cases that are handled by
+kernel boot parameters and <tt>Kconfig</tt> options.
+Unfortunately, the <tt>Kconfig</tt> system will explicitly ask users
+about new <tt>Kconfig</tt> options, which requires almost all of them
+be hidden behind a <tt>CONFIG_RCU_EXPERT</tt> <tt>Kconfig</tt> option.
+
+<p>
+This all should be quite obvious, but the fact remains that
+Linus Torvalds recently had to
+<a href="https://lkml.kernel.org/g/CA+55aFy4wcCwaL4okTs8wXhGZ5h-ibecy_Meg9C4MNQrUnwMcg@mail.gmail.com">remind</a>
+me of this requirement.
+
+<h3><a name="Firmware Interface">Firmware Interface</a></h3>
+
+<p>
+In many cases, kernel obtains information about the system from the
+firmware, and sometimes things are lost in translation.
+Or the translation is accurate, but the original message is bogus.
+
+<p>
+For example, some systems' firmware overreports the number of CPUs,
+sometimes by a large factor.
+If RCU naively believed the firmware, as it used to do,
+it would create too many per-CPU kthreads.
+Although the resulting system will still run correctly, the extra
+kthreads needlessly consume memory and can cause confusion
+when they show up in <tt>ps</tt> listings.
+
+<p>
+RCU must therefore wait for a given CPU to actually come online before
+it can allow itself to believe that the CPU actually exists.
+The resulting &ldquo;ghost CPUs&rdquo; (which are never going to
+come online) cause a number of
+<a href="https://paulmck.livejournal.com/37494.html">interesting complications</a>.
+
+<h3><a name="Early Boot">Early Boot</a></h3>
+
+<p>
+The Linux kernel's boot sequence is an interesting process,
+and RCU is used early, even before <tt>rcu_init()</tt>
+is invoked.
+In fact, a number of RCU's primitives can be used as soon as the
+initial task's <tt>task_struct</tt> is available and the
+boot CPU's per-CPU variables are set up.
+The read-side primitives (<tt>rcu_read_lock()</tt>,
+<tt>rcu_read_unlock()</tt>, <tt>rcu_dereference()</tt>,
+and <tt>rcu_access_pointer()</tt>) will operate normally very early on,
+as will <tt>rcu_assign_pointer()</tt>.
+
+<p>
+Although <tt>call_rcu()</tt> may be invoked at any
+time during boot, callbacks are not guaranteed to be invoked until after
+the scheduler is fully up and running.
+This delay in callback invocation is due to the fact that RCU does not
+invoke callbacks until it is fully initialized, and this full initialization
+cannot occur until after the scheduler has initialized itself to the
+point where RCU can spawn and run its kthreads.
+In theory, it would be possible to invoke callbacks earlier,
+however, this is not a panacea because there would be severe restrictions
+on what operations those callbacks could invoke.
+
+<p>
+Perhaps surprisingly, <tt>synchronize_rcu()</tt>,
+<a href="#Bottom-Half Flavor"><tt>synchronize_rcu_bh()</tt></a>
+(<a href="#Bottom-Half Flavor">discussed below</a>),
+and
+<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a>
+will all operate normally
+during very early boot, the reason being that there is only one CPU
+and preemption is disabled.
+This means that the call <tt>synchronize_rcu()</tt> (or friends)
+itself is a quiescent
+state and thus a grace period, so the early-boot implementation can
+be a no-op.
+
+<p>
+Both <tt>synchronize_rcu_bh()</tt> and <tt>synchronize_sched()</tt>
+continue to operate normally through the remainder of boot, courtesy
+of the fact that preemption is disabled across their RCU read-side
+critical sections and also courtesy of the fact that there is still
+only one CPU.
+However, once the scheduler starts initializing, preemption is enabled.
+There is still only a single CPU, but the fact that preemption is enabled
+means that the no-op implementation of <tt>synchronize_rcu()</tt> no
+longer works in <tt>CONFIG_PREEMPT=y</tt> kernels.
+Therefore, as soon as the scheduler starts initializing, the early-boot
+fastpath is disabled.
+This means that <tt>synchronize_rcu()</tt> switches to its runtime
+mode of operation where it posts callbacks, which in turn means that
+any call to <tt>synchronize_rcu()</tt> will block until the corresponding
+callback is invoked.
+Unfortunately, the callback cannot be invoked until RCU's runtime
+grace-period machinery is up and running, which cannot happen until
+the scheduler has initialized itself sufficiently to allow RCU's
+kthreads to be spawned.
+Therefore, invoking <tt>synchronize_rcu()</tt> during scheduler
+initialization can result in deadlock.
+
+<p><a name="Quick Quiz 14"><b>Quick Quiz 14</b>:</a>
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+<br><a href="#qq14answer">Answer</a>
+
+<p>
+I learned of these boot-time requirements as a result of a series of
+system hangs.
+
+<h3><a name="Interrupts and NMIs">Interrupts and NMIs</a></h3>
+
+<p>
+The Linux kernel has interrupts, and RCU read-side critical sections are
+legal within interrupt handlers and within interrupt-disabled regions
+of code, as are invocations of <tt>call_rcu()</tt>.
+
+<p>
+Some Linux-kernel architectures can enter an interrupt handler from
+non-idle process context, and then just never leave it, instead stealthily
+transitioning back to process context.
+This trick is sometimes used to invoke system calls from inside the kernel.
+These &ldquo;half-interrupts&rdquo; mean that RCU has to be very careful
+about how it counts interrupt nesting levels.
+I learned of this requirement the hard way during a rewrite
+of RCU's dyntick-idle code.
+
+<p>
+The Linux kernel has non-maskable interrupts (NMIs), and
+RCU read-side critical sections are legal within NMI handlers.
+Thankfully, RCU update-side primitives, including
+<tt>call_rcu()</tt>, are prohibited within NMI handlers.
+
+<p>
+The name notwithstanding, some Linux-kernel architectures
+can have nested NMIs, which RCU must handle correctly.
+Andy Lutomirski
+<a href="https://lkml.kernel.org/g/CALCETrXLq1y7e_dKFPgou-FKHB6Pu-r8+t-6Ds+8=va7anBWDA@mail.gmail.com">surprised me</a>
+with this requirement;
+he also kindly surprised me with
+<a href="https://lkml.kernel.org/g/CALCETrXSY9JpW3uE6H8WYk81sg56qasA2aqmjMPsq5dOtzso=g@mail.gmail.com">an algorithm</a>
+that meets this requirement.
+
+<h3><a name="Loadable Modules">Loadable Modules</a></h3>
+
+<p>
+The Linux kernel has loadable modules, and these modules can
+also be unloaded.
+After a given module has been unloaded, any attempt to call
+one of its functions results in a segmentation fault.
+The module-unload functions must therefore cancel any
+delayed calls to loadable-module functions, for example,
+any outstanding <tt>mod_timer()</tt> must be dealt with
+via <tt>del_timer_sync()</tt> or similar.
+
+<p>
+Unfortunately, there is no way to cancel an RCU callback;
+once you invoke <tt>call_rcu()</tt>, the callback function is
+going to eventually be invoked, unless the system goes down first.
+Because it is normally considered socially irresponsible to crash the system
+in response to a module unload request, we need some other way
+to deal with in-flight RCU callbacks.
+
+<p>
+RCU therefore provides
+<tt><a href="https://lwn.net/Articles/217484/">rcu_barrier()</a></tt>,
+which waits until all in-flight RCU callbacks have been invoked.
+If a module uses <tt>call_rcu()</tt>, its exit function should therefore
+prevent any future invocation of <tt>call_rcu()</tt>, then invoke
+<tt>rcu_barrier()</tt>.
+In theory, the underlying module-unload code could invoke
+<tt>rcu_barrier()</tt> unconditionally, but in practice this would
+incur unacceptable latencies.
+
+<p>
+Nikita Danilov noted this requirement for an analogous filesystem-unmount
+situation, and Dipankar Sarma incorporated <tt>rcu_barrier()</tt> into RCU.
+The need for <tt>rcu_barrier()</tt> for module unloading became
+apparent later.
+
+<h3><a name="Hotplug CPU">Hotplug CPU</a></h3>
+
+<p>
+The Linux kernel supports CPU hotplug, which means that CPUs
+can come and go.
+It is of course illegal to use any RCU API member from an offline CPU.
+This requirement was present from day one in DYNIX/ptx, but
+on the other hand, the Linux kernel's CPU-hotplug implementation
+is &ldquo;interesting.&rdquo;
+
+<p>
+The Linux-kernel CPU-hotplug implementation has notifiers that
+are used to allow the various kernel subsystems (including RCU)
+to respond appropriately to a given CPU-hotplug operation.
+Most RCU operations may be invoked from CPU-hotplug notifiers,
+including even normal synchronous grace-period operations
+such as <tt>synchronize_rcu()</tt>.
+However, expedited grace-period operations such as
+<tt>synchronize_rcu_expedited()</tt> are not supported,
+due to the fact that current implementations block CPU-hotplug
+operations, which could result in deadlock.
+
+<p>
+In addition, all-callback-wait operations such as
+<tt>rcu_barrier()</tt> are also not supported, due to the
+fact that there are phases of CPU-hotplug operations where
+the outgoing CPU's callbacks will not be invoked until after
+the CPU-hotplug operation ends, which could also result in deadlock.
+
+<h3><a name="Scheduler and RCU">Scheduler and RCU</a></h3>
+
+<p>
+RCU depends on the scheduler, and the scheduler uses RCU to
+protect some of its data structures.
+This means the scheduler is forbidden from acquiring
+the runqueue locks and the priority-inheritance locks
+in the middle of an outermost RCU read-side critical section unless either
+(1)&nbsp;it releases them before exiting that same
+RCU read-side critical section, or
+(2)&nbsp;interrupts are disabled across
+that entire RCU read-side critical section.
+This same prohibition also applies (recursively!) to any lock that is acquired
+while holding any lock to which this prohibition applies.
+Adhering to this rule prevents preemptible RCU from invoking
+<tt>rcu_read_unlock_special()</tt> while either runqueue or
+priority-inheritance locks are held, thus avoiding deadlock.
+
+<p>
+Prior to v4.4, it was only necessary to disable preemption across
+RCU read-side critical sections that acquired scheduler locks.
+In v4.4, expedited grace periods started using IPIs, and these
+IPIs could force a <tt>rcu_read_unlock()</tt> to take the slowpath.
+Therefore, this expedited-grace-period change required disabling of
+interrupts, not just preemption.
+
+<p>
+For RCU's part, the preemptible-RCU <tt>rcu_read_unlock()</tt>
+implementation must be written carefully to avoid similar deadlocks.
+In particular, <tt>rcu_read_unlock()</tt> must tolerate an
+interrupt where the interrupt handler invokes both
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+This possibility requires <tt>rcu_read_unlock()</tt> to use
+negative nesting levels to avoid destructive recursion via
+interrupt handler's use of RCU.
+
+<p>
+This pair of mutual scheduler-RCU requirements came as a
+<a href="https://lwn.net/Articles/453002/">complete surprise</a>.
+
+<p>
+As noted above, RCU makes use of kthreads, and it is necessary to
+avoid excessive CPU-time accumulation by these kthreads.
+This requirement was no surprise, but RCU's violation of it
+when running context-switch-heavy workloads when built with
+<tt>CONFIG_NO_HZ_FULL=y</tt>
+<a href="http://www.rdrop.com/users/paulmck/scalability/paper/BareMetal.2015.01.15b.pdf">did come as a surprise [PDF]</a>.
+RCU has made good progress towards meeting this requirement, even
+for context-switch-have <tt>CONFIG_NO_HZ_FULL=y</tt> workloads,
+but there is room for further improvement.
+
+<h3><a name="Tracing and RCU">Tracing and RCU</a></h3>
+
+<p>
+It is possible to use tracing on RCU code, but tracing itself
+uses RCU.
+For this reason, <tt>rcu_dereference_raw_notrace()</tt>
+is provided for use by tracing, which avoids the destructive
+recursion that could otherwise ensue.
+This API is also used by virtualization in some architectures,
+where RCU readers execute in environments in which tracing
+cannot be used.
+The tracing folks both located the requirement and provided the
+needed fix, so this surprise requirement was relatively painless.
+
+<h3><a name="Energy Efficiency">Energy Efficiency</a></h3>
+
+<p>
+Interrupting idle CPUs is considered socially unacceptable,
+especially by people with battery-powered embedded systems.
+RCU therefore conserves energy by detecting which CPUs are
+idle, including tracking CPUs that have been interrupted from idle.
+This is a large part of the energy-efficiency requirement,
+so I learned of this via an irate phone call.
+
+<p>
+Because RCU avoids interrupting idle CPUs, it is illegal to
+execute an RCU read-side critical section on an idle CPU.
+(Kernels built with <tt>CONFIG_PROVE_RCU=y</tt> will splat
+if you try it.)
+The <tt>RCU_NONIDLE()</tt> macro and <tt>_rcuidle</tt>
+event tracing is provided to work around this restriction.
+In addition, <tt>rcu_is_watching()</tt> may be used to
+test whether or not it is currently legal to run RCU read-side
+critical sections on this CPU.
+I learned of the need for diagnostics on the one hand
+and <tt>RCU_NONIDLE()</tt> on the other while inspecting
+idle-loop code.
+Steven Rostedt supplied <tt>_rcuidle</tt> event tracing,
+which is used quite heavily in the idle loop.
+
+<p>
+It is similarly socially unacceptable to interrupt an
+<tt>nohz_full</tt> CPU running in userspace.
+RCU must therefore track <tt>nohz_full</tt> userspace
+execution.
+And in
+<a href="https://lwn.net/Articles/558284/"><tt>CONFIG_NO_HZ_FULL_SYSIDLE=y</tt></a>
+kernels, RCU must separately track idle CPUs on the one hand and
+CPUs that are either idle or executing in userspace on the other.
+In both cases, RCU must be able to sample state at two points in
+time, and be able to determine whether or not some other CPU spent
+any time idle and/or executing in userspace.
+
+<p>
+These energy-efficiency requirements have proven quite difficult to
+understand and to meet, for example, there have been more than five
+clean-sheet rewrites of RCU's energy-efficiency code, the last of
+which was finally able to demonstrate
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/AMPenergy.2013.04.19a.pdf">real energy savings running on real hardware [PDF]</a>.
+As noted earlier,
+I learned of many of these requirements via angry phone calls:
+Flaming me on the Linux-kernel mailing list was apparently not
+sufficient to fully vent their ire at RCU's energy-efficiency bugs!
+
+<h3><a name="Memory Efficiency">Memory Efficiency</a></h3>
+
+<p>
+Although small-memory non-realtime systems can simply use Tiny RCU,
+code size is only one aspect of memory efficiency.
+Another aspect is the size of the <tt>rcu_head</tt> structure
+used by <tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>.
+Although this structure contains nothing more than a pair of pointers,
+it does appear in many RCU-protected data structures, including
+some that are size critical.
+The <tt>page</tt> structure is a case in point, as evidenced by
+the many occurrences of the <tt>union</tt> keyword within that structure.
+
+<p>
+This need for memory efficiency is one reason that RCU uses hand-crafted
+singly linked lists to track the <tt>rcu_head</tt> structures that
+are waiting for a grace period to elapse.
+It is also the reason why <tt>rcu_head</tt> structures do not contain
+debug information, such as fields tracking the file and line of the
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> that posted them.
+Although this information might appear in debug-only kernel builds at some
+point, in the meantime, the <tt>-&gt;func</tt> field will often provide
+the needed debug information.
+
+<p>
+However, in some cases, the need for memory efficiency leads to even
+more extreme measures.
+Returning to the <tt>page</tt> structure, the <tt>rcu_head</tt> field
+shares storage with a great many other structures that are used at
+various points in the corresponding page's lifetime.
+In order to correctly resolve certain
+<a href="https://lkml.kernel.org/g/1439976106-137226-1-git-send-email-kirill.shutemov@linux.intel.com">race conditions</a>,
+the Linux kernel's memory-management subsystem needs a particular bit
+to remain zero during all phases of grace-period processing,
+and that bit happens to map to the bottom bit of the
+<tt>rcu_head</tt> structure's <tt>-&gt;next</tt> field.
+RCU makes this guarantee as long as <tt>call_rcu()</tt>
+is used to post the callback, as opposed to <tt>kfree_rcu()</tt>
+or some future &ldquo;lazy&rdquo;
+variant of <tt>call_rcu()</tt> that might one day be created for
+energy-efficiency purposes.
+
+<h3><a name="Performance, Scalability, Response Time, and Reliability">
+Performance, Scalability, Response Time, and Reliability</a></h3>
+
+<p>
+Expanding on the
+<a href="#Performance and Scalability">earlier discussion</a>,
+RCU is used heavily by hot code paths in performance-critical
+portions of the Linux kernel's networking, security, virtualization,
+and scheduling code paths.
+RCU must therefore use efficient implementations, especially in its
+read-side primitives.
+To that end, it would be good if preemptible RCU's implementation
+of <tt>rcu_read_lock()</tt> could be inlined, however, doing
+this requires resolving <tt>#include</tt> issues with the
+<tt>task_struct</tt> structure.
+
+<p>
+The Linux kernel supports hardware configurations with up to
+4096 CPUs, which means that RCU must be extremely scalable.
+Algorithms that involve frequent acquisitions of global locks or
+frequent atomic operations on global variables simply cannot be
+tolerated within the RCU implementation.
+RCU therefore makes heavy use of a combining tree based on the
+<tt>rcu_node</tt> structure.
+RCU is required to tolerate all CPUs continuously invoking any
+combination of RCU's runtime primitives with minimal per-operation
+overhead.
+In fact, in many cases, increasing load must <i>decrease</i> the
+per-operation overhead, witness the batching optimizations for
+<tt>synchronize_rcu()</tt>, <tt>call_rcu()</tt>,
+<tt>synchronize_rcu_expedited()</tt>, and <tt>rcu_barrier()</tt>.
+As a general rule, RCU must cheerfully accept whatever the
+rest of the Linux kernel decides to throw at it.
+
+<p>
+The Linux kernel is used for real-time workloads, especially
+in conjunction with the
+<a href="https://rt.wiki.kernel.org/index.php/Main_Page">-rt patchset</a>.
+The real-time-latency response requirements are such that the
+traditional approach of disabling preemption across RCU
+read-side critical sections is inappropriate.
+Kernels built with <tt>CONFIG_PREEMPT=y</tt> therefore
+use an RCU implementation that allows RCU read-side critical
+sections to be preempted.
+This requirement made its presence known after users made it
+clear that an earlier
+<a href="https://lwn.net/Articles/107930/">real-time patch</a>
+did not meet their needs, in conjunction with some
+<a href="https://lkml.kernel.org/g/20050318002026.GA2693@us.ibm.com">RCU issues</a>
+encountered by a very early version of the -rt patchset.
+
+<p>
+In addition, RCU must make do with a sub-100-microsecond real-time latency
+budget.
+In fact, on smaller systems with the -rt patchset, the Linux kernel
+provides sub-20-microsecond real-time latencies for the whole kernel,
+including RCU.
+RCU's scalability and latency must therefore be sufficient for
+these sorts of configurations.
+To my surprise, the sub-100-microsecond real-time latency budget
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/bigrt.2013.01.31a.LCA.pdf">
+applies to even the largest systems [PDF]</a>,
+up to and including systems with 4096 CPUs.
+This real-time requirement motivated the grace-period kthread, which
+also simplified handling of a number of race conditions.
+
+<p>
+Finally, RCU's status as a synchronization primitive means that
+any RCU failure can result in arbitrary memory corruption that can be
+extremely difficult to debug.
+This means that RCU must be extremely reliable, which in
+practice also means that RCU must have an aggressive stress-test
+suite.
+This stress-test suite is called <tt>rcutorture</tt>.
+
+<p>
+Although the need for <tt>rcutorture</tt> was no surprise,
+the current immense popularity of the Linux kernel is posing
+interesting&mdash;and perhaps unprecedented&mdash;validation
+challenges.
+To see this, keep in mind that there are well over one billion
+instances of the Linux kernel running today, given Android
+smartphones, Linux-powered televisions, and servers.
+This number can be expected to increase sharply with the advent of
+the celebrated Internet of Things.
+
+<p>
+Suppose that RCU contains a race condition that manifests on average
+once per million years of runtime.
+This bug will be occurring about three times per <i>day</i> across
+the installed base.
+RCU could simply hide behind hardware error rates, given that no one
+should really expect their smartphone to last for a million years.
+However, anyone taking too much comfort from this thought should
+consider the fact that in most jurisdictions, a successful multi-year
+test of a given mechanism, which might include a Linux kernel,
+suffices for a number of types of safety-critical certifications.
+In fact, rumor has it that the Linux kernel is already being used
+in production for safety-critical applications.
+I don't know about you, but I would feel quite bad if a bug in RCU
+killed someone.
+Which might explain my recent focus on validation and verification.
+
+<h2><a name="Other RCU Flavors">Other RCU Flavors</a></h2>
+
+<p>
+One of the more surprising things about RCU is that there are now
+no fewer than five <i>flavors</i>, or API families.
+In addition, the primary flavor that has been the sole focus up to
+this point has two different implementations, non-preemptible and
+preemptible.
+The other four flavors are listed below, with requirements for each
+described in a separate section.
+
+<ol>
+<li> <a href="#Bottom-Half Flavor">Bottom-Half Flavor</a>
+<li> <a href="#Sched Flavor">Sched Flavor</a>
+<li> <a href="#Sleepable RCU">Sleepable RCU</a>
+<li> <a href="#Tasks RCU">Tasks RCU</a>
+</ol>
+
+<h3><a name="Bottom-Half Flavor">Bottom-Half Flavor</a></h3>
+
+<p>
+The softirq-disable (AKA &ldquo;bottom-half&rdquo;,
+hence the &ldquo;_bh&rdquo; abbreviations)
+flavor of RCU, or <i>RCU-bh</i>, was developed by
+Dipankar Sarma to provide a flavor of RCU that could withstand the
+network-based denial-of-service attacks researched by Robert
+Olsson.
+These attacks placed so much networking load on the system
+that some of the CPUs never exited softirq execution,
+which in turn prevented those CPUs from ever executing a context switch,
+which, in the RCU implementation of that time, prevented grace periods
+from ever ending.
+The result was an out-of-memory condition and a system hang.
+
+<p>
+The solution was the creation of RCU-bh, which does
+<tt>local_bh_disable()</tt>
+across its read-side critical sections, and which uses the transition
+from one type of softirq processing to another as a quiescent state
+in addition to context switch, idle, user mode, and offline.
+This means that RCU-bh grace periods can complete even when some of
+the CPUs execute in softirq indefinitely, thus allowing algorithms
+based on RCU-bh to withstand network-based denial-of-service attacks.
+
+<p>
+Because
+<tt>rcu_read_lock_bh()</tt> and <tt>rcu_read_unlock_bh()</tt>
+disable and re-enable softirq handlers, any attempt to start a softirq
+handlers during the
+RCU-bh read-side critical section will be deferred.
+In this case, <tt>rcu_read_unlock_bh()</tt>
+will invoke softirq processing, which can take considerable time.
+One can of course argue that this softirq overhead should be associated
+with the code following the RCU-bh read-side critical section rather
+than <tt>rcu_read_unlock_bh()</tt>, but the fact
+is that most profiling tools cannot be expected to make this sort
+of fine distinction.
+For example, suppose that a three-millisecond-long RCU-bh read-side
+critical section executes during a time of heavy networking load.
+There will very likely be an attempt to invoke at least one softirq
+handler during that three milliseconds, but any such invocation will
+be delayed until the time of the <tt>rcu_read_unlock_bh()</tt>.
+This can of course make it appear at first glance as if
+<tt>rcu_read_unlock_bh()</tt> was executing very slowly.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-bh API</a>
+includes
+<tt>rcu_read_lock_bh()</tt>,
+<tt>rcu_read_unlock_bh()</tt>,
+<tt>rcu_dereference_bh()</tt>,
+<tt>rcu_dereference_bh_check()</tt>,
+<tt>synchronize_rcu_bh()</tt>,
+<tt>synchronize_rcu_bh_expedited()</tt>,
+<tt>call_rcu_bh()</tt>,
+<tt>rcu_barrier_bh()</tt>, and
+<tt>rcu_read_lock_bh_held()</tt>.
+
+<h3><a name="Sched Flavor">Sched Flavor</a></h3>
+
+<p>
+Before preemptible RCU, waiting for an RCU grace period had the
+side effect of also waiting for all pre-existing interrupt
+and NMI handlers.
+However, there are legitimate preemptible-RCU implementations that
+do not have this property, given that any point in the code outside
+of an RCU read-side critical section can be a quiescent state.
+Therefore, <i>RCU-sched</i> was created, which follows &ldquo;classic&rdquo;
+RCU in that an RCU-sched grace period waits for for pre-existing
+interrupt and NMI handlers.
+In kernels built with <tt>CONFIG_PREEMPT=n</tt>, the RCU and RCU-sched
+APIs have identical implementations, while kernels built with
+<tt>CONFIG_PREEMPT=y</tt> provide a separate implementation for each.
+
+<p>
+Note well that in <tt>CONFIG_PREEMPT=y</tt> kernels,
+<tt>rcu_read_lock_sched()</tt> and <tt>rcu_read_unlock_sched()</tt>
+disable and re-enable preemption, respectively.
+This means that if there was a preemption attempt during the
+RCU-sched read-side critical section, <tt>rcu_read_unlock_sched()</tt>
+will enter the scheduler, with all the latency and overhead entailed.
+Just as with <tt>rcu_read_unlock_bh()</tt>, this can make it look
+as if <tt>rcu_read_unlock_sched()</tt> was executing very slowly.
+However, the highest-priority task won't be preempted, so that task
+will enjoy low-overhead <tt>rcu_read_unlock_sched()</tt> invocations.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-sched API</a>
+includes
+<tt>rcu_read_lock_sched()</tt>,
+<tt>rcu_read_unlock_sched()</tt>,
+<tt>rcu_read_lock_sched_notrace()</tt>,
+<tt>rcu_read_unlock_sched_notrace()</tt>,
+<tt>rcu_dereference_sched()</tt>,
+<tt>rcu_dereference_sched_check()</tt>,
+<tt>synchronize_sched()</tt>,
+<tt>synchronize_rcu_sched_expedited()</tt>,
+<tt>call_rcu_sched()</tt>,
+<tt>rcu_barrier_sched()</tt>, and
+<tt>rcu_read_lock_sched_held()</tt>.
+However, anything that disables preemption also marks an RCU-sched
+read-side critical section, including
+<tt>preempt_disable()</tt> and <tt>preempt_enable()</tt>,
+<tt>local_irq_save()</tt> and <tt>local_irq_restore()</tt>,
+and so on.
+
+<h3><a name="Sleepable RCU">Sleepable RCU</a></h3>
+
+<p>
+For well over a decade, someone saying &ldquo;I need to block within
+an RCU read-side critical section&rdquo; was a reliable indication
+that this someone did not understand RCU.
+After all, if you are always blocking in an RCU read-side critical
+section, you can probably afford to use a higher-overhead synchronization
+mechanism.
+However, that changed with the advent of the Linux kernel's notifiers,
+whose RCU read-side critical
+sections almost never sleep, but sometimes need to.
+This resulted in the introduction of
+<a href="https://lwn.net/Articles/202847/">sleepable RCU</a>,
+or <i>SRCU</i>.
+
+<p>
+SRCU allows different domains to be defined, with each such domain
+defined by an instance of an <tt>srcu_struct</tt> structure.
+A pointer to this structure must be passed in to each SRCU function,
+for example, <tt>synchronize_srcu(&amp;ss)</tt>, where
+<tt>ss</tt> is the <tt>srcu_struct</tt> structure.
+The key benefit of these domains is that a slow SRCU reader in one
+domain does not delay an SRCU grace period in some other domain.
+That said, one consequence of these domains is that read-side code
+must pass a &ldquo;cookie&rdquo; from <tt>srcu_read_lock()</tt>
+to <tt>srcu_read_unlock()</tt>, for example, as follows:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+As noted above, it is legal to block within SRCU read-side critical sections,
+however, with great power comes great responsibility.
+If you block forever in one of a given domain's SRCU read-side critical
+sections, then that domain's grace periods will also be blocked forever.
+Of course, one good way to block forever is to deadlock, which can
+happen if any operation in a given domain's SRCU read-side critical
+section can block waiting, either directly or indirectly, for that domain's
+grace period to elapse.
+For example, this results in a self-deadlock:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 synchronize_srcu(&amp;ss);
+ 6 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+However, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for domain <tt>ss</tt>,
+deadlock would still be possible.
+Furthermore, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for some other domain <tt>ss1</tt>,
+and if an <tt>ss1</tt>-domain SRCU read-side critical section
+acquired another mutex that was held across as <tt>ss</tt>-domain
+<tt>synchronize_srcu()</tt>,
+deadlock would again be possible.
+Such a deadlock cycle could extend across an arbitrarily large number
+of different SRCU domains.
+Again, with great power comes great responsibility.
+
+<p>
+Unlike the other RCU flavors, SRCU read-side critical sections can
+run on idle and even offline CPUs.
+This ability requires that <tt>srcu_read_lock()</tt> and
+<tt>srcu_read_unlock()</tt> contain memory barriers, which means
+that SRCU readers will run a bit slower than would RCU readers.
+It also motivates the <tt>smp_mb__after_srcu_read_unlock()</tt>
+API, which, in combination with <tt>srcu_read_unlock()</tt>,
+guarantees a full memory barrier.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">SRCU API</a>
+includes
+<tt>srcu_read_lock()</tt>,
+<tt>srcu_read_unlock()</tt>,
+<tt>srcu_dereference()</tt>,
+<tt>srcu_dereference_check()</tt>,
+<tt>synchronize_srcu()</tt>,
+<tt>synchronize_srcu_expedited()</tt>,
+<tt>call_srcu()</tt>,
+<tt>srcu_barrier()</tt>, and
+<tt>srcu_read_lock_held()</tt>.
+It also includes
+<tt>DEFINE_SRCU()</tt>,
+<tt>DEFINE_STATIC_SRCU()</tt>, and
+<tt>init_srcu_struct()</tt>
+APIs for defining and initializing <tt>srcu_struct</tt> structures.
+
+<h3><a name="Tasks RCU">Tasks RCU</a></h3>
+
+<p>
+Some forms of tracing use &ldquo;tramopolines&rdquo; to handle the
+binary rewriting required to install different types of probes.
+It would be good to be able to free old trampolines, which sounds
+like a job for some form of RCU.
+However, because it is necessary to be able to install a trace
+anywhere in the code, it is not possible to use read-side markers
+such as <tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+In addition, it does not work to have these markers in the trampoline
+itself, because there would need to be instructions following
+<tt>rcu_read_unlock()</tt>.
+Although <tt>synchronize_rcu()</tt> would guarantee that execution
+reached the <tt>rcu_read_unlock()</tt>, it would not be able to
+guarantee that execution had completely left the trampoline.
+
+<p>
+The solution, in the form of
+<a href="https://lwn.net/Articles/607117/"><i>Tasks RCU</i></a>,
+is to have implicit
+read-side critical sections that are delimited by voluntary context
+switches, that is, calls to <tt>schedule()</tt>,
+<tt>cond_resched_rcu_qs()</tt>, and
+<tt>synchronize_rcu_tasks()</tt>.
+In addition, transitions to and from userspace execution also delimit
+tasks-RCU read-side critical sections.
+
+<p>
+The tasks-RCU API is quite compact, consisting only of
+<tt>call_rcu_tasks()</tt>,
+<tt>synchronize_rcu_tasks()</tt>, and
+<tt>rcu_barrier_tasks()</tt>.
+
+<h2><a name="Possible Future Changes">Possible Future Changes</a></h2>
+
+<p>
+One of the tricks that RCU uses to attain update-side scalability is
+to increase grace-period latency with increasing numbers of CPUs.
+If this becomes a serious problem, it will be necessary to rework the
+grace-period state machine so as to avoid the need for the additional
+latency.
+
+<p>
+Expedited grace periods scan the CPUs, so their latency and overhead
+increases with increasing numbers of CPUs.
+If this becomes a serious problem on large systems, it will be necessary
+to do some redesign to avoid this scalability problem.
+
+<p>
+RCU disables CPU hotplug in a few places, perhaps most notably in the
+expedited grace-period and <tt>rcu_barrier()</tt> operations.
+If there is a strong reason to use expedited grace periods in CPU-hotplug
+notifiers, it will be necessary to avoid disabling CPU hotplug.
+This would introduce some complexity, so there had better be a <i>very</i>
+good reason.
+
+<p>
+The tradeoff between grace-period latency on the one hand and interruptions
+of other CPUs on the other hand may need to be re-examined.
+The desire is of course for zero grace-period latency as well as zero
+interprocessor interrupts undertaken during an expedited grace period
+operation.
+While this ideal is unlikely to be achievable, it is quite possible that
+further improvements can be made.
+
+<p>
+The multiprocessor implementations of RCU use a combining tree that
+groups CPUs so as to reduce lock contention and increase cache locality.
+However, this combining tree does not spread its memory across NUMA
+nodes nor does it align the CPU groups with hardware features such
+as sockets or cores.
+Such spreading and alignment is currently believed to be unnecessary
+because the hotpath read-side primitives do not access the combining
+tree, nor does <tt>call_rcu()</tt> in the common case.
+If you believe that your architecture needs such spreading and alignment,
+then your architecture should also benefit from the
+<tt>rcutree.rcu_fanout_leaf</tt> boot parameter, which can be set
+to the number of CPUs in a socket, NUMA node, or whatever.
+If the number of CPUs is too large, use a fraction of the number of
+CPUs.
+If the number of CPUs is a large prime number, well, that certainly
+is an &ldquo;interesting&rdquo; architectural choice!
+More flexible arrangements might be considered, but only if
+<tt>rcutree.rcu_fanout_leaf</tt> has proven inadequate, and only
+if the inadequacy has been demonstrated by a carefully run and
+realistic system-level workload.
+
+<p>
+Please note that arrangements that require RCU to remap CPU numbers will
+require extremely good demonstration of need and full exploration of
+alternatives.
+
+<p>
+There is an embarrassingly large number of flavors of RCU, and this
+number has been increasing over time.
+Perhaps it will be possible to combine some at some future date.
+
+<p>
+RCU's various kthreads are reasonably recent additions.
+It is quite likely that adjustments will be required to more gracefully
+handle extreme loads.
+It might also be necessary to be able to relate CPU utilization by
+RCU's kthreads and softirq handlers to the code that instigated this
+CPU utilization.
+For example, RCU callback overhead might be charged back to the
+originating <tt>call_rcu()</tt> instance, though probably not
+in production kernels.
+
+<h2><a name="Summary">Summary</a></h2>
+
+<p>
+This document has presented more than two decade's worth of RCU
+requirements.
+Given that the requirements keep changing, this will not be the last
+word on this subject, but at least it serves to get an important
+subset of the requirements set forth.
+
+<h2><a name="Acknowledgments">Acknowledgments</a></h2>
+
+I am grateful to Steven Rostedt, Lai Jiangshan, Ingo Molnar,
+Oleg Nesterov, Borislav Petkov, Peter Zijlstra, Boqun Feng, and
+Andy Lutomirski for their help in rendering
+this article human readable, and to Michelle Rankin for her support
+of this effort.
+Other contributions are acknowledged in the Linux kernel's git archive.
+The cartoon is copyright (c) 2013 by Melissa Broussard,
+and is provided
+under the terms of the Creative Commons Attribution-Share Alike 3.0
+United States license.
+
+<h3><a name="Answers to Quick Quizzes">
+Answers to Quick Quizzes</a></h3>
+
+<a name="qq1answer"></a>
+<p><b>Quick Quiz 1</b>:
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+
+
+</p><p><b>Answer</b>:
+First, if updaters do not wish to be blocked by readers, they can use
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt>, which will
+be discussed later.
+Second, even when using <tt>synchronize_rcu()</tt>, the other
+update-side code does run concurrently with readers, whether pre-existing
+or not.
+
+
+</p><p><a href="#Quick%20Quiz%201"><b>Back to Quick Quiz 1</b>.</a>
+
+<a name="qq2answer"></a>
+<p><b>Quick Quiz 2</b>:
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+
+
+</p><p><b>Answer</b>:
+Without that extra grace period, memory reordering could result in
+<tt>do_something_dlm()</tt> executing <tt>do_something()</tt>
+concurrently with the last bits of <tt>recovery()</tt>.
+
+
+</p><p><a href="#Quick%20Quiz%202"><b>Back to Quick Quiz 2</b>.</a>
+
+<a name="qq3answer"></a>
+<p><b>Quick Quiz 3</b>:
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+
+
+</p><p><b>Answer</b>:
+No, it cannot.
+The readers cannot see either of these two fields until
+the assignment to <tt>gp</tt>, by which time both fields are
+fully initialized.
+So reordering the assignments
+to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt> cannot possibly
+cause any problems.
+
+
+</p><p><a href="#Quick%20Quiz%203"><b>Back to Quick Quiz 3</b>.</a>
+
+<a name="qq4answer"></a>
+<p><b>Quick Quiz 4</b>:
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+
+
+</p><p><b>Answer</b>:
+Let's start with what happens to <tt>do_something_gp()</tt>
+if it fails to use <tt>rcu_dereference()</tt>.
+It could reuse a value formerly fetched from this same pointer.
+It could also fetch the pointer from <tt>gp</tt> in a byte-at-a-time
+manner, resulting in <i>load tearing</i>, in turn resulting a bytewise
+mash-up of two distince pointer values.
+It might even use value-speculation optimizations, where it makes a wrong
+guess, but by the time it gets around to checking the value, an update
+has changed the pointer to match the wrong guess.
+Too bad about any dereferences that returned pre-initialization garbage
+in the meantime!
+
+<p>
+For <tt>remove_gp_synchronous()</tt>, as long as all modifications
+to <tt>gp</tt> are carried out while holding <tt>gp_lock</tt>,
+the above optimizations are harmless.
+However,
+with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt>,
+<tt>sparse</tt> will complain if you
+define <tt>gp</tt> with <tt>__rcu</tt> and then
+access it without using
+either <tt>rcu_access_pointer()</tt> or <tt>rcu_dereference()</tt>.
+
+
+</p><p><a href="#Quick%20Quiz%204"><b>Back to Quick Quiz 4</b>.</a>
+
+<a name="qq5answer"></a>
+<p><b>Quick Quiz 5</b>:
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+
+
+</p><p><b>Answer</b>:
+If RCU cannot tell whether or not a given
+RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>,
+then it must assume that the RCU read-side critical section
+started first.
+In other words, a given instance of <tt>synchronize_rcu()</tt>
+can avoid waiting on a given RCU read-side critical section only
+if it can prove that <tt>synchronize_rcu()</tt> started first.
+
+
+</p><p><a href="#Quick%20Quiz%205"><b>Back to Quick Quiz 5</b>.</a>
+
+<a name="qq6answer"></a>
+<p><b>Quick Quiz 6</b>:
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+
+
+</p><p><b>Answer</b>:
+Yes, they really are required.
+To see why the first guarantee is required, consider the following
+sequence of events:
+
+<ol>
+<li> CPU 1: <tt>rcu_read_lock()</tt>
+<li> CPU 1: <tt>q = rcu_dereference(gp);
+ /* Very likely to return p. */</tt>
+<li> CPU 0: <tt>list_del_rcu(p);</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li> CPU 1: <tt>do_something_with(q-&gt;a);
+ /* No smp_mb(), so might happen after kfree(). */</tt>
+<li> CPU 1: <tt>rcu_read_unlock()</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li> CPU 0: <tt>kfree(p);</tt>
+</ol>
+
+<p>
+Therefore, there absolutely must be a full memory barrier between the
+end of the RCU read-side critical section and the end of the
+grace period.
+
+<p>
+The sequence of events demonstrating the necessity of the second rule
+is roughly similar:
+
+<ol>
+<li> CPU 0: <tt>list_del_rcu(p);</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li> CPU 1: <tt>rcu_read_lock()</tt>
+<li> CPU 1: <tt>q = rcu_dereference(gp);
+ /* Might return p if no memory barrier. */</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li> CPU 0: <tt>kfree(p);</tt>
+<li> CPU 1: <tt>do_something_with(q-&gt;a); /* Boom!!! */</tt>
+<li> CPU 1: <tt>rcu_read_unlock()</tt>
+</ol>
+
+<p>
+And similarly, without a memory barrier between the beginning of the
+grace period and the beginning of the RCU read-side critical section,
+CPU&nbsp;1 might end up accessing the freelist.
+
+<p>
+The &ldquo;as if&rdquo; rule of course applies, so that any implementation
+that acts as if the appropriate memory barriers were in place is a
+correct implementation.
+That said, it is much easier to fool yourself into believing that you have
+adhered to the as-if rule than it is to actually adhere to it!
+
+
+</p><p><a href="#Quick%20Quiz%206"><b>Back to Quick Quiz 6</b>.</a>
+
+<a name="qq7answer"></a>
+<p><b>Quick Quiz 7</b>:
+But how does the upgrade-to-write operation exclude other readers?
+
+
+</p><p><b>Answer</b>:
+It doesn't, just like normal RCU updates, which also do not exclude
+RCU readers.
+
+
+</p><p><a href="#Quick%20Quiz%207"><b>Back to Quick Quiz 7</b>.</a>
+
+<a name="qq8answer"></a>
+<p><b>Quick Quiz 8</b>:
+Can't the compiler also reorder this code?
+
+
+</p><p><b>Answer</b>:
+No, the volatile casts in <tt>READ_ONCE()</tt> and
+<tt>WRITE_ONCE()</tt> prevent the compiler from reordering in
+this particular case.
+
+
+</p><p><a href="#Quick%20Quiz%208"><b>Back to Quick Quiz 8</b>.</a>
+
+<a name="qq9answer"></a>
+<p><b>Quick Quiz 9</b>:
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+
+
+</p><p><b>Answer</b>:
+No.
+Even if <tt>synchronize_rcu()</tt> were to wait until
+all readers had completed, a new reader might start immediately after
+<tt>synchronize_rcu()</tt> completed.
+Therefore, the code following
+<tt>synchronize_rcu()</tt> cannot rely on there being no readers
+in any case.
+
+
+</p><p><a href="#Quick%20Quiz%209"><b>Back to Quick Quiz 9</b>.</a>
+
+<a name="qq10answer"></a>
+<p><b>Quick Quiz 10</b>:
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+
+
+</p><p><b>Answer</b>:
+In theory, an infinite number.
+In practice, an unknown number that is sensitive to both implementation
+details and timing considerations.
+Therefore, even in practice, RCU users must abide by the theoretical rather
+than the practical answer.
+
+
+</p><p><a href="#Quick%20Quiz%2010"><b>Back to Quick Quiz 10</b>.</a>
+
+<a name="qq11answer"></a>
+<p><b>Quick Quiz 11</b>:
+What about sleeping locks?
+
+
+</p><p><b>Answer</b>:
+These are forbidden within Linux-kernel RCU read-side critical sections
+because it is not legal to place a quiescent state (in this case,
+voluntary context switch) within an RCU read-side critical section.
+However, sleeping locks may be used within userspace RCU read-side critical
+sections, and also within Linux-kernel sleepable RCU
+<a href="#Sleepable RCU">(SRCU)</a>
+read-side critical sections.
+In addition, the -rt patchset turns spinlocks into a sleeping locks so
+that the corresponding critical sections can be preempted, which
+also means that these sleeplockified spinlocks (but not other sleeping locks!)
+may be acquire within -rt-Linux-kernel RCU read-side critical sections.
+
+<p>
+Note that it <i>is</i> legal for a normal RCU read-side critical section
+to conditionally acquire a sleeping locks (as in <tt>mutex_trylock()</tt>),
+but only as long as it does not loop indefinitely attempting to
+conditionally acquire that sleeping locks.
+The key point is that things like <tt>mutex_trylock()</tt>
+either return with the mutex held, or return an error indication if
+the mutex was not immediately available.
+Either way, <tt>mutex_trylock()</tt> returns immediately without sleeping.
+
+
+</p><p><a href="#Quick%20Quiz%2011"><b>Back to Quick Quiz 11</b>.</a>
+
+<a name="qq12answer"></a>
+<p><b>Quick Quiz 12</b>:
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+
+
+</p><p><b>Answer</b>:
+Presumably the <tt>-&gt;gp_lock</tt> acquired on line&nbsp;18 excludes
+any changes, including any insertions that <tt>rcu_dereference()</tt>
+would protect against.
+Therefore, any insertions will be delayed until after <tt>-&gt;gp_lock</tt>
+is released on line&nbsp;25, which in turn means that
+<tt>rcu_access_pointer()</tt> suffices.
+
+
+</p><p><a href="#Quick%20Quiz%2012"><b>Back to Quick Quiz 12</b>.</a>
+
+<a name="qq13answer"></a>
+<p><b>Quick Quiz 13</b>:
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+
+
+</p><p><b>Answer</b>:
+We could define things this way, but keep in mind that this sort of
+definition would say that updates in garbage-collected languages
+cannot complete until the next time the garbage collector runs,
+which does not seem at all reasonable.
+The key point is that in most cases, an updater using either
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> can proceed to the
+next update as soon as it has invoked <tt>call_rcu()</tt> or
+<tt>kfree_rcu()</tt>, without having to wait for a subsequent
+grace period.
+
+
+</p><p><a href="#Quick%20Quiz%2013"><b>Back to Quick Quiz 13</b>.</a>
+
+<a name="qq14answer"></a>
+<p><b>Quick Quiz 14</b>:
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+
+
+</p><p><b>Answer</b>:
+In <tt>CONFIG_PREEMPT=n</tt> kernel, <tt>synchronize_rcu()</tt>
+maps directly to <tt>synchronize_sched()</tt>.
+Therefore, <tt>synchronize_rcu()</tt> works normally throughout
+boot in <tt>CONFIG_PREEMPT=n</tt> kernels.
+However, your code must also work in <tt>CONFIG_PREEMPT=y</tt> kernels,
+so it is still necessary to avoid invoking <tt>synchronize_rcu()</tt>
+during scheduler initialization.
+
+
+</p><p><a href="#Quick%20Quiz%2014"><b>Back to Quick Quiz 14</b>.</a>
+
+
+</body></html>
diff --git a/Documentation/RCU/Design/Requirements/Requirements.htmlx b/Documentation/RCU/Design/Requirements/Requirements.htmlx
new file mode 100644
index 0000000..3a97ba4
--- /dev/null
+++ b/Documentation/RCU/Design/Requirements/Requirements.htmlx
@@ -0,0 +1,2741 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+ <html>
+ <head><title>A Tour Through RCU's Requirements [LWN.net]</title>
+ <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
+
+<h1>A Tour Through RCU's Requirements</h1>
+
+<p>Copyright IBM Corporation, 2015</p>
+<p>Author: Paul E.&nbsp;McKenney</p>
+<p><i>The initial version of this document appeared in the
+<a href="https://lwn.net/">LWN</a> articles
+<a href="https://lwn.net/Articles/652156/">here</a>,
+<a href="https://lwn.net/Articles/652677/">here</a>, and
+<a href="https://lwn.net/Articles/653326/">here</a>.</i></p>
+
+<h2>Introduction</h2>
+
+<p>
+Read-copy update (RCU) is a synchronization mechanism that is often
+used as a replacement for reader-writer locking.
+RCU is unusual in that updaters do not block readers,
+which means that RCU's read-side primitives can be exceedingly fast
+and scalable.
+In addition, updaters can make useful forward progress concurrently
+with readers.
+However, all this concurrency between RCU readers and updaters does raise
+the question of exactly what RCU readers are doing, which in turn
+raises the question of exactly what RCU's requirements are.
+
+<p>
+This document therefore summarizes RCU's requirements, and can be thought
+of as an informal, high-level specification for RCU.
+It is important to understand that RCU's specification is primarily
+empirical in nature;
+in fact, I learned about many of these requirements the hard way.
+This situation might cause some consternation, however, not only
+has this learning process been a lot of fun, but it has also been
+a great privilege to work with so many people willing to apply
+technologies in interesting new ways.
+
+<p>
+All that aside, here are the categories of currently known RCU requirements:
+</p>
+
+<ol>
+<li> <a href="#Fundamental Requirements">
+ Fundamental Requirements</a>
+<li> <a href="#Fundamental Non-Requirements">Fundamental Non-Requirements</a>
+<li> <a href="#Parallelism Facts of Life">
+ Parallelism Facts of Life</a>
+<li> <a href="#Quality-of-Implementation Requirements">
+ Quality-of-Implementation Requirements</a>
+<li> <a href="#Linux Kernel Complications">
+ Linux Kernel Complications</a>
+<li> <a href="#Software-Engineering Requirements">
+ Software-Engineering Requirements</a>
+<li> <a href="#Other RCU Flavors">
+ Other RCU Flavors</a>
+<li> <a href="#Possible Future Changes">
+ Possible Future Changes</a>
+</ol>
+
+<p>
+This is followed by a <a href="#Summary">summary</a>,
+which is in turn followed by the inevitable
+<a href="#Answers to Quick Quizzes">answers to the quick quizzes</a>.
+
+<h2><a name="Fundamental Requirements">Fundamental Requirements</a></h2>
+
+<p>
+RCU's fundamental requirements are the closest thing RCU has to hard
+mathematical requirements.
+These are:
+
+<ol>
+<li> <a href="#Grace-Period Guarantee">
+ Grace-Period Guarantee</a>
+<li> <a href="#Publish-Subscribe Guarantee">
+ Publish-Subscribe Guarantee</a>
+<li> <a href="#Memory-Barrier Guarantees">
+ Memory-Barrier Guarantees</a>
+<li> <a href="#RCU Primitives Guaranteed to Execute Unconditionally">
+ RCU Primitives Guaranteed to Execute Unconditionally</a>
+<li> <a href="#Guaranteed Read-to-Write Upgrade">
+ Guaranteed Read-to-Write Upgrade</a>
+</ol>
+
+<h3><a name="Grace-Period Guarantee">Grace-Period Guarantee</a></h3>
+
+<p>
+RCU's grace-period guarantee is unusual in being premeditated:
+Jack Slingwine and I had this guarantee firmly in mind when we started
+work on RCU (then called &ldquo;rclock&rdquo;) in the early 1990s.
+That said, the past two decades of experience with RCU have produced
+a much more detailed understanding of this guarantee.
+
+<p>
+RCU's grace-period guarantee allows updaters to wait for the completion
+of all pre-existing RCU read-side critical sections.
+An RCU read-side critical section
+begins with the marker <tt>rcu_read_lock()</tt> and ends with
+the marker <tt>rcu_read_unlock()</tt>.
+These markers may be nested, and RCU treats a nested set as one
+big RCU read-side critical section.
+Production-quality implementations of <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> are extremely lightweight, and in
+fact have exactly zero overhead in Linux kernels built for production
+use with <tt>CONFIG_PREEMPT=n</tt>.
+
+<p>
+This guarantee allows ordering to be enforced with extremely low
+overhead to readers, for example:
+
+<blockquote>
+<pre>
+ 1 int x, y;
+ 2
+ 3 void thread0(void)
+ 4 {
+ 5 rcu_read_lock();
+ 6 r1 = READ_ONCE(x);
+ 7 r2 = READ_ONCE(y);
+ 8 rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13 WRITE_ONCE(x, 1);
+14 synchronize_rcu();
+15 WRITE_ONCE(y, 1);
+16 }
+</pre>
+</blockquote>
+
+<p>
+Because the <tt>synchronize_rcu()</tt> on line&nbsp;14 waits for
+all pre-existing readers, any instance of <tt>thread0()</tt> that
+loads a value of zero from <tt>x</tt> must complete before
+<tt>thread1()</tt> stores to <tt>y</tt>, so that instance must
+also load a value of zero from <tt>y</tt>.
+Similarly, any instance of <tt>thread0()</tt> that loads a value of
+one from <tt>y</tt> must have started after the
+<tt>synchronize_rcu()</tt> started, and must therefore also load
+a value of one from <tt>x</tt>.
+Therefore, the outcome:
+<blockquote>
+<pre>
+(r1 == 0 &amp;&amp; r2 == 1)
+</pre>
+</blockquote>
+cannot happen.
+
+<p>@@QQ@@
+Wait a minute!
+You said that updaters can make useful forward progress concurrently
+with readers, but pre-existing readers will block
+<tt>synchronize_rcu()</tt>!!!
+Just who are you trying to fool???
+<p>@@QQA@@
+First, if updaters do not wish to be blocked by readers, they can use
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt>, which will
+be discussed later.
+Second, even when using <tt>synchronize_rcu()</tt>, the other
+update-side code does run concurrently with readers, whether pre-existing
+or not.
+<p>@@QQE@@
+
+<p>
+This scenario resembles one of the first uses of RCU in
+<a href="https://en.wikipedia.org/wiki/DYNIX">DYNIX/ptx</a>,
+which managed a distributed lock manager's transition into
+a state suitable for handling recovery from node failure,
+more or less as follows:
+
+<blockquote>
+<pre>
+ 1 #define STATE_NORMAL 0
+ 2 #define STATE_WANT_RECOVERY 1
+ 3 #define STATE_RECOVERING 2
+ 4 #define STATE_WANT_NORMAL 3
+ 5
+ 6 int state = STATE_NORMAL;
+ 7
+ 8 void do_something_dlm(void)
+ 9 {
+10 int state_snap;
+11
+12 rcu_read_lock();
+13 state_snap = READ_ONCE(state);
+14 if (state_snap == STATE_NORMAL)
+15 do_something();
+16 else
+17 do_something_carefully();
+18 rcu_read_unlock();
+19 }
+20
+21 void start_recovery(void)
+22 {
+23 WRITE_ONCE(state, STATE_WANT_RECOVERY);
+24 synchronize_rcu();
+25 WRITE_ONCE(state, STATE_RECOVERING);
+26 recovery();
+27 WRITE_ONCE(state, STATE_WANT_NORMAL);
+28 synchronize_rcu();
+29 WRITE_ONCE(state, STATE_NORMAL);
+30 }
+</pre>
+</blockquote>
+
+<p>
+The RCU read-side critical section in <tt>do_something_dlm()</tt>
+works with the <tt>synchronize_rcu()</tt> in <tt>start_recovery()</tt>
+to guarantee that <tt>do_something()</tt> never runs concurrently
+with <tt>recovery()</tt>, but with little or no synchronization
+overhead in <tt>do_something_dlm()</tt>.
+
+<p>@@QQ@@
+Why is the <tt>synchronize_rcu()</tt> on line&nbsp;28 needed?
+<p>@@QQA@@
+Without that extra grace period, memory reordering could result in
+<tt>do_something_dlm()</tt> executing <tt>do_something()</tt>
+concurrently with the last bits of <tt>recovery()</tt>.
+<p>@@QQE@@
+
+<p>
+In order to avoid fatal problems such as deadlocks,
+an RCU read-side critical section must not contain calls to
+<tt>synchronize_rcu()</tt>.
+Similarly, an RCU read-side critical section must not
+contain anything that waits, directly or indirectly, on completion of
+an invocation of <tt>synchronize_rcu()</tt>.
+
+<p>
+Although RCU's grace-period guarantee is useful in and of itself, with
+<a href="https://lwn.net/Articles/573497/">quite a few use cases</a>,
+it would be good to be able to use RCU to coordinate read-side
+access to linked data structures.
+For this, the grace-period guarantee is not sufficient, as can
+be seen in function <tt>add_gp_buggy()</tt> below.
+We will look at the reader's code later, but in the meantime, just think of
+the reader as locklessly picking up the <tt>gp</tt> pointer,
+and, if the value loaded is non-<tt>NULL</tt>, locklessly accessing the
+<tt>-&gt;a</tt> and <tt>-&gt;b</tt> fields.
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 p-&gt;a = a;
+12 p-&gt;b = a;
+13 gp = p; /* ORDERING BUG */
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The problem is that both the compiler and weakly ordered CPUs are within
+their rights to reorder this code as follows:
+
+<blockquote>
+<pre>
+ 1 bool add_gp_buggy_optimized(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+<b>11 gp = p; /* ORDERING BUG */
+12 p-&gt;a = a;
+13 p-&gt;b = a;</b>
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+If an RCU reader fetches <tt>gp</tt> just after
+<tt>add_gp_buggy_optimized</tt> executes line&nbsp;11,
+it will see garbage in the <tt>-&gt;a</tt> and <tt>-&gt;b</tt>
+fields.
+And this is but one of many ways in which compiler and hardware optimizations
+could cause trouble.
+Therefore, we clearly need some way to prevent the compiler and the CPU from
+reordering in this manner, which brings us to the publish-subscribe
+guarantee discussed in the next section.
+
+<h3><a name="Publish-Subscribe Guarantee">Publish/Subscribe Guarantee</a></h3>
+
+<p>
+RCU's publish-subscribe guarantee allows data to be inserted
+into a linked data structure without disrupting RCU readers.
+The updater uses <tt>rcu_assign_pointer()</tt> to insert the
+new data, and readers use <tt>rcu_dereference()</tt> to
+access data, whether new or old.
+The following shows an example of insertion:
+
+<blockquote>
+<pre>
+ 1 bool add_gp(int a, int b)
+ 2 {
+ 3 p = kmalloc(sizeof(*p), GFP_KERNEL);
+ 4 if (!p)
+ 5 return -ENOMEM;
+ 6 spin_lock(&amp;gp_lock);
+ 7 if (rcu_access_pointer(gp)) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 p-&gt;a = a;
+12 p-&gt;b = a;
+13 rcu_assign_pointer(gp, p);
+14 spin_unlock(&amp;gp_lock);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_assign_pointer()</tt> on line&nbsp;13 is conceptually
+equivalent to a simple assignment statement, but also guarantees
+that its assignment will
+happen after the two assignments in lines&nbsp;11 and&nbsp;12,
+similar to the C11 <tt>memory_order_release</tt> store operation.
+It also prevents any number of &ldquo;interesting&rdquo; compiler
+optimizations, for example, the use of <tt>gp</tt> as a scratch
+location immediately preceding the assignment.
+
+<p>@@QQ@@
+But <tt>rcu_assign_pointer()</tt> does nothing to prevent the
+two assignments to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt>
+from being reordered.
+Can't that also cause problems?
+<p>@@QQA@@
+No, it cannot.
+The readers cannot see either of these two fields until
+the assignment to <tt>gp</tt>, by which time both fields are
+fully initialized.
+So reordering the assignments
+to <tt>p-&gt;a</tt> and <tt>p-&gt;b</tt> cannot possibly
+cause any problems.
+<p>@@QQE@@
+
+<p>
+It is tempting to assume that the reader need not do anything special
+to control its accesses to the RCU-protected data,
+as shown in <tt>do_something_gp_buggy()</tt> below:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 p = gp; /* OPTIMIZATIONS GALORE!!! */
+ 5 if (p) {
+ 6 do_something(p-&gt;a, p-&gt;b);
+ 7 rcu_read_unlock();
+ 8 return true;
+ 9 }
+10 rcu_read_unlock();
+11 return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+However, this temptation must be resisted because there are a
+surprisingly large number of ways that the compiler
+(to say nothing of
+<a href="https://h71000.www7.hp.com/wizard/wiz_2637.html">DEC Alpha CPUs</a>)
+can trip this code up.
+For but one example, if the compiler were short of registers, it
+might choose to refetch from <tt>gp</tt> rather than keeping
+a separate copy in <tt>p</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp_buggy_optimized(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 if (gp) { /* OPTIMIZATIONS GALORE!!! */
+<b> 5 do_something(gp-&gt;a, gp-&gt;b);</b>
+ 6 rcu_read_unlock();
+ 7 return true;
+ 8 }
+ 9 rcu_read_unlock();
+10 return false;
+11 }
+</pre>
+</blockquote>
+
+<p>
+If this function ran concurrently with a series of updates that
+replaced the current structure with a new one,
+the fetches of <tt>gp-&gt;a</tt>
+and <tt>gp-&gt;b</tt> might well come from two different structures,
+which could cause serious confusion.
+To prevent this (and much else besides), <tt>do_something_gp()</tt> uses
+<tt>rcu_dereference()</tt> to fetch from <tt>gp</tt>:
+
+<blockquote>
+<pre>
+ 1 bool do_something_gp(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 p = rcu_dereference(gp);
+ 5 if (p) {
+ 6 do_something(p-&gt;a, p-&gt;b);
+ 7 rcu_read_unlock();
+ 8 return true;
+ 9 }
+10 rcu_read_unlock();
+11 return false;
+12 }
+</pre>
+</blockquote>
+
+<p>
+The <tt>rcu_dereference()</tt> uses volatile casts and (for DEC Alpha)
+memory barriers in the Linux kernel.
+Should a
+<a href="http://www.rdrop.com/users/paulmck/RCU/consume.2015.07.13a.pdf">high-quality implementation of C11 <tt>memory_order_consume</tt> [PDF]</a>
+ever appear, then <tt>rcu_dereference()</tt> could be implemented
+as a <tt>memory_order_consume</tt> load.
+Regardless of the exact implementation, a pointer fetched by
+<tt>rcu_dereference()</tt> may not be used outside of the
+outermost RCU read-side critical section containing that
+<tt>rcu_dereference()</tt>, unless protection of
+the corresponding data element has been passed from RCU to some
+other synchronization mechanism, most commonly locking or
+<a href="https://www.kernel.org/doc/Documentation/RCU/rcuref.txt">reference counting</a>.
+
+<p>
+In short, updaters use <tt>rcu_assign_pointer()</tt> and readers
+use <tt>rcu_dereference()</tt>, and these two RCU API elements
+work together to ensure that readers have a consistent view of
+newly added data elements.
+
+<p>
+Of course, it is also necessary to remove elements from RCU-protected
+data structures, for example, using the following process:
+
+<ol>
+<li> Remove the data element from the enclosing structure.
+<li> Wait for all pre-existing RCU read-side critical sections
+ to complete (because only pre-existing readers can possibly have
+ a reference to the newly removed data element).
+<li> At this point, only the updater has a reference to the
+ newly removed data element, so it can safely reclaim
+ the data element, for example, by passing it to <tt>kfree()</tt>.
+</ol>
+
+This process is implemented by <tt>remove_gp_synchronous()</tt>:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_synchronous(void)
+ 2 {
+ 3 struct foo *p;
+ 4
+ 5 spin_lock(&amp;gp_lock);
+ 6 p = rcu_access_pointer(gp);
+ 7 if (!p) {
+ 8 spin_unlock(&amp;gp_lock);
+ 9 return false;
+10 }
+11 rcu_assign_pointer(gp, NULL);
+12 spin_unlock(&amp;gp_lock);
+13 synchronize_rcu();
+14 kfree(p);
+15 return true;
+16 }
+</pre>
+</blockquote>
+
+<p>
+This function is straightforward, with line&nbsp;13 waiting for a grace
+period before line&nbsp;14 frees the old data element.
+This waiting ensures that readers will reach line&nbsp;7 of
+<tt>do_something_gp()</tt> before the data element referenced by
+<tt>p</tt> is freed.
+The <tt>rcu_access_pointer()</tt> on line&nbsp;6 is similar to
+<tt>rcu_dereference()</tt>, except that:
+
+<ol>
+<li> The value returned by <tt>rcu_access_pointer()</tt>
+ cannot be dereferenced.
+ If you want to access the value pointed to as well as
+ the pointer itself, use <tt>rcu_dereference()</tt>
+ instead of <tt>rcu_access_pointer()</tt>.
+<li> The call to <tt>rcu_access_pointer()</tt> need not be
+ protected.
+ In contrast, <tt>rcu_dereference()</tt> must either be
+ within an RCU read-side critical section or in a code
+ segment where the pointer cannot change, for example, in
+ code protected by the corresponding update-side lock.
+</ol>
+
+<p>@@QQ@@
+Without the <tt>rcu_dereference()</tt> or the
+<tt>rcu_access_pointer()</tt>, what destructive optimizations
+might the compiler make use of?
+<p>@@QQA@@
+Let's start with what happens to <tt>do_something_gp()</tt>
+if it fails to use <tt>rcu_dereference()</tt>.
+It could reuse a value formerly fetched from this same pointer.
+It could also fetch the pointer from <tt>gp</tt> in a byte-at-a-time
+manner, resulting in <i>load tearing</i>, in turn resulting a bytewise
+mash-up of two distince pointer values.
+It might even use value-speculation optimizations, where it makes a wrong
+guess, but by the time it gets around to checking the value, an update
+has changed the pointer to match the wrong guess.
+Too bad about any dereferences that returned pre-initialization garbage
+in the meantime!
+
+<p>
+For <tt>remove_gp_synchronous()</tt>, as long as all modifications
+to <tt>gp</tt> are carried out while holding <tt>gp_lock</tt>,
+the above optimizations are harmless.
+However,
+with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt>,
+<tt>sparse</tt> will complain if you
+define <tt>gp</tt> with <tt>__rcu</tt> and then
+access it without using
+either <tt>rcu_access_pointer()</tt> or <tt>rcu_dereference()</tt>.
+<p>@@QQE@@
+
+<p>
+In short, RCU's publish-subscribe guarantee is provided by the combination
+of <tt>rcu_assign_pointer()</tt> and <tt>rcu_dereference()</tt>.
+This guarantee allows data elements to be safely added to RCU-protected
+linked data structures without disrupting RCU readers.
+This guarantee can be used in combination with the grace-period
+guarantee to also allow data elements to be removed from RCU-protected
+linked data structures, again without disrupting RCU readers.
+
+<p>
+This guarantee was only partially premeditated.
+DYNIX/ptx used an explicit memory barrier for publication, but had nothing
+resembling <tt>rcu_dereference()</tt> for subscription, nor did it
+have anything resembling the <tt>smp_read_barrier_depends()</tt>
+that was later subsumed into <tt>rcu_dereference()</tt>.
+The need for these operations made itself known quite suddenly at a
+late-1990s meeting with the DEC Alpha architects, back in the days when
+DEC was still a free-standing company.
+It took the Alpha architects a good hour to convince me that any sort
+of barrier would ever be needed, and it then took me a good <i>two</i> hours
+to convince them that their documentation did not make this point clear.
+More recent work with the C and C++ standards committees have provided
+much education on tricks and traps from the compiler.
+In short, compilers were much less tricky in the early 1990s, but in
+2015, don't even think about omitting <tt>rcu_dereference()</tt>!
+
+<h3><a name="Memory-Barrier Guarantees">Memory-Barrier Guarantees</a></h3>
+
+<p>
+The previous section's simple linked-data-structure scenario clearly
+demonstrates the need for RCU's stringent memory-ordering guarantees on
+systems with more than one CPU:
+
+<ol>
+<li> Each CPU that has an RCU read-side critical section that
+ begins before <tt>synchronize_rcu()</tt> starts is
+ guaranteed to execute a full memory barrier between the time
+ that the RCU read-side critical section ends and the time that
+ <tt>synchronize_rcu()</tt> returns.
+ Without this guarantee, a pre-existing RCU read-side critical section
+ might hold a reference to the newly removed <tt>struct foo</tt>
+ after the <tt>kfree()</tt> on line&nbsp;14 of
+ <tt>remove_gp_synchronous()</tt>.
+<li> Each CPU that has an RCU read-side critical section that ends
+ after <tt>synchronize_rcu()</tt> returns is guaranteed
+ to execute a full memory barrier between the time that
+ <tt>synchronize_rcu()</tt> begins and the time that the RCU
+ read-side critical section begins.
+ Without this guarantee, a later RCU read-side critical section
+ running after the <tt>kfree()</tt> on line&nbsp;14 of
+ <tt>remove_gp_synchronous()</tt> might
+ later run <tt>do_something_gp()</tt> and find the
+ newly deleted <tt>struct foo</tt>.
+<li> If the task invoking <tt>synchronize_rcu()</tt> remains
+ on a given CPU, then that CPU is guaranteed to execute a full
+ memory barrier sometime during the execution of
+ <tt>synchronize_rcu()</tt>.
+ This guarantee ensures that the <tt>kfree()</tt> on
+ line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+ execute after the removal on line&nbsp;11.
+<li> If the task invoking <tt>synchronize_rcu()</tt> migrates
+ among a group of CPUs during that invocation, then each of the
+ CPUs in that group is guaranteed to execute a full memory barrier
+ sometime during the execution of <tt>synchronize_rcu()</tt>.
+ This guarantee also ensures that the <tt>kfree()</tt> on
+ line&nbsp;14 of <tt>remove_gp_synchronous()</tt> really does
+ execute after the removal on
+ line&nbsp;11, but also in the case where the thread executing the
+ <tt>synchronize_rcu()</tt> migrates in the meantime.
+</ol>
+
+<p>@@QQ@@
+Given that multiple CPUs can start RCU read-side critical sections
+at any time without any ordering whatsoever, how can RCU possibly tell whether
+or not a given RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>?
+<p>@@QQA@@
+If RCU cannot tell whether or not a given
+RCU read-side critical section starts before a
+given instance of <tt>synchronize_rcu()</tt>,
+then it must assume that the RCU read-side critical section
+started first.
+In other words, a given instance of <tt>synchronize_rcu()</tt>
+can avoid waiting on a given RCU read-side critical section only
+if it can prove that <tt>synchronize_rcu()</tt> started first.
+<p>@@QQE@@
+
+<p>@@QQ@@
+The first and second guarantees require unbelievably strict ordering!
+Are all these memory barriers <i> really</i> required?
+<p>@@QQA@@
+Yes, they really are required.
+To see why the first guarantee is required, consider the following
+sequence of events:
+
+<ol>
+<li> CPU 1: <tt>rcu_read_lock()</tt>
+<li> CPU 1: <tt>q = rcu_dereference(gp);
+ /* Very likely to return p. */</tt>
+<li> CPU 0: <tt>list_del_rcu(p);</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li> CPU 1: <tt>do_something_with(q-&gt;a);
+ /* No smp_mb(), so might happen after kfree(). */</tt>
+<li> CPU 1: <tt>rcu_read_unlock()</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li> CPU 0: <tt>kfree(p);</tt>
+</ol>
+
+<p>
+Therefore, there absolutely must be a full memory barrier between the
+end of the RCU read-side critical section and the end of the
+grace period.
+
+<p>
+The sequence of events demonstrating the necessity of the second rule
+is roughly similar:
+
+<ol>
+<li> CPU 0: <tt>list_del_rcu(p);</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> starts.
+<li> CPU 1: <tt>rcu_read_lock()</tt>
+<li> CPU 1: <tt>q = rcu_dereference(gp);
+ /* Might return p if no memory barrier. */</tt>
+<li> CPU 0: <tt>synchronize_rcu()</tt> returns.
+<li> CPU 0: <tt>kfree(p);</tt>
+<li> CPU 1: <tt>do_something_with(q-&gt;a); /* Boom!!! */</tt>
+<li> CPU 1: <tt>rcu_read_unlock()</tt>
+</ol>
+
+<p>
+And similarly, without a memory barrier between the beginning of the
+grace period and the beginning of the RCU read-side critical section,
+CPU&nbsp;1 might end up accessing the freelist.
+
+<p>
+The &ldquo;as if&rdquo; rule of course applies, so that any implementation
+that acts as if the appropriate memory barriers were in place is a
+correct implementation.
+That said, it is much easier to fool yourself into believing that you have
+adhered to the as-if rule than it is to actually adhere to it!
+<p>@@QQE@@
+
+<p>
+Note that these memory-barrier requirements do not replace the fundamental
+RCU requirement that a grace period wait for all pre-existing readers.
+On the contrary, the memory barriers called out in this section must operate in
+such a way as to <i>enforce</i> this fundamental requirement.
+Of course, different implementations enforce this requirement in different
+ways, but enforce it they must.
+
+<h3><a name="RCU Primitives Guaranteed to Execute Unconditionally">RCU Primitives Guaranteed to Execute Unconditionally</a></h3>
+
+<p>
+The common-case RCU primitives are unconditional.
+They are invoked, they do their job, and they return, with no possibility
+of error, and no need to retry.
+This is a key RCU design philosophy.
+
+<p>
+However, this philosophy is pragmatic rather than pigheaded.
+If someone comes up with a good justification for a particular conditional
+RCU primitive, it might well be implemented and added.
+After all, this guarantee was reverse-engineered, not premeditated.
+The unconditional nature of the RCU primitives was initially an
+accident of implementation, and later experience with synchronization
+primitives with conditional primitives caused me to elevate this
+accident to a guarantee.
+Therefore, the justification for adding a conditional primitive to
+RCU would need to be based on detailed and compelling use cases.
+
+<h3><a name="Guaranteed Read-to-Write Upgrade">Guaranteed Read-to-Write Upgrade</a></h3>
+
+<p>
+As far as RCU is concerned, it is always possible to carry out an
+update within an RCU read-side critical section.
+For example, that RCU read-side critical section might search for
+a given data element, and then might acquire the update-side
+spinlock in order to update that element, all while remaining
+in that RCU read-side critical section.
+Of course, it is necessary to exit the RCU read-side critical section
+before invoking <tt>synchronize_rcu()</tt>, however, this
+inconvenience can be avoided through use of the
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt> API members
+described later in this document.
+
+<p>@@QQ@@
+But how does the upgrade-to-write operation exclude other readers?
+<p>@@QQA@@
+It doesn't, just like normal RCU updates, which also do not exclude
+RCU readers.
+<p>@@QQE@@
+
+<p>
+This guarantee allows lookup code to be shared between read-side
+and update-side code, and was premeditated, appearing in the earliest
+DYNIX/ptx RCU documentation.
+
+<h2><a name="Fundamental Non-Requirements">Fundamental Non-Requirements</a></h2>
+
+<p>
+RCU provides extremely lightweight readers, and its read-side guarantees,
+though quite useful, are correspondingly lightweight.
+It is therefore all too easy to assume that RCU is guaranteeing more
+than it really is.
+Of course, the list of things that RCU does not guarantee is infinitely
+long, however, the following sections list a few non-guarantees that
+have caused confusion.
+Except where otherwise noted, these non-guarantees were premeditated.
+
+<ol>
+<li> <a href="#Readers Impose Minimal Ordering">
+ Readers Impose Minimal Ordering</a>
+<li> <a href="#Readers Do Not Exclude Updaters">
+ Readers Do Not Exclude Updaters</a>
+<li> <a href="#Updaters Only Wait For Old Readers">
+ Updaters Only Wait For Old Readers</a>
+<li> <a href="#Grace Periods Don't Partition Read-Side Critical Sections">
+ Grace Periods Don't Partition Read-Side Critical Sections</a>
+<li> <a href="#Read-Side Critical Sections Don't Partition Grace Periods">
+ Read-Side Critical Sections Don't Partition Grace Periods</a>
+<li> <a href="#Disabling Preemption Does Not Block Grace Periods">
+ Disabling Preemption Does Not Block Grace Periods</a>
+</ol>
+
+<h3><a name="Readers Impose Minimal Ordering">Readers Impose Minimal Ordering</a></h3>
+
+<p>
+Reader-side markers such as <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> provide absolutely no ordering guarantees
+except through their interaction with the grace-period APIs such as
+<tt>synchronize_rcu()</tt>.
+To see this, consider the following pair of threads:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(x, 1);
+ 5 rcu_read_unlock();
+ 6 rcu_read_lock();
+ 7 WRITE_ONCE(y, 1);
+ 8 rcu_read_unlock();
+ 9 }
+10
+11 void thread1(void)
+12 {
+13 rcu_read_lock();
+14 r1 = READ_ONCE(y);
+15 rcu_read_unlock();
+16 rcu_read_lock();
+17 r2 = READ_ONCE(x);
+18 rcu_read_unlock();
+19 }
+</pre>
+</blockquote>
+
+<p>
+After <tt>thread0()</tt> and <tt>thread1()</tt> execute
+concurrently, it is quite possible to have
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0)
+</pre>
+</blockquote>
+
+(that is, <tt>y</tt> appears to have been assigned before <tt>x</tt>),
+which would not be possible if <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> had much in the way of ordering
+properties.
+But they do not, so the CPU is within its rights
+to do significant reordering.
+This is by design: Any significant ordering constraints would slow down
+these fast-path APIs.
+
+<p>@@QQ@@
+Can't the compiler also reorder this code?
+<p>@@QQA@@
+No, the volatile casts in <tt>READ_ONCE()</tt> and
+<tt>WRITE_ONCE()</tt> prevent the compiler from reordering in
+this particular case.
+<p>@@QQE@@
+
+<h3><a name="Readers Do Not Exclude Updaters">Readers Do Not Exclude Updaters</a></h3>
+
+<p>
+Neither <tt>rcu_read_lock()</tt> nor <tt>rcu_read_unlock()</tt>
+exclude updates.
+All they do is to prevent grace periods from ending.
+The following example illustrates this:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 r1 = READ_ONCE(y);
+ 5 if (r1) {
+ 6 do_something_with_nonzero_x();
+ 7 r2 = READ_ONCE(x);
+ 8 WARN_ON(!r2); /* BUG!!! */
+ 9 }
+10 rcu_read_unlock();
+11 }
+12
+13 void thread1(void)
+14 {
+15 spin_lock(&amp;my_lock);
+16 WRITE_ONCE(x, 1);
+17 WRITE_ONCE(y, 1);
+18 spin_unlock(&amp;my_lock);
+19 }
+</pre>
+</blockquote>
+
+<p>
+If the <tt>thread0()</tt> function's <tt>rcu_read_lock()</tt>
+excluded the <tt>thread1()</tt> function's update,
+the <tt>WARN_ON()</tt> could never fire.
+But the fact is that <tt>rcu_read_lock()</tt> does not exclude
+much of anything aside from subsequent grace periods, of which
+<tt>thread1()</tt> has none, so the
+<tt>WARN_ON()</tt> can and does fire.
+
+<h3><a name="Updaters Only Wait For Old Readers">Updaters Only Wait For Old Readers</a></h3>
+
+<p>
+It might be tempting to assume that after <tt>synchronize_rcu()</tt>
+completes, there are no readers executing.
+This temptation must be avoided because
+new readers can start immediately after <tt>synchronize_rcu()</tt>
+starts, and <tt>synchronize_rcu()</tt> is under no
+obligation to wait for these new readers.
+
+<p>@@QQ@@
+Suppose that synchronize_rcu() did wait until all readers had completed.
+Would the updater be able to rely on this?
+<p>@@QQA@@
+No.
+Even if <tt>synchronize_rcu()</tt> were to wait until
+all readers had completed, a new reader might start immediately after
+<tt>synchronize_rcu()</tt> completed.
+Therefore, the code following
+<tt>synchronize_rcu()</tt> cannot rely on there being no readers
+in any case.
+<p>@@QQE@@
+
+<h3><a name="Grace Periods Don't Partition Read-Side Critical Sections">
+Grace Periods Don't Partition Read-Side Critical Sections</a></h3>
+
+<p>
+It is tempting to assume that if any part of one RCU read-side critical
+section precedes a given grace period, and if any part of another RCU
+read-side critical section follows that same grace period, then all of
+the first RCU read-side critical section must precede all of the second.
+However, this just isn't the case: A single grace period does not
+partition the set of RCU read-side critical sections.
+An example of this situation can be illustrated as follows, where
+<tt>x</tt>, <tt>y</tt>, and <tt>z</tt> are initially all zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 rcu_read_lock();
+19 r2 = READ_ONCE(b);
+20 r3 = READ_ONCE(c);
+21 rcu_read_unlock();
+22 }
+</pre>
+</blockquote>
+
+<p>
+It turns out that the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 0 &amp;&amp; r3 == 1)
+</pre>
+</blockquote>
+
+is entirely possible.
+The following figure show how this can happen, with each circled
+<tt>QS</tt> indicating the point at which RCU recorded a
+<i>quiescent state</i> for each thread, that is, a state in which
+RCU knows that the thread cannot be in the midst of an RCU read-side
+critical section that started before the current grace period:
+
+<p><img src="GPpartitionReaders1.svg" alt="GPpartitionReaders1.svg" width="60%"></p>
+
+<p>
+If it is necessary to partition RCU read-side critical sections in this
+manner, it is necessary to use two grace periods, where the first
+grace period is known to end before the second grace period starts:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 r2 = READ_ONCE(c);
+19 synchronize_rcu();
+20 WRITE_ONCE(d, 1);
+21 }
+22
+23 void thread3(void)
+24 {
+25 rcu_read_lock();
+26 r3 = READ_ONCE(b);
+27 r4 = READ_ONCE(d);
+28 rcu_read_unlock();
+29 }
+</pre>
+</blockquote>
+
+<p>
+Here, if <tt>(r1 == 1)</tt>, then
+<tt>thread0()</tt>'s write to <tt>b</tt> must happen
+before the end of <tt>thread1()</tt>'s grace period.
+If in addition <tt>(r4 == 1)</tt>, then
+<tt>thread3()</tt>'s read from <tt>b</tt> must happen
+after the beginning of <tt>thread2()</tt>'s grace period.
+If it is also the case that <tt>(r2 == 1)</tt>, then the
+end of <tt>thread1()</tt>'s grace period must precede the
+beginning of <tt>thread2()</tt>'s grace period.
+This mean that the two RCU read-side critical sections cannot overlap,
+guaranteeing that <tt>(r3 == 1)</tt>.
+As a result, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 0 &amp;&amp; r4 == 1)
+</pre>
+</blockquote>
+
+cannot happen.
+
+<p>
+This non-requirement was also non-premeditated, but became apparent
+when studying RCU's interaction with memory ordering.
+
+<h3><a name="Read-Side Critical Sections Don't Partition Grace Periods">
+Read-Side Critical Sections Don't Partition Grace Periods</a></h3>
+
+<p>
+It is also tempting to assume that if an RCU read-side critical section
+happens between a pair of grace periods, then those grace periods cannot
+overlap.
+However, this temptation leads nowhere good, as can be illustrated by
+the following, with all variables initially zero:
+
+<blockquote>
+<pre>
+ 1 void thread0(void)
+ 2 {
+ 3 rcu_read_lock();
+ 4 WRITE_ONCE(a, 1);
+ 5 WRITE_ONCE(b, 1);
+ 6 rcu_read_unlock();
+ 7 }
+ 8
+ 9 void thread1(void)
+10 {
+11 r1 = READ_ONCE(a);
+12 synchronize_rcu();
+13 WRITE_ONCE(c, 1);
+14 }
+15
+16 void thread2(void)
+17 {
+18 rcu_read_lock();
+19 WRITE_ONCE(d, 1);
+20 r2 = READ_ONCE(c);
+21 rcu_read_unlock();
+22 }
+23
+24 void thread3(void)
+25 {
+26 r3 = READ_ONCE(d);
+27 synchronize_rcu();
+28 WRITE_ONCE(e, 1);
+29 }
+30
+31 void thread4(void)
+32 {
+33 rcu_read_lock();
+34 r4 = READ_ONCE(b);
+35 r5 = READ_ONCE(e);
+36 rcu_read_unlock();
+37 }
+</pre>
+</blockquote>
+
+<p>
+In this case, the outcome:
+
+<blockquote>
+<pre>
+(r1 == 1 &amp;&amp; r2 == 1 &amp;&amp; r3 == 1 &amp;&amp; r4 == 0 &amp&amp; r5 == 1)
+</pre>
+</blockquote>
+
+is entirely possible, as illustrated below:
+
+<p><img src="ReadersPartitionGP1.svg" alt="ReadersPartitionGP1.svg" width="100%"></p>
+
+<p>
+Again, an RCU read-side critical section can overlap almost all of a
+given grace period, just so long as it does not overlap the entire
+grace period.
+As a result, an RCU read-side critical section cannot partition a pair
+of RCU grace periods.
+
+<p>@@QQ@@
+How long a sequence of grace periods, each separated by an RCU read-side
+critical section, would be required to partition the RCU read-side
+critical sections at the beginning and end of the chain?
+<p>@@QQA@@
+In theory, an infinite number.
+In practice, an unknown number that is sensitive to both implementation
+details and timing considerations.
+Therefore, even in practice, RCU users must abide by the theoretical rather
+than the practical answer.
+<p>@@QQE@@
+
+<h3><a name="Disabling Preemption Does Not Block Grace Periods">
+Disabling Preemption Does Not Block Grace Periods</a></h3>
+
+<p>
+There was a time when disabling preemption on any given CPU would block
+subsequent grace periods.
+However, this was an accident of implementation and is not a requirement.
+And in the current Linux-kernel implementation, disabling preemption
+on a given CPU in fact does not block grace periods, as Oleg Nesterov
+<a href="https://lkml.kernel.org/g/20150614193825.GA19582@redhat.com">demonstrated</a>.
+
+<p>
+If you need a preempt-disable region to block grace periods, you need to add
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>, for example
+as follows:
+
+<blockquote>
+<pre>
+ 1 preempt_disable();
+ 2 rcu_read_lock();
+ 3 do_something();
+ 4 rcu_read_unlock();
+ 5 preempt_enable();
+ 6
+ 7 /* Spinlocks implicitly disable preemption. */
+ 8 spin_lock(&amp;mylock);
+ 9 rcu_read_lock();
+10 do_something();
+11 rcu_read_unlock();
+12 spin_unlock(&amp;mylock);
+</pre>
+</blockquote>
+
+<p>
+In theory, you could enter the RCU read-side critical section first,
+but it is more efficient to keep the entire RCU read-side critical
+section contained in the preempt-disable region as shown above.
+Of course, RCU read-side critical sections that extend outside of
+preempt-disable regions will work correctly, but such critical sections
+can be preempted, which forces <tt>rcu_read_unlock()</tt> to do
+more work.
+And no, this is <i>not</i> an invitation to enclose all of your RCU
+read-side critical sections within preempt-disable regions, because
+doing so would degrade real-time response.
+
+<p>
+This non-requirement appeared with preemptible RCU.
+If you need a grace period that waits on non-preemptible code regions, use
+<a href="#Sched Flavor">RCU-sched</a>.
+
+<h2><a name="Parallelism Facts of Life">Parallelism Facts of Life</a></h2>
+
+<p>
+These parallelism facts of life are by no means specific to RCU, but
+the RCU implementation must abide by them.
+They therefore bear repeating:
+
+<ol>
+<li> Any CPU or task may be delayed at any time,
+ and any attempts to avoid these delays by disabling
+ preemption, interrupts, or whatever are completely futile.
+ This is most obvious in preemptible user-level
+ environments and in virtualized environments (where
+ a given guest OS's VCPUs can be preempted at any time by
+ the underlying hypervisor), but can also happen in bare-metal
+ environments due to ECC errors, NMIs, and other hardware
+ events.
+ Although a delay of more than about 20 seconds can result
+ in splats, the RCU implementation is obligated to use
+ algorithms that can tolerate extremely long delays, but where
+ &ldquo;extremely long&rdquo; is not long enough to allow
+ wrap-around when incrementing a 64-bit counter.
+<li> Both the compiler and the CPU can reorder memory accesses.
+ Where it matters, RCU must use compiler directives and
+ memory-barrier instructions to preserve ordering.
+<li> Conflicting writes to memory locations in any given cache line
+ will result in expensive cache misses.
+ Greater numbers of concurrent writes and more-frequent
+ concurrent writes will result in more dramatic slowdowns.
+ RCU is therefore obligated to use algorithms that have
+ sufficient locality to avoid significant performance and
+ scalability problems.
+<li> As a rough rule of thumb, only one CPU's worth of processing
+ may be carried out under the protection of any given exclusive
+ lock.
+ RCU must therefore use scalable locking designs.
+<li> Counters are finite, especially on 32-bit systems.
+ RCU's use of counters must therefore tolerate counter wrap,
+ or be designed such that counter wrap would take way more
+ time than a single system is likely to run.
+ An uptime of ten years is quite possible, a runtime
+ of a century much less so.
+ As an example of the latter, RCU's dyntick-idle nesting counter
+ allows 54 bits for interrupt nesting level (this counter
+ is 64 bits even on a 32-bit system).
+ Overflowing this counter requires 2<sup>54</sup>
+ half-interrupts on a given CPU without that CPU ever going idle.
+ If a half-interrupt happened every microsecond, it would take
+ 570 years of runtime to overflow this counter, which is currently
+ believed to be an acceptably long time.
+<li> Linux systems can have thousands of CPUs running a single
+ Linux kernel in a single shared-memory environment.
+ RCU must therefore pay close attention to high-end scalability.
+</ol>
+
+<p>
+This last parallelism fact of life means that RCU must pay special
+attention to the preceding facts of life.
+The idea that Linux might scale to systems with thousands of CPUs would
+have been met with some skepticism in the 1990s, but these requirements
+would have otherwise have been unsurprising, even in the early 1990s.
+
+<h2><a name="Quality-of-Implementation Requirements">Quality-of-Implementation Requirements</a></h2>
+
+<p>
+These sections list quality-of-implementation requirements.
+Although an RCU implementation that ignores these requirements could
+still be used, it would likely be subject to limitations that would
+make it inappropriate for industrial-strength production use.
+Classes of quality-of-implementation requirements are as follows:
+
+<ol>
+<li> <a href="#Specialization">Specialization</a>
+<li> <a href="#Performance and Scalability">Performance and Scalability</a>
+<li> <a href="#Composability">Composability</a>
+<li> <a href="#Corner Cases">Corner Cases</a>
+</ol>
+
+<p>
+These classes is covered in the following sections.
+
+<h3><a name="Specialization">Specialization</a></h3>
+
+<p>
+RCU is and always has been intended primarily for read-mostly situations, as
+illustrated by the following figure.
+This means that RCU's read-side primitives are optimized, often at the
+expense of its update-side primitives.
+
+<p><img src="RCUApplicability.svg" alt="RCUApplicability.svg" width="70%"></p>
+
+<p>
+This focus on read-mostly situations means that RCU must interoperate
+with other synchronization primitives.
+For example, the <tt>add_gp()</tt> and <tt>remove_gp_synchronous()</tt>
+examples discussed earlier use RCU to protect readers and locking to
+coordinate updaters.
+However, the need extends much farther, requiring that a variety of
+synchronization primitives be legal within RCU read-side critical sections,
+including spinlocks, sequence locks, atomic operations, reference
+counters, and memory barriers.
+
+<p>@@QQ@@
+What about sleeping locks?
+<p>@@QQA@@
+These are forbidden within Linux-kernel RCU read-side critical sections
+because it is not legal to place a quiescent state (in this case,
+voluntary context switch) within an RCU read-side critical section.
+However, sleeping locks may be used within userspace RCU read-side critical
+sections, and also within Linux-kernel sleepable RCU
+<a href="#Sleepable RCU">(SRCU)</a>
+read-side critical sections.
+In addition, the -rt patchset turns spinlocks into a sleeping locks so
+that the corresponding critical sections can be preempted, which
+also means that these sleeplockified spinlocks (but not other sleeping locks!)
+may be acquire within -rt-Linux-kernel RCU read-side critical sections.
+
+<p>
+Note that it <i>is</i> legal for a normal RCU read-side critical section
+to conditionally acquire a sleeping locks (as in <tt>mutex_trylock()</tt>),
+but only as long as it does not loop indefinitely attempting to
+conditionally acquire that sleeping locks.
+The key point is that things like <tt>mutex_trylock()</tt>
+either return with the mutex held, or return an error indication if
+the mutex was not immediately available.
+Either way, <tt>mutex_trylock()</tt> returns immediately without sleeping.
+<p>@@QQE@@
+
+<p>
+It often comes as a surprise that many algorithms do not require a
+consistent view of data, but many can function in that mode,
+with network routing being the poster child.
+Internet routing algorithms take significant time to propagate
+updates, so that by the time an update arrives at a given system,
+that system has been sending network traffic the wrong way for
+a considerable length of time.
+Having a few threads continue to send traffic the wrong way for a
+few more milliseconds is clearly not a problem: In the worst case,
+TCP retransmissions will eventually get the data where it needs to go.
+In general, when tracking the state of the universe outside of the
+computer, some level of inconsistency must be tolerated due to
+speed-of-light delays if nothing else.
+
+<p>
+Furthermore, uncertainty about external state is inherent in many cases.
+For example, a pair of veternarians might use heartbeat to determine
+whether or not a given cat was alive.
+But how long should they wait after the last heartbeat to decide that
+the cat is in fact dead?
+Waiting less than 400 milliseconds makes no sense because this would
+mean that a relaxed cat would be considered to cycle between death
+and life more than 100 times per minute.
+Moreover, just as with human beings, a cat's heart might stop for
+some period of time, so the exact wait period is a judgment call.
+One of our pair of veternarians might wait 30 seconds before pronouncing
+the cat dead, while the other might insist on waiting a full minute.
+The two veternarians would then disagree on the state of the cat during
+the final 30 seconds of the minute following the last heartbeat, as
+fancifully illustrated below:
+
+<p><img src="2013-08-is-it-dead.png" alt="2013-08-is-it-dead.png" width="431"></p>
+
+<p>
+Interestingly enough, this same situation applies to hardware.
+When push comes to shove, how do we tell whether or not some
+external server has failed?
+We send messages to it periodically, and declare it failed if we
+don't receive a response within a given period of time.
+Policy decisions can usually tolerate short
+periods of inconsistency.
+The policy was decided some time ago, and is only now being put into
+effect, so a few milliseconds of delay is normally inconsequential.
+
+<p>
+However, there are algorithms that absolutely must see consistent data.
+For example, the translation between a user-level SystemV semaphore
+ID to the corresponding in-kernel data structure is protected by RCU,
+but it is absolutely forbidden to update a semaphore that has just been
+removed.
+In the Linux kernel, this need for consistency is accommodated by acquiring
+spinlocks located in the in-kernel data structure from within
+the RCU read-side critical section, and this is indicated by the
+green box in the figure above.
+Many other techniques may be used, and are in fact used within the
+Linux kernel.
+
+<p>
+In short, RCU is not required to maintain consistency, and other
+mechanisms may be used in concert with RCU when consistency is required.
+RCU's specialization allows it to do its job extremely well, and its
+ability to interoperate with other synchronization mechanisms allows
+the right mix of synchronization tools to be used for a given job.
+
+<h3><a name="Performance and Scalability">Performance and Scalability</a></h3>
+
+<p>
+Energy efficiency is a critical component of performance today,
+and Linux-kernel RCU implementations must therefore avoid unnecessarily
+awakening idle CPUs.
+I cannot claim that this requirement was premeditated.
+In fact, I learned of it during a telephone conversation in which I
+was given &ldquo;frank and open&rdquo; feedback on the importance
+of energy efficiency in battery-powered systems and on specific
+energy-efficiency shortcomings of the Linux-kernel RCU implementation.
+In my experience, the battery-powered embedded community will consider
+any unnecessary wakeups to be extremely unfriendly acts.
+So much so that mere Linux-kernel-mailing-list posts are
+insufficient to vent their ire.
+
+<p>
+Memory consumption is not particularly important for in most
+situations, and has become decreasingly
+so as memory sizes have expanded and memory
+costs have plummeted.
+However, as I learned from Matt Mackall's
+<a href="http://elinux.org/Linux_Tiny-FAQ">bloatwatch</a>
+efforts, memory footprint is critically important on single-CPU systems with
+non-preemptible (<tt>CONFIG_PREEMPT=n</tt>) kernels, and thus
+<a href="https://lkml.kernel.org/g/20090113221724.GA15307@linux.vnet.ibm.com">tiny RCU</a>
+was born.
+Josh Triplett has since taken over the small-memory banner with his
+<a href="https://tiny.wiki.kernel.org/">Linux kernel tinification</a>
+project, which resulted in
+<a href="#Sleepable RCU">SRCU</a>
+becoming optional for those kernels not needing it.
+
+<p>
+The remaining performance requirements are, for the most part,
+unsurprising.
+For example, in keeping with RCU's read-side specialization,
+<tt>rcu_dereference()</tt> should have negligible overhead (for
+example, suppression of a few minor compiler optimizations).
+Similarly, in non-preemptible environments, <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have exactly zero overhead.
+
+<p>
+In preemptible environments, in the case where the RCU read-side
+critical section was not preempted (as will be the case for the
+highest-priority real-time process), <tt>rcu_read_lock()</tt> and
+<tt>rcu_read_unlock()</tt> should have minimal overhead.
+In particular, they should not contain atomic read-modify-write
+operations, memory-barrier instructions, preemption disabling,
+interrupt disabling, or backwards branches.
+However, in the case where the RCU read-side critical section was preempted,
+<tt>rcu_read_unlock()</tt> may acquire spinlocks and disable interrupts.
+This is why it is better to nest an RCU read-side critical section
+within a preempt-disable region than vice versa, at least in cases
+where that critical section is short enough to avoid unduly degrading
+real-time latencies.
+
+<p>
+The <tt>synchronize_rcu()</tt> grace-period-wait primitive is
+optimized for throughput.
+It may therefore incur several milliseconds of latency in addition to
+the duration of the longest RCU read-side critical section.
+On the other hand, multiple concurrent invocations of
+<tt>synchronize_rcu()</tt> are required to use batching optimizations
+so that they can be satisfied by a single underlying grace-period-wait
+operation.
+For example, in the Linux kernel, it is not unusual for a single
+grace-period-wait operation to serve more than
+<a href="https://www.usenix.org/conference/2004-usenix-annual-technical-conference/making-rcu-safe-deep-sub-millisecond-response">1,000 separate invocations</a>
+of <tt>synchronize_rcu()</tt>, thus amortizing the per-invocation
+overhead down to nearly zero.
+However, the grace-period optimization is also required to avoid
+measurable degradation of real-time scheduling and interrupt latencies.
+
+<p>
+In some cases, the multi-millisecond <tt>synchronize_rcu()</tt>
+latencies are unacceptable.
+In these cases, <tt>synchronize_rcu_expedited()</tt> may be used
+instead, reducing the grace-period latency down to a few tens of
+microseconds on small systems, at least in cases where the RCU read-side
+critical sections are short.
+There are currently no special latency requirements for
+<tt>synchronize_rcu_expedited()</tt> on large systems, but,
+consistent with the empirical nature of the RCU specification,
+that is subject to change.
+However, there most definitely are scalability requirements:
+A storm of <tt>synchronize_rcu_expedited()</tt> invocations on 4096
+CPUs should at least make reasonable forward progress.
+In return for its shorter latencies, <tt>synchronize_rcu_expedited()</tt>
+is permitted to impose modest degradation of real-time latency
+on non-idle online CPUs.
+That said, it will likely be necessary to take further steps to reduce this
+degradation, hopefully to roughly that of a scheduling-clock interrupt.
+
+<p>
+There are a number of situations where even
+<tt>synchronize_rcu_expedited()</tt>'s reduced grace-period
+latency is unacceptable.
+In these situations, the asynchronous <tt>call_rcu()</tt> can be
+used in place of <tt>synchronize_rcu()</tt> as follows:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2 int a;
+ 3 int b;
+ 4 struct rcu_head rh;
+ 5 };
+ 6
+ 7 static void remove_gp_cb(struct rcu_head *rhp)
+ 8 {
+ 9 struct foo *p = container_of(rhp, struct foo, rh);
+10
+11 kfree(p);
+12 }
+13
+14 bool remove_gp_asynchronous(void)
+15 {
+16 struct foo *p;
+17
+18 spin_lock(&amp;gp_lock);
+19 p = rcu_dereference(gp);
+20 if (!p) {
+21 spin_unlock(&amp;gp_lock);
+22 return false;
+23 }
+24 rcu_assign_pointer(gp, NULL);
+25 call_rcu(&amp;p-&gt;rh, remove_gp_cb);
+26 spin_unlock(&amp;gp_lock);
+27 return true;
+28 }
+</pre>
+</blockquote>
+
+<p>
+A definition of <tt>struct foo</tt> is finally needed, and appears
+on lines&nbsp;1-5.
+The function <tt>remove_gp_cb()</tt> is passed to <tt>call_rcu()</tt>
+on line&nbsp;25, and will be invoked after the end of a subsequent
+grace period.
+This gets the same effect as <tt>remove_gp_synchronous()</tt>,
+but without forcing the updater to wait for a grace period to elapse.
+The <tt>call_rcu()</tt> function may be used in a number of
+situations where neither <tt>synchronize_rcu()</tt> nor
+<tt>synchronize_rcu_expedited()</tt> would be legal,
+including within preempt-disable code, <tt>local_bh_disable()</tt> code,
+interrupt-disable code, and interrupt handlers.
+However, even <tt>call_rcu()</tt> is illegal within NMI handlers.
+The callback function (<tt>remove_gp_cb()</tt> in this case) will be
+executed within softirq (software interrupt) environment within the
+Linux kernel,
+either within a real softirq handler or under the protection
+of <tt>local_bh_disable()</tt>.
+In both the Linux kernel and in userspace, it is bad practice to
+write an RCU callback function that takes too long.
+Long-running operations should be relegated to separate threads or
+(in the Linux kernel) workqueues.
+
+<p>@@QQ@@
+Why does line&nbsp;19 use <tt>rcu_access_pointer()</tt>?
+After all, <tt>call_rcu()</tt> on line&nbsp;25 stores into the
+structure, which would interact badly with concurrent insertions.
+Doesn't this mean that <tt>rcu_dereference()</tt> is required?
+<p>@@QQA@@
+Presumably the <tt>-&gt;gp_lock</tt> acquired on line&nbsp;18 excludes
+any changes, including any insertions that <tt>rcu_dereference()</tt>
+would protect against.
+Therefore, any insertions will be delayed until after <tt>-&gt;gp_lock</tt>
+is released on line&nbsp;25, which in turn means that
+<tt>rcu_access_pointer()</tt> suffices.
+<p>@@QQE@@
+
+<p>
+However, all that <tt>remove_gp_cb()</tt> is doing is
+invoking <tt>kfree()</tt> on the data element.
+This is a common idiom, and is supported by <tt>kfree_rcu()</tt>,
+which allows &ldquo;fire and forget&rdquo; operation as shown below:
+
+<blockquote>
+<pre>
+ 1 struct foo {
+ 2 int a;
+ 3 int b;
+ 4 struct rcu_head rh;
+ 5 };
+ 6
+ 7 bool remove_gp_faf(void)
+ 8 {
+ 9 struct foo *p;
+10
+11 spin_lock(&amp;gp_lock);
+12 p = rcu_dereference(gp);
+13 if (!p) {
+14 spin_unlock(&amp;gp_lock);
+15 return false;
+16 }
+17 rcu_assign_pointer(gp, NULL);
+18 kfree_rcu(p, rh);
+19 spin_unlock(&amp;gp_lock);
+20 return true;
+21 }
+</pre>
+</blockquote>
+
+<p>
+Note that <tt>remove_gp_faf()</tt> simply invokes
+<tt>kfree_rcu()</tt> and proceeds, without any need to pay any
+further attention to the subsequent grace period and <tt>kfree()</tt>.
+It is permissible to invoke <tt>kfree_rcu()</tt> from the same
+environments as for <tt>call_rcu()</tt>.
+Interestingly enough, DYNIX/ptx had the equivalents of
+<tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>, but not
+<tt>synchronize_rcu()</tt>.
+This was due to the fact that RCU was not heavily used within DYNIX/ptx,
+so the very few places that needed something like
+<tt>synchronize_rcu()</tt> simply open-coded it.
+
+<p>@@QQ@@
+Earlier it was claimed that <tt>call_rcu()</tt> and
+<tt>kfree_rcu()</tt> allowed updaters to avoid being blocked
+by readers.
+But how can that be correct, given that the invocation of the callback
+and the freeing of the memory (respectively) must still wait for
+a grace period to elapse?
+<p>@@QQA@@
+We could define things this way, but keep in mind that this sort of
+definition would say that updates in garbage-collected languages
+cannot complete until the next time the garbage collector runs,
+which does not seem at all reasonable.
+The key point is that in most cases, an updater using either
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> can proceed to the
+next update as soon as it has invoked <tt>call_rcu()</tt> or
+<tt>kfree_rcu()</tt>, without having to wait for a subsequent
+grace period.
+<p>@@QQE@@
+
+<p>
+But what if the updater must wait for the completion of code to be
+executed after the end of the grace period, but has other tasks
+that can be carried out in the meantime?
+The polling-style <tt>get_state_synchronize_rcu()</tt> and
+<tt>cond_synchronize_rcu()</tt> functions may be used for this
+purpose, as shown below:
+
+<blockquote>
+<pre>
+ 1 bool remove_gp_poll(void)
+ 2 {
+ 3 struct foo *p;
+ 4 unsigned long s;
+ 5
+ 6 spin_lock(&amp;gp_lock);
+ 7 p = rcu_access_pointer(gp);
+ 8 if (!p) {
+ 9 spin_unlock(&amp;gp_lock);
+10 return false;
+11 }
+12 rcu_assign_pointer(gp, NULL);
+13 spin_unlock(&amp;gp_lock);
+14 s = get_state_synchronize_rcu();
+15 do_something_while_waiting();
+16 cond_synchronize_rcu(s);
+17 kfree(p);
+18 return true;
+19 }
+</pre>
+</blockquote>
+
+<p>
+On line&nbsp;14, <tt>get_state_synchronize_rcu()</tt> obtains a
+&ldquo;cookie&rdquo; from RCU,
+then line&nbsp;15 carries out other tasks,
+and finally, line&nbsp;16 returns immediately if a grace period has
+elapsed in the meantime, but otherwise waits as required.
+The need for <tt>get_state_synchronize_rcu</tt> and
+<tt>cond_synchronize_rcu()</tt> has appeared quite recently,
+so it is too early to tell whether they will stand the test of time.
+
+<p>
+RCU thus provides a range of tools to allow updaters to strike the
+required tradeoff between latency, flexibility and CPU overhead.
+
+<h3><a name="Composability">Composability</a></h3>
+
+<p>
+Composability has received much attention in recent years, perhaps in part
+due to the collision of multicore hardware with object-oriented techniques
+designed in single-threaded environments for single-threaded use.
+And in theory, RCU read-side critical sections may be composed, and in
+fact may be nested arbitrarily deeply.
+In practice, as with all real-world implementations of composable
+constructs, there are limitations.
+
+<p>
+Implementations of RCU for which <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> generate no code, such as
+Linux-kernel RCU when <tt>CONFIG_PREEMPT=n</tt>, can be
+nested arbitrarily deeply.
+After all, there is no overhead.
+Except that if all these instances of <tt>rcu_read_lock()</tt>
+and <tt>rcu_read_unlock()</tt> are visible to the compiler,
+compilation will eventually fail due to exhausting memory,
+mass storage, or user patience, whichever comes first.
+If the nesting is not visible to the compiler, as is the case with
+mutually recursive functions each in its own translation unit,
+stack overflow will result.
+If the nesting takes the form of loops, either the control variable
+will overflow or (in the Linux kernel) you will get an RCU CPU stall warning.
+Nevertheless, this class of RCU implementations is one
+of the most composable constructs in existence.
+
+<p>
+RCU implementations that explicitly track nesting depth
+are limited by the nesting-depth counter.
+For example, the Linux kernel's preemptible RCU limits nesting to
+<tt>INT_MAX</tt>.
+This should suffice for almost all practical purposes.
+That said, a consecutive pair of RCU read-side critical sections
+between which there is an operation that waits for a grace period
+cannot be enclosed in another RCU read-side critical section.
+This is because it is not legal to wait for a grace period within
+an RCU read-side critical section: To do so would result either
+in deadlock or
+in RCU implicitly splitting the enclosing RCU read-side critical
+section, neither of which is conducive to a long-lived and prosperous
+kernel.
+
+<p>
+It is worth noting that RCU is not alone in limiting composability.
+For example, many transactional-memory implementations prohibit
+composing a pair of transactions separated by an irrevocable
+operation (for example, a network receive operation).
+For another example, lock-based critical sections can be composed
+surprisingly freely, but only if deadlock is avoided.
+
+<p>
+In short, although RCU read-side critical sections are highly composable,
+care is required in some situations, just as is the case for any other
+composable synchronization mechanism.
+
+<h3><a name="Corner Cases">Corner Cases</a></h3>
+
+<p>
+A given RCU workload might have an endless and intense stream of
+RCU read-side critical sections, perhaps even so intense that there
+was never a point in time during which there was not at least one
+RCU read-side critical section in flight.
+RCU cannot allow this situation to block grace periods: As long as
+all the RCU read-side critical sections are finite, grace periods
+must also be finite.
+
+<p>
+That said, preemptible RCU implementations could potentially result
+in RCU read-side critical sections being preempted for long durations,
+which has the effect of creating a long-duration RCU read-side
+critical section.
+This situation can arise only in heavily loaded systems, but systems using
+real-time priorities are of course more vulnerable.
+Therefore, RCU priority boosting is provided to help deal with this
+case.
+That said, the exact requirements on RCU priority boosting will likely
+evolve as more experience accumulates.
+
+<p>
+Other workloads might have very high update rates.
+Although one can argue that such workloads should instead use
+something other than RCU, the fact remains that RCU must
+handle such workloads gracefully.
+This requirement is another factor driving batching of grace periods,
+but it is also the driving force behind the checks for large numbers
+of queued RCU callbacks in the <tt>call_rcu()</tt> code path.
+Finally, high update rates should not delay RCU read-side critical
+sections, although some read-side delays can occur when using
+<tt>synchronize_rcu_expedited()</tt>, courtesy of this function's use
+of <tt>try_stop_cpus()</tt>.
+(In the future, <tt>synchronize_rcu_expedited()</tt> will be
+converted to use lighter-weight inter-processor interrupts (IPIs),
+but this will still disturb readers, though to a much smaller degree.)
+
+<p>
+Although all three of these corner cases were understood in the early
+1990s, a simple user-level test consisting of <tt>close(open(path))</tt>
+in a tight loop
+in the early 2000s suddenly provided a much deeper appreciation of the
+high-update-rate corner case.
+This test also motivated addition of some RCU code to react to high update
+rates, for example, if a given CPU finds itself with more than 10,000
+RCU callbacks queued, it will cause RCU to take evasive action by
+more aggressively starting grace periods and more aggressively forcing
+completion of grace-period processing.
+This evasive action causes the grace period to complete more quickly,
+but at the cost of restricting RCU's batching optimizations, thus
+increasing the CPU overhead incurred by that grace period.
+
+<h2><a name="Software-Engineering Requirements">
+Software-Engineering Requirements</a></h2>
+
+<p>
+Between Murphy's Law and &ldquo;To err is human&rdquo;, it is necessary to
+guard against mishaps and misuse:
+
+<ol>
+<li> It is all too easy to forget to use <tt>rcu_read_lock()</tt>
+ everywhere that it is needed, so kernels built with
+ <tt>CONFIG_PROVE_RCU=y</tt> will spat if
+ <tt>rcu_dereference()</tt> is used outside of an
+ RCU read-side critical section.
+ Update-side code can use <tt>rcu_dereference_protected()</tt>,
+ which takes a
+ <a href="https://lwn.net/Articles/371986/">lockdep expression</a>
+ to indicate what is providing the protection.
+ If the indicated protection is not provided, a lockdep splat
+ is emitted.
+
+ <p>
+ Code shared between readers and updaters can use
+ <tt>rcu_dereference_check()</tt>, which also takes a
+ lockdep expression, and emits a lockdep splat if neither
+ <tt>rcu_read_lock()</tt> nor the indicated protection
+ is in place.
+ In addition, <tt>rcu_dereference_raw()</tt> is used in those
+ (hopefully rare) cases where the required protection cannot
+ be easily described.
+ Finally, <tt>rcu_read_lock_held()</tt> is provided to
+ allow a function to verify that it has been invoked within
+ an RCU read-side critical section.
+ I was made aware of this set of requirements shortly after Thomas
+ Gleixner audited a number of RCU uses.
+<li> A given function might wish to check for RCU-related preconditions
+ upon entry, before using any other RCU API.
+ The <tt>rcu_lockdep_assert()</tt> does this job,
+ asserting the expression in kernels having lockdep enabled
+ and doing nothing otherwise.
+<li> It is also easy to forget to use <tt>rcu_assign_pointer()</tt>
+ and <tt>rcu_dereference()</tt>, perhaps (incorrectly)
+ substituting a simple assignment.
+ To catch this sort of error, a given RCU-protected pointer may be
+ tagged with <tt>__rcu</tt>, after which running sparse
+ with <tt>CONFIG_SPARSE_RCU_POINTER=y</tt> will complain
+ about simple-assignment accesses to that pointer.
+ Arnd Bergmann made me aware of this requirement, and also
+ supplied the needed
+ <a href="https://lwn.net/Articles/376011/">patch series</a>.
+<li> Kernels built with <tt>CONFIG_DEBUG_OBJECTS_RCU_HEAD=y</tt>
+ will splat if a data element is passed to <tt>call_rcu()</tt>
+ twice in a row, without a grace period in between.
+ (This error is similar to a double free.)
+ The corresponding <tt>rcu_head</tt> structures that are
+ dynamically allocated are automatically tracked, but
+ <tt>rcu_head</tt> structures allocated on the stack
+ must be initialized with <tt>init_rcu_head_on_stack()</tt>
+ and cleaned up with <tt>destroy_rcu_head_on_stack()</tt>.
+ Similarly, statically allocated non-stack <tt>rcu_head</tt>
+ structures must be initialized with <tt>init_rcu_head()</tt>
+ and cleaned up with <tt>destroy_rcu_head()</tt>.
+ Mathieu Desnoyers made me aware of this requirement, and also
+ supplied the needed
+ <a href="https://lkml.kernel.org/g/20100319013024.GA28456@Krystal">patch</a>.
+<li> An infinite loop in an RCU read-side critical section will
+ eventually trigger an RCU CPU stall warning splat, with
+ the duration of &ldquo;eventually&rdquo; being controlled by the
+ <tt>RCU_CPU_STALL_TIMEOUT</tt> <tt>Kconfig</tt> option, or,
+ alternatively, by the
+ <tt>rcupdate.rcu_cpu_stall_timeout</tt> boot/sysfs
+ parameter.
+ However, RCU is not obligated to produce this splat
+ unless there is a grace period waiting on that particular
+ RCU read-side critical section.
+ <p>
+ Some extreme workloads might intentionally delay
+ RCU grace periods, and systems running those workloads can
+ be booted with <tt>rcupdate.rcu_cpu_stall_suppress</tt>
+ to suppress the splats.
+ This kernel parameter may also be set via <tt>sysfs</tt>.
+ Furthermore, RCU CPU stall warnings are counter-productive
+ during sysrq dumps and during panics.
+ RCU therefore supplies the <tt>rcu_sysrq_start()</tt> and
+ <tt>rcu_sysrq_end()</tt> API members to be called before
+ and after long sysrq dumps.
+ RCU also supplies the <tt>rcu_panic()</tt> notifier that is
+ automatically invoked at the beginning of a panic to suppress
+ further RCU CPU stall warnings.
+
+ <p>
+ This requirement made itself known in the early 1990s, pretty
+ much the first time that it was necessary to debug a CPU stall.
+ That said, the initial implementation in DYNIX/ptx was quite
+ generic in comparison with that of Linux.
+<li> Although it would be very good to detect pointers leaking out
+ of RCU read-side critical sections, there is currently no
+ good way of doing this.
+ One complication is the need to distinguish between pointers
+ leaking and pointers that have been handed off from RCU to
+ some other synchronization mechanism, for example, reference
+ counting.
+<li> In kernels built with <tt>CONFIG_RCU_TRACE=y</tt>, RCU-related
+ information is provided via both debugfs and event tracing.
+<li> Open-coded use of <tt>rcu_assign_pointer()</tt> and
+ <tt>rcu_dereference()</tt> to create typical linked
+ data structures can be surprisingly error-prone.
+ Therefore, RCU-protected
+ <a href="https://lwn.net/Articles/609973/#RCU List APIs">linked lists</a>
+ and, more recently, RCU-protected
+ <a href="https://lwn.net/Articles/612100/">hash tables</a>
+ are available.
+ Many other special-purpose RCU-protected data structures are
+ available in the Linux kernel and the userspace RCU library.
+<li> Some linked structures are created at compile time, but still
+ require <tt>__rcu</tt> checking.
+ The <tt>RCU_POINTER_INITIALIZER()</tt> macro serves this
+ purpose.
+<li> It is not necessary to use <tt>rcu_assign_pointer()</tt>
+ when creating linked structures that are to be published via
+ a single external pointer.
+ The <tt>RCU_INIT_POINTER()</tt> macro is provided for
+ this task and also for assigning <tt>NULL</tt> pointers
+ at runtime.
+</ol>
+
+<p>
+This not a hard-and-fast list: RCU's diagnostic capabilities will
+continue to be guided by the number and type of usage bugs found
+in real-world RCU usage.
+
+<h2><a name="Linux Kernel Complications">Linux Kernel Complications</a></h2>
+
+<p>
+The Linux kernel provides an interesting environment for all kinds of
+software, including RCU.
+Some of the relevant points of interest are as follows:
+
+<ol>
+<li> <a href="#Configuration">Configuration</a>.
+<li> <a href="#Firmware Interface">Firmware Interface</a>.
+<li> <a href="#Early Boot">Early Boot</a>.
+<li> <a href="#Interrupts and NMIs">
+ Interrupts and non-maskable interrupts (NMIs)</a>.
+<li> <a href="#Loadable Modules">Loadable Modules</a>.
+<li> <a href="#Hotplug CPU">Hotplug CPU</a>.
+<li> <a href="#Scheduler and RCU">Scheduler and RCU</a>.
+<li> <a href="#Tracing and RCU">Tracing and RCU</a>.
+<li> <a href="#Energy Efficiency">Energy Efficiency</a>.
+<li> <a href="#Memory Efficiency">Memory Efficiency</a>.
+<li> <a href="#Performance, Scalability, Response Time, and Reliability">
+ Performance, Scalability, Response Time, and Reliability</a>.
+</ol>
+
+<p>
+This list is probably incomplete, but it does give a feel for the
+most notable Linux-kernel complications.
+Each of the following sections covers one of the above topics.
+
+<h3><a name="Configuration">Configuration</a></h3>
+
+<p>
+RCU's goal is automatic configuration, so that almost nobody
+needs to worry about RCU's <tt>Kconfig</tt> options.
+And for almost all users, RCU does in fact work well
+&ldquo;out of the box.&rdquo;
+
+<p>
+However, there are specialized use cases that are handled by
+kernel boot parameters and <tt>Kconfig</tt> options.
+Unfortunately, the <tt>Kconfig</tt> system will explicitly ask users
+about new <tt>Kconfig</tt> options, which requires almost all of them
+be hidden behind a <tt>CONFIG_RCU_EXPERT</tt> <tt>Kconfig</tt> option.
+
+<p>
+This all should be quite obvious, but the fact remains that
+Linus Torvalds recently had to
+<a href="https://lkml.kernel.org/g/CA+55aFy4wcCwaL4okTs8wXhGZ5h-ibecy_Meg9C4MNQrUnwMcg@mail.gmail.com">remind</a>
+me of this requirement.
+
+<h3><a name="Firmware Interface">Firmware Interface</a></h3>
+
+<p>
+In many cases, kernel obtains information about the system from the
+firmware, and sometimes things are lost in translation.
+Or the translation is accurate, but the original message is bogus.
+
+<p>
+For example, some systems' firmware overreports the number of CPUs,
+sometimes by a large factor.
+If RCU naively believed the firmware, as it used to do,
+it would create too many per-CPU kthreads.
+Although the resulting system will still run correctly, the extra
+kthreads needlessly consume memory and can cause confusion
+when they show up in <tt>ps</tt> listings.
+
+<p>
+RCU must therefore wait for a given CPU to actually come online before
+it can allow itself to believe that the CPU actually exists.
+The resulting &ldquo;ghost CPUs&rdquo; (which are never going to
+come online) cause a number of
+<a href="https://paulmck.livejournal.com/37494.html">interesting complications</a>.
+
+<h3><a name="Early Boot">Early Boot</a></h3>
+
+<p>
+The Linux kernel's boot sequence is an interesting process,
+and RCU is used early, even before <tt>rcu_init()</tt>
+is invoked.
+In fact, a number of RCU's primitives can be used as soon as the
+initial task's <tt>task_struct</tt> is available and the
+boot CPU's per-CPU variables are set up.
+The read-side primitives (<tt>rcu_read_lock()</tt>,
+<tt>rcu_read_unlock()</tt>, <tt>rcu_dereference()</tt>,
+and <tt>rcu_access_pointer()</tt>) will operate normally very early on,
+as will <tt>rcu_assign_pointer()</tt>.
+
+<p>
+Although <tt>call_rcu()</tt> may be invoked at any
+time during boot, callbacks are not guaranteed to be invoked until after
+the scheduler is fully up and running.
+This delay in callback invocation is due to the fact that RCU does not
+invoke callbacks until it is fully initialized, and this full initialization
+cannot occur until after the scheduler has initialized itself to the
+point where RCU can spawn and run its kthreads.
+In theory, it would be possible to invoke callbacks earlier,
+however, this is not a panacea because there would be severe restrictions
+on what operations those callbacks could invoke.
+
+<p>
+Perhaps surprisingly, <tt>synchronize_rcu()</tt>,
+<a href="#Bottom-Half Flavor"><tt>synchronize_rcu_bh()</tt></a>
+(<a href="#Bottom-Half Flavor">discussed below</a>),
+and
+<a href="#Sched Flavor"><tt>synchronize_sched()</tt></a>
+will all operate normally
+during very early boot, the reason being that there is only one CPU
+and preemption is disabled.
+This means that the call <tt>synchronize_rcu()</tt> (or friends)
+itself is a quiescent
+state and thus a grace period, so the early-boot implementation can
+be a no-op.
+
+<p>
+Both <tt>synchronize_rcu_bh()</tt> and <tt>synchronize_sched()</tt>
+continue to operate normally through the remainder of boot, courtesy
+of the fact that preemption is disabled across their RCU read-side
+critical sections and also courtesy of the fact that there is still
+only one CPU.
+However, once the scheduler starts initializing, preemption is enabled.
+There is still only a single CPU, but the fact that preemption is enabled
+means that the no-op implementation of <tt>synchronize_rcu()</tt> no
+longer works in <tt>CONFIG_PREEMPT=y</tt> kernels.
+Therefore, as soon as the scheduler starts initializing, the early-boot
+fastpath is disabled.
+This means that <tt>synchronize_rcu()</tt> switches to its runtime
+mode of operation where it posts callbacks, which in turn means that
+any call to <tt>synchronize_rcu()</tt> will block until the corresponding
+callback is invoked.
+Unfortunately, the callback cannot be invoked until RCU's runtime
+grace-period machinery is up and running, which cannot happen until
+the scheduler has initialized itself sufficiently to allow RCU's
+kthreads to be spawned.
+Therefore, invoking <tt>synchronize_rcu()</tt> during scheduler
+initialization can result in deadlock.
+
+<p>@@QQ@@
+So what happens with <tt>synchronize_rcu()</tt> during
+scheduler initialization for <tt>CONFIG_PREEMPT=n</tt>
+kernels?
+<p>@@QQA@@
+In <tt>CONFIG_PREEMPT=n</tt> kernel, <tt>synchronize_rcu()</tt>
+maps directly to <tt>synchronize_sched()</tt>.
+Therefore, <tt>synchronize_rcu()</tt> works normally throughout
+boot in <tt>CONFIG_PREEMPT=n</tt> kernels.
+However, your code must also work in <tt>CONFIG_PREEMPT=y</tt> kernels,
+so it is still necessary to avoid invoking <tt>synchronize_rcu()</tt>
+during scheduler initialization.
+<p>@@QQE@@
+
+<p>
+I learned of these boot-time requirements as a result of a series of
+system hangs.
+
+<h3><a name="Interrupts and NMIs">Interrupts and NMIs</a></h3>
+
+<p>
+The Linux kernel has interrupts, and RCU read-side critical sections are
+legal within interrupt handlers and within interrupt-disabled regions
+of code, as are invocations of <tt>call_rcu()</tt>.
+
+<p>
+Some Linux-kernel architectures can enter an interrupt handler from
+non-idle process context, and then just never leave it, instead stealthily
+transitioning back to process context.
+This trick is sometimes used to invoke system calls from inside the kernel.
+These &ldquo;half-interrupts&rdquo; mean that RCU has to be very careful
+about how it counts interrupt nesting levels.
+I learned of this requirement the hard way during a rewrite
+of RCU's dyntick-idle code.
+
+<p>
+The Linux kernel has non-maskable interrupts (NMIs), and
+RCU read-side critical sections are legal within NMI handlers.
+Thankfully, RCU update-side primitives, including
+<tt>call_rcu()</tt>, are prohibited within NMI handlers.
+
+<p>
+The name notwithstanding, some Linux-kernel architectures
+can have nested NMIs, which RCU must handle correctly.
+Andy Lutomirski
+<a href="https://lkml.kernel.org/g/CALCETrXLq1y7e_dKFPgou-FKHB6Pu-r8+t-6Ds+8=va7anBWDA@mail.gmail.com">surprised me</a>
+with this requirement;
+he also kindly surprised me with
+<a href="https://lkml.kernel.org/g/CALCETrXSY9JpW3uE6H8WYk81sg56qasA2aqmjMPsq5dOtzso=g@mail.gmail.com">an algorithm</a>
+that meets this requirement.
+
+<h3><a name="Loadable Modules">Loadable Modules</a></h3>
+
+<p>
+The Linux kernel has loadable modules, and these modules can
+also be unloaded.
+After a given module has been unloaded, any attempt to call
+one of its functions results in a segmentation fault.
+The module-unload functions must therefore cancel any
+delayed calls to loadable-module functions, for example,
+any outstanding <tt>mod_timer()</tt> must be dealt with
+via <tt>del_timer_sync()</tt> or similar.
+
+<p>
+Unfortunately, there is no way to cancel an RCU callback;
+once you invoke <tt>call_rcu()</tt>, the callback function is
+going to eventually be invoked, unless the system goes down first.
+Because it is normally considered socially irresponsible to crash the system
+in response to a module unload request, we need some other way
+to deal with in-flight RCU callbacks.
+
+<p>
+RCU therefore provides
+<tt><a href="https://lwn.net/Articles/217484/">rcu_barrier()</a></tt>,
+which waits until all in-flight RCU callbacks have been invoked.
+If a module uses <tt>call_rcu()</tt>, its exit function should therefore
+prevent any future invocation of <tt>call_rcu()</tt>, then invoke
+<tt>rcu_barrier()</tt>.
+In theory, the underlying module-unload code could invoke
+<tt>rcu_barrier()</tt> unconditionally, but in practice this would
+incur unacceptable latencies.
+
+<p>
+Nikita Danilov noted this requirement for an analogous filesystem-unmount
+situation, and Dipankar Sarma incorporated <tt>rcu_barrier()</tt> into RCU.
+The need for <tt>rcu_barrier()</tt> for module unloading became
+apparent later.
+
+<h3><a name="Hotplug CPU">Hotplug CPU</a></h3>
+
+<p>
+The Linux kernel supports CPU hotplug, which means that CPUs
+can come and go.
+It is of course illegal to use any RCU API member from an offline CPU.
+This requirement was present from day one in DYNIX/ptx, but
+on the other hand, the Linux kernel's CPU-hotplug implementation
+is &ldquo;interesting.&rdquo;
+
+<p>
+The Linux-kernel CPU-hotplug implementation has notifiers that
+are used to allow the various kernel subsystems (including RCU)
+to respond appropriately to a given CPU-hotplug operation.
+Most RCU operations may be invoked from CPU-hotplug notifiers,
+including even normal synchronous grace-period operations
+such as <tt>synchronize_rcu()</tt>.
+However, expedited grace-period operations such as
+<tt>synchronize_rcu_expedited()</tt> are not supported,
+due to the fact that current implementations block CPU-hotplug
+operations, which could result in deadlock.
+
+<p>
+In addition, all-callback-wait operations such as
+<tt>rcu_barrier()</tt> are also not supported, due to the
+fact that there are phases of CPU-hotplug operations where
+the outgoing CPU's callbacks will not be invoked until after
+the CPU-hotplug operation ends, which could also result in deadlock.
+
+<h3><a name="Scheduler and RCU">Scheduler and RCU</a></h3>
+
+<p>
+RCU depends on the scheduler, and the scheduler uses RCU to
+protect some of its data structures.
+This means the scheduler is forbidden from acquiring
+the runqueue locks and the priority-inheritance locks
+in the middle of an outermost RCU read-side critical section unless either
+(1)&nbsp;it releases them before exiting that same
+RCU read-side critical section, or
+(2)&nbsp;interrupts are disabled across
+that entire RCU read-side critical section.
+This same prohibition also applies (recursively!) to any lock that is acquired
+while holding any lock to which this prohibition applies.
+Adhering to this rule prevents preemptible RCU from invoking
+<tt>rcu_read_unlock_special()</tt> while either runqueue or
+priority-inheritance locks are held, thus avoiding deadlock.
+
+<p>
+Prior to v4.4, it was only necessary to disable preemption across
+RCU read-side critical sections that acquired scheduler locks.
+In v4.4, expedited grace periods started using IPIs, and these
+IPIs could force a <tt>rcu_read_unlock()</tt> to take the slowpath.
+Therefore, this expedited-grace-period change required disabling of
+interrupts, not just preemption.
+
+<p>
+For RCU's part, the preemptible-RCU <tt>rcu_read_unlock()</tt>
+implementation must be written carefully to avoid similar deadlocks.
+In particular, <tt>rcu_read_unlock()</tt> must tolerate an
+interrupt where the interrupt handler invokes both
+<tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+This possibility requires <tt>rcu_read_unlock()</tt> to use
+negative nesting levels to avoid destructive recursion via
+interrupt handler's use of RCU.
+
+<p>
+This pair of mutual scheduler-RCU requirements came as a
+<a href="https://lwn.net/Articles/453002/">complete surprise</a>.
+
+<p>
+As noted above, RCU makes use of kthreads, and it is necessary to
+avoid excessive CPU-time accumulation by these kthreads.
+This requirement was no surprise, but RCU's violation of it
+when running context-switch-heavy workloads when built with
+<tt>CONFIG_NO_HZ_FULL=y</tt>
+<a href="http://www.rdrop.com/users/paulmck/scalability/paper/BareMetal.2015.01.15b.pdf">did come as a surprise [PDF]</a>.
+RCU has made good progress towards meeting this requirement, even
+for context-switch-have <tt>CONFIG_NO_HZ_FULL=y</tt> workloads,
+but there is room for further improvement.
+
+<h3><a name="Tracing and RCU">Tracing and RCU</a></h3>
+
+<p>
+It is possible to use tracing on RCU code, but tracing itself
+uses RCU.
+For this reason, <tt>rcu_dereference_raw_notrace()</tt>
+is provided for use by tracing, which avoids the destructive
+recursion that could otherwise ensue.
+This API is also used by virtualization in some architectures,
+where RCU readers execute in environments in which tracing
+cannot be used.
+The tracing folks both located the requirement and provided the
+needed fix, so this surprise requirement was relatively painless.
+
+<h3><a name="Energy Efficiency">Energy Efficiency</a></h3>
+
+<p>
+Interrupting idle CPUs is considered socially unacceptable,
+especially by people with battery-powered embedded systems.
+RCU therefore conserves energy by detecting which CPUs are
+idle, including tracking CPUs that have been interrupted from idle.
+This is a large part of the energy-efficiency requirement,
+so I learned of this via an irate phone call.
+
+<p>
+Because RCU avoids interrupting idle CPUs, it is illegal to
+execute an RCU read-side critical section on an idle CPU.
+(Kernels built with <tt>CONFIG_PROVE_RCU=y</tt> will splat
+if you try it.)
+The <tt>RCU_NONIDLE()</tt> macro and <tt>_rcuidle</tt>
+event tracing is provided to work around this restriction.
+In addition, <tt>rcu_is_watching()</tt> may be used to
+test whether or not it is currently legal to run RCU read-side
+critical sections on this CPU.
+I learned of the need for diagnostics on the one hand
+and <tt>RCU_NONIDLE()</tt> on the other while inspecting
+idle-loop code.
+Steven Rostedt supplied <tt>_rcuidle</tt> event tracing,
+which is used quite heavily in the idle loop.
+
+<p>
+It is similarly socially unacceptable to interrupt an
+<tt>nohz_full</tt> CPU running in userspace.
+RCU must therefore track <tt>nohz_full</tt> userspace
+execution.
+And in
+<a href="https://lwn.net/Articles/558284/"><tt>CONFIG_NO_HZ_FULL_SYSIDLE=y</tt></a>
+kernels, RCU must separately track idle CPUs on the one hand and
+CPUs that are either idle or executing in userspace on the other.
+In both cases, RCU must be able to sample state at two points in
+time, and be able to determine whether or not some other CPU spent
+any time idle and/or executing in userspace.
+
+<p>
+These energy-efficiency requirements have proven quite difficult to
+understand and to meet, for example, there have been more than five
+clean-sheet rewrites of RCU's energy-efficiency code, the last of
+which was finally able to demonstrate
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/AMPenergy.2013.04.19a.pdf">real energy savings running on real hardware [PDF]</a>.
+As noted earlier,
+I learned of many of these requirements via angry phone calls:
+Flaming me on the Linux-kernel mailing list was apparently not
+sufficient to fully vent their ire at RCU's energy-efficiency bugs!
+
+<h3><a name="Memory Efficiency">Memory Efficiency</a></h3>
+
+<p>
+Although small-memory non-realtime systems can simply use Tiny RCU,
+code size is only one aspect of memory efficiency.
+Another aspect is the size of the <tt>rcu_head</tt> structure
+used by <tt>call_rcu()</tt> and <tt>kfree_rcu()</tt>.
+Although this structure contains nothing more than a pair of pointers,
+it does appear in many RCU-protected data structures, including
+some that are size critical.
+The <tt>page</tt> structure is a case in point, as evidenced by
+the many occurrences of the <tt>union</tt> keyword within that structure.
+
+<p>
+This need for memory efficiency is one reason that RCU uses hand-crafted
+singly linked lists to track the <tt>rcu_head</tt> structures that
+are waiting for a grace period to elapse.
+It is also the reason why <tt>rcu_head</tt> structures do not contain
+debug information, such as fields tracking the file and line of the
+<tt>call_rcu()</tt> or <tt>kfree_rcu()</tt> that posted them.
+Although this information might appear in debug-only kernel builds at some
+point, in the meantime, the <tt>-&gt;func</tt> field will often provide
+the needed debug information.
+
+<p>
+However, in some cases, the need for memory efficiency leads to even
+more extreme measures.
+Returning to the <tt>page</tt> structure, the <tt>rcu_head</tt> field
+shares storage with a great many other structures that are used at
+various points in the corresponding page's lifetime.
+In order to correctly resolve certain
+<a href="https://lkml.kernel.org/g/1439976106-137226-1-git-send-email-kirill.shutemov@linux.intel.com">race conditions</a>,
+the Linux kernel's memory-management subsystem needs a particular bit
+to remain zero during all phases of grace-period processing,
+and that bit happens to map to the bottom bit of the
+<tt>rcu_head</tt> structure's <tt>-&gt;next</tt> field.
+RCU makes this guarantee as long as <tt>call_rcu()</tt>
+is used to post the callback, as opposed to <tt>kfree_rcu()</tt>
+or some future &ldquo;lazy&rdquo;
+variant of <tt>call_rcu()</tt> that might one day be created for
+energy-efficiency purposes.
+
+<h3><a name="Performance, Scalability, Response Time, and Reliability">
+Performance, Scalability, Response Time, and Reliability</a></h3>
+
+<p>
+Expanding on the
+<a href="#Performance and Scalability">earlier discussion</a>,
+RCU is used heavily by hot code paths in performance-critical
+portions of the Linux kernel's networking, security, virtualization,
+and scheduling code paths.
+RCU must therefore use efficient implementations, especially in its
+read-side primitives.
+To that end, it would be good if preemptible RCU's implementation
+of <tt>rcu_read_lock()</tt> could be inlined, however, doing
+this requires resolving <tt>#include</tt> issues with the
+<tt>task_struct</tt> structure.
+
+<p>
+The Linux kernel supports hardware configurations with up to
+4096 CPUs, which means that RCU must be extremely scalable.
+Algorithms that involve frequent acquisitions of global locks or
+frequent atomic operations on global variables simply cannot be
+tolerated within the RCU implementation.
+RCU therefore makes heavy use of a combining tree based on the
+<tt>rcu_node</tt> structure.
+RCU is required to tolerate all CPUs continuously invoking any
+combination of RCU's runtime primitives with minimal per-operation
+overhead.
+In fact, in many cases, increasing load must <i>decrease</i> the
+per-operation overhead, witness the batching optimizations for
+<tt>synchronize_rcu()</tt>, <tt>call_rcu()</tt>,
+<tt>synchronize_rcu_expedited()</tt>, and <tt>rcu_barrier()</tt>.
+As a general rule, RCU must cheerfully accept whatever the
+rest of the Linux kernel decides to throw at it.
+
+<p>
+The Linux kernel is used for real-time workloads, especially
+in conjunction with the
+<a href="https://rt.wiki.kernel.org/index.php/Main_Page">-rt patchset</a>.
+The real-time-latency response requirements are such that the
+traditional approach of disabling preemption across RCU
+read-side critical sections is inappropriate.
+Kernels built with <tt>CONFIG_PREEMPT=y</tt> therefore
+use an RCU implementation that allows RCU read-side critical
+sections to be preempted.
+This requirement made its presence known after users made it
+clear that an earlier
+<a href="https://lwn.net/Articles/107930/">real-time patch</a>
+did not meet their needs, in conjunction with some
+<a href="https://lkml.kernel.org/g/20050318002026.GA2693@us.ibm.com">RCU issues</a>
+encountered by a very early version of the -rt patchset.
+
+<p>
+In addition, RCU must make do with a sub-100-microsecond real-time latency
+budget.
+In fact, on smaller systems with the -rt patchset, the Linux kernel
+provides sub-20-microsecond real-time latencies for the whole kernel,
+including RCU.
+RCU's scalability and latency must therefore be sufficient for
+these sorts of configurations.
+To my surprise, the sub-100-microsecond real-time latency budget
+<a href="http://www.rdrop.com/users/paulmck/realtime/paper/bigrt.2013.01.31a.LCA.pdf">
+applies to even the largest systems [PDF]</a>,
+up to and including systems with 4096 CPUs.
+This real-time requirement motivated the grace-period kthread, which
+also simplified handling of a number of race conditions.
+
+<p>
+Finally, RCU's status as a synchronization primitive means that
+any RCU failure can result in arbitrary memory corruption that can be
+extremely difficult to debug.
+This means that RCU must be extremely reliable, which in
+practice also means that RCU must have an aggressive stress-test
+suite.
+This stress-test suite is called <tt>rcutorture</tt>.
+
+<p>
+Although the need for <tt>rcutorture</tt> was no surprise,
+the current immense popularity of the Linux kernel is posing
+interesting&mdash;and perhaps unprecedented&mdash;validation
+challenges.
+To see this, keep in mind that there are well over one billion
+instances of the Linux kernel running today, given Android
+smartphones, Linux-powered televisions, and servers.
+This number can be expected to increase sharply with the advent of
+the celebrated Internet of Things.
+
+<p>
+Suppose that RCU contains a race condition that manifests on average
+once per million years of runtime.
+This bug will be occurring about three times per <i>day</i> across
+the installed base.
+RCU could simply hide behind hardware error rates, given that no one
+should really expect their smartphone to last for a million years.
+However, anyone taking too much comfort from this thought should
+consider the fact that in most jurisdictions, a successful multi-year
+test of a given mechanism, which might include a Linux kernel,
+suffices for a number of types of safety-critical certifications.
+In fact, rumor has it that the Linux kernel is already being used
+in production for safety-critical applications.
+I don't know about you, but I would feel quite bad if a bug in RCU
+killed someone.
+Which might explain my recent focus on validation and verification.
+
+<h2><a name="Other RCU Flavors">Other RCU Flavors</a></h2>
+
+<p>
+One of the more surprising things about RCU is that there are now
+no fewer than five <i>flavors</i>, or API families.
+In addition, the primary flavor that has been the sole focus up to
+this point has two different implementations, non-preemptible and
+preemptible.
+The other four flavors are listed below, with requirements for each
+described in a separate section.
+
+<ol>
+<li> <a href="#Bottom-Half Flavor">Bottom-Half Flavor</a>
+<li> <a href="#Sched Flavor">Sched Flavor</a>
+<li> <a href="#Sleepable RCU">Sleepable RCU</a>
+<li> <a href="#Tasks RCU">Tasks RCU</a>
+</ol>
+
+<h3><a name="Bottom-Half Flavor">Bottom-Half Flavor</a></h3>
+
+<p>
+The softirq-disable (AKA &ldquo;bottom-half&rdquo;,
+hence the &ldquo;_bh&rdquo; abbreviations)
+flavor of RCU, or <i>RCU-bh</i>, was developed by
+Dipankar Sarma to provide a flavor of RCU that could withstand the
+network-based denial-of-service attacks researched by Robert
+Olsson.
+These attacks placed so much networking load on the system
+that some of the CPUs never exited softirq execution,
+which in turn prevented those CPUs from ever executing a context switch,
+which, in the RCU implementation of that time, prevented grace periods
+from ever ending.
+The result was an out-of-memory condition and a system hang.
+
+<p>
+The solution was the creation of RCU-bh, which does
+<tt>local_bh_disable()</tt>
+across its read-side critical sections, and which uses the transition
+from one type of softirq processing to another as a quiescent state
+in addition to context switch, idle, user mode, and offline.
+This means that RCU-bh grace periods can complete even when some of
+the CPUs execute in softirq indefinitely, thus allowing algorithms
+based on RCU-bh to withstand network-based denial-of-service attacks.
+
+<p>
+Because
+<tt>rcu_read_lock_bh()</tt> and <tt>rcu_read_unlock_bh()</tt>
+disable and re-enable softirq handlers, any attempt to start a softirq
+handlers during the
+RCU-bh read-side critical section will be deferred.
+In this case, <tt>rcu_read_unlock_bh()</tt>
+will invoke softirq processing, which can take considerable time.
+One can of course argue that this softirq overhead should be associated
+with the code following the RCU-bh read-side critical section rather
+than <tt>rcu_read_unlock_bh()</tt>, but the fact
+is that most profiling tools cannot be expected to make this sort
+of fine distinction.
+For example, suppose that a three-millisecond-long RCU-bh read-side
+critical section executes during a time of heavy networking load.
+There will very likely be an attempt to invoke at least one softirq
+handler during that three milliseconds, but any such invocation will
+be delayed until the time of the <tt>rcu_read_unlock_bh()</tt>.
+This can of course make it appear at first glance as if
+<tt>rcu_read_unlock_bh()</tt> was executing very slowly.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-bh API</a>
+includes
+<tt>rcu_read_lock_bh()</tt>,
+<tt>rcu_read_unlock_bh()</tt>,
+<tt>rcu_dereference_bh()</tt>,
+<tt>rcu_dereference_bh_check()</tt>,
+<tt>synchronize_rcu_bh()</tt>,
+<tt>synchronize_rcu_bh_expedited()</tt>,
+<tt>call_rcu_bh()</tt>,
+<tt>rcu_barrier_bh()</tt>, and
+<tt>rcu_read_lock_bh_held()</tt>.
+
+<h3><a name="Sched Flavor">Sched Flavor</a></h3>
+
+<p>
+Before preemptible RCU, waiting for an RCU grace period had the
+side effect of also waiting for all pre-existing interrupt
+and NMI handlers.
+However, there are legitimate preemptible-RCU implementations that
+do not have this property, given that any point in the code outside
+of an RCU read-side critical section can be a quiescent state.
+Therefore, <i>RCU-sched</i> was created, which follows &ldquo;classic&rdquo;
+RCU in that an RCU-sched grace period waits for for pre-existing
+interrupt and NMI handlers.
+In kernels built with <tt>CONFIG_PREEMPT=n</tt>, the RCU and RCU-sched
+APIs have identical implementations, while kernels built with
+<tt>CONFIG_PREEMPT=y</tt> provide a separate implementation for each.
+
+<p>
+Note well that in <tt>CONFIG_PREEMPT=y</tt> kernels,
+<tt>rcu_read_lock_sched()</tt> and <tt>rcu_read_unlock_sched()</tt>
+disable and re-enable preemption, respectively.
+This means that if there was a preemption attempt during the
+RCU-sched read-side critical section, <tt>rcu_read_unlock_sched()</tt>
+will enter the scheduler, with all the latency and overhead entailed.
+Just as with <tt>rcu_read_unlock_bh()</tt>, this can make it look
+as if <tt>rcu_read_unlock_sched()</tt> was executing very slowly.
+However, the highest-priority task won't be preempted, so that task
+will enjoy low-overhead <tt>rcu_read_unlock_sched()</tt> invocations.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">RCU-sched API</a>
+includes
+<tt>rcu_read_lock_sched()</tt>,
+<tt>rcu_read_unlock_sched()</tt>,
+<tt>rcu_read_lock_sched_notrace()</tt>,
+<tt>rcu_read_unlock_sched_notrace()</tt>,
+<tt>rcu_dereference_sched()</tt>,
+<tt>rcu_dereference_sched_check()</tt>,
+<tt>synchronize_sched()</tt>,
+<tt>synchronize_rcu_sched_expedited()</tt>,
+<tt>call_rcu_sched()</tt>,
+<tt>rcu_barrier_sched()</tt>, and
+<tt>rcu_read_lock_sched_held()</tt>.
+However, anything that disables preemption also marks an RCU-sched
+read-side critical section, including
+<tt>preempt_disable()</tt> and <tt>preempt_enable()</tt>,
+<tt>local_irq_save()</tt> and <tt>local_irq_restore()</tt>,
+and so on.
+
+<h3><a name="Sleepable RCU">Sleepable RCU</a></h3>
+
+<p>
+For well over a decade, someone saying &ldquo;I need to block within
+an RCU read-side critical section&rdquo; was a reliable indication
+that this someone did not understand RCU.
+After all, if you are always blocking in an RCU read-side critical
+section, you can probably afford to use a higher-overhead synchronization
+mechanism.
+However, that changed with the advent of the Linux kernel's notifiers,
+whose RCU read-side critical
+sections almost never sleep, but sometimes need to.
+This resulted in the introduction of
+<a href="https://lwn.net/Articles/202847/">sleepable RCU</a>,
+or <i>SRCU</i>.
+
+<p>
+SRCU allows different domains to be defined, with each such domain
+defined by an instance of an <tt>srcu_struct</tt> structure.
+A pointer to this structure must be passed in to each SRCU function,
+for example, <tt>synchronize_srcu(&amp;ss)</tt>, where
+<tt>ss</tt> is the <tt>srcu_struct</tt> structure.
+The key benefit of these domains is that a slow SRCU reader in one
+domain does not delay an SRCU grace period in some other domain.
+That said, one consequence of these domains is that read-side code
+must pass a &ldquo;cookie&rdquo; from <tt>srcu_read_lock()</tt>
+to <tt>srcu_read_unlock()</tt>, for example, as follows:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+As noted above, it is legal to block within SRCU read-side critical sections,
+however, with great power comes great responsibility.
+If you block forever in one of a given domain's SRCU read-side critical
+sections, then that domain's grace periods will also be blocked forever.
+Of course, one good way to block forever is to deadlock, which can
+happen if any operation in a given domain's SRCU read-side critical
+section can block waiting, either directly or indirectly, for that domain's
+grace period to elapse.
+For example, this results in a self-deadlock:
+
+<blockquote>
+<pre>
+ 1 int idx;
+ 2
+ 3 idx = srcu_read_lock(&amp;ss);
+ 4 do_something();
+ 5 synchronize_srcu(&amp;ss);
+ 6 srcu_read_unlock(&amp;ss, idx);
+</pre>
+</blockquote>
+
+<p>
+However, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for domain <tt>ss</tt>,
+deadlock would still be possible.
+Furthermore, if line&nbsp;5 acquired a mutex that was held across
+a <tt>synchronize_srcu()</tt> for some other domain <tt>ss1</tt>,
+and if an <tt>ss1</tt>-domain SRCU read-side critical section
+acquired another mutex that was held across as <tt>ss</tt>-domain
+<tt>synchronize_srcu()</tt>,
+deadlock would again be possible.
+Such a deadlock cycle could extend across an arbitrarily large number
+of different SRCU domains.
+Again, with great power comes great responsibility.
+
+<p>
+Unlike the other RCU flavors, SRCU read-side critical sections can
+run on idle and even offline CPUs.
+This ability requires that <tt>srcu_read_lock()</tt> and
+<tt>srcu_read_unlock()</tt> contain memory barriers, which means
+that SRCU readers will run a bit slower than would RCU readers.
+It also motivates the <tt>smp_mb__after_srcu_read_unlock()</tt>
+API, which, in combination with <tt>srcu_read_unlock()</tt>,
+guarantees a full memory barrier.
+
+<p>
+The
+<a href="https://lwn.net/Articles/609973/#RCU Per-Flavor API Table">SRCU API</a>
+includes
+<tt>srcu_read_lock()</tt>,
+<tt>srcu_read_unlock()</tt>,
+<tt>srcu_dereference()</tt>,
+<tt>srcu_dereference_check()</tt>,
+<tt>synchronize_srcu()</tt>,
+<tt>synchronize_srcu_expedited()</tt>,
+<tt>call_srcu()</tt>,
+<tt>srcu_barrier()</tt>, and
+<tt>srcu_read_lock_held()</tt>.
+It also includes
+<tt>DEFINE_SRCU()</tt>,
+<tt>DEFINE_STATIC_SRCU()</tt>, and
+<tt>init_srcu_struct()</tt>
+APIs for defining and initializing <tt>srcu_struct</tt> structures.
+
+<h3><a name="Tasks RCU">Tasks RCU</a></h3>
+
+<p>
+Some forms of tracing use &ldquo;tramopolines&rdquo; to handle the
+binary rewriting required to install different types of probes.
+It would be good to be able to free old trampolines, which sounds
+like a job for some form of RCU.
+However, because it is necessary to be able to install a trace
+anywhere in the code, it is not possible to use read-side markers
+such as <tt>rcu_read_lock()</tt> and <tt>rcu_read_unlock()</tt>.
+In addition, it does not work to have these markers in the trampoline
+itself, because there would need to be instructions following
+<tt>rcu_read_unlock()</tt>.
+Although <tt>synchronize_rcu()</tt> would guarantee that execution
+reached the <tt>rcu_read_unlock()</tt>, it would not be able to
+guarantee that execution had completely left the trampoline.
+
+<p>
+The solution, in the form of
+<a href="https://lwn.net/Articles/607117/"><i>Tasks RCU</i></a>,
+is to have implicit
+read-side critical sections that are delimited by voluntary context
+switches, that is, calls to <tt>schedule()</tt>,
+<tt>cond_resched_rcu_qs()</tt>, and
+<tt>synchronize_rcu_tasks()</tt>.
+In addition, transitions to and from userspace execution also delimit
+tasks-RCU read-side critical sections.
+
+<p>
+The tasks-RCU API is quite compact, consisting only of
+<tt>call_rcu_tasks()</tt>,
+<tt>synchronize_rcu_tasks()</tt>, and
+<tt>rcu_barrier_tasks()</tt>.
+
+<h2><a name="Possible Future Changes">Possible Future Changes</a></h2>
+
+<p>
+One of the tricks that RCU uses to attain update-side scalability is
+to increase grace-period latency with increasing numbers of CPUs.
+If this becomes a serious problem, it will be necessary to rework the
+grace-period state machine so as to avoid the need for the additional
+latency.
+
+<p>
+Expedited grace periods scan the CPUs, so their latency and overhead
+increases with increasing numbers of CPUs.
+If this becomes a serious problem on large systems, it will be necessary
+to do some redesign to avoid this scalability problem.
+
+<p>
+RCU disables CPU hotplug in a few places, perhaps most notably in the
+expedited grace-period and <tt>rcu_barrier()</tt> operations.
+If there is a strong reason to use expedited grace periods in CPU-hotplug
+notifiers, it will be necessary to avoid disabling CPU hotplug.
+This would introduce some complexity, so there had better be a <i>very</i>
+good reason.
+
+<p>
+The tradeoff between grace-period latency on the one hand and interruptions
+of other CPUs on the other hand may need to be re-examined.
+The desire is of course for zero grace-period latency as well as zero
+interprocessor interrupts undertaken during an expedited grace period
+operation.
+While this ideal is unlikely to be achievable, it is quite possible that
+further improvements can be made.
+
+<p>
+The multiprocessor implementations of RCU use a combining tree that
+groups CPUs so as to reduce lock contention and increase cache locality.
+However, this combining tree does not spread its memory across NUMA
+nodes nor does it align the CPU groups with hardware features such
+as sockets or cores.
+Such spreading and alignment is currently believed to be unnecessary
+because the hotpath read-side primitives do not access the combining
+tree, nor does <tt>call_rcu()</tt> in the common case.
+If you believe that your architecture needs such spreading and alignment,
+then your architecture should also benefit from the
+<tt>rcutree.rcu_fanout_leaf</tt> boot parameter, which can be set
+to the number of CPUs in a socket, NUMA node, or whatever.
+If the number of CPUs is too large, use a fraction of the number of
+CPUs.
+If the number of CPUs is a large prime number, well, that certainly
+is an &ldquo;interesting&rdquo; architectural choice!
+More flexible arrangements might be considered, but only if
+<tt>rcutree.rcu_fanout_leaf</tt> has proven inadequate, and only
+if the inadequacy has been demonstrated by a carefully run and
+realistic system-level workload.
+
+<p>
+Please note that arrangements that require RCU to remap CPU numbers will
+require extremely good demonstration of need and full exploration of
+alternatives.
+
+<p>
+There is an embarrassingly large number of flavors of RCU, and this
+number has been increasing over time.
+Perhaps it will be possible to combine some at some future date.
+
+<p>
+RCU's various kthreads are reasonably recent additions.
+It is quite likely that adjustments will be required to more gracefully
+handle extreme loads.
+It might also be necessary to be able to relate CPU utilization by
+RCU's kthreads and softirq handlers to the code that instigated this
+CPU utilization.
+For example, RCU callback overhead might be charged back to the
+originating <tt>call_rcu()</tt> instance, though probably not
+in production kernels.
+
+<h2><a name="Summary">Summary</a></h2>
+
+<p>
+This document has presented more than two decade's worth of RCU
+requirements.
+Given that the requirements keep changing, this will not be the last
+word on this subject, but at least it serves to get an important
+subset of the requirements set forth.
+
+<h2><a name="Acknowledgments">Acknowledgments</a></h2>
+
+I am grateful to Steven Rostedt, Lai Jiangshan, Ingo Molnar,
+Oleg Nesterov, Borislav Petkov, Peter Zijlstra, Boqun Feng, and
+Andy Lutomirski for their help in rendering
+this article human readable, and to Michelle Rankin for her support
+of this effort.
+Other contributions are acknowledged in the Linux kernel's git archive.
+The cartoon is copyright (c) 2013 by Melissa Broussard,
+and is provided
+under the terms of the Creative Commons Attribution-Share Alike 3.0
+United States license.
+
+<p>@@QQAL@@
+
+</body></html>
diff --git a/Documentation/RCU/Design/htmlqqz.sh b/Documentation/RCU/Design/htmlqqz.sh
new file mode 100755
index 0000000..d354f06
--- /dev/null
+++ b/Documentation/RCU/Design/htmlqqz.sh
@@ -0,0 +1,108 @@
+#!/bin/sh
+#
+# Usage: sh htmlqqz.sh file
+#
+# Extracts and converts quick quizzes in a proto-HTML document file.htmlx.
+# Commands, all of which must be on a line by themselves:
+#
+# "<p>@@QQ@@": Start of a quick quiz.
+# "<p>@@QQA@@": Start of a quick-quiz answer.
+# "<p>@@QQE@@": End of a quick-quiz answer, and thus of the quick quiz.
+# "<p>@@QQAL@@": Place to put quick-quiz answer list.
+#
+# Places the result in file.html.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (c) 2013 Paul E. McKenney, IBM Corporation.
+
+fn=$1
+if test ! -r $fn.htmlx
+then
+ echo "Error: $fn.htmlx unreadable."
+ exit 1
+fi
+
+echo "<!-- DO NOT HAND EDIT. -->" > $fn.html
+echo "<!-- Instead, edit $fn.htmlx and run 'sh htmlqqz.sh $fn' -->" >> $fn.html
+awk < $fn.htmlx >> $fn.html '
+
+state == "" && $1 != "<p>@@QQ@@" && $1 != "<p>@@QQAL@@" {
+ print $0;
+ if ($0 ~ /^<p>@@QQ/)
+ print "Bad Quick Quiz command: " NR " (expected <p>@@QQ@@ or <p>@@QQAL@@)." > "/dev/stderr"
+ next;
+}
+
+state == "" && $1 == "<p>@@QQ@@" {
+ qqn++;
+ qqlineno = NR;
+ haveqq = 1;
+ state = "qq";
+ print "<p><a name=\"Quick Quiz " qqn "\"><b>Quick Quiz " qqn "</b>:</a>"
+ next;
+}
+
+state == "qq" && $1 != "<p>@@QQA@@" {
+ qq[qqn] = qq[qqn] $0 "\n";
+ print $0
+ if ($0 ~ /^<p>@@QQ/)
+ print "Bad Quick Quiz command: " NR ". (expected <p>@@QQA@@)" > "/dev/stderr"
+ next;
+}
+
+state == "qq" && $1 == "<p>@@QQA@@" {
+ state = "qqa";
+ print "<br><a href=\"#qq" qqn "answer\">Answer</a>"
+ next;
+}
+
+state == "qqa" && $1 != "<p>@@QQE@@" {
+ qqa[qqn] = qqa[qqn] $0 "\n";
+ if ($0 ~ /^<p>@@QQ/)
+ print "Bad Quick Quiz command: " NR " (expected <p>@@QQE@@)." > "/dev/stderr"
+ next;
+}
+
+state == "qqa" && $1 == "<p>@@QQE@@" {
+ state = "";
+ next;
+}
+
+state == "" && $1 == "<p>@@QQAL@@" {
+ haveqq = "";
+ print "<h3><a name=\"Answers to Quick Quizzes\">"
+ print "Answers to Quick Quizzes</a></h3>"
+ print "";
+ for (i = 1; i <= qqn; i++) {
+ print "<a name=\"qq" i "answer\"></a>"
+ print "<p><b>Quick Quiz " i "</b>:"
+ print qq[i];
+ print "";
+ print "</p><p><b>Answer</b>:"
+ print qqa[i];
+ print "";
+ print "</p><p><a href=\"#Quick%20Quiz%20" i "\"><b>Back to Quick Quiz " i "</b>.</a>"
+ print "";
+ }
+ next;
+}
+
+END {
+ if (state != "")
+ print "Unterminated Quick Quiz: " qqlineno "." > "/dev/stderr"
+ else if (haveqq)
+ print "Missing \"<p>@@QQAL@@\", no Quick Quiz." > "/dev/stderr"
+}'
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 4710e4a..d603fa0 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -718,8 +718,21 @@ generates appropriate diffstats by default.)
See more details on the proper patch format in the following
references.
+15) Explicit In-Reply-To headers
+--------------------------------
+
+It can be helpful to manually add In-Reply-To: headers to a patch
+(e.g., when using "git send email") to associate the patch with
+previous relevant discussion, e.g. to link a bug fix to the email with
+the bug report. However, for a multi-patch series, it is generally
+best to avoid using In-Reply-To: to link to older versions of the
+series. This way multiple versions of the patch don't become an
+unmanageable forest of references in email clients. If a link is
+helpful, you can use the https://lkml.kernel.org/ redirector (e.g., in
+the cover email text) to link to an earlier version of the patch series.
+
-15) Sending "git pull" requests
+16) Sending "git pull" requests
-------------------------------
If you have a series of patches, it may be most convenient to have the
diff --git a/Documentation/acpi/i2c-muxes.txt b/Documentation/acpi/i2c-muxes.txt
new file mode 100644
index 0000000..9fcc4f0
--- /dev/null
+++ b/Documentation/acpi/i2c-muxes.txt
@@ -0,0 +1,58 @@
+ACPI I2C Muxes
+--------------
+
+Describing an I2C device hierarchy that includes I2C muxes requires an ACPI
+Device () scope per mux channel.
+
+Consider this topology:
+
++------+ +------+
+| SMB1 |-->| MUX0 |--CH00--> i2c client A (0x50)
+| | | 0x70 |--CH01--> i2c client B (0x50)
++------+ +------+
+
+which corresponds to the following ASL:
+
+Device (SMB1)
+{
+ Name (_HID, ...)
+ Device (MUX0)
+ {
+ Name (_HID, ...)
+ Name (_CRS, ResourceTemplate () {
+ I2cSerialBus (0x70, ControllerInitiated, I2C_SPEED,
+ AddressingMode7Bit, "^SMB1", 0x00,
+ ResourceConsumer,,)
+ }
+
+ Device (CH00)
+ {
+ Name (_ADR, 0)
+
+ Device (CLIA)
+ {
+ Name (_HID, ...)
+ Name (_CRS, ResourceTemplate () {
+ I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+ AddressingMode7Bit, "^CH00", 0x00,
+ ResourceConsumer,,)
+ }
+ }
+ }
+
+ Device (CH01)
+ {
+ Name (_ADR, 1)
+
+ Device (CLIB)
+ {
+ Name (_HID, ...)
+ Name (_CRS, ResourceTemplate () {
+ I2cSerialBus (0x50, ControllerInitiated, I2C_SPEED,
+ AddressingMode7Bit, "^CH01", 0x00,
+ ResourceConsumer,,)
+ }
+ }
+ }
+ }
+}
diff --git a/Documentation/arm/Samsung/Bootloader-interface.txt b/Documentation/arm/Samsung/Bootloader-interface.txt
index df8d4fb..ed494ac 100644
--- a/Documentation/arm/Samsung/Bootloader-interface.txt
+++ b/Documentation/arm/Samsung/Bootloader-interface.txt
@@ -19,7 +19,7 @@ executing kernel.
Address: sysram_ns_base_addr
Offset Value Purpose
=============================================================================
-0x08 exynos_cpu_resume_ns System suspend
+0x08 exynos_cpu_resume_ns, mcpm_entry_point System suspend
0x0c 0x00000bad (Magic cookie) System suspend
0x1c exynos4_secondary_startup Secondary CPU boot
0x1c + 4*cpu exynos4_secondary_startup (Exynos4412) Secondary CPU boot
@@ -56,7 +56,8 @@ Offset Value Purpose
Address: pmu_base_addr
Offset Value Purpose
=============================================================================
-0x0908 Non-zero (only Exynos3250) Secondary CPU boot up indicator
+0x0908 Non-zero Secondary CPU boot up indicator
+ on Exynos3250 and Exynos542x
4. Glossary
diff --git a/Documentation/arm/keystone/Overview.txt b/Documentation/arm/keystone/Overview.txt
index f17bc4c..400c0c2 100644
--- a/Documentation/arm/keystone/Overview.txt
+++ b/Documentation/arm/keystone/Overview.txt
@@ -49,24 +49,6 @@ specified through DTS. Following are the DTS used:-
The device tree documentation for the keystone machines are located at
Documentation/devicetree/bindings/arm/keystone/keystone.txt
-Known issues & workaround
--------------------------
-
-Some of the device drivers used on keystone are re-used from that from
-DaVinci and other TI SoCs. These device drivers may use clock APIs directly.
-Some of the keystone specific drivers such as netcp uses run time power
-management API instead to enable clock. As this API has limitations on
-keystone, following workaround is needed to boot Linux.
-
- Add 'clk_ignore_unused' to the bootargs env variable in u-boot. Otherwise
- clock frameworks will try to disable clocks that are unused and disable
- the hardware. This is because netcp related power domain and clock
- domains are enabled in u-boot as run time power management API currently
- doesn't enable clocks for netcp due to a limitation. This workaround is
- expected to be removed in the future when proper API support becomes
- available. Until then, this work around is needed.
-
-
Document Author
---------------
Murali Karicheri <m-karicheri2@ti.com>
diff --git a/Documentation/arm/keystone/knav-qmss.txt b/Documentation/arm/keystone/knav-qmss.txt
new file mode 100644
index 0000000..fcdb9fd
--- /dev/null
+++ b/Documentation/arm/keystone/knav-qmss.txt
@@ -0,0 +1,56 @@
+* Texas Instruments Keystone Navigator Queue Management SubSystem driver
+
+Driver source code path
+ drivers/soc/ti/knav_qmss.c
+ drivers/soc/ti/knav_qmss_acc.c
+
+The QMSS (Queue Manager Sub System) found on Keystone SOCs is one of
+the main hardware sub system which forms the backbone of the Keystone
+multi-core Navigator. QMSS consist of queue managers, packed-data structure
+processors(PDSP), linking RAM, descriptor pools and infrastructure
+Packet DMA.
+The Queue Manager is a hardware module that is responsible for accelerating
+management of the packet queues. Packets are queued/de-queued by writing or
+reading descriptor address to a particular memory mapped location. The PDSPs
+perform QMSS related functions like accumulation, QoS, or event management.
+Linking RAM registers are used to link the descriptors which are stored in
+descriptor RAM. Descriptor RAM is configurable as internal or external memory.
+The QMSS driver manages the PDSP setups, linking RAM regions,
+queue pool management (allocation, push, pop and notify) and descriptor
+pool management.
+
+knav qmss driver provides a set of APIs to drivers to open/close qmss queues,
+allocate descriptor pools, map the descriptors, push/pop to queues etc. For
+details of the available APIs, please refers to include/linux/soc/ti/knav_qmss.h
+
+DT documentation is available at
+Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
+
+Accumulator QMSS queues using PDSP firmware
+============================================
+The QMSS PDSP firmware support accumulator channel that can monitor a single
+queue or multiple contiguous queues. drivers/soc/ti/knav_qmss_acc.c is the
+driver that interface with the accumulator PDSP. This configures
+accumulator channels defined in DTS (example in DT documentation) to monitor
+1 or 32 queues per channel. More description on the firmware is available in
+CPPI/QMSS Low Level Driver document (docs/CPPI_QMSS_LLD_SDS.pdf) at
+ git://git.ti.com/keystone-rtos/qmss-lld.git
+
+k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin firmware supports upto 48 accumulator
+channels. This firmware is available under ti-keystone folder of
+firmware.git at
+ git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git
+
+To use copy the firmware image to lib/firmware folder of the initramfs or
+ubifs file system and provide a sym link to k2_qmss_pdsp_acc48_k2_le_1_0_0_9.bin
+in the file system and boot up the kernel. User would see
+
+ "firmware file ks2_qmss_pdsp_acc48.bin downloaded for PDSP"
+
+in the boot up log if loading of firmware to PDSP is successful.
+
+Use of accumulated queues requires the firmware image to be present in the
+file system. The driver doesn't acc queues to the supported queue range if
+PDSP is not running in the SoC. The API call fails if there is a queue open
+request to an acc queue and PDSP is not running. So make sure to copy firmware
+to file system before using these queue types.
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
index 5e38e15..430d279 100644
--- a/Documentation/arm/sunxi/README
+++ b/Documentation/arm/sunxi/README
@@ -25,7 +25,7 @@ SunXi family
+ Datasheet
http://dl.linux-sunxi.org/A10s/A10s%20Datasheet%20-%20v1.20%20%282012-03-27%29.pdf
- - Allwinner A13 (sun5i)
+ - Allwinner A13 / R8 (sun5i)
+ Datasheet
http://dl.linux-sunxi.org/A13/A13%20Datasheet%20-%20v1.12%20%282012-03-29%29.pdf
+ User Manual
diff --git a/Documentation/arm64/silicon-errata.txt b/Documentation/arm64/silicon-errata.txt
new file mode 100644
index 0000000..58b71dd
--- /dev/null
+++ b/Documentation/arm64/silicon-errata.txt
@@ -0,0 +1,58 @@
+ Silicon Errata and Software Workarounds
+ =======================================
+
+Author: Will Deacon <will.deacon@arm.com>
+Date : 27 November 2015
+
+It is an unfortunate fact of life that hardware is often produced with
+so-called "errata", which can cause it to deviate from the architecture
+under specific circumstances. For hardware produced by ARM, these
+errata are broadly classified into the following categories:
+
+ Category A: A critical error without a viable workaround.
+ Category B: A significant or critical error with an acceptable
+ workaround.
+ Category C: A minor error that is not expected to occur under normal
+ operation.
+
+For more information, consult one of the "Software Developers Errata
+Notice" documents available on infocenter.arm.com (registration
+required).
+
+As far as Linux is concerned, Category B errata may require some special
+treatment in the operating system. For example, avoiding a particular
+sequence of code, or configuring the processor in a particular way. A
+less common situation may require similar actions in order to declassify
+a Category A erratum into a Category C erratum. These are collectively
+known as "software workarounds" and are only required in the minority of
+cases (e.g. those cases that both require a non-secure workaround *and*
+can be triggered by Linux).
+
+For software workarounds that may adversely impact systems unaffected by
+the erratum in question, a Kconfig entry is added under "Kernel
+Features" -> "ARM errata workarounds via the alternatives framework".
+These are enabled by default and patched in at runtime when an affected
+CPU is detected. For less-intrusive workarounds, a Kconfig option is not
+available and the code is structured (preferably with a comment) in such
+a way that the erratum will not be hit.
+
+This approach can make it slightly onerous to determine exactly which
+errata are worked around in an arbitrary kernel source tree, so this
+file acts as a registry of software workarounds in the Linux Kernel and
+will be updated when new workarounds are committed and backported to
+stable kernels.
+
+| Implementor | Component | Erratum ID | Kconfig |
++----------------+-----------------+-----------------+-------------------------+
+| ARM | Cortex-A53 | #826319 | ARM64_ERRATUM_826319 |
+| ARM | Cortex-A53 | #827319 | ARM64_ERRATUM_827319 |
+| ARM | Cortex-A53 | #824069 | ARM64_ERRATUM_824069 |
+| ARM | Cortex-A53 | #819472 | ARM64_ERRATUM_819472 |
+| ARM | Cortex-A53 | #845719 | ARM64_ERRATUM_845719 |
+| ARM | Cortex-A53 | #843419 | ARM64_ERRATUM_843419 |
+| ARM | Cortex-A57 | #832075 | ARM64_ERRATUM_832075 |
+| ARM | Cortex-A57 | #852523 | N/A |
+| ARM | Cortex-A57 | #834220 | ARM64_ERRATUM_834220 |
+| | | | |
+| Cavium | ThunderX ITS | #22375, #24313 | CAVIUM_ERRATUM_22375 |
+| Cavium | ThunderX GICv3 | #23154 | CAVIUM_ERRATUM_23154 |
diff --git a/Documentation/block/null_blk.txt b/Documentation/block/null_blk.txt
index 2f6c6ff..d8880ca 100644
--- a/Documentation/block/null_blk.txt
+++ b/Documentation/block/null_blk.txt
@@ -70,3 +70,6 @@ use_per_node_hctx=[0/1]: Default: 0
parameter.
1: The multi-queue block layer is instantiated with a hardware dispatch
queue for each CPU node in the system.
+
+use_lightnvm=[0/1]: Default: 0
+ Register device with LightNVM. Requires blk-mq to be used.
diff --git a/Documentation/device-mapper/verity.txt b/Documentation/device-mapper/verity.txt
index e15bc1a..89fd8f9 100644
--- a/Documentation/device-mapper/verity.txt
+++ b/Documentation/device-mapper/verity.txt
@@ -18,11 +18,11 @@ Construction Parameters
0 is the original format used in the Chromium OS.
The salt is appended when hashing, digests are stored continuously and
- the rest of the block is padded with zeros.
+ the rest of the block is padded with zeroes.
1 is the current format that should be used for new devices.
The salt is prepended when hashing and each digest is
- padded with zeros to the power of two.
+ padded with zeroes to the power of two.
<dev>
This is the device containing data, the integrity of which needs to be
@@ -79,6 +79,37 @@ restart_on_corruption
not compatible with ignore_corruption and requires user space support to
avoid restart loops.
+ignore_zero_blocks
+ Do not verify blocks that are expected to contain zeroes and always return
+ zeroes instead. This may be useful if the partition contains unused blocks
+ that are not guaranteed to contain zeroes.
+
+use_fec_from_device <fec_dev>
+ Use forward error correction (FEC) to recover from corruption if hash
+ verification fails. Use encoding data from the specified device. This
+ may be the same device where data and hash blocks reside, in which case
+ fec_start must be outside data and hash areas.
+
+ If the encoding data covers additional metadata, it must be accessible
+ on the hash device after the hash blocks.
+
+ Note: block sizes for data and hash devices must match. Also, if the
+ verity <dev> is encrypted the <fec_dev> should be too.
+
+fec_roots <num>
+ Number of generator roots. This equals to the number of parity bytes in
+ the encoding data. For example, in RS(M, N) encoding, the number of roots
+ is M-N.
+
+fec_blocks <num>
+ The number of encoding data blocks on the FEC device. The block size for
+ the FEC device is <data_block_size>.
+
+fec_start <offset>
+ This is the offset, in <data_block_size> blocks, from the start of the
+ FEC device to the beginning of the encoding data.
+
+
Theory of operation
===================
@@ -98,6 +129,11 @@ per-block basis. This allows for a lightweight hash computation on first read
into the page cache. Block hashes are stored linearly, aligned to the nearest
block size.
+If forward error correction (FEC) support is enabled any recovery of
+corrupted data will be verified using the cryptographic hash of the
+corresponding data. This is why combining error correction with
+integrity checking is essential.
+
Hash Tree
---------
diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
index 973884a..1dfee20 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.txt
+++ b/Documentation/devicetree/bindings/arm/amlogic.txt
@@ -9,6 +9,12 @@ Boards with the Amlogic Meson8 SoC shall have the following properties:
Required root node property:
compatible: "amlogic,meson8";
+Boards with the Amlogic Meson8b SoC shall have the following properties:
+ Required root node property:
+ compatible: "amlogic,meson8b";
+
Board compatible values:
- - "geniatech,atv1200"
- - "minix,neo-x8"
+ - "geniatech,atv1200" (Meson6)
+ - "minix,neo-x8" (Meson8)
+ - "tronfy,mxq" (Meson8b)
+ - "hardkernel,odroid-c1" (Meson8b)
diff --git a/Documentation/devicetree/bindings/arm/apm/scu.txt b/Documentation/devicetree/bindings/arm/apm/scu.txt
new file mode 100644
index 0000000..b45be06
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/apm/scu.txt
@@ -0,0 +1,17 @@
+APM X-GENE SoC series SCU Registers
+
+This system clock unit contain various register that control block resets,
+clock enable/disables, clock divisors and other deepsleep registers.
+
+Properties:
+ - compatible : should contain two values. First value must be:
+ - "apm,xgene-scu"
+ second value must be always "syscon".
+
+ - reg : offset and length of the register set.
+
+Example :
+ scu: system-clk-controller@17000000 {
+ compatible = "apm,xgene-scu","syscon";
+ reg = <0x0 0x17000000 0x0 0x400>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/arm,scpi.txt b/Documentation/devicetree/bindings/arm/arm,scpi.txt
new file mode 100644
index 0000000..86302de
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/arm,scpi.txt
@@ -0,0 +1,188 @@
+System Control and Power Interface (SCPI) Message Protocol
+----------------------------------------------------------
+
+Firmware implementing the SCPI described in ARM document number ARM DUI 0922B
+("ARM Compute Subsystem SCP: Message Interface Protocols")[0] can be used
+by Linux to initiate various system control and power operations.
+
+Required properties:
+
+- compatible : should be "arm,scpi"
+- mboxes: List of phandle and mailbox channel specifiers
+ All the channels reserved by remote SCP firmware for use by
+ SCPI message protocol should be specified in any order
+- shmem : List of phandle pointing to the shared memory(SHM) area between the
+ processors using these mailboxes for IPC, one for each mailbox
+ SHM can be any memory reserved for the purpose of this communication
+ between the processors.
+
+See Documentation/devicetree/bindings/mailbox/mailbox.txt
+for more details about the generic mailbox controller and
+client driver bindings.
+
+Clock bindings for the clocks based on SCPI Message Protocol
+------------------------------------------------------------
+
+This binding uses the common clock binding[1].
+
+Container Node
+==============
+Required properties:
+- compatible : should be "arm,scpi-clocks"
+ All the clocks provided by SCP firmware via SCPI message
+ protocol much be listed as sub-nodes under this node.
+
+Sub-nodes
+=========
+Required properties:
+- compatible : shall include one of the following
+ "arm,scpi-dvfs-clocks" - all the clocks that are variable and index based.
+ These clocks don't provide an entire range of values between the
+ limits but only discrete points within the range. The firmware
+ provides the mapping for each such operating frequency and the
+ index associated with it. The firmware also manages the
+ voltage scaling appropriately with the clock scaling.
+ "arm,scpi-variable-clocks" - all the clocks that are variable and provide full
+ range within the specified range. The firmware provides the
+ range of values within a specified range.
+
+Other required properties for all clocks(all from common clock binding):
+- #clock-cells : Should be 1. Contains the Clock ID value used by SCPI commands.
+- clock-output-names : shall be the corresponding names of the outputs.
+- clock-indices: The identifying number for the clocks(i.e.clock_id) in the
+ node. It can be non linear and hence provide the mapping of identifiers
+ into the clock-output-names array.
+
+SRAM and Shared Memory for SCPI
+-------------------------------
+
+A small area of SRAM is reserved for SCPI communication between application
+processors and SCP.
+
+Required properties:
+- compatible : should be "arm,juno-sram-ns" for Non-secure SRAM on Juno
+
+The rest of the properties should follow the generic mmio-sram description
+found in ../../misc/sysram.txt
+
+Each sub-node represents the reserved area for SCPI.
+
+Required sub-node properties:
+- reg : The base offset and size of the reserved area with the SRAM
+- compatible : should be "arm,juno-scp-shmem" for Non-secure SRAM based
+ shared memory on Juno platforms
+
+Sensor bindings for the sensors based on SCPI Message Protocol
+--------------------------------------------------------------
+SCPI provides an API to access the various sensors on the SoC.
+
+Required properties:
+- compatible : should be "arm,scpi-sensors".
+- #thermal-sensor-cells: should be set to 1. This property follows the
+ thermal device tree bindings[2].
+
+ Valid cell values are raw identifiers (Sensor
+ ID) as used by the firmware. Refer to
+ platform documentation for your
+ implementation for the IDs to use. For Juno
+ R0 and Juno R1 refer to [3].
+
+[0] http://infocenter.arm.com/help/topic/com.arm.doc.dui0922b/index.html
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/thermal/thermal.txt
+[3] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/apas03s22.html
+
+Example:
+
+sram: sram@50000000 {
+ compatible = "arm,juno-sram-ns", "mmio-sram";
+ reg = <0x0 0x50000000 0x0 0x10000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x50000000 0x10000>;
+
+ cpu_scp_lpri: scp-shmem@0 {
+ compatible = "arm,juno-scp-shmem";
+ reg = <0x0 0x200>;
+ };
+
+ cpu_scp_hpri: scp-shmem@200 {
+ compatible = "arm,juno-scp-shmem";
+ reg = <0x200 0x200>;
+ };
+};
+
+mailbox: mailbox0@40000000 {
+ ....
+ #mbox-cells = <1>;
+};
+
+scpi_protocol: scpi@2e000000 {
+ compatible = "arm,scpi";
+ mboxes = <&mailbox 0 &mailbox 1>;
+ shmem = <&cpu_scp_lpri &cpu_scp_hpri>;
+
+ clocks {
+ compatible = "arm,scpi-clocks";
+
+ scpi_dvfs: scpi_clocks@0 {
+ compatible = "arm,scpi-dvfs-clocks";
+ #clock-cells = <1>;
+ clock-indices = <0>, <1>, <2>;
+ clock-output-names = "atlclk", "aplclk","gpuclk";
+ };
+ scpi_clk: scpi_clocks@3 {
+ compatible = "arm,scpi-variable-clocks";
+ #clock-cells = <1>;
+ clock-indices = <3>, <4>;
+ clock-output-names = "pxlclk0", "pxlclk1";
+ };
+ };
+
+ scpi_sensors0: sensors {
+ compatible = "arm,scpi-sensors";
+ #thermal-sensor-cells = <1>;
+ };
+};
+
+cpu@0 {
+ ...
+ reg = <0 0>;
+ clocks = <&scpi_dvfs 0>;
+};
+
+hdlcd@7ff60000 {
+ ...
+ reg = <0 0x7ff60000 0 0x1000>;
+ clocks = <&scpi_clk 4>;
+};
+
+thermal-zones {
+ soc_thermal {
+ polling-delay-passive = <100>;
+ polling-delay = <1000>;
+
+ /* sensor ID */
+ thermal-sensors = <&scpi_sensors0 3>;
+ ...
+ };
+};
+
+In the above example, the #clock-cells is set to 1 as required.
+scpi_dvfs has 3 output clocks namely: atlclk, aplclk, and gpuclk with 0,
+1 and 2 as clock-indices. scpi_clk has 2 output clocks namely: pxlclk0
+and pxlclk1 with 3 and 4 as clock-indices.
+
+The first consumer in the example is cpu@0 and it has '0' as the clock
+specifier which points to the first entry in the output clocks of
+scpi_dvfs i.e. "atlclk".
+
+Similarly the second example is hdlcd@7ff60000 and it has pxlclk1 as input
+clock. '4' in the clock specifier here points to the second entry
+in the output clocks of scpi_clocks i.e. "pxlclk1"
+
+The thermal-sensors property in the soc_thermal node uses the
+temperature sensor provided by SCP firmware to setup a thermal
+zone. The ID "3" is the sensor identifier for the temperature sensor
+as used by the firmware.
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt
index 430608e..0d0c1ae 100644
--- a/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,brcmstb.txt
@@ -20,6 +20,25 @@ system control is required:
- compatible: "brcm,bcm<chip_id>-hif-cpubiuctrl", "syscon"
- compatible: "brcm,bcm<chip_id>-hif-continuation", "syscon"
+hif-cpubiuctrl node
+-------------------
+SoCs with Broadcom Brahma15 ARM-based CPUs have a specific Bus Interface Unit
+(BIU) block which controls and interfaces the CPU complex to the different
+Memory Controller Ports (MCP), one per memory controller (MEMC). This BIU block
+offers a feature called Write Pairing which consists in collapsing two adjacent
+cache lines into a single (bursted) write transaction towards the memory
+controller (MEMC) to maximize write bandwidth.
+
+Required properties:
+
+ - compatible: must be "brcm,bcm7445-hif-cpubiuctrl", "syscon"
+
+Optional properties:
+
+ - brcm,write-pairing:
+ Boolean property, which when present indicates that the chip
+ supports write-pairing.
+
example:
rdb {
#address-cells = <1>;
@@ -35,6 +54,7 @@ example:
hif_cpubiuctrl: syscon@3e2400 {
compatible = "brcm,bcm7445-hif-cpubiuctrl", "syscon";
reg = <0x3e2400 0x5b4>;
+ brcm,write-pairing;
};
hif_continuation: syscon@452000 {
@@ -43,8 +63,7 @@ example:
};
};
-Lastly, nodes that allow for support of SMP initialization and reboot are
-required:
+Nodes that allow for support of SMP initialization and reboot are required:
smpboot
-------
@@ -95,3 +114,142 @@ example:
compatible = "brcm,brcmstb-reboot";
syscon = <&sun_top_ctrl 0x304 0x308>;
};
+
+
+
+Power management
+----------------
+
+For power management (particularly, S2/S3/S5 system suspend), the following SoC
+components are needed:
+
+= Always-On control block (AON CTRL)
+
+This hardware provides control registers for the "always-on" (even in low-power
+modes) hardware, such as the Power Management State Machine (PMSM).
+
+Required properties:
+- compatible : should contain "brcm,brcmstb-aon-ctrl"
+- reg : the register start and length for the AON CTRL block
+
+Example:
+
+aon-ctrl@410000 {
+ compatible = "brcm,brcmstb-aon-ctrl";
+ reg = <0x410000 0x400>;
+};
+
+= Memory controllers
+
+A Broadcom STB SoC typically has a number of independent memory controllers,
+each of which may have several associated hardware blocks, which are versioned
+independently (control registers, DDR PHYs, etc.). One might consider
+describing these controllers as a parent "memory controllers" block, which
+contains N sub-nodes (one for each controller in the system), each of which is
+associated with a number of hardware register resources (e.g., its PHY). See
+the example device tree snippet below.
+
+== MEMC (MEMory Controller)
+
+Represents a single memory controller instance.
+
+Required properties:
+- compatible : should contain "brcm,brcmstb-memc" and "simple-bus"
+
+Should contain subnodes for any of the following relevant hardware resources:
+
+== DDR PHY control
+
+Control registers for this memory controller's DDR PHY.
+
+Required properties:
+- compatible : should contain one of these
+ "brcm,brcmstb-ddr-phy-v225.1"
+ "brcm,brcmstb-ddr-phy-v240.1"
+ "brcm,brcmstb-ddr-phy-v240.2"
+
+- reg : the DDR PHY register range
+
+== DDR SHIMPHY
+
+Control registers for this memory controller's DDR SHIMPHY.
+
+Required properties:
+- compatible : should contain "brcm,brcmstb-ddr-shimphy-v1.0"
+- reg : the DDR SHIMPHY register range
+
+== MEMC DDR control
+
+Sequencer DRAM parameters and control registers. Used for Self-Refresh
+Power-Down (SRPD), among other things.
+
+Required properties:
+- compatible : should contain "brcm,brcmstb-memc-ddr"
+- reg : the MEMC DDR register range
+
+Example:
+
+memory_controllers {
+ ranges;
+ compatible = "simple-bus";
+
+ memc@0 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ ranges;
+
+ ddr-phy@f1106000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0xf1106000 0x21c>;
+ };
+
+ shimphy@f1108000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0xf1108000 0xe4>;
+ };
+
+ memc-ddr@f1102000 {
+ reg = <0xf1102000 0x800>;
+ compatible = "brcm,brcmstb-memc-ddr";
+ };
+ };
+
+ memc@1 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ ranges;
+
+ ddr-phy@f1186000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0xf1186000 0x21c>;
+ };
+
+ shimphy@f1188000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0xf1188000 0xe4>;
+ };
+
+ memc-ddr@f1182000 {
+ reg = <0xf1182000 0x800>;
+ compatible = "brcm,brcmstb-memc-ddr";
+ };
+ };
+
+ memc@2 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ ranges;
+
+ ddr-phy@f1206000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0xf1206000 0x21c>;
+ };
+
+ shimphy@f1208000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0xf1208000 0xe4>;
+ };
+
+ memc-ddr@f1202000 {
+ reg = <0xf1202000 0x800>;
+ compatible = "brcm,brcmstb-memc-ddr";
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/bcm/brcm,nsp.txt b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp.txt
new file mode 100644
index 0000000..eae53e4
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/bcm/brcm,nsp.txt
@@ -0,0 +1,34 @@
+Broadcom Northstar Plus device tree bindings
+--------------------------------------------
+
+Broadcom Northstar Plus family of SoCs are used for switching control
+and management applications as well as residential router/gateway
+applications. The SoC features dual core Cortex A9 ARM CPUs, integrating
+several peripheral interfaces including multiple Gigabit Ethernet PHYs,
+DDR3 memory, PCIE Gen-2, USB 2.0 and USB 3.0, serial and NAND flash,
+SATA and several other IO controllers.
+
+Boards with Northstar Plus SoCs shall have the following properties:
+
+Required root node property:
+
+BCM58522
+compatible = "brcm,bcm58522", "brcm,nsp";
+
+BCM58525
+compatible = "brcm,bcm58525", "brcm,nsp";
+
+BCM58535
+compatible = "brcm,bcm58535", "brcm,nsp";
+
+BCM58622
+compatible = "brcm,bcm58622", "brcm,nsp";
+
+BCM58623
+compatible = "brcm,bcm58623", "brcm,nsp";
+
+BCM58625
+compatible = "brcm,bcm58625", "brcm,nsp";
+
+BCM88312
+compatible = "brcm,bcm88312", "brcm,nsp";
diff --git a/Documentation/devicetree/bindings/arm/coherency-fabric.txt b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
index 8dd4661..9b5c3f6 100644
--- a/Documentation/devicetree/bindings/arm/coherency-fabric.txt
+++ b/Documentation/devicetree/bindings/arm/coherency-fabric.txt
@@ -27,6 +27,11 @@ Required properties:
* For "marvell,armada-380-coherency-fabric", only one pair is needed
for the per-CPU fabric registers.
+Optional properties:
+
+- broken-idle: boolean to set when the Idle mode is not supported by the
+ hardware.
+
Examples:
coherency-fabric@d0020200 {
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index 91e6e5c..3a07a87 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -195,6 +195,8 @@ nodes to be present and contain the properties described below.
"marvell,armada-380-smp"
"marvell,armada-390-smp"
"marvell,armada-xp-smp"
+ "mediatek,mt6589-smp"
+ "mediatek,mt81xx-tz-smp"
"qcom,gcc-msm8660"
"qcom,kpss-acc-v1"
"qcom,kpss-acc-v2"
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index 2a3ba73..34c88b0 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -128,10 +128,18 @@ Example:
reg = <0x0 0x1ee0000 0x0 0x10000>;
};
-Freescale LS2085A SoC Device Tree Bindings
-------------------------------------------
+Freescale ARMv8 based Layerscape SoC family Device Tree Bindings
+----------------------------------------------------------------
-LS2085A ARMv8 based Simulator model
+LS2080A ARMv8 based Simulator model
Required root node properties:
- - compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
+ - compatible = "fsl,ls2080a-simu", "fsl,ls2080a";
+
+LS2080A ARMv8 based QDS Board
+Required root node properties:
+ - compatible = "fsl,ls2080a-qds", "fsl,ls2080a";
+
+LS2080A ARMv8 based RDB Board
+Required root node properties:
+ - compatible = "fsl,ls2080a-rdb", "fsl,ls2080a";
diff --git a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
index 764c738..6ac7c00 100644
--- a/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
+++ b/Documentation/devicetree/bindings/arm/hisilicon/hisilicon.txt
@@ -20,6 +20,10 @@ HiKey Board
Required root node properties:
- compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220";
+HiP05 D02 Board
+Required root node properties:
+ - compatible = "hisilicon,hip05-d02";
+
Hisilicon system controller
Required properties:
diff --git a/Documentation/devicetree/bindings/arm/keystone/keystone.txt b/Documentation/devicetree/bindings/arm/keystone/keystone.txt
index 59d7a46..3090a8a 100644
--- a/Documentation/devicetree/bindings/arm/keystone/keystone.txt
+++ b/Documentation/devicetree/bindings/arm/keystone/keystone.txt
@@ -9,12 +9,26 @@ Required properties:
the form "ti,keystone-*". Generic devices like gic, arch_timers, ns16550
type UART should use the specified compatible for those devices.
+SoC families:
+
+- Keystone 2 generic SoC:
+ compatible = "ti,keystone"
+
+SoCs:
+
+- Keystone 2 Hawking/Kepler
+ compatible = "ti,k2hk", "ti,keystone"
+- Keystone 2 Lamarr
+ compatible = "ti,k2l", "ti,keystone"
+- Keystone 2 Edison
+ compatible = "ti,k2e", "ti,keystone"
+
Boards:
- Keystone 2 Hawking/Kepler EVM
- compatible = "ti,k2hk-evm","ti,keystone"
+ compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone"
- Keystone 2 Lamarr EVM
- compatible = "ti,k2l-evm","ti,keystone"
+ compatible = "ti,k2l-evm", "ti, k2l", "ti,keystone"
- Keystone 2 Edison EVM
- compatible = "ti,k2e-evm","ti,keystone"
+ compatible = "ti,k2e-evm", "ti,k2e", "ti,keystone"
diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2c2x0.txt
index 06c88a4..fe0398c 100644
--- a/Documentation/devicetree/bindings/arm/l2cc.txt
+++ b/Documentation/devicetree/bindings/arm/l2c2x0.txt
@@ -1,7 +1,8 @@
* ARM L2 Cache Controller
-ARM cores often have a separate level 2 cache controller. There are various
-implementations of the L2 cache controller with compatible programming models.
+ARM cores often have a separate L2C210/L2C220/L2C310 (also known as PL210/PL220/
+PL310 and variants) based level 2 cache controller. All these various implementations
+of the L2 cache controller have compatible programming models (Note 1).
Some of the properties that are just prefixed "cache-*" are taken from section
3.7.3 of the ePAPR v1.1 specification which can be found at:
https://www.power.org/wp-content/uploads/2012/06/Power_ePAPR_APPROVED_v1.1.pdf
@@ -67,12 +68,17 @@ Optional properties:
disable if zero.
- arm,prefetch-offset : Override prefetch offset value. Valid values are
0-7, 15, 23, and 31.
-- arm,shared-override : The default behavior of the pl310 cache controller with
- respect to the shareable attribute is to transform "normal memory
- non-cacheable transactions" into "cacheable no allocate" (for reads) or
- "write through no write allocate" (for writes).
+- arm,shared-override : The default behavior of the L220 or PL310 cache
+ controllers with respect to the shareable attribute is to transform "normal
+ memory non-cacheable transactions" into "cacheable no allocate" (for reads)
+ or "write through no write allocate" (for writes).
On systems where this may cause DMA buffer corruption, this property must be
specified to indicate that such transforms are precluded.
+- arm,parity-enable : enable parity checking on the L2 cache (L220 or PL310).
+- arm,parity-disable : disable parity checking on the L2 cache (L220 or PL310).
+- arm,outer-sync-disable : disable the outer sync operation on the L2 cache.
+ Some core tiles, especially ARM PB11MPCore have a faulty L220 cache that
+ will randomly hang unless outer sync operations are disabled.
- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
(forcibly enable), property absent (retain settings set by firmware)
- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
@@ -91,3 +97,9 @@ L2: cache-controller {
cache-level = <2>;
interrupts = <45>;
};
+
+Note 1: The description in this document doesn't apply to integrated L2
+ cache controllers as found in e.g. Cortex-A15/A7/A57/A53. These
+ integrated L2 controllers are assumed to be all preconfigured by
+ early secure boot code. Thus no need to deal with their configuration
+ in the kernel at all.
diff --git a/Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt b/Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt
new file mode 100644
index 0000000..2cdcd71
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/mvebu-cpu-config.txt
@@ -0,0 +1,20 @@
+MVEBU CPU Config registers
+--------------------------
+
+MVEBU (Marvell SOCs: Armada 370/XP)
+
+Required properties:
+
+- compatible: one of:
+ - "marvell,armada-370-cpu-config"
+ - "marvell,armada-xp-cpu-config"
+
+- reg: Should contain CPU config registers location and length, in
+ their per-CPU variant
+
+Example:
+
+ cpu-config@21000 {
+ compatible = "marvell,armada-xp-cpu-config";
+ reg = <0x21000 0x8>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/pmu.txt b/Documentation/devicetree/bindings/arm/pmu.txt
index 4b7c3d9..5651883 100644
--- a/Documentation/devicetree/bindings/arm/pmu.txt
+++ b/Documentation/devicetree/bindings/arm/pmu.txt
@@ -7,9 +7,11 @@ representation in the device tree should be done as under:-
Required properties:
- compatible : should be one of
+ "apm,potenza-pmu"
"arm,armv8-pmuv3"
- "arm.cortex-a57-pmu"
- "arm.cortex-a53-pmu"
+ "arm,cortex-a72-pmu"
+ "arm,cortex-a57-pmu"
+ "arm,cortex-a53-pmu"
"arm,cortex-a17-pmu"
"arm,cortex-a15-pmu"
"arm,cortex-a12-pmu"
diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
index 5aa40ed..a9adab8 100644
--- a/Documentation/devicetree/bindings/arm/psci.txt
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -31,6 +31,10 @@ Main node required properties:
support, but are permitted to be present for compatibility with
existing software when "arm,psci" is later in the compatible list.
+ * "arm,psci-1.0" : for implementations complying to PSCI 1.0. PSCI 1.0 is
+ backward compatible with PSCI 0.2 with minor specification updates,
+ as defined in the PSCI specification[2].
+
- method : The method of calling the PSCI firmware. Permitted
values are:
@@ -100,3 +104,5 @@ Case 3: PSCI v0.2 and PSCI v0.1.
[1] Kernel documentation - ARM idle states bindings
Documentation/devicetree/bindings/arm/idle-states.txt
+[2] Power State Coordination Interface (PSCI) specification
+ http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index af58cd7..8e985dd 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -17,6 +17,10 @@ Rockchip platforms device tree bindings
Required root node properties:
- compatible = "radxa,rock", "rockchip,rk3188";
+- Radxa Rock2 Square board:
+ Required root node properties:
+ - compatible = "radxa,rock2-square", "rockchip,rk3288";
+
- Firefly Firefly-RK3288 board:
Required root node properties:
- compatible = "firefly,firefly-rk3288", "rockchip,rk3288";
@@ -31,6 +35,13 @@ Rockchip platforms device tree bindings
Required root node properties:
- compatible = "netxeon,r89", "rockchip,rk3288";
+- Google Jaq (Haier Chromebook 11 and more):
+ Required root node properties:
+ - compatible = "google,veyron-jaq-rev5", "google,veyron-jaq-rev4",
+ "google,veyron-jaq-rev3", "google,veyron-jaq-rev2",
+ "google,veyron-jaq-rev1", "google,veyron-jaq",
+ "google,veyron", "rockchip,rk3288";
+
- Google Jerry (Hisense Chromebook C11 and more):
Required root node properties:
- compatible = "google,veyron-jerry-rev7", "google,veyron-jerry-rev6",
diff --git a/Documentation/devicetree/bindings/arm/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung-boards.txt
deleted file mode 100644
index 43589d2..0000000
--- a/Documentation/devicetree/bindings/arm/samsung-boards.txt
+++ /dev/null
@@ -1,27 +0,0 @@
-* Samsung's Exynos SoC based boards
-
-Required root node properties:
- - compatible = should be one or more of the following.
- - "samsung,monk" - for Exynos3250-based Samsung Simband board.
- - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board.
- - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board.
- - "samsung,trats" - for Exynos4210-based Tizen Reference board.
- - "samsung,universal_c210" - for Exynos4210-based Samsung board.
- - "samsung,smdk4412", - for Exynos4412-based Samsung SMDK4412 eval board.
- - "samsung,trats2" - for Exynos4412-based Tizen Reference board.
- - "samsung,smdk5250" - for Exynos5250-based Samsung SMDK5250 eval board.
- - "samsung,xyref5260" - for Exynos5260-based Samsung board.
- - "samsung,smdk5410" - for Exynos5410-based Samsung SMDK5410 eval board.
- - "samsung,smdk5420" - for Exynos5420-based Samsung SMDK5420 eval board.
- - "samsung,sd5v1" - for Exynos5440-based Samsung board.
- - "samsung,ssdk5440" - for Exynos5440-based Samsung board.
-
-Optional:
- - firmware node, specifying presence and type of secure firmware:
- - compatible: only "samsung,secure-firmware" is currently supported
- - reg: address of non-secure SYSRAM used for communication with firmware
-
- firmware@0203F000 {
- compatible = "samsung,secure-firmware";
- reg = <0x0203F000 0x1000>;
- };
diff --git a/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
new file mode 100644
index 0000000..12129c0
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/samsung/samsung-boards.txt
@@ -0,0 +1,69 @@
+* Samsung's Exynos SoC based boards
+
+Required root node properties:
+ - compatible = should be one or more of the following.
+ - "samsung,monk" - for Exynos3250-based Samsung Simband board.
+ - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board.
+ - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board.
+ - "samsung,trats" - for Exynos4210-based Tizen Reference board.
+ - "samsung,universal_c210" - for Exynos4210-based Samsung board.
+ - "samsung,smdk4412", - for Exynos4412-based Samsung SMDK4412 eval board.
+ - "samsung,trats2" - for Exynos4412-based Tizen Reference board.
+ - "samsung,smdk5250" - for Exynos5250-based Samsung SMDK5250 eval board.
+ - "samsung,xyref5260" - for Exynos5260-based Samsung board.
+ - "samsung,smdk5410" - for Exynos5410-based Samsung SMDK5410 eval board.
+ - "samsung,smdk5420" - for Exynos5420-based Samsung SMDK5420 eval board.
+ - "samsung,sd5v1" - for Exynos5440-based Samsung board.
+ - "samsung,ssdk5440" - for Exynos5440-based Samsung board.
+
+* Other companies Exynos SoC based
+ * FriendlyARM
+ - "friendlyarm,tiny4412" - for Exynos4412-based FriendlyARM
+ TINY4412 board.
+
+ * Google
+ - "google,pi" - for Exynos5800-based Google Peach Pi
+ Rev 10+ board,
+ also: "google,pi-rev16", "google,pi-rev15", "google,pi-rev14",
+ "google,pi-rev13", "google,pi-rev12", "google,pi-rev11",
+ "google,pi-rev10", "google,peach".
+
+ - "google,pit" - for Exynos5420-based Google Peach Pit
+ Rev 6+ (Exynos5420),
+ also: "google,pit-rev16", "google,pit-rev15", "google,pit-rev14",
+ "google,pit-rev13", "google,pit-rev12", "google,pit-rev11",
+ "google,pit-rev10", "google,pit-rev9", "google,pit-rev8",
+ "google,pit-rev7", "google,pit-rev6", "google,peach".
+
+ - "google,snow-rev4" - for Exynos5250-based Google Snow board,
+ also: "google,snow"
+ - "google,snow-rev5" - for Exynos5250-based Google Snow
+ Rev 5+ board.
+ - "google,spring" - for Exynos5250-based Google Spring board.
+
+ * Hardkernel
+ - "hardkernel,odroid-u3" - for Exynos4412-based Hardkernel Odroid U3.
+ - "hardkernel,odroid-x" - for Exynos4412-based Hardkernel Odroid X.
+ - "hardkernel,odroid-x2" - for Exynos4412-based Hardkernel Odroid X2.
+ - "hardkernel,odroid-xu3" - for Exynos5422-based Hardkernel Odroid XU3.
+ - "hardkernel,odroid-xu3-lite" - for Exynos5422-based Hardkernel
+ Odroid XU3 Lite board.
+ - "hardkernel,odroid-xu4" - for Exynos5422-based Hardkernel Odroid XU4.
+
+ * Insignal
+ - "insignal,arndale" - for Exynos5250-based Insignal Arndale board.
+ - "insignal,arndale-octa" - for Exynos5420-based Insignal Arndale
+ Octa board.
+ - "insignal,origen" - for Exynos4210-based Insignal Origen board.
+ - "insignal,origen4412 - for Exynos4412-based Insignal Origen board.
+
+
+Optional nodes:
+ - firmware node, specifying presence and type of secure firmware:
+ - compatible: only "samsung,secure-firmware" is currently supported
+ - reg: address of non-secure SYSRAM used for communication with firmware
+
+ firmware@0203F000 {
+ compatible = "samsung,secure-firmware";
+ reg = <0x0203F000 0x1000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/shmobile.txt b/Documentation/devicetree/bindings/arm/shmobile.txt
index c4f19b2..40bb9007 100644
--- a/Documentation/devicetree/bindings/arm/shmobile.txt
+++ b/Documentation/devicetree/bindings/arm/shmobile.txt
@@ -39,8 +39,6 @@ Boards:
compatible = "renesas,armadillo800eva"
- BOCK-W
compatible = "renesas,bockw", "renesas,r8a7778"
- - BOCK-W - Reference Device Tree Implementation
- compatible = "renesas,bockw-reference", "renesas,r8a7778"
- Genmai (RTK772100BC00000BR)
compatible = "renesas,genmai", "renesas,r7s72100"
- Gose
@@ -57,7 +55,7 @@ Boards:
compatible = "renesas,lager", "renesas,r8a7790"
- Marzen
compatible = "renesas,marzen", "renesas,r8a7779"
-
-Note: Reference Device Tree Implementations are temporary implementations
- to ease the migration from platform devices to Device Tree, and are
- intended to be removed in the future.
+ - Porter (M2-LCDP)
+ compatible = "renesas,porter", "renesas,r8a7791"
+ - SILK (RTP0RC7794LCB00011S)
+ compatible = "renesas,silk", "renesas,r8a7794"
diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt
index 67da205..bb9b0faa 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.txt
+++ b/Documentation/devicetree/bindings/arm/sunxi.txt
@@ -6,6 +6,7 @@ using one of the following compatible strings:
allwinner,sun4i-a10
allwinner,sun5i-a10s
allwinner,sun5i-a13
+ allwinner,sun5i-r8
allwinner,sun6i-a31
allwinner,sun7i-a20
allwinner,sun8i-a23
diff --git a/Documentation/devicetree/bindings/arm/uniphier/cache-uniphier.txt b/Documentation/devicetree/bindings/arm/uniphier/cache-uniphier.txt
new file mode 100644
index 0000000..d27a646
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/uniphier/cache-uniphier.txt
@@ -0,0 +1,60 @@
+UniPhier outer cache controller
+
+UniPhier SoCs are integrated with a full-custom outer cache controller system.
+All of them have a level 2 cache controller, and some have a level 3 cache
+controller as well.
+
+Required properties:
+- compatible: should be "socionext,uniphier-system-cache"
+- reg: offsets and lengths of the register sets for the device. It should
+ contain 3 regions: control register, revision register, operation register,
+ in this order.
+- cache-unified: specifies the cache is a unified cache.
+- cache-size: specifies the size in bytes of the cache
+- cache-sets: specifies the number of associativity sets of the cache
+- cache-line-size: specifies the line size in bytes
+- cache-level: specifies the level in the cache hierarchy. The value should
+ be 2 for L2 cache, 3 for L3 cache, etc.
+
+Optional properties:
+- next-level-cache: phandle to the next level cache if present. The next level
+ cache should be also compatible with "socionext,uniphier-system-cache".
+
+The L2 cache must exist to use the L3 cache; the cache hierarchy must be
+indicated correctly with "next-level-cache" properties.
+
+Example 1 (system with L2):
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ cache-unified;
+ cache-size = <0x80000>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
+Example 2 (system with L2 and L3):
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x8>,
+ <0x506c0000 0x400>;
+ cache-unified;
+ cache-size = <0x200000>;
+ cache-sets = <512>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ next-level-cache = <&l3>;
+ };
+
+ l3: l3-cache@500c8000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c8000 0x2000>, <0x503c8100 0x8>,
+ <0x506c8000 0x400>;
+ cache-unified;
+ cache-size = <0x400000>;
+ cache-sets = <512>;
+ cache-line-size = <256>;
+ cache-level = <3>;
+ };
diff --git a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
index 20ac9bb..6087283 100644
--- a/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
+++ b/Documentation/devicetree/bindings/ata/brcm,sata-brcmstb.txt
@@ -4,7 +4,9 @@ SATA nodes are defined to describe on-chip Serial ATA controllers.
Each SATA controller should have its own node.
Required properties:
-- compatible : compatible list, may contain "brcm,bcm7445-ahci" and/or
+- compatible : should be one or more of
+ "brcm,bcm7425-ahci"
+ "brcm,bcm7445-ahci"
"brcm,sata3-ahci"
- reg : register mappings for AHCI and SATA_TOP_CTRL
- reg-names : "ahci" and "top-ctrl"
diff --git a/Documentation/devicetree/bindings/ata/sata_rcar.txt b/Documentation/devicetree/bindings/ata/sata_rcar.txt
index 2493a5a3..0764f9a 100644
--- a/Documentation/devicetree/bindings/ata/sata_rcar.txt
+++ b/Documentation/devicetree/bindings/ata/sata_rcar.txt
@@ -8,6 +8,7 @@ Required properties:
- "renesas,sata-r8a7790" for R-Car H2 other than ES1
- "renesas,sata-r8a7791" for R-Car M2-W
- "renesas,sata-r8a7793" for R-Car M2-N
+ - "renesas,sata-r8a7795" for R-Car H3
- reg : address and length of the SATA registers;
- interrupts : must consist of one interrupt specifier.
- clocks : must contain a reference to the functional clock.
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/board.txt b/Documentation/devicetree/bindings/board/fsl-board.txt
index cff38bd..fb7b03e 100644
--- a/Documentation/devicetree/bindings/powerpc/fsl/board.txt
+++ b/Documentation/devicetree/bindings/board/fsl-board.txt
@@ -21,11 +21,14 @@ Example:
This is the memory-mapped registers for on board FPGA.
-Required properities:
+Required properties:
- compatible: should be a board-specific string followed by a string
indicating the type of FPGA. Example:
- "fsl,<board>-fpga", "fsl,fpga-pixis"
+ "fsl,<board>-fpga", "fsl,fpga-pixis", or
+ "fsl,<board>-fpga", "fsl,fpga-qixis"
- reg: should contain the address and the length of the FPGA register set.
+
+Optional properties:
- interrupt-parent: should specify phandle for the interrupt controller.
- interrupts: should specify event (wakeup) IRQ.
@@ -38,6 +41,13 @@ Example (P1022DS):
interrupts = <8 8 0 0>;
};
+Example (LS2080A-RDB):
+
+ cpld@3,0 {
+ compatible = "fsl,ls2080ardb-fpga", "fsl,fpga-qixis";
+ reg = <0x3 0 0x10000>;
+ };
+
* Freescale BCSR GPIO banks
Some BCSR registers act as simple GPIO controllers, each such
diff --git a/Documentation/devicetree/bindings/bus/sunxi-rsb.txt b/Documentation/devicetree/bindings/bus/sunxi-rsb.txt
new file mode 100644
index 0000000..3dd2834
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/sunxi-rsb.txt
@@ -0,0 +1,47 @@
+Allwinner Reduced Serial Bus (RSB) controller
+
+The RSB controller found on later Allwinner SoCs is an SMBus like 2 wire
+serial bus with 1 master and up to 15 slaves. It is represented by a node
+for the controller itself, and child nodes representing the slave devices.
+
+Required properties :
+
+ - reg : Offset and length of the register set for the controller.
+ - compatible : Shall be "allwinner,sun8i-a23-rsb".
+ - interrupts : The interrupt line associated to the RSB controller.
+ - clocks : The gate clk associated to the RSB controller.
+ - resets : The reset line associated to the RSB controller.
+ - #address-cells : shall be 1
+ - #size-cells : shall be 0
+
+Optional properties :
+
+ - clock-frequency : Desired RSB bus clock frequency in Hz. Maximum is 20MHz.
+ If not set this defaults to 3MHz.
+
+Child nodes:
+
+An RSB controller node can contain zero or more child nodes representing
+slave devices on the bus. Child 'reg' properties should contain the slave
+device's hardware address. The hardware address is hardwired in the device,
+which can normally be found in the datasheet.
+
+Example:
+
+ rsb@01f03400 {
+ compatible = "allwinner,sun8i-a23-rsb";
+ reg = <0x01f03400 0x400>;
+ interrupts = <0 39 4>;
+ clocks = <&apb0_gates 3>;
+ clock-frequency = <3000000>;
+ resets = <&apb0_rst 3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pmic@3e3 {
+ compatible = "...";
+ reg = <0x3e3>;
+
+ /* ... */
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/qcom,gcc.txt b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
index 54c23f3..152dfaa 100644
--- a/Documentation/devicetree/bindings/clock/qcom,gcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,gcc.txt
@@ -18,10 +18,14 @@ Required properties :
- #clock-cells : shall contain 1
- #reset-cells : shall contain 1
+Optional properties :
+- #power-domain-cells : shall contain 1
+
Example:
clock-controller@900000 {
compatible = "qcom,gcc-msm8960";
reg = <0x900000 0x4000>;
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
};
diff --git a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
index 29ebf84..34e7614 100644
--- a/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
+++ b/Documentation/devicetree/bindings/clock/qcom,mmcc.txt
@@ -14,10 +14,14 @@ Required properties :
- #clock-cells : shall contain 1
- #reset-cells : shall contain 1
+Optional properties :
+- #power-domain-cells : shall contain 1
+
Example:
clock-controller@4000000 {
compatible = "qcom,mmcc-msm8960";
reg = <0x4000000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
};
diff --git a/Documentation/devicetree/bindings/dma/ti-edma.txt b/Documentation/devicetree/bindings/dma/ti-edma.txt
index d3d0a4f..079b42a 100644
--- a/Documentation/devicetree/bindings/dma/ti-edma.txt
+++ b/Documentation/devicetree/bindings/dma/ti-edma.txt
@@ -22,8 +22,7 @@ Required properties:
Optional properties:
- ti,hwmods: Name of the hwmods associated to the eDMA CC
- ti,edma-memcpy-channels: List of channels allocated to be used for memcpy, iow
- these channels will be SW triggered channels. The list must
- contain 16 bits numbers, see example.
+ these channels will be SW triggered channels. See example.
- ti,edma-reserved-slot-ranges: PaRAM slot ranges which should not be used by
the driver, they are allocated to be used by for example the
DSP. See example.
@@ -56,10 +55,9 @@ edma: edma@49000000 {
ti,tptcs = <&edma_tptc0 7>, <&edma_tptc1 7>, <&edma_tptc2 0>;
/* Channel 20 and 21 is allocated for memcpy */
- ti,edma-memcpy-channels = /bits/ 16 <20 21>;
- /* The following PaRAM slots are reserved: 35-45 and 100-110 */
- ti,edma-reserved-slot-ranges = /bits/ 16 <35 10>,
- /bits/ 16 <100 10>;
+ ti,edma-memcpy-channels = <20 21>;
+ /* The following PaRAM slots are reserved: 35-44 and 100-109 */
+ ti,edma-reserved-slot-ranges = <35 10>, <100 10>;
};
edma_tptc0: tptc@49800000 {
diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
index 805ddcd..120bc49 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
+++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt
@@ -1,9 +1,9 @@
-* Freescale MPC512x/MPC8xxx GPIO controller
+* Freescale MPC512x/MPC8xxx/Layerscape GPIO controller
Required properties:
- compatible : Should be "fsl,<soc>-gpio"
The following <soc>s are known to be supported:
- mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq
+ mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq.
- reg : Address and length of the register set for the device
- interrupts : Should be the port interrupt shared by all 32 pins.
- #gpio-cells : Should be two. The first cell is the pin number and
@@ -11,6 +11,10 @@ Required properties:
0 = active high
1 = active low
+Optional properties:
+- little-endian : GPIO registers are used as little endian. If not
+ present registers are used as big endian by default.
+
Example:
gpio0: gpio@1100 {
diff --git a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
index 610757c..c6d5332 100644
--- a/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
+++ b/Documentation/devicetree/bindings/hwmon/pwm-fan.txt
@@ -3,10 +3,35 @@ Bindings for a fan connected to the PWM lines
Required properties:
- compatible : "pwm-fan"
- pwms : the PWM that is used to control the PWM fan
+- cooling-levels : PWM duty cycle values in a range from 0 to 255
+ which correspond to thermal cooling states
Example:
- pwm-fan {
+ fan0: pwm-fan {
compatible = "pwm-fan";
- status = "okay";
+ cooling-min-state = <0>;
+ cooling-max-state = <3>;
+ #cooling-cells = <2>;
pwms = <&pwm 0 10000 0>;
+ cooling-levels = <0 102 170 230>;
};
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ thermal-sensors = <&tmu 0>;
+ polling-delay-passive = <0>;
+ polling-delay = <0>;
+ trips {
+ cpu_alert1: cpu-alert1 {
+ temperature = <100000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ };
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&fan0 0 1>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
index a4e1cbc..5b123e0 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-davinci.txt
@@ -1,10 +1,10 @@
-* Texas Instruments Davinci I2C
+* Texas Instruments Davinci/Keystone I2C
This file provides information, what the device node for the
-davinci i2c interface contain.
+davinci/keystone i2c interface contains.
Required properties:
-- compatible: "ti,davinci-i2c";
+- compatible: "ti,davinci-i2c" or "ti,keystone-i2c";
- reg : Offset and length of the register set for the device
Recommended properties :
diff --git a/Documentation/devicetree/bindings/i2c/i2c-imx.txt b/Documentation/devicetree/bindings/i2c/i2c-imx.txt
index ce4311d..eab5836 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-imx.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-imx.txt
@@ -14,6 +14,10 @@ Optional properties:
The absence of the propoerty indicates the default frequency 100 kHz.
- dmas: A list of two dma specifiers, one for each entry in dma-names.
- dma-names: should contain "tx" and "rx".
+- scl-gpios: specify the gpio related to SCL pin
+- sda-gpios: specify the gpio related to SDA pin
+- pinctrl: add extra pinctrl to configure i2c pins to gpio function for i2c
+ bus recovery, call it "gpio" state
Examples:
@@ -37,4 +41,9 @@ i2c0: i2c@40066000 { /* i2c0 on vf610 */
dmas = <&edma0 0 50>,
<&edma0 0 51>;
dma-names = "rx","tx";
+ pinctrl-names = "default", "gpio";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ pinctrl-1 = <&pinctrl_i2c1_gpio>;
+ scl-gpios = <&gpio5 26 GPIO_ACTIVE_HIGH>;
+ sda-gpios = <&gpio5 27 GPIO_ACTIVE_HIGH>;
};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
index 16b3e07..ea406eb2 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt
@@ -10,6 +10,7 @@ Required properties:
"renesas,i2c-r8a7792"
"renesas,i2c-r8a7793"
"renesas,i2c-r8a7794"
+ "renesas,i2c-r8a7795"
- reg: physical base address of the controller and length of memory mapped
region.
- interrupts: interrupt specifier.
diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
index 2bfc6e7..214f94c 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt
@@ -10,6 +10,7 @@ Required properties:
- "renesas,iic-r8a7792" (R-Car V2H)
- "renesas,iic-r8a7793" (R-Car M2-N)
- "renesas,iic-r8a7794" (R-Car E2)
+ - "renesas,iic-r8a7795" (R-Car H3)
- "renesas,iic-sh73a0" (SH-Mobile AG5)
- reg : address start and address range size of device
- interrupts : interrupt of device
diff --git a/Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt b/Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt
new file mode 100644
index 0000000..27fc6f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-uniphier-f.txt
@@ -0,0 +1,25 @@
+UniPhier I2C controller (FIFO-builtin)
+
+Required properties:
+- compatible: should be "socionext,uniphier-fi2c".
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- reg: offset and length of the register set for the device.
+- interrupts: a single interrupt specifier.
+- clocks: phandle to the input clock.
+
+Optional properties:
+- clock-frequency: desired I2C bus frequency in Hz. The maximum supported
+ value is 400000. Defaults to 100000 if not specified.
+
+Examples:
+
+ i2c0: i2c@58780000 {
+ compatible = "socionext,uniphier-fi2c";
+ reg = <0x58780000 0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 4>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-uniphier.txt b/Documentation/devicetree/bindings/i2c/i2c-uniphier.txt
new file mode 100644
index 0000000..26f9d95
--- /dev/null
+++ b/Documentation/devicetree/bindings/i2c/i2c-uniphier.txt
@@ -0,0 +1,25 @@
+UniPhier I2C controller (FIFO-less)
+
+Required properties:
+- compatible: should be "socionext,uniphier-i2c".
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+- reg: offset and length of the register set for the device.
+- interrupts: a single interrupt specifier.
+- clocks: phandle to the input clock.
+
+Optional properties:
+- clock-frequency: desired I2C bus frequency in Hz. The maximum supported
+ value is 400000. Defaults to 100000 if not specified.
+
+Examples:
+
+ i2c0: i2c@58400000 {
+ compatible = "socionext,uniphier-i2c";
+ reg = <0x58400000 0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <0 41 1>;
+ clocks = <&i2c_clk>;
+ clock-frequency = <100000>;
+ };
diff --git a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
index b9c32f6..4357e49 100644
--- a/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
+++ b/Documentation/devicetree/bindings/input/sun4i-lradc-keys.txt
@@ -12,7 +12,7 @@ Each key is represented as a sub-node of "allwinner,sun4i-a10-lradc-keys":
Required subnode-properties:
- label: Descriptive name of the key.
- linux,code: Keycode to emit.
- - channel: Channel this key is attached to, mut be 0 or 1.
+ - channel: Channel this key is attached to, must be 0 or 1.
- voltage: Voltage in µV at lradc input when this key is pressed.
Example:
diff --git a/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt b/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt
index 09089a6..b80c04b 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/tsc2005.txt
@@ -1,14 +1,15 @@
-* Texas Instruments tsc2005 touchscreen controller
+* Texas Instruments tsc2004 and tsc2005 touchscreen controllers
Required properties:
- - compatible : "ti,tsc2005"
- - reg : SPI device address
- - spi-max-frequency : Maximal SPI speed
+ - compatible : "ti,tsc2004" or "ti,tsc2005"
+ - reg : Device address
- interrupts : IRQ specifier
- - reset-gpios : GPIO specifier
- - vio-supply : Regulator specifier
+ - spi-max-frequency : Maximum SPI clocking speed of the device
+ (for tsc2005)
Optional properties:
+ - vio-supply : Regulator specifier
+ - reset-gpios : GPIO specifier for the controller reset line
- ti,x-plate-ohms : integer, resistance of the touchscreen's X plates
in ohm (defaults to 280)
- ti,esd-recovery-timeout-ms : integer, if the touchscreen does not respond after
@@ -18,6 +19,27 @@ Optional properties:
Example:
+&i2c3 {
+ tsc2004@48 {
+ compatible = "ti,tsc2004";
+ reg = <0x48>;
+ vio-supply = <&vio>;
+
+ reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;
+ interrupts-extended = <&gpio1 27 IRQ_TYPE_EDGE_RISING>;
+
+ touchscreen-fuzz-x = <4>;
+ touchscreen-fuzz-y = <7>;
+ touchscreen-fuzz-pressure = <2>;
+ touchscreen-size-x = <4096>;
+ touchscreen-size-y = <4096>;
+ touchscreen-max-pressure = <2048>;
+
+ ti,x-plate-ohms = <280>;
+ ti,esd-recovery-timeout-ms = <8000>;
+ };
+}
+
&mcspi1 {
tsc2005@0 {
compatible = "ti,tsc2005";
diff --git a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
index d1c5cda..81cd369 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/allwinner,sun67i-sc-nmi.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/allwinner,sunxi-nmi.txt
@@ -4,7 +4,7 @@ Allwinner Sunxi NMI Controller
Required properties:
- compatible : should be "allwinner,sun7i-a20-sc-nmi" or
- "allwinner,sun6i-a31-sc-nmi"
+ "allwinner,sun6i-a31-sc-nmi" or "allwinner,sun9i-a80-nmi"
- reg : Specifies base physical address and size of the registers.
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
diff --git a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
index cc56021..5a1cb4b 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/arm,gic.txt
@@ -18,6 +18,7 @@ Main node required properties:
"arm,cortex-a9-gic"
"arm,gic-400"
"arm,pl390"
+ "arm,tc11mp-gic"
"brcm,brahma-b15-gic"
"qcom,msm-8660-qgic"
"qcom,msm-qgic2"
diff --git a/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
new file mode 100644
index 0000000..720f7c9
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/hisilicon,mbigen-v2.txt
@@ -0,0 +1,74 @@
+Hisilicon mbigen device tree bindings.
+=======================================
+
+Mbigen means: message based interrupt generator.
+
+MBI is kind of msi interrupt only used on Non-PCI devices.
+
+To reduce the wired interrupt number connected to GIC,
+Hisilicon designed mbigen to collect and generate interrupt.
+
+
+Non-pci devices can connect to mbigen and generate the
+interrupt by writing ITS register.
+
+The mbigen chip and devices connect to mbigen have the following properties:
+
+Mbigen main node required properties:
+-------------------------------------------
+- compatible: Should be "hisilicon,mbigen-v2"
+
+- reg: Specifies the base physical address and size of the Mbigen
+ registers.
+
+- interrupt controller: Identifies the node as an interrupt controller
+
+- msi-parent: Specifies the MSI controller this mbigen use.
+ For more detail information,please refer to the generic msi-parent binding in
+ Documentation/devicetree/bindings/interrupt-controller/msi.txt.
+
+- num-pins: the total number of pins implemented in this Mbigen
+ instance.
+
+- #interrupt-cells : Specifies the number of cells needed to encode an
+ interrupt source. The value must be 2.
+
+ The 1st cell is hardware pin number of the interrupt.This number is local to
+ each mbigen chip and in the range from 0 to the maximum interrupts number
+ of the mbigen.
+
+ The 2nd cell is the interrupt trigger type.
+ The value of this cell should be:
+ 1: rising edge triggered
+ or
+ 4: high level triggered
+
+Examples:
+
+ mbigen_device_gmac:intc {
+ compatible = "hisilicon,mbigen-v2";
+ reg = <0x0 0xc0080000 0x0 0x10000>;
+ interrupt-controller;
+ msi-parent = <&its_dsa 0x40b1c>;
+ num-pins = <9>;
+ #interrupt-cells = <2>;
+ };
+
+Devices connect to mbigen required properties:
+----------------------------------------------------
+-interrupt-parent: Specifies the mbigen device node which device connected.
+
+-interrupts:Specifies the interrupt source.
+ For the specific information of each cell in this property,please refer to
+ the "interrupt-cells" description mentioned above.
+
+Examples:
+ gmac0: ethernet@c2080000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0 0xc2080000 0 0x20000>,
+ <0 0xc0000000 0 0x1000>;
+ interrupt-parent = <&mbigen_device_gmac>;
+ interrupts = <656 1>,
+ <657 1>;
+ };
diff --git a/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt b/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt
new file mode 100644
index 0000000..7f15f1b
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/technologic,ts4800.txt
@@ -0,0 +1,16 @@
+TS-4800 FPGA interrupt controller
+
+TS-4800 FPGA has an internal interrupt controller. When one of the
+interrupts is triggered, the SoC is notified, usually using a GPIO as
+parent interrupt source.
+
+Required properties:
+- compatible: should be "technologic,ts4800-irqc"
+- interrupt-controller: identifies the node as an interrupt controller
+- reg: physical base address of the controller and length of memory mapped
+ region
+- #interrupt-cells: specifies the number of cells needed to encode an interrupt
+ source, should be 1.
+- interrupt-parent: phandle to the parent interrupt controller this one is
+ cascaded from
+- interrupts: specifies the interrupt line in the interrupt-parent controller
diff --git a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
index 729543c..bc620fe 100644
--- a/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
+++ b/Documentation/devicetree/bindings/iommu/samsung,sysmmu.txt
@@ -47,7 +47,7 @@ Required properties:
- clocks: Required if the System MMU is needed to gate its clock.
- power-domains: Required if the System MMU is needed to gate its power.
Please refer to the following document:
- Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+ Documentation/devicetree/bindings/power/pd-samsung.txt
Examples:
gsc_0: gsc@13e00000 {
diff --git a/Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt b/Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
index d4def76..cc51b1f 100644
--- a/Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
+++ b/Documentation/devicetree/bindings/media/stih407-c8sectpfe.txt
@@ -35,7 +35,7 @@ Required properties (tsin (child) node):
- tsin-num : tsin id of the InputBlock (must be between 0 to 6)
- i2c-bus : phandle to the I2C bus DT node which the demodulators & tuners on this tsin channel are connected.
-- rst-gpio : reset gpio for this tsin channel.
+- reset-gpios : reset gpio for this tsin channel.
Optional properties (tsin (child) node):
@@ -55,27 +55,27 @@ Example:
status = "okay";
reg = <0x08a20000 0x10000>, <0x08a00000 0x4000>;
reg-names = "stfe", "stfe-ram";
- interrupts = <0 34 0>, <0 35 0>;
+ interrupts = <GIC_SPI 34 IRQ_TYPE_NONE>, <GIC_SPI 35 IRQ_TYPE_NONE>;
interrupt-names = "stfe-error-irq", "stfe-idle-irq";
-
- pinctrl-names = "tsin0-serial", "tsin0-parallel", "tsin3-serial",
- "tsin4-serial", "tsin5-serial";
-
pinctrl-0 = <&pinctrl_tsin0_serial>;
pinctrl-1 = <&pinctrl_tsin0_parallel>;
pinctrl-2 = <&pinctrl_tsin3_serial>;
pinctrl-3 = <&pinctrl_tsin4_serial_alt3>;
pinctrl-4 = <&pinctrl_tsin5_serial_alt1>;
-
+ pinctrl-names = "tsin0-serial",
+ "tsin0-parallel",
+ "tsin3-serial",
+ "tsin4-serial",
+ "tsin5-serial";
clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>;
- clock-names = "stfe";
+ clock-names = "c8sectpfe";
/* tsin0 is TSA on NIMA */
tsin0: port@0 {
tsin-num = <0>;
serial-not-parallel;
i2c-bus = <&ssc2>;
- rst-gpio = <&pio15 4 0>;
+ reset-gpios = <&pio15 4 GPIO_ACTIVE_HIGH>;
dvb-card = <STV0367_TDA18212_NIMA_1>;
};
@@ -83,7 +83,7 @@ Example:
tsin-num = <3>;
serial-not-parallel;
i2c-bus = <&ssc3>;
- rst-gpio = <&pio15 7 0>;
+ reset-gpios = <&pio15 7 GPIO_ACTIVE_HIGH>;
dvb-card = <STV0367_TDA18212_NIMB_1>;
};
};
diff --git a/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt b/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt
index e6df32f..22b77ee 100644
--- a/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/arm,pl172.txt
@@ -1,8 +1,9 @@
-* Device tree bindings for ARM PL172 MultiPort Memory Controller
+* Device tree bindings for ARM PL172/PL175/PL176 MultiPort Memory Controller
Required properties:
-- compatible: "arm,pl172", "arm,primecell"
+- compatible: Must be "arm,primecell" and exactly one from
+ "arm,pl172", "arm,pl175" or "arm,pl176".
- reg: Must contains offset/length value for controller.
@@ -56,7 +57,8 @@ Optional child cs node config properties:
- mpmc,extended-wait: Enable extended wait.
-- mpmc,buffer-enable: Enable write buffer.
+- mpmc,buffer-enable: Enable write buffer, option is not supported by
+ PL175 and PL176 controllers.
- mpmc,write-protect: Enable write protect.
diff --git a/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt b/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt
index c64b792..9f78e6c 100644
--- a/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt
+++ b/Documentation/devicetree/bindings/memory-controllers/renesas-memory-controllers.txt
@@ -24,9 +24,9 @@ Required properties:
Optional properties:
- interrupts: Must contain a list of interrupt specifiers for memory
controller interrupts, if available.
- - interrupts-names: Must contain a list of interrupt names corresponding to
- the interrupts in the interrupts property, if available.
- Valid interrupt names are:
+ - interrupt-names: Must contain a list of interrupt names corresponding to
+ the interrupts in the interrupts property, if available.
+ Valid interrupt names are:
- "sec" (secure interrupt)
- "temp" (normal (temperature) interrupt)
- power-domains: Must contain a reference to the PM domain that the memory
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
index a42adda..09b94c9 100644
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt
@@ -22,6 +22,10 @@ Optional properties:
- samsung,s2mps11-wrstbi-ground: Indicates that WRSTBI pin of PMIC is pulled
down. When the system is suspended it will always go down thus triggerring
unwanted buck warm reset (setting buck voltages to default values).
+- samsung,s2mps11-acokb-ground: Indicates that ACOKB pin of S2MPS11 PMIC is
+ connected to the ground so the PMIC must manually set PWRHOLD bit in CTRL1
+ register to turn off the power. Usually the ACOKB is pulled up to VBATT so
+ when PWRHOLD pin goes low, the rising ACOKB will trigger power off.
Optional nodes:
- clocks: s2mps11, s2mps13, s2mps15 and s5m8767 provide three(AP/CP/BT) buffered 32.768
diff --git a/Documentation/devicetree/bindings/mips/img/xilfpga.txt b/Documentation/devicetree/bindings/mips/img/xilfpga.txt
new file mode 100644
index 0000000..57e7ee9
--- /dev/null
+++ b/Documentation/devicetree/bindings/mips/img/xilfpga.txt
@@ -0,0 +1,83 @@
+Imagination University Program MIPSfpga
+=======================================
+
+Under the Imagination University Program, a microAptiv UP core has been
+released for academic usage.
+
+As we are dealing with a MIPS core instantiated on an FPGA, specifications
+are fluid and can be varied in RTL.
+
+This binding document is provided as baseline guidance for the example
+project provided by IMG.
+
+The example project runs on the Nexys4DDR board by Digilent powered by
+the ARTIX-7 FPGA by Xilinx.
+
+Relevant details about the example project and the Nexys4DDR board:
+
+- microAptiv UP core m14Kc
+- 50MHz clock speed
+- 128Mbyte DDR RAM at 0x0000_0000
+- 8Kbyte RAM at 0x1000_0000
+- axi_intc at 0x1020_0000
+- axi_uart16550 at 0x1040_0000
+- axi_gpio at 0x1060_0000
+- axi_i2c at 0x10A0_0000
+- custom_gpio at 0x10C0_0000
+- axi_ethernetlite at 0x10E0_0000
+- 8Kbyte BootRAM at 0x1FC0_0000
+
+Required properties:
+--------------------
+ - compatible: Must include "digilent,nexys4ddr","img,xilfpga".
+
+CPU nodes:
+----------
+A "cpus" node is required. Required properties:
+ - #address-cells: Must be 1.
+ - #size-cells: Must be 0.
+A CPU sub-node is also required for at least CPU 0. Required properties:
+ - device_type: Must be "cpu".
+ - compatible: Must be "mips,m14Kc".
+ - reg: Must be <0>.
+ - clocks: phandle to ext clock for fixed-clock received by MIPS core.
+
+Example:
+
+ compatible = "img,xilfpga","digilent,nexys4ddr";
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "mips,m14Kc";
+ reg = <0>;
+ clocks = <&ext>;
+ };
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+
+Boot protocol:
+--------------
+
+The BootRAM is a writeable "RAM" in FPGA at 0x1FC0_0000.
+This is for easy reprogrammibility via JTAG.
+
+The BootRAM initializes the cache and the axi_uart peripheral.
+
+DDR initialization is already handled by a HW IP block.
+
+When the example project bitstream is loaded, the cpu_reset button
+needs to be pressed.
+
+The bootram initializes the cache and axi_uart.
+Then outputs MIPSFPGA\n\r on the serial port on the Nexys4DDR board.
+
+At this point, the board is ready to load the Linux kernel
+vmlinux file via JTAG.
diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
index cae29eb..ff611fa 100644
--- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
+++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
@@ -11,6 +11,7 @@ Required properties:
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
+ - "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
- "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
- clocks: reference to the functional clock
diff --git a/Documentation/devicetree/bindings/mtd/partition.txt b/Documentation/devicetree/bindings/mtd/partition.txt
index f1e2a02..1c63e40 100644
--- a/Documentation/devicetree/bindings/mtd/partition.txt
+++ b/Documentation/devicetree/bindings/mtd/partition.txt
@@ -6,7 +6,9 @@ used for what purposes, but which don't use an on-flash partition table such
as RedBoot.
The partition table should be a subnode of the mtd node and should be named
-'partitions'. Partitions are defined in subnodes of the partitions node.
+'partitions'. This node should have the following property:
+- compatible : (required) must be "fixed-partitions"
+Partitions are then defined in subnodes of the partitions node.
For backwards compatibility partitions as direct subnodes of the mtd device are
supported. This use is discouraged.
@@ -36,6 +38,7 @@ Examples:
flash@0 {
partitions {
+ compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
@@ -53,6 +56,7 @@ flash@0 {
flash@1 {
partitions {
+ compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <2>;
@@ -66,6 +70,7 @@ flash@1 {
flash@2 {
partitions {
+ compatible = "fixed-partitions";
#address-cells = <2>;
#size-cells = <2>;
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 4efca56..28a4781 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -40,14 +40,19 @@ Optional properties:
Slave Properties:
Required properties:
-- phy_id : Specifies slave phy id
- phy-mode : See ethernet.txt file in the same directory
Optional properties:
- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
- mac-address : See ethernet.txt file in the same directory
+- phy_id : Specifies slave phy id
- phy-handle : See ethernet.txt file in the same directory
+Slave sub-nodes:
+- fixed-link : See fixed-link.txt file in the same directory
+ Either the property phy_id, or the sub-node
+ fixed-link can be specified
+
Note: "ti,hwmods" field is used to fetch the base address and irq
resources from TI, omap hwmod data base during device registration.
Future plan is to migrate hwmod data base contents into device tree
diff --git a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
index f5a8ca2..aeea50c 100644
--- a/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
+++ b/Documentation/devicetree/bindings/net/marvell-armada-370-neta.txt
@@ -8,6 +8,11 @@ Required properties:
- phy-mode: See ethernet.txt file in the same directory
- clocks: a pointer to the reference clock for this device.
+Optional properties:
+- tx-csum-limit: maximum mtu supported by port that allow TX checksum.
+ Value is presented in bytes. If not used, by default 1600B is set for
+ "marvell,armada-370-neta" and 9800B for others.
+
Example:
ethernet@d0070000 {
@@ -15,6 +20,7 @@ ethernet@d0070000 {
reg = <0xd0070000 0x2500>;
interrupts = <8>;
clocks = <&gate_clk 4>;
+ tx-csum-limit = <9800>
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
diff --git a/Documentation/devicetree/bindings/pci/arm,juno-r1-pcie.txt b/Documentation/devicetree/bindings/pci/arm,juno-r1-pcie.txt
new file mode 100644
index 0000000..f7514c1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/arm,juno-r1-pcie.txt
@@ -0,0 +1,10 @@
+* ARM Juno R1 PCIe interface
+
+This PCIe host controller is based on PLDA XpressRICH3-AXI IP
+and thus inherits all the common properties defined in plda,xpressrich3-axi.txt
+as well as the base properties defined in host-generic-pci.txt.
+
+Required properties:
+ - compatible: "arm,juno-r1-pcie"
+ - dma-coherent: The host controller bridges the AXI transactions into PCIe bus
+ in a manner that makes the DMA operations to appear coherent to the CPUs.
diff --git a/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi.txt b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi.txt
new file mode 100644
index 0000000..f3f75bf
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/plda,xpressrich3-axi.txt
@@ -0,0 +1,12 @@
+* PLDA XpressRICH3-AXI host controller
+
+The PLDA XpressRICH3-AXI host controller can be configured in a manner that
+makes it compliant with the SBSA[1] standard published by ARM Ltd. For those
+scenarios, the host-generic-pci.txt bindings apply with the following additions
+to the compatible property:
+
+Required properties:
+ - compatible: should contain "plda,xpressrich3-axi" to identify the IP used.
+
+
+[1] http://infocenter.arm.com/help/topic/com.arm.doc.den0029a/
diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
index b321b26..9213b27 100644
--- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt
@@ -17,7 +17,10 @@ Required properties:
"allwinner,sun8i-a23-pinctrl"
"allwinner,sun8i-a23-r-pinctrl"
"allwinner,sun8i-a33-pinctrl"
+ "allwinner,sun9i-a80-pinctrl"
+ "allwinner,sun9i-a80-r-pinctrl"
"allwinner,sun8i-a83t-pinctrl"
+ "allwinner,sun8i-h3-pinctrl"
- reg: Should contain the register physical address and length for the
pin controller.
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt
index 16589fb6..e427792 100644
--- a/Documentation/devicetree/bindings/pinctrl/brcm,cygnus-gpio.txt
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,iproc-gpio.txt
@@ -1,4 +1,4 @@
-Broadcom Cygnus GPIO/PINCONF Controller
+Broadcom iProc GPIO/PINCONF Controller
Required properties:
@@ -7,9 +7,12 @@ Required properties:
"brcm,cygnus-crmu-gpio" or "brcm,iproc-gpio"
- reg:
- Define the base and range of the I/O address space that contains the Cygnus
+ Define the base and range of the I/O address space that contains SoC
GPIO/PINCONF controller registers
+- ngpios:
+ Total number of in-use slots in GPIO controller
+
- #gpio-cells:
Must be two. The first cell is the GPIO pin number (within the
controller's pin space) and the second cell is used for the following:
@@ -57,6 +60,7 @@ Example:
compatible = "brcm,cygnus-ccm-gpio";
reg = <0x1800a000 0x50>,
<0x0301d164 0x20>;
+ ngpios = <24>;
#gpio-cells = <2>;
gpio-controller;
interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
@@ -78,6 +82,7 @@ Example:
gpio_asiu: gpio@180a5000 {
compatible = "brcm,cygnus-asiu-gpio";
reg = <0x180a5000 0x668>;
+ ngpios = <146>;
#gpio-cells = <2>;
gpio-controller;
interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt b/Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt
new file mode 100644
index 0000000..0844168
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/brcm,nsp-gpio.txt
@@ -0,0 +1,80 @@
+Broadcom Northstar plus (NSP) GPIO/PINCONF Controller
+
+Required properties:
+- compatible:
+ Must be "brcm,nsp-gpio-a"
+
+- reg:
+ Should contain the register physical address and length for each of
+ GPIO base, IO control registers
+
+- #gpio-cells:
+ Must be two. The first cell is the GPIO pin number (within the
+ controller's pin space) and the second cell is used for the following:
+ bit[0]: polarity (0 for active high and 1 for active low)
+
+- gpio-controller:
+ Specifies that the node is a GPIO controller
+
+- ngpios:
+ Number of gpios supported (58x25 supports 32 and 58x23 supports 24)
+
+Optional properties:
+- interrupts:
+ Interrupt ID
+
+- interrupt-controller:
+ Specifies that the node is an interrupt controller
+
+- gpio-ranges:
+ Specifies the mapping between gpio controller and pin-controllers pins.
+ This requires 4 fields in cells defined as -
+ 1. Phandle of pin-controller.
+ 2. GPIO base pin offset.
+ 3 Pin-control base pin offset.
+ 4. number of gpio pins which are linearly mapped from pin base.
+
+Supported generic PINCONF properties in child nodes:
+- pins:
+ The list of pins (within the controller's own pin space) that properties
+ in the node apply to. Pin names are "gpio-<pin>"
+
+- bias-disable:
+ Disable pin bias
+
+- bias-pull-up:
+ Enable internal pull up resistor
+
+- bias-pull-down:
+ Enable internal pull down resistor
+
+- drive-strength:
+ Valid drive strength values include 2, 4, 6, 8, 10, 12, 14, 16 (mA)
+
+Example:
+
+ gpioa: gpio@18000020 {
+ compatible = "brcm,nsp-gpio-a";
+ reg = <0x18000020 0x100>,
+ <0x1803f1c4 0x1c>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ ngpios = <32>;
+ gpio-ranges = <&pinctrl 0 0 31>;
+ interrupt-controller;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+
+ /* Hog a few default settings */
+ pinctrl-names = "default";
+ pinctrl-0 = <&led>;
+ led: led {
+ pins = "gpio-1";
+ bias-pull-up;
+ };
+
+ pwr: pwr {
+ gpio-hog;
+ gpios = <3 1>;
+ output-high;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt
index e89b467..8e5216b 100644
--- a/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt
+++ b/Documentation/devicetree/bindings/pinctrl/lantiq,pinctrl-xway.txt
@@ -1,7 +1,16 @@
Lantiq XWAY pinmux controller
Required properties:
-- compatible: "lantiq,pinctrl-xway" or "lantiq,pinctrl-xr9"
+- compatible: "lantiq,pinctrl-xway", (DEPRECATED: Use "lantiq,pinctrl-danube")
+ "lantiq,pinctrl-xr9", (DEPRECATED: Use "lantiq,xrx100-pinctrl" or
+ "lantiq,xrx200-pinctrl")
+ "lantiq,pinctrl-ase", (DEPRECATED: Use "lantiq,ase-pinctrl")
+ "lantiq,<chip>-pinctrl", where <chip> is:
+ "ase" (XWAY AMAZON Family)
+ "danube" (XWAY DANUBE Family)
+ "xrx100" (XWAY xRX100 Family)
+ "xrx200" (XWAY xRX200 Family)
+ "xrx300" (XWAY xRX300 Family)
- reg: Should contain the physical address and length of the gpio/pinmux
register range
@@ -36,19 +45,87 @@ Required subnode-properties:
Valid values for group and function names:
+XWAY: (DEPRECATED: Use DANUBE)
mux groups:
exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1,
ebu wait, nand ale, nand cs1, nand cle, spi, spi_cs1, spi_cs2, spi_cs3,
- spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi , gpt1, gpt2,
+ spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2,
gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3, req1, req2,
req3
- additional mux groups (XR9 only):
- mdio, nand rdy, nand rd, exin3, exin4, gnt4, req4
+ functions:
+ spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu
+
+XR9: ( DEPRECATED: Use xRX100/xRX200)
+ mux groups:
+ exin0, exin1, exin2, exin3, exin4, jtag, ebu a23, ebu a24, ebu a25,
+ ebu clk, ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy,
+ nand rd, spi, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6,
+ asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1,
+ clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio,
+ gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2
+
+ functions:
+ spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio, gphy
+
+AMAZON:
+ mux groups:
+ exin0, exin1, exin2, jtag, spi_di, spi_do, spi_clk, spi_cs1, spi_cs2,
+ spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc, stp, gpt1, gpt2, gpt3, clkout0,
+ clkout1, clkout2, mdio, dfe led0, dfe led1, ephy led0, ephy led1, ephy led2
+
+ functions:
+ spi, asc, cgu, jtag, exin, stp, gpt, mdio, ephy, dfe
+
+DANUBE:
+ mux groups:
+ exin0, exin1, exin2, jtag, ebu a23, ebu a24, ebu a25, ebu clk, ebu cs1,
+ ebu wait, nand ale, nand cs1, nand cle, spi_di, spi_do, spi_clk, spi_cs1,
+ spi_cs2, spi_cs3, spi_cs4, spi_cs5, spi_cs6, asc0, asc0 cts rts, stp, nmi,
+ gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1, gnt2, gnt3,
+ req1, req2, req3, dfe led0, dfe led1
functions:
- spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, mdio
+ spi, asc, cgu, jtag, exin, stp, gpt, nmi, pci, ebu, dfe
+xRX100:
+ mux groups:
+ exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk,
+ ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd,
+ spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5,
+ spi_cs6, asc0, asc0 cts rts, stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1,
+ clkout2, clkout3, gnt1, gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio,
+ dfe led0, dfe led1
+
+ functions:
+ spi, asc, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe
+
+xRX200:
+ mux groups:
+ exin0, exin1, exin2, exin3, exin4, ebu a23, ebu a24, ebu a25, ebu clk,
+ ebu cs1, ebu wait, nand ale, nand cs1, nand cle, nand rdy, nand rd,
+ spi_di, spi_do, spi_clk, spi_cs1, spi_cs2, spi_cs3, spi_cs4, spi_cs5,
+ spi_cs6, usif uart_rx, usif uart_tx, usif uart_rts, usif uart_cts,
+ usif uart_dtr, usif uart_dsr, usif uart_dcd, usif uart_ri, usif spi_di,
+ usif spi_do, usif spi_clk, usif spi_cs0, usif spi_cs1, usif spi_cs2,
+ stp, nmi, gpt1, gpt2, gpt3, clkout0, clkout1, clkout2, clkout3, gnt1,
+ gnt2, gnt3, gnt4, req1, req2, req3, req4, mdio, dfe led0, dfe led1,
+ gphy0 led0, gphy0 led1, gphy0 led2, gphy1 led0, gphy1 led1, gphy1 led2
+
+ functions:
+ spi, usif, cgu, exin, stp, gpt, nmi, pci, ebu, mdio, dfe, gphy
+
+xRX300:
+ mux groups:
+ exin0, exin1, exin2, exin4, nand ale, nand cs0, nand cs1, nand cle,
+ nand rdy, nand rd, nand_d0, nand_d1, nand_d2, nand_d3, nand_d4, nand_d5,
+ nand_d6, nand_d7, nand_d1, nand wr, nand wp, nand se, spi_di, spi_do,
+ spi_clk, spi_cs1, spi_cs4, spi_cs6, usif uart_rx, usif uart_tx,
+ usif spi_di, usif spi_do, usif spi_clk, usif spi_cs0, stp, clkout2,
+ mdio, dfe led0, dfe led1, ephy0 led0, ephy0 led1, ephy1 led0, ephy1 led1
+
+ functions:
+ spi, usif, cgu, exin, stp, ebu, mdio, dfe, ephy
Definition of pin configurations:
@@ -62,15 +139,32 @@ Optional subnode-properties:
0: none, 1: down, 2: up.
- lantiq,open-drain: Boolean, enables open-drain on the defined pin.
-Valid values for XWAY pin names:
+Valid values for XWAY pin names: (DEPRECATED: Use DANUBE)
Pinconf pins can be referenced via the names io0-io31.
-Valid values for XR9 pin names:
+Valid values for XR9 pin names: (DEPRECATED: Use xrX100/xRX200)
Pinconf pins can be referenced via the names io0-io55.
+Valid values for AMAZON pin names:
+ Pinconf pins can be referenced via the names io0-io31.
+
+Valid values for DANUBE pin names:
+ Pinconf pins can be referenced via the names io0-io31.
+
+Valid values for xRX100 pin names:
+ Pinconf pins can be referenced via the names io0-io55.
+
+Valid values for xRX200 pin names:
+ Pinconf pins can be referenced via the names io0-io49.
+
+Valid values for xRX300 pin names:
+ Pinconf pins can be referenced via the names io0-io1,io3-io6,io8-io11,
+ io13-io19,io23-io27,io34-io36,
+ io42-io43,io48-io61.
+
Example:
gpio: pinmux@E100B10 {
- compatible = "lantiq,pinctrl-xway";
+ compatible = "lantiq,danube-pinctrl";
pinctrl-names = "default";
pinctrl-0 = <&state_default>;
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
index 0480bc3..9ffb0b2 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-mt65xx.txt
@@ -4,10 +4,11 @@ The Mediatek's Pin controller is used to control SoC pins.
Required properties:
- compatible: value should be one of the following.
- (a) "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
- (b) "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
- (c) "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl.
- (d) "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
+ "mediatek,mt2701-pinctrl", compatible with mt2701 pinctrl.
+ "mediatek,mt6397-pinctrl", compatible with mt6397 pinctrl.
+ "mediatek,mt8127-pinctrl", compatible with mt8127 pinctrl.
+ "mediatek,mt8135-pinctrl", compatible with mt8135 pinctrl.
+ "mediatek,mt8173-pinctrl", compatible with mt8173 pinctrl.
- pins-are-numbered: Specify the subnodes are using numbered pinmux to
specify pins.
- gpio-controller : Marks the device node as a gpio controller.
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
new file mode 100644
index 0000000..e312a71
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,msm8996-pinctrl.txt
@@ -0,0 +1,199 @@
+Qualcomm MSM8996 TLMM block
+
+This binding describes the Top Level Mode Multiplexer block found in the
+MSM8996 platform.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be "qcom,msm8996-pinctrl"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: the base address and size of the TLMM register space.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: should specify the TLMM summary IRQ.
+
+- interrupt-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as an interrupt controller
+
+- #interrupt-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/interrupt-controller/irq.h>
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: identifies this node as a gpio controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: must be 2. Specifying the pin number and flags, as defined
+ in <dt-bindings/gpio/gpio.h>
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+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".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin, a group, or a list of pins or groups. This configuration can include the
+mux function to select on those pin(s)/group(s), and various pin configuration
+parameters, such as pull-up, drive strength, etc.
+
+
+PIN CONFIGURATION NODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode.
+
+ Valid pins are:
+ gpio0-gpio149
+ Supports mux, bias and drive-strength
+
+ sdc1_clk, sdc1_cmd, sdc1_data sdc2_clk, sdc2_cmd,
+ sdc2_data sdc1_rclk
+ Supports bias and drive-strength
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Functions are only valid for gpio pins.
+ Valid values are:
+
+ blsp_uart1, blsp_spi1, blsp_i2c1, blsp_uim1, atest_tsens,
+ bimc_dte1, dac_calib0, blsp_spi8, blsp_uart8, blsp_uim8,
+ qdss_cti_trig_out_b, bimc_dte0, dac_calib1, qdss_cti_trig_in_b,
+ dac_calib2, atest_tsens2, atest_usb1, blsp_spi10, blsp_uart10,
+ blsp_uim10, atest_bbrx1, atest_usb13, atest_bbrx0, atest_usb12,
+ mdp_vsync, edp_lcd, blsp_i2c10, atest_gpsadc1, atest_usb11,
+ atest_gpsadc0, edp_hot, atest_usb10, m_voc, dac_gpio, atest_char,
+ cam_mclk, pll_bypassnl, qdss_stm7, blsp_i2c8, qdss_tracedata_b,
+ pll_reset, qdss_stm6, qdss_stm5, qdss_stm4, atest_usb2, cci_i2c,
+ qdss_stm3, dac_calib3, atest_usb23, atest_char3, dac_calib4,
+ qdss_stm2, atest_usb22, atest_char2, qdss_stm1, dac_calib5,
+ atest_usb21, atest_char1, dbg_out, qdss_stm0, dac_calib6,
+ atest_usb20, atest_char0, dac_calib10, qdss_stm10,
+ qdss_cti_trig_in_a, cci_timer4, blsp_spi6, blsp_uart6, blsp_uim6,
+ blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11,
+ qdss_stm8, cci_timer0, qdss_stm13, dac_calib7, cci_timer1,
+ qdss_stm12, dac_calib8, cci_timer2, blsp1_spi, qdss_stm11,
+ dac_calib9, cci_timer3, cci_async, dac_calib12, blsp_i2c6,
+ qdss_tracectl_a, dac_calib13, qdss_traceclk_a, dac_calib14,
+ dac_calib15, hdmi_rcv, dac_calib16, hdmi_cec, pwr_modem,
+ dac_calib17, hdmi_ddc, pwr_nav, dac_calib18, pwr_crypto,
+ dac_calib19, hdmi_hot, dac_calib20, dac_calib21, pci_e0,
+ dac_calib22, dac_calib23, dac_calib24, tsif1_sync, dac_calib25,
+ sd_write, tsif1_error, blsp_spi2, blsp_uart2, blsp_uim2,
+ qdss_cti, blsp_i2c2, blsp_spi3, blsp_uart3, blsp_uim3, blsp_i2c3,
+ uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi, blsp_i2c9,
+ blsp_spi7, blsp_uart7, blsp_uim7, qdss_tracedata_a, blsp_i2c7,
+ qua_mi2s, gcc_gp1_clk_a, ssc_irq, uim4, blsp_spi11, blsp_uart11,
+ blsp_uim11, gcc_gp2_clk_a, gcc_gp3_clk_a, blsp_i2c11, cri_trng0,
+ cri_trng1, cri_trng, qdss_stm18, pri_mi2s, qdss_stm17, blsp_spi4,
+ blsp_uart4, blsp_uim4, qdss_stm16, qdss_stm15, blsp_i2c4,
+ qdss_stm14, dac_calib26, spkr_i2s, audio_ref, lpass_slimbus,
+ isense_dbg, tsense_pwm1, tsense_pwm2, btfm_slimbus, ter_mi2s,
+ qdss_stm22, qdss_stm21, qdss_stm20, qdss_stm19, gcc_gp1_clk_b,
+ sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b,
+ gcc_gp3_clk_b, blsp_i2c5, blsp_spi12, blsp_uart12, blsp_uim12,
+ qdss_stm25, qdss_stm31, blsp_i2c12, qdss_stm30, qdss_stm29,
+ tsif1_clk, qdss_stm28, tsif1_en, tsif1_data, sdc4_cmd, qdss_stm27,
+ qdss_traceclk_b, tsif2_error, sdc43, vfr_1, qdss_stm26, tsif2_clk,
+ sdc4_clk, qdss_stm24, tsif2_en, sdc42, qdss_stm23, qdss_tracectl_b,
+ sd_card, tsif2_data, sdc41, tsif2_sync, sdc40, mdp_vsync_p_b,
+ ldo_en, mdp_vsync_s_b, ldo_update, blsp11_uart_tx_b, blsp11_uart_rx_b,
+ blsp11_i2c_sda_b, prng_rosc, blsp11_i2c_scl_b, uim2, uim1, uim_batt,
+ pci_e2, pa_indicator, adsp_ext, ddr_bist, qdss_tracedata_11,
+ qdss_tracedata_12, modem_tsync, nav_dr, nav_pps, pci_e1, gsm_tx,
+ qspi_cs, ssbi2, ssbi1, mss_lte, qspi_clk, qspi0, qspi1, qspi2, qspi3,
+ gpio
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull down.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configued as pull up.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+ Not valid for sdc pins.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+ Not valid for sdc pins.
+
+- drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins, in mA.
+ Valid values are: 2, 4, 6, 8, 10, 12, 14 and 16
+
+Example:
+
+ tlmm: pinctrl@01010000 {
+ compatible = "qcom,msm8996-pinctrl";
+ reg = <0x01010000 0x300000>;
+ interrupts = <0 208 0>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ uart_console_active: uart_console_active {
+ mux {
+ pins = "gpio4", "gpio5";
+ function = "blsp_uart8";
+ };
+
+ config {
+ pins = "gpio4", "gpio5";
+ drive-strength = <2>;
+ bias-disable;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
index 1ae63c0..a90c812 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
@@ -14,6 +14,7 @@ PMIC's from Qualcomm.
"qcom,pm8917-gpio"
"qcom,pm8921-gpio"
"qcom,pm8941-gpio"
+ "qcom,pm8994-gpio"
"qcom,pma8084-gpio"
- reg:
@@ -79,6 +80,7 @@ to specify in a pin configuration subnode:
gpio1-gpio38 for pm8917
gpio1-gpio44 for pm8921
gpio1-gpio36 for pm8941
+ gpio1-gpio22 for pm8994
gpio1-gpio22 for pma8084
- function:
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
index d7803a2..d74e631 100644
--- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
@@ -15,6 +15,7 @@ of PMIC's from Qualcomm.
"qcom,pm8917-mpp",
"qcom,pm8921-mpp",
"qcom,pm8941-mpp",
+ "qcom,pm8994-mpp",
"qcom,pma8084-mpp",
- reg:
diff --git a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
index 391ef4b..0cd701b 100644
--- a/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/rockchip,pinctrl.txt
@@ -21,7 +21,8 @@ defined as gpio sub-nodes of the pinmux controller.
Required properties for iomux controller:
- compatible: one of "rockchip,rk2928-pinctrl", "rockchip,rk3066a-pinctrl"
"rockchip,rk3066b-pinctrl", "rockchip,rk3188-pinctrl"
- "rockchip,rk3288-pinctrl", "rockchip,rk3368-pinctrl"
+ "rockchip,rk3228-pinctrl", "rockchip,rk3288-pinctrl"
+ "rockchip,rk3368-pinctrl"
- rockchip,grf: phandle referencing a syscon providing the
"general register files"
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index 9d2a995..6db16b9 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -17,6 +17,7 @@ Required Properties:
- "samsung,exynos4x12-pinctrl": for Exynos4x12 compatible pin-controller.
- "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
- "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
+ - "samsung,exynos5410-pinctrl": for Exynos5410 compatible pin-controller.
- "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
- "samsung,exynos7-pinctrl": for Exynos7 compatible pin-controller.
diff --git a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt b/Documentation/devicetree/bindings/power/pd-samsung.txt
index e151057..4e94737 100644
--- a/Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+++ b/Documentation/devicetree/bindings/power/pd-samsung.txt
@@ -43,9 +43,8 @@ Example:
mfc_pd: power-domain@10044060 {
compatible = "samsung,exynos4210-pd";
reg = <0x10044060 0x20>;
- clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_SW_ACLK333>,
- <&clock CLK_MOUT_USER_ACLK333>;
- clock-names = "oscclk", "pclk0", "clk0";
+ clocks = <&clock CLK_FIN_PLL>, <&clock CLK_MOUT_USER_ACLK333>;
+ clock-names = "oscclk", "clk0";
#power-domain-cells = <0>;
};
diff --git a/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
new file mode 100644
index 0000000..d9254a6
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/brcm,bcm7038-pwm.txt
@@ -0,0 +1,20 @@
+Broadcom BCM7038 PWM controller (BCM7xxx Set Top Box PWM controller)
+
+Required properties:
+
+- compatible: must be "brcm,bcm7038-pwm"
+- reg: physical base address and length for this controller
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description
+ of the cells format
+- clocks: a phandle to the reference clock for this block which is fed through
+ its internal variable clock frequency generator
+
+
+Example:
+
+ pwm: pwm@f0408000 {
+ compatible = "brcm,bcm7038-pwm";
+ reg = <0xf0408000 0x28>;
+ #pwm-cells = <2>;
+ clocks = <&upg_fixed>;
+ };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-berlin.txt b/Documentation/devicetree/bindings/pwm/pwm-berlin.txt
new file mode 100644
index 0000000..82cbe16
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-berlin.txt
@@ -0,0 +1,17 @@
+Berlin PWM controller
+
+Required properties:
+- compatible: should be "marvell,berlin-pwm"
+- reg: physical base address and length of the controller's registers
+- clocks: phandle to the input clock
+- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
+ the cells format.
+
+Example:
+
+pwm: pwm@f7f20000 {
+ compatible = "marvell,berlin-pwm";
+ reg = <0xf7f20000 0x40>;
+ clocks = <&chip_clk CLKID_CFG>;
+ #pwm-cells = <3>;
+}
diff --git a/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
new file mode 100644
index 0000000..f8f59ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/pwm-mtk-disp.txt
@@ -0,0 +1,42 @@
+MediaTek display PWM controller
+
+Required properties:
+ - compatible: should be "mediatek,<name>-disp-pwm":
+ - "mediatek,mt8173-disp-pwm": found on mt8173 SoC.
+ - "mediatek,mt6595-disp-pwm": found on mt6595 SoC.
+ - reg: physical base address and length of the controller's registers.
+ - #pwm-cells: must be 2. See pwm.txt in this directory for a description of
+ the cell format.
+ - clocks: phandle and clock specifier of the PWM reference clock.
+ - clock-names: must contain the following:
+ - "main": clock used to generate PWM signals.
+ - "mm": sync signals from the modules of mmsys.
+ - pinctrl-names: Must contain a "default" entry.
+ - pinctrl-0: One property must exist for each entry in pinctrl-names.
+ See pinctrl/pinctrl-bindings.txt for details of the property values.
+
+Example:
+ pwm0: pwm@1401e000 {
+ compatible = "mediatek,mt8173-disp-pwm",
+ "mediatek,mt6595-disp-pwm";
+ reg = <0 0x1401e000 0 0x1000>;
+ #pwm-cells = <2>;
+ clocks = <&mmsys CLK_MM_DISP_PWM026M>,
+ <&mmsys CLK_MM_DISP_PWM0MM>;
+ clock-names = "main", "mm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&disp_pwm0_pins>;
+ };
+
+ backlight_lcd: backlight_lcd {
+ compatible = "pwm-backlight";
+ pwms = <&pwm0 0 1000000>;
+ brightness-levels = <
+ 0 16 32 48 64 80 96 112
+ 128 144 160 176 192 208 224 240
+ 255
+ >;
+ default-brightness-level = <9>;
+ power-supply = <&mt6397_vio18_reg>;
+ enable-gpios = <&pio 95 GPIO_ACTIVE_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
index ae0273e..cf6068b 100644
--- a/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
+++ b/Documentation/devicetree/bindings/pwm/pwm-sun4i.txt
@@ -3,6 +3,8 @@ Allwinner sun4i and sun7i SoC PWM controller
Required properties:
- compatible: should be one of:
- "allwinner,sun4i-a10-pwm"
+ - "allwinner,sun5i-a10s-pwm"
+ - "allwinner,sun5i-a13-pwm"
- "allwinner,sun7i-a20-pwm"
- reg: physical base address and length of the controller's registers
- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
diff --git a/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
new file mode 100644
index 0000000..0822a08
--- /dev/null
+++ b/Documentation/devicetree/bindings/pwm/renesas,pwm-rcar.txt
@@ -0,0 +1,26 @@
+* Renesas R-Car PWM Timer Controller
+
+Required Properties:
+- compatible: should be "renesas,pwm-rcar" and one of the following.
+ - "renesas,pwm-r8a7778": for R-Car M1A
+ - "renesas,pwm-r8a7779": for R-Car H1
+ - "renesas,pwm-r8a7790": for R-Car H2
+ - "renesas,pwm-r8a7791": for R-Car M2-W
+ - "renesas,pwm-r8a7794": for R-Car E2
+- reg: base address and length of the registers block for the PWM.
+- #pwm-cells: should be 2. See pwm.txt in this directory for a description of
+ the cells format.
+- clocks: clock phandle and specifier pair.
+- pinctrl-0: phandle, referring to a default pin configuration node.
+- pinctrl-names: Set to "default".
+
+Example: R8A7790 (R-Car H2) PWM Timer node
+
+ pwm0: pwm@e6e30000 {
+ compatible = "renesas,pwm-r8a7790", "renesas,pwm-rcar";
+ reg = <0 0xe6e30000 0 0x8>;
+ #pwm-cells = <2>;
+ clocks = <&mstp5_clks R8A7790_CLK_PWM>;
+ pinctrl-0 = <&pwm0_pins>;
+ pinctrl-names = "default";
+ };
diff --git a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
index c051114..a6c8afc 100644
--- a/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
+++ b/Documentation/devicetree/bindings/soc/mediatek/scpsys.txt
@@ -17,9 +17,9 @@ Required properties:
- reg: Address range of the SCPSYS unit
- infracfg: must contain a phandle to the infracfg controller
- clock, clock-names: clocks according to the common clock binding.
- The clocks needed "mm" and "mfg". These are the
- clocks which hardware needs to be enabled before
- enabling certain power domains.
+ The clocks needed "mm", "mfg", "venc" and "venc_lt".
+ These are the clocks which hardware needs to be enabled
+ before enabling certain power domains.
Example:
@@ -30,7 +30,9 @@ Example:
infracfg = <&infracfg>;
clocks = <&clk26m>,
<&topckgen CLK_TOP_MM_SEL>;
- clock-names = "mfg", "mm";
+ <&topckgen CLK_TOP_VENC_SEL>,
+ <&topckgen CLK_TOP_VENC_LT_SEL>;
+ clock-names = "mfg", "mm", "venc", "venc_lt";
};
Example consumer:
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt
new file mode 100644
index 0000000..9326cdf
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt
@@ -0,0 +1,57 @@
+Qualcomm Shared Memory Manager binding
+
+This binding describes the Qualcomm Shared Memory Manager, used to share data
+between various subsystems and OSes in Qualcomm platforms.
+
+- compatible:
+ Usage: required
+ Value type: <stringlist>
+ Definition: must be:
+ "qcom,smem"
+
+- memory-region:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: handle to memory reservation for main SMEM memory region.
+
+- qcom,rpm-msg-ram:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: handle to RPM message memory resource
+
+- hwlocks:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: reference to a hwspinlock used to protect allocations from
+ the shared memory
+
+= EXAMPLE
+The following example shows the SMEM setup for MSM8974, with a main SMEM region
+at 0xfa00000 and the RPM message ram at 0xfc428000:
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ smem_region: smem@fa00000 {
+ reg = <0xfa00000 0x200000>;
+ no-map;
+ };
+ };
+
+ smem@fa00000 {
+ compatible = "qcom,smem";
+
+ memory-region = <&smem_region>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
+ soc {
+ rpm_msg_ram: memory@fc428000 {
+ compatible = "qcom,rpm-msg-ram";
+ reg = <0xfc428000 0x4000>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt
new file mode 100644
index 0000000..112756e
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt
@@ -0,0 +1,46 @@
+* Rockchip Power Domains
+
+Rockchip processors include support for multiple power domains which can be
+powered up/down by software based on different application scenes to save power.
+
+Required properties for power domain controller:
+- compatible: Should be one of the following.
+ "rockchip,rk3288-power-controller" - for RK3288 SoCs.
+- #power-domain-cells: Number of cells in a power-domain specifier.
+ Should be 1 for multiple PM domains.
+- #address-cells: Should be 1.
+- #size-cells: Should be 0.
+
+Required properties for power domain sub nodes:
+- reg: index of the power domain, should use macros in:
+ "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
+- clocks (optional): phandles to clocks which need to be enabled while power domain
+ switches state.
+
+Example:
+
+ power: power-controller {
+ compatible = "rockchip,rk3288-power-controller";
+ #power-domain-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ pd_gpu {
+ reg = <RK3288_PD_GPU>;
+ clocks = <&cru ACLK_GPU>;
+ };
+ };
+
+Node of a device using power domains must have a power-domains property,
+containing a phandle to the power device node and an index specifying which
+power domain to use.
+The index should use macros in:
+ "include/dt-bindings/power/rk3288-power.h" - for rk3288 type power domain.
+
+Example of the node using power domain:
+
+ node {
+ /* ... */
+ power-domains = <&power RK3288_PD_GPU>;
+ /* ... */
+ };
diff --git a/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt b/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
index d8e8cdb..d1ce21a 100644
--- a/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
+++ b/Documentation/devicetree/bindings/soc/ti/keystone-navigator-qmss.txt
@@ -221,7 +221,6 @@ qmss: qmss@2a40000 {
#size-cells = <1>;
ranges;
pdsp0@0x2a10000 {
- firmware = "keystone/qmss_pdsp_acc48_k2_le_1_0_0_8.fw";
reg = <0x2a10000 0x1000>,
<0x2a0f000 0x100>,
<0x2a0c000 0x3c8>,
diff --git a/Documentation/devicetree/bindings/sound/ak4554.c b/Documentation/devicetree/bindings/sound/ak4554.txt
index 934fa02..934fa02 100644
--- a/Documentation/devicetree/bindings/sound/ak4554.c
+++ b/Documentation/devicetree/bindings/sound/ak4554.txt
diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
index ef802de..0dfa60d 100644
--- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt
@@ -1,7 +1,9 @@
* Temperature Sensor ADC (TSADC) on rockchip SoCs
Required properties:
-- compatible : "rockchip,rk3288-tsadc"
+- compatible : should be "rockchip,<name>-tsadc"
+ "rockchip,rk3288-tsadc": found on RK3288 SoCs
+ "rockchip,rk3368-tsadc": found on RK3368 SoCs
- reg : physical base address of the controller and length of memory mapped
region.
- interrupts : The interrupt number to the cpu. The interrupt specifier format
@@ -12,6 +14,11 @@ Required properties:
- resets : Must contain an entry for each entry in reset-names.
See ../reset/reset.txt for details.
- reset-names : Must include the name "tsadc-apb".
+- pinctrl-names : The pin control state names;
+- pinctrl-0 : The "init" pinctrl state, it will be set before device probe.
+- pinctrl-1 : The "default" pinctrl state, it will be set after reset the
+ TSADC controller.
+- pinctrl-2 : The "sleep" pinctrl state, it will be in for suspend.
- #thermal-sensor-cells : Should be 1. See ./thermal.txt for a description.
- rockchip,hw-tshut-temp : The hardware-controlled shutdown temperature value.
- rockchip,hw-tshut-mode : The hardware-controlled shutdown mode 0:CRU 1:GPIO.
@@ -27,8 +34,10 @@ tsadc: tsadc@ff280000 {
clock-names = "tsadc", "apb_pclk";
resets = <&cru SRST_TSADC>;
reset-names = "tsadc-apb";
- pinctrl-names = "default";
- pinctrl-0 = <&otp_out>;
+ pinctrl-names = "init", "default", "sleep";
+ pinctrl-0 = <&otp_gpio>;
+ pinctrl-1 = <&otp_out>;
+ pinctrl-2 = <&otp_gpio>;
#thermal-sensor-cells = <1>;
rockchip,hw-tshut-temp = <95000>;
rockchip,hw-tshut-mode = <0>;
diff --git a/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
index 0c9222d..6299dd8 100644
--- a/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/ti_soc_thermal.txt
@@ -10,6 +10,8 @@ to the silicon temperature.
Required properties:
- compatible : Should be:
+ - "ti,omap34xx-bandgap" : for OMAP34xx bandgap
+ - "ti,omap36xx-bandgap" : for OMAP36xx bandgap
- "ti,omap4430-bandgap" : for OMAP4430 bandgap
- "ti,omap4460-bandgap" : for OMAP4460 bandgap
- "ti,omap4470-bandgap" : for OMAP4470 bandgap
@@ -25,6 +27,18 @@ to each bandgap version, because the mapping may change from
soc to soc, apart of depending on available features.
Example:
+OMAP34xx:
+bandgap {
+ reg = <0x48002524 0x4>;
+ compatible = "ti,omap34xx-bandgap";
+};
+
+OMAP36xx:
+bandgap {
+ reg = <0x48002524 0x4>;
+ compatible = "ti,omap36xx-bandgap";
+};
+
OMAP4430:
bandgap {
reg = <0x4a002260 0x4 0x4a00232C 0x4>;
diff --git a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
index 53a3029..64083bc 100644
--- a/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
+++ b/Documentation/devicetree/bindings/timer/mediatek,mtk-timer.txt
@@ -3,10 +3,12 @@ Mediatek MT6577, MT6572 and MT6589 Timers
Required properties:
- compatible should contain:
- * "mediatek,mt6589-timer" for MT6589 compatible timers
* "mediatek,mt6580-timer" for MT6580 compatible timers
- * "mediatek,mt6577-timer" for all compatible timers (MT6589, MT6580,
- MT6577)
+ * "mediatek,mt6589-timer" for MT6589 compatible timers
+ * "mediatek,mt8127-timer" for MT8127 compatible timers
+ * "mediatek,mt8135-timer" for MT8135 compatible timers
+ * "mediatek,mt8173-timer" for MT8173 compatible timers
+ * "mediatek,mt6577-timer" for MT6577 and all above compatible timers
- reg: Should contain location and length for timers register.
- clocks: Clocks driving the timer hardware. This list should include two
clocks. The order is system clock and as second clock the RTC clock.
diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
new file mode 100644
index 0000000..070baf4
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
@@ -0,0 +1,58 @@
+* Qualcomm Technologies Inc Universal Flash Storage (UFS) PHY
+
+UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro.
+Each UFS PHY node should have its own node.
+
+To bind UFS PHY with UFS host controller, the controller node should
+contain a phandle reference to UFS PHY node.
+
+Required properties:
+- compatible : compatible list, contains "qcom,ufs-phy-qmp-20nm"
+ or "qcom,ufs-phy-qmp-14nm" according to the relevant phy in use.
+- reg : should contain PHY register address space (mandatory),
+- reg-names : indicates various resources passed to driver (via reg proptery) by name.
+ Required "reg-names" is "phy_mem".
+- #phy-cells : This property shall be set to 0
+- vdda-phy-supply : phandle to main PHY supply for analog domain
+- vdda-pll-supply : phandle to PHY PLL and Power-Gen block power supply
+- clocks : List of phandle and clock specifier pairs
+- clock-names : List of clock input name strings sorted in the same
+ order as the clocks property. "ref_clk_src", "ref_clk",
+ "tx_iface_clk" & "rx_iface_clk" are mandatory but
+ "ref_clk_parent" is optional
+
+Optional properties:
+- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply
+- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
+- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply
+- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
+- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
+
+Example:
+
+ ufsphy1: ufsphy@0xfc597000 {
+ compatible = "qcom,ufs-phy-qmp-20nm";
+ reg = <0xfc597000 0x800>;
+ reg-names = "phy_mem";
+ #phy-cells = <0>;
+ vdda-phy-supply = <&pma8084_l4>;
+ vdda-pll-supply = <&pma8084_l12>;
+ vdda-phy-max-microamp = <50000>;
+ vdda-pll-max-microamp = <1000>;
+ clock-names = "ref_clk_src",
+ "ref_clk_parent",
+ "ref_clk",
+ "tx_iface_clk",
+ "rx_iface_clk";
+ clocks = <&clock_rpm clk_ln_bb_clk>,
+ <&clock_gcc clk_pcie_1_phy_ldo >,
+ <&clock_gcc clk_ufs_phy_ldo>,
+ <&clock_gcc clk_gcc_ufs_tx_cfg_clk>,
+ <&clock_gcc clk_gcc_ufs_rx_cfg_clk>;
+ };
+
+ ufshc@0xfc598000 {
+ ...
+ phys = <&ufsphy1>;
+ phy-names = "ufsphy";
+ };
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 5357919..03c0e98 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -4,11 +4,18 @@ UFSHC nodes are defined to describe on-chip UFS host controllers.
Each UFS controller instance should have its own node.
Required properties:
-- compatible : compatible list, contains "jedec,ufs-1.1"
+- compatible : must contain "jedec,ufs-1.1", may also list one or more
+ of the following:
+ "qcom,msm8994-ufshc"
+ "qcom,msm8996-ufshc"
+ "qcom,ufshc"
- interrupts : <interrupt mapping for UFS host controller IRQ>
- reg : <registers mapping>
Optional properties:
+- phys : phandle to UFS PHY node
+- phy-names : the string "ufsphy" when is found in a node, along
+ with "phys" attribute, provides phandle to UFS PHY node
- vdd-hba-supply : phandle to UFS host controller supply regulator node
- vcc-supply : phandle to VCC supply regulator node
- vccq-supply : phandle to VCCQ supply regulator node
@@ -54,4 +61,6 @@ Example:
clocks = <&core 0>, <&ref 0>, <&iface 0>;
clock-names = "core_clk", "ref_clk", "iface_clk";
freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
+ phys = <&ufsphy1>;
+ phy-names = "ufsphy";
};
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 9ff48e0..fb2ad0a 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -1,6 +1,7 @@
synopsys DWC3 CORE
-DWC3- USB3 CONTROLLER
+DWC3- USB3 CONTROLLER. Complies to the generic USB binding properties
+ as described in 'usb/generic.txt'
Required properties:
- compatible: must be "snps,dwc3"
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 8c6cef7..55df1d4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -34,6 +34,7 @@ avago Avago Technologies
avic Shanghai AVIC Optoelectronics Co., Ltd.
axis Axis Communications AB
bosch Bosch Sensortec GmbH
+boundary Boundary Devices Inc.
brcm Broadcom Corporation
buffalo Buffalo, Inc.
calxeda Calxeda
@@ -171,6 +172,7 @@ pericom Pericom Technology Inc.
phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
plathome Plat'Home Co., Ltd.
+plda PLDA
pixcir PIXCIR MICROELECTRONICS Co., Ltd
pulsedlight PulsedLight, Inc
powervr PowerVR (deprecated, use img)
@@ -228,6 +230,7 @@ toradex Toradex AG
toshiba Toshiba Corporation
toumaz Toumaz
tplink TP-LINK Technologies Co., Ltd.
+tronfy Tronfy
truly Truly Semiconductors Limited
upisemi uPI Semiconductor Corp.
usi Universal Scientific Industrial Co., Ltd.
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index 9de9813..8ea834f 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -165,7 +165,6 @@ mach-types.h
machtypes.h
map
map_hugetlb
-media
mconf
miboot*
mk_elfconfig
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
index 8eb9226..669dc6c 100644
--- a/Documentation/dvb/README.dvb-usb
+++ b/Documentation/dvb/README.dvb-usb
@@ -45,7 +45,7 @@ Supported devices
See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
cards/drivers/firmwares:
-http://www.linuxtv.org/wiki/index.php/DVB_USB
+https://linuxtv.org/wiki/index.php/DVB_USB
0. History & News:
2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
@@ -121,7 +121,7 @@ working.
Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
you need for your device:
-http://www.linuxtv.org/wiki/index.php/DVB_USB
+https://linuxtv.org/wiki/index.php/DVB_USB
1.2. Compiling
diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt
index 97b1373..a0be920 100644
--- a/Documentation/dvb/faq.txt
+++ b/Documentation/dvb/faq.txt
@@ -76,7 +76,7 @@ Some very frequently asked questions about linuxtv-dvb
the TuxBox CVS many interesting DVB applications and the dBox2
DVB source
- http://www.linuxtv.org/downloads/
+ https://linuxtv.org/downloads
DVB Swiss Army Knife library and utilities
http://www.nenie.org/misc/mpsys/
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 91b43d2..1a0a041 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -152,7 +152,7 @@ sub tda10046lifeview {
sub av7110 {
my $sourcefile = "dvb-ttpci-01.fw-261d";
- my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
+ my $url = "https://linuxtv.org/downloads/firmware/$sourcefile";
my $hash = "603431b6259715a8e88f376a53b64e2f";
my $outfile = "dvb-ttpci-01.fw";
@@ -303,7 +303,7 @@ sub vp7049 {
}
sub dibusb {
- my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
+ my $url = "https://linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
my $outfile = "dvb-dibusb-5.0.0.11.fw";
my $hash = "fa490295a527360ca16dcdf3224ca243";
@@ -351,7 +351,7 @@ sub nxt2004 {
sub or51211 {
my $fwfile = "dvb-fe-or51211.fw";
- my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
my $hash = "d830949c771a289505bf9eafc225d491";
checkstandard();
@@ -364,7 +364,7 @@ sub or51211 {
sub cx231xx {
my $fwfile = "v4l-cx231xx-avcore-01.fw";
- my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
my $hash = "7d3bb956dc9df0eafded2b56ba57cc42";
checkstandard();
@@ -376,7 +376,7 @@ sub cx231xx {
}
sub cx18 {
- my $url = "http://linuxtv.org/downloads/firmware/";
+ my $url = "https://linuxtv.org/downloads/firmware/";
my %files = (
'v4l-cx23418-apu.fw' => '588f081b562f5c653a3db1ad8f65939a',
@@ -450,7 +450,7 @@ sub mpc718 {
}
sub cx23885 {
- my $url = "http://linuxtv.org/downloads/firmware/";
+ my $url = "https://linuxtv.org/downloads/firmware/";
my %files = (
'v4l-cx23885-avcore-01.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
@@ -472,7 +472,7 @@ sub cx23885 {
}
sub pvrusb2 {
- my $url = "http://linuxtv.org/downloads/firmware/";
+ my $url = "https://linuxtv.org/downloads/firmware/";
my %files = (
'v4l-cx25840.fw' => 'dadb79e9904fc8af96e8111d9cb59320',
@@ -494,7 +494,7 @@ sub pvrusb2 {
sub or51132_qam {
my $fwfile = "dvb-fe-or51132-qam.fw";
- my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
my $hash = "7702e8938612de46ccadfe9b413cb3b5";
checkstandard();
@@ -507,7 +507,7 @@ sub or51132_qam {
sub or51132_vsb {
my $fwfile = "dvb-fe-or51132-vsb.fw";
- my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
+ my $url = "https://linuxtv.org/downloads/firmware/$fwfile";
my $hash = "c16208e02f36fc439a557ad4c613364a";
checkstandard();
@@ -519,7 +519,7 @@ sub or51132_vsb {
}
sub bluebird {
- my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
+ my $url = "https://linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
my $outfile = "dvb-usb-bluebird-01.fw";
my $hash = "658397cb9eba9101af9031302671f49d";
@@ -677,7 +677,7 @@ sub drxk_hauppauge_hvr930c {
}
sub drxk_terratec_h5 {
- my $url = "http://www.linuxtv.org/downloads/firmware/";
+ my $url = "https://linuxtv.org/downloads/firmware/";
my $hash = "19000dada8e2741162ccc50cc91fa7f1";
my $fwfile = "dvb-usb-terratec-h5-drxk.fw";
diff --git a/Documentation/dvb/readme.txt b/Documentation/dvb/readme.txt
index 0b0380c..8996504 100644
--- a/Documentation/dvb/readme.txt
+++ b/Documentation/dvb/readme.txt
@@ -2,12 +2,12 @@ Linux Digital Video Broadcast (DVB) subsystem
=============================================
The main development site and CVS repository for these
-drivers is http://linuxtv.org/.
+drivers is https://linuxtv.org.
The developer mailing list linux-dvb is also hosted there,
-see http://linuxtv.org/lists.php. Please check
-the archive http://linuxtv.org/pipermail/linux-dvb/
-and the Wiki http://linuxtv.org/wiki/
+see https://linuxtv.org/lists.php. Please check
+the archive https://linuxtv.org/pipermail/linux-dvb/
+and the Wiki https://linuxtv.org/wiki/
before asking newbie questions on the list.
API documentation, utilities and test/example programs
@@ -16,7 +16,7 @@ are available as part of the old driver package for Linux 2.4
We plan to split this into separate packages, but it's not
been done yet.
-http://linuxtv.org/downloads/
+https://linuxtv.org/downloads/
What's inside this directory:
diff --git a/Documentation/edac.txt b/Documentation/edac.txt
index 80841a2..f89cfd8 100644
--- a/Documentation/edac.txt
+++ b/Documentation/edac.txt
@@ -1,9 +1,13 @@
EDAC - Error Detection And Correction
=====================================
-"bluesmoke" was the name for this device driver when it was "out-of-tree"
-and maintained at sourceforge.net. When it was pushed into 2.6.16 for the
-first time, it was renamed to 'EDAC'.
+"bluesmoke" was the name for this device driver when it
+was "out-of-tree" and maintained at sourceforge.net -
+bluesmoke.sourceforge.net. That site is mostly archaic now and can be
+used only for historical purposes.
+
+When the subsystem was pushed into 2.6.16 for the first time, it was
+renamed to 'EDAC'.
PURPOSE
-------
diff --git a/Documentation/email-clients.txt b/Documentation/email-clients.txt
index aba85b3..2d485de 100644
--- a/Documentation/email-clients.txt
+++ b/Documentation/email-clients.txt
@@ -176,11 +176,47 @@ To use 'vim' with mutt:
if you want to include the patch inline.
(a)ttach works fine without "set paste".
+You can also generate patches with 'git format-patch' and then use Mutt
+to send them:
+ $ mutt -H 0001-some-bug-fix.patch
+
Config options:
It should work with default settings.
However, it's a good idea to set the "send_charset" to:
set send_charset="us-ascii:utf-8"
+Mutt is highly customizable. Here is a minimum configuration to start
+using Mutt to send patches through Gmail:
+
+# .muttrc
+# ================ IMAP ====================
+set imap_user = 'yourusername@gmail.com'
+set imap_pass = 'yourpassword'
+set spoolfile = imaps://imap.gmail.com/INBOX
+set folder = imaps://imap.gmail.com/
+set record="imaps://imap.gmail.com/[Gmail]/Sent Mail"
+set postponed="imaps://imap.gmail.com/[Gmail]/Drafts"
+set mbox="imaps://imap.gmail.com/[Gmail]/All Mail"
+
+# ================ SMTP ====================
+set smtp_url = "smtp://username@smtp.gmail.com:587/"
+set smtp_pass = $imap_pass
+set ssl_force_tls = yes # Require encrypted connection
+
+# ================ Composition ====================
+set editor = `echo \$EDITOR`
+set edit_headers = yes # See the headers when editing
+set charset = UTF-8 # value of $LANG; also fallback for send_charset
+# Sender, email address, and sign-off line must match
+unset use_domain # because joe@localhost is just embarrassing
+set realname = "YOUR NAME"
+set from = "username@gmail.com"
+set use_from = yes
+
+The Mutt docs have lots more information:
+ http://dev.mutt.org/trac/wiki/UseCases/Gmail
+ http://dev.mutt.org/doc/manual.html
+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Pine (TUI)
diff --git a/Documentation/features/seccomp/seccomp-filter/arch-support.txt b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
index 76d39d6..4f66ec1 100644
--- a/Documentation/features/seccomp/seccomp-filter/arch-support.txt
+++ b/Documentation/features/seccomp/seccomp-filter/arch-support.txt
@@ -33,7 +33,7 @@
| sh: | TODO |
| sparc: | TODO |
| tile: | ok |
- | um: | TODO |
+ | um: | ok |
| unicore32: | TODO |
| x86: | ok |
| xtensa: | TODO |
diff --git a/Documentation/features/time/irq-time-acct/arch-support.txt b/Documentation/features/time/irq-time-acct/arch-support.txt
index e633162..4199ffec 100644
--- a/Documentation/features/time/irq-time-acct/arch-support.txt
+++ b/Documentation/features/time/irq-time-acct/arch-support.txt
@@ -9,7 +9,7 @@
| alpha: | .. |
| arc: | TODO |
| arm: | ok |
- | arm64: | .. |
+ | arm64: | ok |
| avr32: | TODO |
| blackfin: | TODO |
| c6x: | TODO |
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 06d4434..619af9b 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -50,8 +50,7 @@ prototypes:
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
- const char *(*follow_link) (struct dentry *, void **);
- void (*put_link) (struct inode *, void *);
+ const char *(*get_link) (struct dentry *, struct inode *, void **);
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
int (*get_acl)(struct inode *, int);
@@ -83,8 +82,7 @@ rmdir: yes (both) (see below)
rename: yes (all) (see below)
rename2: yes (all) (see below)
readlink: no
-follow_link: no
-put_link: no
+get_link: no
setattr: yes
permission: no (may not block if called in rcu-walk mode)
get_acl: no
diff --git a/Documentation/filesystems/Makefile b/Documentation/filesystems/Makefile
index 13483d1..883010c 100644
--- a/Documentation/filesystems/Makefile
+++ b/Documentation/filesystems/Makefile
@@ -1,5 +1,3 @@
-subdir-y := configfs
-
# List of programs to build
hostprogs-y := dnotify_test
diff --git a/Documentation/filesystems/configfs/Makefile b/Documentation/filesystems/configfs/Makefile
deleted file mode 100644
index be7ec5e..0000000
--- a/Documentation/filesystems/configfs/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-ifneq ($(CONFIG_CONFIGFS_FS),)
-obj-m += configfs_example_explicit.o configfs_example_macros.o
-endif
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index b40fec9..af68efd 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -160,12 +160,6 @@ among other things. For that, it needs a type.
struct configfs_item_operations {
void (*release)(struct config_item *);
- ssize_t (*show_attribute)(struct config_item *,
- struct configfs_attribute *,
- char *);
- ssize_t (*store_attribute)(struct config_item *,
- struct configfs_attribute *,
- const char *, size_t);
int (*allow_link)(struct config_item *src,
struct config_item *target);
int (*drop_link)(struct config_item *src,
@@ -183,9 +177,7 @@ The most basic function of a config_item_type is to define what
operations can be performed on a config_item. All items that have been
allocated dynamically will need to provide the ct_item_ops->release()
method. This method is called when the config_item's reference count
-reaches zero. Items that wish to display an attribute need to provide
-the ct_item_ops->show_attribute() method. Similarly, storing a new
-attribute value uses the store_attribute() method.
+reaches zero.
[struct configfs_attribute]
@@ -193,6 +185,8 @@ attribute value uses the store_attribute() method.
char *ca_name;
struct module *ca_owner;
umode_t ca_mode;
+ ssize_t (*show)(struct config_item *, char *);
+ ssize_t (*store)(struct config_item *, const char *, size_t);
};
When a config_item wants an attribute to appear as a file in the item's
@@ -202,10 +196,10 @@ config_item_type->ct_attrs. When the item appears in configfs, the
attribute file will appear with the configfs_attribute->ca_name
filename. configfs_attribute->ca_mode specifies the file permissions.
-If an attribute is readable and the config_item provides a
-ct_item_ops->show_attribute() method, that method will be called
-whenever userspace asks for a read(2) on the attribute. The converse
-will happen for write(2).
+If an attribute is readable and provides a ->show method, that method will
+be called whenever userspace asks for a read(2) on the attribute. If an
+attribute is writable and provides a ->store method, that method will be
+be called whenever userspace asks for a write(2) on the attribute.
[struct config_group]
@@ -311,20 +305,10 @@ the subsystem must be ready for it.
[An Example]
The best example of these basic concepts is the simple_children
-subsystem/group and the simple_child item in configfs_example_explicit.c
-and configfs_example_macros.c. It shows a trivial object displaying and
-storing an attribute, and a simple group creating and destroying these
-children.
-
-The only difference between configfs_example_explicit.c and
-configfs_example_macros.c is how the attributes of the childless item
-are defined. The childless item has extended attributes, each with
-their own show()/store() operation. This follows a convention commonly
-used in sysfs. configfs_example_explicit.c creates these attributes
-by explicitly defining the structures involved. Conversely
-configfs_example_macros.c uses some convenience macros from configfs.h
-to define the attributes. These macros are similar to their sysfs
-counterparts.
+subsystem/group and the simple_child item in
+samples/configfs/configfs_sample.c. It shows a trivial object displaying
+and storing an attribute, and a simple group creating and destroying
+these children.
[Hierarchy Navigation and the Subsystem Mutex]
diff --git a/Documentation/filesystems/configfs/configfs_example_explicit.c b/Documentation/filesystems/configfs/configfs_example_explicit.c
deleted file mode 100644
index 1420233..0000000
--- a/Documentation/filesystems/configfs/configfs_example_explicit.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * vim: noexpandtab ts=8 sts=0 sw=8:
- *
- * configfs_example_explicit.c - This file is a demonstration module
- * containing a number of configfs subsystems. It explicitly defines
- * each structure without using the helper macros defined in
- * configfs.h.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- * Based on sysfs:
- * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
- *
- * configfs Copyright (C) 2005 Oracle. All rights reserved.
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-
-#include <linux/configfs.h>
-
-
-
-/*
- * 01-childless
- *
- * This first example is a childless subsystem. It cannot create
- * any config_items. It just has attributes.
- *
- * Note that we are enclosing the configfs_subsystem inside a container.
- * This is not necessary if a subsystem has no attributes directly
- * on the subsystem. See the next example, 02-simple-children, for
- * such a subsystem.
- */
-
-struct childless {
- struct configfs_subsystem subsys;
- int showme;
- int storeme;
-};
-
-struct childless_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct childless *, char *);
- ssize_t (*store)(struct childless *, const char *, size_t);
-};
-
-static inline struct childless *to_childless(struct config_item *item)
-{
- return item ? container_of(to_configfs_subsystem(to_config_group(item)), struct childless, subsys) : NULL;
-}
-
-static ssize_t childless_showme_read(struct childless *childless,
- char *page)
-{
- ssize_t pos;
-
- pos = sprintf(page, "%d\n", childless->showme);
- childless->showme++;
-
- return pos;
-}
-
-static ssize_t childless_storeme_read(struct childless *childless,
- char *page)
-{
- return sprintf(page, "%d\n", childless->storeme);
-}
-
-static ssize_t childless_storeme_write(struct childless *childless,
- const char *page,
- size_t count)
-{
- unsigned long tmp;
- char *p = (char *) page;
-
- tmp = simple_strtoul(p, &p, 10);
- if ((*p != '\0') && (*p != '\n'))
- return -EINVAL;
-
- if (tmp > INT_MAX)
- return -ERANGE;
-
- childless->storeme = tmp;
-
- return count;
-}
-
-static ssize_t childless_description_read(struct childless *childless,
- char *page)
-{
- return sprintf(page,
-"[01-childless]\n"
-"\n"
-"The childless subsystem is the simplest possible subsystem in\n"
-"configfs. It does not support the creation of child config_items.\n"
-"It only has a few attributes. In fact, it isn't much different\n"
-"than a directory in /proc.\n");
-}
-
-static struct childless_attribute childless_attr_showme = {
- .attr = { .ca_owner = THIS_MODULE, .ca_name = "showme", .ca_mode = S_IRUGO },
- .show = childless_showme_read,
-};
-static struct childless_attribute childless_attr_storeme = {
- .attr = { .ca_owner = THIS_MODULE, .ca_name = "storeme", .ca_mode = S_IRUGO | S_IWUSR },
- .show = childless_storeme_read,
- .store = childless_storeme_write,
-};
-static struct childless_attribute childless_attr_description = {
- .attr = { .ca_owner = THIS_MODULE, .ca_name = "description", .ca_mode = S_IRUGO },
- .show = childless_description_read,
-};
-
-static struct configfs_attribute *childless_attrs[] = {
- &childless_attr_showme.attr,
- &childless_attr_storeme.attr,
- &childless_attr_description.attr,
- NULL,
-};
-
-static ssize_t childless_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct childless *childless = to_childless(item);
- struct childless_attribute *childless_attr =
- container_of(attr, struct childless_attribute, attr);
- ssize_t ret = 0;
-
- if (childless_attr->show)
- ret = childless_attr->show(childless, page);
- return ret;
-}
-
-static ssize_t childless_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct childless *childless = to_childless(item);
- struct childless_attribute *childless_attr =
- container_of(attr, struct childless_attribute, attr);
- ssize_t ret = -EINVAL;
-
- if (childless_attr->store)
- ret = childless_attr->store(childless, page, count);
- return ret;
-}
-
-static struct configfs_item_operations childless_item_ops = {
- .show_attribute = childless_attr_show,
- .store_attribute = childless_attr_store,
-};
-
-static struct config_item_type childless_type = {
- .ct_item_ops = &childless_item_ops,
- .ct_attrs = childless_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-static struct childless childless_subsys = {
- .subsys = {
- .su_group = {
- .cg_item = {
- .ci_namebuf = "01-childless",
- .ci_type = &childless_type,
- },
- },
- },
-};
-
-
-/* ----------------------------------------------------------------- */
-
-/*
- * 02-simple-children
- *
- * This example merely has a simple one-attribute child. Note that
- * there is no extra attribute structure, as the child's attribute is
- * known from the get-go. Also, there is no container for the
- * subsystem, as it has no attributes of its own.
- */
-
-struct simple_child {
- struct config_item item;
- int storeme;
-};
-
-static inline struct simple_child *to_simple_child(struct config_item *item)
-{
- return item ? container_of(item, struct simple_child, item) : NULL;
-}
-
-static struct configfs_attribute simple_child_attr_storeme = {
- .ca_owner = THIS_MODULE,
- .ca_name = "storeme",
- .ca_mode = S_IRUGO | S_IWUSR,
-};
-
-static struct configfs_attribute *simple_child_attrs[] = {
- &simple_child_attr_storeme,
- NULL,
-};
-
-static ssize_t simple_child_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- ssize_t count;
- struct simple_child *simple_child = to_simple_child(item);
-
- count = sprintf(page, "%d\n", simple_child->storeme);
-
- return count;
-}
-
-static ssize_t simple_child_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct simple_child *simple_child = to_simple_child(item);
- unsigned long tmp;
- char *p = (char *) page;
-
- tmp = simple_strtoul(p, &p, 10);
- if (!p || (*p && (*p != '\n')))
- return -EINVAL;
-
- if (tmp > INT_MAX)
- return -ERANGE;
-
- simple_child->storeme = tmp;
-
- return count;
-}
-
-static void simple_child_release(struct config_item *item)
-{
- kfree(to_simple_child(item));
-}
-
-static struct configfs_item_operations simple_child_item_ops = {
- .release = simple_child_release,
- .show_attribute = simple_child_attr_show,
- .store_attribute = simple_child_attr_store,
-};
-
-static struct config_item_type simple_child_type = {
- .ct_item_ops = &simple_child_item_ops,
- .ct_attrs = simple_child_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-
-struct simple_children {
- struct config_group group;
-};
-
-static inline struct simple_children *to_simple_children(struct config_item *item)
-{
- return item ? container_of(to_config_group(item), struct simple_children, group) : NULL;
-}
-
-static struct config_item *simple_children_make_item(struct config_group *group, const char *name)
-{
- struct simple_child *simple_child;
-
- simple_child = kzalloc(sizeof(struct simple_child), GFP_KERNEL);
- if (!simple_child)
- return ERR_PTR(-ENOMEM);
-
- config_item_init_type_name(&simple_child->item, name,
- &simple_child_type);
-
- simple_child->storeme = 0;
-
- return &simple_child->item;
-}
-
-static struct configfs_attribute simple_children_attr_description = {
- .ca_owner = THIS_MODULE,
- .ca_name = "description",
- .ca_mode = S_IRUGO,
-};
-
-static struct configfs_attribute *simple_children_attrs[] = {
- &simple_children_attr_description,
- NULL,
-};
-
-static ssize_t simple_children_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- return sprintf(page,
-"[02-simple-children]\n"
-"\n"
-"This subsystem allows the creation of child config_items. These\n"
-"items have only one attribute that is readable and writeable.\n");
-}
-
-static void simple_children_release(struct config_item *item)
-{
- kfree(to_simple_children(item));
-}
-
-static struct configfs_item_operations simple_children_item_ops = {
- .release = simple_children_release,
- .show_attribute = simple_children_attr_show,
-};
-
-/*
- * Note that, since no extra work is required on ->drop_item(),
- * no ->drop_item() is provided.
- */
-static struct configfs_group_operations simple_children_group_ops = {
- .make_item = simple_children_make_item,
-};
-
-static struct config_item_type simple_children_type = {
- .ct_item_ops = &simple_children_item_ops,
- .ct_group_ops = &simple_children_group_ops,
- .ct_attrs = simple_children_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-static struct configfs_subsystem simple_children_subsys = {
- .su_group = {
- .cg_item = {
- .ci_namebuf = "02-simple-children",
- .ci_type = &simple_children_type,
- },
- },
-};
-
-
-/* ----------------------------------------------------------------- */
-
-/*
- * 03-group-children
- *
- * This example reuses the simple_children group from above. However,
- * the simple_children group is not the subsystem itself, it is a
- * child of the subsystem. Creation of a group in the subsystem creates
- * a new simple_children group. That group can then have simple_child
- * children of its own.
- */
-
-static struct config_group *group_children_make_group(struct config_group *group, const char *name)
-{
- struct simple_children *simple_children;
-
- simple_children = kzalloc(sizeof(struct simple_children),
- GFP_KERNEL);
- if (!simple_children)
- return ERR_PTR(-ENOMEM);
-
- config_group_init_type_name(&simple_children->group, name,
- &simple_children_type);
-
- return &simple_children->group;
-}
-
-static struct configfs_attribute group_children_attr_description = {
- .ca_owner = THIS_MODULE,
- .ca_name = "description",
- .ca_mode = S_IRUGO,
-};
-
-static struct configfs_attribute *group_children_attrs[] = {
- &group_children_attr_description,
- NULL,
-};
-
-static ssize_t group_children_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- return sprintf(page,
-"[03-group-children]\n"
-"\n"
-"This subsystem allows the creation of child config_groups. These\n"
-"groups are like the subsystem simple-children.\n");
-}
-
-static struct configfs_item_operations group_children_item_ops = {
- .show_attribute = group_children_attr_show,
-};
-
-/*
- * Note that, since no extra work is required on ->drop_item(),
- * no ->drop_item() is provided.
- */
-static struct configfs_group_operations group_children_group_ops = {
- .make_group = group_children_make_group,
-};
-
-static struct config_item_type group_children_type = {
- .ct_item_ops = &group_children_item_ops,
- .ct_group_ops = &group_children_group_ops,
- .ct_attrs = group_children_attrs,
- .ct_owner = THIS_MODULE,
-};
-
-static struct configfs_subsystem group_children_subsys = {
- .su_group = {
- .cg_item = {
- .ci_namebuf = "03-group-children",
- .ci_type = &group_children_type,
- },
- },
-};
-
-/* ----------------------------------------------------------------- */
-
-/*
- * We're now done with our subsystem definitions.
- * For convenience in this module, here's a list of them all. It
- * allows the init function to easily register them. Most modules
- * will only have one subsystem, and will only call register_subsystem
- * on it directly.
- */
-static struct configfs_subsystem *example_subsys[] = {
- &childless_subsys.subsys,
- &simple_children_subsys,
- &group_children_subsys,
- NULL,
-};
-
-static int __init configfs_example_init(void)
-{
- int ret;
- int i;
- struct configfs_subsystem *subsys;
-
- for (i = 0; example_subsys[i]; i++) {
- subsys = example_subsys[i];
-
- config_group_init(&subsys->su_group);
- mutex_init(&subsys->su_mutex);
- ret = configfs_register_subsystem(subsys);
- if (ret) {
- printk(KERN_ERR "Error %d while registering subsystem %s\n",
- ret,
- subsys->su_group.cg_item.ci_namebuf);
- goto out_unregister;
- }
- }
-
- return 0;
-
-out_unregister:
- for (i--; i >= 0; i--)
- configfs_unregister_subsystem(example_subsys[i]);
-
- return ret;
-}
-
-static void __exit configfs_example_exit(void)
-{
- int i;
-
- for (i = 0; example_subsys[i]; i++)
- configfs_unregister_subsystem(example_subsys[i]);
-}
-
-module_init(configfs_example_init);
-module_exit(configfs_example_exit);
-MODULE_LICENSE("GPL");
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt
index 6db0e5d..2809145 100644
--- a/Documentation/filesystems/overlayfs.txt
+++ b/Documentation/filesystems/overlayfs.txt
@@ -1,4 +1,5 @@
-Written by: Neil Brown <neilb@suse.de>
+Written by: Neil Brown
+Please see MAINTAINERS file for where to send questions.
Overlay Filesystem
==================
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index f24d1b8..0f88e60 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -504,3 +504,20 @@ in your dentry operations instead.
[mandatory]
__fd_install() & fd_install() can now sleep. Callers should not
hold a spinlock or other resources that do not allow a schedule.
+--
+[mandatory]
+ any symlink that might use page_follow_link_light/page_put_link() must
+ have inode_nohighmem(inode) called before anything might start playing with
+ its pagecache.
+--
+[mandatory]
+ ->follow_link() is replaced with ->get_link(); same API, except that
+ * ->get_link() gets inode as a separate argument
+ * ->get_link() may be called in RCU mode - in that case NULL
+ dentry is passed
+--
+[mandatory]
+ ->get_link() gets struct delayed_call *done now, and should do
+ set_delayed_call() where it used to set *cookie.
+ ->put_link() is gone - just give the destructor to set_delayed_call()
+ in ->get_link().
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 1e4a6cc..402ab99 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1605,16 +1605,16 @@ Documentation/accounting.
---------------------------------------------------------------
When a process is dumped, all anonymous memory is written to a core file as
long as the size of the core file isn't limited. But sometimes we don't want
-to dump some memory segments, for example, huge shared memory. Conversely,
-sometimes we want to save file-backed memory segments into a core file, not
-only the individual files.
+to dump some memory segments, for example, huge shared memory or DAX.
+Conversely, sometimes we want to save file-backed memory segments into a core
+file, not only the individual files.
/proc/<pid>/coredump_filter allows you to customize which memory segments
will be dumped when the <pid> process is dumped. coredump_filter is a bitmask
of memory types. If a bit of the bitmask is set, memory segments of the
corresponding memory type are dumped, otherwise they are not dumped.
-The following 7 memory types are supported:
+The following 9 memory types are supported:
- (bit 0) anonymous private memory
- (bit 1) anonymous shared memory
- (bit 2) file-backed private memory
@@ -1623,20 +1623,22 @@ The following 7 memory types are supported:
effective only if the bit 2 is cleared)
- (bit 5) hugetlb private memory
- (bit 6) hugetlb shared memory
+ - (bit 7) DAX private memory
+ - (bit 8) DAX shared memory
Note that MMIO pages such as frame buffer are never dumped and vDSO pages
are always dumped regardless of the bitmask status.
- Note bit 0-4 doesn't effect any hugetlb memory. hugetlb memory are only
- effected by bit 5-6.
+ Note that bits 0-4 don't affect hugetlb or DAX memory. hugetlb memory is
+ only affected by bit 5-6, and DAX is only affected by bits 7-8.
-Default value of coredump_filter is 0x23; this means all anonymous memory
-segments and hugetlb private memory are dumped.
+The default value of coredump_filter is 0x33; this means all anonymous memory
+segments, ELF header pages and hugetlb private memory are dumped.
If you don't want to dump all shared memory segments attached to pid 1234,
-write 0x21 to the process's proc file.
+write 0x31 to the process's proc file.
- $ echo 0x21 > /proc/1234/coredump_filter
+ $ echo 0x31 > /proc/1234/coredump_filter
When a new process is created, the process inherits the bitmask status from its
parent. It is useful to set up coredump_filter before the program runs.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 8c6f07a..b02a7d5 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -350,8 +350,8 @@ struct inode_operations {
int (*rename2) (struct inode *, struct dentry *,
struct inode *, struct dentry *, unsigned int);
int (*readlink) (struct dentry *, char __user *,int);
- const char *(*follow_link) (struct dentry *, void **);
- void (*put_link) (struct inode *, void *);
+ const char *(*get_link) (struct dentry *, struct inode *,
+ struct delayed_call *);
int (*permission) (struct inode *, int);
int (*get_acl)(struct inode *, int);
int (*setattr) (struct dentry *, struct iattr *);
@@ -434,20 +434,19 @@ otherwise noted.
readlink: called by the readlink(2) system call. Only required if
you want to support reading symbolic links
- follow_link: called by the VFS to follow a symbolic link to the
+ get_link: called by the VFS to follow a symbolic link to the
inode it points to. Only required if you want to support
symbolic links. This method returns the symlink body
to traverse (and possibly resets the current position with
nd_jump_link()). If the body won't go away until the inode
is gone, nothing else is needed; if it needs to be otherwise
- pinned, the data needed to release whatever we'd grabbed
- is to be stored in void * variable passed by address to
- follow_link() instance.
-
- put_link: called by the VFS to release resources allocated by
- follow_link(). The cookie stored by follow_link() is passed
- to this method as the last parameter; only called when
- cookie isn't NULL.
+ pinned, arrange for its release by having get_link(..., ..., done)
+ do set_delayed_call(done, destructor, argument).
+ In that case destructor(argument) will be called once VFS is
+ done with the body you've returned.
+ May be called in RCU mode; that is indicated by NULL dentry
+ argument. If request can't be handled without leaving RCU mode,
+ have it return ERR_PTR(-ECHILD).
permission: called by the VFS to check for access rights on a POSIX-like
filesystem.
diff --git a/Documentation/hwmon/htu21 b/Documentation/hwmon/htu21
deleted file mode 100644
index f39a215..0000000
--- a/Documentation/hwmon/htu21
+++ /dev/null
@@ -1,46 +0,0 @@
-Kernel driver htu21
-===================
-
-Supported chips:
- * Measurement Specialties HTU21D
- Prefix: 'htu21'
- Addresses scanned: none
- Datasheet: Publicly available at the Measurement Specialties website
- http://www.meas-spec.com/downloads/HTU21D.pdf
-
-
-Author:
- William Markezana <william.markezana@meas-spec.com>
-
-Description
------------
-
-The HTU21D is a humidity and temperature sensor in a DFN package of
-only 3 x 3 mm footprint and 0.9 mm height.
-
-The devices communicate with the I2C protocol. All sensors are set to the
-same I2C address 0x40, so an entry with I2C_BOARD_INFO("htu21", 0x40) can
-be used in the board setup code.
-
-This driver does not auto-detect devices. You will have to instantiate the
-devices explicitly. Please see Documentation/i2c/instantiating-devices
-for details.
-
-sysfs-Interface
----------------
-
-temp1_input - temperature input
-humidity1_input - humidity input
-
-Notes
------
-
-The driver uses the default resolution settings of 12 bit for humidity and 14
-bit for temperature, which results in typical measurement times of 11 ms for
-humidity and 44 ms for temperature. To keep self heating below 0.1 degree
-Celsius, the device should not be active for more than 10% of the time. For
-this reason, the driver performs no more than two measurements per second and
-reports cached information if polled more frequently.
-
-Different resolutions, the on-chip heater, using the CRC checksum and reading
-the serial number are not supported yet.
diff --git a/Documentation/hwmon/ltc3815 b/Documentation/hwmon/ltc3815
new file mode 100644
index 0000000..eb7db2d
--- /dev/null
+++ b/Documentation/hwmon/ltc3815
@@ -0,0 +1,61 @@
+Kernel driver ltc3815
+=====================
+
+Supported chips:
+ * Linear Technology LTC3815
+ Prefix: 'ltc3815'
+ Addresses scanned: -
+ Datasheet: http://www.linear.com/product/ltc3815
+
+Author: Guenter Roeck <linux@roeck-us.net>
+
+
+Description
+-----------
+
+LTC3815 is a Monolithic Synchronous DC/DC Step-Down Converter.
+
+
+Usage Notes
+-----------
+
+This driver does not probe for PMBus devices. You will have to instantiate
+devices explicitly.
+
+Example: the following commands will load the driver for an LTC3815
+at address 0x20 on I2C bus #1:
+
+# modprobe ltc3815
+# echo ltc3815 0x20 > /sys/bus/i2c/devices/i2c-1/new_device
+
+
+Sysfs attributes
+----------------
+
+in1_label "vin"
+in1_input Measured input voltage.
+in1_alarm Input voltage alarm.
+in1_highest Highest input voltage.
+in1_reset_history Reset input voltage history.
+
+in2_label "vout1".
+in2_input Measured output voltage.
+in2_alarm Output voltage alarm.
+in2_highest Highest output voltage.
+in2_reset_history Reset output voltage history.
+
+temp1_input Measured chip temperature.
+temp1_alarm Temperature alarm.
+temp1_highest Highest measured temperature.
+temp1_reset_history Reset temperature history.
+
+curr1_label "iin".
+curr1_input Measured input current.
+curr1_highest Highest input current.
+curr1_reset_history Reset input current history.
+
+curr2_label "iout1".
+curr2_input Measured output current.
+curr2_alarm Output current alarm.
+curr2_highest Highest output current.
+curr2_reset_history Reset output current history.
diff --git a/Documentation/hwmon/scpi-hwmon b/Documentation/hwmon/scpi-hwmon
new file mode 100644
index 0000000..4cfcdf2d
--- /dev/null
+++ b/Documentation/hwmon/scpi-hwmon
@@ -0,0 +1,33 @@
+Kernel driver scpi-hwmon
+========================
+
+Supported chips:
+ * Chips based on ARM System Control Processor Interface
+ Addresses scanned: -
+ Datasheet: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0922b/index.html
+
+Author: Punit Agrawal <punit.agrawal@arm.com>
+
+Description
+-----------
+
+This driver supports hardware monitoring for SoC's based on the ARM
+System Control Processor (SCP) implementing the System Control
+Processor Interface (SCPI). The following sensor types are supported
+by the SCP -
+
+ * temperature
+ * voltage
+ * current
+ * power
+
+The SCP interface provides an API to query the available sensors and
+their values which are then exported to userspace by this driver.
+
+Usage Notes
+-----------
+
+The driver relies on device tree node to indicate the presence of SCPI
+support in the kernel. See
+Documentation/devicetree/bindings/arm/arm,scpi.txt for details of the
+devicetree node. \ No newline at end of file
diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801
index 82f48f7..1bba38d 100644
--- a/Documentation/i2c/busses/i2c-i801
+++ b/Documentation/i2c/busses/i2c-i801
@@ -30,6 +30,9 @@ Supported adapters:
* Intel BayTrail (SOC)
* Intel Sunrise Point-H (PCH)
* Intel Sunrise Point-LP (PCH)
+ * Intel DNV (SOC)
+ * Intel Broxton (SOC)
+ * Intel Lewisburg (PCH)
Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller
diff --git a/Documentation/kbuild/Kconfig.recursion-issue-01 b/Documentation/kbuild/Kconfig.recursion-issue-01
new file mode 100644
index 0000000..e8877db
--- /dev/null
+++ b/Documentation/kbuild/Kconfig.recursion-issue-01
@@ -0,0 +1,57 @@
+# Simple Kconfig recursive issue
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Test with:
+#
+# make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig
+#
+# This Kconfig file has a simple recursive dependency issue. In order to
+# understand why this recursive dependency issue occurs lets consider what
+# Kconfig needs to address. We iterate over what Kconfig needs to address
+# by stepping through the questions it needs to address sequentially.
+#
+# * What values are possible for CORE?
+#
+# CORE_BELL_A_ADVANCED selects CORE, which means that it influences the values
+# that are possible for CORE. So for example if CORE_BELL_A_ADVANCED is 'y',
+# CORE must be 'y' too.
+#
+# * What influences CORE_BELL_A_ADVANCED ?
+#
+# As the name implies CORE_BELL_A_ADVANCED is an advanced feature of
+# CORE_BELL_A so naturally it depends on CORE_BELL_A. So if CORE_BELL_A is 'y'
+# we know CORE_BELL_A_ADVANCED can be 'y' too.
+#
+# * What influences CORE_BELL_A ?
+#
+# CORE_BELL_A depends on CORE, so CORE influences CORE_BELL_A.
+#
+# But that is a problem, because this means that in order to determine
+# what values are possible for CORE we ended up needing to address questions
+# regarding possible values of CORE itself again. Answering the original
+# question of what are the possible values of CORE would make the kconfig
+# tools run in a loop. When this happens Kconfig exits and complains about
+# the "recursive dependency detected" error.
+#
+# Reading the Documentation/kbuild/Kconfig.recursion-issue-01 file it may be
+# obvious that an easy to solution to this problem should just be the removal
+# of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already
+# since CORE_BELL_A depends on CORE. Recursive dependency issues are not always
+# so trivial to resolve, we provide another example below of practical
+# implications of this recursive issue where the solution is perhaps not so
+# easy to understand. Note that matching semantics on the dependency on
+# CORE also consist of a solution to this recursive problem.
+
+mainmenu "Simple example to demo kconfig recursive dependency issue"
+
+config CORE
+ tristate
+
+config CORE_BELL_A
+ tristate
+ depends on CORE
+
+config CORE_BELL_A_ADVANCED
+ tristate
+ depends on CORE_BELL_A
+ select CORE
diff --git a/Documentation/kbuild/Kconfig.recursion-issue-02 b/Documentation/kbuild/Kconfig.recursion-issue-02
new file mode 100644
index 0000000..b9fd56c
--- /dev/null
+++ b/Documentation/kbuild/Kconfig.recursion-issue-02
@@ -0,0 +1,63 @@
+# Cumulative Kconfig recursive issue
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Test with:
+#
+# make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig
+#
+# The recursive limitations with Kconfig has some non intuitive implications on
+# kconfig sematics which are documented here. One known practical implication
+# of the recursive limitation is that drivers cannot negate features from other
+# drivers if they share a common core requirement and use disjoint semantics to
+# annotate those requirements, ie, some drivers use "depends on" while others
+# use "select". For instance it means if a driver A and driver B share the same
+# core requirement, and one uses "select" while the other uses "depends on" to
+# annotate this, all features that driver A selects cannot now be negated by
+# driver B.
+#
+# A perhaps not so obvious implication of this is that, if semantics on these
+# core requirements are not carefully synced, as drivers evolve features
+# they select or depend on end up becoming shared requirements which cannot be
+# negated by other drivers.
+#
+# The example provided in Documentation/kbuild/Kconfig.recursion-issue-02
+# describes a simple driver core layout of example features a kernel might
+# have. Let's assume we have some CORE functionality, then the kernel has a
+# series of bells and whistles it desires to implement, its not so advanced so
+# it only supports bells at this time: CORE_BELL_A and CORE_BELL_B. If
+# CORE_BELL_A has some advanced feature CORE_BELL_A_ADVANCED which selects
+# CORE_BELL_A then CORE_BELL_A ends up becoming a common BELL feature which
+# other bells in the system cannot negate. The reason for this issue is
+# due to the disjoint use of semantics on expressing each bell's relationship
+# with CORE, one uses "depends on" while the other uses "select". Another
+# more important reason is that kconfig does not check for dependencies listed
+# under 'select' for a symbol, when such symbols are selected kconfig them
+# as mandatory required symbols. For more details on the heavy handed nature
+# of select refer to Documentation/kbuild/Kconfig.select-break
+#
+# To fix this the "depends on CORE" must be changed to "select CORE", or the
+# "select CORE" must be changed to "depends on CORE".
+#
+# For an example real world scenario issue refer to the attempt to remove
+# "select FW_LOADER" [0], in the end the simple alternative solution to this
+# problem consisted on matching semantics with newly introduced features.
+#
+# [0] http://lkml.kernel.org/r/1432241149-8762-1-git-send-email-mcgrof@do-not-panic.com
+
+mainmenu "Simple example to demo cumulative kconfig recursive dependency implication"
+
+config CORE
+ tristate
+
+config CORE_BELL_A
+ tristate
+ depends on CORE
+
+config CORE_BELL_A_ADVANCED
+ tristate
+ select CORE_BELL_A
+
+config CORE_BELL_B
+ tristate
+ depends on !CORE_BELL_A
+ select CORE
diff --git a/Documentation/kbuild/Kconfig.select-break b/Documentation/kbuild/Kconfig.select-break
new file mode 100644
index 0000000..365ceb3
--- /dev/null
+++ b/Documentation/kbuild/Kconfig.select-break
@@ -0,0 +1,33 @@
+# Select broken dependency issue
+# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#
+# Test with:
+#
+# make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.select-break menuconfig
+#
+# kconfig will not complain and enable this layout for configuration. This is
+# currently a feature of kconfig, given select was designed to be heavy handed.
+# Kconfig currently does not check the list of symbols listed on a symbol's
+# "select" list, this is done on purpose to help load a set of known required
+# symbols. Because of this use of select should be used with caution. An
+# example of this issue is below.
+#
+# The option B and C are clearly contradicting with respect to A.
+# However, when A is set, C can be set as well because Kconfig does not
+# visit the dependencies of the select target (in this case B). And since
+# Kconfig does not visit the dependencies, it breaks the dependencies of B
+# (!A).
+
+mainmenu "Simple example to demo kconfig select broken dependency issue"
+
+config A
+ bool "CONFIG A"
+
+config B
+ bool "CONFIG B"
+ depends on !A
+
+config C
+ bool "CONFIG C"
+ depends on A
+ select B
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 350f733..c52856d 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -393,3 +393,164 @@ config FOO
depends on BAR && m
limits FOO to module (=m) or disabled (=n).
+
+Kconfig recursive dependency limitations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you've hit the Kconfig error: "recursive dependency detected" you've run
+into a recursive dependency issue with Kconfig, a recursive dependency can be
+summarized as a circular dependency. The kconfig tools need to ensure that
+Kconfig files comply with specified configuration requirements. In order to do
+that kconfig must determine the values that are possible for all Kconfig
+symbols, this is currently not possible if there is a circular relation
+between two or more Kconfig symbols. For more details refer to the "Simple
+Kconfig recursive issue" subsection below. Kconfig does not do recursive
+dependency resolution; this has a few implications for Kconfig file writers.
+We'll first explain why this issues exists and then provide an example
+technical limitation which this brings upon Kconfig developers. Eager
+developers wishing to try to address this limitation should read the next
+subsections.
+
+Simple Kconfig recursive issue
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Read: Documentation/kbuild/Kconfig.recursion-issue-01
+
+Test with:
+
+make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-01 allnoconfig
+
+Cumulative Kconfig recursive issue
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Read: Documentation/kbuild/Kconfig.recursion-issue-02
+
+Test with:
+
+make KBUILD_KCONFIG=Documentation/kbuild/Kconfig.recursion-issue-02 allnoconfig
+
+Practical solutions to kconfig recursive issue
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Developers who run into the recursive Kconfig issue have three options
+at their disposal. We document them below and also provide a list of
+historical issues resolved through these different solutions.
+
+ a) Remove any superfluous "select FOO" or "depends on FOO"
+ b) Match dependency semantics:
+ b1) Swap all "select FOO" to "depends on FOO" or,
+ b2) Swap all "depends on FOO" to "select FOO"
+
+The resolution to a) can be tested with the sample Kconfig file
+Documentation/kbuild/Kconfig.recursion-issue-01 through the removal
+of the "select CORE" from CORE_BELL_A_ADVANCED as that is implicit already
+since CORE_BELL_A depends on CORE. At times it may not be possible to remove
+some dependency criteria, for such cases you can work with solution b).
+
+The two different resolutions for b) can be tested in the sample Kconfig file
+Documentation/kbuild/Kconfig.recursion-issue-02.
+
+Below is a list of examples of prior fixes for these types of recursive issues;
+all errors appear to involve one or more select's and one or more "depends on".
+
+commit fix
+====== ===
+06b718c01208 select A -> depends on A
+c22eacfe82f9 depends on A -> depends on B
+6a91e854442c select A -> depends on A
+118c565a8f2e select A -> select B
+f004e5594705 select A -> depends on A
+c7861f37b4c6 depends on A -> (null)
+80c69915e5fb select A -> (null) (1)
+c2218e26c0d0 select A -> depends on A (1)
+d6ae99d04e1c select A -> depends on A
+95ca19cf8cbf select A -> depends on A
+8f057d7bca54 depends on A -> (null)
+8f057d7bca54 depends on A -> select A
+a0701f04846e select A -> depends on A
+0c8b92f7f259 depends on A -> (null)
+e4e9e0540928 select A -> depends on A (2)
+7453ea886e87 depends on A > (null) (1)
+7b1fff7e4fdf select A -> depends on A
+86c747d2a4f0 select A -> depends on A
+d9f9ab51e55e select A -> depends on A
+0c51a4d8abd6 depends on A -> select A (3)
+e98062ed6dc4 select A -> depends on A (3)
+91e5d284a7f1 select A -> (null)
+
+(1) Partial (or no) quote of error.
+(2) That seems to be the gist of that fix.
+(3) Same error.
+
+Future kconfig work
+~~~~~~~~~~~~~~~~~~~
+
+Work on kconfig is welcomed on both areas of clarifying semantics and on
+evaluating the use of a full SAT solver for it. A full SAT solver can be
+desirable to enable more complex dependency mappings and / or queries,
+for instance on possible use case for a SAT solver could be that of handling
+the current known recursive dependency issues. It is not known if this would
+address such issues but such evaluation is desirable. If support for a full SAT
+solver proves too complex or that it cannot address recursive dependency issues
+Kconfig should have at least clear and well defined semantics which also
+addresses and documents limitations or requirements such as the ones dealing
+with recursive dependencies.
+
+Further work on both of these areas is welcomed on Kconfig. We elaborate
+on both of these in the next two subsections.
+
+Semantics of Kconfig
+~~~~~~~~~~~~~~~~~~~~
+
+The use of Kconfig is broad, Linux is now only one of Kconfig's users:
+one study has completed a broad analysis of Kconfig use in 12 projects [0].
+Despite its widespread use, and although this document does a reasonable job
+in documenting basic Kconfig syntax a more precise definition of Kconfig
+semantics is welcomed. One project deduced Kconfig semantics through
+the use of the xconfig configurator [1]. Work should be done to confirm if
+the deduced semantics matches our intended Kconfig design goals.
+
+Having well defined semantics can be useful for tools for practical
+evaluation of depenencies, for instance one such use known case was work to
+express in boolean abstraction of the inferred semantics of Kconfig to
+translate Kconfig logic into boolean formulas and run a SAT solver on this to
+find dead code / features (always inactive), 114 dead features were found in
+Linux using this methodology [1] (Section 8: Threats to validity).
+
+Confirming this could prove useful as Kconfig stands as one of the the leading
+industrial variability modeling languages [1] [2]. Its study would help
+evaluate practical uses of such languages, their use was only theoretical
+and real world requirements were not well understood. As it stands though
+only reverse engineering techniques have been used to deduce semantics from
+variability modeling languages such as Kconfig [3].
+
+[0] http://www.eng.uwaterloo.ca/~shshe/kconfig_semantics.pdf
+[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
+[2] http://gsd.uwaterloo.ca/sites/default/files/ase241-berger_0.pdf
+[3] http://gsd.uwaterloo.ca/sites/default/files/icse2011.pdf
+
+Full SAT solver for Kconfig
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Although SAT solvers [0] haven't yet been used by Kconfig directly, as noted in
+the previous subsection, work has been done however to express in boolean
+abstraction the inferred semantics of Kconfig to translate Kconfig logic into
+boolean formulas and run a SAT solver on it [1]. Another known related project
+is CADOS [2] (former VAMOS [3]) and the tools, mainly undertaker [4], which has
+been introduced first with [5]. The basic concept of undertaker is to exract
+variability models from Kconfig, and put them together with a propositional
+formula extracted from CPP #ifdefs and build-rules into a SAT solver in order
+to find dead code, dead files, and dead symbols. If using a SAT solver is
+desirable on Kconfig one approach would be to evaluate repurposing such efforts
+somehow on Kconfig. There is enough interest from mentors of existing projects
+to not only help advise how to integrate this work upstream but also help
+maintain it long term. Interested developers should visit:
+
+http://kernelnewbies.org/KernelProjects/kconfig-sat
+
+[0] http://www.cs.cornell.edu/~sabhar/chapters/SATSolvers-KR-Handbook.pdf
+[1] http://gsd.uwaterloo.ca/sites/default/files/vm-2013-berger.pdf
+[2] https://cados.cs.fau.de
+[3] https://vamos.cs.fau.de
+[4] https://undertaker.cs.fau.de
+[5] https://www4.cs.fau.de/Publications/2011/tartler_11_eurosys.pdf
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index f8aae63..1a8169b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -472,6 +472,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
Change the amount of debugging information output
when initialising the APIC and IO-APIC components.
+ apic_extnmi= [APIC,X86] External NMI delivery setting
+ Format: { bsp (default) | all | none }
+ bsp: External NMI is delivered only to CPU 0
+ all: External NMIs are broadcast to all CPUs as a
+ backup of CPU 0
+ none: External NMI is masked for all CPUs. This is
+ useful so that a dump capture kernel won't be
+ shot down by NMI
+
autoconf= [IPV6]
See Documentation/networking/ipv6.txt.
@@ -1583,9 +1592,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
hwp_only
Only load intel_pstate on systems which support
hardware P state control (HWP) if available.
- no_acpi
- Don't use ACPI processor performance control objects
- _PSS and _PPC specified limits.
intremap= [X86-64, Intel-IOMMU]
on enable Interrupt Remapping (default)
@@ -3299,18 +3305,35 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
rcutorture.verbose= [KNL]
Enable additional printk() statements.
+ rcupdate.rcu_cpu_stall_suppress= [KNL]
+ Suppress RCU CPU stall warning messages.
+
+ rcupdate.rcu_cpu_stall_timeout= [KNL]
+ Set timeout for RCU CPU stall warning messages.
+
rcupdate.rcu_expedited= [KNL]
Use expedited grace-period primitives, for
example, synchronize_rcu_expedited() instead
of synchronize_rcu(). This reduces latency,
but can increase CPU utilization, degrade
real-time latency, and degrade energy efficiency.
-
- rcupdate.rcu_cpu_stall_suppress= [KNL]
- Suppress RCU CPU stall warning messages.
-
- rcupdate.rcu_cpu_stall_timeout= [KNL]
- Set timeout for RCU CPU stall warning messages.
+ No effect on CONFIG_TINY_RCU kernels.
+
+ rcupdate.rcu_normal= [KNL]
+ Use only normal grace-period primitives,
+ for example, synchronize_rcu() instead of
+ synchronize_rcu_expedited(). This improves
+ real-time latency, CPU utilization, and
+ energy efficiency, but can expose users to
+ increased grace-period latency. This parameter
+ overrides rcupdate.rcu_expedited. No effect on
+ CONFIG_TINY_RCU kernels.
+
+ rcupdate.rcu_normal_after_boot= [KNL]
+ Once boot has completed (that is, after
+ rcu_end_inkernel_boot() has been invoked), use
+ only normal grace-period primitives. No effect
+ on CONFIG_TINY_RCU kernels.
rcupdate.rcu_task_stall_timeout= [KNL]
Set timeout in jiffies for RCU task stall warning
@@ -4117,6 +4140,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
or other driver-specific files in the
Documentation/watchdog/ directory.
+ workqueue.watchdog_thresh=
+ If CONFIG_WQ_WATCHDOG is configured, workqueue can
+ warn stall conditions and dump internal state to
+ help debugging. 0 disables workqueue stall
+ detection; otherwise, it's the stall threshold
+ duration in seconds. The default value is 30 and
+ it can be updated at runtime by writing to the
+ corresponding sysfs file.
+
workqueue.disable_numa
By default, all work items queued to unbound
workqueues are affine to the NUMA nodes they're
diff --git a/Documentation/leds/leds-class.txt b/Documentation/leds/leds-class.txt
index 62261c0..d406d98 100644
--- a/Documentation/leds/leds-class.txt
+++ b/Documentation/leds/leds-class.txt
@@ -52,6 +52,19 @@ above leaves scope for further attributes should they be needed. If sections
of the name don't apply, just leave that section blank.
+Brightness setting API
+======================
+
+LED subsystem core exposes following API for setting brightness:
+
+ - led_set_brightness : it is guaranteed not to sleep, passing LED_OFF stops
+ blinking,
+ - led_set_brightness_sync : for use cases when immediate effect is desired -
+ it can block the caller for the time required for accessing
+ device registers and can sleep, passing LED_OFF stops hardware
+ blinking, returns -EBUSY if software blink fallback is enabled.
+
+
Hardware accelerated blink of LEDs
==================================
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index aef9487..a61be39 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -194,7 +194,7 @@ There are some minimal guarantees that may be expected of a CPU:
(*) On any given CPU, dependent memory accesses will be issued in order, with
respect to itself. This means that for:
- WRITE_ONCE(Q, P); smp_read_barrier_depends(); D = READ_ONCE(*Q);
+ Q = READ_ONCE(P); smp_read_barrier_depends(); D = READ_ONCE(*Q);
the CPU will issue the following memory operations:
@@ -202,9 +202,9 @@ There are some minimal guarantees that may be expected of a CPU:
and always in that order. On most systems, smp_read_barrier_depends()
does nothing, but it is required for DEC Alpha. The READ_ONCE()
- and WRITE_ONCE() are required to prevent compiler mischief. Please
- note that you should normally use something like rcu_dereference()
- instead of open-coding smp_read_barrier_depends().
+ is required to prevent compiler mischief. Please note that you
+ should normally use something like rcu_dereference() instead of
+ open-coding smp_read_barrier_depends().
(*) Overlapping loads and stores within a particular CPU will appear to be
ordered within that CPU. This means that for:
@@ -1673,8 +1673,8 @@ There are some more advanced barrier functions:
(*) smp_store_mb(var, value)
This assigns the value to the variable and then inserts a full memory
- barrier after it, depending on the function. It isn't guaranteed to
- insert anything more than a compiler barrier in a UP compilation.
+ barrier after it. It isn't guaranteed to insert anything more than a
+ compiler barrier in a UP compilation.
(*) smp_mb__before_atomic();
diff --git a/Documentation/networking/can.txt b/Documentation/networking/can.txt
index 4636b94..05fd83b 100644
--- a/Documentation/networking/can.txt
+++ b/Documentation/networking/can.txt
@@ -681,7 +681,7 @@ solution for a couple of reasons:
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
- connect(s, (struct sockaddr *)&addr, sizeof(addr))
+ connect(s, (struct sockaddr *)&addr, sizeof(addr));
(..)
diff --git a/Documentation/networking/e100.txt b/Documentation/networking/e100.txt
index f862cf3..42ddbd4 100644
--- a/Documentation/networking/e100.txt
+++ b/Documentation/networking/e100.txt
@@ -181,17 +181,3 @@ For general information, go to the Intel support website at:
If an issue is identified with the released source code on the supported
kernel with a supported adapter, email the specific information related to the
issue to e1000-devel@lists.sourceforge.net.
-
-
-License
-=======
-
-This software program is released under the terms of a license agreement
-between you ('Licensee') and Intel. Do not use or load this software or any
-associated materials (collectively, the 'Software') until you have carefully
-read the full terms and conditions of the file COPYING located in this software
-package. By loading or using the Software, you agree to the terms of this
-Agreement. If you do not agree with the terms of this Agreement, do not install
-or use the Software.
-
-* Other names and brands may be claimed as the property of others.
diff --git a/Documentation/networking/filter.txt b/Documentation/networking/filter.txt
index 135581f..96da119 100644
--- a/Documentation/networking/filter.txt
+++ b/Documentation/networking/filter.txt
@@ -596,9 +596,9 @@ skb pointer). All constraints and restrictions from bpf_check_classic() apply
before a conversion to the new layout is being done behind the scenes!
Currently, the classic BPF format is being used for JITing on most of the
-architectures. Only x86-64 performs JIT compilation from eBPF instruction set,
-however, future work will migrate other JIT compilers as well, so that they
-will profit from the very same benefits.
+architectures. x86-64, aarch64 and s390x perform JIT compilation from eBPF
+instruction set, however, future work will migrate other JIT compilers as well,
+so that they will profit from the very same benefits.
Some core changes of the new internal format:
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 05915be..2ea4c45 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -709,7 +709,7 @@ tcp_limit_output_bytes - INTEGER
typical pfifo_fast qdiscs.
tcp_limit_output_bytes limits the number of bytes on qdisc
or device to reduce artificial RTT/cwnd and reduce bufferbloat.
- Default: 131072
+ Default: 262144
tcp_challenge_ack_limit - INTEGER
Limits number of Challenge ACK sent per second, as recommended
diff --git a/Documentation/nvdimm/nvdimm.txt b/Documentation/nvdimm/nvdimm.txt
index 197a0b6..e894de6 100644
--- a/Documentation/nvdimm/nvdimm.txt
+++ b/Documentation/nvdimm/nvdimm.txt
@@ -62,6 +62,12 @@ DAX: File system extensions to bypass the page cache and block layer to
mmap persistent memory, from a PMEM block device, directly into a
process address space.
+DSM: Device Specific Method: ACPI method to to control specific
+device - in this case the firmware.
+
+DCR: NVDIMM Control Region Structure defined in ACPI 6 Section 5.2.25.5.
+It defines a vendor-id, device-id, and interface format for a given DIMM.
+
BTT: Block Translation Table: Persistent memory is byte addressable.
Existing software may have an expectation that the power-fail-atomicity
of writes is at least one sector, 512 bytes. The BTT is an indirection
@@ -133,16 +139,16 @@ device driver:
registered, can be immediately attached to nd_pmem.
2. BLK (nd_blk.ko): This driver performs I/O using a set of platform
- defined apertures. A set of apertures will all access just one DIMM.
- Multiple windows allow multiple concurrent accesses, much like
+ defined apertures. A set of apertures will access just one DIMM.
+ Multiple windows (apertures) allow multiple concurrent accesses, much like
tagged-command-queuing, and would likely be used by different threads or
different CPUs.
The NFIT specification defines a standard format for a BLK-aperture, but
the spec also allows for vendor specific layouts, and non-NFIT BLK
- implementations may other designs for BLK I/O. For this reason "nd_blk"
- calls back into platform-specific code to perform the I/O. One such
- implementation is defined in the "Driver Writer's Guide" and "DSM
+ implementations may have other designs for BLK I/O. For this reason
+ "nd_blk" calls back into platform-specific code to perform the I/O.
+ One such implementation is defined in the "Driver Writer's Guide" and "DSM
Interface Example".
@@ -152,7 +158,7 @@ Why BLK?
While PMEM provides direct byte-addressable CPU-load/store access to
NVDIMM storage, it does not provide the best system RAS (recovery,
availability, and serviceability) model. An access to a corrupted
-system-physical-address address causes a cpu exception while an access
+system-physical-address address causes a CPU exception while an access
to a corrupted address through an BLK-aperture causes that block window
to raise an error status in a register. The latter is more aligned with
the standard error model that host-bus-adapter attached disks present.
@@ -162,7 +168,7 @@ data could be interleaved in an opaque hardware specific manner across
several DIMMs.
PMEM vs BLK
-BLK-apertures solve this RAS problem, but their presence is also the
+BLK-apertures solve these RAS problems, but their presence is also the
major contributing factor to the complexity of the ND subsystem. They
complicate the implementation because PMEM and BLK alias in DPA space.
Any given DIMM's DPA-range may contribute to one or more
@@ -220,8 +226,8 @@ socket. Each unique interface (BLK or PMEM) to DPA space is identified
by a region device with a dynamically assigned id (REGION0 - REGION5).
1. The first portion of DIMM0 and DIMM1 are interleaved as REGION0. A
- single PMEM namespace is created in the REGION0-SPA-range that spans
- DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
+ single PMEM namespace is created in the REGION0-SPA-range that spans most
+ of DIMM0 and DIMM1 with a user-specified name of "pm0.0". Some of that
interleaved system-physical-address range is reclaimed as BLK-aperture
accessed space starting at DPA-offset (a) into each DIMM. In that
reclaimed space we create two BLK-aperture "namespaces" from REGION2 and
@@ -230,13 +236,13 @@ by a region device with a dynamically assigned id (REGION0 - REGION5).
2. In the last portion of DIMM0 and DIMM1 we have an interleaved
system-physical-address range, REGION1, that spans those two DIMMs as
- well as DIMM2 and DIMM3. Some of REGION1 allocated to a PMEM namespace
- named "pm1.0" the rest is reclaimed in 4 BLK-aperture namespaces (for
+ well as DIMM2 and DIMM3. Some of REGION1 is allocated to a PMEM namespace
+ named "pm1.0", the rest is reclaimed in 4 BLK-aperture namespaces (for
each DIMM in the interleave set), "blk2.1", "blk3.1", "blk4.0", and
"blk5.0".
3. The portion of DIMM2 and DIMM3 that do not participate in the REGION1
- interleaved system-physical-address range (i.e. the DPA address below
+ interleaved system-physical-address range (i.e. the DPA address past
offset (b) are also included in the "blk4.0" and "blk5.0" namespaces.
Note, that this example shows that BLK-aperture namespaces don't need to
be contiguous in DPA-space.
@@ -252,15 +258,15 @@ LIBNVDIMM Kernel Device Model and LIBNDCTL Userspace API
What follows is a description of the LIBNVDIMM sysfs layout and a
corresponding object hierarchy diagram as viewed through the LIBNDCTL
-api. The example sysfs paths and diagrams are relative to the Example
+API. The example sysfs paths and diagrams are relative to the Example
NVDIMM Platform which is also the LIBNVDIMM bus used in the LIBNDCTL unit
test.
LIBNDCTL: Context
-Every api call in the LIBNDCTL library requires a context that holds the
+Every API call in the LIBNDCTL library requires a context that holds the
logging parameters and other library instance state. The library is
based on the libabc template:
-https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git/
+https://git.kernel.org/cgit/linux/kernel/git/kay/libabc.git
LIBNDCTL: instantiate a new library context example
@@ -409,7 +415,7 @@ Bit 31:28 Reserved
LIBNVDIMM/LIBNDCTL: Region
----------------------
-A generic REGION device is registered for each PMEM range orBLK-aperture
+A generic REGION device is registered for each PMEM range or BLK-aperture
set. Per the example there are 6 regions: 2 PMEM and 4 BLK-aperture
sets on the "nfit_test.0" bus. The primary role of regions are to be a
container of "mappings". A mapping is a tuple of <DIMM,
@@ -509,7 +515,7 @@ At first glance it seems since NFIT defines just PMEM and BLK interface
types that we should simply name REGION devices with something derived
from those type names. However, the ND subsystem explicitly keeps the
REGION name generic and expects userspace to always consider the
-region-attributes for 4 reasons:
+region-attributes for four reasons:
1. There are already more than two REGION and "namespace" types. For
PMEM there are two subtypes. As mentioned previously we have PMEM where
@@ -698,8 +704,8 @@ static int configure_namespace(struct ndctl_region *region,
Why the Term "namespace"?
- 1. Why not "volume" for instance? "volume" ran the risk of confusing ND
- as a volume manager like device-mapper.
+ 1. Why not "volume" for instance? "volume" ran the risk of confusing
+ ND (libnvdimm subsystem) to a volume manager like device-mapper.
2. The term originated to describe the sub-devices that can be created
within a NVME controller (see the nvme specification:
@@ -774,13 +780,14 @@ block" needs to be destroyed. Note, that to destroy a BTT the media
needs to be written in raw mode. By default, the kernel will autodetect
the presence of a BTT and disable raw mode. This autodetect behavior
can be suppressed by enabling raw mode for the namespace via the
-ndctl_namespace_set_raw_mode() api.
+ndctl_namespace_set_raw_mode() API.
Summary LIBNDCTL Diagram
------------------------
-For the given example above, here is the view of the objects as seen by the LIBNDCTL api:
+For the given example above, here is the view of the objects as seen by the
+LIBNDCTL API:
+---+
|CTX| +---------+ +--------------+ +---------------+
+-+-+ +-> REGION0 +---> NAMESPACE0.0 +--> PMEM8 "pm0.0" |
diff --git a/Documentation/printk-formats.txt b/Documentation/printk-formats.txt
index b784c27..6389551 100644
--- a/Documentation/printk-formats.txt
+++ b/Documentation/printk-formats.txt
@@ -250,6 +250,12 @@ dentry names:
Passed by reference.
+block_device names:
+
+ %pg sda, sda1 or loop0p1
+
+ For printing name of block_device pointers.
+
struct va_format:
%pV
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index f29fa55..b3211af 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -569,7 +569,9 @@ Debugging code is now compiled in by default but debugging is turned off
with the kernel module parameter debug_flag defaulting to 0. Debugging
can still be switched on and off with an ioctl. To enable debug at
module load time add debug_flag=1 to the module load options, the
-debugging output is not voluminous.
+debugging output is not voluminous. Debugging can also be enabled
+and disabled by writing a '0' (disable) or '1' (enable) to the sysfs
+file /sys/bus/scsi/drivers/st/debug_flag.
If the tape seems to hang, I would be very interested to hear where
the driver is waiting. With the command 'ps -l' you can see the state
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index 3352f97..13a0b7f 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -22,15 +22,10 @@ Typically a SPI master is defined in the arch/.../mach-*/board-*.c as a
found in include/linux/spi/pxa2xx_spi.h:
struct pxa2xx_spi_master {
- u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
};
-The "pxa2xx_spi_master.clock_enable" field is used to enable/disable the
-corresponding SSP peripheral block in the "Clock Enable Register (CKEN"). See
-the "PXA2xx Developer Manual" section "Clocks and Power Management".
-
The "pxa2xx_spi_master.num_chipselect" field is used to determine the number of
slave device (chips) attached to this SPI master.
@@ -57,7 +52,6 @@ static struct resource pxa_spi_nssp_resources[] = {
};
static struct pxa2xx_spi_master pxa_nssp_master_info = {
- .clock_enable = CKEN_NSSP, /* NSSP Peripheral clock */
.num_chipselect = 1, /* Matches the number of chips attached to NSSP */
.enable_dma = 1, /* Enables NSSP DMA */
};
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index af70d15..73c6b1e 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -551,6 +551,21 @@ the recommended setting is 60.
==============================================================
+panic_on_io_nmi:
+
+Controls the kernel's behavior when a CPU receives an NMI caused by
+an IO error.
+
+0: try to continue operation (default)
+
+1: panic immediately. The IO error triggered an NMI. This indicates a
+ serious system condition which could result in IO data corruption.
+ Rather than continuing, panicking might be a better choice. Some
+ servers issue this sort of NMI when the dump button is pushed,
+ and you can use this option to take a crash dump.
+
+==============================================================
+
panic_on_oops:
Controls the kernel's behaviour when an oops or BUG is encountered.
diff --git a/Documentation/target/tcm_mod_builder.py b/Documentation/target/tcm_mod_builder.py
index cda56df..7d370c9 100755
--- a/Documentation/target/tcm_mod_builder.py
+++ b/Documentation/target/tcm_mod_builder.py
@@ -203,8 +203,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += "#include <scsi/scsi_proto.h>\n\n"
buf += "#include <target/target_core_base.h>\n"
buf += "#include <target/target_core_fabric.h>\n"
- buf += "#include <target/target_core_fabric_configfs.h>\n"
- buf += "#include <target/configfs_macros.h>\n\n"
buf += "#include \"" + fabric_mod_name + "_base.h\"\n"
buf += "#include \"" + fabric_mod_name + "_fabric.h\"\n\n"
@@ -283,19 +281,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " struct " + fabric_mod_name + "_" + fabric_mod_port + ", " + fabric_mod_port + "_wwn);\n"
buf += " kfree(" + fabric_mod_port + ");\n"
buf += "}\n\n"
- buf += "static ssize_t " + fabric_mod_name + "_wwn_show_attr_version(\n"
- buf += " struct target_fabric_configfs *tf,\n"
- buf += " char *page)\n"
- buf += "{\n"
- buf += " return sprintf(page, \"" + fabric_mod_name.upper() + " fabric module %s on %s/%s\"\n"
- buf += " \"on \"UTS_RELEASE\"\\n\", " + fabric_mod_name.upper() + "_VERSION, utsname()->sysname,\n"
- buf += " utsname()->machine);\n"
- buf += "}\n\n"
- buf += "TF_WWN_ATTR_RO(" + fabric_mod_name + ", version);\n\n"
- buf += "static struct configfs_attribute *" + fabric_mod_name + "_wwn_attrs[] = {\n"
- buf += " &" + fabric_mod_name + "_wwn_version.attr,\n"
- buf += " NULL,\n"
- buf += "};\n\n"
buf += "static const struct target_core_fabric_ops " + fabric_mod_name + "_ops = {\n"
buf += " .module = THIS_MODULE,\n"
@@ -328,8 +313,6 @@ def tcm_mod_build_configfs(proto_ident, fabric_mod_dir_var, fabric_mod_name):
buf += " .fabric_drop_wwn = " + fabric_mod_name + "_drop_" + fabric_mod_port + ",\n"
buf += " .fabric_make_tpg = " + fabric_mod_name + "_make_tpg,\n"
buf += " .fabric_drop_tpg = " + fabric_mod_name + "_drop_tpg,\n"
- buf += "\n"
- buf += " .tfc_wwn_attrs = " + fabric_mod_name + "_wwn_attrs,\n"
buf += "};\n\n"
buf += "static int __init " + fabric_mod_name + "_init(void)\n"
diff --git a/Documentation/trace/events-msr.txt b/Documentation/trace/events-msr.txt
new file mode 100644
index 0000000..78c383b
--- /dev/null
+++ b/Documentation/trace/events-msr.txt
@@ -0,0 +1,37 @@
+
+The x86 kernel supports tracing most MSR (Model Specific Register) accesses.
+To see the definition of the MSRs on Intel systems please see the SDM
+at http://www.intel.com/sdm (Volume 3)
+
+Available trace points:
+
+/sys/kernel/debug/tracing/events/msr/
+
+Trace MSR reads
+
+read_msr
+
+msr: MSR number
+val: Value written
+failed: 1 if the access failed, otherwise 0
+
+
+Trace MSR writes
+
+write_msr
+
+msr: MSR number
+val: Value written
+failed: 1 if the access failed, otherwise 0
+
+
+Trace RDPMC in kernel
+
+rdpmc
+
+The trace data can be post processed with the postprocess/decode_msr.py script
+
+cat /sys/kernel/debug/tracing/trace | decode_msr.py /usr/src/linux/include/asm/msr-index.h
+
+to add symbolic MSR names.
+
diff --git a/Documentation/trace/postprocess/decode_msr.py b/Documentation/trace/postprocess/decode_msr.py
new file mode 100644
index 0000000..0ab40e0
--- /dev/null
+++ b/Documentation/trace/postprocess/decode_msr.py
@@ -0,0 +1,37 @@
+#!/usr/bin/python
+# add symbolic names to read_msr / write_msr in trace
+# decode_msr msr-index.h < trace
+import sys
+import re
+
+msrs = dict()
+
+with open(sys.argv[1] if len(sys.argv) > 1 else "msr-index.h", "r") as f:
+ for j in f:
+ m = re.match(r'#define (MSR_\w+)\s+(0x[0-9a-fA-F]+)', j)
+ if m:
+ msrs[int(m.group(2), 16)] = m.group(1)
+
+extra_ranges = (
+ ( "MSR_LASTBRANCH_%d_FROM_IP", 0x680, 0x69F ),
+ ( "MSR_LASTBRANCH_%d_TO_IP", 0x6C0, 0x6DF ),
+ ( "LBR_INFO_%d", 0xdc0, 0xddf ),
+)
+
+for j in sys.stdin:
+ m = re.search(r'(read|write)_msr:\s+([0-9a-f]+)', j)
+ if m:
+ r = None
+ num = int(m.group(2), 16)
+ if num in msrs:
+ r = msrs[num]
+ else:
+ for er in extra_ranges:
+ if er[1] <= num <= er[2]:
+ r = er[0] % (num - er[1],)
+ break
+ if r:
+ j = j.replace(" " + m.group(2), " " + r + "(" + m.group(2) + ")")
+ print j,
+
+
diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html
index 256f8ef..eaf948c 100644
--- a/Documentation/video4linux/API.html
+++ b/Documentation/video4linux/API.html
@@ -9,7 +9,7 @@
<table border="0">
<tr>
<td>
- <a href="http://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
+ <a href="https://linuxtv.org/downloads/legacy/video4linux/API/V4L1_API.html">V4L original API</a>
</td>
<td>
Obsoleted by V4L2 API
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 9e57ce4..6720999 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -41,8 +41,8 @@
40 -> Plextor ConvertX PX-TV100U (em2861) [093b:a005]
41 -> Kworld 350 U DVB-T (em2870) [eb1a:e350]
42 -> Kworld 355 U DVB-T (em2870) [eb1a:e355,eb1a:e357,eb1a:e359]
- 43 -> Terratec Cinergy T XS (em2870) [0ccd:0043]
- 44 -> Terratec Cinergy T XS (MT2060) (em2870)
+ 43 -> Terratec Cinergy T XS (em2870)
+ 44 -> Terratec Cinergy T XS (MT2060) (em2870) [0ccd:0043]
45 -> Pinnacle PCTV DVB-T (em2870)
46 -> Compro, VideoMate U3 (em2870) [185b:2870]
47 -> KWorld DVB-T 305U (em2880) [eb1a:e305]
diff --git a/Documentation/video4linux/fimc.txt b/Documentation/video4linux/fimc.txt
index e0c6b8b..4fab231b 100644
--- a/Documentation/video4linux/fimc.txt
+++ b/Documentation/video4linux/fimc.txt
@@ -58,7 +58,7 @@ Not currently supported:
4.1. Media device interface
The driver supports Media Controller API as defined at
-http://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
+https://linuxtv.org/downloads/v4l-dvb-apis/media_common.html
The media device driver name is "SAMSUNG S5P FIMC".
The purpose of this interface is to allow changing assignment of FIMC instances
@@ -83,11 +83,11 @@ undefined behaviour.
4.3. Capture video node
The driver supports V4L2 Video Capture Interface as defined at:
-http://linuxtv.org/downloads/v4l-dvb-apis/devices.html
+https://linuxtv.org/downloads/v4l-dvb-apis/devices.html
At the capture and mem-to-mem video nodes only the multi-planar API is
supported. For more details see:
-http://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
+https://linuxtv.org/downloads/v4l-dvb-apis/planar-apis.html
4.4. Camera capture subdevs
diff --git a/Documentation/video4linux/omap4_camera.txt b/Documentation/video4linux/omap4_camera.txt
index 25d9b40..a6734aa 100644
--- a/Documentation/video4linux/omap4_camera.txt
+++ b/Documentation/video4linux/omap4_camera.txt
@@ -47,7 +47,7 @@ Tested platforms
File list
---------
drivers/staging/media/omap4iss/
-include/media/omap4iss.h
+include/linux/platform_data/media/omap4iss.h
References
----------
diff --git a/Documentation/video4linux/si4713.txt b/Documentation/video4linux/si4713.txt
index 2e7392a..2ddc6b0 100644
--- a/Documentation/video4linux/si4713.txt
+++ b/Documentation/video4linux/si4713.txt
@@ -157,7 +157,7 @@ int main (int argc, char *argv[])
}
The struct si4713_rnl and SI4713_IOC_MEASURE_RNL are defined under
-include/media/si4713.h.
+include/linux/platform_data/media/si4713.h.
Stereo/Mono and RDS subchannels
===============================
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
index 95ae828..79af0c0 100644
--- a/Documentation/video4linux/v4l2-pci-skeleton.c
+++ b/Documentation/video4linux/v4l2-pci-skeleton.c
@@ -163,11 +163,10 @@ static irqreturn_t skeleton_irq(int irq, void *dev_id)
* minimum number: many DMA engines need a minimum of 2 buffers in the
* queue and you need to have another available for userspace processing.
*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct skeleton *skel = vb2_get_drv_priv(vq);
skel->field = skel->format.field;
@@ -183,12 +182,12 @@ static int queue_setup(struct vb2_queue *vq, const void *parg,
if (vq->num_buffers + *nbuffers < 3)
*nbuffers = 3 - vq->num_buffers;
+ alloc_ctxs[0] = skel->alloc_ctx;
- if (fmt && fmt->fmt.pix.sizeimage < skel->format.sizeimage)
- return -EINVAL;
+ if (*nplanes)
+ return sizes[0] < skel->format.sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : skel->format.sizeimage;
- alloc_ctxs[0] = skel->alloc_ctx;
+ sizes[0] = skel->format.sizeimage;
return 0;
}
@@ -509,7 +508,7 @@ static int skeleton_s_dv_timings(struct file *file, void *_fh,
return -EINVAL;
/* Return 0 if the new timings are the same as the current timings. */
- if (v4l2_match_dv_timings(timings, &skel->timings, 0))
+ if (v4l2_match_dv_timings(timings, &skel->timings, 0, false))
return 0;
/*
diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
index 092ee9f..053f613 100644
--- a/Documentation/virtual/kvm/api.txt
+++ b/Documentation/virtual/kvm/api.txt
@@ -1451,6 +1451,7 @@ struct kvm_irq_routing_entry {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
struct kvm_irq_routing_s390_adapter adapter;
+ struct kvm_irq_routing_hv_sint hv_sint;
__u32 pad[8];
} u;
};
@@ -1459,6 +1460,7 @@ struct kvm_irq_routing_entry {
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
#define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
No flags are specified so far, the corresponding field must be set to zero.
@@ -1482,6 +1484,10 @@ struct kvm_irq_routing_s390_adapter {
__u32 adapter_id;
};
+struct kvm_irq_routing_hv_sint {
+ __u32 vcpu;
+ __u32 sint;
+};
4.53 KVM_ASSIGN_SET_MSIX_NR (deprecated)
@@ -3331,6 +3337,28 @@ the userspace IOAPIC should process the EOI and retrigger the interrupt if
it is still asserted. Vector is the LAPIC interrupt vector for which the
EOI was received.
+ struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC 1
+ __u32 type;
+ union {
+ struct {
+ __u32 msr;
+ __u64 control;
+ __u64 evt_page;
+ __u64 msg_page;
+ } synic;
+ } u;
+ };
+ /* KVM_EXIT_HYPERV */
+ struct kvm_hyperv_exit hyperv;
+Indicates that the VCPU exits into userspace to process some tasks
+related to Hyper-V emulation.
+Valid values for 'type' are:
+ KVM_EXIT_HYPERV_SYNIC -- synchronously notify user-space about
+Hyper-V SynIC state change. Notification is used to remap SynIC
+event/message pages and to enable/disable SynIC messages/events processing
+in userspace.
+
/* Fix the size of the union. */
char padding[256];
};
@@ -3685,3 +3713,16 @@ available, means that that the kernel has an implementation of the
H_RANDOM hypercall backed by a hardware random-number generator.
If present, the kernel H_RANDOM handler can be enabled for guest use
with the KVM_CAP_PPC_ENABLE_HCALL capability.
+
+8.2 KVM_CAP_HYPERV_SYNIC
+
+Architectures: x86
+This capability, if KVM_CHECK_EXTENSION indicates that it is
+available, means that that the kernel has an implementation of the
+Hyper-V Synthetic interrupt controller(SynIC). Hyper-V SynIC is
+used to support Windows Hyper-V based guest paravirt drivers(VMBus).
+
+In order to use SynIC, it has to be activated by setting this
+capability via KVM_ENABLE_CAP ioctl on the vcpu fd. Note that this
+will disable the use of APIC hardware virtualization even if supported
+by the CPU, as it's incompatible with SynIC auto-EOI behavior.
diff --git a/Documentation/virtual/kvm/devices/vm.txt b/Documentation/virtual/kvm/devices/vm.txt
index 2d09d1e..f083a16 100644
--- a/Documentation/virtual/kvm/devices/vm.txt
+++ b/Documentation/virtual/kvm/devices/vm.txt
@@ -37,7 +37,8 @@ Returns: -EFAULT if the given address is not accessible
Allows userspace to query the actual limit and set a new limit for
the maximum guest memory size. The limit will be rounded up to
2048 MB, 4096 GB, 8192 TB respectively, as this limit is governed by
-the number of page table levels.
+the number of page table levels. In the case that there is no limit we will set
+the limit to KVM_S390_NO_MEM_LIMIT (U64_MAX).
2. GROUP: KVM_S390_VM_CPU_MODEL
Architectures: s390
diff --git a/Documentation/virtual/kvm/mmu.txt b/Documentation/virtual/kvm/mmu.txt
index 3a4d681..daf9c0f 100644
--- a/Documentation/virtual/kvm/mmu.txt
+++ b/Documentation/virtual/kvm/mmu.txt
@@ -203,10 +203,10 @@ Shadow pages contain the following information:
page cannot be destroyed. See role.invalid.
parent_ptes:
The reverse mapping for the pte/ptes pointing at this page's spt. If
- parent_ptes bit 0 is zero, only one spte points at this pages and
+ parent_ptes bit 0 is zero, only one spte points at this page and
parent_ptes points at this single spte, otherwise, there exists multiple
sptes pointing at this page and (parent_ptes & ~0x1) points at a data
- structure with a list of parent_ptes.
+ structure with a list of parent sptes.
unsync:
If true, then the translations in this page may not match the guest's
translation. This is equivalent to the state of the tlb when a pte is
diff --git a/MAINTAINERS b/MAINTAINERS
index 1a73c20..e99a7b3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -206,7 +206,7 @@ F: include/trace/events/9p.h
A8293 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -318,7 +318,7 @@ M: Zhang Rui <rui.zhang@intel.com>
L: linux-acpi@vger.kernel.org
W: https://01.org/linux-acpi
S: Supported
-F: drivers/acpi/video.c
+F: drivers/acpi/acpi_video.c
ACPI WMI DRIVER
L: platform-driver-x86@vger.kernel.org
@@ -395,7 +395,7 @@ M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/adp1653.c
-F: include/media/adp1653.h
+F: include/media/i2c/adp1653.h
ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
M: Michael Hennerich <michael.hennerich@analog.com>
@@ -466,7 +466,7 @@ F: sound/oss/aedsp16.c
AF9013 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -476,7 +476,7 @@ F: drivers/media/dvb-frontends/af9013*
AF9033 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -522,7 +522,7 @@ AIMSLAB FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-aimslab*
@@ -536,7 +536,7 @@ F: include/linux/*aio*.h
AIRSPY MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -614,9 +614,9 @@ F: drivers/crypto/ccp/
F: include/linux/ccp.h
AMD FAM15H PROCESSOR POWER MONITORING DRIVER
-M: Andreas Herrmann <herrmann.der.user@googlemail.com>
+M: Huang Rui <ray.huang@amd.com>
L: lm-sensors@lm-sensors.org
-S: Maintained
+S: Supported
F: Documentation/hwmon/fam15h_power
F: drivers/hwmon/fam15h_power.c
@@ -789,6 +789,11 @@ S: Maintained
F: drivers/net/appletalk/
F: net/appletalk/
+APPLIED MICRO (APM) X-GENE DEVICE TREE SUPPORT
+M: Duc Dang <dhdang@apm.com>
+S: Supported
+F: arch/arm64/boot/dts/apm/
+
APPLIED MICRO (APM) X-GENE SOC ETHERNET DRIVER
M: Iyappan Subramanian <isubramanian@apm.com>
M: Keyur Chudgar <kchudgar@apm.com>
@@ -920,7 +925,7 @@ M: Tsahee Zidenberg <tsahee@annapurnalabs.com>
S: Maintained
F: arch/arm/mach-alpine/
-ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
+ARM/ATMEL AT91RM9200, AT91SAM9 AND SAMA5 SOC SUPPORT
M: Nicolas Ferre <nicolas.ferre@atmel.com>
M: Alexandre Belloni <alexandre.belloni@free-electrons.com>
M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
@@ -1233,6 +1238,13 @@ ARM/LPC18XX ARCHITECTURE
M: Joachim Eastwood <manabian@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+F: arch/arm/boot/dts/lpc43*
+F: drivers/clk/nxp/clk-lpc18xx*
+F: drivers/clocksource/time-lpc32xx.c
+F: drivers/i2c/busses/i2c-lpc2k.c
+F: drivers/memory/pl172.c
+F: drivers/mtd/spi-nor/nxp-spifi.c
+F: drivers/rtc/rtc-lpc24xx.c
N: lpc18xx
ARM/MAGICIAN MACHINE SUPPORT
@@ -1455,6 +1467,10 @@ F: drivers/*/*s3c2410*
F: drivers/*/*/*s3c2410*
F: drivers/spi/spi-s3c*
F: sound/soc/samsung/*
+F: Documentation/arm/Samsung/
+F: Documentation/devicetree/bindings/arm/samsung/
+F: Documentation/devicetree/bindings/sram/samsung-sram.txt
+F: Documentation/devicetree/bindings/power/pd-samsung.txt
N: exynos
ARM/SAMSUNG MOBILE MACHINE SUPPORT
@@ -1509,8 +1525,6 @@ F: arch/arm/boot/dts/emev2*
F: arch/arm/boot/dts/r7s*
F: arch/arm/boot/dts/r8a*
F: arch/arm/boot/dts/sh*
-F: arch/arm/configs/bockw_defconfig
-F: arch/arm/configs/marzen_defconfig
F: arch/arm/configs/shmobile_defconfig
F: arch/arm/include/debug/renesas-scif.S
F: arch/arm/mach-shmobile/
@@ -1625,7 +1639,10 @@ M: Masahiro Yamada <yamada.masahiro@socionext.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/boot/dts/uniphier*
+F: arch/arm/include/asm/hardware/cache-uniphier.h
F: arch/arm/mach-uniphier/
+F: arch/arm/mm/cache-uniphier.c
+F: drivers/i2c/busses/i2c-uniphier*
F: drivers/pinctrl/uniphier/
F: drivers/tty/serial/8250/8250_uniphier.c
N: uniphier
@@ -1756,7 +1773,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/as3645a.c
-F: include/media/as3645a.h
+F: include/media/i2c/as3645a.h
ASC7621 HARDWARE MONITOR DRIVER
M: George Joseph <george.joseph@fairview5.com>
@@ -1830,7 +1847,7 @@ S: Supported
F: drivers/net/wireless/ath/ath6kl/
WILOCITY WIL6210 WIRELESS DRIVER
-M: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
+M: Maya Erez <qca_merez@qca.qualcomm.com>
L: linux-wireless@vger.kernel.org
L: wil6210@qca.qualcomm.com
S: Supported
@@ -1879,7 +1896,6 @@ ATMEL AT91 / AT32 MCI DRIVER
M: Ludovic Desroches <ludovic.desroches@atmel.com>
S: Maintained
F: drivers/mmc/host/atmel-mci.c
-F: drivers/mmc/host/atmel-mci-regs.h
ATMEL AT91 / AT32 SERIAL DRIVER
M: Nicolas Ferre <nicolas.ferre@atmel.com>
@@ -1914,7 +1930,7 @@ S: Supported
F: drivers/i2c/busses/i2c-at91.c
ATMEL ISI DRIVER
-M: Josh Wu <josh.wu@atmel.com>
+M: Ludovic Desroches <ludovic.desroches@atmel.com>
L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/platform/soc_camera/atmel-isi.c
@@ -1933,7 +1949,8 @@ S: Supported
F: drivers/net/ethernet/cadence/
ATMEL NAND DRIVER
-M: Josh Wu <josh.wu@atmel.com>
+M: Wenyou Yang <wenyou.yang@atmel.com>
+M: Josh Wu <rainyfeeling@outlook.com>
L: linux-mtd@lists.infradead.org
S: Supported
F: drivers/mtd/nand/atmel_nand*
@@ -2046,7 +2063,7 @@ F: net/ax25/
AZ6007 DVB DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/usb/dvb-usb-v2/az6007.c
@@ -2055,7 +2072,7 @@ AZTECH FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-aztech*
@@ -2108,7 +2125,7 @@ BDISP ST MEDIA DRIVER
M: Fabien Dessenne <fabien.dessenne@st.com>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Supported
F: drivers/media/platform/sti/bdisp
@@ -2193,6 +2210,7 @@ F: drivers/leds/leds-blinkm.c
BLOCK LAYER
M: Jens Axboe <axboe@kernel.dk>
+L: linux-block@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux-block.git
S: Maintained
F: block/
@@ -2387,19 +2405,27 @@ L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bnx2i/
-BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+BROADCOM IPROC ARM ARCHITECTURE
M: Ray Jui <rjui@broadcom.com>
M: Scott Branden <sbranden@broadcom.com>
+M: Jon Mason <jonmason@broadcom.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: bcm-kernel-feedback-list@broadcom.com
T: git git://github.com/broadcom/cygnus-linux.git
S: Maintained
N: iproc
N: cygnus
+N: nsp
N: bcm9113*
N: bcm9583*
-N: bcm583*
+N: bcm9585*
+N: bcm9586*
+N: bcm988312
N: bcm113*
+N: bcm583*
+N: bcm585*
+N: bcm586*
+N: bcm88312
BROADCOM BRCMSTB GPIO DRIVER
M: Gregory Fong <gregory.0xf0@gmail.com>
@@ -2423,7 +2449,9 @@ F: drivers/firmware/broadcom/*
BROADCOM STB NAND FLASH DRIVER
M: Brian Norris <computersforpeace@gmail.com>
+M: Kamal Dasu <kdasu.kdev@gmail.com>
L: linux-mtd@lists.infradead.org
+L: bcm-kernel-feedback-list@broadcom.com
S: Maintained
F: drivers/mtd/nand/brcmnand/
@@ -2490,7 +2518,7 @@ F: fs/btrfs/
BTTV VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: Documentation/video4linux/bttv/
@@ -2520,7 +2548,7 @@ F: arch/c6x/
CACHEFILES: FS-CACHE BACKEND FOR CACHING ON MOUNTED FILESYSTEMS
M: David Howells <dhowells@redhat.com>
-L: linux-cachefs@redhat.com
+L: linux-cachefs@redhat.com (moderated for non-subscribers)
S: Supported
F: Documentation/filesystems/caching/cachefiles.txt
F: fs/cachefiles/
@@ -2529,7 +2557,7 @@ CADET FM/AM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-cadet*
@@ -2822,7 +2850,7 @@ COBALT MEDIA DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Supported
F: drivers/media/pci/cobalt/
@@ -2903,10 +2931,9 @@ S: Maintained
F: drivers/platform/x86/compal-laptop.c
CONEXANT ACCESSRUNNER USB DRIVER
-M: Simon Arlott <cxacru@fire.lp0.eu>
L: accessrunner-general@lists.sourceforge.net
W: http://accessrunner.sourceforge.net/
-S: Maintained
+S: Orphan
F: drivers/usb/atm/cxacru.c
CONFIGFS
@@ -2947,6 +2974,7 @@ F: kernel/cpuset.c
CONTROL GROUP - MEMORY RESOURCE CONTROLLER (MEMCG)
M: Johannes Weiner <hannes@cmpxchg.org>
M: Michal Hocko <mhocko@kernel.org>
+M: Vladimir Davydov <vdavydov@virtuozzo.com>
L: cgroups@vger.kernel.org
L: linux-mm@kvack.org
S: Maintained
@@ -3067,6 +3095,15 @@ S: Maintained
F: crypto/ansi_cprng.c
F: crypto/rng.c
+CS3308 MEDIA DRIVER
+M: Hans Verkuil <hverkuil@xs4all.nl>
+L: linux-media@vger.kernel.org
+T: git git://linuxtv.org/media_tree.git
+W: http://linuxtv.org
+S: Odd Fixes
+F: drivers/media/i2c/cs3308.c
+F: drivers/media/i2c/cs3308.h
+
CS5535 Audio ALSA driver
M: Jaya Kumar <jayakumar.alsa@gmail.com>
S: Maintained
@@ -3082,7 +3119,7 @@ M: Andy Walls <awalls@md.metrocast.net>
L: ivtv-devel@ivtvdriver.org (subscribers-only)
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
W: http://www.ivtvdriver.org/index.php/Cx18
S: Maintained
F: Documentation/video4linux/cx18.txt
@@ -3093,7 +3130,7 @@ CX2341X MPEG ENCODER HELPER MODULE
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/common/cx2341x*
F: include/media/cx2341x*
@@ -3102,7 +3139,7 @@ CX24120 MEDIA DRIVER
M: Jemma Denson <jdenson@gmail.com>
M: Patrick Boettcher <patrick.boettcher@posteo.de>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/cx24120*
@@ -3110,7 +3147,7 @@ F: drivers/media/dvb-frontends/cx24120*
CX88 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: Documentation/video4linux/cx88/
@@ -3119,7 +3156,7 @@ F: drivers/media/pci/cx88/
CXD2820R MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3225,7 +3262,7 @@ F: drivers/net/wan/pc300*
CYPRESS_FIRMWARE MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3732,14 +3769,14 @@ DT3155 MEDIA DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/pci/dt3155/
DVB_USB_AF9015 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3749,7 +3786,7 @@ F: drivers/media/usb/dvb-usb-v2/af9015*
DVB_USB_AF9035 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3759,7 +3796,7 @@ F: drivers/media/usb/dvb-usb-v2/af9035*
DVB_USB_ANYSEE MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3769,7 +3806,7 @@ F: drivers/media/usb/dvb-usb-v2/anysee*
DVB_USB_AU6610 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3779,7 +3816,7 @@ F: drivers/media/usb/dvb-usb-v2/au6610*
DVB_USB_CE6230 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3789,7 +3826,7 @@ F: drivers/media/usb/dvb-usb-v2/ce6230*
DVB_USB_CXUSB MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/media_tree.git
@@ -3799,7 +3836,7 @@ F: drivers/media/usb/dvb-usb/cxusb*
DVB_USB_EC168 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3809,7 +3846,7 @@ F: drivers/media/usb/dvb-usb-v2/ec168*
DVB_USB_GL861 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
S: Maintained
@@ -3818,7 +3855,7 @@ F: drivers/media/usb/dvb-usb-v2/gl861*
DVB_USB_MXL111SF MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/mxl111sf.git
@@ -3828,7 +3865,7 @@ F: drivers/media/usb/dvb-usb-v2/mxl111sf*
DVB_USB_RTL28XXU MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3838,7 +3875,7 @@ F: drivers/media/usb/dvb-usb-v2/rtl28xxu*
DVB_USB_V2 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3868,7 +3905,7 @@ F: Documentation/devicetree/bindings/input/e3x0-button.txt
E4000 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3884,7 +3921,7 @@ F: drivers/scsi/eata.c
EC100 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -3905,9 +3942,8 @@ M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
-T: git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git#for-next
-T: git://git.kernel.org/pub/linux/kernel/git/mchehab/linux-edac.git#linux_next
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp.git for-next
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac.git linux_next
S: Supported
F: Documentation/edac.txt
F: drivers/edac/
@@ -3917,7 +3953,6 @@ EDAC-AMD64
M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/amd64_edac*
@@ -3925,7 +3960,6 @@ EDAC-CALXEDA
M: Doug Thompson <dougthompson@xmission.com>
M: Robert Richter <rric@kernel.org>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/highbank*
@@ -3934,7 +3968,6 @@ M: Ralf Baechle <ralf@linux-mips.org>
M: David Daney <david.daney@cavium.com>
L: linux-edac@vger.kernel.org
L: linux-mips@linux-mips.org
-W: bluesmoke.sourceforge.net
S: Supported
F: drivers/edac/octeon_edac*
@@ -3942,63 +3975,54 @@ EDAC-E752X
M: Mark Gross <mark.gross@intel.com>
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e752x_edac.c
EDAC-E7XXX
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/e7xxx_edac.c
EDAC-GHES
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/ghes_edac.c
EDAC-I82443BXGX
M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82443bxgx_edac.c
EDAC-I3000
M: Jason Uhlenkott <juhlenko@akamai.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i3000_edac.c
EDAC-I5000
M: Doug Thompson <dougthompson@xmission.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I7300
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7300_edac.c
EDAC-I7CORE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7core_edac.c
@@ -4006,42 +4030,36 @@ EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com>
M: "Arvind R." <arvino55@gmail.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i82975x_edac.c
EDAC-IE31200
M: Jason Baron <jbaron@akamai.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/ie31200_edac.c
EDAC-MPC85XX
M: Johannes Thumshirn <morbidrsa@gmail.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/mpc85xx_edac.[ch]
EDAC-PASEMI
M: Egor Martovetsky <egor@pasemi.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/pasemi_edac.c
EDAC-R82600
M: Tim Small <tim@buttersideup.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
-W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/sb_edac.c
@@ -4108,7 +4126,7 @@ F: drivers/net/ethernet/ibm/ehea/
EM28XX VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/usb/em28xx/
@@ -4248,7 +4266,7 @@ F: drivers/media/tuners/fc0011.c
FC2580 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -4383,6 +4401,7 @@ K: fmc_d.*register
FPGA MANAGER FRAMEWORK
M: Alan Tull <atull@opensource.altera.com>
+R: Moritz Fischer <moritz.fischer@ettus.com>
S: Maintained
F: drivers/fpga/
F: include/linux/fpga/fpga-mgr.h
@@ -4533,7 +4552,7 @@ F: include/linux/frontswap.h
FS-CACHE: LOCAL CACHING FOR NETWORK FILESYSTEMS
M: David Howells <dhowells@redhat.com>
-L: linux-cachefs@redhat.com
+L: linux-cachefs@redhat.com (moderated for non-subscribers)
S: Supported
F: Documentation/filesystems/caching/
F: fs/fscache/
@@ -4570,7 +4589,7 @@ M: Heungjun Kim <riverful.kim@samsung.com>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/m5mols/
-F: include/media/m5mols.h
+F: include/media/i2c/m5mols.h
FUJITSU TABLET EXTRAS
M: Robert Gerlach <khnz@gmx.de>
@@ -4616,7 +4635,7 @@ GEMTEK FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-gemtek*
@@ -4824,7 +4843,7 @@ HDPVR USB VIDEO ENCODER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/usb/hdpvr/
@@ -4843,7 +4862,7 @@ F: drivers/tty/hvc/
HACKRF MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -4886,7 +4905,7 @@ F: sound/parisc/harmony.*
HD29L2 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -5163,6 +5182,7 @@ S: Maintained
F: Documentation/devicetree/bindings/i2c/
F: Documentation/i2c/
F: drivers/i2c/
+F: drivers/i2c/*/
F: include/linux/i2c.h
F: include/linux/i2c-*.h
F: include/uapi/linux/i2c.h
@@ -5479,7 +5499,8 @@ S: Supported
F: drivers/idle/intel_idle.c
INTEL PSTATE DRIVER
-M: Kristen Carlson Accardi <kristen@linux.intel.com>
+M: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
+M: Len Brown <lenb@kernel.org>
L: linux-pm@vger.kernel.org
S: Supported
F: drivers/cpufreq/intel_pstate.c
@@ -5546,7 +5567,7 @@ R: Jesse Brandeburg <jesse.brandeburg@intel.com>
R: Shannon Nelson <shannon.nelson@intel.com>
R: Carolyn Wyborny <carolyn.wyborny@intel.com>
R: Don Skidmore <donald.c.skidmore@intel.com>
-R: Matthew Vick <matthew.vick@intel.com>
+R: Bruce Allan <bruce.w.allan@intel.com>
R: John Ronciak <john.ronciak@intel.com>
R: Mitch Williams <mitch.a.williams@intel.com>
L: intel-wired-lan@lists.osuosl.org
@@ -5590,9 +5611,7 @@ F: Documentation/trace/intel_th.txt
F: drivers/hwtracing/intel_th/
INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT)
-M: Richard L Maliszewski <richard.l.maliszewski@intel.com>
-M: Gang Wei <gang.wei@intel.com>
-M: Shane Wang <shane.wang@intel.com>
+M: Ning Sun <ning.sun@intel.com>
L: tboot-devel@lists.sourceforge.net
W: http://tboot.sourceforge.net
T: hg http://tboot.hg.sourceforge.net:8000/hgroot/tboot/tboot
@@ -5683,13 +5702,6 @@ M: Juanjo Ciarlante <jjciarla@raiz.uncu.edu.ar>
S: Maintained
F: net/ipv4/netfilter/ipt_MASQUERADE.c
-IP1000A 10/100/1000 GIGABIT ETHERNET DRIVER
-M: Francois Romieu <romieu@fr.zoreil.com>
-M: Sorbica Shieh <sorbica@icplus.com.tw>
-L: netdev@vger.kernel.org
-S: Maintained
-F: drivers/net/ethernet/icplus/ipg.*
-
IPATH DRIVER
M: Mike Marciniszyn <infinipath@intel.com>
L: linux-rdma@vger.kernel.org
@@ -5797,7 +5809,7 @@ ISA RADIO MODULE
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-isa*
@@ -5867,7 +5879,7 @@ F: drivers/hwmon/it87.c
IT913X MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -5888,7 +5900,7 @@ F: include/uapi/linux/ivtv*
IX2505V MEDIA DRIVER
M: Malcolm Priestley <tvboxspy@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/ix2505v*
@@ -5977,7 +5989,7 @@ KEENE FM RADIO TRANSMITTER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-keene*
@@ -6077,6 +6089,7 @@ M: Marc Zyngier <marc.zyngier@arm.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: kvmarm@lists.cs.columbia.edu
W: http://systems.cs.columbia.edu/projects/kvm-arm
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
S: Supported
F: arch/arm/include/uapi/asm/kvm*
F: arch/arm/include/asm/kvm*
@@ -6229,7 +6242,7 @@ F: drivers/usb/misc/legousbtower.c
LG2160 MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -6239,7 +6252,7 @@ F: drivers/media/dvb-frontends/lg2160.*
LGDT3305 MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -6343,6 +6356,7 @@ F: arch/*/include/asm/pmem.h
LIGHTNVM PLATFORM SUPPORT
M: Matias Bjorling <mb@lightnvm.io>
W: http://github/OpenChannelSSD
+L: linux-block@vger.kernel.org
S: Maintained
F: drivers/lightnvm/
F: include/linux/lightnvm.h
@@ -6495,7 +6509,7 @@ F: drivers/hwmon/lm95234.c
LME2510 MEDIA DRIVER
M: Malcolm Priestley <tvboxspy@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/usb/dvb-usb-v2/lmedm04*
@@ -6601,7 +6615,7 @@ F: arch/m68k/hp300/
M88DS3103 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -6611,7 +6625,7 @@ F: drivers/media/dvb-frontends/m88ds3103*
M88RS2000 MEDIA DRIVER
M: Malcolm Priestley <tvboxspy@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/m88rs2000*
@@ -6790,7 +6804,7 @@ MAXIRADIO FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-maxiradio*
@@ -6812,7 +6826,7 @@ F: drivers/media/platform/vsp1/
MEDIA DRIVERS FOR ASCOT2E
M: Sergey Kozlov <serjk@netup.ru>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
W: http://netup.tv/
T: git git://linuxtv.org/media_tree.git
S: Supported
@@ -6821,7 +6835,7 @@ F: drivers/media/dvb-frontends/ascot2e*
MEDIA DRIVERS FOR CXD2841ER
M: Sergey Kozlov <serjk@netup.ru>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://netup.tv/
T: git git://linuxtv.org/media_tree.git
S: Supported
@@ -6830,7 +6844,7 @@ F: drivers/media/dvb-frontends/cxd2841er*
MEDIA DRIVERS FOR HORUS3A
M: Sergey Kozlov <serjk@netup.ru>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://netup.tv/
T: git git://linuxtv.org/media_tree.git
S: Supported
@@ -6839,7 +6853,7 @@ F: drivers/media/dvb-frontends/horus3a*
MEDIA DRIVERS FOR LNBH25
M: Sergey Kozlov <serjk@netup.ru>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://netup.tv/
T: git git://linuxtv.org/media_tree.git
S: Supported
@@ -6848,7 +6862,7 @@ F: drivers/media/dvb-frontends/lnbh25*
MEDIA DRIVERS FOR NETUP PCI UNIVERSAL DVB devices
M: Sergey Kozlov <serjk@netup.ru>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://netup.tv/
T: git git://linuxtv.org/media_tree.git
S: Supported
@@ -6858,7 +6872,7 @@ MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
P: LinuxTV.org Project
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
Q: http://patchwork.kernel.org/project/linux-media/list/
T: git git://linuxtv.org/media_tree.git
S: Maintained
@@ -6867,6 +6881,7 @@ F: Documentation/video4linux/
F: Documentation/DocBook/media/
F: drivers/media/
F: drivers/staging/media/
+F: include/linux/platform_data/media/
F: include/media/
F: include/uapi/linux/dvb/
F: include/uapi/linux/videodev2.h
@@ -6895,13 +6910,21 @@ F: drivers/scsi/megaraid.*
F: drivers/scsi/megaraid/
MELLANOX ETHERNET DRIVER (mlx4_en)
-M: Amir Vadai <amirv@mellanox.com>
+M: Eugenia Emantayev <eugenia@mellanox.com>
L: netdev@vger.kernel.org
S: Supported
W: http://www.mellanox.com
Q: http://patchwork.ozlabs.org/project/netdev/list/
F: drivers/net/ethernet/mellanox/mlx4/en_*
+MELLANOX ETHERNET DRIVER (mlx5e)
+M: Saeed Mahameed <saeedm@mellanox.com>
+L: netdev@vger.kernel.org
+S: Supported
+W: http://www.mellanox.com
+Q: http://patchwork.ozlabs.org/project/netdev/list/
+F: drivers/net/ethernet/mellanox/mlx5/core/en_*
+
MELLANOX ETHERNET SWITCH DRIVERS
M: Jiri Pirko <jiri@mellanox.com>
M: Ido Schimmel <idosch@mellanox.com>
@@ -6968,7 +6991,7 @@ F: Documentation/hwmon/menf21bmc
METAG ARCHITECTURE
M: James Hogan <james.hogan@imgtec.com>
L: linux-metag@vger.kernel.org
-S: Supported
+S: Odd Fixes
F: arch/metag/
F: Documentation/metag/
F: Documentation/devicetree/bindings/metag/
@@ -7010,7 +7033,7 @@ MIROSOUND PCM20 FM RADIO RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/radio-miropcm20*
@@ -7046,7 +7069,7 @@ F: drivers/iio/temperature/mlx90614.c
MN88472 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -7057,7 +7080,7 @@ F: drivers/media/dvb-frontends/mn88472.h
MN88473 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -7112,7 +7135,7 @@ F: drivers/platform/x86/msi-wmi.c
MSI001 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -7122,7 +7145,7 @@ F: drivers/media/tuners/msi001*
MSI2500 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -7141,7 +7164,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/mt9m032.c
-F: include/media/mt9m032.h
+F: include/media/i2c/mt9m032.h
MT9P031 APTINA CAMERA SENSOR
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7149,7 +7172,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/mt9p031.c
-F: include/media/mt9p031.h
+F: include/media/i2c/mt9p031.h
MT9T001 APTINA CAMERA SENSOR
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7157,7 +7180,7 @@ L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/i2c/mt9t001.c
-F: include/media/mt9t001.h
+F: include/media/i2c/mt9t001.h
MT9V032 APTINA CAMERA SENSOR
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -7166,7 +7189,7 @@ T: git git://linuxtv.org/media_tree.git
S: Maintained
F: Documentation/devicetree/bindings/media/i2c/mt9v032.txt
F: drivers/media/i2c/mt9v032.c
-F: include/media/mt9v032.h
+F: include/media/i2c/mt9v032.h
MULTIFUNCTION DEVICES (MFD)
M: Lee Jones <lee.jones@linaro.org>
@@ -7210,7 +7233,7 @@ F: drivers/usb/musb/
MXL5007T MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -7873,6 +7896,18 @@ S: Maintained
F: net/openvswitch/
F: include/uapi/linux/openvswitch.h
+OPERATING PERFORMANCE POINTS (OPP)
+M: Viresh Kumar <vireshk@kernel.org>
+M: Nishanth Menon <nm@ti.com>
+M: Stephen Boyd <sboyd@codeaurora.org>
+L: linux-pm@vger.kernel.org
+S: Maintained
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm.git
+F: drivers/base/power/opp/
+F: include/linux/pm_opp.h
+F: Documentation/power/opp.txt
+F: Documentation/devicetree/bindings/opp/
+
OPL4 DRIVER
M: Clemens Ladisch <clemens@ladisch.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -8241,7 +8276,7 @@ F: include/linux/delayacct.h
F: kernel/delayacct.c
PERFORMANCE EVENTS SUBSYSTEM
-M: Peter Zijlstra <a.p.zijlstra@chello.nl>
+M: Peter Zijlstra <peterz@infradead.org>
M: Ingo Molnar <mingo@redhat.com>
M: Arnaldo Carvalho de Melo <acme@kernel.org>
L: linux-kernel@vger.kernel.org
@@ -8323,6 +8358,7 @@ F: drivers/pinctrl/intel/
PIN CONTROLLER - RENESAS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+M: Geert Uytterhoeven <geert+renesas@glider.be>
L: linux-sh@vger.kernel.org
S: Maintained
F: drivers/pinctrl/sh-pfc/
@@ -8334,6 +8370,14 @@ L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/pinctrl/samsung/
+PIN CONTROLLER - SINGLE
+M: Tony Lindgren <tony@atomide.com>
+M: Haojian Zhuang <haojian.zhuang@linaro.org>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: linux-omap@vger.kernel.org
+S: Maintained
+F: drivers/pinctrl/pinctrl-single.c
+
PIN CONTROLLER - ST SPEAR
M: Viresh Kumar <vireshk@kernel.org>
L: spear-devel@list.st.com
@@ -8418,12 +8462,6 @@ M: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
S: Maintained
F: drivers/pnp/
-PNXxxxx I2C DRIVER
-M: Vitaly Wool <vitalywool@gmail.com>
-L: linux-i2c@vger.kernel.org
-S: Maintained
-F: drivers/i2c/busses/i2c-pnx.c
-
PPP PROTOCOL DRIVERS AND COMPRESSORS
M: Paul Mackerras <paulus@samba.org>
L: linux-ppp@vger.kernel.org
@@ -8591,6 +8629,7 @@ S: Maintained
F: arch/arm/mach-pxa/
F: drivers/dma/pxa*
F: drivers/pcmcia/pxa2xx*
+F: drivers/pinctrl/pxa/
F: drivers/spi/spi-pxa2xx*
F: drivers/usb/gadget/udc/pxa2*
F: include/sound/pxa2xx-lib.h
@@ -8697,7 +8736,7 @@ F: include/uapi/linux/qnxtypes.h
QT1010 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -8906,6 +8945,13 @@ F: drivers/rpmsg/
F: Documentation/rpmsg.txt
F: include/linux/rpmsg.h
+RENESAS ETHERNET DRIVERS
+R: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>
+L: netdev@vger.kernel.org
+L: linux-sh@vger.kernel.org
+F: drivers/net/ethernet/renesas/
+F: include/linux/sh_eth.h
+
RESET CONTROLLER FRAMEWORK
M: Philipp Zabel <p.zabel@pengutronix.de>
S: Maintained
@@ -8983,7 +9029,7 @@ F: net/rose/
RTL2830 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -8993,7 +9039,7 @@ F: drivers/media/dvb-frontends/rtl2830*
RTL2832 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -9003,7 +9049,7 @@ F: drivers/media/dvb-frontends/rtl2832*
RTL2832_SDR MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -9134,14 +9180,14 @@ SAA6588 RDS RECEIVER DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/i2c/saa6588*
SAA7134 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: Documentation/video4linux/*.saa7134
@@ -9203,7 +9249,7 @@ L: linux-media@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
S: Maintained
F: drivers/media/platform/s3c-camif/
-F: include/media/s3c_camif.h
+F: include/media/drv-intf/s3c_camif.h
SAMSUNG S5C73M3 CAMERA DRIVER
M: Kyungmin Park <kyungmin.park@samsung.com>
@@ -9292,7 +9338,6 @@ F: drivers/i2c/busses/i2c-designware-*
F: include/linux/platform_data/i2c-designware.h
SYNOPSYS DESIGNWARE MMC/SD/SDIO DRIVER
-M: Seungwon Jeon <tgih.jun@samsung.com>
M: Jaehoon Chung <jh80.chung@samsung.com>
L: linux-mmc@vger.kernel.org
S: Maintained
@@ -9312,7 +9357,7 @@ M: Andreas Noever <andreas.noever@gmail.com>
S: Maintained
F: drivers/thunderbolt/
-TIMEKEEPING, CLOCKSOURCE CORE, NTP
+TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
M: John Stultz <john.stultz@linaro.org>
M: Thomas Gleixner <tglx@linutronix.de>
L: linux-kernel@vger.kernel.org
@@ -9325,6 +9370,7 @@ F: include/uapi/linux/time.h
F: include/uapi/linux/timex.h
F: kernel/time/clocksource.c
F: kernel/time/time*.c
+F: kernel/time/alarmtimer.c
F: kernel/time/ntp.c
F: tools/testing/selftests/timers/
@@ -9351,6 +9397,16 @@ W: http://www.sunplus.com
S: Supported
F: arch/score/
+SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers
+M: Sudeep Holla <sudeep.holla@arm.com>
+L: linux-arm-kernel@lists.infradead.org
+S: Maintained
+F: Documentation/devicetree/bindings/arm/arm,scpi.txt
+F: drivers/clk/clk-scpi.c
+F: drivers/cpufreq/scpi-cpufreq.c
+F: drivers/firmware/arm_scpi.c
+F: include/linux/scpi_protocol.h
+
SCSI CDROM DRIVER
M: Jens Axboe <axboe@kernel.dk>
L: linux-scsi@vger.kernel.org
@@ -9379,8 +9435,10 @@ F: include/scsi/sg.h
SCSI SUBSYSTEM
M: "James E.J. Bottomley" <JBottomley@odin.com>
-L: linux-scsi@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi.git
+M: "Martin K. Petersen" <martin.petersen@oracle.com>
+T: git git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git
+L: linux-scsi@vger.kernel.org
S: Maintained
F: drivers/scsi/
F: include/scsi/
@@ -9567,7 +9625,7 @@ F: drivers/misc/sgi-xp/
SI2157 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -9577,7 +9635,7 @@ F: drivers/media/tuners/si2157*
SI2168 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -9588,7 +9646,7 @@ SI470X FM RADIO RECEIVER I2C DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -9596,7 +9654,7 @@ SI470X FM RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/si470x/radio-si470x-common.c
F: drivers/media/radio/si470x/radio-si470x.h
@@ -9606,7 +9664,7 @@ SI4713 FM RADIO TRANSMITTER I2C DRIVER
M: Eduardo Valentin <edubezval@gmail.com>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/si4713/si4713.?
@@ -9614,7 +9672,7 @@ SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
M: Eduardo Valentin <edubezval@gmail.com>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/radio/si4713/radio-platform-si4713.c
@@ -9622,14 +9680,14 @@ SI4713 FM RADIO TRANSMITTER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/si4713/radio-usb-si4713.c
SIANO DVB DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: drivers/media/common/siano/
@@ -9654,7 +9712,7 @@ SH_VOU V4L2 OUTPUT DRIVER
L: linux-media@vger.kernel.org
S: Orphan
F: drivers/media/platform/sh_vou.c
-F: include/media/sh_vou.h
+F: include/media/drv-intf/sh_vou.h
SIMPLE FIRMWARE INTERFACE (SFI)
M: Len Brown <lenb@kernel.org>
@@ -9695,7 +9753,7 @@ F: drivers/i2c/busses/i2c-davinci.c
TI DAVINCI SERIES MEDIA DRIVER
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
S: Maintained
@@ -9705,7 +9763,7 @@ F: include/media/davinci/
TI AM437X VPFE DRIVER
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
S: Maintained
@@ -9714,12 +9772,12 @@ F: drivers/media/platform/am437x/
OV2659 OMNIVISION SENSOR DRIVER
M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git
S: Maintained
F: drivers/media/i2c/ov2659.c
-F: include/media/ov2659.h
+F: include/media/i2c/ov2659.h
SILICON MOTION SM712 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
@@ -9808,7 +9866,7 @@ M: Sakari Ailus <sakari.ailus@iki.fi>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/smiapp/
-F: include/media/smiapp.h
+F: include/media/i2c/smiapp.h
F: drivers/media/i2c/smiapp-pll.c
F: drivers/media/i2c/smiapp-pll.h
F: include/uapi/linux/smiapp.h
@@ -9972,7 +10030,7 @@ F: sound/soc/soc-generic-dmaengine-pcm.c
SP2 MEDIA DRIVER
M: Olli Salonen <olli.salonen@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
S: Maintained
F: drivers/media/dvb-frontends/sp2*
@@ -10268,7 +10326,7 @@ F: include/net/switchdev.h
SYNOPSYS ARC ARCHITECTURE
M: Vineet Gupta <vgupta@synopsys.com>
-L: linux-snps-arc@lists.infraded.org
+L: linux-snps-arc@lists.infradead.org
S: Supported
F: arch/arc/
F: Documentation/devicetree/bindings/arc/*
@@ -10334,7 +10392,7 @@ F: net/ipv4/tcp_lp.c
TDA10071 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -10344,7 +10402,7 @@ F: drivers/media/dvb-frontends/tda10071*
TDA18212 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -10354,7 +10412,7 @@ F: drivers/media/tuners/tda18212*
TDA18218 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -10364,7 +10422,7 @@ F: drivers/media/tuners/tda18218*
TDA18271 MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -10374,7 +10432,7 @@ F: drivers/media/tuners/tda18271*
TDA827x MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -10384,7 +10442,7 @@ F: drivers/media/tuners/tda8290.*
TDA8290 MEDIA DRIVER
M: Michael Krufky <mkrufky@linuxtv.org>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://github.com/mkrufky
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/mkrufky/tuners.git
@@ -10395,14 +10453,14 @@ TDA9840 MEDIA DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/i2c/tda9840*
TEA5761 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: drivers/media/tuners/tea5761.*
@@ -10410,7 +10468,7 @@ F: drivers/media/tuners/tea5761.*
TEA5767 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/tuners/tea5767.*
@@ -10419,7 +10477,7 @@ TEA6415C MEDIA DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/i2c/tea6415c*
@@ -10427,7 +10485,7 @@ TEA6420 MEDIA DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/i2c/tea6420*
@@ -10525,7 +10583,7 @@ THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/radio/radio-raremono.c
@@ -10749,7 +10807,7 @@ M: Mats Randgaard <matrandg@cisco.com>
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/i2c/tc358743*
-F: include/media/tc358743.h
+F: include/media/i2c/tc358743.h
TMIO MMC DRIVER
M: Ian Molton <ian@mnementh.co.uk>
@@ -10777,7 +10835,7 @@ F: mm/shmem.c
TM6000 VIDEO4LINUX DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Odd fixes
F: drivers/media/usb/tm6000/
@@ -10786,7 +10844,7 @@ TW68 VIDEO4LINUX DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/pci/tw68/
@@ -10847,7 +10905,7 @@ F: include/uapi/linux/tty.h
TUA9001 MEDIA DRIVER
M: Antti Palosaari <crope@iki.fi>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org/
+W: https://linuxtv.org
W: http://palosaari.fi/linux/
Q: http://patchwork.linuxtv.org/project/linux-media/list/
T: git git://linuxtv.org/anttip/media_tree.git
@@ -10855,9 +10913,9 @@ S: Maintained
F: drivers/media/tuners/tua9001*
TULIP NETWORK DRIVERS
-M: Grant Grundler <grundler@parisc-linux.org>
L: netdev@vger.kernel.org
-S: Maintained
+L: linux-parisc@vger.kernel.org
+S: Orphan
F: drivers/net/ethernet/dec/tulip/
TUN/TAP driver
@@ -11194,7 +11252,7 @@ USB VISION DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Odd Fixes
F: drivers/media/usb/usbvision/
@@ -11408,7 +11466,7 @@ VIVID VIRTUAL VIDEO DRIVER
M: Hans Verkuil <hverkuil@xs4all.nl>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
-W: http://linuxtv.org
+W: https://linuxtv.org
S: Maintained
F: drivers/media/platform/vivid/*
@@ -11697,7 +11755,7 @@ F: arch/x86/entry/vdso/
XC2028/3028 TUNER DRIVER
M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
-W: http://linuxtv.org
+W: https://linuxtv.org
T: git git://linuxtv.org/media_tree.git
S: Maintained
F: drivers/media/tuners/tuner-xc2028.*
@@ -11866,7 +11924,7 @@ ZR36067 VIDEO FOR LINUX DRIVER
L: mjpeg-users@lists.sourceforge.net
L: linux-media@vger.kernel.org
W: http://mjpeg.sourceforge.net/driver-zoran/
-T: hg http://linuxtv.org/hg/v4l-dvb
+T: hg https://linuxtv.org/hg/v4l-dvb
S: Odd Fixes
F: drivers/media/pci/zoran/
diff --git a/Makefile b/Makefile
index 69be581..70dea02 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
VERSION = 4
-PATCHLEVEL = 3
+PATCHLEVEL = 4
SUBLEVEL = 0
EXTRAVERSION =
NAME = Blurry Fish Butt
@@ -1077,6 +1077,9 @@ PHONY += kselftest
kselftest:
$(Q)$(MAKE) -C tools/testing/selftests run_tests
+kselftest-clean:
+ $(Q)$(MAKE) -C tools/testing/selftests clean
+
# ---------------------------------------------------------------------------
# Modules
@@ -1284,6 +1287,7 @@ help:
@echo ' kselftest - Build and run kernel selftest (run as root)'
@echo ' Build, install, and boot kernel before'
@echo ' running kselftest on it'
+ @echo ' kselftest-clean - Remove all generated kselftest files'
@echo ''
@echo 'Kernel packaging:'
@$(MAKE) $(build)=$(package-dir) help
diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig
index 2c2ac3f..6312f60 100644
--- a/arch/arc/Kconfig
+++ b/arch/arc/Kconfig
@@ -445,6 +445,7 @@ config LINUX_LINK_BASE
However some customers have peripherals mapped at this addr, so
Linux needs to be scooted a bit.
If you don't know what the above means, leave this setting alone.
+ This needs to match memory start address specified in Device Tree
config HIGHMEM
bool "High Memory Support"
diff --git a/arch/arc/Makefile b/arch/arc/Makefile
index cf0cf34..aeb1902 100644
--- a/arch/arc/Makefile
+++ b/arch/arc/Makefile
@@ -81,7 +81,7 @@ endif
LIBGCC := $(shell $(CC) $(cflags-y) --print-libgcc-file-name)
# Modules with short calls might break for calls into builtin-kernel
-KBUILD_CFLAGS_MODULE += -mlong-calls
+KBUILD_CFLAGS_MODULE += -mlong-calls -mno-millicode
# Finally dump eveything into kernel build system
KBUILD_CFLAGS += $(cflags-y)
diff --git a/arch/arc/boot/dts/axs10x_mb.dtsi b/arch/arc/boot/dts/axs10x_mb.dtsi
index f3db321..44a578c 100644
--- a/arch/arc/boot/dts/axs10x_mb.dtsi
+++ b/arch/arc/boot/dts/axs10x_mb.dtsi
@@ -46,6 +46,7 @@
snps,pbl = < 32 >;
clocks = <&apbclk>;
clock-names = "stmmaceth";
+ max-speed = <100>;
};
ehci@0x40000 {
diff --git a/arch/arc/boot/dts/nsim_hs.dts b/arch/arc/boot/dts/nsim_hs.dts
index b0eb0e7..fc81879 100644
--- a/arch/arc/boot/dts/nsim_hs.dts
+++ b/arch/arc/boot/dts/nsim_hs.dts
@@ -17,7 +17,8 @@
memory {
device_type = "memory";
- reg = <0x0 0x80000000 0x0 0x40000000 /* 1 GB low mem */
+ /* CONFIG_LINUX_LINK_BASE needs to match low mem start */
+ reg = <0x0 0x80000000 0x0 0x20000000 /* 512 MB low mem */
0x1 0x00000000 0x0 0x40000000>; /* 1 GB highmem */
};
diff --git a/arch/arc/configs/axs101_defconfig b/arch/arc/configs/axs101_defconfig
index c92c0ef..f1ac981 100644
--- a/arch/arc/configs/axs101_defconfig
+++ b/arch/arc/configs/axs101_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
diff --git a/arch/arc/configs/axs103_defconfig b/arch/arc/configs/axs103_defconfig
index cfac24e..323486d 100644
--- a/arch/arc/configs/axs103_defconfig
+++ b/arch/arc/configs/axs103_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
diff --git a/arch/arc/configs/axs103_smp_defconfig b/arch/arc/configs/axs103_smp_defconfig
index 9922a11..66191cd 100644
--- a/arch/arc/configs/axs103_smp_defconfig
+++ b/arch/arc/configs/axs103_smp_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
diff --git a/arch/arc/configs/nsim_hs_defconfig b/arch/arc/configs/nsim_hs_defconfig
index f761a7c..f68838e 100644
--- a/arch/arc/configs/nsim_hs_defconfig
+++ b/arch/arc/configs/nsim_hs_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
diff --git a/arch/arc/configs/nsim_hs_smp_defconfig b/arch/arc/configs/nsim_hs_smp_defconfig
index dc6f74f..96bd1c2 100644
--- a/arch/arc/configs/nsim_hs_smp_defconfig
+++ b/arch/arc/configs/nsim_hs_smp_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
diff --git a/arch/arc/configs/nsimosci_hs_defconfig b/arch/arc/configs/nsimosci_hs_defconfig
index 3fef0a2..fcae666 100644
--- a/arch/arc/configs/nsimosci_hs_defconfig
+++ b/arch/arc/configs/nsimosci_hs_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
diff --git a/arch/arc/configs/nsimosci_hs_smp_defconfig b/arch/arc/configs/nsimosci_hs_smp_defconfig
index 5178483..b01b659 100644
--- a/arch/arc/configs/nsimosci_hs_smp_defconfig
+++ b/arch/arc/configs/nsimosci_hs_smp_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
diff --git a/arch/arc/configs/vdk_hs38_defconfig b/arch/arc/configs/vdk_hs38_defconfig
index ef35ef3..a07f20d 100644
--- a/arch/arc/configs/vdk_hs38_defconfig
+++ b/arch/arc/configs/vdk_hs38_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_CROSS_MEMORY_ATTACH is not set
diff --git a/arch/arc/configs/vdk_hs38_smp_defconfig b/arch/arc/configs/vdk_hs38_smp_defconfig
index 634509e..f36c047 100644
--- a/arch/arc/configs/vdk_hs38_smp_defconfig
+++ b/arch/arc/configs/vdk_hs38_smp_defconfig
@@ -1,4 +1,4 @@
-CONFIG_CROSS_COMPILE="arc-linux-uclibc-"
+CONFIG_CROSS_COMPILE="arc-linux-"
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_DEFAULT_HOSTNAME="ARCLinux"
# CONFIG_CROSS_MEMORY_ATTACH is not set
diff --git a/arch/arc/include/asm/cache.h b/arch/arc/include/asm/cache.h
index abf06e8..210ef3e 100644
--- a/arch/arc/include/asm/cache.h
+++ b/arch/arc/include/asm/cache.h
@@ -62,9 +62,7 @@ extern int ioc_exists;
#define ARC_REG_IC_IVIC 0x10
#define ARC_REG_IC_CTRL 0x11
#define ARC_REG_IC_IVIL 0x19
-#if defined(CONFIG_ARC_MMU_V3) || defined(CONFIG_ARC_MMU_V4)
#define ARC_REG_IC_PTAG 0x1E
-#endif
#define ARC_REG_IC_PTAG_HI 0x1F
/* Bit val in IC_CTRL */
diff --git a/arch/arc/include/asm/irqflags-arcv2.h b/arch/arc/include/asm/irqflags-arcv2.h
index ad481c2..258b0e5 100644
--- a/arch/arc/include/asm/irqflags-arcv2.h
+++ b/arch/arc/include/asm/irqflags-arcv2.h
@@ -37,6 +37,9 @@
#define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \
(ARCV2_IRQ_DEF_PRIO << 1))
+/* SLEEP needs default irq priority (<=) which can interrupt the doze */
+#define ISA_SLEEP_ARG (0x10 | ARCV2_IRQ_DEF_PRIO)
+
#ifndef __ASSEMBLY__
/*
diff --git a/arch/arc/include/asm/irqflags-compact.h b/arch/arc/include/asm/irqflags-compact.h
index d8c6081..c1d3645 100644
--- a/arch/arc/include/asm/irqflags-compact.h
+++ b/arch/arc/include/asm/irqflags-compact.h
@@ -43,6 +43,8 @@
#define ISA_INIT_STATUS_BITS STATUS_IE_MASK
+#define ISA_SLEEP_ARG 0x3
+
#ifndef __ASSEMBLY__
/******************************************************************
diff --git a/arch/arc/include/asm/mach_desc.h b/arch/arc/include/asm/mach_desc.h
index 6ff657a..c28e6c3 100644
--- a/arch/arc/include/asm/mach_desc.h
+++ b/arch/arc/include/asm/mach_desc.h
@@ -23,7 +23,7 @@
* @dt_compat: Array of device tree 'compatible' strings
* (XXX: although only 1st entry is looked at)
* @init_early: Very early callback [called from setup_arch()]
- * @init_cpu_smp: for each CPU as it is coming up (SMP as well as UP)
+ * @init_per_cpu: for each CPU as it is coming up (SMP as well as UP)
* [(M):init_IRQ(), (o):start_kernel_secondary()]
* @init_machine: arch initcall level callback (e.g. populate static
* platform devices or parse Devicetree)
@@ -35,7 +35,7 @@ struct machine_desc {
const char **dt_compat;
void (*init_early)(void);
#ifdef CONFIG_SMP
- void (*init_cpu_smp)(unsigned int);
+ void (*init_per_cpu)(unsigned int);
#endif
void (*init_machine)(void);
void (*init_late)(void);
diff --git a/arch/arc/include/asm/processor.h b/arch/arc/include/asm/processor.h
index 4454535..1d694c1 100644
--- a/arch/arc/include/asm/processor.h
+++ b/arch/arc/include/asm/processor.h
@@ -57,11 +57,7 @@ struct task_struct;
* A lot of busy-wait loops in SMP are based off of non-volatile data otherwise
* get optimised away by gcc
*/
-#ifdef CONFIG_SMP
#define cpu_relax() __asm__ __volatile__ ("" : : : "memory")
-#else
-#define cpu_relax() do { } while (0)
-#endif
#define cpu_relax_lowlatency() cpu_relax()
diff --git a/arch/arc/include/asm/smp.h b/arch/arc/include/asm/smp.h
index 133c867..9913804 100644
--- a/arch/arc/include/asm/smp.h
+++ b/arch/arc/include/asm/smp.h
@@ -48,7 +48,7 @@ extern int smp_ipi_irq_setup(int cpu, int irq);
* @init_early_smp: A SMP specific h/w block can init itself
* Could be common across platforms so not covered by
* mach_desc->init_early()
- * @init_irq_cpu: Called for each core so SMP h/w block driver can do
+ * @init_per_cpu: Called for each core so SMP h/w block driver can do
* any needed setup per cpu (e.g. IPI request)
* @cpu_kick: For Master to kickstart a cpu (optionally at a PC)
* @ipi_send: To send IPI to a @cpu
@@ -57,7 +57,7 @@ extern int smp_ipi_irq_setup(int cpu, int irq);
struct plat_smp_ops {
const char *info;
void (*init_early_smp)(void);
- void (*init_irq_cpu)(int cpu);
+ void (*init_per_cpu)(int cpu);
void (*cpu_kick)(int cpu, unsigned long pc);
void (*ipi_send)(int cpu);
void (*ipi_clear)(int irq);
diff --git a/arch/arc/include/asm/unwind.h b/arch/arc/include/asm/unwind.h
index 7ca628b..c11a25b 100644
--- a/arch/arc/include/asm/unwind.h
+++ b/arch/arc/include/asm/unwind.h
@@ -112,7 +112,6 @@ struct unwind_frame_info {
extern int arc_unwind(struct unwind_frame_info *frame);
extern void arc_unwind_init(void);
-extern void arc_unwind_setup(void);
extern void *unwind_add_table(struct module *module, const void *table_start,
unsigned long table_size);
extern void unwind_remove_table(void *handle, int init_only);
@@ -152,9 +151,6 @@ static inline void arc_unwind_init(void)
{
}
-static inline void arc_unwind_setup(void)
-{
-}
#define unwind_add_table(a, b, c)
#define unwind_remove_table(a, b)
diff --git a/arch/arc/kernel/ctx_sw.c b/arch/arc/kernel/ctx_sw.c
index c14a5be..5d446df 100644
--- a/arch/arc/kernel/ctx_sw.c
+++ b/arch/arc/kernel/ctx_sw.c
@@ -58,8 +58,6 @@ __switch_to(struct task_struct *prev_task, struct task_struct *next_task)
"st sp, [r24] \n\t"
#endif
- "sync \n\t"
-
/*
* setup _current_task with incoming tsk.
* optionally, set r25 to that as well
diff --git a/arch/arc/kernel/ctx_sw_asm.S b/arch/arc/kernel/ctx_sw_asm.S
index e248594..e6890b1 100644
--- a/arch/arc/kernel/ctx_sw_asm.S
+++ b/arch/arc/kernel/ctx_sw_asm.S
@@ -44,9 +44,6 @@ __switch_to:
* don't need to do anything special to return it
*/
- /* hardware memory barrier */
- sync
-
/*
* switch to new task, contained in r1
* Temp reg r3 is required to get the ptr to store val
diff --git a/arch/arc/kernel/entry-arcv2.S b/arch/arc/kernel/entry-arcv2.S
index 445e63a..cbfec79 100644
--- a/arch/arc/kernel/entry-arcv2.S
+++ b/arch/arc/kernel/entry-arcv2.S
@@ -91,6 +91,25 @@ ENTRY(EV_DCError)
flag 1
END(EV_DCError)
+; ---------------------------------------------
+; Memory Error Exception Handler
+; - Unlike ARCompact, handles Bus errors for both User/Kernel mode,
+; Instruction fetch or Data access, under a single Exception Vector
+; ---------------------------------------------
+
+ENTRY(mem_service)
+
+ EXCEPTION_PROLOGUE
+
+ lr r0, [efa]
+ mov r1, sp
+
+ FAKE_RET_FROM_EXCPN
+
+ bl do_memory_error
+ b ret_from_exception
+END(mem_service)
+
ENTRY(EV_Misaligned)
EXCEPTION_PROLOGUE
diff --git a/arch/arc/kernel/entry-compact.S b/arch/arc/kernel/entry-compact.S
index 59f5203..4314339 100644
--- a/arch/arc/kernel/entry-compact.S
+++ b/arch/arc/kernel/entry-compact.S
@@ -142,16 +142,12 @@ int1_saved_reg:
.zero 4
/* Each Interrupt level needs its own scratch */
-#ifdef CONFIG_ARC_COMPACT_IRQ_LEVELS
-
ARCFP_DATA int2_saved_reg
.type int2_saved_reg, @object
.size int2_saved_reg, 4
int2_saved_reg:
.zero 4
-#endif
-
; ---------------------------------------------
.section .text, "ax",@progbits
@@ -216,6 +212,31 @@ END(handle_interrupt_level2)
#endif
; ---------------------------------------------
+; User Mode Memory Bus Error Interrupt Handler
+; (Kernel mode memory errors handled via seperate exception vectors)
+; ---------------------------------------------
+ENTRY(mem_service)
+
+ INTERRUPT_PROLOGUE 2
+
+ mov r0, ilink2
+ mov r1, sp
+
+ ; User process needs to be killed with SIGBUS, but first need to get
+ ; out of the L2 interrupt context (drop to pure kernel mode) and jump
+ ; off to "C" code where SIGBUS in enqueued
+ lr r3, [status32]
+ bclr r3, r3, STATUS_A2_BIT
+ or r3, r3, (STATUS_E1_MASK|STATUS_E2_MASK)
+ sr r3, [status32_l2]
+ mov ilink2, 1f
+ rtie
+1:
+ bl do_memory_error
+ b ret_from_exception
+END(mem_service)
+
+; ---------------------------------------------
; Level 1 ISR
; ---------------------------------------------
ENTRY(handle_interrupt_level1)
diff --git a/arch/arc/kernel/entry.S b/arch/arc/kernel/entry.S
index 589abf5..2efb062 100644
--- a/arch/arc/kernel/entry.S
+++ b/arch/arc/kernel/entry.S
@@ -93,23 +93,6 @@ ENTRY(instr_service)
END(instr_service)
; ---------------------------------------------
-; Memory Error Exception Handler
-; ---------------------------------------------
-
-ENTRY(mem_service)
-
- EXCEPTION_PROLOGUE
-
- lr r0, [efa]
- mov r1, sp
-
- FAKE_RET_FROM_EXCPN
-
- bl do_memory_error
- b ret_from_exception
-END(mem_service)
-
-; ---------------------------------------------
; Machine Check Exception Handler
; ---------------------------------------------
diff --git a/arch/arc/kernel/intc-arcv2.c b/arch/arc/kernel/intc-arcv2.c
index 26c1568..0394f9f 100644
--- a/arch/arc/kernel/intc-arcv2.c
+++ b/arch/arc/kernel/intc-arcv2.c
@@ -106,10 +106,21 @@ static struct irq_chip arcv2_irq_chip = {
static int arcv2_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
- if (irq == TIMER0_IRQ || irq == IPI_IRQ)
+ /*
+ * core intc IRQs [16, 23]:
+ * Statically assigned always private-per-core (Timers, WDT, IPI, PCT)
+ */
+ if (hw < 24) {
+ /*
+ * A subsequent request_percpu_irq() fails if percpu_devid is
+ * not set. That in turns sets NOAUTOEN, meaning each core needs
+ * to call enable_percpu_irq()
+ */
+ irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq);
- else
+ } else {
irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq);
+ }
return 0;
}
diff --git a/arch/arc/kernel/irq.c b/arch/arc/kernel/irq.c
index 2ee2265..ba17f85 100644
--- a/arch/arc/kernel/irq.c
+++ b/arch/arc/kernel/irq.c
@@ -29,11 +29,11 @@ void __init init_IRQ(void)
#ifdef CONFIG_SMP
/* a SMP H/w block could do IPI IRQ request here */
- if (plat_smp_ops.init_irq_cpu)
- plat_smp_ops.init_irq_cpu(smp_processor_id());
+ if (plat_smp_ops.init_per_cpu)
+ plat_smp_ops.init_per_cpu(smp_processor_id());
- if (machine_desc->init_cpu_smp)
- machine_desc->init_cpu_smp(smp_processor_id());
+ if (machine_desc->init_per_cpu)
+ machine_desc->init_per_cpu(smp_processor_id());
#endif
}
@@ -51,6 +51,18 @@ void arch_do_IRQ(unsigned int irq, struct pt_regs *regs)
set_irq_regs(old_regs);
}
+/*
+ * API called for requesting percpu interrupts - called by each CPU
+ * - For boot CPU, actually request the IRQ with genirq core + enables
+ * - For subsequent callers only enable called locally
+ *
+ * Relies on being called by boot cpu first (i.e. request called ahead) of
+ * any enable as expected by genirq. Hence Suitable only for TIMER, IPI
+ * which are guaranteed to be setup on boot core first.
+ * Late probed peripherals such as perf can't use this as there no guarantee
+ * of being called on boot CPU first.
+ */
+
void arc_request_percpu_irq(int irq, int cpu,
irqreturn_t (*isr)(int irq, void *dev),
const char *irq_nm,
@@ -60,14 +72,17 @@ void arc_request_percpu_irq(int irq, int cpu,
if (!cpu) {
int rc;
+#ifdef CONFIG_ISA_ARCOMPACT
/*
- * These 2 calls are essential to making percpu IRQ APIs work
- * Ideally these details could be hidden in irq chip map function
- * but the issue is IPIs IRQs being static (non-DT) and platform
- * specific, so we can't identify them there.
+ * A subsequent request_percpu_irq() fails if percpu_devid is
+ * not set. That in turns sets NOAUTOEN, meaning each core needs
+ * to call enable_percpu_irq()
+ *
+ * For ARCv2, this is done in irq map function since we know
+ * which irqs are strictly per cpu
*/
irq_set_percpu_devid(irq);
- irq_modify_status(irq, IRQ_NOAUTOEN, 0); /* @irq, @clr, @set */
+#endif
rc = request_percpu_irq(irq, isr, irq_nm, percpu_dev);
if (rc)
diff --git a/arch/arc/kernel/mcip.c b/arch/arc/kernel/mcip.c
index 74a9b07..bd237ac 100644
--- a/arch/arc/kernel/mcip.c
+++ b/arch/arc/kernel/mcip.c
@@ -132,7 +132,7 @@ static void mcip_probe_n_setup(void)
struct plat_smp_ops plat_smp_ops = {
.info = smp_cpuinfo_buf,
.init_early_smp = mcip_probe_n_setup,
- .init_irq_cpu = mcip_setup_per_cpu,
+ .init_per_cpu = mcip_setup_per_cpu,
.ipi_send = mcip_ipi_send,
.ipi_clear = mcip_ipi_clear,
};
diff --git a/arch/arc/kernel/perf_event.c b/arch/arc/kernel/perf_event.c
index 0c08bb1..8b134cf 100644
--- a/arch/arc/kernel/perf_event.c
+++ b/arch/arc/kernel/perf_event.c
@@ -428,12 +428,11 @@ static irqreturn_t arc_pmu_intr(int irq, void *dev)
#endif /* CONFIG_ISA_ARCV2 */
-void arc_cpu_pmu_irq_init(void)
+static void arc_cpu_pmu_irq_init(void *data)
{
- struct arc_pmu_cpu *pmu_cpu = this_cpu_ptr(&arc_pmu_cpu);
+ int irq = *(int *)data;
- arc_request_percpu_irq(arc_pmu->irq, smp_processor_id(), arc_pmu_intr,
- "ARC perf counters", pmu_cpu);
+ enable_percpu_irq(irq, IRQ_TYPE_NONE);
/* Clear all pending interrupt flags */
write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff);
@@ -515,7 +514,6 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
if (has_interrupts) {
int irq = platform_get_irq(pdev, 0);
- unsigned long flags;
if (irq < 0) {
pr_err("Cannot get IRQ number for the platform\n");
@@ -524,24 +522,12 @@ static int arc_pmu_device_probe(struct platform_device *pdev)
arc_pmu->irq = irq;
- /*
- * arc_cpu_pmu_irq_init() needs to be called on all cores for
- * their respective local PMU.
- * However we use opencoded on_each_cpu() to ensure it is called
- * on core0 first, so that arc_request_percpu_irq() sets up
- * AUTOEN etc. Otherwise enable_percpu_irq() fails to enable
- * perf IRQ on non master cores.
- * see arc_request_percpu_irq()
- */
- preempt_disable();
- local_irq_save(flags);
- arc_cpu_pmu_irq_init();
- local_irq_restore(flags);
- smp_call_function((smp_call_func_t)arc_cpu_pmu_irq_init, 0, 1);
- preempt_enable();
-
- /* Clean all pending interrupt flags */
- write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff);
+ /* intc map function ensures irq_set_percpu_devid() called */
+ request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
+ this_cpu_ptr(&arc_pmu_cpu));
+
+ on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
+
} else
arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
diff --git a/arch/arc/kernel/process.c b/arch/arc/kernel/process.c
index 91d5a0f..a3f750e 100644
--- a/arch/arc/kernel/process.c
+++ b/arch/arc/kernel/process.c
@@ -44,11 +44,10 @@ SYSCALL_DEFINE0(arc_gettls)
void arch_cpu_idle(void)
{
/* sleep, but enable all interrupts before committing */
- if (is_isa_arcompact()) {
- __asm__("sleep 0x3");
- } else {
- __asm__("sleep 0x10");
- }
+ __asm__ __volatile__(
+ "sleep %0 \n"
+ :
+ :"I"(ISA_SLEEP_ARG)); /* can't be "r" has to be embedded const */
}
asmlinkage void ret_from_fork(void);
diff --git a/arch/arc/kernel/setup.c b/arch/arc/kernel/setup.c
index c33e77c..e1b8744 100644
--- a/arch/arc/kernel/setup.c
+++ b/arch/arc/kernel/setup.c
@@ -429,7 +429,6 @@ void __init setup_arch(char **cmdline_p)
#endif
arc_unwind_init();
- arc_unwind_setup();
}
static int __init customize_machine(void)
diff --git a/arch/arc/kernel/smp.c b/arch/arc/kernel/smp.c
index 5805878..ef6e9e1 100644
--- a/arch/arc/kernel/smp.c
+++ b/arch/arc/kernel/smp.c
@@ -132,11 +132,11 @@ void start_kernel_secondary(void)
pr_info("## CPU%u LIVE ##: Executing Code...\n", cpu);
/* Some SMP H/w setup - for each cpu */
- if (plat_smp_ops.init_irq_cpu)
- plat_smp_ops.init_irq_cpu(cpu);
+ if (plat_smp_ops.init_per_cpu)
+ plat_smp_ops.init_per_cpu(cpu);
- if (machine_desc->init_cpu_smp)
- machine_desc->init_cpu_smp(cpu);
+ if (machine_desc->init_per_cpu)
+ machine_desc->init_per_cpu(cpu);
arc_local_timer_setup();
diff --git a/arch/arc/kernel/unwind.c b/arch/arc/kernel/unwind.c
index 93c6ea5..5eb7076 100644
--- a/arch/arc/kernel/unwind.c
+++ b/arch/arc/kernel/unwind.c
@@ -170,6 +170,23 @@ static struct unwind_table *find_table(unsigned long pc)
static unsigned long read_pointer(const u8 **pLoc,
const void *end, signed ptrType);
+static void init_unwind_hdr(struct unwind_table *table,
+ void *(*alloc) (unsigned long));
+
+/*
+ * wrappers for header alloc (vs. calling one vs. other at call site)
+ * to elide section mismatches warnings
+ */
+static void *__init unw_hdr_alloc_early(unsigned long sz)
+{
+ return __alloc_bootmem_nopanic(sz, sizeof(unsigned int),
+ MAX_DMA_ADDRESS);
+}
+
+static void *unw_hdr_alloc(unsigned long sz)
+{
+ return kmalloc(sz, GFP_KERNEL);
+}
static void init_unwind_table(struct unwind_table *table, const char *name,
const void *core_start, unsigned long core_size,
@@ -209,6 +226,8 @@ void __init arc_unwind_init(void)
__start_unwind, __end_unwind - __start_unwind,
NULL, 0);
/*__start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);*/
+
+ init_unwind_hdr(&root_table, unw_hdr_alloc_early);
}
static const u32 bad_cie, not_fde;
@@ -241,8 +260,8 @@ static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
e2->fde = v;
}
-static void __init setup_unwind_table(struct unwind_table *table,
- void *(*alloc) (unsigned long))
+static void init_unwind_hdr(struct unwind_table *table,
+ void *(*alloc) (unsigned long))
{
const u8 *ptr;
unsigned long tableSize = table->size, hdrSize;
@@ -277,10 +296,10 @@ static void __init setup_unwind_table(struct unwind_table *table,
if (cie == &not_fde)
continue;
if (cie == NULL || cie == &bad_cie)
- return;
+ goto ret_err;
ptrType = fde_pointer_type(cie);
if (ptrType < 0)
- return;
+ goto ret_err;
ptr = (const u8 *)(fde + 2);
if (!read_pointer(&ptr, (const u8 *)(fde + 1) + *fde,
@@ -296,13 +315,15 @@ static void __init setup_unwind_table(struct unwind_table *table,
}
if (tableSize || !n)
- return;
+ goto ret_err;
hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
+ 2 * n * sizeof(unsigned long);
+
header = alloc(hdrSize);
if (!header)
- return;
+ goto ret_err;
+
header->version = 1;
header->eh_frame_ptr_enc = DW_EH_PE_abs | DW_EH_PE_native;
header->fde_count_enc = DW_EH_PE_abs | DW_EH_PE_data4;
@@ -340,18 +361,10 @@ static void __init setup_unwind_table(struct unwind_table *table,
table->hdrsz = hdrSize;
smp_wmb();
table->header = (const void *)header;
-}
-
-static void *__init balloc(unsigned long sz)
-{
- return __alloc_bootmem_nopanic(sz,
- sizeof(unsigned int),
- __pa(MAX_DMA_ADDRESS));
-}
+ return;
-void __init arc_unwind_setup(void)
-{
- setup_unwind_table(&root_table, balloc);
+ret_err:
+ panic("Attention !!! Dwarf FDE parsing errors\n");;
}
#ifdef CONFIG_MODULES
@@ -377,6 +390,8 @@ void *unwind_add_table(struct module *module, const void *table_start,
table_start, table_size,
NULL, 0);
+ init_unwind_hdr(table, unw_hdr_alloc);
+
#ifdef UNWIND_DEBUG
unw_debug("Table added for [%s] %lx %lx\n",
module->name, table->core.pc, table->core.range);
@@ -439,6 +454,7 @@ void unwind_remove_table(void *handle, int init_only)
info.init_only = init_only;
unlink_table(&info); /* XXX: SMP */
+ kfree(table->header);
kfree(table);
}
@@ -588,9 +604,6 @@ static signed fde_pointer_type(const u32 *cie)
const u8 *ptr = (const u8 *)(cie + 2);
unsigned version = *ptr;
- if (version != 1)
- return -1; /* unsupported */
-
if (*++ptr) {
const char *aug;
const u8 *end = (const u8 *)(cie + 1) + *cie;
@@ -986,42 +999,13 @@ int arc_unwind(struct unwind_frame_info *frame)
(const u8 *)(fde +
1) +
*fde, ptrType);
- if (pc >= endLoc)
+ if (pc >= endLoc) {
fde = NULL;
- } else
- fde = NULL;
- }
- if (fde == NULL) {
- for (fde = table->address, tableSize = table->size;
- cie = NULL, tableSize > sizeof(*fde)
- && tableSize - sizeof(*fde) >= *fde;
- tableSize -= sizeof(*fde) + *fde,
- fde += 1 + *fde / sizeof(*fde)) {
- cie = cie_for_fde(fde, table);
- if (cie == &bad_cie) {
cie = NULL;
- break;
}
- if (cie == NULL
- || cie == &not_fde
- || (ptrType = fde_pointer_type(cie)) < 0)
- continue;
- ptr = (const u8 *)(fde + 2);
- startLoc = read_pointer(&ptr,
- (const u8 *)(fde + 1) +
- *fde, ptrType);
- if (!startLoc)
- continue;
- if (!(ptrType & DW_EH_PE_indirect))
- ptrType &=
- DW_EH_PE_FORM | DW_EH_PE_signed;
- endLoc =
- startLoc + read_pointer(&ptr,
- (const u8 *)(fde +
- 1) +
- *fde, ptrType);
- if (pc >= startLoc && pc < endLoc)
- break;
+ } else {
+ fde = NULL;
+ cie = NULL;
}
}
}
@@ -1031,9 +1015,7 @@ int arc_unwind(struct unwind_frame_info *frame)
ptr = (const u8 *)(cie + 2);
end = (const u8 *)(cie + 1) + *cie;
frame->call_frame = 1;
- if ((state.version = *ptr) != 1)
- cie = NULL; /* unsupported version */
- else if (*++ptr) {
+ if (*++ptr) {
/* check if augmentation size is first (thus present) */
if (*ptr == 'z') {
while (++ptr < end && *ptr) {
diff --git a/arch/arc/lib/memcpy-archs.S b/arch/arc/lib/memcpy-archs.S
index 0cab0b8..f96c75e 100644
--- a/arch/arc/lib/memcpy-archs.S
+++ b/arch/arc/lib/memcpy-archs.S
@@ -50,26 +50,26 @@ ENTRY(memcpy)
;;; if size <= 8
cmp r2, 8
- bls.d @smallchunk
+ bls.d @.Lsmallchunk
mov.f lp_count, r2
and.f r4, r0, 0x03
rsub lp_count, r4, 4
- lpnz @aligndestination
+ lpnz @.Laligndestination
;; LOOP BEGIN
ldb.ab r5, [r1,1]
sub r2, r2, 1
stb.ab r5, [r3,1]
-aligndestination:
+.Laligndestination:
;;; Check the alignment of the source
and.f r4, r1, 0x03
- bnz.d @sourceunaligned
+ bnz.d @.Lsourceunaligned
;;; CASE 0: Both source and destination are 32bit aligned
;;; Convert len to Dwords, unfold x4
lsr.f lp_count, r2, ZOLSHFT
- lpnz @copy32_64bytes
+ lpnz @.Lcopy32_64bytes
;; LOOP START
LOADX (r6, r1)
PREFETCH_READ (r1)
@@ -81,25 +81,25 @@ aligndestination:
STOREX (r8, r3)
STOREX (r10, r3)
STOREX (r4, r3)
-copy32_64bytes:
+.Lcopy32_64bytes:
and.f lp_count, r2, ZOLAND ;Last remaining 31 bytes
-smallchunk:
- lpnz @copyremainingbytes
+.Lsmallchunk:
+ lpnz @.Lcopyremainingbytes
;; LOOP START
ldb.ab r5, [r1,1]
stb.ab r5, [r3,1]
-copyremainingbytes:
+.Lcopyremainingbytes:
j [blink]
;;; END CASE 0
-sourceunaligned:
+.Lsourceunaligned:
cmp r4, 2
- beq.d @unalignedOffby2
+ beq.d @.LunalignedOffby2
sub r2, r2, 1
- bhi.d @unalignedOffby3
+ bhi.d @.LunalignedOffby3
ldb.ab r5, [r1, 1]
;;; CASE 1: The source is unaligned, off by 1
@@ -114,7 +114,7 @@ sourceunaligned:
or r5, r5, r6
;; Both src and dst are aligned
- lpnz @copy8bytes_1
+ lpnz @.Lcopy8bytes_1
;; LOOP START
ld.ab r6, [r1, 4]
prefetch [r1, 28] ;Prefetch the next read location
@@ -131,7 +131,7 @@ sourceunaligned:
st.ab r7, [r3, 4]
st.ab r9, [r3, 4]
-copy8bytes_1:
+.Lcopy8bytes_1:
;; Write back the remaining 16bits
EXTRACT_1 (r6, r5, 16)
@@ -141,14 +141,14 @@ copy8bytes_1:
stb.ab r5, [r3, 1]
and.f lp_count, r2, 0x07 ;Last 8bytes
- lpnz @copybytewise_1
+ lpnz @.Lcopybytewise_1
;; LOOP START
ldb.ab r6, [r1,1]
stb.ab r6, [r3,1]
-copybytewise_1:
+.Lcopybytewise_1:
j [blink]
-unalignedOffby2:
+.LunalignedOffby2:
;;; CASE 2: The source is unaligned, off by 2
ldh.ab r5, [r1, 2]
sub r2, r2, 1
@@ -159,7 +159,7 @@ unalignedOffby2:
#ifdef __BIG_ENDIAN__
asl.nz r5, r5, 16
#endif
- lpnz @copy8bytes_2
+ lpnz @.Lcopy8bytes_2
;; LOOP START
ld.ab r6, [r1, 4]
prefetch [r1, 28] ;Prefetch the next read location
@@ -176,7 +176,7 @@ unalignedOffby2:
st.ab r7, [r3, 4]
st.ab r9, [r3, 4]
-copy8bytes_2:
+.Lcopy8bytes_2:
#ifdef __BIG_ENDIAN__
lsr.nz r5, r5, 16
@@ -184,14 +184,14 @@ copy8bytes_2:
sth.ab r5, [r3, 2]
and.f lp_count, r2, 0x07 ;Last 8bytes
- lpnz @copybytewise_2
+ lpnz @.Lcopybytewise_2
;; LOOP START
ldb.ab r6, [r1,1]
stb.ab r6, [r3,1]
-copybytewise_2:
+.Lcopybytewise_2:
j [blink]
-unalignedOffby3:
+.LunalignedOffby3:
;;; CASE 3: The source is unaligned, off by 3
;;; Hence, I need to read 1byte for achieve the 32bit alignment
@@ -201,7 +201,7 @@ unalignedOffby3:
#ifdef __BIG_ENDIAN__
asl.ne r5, r5, 24
#endif
- lpnz @copy8bytes_3
+ lpnz @.Lcopy8bytes_3
;; LOOP START
ld.ab r6, [r1, 4]
prefetch [r1, 28] ;Prefetch the next read location
@@ -218,7 +218,7 @@ unalignedOffby3:
st.ab r7, [r3, 4]
st.ab r9, [r3, 4]
-copy8bytes_3:
+.Lcopy8bytes_3:
#ifdef __BIG_ENDIAN__
lsr.nz r5, r5, 24
@@ -226,11 +226,11 @@ copy8bytes_3:
stb.ab r5, [r3, 1]
and.f lp_count, r2, 0x07 ;Last 8bytes
- lpnz @copybytewise_3
+ lpnz @.Lcopybytewise_3
;; LOOP START
ldb.ab r6, [r1,1]
stb.ab r6, [r3,1]
-copybytewise_3:
+.Lcopybytewise_3:
j [blink]
END(memcpy)
diff --git a/arch/arc/mm/highmem.c b/arch/arc/mm/highmem.c
index 065ee6b..92dd92c 100644
--- a/arch/arc/mm/highmem.c
+++ b/arch/arc/mm/highmem.c
@@ -111,7 +111,7 @@ void __kunmap_atomic(void *kv)
}
EXPORT_SYMBOL(__kunmap_atomic);
-noinline pte_t *alloc_kmap_pgtable(unsigned long kvaddr)
+static noinline pte_t * __init alloc_kmap_pgtable(unsigned long kvaddr)
{
pgd_t *pgd_k;
pud_t *pud_k;
@@ -127,7 +127,7 @@ noinline pte_t *alloc_kmap_pgtable(unsigned long kvaddr)
return pte_k;
}
-void kmap_init(void)
+void __init kmap_init(void)
{
/* Due to recursive include hell, we can't do this in processor.h */
BUILD_BUG_ON(PAGE_OFFSET < (VMALLOC_END + FIXMAP_SIZE + PKMAP_SIZE));
diff --git a/arch/arc/mm/init.c b/arch/arc/mm/init.c
index a9305b5..7d2c4fb 100644
--- a/arch/arc/mm/init.c
+++ b/arch/arc/mm/init.c
@@ -51,7 +51,9 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
int in_use = 0;
if (!low_mem_sz) {
- BUG_ON(base != low_mem_start);
+ if (base != low_mem_start)
+ panic("CONFIG_LINUX_LINK_BASE != DT memory { }");
+
low_mem_sz = size;
in_use = 1;
} else {
diff --git a/arch/arc/mm/tlb.c b/arch/arc/mm/tlb.c
index 0ee7398..daf2bf5 100644
--- a/arch/arc/mm/tlb.c
+++ b/arch/arc/mm/tlb.c
@@ -619,10 +619,10 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long vaddr_unaligned,
int dirty = !test_and_set_bit(PG_dc_clean, &page->flags);
if (dirty) {
- /* wback + inv dcache lines */
+ /* wback + inv dcache lines (K-mapping) */
__flush_dcache_page(paddr, paddr);
- /* invalidate any existing icache lines */
+ /* invalidate any existing icache lines (U-mapping) */
if (vma->vm_flags & VM_EXEC)
__inv_icache_page(paddr, vaddr);
}
diff --git a/arch/arc/mm/tlbex.S b/arch/arc/mm/tlbex.S
index 63860ad..f1967ee 100644
--- a/arch/arc/mm/tlbex.S
+++ b/arch/arc/mm/tlbex.S
@@ -88,7 +88,7 @@ ex_saved_reg1:
#ifdef CONFIG_SMP
sr r0, [ARC_REG_SCRATCH_DATA0] ; freeup r0 to code with
GET_CPU_ID r0 ; get to per cpu scratch mem,
- lsl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu
+ asl r0, r0, L1_CACHE_SHIFT ; cache line wide per cpu
add r0, @ex_saved_reg1, r0
#else
st r0, [@ex_saved_reg1]
@@ -107,7 +107,7 @@ ex_saved_reg1:
.macro TLBMISS_RESTORE_REGS
#ifdef CONFIG_SMP
GET_CPU_ID r0 ; get to per cpu scratch mem
- lsl r0, r0, L1_CACHE_SHIFT ; each is cache line wide
+ asl r0, r0, L1_CACHE_SHIFT ; each is cache line wide
add r0, @ex_saved_reg1, r0
ld_s r3, [r0,12]
ld_s r2, [r0, 8]
@@ -256,7 +256,7 @@ ex_saved_reg1:
.macro CONV_PTE_TO_TLB
and r3, r0, PTE_BITS_RWX ; r w x
- lsl r2, r3, 3 ; Kr Kw Kx 0 0 0 (GLOBAL, kernel only)
+ asl r2, r3, 3 ; Kr Kw Kx 0 0 0 (GLOBAL, kernel only)
and.f 0, r0, _PAGE_GLOBAL
or.z r2, r2, r3 ; Kr Kw Kx Ur Uw Ux (!GLOBAL, user page)
diff --git a/arch/arc/plat-sim/platform.c b/arch/arc/plat-sim/platform.c
index dde6928..e4fe514 100644
--- a/arch/arc/plat-sim/platform.c
+++ b/arch/arc/plat-sim/platform.c
@@ -10,7 +10,6 @@
#include <linux/init.h>
#include <asm/mach_desc.h>
-#include <asm/mcip.h>
/*----------------------- Machine Descriptions ------------------------------
*
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9246bd7..426115f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -20,6 +20,7 @@ config ARM
select GENERIC_ALLOCATOR
select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI)
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
+ select GENERIC_EARLY_IOREMAP
select GENERIC_IDLE_POLL_SETUP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
@@ -33,10 +34,11 @@ config ARM
select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
- select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32
- select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32
+ select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU
+ select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
select HAVE_ARCH_SECCOMP_FILTER if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_TRACEHOOK
+ select HAVE_ARM_SMCCC if CPU_V7
select HAVE_BPF_JIT
select HAVE_CC_STACKPROTECTOR
select HAVE_CONTEXT_TRACKING
@@ -45,7 +47,7 @@ config ARM
select HAVE_DMA_API_DEBUG
select HAVE_DMA_ATTRS
select HAVE_DMA_CONTIGUOUS if MMU
- select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32
+ select HAVE_DYNAMIC_FTRACE if (!XIP_KERNEL) && !CPU_ENDIAN_BE32 && MMU
select HAVE_EFFICIENT_UNALIGNED_ACCESS if (CPU_V6 || CPU_V6K || CPU_V7) && MMU
select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL)
select HAVE_FUNCTION_GRAPH_TRACER if (!THUMB2_KERNEL)
@@ -76,6 +78,8 @@ config ARM
select IRQ_FORCED_THREADING
select MODULES_USE_ELF_REL
select NO_BOOTMEM
+ select OF_EARLY_FLATTREE if OF
+ select OF_RESERVED_MEM if OF
select OLD_SIGACTION
select OLD_SIGSUSPEND3
select PERF_USE_VMALLOC
@@ -609,6 +613,7 @@ config ARCH_PXA
select AUTO_ZRELADDR
select COMMON_CLK
select CLKDEV_LOOKUP
+ select CLKSRC_PXA
select CLKSRC_MMIO
select CLKSRC_OF
select GENERIC_CLOCKEVENTS
@@ -621,28 +626,6 @@ config ARCH_PXA
help
Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
-config ARCH_SHMOBILE_LEGACY
- bool "Renesas ARM SoCs (non-multiplatform)"
- select ARCH_SHMOBILE
- select ARM_PATCH_PHYS_VIRT if MMU
- select CLKDEV_LOOKUP
- select CPU_V7
- select GENERIC_CLOCKEVENTS
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select HAVE_SMP
- select MIGHT_HAVE_CACHE_L2X0
- select MULTI_IRQ_HANDLER
- select NO_IOPORT_MAP
- select PINCTRL
- select PM_GENERIC_DOMAINS if PM
- select SH_CLK_CPG
- select SPARSE_IRQ
- help
- Support for Renesas ARM SoC platforms using a non-multiplatform
- kernel. This includes the SH-Mobile, R-Mobile, EMMA-Mobile, R-Car
- and RZ families.
-
config ARCH_RPC
bool "RiscPC"
depends on MMU
@@ -670,6 +653,8 @@ config ARCH_SA1100
select ARCH_SPARSEMEM_ENABLE
select CLKDEV_LOOKUP
select CLKSRC_MMIO
+ select CLKSRC_PXA
+ select CLKSRC_OF if OF
select CPU_FREQ
select CPU_SA1100
select GENERIC_CLOCKEVENTS
@@ -819,6 +804,7 @@ config ARCH_VIRT
bool "Dummy Virtual Machine" if ARCH_MULTI_V7
select ARM_AMBA
select ARM_GIC
+ select ARM_GIC_V2M if PCI_MSI
select ARM_GIC_V3
select ARM_PSCI
select HAVE_ARM_ARCH_TIMER
@@ -1442,7 +1428,7 @@ config BIG_LITTLE
config BL_SWITCHER
bool "big.LITTLE switcher support"
- depends on BIG_LITTLE && MCPM && HOTPLUG_CPU
+ depends on BIG_LITTLE && MCPM && HOTPLUG_CPU && ARM_GIC
select ARM_CPU_SUSPEND
select CPU_PM
help
@@ -1501,7 +1487,7 @@ config HOTPLUG_CPU
config ARM_PSCI
bool "Support for the ARM Power State Coordination Interface (PSCI)"
- depends on CPU_V7
+ depends on HAVE_ARM_SMCCC
select ARM_PSCI_FW
help
Say Y here if you want Linux to communicate with system firmware
@@ -1537,7 +1523,6 @@ config HZ_FIXED
default 200 if ARCH_EBSA110 || ARCH_S3C24XX || \
ARCH_S5PV210 || ARCH_EXYNOS4
default 128 if SOC_AT91RM9200
- default SHMOBILE_TIMER_HZ if ARCH_SHMOBILE_LEGACY
default 0
choice
@@ -1625,6 +1610,24 @@ config THUMB2_AVOID_R_ARM_THM_JUMP11
config ARM_ASM_UNIFIED
bool
+config ARM_PATCH_IDIV
+ bool "Runtime patch udiv/sdiv instructions into __aeabi_{u}idiv()"
+ depends on CPU_32v7 && !XIP_KERNEL
+ default y
+ help
+ The ARM compiler inserts calls to __aeabi_idiv() and
+ __aeabi_uidiv() when it needs to perform division on signed
+ and unsigned integers. Some v7 CPUs have support for the sdiv
+ and udiv instructions that can be used to implement those
+ functions.
+
+ Enabling this option allows the kernel to modify itself to
+ replace the first two instructions of these library functions
+ with the sdiv or udiv plus "bx lr" instructions when the CPU
+ it is running on supports them. Typically this will be faster
+ and less power intensive than running the original library
+ code to do integer division.
+
config AEABI
bool "Use the ARM EABI to compile the kernel"
help
@@ -1756,8 +1759,7 @@ config ARM_MODULE_PLTS
source "mm/Kconfig"
config FORCE_MAX_ZONEORDER
- int "Maximum zone order" if ARCH_SHMOBILE_LEGACY
- range 11 64 if ARCH_SHMOBILE_LEGACY
+ int "Maximum zone order"
default "12" if SOC_AM33XX
default "9" if SA1111 || ARCH_EFM32
default "11"
@@ -1822,6 +1824,25 @@ config SWIOTLB
config IOMMU_HELPER
def_bool SWIOTLB
+config PARAVIRT
+ bool "Enable paravirtualization code"
+ help
+ This changes the kernel so it can modify itself when it is run
+ under a hypervisor, potentially improving performance significantly
+ over full virtualization.
+
+config PARAVIRT_TIME_ACCOUNTING
+ bool "Paravirtual steal time accounting"
+ select PARAVIRT
+ default n
+ help
+ Select this option to enable fine granularity task steal time
+ accounting. Time spent executing other tasks in parallel with
+ the current vCPU is discounted from the vCPU power. To account for
+ that, there can be a small performance impact.
+
+ If in doubt, say N here.
+
config XEN_DOM0
def_bool y
depends on XEN
@@ -1835,6 +1856,7 @@ config XEN
select ARCH_DMA_ADDR_T_64BIT
select ARM_PSCI
select SWIOTLB_XEN
+ select PARAVIRT
help
Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
@@ -1846,8 +1868,6 @@ config USE_OF
bool "Flattened Device Tree support"
select IRQ_DOMAIN
select OF
- select OF_EARLY_FLATTREE
- select OF_RESERVED_MEM
help
Include support for flattened device tree machine descriptions.
@@ -2064,6 +2084,25 @@ config AUTO_ZRELADDR
0xf8000000. This assumes the zImage being placed in the first 128MB
from start of memory.
+config EFI_STUB
+ bool
+
+config EFI
+ bool "UEFI runtime support"
+ depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL
+ select UCS2_STRING
+ select EFI_PARAMS_FROM_FDT
+ select EFI_STUB
+ select EFI_ARMSTUB
+ select EFI_RUNTIME_WRAPPERS
+ ---help---
+ This option provides support for runtime services provided
+ by UEFI firmware (such as non-volatile variables, realtime
+ clock, and platform reset). A UEFI stub is also provided to
+ allow the kernel to be booted as an EFI application. This
+ is only useful for kernels that may run on systems that have
+ UEFI firmware.
+
endmenu
menu "CPU Power Management"
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index 0cfd7f9..259c0ca 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -123,29 +123,23 @@ choice
0x80020000 | 0xf0020000 | UART8
0x80024000 | 0xf0024000 | UART9
- config AT91_DEBUG_LL_DBGU0
- bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10, 9rl, 9x5, 9n12"
- select DEBUG_AT91_UART
+ config DEBUG_AT91_UART
+ bool "Kernel low-level debugging on Atmel SoCs"
depends on ARCH_AT91
- depends on SOC_AT91RM9200 || SOC_AT91SAM9
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the serial port on atmel devices.
- config AT91_DEBUG_LL_DBGU1
- bool "Kernel low-level debugging on 9263, 9g45 and sama5d3"
- select DEBUG_AT91_UART
- depends on ARCH_AT91
- depends on SOC_AT91SAM9 || SOC_SAMA5
+ SOC DEBUG_UART_PHYS DEBUG_UART_VIRT PORT
+ rm9200, 9260/9g20, 0xfffff200 0xfefff200 DBGU
+ 9261/9g10, 9rl
+ 9263, 9g45, sama5d3 0xffffee00 0xfeffee00 DBGU
+ sama5d4 0xfc00c000 0xfb00c000 USART3
+ sama5d4 0xfc069000 0xfb069000 DBGU
+ sama5d2 0xf8020000 0xf7020000 UART1
- config AT91_DEBUG_LL_DBGU2
- bool "Kernel low-level debugging on sama5d4"
- select DEBUG_AT91_UART
- depends on ARCH_AT91
- depends on SOC_SAMA5
-
- config AT91_DEBUG_LL_DBGU3
- bool "Kernel low-level debugging on sama5d2"
- select DEBUG_AT91_UART
- depends on ARCH_AT91
- depends on SOC_SAMA5
+ Please adjust DEBUG_UART_PHYS configuration options based on
+ your needs.
config DEBUG_BCM2835
bool "Kernel low-level debugging on BCM2835 PL011 UART"
@@ -1249,10 +1243,6 @@ choice
endchoice
-config DEBUG_AT91_UART
- bool
- depends on ARCH_AT91
-
config DEBUG_EXYNOS_UART
bool
@@ -1485,7 +1475,8 @@ config DEBUG_UART_PHYS
DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART || \
- DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0
+ DEBUG_SIRFSOC_UART || DEBUG_DIGICOLOR_UA0 || \
+ DEBUG_AT91_UART
config DEBUG_UART_VIRT
hex "Virtual base address of debug UART"
@@ -1621,8 +1612,7 @@ config DEBUG_UNCOMPRESS
config UNCOMPRESS_INCLUDE
string
default "debug/uncompress.h" if ARCH_MULTIPLATFORM || ARCH_MSM || \
- PLAT_SAMSUNG || ARM_SINGLE_ARMV7M || \
- ARCH_SHMOBILE_LEGACY
+ PLAT_SAMSUNG || ARM_SINGLE_ARMV7M
default "mach/uncompress.h"
config EARLY_PRINTK
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 3f9a9eb..4c23a68 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -167,9 +167,11 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \
false; \
fi
+efi-obj-$(CONFIG_EFI_STUB) := $(objtree)/drivers/firmware/efi/libstub/lib.a
+
$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \
$(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \
- $(bswapsdi2) FORCE
+ $(bswapsdi2) $(efi-obj-y) FORCE
@$(check_for_multiple_zreladdr)
$(call if_changed,ld)
@$(check_for_bad_syms)
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S
new file mode 100644
index 0000000..9d5dc4f
--- /dev/null
+++ b/arch/arm/boot/compressed/efi-header.S
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013-2015 Linaro Ltd
+ * Authors: Roy Franz <roy.franz@linaro.org>
+ * Ard Biesheuvel <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+ .macro __nop
+#ifdef CONFIG_EFI_STUB
+ @ This is almost but not quite a NOP, since it does clobber the
+ @ condition flags. But it is the best we can do for EFI, since
+ @ PE/COFF expects the magic string "MZ" at offset 0, while the
+ @ ARM/Linux boot protocol expects an executable instruction
+ @ there.
+ .inst 'M' | ('Z' << 8) | (0x1310 << 16) @ tstne r0, #0x4d000
+#else
+ mov r0, r0
+#endif
+ .endm
+
+ .macro __EFI_HEADER
+#ifdef CONFIG_EFI_STUB
+ b __efi_start
+
+ .set start_offset, __efi_start - start
+ .org start + 0x3c
+ @
+ @ The PE header can be anywhere in the file, but for
+ @ simplicity we keep it together with the MSDOS header
+ @ The offset to the PE/COFF header needs to be at offset
+ @ 0x3C in the MSDOS header.
+ @ The only 2 fields of the MSDOS header that are used are this
+ @ PE/COFF offset, and the "MZ" bytes at offset 0x0.
+ @
+ .long pe_header - start @ Offset to the PE header.
+
+pe_header:
+ .ascii "PE\0\0"
+
+coff_header:
+ .short 0x01c2 @ ARM or Thumb
+ .short 2 @ nr_sections
+ .long 0 @ TimeDateStamp
+ .long 0 @ PointerToSymbolTable
+ .long 1 @ NumberOfSymbols
+ .short section_table - optional_header
+ @ SizeOfOptionalHeader
+ .short 0x306 @ Characteristics.
+ @ IMAGE_FILE_32BIT_MACHINE |
+ @ IMAGE_FILE_DEBUG_STRIPPED |
+ @ IMAGE_FILE_EXECUTABLE_IMAGE |
+ @ IMAGE_FILE_LINE_NUMS_STRIPPED
+
+optional_header:
+ .short 0x10b @ PE32 format
+ .byte 0x02 @ MajorLinkerVersion
+ .byte 0x14 @ MinorLinkerVersion
+ .long _end - __efi_start @ SizeOfCode
+ .long 0 @ SizeOfInitializedData
+ .long 0 @ SizeOfUninitializedData
+ .long efi_stub_entry - start @ AddressOfEntryPoint
+ .long start_offset @ BaseOfCode
+ .long 0 @ data
+
+extra_header_fields:
+ .long 0 @ ImageBase
+ .long 0x200 @ SectionAlignment
+ .long 0x200 @ FileAlignment
+ .short 0 @ MajorOperatingSystemVersion
+ .short 0 @ MinorOperatingSystemVersion
+ .short 0 @ MajorImageVersion
+ .short 0 @ MinorImageVersion
+ .short 0 @ MajorSubsystemVersion
+ .short 0 @ MinorSubsystemVersion
+ .long 0 @ Win32VersionValue
+
+ .long _end - start @ SizeOfImage
+ .long start_offset @ SizeOfHeaders
+ .long 0 @ CheckSum
+ .short 0xa @ Subsystem (EFI application)
+ .short 0 @ DllCharacteristics
+ .long 0 @ SizeOfStackReserve
+ .long 0 @ SizeOfStackCommit
+ .long 0 @ SizeOfHeapReserve
+ .long 0 @ SizeOfHeapCommit
+ .long 0 @ LoaderFlags
+ .long 0x6 @ NumberOfRvaAndSizes
+
+ .quad 0 @ ExportTable
+ .quad 0 @ ImportTable
+ .quad 0 @ ResourceTable
+ .quad 0 @ ExceptionTable
+ .quad 0 @ CertificationTable
+ .quad 0 @ BaseRelocationTable
+
+section_table:
+ @
+ @ The EFI application loader requires a relocation section
+ @ because EFI applications must be relocatable. This is a
+ @ dummy section as far as we are concerned.
+ @
+ .ascii ".reloc\0\0"
+ .long 0 @ VirtualSize
+ .long 0 @ VirtualAddress
+ .long 0 @ SizeOfRawData
+ .long 0 @ PointerToRawData
+ .long 0 @ PointerToRelocations
+ .long 0 @ PointerToLineNumbers
+ .short 0 @ NumberOfRelocations
+ .short 0 @ NumberOfLineNumbers
+ .long 0x42100040 @ Characteristics
+
+ .ascii ".text\0\0\0"
+ .long _end - __efi_start @ VirtualSize
+ .long __efi_start @ VirtualAddress
+ .long _edata - __efi_start @ SizeOfRawData
+ .long __efi_start @ PointerToRawData
+ .long 0 @ PointerToRelocations
+ .long 0 @ PointerToLineNumbers
+ .short 0 @ NumberOfRelocations
+ .short 0 @ NumberOfLineNumbers
+ .long 0xe0500020 @ Characteristics
+
+ .align 9
+__efi_start:
+#endif
+ .endm
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 06e983f..af11c2f 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -12,6 +12,8 @@
#include <asm/assembler.h>
#include <asm/v7m.h>
+#include "efi-header.S"
+
AR_CLASS( .arch armv7-a )
M_CLASS( .arch armv7-m )
@@ -126,7 +128,7 @@
start:
.type start,#function
.rept 7
- mov r0, r0
+ __nop
.endr
ARM( mov r0, r0 )
ARM( b 1f )
@@ -139,7 +141,8 @@ start:
.word 0x04030201 @ endianness flag
THUMB( .thumb )
-1:
+1: __EFI_HEADER
+
ARM_BE8( setend be ) @ go BE8 if compiled for BE8
AR_CLASS( mrs r9, cpsr )
#ifdef CONFIG_ARM_VIRT_EXT
@@ -1353,6 +1356,53 @@ __enter_kernel:
reloc_code_end:
+#ifdef CONFIG_EFI_STUB
+ .align 2
+_start: .long start - .
+
+ENTRY(efi_stub_entry)
+ @ allocate space on stack for passing current zImage address
+ @ and for the EFI stub to return of new entry point of
+ @ zImage, as EFI stub may copy the kernel. Pointer address
+ @ is passed in r2. r0 and r1 are passed through from the
+ @ EFI firmware to efi_entry
+ adr ip, _start
+ ldr r3, [ip]
+ add r3, r3, ip
+ stmfd sp!, {r3, lr}
+ mov r2, sp @ pass zImage address in r2
+ bl efi_entry
+
+ @ Check for error return from EFI stub. r0 has FDT address
+ @ or error code.
+ cmn r0, #1
+ beq efi_load_fail
+
+ @ Preserve return value of efi_entry() in r4
+ mov r4, r0
+ bl cache_clean_flush
+ bl cache_off
+
+ @ Set parameters for booting zImage according to boot protocol
+ @ put FDT address in r2, it was returned by efi_entry()
+ @ r1 is the machine type, and r0 needs to be 0
+ mov r0, #0
+ mov r1, #0xFFFFFFFF
+ mov r2, r4
+
+ @ Branch to (possibly) relocated zImage that is in [sp]
+ ldr lr, [sp]
+ ldr ip, =start_offset
+ add lr, lr, ip
+ mov pc, lr @ no mode switch
+
+efi_load_fail:
+ @ Return EFI_LOAD_ERROR to EFI firmware on error.
+ ldr r0, =0x80000001
+ ldmfd sp!, {ip, pc}
+ENDPROC(efi_stub_entry)
+#endif
+
.align
.section ".stack", "aw", %nobits
.L_user_stack: .space 4096
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S
index 2b60b84..81c4931 100644
--- a/arch/arm/boot/compressed/vmlinux.lds.S
+++ b/arch/arm/boot/compressed/vmlinux.lds.S
@@ -48,6 +48,13 @@ SECTIONS
*(.rodata)
*(.rodata.*)
}
+ .data : {
+ /*
+ * The EFI stub always executes from RAM, and runs strictly before the
+ * decompressor, so we can make an exception for its r/w data, and keep it
+ */
+ *(.data.efistub)
+ }
.piggydata : {
*(.piggydata)
}
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 6019f5d..30bbc37 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -58,7 +58,9 @@ dtb-$(CONFIG_ARCH_AXXIA) += \
axm5516-amarillo.dtb
dtb-$(CONFIG_ARCH_BCM2835) += \
bcm2835-rpi-b.dtb \
- bcm2835-rpi-b-plus.dtb
+ bcm2835-rpi-b-rev2.dtb \
+ bcm2835-rpi-b-plus.dtb \
+ bcm2835-rpi-a-plus.dtb
dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4708-asus-rt-ac56u.dtb \
bcm4708-asus-rt-ac68u.dtb \
@@ -72,6 +74,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm47081-buffalo-wzr-900dhp.dtb \
bcm4709-asus-rt-ac87u.dtb \
bcm4709-buffalo-wxr-1900dhp.dtb \
+ bcm4709-netgear-r7000.dtb \
bcm4709-netgear-r8000.dtb
dtb-$(CONFIG_ARCH_BCM_63XX) += \
bcm963138dvt.dtb
@@ -83,6 +86,8 @@ dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
dtb-$(CONFIG_ARCH_BCM_MOBILE) += \
bcm28155-ap.dtb \
bcm21664-garnet.dtb
+dtb-$(CONFIG_ARCH_BCM_NSP) += \
+ bcm958625k.dtb
dtb-$(CONFIG_ARCH_BERLIN) += \
berlin2-sony-nsz-gs7.dtb \
berlin2cd-google-chromecast.dtb \
@@ -115,6 +120,7 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \
exynos5250-arndale.dtb \
exynos5250-smdk5250.dtb \
exynos5250-snow.dtb \
+ exynos5250-snow-rev5.dtb \
exynos5250-spring.dtb \
exynos5260-xyref5260.dtb \
exynos5410-smdk5410.dtb \
@@ -123,6 +129,7 @@ dtb-$(CONFIG_ARCH_EXYNOS5) += \
exynos5420-smdk5420.dtb \
exynos5422-odroidxu3.dtb \
exynos5422-odroidxu3-lite.dtb \
+ exynos5422-odroidxu4.dtb \
exynos5440-sd5v1.dtb \
exynos5440-ssdk5440.dtb \
exynos5800-peach-pi.dtb
@@ -227,6 +234,9 @@ dtb-$(CONFIG_ARCH_MMP) += \
pxa168-aspenite.dtb \
pxa910-dkb.dtb \
mmp2-brownstone.dtb
+dtb-$(CONFIG_MACH_MESON8B) += \
+ meson8b-mxq.dtb \
+ meson8b-odroidc1.dtb
dtb-$(CONFIG_ARCH_MOXART) += \
moxart-uc7112lx.dtb
dtb-$(CONFIG_SOC_IMX1) += \
@@ -284,6 +294,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6dl-gw551x.dtb \
imx6dl-gw552x.dtb \
imx6dl-hummingboard.dtb \
+ imx6dl-nit6xlite.dtb \
imx6dl-nitrogen6x.dtb \
imx6dl-phytec-pbab01.dtb \
imx6dl-rex-basic.dtb \
@@ -313,6 +324,7 @@ dtb-$(CONFIG_SOC_IMX6Q) += \
imx6q-gw552x.dtb \
imx6q-hummingboard.dtb \
imx6q-nitrogen6x.dtb \
+ imx6q-nitrogen6_max.dtb \
imx6q-phytec-pbab01.dtb \
imx6q-rex-pro.dtb \
imx6q-sabreauto.dtb \
@@ -446,6 +458,7 @@ dtb-$(CONFIG_SOC_AM33XX) += \
am335x-base0033.dtb \
am335x-bone.dtb \
am335x-boneblack.dtb \
+ am335x-bonegreen.dtb \
am335x-sl50.dtb \
am335x-evm.dtb \
am335x-evmsk.dtb \
@@ -470,6 +483,7 @@ dtb-$(CONFIG_SOC_AM43XX) += \
am437x-gp-evm.dtb
dtb-$(CONFIG_SOC_OMAP5) += \
omap5-cm-t54.dtb \
+ omap5-igep0050.dtb \
omap5-sbc-t54.dtb \
omap5-uevm.dtb
dtb-$(CONFIG_SOC_DRA7XX) += \
@@ -506,7 +520,10 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3288-evb-rk808.dtb \
rk3288-firefly-beta.dtb \
rk3288-firefly.dtb \
+ rk3288-popmetal.dtb \
rk3288-r89.dtb \
+ rk3288-rock2-square.dtb \
+ rk3288-veyron-jaq.dtb \
rk3288-veyron-jerry.dtb \
rk3288-veyron-minnie.dtb \
rk3288-veyron-pinky.dtb \
@@ -522,9 +539,6 @@ dtb-$(CONFIG_ARCH_S5PV210) += \
s5pv210-smdkc110.dtb \
s5pv210-smdkv210.dtb \
s5pv210-torbreck.dtb
-dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += \
- r8a7778-bockw.dtb \
- r8a7778-bockw-reference.dtb
dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
emev2-kzm9d.dtb \
r7s72100-genmai.dtb \
@@ -535,6 +549,7 @@ dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += \
r8a7790-lager.dtb \
r8a7791-henninger.dtb \
r8a7791-koelsch.dtb \
+ r8a7791-porter.dtb \
r8a7793-gose.dtb \
r8a7794-alt.dtb \
r8a7794-silk.dtb \
@@ -577,7 +592,9 @@ dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-gemei-g9.dtb \
sun4i-a10-hackberry.dtb \
sun4i-a10-hyundai-a7hd.dtb \
+ sun4i-a10-inet1.dtb \
sun4i-a10-inet97fv2.dtb \
+ sun4i-a10-inet9f-rev03.dtb \
sun4i-a10-itead-iteaduino-plus.dtb \
sun4i-a10-jesurun-q5.dtb \
sun4i-a10-marsboard.dtb \
@@ -585,16 +602,23 @@ dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-mk802.dtb \
sun4i-a10-mk802ii.dtb \
sun4i-a10-olinuxino-lime.dtb \
- sun4i-a10-pcduino.dtb
+ sun4i-a10-pcduino.dtb \
+ sun4i-a10-pcduino2.dtb \
+ sun4i-a10-pov-protab2-ips9.dtb
dtb-$(CONFIG_MACH_SUN5I) += \
+ sun5i-a10s-auxtek-t003.dtb \
sun5i-a10s-auxtek-t004.dtb \
sun5i-a10s-mk802.dtb \
sun5i-a10s-olinuxino-micro.dtb \
sun5i-a10s-r7-tv-dongle.dtb \
+ sun5i-a10s-wobo-i5.dtb \
sun5i-a13-hsg-h702.dtb \
+ sun5i-a13-inet-98v-rev2.dtb \
sun5i-a13-olinuxino.dtb \
sun5i-a13-olinuxino-micro.dtb \
- sun5i-a13-utoo-p66.dtb
+ sun5i-a13-q8-tablet.dtb \
+ sun5i-a13-utoo-p66.dtb \
+ sun5i-r8-chip.dtb
dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-app4-evb1.dtb \
sun6i-a31-colombus.dtb \
@@ -602,7 +626,11 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-i7.dtb \
sun6i-a31-m9.dtb \
sun6i-a31-mele-a1000g-quad.dtb \
- sun6i-a31s-cs908.dtb
+ sun6i-a31s-cs908.dtb \
+ sun6i-a31s-primo81.dtb \
+ sun6i-a31s-sina31s.dtb \
+ sun6i-a31s-sinovoip-bpi-m2.dtb \
+ sun6i-a31s-yones-toptech-bs1078-v2.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-bananapi.dtb \
sun7i-a20-bananapro.dtb \
@@ -612,6 +640,7 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-i12-tvbox.dtb \
sun7i-a20-m3.dtb \
sun7i-a20-mk808c.dtb \
+ sun7i-a20-olimex-som-evb.dtb \
sun7i-a20-olinuxino-lime.dtb \
sun7i-a20-olinuxino-lime2.dtb \
sun7i-a20-olinuxino-micro.dtb \
@@ -619,14 +648,18 @@ dtb-$(CONFIG_MACH_SUN7I) += \
sun7i-a20-orangepi-mini.dtb \
sun7i-a20-pcduino3.dtb \
sun7i-a20-pcduino3-nano.dtb \
- sun7i-a20-wexler-tab7200.dtb
+ sun7i-a20-wexler-tab7200.dtb \
+ sun7i-a20-wits-pro-a20-dkt.dtb
dtb-$(CONFIG_MACH_SUN8I) += \
sun8i-a23-evb.dtb \
+ sun8i-a23-gt90h-v4.dtb \
sun8i-a23-ippo-q8h-v5.dtb \
sun8i-a23-ippo-q8h-v1.2.dtb \
+ sun8i-a23-q8-tablet.dtb \
sun8i-a33-et-q8-v1.6.dtb \
sun8i-a33-ga10h-v1.1.dtb \
sun8i-a33-ippo-q8h-v1.2.dtb \
+ sun8i-a33-q8-tablet.dtb \
sun8i-a33-sinlinx-sina33.dtb
dtb-$(CONFIG_MACH_SUN9I) += \
sun9i-a80-optimus.dtb \
@@ -672,7 +705,9 @@ dtb-$(CONFIG_ARCH_UNIPHIER) += \
uniphier-ph1-ld6b-ref.dtb \
uniphier-ph1-pro4-ref.dtb \
uniphier-ph1-sld3-ref.dtb \
- uniphier-ph1-sld8-ref.dtb
+ uniphier-ph1-sld8-ref.dtb \
+ uniphier-proxstream2-gentil.dtb \
+ uniphier-proxstream2-vodka.dtb
dtb-$(CONFIG_ARCH_VERSATILE) += \
versatile-ab.dtb \
versatile-pb.dtb
@@ -702,6 +737,10 @@ dtb-$(CONFIG_MACH_ARMADA_370) += \
armada-370-netgear-rn102.dtb \
armada-370-netgear-rn104.dtb \
armada-370-rd.dtb \
+ armada-370-seagate-nas-2bay.dtb \
+ armada-370-seagate-nas-4bay.dtb \
+ armada-370-seagate-personal-cloud.dtb \
+ armada-370-seagate-personal-cloud-2bay.dtb \
armada-370-synology-ds213j.dtb
dtb-$(CONFIG_MACH_ARMADA_375) += \
armada-375-db.dtb
diff --git a/arch/arm/boot/dts/am335x-base0033.dts b/arch/arm/boot/dts/am335x-base0033.dts
index 72a9b3f..58a05f7 100644
--- a/arch/arm/boot/dts/am335x-base0033.dts
+++ b/arch/arm/boot/dts/am335x-base0033.dts
@@ -46,39 +46,39 @@
&am33xx_pinmux {
nxp_hdmi_pins: pinmux_nxp_hdmi_pins {
pinctrl-single,pins = <
- 0x1b0 (PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */
- 0xa0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data0 */
- 0xa4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data1 */
- 0xa8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data2 */
- 0xac (PIN_OUTPUT | MUX_MODE0) /* lcd_data3 */
- 0xb0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data4 */
- 0xb4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data5 */
- 0xb8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data6 */
- 0xbc (PIN_OUTPUT | MUX_MODE0) /* lcd_data7 */
- 0xc0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data8 */
- 0xc4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data9 */
- 0xc8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data10 */
- 0xcc (PIN_OUTPUT | MUX_MODE0) /* lcd_data11 */
- 0xd0 (PIN_OUTPUT | MUX_MODE0) /* lcd_data12 */
- 0xd4 (PIN_OUTPUT | MUX_MODE0) /* lcd_data13 */
- 0xd8 (PIN_OUTPUT | MUX_MODE0) /* lcd_data14 */
- 0xdc (PIN_OUTPUT | MUX_MODE0) /* lcd_data15 */
- 0xe0 (PIN_OUTPUT | MUX_MODE0) /* lcd_vsync */
- 0xe4 (PIN_OUTPUT | MUX_MODE0) /* lcd_hsync */
- 0xe8 (PIN_OUTPUT | MUX_MODE0) /* lcd_pclk */
- 0xec (PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en */
+ AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */
+ AM33XX_IOPAD(0x8a0, PIN_OUTPUT | MUX_MODE0) /* lcd_data0 */
+ AM33XX_IOPAD(0x8a4, PIN_OUTPUT | MUX_MODE0) /* lcd_data1 */
+ AM33XX_IOPAD(0x8a8, PIN_OUTPUT | MUX_MODE0) /* lcd_data2 */
+ AM33XX_IOPAD(0x8ac, PIN_OUTPUT | MUX_MODE0) /* lcd_data3 */
+ AM33XX_IOPAD(0x8b0, PIN_OUTPUT | MUX_MODE0) /* lcd_data4 */
+ AM33XX_IOPAD(0x8b4, PIN_OUTPUT | MUX_MODE0) /* lcd_data5 */
+ AM33XX_IOPAD(0x8b8, PIN_OUTPUT | MUX_MODE0) /* lcd_data6 */
+ AM33XX_IOPAD(0x8bc, PIN_OUTPUT | MUX_MODE0) /* lcd_data7 */
+ AM33XX_IOPAD(0x8c0, PIN_OUTPUT | MUX_MODE0) /* lcd_data8 */
+ AM33XX_IOPAD(0x8c4, PIN_OUTPUT | MUX_MODE0) /* lcd_data9 */
+ AM33XX_IOPAD(0x8c8, PIN_OUTPUT | MUX_MODE0) /* lcd_data10 */
+ AM33XX_IOPAD(0x8cc, PIN_OUTPUT | MUX_MODE0) /* lcd_data11 */
+ AM33XX_IOPAD(0x8d0, PIN_OUTPUT | MUX_MODE0) /* lcd_data12 */
+ AM33XX_IOPAD(0x8d4, PIN_OUTPUT | MUX_MODE0) /* lcd_data13 */
+ AM33XX_IOPAD(0x8d8, PIN_OUTPUT | MUX_MODE0) /* lcd_data14 */
+ AM33XX_IOPAD(0x8dc, PIN_OUTPUT | MUX_MODE0) /* lcd_data15 */
+ AM33XX_IOPAD(0x8e0, PIN_OUTPUT | MUX_MODE0) /* lcd_vsync */
+ AM33XX_IOPAD(0x8e4, PIN_OUTPUT | MUX_MODE0) /* lcd_hsync */
+ AM33XX_IOPAD(0x8e8, PIN_OUTPUT | MUX_MODE0) /* lcd_pclk */
+ AM33XX_IOPAD(0x8ec, PIN_OUTPUT | MUX_MODE0) /* lcd_ac_bias_en */
>;
};
nxp_hdmi_off_pins: pinmux_nxp_hdmi_off_pins {
pinctrl-single,pins = <
- 0x1b0 (PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */
+ AM33XX_IOPAD(0x9b0, PIN_OUTPUT | MUX_MODE3) /* xdma_event_intr0.clkout1 */
>;
};
leds_base_pins: pinmux_leds_base_pins {
pinctrl-single,pins = <
- 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
- 0x88 (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn3.gpio2_0 */
+ AM33XX_IOPAD(0x854, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a5.gpio1_21 */
+ AM33XX_IOPAD(0x888, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_csn3.gpio2_0 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-bone-common.dtsi b/arch/arm/boot/dts/am335x-bone-common.dtsi
index fec7834..5d370d5 100644
--- a/arch/arm/boot/dts/am335x-bone-common.dtsi
+++ b/arch/arm/boot/dts/am335x-bone-common.dtsi
@@ -383,8 +383,7 @@
bus-width = <0x4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
- cd-inverted;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&aes {
diff --git a/arch/arm/boot/dts/am335x-bonegreen.dts b/arch/arm/boot/dts/am335x-bonegreen.dts
new file mode 100644
index 0000000..0f65bda
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-bonegreen.dts
@@ -0,0 +1,53 @@
+/*
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+#include "am335x-bone-common.dtsi"
+
+/ {
+ model = "TI AM335x BeagleBone Green";
+ compatible = "ti,am335x-bone-green", "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
+};
+
+&ldo3_reg {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+};
+
+&mmc1 {
+ vmmc-supply = <&vmmcsd_fixed>;
+};
+
+&mmc2 {
+ vmmc-supply = <&vmmcsd_fixed>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ bus-width = <8>;
+ status = "okay";
+};
+
+&am33xx_pinmux {
+ uart2_pins: uart2_pins {
+ pinctrl-single,pins = <
+ 0x150 (PIN_INPUT | MUX_MODE1) /* spi0_sclk.uart2_rxd */
+ 0x154 (PIN_OUTPUT | MUX_MODE1) /* spi0_d0.uart2_txd */
+ >;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+ status = "okay";
+};
+
+&rtc {
+ system-power-controller;
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index 1942a5c..d9d00ab 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -737,7 +737,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&mmc3 {
diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 315bb02..89442e9 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -647,7 +647,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&sham {
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index c0e1135..54f1135 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -56,41 +56,41 @@
&am33xx_pinmux {
i2c0_pins: pinmux_i2c0_pins {
pinctrl-single,pins = <
- 0x188 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
- 0x18c (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ AM33XX_IOPAD(0x988, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ AM33XX_IOPAD(0x98c, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c0_scl.i2c0_scl */
>;
};
nandflash_pins: pinmux_nandflash_pins {
pinctrl-single,pins = <
- 0x0 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
- 0x4 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
- 0x8 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
- 0xc (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
- 0x10 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
- 0x14 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
- 0x18 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
- 0x1c (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
- 0x70 (PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
- 0x74 (PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
- 0x7c (PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
- 0x90 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
- 0x94 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
- 0x98 (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
- 0x9c (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
+ AM33XX_IOPAD(0x800, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad0.gpmc_ad0 */
+ AM33XX_IOPAD(0x804, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad1.gpmc_ad1 */
+ AM33XX_IOPAD(0x808, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad2.gpmc_ad2 */
+ AM33XX_IOPAD(0x80c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad3.gpmc_ad3 */
+ AM33XX_IOPAD(0x810, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad4.gpmc_ad4 */
+ AM33XX_IOPAD(0x814, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad5.gpmc_ad5 */
+ AM33XX_IOPAD(0x818, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad6.gpmc_ad6 */
+ AM33XX_IOPAD(0x81c, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_ad7.gpmc_ad7 */
+ AM33XX_IOPAD(0x870, PIN_INPUT_PULLUP | MUX_MODE0) /* gpmc_wait0.gpmc_wait0 */
+ AM33XX_IOPAD(0x874, PIN_INPUT_PULLUP | MUX_MODE7) /* gpmc_wpn.gpio0_30 */
+ AM33XX_IOPAD(0x87c, PIN_OUTPUT | MUX_MODE0) /* gpmc_csn0.gpmc_csn0 */
+ AM33XX_IOPAD(0x890, PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale.gpmc_advn_ale */
+ AM33XX_IOPAD(0x894, PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren.gpmc_oen_ren */
+ AM33XX_IOPAD(0x898, PIN_OUTPUT | MUX_MODE0) /* gpmc_wen.gpmc_wen */
+ AM33XX_IOPAD(0x89c, PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle.gpmc_be0n_cle */
>;
};
uart0_pins: pinmux_uart0_pins {
pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
- 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ AM33XX_IOPAD(0x970, PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ AM33XX_IOPAD(0x974, PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
>;
};
leds_pins: pinmux_leds_pins {
pinctrl-single,pins = <
- 0x5c (PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
+ AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLDOWN | MUX_MODE7) /* gpmc_a7.gpio1_23 */
>;
};
};
diff --git a/arch/arm/boot/dts/am335x-phycore-som.dtsi b/arch/arm/boot/dts/am335x-phycore-som.dtsi
index 5dd084f..2f43e45 100644
--- a/arch/arm/boot/dts/am335x-phycore-som.dtsi
+++ b/arch/arm/boot/dts/am335x-phycore-som.dtsi
@@ -29,8 +29,17 @@
reg = <0x80000000 0x10000000>; /* 256 MB */
};
- vbat: fixedregulator@0 {
- compatible = "regulator-fixed";
+ regulators {
+ compatible = "simple-bus";
+
+ vcc5v: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc5v";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
};
};
@@ -233,14 +242,14 @@
#include "tps65910.dtsi"
&tps {
- vcc1-supply = <&vbat>;
- vcc2-supply = <&vbat>;
- vcc3-supply = <&vbat>;
- vcc4-supply = <&vbat>;
- vcc5-supply = <&vbat>;
- vcc6-supply = <&vbat>;
- vcc7-supply = <&vbat>;
- vccio-supply = <&vbat>;
+ vcc1-supply = <&vcc5v>;
+ vcc2-supply = <&vcc5v>;
+ vcc3-supply = <&vcc5v>;
+ vcc4-supply = <&vcc5v>;
+ vcc5-supply = <&vcc5v>;
+ vcc6-supply = <&vcc5v>;
+ vcc7-supply = <&vcc5v>;
+ vccio-supply = <&vcc5v>;
regulators {
vrtc_reg: regulator@0 {
@@ -311,13 +320,6 @@
};
};
-&vbat {
- regulator-name = "vbat";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-boot-on;
-};
-
/* SPI Busses */
&am33xx_pinmux {
spi0_pins: pinmux_spi0 {
diff --git a/arch/arm/boot/dts/am335x-wega.dtsi b/arch/arm/boot/dts/am335x-wega.dtsi
index 5e541bd..2cecb39 100644
--- a/arch/arm/boot/dts/am335x-wega.dtsi
+++ b/arch/arm/boot/dts/am335x-wega.dtsi
@@ -11,6 +11,17 @@
model = "Phytec AM335x phyBOARD-WEGA";
compatible = "phytec,am335x-wega", "phytec,am335x-phycore-som", "ti,am33xx";
+ regulators {
+ compatible = "simple-bus";
+
+ vcc3v3: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+ };
};
/* CAN Busses */
@@ -80,7 +91,7 @@
};
&mmc1 {
- vmmc-supply = <&vmmc_reg>;
+ vmmc-supply = <&vcc3v3>;
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index d83ff9c..de8791a 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -74,7 +74,7 @@
reg = <0x48240200 0x100>;
interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
- clocks = <&dpll_mpu_m2_ck>;
+ clocks = <&mpu_periphclk>;
};
local_timer: timer@48240600 {
@@ -82,7 +82,7 @@
reg = <0x48240600 0x100>;
interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
interrupt-parent = <&gic>;
- clocks = <&dpll_mpu_m2_ck>;
+ clocks = <&mpu_periphclk>;
};
l2-cache-controller@48242000 {
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index 22038f2..d2450ab 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -304,6 +304,13 @@
>;
};
+ dcan0_sleep: dcan0_sleep_pins {
+ pinctrl-single,pins = <
+ 0x178 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_ctsn.gpio0_12 */
+ 0x17c (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rtsn.gpio0_13 */
+ >;
+ };
+
dcan1_default: dcan1_default_pins {
pinctrl-single,pins = <
0x180 (PIN_OUTPUT | MUX_MODE2) /* uart1_rxd.d_can1_tx */
@@ -311,6 +318,13 @@
>;
};
+ dcan1_sleep: dcan1_sleep_pins {
+ pinctrl-single,pins = <
+ 0x180 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_rxd.gpio0_14 */
+ 0x184 (PIN_INPUT_PULLUP | MUX_MODE7) /* uart1_txd.gpio0_15 */
+ >;
+ };
+
vpfe0_pins_default: vpfe0_pins_default {
pinctrl-single,pins = <
0x1B0 (PIN_INPUT_PULLUP | MUX_MODE0) /* cam0_hd mode 0*/
@@ -581,8 +595,17 @@
attb-gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+ /*
+ * 0x264 represents the offset of padconf register of
+ * gpio3_22 from am43xx_pinmux base.
+ */
+ interrupts-extended = <&gpio3 22 IRQ_TYPE_NONE>,
+ <&am43xx_pinmux 0x264>;
+ interrupt-names = "tsc", "wakeup";
+
touchscreen-size-x = <1024>;
touchscreen-size-y = <600>;
+ wakeup-source;
};
ov2659@30 {
@@ -689,7 +712,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
/* eMMC sits on mmc2 */
@@ -886,14 +909,16 @@
};
&dcan0 {
- pinctrl-names = "default";
+ pinctrl-names = "default", "sleep";
pinctrl-0 = <&dcan0_default>;
+ pinctrl-1 = <&dcan0_sleep>;
status = "okay";
};
&dcan1 {
- pinctrl-names = "default";
+ pinctrl-names = "default", "sleep";
pinctrl-0 = <&dcan1_default>;
+ pinctrl-1 = <&dcan1_sleep>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts
index af25801..337fb91 100644
--- a/arch/arm/boot/dts/am437x-idk-evm.dts
+++ b/arch/arm/boot/dts/am437x-idk-evm.dts
@@ -325,7 +325,7 @@
pinctrl-1 = <&mmc1_pins_sleep>;
vmmc-supply = <&v3_3d>;
bus-width = <4>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&qspi {
diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts
index 0bb36e9..63de2a1 100644
--- a/arch/arm/boot/dts/am437x-sk-evm.dts
+++ b/arch/arm/boot/dts/am437x-sk-evm.dts
@@ -563,7 +563,7 @@
vmmc-supply = <&dcdc4>;
bus-width = <4>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&usb2_phy1 {
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index 86c2dfb..47954ed 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -376,7 +376,7 @@
bus-width = <4>;
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins>;
- cd-gpios = <&gpio0 6 GPIO_ACTIVE_HIGH>;
+ cd-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
};
&mac {
diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi
index cc88728..a38af2b 100644
--- a/arch/arm/boot/dts/am43xx-clocks.dtsi
+++ b/arch/arm/boot/dts/am43xx-clocks.dtsi
@@ -259,6 +259,14 @@
ti,invert-autoidle-bit;
};
+ mpu_periphclk: mpu_periphclk {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&dpll_mpu_m2_ck>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ };
+
dpll_ddr_ck: dpll_ddr_ck {
#clock-cells = <0>;
compatible = "ti,am3-dpll-clock";
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
index d55e3ea..00352e7 100644
--- a/arch/arm/boot/dts/am57xx-beagle-x15.dts
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -35,6 +35,14 @@
regulator-max-microvolt = <3300000>;
};
+ aic_dvdd: fixedregulator-aic_dvdd {
+ compatible = "regulator-fixed";
+ regulator-name = "aic_dvdd_fixed";
+ vin-supply = <&vdd_3v3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
vtt_fixed: fixedregulator-vtt {
/* TPS51200 */
compatible = "regulator-fixed";
@@ -142,6 +150,32 @@
};
};
};
+
+ sound0: sound@0 {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "BeagleBoard-X15";
+ simple-audio-card,widgets =
+ "Line", "Line Out",
+ "Line", "Line In";
+ simple-audio-card,routing =
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "MIC2L", "Line In",
+ "MIC2R", "Line In";
+ simple-audio-card,format = "dsp_b";
+ simple-audio-card,bitclock-master = <&sound0_master>;
+ simple-audio-card,frame-master = <&sound0_master>;
+ simple-audio-card,bitclock-inversion;
+
+ simple-audio-card,cpu {
+ sound-dai = <&mcasp3>;
+ };
+
+ sound0_master: simple-audio-card,codec {
+ sound-dai = <&tlv320aic3104>;
+ clocks = <&clkout2_clk>;
+ };
+ };
};
&dra7_pmx_core {
@@ -326,6 +360,36 @@
0x370 (PIN_OUTPUT | MUX_MODE14) /* gpio6_28 LS_OE */
>;
};
+
+ clkout2_pins_default: clkout2_pins_default {
+ pinctrl-single,pins = <
+ 0x294 (PIN_OUTPUT_PULLDOWN | MUX_MODE9) /* xref_clk0.clkout2 */
+ >;
+ };
+
+ clkout2_pins_sleep: clkout2_pins_sleep {
+ pinctrl-single,pins = <
+ 0x294 (PIN_INPUT | MUX_MODE15) /* xref_clk0.clkout2 */
+ >;
+ };
+
+ mcasp3_pins_default: mcasp3_pins_default {
+ pinctrl-single,pins = <
+ 0x324 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx.mcasp3_aclkx */
+ 0x328 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx.mcasp3_fsx */
+ 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0.mcasp3_axr0 */
+ 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1.mcasp3_axr1 */
+ >;
+ };
+
+ mcasp3_pins_sleep: mcasp3_pins_sleep {
+ pinctrl-single,pins = <
+ 0x324 (PIN_INPUT | MUX_MODE15)
+ 0x328 (PIN_INPUT | MUX_MODE15)
+ 0x32c (PIN_INPUT | MUX_MODE15)
+ 0x330 (PIN_INPUT | MUX_MODE15)
+ >;
+ };
};
&i2c1 {
@@ -511,6 +575,22 @@
interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
#thermal-sensor-cells = <1>;
};
+
+ tlv320aic3104: tlv320aic3104@18 {
+ #sound-dai-cells = <0>;
+ compatible = "ti,tlv320aic3104";
+ reg = <0x18>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&clkout2_pins_default>;
+ pinctrl-1 = <&clkout2_pins_sleep>;
+ status = "okay";
+ adc-settle-ms = <40>;
+
+ AVDD-supply = <&vdd_3v3>;
+ IOVDD-supply = <&vdd_3v3>;
+ DRVDD-supply = <&vdd_3v3>;
+ DVDD-supply = <&aic_dvdd>;
+ };
};
&i2c3 {
@@ -524,6 +604,7 @@
reg = <0x6f>;
interrupts-extended = <&crossbar_mpu GIC_SPI 2 IRQ_TYPE_EDGE_RISING>,
<&dra7_pmx_core 0x424>;
+ interrupt-names = "irq", "wakeup";
pinctrl-names = "default";
pinctrl-0 = <&mcp79410_pins_default>;
@@ -586,7 +667,7 @@
vmmc-supply = <&ldo1_reg>;
bus-width = <4>;
- cd-gpios = <&gpio6 27 0>; /* gpio 219 */
+ cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>; /* gpio 219 */
};
&mmc2 {
@@ -709,3 +790,38 @@
&pcie1 {
gpios = <&gpio2 8 GPIO_ACTIVE_LOW>;
};
+
+&mcasp3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mcasp3_pins_default>;
+ pinctrl-1 = <&mcasp3_pins_sleep>;
+ status = "okay";
+
+ op-mode = <0>; /* MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ /* 4 serializers */
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 1 2 0 0
+ >;
+};
+
+&mailbox5 {
+ status = "okay";
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ status = "okay";
+ };
+};
+
+&mailbox6 {
+ status = "okay";
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/animeo_ip.dts b/arch/arm/boot/dts/animeo_ip.dts
index 4e0ad3b..0962f2f 100644
--- a/arch/arm/boot/dts/animeo_ip.dts
+++ b/arch/arm/boot/dts/animeo_ip.dts
@@ -155,21 +155,21 @@
label = "keyswitch_in";
gpios = <&pioB 1 GPIO_ACTIVE_HIGH>;
linux,code = <28>;
- gpio-key,wakeup;
+ wakeup-source;
};
error_in {
label = "error_in";
gpios = <&pioB 2 GPIO_ACTIVE_HIGH>;
linux,code = <29>;
- gpio-key,wakeup;
+ wakeup-source;
};
btn {
label = "btn";
gpios = <&pioC 23 GPIO_ACTIVE_HIGH>;
linux,code = <31>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index 03542f7..bb280de 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -74,7 +74,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
internal-regs {
serial@12000 {
diff --git a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
index af4dc54..e2a363b 100644
--- a/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
+++ b/arch/arm/boot/dts/armada-370-dlink-dns327l.dts
@@ -69,7 +69,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 0f40d5d..3aa980a 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -61,7 +61,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
pcie-controller {
status = "okay";
@@ -138,6 +139,10 @@
phy-mode = "rgmii-id";
};
+ crypto@90000 {
+ status = "okay";
+ };
+
mvsdio@d4000 {
pinctrl-0 = <&sdio_pins3>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index a312078..5555875 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -63,7 +63,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
pcie-controller {
status = "okay";
@@ -82,6 +83,12 @@
};
internal-regs {
+
+ /* RTC is provided by Intersil ISL12057 I2C RTC chip */
+ rtc@10300 {
+ status = "disabled";
+ };
+
serial@12000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index 00540f2..78b563c 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -63,7 +63,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
pcie-controller {
status = "okay";
@@ -82,6 +83,12 @@
};
internal-regs {
+
+ /* RTC is provided by Intersil ISL12057 I2C RTC chip */
+ rtc@10300 {
+ status = "disabled";
+ };
+
serial@12000 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index 19475e6..fbef730 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -74,7 +74,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-2bay.dts b/arch/arm/boot/dts/armada-370-seagate-nas-2bay.dts
new file mode 100644
index 0000000..fef0110
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-2bay.dts
@@ -0,0 +1,36 @@
+/*
+ * Device Tree file for Seagate NAS 2-Bay (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Vincent Donnefort <vdonnefort@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * Here are some information allowing to identify the device:
+ *
+ * Product name : Seagate NAS 2-Bay
+ * Code name (board/PCB) : Dart 2-Bay
+ * Model name (case sticker) : SRPD20
+ * Material desc (product spec) : STCTxxxxxxx
+ */
+
+/dts-v1/;
+#include "armada-370-seagate-nas-xbay.dtsi"
+
+/ {
+ model = "Seagate NAS 2-Bay (Dart, SRPD20)";
+ compatible = "seagate,dart-2", "marvell,armada370", "marvell,armada-370-xp";
+
+ gpio-fan {
+ gpio-fan,speed-map =
+ < 0 3
+ 950 2
+ 1400 1
+ 1800 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts b/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts
new file mode 100644
index 0000000..ae2e1fe
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-4bay.dts
@@ -0,0 +1,133 @@
+/*
+ * Device Tree file for Seagate NAS 4-Bay (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Vincent Donnefort <vdonnefort@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * Here are some information allowing to identify the device:
+ *
+ * Product name : Seagate NAS 4-Bay
+ * Code name (board/PCB) : Dart 4-Bay
+ * Model name (case sticker) : SRPD40
+ * Material desc (product spec) : STCUxxxxxxx
+ */
+
+/dts-v1/;
+#include "armada-370-seagate-nas-xbay.dtsi"
+#include <dt-bindings/leds/leds-ns2.h>
+
+/ {
+ model = "Seagate NAS 4-Bay (Dart, SRPD40)";
+ compatible = "seagate,dart-4", "marvell,armada370", "marvell,armada-370-xp";
+
+ soc {
+ pcie-controller {
+ /* SATA AHCI controller 88SE9170 */
+ pcie@1,0 {
+ status = "okay";
+ };
+ };
+
+ internal-regs {
+ mdio {
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+
+ ethernet@74000 {
+ status = "okay";
+ pinctrl-0 = <&ge1_rgmii_pins>;
+ pinctrl-names = "default";
+ phy = <&phy1>;
+ phy-mode = "rgmii-id";
+ };
+
+ i2c@11000 {
+ /* I2C GPIO expander (PCA9554A) */
+ pca9554: pca9554@21 {
+ compatible = "nxp,pca9554";
+ reg = <0x21>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
+ };
+ };
+ };
+
+ regulators {
+ regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "SATA2 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&pca9554 6 GPIO_ACTIVE_HIGH>;
+ };
+ regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ regulator-name = "SATA3 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&pca9554 7 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ gpio-leds {
+ red-sata2 {
+ label = "dart:red:sata2";
+ gpios = <&pca9554 0 GPIO_ACTIVE_LOW>;
+ };
+ red-sata3 {
+ label = "dart:red:sata3";
+ gpios = <&pca9554 3 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds-ns2 {
+ compatible = "lacie,ns2-leds";
+
+ white-sata2 {
+ label = "dart:white:sata2";
+ cmd-gpio = <&pca9554 1 GPIO_ACTIVE_HIGH>;
+ slow-gpio = <&pca9554 2 GPIO_ACTIVE_HIGH>;
+ num-modes = <4>;
+ modes-map = <NS_V2_LED_SATA 0 0
+ NS_V2_LED_OFF 0 1
+ NS_V2_LED_ON 1 0
+ NS_V2_LED_ON 1 1>;
+ };
+ white-sata3 {
+ label = "dart:white:sata3";
+ cmd-gpio = <&pca9554 4 GPIO_ACTIVE_HIGH>;
+ slow-gpio = <&pca9554 5 GPIO_ACTIVE_HIGH>;
+ num-modes = <4>;
+ modes-map = <NS_V2_LED_SATA 0 0
+ NS_V2_LED_OFF 0 1
+ NS_V2_LED_ON 1 0
+ NS_V2_LED_ON 1 1>;
+ };
+ };
+
+ gpio-fan {
+ gpio-fan,speed-map =
+ < 0 3
+ 800 2
+ 1050 1
+ 1300 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
new file mode 100644
index 0000000..3036e25
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-nas-xbay.dtsi
@@ -0,0 +1,231 @@
+/*
+ * Device Tree common file for the Seagate NAS 2 and 4-bay (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Vincent Donnefort <vdonnefort@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/*
+ * TODO: add support for the white SATA LEDs associated with HDD 0 and 1.
+ */
+
+#include "armada-370.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; /* 512 MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+ pcie-controller {
+ status = "okay";
+
+ /* USB 3.0 bridge ASM1042A */
+ pcie@2,0 {
+ status = "okay";
+ };
+ };
+
+ internal-regs {
+ serial@12000 {
+ status = "okay";
+ };
+
+ sata@a0000 {
+ nr-ports = <2>;
+ status = "okay";
+ };
+
+ mdio {
+ pinctrl-0 = <&mdio_pins>;
+ pinctrl-names = "default";
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
+ ethernet@70000 {
+ status = "okay";
+ pinctrl-0 = <&ge0_rgmii_pins>;
+ pinctrl-names = "default";
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ };
+
+ i2c@11000 {
+ status = "okay";
+ pinctrl-0 = <&i2c0_pins>;
+ pinctrl-names = "default";
+ clock-frequency = <100000>;
+
+ /* RTC - NXP 8563T (second source) */
+ rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ interrupts = <110>;
+ };
+ /* RTC - MCP7940NT */
+ rtc@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+ interrupts = <110>;
+ };
+ };
+
+ nand@d0000 {
+ status = "okay";
+ num-cs = <1>;
+ marvell,nand-keep-config;
+ marvell,nand-enable-arbiter;
+ nand-on-flash-bbt;
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x300000>;
+ };
+ partition@300000 {
+ label = "device-tree";
+ reg = <0x300000 0x20000>;
+ };
+ partition@320000 {
+ label = "linux";
+ reg = <0x320000 0x2000000>;
+ };
+ partition@2320000 {
+ label = "rootfs";
+ reg = <0x2320000 0xdce0000>;
+ };
+ };
+ };
+
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+
+ regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "SATA0 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+ };
+ regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "SATA1 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ gpio-fan {
+ compatible = "gpio-fan";
+ gpios = <&gpio2 0 GPIO_ACTIVE_HIGH
+ &gpio2 1 GPIO_ACTIVE_HIGH>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ button@1 {
+ label = "Power button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
+ debounce-interval = <100>;
+ };
+ button@2 {
+ label = "Backup button";
+ linux,code = <KEY_OPTION>;
+ gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
+ debounce-interval = <100>;
+ };
+ button@3 {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
+ debounce-interval = <100>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ white-power {
+ label = "dart:white:power";
+ gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "timer";
+
+ };
+ red-power {
+ label = "dart:red:power";
+ gpios = <&gpio1 31 GPIO_ACTIVE_HIGH>;
+ };
+ red-sata0 {
+ label = "dart:red:sata0";
+ gpios = <&gpio1 15 GPIO_ACTIVE_LOW>;
+ };
+ red-sata1 {
+ label = "dart:red:sata1";
+ gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio_poweroff {
+ compatible = "gpio-poweroff";
+ gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
+ };
+};
+
+&pinctrl {
+ pinctrl-0 = <&hdd0_led_sata_pin>, <&hdd1_led_sata_pin>;
+ pinctrl-names = "default";
+
+ hdd0_led_sata_pin: hdd0-led-sata-pin {
+ marvell,pins = "mpp48";
+ marvell,function = "sata1";
+ };
+ hdd0_led_gpio_pin: hdd0-led-gpio-pin {
+ marvell,pins = "mpp48";
+ marvell,function = "gpio";
+ };
+ hdd1_led_sata_pin: hdd1-led-sata-pin {
+ marvell,pins = "mpp57";
+ marvell,function = "sata0";
+ };
+ hdd1_led_gpio_pin: hdd1-led-gpio-pin {
+ marvell,pins = "mpp57";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-personal-cloud-2bay.dts b/arch/arm/boot/dts/armada-370-seagate-personal-cloud-2bay.dts
new file mode 100644
index 0000000..3c91f98
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-personal-cloud-2bay.dts
@@ -0,0 +1,51 @@
+/*
+ * Device Tree file for Seagate Personal Cloud NAS 2-Bay (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Simon Guinot <simon.guinot@sequanux.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.
+ */
+
+/*
+ * Here are some information allowing to identify the device:
+ *
+ * Product name : Seagate Personal Cloud 2-Bay
+ * Code name (board/PCB) : Cumulus Max
+ * Model name (case sticker) : SRN22C
+ * Material desc (product spec) : STCSxxxxxxx
+ */
+
+/dts-v1/;
+#include "armada-370-seagate-personal-cloud.dtsi"
+
+/ {
+ model = "Seagate Personal Cloud 2-Bay (Cumulus, SRN22C)";
+ compatible = "seagate,cumulus-max", "marvell,armada370", "marvell,armada-370-xp";
+
+ soc {
+ internal-regs {
+ sata@a0000 {
+ status = "okay";
+ nr-ports = <2>;
+ };
+ };
+ };
+
+ regulators {
+ regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "SATA1 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 22 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dts b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dts
new file mode 100644
index 0000000..aad39e9
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dts
@@ -0,0 +1,37 @@
+/*
+ * Device Tree file for Seagate Personal Cloud NAS (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Simon Guinot <simon.guinot@sequanux.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.
+ */
+
+/*
+ * Here are some information allowing to identify the device:
+ *
+ * Product name : Seagate Personal Cloud
+ * Code name (board/PCB) : Cumulus
+ * Model name (case sticker) : SRN21C
+ * Material desc (product spec) : STCRxxxxxxx
+ */
+
+/dts-v1/;
+#include "armada-370-seagate-personal-cloud.dtsi"
+
+/ {
+ model = "Seagate Personal Cloud (Cumulus, SRN21C)";
+ compatible = "seagate,cumulus", "marvell,armada370", "marvell,armada-370-xp";
+
+ soc {
+ internal-regs {
+ sata@a0000 {
+ status = "okay";
+ nr-ports = <1>;
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
new file mode 100644
index 0000000..1aba08e
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-seagate-personal-cloud.dtsi
@@ -0,0 +1,178 @@
+/*
+ * Device Tree common file for the Seagate Personal Cloud NAS 1 and 2-Bay
+ * (Armada 370 SoC).
+ *
+ * Copyright (C) 2015 Seagate
+ *
+ * Author: Simon Guinot <simon.guinot@sequanux.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.
+ */
+
+/*
+ * TODO: add support for the white SATA LED.
+ */
+
+#include "armada-370.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; /* 512 MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+ pcie-controller {
+ status = "okay";
+
+ /* USB 3.0 Bridge ASM1042A */
+ pcie@1,0 {
+ status = "okay";
+ };
+ };
+
+ internal-regs {
+ coherency-fabric@20200 {
+ broken-idle;
+ };
+
+ serial@12000 {
+ status = "okay";
+ };
+
+ mdio {
+ pinctrl-0 = <&mdio_pins>;
+ pinctrl-names = "default";
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
+ ethernet@74000 {
+ status = "okay";
+ pinctrl-0 = <&ge1_rgmii_pins>;
+ pinctrl-names = "default";
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ };
+
+ spi@10600 {
+ status = "okay";
+ pinctrl-0 = <&spi0_pins2>;
+ pinctrl-names = "default";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /* MX25L8006E */
+ compatible = "mxicy,mx25l8005", "jedec,spi-nor";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <50000000>;
+
+ partition@0 {
+ label = "u-boot";
+ reg = <0x0 0x100000>;
+ };
+ };
+ };
+
+ usb@50000 {
+ status = "okay";
+ };
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "USB Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 27 GPIO_ACTIVE_LOW>;
+ };
+ regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "SATA0 power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ button@1 {
+ label = "Power button";
+ linux,code = <KEY_POWER>;
+ gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
+ debounce-interval = <100>;
+ };
+ button@2 {
+ label = "Reset Button";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
+ debounce-interval = <100>;
+ };
+ button@3 {
+ label = "USB VBUS error";
+ linux,code = <KEY_UNKNOWN>;
+ gpios = <&gpio1 21 GPIO_ACTIVE_LOW>;
+ debounce-interval = <100>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ red-sata0 {
+ label = "cumulus:red:sata0";
+ gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+ };
+
+ gpio_poweroff {
+ compatible = "gpio-poweroff";
+ gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&pinctrl {
+ pinctrl-0 = <&sata_led_pin>;
+ pinctrl-names = "default";
+
+ sata_led_pin: sata-led-pin {
+ marvell,pins = "mpp60";
+ marvell,function = "sata0";
+ };
+ gpio_led_pin: gpio-led-pin {
+ marvell,pins = "mpp60";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
index 4f49243..836bcc0 100644
--- a/arch/arm/boot/dts/armada-370-synology-ds213j.dts
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -77,7 +77,8 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x01) 0 0xf1100000 0x10000>;
internal-regs {
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 53a1a5a..3b06aa8 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -256,6 +256,11 @@
reg = <0x20800 0x8>;
};
+ cpu-config@21000 {
+ compatible = "marvell,armada-370-cpu-config";
+ reg = <0x21000 0x8>;
+ };
+
audio_controller: audio-controller@30000 {
#sound-dai-cells = <1>;
compatible = "marvell,armada370-audio";
@@ -319,6 +324,38 @@
ethernet@74000 {
compatible = "marvell,armada-370-neta";
};
+
+ crypto@90000 {
+ compatible = "marvell,armada-370-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <48>;
+ clocks = <&gateclk 23>;
+ clock-names = "cesa0";
+ marvell,crypto-srams = <&crypto_sram>;
+ marvell,crypto-sram-size = <0x7e0>;
+ };
+ };
+
+ crypto_sram: sa-sram {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x01) 0 0x800>;
+ reg-names = "sram";
+ clocks = <&gateclk 23>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x01) 0 0x800>;
+
+ /*
+ * The Armada 370 has an erratum preventing the use of
+ * the standard workflow for CPU idle support (relying
+ * on the BootROM code to enter/exit idle state).
+ * Reserve some amount of the crypto SRAM to put the
+ * cpuidle workaround.
+ */
+ idle-sram@0 {
+ reg = <0x0 0x20>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/armada-375-db.dts b/arch/arm/boot/dts/armada-375-db.dts
index 5711b97..cded5f0 100644
--- a/arch/arm/boot/dts/armada-375-db.dts
+++ b/arch/arm/boot/dts/armada-375-db.dts
@@ -65,7 +65,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0xf1110000 0x10000>;
internal-regs {
spi@10600 {
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index e9a3817..7ccce75 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -513,6 +513,21 @@
};
};
+ crypto@90000 {
+ compatible = "marvell,armada-375-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gateclk 30>, <&gateclk 31>,
+ <&gateclk 28>, <&gateclk 29>;
+ clock-names = "cesa0", "cesa1",
+ "cesaz0", "cesaz1";
+ marvell,crypto-srams = <&crypto_sram0>,
+ <&crypto_sram1>;
+ marvell,crypto-sram-size = <0x800>;
+ };
+
sata@a0000 {
compatible = "marvell,orion-sata";
reg = <0xa0000 0x5000>;
@@ -619,5 +634,23 @@
};
};
+
+ crypto_sram0: sa-sram0 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x09) 0 0x800>;
+ clocks = <&gateclk 30>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x09) 0 0x800>;
+ };
+
+ crypto_sram1: sa-sram1 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x05) 0 0x800>;
+ clocks = <&gateclk 31>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x05) 0 0x800>;
+ };
};
};
diff --git a/arch/arm/boot/dts/armada-385-db-ap.dts b/arch/arm/boot/dts/armada-385-db-ap.dts
index 4047621..acd5b15 100644
--- a/arch/arm/boot/dts/armada-385-db-ap.dts
+++ b/arch/arm/boot/dts/armada-385-db-ap.dts
@@ -59,7 +59,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
spi1: spi@10680 {
diff --git a/arch/arm/boot/dts/armada-385-linksys.dtsi b/arch/arm/boot/dts/armada-385-linksys.dtsi
index 74a9c6b..3710755 100644
--- a/arch/arm/boot/dts/armada-385-linksys.dtsi
+++ b/arch/arm/boot/dts/armada-385-linksys.dtsi
@@ -57,7 +57,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0xf1110000 0x10000>;
internal-regs {
diff --git a/arch/arm/boot/dts/armada-388-db.dts b/arch/arm/boot/dts/armada-388-db.dts
index 91ac8c1..ff47af5 100644
--- a/arch/arm/boot/dts/armada-388-db.dts
+++ b/arch/arm/boot/dts/armada-388-db.dts
@@ -64,7 +64,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
spi@10600 {
diff --git a/arch/arm/boot/dts/armada-388-gp.dts b/arch/arm/boot/dts/armada-388-gp.dts
index 353c925..a633be3 100644
--- a/arch/arm/boot/dts/armada-388-gp.dts
+++ b/arch/arm/boot/dts/armada-388-gp.dts
@@ -58,7 +58,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
spi@10600 {
@@ -205,8 +207,21 @@
sdhci@d8000 {
pinctrl-names = "default";
pinctrl-0 = <&sdhci_pins>;
- cd-gpios = <&expander0 5 GPIO_ACTIVE_LOW>;
no-1-8-v;
+ /*
+ * A388-GP board v1.5 and higher replace
+ * hitherto card detection method based on GPIO
+ * with the one using DAT3 pin. As they are
+ * incompatible, software-based polling is
+ * enabled with 'broken-cd' property. For boards
+ * older than v1.5 it can be replaced with:
+ * 'cd-gpios = <&expander0 5 GPIO_ACTIVE_LOW>;',
+ * whereas for the newer ones following can be
+ * used instead:
+ * 'dat3-cd;'
+ * 'cd-inverted;'
+ */
+ broken-cd;
wp-inverted;
bus-width = <8>;
status = "okay";
diff --git a/arch/arm/boot/dts/armada-388-rd.dts b/arch/arm/boot/dts/armada-388-rd.dts
index b657b16..853f973 100644
--- a/arch/arm/boot/dts/armada-388-rd.dts
+++ b/arch/arm/boot/dts/armada-388-rd.dts
@@ -65,7 +65,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x19) 0 0xf1100000 0x10000
+ MBUS_ID(0x09, 0x15) 0 0xf1110000 0x10000>;
internal-regs {
spi@10600 {
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index f9f2347..e8b7f67 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -498,6 +498,7 @@
reg = <0x70000 0x4000>;
interrupts-extended = <&mpic 8>;
clocks = <&gateclk 4>;
+ tx-csum-limit = <9800>;
status = "disabled";
};
@@ -509,6 +510,21 @@
clocks = <&gateclk 4>;
};
+ crypto@90000 {
+ compatible = "marvell,armada-38x-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gateclk 23>, <&gateclk 21>,
+ <&gateclk 14>, <&gateclk 16>;
+ clock-names = "cesa0", "cesa1",
+ "cesaz0", "cesaz1";
+ marvell,crypto-srams = <&crypto_sram0>,
+ <&crypto_sram1>;
+ marvell,crypto-sram-size = <0x800>;
+ };
+
rtc@a3800 {
compatible = "marvell,armada-380-rtc";
reg = <0xa3800 0x20>, <0x184a0 0x0c>;
@@ -584,6 +600,24 @@
status = "disabled";
};
};
+
+ crypto_sram0: sa-sram0 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x19) 0 0x800>;
+ clocks = <&gateclk 23>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x19) 0 0x800>;
+ };
+
+ crypto_sram1: sa-sram1 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x15) 0 0x800>;
+ clocks = <&gateclk 21>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x15) 0 0x800>;
+ };
};
clocks {
diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
index 60bbfe3..23fc670 100644
--- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -69,7 +69,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-db.dts b/arch/arm/boot/dts/armada-xp-db.dts
index 7dd900f..f774101 100644
--- a/arch/arm/boot/dts/armada-xp-db.dts
+++ b/arch/arm/boot/dts/armada-xp-db.dts
@@ -75,7 +75,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
- MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000>;
+ MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
devbus-bootcs {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index bf724ca..4878d73 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -94,7 +94,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
- MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000>;
+ MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x1000000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
devbus-bootcs {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
index 06a6a6c..58b5008 100644
--- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -64,7 +64,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
index fdd187c..6e9820e 100644
--- a/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
+++ b/arch/arm/boot/dts/armada-xp-linksys-mamba.dts
@@ -69,7 +69,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-matrix.dts b/arch/arm/boot/dts/armada-xp-matrix.dts
index f894bc8..6ab3383 100644
--- a/arch/arm/boot/dts/armada-xp-matrix.dts
+++ b/arch/arm/boot/dts/armada-xp-matrix.dts
@@ -67,7 +67,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
internal-regs {
serial@12000 {
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 1516fc2..6fe8972 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -63,7 +63,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
pcie-controller {
status = "okay";
@@ -88,41 +90,10 @@
};
internal-regs {
- /* Two rear eSATA ports */
- sata@a0000 {
- nr-ports = <2>;
- status = "okay";
- };
-
- serial@12000 {
- status = "okay";
- };
-
- mdio {
- phy0: ethernet-phy@0 { /* Marvell 88E1318 */
- reg = <0>;
- };
-
- phy1: ethernet-phy@1 { /* Marvell 88E1318 */
- reg = <1>;
- };
- };
-
- ethernet@70000 {
- status = "okay";
- phy = <&phy0>;
- phy-mode = "rgmii-id";
- };
- ethernet@74000 {
- status = "okay";
- phy = <&phy1>;
- phy-mode = "rgmii-id";
- };
-
- /* Front USB 2.0 port */
- usb@50000 {
- status = "okay";
+ /* RTC is provided by Intersil ISL12057 I2C RTC chip */
+ rtc@10300 {
+ status = "disabled";
};
i2c@11000 {
@@ -130,12 +101,6 @@
clock-frequency = <400000>;
status = "okay";
- isl12057: isl12057@68 {
- compatible = "isil,isl12057";
- reg = <0x68>;
- isil,irq2-can-wakeup-machine;
- };
-
/* Controller for rear fan #1 of 3 (Protechnic
* MGT4012XB-O20, 8000RPM) near eSATA port */
g762_fan1: g762@3e {
@@ -172,6 +137,49 @@
compatible = "gmt,g751";
reg = <0x4c>;
};
+
+ isl12057: isl12057@68 {
+ compatible = "isil,isl12057";
+ reg = <0x68>;
+ isil,irq2-can-wakeup-machine;
+ };
+ };
+
+ serial@12000 {
+ status = "okay";
+ };
+
+ /* Front USB 2.0 port */
+ usb@50000 {
+ status = "okay";
+ };
+
+ mdio {
+ phy0: ethernet-phy@0 { /* Marvell 88E1318 */
+ reg = <0>;
+ };
+
+ phy1: ethernet-phy@1 { /* Marvell 88E1318 */
+ reg = <1>;
+ };
+ };
+
+ ethernet@70000 {
+ status = "okay";
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ };
+
+ ethernet@74000 {
+ status = "okay";
+ phy = <&phy1>;
+ phy-mode = "rgmii-id";
+ };
+
+ /* Two rear eSATA ports */
+ sata@a0000 {
+ nr-ports = <2>;
+ status = "okay";
};
nand@d0000 {
diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index 990e8a2..a5db177 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -65,7 +65,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xd0000000 0x100000
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
- MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x8000000>;
+ MBUS_ID(0x01, 0x2f) 0 0 0xf0000000 0x8000000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
devbus-bootcs {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
index 20267ad..2391b11 100644
--- a/arch/arm/boot/dts/armada-xp-synology-ds414.dts
+++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -77,7 +77,9 @@
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
- MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
+ MBUS_ID(0x09, 0x09) 0 0 0xf8100000 0x10000
+ MBUS_ID(0x09, 0x05) 0 0 0xf8110000 0x10000>;
pcie-controller {
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index 3de9b76..be23196 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -184,6 +184,11 @@
reg = <0x20800 0x20>;
};
+ cpu-config@21000 {
+ compatible = "marvell,armada-xp-cpu-config";
+ reg = <0x21000 0x8>;
+ };
+
eth2: ethernet@30000 {
compatible = "marvell,armada-xp-neta";
reg = <0x30000 0x4000>;
@@ -236,6 +241,18 @@
compatible = "marvell,armada-xp-neta";
};
+ crypto@90000 {
+ compatible = "marvell,armada-xp-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <48>, <49>;
+ clocks = <&gateclk 23>, <&gateclk 23>;
+ clock-names = "cesa0", "cesa1";
+ marvell,crypto-srams = <&crypto_sram0>,
+ <&crypto_sram1>;
+ marvell,crypto-sram-size = <0x800>;
+ };
+
xor@f0900 {
compatible = "marvell,orion-xor";
reg = <0xF0900 0x100
@@ -256,6 +273,24 @@
};
};
};
+
+ crypto_sram0: sa-sram0 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x09) 0 0x800>;
+ clocks = <&gateclk 23>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x09) 0 0x800>;
+ };
+
+ crypto_sram1: sa-sram1 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x05) 0 0x800>;
+ clocks = <&gateclk 23>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 MBUS_ID(0x09, 0x05) 0 0x800>;
+ };
};
clocks {
diff --git a/arch/arm/boot/dts/at91-foxg20.dts b/arch/arm/boot/dts/at91-foxg20.dts
index f89598a..6bf873e 100644
--- a/arch/arm/boot/dts/at91-foxg20.dts
+++ b/arch/arm/boot/dts/at91-foxg20.dts
@@ -159,7 +159,7 @@
label = "Button";
gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
linux,code = <0x103>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/at91-kizbox.dts b/arch/arm/boot/dts/at91-kizbox.dts
index bf18ece..229e989 100644
--- a/arch/arm/boot/dts/at91-kizbox.dts
+++ b/arch/arm/boot/dts/at91-kizbox.dts
@@ -24,15 +24,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <18432000>;
- };
-
main_xtal {
clock-frequency = <18432000>;
};
@@ -94,14 +85,14 @@
label = "PB_RST";
gpios = <&pioB 30 GPIO_ACTIVE_HIGH>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
user {
label = "PB_USER";
gpios = <&pioB 31 GPIO_ACTIVE_HIGH>;
linux,code = <0x101>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-kizbox2.dts b/arch/arm/boot/dts/at91-kizbox2.dts
index f0b1563..50a1456 100644
--- a/arch/arm/boot/dts/at91-kizbox2.dts
+++ b/arch/arm/boot/dts/at91-kizbox2.dts
@@ -171,21 +171,21 @@
label = "PB_PROG";
gpios = <&pioE 27 GPIO_ACTIVE_LOW>;
linux,code = <0x102>;
- gpio-key,wakeup;
+ wakeup-source;
};
reset {
label = "PB_RST";
gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
user {
label = "PB_USER";
gpios = <&pioE 31 GPIO_ACTIVE_HIGH>;
linux,code = <0x101>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-kizboxmini.dts b/arch/arm/boot/dts/at91-kizboxmini.dts
index 9f72b49..9682d10 100644
--- a/arch/arm/boot/dts/at91-kizboxmini.dts
+++ b/arch/arm/boot/dts/at91-kizboxmini.dts
@@ -98,14 +98,14 @@
label = "PB_PROG";
gpios = <&pioC 17 GPIO_ACTIVE_LOW>;
linux,code = <0x102>;
- gpio-key,wakeup;
+ wakeup-source;
};
reset {
label = "PB_RST";
gpios = <&pioC 16 GPIO_ACTIVE_LOW>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-qil_a9260.dts b/arch/arm/boot/dts/at91-qil_a9260.dts
index a9aef53..4f2eebf 100644
--- a/arch/arm/boot/dts/at91-qil_a9260.dts
+++ b/arch/arm/boot/dts/at91-qil_a9260.dts
@@ -183,7 +183,7 @@
label = "user_pb";
gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
linux,code = <28>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
index e8d63afd..e74df32 100644
--- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts
@@ -44,6 +44,8 @@
*/
/dts-v1/;
#include "sama5d2.dtsi"
+#include "sama5d2-pinfunc.h"
+#include <dt-bindings/mfd/atmel-flexcom.h>
/ {
model = "Atmel SAMA5D2 Xplained";
@@ -58,15 +60,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -90,8 +83,26 @@
status = "okay";
};
+ sdmmc0: sdio-host@a0000000 {
+ bus-width = <8>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sdmmc0_default>;
+ non-removable;
+ mmc-ddr-1_8v;
+ status = "okay";
+ };
+
+ sdmmc1: sdio-host@b0000000 {
+ bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sdmmc1_default>;
+ status = "okay"; /* conflict with qspi0 */
+ };
+
apb {
spi0: spi@f8000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi0_default>;
status = "okay";
m25p80@0 {
@@ -102,25 +113,130 @@
};
macb0: ethernet@f8008000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb0_default>;
phy-mode = "rmii";
status = "okay";
};
uart1: serial@f8020000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1_default>;
status = "okay";
};
i2c0: i2c@f8028000 {
dmas = <0>, <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0_default>;
status = "okay";
+
+ pmic: act8865@5b {
+ compatible = "active-semi,act8865";
+ reg = <0x5b>;
+ active-semi,vsel-high;
+ status = "okay";
+
+ regulators {
+ vdd_1v35_reg: DCDC_REG1 {
+ regulator-name = "VDD_1V35";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ vdd_1v2_reg: DCDC_REG2 {
+ regulator-name = "VDD_1V2";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ };
+
+ vdd_3v3_reg: DCDC_REG3 {
+ regulator-name = "VDD_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_fuse_reg: LDO_REG1 {
+ regulator-name = "VDD_FUSE";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ vdd_3v3_lp_reg: LDO_REG2 {
+ regulator-name = "VDD_3V3_LP";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_led_reg: LDO_REG3 {
+ regulator-name = "VDD_LED";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_sdhc_1v8_reg: LDO_REG4 {
+ regulator-name = "VDD_SDHC_1V8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
+
+ flx0: flexcom@f8034000 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_USART>;
+ status = "disabled"; /* conflict with ISC_D2 & ISC_D3 data pins */
+
+ uart5: serial@200 {
+ compatible = "atmel,at91sam9260-usart";
+ reg = <0x200 0x200>;
+ interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+ clocks = <&flx0_clk>;
+ clock-names = "usart";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flx0_default>;
+ atmel,fifo-size = <32>;
+ status = "okay";
+ };
};
uart3: serial@fc008000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3_default>;
+ status = "okay";
+ };
+
+ flx4: flexcom@fc018000 {
+ atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
status = "okay";
+
+ i2c2: i2c@600 {
+ compatible = "atmel,sama5d2-i2c";
+ reg = <0x600 0x200>;
+ interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>;
+ dmas = <0>, <0>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&flx4_clk>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flx4_default>;
+ atmel,fifo-size = <16>;
+ status = "okay";
+ };
};
i2c1: i2c@fc028000 {
dmas = <0>, <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1_default>;
status = "okay";
at24@54 {
@@ -129,6 +245,106 @@
pagesize = <16>;
};
};
+
+ pinctrl@fc038000 {
+ pinctrl_flx0_default: flx0_default {
+ pinmux = <PIN_PB28__FLEXCOM0_IO0>,
+ <PIN_PB29__FLEXCOM0_IO1>;
+ bias-disable;
+ };
+
+ pinctrl_flx4_default: flx4_default {
+ pinmux = <PIN_PD12__FLEXCOM4_IO0>,
+ <PIN_PD13__FLEXCOM4_IO1>;
+ bias-disable;
+ };
+
+ pinctrl_i2c0_default: i2c0_default {
+ pinmux = <PIN_PD21__TWD0>,
+ <PIN_PD22__TWCK0>;
+ bias-disable;
+ };
+
+ pinctrl_i2c1_default: i2c1_default {
+ pinmux = <PIN_PD4__TWD1>,
+ <PIN_PD5__TWCK1>;
+ bias-disable;
+ };
+
+ pinctrl_macb0_default: macb0_default {
+ pinmux = <PIN_PB14__GTXCK>,
+ <PIN_PB15__GTXEN>,
+ <PIN_PB16__GRXDV>,
+ <PIN_PB17__GRXER>,
+ <PIN_PB18__GRX0>,
+ <PIN_PB19__GRX1>,
+ <PIN_PB20__GTX0>,
+ <PIN_PB21__GTX1>,
+ <PIN_PB22__GMDC>,
+ <PIN_PB23__GMDIO>;
+ bias-disable;
+ };
+
+ pinctrl_sdmmc0_default: sdmmc0_default {
+ cmd_data {
+ pinmux = <PIN_PA1__SDMMC0_CMD>,
+ <PIN_PA2__SDMMC0_DAT0>,
+ <PIN_PA3__SDMMC0_DAT1>,
+ <PIN_PA4__SDMMC0_DAT2>,
+ <PIN_PA5__SDMMC0_DAT3>,
+ <PIN_PA6__SDMMC0_DAT4>,
+ <PIN_PA7__SDMMC0_DAT5>,
+ <PIN_PA8__SDMMC0_DAT6>,
+ <PIN_PA9__SDMMC0_DAT7>;
+ bias-pull-up;
+ };
+
+ ck_cd_rstn_vddsel {
+ pinmux = <PIN_PA0__SDMMC0_CK>,
+ <PIN_PA10__SDMMC0_RSTN>,
+ <PIN_PA11__SDMMC0_VDDSEL>,
+ <PIN_PA13__SDMMC0_CD>;
+ bias-disable;
+ };
+ };
+
+ pinctrl_sdmmc1_default: sdmmc1_default {
+ cmd_data {
+ pinmux = <PIN_PA28__SDMMC1_CMD>,
+ <PIN_PA18__SDMMC1_DAT0>,
+ <PIN_PA19__SDMMC1_DAT1>,
+ <PIN_PA20__SDMMC1_DAT2>,
+ <PIN_PA21__SDMMC1_DAT3>;
+ bias-pull-up;
+ };
+
+ conf-ck_cd {
+ pinmux = <PIN_PA22__SDMMC1_CK>,
+ <PIN_PA30__SDMMC1_CD>;
+ bias-disable;
+ };
+ };
+
+ pinctrl_spi0_default: spi0_default {
+ pinmux = <PIN_PA14__SPI0_SPCK>,
+ <PIN_PA15__SPI0_MOSI>,
+ <PIN_PA16__SPI0_MISO>,
+ <PIN_PA17__SPI0_NPCS0>;
+ bias-disable;
+ };
+
+ pinctrl_uart1_default: uart1_default {
+ pinmux = <PIN_PD2__URXD1>,
+ <PIN_PD3__UTXD1>;
+ bias-disable;
+ };
+
+ pinctrl_uart3_default: uart3_default {
+ pinmux = <PIN_PB11__URXD3>,
+ <PIN_PB12__UTXD3>;
+ bias-disable;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
index d81474e..ff888d2 100644
--- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts
@@ -76,7 +76,7 @@
pmic: act8865@5b {
compatible = "active-semi,act8865";
reg = <0x5b>;
- status = "okay";
+ status = "disabled";
regulators {
vcc_1v8_reg: DCDC_REG1 {
@@ -315,7 +315,7 @@
label = "PB_USER";
gpios = <&pioE 29 GPIO_ACTIVE_LOW>;
linux,code = <0x104>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
index 07f4696..131614f 100644
--- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts
@@ -50,7 +50,6 @@
compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5";
chosen {
- bootargs = "ignore_loglevel earlyprintk";
stdout-path = "serial0:115200n8";
};
@@ -59,15 +58,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -235,7 +225,7 @@
label = "pb_user1";
gpios = <&pioE 8 GPIO_ACTIVE_HIGH>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
@@ -246,7 +236,7 @@
d8 {
label = "d8";
gpios = <&pioD 30 GPIO_ACTIVE_HIGH>;
- status = "disabled";
+ default-state = "on";
};
d10 {
diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts
index 49a59c7..2d4a331 100644
--- a/arch/arm/boot/dts/at91-sama5d4ek.dts
+++ b/arch/arm/boot/dts/at91-sama5d4ek.dts
@@ -50,7 +50,6 @@
compatible = "atmel,sama5d4ek", "atmel,sama5d4", "atmel,sama5";
chosen {
- bootargs = "ignore_loglevel earlyprintk";
stdout-path = "serial0:115200n8";
};
@@ -59,15 +58,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -148,6 +138,25 @@
clocks = <&pck2>;
clock-names = "mclk";
};
+
+ qt1070:keyboard@1b {
+ compatible = "qt1070";
+ reg = <0x1b>;
+ interrupt-parent = <&pioE>;
+ interrupts = <25 0x0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_qt1070_irq>;
+ wakeup-source;
+ };
+
+ atmel_mxt_ts@4c {
+ compatible = "atmel,atmel_mxt_ts";
+ reg = <0x4c>;
+ interrupt-parent = <&pioE>;
+ interrupts = <24 0x0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mxt_ts>;
+ };
};
macb0: ethernet@f8020000 {
@@ -204,6 +213,14 @@
atmel,pins =
<AT91_PIOE 13 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>; /* PE13 gpio */
};
+ pinctrl_qt1070_irq: qt1070_irq {
+ atmel,pins =
+ <AT91_PIOE 25 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+ };
+ pinctrl_mxt_ts: mxt_irq {
+ atmel,pins =
+ <AT91_PIOE 24 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
+ };
};
};
};
@@ -277,7 +294,7 @@
label = "pb_user1";
gpios = <&pioE 13 GPIO_ACTIVE_HIGH>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi
index 60edd8b..f6cb7a8 100644
--- a/arch/arm/boot/dts/at91rm9200.dtsi
+++ b/arch/arm/boot/dts/at91rm9200.dtsi
@@ -97,7 +97,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91rm9200-pmc";
+ compatible = "atmel,at91rm9200-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
@@ -426,7 +426,7 @@
pinctrl-0 = <&pinctrl_ssc0_tx &pinctrl_ssc0_rx>;
clocks = <&ssc0_clk>;
clock-names = "pclk";
- status = "disable";
+ status = "disabled";
};
ssc1: ssc@fffd4000 {
@@ -437,7 +437,7 @@
pinctrl-0 = <&pinctrl_ssc1_tx &pinctrl_ssc1_rx>;
clocks = <&ssc1_clk>;
clock-names = "pclk";
- status = "disable";
+ status = "disabled";
};
ssc2: ssc@fffd8000 {
@@ -448,7 +448,7 @@
pinctrl-0 = <&pinctrl_ssc2_tx &pinctrl_ssc2_rx>;
clocks = <&ssc2_clk>;
clock-names = "pclk";
- status = "disable";
+ status = "disabled";
};
macb0: ethernet@fffbc000 {
diff --git a/arch/arm/boot/dts/at91rm9200ek.dts b/arch/arm/boot/dts/at91rm9200ek.dts
index 8dab4b7..f90e1c2 100644
--- a/arch/arm/boot/dts/at91rm9200ek.dts
+++ b/arch/arm/boot/dts/at91rm9200ek.dts
@@ -21,15 +21,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <18432000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi
index be9c027..d4884dd 100644
--- a/arch/arm/boot/dts/at91sam9260.dtsi
+++ b/arch/arm/boot/dts/at91sam9260.dtsi
@@ -100,7 +100,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91sam9260-pmc";
+ compatible = "atmel,at91sam9260-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi
index ce1e3e9..5e09de4 100644
--- a/arch/arm/boot/dts/at91sam9261.dtsi
+++ b/arch/arm/boot/dts/at91sam9261.dtsi
@@ -568,7 +568,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91rm9200-pmc";
+ compatible = "atmel,at91rm9200-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9261ek.dts b/arch/arm/boot/dts/at91sam9261ek.dts
index 2e92ac0..55bd51f 100644
--- a/arch/arm/boot/dts/at91sam9261ek.dts
+++ b/arch/arm/boot/dts/at91sam9261ek.dts
@@ -22,15 +22,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <18432000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -149,7 +140,7 @@
ti,debounce-tol = /bits/ 16 <65535>;
ti,debounce-max = /bits/ 16 <1>;
- linux,wakeup;
+ wakeup-source;
};
};
@@ -193,28 +184,28 @@
label = "button_0";
gpios = <&pioA 27 GPIO_ACTIVE_LOW>;
linux,code = <256>;
- gpio-key,wakeup;
+ wakeup-source;
};
button_1 {
label = "button_1";
gpios = <&pioA 26 GPIO_ACTIVE_LOW>;
linux,code = <257>;
- gpio-key,wakeup;
+ wakeup-source;
};
button_2 {
label = "button_2";
gpios = <&pioA 25 GPIO_ACTIVE_LOW>;
linux,code = <258>;
- gpio-key,wakeup;
+ wakeup-source;
};
button_3 {
label = "button_3";
gpios = <&pioA 24 GPIO_ACTIVE_LOW>;
linux,code = <259>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index f1f5fa3..9344642 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -93,7 +93,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91rm9200-pmc";
+ compatible = "atmel,at91rm9200-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9263ek.dts b/arch/arm/boot/dts/at91sam9263ek.dts
index 2338127..59df9d7 100644
--- a/arch/arm/boot/dts/at91sam9263ek.dts
+++ b/arch/arm/boot/dts/at91sam9263ek.dts
@@ -22,15 +22,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <16367660>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -213,14 +204,14 @@
label = "left_click";
gpios = <&pioC 5 GPIO_ACTIVE_LOW>;
linux,code = <272>;
- gpio-key,wakeup;
+ wakeup-source;
};
right_click {
label = "right_click";
gpios = <&pioC 4 GPIO_ACTIVE_LOW>;
linux,code = <273>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
index 57548a2..e9cc99b 100644
--- a/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
+++ b/arch/arm/boot/dts/at91sam9g20ek_common.dtsi
@@ -19,15 +19,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <18432000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -206,14 +197,14 @@
label = "Button 3";
gpios = <&pioA 30 GPIO_ACTIVE_LOW>;
linux,code = <0x103>;
- gpio-key,wakeup;
+ wakeup-source;
};
btn4 {
label = "Button 4";
gpios = <&pioA 31 GPIO_ACTIVE_LOW>;
linux,code = <0x104>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi
index 18b8b9e..af8b708 100644
--- a/arch/arm/boot/dts/at91sam9g45.dtsi
+++ b/arch/arm/boot/dts/at91sam9g45.dtsi
@@ -114,7 +114,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91sam9g45-pmc";
+ compatible = "atmel,at91sam9g45-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts
index d1ae60a..2400c99 100644
--- a/arch/arm/boot/dts/at91sam9m10g45ek.dts
+++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts
@@ -24,15 +24,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -198,6 +189,8 @@
isi_0: endpoint {
remote-endpoint = <&ov2640_0>;
bus-width = <8>;
+ vsync-active = <1>;
+ hsync-active = <1>;
};
};
};
@@ -321,14 +314,14 @@
label = "left_click";
gpios = <&pioB 6 GPIO_ACTIVE_LOW>;
linux,code = <272>;
- gpio-key,wakeup;
+ wakeup-source;
};
right_click {
label = "right_click";
gpios = <&pioB 7 GPIO_ACTIVE_LOW>;
linux,code = <273>;
- gpio-key,wakeup;
+ wakeup-source;
};
left {
diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi
index 32bc9a1..95569a8 100644
--- a/arch/arm/boot/dts/at91sam9n12.dtsi
+++ b/arch/arm/boot/dts/at91sam9n12.dtsi
@@ -97,7 +97,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91sam9n12-pmc";
+ compatible = "atmel,at91sam9n12-pmc", "syscon";
reg = <0xfffffc00 0x200>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts
index efa7506..ca4ddf8 100644
--- a/arch/arm/boot/dts/at91sam9n12ek.dts
+++ b/arch/arm/boot/dts/at91sam9n12ek.dts
@@ -23,15 +23,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <16000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -71,10 +62,6 @@
};
};
- i2c1: i2c@f8014000 {
- status = "okay";
- };
-
mmc0: mmc@f0008000 {
pinctrl-0 = <
&pinctrl_board_mmc0
@@ -204,13 +191,13 @@
};
d9 {
- label = "d6";
+ label = "d9";
gpios = <&pioB 5 GPIO_ACTIVE_LOW>;
linux,default-trigger = "nand-disk";
};
d10 {
- label = "d7";
+ label = "d10";
gpios = <&pioB 6 GPIO_ACTIVE_HIGH>;
linux,default-trigger = "heartbeat";
};
@@ -223,7 +210,7 @@
label = "Enter";
gpios = <&pioB 3 GPIO_ACTIVE_LOW>;
linux,code = <28>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi
index a0b90ae..6d829db 100644
--- a/arch/arm/boot/dts/at91sam9rl.dtsi
+++ b/arch/arm/boot/dts/at91sam9rl.dtsi
@@ -814,7 +814,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91sam9g45-pmc";
+ compatible = "atmel,at91sam9g45-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/at91sam9rlek.dts b/arch/arm/boot/dts/at91sam9rlek.dts
index 558c9f2..f10566f 100644
--- a/arch/arm/boot/dts/at91sam9rlek.dts
+++ b/arch/arm/boot/dts/at91sam9rlek.dts
@@ -22,15 +22,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
-
slow_xtal {
clock-frequency = <32768>;
};
@@ -225,14 +216,14 @@
label = "right_click";
gpios = <&pioB 0 GPIO_ACTIVE_LOW>;
linux,code = <273>;
- gpio-key,wakeup;
+ wakeup-source;
};
left_click {
label = "left_click";
gpios = <&pioB 1 GPIO_ACTIVE_LOW>;
linux,code = <272>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 747d8f0..0827d59 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -68,7 +68,7 @@
adc_op_clk: adc_op_clk{
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <5000000>;
+ clock-frequency = <1000000>;
};
};
@@ -105,7 +105,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,at91sam9x5-pmc";
+ compatible = "atmel,at91sam9x5-pmc", "syscon";
reg = <0xfffffc00 0x100>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
@@ -1043,6 +1043,7 @@
atmel,adc-channels-used = <0xffff>;
atmel,adc-vref = <3300>;
atmel,adc-startup-time = <40>;
+ atmel,adc-sample-hold-time = <11>;
atmel,adc-res = <8 10>;
atmel,adc-res-names = "lowres", "highres";
atmel,adc-use-res = "highres";
diff --git a/arch/arm/boot/dts/at91sam9x5cm.dtsi b/arch/arm/boot/dts/at91sam9x5cm.dtsi
index 26112eb..b098ad8 100644
--- a/arch/arm/boot/dts/at91sam9x5cm.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5cm.dtsi
@@ -13,17 +13,6 @@
};
clocks {
- #address-cells = <1>;
- #size-cells = <1>;
- ranges;
-
- main_clock: clock@0 {
- compatible = "atmel,osc", "fixed-clock";
- clock-frequency = <12000000>;
- };
- };
-
- clocks {
slow_xtal {
clock-frequency = <32768>;
};
diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi
index d237c46..52425a4 100644
--- a/arch/arm/boot/dts/at91sam9x5ek.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi
@@ -66,6 +66,8 @@
isi_0: endpoint@0 {
remote-endpoint = <&ov2640_0>;
bus-width = <8>;
+ vsync-active = <1>;
+ hsync-active = <1>;
};
};
};
@@ -100,6 +102,12 @@
};
};
+ adc0: adc@f804c000 {
+ atmel,adc-ts-wires = <4>;
+ atmel,adc-ts-pressure-threshold = <10000>;
+ status = "okay";
+ };
+
pinctrl@fffff400 {
camera_sensor {
pinctrl_pck0_as_isi_mck: pck0_as_isi_mck-0 {
diff --git a/arch/arm/boot/dts/axp209.dtsi b/arch/arm/boot/dts/axp209.dtsi
index 24c935c..051ab3b 100644
--- a/arch/arm/boot/dts/axp209.dtsi
+++ b/arch/arm/boot/dts/axp209.dtsi
@@ -89,4 +89,9 @@
regulator-name = "ldo5";
};
};
+
+ usb_power_supply: usb_power_supply {
+ compatible = "x-powers,axp202-usb-power-supply";
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/axp22x.dtsi b/arch/arm/boot/dts/axp22x.dtsi
new file mode 100644
index 0000000..76302f5
--- /dev/null
+++ b/arch/arm/boot/dts/axp22x.dtsi
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * AXP221/221s/223 Integrated Power Management Chip
+ * http://www.x-powers.com/product/AXP22X.php
+ * http://dl.linux-sunxi.org/AXP/AXP221%20Datasheet%20V1.2%2020130326%20.pdf
+ */
+
+&axp22x {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ regulators {
+ /* Default work frequency for buck regulators */
+ x-powers,dcdc-freq = <3000>;
+
+ reg_dcdc1: dcdc1 {
+ regulator-name = "dcdc1";
+ };
+
+ reg_dcdc2: dcdc2 {
+ regulator-name = "dcdc2";
+ };
+
+ reg_dcdc3: dcdc3 {
+ regulator-name = "dcdc3";
+ };
+
+ reg_dcdc4: dcdc4 {
+ regulator-name = "dcdc4";
+ };
+
+ reg_dcdc5: dcdc5 {
+ regulator-name = "dcdc5";
+ };
+
+ reg_dc1sw: dc1sw {
+ regulator-name = "dc1sw";
+ };
+
+ reg_dc5ldo: dc5ldo {
+ regulator-name = "dc5ldo";
+ };
+
+ reg_aldo1: aldo1 {
+ regulator-name = "aldo1";
+ };
+
+ reg_aldo2: aldo2 {
+ regulator-name = "aldo2";
+ };
+
+ reg_aldo3: aldo3 {
+ regulator-name = "aldo3";
+ };
+
+ reg_dldo1: dldo1 {
+ regulator-name = "dldo1";
+ };
+
+ reg_dldo2: dldo2 {
+ regulator-name = "dldo2";
+ };
+
+ reg_dldo3: dldo3 {
+ regulator-name = "dldo3";
+ };
+
+ reg_dldo4: dldo4 {
+ regulator-name = "dldo4";
+ };
+
+ reg_eldo1: eldo1 {
+ regulator-name = "eldo1";
+ };
+
+ reg_eldo2: eldo2 {
+ regulator-name = "eldo2";
+ };
+
+ reg_eldo3: eldo3 {
+ regulator-name = "eldo3";
+ };
+
+ reg_ldo_io0: ldo_io0 {
+ regulator-name = "ldo_io0";
+ };
+
+ reg_ldo_io1: ldo_io1 {
+ regulator-name = "ldo_io1";
+ };
+
+ reg_rtc_ldo: rtc_ldo {
+ /* RTC_LDO is a fixed, always-on regulator */
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "rtc_ldo";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
index e1ac07a..2778533 100644
--- a/arch/arm/boot/dts/bcm-cygnus.dtsi
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -32,6 +32,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/bcm-cygnus.h>
#include "skeleton.dtsi"
@@ -54,197 +55,212 @@
/include/ "bcm-cygnus-clock.dtsi"
- pinctrl: pinctrl@0x0301d0c8 {
- compatible = "brcm,cygnus-pinmux";
- reg = <0x0301d0c8 0x30>,
- <0x0301d24c 0x2c>;
- };
-
- gpio_crmu: gpio@03024800 {
- compatible = "brcm,cygnus-crmu-gpio";
- reg = <0x03024800 0x50>,
- <0x03024008 0x18>;
- #gpio-cells = <2>;
- gpio-controller;
- };
-
- gpio_ccm: gpio@1800a000 {
- compatible = "brcm,cygnus-ccm-gpio";
- reg = <0x1800a000 0x50>,
- <0x0301d164 0x20>;
- #gpio-cells = <2>;
- gpio-controller;
- interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-controller;
- };
+ core {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x19000000 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
- gpio_asiu: gpio@180a5000 {
- compatible = "brcm,cygnus-asiu-gpio";
- reg = <0x180a5000 0x668>;
- #gpio-cells = <2>;
- gpio-controller;
+ timer@20200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x20200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+ };
- pinmux = <&pinctrl>;
+ gic: interrupt-controller@21000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x21000 0x1000>,
+ <0x20100 0x100>;
+ };
- interrupt-controller;
- interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+ L2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0x22000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
};
- amba {
+ axi {
+ compatible = "simple-bus";
+ ranges;
#address-cells = <1>;
#size-cells = <1>;
- compatible = "arm,amba-bus", "simple-bus";
- interrupt-parent = <&gic>;
- ranges;
- wdt@18009000 {
- compatible = "arm,sp805" , "arm,primecell";
- reg = <0x18009000 0x1000>;
- interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&axi81_clk>;
- clock-names = "apb_pclk";
+ pinctrl: pinctrl@0x0301d0c8 {
+ compatible = "brcm,cygnus-pinmux";
+ reg = <0x0301d0c8 0x30>,
+ <0x0301d24c 0x2c>;
};
- };
- i2c0: i2c@18008000 {
- compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c";
- reg = <0x18008000 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
- clock-frequency = <100000>;
- status = "disabled";
- };
+ gpio_crmu: gpio@03024800 {
+ compatible = "brcm,cygnus-crmu-gpio";
+ reg = <0x03024800 0x50>,
+ <0x03024008 0x18>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ };
- i2c1: i2c@1800b000 {
- compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c";
- reg = <0x1800b000 0x100>;
- #address-cells = <1>;
- #size-cells = <0>;
- interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
- clock-frequency = <100000>;
- status = "disabled";
- };
+ i2c0: i2c@18008000 {
+ compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c";
+ reg = <0x18008000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
- pcie0: pcie@18012000 {
- compatible = "brcm,iproc-pcie";
- reg = <0x18012000 0x1000>;
+ wdt0: wdt@18009000 {
+ compatible = "arm,sp805" , "arm,primecell";
+ reg = <0x18009000 0x1000>;
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-names = "apb_pclk";
+ };
- #interrupt-cells = <1>;
- interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
+ gpio_ccm: gpio@1800a000 {
+ compatible = "brcm,cygnus-ccm-gpio";
+ reg = <0x1800a000 0x50>,
+ <0x0301d164 0x20>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ };
- linux,pci-domain = <0>;
+ i2c1: i2c@1800b000 {
+ compatible = "brcm,cygnus-iproc-i2c", "brcm,iproc-i2c";
+ reg = <0x1800b000 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
- bus-range = <0x00 0xff>;
+ pcie0: pcie@18012000 {
+ compatible = "brcm,iproc-pcie";
+ reg = <0x18012000 0x1000>;
- #address-cells = <3>;
- #size-cells = <2>;
- device_type = "pci";
- ranges = <0x81000000 0 0 0x28000000 0 0x00010000
- 0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 100 IRQ_TYPE_NONE>;
- status = "disabled";
- };
+ linux,pci-domain = <0>;
- pcie1: pcie@18013000 {
- compatible = "brcm,iproc-pcie";
- reg = <0x18013000 0x1000>;
+ bus-range = <0x00 0xff>;
- #interrupt-cells = <1>;
- interrupt-map-mask = <0 0 0 0>;
- interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x81000000 0 0 0x28000000 0 0x00010000
+ 0x82000000 0 0x20000000 0x20000000 0 0x04000000>;
- linux,pci-domain = <1>;
+ status = "disabled";
+ };
- bus-range = <0x00 0xff>;
+ pcie1: pcie@18013000 {
+ compatible = "brcm,iproc-pcie";
+ reg = <0x18013000 0x1000>;
- #address-cells = <3>;
- #size-cells = <2>;
- device_type = "pci";
- ranges = <0x81000000 0 0 0x48000000 0 0x00010000
- 0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 0>;
+ interrupt-map = <0 0 0 0 &gic GIC_SPI 106 IRQ_TYPE_NONE>;
- status = "disabled";
- };
+ linux,pci-domain = <1>;
- uart0: serial@18020000 {
- compatible = "snps,dw-apb-uart";
- reg = <0x18020000 0x100>;
- reg-shift = <2>;
- reg-io-width = <4>;
- interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&axi81_clk>;
- clock-frequency = <100000000>;
- status = "disabled";
- };
+ bus-range = <0x00 0xff>;
- uart1: serial@18021000 {
- compatible = "snps,dw-apb-uart";
- reg = <0x18021000 0x100>;
- reg-shift = <2>;
- reg-io-width = <4>;
- interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&axi81_clk>;
- clock-frequency = <100000000>;
- status = "disabled";
- };
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ ranges = <0x81000000 0 0 0x48000000 0 0x00010000
+ 0x82000000 0 0x40000000 0x40000000 0 0x04000000>;
- uart2: serial@18022000 {
- compatible = "snps,dw-apb-uart";
- reg = <0x18020000 0x100>;
- reg-shift = <2>;
- reg-io-width = <4>;
- interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&axi81_clk>;
- clock-frequency = <100000000>;
- status = "disabled";
- };
+ status = "disabled";
+ };
- uart3: serial@18023000 {
- compatible = "snps,dw-apb-uart";
- reg = <0x18023000 0x100>;
- reg-shift = <2>;
- reg-io-width = <4>;
- interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&axi81_clk>;
- clock-frequency = <100000000>;
- status = "disabled";
- };
+ uart0: serial@18020000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18020000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
- nand: nand@18046000 {
- compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
- reg = <0x18046000 0x600>, <0xf8105408 0x600>, <0x18046f00 0x20>;
- reg-names = "nand", "iproc-idm", "iproc-ext";
- interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
+ uart1: serial@18021000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18021000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
- #address-cells = <1>;
- #size-cells = <0>;
+ uart2: serial@18022000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18020000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
- brcm,nand-has-wp;
- };
+ uart3: serial@18023000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18023000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
- gic: interrupt-controller@19021000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- #address-cells = <0>;
- interrupt-controller;
- reg = <0x19021000 0x1000>,
- <0x19020100 0x100>;
- };
+ nand: nand@18046000 {
+ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1";
+ reg = <0x18046000 0x600>, <0xf8105408 0x600>,
+ <0x18046f00 0x20>;
+ reg-names = "nand", "iproc-idm", "iproc-ext";
+ interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
- L2: l2-cache {
- compatible = "arm,pl310-cache";
- reg = <0x19022000 0x1000>;
- cache-unified;
- cache-level = <2>;
- };
+ #address-cells = <1>;
+ #size-cells = <0>;
- timer@19020200 {
- compatible = "arm,cortex-a9-global-timer";
- reg = <0x19020200 0x100>;
- interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&periph_clk>;
- };
+ brcm,nand-has-wp;
+ };
+ gpio_asiu: gpio@180a5000 {
+ compatible = "brcm,cygnus-asiu-gpio";
+ reg = <0x180a5000 0x668>;
+ #gpio-cells = <2>;
+ gpio-controller;
+
+ pinmux = <&pinctrl>;
+
+ interrupt-controller;
+ interrupts = <GIC_SPI 174 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ touchscreen: tsc@180a6000 {
+ compatible = "brcm,iproc-touchscreen";
+ reg = <0x180a6000 0x40>;
+ clocks = <&asiu_clks BCM_CYGNUS_ASIU_ADC_CLK>;
+ clock-names = "tsc_clk";
+ interrupts = <GIC_SPI 164 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
};
diff --git a/arch/arm/boot/dts/bcm-nsp.dtsi b/arch/arm/boot/dts/bcm-nsp.dtsi
new file mode 100644
index 0000000..58aca27
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-nsp.dtsi
@@ -0,0 +1,119 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "brcm,nsp";
+ model = "Broadcom Northstar Plus SoC";
+ interrupt-parent = <&gic>;
+
+ mpcore {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x19020000 0x00003000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x0>;
+ };
+ };
+
+ L2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0x2000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ gic: interrupt-controller@19021000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x1000 0x1000>,
+ <0x0100 0x100>;
+ };
+
+ timer@19020200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x0200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+ };
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <500000000>;
+ };
+ };
+
+ axi {
+ compatible = "simple-bus";
+ ranges = <0x00000000 0x18000000 0x00001000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ uart0: serial@18000300 {
+ compatible = "ns16550a";
+ reg = <0x0300 0x100>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <62499840>;
+ status = "disabled";
+ };
+
+ uart1: serial@18000400 {
+ compatible = "ns16550a";
+ reg = <0x0400 0x100>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <62499840>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
new file mode 100644
index 0000000..b2bff43
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi-a-plus.dts
@@ -0,0 +1,30 @@
+/dts-v1/;
+#include "bcm2835-rpi.dtsi"
+
+/ {
+ compatible = "raspberrypi,model-a-plus", "brcm,bcm2835";
+ model = "Raspberry Pi Model A+";
+
+ leds {
+ act {
+ gpios = <&gpio 47 0>;
+ };
+
+ pwr {
+ label = "PWR";
+ gpios = <&gpio 35 0>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+ };
+};
+
+&gpio {
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
+
+ /* I2S interface */
+ i2s_alt0: i2s_alt0 {
+ brcm,pins = <18 19 20 21>;
+ brcm,function = <BCM2835_FSEL_ALT0>;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
new file mode 100644
index 0000000..eab8b591
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-rev2.dts
@@ -0,0 +1,23 @@
+/dts-v1/;
+#include "bcm2835-rpi.dtsi"
+
+/ {
+ compatible = "raspberrypi,model-b-rev2", "brcm,bcm2835";
+ model = "Raspberry Pi Model B rev2";
+
+ leds {
+ act {
+ gpios = <&gpio 16 1>;
+ };
+ };
+};
+
+&gpio {
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
+
+ /* I2S interface */
+ i2s_alt2: i2s_alt2 {
+ brcm,pins = <28 29 30 31>;
+ brcm,function = <BCM2835_FSEL_ALT2>;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index ee89b79..ff6b2d1 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -13,11 +13,5 @@
};
&gpio {
- pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
-
- /* I2S interface */
- i2s_alt2: i2s_alt2 {
- brcm,pins = <28 29 30 31>;
- brcm,function = <BCM2835_FSEL_ALT2>;
- };
+ pinctrl-0 = <&gpioout &alt0 &alt3>;
};
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index ab5474e..3572f03 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -52,6 +52,10 @@
clock-frequency = <100000>;
};
+&i2c2 {
+ status = "okay";
+};
+
&sdhci {
status = "okay";
bus-width = <4>;
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 301c73f..aef64de 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -1,4 +1,5 @@
#include <dt-bindings/pinctrl/bcm2835.h>
+#include <dt-bindings/clock/bcm2835.h>
#include "skeleton.dtsi"
/ {
@@ -21,6 +22,10 @@
compatible = "brcm,bcm2835-system-timer";
reg = <0x7e003000 0x1000>;
interrupts = <1 0>, <1 1>, <1 2>, <1 3>;
+ /* This could be a reference to BCM2835_CLOCK_TIMER,
+ * but we don't have the driver using the common clock
+ * support yet.
+ */
clock-frequency = <1000000>;
};
@@ -57,6 +62,17 @@
reg = <0x7e100000 0x28>;
};
+ clocks: cprman@7e101000 {
+ compatible = "brcm,bcm2835-cprman";
+ #clock-cells = <1>;
+ reg = <0x7e101000 0x2000>;
+
+ /* CPRMAN derives everything from the platform's
+ * oscillator.
+ */
+ clocks = <&clk_osc>;
+ };
+
rng@7e104000 {
compatible = "brcm,bcm2835-rng";
reg = <0x7e104000 0x10>;
@@ -92,11 +108,13 @@
#interrupt-cells = <2>;
};
- uart@7e201000 {
+ uart0: uart@7e201000 {
compatible = "brcm,bcm2835-pl011", "arm,pl011", "arm,primecell";
reg = <0x7e201000 0x1000>;
interrupts = <2 25>;
- clock-frequency = <3000000>;
+ clocks = <&clocks BCM2835_CLOCK_UART>,
+ <&clocks BCM2835_CLOCK_VPU>;
+ clock-names = "uartclk", "apb_pclk";
arm,primecell-periphid = <0x00241011>;
};
@@ -115,7 +133,7 @@
compatible = "brcm,bcm2835-spi";
reg = <0x7e204000 0x1000>;
interrupts = <2 22>;
- clocks = <&clk_spi>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -125,7 +143,7 @@
compatible = "brcm,bcm2835-i2c";
reg = <0x7e205000 0x1000>;
interrupts = <2 21>;
- clocks = <&clk_i2c>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -135,7 +153,7 @@
compatible = "brcm,bcm2835-sdhci";
reg = <0x7e300000 0x100>;
interrupts = <2 30>;
- clocks = <&clk_mmc>;
+ clocks = <&clocks BCM2835_CLOCK_EMMC>;
status = "disabled";
};
@@ -143,7 +161,17 @@
compatible = "brcm,bcm2835-i2c";
reg = <0x7e804000 0x1000>;
interrupts = <2 21>;
- clocks = <&clk_i2c>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@7e805000 {
+ compatible = "brcm,bcm2835-i2c";
+ reg = <0x7e805000 0x1000>;
+ interrupts = <2 21>;
+ clocks = <&clocks BCM2835_CLOCK_VPU>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -165,28 +193,14 @@
#address-cells = <1>;
#size-cells = <0>;
- clk_mmc: clock@0 {
+ /* The oscillator is the root of the clock tree. */
+ clk_osc: clock@3 {
compatible = "fixed-clock";
- reg = <0>;
+ reg = <3>;
#clock-cells = <0>;
- clock-output-names = "mmc";
- clock-frequency = <100000000>;
+ clock-output-names = "osc";
+ clock-frequency = <19200000>;
};
- clk_i2c: clock@1 {
- compatible = "fixed-clock";
- reg = <1>;
- #clock-cells = <0>;
- clock-output-names = "i2c";
- clock-frequency = <250000000>;
- };
-
- clk_spi: clock@2 {
- compatible = "fixed-clock";
- reg = <2>;
- #clock-cells = <0>;
- clock-output-names = "spi";
- clock-frequency = <250000000>;
- };
};
};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index 64b8d10..ca92bba 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -24,6 +24,17 @@
reg = <0x00000000 0x08000000>;
};
+ axi@18000000 {
+ usb3@23000 {
+ reg = <0x00023000 0x1000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
leds {
compatible = "gpio-leds";
diff --git a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
index aedf3c4..8ade7de 100644
--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
@@ -10,6 +10,7 @@
/dts-v1/;
#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
/ {
compatible = "asus,rt-ac87u", "brcm,bcm4709", "brcm,bcm4708";
diff --git a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
new file mode 100644
index 0000000..a22ed14
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
@@ -0,0 +1,106 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Netgear R7000
+ *
+ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+/ {
+ compatible = "netgear,r7000", "brcm,bcm4709", "brcm,bcm4708";
+ model = "Netgear R7000";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power-white {
+ label = "bcm53xx:white:power";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ power-amber {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ 5ghz {
+ label = "bcm53xx:white:5ghz";
+ gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ 2ghz {
+ label = "bcm53xx:white:2ghz";
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wps {
+ label = "bcm53xx:white:wps";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ wireless {
+ label = "bcm53xx:white:wireless";
+ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb3 {
+ label = "bcm53xx:white:usb3";
+ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb2 {
+ label = "bcm53xx:white:usb2";
+ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ };
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm7445.dtsi b/arch/arm/boot/dts/bcm7445.dtsi
index 3b6b175..4791321 100644
--- a/arch/arm/boot/dts/bcm7445.dtsi
+++ b/arch/arm/boot/dts/bcm7445.dtsi
@@ -143,6 +143,12 @@
brcm,irq-can-wake;
};
+ aon-ctrl@410000 {
+ compatible = "brcm,brcmstb-aon-ctrl";
+ reg = <0x410000 0x200>, <0x410200 0x400>;
+ reg-names = "aon-ctrl", "aon-sram";
+ };
+
nand: nand@3e2800 {
status = "disabled";
#address-cells = <1>;
@@ -219,6 +225,84 @@
};
+ memory_controllers {
+ compatible = "simple-bus";
+ ranges = <0x0 0x0 0xf1100000 0x200000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ memc@0 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x80000>;
+
+ memc-ddr@2000 {
+ compatible = "brcm,brcmstb-memc-ddr";
+ reg = <0x2000 0x800>;
+ };
+
+ ddr-phy@6000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0x6000 0x21c>;
+ };
+
+ shimphy@8000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0x8000 0xe4>;
+ };
+ };
+
+ memc@1 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x80000 0x80000>;
+
+ memc-ddr@2000 {
+ compatible = "brcm,brcmstb-memc-ddr";
+ reg = <0x2000 0x800>;
+ };
+
+ ddr-phy@6000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0x6000 0x21c>;
+ };
+
+ shimphy@8000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0x8000 0xe4>;
+ };
+ };
+
+ memc@2 {
+ compatible = "brcm,brcmstb-memc", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x100000 0x80000>;
+
+ memc-ddr@2000 {
+ compatible = "brcm,brcmstb-memc-ddr";
+ reg = <0x2000 0x800>;
+ };
+
+ ddr-phy@6000 {
+ compatible = "brcm,brcmstb-ddr-phy-v240.1";
+ reg = <0x6000 0x21c>;
+ };
+
+ shimphy@8000 {
+ compatible = "brcm,brcmstb-ddr-shimphy-v1.0";
+ reg = <0x8000 0xe4>;
+ };
+ };
+ };
+
+ sram@ffe00000 {
+ compatible = "brcm,boot-sram", "mmio-sram";
+ reg = <0x0 0xffe00000 0x0 0x10000>;
+ };
+
smpboot {
compatible = "brcm,brcmstb-smpboot";
syscon-cpu = <&hif_cpubiuctrl 0x88 0x178>;
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
index 7db4843..8b3800f 100644
--- a/arch/arm/boot/dts/bcm911360_entphn.dts
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -39,19 +39,11 @@
model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
compatible = "brcm,bcm11360", "brcm,cygnus";
- aliases {
- serial0 = &uart3;
- };
-
chosen {
stdout-path = &uart3;
bootargs = "console=ttyS0,115200";
};
- uart3: serial@18023000 {
- status = "okay";
- };
-
gpio_keys {
compatible = "gpio-keys";
#address-cells = <1>;
@@ -64,3 +56,23 @@
};
};
};
+
+&uart3 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@1 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
+
+ brcm,nand-oob-sector-size = <27>;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm911360k.dts b/arch/arm/boot/dts/bcm911360k.dts
index 9658d4f..091c73a 100644
--- a/arch/arm/boot/dts/bcm911360k.dts
+++ b/arch/arm/boot/dts/bcm911360k.dts
@@ -43,11 +43,10 @@
};
chosen {
- stdout-path = &uart3;
- bootargs = "console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
- uart3: serial@18023000 {
- status = "okay";
- };
+&uart3 {
+ status = "okay";
};
diff --git a/arch/arm/boot/dts/bcm958300k.dts b/arch/arm/boot/dts/bcm958300k.dts
index 2f63052..b4a1392 100644
--- a/arch/arm/boot/dts/bcm958300k.dts
+++ b/arch/arm/boot/dts/bcm958300k.dts
@@ -33,6 +33,7 @@
/dts-v1/;
#include "bcm-cygnus.dtsi"
+#include "bcm9hmidc.dtsi"
/ {
model = "Cygnus SVK (BCM958300K)";
@@ -43,35 +44,34 @@
};
chosen {
- stdout-path = &uart3;
- bootargs = "console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
- pcie0: pcie@18012000 {
- status = "okay";
- };
+&pcie0 {
+ status = "okay";
+};
- pcie1: pcie@18013000 {
- status = "okay";
- };
+&pcie1 {
+ status = "okay";
+};
- uart3: serial@18023000 {
- status = "okay";
- };
+&uart3 {
+ status = "okay";
+};
- nand: nand@18046000 {
- nandcs@1 {
- compatible = "brcm,nandcs";
- reg = <0>;
- nand-on-flash-bbt;
+&nand {
+ nandcs@1 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
- #address-cells = <1>;
- #size-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
- nand-ecc-strength = <24>;
- nand-ecc-step-size = <1024>;
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
- brcm,nand-oob-sector-size = <27>;
- };
+ brcm,nand-oob-sector-size = <27>;
};
};
diff --git a/arch/arm/boot/dts/bcm958305k.dts b/arch/arm/boot/dts/bcm958305k.dts
index 56b429a..3378683 100644
--- a/arch/arm/boot/dts/bcm958305k.dts
+++ b/arch/arm/boot/dts/bcm958305k.dts
@@ -33,6 +33,7 @@
/dts-v1/;
#include "bcm-cygnus.dtsi"
+#include "bcm9hmidc.dtsi"
/ {
model = "Cygnus Wireless Audio (BCM958305K)";
@@ -43,11 +44,42 @@
};
chosen {
- stdout-path = &uart3;
- bootargs = "console=ttyS0,115200";
+ stdout-path = "serial0:115200n8";
};
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&pcie0 {
+ status = "okay";
+};
+
+&pcie1 {
+ status = "okay";
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&nand {
+ nandcs@1 {
+ compatible = "brcm,nandcs";
+ reg = <0>;
+ nand-on-flash-bbt;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <1024>;
- uart3: serial@18023000 {
- status = "okay";
+ brcm,nand-oob-sector-size = <27>;
};
};
diff --git a/arch/arm/boot/dts/bcm958625k.dts b/arch/arm/boot/dts/bcm958625k.dts
new file mode 100644
index 0000000..16303db
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958625k.dts
@@ -0,0 +1,57 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-nsp.dtsi"
+
+/ {
+ model = "NorthStar Plus SVK (BCM958625K)";
+ compatible = "brcm,bcm58625", "brcm,nsp";
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm9hmidc.dtsi b/arch/arm/boot/dts/bcm9hmidc.dtsi
new file mode 100644
index 0000000..65397c0
--- /dev/null
+++ b/arch/arm/boot/dts/bcm9hmidc.dtsi
@@ -0,0 +1,42 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Broadcom human machine interface daughter card (bcm9hmidc) installed on
+ * bcm958300k/bcm958305k boards
+ */
+
+&touchscreen {
+ touchscreen-inverted-x;
+ touchscreen-inverted-y;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
index 5c99fb3..3c0907b 100644
--- a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
+++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
@@ -45,7 +45,8 @@
compatible = "sony,nsz-gs7", "marvell,berlin2", "marvell,berlin";
chosen {
- bootargs = "console=ttyS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index ef811de..eaadac3 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -47,6 +47,12 @@
model = "Marvell Armada 1500 (BG2) SoC";
compatible = "marvell,berlin2", "marvell,berlin";
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -57,6 +63,16 @@
device_type = "cpu";
next-level-cache = <&l2>;
reg = <0>;
+
+ clocks = <&chip_clk CLKID_CPU>;
+ clock-latency = <100000>;
+ operating-points = <
+ /* kHz uV */
+ 1200000 1200000
+ 1000000 1200000
+ 800000 1200000
+ 600000 1200000
+ >;
};
cpu@1 {
@@ -404,6 +420,13 @@
};
};
+ pwm: pwm@f20000 {
+ compatible = "marvell,berlin-pwm";
+ reg = <0xf20000 0x40>;
+ clocks = <&chip_clk CLKID_CFG>;
+ #pwm-cells = <3>;
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 772165a..8ba8b50 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -46,7 +46,8 @@
compatible = "google,chromecast", "marvell,berlin2cd", "marvell,berlin";
chosen {
- bootargs = "console=ttyS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index 900213d..b16df15 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -47,6 +47,11 @@
model = "Marvell Armada 1500-mini (BG2CD) SoC";
compatible = "marvell,berlin2cd", "marvell,berlin";
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -56,6 +61,14 @@
device_type = "cpu";
next-level-cache = <&l2>;
reg = <0>;
+
+ clocks = <&chip_clk CLKID_CPU>;
+ clock-latency = <100000>;
+ operating-points = <
+ /* kHz uV */
+ 800000 1200000
+ 600000 1200000
+ >;
};
};
@@ -368,6 +381,13 @@
status = "disabled";
};
+ pwm: pwm@f20000 {
+ compatible = "marvell,berlin-pwm";
+ reg = <0xf20000 0x40>;
+ clocks = <&chip_clk CLKID_CFG>;
+ #pwm-cells = <3>;
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index 4a749e5..da28c97 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -49,7 +49,8 @@
};
choosen {
- bootargs = "console=ttyS0,115200 earlyprintk";
+ bootargs = "earlyprintk";
+ stdout-path = "serial0:115200n8";
};
regulators {
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index d4dbd28..fb1da99 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -43,6 +43,11 @@
model = "Marvell Armada 1500 pro (BG2-Q) SoC";
compatible = "marvell,berlin2q", "marvell,berlin";
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -53,6 +58,17 @@
device_type = "cpu";
next-level-cache = <&l2>;
reg = <0>;
+
+ clocks = <&chip_clk CLKID_CPU>;
+ clock-latency = <100000>;
+ /* Can be modified by the bootloader */
+ operating-points = <
+ /* kHz uV */
+ 1200000 1200000
+ 1000000 1200000
+ 800000 1200000
+ 600000 1200000
+ >;
};
cpu@1 {
@@ -102,7 +118,8 @@
sdhci0: sdhci@ab0000 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0000 0x200>;
- clocks = <&chip_clk CLKID_SDIO1XIN>;
+ clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>;
+ clock-names = "io", "core";
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -110,7 +127,8 @@
sdhci1: sdhci@ab0800 {
compatible = "mrvl,pxav3-mmc";
reg = <0xab0800 0x200>;
- clocks = <&chip_clk CLKID_SDIO1XIN>;
+ clocks = <&chip_clk CLKID_SDIO1XIN>, <&chip_clk CLKID_SDIO>;
+ clock-names = "io", "core";
interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
@@ -119,7 +137,7 @@
compatible = "mrvl,pxav3-mmc";
reg = <0xab1000 0x200>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_NFC>;
+ clocks = <&chip_clk CLKID_NFC_ECC>, <&chip_clk CLKID_SDIO>;
clock-names = "io", "core";
status = "disabled";
};
@@ -477,6 +495,13 @@
status = "disabled";
};
+ pwm: pwm@f20000 {
+ compatible = "marvell,berlin-pwm";
+ reg = <0xf20000 0x40>;
+ clocks = <&chip_clk CLKID_CFG>;
+ #pwm-cells = <3>;
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/cx92755.dtsi b/arch/arm/boot/dts/cx92755.dtsi
index df4c6f1..a5a23c3 100644
--- a/arch/arm/boot/dts/cx92755.dtsi
+++ b/arch/arm/boot/dts/cx92755.dtsi
@@ -95,6 +95,13 @@
timeout-sec = <15>;
};
+ pinctrl: pinctrl@f0000e20 {
+ compatible = "cnxt,cx92755-pinctrl";
+ reg = <0xf0000e20 0x100>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
uc_regs: syscon@f00003a0 {
compatible = "cnxt,cx92755-uc", "syscon";
reg = <0xf00003a0 0x10>;
diff --git a/arch/arm/boot/dts/cx92755_equinox.dts b/arch/arm/boot/dts/cx92755_equinox.dts
index 5da0080..026f556c 100644
--- a/arch/arm/boot/dts/cx92755_equinox.dts
+++ b/arch/arm/boot/dts/cx92755_equinox.dts
@@ -70,8 +70,17 @@
&uart0 {
status = "okay";
+ pinctrl-0 = <&uart0_default>;
+ pinctrl-names = "default";
};
&i2c {
status = "okay";
};
+
+&pinctrl {
+ uart0_default: uart0_active {
+ pins = "GP_O0", "GP_O1";
+ function = "client_b";
+ };
+};
diff --git a/arch/arm/boot/dts/dm816x.dtsi b/arch/arm/boot/dts/dm816x.dtsi
index 3c99cfa..eee636d 100644
--- a/arch/arm/boot/dts/dm816x.dtsi
+++ b/arch/arm/boot/dts/dm816x.dtsi
@@ -218,6 +218,7 @@
reg = <0x480c8000 0x2000>;
interrupts = <77>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
mbox_dsp: mbox_dsp {
@@ -279,8 +280,11 @@
ti,spi-num-cs = <4>;
ti,hwmods = "mcspi1";
dmas = <&edma 16 &edma 17
- &edma 18 &edma 19>;
- dma-names = "tx0", "rx0", "tx1", "rx1";
+ &edma 18 &edma 19
+ &edma 20 &edma 21
+ &edma 22 &edma 23>;
+ dma-names = "tx0", "rx0", "tx1", "rx1",
+ "tx2", "rx2", "tx3", "rx3";
};
mmc1: mmc@48060000 {
diff --git a/arch/arm/boot/dts/dove.dtsi b/arch/arm/boot/dts/dove.dtsi
index 1791216..cd58c2e 100644
--- a/arch/arm/boot/dts/dove.dtsi
+++ b/arch/arm/boot/dts/dove.dtsi
@@ -263,12 +263,13 @@
};
crypto: crypto-engine@30000 {
- compatible = "marvell,orion-crypto";
- reg = <0x30000 0x10000>,
- <0xffffe000 0x800>;
- reg-names = "regs", "sram";
+ compatible = "marvell,dove-crypto";
+ reg = <0x30000 0x10000>;
+ reg-names = "regs";
interrupts = <31>;
clocks = <&gate_clk 15>;
+ marvell,crypto-srams = <&crypto_sram>;
+ marvell,crypto-sram-size = <0x800>;
status = "okay";
};
@@ -767,6 +768,14 @@
interrupts = <47>;
status = "disabled";
};
+
+ crypto_sram: sa-sram@ffffe000 {
+ compatible = "mmio-sram";
+ reg = <0xffffe000 0x800>;
+ clocks = <&gate_clk 15>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
};
};
};
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index a6c82e5..864f600 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -9,6 +9,8 @@
#include "dra74x.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clk/ti-dra7-atl.h>
+#include <dt-bindings/input/input.h>
/ {
model = "TI DRA742";
@@ -28,13 +30,22 @@
gpio = <&pcf_gpio_21 5 GPIO_ACTIVE_HIGH>;
};
- mmc2_3v3: fixedregulator-mmc2 {
+ evm_3v3_sw: fixedregulator-evm_3v3_sw {
compatible = "regulator-fixed";
- regulator-name = "mmc2_3v3";
+ regulator-name = "evm_3v3_sw";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
+ aic_dvdd: fixedregulator-aic_dvdd {
+ /* TPS77018DBVT */
+ compatible = "regulator-fixed";
+ regulator-name = "aic_dvdd";
+ vin-supply = <&evm_3v3_sw>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
extcon_usb1: extcon_usb1 {
compatible = "linux,extcon-usb-gpio";
id-gpio = <&pcf_gpio_21 1 GPIO_ACTIVE_HIGH>;
@@ -55,6 +66,86 @@
enable-active-high;
gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
};
+
+ sound0: sound@0 {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "DRA7xx-EVM";
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Line", "Line Out",
+ "Microphone", "Mic Jack",
+ "Line", "Line In";
+ simple-audio-card,routing =
+ "Headphone Jack", "HPLOUT",
+ "Headphone Jack", "HPROUT",
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "MIC3L", "Mic Jack",
+ "MIC3R", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "LINE1L", "Line In",
+ "LINE1R", "Line In";
+ simple-audio-card,format = "dsp_b";
+ simple-audio-card,bitclock-master = <&sound0_master>;
+ simple-audio-card,frame-master = <&sound0_master>;
+ simple-audio-card,bitclock-inversion;
+
+ sound0_master: simple-audio-card,cpu {
+ sound-dai = <&mcasp3>;
+ system-clock-frequency = <5644800>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&tlv320aic3106>;
+ clocks = <&atl_clkin2_ck>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ led@0 {
+ label = "dra7:usr1";
+ gpios = <&pcf_lcd 4 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@1 {
+ label = "dra7:usr2";
+ gpios = <&pcf_lcd 5 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@2 {
+ label = "dra7:usr3";
+ gpios = <&pcf_lcd 6 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+
+ led@3 {
+ label = "dra7:usr4";
+ gpios = <&pcf_lcd 7 GPIO_ACTIVE_LOW>;
+ default-state = "off";
+ };
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ autorepeat;
+
+ USER1 {
+ label = "btnUser1";
+ linux,code = <BTN_0>;
+ gpios = <&pcf_lcd 2 GPIO_ACTIVE_LOW>;
+ };
+
+ USER2 {
+ label = "btnUser2";
+ linux,code = <BTN_1>;
+ gpios = <&pcf_lcd 3 GPIO_ACTIVE_LOW>;
+ };
+ };
};
&dra7_pmx_core {
@@ -283,6 +374,31 @@
0x418 (MUX_MODE15 | PULL_UP) /* wakeup0.off */
>;
};
+
+ atl_pins: pinmux_atl_pins {
+ pinctrl-single,pins = <
+ 0x298 (PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
+ 0x29c (PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
+ >;
+ };
+
+ mcasp3_pins: pinmux_mcasp3_pins {
+ pinctrl-single,pins = <
+ 0x324 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
+ 0x328 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
+ 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
+ 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
+ >;
+ };
+
+ mcasp3_sleep_pins: pinmux_mcasp3_sleep_pins {
+ pinctrl-single,pins = <
+ 0x324 (MUX_MODE15)
+ 0x328 (MUX_MODE15)
+ 0x32c (MUX_MODE15)
+ 0x330 (MUX_MODE15)
+ >;
+ };
};
&i2c1 {
@@ -410,6 +526,17 @@
};
};
+ pcf_lcd: gpio@20 {
+ compatible = "nxp,pcf8575";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
pcf_gpio_21: gpio@21 {
compatible = "ti,pcf8575";
reg = <0x21>;
@@ -422,6 +549,20 @@
#interrupt-cells = <2>;
};
+ tlv320aic3106: tlv320aic3106@19 {
+ #sound-dai-cells = <0>;
+ compatible = "ti,tlv320aic3106";
+ reg = <0x19>;
+ adc-settle-ms = <40>;
+ ai3x-micbias-vg = <1>; /* 2.0V */
+ status = "okay";
+
+ /* Regulators */
+ AVDD-supply = <&evm_3v3_sw>;
+ IOVDD-supply = <&evm_3v3_sw>;
+ DRVDD-supply = <&evm_3v3_sw>;
+ DVDD-supply = <&aic_dvdd>;
+ };
};
&i2c2 {
@@ -429,6 +570,20 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c2_pins>;
clock-frequency = <400000>;
+
+ pcf_hdmi: gpio@26 {
+ compatible = "nxp,pcf8575";
+ reg = <0x26>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ p1 {
+ /* vin6_sel_s0: high: VIN6, low: audio */
+ gpio-hog;
+ gpios = <1 GPIO_ACTIVE_HIGH>;
+ output-low;
+ line-name = "vin6_sel_s0";
+ };
+ };
};
&i2c3 {
@@ -479,12 +634,12 @@
* SDCD signal is not being used here - using the fact that GPIO mode
* is always hardwired.
*/
- cd-gpios = <&gpio6 27 0>;
+ cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>;
};
&mmc2 {
status = "okay";
- vmmc-supply = <&mmc2_3v3>;
+ vmmc-supply = <&evm_3v3_sw>;
bus-width = <8>;
};
@@ -707,3 +862,62 @@
pinctrl-1 = <&dcan1_pins_sleep>;
pinctrl-2 = <&dcan1_pins_default>;
};
+
+&atl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&atl_pins>;
+
+ assigned-clocks = <&abe_dpll_sys_clk_mux>,
+ <&atl_gfclk_mux>,
+ <&dpll_abe_ck>,
+ <&dpll_abe_m2x2_ck>,
+ <&atl_clkin2_ck>;
+ assigned-clock-parents = <&sys_clkin2>, <&dpll_abe_m2_ck>;
+ assigned-clock-rates = <0>, <0>, <180633600>, <361267200>, <5644800>;
+
+ status = "okay";
+
+ atl2 {
+ bws = <DRA7_ATL_WS_MCASP2_FSX>;
+ aws = <DRA7_ATL_WS_MCASP3_FSX>;
+ };
+};
+
+&mcasp3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mcasp3_pins>;
+ pinctrl-1 = <&mcasp3_sleep_pins>;
+
+ assigned-clocks = <&mcasp3_ahclkx_mux>;
+ assigned-clock-parents = <&atl_clkin2_ck>;
+
+ status = "okay";
+
+ op-mode = <0>; /* MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ /* 4 serializer */
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 1 2 0 0
+ >;
+};
+
+&mailbox5 {
+ status = "okay";
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ status = "okay";
+ };
+};
+
+&mailbox6 {
+ status = "okay";
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 8fedddc..fe99231 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -292,6 +292,11 @@
#thermal-sensor-cells = <1>;
};
+ dsp1_system: dsp_system@40d00000 {
+ compatible = "syscon";
+ reg = <0x40d00000 0x100>;
+ };
+
sdma: dma-controller@4a056000 {
compatible = "ti,omap4430-sdma";
reg = <0x4a056000 0x1000>;
@@ -911,6 +916,46 @@
status = "disabled";
};
+ mmu0_dsp1: mmu@40d01000 {
+ compatible = "ti,dra7-dsp-iommu";
+ reg = <0x40d01000 0x100>;
+ interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu0_dsp1";
+ #iommu-cells = <0>;
+ ti,syscon-mmuconfig = <&dsp1_system 0x0>;
+ status = "disabled";
+ };
+
+ mmu1_dsp1: mmu@40d02000 {
+ compatible = "ti,dra7-dsp-iommu";
+ reg = <0x40d02000 0x100>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu1_dsp1";
+ #iommu-cells = <0>;
+ ti,syscon-mmuconfig = <&dsp1_system 0x1>;
+ status = "disabled";
+ };
+
+ mmu_ipu1: mmu@58882000 {
+ compatible = "ti,dra7-iommu";
+ reg = <0x58882000 0x100>;
+ interrupts = <GIC_SPI 395 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu_ipu1";
+ #iommu-cells = <0>;
+ ti,iommu-bus-err-back;
+ status = "disabled";
+ };
+
+ mmu_ipu2: mmu@55082000 {
+ compatible = "ti,dra7-iommu";
+ reg = <0x55082000 0x100>;
+ interrupts = <GIC_SPI 396 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu_ipu2";
+ #iommu-cells = <0>;
+ ti,iommu-bus-err-back;
+ status = "disabled";
+ };
+
abb_mpu: regulator-abb-mpu {
compatible = "ti,abb-v3";
regulator-name = "abb_mpu";
@@ -1404,6 +1449,21 @@
status = "disabled";
};
+ mcasp3: mcasp@48468000 {
+ compatible = "ti,dra7-mcasp-audio";
+ ti,hwmods = "mcasp3";
+ reg = <0x48468000 0x2000>;
+ reg-names = "mpu";
+ interrupts = <GIC_SPI 151 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "tx", "rx";
+ dmas = <&sdma_xbar 133>, <&sdma_xbar 132>;
+ dma-names = "tx", "rx";
+ clocks = <&mcasp3_aux_gfclk_mux>, <&mcasp3_ahclkx_mux>;
+ clock-names = "fck", "ahclkx";
+ status = "disabled";
+ };
+
crossbar_mpu: crossbar@4a002a48 {
compatible = "ti,irq-crossbar";
reg = <0x4a002a48 0x130>;
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index 6f6bd98..d6104d5 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -9,6 +9,7 @@
#include "dra72x.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clk/ti-dra7-atl.h>
/ {
model = "TI DRA722";
@@ -30,6 +31,15 @@
regulator-max-microvolt = <3300000>;
};
+ aic_dvdd: fixedregulator-aic_dvdd {
+ /* TPS77018DBVT */
+ compatible = "regulator-fixed";
+ regulator-name = "aic_dvdd";
+ vin-supply = <&evm_3v3>;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
evm_3v3_sd: fixedregulator-sd {
compatible = "regulator-fixed";
regulator-name = "evm_3v3_sd";
@@ -93,6 +103,40 @@
};
};
};
+
+ sound0: sound@0 {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "DRA7xx-EVM";
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Line", "Line Out",
+ "Microphone", "Mic Jack",
+ "Line", "Line In";
+ simple-audio-card,routing =
+ "Headphone Jack", "HPLOUT",
+ "Headphone Jack", "HPROUT",
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "MIC3L", "Mic Jack",
+ "MIC3R", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "LINE1L", "Line In",
+ "LINE1R", "Line In";
+ simple-audio-card,format = "dsp_b";
+ simple-audio-card,bitclock-master = <&sound0_master>;
+ simple-audio-card,frame-master = <&sound0_master>;
+ simple-audio-card,bitclock-inversion;
+
+ sound0_master: simple-audio-card,cpu {
+ sound-dai = <&mcasp3>;
+ system-clock-frequency = <5644800>;
+ };
+
+ simple-audio-card,codec {
+ sound-dai = <&tlv320aic3106>;
+ clocks = <&atl_clkin2_ck>;
+ };
+ };
};
&dra7_pmx_core {
@@ -110,6 +154,13 @@
>;
};
+ i2c5_pins: pinmux_i2c5_pins {
+ pinctrl-single,pins = <
+ 0x2b4 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr0.i2c5_sda */
+ 0x2b8 (PIN_INPUT | MUX_MODE10) /* mcasp1_axr1.i2c5_scl */
+ >;
+ };
+
nand_default: nand_default {
pinctrl-single,pins = <
0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
@@ -220,6 +271,31 @@
0x3b8 (PIN_INPUT_PULLDOWN | MUX_MODE14) /* gpio7_12 HPD */
>;
};
+
+ atl_pins: pinmux_atl_pins {
+ pinctrl-single,pins = <
+ 0x298 (PIN_OUTPUT | MUX_MODE5) /* xref_clk1.atl_clk1 */
+ 0x29c (PIN_OUTPUT | MUX_MODE5) /* xref_clk2.atl_clk2 */
+ >;
+ };
+
+ mcasp3_pins: pinmux_mcasp3_pins {
+ pinctrl-single,pins = <
+ 0x324 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_aclkx */
+ 0x328 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_fsx */
+ 0x32c (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr0 */
+ 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcasp3_axr1 */
+ >;
+ };
+
+ mcasp3_sleep_pins: pinmux_mcasp3_sleep_pins {
+ pinctrl-single,pins = <
+ 0x324 (PIN_INPUT_PULLDOWN | MUX_MODE15)
+ 0x328 (PIN_INPUT_PULLDOWN | MUX_MODE15)
+ 0x32c (PIN_INPUT_PULLDOWN | MUX_MODE15)
+ 0x330 (PIN_INPUT_PULLDOWN | MUX_MODE15)
+ >;
+ };
};
&i2c1 {
@@ -353,12 +429,21 @@
interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
interrupt-controller;
#interrupt-cells = <2>;
+ };
- cpsw_sel_s0 {
- gpio-hog;
- gpios = <4 GPIO_ACTIVE_HIGH>;
- output-low;
- };
+ tlv320aic3106: tlv320aic3106@19 {
+ #sound-dai-cells = <0>;
+ compatible = "ti,tlv320aic3106";
+ reg = <0x19>;
+ adc-settle-ms = <40>;
+ ai3x-micbias-vg = <1>; /* 2.0V */
+ status = "okay";
+
+ /* Regulators */
+ AVDD-supply = <&evm_3v3>;
+ IOVDD-supply = <&evm_3v3>;
+ DRVDD-supply = <&evm_3v3>;
+ DVDD-supply = <&aic_dvdd>;
};
};
@@ -380,6 +465,14 @@
* VIN6_SEL_S0 is low, thus selecting McASP3 over VIN6
*/
lines-initial-states = <0x0f2b>;
+
+ p1 {
+ /* vin6_sel_s0: high: VIN6, low: audio */
+ gpio-hog;
+ gpios = <1 GPIO_ACTIVE_HIGH>;
+ output-low;
+ line-name = "vin6_sel_s0";
+ };
};
};
@@ -514,7 +607,7 @@
* SDCD signal is not being used here - using the fact that GPIO mode
* is a viable alternative
*/
- cd-gpios = <&gpio6 27 0>;
+ cd-gpios = <&gpio6 27 GPIO_ACTIVE_LOW>;
max-frequency = <192000000>;
};
@@ -590,6 +683,7 @@
pinctrl-0 = <&cpsw_default>;
pinctrl-1 = <&cpsw_sleep>;
slaves = <1>;
+ mode-gpios = <&pcf_gpio_21 4 GPIO_ACTIVE_HIGH>;
};
&cpsw_emac0 {
@@ -695,3 +789,59 @@
};
};
};
+
+&atl {
+ pinctrl-names = "default";
+ pinctrl-0 = <&atl_pins>;
+
+ assigned-clocks = <&abe_dpll_sys_clk_mux>,
+ <&atl_gfclk_mux>,
+ <&dpll_abe_ck>,
+ <&dpll_abe_m2x2_ck>,
+ <&atl_clkin2_ck>;
+ assigned-clock-parents = <&sys_clkin2>, <&dpll_abe_m2_ck>;
+ assigned-clock-rates = <0>, <0>, <180633600>, <361267200>, <5644800>;
+
+ status = "okay";
+
+ atl2 {
+ bws = <DRA7_ATL_WS_MCASP2_FSX>;
+ aws = <DRA7_ATL_WS_MCASP3_FSX>;
+ };
+};
+
+&mcasp3 {
+ #sound-dai-cells = <0>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&mcasp3_pins>;
+ pinctrl-1 = <&mcasp3_sleep_pins>;
+
+ assigned-clocks = <&mcasp3_ahclkx_mux>;
+ assigned-clock-parents = <&atl_clkin2_ck>;
+
+ status = "okay";
+
+ op-mode = <0>; /* MCASP_IIS_MODE */
+ tdm-slots = <2>;
+ /* 4 serializer */
+ serial-dir = < /* 0: INACTIVE, 1: TX, 2: RX */
+ 1 2 0 0
+ >;
+};
+
+&mailbox5 {
+ status = "okay";
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ status = "okay";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ status = "okay";
+ };
+};
+
+&mailbox6 {
+ status = "okay";
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/dra72x.dtsi b/arch/arm/boot/dts/dra72x.dtsi
index eaca143..70a2170 100644
--- a/arch/arm/boot/dts/dra72x.dtsi
+++ b/arch/arm/boot/dts/dra72x.dtsi
@@ -45,3 +45,24 @@
<&dss_video1_clk>;
clock-names = "fck", "video1_clk";
};
+
+&mailbox5 {
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ ti,mbox-tx = <6 2 2>;
+ ti,mbox-rx = <4 2 2>;
+ status = "disabled";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ ti,mbox-tx = <5 2 2>;
+ ti,mbox-rx = <1 2 2>;
+ status = "disabled";
+ };
+};
+
+&mailbox6 {
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ ti,mbox-tx = <6 2 2>;
+ ti,mbox-rx = <4 2 2>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
index feea98e..8bcc47d 100644
--- a/arch/arm/boot/dts/dra74x.dtsi
+++ b/arch/arm/boot/dts/dra74x.dtsi
@@ -52,6 +52,11 @@
};
ocp {
+ dsp2_system: dsp_system@41500000 {
+ compatible = "syscon";
+ reg = <0x41500000 0x100>;
+ };
+
omap_dwc3_4: omap_dwc3_4@48940000 {
compatible = "ti,dwc3";
ti,hwmods = "usb_otg_ss4";
@@ -76,6 +81,26 @@
dr_mode = "otg";
};
};
+
+ mmu0_dsp2: mmu@41501000 {
+ compatible = "ti,dra7-dsp-iommu";
+ reg = <0x41501000 0x100>;
+ interrupts = <GIC_SPI 146 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu0_dsp2";
+ #iommu-cells = <0>;
+ ti,syscon-mmuconfig = <&dsp2_system 0x0>;
+ status = "disabled";
+ };
+
+ mmu1_dsp2: mmu@41502000 {
+ compatible = "ti,dra7-dsp-iommu";
+ reg = <0x41502000 0x100>;
+ interrupts = <GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "mmu1_dsp2";
+ #iommu-cells = <0>;
+ ti,syscon-mmuconfig = <&dsp2_system 0x1>;
+ status = "disabled";
+ };
};
};
@@ -93,3 +118,29 @@
<&dss_video2_clk>;
clock-names = "fck", "video1_clk", "video2_clk";
};
+
+&mailbox5 {
+ mbox_ipu1_ipc3x: mbox_ipu1_ipc3x {
+ ti,mbox-tx = <6 2 2>;
+ ti,mbox-rx = <4 2 2>;
+ status = "disabled";
+ };
+ mbox_dsp1_ipc3x: mbox_dsp1_ipc3x {
+ ti,mbox-tx = <5 2 2>;
+ ti,mbox-rx = <1 2 2>;
+ status = "disabled";
+ };
+};
+
+&mailbox6 {
+ mbox_ipu2_ipc3x: mbox_ipu2_ipc3x {
+ ti,mbox-tx = <6 2 2>;
+ ti,mbox-rx = <4 2 2>;
+ status = "disabled";
+ };
+ mbox_dsp2_ipc3x: mbox_dsp2_ipc3x {
+ ti,mbox-tx = <5 2 2>;
+ ti,mbox-rx = <1 2 2>;
+ status = "disabled";
+ };
+};
diff --git a/arch/arm/boot/dts/efm32gg-dk3750.dts b/arch/arm/boot/dts/efm32gg-dk3750.dts
index b4031fa..504cf45 100644
--- a/arch/arm/boot/dts/efm32gg-dk3750.dts
+++ b/arch/arm/boot/dts/efm32gg-dk3750.dts
@@ -26,7 +26,7 @@
};
i2c@4000a000 {
- efm32,location = <3>;
+ energymicro,location = <3>;
status = "ok";
temp@48 {
@@ -43,7 +43,7 @@
spi0: spi@4000c000 { /* USART0 */
cs-gpios = <&gpio 68 1>; // E4
- location = <1>;
+ energymicro,location = <1>;
status = "ok";
microsd@0 {
@@ -57,7 +57,7 @@
spi1: spi@4000c400 { /* USART1 */
cs-gpios = <&gpio 51 1>; // D3
- location = <1>;
+ energymicro,location = <1>;
status = "ok";
ks8851@0 {
@@ -70,7 +70,7 @@
};
uart4: uart@4000e400 { /* UART1 */
- location = <2>;
+ energymicro,location = <2>;
status = "ok";
};
diff --git a/arch/arm/boot/dts/efm32gg.dtsi b/arch/arm/boot/dts/efm32gg.dtsi
index 106d505..c747983 100644
--- a/arch/arm/boot/dts/efm32gg.dtsi
+++ b/arch/arm/boot/dts/efm32gg.dtsi
@@ -23,7 +23,7 @@
soc {
adc: adc@40002000 {
- compatible = "efm32,adc";
+ compatible = "energymicro,efm32-adc";
reg = <0x40002000 0x400>;
interrupts = <7>;
clocks = <&cmu clk_HFPERCLKADC0>;
@@ -31,7 +31,7 @@
};
gpio: gpio@40006000 {
- compatible = "efm32,gpio";
+ compatible = "energymicro,efm32-gpio";
reg = <0x40006000 0x1000>;
interrupts = <1 11>;
gpio-controller;
@@ -45,7 +45,7 @@
i2c0: i2c@4000a000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,i2c";
+ compatible = "energymicro,efm32-i2c";
reg = <0x4000a000 0x400>;
interrupts = <9>;
clocks = <&cmu clk_HFPERCLKI2C0>;
@@ -56,7 +56,7 @@
i2c1: i2c@4000a400 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,i2c";
+ compatible = "energymicro,efm32-i2c";
reg = <0x4000a400 0x400>;
interrupts = <10>;
clocks = <&cmu clk_HFPERCLKI2C1>;
@@ -67,7 +67,7 @@
spi0: spi@4000c000 { /* USART0 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c000 0x400>;
interrupts = <3 4>;
clocks = <&cmu clk_HFPERCLKUSART0>;
@@ -77,7 +77,7 @@
spi1: spi@4000c400 { /* USART1 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu clk_HFPERCLKUSART1>;
@@ -87,7 +87,7 @@
spi2: spi@4000c800 { /* USART2 */
#address-cells = <1>;
#size-cells = <0>;
- compatible = "efm32,spi";
+ compatible = "energymicro,efm32-spi";
reg = <0x4000c800 0x400>;
interrupts = <18 19>;
clocks = <&cmu clk_HFPERCLKUSART2>;
@@ -95,7 +95,7 @@
};
uart0: uart@4000c000 { /* USART0 */
- compatible = "efm32,uart";
+ compatible = "energymicro,efm32-uart";
reg = <0x4000c000 0x400>;
interrupts = <3 4>;
clocks = <&cmu clk_HFPERCLKUSART0>;
@@ -103,7 +103,7 @@
};
uart1: uart@4000c400 { /* USART1 */
- compatible = "efm32,uart";
+ compatible = "energymicro,efm32-uart";
reg = <0x4000c400 0x400>;
interrupts = <15 16>;
clocks = <&cmu clk_HFPERCLKUSART1>;
@@ -111,7 +111,7 @@
};
uart2: uart@4000c800 { /* USART2 */
- compatible = "efm32,uart";
+ compatible = "energymicro,efm32-uart";
reg = <0x4000c800 0x400>;
interrupts = <18 19>;
clocks = <&cmu clk_HFPERCLKUSART2>;
@@ -119,7 +119,7 @@
};
uart3: uart@4000e000 { /* UART0 */
- compatible = "efm32,uart";
+ compatible = "energymicro,efm32-uart";
reg = <0x4000e000 0x400>;
interrupts = <20 21>;
clocks = <&cmu clk_HFPERCLKUART0>;
@@ -127,7 +127,7 @@
};
uart4: uart@4000e400 { /* UART1 */
- compatible = "efm32,uart";
+ compatible = "energymicro,efm32-uart";
reg = <0x4000e400 0x400>;
interrupts = <22 23>;
clocks = <&cmu clk_HFPERCLKUART1>;
@@ -135,28 +135,28 @@
};
timer0: timer@40010000 {
- compatible = "efm32,timer";
+ compatible = "energymicro,efm32-timer";
reg = <0x40010000 0x400>;
interrupts = <2>;
clocks = <&cmu clk_HFPERCLKTIMER0>;
};
timer1: timer@40010400 {
- compatible = "efm32,timer";
+ compatible = "energymicro,efm32-timer";
reg = <0x40010400 0x400>;
interrupts = <12>;
clocks = <&cmu clk_HFPERCLKTIMER1>;
};
timer2: timer@40010800 {
- compatible = "efm32,timer";
+ compatible = "energymicro,efm32-timer";
reg = <0x40010800 0x400>;
interrupts = <13>;
clocks = <&cmu clk_HFPERCLKTIMER2>;
};
timer3: timer@40010c00 {
- compatible = "efm32,timer";
+ compatible = "energymicro,efm32-timer";
reg = <0x40010c00 0x400>;
interrupts = <14>;
clocks = <&cmu clk_HFPERCLKTIMER3>;
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
index 540a0ad..443a350 100644
--- a/arch/arm/boot/dts/exynos3250-monk.dts
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -52,13 +52,13 @@
regulator-name = "V_EMMC_2.8V-fixed";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpk0 2 0>;
+ gpio = <&gpk0 2 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
i2c_max77836: i2c-gpio-0 {
compatible = "i2c-gpio";
- gpios = <&gpd0 2 0>, <&gpd0 3 0>;
+ gpios = <&gpd0 2 GPIO_ACTIVE_HIGH>, <&gpd0 3 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -161,6 +161,7 @@
};
&exynos_usbphy {
+ vbus-supply = <&safeout_reg>;
status = "okay";
};
@@ -266,14 +267,14 @@
regulator-name = "V_EMMC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- samsung,ext-control-gpios = <&gpk0 2 0>;
+ samsung,ext-control-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
ldo12_reg: LDO12 {
regulator-name = "V_EMMC_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- samsung,ext-control-gpios = <&gpk0 2 0>;
+ samsung,ext-control-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
ldo13_reg: LDO13 {
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
index 41a5faf..3e64d5d 100644
--- a/arch/arm/boot/dts/exynos3250-rinato.dts
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -49,7 +49,7 @@
i2c_max77836: i2c-gpio-0 {
compatible = "i2c-gpio";
- gpios = <&gpd0 2 0>, <&gpd0 3 0>;
+ gpios = <&gpd0 2 GPIO_ACTIVE_HIGH>, <&gpd0 3 GPIO_ACTIVE_HIGH>;
#address-cells = <1>;
#size-cells = <0>;
@@ -153,6 +153,7 @@
&exynos_usbphy {
status = "okay";
+ vbus-supply = <&safeout_reg>;
};
&hsotg {
@@ -188,8 +189,8 @@
reg = <0>;
vdd3-supply = <&ldo16_reg>;
vci-supply = <&ldo20_reg>;
- reset-gpios = <&gpe0 1 0>;
- te-gpios = <&gpx0 6 0>;
+ reset-gpios = <&gpe0 1 GPIO_ACTIVE_HIGH>;
+ te-gpios = <&gpx0 6 GPIO_ACTIVE_HIGH>;
power-on-delay= <30>;
power-off-delay= <120>;
reset-delay = <5>;
@@ -368,14 +369,14 @@
regulator-name = "V_EMMC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- samsung,ext-control-gpios = <&gpk0 2 0>;
+ samsung,ext-control-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
ldo12_reg: LDO12 {
regulator-name = "V_EMMC_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- samsung,ext-control-gpios = <&gpk0 2 0>;
+ samsung,ext-control-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
ldo13_reg: LDO13 {
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 033def4..2f30d63 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -333,7 +333,7 @@
};
mshc_0: mshc@12510000 {
- compatible = "samsung,exynos5250-dw-mshc";
+ compatible = "samsung,exynos5420-dw-mshc";
reg = <0x12510000 0x1000>;
interrupts = <0 142 0>;
clocks = <&cmu CLK_SDMMC0>, <&cmu CLK_SCLK_MMC0>;
@@ -345,7 +345,7 @@
};
mshc_1: mshc@12520000 {
- compatible = "samsung,exynos5250-dw-mshc";
+ compatible = "samsung,exynos5420-dw-mshc";
reg = <0x12520000 0x1000>;
interrupts = <0 143 0>;
clocks = <&cmu CLK_SDMMC1>, <&cmu CLK_SCLK_MMC1>;
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 98c0a36..3184e10 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -431,6 +431,8 @@
interrupts = <0 52 0>;
clocks = <&clock CLK_UART0>, <&clock CLK_SCLK_UART0>;
clock-names = "uart", "clk_uart_baud0";
+ dmas = <&pdma0 15>, <&pdma0 16>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -440,6 +442,8 @@
interrupts = <0 53 0>;
clocks = <&clock CLK_UART1>, <&clock CLK_SCLK_UART1>;
clock-names = "uart", "clk_uart_baud0";
+ dmas = <&pdma1 15>, <&pdma1 16>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -449,6 +453,8 @@
interrupts = <0 54 0>;
clocks = <&clock CLK_UART2>, <&clock CLK_SCLK_UART2>;
clock-names = "uart", "clk_uart_baud0";
+ dmas = <&pdma0 17>, <&pdma0 18>;
+ dma-names = "rx", "tx";
status = "disabled";
};
@@ -458,6 +464,8 @@
interrupts = <0 55 0>;
clocks = <&clock CLK_UART3>, <&clock CLK_SCLK_UART3>;
clock-names = "uart", "clk_uart_baud0";
+ dmas = <&pdma1 17>, <&pdma1 18>;
+ dma-names = "rx", "tx";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/exynos4210-origen.dts b/arch/arm/boot/dts/exynos4210-origen.dts
index e050d85..b8f8669 100644
--- a/arch/arm/boot/dts/exynos4210-origen.dts
+++ b/arch/arm/boot/dts/exynos4210-origen.dts
@@ -16,6 +16,7 @@
/dts-v1/;
#include "exynos4210.dtsi"
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
@@ -45,7 +46,7 @@
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpx1 1 0>;
+ gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
};
@@ -57,35 +58,35 @@
up {
label = "Up";
- gpios = <&gpx2 0 1>;
+ gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_UP>;
gpio-key,wakeup;
};
down {
label = "Down";
- gpios = <&gpx2 1 1>;
+ gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_DOWN>;
gpio-key,wakeup;
};
back {
label = "Back";
- gpios = <&gpx1 7 1>;
+ gpios = <&gpx1 7 GPIO_ACTIVE_LOW>;
linux,code = <KEY_BACK>;
gpio-key,wakeup;
};
home {
label = "Home";
- gpios = <&gpx1 6 1>;
+ gpios = <&gpx1 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_HOME>;
gpio-key,wakeup;
};
menu {
label = "Menu";
- gpios = <&gpx1 5 1>;
+ gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
linux,code = <KEY_MENU>;
gpio-key,wakeup;
};
@@ -94,7 +95,7 @@
leds {
compatible = "gpio-leds";
status {
- gpios = <&gpx1 3 1>;
+ gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
linux,default-trigger = "heartbeat";
};
};
diff --git a/arch/arm/boot/dts/exynos4210-smdkv310.dts b/arch/arm/boot/dts/exynos4210-smdkv310.dts
index 043b03c..bc1448b 100644
--- a/arch/arm/boot/dts/exynos4210-smdkv310.dts
+++ b/arch/arm/boot/dts/exynos4210-smdkv310.dts
@@ -16,6 +16,7 @@
/dts-v1/;
#include "exynos4210.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Samsung smdkv310 evaluation board based on Exynos4210";
@@ -182,7 +183,7 @@
};
&spi_2 {
- cs-gpios = <&gpc1 2 0>;
+ cs-gpios = <&gpc1 2 GPIO_ACTIVE_HIGH>;
status = "okay";
w25x80@0 {
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index ba34886..a50be64 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "exynos4210.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Samsung Trats based on Exynos4210";
@@ -39,7 +40,7 @@
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpk0 2 0>;
+ gpio = <&gpk0 2 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -48,7 +49,7 @@
regulator-name = "TSP_FIXED_VOLTAGES";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpl0 3 0>;
+ gpio = <&gpl0 3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -57,7 +58,7 @@
regulator-name = "8M_AF_2.8V_EN";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpk1 1 0>;
+ gpio = <&gpk1 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -66,7 +67,7 @@
regulator-name = "CAM_IO_EN";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpe2 1 0>;
+ gpio = <&gpe2 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -75,7 +76,7 @@
regulator-name = "8M_1.2V_EN";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
- gpio = <&gpe2 5 0>;
+ gpio = <&gpe2 5 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -84,7 +85,7 @@
regulator-name = "VT_CORE_1.5V";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <1500000>;
- gpio = <&gpe2 2 0>;
+ gpio = <&gpe2 2 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
};
@@ -93,21 +94,21 @@
compatible = "gpio-keys";
vol-down-key {
- gpios = <&gpx2 1 1>;
+ gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
linux,code = <114>;
label = "volume down";
debounce-interval = <10>;
};
vol-up-key {
- gpios = <&gpx2 0 1>;
+ gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
linux,code = <115>;
label = "volume up";
debounce-interval = <10>;
};
power-key {
- gpios = <&gpx2 7 1>;
+ gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
debounce-interval = <10>;
@@ -115,7 +116,7 @@
};
ok-key {
- gpios = <&gpx3 5 1>;
+ gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
linux,code = <352>;
label = "ok";
debounce-interval = <10>;
@@ -218,7 +219,7 @@
compatible = "samsung,s6e8aa0";
vdd3-supply = <&vcclcd_reg>;
vci-supply = <&vlcd_reg>;
- reset-gpios = <&gpy4 5 0>;
+ reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
power-on-delay= <50>;
reset-delay = <100>;
init-delay = <100>;
@@ -251,6 +252,7 @@
&exynos_usbphy {
status = "okay";
+ vbus-supply = <&safe1_sreg>;
};
&fimd {
@@ -304,9 +306,9 @@
max8997,pmic-ignore-gpiodvs-side-effect;
max8997,pmic-buck125-default-dvs-idx = <0>;
- max8997,pmic-buck125-dvs-gpios = <&gpx0 5 0>,
- <&gpx0 6 0>,
- <&gpl0 0 0>;
+ max8997,pmic-buck125-dvs-gpios = <&gpx0 5 GPIO_ACTIVE_HIGH>,
+ <&gpx0 6 GPIO_ACTIVE_HIGH>,
+ <&gpl0 0 GPIO_ACTIVE_HIGH>;
max8997,pmic-buck1-dvs-voltage = <1350000>, <1300000>,
<1250000>, <1200000>,
@@ -448,7 +450,6 @@
safe1_sreg: ESAFEOUT1 {
regulator-name = "SAFEOUT1";
- regulator-always-on;
};
safe2_sreg: ESAFEOUT2 {
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index eb37952..81b7ec7 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "exynos4210.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Samsung Universal C210 based on Exynos4210 rev0";
@@ -65,7 +66,7 @@
regulator-name = "VMEM_VDD_2_8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpe1 3 0>;
+ gpio = <&gpe1 3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -73,21 +74,21 @@
compatible = "gpio-keys";
vol-up-key {
- gpios = <&gpx2 0 1>;
+ gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
linux,code = <115>;
label = "volume up";
debounce-interval = <1>;
};
vol-down-key {
- gpios = <&gpx2 1 1>;
+ gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
linux,code = <114>;
label = "volume down";
debounce-interval = <1>;
};
config-key {
- gpios = <&gpx2 2 1>;
+ gpios = <&gpx2 2 GPIO_ACTIVE_LOW>;
linux,code = <171>;
label = "config";
debounce-interval = <1>;
@@ -95,14 +96,14 @@
};
camera-key {
- gpios = <&gpx2 3 1>;
+ gpios = <&gpx2 3 GPIO_ACTIVE_LOW>;
linux,code = <212>;
label = "camera";
debounce-interval = <1>;
};
power-key {
- gpios = <&gpx2 7 1>;
+ gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
debounce-interval = <1>;
@@ -110,7 +111,7 @@
};
ok-key {
- gpios = <&gpx3 5 1>;
+ gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
linux,code = <352>;
label = "ok";
debounce-interval = <1>;
@@ -122,7 +123,7 @@
regulator-name = "TSP_2_8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpe2 3 0>;
+ gpio = <&gpe2 3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -131,17 +132,17 @@
#address-cells = <1>;
#size-cells = <0>;
- gpio-sck = <&gpy3 1 0>;
- gpio-mosi = <&gpy3 3 0>;
+ gpio-sck = <&gpy3 1 GPIO_ACTIVE_HIGH>;
+ gpio-mosi = <&gpy3 3 GPIO_ACTIVE_HIGH>;
num-chipselects = <1>;
- cs-gpios = <&gpy4 3 0>;
+ cs-gpios = <&gpy4 3 GPIO_ACTIVE_HIGH>;
lcd@0 {
compatible = "samsung,ld9040";
reg = <0>;
vdd3-supply = <&ldo7_reg>;
vci-supply = <&ldo17_reg>;
- reset-gpios = <&gpy4 5 0>;
+ reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
spi-max-frequency = <1200000>;
spi-cpol;
spi-cpha;
@@ -218,13 +219,13 @@
regulator-name = "HDMI_5V";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gpe0 1 0>;
+ gpio = <&gpe0 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
hdmi_ddc: i2c-ddc {
compatible = "i2c-gpio";
- gpios = <&gpe4 2 0 &gpe4 3 0>;
+ gpios = <&gpe4 2 GPIO_ACTIVE_HIGH &gpe4 3 GPIO_ACTIVE_HIGH>;
i2c-gpio,delay-us = <100>;
#address-cells = <1>;
#size-cells = <0>;
@@ -248,6 +249,7 @@
&exynos_usbphy {
status = "okay";
+ vbus-supply = <&safeout1_reg>;
};
&fimd {
@@ -267,7 +269,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 0>;
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd>;
hdmi-en-supply = <&hdmi_en>;
@@ -311,7 +313,8 @@
compatible = "maxim,max8952";
reg = <0x60>;
- max8952,vid-gpios = <&gpx0 3 0>, <&gpx0 4 0>;
+ max8952,vid-gpios = <&gpx0 3 GPIO_ACTIVE_HIGH>,
+ <&gpx0 4 GPIO_ACTIVE_HIGH>;
max8952,default-mode = <0>;
max8952,dvs-mode-microvolt = <1250000>, <1200000>,
<1050000>, <950000>;
@@ -330,13 +333,13 @@
reg = <0x66>;
max8998,pmic-buck1-default-dvs-idx = <0>;
- max8998,pmic-buck1-dvs-gpios = <&gpx0 5 0>,
- <&gpx0 6 0>;
+ max8998,pmic-buck1-dvs-gpios = <&gpx0 5 GPIO_ACTIVE_HIGH>,
+ <&gpx0 6 GPIO_ACTIVE_HIGH>;
max8998,pmic-buck1-dvs-voltage = <1100000>, <1000000>,
<1100000>, <1000000>;
max8998,pmic-buck2-default-dvs-idx = <0>;
- max8998,pmic-buck2-dvs-gpio = <&gpe2 0 0>;
+ max8998,pmic-buck2-dvs-gpio = <&gpe2 0 GPIO_ACTIVE_HIGH>;
max8998,pmic-buck2-dvs-voltage = <1200000>, <1100000>;
regulators {
@@ -486,7 +489,6 @@
safeout1_reg: ESAFEOUT1 {
regulator-name = "SAFEOUT1";
- regulator-always-on;
};
safeout2_reg: ESAFEOUT2 {
@@ -551,7 +553,7 @@
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
pinctrl-names = "default";
vmmc-supply = <&ldo5_reg>;
- cd-gpios = <&gpx3 4 0>;
+ cd-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>;
cd-inverted;
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index db52841..edf0fc8 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/clock/maxim,max77686.h>
#include "exynos4412.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
chosen {
@@ -30,7 +31,7 @@
power_key {
interrupt-parent = <&gpx1>;
interrupts = <3 0>;
- gpios = <&gpx1 3 1>;
+ gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
linux,code = <KEY_POWER>;
label = "power key";
debounce-interval = <10>;
@@ -70,7 +71,7 @@
pinctrl-0 = <&sd1_cd>;
pinctrl-names = "default";
compatible = "mmc-pwrseq-emmc";
- reset-gpios = <&gpk1 2 1>;
+ reset-gpios = <&gpk1 2 GPIO_ACTIVE_LOW>;
};
camera {
@@ -181,7 +182,7 @@
};
&hdmi {
- hpd-gpio = <&gpx3 7 0>;
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd>;
vdd-supply = <&ldo8_reg>;
@@ -199,8 +200,6 @@
};
&i2c_0 {
- pinctrl-0 = <&i2c0_bus>;
- pinctrl-names = "default";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <400000>;
status = "okay";
@@ -209,9 +208,9 @@
compatible = "smsc,usb3503";
reg = <0x08>;
- intn-gpios = <&gpx3 0 0>;
- connect-gpios = <&gpx3 4 0>;
- reset-gpios = <&gpx3 5 0>;
+ intn-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>;
+ connect-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpx3 5 GPIO_ACTIVE_HIGH>;
initial-mode = <1>;
};
@@ -276,15 +275,13 @@
regulator-always-on;
};
- ldo8_reg: ldo@8 {
- regulator-compatible = "LDO8";
+ ldo8_reg: LDO8 {
regulator-name = "VDD10_HDMI_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
};
- ldo10_reg: ldo@10 {
- regulator-compatible = "LDO10";
+ ldo10_reg: LDO10 {
regulator-name = "VDDQ_MIPIHSI_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -424,8 +421,6 @@
};
&i2c_1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_bus>;
status = "okay";
max98090: max98090@10 {
compatible = "maxim,max98090";
@@ -440,8 +435,6 @@
&i2c_2 {
status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_bus>;
};
&i2c_8 {
@@ -490,7 +483,7 @@
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
pinctrl-names = "default";
vmmc-supply = <&ldo4_reg &ldo21_reg>;
- cd-gpios = <&gpk2 2 0>;
+ cd-gpios = <&gpk2 2 GPIO_ACTIVE_HIGH>;
cd-inverted;
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts
index 8632f35..646ff0b 100644
--- a/arch/arm/boot/dts/exynos4412-odroidu3.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts
@@ -27,11 +27,54 @@
compatible = "gpio-leds";
led1 {
label = "led1:heart";
- gpios = <&gpc1 0 1>;
+ gpios = <&gpc1 0 GPIO_ACTIVE_LOW>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
};
+
+ fan0: pwm-fan {
+ compatible = "pwm-fan";
+ pwms = <&pwm 0 10000 0>;
+ cooling-min-state = <0>;
+ cooling-max-state = <3>;
+ #cooling-cells = <2>;
+ cooling-levels = <0 102 170 230>;
+ };
+
+ thermal-zones {
+ cpu_thermal: cpu-thermal {
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&cpu0 7 7>;
+ };
+ map1 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&cpu0 13 13>;
+ };
+ map2 {
+ trip = <&cpu_alert0>;
+ cooling-device = <&fan0 0 1>;
+ };
+ map3 {
+ trip = <&cpu_alert1>;
+ cooling-device = <&fan0 1 2>;
+ };
+ map4 {
+ trip = <&cpu_alert2>;
+ cooling-device = <&fan0 2 3>;
+ };
+ };
+ };
+ };
+};
+
+&pwm {
+ pinctrl-0 = <&pwm0_out>;
+ pinctrl-names = "default";
+ samsung,pwm-outputs = <0>;
+ status = "okay";
};
&usb3503 {
diff --git a/arch/arm/boot/dts/exynos4412-odroidx.dts b/arch/arm/boot/dts/exynos4412-odroidx.dts
index 679ac10..b44bb68 100644
--- a/arch/arm/boot/dts/exynos4412-odroidx.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidx.dts
@@ -26,13 +26,13 @@
compatible = "gpio-leds";
led1 {
label = "led1:heart";
- gpios = <&gpc1 0 1>;
+ gpios = <&gpc1 0 GPIO_ACTIVE_LOW>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
led2 {
label = "led2:mmc0";
- gpios = <&gpc1 2 1>;
+ gpios = <&gpc1 2 GPIO_ACTIVE_LOW>;
default-state = "on";
linux,default-trigger = "mmc0";
};
@@ -44,7 +44,7 @@
home_key {
interrupt-parent = <&gpx2>;
interrupts = <2 0>;
- gpios = <&gpx2 2 0>;
+ gpios = <&gpx2 2 GPIO_ACTIVE_HIGH>;
linux,code = <KEY_HOME>;
label = "home key";
debounce-interval = <10>;
@@ -57,7 +57,7 @@
regulator-name = "p3v3_en";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpa1 1 1>;
+ gpio = <&gpa1 1 GPIO_ACTIVE_LOW>;
enable-active-high;
regulator-always-on;
};
diff --git a/arch/arm/boot/dts/exynos4412-origen.dts b/arch/arm/boot/dts/exynos4412-origen.dts
index 9d528af..c8d86af 100644
--- a/arch/arm/boot/dts/exynos4412-origen.dts
+++ b/arch/arm/boot/dts/exynos4412-origen.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "exynos4412.dtsi"
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
/ {
@@ -45,7 +46,7 @@
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpx1 1 0>;
+ gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
};
@@ -107,13 +108,13 @@
s5m8767,pmic-buck-default-dvs-idx = <3>;
- s5m8767,pmic-buck-dvs-gpios = <&gpx2 3 0>,
- <&gpx2 4 0>,
- <&gpx2 5 0>;
+ s5m8767,pmic-buck-dvs-gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>,
+ <&gpx2 4 GPIO_ACTIVE_HIGH>,
+ <&gpx2 5 GPIO_ACTIVE_HIGH>;
- s5m8767,pmic-buck-ds-gpios = <&gpm3 5 0>,
- <&gpm3 6 0>,
- <&gpm3 7 0>;
+ s5m8767,pmic-buck-ds-gpios = <&gpm3 5 GPIO_ACTIVE_HIGH>,
+ <&gpm3 6 GPIO_ACTIVE_HIGH>,
+ <&gpm3 7 GPIO_ACTIVE_HIGH>;
s5m8767,pmic-buck2-dvs-voltage = <1250000>, <1200000>,
<1200000>, <1200000>,
diff --git a/arch/arm/boot/dts/exynos4412-tiny4412.dts b/arch/arm/boot/dts/exynos4412-tiny4412.dts
index 525684c..4840bbd 100644
--- a/arch/arm/boot/dts/exynos4412-tiny4412.dts
+++ b/arch/arm/boot/dts/exynos4412-tiny4412.dts
@@ -13,6 +13,7 @@
/dts-v1/;
#include "exynos4412.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "FriendlyARM TINY4412 board based on Exynos4412";
@@ -31,26 +32,26 @@
led1 {
label = "led1";
- gpios = <&gpm4 0 1>;
+ gpios = <&gpm4 0 GPIO_ACTIVE_LOW>;
default-state = "off";
linux,default-trigger = "heartbeat";
};
led2 {
label = "led2";
- gpios = <&gpm4 1 1>;
+ gpios = <&gpm4 1 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led3 {
label = "led3";
- gpios = <&gpm4 2 1>;
+ gpios = <&gpm4 2 GPIO_ACTIVE_LOW>;
default-state = "off";
};
led4 {
label = "led4";
- gpios = <&gpm4 3 1>;
+ gpios = <&gpm4 3 GPIO_ACTIVE_LOW>;
default-state = "off";
linux,default-trigger = "mmc0";
};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 2a1ebb7..40a474c 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -65,7 +65,7 @@
regulator-name = "CAM_SENSOR_A";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpm0 2 0>;
+ gpio = <&gpm0 2 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -74,7 +74,7 @@
regulator-name = "LCD_VDD_2.2V";
regulator-min-microvolt = <2200000>;
regulator-max-microvolt = <2200000>;
- gpio = <&gpc0 1 0>;
+ gpio = <&gpc0 1 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -83,7 +83,7 @@
regulator-name = "CAM_AF";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpm0 4 0>;
+ gpio = <&gpm0 4 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
@@ -92,7 +92,7 @@
regulator-name = "LED_A_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
- gpio = <&gpj0 5 0>;
+ gpio = <&gpj0 5 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
};
@@ -101,21 +101,21 @@
compatible = "gpio-keys";
key-down {
- gpios = <&gpx3 3 1>;
+ gpios = <&gpx3 3 GPIO_ACTIVE_LOW>;
linux,code = <114>;
label = "volume down";
debounce-interval = <10>;
};
key-up {
- gpios = <&gpx2 2 1>;
+ gpios = <&gpx2 2 GPIO_ACTIVE_LOW>;
linux,code = <115>;
label = "volume up";
debounce-interval = <10>;
};
key-power {
- gpios = <&gpx2 7 1>;
+ gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
linux,code = <116>;
label = "power";
debounce-interval = <10>;
@@ -123,7 +123,7 @@
};
key-ok {
- gpios = <&gpx0 1 1>;
+ gpios = <&gpx0 1 GPIO_ACTIVE_LOW>;
linux,code = <139>;
label = "ok";
debounce-inteval = <10>;
@@ -198,7 +198,7 @@
i2c_ak8975: i2c-gpio-0 {
compatible = "i2c-gpio";
- gpios = <&gpy2 4 0>, <&gpy2 5 0>;
+ gpios = <&gpy2 4 GPIO_ACTIVE_HIGH>, <&gpy2 5 GPIO_ACTIVE_HIGH>;
i2c-gpio,delay-us = <2>;
#address-cells = <1>;
#size-cells = <0>;
@@ -207,13 +207,13 @@
ak8975@0c {
compatible = "asahi-kasei,ak8975";
reg = <0x0c>;
- gpios = <&gpj0 7 0>;
+ gpios = <&gpj0 7 GPIO_ACTIVE_HIGH>;
};
};
i2c_cm36651: i2c-gpio-2 {
compatible = "i2c-gpio";
- gpios = <&gpf0 0 1>, <&gpf0 1 1>;
+ gpios = <&gpf0 0 GPIO_ACTIVE_LOW>, <&gpf0 1 GPIO_ACTIVE_LOW>;
i2c-gpio,delay-us = <2>;
#address-cells = <1>;
#size-cells = <0>;
@@ -359,7 +359,7 @@
reg = <0>;
vdd3-supply = <&lcd_vdd3_reg>;
vci-supply = <&ldo25_reg>;
- reset-gpios = <&gpy4 5 0>;
+ reset-gpios = <&gpy4 5 GPIO_ACTIVE_HIGH>;
power-on-delay= <50>;
reset-delay = <100>;
init-delay = <100>;
@@ -391,6 +391,7 @@
};
&exynos_usbphy {
+ vbus-supply = <&esafeout1_reg>;
status = "okay";
};
@@ -446,7 +447,7 @@
clocks = <&camera 1>;
clock-names = "extclk";
samsung,camclk-out = <1>;
- gpios = <&gpm1 6 0>;
+ gpios = <&gpm1 6 GPIO_ACTIVE_HIGH>;
port {
is_s5k6a3_ep: endpoint {
@@ -488,8 +489,8 @@
s5c73m3@3c {
compatible = "samsung,s5c73m3";
reg = <0x3c>;
- standby-gpios = <&gpm0 1 1>; /* ISP_STANDBY */
- xshutdown-gpios = <&gpf1 3 1>; /* ISP_RESET */
+ standby-gpios = <&gpm0 1 GPIO_ACTIVE_LOW>; /* ISP_STANDBY */
+ xshutdown-gpios = <&gpf1 3 GPIO_ACTIVE_LOW>; /* ISP_RESET */
vdd-int-supply = <&buck9_reg>;
vddio-cis-supply = <&ldo9_reg>;
vdda-supply = <&ldo17_reg>;
@@ -564,16 +565,14 @@
#clock-cells = <1>;
voltage-regulators {
- ldo1_reg: ldo1 {
- regulator-compatible = "LDO1";
+ ldo1_reg: LDO1 {
regulator-name = "VALIVE_1.0V_AP";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
};
- ldo2_reg: ldo2 {
- regulator-compatible = "LDO2";
+ ldo2_reg: LDO2 {
regulator-name = "VM1M2_1.2V_AP";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
@@ -583,32 +582,28 @@
};
};
- ldo3_reg: ldo3 {
- regulator-compatible = "LDO3";
+ ldo3_reg: LDO3 {
regulator-name = "VCC_1.8V_AP";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
- ldo4_reg: ldo4 {
- regulator-compatible = "LDO4";
+ ldo4_reg: LDO4 {
regulator-name = "VCC_2.8V_AP";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-always-on;
};
- ldo5_reg: ldo5 {
- regulator-compatible = "LDO5";
+ ldo5_reg: LDO5 {
regulator-name = "VCC_1.8V_IO";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
};
- ldo6_reg: ldo6 {
- regulator-compatible = "LDO6";
+ ldo6_reg: LDO6 {
regulator-name = "VMPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
@@ -618,8 +613,7 @@
};
};
- ldo7_reg: ldo7 {
- regulator-compatible = "LDO7";
+ ldo7_reg: LDO7 {
regulator-name = "VPLL_1.0V_AP";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
@@ -629,8 +623,7 @@
};
};
- ldo8_reg: ldo8 {
- regulator-compatible = "LDO8";
+ ldo8_reg: LDO8 {
regulator-name = "VMIPI_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
@@ -639,15 +632,13 @@
};
};
- ldo9_reg: ldo9 {
- regulator-compatible = "LDO9";
+ ldo9_reg: LDO9 {
regulator-name = "CAM_ISP_MIPI_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
- ldo10_reg: ldo10 {
- regulator-compatible = "LDO10";
+ ldo10_reg: LDO10 {
regulator-name = "VMIPI_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -656,8 +647,7 @@
};
};
- ldo11_reg: ldo11 {
- regulator-compatible = "LDO11";
+ ldo11_reg: LDO11 {
regulator-name = "VABB1_1.95V";
regulator-min-microvolt = <1950000>;
regulator-max-microvolt = <1950000>;
@@ -667,8 +657,7 @@
};
};
- ldo12_reg: ldo12 {
- regulator-compatible = "LDO12";
+ ldo12_reg: LDO12 {
regulator-name = "VUOTG_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
@@ -677,15 +666,13 @@
};
};
- ldo13_reg: ldo13 {
- regulator-compatible = "LDO13";
+ ldo13_reg: LDO13 {
regulator-name = "NFC_AVDD_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo14_reg: ldo14 {
- regulator-compatible = "LDO14";
+ ldo14_reg: LDO14 {
regulator-name = "VABB2_1.95V";
regulator-min-microvolt = <1950000>;
regulator-max-microvolt = <1950000>;
@@ -695,8 +682,7 @@
};
};
- ldo15_reg: ldo15 {
- regulator-compatible = "LDO15";
+ ldo15_reg: LDO15 {
regulator-name = "VHSIC_1.0V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
@@ -705,8 +691,7 @@
};
};
- ldo16_reg: ldo16 {
- regulator-compatible = "LDO16";
+ ldo16_reg: LDO16 {
regulator-name = "VHSIC_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -715,80 +700,69 @@
};
};
- ldo17_reg: ldo17 {
- regulator-compatible = "LDO17";
+ ldo17_reg: LDO17 {
regulator-name = "CAM_SENSOR_CORE_1.2V";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
};
- ldo18_reg: ldo18 {
- regulator-compatible = "LDO18";
+ ldo18_reg: LDO18 {
regulator-name = "CAM_ISP_SEN_IO_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo19_reg: ldo19 {
- regulator-compatible = "LDO19";
+ ldo19_reg: LDO19 {
regulator-name = "VT_CAM_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo20_reg: ldo20 {
- regulator-compatible = "LDO20";
+ ldo20_reg: LDO20 {
regulator-name = "VDDQ_PRE_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo21_reg: ldo21 {
- regulator-compatible = "LDO21";
+ ldo21_reg: LDO21 {
regulator-name = "VTF_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
maxim,ena-gpios = <&gpy2 0 GPIO_ACTIVE_HIGH>;
};
- ldo22_reg: ldo22 {
- regulator-compatible = "LDO22";
+ ldo22_reg: LDO22 {
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
- ldo23_reg: ldo23 {
- regulator-compatible = "LDO23";
+ ldo23_reg: LDO23 {
regulator-name = "TSP_AVDD_3.3V";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
- ldo24_reg: ldo24 {
- regulator-compatible = "LDO24";
+ ldo24_reg: LDO24 {
regulator-name = "TSP_VDD_1.8V";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
};
- ldo25_reg: ldo25 {
- regulator-compatible = "LDO25";
+ ldo25_reg: LDO25 {
regulator-name = "LCD_VCC_3.3V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
};
- ldo26_reg: ldo26 {
- regulator-compatible = "LDO26";
+ ldo26_reg: LDO26 {
regulator-name = "MOTOR_VCC_3.0V";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
};
- buck1_reg: buck1 {
- regulator-compatible = "BUCK1";
+ buck1_reg: BUCK1 {
regulator-name = "vdd_mif";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1100000>;
@@ -799,8 +773,7 @@
};
};
- buck2_reg: buck2 {
- regulator-compatible = "BUCK2";
+ buck2_reg: BUCK2 {
regulator-name = "vdd_arm";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1500000>;
@@ -811,8 +784,7 @@
};
};
- buck3_reg: buck3 {
- regulator-compatible = "BUCK3";
+ buck3_reg: BUCK3 {
regulator-name = "vdd_int";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
@@ -823,8 +795,7 @@
};
};
- buck4_reg: buck4 {
- regulator-compatible = "BUCK4";
+ buck4_reg: BUCK4 {
regulator-name = "vdd_g3d";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <1150000>;
@@ -834,40 +805,35 @@
};
};
- buck5_reg: buck5 {
- regulator-compatible = "BUCK5";
+ buck5_reg: BUCK5 {
regulator-name = "VMEM_1.2V_AP";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1200000>;
regulator-always-on;
};
- buck6_reg: buck6 {
- regulator-compatible = "BUCK6";
+ buck6_reg: BUCK6 {
regulator-name = "VCC_SUB_1.35V";
regulator-min-microvolt = <1350000>;
regulator-max-microvolt = <1350000>;
regulator-always-on;
};
- buck7_reg: buck7 {
- regulator-compatible = "BUCK7";
+ buck7_reg: BUCK7 {
regulator-name = "VCC_SUB_2.0V";
regulator-min-microvolt = <2000000>;
regulator-max-microvolt = <2000000>;
regulator-always-on;
};
- buck8_reg: buck8 {
- regulator-compatible = "BUCK8";
+ buck8_reg: BUCK8 {
regulator-name = "VMEM_VDDF_3.0V";
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
maxim,ena-gpios = <&gpk0 2 GPIO_ACTIVE_HIGH>;
};
- buck9_reg: buck9 {
- regulator-compatible = "BUCK9";
+ buck9_reg: BUCK9 {
regulator-name = "CAM_ISP_CORE_1.2V";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1200000>;
@@ -1276,7 +1242,7 @@
&sdhci_2 {
bus-width = <4>;
- cd-gpios = <&gpx3 4 0>;
+ cd-gpios = <&gpx3 4 GPIO_ACTIVE_HIGH>;
cd-inverted;
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
pinctrl-names = "default";
@@ -1303,7 +1269,7 @@
&spi_1 {
pinctrl-names = "default";
pinctrl-0 = <&spi1_bus>;
- cs-gpios = <&gpb 5 0>;
+ cs-gpios = <&gpb 5 GPIO_ACTIVE_HIGH>;
status = "okay";
s5c73m3_spi: s5c73m3 {
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index db3f65f..c000532 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -129,10 +129,6 @@
samsung,color-depth = <1>;
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
-};
-
-&fimd {
- status = "okay";
display-timings {
native-mode = <&timing0>;
@@ -152,6 +148,10 @@
};
};
+&fimd {
+ status = "okay";
+};
+
&hdmi {
hpd-gpio = <&gpx3 7 GPIO_ACTIVE_LOW>;
vdd_osc-supply = <&ldo10_reg>;
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index c625e71..0f5dcd4 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -89,14 +89,6 @@
pinctrl-names = "default";
pinctrl-0 = <&dp_hpd>;
status = "okay";
-};
-
-&ehci {
- samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
-};
-
-&fimd {
- status = "okay";
display-timings {
native-mode = <&timing0>;
@@ -116,6 +108,14 @@
};
};
+&ehci {
+ samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
+};
+
+&fimd {
+ status = "okay";
+};
+
&hdmi {
hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
};
diff --git a/arch/arm/boot/dts/exynos5250-snow-common.dtsi b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
new file mode 100644
index 0000000..0a7f408
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-snow-common.dtsi
@@ -0,0 +1,684 @@
+/*
+ * Google Snow board device tree source
+ *
+ * Copyright (c) 2012 Google, 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 <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/maxim,max77686.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
+#include "exynos5250.dtsi"
+
+/ {
+ aliases {
+ i2c104 = &i2c_104;
+ };
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ chosen {
+ bootargs = "console=tty1";
+ stdout-path = "serial3:115200n8";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&power_key_irq &lid_irq>;
+
+ power {
+ label = "Power";
+ gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ gpio-key,wakeup;
+ };
+
+ lid-switch {
+ label = "Lid";
+ gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <5>; /* EV_SW */
+ linux,code = <0>; /* SW_LID */
+ debounce-interval = <1>;
+ gpio-key,wakeup;
+ };
+ };
+
+ vbat: vbat-fixed-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vbat-supply";
+ regulator-boot-on;
+ };
+
+ i2c-arbitrator {
+ compatible = "i2c-arb-gpio-challenge";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c-parent = <&{/i2c@12CA0000}>;
+
+ our-claim-gpio = <&gpf0 3 GPIO_ACTIVE_LOW>;
+ their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>;
+ slew-delay-us = <10>;
+ wait-retry-us = <3000>;
+ wait-free-us = <50000>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&arb_our_claim &arb_their_claim>;
+
+ /* Use ID 104 as a hint that we're on physical bus 4 */
+ i2c_104: i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ battery: sbs-battery@b {
+ compatible = "sbs,sbs-battery";
+ reg = <0xb>;
+ sbs,poll-retry-count = <1>;
+ };
+
+ cros_ec: embedded-controller {
+ compatible = "google,cros-ec-i2c";
+ reg = <0x1e>;
+ interrupts = <6 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ec_irq>;
+ wakeup-source;
+ };
+
+ power-regulator {
+ compatible = "ti,tps65090";
+ reg = <0x48>;
+
+ /*
+ * Config irq to disable internal pulls
+ * even though we run in polling mode.
+ */
+ pinctrl-names = "default";
+ pinctrl-0 = <&tps65090_irq>;
+
+ vsys1-supply = <&vbat>;
+ vsys2-supply = <&vbat>;
+ vsys3-supply = <&vbat>;
+ infet1-supply = <&vbat>;
+ infet2-supply = <&vbat>;
+ infet3-supply = <&vbat>;
+ infet4-supply = <&vbat>;
+ infet5-supply = <&vbat>;
+ infet6-supply = <&vbat>;
+ infet7-supply = <&vbat>;
+ vsys-l1-supply = <&vbat>;
+ vsys-l2-supply = <&vbat>;
+
+ regulators {
+ dcdc1 {
+ ti,enable-ext-control;
+ };
+ dcdc2 {
+ ti,enable-ext-control;
+ };
+ dcdc3 {
+ ti,enable-ext-control;
+ };
+ fet1: fet1 {
+ regulator-name = "vcd_led";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet2: fet2 {
+ regulator-name = "video_mid";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet3 {
+ regulator-name = "wwan_r";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet4 {
+ regulator-name = "sdcard";
+ ti,overcurrent-wait = <3>;
+ };
+ fet5 {
+ regulator-name = "camout";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ fet6: fet6 {
+ regulator-name = "lcd_vdd";
+ ti,overcurrent-wait = <3>;
+ };
+ tps65090_fet7: fet7 {
+ regulator-name = "video_mid_1a";
+ regulator-always-on;
+ ti,overcurrent-wait = <3>;
+ };
+ ldo1 {
+ };
+ ldo2 {
+ };
+ };
+
+ charger {
+ compatible = "ti,tps65090-charger";
+ };
+ };
+ };
+ };
+
+ sound {
+ samsung,i2s-controller = <&i2s0>;
+ };
+
+ usb3_vbus_reg: regulator-usb3 {
+ compatible = "regulator-fixed";
+ regulator-name = "P5.0V_USB3CON";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb3_vbus_en>;
+ enable-active-high;
+ };
+
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <24000000>;
+ };
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 1000000 0>;
+ brightness-levels = <0 100 500 1000 1500 2000 2500 2800>;
+ default-brightness-level = <7>;
+ enable-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>;
+ power-supply = <&fet1>;
+ pinctrl-0 = <&pwm0_out>;
+ pinctrl-names = "default";
+ };
+
+ panel: panel {
+ compatible = "auo,b116xw03";
+ power-supply = <&fet6>;
+ backlight = <&backlight>;
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&bridge_out>;
+ };
+ };
+ };
+
+ mmc3_pwrseq: mmc3_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&gpx0 2 GPIO_ACTIVE_LOW>, /* WIFI_RSTn */
+ <&gpx0 1 GPIO_ACTIVE_LOW>; /* WIFI_EN */
+ clocks = <&max77686 MAX77686_CLK_PMIC>;
+ clock-names = "ext_clock";
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&buck2_reg>;
+};
+
+&dp {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd>;
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <2>;
+ samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
+
+ ports {
+ port@0 {
+ dp_out: endpoint {
+ remote-endpoint = <&bridge_in>;
+ };
+ };
+ };
+};
+
+&ehci {
+ samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
+};
+
+&fimd {
+ status = "okay";
+ samsung,invert-vclk;
+};
+
+&hdmi {
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd_irq>;
+ phy = <&hdmiphy>;
+ ddc = <&i2c_2>;
+ hdmi-en-supply = <&tps65090_fet7>;
+ vdd-supply = <&ldo8_reg>;
+ vdd_osc-supply = <&ldo10_reg>;
+ vdd_pll-supply = <&ldo8_reg>;
+};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ max77686: max77686@09 {
+ compatible = "maxim,max77686";
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&max77686_irq>;
+ wakeup-source;
+ reg = <0x09>;
+ #clock-cells = <1>;
+
+ voltage-regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "P1.0V_LDO_OUT1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "P1.8V_LDO_OUT2";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "P1.8V_LDO_OUT3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "P1.35V_BUCK_OUT6";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "P2.0V_BUCK_OUT7";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "P2.85V_BUCK_OUT8";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c_1 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ trackpad {
+ reg = <0x67>;
+ compatible = "cypress,cyapa";
+ interrupts = <2 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx1>;
+ wakeup-source;
+ };
+};
+
+/*
+ * Disabled pullups since external part has its own pullups and
+ * double-pulling gets us out of spec in some cases.
+ */
+&i2c2_bus {
+ samsung,pin-pud = <0>;
+};
+
+&i2c_2 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
+ };
+};
+
+&i2c_3 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_4 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_5 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_7 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ ptn3460: lvds-bridge@20 {
+ compatible = "nxp,ptn3460";
+ reg = <0x20>;
+ powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
+ reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
+ edid-emulation = <5>;
+
+ ports {
+ port@0 {
+ bridge_out: endpoint {
+ remote-endpoint = <&panel_in>;
+ };
+ };
+
+ port@1 {
+ bridge_in: endpoint {
+ remote-endpoint = <&dp_out>;
+ };
+ };
+ };
+ };
+};
+
+&i2c_8 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ hdmiphy: hdmiphy@38 {
+ compatible = "samsung,exynos4212-hdmiphy";
+ reg = <0x38>;
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
+
+&mmc_0 {
+ status = "okay";
+ num-slots = <1>;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
+&mmc_2 {
+ status = "okay";
+ num-slots = <1>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ bus-width = <4>;
+ wp-gpios = <&gpc2 1 GPIO_ACTIVE_HIGH>;
+ cap-sd-highspeed;
+};
+
+/*
+ * On Snow we've got SIP WiFi and so can keep drive strengths low to
+ * reduce EMI.
+ */
+&mmc_3 {
+ status = "okay";
+ num-slots = <1>;
+ broken-cd;
+ cap-sdio-irq;
+ keep-power-in-suspend;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4 &wifi_en &wifi_rst>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+ mmc-pwrseq = <&mmc3_pwrseq>;
+};
+
+&pinctrl_0 {
+ wifi_en: wifi-en {
+ samsung,pins = "gpx0-1";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ wifi_rst: wifi-rst {
+ samsung,pins = "gpx0-2";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ power_key_irq: power-key-irq {
+ samsung,pins = "gpx1-3";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ ec_irq: ec-irq {
+ samsung,pins = "gpx1-6";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ tps65090_irq: tps65090-irq {
+ samsung,pins = "gpx2-6";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ usb3_vbus_en: usb3-vbus-en {
+ samsung,pins = "gpx2-7";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ max77686_irq: max77686-irq {
+ samsung,pins = "gpx3-2";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ lid_irq: lid-irq {
+ samsung,pins = "gpx3-5";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ hdmi_hpd_irq: hdmi-hpd-irq {
+ samsung,pins = "gpx3-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_1 {
+ arb_their_claim: arb-their-claim {
+ samsung,pins = "gpe0-4";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ arb_our_claim: arb-our-claim {
+ samsung,pins = "gpf0-3";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
+
+&sd3_bus4 {
+ samsung,pin-drv = <0>;
+};
+
+&sd3_clk {
+ samsung,pin-drv = <0>;
+};
+
+&sd3_cmd {
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+};
+
+&spi_1 {
+ status = "okay";
+ samsung,spi-src-clk = <0>;
+ num-cs = <1>;
+ cs-gpios = <&gpa2 5 GPIO_ACTIVE_HIGH>;
+};
+
+&usbdrd_dwc3 {
+ dr_mode = "host";
+};
+
+&usbdrd_phy {
+ vbus-supply = <&usb3_vbus_reg>;
+};
+
+#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/boot/dts/exynos5250-snow-rev5.dts b/arch/arm/boot/dts/exynos5250-snow-rev5.dts
new file mode 100644
index 0000000..f811dc8
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-snow-rev5.dts
@@ -0,0 +1,47 @@
+/*
+ * Google Snow Rev 5+ board device tree source
+ *
+ * Copyright (c) 2012 Google, Inc
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+#include "exynos5250-snow-common.dtsi"
+
+/ {
+ model = "Google Snow Rev 5+";
+ compatible = "google,snow-rev5", "samsung,exynos5250",
+ "samsung,exynos5";
+
+ sound {
+ compatible = "google,snow-audio-max98090";
+
+ samsung,model = "Snow-I2S-MAX98090";
+ samsung,audio-codec = <&max98090>;
+ };
+};
+
+&i2c_7 {
+ max98090: codec@10 {
+ compatible = "maxim,max98090";
+ reg = <0x10>;
+ interrupts = <4 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&max98090_irq>;
+ };
+};
+
+&pinctrl_0 {
+ max98090_irq: max98090-irq {
+ samsung,pins = "gpx0-4";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 0720caa..995c7ce 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -9,698 +9,35 @@
*/
/dts-v1/;
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/clock/maxim,max77686.h>
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/input/input.h>
-#include "exynos5250.dtsi"
+#include "exynos5250-snow-common.dtsi"
/ {
model = "Google Snow";
- compatible = "google,snow", "samsung,exynos5250", "samsung,exynos5";
-
- aliases {
- i2c104 = &i2c_104;
- };
-
- memory {
- reg = <0x40000000 0x80000000>;
- };
-
- chosen {
- bootargs = "console=tty1";
- stdout-path = "serial3:115200n8";
- };
-
- gpio-keys {
- compatible = "gpio-keys";
- pinctrl-names = "default";
- pinctrl-0 = <&power_key_irq &lid_irq>;
-
- power {
- label = "Power";
- gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
- linux,code = <KEY_POWER>;
- gpio-key,wakeup;
- };
-
- lid-switch {
- label = "Lid";
- gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
- linux,input-type = <5>; /* EV_SW */
- linux,code = <0>; /* SW_LID */
- debounce-interval = <1>;
- gpio-key,wakeup;
- };
- };
-
- vbat: vbat-fixed-regulator {
- compatible = "regulator-fixed";
- regulator-name = "vbat-supply";
- regulator-boot-on;
- };
-
- i2c-arbitrator {
- compatible = "i2c-arb-gpio-challenge";
- #address-cells = <1>;
- #size-cells = <0>;
-
- i2c-parent = <&{/i2c@12CA0000}>;
-
- our-claim-gpio = <&gpf0 3 GPIO_ACTIVE_LOW>;
- their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>;
- slew-delay-us = <10>;
- wait-retry-us = <3000>;
- wait-free-us = <50000>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&arb_our_claim &arb_their_claim>;
-
- /* Use ID 104 as a hint that we're on physical bus 4 */
- i2c_104: i2c@0 {
- reg = <0>;
- #address-cells = <1>;
- #size-cells = <0>;
-
- battery: sbs-battery@b {
- compatible = "sbs,sbs-battery";
- reg = <0xb>;
- sbs,poll-retry-count = <1>;
- };
-
- cros_ec: embedded-controller {
- compatible = "google,cros-ec-i2c";
- reg = <0x1e>;
- interrupts = <6 IRQ_TYPE_NONE>;
- interrupt-parent = <&gpx1>;
- pinctrl-names = "default";
- pinctrl-0 = <&ec_irq>;
- wakeup-source;
- };
-
- power-regulator {
- compatible = "ti,tps65090";
- reg = <0x48>;
-
- /*
- * Config irq to disable internal pulls
- * even though we run in polling mode.
- */
- pinctrl-names = "default";
- pinctrl-0 = <&tps65090_irq>;
-
- vsys1-supply = <&vbat>;
- vsys2-supply = <&vbat>;
- vsys3-supply = <&vbat>;
- infet1-supply = <&vbat>;
- infet2-supply = <&vbat>;
- infet3-supply = <&vbat>;
- infet4-supply = <&vbat>;
- infet5-supply = <&vbat>;
- infet6-supply = <&vbat>;
- infet7-supply = <&vbat>;
- vsys-l1-supply = <&vbat>;
- vsys-l2-supply = <&vbat>;
-
- regulators {
- dcdc1 {
- ti,enable-ext-control;
- };
- dcdc2 {
- ti,enable-ext-control;
- };
- dcdc3 {
- ti,enable-ext-control;
- };
- fet1: fet1 {
- regulator-name = "vcd_led";
- ti,overcurrent-wait = <3>;
- };
- tps65090_fet2: fet2 {
- regulator-name = "video_mid";
- regulator-always-on;
- ti,overcurrent-wait = <3>;
- };
- fet3 {
- regulator-name = "wwan_r";
- regulator-always-on;
- ti,overcurrent-wait = <3>;
- };
- fet4 {
- regulator-name = "sdcard";
- ti,overcurrent-wait = <3>;
- };
- fet5 {
- regulator-name = "camout";
- regulator-always-on;
- ti,overcurrent-wait = <3>;
- };
- fet6: fet6 {
- regulator-name = "lcd_vdd";
- ti,overcurrent-wait = <3>;
- };
- tps65090_fet7: fet7 {
- regulator-name = "video_mid_1a";
- regulator-always-on;
- ti,overcurrent-wait = <3>;
- };
- ldo1 {
- };
- ldo2 {
- };
- };
-
- charger {
- compatible = "ti,tps65090-charger";
- };
- };
- };
- };
+ compatible = "google,snow-rev4", "google,snow", "samsung,exynos5250",
+ "samsung,exynos5";
sound {
compatible = "google,snow-audio-max98095";
samsung,model = "Snow-I2S-MAX98095";
- samsung,i2s-controller = <&i2s0>;
samsung,audio-codec = <&max98095>;
};
-
- usb3_vbus_reg: regulator-usb3 {
- compatible = "regulator-fixed";
- regulator-name = "P5.0V_USB3CON";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&usb3_vbus_en>;
- enable-active-high;
- };
-
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <24000000>;
- };
- };
-
- backlight: backlight {
- compatible = "pwm-backlight";
- pwms = <&pwm 0 1000000 0>;
- brightness-levels = <0 100 500 1000 1500 2000 2500 2800>;
- default-brightness-level = <7>;
- enable-gpios = <&gpx3 0 GPIO_ACTIVE_HIGH>;
- power-supply = <&fet1>;
- pinctrl-0 = <&pwm0_out>;
- pinctrl-names = "default";
- };
-
- panel: panel {
- compatible = "auo,b116xw03";
- power-supply = <&fet6>;
- backlight = <&backlight>;
-
- port {
- panel_in: endpoint {
- remote-endpoint = <&bridge_out>;
- };
- };
- };
-
- mmc3_pwrseq: mmc3_pwrseq {
- compatible = "mmc-pwrseq-simple";
- reset-gpios = <&gpx0 2 GPIO_ACTIVE_LOW>, /* WIFI_RSTn */
- <&gpx0 1 GPIO_ACTIVE_LOW>; /* WIFI_EN */
- clocks = <&max77686 MAX77686_CLK_PMIC>;
- clock-names = "ext_clock";
- };
-};
-
-&cpu0 {
- cpu0-supply = <&buck2_reg>;
-};
-
-&dp {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dp_hpd>;
- samsung,color-space = <0>;
- samsung,dynamic-range = <0>;
- samsung,ycbcr-coeff = <0>;
- samsung,color-depth = <1>;
- samsung,link-rate = <0x0a>;
- samsung,lane-count = <2>;
- samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
-
- ports {
- port@0 {
- dp_out: endpoint {
- remote-endpoint = <&bridge_in>;
- };
- };
- };
-};
-
-&ehci {
- samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
-};
-
-&fimd {
- status = "okay";
- samsung,invert-vclk;
-};
-
-&hdmi {
- hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_hpd_irq>;
- phy = <&hdmiphy>;
- ddc = <&i2c_2>;
- hdmi-en-supply = <&tps65090_fet7>;
- vdd-supply = <&ldo8_reg>;
- vdd_osc-supply = <&ldo10_reg>;
- vdd_pll-supply = <&ldo8_reg>;
-};
-
-&i2c_0 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <378000>;
-
- max77686: max77686@09 {
- compatible = "maxim,max77686";
- interrupt-parent = <&gpx3>;
- interrupts = <2 IRQ_TYPE_NONE>;
- pinctrl-names = "default";
- pinctrl-0 = <&max77686_irq>;
- wakeup-source;
- reg = <0x09>;
- #clock-cells = <1>;
-
- voltage-regulators {
- ldo1_reg: LDO1 {
- regulator-name = "P1.0V_LDO_OUT1";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "P1.8V_LDO_OUT2";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "P1.8V_LDO_OUT3";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "P1.1V_LDO_OUT7";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "P1.0V_LDO_OUT8";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "P1.8V_LDO_OUT10";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "P3.0V_LDO_OUT12";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- };
-
- ldo14_reg: LDO14 {
- regulator-name = "P1.8V_LDO_OUT14";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "P1.0V_LDO_OUT15";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "P1.8V_LDO_OUT16";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "P1.8V_BUCK_OUT5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck6_reg: BUCK6 {
- regulator-name = "P1.35V_BUCK_OUT6";
- regulator-min-microvolt = <1350000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "P2.0V_BUCK_OUT7";
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- regulator-always-on;
- };
-
- buck8_reg: BUCK8 {
- regulator-name = "P2.85V_BUCK_OUT8";
- regulator-min-microvolt = <2850000>;
- regulator-max-microvolt = <2850000>;
- regulator-always-on;
- };
- };
- };
-};
-
-&i2c_1 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <378000>;
-
- trackpad {
- reg = <0x67>;
- compatible = "cypress,cyapa";
- interrupts = <2 IRQ_TYPE_NONE>;
- interrupt-parent = <&gpx1>;
- wakeup-source;
- };
-};
-
-/*
- * Disabled pullups since external part has its own pullups and
- * double-pulling gets us out of spec in some cases.
- */
-&i2c2_bus {
- samsung,pin-pud = <0>;
-};
-
-&i2c_2 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
-
- hdmiddc@50 {
- compatible = "samsung,exynos4210-hdmiddc";
- reg = <0x50>;
- };
-};
-
-&i2c_3 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
-};
-
-&i2c_4 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
-};
-
-&i2c_5 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
};
&i2c_7 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
-
- ptn3460: lvds-bridge@20 {
- compatible = "nxp,ptn3460";
- reg = <0x20>;
- powerdown-gpios = <&gpy2 5 GPIO_ACTIVE_HIGH>;
- reset-gpios = <&gpx1 5 GPIO_ACTIVE_HIGH>;
- edid-emulation = <5>;
-
- ports {
- port@0 {
- bridge_out: endpoint {
- remote-endpoint = <&panel_in>;
- };
- };
-
- port@1 {
- bridge_in: endpoint {
- remote-endpoint = <&dp_out>;
- };
- };
- };
- };
-
max98095: codec@11 {
compatible = "maxim,max98095";
reg = <0x11>;
- pinctrl-0 = <&max98095_en>;
pinctrl-names = "default";
+ pinctrl-0 = <&max98095_en>;
};
};
-&i2c_8 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <378000>;
-
- hdmiphy: hdmiphy@38 {
- compatible = "samsung,exynos4212-hdmiphy";
- reg = <0x38>;
- };
-};
-
-&i2s0 {
- status = "okay";
-};
-
-&mmc_0 {
- status = "okay";
- num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
- bus-width = <8>;
- cap-mmc-highspeed;
-};
-
-&mmc_2 {
- status = "okay";
- num-slots = <1>;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- bus-width = <4>;
- wp-gpios = <&gpc2 1 GPIO_ACTIVE_HIGH>;
- cap-sd-highspeed;
-};
-
-/*
- * On Snow we've got SIP WiFi and so can keep drive strengths low to
- * reduce EMI.
- */
-&mmc_3 {
- status = "okay";
- num-slots = <1>;
- broken-cd;
- cap-sdio-irq;
- keep-power-in-suspend;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd3_clk &sd3_cmd &sd3_bus4 &wifi_en &wifi_rst>;
- bus-width = <4>;
- cap-sd-highspeed;
- mmc-pwrseq = <&mmc3_pwrseq>;
-};
-
&pinctrl_0 {
- wifi_en: wifi-en {
- samsung,pins = "gpx0-1";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- wifi_rst: wifi-rst {
- samsung,pins = "gpx0-2";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- power_key_irq: power-key-irq {
- samsung,pins = "gpx1-3";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- ec_irq: ec-irq {
- samsung,pins = "gpx1-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
max98095_en: max98095-en {
samsung,pins = "gpx1-7";
samsung,pin-function = <0>;
samsung,pin-pud = <3>;
samsung,pin-drv = <0>;
};
-
- tps65090_irq: tps65090-irq {
- samsung,pins = "gpx2-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- usb3_vbus_en: usb3-vbus-en {
- samsung,pins = "gpx2-7";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- max77686_irq: max77686-irq {
- samsung,pins = "gpx3-2";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- lid_irq: lid-irq {
- samsung,pins = "gpx3-5";
- samsung,pin-function = <0xf>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- hdmi_hpd_irq: hdmi-hpd-irq {
- samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
- };
-};
-
-&pinctrl_1 {
- arb_their_claim: arb-their-claim {
- samsung,pins = "gpe0-4";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
- };
-
- arb_our_claim: arb-our-claim {
- samsung,pins = "gpf0-3";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
};
-
-&rtc {
- status = "okay";
- clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
- clock-names = "rtc", "rtc_src";
-};
-
-&sd3_bus4 {
- samsung,pin-drv = <0>;
-};
-
-&sd3_clk {
- samsung,pin-drv = <0>;
-};
-
-&sd3_cmd {
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
-};
-
-&spi_1 {
- status = "okay";
- samsung,spi-src-clk = <0>;
- num-cs = <1>;
- cs-gpios = <&gpa2 5 GPIO_ACTIVE_HIGH>;
-};
-
-&usbdrd_dwc3 {
- dr_mode = "host";
-};
-
-&usbdrd_phy {
- vbus-supply = <&usb3_vbus_reg>;
-};
-
-#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index b24610e..88b9cf5 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -130,6 +130,10 @@
compatible = "samsung,exynos4210-pd";
reg = <0x100440A0 0x20>;
#power-domain-cells = <0>;
+ clocks = <&clock CLK_FIN_PLL>,
+ <&clock CLK_MOUT_ACLK200_DISP1_SUB>,
+ <&clock CLK_MOUT_ACLK300_DISP1_SUB>;
+ clock-names = "oscclk", "clk0", "clk1";
};
clock: clock-controller@10010000 {
diff --git a/arch/arm/boot/dts/exynos5420-arndale-octa.dts b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
index eeb4ac2..4ecef69 100644
--- a/arch/arm/boot/dts/exynos5420-arndale-octa.dts
+++ b/arch/arm/boot/dts/exynos5420-arndale-octa.dts
@@ -11,6 +11,7 @@
/dts-v1/;
#include "exynos5420.dtsi"
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/clock/samsung,s2mps11.h>
@@ -44,7 +45,7 @@
wakeup {
label = "SW-TACT1";
- gpios = <&gpx2 7 1>;
+ gpios = <&gpx2 7 GPIO_ACTIVE_LOW>;
linux,code = <KEY_WAKEUP>;
gpio-key,wakeup;
};
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 1b95da7..72ba6f0 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -94,7 +94,7 @@
regulator-name = "P5.0V_USB3CON0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gph0 0 0>;
+ gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb300_vbus_en>;
enable-active-high;
@@ -105,7 +105,7 @@
regulator-name = "P5.0V_USB3CON1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gph0 1 0>;
+ gpio = <&gph0 1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb301_vbus_en>;
enable-active-high;
@@ -153,7 +153,7 @@
samsung,color-depth = <1>;
samsung,link-rate = <0x06>;
samsung,lane-count = <2>;
- samsung,hpd-gpio = <&gpx2 6 0>;
+ samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
ports {
port@0 {
@@ -930,7 +930,7 @@
status = "okay";
num-cs = <1>;
samsung,spi-src-clk = <0>;
- cs-gpios = <&gpb1 2 0>;
+ cs-gpios = <&gpb1 2 GPIO_ACTIVE_HIGH>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
@@ -940,6 +940,7 @@
pinctrl-0 = <&ec_spi_cs &ec_irq>;
reg = <0>;
spi-max-frequency = <3125000>;
+ google,has-vbc-nvram;
controller-data {
samsung,spi-feedback-delay = <1>;
diff --git a/arch/arm/boot/dts/exynos5420-smdk5420.dts b/arch/arm/boot/dts/exynos5420-smdk5420.dts
index 98871f9..ac35aef 100644
--- a/arch/arm/boot/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/boot/dts/exynos5420-smdk5420.dts
@@ -11,6 +11,7 @@
/dts-v1/;
#include "exynos5420.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Samsung SMDK5420 board based on EXYNOS5420";
@@ -69,7 +70,7 @@
regulator-name = "VBUS0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gpg0 5 0>;
+ gpio = <&gpg0 5 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb300_vbus_en>;
enable-active-high;
@@ -80,7 +81,7 @@
regulator-name = "VBUS1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gpg1 4 0>;
+ gpio = <&gpg1 4 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb301_vbus_en>;
enable-active-high;
@@ -98,10 +99,7 @@
samsung,link-rate = <0x0a>;
samsung,lane-count = <4>;
status = "okay";
-};
-&fimd {
- status = "okay";
display-timings {
native-mode = <&timing0>;
timing0: timing@0 {
@@ -118,9 +116,13 @@
};
};
+&fimd {
+ status = "okay";
+};
+
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 0>;
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi
new file mode 100644
index 0000000..9493923
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi
@@ -0,0 +1,61 @@
+/*
+ * Hardkernel Odroid XU3 Audio Codec device tree source
+ *
+ * Copyright (c) 2015 Krzysztof Kozlowski
+ * Copyright (c) 2014 Collabora Ltd.
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/ {
+ sound: sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,name = "Odroid-XU3";
+ simple-audio-card,widgets =
+ "Headphone", "Headphone Jack",
+ "Speakers", "Speakers";
+ simple-audio-card,routing =
+ "Headphone Jack", "HPL",
+ "Headphone Jack", "HPR",
+ "Headphone Jack", "MICBIAS",
+ "IN1", "Headphone Jack",
+ "Speakers", "SPKL",
+ "Speakers", "SPKR";
+
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&link0_codec>;
+ simple-audio-card,frame-master = <&link0_codec>;
+
+ simple-audio-card,cpu {
+ sound-dai = <&i2s0 0>;
+ system-clock-frequency = <19200000>;
+ };
+
+ link0_codec: simple-audio-card,codec {
+ sound-dai = <&max98090>;
+ clocks = <&i2s0 CLK_I2S_CDCLK>;
+ };
+ };
+};
+
+&hsi2c_5 {
+ status = "okay";
+ max98090: max98090@10 {
+ compatible = "maxim,max98090";
+ reg = <0x10>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 0>;
+ clocks = <&i2s0 CLK_I2S_CDCLK>;
+ clock-names = "mclk";
+ #sound-dai-cells = <0>;
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
index 3b43e57..1af5bdc 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-common.dtsi
@@ -43,71 +43,7 @@
pinctrl-0 = <&emmc_nrst_pin>;
pinctrl-names = "default";
compatible = "mmc-pwrseq-emmc";
- reset-gpios = <&gpd1 0 1>;
- };
-
- pwmleds {
- compatible = "pwm-leds";
-
- greenled {
- label = "green:mmc0";
- pwms = <&pwm 1 2000000 0>;
- pwm-names = "pwm1";
- /*
- * Green LED is much brighter than the others
- * so limit its max brightness
- */
- max_brightness = <127>;
- linux,default-trigger = "mmc0";
- };
-
- blueled {
- label = "blue:heartbeat";
- pwms = <&pwm 2 2000000 0>;
- pwm-names = "pwm2";
- max_brightness = <255>;
- linux,default-trigger = "heartbeat";
- };
- };
-
- gpioleds {
- compatible = "gpio-leds";
- redled {
- label = "red:microSD";
- gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- linux,default-trigger = "mmc1";
- };
- };
-
- sound: sound {
- compatible = "simple-audio-card";
-
- simple-audio-card,name = "Odroid-XU3";
- simple-audio-card,widgets =
- "Headphone", "Headphone Jack",
- "Speakers", "Speakers";
- simple-audio-card,routing =
- "Headphone Jack", "HPL",
- "Headphone Jack", "HPR",
- "Headphone Jack", "MICBIAS",
- "IN1", "Headphone Jack",
- "Speakers", "SPKL",
- "Speakers", "SPKR";
-
- simple-audio-card,format = "i2s";
- simple-audio-card,bitclock-master = <&link0_codec>;
- simple-audio-card,frame-master = <&link0_codec>;
-
- simple-audio-card,cpu {
- sound-dai = <&i2s0 0>;
- system-clock-frequency = <19200000>;
- };
-
- link0_codec: simple-audio-card,codec {
- sound-dai = <&max98090>;
- clocks = <&i2s0 CLK_I2S_CDCLK>;
- };
+ reset-gpios = <&gpd1 0 GPIO_ACTIVE_LOW>;
};
fan0: pwm-fan {
@@ -138,7 +74,7 @@
&hdmi {
status = "okay";
- hpd-gpio = <&gpx3 7 0>;
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_hpd_irq>;
@@ -160,6 +96,7 @@
s2mps11,buck2-ramp-enable = <1>;
s2mps11,buck3-ramp-enable = <1>;
s2mps11,buck4-ramp-enable = <1>;
+ samsung,s2mps11-acokb-ground;
interrupt-parent = <&gpx0>;
interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
@@ -375,19 +312,6 @@
};
};
-&hsi2c_5 {
- status = "okay";
- max98090: max98090@10 {
- compatible = "maxim,max98090";
- reg = <0x10>;
- interrupt-parent = <&gpx3>;
- interrupts = <2 0>;
- clocks = <&i2s0 CLK_I2S_CDCLK>;
- clock-names = "mclk";
- #sound-dai-cells = <0>;
- };
-};
-
&i2c_2 {
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
@@ -399,10 +323,6 @@
};
};
-&i2s0 {
- status = "okay";
-};
-
&mfc {
samsung,mfc-r = <0x43000000 0x800000>;
samsung,mfc-l = <0x51000000 0x800000>;
@@ -463,18 +383,6 @@
};
};
-&pwm {
- /*
- * PWM 0 -- fan
- * PWM 1 -- Green LED
- * PWM 2 -- Blue LED
- * PWM 3 -- on MIPI connector for backlight
- */
- pinctrl-0 = <&pwm0_out &pwm1_out &pwm2_out &pwm3_out>;
- pinctrl-names = "default";
- status = "okay";
-};
-
&tmu_cpu0 {
vtmu-supply = <&ldo7_reg>;
status = "okay";
@@ -510,9 +418,7 @@
dr_mode = "host";
};
-&usbdrd_dwc3_1 {
- dr_mode = "otg";
-};
+/* usbdrd_dwc3_1 mode customized in each board */
&usbdrd3_0 {
vdd33-supply = <&ldo9_reg>;
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
index c06882b..b1b3608 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3-lite.dts
@@ -13,8 +13,59 @@
/dts-v1/;
#include "exynos5422-odroidxu3-common.dtsi"
+#include "exynos5422-odroidxu3-audio.dtsi"
/ {
model = "Hardkernel Odroid XU3 Lite";
compatible = "hardkernel,odroid-xu3-lite", "samsung,exynos5800", "samsung,exynos5";
+
+ pwmleds {
+ compatible = "pwm-leds";
+
+ greenled {
+ label = "green:mmc0";
+ pwms = <&pwm 1 2000000 0>;
+ pwm-names = "pwm1";
+ /*
+ * Green LED is much brighter than the others
+ * so limit its max brightness
+ */
+ max_brightness = <127>;
+ linux,default-trigger = "mmc0";
+ };
+
+ blueled {
+ label = "blue:heartbeat";
+ pwms = <&pwm 2 2000000 0>;
+ pwm-names = "pwm2";
+ max_brightness = <255>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpioleds {
+ compatible = "gpio-leds";
+ redled {
+ label = "red:microSD";
+ gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ linux,default-trigger = "mmc1";
+ };
+ };
+};
+
+&pwm {
+ /*
+ * PWM 0 -- fan
+ * PWM 1 -- Green LED
+ * PWM 2 -- Blue LED
+ * PWM 3 -- on MIPI connector for backlight
+ */
+ pinctrl-0 = <&pwm0_out &pwm1_out &pwm2_out &pwm3_out>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "otg";
};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3.dts b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
index 78e6a50..0c0bbdb 100644
--- a/arch/arm/boot/dts/exynos5422-odroidxu3.dts
+++ b/arch/arm/boot/dts/exynos5422-odroidxu3.dts
@@ -12,10 +12,45 @@
/dts-v1/;
#include "exynos5422-odroidxu3-common.dtsi"
+#include "exynos5422-odroidxu3-audio.dtsi"
/ {
model = "Hardkernel Odroid XU3";
compatible = "hardkernel,odroid-xu3", "samsung,exynos5800", "samsung,exynos5";
+
+ pwmleds {
+ compatible = "pwm-leds";
+
+ greenled {
+ label = "green:mmc0";
+ pwms = <&pwm 1 2000000 0>;
+ pwm-names = "pwm1";
+ /*
+ * Green LED is much brighter than the others
+ * so limit its max brightness
+ */
+ max_brightness = <127>;
+ linux,default-trigger = "mmc0";
+ };
+
+ blueled {
+ label = "blue:heartbeat";
+ pwms = <&pwm 2 2000000 0>;
+ pwm-names = "pwm2";
+ max_brightness = <255>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+
+ gpioleds {
+ compatible = "gpio-leds";
+ redled {
+ label = "red:microSD";
+ gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ linux,default-trigger = "mmc1";
+ };
+ };
};
&i2c_0 {
@@ -49,3 +84,19 @@
shunt-resistor = <10000>;
};
};
+
+&pwm {
+ /*
+ * PWM 0 -- fan
+ * PWM 1 -- Green LED
+ * PWM 2 -- Blue LED
+ * PWM 3 -- on MIPI connector for backlight
+ */
+ pinctrl-0 = <&pwm0_out &pwm1_out &pwm2_out &pwm3_out>;
+ pinctrl-names = "default";
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "otg";
+};
diff --git a/arch/arm/boot/dts/exynos5422-odroidxu4.dts b/arch/arm/boot/dts/exynos5422-odroidxu4.dts
new file mode 100644
index 0000000..2faf886
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5422-odroidxu4.dts
@@ -0,0 +1,48 @@
+/*
+ * Hardkernel Odroid XU4 board device tree source
+ *
+ * Copyright (c) 2015 Krzysztof Kozlowski
+ * Copyright (c) 2014 Collabora Ltd.
+ * Copyright (c) 2013-2015 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+/dts-v1/;
+#include "exynos5422-odroidxu3-common.dtsi"
+
+/ {
+ model = "Hardkernel Odroid XU4";
+ compatible = "hardkernel,odroid-xu4", "samsung,exynos5800", \
+ "samsung,exynos5";
+
+ pwmleds {
+ compatible = "pwm-leds";
+
+ blueled {
+ label = "blue:heartbeat";
+ pwms = <&pwm 2 2000000 0>;
+ pwm-names = "pwm2";
+ max_brightness = <255>;
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
+
+&pwm {
+ /*
+ * PWM 0 -- fan
+ * PWM 2 -- Blue LED
+ */
+ pinctrl-0 = <&pwm0_out &pwm2_out>;
+ pinctrl-names = "default";
+ samsung,pwm-outputs = <0>, <2>;
+ status = "okay";
+};
+
+&usbdrd_dwc3_1 {
+ dr_mode = "host";
+};
diff --git a/arch/arm/boot/dts/exynos5440-ssdk5440.dts b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
index e4443f4..6a0d802 100644
--- a/arch/arm/boot/dts/exynos5440-ssdk5440.dts
+++ b/arch/arm/boot/dts/exynos5440-ssdk5440.dts
@@ -11,6 +11,7 @@
/dts-v1/;
#include "exynos5440.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "SAMSUNG SSDK5440 board based on EXYNOS5440";
@@ -29,12 +30,12 @@
};
&pcie_0 {
- reset-gpio = <&pin_ctrl 5 0>;
+ reset-gpio = <&pin_ctrl 5 GPIO_ACTIVE_HIGH>;
status = "okay";
};
&pcie_1 {
- reset-gpio = <&pin_ctrl 22 0>;
+ reset-gpio = <&pin_ctrl 22 GPIO_ACTIVE_HIGH>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 8f40c7e..49a4f43 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -94,7 +94,7 @@
regulator-name = "P5.0V_USB3CON0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gph0 0 0>;
+ gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb300_vbus_en>;
enable-active-high;
@@ -105,7 +105,7 @@
regulator-name = "P5.0V_USB3CON1";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gph0 1 0>;
+ gpio = <&gph0 1 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb301_vbus_en>;
enable-active-high;
@@ -147,7 +147,7 @@
samsung,color-depth = <1>;
samsung,link-rate = <0x0a>;
samsung,lane-count = <2>;
- samsung,hpd-gpio = <&gpx2 6 0>;
+ samsung,hpd-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
panel = <&panel>;
};
@@ -893,7 +893,7 @@
status = "okay";
num-cs = <1>;
samsung,spi-src-clk = <0>;
- cs-gpios = <&gpb1 2 0>;
+ cs-gpios = <&gpb1 2 GPIO_ACTIVE_HIGH>;
cros_ec: cros-ec@0 {
compatible = "google,cros-ec-spi";
@@ -903,6 +903,7 @@
pinctrl-0 = <&ec_spi_cs &ec_irq>;
reg = <0>;
spi-max-frequency = <3125000>;
+ google,has-vbc-nvram;
controller-data {
samsung,spi-feedback-delay = <1>;
diff --git a/arch/arm/boot/dts/hi3620-hi4511.dts b/arch/arm/boot/dts/hi3620-hi4511.dts
index fe62392..a579fbf 100644
--- a/arch/arm/boot/dts/hi3620-hi4511.dts
+++ b/arch/arm/boot/dts/hi3620-hi4511.dts
@@ -16,7 +16,8 @@
compatible = "hisilicon,hi3620-hi4511";
chosen {
- bootargs = "console=ttyAMA0,115200 root=/dev/ram0 earlyprintk";
+ bootargs = "root=/dev/ram0";
+ stdout-path = "serial0:115200n8";
};
memory {
diff --git a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
index 721b092..d13af84 100644
--- a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
+++ b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
@@ -15,7 +15,7 @@
compatible = "hisilicon,hix5hd2";
chosen {
- bootargs = "console=ttyAMA0,115200 earlyprintk";
+ stdout-path = "serial0:115200n8";
};
cpus {
diff --git a/arch/arm/boot/dts/imx23.dtsi b/arch/arm/boot/dts/imx23.dtsi
index b995333..1c6c075 100644
--- a/arch/arm/boot/dts/imx23.dtsi
+++ b/arch/arm/boot/dts/imx23.dtsi
@@ -383,9 +383,11 @@
};
ocotp@8002c000 {
- compatible = "fsl,ocotp";
+ compatible = "fsl,imx23-ocotp", "fsl,ocotp";
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0x8002c000 0x2000>;
- status = "disabled";
+ clocks = <&clks 15>;
};
axi-ahb@8002e000 {
diff --git a/arch/arm/boot/dts/imx27.dtsi b/arch/arm/boot/dts/imx27.dtsi
index feb9d34..f818ea4 100644
--- a/arch/arm/boot/dts/imx27.dtsi
+++ b/arch/arm/boot/dts/imx27.dtsi
@@ -486,7 +486,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024000 0x200>;
interrupts = <56>;
- clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+ clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+ <&clks IMX27_CLK_USB_AHB_GATE>,
+ <&clks IMX27_CLK_USB_DIV>;
+ clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 0>;
status = "disabled";
};
@@ -495,7 +498,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024200 0x200>;
interrupts = <54>;
- clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+ clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+ <&clks IMX27_CLK_USB_AHB_GATE>,
+ <&clks IMX27_CLK_USB_DIV>;
+ clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 1>;
dr_mode = "host";
status = "disabled";
@@ -505,7 +511,10 @@
compatible = "fsl,imx27-usb";
reg = <0x10024400 0x200>;
interrupts = <55>;
- clocks = <&clks IMX27_CLK_USB_IPG_GATE>;
+ clocks = <&clks IMX27_CLK_USB_IPG_GATE>,
+ <&clks IMX27_CLK_USB_AHB_GATE>,
+ <&clks IMX27_CLK_USB_DIV>;
+ clock-names = "ipg", "ahb", "per";
fsl,usbmisc = <&usbmisc 2>;
dr_mode = "host";
status = "disabled";
@@ -515,7 +524,6 @@
#index-cells = <1>;
compatible = "fsl,imx27-usbmisc";
reg = <0x10024600 0x200>;
- clocks = <&clks IMX27_CLK_USB_AHB_GATE>;
};
sahara2: sahara@10025000 {
diff --git a/arch/arm/boot/dts/imx28-evk.dts b/arch/arm/boot/dts/imx28-evk.dts
index 279249b..e3ef94a 100644
--- a/arch/arm/boot/dts/imx28-evk.dts
+++ b/arch/arm/boot/dts/imx28-evk.dts
@@ -57,7 +57,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "sst,sst25vf016b";
+ compatible = "sst,sst25vf016b", "jedec,spi-nor";
spi-max-frequency = <40000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx28-m28evk.dts b/arch/arm/boot/dts/imx28-m28evk.dts
index e35cc6b..8d04e57 100644
--- a/arch/arm/boot/dts/imx28-m28evk.dts
+++ b/arch/arm/boot/dts/imx28-m28evk.dts
@@ -41,7 +41,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "m25p80";
+ compatible = "m25p80", "jedec,spi-nor";
spi-max-frequency = <40000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi
index 4e073e8..c5b57d4 100644
--- a/arch/arm/boot/dts/imx28.dtsi
+++ b/arch/arm/boot/dts/imx28.dtsi
@@ -936,9 +936,11 @@
};
ocotp: ocotp@8002c000 {
- compatible = "fsl,ocotp";
+ compatible = "fsl,imx28-ocotp", "fsl,ocotp";
+ #address-cells = <1>;
+ #size-cells = <1>;
reg = <0x8002c000 0x2000>;
- status = "disabled";
+ clocks = <&clks 25>;
};
axi-ahb@8002e000 {
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
index c34f825..5fdb222 100644
--- a/arch/arm/boot/dts/imx31.dtsi
+++ b/arch/arm/boot/dts/imx31.dtsi
@@ -25,7 +25,7 @@
#size-cells = <0>;
cpu {
- compatible = "arm,arm1136";
+ compatible = "arm,arm1136jf-s";
device_type = "cpu";
};
};
diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi
index e6540b5..ed3dc33 100644
--- a/arch/arm/boot/dts/imx35.dtsi
+++ b/arch/arm/boot/dts/imx35.dtsi
@@ -29,7 +29,7 @@
#size-cells = <0>;
cpu {
- compatible = "arm,arm1136";
+ compatible = "arm,arm1136jf-s";
device_type = "cpu";
};
};
diff --git a/arch/arm/boot/dts/imx50-evk.dts b/arch/arm/boot/dts/imx50-evk.dts
index 1b22512..27d763c 100644
--- a/arch/arm/boot/dts/imx50-evk.dts
+++ b/arch/arm/boot/dts/imx50-evk.dts
@@ -33,7 +33,7 @@
flash: m25p32@1 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "m25p32", "m25p80";
+ compatible = "m25p32", "jedec,spi-nor";
spi-max-frequency = <25000000>;
reg = <1>;
diff --git a/arch/arm/boot/dts/imx53-smd.dts b/arch/arm/boot/dts/imx53-smd.dts
index fc89ce1..542ab9e 100644
--- a/arch/arm/boot/dts/imx53-smd.dts
+++ b/arch/arm/boot/dts/imx53-smd.dts
@@ -76,7 +76,7 @@
flash: m25p32@1 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p32", "st,m25p";
+ compatible = "st,m25p32", "st,m25p", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <1>;
diff --git a/arch/arm/boot/dts/imx6dl-nit6xlite.dts b/arch/arm/boot/dts/imx6dl-nit6xlite.dts
new file mode 100644
index 0000000..e0161e4
--- /dev/null
+++ b/arch/arm/boot/dts/imx6dl-nit6xlite.dts
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Boundary Devices, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-nit6xlite.dtsi"
+
+/ {
+ model = "Boundary Devices i.MX6 Solo Nitrogen6_Lite Board";
+ compatible = "boundary,imx6dl-nit6xlite", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl-nitrogen6x.dts b/arch/arm/boot/dts/imx6dl-nitrogen6x.dts
index 5f4d33c..8398f97 100644
--- a/arch/arm/boot/dts/imx6dl-nitrogen6x.dts
+++ b/arch/arm/boot/dts/imx6dl-nitrogen6x.dts
@@ -3,12 +3,42 @@
* Copyright 2012 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
@@ -16,6 +46,6 @@
#include "imx6qdl-nitrogen6x.dtsi"
/ {
- model = "Freescale i.MX6 DualLite Nitrogen6x Board";
- compatible = "fsl,imx6dl-nitrogen6x", "fsl,imx6dl";
+ model = "Boundary Devices i.MX6 DualLite Nitrogen6x Board";
+ compatible = "boundary,imx6dl-nitrogen6x", "fsl,imx6dl";
};
diff --git a/arch/arm/boot/dts/imx6dl-rex-basic.dts b/arch/arm/boot/dts/imx6dl-rex-basic.dts
index b13845c..c3a14a4 100644
--- a/arch/arm/boot/dts/imx6dl-rex-basic.dts
+++ b/arch/arm/boot/dts/imx6dl-rex-basic.dts
@@ -23,7 +23,7 @@
&ecspi3 {
flash: m25p80@0 {
- compatible = "sst,sst25vf016b";
+ compatible = "sst,sst25vf016b", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6dl-sabrelite.dts b/arch/arm/boot/dts/imx6dl-sabrelite.dts
index 2de0447..0f06ca5 100644
--- a/arch/arm/boot/dts/imx6dl-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6dl-sabrelite.dts
@@ -2,12 +2,42 @@
* Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
index 4fa2543..364578d 100644
--- a/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
+++ b/arch/arm/boot/dts/imx6q-dmo-edmqmx6.dts
@@ -109,7 +109,7 @@
status = "okay";
flash: m25p80@0 {
- compatible = "m25p80";
+ compatible = "m25p80", "jedec,spi-nor";
spi-max-frequency = <40000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6q-gw5400-a.dts b/arch/arm/boot/dts/imx6q-gw5400-a.dts
index 822ffb2..a51834e 100644
--- a/arch/arm/boot/dts/imx6q-gw5400-a.dts
+++ b/arch/arm/boot/dts/imx6q-gw5400-a.dts
@@ -145,7 +145,7 @@
status = "okay";
flash: m25p80@0 {
- compatible = "sst,w25q256";
+ compatible = "sst,w25q256", "jedec,spi-nor";
spi-max-frequency = <30000000>;
reg = <0>;
};
@@ -154,7 +154,7 @@
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_HIGH>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6q-nitrogen6_max.dts b/arch/arm/boot/dts/imx6q-nitrogen6_max.dts
new file mode 100644
index 0000000..d417457
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-nitrogen6_max.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2015 Boundary Devices, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-nitrogen6_max.dtsi"
+
+/ {
+ model = "Boundary Devices i.MX6 Quad Nitrogen6_MAX Board";
+ compatible = "boundary,imx6q-nitrogen6_max", "fsl,imx6q";
+};
+
+&sata {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-nitrogen6x.dts b/arch/arm/boot/dts/imx6q-nitrogen6x.dts
index a57866b..d168633 100644
--- a/arch/arm/boot/dts/imx6q-nitrogen6x.dts
+++ b/arch/arm/boot/dts/imx6q-nitrogen6x.dts
@@ -3,12 +3,42 @@
* Copyright 2012 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
@@ -16,8 +46,8 @@
#include "imx6qdl-nitrogen6x.dtsi"
/ {
- model = "Freescale i.MX6 Quad Nitrogen6x Board";
- compatible = "fsl,imx6q-nitrogen6x", "fsl,imx6q";
+ model = "Boundary Devices i.MX6 Quad Nitrogen6x Board";
+ compatible = "boundary,imx6q-nitrogen6x", "fsl,imx6q";
};
&sata {
diff --git a/arch/arm/boot/dts/imx6q-rex-pro.dts b/arch/arm/boot/dts/imx6q-rex-pro.dts
index 3c2852b..90ea61a 100644
--- a/arch/arm/boot/dts/imx6q-rex-pro.dts
+++ b/arch/arm/boot/dts/imx6q-rex-pro.dts
@@ -23,7 +23,7 @@
&ecspi3 {
flash: m25p80@0 {
- compatible = "sst,sst25vf032b";
+ compatible = "sst,sst25vf032b", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6q-sabrelite.dts b/arch/arm/boot/dts/imx6q-sabrelite.dts
index 96e4688..66d10d8 100644
--- a/arch/arm/boot/dts/imx6q-sabrelite.dts
+++ b/arch/arm/boot/dts/imx6q-sabrelite.dts
@@ -2,12 +2,42 @@
* Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi b/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi
index f4d6ae5..ecbc6eb 100644
--- a/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-aristainetos.dtsi
@@ -109,7 +109,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q128a11";
+ compatible = "micron,n25q128a11", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
index a47a039..7d81100 100644
--- a/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-aristainetos2.dtsi
@@ -141,7 +141,7 @@
flash: m25p80@1 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q128a11";
+ compatible = "micron,n25q128a11", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <1>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
index 45e7c39..da1341d 100644
--- a/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-dfi-fs700-m60.dtsi
@@ -38,7 +38,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "sst,sst25vf040b", "m25p80";
+ compatible = "sst,sst25vf040b", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
index 7b31fdb..dc0cebf 100644
--- a/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw51xx.dtsi
@@ -94,7 +94,7 @@
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
index 1b66328..18cd411 100644
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -154,7 +154,7 @@
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
index 7c51839..eea90f3 100644
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -155,7 +155,7 @@
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index 929e0b3..6c11a2a 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -145,7 +145,7 @@
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
+ phy-mode = "rgmii-id";
phy-reset-gpios = <&gpio1 30 GPIO_ACTIVE_LOW>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
new file mode 100644
index 0000000..24d7d3f
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-nit6xlite.dtsi
@@ -0,0 +1,630 @@
+/*
+ * Copyright 2015 Boundary Devices, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ memory {
+ reg = <0x10000000 0x20000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_2p5v: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ reg_3p3v: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_usb_otg_vbus: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_wlan_vmmc: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wlan_vmmc>;
+ regulator-name = "reg_wlan_vmmc";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio6 7 GPIO_ACTIVE_HIGH>;
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+ };
+
+ bt_rfkill {
+ compatible = "rfkill-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_bt_rfkill>;
+ gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>;
+ name = "bt_rfkill";
+ type = <2>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ home {
+ label = "Home";
+ gpios = <&gpio7 13 IRQ_TYPE_LEVEL_LOW>;
+ linux,code = <102>;
+ };
+
+ back {
+ label = "Back";
+ gpios = <&gpio4 5 IRQ_TYPE_LEVEL_LOW>;
+ linux,code = <158>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_leds>;
+
+ j14-pin1 {
+ gpios = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+
+ j14-pin3 {
+ gpios = <&gpio1 3 GPIO_ACTIVE_LOW>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+
+ j14-pins8-9 {
+ gpios = <&gpio3 29 GPIO_ACTIVE_LOW>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+
+ j46-pin2 {
+ gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+
+ j46-pin3 {
+ gpios = <&gpio1 8 GPIO_ACTIVE_LOW>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+ };
+
+ backlight_lcd {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ power-supply = <&reg_3p3v>;
+ status = "okay";
+ };
+
+ backlight_lvds0: backlight_lvds0 {
+ compatible = "pwm-backlight";
+ pwms = <&pwm4 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ power-supply = <&reg_3p3v>;
+ status = "okay";
+ };
+
+ panel_lvds0 {
+ compatible = "hannstar,hsd100pxn1";
+ backlight = <&backlight_lvds0>;
+
+ port {
+ panel_in_lvds0: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+
+ sound {
+ compatible = "fsl,imx6dl-nit6xlite-sgtl5000",
+ "fsl,imx-audio-sgtl5000";
+ model = "imx6dl-nit6xlite-sgtl5000";
+ ssi-controller = <&ssi1>;
+ audio-codec = <&codec>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <1>;
+ mux-ext-port = <3>;
+ };
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
+&ecspi1 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ flash: m25p80@0 {
+ compatible = "microchip,sst25vf016b";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
+ txen-skew-ps = <0>;
+ txc-skew-ps = <3000>;
+ rxdv-skew-ps = <0>;
+ rxc-skew-ps = <3000>;
+ rxd0-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd3-skew-ps = <0>;
+ txd0-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd3-skew-ps = <0>;
+ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ codec: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgtl5000>;
+ reg = <0x0a>;
+ clocks = <&clks 201>;
+ VDDA-supply = <&reg_2p5v>;
+ VDDIO-supply = <&reg_3p3v>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ touchscreen@04 {
+ compatible = "eeti,egalax_ts";
+ reg = <0x04>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ };
+
+ touchscreen@38 {
+ compatible = "edt,edt-ft5x06";
+ reg = <0x38>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ };
+
+ rtc@6f {
+ compatible = "isil,isl1208";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rtc>;
+ reg = <0x6f>;
+ interrupts-extended = <&gpio2 26 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&iomuxc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_j10>;
+ pinctrl-1 = <&pinctrl_j28>;
+
+ imx6dl-nit6xlite {
+ pinctrl_audmux: audmuxgrp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
+ >;
+ };
+
+ pinctrl_bt_rfkill: bt_rfkillgrp {
+ fsl,pins = <
+ /* BT wake */
+ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+ /* BT reset */
+ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x0b0b0
+ /* BT reg en */
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x1b0b0
+ /* BT host wake irq */
+ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x100b0
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+ /* Phy reset */
+ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0
+ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0
+ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
+ >;
+ };
+
+ pinctrl_gpio_keys: gpio_keysgrp {
+ fsl,pins = <
+ /* Home Button: J14 pin 5 */
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0
+ /* Back Button: J14 pin 7 */
+ MX6QDL_PAD_GPIO_19__GPIO4_IO05 0x1b0b0
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1
+ /* Touch IRQ: J7 pin 4 */
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
+ /* tcs2004 IRQ */
+ MX6QDL_PAD_EIM_LBA__GPIO2_IO27 0x1b0b0
+ /* tsc2004 reset */
+ MX6QDL_PAD_KEY_COL2__GPIO4_IO10 0x0b0b0
+ >;
+ };
+
+ pinctrl_j10: j10grp {
+ fsl,pins = <
+ /* Broadcom WiFi module pins */
+ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x1b0b0
+ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0
+ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0
+ MX6QDL_PAD_NANDF_WP_B__GPIO6_IO09 0x0b0b0
+ MX6QDL_PAD_NANDF_CS1__GPIO6_IO14 0x1b0b0
+ MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0
+ >;
+ };
+
+ pinctrl_j28: j28grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_4__GPIO1_IO04 0x1b0b0
+ >;
+ };
+
+ pinctrl_leds: ledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x0b0b0
+ MX6QDL_PAD_GPIO_3__GPIO1_IO03 0x0b0b0
+ MX6QDL_PAD_EIM_D29__GPIO3_IO29 0x030b0
+ MX6QDL_PAD_GPIO_7__GPIO1_IO07 0x0b0b0
+ MX6QDL_PAD_GPIO_8__GPIO1_IO08 0x0b0b0
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm4: pwm4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_wlan_vmmc: wlan_vmmcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b0
+ >;
+ };
+
+ pinctrl_rtc: rtcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_RW__GPIO2_IO26 0x1b0b0
+ >;
+ };
+
+ pinctrl_sgtl5000: sgtl5000grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0
+ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart3: uart3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D23__UART3_CTS_B 0x1b0b1
+ MX6QDL_PAD_EIM_D31__UART3_RTS_B 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
+ /* power enable, high active */
+ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0
+ >;
+ };
+ };
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ fsl,data-mapping = "spwg";
+ fsl,data-width = <18>;
+ status = "okay";
+
+ port@4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in_lvds0>;
+ };
+ };
+ };
+};
+
+&pcie {
+ status = "okay";
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>;
+ status = "okay";
+};
+
+&pwm4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm4>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart3>;
+ fsl,uart-has-rtscts;
+ status = "okay";
+};
+
+&usbh1 {
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ bus-width = <4>;
+ non-removable;
+ vmmc-supply = <&reg_3p3v>;
+ vqmmc-supply = <&reg_wlan_vmmc>;
+ vqmmc-1-8-v;
+ ocr-limit = <0x180>; /* 1.65v - 2.1v */
+ cap-power-off-card;
+ keep-power-in-suspend;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+ vmmc-supply = <&reg_3p3v>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
new file mode 100644
index 0000000..a35d54f
--- /dev/null
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6_max.dtsi
@@ -0,0 +1,873 @@
+/*
+ * Copyright 2015 Boundary Devices, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ chosen {
+ stdout-path = &uart2;
+ };
+
+ memory {
+ reg = <0x10000000 0xF0000000>;
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_1p8v: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "1P8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ reg_2p5v: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ regulator-always-on;
+ };
+
+ reg_3p3v: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ reg_usb_otg_vbus: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "usb_otg_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio3 22 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usb_h1_vbus: regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbh1>;
+ regulator-name = "usb_h1_vbus";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_wlan_vmmc: regulator@5 {
+ compatible = "regulator-fixed";
+ reg = <5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wlan_vmmc>;
+ regulator-name = "reg_wlan_vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio6 15 GPIO_ACTIVE_HIGH>;
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
+
+ reg_can_xcvr: regulator@6 {
+ compatible = "regulator-fixed";
+ reg = <6>;
+ regulator-name = "CAN XCVR";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can_xcvr>;
+ gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_keys>;
+
+ power {
+ label = "Power Button";
+ gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ gpio-key,wakeup;
+ };
+
+ menu {
+ label = "Menu";
+ gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_MENU>;
+ };
+
+ home {
+ label = "Home";
+ gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_HOME>;
+ };
+
+ back {
+ label = "Back";
+ gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_BACK>;
+ };
+
+ volume-up {
+ label = "Volume Up";
+ gpios = <&gpio7 13 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEUP>;
+ };
+
+ volume-down {
+ label = "Volume Down";
+ gpios = <&gpio7 1 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_VOLUMEDOWN>;
+ };
+ };
+
+ i2cmux@2 {
+ compatible = "i2c-mux-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2mux>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mux-gpios = <&gpio3 20 GPIO_ACTIVE_HIGH
+ &gpio4 15 GPIO_ACTIVE_HIGH>;
+ i2c-parent = <&i2c2>;
+ idle-state = <0>;
+
+ i2c2@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ i2cmux@3 {
+ compatible = "i2c-mux-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3mux>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ mux-gpios = <&gpio2 25 GPIO_ACTIVE_HIGH>;
+ i2c-parent = <&i2c3>;
+ idle-state = <0>;
+
+ i2c3@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ speaker-enable {
+ gpios = <&gpio1 29 GPIO_ACTIVE_HIGH>;
+ retain-state-suspended;
+ default-state = "off";
+ };
+
+ ttymxc4-rs232 {
+ gpios = <&gpio6 10 GPIO_ACTIVE_HIGH>;
+ retain-state-suspended;
+ default-state = "on";
+ };
+ };
+
+ backlight_lcd: backlight_lcd {
+ compatible = "pwm-backlight";
+ pwms = <&pwm1 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ power-supply = <&reg_3p3v>;
+ status = "okay";
+ };
+
+ backlight_lvds0: backlight_lvds0 {
+ compatible = "pwm-backlight";
+ pwms = <&pwm4 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ power-supply = <&reg_3p3v>;
+ status = "okay";
+ };
+
+ backlight_lvds1: backlight_lvds1 {
+ compatible = "pwm-backlight";
+ pwms = <&pwm2 0 5000000>;
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <7>;
+ power-supply = <&reg_3p3v>;
+ status = "okay";
+ };
+
+ lcd_display: display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interface-pix-fmt = "bgr666";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_j15>;
+ status = "okay";
+
+ port@0 {
+ reg = <0>;
+
+ lcd_display_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lcd_display_out: endpoint {
+ remote-endpoint = <&lcd_panel_in>;
+ };
+ };
+ };
+
+ panel_lcd {
+ compatible = "okaya,rs800480t-7x0gp";
+ backlight = <&backlight_lcd>;
+
+ port {
+ lcd_panel_in: endpoint {
+ remote-endpoint = <&lcd_display_out>;
+ };
+ };
+ };
+
+ panel_lvds0 {
+ compatible = "hannstar,hsd100pxn1";
+ backlight = <&backlight_lvds0>;
+
+ port {
+ panel_in_lvds0: endpoint {
+ remote-endpoint = <&lvds0_out>;
+ };
+ };
+ };
+
+ panel_lvds1 {
+ compatible = "hannstar,hsd100pxn1";
+ backlight = <&backlight_lvds1>;
+
+ port {
+ panel_in_lvds1: endpoint {
+ remote-endpoint = <&lvds1_out>;
+ };
+ };
+ };
+
+ sound {
+ compatible = "fsl,imx6q-nitrogen6_max-sgtl5000",
+ "fsl,imx-audio-sgtl5000";
+ model = "imx6q-nitrogen6_max-sgtl5000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgtl5000>;
+ ssi-controller = <&ssi1>;
+ audio-codec = <&codec>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ mux-int-port = <1>;
+ mux-ext-port = <3>;
+ };
+};
+
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "okay";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can1>;
+ xceiver-supply = <&reg_can_xcvr>;
+ status = "okay";
+};
+
+&clks {
+ assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ assigned-clock-parents = <&clks IMX6QDL_CLK_PLL3_USB_OTG>,
+ <&clks IMX6QDL_CLK_PLL3_USB_OTG>;
+};
+
+&ecspi1 {
+ fsl,spi-num-chipselects = <1>;
+ cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ flash: m25p80@0 {
+ compatible = "microchip,sst25vf016b";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio1 27 GPIO_ACTIVE_LOW>;
+ txen-skew-ps = <0>;
+ txc-skew-ps = <3000>;
+ rxdv-skew-ps = <0>;
+ rxc-skew-ps = <3000>;
+ rxd0-skew-ps = <0>;
+ rxd1-skew-ps = <0>;
+ rxd2-skew-ps = <0>;
+ rxd3-skew-ps = <0>;
+ txd0-skew-ps = <0>;
+ txd1-skew-ps = <0>;
+ txd2-skew-ps = <0>;
+ txd3-skew-ps = <0>;
+ interrupts-extended = <&gpio1 6 IRQ_TYPE_LEVEL_HIGH>,
+ <&intc 0 119 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ codec: sgtl5000@0a {
+ compatible = "fsl,sgtl5000";
+ reg = <0x0a>;
+ clocks = <&clks 201>;
+ VDDA-supply = <&reg_2p5v>;
+ VDDIO-supply = <&reg_3p3v>;
+ };
+
+ rtc: rtc@68 {
+ compatible = "st,rv4162";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rv4162>;
+ reg = <0x68>;
+ interrupts-extended = <&gpio4 6 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ touchscreen@04 {
+ compatible = "eeti,egalax_ts";
+ reg = <0x04>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ };
+
+ touchscreen@38 {
+ compatible = "edt,edt-ft5x06";
+ reg = <0x38>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ };
+};
+
+&iomuxc {
+ imx6q-nitrogen6_max {
+ pinctrl_audmux: audmuxgrp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
+ >;
+ };
+
+ pinctrl_can1: can1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0
+ >;
+ };
+
+ pinctrl_can_xcvr: can-xcvrgrp {
+ fsl,pins = <
+ /* Flexcan XCVR enable */
+ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x1b0b0
+ >;
+ };
+
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1
+ >;
+ };
+
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x100b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x100b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x100b0
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x100b0
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x100b0
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x100b0
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x100b0
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x100b0
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x100b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+ /* Phy reset */
+ MX6QDL_PAD_ENET_RXD0__GPIO1_IO27 0x0f0b0
+ MX6QDL_PAD_ENET_TX_EN__GPIO1_IO28 0x1b0b0
+ MX6QDL_PAD_GPIO_6__ENET_IRQ 0x000b1
+ >;
+ };
+
+ pinctrl_gpio_keys: gpio_keysgrp {
+ fsl,pins = <
+ /* Power Button */
+ MX6QDL_PAD_NANDF_D3__GPIO2_IO03 0x1b0b0
+ /* Menu Button */
+ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x1b0b0
+ /* Home Button */
+ MX6QDL_PAD_NANDF_D4__GPIO2_IO04 0x1b0b0
+ /* Back Button */
+ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x1b0b0
+ /* Volume Up Button */
+ MX6QDL_PAD_GPIO_18__GPIO7_IO13 0x1b0b0
+ /* Volume Down Button */
+ MX6QDL_PAD_SD3_DAT4__GPIO7_IO01 0x1b0b0
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2mux: i2c2muxgrp {
+ fsl,pins = <
+ /* ov5642 camera i2c enable */
+ MX6QDL_PAD_EIM_D20__GPIO3_IO20 0x000b0
+ /* ov5640_mipi camera i2c enable */
+ MX6QDL_PAD_KEY_ROW4__GPIO4_IO15 0x000b0
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_5__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_16__I2C3_SDA 0x4001b8b1
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
+ >;
+ };
+
+ pinctrl_i2c3mux: i2c3muxgrp {
+ fsl,pins = <
+ /* PCIe I2C enable */
+ MX6QDL_PAD_EIM_OE__GPIO2_IO25 0x000b0
+ >;
+ };
+
+ pinctrl_j15: j15grp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ /* PCIe reset */
+ MX6QDL_PAD_EIM_BCLK__GPIO6_IO31 0x000b0
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm2: pwm2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT2__PWM2_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm3: pwm3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_DAT1__PWM3_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_pwm4: pwm4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD1_CMD__PWM4_OUT 0x1b0b1
+ >;
+ };
+
+ pinctrl_rv4162: rv4162grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL0__GPIO4_IO06 0x1b0b0
+ >;
+ };
+
+ pinctrl_sgtl5000: sgtl5000grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x000b0
+ MX6QDL_PAD_EIM_A25__GPIO5_IO02 0x1b0b0
+ MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x1b0b0
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_DAT7__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_SD3_DAT6__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart5: uart5grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW1__UART5_RX_DATA 0x130b1
+ MX6QDL_PAD_KEY_COL1__UART5_TX_DATA 0x030b1
+ /* RS485 RX Enable: pull up */
+ MX6QDL_PAD_NANDF_RB0__GPIO6_IO10 0x1b0b1
+ /* RS485 DEN: pull down */
+ MX6QDL_PAD_NANDF_CLE__GPIO6_IO07 0x030b1
+ /* RS485/!RS232 Select: pull down (rs232) */
+ MX6QDL_PAD_EIM_CS1__GPIO2_IO24 0x030b1
+ /* ON: pull down */
+ MX6QDL_PAD_NANDF_ALE__GPIO6_IO08 0x030b1
+ >;
+ };
+
+ pinctrl_usbh1: usbh1grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x0b0b0
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x17059
+ MX6QDL_PAD_KEY_COL4__USB_OTG_OC 0x1b0b0
+ /* power enable, high active */
+ MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x000b0
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_NANDF_CS1__SD3_VSELECT 0x100b0
+ MX6QDL_PAD_SD3_DAT5__GPIO7_IO00 0x1b0b0
+ >;
+ };
+
+ pinctrl_usdhc4: usdhc4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
+ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
+ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
+ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
+ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
+ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
+ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
+ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
+ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
+ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
+ >;
+ };
+
+ pinctrl_wlan_vmmc: wlan_vmmcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0
+ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0
+ MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0
+ >;
+ };
+ };
+};
+
+&ipu1_di0_disp0 {
+ remote-endpoint = <&lcd_display_in>;
+};
+
+&ldb {
+ status = "okay";
+
+ lvds-channel@0 {
+ fsl,data-mapping = "spwg";
+ fsl,data-width = <18>;
+ status = "okay";
+
+ port@4 {
+ reg = <4>;
+
+ lvds0_out: endpoint {
+ remote-endpoint = <&panel_in_lvds0>;
+ };
+ };
+ };
+
+ lvds-channel@1 {
+ fsl,data-mapping = "spwg";
+ fsl,data-width = <18>;
+ status = "okay";
+
+ port@4 {
+ reg = <4>;
+
+ lvds1_out: endpoint {
+ remote-endpoint = <&panel_in_lvds1>;
+ };
+ };
+ };
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio6 31 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+ status = "okay";
+};
+
+&pwm2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm2>;
+ status = "okay";
+};
+
+&pwm3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm3>;
+ status = "okay";
+};
+
+&pwm4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm4>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart5>;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_usb_h1_vbus>;
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_usb_otg_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ bus-width = <4>;
+ non-removable;
+ vmmc-supply = <&reg_wlan_vmmc>;
+ cap-power-off-card;
+ keep-power-in-suspend;
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1271";
+ reg = <2>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+ ref-clock-frequency = <38400000>;
+ };
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ cd-gpios = <&gpio7 0 GPIO_ACTIVE_LOW>;
+ bus-width = <4>;
+ vmmc-supply = <&reg_3p3v>;
+ status = "okay";
+};
+
+&usdhc4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc4>;
+ bus-width = <8>;
+ non-removable;
+ vmmc-supply = <&reg_1p8v>;
+ keep-power-in-suspend;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
index 340bc8e..caeed56 100644
--- a/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-nitrogen6x.dtsi
@@ -3,12 +3,42 @@
* Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
@@ -65,6 +95,19 @@
pinctrl-0 = <&pinctrl_can_xcvr>;
gpio = <&gpio1 2 GPIO_ACTIVE_LOW>;
};
+
+ reg_wlan_vmmc: regulator@4 {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_wlan_vmmc>;
+ regulator-name = "reg_wlan_vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio6 15 GPIO_ACTIVE_HIGH>;
+ startup-delay-us = <70000>;
+ enable-active-high;
+ };
};
gpio-keys {
@@ -124,7 +167,7 @@
mux-ext-port = <3>;
};
- backlight_lcd {
+ backlight_lcd: backlight_lcd {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -142,6 +185,43 @@
status = "okay";
};
+ lcd_display: display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interface-pix-fmt = "bgr666";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_j15>;
+ status = "okay";
+
+ port@0 {
+ reg = <0>;
+
+ lcd_display_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lcd_display_out: endpoint {
+ remote-endpoint = <&lcd_panel_in>;
+ };
+ };
+ };
+
+ lcd_panel {
+ compatible = "okaya,rs800480t-7x0gp";
+ backlight = <&backlight_lcd>;
+
+ port {
+ lcd_panel_in: endpoint {
+ remote-endpoint = <&lcd_display_out>;
+ };
+ };
+ };
+
panel {
compatible = "hannstar,hsd100pxn1";
backlight = <&backlight_lvds>;
@@ -182,7 +262,7 @@
status = "okay";
flash: m25p80@0 {
- compatible = "sst,sst25vf016b";
+ compatible = "sst,sst25vf016b", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
@@ -247,6 +327,21 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
status = "okay";
+
+ touchscreen@04 {
+ compatible = "eeti,egalax_ts";
+ reg = <0x04>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
+ };
+
+ touchscreen@38 {
+ compatible = "edt,edt-ft5x06";
+ reg = <0x38>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <9 IRQ_TYPE_EDGE_FALLING>;
+ };
};
&iomuxc {
@@ -258,6 +353,7 @@
fsl,pins = <
/* SGTL5000 sys_mclk */
MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x030b0
+ MX6QDL_PAD_GPIO_9__GPIO1_IO09 0x1b0b0
>;
};
@@ -354,6 +450,39 @@
>;
};
+ pinctrl_j15: j15grp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10
+ >;
+ };
+
pinctrl_pwm1: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
@@ -395,6 +524,18 @@
>;
};
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17071
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10071
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17071
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17071
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17071
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17071
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0
+ >;
+ };
+
pinctrl_usdhc3: usdhc3grp {
fsl,pins = <
MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
@@ -418,9 +559,22 @@
MX6QDL_PAD_NANDF_D6__GPIO2_IO06 0x1b0b0 /* CD */
>;
};
+
+ pinctrl_wlan_vmmc: wlan_vmmcgrp {
+ fsl,pins = <
+ MX6QDL_PAD_NANDF_CS0__GPIO6_IO11 0x100b0
+ MX6QDL_PAD_NANDF_CS2__GPIO6_IO15 0x000b0
+ MX6QDL_PAD_NANDF_CS3__GPIO6_IO16 0x000b0
+ MX6QDL_PAD_SD1_CLK__OSC32K_32K_OUT 0x000b0
+ >;
+ };
};
};
+&ipu1_di0_disp0 {
+ remote-endpoint = <&lcd_display_in>;
+};
+
&ldb {
status = "okay";
@@ -489,6 +643,27 @@
status = "okay";
};
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ bus-width = <4>;
+ non-removable;
+ vmmc-supply = <&reg_wlan_vmmc>;
+ cap-power-off-card;
+ keep-power-in-suspend;
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1271";
+ reg = <2>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>;
+ ref-clock-frequency = <38400000>;
+ };
+};
+
&usdhc3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc3>;
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
index 9e6ecd9..d6d98d4 100644
--- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -12,7 +12,7 @@
#include <dt-bindings/gpio/gpio.h>
/ {
- model = "Phytec phyFLEX-i.MX6 Ouad";
+ model = "Phytec phyFLEX-i.MX6 Quad";
compatible = "phytec,imx6q-pfla02", "fsl,imx6q";
memory {
@@ -80,7 +80,7 @@
cs-gpios = <&gpio4 24 0>;
flash@0 {
- compatible = "m25p80";
+ compatible = "m25p80", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
@@ -373,7 +373,7 @@
};
&pcie {
- pinctrl-name = "default";
+ pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pcie>;
reset-gpio = <&gpio4 17 0>;
status = "disabled";
diff --git a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
index c37bb9ff..d354d40 100644
--- a/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabreauto.dtsi
@@ -113,14 +113,14 @@
&clks {
assigned-clocks = <&clks IMX6QDL_PLL4_BYPASS_SRC>,
<&clks IMX6QDL_PLL4_BYPASS>,
- <&clks IMX6QDL_CLK_PLL4_POST_DIV>,
<&clks IMX6QDL_CLK_LDB_DI0_SEL>,
- <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
+ <&clks IMX6QDL_CLK_LDB_DI1_SEL>,
+ <&clks IMX6QDL_CLK_PLL4_POST_DIV>;
assigned-clock-parents = <&clks IMX6QDL_CLK_LVDS2_IN>,
<&clks IMX6QDL_PLL4_BYPASS_SRC>,
<&clks IMX6QDL_CLK_PLL3_USB_OTG>,
<&clks IMX6QDL_CLK_PLL3_USB_OTG>;
- assigned-clock-rates = <0>, <0>, <24576000>;
+ assigned-clock-rates = <0>, <0>, <0>, <0>, <24576000>;
};
&ecspi1 {
@@ -133,7 +133,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p32";
+ compatible = "st,m25p32", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
index ce4c731..1a69a34 100644
--- a/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabrelite.dtsi
@@ -2,12 +2,42 @@
* Copyright 2011 Freescale Semiconductor, Inc.
* Copyright 2011 Linaro Ltd.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This file is distributed in the hope that it will be useful
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED , WITHOUT WARRANTY OF ANY KIND
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
@@ -123,7 +153,7 @@
mux-ext-port = <4>;
};
- backlight_lcd {
+ backlight_lcd: backlight_lcd {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -141,6 +171,43 @@
status = "okay";
};
+ lcd_display: display@di0 {
+ compatible = "fsl,imx-parallel-display";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interface-pix-fmt = "bgr666";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_j15>;
+ status = "okay";
+
+ port@0 {
+ reg = <0>;
+
+ lcd_display_in: endpoint {
+ remote-endpoint = <&ipu1_di0_disp0>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ lcd_display_out: endpoint {
+ remote-endpoint = <&lcd_panel_in>;
+ };
+ };
+ };
+
+ lcd_panel {
+ compatible = "okaya,rs800480t-7x0gp";
+ backlight = <&backlight_lcd>;
+
+ port {
+ lcd_panel_in: endpoint {
+ remote-endpoint = <&lcd_display_out>;
+ };
+ };
+ };
+
panel {
compatible = "hannstar,hsd100pxn1";
backlight = <&backlight_lvds>;
@@ -181,7 +248,7 @@
status = "okay";
flash: m25p80@0 {
- compatible = "sst,sst25vf016b";
+ compatible = "sst,sst25vf016b", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
@@ -348,6 +415,39 @@
>;
};
+ pinctrl_j15: j15grp {
+ fsl,pins = <
+ MX6QDL_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK 0x10
+ MX6QDL_PAD_DI0_PIN15__IPU1_DI0_PIN15 0x10
+ MX6QDL_PAD_DI0_PIN2__IPU1_DI0_PIN02 0x10
+ MX6QDL_PAD_DI0_PIN3__IPU1_DI0_PIN03 0x10
+ MX6QDL_PAD_DISP0_DAT0__IPU1_DISP0_DATA00 0x10
+ MX6QDL_PAD_DISP0_DAT1__IPU1_DISP0_DATA01 0x10
+ MX6QDL_PAD_DISP0_DAT2__IPU1_DISP0_DATA02 0x10
+ MX6QDL_PAD_DISP0_DAT3__IPU1_DISP0_DATA03 0x10
+ MX6QDL_PAD_DISP0_DAT4__IPU1_DISP0_DATA04 0x10
+ MX6QDL_PAD_DISP0_DAT5__IPU1_DISP0_DATA05 0x10
+ MX6QDL_PAD_DISP0_DAT6__IPU1_DISP0_DATA06 0x10
+ MX6QDL_PAD_DISP0_DAT7__IPU1_DISP0_DATA07 0x10
+ MX6QDL_PAD_DISP0_DAT8__IPU1_DISP0_DATA08 0x10
+ MX6QDL_PAD_DISP0_DAT9__IPU1_DISP0_DATA09 0x10
+ MX6QDL_PAD_DISP0_DAT10__IPU1_DISP0_DATA10 0x10
+ MX6QDL_PAD_DISP0_DAT11__IPU1_DISP0_DATA11 0x10
+ MX6QDL_PAD_DISP0_DAT12__IPU1_DISP0_DATA12 0x10
+ MX6QDL_PAD_DISP0_DAT13__IPU1_DISP0_DATA13 0x10
+ MX6QDL_PAD_DISP0_DAT14__IPU1_DISP0_DATA14 0x10
+ MX6QDL_PAD_DISP0_DAT15__IPU1_DISP0_DATA15 0x10
+ MX6QDL_PAD_DISP0_DAT16__IPU1_DISP0_DATA16 0x10
+ MX6QDL_PAD_DISP0_DAT17__IPU1_DISP0_DATA17 0x10
+ MX6QDL_PAD_DISP0_DAT18__IPU1_DISP0_DATA18 0x10
+ MX6QDL_PAD_DISP0_DAT19__IPU1_DISP0_DATA19 0x10
+ MX6QDL_PAD_DISP0_DAT20__IPU1_DISP0_DATA20 0x10
+ MX6QDL_PAD_DISP0_DAT21__IPU1_DISP0_DATA21 0x10
+ MX6QDL_PAD_DISP0_DAT22__IPU1_DISP0_DATA22 0x10
+ MX6QDL_PAD_DISP0_DAT23__IPU1_DISP0_DATA23 0x10
+ >;
+ };
+
pinctrl_pwm1: pwm1grp {
fsl,pins = <
MX6QDL_PAD_SD1_DAT3__PWM1_OUT 0x1b0b1
@@ -416,6 +516,10 @@
};
};
+&ipu1_di0_disp0 {
+ remote-endpoint = <&lcd_display_in>;
+};
+
&ldb {
status = "okay";
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index 2c07d3a..a6d445c 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -158,7 +158,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p32";
+ compatible = "st,m25p32", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index e716e6f..2b6cc8b 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -218,16 +218,16 @@
dmas = <&sdma 14 18 0>,
<&sdma 15 18 0>;
dma-names = "rx", "tx";
- clocks = <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_OSC>,
- <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_DUMMY>,
- <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_DUMMY>,
- <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_DUMMY>,
- <&clks IMX6QDL_CLK_DUMMY>;
+ clocks = <&clks IMX6QDL_CLK_SPDIF_GCLK>, <&clks IMX6QDL_CLK_OSC>,
+ <&clks IMX6QDL_CLK_SPDIF>, <&clks IMX6QDL_CLK_ASRC>,
+ <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_ESAI_EXTAL>,
+ <&clks IMX6QDL_CLK_IPG>, <&clks IMX6QDL_CLK_MLB>,
+ <&clks IMX6QDL_CLK_DUMMY>, <&clks IMX6QDL_CLK_SPBA>;
clock-names = "core", "rxtx0",
"rxtx1", "rxtx2",
"rxtx3", "rxtx4",
"rxtx5", "rxtx6",
- "rxtx7";
+ "rxtx7", "dma";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index b84dff2..be11882 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -126,7 +126,7 @@
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "st,m25p32";
+ compatible = "st,m25p32", "jedec,spi-nor";
spi-max-frequency = <20000000>;
reg = <0>;
};
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 320a27f..d8ba99f 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -135,8 +135,24 @@
ranges;
spdif: spdif@02004000 {
+ compatible = "fsl,imx6sl-spdif",
+ "fsl,imx35-spdif";
reg = <0x02004000 0x4000>;
interrupts = <0 52 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&sdma 14 18 0>,
+ <&sdma 15 18 0>;
+ dma-names = "rx", "tx";
+ clocks = <&clks IMX6SL_CLK_SPDIF_GCLK>, <&clks IMX6SL_CLK_OSC>,
+ <&clks IMX6SL_CLK_SPDIF>, <&clks IMX6SL_CLK_DUMMY>,
+ <&clks IMX6SL_CLK_DUMMY>, <&clks IMX6SL_CLK_DUMMY>,
+ <&clks IMX6SL_CLK_IPG>, <&clks IMX6SL_CLK_DUMMY>,
+ <&clks IMX6SL_CLK_DUMMY>, <&clks IMX6SL_CLK_SPBA>;
+ clock-names = "core", "rxtx0",
+ "rxtx1", "rxtx2",
+ "rxtx3", "rxtx4",
+ "rxtx5", "rxtx6",
+ "rxtx7", "dma";
+ status = "disabled";
};
ecspi1: ecspi@02008000 {
@@ -670,8 +686,11 @@
};
dcp: dcp@020fc000 {
+ compatible = "fsl,imx6sl-dcp", "fsl,imx28-dcp";
reg = <0x020fc000 0x4000>;
- interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <0 99 IRQ_TYPE_LEVEL_HIGH>,
+ <0 100 IRQ_TYPE_LEVEL_HIGH>,
+ <0 101 IRQ_TYPE_LEVEL_HIGH>;
};
};
diff --git a/arch/arm/boot/dts/imx6sx-sdb-reva.dts b/arch/arm/boot/dts/imx6sx-sdb-reva.dts
index c76b87c..7100547 100644
--- a/arch/arm/boot/dts/imx6sx-sdb-reva.dts
+++ b/arch/arm/boot/dts/imx6sx-sdb-reva.dts
@@ -129,7 +129,7 @@
reg = <0>;
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl128s";
+ compatible = "spansion,s25fl128s", "jedec,spi-nor";
spi-max-frequency = <66000000>;
};
@@ -137,7 +137,7 @@
reg = <1>;
#address-cells = <1>;
#size-cells = <1>;
- compatible = "spansion,s25fl128s";
+ compatible = "spansion,s25fl128s", "jedec,spi-nor";
spi-max-frequency = <66000000>;
};
};
diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts
index 0bfc4e7..0ad164a 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dts
+++ b/arch/arm/boot/dts/imx6sx-sdb.dts
@@ -130,7 +130,7 @@
flash0: n25q256a@0 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q256a";
+ compatible = "micron,n25q256a", "jedec,spi-nor";
spi-max-frequency = <29000000>;
reg = <0>;
};
@@ -138,7 +138,7 @@
flash1: n25q256a@1 {
#address-cells = <1>;
#size-cells = <1>;
- compatible = "micron,n25q256a";
+ compatible = "micron,n25q256a", "jedec,spi-nor";
spi-max-frequency = <29000000>;
reg = <1>;
};
diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi
index ac88c34..94ac400 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dtsi
+++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi
@@ -114,7 +114,7 @@
regulator-name = "peri_3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;
+ gpio = <&gpio4 16 GPIO_ACTIVE_HIGH>;
enable-active-high;
regulator-always-on;
};
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index c94f2ea..167f77b 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -211,7 +211,7 @@
dmas = <&sdma 14 18 0>,
<&sdma 15 18 0>;
dma-names = "rx", "tx";
- clocks = <&clks IMX6SX_CLK_SPDIF>,
+ clocks = <&clks IMX6SX_CLK_SPDIF_GCLK>,
<&clks IMX6SX_CLK_OSC>,
<&clks IMX6SX_CLK_SPDIF>,
<&clks 0>, <&clks 0>, <&clks 0>,
diff --git a/arch/arm/boot/dts/imx6ul-14x14-evk.dts b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
index 25746b1..6aaa5ec 100644
--- a/arch/arm/boot/dts/imx6ul-14x14-evk.dts
+++ b/arch/arm/boot/dts/imx6ul-14x14-evk.dts
@@ -87,6 +87,19 @@
};
};
+&snvs_poweroff {
+ status = "okay";
+};
+
+&tsc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_tsc>;
+ xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
+ measure-delay-time = <0xffff>;
+ pre-charge-time = <0xfff>;
+ status = "okay";
+};
+
&uart1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart1>;
@@ -277,6 +290,15 @@
>;
};
+ pinctrl_tsc: tscgrp {
+ fsl,pins = <
+ MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
+ MX6UL_PAD_GPIO1_IO02__GPIO1_IO02 0xb0
+ MX6UL_PAD_GPIO1_IO03__GPIO1_IO03 0xb0
+ MX6UL_PAD_GPIO1_IO04__GPIO1_IO04 0xb0
+ >;
+ };
+
pinctrl_uart1: uart1grp {
fsl,pins = <
MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
diff --git a/arch/arm/boot/dts/imx6ul.dtsi b/arch/arm/boot/dts/imx6ul.dtsi
index 09edbed..d00e994 100644
--- a/arch/arm/boot/dts/imx6ul.dtsi
+++ b/arch/arm/boot/dts/imx6ul.dtsi
@@ -135,6 +135,11 @@
status = "disabled";
};
+ ocram: sram@00900000 {
+ compatible = "mmio-sram";
+ reg = <0x00900000 0x20000>;
+ };
+
aips1: aips-bus@02000000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
@@ -424,6 +429,14 @@
<GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
};
+ snvs_poweroff: snvs-poweroff {
+ compatible = "syscon-poweroff";
+ regmap = <&snvs>;
+ offset = <0x38>;
+ mask = <0x60>;
+ status = "disabled";
+ };
+
snvs_pwrkey: snvs-powerkey {
compatible = "fsl,sec-v4.0-pwrkey";
regmap = <&snvs>;
@@ -571,6 +584,17 @@
status = "disabled";
};
+ tsc: tsc@02040000 {
+ compatible = "fsl,imx6ul-tsc";
+ reg = <0x02040000 0x4000>, <0x0219c000 0x4000>;
+ interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX6UL_CLK_IPG>,
+ <&clks IMX6UL_CLK_ADC2>;
+ clock-names = "tsc", "adc";
+ status = "disabled";
+ };
+
usdhc1: usdhc@02190000 {
compatible = "fsl,imx6ul-usdhc", "fsl,imx6sx-usdhc";
reg = <0x02190000 0x4000>;
@@ -625,6 +649,11 @@
status = "disabled";
};
+ mmdc: mmdc@021b0000 {
+ compatible = "fsl,imx6ul-mmdc", "fsl,imx6q-mmdc";
+ reg = <0x021b0000 0x4000>;
+ };
+
qspi: qspi@021e0000 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/imx7d-pinfunc.h b/arch/arm/boot/dts/imx7d-pinfunc.h
index a8d8149..eeda783 100644
--- a/arch/arm/boot/dts/imx7d-pinfunc.h
+++ b/arch/arm/boot/dts/imx7d-pinfunc.h
@@ -15,6 +15,122 @@
* <mux_reg conf_reg input_reg mux_mode input_val>
*/
+#define MX7D_PAD_GPIO1_IO00__GPIO1_IO0 0x0000 0x0030 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO00__PWM4_OUT 0x0000 0x0030 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO00__WDOD1_WDOG_ANY 0x0000 0x0030 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO00__WDOD1_WDOG_B 0x0000 0x0030 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO00__WDOD1_WDOG__RST_B_DEB 0x0000 0x0030 0x0000 0x4 0x0
+#define MX7D_PAD_GPIO1_IO01__GPIO1_IO1 0x0004 0x0034 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO01__PWM1_OUT 0x0004 0x0034 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO01__CCM_ENET_REF_CLK3 0x0004 0x0034 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO01__SAI1_MCLK 0x0004 0x0034 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO01__ANATOP_24M_OUT 0x0004 0x0034 0x0000 0x4 0x0
+#define MX7D_PAD_GPIO1_IO01__OBSERVE0_OUT 0x0004 0x0034 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO02__GPIO1_IO2 0x0008 0x0038 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO02__PWM2_OUT 0x0008 0x0038 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO02__CCM_ENET_REF_CLK1 0x0008 0x0038 0x0564 0x2 0x3
+#define MX7D_PAD_GPIO1_IO02__SAI2_MCLK 0x0008 0x0038 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO02__CCM_CLKO1 0x0008 0x0038 0x0000 0x5 0x0
+#define MX7D_PAD_GPIO1_IO02__OBSERVE1_OUT 0x0008 0x0038 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO02__USB_OTG1_ID 0x0008 0x0038 0x0734 0x7 0x3
+#define MX7D_PAD_GPIO1_IO03__GPIO1_IO3 0x000C 0x003C 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO03__PWM3_OUT 0x000C 0x003C 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO03__CCM_ENET_REF_CLK2 0x000C 0x003C 0x0570 0x2 0x3
+#define MX7D_PAD_GPIO1_IO03__SAI3_MCLK 0x000C 0x003C 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO03__CCM_CLKO2 0x000C 0x003C 0x0000 0x5 0x0
+#define MX7D_PAD_GPIO1_IO03__OBSERVE2_OUT 0x000C 0x003C 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO03__USB_OTG2_ID 0x000C 0x003C 0x0730 0x7 0x3
+#define MX7D_PAD_GPIO1_IO04__GPIO1_IO4 0x0010 0x0040 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO04__USB_OTG1_OC 0x0010 0x0040 0x072C 0x1 0x1
+#define MX7D_PAD_GPIO1_IO04__FLEXTIMER1_CH4 0x0010 0x0040 0x0594 0x2 0x1
+#define MX7D_PAD_GPIO1_IO04__UART5_CTS_B 0x0010 0x0040 0x0710 0x3 0x4
+#define MX7D_PAD_GPIO1_IO04__I2C1_SCL 0x0010 0x0040 0x05D4 0x4 0x2
+#define MX7D_PAD_GPIO1_IO04__OBSERVE3_OUT 0x0010 0x0040 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO05__GPIO1_IO5 0x0014 0x0044 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO05__USB_OTG1_PWR 0x0014 0x0044 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO05__FLEXTIMER1_CH5 0x0014 0x0044 0x0598 0x2 0x1
+#define MX7D_PAD_GPIO1_IO05__UART5_RTS_B 0x0014 0x0044 0x0710 0x3 0x5
+#define MX7D_PAD_GPIO1_IO05__I2C1_SDA 0x0014 0x0044 0x05D8 0x4 0x2
+#define MX7D_PAD_GPIO1_IO05__OBSERVE4_OUT 0x0014 0x0044 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO06__GPIO1_IO6 0x0018 0x0048 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO06__USB_OTG2_OC 0x0018 0x0048 0x0728 0x1 0x1
+#define MX7D_PAD_GPIO1_IO06__FLEXTIMER1_CH6 0x0018 0x0048 0x059C 0x2 0x1
+#define MX7D_PAD_GPIO1_IO06__UART5_RX_DATA 0x0018 0x0048 0x0714 0x3 0x4
+#define MX7D_PAD_GPIO1_IO06__I2C2_SCL 0x0018 0x0048 0x05DC 0x4 0x2
+#define MX7D_PAD_GPIO1_IO06__CCM_WAIT 0x0018 0x0048 0x0000 0x5 0x0
+#define MX7D_PAD_GPIO1_IO06__KPP_ROW4 0x0018 0x0048 0x0624 0x6 0x1
+#define MX7D_PAD_GPIO1_IO07__GPIO1_IO7 0x001C 0x004C 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO07__USB_OTG2_PWR 0x001C 0x004C 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO07__FLEXTIMER1_CH7 0x001C 0x004C 0x05A0 0x2 0x1
+#define MX7D_PAD_GPIO1_IO07__UART5_TX_DATA 0x001C 0x004C 0x0714 0x3 0x5
+#define MX7D_PAD_GPIO1_IO07__I2C2_SDA 0x001C 0x004C 0x05E0 0x4 0x2
+#define MX7D_PAD_GPIO1_IO07__CCM_STOP 0x001C 0x004C 0x0000 0x5 0x0
+#define MX7D_PAD_GPIO1_IO07__KPP_COL4 0x001C 0x004C 0x0604 0x6 0x1
+#define MX7D_PAD_GPIO1_IO08__GPIO1_IO8 0x0014 0x026C 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO08__SD1_VSELECT 0x0014 0x026C 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO08__WDOG1_WDOG_B 0x0014 0x026C 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO08__UART3_DCE_RX 0x0014 0x026C 0x0704 0x3 0x0
+#define MX7D_PAD_GPIO1_IO08__UART3_DTE_TX 0x0014 0x026C 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO08__I2C3_SCL 0x0014 0x026C 0x05E4 0x4 0x0
+#define MX7D_PAD_GPIO1_IO08__KPP_COL5 0x0014 0x026C 0x0608 0x6 0x0
+#define MX7D_PAD_GPIO1_IO08__PWM1_OUT 0x0014 0x026C 0x0000 0x7 0x0
+#define MX7D_PAD_GPIO1_IO09__GPIO1_IO9 0x0018 0x0270 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO09__SD1_LCTL 0x0018 0x0270 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO09__CCM_ENET_REF_CLK3 0x0018 0x0270 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO09__UART3_DCE_TX 0x0018 0x0270 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO09__UART3_DTE_RX 0x0018 0x0270 0x0704 0x3 0x1
+#define MX7D_PAD_GPIO1_IO09__I2C3_SDA 0x0018 0x0270 0x05E8 0x4 0x0
+#define MX7D_PAD_GPIO1_IO09__CCM_PMIC_READY 0x0018 0x0270 0x04F4 0x5 0x0
+#define MX7D_PAD_GPIO1_IO09__KPP_ROW5 0x0018 0x0270 0x0628 0x6 0x0
+#define MX7D_PAD_GPIO1_IO09__PWM2_OUT 0x0018 0x0270 0x0000 0x7 0x0
+#define MX7D_PAD_GPIO1_IO10__GPIO1_IO10 0x001C 0x0274 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO10__SD2_LCTL 0x001C 0x0274 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO10__ENET1_MDIO 0x001C 0x0274 0x0568 0x2 0x0
+#define MX7D_PAD_GPIO1_IO10__UART3_DCE_RTS 0x001C 0x0274 0x0700 0x3 0x0
+#define MX7D_PAD_GPIO1_IO10__UART3_DTE_CTS 0x001C 0x0274 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO10__I2C4_SCL 0x001C 0x0274 0x05EC 0x4 0x0
+#define MX7D_PAD_GPIO1_IO10__FLEXTIMER1_PHA 0x001C 0x0274 0x05A4 0x5 0x0
+#define MX7D_PAD_GPIO1_IO10__KPP_COL6 0x001C 0x0274 0x060C 0x6 0x0
+#define MX7D_PAD_GPIO1_IO10__PWM3_OUT 0x001C 0x0274 0x0000 0x7 0x0
+#define MX7D_PAD_GPIO1_IO11__GPIO1_IO11 0x0020 0x0278 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO11__SD3_LCTL 0x0020 0x0278 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO11__ENET1_MDC 0x0020 0x0278 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO11__UART3_DCE_CTS 0x0020 0x0278 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO11__UART3_DTE_RTS 0x0020 0x0278 0x0700 0x3 0x1
+#define MX7D_PAD_GPIO1_IO11__I2C4_SDA 0x0020 0x0278 0x05F0 0x4 0x0
+#define MX7D_PAD_GPIO1_IO11__FLEXTIMER1_PHB 0x0020 0x0278 0x05A8 0x5 0x0
+#define MX7D_PAD_GPIO1_IO11__KPP_ROW6 0x0020 0x0278 0x062C 0x6 0x0
+#define MX7D_PAD_GPIO1_IO11__PWM4_OUT 0x0020 0x0278 0x0000 0x7 0x0
+#define MX7D_PAD_GPIO1_IO12__GPIO1_IO12 0x0024 0x027C 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO12__SD2_VSELECT 0x0024 0x027C 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO12__CCM_ENET_REF_CLK1 0x0024 0x027C 0x0564 0x2 0x0
+#define MX7D_PAD_GPIO1_IO12__FLEXCAN1_RX 0x0024 0x027C 0x04DC 0x3 0x0
+#define MX7D_PAD_GPIO1_IO12__CM4_NMI 0x0024 0x027C 0x0000 0x4 0x0
+#define MX7D_PAD_GPIO1_IO12__CCM_EXT_CLK1 0x0024 0x027C 0x04E4 0x5 0x0
+#define MX7D_PAD_GPIO1_IO12__SNVS_VIO_5 0x0024 0x027C 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO12__USB_OTG1_ID 0x0024 0x027C 0x0734 0x7 0x0
+#define MX7D_PAD_GPIO1_IO13__GPIO1_IO13 0x0028 0x0280 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO13__SD3_VSELECT 0x0028 0x0280 0x0000 0x1 0x0
+#define MX7D_PAD_GPIO1_IO13__CCM_ENET_REF_CLK2 0x0028 0x0280 0x0570 0x2 0x0
+#define MX7D_PAD_GPIO1_IO13__FLEXCAN1_TX 0x0028 0x0280 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO13__CCM_PMIC_READY 0x0028 0x0280 0x04F4 0x4 0x1
+#define MX7D_PAD_GPIO1_IO13__CCM_EXT_CLK2 0x0028 0x0280 0x04E8 0x5 0x0
+#define MX7D_PAD_GPIO1_IO13__SNVS_VIO_5_CTL 0x0028 0x0280 0x0000 0x6 0x0
+#define MX7D_PAD_GPIO1_IO13__USB_OTG2_ID 0x0028 0x0280 0x0730 0x7 0x0
+#define MX7D_PAD_GPIO1_IO14__GPIO1_IO14 0x002C 0x0284 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO14__SD3_CD_B 0x002C 0x0284 0x0738 0x1 0x0
+#define MX7D_PAD_GPIO1_IO14__ENET2_MDIO 0x002C 0x0284 0x0574 0x2 0x0
+#define MX7D_PAD_GPIO1_IO14__FLEXCAN2_RX 0x002C 0x0284 0x04E0 0x3 0x0
+#define MX7D_PAD_GPIO1_IO14__WDOG3_WDOG_B 0x002C 0x0284 0x0000 0x4 0x0
+#define MX7D_PAD_GPIO1_IO14__CCM_EXT_CLK3 0x002C 0x0284 0x04EC 0x5 0x0
+#define MX7D_PAD_GPIO1_IO14__SDMA_EXT_EVENT0 0x002C 0x0284 0x06D8 0x6 0x0
+#define MX7D_PAD_GPIO1_IO15__GPIO1_IO15 0x0030 0x0288 0x0000 0x0 0x0
+#define MX7D_PAD_GPIO1_IO15__SD3_WP 0x0030 0x0288 0x073C 0x1 0x0
+#define MX7D_PAD_GPIO1_IO15__ENET2_MDC 0x0030 0x0288 0x0000 0x2 0x0
+#define MX7D_PAD_GPIO1_IO15__FLEXCAN2_TX 0x0030 0x0288 0x0000 0x3 0x0
+#define MX7D_PAD_GPIO1_IO15__WDOG4_WDOG_B 0x0030 0x0288 0x0000 0x4 0x0
+#define MX7D_PAD_GPIO1_IO15__CCM_EXT_CLK4 0x0030 0x0288 0x04F0 0x5 0x0
+#define MX7D_PAD_GPIO1_IO15__SDMA_EXT_EVENT1 0x0030 0x0288 0x06DC 0x6 0x0
#define MX7D_PAD_EPDC_DATA00__EPDC_DATA0 0x0034 0x02A4 0x0000 0x0 0x0
#define MX7D_PAD_EPDC_DATA00__SIM1_PORT2_TRXD 0x0034 0x02A4 0x0000 0x1 0x0
#define MX7D_PAD_EPDC_DATA00__QSPI_A_DATA0 0x0034 0x02A4 0x0000 0x2 0x0
@@ -453,7 +569,7 @@
#define MX7D_PAD_LCD_DATA23__EIM_ADDR26 0x0124 0x0394 0x0000 0x4 0x0
#define MX7D_PAD_LCD_DATA23__GPIO3_IO28 0x0124 0x0394 0x0000 0x5 0x0
#define MX7D_PAD_LCD_DATA23__I2C4_SDA 0x0124 0x0394 0x05F0 0x6 0x1
-#define MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x0128 0x0398 0x0000 0x0 0x0
+#define MX7D_PAD_UART1_RX_DATA__UART1_DCE_RX 0x0128 0x0398 0x06F4 0x0 0x0
#define MX7D_PAD_UART1_RX_DATA__UART1_DTE_TX 0x0128 0x0398 0x0000 0x0 0x0
#define MX7D_PAD_UART1_RX_DATA__I2C1_SCL 0x0128 0x0398 0x05D4 0x1 0x0
#define MX7D_PAD_UART1_RX_DATA__CCM_PMIC_READY 0x0128 0x0398 0x0000 0x2 0x0
@@ -469,7 +585,7 @@
#define MX7D_PAD_UART1_TX_DATA__ENET2_1588_EVENT0_OUT 0x012C 0x039C 0x0000 0x4 0x0
#define MX7D_PAD_UART1_TX_DATA__GPIO4_IO1 0x012C 0x039C 0x0000 0x5 0x0
#define MX7D_PAD_UART1_TX_DATA__ENET1_MDC 0x012C 0x039C 0x0000 0x6 0x0
-#define MX7D_PAD_UART2_RX_DATA__UART2_DCE_RX 0x0130 0x03A0 0x0000 0x0 0x0
+#define MX7D_PAD_UART2_RX_DATA__UART2_DCE_RX 0x0130 0x03A0 0x06FC 0x0 0x2
#define MX7D_PAD_UART2_RX_DATA__UART2_DTE_TX 0x0130 0x03A0 0x0000 0x0 0x0
#define MX7D_PAD_UART2_RX_DATA__I2C2_SCL 0x0130 0x03A0 0x05DC 0x1 0x0
#define MX7D_PAD_UART2_RX_DATA__SAI3_RX_BCLK 0x0130 0x03A0 0x0000 0x2 0x0
@@ -501,7 +617,7 @@
#define MX7D_PAD_UART3_TX_DATA__ENET1_1588_EVENT0_OUT 0x013C 0x03AC 0x0000 0x4 0x0
#define MX7D_PAD_UART3_TX_DATA__GPIO4_IO5 0x013C 0x03AC 0x0000 0x5 0x0
#define MX7D_PAD_UART3_TX_DATA__SD2_LCTL 0x013C 0x03AC 0x0000 0x6 0x0
-#define MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS 0x0140 0x03B0 0x0000 0x0 0x0
+#define MX7D_PAD_UART3_RTS_B__UART3_DCE_RTS 0x0140 0x03B0 0x0700 0x0 0x2
#define MX7D_PAD_UART3_RTS_B__UART3_DTE_CTS 0x0140 0x03B0 0x0000 0x0 0x0
#define MX7D_PAD_UART3_RTS_B__USB_OTG2_OC 0x0140 0x03B0 0x0728 0x1 0x0
#define MX7D_PAD_UART3_RTS_B__SAI3_TX_DATA0 0x0140 0x03B0 0x0000 0x2 0x0
diff --git a/arch/arm/boot/dts/imx7d-sdb.dts b/arch/arm/boot/dts/imx7d-sdb.dts
index fdd1d7c..432aaf5 100644
--- a/arch/arm/boot/dts/imx7d-sdb.dts
+++ b/arch/arm/boot/dts/imx7d-sdb.dts
@@ -101,6 +101,45 @@
arm-supply = <&sw1a_reg>;
};
+&fec1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet1>;
+ assigned-clocks = <&clks IMX7D_ENET1_TIME_ROOT_SRC>,
+ <&clks IMX7D_ENET1_TIME_ROOT_CLK>;
+ assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
+ assigned-clock-rates = <0>, <100000000>;
+ phy-mode = "rgmii";
+ phy-handle = <&ethphy0>;
+ fsl,magic-packet;
+ status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
+ assigned-clocks = <&clks IMX7D_ENET2_TIME_ROOT_SRC>,
+ <&clks IMX7D_ENET2_TIME_ROOT_CLK>;
+ assigned-clock-parents = <&clks IMX7D_PLL_ENET_MAIN_100M_CLK>;
+ assigned-clock-rates = <0>, <100000000>;
+ phy-mode = "rgmii";
+ phy-handle = <&ethphy1>;
+ fsl,magic-packet;
+ status = "okay";
+};
+
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
@@ -231,6 +270,17 @@
status = "okay";
};
+&usbotg1 {
+ vbus-supply = <&reg_usb_otg1_vbus>;
+ status = "okay";
+};
+
+&usbotg2 {
+ vbus-supply = <&reg_usb_otg2_vbus>;
+ dr_mode = "host";
+ status = "okay";
+};
+
&usdhc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usdhc1>;
@@ -241,11 +291,60 @@
status = "okay";
};
+&usdhc3 {
+ pinctrl-names = "default", "state_100mhz", "state_200mhz";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ pinctrl-1 = <&pinctrl_usdhc3_100mhz>;
+ pinctrl-2 = <&pinctrl_usdhc3_200mhz>;
+ assigned-clocks = <&clks IMX7D_USDHC3_ROOT_CLK>;
+ assigned-clock-rates = <400000000>;
+ bus-width = <8>;
+ fsl,tuning-step = <2>;
+ non-removable;
+ status = "okay";
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
imx7d-sdb {
+ pinctrl_enet1: enet1grp {
+ fsl,pins = <
+ MX7D_PAD_GPIO1_IO10__ENET1_MDIO 0x3
+ MX7D_PAD_GPIO1_IO11__ENET1_MDC 0x3
+ MX7D_PAD_ENET1_RGMII_TXC__ENET1_RGMII_TXC 0x1
+ MX7D_PAD_ENET1_RGMII_TD0__ENET1_RGMII_TD0 0x1
+ MX7D_PAD_ENET1_RGMII_TD1__ENET1_RGMII_TD1 0x1
+ MX7D_PAD_ENET1_RGMII_TD2__ENET1_RGMII_TD2 0x1
+ MX7D_PAD_ENET1_RGMII_TD3__ENET1_RGMII_TD3 0x1
+ MX7D_PAD_ENET1_RGMII_TX_CTL__ENET1_RGMII_TX_CTL 0x1
+ MX7D_PAD_ENET1_RGMII_RXC__ENET1_RGMII_RXC 0x1
+ MX7D_PAD_ENET1_RGMII_RD0__ENET1_RGMII_RD0 0x1
+ MX7D_PAD_ENET1_RGMII_RD1__ENET1_RGMII_RD1 0x1
+ MX7D_PAD_ENET1_RGMII_RD2__ENET1_RGMII_RD2 0x1
+ MX7D_PAD_ENET1_RGMII_RD3__ENET1_RGMII_RD3 0x1
+ MX7D_PAD_ENET1_RGMII_RX_CTL__ENET1_RGMII_RX_CTL 0x1
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX7D_PAD_EPDC_GDSP__ENET2_RGMII_TXC 0x1
+ MX7D_PAD_EPDC_SDCE2__ENET2_RGMII_TD0 0x1
+ MX7D_PAD_EPDC_SDCE3__ENET2_RGMII_TD1 0x1
+ MX7D_PAD_EPDC_GDCLK__ENET2_RGMII_TD2 0x1
+ MX7D_PAD_EPDC_GDOE__ENET2_RGMII_TD3 0x1
+ MX7D_PAD_EPDC_GDRL__ENET2_RGMII_TX_CTL 0x1
+ MX7D_PAD_EPDC_SDCE1__ENET2_RGMII_RXC 0x1
+ MX7D_PAD_EPDC_SDCLK__ENET2_RGMII_RD0 0x1
+ MX7D_PAD_EPDC_SDLE__ENET2_RGMII_RD1 0x1
+ MX7D_PAD_EPDC_SDOE__ENET2_RGMII_RD2 0x1
+ MX7D_PAD_EPDC_SDSHR__ENET2_RGMII_RD3 0x1
+ MX7D_PAD_EPDC_SDCE0__ENET2_RGMII_RX_CTL 0x1
+ >;
+ };
+
pinctrl_hog: hoggrp {
fsl,pins = <
MX7D_PAD_UART3_CTS_B__GPIO4_IO7 0x14
@@ -281,7 +380,6 @@
>;
};
-
pinctrl_uart1: uart1grp {
fsl,pins = <
MX7D_PAD_UART1_TX_DATA__UART1_DCE_TX 0x79
diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index 6e444bb..ebc053a 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -446,6 +446,12 @@
status = "disabled";
};
+ iomuxc_lpsr: iomuxc-lpsr@302c0000 {
+ compatible = "fsl,imx7d-iomuxc-lpsr";
+ reg = <0x302c0000 0x10000>;
+ fsl,input-sel = <&iomuxc>;
+ };
+
gpt1: gpt@302d0000 {
compatible = "fsl,imx7d-gpt", "fsl,imx6sx-gpt";
reg = <0x302d0000 0x10000>;
@@ -570,6 +576,58 @@
};
};
+ aips2: aips-bus@30400000 {
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x30400000 0x400000>;
+ ranges;
+
+ pwm1: pwm@30660000 {
+ compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm";
+ reg = <0x30660000 0x10000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_PWM1_ROOT_CLK>,
+ <&clks IMX7D_PWM1_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
+ pwm2: pwm@30670000 {
+ compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm";
+ reg = <0x30670000 0x10000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_PWM2_ROOT_CLK>,
+ <&clks IMX7D_PWM2_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
+ pwm3: pwm@30680000 {
+ compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm";
+ reg = <0x30680000 0x10000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_PWM3_ROOT_CLK>,
+ <&clks IMX7D_PWM3_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+
+ pwm4: pwm@30690000 {
+ compatible = "fsl,imx7d-pwm", "fsl,imx27-pwm";
+ reg = <0x30690000 0x10000>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_PWM4_ROOT_CLK>,
+ <&clks IMX7D_PWM4_ROOT_CLK>;
+ clock-names = "ipg", "per";
+ #pwm-cells = <2>;
+ status = "disabled";
+ };
+ };
+
aips3: aips-bus@30800000 {
compatible = "fsl,aips-bus", "simple-bus";
#address-cells = <1>;
@@ -694,6 +752,77 @@
status = "disabled";
};
+ usbotg1: usb@30b10000 {
+ compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
+ reg = <0x30b10000 0x200>;
+ interrupts = <GIC_SPI 43 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_USB_CTRL_CLK>;
+ fsl,usbphy = <&usbphynop1>;
+ fsl,usbmisc = <&usbmisc1 0>;
+ phy-clkgate-delay-us = <400>;
+ status = "disabled";
+ };
+
+ usbotg2: usb@30b20000 {
+ compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
+ reg = <0x30b20000 0x200>;
+ interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_USB_CTRL_CLK>;
+ fsl,usbphy = <&usbphynop2>;
+ fsl,usbmisc = <&usbmisc2 0>;
+ phy-clkgate-delay-us = <400>;
+ status = "disabled";
+ };
+
+ usbh: usb@30b30000 {
+ compatible = "fsl,imx7d-usb", "fsl,imx27-usb";
+ reg = <0x30b30000 0x200>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_USB_CTRL_CLK>;
+ fsl,usbphy = <&usbphynop3>;
+ fsl,usbmisc = <&usbmisc3 0>;
+ phy_type = "hsic";
+ dr_mode = "host";
+ phy-clkgate-delay-us = <400>;
+ status = "disabled";
+ };
+
+ usbmisc1: usbmisc@30b10200 {
+ #index-cells = <1>;
+ compatible = "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
+ reg = <0x30b10200 0x200>;
+ };
+
+ usbmisc2: usbmisc@30b20200 {
+ #index-cells = <1>;
+ compatible = "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
+ reg = <0x30b20200 0x200>;
+ };
+
+ usbmisc3: usbmisc@30b30200 {
+ #index-cells = <1>;
+ compatible = "fsl,imx7d-usbmisc", "fsl,imx6q-usbmisc";
+ reg = <0x30b30200 0x200>;
+ };
+
+ usbphynop1: usbphynop1 {
+ compatible = "usb-nop-xceiv";
+ clocks = <&clks IMX7D_USB_PHY1_CLK>;
+ clock-names = "main_clk";
+ };
+
+ usbphynop2: usbphynop2 {
+ compatible = "usb-nop-xceiv";
+ clocks = <&clks IMX7D_USB_PHY2_CLK>;
+ clock-names = "main_clk";
+ };
+
+ usbphynop3: usbphynop3 {
+ compatible = "usb-nop-xceiv";
+ clocks = <&clks IMX7D_USB_HSIC_ROOT_CLK>;
+ clock-names = "main_clk";
+ };
+
usdhc1: usdhc@30b40000 {
compatible = "fsl,imx7d-usdhc", "fsl,imx6sl-usdhc";
reg = <0x30b40000 0x10000>;
@@ -729,6 +858,42 @@
bus-width = <4>;
status = "disabled";
};
+
+ fec1: ethernet@30be0000 {
+ compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec";
+ reg = <0x30be0000 0x10000>;
+ interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+ <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+ <&clks IMX7D_ENET1_TIME_ROOT_CLK>,
+ <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,
+ <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>;
+ clock-names = "ipg", "ahb", "ptp",
+ "enet_clk_ref", "enet_out";
+ fsl,num-tx-queues=<3>;
+ fsl,num-rx-queues=<3>;
+ status = "disabled";
+ };
+
+ fec2: ethernet@30bf0000 {
+ compatible = "fsl,imx7d-fec", "fsl,imx6sx-fec";
+ reg = <0x30bf0000 0x10000>;
+ interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+ <&clks IMX7D_ENET_AXI_ROOT_CLK>,
+ <&clks IMX7D_ENET2_TIME_ROOT_CLK>,
+ <&clks IMX7D_PLL_ENET_MAIN_125M_CLK>,
+ <&clks IMX7D_ENET_PHY_REF_ROOT_CLK>;
+ clock-names = "ipg", "ahb", "ptp",
+ "enet_clk_ref", "enet_out";
+ fsl,num-tx-queues=<3>;
+ fsl,num-rx-queues=<3>;
+ status = "disabled";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/k2e-evm.dts b/arch/arm/boot/dts/k2e-evm.dts
index 50c83c2..b7e9980 100644
--- a/arch/arm/boot/dts/k2e-evm.dts
+++ b/arch/arm/boot/dts/k2e-evm.dts
@@ -13,7 +13,7 @@
#include "k2e.dtsi"
/ {
- compatible = "ti,k2e-evm","ti,keystone";
+ compatible = "ti,k2e-evm", "ti,k2e", "ti,keystone";
model = "Texas Instruments Keystone 2 Edison EVM";
soc {
diff --git a/arch/arm/boot/dts/k2e-netcp.dtsi b/arch/arm/boot/dts/k2e-netcp.dtsi
index b13b3c9..ac990f6 100644
--- a/arch/arm/boot/dts/k2e-netcp.dtsi
+++ b/arch/arm/boot/dts/k2e-netcp.dtsi
@@ -72,7 +72,17 @@ qmss: qmss@2a40000 {
qalloc-by-id;
};
};
+ accumulator {
+ acc-low-0 {
+ qrange = <480 32>;
+ accumulator = <0 47 16 2 50>;
+ interrupts = <0 226 0xf01>;
+ multi-queue;
+ qalloc-by-id;
+ };
+ };
};
+
descriptor-regions {
#address-cells = <1>;
#size-cells = <1>;
@@ -83,6 +93,19 @@ qmss: qmss@2a40000 {
link-index = <0x4000>;
};
};
+
+ pdsps {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ pdsp0@0x2a10000 {
+ reg = <0x2a10000 0x1000 /*iram */
+ 0x2a0f000 0x100 /*reg*/
+ 0x2a0c000 0x3c8 /*intd */
+ 0x2a20000 0x4000>; /*cmd*/
+ id = <0>;
+ };
+ };
}; /* qmss */
knav_dmas: knav_dmas@0 {
diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
index 675fb8e..1097dad 100644
--- a/arch/arm/boot/dts/k2e.dtsi
+++ b/arch/arm/boot/dts/k2e.dtsi
@@ -9,6 +9,9 @@
*/
/ {
+ compatible = "ti,k2e", "ti,keystone";
+ model = "Texas Instruments Keystone 2 Edison SoC";
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/k2hk-evm.dts b/arch/arm/boot/dts/k2hk-evm.dts
index 660ebf5..8161bf5 100644
--- a/arch/arm/boot/dts/k2hk-evm.dts
+++ b/arch/arm/boot/dts/k2hk-evm.dts
@@ -13,7 +13,7 @@
#include "k2hk.dtsi"
/ {
- compatible = "ti,k2hk-evm","ti,keystone";
+ compatible = "ti,k2hk-evm", "ti,k2hk", "ti,keystone";
model = "Texas Instruments Keystone 2 Kepler/Hawking EVM";
soc {
diff --git a/arch/arm/boot/dts/k2hk-netcp.dtsi b/arch/arm/boot/dts/k2hk-netcp.dtsi
index 77a32c3..f86d6dd 100644
--- a/arch/arm/boot/dts/k2hk-netcp.dtsi
+++ b/arch/arm/boot/dts/k2hk-netcp.dtsi
@@ -47,6 +47,7 @@ qmss: qmss@2a40000 {
"region", "push", "pop";
};
};
+
queue-pools {
qpend {
qpend-0 {
@@ -88,7 +89,17 @@ qmss: qmss@2a40000 {
qalloc-by-id;
};
};
+ accumulator {
+ acc-low-0 {
+ qrange = <480 32>;
+ accumulator = <0 47 16 2 50>;
+ interrupts = <0 226 0xf01>;
+ multi-queue;
+ qalloc-by-id;
+ };
+ };
};
+
descriptor-regions {
#address-cells = <1>;
#size-cells = <1>;
@@ -99,6 +110,19 @@ qmss: qmss@2a40000 {
link-index = <0x4000>;
};
};
+
+ pdsps {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ pdsp0@0x2a10000 {
+ reg = <0x2a10000 0x1000 /*iram */
+ 0x2a0f000 0x100 /*reg*/
+ 0x2a0c000 0x3c8 /*intd */
+ 0x2a20000 0x4000>; /*cmd*/
+ id = <0>;
+ };
+ };
}; /* qmss */
knav_dmas: knav_dmas@0 {
diff --git a/arch/arm/boot/dts/k2hk.dtsi b/arch/arm/boot/dts/k2hk.dtsi
index d0810a5..ada4c7a 100644
--- a/arch/arm/boot/dts/k2hk.dtsi
+++ b/arch/arm/boot/dts/k2hk.dtsi
@@ -9,6 +9,9 @@
*/
/ {
+ compatible = "ti,k2hk", "ti,keystone";
+ model = "Texas Instruments Keystone 2 Kepler/Hawking SoC";
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/k2l-evm.dts b/arch/arm/boot/dts/k2l-evm.dts
index 9a69a6b..0086124 100644
--- a/arch/arm/boot/dts/k2l-evm.dts
+++ b/arch/arm/boot/dts/k2l-evm.dts
@@ -13,7 +13,7 @@
#include "k2l.dtsi"
/ {
- compatible = "ti,k2l-evm","ti,keystone";
+ compatible = "ti,k2l-evm", "ti,k2l", "ti,keystone";
model = "Texas Instruments Keystone 2 Lamarr EVM";
soc {
diff --git a/arch/arm/boot/dts/k2l-netcp.dtsi b/arch/arm/boot/dts/k2l-netcp.dtsi
index 6b95284..5acbd0d 100644
--- a/arch/arm/boot/dts/k2l-netcp.dtsi
+++ b/arch/arm/boot/dts/k2l-netcp.dtsi
@@ -72,7 +72,16 @@ qmss: qmss@2a40000 {
qalloc-by-id;
};
};
+ accumulator {
+ acc-low-0 {
+ qrange = <480 32>;
+ accumulator = <0 47 16 2 50>;
+ interrupts = <0 226 0xf01>;
+ multi-queue;
+ };
+ };
};
+
descriptor-regions {
#address-cells = <1>;
#size-cells = <1>;
@@ -83,6 +92,20 @@ qmss: qmss@2a40000 {
link-index = <0x4000>;
};
};
+
+ pdsps {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ pdsp0@0x2a10000 {
+ reg = <0x2a10000 0x1000 /*iram */
+ 0x2a0f000 0x100 /*reg*/
+ 0x2a0c000 0x3c8 /*intd */
+ 0x2a20000 0x4000>; /*cmd*/
+ id = <0>;
+ };
+ };
+
}; /* qmss */
knav_dmas: knav_dmas@0 {
@@ -114,7 +137,7 @@ netcp: netcp@26000000 {
/* NetCP address range */
ranges = <0 0x26000000 0x1000000>;
- clocks = <&papllclk>, <&clkcpgmac>, <&chipclk12>;
+ clocks = <&clkosr>, <&papllclk>, <&clkcpgmac>, <&chipclk12>;
dma-coherent;
ti,navigator-dmas = <&dma_gbe 0>,
diff --git a/arch/arm/boot/dts/k2l.dtsi b/arch/arm/boot/dts/k2l.dtsi
index 49fd414..4446da7 100644
--- a/arch/arm/boot/dts/k2l.dtsi
+++ b/arch/arm/boot/dts/k2l.dtsi
@@ -9,6 +9,9 @@
*/
/ {
+ compatible = "ti,k2l", "ti,keystone";
+ model = "Texas Instruments Keystone 2 Lamarr SoC";
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
index 72816d6..3f27282 100644
--- a/arch/arm/boot/dts/keystone.dtsi
+++ b/arch/arm/boot/dts/keystone.dtsi
@@ -12,6 +12,7 @@
#include "skeleton.dtsi"
/ {
+ compatible = "ti,keystone";
model = "Texas Instruments Keystone 2 SoC";
#address-cells = <2>;
#size-cells = <2>;
@@ -136,7 +137,7 @@
};
spi0: spi@21000400 {
- compatible = "ti,dm6441-spi";
+ compatible = "ti,keystone-spi", "ti,dm6441-spi";
reg = <0x21000400 0x200>;
num-cs = <4>;
ti,davinci-spi-intr-line = <0>;
@@ -147,7 +148,7 @@
};
spi1: spi@21000600 {
- compatible = "ti,dm6441-spi";
+ compatible = "ti,keystone-spi", "ti,dm6441-spi";
reg = <0x21000600 0x200>;
num-cs = <4>;
ti,davinci-spi-intr-line = <0>;
@@ -158,7 +159,7 @@
};
spi2: spi@21000800 {
- compatible = "ti,dm6441-spi";
+ compatible = "ti,keystone-spi", "ti,dm6441-spi";
reg = <0x21000800 0x200>;
num-cs = <4>;
ti,davinci-spi-intr-line = <0>;
diff --git a/arch/arm/boot/dts/kirkwood-ts219.dtsi b/arch/arm/boot/dts/kirkwood-ts219.dtsi
index c56ab6b..0e46560 100644
--- a/arch/arm/boot/dts/kirkwood-ts219.dtsi
+++ b/arch/arm/boot/dts/kirkwood-ts219.dtsi
@@ -40,7 +40,7 @@
};
poweroff@12100 {
compatible = "qnap,power-off";
- reg = <0x12000 0x100>;
+ reg = <0x12100 0x100>;
clocks = <&gate_clk 7>;
};
spi@10600 {
diff --git a/arch/arm/boot/dts/kirkwood.dtsi b/arch/arm/boot/dts/kirkwood.dtsi
index 464f09a..7b5a4a1 100644
--- a/arch/arm/boot/dts/kirkwood.dtsi
+++ b/arch/arm/boot/dts/kirkwood.dtsi
@@ -40,16 +40,6 @@
pcie-mem-aperture = <0xe0000000 0x10000000>; /* 256 MiB memory space */
pcie-io-aperture = <0xf2000000 0x100000>; /* 1 MiB I/O space */
- cesa: crypto@0301 {
- compatible = "marvell,orion-crypto";
- reg = <MBUS_ID(0xf0, 0x01) 0x30000 0x10000>,
- <MBUS_ID(0x03, 0x01) 0 0x800>;
- reg-names = "regs", "sram";
- interrupts = <22>;
- clocks = <&gate_clk 17>;
- status = "okay";
- };
-
nand: nand@012f {
#address-cells = <1>;
#size-cells = <1>;
@@ -65,6 +55,14 @@
pinctrl-names = "default";
status = "disabled";
};
+
+ crypto_sram: sa-sram@0301 {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x03, 0x01) 0x0 0x800>;
+ clocks = <&gate_clk 17>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
};
ocp@f1000000 {
@@ -252,6 +250,17 @@
status = "okay";
};
+ cesa: crypto@30000 {
+ compatible = "marvell,kirkwood-crypto";
+ reg = <0x30000 0x10000>;
+ reg-names = "regs";
+ interrupts = <22>;
+ clocks = <&gate_clk 17>;
+ marvell,crypto-srams = <&crypto_sram>;
+ marvell,crypto-sram-size = <0x800>;
+ status = "okay";
+ };
+
usb0: ehci@50000 {
compatible = "marvell,orion-ehci";
reg = <0x50000 0x1000>;
diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi
index 2c569a6..52591d8 100644
--- a/arch/arm/boot/dts/lpc18xx.dtsi
+++ b/arch/arm/boot/dts/lpc18xx.dtsi
@@ -68,6 +68,46 @@
};
soc {
+ sct_pwm: pwm@40000000 {
+ compatible = "nxp,lpc1850-sct-pwm";
+ reg = <0x40000000 0x1000>;
+ clocks =<&ccu1 CLK_CPU_SCT>;
+ clock-names = "pwm";
+ resets = <&rgu 37>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ dmac: dma-controller@40002000 {
+ compatible = "arm,pl080", "arm,primecell";
+ arm,primecell-periphid = <0x00041080>;
+ reg = <0x40002000 0x1000>;
+ interrupts = <2>;
+ clocks = <&ccu1 CLK_CPU_DMA>;
+ clock-names = "apb_pclk";
+ resets = <&rgu 19>;
+ #dma-cells = <2>;
+ dma-channels = <8>;
+ dma-requests = <16>;
+ lli-bus-interface-ahb1;
+ lli-bus-interface-ahb2;
+ mem-bus-interface-ahb1;
+ mem-bus-interface-ahb2;
+ memcpy-burst-size = <256>;
+ memcpy-bus-width = <32>;
+ };
+
+ spifi: flash-controller@40003000 {
+ compatible = "nxp,lpc1773-spifi";
+ reg = <0x40003000 0x1000>, <0x14000000 0x4000000>;
+ reg-names = "spifi", "flash";
+ interrupts = <30>;
+ clocks = <&ccu1 CLK_SPIFI>, <&ccu1 CLK_CPU_SPIFI>;
+ clock-names = "spifi", "reg";
+ resets = <&rgu 53>;
+ status = "disabled";
+ };
+
mmcsd: mmcsd@40004000 {
compatible = "snps,dw-mshc";
reg = <0x40004000 0x1000>;
@@ -75,6 +115,7 @@
num-slots = <1>;
clocks = <&ccu2 CLK_SDIO>, <&ccu1 CLK_CPU_SDIO>;
clock-names = "ciu", "biu";
+ resets = <&rgu 20>;
status = "disabled";
};
@@ -83,6 +124,7 @@
reg = <0x40006100 0x100>;
interrupts = <8>;
clocks = <&ccu1 CLK_CPU_USB0>;
+ resets = <&rgu 17>;
phys = <&usb0_otg_phy>;
phy-names = "usb";
has-transaction-translator;
@@ -94,6 +136,7 @@
reg = <0x40007100 0x100>;
interrupts = <9>;
clocks = <&ccu1 CLK_CPU_USB1>;
+ resets = <&rgu 18>;
status = "disabled";
};
@@ -102,6 +145,7 @@
reg = <0x40005000 0x1000>;
clocks = <&ccu1 CLK_CPU_EMCDIV>, <&ccu1 CLK_CPU_EMC>;
clock-names = "mpmcclk", "apb_pclk";
+ resets = <&rgu 21>;
#address-cells = <2>;
#size-cells = <1>;
ranges = <0 0 0x1c000000 0x1000000
@@ -118,6 +162,7 @@
interrupt-names = "combined";
clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
clock-names = "clcdclk", "apb_pclk";
+ resets = <&rgu 16>;
status = "disabled";
};
@@ -128,6 +173,8 @@
interrupt-names = "macirq";
clocks = <&ccu1 CLK_CPU_ETHERNET>;
clock-names = "stmmaceth";
+ resets = <&rgu 22>;
+ reset-names = "stmmaceth";
status = "disabled";
};
@@ -135,12 +182,20 @@
compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd";
reg = <0x40043000 0x1000>;
clocks = <&ccu1 CLK_CPU_CREG>;
+ resets = <&rgu 5>;
usb0_otg_phy: phy@004 {
compatible = "nxp,lpc1850-usb-otg-phy";
clocks = <&ccu1 CLK_USB0>;
#phy-cells = <0>;
};
+
+ dmamux: dma-mux@11c {
+ compatible = "nxp,lpc1850-dmamux";
+ #dma-cells = <3>;
+ dma-requests = <64>;
+ dma-masters = <&dmac>;
+ };
};
cgu: clock-controller@40050000 {
@@ -178,6 +233,22 @@
"base_ssp0_clk", "base_sdio_clk";
};
+ rgu: reset-controller@40053000 {
+ compatible = "nxp,lpc1850-rgu";
+ reg = <0x40053000 0x1000>;
+ clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_BUS>;
+ clock-names = "delay", "reg";
+ #reset-cells = <1>;
+ };
+
+ watchdog@40080000 {
+ compatible = "nxp,lpc1850-wwdt";
+ reg = <0x40080000 0x24>;
+ interrupts = <49>;
+ clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_WWDT>;
+ clock-names = "wdtclk", "reg";
+ };
+
uart0: serial@40081000 {
compatible = "nxp,lpc1850-uart", "ns16550a";
reg = <0x40081000 0x1000>;
@@ -185,6 +256,12 @@
interrupts = <24>;
clocks = <&ccu2 CLK_APB0_UART0>, <&ccu1 CLK_CPU_UART0>;
clock-names = "uartclk", "reg";
+ resets = <&rgu 44>;
+ dmas = <&dmamux 1 1 2
+ &dmamux 2 1 2
+ &dmamux 11 2 2
+ &dmamux 12 2 2>;
+ dma-names = "tx", "rx", "tx", "rx";
status = "disabled";
};
@@ -195,6 +272,10 @@
interrupts = <25>;
clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
clock-names = "uartclk", "reg";
+ resets = <&rgu 45>;
+ dmas = <&dmamux 3 1 2
+ &dmamux 4 1 2>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -204,6 +285,10 @@
interrupts = <22>;
clocks = <&ccu2 CLK_APB0_SSP0>, <&ccu1 CLK_CPU_SSP0>;
clock-names = "sspclk", "apb_pclk";
+ resets = <&rgu 50>;
+ dmas = <&dmamux 9 0 2
+ &dmamux 10 0 2>;
+ dma-names = "rx", "tx";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -215,6 +300,7 @@
interrupts = <12>;
clocks = <&ccu1 CLK_CPU_TIMER0>;
clock-names = "timerclk";
+ resets = <&rgu 32>;
};
timer1: timer@40085000 {
@@ -223,6 +309,7 @@
interrupts = <13>;
clocks = <&ccu1 CLK_CPU_TIMER1>;
clock-names = "timerclk";
+ resets = <&rgu 33>;
};
pinctrl: pinctrl@40086000 {
@@ -231,11 +318,23 @@
clocks = <&ccu1 CLK_CPU_SCU>;
};
+ i2c0: i2c@400a1000 {
+ compatible = "nxp,lpc1788-i2c";
+ reg = <0x400a1000 0x1000>;
+ interrupts = <18>;
+ clocks = <&ccu1 CLK_APB1_I2C0>;
+ resets = <&rgu 48>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
can1: can@400a4000 {
compatible = "bosch,c_can";
reg = <0x400a4000 0x1000>;
interrupts = <43>;
clocks = <&ccu1 CLK_APB1_CAN1>;
+ resets = <&rgu 54>;
status = "disabled";
};
@@ -246,6 +345,10 @@
interrupts = <26>;
clocks = <&ccu2 CLK_APB2_UART2>, <&ccu1 CLK_CPU_UART2>;
clock-names = "uartclk", "reg";
+ resets = <&rgu 46>;
+ dmas = <&dmamux 5 1 2
+ &dmamux 6 1 2>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -256,6 +359,12 @@
interrupts = <27>;
clocks = <&ccu2 CLK_APB2_UART3>, <&ccu1 CLK_CPU_UART3>;
clock-names = "uartclk", "reg";
+ resets = <&rgu 47>;
+ dmas = <&dmamux 7 1 2
+ &dmamux 8 1 2
+ &dmamux 13 3 2
+ &dmamux 14 3 2>;
+ dma-names = "tx", "rx", "rx", "tx";
status = "disabled";
};
@@ -265,6 +374,7 @@
interrupts = <14>;
clocks = <&ccu1 CLK_CPU_TIMER2>;
clock-names = "timerclk";
+ resets = <&rgu 34>;
};
timer3: timer@400c4000 {
@@ -273,6 +383,7 @@
interrupts = <15>;
clocks = <&ccu1 CLK_CPU_TIMER3>;
clock-names = "timerclk";
+ resets = <&rgu 35>;
};
ssp1: spi@400c5000 {
@@ -281,6 +392,28 @@
interrupts = <23>;
clocks = <&ccu2 CLK_APB2_SSP1>, <&ccu1 CLK_CPU_SSP1>;
clock-names = "sspclk", "apb_pclk";
+ resets = <&rgu 51>;
+ dmas = <&dmamux 11 2 2
+ &dmamux 12 2 2
+ &dmamux 3 3 2
+ &dmamux 4 3 2
+ &dmamux 5 2 2
+ &dmamux 6 2 2
+ &dmamux 13 2 2
+ &dmamux 14 2 2>;
+ dma-names = "rx", "tx", "tx", "rx",
+ "tx", "rx", "rx", "tx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@400e0000 {
+ compatible = "nxp,lpc1788-i2c";
+ reg = <0x400e0000 0x1000>;
+ interrupts = <19>;
+ clocks = <&ccu1 CLK_APB3_I2C1>;
+ resets = <&rgu 49>;
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
@@ -291,6 +424,7 @@
reg = <0x400e2000 0x1000>;
interrupts = <51>;
clocks = <&ccu1 CLK_APB3_CAN0>;
+ resets = <&rgu 55>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index 32bc7ff..022d495 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -15,6 +15,9 @@
#include "lpc18xx.dtsi"
#include "lpc4350.dtsi"
+#include "dt-bindings/input/input.h"
+#include "dt-bindings/gpio/gpio.h"
+
/ {
model = "Hitex LPC4350 Evaluation Board";
compatible = "hitex,lpc4350-eval-board", "nxp,lpc4350";
@@ -34,6 +37,88 @@
device_type = "memory";
reg = <0x28000000 0x800000>; /* 8 MB */
};
+
+ pca_buttons {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <100>;
+ autorepeat;
+
+ button@0 {
+ label = "joy:right";
+ linux,code = <KEY_RIGHT>;
+ gpios = <&pca_gpio 8 GPIO_ACTIVE_LOW>;
+ };
+
+ button@1 {
+ label = "joy:up";
+ linux,code = <KEY_UP>;
+ gpios = <&pca_gpio 9 GPIO_ACTIVE_LOW>;
+ };
+
+
+ button@2 {
+ label = "joy:enter";
+ linux,code = <KEY_ENTER>;
+ gpios = <&pca_gpio 10 GPIO_ACTIVE_LOW>;
+ };
+
+ button@3 {
+ label = "joy:left";
+ linux,code = <KEY_LEFT>;
+ gpios = <&pca_gpio 11 GPIO_ACTIVE_LOW>;
+ };
+
+ button@4 {
+ label = "joy:down";
+ linux,code = <KEY_DOWN>;
+ gpios = <&pca_gpio 12 GPIO_ACTIVE_LOW>;
+ };
+
+ button@5 {
+ label = "user:sw3";
+ linux,code = <KEY_F1>;
+ gpios = <&pca_gpio 13 GPIO_ACTIVE_LOW>;
+ };
+
+ button@6 {
+ label = "user:sw4";
+ linux,code = <KEY_F2>;
+ gpios = <&pca_gpio 14 GPIO_ACTIVE_LOW>;
+ };
+
+ button@7 {
+ label = "user:sw5";
+ linux,code = <KEY_F3>;
+ gpios = <&pca_gpio 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ pca_leds {
+ compatible = "gpio-leds";
+
+ led0 {
+ label = "ext:led0";
+ gpios = <&pca_gpio 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "heartbeat";
+ };
+
+ led1 {
+ label = "ext:led1";
+ gpios = <&pca_gpio 1 GPIO_ACTIVE_LOW>;
+ };
+
+ led2 {
+ label = "ext:led2";
+ gpios = <&pca_gpio 2 GPIO_ACTIVE_LOW>;
+ };
+
+ led3 {
+ label = "ext:led3";
+ gpios = <&pca_gpio 3 GPIO_ACTIVE_LOW>;
+ };
+ };
};
&pinctrl {
@@ -186,6 +271,43 @@
};
};
+ i2c0_pins: i2c0-pins {
+ i2c0_pins_cfg {
+ pins = "i2c0_scl", "i2c0_sda";
+ function = "i2c0";
+ input-enable;
+ };
+ };
+
+ spifi_pins: spifi-pins {
+ spifi_clk_cfg {
+ pins = "p3_3";
+ function = "spifi";
+ slew-rate = <1>;
+ bias-disable;
+ input-enable;
+ input-schmitt-disable;
+ };
+
+ spifi_mosi_miso_sio2_3_cfg {
+ pins = "p3_7", "p3_6", "p3_5", "p3_4";
+ function = "spifi";
+ slew-rate = <1>;
+ bias-disable;
+ input-enable;
+ input-schmitt-disable;
+ };
+
+ spifi_cs_cfg {
+ pins = "p3_8";
+ function = "spifi";
+ slew-rate = <1>;
+ bias-disable;
+ input-enable;
+ input-schmitt-disable;
+ };
+ };
+
uart0_pins: uart0-pins {
uart0_rx_cfg {
pins = "pf_11";
@@ -271,6 +393,31 @@
clock-frequency = <25000000>;
};
+&i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <400000>;
+
+ /* NXP SE97BTP with temperature sensor + eeprom */
+ sensor@18 {
+ compatible = "nxp,jc42";
+ reg = <0x18>;
+ };
+
+ eeprom@50 {
+ compatible = "nxp,24c02";
+ reg = <0x50>;
+ };
+
+ pca_gpio: gpio@24 {
+ compatible = "nxp,pca9673";
+ reg = <0x24>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
+
&mac {
status = "okay";
phy-mode = "mii";
@@ -278,6 +425,34 @@
pinctrl-0 = <&enet_mii_pins>;
};
+&spifi {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spifi_pins>;
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ spi-rx-bus-width = <4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "bootloader";
+ reg = <0x000000 0x040000>; /* 256 KiB */
+ };
+
+ partition@1 {
+ label = "kernel";
+ reg = <0x040000 0x2c0000>; /* 2.75 MiB */
+ };
+
+ partition@2 {
+ label = "rootfs";
+ reg = <0x300000 0x500000>; /* 5 MiB */
+ };
+ };
+};
+
&uart0 {
status = "okay";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
index 5f7bdad..391121d 100644
--- a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
+++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
@@ -332,6 +332,14 @@
};
};
+ i2c0_pins: i2c0-pins {
+ i2c0_pins_cfg {
+ pins = "i2c0_scl", "i2c0_sda";
+ function = "i2c0";
+ input-enable;
+ };
+ };
+
sdmmc_pins: sdmmc-pins {
sdmmc_clk_cfg {
pins = "pc_0";
@@ -363,6 +371,49 @@
};
};
+ spifi_pins: spifi-pins {
+ spifi_clk_cfg {
+ pins = "p3_3";
+ function = "spifi";
+ slew-rate = <1>;
+ bias-disable;
+ input-enable;
+ input-schmitt-disable;
+ };
+
+ spifi_mosi_miso_sio2_3_cfg {
+ pins = "p3_7", "p3_6", "p3_5", "p3_4";
+ function = "spifi";
+ slew-rate = <0>;
+ bias-disable;
+ input-enable;
+ input-schmitt-disable;
+ };
+
+ spifi_cs_cfg {
+ pins = "p3_8";
+ function = "spifi";
+ bias-disable;
+ };
+ };
+
+ ssp0_pins: ssp0-pins {
+ ssp0_sck_miso_mosi {
+ pins = "pf_0", "pf_2", "pf_3";
+ function = "ssp0";
+ slew-rate = <1>;
+ bias-pull-down;
+ input-enable;
+ input-schmitt-disable;
+ };
+
+ ssp0_ssel {
+ pins = "pf_1";
+ function = "ssp0";
+ bias-pull-up;
+ };
+ };
+
uart0_pins: uart0-pins {
uart0_rx_cfg {
pins = "pf_11";
@@ -410,6 +461,23 @@
};
};
+&i2c0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+ clock-frequency = <400000>;
+
+ lm75@48 {
+ compatible = "nxp,lm75";
+ reg = <0x48>;
+ };
+
+ eeprom@57 {
+ compatible = "microchip,24c64";
+ reg = <0x57>;
+ };
+};
+
&emc {
status = "okay";
pinctrl-names = "default";
@@ -489,6 +557,33 @@
pinctrl-0 = <&sdmmc_pins>;
};
+&spifi {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&spifi_pins>;
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ spi-cpol;
+ spi-cpha;
+ spi-rx-bus-width = <4>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "data";
+ reg = <0 0x200000>;
+ };
+ };
+};
+
+&ssp0 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&ssp0_pins>;
+ num-cs = <1>;
+};
+
&uart0 {
status = "okay";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts
index e008f93..fbb89d1 100644
--- a/arch/arm/boot/dts/ls1021a-twr.dts
+++ b/arch/arm/boot/dts/ls1021a-twr.dts
@@ -144,6 +144,19 @@
&i2c0 {
status = "okay";
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+
};
&i2c1 {
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
index 973a496..9430a99 100644
--- a/arch/arm/boot/dts/ls1021a.dtsi
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -53,6 +53,7 @@
interrupt-parent = <&gic>;
aliases {
+ crypto = &crypto;
ethernet0 = &enet0;
ethernet1 = &enet1;
ethernet2 = &enet2;
@@ -148,6 +149,45 @@
big-endian;
};
+ crypto: crypto@1700000 {
+ compatible = "fsl,sec-v5.0", "fsl,sec-v4.0";
+ fsl,sec-era = <7>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0x0 0x1700000 0x0 0x100000>;
+ ranges = <0x0 0x0 0x1700000 0x100000>;
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+
+ sec_jr0: jr@10000 {
+ compatible = "fsl,sec-v5.0-job-ring",
+ "fsl,sec-v4.0-job-ring";
+ reg = <0x10000 0x10000>;
+ interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ sec_jr1: jr@20000 {
+ compatible = "fsl,sec-v5.0-job-ring",
+ "fsl,sec-v4.0-job-ring";
+ reg = <0x20000 0x10000>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ sec_jr2: jr@30000 {
+ compatible = "fsl,sec-v5.0-job-ring",
+ "fsl,sec-v4.0-job-ring";
+ reg = <0x30000 0x10000>;
+ interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ sec_jr3: jr@40000 {
+ compatible = "fsl,sec-v5.0-job-ring",
+ "fsl,sec-v4.0-job-ring";
+ reg = <0x40000 0x10000>;
+ interrupts = <GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ };
+
clockgen: clocking@1ee1000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -405,6 +445,7 @@
model = "eTSEC";
fsl,magic-packet;
ranges;
+ dma-coherent;
queue-group@2d10000 {
#address-cells = <2>;
@@ -433,6 +474,7 @@
interrupt-parent = <&gic>;
model = "eTSEC";
ranges;
+ dma-coherent;
queue-group@2d50000 {
#address-cells = <2>;
@@ -461,6 +503,7 @@
interrupt-parent = <&gic>;
model = "eTSEC";
ranges;
+ dma-coherent;
queue-group@2d90000 {
#address-cells = <2>;
@@ -494,6 +537,7 @@
reg = <0x0 0x3100000 0x0 0x10000>;
interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
dr_mode = "host";
+ snps,quirk-frame-length-adjustment = <0x20>;
};
};
};
diff --git a/arch/arm/boot/dts/meson8b-mxq.dts b/arch/arm/boot/dts/meson8b-mxq.dts
new file mode 100644
index 0000000..c7fdaea
--- /dev/null
+++ b/arch/arm/boot/dts/meson8b-mxq.dts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "meson8b.dtsi"
+
+/ {
+ model = "TRONFY MXQ S805";
+ compatible = "tronfy,mxq", "amlogic,meson8b";
+
+ aliases {
+ serial0 = &uart_AO;
+ };
+
+ memory {
+ reg = <0x40000000 0x40000000>;
+ };
+};
+
+&uart_AO {
+ status = "okay";
+ pinctrl-0 = <&uart_ao_a_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/meson8b-odroidc1.dts b/arch/arm/boot/dts/meson8b-odroidc1.dts
new file mode 100644
index 0000000..a8e2911
--- /dev/null
+++ b/arch/arm/boot/dts/meson8b-odroidc1.dts
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "meson8b.dtsi"
+
+/ {
+ model = "Hardkernel ODROID-C1";
+ compatible = "hardkernel,odroid-c1", "amlogic,meson8b";
+
+ aliases {
+ serial0 = &uart_AO;
+ };
+
+ memory {
+ reg = <0x40000000 0x40000000>;
+ };
+};
+
+&uart_AO {
+ status = "okay";
+ pinctrl-0 = <&uart_ao_a_pins>;
+ pinctrl-names = "default";
+};
diff --git a/arch/arm/boot/dts/meson8b.dtsi b/arch/arm/boot/dts/meson8b.dtsi
new file mode 100644
index 0000000..ee352bf
--- /dev/null
+++ b/arch/arm/boot/dts/meson8b.dtsi
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2015 Endless Mobile, Inc.
+ * Author: Carlo Caione <carlo@endlessm.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/clock/meson8b-clkc.h>
+#include <dt-bindings/gpio/meson8b-gpio.h>
+#include "skeleton.dtsi"
+
+/ {
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x200>;
+ };
+
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x201>;
+ };
+
+ cpu@202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x202>;
+ };
+
+ cpu@203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ next-level-cache = <&L2>;
+ reg = <0x203>;
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ L2: l2-cache-controller@c4200000 {
+ compatible = "arm,pl310-cache";
+ reg = <0xc4200000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ gic: interrupt-controller@c4301000 {
+ compatible = "arm,cortex-a9-gic";
+ reg = <0xc4301000 0x1000>,
+ <0xc4300100 0x0100>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ };
+
+ timer@c1109940 {
+ compatible = "amlogic,meson6-timer";
+ reg = <0xc1109940 0x18>;
+ interrupts = <0 10 1>;
+ };
+
+ uart_AO: serial@c81004c0 {
+ compatible = "amlogic,meson-uart";
+ reg = <0xc81004c0 0x18>;
+ interrupts = <0 90 1>;
+ clocks = <&clkc CLKID_CLK81>;
+ status = "disabled";
+ };
+
+ uart_A: serial@c11084c0 {
+ compatible = "amlogic,meson-uart";
+ reg = <0xc11084c0 0x18>;
+ interrupts = <0 26 1>;
+ clocks = <&clkc CLKID_CLK81>;
+ status = "disabled";
+ };
+
+ uart_B: serial@c11084dc {
+ compatible = "amlogic,meson-uart";
+ reg = <0xc11084dc 0x18>;
+ interrupts = <0 75 1>;
+ clocks = <&clkc CLKID_CLK81>;
+ status = "disabled";
+ };
+
+ uart_C: serial@c1108700 {
+ compatible = "amlogic,meson-uart";
+ reg = <0xc1108700 0x18>;
+ interrupts = <0 93 1>;
+ clocks = <&clkc CLKID_CLK81>;
+ status = "disabled";
+ };
+
+ clkc: clock-controller@c1104000 {
+ #clock-cells = <1>;
+ compatible = "amlogic,meson8b-clkc";
+ reg = <0xc1108000 0x4>, <0xc1104000 0x460>;
+ };
+
+ pinctrl: pinctrl@c1109880 {
+ compatible = "amlogic,meson8b-pinctrl";
+ reg = <0xc1109880 0x10>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio: banks@c11080b0 {
+ reg = <0xc11080b0 0x28>,
+ <0xc11080e8 0x18>,
+ <0xc1108120 0x18>,
+ <0xc1108030 0x38>;
+ reg-names = "mux", "pull", "pull-enable", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_ao: ao-bank@c1108030 {
+ reg = <0xc8100014 0x4>,
+ <0xc810002c 0x4>,
+ <0xc8100024 0x8>;
+ reg-names = "mux", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart_ao_a_pins: uart_ao_a {
+ mux {
+ groups = "uart_tx_ao_a", "uart_rx_ao_a";
+ function = "uart_ao";
+ };
+ };
+ };
+ };
+}; /* end of / */
diff --git a/arch/arm/boot/dts/mt8127.dtsi b/arch/arm/boot/dts/mt8127.dtsi
index ca3402e..52086c8 100644
--- a/arch/arm/boot/dts/mt8127.dtsi
+++ b/arch/arm/boot/dts/mt8127.dtsi
@@ -23,6 +23,7 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "mediatek,mt81xx-tz-smp";
cpu@0 {
device_type = "cpu";
@@ -47,6 +48,17 @@
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ trustzone-bootinfo@80002000 {
+ compatible = "mediatek,trustzone-bootinfo";
+ reg = <0 0x80002000 0 0x1000>;
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -72,6 +84,21 @@
};
};
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ clock-frequency = <13000000>;
+ arm,cpu-registers-not-fw-configured;
+ };
+
soc {
#address-cells = <2>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/mt8135-evbp1.dts b/arch/arm/boot/dts/mt8135-evbp1.dts
index 357a91f..460db6d 100644
--- a/arch/arm/boot/dts/mt8135-evbp1.dts
+++ b/arch/arm/boot/dts/mt8135-evbp1.dts
@@ -32,7 +32,6 @@
compatible = "mediatek,mt6397-regulator";
mt6397_vpca15_reg: buck_vpca15 {
- regulator-compatible = "buck_vpca15";
regulator-name = "vpca15";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1350000>;
@@ -41,7 +40,6 @@
};
mt6397_vpca7_reg: buck_vpca7 {
- regulator-compatible = "buck_vpca7";
regulator-name = "vpca7";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1350000>;
@@ -50,7 +48,6 @@
};
mt6397_vsramca15_reg: buck_vsramca15 {
- regulator-compatible = "buck_vsramca15";
regulator-name = "vsramca15";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1350000>;
@@ -59,7 +56,6 @@
};
mt6397_vsramca7_reg: buck_vsramca7 {
- regulator-compatible = "buck_vsramca7";
regulator-name = "vsramca7";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1350000>;
@@ -68,7 +64,6 @@
};
mt6397_vcore_reg: buck_vcore {
- regulator-compatible = "buck_vcore";
regulator-name = "vcore";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1350000>;
@@ -77,7 +72,6 @@
};
mt6397_vgpu_reg: buck_vgpu {
- regulator-compatible = "buck_vgpu";
regulator-name = "vgpu";
regulator-min-microvolt = < 700000>;
regulator-max-microvolt = <1350000>;
@@ -86,7 +80,6 @@
};
mt6397_vdrm_reg: buck_vdrm {
- regulator-compatible = "buck_vdrm";
regulator-name = "vdrm";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <1400000>;
@@ -95,7 +88,6 @@
};
mt6397_vio18_reg: buck_vio18 {
- regulator-compatible = "buck_vio18";
regulator-name = "vio18";
regulator-min-microvolt = <1620000>;
regulator-max-microvolt = <1980000>;
@@ -104,19 +96,16 @@
};
mt6397_vtcxo_reg: ldo_vtcxo {
- regulator-compatible = "ldo_vtcxo";
regulator-name = "vtcxo";
regulator-always-on;
};
mt6397_va28_reg: ldo_va28 {
- regulator-compatible = "ldo_va28";
regulator-name = "va28";
regulator-always-on;
};
mt6397_vcama_reg: ldo_vcama {
- regulator-compatible = "ldo_vcama";
regulator-name = "vcama";
regulator-min-microvolt = <1500000>;
regulator-max-microvolt = <2800000>;
@@ -124,18 +113,15 @@
};
mt6397_vio28_reg: ldo_vio28 {
- regulator-compatible = "ldo_vio28";
regulator-name = "vio28";
regulator-always-on;
};
mt6397_vusb_reg: ldo_vusb {
- regulator-compatible = "ldo_vusb";
regulator-name = "vusb";
};
mt6397_vmc_reg: ldo_vmc {
- regulator-compatible = "ldo_vmc";
regulator-name = "vmc";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
@@ -143,7 +129,6 @@
};
mt6397_vmch_reg: ldo_vmch {
- regulator-compatible = "ldo_vmch";
regulator-name = "vmch";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3300000>;
@@ -151,7 +136,6 @@
};
mt6397_vemc_3v3_reg: ldo_vemc3v3 {
- regulator-compatible = "ldo_vemc3v3";
regulator-name = "vemc_3v3";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3300000>;
@@ -159,7 +143,6 @@
};
mt6397_vgp1_reg: ldo_vgp1 {
- regulator-compatible = "ldo_vgp1";
regulator-name = "vcamd";
regulator-min-microvolt = <1220000>;
regulator-max-microvolt = <3300000>;
@@ -167,7 +150,6 @@
};
mt6397_vgp2_reg: ldo_vgp2 {
- regulator-compatible = "ldo_vgp2";
regulator-name = "vcamio";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <3300000>;
@@ -175,7 +157,6 @@
};
mt6397_vgp3_reg: ldo_vgp3 {
- regulator-compatible = "ldo_vgp3";
regulator-name = "vcamaf";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3300000>;
@@ -183,7 +164,6 @@
};
mt6397_vgp4_reg: ldo_vgp4 {
- regulator-compatible = "ldo_vgp4";
regulator-name = "vgp4";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3300000>;
@@ -191,7 +171,6 @@
};
mt6397_vgp5_reg: ldo_vgp5 {
- regulator-compatible = "ldo_vgp5";
regulator-name = "vgp5";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3000000>;
@@ -199,7 +178,6 @@
};
mt6397_vgp6_reg: ldo_vgp6 {
- regulator-compatible = "ldo_vgp6";
regulator-name = "vgp6";
regulator-min-microvolt = <1200000>;
regulator-max-microvolt = <3300000>;
@@ -207,7 +185,6 @@
};
mt6397_vibr_reg: ldo_vibr {
- regulator-compatible = "ldo_vibr";
regulator-name = "vibr";
regulator-min-microvolt = <1300000>;
regulator-max-microvolt = <3300000>;
diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
index 08371db..cb99b02 100644
--- a/arch/arm/boot/dts/mt8135.dtsi
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -46,6 +46,7 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "mediatek,mt81xx-tz-smp";
cpu0: cpu@0 {
device_type = "cpu";
@@ -72,6 +73,17 @@
};
};
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ trustzone-bootinfo@80002000 {
+ compatible = "mediatek,trustzone-bootinfo";
+ reg = <0 0x80002000 0 0x1000>;
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -97,6 +109,21 @@
};
};
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) |
+ IRQ_TYPE_LEVEL_LOW)>;
+ clock-frequency = <13000000>;
+ arm,cpu-registers-not-fw-configured;
+ };
+
soc {
#address-cells = <2>;
#size-cells = <2>;
diff --git a/arch/arm/boot/dts/nspire.dtsi b/arch/arm/boot/dts/nspire.dtsi
index 390c91a..ee5a0bb 100644
--- a/arch/arm/boot/dts/nspire.dtsi
+++ b/arch/arm/boot/dts/nspire.dtsi
@@ -16,7 +16,7 @@
cpus {
cpu@0 {
- compatible = "arm,arm926ejs";
+ compatible = "arm,arm926ej-s";
};
};
diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index c9f1e93..8491f46 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -9,9 +9,9 @@
ocp {
i2c@0 {
compatible = "i2c-cbus-gpio";
- gpios = <&gpio3 2 0 /* gpio66 clk */
- &gpio3 1 0 /* gpio65 dat */
- &gpio3 0 0 /* gpio64 sel */
+ gpios = <&gpio3 2 GPIO_ACTIVE_HIGH /* gpio66 clk */
+ &gpio3 1 GPIO_ACTIVE_HIGH /* gpio65 dat */
+ &gpio3 0 GPIO_ACTIVE_HIGH /* gpio64 sel */
>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 7c4dca1..73f1e3a 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -80,7 +80,7 @@
regulator-name = "hsusb2_vbus";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&twl_gpio 18 0>; /* GPIO LEDA */
+ gpio = <&twl_gpio 18 GPIO_ACTIVE_HIGH>; /* GPIO LEDA */
startup-delay-us = <70000>;
};
diff --git a/arch/arm/boot/dts/omap3-beagle.dts b/arch/arm/boot/dts/omap3-beagle.dts
index 67659a0..274c2c4 100644
--- a/arch/arm/boot/dts/omap3-beagle.dts
+++ b/arch/arm/boot/dts/omap3-beagle.dts
@@ -55,7 +55,7 @@
regulator-name = "hsusb2_vbus";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&twl_gpio 18 0>; /* GPIO LEDA */
+ gpio = <&twl_gpio 18 GPIO_ACTIVE_HIGH>; /* GPIO LEDA */
startup-delay-us = <70000>;
};
diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
index 4d091ca..8c813e7 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -224,7 +224,7 @@
interrupt-parent = <&gpio2>;
interrupts = <25 0>; /* gpio_57 */
- pendown-gpio = <&gpio2 25 0>;
+ pendown-gpio = <&gpio2 25 GPIO_ACTIVE_HIGH>;
ti,x-min = /bits/ 16 <0x0>;
ti,x-max = /bits/ 16 <0x0fff>;
diff --git a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
index e84184d..4813e96 100644
--- a/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
+++ b/arch/arm/boot/dts/omap3-devkit8000-lcd-common.dtsi
@@ -54,7 +54,7 @@
interrupt-parent = <&gpio1>;
interrupts = <27 0>; /* gpio_27 */
- pendown-gpio = <&gpio1 27 0>;
+ pendown-gpio = <&gpio1 27 GPIO_ACTIVE_HIGH>;
ti,x-min = /bits/ 16 <0x0>;
ti,x-max = /bits/ 16 <0x0fff>;
diff --git a/arch/arm/boot/dts/omap3-evm-common.dtsi b/arch/arm/boot/dts/omap3-evm-common.dtsi
index b2589f9..0904750 100644
--- a/arch/arm/boot/dts/omap3-evm-common.dtsi
+++ b/arch/arm/boot/dts/omap3-evm-common.dtsi
@@ -26,7 +26,7 @@
regulator-name = "vwl1271";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- gpio = <&gpio5 22 0>; /* gpio150 */
+ gpio = <&gpio5 22 GPIO_ACTIVE_HIGH>; /* gpio150 */
startup-delay-us = <70000>;
enable-active-high;
vin-supply = <&vmmc2>;
@@ -91,7 +91,7 @@
tsc2046@0 {
interrupt-parent = <&gpio6>;
interrupts = <15 0>; /* gpio175 */
- pendown-gpio = <&gpio6 15 0>;
+ pendown-gpio = <&gpio6 15 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index 7166d88..e14d15e 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -77,10 +77,10 @@
pinctrl-names = "default";
pinctrl-0 = <&spi_gpio_pins>;
- gpio-sck = <&gpio1 12 0>;
- gpio-miso = <&gpio1 18 0>;
- gpio-mosi = <&gpio1 20 0>;
- cs-gpios = <&gpio1 19 0>;
+ gpio-sck = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+ gpio-miso = <&gpio1 18 GPIO_ACTIVE_HIGH>;
+ gpio-mosi = <&gpio1 20 GPIO_ACTIVE_HIGH>;
+ cs-gpios = <&gpio1 19 GPIO_ACTIVE_HIGH>;
num-chipselects = <1>;
/* lcd panel */
@@ -118,7 +118,7 @@
tv_amp: opa362 {
compatible = "ti,opa362";
- enable-gpios = <&gpio1 23 0>;
+ enable-gpios = <&gpio1 23 GPIO_ACTIVE_HIGH>;
ports {
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/omap3-gta04a5.dts b/arch/arm/boot/dts/omap3-gta04a5.dts
index 52b386f..600b6ca 100644
--- a/arch/arm/boot/dts/omap3-gta04a5.dts
+++ b/arch/arm/boot/dts/omap3-gta04a5.dts
@@ -12,6 +12,6 @@
model = "Goldelico GTA04A5";
sound {
- ti,jack-det-gpio = <&twl_gpio 2 0>; /* GTA04A5 only */
+ ti,jack-det-gpio = <&twl_gpio 2 GPIO_ACTIVE_HIGH>; /* GTA04A5 only */
};
};
diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi
index 2230e1c..3caf062 100644
--- a/arch/arm/boot/dts/omap3-igep.dtsi
+++ b/arch/arm/boot/dts/omap3-igep.dtsi
@@ -1,7 +1,7 @@
/*
* Common device tree for IGEP boards based on AM/DM37x
*
- * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -35,60 +35,60 @@
&omap3_pmx_core {
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x152 (PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
- 0x14c (PIN_OUTPUT |MUX_MODE0) /* uart1_tx.uart1_tx */
+ OMAP3_CORE1_IOPAD(0x2182, PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
+ OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx.uart3_rx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx.uart3_tx */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx.uart3_rx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx.uart3_tx */
>;
};
mcbsp2_pins: pinmux_mcbsp2_pins {
pinctrl-single,pins = <
- 0x10c (PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx.mcbsp2_fsx */
- 0x10e (PIN_INPUT | MUX_MODE0) /* mcbsp2_clkx.mcbsp2_clkx */
- 0x110 (PIN_INPUT | MUX_MODE0) /* mcbsp2_dr.mcbsp2.dr */
- 0x112 (PIN_OUTPUT | MUX_MODE0) /* mcbsp2_dx.mcbsp2_dx */
+ OMAP3_CORE1_IOPAD(0x213c, PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx.mcbsp2_fsx */
+ OMAP3_CORE1_IOPAD(0x213e, PIN_INPUT | MUX_MODE0) /* mcbsp2_clkx.mcbsp2_clkx */
+ OMAP3_CORE1_IOPAD(0x2140, PIN_INPUT | MUX_MODE0) /* mcbsp2_dr.mcbsp2.dr */
+ OMAP3_CORE1_IOPAD(0x2142, PIN_OUTPUT | MUX_MODE0) /* mcbsp2_dx.mcbsp2_dx */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x114 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
- 0x116 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
- 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
- 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
- 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
>;
};
mmc2_pins: pinmux_mmc2_pins {
pinctrl-single,pins = <
- 0x128 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
- 0x12a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
- 0x12c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
- 0x12e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
- 0x130 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
- 0x132 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
+ OMAP3_CORE1_IOPAD(0x2158, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_clk.sdmmc2_clk */
+ OMAP3_CORE1_IOPAD(0x215a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_cmd.sdmmc2_cmd */
+ OMAP3_CORE1_IOPAD(0x215c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat0.sdmmc2_dat0 */
+ OMAP3_CORE1_IOPAD(0x215e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat1.sdmmc2_dat1 */
+ OMAP3_CORE1_IOPAD(0x2160, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat2.sdmmc2_dat2 */
+ OMAP3_CORE1_IOPAD(0x2162, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc2_dat3.sdmmc2_dat3 */
>;
};
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
- 0x18a (PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */
- 0x18c (PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */
+ OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */
+ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT | MUX_MODE0) /* i2c1_sda.i2c1_sda */
>;
};
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
- 0x192 (PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */
- 0x194 (PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */
+ OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */
+ OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT | MUX_MODE0) /* i2c3_sda.i2c3_sda */
>;
};
};
@@ -155,7 +155,7 @@
twl_audio: audio {
compatible = "ti,twl4030-audio";
codec {
- };
+ };
};
};
};
@@ -175,11 +175,11 @@
};
&mmc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc1_pins>;
- vmmc-supply = <&vmmc1>;
- vmmc_aux-supply = <&vsim>;
- bus-width = <4>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ vmmc-supply = <&vmmc1>;
+ vmmc_aux-supply = <&vsim>;
+ bus-width = <4>;
};
&mmc3 {
@@ -187,13 +187,13 @@
};
&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
};
&uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
};
&twl_gpio {
diff --git a/arch/arm/boot/dts/omap3-igep0020-common.dtsi b/arch/arm/boot/dts/omap3-igep0020-common.dtsi
index 5ad688c..d90f12c 100644
--- a/arch/arm/boot/dts/omap3-igep0020-common.dtsi
+++ b/arch/arm/boot/dts/omap3-igep0020-common.dtsi
@@ -1,7 +1,7 @@
/*
* Common Device Tree Source for IGEPv2
*
- * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -111,40 +111,40 @@
tfp410_pins: pinmux_tfp410_pins {
pinctrl-single,pins = <
- 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
+ OMAP3_CORE1_IOPAD(0x21c6, PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
>;
};
dss_dpi_pins: pinmux_dss_dpi_pins {
pinctrl-single,pins = <
- 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
- 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
- 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
- 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
- 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
- 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
- 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
- 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
- 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
- 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
- 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
- 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
- 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
- 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
- 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
- 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
- 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
- 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
- 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
- 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
- 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
- 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
- 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
- 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
- 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
- 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
- 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
- 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
+ OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
+ OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
>;
};
diff --git a/arch/arm/boot/dts/omap3-igep0020-rev-f.dts b/arch/arm/boot/dts/omap3-igep0020-rev-f.dts
index 72f7cdc..321c2b7 100644
--- a/arch/arm/boot/dts/omap3-igep0020-rev-f.dts
+++ b/arch/arm/boot/dts/omap3-igep0020-rev-f.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for IGEPv2 Rev. F (TI OMAP AM/DM37x)
*
- * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index fea7f7e..3835e15 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for IGEPv2 Rev. C (TI OMAP AM/DM37x)
*
- * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -45,15 +45,6 @@
OMAP3_CORE1_IOPAD(0x216a, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 - RST_N_B */
>;
};
-
- uart2_pins: pinmux_uart2_pins {
- pinctrl-single,pins = <
- OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT | MUX_MODE0) /* uart2_cts.uart2_cts */
- OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts .uart2_rts*/
- OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
- OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
- >;
- };
};
/* On board Wifi module */
diff --git a/arch/arm/boot/dts/omap3-igep0030-common.dtsi b/arch/arm/boot/dts/omap3-igep0030-common.dtsi
index 0cb1527..640f066 100644
--- a/arch/arm/boot/dts/omap3-igep0030-common.dtsi
+++ b/arch/arm/boot/dts/omap3-igep0030-common.dtsi
@@ -1,7 +1,7 @@
/*
* Common Device Tree Source for IGEP COM MODULE
*
- * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/boot/dts/omap3-igep0030-rev-g.dts b/arch/arm/boot/dts/omap3-igep0030-rev-g.dts
index b899e34..76dc088 100644
--- a/arch/arm/boot/dts/omap3-igep0030-rev-g.dts
+++ b/arch/arm/boot/dts/omap3-igep0030-rev-g.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for IGEP COM MODULE Rev. G (TI OMAP AM/DM37x)
*
- * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 8150f47..468608da 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -1,7 +1,7 @@
/*
* Device Tree Source for IGEP COM MODULE Rev. E (TI OMAP AM/DM37x)
*
- * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@osg.samsung.com>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index bd6e676..d2fab8c 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -200,7 +200,7 @@
tsc2046@0 {
interrupt-parent = <&gpio2>;
interrupts = <22 0>; /* gpio54 */
- pendown-gpio = <&gpio2 22 0>;
+ pendown-gpio = <&gpio2 22 GPIO_ACTIVE_HIGH>;
};
};
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index d0dd036..57d7c93 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -284,7 +284,7 @@
};
&mmc1 {
- cd-gpios = <&gpio4 30 IRQ_TYPE_LEVEL_LOW>;
+ cd-gpios = <&gpio4 30 GPIO_ACTIVE_LOW>;
cd-inverted;
vmmc-supply = <&vmmc1>;
bus-width = <4>;
@@ -314,7 +314,7 @@
interrupt-parent = <&gpio1>;
interrupts = <8 0>; /* boot6 / gpio_8 */
spi-max-frequency = <1000000>;
- pendown-gpio = <&gpio1 8 0>;
+ pendown-gpio = <&gpio1 8 GPIO_ACTIVE_HIGH>;
vcc-supply = <&reg_vcc3>;
pinctrl-names = "default";
pinctrl-0 = <&tsc2048_pins>;
diff --git a/arch/arm/boot/dts/omap3-lilly-dbb056.dts b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
index 834f7c6..0e3c981 100644
--- a/arch/arm/boot/dts/omap3-lilly-dbb056.dts
+++ b/arch/arm/boot/dts/omap3-lilly-dbb056.dts
@@ -114,8 +114,8 @@
status = "okay";
bus-width = <4>;
vmmc-supply = <&vmmc1>;
- cd-gpios = <&gpio6 4 0>; /* gpio_164 */
- wp-gpios = <&gpio6 3 0>; /* gpio_163 */
+ cd-gpios = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* gpio_164 */
+ wp-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* gpio_163 */
pinctrl-names = "default";
pinctrl-0 = <&mmc2_pins>;
ti,dual-volt;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 800b379..e9ee1df 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -27,7 +27,7 @@
regulator-name = "VEMMC";
regulator-min-microvolt = <2900000>;
regulator-max-microvolt = <2900000>;
- gpio = <&gpio5 29 0>; /* gpio line 157 */
+ gpio = <&gpio5 29 GPIO_ACTIVE_HIGH>; /* gpio line 157 */
startup-delay-us = <150>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/omap3-overo-base.dtsi b/arch/arm/boot/dts/omap3-overo-base.dtsi
index 28430f1..a29ad16 100644
--- a/arch/arm/boot/dts/omap3-overo-base.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-base.dtsi
@@ -35,7 +35,7 @@
regulator-name = "hsusb2_vbus";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gpio6 8 0>; /* gpio_168: vbus enable */
+ gpio = <&gpio6 8 GPIO_ACTIVE_HIGH>; /* gpio_168: vbus enable */
startup-delay-us = <70000>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
index 80d236a..b09cedf 100644
--- a/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-common-lcd35.dtsi
@@ -152,7 +152,7 @@
interrupt-parent = <&gpio4>;
interrupts = <18 0>; /* gpio_114 */
- pendown-gpio = <&gpio4 18 0>;
+ pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
ti,x-min = /bits/ 16 <0x0>;
ti,x-max = /bits/ 16 <0x0fff>;
diff --git a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
index 048fd21..5f97959 100644
--- a/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
+++ b/arch/arm/boot/dts/omap3-overo-common-lcd43.dtsi
@@ -163,7 +163,7 @@
interrupt-parent = <&gpio4>;
interrupts = <18 0>; /* gpio_114 */
- pendown-gpio = <&gpio4 18 0>;
+ pendown-gpio = <&gpio4 18 GPIO_ACTIVE_HIGH>;
ti,x-min = /bits/ 16 <0x0>;
ti,x-max = /bits/ 16 <0x0fff>;
diff --git a/arch/arm/boot/dts/omap3-pandora-common.dtsi b/arch/arm/boot/dts/omap3-pandora-common.dtsi
index f2084e6..cfe140c 100644
--- a/arch/arm/boot/dts/omap3-pandora-common.dtsi
+++ b/arch/arm/boot/dts/omap3-pandora-common.dtsi
@@ -218,7 +218,7 @@
regulator-always-on;
regulator-boot-on;
enable-active-high;
- gpio = <&gpio6 4 0>; /* GPIO_164 */
+ gpio = <&gpio6 4 GPIO_ACTIVE_HIGH>; /* GPIO_164 */
};
/* wg7210 (wifi+bt module) 32k clock buffer */
@@ -607,7 +607,7 @@
pinctrl-0 = <&penirq_pins>;
interrupt-parent = <&gpio3>;
interrupts = <30 0>; /* GPIO_94 */
- pendown-gpio = <&gpio3 30 0>;
+ pendown-gpio = <&gpio3 30 GPIO_ACTIVE_HIGH>;
vcc-supply = <&vaux4>;
ti,x-min = /bits/ 16 <0>;
diff --git a/arch/arm/boot/dts/omap3-tao3530.dtsi b/arch/arm/boot/dts/omap3-tao3530.dtsi
index 7bd8d9a..ae5dbbd 100644
--- a/arch/arm/boot/dts/omap3-tao3530.dtsi
+++ b/arch/arm/boot/dts/omap3-tao3530.dtsi
@@ -37,7 +37,7 @@
regulator-name = "hsusb2_vbus";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&twl_gpio 18 0>; /* GPIO LEDA */
+ gpio = <&twl_gpio 18 GPIO_ACTIVE_HIGH>; /* GPIO LEDA */
startup-delay-us = <70000>;
};
@@ -225,7 +225,7 @@
pinctrl-0 = <&mmc1_pins>;
vmmc-supply = <&vmmc1>;
vmmc_aux-supply = <&vsim>;
- cd-gpios = <&twl_gpio 0 0>;
+ cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_HIGH>;
bus-width = <8>;
};
diff --git a/arch/arm/boot/dts/omap3-zoom3.dts b/arch/arm/boot/dts/omap3-zoom3.dts
index 131448d..7bc5fdd 100644
--- a/arch/arm/boot/dts/omap3-zoom3.dts
+++ b/arch/arm/boot/dts/omap3-zoom3.dts
@@ -44,7 +44,7 @@
regulator-name = "vwl1271";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- gpio = <&gpio4 5 0>; /* gpio101 */
+ gpio = <&gpio4 5 GPIO_ACTIVE_HIGH>; /* gpio101 */
startup-delay-us = <70000>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
index 1a78f01..b75f7b2 100644
--- a/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -189,3 +189,7 @@
};
};
+&uart3 {
+ interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH
+ &omap4_pmx_core OMAP4_UART3_RX>;
+};
diff --git a/arch/arm/boot/dts/omap4-panda-common.dtsi b/arch/arm/boot/dts/omap4-panda-common.dtsi
index f1507bc..18d0966 100644
--- a/arch/arm/boot/dts/omap4-panda-common.dtsi
+++ b/arch/arm/boot/dts/omap4-panda-common.dtsi
@@ -68,7 +68,7 @@
regulator-name = "hsusb1_vbus";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio1 1 0>; /* gpio_1 */
+ gpio = <&gpio1 1 GPIO_ACTIVE_HIGH>; /* gpio_1 */
startup-delay-us = <70000>;
enable-active-high;
/*
@@ -98,7 +98,7 @@
regulator-name = "vwl1271";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- gpio = <&gpio2 11 0>;
+ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>;
startup-delay-us = <70000>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index dac86ed..f0bdc41 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -30,7 +30,7 @@
regulator-name = "VDD_ETH";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- gpio = <&gpio2 16 0>; /* gpio line 48 */
+ gpio = <&gpio2 16 GPIO_ACTIVE_HIGH>; /* gpio line 48 */
enable-active-high;
regulator-boot-on;
};
@@ -155,7 +155,7 @@
regulator-name = "vwl1271";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- gpio = <&gpio2 22 0>;
+ gpio = <&gpio2 22 GPIO_ACTIVE_HIGH>;
startup-delay-us = <70000>;
enable-active-high;
};
@@ -374,7 +374,7 @@
/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
- ti,audpwron-gpio = <&gpio4 31 0>; /* gpio line 127 */
+ ti,audpwron-gpio = <&gpio4 31 GPIO_ACTIVE_HIGH>; /* gpio line 127 */
vio-supply = <&v1v8>;
v2v1-supply = <&v2v1>;
diff --git a/arch/arm/boot/dts/omap4-var-som-om44-wlan.dtsi b/arch/arm/boot/dts/omap4-var-som-om44-wlan.dtsi
index 9bceeb7..1c5f6f3 100644
--- a/arch/arm/boot/dts/omap4-var-som-om44-wlan.dtsi
+++ b/arch/arm/boot/dts/omap4-var-som-om44-wlan.dtsi
@@ -15,7 +15,7 @@
regulator-name = "vwl1271";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
- gpio = <&gpio2 11 0>; /* gpio 43 */
+ gpio = <&gpio2 11 GPIO_ACTIVE_HIGH>; /* gpio 43 */
startup-delay-us = <70000>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/omap4-var-som-om44.dtsi b/arch/arm/boot/dts/omap4-var-som-om44.dtsi
index a4f1ba2..49d032b 100644
--- a/arch/arm/boot/dts/omap4-var-som-om44.dtsi
+++ b/arch/arm/boot/dts/omap4-var-som-om44.dtsi
@@ -196,7 +196,7 @@
/* SPI = 0, IRQ# = 119, 4 = active high level-sensitive */
interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; /* IRQ_SYS_2N cascaded to gic */
- ti,audpwron-gpio = <&gpio6 22 0>; /* gpio 182 */
+ ti,audpwron-gpio = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* gpio 182 */
vio-supply = <&v1v8>;
v2v1-supply = <&v2v1>;
diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi
index 194f9ef..5fa68f19 100644
--- a/arch/arm/boot/dts/omap4460.dtsi
+++ b/arch/arm/boot/dts/omap4460.dtsi
@@ -46,7 +46,7 @@
0x4a002378 0x18>;
compatible = "ti,omap4460-bandgap";
interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>; /* talert */
- gpios = <&gpio3 22 0>; /* tshut */
+ gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>; /* tshut */
#thermal-sensor-cells = <0>;
};
diff --git a/arch/arm/boot/dts/omap5-board-common.dtsi b/arch/arm/boot/dts/omap5-board-common.dtsi
new file mode 100644
index 0000000..5cf76a1
--- /dev/null
+++ b/arch/arm/boot/dts/omap5-board-common.dtsi
@@ -0,0 +1,655 @@
+/*
+ * Copyright (C) 2013 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "omap5.dtsi"
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ aliases {
+ display0 = &hdmi0;
+ };
+
+ vmmcsd_fixed: fixedregulator-mmcsd {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
+
+ mmc3_pwrseq: sdhci0_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ clocks = <&clk32kgaudio>;
+ clock-names = "ext_clock";
+ };
+
+ vmmcsdio_fixed: fixedregulator-mmcsdio {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsdio_fixed";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ gpio = <&gpio5 12 GPIO_ACTIVE_HIGH>; /* gpio140 WLAN_EN */
+ enable-active-high;
+ startup-delay-us = <70000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_pins>;
+ };
+
+ /* HS USB Host PHY on PORT 2 */
+ hsusb2_phy: hsusb2_phy {
+ compatible = "usb-nop-xceiv";
+ reset-gpios = <&gpio3 16 GPIO_ACTIVE_LOW>; /* gpio3_80 HUB_NRESET */
+ clocks = <&auxclk1_ck>;
+ clock-names = "main_clk";
+ clock-frequency = <19200000>;
+ };
+
+ /* HS USB Host PHY on PORT 3 */
+ hsusb3_phy: hsusb3_phy {
+ compatible = "usb-nop-xceiv";
+ reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; /* gpio3_79 ETH_NRESET */
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ led@1 {
+ label = "omap5:blue:usr1";
+ gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>; /* gpio5_153 D1 LED */
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+ };
+
+ tpd12s015: encoder@0 {
+ compatible = "ti,tpd12s015";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tpd12s015_pins>;
+
+ /* gpios defined in the board specific dts */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tpd12s015_in: endpoint@0 {
+ remote-endpoint = <&hdmi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tpd12s015_out: endpoint@0 {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
+ };
+
+ hdmi0: connector@0 {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+
+ type = "b";
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&tpd12s015_out>;
+ };
+ };
+ };
+
+ sound: sound {
+ compatible = "ti,abe-twl6040";
+ ti,model = "omap5-uevm";
+
+ ti,mclk-freq = <19200000>;
+
+ ti,mcpdm = <&mcpdm>;
+
+ ti,twl6040 = <&twl6040>;
+
+ /* Audio routing */
+ ti,audio-routing =
+ "Headset Stereophone", "HSOL",
+ "Headset Stereophone", "HSOR",
+ "Line Out", "AUXL",
+ "Line Out", "AUXR",
+ "HSMIC", "Headset Mic",
+ "Headset Mic", "Headset Mic Bias",
+ "AFML", "Line In",
+ "AFMR", "Line In";
+ };
+};
+
+&omap5_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &usbhost_pins
+ &led_gpio_pins
+ >;
+
+ twl6040_pins: pinmux_twl6040_pins {
+ pinctrl-single,pins = <
+ 0x17e (PIN_OUTPUT | MUX_MODE6) /* mcspi1_somi.gpio5_141 */
+ >;
+ };
+
+ mcpdm_pins: pinmux_mcpdm_pins {
+ pinctrl-single,pins = <
+ 0x142 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
+ 0x15c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_ul_data.abemcpdm_ul_data */
+ 0x15e (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_dl_data.abemcpdm_dl_data */
+ 0x160 (PIN_INPUT_PULLUP | MUX_MODE0) /* abemcpdm_frame.abemcpdm_frame */
+ 0x162 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_lb_clk.abemcpdm_lb_clk */
+ >;
+ };
+
+ mcbsp1_pins: pinmux_mcbsp1_pins {
+ pinctrl-single,pins = <
+ 0x14c (PIN_INPUT | MUX_MODE1) /* abedmic_clk2.abemcbsp1_fsx */
+ 0x14e (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* abedmic_clk3.abemcbsp1_dx */
+ 0x150 (PIN_INPUT | MUX_MODE1) /* abeslimbus1_clock.abemcbsp1_clkx */
+ 0x152 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* abeslimbus1_data.abemcbsp1_dr */
+ >;
+ };
+
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ 0x154 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dr.abemcbsp2_dr */
+ 0x156 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dx.abemcbsp2_dx */
+ 0x158 (PIN_INPUT | MUX_MODE0) /* abemcbsp2_fsx.abemcbsp2_fsx */
+ 0x15a (PIN_INPUT | MUX_MODE0) /* abemcbsp2_clkx.abemcbsp2_clkx */
+ >;
+ };
+
+ i2c1_pins: pinmux_i2c1_pins {
+ pinctrl-single,pins = <
+ 0x1b2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ 0x1b4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ >;
+ };
+
+ mcspi2_pins: pinmux_mcspi2_pins {
+ pinctrl-single,pins = <
+ 0xbc (PIN_INPUT | MUX_MODE0) /* mcspi2_clk */
+ 0xbe (PIN_INPUT | MUX_MODE0) /* mcspi2_simo */
+ 0xc0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mcspi2_somi */
+ 0xc2 (PIN_OUTPUT | MUX_MODE0) /* mcspi2_cs0 */
+ >;
+ };
+
+ mcspi3_pins: pinmux_mcspi3_pins {
+ pinctrl-single,pins = <
+ 0x78 (PIN_INPUT | MUX_MODE1) /* mcspi3_somi */
+ 0x7a (PIN_INPUT | MUX_MODE1) /* mcspi3_cs0 */
+ 0x7c (PIN_INPUT | MUX_MODE1) /* mcspi3_simo */
+ 0x7e (PIN_INPUT | MUX_MODE1) /* mcspi3_clk */
+ >;
+ };
+
+ mmc3_pins: pinmux_mmc3_pins {
+ pinctrl-single,pins = <
+ OMAP5_IOPAD(0x01a4, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_clk */
+ OMAP5_IOPAD(0x01a6, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_cmd */
+ OMAP5_IOPAD(0x01a8, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_data0 */
+ OMAP5_IOPAD(0x01aa, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_data1 */
+ OMAP5_IOPAD(0x01ac, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_data2 */
+ OMAP5_IOPAD(0x01ae, PIN_INPUT_PULLUP | MUX_MODE0) /* wlsdio_data3 */
+ >;
+ };
+
+ wlan_pins: pinmux_wlan_pins {
+ pinctrl-single,pins = <
+ OMAP5_IOPAD(0x1bc, PIN_OUTPUT | MUX_MODE6) /* mcspi1_clk.gpio5_140 */
+ >;
+ };
+
+ usbhost_pins: pinmux_usbhost_pins {
+ pinctrl-single,pins = <
+ 0x84 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
+ 0x86 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_data */
+
+ 0x19e (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_strobe */
+ 0x1a0 (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_data */
+
+ 0x70 (PIN_OUTPUT | MUX_MODE6) /* gpio3_80 HUB_NRESET */
+ 0x6e (PIN_OUTPUT | MUX_MODE6) /* gpio3_79 ETH_NRESET */
+ >;
+ };
+
+ led_gpio_pins: pinmux_led_gpio_pins {
+ pinctrl-single,pins = <
+ 0x196 (PIN_OUTPUT | MUX_MODE6) /* uart3_cts_rctx.gpio5_153 */
+ >;
+ };
+
+ uart1_pins: pinmux_uart1_pins {
+ pinctrl-single,pins = <
+ 0x60 (PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_cts */
+ 0x62 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_tx.uart1_cts */
+ 0x64 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rx.uart1_rts */
+ 0x66 (PIN_OUTPUT | MUX_MODE0) /* uart1_rx.uart1_rts */
+ >;
+ };
+
+ uart3_pins: pinmux_uart3_pins {
+ pinctrl-single,pins = <
+ 0x19a (PIN_OUTPUT | MUX_MODE0) /* uart3_rts_irsd.uart3_tx_irtx */
+ 0x19c (PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_rx_irrx.uart3_usbb3_hsic */
+ >;
+ };
+
+ uart5_pins: pinmux_uart5_pins {
+ pinctrl-single,pins = <
+ 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_rx.uart5_rx */
+ 0x172 (PIN_OUTPUT | MUX_MODE0) /* uart5_tx.uart5_tx */
+ 0x174 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_cts.uart5_rts */
+ 0x176 (PIN_OUTPUT | MUX_MODE0) /* uart5_cts.uart5_rts */
+ >;
+ };
+
+ dss_hdmi_pins: pinmux_dss_hdmi_pins {
+ pinctrl-single,pins = <
+ 0x0fc (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
+ 0x100 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_scl.hdmi_ddc_scl */
+ 0x102 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_sda.hdmi_ddc_sda */
+ >;
+ };
+
+ tpd12s015_pins: pinmux_tpd12s015_pins {
+ pinctrl-single,pins = <
+ 0x0fe (PIN_INPUT_PULLDOWN | MUX_MODE6) /* hdmi_hpd.gpio7_193 */
+ >;
+ };
+};
+
+&omap5_pmx_wkup {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &usbhost_wkup_pins
+ >;
+
+ usbhost_wkup_pins: pinmux_usbhost_wkup_pins {
+ pinctrl-single,pins = <
+ 0x1A (PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
+ >;
+ };
+
+ wlcore_irq_pin: pinmux_wlcore_irq_pin {
+ pinctrl-single,pins = <
+ OMAP5_IOPAD(0x040, WAKEUP_EN | PIN_INPUT_PULLUP | MUX_MODE6) /* llia_wakereqin.gpio1_wk14 */
+ >;
+ };
+};
+
+&mmc1 {
+ vmmc-supply = <&ldo9_reg>;
+ bus-width = <4>;
+};
+
+&mmc2 {
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <8>;
+ ti,non-removable;
+};
+
+&mmc3 {
+ vmmc-supply = <&vmmcsdio_fixed>;
+ mmc-pwrseq = <&mmc3_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ cap-power-off-card;
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins &wlcore_irq_pin>;
+ interrupts-extended = <&gic GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH
+ &omap5_pmx_core 0x168>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+ wlcore: wlcore@2 {
+ compatible = "ti,wl1271";
+ reg = <2>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <14 IRQ_TYPE_LEVEL_HIGH>; /* gpio 14 */
+ ref-clock-frequency = <26000000>;
+ };
+};
+
+&mmc4 {
+ status = "disabled";
+};
+
+&mmc5 {
+ status = "disabled";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
+ clock-frequency = <400000>;
+
+ palmas: palmas@48 {
+ compatible = "ti,palmas";
+ interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
+ reg = <0x48>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ ti,system-power-controller;
+
+ extcon_usb3: palmas_usb {
+ compatible = "ti,palmas-usb-vid";
+ ti,enable-vbus-detection;
+ ti,enable-id-detection;
+ ti,wakeup;
+ };
+
+ clk32kgaudio: palmas_clk32k@1 {
+ compatible = "ti,palmas-clk32kgaudio";
+ #clock-cells = <0>;
+ };
+
+ palmas_pmic {
+ compatible = "ti,palmas-pmic";
+ interrupt-parent = <&palmas>;
+ interrupts = <14 IRQ_TYPE_NONE>;
+ interrupt-name = "short-irq";
+
+ ti,ldo6-vibrator;
+
+ regulators {
+ smps123_reg: smps123 {
+ /* VDD_OPP_MPU */
+ regulator-name = "smps123";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps45_reg: smps45 {
+ /* VDD_OPP_MM */
+ regulator-name = "smps45";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1310000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps6_reg: smps6 {
+ /* VDD_DDR3 - over VDD_SMPS6 */
+ regulator-name = "smps6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps7_reg: smps7 {
+ /* VDDS_1v8_OMAP over VDDS_1v8_MAIN */
+ regulator-name = "smps7";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps8_reg: smps8 {
+ /* VDD_OPP_CORE */
+ regulator-name = "smps8";
+ regulator-min-microvolt = < 600000>;
+ regulator-max-microvolt = <1310000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps9_reg: smps9 {
+ /* VDDA_2v1_AUD over VDD_2v1 */
+ regulator-name = "smps9";
+ regulator-min-microvolt = <2100000>;
+ regulator-max-microvolt = <2100000>;
+ ti,smps-range = <0x80>;
+ };
+
+ smps10_out2_reg: smps10_out2 {
+ /* VBUS_5V_OTG */
+ regulator-name = "smps10_out2";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps10_out1_reg: smps10_out1 {
+ /* VBUS_5V_OTG */
+ regulator-name = "smps10_out1";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+
+ ldo1_reg: ldo1 {
+ /* VDDAPHY_CAM: vdda_csiport */
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo2_reg: ldo2 {
+ /* VCC_2V8_DISP: Does not go anywhere */
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ /* Unused */
+ status = "disabled";
+ };
+
+ ldo3_reg: ldo3 {
+ /* VDDAPHY_MDM: vdda_lli */
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ /* Only if Modem is used */
+ status = "disabled";
+ };
+
+ ldo4_reg: ldo4 {
+ /* VDDAPHY_DISP: vdda_dsiport/hdmi */
+ regulator-name = "ldo4";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo5_reg: ldo5 {
+ /* VDDA_1V8_PHY: usb/sata/hdmi.. */
+ regulator-name = "ldo5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo6_reg: ldo6 {
+ /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */
+ regulator-name = "ldo6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo7_reg: ldo7 {
+ /* VDD_VPP: vpp1 */
+ regulator-name = "ldo7";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ /* Only for efuse reprograming! */
+ status = "disabled";
+ };
+
+ ldo8_reg: ldo8 {
+ /* VDD_3v0: Does not go anywhere */
+ regulator-name = "ldo8";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ /* Unused */
+ status = "disabled";
+ };
+
+ ldo9_reg: ldo9 {
+ /* VCC_DV_SDIO: vdds_sdcard */
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-boot-on;
+ };
+
+ ldoln_reg: ldoln {
+ /* VDDA_1v8_REF: vdds_osc/mm_l4per.. */
+ regulator-name = "ldoln";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldousb_reg: ldousb {
+ /* VDDA_3V_USB: VDDA_USBHS33 */
+ regulator-name = "ldousb";
+ regulator-min-microvolt = <3250000>;
+ regulator-max-microvolt = <3250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ regen3_reg: regen3 {
+ /* REGEN3 controls LDO9 supply to card */
+ regulator-name = "regen3";
+ regulator-always-on;
+ regulator-boot-on;
+ };
+ };
+ };
+
+ palmas_power_button: palmas_power_button {
+ compatible = "ti,palmas-pwrbutton";
+ interrupt-parent = <&palmas>;
+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ };
+ };
+
+ twl6040: twl@4b {
+ compatible = "ti,twl6040";
+ reg = <0x4b>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&twl6040_pins>;
+
+ interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */
+ ti,audpwron-gpio = <&gpio5 13 GPIO_ACTIVE_HIGH>; /* gpio line 141 */
+
+ vio-supply = <&smps7_reg>;
+ v2v1-supply = <&smps9_reg>;
+ enable-active-high;
+
+ clocks = <&clk32kgaudio>;
+ clock-names = "clk32k";
+ };
+};
+
+&mcpdm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcpdm_pins>;
+ status = "okay";
+};
+
+&mcbsp1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp1_pins>;
+ status = "okay";
+};
+
+&mcbsp2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp2_pins>;
+ status = "okay";
+};
+
+&usbhshost {
+ port2-mode = "ehci-hsic";
+ port3-mode = "ehci-hsic";
+};
+
+&usbhsehci {
+ phys = <0 &hsusb2_phy &hsusb3_phy>;
+};
+
+&usb3 {
+ extcon = <&extcon_usb3>;
+ vbus-supply = <&smps10_out1_reg>;
+};
+
+&mcspi1 {
+
+};
+
+&mcspi2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcspi2_pins>;
+};
+
+&mcspi3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcspi3_pins>;
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins>;
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins>;
+ interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
+ <&omap5_pmx_core 0x19c>;
+};
+
+&uart5 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart5_pins>;
+};
+
+&cpu0 {
+ cpu0-supply = <&smps123_reg>;
+};
+
+&dss {
+ status = "ok";
+};
+
+&hdmi {
+ status = "ok";
+
+ /* vdda-supply populated in board specific dts file */
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dss_hdmi_pins>;
+
+ port {
+ hdmi_out: endpoint {
+ remote-endpoint = <&tpd12s015_in>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/omap5-cm-t54.dts b/arch/arm/boot/dts/omap5-cm-t54.dts
index 61ad2ea..3774b37 100644
--- a/arch/arm/boot/dts/omap5-cm-t54.dts
+++ b/arch/arm/boot/dts/omap5-cm-t54.dts
@@ -344,7 +344,7 @@
interrupt-parent = <&gpio1>;
interrupts = <15 0>; /* gpio1_wk15 */
- pendown-gpio = <&gpio1 15 0>;
+ pendown-gpio = <&gpio1 15 GPIO_ACTIVE_HIGH>;
ti,x-min = /bits/ 16 <0x0>;
diff --git a/arch/arm/boot/dts/omap5-igep0050.dts b/arch/arm/boot/dts/omap5-igep0050.dts
new file mode 100644
index 0000000..46ecb1d
--- /dev/null
+++ b/arch/arm/boot/dts/omap5-igep0050.dts
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 ISEE 2007 SL - http://www.isee.biz/
+ *
+ * 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.
+ */
+/dts-v1/;
+
+#include "omap5-board-common.dtsi"
+
+/ {
+ model = "IGEPv5";
+ compatible = "isee,omap5-igep0050", "ti,omap5";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x7f000000>; /* 2032 MB */
+ };
+};
+
+&hdmi {
+ vdda-supply = <&ldo7_reg>;
+};
+
+&i2c4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_pins>;
+
+ tca6416: tca6416@21 {
+ compatible = "ti,tca6416";
+ reg = <0x21>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
+
+&omap5_pmx_core {
+ i2c4_pins: pinmux_i2c4_pins {
+ pinctrl-single,pins = <
+ OMAP5_IOPAD(0x0f8, PIN_INPUT | MUX_MODE0) /* i2c4_scl */
+ OMAP5_IOPAD(0x0fa, PIN_INPUT | MUX_MODE0) /* i2c4_sda */
+ >;
+ };
+};
+
+&tpd12s015 {
+ gpios = <&tca6416 11 0>, /* TCA6416 P01, CT_CP_HDP */
+ <&tca6416 12 0>, /* TCA6416 P00, LS_OE*/
+ <&gpio7 1 0>, /* 193, HPD */
+ <&gpio7 2 0>, /* 194, SCL */
+ <&gpio7 3 0>; /* 195, SDA */
+};
+
diff --git a/arch/arm/boot/dts/omap5-uevm.dts b/arch/arm/boot/dts/omap5-uevm.dts
index 3cb030f..05b1c1e 100644
--- a/arch/arm/boot/dts/omap5-uevm.dts
+++ b/arch/arm/boot/dts/omap5-uevm.dts
@@ -7,9 +7,7 @@
*/
/dts-v1/;
-#include "omap5.dtsi"
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "omap5-board-common.dtsi"
/ {
model = "TI OMAP5 uEVM board";
@@ -19,523 +17,10 @@
device_type = "memory";
reg = <0x80000000 0x7F000000>; /* 2032 MB */
};
-
- aliases {
- display0 = &hdmi0;
- };
-
- vmmcsd_fixed: fixedregulator-mmcsd {
- compatible = "regulator-fixed";
- regulator-name = "vmmcsd_fixed";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
-
- /* HS USB Host PHY on PORT 2 */
- hsusb2_phy: hsusb2_phy {
- compatible = "usb-nop-xceiv";
- reset-gpios = <&gpio3 16 GPIO_ACTIVE_LOW>; /* gpio3_80 HUB_NRESET */
- clocks = <&auxclk1_ck>;
- clock-names = "main_clk";
- clock-frequency = <19200000>;
- };
-
- /* HS USB Host PHY on PORT 3 */
- hsusb3_phy: hsusb3_phy {
- compatible = "usb-nop-xceiv";
- reset-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>; /* gpio3_79 ETH_NRESET */
- };
-
- leds {
- compatible = "gpio-leds";
- led@1 {
- label = "omap5:blue:usr1";
- gpios = <&gpio5 25 GPIO_ACTIVE_HIGH>; /* gpio5_153 D1 LED */
- linux,default-trigger = "heartbeat";
- default-state = "off";
- };
- };
-
- tpd12s015: encoder@0 {
- compatible = "ti,tpd12s015";
-
- pinctrl-names = "default";
- pinctrl-0 = <&tpd12s015_pins>;
-
- gpios = <&gpio9 0 GPIO_ACTIVE_HIGH>, /* TCA6424A P01, CT CP HPD */
- <&gpio9 1 GPIO_ACTIVE_HIGH>, /* TCA6424A P00, LS OE */
- <&gpio7 1 GPIO_ACTIVE_HIGH>; /* GPIO 193, HPD */
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
-
- tpd12s015_in: endpoint@0 {
- remote-endpoint = <&hdmi_out>;
- };
- };
-
- port@1 {
- reg = <1>;
-
- tpd12s015_out: endpoint@0 {
- remote-endpoint = <&hdmi_connector_in>;
- };
- };
- };
- };
-
- hdmi0: connector@0 {
- compatible = "hdmi-connector";
- label = "hdmi";
-
- type = "b";
-
- port {
- hdmi_connector_in: endpoint {
- remote-endpoint = <&tpd12s015_out>;
- };
- };
- };
-
- sound: sound {
- compatible = "ti,abe-twl6040";
- ti,model = "omap5-uevm";
-
- ti,mclk-freq = <19200000>;
-
- ti,mcpdm = <&mcpdm>;
-
- ti,twl6040 = <&twl6040>;
-
- /* Audio routing */
- ti,audio-routing =
- "Headset Stereophone", "HSOL",
- "Headset Stereophone", "HSOR",
- "Line Out", "AUXL",
- "Line Out", "AUXR",
- "HSMIC", "Headset Mic",
- "Headset Mic", "Headset Mic Bias",
- "AFML", "Line In",
- "AFMR", "Line In";
- };
-};
-
-&omap5_pmx_core {
- pinctrl-names = "default";
- pinctrl-0 = <
- &usbhost_pins
- &led_gpio_pins
- >;
-
- twl6040_pins: pinmux_twl6040_pins {
- pinctrl-single,pins = <
- 0x17e (PIN_OUTPUT | MUX_MODE6) /* mcspi1_somi.gpio5_141 */
- >;
- };
-
- mcpdm_pins: pinmux_mcpdm_pins {
- pinctrl-single,pins = <
- 0x142 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abe_clks.abe_clks */
- 0x15c (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_ul_data.abemcpdm_ul_data */
- 0x15e (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_dl_data.abemcpdm_dl_data */
- 0x160 (PIN_INPUT_PULLUP | MUX_MODE0) /* abemcpdm_frame.abemcpdm_frame */
- 0x162 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcpdm_lb_clk.abemcpdm_lb_clk */
- >;
- };
-
- mcbsp1_pins: pinmux_mcbsp1_pins {
- pinctrl-single,pins = <
- 0x14c (PIN_INPUT | MUX_MODE1) /* abedmic_clk2.abemcbsp1_fsx */
- 0x14e (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* abedmic_clk3.abemcbsp1_dx */
- 0x150 (PIN_INPUT | MUX_MODE1) /* abeslimbus1_clock.abemcbsp1_clkx */
- 0x152 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* abeslimbus1_data.abemcbsp1_dr */
- >;
- };
-
- mcbsp2_pins: pinmux_mcbsp2_pins {
- pinctrl-single,pins = <
- 0x154 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dr.abemcbsp2_dr */
- 0x156 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* abemcbsp2_dx.abemcbsp2_dx */
- 0x158 (PIN_INPUT | MUX_MODE0) /* abemcbsp2_fsx.abemcbsp2_fsx */
- 0x15a (PIN_INPUT | MUX_MODE0) /* abemcbsp2_clkx.abemcbsp2_clkx */
- >;
- };
-
- i2c1_pins: pinmux_i2c1_pins {
- pinctrl-single,pins = <
- 0x1b2 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
- 0x1b4 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
- >;
- };
-
- i2c5_pins: pinmux_i2c5_pins {
- pinctrl-single,pins = <
- 0x186 (PIN_INPUT | MUX_MODE0) /* i2c5_scl */
- 0x188 (PIN_INPUT | MUX_MODE0) /* i2c5_sda */
- >;
- };
-
- mcspi2_pins: pinmux_mcspi2_pins {
- pinctrl-single,pins = <
- 0xbc (PIN_INPUT | MUX_MODE0) /* mcspi2_clk */
- 0xbe (PIN_INPUT | MUX_MODE0) /* mcspi2_simo */
- 0xc0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mcspi2_somi */
- 0xc2 (PIN_OUTPUT | MUX_MODE0) /* mcspi2_cs0 */
- >;
- };
-
- mcspi3_pins: pinmux_mcspi3_pins {
- pinctrl-single,pins = <
- 0x78 (PIN_INPUT | MUX_MODE1) /* mcspi3_somi */
- 0x7a (PIN_INPUT | MUX_MODE1) /* mcspi3_cs0 */
- 0x7c (PIN_INPUT | MUX_MODE1) /* mcspi3_simo */
- 0x7e (PIN_INPUT | MUX_MODE1) /* mcspi3_clk */
- >;
- };
-
- mcspi4_pins: pinmux_mcspi4_pins {
- pinctrl-single,pins = <
- 0x164 (PIN_INPUT | MUX_MODE1) /* mcspi4_clk */
- 0x168 (PIN_INPUT | MUX_MODE1) /* mcspi4_simo */
- 0x16a (PIN_INPUT | MUX_MODE1) /* mcspi4_somi */
- 0x16c (PIN_INPUT | MUX_MODE1) /* mcspi4_cs0 */
- >;
- };
-
- usbhost_pins: pinmux_usbhost_pins {
- pinctrl-single,pins = <
- 0x84 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_strobe */
- 0x86 (PIN_INPUT | MUX_MODE0) /* usbb2_hsic_data */
-
- 0x19e (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_strobe */
- 0x1a0 (PIN_INPUT | MUX_MODE0) /* usbb3_hsic_data */
-
- 0x70 (PIN_OUTPUT | MUX_MODE6) /* gpio3_80 HUB_NRESET */
- 0x6e (PIN_OUTPUT | MUX_MODE6) /* gpio3_79 ETH_NRESET */
- >;
- };
-
- led_gpio_pins: pinmux_led_gpio_pins {
- pinctrl-single,pins = <
- 0x196 (PIN_OUTPUT | MUX_MODE6) /* uart3_cts_rctx.gpio5_153 */
- >;
- };
-
- uart1_pins: pinmux_uart1_pins {
- pinctrl-single,pins = <
- 0x60 (PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_cts */
- 0x62 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_tx.uart1_cts */
- 0x64 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart1_rx.uart1_rts */
- 0x66 (PIN_OUTPUT | MUX_MODE0) /* uart1_rx.uart1_rts */
- >;
- };
-
- uart3_pins: pinmux_uart3_pins {
- pinctrl-single,pins = <
- 0x19a (PIN_OUTPUT | MUX_MODE0) /* uart3_rts_irsd.uart3_tx_irtx */
- 0x19c (PIN_INPUT_PULLUP | MUX_MODE0) /* uart3_rx_irrx.uart3_usbb3_hsic */
- >;
- };
-
- uart5_pins: pinmux_uart5_pins {
- pinctrl-single,pins = <
- 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_rx.uart5_rx */
- 0x172 (PIN_OUTPUT | MUX_MODE0) /* uart5_tx.uart5_tx */
- 0x174 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart5_cts.uart5_rts */
- 0x176 (PIN_OUTPUT | MUX_MODE0) /* uart5_cts.uart5_rts */
- >;
- };
-
- dss_hdmi_pins: pinmux_dss_hdmi_pins {
- pinctrl-single,pins = <
- 0x0fc (PIN_INPUT_PULLUP | MUX_MODE0) /* hdmi_cec.hdmi_cec */
- 0x100 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_scl.hdmi_ddc_scl */
- 0x102 (PIN_INPUT | MUX_MODE0) /* hdmi_ddc_sda.hdmi_ddc_sda */
- >;
- };
-
- tpd12s015_pins: pinmux_tpd12s015_pins {
- pinctrl-single,pins = <
- 0x0fe (PIN_INPUT_PULLDOWN | MUX_MODE6) /* hdmi_hpd.gpio7_193 */
- >;
- };
-};
-
-&omap5_pmx_wkup {
- pinctrl-names = "default";
- pinctrl-0 = <
- &usbhost_wkup_pins
- >;
-
- usbhost_wkup_pins: pinmux_usbhost_wkup_pins {
- pinctrl-single,pins = <
- 0x1A (PIN_OUTPUT | MUX_MODE0) /* fref_clk1_out, USB hub clk */
- >;
- };
-};
-
-&mmc1 {
- vmmc-supply = <&ldo9_reg>;
- bus-width = <4>;
-};
-
-&mmc2 {
- vmmc-supply = <&vmmcsd_fixed>;
- bus-width = <8>;
- ti,non-removable;
-};
-
-&mmc3 {
- bus-width = <4>;
- ti,non-removable;
-};
-
-&mmc4 {
- status = "disabled";
};
-&mmc5 {
- status = "disabled";
-};
-
-&i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins>;
-
- clock-frequency = <400000>;
-
- palmas: palmas@48 {
- compatible = "ti,palmas";
- interrupts = <GIC_SPI 7 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
- reg = <0x48>;
- interrupt-controller;
- #interrupt-cells = <2>;
- ti,system-power-controller;
-
- extcon_usb3: palmas_usb {
- compatible = "ti,palmas-usb-vid";
- ti,enable-vbus-detection;
- ti,enable-id-detection;
- ti,wakeup;
- };
-
- clk32kgaudio: palmas_clk32k@1 {
- compatible = "ti,palmas-clk32kgaudio";
- #clock-cells = <0>;
- };
-
- palmas_pmic {
- compatible = "ti,palmas-pmic";
- interrupt-parent = <&palmas>;
- interrupts = <14 IRQ_TYPE_NONE>;
- interrupt-name = "short-irq";
-
- ti,ldo6-vibrator;
-
- regulators {
- smps123_reg: smps123 {
- /* VDD_OPP_MPU */
- regulator-name = "smps123";
- regulator-min-microvolt = < 600000>;
- regulator-max-microvolt = <1500000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps45_reg: smps45 {
- /* VDD_OPP_MM */
- regulator-name = "smps45";
- regulator-min-microvolt = < 600000>;
- regulator-max-microvolt = <1310000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps6_reg: smps6 {
- /* VDD_DDR3 - over VDD_SMPS6 */
- regulator-name = "smps6";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps7_reg: smps7 {
- /* VDDS_1v8_OMAP over VDDS_1v8_MAIN */
- regulator-name = "smps7";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps8_reg: smps8 {
- /* VDD_OPP_CORE */
- regulator-name = "smps8";
- regulator-min-microvolt = < 600000>;
- regulator-max-microvolt = <1310000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps9_reg: smps9 {
- /* VDDA_2v1_AUD over VDD_2v1 */
- regulator-name = "smps9";
- regulator-min-microvolt = <2100000>;
- regulator-max-microvolt = <2100000>;
- ti,smps-range = <0x80>;
- };
-
- smps10_out2_reg: smps10_out2 {
- /* VBUS_5V_OTG */
- regulator-name = "smps10_out2";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- smps10_out1_reg: smps10_out1 {
- /* VBUS_5V_OTG */
- regulator-name = "smps10_out1";
- regulator-min-microvolt = <5000000>;
- regulator-max-microvolt = <5000000>;
- };
-
- ldo1_reg: ldo1 {
- /* VDDAPHY_CAM: vdda_csiport */
- regulator-name = "ldo1";
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo2_reg: ldo2 {
- /* VCC_2V8_DISP: Does not go anywhere */
- regulator-name = "ldo2";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- /* Unused */
- status = "disabled";
- };
-
- ldo3_reg: ldo3 {
- /* VDDAPHY_MDM: vdda_lli */
- regulator-name = "ldo3";
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- regulator-boot-on;
- /* Only if Modem is used */
- status = "disabled";
- };
-
- ldo4_reg: ldo4 {
- /* VDDAPHY_DISP: vdda_dsiport/hdmi */
- regulator-name = "ldo4";
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo5_reg: ldo5 {
- /* VDDA_1V8_PHY: usb/sata/hdmi.. */
- regulator-name = "ldo5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldo6_reg: ldo6 {
- /* VDDS_1V2_WKUP: hsic/ldo_emu_wkup */
- regulator-name = "ldo6";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldo7_reg: ldo7 {
- /* VDD_VPP: vpp1 */
- regulator-name = "ldo7";
- regulator-min-microvolt = <2000000>;
- regulator-max-microvolt = <2000000>;
- /* Only for efuse reprograming! */
- status = "disabled";
- };
-
- ldo8_reg: ldo8 {
- /* VDD_3v0: Does not go anywhere */
- regulator-name = "ldo8";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-boot-on;
- /* Unused */
- status = "disabled";
- };
-
- ldo9_reg: ldo9 {
- /* VCC_DV_SDIO: vdds_sdcard */
- regulator-name = "ldo9";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <3000000>;
- regulator-boot-on;
- };
-
- ldoln_reg: ldoln {
- /* VDDA_1v8_REF: vdds_osc/mm_l4per.. */
- regulator-name = "ldoln";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- ldousb_reg: ldousb {
- /* VDDA_3V_USB: VDDA_USBHS33 */
- regulator-name = "ldousb";
- regulator-min-microvolt = <3250000>;
- regulator-max-microvolt = <3250000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- regen3_reg: regen3 {
- /* REGEN3 controls LDO9 supply to card */
- regulator-name = "regen3";
- regulator-always-on;
- regulator-boot-on;
- };
- };
- };
-
- palmas_power_button: palmas_power_button {
- compatible = "ti,palmas-pwrbutton";
- interrupt-parent = <&palmas>;
- interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
- wakeup-source;
- };
- };
-
- twl6040: twl@4b {
- compatible = "ti,twl6040";
- reg = <0x4b>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&twl6040_pins>;
-
- interrupts = <GIC_SPI 119 IRQ_TYPE_NONE>; /* IRQ_SYS_2N cascaded to gic */
- ti,audpwron-gpio = <&gpio5 13 0>; /* gpio line 141 */
-
- vio-supply = <&smps7_reg>;
- v2v1-supply = <&smps9_reg>;
- enable-active-high;
-
- clocks = <&clk32kgaudio>;
- clock-names = "clk32k";
- };
+&hdmi {
+ vdda-supply = <&ldo4_reg>;
};
&i2c5 {
@@ -552,92 +37,17 @@
};
};
-&mcpdm {
- pinctrl-names = "default";
- pinctrl-0 = <&mcpdm_pins>;
- status = "okay";
-};
-
-&mcbsp1 {
- pinctrl-names = "default";
- pinctrl-0 = <&mcbsp1_pins>;
- status = "okay";
-};
-
-&mcbsp2 {
- pinctrl-names = "default";
- pinctrl-0 = <&mcbsp2_pins>;
- status = "okay";
-};
-
-&usbhshost {
- port2-mode = "ehci-hsic";
- port3-mode = "ehci-hsic";
-};
-
-&usbhsehci {
- phys = <0 &hsusb2_phy &hsusb3_phy>;
-};
-
-&usb3 {
- extcon = <&extcon_usb3>;
- vbus-supply = <&smps10_out1_reg>;
-};
-
-&mcspi1 {
-
-};
-
-&mcspi2 {
- pinctrl-names = "default";
- pinctrl-0 = <&mcspi2_pins>;
-};
-
-&mcspi3 {
- pinctrl-names = "default";
- pinctrl-0 = <&mcspi3_pins>;
-};
-
-&mcspi4 {
- pinctrl-names = "default";
- pinctrl-0 = <&mcspi4_pins>;
-};
-
-&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart1_pins>;
-};
-
-&uart3 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart3_pins>;
- interrupts-extended = <&wakeupgen GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>,
- <&omap5_pmx_core 0x19c>;
-};
-
-&uart5 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart5_pins>;
-};
-
-&cpu0 {
- cpu0-supply = <&smps123_reg>;
-};
-
-&dss {
- status = "ok";
+&omap5_pmx_core {
+ i2c5_pins: pinmux_i2c5_pins {
+ pinctrl-single,pins = <
+ 0x186 (PIN_INPUT | MUX_MODE0) /* i2c5_scl */
+ 0x188 (PIN_INPUT | MUX_MODE0) /* i2c5_sda */
+ >;
+ };
};
-&hdmi {
- status = "ok";
- vdda-supply = <&ldo4_reg>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&dss_hdmi_pins>;
-
- port {
- hdmi_out: endpoint {
- remote-endpoint = <&tpd12s015_in>;
- };
- };
+&tpd12s015 {
+ gpios = <&gpio9 0 GPIO_ACTIVE_HIGH>, /* TCA6424A P01, CT CP HPD */
+ <&gpio9 1 GPIO_ACTIVE_HIGH>, /* TCA6424A P00, LS OE */
+ <&gpio7 1 GPIO_ACTIVE_HIGH>; /* GPIO 193, HPD */
};
diff --git a/arch/arm/boot/dts/orion5x.dtsi b/arch/arm/boot/dts/orion5x.dtsi
index 75cd01b..e1b6d2a 100644
--- a/arch/arm/boot/dts/orion5x.dtsi
+++ b/arch/arm/boot/dts/orion5x.dtsi
@@ -212,6 +212,16 @@
status = "disabled";
};
+ cesa: crypto@90000 {
+ compatible = "marvell,orion-crypto";
+ reg = <0x90000 0x10000>;
+ reg-names = "regs";
+ interrupts = <28>;
+ marvell,crypto-srams = <&crypto_sram>;
+ marvell,crypto-sram-size = <0x800>;
+ status = "okay";
+ };
+
ehci1: ehci@a0000 {
compatible = "marvell,orion-ehci";
reg = <0xa0000 0x1000>;
@@ -220,13 +230,11 @@
};
};
- cesa: crypto@90000 {
- compatible = "marvell,orion-crypto";
- reg = <MBUS_ID(0xf0, 0x01) 0x90000 0x10000>,
- <MBUS_ID(0x09, 0x00) 0x0 0x800>;
- reg-names = "regs", "sram";
- interrupts = <28>;
- status = "okay";
+ crypto_sram: sa-sram {
+ compatible = "mmio-sram";
+ reg = <MBUS_ID(0x09, 0x00) 0x0 0x800>;
+ #address-cells = <1>;
+ #size-cells = <1>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
index 47c0282..03784f1 100644
--- a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts
@@ -1,4 +1,6 @@
#include "qcom-apq8064-v2.0.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
/ {
model = "CompuLab CM-QS600";
@@ -12,12 +14,27 @@
stdout-path = "serial0:115200n8";
};
+ pwrseq {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ compatible = "simple-bus";
+
+ sdcc4_pwrseq: sdcc4_pwrseq {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_default_gpios>;
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pm8921_gpio 43 GPIO_ACTIVE_LOW>;
+ };
+ };
+
soc {
pinctrl@800000 {
- i2c1_pins: i2c1 {
+ card_detect: card_detect {
mux {
- pins = "gpio20", "gpio21";
- function = "gsbi1";
+ pins = "gpio26";
+ function = "gpio";
+ bias-disable;
};
};
};
@@ -96,10 +113,8 @@
i2c@12460000 {
status = "okay";
clock-frequency = <200000>;
- pinctrl-0 = <&i2c1_pins>;
- pinctrl-names = "default";
- eeprom: eeprom@50 {
+ eeprom@50 {
compatible = "24c02";
reg = <0x50>;
pagesize = <32>;
@@ -112,6 +127,8 @@
qcom,mode = <GSBI_PROT_I2C_UART>;
serial@16640000 {
status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi7_uart_2pins>;
};
};
@@ -163,6 +180,21 @@
regulator-always-on;
};
+ qcom,ssbi@500000 {
+ pmic@0 {
+ gpio@150 {
+ wlan_default_gpios: wlan-gpios {
+ pios {
+ pins = "gpio43";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
+ };
+ };
+ };
+ };
+ };
+
amba {
/* eMMC */
sdcc1: sdcc@12400000 {
@@ -175,12 +207,16 @@
sdcc3: sdcc@12180000 {
status = "okay";
vmmc-supply = <&v3p3_fixed>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&card_detect>;
+ cd-gpios = <&tlmm_pinmux 26 GPIO_ACTIVE_LOW>;
};
/* WLAN */
sdcc4: sdcc@121c0000 {
status = "okay";
vmmc-supply = <&v3p3_fixed>;
vqmmc-supply = <&v3p3_fixed>;
+ mmc-pwrseq = <&sdcc4_pwrseq>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
index f3100da..11ac608 100644
--- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
+++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts
@@ -1,5 +1,6 @@
#include "qcom-apq8064-v2.0.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
/ {
model = "Qualcomm APQ8064/IFC6410";
@@ -14,6 +15,29 @@
stdout-path = "serial0:115200n8";
};
+ pwrseq {
+ compatible = "simple-bus";
+
+ sdcc4_pwrseq: sdcc4_pwrseq {
+ pinctrl-names = "default";
+ pinctrl-0 = <&wlan_default_gpios>;
+ compatible = "mmc-pwrseq-simple";
+ reset-gpios = <&pm8921_gpio 43 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&notify_led>;
+
+ led@1 {
+ label = "apq8064:green:user1";
+ gpios = <&pm8921_gpio 18 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+ };
+
soc {
pinctrl@800000 {
card_detect: card_detect {
@@ -119,8 +143,6 @@
qcom,mode = <GSBI_PROT_I2C>;
i2c3: i2c@16280000 {
status = "okay";
- pinctrl-0 = <&i2c3_pins>;
- pinctrl-names = "default";
};
};
@@ -131,10 +153,8 @@
i2c@12460000 {
status = "okay";
clock-frequency = <200000>;
- pinctrl-0 = <&i2c1_pins>;
- pinctrl-names = "default";
- eeprom: eeprom@52 {
+ eeprom@52 {
compatible = "atmel,24c128";
reg = <0x52>;
pagesize = <32>;
@@ -148,9 +168,8 @@
serial@16540000 {
status = "ok";
-
pinctrl-names = "default";
- pinctrl-0 = <&uart_pins>;
+ pinctrl-0 = <&gsbi6_uart_4pins>;
};
};
@@ -159,6 +178,8 @@
qcom,mode = <GSBI_PROT_I2C_UART>;
serial@16640000 {
status = "ok";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gsbi7_uart_2pins>;
};
};
@@ -210,6 +231,30 @@
status = "okay";
};
+ qcom,ssbi@500000 {
+ pmic@0 {
+ gpio@150 {
+ wlan_default_gpios: wlan-gpios {
+ pios {
+ pins = "gpio43";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
+ };
+ };
+
+ notify_led: nled {
+ pios {
+ pins = "gpio18";
+ function = "normal";
+ bias-disable;
+ power-source = <PM8921_GPIO_S4>;
+ };
+ };
+ };
+ };
+ };
+
amba {
/* eMMC */
sdcc1: sdcc@12400000 {
@@ -231,6 +276,7 @@
status = "okay";
vmmc-supply = <&ext_3p3v>;
vqmmc-supply = <&pm8921_lvs1>;
+ mmc-pwrseq = <&sdcc4_pwrseq>;
};
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8064.dtsi b/arch/arm/boot/dts/qcom-apq8064.dtsi
index d2e94d6..a4c1762 100644
--- a/arch/arm/boot/dts/qcom-apq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8064.dtsi
@@ -127,12 +127,33 @@
};
};
- uart_pins: uart_pins {
+ gsbi6_uart_2pins: gsbi6_uart_2pins {
+ mux {
+ pins = "gpio14", "gpio15";
+ function = "gsbi6";
+ };
+ };
+
+ gsbi6_uart_4pins: gsbi6_uart_4pins {
mux {
pins = "gpio14", "gpio15", "gpio16", "gpio17";
function = "gsbi6";
};
};
+
+ gsbi7_uart_2pins: gsbi7_uart_2pins {
+ mux {
+ pins = "gpio82", "gpio83";
+ function = "gsbi7";
+ };
+ };
+
+ gsbi7_uart_4pins: gsbi7_uart_4pins {
+ mux {
+ pins = "gpio82", "gpio83", "gpio84", "gpio85";
+ function = "gsbi7";
+ };
+ };
};
intc: interrupt-controller@2000000 {
@@ -213,6 +234,8 @@
i2c1: i2c@12460000 {
compatible = "qcom,i2c-qup-v1.1.1";
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "default";
reg = <0x12460000 0x1000>;
interrupts = <0 194 IRQ_TYPE_NONE>;
clocks = <&gcc GSBI1_QUP_CLK>, <&gcc GSBI1_H_CLK>;
@@ -258,6 +281,8 @@
ranges;
i2c3: i2c@16280000 {
compatible = "qcom,i2c-qup-v1.1.1";
+ pinctrl-0 = <&i2c3_pins>;
+ pinctrl-names = "default";
reg = <0x16280000 0x1000>;
interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
clocks = <&gcc GSBI3_QUP_CLK>,
@@ -361,6 +386,22 @@
<136 1>, <137 1>, <138 1>, <139 1>;
};
+ rtc@11d {
+ compatible = "qcom,pm8921-rtc";
+ interrupt-parent = <&pmicintc>;
+ interrupts = <39 1>;
+ reg = <0x11d>;
+ allow-set-time;
+ };
+
+ pwrkey@1c {
+ compatible = "qcom,pm8921-pwrkey";
+ reg = <0x1c>;
+ interrupt-parent = <&pmicintc>;
+ interrupts = <50 1>, <51 1>;
+ debounce = <15625>;
+ pull-up;
+ };
};
};
diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi
index 0554fbd..fcffeca 100644
--- a/arch/arm/boot/dts/qcom-apq8084.dtsi
+++ b/arch/arm/boot/dts/qcom-apq8084.dtsi
@@ -221,6 +221,7 @@
compatible = "qcom,gcc-apq8084";
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
reg = <0xfc400000 0x4000>;
};
diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi
index ab8e572..753bdfd 100644
--- a/arch/arm/boot/dts/qcom-msm8974.dtsi
+++ b/arch/arm/boot/dts/qcom-msm8974.dtsi
@@ -100,6 +100,15 @@
clock-frequency = <19200000>;
};
+ smem {
+ compatible = "qcom,smem";
+
+ memory-region = <&smem_region>;
+ qcom,rpm-msg-ram = <&rpm_msg_ram>;
+
+ hwlocks = <&tcsr_mutex 3>;
+ };
+
soc: soc {
#address-cells = <1>;
#size-cells = <1>;
@@ -114,6 +123,11 @@
<0xf9002000 0x1000>;
};
+ apcs: syscon@f9011000 {
+ compatible = "syscon";
+ reg = <0xf9011000 0x1000>;
+ };
+
timer@f9020000 {
#address-cells = <1>;
#size-cells = <1>;
@@ -228,6 +242,7 @@
compatible = "qcom,gcc-msm8974";
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
reg = <0xfc400000 0x4000>;
};
@@ -240,6 +255,7 @@
compatible = "qcom,mmcc-msm8974";
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
reg = <0xfd8c0000 0x6000>;
};
@@ -250,13 +266,9 @@
#hwlock-cells = <1>;
};
- smem@fa00000 {
- compatible = "qcom,smem";
-
- memory-region = <&smem_region>;
+ rpm_msg_ram: memory@fc428000 {
+ compatible = "qcom,rpm-msg-ram";
reg = <0xfc428000 0x4000>;
-
- hwlocks = <&tcsr_mutex 3>;
};
blsp1_uart2: serial@f991e000 {
@@ -308,7 +320,7 @@
};
blsp_i2c11: i2c@f9967000 {
- status = "disable";
+ status = "disabled";
compatible = "qcom,i2c-qup-v2.1.1";
reg = <0xf9967000 0x1000>;
interrupts = <0 105 IRQ_TYPE_NONE>;
@@ -334,4 +346,73 @@
#interrupt-cells = <4>;
};
};
+
+ smd {
+ compatible = "qcom,smd";
+
+ rpm {
+ interrupts = <0 168 1>;
+ qcom,ipc = <&apcs 8 0>;
+ qcom,smd-edge = <15>;
+
+ rpm_requests {
+ compatible = "qcom,rpm-msm8974";
+ qcom,smd-channels = "rpm_requests";
+
+ pm8841-regulators {
+ compatible = "qcom,rpm-pm8841-regulators";
+
+ pm8841_s1: s1 {};
+ pm8841_s2: s2 {};
+ pm8841_s3: s3 {};
+ pm8841_s4: s4 {};
+ pm8841_s5: s5 {};
+ pm8841_s6: s6 {};
+ pm8841_s7: s7 {};
+ pm8841_s8: s8 {};
+ };
+
+ pm8941-regulators {
+ compatible = "qcom,rpm-pm8941-regulators";
+
+ pm8941_s1: s1 {};
+ pm8941_s2: s2 {};
+ pm8941_s3: s3 {};
+ pm8941_5v: s4 {};
+
+ pm8941_l1: l1 {};
+ pm8941_l2: l2 {};
+ pm8941_l3: l3 {};
+ pm8941_l4: l4 {};
+ pm8941_l5: l5 {};
+ pm8941_l6: l6 {};
+ pm8941_l7: l7 {};
+ pm8941_l8: l8 {};
+ pm8941_l9: l9 {};
+ pm8941_l10: l10 {};
+ pm8941_l11: l11 {};
+ pm8941_l12: l12 {};
+ pm8941_l13: l13 {};
+ pm8941_l14: l14 {};
+ pm8941_l15: l15 {};
+ pm8941_l16: l16 {};
+ pm8941_l17: l17 {};
+ pm8941_l18: l18 {};
+ pm8941_l19: l19 {};
+ pm8941_l20: l20 {};
+ pm8941_l21: l21 {};
+ pm8941_l22: l22 {};
+ pm8941_l23: l23 {};
+ pm8941_l24: l24 {};
+
+ pm8941_lvs1: lvs1 {};
+ pm8941_lvs2: lvs2 {};
+ pm8941_lvs3: lvs3 {};
+
+ pm8941_5vs1: 5vs1 {};
+ pm8941_5vs2: 5vs2 {};
+ };
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/qcom-pm8941.dtsi b/arch/arm/boot/dts/qcom-pm8941.dtsi
index 968f104..b0d4439 100644
--- a/arch/arm/boot/dts/qcom-pm8941.dtsi
+++ b/arch/arm/boot/dts/qcom-pm8941.dtsi
@@ -26,6 +26,27 @@
bias-pull-up;
};
+ charger@1000 {
+ compatible = "qcom,pm8941-charger";
+ reg = <0x1000 0x700>;
+ interrupts = <0x0 0x10 7 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x10 5 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x10 4 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x12 0 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 2 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x13 1 IRQ_TYPE_EDGE_BOTH>,
+ <0x0 0x14 1 IRQ_TYPE_EDGE_BOTH>;
+ interrupt-names = "chg-done",
+ "chg-fast",
+ "chg-trkl",
+ "bat-temp-ok",
+ "bat-present",
+ "chg-gone",
+ "usb-valid",
+ "dc-valid";
+ };
+
pm8941_gpios: gpios@c000 {
compatible = "qcom,pm8941-gpio";
reg = <0xc000 0x2400>;
@@ -120,8 +141,7 @@
pm8941_iadc: iadc@3600 {
compatible = "qcom,pm8941-iadc", "qcom,spmi-iadc";
- reg = <0x3600 0x100>,
- <0x12f1 0x1>;
+ reg = <0x3600 0x100>;
interrupts = <0x0 0x36 0x0 IRQ_TYPE_EDGE_RISING>;
qcom,external-resistor-micro-ohms = <10000>;
};
diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
deleted file mode 100644
index dffa6ff..0000000
--- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Reference Device Tree Source for the Bock-W board
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on r8a7779
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Simon Horman
- *
- * 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.
- */
-
-/dts-v1/;
-#include "r8a7778.dtsi"
-#include <dt-bindings/interrupt-controller/irq.h>
-#include <dt-bindings/gpio/gpio.h>
-
-/ {
- model = "bockw";
- compatible = "renesas,bockw-reference", "renesas,r8a7778";
-
- aliases {
- serial0 = &scif0;
- };
-
- chosen {
- bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp rw";
- stdout-path = &scif0;
- };
-
- memory {
- device_type = "memory";
- reg = <0x60000000 0x10000000>;
- };
-
- fixedregulator3v3: fixedregulator@0 {
- compatible = "regulator-fixed";
- regulator-name = "fixed-3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-boot-on;
- regulator-always-on;
- };
-
- ethernet@18300000 {
- compatible = "smsc,lan9220", "smsc,lan9115";
- reg = <0x18300000 0x1000>;
-
- phy-mode = "mii";
- interrupt-parent = <&irqpin>;
- interrupts = <0 IRQ_TYPE_EDGE_FALLING>;
- reg-io-width = <4>;
- vddvario-supply = <&fixedregulator3v3>;
- vdd33a-supply = <&fixedregulator3v3>;
- };
-
-};
-
-&mmcif {
- pinctrl-0 = <&mmc_pins>;
- pinctrl-names = "default";
-
- vmmc-supply = <&fixedregulator3v3>;
- bus-width = <8>;
- broken-cd;
- status = "okay";
-};
-
-&irqpin {
- status = "okay";
-};
-
-&tmu0 {
- status = "okay";
-};
-
-&pfc {
- scif0_pins: serial0 {
- renesas,groups = "scif0_data_a", "scif0_ctrl";
- renesas,function = "scif0";
- };
-
- mmc_pins: mmc {
- renesas,groups = "mmc_data8", "mmc_ctrl";
- renesas,function = "mmc";
- };
-
- sdhi0_pins: sd0 {
- renesas,groups = "sdhi0_data4", "sdhi0_ctrl",
- "sdhi0_cd";
- renesas,function = "sdhi0";
- };
-
- hspi0_pins: hspi0 {
- renesas,groups = "hspi0_a";
- renesas,function = "hspi0";
- };
-};
-
-&sdhi0 {
- pinctrl-0 = <&sdhi0_pins>;
- pinctrl-names = "default";
-
- vmmc-supply = <&fixedregulator3v3>;
- bus-width = <4>;
- status = "okay";
- wp-gpios = <&gpio3 18 GPIO_ACTIVE_HIGH>;
-};
-
-&hspi0 {
- pinctrl-0 = <&hspi0_pins>;
- pinctrl-names = "default";
- status = "okay";
-
- flash: flash@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "spansion,s25fl008k", "jedec,spi-nor";
- reg = <0>;
- spi-max-frequency = <104000000>;
- m25p,fast-read;
-
- partition@0 {
- label = "data(spi)";
- reg = <0x00000000 0x00100000>;
- };
- };
-};
-
-&scif0 {
- pinctrl-0 = <&scif0_pins>;
- pinctrl-names = "default";
-
- status = "okay";
-};
diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi
index 4b1fa9f..4f8e078 100644
--- a/arch/arm/boot/dts/r8a7778.dtsi
+++ b/arch/arm/boot/dts/r8a7778.dtsi
@@ -239,7 +239,7 @@
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-r8a7778", "renesas,rcar_sound-gen1";
reg = <0xffd90000 0x1000>, /* SRU */
- <0xffd91000 0x1240>, /* SSI */
+ <0xffd91000 0x240>, /* SSI */
<0xfffe0000 0x24>; /* ADG */
clocks = <&mstp3_clks R8A7778_CLK_SSI8>,
<&mstp3_clks R8A7778_CLK_SSI7>,
diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts
index 20afea6..fe396c8 100644
--- a/arch/arm/boot/dts/r8a7779-marzen.dts
+++ b/arch/arm/boot/dts/r8a7779-marzen.dts
@@ -19,12 +19,12 @@
compatible = "renesas,marzen", "renesas,r8a7779";
aliases {
- serial2 = &scif2;
- serial4 = &scif4;
+ serial0 = &scif2;
+ serial1 = &scif4;
};
chosen {
- bootargs = "console=ttySC2,115200 ignore_loglevel root=/dev/nfs ip=on";
+ bootargs = "ignore_loglevel root=/dev/nfs ip=on";
stdout-path = &scif2;
};
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index 37dec52..c553abd 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -174,6 +174,13 @@
1800000 0>;
};
+ audio_clock: clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <11289600>;
+ clock-output-names = "audio_clock";
+ };
+
rsnd_ak4643: sound {
compatible = "simple-audio-card";
@@ -187,7 +194,7 @@
sndcodec: simple-audio-card,codec {
sound-dai = <&ak4643>;
- system-clock-frequency = <11289600>;
+ clocks = <&audio_clock>;
};
};
@@ -335,6 +342,11 @@
renesas,function = "msiof1";
};
+ iic0_pins: iic0 {
+ renesas,groups = "iic0";
+ renesas,function = "iic0";
+ };
+
iic1_pins: iic1 {
renesas,groups = "iic1";
renesas,function = "iic1";
@@ -510,6 +522,8 @@
&iic0 {
status = "okay";
+ pinctrl-0 = <&iic0_pins>;
+ pinctrl-names = "default";
};
&iic1 {
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index 4624d0f..e07ae5d 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -1599,7 +1599,7 @@
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
- <0 0xec541000 0 0x1280>, /* SSI */
+ <0 0xec541000 0 0x280>, /* SSI */
<0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index dc15884..fc44ea3 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -242,6 +242,13 @@
1800000 0>;
};
+ audio_clock: clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <11289600>;
+ clock-output-names = "audio_clock";
+ };
+
rsnd_ak4643: sound {
compatible = "simple-audio-card";
@@ -255,7 +262,7 @@
sndcodec: simple-audio-card,codec {
sound-dai = <&ak4643>;
- system-clock-frequency = <11289600>;
+ clocks = <&audio_clock>;
};
};
diff --git a/arch/arm/boot/dts/r8a7791-porter.dts b/arch/arm/boot/dts/r8a7791-porter.dts
new file mode 100644
index 0000000..fe0f12f
--- /dev/null
+++ b/arch/arm/boot/dts/r8a7791-porter.dts
@@ -0,0 +1,282 @@
+/*
+ * Device Tree Source for the Porter board
+ *
+ * Copyright (C) 2015 Cogent Embedded, Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+#include "r8a7791.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Porter";
+ compatible = "renesas,porter", "renesas,r8a7791";
+
+ aliases {
+ serial0 = &scif0;
+ };
+
+ chosen {
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scif0;
+ };
+
+ memory@40000000 {
+ device_type = "memory";
+ reg = <0 0x40000000 0 0x40000000>;
+ };
+
+ memory@200000000 {
+ device_type = "memory";
+ reg = <2 0x00000000 0 0x40000000>;
+ };
+
+ vcc_sdhi0: regulator@0 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI0 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vccq_sdhi0: regulator@1 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI0 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
+
+ vcc_sdhi2: regulator@2 {
+ compatible = "regulator-fixed";
+
+ regulator-name = "SDHI2 Vcc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vccq_sdhi2: regulator@3 {
+ compatible = "regulator-gpio";
+
+ regulator-name = "SDHI2 VccQ";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+
+ gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
+ gpios-states = <1>;
+ states = <3300000 1
+ 1800000 0>;
+ };
+};
+
+&extal_clk {
+ clock-frequency = <20000000>;
+};
+
+&pfc {
+ scif0_pins: serial0 {
+ renesas,groups = "scif0_data_d";
+ renesas,function = "scif0";
+ };
+
+ ether_pins: ether {
+ renesas,groups = "eth_link", "eth_mdio", "eth_rmii";
+ renesas,function = "eth";
+ };
+
+ phy1_pins: phy1 {
+ renesas,groups = "intc_irq0";
+ renesas,function = "intc";
+ };
+
+ sdhi0_pins: sd0 {
+ renesas,groups = "sdhi0_data4", "sdhi0_ctrl";
+ renesas,function = "sdhi0";
+ };
+
+ sdhi2_pins: sd2 {
+ renesas,groups = "sdhi2_data4", "sdhi2_ctrl";
+ renesas,function = "sdhi2";
+ };
+
+ qspi_pins: spi0 {
+ renesas,groups = "qspi_ctrl", "qspi_data4";
+ renesas,function = "qspi";
+ };
+
+ i2c2_pins: i2c2 {
+ renesas,groups = "i2c2";
+ renesas,function = "i2c2";
+ };
+
+ usb0_pins: usb0 {
+ renesas,groups = "usb0";
+ renesas,function = "usb0";
+ };
+
+ usb1_pins: usb1 {
+ renesas,groups = "usb1";
+ renesas,function = "usb1";
+ };
+
+ vin0_pins: vin0 {
+ renesas,groups = "vin0_data8", "vin0_clk";
+ renesas,function = "vin0";
+ };
+};
+
+&scif0 {
+ pinctrl-0 = <&scif0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&ether {
+ pinctrl-0 = <&ether_pins &phy1_pins>;
+ pinctrl-names = "default";
+
+ phy-handle = <&phy1>;
+ renesas,ether-link-active-low;
+ status = "ok";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ interrupt-parent = <&irqc0>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ micrel,led-mode = <1>;
+ };
+};
+
+&sdhi0 {
+ pinctrl-0 = <&sdhi0_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi0>;
+ vqmmc-supply = <&vccq_sdhi0>;
+ cd-gpios = <&gpio6 6 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&sdhi2 {
+ pinctrl-0 = <&sdhi2_pins>;
+ pinctrl-names = "default";
+
+ vmmc-supply = <&vcc_sdhi2>;
+ vqmmc-supply = <&vccq_sdhi2>;
+ cd-gpios = <&gpio6 22 GPIO_ACTIVE_LOW>;
+ status = "okay";
+};
+
+&qspi {
+ pinctrl-0 = <&qspi_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <30000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ m25p,fast-read;
+
+ partition@0 {
+ label = "loader_prg";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user_prg";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash_fs";
+ reg = <0x00440000 0x03bc0000>;
+ };
+ };
+};
+
+&i2c2 {
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin0>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+};
+
+&sata0 {
+ status = "okay";
+};
+
+/* composite video input */
+&vin0 {
+ status = "ok";
+ pinctrl-0 = <&vin0_pins>;
+ pinctrl-names = "default";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vin0ep: endpoint {
+ remote-endpoint = <&adv7180>;
+ bus-width = <8>;
+ };
+ };
+};
+
+&pci0 {
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&pci1 {
+ pinctrl-0 = <&usb1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+&pcie_bus_clk {
+ status = "okay";
+};
+
+&pciec {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index 1666c8a..328f48b 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -1649,7 +1649,7 @@
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
- <0 0xec541000 0 0x1280>, /* SSI */
+ <0 0xec541000 0 0x280>, /* SSI */
<0 0xec740000 0 0x200>; /* Audio DMAC peri peri*/
reg-names = "scu", "adg", "ssiu", "ssi", "audmapp";
diff --git a/arch/arm/boot/dts/r8a7794-silk.dts b/arch/arm/boot/dts/r8a7794-silk.dts
index d4dd5a3..48ff3e2 100644
--- a/arch/arm/boot/dts/r8a7794-silk.dts
+++ b/arch/arm/boot/dts/r8a7794-silk.dts
@@ -61,10 +61,35 @@
renesas,function = "intc";
};
+ i2c1_pins: i2c1 {
+ renesas,groups = "i2c1";
+ renesas,function = "i2c1";
+ };
+
mmcif0_pins: mmcif0 {
renesas,groups = "mmc_data8", "mmc_ctrl";
renesas,function = "mmc";
};
+
+ qspi_pins: spi0 {
+ renesas,groups = "qspi_ctrl", "qspi_data4";
+ renesas,function = "qspi";
+ };
+
+ vin0_pins: vin0 {
+ renesas,groups = "vin0_data8", "vin0_clk";
+ renesas,function = "vin0";
+ };
+
+ usb0_pins: usb0 {
+ renesas,groups = "usb0";
+ renesas,function = "usb0";
+ };
+
+ usb1_pins: usb1 {
+ renesas,groups = "usb1";
+ renesas,function = "usb1";
+ };
};
&scif2 {
@@ -90,6 +115,27 @@
};
};
+&i2c1 {
+ pinctrl-0 = <&i2c1_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ composite-in@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin0>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin0ep>;
+ };
+ };
+ };
+};
+
&mmcif0 {
pinctrl-0 = <&mmcif0_pins>;
pinctrl-names = "default";
@@ -100,3 +146,71 @@
non-removable;
status = "okay";
};
+
+&qspi {
+ pinctrl-0 = <&qspi_pins>;
+ pinctrl-names = "default";
+
+ status = "okay";
+
+ flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,s25fl512s", "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <30000000>;
+ spi-tx-bus-width = <4>;
+ spi-rx-bus-width = <4>;
+ spi-cpol;
+ spi-cpha;
+ m25p,fast-read;
+
+ partition@0 {
+ label = "loader";
+ reg = <0x00000000 0x00040000>;
+ read-only;
+ };
+ partition@40000 {
+ label = "user";
+ reg = <0x00040000 0x00400000>;
+ read-only;
+ };
+ partition@440000 {
+ label = "flash";
+ reg = <0x00440000 0x03bc0000>;
+ };
+ };
+};
+
+/* composite video input */
+&vin0 {
+ status = "okay";
+ pinctrl-0 = <&vin0_pins>;
+ pinctrl-names = "default";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vin0ep: endpoint {
+ remote-endpoint = <&adv7180>;
+ bus-width = <8>;
+ };
+ };
+};
+
+&pci0 {
+ status = "okay";
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+};
+
+&pci1 {
+ status = "okay";
+ pinctrl-0 = <&usb1_pins>;
+ pinctrl-names = "default";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index 97c8e9a..a9977d6 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -19,6 +19,18 @@
#address-cells = <2>;
#size-cells = <2>;
+ aliases {
+ i2c0 = &i2c0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ i2c3 = &i2c3;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ spi0 = &qspi;
+ vin0 = &vin0;
+ vin1 = &vin1;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -50,6 +62,97 @@
interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ gpio0: gpio@e6050000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6050000 0 0x50>;
+ interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 0 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO0>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio1: gpio@e6051000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6051000 0 0x50>;
+ interrupts = <0 5 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 32 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO1>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio2: gpio@e6052000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6052000 0 0x50>;
+ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 64 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO2>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio3: gpio@e6053000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6053000 0 0x50>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 96 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO3>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio4: gpio@e6054000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6054000 0 0x50>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 128 32>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO4>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio5: gpio@e6055000 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6055000 0 0x50>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 160 28>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO5>;
+ power-domains = <&cpg_clocks>;
+ };
+
+ gpio6: gpio@e6055400 {
+ compatible = "renesas,gpio-r8a7794", "renesas,gpio-rcar";
+ reg = <0 0xe6055400 0 0x50>;
+ interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ gpio-ranges = <&pfc 0 192 26>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ clocks = <&mstp9_clks R8A7794_CLK_GPIO6>;
+ power-domains = <&cpg_clocks>;
+ };
+
cmt0: timer@ffca0000 {
compatible = "renesas,cmt-48-gen2";
reg = <0 0xffca0000 0 0x1004>;
@@ -407,6 +510,73 @@
status = "disabled";
};
+ /* The memory map in the User's Manual maps the cores to bus numbers */
+ i2c0: i2c@e6508000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6508000 0 0x40>;
+ interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C0>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@e6518000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6518000 0 0x40>;
+ interrupts = <0 288 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C1>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@e6530000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6530000 0 0x40>;
+ interrupts = <0 286 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C2>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@e6540000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6540000 0 0x40>;
+ interrupts = <0 290 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C3>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@e6520000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6520000 0 0x40>;
+ interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C4>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@e6528000 {
+ compatible = "renesas,i2c-r8a7794";
+ reg = <0 0xe6528000 0 0x40>;
+ interrupts = <0 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_I2C5>;
+ power-domains = <&cpg_clocks>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
mmcif0: mmc@ee200000 {
compatible = "renesas,mmcif-r8a7794", "renesas,sh-mmcif";
reg = <0 0xee200000 0 0x80>;
@@ -446,6 +616,140 @@
status = "disabled";
};
+ qspi: spi@e6b10000 {
+ compatible = "renesas,qspi-r8a7794", "renesas,qspi";
+ reg = <0 0xe6b10000 0 0x2c>;
+ interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R8A7794_CLK_QSPI_MOD>;
+ dmas = <&dmac0 0x17>, <&dmac0 0x18>;
+ dma-names = "tx", "rx";
+ power-domains = <&cpg_clocks>;
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ vin0: video@e6ef0000 {
+ compatible = "renesas,vin-r8a7794";
+ reg = <0 0xe6ef0000 0 0x1000>;
+ interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7794_CLK_VIN0>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ vin1: video@e6ef1000 {
+ compatible = "renesas,vin-r8a7794";
+ reg = <0 0xe6ef1000 0 0x1000>;
+ interrupts = <0 189 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp8_clks R8A7794_CLK_VIN1>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+ };
+
+ pci0: pci@ee090000 {
+ compatible = "renesas,pci-r8a7794";
+ device_type = "pci";
+ reg = <0 0xee090000 0 0xc00>,
+ <0 0xee080000 0 0x1100>;
+ interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7794_CLK_EHCI>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+
+ bus-range = <0 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges = <0x02000000 0 0xee080000 0 0xee080000 0 0x00010000>;
+ interrupt-map-mask = <0xff00 0 0 0x7>;
+ interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
+ 0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
+ 0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
+ };
+
+ pci1: pci@ee0d0000 {
+ compatible = "renesas,pci-r8a7794";
+ device_type = "pci";
+ reg = <0 0xee0d0000 0 0xc00>,
+ <0 0xee0c0000 0 0x1100>;
+ interrupts = <0 113 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7794_CLK_EHCI>;
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+
+ bus-range = <1 1>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ ranges = <0x02000000 0 0xee0c0000 0 0xee0c0000 0 0x00010000>;
+ interrupt-map-mask = <0xff00 0 0 0x7>;
+ interrupt-map = <0x0000 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
+ 0x0800 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
+ 0x1000 0 0 2 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
+ };
+
+ hsusb: usb@e6590000 {
+ compatible = "renesas,usbhs-r8a7794";
+ reg = <0 0xe6590000 0 0x100>;
+ interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7794_CLK_HSUSB>;
+ power-domains = <&cpg_clocks>;
+ renesas,buswait = <4>;
+ phys = <&usb0 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy: usb-phy@e6590100 {
+ compatible = "renesas,usb-phy-r8a7794";
+ reg = <0 0xe6590100 0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mstp7_clks R8A7794_CLK_HSUSB>;
+ clock-names = "usbhs";
+ power-domains = <&cpg_clocks>;
+ status = "disabled";
+
+ usb0: usb-channel@0 {
+ reg = <0>;
+ #phy-cells = <1>;
+ };
+ usb2: usb-channel@2 {
+ reg = <2>;
+ #phy-cells = <1>;
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -749,16 +1053,22 @@
mstp9_clks: mstp9_clks@e6150994 {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150994 0 4>, <0 0xe61509a4 0 4>;
- clocks = <&cpg_clocks R8A7794_CLK_QSPI>, <&hp_clk>, <&hp_clk>,
- <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
+ clocks = <&cp_clk>, <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cp_clk>, <&cp_clk>, <&cp_clk>,
+ <&cpg_clocks R8A7794_CLK_QSPI>, <&hp_clk>, <&hp_clk>,
+ <&hp_clk>, <&hp_clk>, <&hp_clk>, <&hp_clk>;
#clock-cells = <1>;
- clock-indices = <
- R8A7794_CLK_QSPI_MOD R8A7794_CLK_I2C5 R8A7794_CLK_I2C4
- R8A7794_CLK_I2C3 R8A7794_CLK_I2C2 R8A7794_CLK_I2C1
- R8A7794_CLK_I2C0
- >;
+ clock-indices = <R8A7794_CLK_GPIO6 R8A7794_CLK_GPIO5
+ R8A7794_CLK_GPIO4 R8A7794_CLK_GPIO3
+ R8A7794_CLK_GPIO2 R8A7794_CLK_GPIO1
+ R8A7794_CLK_GPIO0 R8A7794_CLK_QSPI_MOD
+ R8A7794_CLK_I2C5 R8A7794_CLK_I2C4
+ R8A7794_CLK_I2C3 R8A7794_CLK_I2C2
+ R8A7794_CLK_I2C1 R8A7794_CLK_I2C0>;
clock-output-names =
- "qspi_mod", "i2c5", "i2c4", "i2c3", "i2c2", "i2c1", "i2c0";
+ "gpio6", "gpio5", "gpio4", "gpio3", "gpio2",
+ "gpio1", "gpio0", "qspi_mod",
+ "i2c5", "i2c4", "i2c3", "i2c2", "i2c1", "i2c0";
};
mstp11_clks: mstp11_clks@e615099c {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/arch/arm/boot/dts/r8a77xx-aa121td01-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa121td01-panel.dtsi
new file mode 100644
index 0000000..a07ebf8
--- /dev/null
+++ b/arch/arm/boot/dts/r8a77xx-aa121td01-panel.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Common file for the AA121TD01 panel connected to Renesas R-Car boards
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ *
+ * 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.
+ */
+
+/ {
+ panel {
+ compatible = "mitsubishi,aa121td01", "panel-dpi";
+
+ width-mm = <261>;
+ height-mm = <163>;
+
+ panel-timing {
+ /* 1280x800 @60Hz */
+ clock-frequency = <71000000>;
+ hactive = <1280>;
+ vactive = <800>;
+ hsync-len = <70>;
+ hfront-porch = <20>;
+ hback-porch = <70>;
+ vsync-len = <5>;
+ vfront-porch = <3>;
+ vback-porch = <15>;
+ };
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds_connector>;
+ };
+ };
+ };
+};
+
+&lvds_connector {
+ remote-endpoint = <&panel_in>;
+};
diff --git a/arch/arm/boot/dts/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
index c027375..38c91a8 100644
--- a/arch/arm/boot/dts/rk3066a-bqcurie2.dts
+++ b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
@@ -186,6 +186,8 @@
pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
vmmc-supply = <&vcc_sd0>;
bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
disable-wp;
};
diff --git a/arch/arm/boot/dts/rk3066a-marsboard.dts b/arch/arm/boot/dts/rk3066a-marsboard.dts
index bae965c..7cdc308 100644
--- a/arch/arm/boot/dts/rk3066a-marsboard.dts
+++ b/arch/arm/boot/dts/rk3066a-marsboard.dts
@@ -178,6 +178,14 @@
};
};
+&mmc0 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
+ vmmc-supply = <&vcc_sd0>;
+};
+
&pinctrl {
lan8720a {
phy_int: phy-int {
diff --git a/arch/arm/boot/dts/rk3066a-rayeager.dts b/arch/arm/boot/dts/rk3066a-rayeager.dts
index e36383c..341c1f8 100644
--- a/arch/arm/boot/dts/rk3066a-rayeager.dts
+++ b/arch/arm/boot/dts/rk3066a-rayeager.dts
@@ -330,6 +330,8 @@
pinctrl-names = "default";
pinctrl-0 = <&sd0_clk>, <&sd0_cmd>, <&sd0_cd>, <&sd0_bus4>;
vmmc-supply = <&vcc_sd>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts
index d2180e5..66fa87d 100644
--- a/arch/arm/boot/dts/rk3188-radxarock.dts
+++ b/arch/arm/boot/dts/rk3188-radxarock.dts
@@ -90,6 +90,21 @@
};
};
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SPDIF";
+
+ simple-audio-card,dai-link@1 { /* S/PDIF - S/PDIF */
+ cpu { sound-dai = <&spdif>; };
+ codec { sound-dai = <&spdif_out>; };
+ };
+ };
+
+ spdif_out: spdif-out {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
ir_recv: gpio-ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio0 10 1>;
@@ -289,6 +304,8 @@
vmmc-supply = <&vcc_sd0>;
bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
disable-wp;
};
@@ -343,6 +360,10 @@
};
};
+&spdif {
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index 3163042..6399942 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -121,6 +121,20 @@
status = "disabled";
};
+ spdif: sound@1011e000 {
+ compatible = "rockchip,rk3188-spdif", "rockchip,rk3066-spdif";
+ reg = <0x1011e000 0x2000>;
+ #sound-dai-cells = <0>;
+ clock-names = "hclk", "mclk";
+ clocks = <&cru HCLK_SPDIF>, <&cru SCLK_SPDIF>;
+ dmas = <&dmac1_s 8>;
+ dma-names = "tx";
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_tx>;
+ status = "disabled";
+ };
+
cru: clock-controller@20000000 {
compatible = "rockchip,rk3188-cru";
reg = <0x20000000 0x1000>;
@@ -484,6 +498,12 @@
<RK_GPIO1 21 RK_FUNC_1 &pcfg_pull_none>;
};
};
+
+ spdif {
+ spdif_tx: spdif-tx {
+ rockchip,pins = <RK_GPIO1 14 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi
index 20fa0ef..4e3fd9a 100644
--- a/arch/arm/boot/dts/rk3288-firefly.dtsi
+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -48,6 +48,14 @@
reg = <0 0x80000000>;
};
+ dovdd_1v8: dovdd-1v8-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "dovdd_1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc28_dvp>;
+ };
+
ext_gmac: external-gmac-clock {
compatible = "fixed-clock";
#clock-cells = <0>;
@@ -55,6 +63,22 @@
clock-output-names = "ext_gmac";
};
+ io_domains: io-domains {
+ compatible = "rockchip,rk3288-io-voltage-domain";
+ rockchip,grf = <&grf>;
+
+ audio-supply = <&vcca_33>;
+ bb-supply = <&vcc_io>;
+ dvp-supply = <&dovdd_1v8>;
+ flash0-supply = <&vcc_flash>;
+ flash1-supply = <&vcc_lan>;
+ gpio30-supply = <&vcc_io>;
+ gpio1830-supply = <&vcc_io>;
+ lcdc-supply = <&vcc_io>;
+ sdcard-supply = <&vccio_sd>;
+ wifi-supply = <&vccio_wl>;
+ };
+
ir: ir-receiver {
compatible = "gpio-ir-receiver";
pinctrl-names = "default";
@@ -96,7 +120,7 @@
};
};
- vcc_sys: vsys-regulator {
+ vbat_wl: vcc_sys: vsys-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc_sys";
regulator-min-microvolt = <5000000>;
@@ -160,6 +184,23 @@
regulator-always-on;
vin-supply = <&vcc_5v>;
};
+
+ /*
+ * A TT8142 creates both dovdd_1v8 and vcc28_dvp, controlled
+ * by the dvp_pwr pin.
+ */
+ vcc28_dvp: vcc28-dvp-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 11 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dvp_pwr>;
+ regulator-name = "vcc28_dvp";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ vin-supply = <&vcc_io>;
+ };
};
&cpu0 {
@@ -325,7 +366,7 @@
regulator-always-on;
};
- vcc_18: REG11 {
+ vccio_wl: vcc_18: REG11 {
regulator-name = "vcc_18";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
@@ -373,6 +414,12 @@
};
};
+ dvp {
+ dvp_pwr: dvp-pwr {
+ rockchip,pins = <0 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
gmac {
phy_int: phy-int {
rockchip,pins = <0 9 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -445,7 +492,8 @@
num-slots = <1>;
pinctrl-names = "default";
pinctrl-0 = <&sdio0_bus4>, <&sdio0_cmd>, <&sdio0_clk>;
- vmmc-supply = <&vcc_18>;
+ vmmc-supply = <&vbat_wl>;
+ vqmmc-supply = <&vccio_wl>;
status = "okay";
};
@@ -459,6 +507,7 @@
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_clk>, <&sdmmc_cmd>, <&sdmmc_cd>, <&sdmmc_bus4>;
vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/rk3288-popmetal.dts b/arch/arm/boot/dts/rk3288-popmetal.dts
index f82b956..65c4756 100644
--- a/arch/arm/boot/dts/rk3288-popmetal.dts
+++ b/arch/arm/boot/dts/rk3288-popmetal.dts
@@ -79,6 +79,22 @@
};
};
+ io_domains: io-domains {
+ compatible = "rockchip,rk3288-io-voltage-domain";
+ rockchip,grf = <&grf>;
+
+ audio-supply = <&vcca_33>;
+ bb-supply = <&vcc_io>;
+ dvp-supply = <&vcc18_dvp>;
+ flash0-supply = <&vcc_flash>;
+ flash1-supply = <&vcc_lan>;
+ gpio30-supply = <&vcc_io>;
+ gpio1830-supply = <&vcc_io>;
+ lcdc-supply = <&vcc_io>;
+ sdcard-supply = <&vccio_sd>;
+ wifi-supply = <&vccio_wl>;
+ };
+
ir: ir-receiver {
compatible = "gpio-ir-receiver";
gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
@@ -86,6 +102,26 @@
pinctrl-0 = <&ir_int>;
};
+ vcc_flash: flash-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_flash";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vcc_sd: sdmmc-regulator {
+ compatible = "regulator-fixed";
+ gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_pwr>;
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ vin-supply = <&vcc_io>;
+ };
+
vcc_sys: vsys-regulator {
compatible = "regulator-fixed";
regulator-name = "vcc_sys";
@@ -94,6 +130,31 @@
regulator-always-on;
regulator-boot-on;
};
+
+ /*
+ * A PT5128 creates both dovdd_1v8 and vcc28_dvp, controlled
+ * by the dvp_pwr pin.
+ */
+ vcc18_dvp: vcc18-dvp-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc18-dvp";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ vin-supply = <&vcc28_dvp>;
+ };
+
+ vcc28_dvp: vcc28-dvp-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 17 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&dvp_pwr>;
+ regulator-name = "vcc28_dvp";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ vin-supply = <&vcc_io>;
+ };
};
&cpu0 {
@@ -109,6 +170,8 @@
num-slots = <1>;
pinctrl-names = "default";
pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_pwr &emmc_bus8>;
+ vmmc-supply = <&vcc_io>;
+ vqmmc-supply = <&vcc_flash>;
status = "okay";
};
@@ -121,6 +184,8 @@
num-slots = <1>;
pinctrl-names = "default";
pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
status = "okay";
};
@@ -297,22 +362,22 @@
};
};
- vcca_codec: LDO_REG8 {
+ vcca_33: LDO_REG8 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
- regulator-name = "vcca_codec";
+ regulator-name = "vcca_33";
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
- vcc_wl: SWITCH_REG1 {
+ vccio_wl: SWITCH_REG1 {
regulator-always-on;
regulator-boot-on;
- regulator-name = "vcc_wl";
+ regulator-name = "vccio_wl";
regulator-state-mem {
regulator-on-in-suspend;
};
@@ -388,6 +453,12 @@
};
};
+ dvp {
+ dvp_pwr: dvp-pwr {
+ rockchip,pins = <0 17 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
ir {
ir_int: ir-int {
rockchip,pins = <0 6 RK_FUNC_GPIO &pcfg_pull_up>;
@@ -405,6 +476,12 @@
rockchip,pins = <RK_GPIO0 4 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
+
+ sdmmc {
+ sdmmc_pwr: sdmmc-pwr {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
};
&tsadc {
diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
new file mode 100644
index 0000000..1813b7c3
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
@@ -0,0 +1,277 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/pwm/pwm.h>
+#include "rk3288.dtsi"
+
+/ {
+ memory {
+ reg = <0x0 0x80000000>;
+ device_type = "memory";
+ };
+
+ emmc_pwrseq: emmc-pwrseq {
+ compatible = "mmc-pwrseq-emmc";
+ pinctrl-0 = <&emmc_reset>;
+ pinctrl-names = "default";
+ reset-gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
+ };
+
+ ext_gmac: external-gmac-clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <125000000>;
+ clock-output-names = "ext_gmac";
+ };
+
+ vcc_sys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vcc_sys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+};
+
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
+&emmc {
+ bus-width = <8>;
+ cap-mmc-highspeed;
+ disable-wp;
+ non-removable;
+ num-slots = <1>;
+ mmc-pwrseq = <&emmc_pwrseq>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+ vmmc-supply = <&vcc_io>;
+ status = "okay";
+};
+
+&gmac {
+ assigned-clocks = <&cru SCLK_MAC>;
+ assigned-clock-parents = <&ext_gmac>;
+ clock_in_out = "input";
+ phy-mode = "rgmii";
+ phy-supply = <&vccio_pmu>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&rgmii_pins &phy_rst>;
+ snps,reset-gpio = <&gpio4 8 GPIO_ACTIVE_LOW>;
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 30000>;
+ rx_delay = <0x10>;
+ tx_delay = <0x30>;
+};
+
+&i2c0 {
+ status = "okay";
+
+ act8846: act8846@5a {
+ compatible = "active-semi,act8846";
+ reg = <0x5a>;
+ inl1-supply = <&vcc_io>;
+ inl2-supply = <&vcc_sys>;
+ inl3-supply = <&vcc_20>;
+ vp1-supply = <&vcc_sys>;
+ vp2-supply = <&vcc_sys>;
+ vp3-supply = <&vcc_sys>;
+ vp4-supply = <&vcc_sys>;
+
+ regulators {
+ vcc_ddr: REG1 {
+ regulator-name = "VCC_DDR";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ vcc_io: REG2 {
+ regulator-name = "VCC_IO";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_log: REG3 {
+ regulator-name = "VDD_LOG";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcc_20: REG4 {
+ regulator-name = "VCC_20";
+ regulator-min-microvolt = <2000000>;
+ regulator-max-microvolt = <2000000>;
+ regulator-always-on;
+ };
+
+ vccio_sd: REG5 {
+ regulator-name = "VCCIO_SD";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd10_lcd: REG6 {
+ regulator-name = "VDD10_LCD";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcca_codec: REG7 {
+ regulator-name = "VCCA_CODEC";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vcca_tp: REG8 {
+ regulator-name = "VCCA_TP";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vccio_pmu: REG9 {
+ regulator-name = "VCCIO_PMU";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_10: REG10 {
+ regulator-name = "VDD_10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ vcc_18: REG11 {
+ regulator-name = "VCC_18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ vcc18_lcd: REG12 {
+ regulator-name = "VCC18_LCD";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+ };
+ };
+
+ vdd_cpu: syr827@40 {
+ compatible = "silergy,syr827";
+ reg = <0x40>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-enable-ramp-delay = <300>;
+ regulator-name = "vdd_cpu";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-ramp-delay = <8000>;
+ vin-supply = <&vcc_sys>;
+ };
+
+ vdd_gpu: syr828@41 {
+ compatible = "silergy,syr828";
+ reg = <0x41>;
+ fcs,suspend-voltage-selector = <1>;
+ regulator-always-on;
+ regulator-enable-ramp-delay = <300>;
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-name = "vdd_gpu";
+ regulator-ramp-delay = <8000>;
+ vin-supply = <&vcc_sys>;
+ };
+};
+
+&pinctrl {
+ pcfg_output_high: pcfg-output-high {
+ output-high;
+ };
+
+ emmc {
+ emmc_reset: emmc-reset {
+ rockchip,pins = <3 9 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ gmac {
+ phy_rst: phy-rst {
+ rockchip,pins = <4 8 RK_FUNC_GPIO &pcfg_output_high>;
+ };
+ };
+};
+
+&tsadc {
+ rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */
+ status = "okay";
+};
+
+&vopb {
+ status = "okay";
+};
+
+&vopb_mmu {
+ status = "okay";
+};
+
+&vopl {
+ status = "okay";
+};
+
+&vopl_mmu {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-rock2-square.dts b/arch/arm/boot/dts/rk3288-rock2-square.dts
new file mode 100644
index 0000000..8af35c8
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-rock2-square.dts
@@ -0,0 +1,167 @@
+/*
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3288-rock2-som.dtsi"
+
+/ {
+ model = "Radxa Rock 2 Square";
+ compatible = "radxa,rock2-square", "rockchip,rk3288";
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "SPDIF";
+ simple-audio-card,dai-link@1 { /* S/PDIF - S/PDIF */
+ cpu { sound-dai = <&spdif>; };
+ codec { sound-dai = <&spdif_out>; };
+ };
+ };
+
+ spdif_out: spdif-out {
+ compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ };
+
+ vcc_usb_host: vcc-host-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio0 14 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&host_vbus_drv>;
+ /* Always on as the rockchip usb phy doesn't have a vbus-supply
+ * property
+ */
+ regulator-always-on;
+ regulator-name = "vcc_host";
+ };
+
+ vcc_sd: sdmmc-regulator {
+ compatible = "regulator-fixed";
+ gpio = <&gpio7 11 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_pwr>;
+ regulator-name = "vcc_sd";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ vin-supply = <&vcc_io>;
+ };
+};
+
+&sdmmc {
+ bus-width = <4>;
+ cap-mmc-highspeed;
+ cap-sd-highspeed;
+ card-detect-delay = <200>;
+ disable-wp; /* wp not hooked up */
+ num-slots = <1>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd &sdmmc_bus4>;
+ vmmc-supply = <&vcc_sd>;
+ vqmmc-supply = <&vccio_sd>;
+ status = "okay";
+};
+
+&gmac {
+ status = "ok";
+};
+
+&hdmi {
+ ddc-i2c-bus = <&i2c5>;
+ status = "okay";
+};
+
+&i2c0 {
+ hym8563@51 {
+ compatible = "haoyu,hym8563";
+ reg = <0x51>;
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ clock-output-names = "xin32k";
+ interrupt-parent = <&gpio0>;
+ interrupts = <4 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int>;
+
+ };
+};
+
+&i2c5 {
+ status = "okay";
+};
+
+&pinctrl {
+ pmic {
+ pmic_int: pmic-int {
+ rockchip,pins = <0 4 RK_FUNC_GPIO &pcfg_pull_up>;
+ };
+ };
+
+ usb {
+ host_vbus_drv: host-vbus-drv {
+ rockchip,pins = <0 14 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ sdmmc {
+ sdmmc_pwr: sdmmc-pwr {
+ rockchip,pins = <7 11 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&spdif {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
+
+&usb_host0_ehci {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3288-veyron-jaq.dts b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
new file mode 100644
index 0000000..c2f52cf
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-jaq.dts
@@ -0,0 +1,176 @@
+/*
+ * Google Veyron Jaq Rev 1+ board device tree source
+ *
+ * Copyright 2015 Google, Inc
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "rk3288-veyron-chromebook.dtsi"
+#include "cros-ec-sbs.dtsi"
+
+/ {
+ model = "Google Jaq";
+ compatible = "google,veyron-jaq-rev5", "google,veyron-jaq-rev4",
+ "google,veyron-jaq-rev3", "google,veyron-jaq-rev2",
+ "google,veyron-jaq-rev1", "google,veyron-jaq",
+ "google,veyron", "rockchip,rk3288";
+
+ panel_regulator: panel-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio7 14 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&lcd_enable_h>;
+ regulator-name = "panel_regulator";
+ vin-supply = <&vcc33_sys>;
+ };
+
+ vcc18_lcd: vcc18-lcd {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio2 13 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&avdd_1v8_disp_en>;
+ regulator-name = "vcc18_lcd";
+ regulator-always-on;
+ regulator-boot-on;
+ vin-supply = <&vcc18_wl>;
+ };
+
+ backlight_regulator: backlight-regulator {
+ compatible = "regulator-fixed";
+ enable-active-high;
+ gpio = <&gpio2 12 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_pwr_en>;
+ regulator-name = "backlight_regulator";
+ vin-supply = <&vcc33_sys>;
+ startup-delay-us = <15000>;
+ };
+};
+
+&rk808 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pmic_int_l &dvs_1 &dvs_2>;
+ dvs-gpios = <&gpio7 12 GPIO_ACTIVE_HIGH>,
+ <&gpio7 15 GPIO_ACTIVE_HIGH>;
+
+ regulators {
+ mic_vcc: LDO_REG2 {
+ regulator-name = "mic_vcc";
+ regulator-always-on;
+ regulator-boot-on;
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+ };
+};
+
+&sdmmc {
+ disable-wp;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sdmmc_clk &sdmmc_cmd &sdmmc_cd_disabled &sdmmc_cd_gpio
+ &sdmmc_bus4>;
+};
+
+&vcc_5v {
+ enable-active-high;
+ gpio = <&gpio7 21 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&drv_5v>;
+};
+
+&vcc50_hdmi {
+ enable-active-high;
+ gpio = <&gpio5 19 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&vcc50_hdmi_en>;
+};
+
+&pinctrl {
+ backlight {
+ bl_pwr_en: bl_pwr_en {
+ rockchip,pins = <2 12 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ buck-5v {
+ drv_5v: drv-5v {
+ rockchip,pins = <7 21 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ edp {
+ edp_hpd: edp_hpd {
+ rockchip,pins = <7 11 RK_FUNC_2 &pcfg_pull_down>;
+ };
+ };
+
+ hdmi {
+ vcc50_hdmi_en: vcc50-hdmi-en {
+ rockchip,pins = <5 19 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ lcd {
+ lcd_enable_h: lcd-en {
+ rockchip,pins = <7 14 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
+ avdd_1v8_disp_en: avdd-1v8-disp-en {
+ rockchip,pins = <2 13 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+
+ pmic {
+ dvs_1: dvs-1 {
+ rockchip,pins = <7 12 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+
+ dvs_2: dvs-2 {
+ rockchip,pins = <7 15 RK_FUNC_GPIO &pcfg_pull_down>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3288-veyron-minnie.dts b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
index 8fd8ef2..85f0373 100644
--- a/arch/arm/boot/dts/rk3288-veyron-minnie.dts
+++ b/arch/arm/boot/dts/rk3288-veyron-minnie.dts
@@ -86,6 +86,10 @@
};
};
+&emmc {
+ /delete-property/mmc-hs200-1_8v;
+};
+
&gpio_keys {
pinctrl-0 = <&pwr_key_l &ap_lid_int_l &volum_down_l &volum_up_l>;
diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi
index 860cea0..5e61f07 100644
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -550,18 +550,6 @@
};
};
- /*
- * On Marvell-based hardware this is a no-connect. Make sure we enable
- * the pullup so that the line doesn't float. The pullup shouldn't
- * hurt on Broadcom-based hardware since the other side is actively
- * driving this signal. As proof: we've already got a pullup on RX.
- */
- uart0 {
- uart0_cts: uart0-cts {
- rockchip,pins = <4 18 RK_FUNC_1 &pcfg_pull_up>;
- };
- };
-
write-protect {
fw_wp_ap: fw-wp-ap {
rockchip,pins = <7 6 RK_FUNC_GPIO &pcfg_pull_none>;
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 4e7c6b7..04ea209 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -44,6 +44,7 @@
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/clock/rk3288-cru.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/power/rk3288-power.h>
#include "skeleton.dtsi"
/ {
@@ -451,8 +452,10 @@
clock-names = "tsadc", "apb_pclk";
resets = <&cru SRST_TSADC>;
reset-names = "tsadc-apb";
- pinctrl-names = "default";
- pinctrl-0 = <&otp_out>;
+ pinctrl-names = "init", "default", "sleep";
+ pinctrl-0 = <&otp_gpio>;
+ pinctrl-1 = <&otp_out>;
+ pinctrl-2 = <&otp_gpio>;
#thermal-sensor-cells = <1>;
rockchip,hw-tshut-temp = <95000>;
status = "disabled";
@@ -617,8 +620,98 @@
};
pmu: power-management@ff730000 {
- compatible = "rockchip,rk3288-pmu", "syscon";
+ compatible = "rockchip,rk3288-pmu", "syscon", "simple-mfd";
reg = <0xff730000 0x100>;
+
+ power: power-controller {
+ compatible = "rockchip,rk3288-power-controller";
+ #power-domain-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /*
+ * Note: Although SCLK_* are the working clocks
+ * of device without including on the NOC, needed for
+ * synchronous reset.
+ *
+ * The clocks on the which NOC:
+ * ACLK_IEP/ACLK_VIP/ACLK_VOP0 are on ACLK_VIO0_NIU.
+ * ACLK_ISP/ACLK_VOP1 are on ACLK_VIO1_NIU.
+ * ACLK_RGA is on ACLK_RGA_NIU.
+ * The others (HCLK_*,PLCK_*) are on HCLK_VIO_NIU.
+ *
+ * Which clock are device clocks:
+ * clocks devices
+ * *_IEP IEP:Image Enhancement Processor
+ * *_ISP ISP:Image Signal Processing
+ * *_VIP VIP:Video Input Processor
+ * *_VOP* VOP:Visual Output Processor
+ * *_RGA RGA
+ * *_EDP* EDP
+ * *_LVDS_* LVDS
+ * *_HDMI HDMI
+ * *_MIPI_* MIPI
+ */
+ pd_vio {
+ reg = <RK3288_PD_VIO>;
+ clocks = <&cru ACLK_IEP>,
+ <&cru ACLK_ISP>,
+ <&cru ACLK_RGA>,
+ <&cru ACLK_VIP>,
+ <&cru ACLK_VOP0>,
+ <&cru ACLK_VOP1>,
+ <&cru DCLK_VOP0>,
+ <&cru DCLK_VOP1>,
+ <&cru HCLK_IEP>,
+ <&cru HCLK_ISP>,
+ <&cru HCLK_RGA>,
+ <&cru HCLK_VIP>,
+ <&cru HCLK_VOP0>,
+ <&cru HCLK_VOP1>,
+ <&cru PCLK_EDP_CTRL>,
+ <&cru PCLK_HDMI_CTRL>,
+ <&cru PCLK_LVDS_PHY>,
+ <&cru PCLK_MIPI_CSI>,
+ <&cru PCLK_MIPI_DSI0>,
+ <&cru PCLK_MIPI_DSI1>,
+ <&cru SCLK_EDP_24M>,
+ <&cru SCLK_EDP>,
+ <&cru SCLK_ISP_JPE>,
+ <&cru SCLK_ISP>,
+ <&cru SCLK_RGA>;
+ };
+
+ /*
+ * Note: The following 3 are HEVC(H.265) clocks,
+ * and on the ACLK_HEVC_NIU (NOC).
+ */
+ pd_hevc {
+ reg = <RK3288_PD_HEVC>;
+ clocks = <&cru ACLK_HEVC>,
+ <&cru SCLK_HEVC_CABAC>,
+ <&cru SCLK_HEVC_CORE>;
+ };
+
+ /*
+ * Note: ACLK_VCODEC/HCLK_VCODEC are VCODEC
+ * (video endecoder & decoder) clocks that on the
+ * ACLK_VCODEC_NIU and HCLK_VCODEC_NIU (NOC).
+ */
+ pd_video {
+ reg = <RK3288_PD_VIDEO>;
+ clocks = <&cru ACLK_VCODEC>,
+ <&cru HCLK_VCODEC>;
+ };
+
+ /*
+ * Note: ACLK_GPU is the GPU clock,
+ * and on the ACLK_GPU_NIU (NOC).
+ */
+ pd_gpu {
+ reg = <RK3288_PD_GPU>;
+ clocks = <&cru ACLK_GPU>;
+ };
+ };
};
sgrf: syscon@ff740000 {
@@ -657,6 +750,21 @@
status = "disabled";
};
+ spdif: sound@ff88b0000 {
+ compatible = "rockchip,rk3288-spdif", "rockchip,rk3066-spdif";
+ reg = <0xff8b0000 0x10000>;
+ #sound-dai-cells = <0>;
+ clock-names = "hclk", "mclk";
+ clocks = <&cru HCLK_SPDIF8CH>, <&cru SCLK_SPDIF8CH>;
+ dmas = <&dmac_bus_s 3>;
+ dma-names = "tx";
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spdif_tx>;
+ rockchip,grf = <&grf>;
+ status = "disabled";
+ };
+
i2s: i2s@ff890000 {
compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s";
reg = <0xff890000 0x10000>;
@@ -678,6 +786,7 @@
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+ power-domains = <&power RK3288_PD_VIO>;
resets = <&cru SRST_LCDC0_AXI>, <&cru SRST_LCDC0_AHB>, <&cru SRST_LCDC0_DCLK>;
reset-names = "axi", "ahb", "dclk";
iommus = <&vopb_mmu>;
@@ -699,6 +808,7 @@
reg = <0xff930300 0x100>;
interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopb_mmu";
+ power-domains = <&power RK3288_PD_VIO>;
#iommu-cells = <0>;
status = "disabled";
};
@@ -709,6 +819,7 @@
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+ power-domains = <&power RK3288_PD_VIO>;
resets = <&cru SRST_LCDC1_AXI>, <&cru SRST_LCDC1_AHB>, <&cru SRST_LCDC1_DCLK>;
reset-names = "axi", "ahb", "dclk";
iommus = <&vopl_mmu>;
@@ -730,6 +841,7 @@
reg = <0xff940300 0x100>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
interrupt-names = "vopl_mmu";
+ power-domains = <&power RK3288_PD_VIO>;
#iommu-cells = <0>;
status = "disabled";
};
@@ -742,6 +854,7 @@
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru PCLK_HDMI_CTRL>, <&cru SCLK_HDMI_HDCP>;
clock-names = "iahb", "isfr";
+ power-domains = <&power RK3288_PD_VIO>;
status = "disabled";
ports {
@@ -927,6 +1040,13 @@
#interrupt-cells = <2>;
};
+ hdmi {
+ hdmi_ddc: hdmi-ddc {
+ rockchip,pins = <7 19 RK_FUNC_2 &pcfg_pull_none>,
+ <7 20 RK_FUNC_2 &pcfg_pull_none>;
+ };
+ };
+
pcfg_pull_up: pcfg-pull-up {
bias-pull-up;
};
@@ -1215,7 +1335,7 @@
};
uart0_cts: uart0-cts {
- rockchip,pins = <4 18 RK_FUNC_1 &pcfg_pull_none>;
+ rockchip,pins = <4 18 RK_FUNC_1 &pcfg_pull_up>;
};
uart0_rts: uart0-rts {
@@ -1230,7 +1350,7 @@
};
uart1_cts: uart1-cts {
- rockchip,pins = <5 10 RK_FUNC_1 &pcfg_pull_none>;
+ rockchip,pins = <5 10 RK_FUNC_1 &pcfg_pull_up>;
};
uart1_rts: uart1-rts {
@@ -1253,7 +1373,7 @@
};
uart3_cts: uart3-cts {
- rockchip,pins = <7 9 RK_FUNC_1 &pcfg_pull_none>;
+ rockchip,pins = <7 9 RK_FUNC_1 &pcfg_pull_up>;
};
uart3_rts: uart3-rts {
@@ -1268,7 +1388,7 @@
};
uart4_cts: uart4-cts {
- rockchip,pins = <5 14 3 &pcfg_pull_none>;
+ rockchip,pins = <5 14 3 &pcfg_pull_up>;
};
uart4_rts: uart4-rts {
@@ -1277,6 +1397,10 @@
};
tsadc {
+ otp_gpio: otp-gpio {
+ rockchip,pins = <0 10 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+
otp_out: otp-out {
rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
};
@@ -1338,5 +1462,11 @@
<4 3 3 &pcfg_pull_none>;
};
};
+
+ spdif {
+ spdif_tx: spdif-tx {
+ rockchip,pins = <RK_GPIO6 11 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/s3c2416.dtsi b/arch/arm/boot/dts/s3c2416.dtsi
index a5184ff..80f0075 100644
--- a/arch/arm/boot/dts/s3c2416.dtsi
+++ b/arch/arm/boot/dts/s3c2416.dtsi
@@ -25,7 +25,7 @@
#size-cells = <0>;
cpu {
- compatible = "arm,arm926ejs";
+ compatible = "arm,arm926ej-s";
};
};
diff --git a/arch/arm/boot/dts/s5pv210-aquila.dts b/arch/arm/boot/dts/s5pv210-aquila.dts
index f00cea7..aa64faa 100644
--- a/arch/arm/boot/dts/s5pv210-aquila.dts
+++ b/arch/arm/boot/dts/s5pv210-aquila.dts
@@ -46,7 +46,7 @@
regulator-name = "V_TF_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpios = <&mp05 4 0>;
+ gpio = <&mp05 4 0>;
enable-active-high;
};
diff --git a/arch/arm/boot/dts/s5pv210-goni.dts b/arch/arm/boot/dts/s5pv210-goni.dts
index a3d4643..3b76eee 100644
--- a/arch/arm/boot/dts/s5pv210-goni.dts
+++ b/arch/arm/boot/dts/s5pv210-goni.dts
@@ -47,7 +47,7 @@
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
reg = <0>;
- gpios = <&mp05 4 0>;
+ gpio = <&mp05 4 0>;
enable-active-high;
};
@@ -73,7 +73,7 @@
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
reg = <3>;
- gpios = <&gpj1 3 0>;
+ gpio = <&gpj1 3 0>;
enable-active-high;
};
};
diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h
new file mode 100644
index 0000000..1afe246
--- /dev/null
+++ b/arch/arm/boot/dts/sama5d2-pinfunc.h
@@ -0,0 +1,880 @@
+#define PINMUX_PIN(no, func, ioset) \
+(((no) & 0xffff) | (((func) & 0xf) << 16) | (((ioset) & 0xff) << 20))
+
+#define PIN_PA0 0
+#define PIN_PA0__GPIO PINMUX_PIN(PIN_PA0, 0, 0)
+#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1, 1)
+#define PIN_PA0__QSPI0_SCK PINMUX_PIN(PIN_PA0, 2, 1)
+#define PIN_PA0__D0 PINMUX_PIN(PIN_PA0, 6, 2)
+#define PIN_PA1 1
+#define PIN_PA1__GPIO PINMUX_PIN(PIN_PA1, 0, 0)
+#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1, 1)
+#define PIN_PA1__QSPI0_CS PINMUX_PIN(PIN_PA1, 2, 1)
+#define PIN_PA1__D1 PINMUX_PIN(PIN_PA1, 6, 2)
+#define PIN_PA2 2
+#define PIN_PA2__GPIO PINMUX_PIN(PIN_PA2, 0, 0)
+#define PIN_PA2__SDMMC0_DAT0 PINMUX_PIN(PIN_PA2, 1, 1)
+#define PIN_PA2__QSPI0_IO0 PINMUX_PIN(PIN_PA2, 2, 1)
+#define PIN_PA2__D2 PINMUX_PIN(PIN_PA2, 6, 2)
+#define PIN_PA3 3
+#define PIN_PA3__GPIO PINMUX_PIN(PIN_PA3, 0, 0)
+#define PIN_PA3__SDMMC0_DAT1 PINMUX_PIN(PIN_PA3, 1, 1)
+#define PIN_PA3__QSPI0_IO1 PINMUX_PIN(PIN_PA3, 2, 1)
+#define PIN_PA3__D3 PINMUX_PIN(PIN_PA3, 6, 2)
+#define PIN_PA4 4
+#define PIN_PA4__GPIO PINMUX_PIN(PIN_PA4, 0, 0)
+#define PIN_PA4__SDMMC0_DAT2 PINMUX_PIN(PIN_PA4, 1, 1)
+#define PIN_PA4__QSPI0_IO2 PINMUX_PIN(PIN_PA4, 2, 1)
+#define PIN_PA4__D4 PINMUX_PIN(PIN_PA4, 6, 2)
+#define PIN_PA5 5
+#define PIN_PA5__GPIO PINMUX_PIN(PIN_PA5, 0, 0)
+#define PIN_PA5__SDMMC0_DAT3 PINMUX_PIN(PIN_PA5, 1, 1)
+#define PIN_PA5__QSPI0_IO3 PINMUX_PIN(PIN_PA5, 2, 1)
+#define PIN_PA5__D5 PINMUX_PIN(PIN_PA5, 6, 2)
+#define PIN_PA6 6
+#define PIN_PA6__GPIO PINMUX_PIN(PIN_PA6, 0, 0)
+#define PIN_PA6__SDMMC0_DAT4 PINMUX_PIN(PIN_PA6, 1, 1)
+#define PIN_PA6__QSPI1_SCK PINMUX_PIN(PIN_PA6, 2, 1)
+#define PIN_PA6__TIOA5 PINMUX_PIN(PIN_PA6, 4, 1)
+#define PIN_PA6__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA6, 5, 1)
+#define PIN_PA6__D6 PINMUX_PIN(PIN_PA6, 6, 2)
+#define PIN_PA7 7
+#define PIN_PA7__GPIO PINMUX_PIN(PIN_PA7, 0, 0)
+#define PIN_PA7__SDMMC0_DAT5 PINMUX_PIN(PIN_PA7, 1, 1)
+#define PIN_PA7__QSPI1_IO0 PINMUX_PIN(PIN_PA7, 2, 1)
+#define PIN_PA7__TIOB5 PINMUX_PIN(PIN_PA7, 4, 1)
+#define PIN_PA7__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA7, 5, 1)
+#define PIN_PA7__D7 PINMUX_PIN(PIN_PA7, 6, 2)
+#define PIN_PA8 8
+#define PIN_PA8__GPIO PINMUX_PIN(PIN_PA8, 0, 0)
+#define PIN_PA8__SDMMC0_DAT6 PINMUX_PIN(PIN_PA8, 1, 1)
+#define PIN_PA8__QSPI1_IO1 PINMUX_PIN(PIN_PA8, 2, 1)
+#define PIN_PA8__TCLK5 PINMUX_PIN(PIN_PA8, 4, 1)
+#define PIN_PA8__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA8, 5, 1)
+#define PIN_PA8__NWE_NANDWE PINMUX_PIN(PIN_PA8, 6, 2)
+#define PIN_PA9 9
+#define PIN_PA9__GPIO PINMUX_PIN(PIN_PA9, 0, 0)
+#define PIN_PA9__SDMMC0_DAT7 PINMUX_PIN(PIN_PA9, 1, 1)
+#define PIN_PA9__QSPI1_IO2 PINMUX_PIN(PIN_PA9, 2, 1)
+#define PIN_PA9__TIOA4 PINMUX_PIN(PIN_PA9, 4, 1)
+#define PIN_PA9__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA9, 5, 1)
+#define PIN_PA9__NCS3 PINMUX_PIN(PIN_PA9, 6, 2)
+#define PIN_PA10 10
+#define PIN_PA10__GPIO PINMUX_PIN(PIN_PA10, 0, 0)
+#define PIN_PA10__SDMMC0_RSTN PINMUX_PIN(PIN_PA10, 1, 1)
+#define PIN_PA10__QSPI1_IO3 PINMUX_PIN(PIN_PA10, 2, 1)
+#define PIN_PA10__TIOB4 PINMUX_PIN(PIN_PA10, 4, 1)
+#define PIN_PA10__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA10, 5, 1)
+#define PIN_PA10__A21_NANDALE PINMUX_PIN(PIN_PA10, 6, 2)
+#define PIN_PA11 11
+#define PIN_PA11__GPIO PINMUX_PIN(PIN_PA11, 0, 0)
+#define PIN_PA11__SDMMC0_VDDSEL PINMUX_PIN(PIN_PA11, 1, 1)
+#define PIN_PA11__QSPI1_CS PINMUX_PIN(PIN_PA11, 2, 1)
+#define PIN_PA11__TCLK4 PINMUX_PIN(PIN_PA11, 4, 1)
+#define PIN_PA11__A22_NANDCLE PINMUX_PIN(PIN_PA11, 6, 2)
+#define PIN_PA12 12
+#define PIN_PA12__GPIO PINMUX_PIN(PIN_PA12, 0, 0)
+#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1, 1)
+#define PIN_PA12__IRQ PINMUX_PIN(PIN_PA12, 2, 1)
+#define PIN_PA12__NRD_NANDOE PINMUX_PIN(PIN_PA12, 6, 2)
+#define PIN_PA13 13
+#define PIN_PA13__GPIO PINMUX_PIN(PIN_PA13, 0, 0)
+#define PIN_PA13__SDMMC0_CD PINMUX_PIN(PIN_PA13, 1, 1)
+#define PIN_PA13__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA13, 5, 1)
+#define PIN_PA13__D8 PINMUX_PIN(PIN_PA13, 6, 2)
+#define PIN_PA14 14
+#define PIN_PA14__GPIO PINMUX_PIN(PIN_PA14, 0, 0)
+#define PIN_PA14__SPI0_SPCK PINMUX_PIN(PIN_PA14, 1, 1)
+#define PIN_PA14__TK1 PINMUX_PIN(PIN_PA14, 2, 1)
+#define PIN_PA14__QSPI0_SCK PINMUX_PIN(PIN_PA14, 3, 2)
+#define PIN_PA14__I2SC1_MCK PINMUX_PIN(PIN_PA14, 4, 2)
+#define PIN_PA14__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA14, 5, 1)
+#define PIN_PA14__D9 PINMUX_PIN(PIN_PA14, 6, 2)
+#define PIN_PA15 14
+#define PIN_PA15__GPIO PINMUX_PIN(PIN_PA15, 0, 0)
+#define PIN_PA15__SPI0_MOSI PINMUX_PIN(PIN_PA15, 1, 1)
+#define PIN_PA15__TF1 PINMUX_PIN(PIN_PA15, 2, 1)
+#define PIN_PA15__QSPI0_CS PINMUX_PIN(PIN_PA15, 3, 2)
+#define PIN_PA15__I2SC1_CK PINMUX_PIN(PIN_PA15, 4, 2)
+#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 5, 1)
+#define PIN_PA15__D10 PINMUX_PIN(PIN_PA15, 6, 2)
+#define PIN_PA16 16
+#define PIN_PA16__GPIO PINMUX_PIN(PIN_PA16, 0, 0)
+#define PIN_PA16__SPI0_MISO PINMUX_PIN(PIN_PA16, 1, 1)
+#define PIN_PA16__TD1 PINMUX_PIN(PIN_PA16, 2, 1)
+#define PIN_PA16__QSPI0_IO0 PINMUX_PIN(PIN_PA16, 3, 2)
+#define PIN_PA16__I2SC1_WS PINMUX_PIN(PIN_PA16, 4, 2)
+#define PIN_PA16__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA16, 5, 1)
+#define PIN_PA16__D11 PINMUX_PIN(PIN_PA16, 6, 2)
+#define PIN_PA17 17
+#define PIN_PA17__GPIO PINMUX_PIN(PIN_PA17, 0, 0)
+#define PIN_PA17__SPI0_NPCS0 PINMUX_PIN(PIN_PA17, 1, 1)
+#define PIN_PA17__RD1 PINMUX_PIN(PIN_PA17, 2, 1)
+#define PIN_PA17__QSPI0_IO1 PINMUX_PIN(PIN_PA17, 3, 2)
+#define PIN_PA17__I2SC1_DI0 PINMUX_PIN(PIN_PA17, 4, 2)
+#define PIN_PA17__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA17, 5, 1)
+#define PIN_PA17__D12 PINMUX_PIN(PIN_PA17, 6, 2)
+#define PIN_PA18 18
+#define PIN_PA18__GPIO PINMUX_PIN(PIN_PA18, 0, 0)
+#define PIN_PA18__SPI0_NPCS1 PINMUX_PIN(PIN_PA18, 1, 1)
+#define PIN_PA18__RK1 PINMUX_PIN(PIN_PA18, 2, 1)
+#define PIN_PA18__QSPI0_IO2 PINMUX_PIN(PIN_PA18, 3, 2)
+#define PIN_PA18__I2SC1_DO0 PINMUX_PIN(PIN_PA18, 4, 2)
+#define PIN_PA18__SDMMC1_DAT0 PINMUX_PIN(PIN_PA18, 5, 1)
+#define PIN_PA18__D13 PINMUX_PIN(PIN_PA18, 6, 2)
+#define PIN_PA19 19
+#define PIN_PA19__GPIO PINMUX_PIN(PIN_PA19, 0, 0)
+#define PIN_PA19__SPI0_NPCS2 PINMUX_PIN(PIN_PA19, 1, 1)
+#define PIN_PA19__RF1 PINMUX_PIN(PIN_PA19, 2, 1)
+#define PIN_PA19__QSPI0_IO3 PINMUX_PIN(PIN_PA19, 3, 2)
+#define PIN_PA19__TIOA0 PINMUX_PIN(PIN_PA19, 4, 1)
+#define PIN_PA19__SDMMC1_DAT1 PINMUX_PIN(PIN_PA19, 5, 1)
+#define PIN_PA19__D14 PINMUX_PIN(PIN_PA19, 6, 2)
+#define PIN_PA20 20
+#define PIN_PA20__GPIO PINMUX_PIN(PIN_PA20, 0, 0)
+#define PIN_PA20__SPI0_NPCS3 PINMUX_PIN(PIN_PA20, 1, 1)
+#define PIN_PA20__TIOB0 PINMUX_PIN(PIN_PA20, 4, 1)
+#define PIN_PA20__SDMMC1_DAT2 PINMUX_PIN(PIN_PA20, 5, 1)
+#define PIN_PA20__D15 PINMUX_PIN(PIN_PA20, 6, 2)
+#define PIN_PA21 21
+#define PIN_PA21__GPIO PINMUX_PIN(PIN_PA21, 0, 0)
+#define PIN_PA21__IRQ PINMUX_PIN(PIN_PA21, 1, 2)
+#define PIN_PA21__PCK2 PINMUX_PIN(PIN_PA21, 2, 3)
+#define PIN_PA21__TCLK0 PINMUX_PIN(PIN_PA21, 4, 1)
+#define PIN_PA21__SDMMC1_DAT3 PINMUX_PIN(PIN_PA21, 5, 1)
+#define PIN_PA21__NANDRDY PINMUX_PIN(PIN_PA21, 6, 2)
+#define PIN_PA22 22
+#define PIN_PA22__GPIO PINMUX_PIN(PIN_PA22, 0, 0)
+#define PIN_PA22__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA22, 1, 1)
+#define PIN_PA22__D0 PINMUX_PIN(PIN_PA22, 2, 1)
+#define PIN_PA22__TCK PINMUX_PIN(PIN_PA22, 3, 4)
+#define PIN_PA22__SPI1_SPCK PINMUX_PIN(PIN_PA22, 4, 2)
+#define PIN_PA22__SDMMC1_CK PINMUX_PIN(PIN_PA22, 5, 1)
+#define PIN_PA22__QSPI0_SCK PINMUX_PIN(PIN_PA22, 6, 3)
+#define PIN_PA23 23
+#define PIN_PA23__GPIO PINMUX_PIN(PIN_PA23, 0, 0)
+#define PIN_PA23__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA23, 1, 1)
+#define PIN_PA23__D1 PINMUX_PIN(PIN_PA23, 2, 1)
+#define PIN_PA23__TDI PINMUX_PIN(PIN_PA23, 3, 4)
+#define PIN_PA23__SPI1_MOSI PINMUX_PIN(PIN_PA23, 4, 2)
+#define PIN_PA23__QSPI0_CS PINMUX_PIN(PIN_PA23, 6, 3)
+#define PIN_PA24 24
+#define PIN_PA24__GPIO PINMUX_PIN(PIN_PA24, 0, 0)
+#define PIN_PA24__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA24, 1, 1)
+#define PIN_PA24__D2 PINMUX_PIN(PIN_PA24, 2, 1)
+#define PIN_PA24__TDO PINMUX_PIN(PIN_PA24, 3, 4)
+#define PIN_PA24__SPI1_MISO PINMUX_PIN(PIN_PA24, 4, 2)
+#define PIN_PA24__QSPI0_IO0 PINMUX_PIN(PIN_PA24, 6, 3)
+#define PIN_PA25 25
+#define PIN_PA25__GPIO PINMUX_PIN(PIN_PA25, 0, 0)
+#define PIN_PA25__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA25, 1, 1)
+#define PIN_PA25__D3 PINMUX_PIN(PIN_PA25, 2, 1)
+#define PIN_PA25__TMS PINMUX_PIN(PIN_PA25, 3, 4)
+#define PIN_PA25__SPI1_NPCS0 PINMUX_PIN(PIN_PA25, 4, 2)
+#define PIN_PA25__QSPI0_IO1 PINMUX_PIN(PIN_PA25, 6, 3)
+#define PIN_PA26 26
+#define PIN_PA26__GPIO PINMUX_PIN(PIN_PA26, 0, 0)
+#define PIN_PA26__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA26, 1, 1)
+#define PIN_PA26__D4 PINMUX_PIN(PIN_PA26, 2, 1)
+#define PIN_PA26__NTRST PINMUX_PIN(PIN_PA26, 3, 4)
+#define PIN_PA26__SPI1_NPCS1 PINMUX_PIN(PIN_PA26, 4, 2)
+#define PIN_PA26__QSPI0_IO2 PINMUX_PIN(PIN_PA26, 6, 3)
+#define PIN_PA27 27
+#define PIN_PA27__GPIO PINMUX_PIN(PIN_PA27, 0, 0)
+#define PIN_PA27__TIOA1 PINMUX_PIN(PIN_PA27, 1, 2)
+#define PIN_PA27__D5 PINMUX_PIN(PIN_PA27, 2, 1)
+#define PIN_PA27__SPI0_NPCS2 PINMUX_PIN(PIN_PA27, 3, 2)
+#define PIN_PA27__SPI1_NPCS2 PINMUX_PIN(PIN_PA27, 4, 2)
+#define PIN_PA27__SDMMC1_RSTN PINMUX_PIN(PIN_PA27, 5, 1)
+#define PIN_PA27__QSPI0_IO3 PINMUX_PIN(PIN_PA27, 6, 3)
+#define PIN_PA28 28
+#define PIN_PA28__GPIO PINMUX_PIN(PIN_PA28, 0, 0)
+#define PIN_PA28__TIOB1 PINMUX_PIN(PIN_PA28, 1, 2)
+#define PIN_PA28__D6 PINMUX_PIN(PIN_PA28, 2, 1)
+#define PIN_PA28__SPI0_NPCS3 PINMUX_PIN(PIN_PA28, 3, 2)
+#define PIN_PA28__SPI1_NPCS3 PINMUX_PIN(PIN_PA28, 4, 2)
+#define PIN_PA28__SDMMC1_CMD PINMUX_PIN(PIN_PA28, 5, 1)
+#define PIN_PA28__CLASSD_L0 PINMUX_PIN(PIN_PA28, 6, 1)
+#define PIN_PA29 29
+#define PIN_PA29__GPIO PINMUX_PIN(PIN_PA29, 0, 0)
+#define PIN_PA29__TCLK1 PINMUX_PIN(PIN_PA29, 1, 2)
+#define PIN_PA29__D7 PINMUX_PIN(PIN_PA29, 2, 1)
+#define PIN_PA29__SPI0_NPCS1 PINMUX_PIN(PIN_PA29, 3, 2)
+#define PIN_PA29__SDMMC1_WP PINMUX_PIN(PIN_PA29, 5, 1)
+#define PIN_PA29__CLASSD_L1 PINMUX_PIN(PIN_PA29, 6, 1)
+#define PIN_PA30 30
+#define PIN_PA30__GPIO PINMUX_PIN(PIN_PA30, 0, 0)
+#define PIN_PA30__NWE_NANDWE PINMUX_PIN(PIN_PA30, 2, 1)
+#define PIN_PA30__SPI0_NPCS0 PINMUX_PIN(PIN_PA30, 3, 2)
+#define PIN_PA30__PWMH0 PINMUX_PIN(PIN_PA30, 4, 1)
+#define PIN_PA30__SDMMC1_CD PINMUX_PIN(PIN_PA30, 5, 1)
+#define PIN_PA30__CLASSD_L2 PINMUX_PIN(PIN_PA30, 6, 1)
+#define PIN_PA31 31
+#define PIN_PA31__GPIO PINMUX_PIN(PIN_PA31, 0, 0)
+#define PIN_PA31__NCS3 PINMUX_PIN(PIN_PA31, 2, 1)
+#define PIN_PA31__SPI0_MISO PINMUX_PIN(PIN_PA31, 3, 2)
+#define PIN_PA31__PWML0 PINMUX_PIN(PIN_PA31, 4, 1)
+#define PIN_PA31__CLASSD_L3 PINMUX_PIN(PIN_PA31, 6, 1)
+#define PIN_PB0 32
+#define PIN_PB0__GPIO PINMUX_PIN(PIN_PB0, 0, 0)
+#define PIN_PB0__A21_NANDALE PINMUX_PIN(PIN_PB0, 2, 1)
+#define PIN_PB0__SPI0_MOSI PINMUX_PIN(PIN_PB0, 3, 2)
+#define PIN_PB0__PWMH1 PINMUX_PIN(PIN_PB0, 4, 1)
+#define PIN_PB1 33
+#define PIN_PB1__GPIO PINMUX_PIN(PIN_PB1, 0, 0)
+#define PIN_PB1__A22_NANDCLE PINMUX_PIN(PIN_PB1, 2, 1)
+#define PIN_PB1__SPI0_SPCK PINMUX_PIN(PIN_PB1, 3, 2)
+#define PIN_PB1__PWML1 PINMUX_PIN(PIN_PB1, 4, 1)
+#define PIN_PB1__CLASSD_R0 PINMUX_PIN(PIN_PB1, 6, 1)
+#define PIN_PB2 34
+#define PIN_PB2__GPIO PINMUX_PIN(PIN_PB2, 0, 0)
+#define PIN_PB2__NRD_NANDOE PINMUX_PIN(PIN_PB2, 2, 1)
+#define PIN_PB2__PWMFI0 PINMUX_PIN(PIN_PB2, 4, 1)
+#define PIN_PB2__CLASSD_R1 PINMUX_PIN(PIN_PB2, 6, 1)
+#define PIN_PB3 35
+#define PIN_PB3__GPIO PINMUX_PIN(PIN_PB3, 0, 0)
+#define PIN_PB3__URXD4 PINMUX_PIN(PIN_PB3, 1, 1)
+#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 2, 1)
+#define PIN_PB3__IRQ PINMUX_PIN(PIN_PB3, 3, 3)
+#define PIN_PB3__PWMEXTRG0 PINMUX_PIN(PIN_PB3, 4, 1)
+#define PIN_PB3__CLASSD_R2 PINMUX_PIN(PIN_PB3, 6, 1)
+#define PIN_PB4 36
+#define PIN_PB4__GPIO PINMUX_PIN(PIN_PB4, 0, 0)
+#define PIN_PB4__UTXD4 PINMUX_PIN(PIN_PB4, 1, 1)
+#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 2, 1)
+#define PIN_PB4__FIQ PINMUX_PIN(PIN_PB4, 3, 4)
+#define PIN_PB4__CLASSD_R3 PINMUX_PIN(PIN_PB4, 6, 1)
+#define PIN_PB5 37
+#define PIN_PB5__GPIO PINMUX_PIN(PIN_PB5, 0, 0)
+#define PIN_PB5__TCLK2 PINMUX_PIN(PIN_PB5, 1, 1)
+#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 2, 1)
+#define PIN_PB5__PWMH2 PINMUX_PIN(PIN_PB5, 3, 1)
+#define PIN_PB5__QSPI1_SCK PINMUX_PIN(PIN_PB5, 4, 2)
+#define PIN_PB5__GTSUCOMP PINMUX_PIN(PIN_PB5, 6, 3)
+#define PIN_PB6 38
+#define PIN_PB6__GPIO PINMUX_PIN(PIN_PB6, 0, 0)
+#define PIN_PB6__TIOA2 PINMUX_PIN(PIN_PB6, 1, 1)
+#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 2, 1)
+#define PIN_PB6__PWML2 PINMUX_PIN(PIN_PB6, 3, 1)
+#define PIN_PB6__QSPI1_CS PINMUX_PIN(PIN_PB6, 4, 2)
+#define PIN_PB6__GTXER PINMUX_PIN(PIN_PB6, 6, 3)
+#define PIN_PB7 39
+#define PIN_PB7__GPIO PINMUX_PIN(PIN_PB7, 0, 0)
+#define PIN_PB7__TIOB2 PINMUX_PIN(PIN_PB7, 1, 1)
+#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 2, 1)
+#define PIN_PB7__PWMH3 PINMUX_PIN(PIN_PB7, 3, 1)
+#define PIN_PB7__QSPI1_IO0 PINMUX_PIN(PIN_PB7, 4, 2)
+#define PIN_PB7__GRXCK PINMUX_PIN(PIN_PB7, 6, 3)
+#define PIN_PB8 40
+#define PIN_PB8__GPIO PINMUX_PIN(PIN_PB8, 0, 0)
+#define PIN_PB8__TCLK3 PINMUX_PIN(PIN_PB8, 1, 1)
+#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 2, 1)
+#define PIN_PB8__PWML3 PINMUX_PIN(PIN_PB8, 3, 1)
+#define PIN_PB8__QSPI1_IO1 PINMUX_PIN(PIN_PB8, 4, 2)
+#define PIN_PB8__GCRS PINMUX_PIN(PIN_PB8, 6, 3)
+#define PIN_PB9 41
+#define PIN_PB9__GPIO PINMUX_PIN(PIN_PB9, 0, 0)
+#define PIN_PB9__TIOA3 PINMUX_PIN(PIN_PB9, 1, 1)
+#define PIN_PB9__D14 PINMUX_PIN(PIN_PB9, 2, 1)
+#define PIN_PB9__PWMFI1 PINMUX_PIN(PIN_PB9, 3, 1)
+#define PIN_PB9__QSPI1_IO2 PINMUX_PIN(PIN_PB9, 4, 2)
+#define PIN_PB9__GCOL PINMUX_PIN(PIN_PB9, 6, 3)
+#define PIN_PB10 42
+#define PIN_PB10__GPIO PINMUX_PIN(PIN_PB10, 0, 0)
+#define PIN_PB10__TIOB3 PINMUX_PIN(PIN_PB10, 1, 1)
+#define PIN_PB10__D15 PINMUX_PIN(PIN_PB10, 2, 1)
+#define PIN_PB10__PWMEXTRG1 PINMUX_PIN(PIN_PB10, 3, 1)
+#define PIN_PB10__QSPI1_IO3 PINMUX_PIN(PIN_PB10, 4, 2)
+#define PIN_PB10__GRX2 PINMUX_PIN(PIN_PB10, 6, 3)
+#define PIN_PB11 43
+#define PIN_PB11__GPIO PINMUX_PIN(PIN_PB11, 0, 0)
+#define PIN_PB11__LCDDAT0 PINMUX_PIN(PIN_PB11, 1, 1)
+#define PIN_PB11__A0_NBS0 PINMUX_PIN(PIN_PB11, 2, 1)
+#define PIN_PB11__URXD3 PINMUX_PIN(PIN_PB11, 3, 3)
+#define PIN_PB11__PDMIC_DAT PINMUX_PIN(PIN_PB11, 4, 2)
+#define PIN_PB11__GRX3 PINMUX_PIN(PIN_PB11, 6, 3)
+#define PIN_PB12 44
+#define PIN_PB12__GPIO PINMUX_PIN(PIN_PB12, 0, 0)
+#define PIN_PB12__LCDDAT1 PINMUX_PIN(PIN_PB12, 1, 1)
+#define PIN_PB12__A1 PINMUX_PIN(PIN_PB12, 2, 1)
+#define PIN_PB12__UTXD3 PINMUX_PIN(PIN_PB12, 3, 3)
+#define PIN_PB12__PDMIC_CLK PINMUX_PIN(PIN_PB12, 4, 2)
+#define PIN_PB12__GTX2 PINMUX_PIN(PIN_PB12, 6, 3)
+#define PIN_PB13 45
+#define PIN_PB13__GPIO PINMUX_PIN(PIN_PB13, 0, 0)
+#define PIN_PB13__LCDDAT2 PINMUX_PIN(PIN_PB13, 1, 1)
+#define PIN_PB13__A2 PINMUX_PIN(PIN_PB13, 2, 1)
+#define PIN_PB13__PCK1 PINMUX_PIN(PIN_PB13, 3, 3)
+#define PIN_PB13__GTX3 PINMUX_PIN(PIN_PB13, 6, 3)
+#define PIN_PB14 46
+#define PIN_PB14__GPIO PINMUX_PIN(PIN_PB14, 0, 0)
+#define PIN_PB14__LCDDAT3 PINMUX_PIN(PIN_PB14, 1, 1)
+#define PIN_PB14__A3 PINMUX_PIN(PIN_PB14, 2, 1)
+#define PIN_PB14__TK1 PINMUX_PIN(PIN_PB14, 3, 2)
+#define PIN_PB14__I2SC1_MCK PINMUX_PIN(PIN_PB14, 4, 1)
+#define PIN_PB14__QSPI1_SCK PINMUX_PIN(PIN_PB14, 5, 3)
+#define PIN_PB14__GTXCK PINMUX_PIN(PIN_PB14, 6, 3)
+#define PIN_PB15 47
+#define PIN_PB15__GPIO PINMUX_PIN(PIN_PB15, 0, 0)
+#define PIN_PB15__LCDDAT4 PINMUX_PIN(PIN_PB15, 1, 1)
+#define PIN_PB15__A4 PINMUX_PIN(PIN_PB15, 2, 1)
+#define PIN_PB15__TF1 PINMUX_PIN(PIN_PB15, 3, 2)
+#define PIN_PB15__I2SC1_CK PINMUX_PIN(PIN_PB15, 4, 1)
+#define PIN_PB15__QSPI1_CS PINMUX_PIN(PIN_PB15, 5, 3)
+#define PIN_PB15__GTXEN PINMUX_PIN(PIN_PB15, 6, 3)
+#define PIN_PB16 48
+#define PIN_PB16__GPIO PINMUX_PIN(PIN_PB16, 0, 0)
+#define PIN_PB16__LCDDAT5 PINMUX_PIN(PIN_PB16, 1, 1)
+#define PIN_PB16__A5 PINMUX_PIN(PIN_PB16, 2, 1)
+#define PIN_PB16__TD1 PINMUX_PIN(PIN_PB16, 3, 2)
+#define PIN_PB16__I2SC1_WS PINMUX_PIN(PIN_PB16, 4, 1)
+#define PIN_PB16__QSPI1_IO0 PINMUX_PIN(PIN_PB16, 5, 3)
+#define PIN_PB16__GRXDV PINMUX_PIN(PIN_PB16, 6, 3)
+#define PIN_PB17 49
+#define PIN_PB17__GPIO PINMUX_PIN(PIN_PB17, 0, 0)
+#define PIN_PB17__LCDDAT6 PINMUX_PIN(PIN_PB17, 1, 1)
+#define PIN_PB17__A6 PINMUX_PIN(PIN_PB17, 2, 1)
+#define PIN_PB17__RD1 PINMUX_PIN(PIN_PB17, 3, 2)
+#define PIN_PB17__I2SC1_DI0 PINMUX_PIN(PIN_PB17, 4, 1)
+#define PIN_PB17__QSPI1_IO1 PINMUX_PIN(PIN_PB17, 5, 3)
+#define PIN_PB17__GRXER PINMUX_PIN(PIN_PB17, 6, 3)
+#define PIN_PB18 50
+#define PIN_PB18__GPIO PINMUX_PIN(PIN_PB18, 0, 0)
+#define PIN_PB18__LCDDAT7 PINMUX_PIN(PIN_PB18, 1, 1)
+#define PIN_PB18__A7 PINMUX_PIN(PIN_PB18, 2, 1)
+#define PIN_PB18__RK1 PINMUX_PIN(PIN_PB18, 3, 2)
+#define PIN_PB18__I2SC1_DO0 PINMUX_PIN(PIN_PB18, 4, 1)
+#define PIN_PB18__QSPI1_IO2 PINMUX_PIN(PIN_PB18, 5, 3)
+#define PIN_PB18__GRX0 PINMUX_PIN(PIN_PB18, 6, 3)
+#define PIN_PB19 51
+#define PIN_PB19__GPIO PINMUX_PIN(PIN_PB19, 0, 0)
+#define PIN_PB19__LCDDAT8 PINMUX_PIN(PIN_PB19, 1, 1)
+#define PIN_PB19__A8 PINMUX_PIN(PIN_PB19, 2, 1)
+#define PIN_PB19__RF1 PINMUX_PIN(PIN_PB19, 3, 2)
+#define PIN_PB19__TIOA3 PINMUX_PIN(PIN_PB19, 4, 2)
+#define PIN_PB19__QSPI1_IO3 PINMUX_PIN(PIN_PB19, 5, 3)
+#define PIN_PB19__GRX1 PINMUX_PIN(PIN_PB19, 6, 3)
+#define PIN_PB20 52
+#define PIN_PB20__GPIO PINMUX_PIN(PIN_PB20, 0, 0)
+#define PIN_PB20__LCDDAT9 PINMUX_PIN(PIN_PB20, 1, 1)
+#define PIN_PB20__A9 PINMUX_PIN(PIN_PB20, 2, 1)
+#define PIN_PB20__TK0 PINMUX_PIN(PIN_PB20, 3, 1)
+#define PIN_PB20__TIOB3 PINMUX_PIN(PIN_PB20, 4, 2)
+#define PIN_PB20__PCK1 PINMUX_PIN(PIN_PB20, 5, 4)
+#define PIN_PB20__GTX0 PINMUX_PIN(PIN_PB20, 6, 3)
+#define PIN_PB21 53
+#define PIN_PB21__GPIO PINMUX_PIN(PIN_PB21, 0, 0)
+#define PIN_PB21__LCDDAT10 PINMUX_PIN(PIN_PB21, 1, 1)
+#define PIN_PB21__A10 PINMUX_PIN(PIN_PB21, 2, 1)
+#define PIN_PB21__TF0 PINMUX_PIN(PIN_PB21, 3, 1)
+#define PIN_PB21__TCLK3 PINMUX_PIN(PIN_PB21, 4, 2)
+#define PIN_PB21__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB21, 5, 3)
+#define PIN_PB21__GTX1 PINMUX_PIN(PIN_PB21, 6, 3)
+#define PIN_PB22 54
+#define PIN_PB22__GPIO PINMUX_PIN(PIN_PB22, 0, 0)
+#define PIN_PB22__LCDDAT11 PINMUX_PIN(PIN_PB22, 1, 1)
+#define PIN_PB22__A11 PINMUX_PIN(PIN_PB22, 2, 1)
+#define PIN_PB22__TDO PINMUX_PIN(PIN_PB22, 3, 1)
+#define PIN_PB22__TIOA2 PINMUX_PIN(PIN_PB22, 4, 2)
+#define PIN_PB22__FLEXCOM3_IO1 PINMUX_PIN(PIN_PB22, 5, 3)
+#define PIN_PB22__GMDC PINMUX_PIN(PIN_PB22, 6, 3)
+#define PIN_PB23 55
+#define PIN_PB23__GPIO PINMUX_PIN(PIN_PB23, 0, 0)
+#define PIN_PB23__LCDDAT12 PINMUX_PIN(PIN_PB23, 1, 1)
+#define PIN_PB23__A12 PINMUX_PIN(PIN_PB23, 2, 1)
+#define PIN_PB23__RD0 PINMUX_PIN(PIN_PB23, 3, 1)
+#define PIN_PB23__TIOB2 PINMUX_PIN(PIN_PB23, 4, 2)
+#define PIN_PB23__FLEXCOM3_IO0 PINMUX_PIN(PIN_PB23, 5, 3)
+#define PIN_PB23__GMDIO PINMUX_PIN(PIN_PB23, 6, 3)
+#define PIN_PB24 56
+#define PIN_PB24__GPIO PINMUX_PIN(PIN_PB24, 0, 0)
+#define PIN_PB24__LCDDAT13 PINMUX_PIN(PIN_PB24, 1, 1)
+#define PIN_PB24__A13 PINMUX_PIN(PIN_PB24, 2, 1)
+#define PIN_PB24__RK0 PINMUX_PIN(PIN_PB24, 3, 1)
+#define PIN_PB24__TCLK2 PINMUX_PIN(PIN_PB24, 4, 2)
+#define PIN_PB24__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB24, 5, 3)
+#define PIN_PB24__ISC_D10 PINMUX_PIN(PIN_PB24, 6, 3)
+#define PIN_PB25 57
+#define PIN_PB25__GPIO PINMUX_PIN(PIN_PB25, 0, 0)
+#define PIN_PB25__LCDDAT14 PINMUX_PIN(PIN_PB25, 1, 1)
+#define PIN_PB25__A14 PINMUX_PIN(PIN_PB25, 2, 1)
+#define PIN_PB25__RF0 PINMUX_PIN(PIN_PB25, 3, 1)
+#define PIN_PB25__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB25, 5, 3)
+#define PIN_PB25__ISC_D11 PINMUX_PIN(PIN_PB25, 6, 3)
+#define PIN_PB26 58
+#define PIN_PB26__GPIO PINMUX_PIN(PIN_PB26, 0, 0)
+#define PIN_PB26__LCDDAT15 PINMUX_PIN(PIN_PB26, 1, 1)
+#define PIN_PB26__A15 PINMUX_PIN(PIN_PB26, 2, 1)
+#define PIN_PB26__URXD0 PINMUX_PIN(PIN_PB26, 3, 1)
+#define PIN_PB26__PDMIC_DAT PINMUX_PIN(PIN_PB26, 4, 1)
+#define PIN_PB26__ISC_D0 PINMUX_PIN(PIN_PB26, 6, 3)
+#define PIN_PB27 59
+#define PIN_PB27__GPIO PINMUX_PIN(PIN_PB27, 0, 0)
+#define PIN_PB27__LCDDAT16 PINMUX_PIN(PIN_PB27, 1, 1)
+#define PIN_PB27__A16 PINMUX_PIN(PIN_PB27, 2, 1)
+#define PIN_PB27__UTXD0 PINMUX_PIN(PIN_PB27, 3, 1)
+#define PIN_PB27__PDMIC_CLK PINMUX_PIN(PIN_PB27, 4, 1)
+#define PIN_PB27__ISC_D1 PINMUX_PIN(PIN_PB27, 6, 3)
+#define PIN_PB28 60
+#define PIN_PB28__GPIO PINMUX_PIN(PIN_PB28, 0, 0)
+#define PIN_PB28__LCDDAT17 PINMUX_PIN(PIN_PB28, 1, 1)
+#define PIN_PB28__A17 PINMUX_PIN(PIN_PB28, 2, 1)
+#define PIN_PB28__FLEXCOM0_IO0 PINMUX_PIN(PIN_PB28, 3, 1)
+#define PIN_PB28__TIOA5 PINMUX_PIN(PIN_PB28, 4, 2)
+#define PIN_PB28__ISC_D2 PINMUX_PIN(PIN_PB28, 6, 3)
+#define PIN_PB29 61
+#define PIN_PB29__GPIO PINMUX_PIN(PIN_PB29, 0, 0)
+#define PIN_PB29__LCDDAT18 PINMUX_PIN(PIN_PB29, 1, 1)
+#define PIN_PB29__A18 PINMUX_PIN(PIN_PB29, 2, 1)
+#define PIN_PB29__FLEXCOM0_IO1 PINMUX_PIN(PIN_PB29, 3, 1)
+#define PIN_PB29__TIOB5 PINMUX_PIN(PIN_PB29, 4, 2)
+#define PIN_PB29__ISC_D3 PINMUX_PIN(PIN_PB29, 7, 3)
+#define PIN_PB30 62
+#define PIN_PB30__GPIO PINMUX_PIN(PIN_PB30, 0, 0)
+#define PIN_PB30__LCDDAT19 PINMUX_PIN(PIN_PB30, 1, 1)
+#define PIN_PB30__A19 PINMUX_PIN(PIN_PB30, 2, 1)
+#define PIN_PB30__FLEXCOM0_IO2 PINMUX_PIN(PIN_PB30, 3, 1)
+#define PIN_PB30__TCLK5 PINMUX_PIN(PIN_PB30, 4, 2)
+#define PIN_PB30__ISC_D4 PINMUX_PIN(PIN_PB30, 6, 3)
+#define PIN_PB31 63
+#define PIN_PB31__GPIO PINMUX_PIN(PIN_PB31, 0, 0)
+#define PIN_PB31__LCDDAT20 PINMUX_PIN(PIN_PB31, 1, 1)
+#define PIN_PB31__A20 PINMUX_PIN(PIN_PB31, 2, 1)
+#define PIN_PB31__FLEXCOM0_IO3 PINMUX_PIN(PIN_PB31, 3, 1)
+#define PIN_PB31__TWD0 PINMUX_PIN(PIN_PB31, 4, 1)
+#define PIN_PB31__ISC_D5 PINMUX_PIN(PIN_PB31, 6, 3)
+#define PIN_PC0 64
+#define PIN_PC0__GPIO PINMUX_PIN(PIN_PC0, 0, 0)
+#define PIN_PC0__LCDDAT21 PINMUX_PIN(PIN_PC0, 1, 1)
+#define PIN_PC0__A23 PINMUX_PIN(PIN_PC0, 2, 1)
+#define PIN_PC0__FLEXCOM0_IO4 PINMUX_PIN(PIN_PC0, 3, 1)
+#define PIN_PC0__TWCK0 PINMUX_PIN(PIN_PC0, 4, 1)
+#define PIN_PC0__ISC_D6 PINMUX_PIN(PIN_PC0, 6, 3)
+#define PIN_PC1 65
+#define PIN_PC1__GPIO PINMUX_PIN(PIN_PC1, 0, 0)
+#define PIN_PC1__LCDDAT22 PINMUX_PIN(PIN_PC1, 1, 1)
+#define PIN_PC1__A24 PINMUX_PIN(PIN_PC1, 2, 1)
+#define PIN_PC1__CANTX0 PINMUX_PIN(PIN_PC1, 3, 1)
+#define PIN_PC1__SPI1_SPCK PINMUX_PIN(PIN_PC1, 4, 1)
+#define PIN_PC1__I2SC0_CK PINMUX_PIN(PIN_PC1, 5, 1)
+#define PIN_PC1__ISC_D7 PINMUX_PIN(PIN_PC1, 6, 3)
+#define PIN_PC2 66
+#define PIN_PC2__GPIO PINMUX_PIN(PIN_PC2, 0, 0)
+#define PIN_PC2__LCDDAT23 PINMUX_PIN(PIN_PC2, 1, 1)
+#define PIN_PC2__A25 PINMUX_PIN(PIN_PC2, 2, 1)
+#define PIN_PC2__CANRX0 PINMUX_PIN(PIN_PC2, 3, 1)
+#define PIN_PC2__SPI1_MOSI PINMUX_PIN(PIN_PC2, 4, 1)
+#define PIN_PC2__I2SC0_MCK PINMUX_PIN(PIN_PC2, 5, 1)
+#define PIN_PC2__ISC_D8 PINMUX_PIN(PIN_PC2, 6, 3)
+#define PIN_PC3 67
+#define PIN_PC3__GPIO PINMUX_PIN(PIN_PC3, 0, 0)
+#define PIN_PC3__LCDPWM PINMUX_PIN(PIN_PC3, 1, 1)
+#define PIN_PC3__NWAIT PINMUX_PIN(PIN_PC3, 2, 1)
+#define PIN_PC3__TIOA1 PINMUX_PIN(PIN_PC3, 3, 1)
+#define PIN_PC3__SPI1_MISO PINMUX_PIN(PIN_PC3, 4, 1)
+#define PIN_PC3__I2SC0_WS PINMUX_PIN(PIN_PC3, 5, 1)
+#define PIN_PC3__ISC_D9 PINMUX_PIN(PIN_PC3, 6, 3)
+#define PIN_PC4 68
+#define PIN_PC4__GPIO PINMUX_PIN(PIN_PC4, 0, 0)
+#define PIN_PC4__LCDDISP PINMUX_PIN(PIN_PC4, 1, 1)
+#define PIN_PC4__NWR1_NBS1 PINMUX_PIN(PIN_PC4, 2, 1)
+#define PIN_PC4__TIOB1 PINMUX_PIN(PIN_PC4, 3, 1)
+#define PIN_PC4__SPI1_NPCS0 PINMUX_PIN(PIN_PC4, 4, 1)
+#define PIN_PC4__I2SC0_DI0 PINMUX_PIN(PIN_PC4, 5, 1)
+#define PIN_PC4__ISC_PCK PINMUX_PIN(PIN_PC4, 6, 3)
+#define PIN_PC5 69
+#define PIN_PC5__GPIO PINMUX_PIN(PIN_PC5, 0, 0)
+#define PIN_PC5__LCDVSYNC PINMUX_PIN(PIN_PC5, 1, 1)
+#define PIN_PC5__NCS0 PINMUX_PIN(PIN_PC5, 2, 1)
+#define PIN_PC5__TCLK1 PINMUX_PIN(PIN_PC5, 3, 1)
+#define PIN_PC5__SPI1_NPCS1 PINMUX_PIN(PIN_PC5, 4, 1)
+#define PIN_PC5__I2SC0_DO0 PINMUX_PIN(PIN_PC5, 5, 1)
+#define PIN_PC5__ISC_VSYNC PINMUX_PIN(PIN_PC5, 6, 3)
+#define PIN_PC6 70
+#define PIN_PC6__GPIO PINMUX_PIN(PIN_PC6, 0, 0)
+#define PIN_PC6__LCDHSYNC PINMUX_PIN(PIN_PC6, 1, 1)
+#define PIN_PC6__NCS1 PINMUX_PIN(PIN_PC6, 2, 1)
+#define PIN_PC6__TWD1 PINMUX_PIN(PIN_PC6, 3, 1)
+#define PIN_PC6__SPI1_NPCS2 PINMUX_PIN(PIN_PC6, 4, 1)
+#define PIN_PC6__ISC_HSYNC PINMUX_PIN(PIN_PC6, 6, 3)
+#define PIN_PC7 71
+#define PIN_PC7__GPIO PINMUX_PIN(PIN_PC7, 0, 0)
+#define PIN_PC7__LCDPCK PINMUX_PIN(PIN_PC7, 1, 1)
+#define PIN_PC7__NCS2 PINMUX_PIN(PIN_PC7, 2, 1)
+#define PIN_PC7__TWCK1 PINMUX_PIN(PIN_PC7, 3, 1)
+#define PIN_PC7__SPI1_NPCS3 PINMUX_PIN(PIN_PC7, 4, 1)
+#define PIN_PC7__URXD1 PINMUX_PIN(PIN_PC7, 5, 2)
+#define PIN_PC7__ISC_MCK PINMUX_PIN(PIN_PC7, 6, 3)
+#define PIN_PC8 72
+#define PIN_PC8__GPIO PINMUX_PIN(PIN_PC8, 0, 0)
+#define PIN_PC8__LCDDEN PINMUX_PIN(PIN_PC8, 1, 1)
+#define PIN_PC8__NANDRDY PINMUX_PIN(PIN_PC8, 2, 1)
+#define PIN_PC8__FIQ PINMUX_PIN(PIN_PC8, 3, 1)
+#define PIN_PC8__PCK0 PINMUX_PIN(PIN_PC8, 4, 3)
+#define PIN_PC8__UTXD1 PINMUX_PIN(PIN_PC8, 5, 2)
+#define PIN_PC8__ISC_FIELD PINMUX_PIN(PIN_PC8, 6, 3)
+#define PIN_PC9 73
+#define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0)
+#define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 1, 3)
+#define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 2, 1)
+#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 2, 1)
+#define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 4, 2)
+#define PIN_PC10 74
+#define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0)
+#define PIN_PC10__LCDDAT2 PINMUX_PIN(PIN_PC10, 1, 2)
+#define PIN_PC10__GTXCK PINMUX_PIN(PIN_PC10, 2, 1)
+#define PIN_PC10__ISC_D1 PINMUX_PIN(PIN_PC10, 3, 1)
+#define PIN_PC10__TIOB4 PINMUX_PIN(PIN_PC10, 4, 2)
+#define PIN_PC10__CANTX0 PINMUX_PIN(PIN_PC10, 5, 2)
+#define PIN_PC11 75
+#define PIN_PC11__GPIO PINMUX_PIN(PIN_PC11, 0, 0)
+#define PIN_PC11__LCDDAT3 PINMUX_PIN(PIN_PC11, 1, 2)
+#define PIN_PC11__GTXEN PINMUX_PIN(PIN_PC11, 2, 1)
+#define PIN_PC11__ISC_D2 PINMUX_PIN(PIN_PC11, 3, 1)
+#define PIN_PC11__TCLK4 PINMUX_PIN(PIN_PC11, 4, 2)
+#define PIN_PC11__CANRX0 PINMUX_PIN(PIN_PC11, 5, 2)
+#define PIN_PC11__A0_NBS0 PINMUX_PIN(PIN_PC11, 6, 2)
+#define PIN_PC12 76
+#define PIN_PC12__GPIO PINMUX_PIN(PIN_PC12, 0, 0)
+#define PIN_PC12__LCDDAT4 PINMUX_PIN(PIN_PC12, 1, 2)
+#define PIN_PC12__GRXDV PINMUX_PIN(PIN_PC12, 2, 1)
+#define PIN_PC12__ISC_D3 PINMUX_PIN(PIN_PC12, 3, 1)
+#define PIN_PC12__URXD3 PINMUX_PIN(PIN_PC12, 4, 1)
+#define PIN_PC12__TK0 PINMUX_PIN(PIN_PC12, 5, 2)
+#define PIN_PC12__A1 PINMUX_PIN(PIN_PC12, 6, 2)
+#define PIN_PC13 77
+#define PIN_PC13__GPIO PINMUX_PIN(PIN_PC13, 0, 0)
+#define PIN_PC13__LCDDAT5 PINMUX_PIN(PIN_PC13, 1, 2)
+#define PIN_PC13__GRXER PINMUX_PIN(PIN_PC13, 2, 1)
+#define PIN_PC13__ISC_D4 PINMUX_PIN(PIN_PC13, 3, 1)
+#define PIN_PC13__UTXD3 PINMUX_PIN(PIN_PC13, 4, 1)
+#define PIN_PC13__TF0 PINMUX_PIN(PIN_PC13, 5, 2)
+#define PIN_PC13__A2 PINMUX_PIN(PIN_PC13, 6, 2)
+#define PIN_PC14 78
+#define PIN_PC14__GPIO PINMUX_PIN(PIN_PC14, 0, 0)
+#define PIN_PC14__LCDDAT6 PINMUX_PIN(PIN_PC14, 1, 2)
+#define PIN_PC14__GRX0 PINMUX_PIN(PIN_PC14, 2, 1)
+#define PIN_PC14__ISC_D5 PINMUX_PIN(PIN_PC14, 3, 1)
+#define PIN_PC14__TDO PINMUX_PIN(PIN_PC14, 5, 2)
+#define PIN_PC14__A3 PINMUX_PIN(PIN_PC14, 6, 2)
+#define PIN_PC15 79
+#define PIN_PC15__GPIO PINMUX_PIN(PIN_PC15, 0, 0)
+#define PIN_PC15__LCDDAT7 PINMUX_PIN(PIN_PC15, 1, 2)
+#define PIN_PC15__GRX1 PINMUX_PIN(PIN_PC15, 2, 1)
+#define PIN_PC15__ISC_D6 PINMUX_PIN(PIN_PC15, 3, 1)
+#define PIN_PC15__RD0 PINMUX_PIN(PIN_PC15, 5, 2)
+#define PIN_PC15__A4 PINMUX_PIN(PIN_PC15, 6, 2)
+#define PIN_PC16 80
+#define PIN_PC16__GPIO PINMUX_PIN(PIN_PC16, 0, 0)
+#define PIN_PC16__LCDDAT10 PINMUX_PIN(PIN_PC16, 1, 2)
+#define PIN_PC16__GTX0 PINMUX_PIN(PIN_PC16, 2, 1)
+#define PIN_PC16__ISC_D7 PINMUX_PIN(PIN_PC16, 3, 1)
+#define PIN_PC16__RK0 PINMUX_PIN(PIN_PC16, 5, 2)
+#define PIN_PC16__A5 PINMUX_PIN(PIN_PC16, 6, 2)
+#define PIN_PC17 81
+#define PIN_PC17__GPIO PINMUX_PIN(PIN_PC17, 0, 0)
+#define PIN_PC17__LCDDAT11 PINMUX_PIN(PIN_PC17, 1, 2)
+#define PIN_PC17__GTX1 PINMUX_PIN(PIN_PC17, 2, 1)
+#define PIN_PC17__ISC_D8 PINMUX_PIN(PIN_PC17, 3, 1)
+#define PIN_PC17__RF0 PINMUX_PIN(PIN_PC17, 5, 2)
+#define PIN_PC17__A6 PINMUX_PIN(PIN_PC17, 6, 2)
+#define PIN_PC18 82
+#define PIN_PC18__GPIO PINMUX_PIN(PIN_PC18, 0, 0)
+#define PIN_PC18__LCDDAT12 PINMUX_PIN(PIN_PC18, 1, 2)
+#define PIN_PC18__GMDC PINMUX_PIN(PIN_PC18, 2, 1)
+#define PIN_PC18__ISC_D9 PINMUX_PIN(PIN_PC18, 3, 1)
+#define PIN_PC18__FLEXCOM3_IO2 PINMUX_PIN(PIN_PC18, 5, 2)
+#define PIN_PC18__A7 PINMUX_PIN(PIN_PC18, 6, 2)
+#define PIN_PC19 83
+#define PIN_PC19__GPIO PINMUX_PIN(PIN_PC19, 0, 0)
+#define PIN_PC19__LCDDAT13 PINMUX_PIN(PIN_PC19, 1, 2)
+#define PIN_PC19__GMDIO PINMUX_PIN(PIN_PC19, 2, 1)
+#define PIN_PC19__ISC_D10 PINMUX_PIN(PIN_PC19, 3, 1)
+#define PIN_PC19__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC19, 5, 2)
+#define PIN_PC19__A8 PINMUX_PIN(PIN_PC19, 6, 2)
+#define PIN_PC20 84
+#define PIN_PC20__GPIO PINMUX_PIN(PIN_PC20, 0, 0)
+#define PIN_PC20__LCDDAT14 PINMUX_PIN(PIN_PC20, 1, 2)
+#define PIN_PC20__GRXCK PINMUX_PIN(PIN_PC20, 2, 1)
+#define PIN_PC20__ISC_D11 PINMUX_PIN(PIN_PC20, 3, 1)
+#define PIN_PC20__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC20, 5, 2)
+#define PIN_PC20__A9 PINMUX_PIN(PIN_PC20, 6, 2)
+#define PIN_PC21 85
+#define PIN_PC21__GPIO PINMUX_PIN(PIN_PC21, 0, 0)
+#define PIN_PC21__LCDDAT15 PINMUX_PIN(PIN_PC21, 1, 2)
+#define PIN_PC21__GTXER PINMUX_PIN(PIN_PC21, 2, 1)
+#define PIN_PC21__ISC_PCK PINMUX_PIN(PIN_PC21, 3, 1)
+#define PIN_PC21__FLEXCOM3_IO3 PINMUX_PIN(PIN_PC21, 5, 2)
+#define PIN_PC21__A10 PINMUX_PIN(PIN_PC21, 6, 2)
+#define PIN_PC22 86
+#define PIN_PC22__GPIO PINMUX_PIN(PIN_PC22, 0, 0)
+#define PIN_PC22__LCDDAT18 PINMUX_PIN(PIN_PC22, 1, 2)
+#define PIN_PC22__GCRS PINMUX_PIN(PIN_PC22, 2, 1)
+#define PIN_PC22__ISC_VSYNC PINMUX_PIN(PIN_PC22, 3, 1)
+#define PIN_PC22__FLEXCOM3_IO4 PINMUX_PIN(PIN_PC22, 5, 2)
+#define PIN_PC22__A11 PINMUX_PIN(PIN_PC22, 6, 2)
+#define PIN_PC23 87
+#define PIN_PC23__GPIO PINMUX_PIN(PIN_PC23, 0, 0)
+#define PIN_PC23__LCDDAT19 PINMUX_PIN(PIN_PC23, 1, 2)
+#define PIN_PC23__GCOL PINMUX_PIN(PIN_PC23, 2, 1)
+#define PIN_PC23__ISC_HSYNC PINMUX_PIN(PIN_PC23, 3, 1)
+#define PIN_PC23__A12 PINMUX_PIN(PIN_PC23, 6, 2)
+#define PIN_PC24 88
+#define PIN_PC24__GPIO PINMUX_PIN(PIN_PC24, 0, 0)
+#define PIN_PC24__LCDDAT20 PINMUX_PIN(PIN_PC24, 1, 2)
+#define PIN_PC24__GRX2 PINMUX_PIN(PIN_PC24, 2, 1)
+#define PIN_PC24__ISC_MCK PINMUX_PIN(PIN_PC24, 3, 1)
+#define PIN_PC24__A13 PINMUX_PIN(PIN_PC24, 6, 2)
+#define PIN_PC25 89
+#define PIN_PC25__GPIO PINMUX_PIN(PIN_PC25, 0, 0)
+#define PIN_PC25__LCDDAT21 PINMUX_PIN(PIN_PC25, 1, 2)
+#define PIN_PC25__GRX3 PINMUX_PIN(PIN_PC25, 2, 1)
+#define PIN_PC25__ISC_FIELD PINMUX_PIN(PIN_PC25, 3, 1)
+#define PIN_PC25__A14 PINMUX_PIN(PIN_PC25, 6, 2)
+#define PIN_PC26 90
+#define PIN_PC26__GPIO PINMUX_PIN(PIN_PC26, 0, 0)
+#define PIN_PC26__LCDDAT22 PINMUX_PIN(PIN_PC26, 1, 2)
+#define PIN_PC26__GTX2 PINMUX_PIN(PIN_PC26, 2, 1)
+#define PIN_PC26__CANTX1 PINMUX_PIN(PIN_PC26, 4, 1)
+#define PIN_PC26__A15 PINMUX_PIN(PIN_PC26, 6, 2)
+#define PIN_PC27 91
+#define PIN_PC27__GPIO PINMUX_PIN(PIN_PC27, 0, 0)
+#define PIN_PC27__LCDDAT23 PINMUX_PIN(PIN_PC27, 1, 2)
+#define PIN_PC27__GTX3 PINMUX_PIN(PIN_PC27, 2, 1)
+#define PIN_PC27__PCK1 PINMUX_PIN(PIN_PC27, 3, 2)
+#define PIN_PC27__CANRX1 PINMUX_PIN(PIN_PC27, 4, 1)
+#define PIN_PC27__TWD0 PINMUX_PIN(PIN_PC27, 5, 2)
+#define PIN_PC27__A16 PINMUX_PIN(PIN_PC27, 6, 2)
+#define PIN_PC28 92
+#define PIN_PC28__GPIO PINMUX_PIN(PIN_PC28, 0, 0)
+#define PIN_PC28__LCDPWM PINMUX_PIN(PIN_PC28, 1, 2)
+#define PIN_PC28__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC28, 2, 1)
+#define PIN_PC28__PCK2 PINMUX_PIN(PIN_PC28, 3, 2)
+#define PIN_PC28__TWCK0 PINMUX_PIN(PIN_PC28, 5, 2)
+#define PIN_PC28__A17 PINMUX_PIN(PIN_PC28, 6, 2)
+#define PIN_PC29 93
+#define PIN_PC29__GPIO PINMUX_PIN(PIN_PC29, 0, 0)
+#define PIN_PC29__LCDDISP PINMUX_PIN(PIN_PC29, 1, 2)
+#define PIN_PC29__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC29, 2, 1)
+#define PIN_PC29__A18 PINMUX_PIN(PIN_PC29, 6, 2)
+#define PIN_PC30 94
+#define PIN_PC30__GPIO PINMUX_PIN(PIN_PC30, 0, 0)
+#define PIN_PC30__LCDVSYNC PINMUX_PIN(PIN_PC30, 1, 2)
+#define PIN_PC30__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC30, 2, 1)
+#define PIN_PC30__A19 PINMUX_PIN(PIN_PC30, 6, 2)
+#define PIN_PC31 95
+#define PIN_PC31__GPIO PINMUX_PIN(PIN_PC31, 0, 0)
+#define PIN_PC31__LCDHSYNC PINMUX_PIN(PIN_PC31, 1, 2)
+#define PIN_PC31__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC31, 2, 1)
+#define PIN_PC31__URXD3 PINMUX_PIN(PIN_PC31, 3, 2)
+#define PIN_PC31__A20 PINMUX_PIN(PIN_PC31, 6, 2)
+#define PIN_PD0 96
+#define PIN_PD0__GPIO PINMUX_PIN(PIN_PD0, 0, 0)
+#define PIN_PD0__LCDPCK PINMUX_PIN(PIN_PD0, 1, 2)
+#define PIN_PD0__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD0, 2, 1)
+#define PIN_PD0__UTXD3 PINMUX_PIN(PIN_PD0, 3, 2)
+#define PIN_PD0__GTSUCOMP PINMUX_PIN(PIN_PD0, 4, 2)
+#define PIN_PD0__A23 PINMUX_PIN(PIN_PD0, 6, 2)
+#define PIN_PD1 97
+#define PIN_PD1__GPIO PINMUX_PIN(PIN_PD1, 0, 0)
+#define PIN_PD1__LCDDEN PINMUX_PIN(PIN_PD1, 1, 2)
+#define PIN_PD1__GRXCK PINMUX_PIN(PIN_PD1, 4, 2)
+#define PIN_PD1__A24 PINMUX_PIN(PIN_PD1, 6, 2)
+#define PIN_PD2 98
+#define PIN_PD2__GPIO PINMUX_PIN(PIN_PD2, 0, 0)
+#define PIN_PD2__URXD1 PINMUX_PIN(PIN_PD2, 1, 1)
+#define PIN_PD2__GTXER PINMUX_PIN(PIN_PD2, 4, 2)
+#define PIN_PD2__ISC_MCK PINMUX_PIN(PIN_PD2, 5, 2)
+#define PIN_PD2__A25 PINMUX_PIN(PIN_PD2, 6, 2)
+#define PIN_PD3 99
+#define PIN_PD3__GPIO PINMUX_PIN(PIN_PD3, 0, 0)
+#define PIN_PD3__UTXD1 PINMUX_PIN(PIN_PD3, 1, 1)
+#define PIN_PD3__FIQ PINMUX_PIN(PIN_PD3, 2, 2)
+#define PIN_PD3__GCRS PINMUX_PIN(PIN_PD3, 4, 2)
+#define PIN_PD3__ISC_D11 PINMUX_PIN(PIN_PD3, 5, 2)
+#define PIN_PD3__NWAIT PINMUX_PIN(PIN_PD3, 6, 2)
+#define PIN_PD4 100
+#define PIN_PD4__GPIO PINMUX_PIN(PIN_PD4, 0, 0)
+#define PIN_PD4__TWD1 PINMUX_PIN(PIN_PD4, 1, 2)
+#define PIN_PD4__URXD2 PINMUX_PIN(PIN_PD4, 2, 1)
+#define PIN_PD4__GCOL PINMUX_PIN(PIN_PD4, 4, 2)
+#define PIN_PD4__ISC_D10 PINMUX_PIN(PIN_PD4, 5, 2)
+#define PIN_PD4__NCS0 PINMUX_PIN(PIN_PD4, 6, 2)
+#define PIN_PD5 101
+#define PIN_PD5__GPIO PINMUX_PIN(PIN_PD5, 0, 0)
+#define PIN_PD5__TWCK1 PINMUX_PIN(PIN_PD5, 1, 2)
+#define PIN_PD5__UTXD2 PINMUX_PIN(PIN_PD5, 2, 1)
+#define PIN_PD5__GRX2 PINMUX_PIN(PIN_PD5, 4, 2)
+#define PIN_PD5__ISC_D9 PINMUX_PIN(PIN_PD5, 5, 2)
+#define PIN_PD5__NCS1 PINMUX_PIN(PIN_PD5, 6, 2)
+#define PIN_PD6 102
+#define PIN_PD6__GPIO PINMUX_PIN(PIN_PD6, 0, 0)
+#define PIN_PD6__TCK PINMUX_PIN(PIN_PD6, 1, 2)
+#define PIN_PD6__PCK1 PINMUX_PIN(PIN_PD6, 2, 1)
+#define PIN_PD6__GRX3 PINMUX_PIN(PIN_PD6, 4, 2)
+#define PIN_PD6__ISC_D8 PINMUX_PIN(PIN_PD6, 5, 2)
+#define PIN_PD6__NCS2 PINMUX_PIN(PIN_PD6, 6, 2)
+#define PIN_PD7 103
+#define PIN_PD7__GPIO PINMUX_PIN(PIN_PD7, 0, 0)
+#define PIN_PD7__TDI PINMUX_PIN(PIN_PD7, 1, 2)
+#define PIN_PD7__UTMI_RXVAL PINMUX_PIN(PIN_PD7, 3, 1)
+#define PIN_PD7__GTX2 PINMUX_PIN(PIN_PD7, 4, 2)
+#define PIN_PD7__ISC_D0 PINMUX_PIN(PIN_PD7, 5, 2)
+#define PIN_PD7__NWR1_NBS1 PINMUX_PIN(PIN_PD7, 6, 2)
+#define PIN_PD8 104
+#define PIN_PD8__GPIO PINMUX_PIN(PIN_PD8, 0, 0)
+#define PIN_PD8__TDO PINMUX_PIN(PIN_PD8, 1, 2)
+#define PIN_PD8__UTMI_RXERR PINMUX_PIN(PIN_PD8, 3, 1)
+#define PIN_PD8__GTX3 PINMUX_PIN(PIN_PD8, 4, 2)
+#define PIN_PD8__ISC_D1 PINMUX_PIN(PIN_PD8, 5, 2)
+#define PIN_PD8__NANDRDY PINMUX_PIN(PIN_PD8, 6, 2)
+#define PIN_PD9 105
+#define PIN_PD9__GPIO PINMUX_PIN(PIN_PD9, 0, 0)
+#define PIN_PD9__TMS PINMUX_PIN(PIN_PD9, 1, 2)
+#define PIN_PD9__UTMI_RXACT PINMUX_PIN(PIN_PD9, 3, 1)
+#define PIN_PD9__GTXCK PINMUX_PIN(PIN_PD9, 4, 2)
+#define PIN_PD9__ISC_D2 PINMUX_PIN(PIN_PD9, 5, 2)
+#define PIN_PD10 106
+#define PIN_PD10__GPIO PINMUX_PIN(PIN_PD10, 0, 0)
+#define PIN_PD10__NTRST PINMUX_PIN(PIN_PD10, 1, 2)
+#define PIN_PD10__UTMI_HDIS PINMUX_PIN(PIN_PD10, 3, 1)
+#define PIN_PD10__GTXEN PINMUX_PIN(PIN_PD10, 4, 2)
+#define PIN_PD10__ISC_D3 PINMUX_PIN(PIN_PD10, 5, 2)
+#define PIN_PD11 107
+#define PIN_PD11__GPIO PINMUX_PIN(PIN_PD11, 0, 0)
+#define PIN_PD11__TIOA1 PINMUX_PIN(PIN_PD11, 1, 3)
+#define PIN_PD11__PCK2 PINMUX_PIN(PIN_PD11, 2, 2)
+#define PIN_PD11__UTMI_LS0 PINMUX_PIN(PIN_PD11, 3, 1)
+#define PIN_PD11__GRXDV PINMUX_PIN(PIN_PD11, 4, 2)
+#define PIN_PD11__ISC_D4 PINMUX_PIN(PIN_PD11, 5, 2)
+#define PIN_PD11__ISC_MCK PINMUX_PIN(PIN_PD11, 7, 4)
+#define PIN_PD12 108
+#define PIN_PD12__GPIO PINMUX_PIN(PIN_PD12, 0, 0)
+#define PIN_PD12__TIOB1 PINMUX_PIN(PIN_PD12, 1, 3)
+#define PIN_PD12__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD12, 2, 2)
+#define PIN_PD12__UTMI_LS1 PINMUX_PIN(PIN_PD12, 3, 1)
+#define PIN_PD12__GRXER PINMUX_PIN(PIN_PD12, 4, 2)
+#define PIN_PD12__ISC_D5 PINMUX_PIN(PIN_PD12, 5, 2)
+#define PIN_PD12__ISC_D4 PINMUX_PIN(PIN_PD12, 6, 4)
+#define PIN_PD13 109
+#define PIN_PD13__GPIO PINMUX_PIN(PIN_PD13, 0, 0)
+#define PIN_PD13__TCLK1 PINMUX_PIN(PIN_PD13, 1, 3)
+#define PIN_PD13__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD13, 2, 2)
+#define PIN_PD13__UTMI_CDRPCSEL0 PINMUX_PIN(PIN_PD13, 3, 1)
+#define PIN_PD13__GRX0 PINMUX_PIN(PIN_PD13, 4, 2)
+#define PIN_PD13__ISC_D6 PINMUX_PIN(PIN_PD13, 5, 2)
+#define PIN_PD13__ISC_D5 PINMUX_PIN(PIN_PD13, 6, 4)
+#define PIN_PD14 110
+#define PIN_PD14__GPIO PINMUX_PIN(PIN_PD14, 0, 0)
+#define PIN_PD14__TCK PINMUX_PIN(PIN_PD14, 1, 1)
+#define PIN_PD14__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD14, 2, 2)
+#define PIN_PD14__UTMI_CDRPCSEL1 PINMUX_PIN(PIN_PD14, 3, 1)
+#define PIN_PD14__GRX1 PINMUX_PIN(PIN_PD14, 4, 2)
+#define PIN_PD14__ISC_D7 PINMUX_PIN(PIN_PD14, 5, 2)
+#define PIN_PD14__ISC_D6 PINMUX_PIN(PIN_PD14, 6, 4)
+#define PIN_PD15 111
+#define PIN_PD15__GPIO PINMUX_PIN(PIN_PD15, 0, 0)
+#define PIN_PD15__TDI PINMUX_PIN(PIN_PD15, 1, 1)
+#define PIN_PD15__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD15, 2, 2)
+#define PIN_PD15__UTMI_CDRCPDIVEN PINMUX_PIN(PIN_PD15, 3, 1)
+#define PIN_PD15__GTX0 PINMUX_PIN(PIN_PD15, 4, 2)
+#define PIN_PD15__ISC_PCK PINMUX_PIN(PIN_PD15, 5, 2)
+#define PIN_PD15__ISC_D7 PINMUX_PIN(PIN_PD15, 6, 4)
+#define PIN_PD16 112
+#define PIN_PD16__GPIO PINMUX_PIN(PIN_PD16, 0, 0)
+#define PIN_PD16__TDO PINMUX_PIN(PIN_PD16, 1, 1)
+#define PIN_PD16__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD16, 2, 2)
+#define PIN_PD16__UTMI_CDRBISTEN PINMUX_PIN(PIN_PD16, 3, 1)
+#define PIN_PD16__GTX1 PINMUX_PIN(PIN_PD16, 4, 2)
+#define PIN_PD16__ISC_VSYNC PINMUX_PIN(PIN_PD16, 5, 2)
+#define PIN_PD16__ISC_D8 PINMUX_PIN(PIN_PD16, 6, 4)
+#define PIN_PD17 113
+#define PIN_PD17__GPIO PINMUX_PIN(PIN_PD17, 0, 0)
+#define PIN_PD17__TMS PINMUX_PIN(PIN_PD17, 1, 1)
+#define PIN_PD17__UTMI_CDRCPSELDIV PINMUX_PIN(PIN_PD17, 3, 1)
+#define PIN_PD17__GMDC PINMUX_PIN(PIN_PD17, 4, 2)
+#define PIN_PD17__ISC_HSYNC PINMUX_PIN(PIN_PD17, 5, 2)
+#define PIN_PD17__ISC_D9 PINMUX_PIN(PIN_PD17, 6, 4)
+#define PIN_PD18 114
+#define PIN_PD18__GPIO PINMUX_PIN(PIN_PD18, 0, 0)
+#define PIN_PD18__NTRST PINMUX_PIN(PIN_PD18, 1, 1)
+#define PIN_PD18__GMDIO PINMUX_PIN(PIN_PD18, 4, 2)
+#define PIN_PD18__ISC_FIELD PINMUX_PIN(PIN_PD18, 5, 2)
+#define PIN_PD18__ISC_D10 PINMUX_PIN(PIN_PD18, 6, 4)
+#define PIN_PD19 115
+#define PIN_PD19__GPIO PINMUX_PIN(PIN_PD19, 0, 0)
+#define PIN_PD19__PCK0 PINMUX_PIN(PIN_PD19, 1, 1)
+#define PIN_PD19__TWD1 PINMUX_PIN(PIN_PD19, 2, 3)
+#define PIN_PD19__URXD2 PINMUX_PIN(PIN_PD19, 3, 3)
+#define PIN_PD19__I2SC0_CK PINMUX_PIN(PIN_PD19, 5, 2)
+#define PIN_PD19__ISC_D11 PINMUX_PIN(PIN_PD19, 6, 4)
+#define PIN_PD20 116
+#define PIN_PD20__GPIO PINMUX_PIN(PIN_PD20, 0, 0)
+#define PIN_PD20__TIOA2 PINMUX_PIN(PIN_PD20, 1, 3)
+#define PIN_PD20__TWCK1 PINMUX_PIN(PIN_PD20, 2, 3)
+#define PIN_PD20__UTXD2 PINMUX_PIN(PIN_PD20, 3, 3)
+#define PIN_PD20__I2SC0_MCK PINMUX_PIN(PIN_PD20, 5, 2)
+#define PIN_PD20__ISC_PCK PINMUX_PIN(PIN_PD20, 6, 4)
+#define PIN_PD21 117
+#define PIN_PD21__GPIO PINMUX_PIN(PIN_PD21, 0, 0)
+#define PIN_PD21__TIOB2 PINMUX_PIN(PIN_PD21, 1, 3)
+#define PIN_PD21__TWD0 PINMUX_PIN(PIN_PD21, 2, 4)
+#define PIN_PD21__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD21, 3, 3)
+#define PIN_PD21__I2SC0_WS PINMUX_PIN(PIN_PD21, 5, 2)
+#define PIN_PD21__ISC_VSYNC PINMUX_PIN(PIN_PD21, 6, 4)
+#define PIN_PD22 118
+#define PIN_PD22__GPIO PINMUX_PIN(PIN_PD22, 0, 0)
+#define PIN_PD22__TCLK2 PINMUX_PIN(PIN_PD22, 1, 3)
+#define PIN_PD22__TWCK0 PINMUX_PIN(PIN_PD22, 2, 4)
+#define PIN_PD22__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD22, 3, 3)
+#define PIN_PD22__I2SC0_DI0 PINMUX_PIN(PIN_PD22, 5, 2)
+#define PIN_PD22__ISC_HSYNC PINMUX_PIN(PIN_PD22, 6, 4)
+#define PIN_PD23 119
+#define PIN_PD23__GPIO PINMUX_PIN(PIN_PD23, 0, 0)
+#define PIN_PD23__URXD2 PINMUX_PIN(PIN_PD23, 1, 2)
+#define PIN_PD23__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD23, 3, 3)
+#define PIN_PD23__I2SC0_DO0 PINMUX_PIN(PIN_PD23, 5, 2)
+#define PIN_PD23__ISC_FIELD PINMUX_PIN(PIN_PD23, 6, 4)
+#define PIN_PD24 120
+#define PIN_PD24__GPIO PINMUX_PIN(PIN_PD24, 0, 0)
+#define PIN_PD24__UTXD2 PINMUX_PIN(PIN_PD23, 1, 2)
+#define PIN_PD24__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD23, 3, 3)
+#define PIN_PD25 121
+#define PIN_PD25__GPIO PINMUX_PIN(PIN_PD25, 0, 0)
+#define PIN_PD25__SPI1_SPCK PINMUX_PIN(PIN_PD25, 1, 3)
+#define PIN_PD25__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD25, 3, 3)
+#define PIN_PD26 122
+#define PIN_PD26__GPIO PINMUX_PIN(PIN_PD26, 0, 0)
+#define PIN_PD26__SPI1_MOSI PINMUX_PIN(PIN_PD26, 1, 3)
+#define PIN_PD26__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD26, 3, 2)
+#define PIN_PD27 123
+#define PIN_PD27__GPIO PINMUX_PIN(PIN_PD27, 0, 0)
+#define PIN_PD27__SPI1_MISO PINMUX_PIN(PIN_PD27, 1, 3)
+#define PIN_PD27__TCK PINMUX_PIN(PIN_PD27, 2, 3)
+#define PIN_PD27__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD27, 3, 2)
+#define PIN_PD28 124
+#define PIN_PD28__GPIO PINMUX_PIN(PIN_PD28, 0, 0)
+#define PIN_PD28__SPI1_NPCS0 PINMUX_PIN(PIN_PD28, 1, 3)
+#define PIN_PD28__TCI PINMUX_PIN(PIN_PD28, 2, 3)
+#define PIN_PD28__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD28, 3, 2)
+#define PIN_PD29 125
+#define PIN_PD29__GPIO PINMUX_PIN(PIN_PD29, 0, 0)
+#define PIN_PD29__SPI1_NPCS1 PINMUX_PIN(PIN_PD29, 1, 3)
+#define PIN_PD29__TDO PINMUX_PIN(PIN_PD29, 2, 3)
+#define PIN_PD29__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD29, 3, 2)
+#define PIN_PD29__TIOA3 PINMUX_PIN(PIN_PD29, 4, 3)
+#define PIN_PD29__TWD0 PINMUX_PIN(PIN_PD29, 5, 3)
+#define PIN_PD30 126
+#define PIN_PD30__GPIO PINMUX_PIN(PIN_PD30, 0, 0)
+#define PIN_PD30__SPI1_NPCS2 PINMUX_PIN(PIN_PD30, 1, 3)
+#define PIN_PD30__TMS PINMUX_PIN(PIN_PD30, 2, 3)
+#define PIN_PD30__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD30, 3, 2)
+#define PIN_PD30__TIOB3 PINMUX_PIN(PIN_PD30, 4, 3)
+#define PIN_PD30__TWCK0 PINMUX_PIN(PIN_PD30, 5, 3)
+#define PIN_PD31 127
+#define PIN_PD31__GPIO PINMUX_PIN(PIN_PD31, 0, 0)
+#define PIN_PD31__ADTRG PINMUX_PIN(PIN_PD31, 1, 1)
+#define PIN_PD31__NTRST PINMUX_PIN(PIN_PD31, 2, 3)
+#define PIN_PD31__IRQ PINMUX_PIN(PIN_PD31, 3, 4)
+#define PIN_PD31__TCLK3 PINMUX_PIN(PIN_PD31, 4, 3)
+#define PIN_PD31__PCK0 PINMUX_PIN(PIN_PD31, 5, 2)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index cc05cde..4dfca8f 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -263,6 +263,24 @@
cache-level = <2>;
};
+ sdmmc0: sdio-host@a0000000 {
+ compatible = "atmel,sama5d2-sdhci";
+ reg = <0xa0000000 0x300>;
+ interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>;
+ clock-names = "hclock", "multclk", "baseclk";
+ status = "disabled";
+ };
+
+ sdmmc1: sdio-host@b0000000 {
+ compatible = "atmel,sama5d2-sdhci";
+ reg = <0xb0000000 0x300>;
+ interrupts = <32 IRQ_TYPE_LEVEL_HIGH 0>;
+ clocks = <&sdmmc1_hclk>, <&sdmmc1_gclk>, <&main>;
+ clock-names = "hclock", "multclk", "baseclk";
+ status = "disabled";
+ };
+
apb {
compatible = "simple-bus";
#address-cells = <1>;
@@ -286,7 +304,7 @@
};
pmc: pmc@f0014000 {
- compatible = "atmel,sama5d2-pmc";
+ compatible = "atmel,sama5d2-pmc", "syscon";
reg = <0xf0014000 0x160>;
interrupts = <74 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
@@ -619,6 +637,18 @@
atmel,clk-output-range = <0 83000000>;
};
+ i2s0_clk: i2s0_clk {
+ #clock-cells = <0>;
+ reg = <54>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
+ i2s1_clk: i2s1_clk {
+ #clock-cells = <0>;
+ reg = <55>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
classd_clk: classd_clk {
#clock-cells = <0>;
reg = <59>;
@@ -697,6 +727,52 @@
reg = <53>;
};
};
+
+ gck {
+ compatible = "atmel,sama5d2-clk-generated";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <&pmc>;
+ clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>;
+
+ sdmmc0_gclk: sdmmc0_gclk {
+ #clock-cells = <0>;
+ reg = <31>;
+ };
+
+ sdmmc1_gclk: sdmmc1_gclk {
+ #clock-cells = <0>;
+ reg = <32>;
+ };
+
+ tcb0_gclk: tcb0_gclk {
+ #clock-cells = <0>;
+ reg = <35>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
+ tcb1_gclk: tcb1_gclk {
+ #clock-cells = <0>;
+ reg = <36>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
+ pwm_gclk: pwm_gclk {
+ #clock-cells = <0>;
+ reg = <38>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
+ i2s0_gclk: i2s0_gclk {
+ #clock-cells = <0>;
+ reg = <54>;
+ };
+
+ i2s1_gclk: i2s1_gclk {
+ #clock-cells = <0>;
+ reg = <55>;
+ };
+ };
};
sha@f0028000 {
@@ -709,7 +785,7 @@
dma-names = "tx";
clocks = <&sha_clk>;
clock-names = "sha_clk";
- status = "disabled";
+ status = "okay";
};
aes@f002c000 {
@@ -725,7 +801,7 @@
dma-names = "tx", "rx";
clocks = <&aes_clk>;
clock-names = "aes_clk";
- status = "disabled";
+ status = "okay";
};
spi0: spi@f8000000 {
@@ -820,6 +896,32 @@
status = "disabled";
};
+ flx0: flexcom@f8034000 {
+ compatible = "atmel,sama5d2-flexcom";
+ reg = <0xf8034000 0x200>;
+ clocks = <&flx0_clk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xf8034000 0x800>;
+ status = "disabled";
+ };
+
+ flx1: flexcom@f8038000 {
+ compatible = "atmel,sama5d2-flexcom";
+ reg = <0xf8038000 0x200>;
+ clocks = <&flx1_clk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xf8038000 0x800>;
+ status = "disabled";
+ };
+
+ rstc@f8048000 {
+ compatible = "atmel,sama5d3-rstc";
+ reg = <0xf8048000 0x10>;
+ clocks = <&clk32k>;
+ };
+
pit: timer@f8048030 {
compatible = "atmel,at91sam9260-pit";
reg = <0xf8048030 0x10>;
@@ -897,6 +999,36 @@
status = "disabled";
};
+ flx2: flexcom@fc010000 {
+ compatible = "atmel,sama5d2-flexcom";
+ reg = <0xfc010000 0x200>;
+ clocks = <&flx2_clk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfc010000 0x800>;
+ status = "disabled";
+ };
+
+ flx3: flexcom@fc014000 {
+ compatible = "atmel,sama5d2-flexcom";
+ reg = <0xfc014000 0x200>;
+ clocks = <&flx3_clk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfc014000 0x800>;
+ status = "disabled";
+ };
+
+ flx4: flexcom@fc018000 {
+ compatible = "atmel,sama5d2-flexcom";
+ reg = <0xfc018000 0x200>;
+ clocks = <&flx4_clk>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0xfc018000 0x800>;
+ status = "disabled";
+ };
+
aic: interrupt-controller@fc020000 {
#interrupt-cells = <3>;
compatible = "atmel,sama5d2-aic";
@@ -935,6 +1067,22 @@
#gpio-cells = <2>;
clocks = <&pioA_clk>;
};
+
+ tdes@fc044000 {
+ compatible = "atmel,at91sam9g46-tdes";
+ reg = <0xfc044000 0x100>;
+ interrupts = <11 IRQ_TYPE_LEVEL_HIGH 0>;
+ dmas = <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(28))>,
+ <&dma0
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) |
+ AT91_XDMAC_DT_PERID(29))>;
+ dma-names = "tx", "rx";
+ clocks = <&tdes_clk>;
+ clock-names = "tdes_clk";
+ status = "okay";
+ };
};
};
};
diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi
index 7fa2765..a532791 100644
--- a/arch/arm/boot/dts/sama5d3.dtsi
+++ b/arch/arm/boot/dts/sama5d3.dtsi
@@ -75,7 +75,7 @@
adc_op_clk: adc_op_clk{
compatible = "fixed-clock";
#clock-cells = <0>;
- clock-frequency = <20000000>;
+ clock-frequency = <1000000>;
};
};
@@ -322,6 +322,7 @@
atmel,adc-use-external-triggers;
atmel,adc-vref = <3000>;
atmel,adc-res = <10 12>;
+ atmel,adc-sample-hold-time = <11>;
atmel,adc-res-names = "lowres", "highres";
status = "disabled";
@@ -906,7 +907,7 @@
};
pmc: pmc@fffffc00 {
- compatible = "atmel,sama5d3-pmc";
+ compatible = "atmel,sama5d3-pmc", "syscon";
reg = <0xfffffc00 0x120>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/sama5d35ek.dts b/arch/arm/boot/dts/sama5d35ek.dts
index d9a9aca..e812f5c 100644
--- a/arch/arm/boot/dts/sama5d35ek.dts
+++ b/arch/arm/boot/dts/sama5d35ek.dts
@@ -49,7 +49,7 @@
label = "pb_user1";
gpios = <&pioE 27 GPIO_ACTIVE_HIGH>;
linux,code = <0x100>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
};
diff --git a/arch/arm/boot/dts/sama5d3_mci2.dtsi b/arch/arm/boot/dts/sama5d3_mci2.dtsi
index 026b252..e21099a 100644
--- a/arch/arm/boot/dts/sama5d3_mci2.dtsi
+++ b/arch/arm/boot/dts/sama5d3_mci2.dtsi
@@ -24,9 +24,9 @@
};
pinctrl_mmc2_dat1_3: mmc2_dat1_3 {
atmel,pins =
- <AT91_PIOC 12 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC12 periph A MCI2_DA1 with pullup, conflicts with TIOA1 */
- AT91_PIOC 13 AT91_PERIPH_A AT91_PINCTRL_NONE /* PC13 periph A MCI2_DA2 with pullup, conflicts with TIOB1 */
- AT91_PIOC 14 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* PC14 periph A MCI2_DA3 with pullup, conflicts with TCLK1 */
+ <AT91_PIOC 12 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PC12 periph A MCI2_DA1 with pullup, conflicts with TIOA1 */
+ AT91_PIOC 13 AT91_PERIPH_A AT91_PINCTRL_PULL_UP /* PC13 periph A MCI2_DA2 with pullup, conflicts with TIOB1 */
+ AT91_PIOC 14 AT91_PERIPH_A AT91_PINCTRL_PULL_UP>; /* PC14 periph A MCI2_DA3 with pullup, conflicts with TCLK1 */
};
};
};
diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi
index 83bee7a..8901042 100644
--- a/arch/arm/boot/dts/sama5d3xmb.dtsi
+++ b/arch/arm/boot/dts/sama5d3xmb.dtsi
@@ -87,6 +87,8 @@
isi_0: endpoint {
remote-endpoint = <&ov2640_0>;
bus-width = <8>;
+ vsync-active = <1>;
+ hsync-active = <1>;
};
};
};
diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi
index 8d1de29..2193637 100644
--- a/arch/arm/boot/dts/sama5d4.dtsi
+++ b/arch/arm/boot/dts/sama5d4.dtsi
@@ -386,7 +386,7 @@
};
pmc: pmc@f0018000 {
- compatible = "atmel,sama5d3-pmc";
+ compatible = "atmel,sama5d3-pmc", "syscon";
reg = <0xf0018000 0x120>;
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
interrupt-controller;
@@ -939,11 +939,11 @@
reg = <0xf8018000 0x4000>;
interrupts = <33 IRQ_TYPE_LEVEL_HIGH 6>;
dmas = <&dma1
- (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(4)>,
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(4))>,
<&dma1
- (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1))
- AT91_XDMAC_DT_PERID(5)>;
+ (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)
+ | AT91_XDMAC_DT_PERID(5))>;
dma-names = "tx", "rx";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
@@ -1189,6 +1189,19 @@
clock-names = "t0_clk", "slow_clk";
};
+ macb1: ethernet@fc028000 {
+ compatible = "atmel,sama5d4-gem";
+ reg = <0xfc028000 0x100>;
+ interrupts = <55 IRQ_TYPE_LEVEL_HIGH 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_macb1_rmii>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&macb1_clk>, <&macb1_clk>;
+ clock-names = "hclk", "pclk";
+ status = "disabled";
+ };
+
adc0: adc@fc034000 {
compatible = "atmel,at91sam9x5-adc";
reg = <0xfc034000 0x100>;
@@ -1238,7 +1251,7 @@
dma-names = "tx", "rx";
clocks = <&aes_clk>;
clock-names = "aes_clk";
- status = "disabled";
+ status = "okay";
};
tdes@fc04c000 {
@@ -1252,7 +1265,7 @@
dma-names = "tx", "rx";
clocks = <&tdes_clk>;
clock-names = "tdes_clk";
- status = "disabled";
+ status = "okay";
};
sha@fc050000 {
@@ -1264,7 +1277,7 @@
dma-names = "tx";
clocks = <&sha_clk>;
clock-names = "sha_clk";
- status = "disabled";
+ status = "okay";
};
rstc@fc068600 {
@@ -1287,7 +1300,7 @@
};
watchdog@fc068640 {
- compatible = "atmel,at91sam9260-wdt";
+ compatible = "atmel,sama5d4-wdt";
reg = <0xfc068640 0x10>;
clocks = <&clk32k>;
status = "disabled";
@@ -1350,7 +1363,7 @@
0xffffffff 0x3ffcfe7c 0x1c010101 /* pioA */
0x7fffffff 0xfffccc3a 0x3f00cc3a /* pioB */
0xffffffff 0x3ff83fff 0xff00ffff /* pioC */
- 0x00000000 0x00000000 0x00000000 /* pioD */
+ 0x0003ff00 0x8002a800 0x00000000 /* pioD */
0xffffffff 0x7fffffff 0x76fff1bf /* pioE */
>;
@@ -1396,7 +1409,6 @@
interrupt-controller;
#interrupt-cells = <2>;
clocks = <&pioD_clk>;
- status = "disabled";
};
pioE: gpio@fc06d000 {
@@ -1636,6 +1648,23 @@
};
};
+ macb1 {
+ pinctrl_macb1_rmii: macb1_rmii-0 {
+ atmel,pins =
+ <AT91_PIOA 14 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_TX0 */
+ AT91_PIOA 15 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_TX1 */
+ AT91_PIOA 12 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_RX0 */
+ AT91_PIOA 13 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_RX1 */
+ AT91_PIOA 10 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_RXDV */
+ AT91_PIOA 11 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_RXER */
+ AT91_PIOA 4 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_TXEN */
+ AT91_PIOA 2 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_TXCK */
+ AT91_PIOA 22 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_MDC */
+ AT91_PIOA 23 AT91_PERIPH_B AT91_PINCTRL_NONE /* G1_MDIO */
+ >;
+ };
+ };
+
mmc0 {
pinctrl_mmc0_clk_cmd_dat0: mmc0_clk_cmd_dat0 {
atmel,pins =
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g.dts b/arch/arm/boot/dts/sh73a0-kzm9g.dts
index 24b4cd2..7fc5602 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g.dts
@@ -206,7 +206,7 @@
};
accelerometer@1d {
- compatible = "adi,adxl34x";
+ compatible = "adi,adxl345";
reg = <0x1d>;
interrupt-parent = <&irqpin3>;
interrupts = <2 IRQ_TYPE_LEVEL_HIGH>,
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 314e589..39c470e 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -513,6 +513,13 @@
};
};
+ fpgamgr0: fpgamgr@ff706000 {
+ compatible = "altr,socfpga-fpga-mgr";
+ reg = <0xff706000 0x1000
+ 0xffb90000 0x1000>;
+ interrupts = <0 175 4>;
+ };
+
gmac0: ethernet@ff700000 {
compatible = "altr,socfpga-stmmac", "snps,dwmac-3.70a", "snps,dwmac";
altr,sysmgr-syscon = <&sysmgr 0x60 0>;
@@ -549,46 +556,6 @@
status = "disabled";
};
- i2c0: i2c@ffc04000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,designware-i2c";
- reg = <0xffc04000 0x1000>;
- clocks = <&l4_sp_clk>;
- interrupts = <0 158 0x4>;
- status = "disabled";
- };
-
- i2c1: i2c@ffc05000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,designware-i2c";
- reg = <0xffc05000 0x1000>;
- clocks = <&l4_sp_clk>;
- interrupts = <0 159 0x4>;
- status = "disabled";
- };
-
- i2c2: i2c@ffc06000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,designware-i2c";
- reg = <0xffc06000 0x1000>;
- clocks = <&l4_sp_clk>;
- interrupts = <0 160 0x4>;
- status = "disabled";
- };
-
- i2c3: i2c@ffc07000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,designware-i2c";
- reg = <0xffc07000 0x1000>;
- clocks = <&l4_sp_clk>;
- interrupts = <0 161 0x4>;
- status = "disabled";
- };
-
gpio0: gpio@ff708000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -649,15 +616,44 @@
};
};
- sdr: sdr@ffc25000 {
- compatible = "syscon";
- reg = <0xffc25000 0x1000>;
+ i2c0: i2c@ffc04000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc04000 0x1000>;
+ clocks = <&l4_sp_clk>;
+ interrupts = <0 158 0x4>;
+ status = "disabled";
};
- sdramedac {
- compatible = "altr,sdram-edac";
- altr,sdr-syscon = <&sdr>;
- interrupts = <0 39 4>;
+ i2c1: i2c@ffc05000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc05000 0x1000>;
+ clocks = <&l4_sp_clk>;
+ interrupts = <0 159 0x4>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@ffc06000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc06000 0x1000>;
+ clocks = <&l4_sp_clk>;
+ interrupts = <0 160 0x4>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@ffc07000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc07000 0x1000>;
+ clocks = <&l4_sp_clk>;
+ interrupts = <0 161 0x4>;
+ status = "disabled";
};
L2: l2-cache@fffef000 {
@@ -688,6 +684,29 @@
reg = <0xffff0000 0x10000>;
};
+ rst: rstmgr@ffd05000 {
+ #reset-cells = <1>;
+ compatible = "altr,rst-mgr";
+ reg = <0xffd05000 0x1000>;
+ altr,modrst-offset = <0x10>;
+ };
+
+ scu: snoop-control-unit@fffec000 {
+ compatible = "arm,cortex-a9-scu";
+ reg = <0xfffec000 0x100>;
+ };
+
+ sdr: sdr@ffc25000 {
+ compatible = "syscon";
+ reg = <0xffc25000 0x1000>;
+ };
+
+ sdramedac {
+ compatible = "altr,sdram-edac";
+ altr,sdr-syscon = <&sdr>;
+ interrupts = <0 39 4>;
+ };
+
spi0: spi@fff00000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <1>;
@@ -699,11 +718,6 @@
status = "disabled";
};
- scu: snoop-control-unit@fffec000 {
- compatible = "arm,cortex-a9-scu";
- reg = <0xfffec000 0x100>;
- };
-
spi1: spi@fff01000 {
compatible = "snps,dw-apb-ssi";
#address-cells = <1>;
@@ -715,6 +729,11 @@
status = "disabled";
};
+ sysmgr: sysmgr@ffd08000 {
+ compatible = "altr,sys-mgr", "syscon";
+ reg = <0xffd08000 0x4000>;
+ };
+
/* Local timer */
timer@fffec600 {
compatible = "arm,cortex-a9-twd-timer";
@@ -779,13 +798,6 @@
dma-names = "tx", "rx";
};
- rst: rstmgr@ffd05000 {
- #reset-cells = <1>;
- compatible = "altr,rst-mgr";
- reg = <0xffd05000 0x1000>;
- altr,modrst-offset = <0x10>;
- };
-
usbphy0: usbphy@0 {
#phy-cells = <0>;
compatible = "usb-nop-xceiv";
@@ -829,10 +841,5 @@
clocks = <&osc1>;
status = "disabled";
};
-
- sysmgr: sysmgr@ffd08000 {
- compatible = "altr,sys-mgr", "syscon";
- reg = <0xffd08000 0x4000>;
- };
};
};
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
index 2340fcb..cce9e50 100644
--- a/arch/arm/boot/dts/socfpga_arria10.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -519,6 +519,7 @@
compatible = "snps,designware-i2c";
reg = <0xffc02200 0x100>;
interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -528,6 +529,7 @@
compatible = "snps,designware-i2c";
reg = <0xffc02300 0x100>;
interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -537,6 +539,7 @@
compatible = "snps,designware-i2c";
reg = <0xffc02400 0x100>;
interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -546,6 +549,7 @@
compatible = "snps,designware-i2c";
reg = <0xffc02500 0x100>;
interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -555,6 +559,7 @@
compatible = "snps,designware-i2c";
reg = <0xffc02600 0x100>;
interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -658,6 +663,7 @@
interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
+ clocks = <&l4_sp_clk>;
status = "disabled";
};
@@ -692,6 +698,8 @@
compatible = "snps,dwc2";
reg = <0xffb40000 0xffff>;
interrupts = <0 96 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&usb_clk>;
+ clock-names = "otg";
phys = <&usbphy0>;
phy-names = "usb2-phy";
status = "disabled";
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
index 99aa9a1..567df98 100644
--- a/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dtsi
@@ -70,6 +70,33 @@
status = "okay";
};
+&i2c1 {
+ speed-mode = <0>;
+ status = "okay";
+
+ /*
+ * adjust the falling times to decrease the i2c frequency to 50Khz
+ * because the LCD module does not work at the standard 100Khz
+ */
+ i2c-sda-falling-time-ns = <6000>;
+ i2c-scl-falling-time-ns = <6000>;
+
+ eeprom@51 {
+ compatible = "atmel,24c32";
+ reg = <0x51>;
+ pagesize = <32>;
+ };
+
+ rtc@68 {
+ compatible = "dallas,ds1339";
+ reg = <0x68>;
+ };
+};
+
&uart1 {
status = "okay";
};
+
+&usb0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
index 314f59c..d0c7438 100644
--- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -25,9 +25,9 @@
cache-sets = <512>;
cache-line-size = <32>;
/* At full speed latency must be >=2 */
- arm,tag-latency = <2>;
- arm,data-latency = <2 2>;
- arm,dirty-latency = <2>;
+ arm,tag-latency = <8>;
+ arm,data-latency = <8 8>;
+ arm,dirty-latency = <8>;
};
mtu0: mtu@101e2000 {
diff --git a/arch/arm/boot/dts/stih407-b2120.dts b/arch/arm/boot/dts/stih407-b2120.dts
index 6d93475..c8ad905 100644
--- a/arch/arm/boot/dts/stih407-b2120.dts
+++ b/arch/arm/boot/dts/stih407-b2120.dts
@@ -25,6 +25,7 @@
aliases {
ttyAS0 = &sbc_serial0;
+ ethernet0 = &ethernet0;
};
};
diff --git a/arch/arm/boot/dts/stih407-family.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
index 0c24fcb..81f8121 100644
--- a/arch/arm/boot/dts/stih407-family.dtsi
+++ b/arch/arm/boot/dts/stih407-family.dtsi
@@ -152,6 +152,19 @@
<ST_IRQ_SYSCFG_DISABLED>;
};
+ /* Display */
+ vtg_main: sti-vtg-main@8d02800 {
+ compatible = "st,vtg";
+ reg = <0x8d02800 0x200>;
+ interrupts = <GIC_SPI 108 IRQ_TYPE_NONE>;
+ };
+
+ vtg_aux: sti-vtg-aux@8d00200 {
+ compatible = "st,vtg";
+ reg = <0x8d00200 0x100>;
+ interrupts = <GIC_SPI 109 IRQ_TYPE_NONE>;
+ };
+
serial@9830000 {
compatible = "st,asc";
reg = <0x9830000 0x2c>;
@@ -396,6 +409,8 @@
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi1_default>;
status = "disabled";
};
@@ -406,6 +421,8 @@
interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi2_default>;
status = "disabled";
};
@@ -416,6 +433,8 @@
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi3_default>;
status = "disabled";
};
@@ -426,6 +445,8 @@
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi4_default>;
status = "disabled";
};
@@ -437,6 +458,8 @@
interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_sysin>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi10_default>;
status = "disabled";
};
@@ -447,6 +470,8 @@
interrupts = <GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_sysin>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi11_default>;
status = "disabled";
};
@@ -457,6 +482,8 @@
interrupts = <GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clk_sysin>;
clock-names = "ssc";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spi12_default>;
status = "disabled";
};
@@ -585,7 +612,6 @@
/* COMMS PWM Module */
pwm0: pwm@9810000 {
compatible = "st,sti-pwm";
- status = "okay";
#pwm-cells = <2>;
reg = <0x9810000 0x68>;
pinctrl-names = "default";
@@ -593,12 +619,13 @@
clock-names = "pwm";
clocks = <&clk_sysin>;
st,pwm-num-chan = <1>;
+
+ status = "disabled";
};
/* SBC PWM Module */
pwm1: pwm@9510000 {
compatible = "st,sti-pwm";
- status = "okay";
#pwm-cells = <2>;
reg = <0x9510000 0x68>;
pinctrl-names = "default";
@@ -609,6 +636,49 @@
clock-names = "pwm";
clocks = <&clk_sysin>;
st,pwm-num-chan = <4>;
+
+ status = "disabled";
+ };
+
+ rng10: rng@08a89000 {
+ compatible = "st,rng";
+ reg = <0x08a89000 0x1000>;
+ clocks = <&clk_sysin>;
+ status = "okay";
+ };
+
+ rng11: rng@08a8a000 {
+ compatible = "st,rng";
+ reg = <0x08a8a000 0x1000>;
+ clocks = <&clk_sysin>;
+ status = "okay";
+ };
+
+ ethernet0: dwmac@9630000 {
+ device_type = "network";
+ status = "disabled";
+ compatible = "st,stih407-dwmac", "snps,dwmac", "snps,dwmac-3.710";
+ reg = <0x9630000 0x8000>, <0x80 0x4>;
+ reg-names = "stmmaceth", "sti-ethconf";
+
+ st,syscon = <&syscfg_sbc_reg 0x80>;
+ st,gmac_en;
+ resets = <&softreset STIH407_ETH1_SOFTRESET>;
+ reset-names = "stmmaceth";
+
+ interrupts = <GIC_SPI 98 IRQ_TYPE_NONE>,
+ <GIC_SPI 99 IRQ_TYPE_NONE>;
+ interrupt-names = "macirq", "eth_wake_irq";
+
+ /* DMA Bus Mode */
+ snps,pbl = <8>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_rgmii1>;
+
+ clock-names = "stmmaceth", "sti-ethclk";
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>,
+ <&clk_s_c0_flexgen CLK_ETH_PHY>;
};
rng10: rng@08a89000 {
diff --git a/arch/arm/boot/dts/stih407-pinctrl.dtsi b/arch/arm/boot/dts/stih407-pinctrl.dtsi
index 1683deb..a538ae5 100644
--- a/arch/arm/boot/dts/stih407-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih407-pinctrl.dtsi
@@ -53,7 +53,7 @@
reg = <0x0961f080 0x4>;
reg-names = "irqmux";
interrupts = <GIC_SPI 188 IRQ_TYPE_NONE>;
- interrupts-names = "irqmux";
+ interrupt-names = "irqmux";
ranges = <0 0x09610000 0x6000>;
pio0: gpio@09610000 {
@@ -107,12 +107,38 @@
st,retime-pin-mask = <0x3f>;
};
+ cec0 {
+ pinctrl_cec0_default: cec0-default {
+ st,pins {
+ hdmi_cec = <&pio2 4 ALT1 BIDIR>;
+ };
+ };
+ };
+
rc {
pinctrl_ir: ir0 {
st,pins {
ir = <&pio4 0 ALT2 IN>;
};
};
+
+ pinctrl_uhf: uhf0 {
+ st,pins {
+ ir = <&pio4 1 ALT2 IN>;
+ };
+ };
+
+ pinctrl_tx: tx0 {
+ st,pins {
+ tx = <&pio4 2 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_tx_od: tx_od0 {
+ st,pins {
+ tx_od = <&pio4 3 ALT2 OUT>;
+ };
+ };
};
/* SBC_ASC0 - UART10 */
@@ -190,9 +216,9 @@
rxd2 = <&pio1 6 ALT1 IN DE_IO 0 CLK_A>;
rxd3 = <&pio1 7 ALT1 IN DE_IO 0 CLK_A>;
rxdv = <&pio2 0 ALT1 IN DE_IO 0 CLK_A>;
- rxclk = <&pio2 2 ALT1 IN NICLK 500 CLK_A>;
+ rxclk = <&pio2 2 ALT1 IN NICLK 0 CLK_A>;
clk125 = <&pio3 7 ALT4 IN NICLK 0 CLK_A>;
- phyclk = <&pio2 3 ALT4 OUT NICLK 1750 CLK_B>;
+ phyclk = <&pio2 3 ALT4 OUT NICLK 1250 CLK_B>;
};
};
@@ -230,6 +256,33 @@
phyclk = <&pio2 3 ALT1 OUT NICLK 0 CLK_A>;
};
};
+
+ pinctrl_rmii1: rmii1-0 {
+ st,pins {
+ txd0 = <&pio0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd1 = <&pio0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txen = <&pio0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ mdio = <&pio1 0 ALT1 OUT BYPASS 0>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ mdint = <&pio1 3 ALT1 IN BYPASS 0>;
+ rxd0 = <&pio1 4 ALT1 IN SE_NICLK_IO 0 CLK_B>;
+ rxd1 = <&pio1 5 ALT1 IN SE_NICLK_IO 0 CLK_B>;
+ rxdv = <&pio2 0 ALT1 IN SE_NICLK_IO 0 CLK_B>;
+ rx_er = <&pio2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ };
+ };
+
+ pinctrl_rmii1_phyclk: rmii1_phyclk {
+ st,pins {
+ phyclk = <&pio2 3 ALT1 OUT NICLK 0 CLK_A>;
+ };
+ };
+
+ pinctrl_rmii1_phyclk_ext: rmii1_phyclk_ext {
+ st,pins {
+ phyclk = <&pio2 3 ALT2 IN NICLK 0 CLK_A>;
+ };
+ };
};
pwm1 {
@@ -254,6 +307,57 @@
};
};
};
+
+ spi10 {
+ pinctrl_spi10_default: spi10-4w-alt1-0 {
+ st,pins {
+ mtsr = <&pio4 6 ALT1 OUT>;
+ mrst = <&pio4 7 ALT1 IN>;
+ scl = <&pio4 5 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi10_3w_alt1_0: spi10-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio4 6 ALT1 BIDIR_PU>;
+ scl = <&pio4 5 ALT1 OUT>;
+ };
+ };
+ };
+
+ spi11 {
+ pinctrl_spi11_default: spi11-4w-alt2-0 {
+ st,pins {
+ mtsr = <&pio3 1 ALT2 OUT>;
+ mrst = <&pio3 0 ALT2 IN>;
+ scl = <&pio3 2 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi11_3w_alt2_0: spi11-3w-alt2-0 {
+ st,pins {
+ mtsr = <&pio3 1 ALT2 BIDIR_PU>;
+ scl = <&pio3 2 ALT2 OUT>;
+ };
+ };
+ };
+
+ spi12 {
+ pinctrl_spi12_default: spi12-4w-alt2-0 {
+ st,pins {
+ mtsr = <&pio3 6 ALT2 OUT>;
+ mrst = <&pio3 4 ALT2 IN>;
+ scl = <&pio3 7 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi12_3w_alt2_0: spi12-3w-alt2-0 {
+ st,pins {
+ mtsr = <&pio3 6 ALT2 BIDIR_PU>;
+ scl = <&pio3 7 ALT2 OUT>;
+ };
+ };
+ };
};
pin-controller-front0 {
@@ -264,7 +368,7 @@
reg = <0x0920f080 0x4>;
reg-names = "irqmux";
interrupts = <GIC_SPI 189 IRQ_TYPE_NONE>;
- interrupts-names = "irqmux";
+ interrupt-names = "irqmux";
ranges = <0 0x09200000 0x10000>;
pio10: pio@09200000 {
@@ -422,20 +526,180 @@
};
i2c3 {
- pinctrl_i2c3_default: i2c3-default {
+ pinctrl_i2c3_default: i2c3-alt1-0 {
st,pins {
sda = <&pio18 6 ALT1 BIDIR>;
scl = <&pio18 5 ALT1 BIDIR>;
};
};
+ pinctrl_i2c3_alt1_1: i2c3-alt1-1 {
+ st,pins {
+ sda = <&pio17 7 ALT1 BIDIR>;
+ scl = <&pio17 6 ALT1 BIDIR>;
+ };
+ };
+ pinctrl_i2c3_alt3_0: i2c3-alt3-0 {
+ st,pins {
+ sda = <&pio13 6 ALT3 BIDIR>;
+ scl = <&pio13 5 ALT3 BIDIR>;
+ };
+ };
};
spi0 {
- pinctrl_spi0_default: spi0-default {
+ pinctrl_spi0_default: spi0-4w-alt2-0 {
+ st,pins {
+ mtsr = <&pio10 6 ALT2 OUT>;
+ mrst = <&pio10 7 ALT2 IN>;
+ scl = <&pio10 5 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi0_3w_alt2_0: spi0-3w-alt2-0 {
+ st,pins {
+ mtsr = <&pio10 6 ALT2 BIDIR_PU>;
+ scl = <&pio10 5 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi0_4w_alt1_0: spi0-4w-alt1-0 {
+ st,pins {
+ mtsr = <&pio19 7 ALT1 OUT>;
+ mrst = <&pio19 5 ALT1 IN>;
+ scl = <&pio19 6 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi0_3w_alt1_0: spi0-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio19 7 ALT1 BIDIR_PU>;
+ scl = <&pio19 6 ALT1 OUT>;
+ };
+ };
+ };
+
+ spi1 {
+ pinctrl_spi1_default: spi1-4w-alt2-0 {
+ st,pins {
+ mtsr = <&pio11 1 ALT2 OUT>;
+ mrst = <&pio11 2 ALT2 IN>;
+ scl = <&pio11 0 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi1_3w_alt2_0: spi1-3w-alt2-0 {
+ st,pins {
+ mtsr = <&pio11 1 ALT2 BIDIR_PU>;
+ scl = <&pio11 0 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi1_4w_alt1_0: spi1-4w-alt1-0 {
st,pins {
- mtsr = <&pio12 6 ALT2 BIDIR>;
- mrst = <&pio12 7 ALT2 BIDIR>;
- scl = <&pio12 5 ALT2 BIDIR>;
+ mtsr = <&pio14 3 ALT1 OUT>;
+ mrst = <&pio14 4 ALT1 IN>;
+ scl = <&pio14 2 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi1_3w_alt1_0: spi1-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio14 3 ALT1 BIDIR_PU>;
+ scl = <&pio14 2 ALT1 OUT>;
+ };
+ };
+ };
+
+ spi2 {
+ pinctrl_spi2_default: spi2-4w-alt2-0 {
+ st,pins {
+ mtsr = <&pio12 6 ALT2 OUT>;
+ mrst = <&pio12 7 ALT2 IN>;
+ scl = <&pio12 5 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi2_3w_alt2_0: spi2-3w-alt2-0 {
+ st,pins {
+ mtsr = <&pio12 6 ALT2 BIDIR_PU>;
+ scl = <&pio12 5 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi2_4w_alt1_0: spi2-4w-alt1-0 {
+ st,pins {
+ mtsr = <&pio14 6 ALT1 OUT>;
+ mrst = <&pio14 7 ALT1 IN>;
+ scl = <&pio14 5 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi2_3w_alt1_0: spi2-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio14 6 ALT1 BIDIR_PU>;
+ scl = <&pio14 5 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi2_4w_alt2_1: spi2-4w-alt2-1 {
+ st,pins {
+ mtsr = <&pio15 6 ALT2 OUT>;
+ mrst = <&pio15 7 ALT2 IN>;
+ scl = <&pio15 5 ALT2 OUT>;
+ };
+ };
+
+ pinctrl_spi2_3w_alt2_1: spi2-3w-alt2-1 {
+ st,pins {
+ mtsr = <&pio15 6 ALT2 BIDIR_PU>;
+ scl = <&pio15 5 ALT2 OUT>;
+ };
+ };
+ };
+
+ spi3 {
+ pinctrl_spi3_default: spi3-4w-alt3-0 {
+ st,pins {
+ mtsr = <&pio13 6 ALT3 OUT>;
+ mrst = <&pio13 7 ALT3 IN>;
+ scl = <&pio13 5 ALT3 OUT>;
+ };
+ };
+
+ pinctrl_spi3_3w_alt3_0: spi3-3w-alt3-0 {
+ st,pins {
+ mtsr = <&pio13 6 ALT3 BIDIR_PU>;
+ scl = <&pio13 5 ALT3 OUT>;
+ };
+ };
+
+ pinctrl_spi3_4w_alt1_0: spi3-4w-alt1-0 {
+ st,pins {
+ mtsr = <&pio17 7 ALT1 OUT>;
+ mrst = <&pio17 5 ALT1 IN>;
+ scl = <&pio17 6 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi3_3w_alt1_0: spi3-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio17 7 ALT1 BIDIR_PU>;
+ scl = <&pio17 6 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi3_4w_alt1_1: spi3-4w-alt1-1 {
+ st,pins {
+ mtsr = <&pio18 6 ALT1 OUT>;
+ mrst = <&pio18 7 ALT1 IN>;
+ scl = <&pio18 5 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi3_3w_alt1_1: spi3-3w-alt1-1 {
+ st,pins {
+ mtsr = <&pio18 6 ALT1 BIDIR_PU>;
+ scl = <&pio18 5 ALT1 OUT>;
};
};
};
@@ -627,6 +891,18 @@
};
};
};
+
+ systrace {
+ pinctrl_systrace_default: systrace-default {
+ st,pins {
+ trc_data0 = <&pio11 3 ALT5 OUT>;
+ trc_data1 = <&pio11 4 ALT5 OUT>;
+ trc_data2 = <&pio11 5 ALT5 OUT>;
+ trc_data3 = <&pio11 6 ALT5 OUT>;
+ trc_clk = <&pio11 7 ALT5 OUT>;
+ };
+ };
+ };
};
pin-controller-front1 {
@@ -637,7 +913,7 @@
reg = <0x0921f080 0x4>;
reg-names = "irqmux";
interrupts = <GIC_SPI 190 IRQ_TYPE_NONE>;
- interrupts-names = "irqmux";
+ interrupt-names = "irqmux";
ranges = <0 0x09210000 0x10000>;
tsin4 {
@@ -670,7 +946,7 @@
reg = <0x0922f080 0x4>;
reg-names = "irqmux";
interrupts = <GIC_SPI 191 IRQ_TYPE_NONE>;
- interrupts-names = "irqmux";
+ interrupt-names = "irqmux";
ranges = <0 0x09220000 0x6000>;
pio30: gpio@09220000 {
@@ -758,6 +1034,47 @@
};
};
};
+
+ spi4 {
+ pinctrl_spi4_default: spi4-4w-alt1-0 {
+ st,pins {
+ mtsr = <&pio30 1 ALT1 OUT>;
+ mrst = <&pio30 2 ALT1 IN>;
+ scl = <&pio30 0 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi4_3w_alt1_0: spi4-3w-alt1-0 {
+ st,pins {
+ mtsr = <&pio30 1 ALT1 BIDIR_PU>;
+ scl = <&pio30 0 ALT1 OUT>;
+ };
+ };
+
+ pinctrl_spi4_4w_alt3_0: spi4-4w-alt3-0 {
+ st,pins {
+ mtsr = <&pio34 1 ALT3 OUT>;
+ mrst = <&pio34 2 ALT3 IN>;
+ scl = <&pio34 0 ALT3 OUT>;
+ };
+ };
+
+ pinctrl_spi4_3w_alt3_0: spi4-3w-alt3-0 {
+ st,pins {
+ mtsr = <&pio34 1 ALT3 BIDIR_PU>;
+ scl = <&pio34 0 ALT3 OUT>;
+ };
+ };
+ };
+
+ serial3 {
+ pinctrl_serial3: serial3-0 {
+ st,pins {
+ tx = <&pio31 3 ALT1 OUT>;
+ rx = <&pio31 4 ALT1 IN>;
+ };
+ };
+ };
};
pin-controller-flash {
@@ -811,6 +1128,57 @@
emmc_d7 = <&pio41 7 ALT1 BIDIR_PU>;
};
};
+ pinctrl_sd0: sd0-0 {
+ st,pins {
+ sd_clk = <&pio40 6 ALT1 BIDIR>;
+ sd_cmd = <&pio40 7 ALT1 BIDIR_PU>;
+ sd_dat0 = <&pio41 0 ALT1 BIDIR_PU>;
+ sd_dat1 = <&pio41 1 ALT1 BIDIR_PU>;
+ sd_dat2 = <&pio41 2 ALT1 BIDIR_PU>;
+ sd_dat3 = <&pio41 3 ALT1 BIDIR_PU>;
+ sd_led = <&pio42 0 ALT2 OUT>;
+ sd_pwren = <&pio42 2 ALT2 OUT>;
+ sd_vsel = <&pio42 3 ALT2 OUT>;
+ sd_cd = <&pio42 4 ALT2 IN>;
+ sd_wp = <&pio42 5 ALT2 IN>;
+ };
+ };
+ };
+
+ fsm {
+ pinctrl_fsm: fsm {
+ st,pins {
+ spi-fsm-clk = <&pio40 1 ALT1 OUT>;
+ spi-fsm-cs = <&pio40 0 ALT1 OUT>;
+ spi-fsm-mosi = <&pio40 2 ALT1 OUT>;
+ spi-fsm-miso = <&pio40 3 ALT1 IN>;
+ spi-fsm-hol = <&pio40 5 ALT1 OUT>;
+ spi-fsm-wp = <&pio40 4 ALT1 OUT>;
+ };
+ };
+ };
+
+ nand {
+ pinctrl_nand: nand {
+ st,pins {
+ nand_cs1 = <&pio40 6 ALT3 OUT>;
+ nand_cs0 = <&pio40 7 ALT3 OUT>;
+ nand_d0 = <&pio41 0 ALT3 BIDIR>;
+ nand_d1 = <&pio41 1 ALT3 BIDIR>;
+ nand_d2 = <&pio41 2 ALT3 BIDIR>;
+ nand_d3 = <&pio41 3 ALT3 BIDIR>;
+ nand_d4 = <&pio41 4 ALT3 BIDIR>;
+ nand_d5 = <&pio41 5 ALT3 BIDIR>;
+ nand_d6 = <&pio41 6 ALT3 BIDIR>;
+ nand_d7 = <&pio41 7 ALT3 BIDIR>;
+ nand_we = <&pio42 0 ALT3 OUT>;
+ nand_dqs = <&pio42 1 ALT3 OUT>;
+ nand_ale = <&pio42 2 ALT3 OUT>;
+ nand_cle = <&pio42 3 ALT3 OUT>;
+ nand_rnb = <&pio42 4 ALT3 IN>;
+ nand_oe = <&pio42 5 ALT3 OUT>;
+ };
+ };
};
};
};
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407.dtsi
index 6b914e4..d60f0d8 100644
--- a/arch/arm/boot/dts/stih407.dtsi
+++ b/arch/arm/boot/dts/stih407.dtsi
@@ -10,19 +10,6 @@
#include "stih407-family.dtsi"
/ {
soc {
- /* Display */
- vtg_main: sti-vtg-main@8d02800 {
- compatible = "st,vtg";
- reg = <0x8d02800 0x200>;
- interrupts = <GIC_SPI 108 IRQ_TYPE_NONE>;
- };
-
- vtg_aux: sti-vtg-aux@8d00200 {
- compatible = "st,vtg";
- reg = <0x8d00200 0x100>;
- interrupts = <GIC_SPI 109 IRQ_TYPE_NONE>;
- };
-
sti-display-subsystem {
compatible = "st,sti-display-subsystem";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/stih410-b2120.dts b/arch/arm/boot/dts/stih410-b2120.dts
index 16f02c5..118ac28 100644
--- a/arch/arm/boot/dts/stih410-b2120.dts
+++ b/arch/arm/boot/dts/stih410-b2120.dts
@@ -25,6 +25,7 @@
aliases {
ttyAS0 = &sbc_serial0;
+ ethernet0 = &ethernet0;
};
soc {
@@ -35,5 +36,29 @@
sd-uhs-sdr104;
sd-uhs-ddr50;
};
+
+ usb2_picophy1: phy2 {
+ status = "okay";
+ };
+
+ usb2_picophy2: phy3 {
+ status = "okay";
+ };
+
+ ohci0: usb@9a03c00 {
+ status = "okay";
+ };
+
+ ehci0: usb@9a03e00 {
+ status = "okay";
+ };
+
+ ohci1: usb@9a83c00 {
+ status = "okay";
+ };
+
+ ehci1: usb@9a83e00 {
+ status = "okay";
+ };
};
};
diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
index 8c6e61a..18ed1ad 100644
--- a/arch/arm/boot/dts/stih410.dtsi
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -22,6 +22,8 @@
resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
<&picophyreset STIH407_PICOPHY0_RESET>;
reset-names = "global", "port";
+
+ status = "disabled";
};
usb2_picophy2: phy3 {
@@ -31,6 +33,8 @@
resets = <&softreset STIH407_PICOPHY_SOFTRESET>,
<&picophyreset STIH407_PICOPHY1_RESET>;
reset-names = "global", "port";
+
+ status = "disabled";
};
ohci0: usb@9a03c00 {
@@ -43,6 +47,8 @@
reset-names = "power", "softreset";
phys = <&usb2_picophy1>;
phy-names = "usb";
+
+ status = "disabled";
};
ehci0: usb@9a03e00 {
@@ -57,6 +63,8 @@
reset-names = "power", "softreset";
phys = <&usb2_picophy1>;
phy-names = "usb";
+
+ status = "disabled";
};
ohci1: usb@9a83c00 {
@@ -69,6 +77,8 @@
reset-names = "power", "softreset";
phys = <&usb2_picophy2>;
phy-names = "usb";
+
+ status = "disabled";
};
ehci1: usb@9a83e00 {
@@ -83,19 +93,8 @@
reset-names = "power", "softreset";
phys = <&usb2_picophy2>;
phy-names = "usb";
- };
-
- /* Display */
- vtg_main: sti-vtg-main@8d02800 {
- compatible = "st,vtg";
- reg = <0x8d02800 0x200>;
- interrupts = <GIC_SPI 108 IRQ_TYPE_NONE>;
- };
- vtg_aux: sti-vtg-aux@8d00200 {
- compatible = "st,vtg";
- reg = <0x8d00200 0x100>;
- interrupts = <GIC_SPI 109 IRQ_TYPE_NONE>;
+ status = "disabled";
};
sti-display-subsystem {
diff --git a/arch/arm/boot/dts/stih418-b2199.dts b/arch/arm/boot/dts/stih418-b2199.dts
index 82eee39..772d2bb 100644
--- a/arch/arm/boot/dts/stih418-b2199.dts
+++ b/arch/arm/boot/dts/stih418-b2199.dts
@@ -24,6 +24,7 @@
aliases {
ttyAS0 = &sbc_serial0;
+ ethernet0 = &ethernet0;
};
soc {
@@ -101,5 +102,12 @@
st_dwc3: dwc3@8f94000 {
status = "okay";
};
+
+ ethernet0: dwmac@9630000 {
+ st,tx-retime-src = "clkgen";
+ status = "okay";
+ phy-mode = "rgmii";
+ fixed-link = <0 1 1000 0 0>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih418-clock.dtsi b/arch/arm/boot/dts/stih418-clock.dtsi
index 148e177..ae6d997 100644
--- a/arch/arm/boot/dts/stih418-clock.dtsi
+++ b/arch/arm/boot/dts/stih418-clock.dtsi
@@ -44,7 +44,7 @@
clockgen_a9_pll: clockgen-a9-pll {
#clock-cells = <1>;
- compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+ compatible = "st,stih418-plls-c28-a9", "st,clkgen-plls-c32";
clocks = <&clk_sysin>;
diff --git a/arch/arm/boot/dts/stih418.dtsi b/arch/arm/boot/dts/stih418.dtsi
index 8160a75..965f881 100644
--- a/arch/arm/boot/dts/stih418.dtsi
+++ b/arch/arm/boot/dts/stih418.dtsi
@@ -99,5 +99,11 @@
phys = <&usb2_picophy2>;
phy-names = "usb";
};
+
+ mmc0: sdhci@09060000 {
+ assigned-clocks = <&clk_s_c0_flexgen CLK_MMC_0>;
+ assigned-clock-parents = <&clk_s_c0_pll1 0>;
+ assigned-clock-rates = <200000000>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
index f589fe4..133375b 100644
--- a/arch/arm/boot/dts/stihxxx-b2120.dtsi
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -6,6 +6,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <dt-bindings/clock/stih407-clks.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/media/c8sectpfe.h>
/ {
soc {
sbc_serial0: serial@9530000 {
@@ -27,14 +30,28 @@
};
};
- i2c@9842000 {
+ pwm0: pwm@9810000 {
status = "okay";
};
- i2c@9843000 {
+ pwm1: pwm@9510000 {
status = "okay";
};
+ ssc2: i2c@9842000 {
+ status = "okay";
+ clock-frequency = <100000>;
+ st,i2c-min-scl-pulse-width-us = <0>;
+ st,i2c-min-sda-pulse-width-us = <5>;
+ };
+
+ ssc3: i2c@9843000 {
+ status = "okay";
+ clock-frequency = <100000>;
+ st,i2c-min-scl-pulse-width-us = <0>;
+ st,i2c-min-sda-pulse-width-us = <5>;
+ };
+
i2c@9844000 {
status = "okay";
};
@@ -79,5 +96,44 @@
status = "okay";
};
+ ethernet0: dwmac@9630000 {
+ st,tx-retime-src = "clkgen";
+ status = "okay";
+ phy-mode = "rgmii";
+ fixed-link = <0 1 1000 0 0>;
+ };
+
+ demux@08a20000 {
+ compatible = "st,stih407-c8sectpfe";
+ status = "okay";
+ reg = <0x08a20000 0x10000>,
+ <0x08a00000 0x4000>;
+ reg-names = "c8sectpfe", "c8sectpfe-ram";
+ interrupts = <GIC_SPI 34 IRQ_TYPE_NONE>,
+ <GIC_SPI 35 IRQ_TYPE_NONE>;
+ interrupt-names = "c8sectpfe-error-irq",
+ "c8sectpfe-idle-irq";
+ pinctrl-0 = <&pinctrl_tsin0_serial>;
+ pinctrl-1 = <&pinctrl_tsin0_parallel>;
+ pinctrl-2 = <&pinctrl_tsin3_serial>;
+ pinctrl-3 = <&pinctrl_tsin4_serial_alt3>;
+ pinctrl-4 = <&pinctrl_tsin5_serial_alt1>;
+ pinctrl-names = "tsin0-serial",
+ "tsin0-parallel",
+ "tsin3-serial",
+ "tsin4-serial",
+ "tsin5-serial";
+ clocks = <&clk_s_c0_flexgen CLK_PROC_STFE>;
+ clock-names = "c8sectpfe";
+
+ /* tsin0 is TSA on NIMA */
+ tsin0: port@0 {
+ tsin-num = <0>;
+ serial-not-parallel;
+ i2c-bus = <&ssc2>;
+ reset-gpios = <&pio15 4 GPIO_ACTIVE_HIGH>;
+ dvb-card = <STV0367_TDA18212_NIMA_1>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index 2630d78..97570cb 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -93,6 +93,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
index 1430568..5366089 100644
--- a/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
+++ b/arch/arm/boot/dts/sun4i-a10-chuwi-v7-cw0825.dts
@@ -78,6 +78,18 @@
};
};
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
&lradc {
vref-supply = <&reg_vcc3v0>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 046a84d..710e2ef 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -83,6 +83,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
diff --git a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
index 570754d..3f0aeb8 100644
--- a/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
+++ b/arch/arm/boot/dts/sun4i-a10-gemei-g9.dts
@@ -47,6 +47,7 @@
#include "sunxi-common-regulators.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
/ {
model = "Gemei G9 Tablet";
@@ -64,7 +65,7 @@
/*
* TODO:
* 2x cameras via CSI
- * bma250 IRQs
+ * audio
* AXP battery management
* NAND
* OTG
@@ -103,12 +104,8 @@
bma250@18 {
compatible = "bosch,bma250";
reg = <0x18>;
-
- /*
- * TODO: interrupt pins:
- * int1 - PH00
- * int2 - PI10
- */
+ interrupt-parent = <&pio>;
+ interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH00 / EINT0 */
};
};
diff --git a/arch/arm/boot/dts/sun4i-a10-inet1.dts b/arch/arm/boot/dts/sun4i-a10-inet1.dts
new file mode 100644
index 0000000..487ce63
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-inet1.dts
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "iNet-1";
+ compatible = "inet-tek,inet1", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ /* Accelerometer */
+ bma250@18 {
+ compatible = "bosch,bma250";
+ reg = <0x18>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH0 / EINT0 */
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@1000 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <1000000>;
+ };
+
+ button@1200 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <1200000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index 6c927a8..77c31da 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -47,6 +47,7 @@
#include "sunxi-common-regulators.dtsi"
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
/ {
model = "INet-97F Rev 02";
@@ -61,8 +62,8 @@
};
};
-&ehci0 {
- status = "okay";
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
};
&ehci1 {
@@ -75,12 +76,62 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@200 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@600 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+
+ button@800 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+
+ button@1000 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <1000000>;
+ };
- interrupt-controller;
- #interrupt-cells = <1>;
+ button@1200 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1200000>;
};
};
@@ -94,15 +145,52 @@
status = "okay";
};
-&ohci0 {
+&otg_sram {
status = "okay";
};
-&ohci1 {
- status = "okay";
+&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
};
-&reg_usb1_vbus {
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
status = "okay";
};
@@ -116,8 +204,17 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
- usb1_vbus-supply = <&reg_usb1_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
new file mode 100644
index 0000000..2fffc04
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-inet9f-rev03.dts
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "iNet-9F Rev 03";
+ compatible = "inet-tek,inet9f-rev03", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ /* Accelerometer */
+ bma250@18 {
+ compatible = "bosch,bma250";
+ reg = <0x18>;
+ interrupt-parent = <&pio>;
+ interrupts = <7 0 IRQ_TYPE_EDGE_RISING>; /* PH0 / EINT0 */
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@200 {
+ label = "Menu";
+ linux,code = <KEY_MENU>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@600 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+
+ button@800 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+
+ button@1000 {
+ label = "Home";
+ linux,code = <KEY_HOMEPAGE>;
+ channel = <0>;
+ voltage = <1000000>;
+ };
+
+ button@1200 {
+ label = "Esc";
+ linux,code = <KEY_ESC>;
+ channel = <0>;
+ voltage = <1200000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
index dc2f2ae..7afc7a6 100644
--- a/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
+++ b/arch/arm/boot/dts/sun4i-a10-jesurun-q5.dts
@@ -156,6 +156,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
emac_power_pin_q5: emac_power_pin@0 {
allwinner,pins = "PH19";
@@ -172,6 +176,11 @@
};
};
+&reg_usb0_vbus {
+ regulator-boot-on;
+ status = "okay";
+};
+
&reg_usb1_vbus {
status = "okay";
};
@@ -186,7 +195,13 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
&usbphy {
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun4i-a10-marsboard.dts b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
index 02158bc..8e50723 100644
--- a/arch/arm/boot/dts/sun4i-a10-marsboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-marsboard.dts
@@ -91,6 +91,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&ehci0 {
status = "okay";
};
@@ -154,6 +158,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
led_pins_marsboard: led_pins@0 {
allwinner,pins = "PB5", "PB6", "PB7", "PB8";
@@ -161,6 +169,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
&reg_usb1_vbus {
@@ -184,7 +199,15 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index 28e32ad..b350448 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -124,6 +124,18 @@
};
};
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ eeprom: eeprom@50 {
+ compatible = "atmel,24c16";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+};
+
&mdio {
status = "okay";
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index 4e3e1b9..39034aa 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -104,6 +104,10 @@
};
};
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
&ehci0 {
status = "okay";
};
@@ -129,12 +133,8 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupts = <0>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
};
};
@@ -164,6 +164,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
led_pins_pcduino: led_pins@0 {
allwinner,pins = "PH15", "PH16";
@@ -178,14 +182,40 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
-&reg_usb1_vbus {
- status = "okay";
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
};
-&reg_usb2_vbus {
- status = "okay";
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
};
&uart0 {
@@ -194,8 +224,16 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
- usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb1_vbus-supply = <&reg_vcc5v0>; /* USB1 VBUS is always on */
+ usb2_vbus-supply = <&reg_vcc5v0>; /* USB2 VBUS is always on */
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino2.dts b/arch/arm/boot/dts/sun4i-a10-pcduino2.dts
new file mode 100644
index 0000000..de483a1
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino2.dts
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2015 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The LinkSprite pcDuino2 board is almost identical to the older
+ * LinkSprite pcDuino1 board. The only software visible difference
+ * is that the pcDuino2 board got a USB VBUS voltage regulator, which
+ * is controlled by the PD2 pin (pulled-up by default). Also one of
+ * the USB host ports has been replaced with a USB WIFI chip.
+ */
+
+#include "sun4i-a10-pcduino.dts"
+
+/ {
+ model = "LinkSprite pcDuino2";
+ compatible = "linksprite,a10-pcduino2", "allwinner,sun4i-a10";
+};
+
+&pio {
+ usb2_vbus_pin_pcduino2: usb2_vbus_pin@0 {
+ allwinner,pins = "PD2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb2_vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_vbus_pin_pcduino2>;
+ gpio = <&pio 3 2 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_vcc3v3>; /* USB WIFI is always on */
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
new file mode 100644
index 0000000..82e69c3
--- /dev/null
+++ b/arch/arm/boot/dts/sun4i-a10-pov-protab2-ips9.dts
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun4i-a10.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Point of View Protab2-IPS9";
+ compatible = "pov,protab2-ips9", "allwinner,sun4i-a10";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ /* pull-ups and devices require AXP209 LDO3 */
+ status = "failed";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@400 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+
+ button@800 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <800000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 1f3c51a..aa90f31 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -45,6 +45,7 @@
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
#include <dt-bindings/dma/sun4i-a10.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -195,6 +196,15 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll2-clk";
+ reg = <0x01c20008 0x8>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2-1x", "pll2-2x",
+ "pll2-4x", "pll2-8x";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-pll1-clk";
@@ -481,6 +491,14 @@
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
clock-output-names = "spi3";
};
+
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "codec";
+ };
};
soc@01c00000 {
@@ -1004,6 +1022,19 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec";
+ reg = <0x01c22c00 0x40>;
+ interrupts = <30>;
+ clocks = <&apb0_gates 0>, <&codec_clk>;
+ clock-names = "apb", "codec";
+ dmas = <&dma SUN4I_DMA_NORMAL 19>,
+ <&dma SUN4I_DMA_NORMAL 19>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
diff --git a/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts
new file mode 100644
index 0000000..d4ad021
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a10s-auxtek-t003.dts
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Auxtek t003 A10s hdmi tv-stick";
+ compatible = "allwinner,auxtek-t003", "allwinner,sun5i-a10s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_t003>;
+
+ red {
+ label = "t003-tv-dongle:red:usr";
+ gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>; /* PB2 */
+ default-state = "on";
+ };
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp152: pmic@30 {
+ compatible = "x-powers,axp152";
+ reg = <0x30>;
+ interrupts = <0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_t003>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_t003: mmc0_cd_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ led_pins_t003: led_pins@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_usb0_vbus {
+ gpio = <&pio 6 13 GPIO_ACTIVE_HIGH>; /* PG13 */
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>; /* PB10 */
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb0_vbus_pin_a {
+ allwinner,pins = "PG13";
+};
+
+&usb1_vbus_pin_a {
+ allwinner,pins = "PB10";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index 5a422c1..86d046a 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -111,7 +111,7 @@
status = "okay";
at24@50 {
- compatible = "at,24c16";
+ compatible = "atmel,24c16";
pagesize = <16>;
reg = <0x50>;
read-only;
diff --git a/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
new file mode 100644
index 0000000..9fea918
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a10s-wobo-i5.dts
@@ -0,0 +1,224 @@
+/*
+ * Copyright 2015 Jelle van der Waa <jelle@vdwaa.nl>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a10s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "A10s-Wobo i5";
+ compatible = "wobo,a10s-wobo-i5", "allwinner,sun5i-a10s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_wobo_i5>;
+
+ blue {
+ label = "a10s-wobo-i5:blue:usr";
+ gpios = <&pio 1 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+ };
+
+ reg_emac_3v3: emac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_power_pin_wobo>;
+ regulator-name = "emac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pio 0 2 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&emac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_pins_b>;
+ phy = <&phy1>;
+ status = "okay";
+};
+
+&emac_sram {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&mdio {
+ phy-supply = <&reg_emac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_wobo_i5>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; /* PB3 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ led_pins_wobo_i5: led_pins@0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_wobo_i5: mmc0_cd_pin@0 {
+ allwinner,pins = "PB3";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ emac_power_pin_wobo: emac_power_pin@0 {
+ allwinner,pins = "PA02";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_ldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_usb1_vbus {
+ gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usb1_vbus_pin_a {
+ allwinner,pins = "PG12";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index a513b41..bddd0de 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -77,6 +77,15 @@
clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 44>;
status = "disabled";
};
+
+ framebuffer@2 {
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-tve0";
+ clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
};
clocks {
@@ -156,6 +165,14 @@
#size-cells = <0>;
};
+ pwm: pwm@01c20e00 {
+ compatible = "allwinner,sun5i-a10s-pwm";
+ reg = <0x01c20e00 0xc>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
@@ -195,13 +212,6 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
- uart3_pins_a: uart3@0 {
- allwinner,pins = "PG9", "PG10";
- allwinner,function = "uart3";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
- };
-
emac_pins_a: emac0@0 {
allwinner,pins = "PA0", "PA1", "PA2",
"PA3", "PA4", "PA5", "PA6",
@@ -213,6 +223,17 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ emac_pins_b: emac0@1 {
+ allwinner,pins = "PD6", "PD7", "PD10",
+ "PD11", "PD12", "PD13", "PD14",
+ "PD15", "PD18", "PD19", "PD20",
+ "PD21", "PD22", "PD23", "PD24",
+ "PD25", "PD26", "PD27";
+ allwinner,function = "emac";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc1_pins_a: mmc1@0 {
allwinner,pins = "PG3", "PG4", "PG5",
"PG6", "PG7", "PG8";
diff --git a/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts b/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts
new file mode 100644
index 0000000..6fa54b6
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-inet-98v-rev2.dts
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a13.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "INet-98V Rev 02";
+ compatible = "primux,inet98v-rev2", "allwinner,sun5i-a13";
+
+ aliases {
+ serial0 = &uart1;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ pcf8563: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_ldo2>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_inet98fv2>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+
+ mmccard: mmccard@0 {
+ reg = <0>;
+ compatible = "mmc-card";
+ broken-hpi;
+ };
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_inet98fv2: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PG2";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-name = "vdd-int-pll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_ldo3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_usb0_vbus {
+ gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb0_vbus_pin_a {
+ allwinner,pins = "PG12";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_ldo3>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts b/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts
new file mode 100644
index 0000000..72e93ac
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-a13-q8-tablet.dts
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-a13.dtsi"
+#include "sun5i-q8-common.dtsi"
+
+/ {
+ model = "Q8 A13 Tablet";
+ compatible = "allwinner,q8-a13", "allwinner,sun5i-a13";
+};
+
+&reg_ldo3 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_ldo3>;
+};
diff --git a/arch/arm/boot/dts/sun5i-a13.dtsi b/arch/arm/boot/dts/sun5i-a13.dtsi
index f3631c9..d910d3a 100644
--- a/arch/arm/boot/dts/sun5i-a13.dtsi
+++ b/arch/arm/boot/dts/sun5i-a13.dtsi
@@ -150,6 +150,16 @@
"apb1_uart3";
};
};
+
+ soc@01c00000 {
+ pwm: pwm@01c20e00 {
+ compatible = "allwinner,sun5i-a13-pwm";
+ reg = <0x01c20e00 0xc>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+ };
};
&cpu0 {
diff --git a/arch/arm/boot/dts/sun5i-q8-common.dtsi b/arch/arm/boot/dts/sun5i-q8-common.dtsi
new file mode 100644
index 0000000..a78e189
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-q8-common.dtsi
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "sunxi-q8-common.dtsi"
+
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ aliases {
+ serial0 = &uart1;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ /* TODO: backlight uses axp gpio1 as enable pin */
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupts = <0>;
+ };
+};
+
+&i2c1 {
+ pcf8563: rtc@51 {
+ compatible = "nxp,pcf8563";
+ reg = <0x51>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 6 0 GPIO_ACTIVE_HIGH>; /* PG0 */
+ cd-inverted;
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_q8: mmc0_cd_pin@0 {
+ allwinner,pins = "PG0";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PG1";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PG2";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_pin_a: usb0_vbus_pin@0 {
+ allwinner,pins = "PG12";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-pll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ gpio = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ usb0_vbus_det-gpio = <&pio 6 1 GPIO_ACTIVE_HIGH>; /* PG1 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun5i-r8-chip.dts b/arch/arm/boot/dts/sun5i-r8-chip.dts
new file mode 100644
index 0000000..530ab28
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-r8-chip.dts
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2015 Free Electrons
+ * Copyright 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun5i-r8.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "NextThing C.H.I.P.";
+ compatible = "nextthing,chip", "allwinner,sun5i-r8";
+
+ aliases {
+ i2c0 = &i2c0;
+ i2c2 = &i2c2;
+ serial0 = &uart1;
+ serial1 = &uart3;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&codec {
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+
+ /*
+ * The interrupt is routed through the "External Fast
+ * Interrupt Request" pin (ball G13 of the module)
+ * directly to the main interrupt controller, without
+ * any other controller interfering.
+ */
+ interrupts = <0>;
+ };
+};
+
+#include "axp209.dtsi"
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+
+ xio: gpio@38 {
+ compatible = "nxp,pcf8574a";
+ reg = <0x38>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-parent = <&pio>;
+ interrupts = <6 0 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ chip_vbus_pin: chip_vbus_pin@0 {
+ allwinner,pins = "PB10";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ chip_id_det_pin: chip_id_det_pin@0 {
+ allwinner,pins = "PG2";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "cpuvdd";
+ regulator-always-on;
+};
+
+&reg_dcdc3 {
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-name = "corevdd";
+ regulator-always-on;
+};
+
+&reg_ldo1 {
+ regulator-name = "rtcvdd";
+};
+
+&reg_ldo2 {
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+ regulator-always-on;
+};
+
+&reg_ldo5 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-name = "vcc-1v8";
+};
+
+&reg_usb0_vbus {
+ pinctrl-0 = <&chip_vbus_pin>;
+ vin-supply = <&reg_vcc5v0>;
+ gpio = <&pio 1 10 GPIO_ACTIVE_HIGH>; /* PB10 */
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart1_pins_b>;
+ status = "okay";
+};
+
+&uart3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_a>,
+ <&uart3_pins_cts_rts_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&chip_id_det_pin>;
+ status = "okay";
+
+ usb0_id_det-gpio = <&pio 6 2 GPIO_ACTIVE_HIGH>; /* PG2 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_vcc5v0>;
+};
diff --git a/arch/arm/boot/dts/sun5i-r8.dtsi b/arch/arm/boot/dts/sun5i-r8.dtsi
new file mode 100644
index 0000000..0ef8656
--- /dev/null
+++ b/arch/arm/boot/dts/sun5i-r8.dtsi
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2015 Free Electrons
+ * Copyright 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "sun5i-a13.dtsi"
+
+/ {
+ chosen {
+ framebuffer@1 {
+ compatible = "allwinner,simple-framebuffer",
+ "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-tve0";
+ clocks = <&pll5 1>, <&ahb_gates 34>, <&ahb_gates 36>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun5i.dtsi b/arch/arm/boot/dts/sun5i.dtsi
index 78b993a..59a9426 100644
--- a/arch/arm/boot/dts/sun5i.dtsi
+++ b/arch/arm/boot/dts/sun5i.dtsi
@@ -44,6 +44,7 @@
#include "skeleton.dtsi"
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
#include <dt-bindings/dma/sun4i-a10.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -102,6 +103,15 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun5i-a13-pll2-clk";
+ reg = <0x01c20008 0x8>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2-1x", "pll2-2x",
+ "pll2-4x", "pll2-8x";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-pll1-clk";
@@ -285,6 +295,14 @@
clock-output-names = "usb_ohci0", "usb_phy";
};
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "codec";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun5i-a13-mbus-clk";
@@ -529,6 +547,27 @@
allwinner,drive = <SUN4I_PINCTRL_30_MA>;
allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
};
+
+ uart3_pins_a: uart3@0 {
+ allwinner,pins = "PG9", "PG10";
+ allwinner,function = "uart3";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ uart3_pins_cts_rts_a: uart3-cts-rts@0 {
+ allwinner,pins = "PG11", "PG12";
+ allwinner,function = "uart3";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ pwm0_pins: pwm0 {
+ allwinner,pins = "PB2";
+ allwinner,function = "pwm";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
timer@01c20c00 {
@@ -550,6 +589,19 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec";
+ reg = <0x01c22c00 0x40>;
+ interrupts = <30>;
+ clocks = <&apb0_gates 0>, <&codec_clk>;
+ clock-names = "apb", "codec";
+ dmas = <&dma SUN4I_DMA_NORMAL 19>,
+ <&dma SUN4I_DMA_NORMAL 19>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun4i-a10-sid";
reg = <0x01c23800 0x10>;
diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts
index 0cf9926..f9cf368 100644
--- a/arch/arm/boot/dts/sun6i-a31-colombus.dts
+++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts
@@ -60,12 +60,34 @@
chosen {
stdout-path = "serial0:115200n8";
};
+
+ i2c_lcd: i2c@0 {
+ /* The lcd panel i2c interface is hooked up via gpios */
+ compatible = "i2c-gpio";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c_lcd_pins>;
+ gpios = <&pio 0 23 GPIO_ACTIVE_HIGH>, /* PA23, sda */
+ <&pio 0 24 GPIO_ACTIVE_HIGH>; /* PA24, scl */
+ i2c-gpio,delay-us = <5>;
+ };
};
&ehci1 {
status = "okay";
};
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
&i2c0 {
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins_a>;
@@ -82,6 +104,13 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c2_pins_a>;
status = "okay";
+
+ mma8452: mma8452@1d {
+ compatible = "fsl,mma8452";
+ reg = <0x1d>;
+ interrupt-parent = <&pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_LOW>; /* PA9 */
+ };
};
&mmc0 {
@@ -112,6 +141,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ i2c_lcd_pins: i2c_lcd_pin@0 {
+ allwinner,pins = "PA23", "PA24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
&reg_usb2_vbus {
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index d0cfada..9a74637 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -54,6 +54,8 @@
compatible = "merrii,a31-hummingbird", "allwinner,sun6i-a31";
aliases {
+ rtc0 = &pcf8563;
+ rtc1 = &rtc;
serial0 = &uart0;
};
@@ -67,13 +69,17 @@
};
};
+&cpu0 {
+ cpu-supply = <&reg_dcdc3>;
+};
+
&ehci0 {
status = "okay";
};
&gmac {
pinctrl-names = "default";
- pinctrl-0 = <&gmac_pins_rgmii_a>;
+ pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_hummingbird>;
phy = <&phy1>;
phy-mode = "rgmii";
snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>;
@@ -119,7 +125,7 @@
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_hummingbird>;
- vmmc-supply = <&vcc_3v0>;
+ vmmc-supply = <&reg_dcdc1>;
bus-width = <4>;
cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
cd-inverted;
@@ -134,7 +140,7 @@
&mmc1 {
pinctrl-names = "default";
pinctrl-0 = <&mmc1_pins_a>, <&wifi_reset_pin_hummingbird>;
- vmmc-supply = <&vcc_wifi>;
+ vmmc-supply = <&reg_aldo1>;
mmc-pwrseq = <&wifi_pwrseq>;
bus-width = <4>;
non-removable;
@@ -146,6 +152,13 @@
};
&pio {
+ gmac_phy_reset_pin_hummingbird: gmac_phy_reset_pin@0 {
+ allwinner,pins = "PA21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
mmc0_cd_pin_hummingbird: mmc0_cd_pin@0 {
allwinner,pins = "PA8";
allwinner,function = "gpio_in";
@@ -164,70 +177,69 @@
&p2wi {
status = "okay";
- axp221: pmic@68 {
+ axp22x: pmic@68 {
compatible = "x-powers,axp221";
reg = <0x68>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
- interrupt-controller;
- #interrupt-cells = <1>;
- dcdc1-supply = <&vcc_3v0>;
- dcdc5-supply = <&vcc_dram>;
-
- regulators {
- x-powers,dcdc-freq = <3000>;
-
- vcc_3v0: dcdc1 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "vcc-3v0";
- };
-
- vdd_cpu: dcdc2 {
- regulator-always-on;
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-cpu";
- };
-
- vdd_gpu: dcdc3 {
- regulator-always-on;
- regulator-min-microvolt = <700000>;
- regulator-max-microvolt = <1320000>;
- regulator-name = "vdd-gpu";
- };
-
- vdd_sys_dll: dcdc4 {
- regulator-always-on;
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-name = "vdd-sys-dll";
- };
-
- vcc_dram: dcdc5 {
- regulator-always-on;
- regulator-min-microvolt = <1500000>;
- regulator-max-microvolt = <1500000>;
- regulator-name = "vcc-dram";
- };
-
- vcc_wifi: aldo1 {
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-name = "vcc_wifi";
- };
-
- avcc: aldo3 {
- regulator-always-on;
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-name = "avcc";
- };
- };
};
};
+#include "axp22x.dtsi"
+
+&reg_aldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+};
+
+&reg_dc5ldo {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpus";
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-sys-dll";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
&reg_usb1_vbus {
gpio = <&pio 7 24 GPIO_ACTIVE_HIGH>; /* PH24 */
status = "okay";
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 54bb83b..b6ad785 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -61,7 +61,7 @@
#size-cells = <1>;
ranges;
- framebuffer@0 {
+ simplefb_hdmi: framebuffer@0 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0-hdmi";
@@ -69,7 +69,7 @@
status = "disabled";
};
- framebuffer@1 {
+ simplefb_lcd: framebuffer@1 {
compatible = "allwinner,simple-framebuffer",
"simple-framebuffer";
allwinner,pipeline = "de_be0-lcd0";
@@ -691,6 +691,24 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ mmc2_pins_a: mmc2@0 {
+ allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+ "PC10", "PC11";
+ allwinner,function = "mmc2";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ mmc2_8bit_emmc_pins: mmc2@1 {
+ allwinner,pins = "PC6", "PC7", "PC8", "PC9",
+ "PC10", "PC11", "PC12",
+ "PC13", "PC14", "PC15",
+ "PC24";
+ allwinner,function = "mmc2";
+ allwinner,drive = <SUN4I_PINCTRL_30_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
gmac_pins_mii_a: gmac_mii@0 {
allwinner,pins = "PA0", "PA1", "PA2", "PA3",
"PA8", "PA9", "PA11",
@@ -768,6 +786,13 @@
reg = <0x01c20ca0 0x20>;
};
+ lradc: lradc@01c22800 {
+ compatible = "allwinner,sun4i-a10-lradc-keys";
+ reg = <0x01c22800 0x100>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
rtp: rtp@01c25000 {
compatible = "allwinner,sun6i-a31-ts";
reg = <0x01c25000 0x100>;
@@ -1085,7 +1110,7 @@
resets = <&apb0_rst 0>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
+ #interrupt-cells = <3>;
#size-cells = <0>;
#gpio-cells = <3>;
diff --git a/arch/arm/boot/dts/sun6i-a31s-primo81.dts b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
new file mode 100644
index 0000000..68b479b
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-primo81.dts
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2014 Siarhei Siamashka <siarhei.siamashka@gmail.com>
+ * Copyright 2015 Karsten Merker <merker@debian.org>
+ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "MSI Primo81 tablet";
+ compatible = "msi,primo81", "allwinner,sun6i-a31s";
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc3>;
+};
+
+&ehci0 {
+ /* rtl8188etv wifi is connected here */
+ status = "okay";
+};
+
+&i2c0 {
+ /* pull-ups and device VDDIO use AXP221 DLDO3 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "failed";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ ctp@5d {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gt911_int_primo81>;
+ compatible = "goodix,gt911";
+ reg = <0x5d>;
+ interrupt-parent = <&pio>;
+ interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>; /* PA3 */
+ touchscreen-swapped-x-y;
+ };
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+
+ accelerometer@1c {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mma8452_int_primo81>;
+ compatible = "fsl,mma8452";
+ reg = <0x1c>;
+ interrupt-parent = <&pio>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>; /* PA9 */
+ #io-channel-cells = <1>;
+ };
+};
+
+&lradc {
+ vref-supply = <&reg_aldo3>;
+ status = "okay";
+
+ button@158 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <158730>;
+ };
+
+ button@349 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <349206>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_primo81>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ gt911_int_primo81: gt911_int_pin@0 {
+ allwinner,pins = "PA3";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mma8452_int_primo81: mma8452_int_pin@0 {
+ allwinner,pins = "PA9";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ mmc0_cd_pin_primo81: mmc0_cd_pin@0 {
+ allwinner,pins = "PA8";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&p2wi {
+ status = "okay";
+
+ axp22x: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "axp22x.dtsi"
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+};
+
+&reg_dc1sw {
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-lcd";
+};
+
+&reg_dc5ldo {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpus"; /* This is an educated guess */
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-sys-dll";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+&reg_dldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-wifi";
+};
+
+&reg_dldo3 {
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-name = "vddio-csi";
+};
+
+&reg_eldo3 {
+ regulator-min-microvolt = <1080000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-mipi-bridge";
+};
+
+&simplefb_lcd {
+ vcc-lcd-supply = <&reg_dc1sw>;
+ vdd-mipi-bridge-supply = <&reg_eldo3>;
+};
+
+&usb_otg {
+ /* otg support requires support for AXP221 usb-power-supply and GPIO */
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_dldo1>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
new file mode 100644
index 0000000..ea69fb8
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s-core.dtsi
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Sinlinx SinA31s Core Board";
+ compatible = "sinlinx,sina31s", "allwinner,sun6i-a31s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc3>;
+};
+
+/* eMMC on core board */
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_8bit_emmc_pins>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <8>;
+ non-removable;
+ status = "okay";
+};
+
+/* AXP221s PMIC on core board */
+&p2wi {
+ status = "okay";
+
+ axp22x: pmic@68 {
+ compatible = "x-powers,axp221";
+ reg = <0x68>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+#include "axp22x.dtsi"
+
+&reg_aldo3 {
+ regulator-always-on;
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "avcc";
+};
+
+&reg_dc5ldo {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpus";
+};
+
+&reg_dcdc1 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "vcc-3v0";
+};
+
+&reg_dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-gpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc4 {
+ regulator-always-on;
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <1320000>;
+ regulator-name = "vdd-sys-dll";
+};
+
+&reg_dcdc5 {
+ regulator-always-on;
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-name = "vcc-dram";
+};
+
+/* UART0 pads available on core board */
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
diff --git a/arch/arm/boot/dts/sun6i-a31s-sina31s.dts b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
new file mode 100644
index 0000000..6ead2f5
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-sina31s.dts
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* The SinA31s development board has the SinA31s core board soldered on */
+#include "sun6i-a31s-sina31s-core.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Sinlinx SinA31s Development Board";
+ compatible = "sinlinx,sina31s-sdk", "allwinner,sun6i-a31s";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pin_sina31s>;
+
+ status {
+ label = "sina31s:status:usr";
+ gpios = <&pio 7 13 GPIO_ACTIVE_HIGH>; /* PH13 */
+ };
+ };
+};
+
+&ehci0 {
+ /* USB 2.0 4 port hub IC */
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ phy-supply = <&reg_dldo1>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_aldo3>;
+ status = "okay";
+
+ button@158 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <158730>;
+ };
+
+ button@349 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <349206>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_sina31s>;
+ vmmc-supply = <&reg_dcdc1>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ led_pin_sina31s: led_pin@0 {
+ allwinner,pins = "PH13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_sina31s: mmc0_cd_pin@0 {
+ allwinner,pins = "PA4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&reg_dldo1 {
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-name = "vcc-gmac-phy";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
new file mode 100644
index 0000000..db7fa13
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-sinovoip-bpi-m2.dts
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ model = "Sinovoip BPI-M2";
+ compatible = "sinovoip,bpi-m2", "allwinner,sun6i-a31s";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_bpi_m2>;
+
+ blue {
+ label = "bpi-m2:blue:usr";
+ gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>; /* PG11 */
+ };
+
+ green {
+ label = "bpi-m2:green:usr";
+ gpios = <&pio 6 10 GPIO_ACTIVE_HIGH>; /* PG10 */
+ };
+
+ red {
+ label = "bpi-m2:red:usr";
+ gpios = <&pio 6 5 GPIO_ACTIVE_HIGH>; /* PG5 */
+ };
+ };
+
+ mmc2_pwrseq: mmc2_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pwrseq_pin_bpi_m2>;
+ reset-gpios = <&r_pio 0 8 GPIO_ACTIVE_LOW>; /* PL8 WIFI_EN */
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>, <&gmac_phy_reset_pin_bpi_m2>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ snps,reset-gpio = <&pio 0 21 GPIO_ACTIVE_HIGH>; /* PA21 */
+ snps,reset-active-low;
+ snps,reset-delays-us = <0 10000 30000>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&ir {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir_pins_a>;
+ status = "okay";
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bpi_m2>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 4 GPIO_ACTIVE_HIGH>; /* PA4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc0_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_a>;
+ vmmc-supply = <&reg_vcc3v0>;
+ mmc-pwrseq = <&mmc2_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&r_pio>;
+ interrupts = <0 5 IRQ_TYPE_LEVEL_LOW>; /* PL5 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&mmc2_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&pio {
+ gmac_phy_reset_pin_bpi_m2: gmac_phy_reset_pin@0 {
+ allwinner,pins = "PA21";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_bpi_m2: led_pins@0 {
+ allwinner,pins = "PG5", "PG10", "PG11";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_bpi_m2: mmc0_cd_pin@0 {
+ allwinner,pins = "PA4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&r_pio {
+ mmc2_pwrseq_pin_bpi_m2: mmc2_pwrseq_pin@0 {
+ allwinner,pins = "PL8";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
new file mode 100644
index 0000000..b199020
--- /dev/null
+++ b/arch/arm/boot/dts/sun6i-a31s-yones-toptech-bs1078-v2.dts
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2015 Lawrence Yu <lyu@micile.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun6i-a31s.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Yones TopTech BS1078 v2 Tablet";
+ compatible = "yones-toptech,bs1078-v2", "allwinner,sun6i-a31s";
+
+ aliases {
+ serial0 = &uart0;
+ i2c1 = &i2c1;
+ i2c2 = &i2c2;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_bs1078v2: mmc0_cd_pin@0 {
+ allwinner,pins = "PA8";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bs1078v2>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 0 8 GPIO_ACTIVE_HIGH>; /* PA8 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc0_pins_a {
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+};
+
+&reg_usb1_vbus {
+ gpio = <&pio 7 27 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&usb1_vbus_pin_a {
+ allwinner,pins = "PH27";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
index 9f7b472..fd7594f 100644
--- a/arch/arm/boot/dts/sun7i-a20-bananapi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -92,6 +92,20 @@
status = "okay";
};
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+ operating-points = <
+ /* kHz uV */
+ 960000 1400000
+ 912000 1400000
+ 864000 1350000
+ 720000 1250000
+ 528000 1150000
+ 312000 1100000
+ 144000 1050000
+ >;
+};
+
&ehci0 {
status = "okay";
};
@@ -119,13 +133,9 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
};
};
@@ -159,7 +169,18 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
allwinner,pins = "PH10";
allwinner,function = "gpio_in";
@@ -182,6 +203,37 @@
};
};
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ status = "okay";
+};
+
&reg_usb1_vbus {
status = "okay";
};
@@ -216,7 +268,21 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
index 39a51d5..1fa832d 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubieboard2.dts
@@ -84,6 +84,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
@@ -150,6 +154,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
led_pins_cubieboard2: led_pins@0 {
allwinner,pins = "PH20", "PH21";
@@ -157,12 +165,24 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
&reg_ahci_5v {
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
#include "axp209.dtsi"
&reg_dcdc2 {
@@ -205,6 +225,9 @@
};
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index e6b0192..8da939a 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -101,6 +101,10 @@
status = "okay";
};
+&codec {
+ status = "okay";
+};
+
&cpu0 {
cpu-supply = <&reg_dcdc2>;
};
diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
new file mode 100644
index 0000000..b7fe102
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2015 - Marcus Cooper <codekipper@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Olimex A20-Olimex-SOM-EVB";
+ compatible = "olimex,a20-olimex-som-evb", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olimex_som_evb>;
+
+ green {
+ label = "a20-olimex-som-evb:green:usr";
+ gpios = <&pio 7 2 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+ };
+};
+
+&ahci {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&gmac {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&pio {
+ ahci_pwr_pin_olimex_som_evb: ahci_pwr_pin@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ led_pins_olimex_som_evb: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+};
+
+&reg_ahci_5v {
+ pinctrl-0 = <&ahci_pwr_pin_olimex_som_evb>;
+ gpio = <&pio 2 3 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usbphy {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
index 0423708..35ad700 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
@@ -117,6 +117,18 @@
};
};
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+
+ eeprom: eeprom@50 {
+ compatible = "atmel,24c16";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
+};
+
&mmc0 {
pinctrl-names = "default";
pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
index 8acff78..d5c796c 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -170,6 +170,12 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_a>;
status = "okay";
+
+ eeprom: eeprom@50 {
+ compatible = "atmel,24c16";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
};
&mmc0 {
@@ -190,6 +196,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
allwinner,pins = "PC3";
@@ -204,6 +214,27 @@
allwinner,drive = <SUN4I_PINCTRL_20_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
+ usb0_vbus_detect_pin: usb0_vbus_detect_pin@0 {
+ allwinner,pins = "PH5";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_DOWN>;
+ };
+
+ usb0_vbus_pin_lime2: usb0_vbus_pin@0 {
+ allwinner,pins = "PC17";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
};
&reg_ahci_5v {
@@ -212,6 +243,12 @@
status = "okay";
};
+&reg_usb0_vbus {
+ pinctrl-0 = <&usb0_vbus_pin_lime2>;
+ gpio = <&pio 2 17 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
&reg_usb1_vbus {
status = "okay";
};
@@ -226,7 +263,17 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_det-gpio = <&pio 7 5 GPIO_ACTIVE_HIGH>; /* PH5 */
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
index c5d70ca..7e3006f 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-micro.dts
@@ -125,6 +125,12 @@
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_a>;
status = "okay";
+
+ eeprom: eeprom@50 {
+ compatible = "atmel,24c16";
+ reg = <0x50>;
+ pagesize = <16>;
+ };
};
&i2c2 {
diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
index 73cd81ee..4f65664 100644
--- a/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi-mini.dts
@@ -156,7 +156,18 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
allwinner,pins = "PH10";
allwinner,function = "gpio_in";
@@ -225,6 +236,10 @@
regulator-name = "avcc";
};
+&reg_usb0_vbus {
+ status = "okay";
+};
+
&reg_usb1_vbus {
pinctrl-0 = <&usb1_vbus_pin_bananapro>;
gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
@@ -243,7 +258,21 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-orangepi.dts b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
index 55a06ce..71125bf 100644
--- a/arch/arm/boot/dts/sun7i-a20-orangepi.dts
+++ b/arch/arm/boot/dts/sun7i-a20-orangepi.dts
@@ -141,7 +141,18 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
mmc0_cd_pin_orangepi: mmc0_cd_pin@0 {
allwinner,pins = "PH10";
allwinner,function = "gpio_in";
@@ -203,6 +214,10 @@
regulator-name = "avcc";
};
+&reg_usb0_vbus {
+ status = "okay";
+};
+
&reg_usb1_vbus {
pinctrl-0 = <&usb1_vbus_pin_bananapro>;
gpio = <&pio 7 26 GPIO_ACTIVE_HIGH>; /* PH26 */
@@ -221,7 +236,21 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
index 5361fce..1757a6a 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3-nano.dts
@@ -82,6 +82,10 @@
status = "okay";
};
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
&ehci0 {
status = "okay";
};
@@ -108,13 +112,9 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
};
};
@@ -142,6 +142,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
ahci_pwr_pin_pcduino3_nano: ahci_pwr_pin@0 {
allwinner,pins = "PH2";
@@ -157,8 +161,15 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
usb1_vbus_pin_pcduino3_nano: usb1_vbus_pin@0 {
- allwinner,pins = "PH11";
+ allwinner,pins = "PD2";
allwinner,function = "gpio_out";
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
@@ -171,13 +182,37 @@
status = "okay";
};
-&reg_usb1_vbus {
- pinctrl-0 = <&usb1_vbus_pin_pcduino3_nano>;
- gpio = <&pio 7 11 GPIO_ACTIVE_HIGH>; /* PH11 */
- status = "okay";
+#include "axp209.dtsi"
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
};
-&reg_usb2_vbus {
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-pll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+/* A single regulator (U24) powers both USB host ports. */
+&reg_usb1_vbus {
+ pinctrl-0 = <&usb1_vbus_pin_pcduino3_nano>;
+ gpio = <&pio 3 2 GPIO_ACTIVE_HIGH>; /* PD2 */
status = "okay";
};
@@ -187,8 +222,16 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
usb1_vbus-supply = <&reg_usb1_vbus>;
- usb2_vbus-supply = <&reg_usb2_vbus>;
+ usb2_vbus-supply = <&reg_usb1_vbus>;
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index afc9ece..861a4a6 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -111,6 +111,10 @@
allwinner,pins = "PH2";
};
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
&ehci0 {
status = "okay";
};
@@ -137,16 +141,14 @@
status = "okay";
axp209: pmic@34 {
- compatible = "x-powers,axp209";
reg = <0x34>;
interrupt-parent = <&nmi_intc>;
interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
-
- interrupt-controller;
- #interrupt-cells = <1>;
};
};
+#include "axp209.dtsi"
+
&ir0 {
pinctrl-names = "default";
pinctrl-0 = <&ir0_rx_pins_a>;
@@ -171,6 +173,10 @@
status = "okay";
};
+&otg_sram {
+ status = "okay";
+};
+
&pio {
led_pins_pcduino3: led_pins@0 {
allwinner,pins = "PH15", "PH16";
@@ -185,6 +191,13 @@
allwinner,drive = <SUN4I_PINCTRL_10_MA>;
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
};
&reg_ahci_5v {
@@ -192,6 +205,31 @@
status = "okay";
};
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-pll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
&reg_usb1_vbus {
status = "okay";
};
@@ -206,7 +244,15 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
index 83c6d3f..78239ad 100644
--- a/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
+++ b/arch/arm/boot/dts/sun7i-a20-wexler-tab7200.dts
@@ -86,6 +86,8 @@
};
};
+#include "axp209.dtsi"
+
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins_a>;
@@ -135,7 +137,18 @@
status = "okay";
};
-#include "axp209.dtsi"
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
&reg_dcdc2 {
regulator-always-on;
@@ -162,6 +175,10 @@
regulator-name = "avcc";
};
+&reg_usb0_vbus {
+ status = "okay";
+};
+
&reg_usb1_vbus {
status = "okay";
};
@@ -176,7 +193,21 @@
status = "okay";
};
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
diff --git a/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
new file mode 100644
index 0000000..85b500d
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-wits-pro-a20-dkt.dts
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2015 Jelle de Jong <jelledejong@powercraft.nl>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun7i-a20.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "Wits Pro A20 DKT";
+ compatible = "wits,pro-a20-dkt", "allwinner,sun7i-a20";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ mmc3_pwrseq: mmc3_pwrseq {
+ compatible = "mmc-pwrseq-simple";
+ pinctrl-names = "default";
+ pinctrl-0 = <&vmmc3_pin_ap6xxx_wl_regon>;
+ reset-gpios = <&pio 7 9 GPIO_ACTIVE_LOW>; /* PH9 WIFI_EN */
+ };
+};
+
+&cpu0 {
+ cpu-supply = <&reg_dcdc2>;
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&ehci1 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+};
+
+#include "axp209.dtsi"
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 GPIO_ACTIVE_HIGH>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+};
+
+&mmc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc3_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ mmc-pwrseq = <&mmc3_pwrseq>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+
+ brcmf: bcrmf@1 {
+ reg = <1>;
+ compatible = "brcm,bcm4329-fmac";
+ interrupt-parent = <&pio>;
+ interrupts = <7 10 IRQ_TYPE_LEVEL_LOW>; /* PH10 / EINT10 */
+ interrupt-names = "host-wake";
+ };
+};
+
+&ohci0 {
+ status = "okay";
+};
+
+&ohci1 {
+ status = "okay";
+};
+
+&otg_sram {
+ status = "okay";
+};
+
+&pio {
+ vmmc3_pin_ap6xxx_wl_regon: vmmc3_pin@0 {
+ allwinner,pins = "PH9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ usb0_id_detect_pin: usb0_id_detect_pin@0 {
+ allwinner,pins = "PH4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&reg_dcdc2 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1450000>;
+ regulator-name = "vdd-cpu";
+};
+
+&reg_dcdc3 {
+ regulator-always-on;
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1400000>;
+ regulator-name = "vdd-int-dll";
+};
+
+&reg_ldo1 {
+ regulator-name = "vdd-rtc";
+};
+
+&reg_ldo2 {
+ regulator-always-on;
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-name = "avcc";
+};
+
+&reg_usb0_vbus {
+ status = "okay";
+};
+
+&reg_usb1_vbus {
+ status = "okay";
+};
+
+&reg_usb2_vbus {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+};
+
+&usb_otg {
+ dr_mode = "otg";
+ status = "okay";
+};
+
+&usb_power_supply {
+ status = "okay";
+};
+
+&usbphy {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_id_detect_pin>;
+ usb0_id_det-gpio = <&pio 7 4 GPIO_ACTIVE_HIGH>; /* PH4 */
+ usb0_vbus_power-supply = <&usb_power_supply>;
+ usb0_vbus-supply = <&reg_usb0_vbus>;
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 391230c..e02eb72 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -47,6 +47,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/thermal/thermal.h>
+#include <dt-bindings/clock/sun4i-a10-pll2.h>
#include <dt-bindings/dma/sun4i-a10.h>
#include <dt-bindings/pinctrl/sun4i-a10.h>
@@ -199,6 +200,15 @@
clock-output-names = "pll1";
};
+ pll2: clk@01c20008 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun4i-a10-pll2-clk";
+ reg = <0x01c20008 0x8>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll2-1x", "pll2-2x",
+ "pll2-4x", "pll2-8x";
+ };
+
pll4: clk@01c20018 {
#clock-cells = <0>;
compatible = "allwinner,sun7i-a20-pll4-clk";
@@ -465,6 +475,14 @@
clock-output-names = "ir1";
};
+ keypad_clk: clk@01c200c4 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c200c4 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "keypad";
+ };
+
usb_clk: clk@01c200cc {
#clock-cells = <1>;
#reset-cells = <1>;
@@ -483,6 +501,14 @@
clock-output-names = "spi3";
};
+ codec_clk: clk@01c20140 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-codec-clk";
+ reg = <0x01c20140 0x4>;
+ clocks = <&pll2 SUN4I_A10_PLL2_1X>;
+ clock-output-names = "codec";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun5i-a13-mbus-clk";
@@ -1190,6 +1216,19 @@
status = "disabled";
};
+ codec: codec@01c22c00 {
+ #sound-dai-cells = <0>;
+ compatible = "allwinner,sun7i-a20-codec";
+ reg = <0x01c22c00 0x40>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb0_gates 0>, <&codec_clk>;
+ clock-names = "apb", "codec";
+ dmas = <&dma SUN4I_DMA_NORMAL 19>,
+ <&dma SUN4I_DMA_NORMAL 19>;
+ dma-names = "rx", "tx";
+ status = "disabled";
+ };
+
sid: eeprom@01c23800 {
compatible = "allwinner,sun7i-a20-sid";
reg = <0x01c23800 0x200>;
diff --git a/arch/arm/boot/dts/sun8i-a23-a33.dtsi b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
index 27a925e..0c0964d 100644
--- a/arch/arm/boot/dts/sun8i-a23-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23-a33.dtsi
@@ -175,31 +175,6 @@
clock-output-names = "apb1";
};
- ahb1_gates: clk@01c20060 {
- #clock-cells = <1>;
- compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
- reg = <0x01c20060 0x8>;
- clocks = <&ahb1>;
- clock-indices = <1>, <6>,
- <8>, <9>, <10>,
- <13>, <14>,
- <19>, <20>,
- <21>, <24>, <26>,
- <29>, <32>, <36>,
- <40>, <44>, <46>,
- <52>, <54>,
- <57>;
- clock-output-names = "ahb1_mipidsi", "ahb1_dma",
- "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
- "ahb1_nand", "ahb1_sdram",
- "ahb1_hstimer", "ahb1_spi0",
- "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
- "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
- "ahb1_csi", "ahb1_be", "ahb1_fe",
- "ahb1_gpu", "ahb1_spinlock",
- "ahb1_drc";
- };
-
apb1_gates: clk@01c20068 {
#clock-cells = <1>;
compatible = "allwinner,sun8i-a23-apb1-gates-clk";
@@ -412,6 +387,13 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
+ pwm0_pins: pwm0 {
+ allwinner,pins = "PH0";
+ allwinner,function = "pwm0";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
i2c0_pins_a: i2c0@0 {
allwinner,pins = "PH2", "PH3";
allwinner,function = "i2c0";
@@ -466,6 +448,14 @@
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
};
+ pwm: pwm@01c21400 {
+ compatible = "allwinner,sun7i-a20-pwm";
+ reg = <0x01c21400 0xc>;
+ clocks = <&osc24M>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
lradc: lradc@01c22800 {
compatible = "allwinner,sun4i-a10-lradc-keys";
reg = <0x01c22800 0x100>;
@@ -589,6 +579,14 @@
<GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>;
};
+ nmi_intc: interrupt-controller@01f00c0c {
+ compatible = "allwinner,sun6i-a31-sc-nmi";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ reg = <0x01f00c0c 0x38>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
prcm@01f01400 {
compatible = "allwinner,sun8i-a23-prcm";
reg = <0x01f01400 0x200>;
@@ -657,10 +655,18 @@
resets = <&apb0_rst 0>;
gpio-controller;
interrupt-controller;
+ #interrupt-cells = <3>;
#address-cells = <1>;
#size-cells = <0>;
#gpio-cells = <3>;
+ r_rsb_pins: r_rsb {
+ allwinner,pins = "PL0", "PL1";
+ allwinner,function = "s_rsb";
+ allwinner,drive = <SUN4I_PINCTRL_20_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+
r_uart_pins_a: r_uart@0 {
allwinner,pins = "PL2", "PL3";
allwinner,function = "s_uart";
@@ -668,5 +674,19 @@
allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
};
};
+
+ r_rsb: rsb@01f03400 {
+ compatible = "allwinner,sun8i-a23-rsb";
+ reg = <0x01f03400 0x400>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&apb0_gates 3>;
+ clock-frequency = <3000000>;
+ resets = <&apb0_rst 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_rsb_pins>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
};
};
diff --git a/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts b/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts
new file mode 100644
index 0000000..1aeb06c
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-gt90h-v4.dts
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-a23.dtsi"
+#include "sunxi-common-regulators.dtsi"
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+
+/ {
+ model = "Allwinner GT90H Quad Core Tablet (v4)";
+ compatible = "allwinner,gt90h-v4", "allwinner,sun8i-a33";
+
+ aliases {
+ serial0 = &r_uart;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&ehci0 {
+ status = "okay";
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+
+ button@600 {
+ label = "Back";
+ linux,code = <KEY_BACK>;
+ channel = <0>;
+ voltage = <600000>;
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_gt90h>;
+ /* FIXME this really is aldo1, correct once we've pmic support */
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ mmc0_cd_pin_gt90h: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+};
+
+/*
+ * FIXME for now we only support host mode and rely on u-boot to have
+ * turned on Vbus which is controlled by the axp223 pmic on the board.
+ *
+ * Once we have axp223 support we should switch to fully supporting otg.
+ */
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
index 382d64c..c2f22fc 100644..120000
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts
@@ -1,54 +1 @@
-/*
- * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- * a) This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- * b) Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/*
- * The Ippo Q8H v1.2 is almost identical to the v5, still it needs a separate
- * dtb file since some gpio-s surrounding the wlan/bluetooth are different,
- * and it uses different camera sensors.
- */
-
-#include "sun8i-a23-ippo-q8h-v5.dts"
-
-/ {
- model = "Ippo Q8H Dual Core Tablet (v1.2)";
- compatible = "ippo,q8h-v1.2", "allwinner,sun8i-a23";
-};
+sun8i-a23-q8-tablet.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
index 8d9da68..c2f22fc 100644..120000
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
@@ -1,136 +1 @@
-/*
- * Copyright 2014 Chen-Yu Tsai
- *
- * Chen-Yu Tsai <wens@csie.org>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- * a) This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- * b) Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/dts-v1/;
-#include "sun8i-a23.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
-
-/ {
- model = "Ippo Q8H Dual Core Tablet (v5)";
- compatible = "ippo,q8h-v5", "allwinner,sun8i-a23";
-
- aliases {
- serial0 = &r_uart;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-};
-
-&i2c0 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-};
-
-&i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
-};
-
-&i2c2 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins_a>;
- /* pull-ups and devices require PMIC regulator */
- status = "failed";
-};
-
-&lradc {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
-
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
-};
-
-&mmc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
- vmmc-supply = <&reg_vcc3v0>;
- bus-width = <4>;
- cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
- cd-inverted;
- status = "okay";
-};
-
-&pio {
- mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
- allwinner,pins = "PB4";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-};
-
-&r_uart {
- pinctrl-names = "default";
- pinctrl-0 = <&r_uart_pins_a>;
- status = "okay";
-};
-
-&usb_otg {
- dr_mode = "host";
- status = "okay";
-};
-
-&usbphy {
- status = "okay";
-};
+sun8i-a23-q8-tablet.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
new file mode 100644
index 0000000..6062ea7
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a23-q8-tablet.dts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-a23.dtsi"
+#include "sun8i-q8-common.dtsi"
+
+/ {
+ model = "Q8 A23 Tablet";
+ compatible = "allwinner,q8-a23", "allwinner,sun8i-a23";
+};
+
+/*
+ * FIXME for now we only support host mode and rely on u-boot to have
+ * turned on Vbus which is controlled by the axp223 pmic on the board.
+ *
+ * Once we have axp223 support we should switch to fully supporting otg.
+ */
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 2cc27c7..92e6616 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -50,6 +50,31 @@
};
clocks {
+ ahb1_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a23-ahb1-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb1>;
+ clock-indices = <1>, <6>,
+ <8>, <9>, <10>,
+ <13>, <14>,
+ <19>, <20>,
+ <21>, <24>, <26>,
+ <29>, <32>, <36>,
+ <40>, <44>, <46>,
+ <52>, <53>,
+ <54>, <57>;
+ clock-output-names = "ahb1_mipidsi", "ahb1_dma",
+ "ahb1_mmc0", "ahb1_mmc1", "ahb1_mmc2",
+ "ahb1_nand", "ahb1_sdram",
+ "ahb1_hstimer", "ahb1_spi0",
+ "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
+ "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
+ "ahb1_csi", "ahb1_be", "ahb1_fe",
+ "ahb1_gpu", "ahb1_msgbox",
+ "ahb1_spinlock", "ahb1_drc";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun8i-a23-mbus-clk";
diff --git a/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts b/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts
index 19db844..4519fd7 100644..120000
--- a/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts
+++ b/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts
@@ -1,88 +1 @@
-/*
- * Copyright 2015 Vishnu Patekar
- * Vishnu Patekar <vishnupatekar0510@gmail.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- * a) This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- * b) Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/dts-v1/;
-#include "sun8i-a33.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
-
-/ {
- model = "ET Q8 Quad Core Tablet (v1.6)";
- compatible = "et,q8-v1.6", "allwinner,sun8i-a33";
-
- aliases {
- serial0 = &uart0;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-};
-
-&lradc {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
-
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
-};
-
-&uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart0_pins_a>;
- status = "okay";
-};
+sun8i-a33-q8-tablet.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts b/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts
index a438975..4519fd7 100644..120000
--- a/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts
+++ b/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts
@@ -1,133 +1 @@
-/*
- * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPL or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- * a) This file is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Or, alternatively,
- *
- * b) Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/dts-v1/;
-#include "sun8i-a33.dtsi"
-#include "sunxi-common-regulators.dtsi"
-
-#include <dt-bindings/gpio/gpio.h>
-#include <dt-bindings/input/input.h>
-#include <dt-bindings/pinctrl/sun4i-a10.h>
-
-/ {
- model = "Ippo Q8H Quad Core Tablet (v1.2)";
- compatible = "ippo,a33-q8h-v1.2", "allwinner,sun8i-a33";
-
- aliases {
- serial0 = &r_uart;
- };
-
- chosen {
- stdout-path = "serial0:115200n8";
- };
-};
-
-&i2c0 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c0_pins_a>;
- status = "okay";
-};
-
-&i2c1 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c1_pins_a>;
- status = "okay";
-};
-
-&lradc {
- vref-supply = <&reg_vcc3v0>;
- status = "okay";
-
- button@200 {
- label = "Volume Up";
- linux,code = <KEY_VOLUMEUP>;
- channel = <0>;
- voltage = <200000>;
- };
-
- button@400 {
- label = "Volume Down";
- linux,code = <KEY_VOLUMEDOWN>;
- channel = <0>;
- voltage = <400000>;
- };
-};
-
-&mmc0 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8h>;
- vmmc-supply = <&reg_vcc3v0>;
- bus-width = <4>;
- cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
- cd-inverted;
- status = "okay";
-};
-
-&pio {
- mmc0_cd_pin_q8h: mmc0_cd_pin@0 {
- allwinner,pins = "PB4";
- allwinner,function = "gpio_in";
- allwinner,drive = <SUN4I_PINCTRL_10_MA>;
- allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
- };
-};
-
-&r_uart {
- pinctrl-names = "default";
- pinctrl-0 = <&r_uart_pins_a>;
- status = "okay";
-};
-
-/*
- * FIXME for now we only support host mode and rely on u-boot to have
- * turned on Vbus which is controlled by the axp223 pmic on the board.
- *
- * Once we have axp223 support we should switch to fully supporting otg.
- */
-&usb_otg {
- dr_mode = "host";
- status = "okay";
-};
-
-&usbphy {
- status = "okay";
-};
+sun8i-a33-q8-tablet.dts \ No newline at end of file
diff --git a/arch/arm/boot/dts/sun8i-a33-q8-tablet.dts b/arch/arm/boot/dts/sun8i-a33-q8-tablet.dts
new file mode 100644
index 0000000..44b3229
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-a33-q8-tablet.dts
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "sun8i-a33.dtsi"
+#include "sun8i-q8-common.dtsi"
+
+/ {
+ model = "Q8 A33 Tablet";
+ compatible = "allwinner,q8-a33", "allwinner,sun8i-a33";
+};
+
+/*
+ * FIXME for now we only support host mode and rely on u-boot to have
+ * turned on Vbus which is controlled by the axp223 pmic on the board.
+ *
+ * Once we have axp223 support we should switch to fully supporting otg.
+ */
+&usb_otg {
+ dr_mode = "host";
+ status = "okay";
+};
+
+&usbphy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
index 1d5390d..13ce68f 100644
--- a/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
+++ b/arch/arm/boot/dts/sun8i-a33-sinlinx-sina33.dts
@@ -130,6 +130,10 @@
};
};
+&r_rsb {
+ status = "okay";
+};
+
&uart0 {
pinctrl-names = "default";
pinctrl-0 = <&uart0_pins_b>;
diff --git a/arch/arm/boot/dts/sun8i-a33.dtsi b/arch/arm/boot/dts/sun8i-a33.dtsi
index faa7d3c..001d840 100644
--- a/arch/arm/boot/dts/sun8i-a33.dtsi
+++ b/arch/arm/boot/dts/sun8i-a33.dtsi
@@ -72,6 +72,41 @@
clock-output-names = "pll11";
};
+ ahb1_gates: clk@01c20060 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun8i-a33-ahb1-gates-clk";
+ reg = <0x01c20060 0x8>;
+ clocks = <&ahb1>;
+ clock-indices = <1>, <5>,
+ <6>, <8>, <9>,
+ <10>, <13>, <14>,
+ <19>, <20>,
+ <21>, <24>, <26>,
+ <29>, <32>, <36>,
+ <40>, <44>, <46>,
+ <52>, <53>,
+ <54>, <57>,
+ <58>;
+ clock-output-names = "ahb1_mipidsi", "ahb1_ss",
+ "ahb1_dma","ahb1_mmc0", "ahb1_mmc1",
+ "ahb1_mmc2", "ahb1_nand", "ahb1_sdram",
+ "ahb1_hstimer", "ahb1_spi0",
+ "ahb1_spi1", "ahb1_otg", "ahb1_ehci",
+ "ahb1_ohci", "ahb1_ve", "ahb1_lcd",
+ "ahb1_csi", "ahb1_be", "ahb1_fe",
+ "ahb1_gpu", "ahb1_msgbox",
+ "ahb1_spinlock", "ahb1_drc",
+ "ahb1_sat";
+ };
+
+ ss_clk: clk@01c2009c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun4i-a10-mod0-clk";
+ reg = <0x01c2009c 0x4>;
+ clocks = <&osc24M>, <&pll6 0>;
+ clock-output-names = "ss";
+ };
+
mbus_clk: clk@01c2015c {
#clock-cells = <0>;
compatible = "allwinner,sun8i-a23-mbus-clk";
@@ -82,6 +117,16 @@
};
soc@01c00000 {
+ crypto: crypto-engine@01c15000 {
+ compatible = "allwinner,sun4i-a10-crypto";
+ reg = <0x01c15000 0x1000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ahb1_gates 5>, <&ss_clk>;
+ clock-names = "ahb", "mod";
+ resets = <&ahb1_rst 5>;
+ reset-names = "ahb";
+ };
+
usb_otg: usb@01c19000 {
compatible = "allwinner,sun8i-a33-musb";
reg = <0x01c19000 0x0400>;
diff --git a/arch/arm/boot/dts/sun8i-q8-common.dtsi b/arch/arm/boot/dts/sun8i-q8-common.dtsi
new file mode 100644
index 0000000..1a69231
--- /dev/null
+++ b/arch/arm/boot/dts/sun8i-q8-common.dtsi
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "sunxi-q8-common.dtsi"
+
+#include <dt-bindings/pwm/pwm.h>
+
+/ {
+ aliases {
+ serial0 = &r_uart;
+ };
+
+ backlight: backlight {
+ compatible = "pwm-backlight";
+ pinctrl-names = "default";
+ pinctrl-0 = <&bl_en_pin_q8>;
+ pwms = <&pwm 0 50000 PWM_POLARITY_INVERTED>;
+ brightness-levels = <0 10 20 30 40 50 60 70 80 90 100>;
+ default-brightness-level = <8>;
+ enable-gpios = <&pio 7 6 GPIO_ACTIVE_HIGH>; /* PH6 */
+ /* backlight is powered by AXP223 DC1SW */
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&mmc0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_q8>;
+ vmmc-supply = <&reg_vcc3v0>;
+ bus-width = <4>;
+ cd-gpios = <&pio 1 4 GPIO_ACTIVE_HIGH>; /* PB4 */
+ cd-inverted;
+ status = "okay";
+};
+
+&pio {
+ bl_en_pin_q8: bl_en_pin@0 {
+ allwinner,pins = "PH6";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
+ };
+
+ mmc0_cd_pin_q8: mmc0_cd_pin@0 {
+ allwinner,pins = "PB4";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <SUN4I_PINCTRL_10_MA>;
+ allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
+ };
+};
+
+&r_rsb {
+ status = "okay";
+};
+
+&r_uart {
+ pinctrl-names = "default";
+ pinctrl-0 = <&r_uart_pins_a>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
index 5908e3d..1118bf5 100644
--- a/arch/arm/boot/dts/sun9i-a80.dtsi
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -594,7 +594,7 @@
clocks = <&apb0_gates 5>;
gpio-controller;
interrupt-controller;
- #interrupt-cells = <2>;
+ #interrupt-cells = <3>;
#size-cells = <0>;
#gpio-cells = <3>;
diff --git a/arch/arm/boot/dts/sunxi-q8-common.dtsi b/arch/arm/boot/dts/sunxi-q8-common.dtsi
new file mode 100644
index 0000000..b824146
--- /dev/null
+++ b/arch/arm/boot/dts/sunxi-q8-common.dtsi
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/pinctrl/sun4i-a10.h>
+#include "sunxi-common-regulators.dtsi"
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+};
+
+&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+};
+
+&lradc {
+ vref-supply = <&reg_vcc3v0>;
+ status = "okay";
+
+ button@200 {
+ label = "Volume Up";
+ linux,code = <KEY_VOLUMEUP>;
+ channel = <0>;
+ voltage = <200000>;
+ };
+
+ button@400 {
+ label = "Volume Down";
+ linux,code = <KEY_VOLUMEDOWN>;
+ channel = <0>;
+ voltage = <400000>;
+ };
+};
+
+&pwm {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pwm0_pins>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/tegra124-nyan.dtsi b/arch/arm/boot/dts/tegra124-nyan.dtsi
index a9aec23..ec1aa64 100644
--- a/arch/arm/boot/dts/tegra124-nyan.dtsi
+++ b/arch/arm/boot/dts/tegra124-nyan.dtsi
@@ -159,7 +159,7 @@
vin-ldo9-10-supply = <&vdd_5v0_sys>;
vin-ldo11-supply = <&vdd_3v3_run>;
- sd0 {
+ vdd_cpu: sd0 {
regulator-name = "+VDD_CPU_AP";
regulator-min-microvolt = <700000>;
regulator-max-microvolt = <1350000>;
@@ -397,6 +397,13 @@
non-removable;
};
+ /* CPU DFLL clock */
+ clock@0,70110000 {
+ status = "disabled";
+ vdd-cpu-supply = <&vdd_cpu>;
+ nvidia,i2c-fs-rate = <400000>;
+ };
+
ahub@0,70300000 {
i2s@0,70301100 {
status = "okay";
@@ -487,6 +494,12 @@
};
};
+ cpus {
+ cpu@0 {
+ vdd-cpu-supply = <&vdd_cpu>;
+ };
+ };
+
gpio-keys {
compatible = "gpio-keys";
diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 819e2ae..68669f7 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -610,26 +610,20 @@
sata@0,70020000 {
compatible = "nvidia,tegra124-ahci";
-
reg = <0x0 0x70027000 0x0 0x2000>, /* AHCI */
- <0x0 0x70020000 0x0 0x7000>; /* SATA */
-
+ <0x0 0x70020000 0x0 0x7000>; /* SATA */
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&tegra_car TEGRA124_CLK_SATA>,
- <&tegra_car TEGRA124_CLK_SATA_OOB>,
- <&tegra_car TEGRA124_CLK_CML1>,
- <&tegra_car TEGRA124_CLK_PLL_E>;
+ <&tegra_car TEGRA124_CLK_SATA_OOB>,
+ <&tegra_car TEGRA124_CLK_CML1>,
+ <&tegra_car TEGRA124_CLK_PLL_E>;
clock-names = "sata", "sata-oob", "cml1", "pll_e";
-
resets = <&tegra_car 124>,
- <&tegra_car 123>,
- <&tegra_car 129>;
+ <&tegra_car 123>,
+ <&tegra_car 129>;
reset-names = "sata", "sata-oob", "sata-cold";
-
phys = <&padctl TEGRA_XUSB_PADCTL_SATA>;
phy-names = "sata-phy";
-
status = "disabled";
};
@@ -638,7 +632,7 @@
reg = <0x0 0x70030000 0x0 0x10000>;
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA124_CLK_HDA>,
- <&tegra_car TEGRA124_CLK_HDA2HDMI>,
+ <&tegra_car TEGRA124_CLK_HDA2HDMI>,
<&tegra_car TEGRA124_CLK_HDA2CODEC_2X>;
clock-names = "hda", "hda2hdmi", "hda2codec_2x";
resets = <&tegra_car 125>, /* hda */
diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 969b828..33173e1 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -603,8 +603,8 @@
<&tegra_car TEGRA20_CLK_PLL_E>;
clock-names = "pex", "afi", "pll_e";
resets = <&tegra_car 70>,
- <&tegra_car 72>,
- <&tegra_car 74>;
+ <&tegra_car 72>,
+ <&tegra_car 74>;
reset-names = "pex", "afi", "pcie_x";
status = "disabled";
diff --git a/arch/arm/boot/dts/tegra30-apalis-eval.dts b/arch/arm/boot/dts/tegra30-apalis-eval.dts
index 6236bde..f2879cf 100644
--- a/arch/arm/boot/dts/tegra30-apalis-eval.dts
+++ b/arch/arm/boot/dts/tegra30-apalis-eval.dts
@@ -126,6 +126,10 @@
};
};
+ hda@70030000 {
+ status = "okay";
+ };
+
sd1: sdhci@78000000 {
status = "okay";
bus-width = <4>;
@@ -149,6 +153,7 @@
usb-phy@7d000000 {
status = "okay";
+ dr_mode = "otg";
vbus-supply = <&usbo1_vbus_reg>;
};
@@ -175,7 +180,7 @@
backlight: backlight {
compatible = "pwm-backlight";
- /* PWM0 */
+ /* PWM_BKL1 */
pwms = <&pwm 0 5000000>;
brightness-levels = <255 231 223 207 191 159 127 0>;
default-brightness-level = <6>;
@@ -186,10 +191,10 @@
gpio-keys {
compatible = "gpio-keys";
- power {
- label = "Power";
+ wakeup {
+ label = "WAKE1_MICO";
gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_LOW>;
- linux,code = <KEY_POWER>;
+ linux,code = <KEY_WAKEUP>;
debounce-interval = <10>;
gpio-key,wakeup;
};
diff --git a/arch/arm/boot/dts/tegra30-apalis.dtsi b/arch/arm/boot/dts/tegra30-apalis.dtsi
index a5446cb..bf36127 100644
--- a/arch/arm/boot/dts/tegra30-apalis.dtsi
+++ b/arch/arm/boot/dts/tegra30-apalis.dtsi
@@ -1,8 +1,9 @@
#include "tegra30.dtsi"
/*
- * Toradex Apalis T30 Device Tree
- * Compatible for Revisions 1GB: V1.0A; 2GB: V1.0B, V1.0C
+ * Toradex Apalis T30 Module Device Tree
+ * Compatible for Revisions 1GB: V1.0A, V1.1A; 1GB IT: V1.1A;
+ * 2GB: V1.0B, V1.0C, V1.0E, V1.1A
*/
/ {
model = "Toradex Apalis T30";
@@ -33,8 +34,8 @@
host1x@50000000 {
hdmi@54280000 {
- vdd-supply = <&sys_3v3_reg>;
- pll-supply = <&vio_reg>;
+ vdd-supply = <&avdd_hdmi_3v3_reg>;
+ pll-supply = <&avdd_hdmi_pll_1v8_reg>;
nvidia,hpd-gpio =
<&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>;
@@ -57,25 +58,25 @@
/* Apalis BKL1_PWM */
uart3_rts_n_pc0 {
- nvidia,pins = "uart3_rts_n_pc0";
+ nvidia,pins = "uart3_rts_n_pc0";
nvidia,function = "pwm0";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
/* BKL1_PWM_EN#, disable TPS65911 PMIC PWM backlight */
uart3_cts_n_pa1 {
- nvidia,pins = "uart3_cts_n_pa1";
- nvidia,function = "rsvd1";
+ nvidia,pins = "uart3_cts_n_pa1";
+ nvidia,function = "rsvd2";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
/* Apalis CAN1 on SPI6 */
spi2_cs0_n_px3 {
- nvidia,pins = "spi2_cs0_n_px3",
- "spi2_miso_px1",
- "spi2_mosi_px0",
- "spi2_sck_px2";
+ nvidia,pins = "spi2_cs0_n_px3",
+ "spi2_miso_px1",
+ "spi2_mosi_px0",
+ "spi2_sck_px2";
nvidia,function = "spi6";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -91,10 +92,10 @@
/* Apalis CAN2 on SPI4 */
gmi_a16_pj7 {
- nvidia,pins = "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7";
+ nvidia,pins = "gmi_a16_pj7",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gmi_a19_pk7";
nvidia,function = "spi4";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -108,6 +109,30 @@
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
};
+ /* Apalis Digital Audio */
+ clk1_req_pee2 {
+ nvidia,pins = "clk1_req_pee2";
+ nvidia,function = "hda";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ };
+ clk2_out_pw5 {
+ nvidia,pins = "clk2_out_pw5";
+ nvidia,function = "extperiph2";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_DISABLE>;
+ };
+ dap1_fs_pn0 {
+ nvidia,pins = "dap1_fs_pn0",
+ "dap1_din_pn1",
+ "dap1_dout_pn2",
+ "dap1_sclk_pn3";
+ nvidia,function = "hda";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ };
+
/* Apalis I2C3 */
cam_i2c_scl_pbb1 {
nvidia,pins = "cam_i2c_scl_pbb1",
@@ -122,21 +147,21 @@
/* Apalis MMC1 */
sdmmc3_clk_pa6 {
- nvidia,pins = "sdmmc3_clk_pa6",
- "sdmmc3_cmd_pa7";
+ nvidia,pins = "sdmmc3_clk_pa6",
+ "sdmmc3_cmd_pa7";
nvidia,function = "sdmmc3";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
sdmmc3_dat0_pb7 {
- nvidia,pins = "sdmmc3_dat0_pb7",
- "sdmmc3_dat1_pb6",
- "sdmmc3_dat2_pb5",
- "sdmmc3_dat3_pb4",
- "sdmmc3_dat4_pd1",
- "sdmmc3_dat5_pd0",
- "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4";
+ nvidia,pins = "sdmmc3_dat0_pb7",
+ "sdmmc3_dat1_pb6",
+ "sdmmc3_dat2_pb5",
+ "sdmmc3_dat3_pb4",
+ "sdmmc3_dat4_pd1",
+ "sdmmc3_dat5_pd0",
+ "sdmmc3_dat6_pd3",
+ "sdmmc3_dat7_pd4";
nvidia,function = "sdmmc3";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -151,32 +176,32 @@
};
/* Apalis PWM1 */
- gpio_pu6 {
- nvidia,pins = "gpio_pu6";
+ pu6 {
+ nvidia,pins = "pu6";
nvidia,function = "pwm3";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
/* Apalis PWM2 */
- gpio_pu5 {
- nvidia,pins = "gpio_pu5";
+ pu5 {
+ nvidia,pins = "pu5";
nvidia,function = "pwm2";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
/* Apalis PWM3 */
- gpio_pu4 {
- nvidia,pins = "gpio_pu4";
+ pu4 {
+ nvidia,pins = "pu4";
nvidia,function = "pwm1";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
/* Apalis PWM4 */
- gpio_pu3 {
- nvidia,pins = "gpio_pu3";
+ pu3 {
+ nvidia,pins = "pu3";
nvidia,function = "pwm0";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -198,11 +223,11 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
sdmmc1_cmd_pz1 {
- nvidia,pins = "sdmmc1_cmd_pz1",
- "sdmmc1_dat0_py7",
- "sdmmc1_dat1_py6",
- "sdmmc1_dat2_py5",
- "sdmmc1_dat3_py4";
+ nvidia,pins = "sdmmc1_cmd_pz1",
+ "sdmmc1_dat0_py7",
+ "sdmmc1_dat1_py6",
+ "sdmmc1_dat2_py5",
+ "sdmmc1_dat3_py4";
nvidia,function = "sdmmc1";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -218,10 +243,10 @@
/* Apalis SPI1 */
spi1_sck_px5 {
- nvidia,pins = "spi1_sck_px5",
- "spi1_mosi_px4",
- "spi1_miso_px7",
- "spi1_cs0_n_px6";
+ nvidia,pins = "spi1_sck_px5",
+ "spi1_mosi_px4",
+ "spi1_miso_px7",
+ "spi1_cs0_n_px6";
nvidia,function = "spi1";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -229,10 +254,10 @@
/* Apalis SPI2 */
lcd_sck_pz4 {
- nvidia,pins = "lcd_sck_pz4",
- "lcd_sdout_pn5",
- "lcd_sdin_pz2",
- "lcd_cs0_n_pn4";
+ nvidia,pins = "lcd_sck_pz4",
+ "lcd_sdout_pn5",
+ "lcd_sdin_pz2",
+ "lcd_cs0_n_pn4";
nvidia,function = "spi5";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -240,14 +265,14 @@
/* Apalis UART1 */
ulpi_data0 {
- nvidia,pins = "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0";
+ nvidia,pins = "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0";
nvidia,function = "uarta";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -255,10 +280,10 @@
/* Apalis UART2 */
ulpi_clk_py0 {
- nvidia,pins = "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3";
+ nvidia,pins = "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3";
nvidia,function = "uartd";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -266,8 +291,8 @@
/* Apalis UART3 */
uart2_rxd_pc3 {
- nvidia,pins = "uart2_rxd_pc3",
- "uart2_txd_pc2";
+ nvidia,pins = "uart2_rxd_pc3",
+ "uart2_txd_pc2";
nvidia,function = "uartb";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -275,8 +300,8 @@
/* Apalis UART4 */
uart3_rxd_pw7 {
- nvidia,pins = "uart3_rxd_pw7",
- "uart3_txd_pw6";
+ nvidia,pins = "uart3_rxd_pw7",
+ "uart3_txd_pw6";
nvidia,function = "uartc";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -312,21 +337,21 @@
/* eMMC (On-module) */
sdmmc4_clk_pcc4 {
- nvidia,pins = "sdmmc4_clk_pcc4",
- "sdmmc4_rst_n_pcc3";
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ "sdmmc4_rst_n_pcc3";
nvidia,function = "sdmmc4";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
sdmmc4_dat0_paa0 {
- nvidia,pins = "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7";
+ nvidia,pins = "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7";
nvidia,function = "sdmmc4";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -334,10 +359,10 @@
/* LVDS Transceiver Configuration */
pbb0 {
- nvidia,pins = "pbb0",
- "pbb7",
- "pcc1",
- "pcc2";
+ nvidia,pins = "pbb0",
+ "pbb7",
+ "pcc1",
+ "pcc2";
nvidia,function = "rsvd2";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -345,10 +370,10 @@
nvidia,lock = <TEGRA_PIN_DISABLE>;
};
pbb3 {
- nvidia,pins = "pbb3",
- "pbb4",
- "pbb5",
- "pbb6";
+ nvidia,pins = "pbb3",
+ "pbb4",
+ "pbb5",
+ "pbb6";
nvidia,function = "displayb";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -635,6 +660,7 @@
nvidia,sys-clock-req-active-high;
};
+ /* eMMC */
sdhci@78000600 {
status = "okay";
bus-width = <8>;
@@ -666,18 +692,40 @@
#address-cells = <1>;
#size-cells = <0>;
- sys_3v3_reg: regulator@100 {
+ avdd_hdmi_pll_1v8_reg: regulator@100 {
compatible = "regulator-fixed";
reg = <100>;
+ regulator-name = "+V1.8_AVDD_HDMI_PLL";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&vio_reg>;
+ };
+
+ sys_3v3_reg: regulator@101 {
+ compatible = "regulator-fixed";
+ reg = <101>;
regulator-name = "3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
- charge_pump_5v0_reg: regulator@101 {
+ avdd_hdmi_3v3_reg: regulator@102 {
compatible = "regulator-fixed";
- reg = <101>;
+ reg = <102>;
+ regulator-name = "+V3.3_AVDD_HDMI";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&sys_3v3_reg>;
+ };
+
+ charge_pump_5v0_reg: regulator@103 {
+ compatible = "regulator-fixed";
+ reg = <103>;
regulator-name = "5v0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
diff --git a/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts b/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts
index 4d3ddc5..3ff019f 100644
--- a/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/tegra30-colibri-eval-v3.dts
@@ -55,7 +55,7 @@
/* M41T0M6 real time clock on carrier board */
rtc@68 {
- compatible = "stm,m41t00";
+ compatible = "st,m41t00";
reg = <0x68>;
};
};
@@ -84,6 +84,7 @@
};
};
+ /* SD/MMC */
sdhci@78000200 {
status = "okay";
bus-width = <4>;
@@ -136,10 +137,10 @@
gpio-keys {
compatible = "gpio-keys";
- power {
- label = "Power";
+ wakeup {
+ label = "SODIMM pin 45 wakeup";
gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
- linux,code = <KEY_POWER>;
+ linux,code = <KEY_WAKEUP>;
debounce-interval = <10>;
gpio-key,wakeup;
};
diff --git a/arch/arm/boot/dts/tegra30-colibri.dtsi b/arch/arm/boot/dts/tegra30-colibri.dtsi
index c4ed1be..2d8c58f 100644
--- a/arch/arm/boot/dts/tegra30-colibri.dtsi
+++ b/arch/arm/boot/dts/tegra30-colibri.dtsi
@@ -2,8 +2,8 @@
#include "tegra30.dtsi"
/*
- * Toradex Colibri T30 Device Tree
- * Compatible for Revisions 1.1B/1.1C/1.1D
+ * Toradex Colibri T30 Module Device Tree
+ * Compatible for Revisions V1.1B, V1.1C, V1.1D, V1.1E; IT: V1.1A
*/
/ {
model = "Toradex Colibri T30";
@@ -15,8 +15,8 @@
host1x@50000000 {
hdmi@54280000 {
- vdd-supply = <&sys_3v3_reg>;
- pll-supply = <&vio_reg>;
+ vdd-supply = <&avdd_hdmi_3v3_reg>;
+ pll-supply = <&avdd_hdmi_pll_1v8_reg>;
nvidia,hpd-gpio =
<&gpio TEGRA_GPIO(N, 7) GPIO_ACTIVE_HIGH>;
@@ -39,7 +39,7 @@
/* Colibri Backlight PWM<A> */
sdmmc3_dat3_pb4 {
- nvidia,pins = "sdmmc3_dat3_pb4";
+ nvidia,pins = "sdmmc3_dat3_pb4";
nvidia,function = "pwm0";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -66,15 +66,6 @@
nvidia,enable-input = <TEGRA_PIN_ENABLE>;
};
- /* Thermal alert, need to be disabled */
- lcd_dc1_pd2 {
- nvidia,pins = "lcd_dc1_pd2";
- nvidia,function = "rsvd3";
- nvidia,pull = <TEGRA_PIN_PULL_NONE>;
- nvidia,tristate = <TEGRA_PIN_DISABLE>;
- nvidia,enable-input = <TEGRA_PIN_ENABLE>;
- };
-
/* Colibri MMC */
kb_row10_ps2 {
nvidia,pins = "kb_row10_ps2";
@@ -83,11 +74,11 @@
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
kb_row11_ps3 {
- nvidia,pins = "kb_row11_ps3",
- "kb_row12_ps4",
- "kb_row13_ps5",
- "kb_row14_ps6",
- "kb_row15_ps7";
+ nvidia,pins = "kb_row11_ps3",
+ "kb_row12_ps4",
+ "kb_row13_ps5",
+ "kb_row14_ps6",
+ "kb_row15_ps7";
nvidia,function = "sdmmc2";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -95,17 +86,17 @@
/* Colibri SSP */
ulpi_clk_py0 {
- nvidia,pins = "ulpi_clk_py0",
- "ulpi_dir_py1",
- "ulpi_nxt_py2",
- "ulpi_stp_py3";
+ nvidia,pins = "ulpi_clk_py0",
+ "ulpi_dir_py1",
+ "ulpi_nxt_py2",
+ "ulpi_stp_py3";
nvidia,function = "spi1";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
sdmmc3_dat6_pd3 {
- nvidia,pins = "sdmmc3_dat6_pd3",
- "sdmmc3_dat7_pd4";
+ nvidia,pins = "sdmmc3_dat6_pd3",
+ "sdmmc3_dat7_pd4";
nvidia,function = "spdif";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_ENABLE>;
@@ -113,14 +104,14 @@
/* Colibri UART_A */
ulpi_data0 {
- nvidia,pins = "ulpi_data0_po1",
- "ulpi_data1_po2",
- "ulpi_data2_po3",
- "ulpi_data3_po4",
- "ulpi_data4_po5",
- "ulpi_data5_po6",
- "ulpi_data6_po7",
- "ulpi_data7_po0";
+ nvidia,pins = "ulpi_data0_po1",
+ "ulpi_data1_po2",
+ "ulpi_data2_po3",
+ "ulpi_data3_po4",
+ "ulpi_data4_po5",
+ "ulpi_data5_po6",
+ "ulpi_data6_po7",
+ "ulpi_data7_po0";
nvidia,function = "uarta";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -128,10 +119,10 @@
/* Colibri UART_B */
gmi_a16_pj7 {
- nvidia,pins = "gmi_a16_pj7",
- "gmi_a17_pb0",
- "gmi_a18_pb1",
- "gmi_a19_pk7";
+ nvidia,pins = "gmi_a16_pj7",
+ "gmi_a17_pb0",
+ "gmi_a18_pb1",
+ "gmi_a19_pk7";
nvidia,function = "uartd";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -139,8 +130,8 @@
/* Colibri UART_C */
uart2_rxd {
- nvidia,pins = "uart2_rxd_pc3",
- "uart2_txd_pc2";
+ nvidia,pins = "uart2_rxd_pc3",
+ "uart2_txd_pc2";
nvidia,function = "uartb";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
@@ -148,25 +139,59 @@
/* eMMC */
sdmmc4_clk_pcc4 {
- nvidia,pins = "sdmmc4_clk_pcc4",
- "sdmmc4_rst_n_pcc3";
+ nvidia,pins = "sdmmc4_clk_pcc4",
+ "sdmmc4_rst_n_pcc3";
nvidia,function = "sdmmc4";
nvidia,pull = <TEGRA_PIN_PULL_NONE>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
sdmmc4_dat0_paa0 {
- nvidia,pins = "sdmmc4_dat0_paa0",
- "sdmmc4_dat1_paa1",
- "sdmmc4_dat2_paa2",
- "sdmmc4_dat3_paa3",
- "sdmmc4_dat4_paa4",
- "sdmmc4_dat5_paa5",
- "sdmmc4_dat6_paa6",
- "sdmmc4_dat7_paa7";
+ nvidia,pins = "sdmmc4_dat0_paa0",
+ "sdmmc4_dat1_paa1",
+ "sdmmc4_dat2_paa2",
+ "sdmmc4_dat3_paa3",
+ "sdmmc4_dat4_paa4",
+ "sdmmc4_dat5_paa5",
+ "sdmmc4_dat6_paa6",
+ "sdmmc4_dat7_paa7";
nvidia,function = "sdmmc4";
nvidia,pull = <TEGRA_PIN_PULL_UP>;
nvidia,tristate = <TEGRA_PIN_DISABLE>;
};
+
+ /* Power I2C (On-module) */
+ pwr_i2c_scl_pz6 {
+ nvidia,pins = "pwr_i2c_scl_pz6",
+ "pwr_i2c_sda_pz7";
+ nvidia,function = "i2cpwr";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+ nvidia,lock = <TEGRA_PIN_DISABLE>;
+ nvidia,open-drain = <TEGRA_PIN_ENABLE>;
+ };
+
+ /*
+ * THERMD_ALERT#, unlatched I2C address pin of LM95245
+ * temperature sensor therefore requires disabling for
+ * now
+ */
+ lcd_dc1_pd2 {
+ nvidia,pins = "lcd_dc1_pd2";
+ nvidia,function = "rsvd3";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+ };
+
+ /* TOUCH_PEN_INT# */
+ pv0 {
+ nvidia,pins = "pv0";
+ nvidia,function = "rsvd1";
+ nvidia,pull = <TEGRA_PIN_PULL_NONE>;
+ nvidia,tristate = <TEGRA_PIN_DISABLE>;
+ nvidia,enable-input = <TEGRA_PIN_ENABLE>;
+ };
};
};
@@ -236,7 +261,7 @@
/*
* EN_+V3.3 switching via FET:
* +V3.3_AUDIO_AVDD_S, +V3.3 and +V1.8_VDD_LAN
- * see also v3_3 fixed supply
+ * see also 3v3 fixed supply
*/
ldo2_reg: ldo2 {
regulator-name = "en_3v3";
@@ -295,6 +320,46 @@
};
};
+ /* STMPE811 touch screen controller */
+ stmpe811@41 {
+ compatible = "st,stmpe811";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x41>;
+ interrupts = <TEGRA_GPIO(V, 0) IRQ_TYPE_LEVEL_LOW>;
+ interrupt-parent = <&gpio>;
+ interrupt-controller;
+ id = <0>;
+ blocks = <0x5>;
+ irq-trigger = <0x1>;
+
+ stmpe_touchscreen {
+ compatible = "st,stmpe-ts";
+ reg = <0>;
+ /* 3.25 MHz ADC clock speed */
+ st,adc-freq = <1>;
+ /* 8 sample average control */
+ st,ave-ctrl = <3>;
+ /* 7 length fractional part in z */
+ st,fraction-z = <7>;
+ /*
+ * 50 mA typical 80 mA max touchscreen drivers
+ * current limit value
+ */
+ st,i-drive = <1>;
+ /* 12-bit ADC */
+ st,mod-12b = <1>;
+ /* internal ADC reference */
+ st,ref-sel = <0>;
+ /* ADC converstion time: 80 clocks */
+ st,sample-time = <4>;
+ /* 1 ms panel driver settling time */
+ st,settling = <3>;
+ /* 5 ms touch detect interrupt delay */
+ st,touch-det-delay = <5>;
+ };
+ };
+
/*
* LM95245 temperature sensor
* Note: OVERT_N directly connected to PMIC PWRDN
@@ -331,7 +396,8 @@
nvidia,sys-clock-req-active-high;
};
- emmc: sdhci@78000600 {
+ /* eMMC */
+ sdhci@78000600 {
status = "okay";
bus-width = <8>;
non-removable;
@@ -365,18 +431,40 @@
#address-cells = <1>;
#size-cells = <0>;
- sys_3v3_reg: regulator@100 {
+ avdd_hdmi_pll_1v8_reg: regulator@100 {
compatible = "regulator-fixed";
reg = <100>;
+ regulator-name = "+V1.8_AVDD_HDMI_PLL";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ enable-active-high;
+ gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&vio_reg>;
+ };
+
+ sys_3v3_reg: regulator@101 {
+ compatible = "regulator-fixed";
+ reg = <101>;
regulator-name = "3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
};
- charge_pump_5v0_reg: regulator@101 {
+ avdd_hdmi_3v3_reg: regulator@102 {
compatible = "regulator-fixed";
- reg = <101>;
+ reg = <102>;
+ regulator-name = "+V3.3_AVDD_HDMI";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ enable-active-high;
+ gpio = <&pmic 6 GPIO_ACTIVE_HIGH>;
+ vin-supply = <&sys_3v3_reg>;
+ };
+
+ charge_pump_5v0_reg: regulator@103 {
+ compatible = "regulator-fixed";
+ reg = <103>;
regulator-name = "5v0";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index c6938ad..313e260 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -42,8 +42,8 @@
<&tegra_car TEGRA30_CLK_CML0>;
clock-names = "pex", "afi", "pll_e", "cml";
resets = <&tegra_car 70>,
- <&tegra_car 72>,
- <&tegra_car 74>;
+ <&tegra_car 72>,
+ <&tegra_car 74>;
reset-names = "pex", "afi", "pcie_x";
status = "disabled";
@@ -153,7 +153,7 @@
&tegra_car TEGRA30_CLK_GR3D2>;
clock-names = "3d", "3d2";
resets = <&tegra_car 24>,
- <&tegra_car 98>;
+ <&tegra_car 98>;
reset-names = "3d", "3d2";
};
@@ -457,7 +457,7 @@
};
i2c@7000c000 {
- compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
+ compatible = "nvidia,tegra30-i2c", "nvidia,tegra20-i2c";
reg = <0x7000c000 0x100>;
interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
#address-cells = <1>;
@@ -662,7 +662,7 @@
reg = <0x70030000 0x10000>;
interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_HDA>,
- <&tegra_car TEGRA30_CLK_HDA2HDMI>,
+ <&tegra_car TEGRA30_CLK_HDA2HDMI>,
<&tegra_car TEGRA30_CLK_HDA2CODEC_2X>;
clock-names = "hda", "hda2hdmi", "hda2codec_2x";
resets = <&tegra_car 125>, /* hda */
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts b/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
index bfd3bb8..f1e9d40 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ph1-ld4-ref.dts
@@ -57,8 +57,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200";
- stdout-path = &serial0;
+ stdout-path = "serial0:115200n8";
};
aliases {
@@ -74,12 +73,11 @@
};
&extbus {
- ranges = <0 0x00000000 0x0f000000 0x01000000
- 1 0x00000000 0x00000000 0x08000000>;
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
};
&support_card {
- ranges = <0x00000000 1 0x03f00000 0x00100000>;
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
};
&ethsc {
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
index a6a185f..af49381 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-ld4.dtsi
@@ -55,6 +55,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
};
@@ -91,6 +92,18 @@
#size-cells = <1>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(512 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -187,10 +200,9 @@
clock-frequency = <100000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
usb0: usb@5a800100 {
diff --git a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts b/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts
index f80f772..5baa9fc 100644
--- a/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ph1-ld6b-ref.dts
@@ -57,8 +57,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200";
- stdout-path = &serial0;
+ stdout-path = "serial0:115200n8";
};
aliases {
@@ -76,12 +75,11 @@
};
&extbus {
- ranges = <0 0x00000000 0x0f000000 0x01000000
- 1 0x00000000 0x00000000 0x08000000>;
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
};
&support_card {
- ranges = <0x00000000 1 0x03f00000 0x00100000>;
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
};
&ethsc {
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts b/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
index 69a5b7d..2462668 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ph1-pro4-ref.dts
@@ -57,8 +57,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200";
- stdout-path = &serial0;
+ stdout-path = "serial0:115200n8";
};
aliases {
@@ -76,12 +75,11 @@
};
&extbus {
- ranges = <0 0x00000000 0x0f000000 0x01000000
- 1 0x00000000 0x00000000 0x08000000>;
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
};
&support_card {
- ranges = <0x00000000 1 0x03f00000 0x00100000>;
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
};
&ethsc {
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
index e8bbc45..254642f 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-pro4.dtsi
@@ -56,12 +56,14 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ next-level-cache = <&l2>;
};
};
@@ -98,6 +100,18 @@
#size-cells = <1>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(768 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -218,10 +232,9 @@
clock-frequency = <400000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
usb2: usb@5a800100 {
diff --git a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi b/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
index 59c2b12..11eb762 100644
--- a/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-pro5.dtsi
@@ -56,12 +56,14 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ next-level-cache = <&l2>;
};
};
@@ -98,6 +100,31 @@
#size-cells = <1>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x8>,
+ <0x506c0000 0x400>;
+ interrupts = <0 190 4>, <0 191 4>;
+ cache-unified;
+ cache-size = <(2 * 1024 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ next-level-cache = <&l3>;
+ };
+
+ l3: l3-cache@500c8000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c8000 0x2000>, <0x503c8100 0x8>,
+ <0x506c8000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(2 * 1024 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <256>;
+ cache-level = <3>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -214,10 +241,9 @@
clock-frequency = <400000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
pinctrl: pinctrl@5f801000 {
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts b/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
index 1a440f8..b7a03215 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ph1-sld3-ref.dts
@@ -58,8 +58,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200";
- stdout-path = &serial0;
+ stdout-path = "serial0:115200n8";
};
aliases {
@@ -75,12 +74,11 @@
};
&extbus {
- ranges = <0 0x00000000 0x0f000000 0x01000000
- 1 0x00000000 0x00000000 0x08000000>;
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
};
&support_card {
- ranges = <0x00000000 1 0x03f00000 0x00100000>;
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
};
&ethsc {
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi b/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
index 3cc90cd..691a17d 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-sld3.dtsi
@@ -56,12 +56,14 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ next-level-cache = <&l2>;
};
};
@@ -120,6 +122,18 @@
<0x20000100 0x100>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(512 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -202,10 +216,9 @@
clock-frequency = <400000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
usb0: usb@5a800100 {
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts b/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
index 955d417..fc7250c 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
+++ b/arch/arm/boot/dts/uniphier-ph1-sld8-ref.dts
@@ -57,8 +57,7 @@
};
chosen {
- bootargs = "console=ttyS0,115200";
- stdout-path = &serial0;
+ stdout-path = "serial0:115200n8";
};
aliases {
@@ -74,12 +73,11 @@
};
&extbus {
- ranges = <0 0x00000000 0x0f000000 0x01000000
- 1 0x00000000 0x00000000 0x08000000>;
+ ranges = <1 0x00000000 0x42000000 0x02000000>;
};
&support_card {
- ranges = <0x00000000 1 0x03f00000 0x00100000>;
+ ranges = <0x00000000 1 0x01f00000 0x00100000>;
};
&ethsc {
diff --git a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
index 58067df..e88559b 100644
--- a/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
+++ b/arch/arm/boot/dts/uniphier-ph1-sld8.dtsi
@@ -55,6 +55,7 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
};
@@ -91,6 +92,18 @@
#size-cells = <1>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>;
+ cache-unified;
+ cache-size = <(256 * 1024)>;
+ cache-sets = <256>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -187,10 +200,9 @@
clock-frequency = <100000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
usb0: usb@5a800100 {
diff --git a/arch/arm/boot/dts/uniphier-proxstream2-gentil.dts b/arch/arm/boot/dts/uniphier-proxstream2-gentil.dts
new file mode 100644
index 0000000..9d7ec5c
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-proxstream2-gentil.dts
@@ -0,0 +1,78 @@
+/*
+ * Device Tree Source for UniPhier ProXstream2 Gentil Board
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-proxstream2.dtsi"
+
+/ {
+ model = "UniPhier ProXstream2 Gentil Board";
+ compatible = "socionext,proxstream2-gentil", "socionext,proxstream2";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>;
+ };
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ i2c0 = &i2c0;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ };
+};
+
+&serial2 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/uniphier-proxstream2-vodka.dts b/arch/arm/boot/dts/uniphier-proxstream2-vodka.dts
new file mode 100644
index 0000000..498acac
--- /dev/null
+++ b/arch/arm/boot/dts/uniphier-proxstream2-vodka.dts
@@ -0,0 +1,78 @@
+/*
+ * Device Tree Source for UniPhier ProXstream2 Vodka Board
+ *
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "uniphier-proxstream2.dtsi"
+
+/ {
+ model = "UniPhier ProXstream2 Vodka Board";
+ compatible = "socionext,proxstream2-vodka", "socionext,proxstream2";
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>;
+ };
+
+ chosen {
+ stdout-path = "serial2:115200n8";
+ };
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ serial2 = &serial2;
+ i2c0 = &i2c0;
+ i2c4 = &i2c4;
+ i2c5 = &i2c5;
+ i2c6 = &i2c6;
+ };
+};
+
+&serial2 {
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/uniphier-proxstream2.dtsi b/arch/arm/boot/dts/uniphier-proxstream2.dtsi
index 4c7b246..259f1a9 100644
--- a/arch/arm/boot/dts/uniphier-proxstream2.dtsi
+++ b/arch/arm/boot/dts/uniphier-proxstream2.dtsi
@@ -56,24 +56,28 @@
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <0>;
+ next-level-cache = <&l2>;
};
cpu@1 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <1>;
+ next-level-cache = <&l2>;
};
cpu@2 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <2>;
+ next-level-cache = <&l2>;
};
cpu@3 {
device_type = "cpu";
compatible = "arm,cortex-a9";
reg = <3>;
+ next-level-cache = <&l2>;
};
};
@@ -110,6 +114,18 @@
#size-cells = <1>;
};
+ l2: l2-cache@500c0000 {
+ compatible = "socionext,uniphier-system-cache";
+ reg = <0x500c0000 0x2000>, <0x503c0100 0x4>,
+ <0x506c0000 0x400>;
+ interrupts = <0 174 4>, <0 175 4>, <0 190 4>, <0 191 4>;
+ cache-unified;
+ cache-size = <(1280 * 1024)>;
+ cache-sets = <512>;
+ cache-line-size = <128>;
+ cache-level = <2>;
+ };
+
serial0: serial@54006800 {
compatible = "socionext,uniphier-uart";
status = "disabled";
@@ -235,10 +251,9 @@
clock-frequency = <400000>;
};
- system-bus-controller-misc@59800000 {
- compatible = "socionext,uniphier-system-bus-controller-misc",
- "syscon";
- reg = <0x59800000 0x2000>;
+ system-bus-controller@58c00000 {
+ compatible = "socionext,uniphier-system-bus-controller";
+ reg = <0x58c00000 0x400>, <0x59800000 0x2000>;
};
pinctrl: pinctrl@5f801000 {
diff --git a/arch/arm/boot/dts/usb_a9260_common.dtsi b/arch/arm/boot/dts/usb_a9260_common.dtsi
index 12edafe..9beea89 100644
--- a/arch/arm/boot/dts/usb_a9260_common.dtsi
+++ b/arch/arm/boot/dts/usb_a9260_common.dtsi
@@ -115,7 +115,7 @@
label = "user_pb";
gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
linux,code = <28>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/usb_a9263.dts b/arch/arm/boot/dts/usb_a9263.dts
index 68c0de3..8cc6edb 100644
--- a/arch/arm/boot/dts/usb_a9263.dts
+++ b/arch/arm/boot/dts/usb_a9263.dts
@@ -143,7 +143,7 @@
label = "user_pb";
gpios = <&pioB 10 GPIO_ACTIVE_LOW>;
linux,code = <28>;
- gpio-key,wakeup;
+ wakeup-source;
};
};
diff --git a/arch/arm/boot/dts/versatile-ab.dts b/arch/arm/boot/dts/versatile-ab.dts
index 01f4019..3279bf1 100644
--- a/arch/arm/boot/dts/versatile-ab.dts
+++ b/arch/arm/boot/dts/versatile-ab.dts
@@ -110,7 +110,11 @@
interrupt-parent = <&vic>;
interrupts = <31>; /* Cascaded to vic */
clear-mask = <0xffffffff>;
- valid-mask = <0xffc203f8>;
+ /*
+ * Valid interrupt lines mask according to
+ * table 4-36 page 4-50 of ARM DUI 0225D
+ */
+ valid-mask = <0x0760031b>;
};
dma@10130000 {
@@ -266,8 +270,8 @@
};
mmc@5000 {
compatible = "arm,pl180", "arm,primecell";
- reg = < 0x5000 0x1000>;
- interrupts-extended = <&vic 22 &sic 2>;
+ reg = <0x5000 0x1000>;
+ interrupts-extended = <&vic 22 &sic 1>;
clocks = <&xtal24mhz>, <&pclk>;
clock-names = "mclk", "apb_pclk";
};
diff --git a/arch/arm/boot/dts/versatile-pb.dts b/arch/arm/boot/dts/versatile-pb.dts
index b83137f..33a8eb2 100644
--- a/arch/arm/boot/dts/versatile-pb.dts
+++ b/arch/arm/boot/dts/versatile-pb.dts
@@ -5,6 +5,16 @@
compatible = "arm,versatile-pb";
amba {
+ /* The Versatile PB is using more SIC IRQ lines than the AB */
+ sic: intc@10003000 {
+ clear-mask = <0xffffffff>;
+ /*
+ * Valid interrupt lines mask according to
+ * figure 3-30 page 3-74 of ARM DUI 0224B
+ */
+ valid-mask = <0x7fe003ff>;
+ };
+
gpio2: gpio@101e6000 {
compatible = "arm,pl061", "arm,primecell";
reg = <0x101e6000 0x1000>;
@@ -67,6 +77,13 @@
};
fpga {
+ mmc@5000 {
+ /*
+ * Overrides the interrupt assignment from
+ * the Versatile AB board file.
+ */
+ interrupts-extended = <&sic 22 &sic 23>;
+ };
uart@9000 {
compatible = "arm,pl011", "arm,primecell";
reg = <0x9000 0x1000>;
@@ -86,7 +103,8 @@
mmc@b000 {
compatible = "arm,pl180", "arm,primecell";
reg = <0xb000 0x1000>;
- interrupts-extended = <&vic 23 &sic 2>;
+ interrupt-parent = <&sic>;
+ interrupts = <1>, <2>;
clocks = <&xtal24mhz>, <&pclk>;
clock-names = "mclk", "apb_pclk";
};
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
index 68ca125..e5949b9 100644
--- a/arch/arm/boot/dts/vf-colibri.dtsi
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -52,6 +52,26 @@
pinctrl-0 = <&pinctrl_i2c0>;
};
+&nfc {
+ assigned-clocks = <&clks VF610_CLK_NFC>;
+ assigned-clock-rates = <33000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nfc>;
+ status = "okay";
+
+ nand@0 {
+ compatible = "fsl,vf610-nfc-nandcs";
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ nand-bus-width = <8>;
+ nand-ecc-mode = "hw";
+ nand-ecc-strength = <32>;
+ nand-ecc-step-size = <2048>;
+ nand-on-flash-bbt;
+ };
+};
+
&pwm0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm0>;
@@ -156,6 +176,25 @@
>;
};
+ pinctrl_nfc: nfcgrp {
+ fsl,pins = <
+ VF610_PAD_PTD23__NF_IO7 0x28df
+ VF610_PAD_PTD22__NF_IO6 0x28df
+ VF610_PAD_PTD21__NF_IO5 0x28df
+ VF610_PAD_PTD20__NF_IO4 0x28df
+ VF610_PAD_PTD19__NF_IO3 0x28df
+ VF610_PAD_PTD18__NF_IO2 0x28df
+ VF610_PAD_PTD17__NF_IO1 0x28df
+ VF610_PAD_PTD16__NF_IO0 0x28df
+ VF610_PAD_PTB24__NF_WE_B 0x28c2
+ VF610_PAD_PTB25__NF_CE0_B 0x28c2
+ VF610_PAD_PTB27__NF_RE_B 0x28c2
+ VF610_PAD_PTC26__NF_RB_B 0x283d
+ VF610_PAD_PTC27__NF_ALE 0x28c2
+ VF610_PAD_PTC28__NF_CLE 0x28c2
+ >;
+ };
+
pinctrl_pwm0: pwm0grp {
fsl,pins = <
VF610_PAD_PTB0__FTM0_CH0 0x1182
diff --git a/arch/arm/boot/dts/vf500-colibri-eval-v3.dts b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
index 7fc782c..c3173fc 100644
--- a/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
@@ -15,3 +15,8 @@
model = "Toradex Colibri VF50 on Colibri Evaluation Board";
compatible = "toradex,vf500-colibri_vf50-on-eval", "toradex,vf500-colibri_vf50", "fsl,vf500";
};
+
+&touchscreen {
+ vf50-ts-min-pressure = <200>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/vf500-colibri.dtsi b/arch/arm/boot/dts/vf500-colibri.dtsi
index cee34a3..84f091d 100644
--- a/arch/arm/boot/dts/vf500-colibri.dtsi
+++ b/arch/arm/boot/dts/vf500-colibri.dtsi
@@ -17,4 +17,51 @@
memory {
reg = <0x80000000 0x8000000>;
};
+
+ touchscreen: vf50-touchscreen {
+ compatible = "toradex,vf50-touchscreen";
+ io-channels = <&adc1 0>,<&adc0 0>,
+ <&adc0 1>,<&adc1 2>;
+ xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
+ xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>;
+ yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
+ ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <8 IRQ_TYPE_LEVEL_LOW>;
+ pinctrl-names = "idle","default","gpios";
+ pinctrl-0 = <&pinctrl_touchctrl_idle>;
+ pinctrl-1 = <&pinctrl_touchctrl_default>;
+ pinctrl-2 = <&pinctrl_touchctrl_gpios>;
+ vf50-ts-min-pressure = <200>;
+ status = "disabled";
+ };
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_touchctrl_idle: touchctrl_idle {
+ fsl,pins = <
+ VF610_PAD_PTA18__GPIO_8 0x006d
+ VF610_PAD_PTA19__GPIO_9 0x006c
+ >;
+ };
+
+ pinctrl_touchctrl_default: touchctrl_default {
+ fsl,pins = <
+ VF610_PAD_PTA18__ADC0_SE0 0x0040
+ VF610_PAD_PTA19__ADC0_SE1 0x0040
+ VF610_PAD_PTA16__ADC1_SE0 0x0040
+ VF610_PAD_PTB2__ADC1_SE2 0x0040
+ >;
+ };
+
+ pinctrl_touchctrl_gpios: touchctrl_gpios {
+ fsl,pins = <
+ VF610_PAD_PTA23__GPIO_13 0x22e9
+ VF610_PAD_PTB23__GPIO_93 0x22e9
+ VF610_PAD_PTA22__GPIO_12 0x22e9
+ VF610_PAD_PTA11__GPIO_4 0x22e9
+ >;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/vf610-colibri.dtsi b/arch/arm/boot/dts/vf610-colibri.dtsi
index 19fe045..2d7eab7 100644
--- a/arch/arm/boot/dts/vf610-colibri.dtsi
+++ b/arch/arm/boot/dts/vf610-colibri.dtsi
@@ -18,8 +18,3 @@
reg = <0x80000000 0x10000000>;
};
};
-
-&L2 {
- arm,data-latency = <2 1 2>;
- arm,tag-latency = <3 2 3>;
-};
diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index 375ab23..5438ee4 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -237,6 +237,33 @@
>;
};
+ pinctrl_nfc: nfcgrp {
+ fsl,pins = <
+ VF610_PAD_PTD31__NF_IO15 0x28df
+ VF610_PAD_PTD30__NF_IO14 0x28df
+ VF610_PAD_PTD29__NF_IO13 0x28df
+ VF610_PAD_PTD28__NF_IO12 0x28df
+ VF610_PAD_PTD27__NF_IO11 0x28df
+ VF610_PAD_PTD26__NF_IO10 0x28df
+ VF610_PAD_PTD25__NF_IO9 0x28df
+ VF610_PAD_PTD24__NF_IO8 0x28df
+ VF610_PAD_PTD23__NF_IO7 0x28df
+ VF610_PAD_PTD22__NF_IO6 0x28df
+ VF610_PAD_PTD21__NF_IO5 0x28df
+ VF610_PAD_PTD20__NF_IO4 0x28df
+ VF610_PAD_PTD19__NF_IO3 0x28df
+ VF610_PAD_PTD18__NF_IO2 0x28df
+ VF610_PAD_PTD17__NF_IO1 0x28df
+ VF610_PAD_PTD16__NF_IO0 0x28df
+ VF610_PAD_PTB24__NF_WE_B 0x28c2
+ VF610_PAD_PTB25__NF_CE0_B 0x28c2
+ VF610_PAD_PTB27__NF_RE_B 0x28c2
+ VF610_PAD_PTC26__NF_RB_B 0x283d
+ VF610_PAD_PTC27__NF_ALE 0x28c2
+ VF610_PAD_PTC28__NF_CLE 0x28c2
+ >;
+ };
+
pinctrl_pwm0: pwm0grp {
fsl,pins = <
VF610_PAD_PTB0__FTM0_CH0 0x1582
@@ -274,6 +301,26 @@
};
};
+&nfc {
+ assigned-clocks = <&clks VF610_CLK_NFC>;
+ assigned-clock-rates = <33000000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_nfc>;
+ status = "okay";
+
+ nand@0 {
+ compatible = "fsl,vf610-nfc-nandcs";
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ nand-bus-width = <16>;
+ nand-ecc-mode = "hw";
+ nand-ecc-strength = <24>;
+ nand-ecc-step-size = <2048>;
+ nand-on-flash-bbt;
+ };
+};
+
&pwm0 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm0>;
diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index 5f8eb1b..58bc6e4 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -19,7 +19,7 @@
reg = <0x40006000 0x1000>;
cache-unified;
cache-level = <2>;
- arm,data-latency = <1 1 1>;
+ arm,data-latency = <3 3 3>;
arm,tag-latency = <2 2 2>;
};
};
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
index 6865137..3cd1b27 100644
--- a/arch/arm/boot/dts/vfxxx.dtsi
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -158,7 +158,7 @@
interrupts = <67 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_DSPI0>;
clock-names = "dspi";
- spi-num-chipselects = <5>;
+ spi-num-chipselects = <6>;
status = "disabled";
};
@@ -170,7 +170,7 @@
interrupts = <68 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clks VF610_CLK_DSPI1>;
clock-names = "dspi";
- spi-num-chipselects = <5>;
+ spi-num-chipselects = <4>;
status = "disabled";
};
@@ -178,8 +178,10 @@
compatible = "fsl,vf610-sai";
reg = <0x40031000 0x1000>;
interrupts = <86 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_SAI2>;
- clock-names = "sai";
+ clocks = <&clks VF610_CLK_SAI2>,
+ <&clks VF610_CLK_SAI2_DIV>,
+ <&clks 0>, <&clks 0>;
+ clock-names = "bus", "mclk1", "mclk2", "mclk3";
dma-names = "tx", "rx";
dmas = <&edma0 0 21>,
<&edma0 0 20>;
@@ -461,6 +463,8 @@
clock-names = "adc";
#io-channel-cells = <1>;
status = "disabled";
+ fsl,adck-max-frequency = <30000000>, <40000000>,
+ <20000000>;
};
esdhc0: esdhc@400b1000 {
@@ -472,8 +476,6 @@
<&clks VF610_CLK_ESDHC0>;
clock-names = "ipg", "ahb", "per";
status = "disabled";
- fsl,adck-max-frequency = <30000000>, <40000000>,
- <20000000>;
};
esdhc1: esdhc@400b2000 {
@@ -564,6 +566,17 @@
status = "disabled";
};
+ nfc: nand@400e0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-nfc";
+ reg = <0x400e0000 0x4000>;
+ interrupts = <83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_NFC>;
+ clock-names = "nfc";
+ status = "disabled";
+ };
+
i2c2: i2c@400e6000 {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/wm8650.dtsi b/arch/arm/boot/dts/wm8650.dtsi
index b1c59a7..e12213d 100644
--- a/arch/arm/boot/dts/wm8650.dtsi
+++ b/arch/arm/boot/dts/wm8650.dtsi
@@ -187,6 +187,15 @@
interrupts = <43>;
};
+ sdhc@d800a000 {
+ compatible = "wm,wm8505-sdhc";
+ reg = <0xd800a000 0x400>;
+ interrupts = <20>, <21>;
+ clocks = <&clksdhc>;
+ bus-width = <4>;
+ sdon-inverted;
+ };
+
fb: fb@d8050800 {
compatible = "wm,wm8505-fb";
reg = <0xd8050800 0x200>;
diff --git a/arch/arm/boot/dts/wm8750.dtsi b/arch/arm/boot/dts/wm8750.dtsi
index 557a9c2a..46d076d 100644
--- a/arch/arm/boot/dts/wm8750.dtsi
+++ b/arch/arm/boot/dts/wm8750.dtsi
@@ -17,7 +17,7 @@
cpu {
device_type = "cpu";
- compatible = "arm,arm1176ej-s";
+ compatible = "arm,arm1176jzf";
};
};
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index 090c5b2..e4b1be6 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -17,7 +17,6 @@ CONFIG_ARCH_MULTI_V4T=y
CONFIG_ARCH_MULTI_V5=y
# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_AT91=y
-CONFIG_SOC_SAM_V4_V5=y
CONFIG_SOC_AT91RM9200=y
CONFIG_SOC_AT91SAM9=y
CONFIG_AEABI=y
@@ -28,7 +27,6 @@ CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
CONFIG_KEXEC=y
-CONFIG_AUTO_ZRELADDR=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_NET=y
CONFIG_PACKET=y
@@ -43,7 +41,6 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
# CONFIG_INET6_XFRM_MODE_BEET is not set
@@ -119,7 +116,6 @@ CONFIG_LEGACY_PTY_COUNT=4
CONFIG_SERIAL_ATMEL=y
CONFIG_SERIAL_ATMEL_CONSOLE=y
CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
CONFIG_I2C_AT91=y
CONFIG_I2C_GPIO=y
CONFIG_SPI=y
@@ -129,7 +125,6 @@ CONFIG_POWER_RESET=y
# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_SSB=m
CONFIG_MFD_ATMEL_HLCDC=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -142,16 +137,12 @@ CONFIG_SOC_CAMERA_OV2640=m
CONFIG_DRM=y
CONFIG_DRM_ATMEL_HLCDC=y
CONFIG_DRM_PANEL_SIMPLE=y
-CONFIG_FB=y
CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_ATMEL_LCDC=y
# CONFIG_BACKLIGHT_GENERIC is not set
CONFIG_BACKLIGHT_PWM=y
CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
CONFIG_LOGO=y
CONFIG_SOUND=y
CONFIG_SND=y
@@ -216,18 +207,11 @@ CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
-CONFIG_CRYPTO=y
CONFIG_CRYPTO_ECB=y
-CONFIG_CRYPTO_AES=y
-CONFIG_CRYPTO_ARC4=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
# CONFIG_CRYPTO_HW is not set
CONFIG_CRC_CCITT=y
-CONFIG_CRC_ITU_T=y
-CONFIG_CRC7=m
-CONFIG_AVERAGE=y
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_ACORN_8x8=y
diff --git a/arch/arm/configs/bockw_defconfig b/arch/arm/configs/bockw_defconfig
deleted file mode 100644
index 3125e00..0000000
--- a/arch/arm/configs/bockw_defconfig
+++ /dev/null
@@ -1,133 +0,0 @@
-# CONFIG_ARM_PATCH_PHYS_VIRT is not set
-CONFIG_KERNEL_LZMA=y
-CONFIG_NO_HZ=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_SHMOBILE_LEGACY=y
-CONFIG_ARCH_R8A7778=y
-CONFIG_MACH_BOCKW=y
-CONFIG_MEMORY_START=0x60000000
-CONFIG_MEMORY_SIZE=0x10000000
-CONFIG_SHMOBILE_TIMER_HZ=1024
-# CONFIG_SH_TIMER_CMT is not set
-# CONFIG_EM_TIMER_STI is not set
-CONFIG_ARM_ERRATA_430973=y
-CONFIG_ARM_ERRATA_458693=y
-CONFIG_ARM_ERRATA_460075=y
-CONFIG_ARM_ERRATA_743622=y
-CONFIG_ARM_ERRATA_754322=y
-CONFIG_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_HIGHMEM=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-# CONFIG_FW_LOADER is not set
-CONFIG_MTD=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_NETDEVICES=y
-# CONFIG_NET_CADENCE is not set
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_CIRRUS is not set
-# CONFIG_NET_VENDOR_FARADAY is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-# CONFIG_NET_VENDOR_SEEQ is not set
-CONFIG_SMSC911X=y
-# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_NET_VENDOR_WIZNET is not set
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_DEVKMEM is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=6
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-CONFIG_I2C=y
-CONFIG_I2C_RCAR=y
-CONFIG_GPIO_RCAR=y
-CONFIG_REGULATOR=y
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_SOC_CAMERA=y
-CONFIG_VIDEO_RCAR_VIN=y
-# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-CONFIG_VIDEO_ML86V7667=y
-CONFIG_SPI=y
-CONFIG_SPI_SH_HSPI=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SOC=y
-CONFIG_SND_SOC_RCAR=y
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_OHCI_HCD_PLATFORM=y
-CONFIG_USB_EHCI_HCD_PLATFORM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_RCAR_PHY=y
-CONFIG_MMC=y
-CONFIG_MMC_SDHI=y
-CONFIG_MMC_SH_MMCIF=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_RX8581=y
-CONFIG_DMADEVICES=y
-CONFIG_RCAR_HPB_DMAE=y
-CONFIG_UIO=y
-CONFIG_UIO_PDRV_GENIRQ=y
-# CONFIG_IOMMU_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFS_SWAP=y
-CONFIG_NFS_V4_1=y
-CONFIG_ROOT_NFS=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_FTRACE is not set
-# CONFIG_ARM_UNWIND is not set
-CONFIG_AVERAGE=y
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index 0ff608f..e0841a5 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -61,11 +61,12 @@ CONFIG_BLK_DEV_DM=y
CONFIG_DM_CRYPT=m
CONFIG_NETDEVICES=y
CONFIG_SMSC911X=y
+CONFIG_USB_RTL8152=y
CONFIG_USB_USBNET=y
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
-CONFIG_MWIFIEX=y
-CONFIG_MWIFIEX_SDIO=y
+CONFIG_MWIFIEX=m
+CONFIG_MWIFIEX_SDIO=m
CONFIG_INPUT_EVDEV=y
CONFIG_KEYBOARD_GPIO=y
CONFIG_KEYBOARD_CROS_EC=y
@@ -126,6 +127,10 @@ CONFIG_REGULATOR_S2MPA01=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_REGULATOR_TPS65090=y
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_MEDIA_CAMERA_SUPPORT=y
+CONFIG_MEDIA_USB_SUPPORT=y
+CONFIG_USB_VIDEO_CLASS=m
CONFIG_DRM=y
CONFIG_DRM_NXP_PTN3460=y
CONFIG_DRM_PARADE_PS8622=y
@@ -136,7 +141,6 @@ CONFIG_DRM_EXYNOS_MIXER=y
CONFIG_DRM_EXYNOS_HDMI=y
CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=y
-CONFIG_FB_SIMPLE=y
CONFIG_EXYNOS_VIDEO=y
CONFIG_EXYNOS_MIPI_DSI=y
CONFIG_LCD_CLASS_DEVICE=y
@@ -159,8 +163,10 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_EXYNOS=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
+CONFIG_USB_DWC2=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_USB_GADGET=y
+CONFIG_USB_ETH=y
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_SDHCI=y
@@ -168,6 +174,12 @@ CONFIG_MMC_SDHCI_S3C=y
CONFIG_MMC_SDHCI_S3C_DMA=y
CONFIG_MMC_DW=y
CONFIG_MMC_DW_EXYNOS=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_PWM=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_MAX77802=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 79194c6..4187f69 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -47,7 +47,6 @@ CONFIG_SOC_VF610=y
CONFIG_PCI=y
CONFIG_PCI_IMX6=y
CONFIG_SMP=y
-CONFIG_VMSPLIT_2G=y
CONFIG_PREEMPT_VOLUNTARY=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
@@ -159,6 +158,7 @@ CONFIG_MOUSE_PS2=m
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_EGALAX=y
+CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
CONFIG_TOUCHSCREEN_MC13783=y
CONFIG_TOUCHSCREEN_TSC2007=y
CONFIG_TOUCHSCREEN_STMPE=y
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 95ce128..5bcc9cf 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -4,6 +4,12 @@ CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_CGROUPS=y
+CONFIG_CGROUP_FREEZER=y
+CONFIG_CGROUP_DEVICE=y
+CONFIG_CGROUP_CPUACCT=y
+CONFIG_CGROUP_SCHED=y
+CONFIG_BLK_CGROUP=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_SYSCTL_SYSCALL=y
CONFIG_KALLSYMS_ALL=y
@@ -27,6 +33,7 @@ CONFIG_SMP=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_HIGHMEM=y
+CONFIG_CMA=y
CONFIG_VFP=y
CONFIG_NEON=y
# CONFIG_SUSPEND is not set
@@ -57,7 +64,6 @@ CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
CONFIG_IP_PIMSM_V2=y
CONFIG_INET_AH=y
CONFIG_INET_IPCOMP=y
-CONFIG_IPV6=y
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
CONFIG_INET6_XFRM_MODE_BEET=m
@@ -93,7 +99,6 @@ CONFIG_IP_NF_MATCH_ECN=y
CONFIG_IP_NF_MATCH_TTL=y
CONFIG_IP_NF_FILTER=y
CONFIG_IP_NF_TARGET_REJECT=y
-CONFIG_IP_NF_TARGET_ULOG=y
CONFIG_IP_NF_MANGLE=y
CONFIG_IP_NF_TARGET_CLUSTERIP=y
CONFIG_IP_NF_TARGET_ECN=y
@@ -106,7 +111,8 @@ CONFIG_IP6_NF_IPTABLES=m
CONFIG_IP_SCTP=y
CONFIG_VLAN_8021Q=y
CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_CMA=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
CONFIG_DMA_CMA=y
CONFIG_MTD=y
CONFIG_MTD_CMDLINE_PARTS=y
@@ -117,7 +123,6 @@ CONFIG_MTD_NAND=y
CONFIG_MTD_NAND_DAVINCI=y
CONFIG_MTD_SPI_NOR=y
CONFIG_MTD_UBI=y
-CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_EEPROM_AT24=y
CONFIG_SCSI=y
@@ -125,7 +130,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
CONFIG_TI_KEYSTONE_NETCP=y
CONFIG_TI_KEYSTONE_NETCP_ETHSS=y
-CONFIG_PHYLIB=y
+CONFIG_MARVELL_PHY=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
@@ -137,12 +142,15 @@ CONFIG_I2C_DAVINCI=y
CONFIG_SPI=y
CONFIG_SPI_DAVINCI=y
CONFIG_SPI_SPIDEV=y
-# CONFIG_HWMON is not set
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_DAVINCI=y
+CONFIG_GPIO_SYSCON=y
CONFIG_POWER_SUPPLY=y
CONFIG_POWER_RESET=y
CONFIG_POWER_RESET_KEYSTONE=y
+# CONFIG_HWMON is not set
CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_CORE=y
CONFIG_DAVINCI_WATCHDOG=y
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
@@ -150,9 +158,15 @@ CONFIG_USB_MON=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
-CONFIG_USB_DWC3_DEBUG=y
-CONFIG_USB_DWC3_VERBOSE=y
CONFIG_KEYSTONE_USB_PHY=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_ONESHOT=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_BACKLIGHT=y
+CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_DMADEVICES=y
CONFIG_TI_EDMA=y
CONFIG_SOC_TI=y
@@ -160,8 +174,11 @@ CONFIG_KEYSTONE_NAVIGATOR_QMSS=y
CONFIG_KEYSTONE_NAVIGATOR_DMA=y
CONFIG_MEMORY=y
CONFIG_TI_AEMIF=y
+CONFIG_KEYSTONE_IRQ=y
CONFIG_EXT4_FS=y
CONFIG_EXT4_FS_POSIX_ACL=y
+CONFIG_FANOTIFY=y
+CONFIG_AUTOFS4_FS=y
CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
CONFIG_NTFS_FS=y
@@ -179,11 +196,10 @@ CONFIG_NFSD_V3_ACL=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_PRINTK_TIME=y
-CONFIG_DEBUG_SHIRQ=y
CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_SHIRQ=y
CONFIG_DEBUG_USER=y
CONFIG_CRYPTO_USER=y
-CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_AUTHENC=y
CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_CTR=y
@@ -192,19 +208,3 @@ CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_ANSI_CPRNG=y
CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_CRYPTO_USER_API_SKCIPHER=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_GPIO_DAVINCI=y
-CONFIG_LEDS_CLASS=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_ONESHOT=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_BACKLIGHT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_KEYSTONE_IRQ=y
-CONFIG_GPIO_SYSCON=y
-CONFIG_TI_DAVINCI_MDIO=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DEVTMPFS=y
diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig
index b7e8cda..03c155f 100644
--- a/arch/arm/configs/lpc18xx_defconfig
+++ b/arch/arm/configs/lpc18xx_defconfig
@@ -52,15 +52,22 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_FW_LOADER is not set
CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
CONFIG_MTD_CFI_STAA=y
CONFIG_MTD_PHYSMAP=y
CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_MTD_SPI_NOR=y
+# CONFIG_MTD_SPI_NOR_USE_4K_SECTORS is not set
+CONFIG_SPI_NXP_SPIFI=y
CONFIG_BLK_DEV_RAM=y
CONFIG_SRAM=y
CONFIG_EEPROM_AT24=y
+CONFIG_SCSI=y
+CONFIG_BLK_DEV_SD=y
+# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_ARC is not set
# CONFIG_NET_CADENCE is not set
@@ -102,14 +109,17 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_OF_PLATFORM=y
# CONFIG_HW_RANDOM is not set
CONFIG_I2C=y
+CONFIG_I2C_LPC2K=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
+CONFIG_GPIOLIB=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_74XX_MMIO=y
+CONFIG_GPIO_PCF857X=y
+CONFIG_SENSORS_JC42=y
CONFIG_SENSORS_LM75=y
CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_CORE=y
-CONFIG_MFD_SYSCON=y
+CONFIG_LPC18XX_WATCHDOG=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_FB=y
@@ -117,6 +127,8 @@ CONFIG_FB_ARMCLCD=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_STORAGE=y
CONFIG_MMC=y
CONFIG_MMC_DW=y
CONFIG_NEW_LEDS=y
@@ -127,12 +139,20 @@ CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_LPC24XX=y
CONFIG_DMADEVICES=y
CONFIG_AMBA_PL08X=y
+CONFIG_LPC18XX_DMAMUX=y
+CONFIG_MEMORY=y
+CONFIG_ARM_PL172_MPMC=y
+CONFIG_PWM=y
+CONFIG_PWM_LPC18XX_SCT=y
+CONFIG_PHY_LPC18XX_USB_OTG=y
CONFIG_EXT2_FS=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
+CONFIG_JFFS2_FS=y
# CONFIG_NETWORK_FILESYSTEMS is not set
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_INFO=y
@@ -142,8 +162,6 @@ CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_RCU_CPU_STALL_INFO is not set
-# CONFIG_FTRACE is not set
CONFIG_DEBUG_LL=y
CONFIG_EARLY_PRINTK=y
CONFIG_CRC_ITU_T=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 03deb7f..cd7b198 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -21,10 +21,12 @@ CONFIG_MACH_ARMADA_39X=y
CONFIG_MACH_ARMADA_XP=y
CONFIG_MACH_DOVE=y
CONFIG_ARCH_AT91=y
+CONFIG_SOC_SAMA5D2=y
CONFIG_SOC_SAMA5D3=y
CONFIG_SOC_SAMA5D4=y
CONFIG_ARCH_BCM=y
CONFIG_ARCH_BCM_CYGNUS=y
+CONFIG_ARCH_BCM_NSP=y
CONFIG_ARCH_BCM_21664=y
CONFIG_ARCH_BCM_281XX=y
CONFIG_ARCH_BCM_5301X=y
@@ -85,7 +87,6 @@ CONFIG_ARCH_R8A7791=y
CONFIG_ARCH_R8A7793=y
CONFIG_ARCH_R8A7794=y
CONFIG_ARCH_SH73A0=y
-CONFIG_MACH_MARZEN=y
CONFIG_ARCH_SUNXI=y
CONFIG_ARCH_SIRF=y
CONFIG_ARCH_TEGRA=y
@@ -153,6 +154,7 @@ CONFIG_CAN_DEV=y
CONFIG_CAN_AT91=m
CONFIG_CAN_XILINXCAN=y
CONFIG_CAN_MCP251X=y
+CONFIG_CAN_SUN4I=y
CONFIG_BT=m
CONFIG_BT_MRVL=m
CONFIG_BT_MRVL_SDIO=m
@@ -207,6 +209,7 @@ CONFIG_NET_CALXEDA_XGMAC=y
CONFIG_IGB=y
CONFIG_MV643XX_ETH=y
CONFIG_MVNETA=y
+CONFIG_PXA168_ETH=m
CONFIG_KS8851=y
CONFIG_R8169=y
CONFIG_SH_ETH=y
@@ -220,7 +223,9 @@ CONFIG_SMSC_PHY=y
CONFIG_BROADCOM_PHY=y
CONFIG_ICPLUS_PHY=y
CONFIG_MICREL_PHY=y
+CONFIG_FIXED_PHY=y
CONFIG_USB_PEGASUS=y
+CONFIG_USB_RTL8152=m
CONFIG_USB_USBNET=y
CONFIG_USB_NET_SMSC75XX=y
CONFIG_USB_NET_SMSC95XX=y
@@ -245,6 +250,7 @@ CONFIG_TOUCHSCREEN_ATMEL_MXT=y
CONFIG_TOUCHSCREEN_ST1232=m
CONFIG_TOUCHSCREEN_STMPE=y
CONFIG_TOUCHSCREEN_SUN4I=y
+CONFIG_TOUCHSCREEN_WM97XX=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MPU3050=y
CONFIG_INPUT_AXP20X_PEK=y
@@ -302,12 +308,15 @@ CONFIG_I2C_GPIO=m
CONFIG_I2C_EXYNOS5=y
CONFIG_I2C_MV64XXX=y
CONFIG_I2C_RIIC=y
+CONFIG_I2C_RK3X=y
CONFIG_I2C_S3C2410=y
CONFIG_I2C_SH_MOBILE=y
CONFIG_I2C_SIRF=y
CONFIG_I2C_ST=y
CONFIG_I2C_SUN6I_P2WI=y
CONFIG_I2C_TEGRA=y
+CONFIG_I2C_UNIPHIER=y
+CONFIG_I2C_UNIPHIER_F=y
CONFIG_I2C_XILINX=y
CONFIG_I2C_RCAR=y
CONFIG_I2C_CROS_EC_TUNNEL=m
@@ -318,6 +327,7 @@ CONFIG_SPI_DAVINCI=y
CONFIG_SPI_OMAP24XX=y
CONFIG_SPI_ORION=y
CONFIG_SPI_PL022=y
+CONFIG_SPI_ROCKCHIP=m
CONFIG_SPI_RSPI=y
CONFIG_SPI_S3C64XX=m
CONFIG_SPI_SH_MSIOF=m
@@ -332,6 +342,7 @@ CONFIG_SPI_XILINX=y
CONFIG_SPI_SPIDEV=y
CONFIG_PINCTRL_AS3722=y
CONFIG_PINCTRL_PALMAS=y
+CONFIG_PINCTRL_APQ8064=y
CONFIG_PINCTRL_APQ8084=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_GENERIC_PLATFORM=y
@@ -355,6 +366,7 @@ CONFIG_BATTERY_MAX17042=m
CONFIG_CHARGER_MAX14577=m
CONFIG_CHARGER_MAX77693=m
CONFIG_CHARGER_TPS65090=y
+CONFIG_AXP20X_POWER=m
CONFIG_POWER_RESET_AS3722=y
CONFIG_POWER_RESET_GPIO=y
CONFIG_POWER_RESET_GPIO_RESTART=y
@@ -365,6 +377,7 @@ CONFIG_SENSORS_LM95245=y
CONFIG_SENSORS_NTC_THERMISTOR=m
CONFIG_THERMAL=y
CONFIG_CPU_THERMAL=y
+CONFIG_ROCKCHIP_THERMAL=y
CONFIG_RCAR_THERMAL=y
CONFIG_ARMADA_THERMAL=y
CONFIG_DAVINCI_WATCHDOG=m
@@ -382,6 +395,7 @@ CONFIG_MESON_WATCHDOG=y
CONFIG_DIGICOLOR_WATCHDOG=y
CONFIG_MFD_AS3711=y
CONFIG_MFD_AS3722=y
+CONFIG_MFD_ATMEL_FLEXCOM=y
CONFIG_MFD_BCM590XX=y
CONFIG_MFD_AXP20X=y
CONFIG_MFD_CROS_EC=y
@@ -391,6 +405,9 @@ CONFIG_MFD_MAX14577=y
CONFIG_MFD_MAX77686=y
CONFIG_MFD_MAX77693=y
CONFIG_MFD_MAX8907=y
+CONFIG_MFD_RK808=y
+CONFIG_MFD_PM8921_CORE=y
+CONFIG_MFD_QCOM_RPM=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_STMPE=y
CONFIG_MFD_PALMAS=y
@@ -398,11 +415,14 @@ CONFIG_MFD_TPS65090=y
CONFIG_MFD_TPS6586X=y
CONFIG_MFD_TPS65910=y
CONFIG_REGULATOR_AB8500=y
+CONFIG_REGULATOR_ACT8865=y
CONFIG_REGULATOR_AS3711=y
CONFIG_REGULATOR_AS3722=y
CONFIG_REGULATOR_AXP20X=y
CONFIG_REGULATOR_BCM590XX=y
CONFIG_REGULATOR_DA9210=y
+CONFIG_REGULATOR_FAN53555=y
+CONFIG_REGULATOR_RK808=y
CONFIG_REGULATOR_GPIO=y
CONFIG_MFD_SYSCON=y
CONFIG_POWER_RESET_SYSCON=y
@@ -415,6 +435,8 @@ CONFIG_REGULATOR_MAX77802=m
CONFIG_REGULATOR_PALMAS=y
CONFIG_REGULATOR_PBIAS=y
CONFIG_REGULATOR_PWM=m
+CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
CONFIG_REGULATOR_TPS51632=y
@@ -441,6 +463,7 @@ CONFIG_VIDEO_RENESAS_VSP1=m
CONFIG_VIDEO_ADV7180=m
CONFIG_VIDEO_ML86V7667=m
CONFIG_DRM=y
+CONFIG_DRM_I2C_ADV7511=m
# CONFIG_DRM_I2C_CH7006 is not set
# CONFIG_DRM_I2C_SIL164 is not set
CONFIG_DRM_NXP_PTN3460=m
@@ -450,7 +473,11 @@ CONFIG_DRM_EXYNOS=m
CONFIG_DRM_EXYNOS_DSI=y
CONFIG_DRM_EXYNOS_FIMD=y
CONFIG_DRM_EXYNOS_HDMI=y
+CONFIG_DRM_ROCKCHIP=m
+CONFIG_ROCKCHIP_DW_HDMI=m
CONFIG_DRM_RCAR_DU=m
+CONFIG_DRM_RCAR_HDMI=y
+CONFIG_DRM_RCAR_LVDS=y
CONFIG_DRM_TEGRA=y
CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0=m
CONFIG_DRM_PANEL_SIMPLE=y
@@ -485,6 +512,7 @@ CONFIG_SND_SOC_TEGRA=m
CONFIG_SND_SOC_TEGRA_RT5640=m
CONFIG_SND_SOC_TEGRA_WM8753=m
CONFIG_SND_SOC_TEGRA_WM8903=m
+CONFIG_SND_SOC_TEGRA_WM9712=m
CONFIG_SND_SOC_TEGRA_TRIMSLICE=m
CONFIG_SND_SOC_TEGRA_ALC5632=m
CONFIG_SND_SOC_TEGRA_MAX98090=m
@@ -494,6 +522,7 @@ CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_MVEBU=y
CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_MSM=m
CONFIG_USB_EHCI_EXYNOS=y
CONFIG_USB_EHCI_TEGRA=y
CONFIG_USB_EHCI_HCD_STI=y
@@ -507,6 +536,7 @@ CONFIG_USB_R8A66597_HCD=m
CONFIG_USB_RENESAS_USBHS=m
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
+CONFIG_USB_DWC2=m
CONFIG_USB_CHIPIDEA=y
CONFIG_USB_CHIPIDEA_HOST=y
CONFIG_AB8500_USB=y
@@ -514,16 +544,19 @@ CONFIG_KEYSTONE_USB_PHY=y
CONFIG_OMAP_USB3=y
CONFIG_USB_GPIO_VBUS=y
CONFIG_USB_ISP1301=y
+CONFIG_USB_MSM_OTG=m
CONFIG_USB_MXS_PHY=y
CONFIG_USB_RCAR_PHY=m
CONFIG_USB_GADGET=y
CONFIG_USB_RENESAS_USBHS_UDC=m
+CONFIG_USB_ETH=m
CONFIG_MMC=y
CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_ARMMMCI=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_OF_ARASAN=y
+CONFIG_MMC_SDHCI_OF_AT91=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_DOVE=y
CONFIG_MMC_SDHCI_TEGRA=y
@@ -566,8 +599,10 @@ CONFIG_EDAC_HIGHBANK_L2=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_AS3722=y
CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_HYM8563=m
CONFIG_RTC_DRV_MAX8907=y
CONFIG_RTC_DRV_MAX77686=y
+CONFIG_RTC_DRV_RK808=m
CONFIG_RTC_DRV_MAX77802=m
CONFIG_RTC_DRV_RS5C372=m
CONFIG_RTC_DRV_PALMAS=y
@@ -605,6 +640,7 @@ CONFIG_IMX_SDMA=y
CONFIG_IMX_DMA=y
CONFIG_MXS_DMA=y
CONFIG_DMA_OMAP=y
+CONFIG_QCOM_BAM_DMA=y
CONFIG_XILINX_VDMA=y
CONFIG_DMA_SUN6I=y
CONFIG_STAGING=y
@@ -617,6 +653,9 @@ CONFIG_NVEC_POWER=y
CONFIG_NVEC_PAZ00=y
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_PM=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMEM=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_CHROME_PLATFORMS=y
CONFIG_CROS_EC_CHARDEV=m
@@ -627,6 +666,8 @@ CONFIG_APQ_MMCC_8084=y
CONFIG_MSM_GCC_8660=y
CONFIG_MSM_MMCC_8960=y
CONFIG_MSM_MMCC_8974=y
+CONFIG_HWSPINLOCK_QCOM=y
+CONFIG_ROCKCHIP_IOMMU=y
CONFIG_TEGRA_IOMMU_GART=y
CONFIG_TEGRA_IOMMU_SMMU=y
CONFIG_PM_DEVFREQ=y
@@ -636,6 +677,7 @@ CONFIG_EXTCON=y
CONFIG_TI_AEMIF=y
CONFIG_IIO=y
CONFIG_AT91_ADC=m
+CONFIG_BERLIN2_ADC=m
CONFIG_EXYNOS_ADC=m
CONFIG_XILINX_XADC=y
CONFIG_AK8975=y
@@ -643,6 +685,7 @@ CONFIG_PWM=y
CONFIG_PWM_ATMEL=m
CONFIG_PWM_ATMEL_TCB=m
CONFIG_PWM_RENESAS_TPU=y
+CONFIG_PWM_ROCKCHIP=m
CONFIG_PWM_SAMSUNG=m
CONFIG_PWM_SUN4I=y
CONFIG_PWM_TEGRA=y
@@ -651,6 +694,10 @@ CONFIG_PHY_HIX5HD2_SATA=y
CONFIG_PWM_STI=m
CONFIG_OMAP_USB2=y
CONFIG_TI_PIPE3=y
+CONFIG_PHY_BERLIN_USB=y
+CONFIG_PHY_BERLIN_SATA=y
+CONFIG_PHY_ROCKCHIP_USB=m
+CONFIG_PHY_QCOM_APQ8064_SATA=m
CONFIG_PHY_MIPHY28LP=y
CONFIG_PHY_MIPHY365X=y
CONFIG_PHY_RCAR_GEN2=m
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index 13fcd02..c6729bf 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -61,6 +61,7 @@ CONFIG_MTD_SPI_NOR=y
CONFIG_EEPROM_AT24=y
CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
+CONFIG_SATA_AHCI=y
CONFIG_AHCI_MVEBU=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
@@ -85,6 +86,9 @@ CONFIG_SPI=y
CONFIG_SPI_ORION=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PCA953X=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_GPIO=y
CONFIG_SENSORS_GPIO_FAN=y
CONFIG_THERMAL=y
CONFIG_ARMADA_THERMAL=y
@@ -111,12 +115,15 @@ CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_DOVE=y
CONFIG_MMC_SDHCI_PXAV3=y
CONFIG_MMC_MVSDIO=y
-CONFIG_LEDS_GPIO=y
+CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_GPIO=y
CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_TIMER=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_DS1307=y
+CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_S35390A=y
CONFIG_RTC_DRV_MV=y
CONFIG_RTC_DRV_ARMADA38X=y
diff --git a/arch/arm/configs/qcom_defconfig b/arch/arm/configs/qcom_defconfig
index ff7985b..ee54a70 100644
--- a/arch/arm/configs/qcom_defconfig
+++ b/arch/arm/configs/qcom_defconfig
@@ -109,6 +109,7 @@ CONFIG_MFD_QCOM_RPM=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_QCOM_RPM=y
+CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_MEDIA_SUPPORT=y
CONFIG_FB=y
CONFIG_SOUND=y
@@ -145,16 +146,17 @@ CONFIG_MSM_GCC_8660=y
CONFIG_MSM_LCC_8960=y
CONFIG_MSM_MMCC_8960=y
CONFIG_MSM_MMCC_8974=y
-CONFIG_MSM_IOMMU=y
+CONFIG_HWSPINLOCK_QCOM=y
CONFIG_QCOM_GSBI=y
CONFIG_QCOM_PM=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SMD_RPM=y
+CONFIG_QCOM_SMEM=y
CONFIG_PHY_QCOM_APQ8064_SATA=y
CONFIG_PHY_QCOM_IPQ806X_SATA=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT4_FS=y
CONFIG_FUSE_FS=y
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index 31eb951..63f7e6c 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -10,12 +10,11 @@ CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
CONFIG_ARCH_AT91=y
-CONFIG_SOC_SAM_V7=y
+CONFIG_SOC_SAMA5D2=y
CONFIG_SOC_SAMA5D3=y
CONFIG_SOC_SAMA5D4=y
CONFIG_AEABI=y
@@ -25,12 +24,10 @@ CONFIG_ZBOOT_ROM_BSS=0x0
CONFIG_ARM_APPENDED_DTB=y
CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw"
CONFIG_KEXEC=y
-CONFIG_AUTO_ZRELADDR=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_KERNEL_MODE_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM=y
CONFIG_PM_DEBUG=y
CONFIG_PM_ADVANCED_DEBUG=y
CONFIG_NET=y
@@ -47,7 +44,6 @@ CONFIG_IP_PNP_RARP=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
# CONFIG_INET6_XFRM_MODE_BEET is not set
@@ -123,7 +119,6 @@ CONFIG_LEGACY_PTY_COUNT=4
CONFIG_SERIAL_ATMEL=y
CONFIG_SERIAL_ATMEL_CONSOLE=y
CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_AT91=y
CONFIG_I2C_GPIO=y
@@ -134,7 +129,7 @@ CONFIG_GPIO_SYSFS=y
CONFIG_POWER_SUPPLY=y
CONFIG_POWER_RESET=y
# CONFIG_HWMON is not set
-CONFIG_SSB=m
+CONFIG_MFD_ATMEL_FLEXCOM=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
CONFIG_REGULATOR_ACT8865=y
@@ -142,8 +137,8 @@ CONFIG_MEDIA_SUPPORT=y
CONFIG_MEDIA_CAMERA_SUPPORT=y
CONFIG_V4L_PLATFORM_DRIVERS=y
CONFIG_SOC_CAMERA=y
-CONFIG_SOC_CAMERA_OV2640=y
CONFIG_VIDEO_ATMEL_ISI=y
+CONFIG_SOC_CAMERA_OV2640=y
CONFIG_FB=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
# CONFIG_LCD_CLASS_DEVICE is not set
@@ -171,6 +166,9 @@ CONFIG_USB_ATMEL_USBA=y
CONFIG_USB_G_SERIAL=y
CONFIG_MMC=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_PLTFM=y
+CONFIG_MMC_SDHCI_OF_AT91=y
CONFIG_MMC_ATMELMCI=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
@@ -207,11 +205,8 @@ CONFIG_DEBUG_MEMORY_INIT=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_FTRACE is not set
CONFIG_DEBUG_USER=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
CONFIG_CRYPTO_USER_API_HASH=m
CONFIG_CRYPTO_USER_API_SKCIPHER=m
CONFIG_CRYPTO_DEV_ATMEL_AES=y
CONFIG_CRYPTO_DEV_ATMEL_TDES=y
CONFIG_CRYPTO_DEV_ATMEL_SHA=y
-CONFIG_CRC_CCITT=m
-CONFIG_CRC_ITU_T=m
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index 89bf31c..3aef019 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -21,7 +21,6 @@ CONFIG_ARCH_R8A7791=y
CONFIG_ARCH_R8A7793=y
CONFIG_ARCH_R8A7794=y
CONFIG_ARCH_SH73A0=y
-CONFIG_MACH_MARZEN=y
CONFIG_CPU_BPREDICT_DISABLE=y
CONFIG_PL310_ERRATA_588369=y
CONFIG_ARM_ERRATA_754322=y
@@ -141,7 +140,10 @@ CONFIG_VIDEO_RENESAS_VSP1=y
CONFIG_VIDEO_ADV7180=y
CONFIG_VIDEO_ML86V7667=y
CONFIG_DRM=y
+CONFIG_DRM_I2C_ADV7511=y
CONFIG_DRM_RCAR_DU=y
+CONFIG_DRM_RCAR_HDMI=y
+CONFIG_DRM_RCAR_LVDS=y
CONFIG_FB_SH_MOBILE_LCDC=y
CONFIG_FB_SH_MOBILE_MERAM=y
# CONFIG_LCD_CLASS_DEVICE is not set
diff --git a/arch/arm/configs/socfpga_defconfig b/arch/arm/configs/socfpga_defconfig
index a2956c3..8128b93e 100644
--- a/arch/arm/configs/socfpga_defconfig
+++ b/arch/arm/configs/socfpga_defconfig
@@ -86,6 +86,8 @@ CONFIG_USB_DWC2=y
CONFIG_USB_DWC2_HOST=y
CONFIG_MMC=y
CONFIG_MMC_DW=y
+CONFIG_FPGA=y
+CONFIG_FPGA_MGR_SOCFPGA=y
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index 51eea22..b503a89 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -5,6 +5,7 @@ CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_PERF_EVENTS=y
CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
CONFIG_ARCH_SUNXI=y
CONFIG_SMP=y
CONFIG_NR_CPUS=8
@@ -31,6 +32,8 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
# CONFIG_IPV6 is not set
+CONFIG_CAN=y
+CONFIG_CAN_SUN4I=y
# CONFIG_WIRELESS is not set
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
@@ -63,6 +66,7 @@ CONFIG_STMMAC_ETH=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_AXP20X_PEK=y
CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_KEYBOARD_SUN4I_LRADC=y
CONFIG_TOUCHSCREEN_SUN4I=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
@@ -80,6 +84,7 @@ CONFIG_SPI_SUN4I=y
CONFIG_SPI_SUN6I=y
CONFIG_GPIO_SYSFS=y
CONFIG_POWER_SUPPLY=y
+CONFIG_AXP20X_POWER=y
CONFIG_THERMAL=y
CONFIG_CPU_THERMAL=y
CONFIG_WATCHDOG=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 9808581..3a36244 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -1,5 +1,6 @@
CONFIG_SYSVIPC=y
CONFIG_FHANDLE=y
+CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_IKCONFIG=y
@@ -60,7 +61,6 @@ CONFIG_INET_ESP=y
# CONFIG_INET_XFRM_MODE_BEET is not set
# CONFIG_INET_LRO is not set
# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
CONFIG_IPV6_ROUTER_PREF=y
CONFIG_IPV6_OPTIMISTIC_DAD=y
CONFIG_INET6_AH=y
@@ -121,6 +121,9 @@ CONFIG_KEYBOARD_CROS_EC=y
CONFIG_MOUSE_PS2_ELANTECH=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ATMEL_MXT=y
+CONFIG_TOUCHSCREEN_WM97XX=y
+# CONFIG_TOUCHSCREEN_WM9705 is not set
+# CONFIG_TOUCHSCREEN_WM9713 is not set
CONFIG_TOUCHSCREEN_STMPE=y
CONFIG_INPUT_MISC=y
CONFIG_INPUT_MPU3050=y
@@ -142,6 +145,7 @@ CONFIG_SPI_TEGRA20_SFLASH=y
CONFIG_SPI_TEGRA20_SLINK=y
CONFIG_PINCTRL_AS3722=y
CONFIG_PINCTRL_PALMAS=y
+CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_PCA953X=y
CONFIG_GPIO_PCA953X_IRQ=y
CONFIG_GPIO_PALMAS=y
@@ -208,6 +212,7 @@ CONFIG_SND_SOC_TEGRA=y
CONFIG_SND_SOC_TEGRA_RT5640=y
CONFIG_SND_SOC_TEGRA_WM8753=y
CONFIG_SND_SOC_TEGRA_WM8903=y
+CONFIG_SND_SOC_TEGRA_WM9712=y
CONFIG_SND_SOC_TEGRA_TRIMSLICE=y
CONFIG_SND_SOC_TEGRA_ALC5632=y
CONFIG_SND_SOC_TEGRA_MAX98090=y
@@ -266,10 +271,8 @@ CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
-CONFIG_EXT4_FS=y
# CONFIG_DNOTIFY is not set
CONFIG_VFAT_FS=y
CONFIG_TMPFS=y
@@ -278,6 +281,7 @@ CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_LZO=y
CONFIG_SQUASHFS_XZ=y
CONFIG_NFS_FS=y
+CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild
index bd42530..16da638 100644
--- a/arch/arm/include/asm/Kbuild
+++ b/arch/arm/include/asm/Kbuild
@@ -3,6 +3,7 @@
generic-y += bitsperlong.h
generic-y += cputime.h
generic-y += current.h
+generic-y += early_ioremap.h
generic-y += emergency-restart.h
generic-y += errno.h
generic-y += exec.h
diff --git a/arch/arm/include/asm/arch_gicv3.h b/arch/arm/include/asm/arch_gicv3.h
index 6607d97..7da5503 100644
--- a/arch/arm/include/asm/arch_gicv3.h
+++ b/arch/arm/include/asm/arch_gicv3.h
@@ -21,6 +21,7 @@
#ifndef __ASSEMBLY__
#include <linux/io.h>
+#include <asm/barrier.h>
#define __ACCESS_CP15(CRn, Op1, CRm, Op2) p15, Op1, %0, CRn, CRm, Op2
#define __ACCESS_CP15_64(Op1, CRm) p15, Op1, %Q0, %R0, CRm
diff --git a/arch/arm/include/asm/bug.h b/arch/arm/include/asm/bug.h
index e7335a9..4e6e88a 100644
--- a/arch/arm/include/asm/bug.h
+++ b/arch/arm/include/asm/bug.h
@@ -5,8 +5,6 @@
#include <linux/types.h>
#include <asm/opcodes.h>
-#ifdef CONFIG_BUG
-
/*
* Use a suitable undefined instruction to use for ARM/Thumb2 bug handling.
* We need to be careful not to conflict with those used by other modules and
@@ -47,7 +45,7 @@ do { \
unreachable(); \
} while (0)
-#else /* not CONFIG_DEBUG_BUGVERBOSE */
+#else
#define __BUG(__file, __line, __value) \
do { \
@@ -57,7 +55,6 @@ do { \
#endif /* CONFIG_DEBUG_BUGVERBOSE */
#define HAVE_ARCH_BUG
-#endif /* CONFIG_BUG */
#include <asm-generic/bug.h>
diff --git a/arch/arm/include/asm/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 0f84249..3848259 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -30,7 +30,7 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
struct device_node;
struct cpuidle_ops {
- int (*suspend)(int cpu, unsigned long arg);
+ int (*suspend)(unsigned long arg);
int (*init)(struct device_node *, int cpu);
};
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h
new file mode 100644
index 0000000..e0eea72
--- /dev/null
+++ b/arch/arm/include/asm/efi.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ASM_ARM_EFI_H
+#define __ASM_ARM_EFI_H
+
+#include <asm/cacheflush.h>
+#include <asm/cachetype.h>
+#include <asm/early_ioremap.h>
+#include <asm/fixmap.h>
+#include <asm/highmem.h>
+#include <asm/mach/map.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_EFI
+void efi_init(void);
+
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
+#define efi_call_virt(f, ...) \
+({ \
+ efi_##f##_t *__f; \
+ efi_status_t __s; \
+ \
+ efi_virtmap_load(); \
+ __f = efi.systab->runtime->f; \
+ __s = __f(__VA_ARGS__); \
+ efi_virtmap_unload(); \
+ __s; \
+})
+
+#define __efi_call_virt(f, ...) \
+({ \
+ efi_##f##_t *__f; \
+ \
+ efi_virtmap_load(); \
+ __f = efi.systab->runtime->f; \
+ __f(__VA_ARGS__); \
+ efi_virtmap_unload(); \
+})
+
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+ check_and_switch_context(mm, NULL);
+}
+
+void efi_virtmap_load(void);
+void efi_virtmap_unload(void);
+
+#else
+#define efi_init()
+#endif /* CONFIG_EFI */
+
+/* arch specific definitions used by the stub code */
+
+#define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__)
+
+/*
+ * A reasonable upper bound for the uncompressed kernel size is 32 MBytes,
+ * so we will reserve that amount of memory. We have no easy way to tell what
+ * the actuall size of code + data the uncompressed kernel will use.
+ * If this is insufficient, the decompressor will relocate itself out of the
+ * way before performing the decompression.
+ */
+#define MAX_UNCOMP_KERNEL_SIZE SZ_32M
+
+/*
+ * The kernel zImage should preferably be located between 32 MB and 128 MB
+ * from the base of DRAM. The min address leaves space for a maximal size
+ * uncompressed image, and the max address is due to how the zImage decompressor
+ * picks a destination address.
+ */
+#define ZIMAGE_OFFSET_LIMIT SZ_128M
+#define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE
+#define MAX_FDT_OFFSET ZIMAGE_OFFSET_LIMIT
+
+#endif /* _ASM_ARM_EFI_H */
diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h
index 58cfe9f..5c17d2d 100644
--- a/arch/arm/include/asm/fixmap.h
+++ b/arch/arm/include/asm/fixmap.h
@@ -19,20 +19,47 @@ enum fixed_addresses {
FIX_TEXT_POKE0,
FIX_TEXT_POKE1,
- __end_of_fixed_addresses
+ __end_of_fixmap_region,
+
+ /*
+ * Share the kmap() region with early_ioremap(): this is guaranteed
+ * not to clash since early_ioremap() is only available before
+ * paging_init(), and kmap() only after.
+ */
+#define NR_FIX_BTMAPS 32
+#define FIX_BTMAPS_SLOTS 7
+#define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
+
+ FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+ FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
+ __end_of_early_ioremap_region
};
+static const enum fixed_addresses __end_of_fixed_addresses =
+ __end_of_fixmap_region > __end_of_early_ioremap_region ?
+ __end_of_fixmap_region : __end_of_early_ioremap_region;
+
#define FIXMAP_PAGE_COMMON (L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY)
#define FIXMAP_PAGE_NORMAL (FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK)
+#define FIXMAP_PAGE_RO (FIXMAP_PAGE_NORMAL | L_PTE_RDONLY)
/* Used by set_fixmap_(io|nocache), both meant for mapping a device */
#define FIXMAP_PAGE_IO (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED)
#define FIXMAP_PAGE_NOCACHE FIXMAP_PAGE_IO
+#define __early_set_fixmap __set_fixmap
+
+#ifdef CONFIG_MMU
+
void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
void __init early_fixmap_init(void);
#include <asm-generic/fixmap.h>
+#else
+
+static inline void early_fixmap_init(void) { }
+
+#endif
#endif
diff --git a/arch/arm/include/asm/hardirq.h b/arch/arm/include/asm/hardirq.h
index fe3ea77..3d7351c 100644
--- a/arch/arm/include/asm/hardirq.h
+++ b/arch/arm/include/asm/hardirq.h
@@ -5,7 +5,7 @@
#include <linux/threads.h>
#include <asm/irq.h>
-#define NR_IPI 8
+#define NR_IPI 7
typedef struct {
unsigned int __softirq_pending;
diff --git a/arch/arm/include/asm/hardware/cache-uniphier.h b/arch/arm/include/asm/hardware/cache-uniphier.h
new file mode 100644
index 0000000..102e3fb
--- /dev/null
+++ b/arch/arm/include/asm/hardware/cache-uniphier.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CACHE_UNIPHIER_H
+#define __CACHE_UNIPHIER_H
+
+#include <linux/types.h>
+
+#ifdef CONFIG_CACHE_UNIPHIER
+int uniphier_cache_init(void);
+int uniphier_cache_l2_is_enabled(void);
+void uniphier_cache_l2_touch_range(unsigned long start, unsigned long end);
+void uniphier_cache_l2_set_locked_ways(u32 way_mask);
+#else
+static inline int uniphier_cache_init(void)
+{
+ return -ENODEV;
+}
+
+static inline int uniphier_cache_l2_is_enabled(void)
+{
+ return 0;
+}
+
+static inline void uniphier_cache_l2_touch_range(unsigned long start,
+ unsigned long end)
+{
+}
+
+static inline void uniphier_cache_l2_set_locked_ways(u32 way_mask)
+{
+}
+#endif
+
+#endif /* __CACHE_UNIPHIER_H */
diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h
index be1d07d..1bd9510de 100644
--- a/arch/arm/include/asm/irq.h
+++ b/arch/arm/include/asm/irq.h
@@ -40,6 +40,11 @@ extern void arch_trigger_all_cpu_backtrace(bool);
#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x)
#endif
+static inline int nr_legacy_irqs(void)
+{
+ return NR_IRQS_LEGACY;
+}
+
#endif
#endif
diff --git a/arch/arm/include/asm/kvm_arm.h b/arch/arm/include/asm/kvm_arm.h
index dc641dd..e22089f 100644
--- a/arch/arm/include/asm/kvm_arm.h
+++ b/arch/arm/include/asm/kvm_arm.h
@@ -19,6 +19,7 @@
#ifndef __ARM_KVM_ARM_H__
#define __ARM_KVM_ARM_H__
+#include <linux/const.h>
#include <linux/types.h>
/* Hyp Configuration Register (HCR) bits */
@@ -132,10 +133,9 @@
* space.
*/
#define KVM_PHYS_SHIFT (40)
-#define KVM_PHYS_SIZE (1ULL << KVM_PHYS_SHIFT)
-#define KVM_PHYS_MASK (KVM_PHYS_SIZE - 1ULL)
-#define PTRS_PER_S2_PGD (1ULL << (KVM_PHYS_SHIFT - 30))
-#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
+#define KVM_PHYS_SIZE (_AC(1, ULL) << KVM_PHYS_SHIFT)
+#define KVM_PHYS_MASK (KVM_PHYS_SIZE - _AC(1, ULL))
+#define PTRS_PER_S2_PGD (_AC(1, ULL) << (KVM_PHYS_SHIFT - 30))
/* Virtualization Translation Control Register (VTCR) bits */
#define VTCR_SH0 (3 << 12)
@@ -162,17 +162,17 @@
#define VTTBR_X (5 - KVM_T0SZ)
#endif
#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK (((1LLU << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
-#define VTTBR_VMID_SHIFT (48LLU)
-#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
+#define VTTBR_BADDR_MASK (((_AC(1, ULL) << (40 - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT _AC(48, ULL)
+#define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
/* Hyp Syndrome Register (HSR) bits */
#define HSR_EC_SHIFT (26)
-#define HSR_EC (0x3fU << HSR_EC_SHIFT)
-#define HSR_IL (1U << 25)
+#define HSR_EC (_AC(0x3f, UL) << HSR_EC_SHIFT)
+#define HSR_IL (_AC(1, UL) << 25)
#define HSR_ISS (HSR_IL - 1)
#define HSR_ISV_SHIFT (24)
-#define HSR_ISV (1U << HSR_ISV_SHIFT)
+#define HSR_ISV (_AC(1, UL) << HSR_ISV_SHIFT)
#define HSR_SRT_SHIFT (16)
#define HSR_SRT_MASK (0xf << HSR_SRT_SHIFT)
#define HSR_FSC (0x3f)
@@ -180,9 +180,9 @@
#define HSR_SSE (1 << 21)
#define HSR_WNR (1 << 6)
#define HSR_CV_SHIFT (24)
-#define HSR_CV (1U << HSR_CV_SHIFT)
+#define HSR_CV (_AC(1, UL) << HSR_CV_SHIFT)
#define HSR_COND_SHIFT (20)
-#define HSR_COND (0xfU << HSR_COND_SHIFT)
+#define HSR_COND (_AC(0xf, UL) << HSR_COND_SHIFT)
#define FSC_FAULT (0x04)
#define FSC_ACCESS (0x08)
@@ -210,13 +210,13 @@
#define HSR_EC_DABT (0x24)
#define HSR_EC_DABT_HYP (0x25)
-#define HSR_WFI_IS_WFE (1U << 0)
+#define HSR_WFI_IS_WFE (_AC(1, UL) << 0)
-#define HSR_HVC_IMM_MASK ((1UL << 16) - 1)
+#define HSR_HVC_IMM_MASK ((_AC(1, UL) << 16) - 1)
-#define HSR_DABT_S1PTW (1U << 7)
-#define HSR_DABT_CM (1U << 8)
-#define HSR_DABT_EA (1U << 9)
+#define HSR_DABT_S1PTW (_AC(1, UL) << 7)
+#define HSR_DABT_CM (_AC(1, UL) << 8)
+#define HSR_DABT_EA (_AC(1, UL) << 9)
#define kvm_arm_exception_type \
{0, "RESET" }, \
diff --git a/arch/arm/include/asm/kvm_emulate.h b/arch/arm/include/asm/kvm_emulate.h
index a9c80a2..3095df0 100644
--- a/arch/arm/include/asm/kvm_emulate.h
+++ b/arch/arm/include/asm/kvm_emulate.h
@@ -28,6 +28,18 @@
unsigned long *vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num);
unsigned long *vcpu_spsr(struct kvm_vcpu *vcpu);
+static inline unsigned long vcpu_get_reg(struct kvm_vcpu *vcpu,
+ u8 reg_num)
+{
+ return *vcpu_reg(vcpu, reg_num);
+}
+
+static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+ unsigned long val)
+{
+ *vcpu_reg(vcpu, reg_num) = val;
+}
+
bool kvm_condition_valid(struct kvm_vcpu *vcpu);
void kvm_skip_instr(struct kvm_vcpu *vcpu, bool is_wide_instr);
void kvm_inject_undefined(struct kvm_vcpu *vcpu);
diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
index 6692982..f9f2779 100644
--- a/arch/arm/include/asm/kvm_host.h
+++ b/arch/arm/include/asm/kvm_host.h
@@ -150,6 +150,12 @@ struct kvm_vcpu_stat {
u32 halt_successful_poll;
u32 halt_attempted_poll;
u32 halt_wakeup;
+ u32 hvc_exit_stat;
+ u64 wfe_exit_stat;
+ u64 wfi_exit_stat;
+ u64 mmio_exit_user;
+ u64 mmio_exit_kernel;
+ u64 exits;
};
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 405aa18..9203c21 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -279,6 +279,11 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
pgd_t *merged_hyp_pgd,
unsigned long hyp_idmap_start) { }
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+ return 8;
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index f98c7f3..9b7c328 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -42,6 +42,8 @@ enum {
extern void iotable_init(struct map_desc *, int);
extern void vm_reserve_area_early(unsigned long addr, unsigned long size,
void *caller);
+extern void create_mapping_late(struct mm_struct *mm, struct map_desc *md,
+ bool ng);
#ifdef CONFIG_DEBUG_LL
extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr);
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h
index 9b32f76..432ce81 100644
--- a/arch/arm/include/asm/mmu_context.h
+++ b/arch/arm/include/asm/mmu_context.h
@@ -26,7 +26,7 @@ void __check_vmalloc_seq(struct mm_struct *mm);
#ifdef CONFIG_CPU_HAS_ASID
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk);
-#define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; })
+#define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; })
#ifdef CONFIG_ARM_ERRATA_798181
void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm,
diff --git a/arch/arm/include/asm/paravirt.h b/arch/arm/include/asm/paravirt.h
new file mode 100644
index 0000000..8435ff5
--- /dev/null
+++ b/arch/arm/include/asm/paravirt.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_ARM_PARAVIRT_H
+#define _ASM_ARM_PARAVIRT_H
+
+#ifdef CONFIG_PARAVIRT
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops {
+ unsigned long long (*steal_clock)(int cpu);
+};
+extern struct pv_time_ops pv_time_ops;
+
+static inline u64 paravirt_steal_clock(int cpu)
+{
+ return pv_time_ops.steal_clock(cpu);
+}
+#endif
+
+#endif
diff --git a/arch/arm/include/asm/psci.h b/arch/arm/include/asm/psci.h
index 68ee3ce..b4c6d99 100644
--- a/arch/arm/include/asm/psci.h
+++ b/arch/arm/include/asm/psci.h
@@ -16,7 +16,7 @@
extern struct smp_operations psci_smp_ops;
-#ifdef CONFIG_ARM_PSCI
+#if defined(CONFIG_SMP) && defined(CONFIG_ARM_PSCI)
bool psci_smp_available(void);
#else
static inline bool psci_smp_available(void) { return false; }
diff --git a/arch/arm/include/asm/setup.h b/arch/arm/include/asm/setup.h
index e0adb9f..3613d7e 100644
--- a/arch/arm/include/asm/setup.h
+++ b/arch/arm/include/asm/setup.h
@@ -25,4 +25,10 @@ extern int arm_add_memory(u64 start, u64 size);
extern void early_print(const char *str, ...);
extern void dump_machine_table(void);
+#ifdef CONFIG_ATAGS_PROC
+extern void save_atags(const struct tag *tags);
+#else
+static inline void save_atags(const struct tag *tags) { }
+#endif
+
#endif
diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h
index 8cc85a4..35c9db8 100644
--- a/arch/arm/include/asm/uaccess.h
+++ b/arch/arm/include/asm/uaccess.h
@@ -510,10 +510,14 @@ __copy_to_user_std(void __user *to, const void *from, unsigned long n);
static inline unsigned long __must_check
__copy_to_user(void __user *to, const void *from, unsigned long n)
{
+#ifndef CONFIG_UACCESS_WITH_MEMCPY
unsigned int __ua_flags = uaccess_save_and_enable();
n = arm_copy_to_user(to, from, n);
uaccess_restore(__ua_flags);
return n;
+#else
+ return arm_copy_to_user(to, from, n);
+#endif
}
extern unsigned long __must_check
diff --git a/arch/arm/include/asm/xen/hypercall.h b/arch/arm/include/asm/xen/hypercall.h
index 712b50e..d769972 100644
--- a/arch/arm/include/asm/xen/hypercall.h
+++ b/arch/arm/include/asm/xen/hypercall.h
@@ -35,6 +35,7 @@
#include <xen/interface/xen.h>
#include <xen/interface/sched.h>
+#include <xen/interface/platform.h>
long privcmd_call(unsigned call, unsigned long a1,
unsigned long a2, unsigned long a3,
@@ -49,6 +50,12 @@ int HYPERVISOR_memory_op(unsigned int cmd, void *arg);
int HYPERVISOR_physdev_op(int cmd, void *arg);
int HYPERVISOR_vcpu_op(int cmd, int vcpuid, void *extra_args);
int HYPERVISOR_tmem_op(void *arg);
+int HYPERVISOR_platform_op_raw(void *arg);
+static inline int HYPERVISOR_platform_op(struct xen_platform_op *op)
+{
+ op->interface_version = XENPF_INTERFACE_VERSION;
+ return HYPERVISOR_platform_op_raw(op);
+}
int HYPERVISOR_multicall(struct multicall_entry *calls, uint32_t nr);
static inline int
diff --git a/arch/arm/include/asm/xen/interface.h b/arch/arm/include/asm/xen/interface.h
index 5006600..75d5968 100644
--- a/arch/arm/include/asm/xen/interface.h
+++ b/arch/arm/include/asm/xen/interface.h
@@ -27,6 +27,8 @@
(hnd).p = val; \
} while (0)
+#define __HYPERVISOR_platform_op_raw __HYPERVISOR_platform_op
+
#ifndef __ASSEMBLY__
/* Explicitly size integers that represent pfns in the interface with
* Xen so that we can have one ABI that works for 32 and 64 bit guests.
@@ -76,6 +78,7 @@ struct pvclock_wall_clock {
u32 version;
u32 sec;
u32 nsec;
+ u32 sec_hi;
} __attribute__((__packed__));
#endif
diff --git a/arch/arm/include/debug/at91.S b/arch/arm/include/debug/at91.S
index 2556a88..43243be 100644
--- a/arch/arm/include/debug/at91.S
+++ b/arch/arm/include/debug/at91.S
@@ -9,32 +9,22 @@
*
*/
-#if defined(CONFIG_AT91_DEBUG_LL_DBGU0)
-#define AT91_DBGU 0xfffff200 /* AT91_BASE_DBGU0 */
-#elif defined(CONFIG_AT91_DEBUG_LL_DBGU1)
-#define AT91_DBGU 0xffffee00 /* AT91_BASE_DBGU1 */
-#elif defined(CONFIG_AT91_DEBUG_LL_DBGU2)
-/* On sama5d4, use USART3 as low level serial console */
-#define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */
-#else
-/* On sama5d2, use UART1 as low level serial console */
-#define AT91_DBGU 0xf8020000
-#endif
-
#ifdef CONFIG_MMU
#define AT91_IO_P2V(x) ((x) - 0x01000000)
#else
#define AT91_IO_P2V(x) (x)
#endif
+#define CONFIG_DEBUG_UART_VIRT AT91_IO_P2V(CONFIG_DEBUG_UART_PHYS)
+
#define AT91_DBGU_SR (0x14) /* Status Register */
#define AT91_DBGU_THR (0x1c) /* Transmitter Holding Register */
#define AT91_DBGU_TXRDY (1 << 1) /* Transmitter Ready */
#define AT91_DBGU_TXEMPTY (1 << 9) /* Transmitter Empty */
.macro addruart, rp, rv, tmp
- ldr \rp, =AT91_DBGU @ System peripherals (phys address)
- ldr \rv, =AT91_IO_P2V(AT91_DBGU) @ System peripherals (virt address)
+ ldr \rp, =CONFIG_DEBUG_UART_PHYS @ System peripherals (phys address)
+ ldr \rv, =CONFIG_DEBUG_UART_VIRT @ System peripherals (virt address)
.endm
.macro senduart,rd,rx
diff --git a/arch/arm/include/uapi/asm/unistd.h b/arch/arm/include/uapi/asm/unistd.h
index 7a2a32a1..ede692f 100644
--- a/arch/arm/include/uapi/asm/unistd.h
+++ b/arch/arm/include/uapi/asm/unistd.h
@@ -416,6 +416,7 @@
#define __NR_execveat (__NR_SYSCALL_BASE+387)
#define __NR_userfaultfd (__NR_SYSCALL_BASE+388)
#define __NR_membarrier (__NR_SYSCALL_BASE+389)
+#define __NR_mlock2 (__NR_SYSCALL_BASE+390)
/*
* The following SWIs are ARM private.
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index af9e59b..2c5f160 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -73,14 +73,15 @@ obj-$(CONFIG_IWMMXT) += iwmmxt.o
obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \
perf_event_v7.o
-CFLAGS_pj4-cp0.o := -marm
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
obj-$(CONFIG_VDSO) += vdso.o
+obj-$(CONFIG_EFI) += efi.o
ifneq ($(CONFIG_ARCH_EBSA110),y)
obj-y += io.o
endif
+obj-$(CONFIG_PARAVIRT) += paravirt.o
head-y := head$(MMUEXT).o
obj-$(CONFIG_DEBUG_LL) += debug.o
@@ -88,8 +89,9 @@ obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_ARM_VIRT_EXT) += hyp-stub.o
ifeq ($(CONFIG_ARM_PSCI),y)
-obj-y += psci-call.o
obj-$(CONFIG_SMP) += psci_smp.o
endif
+obj-$(CONFIG_HAVE_ARM_SMCCC) += smccc-call.o
+
extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index f89811f..7e45f69 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -16,6 +16,7 @@
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/arm-smccc.h>
#include <asm/checksum.h>
#include <asm/ftrace.h>
@@ -175,3 +176,8 @@ EXPORT_SYMBOL(__gnu_mcount_nc);
EXPORT_SYMBOL(__pv_phys_pfn_offset);
EXPORT_SYMBOL(__pv_offset);
#endif
+
+#ifdef CONFIG_HAVE_ARM_SMCCC
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
+#endif
diff --git a/arch/arm/kernel/atags.h b/arch/arm/kernel/atags.h
index ec4164d..edfa226 100644
--- a/arch/arm/kernel/atags.h
+++ b/arch/arm/kernel/atags.h
@@ -1,9 +1,3 @@
-#ifdef CONFIG_ATAGS_PROC
-extern void save_atags(struct tag *tags);
-#else
-static inline void save_atags(struct tag *tags) { }
-#endif
-
void convert_to_tag_list(struct tag *tags);
#ifdef CONFIG_ATAGS
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 6551d28..066f7f9 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -17,11 +17,6 @@
#include <asm/mach/pci.h>
static int debug_pci;
-static resource_size_t (*align_resource)(struct pci_dev *dev,
- const struct resource *res,
- resource_size_t start,
- resource_size_t size,
- resource_size_t align) = NULL;
/*
* We can't use pci_get_device() here since we are
@@ -461,7 +456,6 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
sys->busnr = busnr;
sys->swizzle = hw->swizzle;
sys->map_irq = hw->map_irq;
- align_resource = hw->align_resource;
INIT_LIST_HEAD(&sys->resources);
if (hw->private_data)
@@ -470,6 +464,8 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
ret = hw->setup(nr, sys);
if (ret > 0) {
+ struct pci_host_bridge *host_bridge;
+
ret = pcibios_init_resources(nr, sys);
if (ret) {
kfree(sys);
@@ -491,6 +487,9 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
busnr = sys->bus->busn_res.end + 1;
list_add(&sys->node, head);
+
+ host_bridge = pci_find_host_bridge(sys->bus);
+ host_bridge->align_resource = hw->align_resource;
} else {
kfree(sys);
if (ret < 0)
@@ -578,14 +577,18 @@ resource_size_t pcibios_align_resource(void *data, const struct resource *res,
{
struct pci_dev *dev = data;
resource_size_t start = res->start;
+ struct pci_host_bridge *host_bridge;
if (res->flags & IORESOURCE_IO && start & 0x300)
start = (start + 0x3ff) & ~0x3ff;
start = (start + align - 1) & ~(align - 1);
- if (align_resource)
- return align_resource(dev, res, start, size, align);
+ host_bridge = pci_find_host_bridge(dev->bus);
+
+ if (host_bridge->align_resource)
+ return host_bridge->align_resource(dev, res,
+ start, size, align);
return start;
}
diff --git a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
index fde6c88..ac368bb 100644
--- a/arch/arm/kernel/calls.S
+++ b/arch/arm/kernel/calls.S
@@ -399,6 +399,7 @@
CALL(sys_execveat)
CALL(sys_userfaultfd)
CALL(sys_membarrier)
+ CALL(sys_mlock2)
#ifndef syscalls_counted
.equ syscalls_padding, ((NR_syscalls + 3) & ~3) - NR_syscalls
#define syscalls_counted
diff --git a/arch/arm/kernel/cpuidle.c b/arch/arm/kernel/cpuidle.c
index 318da33..703926e 100644
--- a/arch/arm/kernel/cpuidle.c
+++ b/arch/arm/kernel/cpuidle.c
@@ -56,7 +56,7 @@ int arm_cpuidle_suspend(int index)
int cpu = smp_processor_id();
if (cpuidle_ops[cpu].suspend)
- ret = cpuidle_ops[cpu].suspend(cpu, index);
+ ret = cpuidle_ops[cpu].suspend(index);
return ret;
}
diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c
new file mode 100644
index 0000000..ff8a9d8
--- /dev/null
+++ b/arch/arm/kernel/efi.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/efi.h>
+#include <asm/efi.h>
+#include <asm/mach/map.h>
+#include <asm/mmu_context.h>
+
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
+{
+ struct map_desc desc = {
+ .virtual = md->virt_addr,
+ .pfn = __phys_to_pfn(md->phys_addr),
+ .length = md->num_pages * EFI_PAGE_SIZE,
+ };
+
+ /*
+ * Order is important here: memory regions may have all of the
+ * bits below set (and usually do), so we check them in order of
+ * preference.
+ */
+ if (md->attribute & EFI_MEMORY_WB)
+ desc.type = MT_MEMORY_RWX;
+ else if (md->attribute & EFI_MEMORY_WT)
+ desc.type = MT_MEMORY_RWX_NONCACHED;
+ else if (md->attribute & EFI_MEMORY_WC)
+ desc.type = MT_DEVICE_WC;
+ else
+ desc.type = MT_DEVICE;
+
+ create_mapping_late(mm, &desc, true);
+ return 0;
+}
diff --git a/arch/arm/kernel/entry-v7m.S b/arch/arm/kernel/entry-v7m.S
index b6c8bb9..907534f 100644
--- a/arch/arm/kernel/entry-v7m.S
+++ b/arch/arm/kernel/entry-v7m.S
@@ -88,7 +88,7 @@ __pendsv_entry:
@ execute the pending work, including reschedule
get_thread_info tsk
mov why, #0
- b ret_to_user
+ b ret_to_user_from_irq
ENDPROC(__pendsv_entry)
/*
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 2766183..1d45320 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -39,6 +39,7 @@
#include <linux/export.h>
#include <asm/hardware/cache-l2x0.h>
+#include <asm/hardware/cache-uniphier.h>
#include <asm/outercache.h>
#include <asm/exception.h>
#include <asm/mach/arch.h>
@@ -97,6 +98,8 @@ void __init init_IRQ(void)
if (ret)
pr_err("L2C: failed to init: %d\n", ret);
}
+
+ uniphier_cache_init();
}
#ifdef CONFIG_MULTI_IRQ_HANDLER
diff --git a/arch/arm64/kernel/psci-call.S b/arch/arm/kernel/paravirt.c
index cf83e61..53f371e 100644
--- a/arch/arm64/kernel/psci-call.S
+++ b/arch/arm/kernel/paravirt.c
@@ -8,21 +8,18 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * Copyright (C) 2015 ARM Limited
+ * Copyright (C) 2013 Citrix Systems
*
- * Author: Will Deacon <will.deacon@arm.com>
+ * Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
*/
-#include <linux/linkage.h>
+#include <linux/export.h>
+#include <linux/jump_label.h>
+#include <linux/types.h>
+#include <asm/paravirt.h>
-/* int __invoke_psci_fn_hvc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
-ENTRY(__invoke_psci_fn_hvc)
- hvc #0
- ret
-ENDPROC(__invoke_psci_fn_hvc)
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
-/* int __invoke_psci_fn_smc(u64 function_id, u64 arg0, u64 arg1, u64 arg2) */
-ENTRY(__invoke_psci_fn_smc)
- smc #0
- ret
-ENDPROC(__invoke_psci_fn_smc)
+struct pv_time_ops pv_time_ops;
+EXPORT_SYMBOL_GPL(pv_time_ops);
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 126dc67..4152158 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -35,133 +35,117 @@
* but the encodings are considered to be `reserved' in the case that
* they are not available.
*/
-enum armv7_perf_types {
- ARMV7_PERFCTR_PMNC_SW_INCR = 0x00,
- ARMV7_PERFCTR_L1_ICACHE_REFILL = 0x01,
- ARMV7_PERFCTR_ITLB_REFILL = 0x02,
- ARMV7_PERFCTR_L1_DCACHE_REFILL = 0x03,
- ARMV7_PERFCTR_L1_DCACHE_ACCESS = 0x04,
- ARMV7_PERFCTR_DTLB_REFILL = 0x05,
- ARMV7_PERFCTR_MEM_READ = 0x06,
- ARMV7_PERFCTR_MEM_WRITE = 0x07,
- ARMV7_PERFCTR_INSTR_EXECUTED = 0x08,
- ARMV7_PERFCTR_EXC_TAKEN = 0x09,
- ARMV7_PERFCTR_EXC_EXECUTED = 0x0A,
- ARMV7_PERFCTR_CID_WRITE = 0x0B,
+#define ARMV7_PERFCTR_PMNC_SW_INCR 0x00
+#define ARMV7_PERFCTR_L1_ICACHE_REFILL 0x01
+#define ARMV7_PERFCTR_ITLB_REFILL 0x02
+#define ARMV7_PERFCTR_L1_DCACHE_REFILL 0x03
+#define ARMV7_PERFCTR_L1_DCACHE_ACCESS 0x04
+#define ARMV7_PERFCTR_DTLB_REFILL 0x05
+#define ARMV7_PERFCTR_MEM_READ 0x06
+#define ARMV7_PERFCTR_MEM_WRITE 0x07
+#define ARMV7_PERFCTR_INSTR_EXECUTED 0x08
+#define ARMV7_PERFCTR_EXC_TAKEN 0x09
+#define ARMV7_PERFCTR_EXC_EXECUTED 0x0A
+#define ARMV7_PERFCTR_CID_WRITE 0x0B
- /*
- * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
- * It counts:
- * - all (taken) branch instructions,
- * - instructions that explicitly write the PC,
- * - exception generating instructions.
- */
- ARMV7_PERFCTR_PC_WRITE = 0x0C,
- ARMV7_PERFCTR_PC_IMM_BRANCH = 0x0D,
- ARMV7_PERFCTR_PC_PROC_RETURN = 0x0E,
- ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS = 0x0F,
- ARMV7_PERFCTR_PC_BRANCH_MIS_PRED = 0x10,
- ARMV7_PERFCTR_CLOCK_CYCLES = 0x11,
- ARMV7_PERFCTR_PC_BRANCH_PRED = 0x12,
-
- /* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
- ARMV7_PERFCTR_MEM_ACCESS = 0x13,
- ARMV7_PERFCTR_L1_ICACHE_ACCESS = 0x14,
- ARMV7_PERFCTR_L1_DCACHE_WB = 0x15,
- ARMV7_PERFCTR_L2_CACHE_ACCESS = 0x16,
- ARMV7_PERFCTR_L2_CACHE_REFILL = 0x17,
- ARMV7_PERFCTR_L2_CACHE_WB = 0x18,
- ARMV7_PERFCTR_BUS_ACCESS = 0x19,
- ARMV7_PERFCTR_MEM_ERROR = 0x1A,
- ARMV7_PERFCTR_INSTR_SPEC = 0x1B,
- ARMV7_PERFCTR_TTBR_WRITE = 0x1C,
- ARMV7_PERFCTR_BUS_CYCLES = 0x1D,
-
- ARMV7_PERFCTR_CPU_CYCLES = 0xFF
-};
+/*
+ * ARMV7_PERFCTR_PC_WRITE is equivalent to HW_BRANCH_INSTRUCTIONS.
+ * It counts:
+ * - all (taken) branch instructions,
+ * - instructions that explicitly write the PC,
+ * - exception generating instructions.
+ */
+#define ARMV7_PERFCTR_PC_WRITE 0x0C
+#define ARMV7_PERFCTR_PC_IMM_BRANCH 0x0D
+#define ARMV7_PERFCTR_PC_PROC_RETURN 0x0E
+#define ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS 0x0F
+#define ARMV7_PERFCTR_PC_BRANCH_MIS_PRED 0x10
+#define ARMV7_PERFCTR_CLOCK_CYCLES 0x11
+#define ARMV7_PERFCTR_PC_BRANCH_PRED 0x12
+
+/* These events are defined by the PMUv2 supplement (ARM DDI 0457A). */
+#define ARMV7_PERFCTR_MEM_ACCESS 0x13
+#define ARMV7_PERFCTR_L1_ICACHE_ACCESS 0x14
+#define ARMV7_PERFCTR_L1_DCACHE_WB 0x15
+#define ARMV7_PERFCTR_L2_CACHE_ACCESS 0x16
+#define ARMV7_PERFCTR_L2_CACHE_REFILL 0x17
+#define ARMV7_PERFCTR_L2_CACHE_WB 0x18
+#define ARMV7_PERFCTR_BUS_ACCESS 0x19
+#define ARMV7_PERFCTR_MEM_ERROR 0x1A
+#define ARMV7_PERFCTR_INSTR_SPEC 0x1B
+#define ARMV7_PERFCTR_TTBR_WRITE 0x1C
+#define ARMV7_PERFCTR_BUS_CYCLES 0x1D
+
+#define ARMV7_PERFCTR_CPU_CYCLES 0xFF
/* ARMv7 Cortex-A8 specific event types */
-enum armv7_a8_perf_types {
- ARMV7_A8_PERFCTR_L2_CACHE_ACCESS = 0x43,
- ARMV7_A8_PERFCTR_L2_CACHE_REFILL = 0x44,
- ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS = 0x50,
- ARMV7_A8_PERFCTR_STALL_ISIDE = 0x56,
-};
+#define ARMV7_A8_PERFCTR_L2_CACHE_ACCESS 0x43
+#define ARMV7_A8_PERFCTR_L2_CACHE_REFILL 0x44
+#define ARMV7_A8_PERFCTR_L1_ICACHE_ACCESS 0x50
+#define ARMV7_A8_PERFCTR_STALL_ISIDE 0x56
/* ARMv7 Cortex-A9 specific event types */
-enum armv7_a9_perf_types {
- ARMV7_A9_PERFCTR_INSTR_CORE_RENAME = 0x68,
- ARMV7_A9_PERFCTR_STALL_ICACHE = 0x60,
- ARMV7_A9_PERFCTR_STALL_DISPATCH = 0x66,
-};
+#define ARMV7_A9_PERFCTR_INSTR_CORE_RENAME 0x68
+#define ARMV7_A9_PERFCTR_STALL_ICACHE 0x60
+#define ARMV7_A9_PERFCTR_STALL_DISPATCH 0x66
/* ARMv7 Cortex-A5 specific event types */
-enum armv7_a5_perf_types {
- ARMV7_A5_PERFCTR_PREFETCH_LINEFILL = 0xc2,
- ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP = 0xc3,
-};
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL 0xc2
+#define ARMV7_A5_PERFCTR_PREFETCH_LINEFILL_DROP 0xc3
/* ARMv7 Cortex-A15 specific event types */
-enum armv7_a15_perf_types {
- ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ = 0x40,
- ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE = 0x41,
- ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ = 0x42,
- ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE = 0x43,
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_READ 0x40
+#define ARMV7_A15_PERFCTR_L1_DCACHE_ACCESS_WRITE 0x41
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_READ 0x42
+#define ARMV7_A15_PERFCTR_L1_DCACHE_REFILL_WRITE 0x43
- ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ = 0x4C,
- ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE = 0x4D,
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_READ 0x4C
+#define ARMV7_A15_PERFCTR_DTLB_REFILL_L1_WRITE 0x4D
- ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ = 0x50,
- ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE = 0x51,
- ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ = 0x52,
- ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE = 0x53,
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_READ 0x50
+#define ARMV7_A15_PERFCTR_L2_CACHE_ACCESS_WRITE 0x51
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_READ 0x52
+#define ARMV7_A15_PERFCTR_L2_CACHE_REFILL_WRITE 0x53
- ARMV7_A15_PERFCTR_PC_WRITE_SPEC = 0x76,
-};
+#define ARMV7_A15_PERFCTR_PC_WRITE_SPEC 0x76
/* ARMv7 Cortex-A12 specific event types */
-enum armv7_a12_perf_types {
- ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ = 0x40,
- ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE = 0x41,
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_READ 0x40
+#define ARMV7_A12_PERFCTR_L1_DCACHE_ACCESS_WRITE 0x41
- ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ = 0x50,
- ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE = 0x51,
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_READ 0x50
+#define ARMV7_A12_PERFCTR_L2_CACHE_ACCESS_WRITE 0x51
- ARMV7_A12_PERFCTR_PC_WRITE_SPEC = 0x76,
+#define ARMV7_A12_PERFCTR_PC_WRITE_SPEC 0x76
- ARMV7_A12_PERFCTR_PF_TLB_REFILL = 0xe7,
-};
+#define ARMV7_A12_PERFCTR_PF_TLB_REFILL 0xe7
/* ARMv7 Krait specific event types */
-enum krait_perf_types {
- KRAIT_PMRESR0_GROUP0 = 0xcc,
- KRAIT_PMRESR1_GROUP0 = 0xd0,
- KRAIT_PMRESR2_GROUP0 = 0xd4,
- KRAIT_VPMRESR0_GROUP0 = 0xd8,
+#define KRAIT_PMRESR0_GROUP0 0xcc
+#define KRAIT_PMRESR1_GROUP0 0xd0
+#define KRAIT_PMRESR2_GROUP0 0xd4
+#define KRAIT_VPMRESR0_GROUP0 0xd8
- KRAIT_PERFCTR_L1_ICACHE_ACCESS = 0x10011,
- KRAIT_PERFCTR_L1_ICACHE_MISS = 0x10010,
+#define KRAIT_PERFCTR_L1_ICACHE_ACCESS 0x10011
+#define KRAIT_PERFCTR_L1_ICACHE_MISS 0x10010
- KRAIT_PERFCTR_L1_ITLB_ACCESS = 0x12222,
- KRAIT_PERFCTR_L1_DTLB_ACCESS = 0x12210,
-};
+#define KRAIT_PERFCTR_L1_ITLB_ACCESS 0x12222
+#define KRAIT_PERFCTR_L1_DTLB_ACCESS 0x12210
/* ARMv7 Scorpion specific event types */
-enum scorpion_perf_types {
- SCORPION_LPM0_GROUP0 = 0x4c,
- SCORPION_LPM1_GROUP0 = 0x50,
- SCORPION_LPM2_GROUP0 = 0x54,
- SCORPION_L2LPM_GROUP0 = 0x58,
- SCORPION_VLPM_GROUP0 = 0x5c,
+#define SCORPION_LPM0_GROUP0 0x4c
+#define SCORPION_LPM1_GROUP0 0x50
+#define SCORPION_LPM2_GROUP0 0x54
+#define SCORPION_L2LPM_GROUP0 0x58
+#define SCORPION_VLPM_GROUP0 0x5c
- SCORPION_ICACHE_ACCESS = 0x10053,
- SCORPION_ICACHE_MISS = 0x10052,
+#define SCORPION_ICACHE_ACCESS 0x10053
+#define SCORPION_ICACHE_MISS 0x10052
- SCORPION_DTLB_ACCESS = 0x12013,
- SCORPION_DTLB_MISS = 0x12012,
+#define SCORPION_DTLB_ACCESS 0x12013
+#define SCORPION_DTLB_MISS 0x12012
- SCORPION_ITLB_MISS = 0x12021,
-};
+#define SCORPION_ITLB_MISS 0x12021
/*
* Cortex-A8 HW events mapping
@@ -547,6 +531,134 @@ static const unsigned scorpion_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV7_PERFCTR_PC_BRANCH_MIS_PRED,
};
+PMU_FORMAT_ATTR(event, "config:0-7");
+
+static struct attribute *armv7_pmu_format_attrs[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group armv7_pmu_format_attr_group = {
+ .name = "format",
+ .attrs = armv7_pmu_format_attrs,
+};
+
+#define ARMV7_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV7_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_STRING(name, armv7_event_attr_##name, \
+ "event=" ARMV7_EVENT_ATTR_RESOLVE(config))
+
+ARMV7_EVENT_ATTR(sw_incr, ARMV7_PERFCTR_PMNC_SW_INCR);
+ARMV7_EVENT_ATTR(l1i_cache_refill, ARMV7_PERFCTR_L1_ICACHE_REFILL);
+ARMV7_EVENT_ATTR(l1i_tlb_refill, ARMV7_PERFCTR_ITLB_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache_refill, ARMV7_PERFCTR_L1_DCACHE_REFILL);
+ARMV7_EVENT_ATTR(l1d_cache, ARMV7_PERFCTR_L1_DCACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_tlb_refill, ARMV7_PERFCTR_DTLB_REFILL);
+ARMV7_EVENT_ATTR(ld_retired, ARMV7_PERFCTR_MEM_READ);
+ARMV7_EVENT_ATTR(st_retired, ARMV7_PERFCTR_MEM_WRITE);
+ARMV7_EVENT_ATTR(inst_retired, ARMV7_PERFCTR_INSTR_EXECUTED);
+ARMV7_EVENT_ATTR(exc_taken, ARMV7_PERFCTR_EXC_TAKEN);
+ARMV7_EVENT_ATTR(exc_return, ARMV7_PERFCTR_EXC_EXECUTED);
+ARMV7_EVENT_ATTR(cid_write_retired, ARMV7_PERFCTR_CID_WRITE);
+ARMV7_EVENT_ATTR(pc_write_retired, ARMV7_PERFCTR_PC_WRITE);
+ARMV7_EVENT_ATTR(br_immed_retired, ARMV7_PERFCTR_PC_IMM_BRANCH);
+ARMV7_EVENT_ATTR(br_return_retired, ARMV7_PERFCTR_PC_PROC_RETURN);
+ARMV7_EVENT_ATTR(unaligned_ldst_retired, ARMV7_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV7_EVENT_ATTR(br_mis_pred, ARMV7_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV7_EVENT_ATTR(cpu_cycles, ARMV7_PERFCTR_CLOCK_CYCLES);
+ARMV7_EVENT_ATTR(br_pred, ARMV7_PERFCTR_PC_BRANCH_PRED);
+
+static struct attribute *armv7_pmuv1_event_attrs[] = {
+ &armv7_event_attr_sw_incr.attr.attr,
+ &armv7_event_attr_l1i_cache_refill.attr.attr,
+ &armv7_event_attr_l1i_tlb_refill.attr.attr,
+ &armv7_event_attr_l1d_cache_refill.attr.attr,
+ &armv7_event_attr_l1d_cache.attr.attr,
+ &armv7_event_attr_l1d_tlb_refill.attr.attr,
+ &armv7_event_attr_ld_retired.attr.attr,
+ &armv7_event_attr_st_retired.attr.attr,
+ &armv7_event_attr_inst_retired.attr.attr,
+ &armv7_event_attr_exc_taken.attr.attr,
+ &armv7_event_attr_exc_return.attr.attr,
+ &armv7_event_attr_cid_write_retired.attr.attr,
+ &armv7_event_attr_pc_write_retired.attr.attr,
+ &armv7_event_attr_br_immed_retired.attr.attr,
+ &armv7_event_attr_br_return_retired.attr.attr,
+ &armv7_event_attr_unaligned_ldst_retired.attr.attr,
+ &armv7_event_attr_br_mis_pred.attr.attr,
+ &armv7_event_attr_cpu_cycles.attr.attr,
+ &armv7_event_attr_br_pred.attr.attr,
+ NULL,
+};
+
+static struct attribute_group armv7_pmuv1_events_attr_group = {
+ .name = "events",
+ .attrs = armv7_pmuv1_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv1_attr_groups[] = {
+ &armv7_pmuv1_events_attr_group,
+ &armv7_pmu_format_attr_group,
+ NULL,
+};
+
+ARMV7_EVENT_ATTR(mem_access, ARMV7_PERFCTR_MEM_ACCESS);
+ARMV7_EVENT_ATTR(l1i_cache, ARMV7_PERFCTR_L1_ICACHE_ACCESS);
+ARMV7_EVENT_ATTR(l1d_cache_wb, ARMV7_PERFCTR_L1_DCACHE_WB);
+ARMV7_EVENT_ATTR(l2d_cache, ARMV7_PERFCTR_L2_CACHE_ACCESS);
+ARMV7_EVENT_ATTR(l2d_cache_refill, ARMV7_PERFCTR_L2_CACHE_REFILL);
+ARMV7_EVENT_ATTR(l2d_cache_wb, ARMV7_PERFCTR_L2_CACHE_WB);
+ARMV7_EVENT_ATTR(bus_access, ARMV7_PERFCTR_BUS_ACCESS);
+ARMV7_EVENT_ATTR(memory_error, ARMV7_PERFCTR_MEM_ERROR);
+ARMV7_EVENT_ATTR(inst_spec, ARMV7_PERFCTR_INSTR_SPEC);
+ARMV7_EVENT_ATTR(ttbr_write_retired, ARMV7_PERFCTR_TTBR_WRITE);
+ARMV7_EVENT_ATTR(bus_cycles, ARMV7_PERFCTR_BUS_CYCLES);
+
+static struct attribute *armv7_pmuv2_event_attrs[] = {
+ &armv7_event_attr_sw_incr.attr.attr,
+ &armv7_event_attr_l1i_cache_refill.attr.attr,
+ &armv7_event_attr_l1i_tlb_refill.attr.attr,
+ &armv7_event_attr_l1d_cache_refill.attr.attr,
+ &armv7_event_attr_l1d_cache.attr.attr,
+ &armv7_event_attr_l1d_tlb_refill.attr.attr,
+ &armv7_event_attr_ld_retired.attr.attr,
+ &armv7_event_attr_st_retired.attr.attr,
+ &armv7_event_attr_inst_retired.attr.attr,
+ &armv7_event_attr_exc_taken.attr.attr,
+ &armv7_event_attr_exc_return.attr.attr,
+ &armv7_event_attr_cid_write_retired.attr.attr,
+ &armv7_event_attr_pc_write_retired.attr.attr,
+ &armv7_event_attr_br_immed_retired.attr.attr,
+ &armv7_event_attr_br_return_retired.attr.attr,
+ &armv7_event_attr_unaligned_ldst_retired.attr.attr,
+ &armv7_event_attr_br_mis_pred.attr.attr,
+ &armv7_event_attr_cpu_cycles.attr.attr,
+ &armv7_event_attr_br_pred.attr.attr,
+ &armv7_event_attr_mem_access.attr.attr,
+ &armv7_event_attr_l1i_cache.attr.attr,
+ &armv7_event_attr_l1d_cache_wb.attr.attr,
+ &armv7_event_attr_l2d_cache.attr.attr,
+ &armv7_event_attr_l2d_cache_refill.attr.attr,
+ &armv7_event_attr_l2d_cache_wb.attr.attr,
+ &armv7_event_attr_bus_access.attr.attr,
+ &armv7_event_attr_memory_error.attr.attr,
+ &armv7_event_attr_inst_spec.attr.attr,
+ &armv7_event_attr_ttbr_write_retired.attr.attr,
+ &armv7_event_attr_bus_cycles.attr.attr,
+ NULL,
+};
+
+static struct attribute_group armv7_pmuv2_events_attr_group = {
+ .name = "events",
+ .attrs = armv7_pmuv2_event_attrs,
+};
+
+static const struct attribute_group *armv7_pmuv2_attr_groups[] = {
+ &armv7_pmuv2_events_attr_group,
+ &armv7_pmu_format_attr_group,
+ NULL,
+};
+
/*
* Perf Events' indices
*/
@@ -1085,6 +1197,7 @@ static int armv7_a8_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a8";
cpu_pmu->map_event = armv7_a8_map_event;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1093,6 +1206,7 @@ static int armv7_a9_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a9";
cpu_pmu->map_event = armv7_a9_map_event;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1101,6 +1215,7 @@ static int armv7_a5_pmu_init(struct arm_pmu *cpu_pmu)
armv7pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a5";
cpu_pmu->map_event = armv7_a5_map_event;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv1_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1110,6 +1225,7 @@ static int armv7_a15_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->name = "armv7_cortex_a15";
cpu_pmu->map_event = armv7_a15_map_event;
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1119,6 +1235,7 @@ static int armv7_a7_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->name = "armv7_cortex_a7";
cpu_pmu->map_event = armv7_a7_map_event;
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1128,6 +1245,7 @@ static int armv7_a12_pmu_init(struct arm_pmu *cpu_pmu)
cpu_pmu->name = "armv7_cortex_a12";
cpu_pmu->map_event = armv7_a12_map_event;
cpu_pmu->set_event_filter = armv7pmu_set_event_filter;
+ cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
return armv7_probe_num_events(cpu_pmu);
}
@@ -1135,6 +1253,7 @@ static int armv7_a17_pmu_init(struct arm_pmu *cpu_pmu)
{
int ret = armv7_a12_pmu_init(cpu_pmu);
cpu_pmu->name = "armv7_cortex_a17";
+ cpu_pmu->pmu.attr_groups = armv7_pmuv2_attr_groups;
return ret;
}
diff --git a/arch/arm/kernel/pj4-cp0.c b/arch/arm/kernel/pj4-cp0.c
index 8153e36..7c9248b 100644
--- a/arch/arm/kernel/pj4-cp0.c
+++ b/arch/arm/kernel/pj4-cp0.c
@@ -66,9 +66,13 @@ static void __init pj4_cp_access_write(u32 value)
__asm__ __volatile__ (
"mcr p15, 0, %1, c1, c0, 2\n\t"
+#ifdef CONFIG_THUMB2_KERNEL
+ "isb\n\t"
+#else
"mrc p15, 0, %0, c1, c0, 2\n\t"
"mov %0, %0\n\t"
"sub pc, pc, #4\n\t"
+#endif
: "=r" (temp) : "r" (value));
}
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 7a7c4ce..4adfb46 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -95,6 +95,22 @@ void __show_regs(struct pt_regs *regs)
{
unsigned long flags;
char buf[64];
+#ifndef CONFIG_CPU_V7M
+ unsigned int domain;
+#ifdef CONFIG_CPU_SW_DOMAIN_PAN
+ /*
+ * Get the domain register for the parent context. In user
+ * mode, we don't save the DACR, so lets use what it should
+ * be. For other modes, we place it after the pt_regs struct.
+ */
+ if (user_mode(regs))
+ domain = DACR_UACCESS_ENABLE;
+ else
+ domain = *(unsigned int *)(regs + 1);
+#else
+ domain = get_domain();
+#endif
+#endif
show_regs_print_info(KERN_DEFAULT);
@@ -123,21 +139,8 @@ void __show_regs(struct pt_regs *regs)
#ifndef CONFIG_CPU_V7M
{
- unsigned int domain = get_domain();
const char *segment;
-#ifdef CONFIG_CPU_SW_DOMAIN_PAN
- /*
- * Get the domain register for the parent context. In user
- * mode, we don't save the DACR, so lets use what it should
- * be. For other modes, we place it after the pt_regs struct.
- */
- if (user_mode(regs))
- domain = DACR_UACCESS_ENABLE;
- else
- domain = *(unsigned int *)(regs + 1);
-#endif
-
if ((domain & domain_mask(DOMAIN_USER)) ==
domain_val(DOMAIN_USER, DOMAIN_NOACCESS))
segment = "none";
@@ -163,11 +166,11 @@ void __show_regs(struct pt_regs *regs)
buf[0] = '\0';
#ifdef CONFIG_CPU_CP15_MMU
{
- unsigned int transbase, dac = get_domain();
+ unsigned int transbase;
asm("mrc p15, 0, %0, c2, c0\n\t"
: "=r" (transbase));
snprintf(buf, sizeof(buf), " Table: %08x DAC: %08x",
- transbase, dac);
+ transbase, domain);
}
#endif
asm("mrc p15, 0, %0, c1, c0\n" : "=r" (ctrl));
diff --git a/arch/arm/kernel/psci_smp.c b/arch/arm/kernel/psci_smp.c
index 61c04b0..9d479b2 100644
--- a/arch/arm/kernel/psci_smp.c
+++ b/arch/arm/kernel/psci_smp.c
@@ -71,7 +71,7 @@ int psci_cpu_disable(unsigned int cpu)
return 0;
}
-void __ref psci_cpu_die(unsigned int cpu)
+void psci_cpu_die(unsigned int cpu)
{
u32 state = PSCI_POWER_STATE_TYPE_POWER_DOWN <<
PSCI_0_2_POWER_STATE_TYPE_SHIFT;
@@ -83,7 +83,7 @@ void __ref psci_cpu_die(unsigned int cpu)
panic("psci: cpu %d failed to shutdown\n", cpu);
}
-int __ref psci_cpu_kill(unsigned int cpu)
+int psci_cpu_kill(unsigned int cpu)
{
int err, i;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 20edd34..7d0cba6f 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -7,6 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/efi.h>
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
@@ -37,7 +38,9 @@
#include <asm/cp15.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/efi.h>
#include <asm/elf.h>
+#include <asm/early_ioremap.h>
#include <asm/fixmap.h>
#include <asm/procinfo.h>
#include <asm/psci.h>
@@ -375,6 +378,72 @@ void __init early_print(const char *str, ...)
printk("%s", buf);
}
+#ifdef CONFIG_ARM_PATCH_IDIV
+
+static inline u32 __attribute_const__ sdiv_instruction(void)
+{
+ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ /* "sdiv r0, r0, r1" */
+ u32 insn = __opcode_thumb32_compose(0xfb90, 0xf0f1);
+ return __opcode_to_mem_thumb32(insn);
+ }
+
+ /* "sdiv r0, r0, r1" */
+ return __opcode_to_mem_arm(0xe710f110);
+}
+
+static inline u32 __attribute_const__ udiv_instruction(void)
+{
+ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ /* "udiv r0, r0, r1" */
+ u32 insn = __opcode_thumb32_compose(0xfbb0, 0xf0f1);
+ return __opcode_to_mem_thumb32(insn);
+ }
+
+ /* "udiv r0, r0, r1" */
+ return __opcode_to_mem_arm(0xe730f110);
+}
+
+static inline u32 __attribute_const__ bx_lr_instruction(void)
+{
+ if (IS_ENABLED(CONFIG_THUMB2_KERNEL)) {
+ /* "bx lr; nop" */
+ u32 insn = __opcode_thumb32_compose(0x4770, 0x46c0);
+ return __opcode_to_mem_thumb32(insn);
+ }
+
+ /* "bx lr" */
+ return __opcode_to_mem_arm(0xe12fff1e);
+}
+
+static void __init patch_aeabi_idiv(void)
+{
+ extern void __aeabi_uidiv(void);
+ extern void __aeabi_idiv(void);
+ uintptr_t fn_addr;
+ unsigned int mask;
+
+ mask = IS_ENABLED(CONFIG_THUMB2_KERNEL) ? HWCAP_IDIVT : HWCAP_IDIVA;
+ if (!(elf_hwcap & mask))
+ return;
+
+ pr_info("CPU: div instructions available: patching division code\n");
+
+ fn_addr = ((uintptr_t)&__aeabi_uidiv) & ~1;
+ ((u32 *)fn_addr)[0] = udiv_instruction();
+ ((u32 *)fn_addr)[1] = bx_lr_instruction();
+ flush_icache_range(fn_addr, fn_addr + 8);
+
+ fn_addr = ((uintptr_t)&__aeabi_idiv) & ~1;
+ ((u32 *)fn_addr)[0] = sdiv_instruction();
+ ((u32 *)fn_addr)[1] = bx_lr_instruction();
+ flush_icache_range(fn_addr, fn_addr + 8);
+}
+
+#else
+static inline void patch_aeabi_idiv(void) { }
+#endif
+
static void __init cpuid_init_hwcaps(void)
{
int block;
@@ -642,6 +711,7 @@ static void __init setup_processor(void)
elf_hwcap = list->elf_hwcap;
cpuid_init_hwcaps();
+ patch_aeabi_idiv();
#ifndef CONFIG_ARM_THUMB
elf_hwcap &= ~(HWCAP_THUMB | HWCAP_IDIVT);
@@ -956,8 +1026,8 @@ void __init setup_arch(char **cmdline_p)
strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);
*cmdline_p = cmd_line;
- if (IS_ENABLED(CONFIG_FIX_EARLYCON_MEM))
- early_fixmap_init();
+ early_fixmap_init();
+ early_ioremap_init();
parse_early_param();
@@ -965,9 +1035,12 @@ void __init setup_arch(char **cmdline_p)
early_paging_init(mdesc);
#endif
setup_dma_zone(mdesc);
+ efi_init();
sanity_check_meminfo();
arm_memblock_init(mdesc);
+ early_ioremap_reset();
+
paging_init(mdesc);
request_standard_resources(mdesc);
diff --git a/arch/arm/kernel/smccc-call.S b/arch/arm/kernel/smccc-call.S
new file mode 100644
index 0000000..2e48b67
--- /dev/null
+++ b/arch/arm/kernel/smccc-call.S
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+
+#include <asm/opcodes-sec.h>
+#include <asm/opcodes-virt.h>
+#include <asm/unwind.h>
+
+ /*
+ * Wrap c macros in asm macros to delay expansion until after the
+ * SMCCC asm macro is expanded.
+ */
+ .macro SMCCC_SMC
+ __SMC(0)
+ .endm
+
+ .macro SMCCC_HVC
+ __HVC(0)
+ .endm
+
+ .macro SMCCC instr
+UNWIND( .fnstart)
+ mov r12, sp
+ push {r4-r7}
+UNWIND( .save {r4-r7})
+ ldm r12, {r4-r7}
+ \instr
+ pop {r4-r7}
+ ldr r12, [sp, #(4 * 4)]
+ stm r12, {r0-r3}
+ bx lr
+UNWIND( .fnend)
+ .endm
+
+/*
+ * void smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+ SMCCC SMCCC_SMC
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+ SMCCC SMCCC_HVC
+ENDPROC(arm_smccc_hvc)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index b263613..37312f6 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -69,11 +69,15 @@ enum ipi_msg_type {
IPI_TIMER,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
- IPI_CALL_FUNC_SINGLE,
IPI_CPU_STOP,
IPI_IRQ_WORK,
IPI_COMPLETION,
- IPI_CPU_BACKTRACE = 15,
+ IPI_CPU_BACKTRACE,
+ /*
+ * SGI8-15 can be reserved by secure firmware, and thus may
+ * not be usable by the kernel. Please keep the above limited
+ * to at most 8 entries.
+ */
};
static DECLARE_COMPLETION(cpu_running);
@@ -475,7 +479,6 @@ static const char *ipi_types[NR_IPI] __tracepoint_string = {
S(IPI_TIMER, "Timer broadcast interrupts"),
S(IPI_RESCHEDULE, "Rescheduling interrupts"),
S(IPI_CALL_FUNC, "Function call interrupts"),
- S(IPI_CALL_FUNC_SINGLE, "Single function call interrupts"),
S(IPI_CPU_STOP, "CPU stop interrupts"),
S(IPI_IRQ_WORK, "IRQ work interrupts"),
S(IPI_COMPLETION, "completion interrupts"),
@@ -525,7 +528,7 @@ void arch_send_wakeup_ipi_mask(const struct cpumask *mask)
void arch_send_call_function_single_ipi(int cpu)
{
- smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC_SINGLE);
+ smp_cross_call(cpumask_of(cpu), IPI_CALL_FUNC);
}
#ifdef CONFIG_IRQ_WORK
@@ -620,12 +623,6 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
irq_exit();
break;
- case IPI_CALL_FUNC_SINGLE:
- irq_enter();
- generic_smp_call_function_single_interrupt();
- irq_exit();
- break;
-
case IPI_CPU_STOP:
irq_enter();
ipi_cpu_stop(cpu);
diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c
index 5b26e7e..c3fe769d 100644
--- a/arch/arm/kernel/swp_emulate.c
+++ b/arch/arm/kernel/swp_emulate.c
@@ -36,10 +36,10 @@
*/
#define __user_swpX_asm(data, addr, res, temp, B) \
__asm__ __volatile__( \
- " mov %2, %1\n" \
- "0: ldrex"B" %1, [%3]\n" \
- "1: strex"B" %0, %2, [%3]\n" \
+ "0: ldrex"B" %2, [%3]\n" \
+ "1: strex"B" %0, %1, [%3]\n" \
" cmp %0, #0\n" \
+ " moveq %1, %2\n" \
" movne %0, %4\n" \
"2:\n" \
" .section .text.fixup,\"ax\"\n" \
diff --git a/arch/arm/kernel/sys_oabi-compat.c b/arch/arm/kernel/sys_oabi-compat.c
index b83f3b7..087acb5 100644
--- a/arch/arm/kernel/sys_oabi-compat.c
+++ b/arch/arm/kernel/sys_oabi-compat.c
@@ -193,15 +193,44 @@ struct oabi_flock64 {
pid_t l_pid;
} __attribute__ ((packed,aligned(4)));
-asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+static long do_locks(unsigned int fd, unsigned int cmd,
unsigned long arg)
{
- struct oabi_flock64 user;
struct flock64 kernel;
- mm_segment_t fs = USER_DS; /* initialized to kill a warning */
- unsigned long local_arg = arg;
- int ret;
+ struct oabi_flock64 user;
+ mm_segment_t fs;
+ long ret;
+
+ if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
+ sizeof(user)))
+ return -EFAULT;
+ kernel.l_type = user.l_type;
+ kernel.l_whence = user.l_whence;
+ kernel.l_start = user.l_start;
+ kernel.l_len = user.l_len;
+ kernel.l_pid = user.l_pid;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = sys_fcntl64(fd, cmd, (unsigned long)&kernel);
+ set_fs(fs);
+
+ if (!ret && (cmd == F_GETLK64 || cmd == F_OFD_GETLK)) {
+ user.l_type = kernel.l_type;
+ user.l_whence = kernel.l_whence;
+ user.l_start = kernel.l_start;
+ user.l_len = kernel.l_len;
+ user.l_pid = kernel.l_pid;
+ if (copy_to_user((struct oabi_flock64 __user *)arg,
+ &user, sizeof(user)))
+ ret = -EFAULT;
+ }
+ return ret;
+}
+asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
+ unsigned long arg)
+{
switch (cmd) {
case F_OFD_GETLK:
case F_OFD_SETLK:
@@ -209,39 +238,11 @@ asmlinkage long sys_oabi_fcntl64(unsigned int fd, unsigned int cmd,
case F_GETLK64:
case F_SETLK64:
case F_SETLKW64:
- if (copy_from_user(&user, (struct oabi_flock64 __user *)arg,
- sizeof(user)))
- return -EFAULT;
- kernel.l_type = user.l_type;
- kernel.l_whence = user.l_whence;
- kernel.l_start = user.l_start;
- kernel.l_len = user.l_len;
- kernel.l_pid = user.l_pid;
- local_arg = (unsigned long)&kernel;
- fs = get_fs();
- set_fs(KERNEL_DS);
- }
-
- ret = sys_fcntl64(fd, cmd, local_arg);
+ return do_locks(fd, cmd, arg);
- switch (cmd) {
- case F_GETLK64:
- if (!ret) {
- user.l_type = kernel.l_type;
- user.l_whence = kernel.l_whence;
- user.l_start = kernel.l_start;
- user.l_len = kernel.l_len;
- user.l_pid = kernel.l_pid;
- if (copy_to_user((struct oabi_flock64 __user *)arg,
- &user, sizeof(user)))
- ret = -EFAULT;
- }
- case F_SETLK64:
- case F_SETLKW64:
- set_fs(fs);
+ default:
+ return sys_fcntl64(fd, cmd, arg);
}
-
- return ret;
}
struct oabi_epoll_event {
diff --git a/arch/arm/kernel/vdso.c b/arch/arm/kernel/vdso.c
index 54a5aea..994e971 100644
--- a/arch/arm/kernel/vdso.c
+++ b/arch/arm/kernel/vdso.c
@@ -224,7 +224,7 @@ static int install_vvar(struct mm_struct *mm, unsigned long addr)
VM_READ | VM_MAYREAD,
&vdso_data_mapping);
- return IS_ERR(vma) ? PTR_ERR(vma) : 0;
+ return PTR_ERR_OR_ZERO(vma);
}
/* assumes mmap_sem is write-locked */
diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c
index eab83b2..dda1959 100644
--- a/arch/arm/kvm/arm.c
+++ b/arch/arm/kvm/arm.c
@@ -44,6 +44,7 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_psci.h>
+#include <asm/sections.h>
#ifdef REQUIRES_VIRT
__asm__(".arch_extension virt");
@@ -58,9 +59,12 @@ static DEFINE_PER_CPU(struct kvm_vcpu *, kvm_arm_running_vcpu);
/* The VMID used in the VTTBR */
static atomic64_t kvm_vmid_gen = ATOMIC64_INIT(1);
-static u8 kvm_next_vmid;
+static u32 kvm_next_vmid;
+static unsigned int kvm_vmid_bits __read_mostly;
static DEFINE_SPINLOCK(kvm_vmid_lock);
+static bool vgic_present;
+
static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu)
{
BUG_ON(preemptible());
@@ -132,7 +136,8 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.vmid_gen = 0;
/* The maximum number of VCPUs is limited by the host's GIC model */
- kvm->arch.max_vcpus = kvm_vgic_get_max_vcpus();
+ kvm->arch.max_vcpus = vgic_present ?
+ kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
return ret;
out_free_stage2_pgd:
@@ -172,6 +177,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
int r;
switch (ext) {
case KVM_CAP_IRQCHIP:
+ r = vgic_present;
+ break;
case KVM_CAP_IOEVENTFD:
case KVM_CAP_DEVICE_CTRL:
case KVM_CAP_USER_MEMORY:
@@ -433,11 +440,12 @@ static void update_vttbr(struct kvm *kvm)
kvm->arch.vmid_gen = atomic64_read(&kvm_vmid_gen);
kvm->arch.vmid = kvm_next_vmid;
kvm_next_vmid++;
+ kvm_next_vmid &= (1 << kvm_vmid_bits) - 1;
/* update vttbr to be used with the new vmid */
pgd_phys = virt_to_phys(kvm_get_hwpgd(kvm));
BUG_ON(pgd_phys & ~VTTBR_BADDR_MASK);
- vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK;
+ vmid = ((u64)(kvm->arch.vmid) << VTTBR_VMID_SHIFT) & VTTBR_VMID_MASK(kvm_vmid_bits);
kvm->arch.vttbr = pgd_phys | vmid;
spin_unlock(&kvm_vmid_lock);
@@ -564,17 +572,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
vcpu_sleep(vcpu);
/*
- * Disarming the background timer must be done in a
- * preemptible context, as this call may sleep.
- */
- kvm_timer_flush_hwstate(vcpu);
-
- /*
* Preparing the interrupts to be injected also
* involves poking the GIC, which must be done in a
* non-preemptible context.
*/
preempt_disable();
+ kvm_timer_flush_hwstate(vcpu);
kvm_vgic_flush_hwstate(vcpu);
local_irq_disable();
@@ -608,6 +611,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
ret = kvm_call_hyp(__kvm_vcpu_run, vcpu);
vcpu->mode = OUTSIDE_GUEST_MODE;
+ vcpu->stat.exits++;
/*
* Back from guest
*************************************************************/
@@ -918,6 +922,8 @@ static int kvm_vm_ioctl_set_device_addr(struct kvm *kvm,
switch (dev_id) {
case KVM_ARM_DEVICE_VGIC_V2:
+ if (!vgic_present)
+ return -ENXIO;
return kvm_vgic_addr(kvm, type, &dev_addr->addr, true);
default:
return -ENODEV;
@@ -932,6 +938,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
switch (ioctl) {
case KVM_CREATE_IRQCHIP: {
+ if (!vgic_present)
+ return -ENXIO;
return kvm_vgic_create(kvm, KVM_DEV_TYPE_ARM_VGIC_V2);
}
case KVM_ARM_SET_DEVICE_ADDR: {
@@ -1072,6 +1080,12 @@ static int init_hyp_mode(void)
goto out_free_mappings;
}
+ err = create_hyp_mappings(__start_rodata, __end_rodata);
+ if (err) {
+ kvm_err("Cannot map rodata section\n");
+ goto out_free_mappings;
+ }
+
/*
* Map the Hyp stack pages
*/
@@ -1116,8 +1130,17 @@ static int init_hyp_mode(void)
* Init HYP view of VGIC
*/
err = kvm_vgic_hyp_init();
- if (err)
+ switch (err) {
+ case 0:
+ vgic_present = true;
+ break;
+ case -ENODEV:
+ case -ENXIO:
+ vgic_present = false;
+ break;
+ default:
goto out_free_context;
+ }
/*
* Init HYP architected timer support
@@ -1132,6 +1155,10 @@ static int init_hyp_mode(void)
kvm_perf_init();
+ /* set size of VMID supported by CPU */
+ kvm_vmid_bits = kvm_get_vmid_bits();
+ kvm_info("%d-bit VMID\n", kvm_vmid_bits);
+
kvm_info("Hyp mode initialized successfully\n");
return 0;
diff --git a/arch/arm/kvm/emulate.c b/arch/arm/kvm/emulate.c
index d6c0052..dc99159 100644
--- a/arch/arm/kvm/emulate.c
+++ b/arch/arm/kvm/emulate.c
@@ -275,6 +275,40 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
return vbar;
}
+/*
+ * Switch to an exception mode, updating both CPSR and SPSR. Follow
+ * the logic described in AArch32.EnterMode() from the ARMv8 ARM.
+ */
+static void kvm_update_psr(struct kvm_vcpu *vcpu, unsigned long mode)
+{
+ unsigned long cpsr = *vcpu_cpsr(vcpu);
+ u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
+
+ *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | mode;
+
+ switch (mode) {
+ case FIQ_MODE:
+ *vcpu_cpsr(vcpu) |= PSR_F_BIT;
+ /* Fall through */
+ case ABT_MODE:
+ case IRQ_MODE:
+ *vcpu_cpsr(vcpu) |= PSR_A_BIT;
+ /* Fall through */
+ default:
+ *vcpu_cpsr(vcpu) |= PSR_I_BIT;
+ }
+
+ *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
+
+ if (sctlr & SCTLR_TE)
+ *vcpu_cpsr(vcpu) |= PSR_T_BIT;
+ if (sctlr & SCTLR_EE)
+ *vcpu_cpsr(vcpu) |= PSR_E_BIT;
+
+ /* Note: These now point to the mode banked copies */
+ *vcpu_spsr(vcpu) = cpsr;
+}
+
/**
* kvm_inject_undefined - inject an undefined exception into the guest
* @vcpu: The VCPU to receive the undefined exception
@@ -286,29 +320,13 @@ static u32 exc_vector_base(struct kvm_vcpu *vcpu)
*/
void kvm_inject_undefined(struct kvm_vcpu *vcpu)
{
- unsigned long new_lr_value;
- unsigned long new_spsr_value;
unsigned long cpsr = *vcpu_cpsr(vcpu);
- u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
bool is_thumb = (cpsr & PSR_T_BIT);
u32 vect_offset = 4;
u32 return_offset = (is_thumb) ? 2 : 4;
- new_spsr_value = cpsr;
- new_lr_value = *vcpu_pc(vcpu) - return_offset;
-
- *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | UND_MODE;
- *vcpu_cpsr(vcpu) |= PSR_I_BIT;
- *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
- if (sctlr & SCTLR_TE)
- *vcpu_cpsr(vcpu) |= PSR_T_BIT;
- if (sctlr & SCTLR_EE)
- *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
- /* Note: These now point to UND banked copies */
- *vcpu_spsr(vcpu) = cpsr;
- *vcpu_reg(vcpu, 14) = new_lr_value;
+ kvm_update_psr(vcpu, UND_MODE);
+ *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset;
/* Branch to exception vector */
*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
@@ -320,30 +338,14 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
*/
static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
{
- unsigned long new_lr_value;
- unsigned long new_spsr_value;
unsigned long cpsr = *vcpu_cpsr(vcpu);
- u32 sctlr = vcpu->arch.cp15[c1_SCTLR];
bool is_thumb = (cpsr & PSR_T_BIT);
u32 vect_offset;
u32 return_offset = (is_thumb) ? 4 : 0;
bool is_lpae;
- new_spsr_value = cpsr;
- new_lr_value = *vcpu_pc(vcpu) + return_offset;
-
- *vcpu_cpsr(vcpu) = (cpsr & ~MODE_MASK) | ABT_MODE;
- *vcpu_cpsr(vcpu) |= PSR_I_BIT | PSR_A_BIT;
- *vcpu_cpsr(vcpu) &= ~(PSR_IT_MASK | PSR_J_BIT | PSR_E_BIT | PSR_T_BIT);
-
- if (sctlr & SCTLR_TE)
- *vcpu_cpsr(vcpu) |= PSR_T_BIT;
- if (sctlr & SCTLR_EE)
- *vcpu_cpsr(vcpu) |= PSR_E_BIT;
-
- /* Note: These now point to ABT banked copies */
- *vcpu_spsr(vcpu) = cpsr;
- *vcpu_reg(vcpu, 14) = new_lr_value;
+ kvm_update_psr(vcpu, ABT_MODE);
+ *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
if (is_pabt)
vect_offset = 12;
diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
index 96e935b..5fa69d7 100644
--- a/arch/arm/kvm/guest.c
+++ b/arch/arm/kvm/guest.c
@@ -33,6 +33,12 @@
#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
struct kvm_stats_debugfs_item debugfs_entries[] = {
+ VCPU_STAT(hvc_exit_stat),
+ VCPU_STAT(wfe_exit_stat),
+ VCPU_STAT(wfi_exit_stat),
+ VCPU_STAT(mmio_exit_user),
+ VCPU_STAT(mmio_exit_kernel),
+ VCPU_STAT(exits),
{ NULL }
};
diff --git a/arch/arm/kvm/handle_exit.c b/arch/arm/kvm/handle_exit.c
index 95f12b2..3ede90d 100644
--- a/arch/arm/kvm/handle_exit.c
+++ b/arch/arm/kvm/handle_exit.c
@@ -42,6 +42,7 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
trace_kvm_hvc(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
kvm_vcpu_hvc_get_imm(vcpu));
+ vcpu->stat.hvc_exit_stat++;
ret = kvm_psci_call(vcpu);
if (ret < 0) {
@@ -89,9 +90,11 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
if (kvm_vcpu_get_hsr(vcpu) & HSR_WFI_IS_WFE) {
trace_kvm_wfx(*vcpu_pc(vcpu), true);
+ vcpu->stat.wfe_exit_stat++;
kvm_vcpu_on_spin(vcpu);
} else {
trace_kvm_wfx(*vcpu_pc(vcpu), false);
+ vcpu->stat.wfi_exit_stat++;
kvm_vcpu_block(vcpu);
}
diff --git a/arch/arm/kvm/mmio.c b/arch/arm/kvm/mmio.c
index 974b1c6..7f33b20 100644
--- a/arch/arm/kvm/mmio.c
+++ b/arch/arm/kvm/mmio.c
@@ -115,7 +115,7 @@ int kvm_handle_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run)
trace_kvm_mmio(KVM_TRACE_MMIO_READ, len, run->mmio.phys_addr,
data);
data = vcpu_data_host_to_guest(vcpu, data, len);
- *vcpu_reg(vcpu, vcpu->arch.mmio_decode.rt) = data;
+ vcpu_set_reg(vcpu, vcpu->arch.mmio_decode.rt, data);
}
return 0;
@@ -186,7 +186,8 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
rt = vcpu->arch.mmio_decode.rt;
if (is_write) {
- data = vcpu_data_guest_to_host(vcpu, *vcpu_reg(vcpu, rt), len);
+ data = vcpu_data_guest_to_host(vcpu, vcpu_get_reg(vcpu, rt),
+ len);
trace_kvm_mmio(KVM_TRACE_MMIO_WRITE, len, fault_ipa, data);
mmio_write_buf(data_buf, len, data);
@@ -209,8 +210,11 @@ int io_mem_abort(struct kvm_vcpu *vcpu, struct kvm_run *run,
if (!ret) {
/* We handled the access successfully in the kernel. */
+ vcpu->stat.mmio_exit_kernel++;
kvm_handle_mmio_return(vcpu, run);
return 1;
+ } else {
+ vcpu->stat.mmio_exit_user++;
}
run->exit_reason = KVM_EXIT_MMIO;
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 6984342..22f7fa0 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -98,6 +98,11 @@ static void kvm_flush_dcache_pud(pud_t pud)
__kvm_flush_dcache_pud(pud);
}
+static bool kvm_is_device_pfn(unsigned long pfn)
+{
+ return !pfn_valid(pfn);
+}
+
/**
* stage2_dissolve_pmd() - clear and flush huge PMD entry
* @kvm: pointer to kvm structure.
@@ -213,7 +218,7 @@ static void unmap_ptes(struct kvm *kvm, pmd_t *pmd,
kvm_tlb_flush_vmid_ipa(kvm, addr);
/* No need to invalidate the cache for device mappings */
- if ((pte_val(old_pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+ if (!kvm_is_device_pfn(pte_pfn(old_pte)))
kvm_flush_dcache_pte(old_pte);
put_page(virt_to_page(pte));
@@ -305,8 +310,7 @@ static void stage2_flush_ptes(struct kvm *kvm, pmd_t *pmd,
pte = pte_offset_kernel(pmd, addr);
do {
- if (!pte_none(*pte) &&
- (pte_val(*pte) & PAGE_S2_DEVICE) != PAGE_S2_DEVICE)
+ if (!pte_none(*pte) && !kvm_is_device_pfn(pte_pfn(*pte)))
kvm_flush_dcache_pte(*pte);
} while (pte++, addr += PAGE_SIZE, addr != end);
}
@@ -652,9 +656,9 @@ static void *kvm_alloc_hwpgd(void)
* kvm_alloc_stage2_pgd - allocate level-1 table for stage-2 translation.
* @kvm: The KVM struct pointer for the VM.
*
- * Allocates the 1st level table only of size defined by S2_PGD_ORDER (can
- * support either full 40-bit input addresses or limited to 32-bit input
- * addresses). Clears the allocated pages.
+ * Allocates only the stage-2 HW PGD level table(s) (can support either full
+ * 40-bit input addresses or limited to 32-bit input addresses). Clears the
+ * allocated pages.
*
* Note we don't need locking here as this is only called when the VM is
* created, which can only be done once.
@@ -1037,11 +1041,6 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu)
return kvm_vcpu_dabt_iswrite(vcpu);
}
-static bool kvm_is_device_pfn(unsigned long pfn)
-{
- return !pfn_valid(pfn);
-}
-
/**
* stage2_wp_ptes - write protect PMD range
* @pmd: pointer to pmd entry
diff --git a/arch/arm/kvm/psci.c b/arch/arm/kvm/psci.c
index 0b55696..a9b3b90 100644
--- a/arch/arm/kvm/psci.c
+++ b/arch/arm/kvm/psci.c
@@ -75,7 +75,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
unsigned long context_id;
phys_addr_t target_pc;
- cpu_id = *vcpu_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
+ cpu_id = vcpu_get_reg(source_vcpu, 1) & MPIDR_HWID_BITMASK;
if (vcpu_mode_is_32bit(source_vcpu))
cpu_id &= ~((u32) 0);
@@ -94,8 +94,8 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
return PSCI_RET_INVALID_PARAMS;
}
- target_pc = *vcpu_reg(source_vcpu, 2);
- context_id = *vcpu_reg(source_vcpu, 3);
+ target_pc = vcpu_get_reg(source_vcpu, 2);
+ context_id = vcpu_get_reg(source_vcpu, 3);
kvm_reset_vcpu(vcpu);
@@ -114,7 +114,7 @@ static unsigned long kvm_psci_vcpu_on(struct kvm_vcpu *source_vcpu)
* NOTE: We always update r0 (or x0) because for PSCI v0.1
* the general puspose registers are undefined upon CPU_ON.
*/
- *vcpu_reg(vcpu, 0) = context_id;
+ vcpu_set_reg(vcpu, 0, context_id);
vcpu->arch.power_off = false;
smp_mb(); /* Make sure the above is visible */
@@ -134,8 +134,8 @@ static unsigned long kvm_psci_vcpu_affinity_info(struct kvm_vcpu *vcpu)
struct kvm *kvm = vcpu->kvm;
struct kvm_vcpu *tmp;
- target_affinity = *vcpu_reg(vcpu, 1);
- lowest_affinity_level = *vcpu_reg(vcpu, 2);
+ target_affinity = vcpu_get_reg(vcpu, 1);
+ lowest_affinity_level = vcpu_get_reg(vcpu, 2);
/* Determine target affinity mask */
target_affinity_mask = psci_affinity_mask(lowest_affinity_level);
@@ -209,7 +209,7 @@ int kvm_psci_version(struct kvm_vcpu *vcpu)
static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
{
int ret = 1;
- unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
switch (psci_fn) {
@@ -273,13 +273,13 @@ static int kvm_psci_0_2_call(struct kvm_vcpu *vcpu)
break;
}
- *vcpu_reg(vcpu, 0) = val;
+ vcpu_set_reg(vcpu, 0, val);
return ret;
}
static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
{
- unsigned long psci_fn = *vcpu_reg(vcpu, 0) & ~((u32) 0);
+ unsigned long psci_fn = vcpu_get_reg(vcpu, 0) & ~((u32) 0);
unsigned long val;
switch (psci_fn) {
@@ -295,7 +295,7 @@ static int kvm_psci_0_1_call(struct kvm_vcpu *vcpu)
break;
}
- *vcpu_reg(vcpu, 0) = val;
+ vcpu_set_reg(vcpu, 0, val);
return 1;
}
diff --git a/arch/arm/lib/lib1funcs.S b/arch/arm/lib/lib1funcs.S
index af2267f..9397b2e 100644
--- a/arch/arm/lib/lib1funcs.S
+++ b/arch/arm/lib/lib1funcs.S
@@ -205,6 +205,10 @@ Boston, MA 02111-1307, USA. */
.endm
+#ifdef CONFIG_ARM_PATCH_IDIV
+ .align 3
+#endif
+
ENTRY(__udivsi3)
ENTRY(__aeabi_uidiv)
UNWIND(.fnstart)
@@ -253,6 +257,10 @@ UNWIND(.fnstart)
UNWIND(.fnend)
ENDPROC(__umodsi3)
+#ifdef CONFIG_ARM_PATCH_IDIV
+ .align 3
+#endif
+
ENTRY(__divsi3)
ENTRY(__aeabi_idiv)
UNWIND(.fnstart)
diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c
index d72b909..588bbc2 100644
--- a/arch/arm/lib/uaccess_with_memcpy.c
+++ b/arch/arm/lib/uaccess_with_memcpy.c
@@ -88,6 +88,7 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
static unsigned long noinline
__copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
{
+ unsigned long ua_flags;
int atomic;
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
@@ -118,7 +119,9 @@ __copy_to_user_memcpy(void __user *to, const void *from, unsigned long n)
if (tocopy > n)
tocopy = n;
+ ua_flags = uaccess_save_and_enable();
memcpy((void *)to, from, tocopy);
+ uaccess_restore(ua_flags);
to += tocopy;
from += tocopy;
n -= tocopy;
@@ -145,14 +148,21 @@ arm_copy_to_user(void __user *to, const void *from, unsigned long n)
* With frame pointer disabled, tail call optimization kicks in
* as well making this test almost invisible.
*/
- if (n < 64)
- return __copy_to_user_std(to, from, n);
- return __copy_to_user_memcpy(to, from, n);
+ if (n < 64) {
+ unsigned long ua_flags = uaccess_save_and_enable();
+ n = __copy_to_user_std(to, from, n);
+ uaccess_restore(ua_flags);
+ } else {
+ n = __copy_to_user_memcpy(to, from, n);
+ }
+ return n;
}
static unsigned long noinline
__clear_user_memset(void __user *addr, unsigned long n)
{
+ unsigned long ua_flags;
+
if (unlikely(segment_eq(get_fs(), KERNEL_DS))) {
memset((void *)addr, 0, n);
return 0;
@@ -175,7 +185,9 @@ __clear_user_memset(void __user *addr, unsigned long n)
if (tocopy > n)
tocopy = n;
+ ua_flags = uaccess_save_and_enable();
memset((void *)addr, 0, tocopy);
+ uaccess_restore(ua_flags);
addr += tocopy;
n -= tocopy;
@@ -193,9 +205,14 @@ out:
unsigned long arm_clear_user(void __user *addr, unsigned long n)
{
/* See rational for this in __copy_to_user() above. */
- if (n < 64)
- return __clear_user_std(addr, n);
- return __clear_user_memset(addr, n);
+ if (n < 64) {
+ unsigned long ua_flags = uaccess_save_and_enable();
+ n = __clear_user_std(addr, n);
+ uaccess_restore(ua_flags);
+ } else {
+ n = __clear_user_memset(addr, n);
+ }
+ return n;
}
#if 0
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 9267300..28656c2 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -4,7 +4,6 @@ menuconfig ARCH_AT91
select ARCH_REQUIRE_GPIOLIB
select COMMON_CLK_AT91
select PINCTRL
- select PINCTRL_AT91
select SOC_BUS
if ARCH_AT91
@@ -17,6 +16,7 @@ config SOC_SAMA5D2
select HAVE_AT91_USB_CLK
select HAVE_AT91_H32MX
select HAVE_AT91_GENERATED_CLK
+ select PINCTRL_AT91PIO4
help
Select this if ou are using one of Atmel's SAMA5D2 family SoC.
@@ -27,6 +27,7 @@ config SOC_SAMA5D3
select HAVE_AT91_UTMI
select HAVE_AT91_SMD
select HAVE_AT91_USB_CLK
+ select PINCTRL_AT91
help
Select this if you are using one of Atmel's SAMA5D3 family SoC.
This support covers SAMA5D31, SAMA5D33, SAMA5D34, SAMA5D35, SAMA5D36.
@@ -40,6 +41,7 @@ config SOC_SAMA5D4
select HAVE_AT91_SMD
select HAVE_AT91_USB_CLK
select HAVE_AT91_H32MX
+ select PINCTRL_AT91
help
Select this if you are using one of Atmel's SAMA5D4 family SoC.
@@ -50,6 +52,7 @@ config SOC_AT91RM9200
select CPU_ARM920T
select HAVE_AT91_USB_CLK
select MIGHT_HAVE_PCI
+ select PINCTRL_AT91
select SOC_SAM_V4_V5
select SRAM if PM
help
@@ -65,6 +68,7 @@ config SOC_AT91SAM9
select HAVE_AT91_UTMI
select HAVE_FB_ATMEL
select MEMORY
+ select PINCTRL_AT91
select SOC_SAM_V4_V5
select SRAM if PM
help
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 80e277c..23726fb 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -41,8 +41,10 @@
* implementation should be moved down into the pinctrl driver and get
* called as part of the generic suspend/resume path.
*/
+#ifdef CONFIG_PINCTRL_AT91
extern void at91_pinctrl_gpio_suspend(void);
extern void at91_pinctrl_gpio_resume(void);
+#endif
static struct {
unsigned long uhp_udp_mask;
@@ -151,8 +153,9 @@ static void at91_pm_suspend(suspend_state_t state)
static int at91_pm_enter(suspend_state_t state)
{
+#ifdef CONFIG_PINCTRL_AT91
at91_pinctrl_gpio_suspend();
-
+#endif
switch (state) {
/*
* Suspend-to-RAM is like STANDBY plus slow clock mode, so
@@ -192,7 +195,9 @@ static int at91_pm_enter(suspend_state_t state)
error:
target_state = PM_SUSPEND_ON;
+#ifdef CONFIG_PINCTRL_AT91
at91_pinctrl_gpio_resume();
+#endif
return 0;
}
diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S
index 0d95f48..a25defd 100644
--- a/arch/arm/mach-at91/pm_suspend.S
+++ b/arch/arm/mach-at91/pm_suspend.S
@@ -80,6 +80,8 @@ tmp2 .req r5
* @r2: base address of second SDRAM Controller or 0 if not present
* @r3: pm information
*/
+/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */
+ .align 3
ENTRY(at91_pm_suspend_in_sram)
/* Save registers on stack */
stmfd sp!, {r4 - r12, lr}
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 84bd265..8c53c55 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -35,6 +35,20 @@ config ARCH_BCM_CYGNUS
BCM11300, BCM11320, BCM11350, BCM11360,
BCM58300, BCM58302, BCM58303, BCM58305.
+config ARCH_BCM_NSP
+ bool "Broadcom Northstar Plus SoC Support" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
+ select ARM_ERRATA_754322
+ select ARM_ERRATA_775420
+ help
+ Support for Broadcom Northstar Plus SoC.
+ Broadcom Northstar Plus family of SoCs are used for switching control
+ and management applications as well as residential router/gateway
+ applications. The SoC features dual core Cortex A9 ARM CPUs,
+ integrating several peripheral interfaces including multiple Gigabit
+ Ethernet PHYs, DDR3 memory, PCIE Gen-2, USB 2.0 and USB 3.0, serial and
+ NAND flash, SATA and several other IO controllers.
+
config ARCH_BCM_5301X
bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
select ARCH_BCM_IPROC
@@ -147,6 +161,7 @@ config ARCH_BRCMSTB
select BCM7120_L2_IRQ
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
select ARCH_WANT_OPTIONAL_GPIOLIB
+ select SOC_BRCMSTB
help
Say Y if you intend to run the kernel on a Broadcom ARM-based STB
chipset.
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 1780a3f..892261f 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2012-2014 Broadcom Corporation
+# Copyright (C) 2012-2015 Broadcom Corporation
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
@@ -13,6 +13,9 @@
# Cygnus
obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
+# Northstar Plus
+obj-$(CONFIG_ARCH_BCM_NSP) += bcm_nsp.o
+
# BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
diff --git a/arch/arm/mach-bcm/bcm_nsp.c b/arch/arm/mach-bcm/bcm_nsp.c
new file mode 100644
index 0000000..a1101a3
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm_nsp.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/mach/arch.h>
+
+static const char *const bcm_nsp_dt_compat[] __initconst = {
+ "brcm,nsp",
+ NULL,
+};
+
+DT_MACHINE_START(NSP_DT, "Broadcom Northstar Plus SoC")
+ .l2c_aux_val = 0,
+ .l2c_aux_mask = ~0,
+ .dt_compat = bcm_nsp_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-bcm/brcmstb.c b/arch/arm/mach-bcm/brcmstb.c
index 3a60f7e..99a67cf 100644
--- a/arch/arm/mach-bcm/brcmstb.c
+++ b/arch/arm/mach-bcm/brcmstb.c
@@ -12,11 +12,19 @@
*/
#include <linux/init.h>
+#include <linux/irqchip.h>
#include <linux/of_platform.h>
+#include <linux/soc/brcmstb/brcmstb.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
+static void __init brcmstb_init_irq(void)
+{
+ irqchip_init();
+ brcmstb_biuctrl_init();
+}
+
static const char *const brcmstb_match[] __initconst = {
"brcm,bcm7445",
"brcm,brcmstb",
@@ -25,4 +33,5 @@ static const char *const brcmstb_match[] __initconst = {
DT_MACHINE_START(BRCMSTB, "Broadcom STB (Flattened Device Tree)")
.dt_compat = brcmstb_match,
+ .init_irq = brcmstb_init_irq,
MACHINE_END
diff --git a/arch/arm/mach-berlin/berlin.c b/arch/arm/mach-berlin/berlin.c
index ac181c6..25d7387 100644
--- a/arch/arm/mach-berlin/berlin.c
+++ b/arch/arm/mach-berlin/berlin.c
@@ -18,6 +18,11 @@
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
+static void __init berlin_init_late(void)
+{
+ platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+}
+
static const char * const berlin_dt_compat[] = {
"marvell,berlin",
NULL,
@@ -25,6 +30,7 @@ static const char * const berlin_dt_compat[] = {
DT_MACHINE_START(BERLIN_DT, "Marvell Berlin")
.dt_compat = berlin_dt_compat,
+ .init_late = berlin_init_late,
/*
* with DT probing for L2CCs, berlin_init_machine can be removed.
* Note: 88DE3005 (Armada 1500-mini) uses pl310 l2cc
diff --git a/arch/arm/mach-berlin/platsmp.c b/arch/arm/mach-berlin/platsmp.c
index 34a3753..405cd37 100644
--- a/arch/arm/mach-berlin/platsmp.c
+++ b/arch/arm/mach-berlin/platsmp.c
@@ -14,10 +14,16 @@
#include <linux/of_address.h>
#include <asm/cacheflush.h>
+#include <asm/cp15.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
-#define CPU_RESET 0x00
+/*
+ * There are two reset registers, one with self-clearing (SC)
+ * reset and one with non-self-clearing reset (NON_SC).
+ */
+#define CPU_RESET_SC 0x00
+#define CPU_RESET_NON_SC 0x20
#define RESET_VECT 0x00
#define SW_RESET_ADDR 0x94
@@ -30,9 +36,11 @@ static inline void berlin_perform_reset_cpu(unsigned int cpu)
{
u32 val;
- val = readl(cpu_ctrl + CPU_RESET);
+ val = readl(cpu_ctrl + CPU_RESET_NON_SC);
+ val &= ~BIT(cpu_logical_map(cpu));
+ writel(val, cpu_ctrl + CPU_RESET_NON_SC);
val |= BIT(cpu_logical_map(cpu));
- writel(val, cpu_ctrl + CPU_RESET);
+ writel(val, cpu_ctrl + CPU_RESET_NON_SC);
}
static int berlin_boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -91,8 +99,32 @@ unmap_scu:
iounmap(scu_base);
}
+#ifdef CONFIG_HOTPLUG_CPU
+static void berlin_cpu_die(unsigned int cpu)
+{
+ v7_exit_coherency_flush(louis);
+ while (1)
+ cpu_do_idle();
+}
+
+static int berlin_cpu_kill(unsigned int cpu)
+{
+ u32 val;
+
+ val = readl(cpu_ctrl + CPU_RESET_NON_SC);
+ val &= ~BIT(cpu_logical_map(cpu));
+ writel(val, cpu_ctrl + CPU_RESET_NON_SC);
+
+ return 1;
+}
+#endif
+
static struct smp_operations berlin_smp_ops __initdata = {
.smp_prepare_cpus = berlin_smp_prepare_cpus,
.smp_boot_secondary = berlin_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = berlin_cpu_die,
+ .cpu_kill = berlin_cpu_kill,
+#endif
};
CPU_METHOD_OF_DECLARE(berlin_smp, "marvell,berlin-smp", &berlin_smp_ops);
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
index c622c30..47905a5 100644
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -65,8 +65,9 @@ static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus,
/*
* The CNS PCI bridge doesn't fit into the PCI hierarchy, though
- * we still want to access it. For this to work, we must place
- * the first device on the same bus as the CNS PCI bridge.
+ * we still want to access it.
+ * We place the host bridge on bus 0, and the directly connected
+ * device on bus 1, slot 0.
*/
if (busno == 0) { /* internal PCIe bus, host bridge device */
if (devfn == 0) /* device# and function# are ignored by hw */
@@ -211,58 +212,46 @@ static void __init cns3xxx_pcie_check_link(struct cns3xxx_pcie *cnspci)
}
}
+static void cns3xxx_write_config(struct cns3xxx_pcie *cnspci,
+ int where, int size, u32 val)
+{
+ void __iomem *base = cnspci->host_regs + (where & 0xffc);
+ u32 v;
+ u32 mask = (0x1ull << (size * 8)) - 1;
+ int shift = (where % 4) * 8;
+
+ v = readl_relaxed(base + (where & 0xffc));
+
+ v &= ~(mask << shift);
+ v |= (val & mask) << shift;
+
+ writel_relaxed(v, base + (where & 0xffc));
+ readl_relaxed(base + (where & 0xffc));
+}
+
static void __init cns3xxx_pcie_hw_init(struct cns3xxx_pcie *cnspci)
{
- int port = cnspci->port;
- struct pci_sys_data sd = {
- .private_data = cnspci,
- };
- struct pci_bus bus = {
- .number = 0,
- .ops = &cns3xxx_pcie_ops,
- .sysdata = &sd,
- };
u16 mem_base = cnspci->res_mem.start >> 16;
u16 mem_limit = cnspci->res_mem.end >> 16;
u16 io_base = cnspci->res_io.start >> 16;
u16 io_limit = cnspci->res_io.end >> 16;
- u32 devfn = 0;
- u8 tmp8;
- u16 pos;
- u16 dc;
-
- pci_bus_write_config_byte(&bus, devfn, PCI_PRIMARY_BUS, 0);
- pci_bus_write_config_byte(&bus, devfn, PCI_SECONDARY_BUS, 1);
- pci_bus_write_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, 1);
- pci_bus_read_config_byte(&bus, devfn, PCI_PRIMARY_BUS, &tmp8);
- pci_bus_read_config_byte(&bus, devfn, PCI_SECONDARY_BUS, &tmp8);
- pci_bus_read_config_byte(&bus, devfn, PCI_SUBORDINATE_BUS, &tmp8);
-
- pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_BASE, mem_base);
- pci_bus_write_config_word(&bus, devfn, PCI_MEMORY_LIMIT, mem_limit);
- pci_bus_write_config_word(&bus, devfn, PCI_IO_BASE_UPPER16, io_base);
- pci_bus_write_config_word(&bus, devfn, PCI_IO_LIMIT_UPPER16, io_limit);
+ cns3xxx_write_config(cnspci, PCI_PRIMARY_BUS, 1, 0);
+ cns3xxx_write_config(cnspci, PCI_SECONDARY_BUS, 1, 1);
+ cns3xxx_write_config(cnspci, PCI_SUBORDINATE_BUS, 1, 1);
+ cns3xxx_write_config(cnspci, PCI_MEMORY_BASE, 2, mem_base);
+ cns3xxx_write_config(cnspci, PCI_MEMORY_LIMIT, 2, mem_limit);
+ cns3xxx_write_config(cnspci, PCI_IO_BASE_UPPER16, 2, io_base);
+ cns3xxx_write_config(cnspci, PCI_IO_LIMIT_UPPER16, 2, io_limit);
if (!cnspci->linked)
return;
/* Set Device Max_Read_Request_Size to 128 byte */
- bus.number = 1; /* directly connected PCIe device */
- devfn = PCI_DEVFN(0, 0);
- pos = pci_bus_find_capability(&bus, devfn, PCI_CAP_ID_EXP);
- pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
- if (dc & PCI_EXP_DEVCTL_READRQ) {
- dc &= ~PCI_EXP_DEVCTL_READRQ;
- pci_bus_write_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, dc);
- pci_bus_read_config_word(&bus, devfn, pos + PCI_EXP_DEVCTL, &dc);
- if (dc & PCI_EXP_DEVCTL_READRQ)
- pr_warn("PCIe: Unable to set device Max_Read_Request_Size\n");
- else
- pr_info("PCIe: Max_Read_Request_Size set to 128 bytes\n");
- }
+ pcie_bus_config = PCIE_BUS_PEER2PEER;
+
/* Disable PCIe0 Interrupt Mask INTA to INTD */
- __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(port));
+ __raw_writel(~0x3FFF, MISC_PCIE_INT_MASK(cnspci->port));
}
static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 1ed545c..9cc7b81 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -49,8 +49,8 @@
#include <asm/mach/arch.h>
#include <asm/system_info.h>
-#include <media/tvp514x.h>
-#include <media/adv7343.h>
+#include <media/i2c/tvp514x.h>
+#include <media/i2c/adv7343.h>
#define DA850_EVM_PHY_ID "davinci_mdio-0:00"
#define DA850_LCD_PWR_PIN GPIO_TO_PIN(2, 8)
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index b46b4d2..c71dd99 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -19,7 +19,7 @@
#include <linux/gpio.h>
#include <linux/clk.h>
#include <linux/videodev2.h>
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
#include <linux/platform_data/gpio-davinci.h>
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index a756003..f073518 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -40,8 +40,8 @@
#include <linux/platform_data/mtd-davinci.h>
#include <linux/platform_data/keyscan-davinci.h>
-#include <media/ths7303.h>
-#include <media/tvp514x.h>
+#include <media/i2c/ths7303.h>
+#include <media/i2c/tvp514x.h>
#include "davinci.h"
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index 1a0898c..7a20507 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -26,7 +26,7 @@
#include <linux/v4l2-dv-timings.h>
#include <linux/export.h>
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
@@ -546,9 +546,7 @@ static int dm6444evm_msp430_get_pins(void)
if (status < 0)
return status;
- dev_dbg(&dm6446evm_msp->dev,
- "PINS: %02x %02x %02x %02x\n",
- buf[0], buf[1], buf[2], buf[3]);
+ dev_dbg(&dm6446evm_msp->dev, "PINS: %4ph\n", buf);
return (buf[3] << 8) | buf[2];
}
diff --git a/arch/arm/mach-davinci/board-dm646x-evm.c b/arch/arm/mach-davinci/board-dm646x-evm.c
index 846a84d..ee6ab7e 100644
--- a/arch/arm/mach-davinci/board-dm646x-evm.c
+++ b/arch/arm/mach-davinci/board-dm646x-evm.c
@@ -25,8 +25,8 @@
#include <linux/platform_data/at24.h>
#include <linux/i2c/pcf857x.h>
-#include <media/tvp514x.h>
-#include <media/adv7343.h>
+#include <media/i2c/tvp514x.h>
+#include <media/i2c/adv7343.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index c70bb0a..3caff96 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -97,7 +97,9 @@ int clk_enable(struct clk *clk)
{
unsigned long flags;
- if (clk == NULL || IS_ERR(clk))
+ if (!clk)
+ return 0;
+ else if (IS_ERR(clk))
return -EINVAL;
spin_lock_irqsave(&clockfw_lock, flags);
@@ -124,7 +126,7 @@ EXPORT_SYMBOL(clk_disable);
unsigned long clk_get_rate(struct clk *clk)
{
if (clk == NULL || IS_ERR(clk))
- return -EINVAL;
+ return 0;
return clk->rate;
}
@@ -159,8 +161,10 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
unsigned long flags;
int ret = -EINVAL;
- if (clk == NULL || IS_ERR(clk))
- return ret;
+ if (!clk)
+ return 0;
+ else if (IS_ERR(clk))
+ return -EINVAL;
if (clk->set_rate)
ret = clk->set_rate(clk, rate);
@@ -181,7 +185,9 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
- if (clk == NULL || IS_ERR(clk))
+ if (!clk)
+ return 0;
+ else if (IS_ERR(clk))
return -EINVAL;
/* Cannot change parent on enabled clock */
diff --git a/arch/arm/mach-digicolor/Kconfig b/arch/arm/mach-digicolor/Kconfig
index 4f36d8d..fc65b0f 100644
--- a/arch/arm/mach-digicolor/Kconfig
+++ b/arch/arm/mach-digicolor/Kconfig
@@ -1,7 +1,10 @@
config ARCH_DIGICOLOR
bool "Conexant Digicolor SoC Support"
depends on ARCH_MULTI_V7
+ select ARCH_REQUIRE_GPIOLIB
select CLKSRC_MMIO
select DIGICOLOR_TIMER
select GENERIC_IRQ_CHIP
select MFD_SYSCON
+ select PINCTRL
+ select PINCTRL_DIGICOLOR
diff --git a/arch/arm/mach-dove/include/mach/entry-macro.S b/arch/arm/mach-dove/include/mach/entry-macro.S
index 72d622b..df1d44b 100644
--- a/arch/arm/mach-dove/include/mach/entry-macro.S
+++ b/arch/arm/mach-dove/include/mach/entry-macro.S
@@ -18,13 +18,13 @@
@ check low interrupts
ldr \irqstat, [\base, #IRQ_CAUSE_LOW_OFF]
ldr \tmp, [\base, #IRQ_MASK_LOW_OFF]
- mov \irqnr, #31
+ mov \irqnr, #32
ands \irqstat, \irqstat, \tmp
@ if no low interrupts set, check high interrupts
ldreq \irqstat, [\base, #IRQ_CAUSE_HIGH_OFF]
ldreq \tmp, [\base, #IRQ_MASK_HIGH_OFF]
- moveq \irqnr, #63
+ moveq \irqnr, #64
andeqs \irqstat, \irqstat, \tmp
@ find first active interrupt source
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 3a10f1a..ff10539 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -27,6 +27,7 @@ menuconfig ARCH_EXYNOS
select SRAM
select THERMAL
select MFD_SYSCON
+ select CLKSRC_EXYNOS_MCT
help
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index de68938..c21e41d 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -748,8 +748,12 @@ static void exynos5_powerdown_conf(enum sys_powerdown mode)
void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{
unsigned int i;
+ const struct exynos_pmu_data *pmu_data;
+
+ if (!pmu_context)
+ return;
- const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
+ pmu_data = pmu_context->pmu_data;
if (pmu_data->powerdown_conf)
pmu_data->powerdown_conf(mode);
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
index 5a7e47c..c169cc3 100644
--- a/arch/arm/mach-exynos/suspend.c
+++ b/arch/arm/mach-exynos/suspend.c
@@ -19,6 +19,7 @@
#include <linux/cpu_pm.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/err.h>
@@ -265,7 +266,7 @@ static int __init exynos_pmu_irq_init(struct device_node *node,
return 0;
}
-#define EXYNOS_PMU_IRQ(symbol, name) OF_DECLARE_2(irqchip, symbol, name, exynos_pmu_irq_init)
+#define EXYNOS_PMU_IRQ(symbol, name) IRQCHIP_DECLARE(symbol, name, exynos_pmu_irq_init)
EXYNOS_PMU_IRQ(exynos3250_pmu_irq, "samsung,exynos3250-pmu");
EXYNOS_PMU_IRQ(exynos4210_pmu_irq, "samsung,exynos4210-pmu");
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 21e4e86..e2d5383 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -131,6 +131,7 @@ void imx6q_pm_init(void);
void imx6dl_pm_init(void);
void imx6sl_pm_init(void);
void imx6sx_pm_init(void);
+void imx6ul_pm_init(void);
#ifdef CONFIG_PM
void imx51_pm_init(void);
diff --git a/arch/arm/mach-imx/devices/devices-common.h b/arch/arm/mach-imx/devices/devices-common.h
index 67f7fb1..09cebd8 100644
--- a/arch/arm/mach-imx/devices/devices-common.h
+++ b/arch/arm/mach-imx/devices/devices-common.h
@@ -177,7 +177,7 @@ struct platform_device *__init imx_add_imx_uart_1irq(
const struct imxuart_platform_data *pdata);
#include <linux/platform_data/video-mx3fb.h>
-#include <linux/platform_data/camera-mx3.h>
+#include <linux/platform_data/media/camera-mx3.h>
struct imx_ipu_core_data {
resource_size_t iobase;
resource_size_t synirq;
@@ -192,7 +192,7 @@ struct platform_device *__init imx_add_mx3_sdc_fb(
const struct imx_ipu_core_data *data,
struct mx3fb_platform_data *pdata);
-#include <linux/platform_data/camera-mx2.h>
+#include <linux/platform_data/media/camera-mx2.h>
struct imx_mx2_camera_data {
const char *devid;
resource_size_t iobasecsi;
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 10bf715..cfc696b 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
@@ -176,6 +177,7 @@ static struct irq_chip imx_gpc_chip = {
.irq_unmask = imx_gpc_irq_unmask,
.irq_retrigger = irq_chip_retrigger_hierarchy,
.irq_set_wake = imx_gpc_irq_set_wake,
+ .irq_set_type = irq_chip_set_type_parent,
#ifdef CONFIG_SMP
.irq_set_affinity = irq_chip_set_affinity_parent,
#endif
@@ -271,12 +273,7 @@ static int __init imx_gpc_init(struct device_node *node,
return 0;
}
-
-/*
- * We cannot use the IRQCHIP_DECLARE macro that lives in
- * drivers/irqchip, so we're forced to roll our own. Not very nice.
- */
-OF_DECLARE_2(irqchip, imx_gpc, "fsl,imx6q-gpc", imx_gpc_init);
+IRQCHIP_DECLARE(imx_gpc, "fsl,imx6q-gpc", imx_gpc_init);
void __init imx_gpc_check_dt(void)
{
diff --git a/arch/arm/mach-imx/mach-imx6ul.c b/arch/arm/mach-imx/mach-imx6ul.c
index 1b97fe1..acaf705 100644
--- a/arch/arm/mach-imx/mach-imx6ul.c
+++ b/arch/arm/mach-imx/mach-imx6ul.c
@@ -67,6 +67,7 @@ static void __init imx6ul_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
imx6ul_enet_init();
imx_anatop_init();
+ imx6ul_pm_init();
}
static void __init imx6ul_init_irq(void)
@@ -74,6 +75,13 @@ static void __init imx6ul_init_irq(void)
imx_init_revision_from_anatop();
imx_src_init();
irqchip_init();
+ imx6_pm_ccm_init("fsl,imx6ul-ccm");
+}
+
+static void __init imx6ul_init_late(void)
+{
+ if (IS_ENABLED(CONFIG_ARM_IMX6Q_CPUFREQ))
+ platform_device_register_simple("imx6q-cpufreq", -1, NULL, 0);
}
static const char *imx6ul_dt_compat[] __initconst = {
@@ -84,5 +92,6 @@ static const char *imx6ul_dt_compat[] __initconst = {
DT_MACHINE_START(IMX6UL, "Freescale i.MX6 Ultralite (Device Tree)")
.init_irq = imx6ul_init_irq,
.init_machine = imx6ul_init_machine,
+ .init_late = imx6ul_init_late,
.dt_compat = imx6ul_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx7d.c b/arch/arm/mach-imx/mach-imx7d.c
index 62f3437..b450f52 100644
--- a/arch/arm/mach-imx/mach-imx7d.c
+++ b/arch/arm/mach-imx/mach-imx7d.c
@@ -6,12 +6,85 @@
* published by the Free Software Foundation.
*/
#include <linux/irqchip.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
+static int ar8031_phy_fixup(struct phy_device *dev)
+{
+ u16 val;
+
+ /* Set RGMII IO voltage to 1.8V */
+ phy_write(dev, 0x1d, 0x1f);
+ phy_write(dev, 0x1e, 0x8);
+
+ /* disable phy AR8031 SmartEEE function. */
+ phy_write(dev, 0xd, 0x3);
+ phy_write(dev, 0xe, 0x805d);
+ phy_write(dev, 0xd, 0x4003);
+ val = phy_read(dev, 0xe);
+ val &= ~(0x1 << 8);
+ phy_write(dev, 0xe, val);
+
+ /* introduce tx clock delay */
+ phy_write(dev, 0x1d, 0x5);
+ val = phy_read(dev, 0x1e);
+ val |= 0x0100;
+ phy_write(dev, 0x1e, val);
+
+ return 0;
+}
+
+static int bcm54220_phy_fixup(struct phy_device *dev)
+{
+ /* enable RXC skew select RGMII copper mode */
+ phy_write(dev, 0x1e, 0x21);
+ phy_write(dev, 0x1f, 0x7ea8);
+ phy_write(dev, 0x1e, 0x2f);
+ phy_write(dev, 0x1f, 0x71b7);
+
+ return 0;
+}
+
+#define PHY_ID_AR8031 0x004dd074
+#define PHY_ID_BCM54220 0x600d8589
+
+static void __init imx7d_enet_phy_init(void)
+{
+ if (IS_BUILTIN(CONFIG_PHYLIB)) {
+ phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
+ ar8031_phy_fixup);
+ phy_register_fixup_for_uid(PHY_ID_BCM54220, 0xffffffff,
+ bcm54220_phy_fixup);
+ }
+}
+
+static void __init imx7d_enet_clk_sel(void)
+{
+ struct regmap *gpr;
+
+ gpr = syscon_regmap_lookup_by_compatible("fsl,imx7d-iomuxc-gpr");
+ if (!IS_ERR(gpr)) {
+ regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_TX_CLK_SEL_MASK, 0);
+ regmap_update_bits(gpr, IOMUXC_GPR1, IMX7D_GPR1_ENET_CLK_DIR_MASK, 0);
+ } else {
+ pr_err("failed to find fsl,imx7d-iomux-gpr regmap\n");
+ }
+}
+
+static inline void imx7d_enet_init(void)
+{
+ imx7d_enet_phy_init();
+ imx7d_enet_clk_sel();
+}
+
static void __init imx7d_init_machine(void)
{
struct device *parent;
@@ -22,6 +95,7 @@ static void __init imx7d_init_machine(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
imx_anatop_init();
+ imx7d_enet_init();
}
static void __init imx7d_init_irq(void)
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 8ff8fc0..4470376 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -93,6 +93,7 @@ struct imx6_pm_socdata {
const char *src_compat;
const char *iomuxc_compat;
const char *gpc_compat;
+ const char *pl310_compat;
const u32 mmdc_io_num;
const u32 *mmdc_io_offset;
};
@@ -137,11 +138,19 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
0x330, 0x334, 0x338, 0x33c, /* SDQS0 ~ SDQS3 */
};
+static const u32 imx6ul_mmdc_io_offset[] __initconst = {
+ 0x244, 0x248, 0x24c, 0x250, /* DQM0, DQM1, RAS, CAS */
+ 0x27c, 0x498, 0x4a4, 0x490, /* SDCLK0, GPR_B0DS-B1DS, GPR_ADDS */
+ 0x280, 0x284, 0x260, 0x264, /* SDQS0~1, SODT0, SODT1 */
+ 0x494, 0x4b0, /* MODE_CTL, MODE, */
+};
+
static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
.mmdc_compat = "fsl,imx6q-mmdc",
.src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6q-iomuxc",
.gpc_compat = "fsl,imx6q-gpc",
+ .pl310_compat = "arm,pl310-cache",
.mmdc_io_num = ARRAY_SIZE(imx6q_mmdc_io_offset),
.mmdc_io_offset = imx6q_mmdc_io_offset,
};
@@ -151,6 +160,7 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
.src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6dl-iomuxc",
.gpc_compat = "fsl,imx6q-gpc",
+ .pl310_compat = "arm,pl310-cache",
.mmdc_io_num = ARRAY_SIZE(imx6dl_mmdc_io_offset),
.mmdc_io_offset = imx6dl_mmdc_io_offset,
};
@@ -160,6 +170,7 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
.src_compat = "fsl,imx6sl-src",
.iomuxc_compat = "fsl,imx6sl-iomuxc",
.gpc_compat = "fsl,imx6sl-gpc",
+ .pl310_compat = "arm,pl310-cache",
.mmdc_io_num = ARRAY_SIZE(imx6sl_mmdc_io_offset),
.mmdc_io_offset = imx6sl_mmdc_io_offset,
};
@@ -169,10 +180,21 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
.src_compat = "fsl,imx6sx-src",
.iomuxc_compat = "fsl,imx6sx-iomuxc",
.gpc_compat = "fsl,imx6sx-gpc",
+ .pl310_compat = "arm,pl310-cache",
.mmdc_io_num = ARRAY_SIZE(imx6sx_mmdc_io_offset),
.mmdc_io_offset = imx6sx_mmdc_io_offset,
};
+static const struct imx6_pm_socdata imx6ul_pm_data __initconst = {
+ .mmdc_compat = "fsl,imx6ul-mmdc",
+ .src_compat = "fsl,imx6ul-src",
+ .iomuxc_compat = "fsl,imx6ul-iomuxc",
+ .gpc_compat = "fsl,imx6ul-gpc",
+ .pl310_compat = NULL,
+ .mmdc_io_num = ARRAY_SIZE(imx6ul_mmdc_io_offset),
+ .mmdc_io_offset = imx6ul_mmdc_io_offset,
+};
+
/*
* This structure is for passing necessary data for low level ocram
* suspend code(arch/arm/mach-imx/suspend-imx6.S), if this struct
@@ -290,7 +312,7 @@ int imx6_set_lpm(enum mxc_cpu_pwr_mode mode)
val |= BM_CLPCR_SBYOS;
if (cpu_is_imx6sl())
val |= BM_CLPCR_BYPASS_PMIC_READY;
- if (cpu_is_imx6sl() || cpu_is_imx6sx())
+ if (cpu_is_imx6sl() || cpu_is_imx6sx() || cpu_is_imx6ul())
val |= BM_CLPCR_BYP_MMDC_CH0_LPM_HS;
else
val |= BM_CLPCR_BYP_MMDC_CH1_LPM_HS;
@@ -330,6 +352,10 @@ static int imx6q_suspend_finish(unsigned long val)
* as we need to float DDR IO.
*/
local_flush_tlb_all();
+ /* check if need to flush internal L2 cache */
+ if (!((struct imx6_cpu_pm_info *)
+ suspend_ocram_base)->l2_base.vbase)
+ flush_cache_all();
imx6_suspend_in_ocram_fn(suspend_ocram_base);
}
@@ -470,6 +496,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
suspend_ocram_base = __arm_ioremap_exec(ocram_pbase,
MX6Q_SUSPEND_OCRAM_SIZE, false);
+ memset(suspend_ocram_base, 0, sizeof(*pm_info));
pm_info = suspend_ocram_base;
pm_info->pbase = ocram_pbase;
pm_info->resume_addr = virt_to_phys(v7_cpu_resume);
@@ -505,11 +532,13 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
goto gpc_map_failed;
}
- ret = imx6_pm_get_base(&pm_info->l2_base, "arm,pl310-cache");
- if (ret) {
- pr_warn("%s: failed to get pl310-cache base %d!\n",
- __func__, ret);
- goto pl310_cache_map_failed;
+ if (socdata->pl310_compat) {
+ ret = imx6_pm_get_base(&pm_info->l2_base, socdata->pl310_compat);
+ if (ret) {
+ pr_warn("%s: failed to get pl310-cache base %d!\n",
+ __func__, ret);
+ goto pl310_cache_map_failed;
+ }
}
pm_info->ddr_type = imx_mmdc_get_ddr_type();
@@ -610,3 +639,8 @@ void __init imx6sx_pm_init(void)
{
imx6_pm_common_init(&imx6sx_pm_data);
}
+
+void __init imx6ul_pm_init(void)
+{
+ imx6_pm_common_init(&imx6ul_pm_data);
+}
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index b99987b..76ee2ce 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -79,12 +79,15 @@
/* sync L2 cache to drain L2's buffers to DRAM. */
#ifdef CONFIG_CACHE_L2X0
ldr r11, [r0, #PM_INFO_MX6Q_L2_V_OFFSET]
+ teq r11, #0
+ beq 6f
mov r6, #0x0
str r6, [r11, #L2X0_CACHE_SYNC]
1:
ldr r6, [r11, #L2X0_CACHE_SYNC]
ands r6, r6, #0x1
bne 1b
+6:
#endif
.endm
diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h
index b024390..7a0c13b 100644
--- a/arch/arm/mach-ixp4xx/include/mach/io.h
+++ b/arch/arm/mach-ixp4xx/include/mach/io.h
@@ -143,7 +143,7 @@ static inline void __indirect_writesl(volatile void __iomem *bus_addr,
writel(*vaddr++, bus_addr);
}
-static inline unsigned char __indirect_readb(const volatile void __iomem *p)
+static inline u8 __indirect_readb(const volatile void __iomem *p)
{
u32 addr = (u32)p;
u32 n, byte_enables, data;
@@ -166,7 +166,7 @@ static inline void __indirect_readsb(const volatile void __iomem *bus_addr,
*vaddr++ = readb(bus_addr);
}
-static inline unsigned short __indirect_readw(const volatile void __iomem *p)
+static inline u16 __indirect_readw(const volatile void __iomem *p)
{
u32 addr = (u32)p;
u32 n, byte_enables, data;
@@ -189,7 +189,7 @@ static inline void __indirect_readsw(const volatile void __iomem *bus_addr,
*vaddr++ = readw(bus_addr);
}
-static inline unsigned long __indirect_readl(const volatile void __iomem *p)
+static inline u32 __indirect_readl(const volatile void __iomem *p)
{
u32 addr = (__force u32)p;
u32 data;
@@ -350,7 +350,7 @@ static inline void insl(u32 io_addr, void *p, u32 count)
((unsigned long)p <= (PIO_MASK + PIO_OFFSET)))
#define ioread8(p) ioread8(p)
-static inline unsigned int ioread8(const void __iomem *addr)
+static inline u8 ioread8(const void __iomem *addr)
{
unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
@@ -378,7 +378,7 @@ static inline void ioread8_rep(const void __iomem *addr, void *vaddr, u32 count)
}
#define ioread16(p) ioread16(p)
-static inline unsigned int ioread16(const void __iomem *addr)
+static inline u16 ioread16(const void __iomem *addr)
{
unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
@@ -407,7 +407,7 @@ static inline void ioread16_rep(const void __iomem *addr, void *vaddr,
}
#define ioread32(p) ioread32(p)
-static inline unsigned int ioread32(const void __iomem *addr)
+static inline u32 ioread32(const void __iomem *addr)
{
unsigned long port = (unsigned long __force)addr;
if (__is_io_address(port))
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
index e288010..c279293 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -97,6 +97,9 @@ static long long __init keystone_pv_fixup(void)
}
static const char *const keystone_match[] __initconst = {
+ "ti,k2hk",
+ "ti,k2e",
+ "ti,k2l",
"ti,keystone",
NULL,
};
diff --git a/arch/arm/mach-mediatek/Makefile b/arch/arm/mach-mediatek/Makefile
index 43e619f..2116460 100644
--- a/arch/arm/mach-mediatek/Makefile
+++ b/arch/arm/mach-mediatek/Makefile
@@ -1 +1,4 @@
+ifeq ($(CONFIG_SMP),y)
+obj-$(CONFIG_ARCH_MEDIATEK) += platsmp.o
+endif
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek.o
diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
index a954900..d019a08 100644
--- a/arch/arm/mach-mediatek/mediatek.c
+++ b/arch/arm/mach-mediatek/mediatek.c
@@ -16,6 +16,32 @@
*/
#include <linux/init.h>
#include <asm/mach/arch.h>
+#include <linux/of.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+
+
+#define GPT6_CON_MT65xx 0x10008060
+#define GPT_ENABLE 0x31
+
+static void __init mediatek_timer_init(void)
+{
+ void __iomem *gpt_base;
+
+ if (of_machine_is_compatible("mediatek,mt6589") ||
+ of_machine_is_compatible("mediatek,mt8135") ||
+ of_machine_is_compatible("mediatek,mt8127")) {
+ /* turn on GPT6 which ungates arch timer clocks */
+ gpt_base = ioremap(GPT6_CON_MT65xx, 0x04);
+
+ /* enable clock and set to free-run */
+ writel(GPT_ENABLE, gpt_base);
+ iounmap(gpt_base);
+ }
+
+ of_clk_init(NULL);
+ clocksource_probe();
+};
static const char * const mediatek_board_dt_compat[] = {
"mediatek,mt6589",
@@ -27,4 +53,5 @@ static const char * const mediatek_board_dt_compat[] = {
DT_MACHINE_START(MEDIATEK_DT, "Mediatek Cortex-A7 (Device Tree)")
.dt_compat = mediatek_board_dt_compat,
+ .init_time = mediatek_timer_init,
MACHINE_END
diff --git a/arch/arm/mach-mediatek/platsmp.c b/arch/arm/mach-mediatek/platsmp.c
new file mode 100644
index 0000000..8141f3f
--- /dev/null
+++ b/arch/arm/mach-mediatek/platsmp.c
@@ -0,0 +1,141 @@
+/*
+ * arch/arm/mach-mediatek/platsmp.c
+ *
+ * Copyright (c) 2014 Mediatek Inc.
+ * Author: Shunli Wang <shunli.wang@mediatek.com>
+ * Yingjoe Chen <yingjoe.chen@mediatek.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.
+ *
+ */
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/string.h>
+#include <linux/threads.h>
+
+#define MTK_MAX_CPU 8
+#define MTK_SMP_REG_SIZE 0x1000
+
+struct mtk_smp_boot_info {
+ unsigned long smp_base;
+ unsigned int jump_reg;
+ unsigned int core_keys[MTK_MAX_CPU - 1];
+ unsigned int core_regs[MTK_MAX_CPU - 1];
+};
+
+static const struct mtk_smp_boot_info mtk_mt8135_tz_boot = {
+ 0x80002000, 0x3fc,
+ { 0x534c4131, 0x4c415332, 0x41534c33 },
+ { 0x3f8, 0x3f8, 0x3f8 },
+};
+
+static const struct mtk_smp_boot_info mtk_mt6589_boot = {
+ 0x10002000, 0x34,
+ { 0x534c4131, 0x4c415332, 0x41534c33 },
+ { 0x38, 0x3c, 0x40 },
+};
+
+static const struct of_device_id mtk_tz_smp_boot_infos[] __initconst = {
+ { .compatible = "mediatek,mt8135", .data = &mtk_mt8135_tz_boot },
+ { .compatible = "mediatek,mt8127", .data = &mtk_mt8135_tz_boot },
+};
+
+static const struct of_device_id mtk_smp_boot_infos[] __initconst = {
+ { .compatible = "mediatek,mt6589", .data = &mtk_mt6589_boot },
+};
+
+static void __iomem *mtk_smp_base;
+static const struct mtk_smp_boot_info *mtk_smp_info;
+
+static int mtk_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ if (!mtk_smp_base)
+ return -EINVAL;
+
+ if (!mtk_smp_info->core_keys[cpu-1])
+ return -EINVAL;
+
+ writel_relaxed(mtk_smp_info->core_keys[cpu-1],
+ mtk_smp_base + mtk_smp_info->core_regs[cpu-1]);
+
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ return 0;
+}
+
+static void __init __mtk_smp_prepare_cpus(unsigned int max_cpus, int trustzone)
+{
+ int i, num;
+ const struct of_device_id *infos;
+
+ if (trustzone) {
+ num = ARRAY_SIZE(mtk_tz_smp_boot_infos);
+ infos = mtk_tz_smp_boot_infos;
+ } else {
+ num = ARRAY_SIZE(mtk_smp_boot_infos);
+ infos = mtk_smp_boot_infos;
+ }
+
+ /* Find smp boot info for this SoC */
+ for (i = 0; i < num; i++) {
+ if (of_machine_is_compatible(infos[i].compatible)) {
+ mtk_smp_info = infos[i].data;
+ break;
+ }
+ }
+
+ if (!mtk_smp_info) {
+ pr_err("%s: Device is not supported\n", __func__);
+ return;
+ }
+
+ if (trustzone) {
+ /* smp_base(trustzone-bootinfo) is reserved by device tree */
+ mtk_smp_base = phys_to_virt(mtk_smp_info->smp_base);
+ } else {
+ mtk_smp_base = ioremap(mtk_smp_info->smp_base, MTK_SMP_REG_SIZE);
+ if (!mtk_smp_base) {
+ pr_err("%s: Can't remap %lx\n", __func__,
+ mtk_smp_info->smp_base);
+ return;
+ }
+ }
+
+ /*
+ * write the address of slave startup address into the system-wide
+ * jump register
+ */
+ writel_relaxed(virt_to_phys(secondary_startup_arm),
+ mtk_smp_base + mtk_smp_info->jump_reg);
+}
+
+static void __init mtk_tz_smp_prepare_cpus(unsigned int max_cpus)
+{
+ __mtk_smp_prepare_cpus(max_cpus, 1);
+}
+
+static void __init mtk_smp_prepare_cpus(unsigned int max_cpus)
+{
+ __mtk_smp_prepare_cpus(max_cpus, 0);
+}
+
+static struct smp_operations mt81xx_tz_smp_ops __initdata = {
+ .smp_prepare_cpus = mtk_tz_smp_prepare_cpus,
+ .smp_boot_secondary = mtk_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(mt81xx_tz_smp, "mediatek,mt81xx-tz-smp", &mt81xx_tz_smp_ops);
+
+static struct smp_operations mt6589_smp_ops __initdata = {
+ .smp_prepare_cpus = mtk_smp_prepare_cpus,
+ .smp_boot_secondary = mtk_boot_secondary,
+};
+CPU_METHOD_OF_DECLARE(mt6589_smp, "mediatek,mt6589-smp", &mt6589_smp_ops);
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index 0743e20..5d56f86 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -19,4 +19,9 @@ config MACH_MESON8
default ARCH_MESON
select MESON6_TIMER
+config MACH_MESON8B
+ bool "Amlogic Meson8b SoCs support"
+ default ARCH_MESON
+ select MESON6_TIMER
+
endif
diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c
index 5d6affe..4e23571 100644
--- a/arch/arm/mach-meson/meson.c
+++ b/arch/arm/mach-meson/meson.c
@@ -19,6 +19,7 @@
static const char * const meson_common_board_compat[] = {
"amlogic,meson6",
"amlogic,meson8",
+ "amlogic,meson8b",
NULL,
};
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index 9f739f3..1648edd 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -22,7 +22,6 @@
#include <linux/dma-mapping.h>
#include <linux/memblock.h>
#include <linux/mbus.h>
-#include <linux/signal.h>
#include <linux/slab.h>
#include <linux/irqchip.h>
#include <asm/hardware/cache-l2x0.h>
@@ -105,27 +104,6 @@ static void __init mvebu_memblock_reserve(void)
static void __init mvebu_memblock_reserve(void) {}
#endif
-/*
- * Early versions of Armada 375 SoC have a bug where the BootROM
- * leaves an external data abort pending. The kernel is hit by this
- * data abort as soon as it enters userspace, because it unmasks the
- * data aborts at this moment. We register a custom abort handler
- * below to ignore the first data abort to work around this
- * problem.
- */
-static int armada_375_external_abort_wa(unsigned long addr, unsigned int fsr,
- struct pt_regs *regs)
-{
- static int ignore_first;
-
- if (!ignore_first && fsr == 0x1406) {
- ignore_first = 1;
- return 0;
- }
-
- return 1;
-}
-
static void __init mvebu_init_irq(void)
{
irqchip_init();
@@ -134,17 +112,6 @@ static void __init mvebu_init_irq(void)
BUG_ON(mvebu_mbus_dt_init(coherency_available()));
}
-static void __init external_abort_quirk(void)
-{
- u32 dev, rev;
-
- if (mvebu_get_soc_id(&dev, &rev) == 0 && rev > ARMADA_375_Z1_REV)
- return;
-
- hook_fault_code(16 + 6, armada_375_external_abort_wa, SIGBUS, 0,
- "imprecise external abort");
-}
-
static void __init i2c_quirk(void)
{
struct device_node *np;
@@ -177,8 +144,6 @@ static void __init mvebu_dt_init(void)
{
if (of_machine_is_compatible("marvell,armadaxp"))
i2c_quirk();
- if (of_machine_is_compatible("marvell,a375-db"))
- external_abort_quirk();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index 44eedf3..55348ee 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -40,6 +40,7 @@
unsigned long coherency_phys_base;
void __iomem *coherency_base;
static void __iomem *coherency_cpu_base;
+static void __iomem *cpu_config_base;
/* Coherency fabric registers */
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
@@ -65,6 +66,31 @@ static const struct of_device_id of_coherency_table[] = {
int ll_enable_coherency(void);
void ll_add_cpu_to_smp_group(void);
+#define CPU_CONFIG_SHARED_L2 BIT(16)
+
+/*
+ * Disable the "Shared L2 Present" bit in CPU Configuration register
+ * on Armada XP.
+ *
+ * The "Shared L2 Present" bit affects the "level of coherence" value
+ * in the clidr CP15 register. Cache operation functions such as
+ * "flush all" and "invalidate all" operate on all the cache levels
+ * that included in the defined level of coherence. When HW I/O
+ * coherency is used, this bit causes unnecessary flushes of the L2
+ * cache.
+ */
+static void armada_xp_clear_shared_l2(void)
+{
+ u32 reg;
+
+ if (!cpu_config_base)
+ return;
+
+ reg = readl(cpu_config_base);
+ reg &= ~CPU_CONFIG_SHARED_L2;
+ writel(reg, cpu_config_base);
+}
+
static int mvebu_hwcc_notifier(struct notifier_block *nb,
unsigned long event, void *__dev)
{
@@ -85,9 +111,24 @@ static struct notifier_block mvebu_hwcc_pci_nb = {
.notifier_call = mvebu_hwcc_notifier,
};
+static int armada_xp_clear_shared_l2_notifier_func(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
+ armada_xp_clear_shared_l2();
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block armada_xp_clear_shared_l2_notifier = {
+ .notifier_call = armada_xp_clear_shared_l2_notifier_func,
+ .priority = 100,
+};
+
static void __init armada_370_coherency_init(struct device_node *np)
{
struct resource res;
+ struct device_node *cpu_config_np;
of_address_to_resource(np, 0, &res);
coherency_phys_base = res.start;
@@ -100,6 +141,23 @@ static void __init armada_370_coherency_init(struct device_node *np)
sync_cache_w(&coherency_phys_base);
coherency_base = of_iomap(np, 0);
coherency_cpu_base = of_iomap(np, 1);
+
+ cpu_config_np = of_find_compatible_node(NULL, NULL,
+ "marvell,armada-xp-cpu-config");
+ if (!cpu_config_np)
+ goto exit;
+
+ cpu_config_base = of_iomap(cpu_config_np, 0);
+ if (!cpu_config_base) {
+ of_node_put(cpu_config_np);
+ goto exit;
+ }
+
+ of_node_put(cpu_config_np);
+
+ register_cpu_notifier(&armada_xp_clear_shared_l2_notifier);
+
+exit:
set_cpu_coherent();
}
@@ -204,6 +262,8 @@ int set_cpu_coherent(void)
pr_warn("Coherency fabric is not initialized\n");
return 1;
}
+
+ armada_xp_clear_shared_l2();
ll_add_cpu_to_smp_group();
return ll_enable_coherency();
}
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index e8fdb9c..ed8fda4 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -296,11 +296,11 @@ int armada_370_xp_pmsu_idle_enter(unsigned long deepidle)
/* Test the CR_C bit and set it if it was cleared */
asm volatile(
"mrc p15, 0, r0, c1, c0, 0 \n\t"
- "tst r0, #(1 << 2) \n\t"
+ "tst r0, %0 \n\t"
"orreq r0, r0, #(1 << 2) \n\t"
"mcreq p15, 0, r0, c1, c0, 0 \n\t"
"isb "
- : : : "r0");
+ : : "Ir" (CR_C) : "r0");
pr_debug("Failed to suspend the system\n");
@@ -379,6 +379,16 @@ static struct notifier_block mvebu_v7_cpu_pm_notifier = {
static struct platform_device mvebu_v7_cpuidle_device;
+static int broken_idle(struct device_node *np)
+{
+ if (of_property_read_bool(np, "broken-idle")) {
+ pr_warn("CPU idle is currently broken: disabling\n");
+ return 1;
+ }
+
+ return 0;
+}
+
static __init int armada_370_cpuidle_init(void)
{
struct device_node *np;
@@ -387,7 +397,9 @@ static __init int armada_370_cpuidle_init(void)
np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
if (!np)
return -ENODEV;
- of_node_put(np);
+
+ if (broken_idle(np))
+ goto end;
/*
* On Armada 370, there is "a slow exit process from the deep
@@ -406,6 +418,8 @@ static __init int armada_370_cpuidle_init(void)
mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
mvebu_v7_cpuidle_device.name = "cpuidle-armada-370";
+end:
+ of_node_put(np);
return 0;
}
@@ -422,6 +436,10 @@ static __init int armada_38x_cpuidle_init(void)
"marvell,armada-380-coherency-fabric");
if (!np)
return -ENODEV;
+
+ if (broken_idle(np))
+ goto end;
+
of_node_put(np);
np = of_find_compatible_node(NULL, NULL,
@@ -430,7 +448,6 @@ static __init int armada_38x_cpuidle_init(void)
return -ENODEV;
mpsoc_base = of_iomap(np, 0);
BUG_ON(!mpsoc_base);
- of_node_put(np);
/* Set up reset mask when powering down the cpus */
reg = readl(mpsoc_base + MPCORE_RESET_CTL);
@@ -450,6 +467,8 @@ static __init int armada_38x_cpuidle_init(void)
mvebu_v7_cpuidle_device.dev.platform_data = armada_38x_cpu_suspend;
mvebu_v7_cpuidle_device.name = "cpuidle-armada-38x";
+end:
+ of_node_put(np);
return 0;
}
@@ -460,12 +479,16 @@ static __init int armada_xp_cpuidle_init(void)
np = of_find_compatible_node(NULL, NULL, "marvell,coherency-fabric");
if (!np)
return -ENODEV;
- of_node_put(np);
+
+ if (broken_idle(np))
+ goto end;
mvebu_cpu_resume = armada_370_xp_cpu_resume;
mvebu_v7_cpuidle_device.dev.platform_data = armada_370_xp_cpu_suspend;
mvebu_v7_cpuidle_device.name = "cpuidle-armada-xp";
+end:
+ of_node_put(np);
return 0;
}
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
index cdd05f2..afb80950 100644
--- a/arch/arm/mach-omap1/Kconfig
+++ b/arch/arm/mach-omap1/Kconfig
@@ -90,13 +90,6 @@ config MACH_OMAP_FSAMPLE
Support for TI OMAP 850 F-Sample board. Say Y here if you have such
a board.
-config MACH_VOICEBLUE
- bool "Voiceblue"
- depends on ARCH_OMAP1 && ARCH_OMAP15XX
- help
- Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
- such a board.
-
config MACH_OMAP_PALMTE
bool "Palm Tungsten E"
depends on ARCH_OMAP1 && ARCH_OMAP15XX
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
index 3889b6c..0e8ea95 100644
--- a/arch/arm/mach-omap1/Makefile
+++ b/arch/arm/mach-omap1/Makefile
@@ -37,7 +37,6 @@ obj-$(CONFIG_MACH_OMAP_FSAMPLE) += board-fsample.o board-nand.o
obj-$(CONFIG_MACH_OMAP_OSK) += board-osk.o
obj-$(CONFIG_MACH_OMAP_H3) += board-h3.o board-h3-mmc.o \
board-nand.o
-obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
obj-$(CONFIG_MACH_OMAP_PALMTE) += board-palmte.o
obj-$(CONFIG_MACH_OMAP_PALMZ71) += board-palmz71.o
obj-$(CONFIG_MACH_OMAP_PALMTT) += board-palmtt.o
diff --git a/arch/arm/mach-omap1/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
deleted file mode 100644
index e960687..0000000
--- a/arch/arm/mach-omap1/board-voiceblue.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * linux/arch/arm/mach-omap1/board-voiceblue.c
- *
- * Modified from board-generic.c
- *
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Code for OMAP5910 based VoiceBlue board (VoIP to GSM gateway).
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/mtd/physmap.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-#include <linux/smc91x.h>
-#include <linux/export.h>
-#include <linux/reboot.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/board-voiceblue.h>
-#include <mach/flash.h>
-#include <mach/mux.h>
-#include <mach/tc.h>
-
-#include <mach/hardware.h>
-#include <mach/usb.h>
-
-#include "common.h"
-
-static struct plat_serial8250_port voiceblue_ports[] = {
- {
- .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x40000),
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
- .iotype = UPIO_MEM,
- .regshift = 1,
- .uartclk = 3686400,
- },
- {
- .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x50000),
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
- .iotype = UPIO_MEM,
- .regshift = 1,
- .uartclk = 3686400,
- },
- {
- .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x60000),
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
- .iotype = UPIO_MEM,
- .regshift = 1,
- .uartclk = 3686400,
- },
- {
- .mapbase = (unsigned long)(OMAP_CS1_PHYS + 0x70000),
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP,
- .iotype = UPIO_MEM,
- .regshift = 1,
- .uartclk = 3686400,
- },
- { },
-};
-
-static struct platform_device serial_device = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM1,
-};
-
-static int __init ext_uart_init(void)
-{
- if (!machine_is_voiceblue())
- return -ENODEV;
-
- voiceblue_ports[0].irq = gpio_to_irq(12);
- voiceblue_ports[1].irq = gpio_to_irq(13);
- voiceblue_ports[2].irq = gpio_to_irq(14);
- voiceblue_ports[3].irq = gpio_to_irq(15);
- serial_device.dev.platform_data = voiceblue_ports;
- return platform_device_register(&serial_device);
-}
-arch_initcall(ext_uart_init);
-
-static struct physmap_flash_data voiceblue_flash_data = {
- .width = 2,
- .set_vpp = omap1_set_vpp,
-};
-
-static struct resource voiceblue_flash_resource = {
- .start = OMAP_CS0_PHYS,
- .end = OMAP_CS0_PHYS + SZ_32M - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device voiceblue_flash_device = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &voiceblue_flash_data,
- },
- .num_resources = 1,
- .resource = &voiceblue_flash_resource,
-};
-
-static struct smc91x_platdata voiceblue_smc91x_info = {
- .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT,
- .leda = RPC_LED_100_10,
- .ledb = RPC_LED_TX_RX,
-};
-
-static struct resource voiceblue_smc91x_resources[] = {
- [0] = {
- .start = OMAP_CS2_PHYS + 0x300,
- .end = OMAP_CS2_PHYS + 0x300 + 16,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
- },
-};
-
-static struct platform_device voiceblue_smc91x_device = {
- .name = "smc91x",
- .id = 0,
- .dev = {
- .platform_data = &voiceblue_smc91x_info,
- },
- .num_resources = ARRAY_SIZE(voiceblue_smc91x_resources),
- .resource = voiceblue_smc91x_resources,
-};
-
-static struct platform_device *voiceblue_devices[] __initdata = {
- &voiceblue_flash_device,
- &voiceblue_smc91x_device,
-};
-
-static struct omap_usb_config voiceblue_usb_config __initdata = {
- .hmc_mode = 3,
- .register_host = 1,
- .register_dev = 1,
- .pins[0] = 2,
- .pins[1] = 6,
- .pins[2] = 6,
-};
-
-#define MACHINE_PANICED 1
-#define MACHINE_REBOOTING 2
-#define MACHINE_REBOOT 4
-static unsigned long machine_state;
-
-static int panic_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- if (test_and_set_bit(MACHINE_PANICED, &machine_state))
- return NOTIFY_DONE;
-
- /* Flash power LED */
- omap_writeb(0x78, OMAP_LPG1_LCR);
- omap_writeb(0x01, OMAP_LPG1_PMR); /* Enable clock */
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block panic_block = {
- .notifier_call = panic_event,
-};
-
-static int __init voiceblue_setup(void)
-{
- if (!machine_is_voiceblue())
- return -ENODEV;
-
- /* Setup panic notifier */
- atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
-
- return 0;
-}
-postcore_initcall(voiceblue_setup);
-
-static int wdt_gpio_state;
-
-void voiceblue_wdt_enable(void)
-{
- gpio_direction_output(0, 0);
- gpio_set_value(0, 1);
- gpio_set_value(0, 0);
- wdt_gpio_state = 0;
-}
-
-void voiceblue_wdt_disable(void)
-{
- gpio_set_value(0, 0);
- gpio_set_value(0, 1);
- gpio_set_value(0, 0);
- gpio_direction_input(0);
-}
-
-void voiceblue_wdt_ping(void)
-{
- if (test_bit(MACHINE_REBOOT, &machine_state))
- return;
-
- wdt_gpio_state = !wdt_gpio_state;
- gpio_set_value(0, wdt_gpio_state);
-}
-
-static void voiceblue_restart(enum reboot_mode mode, const char *cmd)
-{
- /*
- * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
- * "Global Software Reset Affects Traffic Controller Frequency".
- */
- if (cpu_is_omap5912()) {
- omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4), DPLL_CTL);
- omap_writew(0x8, ARM_RSTCT1);
- }
-
- set_bit(MACHINE_REBOOT, &machine_state);
- voiceblue_wdt_enable();
- while (1) ;
-}
-
-EXPORT_SYMBOL(voiceblue_wdt_enable);
-EXPORT_SYMBOL(voiceblue_wdt_disable);
-EXPORT_SYMBOL(voiceblue_wdt_ping);
-
-static void __init voiceblue_init(void)
-{
- /* mux pins for uarts */
- omap_cfg_reg(UART1_TX);
- omap_cfg_reg(UART1_RTS);
- omap_cfg_reg(UART2_TX);
- omap_cfg_reg(UART2_RTS);
- omap_cfg_reg(UART3_TX);
- omap_cfg_reg(UART3_RX);
-
- /* Watchdog */
- gpio_request(0, "Watchdog");
- /* smc91x reset */
- gpio_request(7, "SMC91x reset");
- gpio_direction_output(7, 1);
- udelay(2); /* wait at least 100ns */
- gpio_set_value(7, 0);
- mdelay(50); /* 50ms until PHY ready */
- /* smc91x interrupt pin */
- gpio_request(8, "SMC91x irq");
- /* 16C554 reset*/
- gpio_request(6, "16C554 reset");
- gpio_direction_output(6, 0);
- /* 16C554 interrupt pins */
- gpio_request(12, "16C554 irq");
- gpio_request(13, "16C554 irq");
- gpio_request(14, "16C554 irq");
- gpio_request(15, "16C554 irq");
- irq_set_irq_type(gpio_to_irq(12), IRQ_TYPE_EDGE_RISING);
- irq_set_irq_type(gpio_to_irq(13), IRQ_TYPE_EDGE_RISING);
- irq_set_irq_type(gpio_to_irq(14), IRQ_TYPE_EDGE_RISING);
- irq_set_irq_type(gpio_to_irq(15), IRQ_TYPE_EDGE_RISING);
-
- voiceblue_smc91x_resources[1].start = gpio_to_irq(8);
- voiceblue_smc91x_resources[1].end = gpio_to_irq(8);
- platform_add_devices(voiceblue_devices, ARRAY_SIZE(voiceblue_devices));
- omap_serial_init();
- omap1_usb_init(&voiceblue_usb_config);
- omap_register_i2c_bus(1, 100, NULL, 0);
-
- /* There is a good chance board is going up, so enable power LED
- * (it is connected through invertor) */
- omap_writeb(0x00, OMAP_LPG1_LCR);
- omap_writeb(0x00, OMAP_LPG1_PMR); /* Disable clock */
-}
-
-MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
- /* Maintainer: Ladislav Michl <michl@2n.cz> */
- .atag_offset = 0x100,
- .map_io = omap15xx_map_io,
- .init_early = omap1_init_early,
- .init_irq = omap1_init_irq,
- .handle_irq = omap1_handle_irq,
- .init_machine = voiceblue_init,
- .init_late = omap1_init_late,
- .init_time = omap1_timer_init,
- .restart = voiceblue_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap1/include/mach/board-voiceblue.h b/arch/arm/mach-omap1/include/mach/board-voiceblue.h
deleted file mode 100644
index 27916b2..0000000
--- a/arch/arm/mach-omap1/include/mach/board-voiceblue.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2004 2N Telekomunikace, Ladislav Michl <michl@2n.cz>
- *
- * Hardware definitions for OMAP5910 based VoiceBlue board.
- *
- * 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_ARCH_VOICEBLUE_H
-#define __ASM_ARCH_VOICEBLUE_H
-
-extern void voiceblue_wdt_enable(void);
-extern void voiceblue_wdt_disable(void);
-extern void voiceblue_wdt_ping(void);
-
-#endif /* __ASM_ARCH_VOICEBLUE_H */
-
diff --git a/arch/arm/mach-omap1/include/mach/camera.h b/arch/arm/mach-omap1/include/mach/camera.h
index 847d00f..caa6c0d 100644
--- a/arch/arm/mach-omap1/include/mach/camera.h
+++ b/arch/arm/mach-omap1/include/mach/camera.h
@@ -1,7 +1,7 @@
#ifndef __ASM_ARCH_CAMERA_H_
#define __ASM_ARCH_CAMERA_H_
-#include <media/omap1_camera.h>
+#include <linux/platform_data/media/omap1_camera.h>
void omap1_camera_init(void *);
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index ddf9124..0517f0c 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -65,6 +65,8 @@ config SOC_AM43XX
select MACH_OMAP_GENERIC
select MIGHT_HAVE_CACHE_L2X0
select HAVE_ARM_SCU
+ select GENERIC_CLOCKEVENTS_BROADCAST
+ select HAVE_ARM_TWD
config SOC_DRA7XX
bool "TI DRA7XX"
@@ -97,6 +99,7 @@ config ARCH_OMAP2PLUS
select PINCTRL
select SOC_BUS
select OMAP_IRQCHIP
+ select CLKSRC_TI_32K
help
Systems based on OMAP2, OMAP3, OMAP4 or OMAP5
@@ -120,6 +123,7 @@ config ARCH_OMAP2PLUS_TYPICAL
select NEON if CPU_V7
select PM
select REGULATOR
+ select REGULATOR_FIXED_VOLTAGE
select TWL4030_CORE if ARCH_OMAP3 || ARCH_OMAP4
select TWL4030_POWER if ARCH_OMAP3 || ARCH_OMAP4
select VFP
@@ -200,7 +204,6 @@ config MACH_OMAP3_PANDORA
depends on ARCH_OMAP3
default y
select OMAP_PACKAGE_CBB
- select REGULATOR_FIXED_VOLTAGE if REGULATOR
config MACH_NOKIA_N810
bool
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 9358696..ceefcee 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -48,11 +48,9 @@ AFLAGS_sleep44xx.o :=-Wa,-march=armv7-a$(plus_sec)
# Functions loaded to SRAM
obj-$(CONFIG_SOC_OMAP2420) += sram242x.o
obj-$(CONFIG_SOC_OMAP2430) += sram243x.o
-obj-$(CONFIG_ARCH_OMAP3) += sram34xx.o
AFLAGS_sram242x.o :=-Wa,-march=armv6
AFLAGS_sram243x.o :=-Wa,-march=armv6
-AFLAGS_sram34xx.o :=-Wa,-march=armv7-a
# Restart code (OMAP4/5 currently in omap4-common.c)
obj-$(CONFIG_SOC_OMAP2420) += omap2-restart.o
@@ -186,7 +184,6 @@ obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpllcore.o
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_virt_prcm_set.o
obj-$(CONFIG_ARCH_OMAP2) += clkt2xxx_dpll.o
obj-$(CONFIG_ARCH_OMAP3) += $(clock-common)
-obj-$(CONFIG_ARCH_OMAP3) += clkt34xx_dpll3m2.o
obj-$(CONFIG_ARCH_OMAP4) += $(clock-common)
obj-$(CONFIG_SOC_AM33XX) += $(clock-common)
obj-$(CONFIG_SOC_OMAP5) += $(clock-common)
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index fb219a3..8098272 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -16,6 +16,7 @@
#include <linux/of_platform.h>
#include <linux/irqdomain.h>
+#include <asm/setup.h>
#include <asm/mach/arch.h>
#include "common.h"
@@ -46,7 +47,7 @@ DT_MACHINE_START(OMAP242X_DT, "Generic OMAP2420 (Flattened Device Tree)")
.map_io = omap242x_map_io,
.init_early = omap2420_init_early,
.init_machine = omap_generic_init,
- .init_time = omap2_sync32k_timer_init,
+ .init_time = omap_init_time,
.dt_compat = omap242x_boards_compat,
.restart = omap2xxx_restart,
MACHINE_END
@@ -63,7 +64,7 @@ DT_MACHINE_START(OMAP243X_DT, "Generic OMAP2430 (Flattened Device Tree)")
.map_io = omap243x_map_io,
.init_early = omap2430_init_early,
.init_machine = omap_generic_init,
- .init_time = omap2_sync32k_timer_init,
+ .init_time = omap_init_time,
.dt_compat = omap243x_boards_compat,
.restart = omap2xxx_restart,
MACHINE_END
@@ -76,13 +77,22 @@ static const char *const n900_boards_compat[] __initconst = {
NULL,
};
+/* Legacy userspace on Nokia N900 needs ATAGS exported in /proc/atags,
+ * save them while the data is still not overwritten
+ */
+static void __init rx51_reserve(void)
+{
+ save_atags((const struct tag *)(PAGE_OFFSET + 0x100));
+ omap_reserve();
+}
+
DT_MACHINE_START(OMAP3_N900_DT, "Nokia RX-51 board")
- .reserve = omap_reserve,
+ .reserve = rx51_reserve,
.map_io = omap3_map_io,
.init_early = omap3430_init_early,
.init_machine = omap_generic_init,
.init_late = omap3_init_late,
- .init_time = omap3_sync32k_timer_init,
+ .init_time = omap_init_time,
.dt_compat = n900_boards_compat,
.restart = omap3xxx_restart,
MACHINE_END
@@ -100,7 +110,7 @@ DT_MACHINE_START(OMAP3_DT, "Generic OMAP3 (Flattened Device Tree)")
.init_early = omap3430_init_early,
.init_machine = omap_generic_init,
.init_late = omap3_init_late,
- .init_time = omap3_sync32k_timer_init,
+ .init_time = omap_init_time,
.dt_compat = omap3_boards_compat,
.restart = omap3xxx_restart,
MACHINE_END
@@ -117,7 +127,7 @@ DT_MACHINE_START(OMAP36XX_DT, "Generic OMAP36xx (Flattened Device Tree)")
.init_early = omap3630_init_early,
.init_machine = omap_generic_init,
.init_late = omap3_init_late,
- .init_time = omap3_sync32k_timer_init,
+ .init_time = omap_init_time,
.dt_compat = omap36xx_boards_compat,
.restart = omap3xxx_restart,
MACHINE_END
@@ -276,7 +286,7 @@ DT_MACHINE_START(AM43_DT, "Generic AM43 (Flattened Device Tree)")
.init_late = am43xx_init_late,
.init_irq = omap_gic_of_init,
.init_machine = omap_generic_init,
- .init_time = omap3_gptimer_timer_init,
+ .init_time = omap4_local_timer_init,
.dt_compat = am43_boards_compat,
.restart = omap44xx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index c2975af..d9c3ffc 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -424,6 +424,6 @@ MACHINE_START(OMAP_LDP, "OMAP LDP board")
.init_irq = omap3_init_irq,
.init_machine = omap_ldp_init,
.init_late = omap3430_init_late,
- .init_time = omap3_sync32k_timer_init,
+ .init_time = omap_init_time,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index 14edcd7..0a0567f 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -39,7 +39,7 @@
#include <sound/tlv320aic3x.h>
#include <sound/tpa6130a2-plat.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
#include <linux/platform_data/leds-lp55xx.h>
#include <linux/platform_data/tsl2563.h>
@@ -48,7 +48,7 @@
#include <video/omap-panel-data.h>
#if defined(CONFIG_IR_RX51) || defined(CONFIG_IR_RX51_MODULE)
-#include <media/ir-rx51.h>
+#include <linux/platform_data/media/ir-rx51.h>
#endif
#include "mux.h"
diff --git a/arch/arm/mach-omap2/board-rx51.c b/arch/arm/mach-omap2/board-rx51.c
index 2d1e5a6..41161ca9 100644
--- a/arch/arm/mach-omap2/board-rx51.c
+++ b/arch/arm/mach-omap2/board-rx51.c
@@ -136,6 +136,6 @@ MACHINE_START(NOKIA_RX51, "Nokia RX-51 board")
.init_irq = omap3_init_irq,
.init_machine = rx51_init,
.init_late = omap3430_init_late,
- .init_time = omap3_sync32k_timer_init,
+ .init_time = omap_init_time,
.restart = omap3xxx_restart,
MACHINE_END
diff --git a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c b/arch/arm/mach-omap2/clkt34xx_dpll3m2.c
deleted file mode 100644
index 3f65213..0000000
--- a/arch/arm/mach-omap2/clkt34xx_dpll3m2.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * OMAP34xx M2 divider clock code
- *
- * Copyright (C) 2007-2008 Texas Instruments, Inc.
- * Copyright (C) 2007-2010 Nokia Corporation
- *
- * Paul Walmsley
- * Jouni Högander
- *
- * Parts of this code are based on code written by
- * Richard Woodruff, Tony Lindgren, Tuukka Tikkanen, Karthik Dasu
- *
- * 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.
- */
-#undef DEBUG
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-
-#include "clock.h"
-#include "clock3xxx.h"
-#include "sdrc.h"
-#include "sram.h"
-
-#define CYCLES_PER_MHZ 1000000
-
-struct clk *sdrc_ick_p, *arm_fck_p;
-
-/*
- * CORE DPLL (DPLL3) M2 divider rate programming functions
- *
- * These call into SRAM code to do the actual CM writes, since the SDRAM
- * is clocked from DPLL3.
- */
-
-/**
- * omap3_core_dpll_m2_set_rate - set CORE DPLL M2 divider
- * @clk: struct clk * of DPLL to set
- * @rate: rounded target rate
- *
- * Program the DPLL M2 divider with the rounded target rate. Returns
- * -EINVAL upon error, or 0 upon success.
- */
-int omap3_core_dpll_m2_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
-{
- struct clk_hw_omap *clk = to_clk_hw_omap(hw);
- u32 new_div = 0;
- u32 unlock_dll = 0;
- u32 c;
- unsigned long validrate, sdrcrate, _mpurate;
- struct omap_sdrc_params *sdrc_cs0;
- struct omap_sdrc_params *sdrc_cs1;
- int ret;
- unsigned long clkrate;
-
- if (!clk || !rate)
- return -EINVAL;
-
- new_div = DIV_ROUND_UP(parent_rate, rate);
- validrate = parent_rate / new_div;
-
- if (validrate != rate)
- return -EINVAL;
-
- sdrcrate = clk_get_rate(sdrc_ick_p);
- clkrate = clk_hw_get_rate(hw);
- if (rate > clkrate)
- sdrcrate <<= ((rate / clkrate) >> 1);
- else
- sdrcrate >>= ((clkrate / rate) >> 1);
-
- ret = omap2_sdrc_get_params(sdrcrate, &sdrc_cs0, &sdrc_cs1);
- if (ret)
- return -EINVAL;
-
- if (sdrcrate < MIN_SDRC_DLL_LOCK_FREQ) {
- pr_debug("clock: will unlock SDRC DLL\n");
- unlock_dll = 1;
- }
-
- /*
- * XXX This only needs to be done when the CPU frequency changes
- */
- _mpurate = clk_get_rate(arm_fck_p) / CYCLES_PER_MHZ;
- c = (_mpurate << SDRC_MPURATE_SCALE) >> SDRC_MPURATE_BASE_SHIFT;
- c += 1; /* for safety */
- c *= SDRC_MPURATE_LOOPS;
- c >>= SDRC_MPURATE_SCALE;
- if (c == 0)
- c = 1;
-
- pr_debug("clock: changing CORE DPLL rate from %lu to %lu\n",
- clkrate, validrate);
- pr_debug("clock: SDRC CS0 timing params used: RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
- sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla,
- sdrc_cs0->actim_ctrlb, sdrc_cs0->mr);
- if (sdrc_cs1)
- pr_debug("clock: SDRC CS1 timing params used: RFR %08x CTRLA %08x CTRLB %08x MR %08x\n",
- sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla,
- sdrc_cs1->actim_ctrlb, sdrc_cs1->mr);
-
- if (sdrc_cs1)
- omap3_configure_core_dpll(
- new_div, unlock_dll, c, rate > clkrate,
- sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla,
- sdrc_cs0->actim_ctrlb, sdrc_cs0->mr,
- sdrc_cs1->rfr_ctrl, sdrc_cs1->actim_ctrla,
- sdrc_cs1->actim_ctrlb, sdrc_cs1->mr);
- else
- omap3_configure_core_dpll(
- new_div, unlock_dll, c, rate > clkrate,
- sdrc_cs0->rfr_ctrl, sdrc_cs0->actim_ctrla,
- sdrc_cs0->actim_ctrlb, sdrc_cs0->mr,
- 0, 0, 0, 0);
- return 0;
-}
-
diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h
index 92e92cf..0cba957 100644
--- a/arch/arm/mach-omap2/common.h
+++ b/arch/arm/mach-omap2/common.h
@@ -88,8 +88,7 @@ static inline int omap_mux_late_init(void)
extern void omap2_init_common_infrastructure(void);
-extern void omap2_sync32k_timer_init(void);
-extern void omap3_sync32k_timer_init(void);
+extern void omap_init_time(void);
extern void omap3_secure_sync32k_timer_init(void);
extern void omap3_gptimer_timer_init(void);
extern void omap4_local_timer_init(void);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index a69bd67..9374da3 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -33,7 +33,6 @@
#include "common.h"
#include "mux.h"
#include "control.h"
-#include "devices.h"
#include "display.h"
#define L3_MODULES_MAX_LEN 12
@@ -67,58 +66,6 @@ static int __init omap3_l3_init(void)
}
omap_postcore_initcall(omap3_l3_init);
-#if defined(CONFIG_IOMMU_API)
-
-#include <linux/platform_data/iommu-omap.h>
-
-static struct resource omap3isp_resources[] = {
- {
- .start = OMAP3430_ISP_BASE,
- .end = OMAP3430_ISP_BASE + 0x12fc,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = OMAP3430_ISP_BASE2,
- .end = OMAP3430_ISP_BASE2 + 0x0600,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 24 + OMAP_INTC_START,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device omap3isp_device = {
- .name = "omap3isp",
- .id = -1,
- .num_resources = ARRAY_SIZE(omap3isp_resources),
- .resource = omap3isp_resources,
-};
-
-static struct omap_iommu_arch_data omap3_isp_iommu = {
- .name = "mmu_isp",
-};
-
-int omap3_init_camera(struct isp_platform_data *pdata)
-{
- if (of_have_populated_dt())
- omap3_isp_iommu.name = "480bd400.mmu";
-
- omap3isp_device.dev.platform_data = pdata;
- omap3isp_device.dev.archdata.iommu = &omap3_isp_iommu;
-
- return platform_device_register(&omap3isp_device);
-}
-
-#else /* !CONFIG_IOMMU_API */
-
-int omap3_init_camera(struct isp_platform_data *pdata)
-{
- return 0;
-}
-
-#endif
-
#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
static inline void __init omap_init_mbox(void)
{
diff --git a/arch/arm/mach-omap2/devices.h b/arch/arm/mach-omap2/devices.h
deleted file mode 100644
index f61eb6e..0000000
--- a/arch/arm/mach-omap2/devices.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * arch/arm/mach-omap2/devices.h
- *
- * OMAP2 platform device setup/initialization
- *
- * 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 __ARCH_ARM_MACH_OMAP_DEVICES_H
-#define __ARCH_ARM_MACH_OMAP_DEVICES_H
-
-struct isp_platform_data;
-
-int omap3_init_camera(struct isp_platform_data *pdata);
-
-#endif
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 17a6f75..7b76ce0 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -149,8 +149,8 @@ static int omap2_onenand_get_freq(struct omap_onenand_platform_data *cfg,
freq = 104;
break;
default:
- freq = 54;
- break;
+ pr_err("onenand rate not detected, bad GPMC async timings?\n");
+ freq = 0;
}
return freq;
@@ -271,6 +271,11 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
struct gpmc_timings t;
int ret;
+ /*
+ * Note that we need to keep sync_write set for the call to
+ * omap2_onenand_set_async_mode() to work to detect the onenand
+ * supported clock rate for the sync timings.
+ */
if (gpmc_onenand_data->of_node) {
gpmc_read_settings_dt(gpmc_onenand_data->of_node,
&onenand_async);
@@ -281,12 +286,9 @@ static int omap2_onenand_setup_async(void __iomem *onenand_base)
else
gpmc_onenand_data->flags |= ONENAND_SYNC_READ;
onenand_async.sync_read = false;
- onenand_async.sync_write = false;
}
}
- omap2_onenand_set_async_mode(onenand_base);
-
omap2_onenand_calc_async_timings(&t);
ret = gpmc_cs_program_settings(gpmc_onenand_data->cs, &onenand_async);
@@ -310,6 +312,8 @@ static int omap2_onenand_setup_sync(void __iomem *onenand_base, int *freq_ptr)
if (!freq) {
/* Very first call freq is not known */
freq = omap2_onenand_get_freq(gpmc_onenand_data, onenand_base);
+ if (!freq)
+ return -ENODEV;
set_onenand_cfg(onenand_base);
}
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 54a5ba5..8a2ae82 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -57,15 +57,15 @@ int omap_type(void)
if (val < OMAP2_DEVICETYPE_MASK)
return val;
- if (cpu_is_omap24xx()) {
+ if (soc_is_omap24xx()) {
val = omap_ctrl_readl(OMAP24XX_CONTROL_STATUS);
- } else if (cpu_is_ti81xx()) {
+ } else if (soc_is_ti81xx()) {
val = omap_ctrl_readl(TI81XX_CONTROL_STATUS);
} else if (soc_is_am33xx() || soc_is_am43xx()) {
val = omap_ctrl_readl(AM33XX_CONTROL_STATUS);
- } else if (cpu_is_omap34xx()) {
+ } else if (soc_is_omap34xx()) {
val = omap_ctrl_readl(OMAP343X_CONTROL_STATUS);
- } else if (cpu_is_omap44xx()) {
+ } else if (soc_is_omap44xx()) {
val = omap_ctrl_readl(OMAP4_CTRL_MODULE_CORE_STATUS);
} else if (soc_is_omap54xx() || soc_is_dra7xx()) {
val = omap_ctrl_readl(OMAP5XXX_CONTROL_STATUS);
@@ -122,7 +122,7 @@ static u16 tap_prod_id;
void omap_get_die_id(struct omap_die_id *odi)
{
- if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
+ if (soc_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
odi->id_0 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_0);
odi->id_1 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_1);
odi->id_2 = read_tap_reg(OMAP_TAP_DIE_ID_44XX_2);
@@ -218,17 +218,17 @@ static void __init omap3_cpuinfo(void)
* on available features. Upon detection, update the CPU id
* and CPU class bits.
*/
- if (cpu_is_omap3630()) {
+ if (soc_is_omap3630()) {
cpu_name = "OMAP3630";
} else if (soc_is_am35xx()) {
cpu_name = (omap3_has_sgx()) ? "AM3517" : "AM3505";
- } else if (cpu_is_ti816x()) {
+ } else if (soc_is_ti816x()) {
cpu_name = "TI816X";
} else if (soc_is_am335x()) {
cpu_name = "AM335X";
} else if (soc_is_am437x()) {
cpu_name = "AM437x";
- } else if (cpu_is_ti814x()) {
+ } else if (soc_is_ti814x()) {
cpu_name = "TI814X";
} else if (omap3_has_iva() && omap3_has_sgx()) {
/* OMAP3430, OMAP3525, OMAP3515, OMAP3503 devices */
@@ -275,11 +275,11 @@ void __init omap3xxx_check_features(void)
OMAP3_CHECK_FEATURE(status, SGX);
OMAP3_CHECK_FEATURE(status, NEON);
OMAP3_CHECK_FEATURE(status, ISP);
- if (cpu_is_omap3630())
+ if (soc_is_omap3630())
omap_features |= OMAP3_HAS_192MHZ_CLK;
- if (cpu_is_omap3430() || cpu_is_omap3630())
+ if (soc_is_omap3430() || soc_is_omap3630())
omap_features |= OMAP3_HAS_IO_WAKEUP;
- if (cpu_is_omap3630() || omap_rev() == OMAP3430_REV_ES3_1 ||
+ if (soc_is_omap3630() || omap_rev() == OMAP3430_REV_ES3_1 ||
omap_rev() == OMAP3430_REV_ES3_1_2)
omap_features |= OMAP3_HAS_IO_CHAIN_CTRL;
@@ -701,7 +701,7 @@ void __init omap2_set_globals_tap(u32 class, void __iomem *tap)
tap_base = tap;
/* XXX What is this intended to do? */
- if (cpu_is_omap34xx())
+ if (soc_is_omap34xx())
tap_prod_id = 0x0210;
else
tap_prod_id = 0x0208;
@@ -719,11 +719,11 @@ static const char * const omap_types[] = {
static const char * __init omap_get_family(void)
{
- if (cpu_is_omap24xx())
+ if (soc_is_omap24xx())
return kasprintf(GFP_KERNEL, "OMAP2");
- else if (cpu_is_omap34xx())
+ else if (soc_is_omap34xx())
return kasprintf(GFP_KERNEL, "OMAP3");
- else if (cpu_is_omap44xx())
+ else if (soc_is_omap44xx())
return kasprintf(GFP_KERNEL, "OMAP4");
else if (soc_is_omap54xx())
return kasprintf(GFP_KERNEL, "OMAP5");
diff --git a/arch/arm/mach-omap2/omap-hotplug.c b/arch/arm/mach-omap2/omap-hotplug.c
index 971791f..593fec7 100644
--- a/arch/arm/mach-omap2/omap-hotplug.c
+++ b/arch/arm/mach-omap2/omap-hotplug.c
@@ -27,7 +27,7 @@
* platform-specific code to shutdown a CPU
* Called with IRQs disabled
*/
-void __ref omap4_cpu_die(unsigned int cpu)
+void omap4_cpu_die(unsigned int cpu)
{
unsigned int boot_cpu = 0;
void __iomem *base = omap_get_wakeupgen_base();
diff --git a/arch/arm/mach-omap2/omap-smp.c b/arch/arm/mach-omap2/omap-smp.c
index 5305ec7..79e1f87 100644
--- a/arch/arm/mach-omap2/omap-smp.c
+++ b/arch/arm/mach-omap2/omap-smp.c
@@ -143,9 +143,9 @@ static int omap4_boot_secondary(unsigned int cpu, struct task_struct *idle)
* Ensure that CPU power state is set to ON to avoid CPU
* powerdomain transition on wfi
*/
- clkdm_wakeup(cpu1_clkdm);
- omap_set_pwrdm_state(cpu1_pwrdm, PWRDM_POWER_ON);
- clkdm_allow_idle(cpu1_clkdm);
+ clkdm_wakeup_nolock(cpu1_clkdm);
+ pwrdm_set_next_pwrst(cpu1_pwrdm, PWRDM_POWER_ON);
+ clkdm_allow_idle_nolock(cpu1_clkdm);
if (IS_PM44XX_ERRATUM(PM_OMAP4_ROM_SMP_BOOT_ERRATUM_GICD)) {
while (gic_dist_disabled()) {
diff --git a/arch/arm/mach-omap2/omap-wakeupgen.c b/arch/arm/mach-omap2/omap-wakeupgen.c
index db7e0ba..f397bd6 100644
--- a/arch/arm/mach-omap2/omap-wakeupgen.c
+++ b/arch/arm/mach-omap2/omap-wakeupgen.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/irq.h>
+#include <linux/irqchip.h>
#include <linux/irqdomain.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -330,7 +331,7 @@ static int irq_cpu_hotplug_notify(struct notifier_block *self,
return NOTIFY_OK;
}
-static struct notifier_block __refdata irq_hotplug_notifier = {
+static struct notifier_block irq_hotplug_notifier = {
.notifier_call = irq_cpu_hotplug_notify,
};
@@ -540,9 +541,4 @@ static int __init wakeupgen_init(struct device_node *node,
return 0;
}
-
-/*
- * We cannot use the IRQCHIP_DECLARE macro that lives in
- * drivers/irqchip, so we're forced to roll our own. Not very nice.
- */
-OF_DECLARE_2(irqchip, ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
+IRQCHIP_DECLARE(ti_wakeupgen, "ti,omap4-wugen-mpu", wakeupgen_init);
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index cc8a987..48495ad 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -890,6 +890,36 @@ static int _init_opt_clks(struct omap_hwmod *oh)
return ret;
}
+static void _enable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk) {
+ pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
+ __clk_get_name(oc->_clk));
+ clk_enable(oc->_clk);
+ }
+}
+
+static void _disable_optional_clocks(struct omap_hwmod *oh)
+{
+ struct omap_hwmod_opt_clk *oc;
+ int i;
+
+ pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
+
+ for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
+ if (oc->_clk) {
+ pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
+ __clk_get_name(oc->_clk));
+ clk_disable(oc->_clk);
+ }
+}
+
/**
* _enable_clocks - enable hwmod main clock and interface clocks
* @oh: struct omap_hwmod *
@@ -917,6 +947,9 @@ static int _enable_clocks(struct omap_hwmod *oh)
clk_enable(os->_clk);
}
+ if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+ _enable_optional_clocks(oh);
+
/* The opt clocks are controlled by the device driver. */
return 0;
@@ -948,41 +981,14 @@ static int _disable_clocks(struct omap_hwmod *oh)
clk_disable(os->_clk);
}
+ if (oh->flags & HWMOD_OPT_CLKS_NEEDED)
+ _disable_optional_clocks(oh);
+
/* The opt clocks are controlled by the device driver. */
return 0;
}
-static void _enable_optional_clocks(struct omap_hwmod *oh)
-{
- struct omap_hwmod_opt_clk *oc;
- int i;
-
- pr_debug("omap_hwmod: %s: enabling optional clocks\n", oh->name);
-
- for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
- if (oc->_clk) {
- pr_debug("omap_hwmod: enable %s:%s\n", oc->role,
- __clk_get_name(oc->_clk));
- clk_enable(oc->_clk);
- }
-}
-
-static void _disable_optional_clocks(struct omap_hwmod *oh)
-{
- struct omap_hwmod_opt_clk *oc;
- int i;
-
- pr_debug("omap_hwmod: %s: disabling optional clocks\n", oh->name);
-
- for (i = oh->opt_clks_cnt, oc = oh->opt_clks; i > 0; i--, oc++)
- if (oc->_clk) {
- pr_debug("omap_hwmod: disable %s:%s\n", oc->role,
- __clk_get_name(oc->_clk));
- clk_disable(oc->_clk);
- }
-}
-
/**
* _omap4_enable_module - enable CLKCTRL modulemode on OMAP4
* @oh: struct omap_hwmod *
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index ca6df1a..76bce11 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -523,6 +523,8 @@ struct omap_hwmod_omap4_prcm {
* HWMOD_RECONFIG_IO_CHAIN: omap_hwmod code needs to reconfigure wake-up
* events by calling _reconfigure_io_chain() when a device is enabled
* or idled.
+ * HWMOD_OPT_CLKS_NEEDED: The optional clocks are needed for the module to
+ * operate and they need to be handled at the same time as the main_clk.
*/
#define HWMOD_SWSUP_SIDLE (1 << 0)
#define HWMOD_SWSUP_MSTANDBY (1 << 1)
@@ -538,6 +540,7 @@ struct omap_hwmod_omap4_prcm {
#define HWMOD_FORCE_MSTANDBY (1 << 11)
#define HWMOD_SWSUP_SIDLE_ACT (1 << 12)
#define HWMOD_RECONFIG_IO_CHAIN (1 << 13)
+#define HWMOD_OPT_CLKS_NEEDED (1 << 14)
/*
* omap_hwmod._int_flags definitions
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
index 8f5989d..1c210cb 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_interconnect_data.c
@@ -152,20 +152,10 @@ struct omap_hwmod_ocp_if am33xx_cpgmac0__mdio = {
.user = OCP_USER_MPU,
};
-static struct omap_hwmod_addr_space am33xx_elm_addr_space[] = {
- {
- .pa_start = 0x48080000,
- .pa_end = 0x48080000 + SZ_8K - 1,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
struct omap_hwmod_ocp_if am33xx_l4_ls__elm = {
.master = &am33xx_l4_ls_hwmod,
.slave = &am33xx_elm_hwmod,
.clk = "l4ls_gclk",
- .addr = am33xx_elm_addr_space,
.user = OCP_USER_MPU,
};
@@ -285,20 +275,10 @@ struct omap_hwmod_ocp_if am33xx_epwmss2__ehrpwm2 = {
};
/* l3s cfg -> gpmc */
-static struct omap_hwmod_addr_space am33xx_gpmc_addr_space[] = {
- {
- .pa_start = 0x50000000,
- .pa_end = 0x50000000 + SZ_8K - 1,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
struct omap_hwmod_ocp_if am33xx_l3_s__gpmc = {
.master = &am33xx_l3_s_hwmod,
.slave = &am33xx_gpmc_hwmod,
.clk = "l3s_gclk",
- .addr = am33xx_gpmc_addr_space,
.user = OCP_USER_MPU,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index dc55f8d..aff78d5 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -26,7 +26,6 @@
#include <linux/platform_data/asoc-ti-mcbsp.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/platform_data/iommu-omap.h>
-#include <linux/platform_data/mailbox-omap.h>
#include <plat/dmtimer.h>
#include "soc.h"
@@ -1506,26 +1505,9 @@ static struct omap_hwmod_class omap3xxx_mailbox_hwmod_class = {
.sysc = &omap3xxx_mailbox_sysc,
};
-static struct omap_mbox_dev_info omap3xxx_mailbox_info[] = {
- { .name = "dsp", .tx_id = 0, .rx_id = 1 },
-};
-
-static struct omap_mbox_pdata omap3xxx_mailbox_attrs = {
- .num_users = 2,
- .num_fifos = 2,
- .info_cnt = ARRAY_SIZE(omap3xxx_mailbox_info),
- .info = omap3xxx_mailbox_info,
-};
-
-static struct omap_hwmod_irq_info omap3xxx_mailbox_irqs[] = {
- { .irq = 26 + OMAP_INTC_START, },
- { .irq = -1 },
-};
-
static struct omap_hwmod omap3xxx_mailbox_hwmod = {
.name = "mailbox",
.class = &omap3xxx_mailbox_hwmod_class,
- .mpu_irqs = omap3xxx_mailbox_irqs,
.main_clk = "mailboxes_ick",
.prcm = {
.omap2 = {
@@ -1536,7 +1518,6 @@ static struct omap_hwmod omap3xxx_mailbox_hwmod = {
.idlest_idle_bit = OMAP3430_ST_MAILBOXES_SHIFT,
},
},
- .dev_attr = &omap3xxx_mailbox_attrs,
};
/*
@@ -3276,20 +3257,10 @@ static struct omap_hwmod_ocp_if omap3xxx_l4_per__mcbsp3_sidetone = {
.user = OCP_USER_MPU,
};
-static struct omap_hwmod_addr_space omap3xxx_mailbox_addrs[] = {
- {
- .pa_start = 0x48094000,
- .pa_end = 0x480941ff,
- .flags = ADDR_TYPE_RT,
- },
- { }
-};
-
/* l4_core -> mailbox */
static struct omap_hwmod_ocp_if omap3xxx_l4_core__mailbox = {
.master = &omap3xxx_l4_core_hwmod,
.slave = &omap3xxx_mailbox_hwmod,
- .addr = omap3xxx_mailbox_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 43eebf2..a5e444b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -4471,21 +4471,11 @@ static struct omap_hwmod_ocp_if omap44xx_l4_cfg__smartreflex_mpu = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_addr_space omap44xx_spinlock_addrs[] = {
- {
- .pa_start = 0x4a0f6000,
- .pa_end = 0x4a0f6fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
/* l4_cfg -> spinlock */
static struct omap_hwmod_ocp_if omap44xx_l4_cfg__spinlock = {
.master = &omap44xx_l4_cfg_hwmod,
.slave = &omap44xx_spinlock_hwmod,
.clk = "l4_div_ck",
- .addr = omap44xx_spinlock_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
index 7c3fac0..8cdfd9b 100644
--- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
@@ -1844,8 +1844,7 @@ static struct omap_hwmod_class_sysconfig omap54xx_usb_host_hs_sysc = {
.rev_offs = 0x0000,
.sysc_offs = 0x0010,
.sysc_flags = (SYSC_HAS_MIDLEMODE | SYSC_HAS_RESET_STATUS |
- SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET |
- SYSC_HAS_RESET_STATUS),
+ SYSC_HAS_SIDLEMODE | SYSC_HAS_SOFTRESET),
.idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
SIDLE_SMART_WKUP | MSTANDBY_FORCE | MSTANDBY_NO |
MSTANDBY_SMART | MSTANDBY_SMART_WKUP),
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 562247b..ee4e044 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -1298,6 +1298,44 @@ static struct omap_hwmod dra7xx_mcspi4_hwmod = {
};
/*
+ * 'mcasp' class
+ *
+ */
+static struct omap_hwmod_class_sysconfig dra7xx_mcasp_sysc = {
+ .sysc_offs = 0x0004,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART),
+ .sysc_fields = &omap_hwmod_sysc_type3,
+};
+
+static struct omap_hwmod_class dra7xx_mcasp_hwmod_class = {
+ .name = "mcasp",
+ .sysc = &dra7xx_mcasp_sysc,
+};
+
+/* mcasp3 */
+static struct omap_hwmod_opt_clk mcasp3_opt_clks[] = {
+ { .role = "ahclkx", .clk = "mcasp3_ahclkx_mux" },
+};
+
+static struct omap_hwmod dra7xx_mcasp3_hwmod = {
+ .name = "mcasp3",
+ .class = &dra7xx_mcasp_hwmod_class,
+ .clkdm_name = "l4per2_clkdm",
+ .main_clk = "mcasp3_aux_gfclk_mux",
+ .flags = HWMOD_OPT_CLKS_NEEDED,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_L4PER2_MCASP3_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_L4PER2_MCASP3_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+ .opt_clks = mcasp3_opt_clks,
+ .opt_clks_cnt = ARRAY_SIZE(mcasp3_opt_clks),
+};
+
+/*
* 'mmc' class
*
*/
@@ -2566,13 +2604,20 @@ static struct omap_hwmod_ocp_if dra7xx_l3_main_1__hdmi = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_addr_space dra7xx_elm_addrs[] = {
- {
- .pa_start = 0x48078000,
- .pa_end = 0x48078fff,
- .flags = ADDR_TYPE_RT
- },
- { }
+/* l4_per2 -> mcasp3 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__mcasp3 = {
+ .master = &dra7xx_l4_per2_hwmod,
+ .slave = &dra7xx_mcasp3_hwmod,
+ .clk = "l4_root_clk_div",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l3_main_1 -> mcasp3 */
+static struct omap_hwmod_ocp_if dra7xx_l3_main_1__mcasp3 = {
+ .master = &dra7xx_l3_main_1_hwmod,
+ .slave = &dra7xx_mcasp3_hwmod,
+ .clk = "l3_iclk_div",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
};
/* l4_per1 -> elm */
@@ -2580,7 +2625,6 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__elm = {
.master = &dra7xx_l4_per1_hwmod,
.slave = &dra7xx_elm_hwmod,
.clk = "l3_iclk_div",
- .addr = dra7xx_elm_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -2648,21 +2692,11 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__gpio8 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_addr_space dra7xx_gpmc_addrs[] = {
- {
- .pa_start = 0x50000000,
- .pa_end = 0x500003ff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
/* l3_main_1 -> gpmc */
static struct omap_hwmod_ocp_if dra7xx_l3_main_1__gpmc = {
.master = &dra7xx_l3_main_1_hwmod,
.slave = &dra7xx_gpmc_hwmod,
.clk = "l3_iclk_div",
- .addr = dra7xx_gpmc_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -3029,21 +3063,11 @@ static struct omap_hwmod_ocp_if dra7xx_l4_cfg__smartreflex_mpu = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
-static struct omap_hwmod_addr_space dra7xx_spinlock_addrs[] = {
- {
- .pa_start = 0x4a0f6000,
- .pa_end = 0x4a0f6fff,
- .flags = ADDR_TYPE_RT
- },
- { }
-};
-
/* l4_cfg -> spinlock */
static struct omap_hwmod_ocp_if dra7xx_l4_cfg__spinlock = {
.master = &dra7xx_l4_cfg_hwmod,
.slave = &dra7xx_spinlock_hwmod,
.clk = "l3_iclk_div",
- .addr = dra7xx_spinlock_addrs,
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
@@ -3338,6 +3362,8 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
&dra7xx_l4_wkup__dcan1,
&dra7xx_l4_per2__dcan2,
&dra7xx_l4_per2__cpgmac0,
+ &dra7xx_l4_per2__mcasp3,
+ &dra7xx_l3_main_1__mcasp3,
&dra7xx_gmac__mdio,
&dra7xx_l4_cfg__dma_system,
&dra7xx_l3_main_1__dss,
diff --git a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
index b1288f5..6256052 100644
--- a/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_81xx_data.c
@@ -144,6 +144,7 @@ static struct omap_hwmod dm81xx_l4_ls_hwmod = {
.name = "l4_ls",
.clkdm_name = "alwon_l3s_clkdm",
.class = &l4_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
};
/*
@@ -155,6 +156,7 @@ static struct omap_hwmod dm81xx_l4_hs_hwmod = {
.name = "l4_hs",
.clkdm_name = "alwon_l3_med_clkdm",
.class = &l4_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
};
/* L3 slow -> L4 ls peripheral interface running at 125MHz */
@@ -850,6 +852,7 @@ static struct omap_hwmod dm816x_emac0_hwmod = {
.name = "emac0",
.clkdm_name = "alwon_ethernet_clkdm",
.class = &dm816x_emac_hwmod_class,
+ .flags = HWMOD_NO_IDLEST,
};
static struct omap_hwmod_ocp_if dm81xx_l4_hs__emac0 = {
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index 1dfe346..5814477 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -24,9 +24,6 @@
#include <linux/platform_data/iommu-omap.h>
#include <linux/platform_data/wkup_m3.h>
-#include <asm/siginfo.h>
-#include <asm/signal.h>
-
#include "common.h"
#include "common-board-devices.h"
#include "dss-common.h"
@@ -385,29 +382,6 @@ static void __init omap3_pandora_legacy_init(void)
}
#endif /* CONFIG_ARCH_OMAP3 */
-#ifdef CONFIG_SOC_TI81XX
-static int fault_fixed_up;
-
-static int t410_abort_handler(unsigned long addr, unsigned int fsr,
- struct pt_regs *regs)
-{
- if ((fsr == 0x406 || fsr == 0xc06) && !fault_fixed_up) {
- pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n",
- addr, fsr);
- fault_fixed_up = 1;
- return 0;
- }
-
- return 1;
-}
-
-static void __init t410_abort_init(void)
-{
- hook_fault_code(16 + 6, t410_abort_handler, SIGBUS, BUS_OBJERR,
- "imprecise external abort");
-}
-#endif
-
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5)
static struct iommu_platform_data omap4_iommu_pdata = {
.reset_name = "mmu_cache",
@@ -536,9 +510,6 @@ static struct pdata_init pdata_quirks[] __initdata = {
{ "openpandora,omap3-pandora-600mhz", omap3_pandora_legacy_init, },
{ "openpandora,omap3-pandora-1ghz", omap3_pandora_legacy_init, },
#endif
-#ifdef CONFIG_SOC_TI81XX
- { "hp,t410", t410_abort_init, },
-#endif
#ifdef CONFIG_SOC_OMAP5
{ "ti,omap5-uevm", omap5_uevm_legacy_init, },
#endif
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 87b98bf9..2dbd378 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -301,11 +301,11 @@ static void omap3_pm_idle(void)
if (omap_irq_pending())
return;
- trace_cpu_idle(1, smp_processor_id());
+ trace_cpu_idle_rcuidle(1, smp_processor_id());
omap_sram_idle();
- trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+ trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
}
#ifdef CONFIG_SUSPEND
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index d697cec..178e22c 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -210,7 +210,7 @@ static inline int omap4plus_init_static_deps(const struct static_dep_map *map)
}
map++;
- };
+ }
return 0;
}
diff --git a/arch/arm/mach-omap2/powerdomains3xxx_data.c b/arch/arm/mach-omap2/powerdomains3xxx_data.c
index d31c495..2e00c7f 100644
--- a/arch/arm/mach-omap2/powerdomains3xxx_data.c
+++ b/arch/arm/mach-omap2/powerdomains3xxx_data.c
@@ -582,7 +582,7 @@ void __init omap3xxx_powerdomains_init(void)
/* Only 81xx needs custom pwrdm_operations */
if (!cpu_is_ti81xx())
- pwrdm_register_platform_funcs(&omap3_pwrdm_operations);;
+ pwrdm_register_platform_funcs(&omap3_pwrdm_operations);
rev = omap_rev();
diff --git a/arch/arm/mach-omap2/soc.h b/arch/arm/mach-omap2/soc.h
index 2d1d384..79ca3c3 100644
--- a/arch/arm/mach-omap2/soc.h
+++ b/arch/arm/mach-omap2/soc.h
@@ -129,9 +129,9 @@ int omap_type(void);
/*
* omap_rev bits:
- * CPU id bits (0730, 1510, 1710, 2422...) [31:16]
- * CPU revision (See _REV_ defined in cpu.h) [15:08]
- * CPU class bits (15xx, 16xx, 24xx, 34xx...) [07:00]
+ * SoC id bits (0730, 1510, 1710, 2422...) [31:16]
+ * SoC revision (See _REV_ defined in cpu.h) [15:08]
+ * SoC class bits (15xx, 16xx, 24xx, 34xx...) [07:00]
*/
unsigned int omap_rev(void);
@@ -141,20 +141,20 @@ static inline int soc_is_omap(void)
}
/*
- * Get the CPU revision for OMAP devices
+ * Get the SoC revision for OMAP devices
*/
#define GET_OMAP_REVISION() ((omap_rev() >> 8) & 0xff)
/*
* Macros to group OMAP into cpu classes.
* These can be used in most places.
- * cpu_is_omap24xx(): True for OMAP2420, OMAP2422, OMAP2423, OMAP2430
- * cpu_is_omap242x(): True for OMAP2420, OMAP2422, OMAP2423
- * cpu_is_omap243x(): True for OMAP2430
- * cpu_is_omap343x(): True for OMAP3430
- * cpu_is_omap443x(): True for OMAP4430
- * cpu_is_omap446x(): True for OMAP4460
- * cpu_is_omap447x(): True for OMAP4470
+ * soc_is_omap24xx(): True for OMAP2420, OMAP2422, OMAP2423, OMAP2430
+ * soc_is_omap242x(): True for OMAP2420, OMAP2422, OMAP2423
+ * soc_is_omap243x(): True for OMAP2430
+ * soc_is_omap343x(): True for OMAP3430
+ * soc_is_omap443x(): True for OMAP4430
+ * soc_is_omap446x(): True for OMAP4460
+ * soc_is_omap447x(): True for OMAP4470
* soc_is_omap543x(): True for OMAP5430, OMAP5432
*/
#define GET_OMAP_CLASS (omap_rev() & 0xff)
@@ -225,23 +225,23 @@ IS_TI_SUBCLASS(814x, 0x814)
IS_AM_SUBCLASS(335x, 0x335)
IS_AM_SUBCLASS(437x, 0x437)
-#define cpu_is_omap24xx() 0
-#define cpu_is_omap242x() 0
-#define cpu_is_omap243x() 0
-#define cpu_is_omap34xx() 0
-#define cpu_is_omap343x() 0
-#define cpu_is_ti81xx() 0
-#define cpu_is_ti816x() 0
-#define cpu_is_ti814x() 0
+#define soc_is_omap24xx() 0
+#define soc_is_omap242x() 0
+#define soc_is_omap243x() 0
+#define soc_is_omap34xx() 0
+#define soc_is_omap343x() 0
+#define soc_is_ti81xx() 0
+#define soc_is_ti816x() 0
+#define soc_is_ti814x() 0
#define soc_is_am35xx() 0
#define soc_is_am33xx() 0
#define soc_is_am335x() 0
#define soc_is_am43xx() 0
#define soc_is_am437x() 0
-#define cpu_is_omap44xx() 0
-#define cpu_is_omap443x() 0
-#define cpu_is_omap446x() 0
-#define cpu_is_omap447x() 0
+#define soc_is_omap44xx() 0
+#define soc_is_omap443x() 0
+#define soc_is_omap446x() 0
+#define soc_is_omap447x() 0
#define soc_is_omap54xx() 0
#define soc_is_omap543x() 0
#define soc_is_dra7xx() 0
@@ -250,54 +250,54 @@ IS_AM_SUBCLASS(437x, 0x437)
#if defined(MULTI_OMAP2)
# if defined(CONFIG_ARCH_OMAP2)
-# undef cpu_is_omap24xx
-# define cpu_is_omap24xx() is_omap24xx()
+# undef soc_is_omap24xx
+# define soc_is_omap24xx() is_omap24xx()
# endif
# if defined (CONFIG_SOC_OMAP2420)
-# undef cpu_is_omap242x
-# define cpu_is_omap242x() is_omap242x()
+# undef soc_is_omap242x
+# define soc_is_omap242x() is_omap242x()
# endif
# if defined (CONFIG_SOC_OMAP2430)
-# undef cpu_is_omap243x
-# define cpu_is_omap243x() is_omap243x()
+# undef soc_is_omap243x
+# define soc_is_omap243x() is_omap243x()
# endif
# if defined(CONFIG_ARCH_OMAP3)
-# undef cpu_is_omap34xx
-# undef cpu_is_omap343x
-# define cpu_is_omap34xx() is_omap34xx()
-# define cpu_is_omap343x() is_omap343x()
+# undef soc_is_omap34xx
+# undef soc_is_omap343x
+# define soc_is_omap34xx() is_omap34xx()
+# define soc_is_omap343x() is_omap343x()
# endif
#else
# if defined(CONFIG_ARCH_OMAP2)
-# undef cpu_is_omap24xx
-# define cpu_is_omap24xx() 1
+# undef soc_is_omap24xx
+# define soc_is_omap24xx() 1
# endif
# if defined(CONFIG_SOC_OMAP2420)
-# undef cpu_is_omap242x
-# define cpu_is_omap242x() 1
+# undef soc_is_omap242x
+# define soc_is_omap242x() 1
# endif
# if defined(CONFIG_SOC_OMAP2430)
-# undef cpu_is_omap243x
-# define cpu_is_omap243x() 1
+# undef soc_is_omap243x
+# define soc_is_omap243x() 1
# endif
# if defined(CONFIG_ARCH_OMAP3)
-# undef cpu_is_omap34xx
-# define cpu_is_omap34xx() 1
+# undef soc_is_omap34xx
+# define soc_is_omap34xx() 1
# endif
# if defined(CONFIG_SOC_OMAP3430)
-# undef cpu_is_omap343x
-# define cpu_is_omap343x() 1
+# undef soc_is_omap343x
+# define soc_is_omap343x() 1
# endif
#endif
/*
* Macros to detect individual cpu types.
* These are only rarely needed.
- * cpu_is_omap2420(): True for OMAP2420
- * cpu_is_omap2422(): True for OMAP2422
- * cpu_is_omap2423(): True for OMAP2423
- * cpu_is_omap2430(): True for OMAP2430
- * cpu_is_omap3430(): True for OMAP3430
+ * soc_is_omap2420(): True for OMAP2420
+ * soc_is_omap2422(): True for OMAP2422
+ * soc_is_omap2423(): True for OMAP2423
+ * soc_is_omap2430(): True for OMAP2430
+ * soc_is_omap3430(): True for OMAP3430
*/
#define GET_OMAP_TYPE ((omap_rev() >> 16) & 0xffff)
@@ -313,51 +313,51 @@ IS_OMAP_TYPE(2423, 0x2423)
IS_OMAP_TYPE(2430, 0x2430)
IS_OMAP_TYPE(3430, 0x3430)
-#define cpu_is_omap2420() 0
-#define cpu_is_omap2422() 0
-#define cpu_is_omap2423() 0
-#define cpu_is_omap2430() 0
-#define cpu_is_omap3430() 0
-#define cpu_is_omap3630() 0
+#define soc_is_omap2420() 0
+#define soc_is_omap2422() 0
+#define soc_is_omap2423() 0
+#define soc_is_omap2430() 0
+#define soc_is_omap3430() 0
+#define soc_is_omap3630() 0
#define soc_is_omap5430() 0
/* These are needed for the common code */
#ifdef CONFIG_ARCH_OMAP2PLUS
-#define cpu_is_omap7xx() 0
-#define cpu_is_omap15xx() 0
-#define cpu_is_omap16xx() 0
-#define cpu_is_omap1510() 0
-#define cpu_is_omap1610() 0
-#define cpu_is_omap1611() 0
-#define cpu_is_omap1621() 0
-#define cpu_is_omap1710() 0
+#define soc_is_omap7xx() 0
+#define soc_is_omap15xx() 0
+#define soc_is_omap16xx() 0
+#define soc_is_omap1510() 0
+#define soc_is_omap1610() 0
+#define soc_is_omap1611() 0
+#define soc_is_omap1621() 0
+#define soc_is_omap1710() 0
#define cpu_class_is_omap1() 0
#define cpu_class_is_omap2() 1
#endif
#if defined(CONFIG_ARCH_OMAP2)
-# undef cpu_is_omap2420
-# undef cpu_is_omap2422
-# undef cpu_is_omap2423
-# undef cpu_is_omap2430
-# define cpu_is_omap2420() is_omap2420()
-# define cpu_is_omap2422() is_omap2422()
-# define cpu_is_omap2423() is_omap2423()
-# define cpu_is_omap2430() is_omap2430()
+# undef soc_is_omap2420
+# undef soc_is_omap2422
+# undef soc_is_omap2423
+# undef soc_is_omap2430
+# define soc_is_omap2420() is_omap2420()
+# define soc_is_omap2422() is_omap2422()
+# define soc_is_omap2423() is_omap2423()
+# define soc_is_omap2430() is_omap2430()
#endif
#if defined(CONFIG_ARCH_OMAP3)
-# undef cpu_is_omap3430
-# undef cpu_is_ti81xx
-# undef cpu_is_ti816x
-# undef cpu_is_ti814x
+# undef soc_is_omap3430
+# undef soc_is_ti81xx
+# undef soc_is_ti816x
+# undef soc_is_ti814x
# undef soc_is_am35xx
-# define cpu_is_omap3430() is_omap3430()
-# undef cpu_is_omap3630
-# define cpu_is_omap3630() is_omap363x()
-# define cpu_is_ti81xx() is_ti81xx()
-# define cpu_is_ti816x() is_ti816x()
-# define cpu_is_ti814x() is_ti814x()
+# define soc_is_omap3430() is_omap3430()
+# undef soc_is_omap3630
+# define soc_is_omap3630() is_omap363x()
+# define soc_is_ti81xx() is_ti81xx()
+# define soc_is_ti816x() is_ti816x()
+# define soc_is_ti814x() is_ti814x()
# define soc_is_am35xx() is_am35xx()
#endif
@@ -376,14 +376,14 @@ IS_OMAP_TYPE(3430, 0x3430)
#endif
# if defined(CONFIG_ARCH_OMAP4)
-# undef cpu_is_omap44xx
-# undef cpu_is_omap443x
-# undef cpu_is_omap446x
-# undef cpu_is_omap447x
-# define cpu_is_omap44xx() is_omap44xx()
-# define cpu_is_omap443x() is_omap443x()
-# define cpu_is_omap446x() is_omap446x()
-# define cpu_is_omap447x() is_omap447x()
+# undef soc_is_omap44xx
+# undef soc_is_omap443x
+# undef soc_is_omap446x
+# undef soc_is_omap447x
+# define soc_is_omap44xx() is_omap44xx()
+# define soc_is_omap443x() is_omap443x()
+# define soc_is_omap446x() is_omap446x()
+# define soc_is_omap447x() is_omap447x()
# endif
# if defined(CONFIG_SOC_OMAP5)
@@ -556,5 +556,22 @@ level(__##fn);
#define omap_late_initcall(fn) omap_initcall(late_initcall, fn)
#define omap_late_initcall_sync(fn) omap_initcall(late_initcall_sync, fn)
-#endif /* __ASSEMBLY__ */
+/* Legacy defines, these can be removed when users are removed */
+#define cpu_is_omap2420() soc_is_omap2420()
+#define cpu_is_omap2422() soc_is_omap2422()
+#define cpu_is_omap242x() soc_is_omap242x()
+#define cpu_is_omap2430() soc_is_omap2430()
+#define cpu_is_omap243x() soc_is_omap243x()
+#define cpu_is_omap24xx() soc_is_omap24xx()
+#define cpu_is_omap3430() soc_is_omap3430()
+#define cpu_is_omap343x() soc_is_omap343x()
+#define cpu_is_omap34xx() soc_is_omap34xx()
+#define cpu_is_omap3630() soc_is_omap3630()
+#define cpu_is_omap443x() soc_is_omap443x()
+#define cpu_is_omap446x() soc_is_omap446x()
+#define cpu_is_omap44xx() soc_is_omap44xx()
+#define cpu_is_ti814x() soc_is_ti814x()
+#define cpu_is_ti816x() soc_is_ti816x()
+#define cpu_is_ti81xx() soc_is_ti81xx()
+#endif /* __ASSEMBLY__ */
diff --git a/arch/arm/mach-omap2/sram.c b/arch/arm/mach-omap2/sram.c
index cd488b8..83d0e61 100644
--- a/arch/arm/mach-omap2/sram.c
+++ b/arch/arm/mach-omap2/sram.c
@@ -211,35 +211,10 @@ static inline int omap243x_sram_init(void)
#ifdef CONFIG_ARCH_OMAP3
-static u32 (*_omap3_sram_configure_core_dpll)(
- u32 m2, u32 unlock_dll, u32 f, u32 inc,
- u32 sdrc_rfr_ctrl_0, u32 sdrc_actim_ctrl_a_0,
- u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0,
- u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1,
- u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1);
-
-u32 omap3_configure_core_dpll(u32 m2, u32 unlock_dll, u32 f, u32 inc,
- u32 sdrc_rfr_ctrl_0, u32 sdrc_actim_ctrl_a_0,
- u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0,
- u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1,
- u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1)
-{
- BUG_ON(!_omap3_sram_configure_core_dpll);
- return _omap3_sram_configure_core_dpll(
- m2, unlock_dll, f, inc,
- sdrc_rfr_ctrl_0, sdrc_actim_ctrl_a_0,
- sdrc_actim_ctrl_b_0, sdrc_mr_0,
- sdrc_rfr_ctrl_1, sdrc_actim_ctrl_a_1,
- sdrc_actim_ctrl_b_1, sdrc_mr_1);
-}
-
void omap3_sram_restore_context(void)
{
omap_sram_reset();
- _omap3_sram_configure_core_dpll =
- omap_sram_push(omap3_sram_configure_core_dpll,
- omap3_sram_configure_core_dpll_sz);
omap_push_sram_idle();
}
diff --git a/arch/arm/mach-omap2/sram.h b/arch/arm/mach-omap2/sram.h
index 948d3ed..18dc884 100644
--- a/arch/arm/mach-omap2/sram.h
+++ b/arch/arm/mach-omap2/sram.h
@@ -15,12 +15,6 @@ extern void omap2_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
u32 mem_type);
extern u32 omap2_set_prcm(u32 dpll_ctrl_val, u32 sdrc_rfr_val, int bypass);
-extern u32 omap3_configure_core_dpll(
- u32 m2, u32 unlock_dll, u32 f, u32 inc,
- u32 sdrc_rfr_ctrl_0, u32 sdrc_actim_ctrl_a_0,
- u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0,
- u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1,
- u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1);
extern void omap3_sram_restore_context(void);
/* Do not use these */
@@ -52,14 +46,6 @@ extern void omap243x_sram_reprogram_sdrc(u32 perf_level, u32 dll_val,
u32 mem_type);
extern unsigned long omap243x_sram_reprogram_sdrc_sz;
-extern u32 omap3_sram_configure_core_dpll(
- u32 m2, u32 unlock_dll, u32 f, u32 inc,
- u32 sdrc_rfr_ctrl_0, u32 sdrc_actim_ctrl_a_0,
- u32 sdrc_actim_ctrl_b_0, u32 sdrc_mr_0,
- u32 sdrc_rfr_ctrl_1, u32 sdrc_actim_ctrl_a_1,
- u32 sdrc_actim_ctrl_b_1, u32 sdrc_mr_1);
-extern unsigned long omap3_sram_configure_core_dpll_sz;
-
#ifdef CONFIG_PM
extern void omap_push_sram_idle(void);
#else
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
deleted file mode 100644
index 1446331..0000000
--- a/arch/arm/mach-omap2/sram34xx.S
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * linux/arch/arm/mach-omap3/sram.S
- *
- * Omap3 specific functions that need to be run in internal SRAM
- *
- * Copyright (C) 2004, 2007, 2008 Texas Instruments, Inc.
- * Copyright (C) 2008 Nokia Corporation
- *
- * Rajendra Nayak <rnayak@ti.com>
- * Richard Woodruff <r-woodruff2@ti.com>
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#include <linux/linkage.h>
-
-#include <asm/assembler.h>
-
-#include "soc.h"
-#include "iomap.h"
-#include "sdrc.h"
-#include "cm3xxx.h"
-
-/*
- * This file needs be built unconditionally as ARM to interoperate correctly
- * with non-Thumb-2-capable firmware.
- */
- .arm
-
- .text
-
-/* r1 parameters */
-#define SDRC_NO_UNLOCK_DLL 0x0
-#define SDRC_UNLOCK_DLL 0x1
-
-/* SDRC_DLLA_CTRL bit settings */
-#define FIXEDDELAY_SHIFT 24
-#define FIXEDDELAY_MASK (0xff << FIXEDDELAY_SHIFT)
-#define DLLIDLE_MASK 0x4
-
-/*
- * SDRC_DLLA_CTRL default values: TI hardware team indicates that
- * FIXEDDELAY should be initialized to 0xf. This apparently was
- * empirically determined during process testing, so no derivation
- * was provided.
- */
-#define FIXEDDELAY_DEFAULT (0x0f << FIXEDDELAY_SHIFT)
-
-/* SDRC_DLLA_STATUS bit settings */
-#define LOCKSTATUS_MASK 0x4
-
-/* SDRC_POWER bit settings */
-#define SRFRONIDLEREQ_MASK 0x40
-
-/* CM_IDLEST1_CORE bit settings */
-#define ST_SDRC_MASK 0x2
-
-/* CM_ICLKEN1_CORE bit settings */
-#define EN_SDRC_MASK 0x2
-
-/* CM_CLKSEL1_PLL bit settings */
-#define CORE_DPLL_CLKOUT_DIV_SHIFT 0x1b
-
-/*
- * omap3_sram_configure_core_dpll - change DPLL3 M2 divider
- *
- * Params passed in registers:
- * r0 = new M2 divider setting (only 1 and 2 supported right now)
- * r1 = unlock SDRC DLL? (1 = yes, 0 = no). Only unlock DLL for
- * SDRC rates < 83MHz
- * r2 = number of MPU cycles to wait for SDRC to stabilize after
- * reprogramming the SDRC when switching to a slower MPU speed
- * r3 = increasing SDRC rate? (1 = yes, 0 = no)
- *
- * Params passed via the stack. The needed params will be copied in SRAM
- * before use by the code in SRAM (SDRAM is not accessible during SDRC
- * reconfiguration):
- * new SDRC_RFR_CTRL_0 register contents
- * new SDRC_ACTIM_CTRL_A_0 register contents
- * new SDRC_ACTIM_CTRL_B_0 register contents
- * new SDRC_MR_0 register value
- * new SDRC_RFR_CTRL_1 register contents
- * new SDRC_ACTIM_CTRL_A_1 register contents
- * new SDRC_ACTIM_CTRL_B_1 register contents
- * new SDRC_MR_1 register value
- *
- * If the param SDRC_RFR_CTRL_1 is 0, the parameters are not programmed into
- * the SDRC CS1 registers
- *
- * NOTE: This code no longer attempts to program the SDRC AC timing and MR
- * registers. This is because the code currently cannot ensure that all
- * L3 initiators (e.g., sDMA, IVA, DSS DISPC, etc.) are not accessing the
- * SDRAM when the registers are written. If the registers are changed while
- * an initiator is accessing SDRAM, memory can be corrupted and/or the SDRC
- * may enter an unpredictable state. In the future, the intent is to
- * re-enable this code in cases where we can ensure that no initiators are
- * touching the SDRAM. Until that time, users who know that their use case
- * can satisfy the above requirement can enable the CONFIG_OMAP3_SDRC_AC_TIMING
- * option.
- *
- * Richard Woodruff notes that any changes to this code must be carefully
- * audited and tested to ensure that they don't cause a TLB miss while
- * the SDRAM is inaccessible. Such a situation will crash the system
- * since it will cause the ARM MMU to attempt to walk the page tables.
- * These crashes may be intermittent.
- */
- .align 3
-ENTRY(omap3_sram_configure_core_dpll)
- stmfd sp!, {r1-r12, lr} @ store regs to stack
-
- @ pull the extra args off the stack
- @ and store them in SRAM
-
-/*
- * PC-relative stores are deprecated in ARMv7 and lead to undefined behaviour
- * in Thumb-2: use a r7 as a base instead.
- * Be careful not to clobber r7 when maintaing this file.
- */
- THUMB( adr r7, omap3_sram_configure_core_dpll )
- .macro strtext Rt:req, label:req
- ARM( str \Rt, \label )
- THUMB( str \Rt, [r7, \label - omap3_sram_configure_core_dpll] )
- .endm
-
- ldr r4, [sp, #52]
- strtext r4, omap_sdrc_rfr_ctrl_0_val
- ldr r4, [sp, #56]
- strtext r4, omap_sdrc_actim_ctrl_a_0_val
- ldr r4, [sp, #60]
- strtext r4, omap_sdrc_actim_ctrl_b_0_val
- ldr r4, [sp, #64]
- strtext r4, omap_sdrc_mr_0_val
- ldr r4, [sp, #68]
- strtext r4, omap_sdrc_rfr_ctrl_1_val
- cmp r4, #0 @ if SDRC_RFR_CTRL_1 is 0,
- beq skip_cs1_params @ do not use cs1 params
- ldr r4, [sp, #72]
- strtext r4, omap_sdrc_actim_ctrl_a_1_val
- ldr r4, [sp, #76]
- strtext r4, omap_sdrc_actim_ctrl_b_1_val
- ldr r4, [sp, #80]
- strtext r4, omap_sdrc_mr_1_val
-skip_cs1_params:
- mrc p15, 0, r8, c1, c0, 0 @ read ctrl register
- bic r10, r8, #0x800 @ clear Z-bit, disable branch prediction
- mcr p15, 0, r10, c1, c0, 0 @ write ctrl register
- dsb @ flush buffered writes to interconnect
- isb @ prevent speculative exec past here
- cmp r3, #1 @ if increasing SDRC clk rate,
- bleq configure_sdrc @ program the SDRC regs early (for RFR)
- cmp r1, #SDRC_UNLOCK_DLL @ set the intended DLL state
- bleq unlock_dll
- blne lock_dll
- bl sdram_in_selfrefresh @ put SDRAM in self refresh, idle SDRC
- bl configure_core_dpll @ change the DPLL3 M2 divider
- mov r12, r2
- bl wait_clk_stable @ wait for SDRC to stabilize
- bl enable_sdrc @ take SDRC out of idle
- cmp r1, #SDRC_UNLOCK_DLL @ wait for DLL status to change
- bleq wait_dll_unlock
- blne wait_dll_lock
- cmp r3, #1 @ if increasing SDRC clk rate,
- beq return_to_sdram @ return to SDRAM code, otherwise,
- bl configure_sdrc @ reprogram SDRC regs now
-return_to_sdram:
- mcr p15, 0, r8, c1, c0, 0 @ restore ctrl register
- isb @ prevent speculative exec past here
- mov r0, #0 @ return value
- ldmfd sp!, {r1-r12, pc} @ restore regs and return
-unlock_dll:
- ldr r11, omap3_sdrc_dlla_ctrl
- ldr r12, [r11]
- bic r12, r12, #FIXEDDELAY_MASK
- orr r12, r12, #FIXEDDELAY_DEFAULT
- orr r12, r12, #DLLIDLE_MASK
- str r12, [r11] @ (no OCP barrier needed)
- bx lr
-lock_dll:
- ldr r11, omap3_sdrc_dlla_ctrl
- ldr r12, [r11]
- bic r12, r12, #DLLIDLE_MASK
- str r12, [r11] @ (no OCP barrier needed)
- bx lr
-sdram_in_selfrefresh:
- ldr r11, omap3_sdrc_power @ read the SDRC_POWER register
- ldr r12, [r11] @ read the contents of SDRC_POWER
- mov r9, r12 @ keep a copy of SDRC_POWER bits
- orr r12, r12, #SRFRONIDLEREQ_MASK @ enable self refresh on idle
- str r12, [r11] @ write back to SDRC_POWER register
- ldr r12, [r11] @ posted-write barrier for SDRC
-idle_sdrc:
- ldr r11, omap3_cm_iclken1_core @ read the CM_ICLKEN1_CORE reg
- ldr r12, [r11]
- bic r12, r12, #EN_SDRC_MASK @ disable iclk bit for SDRC
- str r12, [r11]
-wait_sdrc_idle:
- ldr r11, omap3_cm_idlest1_core
- ldr r12, [r11]
- and r12, r12, #ST_SDRC_MASK @ check for SDRC idle
- cmp r12, #ST_SDRC_MASK
- bne wait_sdrc_idle
- bx lr
-configure_core_dpll:
- ldr r11, omap3_cm_clksel1_pll
- ldr r12, [r11]
- ldr r10, core_m2_mask_val @ modify m2 for core dpll
- and r12, r12, r10
- orr r12, r12, r0, lsl #CORE_DPLL_CLKOUT_DIV_SHIFT
- str r12, [r11]
- ldr r12, [r11] @ posted-write barrier for CM
- bx lr
-wait_clk_stable:
- subs r12, r12, #1
- bne wait_clk_stable
- bx lr
-enable_sdrc:
- ldr r11, omap3_cm_iclken1_core
- ldr r12, [r11]
- orr r12, r12, #EN_SDRC_MASK @ enable iclk bit for SDRC
- str r12, [r11]
-wait_sdrc_idle1:
- ldr r11, omap3_cm_idlest1_core
- ldr r12, [r11]
- and r12, r12, #ST_SDRC_MASK
- cmp r12, #0
- bne wait_sdrc_idle1
-restore_sdrc_power_val:
- ldr r11, omap3_sdrc_power
- str r9, [r11] @ restore SDRC_POWER, no barrier needed
- bx lr
-wait_dll_lock:
- ldr r11, omap3_sdrc_dlla_status
- ldr r12, [r11]
- and r12, r12, #LOCKSTATUS_MASK
- cmp r12, #LOCKSTATUS_MASK
- bne wait_dll_lock
- bx lr
-wait_dll_unlock:
- ldr r11, omap3_sdrc_dlla_status
- ldr r12, [r11]
- and r12, r12, #LOCKSTATUS_MASK
- cmp r12, #0x0
- bne wait_dll_unlock
- bx lr
-configure_sdrc:
- ldr r12, omap_sdrc_rfr_ctrl_0_val @ fetch value from SRAM
- ldr r11, omap3_sdrc_rfr_ctrl_0 @ fetch addr from SRAM
- str r12, [r11] @ store
-#ifdef CONFIG_OMAP3_SDRC_AC_TIMING
- ldr r12, omap_sdrc_actim_ctrl_a_0_val
- ldr r11, omap3_sdrc_actim_ctrl_a_0
- str r12, [r11]
- ldr r12, omap_sdrc_actim_ctrl_b_0_val
- ldr r11, omap3_sdrc_actim_ctrl_b_0
- str r12, [r11]
- ldr r12, omap_sdrc_mr_0_val
- ldr r11, omap3_sdrc_mr_0
- str r12, [r11]
-#endif
- ldr r12, omap_sdrc_rfr_ctrl_1_val
- cmp r12, #0 @ if SDRC_RFR_CTRL_1 is 0,
- beq skip_cs1_prog @ do not program cs1 params
- ldr r11, omap3_sdrc_rfr_ctrl_1
- str r12, [r11]
-#ifdef CONFIG_OMAP3_SDRC_AC_TIMING
- ldr r12, omap_sdrc_actim_ctrl_a_1_val
- ldr r11, omap3_sdrc_actim_ctrl_a_1
- str r12, [r11]
- ldr r12, omap_sdrc_actim_ctrl_b_1_val
- ldr r11, omap3_sdrc_actim_ctrl_b_1
- str r12, [r11]
- ldr r12, omap_sdrc_mr_1_val
- ldr r11, omap3_sdrc_mr_1
- str r12, [r11]
-#endif
-skip_cs1_prog:
- ldr r12, [r11] @ posted-write barrier for SDRC
- bx lr
-
- .align
-omap3_sdrc_power:
- .word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
-omap3_cm_clksel1_pll:
- .word OMAP34XX_CM_REGADDR(PLL_MOD, CM_CLKSEL1)
-omap3_cm_idlest1_core:
- .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
-omap3_cm_iclken1_core:
- .word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
-
-omap3_sdrc_rfr_ctrl_0:
- .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_0)
-omap3_sdrc_rfr_ctrl_1:
- .word OMAP34XX_SDRC_REGADDR(SDRC_RFR_CTRL_1)
-omap3_sdrc_actim_ctrl_a_0:
- .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_0)
-omap3_sdrc_actim_ctrl_a_1:
- .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_A_1)
-omap3_sdrc_actim_ctrl_b_0:
- .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_0)
-omap3_sdrc_actim_ctrl_b_1:
- .word OMAP34XX_SDRC_REGADDR(SDRC_ACTIM_CTRL_B_1)
-omap3_sdrc_mr_0:
- .word OMAP34XX_SDRC_REGADDR(SDRC_MR_0)
-omap3_sdrc_mr_1:
- .word OMAP34XX_SDRC_REGADDR(SDRC_MR_1)
-omap_sdrc_rfr_ctrl_0_val:
- .word 0xDEADBEEF
-omap_sdrc_rfr_ctrl_1_val:
- .word 0xDEADBEEF
-omap_sdrc_actim_ctrl_a_0_val:
- .word 0xDEADBEEF
-omap_sdrc_actim_ctrl_a_1_val:
- .word 0xDEADBEEF
-omap_sdrc_actim_ctrl_b_0_val:
- .word 0xDEADBEEF
-omap_sdrc_actim_ctrl_b_1_val:
- .word 0xDEADBEEF
-omap_sdrc_mr_0_val:
- .word 0xDEADBEEF
-omap_sdrc_mr_1_val:
- .word 0xDEADBEEF
-
-omap3_sdrc_dlla_status:
- .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
-omap3_sdrc_dlla_ctrl:
- .word OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
-core_m2_mask_val:
- .word 0x07FFFFFF
-ENDPROC(omap3_sram_configure_core_dpll)
-
-ENTRY(omap3_sram_configure_core_dpll_sz)
- .word . - omap3_sram_configure_core_dpll
-
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index bef4183..f86692d 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -183,7 +183,8 @@ static struct device_node * __init omap_get_timer_dt(const struct of_device_id *
of_get_property(np, "ti,timer-secure", NULL)))
continue;
- of_add_property(np, &device_disabled);
+ if (!of_device_is_compatible(np, "ti,omap-counter32k"))
+ of_add_property(np, &device_disabled);
return np;
}
@@ -319,6 +320,12 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
return r;
}
+#if !defined(CONFIG_SMP) && defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
+void tick_broadcast(const struct cpumask *mask)
+{
+}
+#endif
+
static void __init omap2_gp_clockevent_init(int gptimer_id,
const char *fck_source,
const char *property)
@@ -394,7 +401,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
int ret;
struct device_node *np = NULL;
struct omap_hwmod *oh;
- void __iomem *vbase;
const char *oh_name = "counter_32k";
/*
@@ -420,18 +426,6 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
omap_hwmod_setup_one(oh_name);
- if (np) {
- vbase = of_iomap(np, 0);
- of_node_put(np);
- } else {
- vbase = omap_hwmod_get_mpu_rt_va(oh);
- }
-
- if (!vbase) {
- pr_warn("%s: failed to get counter_32k resource\n", __func__);
- return -ENXIO;
- }
-
ret = omap_hwmod_enable(oh);
if (ret) {
pr_warn("%s: failed to enable counter_32k module (%d)\n",
@@ -439,13 +433,18 @@ static int __init __maybe_unused omap2_sync32k_clocksource_init(void)
return ret;
}
- ret = omap_init_clocksource_32k(vbase);
- if (ret) {
- pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
- __func__, ret);
- omap_hwmod_idle(oh);
- }
+ if (!of_have_populated_dt()) {
+ void __iomem *vbase;
+
+ vbase = omap_hwmod_get_mpu_rt_va(oh);
+ ret = omap_init_clocksource_32k(vbase);
+ if (ret) {
+ pr_warn("%s: failed to initialize counter_32k as a clocksource (%d)\n",
+ __func__, ret);
+ omap_hwmod_idle(oh);
+ }
+ }
return ret;
}
@@ -476,7 +475,64 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
clocksource_gpt.name, clksrc.rate);
}
-#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
+static void __init __omap_sync32k_timer_init(int clkev_nr, const char *clkev_src,
+ const char *clkev_prop, int clksrc_nr, const char *clksrc_src,
+ const char *clksrc_prop, bool gptimer)
+{
+ omap_clk_init();
+ omap_dmtimer_init();
+ omap2_gp_clockevent_init(clkev_nr, clkev_src, clkev_prop);
+
+ /* Enable the use of clocksource="gp_timer" kernel parameter */
+ if (use_gptimer_clksrc || gptimer)
+ omap2_gptimer_clocksource_init(clksrc_nr, clksrc_src,
+ clksrc_prop);
+ else
+ omap2_sync32k_clocksource_init();
+}
+
+void __init omap_init_time(void)
+{
+ __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
+ 2, "timer_sys_ck", NULL, false);
+
+ if (of_have_populated_dt())
+ clocksource_probe();
+}
+
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
+void __init omap3_secure_sync32k_timer_init(void)
+{
+ __omap_sync32k_timer_init(12, "secure_32k_fck", "ti,timer-secure",
+ 2, "timer_sys_ck", NULL, false);
+}
+#endif /* CONFIG_ARCH_OMAP3 */
+
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX)
+void __init omap3_gptimer_timer_init(void)
+{
+ __omap_sync32k_timer_init(2, "timer_sys_ck", NULL,
+ 1, "timer_sys_ck", "ti,timer-alwon", true);
+}
+#endif
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+ defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX)
+static void __init omap4_sync32k_timer_init(void)
+{
+ __omap_sync32k_timer_init(1, "timer_32k_ck", "ti,timer-alwon",
+ 2, "sys_clkin_ck", NULL, false);
+}
+
+void __init omap4_local_timer_init(void)
+{
+ omap4_sync32k_timer_init();
+ clocksource_probe();
+}
+#endif
+
+#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
+
/*
* The realtime counter also called master counter, is a free-running
* counter, which is related to real time. It produces the count used
@@ -488,6 +544,7 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
*/
static void __init realtime_counter_init(void)
{
+#ifdef CONFIG_SOC_HAS_REALTIME_COUNTER
void __iomem *base;
static struct clk *sys_clk;
unsigned long rate;
@@ -586,78 +643,9 @@ sysclk1_based:
set_cntfreq();
iounmap(base);
-}
-#else
-static inline void __init realtime_counter_init(void)
-{}
#endif
-
-#define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
- clksrc_nr, clksrc_src, clksrc_prop) \
-void __init omap##name##_gptimer_timer_init(void) \
-{ \
- omap_clk_init(); \
- omap_dmtimer_init(); \
- omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
- omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \
- clksrc_prop); \
-}
-
-#define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
- clksrc_nr, clksrc_src, clksrc_prop) \
-void __init omap##name##_sync32k_timer_init(void) \
-{ \
- omap_clk_init(); \
- omap_dmtimer_init(); \
- omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
- /* Enable the use of clocksource="gp_timer" kernel parameter */ \
- if (use_gptimer_clksrc) \
- omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src, \
- clksrc_prop); \
- else \
- omap2_sync32k_clocksource_init(); \
}
-#ifdef CONFIG_ARCH_OMAP2
-OMAP_SYS_32K_TIMER_INIT(2, 1, "timer_32k_ck", "ti,timer-alwon",
- 2, "timer_sys_ck", NULL);
-#endif /* CONFIG_ARCH_OMAP2 */
-
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM43XX)
-OMAP_SYS_32K_TIMER_INIT(3, 1, "timer_32k_ck", "ti,timer-alwon",
- 2, "timer_sys_ck", NULL);
-OMAP_SYS_32K_TIMER_INIT(3_secure, 12, "secure_32k_fck", "ti,timer-secure",
- 2, "timer_sys_ck", NULL);
-#endif /* CONFIG_ARCH_OMAP3 */
-
-#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_SOC_AM33XX) || \
- defined(CONFIG_SOC_AM43XX)
-OMAP_SYS_GP_TIMER_INIT(3, 2, "timer_sys_ck", NULL,
- 1, "timer_sys_ck", "ti,timer-alwon");
-#endif
-
-#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
- defined(CONFIG_SOC_DRA7XX)
-static OMAP_SYS_32K_TIMER_INIT(4, 1, "timer_32k_ck", "ti,timer-alwon",
- 2, "sys_clkin_ck", NULL);
-#endif
-
-#ifdef CONFIG_ARCH_OMAP4
-#ifdef CONFIG_HAVE_ARM_TWD
-void __init omap4_local_timer_init(void)
-{
- omap4_sync32k_timer_init();
- clocksource_probe();
-}
-#else
-void __init omap4_local_timer_init(void)
-{
- omap4_sync32k_timer_init();
-}
-#endif /* CONFIG_HAVE_ARM_TWD */
-#endif /* CONFIG_ARCH_OMAP4 */
-
-#if defined(CONFIG_SOC_OMAP5) || defined(CONFIG_SOC_DRA7XX)
void __init omap5_realtime_timer_init(void)
{
omap4_sync32k_timer_init();
diff --git a/arch/arm/mach-omap2/vc.c b/arch/arm/mach-omap2/vc.c
index d44d311..2028167f 100644
--- a/arch/arm/mach-omap2/vc.c
+++ b/arch/arm/mach-omap2/vc.c
@@ -280,10 +280,6 @@ void omap3_vc_set_pmic_signaling(int core_next_state)
}
}
-#define PRM_POLCTRL_TWL_MASK (OMAP3430_PRM_POLCTRL_CLKREQ_POL | \
- OMAP3430_PRM_POLCTRL_CLKREQ_POL)
-#define PRM_POLCTRL_TWL_VAL OMAP3430_PRM_POLCTRL_CLKREQ_POL
-
/*
* Configure signal polarity for sys_clkreq and sys_off_mode pins
* as the default values are wrong and can cause the system to hang
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig
index 08d2be2..66f1c95 100644
--- a/arch/arm/mach-orion5x/Kconfig
+++ b/arch/arm/mach-orion5x/Kconfig
@@ -45,6 +45,7 @@ config MACH_KUROBOX_PRO
config MACH_DNS323
bool "D-Link DNS-323"
+ select GENERIC_NET_UTILS
select I2C_BOARDINFO
help
Say 'Y' here if you want your kernel to support the
@@ -52,6 +53,7 @@ config MACH_DNS323
config MACH_TS209
bool "QNAP TS-109/TS-209"
+ select GENERIC_NET_UTILS
help
Say 'Y' here if you want your kernel to support the
QNAP TS-109/TS-209 platform.
@@ -93,6 +95,7 @@ config MACH_LINKSTATION_LS_HGL
config MACH_TS409
bool "QNAP TS-409"
+ select GENERIC_NET_UTILS
help
Say 'Y' here if you want your kernel to support the
QNAP TS-409 platform.
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index f267e58..bc279a8 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -173,42 +173,10 @@ static struct mv643xx_eth_platform_data dns323_eth_data = {
.phy_addr = MV643XX_ETH_PHY_ADDR(8),
};
-/* dns323_parse_hex_*() taken from tsx09-common.c; should a common copy of these
- * functions be kept somewhere?
- */
-static int __init dns323_parse_hex_nibble(char n)
-{
- if (n >= '0' && n <= '9')
- return n - '0';
-
- if (n >= 'A' && n <= 'F')
- return n - 'A' + 10;
-
- if (n >= 'a' && n <= 'f')
- return n - 'a' + 10;
-
- return -1;
-}
-
-static int __init dns323_parse_hex_byte(const char *b)
-{
- int hi;
- int lo;
-
- hi = dns323_parse_hex_nibble(b[0]);
- lo = dns323_parse_hex_nibble(b[1]);
-
- if (hi < 0 || lo < 0)
- return -1;
-
- return (hi << 4) | lo;
-}
-
static int __init dns323_read_mac_addr(void)
{
u_int8_t addr[6];
- int i;
- char *mac_page;
+ void __iomem *mac_page;
/* MAC address is stored as a regular ol' string in /dev/mtdblock4
* (0x007d0000-0x00800000) starting at offset 196480 (0x2ff80).
@@ -217,23 +185,8 @@ static int __init dns323_read_mac_addr(void)
if (!mac_page)
return -ENOMEM;
- /* Sanity check the string we're looking at */
- for (i = 0; i < 5; i++) {
- if (*(mac_page + (i * 3) + 2) != ':') {
- goto error_fail;
- }
- }
-
- for (i = 0; i < 6; i++) {
- int byte;
-
- byte = dns323_parse_hex_byte(mac_page + (i * 3));
- if (byte < 0) {
- goto error_fail;
- }
-
- addr[i] = byte;
- }
+ if (!mac_pton((__force const char *) mac_page, addr))
+ goto error_fail;
iounmap(mac_page);
printk("DNS-323: Found ethernet MAC address: %pM\n", addr);
diff --git a/arch/arm/mach-orion5x/include/mach/entry-macro.S b/arch/arm/mach-orion5x/include/mach/entry-macro.S
index 79eb502..73919a3 100644
--- a/arch/arm/mach-orion5x/include/mach/entry-macro.S
+++ b/arch/arm/mach-orion5x/include/mach/entry-macro.S
@@ -21,5 +21,5 @@
@ find cause bits that are unmasked
ands \irqstat, \irqstat, \tmp @ clear Z flag if any
clzne \irqnr, \irqstat @ calc irqnr
- rsbne \irqnr, \irqnr, #31
+ rsbne \irqnr, \irqnr, #32
.endm
diff --git a/arch/arm/mach-orion5x/tsx09-common.c b/arch/arm/mach-orion5x/tsx09-common.c
index 24b2959..d42e006 100644
--- a/arch/arm/mach-orion5x/tsx09-common.c
+++ b/arch/arm/mach-orion5x/tsx09-common.c
@@ -53,53 +53,12 @@ struct mv643xx_eth_platform_data qnap_tsx09_eth_data = {
.phy_addr = MV643XX_ETH_PHY_ADDR(8),
};
-static int __init qnap_tsx09_parse_hex_nibble(char n)
-{
- if (n >= '0' && n <= '9')
- return n - '0';
-
- if (n >= 'A' && n <= 'F')
- return n - 'A' + 10;
-
- if (n >= 'a' && n <= 'f')
- return n - 'a' + 10;
-
- return -1;
-}
-
-static int __init qnap_tsx09_parse_hex_byte(const char *b)
-{
- int hi;
- int lo;
-
- hi = qnap_tsx09_parse_hex_nibble(b[0]);
- lo = qnap_tsx09_parse_hex_nibble(b[1]);
-
- if (hi < 0 || lo < 0)
- return -1;
-
- return (hi << 4) | lo;
-}
-
static int __init qnap_tsx09_check_mac_addr(const char *addr_str)
{
u_int8_t addr[6];
- int i;
- for (i = 0; i < 6; i++) {
- int byte;
-
- /*
- * Enforce "xx:xx:xx:xx:xx:xx\n" format.
- */
- if (addr_str[(i * 3) + 2] != ((i < 5) ? ':' : '\n'))
- return -1;
-
- byte = qnap_tsx09_parse_hex_byte(addr_str + (i * 3));
- if (byte < 0)
- return -1;
- addr[i] = byte;
- }
+ if (!mac_pton(addr_str, addr))
+ return -1;
printk(KERN_INFO "tsx09: found ethernet mac address %pM\n", addr);
@@ -118,12 +77,12 @@ void __init qnap_tsx09_find_mac_addr(u32 mem_base, u32 size)
unsigned long addr;
for (addr = mem_base; addr < (mem_base + size); addr += 1024) {
- char *nor_page;
+ void __iomem *nor_page;
int ret = 0;
nor_page = ioremap(addr, 1024);
if (nor_page != NULL) {
- ret = qnap_tsx09_check_mac_addr(nor_page);
+ ret = qnap_tsx09_check_mac_addr((__force const char *)nor_page);
iounmap(nor_page);
}
diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c
index 0ab2f8b..a728c78 100644
--- a/arch/arm/mach-prima2/hotplug.c
+++ b/arch/arm/mach-prima2/hotplug.c
@@ -32,7 +32,7 @@ static inline void platform_do_lowpower(unsigned int cpu)
*
* Called with IRQs disabled
*/
-void __ref sirfsoc_cpu_die(unsigned int cpu)
+void sirfsoc_cpu_die(unsigned int cpu)
{
platform_do_lowpower(cpu);
}
diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index 5851f4c..a7dae60 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -26,6 +26,7 @@
#include <linux/dm9000.h>
#include <linux/leds.h>
#include <linux/rtc-v3020.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/i2c.h>
@@ -305,11 +306,14 @@ static inline void cm_x300_init_lcd(void) {}
#endif
#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct pwm_lookup cm_x300_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 1, "pwm-backlight.0", NULL, 10000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data cm_x300_backlight_data = {
- .pwm_id = 2,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 10000,
.enable_gpio = -1,
};
@@ -323,6 +327,7 @@ static struct platform_device cm_x300_backlight_device = {
static void cm_x300_init_bl(void)
{
+ pwm_add_table(cm_x300_pwm_lookup, ARRAY_SIZE(cm_x300_pwm_lookup));
platform_device_register(&cm_x300_backlight_device);
}
#else
diff --git a/arch/arm/mach-pxa/colibri-pxa270-income.c b/arch/arm/mach-pxa/colibri-pxa270-income.c
index 3aa2646..db20d25 100644
--- a/arch/arm/mach-pxa/colibri-pxa270-income.c
+++ b/arch/arm/mach-pxa/colibri-pxa270-income.c
@@ -20,6 +20,7 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/i2c/pxa-i2c.h>
@@ -184,11 +185,14 @@ static inline void income_lcd_init(void) {}
* Backlight
******************************************************************************/
#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct pwm_lookup income_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 1000000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data income_backlight_data = {
- .pwm_id = 0,
.max_brightness = 0x3ff,
.dft_brightness = 0x1ff,
- .pwm_period_ns = 1000000,
.enable_gpio = -1,
};
@@ -202,6 +206,7 @@ static struct platform_device income_backlight = {
static void __init income_pwm_init(void)
{
+ pwm_add_table(income_pwm_lookup, ARRAY_SIZE(income_pwm_lookup));
platform_device_register(&income_backlight);
}
#else
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index c624732..d1211a4 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -14,7 +14,7 @@
#include <mach/irqs.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include <mach/audio.h>
#include <mach/hardware.h>
#include <linux/platform_data/mmp_dma.h>
@@ -395,6 +395,26 @@ static struct resource pxa_ir_resources[] = {
.end = IRQ_ICP,
.flags = IORESOURCE_IRQ,
},
+ [3] = {
+ .start = 0x40800000,
+ .end = 0x4080001b,
+ .flags = IORESOURCE_MEM,
+ },
+ [4] = {
+ .start = 0x40700000,
+ .end = 0x40700023,
+ .flags = IORESOURCE_MEM,
+ },
+ [5] = {
+ .start = 17,
+ .end = 17,
+ .flags = IORESOURCE_DMA,
+ },
+ [6] = {
+ .start = 18,
+ .end = 18,
+ .flags = IORESOURCE_DMA,
+ },
};
struct platform_device pxa_device_ficp = {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 9d7072b..8b1f89e 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -46,7 +46,7 @@
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <linux/platform_data/mmc-pxamci.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index ab93441..cd62240 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/input.h>
#include <linux/gpio.h>
@@ -33,7 +34,7 @@
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/hardware.h>
#include <linux/platform_data/keypad-pxa27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include "devices.h"
#include "generic.h"
@@ -49,11 +50,14 @@
#define GPIO19_GEN1_CAM_RST 19
#define GPIO28_GEN2_CAM_RST 28
+static struct pwm_lookup ezx_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 78700,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data ezx_backlight_data = {
- .pwm_id = 0,
.max_brightness = 1023,
.dft_brightness = 1023,
- .pwm_period_ns = 78770,
.enable_gpio = -1,
};
@@ -817,6 +821,7 @@ static void __init a780_init(void)
platform_device_register(&a780_camera);
}
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(a780_devices));
}
@@ -884,6 +889,7 @@ static void __init e680_init(void)
pxa_set_keypad_info(&e680_keypad_platform_data);
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(e680_devices));
}
@@ -951,6 +957,7 @@ static void __init a1200_init(void)
pxa_set_keypad_info(&a1200_keypad_platform_data);
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(a1200_devices));
}
@@ -1143,6 +1150,7 @@ static void __init a910_init(void)
platform_device_register(&a910_camera);
}
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(a910_devices));
}
@@ -1210,6 +1218,7 @@ static void __init e6_init(void)
pxa_set_keypad_info(&e6_keypad_platform_data);
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(e6_devices));
}
@@ -1251,6 +1260,7 @@ static void __init e2_init(void)
pxa_set_keypad_info(&e2_keypad_platform_data);
+ pwm_add_table(ezx_pwm_lookup, ARRAY_SIZE(ezx_pwm_lookup));
platform_add_devices(ARRAY_AND_SIZE(ezx_devices));
platform_add_devices(ARRAY_AND_SIZE(e2_devices));
}
diff --git a/arch/arm/mach-pxa/hx4700.c b/arch/arm/mach-pxa/hx4700.c
index 5fb41ad..b076a83 100644
--- a/arch/arm/mach-pxa/hx4700.c
+++ b/arch/arm/mach-pxa/hx4700.c
@@ -557,10 +557,8 @@ static struct platform_device hx4700_lcd = {
*/
static struct platform_pwm_backlight_data backlight_data = {
- .pwm_id = -1, /* Superseded by pwm_lookup */
.max_brightness = 200,
.dft_brightness = 100,
- .pwm_period_ns = 30923,
.enable_gpio = -1,
};
@@ -630,7 +628,6 @@ static struct spi_board_info tsc2046_board_info[] __initdata = {
static struct pxa2xx_spi_master pxa_ssp2_master_info = {
.num_chipselect = 1,
- .clock_enable = CKEN_SSP2,
.enable_dma = 1,
};
diff --git a/arch/arm/mach-pxa/icontrol.c b/arch/arm/mach-pxa/icontrol.c
index 9b0eb02..a1869f9 100644
--- a/arch/arm/mach-pxa/icontrol.c
+++ b/arch/arm/mach-pxa/icontrol.c
@@ -116,13 +116,11 @@ static struct spi_board_info mcp251x_board_info[] = {
};
static struct pxa2xx_spi_master pxa_ssp3_spi_master_info = {
- .clock_enable = CKEN_SSP3,
.num_chipselect = 2,
.enable_dma = 1
};
static struct pxa2xx_spi_master pxa_ssp4_spi_master_info = {
- .clock_enable = CKEN_SSP4,
.num_chipselect = 2,
.enable_dma = 1
};
diff --git a/arch/arm/mach-pxa/include/mach/magician.h b/arch/arm/mach-pxa/include/mach/magician.h
index ba6a6e1..5f6b850 100644
--- a/arch/arm/mach-pxa/include/mach/magician.h
+++ b/arch/arm/mach-pxa/include/mach/magician.h
@@ -52,9 +52,9 @@
#define GPIO101_MAGICIAN_KEY_VOL_DOWN 101
#define GPIO102_MAGICIAN_KEY_PHONE 102
#define GPIO103_MAGICIAN_LED_KP 103
-#define GPIO104_MAGICIAN_LCD_POWER_1 104
-#define GPIO105_MAGICIAN_LCD_POWER_2 105
-#define GPIO106_MAGICIAN_LCD_POWER_3 106
+#define GPIO104_MAGICIAN_LCD_VOFF_EN 104
+#define GPIO105_MAGICIAN_LCD_VON_EN 105
+#define GPIO106_MAGICIAN_LCD_DCDC_NRESET 106
#define GPIO107_MAGICIAN_DS1WM_IRQ 107
#define GPIO108_MAGICIAN_GSM_READY 108
#define GPIO114_MAGICIAN_UNKNOWN 114
@@ -78,43 +78,51 @@
* CPLD EGPIOs
*/
-#define MAGICIAN_EGPIO_BASE PXA_NR_BUILTIN_GPIO
+#define MAGICIAN_EGPIO_BASE PXA_NR_BUILTIN_GPIO
#define MAGICIAN_EGPIO(reg,bit) \
(MAGICIAN_EGPIO_BASE + 8*reg + bit)
/* output */
-#define EGPIO_MAGICIAN_TOPPOLY_POWER MAGICIAN_EGPIO(0, 2)
-#define EGPIO_MAGICIAN_LED_POWER MAGICIAN_EGPIO(0, 5)
-#define EGPIO_MAGICIAN_GSM_RESET MAGICIAN_EGPIO(0, 6)
-#define EGPIO_MAGICIAN_LCD_POWER MAGICIAN_EGPIO(0, 7)
-#define EGPIO_MAGICIAN_SPK_POWER MAGICIAN_EGPIO(1, 0)
-#define EGPIO_MAGICIAN_EP_POWER MAGICIAN_EGPIO(1, 1)
-#define EGPIO_MAGICIAN_IN_SEL0 MAGICIAN_EGPIO(1, 2)
-#define EGPIO_MAGICIAN_IN_SEL1 MAGICIAN_EGPIO(1, 3)
-#define EGPIO_MAGICIAN_MIC_POWER MAGICIAN_EGPIO(1, 4)
-#define EGPIO_MAGICIAN_CODEC_RESET MAGICIAN_EGPIO(1, 5)
-#define EGPIO_MAGICIAN_CODEC_POWER MAGICIAN_EGPIO(1, 6)
-#define EGPIO_MAGICIAN_BL_POWER MAGICIAN_EGPIO(1, 7)
-#define EGPIO_MAGICIAN_SD_POWER MAGICIAN_EGPIO(2, 0)
-#define EGPIO_MAGICIAN_CARKIT_MIC MAGICIAN_EGPIO(2, 1)
-#define EGPIO_MAGICIAN_UNKNOWN_WAVEDEV_DLL MAGICIAN_EGPIO(2, 2)
-#define EGPIO_MAGICIAN_FLASH_VPP MAGICIAN_EGPIO(2, 3)
-#define EGPIO_MAGICIAN_BL_POWER2 MAGICIAN_EGPIO(2, 4)
-#define EGPIO_MAGICIAN_BQ24022_ISET2 MAGICIAN_EGPIO(2, 5)
-#define EGPIO_MAGICIAN_GSM_POWER MAGICIAN_EGPIO(2, 7)
+#define EGPIO_MAGICIAN_TOPPOLY_POWER MAGICIAN_EGPIO(0, 2)
+#define EGPIO_MAGICIAN_LED_POWER MAGICIAN_EGPIO(0, 5)
+#define EGPIO_MAGICIAN_GSM_RESET MAGICIAN_EGPIO(0, 6)
+#define EGPIO_MAGICIAN_LCD_POWER MAGICIAN_EGPIO(0, 7)
+#define EGPIO_MAGICIAN_SPK_POWER MAGICIAN_EGPIO(1, 0)
+#define EGPIO_MAGICIAN_EP_POWER MAGICIAN_EGPIO(1, 1)
+#define EGPIO_MAGICIAN_IN_SEL0 MAGICIAN_EGPIO(1, 2)
+#define EGPIO_MAGICIAN_IN_SEL1 MAGICIAN_EGPIO(1, 3)
+#define EGPIO_MAGICIAN_MIC_POWER MAGICIAN_EGPIO(1, 4)
+#define EGPIO_MAGICIAN_CODEC_RESET MAGICIAN_EGPIO(1, 5)
+#define EGPIO_MAGICIAN_CODEC_POWER MAGICIAN_EGPIO(1, 6)
+#define EGPIO_MAGICIAN_BL_POWER MAGICIAN_EGPIO(1, 7)
+#define EGPIO_MAGICIAN_SD_POWER MAGICIAN_EGPIO(2, 0)
+#define EGPIO_MAGICIAN_CARKIT_MIC MAGICIAN_EGPIO(2, 1)
+#define EGPIO_MAGICIAN_IR_RX_SHUTDOWN MAGICIAN_EGPIO(2, 2)
+#define EGPIO_MAGICIAN_FLASH_VPP MAGICIAN_EGPIO(2, 3)
+#define EGPIO_MAGICIAN_BL_POWER2 MAGICIAN_EGPIO(2, 4)
+#define EGPIO_MAGICIAN_BQ24022_ISET2 MAGICIAN_EGPIO(2, 5)
+#define EGPIO_MAGICIAN_NICD_CHARGE MAGICIAN_EGPIO(2, 6)
+#define EGPIO_MAGICIAN_GSM_POWER MAGICIAN_EGPIO(2, 7)
/* input */
-#define EGPIO_MAGICIAN_CABLE_STATE_AC MAGICIAN_EGPIO(4, 0)
-#define EGPIO_MAGICIAN_CABLE_STATE_USB MAGICIAN_EGPIO(4, 1)
+/* USB or AC charger type */
+#define EGPIO_MAGICIAN_CABLE_TYPE MAGICIAN_EGPIO(4, 0)
+/*
+ * Vbus is detected
+ * FIXME behaves like (6,3), may differ for host/device
+ */
+#define EGPIO_MAGICIAN_CABLE_VBUS MAGICIAN_EGPIO(4, 1)
-#define EGPIO_MAGICIAN_BOARD_ID0 MAGICIAN_EGPIO(5, 0)
-#define EGPIO_MAGICIAN_BOARD_ID1 MAGICIAN_EGPIO(5, 1)
-#define EGPIO_MAGICIAN_BOARD_ID2 MAGICIAN_EGPIO(5, 2)
-#define EGPIO_MAGICIAN_LCD_SELECT MAGICIAN_EGPIO(5, 3)
-#define EGPIO_MAGICIAN_nSD_READONLY MAGICIAN_EGPIO(5, 4)
+#define EGPIO_MAGICIAN_BOARD_ID0 MAGICIAN_EGPIO(5, 0)
+#define EGPIO_MAGICIAN_BOARD_ID1 MAGICIAN_EGPIO(5, 1)
+#define EGPIO_MAGICIAN_BOARD_ID2 MAGICIAN_EGPIO(5, 2)
+#define EGPIO_MAGICIAN_LCD_SELECT MAGICIAN_EGPIO(5, 3)
+#define EGPIO_MAGICIAN_nSD_READONLY MAGICIAN_EGPIO(5, 4)
-#define EGPIO_MAGICIAN_EP_INSERT MAGICIAN_EGPIO(6, 1)
+#define EGPIO_MAGICIAN_EP_INSERT MAGICIAN_EGPIO(6, 1)
+/* FIXME behaves like (4,1), may differ for host/device */
+#define EGPIO_MAGICIAN_CABLE_INSERTED MAGICIAN_EGPIO(6, 3)
#endif /* _MAGICIAN_H_ */
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h
index 599b925..1a42919 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x.h
@@ -19,7 +19,7 @@
#define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */
#define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */
-extern int __init pxa27x_set_pwrmode(unsigned int mode);
+extern int pxa27x_set_pwrmode(unsigned int mode);
extern void pxa27x_cpu_pm_enter(suspend_state_t state);
#endif /* __MACH_PXA27x_H */
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 4823d97..5fcd4f0 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -23,6 +23,7 @@
#include <linux/ioport.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/smc91x.h>
@@ -271,11 +272,14 @@ static struct platform_device lpd270_flash_device[2] = {
},
};
+static struct pwm_lookup lpd270_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 78770,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data lpd270_backlight_data = {
- .pwm_id = 0,
.max_brightness = 1,
.dft_brightness = 1,
- .pwm_period_ns = 78770,
.enable_gpio = -1,
};
@@ -474,6 +478,7 @@ static void __init lpd270_init(void)
*/
ARB_CNTRL = ARB_CORE_PARK | 0x234;
+ pwm_add_table(lpd270_pwm_lookup, ARRAY_SIZE(lpd270_pwm_lookup));
platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
pxa_set_ac97_info(NULL);
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index a9761c2..896b268 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -24,8 +24,10 @@
#include <linux/mfd/htc-pasic3.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/fixed.h>
#include <linux/regulator/gpio-regulator.h>
#include <linux/regulator/machine.h>
#include <linux/usb/gpio_vbus.h>
@@ -43,6 +45,12 @@
#include <linux/platform_data/irda-pxaficp.h>
#include <linux/platform_data/usb-ohci-pxa27x.h>
+#include <linux/regulator/max1586.h>
+
+#include <linux/platform_data/pxa2xx_udc.h>
+#include <mach/udc.h>
+#include <mach/pxa27x-udc.h>
+
#include "devices.h"
#include "generic.h"
@@ -52,36 +60,36 @@ static unsigned long magician_pin_config[] __initdata = {
GPIO20_nSDCS_2,
GPIO21_nSDCS_3,
GPIO15_nCS_1,
- GPIO78_nCS_2, /* PASIC3 */
- GPIO79_nCS_3, /* EGPIO CPLD */
+ GPIO78_nCS_2, /* PASIC3 */
+ GPIO79_nCS_3, /* EGPIO CPLD */
GPIO80_nCS_4,
GPIO33_nCS_5,
- /* I2C */
+ /* I2C UDA1380 + OV9640 */
GPIO117_I2C_SCL,
GPIO118_I2C_SDA,
- /* PWM 0 */
+ /* PWM 0 - LCD backlight */
GPIO16_PWM0_OUT,
- /* I2S */
+ /* I2S UDA1380 capture */
GPIO28_I2S_BITCLK_OUT,
GPIO29_I2S_SDATA_IN,
GPIO31_I2S_SYNC,
GPIO113_I2S_SYSCLK,
- /* SSP 1 */
+ /* SSP 1 UDA1380 playback */
GPIO23_SSP1_SCLK,
GPIO24_SSP1_SFRM,
GPIO25_SSP1_TXD,
- /* SSP 2 */
+ /* SSP 2 TSC2046 touchscreen */
GPIO19_SSP2_SCLK,
GPIO14_SSP2_SFRM,
GPIO89_SSP2_TXD,
GPIO88_SSP2_RXD,
- /* MMC */
+ /* MMC/SD/SDHC slot */
GPIO32_MMC_CLK,
GPIO92_MMC_DAT_0,
GPIO109_MMC_DAT_1,
@@ -92,7 +100,7 @@ static unsigned long magician_pin_config[] __initdata = {
/* LCD */
GPIOxx_LCD_TFT_16BPP,
- /* QCI */
+ /* QCI camera interface */
GPIO12_CIF_DD_7,
GPIO17_CIF_DD_6,
GPIO50_CIF_DD_3,
@@ -120,12 +128,13 @@ static unsigned long magician_pin_config[] __initdata = {
};
/*
- * IRDA
+ * IrDA
*/
static struct pxaficp_platform_data magician_ficp_info = {
.gpio_pwdown = GPIO83_MAGICIAN_nIR_EN,
.transceiver_cap = IR_SIRMODE | IR_OFF,
+ .gpio_pwdown_inverted = 0,
};
/*
@@ -134,11 +143,11 @@ static struct pxaficp_platform_data magician_ficp_info = {
#define INIT_KEY(_code, _gpio, _desc) \
{ \
- .code = KEY_##_code, \
- .gpio = _gpio, \
- .desc = _desc, \
- .type = EV_KEY, \
- .wakeup = 1, \
+ .code = KEY_##_code, \
+ .gpio = _gpio, \
+ .desc = _desc, \
+ .type = EV_KEY, \
+ .wakeup = 1, \
}
static struct gpio_keys_button magician_button_table[] = {
@@ -160,164 +169,162 @@ static struct gpio_keys_button magician_button_table[] = {
};
static struct gpio_keys_platform_data gpio_keys_data = {
- .buttons = magician_button_table,
- .nbuttons = ARRAY_SIZE(magician_button_table),
+ .buttons = magician_button_table,
+ .nbuttons = ARRAY_SIZE(magician_button_table),
};
static struct platform_device gpio_keys = {
- .name = "gpio-keys",
- .dev = {
+ .name = "gpio-keys",
+ .dev = {
.platform_data = &gpio_keys_data,
},
- .id = -1,
+ .id = -1,
};
-
/*
* EGPIO (Xilinx CPLD)
*
- * 7 32-bit aligned 8-bit registers: 3x output, 1x irq, 3x input
+ * 32-bit aligned 8-bit registers
+ * 16 possible registers (reg windows size), only 7 used:
+ * 3x output, 1x irq, 3x input
*/
static struct resource egpio_resources[] = {
[0] = {
- .start = PXA_CS3_PHYS,
- .end = PXA_CS3_PHYS + 0x20 - 1,
- .flags = IORESOURCE_MEM,
+ .start = PXA_CS3_PHYS,
+ .end = PXA_CS3_PHYS + 0x20 - 1,
+ .flags = IORESOURCE_MEM,
},
[1] = {
- .start = PXA_GPIO_TO_IRQ(GPIO13_MAGICIAN_CPLD_IRQ),
- .end = PXA_GPIO_TO_IRQ(GPIO13_MAGICIAN_CPLD_IRQ),
- .flags = IORESOURCE_IRQ,
+ .start = PXA_GPIO_TO_IRQ(GPIO13_MAGICIAN_CPLD_IRQ),
+ .end = PXA_GPIO_TO_IRQ(GPIO13_MAGICIAN_CPLD_IRQ),
+ .flags = IORESOURCE_IRQ,
},
};
static struct htc_egpio_chip egpio_chips[] = {
[0] = {
- .reg_start = 0,
- .gpio_base = MAGICIAN_EGPIO(0, 0),
- .num_gpios = 24,
- .direction = HTC_EGPIO_OUTPUT,
- .initial_values = 0x40, /* EGPIO_MAGICIAN_GSM_RESET */
+ .reg_start = 0,
+ .gpio_base = MAGICIAN_EGPIO(0, 0),
+ .num_gpios = 24,
+ .direction = HTC_EGPIO_OUTPUT,
+ /*
+ * Depends on modules configuration
+ */
+ .initial_values = 0x40, /* EGPIO_MAGICIAN_GSM_RESET */
},
[1] = {
- .reg_start = 4,
- .gpio_base = MAGICIAN_EGPIO(4, 0),
- .num_gpios = 24,
- .direction = HTC_EGPIO_INPUT,
+ .reg_start = 4,
+ .gpio_base = MAGICIAN_EGPIO(4, 0),
+ .num_gpios = 24,
+ .direction = HTC_EGPIO_INPUT,
},
};
static struct htc_egpio_platform_data egpio_info = {
- .reg_width = 8,
- .bus_width = 32,
- .irq_base = IRQ_BOARD_START,
- .num_irqs = 4,
- .ack_register = 3,
- .chip = egpio_chips,
- .num_chips = ARRAY_SIZE(egpio_chips),
+ .reg_width = 8,
+ .bus_width = 32,
+ .irq_base = IRQ_BOARD_START,
+ .num_irqs = 4,
+ .ack_register = 3,
+ .chip = egpio_chips,
+ .num_chips = ARRAY_SIZE(egpio_chips),
};
static struct platform_device egpio = {
- .name = "htc-egpio",
- .id = -1,
- .resource = egpio_resources,
- .num_resources = ARRAY_SIZE(egpio_resources),
+ .name = "htc-egpio",
+ .id = -1,
+ .resource = egpio_resources,
+ .num_resources = ARRAY_SIZE(egpio_resources),
.dev = {
.platform_data = &egpio_info,
},
};
/*
- * LCD - Toppoly TD028STEB1 or Samsung LTP280QV
+ * PXAFB LCD - Toppoly TD028STEB1 or Samsung LTP280QV
*/
static struct pxafb_mode_info toppoly_modes[] = {
{
- .pixclock = 96153,
- .bpp = 16,
- .xres = 240,
- .yres = 320,
- .hsync_len = 11,
- .vsync_len = 3,
- .left_margin = 19,
- .upper_margin = 2,
- .right_margin = 10,
- .lower_margin = 2,
- .sync = 0,
+ .pixclock = 96153,
+ .bpp = 16,
+ .xres = 240,
+ .yres = 320,
+ .hsync_len = 11,
+ .vsync_len = 3,
+ .left_margin = 19,
+ .upper_margin = 2,
+ .right_margin = 10,
+ .lower_margin = 2,
+ .sync = 0,
},
};
static struct pxafb_mode_info samsung_modes[] = {
{
- .pixclock = 96153,
- .bpp = 16,
- .xres = 240,
- .yres = 320,
- .hsync_len = 8,
- .vsync_len = 4,
- .left_margin = 9,
- .upper_margin = 4,
- .right_margin = 9,
- .lower_margin = 4,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .pixclock = 226469,
+ .bpp = 16,
+ .xres = 240,
+ .yres = 320,
+ .hsync_len = 8,
+ .vsync_len = 4,
+ .left_margin = 9,
+ .upper_margin = 4,
+ .right_margin = 9,
+ .lower_margin = 4,
+ .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
},
};
static void toppoly_lcd_power(int on, struct fb_var_screeninfo *si)
{
- pr_debug("Toppoly LCD power\n");
+ pr_debug("Toppoly LCD power: %s\n", on ? "on" : "off");
if (on) {
- pr_debug("on\n");
gpio_set_value(EGPIO_MAGICIAN_TOPPOLY_POWER, 1);
- gpio_set_value(GPIO106_MAGICIAN_LCD_POWER_3, 1);
+ gpio_set_value(GPIO106_MAGICIAN_LCD_DCDC_NRESET, 1);
udelay(2000);
gpio_set_value(EGPIO_MAGICIAN_LCD_POWER, 1);
udelay(2000);
/* FIXME: enable LCDC here */
udelay(2000);
- gpio_set_value(GPIO104_MAGICIAN_LCD_POWER_1, 1);
+ gpio_set_value(GPIO104_MAGICIAN_LCD_VOFF_EN, 1);
udelay(2000);
- gpio_set_value(GPIO105_MAGICIAN_LCD_POWER_2, 1);
+ gpio_set_value(GPIO105_MAGICIAN_LCD_VON_EN, 1);
} else {
- pr_debug("off\n");
msleep(15);
- gpio_set_value(GPIO105_MAGICIAN_LCD_POWER_2, 0);
+ gpio_set_value(GPIO105_MAGICIAN_LCD_VON_EN, 0);
udelay(500);
- gpio_set_value(GPIO104_MAGICIAN_LCD_POWER_1, 0);
+ gpio_set_value(GPIO104_MAGICIAN_LCD_VOFF_EN, 0);
udelay(1000);
- gpio_set_value(GPIO106_MAGICIAN_LCD_POWER_3, 0);
+ gpio_set_value(GPIO106_MAGICIAN_LCD_DCDC_NRESET, 0);
gpio_set_value(EGPIO_MAGICIAN_LCD_POWER, 0);
}
}
static void samsung_lcd_power(int on, struct fb_var_screeninfo *si)
{
- pr_debug("Samsung LCD power\n");
+ pr_debug("Samsung LCD power: %s\n", on ? "on" : "off");
if (on) {
- pr_debug("on\n");
if (system_rev < 3)
gpio_set_value(GPIO75_MAGICIAN_SAMSUNG_POWER, 1);
else
gpio_set_value(EGPIO_MAGICIAN_LCD_POWER, 1);
- mdelay(10);
- gpio_set_value(GPIO106_MAGICIAN_LCD_POWER_3, 1);
- mdelay(10);
- gpio_set_value(GPIO104_MAGICIAN_LCD_POWER_1, 1);
- mdelay(30);
- gpio_set_value(GPIO105_MAGICIAN_LCD_POWER_2, 1);
- mdelay(10);
+ mdelay(6);
+ gpio_set_value(GPIO106_MAGICIAN_LCD_DCDC_NRESET, 1);
+ mdelay(6); /* Avdd -> Voff >5ms */
+ gpio_set_value(GPIO104_MAGICIAN_LCD_VOFF_EN, 1);
+ mdelay(16); /* Voff -> Von >(5+10)ms */
+ gpio_set_value(GPIO105_MAGICIAN_LCD_VON_EN, 1);
} else {
- pr_debug("off\n");
- mdelay(10);
- gpio_set_value(GPIO105_MAGICIAN_LCD_POWER_2, 0);
- mdelay(30);
- gpio_set_value(GPIO104_MAGICIAN_LCD_POWER_1, 0);
- mdelay(10);
- gpio_set_value(GPIO106_MAGICIAN_LCD_POWER_3, 0);
- mdelay(10);
+ gpio_set_value(GPIO105_MAGICIAN_LCD_VON_EN, 0);
+ mdelay(16);
+ gpio_set_value(GPIO104_MAGICIAN_LCD_VOFF_EN, 0);
+ mdelay(6);
+ gpio_set_value(GPIO106_MAGICIAN_LCD_DCDC_NRESET, 0);
+ mdelay(6);
if (system_rev < 3)
gpio_set_value(GPIO75_MAGICIAN_SAMSUNG_POWER, 0);
else
@@ -326,29 +333,43 @@ static void samsung_lcd_power(int on, struct fb_var_screeninfo *si)
}
static struct pxafb_mach_info toppoly_info = {
- .modes = toppoly_modes,
- .num_modes = 1,
- .fixed_modes = 1,
- .lcd_conn = LCD_COLOR_TFT_16BPP,
- .pxafb_lcd_power = toppoly_lcd_power,
+ .modes = toppoly_modes,
+ .num_modes = 1,
+ .fixed_modes = 1,
+ .lcd_conn = LCD_COLOR_TFT_16BPP,
+ .pxafb_lcd_power = toppoly_lcd_power,
};
static struct pxafb_mach_info samsung_info = {
- .modes = samsung_modes,
- .num_modes = 1,
- .fixed_modes = 1,
- .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |\
- LCD_ALTERNATE_MAPPING,
- .pxafb_lcd_power = samsung_lcd_power,
+ .modes = samsung_modes,
+ .num_modes = 1,
+ .fixed_modes = 1,
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL |
+ LCD_ALTERNATE_MAPPING,
+ .pxafb_lcd_power = samsung_lcd_power,
};
/*
* Backlight
*/
+static struct pwm_lookup magician_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight", NULL, 30923,
+ PWM_POLARITY_NORMAL),
+};
+
+ /*
+ * fixed regulator for pwm_backlight
+ */
+
+static struct regulator_consumer_supply pwm_backlight_supply[] = {
+ REGULATOR_SUPPLY("power", "pwm_backlight"),
+};
+
+
static struct gpio magician_bl_gpios[] = {
- { EGPIO_MAGICIAN_BL_POWER, GPIOF_DIR_OUT, "Backlight power" },
- { EGPIO_MAGICIAN_BL_POWER2, GPIOF_DIR_OUT, "Backlight power 2" },
+ { EGPIO_MAGICIAN_BL_POWER, GPIOF_DIR_OUT, "Backlight power" },
+ { EGPIO_MAGICIAN_BL_POWER2, GPIOF_DIR_OUT, "Backlight power 2" },
};
static int magician_backlight_init(struct device *dev)
@@ -358,6 +379,7 @@ static int magician_backlight_init(struct device *dev)
static int magician_backlight_notify(struct device *dev, int brightness)
{
+ pr_debug("Brightness = %i\n", brightness);
gpio_set_value(EGPIO_MAGICIAN_BL_POWER, brightness);
if (brightness >= 200) {
gpio_set_value(EGPIO_MAGICIAN_BL_POWER2, 1);
@@ -373,28 +395,33 @@ static void magician_backlight_exit(struct device *dev)
gpio_free_array(ARRAY_AND_SIZE(magician_bl_gpios));
}
+/*
+ * LCD PWM backlight (main)
+ *
+ * MP1521 frequency should be:
+ * 100-400 Hz = 2 .5*10^6 - 10 *10^6 ns
+ */
+
static struct platform_pwm_backlight_data backlight_data = {
- .pwm_id = 0,
- .max_brightness = 272,
- .dft_brightness = 100,
- .pwm_period_ns = 30923,
- .enable_gpio = -1,
- .init = magician_backlight_init,
- .notify = magician_backlight_notify,
- .exit = magician_backlight_exit,
+ .max_brightness = 272,
+ .dft_brightness = 100,
+ .enable_gpio = -1,
+ .init = magician_backlight_init,
+ .notify = magician_backlight_notify,
+ .exit = magician_backlight_exit,
};
static struct platform_device backlight = {
- .name = "pwm-backlight",
- .id = -1,
- .dev = {
- .parent = &pxa27x_device_pwm0.dev,
- .platform_data = &backlight_data,
+ .name = "pwm-backlight",
+ .id = -1,
+ .dev = {
+ .parent = &pxa27x_device_pwm0.dev,
+ .platform_data = &backlight_data,
},
};
/*
- * LEDs
+ * GPIO LEDs, Phone keys backlight, vibra
*/
static struct gpio_led gpio_leds[] = {
@@ -416,69 +443,32 @@ static struct gpio_led_platform_data gpio_led_info = {
};
static struct platform_device leds_gpio = {
- .name = "leds-gpio",
- .id = -1,
- .dev = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
.platform_data = &gpio_led_info,
},
};
-static struct pasic3_led pasic3_leds[] = {
- {
- .led = {
- .name = "magician:red",
- .default_trigger = "ds2760-battery.0-charging",
- },
- .hw_num = 0,
- .bit2 = PASIC3_BIT2_LED0,
- .mask = PASIC3_MASK_LED0,
- },
- {
- .led = {
- .name = "magician:green",
- .default_trigger = "ds2760-battery.0-charging-or-full",
- },
- .hw_num = 1,
- .bit2 = PASIC3_BIT2_LED1,
- .mask = PASIC3_MASK_LED1,
- },
- {
- .led = {
- .name = "magician:blue",
- .default_trigger = "bluetooth",
- },
- .hw_num = 2,
- .bit2 = PASIC3_BIT2_LED2,
- .mask = PASIC3_MASK_LED2,
- },
-};
-
-static struct pasic3_leds_machinfo pasic3_leds_info = {
- .num_leds = ARRAY_SIZE(pasic3_leds),
- .power_gpio = EGPIO_MAGICIAN_LED_POWER,
- .leds = pasic3_leds,
-};
-
/*
* PASIC3 with DS1WM
*/
static struct resource pasic3_resources[] = {
[0] = {
- .start = PXA_CS2_PHYS,
+ .start = PXA_CS2_PHYS,
.end = PXA_CS2_PHYS + 0x1b,
- .flags = IORESOURCE_MEM,
+ .flags = IORESOURCE_MEM,
},
/* No IRQ handler in the PASIC3, DS1WM needs an external IRQ */
[1] = {
- .start = PXA_GPIO_TO_IRQ(GPIO107_MAGICIAN_DS1WM_IRQ),
- .end = PXA_GPIO_TO_IRQ(GPIO107_MAGICIAN_DS1WM_IRQ),
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
+ .start = PXA_GPIO_TO_IRQ(GPIO107_MAGICIAN_DS1WM_IRQ),
+ .end = PXA_GPIO_TO_IRQ(GPIO107_MAGICIAN_DS1WM_IRQ),
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
}
};
static struct pasic3_platform_data pasic3_platform_data = {
- .led_pdata = &pasic3_leds_info,
.clock_rate = 4000000,
};
@@ -493,25 +483,42 @@ static struct platform_device pasic3 = {
};
/*
- * USB "Transceiver"
+ * PXA UDC
+ */
+
+static void magician_udc_command(int cmd)
+{
+ if (cmd == PXA2XX_UDC_CMD_CONNECT)
+ UP2OCR |= UP2OCR_DPPUE | UP2OCR_DPPUBE;
+ else if (cmd == PXA2XX_UDC_CMD_DISCONNECT)
+ UP2OCR &= ~(UP2OCR_DPPUE | UP2OCR_DPPUBE);
+}
+
+static struct pxa2xx_udc_mach_info magician_udc_info __initdata = {
+ .udc_command = magician_udc_command,
+ .gpio_pullup = GPIO27_MAGICIAN_USBC_PUEN,
+};
+
+/*
+ * USB device VBus detection
*/
static struct resource gpio_vbus_resource = {
- .flags = IORESOURCE_IRQ,
- .start = IRQ_MAGICIAN_VBUS,
- .end = IRQ_MAGICIAN_VBUS,
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MAGICIAN_VBUS,
+ .end = IRQ_MAGICIAN_VBUS,
};
static struct gpio_vbus_mach_info gpio_vbus_info = {
- .gpio_pullup = GPIO27_MAGICIAN_USBC_PUEN,
- .gpio_vbus = EGPIO_MAGICIAN_CABLE_STATE_USB,
+ .gpio_pullup = GPIO27_MAGICIAN_USBC_PUEN,
+ .gpio_vbus = EGPIO_MAGICIAN_CABLE_VBUS,
};
static struct platform_device gpio_vbus = {
- .name = "gpio-vbus",
- .id = -1,
- .num_resources = 1,
- .resource = &gpio_vbus_resource,
+ .name = "gpio-vbus",
+ .id = -1,
+ .num_resources = 1,
+ .resource = &gpio_vbus_resource,
.dev = {
.platform_data = &gpio_vbus_info,
},
@@ -521,19 +528,60 @@ static struct platform_device gpio_vbus = {
* External power
*/
-static int power_supply_init(struct device *dev)
+static int magician_supply_init(struct device *dev)
+{
+ int ret = -1;
+
+ ret = gpio_request(EGPIO_MAGICIAN_CABLE_TYPE, "Cable is AC charger");
+ if (ret) {
+ pr_err("Cannot request AC/USB charger GPIO (%i)\n", ret);
+ goto err_ac;
+ }
+
+ ret = gpio_request(EGPIO_MAGICIAN_CABLE_INSERTED, "Cable inserted");
+ if (ret) {
+ pr_err("Cannot request cable detection GPIO (%i)\n", ret);
+ goto err_usb;
+ }
+
+ return 0;
+
+err_usb:
+ gpio_free(EGPIO_MAGICIAN_CABLE_TYPE);
+err_ac:
+ return ret;
+}
+
+static void magician_set_charge(int flags)
{
- return gpio_request(EGPIO_MAGICIAN_CABLE_STATE_AC, "CABLE_STATE_AC");
+ if (flags & PDA_POWER_CHARGE_AC) {
+ pr_debug("Charging from AC\n");
+ gpio_set_value(EGPIO_MAGICIAN_NICD_CHARGE, 1);
+ } else if (flags & PDA_POWER_CHARGE_USB) {
+ pr_debug("Charging from USB\n");
+ gpio_set_value(EGPIO_MAGICIAN_NICD_CHARGE, 1);
+ } else {
+ pr_debug("Charging disabled\n");
+ gpio_set_value(EGPIO_MAGICIAN_NICD_CHARGE, 0);
+ }
}
static int magician_is_ac_online(void)
{
- return gpio_get_value(EGPIO_MAGICIAN_CABLE_STATE_AC);
+ return gpio_get_value(EGPIO_MAGICIAN_CABLE_INSERTED) &&
+ gpio_get_value(EGPIO_MAGICIAN_CABLE_TYPE); /* AC=1 */
}
-static void power_supply_exit(struct device *dev)
+static int magician_is_usb_online(void)
{
- gpio_free(EGPIO_MAGICIAN_CABLE_STATE_AC);
+ return gpio_get_value(EGPIO_MAGICIAN_CABLE_INSERTED) &&
+ (!gpio_get_value(EGPIO_MAGICIAN_CABLE_TYPE)); /* USB=0 */
+}
+
+static void magician_supply_exit(struct device *dev)
+{
+ gpio_free(EGPIO_MAGICIAN_CABLE_INSERTED);
+ gpio_free(EGPIO_MAGICIAN_CABLE_TYPE);
}
static char *magician_supplicants[] = {
@@ -541,38 +589,40 @@ static char *magician_supplicants[] = {
};
static struct pda_power_pdata power_supply_info = {
- .init = power_supply_init,
- .is_ac_online = magician_is_ac_online,
- .exit = power_supply_exit,
- .supplied_to = magician_supplicants,
- .num_supplicants = ARRAY_SIZE(magician_supplicants),
+ .init = magician_supply_init,
+ .exit = magician_supply_exit,
+ .is_ac_online = magician_is_ac_online,
+ .is_usb_online = magician_is_usb_online,
+ .set_charge = magician_set_charge,
+ .supplied_to = magician_supplicants,
+ .num_supplicants = ARRAY_SIZE(magician_supplicants),
};
static struct resource power_supply_resources[] = {
[0] = {
- .name = "ac",
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
- IORESOURCE_IRQ_LOWEDGE,
- .start = IRQ_MAGICIAN_VBUS,
- .end = IRQ_MAGICIAN_VBUS,
+ .name = "ac",
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_LOWEDGE,
+ .start = IRQ_MAGICIAN_VBUS,
+ .end = IRQ_MAGICIAN_VBUS,
},
[1] = {
- .name = "usb",
- .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
- IORESOURCE_IRQ_LOWEDGE,
- .start = IRQ_MAGICIAN_VBUS,
- .end = IRQ_MAGICIAN_VBUS,
+ .name = "usb",
+ .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE |
+ IORESOURCE_IRQ_LOWEDGE,
+ .start = IRQ_MAGICIAN_VBUS,
+ .end = IRQ_MAGICIAN_VBUS,
},
};
static struct platform_device power_supply = {
- .name = "pda-power",
- .id = -1,
- .dev = {
+ .name = "pda-power",
+ .id = -1,
+ .dev = {
.platform_data = &power_supply_info,
},
- .resource = power_supply_resources,
- .num_resources = ARRAY_SIZE(power_supply_resources),
+ .resource = power_supply_resources,
+ .num_resources = ARRAY_SIZE(power_supply_resources),
};
/*
@@ -586,11 +636,12 @@ static struct regulator_consumer_supply bq24022_consumers[] = {
static struct regulator_init_data bq24022_init_data = {
.constraints = {
- .max_uA = 500000,
- .valid_ops_mask = REGULATOR_CHANGE_CURRENT | REGULATOR_CHANGE_STATUS,
+ .max_uA = 500000,
+ .valid_ops_mask = REGULATOR_CHANGE_CURRENT |
+ REGULATOR_CHANGE_STATUS,
},
- .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers),
- .consumer_supplies = bq24022_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(bq24022_consumers),
+ .consumer_supplies = bq24022_consumers,
};
static struct gpio bq24022_gpios[] = {
@@ -603,39 +654,85 @@ static struct gpio_regulator_state bq24022_states[] = {
};
static struct gpio_regulator_config bq24022_info = {
- .supply_name = "bq24022",
+ .supply_name = "bq24022",
- .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
- .enable_high = 0,
- .enabled_at_boot = 0,
+ .enable_gpio = GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,
+ .enable_high = 0,
+ .enabled_at_boot = 1,
- .gpios = bq24022_gpios,
- .nr_gpios = ARRAY_SIZE(bq24022_gpios),
+ .gpios = bq24022_gpios,
+ .nr_gpios = ARRAY_SIZE(bq24022_gpios),
- .states = bq24022_states,
- .nr_states = ARRAY_SIZE(bq24022_states),
+ .states = bq24022_states,
+ .nr_states = ARRAY_SIZE(bq24022_states),
- .type = REGULATOR_CURRENT,
- .init_data = &bq24022_init_data,
+ .type = REGULATOR_CURRENT,
+ .init_data = &bq24022_init_data,
};
static struct platform_device bq24022 = {
- .name = "gpio-regulator",
- .id = -1,
- .dev = {
+ .name = "gpio-regulator",
+ .id = -1,
+ .dev = {
.platform_data = &bq24022_info,
},
};
/*
+ * Vcore regulator MAX1587A
+ */
+
+static struct regulator_consumer_supply magician_max1587a_consumers[] = {
+ REGULATOR_SUPPLY("vcc_core", NULL),
+};
+
+static struct regulator_init_data magician_max1587a_v3_info = {
+ .constraints = {
+ .name = "vcc_core range",
+ .min_uV = 700000,
+ .max_uV = 1475000,
+ .always_on = 1,
+ .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE,
+ },
+ .consumer_supplies = magician_max1587a_consumers,
+ .num_consumer_supplies = ARRAY_SIZE(magician_max1587a_consumers),
+};
+
+static struct max1586_subdev_data magician_max1587a_subdevs[] = {
+ {
+ .name = "vcc_core",
+ .id = MAX1586_V3,
+ .platform_data = &magician_max1587a_v3_info,
+ }
+};
+
+static struct max1586_platform_data magician_max1587a_info = {
+ .subdevs = magician_max1587a_subdevs,
+ .num_subdevs = ARRAY_SIZE(magician_max1587a_subdevs),
+ /*
+ * NOTICE measured directly on the PCB (board_id == 0x3a), but
+ * if R24 is present, it will boost the voltage
+ * (write 1.475V, get 1.645V and smoke)
+ */
+ .v3_gain = MAX1586_GAIN_NO_R24,
+};
+
+static struct i2c_board_info magician_pwr_i2c_board_info[] __initdata = {
+ {
+ I2C_BOARD_INFO("max1586", 0x14),
+ .platform_data = &magician_max1587a_info,
+ },
+};
+
+/*
* MMC/SD
*/
static int magician_mci_init(struct device *dev,
- irq_handler_t detect_irq, void *data)
+ irq_handler_t detect_irq, void *data)
{
return request_irq(IRQ_MAGICIAN_SD, detect_irq, 0,
- "mmc card detect", data);
+ "mmc card detect", data);
}
static void magician_mci_exit(struct device *dev, void *data)
@@ -644,9 +741,9 @@ static void magician_mci_exit(struct device *dev, void *data)
}
static struct pxamci_platform_data magician_mci_info = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .init = magician_mci_init,
- .exit = magician_mci_exit,
+ .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
+ .init = magician_mci_init,
+ .exit = magician_mci_exit,
.gpio_card_detect = -1,
.gpio_card_ro = EGPIO_MAGICIAN_nSD_READONLY,
.gpio_card_ro_invert = 1,
@@ -660,47 +757,102 @@ static struct pxamci_platform_data magician_mci_info = {
static struct pxaohci_platform_data magician_ohci_info = {
.port_mode = PMM_PERPORT_MODE,
- .flags = ENABLE_PORT1 | ENABLE_PORT3 | POWER_CONTROL_LOW,
+ /* port1: CSR Bluetooth, port2: OTG with UDC */
+ .flags = ENABLE_PORT1 | ENABLE_PORT2 | POWER_CONTROL_LOW,
.power_budget = 0,
+ .power_on_delay = 100,
};
-
/*
* StrataFlash
*/
+static int magician_flash_init(struct platform_device *pdev)
+{
+ int ret = gpio_request(EGPIO_MAGICIAN_FLASH_VPP, "flash Vpp enable");
+
+ if (ret) {
+ pr_err("Cannot request flash enable GPIO (%i)\n", ret);
+ return ret;
+ }
+
+ ret = gpio_direction_output(EGPIO_MAGICIAN_FLASH_VPP, 1);
+ if (ret) {
+ pr_err("Cannot set direction for flash enable (%i)\n", ret);
+ gpio_free(EGPIO_MAGICIAN_FLASH_VPP);
+ }
+
+ return ret;
+}
+
static void magician_set_vpp(struct platform_device *pdev, int vpp)
{
gpio_set_value(EGPIO_MAGICIAN_FLASH_VPP, vpp);
}
+static void magician_flash_exit(struct platform_device *pdev)
+{
+ gpio_free(EGPIO_MAGICIAN_FLASH_VPP);
+}
+
static struct resource strataflash_resource = {
- .start = PXA_CS0_PHYS,
- .end = PXA_CS0_PHYS + SZ_64M - 1,
- .flags = IORESOURCE_MEM,
+ .start = PXA_CS0_PHYS,
+ .end = PXA_CS0_PHYS + SZ_64M - 1,
+ .flags = IORESOURCE_MEM,
};
+static struct mtd_partition magician_flash_parts[] = {
+ {
+ .name = "Bootloader",
+ .offset = 0x0,
+ .size = 0x40000,
+ .mask_flags = MTD_WRITEABLE, /* EXPERIMENTAL */
+ },
+ {
+ .name = "Linux Kernel",
+ .offset = 0x40000,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+/*
+ * physmap-flash driver
+ */
+
static struct physmap_flash_data strataflash_data = {
- .width = 4,
- .set_vpp = magician_set_vpp,
+ .width = 4,
+ .init = magician_flash_init,
+ .set_vpp = magician_set_vpp,
+ .exit = magician_flash_exit,
+ .parts = magician_flash_parts,
+ .nr_parts = ARRAY_SIZE(magician_flash_parts),
};
static struct platform_device strataflash = {
- .name = "physmap-flash",
- .id = -1,
- .resource = &strataflash_resource,
- .num_resources = 1,
+ .name = "physmap-flash",
+ .id = -1,
+ .resource = &strataflash_resource,
+ .num_resources = 1,
.dev = {
.platform_data = &strataflash_data,
},
};
/*
- * I2C
+ * PXA I2C main controller
*/
static struct i2c_pxa_platform_data i2c_info = {
- .fast_mode = 1,
+ /* OV9640 I2C device doesn't support fast mode */
+ .fast_mode = 0,
+};
+
+/*
+ * PXA I2C power controller
+ */
+
+static struct i2c_pxa_platform_data magician_i2c_power_info = {
+ .fast_mode = 1,
};
/*
@@ -720,12 +872,13 @@ static struct platform_device *devices[] __initdata = {
};
static struct gpio magician_global_gpios[] = {
- { GPIO13_MAGICIAN_CPLD_IRQ, GPIOF_IN, "CPLD_IRQ" },
+ { GPIO13_MAGICIAN_CPLD_IRQ, GPIOF_IN, "CPLD_IRQ" },
{ GPIO107_MAGICIAN_DS1WM_IRQ, GPIOF_IN, "DS1WM_IRQ" },
- { GPIO104_MAGICIAN_LCD_POWER_1, GPIOF_OUT_INIT_LOW, "LCD power 1" },
- { GPIO105_MAGICIAN_LCD_POWER_2, GPIOF_OUT_INIT_LOW, "LCD power 2" },
- { GPIO106_MAGICIAN_LCD_POWER_3, GPIOF_OUT_INIT_LOW, "LCD power 3" },
- { GPIO83_MAGICIAN_nIR_EN, GPIOF_OUT_INIT_HIGH, "nIR_EN" },
+
+ /* NOTICE valid LCD init sequence */
+ { GPIO106_MAGICIAN_LCD_DCDC_NRESET, GPIOF_OUT_INIT_LOW, "LCD DCDC nreset" },
+ { GPIO104_MAGICIAN_LCD_VOFF_EN, GPIOF_OUT_INIT_LOW, "LCD VOFF enable" },
+ { GPIO105_MAGICIAN_LCD_VON_EN, GPIOF_OUT_INIT_LOW, "LCD VON enable" },
};
static void __init magician_init(void)
@@ -737,44 +890,55 @@ static void __init magician_init(void)
pxa2xx_mfp_config(ARRAY_AND_SIZE(magician_pin_config));
err = gpio_request_array(ARRAY_AND_SIZE(magician_global_gpios));
if (err)
- pr_err("magician: Failed to request GPIOs: %d\n", err);
+ pr_err("magician: Failed to request global GPIOs: %d\n", err);
pxa_set_ffuart_info(NULL);
pxa_set_btuart_info(NULL);
- pxa_set_stuart_info(NULL);
- platform_add_devices(ARRAY_AND_SIZE(devices));
+ pwm_add_table(magician_pwm_lookup, ARRAY_SIZE(magician_pwm_lookup));
pxa_set_ficp_info(&magician_ficp_info);
- pxa27x_set_i2c_power_info(NULL);
+ pxa27x_set_i2c_power_info(&magician_i2c_power_info);
pxa_set_i2c_info(&i2c_info);
+
+ i2c_register_board_info(1,
+ ARRAY_AND_SIZE(magician_pwr_i2c_board_info));
+
pxa_set_mci_info(&magician_mci_info);
pxa_set_ohci_info(&magician_ohci_info);
+ pxa_set_udc_info(&magician_udc_info);
/* Check LCD type we have */
cpld = ioremap_nocache(PXA_CS3_PHYS, 0x1000);
if (cpld) {
- u8 board_id = __raw_readb(cpld+0x14);
+ u8 board_id = __raw_readb(cpld + 0x14);
+
iounmap(cpld);
system_rev = board_id & 0x7;
lcd_select = board_id & 0x8;
pr_info("LCD type: %s\n", lcd_select ? "Samsung" : "Toppoly");
if (lcd_select && (system_rev < 3))
+ /* NOTICE valid LCD init sequence */
gpio_request_one(GPIO75_MAGICIAN_SAMSUNG_POWER,
- GPIOF_OUT_INIT_LOW, "SAMSUNG_POWER");
- pxa_set_fb_info(NULL, lcd_select ? &samsung_info : &toppoly_info);
+ GPIOF_OUT_INIT_LOW, "Samsung LCD Power");
+ pxa_set_fb_info(NULL,
+ lcd_select ? &samsung_info : &toppoly_info);
} else
pr_err("LCD detection: CPLD mapping failed\n");
-}
+ regulator_register_always_on(0, "power", pwm_backlight_supply,
+ ARRAY_SIZE(pwm_backlight_supply), 5000000);
+
+ platform_add_devices(ARRAY_AND_SIZE(devices));
+}
MACHINE_START(MAGICIAN, "HTC Magician")
- .atag_offset = 0x100,
- .map_io = pxa27x_map_io,
- .nr_irqs = MAGICIAN_NR_IRQS,
- .init_irq = pxa27x_init_irq,
- .handle_irq = pxa27x_handle_irq,
- .init_machine = magician_init,
+ .atag_offset = 0x100,
+ .map_io = pxa27x_map_io,
+ .nr_irqs = MAGICIAN_NR_IRQS,
+ .init_irq = pxa27x_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .init_machine = magician_init,
.init_time = pxa_timer_init,
.restart = pxa_restart,
MACHINE_END
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 2c0658c..c3a87c1 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -26,6 +26,7 @@
#include <linux/mtd/partitions.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/smc91x.h>
#include <linux/i2c/pxa-i2c.h>
@@ -248,11 +249,14 @@ static struct platform_device mst_flash_device[2] = {
};
#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static struct pwm_lookup mainstone_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 78770,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data mainstone_backlight_data = {
- .pwm_id = 0,
.max_brightness = 1023,
.dft_brightness = 1023,
- .pwm_period_ns = 78770,
.enable_gpio = -1,
};
@@ -266,9 +270,16 @@ static struct platform_device mainstone_backlight_device = {
static void __init mainstone_backlight_register(void)
{
- int ret = platform_device_register(&mainstone_backlight_device);
- if (ret)
+ int ret;
+
+ pwm_add_table(mainstone_pwm_lookup, ARRAY_SIZE(mainstone_pwm_lookup));
+
+ ret = platform_device_register(&mainstone_backlight_device);
+ if (ret) {
printk(KERN_ERR "mainstone: failed to register backlight device: %d\n", ret);
+ pwm_remove_table(mainstone_pwm_lookup,
+ ARRAY_SIZE(mainstone_pwm_lookup));
+ }
}
#else
#define mainstone_backlight_register() do { } while (0)
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 29997bd..ccfd2b6 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -26,6 +26,7 @@
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/gpio_keys.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/rtc.h>
#include <linux/leds.h>
@@ -53,7 +54,7 @@
#include <linux/platform_data/mmc-pxamci.h>
#include <mach/udc.h>
#include <mach/pxa27x-udc.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include <mach/audio.h>
#include <mach/smemc.h>
#include <media/soc_camera.h>
@@ -181,12 +182,15 @@ static unsigned long mioa701_pin_config[] = {
MFP_CFG_OUT(GPIO116, AF0, DRIVE_HIGH),
};
+static struct pwm_lookup mioa701_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight", NULL, 4000 * 1024,
+ PWM_POLARITY_NORMAL),
+};
+
/* LCD Screen and Backlight */
static struct platform_pwm_backlight_data mioa701_backlight_data = {
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 50,
- .pwm_period_ns = 4000 * 1024, /* Fl = 250kHz */
.enable_gpio = -1,
};
@@ -678,6 +682,7 @@ MIO_SIMPLE_DEV(mioa701_led, "leds-gpio", &gpio_led_info)
MIO_SIMPLE_DEV(pxa2xx_pcm, "pxa2xx-pcm", NULL)
MIO_SIMPLE_DEV(mioa701_sound, "mioa701-wm9713", NULL)
MIO_SIMPLE_DEV(mioa701_board, "mioa701-board", NULL)
+MIO_SIMPLE_DEV(wm9713_acodec, "wm9713-codec", NULL);
MIO_SIMPLE_DEV(gpio_vbus, "gpio-vbus", &gpio_vbus_data);
MIO_SIMPLE_DEV(mioa701_camera, "soc-camera-pdrv",&iclink);
@@ -685,6 +690,7 @@ static struct platform_device *devices[] __initdata = {
&mioa701_gpio_keys,
&mioa701_backlight,
&mioa701_led,
+ &wm9713_acodec,
&pxa2xx_pcm,
&mioa701_sound,
&power_dev,
@@ -751,6 +757,7 @@ static void __init mioa701_machine_init(void)
pxa_set_udc_info(&mioa701_udc_info);
pxa_set_ac97_info(&mioa701_ac97_info);
pm_power_off = mioa701_poweroff;
+ pwm_add_table(mioa701_pwm_lookup, ARRAY_SIZE(mioa701_pwm_lookup));
platform_add_devices(devices, ARRAY_SIZE(devices));
gsm_init();
diff --git a/arch/arm/mach-pxa/palm27x.c b/arch/arm/mach-pxa/palm27x.c
index e54a296..8fbfb10 100644
--- a/arch/arm/mach-pxa/palm27x.c
+++ b/arch/arm/mach-pxa/palm27x.c
@@ -15,6 +15,7 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/pda_power.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/wm97xx.h>
@@ -270,6 +271,11 @@ void __init palm27x_ac97_init(int minv, int maxv, int jack, int reset)
* Backlight
******************************************************************************/
#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct pwm_lookup palm27x_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 3500 * 1024,
+ PWM_POLARITY_NORMAL),
+};
+
static int palm_bl_power;
static int palm_lcd_power;
@@ -318,10 +324,8 @@ static void palm27x_backlight_exit(struct device *dev)
}
static struct platform_pwm_backlight_data palm27x_backlight_data = {
- .pwm_id = 0,
.max_brightness = 0xfe,
.dft_brightness = 0x7e,
- .pwm_period_ns = 3500 * 1024,
.enable_gpio = -1,
.init = palm27x_backlight_init,
.notify = palm27x_backlight_notify,
@@ -340,6 +344,7 @@ void __init palm27x_pwm_init(int bl, int lcd)
{
palm_bl_power = bl;
palm_lcd_power = lcd;
+ pwm_add_table(palm27x_pwm_lookup, ARRAY_SIZE(palm27x_pwm_lookup));
platform_device_register(&palm27x_backlight);
}
#endif
diff --git a/arch/arm/mach-pxa/palmtc.c b/arch/arm/mach-pxa/palmtc.c
index 7691c97..0b5c387 100644
--- a/arch/arm/mach-pxa/palmtc.c
+++ b/arch/arm/mach-pxa/palmtc.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/input.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/input/matrix_keypad.h>
@@ -166,11 +167,14 @@ static inline void palmtc_keys_init(void) {}
* Backlight
******************************************************************************/
#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct pwm_lookup palmtc_pwm_lookup[] = {
+ PWM_LOOKUP("pxa25x-pwm.1", 0, "pwm-backlight.0", NULL, PALMTC_PERIOD_NS,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data palmtc_backlight_data = {
- .pwm_id = 1,
.max_brightness = PALMTC_MAX_INTENSITY,
.dft_brightness = PALMTC_MAX_INTENSITY,
- .pwm_period_ns = PALMTC_PERIOD_NS,
.enable_gpio = GPIO_NR_PALMTC_BL_POWER,
};
@@ -184,6 +188,7 @@ static struct platform_device palmtc_backlight = {
static void __init palmtc_pwm_init(void)
{
+ pwm_add_table(palmtc_pwm_lookup, ARRAY_SIZE(palmtc_pwm_lookup));
platform_device_register(&palmtc_backlight);
}
#else
diff --git a/arch/arm/mach-pxa/palmte2.c b/arch/arm/mach-pxa/palmte2.c
index 956fd24..e64bb43 100644
--- a/arch/arm/mach-pxa/palmte2.c
+++ b/arch/arm/mach-pxa/palmte2.c
@@ -21,6 +21,7 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/pda_power.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/wm97xx.h>
@@ -138,6 +139,11 @@ static struct platform_device palmte2_pxa_keys = {
/******************************************************************************
* Backlight
******************************************************************************/
+static struct pwm_lookup palmte2_pwm_lookup[] = {
+ PWM_LOOKUP("pxa25x-pwm.0", 0, "pwm-backlight.0", NULL,
+ PALMTE2_PERIOD_NS, PWM_POLARITY_NORMAL),
+};
+
static struct gpio palmte_bl_gpios[] = {
{ GPIO_NR_PALMTE2_BL_POWER, GPIOF_INIT_LOW, "Backlight power" },
{ GPIO_NR_PALMTE2_LCD_POWER, GPIOF_INIT_LOW, "LCD power" },
@@ -161,10 +167,8 @@ static void palmte2_backlight_exit(struct device *dev)
}
static struct platform_pwm_backlight_data palmte2_backlight_data = {
- .pwm_id = 0,
.max_brightness = PALMTE2_MAX_INTENSITY,
.dft_brightness = PALMTE2_MAX_INTENSITY,
- .pwm_period_ns = PALMTE2_PERIOD_NS,
.enable_gpio = -1,
.init = palmte2_backlight_init,
.notify = palmte2_backlight_notify,
@@ -355,6 +359,7 @@ static void __init palmte2_init(void)
pxa_set_ac97_info(&palmte2_ac97_pdata);
pxa_set_ficp_info(&palmte2_ficp_platform_data);
+ pwm_add_table(palmte2_pwm_lookup, ARRAY_SIZE(palmte2_pwm_lookup));
platform_add_devices(devices, ARRAY_SIZE(devices));
}
diff --git a/arch/arm/mach-pxa/palmtreo.c b/arch/arm/mach-pxa/palmtreo.c
index d8b937c..2dc5606 100644
--- a/arch/arm/mach-pxa/palmtreo.c
+++ b/arch/arm/mach-pxa/palmtreo.c
@@ -43,7 +43,7 @@
#include <linux/platform_data/usb-ohci-pxa27x.h>
#include <mach/pxa2xx-regs.h>
#include <linux/platform_data/asoc-palm27x.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include <mach/palm27x.h>
#include <sound/pxa2xx-lib.h>
diff --git a/arch/arm/mach-pxa/palmz72.c b/arch/arm/mach-pxa/palmz72.c
index 1a35ddf..e3df17a 100644
--- a/arch/arm/mach-pxa/palmz72.c
+++ b/arch/arm/mach-pxa/palmz72.c
@@ -49,7 +49,7 @@
#include <mach/palm27x.h>
#include <mach/pm.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include <media/soc_camera.h>
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index d8319b5..8459239 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -24,12 +24,13 @@
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
-#include <media/mt9v022.h>
+#include <media/i2c/mt9v022.h>
#include <media/soc_camera.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#include <asm/mach/map.h>
#include <mach/pxa27x.h>
#include <mach/audio.h>
@@ -148,11 +149,14 @@ static struct pxafb_mach_info pcm990_fbinfo __initdata = {
};
#endif
+static struct pwm_lookup pcm990_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.0", NULL, 78770,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data pcm990_backlight_data = {
- .pwm_id = 0,
.max_brightness = 1023,
.dft_brightness = 1023,
- .pwm_period_ns = 78770,
.enable_gpio = -1,
};
@@ -542,6 +546,7 @@ void __init pcm990_baseboard_init(void)
#ifndef CONFIG_PCM990_DISPLAY_NONE
pxa_set_fb_info(NULL, &pcm990_fbinfo);
#endif
+ pwm_add_table(pcm990_pwm_lookup, ARRAY_SIZE(pcm990_pwm_lookup));
platform_device_register(&pcm990_backlight_device);
/* MMC */
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 221260d..ffc4240 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(pxa27x_configure_ac97reset);
*/
static unsigned int pwrmode = PWRMODE_SLEEP;
-int __init pxa27x_set_pwrmode(unsigned int mode)
+int pxa27x_set_pwrmode(unsigned int mode)
{
switch (mode) {
case PWRMODE_SLEEP:
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 88f70c3..36571a9 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -29,6 +29,7 @@
#include <linux/leds.h>
#include <linux/w1-gpio.h>
#include <linux/sched.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/i2c.h>
#include <linux/i2c/pxa-i2c.h>
@@ -507,7 +508,7 @@ static struct w1_gpio_platform_data w1_gpio_platform_data = {
.ext_pullup_enable_pin = -EINVAL,
};
-struct platform_device raumfeld_w1_gpio_device = {
+static struct platform_device raumfeld_w1_gpio_device = {
.name = "w1-gpio",
.dev = {
.platform_data = &w1_gpio_platform_data
@@ -531,13 +532,15 @@ static void __init raumfeld_w1_init(void)
* Framebuffer device
*/
+static struct pwm_lookup raumfeld_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight", NULL, 10000,
+ PWM_POLARITY_NORMAL),
+};
+
/* PWM controlled backlight */
static struct platform_pwm_backlight_data raumfeld_pwm_backlight_data = {
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 100,
- /* 10000 ns = 10 ms ^= 100 kHz */
- .pwm_period_ns = 10000,
.enable_gpio = -1,
};
@@ -618,6 +621,8 @@ static void __init raumfeld_lcd_init(void)
} else {
mfp_cfg_t raumfeld_pwm_pin_config = GPIO17_PWM0_OUT;
pxa3xx_mfp_config(&raumfeld_pwm_pin_config, 1);
+ pwm_add_table(raumfeld_pwm_lookup,
+ ARRAY_SIZE(raumfeld_pwm_lookup));
platform_device_register(&raumfeld_pwm_backlight_device);
}
@@ -629,7 +634,7 @@ static void __init raumfeld_lcd_init(void)
* SPI devices
*/
-struct spi_gpio_platform_data raumfeld_spi_platform_data = {
+static struct spi_gpio_platform_data raumfeld_spi_platform_data = {
.sck = GPIO_SPI_CLK,
.mosi = GPIO_SPI_MOSI,
.miso = GPIO_SPI_MISO,
@@ -848,7 +853,7 @@ static void __init raumfeld_power_init(void)
static struct regulator_consumer_supply audio_va_consumer_supply =
REGULATOR_SUPPLY("va", "0-0048");
-struct regulator_init_data audio_va_initdata = {
+static struct regulator_init_data audio_va_initdata = {
.consumer_supplies = &audio_va_consumer_supply,
.num_consumer_supplies = 1,
.constraints = {
@@ -880,7 +885,7 @@ static struct regulator_consumer_supply audio_dummy_supplies[] = {
REGULATOR_SUPPLY("vlc", "0-0048"),
};
-struct regulator_init_data audio_dummy_initdata = {
+static struct regulator_init_data audio_dummy_initdata = {
.consumer_supplies = audio_dummy_supplies,
.num_consumer_supplies = ARRAY_SIZE(audio_dummy_supplies),
.constraints = {
@@ -928,7 +933,7 @@ static struct regulator_init_data vcc_mmc_init_data = {
.num_consumer_supplies = 1,
};
-struct max8660_subdev_data max8660_v6_subdev_data = {
+static struct max8660_subdev_data max8660_v6_subdev_data = {
.id = MAX8660_V6,
.name = "vmmc",
.platform_data = &vcc_mmc_init_data,
diff --git a/arch/arm/mach-pxa/tavorevb.c b/arch/arm/mach-pxa/tavorevb.c
index a71da84..349a13a 100644
--- a/arch/arm/mach-pxa/tavorevb.c
+++ b/arch/arm/mach-pxa/tavorevb.c
@@ -18,6 +18,7 @@
#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/smc91x.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <asm/mach-types.h>
@@ -168,21 +169,24 @@ static inline void tavorevb_init_keypad(void) {}
#endif /* CONFIG_KEYBOARD_PXA27x || CONFIG_KEYBOARD_PXA27x_MODULE */
#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static struct pwm_lookup tavorevb_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.0", 1, "pwm-backlight.0", NULL, 100000,
+ PWM_POLARITY_NORMAL),
+ PWM_LOOKUP("pxa27x-pwm.0", 0, "pwm-backlight.1", NULL, 100000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data tavorevb_backlight_data[] = {
[0] = {
/* primary backlight */
- .pwm_id = 2,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 100000,
.enable_gpio = -1,
},
[1] = {
/* secondary backlight */
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 100000,
.enable_gpio = -1,
},
};
@@ -470,6 +474,7 @@ static struct pxafb_mach_info tavorevb_lcd_info = {
static void __init tavorevb_init_lcd(void)
{
+ pwm_add_table(tavorevb_pwm_lookup, ARRAY_SIZE(tavorevb_pwm_lookup));
platform_device_register(&tavorevb_backlight_devices[0]);
platform_device_register(&tavorevb_backlight_devices[1]);
pxa_set_fb_info(NULL, &tavorevb_lcd_info);
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index 8ab2637..7ecc61a 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -39,6 +39,7 @@
#include <linux/i2c/pxa-i2c.h>
#include <linux/serial_8250.h>
#include <linux/smc91x.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/usb/isp116x.h>
#include <linux/mtd/mtd.h>
@@ -350,6 +351,11 @@ static struct pxafb_mach_info fb_info = {
.lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
};
+static struct pwm_lookup viper_pwm_lookup[] = {
+ PWM_LOOKUP("pxa25x-pwm.0", 0, "pwm-backlight.0", NULL, 1000000,
+ PWM_POLARITY_NORMAL),
+};
+
static int viper_backlight_init(struct device *dev)
{
int ret;
@@ -398,10 +404,8 @@ static void viper_backlight_exit(struct device *dev)
}
static struct platform_pwm_backlight_data viper_backlight_data = {
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 1000000,
.enable_gpio = -1,
.init = viper_backlight_init,
.notify = viper_backlight_notify,
@@ -939,6 +943,7 @@ static void __init viper_init(void)
smc91x_device.num_resources--;
pxa_set_i2c_info(NULL);
+ pwm_add_table(viper_pwm_lookup, ARRAY_SIZE(viper_pwm_lookup));
platform_add_devices(viper_devs, ARRAY_SIZE(viper_devs));
viper_init_vcore_gpios();
diff --git a/arch/arm/mach-pxa/z2.c b/arch/arm/mach-pxa/z2.c
index e1a121b..d9899d7 100644
--- a/arch/arm/mach-pxa/z2.c
+++ b/arch/arm/mach-pxa/z2.c
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/z2_battery.h>
#include <linux/dma-mapping.h>
@@ -199,21 +200,24 @@ static inline void z2_nor_init(void) {}
* Backlight
******************************************************************************/
#if defined(CONFIG_BACKLIGHT_PWM) || defined(CONFIG_BACKLIGHT_PWM_MODULE)
+static struct pwm_lookup z2_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.1", 0, "pwm-backlight.0", NULL, 1260320,
+ PWM_POLARITY_NORMAL),
+ PWM_LOOKUP("pxa27x-pwm.0", 1, "pwm-backlight.1", NULL, 1260320,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data z2_backlight_data[] = {
[0] = {
/* Keypad Backlight */
- .pwm_id = 1,
.max_brightness = 1023,
.dft_brightness = 0,
- .pwm_period_ns = 1260320,
.enable_gpio = -1,
},
[1] = {
/* LCD Backlight */
- .pwm_id = 2,
.max_brightness = 1023,
.dft_brightness = 512,
- .pwm_period_ns = 1260320,
.enable_gpio = -1,
},
};
@@ -236,6 +240,7 @@ static struct platform_device z2_backlight_devices[2] = {
};
static void __init z2_pwm_init(void)
{
+ pwm_add_table(z2_pwm_lookup, ARRAY_SIZE(z2_pwm_lookup));
platform_device_register(&z2_backlight_devices[0]);
platform_device_register(&z2_backlight_devices[1]);
}
@@ -595,13 +600,11 @@ static struct spi_board_info spi_board_info[] __initdata = {
};
static struct pxa2xx_spi_master pxa_ssp1_master_info = {
- .clock_enable = CKEN_SSP,
.num_chipselect = 1,
.enable_dma = 1,
};
static struct pxa2xx_spi_master pxa_ssp2_master_info = {
- .clock_enable = CKEN_SSP2,
.num_chipselect = 1,
};
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index 77daea4..e20359a 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -19,6 +19,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/smc91x.h>
@@ -120,11 +121,14 @@ static inline void zylonite_init_leds(void) {}
#endif
#if defined(CONFIG_FB_PXA) || defined(CONFIG_FB_PXA_MODULE)
+static struct pwm_lookup zylonite_pwm_lookup[] = {
+ PWM_LOOKUP("pxa27x-pwm.1", 1, "pwm-backlight.0", NULL, 10000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data zylonite_backlight_data = {
- .pwm_id = 3,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 10000,
.enable_gpio = -1,
};
@@ -206,6 +210,7 @@ static struct pxafb_mach_info zylonite_sharp_lcd_info = {
static void __init zylonite_init_lcd(void)
{
+ pwm_add_table(zylonite_pwm_lookup, ARRAY_SIZE(zylonite_pwm_lookup));
platform_device_register(&zylonite_backlight_device);
if (lcd_id & 0x20) {
diff --git a/arch/arm/mach-qcom/platsmp.c b/arch/arm/mach-qcom/platsmp.c
index 5cde63a..9b00123 100644
--- a/arch/arm/mach-qcom/platsmp.c
+++ b/arch/arm/mach-qcom/platsmp.c
@@ -49,7 +49,7 @@ extern void secondary_startup_arm(void);
static DEFINE_SPINLOCK(boot_lock);
#ifdef CONFIG_HOTPLUG_CPU
-static void __ref qcom_cpu_die(unsigned int cpu)
+static void qcom_cpu_die(unsigned int cpu)
{
wfi();
}
diff --git a/arch/arm/mach-realview/hotplug.c b/arch/arm/mach-realview/hotplug.c
index ac22dd4..968e2d1 100644
--- a/arch/arm/mach-realview/hotplug.c
+++ b/arch/arm/mach-realview/hotplug.c
@@ -90,7 +90,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
*
* Called with IRQs disabled
*/
-void __ref realview_cpu_die(unsigned int cpu)
+void realview_cpu_die(unsigned int cpu)
{
int spurious = 0;
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index d40d4f5..9f54300 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/i2c.h>
#include <linux/leds.h>
@@ -469,6 +470,11 @@ static struct s3c24xx_mci_pdata h1940_mmc_cfg __initdata = {
.ocr_avail = MMC_VDD_32_33,
};
+static struct pwm_lookup h1940_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 36296,
+ PWM_POLARITY_NORMAL),
+};
+
static int h1940_backlight_init(struct device *dev)
{
gpio_request(S3C2410_GPB(0), "Backlight");
@@ -503,11 +509,8 @@ static void h1940_backlight_exit(struct device *dev)
static struct platform_pwm_backlight_data backlight_data = {
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 50,
- /* tcnt = 0x31 */
- .pwm_period_ns = 36296,
.enable_gpio = -1,
.init = h1940_backlight_init,
.notify = h1940_backlight_notify,
@@ -725,6 +728,7 @@ static void __init h1940_init(void)
gpio_request(H1940_LATCH_SD_POWER, "SD power");
gpio_direction_output(H1940_LATCH_SD_POWER, 0);
+ pwm_add_table(h1940_pwm_lookup, ARRAY_SIZE(h1940_pwm_lookup));
platform_add_devices(h1940_devices, ARRAY_SIZE(h1940_devices));
gpio_request(S3C2410_GPA(1), "Red LED blink");
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index 1d35ff3..774c982 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -375,6 +375,11 @@ static struct s3c2410fb_mach_info rx1950_lcd_cfg = {
};
+static struct pwm_lookup rx1950_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight.0", NULL, 48000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct pwm_device *lcd_pwm;
static void rx1950_lcd_power(int enable)
@@ -520,10 +525,8 @@ static int rx1950_backlight_notify(struct device *dev, int brightness)
}
static struct platform_pwm_backlight_data rx1950_backlight_data = {
- .pwm_id = 0,
.max_brightness = 24,
.dft_brightness = 4,
- .pwm_period_ns = 48000,
.enable_gpio = -1,
.init = rx1950_backlight_init,
.notify = rx1950_backlight_notify,
@@ -792,6 +795,7 @@ static void __init rx1950_init_machine(void)
gpio_direction_output(S3C2410_GPA(4), 0);
gpio_direction_output(S3C2410_GPJ(6), 0);
+ pwm_add_table(rx1950_pwm_lookup, ARRAY_SIZE(rx1950_pwm_lookup));
platform_add_devices(rx1950_devices, ARRAY_SIZE(rx1950_devices));
i2c_register_board_info(0, rx1950_i2c_devices,
diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
index a19460e..b355fca 100644
--- a/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-12000000.c
@@ -20,7 +20,7 @@
#include <plat/cpu.h>
#include <plat/cpu-freq-core.h>
-static struct cpufreq_frequency_table s3c2440_plls_12[] __initdata = {
+static struct cpufreq_frequency_table s3c2440_plls_12[] = {
{ .frequency = 75000000, .driver_data = PLLVAL(0x75, 3, 3), }, /* FVco 600.000000 */
{ .frequency = 80000000, .driver_data = PLLVAL(0x98, 4, 3), }, /* FVco 640.000000 */
{ .frequency = 90000000, .driver_data = PLLVAL(0x70, 2, 3), }, /* FVco 720.000000 */
diff --git a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
index 1191b29..be9a248 100644
--- a/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
+++ b/arch/arm/mach-s3c24xx/pll-s3c2440-16934400.c
@@ -20,7 +20,7 @@
#include <plat/cpu.h>
#include <plat/cpu-freq-core.h>
-static struct cpufreq_frequency_table s3c2440_plls_169344[] __initdata = {
+static struct cpufreq_frequency_table s3c2440_plls_169344[] = {
{ .frequency = 78019200, .driver_data = PLLVAL(121, 5, 3), }, /* FVco 624.153600 */
{ .frequency = 84067200, .driver_data = PLLVAL(131, 5, 3), }, /* FVco 672.537600 */
{ .frequency = 90115200, .driver_data = PLLVAL(141, 5, 3), }, /* FVco 720.921600 */
diff --git a/arch/arm/mach-s3c64xx/dev-backlight.c b/arch/arm/mach-s3c64xx/dev-backlight.c
index 38c323e..e62e789 100644
--- a/arch/arm/mach-s3c64xx/dev-backlight.c
+++ b/arch/arm/mach-s3c64xx/dev-backlight.c
@@ -69,7 +69,6 @@ static struct samsung_bl_drvdata samsung_dfl_bl_data __initdata = {
.plat_data = {
.max_brightness = 255,
.dft_brightness = 255,
- .pwm_period_ns = 78770,
.enable_gpio = -1,
.init = samsung_bl_init,
.exit = samsung_bl_exit,
@@ -111,7 +110,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
samsung_bl_data = &samsung_bl_drvdata->plat_data;
/* Copy board specific data provided by user */
- samsung_bl_data->pwm_id = bl_data->pwm_id;
samsung_bl_device->dev.parent = &samsung_device_pwm.dev;
if (bl_data->max_brightness)
@@ -120,8 +118,6 @@ void __init samsung_bl_set(struct samsung_bl_gpio_info *gpio_info,
samsung_bl_data->dft_brightness = bl_data->dft_brightness;
if (bl_data->lth_brightness)
samsung_bl_data->lth_brightness = bl_data->lth_brightness;
- if (bl_data->pwm_period_ns)
- samsung_bl_data->pwm_period_ns = bl_data->pwm_period_ns;
if (bl_data->enable_gpio >= 0)
samsung_bl_data->enable_gpio = bl_data->enable_gpio;
if (bl_data->init)
diff --git a/arch/arm/mach-s3c64xx/mach-crag6410.c b/arch/arm/mach-s3c64xx/mach-crag6410.c
index 14bd9ae..f776adc 100644
--- a/arch/arm/mach-s3c64xx/mach-crag6410.c
+++ b/arch/arm/mach-s3c64xx/mach-crag6410.c
@@ -25,6 +25,7 @@
#include <linux/mmc/host.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/fixed.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/dm9000.h>
#include <linux/gpio_keys.h>
@@ -108,11 +109,14 @@ static struct s3c2410_uartcfg crag6410_uartcfgs[] __initdata = {
},
};
+static struct pwm_lookup crag6410_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 0, "pwm-backlight", NULL, 100000,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data crag6410_backlight_data = {
- .pwm_id = 0,
.max_brightness = 1000,
.dft_brightness = 600,
- .pwm_period_ns = 100000, /* about 1kHz */
.enable_gpio = -1,
};
@@ -843,6 +847,7 @@ static void __init crag6410_machine_init(void)
samsung_keypad_set_platdata(&crag6410_keypad_data);
s3c64xx_spi0_set_platdata(NULL, 0, 2);
+ pwm_add_table(crag6410_pwm_lookup, ARRAY_SIZE(crag6410_pwm_lookup));
platform_add_devices(crag6410_devices, ARRAY_SIZE(crag6410_devices));
gpio_led_register_device(-1, &gpio_leds_pdata);
diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c
index e4b087c..816b39d 100644
--- a/arch/arm/mach-s3c64xx/mach-hmt.c
+++ b/arch/arm/mach-s3c64xx/mach-hmt.c
@@ -19,6 +19,7 @@
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/leds.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -73,6 +74,11 @@ static struct s3c2410_uartcfg hmt_uartcfgs[] __initdata = {
},
};
+static struct pwm_lookup hmt_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL,
+ 1000000000 / (100 * 256 * 20), PWM_POLARITY_NORMAL),
+};
+
static int hmt_bl_init(struct device *dev)
{
int ret;
@@ -110,10 +116,8 @@ static void hmt_bl_exit(struct device *dev)
}
static struct platform_pwm_backlight_data hmt_backlight_data = {
- .pwm_id = 1,
.max_brightness = 100 * 256,
.dft_brightness = 40 * 256,
- .pwm_period_ns = 1000000000 / (100 * 256 * 20),
.enable_gpio = -1,
.init = hmt_bl_init,
.notify = hmt_bl_notify,
@@ -268,6 +272,7 @@ static void __init hmt_machine_init(void)
gpio_request(S3C64XX_GPF(13), "usb power");
gpio_direction_output(S3C64XX_GPF(13), 1);
+ pwm_add_table(hmt_pwm_lookup, ARRAY_SIZE(hmt_pwm_lookup));
platform_add_devices(hmt_devices, ARRAY_SIZE(hmt_devices));
}
diff --git a/arch/arm/mach-s3c64xx/mach-smartq.c b/arch/arm/mach-s3c64xx/mach-smartq.c
index 719843d..acdfb5f 100644
--- a/arch/arm/mach-s3c64xx/mach-smartq.c
+++ b/arch/arm/mach-s3c64xx/mach-smartq.c
@@ -14,6 +14,7 @@
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/serial_core.h>
#include <linux/serial_s3c.h>
@@ -139,6 +140,11 @@ static struct platform_device smartq_usb_otg_vbus_dev = {
.dev.platform_data = &smartq_usb_otg_vbus_pdata,
};
+static struct pwm_lookup smartq_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL,
+ 1000000000 / (1000 * 20), PWM_POLARITY_NORMAL),
+};
+
static int smartq_bl_init(struct device *dev)
{
s3c_gpio_cfgpin(S3C64XX_GPF(15), S3C_GPIO_SFN(2));
@@ -147,10 +153,8 @@ static int smartq_bl_init(struct device *dev)
}
static struct platform_pwm_backlight_data smartq_backlight_data = {
- .pwm_id = 1,
.max_brightness = 1000,
.dft_brightness = 600,
- .pwm_period_ns = 1000000000 / (1000 * 20),
.enable_gpio = -1,
.init = smartq_bl_init,
};
@@ -396,5 +400,6 @@ void __init smartq_machine_init(void)
WARN_ON(smartq_usb_host_init());
WARN_ON(smartq_wifi_init());
+ pwm_add_table(smartq_pwm_lookup, ARRAY_SIZE(smartq_pwm_lookup));
platform_add_devices(smartq_devices, ARRAY_SIZE(smartq_devices));
}
diff --git a/arch/arm/mach-s3c64xx/mach-smdk6410.c b/arch/arm/mach-s3c64xx/mach-smdk6410.c
index 286c9bd..30fd278 100644
--- a/arch/arm/mach-s3c64xx/mach-smdk6410.c
+++ b/arch/arm/mach-s3c64xx/mach-smdk6410.c
@@ -30,6 +30,7 @@
#include <linux/smsc911x.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/platform_data/s3c-hsotg.h>
@@ -623,8 +624,12 @@ static struct samsung_bl_gpio_info smdk6410_bl_gpio_info = {
.func = S3C_GPIO_SFN(2),
};
+static struct pwm_lookup smdk6410_pwm_lookup[] = {
+ PWM_LOOKUP("samsung-pwm", 1, "pwm-backlight.0", NULL, 78770,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data smdk6410_bl_data = {
- .pwm_id = 1,
.enable_gpio = -1,
};
@@ -695,6 +700,7 @@ static void __init smdk6410_machine_init(void)
platform_add_devices(smdk6410_devices, ARRAY_SIZE(smdk6410_devices));
+ pwm_add_table(smdk6410_pwm_lookup, ARRAY_SIZE(smdk6410_pwm_lookup));
samsung_bl_set(&smdk6410_bl_gpio_info, &smdk6410_bl_data);
}
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 926e336..88734a5 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -98,76 +98,3 @@ config ARCH_SH73A0
comment "Renesas ARM SoCs System Configuration"
endif
-
-if ARCH_SHMOBILE_LEGACY
-
-comment "Renesas ARM SoCs System Type"
-
-config ARCH_R8A7778
- bool "R-Car M1A (R8A77781)"
- select ARCH_RCAR_GEN1
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_GIC
-
-config ARCH_R8A7779
- bool "R-Car H1 (R8A77790)"
- select ARCH_RCAR_GEN1
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_GIC
-
-comment "Renesas ARM SoCs Board Type"
-
-config MACH_BOCKW
- bool "BOCK-W platform"
- depends on ARCH_R8A7778
- select ARCH_REQUIRE_GPIOLIB
- select REGULATOR_FIXED_VOLTAGE if REGULATOR
- select SND_SOC_AK4554 if SND_SIMPLE_CARD
- select SND_SOC_AK4642 if SND_SIMPLE_CARD && I2C
- select USE_OF
-
-config MACH_BOCKW_REFERENCE
- bool "BOCK-W - Reference Device Tree Implementation"
- depends on ARCH_R8A7778
- select ARCH_REQUIRE_GPIOLIB
- select REGULATOR_FIXED_VOLTAGE if REGULATOR
- select USE_OF
- ---help---
- Use reference implementation of BockW board support
- which makes use of device tree at the expense
- of not supporting a number of devices.
-
- This is intended to aid developers
-
-comment "Renesas ARM SoCs System Configuration"
-
-config CPU_HAS_INTEVT
- bool
- default y
-
-config SH_CLK_CPG
- bool
-
-source "drivers/sh/Kconfig"
-
-endif
-
-if ARCH_SHMOBILE
-
-menu "Timer and clock configuration"
-
-config SHMOBILE_TIMER_HZ
- int "Kernel HZ (jiffies per second)"
- range 32 1024
- default "128"
- help
- Allows the configuration of the timer frequency. It is customary
- to have the timer interrupt run at 1000 Hz or 100 Hz, but in the
- case of low timer frequencies other values may be more suitable.
- Renesas ARM SoC systems using a 32768 Hz RCLK for clock events may
- want to select a HZ value such as 128 that can evenly divide RCLK.
- A HZ value that does not divide evenly may cause timer drift.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index 476de30..a65c80ac 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -3,7 +3,7 @@
#
# Common objects
-obj-y := timer.o console.o
+obj-y := timer.o
# CPU objects
obj-$(CONFIG_ARCH_SH73A0) += setup-sh73a0.o
@@ -18,12 +18,6 @@ obj-$(CONFIG_ARCH_R8A7794) += setup-r8a7794.o
obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += setup-r7s72100.o
-# Clock objects
-ifndef CONFIG_COMMON_CLK
-obj-y += clock.o
-obj-$(CONFIG_ARCH_R8A7778) += clock-r8a7778.o
-endif
-
# CPU reset vector handling objects
cpu-y := platsmp.o headsmp.o
@@ -49,11 +43,5 @@ obj-$(CONFIG_PM_RCAR) += pm-rcar.o
obj-$(CONFIG_PM_RMOBILE) += pm-rmobile.o
obj-$(CONFIG_ARCH_RCAR_GEN2) += pm-rcar-gen2.o
-# Board objects
-ifndef CONFIG_ARCH_SHMOBILE_MULTI
-obj-$(CONFIG_MACH_BOCKW) += board-bockw.o
-obj-$(CONFIG_MACH_BOCKW_REFERENCE) += board-bockw-reference.o
-endif
-
# Framework support
obj-$(CONFIG_SMP) += $(smp-y)
diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot
deleted file mode 100644
index a489fe9..0000000
--- a/arch/arm/mach-shmobile/Makefile.boot
+++ /dev/null
@@ -1,12 +0,0 @@
-# per-board load address for uImage
-loadaddr-y :=
-loadaddr-$(CONFIG_MACH_BOCKW) += 0x60008000
-loadaddr-$(CONFIG_MACH_BOCKW_REFERENCE) += 0x60008000
-
-__ZRELADDR := $(sort $(loadaddr-y))
- zreladdr-y += $(__ZRELADDR)
-
-# Unsupported legacy stuff
-#
-#params_phys-y (Instead: Pass atags pointer in r2)
-#initrd_phys-y (Instead: Use compiled-in initramfs)
diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c
deleted file mode 100644
index 4f78296..0000000
--- a/arch/arm/mach-shmobile/board-bockw-reference.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Bock-W board support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/of_platform.h>
-
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "r8a7778.h"
-
-/*
- * see board-bock.c for checking detail of dip-switch
- */
-
-#define FPGA 0x18200000
-#define IRQ0MR 0x30
-#define COMCTLR 0x101c
-
-#define PFC 0xfffc0000
-#define PUPR4 0x110
-static void __init bockw_init(void)
-{
- void __iomem *fpga;
- void __iomem *pfc;
-
-#ifndef CONFIG_COMMON_CLK
- r8a7778_clock_init();
-#endif
- r8a7778_init_irq_extpin_dt(1);
- r8a7778_add_dt_devices();
-
- fpga = ioremap_nocache(FPGA, SZ_1M);
- if (fpga) {
- /*
- * CAUTION
- *
- * IRQ0/1 is cascaded interrupt from FPGA.
- * it should be cared in the future
- * Now, it is assuming IRQ0 was used only from SMSC.
- */
- u16 val = ioread16(fpga + IRQ0MR);
- val &= ~(1 << 4); /* enable SMSC911x */
- iowrite16(val, fpga + IRQ0MR);
-
- iounmap(fpga);
- }
-
- pfc = ioremap_nocache(PFC, 0x200);
- if (pfc) {
- /*
- * FIXME
- *
- * SDHI CD/WP pin needs pull-up
- */
- iowrite32(ioread32(pfc + PUPR4) | (3 << 26), pfc + PUPR4);
- iounmap(pfc);
- }
-
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
-static const char *const bockw_boards_compat_dt[] __initconst = {
- "renesas,bockw-reference",
- NULL,
-};
-
-DT_MACHINE_START(BOCKW_DT, "bockw")
- .init_early = shmobile_init_delay,
- .init_irq = r8a7778_init_irq_dt,
- .init_machine = bockw_init,
- .init_late = shmobile_init_late,
- .dt_compat = bockw_boards_compat_dt,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c
deleted file mode 100644
index 25a0e72..0000000
--- a/arch/arm/mach-shmobile/board-bockw.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/*
- * Bock-W board support
- *
- * Copyright (C) 2013-2014 Renesas Solutions Corp.
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- * Copyright (C) 2013-2014 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mtd/partitions.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/platform_data/camera-rcar.h>
-#include <linux/platform_data/usb-rcar-phy.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/smsc911x.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
-#include <linux/usb/renesas_usbhs.h>
-
-#include <media/soc_camera.h>
-#include <asm/mach/arch.h>
-#include <sound/rcar_snd.h>
-#include <sound/simple_card.h>
-
-#include "common.h"
-#include "irqs.h"
-#include "r8a7778.h"
-
-#define FPGA 0x18200000
-#define IRQ0MR 0x30
-#define COMCTLR 0x101c
-static void __iomem *fpga;
-
-/*
- * CN9(Upper side) SCIF/RCAN selection
- *
- * 1,4 3,6
- * SW40 SCIF RCAN
- * SW41 SCIF RCAN
- */
-
-/*
- * MMC (CN26) pin
- *
- * SW6 (D2) 3 pin
- * SW7 (D5) ON
- * SW8 (D3) 3 pin
- * SW10 (D4) 1 pin
- * SW12 (CLK) 1 pin
- * SW13 (D6) 3 pin
- * SW14 (CMD) ON
- * SW15 (D6) 1 pin
- * SW16 (D0) ON
- * SW17 (D1) ON
- * SW18 (D7) 3 pin
- * SW19 (MMC) 1 pin
- */
-
-/*
- * SSI settings
- *
- * SW45: 1-4 side (SSI5 out, ROUT/LOUT CN19 Mid)
- * SW46: 1101 (SSI6 Recorde)
- * SW47: 1110 (SSI5 Playback)
- * SW48: 11 (Recorde power)
- * SW49: 1 (SSI slave mode)
- * SW50: 1111 (SSI7, SSI8)
- * SW51: 1111 (SSI3, SSI4)
- * SW54: 1pin (ak4554 FPGA control)
- * SW55: 1 (CLKB is 24.5760MHz)
- * SW60: 1pin (ak4554 FPGA control)
- * SW61: 3pin (use X11 clock)
- * SW78: 3-6 (ak4642 connects I2C0)
- *
- * You can use sound as
- *
- * hw0: CN19: SSI56-AK4643
- * hw1: CN21: SSI3-AK4554(playback)
- * hw2: CN21: SSI4-AK4554(capture)
- * hw3: CN20: SSI7-AK4554(playback)
- * hw4: CN20: SSI8-AK4554(capture)
- *
- * this command is required when playback on hw0.
- *
- * # amixer set "LINEOUT Mixer DACL" on
- */
-
-/*
- * USB
- *
- * USB1 (CN29) can be Host/Function
- *
- * Host Func
- * SW98 1 2
- * SW99 1 3
- */
-
-/* Dummy supplies, where voltage doesn't matter */
-static struct regulator_consumer_supply dummy_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x"),
-};
-
-static struct regulator_consumer_supply fixed3v3_power_consumers[] = {
- REGULATOR_SUPPLY("vmmc", "sh_mmcif"),
- REGULATOR_SUPPLY("vqmmc", "sh_mmcif"),
-};
-
-static struct smsc911x_platform_config smsc911x_data __initdata = {
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
- .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
- .flags = SMSC911X_USE_32BIT,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct resource smsc911x_resources[] __initdata = {
- DEFINE_RES_MEM(0x18300000, 0x1000),
- DEFINE_RES_IRQ(irq_pin(0)), /* IRQ 0 */
-};
-
-#if IS_ENABLED(CONFIG_USB_RENESAS_USBHS_UDC)
-/*
- * When USB1 is Func
- */
-static int usbhsf_get_id(struct platform_device *pdev)
-{
- return USBHS_GADGET;
-}
-
-#define SUSPMODE 0x102
-static int usbhsf_power_ctrl(struct platform_device *pdev,
- void __iomem *base, int enable)
-{
- enable = !!enable;
-
- r8a7778_usb_phy_power(enable);
-
- iowrite16(enable << 14, base + SUSPMODE);
-
- return 0;
-}
-
-static struct resource usbhsf_resources[] __initdata = {
- DEFINE_RES_MEM(0xffe60000, 0x110),
- DEFINE_RES_IRQ(gic_iid(0x4f)),
-};
-
-static struct renesas_usbhs_platform_info usbhs_info __initdata = {
- .platform_callback = {
- .get_id = usbhsf_get_id,
- .power_ctrl = usbhsf_power_ctrl,
- },
- .driver_param = {
- .buswait_bwait = 4,
- .d0_tx_id = HPBDMA_SLAVE_USBFUNC_TX,
- .d1_rx_id = HPBDMA_SLAVE_USBFUNC_RX,
- },
-};
-
-#define USB_PHY_SETTING {.port1_func = 1, .ovc_pin[1].active_high = 1,}
-#define USB1_DEVICE "renesas_usbhs"
-#define ADD_USB_FUNC_DEVICE_IF_POSSIBLE() \
- platform_device_register_resndata( \
- NULL, "renesas_usbhs", -1, \
- usbhsf_resources, \
- ARRAY_SIZE(usbhsf_resources), \
- &usbhs_info, sizeof(struct renesas_usbhs_platform_info))
-
-#else
-/*
- * When USB1 is Host
- */
-#define USB_PHY_SETTING { }
-#define USB1_DEVICE "ehci-platform"
-#define ADD_USB_FUNC_DEVICE_IF_POSSIBLE()
-
-#endif
-
-/* USB */
-static struct resource usb_phy_resources[] __initdata = {
- DEFINE_RES_MEM(0xffe70800, 0x100),
- DEFINE_RES_MEM(0xffe76000, 0x100),
-};
-
-static struct rcar_phy_platform_data usb_phy_platform_data __initdata =
- USB_PHY_SETTING;
-
-
-/* SDHI */
-static struct tmio_mmc_data sdhi0_info __initdata = {
- .chan_priv_tx = (void *)HPBDMA_SLAVE_SDHI0_TX,
- .chan_priv_rx = (void *)HPBDMA_SLAVE_SDHI0_RX,
- .capabilities = MMC_CAP_SD_HIGHSPEED,
- .ocr_mask = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
- .flags = TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static struct resource sdhi0_resources[] __initdata = {
- DEFINE_RES_MEM(0xFFE4C000, 0x100),
- DEFINE_RES_IRQ(gic_iid(0x77)),
-};
-
-/* Ether */
-static struct resource ether_resources[] __initdata = {
- DEFINE_RES_MEM(0xfde00000, 0x400),
- DEFINE_RES_IRQ(gic_iid(0x89)),
-};
-
-static struct sh_eth_plat_data ether_platform_data __initdata = {
- .phy = 0x01,
- .edmac_endian = EDMAC_LITTLE_ENDIAN,
- .phy_interface = PHY_INTERFACE_MODE_RMII,
- /*
- * Although the LINK signal is available on the board, it's connected to
- * the link/activity LED output of the PHY, thus the link disappears and
- * reappears after each packet. We'd be better off ignoring such signal
- * and getting the link state from the PHY indirectly.
- */
- .no_ether_link = 1,
-};
-
-static struct platform_device_info ether_info __initdata = {
- .name = "r8a777x-ether",
- .id = -1,
- .res = ether_resources,
- .num_res = ARRAY_SIZE(ether_resources),
- .data = &ether_platform_data,
- .size_data = sizeof(ether_platform_data),
- .dma_mask = DMA_BIT_MASK(32),
-};
-
-/* I2C */
-static struct i2c_board_info i2c0_devices[] = {
- {
- I2C_BOARD_INFO("rx8581", 0x51),
- }, {
- I2C_BOARD_INFO("ak4643", 0x12),
- }
-};
-
-/* HSPI*/
-static struct mtd_partition m25p80_spi_flash_partitions[] = {
- {
- .name = "data(spi)",
- .size = 0x0100000,
- .offset = 0,
- },
-};
-
-static struct flash_platform_data spi_flash_data = {
- .name = "m25p80",
- .type = "s25fl008k",
- .parts = m25p80_spi_flash_partitions,
- .nr_parts = ARRAY_SIZE(m25p80_spi_flash_partitions),
-};
-
-static struct spi_board_info spi_board_info[] __initdata = {
- {
- .modalias = "m25p80",
- .max_speed_hz = 104000000,
- .chip_select = 0,
- .bus_num = 0,
- .mode = SPI_MODE_0,
- .platform_data = &spi_flash_data,
- },
-};
-
-/* MMC */
-static struct resource mmc_resources[] __initdata = {
- DEFINE_RES_MEM(0xffe4e000, 0x100),
- DEFINE_RES_IRQ(gic_iid(0x5d)),
-};
-
-static struct sh_mmcif_plat_data sh_mmcif_plat __initdata = {
- .sup_pclk = 0,
- .caps = MMC_CAP_4_BIT_DATA |
- MMC_CAP_8_BIT_DATA |
- MMC_CAP_NEEDS_POLL,
-};
-
-/* In the default configuration both decoders reside on I2C bus 0 */
-#define BOCKW_CAMERA(idx) \
-static struct i2c_board_info camera##idx##_info = { \
- I2C_BOARD_INFO("ml86v7667", 0x41 + 2 * (idx)), \
-}; \
- \
-static struct soc_camera_link iclink##idx##_ml86v7667 __initdata = { \
- .bus_id = idx, \
- .i2c_adapter_id = 0, \
- .board_info = &camera##idx##_info, \
-}
-
-BOCKW_CAMERA(0);
-BOCKW_CAMERA(1);
-
-/* VIN */
-static struct rcar_vin_platform_data vin_platform_data __initdata = {
- .flags = RCAR_VIN_BT656,
-};
-
-#define R8A7778_VIN(idx) \
-static struct resource vin##idx##_resources[] __initdata = { \
- DEFINE_RES_MEM(0xffc50000 + 0x1000 * (idx), 0x1000), \
- DEFINE_RES_IRQ(gic_iid(0x5a)), \
-}; \
- \
-static struct platform_device_info vin##idx##_info __initdata = { \
- .name = "r8a7778-vin", \
- .id = idx, \
- .res = vin##idx##_resources, \
- .num_res = ARRAY_SIZE(vin##idx##_resources), \
- .dma_mask = DMA_BIT_MASK(32), \
- .data = &vin_platform_data, \
- .size_data = sizeof(vin_platform_data), \
-}
-R8A7778_VIN(0);
-R8A7778_VIN(1);
-
-/* Sound */
-static struct resource rsnd_resources[] __initdata = {
- [RSND_GEN1_SRU] = DEFINE_RES_MEM(0xffd90000, 0x1000),
- [RSND_GEN1_SSI] = DEFINE_RES_MEM(0xffd91000, 0x1240),
- [RSND_GEN1_ADG] = DEFINE_RES_MEM(0xfffe0000, 0x24),
-};
-
-static struct rsnd_ssi_platform_info rsnd_ssi[] = {
- RSND_SSI_UNUSED, /* SSI 0 */
- RSND_SSI_UNUSED, /* SSI 1 */
- RSND_SSI_UNUSED, /* SSI 2 */
- RSND_SSI(HPBDMA_SLAVE_HPBIF3_TX, gic_iid(0x85), 0),
- RSND_SSI(HPBDMA_SLAVE_HPBIF4_RX, gic_iid(0x85), RSND_SSI_CLK_PIN_SHARE),
- RSND_SSI(HPBDMA_SLAVE_HPBIF5_TX, gic_iid(0x86), 0),
- RSND_SSI(HPBDMA_SLAVE_HPBIF6_RX, gic_iid(0x86), 0),
- RSND_SSI(HPBDMA_SLAVE_HPBIF7_TX, gic_iid(0x86), 0),
- RSND_SSI(HPBDMA_SLAVE_HPBIF8_RX, gic_iid(0x86), RSND_SSI_CLK_PIN_SHARE),
-};
-
-static struct rsnd_src_platform_info rsnd_src[9] = {
- RSND_SRC_UNUSED, /* SRU 0 */
- RSND_SRC_UNUSED, /* SRU 1 */
- RSND_SRC_UNUSED, /* SRU 2 */
- RSND_SRC(0, 0),
- RSND_SRC(0, 0),
- RSND_SRC(0, 0),
- RSND_SRC(0, 0),
- RSND_SRC(0, 0),
- RSND_SRC(0, 0),
-};
-
-static struct rsnd_dai_platform_info rsnd_dai[] = {
- {
- .playback = { .ssi = &rsnd_ssi[5], .src = &rsnd_src[5] },
- .capture = { .ssi = &rsnd_ssi[6], .src = &rsnd_src[6] },
- }, {
- .playback = { .ssi = &rsnd_ssi[3], .src = &rsnd_src[3] },
- }, {
- .capture = { .ssi = &rsnd_ssi[4], .src = &rsnd_src[4] },
- }, {
- .playback = { .ssi = &rsnd_ssi[7], .src = &rsnd_src[7] },
- }, {
- .capture = { .ssi = &rsnd_ssi[8], .src = &rsnd_src[8] },
- },
-};
-
-enum {
- AK4554_34 = 0,
- AK4643_56,
- AK4554_78,
- SOUND_MAX,
-};
-
-static int rsnd_codec_power(int id, int enable)
-{
- static int sound_user[SOUND_MAX] = {0, 0, 0};
- int *usr = NULL;
- u32 bit;
-
- switch (id) {
- case 3:
- case 4:
- usr = sound_user + AK4554_34;
- bit = (1 << 10);
- break;
- case 5:
- case 6:
- usr = sound_user + AK4643_56;
- bit = (1 << 6);
- break;
- case 7:
- case 8:
- usr = sound_user + AK4554_78;
- bit = (1 << 7);
- break;
- }
-
- if (!usr)
- return -EIO;
-
- if (enable) {
- if (*usr == 0) {
- u32 val = ioread16(fpga + COMCTLR);
- val &= ~bit;
- iowrite16(val, fpga + COMCTLR);
- }
-
- (*usr)++;
- } else {
- if (*usr == 0)
- return 0;
-
- (*usr)--;
-
- if (*usr == 0) {
- u32 val = ioread16(fpga + COMCTLR);
- val |= bit;
- iowrite16(val, fpga + COMCTLR);
- }
- }
-
- return 0;
-}
-
-static int rsnd_start(int id)
-{
- return rsnd_codec_power(id, 1);
-}
-
-static int rsnd_stop(int id)
-{
- return rsnd_codec_power(id, 0);
-}
-
-static struct rcar_snd_info rsnd_info = {
- .flags = RSND_GEN1,
- .ssi_info = rsnd_ssi,
- .ssi_info_nr = ARRAY_SIZE(rsnd_ssi),
- .src_info = rsnd_src,
- .src_info_nr = ARRAY_SIZE(rsnd_src),
- .dai_info = rsnd_dai,
- .dai_info_nr = ARRAY_SIZE(rsnd_dai),
- .start = rsnd_start,
- .stop = rsnd_stop,
-};
-
-static struct asoc_simple_card_info rsnd_card_info[] = {
- /* SSI5, SSI6 */
- {
- .name = "AK4643",
- .card = "SSI56-AK4643",
- .codec = "ak4642-codec.0-0012",
- .platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_CBM_CFM,
- .cpu_dai = {
- .name = "rsnd-dai.0",
- },
- .codec_dai = {
- .name = "ak4642-hifi",
- .sysclk = 11289600,
- },
- },
- /* SSI3 */
- {
- .name = "AK4554",
- .card = "SSI3-AK4554(playback)",
- .codec = "ak4554-adc-dac.0",
- .platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
- .cpu_dai = {
- .name = "rsnd-dai.1",
- },
- .codec_dai = {
- .name = "ak4554-hifi",
- },
- },
- /* SSI4 */
- {
- .name = "AK4554",
- .card = "SSI4-AK4554(capture)",
- .codec = "ak4554-adc-dac.0",
- .platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
- .cpu_dai = {
- .name = "rsnd-dai.2",
- },
- .codec_dai = {
- .name = "ak4554-hifi",
- },
- },
- /* SSI7 */
- {
- .name = "AK4554",
- .card = "SSI7-AK4554(playback)",
- .codec = "ak4554-adc-dac.1",
- .platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_RIGHT_J,
- .cpu_dai = {
- .name = "rsnd-dai.3",
- },
- .codec_dai = {
- .name = "ak4554-hifi",
- },
- },
- /* SSI8 */
- {
- .name = "AK4554",
- .card = "SSI8-AK4554(capture)",
- .codec = "ak4554-adc-dac.1",
- .platform = "rcar_sound",
- .daifmt = SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_LEFT_J,
- .cpu_dai = {
- .name = "rsnd-dai.4",
- },
- .codec_dai = {
- .name = "ak4554-hifi",
- },
- }
-};
-
-static const struct pinctrl_map bockw_pinctrl_map[] = {
- /* AUDIO */
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "audio_clk_a", "audio_clk"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "audio_clk_b", "audio_clk"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi34_ctrl", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi3_data", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi4_data", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi5_ctrl", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi5_data", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi6_ctrl", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi6_data", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi78_ctrl", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi7_data", "ssi"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar_sound", "pfc-r8a7778",
- "ssi8_data", "ssi"),
- /* Ether */
- PIN_MAP_MUX_GROUP_DEFAULT("r8a777x-ether", "pfc-r8a7778",
- "ether_rmii", "ether"),
- /* HSPI0 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh-hspi.0", "pfc-r8a7778",
- "hspi0_a", "hspi0"),
- /* MMC */
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif", "pfc-r8a7778",
- "mmc_data8", "mmc"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mmcif", "pfc-r8a7778",
- "mmc_ctrl", "mmc"),
- /* SCIF0 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
- "scif0_data_a", "scif0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.0", "pfc-r8a7778",
- "scif0_ctrl", "scif0"),
- /* USB */
- PIN_MAP_MUX_GROUP_DEFAULT("ehci-platform", "pfc-r8a7778",
- "usb0", "usb0"),
- PIN_MAP_MUX_GROUP_DEFAULT(USB1_DEVICE, "pfc-r8a7778",
- "usb1", "usb1"),
- /* SDHI0 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
- "sdhi0_data4", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
- "sdhi0_ctrl", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
- "sdhi0_cd", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7778",
- "sdhi0_wp", "sdhi0"),
- /* VIN0 */
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7778-vin.0", "pfc-r8a7778",
- "vin0_clk", "vin0"),
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7778-vin.0", "pfc-r8a7778",
- "vin0_data8", "vin0"),
- /* VIN1 */
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7778-vin.1", "pfc-r8a7778",
- "vin1_clk", "vin1"),
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7778-vin.1", "pfc-r8a7778",
- "vin1_data8", "vin1"),
-};
-
-#define PFC 0xfffc0000
-#define PUPR4 0x110
-static void __init bockw_init(void)
-{
- void __iomem *base;
- struct clk *clk;
- struct platform_device *pdev;
- int i;
-
- r8a7778_clock_init();
- r8a7778_init_irq_extpin(1);
- r8a7778_add_standard_devices();
-
- platform_device_register_full(&ether_info);
-
- platform_device_register_full(&vin0_info);
- /* VIN1 has a pin conflict with Ether */
- if (!IS_ENABLED(CONFIG_SH_ETH))
- platform_device_register_full(&vin1_info);
- platform_device_register_data(NULL, "soc-camera-pdrv", 0,
- &iclink0_ml86v7667,
- sizeof(iclink0_ml86v7667));
- platform_device_register_data(NULL, "soc-camera-pdrv", 1,
- &iclink1_ml86v7667,
- sizeof(iclink1_ml86v7667));
-
- i2c_register_board_info(0, i2c0_devices,
- ARRAY_SIZE(i2c0_devices));
- spi_register_board_info(spi_board_info,
- ARRAY_SIZE(spi_board_info));
- pinctrl_register_mappings(bockw_pinctrl_map,
- ARRAY_SIZE(bockw_pinctrl_map));
- r8a7778_pinmux_init();
-
- platform_device_register_resndata(
- NULL, "sh_mmcif", -1,
- mmc_resources, ARRAY_SIZE(mmc_resources),
- &sh_mmcif_plat, sizeof(struct sh_mmcif_plat_data));
-
- platform_device_register_resndata(
- NULL, "rcar_usb_phy", -1,
- usb_phy_resources,
- ARRAY_SIZE(usb_phy_resources),
- &usb_phy_platform_data,
- sizeof(struct rcar_phy_platform_data));
-
- regulator_register_fixed(0, dummy_supplies,
- ARRAY_SIZE(dummy_supplies));
- regulator_register_always_on(1, "fixed-3.3V", fixed3v3_power_consumers,
- ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
-
- /* for SMSC */
- fpga = ioremap_nocache(FPGA, SZ_1M);
- if (fpga) {
- /*
- * CAUTION
- *
- * IRQ0/1 is cascaded interrupt from FPGA.
- * it should be cared in the future
- * Now, it is assuming IRQ0 was used only from SMSC.
- */
- u16 val = ioread16(fpga + IRQ0MR);
- val &= ~(1 << 4); /* enable SMSC911x */
- iowrite16(val, fpga + IRQ0MR);
-
- platform_device_register_resndata(
- NULL, "smsc911x", -1,
- smsc911x_resources, ARRAY_SIZE(smsc911x_resources),
- &smsc911x_data, sizeof(smsc911x_data));
- }
-
- /* for SDHI */
- base = ioremap_nocache(PFC, 0x200);
- if (base) {
- /*
- * FIXME
- *
- * SDHI CD/WP pin needs pull-up
- */
- iowrite32(ioread32(base + PUPR4) | (3 << 26), base + PUPR4);
- iounmap(base);
-
- platform_device_register_resndata(
- NULL, "sh_mobile_sdhi", 0,
- sdhi0_resources, ARRAY_SIZE(sdhi0_resources),
- &sdhi0_info, sizeof(struct tmio_mmc_data));
- }
-
- /* for Audio */
- rsnd_codec_power(5, 1); /* enable ak4642 */
-
- platform_device_register_simple(
- "ak4554-adc-dac", 0, NULL, 0);
-
- platform_device_register_simple(
- "ak4554-adc-dac", 1, NULL, 0);
-
- pdev = platform_device_register_resndata(
- NULL, "rcar_sound", -1,
- rsnd_resources, ARRAY_SIZE(rsnd_resources),
- &rsnd_info, sizeof(rsnd_info));
-
- clk = clk_get(&pdev->dev, "clk_b");
- clk_set_rate(clk, 24576000);
- clk_put(clk);
-
- for (i = 0; i < ARRAY_SIZE(rsnd_card_info); i++) {
- struct platform_device_info cardinfo = {
- .name = "asoc-simple-card",
- .id = i,
- .data = &rsnd_card_info[i],
- .size_data = sizeof(struct asoc_simple_card_info),
- .dma_mask = DMA_BIT_MASK(32),
- };
-
- platform_device_register_full(&cardinfo);
- }
-}
-
-static void __init bockw_init_late(void)
-{
- r8a7778_init_late();
- ADD_USB_FUNC_DEVICE_IF_POSSIBLE();
-}
-
-static const char *const bockw_boards_compat_dt[] __initconst = {
- "renesas,bockw",
- NULL,
-};
-
-DT_MACHINE_START(BOCKW_DT, "bockw")
- .init_early = shmobile_init_delay,
- .init_irq = r8a7778_init_irq_dt,
- .init_machine = bockw_init,
- .dt_compat = bockw_boards_compat_dt,
- .init_late = bockw_init_late,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c
deleted file mode 100644
index e8510c3..0000000
--- a/arch/arm/mach-shmobile/clock-r8a7778.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * r8a7778 clock framework support
- *
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- *
- * based on r8a7779
- *
- * Copyright (C) 2011 Renesas Solutions Corp.
- * Copyright (C) 2011 Magnus Damm
- *
- * 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
- *
- * 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.
- */
-
-/*
- * MD MD MD MD PLLA PLLB EXTAL clki clkz
- * 19 18 12 11 (HMz) (MHz) (MHz)
- *----------------------------------------------------------------------------
- * 1 0 0 0 x21 x21 38.00 800 800
- * 1 0 0 1 x24 x24 33.33 800 800
- * 1 0 1 0 x28 x28 28.50 800 800
- * 1 0 1 1 x32 x32 25.00 800 800
- * 1 1 0 1 x24 x21 33.33 800 700
- * 1 1 1 0 x28 x21 28.50 800 600
- * 1 1 1 1 x32 x24 25.00 800 600
- */
-
-#include <linux/io.h>
-#include <linux/sh_clk.h>
-#include <linux/clkdev.h>
-#include "clock.h"
-#include "common.h"
-
-#define MSTPCR0 IOMEM(0xffc80030)
-#define MSTPCR1 IOMEM(0xffc80034)
-#define MSTPCR3 IOMEM(0xffc8003c)
-#define MSTPSR1 IOMEM(0xffc80044)
-#define MSTPSR4 IOMEM(0xffc80048)
-#define MSTPSR6 IOMEM(0xffc8004c)
-#define MSTPCR4 IOMEM(0xffc80050)
-#define MSTPCR5 IOMEM(0xffc80054)
-#define MSTPCR6 IOMEM(0xffc80058)
-#define MODEMR 0xFFCC0020
-
-#define MD(nr) BIT(nr)
-
-/* ioremap() through clock mapping mandatory to avoid
- * collision with ARM coherent DMA virtual memory range.
- */
-
-static struct clk_mapping cpg_mapping = {
- .phys = 0xffc80000,
- .len = 0x80,
-};
-
-static struct clk extal_clk = {
- /* .rate will be updated on r8a7778_clock_init() */
- .mapping = &cpg_mapping,
-};
-
-static struct clk audio_clk_a = {
-};
-
-static struct clk audio_clk_b = {
-};
-
-static struct clk audio_clk_c = {
-};
-
-/*
- * clock ratio of these clock will be updated
- * on r8a7778_clock_init()
- */
-SH_FIXED_RATIO_CLK_SET(plla_clk, extal_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(pllb_clk, extal_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(i_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(s_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(s1_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(s3_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(s4_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(b_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(out_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(p_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(g_clk, plla_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(z_clk, pllb_clk, 1, 1);
-
-static struct clk *main_clks[] = {
- &extal_clk,
- &plla_clk,
- &pllb_clk,
- &i_clk,
- &s_clk,
- &s1_clk,
- &s3_clk,
- &s4_clk,
- &b_clk,
- &out_clk,
- &p_clk,
- &g_clk,
- &z_clk,
- &audio_clk_a,
- &audio_clk_b,
- &audio_clk_c,
-};
-
-enum {
- MSTP531, MSTP530,
- MSTP529, MSTP528, MSTP527, MSTP526, MSTP525, MSTP524, MSTP523,
- MSTP331,
- MSTP323, MSTP322, MSTP321,
- MSTP311, MSTP310,
- MSTP309, MSTP308, MSTP307,
- MSTP114,
- MSTP110, MSTP109,
- MSTP100,
- MSTP030,
- MSTP029, MSTP028, MSTP027, MSTP026, MSTP025, MSTP024, MSTP023, MSTP022, MSTP021,
- MSTP016, MSTP015, MSTP012, MSTP011, MSTP010,
- MSTP009, MSTP008, MSTP007,
- MSTP_NR };
-
-static struct clk mstp_clks[MSTP_NR] = {
- [MSTP531] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 31, 0), /* SCU0 */
- [MSTP530] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 30, 0), /* SCU1 */
- [MSTP529] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 29, 0), /* SCU2 */
- [MSTP528] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 28, 0), /* SCU3 */
- [MSTP527] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 27, 0), /* SCU4 */
- [MSTP526] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 26, 0), /* SCU5 */
- [MSTP525] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 25, 0), /* SCU6 */
- [MSTP524] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 24, 0), /* SCU7 */
- [MSTP523] = SH_CLK_MSTP32(&p_clk, MSTPCR5, 23, 0), /* SCU8 */
- [MSTP331] = SH_CLK_MSTP32(&s4_clk, MSTPCR3, 31, 0), /* MMC */
- [MSTP323] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 23, 0), /* SDHI0 */
- [MSTP322] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 22, 0), /* SDHI1 */
- [MSTP321] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 21, 0), /* SDHI2 */
- [MSTP311] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 11, 0), /* SSI4 */
- [MSTP310] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 10, 0), /* SSI5 */
- [MSTP309] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 9, 0), /* SSI6 */
- [MSTP308] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 8, 0), /* SSI7 */
- [MSTP307] = SH_CLK_MSTP32(&p_clk, MSTPCR3, 7, 0), /* SSI8 */
- [MSTP114] = SH_CLK_MSTP32(&p_clk, MSTPCR1, 14, 0), /* Ether */
- [MSTP110] = SH_CLK_MSTP32(&s_clk, MSTPCR1, 10, 0), /* VIN0 */
- [MSTP109] = SH_CLK_MSTP32(&s_clk, MSTPCR1, 9, 0), /* VIN1 */
- [MSTP100] = SH_CLK_MSTP32(&p_clk, MSTPCR1, 0, 0), /* USB0/1 */
- [MSTP030] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 30, 0), /* I2C0 */
- [MSTP029] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 29, 0), /* I2C1 */
- [MSTP028] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 28, 0), /* I2C2 */
- [MSTP027] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 27, 0), /* I2C3 */
- [MSTP026] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 26, 0), /* SCIF0 */
- [MSTP025] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 25, 0), /* SCIF1 */
- [MSTP024] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 24, 0), /* SCIF2 */
- [MSTP023] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 23, 0), /* SCIF3 */
- [MSTP022] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 22, 0), /* SCIF4 */
- [MSTP021] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 21, 0), /* SCIF5 */
- [MSTP016] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 16, 0), /* TMU0 */
- [MSTP015] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 15, 0), /* TMU1 */
- [MSTP012] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 12, 0), /* SSI0 */
- [MSTP011] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 11, 0), /* SSI1 */
- [MSTP010] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 10, 0), /* SSI2 */
- [MSTP009] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 9, 0), /* SSI3 */
- [MSTP008] = SH_CLK_MSTP32(&p_clk, MSTPCR0, 8, 0), /* SRU */
- [MSTP007] = SH_CLK_MSTP32(&s_clk, MSTPCR0, 7, 0), /* HSPI */
-};
-
-static struct clk_lookup lookups[] = {
- /* main */
- CLKDEV_CON_ID("shyway_clk", &s_clk),
- CLKDEV_CON_ID("peripheral_clk", &p_clk),
-
- /* MSTP32 clocks */
- CLKDEV_DEV_ID("sh_mmcif", &mstp_clks[MSTP331]), /* MMC */
- CLKDEV_DEV_ID("ffe4e000.mmc", &mstp_clks[MSTP331]), /* MMC */
- CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP323]), /* SDHI0 */
- CLKDEV_DEV_ID("ffe4c000.sd", &mstp_clks[MSTP323]), /* SDHI0 */
- CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP322]), /* SDHI1 */
- CLKDEV_DEV_ID("ffe4d000.sd", &mstp_clks[MSTP322]), /* SDHI1 */
- CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP321]), /* SDHI2 */
- CLKDEV_DEV_ID("ffe4f000.sd", &mstp_clks[MSTP321]), /* SDHI2 */
- CLKDEV_DEV_ID("r8a777x-ether", &mstp_clks[MSTP114]), /* Ether */
- CLKDEV_DEV_ID("r8a7778-vin.0", &mstp_clks[MSTP110]), /* VIN0 */
- CLKDEV_DEV_ID("r8a7778-vin.1", &mstp_clks[MSTP109]), /* VIN1 */
- CLKDEV_DEV_ID("ehci-platform", &mstp_clks[MSTP100]), /* USB EHCI port0/1 */
- CLKDEV_DEV_ID("ohci-platform", &mstp_clks[MSTP100]), /* USB OHCI port0/1 */
- CLKDEV_DEV_ID("renesas_usbhs", &mstp_clks[MSTP100]), /* USB FUNC */
- CLKDEV_DEV_ID("i2c-rcar.0", &mstp_clks[MSTP030]), /* I2C0 */
- CLKDEV_DEV_ID("ffc70000.i2c", &mstp_clks[MSTP030]), /* I2C0 */
- CLKDEV_DEV_ID("i2c-rcar.1", &mstp_clks[MSTP029]), /* I2C1 */
- CLKDEV_DEV_ID("ffc71000.i2c", &mstp_clks[MSTP029]), /* I2C1 */
- CLKDEV_DEV_ID("i2c-rcar.2", &mstp_clks[MSTP028]), /* I2C2 */
- CLKDEV_DEV_ID("ffc72000.i2c", &mstp_clks[MSTP028]), /* I2C2 */
- CLKDEV_DEV_ID("i2c-rcar.3", &mstp_clks[MSTP027]), /* I2C3 */
- CLKDEV_DEV_ID("ffc73000.i2c", &mstp_clks[MSTP027]), /* I2C3 */
- CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP026]), /* SCIF0 */
- CLKDEV_DEV_ID("ffe40000.serial", &mstp_clks[MSTP026]), /* SCIF0 */
- CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP025]), /* SCIF1 */
- CLKDEV_DEV_ID("ffe41000.serial", &mstp_clks[MSTP025]), /* SCIF1 */
- CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP024]), /* SCIF2 */
- CLKDEV_DEV_ID("ffe42000.serial", &mstp_clks[MSTP024]), /* SCIF2 */
- CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP023]), /* SCIF3 */
- CLKDEV_DEV_ID("ffe43000.serial", &mstp_clks[MSTP023]), /* SCIF3 */
- CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP022]), /* SCIF4 */
- CLKDEV_DEV_ID("ffe44000.serial", &mstp_clks[MSTP022]), /* SCIF4 */
- CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP021]), /* SCIF6 */
- CLKDEV_DEV_ID("ffe45000.serial", &mstp_clks[MSTP021]), /* SCIF5 */
- CLKDEV_DEV_ID("sh-hspi.0", &mstp_clks[MSTP007]), /* HSPI0 */
- CLKDEV_DEV_ID("fffc7000.spi", &mstp_clks[MSTP007]), /* HSPI0 */
- CLKDEV_DEV_ID("sh-hspi.1", &mstp_clks[MSTP007]), /* HSPI1 */
- CLKDEV_DEV_ID("fffc8000.spi", &mstp_clks[MSTP007]), /* HSPI1 */
- CLKDEV_DEV_ID("sh-hspi.2", &mstp_clks[MSTP007]), /* HSPI2 */
- CLKDEV_DEV_ID("fffc6000.spi", &mstp_clks[MSTP007]), /* HSPI2 */
- CLKDEV_DEV_ID("rcar_sound", &mstp_clks[MSTP008]), /* SRU */
-
- CLKDEV_ICK_ID("clk_a", "rcar_sound", &audio_clk_a),
- CLKDEV_ICK_ID("clk_b", "rcar_sound", &audio_clk_b),
- CLKDEV_ICK_ID("clk_c", "rcar_sound", &audio_clk_c),
- CLKDEV_ICK_ID("clk_i", "rcar_sound", &s1_clk),
- CLKDEV_ICK_ID("ssi.0", "rcar_sound", &mstp_clks[MSTP012]),
- CLKDEV_ICK_ID("ssi.1", "rcar_sound", &mstp_clks[MSTP011]),
- CLKDEV_ICK_ID("ssi.2", "rcar_sound", &mstp_clks[MSTP010]),
- CLKDEV_ICK_ID("ssi.3", "rcar_sound", &mstp_clks[MSTP009]),
- CLKDEV_ICK_ID("ssi.4", "rcar_sound", &mstp_clks[MSTP311]),
- CLKDEV_ICK_ID("ssi.5", "rcar_sound", &mstp_clks[MSTP310]),
- CLKDEV_ICK_ID("ssi.6", "rcar_sound", &mstp_clks[MSTP309]),
- CLKDEV_ICK_ID("ssi.7", "rcar_sound", &mstp_clks[MSTP308]),
- CLKDEV_ICK_ID("ssi.8", "rcar_sound", &mstp_clks[MSTP307]),
- CLKDEV_ICK_ID("src.0", "rcar_sound", &mstp_clks[MSTP531]),
- CLKDEV_ICK_ID("src.1", "rcar_sound", &mstp_clks[MSTP530]),
- CLKDEV_ICK_ID("src.2", "rcar_sound", &mstp_clks[MSTP529]),
- CLKDEV_ICK_ID("src.3", "rcar_sound", &mstp_clks[MSTP528]),
- CLKDEV_ICK_ID("src.4", "rcar_sound", &mstp_clks[MSTP527]),
- CLKDEV_ICK_ID("src.5", "rcar_sound", &mstp_clks[MSTP526]),
- CLKDEV_ICK_ID("src.6", "rcar_sound", &mstp_clks[MSTP525]),
- CLKDEV_ICK_ID("src.7", "rcar_sound", &mstp_clks[MSTP524]),
- CLKDEV_ICK_ID("src.8", "rcar_sound", &mstp_clks[MSTP523]),
- CLKDEV_ICK_ID("fck", "sh-tmu.0", &mstp_clks[MSTP016]),
- CLKDEV_ICK_ID("fck", "ffd80000.timer", &mstp_clks[MSTP016]),
- CLKDEV_ICK_ID("fck", "sh-tmu.1", &mstp_clks[MSTP015]),
- CLKDEV_ICK_ID("fck", "ffd81000.timer", &mstp_clks[MSTP015]),
-};
-
-void __init r8a7778_clock_init(void)
-{
- void __iomem *modemr = ioremap_nocache(MODEMR, PAGE_SIZE);
- u32 mode;
- int k, ret = 0;
-
- BUG_ON(!modemr);
- mode = ioread32(modemr);
- iounmap(modemr);
-
- switch (mode & (MD(19) | MD(18) | MD(12) | MD(11))) {
- case MD(19):
- extal_clk.rate = 38000000;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 21, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 21, 1);
- break;
- case MD(19) | MD(11):
- extal_clk.rate = 33333333;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 24, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 24, 1);
- break;
- case MD(19) | MD(12):
- extal_clk.rate = 28500000;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 28, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 28, 1);
- break;
- case MD(19) | MD(12) | MD(11):
- extal_clk.rate = 25000000;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 32, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 32, 1);
- break;
- case MD(19) | MD(18) | MD(11):
- extal_clk.rate = 33333333;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 24, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 21, 1);
- break;
- case MD(19) | MD(18) | MD(12):
- extal_clk.rate = 28500000;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 28, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 21, 1);
- break;
- case MD(19) | MD(18) | MD(12) | MD(11):
- extal_clk.rate = 25000000;
- SH_CLK_SET_RATIO(&plla_clk_ratio, 32, 1);
- SH_CLK_SET_RATIO(&pllb_clk_ratio, 24, 1);
- break;
- default:
- BUG();
- }
-
- if (mode & MD(1)) {
- SH_CLK_SET_RATIO(&i_clk_ratio, 1, 1);
- SH_CLK_SET_RATIO(&s_clk_ratio, 1, 3);
- SH_CLK_SET_RATIO(&s1_clk_ratio, 1, 6);
- SH_CLK_SET_RATIO(&s3_clk_ratio, 1, 4);
- SH_CLK_SET_RATIO(&s4_clk_ratio, 1, 8);
- SH_CLK_SET_RATIO(&p_clk_ratio, 1, 12);
- SH_CLK_SET_RATIO(&g_clk_ratio, 1, 12);
- if (mode & MD(2)) {
- SH_CLK_SET_RATIO(&b_clk_ratio, 1, 18);
- SH_CLK_SET_RATIO(&out_clk_ratio, 1, 18);
- } else {
- SH_CLK_SET_RATIO(&b_clk_ratio, 1, 12);
- SH_CLK_SET_RATIO(&out_clk_ratio, 1, 12);
- }
- } else {
- SH_CLK_SET_RATIO(&i_clk_ratio, 1, 1);
- SH_CLK_SET_RATIO(&s_clk_ratio, 1, 4);
- SH_CLK_SET_RATIO(&s1_clk_ratio, 1, 8);
- SH_CLK_SET_RATIO(&s3_clk_ratio, 1, 4);
- SH_CLK_SET_RATIO(&s4_clk_ratio, 1, 8);
- SH_CLK_SET_RATIO(&p_clk_ratio, 1, 16);
- SH_CLK_SET_RATIO(&g_clk_ratio, 1, 12);
- if (mode & MD(2)) {
- SH_CLK_SET_RATIO(&b_clk_ratio, 1, 16);
- SH_CLK_SET_RATIO(&out_clk_ratio, 1, 16);
- } else {
- SH_CLK_SET_RATIO(&b_clk_ratio, 1, 12);
- SH_CLK_SET_RATIO(&out_clk_ratio, 1, 12);
- }
- }
-
- for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
- ret = clk_register(main_clks[k]);
-
- if (!ret)
- ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
-
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- if (!ret)
- shmobile_clk_init();
- else
- panic("failed to setup r8a7778 clocks\n");
-}
diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c
deleted file mode 100644
index 68c2d06..0000000
--- a/arch/arm/mach-shmobile/clock.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * SH-Mobile Clock Framework
- *
- * Copyright (C) 2010 Magnus Damm
- *
- * Used together with arch/arm/common/clkdev.c and drivers/sh/clk.c.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/export.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sh_clk.h>
-
-#include "clock.h"
-#include "common.h"
-
-unsigned long shmobile_fixed_ratio_clk_recalc(struct clk *clk)
-{
- struct clk_ratio *p = clk->priv;
-
- return clk->parent->rate / p->div * p->mul;
-};
-
-struct sh_clk_ops shmobile_fixed_ratio_clk_ops = {
- .recalc = shmobile_fixed_ratio_clk_recalc,
-};
-
-int __init shmobile_clk_init(void)
-{
- /* Kick the child clocks.. */
- recalculate_root_clocks();
-
- /* Enable the necessary init clocks */
- clk_enable_init_clocks();
-
- return 0;
-}
diff --git a/arch/arm/mach-shmobile/clock.h b/arch/arm/mach-shmobile/clock.h
deleted file mode 100644
index cf3552e..0000000
--- a/arch/arm/mach-shmobile/clock.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef CLOCK_H
-#define CLOCK_H
-
-/* legacy clock implementation */
-
-struct clk;
-unsigned long shmobile_fixed_ratio_clk_recalc(struct clk *clk);
-extern struct sh_clk_ops shmobile_fixed_ratio_clk_ops;
-
-/* clock ratio */
-struct clk_ratio {
- int mul;
- int div;
-};
-
-#define SH_CLK_RATIO(name, m, d) \
-static struct clk_ratio name ##_ratio = { \
- .mul = m, \
- .div = d, \
-}
-
-#define SH_FIXED_RATIO_CLKg(name, p, r) \
-struct clk name = { \
- .parent = &p, \
- .ops = &shmobile_fixed_ratio_clk_ops,\
- .priv = &r ## _ratio, \
-}
-
-#define SH_FIXED_RATIO_CLK(name, p, r) \
-static SH_FIXED_RATIO_CLKg(name, p, r)
-
-#define SH_FIXED_RATIO_CLK_SET(name, p, m, d) \
- SH_CLK_RATIO(name, m, d); \
- SH_FIXED_RATIO_CLK(name, p, name)
-
-#define SH_CLK_SET_RATIO(p, m, d) \
-do { \
- (p)->mul = m; \
- (p)->div = d; \
-} while (0)
-
-#endif
diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h
index 8d27ec5..9cb1121 100644
--- a/arch/arm/mach-shmobile/common.h
+++ b/arch/arm/mach-shmobile/common.h
@@ -1,10 +1,7 @@
#ifndef __ARCH_MACH_COMMON_H
#define __ARCH_MACH_COMMON_H
-extern void shmobile_earlytimer_init(void);
extern void shmobile_init_delay(void);
-struct twd_local_timer;
-extern void shmobile_setup_console(void);
extern void shmobile_boot_vector(void);
extern unsigned long shmobile_boot_fn;
extern unsigned long shmobile_boot_arg;
@@ -18,8 +15,6 @@ extern void shmobile_boot_scu(void);
extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus);
extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
extern int shmobile_smp_scu_cpu_kill(unsigned int cpu);
-struct clk;
-extern int shmobile_clk_init(void);
extern struct platform_suspend_ops shmobile_suspend_ops;
#ifdef CONFIG_SUSPEND
diff --git a/arch/arm/mach-shmobile/console.c b/arch/arm/mach-shmobile/console.c
deleted file mode 100644
index e329ccb..0000000
--- a/arch/arm/mach-shmobile/console.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * SH-Mobile Console
- *
- * Copyright (C) 2010 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <asm/mach/map.h>
-#include "common.h"
-
-void __init shmobile_setup_console(void)
-{
- parse_early_param();
-
- /* Let earlyprintk output early console messages */
- early_platform_driver_probe("earlyprintk", 1, 1);
-}
diff --git a/arch/arm/mach-shmobile/intc.h b/arch/arm/mach-shmobile/intc.h
deleted file mode 100644
index 40b2ad4..0000000
--- a/arch/arm/mach-shmobile/intc.h
+++ /dev/null
@@ -1,295 +0,0 @@
-#ifndef __ASM_MACH_INTC_H
-#define __ASM_MACH_INTC_H
-#include <linux/sh_intc.h>
-
-#define INTC_IRQ_PINS_ENUM_16L(p) \
- p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \
- p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7, \
- p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \
- p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15
-
-#define INTC_IRQ_PINS_ENUM_16H(p) \
- p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \
- p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23, \
- p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \
- p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31
-
-#define INTC_IRQ_PINS_VECT_16L(p, vect) \
- vect(p ## _IRQ0, 0x0200), vect(p ## _IRQ1, 0x0220), \
- vect(p ## _IRQ2, 0x0240), vect(p ## _IRQ3, 0x0260), \
- vect(p ## _IRQ4, 0x0280), vect(p ## _IRQ5, 0x02a0), \
- vect(p ## _IRQ6, 0x02c0), vect(p ## _IRQ7, 0x02e0), \
- vect(p ## _IRQ8, 0x0300), vect(p ## _IRQ9, 0x0320), \
- vect(p ## _IRQ10, 0x0340), vect(p ## _IRQ11, 0x0360), \
- vect(p ## _IRQ12, 0x0380), vect(p ## _IRQ13, 0x03a0), \
- vect(p ## _IRQ14, 0x03c0), vect(p ## _IRQ15, 0x03e0)
-
-#define INTC_IRQ_PINS_VECT_16H(p, vect) \
- vect(p ## _IRQ16, 0x3200), vect(p ## _IRQ17, 0x3220), \
- vect(p ## _IRQ18, 0x3240), vect(p ## _IRQ19, 0x3260), \
- vect(p ## _IRQ20, 0x3280), vect(p ## _IRQ21, 0x32a0), \
- vect(p ## _IRQ22, 0x32c0), vect(p ## _IRQ23, 0x32e0), \
- vect(p ## _IRQ24, 0x3300), vect(p ## _IRQ25, 0x3320), \
- vect(p ## _IRQ26, 0x3340), vect(p ## _IRQ27, 0x3360), \
- vect(p ## _IRQ28, 0x3380), vect(p ## _IRQ29, 0x33a0), \
- vect(p ## _IRQ30, 0x33c0), vect(p ## _IRQ31, 0x33e0)
-
-#define INTC_IRQ_PINS_MASK_16L(p, base) \
- { base + 0x40, base + 0x60, 8, /* INTMSK00A / INTMSKCLR00A */ \
- { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \
- p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \
- { base + 0x44, base + 0x64, 8, /* INTMSK10A / INTMSKCLR10A */ \
- { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \
- p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } }
-
-#define INTC_IRQ_PINS_MASK_16H(p, base) \
- { base + 0x48, base + 0x68, 8, /* INTMSK20A / INTMSKCLR20A */ \
- { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \
- p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \
- { base + 0x4c, base + 0x6c, 8, /* INTMSK30A / INTMSKCLR30A */ \
- { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \
- p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } }
-
-#define INTC_IRQ_PINS_PRIO_16L(p, base) \
- { base + 0x10, 0, 32, 4, /* INTPRI00A */ \
- { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \
- p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \
- { base + 0x14, 0, 32, 4, /* INTPRI10A */ \
- { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \
- p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } }
-
-#define INTC_IRQ_PINS_PRIO_16H(p, base) \
- { base + 0x18, 0, 32, 4, /* INTPRI20A */ \
- { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \
- p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \
- { base + 0x1c, 0, 32, 4, /* INTPRI30A */ \
- { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \
- p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } }
-
-#define INTC_IRQ_PINS_SENSE_16L(p, base) \
- { base + 0x00, 32, 4, /* ICR1A */ \
- { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \
- p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \
- { base + 0x04, 32, 4, /* ICR2A */ \
- { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \
- p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } }
-
-#define INTC_IRQ_PINS_SENSE_16H(p, base) \
- { base + 0x08, 32, 4, /* ICR3A */ \
- { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \
- p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \
- { base + 0x0c, 32, 4, /* ICR4A */ \
- { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \
- p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } }
-
-#define INTC_IRQ_PINS_ACK_16L(p, base) \
- { base + 0x20, 0, 8, /* INTREQ00A */ \
- { p ## _IRQ0, p ## _IRQ1, p ## _IRQ2, p ## _IRQ3, \
- p ## _IRQ4, p ## _IRQ5, p ## _IRQ6, p ## _IRQ7 } }, \
- { base + 0x24, 0, 8, /* INTREQ10A */ \
- { p ## _IRQ8, p ## _IRQ9, p ## _IRQ10, p ## _IRQ11, \
- p ## _IRQ12, p ## _IRQ13, p ## _IRQ14, p ## _IRQ15 } }
-
-#define INTC_IRQ_PINS_ACK_16H(p, base) \
- { base + 0x28, 0, 8, /* INTREQ20A */ \
- { p ## _IRQ16, p ## _IRQ17, p ## _IRQ18, p ## _IRQ19, \
- p ## _IRQ20, p ## _IRQ21, p ## _IRQ22, p ## _IRQ23 } }, \
- { base + 0x2c, 0, 8, /* INTREQ30A */ \
- { p ## _IRQ24, p ## _IRQ25, p ## _IRQ26, p ## _IRQ27, \
- p ## _IRQ28, p ## _IRQ29, p ## _IRQ30, p ## _IRQ31 } }
-
-#define INTC_IRQ_PINS_16(p, base, vect, str) \
- \
-static struct resource p ## _resources[] __initdata = { \
- [0] = { \
- .start = base, \
- .end = base + 0x64, \
- .flags = IORESOURCE_MEM, \
- }, \
-}; \
- \
-enum { \
- p ## _UNUSED = 0, \
- INTC_IRQ_PINS_ENUM_16L(p), \
-}; \
- \
-static struct intc_vect p ## _vectors[] __initdata = { \
- INTC_IRQ_PINS_VECT_16L(p, vect), \
-}; \
- \
-static struct intc_mask_reg p ## _mask_registers[] __initdata = { \
- INTC_IRQ_PINS_MASK_16L(p, base), \
-}; \
- \
-static struct intc_prio_reg p ## _prio_registers[] __initdata = { \
- INTC_IRQ_PINS_PRIO_16L(p, base), \
-}; \
- \
-static struct intc_sense_reg p ## _sense_registers[] __initdata = { \
- INTC_IRQ_PINS_SENSE_16L(p, base), \
-}; \
- \
-static struct intc_mask_reg p ## _ack_registers[] __initdata = { \
- INTC_IRQ_PINS_ACK_16L(p, base), \
-}; \
- \
-static struct intc_desc p ## _desc __initdata = { \
- .name = str, \
- .resource = p ## _resources, \
- .num_resources = ARRAY_SIZE(p ## _resources), \
- .hw = INTC_HW_DESC(p ## _vectors, NULL, \
- p ## _mask_registers, p ## _prio_registers, \
- p ## _sense_registers, p ## _ack_registers) \
-}
-
-#define INTC_IRQ_PINS_16H(p, base, vect, str) \
- \
-static struct resource p ## _resources[] __initdata = { \
- [0] = { \
- .start = base, \
- .end = base + 0x64, \
- .flags = IORESOURCE_MEM, \
- }, \
-}; \
- \
-enum { \
- p ## _UNUSED = 0, \
- INTC_IRQ_PINS_ENUM_16H(p), \
-}; \
- \
-static struct intc_vect p ## _vectors[] __initdata = { \
- INTC_IRQ_PINS_VECT_16H(p, vect), \
-}; \
- \
-static struct intc_mask_reg p ## _mask_registers[] __initdata = { \
- INTC_IRQ_PINS_MASK_16H(p, base), \
-}; \
- \
-static struct intc_prio_reg p ## _prio_registers[] __initdata = { \
- INTC_IRQ_PINS_PRIO_16H(p, base), \
-}; \
- \
-static struct intc_sense_reg p ## _sense_registers[] __initdata = { \
- INTC_IRQ_PINS_SENSE_16H(p, base), \
-}; \
- \
-static struct intc_mask_reg p ## _ack_registers[] __initdata = { \
- INTC_IRQ_PINS_ACK_16H(p, base), \
-}; \
- \
-static struct intc_desc p ## _desc __initdata = { \
- .name = str, \
- .resource = p ## _resources, \
- .num_resources = ARRAY_SIZE(p ## _resources), \
- .hw = INTC_HW_DESC(p ## _vectors, NULL, \
- p ## _mask_registers, p ## _prio_registers, \
- p ## _sense_registers, p ## _ack_registers) \
-}
-
-#define INTC_IRQ_PINS_32(p, base, vect, str) \
- \
-static struct resource p ## _resources[] __initdata = { \
- [0] = { \
- .start = base, \
- .end = base + 0x6c, \
- .flags = IORESOURCE_MEM, \
- }, \
-}; \
- \
-enum { \
- p ## _UNUSED = 0, \
- INTC_IRQ_PINS_ENUM_16L(p), \
- INTC_IRQ_PINS_ENUM_16H(p), \
-}; \
- \
-static struct intc_vect p ## _vectors[] __initdata = { \
- INTC_IRQ_PINS_VECT_16L(p, vect), \
- INTC_IRQ_PINS_VECT_16H(p, vect), \
-}; \
- \
-static struct intc_mask_reg p ## _mask_registers[] __initdata = { \
- INTC_IRQ_PINS_MASK_16L(p, base), \
- INTC_IRQ_PINS_MASK_16H(p, base), \
-}; \
- \
-static struct intc_prio_reg p ## _prio_registers[] __initdata = { \
- INTC_IRQ_PINS_PRIO_16L(p, base), \
- INTC_IRQ_PINS_PRIO_16H(p, base), \
-}; \
- \
-static struct intc_sense_reg p ## _sense_registers[] __initdata = { \
- INTC_IRQ_PINS_SENSE_16L(p, base), \
- INTC_IRQ_PINS_SENSE_16H(p, base), \
-}; \
- \
-static struct intc_mask_reg p ## _ack_registers[] __initdata = { \
- INTC_IRQ_PINS_ACK_16L(p, base), \
- INTC_IRQ_PINS_ACK_16H(p, base), \
-}; \
- \
-static struct intc_desc p ## _desc __initdata = { \
- .name = str, \
- .resource = p ## _resources, \
- .num_resources = ARRAY_SIZE(p ## _resources), \
- .hw = INTC_HW_DESC(p ## _vectors, NULL, \
- p ## _mask_registers, p ## _prio_registers, \
- p ## _sense_registers, p ## _ack_registers) \
-}
-
-#define INTC_PINT_E_EMPTY
-#define INTC_PINT_E_NONE 0, 0, 0, 0, 0, 0, 0, 0,
-#define INTC_PINT_E(p) \
- PINT ## p ## 0, PINT ## p ## 1, PINT ## p ## 2, PINT ## p ## 3, \
- PINT ## p ## 4, PINT ## p ## 5, PINT ## p ## 6, PINT ## p ## 7,
-
-#define INTC_PINT_V_NONE
-#define INTC_PINT_V(p, vect) \
- vect(PINT ## p ## 0, 0), vect(PINT ## p ## 1, 1), \
- vect(PINT ## p ## 2, 2), vect(PINT ## p ## 3, 3), \
- vect(PINT ## p ## 4, 4), vect(PINT ## p ## 5, 5), \
- vect(PINT ## p ## 6, 6), vect(PINT ## p ## 7, 7),
-
-#define INTC_PINT(p, mask_reg, sense_base, str, \
- enums_1, enums_2, enums_3, enums_4, \
- vect_1, vect_2, vect_3, vect_4, \
- mask_a, mask_b, mask_c, mask_d, \
- sense_a, sense_b, sense_c, sense_d) \
- \
-enum { \
- PINT ## p ## _UNUSED = 0, \
- enums_1 enums_2 enums_3 enums_4 \
-}; \
- \
-static struct intc_vect p ## _vectors[] __initdata = { \
- vect_1 vect_2 vect_3 vect_4 \
-}; \
- \
-static struct intc_mask_reg p ## _mask_registers[] __initdata = { \
- { mask_reg, 0, 32, /* PINTER */ \
- { mask_a mask_b mask_c mask_d } } \
-}; \
- \
-static struct intc_sense_reg p ## _sense_registers[] __initdata = { \
- { sense_base + 0x00, 16, 2, /* PINTCR */ \
- { sense_a } }, \
- { sense_base + 0x04, 16, 2, /* PINTCR */ \
- { sense_b } }, \
- { sense_base + 0x08, 16, 2, /* PINTCR */ \
- { sense_c } }, \
- { sense_base + 0x0c, 16, 2, /* PINTCR */ \
- { sense_d } }, \
-}; \
- \
-static struct intc_desc p ## _desc __initdata = { \
- .name = str, \
- .hw = INTC_HW_DESC(p ## _vectors, NULL, \
- p ## _mask_registers, NULL, \
- p ## _sense_registers, NULL), \
-}
-
-/* INTCS */
-#define INTCS_VECT_BASE 0x3400
-#define INTCS_VECT(n, vect) INTC_VECT((n), INTCS_VECT_BASE + (vect))
-#define intcs_evt2irq(evt) evt2irq(INTCS_VECT_BASE + (evt))
-
-#endif /* __ASM_MACH_INTC_H */
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c
index 4e54512..911884f 100644
--- a/arch/arm/mach-shmobile/platsmp-apmu.c
+++ b/arch/arm/mach-shmobile/platsmp-apmu.c
@@ -88,7 +88,7 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit)
static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit),
struct rcar_apmu_config *apmu_config, int num)
{
- u32 id;
+ int id;
int k;
int bit, index;
bool is_allowed;
@@ -170,7 +170,7 @@ static inline void cpu_enter_lowpower_a15(void)
dsb();
}
-void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu)
+static void shmobile_smp_apmu_cpu_shutdown(unsigned int cpu)
{
/* Select next sleep mode using the APMU */
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c
index 47a862e..14c42a1b 100644
--- a/arch/arm/mach-shmobile/pm-r8a7779.c
+++ b/arch/arm/mach-shmobile/pm-r8a7779.c
@@ -9,20 +9,8 @@
* for more details.
*/
-#include <linux/pm.h>
-#include <linux/suspend.h>
-#include <linux/err.h>
-#include <linux/pm_clock.h>
-#include <linux/pm_domain.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/console.h>
-
#include <asm/io.h>
-#include "common.h"
#include "pm-rcar.h"
#include "r8a7779.h"
@@ -30,17 +18,6 @@
#define SYSCIER 0x0c
#define SYSCIMR 0x10
-struct r8a7779_pm_domain {
- struct generic_pm_domain genpd;
- struct rcar_sysc_ch ch;
-};
-
-static inline
-const struct rcar_sysc_ch *to_r8a7779_ch(struct generic_pm_domain *d)
-{
- return &container_of(d, struct r8a7779_pm_domain, genpd)->ch;
-}
-
#if defined(CONFIG_PM) || defined(CONFIG_SMP)
static void __init r8a7779_sysc_init(void)
@@ -58,82 +35,6 @@ static inline void r8a7779_sysc_init(void) {}
#endif /* CONFIG_PM || CONFIG_SMP */
-#ifdef CONFIG_PM
-
-static int pd_power_down(struct generic_pm_domain *genpd)
-{
- return rcar_sysc_power_down(to_r8a7779_ch(genpd));
-}
-
-static int pd_power_up(struct generic_pm_domain *genpd)
-{
- return rcar_sysc_power_up(to_r8a7779_ch(genpd));
-}
-
-static bool pd_is_off(struct generic_pm_domain *genpd)
-{
- return rcar_sysc_power_is_off(to_r8a7779_ch(genpd));
-}
-
-static bool pd_active_wakeup(struct device *dev)
-{
- return true;
-}
-
-static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
-{
- struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
-
- pm_genpd_init(genpd, NULL, false);
- genpd->dev_ops.active_wakeup = pd_active_wakeup;
- genpd->power_off = pd_power_down;
- genpd->power_on = pd_power_up;
-
- if (pd_is_off(&r8a7779_pd->genpd))
- pd_power_up(&r8a7779_pd->genpd);
-}
-
-static struct r8a7779_pm_domain r8a7779_pm_domains[] = {
- {
- .genpd.name = "SH4A",
- .ch = {
- .chan_offs = 0x80, /* PWRSR1 .. PWRER1 */
- .isr_bit = 16, /* SH4A */
- },
- },
- {
- .genpd.name = "SGX",
- .ch = {
- .chan_offs = 0xc0, /* PWRSR2 .. PWRER2 */
- .isr_bit = 20, /* SGX */
- },
- },
- {
- .genpd.name = "VDP1",
- .ch = {
- .chan_offs = 0x100, /* PWRSR3 .. PWRER3 */
- .isr_bit = 21, /* VDP */
- },
- },
- {
- .genpd.name = "IMPX3",
- .ch = {
- .chan_offs = 0x140, /* PWRSR4 .. PWRER4 */
- .isr_bit = 24, /* IMP */
- },
- },
-};
-
-void __init r8a7779_init_pm_domains(void)
-{
- int j;
-
- for (j = 0; j < ARRAY_SIZE(r8a7779_pm_domains); j++)
- r8a7779_init_pm_domain(&r8a7779_pm_domains[j]);
-}
-
-#endif /* CONFIG_PM */
-
void __init r8a7779_pm_init(void)
{
static int once;
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index a5b96b9..46d0a1d 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -12,6 +12,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
+#include <linux/clk/shmobile.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/of.h>
@@ -124,36 +125,6 @@ static bool rmobile_pd_active_wakeup(struct device *dev)
return true;
}
-static int rmobile_pd_attach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- int error;
-
- error = pm_clk_create(dev);
- if (error) {
- dev_err(dev, "pm_clk_create failed %d\n", error);
- return error;
- }
-
- error = pm_clk_add(dev, NULL);
- if (error) {
- dev_err(dev, "pm_clk_add failed %d\n", error);
- goto fail;
- }
-
- return 0;
-
-fail:
- pm_clk_destroy(dev);
- return error;
-}
-
-static void rmobile_pd_detach_dev(struct generic_pm_domain *domain,
- struct device *dev)
-{
- pm_clk_destroy(dev);
-}
-
static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
{
struct generic_pm_domain *genpd = &rmobile_pd->genpd;
@@ -164,8 +135,8 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
genpd->power_off = rmobile_pd_power_down;
genpd->power_on = rmobile_pd_power_up;
- genpd->attach_dev = rmobile_pd_attach_dev;
- genpd->detach_dev = rmobile_pd_detach_dev;
+ genpd->attach_dev = cpg_mstp_attach_dev;
+ genpd->detach_dev = cpg_mstp_detach_dev;
__rmobile_pd_power_up(rmobile_pd, false);
}
@@ -342,8 +313,10 @@ static int __init rmobile_add_pm_domains(void __iomem *base,
}
pd = kzalloc(sizeof(*pd), GFP_KERNEL);
- if (!pd)
+ if (!pd) {
+ of_node_put(np);
return -ENOMEM;
+ }
pd->genpd.name = np->name;
pd->base = base;
diff --git a/arch/arm/mach-shmobile/pm-rmobile.h b/arch/arm/mach-shmobile/pm-rmobile.h
index 30a4a42..8146bb6 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.h
+++ b/arch/arm/mach-shmobile/pm-rmobile.h
@@ -12,10 +12,6 @@
#include <linux/pm_domain.h>
-#define DEFAULT_DEV_LATENCY_NS 250000
-
-struct platform_device;
-
struct rmobile_pm_domain {
struct generic_pm_domain genpd;
struct dev_power_governor *gov;
@@ -26,9 +22,4 @@ struct rmobile_pm_domain {
bool no_debug;
};
-struct pm_domain_device {
- const char *domain_name;
- struct platform_device *pdev;
-};
-
#endif /* PM_RMOBILE_H */
diff --git a/arch/arm/mach-shmobile/r8a7778.h b/arch/arm/mach-shmobile/r8a7778.h
deleted file mode 100644
index f64fedb..0000000
--- a/arch/arm/mach-shmobile/r8a7778.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
- * Copyright (C) 2013 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#ifndef __ASM_R8A7778_H__
-#define __ASM_R8A7778_H__
-
-#include <linux/sh_eth.h>
-
-/* HPB-DMA slave IDs */
-enum {
- HPBDMA_SLAVE_DUMMY,
- HPBDMA_SLAVE_SDHI0_TX,
- HPBDMA_SLAVE_SDHI0_RX,
- HPBDMA_SLAVE_SSI0_TX,
- HPBDMA_SLAVE_SSI0_RX,
- HPBDMA_SLAVE_SSI1_TX,
- HPBDMA_SLAVE_SSI1_RX,
- HPBDMA_SLAVE_SSI2_TX,
- HPBDMA_SLAVE_SSI2_RX,
- HPBDMA_SLAVE_SSI3_TX,
- HPBDMA_SLAVE_SSI3_RX,
- HPBDMA_SLAVE_SSI4_TX,
- HPBDMA_SLAVE_SSI4_RX,
- HPBDMA_SLAVE_SSI5_TX,
- HPBDMA_SLAVE_SSI5_RX,
- HPBDMA_SLAVE_SSI6_TX,
- HPBDMA_SLAVE_SSI6_RX,
- HPBDMA_SLAVE_SSI7_TX,
- HPBDMA_SLAVE_SSI7_RX,
- HPBDMA_SLAVE_SSI8_TX,
- HPBDMA_SLAVE_SSI8_RX,
- HPBDMA_SLAVE_HPBIF0_TX,
- HPBDMA_SLAVE_HPBIF0_RX,
- HPBDMA_SLAVE_HPBIF1_TX,
- HPBDMA_SLAVE_HPBIF1_RX,
- HPBDMA_SLAVE_HPBIF2_TX,
- HPBDMA_SLAVE_HPBIF2_RX,
- HPBDMA_SLAVE_HPBIF3_TX,
- HPBDMA_SLAVE_HPBIF3_RX,
- HPBDMA_SLAVE_HPBIF4_TX,
- HPBDMA_SLAVE_HPBIF4_RX,
- HPBDMA_SLAVE_HPBIF5_TX,
- HPBDMA_SLAVE_HPBIF5_RX,
- HPBDMA_SLAVE_HPBIF6_TX,
- HPBDMA_SLAVE_HPBIF6_RX,
- HPBDMA_SLAVE_HPBIF7_TX,
- HPBDMA_SLAVE_HPBIF7_RX,
- HPBDMA_SLAVE_HPBIF8_TX,
- HPBDMA_SLAVE_HPBIF8_RX,
- HPBDMA_SLAVE_USBFUNC_TX,
- HPBDMA_SLAVE_USBFUNC_RX,
-};
-
-extern void r8a7778_add_standard_devices(void);
-extern void r8a7778_add_standard_devices_dt(void);
-extern void r8a7778_add_dt_devices(void);
-
-extern void r8a7778_init_late(void);
-extern void r8a7778_init_irq_dt(void);
-extern void r8a7778_clock_init(void);
-extern void r8a7778_init_irq_extpin(int irlm);
-extern void r8a7778_init_irq_extpin_dt(int irlm);
-extern void r8a7778_pinmux_init(void);
-
-extern int r8a7778_usb_phy_power(bool enable);
-
-#endif /* __ASM_R8A7778_H__ */
diff --git a/arch/arm/mach-shmobile/r8a7779.h b/arch/arm/mach-shmobile/r8a7779.h
index db303f7..e1aaa2e 100644
--- a/arch/arm/mach-shmobile/r8a7779.h
+++ b/arch/arm/mach-shmobile/r8a7779.h
@@ -1,16 +1,8 @@
#ifndef __ASM_R8A7779_H__
#define __ASM_R8A7779_H__
-#include <linux/sh_clk.h>
-
extern void r8a7779_pm_init(void);
-#ifdef CONFIG_PM
-extern void __init r8a7779_init_pm_domains(void);
-#else
-static inline void r8a7779_init_pm_domains(void) {}
-#endif /* CONFIG_PM */
-
extern struct smp_operations r8a7779_smp_ops;
#endif /* __ASM_R8A7779_H__ */
diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c
index b9116c8..0ab9d32 100644
--- a/arch/arm/mach-shmobile/setup-r8a7778.c
+++ b/arch/arm/mach-shmobile/setup-r8a7778.c
@@ -16,35 +16,16 @@
*/
#include <linux/clk/shmobile.h>
-#include <linux/kernel.h>
#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/platform_data/dma-rcar-hpbdma.h>
-#include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/irq-renesas-intc-irqpin.h>
-#include <linux/platform_device.h>
#include <linux/irqchip.h>
-#include <linux/serial_sci.h>
-#include <linux/sh_timer.h>
-#include <linux/pm_runtime.h>
-#include <linux/usb/phy.h>
-#include <linux/usb/hcd.h>
-#include <linux/usb/ehci_pdriver.h>
-#include <linux/usb/ohci_pdriver.h>
-#include <linux/dma-mapping.h>
#include <asm/mach/arch.h>
-#include <asm/hardware/cache-l2x0.h>
#include "common.h"
#include "irqs.h"
-#include "r8a7778.h"
#define MODEMR 0xffcc0020
-#ifdef CONFIG_COMMON_CLK
static void __init r8a7778_timer_init(void)
{
u32 mode;
@@ -55,555 +36,21 @@ static void __init r8a7778_timer_init(void)
iounmap(modemr);
r8a7778_clocks_init(mode);
}
-#endif
-/* SCIF */
-#define R8A7778_SCIF(index, baseaddr, irq) \
-static struct plat_sci_port scif##index##_platform_data = { \
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \
- .scscr = SCSCR_RE | SCSCR_TE | SCSCR_CKE1, \
- .type = PORT_SCIF, \
-}; \
- \
-static struct resource scif##index##_resources[] = { \
- DEFINE_RES_MEM(baseaddr, 0x100), \
- DEFINE_RES_IRQ(irq), \
-}
-
-R8A7778_SCIF(0, 0xffe40000, gic_iid(0x66));
-R8A7778_SCIF(1, 0xffe41000, gic_iid(0x67));
-R8A7778_SCIF(2, 0xffe42000, gic_iid(0x68));
-R8A7778_SCIF(3, 0xffe43000, gic_iid(0x69));
-R8A7778_SCIF(4, 0xffe44000, gic_iid(0x6a));
-R8A7778_SCIF(5, 0xffe45000, gic_iid(0x6b));
-
-#define r8a7778_register_scif(index) \
- platform_device_register_resndata(NULL, "sh-sci", index, \
- scif##index##_resources, \
- ARRAY_SIZE(scif##index##_resources), \
- &scif##index##_platform_data, \
- sizeof(scif##index##_platform_data))
-
-/* TMU */
-static struct sh_timer_config sh_tmu0_platform_data = {
- .channels_mask = 7,
-};
-
-static struct resource sh_tmu0_resources[] = {
- DEFINE_RES_MEM(0xffd80000, 0x30),
- DEFINE_RES_IRQ(gic_iid(0x40)),
- DEFINE_RES_IRQ(gic_iid(0x41)),
- DEFINE_RES_IRQ(gic_iid(0x42)),
-};
-
-#define r8a7778_register_tmu(idx) \
- platform_device_register_resndata( \
- NULL, "sh-tmu", idx, \
- sh_tmu##idx##_resources, \
- ARRAY_SIZE(sh_tmu##idx##_resources), \
- &sh_tmu##idx##_platform_data, \
- sizeof(sh_tmu##idx##_platform_data))
-
-int r8a7778_usb_phy_power(bool enable)
-{
- static struct usb_phy *phy = NULL;
- int ret = 0;
-
- if (!phy)
- phy = usb_get_phy(USB_PHY_TYPE_USB2);
-
- if (IS_ERR(phy)) {
- pr_err("kernel doesn't have usb phy driver\n");
- return PTR_ERR(phy);
- }
-
- if (enable)
- ret = usb_phy_init(phy);
- else
- usb_phy_shutdown(phy);
-
- return ret;
-}
-
-/* USB */
-static int usb_power_on(struct platform_device *pdev)
-{
- int ret = r8a7778_usb_phy_power(true);
-
- if (ret)
- return ret;
-
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
-
- return 0;
-}
-
-static void usb_power_off(struct platform_device *pdev)
-{
- if (r8a7778_usb_phy_power(false))
- return;
-
- pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-}
-
-static int ehci_init_internal_buffer(struct usb_hcd *hcd)
-{
- /*
- * Below are recommended values from the datasheet;
- * see [USB :: Setting of EHCI Internal Buffer].
- */
- /* EHCI IP internal buffer setting */
- iowrite32(0x00ff0040, hcd->regs + 0x0094);
- /* EHCI IP internal buffer enable */
- iowrite32(0x00000001, hcd->regs + 0x009C);
-
- return 0;
-}
-
-static struct usb_ehci_pdata ehci_pdata __initdata = {
- .power_on = usb_power_on,
- .power_off = usb_power_off,
- .power_suspend = usb_power_off,
- .pre_setup = ehci_init_internal_buffer,
-};
-
-static struct resource ehci_resources[] __initdata = {
- DEFINE_RES_MEM(0xffe70000, 0x400),
- DEFINE_RES_IRQ(gic_iid(0x4c)),
-};
-
-static struct usb_ohci_pdata ohci_pdata __initdata = {
- .power_on = usb_power_on,
- .power_off = usb_power_off,
- .power_suspend = usb_power_off,
-};
-
-static struct resource ohci_resources[] __initdata = {
- DEFINE_RES_MEM(0xffe70400, 0x400),
- DEFINE_RES_IRQ(gic_iid(0x4c)),
-};
-
-#define USB_PLATFORM_INFO(hci) \
-static struct platform_device_info hci##_info __initdata = { \
- .name = #hci "-platform", \
- .id = -1, \
- .res = hci##_resources, \
- .num_res = ARRAY_SIZE(hci##_resources), \
- .data = &hci##_pdata, \
- .size_data = sizeof(hci##_pdata), \
- .dma_mask = DMA_BIT_MASK(32), \
-}
-
-USB_PLATFORM_INFO(ehci);
-USB_PLATFORM_INFO(ohci);
-
-/* PFC/GPIO */
-static struct resource pfc_resources[] __initdata = {
- DEFINE_RES_MEM(0xfffc0000, 0x118),
-};
-
-#define R8A7778_GPIO(idx) \
-static struct resource r8a7778_gpio##idx##_resources[] __initdata = { \
- DEFINE_RES_MEM(0xffc40000 + 0x1000 * (idx), 0x30), \
- DEFINE_RES_IRQ(gic_iid(0x87)), \
-}; \
- \
-static struct gpio_rcar_config r8a7778_gpio##idx##_platform_data __initdata = { \
- .gpio_base = 32 * (idx), \
- .irq_base = GPIO_IRQ_BASE(idx), \
- .number_of_pins = 32, \
- .pctl_name = "pfc-r8a7778", \
-}
-
-R8A7778_GPIO(0);
-R8A7778_GPIO(1);
-R8A7778_GPIO(2);
-R8A7778_GPIO(3);
-R8A7778_GPIO(4);
-
-#define r8a7778_register_gpio(idx) \
- platform_device_register_resndata( \
- NULL, "gpio_rcar", idx, \
- r8a7778_gpio##idx##_resources, \
- ARRAY_SIZE(r8a7778_gpio##idx##_resources), \
- &r8a7778_gpio##idx##_platform_data, \
- sizeof(r8a7778_gpio##idx##_platform_data))
-
-void __init r8a7778_pinmux_init(void)
-{
- platform_device_register_simple(
- "pfc-r8a7778", -1,
- pfc_resources,
- ARRAY_SIZE(pfc_resources));
-
- r8a7778_register_gpio(0);
- r8a7778_register_gpio(1);
- r8a7778_register_gpio(2);
- r8a7778_register_gpio(3);
- r8a7778_register_gpio(4);
-};
-
-/* I2C */
-static struct resource i2c_resources[] __initdata = {
- /* I2C0 */
- DEFINE_RES_MEM(0xffc70000, 0x1000),
- DEFINE_RES_IRQ(gic_iid(0x63)),
- /* I2C1 */
- DEFINE_RES_MEM(0xffc71000, 0x1000),
- DEFINE_RES_IRQ(gic_iid(0x6e)),
- /* I2C2 */
- DEFINE_RES_MEM(0xffc72000, 0x1000),
- DEFINE_RES_IRQ(gic_iid(0x6c)),
- /* I2C3 */
- DEFINE_RES_MEM(0xffc73000, 0x1000),
- DEFINE_RES_IRQ(gic_iid(0x6d)),
-};
-
-static void __init r8a7778_register_i2c(int id)
-{
- BUG_ON(id < 0 || id > 3);
-
- platform_device_register_simple(
- "i2c-rcar", id,
- i2c_resources + (2 * id), 2);
-}
-
-/* HSPI */
-static struct resource hspi_resources[] __initdata = {
- /* HSPI0 */
- DEFINE_RES_MEM(0xfffc7000, 0x18),
- DEFINE_RES_IRQ(gic_iid(0x5f)),
- /* HSPI1 */
- DEFINE_RES_MEM(0xfffc8000, 0x18),
- DEFINE_RES_IRQ(gic_iid(0x74)),
- /* HSPI2 */
- DEFINE_RES_MEM(0xfffc6000, 0x18),
- DEFINE_RES_IRQ(gic_iid(0x75)),
-};
-
-static void __init r8a7778_register_hspi(int id)
-{
- BUG_ON(id < 0 || id > 2);
-
- platform_device_register_simple(
- "sh-hspi", id,
- hspi_resources + (2 * id), 2);
-}
-
-void __init r8a7778_add_dt_devices(void)
-{
-#ifdef CONFIG_CACHE_L2X0
- void __iomem *base = ioremap_nocache(0xf0100000, 0x1000);
- if (base) {
- /*
- * Shared attribute override enable, 64K*16way
- * don't call iounmap(base)
- */
- l2x0_init(base, 0x00400000, 0xc20f0fff);
- }
-#endif
-}
-
-/* HPB-DMA */
-
-/* Asynchronous mode register (ASYNCMDR) bits */
-#define HPB_DMAE_ASYNCMDR_ASMD22_MASK BIT(2) /* SDHI0 */
-#define HPB_DMAE_ASYNCMDR_ASMD22_SINGLE BIT(2) /* SDHI0 */
-#define HPB_DMAE_ASYNCMDR_ASMD22_MULTI 0 /* SDHI0 */
-#define HPB_DMAE_ASYNCMDR_ASMD21_MASK BIT(1) /* SDHI0 */
-#define HPB_DMAE_ASYNCMDR_ASMD21_SINGLE BIT(1) /* SDHI0 */
-#define HPB_DMAE_ASYNCMDR_ASMD21_MULTI 0 /* SDHI0 */
-
-#define HPBDMA_SSI(_id) \
-{ \
- .id = HPBDMA_SLAVE_SSI## _id ##_TX, \
- .addr = 0xffd91008 + (_id * 0x40), \
- .dcr = HPB_DMAE_DCR_CT | \
- HPB_DMAE_DCR_DIP | \
- HPB_DMAE_DCR_SPDS_32BIT | \
- HPB_DMAE_DCR_DMDL | \
- HPB_DMAE_DCR_DPDS_32BIT, \
- .port = _id + (_id << 8), \
- .dma_ch = (28 + _id), \
-}, { \
- .id = HPBDMA_SLAVE_SSI## _id ##_RX, \
- .addr = 0xffd9100c + (_id * 0x40), \
- .dcr = HPB_DMAE_DCR_CT | \
- HPB_DMAE_DCR_DIP | \
- HPB_DMAE_DCR_SMDL | \
- HPB_DMAE_DCR_SPDS_32BIT | \
- HPB_DMAE_DCR_DPDS_32BIT, \
- .port = _id + (_id << 8), \
- .dma_ch = (28 + _id), \
-}
-
-#define HPBDMA_HPBIF(_id) \
-{ \
- .id = HPBDMA_SLAVE_HPBIF## _id ##_TX, \
- .addr = 0xffda0000 + (_id * 0x1000), \
- .dcr = HPB_DMAE_DCR_CT | \
- HPB_DMAE_DCR_DIP | \
- HPB_DMAE_DCR_SPDS_32BIT | \
- HPB_DMAE_DCR_DMDL | \
- HPB_DMAE_DCR_DPDS_32BIT, \
- .port = 0x1111, \
- .dma_ch = (28 + _id), \
-}, { \
- .id = HPBDMA_SLAVE_HPBIF## _id ##_RX, \
- .addr = 0xffda0000 + (_id * 0x1000), \
- .dcr = HPB_DMAE_DCR_CT | \
- HPB_DMAE_DCR_DIP | \
- HPB_DMAE_DCR_SMDL | \
- HPB_DMAE_DCR_SPDS_32BIT | \
- HPB_DMAE_DCR_DPDS_32BIT, \
- .port = 0x1111, \
- .dma_ch = (28 + _id), \
-}
-
-static const struct hpb_dmae_slave_config hpb_dmae_slaves[] = {
- {
- .id = HPBDMA_SLAVE_SDHI0_TX,
- .addr = 0xffe4c000 + 0x30,
- .dcr = HPB_DMAE_DCR_SPDS_16BIT |
- HPB_DMAE_DCR_DMDL |
- HPB_DMAE_DCR_DPDS_16BIT,
- .rstr = HPB_DMAE_ASYNCRSTR_ASRST21 |
- HPB_DMAE_ASYNCRSTR_ASRST22 |
- HPB_DMAE_ASYNCRSTR_ASRST23,
- .mdr = HPB_DMAE_ASYNCMDR_ASMD21_MULTI,
- .mdm = HPB_DMAE_ASYNCMDR_ASMD21_MASK,
- .port = 0x0D0C,
- .flags = HPB_DMAE_SET_ASYNC_RESET | HPB_DMAE_SET_ASYNC_MODE,
- .dma_ch = 21,
- }, {
- .id = HPBDMA_SLAVE_SDHI0_RX,
- .addr = 0xffe4c000 + 0x30,
- .dcr = HPB_DMAE_DCR_SMDL |
- HPB_DMAE_DCR_SPDS_16BIT |
- HPB_DMAE_DCR_DPDS_16BIT,
- .rstr = HPB_DMAE_ASYNCRSTR_ASRST21 |
- HPB_DMAE_ASYNCRSTR_ASRST22 |
- HPB_DMAE_ASYNCRSTR_ASRST23,
- .mdr = HPB_DMAE_ASYNCMDR_ASMD22_MULTI,
- .mdm = HPB_DMAE_ASYNCMDR_ASMD22_MASK,
- .port = 0x0D0C,
- .flags = HPB_DMAE_SET_ASYNC_RESET | HPB_DMAE_SET_ASYNC_MODE,
- .dma_ch = 22,
- }, {
- .id = HPBDMA_SLAVE_USBFUNC_TX, /* for D0 */
- .addr = 0xffe60018,
- .dcr = HPB_DMAE_DCR_SPDS_32BIT |
- HPB_DMAE_DCR_DMDL |
- HPB_DMAE_DCR_DPDS_32BIT,
- .port = 0x0000,
- .dma_ch = 14,
- }, {
- .id = HPBDMA_SLAVE_USBFUNC_RX, /* for D1 */
- .addr = 0xffe6001c,
- .dcr = HPB_DMAE_DCR_SMDL |
- HPB_DMAE_DCR_SPDS_32BIT |
- HPB_DMAE_DCR_DPDS_32BIT,
- .port = 0x0101,
- .dma_ch = 15,
- },
-
- HPBDMA_SSI(0),
- HPBDMA_SSI(1),
- HPBDMA_SSI(2),
- HPBDMA_SSI(3),
- HPBDMA_SSI(4),
- HPBDMA_SSI(5),
- HPBDMA_SSI(6),
- HPBDMA_SSI(7),
- HPBDMA_SSI(8),
-
- HPBDMA_HPBIF(0),
- HPBDMA_HPBIF(1),
- HPBDMA_HPBIF(2),
- HPBDMA_HPBIF(3),
- HPBDMA_HPBIF(4),
- HPBDMA_HPBIF(5),
- HPBDMA_HPBIF(6),
- HPBDMA_HPBIF(7),
- HPBDMA_HPBIF(8),
-};
-
-static const struct hpb_dmae_channel hpb_dmae_channels[] = {
- HPB_DMAE_CHANNEL(0x7c, HPBDMA_SLAVE_USBFUNC_TX), /* ch. 14 */
- HPB_DMAE_CHANNEL(0x7c, HPBDMA_SLAVE_USBFUNC_RX), /* ch. 15 */
- HPB_DMAE_CHANNEL(0x7e, HPBDMA_SLAVE_SDHI0_TX), /* ch. 21 */
- HPB_DMAE_CHANNEL(0x7e, HPBDMA_SLAVE_SDHI0_RX), /* ch. 22 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI0_TX), /* ch. 28 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI0_RX), /* ch. 28 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF0_TX), /* ch. 28 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF0_RX), /* ch. 28 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI1_TX), /* ch. 29 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI1_RX), /* ch. 29 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF1_TX), /* ch. 29 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF1_RX), /* ch. 29 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI2_TX), /* ch. 30 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI2_RX), /* ch. 30 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF2_TX), /* ch. 30 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF2_RX), /* ch. 30 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI3_TX), /* ch. 31 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI3_RX), /* ch. 31 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF3_TX), /* ch. 31 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF3_RX), /* ch. 31 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI4_TX), /* ch. 32 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI4_RX), /* ch. 32 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF4_TX), /* ch. 32 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF4_RX), /* ch. 32 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI5_TX), /* ch. 33 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI5_RX), /* ch. 33 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF5_TX), /* ch. 33 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF5_RX), /* ch. 33 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI6_TX), /* ch. 34 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI6_RX), /* ch. 34 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF6_TX), /* ch. 34 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF6_RX), /* ch. 34 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI7_TX), /* ch. 35 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI7_RX), /* ch. 35 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF7_TX), /* ch. 35 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF7_RX), /* ch. 35 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI8_TX), /* ch. 36 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_SSI8_RX), /* ch. 36 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF8_TX), /* ch. 36 */
- HPB_DMAE_CHANNEL(0x7f, HPBDMA_SLAVE_HPBIF8_RX), /* ch. 36 */
-};
-
-static struct hpb_dmae_pdata dma_platform_data __initdata = {
- .slaves = hpb_dmae_slaves,
- .num_slaves = ARRAY_SIZE(hpb_dmae_slaves),
- .channels = hpb_dmae_channels,
- .num_channels = ARRAY_SIZE(hpb_dmae_channels),
- .ts_shift = {
- [XMIT_SZ_8BIT] = 0,
- [XMIT_SZ_16BIT] = 1,
- [XMIT_SZ_32BIT] = 2,
- },
- .num_hw_channels = 39,
-};
-
-static struct resource hpb_dmae_resources[] __initdata = {
- /* Channel registers */
- DEFINE_RES_MEM(0xffc08000, 0x1000),
- /* Common registers */
- DEFINE_RES_MEM(0xffc09000, 0x170),
- /* Asynchronous reset registers */
- DEFINE_RES_MEM(0xffc00300, 4),
- /* Asynchronous mode registers */
- DEFINE_RES_MEM(0xffc00400, 4),
- /* IRQ for DMA channels */
- DEFINE_RES_NAMED(gic_iid(0x7b), 5, NULL, IORESOURCE_IRQ),
-};
-
-static void __init r8a7778_register_hpb_dmae(void)
-{
- platform_device_register_resndata(NULL, "hpb-dma-engine",
- -1, hpb_dmae_resources,
- ARRAY_SIZE(hpb_dmae_resources),
- &dma_platform_data,
- sizeof(dma_platform_data));
-}
-
-void __init r8a7778_add_standard_devices(void)
-{
- r8a7778_add_dt_devices();
- r8a7778_register_tmu(0);
- r8a7778_register_scif(0);
- r8a7778_register_scif(1);
- r8a7778_register_scif(2);
- r8a7778_register_scif(3);
- r8a7778_register_scif(4);
- r8a7778_register_scif(5);
- r8a7778_register_i2c(0);
- r8a7778_register_i2c(1);
- r8a7778_register_i2c(2);
- r8a7778_register_i2c(3);
- r8a7778_register_hspi(0);
- r8a7778_register_hspi(1);
- r8a7778_register_hspi(2);
-
- r8a7778_register_hpb_dmae();
-}
-
-void __init r8a7778_init_late(void)
-{
- shmobile_init_late();
- platform_device_register_full(&ehci_info);
- platform_device_register_full(&ohci_info);
-}
-
-static struct renesas_intc_irqpin_config irqpin_platform_data __initdata = {
- .irq_base = irq_pin(0), /* IRQ0 -> IRQ3 */
- .sense_bitfield_width = 2,
-};
-
-static struct resource irqpin_resources[] __initdata = {
- DEFINE_RES_MEM(0xfe78001c, 4), /* ICR1 */
- DEFINE_RES_MEM(0xfe780010, 4), /* INTPRI */
- DEFINE_RES_MEM(0xfe780024, 4), /* INTREQ */
- DEFINE_RES_MEM(0xfe780044, 4), /* INTMSK0 */
- DEFINE_RES_MEM(0xfe780064, 4), /* INTMSKCLR0 */
- DEFINE_RES_IRQ(gic_iid(0x3b)), /* IRQ0 */
- DEFINE_RES_IRQ(gic_iid(0x3c)), /* IRQ1 */
- DEFINE_RES_IRQ(gic_iid(0x3d)), /* IRQ2 */
- DEFINE_RES_IRQ(gic_iid(0x3e)), /* IRQ3 */
-};
-
-void __init r8a7778_init_irq_extpin_dt(int irlm)
-{
- void __iomem *icr0 = ioremap_nocache(0xfe780000, PAGE_SIZE);
- unsigned long tmp;
-
- if (!icr0) {
- pr_warn("r8a7778: unable to setup external irq pin mode\n");
- return;
- }
-
- tmp = ioread32(icr0);
- if (irlm)
- tmp |= 1 << 23; /* IRQ0 -> IRQ3 as individual pins */
- else
- tmp &= ~(1 << 23); /* IRL mode - not supported */
- tmp |= (1 << 21); /* LVLMODE = 1 */
- iowrite32(tmp, icr0);
- iounmap(icr0);
-}
-
-void __init r8a7778_init_irq_extpin(int irlm)
-{
- r8a7778_init_irq_extpin_dt(irlm);
- if (irlm)
- platform_device_register_resndata(
- NULL, "renesas_intc_irqpin", -1,
- irqpin_resources, ARRAY_SIZE(irqpin_resources),
- &irqpin_platform_data, sizeof(irqpin_platform_data));
-}
-
-#ifdef CONFIG_USE_OF
#define INT2SMSKCR0 0x82288 /* 0xfe782288 */
#define INT2SMSKCR1 0x8228c /* 0xfe78228c */
#define INT2NTSR0 0x00018 /* 0xfe700018 */
#define INT2NTSR1 0x0002c /* 0xfe70002c */
-void __init r8a7778_init_irq_dt(void)
+
+static void __init r8a7778_init_irq_dt(void)
{
void __iomem *base = ioremap_nocache(0xfe700000, 0x00100000);
-#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
- void __iomem *gic_dist_base = ioremap_nocache(0xfe438000, 0x1000);
- void __iomem *gic_cpu_base = ioremap_nocache(0xfe430000, 0x1000);
-#endif
BUG_ON(!base);
-#ifdef CONFIG_ARCH_SHMOBILE_LEGACY
- gic_init(0, 29, gic_dist_base, gic_cpu_base);
-#else
irqchip_init();
-#endif
+
/* route all interrupts to ARM */
__raw_writel(0x73ffffff, base + INT2NTSR0);
__raw_writel(0xffffffff, base + INT2NTSR1);
@@ -624,10 +71,6 @@ DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)")
.init_early = shmobile_init_delay,
.init_irq = r8a7778_init_irq_dt,
.init_late = shmobile_init_late,
-#ifdef CONFIG_COMMON_CLK
.init_time = r8a7778_timer_init,
-#endif
.dt_compat = r8a7778_compat_dt,
MACHINE_END
-
-#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/setup-r8a7793.c b/arch/arm/mach-shmobile/setup-r8a7793.c
index 1d2825c..5fce87f 100644
--- a/arch/arm/mach-shmobile/setup-r8a7793.c
+++ b/arch/arm/mach-shmobile/setup-r8a7793.c
@@ -19,7 +19,7 @@
#include "common.h"
#include "rcar-gen2.h"
-static const char *r8a7793_boards_compat_dt[] __initconst = {
+static const char * const r8a7793_boards_compat_dt[] __initconst = {
"renesas,r8a7793",
NULL,
};
diff --git a/arch/arm/mach-shmobile/sh-gpio.h b/arch/arm/mach-shmobile/sh-gpio.h
deleted file mode 100644
index 2c41414..0000000
--- a/arch/arm/mach-shmobile/sh-gpio.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Generic GPIO API and pinmux table support
- *
- * Copyright (c) 2008 Magnus Damm
- *
- * 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.
- */
-#ifndef __ASM_ARCH_GPIO_H
-#define __ASM_ARCH_GPIO_H
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/io.h>
-
-/*
- * FIXME !!
- *
- * current gpio frame work doesn't have
- * the method to control only pull up/down/free.
- * this function should be replaced by correct gpio function
- */
-static inline void __init gpio_direction_none(void __iomem * addr)
-{
- __raw_writeb(0x00, addr);
-}
-
-#endif /* __ASM_ARCH_GPIO_H */
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index f1d027a..c17d4d3 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -77,24 +77,3 @@ void __init shmobile_init_delay(void)
shmobile_setup_delay_hz(max_freq, 2, 4);
}
}
-
-static void __init shmobile_late_time_init(void)
-{
- /*
- * Make sure all compiled-in early timers register themselves.
- *
- * Run probe() for two "earlytimer" devices, these will be the
- * clockevents and clocksource devices respectively. In the event
- * that only a clockevents device is available, we -ENODEV on the
- * clocksource and the jiffies clocksource is used transparently
- * instead. No error handling is necessary here.
- */
- early_platform_driver_register_all("earlytimer");
- early_platform_driver_probe("earlytimer", 2, 0);
-}
-
-void __init shmobile_earlytimer_init(void)
-{
- late_time_init = shmobile_late_time_init;
-}
-
diff --git a/arch/arm/mach-spear/hotplug.c b/arch/arm/mach-spear/hotplug.c
index d97749c..12edd1c 100644
--- a/arch/arm/mach-spear/hotplug.c
+++ b/arch/arm/mach-spear/hotplug.c
@@ -80,7 +80,7 @@ static inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious)
*
* Called with IRQs disabled
*/
-void __ref spear13xx_cpu_die(unsigned int cpu)
+void spear13xx_cpu_die(unsigned int cpu)
{
int spurious = 0;
diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig
index 125865d..12dd1dc 100644
--- a/arch/arm/mach-sti/Kconfig
+++ b/arch/arm/mach-sti/Kconfig
@@ -3,6 +3,7 @@ menuconfig ARCH_STI
select ARM_GIC
select ST_IRQCHIP
select ARM_GLOBAL_TIMER
+ select CLKSRC_ST_LPC
select PINCTRL
select PINCTRL_ST
select MFD_SYSCON
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index 223c9e9..c2be98f 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -26,10 +26,11 @@ static const char * const sunxi_board_dt_compat[] = {
"allwinner,sun4i-a10",
"allwinner,sun5i-a10s",
"allwinner,sun5i-a13",
+ "allwinner,sun5i-r8",
NULL,
};
-DT_MACHINE_START(SUNXI_DT, "Allwinner A1X (Device Tree)")
+DT_MACHINE_START(SUNXI_DT, "Allwinner sun4i/sun5i Families")
.dt_compat = sunxi_board_dt_compat,
.init_late = sunxi_dt_cpufreq_init,
MACHINE_END
diff --git a/arch/arm/mach-tegra/board-paz00.c b/arch/arm/mach-tegra/board-paz00.c
index fbe74c6..49d1110 100644
--- a/arch/arm/mach-tegra/board-paz00.c
+++ b/arch/arm/mach-tegra/board-paz00.c
@@ -39,8 +39,8 @@ static struct platform_device wifi_rfkill_device = {
static struct gpiod_lookup_table wifi_gpio_lookup = {
.dev_id = "rfkill_gpio",
.table = {
- GPIO_LOOKUP_IDX("tegra-gpio", 25, NULL, 0, 0),
- GPIO_LOOKUP_IDX("tegra-gpio", 85, NULL, 1, 0),
+ GPIO_LOOKUP("tegra-gpio", 25, "reset", 0),
+ GPIO_LOOKUP("tegra-gpio", 85, "shutdown", 0),
{ },
},
};
diff --git a/arch/arm/mach-tegra/hotplug.c b/arch/arm/mach-tegra/hotplug.c
index 6fc71f1..1b12989 100644
--- a/arch/arm/mach-tegra/hotplug.c
+++ b/arch/arm/mach-tegra/hotplug.c
@@ -37,7 +37,7 @@ int tegra_cpu_kill(unsigned cpu)
*
* Called with IRQs disabled
*/
-void __ref tegra_cpu_die(unsigned int cpu)
+void tegra_cpu_die(unsigned int cpu)
{
if (!tegra_hotplug_shutdown) {
WARN(1, "hotplug is not yet initialized\n");
diff --git a/arch/arm/mach-uniphier/Makefile b/arch/arm/mach-uniphier/Makefile
index 60bd226..1233f9b 100644
--- a/arch/arm/mach-uniphier/Makefile
+++ b/arch/arm/mach-uniphier/Makefile
@@ -1,2 +1,2 @@
obj-y := uniphier.o
-obj-$(CONFIG_SMP) += platsmp.o
+obj-$(CONFIG_SMP) += platsmp.o headsmp.o
diff --git a/arch/arm/mach-uniphier/headsmp.S b/arch/arm/mach-uniphier/headsmp.S
new file mode 100644
index 0000000..c819dff
--- /dev/null
+++ b/arch/arm/mach-uniphier/headsmp.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/cp15.h>
+
+ENTRY(uniphier_smp_trampoline)
+ARM_BE8(setend be) @ ensure we are in BE8 mode
+ mrc p15, 0, r0, c0, c0, 5 @ MPIDR (Multiprocessor Affinity Reg)
+ and r2, r0, #0x3 @ CPU ID
+ ldr r1, uniphier_smp_trampoline_jump
+ ldr r3, uniphier_smp_trampoline_poll_addr
+ mrc p15, 0, r0, c1, c0, 0 @ SCTLR (System Control Register)
+ orr r0, r0, #CR_I @ Enable ICache
+ bic r0, r0, #(CR_C | CR_M) @ Disable MMU and Dcache
+ mcr p15, 0, r0, c1, c0, 0
+ b 1f @ cache the following 5 instructions
+0: wfe
+1: ldr r0, [r3]
+ cmp r0, r2
+ bxeq r1 @ branch to secondary_startup
+ b 0b
+ .globl uniphier_smp_trampoline_jump
+uniphier_smp_trampoline_jump:
+ .word 0 @ set virt_to_phys(secondary_startup)
+ .globl uniphier_smp_trampoline_poll_addr
+uniphier_smp_trampoline_poll_addr:
+ .word 0 @ set CPU ID to be kicked to this reg
+ .globl uniphier_smp_trampoline_end
+uniphier_smp_trampoline_end:
+ENDPROC(uniphier_smp_trampoline)
diff --git a/arch/arm/mach-uniphier/platsmp.c b/arch/arm/mach-uniphier/platsmp.c
index 4b784f7..f057766 100644
--- a/arch/arm/mach-uniphier/platsmp.c
+++ b/arch/arm/mach-uniphier/platsmp.c
@@ -12,73 +12,198 @@
* GNU General Public License for more details.
*/
-#include <linux/sizes.h>
-#include <linux/compiler.h>
+#define pr_fmt(fmt) "uniphier: " fmt
+
#include <linux/init.h>
#include <linux/io.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
+#include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/sizes.h>
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-uniphier.h>
+#include <asm/pgtable.h>
#include <asm/smp.h>
#include <asm/smp_scu.h>
-static struct regmap *sbcm_regmap;
+/*
+ * The secondary CPUs check this register from the boot ROM for the jump
+ * destination. After that, it can be reused as a scratch register.
+ */
+#define UNIPHIER_SBC_ROM_BOOT_RSV2 0x1208
-static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
+static void __iomem *uniphier_smp_rom_boot_rsv2;
+static unsigned int uniphier_smp_max_cpus;
+
+extern char uniphier_smp_trampoline;
+extern char uniphier_smp_trampoline_jump;
+extern char uniphier_smp_trampoline_poll_addr;
+extern char uniphier_smp_trampoline_end;
+
+/*
+ * Copy trampoline code to the tail of the 1st section of the page table used
+ * in the boot ROM. This area is directly accessible by the secondary CPUs
+ * for all the UniPhier SoCs.
+ */
+static const phys_addr_t uniphier_smp_trampoline_dest_end = SECTION_SIZE;
+static phys_addr_t uniphier_smp_trampoline_dest;
+
+static int __init uniphier_smp_copy_trampoline(phys_addr_t poll_addr)
{
- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
- unsigned long scu_base_phys = 0;
- void __iomem *scu_base;
+ size_t trmp_size;
+ static void __iomem *trmp_base;
- sbcm_regmap = syscon_regmap_lookup_by_compatible(
- "socionext,uniphier-system-bus-controller-misc");
- if (IS_ERR(sbcm_regmap)) {
- pr_err("failed to regmap system-bus-controller-misc\n");
- goto err;
+ if (!uniphier_cache_l2_is_enabled()) {
+ pr_warn("outer cache is needed for SMP, but not enabled\n");
+ return -ENODEV;
}
+ uniphier_cache_l2_set_locked_ways(1);
+
+ outer_flush_all();
+
+ trmp_size = &uniphier_smp_trampoline_end - &uniphier_smp_trampoline;
+ uniphier_smp_trampoline_dest = uniphier_smp_trampoline_dest_end -
+ trmp_size;
+
+ uniphier_cache_l2_touch_range(uniphier_smp_trampoline_dest,
+ uniphier_smp_trampoline_dest_end);
+
+ trmp_base = ioremap_cache(uniphier_smp_trampoline_dest, trmp_size);
+ if (!trmp_base) {
+ pr_err("failed to map trampoline destination area\n");
+ return -ENOMEM;
+ }
+
+ memcpy(trmp_base, &uniphier_smp_trampoline, trmp_size);
+
+ writel(virt_to_phys(secondary_startup),
+ trmp_base + (&uniphier_smp_trampoline_jump -
+ &uniphier_smp_trampoline));
+
+ writel(poll_addr, trmp_base + (&uniphier_smp_trampoline_poll_addr -
+ &uniphier_smp_trampoline));
+
+ flush_cache_all(); /* flush out trampoline code to outer cache */
+
+ iounmap(trmp_base);
+
+ return 0;
+}
+
+static int __init uniphier_smp_prepare_trampoline(unsigned int max_cpus)
+{
+ struct device_node *np;
+ struct resource res;
+ phys_addr_t rom_rsv2_phys;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL,
+ "socionext,uniphier-system-bus-controller");
+ ret = of_address_to_resource(np, 1, &res);
+ if (ret) {
+ pr_err("failed to get resource of system-bus-controller\n");
+ return ret;
+ }
+
+ rom_rsv2_phys = res.start + UNIPHIER_SBC_ROM_BOOT_RSV2;
+
+ ret = uniphier_smp_copy_trampoline(rom_rsv2_phys);
+ if (ret)
+ return ret;
+
+ uniphier_smp_rom_boot_rsv2 = ioremap(rom_rsv2_phys, sizeof(SZ_4));
+ if (!uniphier_smp_rom_boot_rsv2) {
+ pr_err("failed to map ROM_BOOT_RSV2 register\n");
+ return -ENOMEM;
+ }
+
+ writel(uniphier_smp_trampoline_dest, uniphier_smp_rom_boot_rsv2);
+ asm("sev"); /* Bring up all secondary CPUs to the trampoline code */
+
+ uniphier_smp_max_cpus = max_cpus; /* save for later use */
+
+ return 0;
+}
+
+static void __init uniphier_smp_unprepare_trampoline(void)
+{
+ iounmap(uniphier_smp_rom_boot_rsv2);
+
+ if (uniphier_smp_trampoline_dest)
+ outer_inv_range(uniphier_smp_trampoline_dest,
+ uniphier_smp_trampoline_dest_end);
+
+ uniphier_cache_l2_set_locked_ways(0);
+}
+
+static int __init uniphier_smp_enable_scu(void)
+{
+ unsigned long scu_base_phys = 0;
+ void __iomem *scu_base;
+
if (scu_a9_has_base())
scu_base_phys = scu_a9_get_base();
if (!scu_base_phys) {
pr_err("failed to get scu base\n");
- goto err;
+ return -ENODEV;
}
scu_base = ioremap(scu_base_phys, SZ_128);
if (!scu_base) {
- pr_err("failed to remap scu base (0x%08lx)\n", scu_base_phys);
- goto err;
+ pr_err("failed to map scu base\n");
+ return -ENOMEM;
}
scu_enable(scu_base);
iounmap(scu_base);
+ return 0;
+}
+
+static void __init uniphier_smp_prepare_cpus(unsigned int max_cpus)
+{
+ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
+ int ret;
+
+ ret = uniphier_smp_prepare_trampoline(max_cpus);
+ if (ret)
+ goto err;
+
+ ret = uniphier_smp_enable_scu();
+ if (ret)
+ goto err;
+
return;
err:
pr_warn("disabling SMP\n");
init_cpu_present(&only_cpu_0);
- sbcm_regmap = NULL;
+ uniphier_smp_unprepare_trampoline();
}
-static int uniphier_boot_secondary(unsigned int cpu,
- struct task_struct *idle)
+static int __init uniphier_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
{
- int ret;
+ if (WARN_ON_ONCE(!uniphier_smp_rom_boot_rsv2))
+ return -EFAULT;
- if (!sbcm_regmap)
- return -ENODEV;
+ writel(cpu, uniphier_smp_rom_boot_rsv2);
+ readl(uniphier_smp_rom_boot_rsv2); /* relax */
- ret = regmap_write(sbcm_regmap, 0x1208,
- virt_to_phys(secondary_startup));
- if (!ret)
- asm("sev"); /* wake up secondary CPU */
+ asm("sev"); /* wake up secondary CPUs sleeping in the trampoline */
+
+ if (cpu == uniphier_smp_max_cpus - 1) {
+ /* clean up resources if this is the last CPU */
+ uniphier_smp_unprepare_trampoline();
+ }
- return ret;
+ return 0;
}
-struct smp_operations uniphier_smp_ops __initdata = {
+static struct smp_operations uniphier_smp_ops __initdata = {
.smp_prepare_cpus = uniphier_smp_prepare_cpus,
- .smp_boot_secondary = uniphier_boot_secondary,
+ .smp_boot_secondary = uniphier_smp_boot_secondary,
};
CPU_METHOD_OF_DECLARE(uniphier_smp, "socionext,uniphier-smp",
&uniphier_smp_ops);
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index c9ac19b..5eacdd6 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -32,6 +32,7 @@ config UX500_SOC_DB8500
select PINCTRL_AB8540
select REGULATOR
select REGULATOR_DB8500_PRCMU
+ select CLKSRC_DBX500_PRCMU
select PM_GENERIC_DOMAINS if PM
config MACH_MOP500
diff --git a/arch/arm/mach-ux500/hotplug.c b/arch/arm/mach-ux500/hotplug.c
index 2bc00b0..1cbed03 100644
--- a/arch/arm/mach-ux500/hotplug.c
+++ b/arch/arm/mach-ux500/hotplug.c
@@ -21,7 +21,7 @@
*
* Called with IRQs disabled
*/
-void __ref ux500_cpu_die(unsigned int cpu)
+void ux500_cpu_die(unsigned int cpu)
{
/* directly enter low power state, skipping secure registers */
for (;;) {
diff --git a/arch/arm/mach-vexpress/hotplug.c b/arch/arm/mach-vexpress/hotplug.c
index f0ce6b8..f2fafc1 100644
--- a/arch/arm/mach-vexpress/hotplug.c
+++ b/arch/arm/mach-vexpress/hotplug.c
@@ -85,7 +85,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
*
* Called with IRQs disabled
*/
-void __ref vexpress_cpu_die(unsigned int cpu)
+void vexpress_cpu_die(unsigned int cpu)
{
int spurious = 0;
diff --git a/arch/arm/mach-zx/Kconfig b/arch/arm/mach-zx/Kconfig
index 7fdc5bf..446334a 100644
--- a/arch/arm/mach-zx/Kconfig
+++ b/arch/arm/mach-zx/Kconfig
@@ -13,7 +13,7 @@ config SOC_ZX296702
select ARM_GLOBAL_TIMER
select HAVE_ARM_SCU if SMP
select HAVE_ARM_TWD if SMP
- select PM_GENERIC_DOMAINS
+ select PM_GENERIC_DOMAINS if PM
help
Support for ZTE ZX296702 SoC which is a dual core CortexA9MP
endif
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index c219413..4121886 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -974,6 +974,16 @@ config CACHE_TAUROS2
This option enables the Tauros2 L2 cache controller (as
found on PJ1/PJ4).
+config CACHE_UNIPHIER
+ bool "Enable the UniPhier outer cache controller"
+ depends on ARCH_UNIPHIER
+ default y
+ select OUTER_CACHE
+ select OUTER_CACHE_SYNC
+ help
+ This option enables the UniPhier outer cache (system cache)
+ controller.
+
config CACHE_XSC3L2
bool "Enable the L2 cache on XScale3"
depends on CPU_XSC3
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 57c8df5..7f76d96 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -103,3 +103,4 @@ obj-$(CONFIG_CACHE_FEROCEON_L2) += cache-feroceon-l2.o
obj-$(CONFIG_CACHE_L2X0) += cache-l2x0.o l2c-l2x0-resume.o
obj-$(CONFIG_CACHE_XSC3L2) += cache-xsc3l2.o
obj-$(CONFIG_CACHE_TAUROS2) += cache-tauros2.o
+obj-$(CONFIG_CACHE_UNIPHIER) += cache-uniphier.o
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c
index 493692d..9f9d542 100644
--- a/arch/arm/mm/cache-l2x0.c
+++ b/arch/arm/mm/cache-l2x0.c
@@ -790,7 +790,7 @@ static const struct l2c_init_data l2c310_init_fns __initconst = {
};
static int __init __l2c_init(const struct l2c_init_data *data,
- u32 aux_val, u32 aux_mask, u32 cache_id)
+ u32 aux_val, u32 aux_mask, u32 cache_id, bool nosync)
{
struct outer_cache_fns fns;
unsigned way_size_bits, ways;
@@ -866,6 +866,10 @@ static int __init __l2c_init(const struct l2c_init_data *data,
fns.configure = outer_cache.configure;
if (data->fixup)
data->fixup(l2x0_base, cache_id, &fns);
+ if (nosync) {
+ pr_info("L2C: disabling outer sync\n");
+ fns.sync = NULL;
+ }
/*
* Check if l2x0 controller is already enabled. If we are booting
@@ -925,7 +929,7 @@ void __init l2x0_init(void __iomem *base, u32 aux_val, u32 aux_mask)
if (data->save)
data->save(l2x0_base);
- __l2c_init(data, aux_val, aux_mask, cache_id);
+ __l2c_init(data, aux_val, aux_mask, cache_id, false);
}
#ifdef CONFIG_OF
@@ -1060,6 +1064,18 @@ static void __init l2x0_of_parse(const struct device_node *np,
val |= (dirty - 1) << L2X0_AUX_CTRL_DIRTY_LATENCY_SHIFT;
}
+ if (of_property_read_bool(np, "arm,parity-enable")) {
+ mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+ val |= L2C_AUX_CTRL_PARITY_ENABLE;
+ } else if (of_property_read_bool(np, "arm,parity-disable")) {
+ mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+ }
+
+ if (of_property_read_bool(np, "arm,shared-override")) {
+ mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
+ val |= L2C_AUX_CTRL_SHARED_OVERRIDE;
+ }
+
ret = l2x0_cache_size_of_parse(np, aux_val, aux_mask, &assoc, SZ_256K);
if (ret)
return;
@@ -1176,6 +1192,14 @@ static void __init l2c310_of_parse(const struct device_node *np,
*aux_mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
}
+ if (of_property_read_bool(np, "arm,parity-enable")) {
+ *aux_val |= L2C_AUX_CTRL_PARITY_ENABLE;
+ *aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+ } else if (of_property_read_bool(np, "arm,parity-disable")) {
+ *aux_val &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+ *aux_mask &= ~L2C_AUX_CTRL_PARITY_ENABLE;
+ }
+
prefetch = l2x0_saved_regs.prefetch_ctrl;
ret = of_property_read_u32(np, "arm,double-linefill", &val);
@@ -1704,6 +1728,7 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
struct resource res;
u32 cache_id, old_aux;
u32 cache_level = 2;
+ bool nosync = false;
np = of_find_matching_node(NULL, l2x0_ids);
if (!np)
@@ -1742,6 +1767,8 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
if (cache_level != 2)
pr_err("L2C: device tree specifies invalid cache level\n");
+ nosync = of_property_read_bool(np, "arm,outer-sync-disable");
+
/* Read back current (default) hardware configuration */
if (data->save)
data->save(l2x0_base);
@@ -1756,6 +1783,6 @@ int __init l2x0_of_init(u32 aux_val, u32 aux_mask)
else
cache_id = readl_relaxed(l2x0_base + L2X0_CACHE_ID);
- return __l2c_init(data, aux_val, aux_mask, cache_id);
+ return __l2c_init(data, aux_val, aux_mask, cache_id, nosync);
}
#endif
diff --git a/arch/arm/mm/cache-uniphier.c b/arch/arm/mm/cache-uniphier.c
new file mode 100644
index 0000000..a6fa7b7
--- /dev/null
+++ b/arch/arm/mm/cache-uniphier.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "uniphier: " fmt
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/hardware/cache-uniphier.h>
+#include <asm/outercache.h>
+
+/* control registers */
+#define UNIPHIER_SSCC 0x0 /* Control Register */
+#define UNIPHIER_SSCC_BST BIT(20) /* UCWG burst read */
+#define UNIPHIER_SSCC_ACT BIT(19) /* Inst-Data separate */
+#define UNIPHIER_SSCC_WTG BIT(18) /* WT gathering on */
+#define UNIPHIER_SSCC_PRD BIT(17) /* enable pre-fetch */
+#define UNIPHIER_SSCC_ON BIT(0) /* enable cache */
+#define UNIPHIER_SSCLPDAWCR 0x30 /* Unified/Data Active Way Control */
+#define UNIPHIER_SSCLPIAWCR 0x34 /* Instruction Active Way Control */
+
+/* revision registers */
+#define UNIPHIER_SSCID 0x0 /* ID Register */
+
+/* operation registers */
+#define UNIPHIER_SSCOPE 0x244 /* Cache Operation Primitive Entry */
+#define UNIPHIER_SSCOPE_CM_INV 0x0 /* invalidate */
+#define UNIPHIER_SSCOPE_CM_CLEAN 0x1 /* clean */
+#define UNIPHIER_SSCOPE_CM_FLUSH 0x2 /* flush */
+#define UNIPHIER_SSCOPE_CM_SYNC 0x8 /* sync (drain bufs) */
+#define UNIPHIER_SSCOPE_CM_FLUSH_PREFETCH 0x9 /* flush p-fetch buf */
+#define UNIPHIER_SSCOQM 0x248 /* Cache Operation Queue Mode */
+#define UNIPHIER_SSCOQM_TID_MASK (0x3 << 21)
+#define UNIPHIER_SSCOQM_TID_LRU_DATA (0x0 << 21)
+#define UNIPHIER_SSCOQM_TID_LRU_INST (0x1 << 21)
+#define UNIPHIER_SSCOQM_TID_WAY (0x2 << 21)
+#define UNIPHIER_SSCOQM_S_MASK (0x3 << 17)
+#define UNIPHIER_SSCOQM_S_RANGE (0x0 << 17)
+#define UNIPHIER_SSCOQM_S_ALL (0x1 << 17)
+#define UNIPHIER_SSCOQM_S_WAY (0x2 << 17)
+#define UNIPHIER_SSCOQM_CE BIT(15) /* notify completion */
+#define UNIPHIER_SSCOQM_CM_INV 0x0 /* invalidate */
+#define UNIPHIER_SSCOQM_CM_CLEAN 0x1 /* clean */
+#define UNIPHIER_SSCOQM_CM_FLUSH 0x2 /* flush */
+#define UNIPHIER_SSCOQM_CM_PREFETCH 0x3 /* prefetch to cache */
+#define UNIPHIER_SSCOQM_CM_PREFETCH_BUF 0x4 /* prefetch to pf-buf */
+#define UNIPHIER_SSCOQM_CM_TOUCH 0x5 /* touch */
+#define UNIPHIER_SSCOQM_CM_TOUCH_ZERO 0x6 /* touch to zero */
+#define UNIPHIER_SSCOQM_CM_TOUCH_DIRTY 0x7 /* touch with dirty */
+#define UNIPHIER_SSCOQAD 0x24c /* Cache Operation Queue Address */
+#define UNIPHIER_SSCOQSZ 0x250 /* Cache Operation Queue Size */
+#define UNIPHIER_SSCOQMASK 0x254 /* Cache Operation Queue Address Mask */
+#define UNIPHIER_SSCOQWN 0x258 /* Cache Operation Queue Way Number */
+#define UNIPHIER_SSCOPPQSEF 0x25c /* Cache Operation Queue Set Complete*/
+#define UNIPHIER_SSCOPPQSEF_FE BIT(1)
+#define UNIPHIER_SSCOPPQSEF_OE BIT(0)
+#define UNIPHIER_SSCOLPQS 0x260 /* Cache Operation Queue Status */
+#define UNIPHIER_SSCOLPQS_EF BIT(2)
+#define UNIPHIER_SSCOLPQS_EST BIT(1)
+#define UNIPHIER_SSCOLPQS_QST BIT(0)
+
+/* Is the touch/pre-fetch destination specified by ways? */
+#define UNIPHIER_SSCOQM_TID_IS_WAY(op) \
+ ((op & UNIPHIER_SSCOQM_TID_MASK) == UNIPHIER_SSCOQM_TID_WAY)
+/* Is the operation region specified by address range? */
+#define UNIPHIER_SSCOQM_S_IS_RANGE(op) \
+ ((op & UNIPHIER_SSCOQM_S_MASK) == UNIPHIER_SSCOQM_S_RANGE)
+
+/**
+ * uniphier_cache_data - UniPhier outer cache specific data
+ *
+ * @ctrl_base: virtual base address of control registers
+ * @rev_base: virtual base address of revision registers
+ * @op_base: virtual base address of operation registers
+ * @way_present_mask: each bit specifies if the way is present
+ * @way_locked_mask: each bit specifies if the way is locked
+ * @nsets: number of associativity sets
+ * @line_size: line size in bytes
+ * @range_op_max_size: max size that can be handled by a single range operation
+ * @list: list node to include this level in the whole cache hierarchy
+ */
+struct uniphier_cache_data {
+ void __iomem *ctrl_base;
+ void __iomem *rev_base;
+ void __iomem *op_base;
+ u32 way_present_mask;
+ u32 way_locked_mask;
+ u32 nsets;
+ u32 line_size;
+ u32 range_op_max_size;
+ struct list_head list;
+};
+
+/*
+ * List of the whole outer cache hierarchy. This list is only modified during
+ * the early boot stage, so no mutex is taken for the access to the list.
+ */
+static LIST_HEAD(uniphier_cache_list);
+
+/**
+ * __uniphier_cache_sync - perform a sync point for a particular cache level
+ *
+ * @data: cache controller specific data
+ */
+static void __uniphier_cache_sync(struct uniphier_cache_data *data)
+{
+ /* This sequence need not be atomic. Do not disable IRQ. */
+ writel_relaxed(UNIPHIER_SSCOPE_CM_SYNC,
+ data->op_base + UNIPHIER_SSCOPE);
+ /* need a read back to confirm */
+ readl_relaxed(data->op_base + UNIPHIER_SSCOPE);
+}
+
+/**
+ * __uniphier_cache_maint_common - run a queue operation for a particular level
+ *
+ * @data: cache controller specific data
+ * @start: start address of range operation (don't care for "all" operation)
+ * @size: data size of range operation (don't care for "all" operation)
+ * @operation: flags to specify the desired cache operation
+ */
+static void __uniphier_cache_maint_common(struct uniphier_cache_data *data,
+ unsigned long start,
+ unsigned long size,
+ u32 operation)
+{
+ unsigned long flags;
+
+ /*
+ * No spin lock is necessary here because:
+ *
+ * [1] This outer cache controller is able to accept maintenance
+ * operations from multiple CPUs at a time in an SMP system; if a
+ * maintenance operation is under way and another operation is issued,
+ * the new one is stored in the queue. The controller performs one
+ * operation after another. If the queue is full, the status register,
+ * UNIPHIER_SSCOPPQSEF, indicates that the queue registration has
+ * failed. The status registers, UNIPHIER_{SSCOPPQSEF, SSCOLPQS}, have
+ * different instances for each CPU, i.e. each CPU can track the status
+ * of the maintenance operations triggered by itself.
+ *
+ * [2] The cache command registers, UNIPHIER_{SSCOQM, SSCOQAD, SSCOQSZ,
+ * SSCOQWN}, are shared between multiple CPUs, but the hardware still
+ * guarantees the registration sequence is atomic; the write access to
+ * them are arbitrated by the hardware. The first accessor to the
+ * register, UNIPHIER_SSCOQM, holds the access right and it is released
+ * by reading the status register, UNIPHIER_SSCOPPQSEF. While one CPU
+ * is holding the access right, other CPUs fail to register operations.
+ * One CPU should not hold the access right for a long time, so local
+ * IRQs should be disabled while the following sequence.
+ */
+ local_irq_save(flags);
+
+ /* clear the complete notification flag */
+ writel_relaxed(UNIPHIER_SSCOLPQS_EF, data->op_base + UNIPHIER_SSCOLPQS);
+
+ do {
+ /* set cache operation */
+ writel_relaxed(UNIPHIER_SSCOQM_CE | operation,
+ data->op_base + UNIPHIER_SSCOQM);
+
+ /* set address range if needed */
+ if (likely(UNIPHIER_SSCOQM_S_IS_RANGE(operation))) {
+ writel_relaxed(start, data->op_base + UNIPHIER_SSCOQAD);
+ writel_relaxed(size, data->op_base + UNIPHIER_SSCOQSZ);
+ }
+
+ /* set target ways if needed */
+ if (unlikely(UNIPHIER_SSCOQM_TID_IS_WAY(operation)))
+ writel_relaxed(data->way_locked_mask,
+ data->op_base + UNIPHIER_SSCOQWN);
+ } while (unlikely(readl_relaxed(data->op_base + UNIPHIER_SSCOPPQSEF) &
+ (UNIPHIER_SSCOPPQSEF_FE | UNIPHIER_SSCOPPQSEF_OE)));
+
+ /* wait until the operation is completed */
+ while (likely(readl_relaxed(data->op_base + UNIPHIER_SSCOLPQS) !=
+ UNIPHIER_SSCOLPQS_EF))
+ cpu_relax();
+
+ local_irq_restore(flags);
+}
+
+static void __uniphier_cache_maint_all(struct uniphier_cache_data *data,
+ u32 operation)
+{
+ __uniphier_cache_maint_common(data, 0, 0,
+ UNIPHIER_SSCOQM_S_ALL | operation);
+
+ __uniphier_cache_sync(data);
+}
+
+static void __uniphier_cache_maint_range(struct uniphier_cache_data *data,
+ unsigned long start, unsigned long end,
+ u32 operation)
+{
+ unsigned long size;
+
+ /*
+ * If the start address is not aligned,
+ * perform a cache operation for the first cache-line
+ */
+ start = start & ~(data->line_size - 1);
+
+ size = end - start;
+
+ if (unlikely(size >= (unsigned long)(-data->line_size))) {
+ /* this means cache operation for all range */
+ __uniphier_cache_maint_all(data, operation);
+ return;
+ }
+
+ /*
+ * If the end address is not aligned,
+ * perform a cache operation for the last cache-line
+ */
+ size = ALIGN(size, data->line_size);
+
+ while (size) {
+ unsigned long chunk_size = min_t(unsigned long, size,
+ data->range_op_max_size);
+
+ __uniphier_cache_maint_common(data, start, chunk_size,
+ UNIPHIER_SSCOQM_S_RANGE | operation);
+
+ start += chunk_size;
+ size -= chunk_size;
+ }
+
+ __uniphier_cache_sync(data);
+}
+
+static void __uniphier_cache_enable(struct uniphier_cache_data *data, bool on)
+{
+ u32 val = 0;
+
+ if (on)
+ val = UNIPHIER_SSCC_WTG | UNIPHIER_SSCC_PRD | UNIPHIER_SSCC_ON;
+
+ writel_relaxed(val, data->ctrl_base + UNIPHIER_SSCC);
+}
+
+static void __init __uniphier_cache_set_locked_ways(
+ struct uniphier_cache_data *data,
+ u32 way_mask)
+{
+ data->way_locked_mask = way_mask & data->way_present_mask;
+
+ writel_relaxed(~data->way_locked_mask & data->way_present_mask,
+ data->ctrl_base + UNIPHIER_SSCLPDAWCR);
+}
+
+static void uniphier_cache_maint_range(unsigned long start, unsigned long end,
+ u32 operation)
+{
+ struct uniphier_cache_data *data;
+
+ list_for_each_entry(data, &uniphier_cache_list, list)
+ __uniphier_cache_maint_range(data, start, end, operation);
+}
+
+static void uniphier_cache_maint_all(u32 operation)
+{
+ struct uniphier_cache_data *data;
+
+ list_for_each_entry(data, &uniphier_cache_list, list)
+ __uniphier_cache_maint_all(data, operation);
+}
+
+static void uniphier_cache_inv_range(unsigned long start, unsigned long end)
+{
+ uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_INV);
+}
+
+static void uniphier_cache_clean_range(unsigned long start, unsigned long end)
+{
+ uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_CLEAN);
+}
+
+static void uniphier_cache_flush_range(unsigned long start, unsigned long end)
+{
+ uniphier_cache_maint_range(start, end, UNIPHIER_SSCOQM_CM_FLUSH);
+}
+
+static void __init uniphier_cache_inv_all(void)
+{
+ uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_INV);
+}
+
+static void uniphier_cache_flush_all(void)
+{
+ uniphier_cache_maint_all(UNIPHIER_SSCOQM_CM_FLUSH);
+}
+
+static void uniphier_cache_disable(void)
+{
+ struct uniphier_cache_data *data;
+
+ list_for_each_entry_reverse(data, &uniphier_cache_list, list)
+ __uniphier_cache_enable(data, false);
+
+ uniphier_cache_flush_all();
+}
+
+static void __init uniphier_cache_enable(void)
+{
+ struct uniphier_cache_data *data;
+
+ uniphier_cache_inv_all();
+
+ list_for_each_entry(data, &uniphier_cache_list, list) {
+ __uniphier_cache_enable(data, true);
+ __uniphier_cache_set_locked_ways(data, 0);
+ }
+}
+
+static void uniphier_cache_sync(void)
+{
+ struct uniphier_cache_data *data;
+
+ list_for_each_entry(data, &uniphier_cache_list, list)
+ __uniphier_cache_sync(data);
+}
+
+int __init uniphier_cache_l2_is_enabled(void)
+{
+ struct uniphier_cache_data *data;
+
+ data = list_first_entry_or_null(&uniphier_cache_list,
+ struct uniphier_cache_data, list);
+ if (!data)
+ return 0;
+
+ return !!(readl_relaxed(data->ctrl_base + UNIPHIER_SSCC) &
+ UNIPHIER_SSCC_ON);
+}
+
+void __init uniphier_cache_l2_touch_range(unsigned long start,
+ unsigned long end)
+{
+ struct uniphier_cache_data *data;
+
+ data = list_first_entry_or_null(&uniphier_cache_list,
+ struct uniphier_cache_data, list);
+ if (data)
+ __uniphier_cache_maint_range(data, start, end,
+ UNIPHIER_SSCOQM_TID_WAY |
+ UNIPHIER_SSCOQM_CM_TOUCH);
+}
+
+void __init uniphier_cache_l2_set_locked_ways(u32 way_mask)
+{
+ struct uniphier_cache_data *data;
+
+ data = list_first_entry_or_null(&uniphier_cache_list,
+ struct uniphier_cache_data, list);
+ if (data)
+ __uniphier_cache_set_locked_ways(data, way_mask);
+}
+
+static const struct of_device_id uniphier_cache_match[] __initconst = {
+ {
+ .compatible = "socionext,uniphier-system-cache",
+ },
+ { /* sentinel */ }
+};
+
+static int __init __uniphier_cache_init(struct device_node *np,
+ unsigned int *cache_level)
+{
+ struct uniphier_cache_data *data;
+ u32 level, cache_size;
+ struct device_node *next_np;
+ int ret = 0;
+
+ if (!of_match_node(uniphier_cache_match, np)) {
+ pr_err("L%d: not compatible with uniphier cache\n",
+ *cache_level);
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "cache-level", &level)) {
+ pr_err("L%d: cache-level is not specified\n", *cache_level);
+ return -EINVAL;
+ }
+
+ if (level != *cache_level) {
+ pr_err("L%d: cache-level is unexpected value %d\n",
+ *cache_level, level);
+ return -EINVAL;
+ }
+
+ if (!of_property_read_bool(np, "cache-unified")) {
+ pr_err("L%d: cache-unified is not specified\n", *cache_level);
+ return -EINVAL;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "cache-line-size", &data->line_size) ||
+ !is_power_of_2(data->line_size)) {
+ pr_err("L%d: cache-line-size is unspecified or invalid\n",
+ *cache_level);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (of_property_read_u32(np, "cache-sets", &data->nsets) ||
+ !is_power_of_2(data->nsets)) {
+ pr_err("L%d: cache-sets is unspecified or invalid\n",
+ *cache_level);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (of_property_read_u32(np, "cache-size", &cache_size) ||
+ cache_size == 0 || cache_size % (data->nsets * data->line_size)) {
+ pr_err("L%d: cache-size is unspecified or invalid\n",
+ *cache_level);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ data->way_present_mask =
+ ((u32)1 << cache_size / data->nsets / data->line_size) - 1;
+
+ data->ctrl_base = of_iomap(np, 0);
+ if (!data->ctrl_base) {
+ pr_err("L%d: failed to map control register\n", *cache_level);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ data->rev_base = of_iomap(np, 1);
+ if (!data->rev_base) {
+ pr_err("L%d: failed to map revision register\n", *cache_level);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ data->op_base = of_iomap(np, 2);
+ if (!data->op_base) {
+ pr_err("L%d: failed to map operation register\n", *cache_level);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ if (*cache_level == 2) {
+ u32 revision = readl(data->rev_base + UNIPHIER_SSCID);
+ /*
+ * The size of range operation is limited to (1 << 22) or less
+ * for PH-sLD8 or older SoCs.
+ */
+ if (revision <= 0x16)
+ data->range_op_max_size = (u32)1 << 22;
+ }
+
+ data->range_op_max_size -= data->line_size;
+
+ INIT_LIST_HEAD(&data->list);
+ list_add_tail(&data->list, &uniphier_cache_list); /* no mutex */
+
+ /*
+ * OK, this level has been successfully initialized. Look for the next
+ * level cache. Do not roll back even if the initialization of the
+ * next level cache fails because we want to continue with available
+ * cache levels.
+ */
+ next_np = of_find_next_cache_node(np);
+ if (next_np) {
+ (*cache_level)++;
+ ret = __uniphier_cache_init(next_np, cache_level);
+ }
+ of_node_put(next_np);
+
+ return ret;
+err:
+ iounmap(data->op_base);
+ iounmap(data->rev_base);
+ iounmap(data->ctrl_base);
+ kfree(data);
+
+ return ret;
+}
+
+int __init uniphier_cache_init(void)
+{
+ struct device_node *np = NULL;
+ unsigned int cache_level;
+ int ret = 0;
+
+ /* look for level 2 cache */
+ while ((np = of_find_matching_node(np, uniphier_cache_match)))
+ if (!of_property_read_u32(np, "cache-level", &cache_level) &&
+ cache_level == 2)
+ break;
+
+ if (!np)
+ return -ENODEV;
+
+ ret = __uniphier_cache_init(np, &cache_level);
+ of_node_put(np);
+
+ if (ret) {
+ /*
+ * Error out iif L2 initialization fails. Continue with any
+ * error on L3 or outer because they are optional.
+ */
+ if (cache_level == 2) {
+ pr_err("failed to initialize L2 cache\n");
+ return ret;
+ }
+
+ cache_level--;
+ ret = 0;
+ }
+
+ outer_cache.inv_range = uniphier_cache_inv_range;
+ outer_cache.clean_range = uniphier_cache_clean_range;
+ outer_cache.flush_range = uniphier_cache_flush_range;
+ outer_cache.flush_all = uniphier_cache_flush_all;
+ outer_cache.disable = uniphier_cache_disable;
+ outer_cache.sync = uniphier_cache_sync;
+
+ uniphier_cache_enable();
+
+ pr_info("enabled outer cache (cache level: %d)\n", cache_level);
+
+ return ret;
+}
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 845769e..c8c8b9e 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -165,13 +165,28 @@ static void flush_context(unsigned int cpu)
__flush_icache_all();
}
-static int is_reserved_asid(u64 asid)
+static bool check_update_reserved_asid(u64 asid, u64 newasid)
{
int cpu;
- for_each_possible_cpu(cpu)
- if (per_cpu(reserved_asids, cpu) == asid)
- return 1;
- return 0;
+ bool hit = false;
+
+ /*
+ * Iterate over the set of reserved ASIDs looking for a match.
+ * If we find one, then we can update our mm to use newasid
+ * (i.e. the same ASID in the current generation) but we can't
+ * exit the loop early, since we need to ensure that all copies
+ * of the old ASID are updated to reflect the mm. Failure to do
+ * so could result in us missing the reserved ASID in a future
+ * generation.
+ */
+ for_each_possible_cpu(cpu) {
+ if (per_cpu(reserved_asids, cpu) == asid) {
+ hit = true;
+ per_cpu(reserved_asids, cpu) = newasid;
+ }
+ }
+
+ return hit;
}
static u64 new_context(struct mm_struct *mm, unsigned int cpu)
@@ -181,12 +196,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
u64 generation = atomic64_read(&asid_generation);
if (asid != 0) {
+ u64 newasid = generation | (asid & ~ASID_MASK);
+
/*
* If our current ASID was active during a rollover, we
* can continue to use it and this was just a false alarm.
*/
- if (is_reserved_asid(asid))
- return generation | (asid & ~ASID_MASK);
+ if (check_update_reserved_asid(asid, newasid))
+ return newasid;
/*
* We had a valid ASID in a previous life, so try to re-use
@@ -194,7 +211,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
*/
asid &= ~ASID_MASK;
if (!__test_and_set_bit(asid, asid_map))
- goto bump_gen;
+ return newasid;
}
/*
@@ -216,11 +233,8 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
__set_bit(asid, asid_map);
cur_idx = asid;
-
-bump_gen:
- asid |= generation;
cpumask_clear(mm_cpumask(mm));
- return asid;
+ return asid | generation;
}
void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk)
diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index e62400e..534a60a 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -1521,7 +1521,7 @@ static int __map_sg_chunk(struct device *dev, struct scatterlist *sg,
return -ENOMEM;
for (count = 0, s = sg; count < (size >> PAGE_SHIFT); s = sg_next(s)) {
- phys_addr_t phys = sg_phys(s) & PAGE_MASK;
+ phys_addr_t phys = page_to_phys(sg_page(s));
unsigned int len = PAGE_ALIGN(s->offset + s->length);
if (!is_coherent &&
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 8a63b4c..49bd081 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -22,6 +22,7 @@
#include <linux/memblock.h>
#include <linux/dma-contiguous.h>
#include <linux/sizes.h>
+#include <linux/stop_machine.h>
#include <asm/cp15.h>
#include <asm/mach-types.h>
@@ -191,7 +192,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low,
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
int pfn_valid(unsigned long pfn)
{
- return memblock_is_memory(__pfn_to_phys(pfn));
+ return memblock_is_map_memory(__pfn_to_phys(pfn));
}
EXPORT_SYMBOL(pfn_valid);
#endif
@@ -432,6 +433,9 @@ static void __init free_highpages(void)
if (end <= max_low)
continue;
+ if (memblock_is_nomap(mem))
+ continue;
+
/* Truncate partial highmem entries */
if (start < max_low)
start = max_low;
@@ -627,12 +631,10 @@ static struct section_perm ro_perms[] = {
* safe to be called with preemption disabled, as under stop_machine().
*/
static inline void section_update(unsigned long addr, pmdval_t mask,
- pmdval_t prot)
+ pmdval_t prot, struct mm_struct *mm)
{
- struct mm_struct *mm;
pmd_t *pmd;
- mm = current->active_mm;
pmd = pmd_offset(pud_offset(pgd_offset(mm, addr), addr), addr);
#ifdef CONFIG_ARM_LPAE
@@ -656,49 +658,82 @@ static inline bool arch_has_strict_perms(void)
return !!(get_cr() & CR_XP);
}
-#define set_section_perms(perms, field) { \
- size_t i; \
- unsigned long addr; \
- \
- if (!arch_has_strict_perms()) \
- return; \
- \
- for (i = 0; i < ARRAY_SIZE(perms); i++) { \
- if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) || \
- !IS_ALIGNED(perms[i].end, SECTION_SIZE)) { \
- pr_err("BUG: section %lx-%lx not aligned to %lx\n", \
- perms[i].start, perms[i].end, \
- SECTION_SIZE); \
- continue; \
- } \
- \
- for (addr = perms[i].start; \
- addr < perms[i].end; \
- addr += SECTION_SIZE) \
- section_update(addr, perms[i].mask, \
- perms[i].field); \
- } \
+void set_section_perms(struct section_perm *perms, int n, bool set,
+ struct mm_struct *mm)
+{
+ size_t i;
+ unsigned long addr;
+
+ if (!arch_has_strict_perms())
+ return;
+
+ for (i = 0; i < n; i++) {
+ if (!IS_ALIGNED(perms[i].start, SECTION_SIZE) ||
+ !IS_ALIGNED(perms[i].end, SECTION_SIZE)) {
+ pr_err("BUG: section %lx-%lx not aligned to %lx\n",
+ perms[i].start, perms[i].end,
+ SECTION_SIZE);
+ continue;
+ }
+
+ for (addr = perms[i].start;
+ addr < perms[i].end;
+ addr += SECTION_SIZE)
+ section_update(addr, perms[i].mask,
+ set ? perms[i].prot : perms[i].clear, mm);
+ }
+
}
-static inline void fix_kernmem_perms(void)
+static void update_sections_early(struct section_perm perms[], int n)
{
- set_section_perms(nx_perms, prot);
+ struct task_struct *t, *s;
+
+ read_lock(&tasklist_lock);
+ for_each_process(t) {
+ if (t->flags & PF_KTHREAD)
+ continue;
+ for_each_thread(t, s)
+ set_section_perms(perms, n, true, s->mm);
+ }
+ read_unlock(&tasklist_lock);
+ set_section_perms(perms, n, true, current->active_mm);
+ set_section_perms(perms, n, true, &init_mm);
+}
+
+int __fix_kernmem_perms(void *unused)
+{
+ update_sections_early(nx_perms, ARRAY_SIZE(nx_perms));
+ return 0;
+}
+
+void fix_kernmem_perms(void)
+{
+ stop_machine(__fix_kernmem_perms, NULL, NULL);
}
#ifdef CONFIG_DEBUG_RODATA
+int __mark_rodata_ro(void *unused)
+{
+ update_sections_early(ro_perms, ARRAY_SIZE(ro_perms));
+ return 0;
+}
+
void mark_rodata_ro(void)
{
- set_section_perms(ro_perms, prot);
+ stop_machine(__mark_rodata_ro, NULL, NULL);
}
void set_kernel_text_rw(void)
{
- set_section_perms(ro_perms, clear);
+ set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), false,
+ current->active_mm);
}
void set_kernel_text_ro(void)
{
- set_section_perms(ro_perms, prot);
+ set_section_perms(ro_perms, ARRAY_SIZE(ro_perms), true,
+ current->active_mm);
}
#endif /* CONFIG_DEBUG_RODATA */
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 0c81056..66a978d 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -30,6 +30,7 @@
#include <asm/cp15.h>
#include <asm/cputype.h>
#include <asm/cacheflush.h>
+#include <asm/early_ioremap.h>
#include <asm/mmu_context.h>
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
@@ -469,3 +470,11 @@ int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr)
}
EXPORT_SYMBOL_GPL(pci_ioremap_io);
#endif
+
+/*
+ * Must be called after early_fixmap_init
+ */
+void __init early_ioremap_init(void)
+{
+ early_ioremap_setup();
+}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4867f5d..a87f6cc 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -390,7 +390,7 @@ void __init early_fixmap_init(void)
* The early fixmap range spans multiple pmds, for which
* we are not prepared:
*/
- BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT)
+ BUILD_BUG_ON((__fix_to_virt(__end_of_early_ioremap_region) >> PMD_SHIFT)
!= FIXADDR_TOP >> PMD_SHIFT);
pmd = fixmap_pmd(FIXADDR_TOP);
@@ -572,7 +572,7 @@ static void __init build_mem_type_table(void)
* in the Short-descriptor translation table format descriptors.
*/
if (cpu_arch == CPU_ARCH_ARMv7 &&
- (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) == 4) {
+ (read_cpuid_ext(CPUID_EXT_MMFR0) & 0xF) >= 4) {
user_pmd_table |= PMD_PXNTABLE;
}
#endif
@@ -724,30 +724,49 @@ static void __init *early_alloc(unsigned long sz)
return early_alloc_aligned(sz, sz);
}
-static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot)
+static void *__init late_alloc(unsigned long sz)
+{
+ void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz));
+
+ BUG_ON(!ptr);
+ return ptr;
+}
+
+static pte_t * __init pte_alloc(pmd_t *pmd, unsigned long addr,
+ unsigned long prot,
+ void *(*alloc)(unsigned long sz))
{
if (pmd_none(*pmd)) {
- pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
+ pte_t *pte = alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE);
__pmd_populate(pmd, __pa(pte), prot);
}
BUG_ON(pmd_bad(*pmd));
return pte_offset_kernel(pmd, addr);
}
+static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr,
+ unsigned long prot)
+{
+ return pte_alloc(pmd, addr, prot, early_alloc);
+}
+
static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr,
unsigned long end, unsigned long pfn,
- const struct mem_type *type)
+ const struct mem_type *type,
+ void *(*alloc)(unsigned long sz),
+ bool ng)
{
- pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1);
+ pte_t *pte = pte_alloc(pmd, addr, type->prot_l1, alloc);
do {
- set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0);
+ set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)),
+ ng ? PTE_EXT_NG : 0);
pfn++;
} while (pte++, addr += PAGE_SIZE, addr != end);
}
static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
unsigned long end, phys_addr_t phys,
- const struct mem_type *type)
+ const struct mem_type *type, bool ng)
{
pmd_t *p = pmd;
@@ -765,7 +784,7 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
pmd++;
#endif
do {
- *pmd = __pmd(phys | type->prot_sect);
+ *pmd = __pmd(phys | type->prot_sect | (ng ? PMD_SECT_nG : 0));
phys += SECTION_SIZE;
} while (pmd++, addr += SECTION_SIZE, addr != end);
@@ -774,7 +793,8 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr,
static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
unsigned long end, phys_addr_t phys,
- const struct mem_type *type)
+ const struct mem_type *type,
+ void *(*alloc)(unsigned long sz), bool ng)
{
pmd_t *pmd = pmd_offset(pud, addr);
unsigned long next;
@@ -792,10 +812,10 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
*/
if (type->prot_sect &&
((addr | next | phys) & ~SECTION_MASK) == 0) {
- __map_init_section(pmd, addr, next, phys, type);
+ __map_init_section(pmd, addr, next, phys, type, ng);
} else {
alloc_init_pte(pmd, addr, next,
- __phys_to_pfn(phys), type);
+ __phys_to_pfn(phys), type, alloc, ng);
}
phys += next - addr;
@@ -805,21 +825,24 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr,
static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
unsigned long end, phys_addr_t phys,
- const struct mem_type *type)
+ const struct mem_type *type,
+ void *(*alloc)(unsigned long sz), bool ng)
{
pud_t *pud = pud_offset(pgd, addr);
unsigned long next;
do {
next = pud_addr_end(addr, end);
- alloc_init_pmd(pud, addr, next, phys, type);
+ alloc_init_pmd(pud, addr, next, phys, type, alloc, ng);
phys += next - addr;
} while (pud++, addr = next, addr != end);
}
#ifndef CONFIG_ARM_LPAE
-static void __init create_36bit_mapping(struct map_desc *md,
- const struct mem_type *type)
+static void __init create_36bit_mapping(struct mm_struct *mm,
+ struct map_desc *md,
+ const struct mem_type *type,
+ bool ng)
{
unsigned long addr, length, end;
phys_addr_t phys;
@@ -859,7 +882,7 @@ static void __init create_36bit_mapping(struct map_desc *md,
*/
phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
- pgd = pgd_offset_k(addr);
+ pgd = pgd_offset(mm, addr);
end = addr + length;
do {
pud_t *pud = pud_offset(pgd, addr);
@@ -867,7 +890,8 @@ static void __init create_36bit_mapping(struct map_desc *md,
int i;
for (i = 0; i < 16; i++)
- *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER);
+ *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER |
+ (ng ? PMD_SECT_nG : 0));
addr += SUPERSECTION_SIZE;
phys += SUPERSECTION_SIZE;
@@ -876,33 +900,15 @@ static void __init create_36bit_mapping(struct map_desc *md,
}
#endif /* !CONFIG_ARM_LPAE */
-/*
- * Create the page directory entries and any necessary
- * page tables for the mapping specified by `md'. We
- * are able to cope here with varying sizes and address
- * offsets, and we take full advantage of sections and
- * supersections.
- */
-static void __init create_mapping(struct map_desc *md)
+static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md,
+ void *(*alloc)(unsigned long sz),
+ bool ng)
{
unsigned long addr, length, end;
phys_addr_t phys;
const struct mem_type *type;
pgd_t *pgd;
- if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
- pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
- (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
-
- if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
- md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
- (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
- pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
- (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
- }
-
type = &mem_types[md->type];
#ifndef CONFIG_ARM_LPAE
@@ -910,7 +916,7 @@ static void __init create_mapping(struct map_desc *md)
* Catch 36-bit addresses
*/
if (md->pfn >= 0x100000) {
- create_36bit_mapping(md, type);
+ create_36bit_mapping(mm, md, type, ng);
return;
}
#endif
@@ -925,12 +931,12 @@ static void __init create_mapping(struct map_desc *md)
return;
}
- pgd = pgd_offset_k(addr);
+ pgd = pgd_offset(mm, addr);
end = addr + length;
do {
unsigned long next = pgd_addr_end(addr, end);
- alloc_init_pud(pgd, addr, next, phys, type);
+ alloc_init_pud(pgd, addr, next, phys, type, alloc, ng);
phys += next - addr;
addr = next;
@@ -938,6 +944,43 @@ static void __init create_mapping(struct map_desc *md)
}
/*
+ * Create the page directory entries and any necessary
+ * page tables for the mapping specified by `md'. We
+ * are able to cope here with varying sizes and address
+ * offsets, and we take full advantage of sections and
+ * supersections.
+ */
+static void __init create_mapping(struct map_desc *md)
+{
+ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+ pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n",
+ (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+
+ if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+ md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START &&
+ (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) {
+ pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n",
+ (long long)__pfn_to_phys((u64)md->pfn), md->virtual);
+ }
+
+ __create_mapping(&init_mm, md, early_alloc, false);
+}
+
+void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md,
+ bool ng)
+{
+#ifdef CONFIG_ARM_LPAE
+ pud_t *pud = pud_alloc(mm, pgd_offset(mm, md->virtual), md->virtual);
+ if (WARN_ON(!pud))
+ return;
+ pmd_alloc(mm, pud, 0);
+#endif
+ __create_mapping(mm, md, late_alloc, ng);
+}
+
+/*
* Create the architecture specific mappings
*/
void __init iotable_init(struct map_desc *io_desc, int nr)
@@ -1392,6 +1435,9 @@ static void __init map_lowmem(void)
phys_addr_t end = start + reg->size;
struct map_desc map;
+ if (memblock_is_nomap(reg))
+ continue;
+
if (end > arm_lowmem_limit)
end = arm_lowmem_limit;
if (start >= end)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index de2b246..0f92d57 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -95,7 +95,7 @@ ENDPROC(cpu_v7_dcache_clean_area)
.equ cpu_v7_suspend_size, 4 * 9
#ifdef CONFIG_ARM_CPU_SUSPEND
ENTRY(cpu_v7_do_suspend)
- stmfd sp!, {r4 - r10, lr}
+ stmfd sp!, {r4 - r11, lr}
mrc p15, 0, r4, c13, c0, 0 @ FCSE/PID
mrc p15, 0, r5, c13, c0, 3 @ User r/o thread ID
stmia r0!, {r4 - r5}
@@ -112,7 +112,7 @@ ENTRY(cpu_v7_do_suspend)
mrc p15, 0, r9, c1, c0, 1 @ Auxiliary control register
mrc p15, 0, r10, c1, c0, 2 @ Co-processor access control
stmia r0, {r5 - r11}
- ldmfd sp!, {r4 - r10, pc}
+ ldmfd sp!, {r4 - r11, pc}
ENDPROC(cpu_v7_do_suspend)
ENTRY(cpu_v7_do_resume)
@@ -274,10 +274,12 @@ __v7_ca15mp_setup:
__v7_b15mp_setup:
__v7_ca17mp_setup:
mov r10, #0
-1: adr r12, __v7_setup_stack @ the local stack
- stmia r12, {r0-r5, lr} @ v7_invalidate_l1 touches r0-r6
+1: adr r0, __v7_setup_stack_ptr
+ ldr r12, [r0]
+ add r12, r12, r0 @ the local stack
+ stmia r12, {r1-r6, lr} @ v7_invalidate_l1 touches r0-r6
bl v7_invalidate_l1
- ldmia r12, {r0-r5, lr}
+ ldmia r12, {r1-r6, lr}
#ifdef CONFIG_SMP
ALT_SMP(mrc p15, 0, r0, c1, c0, 1)
ALT_UP(mov r0, #(1 << 6)) @ fake it for UP
@@ -415,10 +417,12 @@ __v7_pj4b_setup:
#endif /* CONFIG_CPU_PJ4B */
__v7_setup:
- adr r12, __v7_setup_stack @ the local stack
- stmia r12, {r0-r5, lr} @ v7_invalidate_l1 touches r0-r6
+ adr r0, __v7_setup_stack_ptr
+ ldr r12, [r0]
+ add r12, r12, r0 @ the local stack
+ stmia r12, {r1-r6, lr} @ v7_invalidate_l1 touches r0-r6
bl v7_invalidate_l1
- ldmia r12, {r0-r5, lr}
+ ldmia r12, {r1-r6, lr}
__v7_setup_cont:
and r0, r9, #0xff000000 @ ARM?
@@ -480,11 +484,16 @@ __errata_finish:
orr r0, r0, r6 @ set them
THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions
ret lr @ return to head.S:__ret
+
+ .align 2
+__v7_setup_stack_ptr:
+ .word __v7_setup_stack - .
ENDPROC(__v7_setup)
+ .bss
.align 2
__v7_setup_stack:
- .space 4 * 7 @ 12 registers
+ .space 4 * 7 @ 7 registers
__INITDATA
diff --git a/arch/arm/mm/proc-v7m.S b/arch/arm/mm/proc-v7m.S
index 67d9209..7229d8d 100644
--- a/arch/arm/mm/proc-v7m.S
+++ b/arch/arm/mm/proc-v7m.S
@@ -12,6 +12,7 @@
*/
#include <linux/linkage.h>
#include <asm/assembler.h>
+#include <asm/memory.h>
#include <asm/v7m.h>
#include "proc-macros.S"
@@ -97,19 +98,19 @@ __v7m_setup:
mov r5, #0x00800000
str r5, [r0, V7M_SCB_SHPR3] @ set PendSV priority
- @ SVC to run the kernel in this mode
+ @ SVC to switch to handler mode. Notice that this requires sp to
+ @ point to writeable memory because the processor saves
+ @ some registers to the stack.
badr r1, 1f
ldr r5, [r12, #11 * 4] @ read the SVC vector entry
str r1, [r12, #11 * 4] @ write the temporary SVC vector entry
mov r6, lr @ save LR
- mov r7, sp @ save SP
- ldr sp, =__v7m_setup_stack_top
+ ldr sp, =init_thread_union + THREAD_START_SP
cpsie i
svc #0
1: cpsid i
str r5, [r12, #11 * 4] @ restore the original SVC vector entry
mov lr, r6 @ restore LR
- mov sp, r7 @ restore SP
@ Special-purpose control register
mov r1, #1
@@ -123,11 +124,6 @@ __v7m_setup:
ret lr
ENDPROC(__v7m_setup)
- .align 2
-__v7m_setup_stack:
- .space 4 * 8 @ 8 registers
-__v7m_setup_stack_top:
-
define_processor_functions v7m, dabort=nommu_early_abort, pabort=legacy_pabort, nommu=1
.section ".rodata"
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 2f4b14c..93d0b6d 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -187,19 +187,6 @@ static inline int mem_words_used(struct jit_ctx *ctx)
return fls(ctx->seen & SEEN_MEM);
}
-static inline bool is_load_to_a(u16 inst)
-{
- switch (inst) {
- case BPF_LD | BPF_W | BPF_LEN:
- case BPF_LD | BPF_W | BPF_ABS:
- case BPF_LD | BPF_H | BPF_ABS:
- case BPF_LD | BPF_B | BPF_ABS:
- return true;
- default:
- return false;
- }
-}
-
static void jit_fill_hole(void *area, unsigned int size)
{
u32 *ptr;
@@ -211,7 +198,6 @@ static void jit_fill_hole(void *area, unsigned int size)
static void build_prologue(struct jit_ctx *ctx)
{
u16 reg_set = saved_regs(ctx);
- u16 first_inst = ctx->skf->insns[0].code;
u16 off;
#ifdef CONFIG_FRAME_POINTER
@@ -241,7 +227,7 @@ static void build_prologue(struct jit_ctx *ctx)
emit(ARM_MOV_I(r_X, 0), ctx);
/* do not leak kernel data to userspace */
- if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
+ if (bpf_needs_clear_a(&ctx->skf->insns[0]))
emit(ARM_MOV_I(r_A, 0), ctx);
/* stack space for the BPF_MEM words */
@@ -770,7 +756,8 @@ load_ind:
case BPF_ALU | BPF_RSH | BPF_K:
if (unlikely(k > 31))
return -1;
- emit(ARM_LSR_I(r_A, r_A, k), ctx);
+ if (k)
+ emit(ARM_LSR_I(r_A, r_A, k), ctx);
break;
case BPF_ALU | BPF_RSH | BPF_X:
update_on_xread(ctx);
@@ -1061,7 +1048,7 @@ void bpf_jit_compile(struct bpf_prog *fp)
}
build_epilogue(&ctx);
- flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));
+ flush_icache_range((u32)header, (u32)(ctx.target + ctx.idx));
#if __LINUX_ARM_ARCH__ < 7
if (ctx.imm_count)
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 8207462..74ef889 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -36,7 +36,7 @@
#include <linux/platform_data/s3c-hsotg.h>
#include <linux/platform_data/dma-s3c24xx.h>
-#include <media/s5p_hdmi.h>
+#include <linux/platform_data/media/s5p_hdmi.h>
#include <asm/irq.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c
index fc7ea52..75cd734 100644
--- a/arch/arm/xen/enlighten.c
+++ b/arch/arm/xen/enlighten.c
@@ -12,6 +12,7 @@
#include <xen/page.h>
#include <xen/interface/sched.h>
#include <xen/xen-ops.h>
+#include <asm/paravirt.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
#include <asm/system_misc.h>
@@ -25,6 +26,10 @@
#include <linux/cpufreq.h>
#include <linux/cpu.h>
#include <linux/console.h>
+#include <linux/pvclock_gtod.h>
+#include <linux/time64.h>
+#include <linux/timekeeping.h>
+#include <linux/timekeeper_internal.h>
#include <linux/mm.h>
@@ -79,6 +84,83 @@ int xen_unmap_domain_gfn_range(struct vm_area_struct *vma,
}
EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range);
+static unsigned long long xen_stolen_accounting(int cpu)
+{
+ struct vcpu_runstate_info state;
+
+ BUG_ON(cpu != smp_processor_id());
+
+ xen_get_runstate_snapshot(&state);
+
+ WARN_ON(state.state != RUNSTATE_running);
+
+ return state.time[RUNSTATE_runnable] + state.time[RUNSTATE_offline];
+}
+
+static void xen_read_wallclock(struct timespec64 *ts)
+{
+ u32 version;
+ struct timespec64 now, ts_monotonic;
+ struct shared_info *s = HYPERVISOR_shared_info;
+ struct pvclock_wall_clock *wall_clock = &(s->wc);
+
+ /* get wallclock at system boot */
+ do {
+ version = wall_clock->version;
+ rmb(); /* fetch version before time */
+ now.tv_sec = ((uint64_t)wall_clock->sec_hi << 32) | wall_clock->sec;
+ now.tv_nsec = wall_clock->nsec;
+ rmb(); /* fetch time before checking version */
+ } while ((wall_clock->version & 1) || (version != wall_clock->version));
+
+ /* time since system boot */
+ ktime_get_ts64(&ts_monotonic);
+ *ts = timespec64_add(now, ts_monotonic);
+}
+
+static int xen_pvclock_gtod_notify(struct notifier_block *nb,
+ unsigned long was_set, void *priv)
+{
+ /* Protected by the calling core code serialization */
+ static struct timespec64 next_sync;
+
+ struct xen_platform_op op;
+ struct timespec64 now, system_time;
+ struct timekeeper *tk = priv;
+
+ now.tv_sec = tk->xtime_sec;
+ now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
+ system_time = timespec64_add(now, tk->wall_to_monotonic);
+
+ /*
+ * We only take the expensive HV call when the clock was set
+ * or when the 11 minutes RTC synchronization time elapsed.
+ */
+ if (!was_set && timespec64_compare(&now, &next_sync) < 0)
+ return NOTIFY_OK;
+
+ op.cmd = XENPF_settime64;
+ op.u.settime64.mbz = 0;
+ op.u.settime64.secs = now.tv_sec;
+ op.u.settime64.nsecs = now.tv_nsec;
+ op.u.settime64.system_time = timespec64_to_ns(&system_time);
+ (void)HYPERVISOR_platform_op(&op);
+
+ /*
+ * Move the next drift compensation time 11 minutes
+ * ahead. That's emulating the sync_cmos_clock() update for
+ * the hardware RTC.
+ */
+ next_sync = now;
+ next_sync.tv_sec += 11 * 60;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block xen_pvclock_gtod_notifier = {
+ .notifier_call = xen_pvclock_gtod_notify,
+};
+
static void xen_percpu_init(void)
{
struct vcpu_register_vcpu_info info;
@@ -104,6 +186,8 @@ static void xen_percpu_init(void)
BUG_ON(err);
per_cpu(xen_vcpu, cpu) = vcpup;
+ xen_setup_runstate_info(cpu);
+
after_register_vcpu_info:
enable_percpu_irq(xen_events_irq, 0);
put_cpu();
@@ -271,6 +355,11 @@ static int __init xen_guest_init(void)
register_cpu_notifier(&xen_cpu_notifier);
+ pv_time_ops.steal_clock = xen_stolen_accounting;
+ static_key_slow_inc(&paravirt_steal_enabled);
+ if (xen_initial_domain())
+ pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
+
return 0;
}
early_initcall(xen_guest_init);
@@ -282,6 +371,11 @@ static int __init xen_pm_init(void)
pm_power_off = xen_power_off;
arm_pm_restart = xen_restart;
+ if (!xen_initial_domain()) {
+ struct timespec64 ts;
+ xen_read_wallclock(&ts);
+ do_settimeofday64(&ts);
+ }
return 0;
}
@@ -307,5 +401,6 @@ EXPORT_SYMBOL_GPL(HYPERVISOR_memory_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_physdev_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_vcpu_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_tmem_op);
+EXPORT_SYMBOL_GPL(HYPERVISOR_platform_op);
EXPORT_SYMBOL_GPL(HYPERVISOR_multicall);
EXPORT_SYMBOL_GPL(privcmd_call);
diff --git a/arch/arm/xen/hypercall.S b/arch/arm/xen/hypercall.S
index 10fd99c..9a36f4f 100644
--- a/arch/arm/xen/hypercall.S
+++ b/arch/arm/xen/hypercall.S
@@ -89,6 +89,7 @@ HYPERCALL2(memory_op);
HYPERCALL2(physdev_op);
HYPERCALL3(vcpu_op);
HYPERCALL1(tmem_op);
+HYPERCALL1(platform_op_raw);
HYPERCALL2(multicall);
ENTRY(privcmd_call)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 851fe11..d6ebffd 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -27,6 +27,7 @@ config ARM64
select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS
select EDAC_SUPPORT
+ select FRAME_POINTER
select GENERIC_ALLOCATOR
select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST
@@ -48,7 +49,7 @@ config ARM64
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_BITREVERSE
select HAVE_ARCH_JUMP_LABEL
- select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP
+ select HAVE_ARCH_KASAN if SPARSEMEM_VMEMMAP && !(ARM64_16K_PAGES && ARM64_VA_BITS_48)
select HAVE_ARCH_KGDB
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
@@ -69,6 +70,7 @@ config ARM64
select HAVE_FUNCTION_GRAPH_TRACER
select HAVE_GENERIC_DMA_COHERENT
select HAVE_HW_BREAKPOINT if PERF_EVENTS
+ select HAVE_IRQ_TIME_ACCOUNTING
select HAVE_MEMBLOCK
select HAVE_PATA_PLATFORM
select HAVE_PERF_EVENTS
@@ -91,6 +93,7 @@ config ARM64
select SPARSE_IRQ
select SYSCTL_EXCEPTION_TRACE
select HAVE_CONTEXT_TRACKING
+ select HAVE_ARM_SMCCC
help
ARM 64-bit (AArch64) Linux support.
@@ -315,6 +318,27 @@ config ARM64_ERRATUM_832075
If unsure, say Y.
+config ARM64_ERRATUM_834220
+ bool "Cortex-A57: 834220: Stage 2 translation fault might be incorrectly reported in presence of a Stage 1 fault"
+ depends on KVM
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 834220 on Cortex-A57 parts up to r1p2.
+
+ Affected Cortex-A57 parts might report a Stage 2 translation
+ fault as the result of a Stage 1 fault for load crossing a
+ page boundary when there is a permission or device memory
+ alignment fault at Stage 1 and a translation fault at Stage 2.
+
+ The workaround is to verify that the Stage 1 translation
+ doesn't generate a fault before handling the Stage 2 fault.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
config ARM64_ERRATUM_845719
bool "Cortex-A53: 845719: a load might read incorrect data"
depends on COMPAT
@@ -507,9 +531,6 @@ config HW_PERF_EVENTS
config SYS_SUPPORTS_HUGETLBFS
def_bool y
-config ARCH_WANT_GENERAL_HUGETLB
- def_bool y
-
config ARCH_WANT_HUGE_PMD_SHARE
def_bool y if ARM64_4K_PAGES || (ARM64_16K_PAGES && !ARM64_VA_BITS_36)
@@ -534,6 +555,25 @@ config SECCOMP
and the task is only allowed to execute a few safe syscalls
defined by each seccomp mode.
+config PARAVIRT
+ bool "Enable paravirtualization code"
+ help
+ This changes the kernel so it can modify itself when it is run
+ under a hypervisor, potentially improving performance significantly
+ over full virtualization.
+
+config PARAVIRT_TIME_ACCOUNTING
+ bool "Paravirtual steal time accounting"
+ select PARAVIRT
+ default n
+ help
+ Select this option to enable fine granularity task steal time
+ accounting. Time spent executing other tasks in parallel with
+ the current vCPU is discounted from the vCPU power. To account for
+ that, there can be a small performance impact.
+
+ If in doubt, say N here.
+
config XEN_DOM0
def_bool y
depends on XEN
@@ -542,6 +582,7 @@ config XEN
bool "Xen guest support on ARM64"
depends on ARM64 && OF
select SWIOTLB_XEN
+ select PARAVIRT
help
Say Y if you want to run Linux in a Virtual Machine on Xen on ARM64.
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index c24d6ad..04fb73b 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -2,10 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config FRAME_POINTER
- bool
- default y
-
config ARM64_PTDUMP
bool "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 23800a1..4043c35 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -7,6 +7,7 @@ config ARCH_BCM_IPROC
config ARCH_BERLIN
bool "Marvell Berlin SoC Family"
+ select ARCH_REQUIRE_GPIOLIB
select DW_APB_ICTL
help
This enables support for Marvell Berlin SoC Family
@@ -28,10 +29,10 @@ config ARCH_EXYNOS7
help
This enables support for Samsung Exynos7 SoC family
-config ARCH_FSL_LS2085A
- bool "Freescale LS2085A SOC"
+config ARCH_LAYERSCAPE
+ bool "ARMv8 based Freescale Layerscape SoC family"
help
- This enables support for Freescale LS2085A SOC.
+ This enables support for the Freescale Layerscape SoC family.
config ARCH_HISI
bool "Hisilicon SoC Family"
@@ -66,6 +67,11 @@ config ARCH_SEATTLE
help
This enables support for AMD Seattle SOC Family
+config ARCH_STRATIX10
+ bool "Altera's Stratix 10 SoCFPGA Family"
+ help
+ This enables support for Altera's Stratix 10 SoCFPGA Family.
+
config ARCH_TEGRA
bool "NVIDIA Tegra SoC Family"
select ARCH_HAS_RESET_CONTROLLER
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index b01ec43..eb3c42d 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -1,3 +1,4 @@
+dts-dirs += altera
dts-dirs += amd
dts-dirs += apm
dts-dirs += arm
diff --git a/arch/arm64/boot/dts/altera/Makefile b/arch/arm64/boot/dts/altera/Makefile
new file mode 100644
index 0000000..d7a6416
--- /dev/null
+++ b/arch/arm64/boot/dts/altera/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_STRATIX10) += socfpga_stratix10_socdk.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
new file mode 100644
index 0000000..445aa67
--- /dev/null
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -0,0 +1,358 @@
+/*
+ * Copyright Altera Corporation (C) 2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/dts-v1/;
+
+/ {
+ compatible = "altr,socfpga-stratix10";
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x0>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x1>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x2>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a53", "arm,armv8";
+ device_type = "cpu";
+ enable-method = "psci";
+ reg = <0x3>;
+ };
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <0 120 8>,
+ <0 121 8>,
+ <0 122 8>,
+ <0 123 8>;
+ interrupt-affinity = <&cpu0>,
+ <&cpu1>,
+ <&cpu2>,
+ <&cpu3>;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ intc: intc@fffc1000 {
+ compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x0 0xfffc1000 0x1000>,
+ <0x0 0xfffc2000 0x2000>,
+ <0x0 0xfffc4000 0x2000>,
+ <0x0 0xfffc6000 0x2000>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ device_type = "soc";
+ interrupt-parent = <&intc>;
+ ranges = <0 0 0 0xffffffff>;
+
+ clkmgr@ffd1000 {
+ compatible = "altr,clk-mgr";
+ reg = <0xffd10000 0x1000>;
+ };
+
+ gmac0: ethernet@ff800000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+ reg = <0xff800000 0x2000>;
+ interrupts = <0 90 4>;
+ interrupt-names = "macirq";
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gmac1: ethernet@ff802000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+ reg = <0xff802000 0x2000>;
+ interrupts = <0 91 4>;
+ interrupt-names = "macirq";
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gmac2: ethernet@ff804000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.74a", "snps,dwmac";
+ reg = <0xff804000 0x2000>;
+ interrupts = <0 92 4>;
+ interrupt-names = "macirq";
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gpio0: gpio@ffc03200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dw-apb-gpio";
+ reg = <0xffc03200 0x100>;
+ status = "disabled";
+
+ porta: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <24>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 110 4>;
+ };
+ };
+
+ gpio1: gpio@ffc03300 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dw-apb-gpio";
+ reg = <0xffc03300 0x100>;
+ status = "disabled";
+
+ portb: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <24>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 110 4>;
+ };
+ };
+
+ i2c0: i2c@ffc02800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02800 0x100>;
+ interrupts = <0 103 4>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@ffc02900 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02900 0x100>;
+ interrupts = <0 104 4>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@ffc02a00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02a00 0x100>;
+ interrupts = <0 105 4>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@ffc02b00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02b00 0x100>;
+ interrupts = <0 106 4>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@ffc02c00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02c00 0x100>;
+ interrupts = <0 107 4>;
+ status = "disabled";
+ };
+
+ mmc: dwmmc0@ff808000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "altr,socfpga-dw-mshc";
+ reg = <0xff808000 0x1000>;
+ interrupts = <0 96 4>;
+ fifo-depth = <0x400>;
+ status = "disabled";
+ };
+
+ ocram: sram@ffe00000 {
+ compatible = "mmio-sram";
+ reg = <0xffe00000 0x100000>;
+ };
+
+ rst: rstmgr@ffd11000 {
+ #reset-cells = <1>;
+ compatible = "altr,rst-mgr";
+ reg = <0xffd11000 0x1000>;
+ };
+
+ spi0: spi@ffda4000 {
+ compatible = "snps,dw-apb-ssi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xffda4000 0x1000>;
+ interrupts = <0 101 4>;
+ num-chipselect = <4>;
+ bus-num = <0>;
+ status = "disabled";
+ };
+
+ spi1: spi@ffda5000 {
+ compatible = "snps,dw-apb-ssi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xffda5000 0x1000>;
+ interrupts = <0 102 4>;
+ num-chipselect = <4>;
+ bus-num = <0>;
+ status = "disabled";
+ };
+
+ sysmgr: sysmgr@ffd12000 {
+ compatible = "altr,sys-mgr", "syscon";
+ reg = <0xffd12000 0x1000>;
+ };
+
+ /* Local timer */
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xf01>,
+ <1 14 0xf01>,
+ <1 11 0xf01>,
+ <1 10 0xf01>;
+ };
+
+ timer0: timer0@ffc03000 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 113 4>;
+ reg = <0xffc03000 0x100>;
+ };
+
+ timer1: timer1@ffc03100 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 114 4>;
+ reg = <0xffc03100 0x100>;
+ };
+
+ timer2: timer2@ffd00000 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 115 4>;
+ reg = <0xffd00000 0x100>;
+ };
+
+ timer3: timer3@ffd00100 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 116 4>;
+ reg = <0xffd00100 0x100>;
+ };
+
+ uart0: serial0@ffc02000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xffc02000 0x100>;
+ interrupts = <0 108 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ uart1: serial1@ffc02100 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xffc02100 0x100>;
+ interrupts = <0 109 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ usbphy0: usbphy@0 {
+ #phy-cells = <0>;
+ compatible = "usb-nop-xceiv";
+ status = "okay";
+ };
+
+ usb0: usb@ffb00000 {
+ compatible = "snps,dwc2";
+ reg = <0xffb00000 0x40000>;
+ interrupts = <0 93 4>;
+ phys = <&usbphy0>;
+ phy-names = "usb2-phy";
+ status = "disabled";
+ };
+
+ usb1: usb@ffb40000 {
+ compatible = "snps,dwc2";
+ reg = <0xffb40000 0x40000>;
+ interrupts = <0 94 4>;
+ phys = <&usbphy0>;
+ phy-names = "usb2-phy";
+ status = "disabled";
+ };
+
+ watchdog0: watchdog@ffd00200 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00200 0x100>;
+ interrupts = <0 117 4>;
+ status = "disabled";
+ };
+
+ watchdog1: watchdog@ffd00300 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00300 0x100>;
+ interrupts = <0 118 4>;
+ status = "disabled";
+ };
+
+ watchdog2: watchdog@ffd00400 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00400 0x100>;
+ interrupts = <0 125 4>;
+ status = "disabled";
+ };
+
+ watchdog3: watchdog@ffd00500 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00500 0x100>;
+ interrupts = <0 126 4>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
new file mode 100644
index 0000000..41ea2db
--- /dev/null
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10_socdk.dts
@@ -0,0 +1,39 @@
+/*
+ * Copyright Altera Corporation (C) 2015. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/include/ "socfpga_stratix10.dtsi"
+
+/ {
+ model = "SoCFPGA Stratix 10 SoCDK";
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ /* We expect the bootloader to fill in the reg */
+ reg = <0 0 0 0>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/apm/Makefile b/arch/arm64/boot/dts/apm/Makefile
index a2afabb..c75f17a4 100644
--- a/arch/arm64/boot/dts/apm/Makefile
+++ b/arch/arm64/boot/dts/apm/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
+dtb-$(CONFIG_ARCH_XGENE) += apm-merlin.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/apm/apm-merlin.dts b/arch/arm64/boot/dts/apm/apm-merlin.dts
new file mode 100644
index 0000000..119a469
--- /dev/null
+++ b/arch/arm64/boot/dts/apm/apm-merlin.dts
@@ -0,0 +1,72 @@
+/*
+ * dts file for AppliedMicro (APM) Merlin Board
+ *
+ * Copyright (C) 2015, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/dts-v1/;
+
+/include/ "apm-shadowcat.dtsi"
+
+/ {
+ model = "APM X-Gene Merlin board";
+ compatible = "apm,merlin", "apm,xgene-shadowcat";
+
+ chosen { };
+
+ memory {
+ device_type = "memory";
+ reg = < 0x1 0x00000000 0x0 0x80000000 >;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ button@1 {
+ label = "POWER";
+ linux,code = <116>;
+ linux,input-type = <0x1>;
+ interrupts = <0x0 0x28 0x1>;
+ };
+ };
+
+ poweroff_mbox: poweroff_mbox@10548000 {
+ compatible = "syscon";
+ reg = <0x0 0x10548000 0x0 0x30>;
+ };
+
+ poweroff: poweroff@10548010 {
+ compatible = "syscon-poweroff";
+ regmap = <&poweroff_mbox>;
+ offset = <0x10>;
+ mask = <0x1>;
+ };
+};
+
+&serial0 {
+ status = "ok";
+};
+
+&sata1 {
+ status = "ok";
+};
+
+&sata2 {
+ status = "ok";
+};
+
+&sata3 {
+ status = "ok";
+};
+
+&sgenet0 {
+ status = "ok";
+};
+
+&xgenet1 {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/apm/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts
index 4c55833..01cdeda 100644
--- a/arch/arm64/boot/dts/apm/apm-mustang.dts
+++ b/arch/arm64/boot/dts/apm/apm-mustang.dts
@@ -33,6 +33,18 @@
interrupts = <0x0 0x2d 0x1>;
};
};
+
+ poweroff_mbox: poweroff_mbox@10548000 {
+ compatible = "syscon";
+ reg = <0x0 0x10548000 0x0 0x30>;
+ };
+
+ poweroff: poweroff@10548010 {
+ compatible = "syscon-poweroff";
+ regmap = <&poweroff_mbox>;
+ offset = <0x10>;
+ mask = <0x1>;
+ };
};
&pcie0clk {
diff --git a/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
new file mode 100644
index 0000000..c804f8f
--- /dev/null
+++ b/arch/arm64/boot/dts/apm/apm-shadowcat.dtsi
@@ -0,0 +1,271 @@
+/*
+ * dts file for AppliedMicro (APM) X-Gene Shadowcat SOC
+ *
+ * Copyright (C) 2015, Applied Micro Circuits Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+/ {
+ compatible = "apm,xgene-shadowcat";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ cpu@000 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x000>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@001 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x001>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@100 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x100>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@101 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x101>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x200>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x201>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@300 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x300>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ cpu@301 {
+ device_type = "cpu";
+ compatible = "apm,strega", "arm,armv8";
+ reg = <0x0 0x301>;
+ enable-method = "spin-table";
+ cpu-release-addr = <0x1 0x0000fff8>;
+ };
+ };
+
+ gic: interrupt-controller@78090000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ interrupt-controller;
+ interrupts = <1 9 0xf04>; /* GIC Maintenence IRQ */
+ ranges = <0 0 0 0x79000000 0x0 0x800000>; /* MSI Range */
+ reg = <0x0 0x78090000 0x0 0x10000>, /* GIC Dist */
+ <0x0 0x780A0000 0x0 0x20000>, /* GIC CPU */
+ <0x0 0x780C0000 0x0 0x10000>, /* GIC VCPU Control */
+ <0x0 0x780E0000 0x0 0x20000>; /* GIC VCPU */
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <1 12 0xff04>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 0 0xff04>, /* Secure Phys IRQ */
+ <1 13 0xff04>, /* Non-secure Phys IRQ */
+ <1 14 0xff04>, /* Virt IRQ */
+ <1 15 0xff04>; /* Hyp IRQ */
+ clock-frequency = <50000000>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ clocks {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ refclk: refclk {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <100000000>;
+ clock-output-names = "refclk";
+ };
+
+ socpll: socpll@17000120 {
+ compatible = "apm,xgene-socpll-clock";
+ #clock-cells = <1>;
+ clocks = <&refclk 0>;
+ reg = <0x0 0x17000120 0x0 0x1000>;
+ clock-output-names = "socpll";
+ };
+
+ socplldiv2: socplldiv2 {
+ compatible = "fixed-factor-clock";
+ #clock-cells = <1>;
+ clocks = <&socpll 0>;
+ clock-mult = <1>;
+ clock-div = <2>;
+ clock-output-names = "socplldiv2";
+ };
+
+ pcie0clk: pcie0clk@1f2bc000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f2bc000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ clock-output-names = "pcie0clk";
+ };
+
+ xge0clk: xge0clk@1f61c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f61c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ enable-mask = <0x3>;
+ csr-mask = <0x3>;
+ clock-output-names = "xge0clk";
+ };
+
+ xge1clk: xge1clk@1f62c000 {
+ compatible = "apm,xgene-device-clock";
+ #clock-cells = <1>;
+ clocks = <&socplldiv2 0>;
+ reg = <0x0 0x1f62c000 0x0 0x1000>;
+ reg-names = "csr-reg";
+ enable-mask = <0x3>;
+ csr-mask = <0x3>;
+ clock-output-names = "xge1clk";
+ };
+ };
+
+ scu: system-clk-controller@17000000 {
+ compatible = "apm,xgene-scu","syscon";
+ reg = <0x0 0x17000000 0x0 0x400>;
+ };
+
+ reboot: reboot@17000014 {
+ compatible = "syscon-reboot";
+ regmap = <&scu>;
+ offset = <0x14>;
+ mask = <0x1>;
+ };
+
+ serial0: serial@10600000 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <0 0x10600000 0x0 0x1000>;
+ reg-shift = <2>;
+ clock-frequency = <10000000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0x0 0x4c 0x4>;
+ };
+
+ sata1: sata@1a000000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a000000 0x0 0x1000>,
+ <0x0 0x1f200000 0x0 0x1000>,
+ <0x0 0x1f20d000 0x0 0x1000>,
+ <0x0 0x1f20e000 0x0 0x1000>;
+ interrupts = <0x0 0x5a 0x4>;
+ dma-coherent;
+ };
+
+ sata2: sata@1a200000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a200000 0x0 0x1000>,
+ <0x0 0x1f210000 0x0 0x1000>,
+ <0x0 0x1f21d000 0x0 0x1000>,
+ <0x0 0x1f21e000 0x0 0x1000>;
+ interrupts = <0x0 0x5b 0x4>;
+ dma-coherent;
+ };
+
+ sata3: sata@1a400000 {
+ compatible = "apm,xgene-ahci";
+ reg = <0x0 0x1a400000 0x0 0x1000>,
+ <0x0 0x1f220000 0x0 0x1000>,
+ <0x0 0x1f22d000 0x0 0x1000>,
+ <0x0 0x1f22e000 0x0 0x1000>;
+ interrupts = <0x0 0x5c 0x4>;
+ dma-coherent;
+ };
+
+ sbgpio: sbgpio@17001000{
+ compatible = "apm,xgene-gpio-sb";
+ reg = <0x0 0x17001000 0x0 0x400>;
+ #gpio-cells = <2>;
+ gpio-controller;
+ interrupts = <0x0 0x28 0x1>,
+ <0x0 0x29 0x1>,
+ <0x0 0x2a 0x1>,
+ <0x0 0x2b 0x1>,
+ <0x0 0x2c 0x1>,
+ <0x0 0x2d 0x1>,
+ <0x0 0x2e 0x1>,
+ <0x0 0x2f 0x1>;
+ };
+
+ sgenet0: ethernet@1f610000 {
+ compatible = "apm,xgene2-sgenet";
+ status = "disabled";
+ reg = <0x0 0x1f610000 0x0 0x10000>,
+ <0x0 0x1f600000 0x0 0Xd100>,
+ <0x0 0x20000000 0x0 0X20000>;
+ interrupts = <0 96 4>,
+ <0 97 4>;
+ dma-coherent;
+ clocks = <&xge0clk 0>;
+ local-mac-address = [00 01 73 00 00 01];
+ phy-connection-type = "sgmii";
+ };
+
+ xgenet1: ethernet@1f620000 {
+ compatible = "apm,xgene2-xgenet";
+ status = "disabled";
+ reg = <0x0 0x1f620000 0x0 0x10000>,
+ <0x0 0x1f600000 0x0 0Xd100>,
+ <0x0 0x20000000 0x0 0X220000>;
+ interrupts = <0 108 4>,
+ <0 109 4>;
+ port-id = <1>;
+ dma-coherent;
+ clocks = <&xge1clk 0>;
+ local-mac-address = [00 01 73 00 00 02];
+ phy-connection-type = "xgmii";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/apm/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
index d6c9630a5..6c5ed11 100644
--- a/arch/arm64/boot/dts/apm/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
@@ -97,6 +97,11 @@
clock-frequency = <50000000>;
};
+ pmu {
+ compatible = "apm,potenza-pmu", "arm,armv8-pmuv3";
+ interrupts = <1 12 0xff04>;
+ };
+
soc {
compatible = "simple-bus";
#address-cells = <2>;
@@ -407,6 +412,18 @@
0x0 0x1f 0x4>;
};
+ scu: system-clk-controller@17000000 {
+ compatible = "apm,xgene-scu","syscon";
+ reg = <0x0 0x17000000 0x0 0x400>;
+ };
+
+ reboot: reboot@17000014 {
+ compatible = "syscon-reboot";
+ regmap = <&scu>;
+ offset = <0x14>;
+ mask = <0x1>;
+ };
+
csw: csw@7e200000 {
compatible = "apm,xgene-csw", "syscon";
reg = <0x0 0x7e200000 0x0 0x1000>;
diff --git a/arch/arm64/boot/dts/arm/juno-base.dtsi b/arch/arm64/boot/dts/arm/juno-base.dtsi
index e3ee960..dd5158e 100644
--- a/arch/arm64/boot/dts/arm/juno-base.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-base.dtsi
@@ -17,6 +17,18 @@
};
};
+ mailbox: mhu@2b1f0000 {
+ compatible = "arm,mhu", "arm,primecell";
+ reg = <0x0 0x2b1f0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "mhu_lpri_rx",
+ "mhu_hpri_rx";
+ #mbox-cells = <1>;
+ clocks = <&soc_refclk100mhz>;
+ clock-names = "apb_pclk";
+ };
+
gic: interrupt-controller@2c010000 {
compatible = "arm,gic-400", "arm,cortex-a15-gic";
reg = <0x0 0x2c010000 0 0x1000>,
@@ -44,6 +56,53 @@
<GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
};
+ sram: sram@2e000000 {
+ compatible = "arm,juno-sram-ns", "mmio-sram";
+ reg = <0x0 0x2e000000 0x0 0x8000>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x0 0x2e000000 0x8000>;
+
+ cpu_scp_lpri: scp-shmem@0 {
+ compatible = "arm,juno-scp-shmem";
+ reg = <0x0 0x200>;
+ };
+
+ cpu_scp_hpri: scp-shmem@200 {
+ compatible = "arm,juno-scp-shmem";
+ reg = <0x200 0x200>;
+ };
+ };
+
+ scpi {
+ compatible = "arm,scpi";
+ mboxes = <&mailbox 1>;
+ shmem = <&cpu_scp_hpri>;
+
+ clocks {
+ compatible = "arm,scpi-clocks";
+
+ scpi_dvfs: scpi_clocks@0 {
+ compatible = "arm,scpi-dvfs-clocks";
+ #clock-cells = <1>;
+ clock-indices = <0>, <1>, <2>;
+ clock-output-names = "atlclk", "aplclk","gpuclk";
+ };
+ scpi_clk: scpi_clocks@3 {
+ compatible = "arm,scpi-variable-clocks";
+ #clock-cells = <1>;
+ clock-indices = <3>, <4>;
+ clock-output-names = "pxlclk0", "pxlclk1";
+ };
+ };
+
+ scpi_sensors0: sensors {
+ compatible = "arm,scpi-sensors";
+ #thermal-sensor-cells = <1>;
+ };
+ };
+
/include/ "juno-clocks.dtsi"
dma@7ff00000 {
diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
index 3c38668..413f1b9 100644
--- a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
+++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
@@ -103,6 +103,21 @@
};
};
+ flash@0,00000000 {
+ /* 2 * 32MiB NOR Flash memory mounted on CS0 */
+ compatible = "arm,vexpress-flash", "cfi-flash";
+ linux,part-probe = "afs";
+ reg = <0 0x00000000 0x04000000>;
+ bank-width = <4>;
+ /*
+ * Unfortunately, accessing the flash disturbs
+ * the CPU idle states (suspend) and CPU
+ * hotplug of the platform. For this reason,
+ * flash hardware access is disabled by default.
+ */
+ status = "disabled";
+ };
+
ethernet@2,00000000 {
compatible = "smsc,lan9118", "smsc,lan9115";
reg = <2 0x00000000 0x10000>;
diff --git a/arch/arm64/boot/dts/arm/juno-r1.dts b/arch/arm64/boot/dts/arm/juno-r1.dts
index 734e127..93bc3d7 100644
--- a/arch/arm64/boot/dts/arm/juno-r1.dts
+++ b/arch/arm64/boot/dts/arm/juno-r1.dts
@@ -34,12 +34,39 @@
#address-cells = <2>;
#size-cells = <0>;
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&A57_0>;
+ };
+ core1 {
+ cpu = <&A57_1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&A53_0>;
+ };
+ core1 {
+ cpu = <&A53_1>;
+ };
+ core2 {
+ cpu = <&A53_2>;
+ };
+ core3 {
+ cpu = <&A53_3>;
+ };
+ };
+ };
+
A57_0: cpu@0 {
compatible = "arm,cortex-a57","arm,armv8";
reg = <0x0 0x0>;
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
};
A57_1: cpu@1 {
@@ -48,6 +75,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
};
A53_0: cpu@100 {
@@ -56,6 +84,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_1: cpu@101 {
@@ -64,6 +93,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_2: cpu@102 {
@@ -72,6 +102,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_3: cpu@103 {
@@ -80,6 +111,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A57_L2: l2-cache0 {
@@ -113,6 +145,26 @@
#include "juno-base.dtsi"
+ pcie-controller@40000000 {
+ compatible = "arm,juno-r1-pcie", "plda,xpressrich3-axi", "pci-host-ecam-generic";
+ device_type = "pci";
+ reg = <0 0x40000000 0 0x10000000>; /* ECAM config space */
+ bus-range = <0 255>;
+ linux,pci-domain = <0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ dma-coherent;
+ ranges = <0x01000000 0x00 0x5f800000 0x00 0x5f800000 0x0 0x00800000>,
+ <0x02000000 0x00 0x50000000 0x00 0x50000000 0x0 0x08000000>,
+ <0x42000000 0x40 0x00000000 0x40 0x00000000 0x1 0x00000000>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &gic 0 0 0 136 4>,
+ <0 0 0 2 &gic 0 0 0 137 4>,
+ <0 0 0 3 &gic 0 0 0 138 4>,
+ <0 0 0 4 &gic 0 0 0 139 4>;
+ msi-parent = <&v2m_0>;
+ };
};
&memtimer {
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
index ffa05ae..53442b5 100644
--- a/arch/arm64/boot/dts/arm/juno.dts
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -34,12 +34,39 @@
#address-cells = <2>;
#size-cells = <0>;
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&A57_0>;
+ };
+ core1 {
+ cpu = <&A57_1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&A53_0>;
+ };
+ core1 {
+ cpu = <&A53_1>;
+ };
+ core2 {
+ cpu = <&A53_2>;
+ };
+ core3 {
+ cpu = <&A53_3>;
+ };
+ };
+ };
+
A57_0: cpu@0 {
compatible = "arm,cortex-a57","arm,armv8";
reg = <0x0 0x0>;
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
};
A57_1: cpu@1 {
@@ -48,6 +75,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A57_L2>;
+ clocks = <&scpi_dvfs 0>;
};
A53_0: cpu@100 {
@@ -56,6 +84,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_1: cpu@101 {
@@ -64,6 +93,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_2: cpu@102 {
@@ -72,6 +102,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A53_3: cpu@103 {
@@ -80,6 +111,7 @@
device_type = "cpu";
enable-method = "psci";
next-level-cache = <&A53_L2>;
+ clocks = <&scpi_dvfs 1>;
};
A57_L2: l2-cache0 {
diff --git a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
index 5b1d018..bb3c26d 100644
--- a/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
+++ b/arch/arm64/boot/dts/arm/vexpress-v2f-1xv7-ca53x2.dts
@@ -186,6 +186,6 @@
<0 0 41 &gic GIC_SPI 41 IRQ_TYPE_LEVEL_HIGH>,
<0 0 42 &gic GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
- /include/ "../../../../arm/boot/dts/vexpress-v2m-rs1.dtsi"
+ /include/ "vexpress-v2m-rs1.dtsi"
};
};
diff --git a/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi b/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi
new file mode 120000
index 0000000..68fd0f8
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi
@@ -0,0 +1 @@
+../../../../arm/boot/dts/vexpress-v2m-rs1.dtsi \ No newline at end of file
diff --git a/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi b/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
index 2eef4a2..f77ddaf 100644
--- a/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos7-pinctrl.dtsi
@@ -586,3 +586,106 @@
samsung,pin-drv = <2>;
};
};
+
+&pinctrl_bus1 {
+ gpf0: gpf0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf1: gpf1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf2: gpf2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf3: gpf3 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf4: gpf4 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf5: gpf5 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpg1: gpg1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpg2: gpg2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gph1: gph1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpv6: gpv6 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ spi5_bus: spi5-bus {
+ samsung,pins = "gpf2-0", "gpf2-1", "gpf2-2", "gpf2-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ ufs_refclk_out: ufs-refclk-out {
+ samsung,pins = "gpg2-4";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <2>;
+ };
+
+ ufs_rst_n: ufs-rst-n {
+ samsung,pins = "gph1-5";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+};
diff --git a/arch/arm64/boot/dts/exynos/exynos7.dtsi b/arch/arm64/boot/dts/exynos/exynos7.dtsi
index d7a37c3..f9c5a54 100644
--- a/arch/arm64/boot/dts/exynos/exynos7.dtsi
+++ b/arch/arm64/boot/dts/exynos/exynos7.dtsi
@@ -26,6 +26,7 @@
pinctrl5 = &pinctrl_ese;
pinctrl6 = &pinctrl_fsys0;
pinctrl7 = &pinctrl_fsys1;
+ pinctrl8 = &pinctrl_bus1;
};
cpus {
@@ -278,6 +279,12 @@
interrupts = <0 203 0>;
};
+ pinctrl_bus1: pinctrl@14870000 {
+ compatible = "samsung,exynos7-pinctrl";
+ reg = <0x14870000 0x1000>;
+ interrupts = <0 384 0>;
+ };
+
hsi2c_0: hsi2c@13640000 {
compatible = "samsung,exynos7-hsi2c";
reg = <0x13640000 0x1000>;
diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index 4f2de3e7..c4957a4 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -1,4 +1,6 @@
-dtb-$(CONFIG_ARCH_FSL_LS2085A) += fsl-ls2085a-simu.dtb
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-qds.dtb
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-rdb.dtb
+dtb-$(CONFIG_ARCH_LAYERSCAPE) += fsl-ls2080a-simu.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
new file mode 100644
index 0000000..4cb996d
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-qds.dts
@@ -0,0 +1,204 @@
+/*
+ * Device Tree file for Freescale LS2080a QDS Board.
+ *
+ * Copyright (C) 2015, Freescale Semiconductor
+ *
+ * Bhupesh Sharma <bhupesh.sharma@freescale.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+/include/ "fsl-ls2080a.dtsi"
+
+/ {
+ model = "Freescale Layerscape 2080a QDS Board";
+ compatible = "fsl,ls2080a-qds", "fsl,ls2080a";
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ };
+
+};
+
+&esdhc {
+ status = "okay";
+};
+
+&ifc {
+ status = "okay";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x5 0x80000000 0x08000000
+ 0x2 0x0 0x5 0x30000000 0x00010000
+ 0x3 0x0 0x5 0x20000000 0x00010000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@2,0 {
+ compatible = "fsl,ifc-nand";
+ reg = <0x2 0x0 0x10000>;
+ };
+
+ cpld@3,0 {
+ reg = <0x3 0x0 0x10000>;
+ compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis";
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ pca9547@77 {
+ compatible = "nxp,pca9547";
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x00>;
+ rtc@68 {
+ compatible = "dallas,ds3232";
+ reg = <0x68>;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x02>;
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <500>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x3>;
+
+ adt7481@4c {
+ compatible = "adi,adt7461";
+ reg = <0x4c>;
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "disabled";
+};
+
+&i2c2 {
+ status = "disabled";
+};
+
+&i2c3 {
+ status = "disabled";
+};
+
+&dspi {
+ status = "okay";
+ dflash0: n25q128a {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p80";
+ spi-max-frequency = <3000000>;
+ reg = <0>;
+ };
+ dflash1: sst25wf040b {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p80";
+ spi-max-frequency = <3000000>;
+ reg = <1>;
+ };
+ dflash2: en25s64 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p80";
+ spi-max-frequency = <3000000>;
+ reg = <2>;
+ };
+};
+
+&qspi {
+ status = "okay";
+ qflash0: s25fl008k {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p80";
+ spi-max-frequency = <20000000>;
+ reg = <0>;
+ };
+};
+
+&sata0 {
+ status = "okay";
+};
+
+&sata1 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
new file mode 100644
index 0000000..e127f0b
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-rdb.dts
@@ -0,0 +1,166 @@
+/*
+ * Device Tree file for Freescale LS2080a RDB Board.
+ *
+ * Copyright (C) 2015, Freescale Semiconductor
+ *
+ * Bhupesh Sharma <bhupesh.sharma@freescale.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+/include/ "fsl-ls2080a.dtsi"
+
+/ {
+ model = "Freescale Layerscape 2080a RDB Board";
+ compatible = "fsl,ls2080a-rdb", "fsl,ls2080a";
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ };
+};
+
+&esdhc {
+ status = "okay";
+};
+
+&ifc {
+ status = "okay";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x5 0x80000000 0x08000000
+ 0x2 0x0 0x5 0x30000000 0x00010000
+ 0x3 0x0 0x5 0x20000000 0x00010000>;
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ nand@2,0 {
+ compatible = "fsl,ifc-nand";
+ reg = <0x2 0x0 0x10000>;
+ };
+
+ cpld@3,0 {
+ reg = <0x3 0x0 0x10000>;
+ compatible = "fsl,ls2080aqds-fpga", "fsl,fpga-qixis";
+ };
+
+};
+
+&i2c0 {
+ status = "okay";
+ pca9547@75 {
+ compatible = "nxp,pca9547";
+ reg = <0x75>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x01>;
+ rtc@68 {
+ compatible = "dallas,ds3232";
+ reg = <0x68>;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x3>;
+
+ adt7481@4c {
+ compatible = "adi,adt7461";
+ reg = <0x4c>;
+ };
+ };
+ };
+};
+
+&i2c1 {
+ status = "disabled";
+};
+
+&i2c2 {
+ status = "disabled";
+};
+
+&i2c3 {
+ status = "disabled";
+};
+
+&dspi {
+ status = "okay";
+ dflash0: n25q512a {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,m25p80";
+ spi-max-frequency = <3000000>;
+ reg = <0>;
+ };
+};
+
+&qspi {
+ status = "disabled";
+};
+
+&sata0 {
+ status = "okay";
+};
+
+&sata1 {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+};
+
+&usb1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts b/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts
index 82e2a6f..505d038 100644
--- a/arch/arm64/boot/dts/freescale/fsl-ls2085a-simu.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a-simu.dts
@@ -1,7 +1,7 @@
/*
- * Device Tree file for Freescale LS2085a software Simulator model
+ * Device Tree file for Freescale LS2080a software Simulator model
*
- * Copyright (C) 2014, Freescale Semiconductor
+ * Copyright (C) 2014-2015, Freescale Semiconductor
*
* Bhupesh Sharma <bhupesh.sharma@freescale.com>
*
@@ -20,11 +20,6 @@
* 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 library; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- * MA 02110-1301 USA
- *
* Or, alternatively,
*
* b) Permission is hereby granted, free of charge, to any person
@@ -51,11 +46,16 @@
/dts-v1/;
-/include/ "fsl-ls2085a.dtsi"
+/include/ "fsl-ls2080a.dtsi"
/ {
- model = "Freescale Layerscape 2085a software Simulator model";
- compatible = "fsl,ls2085a-simu", "fsl,ls2085a";
+ model = "Freescale Layerscape 2080a software Simulator model";
+ compatible = "fsl,ls2080a-simu", "fsl,ls2080a";
+
+ aliases {
+ serial0 = &serial0;
+ serial1 = &serial1;
+ };
ethernet@2210000 {
compatible = "smsc,lan91c111";
@@ -63,3 +63,8 @@
interrupts = <0 58 0x1>;
};
};
+
+&ifc {
+ status = "okay";
+};
+
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
new file mode 100644
index 0000000..925552e
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-ls2080a.dtsi
@@ -0,0 +1,520 @@
+/*
+ * Device Tree Include file for Freescale Layerscape-2080A family SoC.
+ *
+ * Copyright (C) 2014-2015, Freescale Semiconductor
+ *
+ * Bhupesh Sharma <bhupesh.sharma@freescale.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/ {
+ compatible = "fsl,ls2080a";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ /*
+ * We expect the enable-method for cpu's to be "psci", but this
+ * is dependent on the SoC FW, which will fill this in.
+ *
+ * Currently supported enable-method is psci v0.2
+ */
+
+ /* We have 4 clusters having 2 Cortex-A57 cores each */
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x0>;
+ clocks = <&clockgen 1 0>;
+ };
+
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x1>;
+ clocks = <&clockgen 1 0>;
+ };
+
+ cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x100>;
+ clocks = <&clockgen 1 1>;
+ };
+
+ cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x101>;
+ clocks = <&clockgen 1 1>;
+ };
+
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x200>;
+ clocks = <&clockgen 1 2>;
+ };
+
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x201>;
+ clocks = <&clockgen 1 2>;
+ };
+
+ cpu@300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x300>;
+ clocks = <&clockgen 1 3>;
+ };
+
+ cpu@301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57";
+ reg = <0x0 0x301>;
+ clocks = <&clockgen 1 3>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x00000000 0x80000000 0 0x80000000>;
+ /* DRAM space - 1, size : 2 GB DRAM */
+ };
+
+ sysclk: sysclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "sysclk";
+ };
+
+ gic: interrupt-controller@6000000 {
+ compatible = "arm,gic-v3";
+ reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */
+ <0x0 0x06100000 0 0x100000>, /* GICR (RD_base + SGI_base) */
+ <0x0 0x0c0c0000 0 0x2000>, /* GICC */
+ <0x0 0x0c0d0000 0 0x1000>, /* GICH */
+ <0x0 0x0c0e0000 0 0x20000>; /* GICV */
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ interrupts = <1 9 0x4>;
+
+ its: gic-its@6020000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ reg = <0x0 0x6020000 0 0x20000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0x8>, /* Physical Secure PPI, active-low */
+ <1 14 0x8>, /* Physical Non-Secure PPI, active-low */
+ <1 11 0x8>, /* Virtual PPI, active-low */
+ <1 10 0x8>; /* Hypervisor PPI, active-low */
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <1 7 0x8>; /* PMU PPI, Level low type */
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ clockgen: clocking@1300000 {
+ compatible = "fsl,ls2080a-clockgen";
+ reg = <0 0x1300000 0 0xa0000>;
+ #clock-cells = <2>;
+ clocks = <&sysclk>;
+ };
+
+ serial0: serial@21c0500 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x0 0x21c0500 0x0 0x100>;
+ clocks = <&clockgen 4 3>;
+ interrupts = <0 32 0x4>; /* Level high type */
+ };
+
+ serial1: serial@21c0600 {
+ compatible = "fsl,ns16550", "ns16550a";
+ reg = <0x0 0x21c0600 0x0 0x100>;
+ clocks = <&clockgen 4 3>;
+ interrupts = <0 32 0x4>; /* Level high type */
+ };
+
+ fsl_mc: fsl-mc@80c000000 {
+ compatible = "fsl,qoriq-mc";
+ reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */
+ <0x00000000 0x08340000 0 0x40000>; /* MC control reg */
+ };
+
+ smmu: iommu@5000000 {
+ compatible = "arm,mmu-500";
+ reg = <0 0x5000000 0 0x800000>;
+ #global-interrupts = <12>;
+ interrupts = <0 13 4>, /* global secure fault */
+ <0 14 4>, /* combined secure interrupt */
+ <0 15 4>, /* global non-secure fault */
+ <0 16 4>, /* combined non-secure interrupt */
+ /* performance counter interrupts 0-7 */
+ <0 211 4>, <0 212 4>,
+ <0 213 4>, <0 214 4>,
+ <0 215 4>, <0 216 4>,
+ <0 217 4>, <0 218 4>,
+ /* per context interrupt, 64 interrupts */
+ <0 146 4>, <0 147 4>,
+ <0 148 4>, <0 149 4>,
+ <0 150 4>, <0 151 4>,
+ <0 152 4>, <0 153 4>,
+ <0 154 4>, <0 155 4>,
+ <0 156 4>, <0 157 4>,
+ <0 158 4>, <0 159 4>,
+ <0 160 4>, <0 161 4>,
+ <0 162 4>, <0 163 4>,
+ <0 164 4>, <0 165 4>,
+ <0 166 4>, <0 167 4>,
+ <0 168 4>, <0 169 4>,
+ <0 170 4>, <0 171 4>,
+ <0 172 4>, <0 173 4>,
+ <0 174 4>, <0 175 4>,
+ <0 176 4>, <0 177 4>,
+ <0 178 4>, <0 179 4>,
+ <0 180 4>, <0 181 4>,
+ <0 182 4>, <0 183 4>,
+ <0 184 4>, <0 185 4>,
+ <0 186 4>, <0 187 4>,
+ <0 188 4>, <0 189 4>,
+ <0 190 4>, <0 191 4>,
+ <0 192 4>, <0 193 4>,
+ <0 194 4>, <0 195 4>,
+ <0 196 4>, <0 197 4>,
+ <0 198 4>, <0 199 4>,
+ <0 200 4>, <0 201 4>,
+ <0 202 4>, <0 203 4>,
+ <0 204 4>, <0 205 4>,
+ <0 206 4>, <0 207 4>,
+ <0 208 4>, <0 209 4>;
+ mmu-masters = <&fsl_mc 0x300 0>;
+ };
+
+ dspi: dspi@2100000 {
+ status = "disabled";
+ compatible = "fsl,vf610-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2100000 0x0 0x10000>;
+ interrupts = <0 26 0x4>; /* Level high type */
+ clocks = <&clockgen 4 3>;
+ clock-names = "dspi";
+ spi-num-chipselects = <5>;
+ bus-num = <0>;
+ };
+
+ esdhc: esdhc@2140000 {
+ status = "disabled";
+ compatible = "fsl,ls2080a-esdhc", "fsl,esdhc";
+ reg = <0x0 0x2140000 0x0 0x10000>;
+ interrupts = <0 28 0x4>; /* Level high type */
+ clock-frequency = <0>; /* Updated by bootloader */
+ voltage-ranges = <1800 1800 3300 3300>;
+ sdhci,auto-cmd12;
+ little-endian;
+ bus-width = <4>;
+ };
+
+ gpio0: gpio@2300000 {
+ compatible = "fsl,qoriq-gpio";
+ reg = <0x0 0x2300000 0x0 0x10000>;
+ interrupts = <0 36 0x4>; /* Level high type */
+ gpio-controller;
+ little-endian;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio1: gpio@2310000 {
+ compatible = "fsl,qoriq-gpio";
+ reg = <0x0 0x2310000 0x0 0x10000>;
+ interrupts = <0 36 0x4>; /* Level high type */
+ gpio-controller;
+ little-endian;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio2: gpio@2320000 {
+ compatible = "fsl,qoriq-gpio";
+ reg = <0x0 0x2320000 0x0 0x10000>;
+ interrupts = <0 37 0x4>; /* Level high type */
+ gpio-controller;
+ little-endian;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpio3: gpio@2330000 {
+ compatible = "fsl,qoriq-gpio";
+ reg = <0x0 0x2330000 0x0 0x10000>;
+ interrupts = <0 37 0x4>; /* Level high type */
+ gpio-controller;
+ little-endian;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ i2c0: i2c@2000000 {
+ status = "disabled";
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2000000 0x0 0x10000>;
+ interrupts = <0 34 0x4>; /* Level high type */
+ clock-names = "i2c";
+ clocks = <&clockgen 4 3>;
+ };
+
+ i2c1: i2c@2010000 {
+ status = "disabled";
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2010000 0x0 0x10000>;
+ interrupts = <0 34 0x4>; /* Level high type */
+ clock-names = "i2c";
+ clocks = <&clockgen 4 3>;
+ };
+
+ i2c2: i2c@2020000 {
+ status = "disabled";
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2020000 0x0 0x10000>;
+ interrupts = <0 35 0x4>; /* Level high type */
+ clock-names = "i2c";
+ clocks = <&clockgen 4 3>;
+ };
+
+ i2c3: i2c@2030000 {
+ status = "disabled";
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2030000 0x0 0x10000>;
+ interrupts = <0 35 0x4>; /* Level high type */
+ clock-names = "i2c";
+ clocks = <&clockgen 4 3>;
+ };
+
+ ifc: ifc@2240000 {
+ compatible = "fsl,ifc", "simple-bus";
+ reg = <0x0 0x2240000 0x0 0x20000>;
+ interrupts = <0 21 0x4>; /* Level high type */
+ little-endian;
+ #address-cells = <2>;
+ #size-cells = <1>;
+
+ ranges = <0 0 0x5 0x80000000 0x08000000
+ 2 0 0x5 0x30000000 0x00010000
+ 3 0 0x5 0x20000000 0x00010000>;
+ };
+
+ qspi: quadspi@20c0000 {
+ status = "disabled";
+ compatible = "fsl,vf610-qspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x20c0000 0x0 0x10000>,
+ <0x0 0x20000000 0x0 0x10000000>;
+ reg-names = "QuadSPI", "QuadSPI-memory";
+ interrupts = <0 25 0x4>; /* Level high type */
+ clocks = <&clockgen 4 3>, <&clockgen 4 3>;
+ clock-names = "qspi_en", "qspi";
+ };
+
+ pcie@3400000 {
+ compatible = "fsl,ls2080a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03400000 0x0 0x00100000 /* controller registers */
+ 0x10 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 108 0x4>; /* Level high type */
+ interrupt-names = "intr";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <4>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x10 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x10 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&its>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 0 0 109 4>,
+ <0000 0 0 2 &gic 0 0 0 110 4>,
+ <0000 0 0 3 &gic 0 0 0 111 4>,
+ <0000 0 0 4 &gic 0 0 0 112 4>;
+ };
+
+ pcie@3500000 {
+ compatible = "fsl,ls2080a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03500000 0x0 0x00100000 /* controller registers */
+ 0x12 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 113 0x4>; /* Level high type */
+ interrupt-names = "intr";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <4>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x12 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x12 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&its>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 0 0 114 4>,
+ <0000 0 0 2 &gic 0 0 0 115 4>,
+ <0000 0 0 3 &gic 0 0 0 116 4>,
+ <0000 0 0 4 &gic 0 0 0 117 4>;
+ };
+
+ pcie@3600000 {
+ compatible = "fsl,ls2080a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03600000 0x0 0x00100000 /* controller registers */
+ 0x14 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 118 0x4>; /* Level high type */
+ interrupt-names = "intr";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <8>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x14 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x14 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&its>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 0 0 119 4>,
+ <0000 0 0 2 &gic 0 0 0 120 4>,
+ <0000 0 0 3 &gic 0 0 0 121 4>,
+ <0000 0 0 4 &gic 0 0 0 122 4>;
+ };
+
+ pcie@3700000 {
+ compatible = "fsl,ls2080a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03700000 0x0 0x00100000 /* controller registers */
+ 0x16 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <0 123 0x4>; /* Level high type */
+ interrupt-names = "intr";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <4>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x16 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0x82000000 0x0 0x40000000 0x16 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ msi-parent = <&its>;
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic 0 0 0 124 4>,
+ <0000 0 0 2 &gic 0 0 0 125 4>,
+ <0000 0 0 3 &gic 0 0 0 126 4>,
+ <0000 0 0 4 &gic 0 0 0 127 4>;
+ };
+
+ sata0: sata@3200000 {
+ status = "disabled";
+ compatible = "fsl,ls2080a-ahci";
+ reg = <0x0 0x3200000 0x0 0x10000>;
+ interrupts = <0 133 0x4>; /* Level high type */
+ clocks = <&clockgen 4 3>;
+ };
+
+ sata1: sata@3210000 {
+ status = "disabled";
+ compatible = "fsl,ls2080a-ahci";
+ reg = <0x0 0x3210000 0x0 0x10000>;
+ interrupts = <0 136 0x4>; /* Level high type */
+ clocks = <&clockgen 4 3>;
+ };
+
+ usb0: usb3@3100000 {
+ status = "disabled";
+ compatible = "snps,dwc3";
+ reg = <0x0 0x3100000 0x0 0x10000>;
+ interrupts = <0 80 0x4>; /* Level high type */
+ dr_mode = "host";
+ };
+
+ usb1: usb3@3110000 {
+ status = "disabled";
+ compatible = "snps,dwc3";
+ reg = <0x0 0x3110000 0x0 0x10000>;
+ interrupts = <0 81 0x4>; /* Level high type */
+ dr_mode = "host";
+ };
+
+ ccn@4000000 {
+ compatible = "arm,ccn-504";
+ reg = <0x0 0x04000000 0x0 0x01000000>;
+ interrupts = <0 12 4>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi b/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi
deleted file mode 100644
index e281ceb..0000000
--- a/arch/arm64/boot/dts/freescale/fsl-ls2085a.dtsi
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Device Tree Include file for Freescale Layerscape-2085A family SoC.
- *
- * Copyright (C) 2014, Freescale Semiconductor
- *
- * Bhupesh Sharma <bhupesh.sharma@freescale.com>
- *
- * This file is dual-licensed: you can use it either under the terms
- * of the GPLv2 or the X11 license, at your option. Note that this dual
- * licensing only applies to this file, and not this project as a
- * whole.
- *
- * a) This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- * MA 02110-1301 USA
- *
- * Or, alternatively,
- *
- * b) Permission is hereby granted, free of charge, to any person
- * obtaining a copy of this software and associated documentation
- * files (the "Software"), to deal in the Software without
- * restriction, including without limitation the rights to use,
- * copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following
- * conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-/ {
- compatible = "fsl,ls2085a";
- interrupt-parent = <&gic>;
- #address-cells = <2>;
- #size-cells = <2>;
-
- cpus {
- #address-cells = <2>;
- #size-cells = <0>;
-
- /*
- * We expect the enable-method for cpu's to be "psci", but this
- * is dependent on the SoC FW, which will fill this in.
- *
- * Currently supported enable-method is psci v0.2
- */
-
- /* We have 4 clusters having 2 Cortex-A57 cores each */
- cpu@0 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x0>;
- };
-
- cpu@1 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x1>;
- };
-
- cpu@100 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x100>;
- };
-
- cpu@101 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x101>;
- };
-
- cpu@200 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x200>;
- };
-
- cpu@201 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x201>;
- };
-
- cpu@300 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x300>;
- };
-
- cpu@301 {
- device_type = "cpu";
- compatible = "arm,cortex-a57";
- reg = <0x0 0x301>;
- };
- };
-
- memory@80000000 {
- device_type = "memory";
- reg = <0x00000000 0x80000000 0 0x80000000>;
- /* DRAM space - 1, size : 2 GB DRAM */
- };
-
- gic: interrupt-controller@6000000 {
- compatible = "arm,gic-v3";
- reg = <0x0 0x06000000 0 0x10000>, /* GIC Dist */
- <0x0 0x06100000 0 0x100000>; /* GICR (RD_base + SGI_base) */
- #interrupt-cells = <3>;
- interrupt-controller;
- interrupts = <1 9 0x4>;
- };
-
- timer {
- compatible = "arm,armv8-timer";
- interrupts = <1 13 0x8>, /* Physical Secure PPI, active-low */
- <1 14 0x8>, /* Physical Non-Secure PPI, active-low */
- <1 11 0x8>, /* Virtual PPI, active-low */
- <1 10 0x8>; /* Hypervisor PPI, active-low */
- };
-
- serial0: serial@21c0500 {
- device_type = "serial";
- compatible = "fsl,ns16550", "ns16550a";
- reg = <0x0 0x21c0500 0x0 0x100>;
- clock-frequency = <0>; /* Updated by bootloader */
- interrupts = <0 32 0x1>; /* edge triggered */
- };
-
- serial1: serial@21c0600 {
- device_type = "serial";
- compatible = "fsl,ns16550", "ns16550a";
- reg = <0x0 0x21c0600 0x0 0x100>;
- clock-frequency = <0>; /* Updated by bootloader */
- interrupts = <0 32 0x1>; /* edge triggered */
- };
-
- fsl_mc: fsl-mc@80c000000 {
- compatible = "fsl,qoriq-mc";
- reg = <0x00000008 0x0c000000 0 0x40>, /* MC portal base */
- <0x00000000 0x08340000 0 0x40000>; /* MC control reg */
- };
-};
diff --git a/arch/arm64/boot/dts/hisilicon/Makefile b/arch/arm64/boot/dts/hisilicon/Makefile
index fa81a6e..cd158b8 100644
--- a/arch/arm64/boot/dts/hisilicon/Makefile
+++ b/arch/arm64/boot/dts/hisilicon/Makefile
@@ -1,4 +1,4 @@
-dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb
+dtb-$(CONFIG_ARCH_HISI) += hi6220-hikey.dtb hip05-d02.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
index e36a539..8d43a0f 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
+++ b/arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts
@@ -17,11 +17,14 @@
compatible = "hisilicon,hi6220-hikey", "hisilicon,hi6220";
aliases {
- serial0 = &uart0;
+ serial0 = &uart0; /* On board UART0 */
+ serial1 = &uart1; /* BT UART */
+ serial2 = &uart2; /* LS Expansion UART0 */
+ serial3 = &uart3; /* LS Expansion UART1 */
};
chosen {
- stdout-path = "serial0:115200n8";
+ stdout-path = "serial3:115200n8";
};
memory@0 {
diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
index 3f03380..82d2488 100644
--- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
+++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
@@ -5,6 +5,7 @@
*/
#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/clock/hi6220-clock.h>
/ {
compatible = "hisilicon,hi6220";
@@ -164,8 +165,48 @@
compatible = "arm,pl011", "arm,primecell";
reg = <0x0 0xf8015000 0x0 0x1000>;
interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&ao_ctrl 36>, <&ao_ctrl 36>;
+ clocks = <&ao_ctrl HI6220_UART0_PCLK>,
+ <&ao_ctrl HI6220_UART0_PCLK>;
clock-names = "uartclk", "apb_pclk";
};
+
+ uart1: uart@f7111000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf7111000 0x0 0x1000>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_ctrl HI6220_UART1_PCLK>,
+ <&sys_ctrl HI6220_UART1_PCLK>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "disabled";
+ };
+
+ uart2: uart@f7112000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf7112000 0x0 0x1000>;
+ interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_ctrl HI6220_UART2_PCLK>,
+ <&sys_ctrl HI6220_UART2_PCLK>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "disabled";
+ };
+
+ uart3: uart@f7113000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf7113000 0x0 0x1000>;
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_ctrl HI6220_UART3_PCLK>,
+ <&sys_ctrl HI6220_UART3_PCLK>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ uart4: uart@f7114000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0xf7114000 0x0 0x1000>;
+ interrupts = <GIC_SPI 40 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_ctrl HI6220_UART4_PCLK>,
+ <&sys_ctrl HI6220_UART4_PCLK>;
+ clock-names = "uartclk", "apb_pclk";
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm64/boot/dts/hisilicon/hip05-d02.dts b/arch/arm64/boot/dts/hisilicon/hip05-d02.dts
new file mode 100644
index 0000000..ae34e25
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hip05-d02.dts
@@ -0,0 +1,36 @@
+/**
+ * dts file for Hisilicon D02 Development Board
+ *
+ * Copyright (C) 2014,2015 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ */
+
+/dts-v1/;
+
+#include "hip05.dtsi"
+
+/ {
+ model = "Hisilicon Hip05 D02 Development Board";
+ compatible = "hisilicon,hip05-d02";
+
+ memory@00000000 {
+ device_type = "memory";
+ reg = <0x0 0x00000000 0x0 0x80000000>;
+ };
+
+ aliases {
+ serial0 = &uart0;
+ };
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/arch/arm64/boot/dts/hisilicon/hip05.dtsi b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
new file mode 100644
index 0000000..4ff16d0
--- /dev/null
+++ b/arch/arm64/boot/dts/hisilicon/hip05.dtsi
@@ -0,0 +1,271 @@
+/**
+ * dts file for Hisilicon D02 Development Board
+ *
+ * Copyright (C) 2014,2015 Hisilicon Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ *
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "hisilicon,hip05-d02";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ core2 {
+ cpu = <&cpu2>;
+ };
+ core3 {
+ cpu = <&cpu3>;
+ };
+ };
+ cluster1 {
+ core0 {
+ cpu = <&cpu4>;
+ };
+ core1 {
+ cpu = <&cpu5>;
+ };
+ core2 {
+ cpu = <&cpu6>;
+ };
+ core3 {
+ cpu = <&cpu7>;
+ };
+ };
+ cluster2 {
+ core0 {
+ cpu = <&cpu8>;
+ };
+ core1 {
+ cpu = <&cpu9>;
+ };
+ core2 {
+ cpu = <&cpu10>;
+ };
+ core3 {
+ cpu = <&cpu11>;
+ };
+ };
+ cluster3 {
+ core0 {
+ cpu = <&cpu12>;
+ };
+ core1 {
+ cpu = <&cpu13>;
+ };
+ core2 {
+ cpu = <&cpu14>;
+ };
+ core3 {
+ cpu = <&cpu15>;
+ };
+ };
+ };
+
+ cpu0: cpu@20000 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20000>;
+ enable-method = "psci";
+ };
+
+ cpu1: cpu@20001 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20001>;
+ enable-method = "psci";
+ };
+
+ cpu2: cpu@20002 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20002>;
+ enable-method = "psci";
+ };
+
+ cpu3: cpu@20003 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20003>;
+ enable-method = "psci";
+ };
+
+ cpu4: cpu@20100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20100>;
+ enable-method = "psci";
+ };
+
+ cpu5: cpu@20101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20101>;
+ enable-method = "psci";
+ };
+
+ cpu6: cpu@20102 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20102>;
+ enable-method = "psci";
+ };
+
+ cpu7: cpu@20103 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20103>;
+ enable-method = "psci";
+ };
+
+ cpu8: cpu@20200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20200>;
+ enable-method = "psci";
+ };
+
+ cpu9: cpu@20201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20201>;
+ enable-method = "psci";
+ };
+
+ cpu10: cpu@20202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20202>;
+ enable-method = "psci";
+ };
+
+ cpu11: cpu@20203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20203>;
+ enable-method = "psci";
+ };
+
+ cpu12: cpu@20300 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20300>;
+ enable-method = "psci";
+ };
+
+ cpu13: cpu@20301 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20301>;
+ enable-method = "psci";
+ };
+
+ cpu14: cpu@20302 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20302>;
+ enable-method = "psci";
+ };
+
+ cpu15: cpu@20303 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a57", "arm,armv8";
+ reg = <0x20303>;
+ enable-method = "psci";
+ };
+ };
+
+ gic: interrupt-controller@8d000000 {
+ compatible = "arm,gic-v3";
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+ interrupt-controller;
+ #redistributor-regions = <1>;
+ redistributor-stride = <0x0 0x30000>;
+ reg = <0x0 0x8d000000 0 0x10000>, /* GICD */
+ <0x0 0x8d100000 0 0x300000>, /* GICR */
+ <0x0 0xfe000000 0 0x10000>, /* GICC */
+ <0x0 0xfe010000 0 0x10000>, /* GICH */
+ <0x0 0xfe020000 0 0x10000>; /* GICV */
+ interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+
+ its_totems: interrupt-controller@8c000000 {
+ compatible = "arm,gic-v3-its";
+ msi-controller;
+ reg = <0x0 0x8c000000 0x0 0x40000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+ <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ refclk200mhz: refclk200mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <200000000>;
+ };
+
+ uart0: uart@80300000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x0 0x80300000 0x0 0x10000>;
+ interrupts = <GIC_SPI 317 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&refclk200mhz>;
+ clock-names = "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ uart1: uart@80310000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x0 0x80310000 0x0 0x10000>;
+ interrupts = <GIC_SPI 318 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&refclk200mhz>;
+ clock-names = "apb_pclk";
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/marvell/Makefile b/arch/arm64/boot/dts/marvell/Makefile
index e2f6afa..348f4db 100644
--- a/arch/arm64/boot/dts/marvell/Makefile
+++ b/arch/arm64/boot/dts/marvell/Makefile
@@ -1,4 +1,5 @@
dtb-$(CONFIG_ARCH_BERLIN) += berlin4ct-dmp.dtb
+dtb-$(CONFIG_ARCH_BERLIN) += berlin4ct-stb.dtb
always := $(dtb-y)
subdir-y := $(dts-dirs)
diff --git a/arch/arm64/boot/dts/marvell/berlin4ct-stb.dts b/arch/arm64/boot/dts/marvell/berlin4ct-stb.dts
new file mode 100644
index 0000000..348c37e
--- /dev/null
+++ b/arch/arm64/boot/dts/marvell/berlin4ct-stb.dts
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 Marvell Technology Group Ltd.
+ *
+ * Author: Jisheng Zhang <jszhang@marvell.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPLv2 or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "berlin4ct.dtsi"
+
+/ {
+ model = "Marvell BG4CT STB board";
+ compatible = "marvell,berlin4ct-stb", "marvell,berlin4ct", "marvell,berlin";
+
+ chosen {
+ stdout-path = "serial0:115200n8";
+ };
+
+ memory {
+ device_type = "memory";
+ /* the first 16MB is for firmwares' usage */
+ reg = <0 0x01000000 0 0x7f000000>;
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
index dd4a10d..a3b5f1d 100644
--- a/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
+++ b/arch/arm64/boot/dts/marvell/berlin4ct.dtsi
@@ -135,6 +135,96 @@
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ apb@e80000 {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0 0xe80000 0x10000>;
+ interrupt-parent = <&aic>;
+
+ gpio0: gpio@0400 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x0400 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porta: gpio-port@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0>;
+ };
+ };
+
+ gpio1: gpio@0800 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x0800 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ portb: gpio-port@1 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <1>;
+ };
+ };
+
+ gpio2: gpio@0c00 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x0c00 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ portc: gpio-port@2 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <2>;
+ };
+ };
+
+ gpio3: gpio@1000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x1000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ portd: gpio-port@3 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <3>;
+ };
+ };
+
+ aic: interrupt-controller@3800 {
+ compatible = "snps,dw-apb-ictl";
+ reg = <0x3800 0x30>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
@@ -151,6 +241,36 @@
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
};
+ sm_gpio0: gpio@8000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x8000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ porte: gpio-port@4 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ };
+ };
+
+ sm_gpio1: gpio@9000 {
+ compatible = "snps,dw-apb-gpio";
+ reg = <0x9000 0x400>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ portf: gpio-port@5 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <32>;
+ reg = <0>;
+ };
+ };
+
uart0: uart@d000 {
compatible = "snps,dw-apb-uart";
reg = <0xd000 0x100>;
diff --git a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
index 4be66ca..811cb76 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt8173-evb.dts
@@ -387,6 +387,24 @@
};
};
+&pio {
+ spi_pins_a: spi0 {
+ pins_spi {
+ pinmux = <MT8173_PIN_69_SPI_CK__FUNC_SPI_CK_0_>,
+ <MT8173_PIN_70_SPI_MI__FUNC_SPI_MI_0_>,
+ <MT8173_PIN_71_SPI_MO__FUNC_SPI_MO_0_>,
+ <MT8173_PIN_72_SPI_CS__FUNC_SPI_CS_0_>;
+ };
+ };
+};
+
+&spi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi_pins_a>;
+ mediatek,pad-select = <0>;
+ status = "okay";
+};
+
&uart0 {
status = "okay";
};
diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
index 06a1564..4dd5f93 100644
--- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi
@@ -116,6 +116,13 @@
clock-output-names = "clk32k";
};
+ cpum_ck: oscillator@2 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <0>;
+ clock-output-names = "cpum_ck";
+ };
+
timer {
compatible = "arm,armv8-timer";
interrupt-parent = <&gic>;
@@ -227,8 +234,10 @@
#power-domain-cells = <1>;
reg = <0 0x10006000 0 0x1000>;
clocks = <&clk26m>,
- <&topckgen CLK_TOP_MM_SEL>;
- clock-names = "mfg", "mm";
+ <&topckgen CLK_TOP_MM_SEL>,
+ <&topckgen CLK_TOP_VENC_SEL>,
+ <&topckgen CLK_TOP_VENC_LT_SEL>;
+ clock-names = "mfg", "mm", "venc", "venc_lt";
infracfg = <&infracfg>;
};
@@ -365,7 +374,20 @@
status = "disabled";
};
- i2c3: i2c3@11010000 {
+ spi: spi@1100a000 {
+ compatible = "mediatek,mt8173-spi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0 0x1100a000 0 0x1000>;
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
+ <&topckgen CLK_TOP_SPI_SEL>,
+ <&pericfg CLK_PERI_SPI0>;
+ clock-names = "parent-clk", "sel-clk", "spi-clk";
+ status = "disabled";
+ };
+
+ i2c3: i2c@11010000 {
compatible = "mediatek,mt8173-i2c";
reg = <0 0x11010000 0 0x70>,
<0 0x11000280 0 0x80>;
@@ -381,7 +403,7 @@
status = "disabled";
};
- i2c4: i2c4@11011000 {
+ i2c4: i2c@11011000 {
compatible = "mediatek,mt8173-i2c";
reg = <0 0x11011000 0 0x70>,
<0 0x11000300 0 0x80>;
@@ -397,7 +419,7 @@
status = "disabled";
};
- i2c6: i2c6@11013000 {
+ i2c6: i2c@11013000 {
compatible = "mediatek,mt8173-i2c";
reg = <0 0x11013000 0 0x70>,
<0 0x11000080 0 0x80>;
@@ -487,6 +509,36 @@
clock-names = "source", "hclk";
status = "disabled";
};
+
+ mmsys: clock-controller@14000000 {
+ compatible = "mediatek,mt8173-mmsys", "syscon";
+ reg = <0 0x14000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ imgsys: clock-controller@15000000 {
+ compatible = "mediatek,mt8173-imgsys", "syscon";
+ reg = <0 0x15000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ vdecsys: clock-controller@16000000 {
+ compatible = "mediatek,mt8173-vdecsys", "syscon";
+ reg = <0 0x16000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ vencsys: clock-controller@18000000 {
+ compatible = "mediatek,mt8173-vencsys", "syscon";
+ reg = <0 0x18000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
+
+ vencltsys: clock-controller@19000000 {
+ compatible = "mediatek,mt8173-vencltsys", "syscon";
+ reg = <0 0x19000000 0 0x1000>;
+ #clock-cells = <1>;
+ };
};
};
diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
index 66804ff..6b8abbe 100644
--- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
+++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
@@ -19,6 +19,7 @@
/ {
aliases {
serial0 = &blsp1_uart2;
+ serial1 = &blsp1_uart1;
};
chosen {
@@ -33,6 +34,31 @@
pinctrl-1 = <&blsp1_uart2_sleep>;
};
+ i2c@78b6000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
+ i2c@78b8000 {
+ /* On High speed expansion */
+ status = "okay";
+ };
+
+ i2c@78ba000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
+ spi@78b7000 {
+ /* On High speed expansion */
+ status = "okay";
+ };
+
+ spi@78b9000 {
+ /* On Low speed expansion */
+ status = "okay";
+ };
+
leds {
pinctrl-names = "default";
pinctrl-0 = <&msmgpio_leds>,
@@ -85,3 +111,7 @@
};
};
};
+
+&sdhc_1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
index 5689568..49ec55a 100644
--- a/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916-pins.dtsi
@@ -13,6 +13,30 @@
&msmgpio {
+ blsp1_uart1_default: blsp1_uart1_default {
+ pinmux {
+ function = "blsp_uart1";
+ pins = "gpio0", "gpio1";
+ };
+ pinconf {
+ pins = "gpio0", "gpio1";
+ drive-strength = <16>;
+ bias-disable;
+ };
+ };
+
+ blsp1_uart1_sleep: blsp1_uart1_sleep {
+ pinmux {
+ function = "gpio";
+ pins = "gpio0", "gpio1";
+ };
+ pinconf {
+ pins = "gpio0", "gpio1";
+ drive-strength = <2>;
+ bias-pull-down;
+ };
+ };
+
blsp1_uart2_default: blsp1_uart2_default {
pinmux {
function = "blsp_uart2";
@@ -27,7 +51,7 @@
blsp1_uart2_sleep: blsp1_uart2_sleep {
pinmux {
- function = "blsp_uart2";
+ function = "gpio";
pins = "gpio4", "gpio5";
};
pinconf {
@@ -241,6 +265,30 @@
};
};
+ i2c2_default: i2c2_default {
+ pinmux {
+ function = "blsp_i2c2";
+ pins = "gpio6", "gpio7";
+ };
+ pinconf {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ i2c2_sleep: i2c2_sleep {
+ pinmux {
+ function = "gpio";
+ pins = "gpio6", "gpio7";
+ };
+ pinconf {
+ pins = "gpio6", "gpio7";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
i2c4_default: i2c4_default {
pinmux {
function = "blsp_i2c4";
@@ -255,7 +303,7 @@
i2c4_sleep: i2c4_sleep {
pinmux {
- function = "blsp_i2c4";
+ function = "gpio";
pins = "gpio14", "gpio15";
};
pinconf {
@@ -265,6 +313,30 @@
};
};
+ i2c6_default: i2c6_default {
+ pinmux {
+ function = "blsp_i2c6";
+ pins = "gpio22", "gpio23";
+ };
+ pinconf {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
+ i2c6_sleep: i2c6_sleep {
+ pinmux {
+ function = "gpio";
+ pins = "gpio22", "gpio23";
+ };
+ pinconf {
+ pins = "gpio22", "gpio23";
+ drive-strength = <2>;
+ bias-disable = <0>;
+ };
+ };
+
sdhc2_cd_pin {
sdc2_cd_on: cd_on {
pinmux {
diff --git a/arch/arm64/boot/dts/qcom/msm8916.dtsi b/arch/arm64/boot/dts/qcom/msm8916.dtsi
index 5911de0..8d184ff1 100644
--- a/arch/arm64/boot/dts/qcom/msm8916.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8916.dtsi
@@ -99,9 +99,19 @@
compatible = "qcom,gcc-msm8916";
#clock-cells = <1>;
#reset-cells = <1>;
+ #power-domain-cells = <1>;
reg = <0x1800000 0x80000>;
};
+ blsp1_uart1: serial@78af000 {
+ compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
+ reg = <0x78af000 0x200>;
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&gcc GCC_BLSP1_UART1_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+ clock-names = "core", "iface";
+ status = "disabled";
+ };
+
blsp1_uart2: serial@78b0000 {
compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm";
reg = <0x78b0000 0x200>;
@@ -224,6 +234,21 @@
status = "disabled";
};
+ blsp_i2c2: i2c@78b6000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x78b6000 0x1000>;
+ interrupts = <GIC_SPI 96 0>;
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>,
+ <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>;
+ clock-names = "iface", "core";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c2_default>;
+ pinctrl-1 = <&i2c2_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
blsp_i2c4: i2c@78b8000 {
compatible = "qcom,i2c-qup-v2.2.1";
reg = <0x78b8000 0x1000>;
@@ -239,6 +264,21 @@
status = "disabled";
};
+ blsp_i2c6: i2c@78ba000 {
+ compatible = "qcom,i2c-qup-v2.2.1";
+ reg = <0x78ba000 0x1000>;
+ interrupts = <GIC_SPI 100 0>;
+ clocks = <&gcc GCC_BLSP1_AHB_CLK>,
+ <&gcc GCC_BLSP1_QUP6_I2C_APPS_CLK>;
+ clock-names = "iface", "core";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c6_default>;
+ pinctrl-1 = <&i2c6_sleep>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
sdhc_1: sdhci@07824000 {
compatible = "qcom,sdhci-msm-v4";
reg = <0x07824900 0x11c>, <0x07824000 0x800>;
@@ -390,6 +430,13 @@
interrupt-controller;
#interrupt-cells = <4>;
};
+
+ rng@22000 {
+ compatible = "qcom,prng";
+ reg = <0x00022000 0x200>;
+ clocks = <&gcc GCC_PRNG_AHB_CLK>;
+ clock-names = "core";
+ };
};
};
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 5f76034..bdd7aa3 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -34,11 +34,12 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_ARCH_BCM_IPROC=y
CONFIG_ARCH_BERLIN=y
CONFIG_ARCH_EXYNOS7=y
-CONFIG_ARCH_FSL_LS2085A=y
+CONFIG_ARCH_LAYERSCAPE=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_MEDIATEK=y
CONFIG_ARCH_ROCKCHIP=y
CONFIG_ARCH_SEATTLE=y
+CONFIG_ARCH_STRATIX10=y
CONFIG_ARCH_TEGRA=y
CONFIG_ARCH_TEGRA_132_SOC=y
CONFIG_ARCH_QCOM=y
@@ -49,6 +50,7 @@ CONFIG_ARCH_XGENE=y
CONFIG_ARCH_ZYNQMP=y
CONFIG_PCI=y
CONFIG_PCI_MSI=y
+CONFIG_PCI_HOST_GENERIC=y
CONFIG_PCI_XGENE=y
CONFIG_SMP=y
CONFIG_SCHED_MC=y
@@ -121,8 +123,11 @@ CONFIG_SERIAL_XILINX_PS_UART=y
CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
CONFIG_VIRTIO_CONSOLE=y
# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_I2C_QUP=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
+CONFIG_SPI_QUP=y
CONFIG_PINCTRL_MSM8916=y
CONFIG_GPIO_PL061=y
CONFIG_GPIO_XGENE=y
@@ -131,6 +136,7 @@ CONFIG_POWER_RESET_SYSCON=y
# CONFIG_HWMON is not set
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_REGULATOR_QCOM_SMD_RPM=y
CONFIG_FB=y
CONFIG_FB_ARMCLCD=y
CONFIG_FRAMEBUFFER_CONSOLE=y
@@ -163,12 +169,18 @@ CONFIG_LEDS_TRIGGER_CPU=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_EFI=y
CONFIG_RTC_DRV_XGENE=y
+CONFIG_DMADEVICES=y
+CONFIG_QCOM_BAM_DMA=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO_BALLOON=y
CONFIG_VIRTIO_MMIO=y
CONFIG_COMMON_CLK_QCOM=y
CONFIG_MSM_GCC_8916=y
+CONFIG_HWSPINLOCK_QCOM=y
# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_QCOM_SMEM=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SMD_RPM=y
CONFIG_PHY_XGENE=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
@@ -212,3 +224,4 @@ CONFIG_CRYPTO_GHASH_ARM64_CE=y
CONFIG_CRYPTO_AES_ARM64_CE_CCM=y
CONFIG_CRYPTO_AES_ARM64_CE_BLK=y
CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y
+CONFIG_CRYPTO_CRC32_ARM64=y
diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c
index ce47792..f7bd9bf 100644
--- a/arch/arm64/crypto/aes-ce-cipher.c
+++ b/arch/arm64/crypto/aes-ce-cipher.c
@@ -237,7 +237,7 @@ EXPORT_SYMBOL(ce_aes_setkey);
static struct crypto_alg aes_alg = {
.cra_name = "aes",
.cra_driver_name = "aes-ce",
- .cra_priority = 300,
+ .cra_priority = 250,
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct crypto_aes_ctx),
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
index d56ec07..e4962f0 100644
--- a/arch/arm64/include/asm/alternative.h
+++ b/arch/arm64/include/asm/alternative.h
@@ -19,7 +19,6 @@ struct alt_instr {
void __init apply_alternatives_all(void);
void apply_alternatives(void *start, size_t length);
-void free_alternatives_memory(void);
#define ALTINSTR_ENTRY(feature) \
" .word 661b - .\n" /* label */ \
diff --git a/arch/arm64/include/asm/arch_gicv3.h b/arch/arm64/include/asm/arch_gicv3.h
index 030cdcb..2731d3b 100644
--- a/arch/arm64/include/asm/arch_gicv3.h
+++ b/arch/arm64/include/asm/arch_gicv3.h
@@ -77,6 +77,7 @@
#ifndef __ASSEMBLY__
#include <linux/stringify.h>
+#include <asm/barrier.h>
/*
* Low-level accessors
diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 12eff92..bb7b727 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -193,6 +193,17 @@ lr .req x30 // link register
str \src, [\tmp, :lo12:\sym]
.endm
+ /*
+ * @sym: The name of the per-cpu variable
+ * @reg: Result of per_cpu(sym, smp_processor_id())
+ * @tmp: scratch register
+ */
+ .macro this_cpu_ptr, sym, reg, tmp
+ adr_l \reg, \sym
+ mrs \tmp, tpidr_el1
+ add \reg, \reg, \tmp
+ .endm
+
/*
* Annotate a function as position independent, i.e., safe to be called before
* the kernel virtual mapping is activated.
diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h
index 74d0b8e..f61c84f 100644
--- a/arch/arm64/include/asm/atomic_ll_sc.h
+++ b/arch/arm64/include/asm/atomic_ll_sc.h
@@ -233,7 +233,7 @@ __CMPXCHG_CASE( , , mb_8, dmb ish, , l, "memory")
#undef __CMPXCHG_CASE
#define __CMPXCHG_DBL(name, mb, rel, cl) \
-__LL_SC_INLINE int \
+__LL_SC_INLINE long \
__LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \
unsigned long old2, \
unsigned long new1, \
diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h
index 1fce790..197e06a 100644
--- a/arch/arm64/include/asm/atomic_lse.h
+++ b/arch/arm64/include/asm/atomic_lse.h
@@ -387,7 +387,7 @@ __CMPXCHG_CASE(x, , mb_8, al, "memory")
#define __LL_SC_CMPXCHG_DBL(op) __LL_SC_CALL(__cmpxchg_double##op)
#define __CMPXCHG_DBL(name, mb, cl...) \
-static inline int __cmpxchg_double##name(unsigned long old1, \
+static inline long __cmpxchg_double##name(unsigned long old1, \
unsigned long old2, \
unsigned long new1, \
unsigned long new2, \
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 624f967..9622eb4 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -64,27 +64,31 @@ do { \
#define smp_load_acquire(p) \
({ \
- typeof(*p) ___p1; \
+ union { typeof(*p) __val; char __c[1]; } __u; \
compiletime_assert_atomic_type(*p); \
switch (sizeof(*p)) { \
case 1: \
asm volatile ("ldarb %w0, %1" \
- : "=r" (___p1) : "Q" (*p) : "memory"); \
+ : "=r" (*(__u8 *)__u.__c) \
+ : "Q" (*p) : "memory"); \
break; \
case 2: \
asm volatile ("ldarh %w0, %1" \
- : "=r" (___p1) : "Q" (*p) : "memory"); \
+ : "=r" (*(__u16 *)__u.__c) \
+ : "Q" (*p) : "memory"); \
break; \
case 4: \
asm volatile ("ldar %w0, %1" \
- : "=r" (___p1) : "Q" (*p) : "memory"); \
+ : "=r" (*(__u32 *)__u.__c) \
+ : "Q" (*p) : "memory"); \
break; \
case 8: \
asm volatile ("ldar %0, %1" \
- : "=r" (___p1) : "Q" (*p) : "memory"); \
+ : "=r" (*(__u64 *)__u.__c) \
+ : "Q" (*p) : "memory"); \
break; \
} \
- ___p1; \
+ __u.__val; \
})
#define read_barrier_depends() do { } while(0)
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 54efeda..7fc294c 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -68,6 +68,7 @@
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void flush_icache_range(unsigned long start, unsigned long end);
extern void __flush_dcache_area(void *addr, size_t len);
+extern void __clean_dcache_area_pou(void *addr, size_t len);
extern long __flush_cache_user_range(unsigned long start, unsigned long end);
static inline void flush_cache_mm(struct mm_struct *mm)
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index 9ea611e..510c7b4 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -19,7 +19,6 @@
#define __ASM_CMPXCHG_H
#include <linux/bug.h>
-#include <linux/mmdebug.h>
#include <asm/atomic.h>
#include <asm/barrier.h>
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 7fbed69..eb8432b 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -23,7 +23,6 @@
*/
#include <linux/types.h>
#include <linux/sched.h>
-#include <linux/ptrace.h>
#define COMPAT_USER_HZ 100
#ifdef __AARCH64EB__
@@ -234,7 +233,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
return (u32)(unsigned long)uptr;
}
-#define compat_user_stack_pointer() (user_stack_pointer(current_pt_regs()))
+#define compat_user_stack_pointer() (user_stack_pointer(task_pt_regs(current)))
static inline void __user *arch_compat_alloc_user_space(long len)
{
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 11d5bb0f..8f271b8 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -29,8 +29,9 @@
#define ARM64_HAS_PAN 4
#define ARM64_HAS_LSE_ATOMICS 5
#define ARM64_WORKAROUND_CAVIUM_23154 6
+#define ARM64_WORKAROUND_834220 7
-#define ARM64_NCAPS 7
+#define ARM64_NCAPS 8
#ifndef __ASSEMBLY__
@@ -46,8 +47,12 @@ enum ftr_type {
#define FTR_STRICT true /* SANITY check strict matching required */
#define FTR_NONSTRICT false /* SANITY check ignored */
+#define FTR_SIGNED true /* Value should be treated as signed */
+#define FTR_UNSIGNED false /* Value should be treated as unsigned */
+
struct arm64_ftr_bits {
- bool strict; /* CPU Sanity check: strict matching required ? */
+ bool sign; /* Value is signed ? */
+ bool strict; /* CPU Sanity check: strict matching required ? */
enum ftr_type type;
u8 shift;
u8 width;
@@ -123,6 +128,18 @@ cpuid_feature_extract_field(u64 features, int field)
return cpuid_feature_extract_field_width(features, field, 4);
}
+static inline unsigned int __attribute_const__
+cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
+{
+ return (u64)(features << (64 - width - field)) >> (64 - width);
+}
+
+static inline unsigned int __attribute_const__
+cpuid_feature_extract_unsigned_field(u64 features, int field)
+{
+ return cpuid_feature_extract_unsigned_field_width(features, field, 4);
+}
+
static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp)
{
return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
@@ -130,7 +147,9 @@ static inline u64 arm64_ftr_mask(struct arm64_ftr_bits *ftrp)
static inline s64 arm64_ftr_value(struct arm64_ftr_bits *ftrp, u64 val)
{
- return cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width);
+ return ftrp->sign ?
+ cpuid_feature_extract_field_width(val, ftrp->shift, ftrp->width) :
+ cpuid_feature_extract_unsigned_field_width(val, ftrp->shift, ftrp->width);
}
static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h
index 54d0ead..61e08f3 100644
--- a/arch/arm64/include/asm/dma-mapping.h
+++ b/arch/arm64/include/asm/dma-mapping.h
@@ -18,7 +18,6 @@
#ifdef __KERNEL__
-#include <linux/acpi.h>
#include <linux/types.h>
#include <linux/vmalloc.h>
@@ -26,22 +25,16 @@
#include <asm/xen/hypervisor.h>
#define DMA_ERROR_CODE (~(dma_addr_t)0)
-extern struct dma_map_ops *dma_ops;
extern struct dma_map_ops dummy_dma_ops;
static inline struct dma_map_ops *__generic_dma_ops(struct device *dev)
{
- if (unlikely(!dev))
- return dma_ops;
- else if (dev->archdata.dma_ops)
+ if (dev && dev->archdata.dma_ops)
return dev->archdata.dma_ops;
- else if (acpi_disabled)
- return dma_ops;
/*
- * When ACPI is enabled, if arch_set_dma_ops is not called,
- * we will disable device DMA capability by setting it
- * to dummy_dma_ops.
+ * We expect no ISA devices, and all other DMA masters are expected to
+ * have someone call arch_setup_dma_ops at device creation time.
*/
return &dummy_dma_ops;
}
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h
index ef57220..8e88a69 100644
--- a/arch/arm64/include/asm/efi.h
+++ b/arch/arm64/include/asm/efi.h
@@ -2,7 +2,9 @@
#define _ASM_EFI_H
#include <asm/io.h>
+#include <asm/mmu_context.h>
#include <asm/neon.h>
+#include <asm/tlbflush.h>
#ifdef CONFIG_EFI
extern void efi_init(void);
@@ -10,6 +12,8 @@ extern void efi_init(void);
#define efi_init()
#endif
+int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md);
+
#define efi_call_virt(f, ...) \
({ \
efi_##f##_t *__f; \
@@ -63,6 +67,11 @@ extern void efi_init(void);
* Services are enabled and the EFI_RUNTIME_SERVICES bit set.
*/
+static inline void efi_set_pgd(struct mm_struct *mm)
+{
+ switch_mm(NULL, mm, NULL);
+}
+
void efi_virtmap_load(void);
void efi_virtmap_unload(void);
diff --git a/arch/arm64/include/asm/ftrace.h b/arch/arm64/include/asm/ftrace.h
index c5534fa..3c60f37 100644
--- a/arch/arm64/include/asm/ftrace.h
+++ b/arch/arm64/include/asm/ftrace.h
@@ -28,6 +28,8 @@ struct dyn_arch_ftrace {
extern unsigned long ftrace_graph_call;
+extern void return_to_handler(void);
+
static inline unsigned long ftrace_call_adjust(unsigned long addr)
{
/*
diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h
index bb4052e..bbc1e35 100644
--- a/arch/arm64/include/asm/hugetlb.h
+++ b/arch/arm64/include/asm/hugetlb.h
@@ -26,36 +26,7 @@ static inline pte_t huge_ptep_get(pte_t *ptep)
return *ptep;
}
-static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t pte)
-{
- set_pte_at(mm, addr, ptep, pte);
-}
-
-static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
- unsigned long addr, pte_t *ptep)
-{
- ptep_clear_flush(vma, addr, ptep);
-}
-
-static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- ptep_set_wrprotect(mm, addr, ptep);
-}
-static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep)
-{
- return ptep_get_and_clear(mm, addr, ptep);
-}
-
-static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
- unsigned long addr, pte_t *ptep,
- pte_t pte, int dirty)
-{
- return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
-}
static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
unsigned long addr, unsigned long end,
@@ -97,4 +68,19 @@ static inline void arch_clear_hugepage_flags(struct page *page)
clear_bit(PG_dcache_clean, &page->flags);
}
+extern pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+ struct page *page, int writable);
+#define arch_make_huge_pte arch_make_huge_pte
+extern void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+extern int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty);
+extern pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
+extern void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
+extern void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep);
+
#endif /* __ASM_HUGETLB_H */
diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h
index e54415e..9732908 100644
--- a/arch/arm64/include/asm/hw_breakpoint.h
+++ b/arch/arm64/include/asm/hw_breakpoint.h
@@ -138,16 +138,18 @@ extern struct pmu perf_ops_bp;
/* Determine number of BRP registers available. */
static inline int get_num_brps(void)
{
+ u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1);
return 1 +
- cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
+ cpuid_feature_extract_unsigned_field(dfr0,
ID_AA64DFR0_BRPS_SHIFT);
}
/* Determine number of WRP registers available. */
static inline int get_num_wrps(void)
{
+ u64 dfr0 = read_system_reg(SYS_ID_AA64DFR0_EL1);
return 1 +
- cpuid_feature_extract_field(read_system_reg(SYS_ID_AA64DFR0_EL1),
+ cpuid_feature_extract_unsigned_field(dfr0,
ID_AA64DFR0_WRPS_SHIFT);
}
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index 23eb450..b77197d 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -1,10 +1,60 @@
#ifndef __ASM_IRQ_H
#define __ASM_IRQ_H
+#define IRQ_STACK_SIZE THREAD_SIZE
+#define IRQ_STACK_START_SP THREAD_START_SP
+
+#ifndef __ASSEMBLER__
+
+#include <linux/percpu.h>
+
#include <asm-generic/irq.h>
+#include <asm/thread_info.h>
struct pt_regs;
+DECLARE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack);
+
+/*
+ * The highest address on the stack, and the first to be used. Used to
+ * find the dummy-stack frame put down by el?_irq() in entry.S, which
+ * is structured as follows:
+ *
+ * ------------
+ * | | <- irq_stack_ptr
+ * top ------------
+ * | x19 | <- irq_stack_ptr - 0x08
+ * ------------
+ * | x29 | <- irq_stack_ptr - 0x10
+ * ------------
+ *
+ * where x19 holds a copy of the task stack pointer where the struct pt_regs
+ * from kernel_entry can be found.
+ *
+ */
+#define IRQ_STACK_PTR(cpu) ((unsigned long)per_cpu(irq_stack, cpu) + IRQ_STACK_START_SP)
+
+/*
+ * The offset from irq_stack_ptr where entry.S will store the original
+ * stack pointer. Used by unwind_frame() and dump_backtrace().
+ */
+#define IRQ_STACK_TO_TASK_STACK(ptr) (*((unsigned long *)((ptr) - 0x08)))
+
extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
+static inline int nr_legacy_irqs(void)
+{
+ return 0;
+}
+
+static inline bool on_irq_stack(unsigned long sp, int cpu)
+{
+ /* variable names the same as kernel/stacktrace.c */
+ unsigned long low = (unsigned long)per_cpu(irq_stack, cpu);
+ unsigned long high = low + IRQ_STACK_START_SP;
+
+ return (low <= sp && sp <= high);
+}
+
+#endif /* !__ASSEMBLER__ */
#endif
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 5e6857b..738a95f 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -125,6 +125,7 @@
#define VTCR_EL2_SL0_LVL1 (1 << 6)
#define VTCR_EL2_T0SZ_MASK 0x3f
#define VTCR_EL2_T0SZ_40B 24
+#define VTCR_EL2_VS 19
/*
* We configure the Stage-2 page tables to always restrict the IPA space to be
@@ -169,7 +170,7 @@
#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
#define VTTBR_VMID_SHIFT (UL(48))
-#define VTTBR_VMID_MASK (UL(0xFF) << VTTBR_VMID_SHIFT)
+#define VTTBR_VMID_MASK(size) (_AT(u64, (1 << size) - 1) << VTTBR_VMID_SHIFT)
/* Hyp System Trap Register */
#define HSTR_EL2_T(x) (1 << x)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 5e37710..52b777b 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -20,82 +20,6 @@
#include <asm/virt.h>
-/*
- * 0 is reserved as an invalid value.
- * Order *must* be kept in sync with the hyp switch code.
- */
-#define MPIDR_EL1 1 /* MultiProcessor Affinity Register */
-#define CSSELR_EL1 2 /* Cache Size Selection Register */
-#define SCTLR_EL1 3 /* System Control Register */
-#define ACTLR_EL1 4 /* Auxiliary Control Register */
-#define CPACR_EL1 5 /* Coprocessor Access Control */
-#define TTBR0_EL1 6 /* Translation Table Base Register 0 */
-#define TTBR1_EL1 7 /* Translation Table Base Register 1 */
-#define TCR_EL1 8 /* Translation Control Register */
-#define ESR_EL1 9 /* Exception Syndrome Register */
-#define AFSR0_EL1 10 /* Auxilary Fault Status Register 0 */
-#define AFSR1_EL1 11 /* Auxilary Fault Status Register 1 */
-#define FAR_EL1 12 /* Fault Address Register */
-#define MAIR_EL1 13 /* Memory Attribute Indirection Register */
-#define VBAR_EL1 14 /* Vector Base Address Register */
-#define CONTEXTIDR_EL1 15 /* Context ID Register */
-#define TPIDR_EL0 16 /* Thread ID, User R/W */
-#define TPIDRRO_EL0 17 /* Thread ID, User R/O */
-#define TPIDR_EL1 18 /* Thread ID, Privileged */
-#define AMAIR_EL1 19 /* Aux Memory Attribute Indirection Register */
-#define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */
-#define PAR_EL1 21 /* Physical Address Register */
-#define MDSCR_EL1 22 /* Monitor Debug System Control Register */
-#define MDCCINT_EL1 23 /* Monitor Debug Comms Channel Interrupt Enable Reg */
-
-/* 32bit specific registers. Keep them at the end of the range */
-#define DACR32_EL2 24 /* Domain Access Control Register */
-#define IFSR32_EL2 25 /* Instruction Fault Status Register */
-#define FPEXC32_EL2 26 /* Floating-Point Exception Control Register */
-#define DBGVCR32_EL2 27 /* Debug Vector Catch Register */
-#define NR_SYS_REGS 28
-
-/* 32bit mapping */
-#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
-#define c0_CSSELR (CSSELR_EL1 * 2)/* Cache Size Selection Register */
-#define c1_SCTLR (SCTLR_EL1 * 2) /* System Control Register */
-#define c1_ACTLR (ACTLR_EL1 * 2) /* Auxiliary Control Register */
-#define c1_CPACR (CPACR_EL1 * 2) /* Coprocessor Access Control */
-#define c2_TTBR0 (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
-#define c2_TTBR0_high (c2_TTBR0 + 1) /* TTBR0 top 32 bits */
-#define c2_TTBR1 (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
-#define c2_TTBR1_high (c2_TTBR1 + 1) /* TTBR1 top 32 bits */
-#define c2_TTBCR (TCR_EL1 * 2) /* Translation Table Base Control R. */
-#define c3_DACR (DACR32_EL2 * 2)/* Domain Access Control Register */
-#define c5_DFSR (ESR_EL1 * 2) /* Data Fault Status Register */
-#define c5_IFSR (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
-#define c5_ADFSR (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
-#define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
-#define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */
-#define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */
-#define c7_PAR (PAR_EL1 * 2) /* Physical Address Register */
-#define c7_PAR_high (c7_PAR + 1) /* PAR top 32 bits */
-#define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */
-#define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
-#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */
-#define c13_CID (CONTEXTIDR_EL1 * 2) /* Context ID Register */
-#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
-#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
-#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
-#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
-#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
-#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
-
-#define cp14_DBGDSCRext (MDSCR_EL1 * 2)
-#define cp14_DBGBCR0 (DBGBCR0_EL1 * 2)
-#define cp14_DBGBVR0 (DBGBVR0_EL1 * 2)
-#define cp14_DBGBXVR0 (cp14_DBGBVR0 + 1)
-#define cp14_DBGWCR0 (DBGWCR0_EL1 * 2)
-#define cp14_DBGWVR0 (DBGWVR0_EL1 * 2)
-#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
-
-#define NR_COPRO_REGS (NR_SYS_REGS * 2)
-
#define ARM_EXCEPTION_IRQ 0
#define ARM_EXCEPTION_TRAP 1
diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
index 17e92f0..3066328 100644
--- a/arch/arm64/include/asm/kvm_emulate.h
+++ b/arch/arm64/include/asm/kvm_emulate.h
@@ -26,7 +26,6 @@
#include <asm/esr.h>
#include <asm/kvm_arm.h>
-#include <asm/kvm_asm.h>
#include <asm/kvm_mmio.h>
#include <asm/ptrace.h>
#include <asm/cputype.h>
@@ -99,12 +98,22 @@ static inline void vcpu_set_thumb(struct kvm_vcpu *vcpu)
*vcpu_cpsr(vcpu) |= COMPAT_PSR_T_BIT;
}
-static inline unsigned long *vcpu_reg(const struct kvm_vcpu *vcpu, u8 reg_num)
+/*
+ * vcpu_get_reg and vcpu_set_reg should always be passed a register number
+ * coming from a read of ESR_EL2. Otherwise, it may give the wrong result on
+ * AArch32 with banked registers.
+ */
+static inline unsigned long vcpu_get_reg(const struct kvm_vcpu *vcpu,
+ u8 reg_num)
{
- if (vcpu_mode_is_32bit(vcpu))
- return vcpu_reg32(vcpu, reg_num);
+ return (reg_num == 31) ? 0 : vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+}
- return (unsigned long *)&vcpu_gp_regs(vcpu)->regs.regs[reg_num];
+static inline void vcpu_set_reg(struct kvm_vcpu *vcpu, u8 reg_num,
+ unsigned long val)
+{
+ if (reg_num != 31)
+ vcpu_gp_regs(vcpu)->regs.regs[reg_num] = val;
}
/* Get vcpu SPSR for current mode */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index a35ce72..689d4c9 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -25,7 +25,6 @@
#include <linux/types.h>
#include <linux/kvm_types.h>
#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
#include <asm/kvm_mmio.h>
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -85,6 +84,86 @@ struct kvm_vcpu_fault_info {
u64 hpfar_el2; /* Hyp IPA Fault Address Register */
};
+/*
+ * 0 is reserved as an invalid value.
+ * Order should be kept in sync with the save/restore code.
+ */
+enum vcpu_sysreg {
+ __INVALID_SYSREG__,
+ MPIDR_EL1, /* MultiProcessor Affinity Register */
+ CSSELR_EL1, /* Cache Size Selection Register */
+ SCTLR_EL1, /* System Control Register */
+ ACTLR_EL1, /* Auxiliary Control Register */
+ CPACR_EL1, /* Coprocessor Access Control */
+ TTBR0_EL1, /* Translation Table Base Register 0 */
+ TTBR1_EL1, /* Translation Table Base Register 1 */
+ TCR_EL1, /* Translation Control Register */
+ ESR_EL1, /* Exception Syndrome Register */
+ AFSR0_EL1, /* Auxilary Fault Status Register 0 */
+ AFSR1_EL1, /* Auxilary Fault Status Register 1 */
+ FAR_EL1, /* Fault Address Register */
+ MAIR_EL1, /* Memory Attribute Indirection Register */
+ VBAR_EL1, /* Vector Base Address Register */
+ CONTEXTIDR_EL1, /* Context ID Register */
+ TPIDR_EL0, /* Thread ID, User R/W */
+ TPIDRRO_EL0, /* Thread ID, User R/O */
+ TPIDR_EL1, /* Thread ID, Privileged */
+ AMAIR_EL1, /* Aux Memory Attribute Indirection Register */
+ CNTKCTL_EL1, /* Timer Control Register (EL1) */
+ PAR_EL1, /* Physical Address Register */
+ MDSCR_EL1, /* Monitor Debug System Control Register */
+ MDCCINT_EL1, /* Monitor Debug Comms Channel Interrupt Enable Reg */
+
+ /* 32bit specific registers. Keep them at the end of the range */
+ DACR32_EL2, /* Domain Access Control Register */
+ IFSR32_EL2, /* Instruction Fault Status Register */
+ FPEXC32_EL2, /* Floating-Point Exception Control Register */
+ DBGVCR32_EL2, /* Debug Vector Catch Register */
+
+ NR_SYS_REGS /* Nothing after this line! */
+};
+
+/* 32bit mapping */
+#define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */
+#define c0_CSSELR (CSSELR_EL1 * 2)/* Cache Size Selection Register */
+#define c1_SCTLR (SCTLR_EL1 * 2) /* System Control Register */
+#define c1_ACTLR (ACTLR_EL1 * 2) /* Auxiliary Control Register */
+#define c1_CPACR (CPACR_EL1 * 2) /* Coprocessor Access Control */
+#define c2_TTBR0 (TTBR0_EL1 * 2) /* Translation Table Base Register 0 */
+#define c2_TTBR0_high (c2_TTBR0 + 1) /* TTBR0 top 32 bits */
+#define c2_TTBR1 (TTBR1_EL1 * 2) /* Translation Table Base Register 1 */
+#define c2_TTBR1_high (c2_TTBR1 + 1) /* TTBR1 top 32 bits */
+#define c2_TTBCR (TCR_EL1 * 2) /* Translation Table Base Control R. */
+#define c3_DACR (DACR32_EL2 * 2)/* Domain Access Control Register */
+#define c5_DFSR (ESR_EL1 * 2) /* Data Fault Status Register */
+#define c5_IFSR (IFSR32_EL2 * 2)/* Instruction Fault Status Register */
+#define c5_ADFSR (AFSR0_EL1 * 2) /* Auxiliary Data Fault Status R */
+#define c5_AIFSR (AFSR1_EL1 * 2) /* Auxiliary Instr Fault Status R */
+#define c6_DFAR (FAR_EL1 * 2) /* Data Fault Address Register */
+#define c6_IFAR (c6_DFAR + 1) /* Instruction Fault Address Register */
+#define c7_PAR (PAR_EL1 * 2) /* Physical Address Register */
+#define c7_PAR_high (c7_PAR + 1) /* PAR top 32 bits */
+#define c10_PRRR (MAIR_EL1 * 2) /* Primary Region Remap Register */
+#define c10_NMRR (c10_PRRR + 1) /* Normal Memory Remap Register */
+#define c12_VBAR (VBAR_EL1 * 2) /* Vector Base Address Register */
+#define c13_CID (CONTEXTIDR_EL1 * 2) /* Context ID Register */
+#define c13_TID_URW (TPIDR_EL0 * 2) /* Thread ID, User R/W */
+#define c13_TID_URO (TPIDRRO_EL0 * 2)/* Thread ID, User R/O */
+#define c13_TID_PRIV (TPIDR_EL1 * 2) /* Thread ID, Privileged */
+#define c10_AMAIR0 (AMAIR_EL1 * 2) /* Aux Memory Attr Indirection Reg */
+#define c10_AMAIR1 (c10_AMAIR0 + 1)/* Aux Memory Attr Indirection Reg */
+#define c14_CNTKCTL (CNTKCTL_EL1 * 2) /* Timer Control Register (PL1) */
+
+#define cp14_DBGDSCRext (MDSCR_EL1 * 2)
+#define cp14_DBGBCR0 (DBGBCR0_EL1 * 2)
+#define cp14_DBGBVR0 (DBGBVR0_EL1 * 2)
+#define cp14_DBGBXVR0 (cp14_DBGBVR0 + 1)
+#define cp14_DBGWCR0 (DBGWCR0_EL1 * 2)
+#define cp14_DBGWVR0 (DBGWVR0_EL1 * 2)
+#define cp14_DBGDCCINT (MDCCINT_EL1 * 2)
+
+#define NR_COPRO_REGS (NR_SYS_REGS * 2)
+
struct kvm_cpu_context {
struct kvm_regs gp_regs;
union {
@@ -197,6 +276,12 @@ struct kvm_vcpu_stat {
u32 halt_successful_poll;
u32 halt_attempted_poll;
u32 halt_wakeup;
+ u32 hvc_exit_stat;
+ u64 wfe_exit_stat;
+ u64 wfi_exit_stat;
+ u64 mmio_exit_user;
+ u64 mmio_exit_kernel;
+ u64 exits;
};
int kvm_vcpu_preferred_target(struct kvm_vcpu_init *init);
diff --git a/arch/arm64/include/asm/kvm_mmio.h b/arch/arm64/include/asm/kvm_mmio.h
index 889c908..fe612a9 100644
--- a/arch/arm64/include/asm/kvm_mmio.h
+++ b/arch/arm64/include/asm/kvm_mmio.h
@@ -19,7 +19,6 @@
#define __ARM64_KVM_MMIO_H__
#include <linux/kvm_host.h>
-#include <asm/kvm_asm.h>
#include <asm/kvm_arm.h>
/*
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index 6150567..0bf8b43 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -20,6 +20,7 @@
#include <asm/page.h>
#include <asm/memory.h>
+#include <asm/cpufeature.h>
/*
* As we only have the TTBR0_EL2 register, we cannot express
@@ -158,7 +159,6 @@ static inline bool kvm_s2pmd_readonly(pmd_t *pmd)
#define PTRS_PER_S2_PGD_SHIFT (KVM_PHYS_SHIFT - PGDIR_SHIFT)
#endif
#define PTRS_PER_S2_PGD (1 << PTRS_PER_S2_PGD_SHIFT)
-#define S2_PGD_ORDER get_order(PTRS_PER_S2_PGD * sizeof(pgd_t))
#define kvm_pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_S2_PGD - 1))
@@ -302,5 +302,12 @@ static inline void __kvm_extend_hypmap(pgd_t *boot_hyp_pgd,
merged_hyp_pgd[idmap_idx] = __pgd(__pa(boot_hyp_pgd) | PMD_TYPE_TABLE);
}
+static inline unsigned int kvm_get_vmid_bits(void)
+{
+ int reg = read_system_reg(SYS_ID_AA64MMFR1_EL1);
+
+ return (cpuid_feature_extract_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/mmu_context.h b/arch/arm64/include/asm/mmu_context.h
index c0e8789..2416578 100644
--- a/arch/arm64/include/asm/mmu_context.h
+++ b/arch/arm64/include/asm/mmu_context.h
@@ -101,7 +101,7 @@ static inline void cpu_set_default_tcr_t0sz(void)
#define destroy_context(mm) do { } while(0)
void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
-#define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; })
+#define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; })
/*
* This is called when "tsk" is about to enter lazy TLB mode.
diff --git a/arch/arm64/include/asm/paravirt.h b/arch/arm64/include/asm/paravirt.h
new file mode 100644
index 0000000..fd5f428
--- /dev/null
+++ b/arch/arm64/include/asm/paravirt.h
@@ -0,0 +1,20 @@
+#ifndef _ASM_ARM64_PARAVIRT_H
+#define _ASM_ARM64_PARAVIRT_H
+
+#ifdef CONFIG_PARAVIRT
+struct static_key;
+extern struct static_key paravirt_steal_enabled;
+extern struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops {
+ unsigned long long (*steal_clock)(int cpu);
+};
+extern struct pv_time_ops pv_time_ops;
+
+static inline u64 paravirt_steal_clock(int cpu)
+{
+ return pv_time_ops.steal_clock(cpu);
+}
+#endif
+
+#endif
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index d6739e8..5c25b83 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -90,7 +90,23 @@
/*
* Contiguous page definitions.
*/
-#define CONT_PTES (_AC(1, UL) << CONT_SHIFT)
+#ifdef CONFIG_ARM64_64K_PAGES
+#define CONT_PTE_SHIFT 5
+#define CONT_PMD_SHIFT 5
+#elif defined(CONFIG_ARM64_16K_PAGES)
+#define CONT_PTE_SHIFT 7
+#define CONT_PMD_SHIFT 5
+#else
+#define CONT_PTE_SHIFT 4
+#define CONT_PMD_SHIFT 4
+#endif
+
+#define CONT_PTES (1 << CONT_PTE_SHIFT)
+#define CONT_PTE_SIZE (CONT_PTES * PAGE_SIZE)
+#define CONT_PTE_MASK (~(CONT_PTE_SIZE - 1))
+#define CONT_PMDS (1 << CONT_PMD_SHIFT)
+#define CONT_PMD_SIZE (CONT_PMDS * PMD_SIZE)
+#define CONT_PMD_MASK (~(CONT_PMD_SIZE - 1))
/* the the numerical offset of the PTE within a range of CONT_PTES */
#define CONT_RANGE_OFFSET(addr) (((addr)>>PAGE_SHIFT)&(CONT_PTES-1))
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index f3acf42..69d2e2f 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -80,6 +80,8 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define _PAGE_DEFAULT (PROT_DEFAULT | PTE_ATTRINDX(MT_NORMAL))
#define PAGE_KERNEL __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_DEFAULT | PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
+#define PAGE_KERNEL_ROX __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_RDONLY)
#define PAGE_KERNEL_EXEC __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE)
#define PAGE_KERNEL_EXEC_CONT __pgprot(_PAGE_DEFAULT | PTE_UXN | PTE_DIRTY | PTE_WRITE | PTE_CONT)
@@ -165,6 +167,16 @@ extern struct page *empty_zero_page;
((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
#define pte_valid_not_user(pte) \
((pte_val(pte) & (PTE_VALID | PTE_USER)) == PTE_VALID)
+#define pte_valid_young(pte) \
+ ((pte_val(pte) & (PTE_VALID | PTE_AF)) == (PTE_VALID | PTE_AF))
+
+/*
+ * Could the pte be present in the TLB? We must check mm_tlb_flush_pending
+ * so that we don't erroneously return false for pages that have been
+ * remapped as PROT_NONE but are yet to be flushed from the TLB.
+ */
+#define pte_accessible(mm, pte) \
+ (mm_tlb_flush_pending(mm) ? pte_present(pte) : pte_valid_young(pte))
static inline pte_t clear_pte_bit(pte_t pte, pgprot_t prot)
{
@@ -215,7 +227,8 @@ static inline pte_t pte_mkspecial(pte_t pte)
static inline pte_t pte_mkcont(pte_t pte)
{
- return set_pte_bit(pte, __pgprot(PTE_CONT));
+ pte = set_pte_bit(pte, __pgprot(PTE_CONT));
+ return set_pte_bit(pte, __pgprot(PTE_TYPE_PAGE));
}
static inline pte_t pte_mknoncont(pte_t pte)
@@ -223,6 +236,11 @@ static inline pte_t pte_mknoncont(pte_t pte)
return clear_pte_bit(pte, __pgprot(PTE_CONT));
}
+static inline pmd_t pmd_mkcont(pmd_t pmd)
+{
+ return __pmd(pmd_val(pmd) | PMD_SECT_CONT);
+}
+
static inline void set_pte(pte_t *ptep, pte_t pte)
{
*ptep = pte;
@@ -274,10 +292,14 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
* hardware updates of the pte (ptep_set_access_flags safely changes
* valid ptes without going through an invalid entry).
*/
- if (IS_ENABLED(CONFIG_DEBUG_VM) && IS_ENABLED(CONFIG_ARM64_HW_AFDBM) &&
- pte_valid(*ptep)) {
- BUG_ON(!pte_young(pte));
- BUG_ON(pte_write(*ptep) && !pte_dirty(pte));
+ if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) &&
+ pte_valid(*ptep) && pte_valid(pte)) {
+ VM_WARN_ONCE(!pte_young(pte),
+ "%s: racy access flag clearing: 0x%016llx -> 0x%016llx",
+ __func__, pte_val(*ptep), pte_val(pte));
+ VM_WARN_ONCE(pte_write(*ptep) && !pte_dirty(pte),
+ "%s: racy dirty state clearing: 0x%016llx -> 0x%016llx",
+ __func__, pte_val(*ptep), pte_val(pte));
}
set_pte(ptep, pte);
@@ -292,7 +314,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
/*
* Hugetlb definitions.
*/
-#define HUGE_MAX_HSTATE 2
+#define HUGE_MAX_HSTATE 4
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
@@ -658,7 +680,8 @@ extern int kern_addr_valid(unsigned long addr);
#include <asm-generic/pgtable.h>
-#define pgtable_cache_init() do { } while (0)
+void pgd_cache_init(void);
+#define pgtable_cache_init pgd_cache_init
/*
* On AArch64, the cache coherency is handled via the set_pte_at() function.
diff --git a/arch/arm64/include/asm/shmparam.h b/arch/arm64/include/asm/shmparam.h
index 4df608a..e368a55 100644
--- a/arch/arm64/include/asm/shmparam.h
+++ b/arch/arm64/include/asm/shmparam.h
@@ -21,7 +21,7 @@
* alignment value. Since we don't have aliasing D-caches, the rest of
* the time we can safely use PAGE_SIZE.
*/
-#define COMPAT_SHMLBA 0x4000
+#define COMPAT_SHMLBA (4 * PAGE_SIZE)
#include <asm-generic/shmparam.h>
diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h
index c85e96d..fc9682b 100644
--- a/arch/arm64/include/asm/spinlock.h
+++ b/arch/arm64/include/asm/spinlock.h
@@ -26,9 +26,28 @@
* The memory barriers are implicit with the load-acquire and store-release
* instructions.
*/
+static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
+{
+ unsigned int tmp;
+ arch_spinlock_t lockval;
-#define arch_spin_unlock_wait(lock) \
- do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
+ asm volatile(
+" sevl\n"
+"1: wfe\n"
+"2: ldaxr %w0, %2\n"
+" eor %w1, %w0, %w0, ror #16\n"
+" cbnz %w1, 1b\n"
+ ARM64_LSE_ATOMIC_INSN(
+ /* LL/SC */
+" stxr %w1, %w0, %2\n"
+" cbnz %w1, 2b\n", /* Serialise against any concurrent lockers */
+ /* LSE atomics */
+" nop\n"
+" nop\n")
+ : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock)
+ :
+ : "memory");
+}
#define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
diff --git a/arch/arm64/include/asm/stacktrace.h b/arch/arm64/include/asm/stacktrace.h
index 7318f6d..801a16db 100644
--- a/arch/arm64/include/asm/stacktrace.h
+++ b/arch/arm64/include/asm/stacktrace.h
@@ -16,14 +16,19 @@
#ifndef __ASM_STACKTRACE_H
#define __ASM_STACKTRACE_H
+struct task_struct;
+
struct stackframe {
unsigned long fp;
unsigned long sp;
unsigned long pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ unsigned int graph;
+#endif
};
-extern int unwind_frame(struct stackframe *frame);
-extern void walk_stackframe(struct stackframe *frame,
+extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame);
+extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data);
#endif /* __ASM_STACKTRACE_H */
diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h
index d48ab5b..4aeebec 100644
--- a/arch/arm64/include/asm/sysreg.h
+++ b/arch/arm64/include/asm/sysreg.h
@@ -20,6 +20,8 @@
#ifndef __ASM_SYSREG_H
#define __ASM_SYSREG_H
+#include <linux/stringify.h>
+
#include <asm/opcodes.h>
/*
@@ -208,6 +210,8 @@
#else
+#include <linux/types.h>
+
asm(
" .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30\n"
" .equ __reg_num_x\\num, \\num\n"
@@ -232,6 +236,23 @@ static inline void config_sctlr_el1(u32 clear, u32 set)
val |= set;
asm volatile("msr sctlr_el1, %0" : : "r" (val));
}
+
+/*
+ * Unlike read_cpuid, calls to read_sysreg are never expected to be
+ * optimized away or replaced with synthetic values.
+ */
+#define read_sysreg(r) ({ \
+ u64 __val; \
+ asm volatile("mrs %0, " __stringify(r) : "=r" (__val)); \
+ __val; \
+})
+
+#define write_sysreg(v, r) do { \
+ u64 __val = (u64)v; \
+ asm volatile("msr " __stringify(r) ", %0" \
+ : : "r" (__val)); \
+} while (0)
+
#endif
#endif /* __ASM_SYSREG_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 90c7ff2..abd64bd 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -73,10 +73,16 @@ register unsigned long current_stack_pointer asm ("sp");
*/
static inline struct thread_info *current_thread_info(void) __attribute_const__;
+/*
+ * struct thread_info can be accessed directly via sp_el0.
+ */
static inline struct thread_info *current_thread_info(void)
{
- return (struct thread_info *)
- (current_stack_pointer & ~(THREAD_SIZE - 1));
+ unsigned long sp_el0;
+
+ asm ("mrs %0, sp_el0" : "=r" (sp_el0));
+
+ return (struct thread_info *)sp_el0;
}
#define thread_saved_pc(tsk) \
diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
index 0cd7b59..2d4ca4b 100644
--- a/arch/arm64/include/uapi/asm/kvm.h
+++ b/arch/arm64/include/uapi/asm/kvm.h
@@ -32,7 +32,7 @@
#ifndef __ASSEMBLY__
#include <linux/psci.h>
-#include <asm/types.h>
+#include <linux/types.h>
#include <asm/ptrace.h>
#define __KVM_HAVE_GUEST_DEBUG
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 474691f..83cd7e6 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -14,10 +14,10 @@ CFLAGS_REMOVE_return_address.o = -pg
arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
- hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o \
+ hyp-stub.o psci.o cpu_ops.o insn.o \
return_address.o cpuinfo.o cpu_errata.o \
cpufeature.o alternative.o cacheinfo.o \
- smp.o smp_spin_table.o topology.o
+ smp.o smp_spin_table.o topology.o smccc-call.o
extra-$(CONFIG_EFI) := efi-entry.o
@@ -41,6 +41,7 @@ arm64-obj-$(CONFIG_EFI) += efi.o efi-entry.stub.o
arm64-obj-$(CONFIG_PCI) += pci.o
arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
arm64-obj-$(CONFIG_ACPI) += acpi.o
+arm64-obj-$(CONFIG_PARAVIRT) += paravirt.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
index ab9db0e..d2ee1b2 100644
--- a/arch/arm64/kernel/alternative.c
+++ b/arch/arm64/kernel/alternative.c
@@ -158,9 +158,3 @@ void apply_alternatives(void *start, size_t length)
__apply_alternatives(&region);
}
-
-void free_alternatives_memory(void)
-{
- free_reserved_area(__alt_instructions, __alt_instructions_end,
- 0, "alternatives");
-}
diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
index 3b6d8cc..678f30b0 100644
--- a/arch/arm64/kernel/arm64ksyms.c
+++ b/arch/arm64/kernel/arm64ksyms.c
@@ -26,6 +26,7 @@
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/io.h>
+#include <linux/arm-smccc.h>
#include <asm/checksum.h>
@@ -68,3 +69,7 @@ EXPORT_SYMBOL(test_and_change_bit);
#ifdef CONFIG_FUNCTION_TRACER
EXPORT_SYMBOL(_mcount);
#endif
+
+ /* arm-smccc */
+EXPORT_SYMBOL(arm_smccc_smc);
+EXPORT_SYMBOL(arm_smccc_hvc);
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
index 937f5e5..3e01207 100644
--- a/arch/arm64/kernel/armv8_deprecated.c
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -62,7 +62,7 @@ struct insn_emulation {
};
static LIST_HEAD(insn_emulation);
-static int nr_insn_emulated;
+static int nr_insn_emulated __initdata;
static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
static void register_emulation_hooks(struct insn_emulation_ops *ops)
@@ -173,7 +173,7 @@ static int update_insn_emulation_mode(struct insn_emulation *insn,
return ret;
}
-static void register_insn_emulation(struct insn_emulation_ops *ops)
+static void __init register_insn_emulation(struct insn_emulation_ops *ops)
{
unsigned long flags;
struct insn_emulation *insn;
@@ -237,7 +237,7 @@ static struct ctl_table ctl_abi[] = {
{ }
};
-static void register_insn_emulation_sysctl(struct ctl_table *table)
+static void __init register_insn_emulation_sysctl(struct ctl_table *table)
{
unsigned long flags;
int i = 0;
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 25de8b2..fffa4ac6 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -28,6 +28,7 @@
#include <asm/suspend.h>
#include <asm/vdso_datapage.h>
#include <linux/kbuild.h>
+#include <linux/arm-smccc.h>
int main(void)
{
@@ -108,49 +109,11 @@ int main(void)
DEFINE(CPU_GP_REGS, offsetof(struct kvm_cpu_context, gp_regs));
DEFINE(CPU_USER_PT_REGS, offsetof(struct kvm_regs, regs));
DEFINE(CPU_FP_REGS, offsetof(struct kvm_regs, fp_regs));
- DEFINE(CPU_SP_EL1, offsetof(struct kvm_regs, sp_el1));
- DEFINE(CPU_ELR_EL1, offsetof(struct kvm_regs, elr_el1));
- DEFINE(CPU_SPSR, offsetof(struct kvm_regs, spsr));
- DEFINE(CPU_SYSREGS, offsetof(struct kvm_cpu_context, sys_regs));
+ DEFINE(VCPU_FPEXC32_EL2, offsetof(struct kvm_vcpu, arch.ctxt.sys_regs[FPEXC32_EL2]));
DEFINE(VCPU_ESR_EL2, offsetof(struct kvm_vcpu, arch.fault.esr_el2));
DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2));
DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2));
- DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags));
- DEFINE(VCPU_DEBUG_PTR, offsetof(struct kvm_vcpu, arch.debug_ptr));
- DEFINE(DEBUG_BCR, offsetof(struct kvm_guest_debug_arch, dbg_bcr));
- DEFINE(DEBUG_BVR, offsetof(struct kvm_guest_debug_arch, dbg_bvr));
- DEFINE(DEBUG_WCR, offsetof(struct kvm_guest_debug_arch, dbg_wcr));
- DEFINE(DEBUG_WVR, offsetof(struct kvm_guest_debug_arch, dbg_wvr));
- DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2));
- DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2));
- DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines));
DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context));
- DEFINE(VCPU_HOST_DEBUG_STATE, offsetof(struct kvm_vcpu, arch.host_debug_state));
- DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl));
- DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval));
- DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff));
- DEFINE(KVM_TIMER_ENABLED, offsetof(struct kvm, arch.timer.enabled));
- DEFINE(VCPU_KVM, offsetof(struct kvm_vcpu, kvm));
- DEFINE(VCPU_VGIC_CPU, offsetof(struct kvm_vcpu, arch.vgic_cpu));
- DEFINE(VGIC_V2_CPU_HCR, offsetof(struct vgic_cpu, vgic_v2.vgic_hcr));
- DEFINE(VGIC_V2_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v2.vgic_vmcr));
- DEFINE(VGIC_V2_CPU_MISR, offsetof(struct vgic_cpu, vgic_v2.vgic_misr));
- DEFINE(VGIC_V2_CPU_EISR, offsetof(struct vgic_cpu, vgic_v2.vgic_eisr));
- DEFINE(VGIC_V2_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v2.vgic_elrsr));
- DEFINE(VGIC_V2_CPU_APR, offsetof(struct vgic_cpu, vgic_v2.vgic_apr));
- DEFINE(VGIC_V2_CPU_LR, offsetof(struct vgic_cpu, vgic_v2.vgic_lr));
- DEFINE(VGIC_V3_CPU_SRE, offsetof(struct vgic_cpu, vgic_v3.vgic_sre));
- DEFINE(VGIC_V3_CPU_HCR, offsetof(struct vgic_cpu, vgic_v3.vgic_hcr));
- DEFINE(VGIC_V3_CPU_VMCR, offsetof(struct vgic_cpu, vgic_v3.vgic_vmcr));
- DEFINE(VGIC_V3_CPU_MISR, offsetof(struct vgic_cpu, vgic_v3.vgic_misr));
- DEFINE(VGIC_V3_CPU_EISR, offsetof(struct vgic_cpu, vgic_v3.vgic_eisr));
- DEFINE(VGIC_V3_CPU_ELRSR, offsetof(struct vgic_cpu, vgic_v3.vgic_elrsr));
- DEFINE(VGIC_V3_CPU_AP0R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap0r));
- DEFINE(VGIC_V3_CPU_AP1R, offsetof(struct vgic_cpu, vgic_v3.vgic_ap1r));
- DEFINE(VGIC_V3_CPU_LR, offsetof(struct vgic_cpu, vgic_v3.vgic_lr));
- DEFINE(VGIC_CPU_NR_LR, offsetof(struct vgic_cpu, nr_lr));
- DEFINE(KVM_VTTBR, offsetof(struct kvm, arch.vttbr));
- DEFINE(KVM_VGIC_VCTRL, offsetof(struct kvm, arch.vgic.vctrl_base));
#endif
#ifdef CONFIG_CPU_PM
DEFINE(CPU_SUSPEND_SZ, sizeof(struct cpu_suspend_ctx));
@@ -161,5 +124,7 @@ int main(void)
DEFINE(SLEEP_SAVE_SP_PHYS, offsetof(struct sleep_save_sp, save_ptr_stash_phys));
DEFINE(SLEEP_SAVE_SP_VIRT, offsetof(struct sleep_save_sp, save_ptr_stash));
#endif
+ DEFINE(ARM_SMCCC_RES_X0_OFFS, offsetof(struct arm_smccc_res, a0));
+ DEFINE(ARM_SMCCC_RES_X2_OFFS, offsetof(struct arm_smccc_res, a2));
return 0;
}
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 24926f2..feb6b4e 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -75,6 +75,15 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
(1 << MIDR_VARIANT_SHIFT) | 2),
},
#endif
+#ifdef CONFIG_ARM64_ERRATUM_834220
+ {
+ /* Cortex-A57 r0p0 - r1p2 */
+ .desc = "ARM erratum 834220",
+ .capability = ARM64_WORKAROUND_834220,
+ MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
+ (1 << MIDR_VARIANT_SHIFT) | 2),
+ },
+#endif
#ifdef CONFIG_ARM64_ERRATUM_845719
{
/* Cortex-A53 r0p[01234] */
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 52f0d7a..5c90aa4 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -44,8 +44,9 @@ unsigned int compat_elf_hwcap2 __read_mostly;
DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
-#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+#define __ARM64_FTR_BITS(SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
{ \
+ .sign = SIGNED, \
.strict = STRICT, \
.type = TYPE, \
.shift = SHIFT, \
@@ -53,6 +54,14 @@ DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
.safe_val = SAFE_VAL, \
}
+/* Define a feature with signed values */
+#define ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+ __ARM64_FTR_BITS(FTR_SIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
+
+/* Define a feature with unsigned value */
+#define U_ARM64_FTR_BITS(STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL) \
+ __ARM64_FTR_BITS(FTR_UNSIGNED, STRICT, TYPE, SHIFT, WIDTH, SAFE_VAL)
+
#define ARM64_FTR_END \
{ \
.width = 0, \
@@ -99,7 +108,7 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr0[] = {
* Differing PARange is fine as long as all peripherals and memory are mapped
* within the minimum PARange of all CPUs
*/
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_LOWER_SAFE, ID_AA64MMFR0_PARANGE_SHIFT, 4, 0),
ARM64_FTR_END,
};
@@ -115,18 +124,18 @@ static struct arm64_ftr_bits ftr_id_aa64mmfr1[] = {
};
static struct arm64_ftr_bits ftr_ctr[] = {
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 31, 1, 1), /* RAO */
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 28, 3, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_HIGHER_SAFE, 24, 4, 0), /* CWG */
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 20, 4, 0), /* ERG */
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 16, 4, 1), /* DminLine */
/*
* Linux can handle differing I-cache policies. Userspace JITs will
* make use of *minLine
*/
- ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0), /* L1Ip */
+ U_ARM64_FTR_BITS(FTR_NONSTRICT, FTR_EXACT, 14, 2, 0), /* L1Ip */
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 4, 10, 0), /* RAZ */
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, 0, 4, 0), /* IminLine */
ARM64_FTR_END,
};
@@ -144,12 +153,12 @@ static struct arm64_ftr_bits ftr_id_mmfr0[] = {
static struct arm64_ftr_bits ftr_id_aa64dfr0[] = {
ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, 32, 32, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
- ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_CTX_CMPS_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_WRPS_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_LOWER_SAFE, ID_AA64DFR0_BRPS_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_PMUVER_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_TRACEVER_SHIFT, 4, 0),
+ U_ARM64_FTR_BITS(FTR_STRICT, FTR_EXACT, ID_AA64DFR0_DEBUGVER_SHIFT, 4, 0x6),
ARM64_FTR_END,
};
@@ -675,7 +684,7 @@ static const struct arm64_cpu_capabilities arm64_hwcaps[] = {
{},
};
-static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
+static void __init cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
{
switch (cap->hwcap_type) {
case CAP_HWCAP:
@@ -696,7 +705,7 @@ static void cap_set_hwcap(const struct arm64_cpu_capabilities *cap)
}
/* Check if we have a particular HWCAP enabled */
-static bool cpus_have_hwcap(const struct arm64_cpu_capabilities *cap)
+static bool __maybe_unused cpus_have_hwcap(const struct arm64_cpu_capabilities *cap)
{
bool rc;
@@ -720,7 +729,7 @@ static bool cpus_have_hwcap(const struct arm64_cpu_capabilities *cap)
return rc;
}
-static void setup_cpu_hwcaps(void)
+static void __init setup_cpu_hwcaps(void)
{
int i;
const struct arm64_cpu_capabilities *hwcaps = arm64_hwcaps;
@@ -749,7 +758,8 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
* Run through the enabled capabilities and enable() it on all active
* CPUs
*/
-static void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
+static void __init
+enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
{
int i;
@@ -888,7 +898,7 @@ static inline void set_sys_caps_initialised(void)
#endif /* CONFIG_HOTPLUG_CPU */
-static void setup_feature_capabilities(void)
+static void __init setup_feature_capabilities(void)
{
update_cpu_capabilities(arm64_features, "detected feature:");
enable_cpu_capabilities(arm64_features);
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 706679d..212ae63 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -30,6 +30,7 @@
#include <linux/seq_file.h>
#include <linux/sched.h>
#include <linux/smp.h>
+#include <linux/delay.h>
/*
* In case the boot CPU is hotpluggable, we record its initial state and
@@ -112,6 +113,10 @@ static int c_show(struct seq_file *m, void *v)
*/
seq_printf(m, "processor\t: %d\n", i);
+ seq_printf(m, "BogoMIPS\t: %lu.%02lu\n",
+ loops_per_jiffy / (500000UL/HZ),
+ loops_per_jiffy / (5000UL/HZ) % 100);
+
/*
* Dump out the common processor features in a single line.
* Userspace should read the hwcaps with getauxval(AT_HWCAP)
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index de46b50..b6abc85 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -11,307 +11,34 @@
*
*/
-#include <linux/atomic.h>
#include <linux/dmi.h>
#include <linux/efi.h>
-#include <linux/export.h>
-#include <linux/memblock.h>
-#include <linux/mm_types.h>
-#include <linux/bootmem.h>
-#include <linux/of.h>
-#include <linux/of_fdt.h>
-#include <linux/preempt.h>
-#include <linux/rbtree.h>
-#include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
+#include <linux/init.h>
-#include <asm/cacheflush.h>
#include <asm/efi.h>
-#include <asm/tlbflush.h>
-#include <asm/mmu_context.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-struct efi_memory_map memmap;
-
-static u64 efi_system_table;
-
-static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss;
-
-static struct mm_struct efi_mm = {
- .mm_rb = RB_ROOT,
- .pgd = efi_pgd,
- .mm_users = ATOMIC_INIT(2),
- .mm_count = ATOMIC_INIT(1),
- .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
- .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
- .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
-};
-
-static int __init is_normal_ram(efi_memory_desc_t *md)
-{
- if (md->attribute & EFI_MEMORY_WB)
- return 1;
- return 0;
-}
-
-/*
- * Translate a EFI virtual address into a physical address: this is necessary,
- * as some data members of the EFI system table are virtually remapped after
- * SetVirtualAddressMap() has been called.
- */
-static phys_addr_t efi_to_phys(unsigned long addr)
+int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md)
{
- efi_memory_desc_t *md;
-
- for_each_efi_memory_desc(&memmap, md) {
- if (!(md->attribute & EFI_MEMORY_RUNTIME))
- continue;
- if (md->virt_addr == 0)
- /* no virtual mapping has been installed by the stub */
- break;
- if (md->virt_addr <= addr &&
- (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
- return md->phys_addr + addr - md->virt_addr;
- }
- return addr;
-}
-
-static int __init uefi_init(void)
-{
- efi_char16_t *c16;
- void *config_tables;
- u64 table_size;
- char vendor[100] = "unknown";
- int i, retval;
-
- efi.systab = early_memremap(efi_system_table,
- sizeof(efi_system_table_t));
- if (efi.systab == NULL) {
- pr_warn("Unable to map EFI system table.\n");
- return -ENOMEM;
- }
-
- set_bit(EFI_BOOT, &efi.flags);
- set_bit(EFI_64BIT, &efi.flags);
+ pteval_t prot_val;
/*
- * Verify the EFI Table
+ * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
+ * executable, everything else can be mapped with the XN bits
+ * set.
*/
- if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
- pr_err("System table signature incorrect\n");
- retval = -EINVAL;
- goto out;
- }
- if ((efi.systab->hdr.revision >> 16) < 2)
- pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
- efi.systab->hdr.revision >> 16,
- efi.systab->hdr.revision & 0xffff);
-
- /* Show what we know for posterity */
- c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
- sizeof(vendor) * sizeof(efi_char16_t));
- if (c16) {
- for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
- vendor[i] = c16[i];
- vendor[i] = '\0';
- early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
- }
-
- pr_info("EFI v%u.%.02u by %s\n",
- efi.systab->hdr.revision >> 16,
- efi.systab->hdr.revision & 0xffff, vendor);
-
- table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
- config_tables = early_memremap(efi_to_phys(efi.systab->tables),
- table_size);
-
- retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
- sizeof(efi_config_table_64_t), NULL);
-
- early_memunmap(config_tables, table_size);
-out:
- early_memunmap(efi.systab, sizeof(efi_system_table_t));
- return retval;
-}
-
-/*
- * Return true for RAM regions we want to permanently reserve.
- */
-static __init int is_reserve_region(efi_memory_desc_t *md)
-{
- switch (md->type) {
- case EFI_LOADER_CODE:
- case EFI_LOADER_DATA:
- case EFI_BOOT_SERVICES_CODE:
- case EFI_BOOT_SERVICES_DATA:
- case EFI_CONVENTIONAL_MEMORY:
- case EFI_PERSISTENT_MEMORY:
- return 0;
- default:
- break;
- }
- return is_normal_ram(md);
-}
-
-static __init void reserve_regions(void)
-{
- efi_memory_desc_t *md;
- u64 paddr, npages, size;
-
- if (efi_enabled(EFI_DBG))
- pr_info("Processing EFI memory map:\n");
-
- for_each_efi_memory_desc(&memmap, md) {
- paddr = md->phys_addr;
- npages = md->num_pages;
-
- if (efi_enabled(EFI_DBG)) {
- char buf[64];
-
- pr_info(" 0x%012llx-0x%012llx %s",
- paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
- efi_md_typeattr_format(buf, sizeof(buf), md));
- }
-
- memrange_efi_to_native(&paddr, &npages);
- size = npages << PAGE_SHIFT;
-
- if (is_normal_ram(md))
- early_init_dt_add_memory_arch(paddr, size);
-
- if (is_reserve_region(md)) {
- memblock_reserve(paddr, size);
- if (efi_enabled(EFI_DBG))
- pr_cont("*");
- }
-
- if (efi_enabled(EFI_DBG))
- pr_cont("\n");
- }
-
- set_bit(EFI_MEMMAP, &efi.flags);
-}
-
-void __init efi_init(void)
-{
- struct efi_fdt_params params;
-
- /* Grab UEFI information placed in FDT by stub */
- if (!efi_get_fdt_params(&params))
- return;
-
- efi_system_table = params.system_table;
-
- memblock_reserve(params.mmap & PAGE_MASK,
- PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK)));
- memmap.phys_map = params.mmap;
- memmap.map = early_memremap(params.mmap, params.mmap_size);
- memmap.map_end = memmap.map + params.mmap_size;
- memmap.desc_size = params.desc_size;
- memmap.desc_version = params.desc_ver;
-
- if (uefi_init() < 0)
- return;
-
- reserve_regions();
- early_memunmap(memmap.map, params.mmap_size);
-}
-
-static bool __init efi_virtmap_init(void)
-{
- efi_memory_desc_t *md;
-
- for_each_efi_memory_desc(&memmap, md) {
- u64 paddr, npages, size;
- pgprot_t prot;
-
- if (!(md->attribute & EFI_MEMORY_RUNTIME))
- continue;
- if (md->virt_addr == 0)
- return false;
-
- paddr = md->phys_addr;
- npages = md->num_pages;
- memrange_efi_to_native(&paddr, &npages);
- size = npages << PAGE_SHIFT;
-
- pr_info(" EFI remap 0x%016llx => %p\n",
- md->phys_addr, (void *)md->virt_addr);
-
- /*
- * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be
- * executable, everything else can be mapped with the XN bits
- * set.
- */
- if (!is_normal_ram(md))
- prot = __pgprot(PROT_DEVICE_nGnRE);
- else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
- !PAGE_ALIGNED(md->phys_addr))
- prot = PAGE_KERNEL_EXEC;
- else
- prot = PAGE_KERNEL;
-
- create_pgd_mapping(&efi_mm, paddr, md->virt_addr, size, prot);
- }
- return true;
-}
-
-/*
- * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
- * non-early mapping of the UEFI system table and virtual mappings for all
- * EFI_MEMORY_RUNTIME regions.
- */
-static int __init arm64_enable_runtime_services(void)
-{
- u64 mapsize;
-
- if (!efi_enabled(EFI_BOOT)) {
- pr_info("EFI services will not be available.\n");
- return -1;
- }
-
- if (efi_runtime_disabled()) {
- pr_info("EFI runtime services will be disabled.\n");
- return -1;
- }
-
- pr_info("Remapping and enabling EFI services.\n");
-
- mapsize = memmap.map_end - memmap.map;
- memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
- mapsize);
- if (!memmap.map) {
- pr_err("Failed to remap EFI memory map\n");
- return -1;
- }
- memmap.map_end = memmap.map + mapsize;
- efi.memmap = &memmap;
-
- efi.systab = (__force void *)ioremap_cache(efi_system_table,
- sizeof(efi_system_table_t));
- if (!efi.systab) {
- pr_err("Failed to remap EFI System Table\n");
- return -1;
- }
- set_bit(EFI_SYSTEM_TABLES, &efi.flags);
-
- if (!efi_virtmap_init()) {
- pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
- return -1;
- }
-
- /* Set up runtime services function pointers */
- efi_native_runtime_setup();
- set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
-
- efi.runtime_version = efi.systab->hdr.revision;
+ if ((md->attribute & EFI_MEMORY_WB) == 0)
+ prot_val = PROT_DEVICE_nGnRE;
+ else if (md->type == EFI_RUNTIME_SERVICES_CODE ||
+ !PAGE_ALIGNED(md->phys_addr))
+ prot_val = pgprot_val(PAGE_KERNEL_EXEC);
+ else
+ prot_val = pgprot_val(PAGE_KERNEL);
+ create_pgd_mapping(mm, md->phys_addr, md->virt_addr,
+ md->num_pages << EFI_PAGE_SHIFT,
+ __pgprot(prot_val | PTE_NG));
return 0;
}
-early_initcall(arm64_enable_runtime_services);
static int __init arm64_dmi_init(void)
{
@@ -327,30 +54,6 @@ static int __init arm64_dmi_init(void)
}
core_initcall(arm64_dmi_init);
-static void efi_set_pgd(struct mm_struct *mm)
-{
- if (mm == &init_mm)
- cpu_set_reserved_ttbr0();
- else
- cpu_switch_mm(mm->pgd, mm);
-
- local_flush_tlb_all();
- if (icache_is_aivivt())
- __local_flush_icache_all();
-}
-
-void efi_virtmap_load(void)
-{
- preempt_disable();
- efi_set_pgd(&efi_mm);
-}
-
-void efi_virtmap_unload(void)
-{
- efi_set_pgd(current->active_mm);
- preempt_enable();
-}
-
/*
* UpdateCapsule() depends on the system being shutdown via
* ResetSystem().
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 7ed3d75..1f7f5a2 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -27,6 +27,7 @@
#include <asm/cpufeature.h>
#include <asm/errno.h>
#include <asm/esr.h>
+#include <asm/irq.h>
#include <asm/thread_info.h>
#include <asm/unistd.h>
@@ -88,9 +89,12 @@
.if \el == 0
mrs x21, sp_el0
- get_thread_info tsk // Ensure MDSCR_EL1.SS is clear,
+ mov tsk, sp
+ and tsk, tsk, #~(THREAD_SIZE - 1) // Ensure MDSCR_EL1.SS is clear,
ldr x19, [tsk, #TI_FLAGS] // since we can unmask debug
disable_step_tsk x19, x20 // exceptions when scheduling.
+
+ mov x29, xzr // fp pointed to user-space
.else
add x21, sp, #S_FRAME_SIZE
.endif
@@ -108,6 +112,13 @@
.endif
/*
+ * Set sp_el0 to current thread_info.
+ */
+ .if \el == 0
+ msr sp_el0, tsk
+ .endif
+
+ /*
* Registers that may be useful after this macro is invoked:
*
* x21 - aborted SP
@@ -164,8 +175,44 @@ alternative_endif
.endm
.macro get_thread_info, rd
- mov \rd, sp
- and \rd, \rd, #~(THREAD_SIZE - 1) // top of stack
+ mrs \rd, sp_el0
+ .endm
+
+ .macro irq_stack_entry
+ mov x19, sp // preserve the original sp
+
+ /*
+ * Compare sp with the current thread_info, if the top
+ * ~(THREAD_SIZE - 1) bits match, we are on a task stack, and
+ * should switch to the irq stack.
+ */
+ and x25, x19, #~(THREAD_SIZE - 1)
+ cmp x25, tsk
+ b.ne 9998f
+
+ this_cpu_ptr irq_stack, x25, x26
+ mov x26, #IRQ_STACK_START_SP
+ add x26, x25, x26
+
+ /* switch to the irq stack */
+ mov sp, x26
+
+ /*
+ * Add a dummy stack frame, this non-standard format is fixed up
+ * by unwind_frame()
+ */
+ stp x29, x19, [sp, #-16]!
+ mov x29, sp
+
+9998:
+ .endm
+
+ /*
+ * x19 should be preserved between irq_stack_entry and
+ * irq_stack_exit.
+ */
+ .macro irq_stack_exit
+ mov sp, x19
.endm
/*
@@ -183,10 +230,11 @@ tsk .req x28 // current thread_info
* Interrupt handling.
*/
.macro irq_handler
- adrp x1, handle_arch_irq
- ldr x1, [x1, #:lo12:handle_arch_irq]
+ ldr_l x1, handle_arch_irq
mov x0, sp
+ irq_stack_entry
blr x1
+ irq_stack_exit
.endm
.text
@@ -358,10 +406,10 @@ el1_irq:
bl trace_hardirqs_off
#endif
+ get_thread_info tsk
irq_handler
#ifdef CONFIG_PREEMPT
- get_thread_info tsk
ldr w24, [tsk, #TI_PREEMPT] // get preempt count
cbnz w24, 1f // preempt count != 0
ldr x0, [tsk, #TI_FLAGS] // get flags
@@ -599,6 +647,8 @@ ENTRY(cpu_switch_to)
ldp x29, x9, [x8], #16
ldr lr, [x8]
mov sp, x9
+ and x9, x9, #~(THREAD_SIZE - 1)
+ msr sp_el0, x9
ret
ENDPROC(cpu_switch_to)
@@ -626,14 +676,14 @@ ret_fast_syscall_trace:
work_pending:
tbnz x1, #TIF_NEED_RESCHED, work_resched
/* TIF_SIGPENDING, TIF_NOTIFY_RESUME or TIF_FOREIGN_FPSTATE case */
- ldr x2, [sp, #S_PSTATE]
mov x0, sp // 'regs'
- tst x2, #PSR_MODE_MASK // user mode regs?
- b.ne no_work_pending // returning to kernel
enable_irq // enable interrupts for do_notify_resume()
bl do_notify_resume
b ret_to_user
work_resched:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl trace_hardirqs_off // the IRQs are off here, inform the tracing code
+#endif
bl schedule
/*
@@ -645,7 +695,6 @@ ret_to_user:
and x2, x1, #_TIF_WORK_MASK
cbnz x2, work_pending
enable_step_tsk x1, x2
-no_work_pending:
kernel_exit 0
ENDPROC(ret_to_user)
diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
index 4c46c54..acc1afd 100644
--- a/arch/arm64/kernel/fpsimd.c
+++ b/arch/arm64/kernel/fpsimd.c
@@ -289,7 +289,7 @@ static struct notifier_block fpsimd_cpu_pm_notifier_block = {
.notifier_call = fpsimd_cpu_pm_notifier,
};
-static void fpsimd_pm_init(void)
+static void __init fpsimd_pm_init(void)
{
cpu_pm_register_notifier(&fpsimd_cpu_pm_notifier_block);
}
diff --git a/arch/arm64/kernel/ftrace.c b/arch/arm64/kernel/ftrace.c
index c851be7..ebecf9a 100644
--- a/arch/arm64/kernel/ftrace.c
+++ b/arch/arm64/kernel/ftrace.c
@@ -29,12 +29,11 @@ static int ftrace_modify_code(unsigned long pc, u32 old, u32 new,
/*
* Note:
- * Due to modules and __init, code can disappear and change,
- * we need to protect against faulting as well as code changing.
- * We do this by aarch64_insn_*() which use the probe_kernel_*().
- *
- * No lock is held here because all the modifications are run
- * through stop_machine().
+ * We are paranoid about modifying text, as if a bug were to happen, it
+ * could cause us to read or write to someplace that could cause harm.
+ * Carefully read and modify the code with aarch64_insn_*() which uses
+ * probe_kernel_*(), and make sure what we read is what we expected it
+ * to be before modifying it.
*/
if (validate) {
if (aarch64_insn_read((void *)pc, &replaced))
@@ -93,6 +92,11 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
return ftrace_modify_code(pc, old, new, true);
}
+void arch_ftrace_update_code(int command)
+{
+ ftrace_modify_all_code(command);
+}
+
int __init ftrace_dyn_arch_init(void)
{
return 0;
@@ -125,23 +129,20 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
* on other archs. It's unlikely on AArch64.
*/
old = *parent;
- *parent = return_hooker;
trace.func = self_addr;
trace.depth = current->curr_ret_stack + 1;
/* Only trace if the calling function expects to */
- if (!ftrace_graph_entry(&trace)) {
- *parent = old;
+ if (!ftrace_graph_entry(&trace))
return;
- }
err = ftrace_push_return_trace(old, self_addr, &trace.depth,
frame_pointer);
- if (err == -EBUSY) {
- *parent = old;
+ if (err == -EBUSY)
return;
- }
+ else
+ *parent = return_hooker;
}
#ifdef CONFIG_DYNAMIC_FTRACE
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 23cfc08..ffe9c2b 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -415,15 +415,17 @@ ENDPROC(__create_page_tables)
*/
.set initial_sp, init_thread_union + THREAD_START_SP
__mmap_switched:
- adr_l x6, __bss_start
- adr_l x7, __bss_stop
-
-1: cmp x6, x7
- b.hs 2f
- str xzr, [x6], #8 // Clear BSS
- b 1b
-2:
+ // Clear BSS
+ adr_l x0, __bss_start
+ mov x1, xzr
+ adr_l x2, __bss_stop
+ sub x2, x2, x0
+ bl __pi_memset
+
adr_l sp, initial_sp, x4
+ mov x4, sp
+ and x4, x4, #~(THREAD_SIZE - 1)
+ msr sp_el0, x4 // Save thread_info
str_l x21, __fdt_pointer, x5 // Save FDT pointer
str_l x24, memstart_addr, x6 // Save PHYS_OFFSET
mov x29, #0
@@ -606,6 +608,8 @@ ENDPROC(secondary_startup)
ENTRY(__secondary_switched)
ldr x0, [x21] // get secondary_data.stack
mov sp, x0
+ and x0, x0, #~(THREAD_SIZE - 1)
+ msr sp_el0, x0 // save thread_info
mov x29, #0
b secondary_start_kernel
ENDPROC(__secondary_switched)
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 9f17ec0..2386b26 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -30,6 +30,9 @@
unsigned long irq_err_count;
+/* irq stack only needs to be 16 byte aligned - not IRQ_STACK_SIZE aligned. */
+DEFINE_PER_CPU(unsigned long [IRQ_STACK_SIZE/sizeof(long)], irq_stack) __aligned(16);
+
int arch_show_interrupts(struct seq_file *p, int prec)
{
show_ipi_list(p, prec);
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index f4bc779..93e9702 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -30,9 +30,6 @@
#include <asm/insn.h>
#include <asm/sections.h>
-#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX
-#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16
-
void *module_alloc(unsigned long size)
{
void *p;
@@ -75,15 +72,18 @@ static u64 do_reloc(enum aarch64_reloc_op reloc_op, void *place, u64 val)
static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
{
- u64 imm_mask = (1 << len) - 1;
s64 sval = do_reloc(op, place, val);
switch (len) {
case 16:
*(s16 *)place = sval;
+ if (sval < S16_MIN || sval > U16_MAX)
+ return -ERANGE;
break;
case 32:
*(s32 *)place = sval;
+ if (sval < S32_MIN || sval > U32_MAX)
+ return -ERANGE;
break;
case 64:
*(s64 *)place = sval;
@@ -92,34 +92,23 @@ static int reloc_data(enum aarch64_reloc_op op, void *place, u64 val, int len)
pr_err("Invalid length (%d) for data relocation\n", len);
return 0;
}
-
- /*
- * Extract the upper value bits (including the sign bit) and
- * shift them to bit 0.
- */
- sval = (s64)(sval & ~(imm_mask >> 1)) >> (len - 1);
-
- /*
- * Overflow has occurred if the value is not representable in
- * len bits (i.e the bottom len bits are not sign-extended and
- * the top bits are not all zero).
- */
- if ((u64)(sval + 1) > 2)
- return -ERANGE;
-
return 0;
}
+enum aarch64_insn_movw_imm_type {
+ AARCH64_INSN_IMM_MOVNZ,
+ AARCH64_INSN_IMM_MOVKZ,
+};
+
static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
- int lsb, enum aarch64_insn_imm_type imm_type)
+ int lsb, enum aarch64_insn_movw_imm_type imm_type)
{
- u64 imm, limit = 0;
+ u64 imm;
s64 sval;
u32 insn = le32_to_cpu(*(u32 *)place);
sval = do_reloc(op, place, val);
- sval >>= lsb;
- imm = sval & 0xffff;
+ imm = sval >> lsb;
if (imm_type == AARCH64_INSN_IMM_MOVNZ) {
/*
@@ -128,7 +117,7 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
* immediate is less than zero.
*/
insn &= ~(3 << 29);
- if ((s64)imm >= 0) {
+ if (sval >= 0) {
/* >=0: Set the instruction to MOVZ (opcode 10b). */
insn |= 2 << 29;
} else {
@@ -140,29 +129,13 @@ static int reloc_insn_movw(enum aarch64_reloc_op op, void *place, u64 val,
*/
imm = ~imm;
}
- imm_type = AARCH64_INSN_IMM_MOVK;
}
/* Update the instruction with the new encoding. */
- insn = aarch64_insn_encode_immediate(imm_type, insn, imm);
+ insn = aarch64_insn_encode_immediate(AARCH64_INSN_IMM_16, insn, imm);
*(u32 *)place = cpu_to_le32(insn);
- /* Shift out the immediate field. */
- sval >>= 16;
-
- /*
- * For unsigned immediates, the overflow check is straightforward.
- * For signed immediates, the sign bit is actually the bit past the
- * most significant bit of the field.
- * The AARCH64_INSN_IMM_16 immediate type is unsigned.
- */
- if (imm_type != AARCH64_INSN_IMM_16) {
- sval++;
- limit++;
- }
-
- /* Check the upper bits depending on the sign of the immediate. */
- if ((u64)sval > limit)
+ if (imm > U16_MAX)
return -ERANGE;
return 0;
@@ -267,25 +240,25 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
overflow_check = false;
case R_AARCH64_MOVW_UABS_G0:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
- AARCH64_INSN_IMM_16);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_UABS_G1_NC:
overflow_check = false;
case R_AARCH64_MOVW_UABS_G1:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 16,
- AARCH64_INSN_IMM_16);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_UABS_G2_NC:
overflow_check = false;
case R_AARCH64_MOVW_UABS_G2:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 32,
- AARCH64_INSN_IMM_16);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_UABS_G3:
/* We're using the top bits so we can't overflow. */
overflow_check = false;
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 48,
- AARCH64_INSN_IMM_16);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_SABS_G0:
ovf = reloc_insn_movw(RELOC_OP_ABS, loc, val, 0,
@@ -302,7 +275,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
case R_AARCH64_MOVW_PREL_G0_NC:
overflow_check = false;
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
- AARCH64_INSN_IMM_MOVK);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_PREL_G0:
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 0,
@@ -311,7 +284,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
case R_AARCH64_MOVW_PREL_G1_NC:
overflow_check = false;
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
- AARCH64_INSN_IMM_MOVK);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_PREL_G1:
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 16,
@@ -320,7 +293,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
case R_AARCH64_MOVW_PREL_G2_NC:
overflow_check = false;
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
- AARCH64_INSN_IMM_MOVK);
+ AARCH64_INSN_IMM_MOVKZ);
break;
case R_AARCH64_MOVW_PREL_G2:
ovf = reloc_insn_movw(RELOC_OP_PREL, loc, val, 32,
diff --git a/arch/arm64/kernel/paravirt.c b/arch/arm64/kernel/paravirt.c
new file mode 100644
index 0000000..53f371e
--- /dev/null
+++ b/arch/arm64/kernel/paravirt.c
@@ -0,0 +1,25 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2013 Citrix Systems
+ *
+ * Author: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ */
+
+#include <linux/export.h>
+#include <linux/jump_label.h>
+#include <linux/types.h>
+#include <asm/paravirt.h>
+
+struct static_key paravirt_steal_enabled;
+struct static_key paravirt_steal_rq_enabled;
+
+struct pv_time_ops pv_time_ops;
+EXPORT_SYMBOL_GPL(pv_time_ops);
diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c
index 3aa7483..ff46654 100644
--- a/arch/arm64/kernel/perf_callchain.c
+++ b/arch/arm64/kernel/perf_callchain.c
@@ -164,8 +164,11 @@ void perf_callchain_kernel(struct perf_callchain_entry *entry,
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = current->curr_ret_stack;
+#endif
- walk_stackframe(&frame, callchain_trace, entry);
+ walk_stackframe(current, &frame, callchain_trace, entry);
}
unsigned long perf_instruction_pointer(struct pt_regs *regs)
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index 5b1897e..f7ab14c 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -29,60 +29,74 @@
* ARMv8 PMUv3 Performance Events handling code.
* Common event types.
*/
-enum armv8_pmuv3_perf_types {
- /* Required events. */
- ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR = 0x00,
- ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL = 0x03,
- ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS = 0x04,
- ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED = 0x10,
- ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES = 0x11,
- ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED = 0x12,
-
- /* At least one of the following is required. */
- ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED = 0x08,
- ARMV8_PMUV3_PERFCTR_OP_SPEC = 0x1B,
-
- /* Common architectural events. */
- ARMV8_PMUV3_PERFCTR_MEM_READ = 0x06,
- ARMV8_PMUV3_PERFCTR_MEM_WRITE = 0x07,
- ARMV8_PMUV3_PERFCTR_EXC_TAKEN = 0x09,
- ARMV8_PMUV3_PERFCTR_EXC_EXECUTED = 0x0A,
- ARMV8_PMUV3_PERFCTR_CID_WRITE = 0x0B,
- ARMV8_PMUV3_PERFCTR_PC_WRITE = 0x0C,
- ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH = 0x0D,
- ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN = 0x0E,
- ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS = 0x0F,
- ARMV8_PMUV3_PERFCTR_TTBR_WRITE = 0x1C,
-
- /* Common microarchitectural events. */
- ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL = 0x01,
- ARMV8_PMUV3_PERFCTR_ITLB_REFILL = 0x02,
- ARMV8_PMUV3_PERFCTR_DTLB_REFILL = 0x05,
- ARMV8_PMUV3_PERFCTR_MEM_ACCESS = 0x13,
- ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS = 0x14,
- ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB = 0x15,
- ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS = 0x16,
- ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL = 0x17,
- ARMV8_PMUV3_PERFCTR_L2_CACHE_WB = 0x18,
- ARMV8_PMUV3_PERFCTR_BUS_ACCESS = 0x19,
- ARMV8_PMUV3_PERFCTR_MEM_ERROR = 0x1A,
- ARMV8_PMUV3_PERFCTR_BUS_CYCLES = 0x1D,
-};
+
+/* Required events. */
+#define ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR 0x00
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL 0x03
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS 0x04
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED 0x10
+#define ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES 0x11
+#define ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED 0x12
+
+/* At least one of the following is required. */
+#define ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED 0x08
+#define ARMV8_PMUV3_PERFCTR_OP_SPEC 0x1B
+
+/* Common architectural events. */
+#define ARMV8_PMUV3_PERFCTR_MEM_READ 0x06
+#define ARMV8_PMUV3_PERFCTR_MEM_WRITE 0x07
+#define ARMV8_PMUV3_PERFCTR_EXC_TAKEN 0x09
+#define ARMV8_PMUV3_PERFCTR_EXC_EXECUTED 0x0A
+#define ARMV8_PMUV3_PERFCTR_CID_WRITE 0x0B
+#define ARMV8_PMUV3_PERFCTR_PC_WRITE 0x0C
+#define ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH 0x0D
+#define ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN 0x0E
+#define ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS 0x0F
+#define ARMV8_PMUV3_PERFCTR_TTBR_WRITE 0x1C
+#define ARMV8_PMUV3_PERFCTR_CHAIN 0x1E
+#define ARMV8_PMUV3_PERFCTR_BR_RETIRED 0x21
+
+/* Common microarchitectural events. */
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL 0x01
+#define ARMV8_PMUV3_PERFCTR_ITLB_REFILL 0x02
+#define ARMV8_PMUV3_PERFCTR_DTLB_REFILL 0x05
+#define ARMV8_PMUV3_PERFCTR_MEM_ACCESS 0x13
+#define ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS 0x14
+#define ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB 0x15
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS 0x16
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL 0x17
+#define ARMV8_PMUV3_PERFCTR_L2_CACHE_WB 0x18
+#define ARMV8_PMUV3_PERFCTR_BUS_ACCESS 0x19
+#define ARMV8_PMUV3_PERFCTR_MEM_ERROR 0x1A
+#define ARMV8_PMUV3_PERFCTR_BUS_CYCLES 0x1D
+#define ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE 0x1F
+#define ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE 0x20
+#define ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED 0x22
+#define ARMV8_PMUV3_PERFCTR_STALL_FRONTEND 0x23
+#define ARMV8_PMUV3_PERFCTR_STALL_BACKEND 0x24
+#define ARMV8_PMUV3_PERFCTR_L1D_TLB 0x25
+#define ARMV8_PMUV3_PERFCTR_L1I_TLB 0x26
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE 0x27
+#define ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL 0x28
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE 0x29
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL 0x2A
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE 0x2B
+#define ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB 0x2C
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL 0x2D
+#define ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL 0x2E
+#define ARMV8_PMUV3_PERFCTR_L2D_TLB 0x2F
+#define ARMV8_PMUV3_PERFCTR_L21_TLB 0x30
/* ARMv8 Cortex-A53 specific event types. */
-enum armv8_a53_pmu_perf_types {
- ARMV8_A53_PERFCTR_PREFETCH_LINEFILL = 0xC2,
-};
+#define ARMV8_A53_PERFCTR_PREFETCH_LINEFILL 0xC2
-/* ARMv8 Cortex-A57 specific event types. */
-enum armv8_a57_perf_types {
- ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD = 0x40,
- ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST = 0x41,
- ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD = 0x42,
- ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST = 0x43,
- ARMV8_A57_PERFCTR_DTLB_REFILL_LD = 0x4c,
- ARMV8_A57_PERFCTR_DTLB_REFILL_ST = 0x4d,
-};
+/* ARMv8 Cortex-A57 and Cortex-A72 specific event types. */
+#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_LD 0x40
+#define ARMV8_A57_PERFCTR_L1_DCACHE_ACCESS_ST 0x41
+#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_LD 0x42
+#define ARMV8_A57_PERFCTR_L1_DCACHE_REFILL_ST 0x43
+#define ARMV8_A57_PERFCTR_DTLB_REFILL_LD 0x4c
+#define ARMV8_A57_PERFCTR_DTLB_REFILL_ST 0x4d
/* PMUv3 HW events mapping. */
static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = {
@@ -106,6 +120,7 @@ static const unsigned armv8_a53_perf_map[PERF_COUNT_HW_MAX] = {
[PERF_COUNT_HW_BUS_CYCLES] = ARMV8_PMUV3_PERFCTR_BUS_CYCLES,
};
+/* ARM Cortex-A57 and Cortex-A72 events mapping. */
static const unsigned armv8_a57_perf_map[PERF_COUNT_HW_MAX] = {
PERF_MAP_ALL_UNSUPPORTED,
[PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES,
@@ -178,6 +193,137 @@ static const unsigned armv8_a57_perf_cache_map[PERF_COUNT_HW_CACHE_MAX]
[C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED,
};
+#define ARMV8_EVENT_ATTR_RESOLVE(m) #m
+#define ARMV8_EVENT_ATTR(name, config) \
+ PMU_EVENT_ATTR_STRING(name, armv8_event_attr_##name, \
+ "event=" ARMV8_EVENT_ATTR_RESOLVE(config))
+
+ARMV8_EVENT_ATTR(sw_incr, ARMV8_PMUV3_PERFCTR_PMNC_SW_INCR);
+ARMV8_EVENT_ATTR(l1i_cache_refill, ARMV8_PMUV3_PERFCTR_L1_ICACHE_REFILL);
+ARMV8_EVENT_ATTR(l1i_tlb_refill, ARMV8_PMUV3_PERFCTR_ITLB_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache_refill, ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL);
+ARMV8_EVENT_ATTR(l1d_cache, ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_tlb_refill, ARMV8_PMUV3_PERFCTR_DTLB_REFILL);
+ARMV8_EVENT_ATTR(ld_retired, ARMV8_PMUV3_PERFCTR_MEM_READ);
+ARMV8_EVENT_ATTR(st_retired, ARMV8_PMUV3_PERFCTR_MEM_WRITE);
+ARMV8_EVENT_ATTR(inst_retired, ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED);
+ARMV8_EVENT_ATTR(exc_taken, ARMV8_PMUV3_PERFCTR_EXC_TAKEN);
+ARMV8_EVENT_ATTR(exc_return, ARMV8_PMUV3_PERFCTR_EXC_EXECUTED);
+ARMV8_EVENT_ATTR(cid_write_retired, ARMV8_PMUV3_PERFCTR_CID_WRITE);
+ARMV8_EVENT_ATTR(pc_write_retired, ARMV8_PMUV3_PERFCTR_PC_WRITE);
+ARMV8_EVENT_ATTR(br_immed_retired, ARMV8_PMUV3_PERFCTR_PC_IMM_BRANCH);
+ARMV8_EVENT_ATTR(br_return_retired, ARMV8_PMUV3_PERFCTR_PC_PROC_RETURN);
+ARMV8_EVENT_ATTR(unaligned_ldst_retired, ARMV8_PMUV3_PERFCTR_MEM_UNALIGNED_ACCESS);
+ARMV8_EVENT_ATTR(br_mis_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED);
+ARMV8_EVENT_ATTR(cpu_cycles, ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES);
+ARMV8_EVENT_ATTR(br_pred, ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED);
+ARMV8_EVENT_ATTR(mem_access, ARMV8_PMUV3_PERFCTR_MEM_ACCESS);
+ARMV8_EVENT_ATTR(l1i_cache, ARMV8_PMUV3_PERFCTR_L1_ICACHE_ACCESS);
+ARMV8_EVENT_ATTR(l1d_cache_wb, ARMV8_PMUV3_PERFCTR_L1_DCACHE_WB);
+ARMV8_EVENT_ATTR(l2d_cache, ARMV8_PMUV3_PERFCTR_L2_CACHE_ACCESS);
+ARMV8_EVENT_ATTR(l2d_cache_refill, ARMV8_PMUV3_PERFCTR_L2_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l2d_cache_wb, ARMV8_PMUV3_PERFCTR_L2_CACHE_WB);
+ARMV8_EVENT_ATTR(bus_access, ARMV8_PMUV3_PERFCTR_BUS_ACCESS);
+ARMV8_EVENT_ATTR(memory_error, ARMV8_PMUV3_PERFCTR_MEM_ERROR);
+ARMV8_EVENT_ATTR(inst_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC);
+ARMV8_EVENT_ATTR(ttbr_write_retired, ARMV8_PMUV3_PERFCTR_TTBR_WRITE);
+ARMV8_EVENT_ATTR(bus_cycles, ARMV8_PMUV3_PERFCTR_BUS_CYCLES);
+ARMV8_EVENT_ATTR(chain, ARMV8_PMUV3_PERFCTR_CHAIN);
+ARMV8_EVENT_ATTR(l1d_cache_allocate, ARMV8_PMUV3_PERFCTR_L1D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l2d_cache_allocate, ARMV8_PMUV3_PERFCTR_L2D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(br_retired, ARMV8_PMUV3_PERFCTR_BR_RETIRED);
+ARMV8_EVENT_ATTR(br_mis_pred_retired, ARMV8_PMUV3_PERFCTR_BR_MIS_PRED_RETIRED);
+ARMV8_EVENT_ATTR(stall_frontend, ARMV8_PMUV3_PERFCTR_STALL_FRONTEND);
+ARMV8_EVENT_ATTR(stall_backend, ARMV8_PMUV3_PERFCTR_STALL_BACKEND);
+ARMV8_EVENT_ATTR(l1d_tlb, ARMV8_PMUV3_PERFCTR_L1D_TLB);
+ARMV8_EVENT_ATTR(l1i_tlb, ARMV8_PMUV3_PERFCTR_L1I_TLB);
+ARMV8_EVENT_ATTR(l2i_cache, ARMV8_PMUV3_PERFCTR_L2I_CACHE);
+ARMV8_EVENT_ATTR(l2i_cache_refill, ARMV8_PMUV3_PERFCTR_L2I_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache_allocate, ARMV8_PMUV3_PERFCTR_L3D_CACHE_ALLOCATE);
+ARMV8_EVENT_ATTR(l3d_cache_refill, ARMV8_PMUV3_PERFCTR_L3D_CACHE_REFILL);
+ARMV8_EVENT_ATTR(l3d_cache, ARMV8_PMUV3_PERFCTR_L3D_CACHE);
+ARMV8_EVENT_ATTR(l3d_cache_wb, ARMV8_PMUV3_PERFCTR_L3D_CACHE_WB);
+ARMV8_EVENT_ATTR(l2d_tlb_refill, ARMV8_PMUV3_PERFCTR_L2D_TLB_REFILL);
+ARMV8_EVENT_ATTR(l21_tlb_refill, ARMV8_PMUV3_PERFCTR_L21_TLB_REFILL);
+ARMV8_EVENT_ATTR(l2d_tlb, ARMV8_PMUV3_PERFCTR_L2D_TLB);
+ARMV8_EVENT_ATTR(l21_tlb, ARMV8_PMUV3_PERFCTR_L21_TLB);
+
+static struct attribute *armv8_pmuv3_event_attrs[] = {
+ &armv8_event_attr_sw_incr.attr.attr,
+ &armv8_event_attr_l1i_cache_refill.attr.attr,
+ &armv8_event_attr_l1i_tlb_refill.attr.attr,
+ &armv8_event_attr_l1d_cache_refill.attr.attr,
+ &armv8_event_attr_l1d_cache.attr.attr,
+ &armv8_event_attr_l1d_tlb_refill.attr.attr,
+ &armv8_event_attr_ld_retired.attr.attr,
+ &armv8_event_attr_st_retired.attr.attr,
+ &armv8_event_attr_inst_retired.attr.attr,
+ &armv8_event_attr_exc_taken.attr.attr,
+ &armv8_event_attr_exc_return.attr.attr,
+ &armv8_event_attr_cid_write_retired.attr.attr,
+ &armv8_event_attr_pc_write_retired.attr.attr,
+ &armv8_event_attr_br_immed_retired.attr.attr,
+ &armv8_event_attr_br_return_retired.attr.attr,
+ &armv8_event_attr_unaligned_ldst_retired.attr.attr,
+ &armv8_event_attr_br_mis_pred.attr.attr,
+ &armv8_event_attr_cpu_cycles.attr.attr,
+ &armv8_event_attr_br_pred.attr.attr,
+ &armv8_event_attr_mem_access.attr.attr,
+ &armv8_event_attr_l1i_cache.attr.attr,
+ &armv8_event_attr_l1d_cache_wb.attr.attr,
+ &armv8_event_attr_l2d_cache.attr.attr,
+ &armv8_event_attr_l2d_cache_refill.attr.attr,
+ &armv8_event_attr_l2d_cache_wb.attr.attr,
+ &armv8_event_attr_bus_access.attr.attr,
+ &armv8_event_attr_memory_error.attr.attr,
+ &armv8_event_attr_inst_spec.attr.attr,
+ &armv8_event_attr_ttbr_write_retired.attr.attr,
+ &armv8_event_attr_bus_cycles.attr.attr,
+ &armv8_event_attr_chain.attr.attr,
+ &armv8_event_attr_l1d_cache_allocate.attr.attr,
+ &armv8_event_attr_l2d_cache_allocate.attr.attr,
+ &armv8_event_attr_br_retired.attr.attr,
+ &armv8_event_attr_br_mis_pred_retired.attr.attr,
+ &armv8_event_attr_stall_frontend.attr.attr,
+ &armv8_event_attr_stall_backend.attr.attr,
+ &armv8_event_attr_l1d_tlb.attr.attr,
+ &armv8_event_attr_l1i_tlb.attr.attr,
+ &armv8_event_attr_l2i_cache.attr.attr,
+ &armv8_event_attr_l2i_cache_refill.attr.attr,
+ &armv8_event_attr_l3d_cache_allocate.attr.attr,
+ &armv8_event_attr_l3d_cache_refill.attr.attr,
+ &armv8_event_attr_l3d_cache.attr.attr,
+ &armv8_event_attr_l3d_cache_wb.attr.attr,
+ &armv8_event_attr_l2d_tlb_refill.attr.attr,
+ &armv8_event_attr_l21_tlb_refill.attr.attr,
+ &armv8_event_attr_l2d_tlb.attr.attr,
+ &armv8_event_attr_l21_tlb.attr.attr,
+ NULL,
+};
+
+static struct attribute_group armv8_pmuv3_events_attr_group = {
+ .name = "events",
+ .attrs = armv8_pmuv3_event_attrs,
+};
+
+PMU_FORMAT_ATTR(event, "config:0-9");
+
+static struct attribute *armv8_pmuv3_format_attrs[] = {
+ &format_attr_event.attr,
+ NULL,
+};
+
+static struct attribute_group armv8_pmuv3_format_attr_group = {
+ .name = "format",
+ .attrs = armv8_pmuv3_format_attrs,
+};
+
+static const struct attribute_group *armv8_pmuv3_attr_groups[] = {
+ &armv8_pmuv3_events_attr_group,
+ &armv8_pmuv3_format_attr_group,
+ NULL,
+};
+
/*
* Perf Events' indices
@@ -574,9 +720,6 @@ static void armv8pmu_reset(void *info)
/* Initialize & Reset PMNC: C and P bits. */
armv8pmu_pmcr_write(ARMV8_PMCR_P | ARMV8_PMCR_C);
-
- /* Disable access from userspace. */
- asm volatile("msr pmuserenr_el0, %0" :: "r" (0));
}
static int armv8_pmuv3_map_event(struct perf_event *event)
@@ -646,6 +789,7 @@ static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cortex_a53";
cpu_pmu->map_event = armv8_a53_map_event;
+ cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
return armv8pmu_probe_num_events(cpu_pmu);
}
@@ -654,6 +798,16 @@ static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
armv8_pmu_init(cpu_pmu);
cpu_pmu->name = "armv8_cortex_a57";
cpu_pmu->map_event = armv8_a57_map_event;
+ cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
+ return armv8pmu_probe_num_events(cpu_pmu);
+}
+
+static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
+{
+ armv8_pmu_init(cpu_pmu);
+ cpu_pmu->name = "armv8_cortex_a72";
+ cpu_pmu->map_event = armv8_a57_map_event;
+ cpu_pmu->pmu.attr_groups = armv8_pmuv3_attr_groups;
return armv8pmu_probe_num_events(cpu_pmu);
}
@@ -661,6 +815,7 @@ static const struct of_device_id armv8_pmu_of_device_ids[] = {
{.compatible = "arm,armv8-pmuv3", .data = armv8_pmuv3_init},
{.compatible = "arm,cortex-a53-pmu", .data = armv8_a53_pmu_init},
{.compatible = "arm,cortex-a57-pmu", .data = armv8_a57_pmu_init},
+ {.compatible = "arm,cortex-a72-pmu", .data = armv8_a72_pmu_init},
{},
};
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c
index f75b540..88d742b 100644
--- a/arch/arm64/kernel/process.c
+++ b/arch/arm64/kernel/process.c
@@ -344,11 +344,14 @@ unsigned long get_wchan(struct task_struct *p)
frame.fp = thread_saved_fp(p);
frame.sp = thread_saved_sp(p);
frame.pc = thread_saved_pc(p);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = p->curr_ret_stack;
+#endif
stack_page = (unsigned long)task_stack_page(p);
do {
if (frame.sp < stack_page ||
frame.sp >= stack_page + THREAD_SIZE ||
- unwind_frame(&frame))
+ unwind_frame(p, &frame))
return 0;
if (!in_sched_functions(frame.pc))
return frame.pc;
diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c
index aa94a88..f67f35b 100644
--- a/arch/arm64/kernel/psci.c
+++ b/arch/arm64/kernel/psci.c
@@ -30,20 +30,6 @@
#include <asm/smp_plat.h>
#include <asm/suspend.h>
-static bool psci_power_state_loses_context(u32 state)
-{
- return state & PSCI_0_2_POWER_STATE_TYPE_MASK;
-}
-
-static bool psci_power_state_is_valid(u32 state)
-{
- const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK |
- PSCI_0_2_POWER_STATE_TYPE_MASK |
- PSCI_0_2_POWER_STATE_AFFL_MASK;
-
- return !(state & ~valid_mask);
-}
-
static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 1971f49..ff7f132 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -58,6 +58,12 @@
*/
void ptrace_disable(struct task_struct *child)
{
+ /*
+ * This would be better off in core code, but PTRACE_DETACH has
+ * grown its fair share of arch-specific worts and changing it
+ * is likely to cause regressions on obscure architectures.
+ */
+ user_disable_single_step(child);
}
#ifdef CONFIG_HAVE_HW_BREAKPOINT
diff --git a/arch/arm64/kernel/return_address.c b/arch/arm64/kernel/return_address.c
index 6c4fd28..1718706 100644
--- a/arch/arm64/kernel/return_address.c
+++ b/arch/arm64/kernel/return_address.c
@@ -43,8 +43,11 @@ void *return_address(unsigned int level)
frame.fp = (unsigned long)__builtin_frame_address(0);
frame.sp = current_stack_pointer;
frame.pc = (unsigned long)return_address; /* dummy */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = current->curr_ret_stack;
+#endif
- walk_stackframe(&frame, save_return_addr, &data);
+ walk_stackframe(current, &frame, save_return_addr, &data);
if (!data.level)
return data.addr;
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index f586f7c..e33fe33 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -173,6 +173,9 @@ ENTRY(cpu_resume)
/* load physical address of identity map page table in x1 */
adrp x1, idmap_pg_dir
mov sp, x2
+ /* save thread_info */
+ and x2, x2, #~(THREAD_SIZE - 1)
+ msr sp_el0, x2
/*
* cpu_do_resume expects x0 to contain context physical address
* pointer and x1 to contain physical address of 1:1 page tables
diff --git a/arch/arm64/kernel/smccc-call.S b/arch/arm64/kernel/smccc-call.S
new file mode 100644
index 0000000..ae0496f
--- /dev/null
+++ b/arch/arm64/kernel/smccc-call.S
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+
+ .macro SMCCC instr
+ .cfi_startproc
+ \instr #0
+ ldr x4, [sp]
+ stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
+ stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
+ ret
+ .cfi_endproc
+ .endm
+
+/*
+ * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_smc)
+ SMCCC smc
+ENDPROC(arm_smccc_smc)
+
+/*
+ * void arm_smccc_hvc(unsigned long a0, unsigned long a1, unsigned long a2,
+ * unsigned long a3, unsigned long a4, unsigned long a5,
+ * unsigned long a6, unsigned long a7, struct arm_smccc_res *res)
+ */
+ENTRY(arm_smccc_hvc)
+ SMCCC hvc
+ENDPROC(arm_smccc_hvc)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 2bbdc0e..b1adc51 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -473,7 +473,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
* cpu logical map array containing MPIDR values related to logical
* cpus. Assumes that cpu_logical_map(0) has already been initialized.
*/
-void __init of_parse_and_init_cpus(void)
+static void __init of_parse_and_init_cpus(void)
{
struct device_node *dn = NULL;
diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c
index ccb6078..4fad978 100644
--- a/arch/arm64/kernel/stacktrace.c
+++ b/arch/arm64/kernel/stacktrace.c
@@ -17,9 +17,11 @@
*/
#include <linux/kernel.h>
#include <linux/export.h>
+#include <linux/ftrace.h>
#include <linux/sched.h>
#include <linux/stacktrace.h>
+#include <asm/irq.h>
#include <asm/stacktrace.h>
/*
@@ -35,25 +37,83 @@
* ldp x29, x30, [sp]
* add sp, sp, #0x10
*/
-int notrace unwind_frame(struct stackframe *frame)
+int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame)
{
unsigned long high, low;
unsigned long fp = frame->fp;
+ unsigned long irq_stack_ptr;
+
+ /*
+ * Use raw_smp_processor_id() to avoid false-positives from
+ * CONFIG_DEBUG_PREEMPT. get_wchan() calls unwind_frame() on sleeping
+ * task stacks, we can be pre-empted in this case, so
+ * {raw_,}smp_processor_id() may give us the wrong value. Sleeping
+ * tasks can't ever be on an interrupt stack, so regardless of cpu,
+ * the checks will always fail.
+ */
+ irq_stack_ptr = IRQ_STACK_PTR(raw_smp_processor_id());
low = frame->sp;
- high = ALIGN(low, THREAD_SIZE);
+ /* irq stacks are not THREAD_SIZE aligned */
+ if (on_irq_stack(frame->sp, raw_smp_processor_id()))
+ high = irq_stack_ptr;
+ else
+ high = ALIGN(low, THREAD_SIZE) - 0x20;
- if (fp < low || fp > high - 0x18 || fp & 0xf)
+ if (fp < low || fp > high || fp & 0xf)
return -EINVAL;
frame->sp = fp + 0x10;
frame->fp = *(unsigned long *)(fp);
frame->pc = *(unsigned long *)(fp + 8);
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ if (tsk && tsk->ret_stack &&
+ (frame->pc == (unsigned long)return_to_handler)) {
+ /*
+ * This is a case where function graph tracer has
+ * modified a return address (LR) in a stack frame
+ * to hook a function return.
+ * So replace it to an original value.
+ */
+ frame->pc = tsk->ret_stack[frame->graph--].ret;
+ }
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+ /*
+ * Check whether we are going to walk through from interrupt stack
+ * to task stack.
+ * If we reach the end of the stack - and its an interrupt stack,
+ * unpack the dummy frame to find the original elr.
+ *
+ * Check the frame->fp we read from the bottom of the irq_stack,
+ * and the original task stack pointer are both in current->stack.
+ */
+ if (frame->sp == irq_stack_ptr) {
+ struct pt_regs *irq_args;
+ unsigned long orig_sp = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
+ if (object_is_on_stack((void *)orig_sp) &&
+ object_is_on_stack((void *)frame->fp)) {
+ frame->sp = orig_sp;
+
+ /* orig_sp is the saved pt_regs, find the elr */
+ irq_args = (struct pt_regs *)orig_sp;
+ frame->pc = irq_args->pc;
+ } else {
+ /*
+ * This frame has a non-standard format, and we
+ * didn't fix it, because the data looked wrong.
+ * Refuse to output this frame.
+ */
+ return -EINVAL;
+ }
+ }
+
return 0;
}
-void notrace walk_stackframe(struct stackframe *frame,
+void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame,
int (*fn)(struct stackframe *, void *), void *data)
{
while (1) {
@@ -61,7 +121,7 @@ void notrace walk_stackframe(struct stackframe *frame,
if (fn(frame, data))
break;
- ret = unwind_frame(frame);
+ ret = unwind_frame(tsk, frame);
if (ret < 0)
break;
}
@@ -112,8 +172,11 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
frame.sp = current_stack_pointer;
frame.pc = (unsigned long)save_stack_trace_tsk;
}
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = tsk->curr_ret_stack;
+#endif
- walk_stackframe(&frame, save_trace, &data);
+ walk_stackframe(tsk, &frame, save_trace, &data);
if (trace->nr_entries < trace->max_entries)
trace->entries[trace->nr_entries++] = ULONG_MAX;
}
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 40f7b33..1095aa4 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -1,3 +1,4 @@
+#include <linux/ftrace.h>
#include <linux/percpu.h>
#include <linux/slab.h>
#include <asm/cacheflush.h>
@@ -41,7 +42,7 @@ void notrace __cpu_suspend_save(struct cpu_suspend_ctx *ptr,
* time the notifier runs debug exceptions might have been enabled already,
* with HW breakpoints registers content still in an unknown state.
*/
-void (*hw_breakpoint_restore)(void *);
+static void (*hw_breakpoint_restore)(void *);
void __init cpu_suspend_set_dbg_restorer(void (*hw_bp_restore)(void *))
{
/* Prevent multiple restore hook initializations */
@@ -71,6 +72,13 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
local_dbg_save(flags);
/*
+ * Function graph tracer state gets incosistent when the kernel
+ * calls functions that never return (aka suspend finishers) hence
+ * disable graph tracing during their execution.
+ */
+ pause_graph_tracing();
+
+ /*
* mm context saved on the stack, it will be restored when
* the cpu comes out of reset through the identity mapped
* page tables, so that the thread address space is properly
@@ -111,6 +119,8 @@ int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
hw_breakpoint_restore(NULL);
}
+ unpause_graph_tracing();
+
/*
* Restore pstate flags. OS lock and mdscr have been already
* restored, so from this point onwards, debugging is fully
diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c
index 13339b6..5977969 100644
--- a/arch/arm64/kernel/time.c
+++ b/arch/arm64/kernel/time.c
@@ -52,8 +52,11 @@ unsigned long profile_pc(struct pt_regs *regs)
frame.fp = regs->regs[29];
frame.sp = regs->sp;
frame.pc = regs->pc;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = -1; /* no task info */
+#endif
do {
- int ret = unwind_frame(&frame);
+ int ret = unwind_frame(NULL, &frame);
if (ret < 0)
return 0;
} while (in_lock_functions(frame.pc));
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index e9b9b53..cbedd72 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -146,17 +146,15 @@ static void dump_instr(const char *lvl, struct pt_regs *regs)
static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
struct stackframe frame;
+ unsigned long irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
+ int skip;
pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);
if (!tsk)
tsk = current;
- if (regs) {
- frame.fp = regs->regs[29];
- frame.sp = regs->sp;
- frame.pc = regs->pc;
- } else if (tsk == current) {
+ if (tsk == current) {
frame.fp = (unsigned long)__builtin_frame_address(0);
frame.sp = current_stack_pointer;
frame.pc = (unsigned long)dump_backtrace;
@@ -168,21 +166,49 @@ static void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
frame.sp = thread_saved_sp(tsk);
frame.pc = thread_saved_pc(tsk);
}
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ frame.graph = tsk->curr_ret_stack;
+#endif
- pr_emerg("Call trace:\n");
+ skip = !!regs;
+ printk("Call trace:\n");
while (1) {
unsigned long where = frame.pc;
unsigned long stack;
int ret;
- dump_backtrace_entry(where);
- ret = unwind_frame(&frame);
+ /* skip until specified stack frame */
+ if (!skip) {
+ dump_backtrace_entry(where);
+ } else if (frame.fp == regs->regs[29]) {
+ skip = 0;
+ /*
+ * Mostly, this is the case where this function is
+ * called in panic/abort. As exception handler's
+ * stack frame does not contain the corresponding pc
+ * at which an exception has taken place, use regs->pc
+ * instead.
+ */
+ dump_backtrace_entry(regs->pc);
+ }
+ ret = unwind_frame(tsk, &frame);
if (ret < 0)
break;
stack = frame.sp;
- if (in_exception_text(where))
+ if (in_exception_text(where)) {
+ /*
+ * If we switched to the irq_stack before calling this
+ * exception handler, then the pt_regs will be on the
+ * task stack. The easiest way to tell is if the large
+ * pt_regs would overlap with the end of the irq_stack.
+ */
+ if (stack < irq_stack_ptr &&
+ (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
+ stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);
+
dump_mem("", "Exception stack", stack,
stack + sizeof(struct pt_regs), false);
+ }
}
}
@@ -456,22 +482,22 @@ asmlinkage void bad_mode(struct pt_regs *regs, int reason, unsigned int esr)
void __pte_error(const char *file, int line, unsigned long val)
{
- pr_crit("%s:%d: bad pte %016lx.\n", file, line, val);
+ pr_err("%s:%d: bad pte %016lx.\n", file, line, val);
}
void __pmd_error(const char *file, int line, unsigned long val)
{
- pr_crit("%s:%d: bad pmd %016lx.\n", file, line, val);
+ pr_err("%s:%d: bad pmd %016lx.\n", file, line, val);
}
void __pud_error(const char *file, int line, unsigned long val)
{
- pr_crit("%s:%d: bad pud %016lx.\n", file, line, val);
+ pr_err("%s:%d: bad pud %016lx.\n", file, line, val);
}
void __pgd_error(const char *file, int line, unsigned long val)
{
- pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val);
+ pr_err("%s:%d: bad pgd %016lx.\n", file, line, val);
}
/* GENERIC_BUG traps */
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index f6fe17d..b467fd0 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -15,6 +15,9 @@ ccflags-y := -shared -fno-common -fno-builtin
ccflags-y += -nostdlib -Wl,-soname=linux-vdso.so.1 \
$(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
# Workaround for bare-metal (ELF) toolchains that neglect to pass -shared
# down to collect2, resulting in silent corruption of the vDSO image.
ccflags-y += -Wl,-shared
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index 1ee2c39..e3928f5 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -5,6 +5,7 @@
*/
#include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
#include <asm/kernel-pgtable.h>
#include <asm/thread_info.h>
#include <asm/memory.h>
@@ -112,7 +113,6 @@ SECTIONS
*(.got) /* Global offset table */
}
- ALIGN_DEBUG_RO
RO_DATA(PAGE_SIZE)
EXCEPTION_TABLE(8)
NOTES
@@ -127,7 +127,6 @@ SECTIONS
ARM_EXIT_KEEP(EXIT_TEXT)
}
- ALIGN_DEBUG_RO_MIN(16)
.init.data : {
INIT_DATA
INIT_SETUP(16)
@@ -140,10 +139,7 @@ SECTIONS
ARM_EXIT_KEEP(EXIT_DATA)
}
- PERCPU_SECTION(64)
-
- . = ALIGN(PAGE_SIZE);
- __init_end = .;
+ PERCPU_SECTION(L1_CACHE_BYTES)
. = ALIGN(4);
.altinstructions : {
@@ -156,9 +152,11 @@ SECTIONS
}
. = ALIGN(PAGE_SIZE);
+ __init_end = .;
+
_data = .;
_sdata = .;
- RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
+ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
PECOFF_EDATA_PADDING
_edata = .;
diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
index 1949fe5..caee9ee 100644
--- a/arch/arm64/kvm/Makefile
+++ b/arch/arm64/kvm/Makefile
@@ -10,6 +10,7 @@ KVM=../../../virt/kvm
ARM=../../../arch/arm/kvm
obj-$(CONFIG_KVM_ARM_HOST) += kvm.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp/
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/eventfd.o $(KVM)/vfio.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/arm.o $(ARM)/mmu.o $(ARM)/mmio.o
@@ -22,8 +23,6 @@ kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generi
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v2-switch.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v3-emul.o
-kvm-$(CONFIG_KVM_ARM_HOST) += vgic-v3-switch.o
kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arch_timer.o
diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
index d250160..fcb7788 100644
--- a/arch/arm64/kvm/guest.c
+++ b/arch/arm64/kvm/guest.c
@@ -28,13 +28,21 @@
#include <asm/cputype.h>
#include <asm/uaccess.h>
#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_coproc.h>
#include "trace.h"
+#define VM_STAT(x) { #x, offsetof(struct kvm, stat.x), KVM_STAT_VM }
+#define VCPU_STAT(x) { #x, offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU }
+
struct kvm_stats_debugfs_item debugfs_entries[] = {
+ VCPU_STAT(hvc_exit_stat),
+ VCPU_STAT(wfe_exit_stat),
+ VCPU_STAT(wfi_exit_stat),
+ VCPU_STAT(mmio_exit_user),
+ VCPU_STAT(mmio_exit_kernel),
+ VCPU_STAT(exits),
{ NULL }
};
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 68a0759..eba89e4 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -23,6 +23,7 @@
#include <linux/kvm_host.h>
#include <asm/esr.h>
+#include <asm/kvm_asm.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
@@ -37,8 +38,9 @@ static int handle_hvc(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
int ret;
- trace_kvm_hvc_arm64(*vcpu_pc(vcpu), *vcpu_reg(vcpu, 0),
+ trace_kvm_hvc_arm64(*vcpu_pc(vcpu), vcpu_get_reg(vcpu, 0),
kvm_vcpu_hvc_get_imm(vcpu));
+ vcpu->stat.hvc_exit_stat++;
ret = kvm_psci_call(vcpu);
if (ret < 0) {
@@ -71,9 +73,11 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
if (kvm_vcpu_get_hsr(vcpu) & ESR_ELx_WFx_ISS_WFE) {
trace_kvm_wfx_arm64(*vcpu_pc(vcpu), true);
+ vcpu->stat.wfe_exit_stat++;
kvm_vcpu_on_spin(vcpu);
} else {
trace_kvm_wfx_arm64(*vcpu_pc(vcpu), false);
+ vcpu->stat.wfi_exit_stat++;
kvm_vcpu_block(vcpu);
}
diff --git a/arch/arm64/kvm/hyp-init.S b/arch/arm64/kvm/hyp-init.S
index 178ba22..3e568dc 100644
--- a/arch/arm64/kvm/hyp-init.S
+++ b/arch/arm64/kvm/hyp-init.S
@@ -94,6 +94,15 @@ __do_hyp_init:
*/
mrs x5, ID_AA64MMFR0_EL1
bfi x4, x5, #16, #3
+ /*
+ * Read the VMIDBits bits from ID_AA64MMFR1_EL1 and set the VS bit in
+ * VTCR_EL2.
+ */
+ mrs x5, ID_AA64MMFR1_EL1
+ ubfx x5, x5, #5, #1
+ lsl x5, x5, #VTCR_EL2_VS
+ orr x4, x4, x5
+
msr vtcr_el2, x4
mrs x4, mair_el1
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index 1599701..0ccdcbb 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -17,906 +17,7 @@
#include <linux/linkage.h>
-#include <asm/alternative.h>
-#include <asm/asm-offsets.h>
#include <asm/assembler.h>
-#include <asm/cpufeature.h>
-#include <asm/debug-monitors.h>
-#include <asm/esr.h>
-#include <asm/fpsimdmacros.h>
-#include <asm/kvm.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_mmu.h>
-#include <asm/memory.h>
-
-#define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
-#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
-#define CPU_SPSR_OFFSET(x) CPU_GP_REG_OFFSET(CPU_SPSR + 8*x)
-#define CPU_SYSREG_OFFSET(x) (CPU_SYSREGS + 8*x)
-
- .text
- .pushsection .hyp.text, "ax"
- .align PAGE_SHIFT
-
-.macro save_common_regs
- // x2: base address for cpu context
- // x3: tmp register
-
- add x3, x2, #CPU_XREG_OFFSET(19)
- stp x19, x20, [x3]
- stp x21, x22, [x3, #16]
- stp x23, x24, [x3, #32]
- stp x25, x26, [x3, #48]
- stp x27, x28, [x3, #64]
- stp x29, lr, [x3, #80]
-
- mrs x19, sp_el0
- mrs x20, elr_el2 // pc before entering el2
- mrs x21, spsr_el2 // pstate before entering el2
-
- stp x19, x20, [x3, #96]
- str x21, [x3, #112]
-
- mrs x22, sp_el1
- mrs x23, elr_el1
- mrs x24, spsr_el1
-
- str x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
- str x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
- str x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-.endm
-
-.macro restore_common_regs
- // x2: base address for cpu context
- // x3: tmp register
-
- ldr x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
- ldr x23, [x2, #CPU_GP_REG_OFFSET(CPU_ELR_EL1)]
- ldr x24, [x2, #CPU_SPSR_OFFSET(KVM_SPSR_EL1)]
-
- msr sp_el1, x22
- msr elr_el1, x23
- msr spsr_el1, x24
-
- add x3, x2, #CPU_XREG_OFFSET(31) // SP_EL0
- ldp x19, x20, [x3]
- ldr x21, [x3, #16]
-
- msr sp_el0, x19
- msr elr_el2, x20 // pc on return from el2
- msr spsr_el2, x21 // pstate on return from el2
-
- add x3, x2, #CPU_XREG_OFFSET(19)
- ldp x19, x20, [x3]
- ldp x21, x22, [x3, #16]
- ldp x23, x24, [x3, #32]
- ldp x25, x26, [x3, #48]
- ldp x27, x28, [x3, #64]
- ldp x29, lr, [x3, #80]
-.endm
-
-.macro save_host_regs
- save_common_regs
-.endm
-
-.macro restore_host_regs
- restore_common_regs
-.endm
-
-.macro save_fpsimd
- // x2: cpu context address
- // x3, x4: tmp regs
- add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
- fpsimd_save x3, 4
-.endm
-
-.macro restore_fpsimd
- // x2: cpu context address
- // x3, x4: tmp regs
- add x3, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
- fpsimd_restore x3, 4
-.endm
-
-.macro save_guest_regs
- // x0 is the vcpu address
- // x1 is the return code, do not corrupt!
- // x2 is the cpu context
- // x3 is a tmp register
- // Guest's x0-x3 are on the stack
-
- // Compute base to save registers
- add x3, x2, #CPU_XREG_OFFSET(4)
- stp x4, x5, [x3]
- stp x6, x7, [x3, #16]
- stp x8, x9, [x3, #32]
- stp x10, x11, [x3, #48]
- stp x12, x13, [x3, #64]
- stp x14, x15, [x3, #80]
- stp x16, x17, [x3, #96]
- str x18, [x3, #112]
-
- pop x6, x7 // x2, x3
- pop x4, x5 // x0, x1
-
- add x3, x2, #CPU_XREG_OFFSET(0)
- stp x4, x5, [x3]
- stp x6, x7, [x3, #16]
-
- save_common_regs
-.endm
-
-.macro restore_guest_regs
- // x0 is the vcpu address.
- // x2 is the cpu context
- // x3 is a tmp register
-
- // Prepare x0-x3 for later restore
- add x3, x2, #CPU_XREG_OFFSET(0)
- ldp x4, x5, [x3]
- ldp x6, x7, [x3, #16]
- push x4, x5 // Push x0-x3 on the stack
- push x6, x7
-
- // x4-x18
- ldp x4, x5, [x3, #32]
- ldp x6, x7, [x3, #48]
- ldp x8, x9, [x3, #64]
- ldp x10, x11, [x3, #80]
- ldp x12, x13, [x3, #96]
- ldp x14, x15, [x3, #112]
- ldp x16, x17, [x3, #128]
- ldr x18, [x3, #144]
-
- // x19-x29, lr, sp*, elr*, spsr*
- restore_common_regs
-
- // Last bits of the 64bit state
- pop x2, x3
- pop x0, x1
-
- // Do not touch any register after this!
-.endm
-
-/*
- * Macros to perform system register save/restore.
- *
- * Ordering here is absolutely critical, and must be kept consistent
- * in {save,restore}_sysregs, {save,restore}_guest_32bit_state,
- * and in kvm_asm.h.
- *
- * In other words, don't touch any of these unless you know what
- * you are doing.
- */
-.macro save_sysregs
- // x2: base address for cpu context
- // x3: tmp register
-
- add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
-
- mrs x4, vmpidr_el2
- mrs x5, csselr_el1
- mrs x6, sctlr_el1
- mrs x7, actlr_el1
- mrs x8, cpacr_el1
- mrs x9, ttbr0_el1
- mrs x10, ttbr1_el1
- mrs x11, tcr_el1
- mrs x12, esr_el1
- mrs x13, afsr0_el1
- mrs x14, afsr1_el1
- mrs x15, far_el1
- mrs x16, mair_el1
- mrs x17, vbar_el1
- mrs x18, contextidr_el1
- mrs x19, tpidr_el0
- mrs x20, tpidrro_el0
- mrs x21, tpidr_el1
- mrs x22, amair_el1
- mrs x23, cntkctl_el1
- mrs x24, par_el1
- mrs x25, mdscr_el1
-
- stp x4, x5, [x3]
- stp x6, x7, [x3, #16]
- stp x8, x9, [x3, #32]
- stp x10, x11, [x3, #48]
- stp x12, x13, [x3, #64]
- stp x14, x15, [x3, #80]
- stp x16, x17, [x3, #96]
- stp x18, x19, [x3, #112]
- stp x20, x21, [x3, #128]
- stp x22, x23, [x3, #144]
- stp x24, x25, [x3, #160]
-.endm
-
-.macro save_debug type
- // x4: pointer to register set
- // x5: number of registers to skip
- // x6..x22 trashed
-
- adr x22, 1f
- add x22, x22, x5, lsl #2
- br x22
-1:
- mrs x21, \type\()15_el1
- mrs x20, \type\()14_el1
- mrs x19, \type\()13_el1
- mrs x18, \type\()12_el1
- mrs x17, \type\()11_el1
- mrs x16, \type\()10_el1
- mrs x15, \type\()9_el1
- mrs x14, \type\()8_el1
- mrs x13, \type\()7_el1
- mrs x12, \type\()6_el1
- mrs x11, \type\()5_el1
- mrs x10, \type\()4_el1
- mrs x9, \type\()3_el1
- mrs x8, \type\()2_el1
- mrs x7, \type\()1_el1
- mrs x6, \type\()0_el1
-
- adr x22, 1f
- add x22, x22, x5, lsl #2
- br x22
-1:
- str x21, [x4, #(15 * 8)]
- str x20, [x4, #(14 * 8)]
- str x19, [x4, #(13 * 8)]
- str x18, [x4, #(12 * 8)]
- str x17, [x4, #(11 * 8)]
- str x16, [x4, #(10 * 8)]
- str x15, [x4, #(9 * 8)]
- str x14, [x4, #(8 * 8)]
- str x13, [x4, #(7 * 8)]
- str x12, [x4, #(6 * 8)]
- str x11, [x4, #(5 * 8)]
- str x10, [x4, #(4 * 8)]
- str x9, [x4, #(3 * 8)]
- str x8, [x4, #(2 * 8)]
- str x7, [x4, #(1 * 8)]
- str x6, [x4, #(0 * 8)]
-.endm
-
-.macro restore_sysregs
- // x2: base address for cpu context
- // x3: tmp register
-
- add x3, x2, #CPU_SYSREG_OFFSET(MPIDR_EL1)
-
- ldp x4, x5, [x3]
- ldp x6, x7, [x3, #16]
- ldp x8, x9, [x3, #32]
- ldp x10, x11, [x3, #48]
- ldp x12, x13, [x3, #64]
- ldp x14, x15, [x3, #80]
- ldp x16, x17, [x3, #96]
- ldp x18, x19, [x3, #112]
- ldp x20, x21, [x3, #128]
- ldp x22, x23, [x3, #144]
- ldp x24, x25, [x3, #160]
-
- msr vmpidr_el2, x4
- msr csselr_el1, x5
- msr sctlr_el1, x6
- msr actlr_el1, x7
- msr cpacr_el1, x8
- msr ttbr0_el1, x9
- msr ttbr1_el1, x10
- msr tcr_el1, x11
- msr esr_el1, x12
- msr afsr0_el1, x13
- msr afsr1_el1, x14
- msr far_el1, x15
- msr mair_el1, x16
- msr vbar_el1, x17
- msr contextidr_el1, x18
- msr tpidr_el0, x19
- msr tpidrro_el0, x20
- msr tpidr_el1, x21
- msr amair_el1, x22
- msr cntkctl_el1, x23
- msr par_el1, x24
- msr mdscr_el1, x25
-.endm
-
-.macro restore_debug type
- // x4: pointer to register set
- // x5: number of registers to skip
- // x6..x22 trashed
-
- adr x22, 1f
- add x22, x22, x5, lsl #2
- br x22
-1:
- ldr x21, [x4, #(15 * 8)]
- ldr x20, [x4, #(14 * 8)]
- ldr x19, [x4, #(13 * 8)]
- ldr x18, [x4, #(12 * 8)]
- ldr x17, [x4, #(11 * 8)]
- ldr x16, [x4, #(10 * 8)]
- ldr x15, [x4, #(9 * 8)]
- ldr x14, [x4, #(8 * 8)]
- ldr x13, [x4, #(7 * 8)]
- ldr x12, [x4, #(6 * 8)]
- ldr x11, [x4, #(5 * 8)]
- ldr x10, [x4, #(4 * 8)]
- ldr x9, [x4, #(3 * 8)]
- ldr x8, [x4, #(2 * 8)]
- ldr x7, [x4, #(1 * 8)]
- ldr x6, [x4, #(0 * 8)]
-
- adr x22, 1f
- add x22, x22, x5, lsl #2
- br x22
-1:
- msr \type\()15_el1, x21
- msr \type\()14_el1, x20
- msr \type\()13_el1, x19
- msr \type\()12_el1, x18
- msr \type\()11_el1, x17
- msr \type\()10_el1, x16
- msr \type\()9_el1, x15
- msr \type\()8_el1, x14
- msr \type\()7_el1, x13
- msr \type\()6_el1, x12
- msr \type\()5_el1, x11
- msr \type\()4_el1, x10
- msr \type\()3_el1, x9
- msr \type\()2_el1, x8
- msr \type\()1_el1, x7
- msr \type\()0_el1, x6
-.endm
-
-.macro skip_32bit_state tmp, target
- // Skip 32bit state if not needed
- mrs \tmp, hcr_el2
- tbnz \tmp, #HCR_RW_SHIFT, \target
-.endm
-
-.macro skip_tee_state tmp, target
- // Skip ThumbEE state if not needed
- mrs \tmp, id_pfr0_el1
- tbz \tmp, #12, \target
-.endm
-
-.macro skip_debug_state tmp, target
- ldr \tmp, [x0, #VCPU_DEBUG_FLAGS]
- tbz \tmp, #KVM_ARM64_DEBUG_DIRTY_SHIFT, \target
-.endm
-
-/*
- * Branch to target if CPTR_EL2.TFP bit is set (VFP/SIMD trapping enabled)
- */
-.macro skip_fpsimd_state tmp, target
- mrs \tmp, cptr_el2
- tbnz \tmp, #CPTR_EL2_TFP_SHIFT, \target
-.endm
-
-.macro compute_debug_state target
- // Compute debug state: If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY
- // is set, we do a full save/restore cycle and disable trapping.
- add x25, x0, #VCPU_CONTEXT
-
- // Check the state of MDSCR_EL1
- ldr x25, [x25, #CPU_SYSREG_OFFSET(MDSCR_EL1)]
- and x26, x25, #DBG_MDSCR_KDE
- and x25, x25, #DBG_MDSCR_MDE
- adds xzr, x25, x26
- b.eq 9998f // Nothing to see there
-
- // If any interesting bits was set, we must set the flag
- mov x26, #KVM_ARM64_DEBUG_DIRTY
- str x26, [x0, #VCPU_DEBUG_FLAGS]
- b 9999f // Don't skip restore
-
-9998:
- // Otherwise load the flags from memory in case we recently
- // trapped
- skip_debug_state x25, \target
-9999:
-.endm
-
-.macro save_guest_32bit_state
- skip_32bit_state x3, 1f
-
- add x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
- mrs x4, spsr_abt
- mrs x5, spsr_und
- mrs x6, spsr_irq
- mrs x7, spsr_fiq
- stp x4, x5, [x3]
- stp x6, x7, [x3, #16]
-
- add x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
- mrs x4, dacr32_el2
- mrs x5, ifsr32_el2
- stp x4, x5, [x3]
-
- skip_fpsimd_state x8, 2f
- mrs x6, fpexc32_el2
- str x6, [x3, #16]
-2:
- skip_debug_state x8, 1f
- mrs x7, dbgvcr32_el2
- str x7, [x3, #24]
-1:
-.endm
-
-.macro restore_guest_32bit_state
- skip_32bit_state x3, 1f
-
- add x3, x2, #CPU_SPSR_OFFSET(KVM_SPSR_ABT)
- ldp x4, x5, [x3]
- ldp x6, x7, [x3, #16]
- msr spsr_abt, x4
- msr spsr_und, x5
- msr spsr_irq, x6
- msr spsr_fiq, x7
-
- add x3, x2, #CPU_SYSREG_OFFSET(DACR32_EL2)
- ldp x4, x5, [x3]
- msr dacr32_el2, x4
- msr ifsr32_el2, x5
-
- skip_debug_state x8, 1f
- ldr x7, [x3, #24]
- msr dbgvcr32_el2, x7
-1:
-.endm
-
-.macro activate_traps
- ldr x2, [x0, #VCPU_HCR_EL2]
-
- /*
- * We are about to set CPTR_EL2.TFP to trap all floating point
- * register accesses to EL2, however, the ARM ARM clearly states that
- * traps are only taken to EL2 if the operation would not otherwise
- * trap to EL1. Therefore, always make sure that for 32-bit guests,
- * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
- */
- tbnz x2, #HCR_RW_SHIFT, 99f // open code skip_32bit_state
- mov x3, #(1 << 30)
- msr fpexc32_el2, x3
- isb
-99:
- msr hcr_el2, x2
- mov x2, #CPTR_EL2_TTA
- orr x2, x2, #CPTR_EL2_TFP
- msr cptr_el2, x2
-
- mov x2, #(1 << 15) // Trap CP15 Cr=15
- msr hstr_el2, x2
-
- // Monitor Debug Config - see kvm_arm_setup_debug()
- ldr x2, [x0, #VCPU_MDCR_EL2]
- msr mdcr_el2, x2
-.endm
-
-.macro deactivate_traps
- mov x2, #HCR_RW
- msr hcr_el2, x2
- msr hstr_el2, xzr
-
- mrs x2, mdcr_el2
- and x2, x2, #MDCR_EL2_HPMN_MASK
- msr mdcr_el2, x2
-.endm
-
-.macro activate_vm
- ldr x1, [x0, #VCPU_KVM]
- kern_hyp_va x1
- ldr x2, [x1, #KVM_VTTBR]
- msr vttbr_el2, x2
-.endm
-
-.macro deactivate_vm
- msr vttbr_el2, xzr
-.endm
-
-/*
- * Call into the vgic backend for state saving
- */
-.macro save_vgic_state
-alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF
- bl __save_vgic_v2_state
-alternative_else
- bl __save_vgic_v3_state
-alternative_endif
- mrs x24, hcr_el2
- mov x25, #HCR_INT_OVERRIDE
- neg x25, x25
- and x24, x24, x25
- msr hcr_el2, x24
-.endm
-
-/*
- * Call into the vgic backend for state restoring
- */
-.macro restore_vgic_state
- mrs x24, hcr_el2
- ldr x25, [x0, #VCPU_IRQ_LINES]
- orr x24, x24, #HCR_INT_OVERRIDE
- orr x24, x24, x25
- msr hcr_el2, x24
-alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF
- bl __restore_vgic_v2_state
-alternative_else
- bl __restore_vgic_v3_state
-alternative_endif
-.endm
-
-.macro save_timer_state
- // x0: vcpu pointer
- ldr x2, [x0, #VCPU_KVM]
- kern_hyp_va x2
- ldr w3, [x2, #KVM_TIMER_ENABLED]
- cbz w3, 1f
-
- mrs x3, cntv_ctl_el0
- and x3, x3, #3
- str w3, [x0, #VCPU_TIMER_CNTV_CTL]
-
- isb
-
- mrs x3, cntv_cval_el0
- str x3, [x0, #VCPU_TIMER_CNTV_CVAL]
-
-1:
- // Disable the virtual timer
- msr cntv_ctl_el0, xzr
-
- // Allow physical timer/counter access for the host
- mrs x2, cnthctl_el2
- orr x2, x2, #3
- msr cnthctl_el2, x2
-
- // Clear cntvoff for the host
- msr cntvoff_el2, xzr
-.endm
-
-.macro restore_timer_state
- // x0: vcpu pointer
- // Disallow physical timer access for the guest
- // Physical counter access is allowed
- mrs x2, cnthctl_el2
- orr x2, x2, #1
- bic x2, x2, #2
- msr cnthctl_el2, x2
-
- ldr x2, [x0, #VCPU_KVM]
- kern_hyp_va x2
- ldr w3, [x2, #KVM_TIMER_ENABLED]
- cbz w3, 1f
-
- ldr x3, [x2, #KVM_TIMER_CNTVOFF]
- msr cntvoff_el2, x3
- ldr x2, [x0, #VCPU_TIMER_CNTV_CVAL]
- msr cntv_cval_el0, x2
- isb
-
- ldr w2, [x0, #VCPU_TIMER_CNTV_CTL]
- and x2, x2, #3
- msr cntv_ctl_el0, x2
-1:
-.endm
-
-__save_sysregs:
- save_sysregs
- ret
-
-__restore_sysregs:
- restore_sysregs
- ret
-
-/* Save debug state */
-__save_debug:
- // x2: ptr to CPU context
- // x3: ptr to debug reg struct
- // x4/x5/x6-22/x24-26: trashed
-
- mrs x26, id_aa64dfr0_el1
- ubfx x24, x26, #12, #4 // Extract BRPs
- ubfx x25, x26, #20, #4 // Extract WRPs
- mov w26, #15
- sub w24, w26, w24 // How many BPs to skip
- sub w25, w26, w25 // How many WPs to skip
-
- mov x5, x24
- add x4, x3, #DEBUG_BCR
- save_debug dbgbcr
- add x4, x3, #DEBUG_BVR
- save_debug dbgbvr
-
- mov x5, x25
- add x4, x3, #DEBUG_WCR
- save_debug dbgwcr
- add x4, x3, #DEBUG_WVR
- save_debug dbgwvr
-
- mrs x21, mdccint_el1
- str x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
- ret
-
-/* Restore debug state */
-__restore_debug:
- // x2: ptr to CPU context
- // x3: ptr to debug reg struct
- // x4/x5/x6-22/x24-26: trashed
-
- mrs x26, id_aa64dfr0_el1
- ubfx x24, x26, #12, #4 // Extract BRPs
- ubfx x25, x26, #20, #4 // Extract WRPs
- mov w26, #15
- sub w24, w26, w24 // How many BPs to skip
- sub w25, w26, w25 // How many WPs to skip
-
- mov x5, x24
- add x4, x3, #DEBUG_BCR
- restore_debug dbgbcr
- add x4, x3, #DEBUG_BVR
- restore_debug dbgbvr
-
- mov x5, x25
- add x4, x3, #DEBUG_WCR
- restore_debug dbgwcr
- add x4, x3, #DEBUG_WVR
- restore_debug dbgwvr
-
- ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)]
- msr mdccint_el1, x21
-
- ret
-
-__save_fpsimd:
- skip_fpsimd_state x3, 1f
- save_fpsimd
-1: ret
-
-__restore_fpsimd:
- skip_fpsimd_state x3, 1f
- restore_fpsimd
-1: ret
-
-switch_to_guest_fpsimd:
- push x4, lr
-
- mrs x2, cptr_el2
- bic x2, x2, #CPTR_EL2_TFP
- msr cptr_el2, x2
- isb
-
- mrs x0, tpidr_el2
-
- ldr x2, [x0, #VCPU_HOST_CONTEXT]
- kern_hyp_va x2
- bl __save_fpsimd
-
- add x2, x0, #VCPU_CONTEXT
- bl __restore_fpsimd
-
- skip_32bit_state x3, 1f
- ldr x4, [x2, #CPU_SYSREG_OFFSET(FPEXC32_EL2)]
- msr fpexc32_el2, x4
-1:
- pop x4, lr
- pop x2, x3
- pop x0, x1
-
- eret
-
-/*
- * u64 __kvm_vcpu_run(struct kvm_vcpu *vcpu);
- *
- * This is the world switch. The first half of the function
- * deals with entering the guest, and anything from __kvm_vcpu_return
- * to the end of the function deals with reentering the host.
- * On the enter path, only x0 (vcpu pointer) must be preserved until
- * the last moment. On the exit path, x0 (vcpu pointer) and x1 (exception
- * code) must both be preserved until the epilogue.
- * In both cases, x2 points to the CPU context we're saving/restoring from/to.
- */
-ENTRY(__kvm_vcpu_run)
- kern_hyp_va x0
- msr tpidr_el2, x0 // Save the vcpu register
-
- // Host context
- ldr x2, [x0, #VCPU_HOST_CONTEXT]
- kern_hyp_va x2
-
- save_host_regs
- bl __save_sysregs
-
- compute_debug_state 1f
- add x3, x0, #VCPU_HOST_DEBUG_STATE
- bl __save_debug
-1:
- activate_traps
- activate_vm
-
- restore_vgic_state
- restore_timer_state
-
- // Guest context
- add x2, x0, #VCPU_CONTEXT
-
- // We must restore the 32-bit state before the sysregs, thanks
- // to Cortex-A57 erratum #852523.
- restore_guest_32bit_state
- bl __restore_sysregs
-
- skip_debug_state x3, 1f
- ldr x3, [x0, #VCPU_DEBUG_PTR]
- kern_hyp_va x3
- bl __restore_debug
-1:
- restore_guest_regs
-
- // That's it, no more messing around.
- eret
-
-__kvm_vcpu_return:
- // Assume x0 is the vcpu pointer, x1 the return code
- // Guest's x0-x3 are on the stack
-
- // Guest context
- add x2, x0, #VCPU_CONTEXT
-
- save_guest_regs
- bl __save_fpsimd
- bl __save_sysregs
-
- skip_debug_state x3, 1f
- ldr x3, [x0, #VCPU_DEBUG_PTR]
- kern_hyp_va x3
- bl __save_debug
-1:
- save_guest_32bit_state
-
- save_timer_state
- save_vgic_state
-
- deactivate_traps
- deactivate_vm
-
- // Host context
- ldr x2, [x0, #VCPU_HOST_CONTEXT]
- kern_hyp_va x2
-
- bl __restore_sysregs
- bl __restore_fpsimd
- /* Clear FPSIMD and Trace trapping */
- msr cptr_el2, xzr
-
- skip_debug_state x3, 1f
- // Clear the dirty flag for the next run, as all the state has
- // already been saved. Note that we nuke the whole 64bit word.
- // If we ever add more flags, we'll have to be more careful...
- str xzr, [x0, #VCPU_DEBUG_FLAGS]
- add x3, x0, #VCPU_HOST_DEBUG_STATE
- bl __restore_debug
-1:
- restore_host_regs
-
- mov x0, x1
- ret
-END(__kvm_vcpu_run)
-
-// void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa);
-ENTRY(__kvm_tlb_flush_vmid_ipa)
- dsb ishst
-
- kern_hyp_va x0
- ldr x2, [x0, #KVM_VTTBR]
- msr vttbr_el2, x2
- isb
-
- /*
- * We could do so much better if we had the VA as well.
- * Instead, we invalidate Stage-2 for this IPA, and the
- * whole of Stage-1. Weep...
- */
- lsr x1, x1, #12
- tlbi ipas2e1is, x1
- /*
- * We have to ensure completion of the invalidation at Stage-2,
- * since a table walk on another CPU could refill a TLB with a
- * complete (S1 + S2) walk based on the old Stage-2 mapping if
- * the Stage-1 invalidation happened first.
- */
- dsb ish
- tlbi vmalle1is
- dsb ish
- isb
-
- msr vttbr_el2, xzr
- ret
-ENDPROC(__kvm_tlb_flush_vmid_ipa)
-
-/**
- * void __kvm_tlb_flush_vmid(struct kvm *kvm) - Flush per-VMID TLBs
- * @struct kvm *kvm - pointer to kvm structure
- *
- * Invalidates all Stage 1 and 2 TLB entries for current VMID.
- */
-ENTRY(__kvm_tlb_flush_vmid)
- dsb ishst
-
- kern_hyp_va x0
- ldr x2, [x0, #KVM_VTTBR]
- msr vttbr_el2, x2
- isb
-
- tlbi vmalls12e1is
- dsb ish
- isb
-
- msr vttbr_el2, xzr
- ret
-ENDPROC(__kvm_tlb_flush_vmid)
-
-ENTRY(__kvm_flush_vm_context)
- dsb ishst
- tlbi alle1is
- ic ialluis
- dsb ish
- ret
-ENDPROC(__kvm_flush_vm_context)
-
-__kvm_hyp_panic:
- // Guess the context by looking at VTTBR:
- // If zero, then we're already a host.
- // Otherwise restore a minimal host context before panicing.
- mrs x0, vttbr_el2
- cbz x0, 1f
-
- mrs x0, tpidr_el2
-
- deactivate_traps
- deactivate_vm
-
- ldr x2, [x0, #VCPU_HOST_CONTEXT]
- kern_hyp_va x2
-
- bl __restore_sysregs
-
- /*
- * Make sure we have a valid host stack, and don't leave junk in the
- * frame pointer that will give us a misleading host stack unwinding.
- */
- ldr x22, [x2, #CPU_GP_REG_OFFSET(CPU_SP_EL1)]
- msr sp_el1, x22
- mov x29, xzr
-
-1: adr x0, __hyp_panic_str
- adr x1, 2f
- ldp x2, x3, [x1]
- sub x0, x0, x2
- add x0, x0, x3
- mrs x1, spsr_el2
- mrs x2, elr_el2
- mrs x3, esr_el2
- mrs x4, far_el2
- mrs x5, hpfar_el2
- mrs x6, par_el1
- mrs x7, tpidr_el2
-
- mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
- PSR_MODE_EL1h)
- msr spsr_el2, lr
- ldr lr, =panic
- msr elr_el2, lr
- eret
-
- .align 3
-2: .quad HYP_PAGE_OFFSET
- .quad PAGE_OFFSET
-ENDPROC(__kvm_hyp_panic)
-
-__hyp_panic_str:
- .ascii "HYP panic:\nPS:%08x PC:%p ESR:%p\nFAR:%p HPFAR:%p PAR:%p\nVCPU:%p\n\0"
-
- .align 2
/*
* u64 kvm_call_hyp(void *hypfn, ...);
@@ -930,7 +31,7 @@ __hyp_panic_str:
* passed as x0, x1, and x2 (a maximum of 3 arguments in addition to the
* function pointer can be passed). The function being called must be mapped
* in Hyp mode (see init_hyp_mode in arch/arm/kvm/arm.c). Return values are
- * passed in r0 and r1.
+ * passed in x0.
*
* A function pointer with a value of 0 has a special meaning, and is
* used to implement __hyp_get_vectors in the same way as in
@@ -940,173 +41,3 @@ ENTRY(kvm_call_hyp)
hvc #0
ret
ENDPROC(kvm_call_hyp)
-
-.macro invalid_vector label, target
- .align 2
-\label:
- b \target
-ENDPROC(\label)
-.endm
-
- /* None of these should ever happen */
- invalid_vector el2t_sync_invalid, __kvm_hyp_panic
- invalid_vector el2t_irq_invalid, __kvm_hyp_panic
- invalid_vector el2t_fiq_invalid, __kvm_hyp_panic
- invalid_vector el2t_error_invalid, __kvm_hyp_panic
- invalid_vector el2h_sync_invalid, __kvm_hyp_panic
- invalid_vector el2h_irq_invalid, __kvm_hyp_panic
- invalid_vector el2h_fiq_invalid, __kvm_hyp_panic
- invalid_vector el2h_error_invalid, __kvm_hyp_panic
- invalid_vector el1_sync_invalid, __kvm_hyp_panic
- invalid_vector el1_irq_invalid, __kvm_hyp_panic
- invalid_vector el1_fiq_invalid, __kvm_hyp_panic
- invalid_vector el1_error_invalid, __kvm_hyp_panic
-
-el1_sync: // Guest trapped into EL2
- push x0, x1
- push x2, x3
-
- mrs x1, esr_el2
- lsr x2, x1, #ESR_ELx_EC_SHIFT
-
- cmp x2, #ESR_ELx_EC_HVC64
- b.ne el1_trap
-
- mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest
- cbnz x3, el1_trap // called HVC
-
- /* Here, we're pretty sure the host called HVC. */
- pop x2, x3
- pop x0, x1
-
- /* Check for __hyp_get_vectors */
- cbnz x0, 1f
- mrs x0, vbar_el2
- b 2f
-
-1: push lr, xzr
-
- /*
- * Compute the function address in EL2, and shuffle the parameters.
- */
- kern_hyp_va x0
- mov lr, x0
- mov x0, x1
- mov x1, x2
- mov x2, x3
- blr lr
-
- pop lr, xzr
-2: eret
-
-el1_trap:
- /*
- * x1: ESR
- * x2: ESR_EC
- */
-
- /* Guest accessed VFP/SIMD registers, save host, restore Guest */
- cmp x2, #ESR_ELx_EC_FP_ASIMD
- b.eq switch_to_guest_fpsimd
-
- cmp x2, #ESR_ELx_EC_DABT_LOW
- mov x0, #ESR_ELx_EC_IABT_LOW
- ccmp x2, x0, #4, ne
- b.ne 1f // Not an abort we care about
-
- /* This is an abort. Check for permission fault */
- and x2, x1, #ESR_ELx_FSC_TYPE
- cmp x2, #FSC_PERM
- b.ne 1f // Not a permission fault
-
- /*
- * Check for Stage-1 page table walk, which is guaranteed
- * to give a valid HPFAR_EL2.
- */
- tbnz x1, #7, 1f // S1PTW is set
-
- /* Preserve PAR_EL1 */
- mrs x3, par_el1
- push x3, xzr
-
- /*
- * Permission fault, HPFAR_EL2 is invalid.
- * Resolve the IPA the hard way using the guest VA.
- * Stage-1 translation already validated the memory access rights.
- * As such, we can use the EL1 translation regime, and don't have
- * to distinguish between EL0 and EL1 access.
- */
- mrs x2, far_el2
- at s1e1r, x2
- isb
-
- /* Read result */
- mrs x3, par_el1
- pop x0, xzr // Restore PAR_EL1 from the stack
- msr par_el1, x0
- tbnz x3, #0, 3f // Bail out if we failed the translation
- ubfx x3, x3, #12, #36 // Extract IPA
- lsl x3, x3, #4 // and present it like HPFAR
- b 2f
-
-1: mrs x3, hpfar_el2
- mrs x2, far_el2
-
-2: mrs x0, tpidr_el2
- str w1, [x0, #VCPU_ESR_EL2]
- str x2, [x0, #VCPU_FAR_EL2]
- str x3, [x0, #VCPU_HPFAR_EL2]
-
- mov x1, #ARM_EXCEPTION_TRAP
- b __kvm_vcpu_return
-
- /*
- * Translation failed. Just return to the guest and
- * let it fault again. Another CPU is probably playing
- * behind our back.
- */
-3: pop x2, x3
- pop x0, x1
-
- eret
-
-el1_irq:
- push x0, x1
- push x2, x3
- mrs x0, tpidr_el2
- mov x1, #ARM_EXCEPTION_IRQ
- b __kvm_vcpu_return
-
- .ltorg
-
- .align 11
-
-ENTRY(__kvm_hyp_vector)
- ventry el2t_sync_invalid // Synchronous EL2t
- ventry el2t_irq_invalid // IRQ EL2t
- ventry el2t_fiq_invalid // FIQ EL2t
- ventry el2t_error_invalid // Error EL2t
-
- ventry el2h_sync_invalid // Synchronous EL2h
- ventry el2h_irq_invalid // IRQ EL2h
- ventry el2h_fiq_invalid // FIQ EL2h
- ventry el2h_error_invalid // Error EL2h
-
- ventry el1_sync // Synchronous 64-bit EL1
- ventry el1_irq // IRQ 64-bit EL1
- ventry el1_fiq_invalid // FIQ 64-bit EL1
- ventry el1_error_invalid // Error 64-bit EL1
-
- ventry el1_sync // Synchronous 32-bit EL1
- ventry el1_irq // IRQ 32-bit EL1
- ventry el1_fiq_invalid // FIQ 32-bit EL1
- ventry el1_error_invalid // Error 32-bit EL1
-ENDPROC(__kvm_hyp_vector)
-
-
-ENTRY(__kvm_get_mdcr_el2)
- mrs x0, mdcr_el2
- ret
-ENDPROC(__kvm_get_mdcr_el2)
-
- .popsection
diff --git a/arch/arm64/kvm/hyp/Makefile b/arch/arm64/kvm/hyp/Makefile
new file mode 100644
index 0000000..826032b
--- /dev/null
+++ b/arch/arm64/kvm/hyp/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for Kernel-based Virtual Machine module, HYP part
+#
+
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v2-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += vgic-v3-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += timer-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += sysreg-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += debug-sr.o
+obj-$(CONFIG_KVM_ARM_HOST) += entry.o
+obj-$(CONFIG_KVM_ARM_HOST) += switch.o
+obj-$(CONFIG_KVM_ARM_HOST) += fpsimd.o
+obj-$(CONFIG_KVM_ARM_HOST) += tlb.o
+obj-$(CONFIG_KVM_ARM_HOST) += hyp-entry.o
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
new file mode 100644
index 0000000..c9c1e97
--- /dev/null
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+#define read_debug(r,n) read_sysreg(r##n##_el1)
+#define write_debug(v,r,n) write_sysreg(v, r##n##_el1)
+
+#define save_debug(ptr,reg,nr) \
+ switch (nr) { \
+ case 15: ptr[15] = read_debug(reg, 15); \
+ case 14: ptr[14] = read_debug(reg, 14); \
+ case 13: ptr[13] = read_debug(reg, 13); \
+ case 12: ptr[12] = read_debug(reg, 12); \
+ case 11: ptr[11] = read_debug(reg, 11); \
+ case 10: ptr[10] = read_debug(reg, 10); \
+ case 9: ptr[9] = read_debug(reg, 9); \
+ case 8: ptr[8] = read_debug(reg, 8); \
+ case 7: ptr[7] = read_debug(reg, 7); \
+ case 6: ptr[6] = read_debug(reg, 6); \
+ case 5: ptr[5] = read_debug(reg, 5); \
+ case 4: ptr[4] = read_debug(reg, 4); \
+ case 3: ptr[3] = read_debug(reg, 3); \
+ case 2: ptr[2] = read_debug(reg, 2); \
+ case 1: ptr[1] = read_debug(reg, 1); \
+ default: ptr[0] = read_debug(reg, 0); \
+ }
+
+#define restore_debug(ptr,reg,nr) \
+ switch (nr) { \
+ case 15: write_debug(ptr[15], reg, 15); \
+ case 14: write_debug(ptr[14], reg, 14); \
+ case 13: write_debug(ptr[13], reg, 13); \
+ case 12: write_debug(ptr[12], reg, 12); \
+ case 11: write_debug(ptr[11], reg, 11); \
+ case 10: write_debug(ptr[10], reg, 10); \
+ case 9: write_debug(ptr[9], reg, 9); \
+ case 8: write_debug(ptr[8], reg, 8); \
+ case 7: write_debug(ptr[7], reg, 7); \
+ case 6: write_debug(ptr[6], reg, 6); \
+ case 5: write_debug(ptr[5], reg, 5); \
+ case 4: write_debug(ptr[4], reg, 4); \
+ case 3: write_debug(ptr[3], reg, 3); \
+ case 2: write_debug(ptr[2], reg, 2); \
+ case 1: write_debug(ptr[1], reg, 1); \
+ default: write_debug(ptr[0], reg, 0); \
+ }
+
+void __hyp_text __debug_save_state(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug_arch *dbg,
+ struct kvm_cpu_context *ctxt)
+{
+ u64 aa64dfr0;
+ int brps, wrps;
+
+ if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+ return;
+
+ aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
+ brps = (aa64dfr0 >> 12) & 0xf;
+ wrps = (aa64dfr0 >> 20) & 0xf;
+
+ save_debug(dbg->dbg_bcr, dbgbcr, brps);
+ save_debug(dbg->dbg_bvr, dbgbvr, brps);
+ save_debug(dbg->dbg_wcr, dbgwcr, wrps);
+ save_debug(dbg->dbg_wvr, dbgwvr, wrps);
+
+ ctxt->sys_regs[MDCCINT_EL1] = read_sysreg(mdccint_el1);
+}
+
+void __hyp_text __debug_restore_state(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug_arch *dbg,
+ struct kvm_cpu_context *ctxt)
+{
+ u64 aa64dfr0;
+ int brps, wrps;
+
+ if (!(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY))
+ return;
+
+ aa64dfr0 = read_sysreg(id_aa64dfr0_el1);
+
+ brps = (aa64dfr0 >> 12) & 0xf;
+ wrps = (aa64dfr0 >> 20) & 0xf;
+
+ restore_debug(dbg->dbg_bcr, dbgbcr, brps);
+ restore_debug(dbg->dbg_bvr, dbgbvr, brps);
+ restore_debug(dbg->dbg_wcr, dbgwcr, wrps);
+ restore_debug(dbg->dbg_wvr, dbgwvr, wrps);
+
+ write_sysreg(ctxt->sys_regs[MDCCINT_EL1], mdccint_el1);
+}
+
+void __hyp_text __debug_cond_save_host_state(struct kvm_vcpu *vcpu)
+{
+ /* If any of KDE, MDE or KVM_ARM64_DEBUG_DIRTY is set, perform
+ * a full save/restore cycle. */
+ if ((vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_KDE) ||
+ (vcpu->arch.ctxt.sys_regs[MDSCR_EL1] & DBG_MDSCR_MDE))
+ vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
+
+ __debug_save_state(vcpu, &vcpu->arch.host_debug_state,
+ kern_hyp_va(vcpu->arch.host_cpu_context));
+}
+
+void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
+{
+ __debug_restore_state(vcpu, &vcpu->arch.host_debug_state,
+ kern_hyp_va(vcpu->arch.host_cpu_context));
+
+ if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+ vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
+}
+
+static u32 __hyp_text __debug_read_mdcr_el2(void)
+{
+ return read_sysreg(mdcr_el2);
+}
+
+__alias(__debug_read_mdcr_el2) u32 __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
new file mode 100644
index 0000000..fd0fbe9
--- /dev/null
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/asm-offsets.h>
+#include <asm/assembler.h>
+#include <asm/fpsimdmacros.h>
+#include <asm/kvm.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#define CPU_GP_REG_OFFSET(x) (CPU_GP_REGS + x)
+#define CPU_XREG_OFFSET(x) CPU_GP_REG_OFFSET(CPU_USER_PT_REGS + 8*x)
+
+ .text
+ .pushsection .hyp.text, "ax"
+
+.macro save_callee_saved_regs ctxt
+ stp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+ stp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+ stp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+ stp x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+ stp x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+ stp x29, lr, [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+.macro restore_callee_saved_regs ctxt
+ ldp x19, x20, [\ctxt, #CPU_XREG_OFFSET(19)]
+ ldp x21, x22, [\ctxt, #CPU_XREG_OFFSET(21)]
+ ldp x23, x24, [\ctxt, #CPU_XREG_OFFSET(23)]
+ ldp x25, x26, [\ctxt, #CPU_XREG_OFFSET(25)]
+ ldp x27, x28, [\ctxt, #CPU_XREG_OFFSET(27)]
+ ldp x29, lr, [\ctxt, #CPU_XREG_OFFSET(29)]
+.endm
+
+/*
+ * u64 __guest_enter(struct kvm_vcpu *vcpu,
+ * struct kvm_cpu_context *host_ctxt);
+ */
+ENTRY(__guest_enter)
+ // x0: vcpu
+ // x1: host/guest context
+ // x2-x18: clobbered by macros
+
+ // Store the host regs
+ save_callee_saved_regs x1
+
+ // Preserve vcpu & host_ctxt for use at exit time
+ stp x0, x1, [sp, #-16]!
+
+ add x1, x0, #VCPU_CONTEXT
+
+ // Prepare x0-x1 for later restore by pushing them onto the stack
+ ldp x2, x3, [x1, #CPU_XREG_OFFSET(0)]
+ stp x2, x3, [sp, #-16]!
+
+ // x2-x18
+ ldp x2, x3, [x1, #CPU_XREG_OFFSET(2)]
+ ldp x4, x5, [x1, #CPU_XREG_OFFSET(4)]
+ ldp x6, x7, [x1, #CPU_XREG_OFFSET(6)]
+ ldp x8, x9, [x1, #CPU_XREG_OFFSET(8)]
+ ldp x10, x11, [x1, #CPU_XREG_OFFSET(10)]
+ ldp x12, x13, [x1, #CPU_XREG_OFFSET(12)]
+ ldp x14, x15, [x1, #CPU_XREG_OFFSET(14)]
+ ldp x16, x17, [x1, #CPU_XREG_OFFSET(16)]
+ ldr x18, [x1, #CPU_XREG_OFFSET(18)]
+
+ // x19-x29, lr
+ restore_callee_saved_regs x1
+
+ // Last bits of the 64bit state
+ ldp x0, x1, [sp], #16
+
+ // Do not touch any register after this!
+ eret
+ENDPROC(__guest_enter)
+
+ENTRY(__guest_exit)
+ // x0: vcpu
+ // x1: return code
+ // x2-x3: free
+ // x4-x29,lr: vcpu regs
+ // vcpu x0-x3 on the stack
+
+ add x2, x0, #VCPU_CONTEXT
+
+ stp x4, x5, [x2, #CPU_XREG_OFFSET(4)]
+ stp x6, x7, [x2, #CPU_XREG_OFFSET(6)]
+ stp x8, x9, [x2, #CPU_XREG_OFFSET(8)]
+ stp x10, x11, [x2, #CPU_XREG_OFFSET(10)]
+ stp x12, x13, [x2, #CPU_XREG_OFFSET(12)]
+ stp x14, x15, [x2, #CPU_XREG_OFFSET(14)]
+ stp x16, x17, [x2, #CPU_XREG_OFFSET(16)]
+ str x18, [x2, #CPU_XREG_OFFSET(18)]
+
+ ldp x6, x7, [sp], #16 // x2, x3
+ ldp x4, x5, [sp], #16 // x0, x1
+
+ stp x4, x5, [x2, #CPU_XREG_OFFSET(0)]
+ stp x6, x7, [x2, #CPU_XREG_OFFSET(2)]
+
+ save_callee_saved_regs x2
+
+ // Restore vcpu & host_ctxt from the stack
+ // (preserving return code in x1)
+ ldp x0, x2, [sp], #16
+ // Now restore the host regs
+ restore_callee_saved_regs x2
+
+ mov x0, x1
+ ret
+ENDPROC(__guest_exit)
+
+ENTRY(__fpsimd_guest_restore)
+ stp x4, lr, [sp, #-16]!
+
+ mrs x2, cptr_el2
+ bic x2, x2, #CPTR_EL2_TFP
+ msr cptr_el2, x2
+ isb
+
+ mrs x3, tpidr_el2
+
+ ldr x0, [x3, #VCPU_HOST_CONTEXT]
+ kern_hyp_va x0
+ add x0, x0, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+ bl __fpsimd_save_state
+
+ add x2, x3, #VCPU_CONTEXT
+ add x0, x2, #CPU_GP_REG_OFFSET(CPU_FP_REGS)
+ bl __fpsimd_restore_state
+
+ // Skip restoring fpexc32 for AArch64 guests
+ mrs x1, hcr_el2
+ tbnz x1, #HCR_RW_SHIFT, 1f
+ ldr x4, [x3, #VCPU_FPEXC32_EL2]
+ msr fpexc32_el2, x4
+1:
+ ldp x4, lr, [sp], #16
+ ldp x2, x3, [sp], #16
+ ldp x0, x1, [sp], #16
+
+ eret
+ENDPROC(__fpsimd_guest_restore)
diff --git a/arch/arm/kernel/psci-call.S b/arch/arm64/kvm/hyp/fpsimd.S
index a78e9e1..da3f22c 100644
--- a/arch/arm/kernel/psci-call.S
+++ b/arch/arm64/kvm/hyp/fpsimd.S
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -8,24 +11,23 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * Copyright (C) 2015 ARM Limited
- *
- * Author: Mark Rutland <mark.rutland@arm.com>
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/linkage.h>
-#include <asm/opcodes-sec.h>
-#include <asm/opcodes-virt.h>
+#include <asm/fpsimdmacros.h>
+
+ .text
+ .pushsection .hyp.text, "ax"
-/* int __invoke_psci_fn_hvc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
-ENTRY(__invoke_psci_fn_hvc)
- __HVC(0)
- bx lr
-ENDPROC(__invoke_psci_fn_hvc)
+ENTRY(__fpsimd_save_state)
+ fpsimd_save x0, 1
+ ret
+ENDPROC(__fpsimd_save_state)
-/* int __invoke_psci_fn_smc(u32 function_id, u32 arg0, u32 arg1, u32 arg2) */
-ENTRY(__invoke_psci_fn_smc)
- __SMC(0)
- bx lr
-ENDPROC(__invoke_psci_fn_smc)
+ENTRY(__fpsimd_restore_state)
+ fpsimd_restore x0, 1
+ ret
+ENDPROC(__fpsimd_restore_state)
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
new file mode 100644
index 0000000..93e8d983
--- /dev/null
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/alternative.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
+#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+ .text
+ .pushsection .hyp.text, "ax"
+
+.macro save_x0_to_x3
+ stp x0, x1, [sp, #-16]!
+ stp x2, x3, [sp, #-16]!
+.endm
+
+.macro restore_x0_to_x3
+ ldp x2, x3, [sp], #16
+ ldp x0, x1, [sp], #16
+.endm
+
+el1_sync: // Guest trapped into EL2
+ save_x0_to_x3
+
+ mrs x1, esr_el2
+ lsr x2, x1, #ESR_ELx_EC_SHIFT
+
+ cmp x2, #ESR_ELx_EC_HVC64
+ b.ne el1_trap
+
+ mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest
+ cbnz x3, el1_trap // called HVC
+
+ /* Here, we're pretty sure the host called HVC. */
+ restore_x0_to_x3
+
+ /* Check for __hyp_get_vectors */
+ cbnz x0, 1f
+ mrs x0, vbar_el2
+ b 2f
+
+1: stp lr, xzr, [sp, #-16]!
+
+ /*
+ * Compute the function address in EL2, and shuffle the parameters.
+ */
+ kern_hyp_va x0
+ mov lr, x0
+ mov x0, x1
+ mov x1, x2
+ mov x2, x3
+ blr lr
+
+ ldp lr, xzr, [sp], #16
+2: eret
+
+el1_trap:
+ /*
+ * x1: ESR
+ * x2: ESR_EC
+ */
+
+ /* Guest accessed VFP/SIMD registers, save host, restore Guest */
+ cmp x2, #ESR_ELx_EC_FP_ASIMD
+ b.eq __fpsimd_guest_restore
+
+ cmp x2, #ESR_ELx_EC_DABT_LOW
+ mov x0, #ESR_ELx_EC_IABT_LOW
+ ccmp x2, x0, #4, ne
+ b.ne 1f // Not an abort we care about
+
+ /* This is an abort. Check for permission fault */
+alternative_if_not ARM64_WORKAROUND_834220
+ and x2, x1, #ESR_ELx_FSC_TYPE
+ cmp x2, #FSC_PERM
+ b.ne 1f // Not a permission fault
+alternative_else
+ nop // Use the permission fault path to
+ nop // check for a valid S1 translation,
+ nop // regardless of the ESR value.
+alternative_endif
+
+ /*
+ * Check for Stage-1 page table walk, which is guaranteed
+ * to give a valid HPFAR_EL2.
+ */
+ tbnz x1, #7, 1f // S1PTW is set
+
+ /* Preserve PAR_EL1 */
+ mrs x3, par_el1
+ stp x3, xzr, [sp, #-16]!
+
+ /*
+ * Permission fault, HPFAR_EL2 is invalid.
+ * Resolve the IPA the hard way using the guest VA.
+ * Stage-1 translation already validated the memory access rights.
+ * As such, we can use the EL1 translation regime, and don't have
+ * to distinguish between EL0 and EL1 access.
+ */
+ mrs x2, far_el2
+ at s1e1r, x2
+ isb
+
+ /* Read result */
+ mrs x3, par_el1
+ ldp x0, xzr, [sp], #16 // Restore PAR_EL1 from the stack
+ msr par_el1, x0
+ tbnz x3, #0, 3f // Bail out if we failed the translation
+ ubfx x3, x3, #12, #36 // Extract IPA
+ lsl x3, x3, #4 // and present it like HPFAR
+ b 2f
+
+1: mrs x3, hpfar_el2
+ mrs x2, far_el2
+
+2: mrs x0, tpidr_el2
+ str w1, [x0, #VCPU_ESR_EL2]
+ str x2, [x0, #VCPU_FAR_EL2]
+ str x3, [x0, #VCPU_HPFAR_EL2]
+
+ mov x1, #ARM_EXCEPTION_TRAP
+ b __guest_exit
+
+ /*
+ * Translation failed. Just return to the guest and
+ * let it fault again. Another CPU is probably playing
+ * behind our back.
+ */
+3: restore_x0_to_x3
+
+ eret
+
+el1_irq:
+ save_x0_to_x3
+ mrs x0, tpidr_el2
+ mov x1, #ARM_EXCEPTION_IRQ
+ b __guest_exit
+
+ENTRY(__hyp_do_panic)
+ mov lr, #(PSR_F_BIT | PSR_I_BIT | PSR_A_BIT | PSR_D_BIT |\
+ PSR_MODE_EL1h)
+ msr spsr_el2, lr
+ ldr lr, =panic
+ msr elr_el2, lr
+ eret
+ENDPROC(__hyp_do_panic)
+
+.macro invalid_vector label, target = __hyp_panic
+ .align 2
+\label:
+ b \target
+ENDPROC(\label)
+.endm
+
+ /* None of these should ever happen */
+ invalid_vector el2t_sync_invalid
+ invalid_vector el2t_irq_invalid
+ invalid_vector el2t_fiq_invalid
+ invalid_vector el2t_error_invalid
+ invalid_vector el2h_sync_invalid
+ invalid_vector el2h_irq_invalid
+ invalid_vector el2h_fiq_invalid
+ invalid_vector el2h_error_invalid
+ invalid_vector el1_sync_invalid
+ invalid_vector el1_irq_invalid
+ invalid_vector el1_fiq_invalid
+ invalid_vector el1_error_invalid
+
+ .ltorg
+
+ .align 11
+
+ENTRY(__kvm_hyp_vector)
+ ventry el2t_sync_invalid // Synchronous EL2t
+ ventry el2t_irq_invalid // IRQ EL2t
+ ventry el2t_fiq_invalid // FIQ EL2t
+ ventry el2t_error_invalid // Error EL2t
+
+ ventry el2h_sync_invalid // Synchronous EL2h
+ ventry el2h_irq_invalid // IRQ EL2h
+ ventry el2h_fiq_invalid // FIQ EL2h
+ ventry el2h_error_invalid // Error EL2h
+
+ ventry el1_sync // Synchronous 64-bit EL1
+ ventry el1_irq // IRQ 64-bit EL1
+ ventry el1_fiq_invalid // FIQ 64-bit EL1
+ ventry el1_error_invalid // Error 64-bit EL1
+
+ ventry el1_sync // Synchronous 32-bit EL1
+ ventry el1_irq // IRQ 32-bit EL1
+ ventry el1_fiq_invalid // FIQ 32-bit EL1
+ ventry el1_error_invalid // Error 32-bit EL1
+ENDPROC(__kvm_hyp_vector)
diff --git a/arch/arm64/kvm/hyp/hyp.h b/arch/arm64/kvm/hyp/hyp.h
new file mode 100644
index 0000000..fb27517
--- /dev/null
+++ b/arch/arm64/kvm/hyp/hyp.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ARM64_KVM_HYP_H__
+#define __ARM64_KVM_HYP_H__
+
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+#include <asm/kvm_mmu.h>
+#include <asm/sysreg.h>
+
+#define __hyp_text __section(.hyp.text) notrace
+
+#define kern_hyp_va(v) (typeof(v))((unsigned long)(v) & HYP_PAGE_OFFSET_MASK)
+#define hyp_kern_va(v) (typeof(v))((unsigned long)(v) - HYP_PAGE_OFFSET \
+ + PAGE_OFFSET)
+
+/**
+ * hyp_alternate_select - Generates patchable code sequences that are
+ * used to switch between two implementations of a function, depending
+ * on the availability of a feature.
+ *
+ * @fname: a symbol name that will be defined as a function returning a
+ * function pointer whose type will match @orig and @alt
+ * @orig: A pointer to the default function, as returned by @fname when
+ * @cond doesn't hold
+ * @alt: A pointer to the alternate function, as returned by @fname
+ * when @cond holds
+ * @cond: a CPU feature (as described in asm/cpufeature.h)
+ */
+#define hyp_alternate_select(fname, orig, alt, cond) \
+typeof(orig) * __hyp_text fname(void) \
+{ \
+ typeof(alt) *val = orig; \
+ asm volatile(ALTERNATIVE("nop \n", \
+ "mov %0, %1 \n", \
+ cond) \
+ : "+r" (val) : "r" (alt)); \
+ return val; \
+}
+
+void __vgic_v2_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v2_restore_state(struct kvm_vcpu *vcpu);
+
+void __vgic_v3_save_state(struct kvm_vcpu *vcpu);
+void __vgic_v3_restore_state(struct kvm_vcpu *vcpu);
+
+void __timer_save_state(struct kvm_vcpu *vcpu);
+void __timer_restore_state(struct kvm_vcpu *vcpu);
+
+void __sysreg_save_state(struct kvm_cpu_context *ctxt);
+void __sysreg_restore_state(struct kvm_cpu_context *ctxt);
+void __sysreg32_save_state(struct kvm_vcpu *vcpu);
+void __sysreg32_restore_state(struct kvm_vcpu *vcpu);
+
+void __debug_save_state(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug_arch *dbg,
+ struct kvm_cpu_context *ctxt);
+void __debug_restore_state(struct kvm_vcpu *vcpu,
+ struct kvm_guest_debug_arch *dbg,
+ struct kvm_cpu_context *ctxt);
+void __debug_cond_save_host_state(struct kvm_vcpu *vcpu);
+void __debug_cond_restore_host_state(struct kvm_vcpu *vcpu);
+
+void __fpsimd_save_state(struct user_fpsimd_state *fp_regs);
+void __fpsimd_restore_state(struct user_fpsimd_state *fp_regs);
+static inline bool __fpsimd_enabled(void)
+{
+ return !(read_sysreg(cptr_el2) & CPTR_EL2_TFP);
+}
+
+u64 __guest_enter(struct kvm_vcpu *vcpu, struct kvm_cpu_context *host_ctxt);
+void __noreturn __hyp_do_panic(unsigned long, ...);
+
+#endif /* __ARM64_KVM_HYP_H__ */
+
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
new file mode 100644
index 0000000..ca8f5a5
--- /dev/null
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hyp.h"
+
+static void __hyp_text __activate_traps(struct kvm_vcpu *vcpu)
+{
+ u64 val;
+
+ /*
+ * We are about to set CPTR_EL2.TFP to trap all floating point
+ * register accesses to EL2, however, the ARM ARM clearly states that
+ * traps are only taken to EL2 if the operation would not otherwise
+ * trap to EL1. Therefore, always make sure that for 32-bit guests,
+ * we set FPEXC.EN to prevent traps to EL1, when setting the TFP bit.
+ */
+ val = vcpu->arch.hcr_el2;
+ if (!(val & HCR_RW)) {
+ write_sysreg(1 << 30, fpexc32_el2);
+ isb();
+ }
+ write_sysreg(val, hcr_el2);
+ /* Trap on AArch32 cp15 c15 accesses (EL1 or EL0) */
+ write_sysreg(1 << 15, hstr_el2);
+ write_sysreg(CPTR_EL2_TTA | CPTR_EL2_TFP, cptr_el2);
+ write_sysreg(vcpu->arch.mdcr_el2, mdcr_el2);
+}
+
+static void __hyp_text __deactivate_traps(struct kvm_vcpu *vcpu)
+{
+ write_sysreg(HCR_RW, hcr_el2);
+ write_sysreg(0, hstr_el2);
+ write_sysreg(read_sysreg(mdcr_el2) & MDCR_EL2_HPMN_MASK, mdcr_el2);
+ write_sysreg(0, cptr_el2);
+}
+
+static void __hyp_text __activate_vm(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+ write_sysreg(kvm->arch.vttbr, vttbr_el2);
+}
+
+static void __hyp_text __deactivate_vm(struct kvm_vcpu *vcpu)
+{
+ write_sysreg(0, vttbr_el2);
+}
+
+static hyp_alternate_select(__vgic_call_save_state,
+ __vgic_v2_save_state, __vgic_v3_save_state,
+ ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static hyp_alternate_select(__vgic_call_restore_state,
+ __vgic_v2_restore_state, __vgic_v3_restore_state,
+ ARM64_HAS_SYSREG_GIC_CPUIF);
+
+static void __hyp_text __vgic_save_state(struct kvm_vcpu *vcpu)
+{
+ __vgic_call_save_state()(vcpu);
+ write_sysreg(read_sysreg(hcr_el2) & ~HCR_INT_OVERRIDE, hcr_el2);
+}
+
+static void __hyp_text __vgic_restore_state(struct kvm_vcpu *vcpu)
+{
+ u64 val;
+
+ val = read_sysreg(hcr_el2);
+ val |= HCR_INT_OVERRIDE;
+ val |= vcpu->arch.irq_lines;
+ write_sysreg(val, hcr_el2);
+
+ __vgic_call_restore_state()(vcpu);
+}
+
+static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpu_context *host_ctxt;
+ struct kvm_cpu_context *guest_ctxt;
+ bool fp_enabled;
+ u64 exit_code;
+
+ vcpu = kern_hyp_va(vcpu);
+ write_sysreg(vcpu, tpidr_el2);
+
+ host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+ guest_ctxt = &vcpu->arch.ctxt;
+
+ __sysreg_save_state(host_ctxt);
+ __debug_cond_save_host_state(vcpu);
+
+ __activate_traps(vcpu);
+ __activate_vm(vcpu);
+
+ __vgic_restore_state(vcpu);
+ __timer_restore_state(vcpu);
+
+ /*
+ * We must restore the 32-bit state before the sysregs, thanks
+ * to Cortex-A57 erratum #852523.
+ */
+ __sysreg32_restore_state(vcpu);
+ __sysreg_restore_state(guest_ctxt);
+ __debug_restore_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+
+ /* Jump in the fire! */
+ exit_code = __guest_enter(vcpu, host_ctxt);
+ /* And we're baaack! */
+
+ fp_enabled = __fpsimd_enabled();
+
+ __sysreg_save_state(guest_ctxt);
+ __sysreg32_save_state(vcpu);
+ __timer_save_state(vcpu);
+ __vgic_save_state(vcpu);
+
+ __deactivate_traps(vcpu);
+ __deactivate_vm(vcpu);
+
+ __sysreg_restore_state(host_ctxt);
+
+ if (fp_enabled) {
+ __fpsimd_save_state(&guest_ctxt->gp_regs.fp_regs);
+ __fpsimd_restore_state(&host_ctxt->gp_regs.fp_regs);
+ }
+
+ __debug_save_state(vcpu, kern_hyp_va(vcpu->arch.debug_ptr), guest_ctxt);
+ __debug_cond_restore_host_state(vcpu);
+
+ return exit_code;
+}
+
+__alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
+
+static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
+
+void __hyp_text __noreturn __hyp_panic(void)
+{
+ unsigned long str_va = (unsigned long)__hyp_panic_string;
+ u64 spsr = read_sysreg(spsr_el2);
+ u64 elr = read_sysreg(elr_el2);
+ u64 par = read_sysreg(par_el1);
+
+ if (read_sysreg(vttbr_el2)) {
+ struct kvm_vcpu *vcpu;
+ struct kvm_cpu_context *host_ctxt;
+
+ vcpu = (struct kvm_vcpu *)read_sysreg(tpidr_el2);
+ host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+ __deactivate_traps(vcpu);
+ __deactivate_vm(vcpu);
+ __sysreg_restore_state(host_ctxt);
+ }
+
+ /* Call panic for real */
+ __hyp_do_panic(hyp_kern_va(str_va),
+ spsr, elr,
+ read_sysreg(esr_el2), read_sysreg(far_el2),
+ read_sysreg(hpfar_el2), par,
+ (void *)read_sysreg(tpidr_el2));
+
+ unreachable();
+}
diff --git a/arch/arm64/kvm/hyp/sysreg-sr.c b/arch/arm64/kvm/hyp/sysreg-sr.c
new file mode 100644
index 0000000..42563098
--- /dev/null
+++ b/arch/arm64/kvm/hyp/sysreg-sr.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_asm.h>
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* ctxt is already in the HYP VA space */
+void __hyp_text __sysreg_save_state(struct kvm_cpu_context *ctxt)
+{
+ ctxt->sys_regs[MPIDR_EL1] = read_sysreg(vmpidr_el2);
+ ctxt->sys_regs[CSSELR_EL1] = read_sysreg(csselr_el1);
+ ctxt->sys_regs[SCTLR_EL1] = read_sysreg(sctlr_el1);
+ ctxt->sys_regs[ACTLR_EL1] = read_sysreg(actlr_el1);
+ ctxt->sys_regs[CPACR_EL1] = read_sysreg(cpacr_el1);
+ ctxt->sys_regs[TTBR0_EL1] = read_sysreg(ttbr0_el1);
+ ctxt->sys_regs[TTBR1_EL1] = read_sysreg(ttbr1_el1);
+ ctxt->sys_regs[TCR_EL1] = read_sysreg(tcr_el1);
+ ctxt->sys_regs[ESR_EL1] = read_sysreg(esr_el1);
+ ctxt->sys_regs[AFSR0_EL1] = read_sysreg(afsr0_el1);
+ ctxt->sys_regs[AFSR1_EL1] = read_sysreg(afsr1_el1);
+ ctxt->sys_regs[FAR_EL1] = read_sysreg(far_el1);
+ ctxt->sys_regs[MAIR_EL1] = read_sysreg(mair_el1);
+ ctxt->sys_regs[VBAR_EL1] = read_sysreg(vbar_el1);
+ ctxt->sys_regs[CONTEXTIDR_EL1] = read_sysreg(contextidr_el1);
+ ctxt->sys_regs[TPIDR_EL0] = read_sysreg(tpidr_el0);
+ ctxt->sys_regs[TPIDRRO_EL0] = read_sysreg(tpidrro_el0);
+ ctxt->sys_regs[TPIDR_EL1] = read_sysreg(tpidr_el1);
+ ctxt->sys_regs[AMAIR_EL1] = read_sysreg(amair_el1);
+ ctxt->sys_regs[CNTKCTL_EL1] = read_sysreg(cntkctl_el1);
+ ctxt->sys_regs[PAR_EL1] = read_sysreg(par_el1);
+ ctxt->sys_regs[MDSCR_EL1] = read_sysreg(mdscr_el1);
+
+ ctxt->gp_regs.regs.sp = read_sysreg(sp_el0);
+ ctxt->gp_regs.regs.pc = read_sysreg(elr_el2);
+ ctxt->gp_regs.regs.pstate = read_sysreg(spsr_el2);
+ ctxt->gp_regs.sp_el1 = read_sysreg(sp_el1);
+ ctxt->gp_regs.elr_el1 = read_sysreg(elr_el1);
+ ctxt->gp_regs.spsr[KVM_SPSR_EL1]= read_sysreg(spsr_el1);
+}
+
+void __hyp_text __sysreg_restore_state(struct kvm_cpu_context *ctxt)
+{
+ write_sysreg(ctxt->sys_regs[MPIDR_EL1], vmpidr_el2);
+ write_sysreg(ctxt->sys_regs[CSSELR_EL1], csselr_el1);
+ write_sysreg(ctxt->sys_regs[SCTLR_EL1], sctlr_el1);
+ write_sysreg(ctxt->sys_regs[ACTLR_EL1], actlr_el1);
+ write_sysreg(ctxt->sys_regs[CPACR_EL1], cpacr_el1);
+ write_sysreg(ctxt->sys_regs[TTBR0_EL1], ttbr0_el1);
+ write_sysreg(ctxt->sys_regs[TTBR1_EL1], ttbr1_el1);
+ write_sysreg(ctxt->sys_regs[TCR_EL1], tcr_el1);
+ write_sysreg(ctxt->sys_regs[ESR_EL1], esr_el1);
+ write_sysreg(ctxt->sys_regs[AFSR0_EL1], afsr0_el1);
+ write_sysreg(ctxt->sys_regs[AFSR1_EL1], afsr1_el1);
+ write_sysreg(ctxt->sys_regs[FAR_EL1], far_el1);
+ write_sysreg(ctxt->sys_regs[MAIR_EL1], mair_el1);
+ write_sysreg(ctxt->sys_regs[VBAR_EL1], vbar_el1);
+ write_sysreg(ctxt->sys_regs[CONTEXTIDR_EL1], contextidr_el1);
+ write_sysreg(ctxt->sys_regs[TPIDR_EL0], tpidr_el0);
+ write_sysreg(ctxt->sys_regs[TPIDRRO_EL0], tpidrro_el0);
+ write_sysreg(ctxt->sys_regs[TPIDR_EL1], tpidr_el1);
+ write_sysreg(ctxt->sys_regs[AMAIR_EL1], amair_el1);
+ write_sysreg(ctxt->sys_regs[CNTKCTL_EL1], cntkctl_el1);
+ write_sysreg(ctxt->sys_regs[PAR_EL1], par_el1);
+ write_sysreg(ctxt->sys_regs[MDSCR_EL1], mdscr_el1);
+
+ write_sysreg(ctxt->gp_regs.regs.sp, sp_el0);
+ write_sysreg(ctxt->gp_regs.regs.pc, elr_el2);
+ write_sysreg(ctxt->gp_regs.regs.pstate, spsr_el2);
+ write_sysreg(ctxt->gp_regs.sp_el1, sp_el1);
+ write_sysreg(ctxt->gp_regs.elr_el1, elr_el1);
+ write_sysreg(ctxt->gp_regs.spsr[KVM_SPSR_EL1], spsr_el1);
+}
+
+void __hyp_text __sysreg32_save_state(struct kvm_vcpu *vcpu)
+{
+ u64 *spsr, *sysreg;
+
+ if (read_sysreg(hcr_el2) & HCR_RW)
+ return;
+
+ spsr = vcpu->arch.ctxt.gp_regs.spsr;
+ sysreg = vcpu->arch.ctxt.sys_regs;
+
+ spsr[KVM_SPSR_ABT] = read_sysreg(spsr_abt);
+ spsr[KVM_SPSR_UND] = read_sysreg(spsr_und);
+ spsr[KVM_SPSR_IRQ] = read_sysreg(spsr_irq);
+ spsr[KVM_SPSR_FIQ] = read_sysreg(spsr_fiq);
+
+ sysreg[DACR32_EL2] = read_sysreg(dacr32_el2);
+ sysreg[IFSR32_EL2] = read_sysreg(ifsr32_el2);
+
+ if (__fpsimd_enabled())
+ sysreg[FPEXC32_EL2] = read_sysreg(fpexc32_el2);
+
+ if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+ sysreg[DBGVCR32_EL2] = read_sysreg(dbgvcr32_el2);
+}
+
+void __hyp_text __sysreg32_restore_state(struct kvm_vcpu *vcpu)
+{
+ u64 *spsr, *sysreg;
+
+ if (read_sysreg(hcr_el2) & HCR_RW)
+ return;
+
+ spsr = vcpu->arch.ctxt.gp_regs.spsr;
+ sysreg = vcpu->arch.ctxt.sys_regs;
+
+ write_sysreg(spsr[KVM_SPSR_ABT], spsr_abt);
+ write_sysreg(spsr[KVM_SPSR_UND], spsr_und);
+ write_sysreg(spsr[KVM_SPSR_IRQ], spsr_irq);
+ write_sysreg(spsr[KVM_SPSR_FIQ], spsr_fiq);
+
+ write_sysreg(sysreg[DACR32_EL2], dacr32_el2);
+ write_sysreg(sysreg[IFSR32_EL2], ifsr32_el2);
+
+ if (vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY)
+ write_sysreg(sysreg[DBGVCR32_EL2], dbgvcr32_el2);
+}
diff --git a/arch/arm64/kvm/hyp/timer-sr.c b/arch/arm64/kvm/hyp/timer-sr.c
new file mode 100644
index 0000000..1051e5d
--- /dev/null
+++ b/arch/arm64/kvm/hyp/timer-sr.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <clocksource/arm_arch_timer.h>
+#include <linux/compiler.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __timer_save_state(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ u64 val;
+
+ if (kvm->arch.timer.enabled) {
+ timer->cntv_ctl = read_sysreg(cntv_ctl_el0);
+ timer->cntv_cval = read_sysreg(cntv_cval_el0);
+ }
+
+ /* Disable the virtual timer */
+ write_sysreg(0, cntv_ctl_el0);
+
+ /* Allow physical timer/counter access for the host */
+ val = read_sysreg(cnthctl_el2);
+ val |= CNTHCTL_EL1PCTEN | CNTHCTL_EL1PCEN;
+ write_sysreg(val, cnthctl_el2);
+
+ /* Clear cntvoff for the host */
+ write_sysreg(0, cntvoff_el2);
+}
+
+void __hyp_text __timer_restore_state(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+ struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
+ u64 val;
+
+ /*
+ * Disallow physical timer access for the guest
+ * Physical counter access is allowed
+ */
+ val = read_sysreg(cnthctl_el2);
+ val &= ~CNTHCTL_EL1PCEN;
+ val |= CNTHCTL_EL1PCTEN;
+ write_sysreg(val, cnthctl_el2);
+
+ if (kvm->arch.timer.enabled) {
+ write_sysreg(kvm->arch.timer.cntvoff, cntvoff_el2);
+ write_sysreg(timer->cntv_cval, cntv_cval_el0);
+ isb();
+ write_sysreg(timer->cntv_ctl, cntv_ctl_el0);
+ }
+}
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
new file mode 100644
index 0000000..2a7e0d8
--- /dev/null
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hyp.h"
+
+static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+{
+ dsb(ishst);
+
+ /* Switch to requested VMID */
+ kvm = kern_hyp_va(kvm);
+ write_sysreg(kvm->arch.vttbr, vttbr_el2);
+ isb();
+
+ /*
+ * We could do so much better if we had the VA as well.
+ * Instead, we invalidate Stage-2 for this IPA, and the
+ * whole of Stage-1. Weep...
+ */
+ ipa >>= 12;
+ asm volatile("tlbi ipas2e1is, %0" : : "r" (ipa));
+
+ /*
+ * We have to ensure completion of the invalidation at Stage-2,
+ * since a table walk on another CPU could refill a TLB with a
+ * complete (S1 + S2) walk based on the old Stage-2 mapping if
+ * the Stage-1 invalidation happened first.
+ */
+ dsb(ish);
+ asm volatile("tlbi vmalle1is" : : );
+ dsb(ish);
+ isb();
+
+ write_sysreg(0, vttbr_el2);
+}
+
+__alias(__tlb_flush_vmid_ipa) void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm,
+ phys_addr_t ipa);
+
+static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+{
+ dsb(ishst);
+
+ /* Switch to requested VMID */
+ kvm = kern_hyp_va(kvm);
+ write_sysreg(kvm->arch.vttbr, vttbr_el2);
+ isb();
+
+ asm volatile("tlbi vmalls12e1is" : : );
+ dsb(ish);
+ isb();
+
+ write_sysreg(0, vttbr_el2);
+}
+
+__alias(__tlb_flush_vmid) void __kvm_tlb_flush_vmid(struct kvm *kvm);
+
+static void __hyp_text __tlb_flush_vm_context(void)
+{
+ dsb(ishst);
+ asm volatile("tlbi alle1is \n"
+ "ic ialluis ": : );
+ dsb(ish);
+}
+
+__alias(__tlb_flush_vm_context) void __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v2-sr.c b/arch/arm64/kvm/hyp/vgic-v2-sr.c
new file mode 100644
index 0000000..e717612
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v2-sr.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_save_state(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+ struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+ struct vgic_dist *vgic = &kvm->arch.vgic;
+ void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+ u32 eisr0, eisr1, elrsr0, elrsr1;
+ int i, nr_lr;
+
+ if (!base)
+ return;
+
+ nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+ cpu_if->vgic_vmcr = readl_relaxed(base + GICH_VMCR);
+ cpu_if->vgic_misr = readl_relaxed(base + GICH_MISR);
+ eisr0 = readl_relaxed(base + GICH_EISR0);
+ elrsr0 = readl_relaxed(base + GICH_ELRSR0);
+ if (unlikely(nr_lr > 32)) {
+ eisr1 = readl_relaxed(base + GICH_EISR1);
+ elrsr1 = readl_relaxed(base + GICH_ELRSR1);
+ } else {
+ eisr1 = elrsr1 = 0;
+ }
+#ifdef CONFIG_CPU_BIG_ENDIAN
+ cpu_if->vgic_eisr = ((u64)eisr0 << 32) | eisr1;
+ cpu_if->vgic_elrsr = ((u64)elrsr0 << 32) | elrsr1;
+#else
+ cpu_if->vgic_eisr = ((u64)eisr1 << 32) | eisr0;
+ cpu_if->vgic_elrsr = ((u64)elrsr1 << 32) | elrsr0;
+#endif
+ cpu_if->vgic_apr = readl_relaxed(base + GICH_APR);
+
+ writel_relaxed(0, base + GICH_HCR);
+
+ for (i = 0; i < nr_lr; i++)
+ cpu_if->vgic_lr[i] = readl_relaxed(base + GICH_LR0 + (i * 4));
+}
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v2_restore_state(struct kvm_vcpu *vcpu)
+{
+ struct kvm *kvm = kern_hyp_va(vcpu->kvm);
+ struct vgic_v2_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v2;
+ struct vgic_dist *vgic = &kvm->arch.vgic;
+ void __iomem *base = kern_hyp_va(vgic->vctrl_base);
+ int i, nr_lr;
+
+ if (!base)
+ return;
+
+ writel_relaxed(cpu_if->vgic_hcr, base + GICH_HCR);
+ writel_relaxed(cpu_if->vgic_vmcr, base + GICH_VMCR);
+ writel_relaxed(cpu_if->vgic_apr, base + GICH_APR);
+
+ nr_lr = vcpu->arch.vgic_cpu.nr_lr;
+ for (i = 0; i < nr_lr; i++)
+ writel_relaxed(cpu_if->vgic_lr[i], base + GICH_LR0 + (i * 4));
+}
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
new file mode 100644
index 0000000..9142e08
--- /dev/null
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2012-2015 - ARM Ltd
+ * Author: Marc Zyngier <marc.zyngier@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/compiler.h>
+#include <linux/irqchip/arm-gic-v3.h>
+#include <linux/kvm_host.h>
+
+#include <asm/kvm_mmu.h>
+
+#include "hyp.h"
+
+#define vtr_to_max_lr_idx(v) ((v) & 0xf)
+#define vtr_to_nr_pri_bits(v) (((u32)(v) >> 29) + 1)
+
+#define read_gicreg(r) \
+ ({ \
+ u64 reg; \
+ asm volatile("mrs_s %0, " __stringify(r) : "=r" (reg)); \
+ reg; \
+ })
+
+#define write_gicreg(v,r) \
+ do { \
+ u64 __val = (v); \
+ asm volatile("msr_s " __stringify(r) ", %0" : : "r" (__val));\
+ } while (0)
+
+/* vcpu is already in the HYP VA space */
+void __hyp_text __vgic_v3_save_state(struct kvm_vcpu *vcpu)
+{
+ struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+ u64 val;
+ u32 max_lr_idx, nr_pri_bits;
+
+ /*
+ * Make sure stores to the GIC via the memory mapped interface
+ * are now visible to the system register interface.
+ */
+ dsb(st);
+
+ cpu_if->vgic_vmcr = read_gicreg(ICH_VMCR_EL2);
+ cpu_if->vgic_misr = read_gicreg(ICH_MISR_EL2);
+ cpu_if->vgic_eisr = read_gicreg(ICH_EISR_EL2);
+ cpu_if->vgic_elrsr = read_gicreg(ICH_ELSR_EL2);
+
+ write_gicreg(0, ICH_HCR_EL2);
+ val = read_gicreg(ICH_VTR_EL2);
+ max_lr_idx = vtr_to_max_lr_idx(val);
+ nr_pri_bits = vtr_to_nr_pri_bits(val);
+
+ switch (max_lr_idx) {
+ case 15:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)] = read_gicreg(ICH_LR15_EL2);
+ case 14:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)] = read_gicreg(ICH_LR14_EL2);
+ case 13:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)] = read_gicreg(ICH_LR13_EL2);
+ case 12:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)] = read_gicreg(ICH_LR12_EL2);
+ case 11:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)] = read_gicreg(ICH_LR11_EL2);
+ case 10:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)] = read_gicreg(ICH_LR10_EL2);
+ case 9:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)] = read_gicreg(ICH_LR9_EL2);
+ case 8:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)] = read_gicreg(ICH_LR8_EL2);
+ case 7:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)] = read_gicreg(ICH_LR7_EL2);
+ case 6:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)] = read_gicreg(ICH_LR6_EL2);
+ case 5:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)] = read_gicreg(ICH_LR5_EL2);
+ case 4:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)] = read_gicreg(ICH_LR4_EL2);
+ case 3:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)] = read_gicreg(ICH_LR3_EL2);
+ case 2:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)] = read_gicreg(ICH_LR2_EL2);
+ case 1:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)] = read_gicreg(ICH_LR1_EL2);
+ case 0:
+ cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)] = read_gicreg(ICH_LR0_EL2);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ cpu_if->vgic_ap0r[3] = read_gicreg(ICH_AP0R3_EL2);
+ cpu_if->vgic_ap0r[2] = read_gicreg(ICH_AP0R2_EL2);
+ case 6:
+ cpu_if->vgic_ap0r[1] = read_gicreg(ICH_AP0R1_EL2);
+ default:
+ cpu_if->vgic_ap0r[0] = read_gicreg(ICH_AP0R0_EL2);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ cpu_if->vgic_ap1r[3] = read_gicreg(ICH_AP1R3_EL2);
+ cpu_if->vgic_ap1r[2] = read_gicreg(ICH_AP1R2_EL2);
+ case 6:
+ cpu_if->vgic_ap1r[1] = read_gicreg(ICH_AP1R1_EL2);
+ default:
+ cpu_if->vgic_ap1r[0] = read_gicreg(ICH_AP1R0_EL2);
+ }
+
+ val = read_gicreg(ICC_SRE_EL2);
+ write_gicreg(val | ICC_SRE_EL2_ENABLE, ICC_SRE_EL2);
+ isb(); /* Make sure ENABLE is set at EL2 before setting SRE at EL1 */
+ write_gicreg(1, ICC_SRE_EL1);
+}
+
+void __hyp_text __vgic_v3_restore_state(struct kvm_vcpu *vcpu)
+{
+ struct vgic_v3_cpu_if *cpu_if = &vcpu->arch.vgic_cpu.vgic_v3;
+ u64 val;
+ u32 max_lr_idx, nr_pri_bits;
+
+ /*
+ * VFIQEn is RES1 if ICC_SRE_EL1.SRE is 1. This causes a
+ * Group0 interrupt (as generated in GICv2 mode) to be
+ * delivered as a FIQ to the guest, with potentially fatal
+ * consequences. So we must make sure that ICC_SRE_EL1 has
+ * been actually programmed with the value we want before
+ * starting to mess with the rest of the GIC.
+ */
+ write_gicreg(cpu_if->vgic_sre, ICC_SRE_EL1);
+ isb();
+
+ write_gicreg(cpu_if->vgic_hcr, ICH_HCR_EL2);
+ write_gicreg(cpu_if->vgic_vmcr, ICH_VMCR_EL2);
+
+ val = read_gicreg(ICH_VTR_EL2);
+ max_lr_idx = vtr_to_max_lr_idx(val);
+ nr_pri_bits = vtr_to_nr_pri_bits(val);
+
+ switch (nr_pri_bits) {
+ case 7:
+ write_gicreg(cpu_if->vgic_ap1r[3], ICH_AP1R3_EL2);
+ write_gicreg(cpu_if->vgic_ap1r[2], ICH_AP1R2_EL2);
+ case 6:
+ write_gicreg(cpu_if->vgic_ap1r[1], ICH_AP1R1_EL2);
+ default:
+ write_gicreg(cpu_if->vgic_ap1r[0], ICH_AP1R0_EL2);
+ }
+
+ switch (nr_pri_bits) {
+ case 7:
+ write_gicreg(cpu_if->vgic_ap0r[3], ICH_AP0R3_EL2);
+ write_gicreg(cpu_if->vgic_ap0r[2], ICH_AP0R2_EL2);
+ case 6:
+ write_gicreg(cpu_if->vgic_ap0r[1], ICH_AP0R1_EL2);
+ default:
+ write_gicreg(cpu_if->vgic_ap0r[0], ICH_AP0R0_EL2);
+ }
+
+ switch (max_lr_idx) {
+ case 15:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(15)], ICH_LR15_EL2);
+ case 14:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(14)], ICH_LR14_EL2);
+ case 13:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(13)], ICH_LR13_EL2);
+ case 12:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(12)], ICH_LR12_EL2);
+ case 11:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(11)], ICH_LR11_EL2);
+ case 10:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(10)], ICH_LR10_EL2);
+ case 9:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(9)], ICH_LR9_EL2);
+ case 8:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(8)], ICH_LR8_EL2);
+ case 7:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(7)], ICH_LR7_EL2);
+ case 6:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(6)], ICH_LR6_EL2);
+ case 5:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(5)], ICH_LR5_EL2);
+ case 4:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(4)], ICH_LR4_EL2);
+ case 3:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(3)], ICH_LR3_EL2);
+ case 2:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(2)], ICH_LR2_EL2);
+ case 1:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(1)], ICH_LR1_EL2);
+ case 0:
+ write_gicreg(cpu_if->vgic_lr[VGIC_V3_LR_INDEX(0)], ICH_LR0_EL2);
+ }
+
+ /*
+ * Ensures that the above will have reached the
+ * (re)distributors. This ensure the guest will read the
+ * correct values from the memory-mapped interface.
+ */
+ isb();
+ dsb(sy);
+
+ /*
+ * Prevent the guest from touching the GIC system registers if
+ * SRE isn't enabled for GICv3 emulation.
+ */
+ if (!cpu_if->vgic_sre) {
+ write_gicreg(read_gicreg(ICC_SRE_EL2) & ~ICC_SRE_EL2_ENABLE,
+ ICC_SRE_EL2);
+ }
+}
+
+static u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
+{
+ return read_gicreg(ICH_VTR_EL2);
+}
+
+__alias(__vgic_v3_read_ich_vtr_el2) u64 __vgic_v3_get_ich_vtr_el2(void);
diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
index 85c5715..648112e 100644
--- a/arch/arm64/kvm/inject_fault.c
+++ b/arch/arm64/kvm/inject_fault.c
@@ -48,7 +48,7 @@ static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
/* Note: These now point to the banked copies */
*vcpu_spsr(vcpu) = new_spsr_value;
- *vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
+ *vcpu_reg32(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
/* Branch to exception vector */
if (sctlr & (1 << 13))
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c
index 87a64e8..eec3598 100644
--- a/arch/arm64/kvm/sys_regs.c
+++ b/arch/arm64/kvm/sys_regs.c
@@ -29,6 +29,7 @@
#include <asm/debug-monitors.h>
#include <asm/esr.h>
#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
#include <asm/kvm_coproc.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_host.h>
@@ -78,7 +79,7 @@ static u32 get_ccsidr(u32 csselr)
* See note at ARMv7 ARM B1.14.4 (TL;DR: S/W ops are not easily virtualized).
*/
static bool access_dcsw(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (!p->is_write)
@@ -94,21 +95,19 @@ static bool access_dcsw(struct kvm_vcpu *vcpu,
* sys_regs and leave it in complete control of the caches.
*/
static bool access_vm_reg(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
- unsigned long val;
bool was_enabled = vcpu_has_cache_enabled(vcpu);
BUG_ON(!p->is_write);
- val = *vcpu_reg(vcpu, p->Rt);
if (!p->is_aarch32) {
- vcpu_sys_reg(vcpu, r->reg) = val;
+ vcpu_sys_reg(vcpu, r->reg) = p->regval;
} else {
if (!p->is_32bit)
- vcpu_cp15_64_high(vcpu, r->reg) = val >> 32;
- vcpu_cp15_64_low(vcpu, r->reg) = val & 0xffffffffUL;
+ vcpu_cp15_64_high(vcpu, r->reg) = upper_32_bits(p->regval);
+ vcpu_cp15_64_low(vcpu, r->reg) = lower_32_bits(p->regval);
}
kvm_toggle_cache(vcpu, was_enabled);
@@ -122,22 +121,19 @@ static bool access_vm_reg(struct kvm_vcpu *vcpu,
* for both AArch64 and AArch32 accesses.
*/
static bool access_gic_sgi(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
- u64 val;
-
if (!p->is_write)
return read_from_write_only(vcpu, p);
- val = *vcpu_reg(vcpu, p->Rt);
- vgic_v3_dispatch_sgi(vcpu, val);
+ vgic_v3_dispatch_sgi(vcpu, p->regval);
return true;
}
static bool trap_raz_wi(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write)
@@ -147,19 +143,19 @@ static bool trap_raz_wi(struct kvm_vcpu *vcpu,
}
static bool trap_oslsr_el1(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write) {
return ignore_write(vcpu, p);
} else {
- *vcpu_reg(vcpu, p->Rt) = (1 << 3);
+ p->regval = (1 << 3);
return true;
}
}
static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write) {
@@ -167,7 +163,7 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
} else {
u32 val;
asm volatile("mrs %0, dbgauthstatus_el1" : "=r" (val));
- *vcpu_reg(vcpu, p->Rt) = val;
+ p->regval = val;
return true;
}
}
@@ -200,17 +196,17 @@ static bool trap_dbgauthstatus_el1(struct kvm_vcpu *vcpu,
* now use the debug registers.
*/
static bool trap_debug_regs(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write) {
- vcpu_sys_reg(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
+ vcpu_sys_reg(vcpu, r->reg) = p->regval;
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
} else {
- *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg);
+ p->regval = vcpu_sys_reg(vcpu, r->reg);
}
- trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt));
+ trace_trap_reg(__func__, r->reg, p->is_write, p->regval);
return true;
}
@@ -224,11 +220,11 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu,
* All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the
* hyp.S code switches between host and guest values in future.
*/
-static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- u64 *dbg_reg)
+static void reg_to_dbg(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ u64 *dbg_reg)
{
- u64 val = *vcpu_reg(vcpu, p->Rt);
+ u64 val = p->regval;
if (p->is_32bit) {
val &= 0xffffffffUL;
@@ -239,21 +235,18 @@ static inline void reg_to_dbg(struct kvm_vcpu *vcpu,
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
}
-static inline void dbg_to_reg(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- u64 *dbg_reg)
+static void dbg_to_reg(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ u64 *dbg_reg)
{
- u64 val = *dbg_reg;
-
+ p->regval = *dbg_reg;
if (p->is_32bit)
- val &= 0xffffffffUL;
-
- *vcpu_reg(vcpu, p->Rt) = val;
+ p->regval &= 0xffffffffUL;
}
-static inline bool trap_bvr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- const struct sys_reg_desc *rd)
+static bool trap_bvr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *rd)
{
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
@@ -287,15 +280,15 @@ static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return 0;
}
-static inline void reset_bvr(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *rd)
+static void reset_bvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
{
vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val;
}
-static inline bool trap_bcr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- const struct sys_reg_desc *rd)
+static bool trap_bcr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *rd)
{
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg];
@@ -330,15 +323,15 @@ static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return 0;
}
-static inline void reset_bcr(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *rd)
+static void reset_bcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
{
vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val;
}
-static inline bool trap_wvr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- const struct sys_reg_desc *rd)
+static bool trap_wvr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *rd)
{
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg];
@@ -373,15 +366,15 @@ static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return 0;
}
-static inline void reset_wvr(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *rd)
+static void reset_wvr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
{
vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val;
}
-static inline bool trap_wcr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- const struct sys_reg_desc *rd)
+static bool trap_wcr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *rd)
{
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg];
@@ -415,8 +408,8 @@ static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd,
return 0;
}
-static inline void reset_wcr(struct kvm_vcpu *vcpu,
- const struct sys_reg_desc *rd)
+static void reset_wcr(struct kvm_vcpu *vcpu,
+ const struct sys_reg_desc *rd)
{
vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val;
}
@@ -687,7 +680,7 @@ static const struct sys_reg_desc sys_reg_descs[] = {
};
static bool trap_dbgidr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write) {
@@ -697,23 +690,23 @@ static bool trap_dbgidr(struct kvm_vcpu *vcpu,
u64 pfr = read_system_reg(SYS_ID_AA64PFR0_EL1);
u32 el3 = !!cpuid_feature_extract_field(pfr, ID_AA64PFR0_EL3_SHIFT);
- *vcpu_reg(vcpu, p->Rt) = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) |
- (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) |
- (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20) |
- (6 << 16) | (el3 << 14) | (el3 << 12));
+ p->regval = ((((dfr >> ID_AA64DFR0_WRPS_SHIFT) & 0xf) << 28) |
+ (((dfr >> ID_AA64DFR0_BRPS_SHIFT) & 0xf) << 24) |
+ (((dfr >> ID_AA64DFR0_CTX_CMPS_SHIFT) & 0xf) << 20)
+ | (6 << 16) | (el3 << 14) | (el3 << 12));
return true;
}
}
static bool trap_debug32(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write) {
- vcpu_cp14(vcpu, r->reg) = *vcpu_reg(vcpu, p->Rt);
+ vcpu_cp14(vcpu, r->reg) = p->regval;
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
} else {
- *vcpu_reg(vcpu, p->Rt) = vcpu_cp14(vcpu, r->reg);
+ p->regval = vcpu_cp14(vcpu, r->reg);
}
return true;
@@ -730,9 +723,9 @@ static bool trap_debug32(struct kvm_vcpu *vcpu,
* system is in.
*/
-static inline bool trap_xvr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
- const struct sys_reg_desc *rd)
+static bool trap_xvr(struct kvm_vcpu *vcpu,
+ struct sys_reg_params *p,
+ const struct sys_reg_desc *rd)
{
u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg];
@@ -740,12 +733,12 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu,
u64 val = *dbg_reg;
val &= 0xffffffffUL;
- val |= *vcpu_reg(vcpu, p->Rt) << 32;
+ val |= p->regval << 32;
*dbg_reg = val;
vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY;
} else {
- *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32;
+ p->regval = *dbg_reg >> 32;
}
trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg);
@@ -991,7 +984,7 @@ int kvm_handle_cp14_load_store(struct kvm_vcpu *vcpu, struct kvm_run *run)
* Return 0 if the access has been handled, and -1 if not.
*/
static int emulate_cp(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *params,
+ struct sys_reg_params *params,
const struct sys_reg_desc *table,
size_t num)
{
@@ -1062,12 +1055,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
{
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
+ int Rt = (hsr >> 5) & 0xf;
int Rt2 = (hsr >> 10) & 0xf;
params.is_aarch32 = true;
params.is_32bit = false;
params.CRm = (hsr >> 1) & 0xf;
- params.Rt = (hsr >> 5) & 0xf;
params.is_write = ((hsr & 1) == 0);
params.Op0 = 0;
@@ -1076,15 +1069,12 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
params.CRn = 0;
/*
- * Massive hack here. Store Rt2 in the top 32bits so we only
- * have one register to deal with. As we use the same trap
+ * Make a 64-bit value out of Rt and Rt2. As we use the same trap
* backends between AArch32 and AArch64, we get away with it.
*/
if (params.is_write) {
- u64 val = *vcpu_reg(vcpu, params.Rt);
- val &= 0xffffffff;
- val |= *vcpu_reg(vcpu, Rt2) << 32;
- *vcpu_reg(vcpu, params.Rt) = val;
+ params.regval = vcpu_get_reg(vcpu, Rt) & 0xffffffff;
+ params.regval |= vcpu_get_reg(vcpu, Rt2) << 32;
}
if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
@@ -1095,11 +1085,10 @@ static int kvm_handle_cp_64(struct kvm_vcpu *vcpu,
unhandled_cp_access(vcpu, &params);
out:
- /* Do the opposite hack for the read side */
+ /* Split up the value between registers for the read side */
if (!params.is_write) {
- u64 val = *vcpu_reg(vcpu, params.Rt);
- val >>= 32;
- *vcpu_reg(vcpu, Rt2) = val;
+ vcpu_set_reg(vcpu, Rt, lower_32_bits(params.regval));
+ vcpu_set_reg(vcpu, Rt2, upper_32_bits(params.regval));
}
return 1;
@@ -1118,21 +1107,24 @@ static int kvm_handle_cp_32(struct kvm_vcpu *vcpu,
{
struct sys_reg_params params;
u32 hsr = kvm_vcpu_get_hsr(vcpu);
+ int Rt = (hsr >> 5) & 0xf;
params.is_aarch32 = true;
params.is_32bit = true;
params.CRm = (hsr >> 1) & 0xf;
- params.Rt = (hsr >> 5) & 0xf;
+ params.regval = vcpu_get_reg(vcpu, Rt);
params.is_write = ((hsr & 1) == 0);
params.CRn = (hsr >> 10) & 0xf;
params.Op0 = 0;
params.Op1 = (hsr >> 14) & 0x7;
params.Op2 = (hsr >> 17) & 0x7;
- if (!emulate_cp(vcpu, &params, target_specific, nr_specific))
- return 1;
- if (!emulate_cp(vcpu, &params, global, nr_global))
+ if (!emulate_cp(vcpu, &params, target_specific, nr_specific) ||
+ !emulate_cp(vcpu, &params, global, nr_global)) {
+ if (!params.is_write)
+ vcpu_set_reg(vcpu, Rt, params.regval);
return 1;
+ }
unhandled_cp_access(vcpu, &params);
return 1;
@@ -1175,7 +1167,7 @@ int kvm_handle_cp14_32(struct kvm_vcpu *vcpu, struct kvm_run *run)
}
static int emulate_sys_reg(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *params)
+ struct sys_reg_params *params)
{
size_t num;
const struct sys_reg_desc *table, *r;
@@ -1230,6 +1222,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
struct sys_reg_params params;
unsigned long esr = kvm_vcpu_get_hsr(vcpu);
+ int Rt = (esr >> 5) & 0x1f;
+ int ret;
trace_kvm_handle_sys_reg(esr);
@@ -1240,10 +1234,14 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run)
params.CRn = (esr >> 10) & 0xf;
params.CRm = (esr >> 1) & 0xf;
params.Op2 = (esr >> 17) & 0x7;
- params.Rt = (esr >> 5) & 0x1f;
+ params.regval = vcpu_get_reg(vcpu, Rt);
params.is_write = !(esr & 1);
- return emulate_sys_reg(vcpu, &params);
+ ret = emulate_sys_reg(vcpu, &params);
+
+ if (!params.is_write)
+ vcpu_set_reg(vcpu, Rt, params.regval);
+ return ret;
}
/******************************************************************************
diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h
index eaa324e..dbbb01c 100644
--- a/arch/arm64/kvm/sys_regs.h
+++ b/arch/arm64/kvm/sys_regs.h
@@ -28,7 +28,7 @@ struct sys_reg_params {
u8 CRn;
u8 CRm;
u8 Op2;
- u8 Rt;
+ u64 regval;
bool is_write;
bool is_aarch32;
bool is_32bit; /* Only valid if is_aarch32 is true */
@@ -44,7 +44,7 @@ struct sys_reg_desc {
/* Trapped access from guest, if non-NULL. */
bool (*access)(struct kvm_vcpu *,
- const struct sys_reg_params *,
+ struct sys_reg_params *,
const struct sys_reg_desc *);
/* Initialization for vcpu. */
@@ -77,9 +77,9 @@ static inline bool ignore_write(struct kvm_vcpu *vcpu,
}
static inline bool read_zero(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p)
+ struct sys_reg_params *p)
{
- *vcpu_reg(vcpu, p->Rt) = 0;
+ p->regval = 0;
return true;
}
diff --git a/arch/arm64/kvm/sys_regs_generic_v8.c b/arch/arm64/kvm/sys_regs_generic_v8.c
index 1e45768..ed90578 100644
--- a/arch/arm64/kvm/sys_regs_generic_v8.c
+++ b/arch/arm64/kvm/sys_regs_generic_v8.c
@@ -31,13 +31,13 @@
#include "sys_regs.h"
static bool access_actlr(struct kvm_vcpu *vcpu,
- const struct sys_reg_params *p,
+ struct sys_reg_params *p,
const struct sys_reg_desc *r)
{
if (p->is_write)
return ignore_write(vcpu, p);
- *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, ACTLR_EL1);
+ p->regval = vcpu_sys_reg(vcpu, ACTLR_EL1);
return true;
}
diff --git a/arch/arm64/kvm/vgic-v2-switch.S b/arch/arm64/kvm/vgic-v2-switch.S
deleted file mode 100644
index 3f00071..0000000
--- a/arch/arm64/kvm/vgic-v2-switch.S
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/linkage.h>
-#include <linux/irqchip/arm-gic.h>
-
-#include <asm/assembler.h>
-#include <asm/memory.h>
-#include <asm/asm-offsets.h>
-#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_arm.h>
-#include <asm/kvm_mmu.h>
-
- .text
- .pushsection .hyp.text, "ax"
-
-/*
- * Save the VGIC CPU state into memory
- * x0: Register pointing to VCPU struct
- * Do not corrupt x1!!!
- */
-ENTRY(__save_vgic_v2_state)
-__save_vgic_v2_state:
- /* Get VGIC VCTRL base into x2 */
- ldr x2, [x0, #VCPU_KVM]
- kern_hyp_va x2
- ldr x2, [x2, #KVM_VGIC_VCTRL]
- kern_hyp_va x2
- cbz x2, 2f // disabled
-
- /* Compute the address of struct vgic_cpu */
- add x3, x0, #VCPU_VGIC_CPU
-
- /* Save all interesting registers */
- ldr w5, [x2, #GICH_VMCR]
- ldr w6, [x2, #GICH_MISR]
- ldr w7, [x2, #GICH_EISR0]
- ldr w8, [x2, #GICH_EISR1]
- ldr w9, [x2, #GICH_ELRSR0]
- ldr w10, [x2, #GICH_ELRSR1]
- ldr w11, [x2, #GICH_APR]
-CPU_BE( rev w5, w5 )
-CPU_BE( rev w6, w6 )
-CPU_BE( rev w7, w7 )
-CPU_BE( rev w8, w8 )
-CPU_BE( rev w9, w9 )
-CPU_BE( rev w10, w10 )
-CPU_BE( rev w11, w11 )
-
- str w5, [x3, #VGIC_V2_CPU_VMCR]
- str w6, [x3, #VGIC_V2_CPU_MISR]
-CPU_LE( str w7, [x3, #VGIC_V2_CPU_EISR] )
-CPU_LE( str w8, [x3, #(VGIC_V2_CPU_EISR + 4)] )
-CPU_LE( str w9, [x3, #VGIC_V2_CPU_ELRSR] )
-CPU_LE( str w10, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
-CPU_BE( str w7, [x3, #(VGIC_V2_CPU_EISR + 4)] )
-CPU_BE( str w8, [x3, #VGIC_V2_CPU_EISR] )
-CPU_BE( str w9, [x3, #(VGIC_V2_CPU_ELRSR + 4)] )
-CPU_BE( str w10, [x3, #VGIC_V2_CPU_ELRSR] )
- str w11, [x3, #VGIC_V2_CPU_APR]
-
- /* Clear GICH_HCR */
- str wzr, [x2, #GICH_HCR]
-
- /* Save list registers */
- add x2, x2, #GICH_LR0
- ldr w4, [x3, #VGIC_CPU_NR_LR]
- add x3, x3, #VGIC_V2_CPU_LR
-1: ldr w5, [x2], #4
-CPU_BE( rev w5, w5 )
- str w5, [x3], #4
- sub w4, w4, #1
- cbnz w4, 1b
-2:
- ret
-ENDPROC(__save_vgic_v2_state)
-
-/*
- * Restore the VGIC CPU state from memory
- * x0: Register pointing to VCPU struct
- */
-ENTRY(__restore_vgic_v2_state)
-__restore_vgic_v2_state:
- /* Get VGIC VCTRL base into x2 */
- ldr x2, [x0, #VCPU_KVM]
- kern_hyp_va x2
- ldr x2, [x2, #KVM_VGIC_VCTRL]
- kern_hyp_va x2
- cbz x2, 2f // disabled
-
- /* Compute the address of struct vgic_cpu */
- add x3, x0, #VCPU_VGIC_CPU
-
- /* We only restore a minimal set of registers */
- ldr w4, [x3, #VGIC_V2_CPU_HCR]
- ldr w5, [x3, #VGIC_V2_CPU_VMCR]
- ldr w6, [x3, #VGIC_V2_CPU_APR]
-CPU_BE( rev w4, w4 )
-CPU_BE( rev w5, w5 )
-CPU_BE( rev w6, w6 )
-
- str w4, [x2, #GICH_HCR]
- str w5, [x2, #GICH_VMCR]
- str w6, [x2, #GICH_APR]
-
- /* Restore list registers */
- add x2, x2, #GICH_LR0
- ldr w4, [x3, #VGIC_CPU_NR_LR]
- add x3, x3, #VGIC_V2_CPU_LR
-1: ldr w5, [x3], #4
-CPU_BE( rev w5, w5 )
- str w5, [x2], #4
- sub w4, w4, #1
- cbnz w4, 1b
-2:
- ret
-ENDPROC(__restore_vgic_v2_state)
-
- .popsection
diff --git a/arch/arm64/kvm/vgic-v3-switch.S b/arch/arm64/kvm/vgic-v3-switch.S
deleted file mode 100644
index 3c20730..0000000
--- a/arch/arm64/kvm/vgic-v3-switch.S
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (C) 2012,2013 - ARM Ltd
- * Author: Marc Zyngier <marc.zyngier@arm.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/linkage.h>
-#include <linux/irqchip/arm-gic-v3.h>
-
-#include <asm/assembler.h>
-#include <asm/memory.h>
-#include <asm/asm-offsets.h>
-#include <asm/kvm.h>
-#include <asm/kvm_asm.h>
-#include <asm/kvm_arm.h>
-
- .text
- .pushsection .hyp.text, "ax"
-
-/*
- * We store LRs in reverse order to let the CPU deal with streaming
- * access. Use this macro to make it look saner...
- */
-#define LR_OFFSET(n) (VGIC_V3_CPU_LR + (15 - n) * 8)
-
-/*
- * Save the VGIC CPU state into memory
- * x0: Register pointing to VCPU struct
- * Do not corrupt x1!!!
- */
-.macro save_vgic_v3_state
- // Compute the address of struct vgic_cpu
- add x3, x0, #VCPU_VGIC_CPU
-
- // Make sure stores to the GIC via the memory mapped interface
- // are now visible to the system register interface
- dsb st
-
- // Save all interesting registers
- mrs_s x5, ICH_VMCR_EL2
- mrs_s x6, ICH_MISR_EL2
- mrs_s x7, ICH_EISR_EL2
- mrs_s x8, ICH_ELSR_EL2
-
- str w5, [x3, #VGIC_V3_CPU_VMCR]
- str w6, [x3, #VGIC_V3_CPU_MISR]
- str w7, [x3, #VGIC_V3_CPU_EISR]
- str w8, [x3, #VGIC_V3_CPU_ELRSR]
-
- msr_s ICH_HCR_EL2, xzr
-
- mrs_s x21, ICH_VTR_EL2
- mvn w22, w21
- ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
-
- adr x24, 1f
- add x24, x24, x23
- br x24
-
-1:
- mrs_s x20, ICH_LR15_EL2
- mrs_s x19, ICH_LR14_EL2
- mrs_s x18, ICH_LR13_EL2
- mrs_s x17, ICH_LR12_EL2
- mrs_s x16, ICH_LR11_EL2
- mrs_s x15, ICH_LR10_EL2
- mrs_s x14, ICH_LR9_EL2
- mrs_s x13, ICH_LR8_EL2
- mrs_s x12, ICH_LR7_EL2
- mrs_s x11, ICH_LR6_EL2
- mrs_s x10, ICH_LR5_EL2
- mrs_s x9, ICH_LR4_EL2
- mrs_s x8, ICH_LR3_EL2
- mrs_s x7, ICH_LR2_EL2
- mrs_s x6, ICH_LR1_EL2
- mrs_s x5, ICH_LR0_EL2
-
- adr x24, 1f
- add x24, x24, x23
- br x24
-
-1:
- str x20, [x3, #LR_OFFSET(15)]
- str x19, [x3, #LR_OFFSET(14)]
- str x18, [x3, #LR_OFFSET(13)]
- str x17, [x3, #LR_OFFSET(12)]
- str x16, [x3, #LR_OFFSET(11)]
- str x15, [x3, #LR_OFFSET(10)]
- str x14, [x3, #LR_OFFSET(9)]
- str x13, [x3, #LR_OFFSET(8)]
- str x12, [x3, #LR_OFFSET(7)]
- str x11, [x3, #LR_OFFSET(6)]
- str x10, [x3, #LR_OFFSET(5)]
- str x9, [x3, #LR_OFFSET(4)]
- str x8, [x3, #LR_OFFSET(3)]
- str x7, [x3, #LR_OFFSET(2)]
- str x6, [x3, #LR_OFFSET(1)]
- str x5, [x3, #LR_OFFSET(0)]
-
- tbnz w21, #29, 6f // 6 bits
- tbz w21, #30, 5f // 5 bits
- // 7 bits
- mrs_s x20, ICH_AP0R3_EL2
- str w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
- mrs_s x19, ICH_AP0R2_EL2
- str w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
-6: mrs_s x18, ICH_AP0R1_EL2
- str w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
-5: mrs_s x17, ICH_AP0R0_EL2
- str w17, [x3, #VGIC_V3_CPU_AP0R]
-
- tbnz w21, #29, 6f // 6 bits
- tbz w21, #30, 5f // 5 bits
- // 7 bits
- mrs_s x20, ICH_AP1R3_EL2
- str w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
- mrs_s x19, ICH_AP1R2_EL2
- str w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
-6: mrs_s x18, ICH_AP1R1_EL2
- str w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
-5: mrs_s x17, ICH_AP1R0_EL2
- str w17, [x3, #VGIC_V3_CPU_AP1R]
-
- // Restore SRE_EL1 access and re-enable SRE at EL1.
- mrs_s x5, ICC_SRE_EL2
- orr x5, x5, #ICC_SRE_EL2_ENABLE
- msr_s ICC_SRE_EL2, x5
- isb
- mov x5, #1
- msr_s ICC_SRE_EL1, x5
-.endm
-
-/*
- * Restore the VGIC CPU state from memory
- * x0: Register pointing to VCPU struct
- */
-.macro restore_vgic_v3_state
- // Compute the address of struct vgic_cpu
- add x3, x0, #VCPU_VGIC_CPU
-
- // Restore all interesting registers
- ldr w4, [x3, #VGIC_V3_CPU_HCR]
- ldr w5, [x3, #VGIC_V3_CPU_VMCR]
- ldr w25, [x3, #VGIC_V3_CPU_SRE]
-
- msr_s ICC_SRE_EL1, x25
-
- // make sure SRE is valid before writing the other registers
- isb
-
- msr_s ICH_HCR_EL2, x4
- msr_s ICH_VMCR_EL2, x5
-
- mrs_s x21, ICH_VTR_EL2
-
- tbnz w21, #29, 6f // 6 bits
- tbz w21, #30, 5f // 5 bits
- // 7 bits
- ldr w20, [x3, #(VGIC_V3_CPU_AP1R + 3*4)]
- msr_s ICH_AP1R3_EL2, x20
- ldr w19, [x3, #(VGIC_V3_CPU_AP1R + 2*4)]
- msr_s ICH_AP1R2_EL2, x19
-6: ldr w18, [x3, #(VGIC_V3_CPU_AP1R + 1*4)]
- msr_s ICH_AP1R1_EL2, x18
-5: ldr w17, [x3, #VGIC_V3_CPU_AP1R]
- msr_s ICH_AP1R0_EL2, x17
-
- tbnz w21, #29, 6f // 6 bits
- tbz w21, #30, 5f // 5 bits
- // 7 bits
- ldr w20, [x3, #(VGIC_V3_CPU_AP0R + 3*4)]
- msr_s ICH_AP0R3_EL2, x20
- ldr w19, [x3, #(VGIC_V3_CPU_AP0R + 2*4)]
- msr_s ICH_AP0R2_EL2, x19
-6: ldr w18, [x3, #(VGIC_V3_CPU_AP0R + 1*4)]
- msr_s ICH_AP0R1_EL2, x18
-5: ldr w17, [x3, #VGIC_V3_CPU_AP0R]
- msr_s ICH_AP0R0_EL2, x17
-
- and w22, w21, #0xf
- mvn w22, w21
- ubfiz w23, w22, 2, 4 // w23 = (15 - ListRegs) * 4
-
- adr x24, 1f
- add x24, x24, x23
- br x24
-
-1:
- ldr x20, [x3, #LR_OFFSET(15)]
- ldr x19, [x3, #LR_OFFSET(14)]
- ldr x18, [x3, #LR_OFFSET(13)]
- ldr x17, [x3, #LR_OFFSET(12)]
- ldr x16, [x3, #LR_OFFSET(11)]
- ldr x15, [x3, #LR_OFFSET(10)]
- ldr x14, [x3, #LR_OFFSET(9)]
- ldr x13, [x3, #LR_OFFSET(8)]
- ldr x12, [x3, #LR_OFFSET(7)]
- ldr x11, [x3, #LR_OFFSET(6)]
- ldr x10, [x3, #LR_OFFSET(5)]
- ldr x9, [x3, #LR_OFFSET(4)]
- ldr x8, [x3, #LR_OFFSET(3)]
- ldr x7, [x3, #LR_OFFSET(2)]
- ldr x6, [x3, #LR_OFFSET(1)]
- ldr x5, [x3, #LR_OFFSET(0)]
-
- adr x24, 1f
- add x24, x24, x23
- br x24
-
-1:
- msr_s ICH_LR15_EL2, x20
- msr_s ICH_LR14_EL2, x19
- msr_s ICH_LR13_EL2, x18
- msr_s ICH_LR12_EL2, x17
- msr_s ICH_LR11_EL2, x16
- msr_s ICH_LR10_EL2, x15
- msr_s ICH_LR9_EL2, x14
- msr_s ICH_LR8_EL2, x13
- msr_s ICH_LR7_EL2, x12
- msr_s ICH_LR6_EL2, x11
- msr_s ICH_LR5_EL2, x10
- msr_s ICH_LR4_EL2, x9
- msr_s ICH_LR3_EL2, x8
- msr_s ICH_LR2_EL2, x7
- msr_s ICH_LR1_EL2, x6
- msr_s ICH_LR0_EL2, x5
-
- // Ensure that the above will have reached the
- // (re)distributors. This ensure the guest will read
- // the correct values from the memory-mapped interface.
- isb
- dsb sy
-
- // Prevent the guest from touching the GIC system registers
- // if SRE isn't enabled for GICv3 emulation
- cbnz x25, 1f
- mrs_s x5, ICC_SRE_EL2
- and x5, x5, #~ICC_SRE_EL2_ENABLE
- msr_s ICC_SRE_EL2, x5
-1:
-.endm
-
-ENTRY(__save_vgic_v3_state)
- save_vgic_v3_state
- ret
-ENDPROC(__save_vgic_v3_state)
-
-ENTRY(__restore_vgic_v3_state)
- restore_vgic_v3_state
- ret
-ENDPROC(__restore_vgic_v3_state)
-
-ENTRY(__vgic_v3_get_ich_vtr_el2)
- mrs_s x0, ICH_VTR_EL2
- ret
-ENDPROC(__vgic_v3_get_ich_vtr_el2)
-
- .popsection
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index cfa44a6..6df0706 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -81,26 +81,32 @@ ENDPROC(__flush_cache_user_range)
/*
* __flush_dcache_area(kaddr, size)
*
- * Ensure that the data held in the page kaddr is written back to the
- * page in question.
+ * Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * are cleaned and invalidated to the PoC.
*
* - kaddr - kernel address
* - size - size in question
*/
ENTRY(__flush_dcache_area)
- dcache_line_size x2, x3
- add x1, x0, x1
- sub x3, x2, #1
- bic x0, x0, x3
-1: dc civac, x0 // clean & invalidate D line / unified line
- add x0, x0, x2
- cmp x0, x1
- b.lo 1b
- dsb sy
+ dcache_by_line_op civac, sy, x0, x1, x2, x3
ret
ENDPIPROC(__flush_dcache_area)
/*
+ * __clean_dcache_area_pou(kaddr, size)
+ *
+ * Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
+ * are cleaned to the PoU.
+ *
+ * - kaddr - kernel address
+ * - size - size in question
+ */
+ENTRY(__clean_dcache_area_pou)
+ dcache_by_line_op cvau, ish, x0, x1, x2, x3
+ ret
+ENDPROC(__clean_dcache_area_pou)
+
+/*
* __inval_cache_range(start, end)
* - start - start address of region
* - end - end address of region
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index f636a26..e87f53f 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -76,13 +76,28 @@ static void flush_context(unsigned int cpu)
__flush_icache_all();
}
-static int is_reserved_asid(u64 asid)
+static bool check_update_reserved_asid(u64 asid, u64 newasid)
{
int cpu;
- for_each_possible_cpu(cpu)
- if (per_cpu(reserved_asids, cpu) == asid)
- return 1;
- return 0;
+ bool hit = false;
+
+ /*
+ * Iterate over the set of reserved ASIDs looking for a match.
+ * If we find one, then we can update our mm to use newasid
+ * (i.e. the same ASID in the current generation) but we can't
+ * exit the loop early, since we need to ensure that all copies
+ * of the old ASID are updated to reflect the mm. Failure to do
+ * so could result in us missing the reserved ASID in a future
+ * generation.
+ */
+ for_each_possible_cpu(cpu) {
+ if (per_cpu(reserved_asids, cpu) == asid) {
+ hit = true;
+ per_cpu(reserved_asids, cpu) = newasid;
+ }
+ }
+
+ return hit;
}
static u64 new_context(struct mm_struct *mm, unsigned int cpu)
@@ -92,12 +107,14 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
u64 generation = atomic64_read(&asid_generation);
if (asid != 0) {
+ u64 newasid = generation | (asid & ~ASID_MASK);
+
/*
* If our current ASID was active during a rollover, we
* can continue to use it and this was just a false alarm.
*/
- if (is_reserved_asid(asid))
- return generation | (asid & ~ASID_MASK);
+ if (check_update_reserved_asid(asid, newasid))
+ return newasid;
/*
* We had a valid ASID in a previous life, so try to re-use
@@ -105,7 +122,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
*/
asid &= ~ASID_MASK;
if (!__test_and_set_bit(asid, asid_map))
- goto bump_gen;
+ return newasid;
}
/*
@@ -129,10 +146,7 @@ static u64 new_context(struct mm_struct *mm, unsigned int cpu)
set_asid:
__set_bit(asid, asid_map);
cur_idx = asid;
-
-bump_gen:
- asid |= generation;
- return asid;
+ return asid | generation;
}
void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
diff --git a/arch/arm64/mm/copypage.c b/arch/arm64/mm/copypage.c
index 13bbc3be..22e4cb4 100644
--- a/arch/arm64/mm/copypage.c
+++ b/arch/arm64/mm/copypage.c
@@ -24,8 +24,9 @@
void __cpu_copy_user_page(void *kto, const void *kfrom, unsigned long vaddr)
{
+ struct page *page = virt_to_page(kto);
copy_page(kto, kfrom);
- __flush_dcache_area(kto, PAGE_SIZE);
+ flush_dcache_page(page);
}
EXPORT_SYMBOL_GPL(__cpu_copy_user_page);
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 131a199..331c4ca 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -18,6 +18,7 @@
*/
#include <linux/gfp.h>
+#include <linux/acpi.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/genalloc.h>
@@ -28,9 +29,6 @@
#include <asm/cacheflush.h>
-struct dma_map_ops *dma_ops;
-EXPORT_SYMBOL(dma_ops);
-
static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
bool coherent)
{
@@ -42,7 +40,7 @@ static pgprot_t __get_dma_pgprot(struct dma_attrs *attrs, pgprot_t prot,
static struct gen_pool *atomic_pool;
#define DEFAULT_DMA_COHERENT_POOL_SIZE SZ_256K
-static size_t atomic_pool_size = DEFAULT_DMA_COHERENT_POOL_SIZE;
+static size_t atomic_pool_size __initdata = DEFAULT_DMA_COHERENT_POOL_SIZE;
static int __init early_coherent_pool(char *p)
{
@@ -515,13 +513,7 @@ EXPORT_SYMBOL(dummy_dma_ops);
static int __init arm64_dma_init(void)
{
- int ret;
-
- dma_ops = &swiotlb_dma_ops;
-
- ret = atomic_pool_init();
-
- return ret;
+ return atomic_pool_init();
}
arch_initcall(arm64_dma_init);
@@ -552,10 +544,14 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
{
bool coherent = is_device_dma_coherent(dev);
int ioprot = dma_direction_to_prot(DMA_BIDIRECTIONAL, coherent);
+ size_t iosize = size;
void *addr;
if (WARN(!dev, "cannot create IOMMU mapping for unknown device\n"))
return NULL;
+
+ size = PAGE_ALIGN(size);
+
/*
* Some drivers rely on this, and we probably don't want the
* possibility of stale kernel data being read by devices anyway.
@@ -566,7 +562,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
struct page **pages;
pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL, coherent);
- pages = iommu_dma_alloc(dev, size, gfp, ioprot, handle,
+ pages = iommu_dma_alloc(dev, iosize, gfp, ioprot, handle,
flush_page);
if (!pages)
return NULL;
@@ -574,7 +570,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
__builtin_return_address(0));
if (!addr)
- iommu_dma_free(dev, pages, size, handle);
+ iommu_dma_free(dev, pages, iosize, handle);
} else {
struct page *page;
/*
@@ -591,7 +587,7 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
if (!addr)
return NULL;
- *handle = iommu_dma_map_page(dev, page, 0, size, ioprot);
+ *handle = iommu_dma_map_page(dev, page, 0, iosize, ioprot);
if (iommu_dma_mapping_error(dev, *handle)) {
if (coherent)
__free_pages(page, get_order(size));
@@ -606,6 +602,9 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
dma_addr_t handle, struct dma_attrs *attrs)
{
+ size_t iosize = size;
+
+ size = PAGE_ALIGN(size);
/*
* @cpu_addr will be one of 3 things depending on how it was allocated:
* - A remapped array of pages from iommu_dma_alloc(), for all
@@ -617,17 +616,17 @@ static void __iommu_free_attrs(struct device *dev, size_t size, void *cpu_addr,
* Hence how dodgy the below logic looks...
*/
if (__in_atomic_pool(cpu_addr, size)) {
- iommu_dma_unmap_page(dev, handle, size, 0, NULL);
+ iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
__free_from_pool(cpu_addr, size);
} else if (is_vmalloc_addr(cpu_addr)){
struct vm_struct *area = find_vm_area(cpu_addr);
if (WARN_ON(!area || !area->pages))
return;
- iommu_dma_free(dev, area->pages, size, &handle);
+ iommu_dma_free(dev, area->pages, iosize, &handle);
dma_common_free_remap(cpu_addr, size, VM_USERMAP);
} else {
- iommu_dma_unmap_page(dev, handle, size, 0, NULL);
+ iommu_dma_unmap_page(dev, handle, iosize, 0, NULL);
__free_pages(virt_to_page(cpu_addr), get_order(size));
}
}
@@ -897,7 +896,7 @@ static int __iommu_attach_notifier(struct notifier_block *nb,
return 0;
}
-static int register_iommu_dma_ops_notifier(struct bus_type *bus)
+static int __init register_iommu_dma_ops_notifier(struct bus_type *bus)
{
struct notifier_block *nb = kzalloc(sizeof(*nb), GFP_KERNEL);
int ret;
@@ -984,8 +983,8 @@ static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
struct iommu_ops *iommu, bool coherent)
{
- if (!acpi_disabled && !dev->archdata.dma_ops)
- dev->archdata.dma_ops = dma_ops;
+ if (!dev->archdata.dma_ops)
+ dev->archdata.dma_ops = &swiotlb_dma_ops;
dev->archdata.dma_coherent = coherent;
__iommu_setup_dma_ops(dev, dma_base, size, iommu);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 19211c4..92ddac1 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -393,16 +393,16 @@ static struct fault_info {
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
- { do_bad, SIGBUS, 0, "reserved access flag fault" },
+ { do_bad, SIGBUS, 0, "unknown 8" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 access flag fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 access flag fault" },
- { do_bad, SIGBUS, 0, "reserved permission fault" },
+ { do_bad, SIGBUS, 0, "unknown 12" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 1 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 2 permission fault" },
{ do_page_fault, SIGSEGV, SEGV_ACCERR, "level 3 permission fault" },
{ do_bad, SIGBUS, 0, "synchronous external abort" },
- { do_bad, SIGBUS, 0, "asynchronous external abort" },
+ { do_bad, SIGBUS, 0, "unknown 17" },
{ do_bad, SIGBUS, 0, "unknown 18" },
{ do_bad, SIGBUS, 0, "unknown 19" },
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
@@ -410,16 +410,16 @@ static struct fault_info {
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
{ do_bad, SIGBUS, 0, "synchronous abort (translation table walk)" },
{ do_bad, SIGBUS, 0, "synchronous parity error" },
- { do_bad, SIGBUS, 0, "asynchronous parity error" },
+ { do_bad, SIGBUS, 0, "unknown 25" },
{ do_bad, SIGBUS, 0, "unknown 26" },
{ do_bad, SIGBUS, 0, "unknown 27" },
- { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
- { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
- { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
- { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
+ { do_bad, SIGBUS, 0, "synchronous parity error (translation table walk)" },
{ do_bad, SIGBUS, 0, "unknown 32" },
{ do_bad, SIGBUS, BUS_ADRALN, "alignment fault" },
- { do_bad, SIGBUS, 0, "debug event" },
+ { do_bad, SIGBUS, 0, "unknown 34" },
{ do_bad, SIGBUS, 0, "unknown 35" },
{ do_bad, SIGBUS, 0, "unknown 36" },
{ do_bad, SIGBUS, 0, "unknown 37" },
@@ -433,21 +433,21 @@ static struct fault_info {
{ do_bad, SIGBUS, 0, "unknown 45" },
{ do_bad, SIGBUS, 0, "unknown 46" },
{ do_bad, SIGBUS, 0, "unknown 47" },
- { do_bad, SIGBUS, 0, "unknown 48" },
+ { do_bad, SIGBUS, 0, "TLB conflict abort" },
{ do_bad, SIGBUS, 0, "unknown 49" },
{ do_bad, SIGBUS, 0, "unknown 50" },
{ do_bad, SIGBUS, 0, "unknown 51" },
{ do_bad, SIGBUS, 0, "implementation fault (lockdown abort)" },
- { do_bad, SIGBUS, 0, "unknown 53" },
+ { do_bad, SIGBUS, 0, "implementation fault (unsupported exclusive)" },
{ do_bad, SIGBUS, 0, "unknown 54" },
{ do_bad, SIGBUS, 0, "unknown 55" },
{ do_bad, SIGBUS, 0, "unknown 56" },
{ do_bad, SIGBUS, 0, "unknown 57" },
- { do_bad, SIGBUS, 0, "implementation fault (coprocessor abort)" },
+ { do_bad, SIGBUS, 0, "unknown 58" },
{ do_bad, SIGBUS, 0, "unknown 59" },
{ do_bad, SIGBUS, 0, "unknown 60" },
- { do_bad, SIGBUS, 0, "unknown 61" },
- { do_bad, SIGBUS, 0, "unknown 62" },
+ { do_bad, SIGBUS, 0, "section domain fault" },
+ { do_bad, SIGBUS, 0, "page domain fault" },
{ do_bad, SIGBUS, 0, "unknown 63" },
};
diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c
index c26b804..46649d6 100644
--- a/arch/arm64/mm/flush.c
+++ b/arch/arm64/mm/flush.c
@@ -34,19 +34,24 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
__flush_icache_all();
}
+static void sync_icache_aliases(void *kaddr, unsigned long len)
+{
+ unsigned long addr = (unsigned long)kaddr;
+
+ if (icache_is_aliasing()) {
+ __clean_dcache_area_pou(kaddr, len);
+ __flush_icache_all();
+ } else {
+ flush_icache_range(addr, addr + len);
+ }
+}
+
static void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
unsigned long uaddr, void *kaddr,
unsigned long len)
{
- if (vma->vm_flags & VM_EXEC) {
- unsigned long addr = (unsigned long)kaddr;
- if (icache_is_aliasing()) {
- __flush_dcache_area(kaddr, len);
- __flush_icache_all();
- } else {
- flush_icache_range(addr, addr + len);
- }
- }
+ if (vma->vm_flags & VM_EXEC)
+ sync_icache_aliases(kaddr, len);
}
/*
@@ -74,13 +79,11 @@ void __sync_icache_dcache(pte_t pte, unsigned long addr)
if (!page_mapping(page))
return;
- if (!test_and_set_bit(PG_dcache_clean, &page->flags)) {
- __flush_dcache_area(page_address(page),
- PAGE_SIZE << compound_order(page));
+ if (!test_and_set_bit(PG_dcache_clean, &page->flags))
+ sync_icache_aliases(page_address(page),
+ PAGE_SIZE << compound_order(page));
+ else if (icache_is_aivivt())
__flush_icache_all();
- } else if (icache_is_aivivt()) {
- __flush_icache_all();
- }
}
/*
diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c
index 383b03f..82d607c 100644
--- a/arch/arm64/mm/hugetlbpage.c
+++ b/arch/arm64/mm/hugetlbpage.c
@@ -41,17 +41,289 @@ int pud_huge(pud_t pud)
#endif
}
+static int find_num_contig(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, size_t *pgsize)
+{
+ pgd_t *pgd = pgd_offset(mm, addr);
+ pud_t *pud;
+ pmd_t *pmd;
+
+ *pgsize = PAGE_SIZE;
+ if (!pte_cont(pte))
+ return 1;
+ if (!pgd_present(*pgd)) {
+ VM_BUG_ON(!pgd_present(*pgd));
+ return 1;
+ }
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud)) {
+ VM_BUG_ON(!pud_present(*pud));
+ return 1;
+ }
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd)) {
+ VM_BUG_ON(!pmd_present(*pmd));
+ return 1;
+ }
+ if ((pte_t *)pmd == ptep) {
+ *pgsize = PMD_SIZE;
+ return CONT_PMDS;
+ }
+ return CONT_PTES;
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte)
+{
+ size_t pgsize;
+ int i;
+ int ncontig = find_num_contig(mm, addr, ptep, pte, &pgsize);
+ unsigned long pfn;
+ pgprot_t hugeprot;
+
+ if (ncontig == 1) {
+ set_pte_at(mm, addr, ptep, pte);
+ return;
+ }
+
+ pfn = pte_pfn(pte);
+ hugeprot = __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^ pte_val(pte));
+ for (i = 0; i < ncontig; i++) {
+ pr_debug("%s: set pte %p to 0x%llx\n", __func__, ptep,
+ pte_val(pfn_pte(pfn, hugeprot)));
+ set_pte_at(mm, addr, ptep, pfn_pte(pfn, hugeprot));
+ ptep++;
+ pfn += pgsize >> PAGE_SHIFT;
+ addr += pgsize;
+ }
+}
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pte_t *pte = NULL;
+
+ pr_debug("%s: addr:0x%lx sz:0x%lx\n", __func__, addr, sz);
+ pgd = pgd_offset(mm, addr);
+ pud = pud_alloc(mm, pgd, addr);
+ if (!pud)
+ return NULL;
+
+ if (sz == PUD_SIZE) {
+ pte = (pte_t *)pud;
+ } else if (sz == (PAGE_SIZE * CONT_PTES)) {
+ pmd_t *pmd = pmd_alloc(mm, pud, addr);
+
+ WARN_ON(addr & (sz - 1));
+ /*
+ * Note that if this code were ever ported to the
+ * 32-bit arm platform then it will cause trouble in
+ * the case where CONFIG_HIGHPTE is set, since there
+ * will be no pte_unmap() to correspond with this
+ * pte_alloc_map().
+ */
+ pte = pte_alloc_map(mm, NULL, pmd, addr);
+ } else if (sz == PMD_SIZE) {
+ if (IS_ENABLED(CONFIG_ARCH_WANT_HUGE_PMD_SHARE) &&
+ pud_none(*pud))
+ pte = huge_pmd_share(mm, addr, pud);
+ else
+ pte = (pte_t *)pmd_alloc(mm, pud, addr);
+ } else if (sz == (PMD_SIZE * CONT_PMDS)) {
+ pmd_t *pmd;
+
+ pmd = pmd_alloc(mm, pud, addr);
+ WARN_ON(addr & (sz - 1));
+ return (pte_t *)pmd;
+ }
+
+ pr_debug("%s: addr:0x%lx sz:0x%lx ret pte=%p/0x%llx\n", __func__, addr,
+ sz, pte, pte_val(*pte));
+ return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd = NULL;
+ pte_t *pte = NULL;
+
+ pgd = pgd_offset(mm, addr);
+ pr_debug("%s: addr:0x%lx pgd:%p\n", __func__, addr, pgd);
+ if (!pgd_present(*pgd))
+ return NULL;
+ pud = pud_offset(pgd, addr);
+ if (!pud_present(*pud))
+ return NULL;
+
+ if (pud_huge(*pud))
+ return (pte_t *)pud;
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_present(*pmd))
+ return NULL;
+
+ if (pte_cont(pmd_pte(*pmd))) {
+ pmd = pmd_offset(
+ pud, (addr & CONT_PMD_MASK));
+ return (pte_t *)pmd;
+ }
+ if (pmd_huge(*pmd))
+ return (pte_t *)pmd;
+ pte = pte_offset_kernel(pmd, addr);
+ if (pte_present(*pte) && pte_cont(*pte)) {
+ pte = pte_offset_kernel(
+ pmd, (addr & CONT_PTE_MASK));
+ return pte;
+ }
+ return NULL;
+}
+
+pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+ struct page *page, int writable)
+{
+ size_t pagesize = huge_page_size(hstate_vma(vma));
+
+ if (pagesize == CONT_PTE_SIZE) {
+ entry = pte_mkcont(entry);
+ } else if (pagesize == CONT_PMD_SIZE) {
+ entry = pmd_pte(pmd_mkcont(pte_pmd(entry)));
+ } else if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) {
+ pr_warn("%s: unrecognized huge page size 0x%lx\n",
+ __func__, pagesize);
+ }
+ return entry;
+}
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t pte;
+
+ if (pte_cont(*ptep)) {
+ int ncontig, i;
+ size_t pgsize;
+ pte_t *cpte;
+ bool is_dirty = false;
+
+ cpte = huge_pte_offset(mm, addr);
+ ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+ /* save the 1st pte to return */
+ pte = ptep_get_and_clear(mm, addr, cpte);
+ for (i = 1; i < ncontig; ++i) {
+ /*
+ * If HW_AFDBM is enabled, then the HW could
+ * turn on the dirty bit for any of the page
+ * in the set, so check them all.
+ */
+ ++cpte;
+ if (pte_dirty(ptep_get_and_clear(mm, addr, cpte)))
+ is_dirty = true;
+ }
+ if (is_dirty)
+ return pte_mkdirty(pte);
+ else
+ return pte;
+ } else {
+ return ptep_get_and_clear(mm, addr, ptep);
+ }
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ pte_t *cpte;
+
+ if (pte_cont(pte)) {
+ int ncontig, i, changed = 0;
+ size_t pgsize = 0;
+ unsigned long pfn = pte_pfn(pte);
+ /* Select all bits except the pfn */
+ pgprot_t hugeprot =
+ __pgprot(pte_val(pfn_pte(pfn, __pgprot(0))) ^
+ pte_val(pte));
+
+ cpte = huge_pte_offset(vma->vm_mm, addr);
+ pfn = pte_pfn(*cpte);
+ ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+ *cpte, &pgsize);
+ for (i = 0; i < ncontig; ++i, ++cpte) {
+ changed = ptep_set_access_flags(vma, addr, cpte,
+ pfn_pte(pfn,
+ hugeprot),
+ dirty);
+ pfn += pgsize >> PAGE_SHIFT;
+ }
+ return changed;
+ } else {
+ return ptep_set_access_flags(vma, addr, ptep, pte, dirty);
+ }
+}
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ if (pte_cont(*ptep)) {
+ int ncontig, i;
+ pte_t *cpte;
+ size_t pgsize = 0;
+
+ cpte = huge_pte_offset(mm, addr);
+ ncontig = find_num_contig(mm, addr, cpte, *cpte, &pgsize);
+ for (i = 0; i < ncontig; ++i, ++cpte)
+ ptep_set_wrprotect(mm, addr, cpte);
+ } else {
+ ptep_set_wrprotect(mm, addr, ptep);
+ }
+}
+
+void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ if (pte_cont(*ptep)) {
+ int ncontig, i;
+ pte_t *cpte;
+ size_t pgsize = 0;
+
+ cpte = huge_pte_offset(vma->vm_mm, addr);
+ ncontig = find_num_contig(vma->vm_mm, addr, cpte,
+ *cpte, &pgsize);
+ for (i = 0; i < ncontig; ++i, ++cpte)
+ ptep_clear_flush(vma, addr, cpte);
+ } else {
+ ptep_clear_flush(vma, addr, ptep);
+ }
+}
+
static __init int setup_hugepagesz(char *opt)
{
unsigned long ps = memparse(opt, &opt);
+
if (ps == PMD_SIZE) {
hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
} else if (ps == PUD_SIZE) {
hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+ } else if (ps == (PAGE_SIZE * CONT_PTES)) {
+ hugetlb_add_hstate(CONT_PTE_SHIFT);
+ } else if (ps == (PMD_SIZE * CONT_PMDS)) {
+ hugetlb_add_hstate((PMD_SHIFT + CONT_PMD_SHIFT) - PAGE_SHIFT);
} else {
- pr_err("hugepagesz: Unsupported page size %lu M\n", ps >> 20);
+ pr_err("hugepagesz: Unsupported page size %lu K\n", ps >> 10);
return 0;
}
return 1;
}
__setup("hugepagesz=", setup_hugepagesz);
+
+#ifdef CONFIG_ARM64_64K_PAGES
+static __init int add_default_hugepagesz(void)
+{
+ if (size_to_hstate(CONT_PTES * PAGE_SIZE) == NULL)
+ hugetlb_add_hstate(CONT_PMD_SHIFT);
+ return 0;
+}
+arch_initcall(add_default_hugepagesz);
+#endif
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 17bf39a..f3b061e 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -71,7 +71,7 @@ early_param("initrd", early_initrd);
* currently assumes that for memory starting above 4G, 32-bit devices will
* use a DMA offset.
*/
-static phys_addr_t max_zone_dma_phys(void)
+static phys_addr_t __init max_zone_dma_phys(void)
{
phys_addr_t offset = memblock_start_of_DRAM() & GENMASK_ULL(63, 32);
return min(offset + (1ULL << 32), memblock_end_of_DRAM());
@@ -120,17 +120,17 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max)
#ifdef CONFIG_HAVE_ARCH_PFN_VALID
int pfn_valid(unsigned long pfn)
{
- return memblock_is_memory(pfn << PAGE_SHIFT);
+ return memblock_is_map_memory(pfn << PAGE_SHIFT);
}
EXPORT_SYMBOL(pfn_valid);
#endif
#ifndef CONFIG_SPARSEMEM
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
{
}
#else
-static void arm64_memory_present(void)
+static void __init arm64_memory_present(void)
{
struct memblock_region *reg;
@@ -360,7 +360,6 @@ void free_initmem(void)
{
fixup_init();
free_initmem_default(0);
- free_alternatives_memory();
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index c2fa6b5..58faeaa 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -64,8 +64,12 @@ EXPORT_SYMBOL(phys_mem_access_prot);
static void __init *early_alloc(unsigned long sz)
{
- void *ptr = __va(memblock_alloc(sz, sz));
- BUG_ON(!ptr);
+ phys_addr_t phys;
+ void *ptr;
+
+ phys = memblock_alloc(sz, sz);
+ BUG_ON(!phys);
+ ptr = __va(phys);
memset(ptr, 0, sz);
return ptr;
}
@@ -81,55 +85,19 @@ static void split_pmd(pmd_t *pmd, pte_t *pte)
do {
/*
* Need to have the least restrictive permissions available
- * permissions will be fixed up later. Default the new page
- * range as contiguous ptes.
+ * permissions will be fixed up later
*/
- set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC_CONT));
+ set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC));
pfn++;
} while (pte++, i++, i < PTRS_PER_PTE);
}
-/*
- * Given a PTE with the CONT bit set, determine where the CONT range
- * starts, and clear the entire range of PTE CONT bits.
- */
-static void clear_cont_pte_range(pte_t *pte, unsigned long addr)
-{
- int i;
-
- pte -= CONT_RANGE_OFFSET(addr);
- for (i = 0; i < CONT_PTES; i++) {
- set_pte(pte, pte_mknoncont(*pte));
- pte++;
- }
- flush_tlb_all();
-}
-
-/*
- * Given a range of PTEs set the pfn and provided page protection flags
- */
-static void __populate_init_pte(pte_t *pte, unsigned long addr,
- unsigned long end, phys_addr_t phys,
- pgprot_t prot)
-{
- unsigned long pfn = __phys_to_pfn(phys);
-
- do {
- /* clear all the bits except the pfn, then apply the prot */
- set_pte(pte, pfn_pte(pfn, prot));
- pte++;
- pfn++;
- addr += PAGE_SIZE;
- } while (addr != end);
-}
-
static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
- unsigned long end, phys_addr_t phys,
+ unsigned long end, unsigned long pfn,
pgprot_t prot,
void *(*alloc)(unsigned long size))
{
pte_t *pte;
- unsigned long next;
if (pmd_none(*pmd) || pmd_sect(*pmd)) {
pte = alloc(PTRS_PER_PTE * sizeof(pte_t));
@@ -142,30 +110,12 @@ static void alloc_init_pte(pmd_t *pmd, unsigned long addr,
pte = pte_offset_kernel(pmd, addr);
do {
- next = min(end, (addr + CONT_SIZE) & CONT_MASK);
- if (((addr | next | phys) & ~CONT_MASK) == 0) {
- /* a block of CONT_PTES */
- __populate_init_pte(pte, addr, next, phys,
- prot | __pgprot(PTE_CONT));
- } else {
- /*
- * If the range being split is already inside of a
- * contiguous range but this PTE isn't going to be
- * contiguous, then we want to unmark the adjacent
- * ranges, then update the portion of the range we
- * are interrested in.
- */
- clear_cont_pte_range(pte, addr);
- __populate_init_pte(pte, addr, next, phys, prot);
- }
-
- pte += (next - addr) >> PAGE_SHIFT;
- phys += next - addr;
- addr = next;
- } while (addr != end);
+ set_pte(pte, pfn_pte(pfn, prot));
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
}
-void split_pud(pud_t *old_pud, pmd_t *pmd)
+static void split_pud(pud_t *old_pud, pmd_t *pmd)
{
unsigned long addr = pud_pfn(*old_pud) << PAGE_SHIFT;
pgprot_t prot = __pgprot(pud_val(*old_pud) ^ addr);
@@ -223,7 +173,8 @@ static void alloc_init_pmd(struct mm_struct *mm, pud_t *pud,
}
}
} else {
- alloc_init_pte(pmd, addr, next, phys, prot, alloc);
+ alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys),
+ prot, alloc);
}
phys += next - addr;
} while (pmd++, addr = next, addr != end);
@@ -300,6 +251,14 @@ static void __create_mapping(struct mm_struct *mm, pgd_t *pgd,
{
unsigned long addr, length, end, next;
+ /*
+ * If the virtual and physical address don't have the same offset
+ * within a page, we cannot map the region as the caller expects.
+ */
+ if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
+ return;
+
+ phys &= PAGE_MASK;
addr = virt & PAGE_MASK;
length = PAGE_ALIGN(size + (virt & ~PAGE_MASK));
@@ -329,7 +288,7 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
&phys, virt);
return;
}
- __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK), phys, virt,
+ __create_mapping(&init_mm, pgd_offset_k(virt), phys, virt,
size, prot, early_alloc);
}
@@ -350,7 +309,7 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
return;
}
- return __create_mapping(&init_mm, pgd_offset_k(virt & PAGE_MASK),
+ return __create_mapping(&init_mm, pgd_offset_k(virt),
phys, virt, size, prot, late_alloc);
}
@@ -362,8 +321,8 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end)
* for now. This will get more fine grained later once all memory
* is mapped
*/
- unsigned long kernel_x_start = round_down(__pa(_stext), SECTION_SIZE);
- unsigned long kernel_x_end = round_up(__pa(__init_end), SECTION_SIZE);
+ unsigned long kernel_x_start = round_down(__pa(_stext), SWAPPER_BLOCK_SIZE);
+ unsigned long kernel_x_end = round_up(__pa(__init_end), SWAPPER_BLOCK_SIZE);
if (end < kernel_x_start) {
create_mapping(start, __phys_to_virt(start),
@@ -421,6 +380,8 @@ static void __init map_mem(void)
if (start >= end)
break;
+ if (memblock_is_nomap(reg))
+ continue;
if (ARM64_SWAPPER_USES_SECTION_MAPS) {
/*
@@ -447,22 +408,22 @@ static void __init map_mem(void)
memblock_set_current_limit(MEMBLOCK_ALLOC_ANYWHERE);
}
-void __init fixup_executable(void)
+static void __init fixup_executable(void)
{
#ifdef CONFIG_DEBUG_RODATA
/* now that we are actually fully mapped, make the start/end more fine grained */
- if (!IS_ALIGNED((unsigned long)_stext, SECTION_SIZE)) {
+ if (!IS_ALIGNED((unsigned long)_stext, SWAPPER_BLOCK_SIZE)) {
unsigned long aligned_start = round_down(__pa(_stext),
- SECTION_SIZE);
+ SWAPPER_BLOCK_SIZE);
create_mapping(aligned_start, __phys_to_virt(aligned_start),
__pa(_stext) - aligned_start,
PAGE_KERNEL);
}
- if (!IS_ALIGNED((unsigned long)__init_end, SECTION_SIZE)) {
+ if (!IS_ALIGNED((unsigned long)__init_end, SWAPPER_BLOCK_SIZE)) {
unsigned long aligned_end = round_up(__pa(__init_end),
- SECTION_SIZE);
+ SWAPPER_BLOCK_SIZE);
create_mapping(__pa(__init_end), (unsigned long)__init_end,
aligned_end - __pa(__init_end),
PAGE_KERNEL);
@@ -475,7 +436,7 @@ void mark_rodata_ro(void)
{
create_mapping_late(__pa(_stext), (unsigned long)_stext,
(unsigned long)_etext - (unsigned long)_stext,
- PAGE_KERNEL_EXEC | PTE_RDONLY);
+ PAGE_KERNEL_ROX);
}
#endif
@@ -505,6 +466,9 @@ void __init paging_init(void)
empty_zero_page = virt_to_page(zero_page);
+ /* Ensure the zero page is visible to the page table walker */
+ dsb(ishst);
+
/*
* TTBR0 is only used for the identity mapping at this stage. Make it
* point to zero page to avoid speculatively fetching new entries.
@@ -691,7 +655,7 @@ void __set_fixmap(enum fixed_addresses idx,
void *__init fixmap_remap_fdt(phys_addr_t dt_phys)
{
const u64 dt_virt_base = __fix_to_virt(FIX_FDT);
- pgprot_t prot = PAGE_KERNEL | PTE_RDONLY;
+ pgprot_t prot = PAGE_KERNEL_RO;
int size, offset;
void *dt_virt;
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
index cb3ba1b..ae11d4e 100644
--- a/arch/arm64/mm/pgd.c
+++ b/arch/arm64/mm/pgd.c
@@ -46,14 +46,14 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd)
kmem_cache_free(pgd_cache, pgd);
}
-static int __init pgd_cache_init(void)
+void __init pgd_cache_init(void)
{
+ if (PGD_SIZE == PAGE_SIZE)
+ return;
+
/*
* Naturally aligned pgds required by the architecture.
*/
- if (PGD_SIZE != PAGE_SIZE)
- pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
- SLAB_PANIC, NULL);
- return 0;
+ pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
+ SLAB_PANIC, NULL);
}
-core_initcall(pgd_cache_init);
diff --git a/arch/arm64/mm/proc-macros.S b/arch/arm64/mm/proc-macros.S
index 4c4d93c..146bd99 100644
--- a/arch/arm64/mm/proc-macros.S
+++ b/arch/arm64/mm/proc-macros.S
@@ -62,3 +62,25 @@
bfi \valreg, \tmpreg, #TCR_T0SZ_OFFSET, #TCR_TxSZ_WIDTH
#endif
.endm
+
+/*
+ * Macro to perform a data cache maintenance for the interval
+ * [kaddr, kaddr + size)
+ *
+ * op: operation passed to dc instruction
+ * domain: domain used in dsb instruciton
+ * kaddr: starting virtual address of the region
+ * size: size of the region
+ * Corrupts: kaddr, size, tmp1, tmp2
+ */
+ .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+ dcache_line_size \tmp1, \tmp2
+ add \size, \kaddr, \size
+ sub \tmp2, \tmp1, #1
+ bic \kaddr, \kaddr, \tmp2
+9998: dc \op, \kaddr
+ add \kaddr, \kaddr, \tmp1
+ cmp \kaddr, \size
+ b.lo 9998b
+ dsb \domain
+ .endm
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index cacecc4..a3d867e 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -117,6 +117,7 @@ ENTRY(cpu_do_resume)
*/
ubfx x11, x11, #1, #1
msr oslar_el1, x11
+ msr pmuserenr_el0, xzr // Disable PMU access from EL0
mov x0, x12
dsb nsh // Make sure local tlb invalidation completed
isb
@@ -139,8 +140,6 @@ ENTRY(cpu_do_switch_mm)
ret
ENDPROC(cpu_do_switch_mm)
- .section ".text.init", #alloc, #execinstr
-
/*
* __cpu_setup
*
@@ -155,6 +154,7 @@ ENTRY(__cpu_setup)
msr cpacr_el1, x0 // Enable FP/ASIMD
mov x0, #1 << 12 // Reset mdscr_el1 and disable
msr mdscr_el1, x0 // access to the DCC from EL0
+ msr pmuserenr_el0, xzr // Disable PMU access from EL0
/*
* Memory region attributes for LPAE:
*
diff --git a/arch/arm64/net/bpf_jit.h b/arch/arm64/net/bpf_jit.h
index 98a26ce..aee5637 100644
--- a/arch/arm64/net/bpf_jit.h
+++ b/arch/arm64/net/bpf_jit.h
@@ -1,7 +1,7 @@
/*
* BPF JIT compiler for ARM64
*
- * Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com>
+ * Copyright (C) 2014-2015 Zi Shen Lim <zlim.lnx@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -35,6 +35,7 @@
aarch64_insn_gen_comp_branch_imm(0, offset, Rt, A64_VARIANT(sf), \
AARCH64_INSN_BRANCH_COMP_##type)
#define A64_CBZ(sf, Rt, imm19) A64_COMP_BRANCH(sf, Rt, (imm19) << 2, ZERO)
+#define A64_CBNZ(sf, Rt, imm19) A64_COMP_BRANCH(sf, Rt, (imm19) << 2, NONZERO)
/* Conditional branch (immediate) */
#define A64_COND_BRANCH(cond, offset) \
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index a44e529..b162ad7 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -1,7 +1,7 @@
/*
* BPF JIT compiler for ARM64
*
- * Copyright (C) 2014 Zi Shen Lim <zlim.lnx@gmail.com>
+ * Copyright (C) 2014-2015 Zi Shen Lim <zlim.lnx@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -50,7 +50,7 @@ static const int bpf2a64[] = {
[BPF_REG_8] = A64_R(21),
[BPF_REG_9] = A64_R(22),
/* read-only frame pointer to access stack */
- [BPF_REG_FP] = A64_FP,
+ [BPF_REG_FP] = A64_R(25),
/* temporary register for internal BPF JIT */
[TMP_REG_1] = A64_R(23),
[TMP_REG_2] = A64_R(24),
@@ -139,6 +139,12 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
/* Stack must be multiples of 16B */
#define STACK_ALIGN(sz) (((sz) + 15) & ~15)
+#define _STACK_SIZE \
+ (MAX_BPF_STACK \
+ + 4 /* extra for skb_copy_bits buffer */)
+
+#define STACK_SIZE STACK_ALIGN(_STACK_SIZE)
+
static void build_prologue(struct jit_ctx *ctx)
{
const u8 r6 = bpf2a64[BPF_REG_6];
@@ -150,10 +156,35 @@ static void build_prologue(struct jit_ctx *ctx)
const u8 rx = bpf2a64[BPF_REG_X];
const u8 tmp1 = bpf2a64[TMP_REG_1];
const u8 tmp2 = bpf2a64[TMP_REG_2];
- int stack_size = MAX_BPF_STACK;
- stack_size += 4; /* extra for skb_copy_bits buffer */
- stack_size = STACK_ALIGN(stack_size);
+ /*
+ * BPF prog stack layout
+ *
+ * high
+ * original A64_SP => 0:+-----+ BPF prologue
+ * |FP/LR|
+ * current A64_FP => -16:+-----+
+ * | ... | callee saved registers
+ * +-----+
+ * | | x25/x26
+ * BPF fp register => -80:+-----+ <= (BPF_FP)
+ * | |
+ * | ... | BPF prog stack
+ * | |
+ * +-----+ <= (BPF_FP - MAX_BPF_STACK)
+ * |RSVD | JIT scratchpad
+ * current A64_SP => +-----+ <= (BPF_FP - STACK_SIZE)
+ * | |
+ * | ... | Function call stack
+ * | |
+ * +-----+
+ * low
+ *
+ */
+
+ /* Save FP and LR registers to stay align with ARM64 AAPCS */
+ emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
+ emit(A64_MOV(1, A64_FP, A64_SP), ctx);
/* Save callee-saved register */
emit(A64_PUSH(r6, r7, A64_SP), ctx);
@@ -161,12 +192,15 @@ static void build_prologue(struct jit_ctx *ctx)
if (ctx->tmp_used)
emit(A64_PUSH(tmp1, tmp2, A64_SP), ctx);
- /* Set up BPF stack */
- emit(A64_SUB_I(1, A64_SP, A64_SP, stack_size), ctx);
+ /* Save fp (x25) and x26. SP requires 16 bytes alignment */
+ emit(A64_PUSH(fp, A64_R(26), A64_SP), ctx);
- /* Set up frame pointer */
+ /* Set up BPF prog stack base register (x25) */
emit(A64_MOV(1, fp, A64_SP), ctx);
+ /* Set up function call stack */
+ emit(A64_SUB_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
+
/* Clear registers A and X */
emit_a64_mov_i64(ra, 0, ctx);
emit_a64_mov_i64(rx, 0, ctx);
@@ -182,13 +216,12 @@ static void build_epilogue(struct jit_ctx *ctx)
const u8 fp = bpf2a64[BPF_REG_FP];
const u8 tmp1 = bpf2a64[TMP_REG_1];
const u8 tmp2 = bpf2a64[TMP_REG_2];
- int stack_size = MAX_BPF_STACK;
-
- stack_size += 4; /* extra for skb_copy_bits buffer */
- stack_size = STACK_ALIGN(stack_size);
/* We're done with BPF stack */
- emit(A64_ADD_I(1, A64_SP, A64_SP, stack_size), ctx);
+ emit(A64_ADD_I(1, A64_SP, A64_SP, STACK_SIZE), ctx);
+
+ /* Restore fs (x25) and x26 */
+ emit(A64_POP(fp, A64_R(26), A64_SP), ctx);
/* Restore callee-saved register */
if (ctx->tmp_used)
@@ -196,8 +229,8 @@ static void build_epilogue(struct jit_ctx *ctx)
emit(A64_POP(r8, r9, A64_SP), ctx);
emit(A64_POP(r6, r7, A64_SP), ctx);
- /* Restore frame pointer */
- emit(A64_MOV(1, fp, A64_SP), ctx);
+ /* Restore FP/LR registers */
+ emit(A64_POP(A64_FP, A64_LR, A64_SP), ctx);
/* Set return value */
emit(A64_MOV(1, A64_R(0), r0), ctx);
@@ -225,6 +258,17 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
u8 jmp_cond;
s32 jmp_offset;
+#define check_imm(bits, imm) do { \
+ if ((((imm) > 0) && ((imm) >> (bits))) || \
+ (((imm) < 0) && (~(imm) >> (bits)))) { \
+ pr_info("[%2d] imm=%d(0x%x) out of range\n", \
+ i, imm, imm); \
+ return -EINVAL; \
+ } \
+} while (0)
+#define check_imm19(imm) check_imm(19, imm)
+#define check_imm26(imm) check_imm(26, imm)
+
switch (code) {
/* dst = src */
case BPF_ALU | BPF_MOV | BPF_X:
@@ -258,15 +302,33 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
break;
case BPF_ALU | BPF_DIV | BPF_X:
case BPF_ALU64 | BPF_DIV | BPF_X:
- emit(A64_UDIV(is64, dst, dst, src), ctx);
- break;
case BPF_ALU | BPF_MOD | BPF_X:
case BPF_ALU64 | BPF_MOD | BPF_X:
- ctx->tmp_used = 1;
- emit(A64_UDIV(is64, tmp, dst, src), ctx);
- emit(A64_MUL(is64, tmp, tmp, src), ctx);
- emit(A64_SUB(is64, dst, dst, tmp), ctx);
+ {
+ const u8 r0 = bpf2a64[BPF_REG_0];
+
+ /* if (src == 0) return 0 */
+ jmp_offset = 3; /* skip ahead to else path */
+ check_imm19(jmp_offset);
+ emit(A64_CBNZ(is64, src, jmp_offset), ctx);
+ emit(A64_MOVZ(1, r0, 0, 0), ctx);
+ jmp_offset = epilogue_offset(ctx);
+ check_imm26(jmp_offset);
+ emit(A64_B(jmp_offset), ctx);
+ /* else */
+ switch (BPF_OP(code)) {
+ case BPF_DIV:
+ emit(A64_UDIV(is64, dst, dst, src), ctx);
+ break;
+ case BPF_MOD:
+ ctx->tmp_used = 1;
+ emit(A64_UDIV(is64, tmp, dst, src), ctx);
+ emit(A64_MUL(is64, tmp, tmp, src), ctx);
+ emit(A64_SUB(is64, dst, dst, tmp), ctx);
+ break;
+ }
break;
+ }
case BPF_ALU | BPF_LSH | BPF_X:
case BPF_ALU64 | BPF_LSH | BPF_X:
emit(A64_LSLV(is64, dst, dst, src), ctx);
@@ -393,17 +455,6 @@ emit_bswap_uxt:
emit(A64_ASR(is64, dst, dst, imm), ctx);
break;
-#define check_imm(bits, imm) do { \
- if ((((imm) > 0) && ((imm) >> (bits))) || \
- (((imm) < 0) && (~(imm) >> (bits)))) { \
- pr_info("[%2d] imm=%d(0x%x) out of range\n", \
- i, imm, imm); \
- return -EINVAL; \
- } \
-} while (0)
-#define check_imm19(imm) check_imm(19, imm)
-#define check_imm26(imm) check_imm(26, imm)
-
/* JUMP off */
case BPF_JMP | BPF_JA:
jmp_offset = bpf2a64_offset(i + off, i, ctx);
@@ -539,7 +590,25 @@ emit_cond_jmp:
case BPF_ST | BPF_MEM | BPF_H:
case BPF_ST | BPF_MEM | BPF_B:
case BPF_ST | BPF_MEM | BPF_DW:
- goto notyet;
+ /* Load imm to a register then store it */
+ ctx->tmp_used = 1;
+ emit_a64_mov_i(1, tmp2, off, ctx);
+ emit_a64_mov_i(1, tmp, imm, ctx);
+ switch (BPF_SIZE(code)) {
+ case BPF_W:
+ emit(A64_STR32(tmp, dst, tmp2), ctx);
+ break;
+ case BPF_H:
+ emit(A64_STRH(tmp, dst, tmp2), ctx);
+ break;
+ case BPF_B:
+ emit(A64_STRB(tmp, dst, tmp2), ctx);
+ break;
+ case BPF_DW:
+ emit(A64_STR64(tmp, dst, tmp2), ctx);
+ break;
+ }
+ break;
/* STX: *(size *)(dst + off) = src */
case BPF_STX | BPF_MEM | BPF_W:
@@ -606,7 +675,7 @@ emit_cond_jmp:
return -EINVAL;
}
emit_a64_mov_i64(r3, size, ctx);
- emit(A64_ADD_I(1, r4, fp, MAX_BPF_STACK), ctx);
+ emit(A64_SUB_I(1, r4, fp, STACK_SIZE), ctx);
emit_a64_mov_i64(r5, (unsigned long)bpf_load_pointer, ctx);
emit(A64_PUSH(A64_FP, A64_LR, A64_SP), ctx);
emit(A64_MOV(1, A64_FP, A64_SP), ctx);
@@ -740,7 +809,7 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
if (bpf_jit_enable > 1)
bpf_jit_dump(prog->len, image_size, 2, ctx.image);
- bpf_flush_icache(ctx.image, ctx.image + ctx.idx);
+ bpf_flush_icache(header, ctx.image + ctx.idx);
set_memory_ro((unsigned long)header, header->pages);
prog->bpf_func = (void *)ctx.image;
diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S
index 8bbe940..70df80e 100644
--- a/arch/arm64/xen/hypercall.S
+++ b/arch/arm64/xen/hypercall.S
@@ -80,6 +80,7 @@ HYPERCALL2(memory_op);
HYPERCALL2(physdev_op);
HYPERCALL3(vcpu_op);
HYPERCALL1(tmem_op);
+HYPERCALL1(platform_op_raw);
HYPERCALL2(multicall);
ENTRY(privcmd_call)
diff --git a/arch/blackfin/include/asm/cmpxchg.h b/arch/blackfin/include/asm/cmpxchg.h
index c05868c..2539288 100644
--- a/arch/blackfin/include/asm/cmpxchg.h
+++ b/arch/blackfin/include/asm/cmpxchg.h
@@ -128,6 +128,5 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
#endif /* !CONFIG_SMP */
#define xchg(ptr, x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
-#define tas(ptr) ((void)xchg((ptr), 1))
#endif /* __ARCH_BLACKFIN_CMPXCHG__ */
diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h
index 90612a7..12f5d68 100644
--- a/arch/blackfin/include/asm/uaccess.h
+++ b/arch/blackfin/include/asm/uaccess.h
@@ -168,12 +168,6 @@ static inline int bad_user_access_length(void)
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
-#define copy_to_user_ret(to, from, n, retval) ({ if (copy_to_user(to, from, n))\
- return retval; })
-
-#define copy_from_user_ret(to, from, n, retval) ({ if (copy_from_user(to, from, n))\
- return retval; })
-
static inline unsigned long __must_check
copy_from_user(void *to, const void __user *from, unsigned long n)
{
diff --git a/arch/blackfin/kernel/perf_event.c b/arch/blackfin/kernel/perf_event.c
index 1e9c8b0..170d786 100644
--- a/arch/blackfin/kernel/perf_event.c
+++ b/arch/blackfin/kernel/perf_event.c
@@ -14,7 +14,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
* Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
*
* ppc:
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index 2de71e8..f35525b 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -443,7 +443,7 @@ static const struct ppi_info ppi_info = {
};
#if IS_ENABLED(CONFIG_VIDEO_ADV7183)
-#include <media/adv7183.h>
+#include <media/i2c/adv7183.h>
static struct v4l2_input adv7183_inputs[] = {
{
.index = 0,
diff --git a/arch/blackfin/mach-bf609/boards/ezkit.c b/arch/blackfin/mach-bf609/boards/ezkit.c
index 2c61fc0..c7928d8 100644
--- a/arch/blackfin/mach-bf609/boards/ezkit.c
+++ b/arch/blackfin/mach-bf609/boards/ezkit.c
@@ -933,7 +933,7 @@ static struct bfin_capture_config bfin_capture_data = {
#endif
#if IS_ENABLED(CONFIG_VIDEO_ADV7842)
-#include <media/adv7842.h>
+#include <media/i2c/adv7842.h>
static struct v4l2_input adv7842_inputs[] = {
{
@@ -1084,7 +1084,7 @@ static const struct ppi_info ppi_info = {
};
#if IS_ENABLED(CONFIG_VIDEO_ADV7511)
-#include <media/adv7511.h>
+#include <media/i2c/adv7511.h>
static struct v4l2_output adv7511_outputs[] = {
{
@@ -1125,7 +1125,7 @@ static struct bfin_display_config bfin_display_data = {
#endif
#if IS_ENABLED(CONFIG_VIDEO_ADV7343)
-#include <media/adv7343.h>
+#include <media/i2c/adv7343.h>
static struct v4l2_output adv7343_outputs[] = {
{
diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
index 945544e..64465e7 100644
--- a/arch/c6x/include/asm/Kbuild
+++ b/arch/c6x/include/asm/Kbuild
@@ -4,6 +4,7 @@ generic-y += auxvec.h
generic-y += barrier.h
generic-y += bitsperlong.h
generic-y += bugs.h
+generic-y += clkdev.h
generic-y += cputime.h
generic-y += current.h
generic-y += device.h
diff --git a/arch/c6x/include/asm/clkdev.h b/arch/c6x/include/asm/clkdev.h
deleted file mode 100644
index 76a070b..0000000
--- a/arch/c6x/include/asm/clkdev.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _ASM_CLKDEV_H
-#define _ASM_CLKDEV_H
-
-#include <linux/slab.h>
-
-struct clk;
-
-static inline int __clk_get(struct clk *clk)
-{
- return 1;
-}
-
-static inline void __clk_put(struct clk *clk)
-{
-}
-
-static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
-{
- return kzalloc(size, GFP_KERNEL);
-}
-
-#endif /* _ASM_CLKDEV_H */
diff --git a/arch/c6x/include/asm/cmpxchg.h b/arch/c6x/include/asm/cmpxchg.h
index b27c8ce..93d0a5a 100644
--- a/arch/c6x/include/asm/cmpxchg.h
+++ b/arch/c6x/include/asm/cmpxchg.h
@@ -47,8 +47,6 @@ static inline unsigned int __xchg(unsigned int x, volatile void *ptr, int size)
#define xchg(ptr, x) \
((__typeof__(*(ptr)))__xchg((unsigned int)(x), (void *) (ptr), \
sizeof(*(ptr))))
-#define tas(ptr) xchg((ptr), 1)
-
#include <asm-generic/cmpxchg-local.h>
diff --git a/arch/frv/include/asm/cmpxchg.h b/arch/frv/include/asm/cmpxchg.h
index 5b04dd0..a899765 100644
--- a/arch/frv/include/asm/cmpxchg.h
+++ b/arch/frv/include/asm/cmpxchg.h
@@ -69,8 +69,6 @@ extern uint32_t __xchg_32(uint32_t i, volatile void *v);
#endif
-#define tas(ptr) (xchg((ptr), 1))
-
/*****************************************************************************/
/*
* compare and conditionally exchange value with memory
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index db58916..2e20333 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -16,6 +16,8 @@ config H8300
select OF_EARLY_FLATTREE
select HAVE_MEMBLOCK
select HAVE_DMA_ATTRS
+ select CLKSRC_OF
+ select H8300_TMR8
config RWSEM_GENERIC_SPINLOCK
def_bool y
diff --git a/arch/h8300/Makefile b/arch/h8300/Makefile
index 0d2d96e..e1c02ca 100644
--- a/arch/h8300/Makefile
+++ b/arch/h8300/Makefile
@@ -22,7 +22,9 @@ KBUILD_CFLAGS += -DUTS_SYSNAME=\"uClinux\"
KBUILD_AFLAGS += $(aflags-y)
LDFLAGS += $(ldflags-y)
+ifeq ($(CROSS_COMPILE),)
CROSS_COMPILE := h8300-unknown-linux-
+endif
core-y += arch/$(ARCH)/kernel/ arch/$(ARCH)/mm/
ifneq '$(CONFIG_H8300_BUILTIN_DTB)' '""'
diff --git a/arch/h8300/boot/compressed/Makefile b/arch/h8300/boot/compressed/Makefile
index 87d03b7..d7bc3fa 100644
--- a/arch/h8300/boot/compressed/Makefile
+++ b/arch/h8300/boot/compressed/Makefile
@@ -14,11 +14,12 @@ OBJECTS = $(obj)/head.o $(obj)/misc.o
# in order to suppress error message.
#
CONFIG_MEMORY_START ?= 0x00400000
-CONFIG_BOOT_LINK_OFFSET ?= 0x00140000
+CONFIG_BOOT_LINK_OFFSET ?= 0x00280000
IMAGE_OFFSET := $(shell printf "0x%08x" $$(($(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET))))
LIBGCC := $(shell $(CROSS-COMPILE)$(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
-LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup $(obj)/vmlinux.lds
+LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -estartup -T $(obj)/vmlinux.lds \
+ --defsym output=$(CONFIG_MEMORY_START)
$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
$(call if_changed,ld)
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
index 74c0d8cc..0436350 100644
--- a/arch/h8300/boot/compressed/head.S
+++ b/arch/h8300/boot/compressed/head.S
@@ -9,8 +9,8 @@
.section .text..startup,"ax"
.global startup
startup:
+ mov.l #startup, sp
mov.l er0, er4
- mov.l er0, sp
mov.l #__sbss, er0
mov.l #__ebss, er1
sub.l er0, er1
@@ -24,7 +24,7 @@ startup:
bne 1b
jsr @decompress_kernel
mov.l er4, er0
- jmp @0x400000
+ jmp @output
.align 9
fake_headers_as_bzImage:
diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c
index c4f2cfc..6029c53 100644
--- a/arch/h8300/boot/compressed/misc.c
+++ b/arch/h8300/boot/compressed/misc.c
@@ -28,7 +28,7 @@ static unsigned long free_mem_end_ptr;
extern char input_data[];
extern int input_len;
-static unsigned char *output;
+extern char output[];
#define HEAP_SIZE 0x10000
@@ -56,15 +56,10 @@ void *memcpy(void *dest, const void *src, size_t n)
static void error(char *x)
{
-
while (1)
; /* Halt */
}
-#define STACK_SIZE (4096)
-long user_stack[STACK_SIZE];
-long *stack_start = &user_stack[STACK_SIZE];
-
void decompress_kernel(void)
{
free_mem_ptr = (unsigned long)&_end;
diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds
index a0a3a0e..44fd209 100644
--- a/arch/h8300/boot/compressed/vmlinux.lds
+++ b/arch/h8300/boot/compressed/vmlinux.lds
@@ -27,6 +27,6 @@ SECTIONS
*(.bss*)
. = ALIGN(0x4) ;
__ebss = . ;
- __end = . ;
}
+ _end = . ;
}
diff --git a/arch/h8300/boot/dts/edosk2674.dts b/arch/h8300/boot/dts/edosk2674.dts
index dfb5c10..4ce9fa8 100644
--- a/arch/h8300/boot/dts/edosk2674.dts
+++ b/arch/h8300/boot/dts/edosk2674.dts
@@ -7,7 +7,7 @@
chosen {
bootargs = "console=ttySC2,38400";
- stdout-path = <&sci2>;
+ stdout-path = &sci2;
};
aliases {
serial0 = &sci0;
@@ -25,13 +25,13 @@
compatible = "renesas,h8s2678-pll-clock";
clocks = <&xclk>;
#clock-cells = <0>;
- reg = <0xfee03b 2>, <0xfee045 2>;
+ reg = <0xffff3b 1>, <0xffff45 1>;
};
core_clk: core_clk {
compatible = "renesas,h8300-div-clock";
clocks = <&pllclk>;
#clock-cells = <0>;
- reg = <0xfee03b 2>;
+ reg = <0xffff3b 1>;
renesas,width = <3>;
};
fclk: fclk {
diff --git a/arch/h8300/include/asm/io.h b/arch/h8300/include/asm/io.h
index 1d09b2f..f0e14f3 100644
--- a/arch/h8300/include/asm/io.h
+++ b/arch/h8300/include/asm/io.h
@@ -3,55 +3,62 @@
#ifdef __KERNEL__
-#include <asm-generic/io.h>
-
/* H8/300 internal I/O functions */
-static inline unsigned char ctrl_inb(unsigned long addr)
+
+#define __raw_readb __raw_readb
+static inline u8 __raw_readb(const volatile void __iomem *addr)
{
- return *(volatile unsigned char *)addr;
+ return *(volatile u8 *)addr;
}
-static inline unsigned short ctrl_inw(unsigned long addr)
+#define __raw_readw __raw_readw
+static inline u16 __raw_readw(const volatile void __iomem *addr)
{
- return *(volatile unsigned short *)addr;
+ return *(volatile u16 *)addr;
}
-static inline unsigned long ctrl_inl(unsigned long addr)
+#define __raw_readl __raw_readl
+static inline u32 __raw_readl(const volatile void __iomem *addr)
{
- return *(volatile unsigned long *)addr;
+ return *(volatile u32 *)addr;
}
-static inline void ctrl_outb(unsigned char b, unsigned long addr)
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 b, const volatile void __iomem *addr)
{
- *(volatile unsigned char *)addr = b;
+ *(volatile u8 *)addr = b;
}
-static inline void ctrl_outw(unsigned short b, unsigned long addr)
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 b, const volatile void __iomem *addr)
{
- *(volatile unsigned short *)addr = b;
+ *(volatile u16 *)addr = b;
}
-static inline void ctrl_outl(unsigned long b, unsigned long addr)
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 b, const volatile void __iomem *addr)
{
- *(volatile unsigned long *)addr = b;
+ *(volatile u32 *)addr = b;
}
-static inline void ctrl_bclr(int b, unsigned long addr)
+static inline void ctrl_bclr(int b, void __iomem *addr)
{
if (__builtin_constant_p(b))
- __asm__("bclr %1,%0" : : "WU"(addr), "i"(b));
+ __asm__("bclr %1,%0" : "+WU"(*addr): "i"(b));
else
- __asm__("bclr %w1,%0" : : "WU"(addr), "r"(b));
+ __asm__("bclr %w1,%0" : "+WU"(*addr): "r"(b));
}
-static inline void ctrl_bset(int b, unsigned long addr)
+static inline void ctrl_bset(int b, void __iomem *addr)
{
if (__builtin_constant_p(b))
- __asm__("bset %1,%0" : : "WU"(addr), "i"(b));
+ __asm__("bset %1,%0" : "+WU"(*addr): "i"(b));
else
- __asm__("bset %w1,%0" : : "WU"(addr), "r"(b));
+ __asm__("bset %w1,%0" : "+WU"(*addr): "r"(b));
}
+#include <asm-generic/io.h>
+
#endif /* __KERNEL__ */
#endif /* _H8300_IO_H */
diff --git a/arch/h8300/include/asm/thread_info.h b/arch/h8300/include/asm/thread_info.h
index 544c307..b408fe6 100644
--- a/arch/h8300/include/asm/thread_info.h
+++ b/arch/h8300/include/asm/thread_info.h
@@ -13,6 +13,12 @@
#ifdef __KERNEL__
+/*
+ * Size of kernel stack for each process. This must be a power of 2...
+ */
+#define THREAD_SIZE_ORDER 1
+#define THREAD_SIZE 8192 /* 2 pages */
+
#ifndef __ASSEMBLY__
/*
@@ -46,14 +52,6 @@ struct thread_info {
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
-
-/*
- * Size of kernel stack for each process. This must be a power of 2...
- */
-#define THREAD_SIZE_ORDER 1
-#define THREAD_SIZE 8192 /* 2 pages */
-
-
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
diff --git a/arch/h8300/kernel/setup.c b/arch/h8300/kernel/setup.c
index 0fd1fe6..e4985df 100644
--- a/arch/h8300/kernel/setup.c
+++ b/arch/h8300/kernel/setup.c
@@ -29,6 +29,7 @@
#include <linux/clk-provider.h>
#include <linux/memblock.h>
#include <linux/screen_info.h>
+#include <linux/clocksource.h>
#include <asm/setup.h>
#include <asm/irq.h>
@@ -206,14 +207,14 @@ device_initcall(device_probe);
#define get_wait(base, addr) ({ \
int baddr; \
baddr = ((addr) / 0x200000 * 2); \
- w *= (ctrl_inw((unsigned long)(base) + 2) & (3 << baddr)) + 1; \
+ w *= (readw((base) + 2) & (3 << baddr)) + 1; \
})
#endif
#if defined(CONFIG_CPU_H8S)
#define get_wait(base, addr) ({ \
int baddr; \
baddr = ((addr) / 0x200000 * 16); \
- w *= (ctrl_inl((unsigned long)(base) + 2) & (7 << baddr)) + 1; \
+ w *= (readl((base) + 2) & (7 << baddr)) + 1; \
})
#endif
@@ -227,8 +228,8 @@ static __init int access_timing(void)
bsc = of_find_compatible_node(NULL, NULL, "renesas,h8300-bsc");
base = of_iomap(bsc, 0);
- w = (ctrl_inb((unsigned long)base + 0) & bit)?2:1;
- if (ctrl_inb((unsigned long)base + 1) & bit)
+ w = (readb(base + 0) & bit)?2:1;
+ if (readb(base + 1) & bit)
w *= get_wait(base, addr);
else
w *= 2;
@@ -252,4 +253,5 @@ void __init calibrate_delay(void)
void __init time_init(void)
{
of_clk_init(NULL);
+ clocksource_probe();
}
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index 7c302dc..cb5dfb0 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -1,5 +1,6 @@
#include <asm-generic/vmlinux.lds.h>
#include <asm/page.h>
+#include <asm/thread_info.h>
#define ROMTOP 0x000000
#define RAMTOP 0x400000
@@ -42,11 +43,10 @@ SECTIONS
. = RAMTOP;
_ramstart = .;
#define ADDR(x) ROMEND
-#else
#endif
_sdata = . ;
__data_start = . ;
- RW_DATA_SECTION(0,0,0)
+ RW_DATA_SECTION(0, PAGE_SIZE, THREAD_SIZE)
#if defined(CONFIG_ROMKERNEL)
#undef ADDR
#endif
diff --git a/arch/ia64/include/asm/barrier.h b/arch/ia64/include/asm/barrier.h
index df896a1..209c4b8 100644
--- a/arch/ia64/include/asm/barrier.h
+++ b/arch/ia64/include/asm/barrier.h
@@ -77,7 +77,7 @@ do { \
___p1; \
})
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
/*
* The group barrier in front of the rsm & ssm are necessary to ensure
diff --git a/arch/ia64/include/asm/percpu.h b/arch/ia64/include/asm/percpu.h
index 0ec484d..b929579 100644
--- a/arch/ia64/include/asm/percpu.h
+++ b/arch/ia64/include/asm/percpu.h
@@ -6,8 +6,6 @@
* David Mosberger-Tang <davidm@hpl.hp.com>
*/
-#define PERCPU_ENOUGH_ROOM PERCPU_PAGE_SIZE
-
#ifdef __ASSEMBLY__
# define THIS_CPU(var) (var) /* use this to mark accesses to per-CPU variables... */
#else /* !__ASSEMBLY__ */
diff --git a/arch/ia64/include/asm/unistd.h b/arch/ia64/include/asm/unistd.h
index db73390..74c132d 100644
--- a/arch/ia64/include/asm/unistd.h
+++ b/arch/ia64/include/asm/unistd.h
@@ -11,7 +11,7 @@
-#define NR_syscalls 322 /* length of syscall table */
+#define NR_syscalls 323 /* length of syscall table */
/*
* The following defines stop scripts/checksyscalls.sh from complaining about
diff --git a/arch/ia64/include/uapi/asm/unistd.h b/arch/ia64/include/uapi/asm/unistd.h
index 9038726..762edce 100644
--- a/arch/ia64/include/uapi/asm/unistd.h
+++ b/arch/ia64/include/uapi/asm/unistd.h
@@ -335,5 +335,6 @@
#define __NR_userfaultfd 1343
#define __NR_membarrier 1344
#define __NR_kcmp 1345
+#define __NR_mlock2 1346
#endif /* _UAPI_ASM_IA64_UNISTD_H */
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index dcd97f8..534a74a 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1771,5 +1771,6 @@ sys_call_table:
data8 sys_userfaultfd
data8 sys_membarrier
data8 sys_kcmp // 1345
+ data8 sys_mlock2
.org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls
diff --git a/arch/m32r/include/asm/Kbuild b/arch/m32r/include/asm/Kbuild
index fd104bd..860e440 100644
--- a/arch/m32r/include/asm/Kbuild
+++ b/arch/m32r/include/asm/Kbuild
@@ -3,6 +3,7 @@ generic-y += clkdev.h
generic-y += cputime.h
generic-y += exec.h
generic-y += irq_work.h
+generic-y += kvm_para.h
generic-y += mcs_spinlock.h
generic-y += mm-arch-hooks.h
generic-y += module.h
diff --git a/arch/m32r/include/asm/io.h b/arch/m32r/include/asm/io.h
index 61b8931..4b0f5e0 100644
--- a/arch/m32r/include/asm/io.h
+++ b/arch/m32r/include/asm/io.h
@@ -168,13 +168,21 @@ static inline void _writel(unsigned long l, unsigned long addr)
#define writew_relaxed writew
#define writel_relaxed writel
-#define ioread8 read
+#define ioread8 readb
#define ioread16 readw
#define ioread32 readl
#define iowrite8 writeb
#define iowrite16 writew
#define iowrite32 writel
+#define ioread8_rep(p, dst, count) insb((unsigned long)(p), (dst), (count))
+#define ioread16_rep(p, dst, count) insw((unsigned long)(p), (dst), (count))
+#define ioread32_rep(p, dst, count) insl((unsigned long)(p), (dst), (count))
+
+#define iowrite8_rep(p, src, count) outsb((unsigned long)(p), (src), (count))
+#define iowrite16_rep(p, src, count) outsw((unsigned long)(p), (src), (count))
+#define iowrite32_rep(p, src, count) outsl((unsigned long)(p), (src), (count))
+
#define ioread16be(addr) be16_to_cpu(readw(addr))
#define ioread32be(addr) be32_to_cpu(readl(addr))
#define iowrite16be(v, addr) writew(cpu_to_be16(v), (addr))
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 192b00f..cbd5991 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -858,7 +858,7 @@ static struct platform_device *atari_netusbee_devices[] __initdata = {
};
#endif /* CONFIG_ATARI_ETHERNEC */
-#ifdef CONFIG_ATARI_SCSI
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
static const struct resource atari_scsi_st_rsrc[] __initconst = {
{
.flags = IORESOURCE_IRQ,
@@ -910,7 +910,7 @@ int __init atari_platform_init(void)
}
#endif
-#ifdef CONFIG_ATARI_SCSI
+#if IS_ENABLED(CONFIG_ATARI_SCSI)
if (ATARIHW_PRESENT(ST_SCSI))
platform_device_register_simple("atari_scsi", -1,
atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc));
diff --git a/arch/m68k/coldfire/gpio.c b/arch/m68k/coldfire/gpio.c
index e7e4286..37a83e2 100644
--- a/arch/m68k/coldfire/gpio.c
+++ b/arch/m68k/coldfire/gpio.c
@@ -121,7 +121,7 @@ static int mcfgpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int mcfgpio_get_value(struct gpio_chip *chip, unsigned offset)
{
- return __mcfgpio_get_value(offset);
+ return !!__mcfgpio_get_value(offset);
}
static int mcfgpio_direction_output(struct gpio_chip *chip, unsigned offset,
diff --git a/arch/m68k/coldfire/m54xx.c b/arch/m68k/coldfire/m54xx.c
index f7836c6..c32f767 100644
--- a/arch/m68k/coldfire/m54xx.c
+++ b/arch/m68k/coldfire/m54xx.c
@@ -98,7 +98,7 @@ static void __init mcf54xx_bootmem_alloc(void)
memstart = PAGE_ALIGN(_ramstart);
min_low_pfn = PFN_DOWN(_rambase);
start_pfn = PFN_DOWN(memstart);
- max_low_pfn = PFN_DOWN(_ramend);
+ max_pfn = max_low_pfn = PFN_DOWN(_ramend);
high_memory = (void *)_ramend;
m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6;
diff --git a/arch/m68k/configs/amiga_defconfig b/arch/m68k/configs/amiga_defconfig
index 5b4ec54..fc96e81 100644
--- a/arch/m68k/configs/amiga_defconfig
+++ b/arch/m68k/configs/amiga_defconfig
@@ -276,6 +276,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -532,11 +533,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -559,6 +562,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/apollo_defconfig b/arch/m68k/configs/apollo_defconfig
index 6e5198e..05c904f 100644
--- a/arch/m68k/configs/apollo_defconfig
+++ b/arch/m68k/configs/apollo_defconfig
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -372,6 +373,7 @@ CONFIG_INPUT_EVDEV=m
# CONFIG_MOUSE_PS2 is not set
CONFIG_MOUSE_SERIAL=m
CONFIG_SERIO=m
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
# CONFIG_HW_RANDOM is not set
@@ -490,11 +492,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -517,6 +521,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/atari_defconfig b/arch/m68k/configs/atari_defconfig
index f75600b..d572b73 100644
--- a/arch/m68k/configs/atari_defconfig
+++ b/arch/m68k/configs/atari_defconfig
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -512,11 +513,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -539,6 +542,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/bvme6000_defconfig b/arch/m68k/configs/bvme6000_defconfig
index a42d91c..11a30c6 100644
--- a/arch/m68k/configs/bvme6000_defconfig
+++ b/arch/m68k/configs/bvme6000_defconfig
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/hp300_defconfig b/arch/m68k/configs/hp300_defconfig
index 77f4a11..6630a51 100644
--- a/arch/m68k/configs/hp300_defconfig
+++ b/arch/m68k/configs/hp300_defconfig
@@ -274,6 +274,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -375,6 +376,7 @@ CONFIG_MOUSE_SERIAL=m
CONFIG_INPUT_MISC=y
CONFIG_HP_SDC_RTC=m
CONFIG_SERIO_SERPORT=m
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
# CONFIG_HW_RANDOM is not set
@@ -492,11 +494,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -519,6 +523,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/mac_defconfig b/arch/m68k/configs/mac_defconfig
index 5a329f7..1d90b71 100644
--- a/arch/m68k/configs/mac_defconfig
+++ b/arch/m68k/configs/mac_defconfig
@@ -276,6 +276,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -394,6 +395,7 @@ CONFIG_MOUSE_SERIAL=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_M68K_BEEP=m
CONFIG_SERIO=m
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_PMACZILOG=y
@@ -514,11 +516,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -541,6 +545,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/multi_defconfig b/arch/m68k/configs/multi_defconfig
index 83c80d2..1fd21c1 100644
--- a/arch/m68k/configs/multi_defconfig
+++ b/arch/m68k/configs/multi_defconfig
@@ -286,6 +286,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -449,6 +450,7 @@ CONFIG_INPUT_MISC=y
CONFIG_INPUT_M68K_BEEP=m
CONFIG_HP_SDC_RTC=m
CONFIG_SERIO_Q40KBD=y
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_SERIAL_PMACZILOG=y
@@ -594,11 +596,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -621,6 +625,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/mvme147_defconfig b/arch/m68k/configs/mvme147_defconfig
index 6cb42c3..74e10f7 100644
--- a/arch/m68k/configs/mvme147_defconfig
+++ b/arch/m68k/configs/mvme147_defconfig
@@ -271,6 +271,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/mvme16x_defconfig b/arch/m68k/configs/mvme16x_defconfig
index c7508c3..7034e71 100644
--- a/arch/m68k/configs/mvme16x_defconfig
+++ b/arch/m68k/configs/mvme16x_defconfig
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -483,11 +484,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -510,6 +513,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/q40_defconfig b/arch/m68k/configs/q40_defconfig
index 64b7166..f7deb5f 100644
--- a/arch/m68k/configs/q40_defconfig
+++ b/arch/m68k/configs/q40_defconfig
@@ -272,6 +272,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -385,6 +386,7 @@ CONFIG_MOUSE_SERIAL=m
CONFIG_INPUT_MISC=y
CONFIG_INPUT_M68K_BEEP=m
CONFIG_SERIO_Q40KBD=y
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
CONFIG_PRINTER=m
@@ -505,11 +507,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -532,6 +536,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/sun3_defconfig b/arch/m68k/configs/sun3_defconfig
index 9a4cab7..0ce79eb 100644
--- a/arch/m68k/configs/sun3_defconfig
+++ b/arch/m68k/configs/sun3_defconfig
@@ -269,6 +269,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -369,6 +370,7 @@ CONFIG_INPUT_EVDEV=m
CONFIG_KEYBOARD_SUNKBD=y
# CONFIG_MOUSE_PS2 is not set
CONFIG_MOUSE_SERIAL=m
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
# CONFIG_HW_RANDOM is not set
@@ -484,11 +486,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -510,6 +514,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/configs/sun3x_defconfig b/arch/m68k/configs/sun3x_defconfig
index 1a2eaac..4cb787e 100644
--- a/arch/m68k/configs/sun3x_defconfig
+++ b/arch/m68k/configs/sun3x_defconfig
@@ -269,6 +269,7 @@ CONFIG_MPLS=y
CONFIG_NET_MPLS_GSO=m
CONFIG_MPLS_ROUTING=m
CONFIG_MPLS_IPTUNNEL=m
+CONFIG_NET_L3_MASTER_DEV=y
# CONFIG_WIRELESS is not set
# CONFIG_UEVENT_HELPER is not set
CONFIG_DEVTMPFS=y
@@ -369,6 +370,7 @@ CONFIG_INPUT_EVDEV=m
CONFIG_KEYBOARD_SUNKBD=y
# CONFIG_MOUSE_PS2 is not set
CONFIG_MOUSE_SERIAL=m
+CONFIG_USERIO=m
# CONFIG_LEGACY_PTYS is not set
# CONFIG_DEVKMEM is not set
# CONFIG_HW_RANDOM is not set
@@ -484,11 +486,13 @@ CONFIG_NLS_MAC_INUIT=m
CONFIG_NLS_MAC_ROMANIAN=m
CONFIG_NLS_MAC_TURKISH=m
CONFIG_DLM=m
+# CONFIG_SECTION_MISMATCH_WARN_ONLY is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_ASYNC_RAID6_TEST=m
CONFIG_TEST_HEXDUMP=m
CONFIG_TEST_STRING_HELPERS=m
CONFIG_TEST_KSTRTOX=m
+CONFIG_TEST_PRINTF=m
CONFIG_TEST_RHASHTABLE=m
CONFIG_TEST_LKM=m
CONFIG_TEST_USER_COPY=m
@@ -511,6 +515,7 @@ CONFIG_CRYPTO_CTS=m
CONFIG_CRYPTO_LRW=m
CONFIG_CRYPTO_PCBC=m
CONFIG_CRYPTO_XTS=m
+CONFIG_CRYPTO_KEYWRAP=m
CONFIG_CRYPTO_XCBC=m
CONFIG_CRYPTO_VMAC=m
CONFIG_CRYPTO_MICHAEL_MIC=m
diff --git a/arch/m68k/emu/nfblock.c b/arch/m68k/emu/nfblock.c
index f2a00c5..e9110b9 100644
--- a/arch/m68k/emu/nfblock.c
+++ b/arch/m68k/emu/nfblock.c
@@ -59,7 +59,7 @@ struct nfhd_device {
struct gendisk *disk;
};
-static void nfhd_make_request(struct request_queue *queue, struct bio *bio)
+static blk_qc_t nfhd_make_request(struct request_queue *queue, struct bio *bio)
{
struct nfhd_device *dev = queue->queuedata;
struct bio_vec bvec;
@@ -77,6 +77,7 @@ static void nfhd_make_request(struct request_queue *queue, struct bio *bio)
sec += len;
}
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
static int nfhd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
diff --git a/arch/m68k/include/asm/mac_psc.h b/arch/m68k/include/asm/mac_psc.h
index e5c0d71..9233051 100644
--- a/arch/m68k/include/asm/mac_psc.h
+++ b/arch/m68k/include/asm/mac_psc.h
@@ -209,7 +209,6 @@
#ifndef __ASSEMBLY__
extern volatile __u8 *psc;
-extern int psc_present;
extern void psc_register_interrupts(void);
extern void psc_irq_enable(int);
diff --git a/arch/m68k/include/asm/page.h b/arch/m68k/include/asm/page.h
index 38b024a..430d4d5 100644
--- a/arch/m68k/include/asm/page.h
+++ b/arch/m68k/include/asm/page.h
@@ -48,6 +48,9 @@ extern unsigned long _ramend;
#include <asm/page_no.h>
#endif
+#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT))
+#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
+
#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
diff --git a/arch/m68k/include/asm/uaccess_no.h b/arch/m68k/include/asm/uaccess_no.h
index 68bbe9b..1bdf152 100644
--- a/arch/m68k/include/asm/uaccess_no.h
+++ b/arch/m68k/include/asm/uaccess_no.h
@@ -135,10 +135,6 @@ extern int __get_user_bad(void);
#define __copy_to_user_inatomic __copy_to_user
#define __copy_from_user_inatomic __copy_from_user
-#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
-
-#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
-
/*
* Copy a null terminated string from userspace.
*/
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h
index 0793a7f..f9d96bf 100644
--- a/arch/m68k/include/asm/unistd.h
+++ b/arch/m68k/include/asm/unistd.h
@@ -4,7 +4,7 @@
#include <uapi/asm/unistd.h>
-#define NR_syscalls 375
+#define NR_syscalls 376
#define __ARCH_WANT_OLD_READDIR
#define __ARCH_WANT_OLD_STAT
diff --git a/arch/m68k/include/uapi/asm/unistd.h b/arch/m68k/include/uapi/asm/unistd.h
index 5e6fae6..36cf129 100644
--- a/arch/m68k/include/uapi/asm/unistd.h
+++ b/arch/m68k/include/uapi/asm/unistd.h
@@ -380,5 +380,6 @@
#define __NR_sendmmsg 372
#define __NR_userfaultfd 373
#define __NR_membarrier 374
+#define __NR_mlock2 375
#endif /* _UAPI_ASM_M68K_UNISTD_H_ */
diff --git a/arch/m68k/kernel/setup_no.c b/arch/m68k/kernel/setup_no.c
index 88c27d9..76b9113 100644
--- a/arch/m68k/kernel/setup_no.c
+++ b/arch/m68k/kernel/setup_no.c
@@ -238,11 +238,14 @@ void __init setup_arch(char **cmdline_p)
* Give all the memory to the bootmap allocator, tell it to put the
* boot mem_map at the start of memory.
*/
+ min_low_pfn = PFN_DOWN(memory_start);
+ max_pfn = max_low_pfn = PFN_DOWN(memory_end);
+
bootmap_size = init_bootmem_node(
NODE_DATA(0),
- memory_start >> PAGE_SHIFT, /* map goes here */
- PAGE_OFFSET >> PAGE_SHIFT, /* 0 on coldfire */
- memory_end >> PAGE_SHIFT);
+ min_low_pfn, /* map goes here */
+ PFN_DOWN(PAGE_OFFSET),
+ max_pfn);
/*
* Free the usable memory, we have to make sure we do not free
* the bootmem bitmap so we then reserve it after freeing it :-)
diff --git a/arch/m68k/kernel/syscalltable.S b/arch/m68k/kernel/syscalltable.S
index 5dd0e80..282cd90 100644
--- a/arch/m68k/kernel/syscalltable.S
+++ b/arch/m68k/kernel/syscalltable.S
@@ -395,3 +395,4 @@ ENTRY(sys_call_table)
.long sys_sendmmsg
.long sys_userfaultfd
.long sys_membarrier
+ .long sys_mlock2 /* 375 */
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 5c1a6b2..9f98c08 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -174,7 +174,7 @@ void __init mac_init_IRQ(void)
oss_register_interrupts();
else
via_register_interrupts();
- if (psc_present)
+ if (psc)
psc_register_interrupts();
if (baboon_present)
baboon_register_interrupts();
@@ -212,7 +212,7 @@ void mac_irq_enable(struct irq_data *data)
case 4:
case 5:
case 6:
- if (psc_present)
+ if (psc)
psc_irq_enable(irq);
else if (oss_present)
oss_irq_enable(irq);
@@ -242,7 +242,7 @@ void mac_irq_disable(struct irq_data *data)
case 4:
case 5:
case 6:
- if (psc_present)
+ if (psc)
psc_irq_disable(irq);
else if (oss_present)
oss_irq_disable(irq);
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index 2290c0c..cb2b1a3 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -27,7 +27,6 @@
#define DEBUG_PSC
-int psc_present;
volatile __u8 *psc;
EXPORT_SYMBOL_GPL(psc);
@@ -39,7 +38,9 @@ static void psc_debug_dump(void)
{
int i;
- if (!psc_present) return;
+ if (!psc)
+ return;
+
for (i = 0x30 ; i < 0x70 ; i += 0x10) {
printk("PSC #%d: IFR = 0x%02X IER = 0x%02X\n",
i >> 4,
@@ -81,7 +82,6 @@ void __init psc_init(void)
&& macintosh_config->ident != MAC_MODEL_Q840)
{
psc = NULL;
- psc_present = 0;
return;
}
@@ -91,7 +91,6 @@ void __init psc_init(void)
*/
psc = (void *) PSC_BASE;
- psc_present = 1;
printk("PSC detected at %p\n", psc);
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index b958916..8f37fdd 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -250,7 +250,7 @@ void __init paging_init(void)
high_memory = phys_to_virt(max_addr);
min_low_pfn = availmem >> PAGE_SHIFT;
- max_low_pfn = max_addr >> PAGE_SHIFT;
+ max_pfn = max_low_pfn = max_addr >> PAGE_SHIFT;
for (i = 0; i < m68k_num_memory; i++) {
addr = m68k_memory[i].addr;
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index a8b942b..71884bf 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -118,13 +118,13 @@ static void __init sun3_bootmem_alloc(unsigned long memory_start,
memory_end = memory_end & PAGE_MASK;
start_page = __pa(memory_start) >> PAGE_SHIFT;
- num_pages = __pa(memory_end) >> PAGE_SHIFT;
+ max_pfn = num_pages = __pa(memory_end) >> PAGE_SHIFT;
high_memory = (void *)memory_end;
availmem = memory_start;
m68k_setup_node(0);
- availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
+ availmem += init_bootmem(start_page, num_pages);
availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
free_bootmem(__pa(availmem), memory_end - (availmem));
@@ -171,7 +171,7 @@ static void __init sun3_sched_init(irq_handler_t timer_routine)
intersil_clear();
}
-#ifdef CONFIG_SUN3_SCSI
+#if IS_ENABLED(CONFIG_SUN3_SCSI)
static const struct resource sun3_scsi_vme_rsrc[] __initconst = {
{
diff --git a/arch/metag/include/asm/irq.h b/arch/metag/include/asm/irq.h
index ad6bd0e..6ac6d4a 100644
--- a/arch/metag/include/asm/irq.h
+++ b/arch/metag/include/asm/irq.h
@@ -6,8 +6,12 @@ extern void irq_ctx_init(int cpu);
extern void irq_ctx_exit(int cpu);
# define __ARCH_HAS_DO_SOFTIRQ
#else
-# define irq_ctx_init(cpu) do { } while (0)
-# define irq_ctx_exit(cpu) do { } while (0)
+static inline void irq_ctx_init(int cpu)
+{
+}
+static inline void irq_ctx_exit(int cpu)
+{
+}
#endif
void tbi_startup_interrupt(int);
diff --git a/arch/metag/kernel/smp.c b/arch/metag/kernel/smp.c
index ac3a199..c3c6f08 100644
--- a/arch/metag/kernel/smp.c
+++ b/arch/metag/kernel/smp.c
@@ -312,6 +312,7 @@ void cpu_die(void)
{
local_irq_disable();
idle_task_exit();
+ irq_ctx_exit(smp_processor_id());
(void)cpu_report_death();
@@ -366,6 +367,7 @@ asmlinkage void secondary_start_kernel(void)
panic("No TBI found!");
per_cpu_trap_init(cpu);
+ irq_ctx_init(cpu);
preempt_disable();
diff --git a/arch/microblaze/kernel/dma.c b/arch/microblaze/kernel/dma.c
index c89da63..bf4dec2 100644
--- a/arch/microblaze/kernel/dma.c
+++ b/arch/microblaze/kernel/dma.c
@@ -61,7 +61,8 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
/* FIXME this part of code is untested */
for_each_sg(sgl, sg, nents, i) {
sg->dma_address = sg_phys(sg);
- __dma_sync(sg_phys(sg), sg->length, direction);
+ __dma_sync(page_to_phys(sg_page(sg)) + sg->offset,
+ sg->length, direction);
}
return nents;
diff --git a/arch/mips/Kbuild b/arch/mips/Kbuild
index dd29533..5c3f688 100644
--- a/arch/mips/Kbuild
+++ b/arch/mips/Kbuild
@@ -17,6 +17,7 @@ obj- := $(platform-)
obj-y += kernel/
obj-y += mm/
obj-y += net/
+obj-y += vdso/
ifdef CONFIG_KVM
obj-y += kvm/
diff --git a/arch/mips/Kbuild.platforms b/arch/mips/Kbuild.platforms
index a424e46..a96c81d 100644
--- a/arch/mips/Kbuild.platforms
+++ b/arch/mips/Kbuild.platforms
@@ -33,6 +33,7 @@ platforms += sibyte
platforms += sni
platforms += txx9
platforms += vr41xx
+platforms += xilfpga
# include the platform specific files
include $(patsubst %, $(srctree)/arch/mips/%/Platform, $(platforms))
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index e3aa5b0..71683a8 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -5,6 +5,7 @@ config MIPS
select ARCH_MIGHT_HAVE_PC_PARPORT
select ARCH_MIGHT_HAVE_PC_SERIO
select ARCH_USE_CMPXCHG_LOCKREF if 64BIT
+ select ARCH_USE_BUILTIN_BSWAP
select HAVE_CONTEXT_TRACKING
select HAVE_GENERIC_DMA_COHERENT
select HAVE_IDE
@@ -60,6 +61,8 @@ config MIPS
select SYSCTL_EXCEPTION_TRACE
select HAVE_VIRT_CPU_ACCOUNTING_GEN
select HAVE_IRQ_TIME_ACCOUNTING
+ select GENERIC_TIME_VSYSCALL
+ select ARCH_CLOCKSOURCE_DATA
menu "Machine selection"
@@ -401,6 +404,28 @@ config MACH_PISTACHIO
help
This enables support for the IMG Pistachio SoC platform.
+config MACH_XILFPGA
+ bool "MIPSfpga Xilinx based boards"
+ select ARCH_REQUIRE_GPIOLIB
+ select BOOT_ELF32
+ select BOOT_RAW
+ select BUILTIN_DTB
+ select CEVT_R4K
+ select COMMON_CLK
+ select CSRC_R4K
+ select IRQ_MIPS_CPU
+ select LIBFDT
+ select MIPS_CPU_SCACHE
+ select SYS_HAS_EARLY_PRINTK
+ select SYS_HAS_CPU_MIPS32_R2
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_ZBOOT_UART16550
+ select USE_OF
+ select USE_GENERIC_EARLY_PRINTK_8250
+ help
+ This enables support for the IMG University Program MIPSfpga platform.
+
config MIPS_MALTA
bool "MIPS Malta board"
select ARCH_MAY_HAVE_PC_FDC
@@ -424,6 +449,7 @@ config MIPS_MALTA
select MIPS_L1_CACHE_SHIFT_6
select PCI_GT64XXX_PCI0
select MIPS_MSC
+ select SMP_UP if SMP
select SWAP_IO_SPACE
select SYS_HAS_CPU_MIPS32_R1
select SYS_HAS_CPU_MIPS32_R2
@@ -449,6 +475,8 @@ config MIPS_MALTA
select SYS_SUPPORTS_ZBOOT
select USE_OF
select ZONE_DMA32 if 64BIT
+ select BUILTIN_DTB
+ select LIBFDT
help
This enables support for the MIPS Technologies Malta evaluation
board.
@@ -964,6 +992,7 @@ source "arch/mips/loongson32/Kconfig"
source "arch/mips/loongson64/Kconfig"
source "arch/mips/netlogic/Kconfig"
source "arch/mips/paravirt/Kconfig"
+source "arch/mips/xilfpga/Kconfig"
endmenu
@@ -1036,6 +1065,9 @@ config CSRC_R4K
config CSRC_SB1250
bool
+config MIPS_CLOCK_VSYSCALL
+ def_bool CSRC_R4K || CLKSRC_MIPS_GIC
+
config GPIO_TXX9
select ARCH_REQUIRE_GPIOLIB
bool
@@ -2529,6 +2561,9 @@ choice
help
Allows the configuration of the timer frequency.
+ config HZ_24
+ bool "24 HZ" if SYS_SUPPORTS_24HZ || SYS_SUPPORTS_ARBIT_HZ
+
config HZ_48
bool "48 HZ" if SYS_SUPPORTS_48HZ || SYS_SUPPORTS_ARBIT_HZ
@@ -2552,6 +2587,9 @@ choice
endchoice
+config SYS_SUPPORTS_24HZ
+ bool
+
config SYS_SUPPORTS_48HZ
bool
@@ -2575,13 +2613,18 @@ config SYS_SUPPORTS_1024HZ
config SYS_SUPPORTS_ARBIT_HZ
bool
- default y if !SYS_SUPPORTS_48HZ && !SYS_SUPPORTS_100HZ && \
- !SYS_SUPPORTS_128HZ && !SYS_SUPPORTS_250HZ && \
- !SYS_SUPPORTS_256HZ && !SYS_SUPPORTS_1000HZ && \
+ default y if !SYS_SUPPORTS_24HZ && \
+ !SYS_SUPPORTS_48HZ && \
+ !SYS_SUPPORTS_100HZ && \
+ !SYS_SUPPORTS_128HZ && \
+ !SYS_SUPPORTS_250HZ && \
+ !SYS_SUPPORTS_256HZ && \
+ !SYS_SUPPORTS_1000HZ && \
!SYS_SUPPORTS_1024HZ
config HZ
int
+ default 24 if HZ_24
default 48 if HZ_48
default 100 if HZ_100
default 128 if HZ_128
@@ -2685,7 +2728,7 @@ config BUILTIN_DTB
bool
choice
- prompt "Kernel appended dtb support" if OF
+ prompt "Kernel appended dtb support" if USE_OF
default MIPS_NO_APPENDED_DTB
config MIPS_NO_APPENDED_DTB
@@ -2693,6 +2736,20 @@ choice
help
Do not enable appended dtb support.
+ config MIPS_ELF_APPENDED_DTB
+ bool "vmlinux"
+ help
+ With this option, the boot code will look for a device tree binary
+ DTB) included in the vmlinux ELF section .appended_dtb. By default
+ it is empty and the DTB can be appended using binutils command
+ objcopy:
+
+ objcopy --update-section .appended_dtb=<filename>.dtb vmlinux
+
+ This is meant as a backward compatiblity convenience for those
+ systems with a bootloader that can't be upgraded to accommodate
+ the documented boot protocol using a device tree.
+
config MIPS_RAW_APPENDED_DTB
bool "vmlinux.bin"
help
@@ -2729,6 +2786,25 @@ choice
if you don't intend to always append a DTB.
endchoice
+choice
+ prompt "Kernel command line type" if !CMDLINE_OVERRIDE
+ default MIPS_CMDLINE_FROM_DTB if USE_OF && !ATH79 && !MACH_INGENIC && \
+ !MIPS_MALTA && !MIPS_SEAD3 && \
+ !CAVIUM_OCTEON_SOC
+ default MIPS_CMDLINE_FROM_BOOTLOADER
+
+ config MIPS_CMDLINE_FROM_DTB
+ depends on USE_OF
+ bool "Dtb kernel arguments if available"
+
+ config MIPS_CMDLINE_DTB_EXTEND
+ depends on USE_OF
+ bool "Extend dtb kernel arguments with bootloader arguments"
+
+ config MIPS_CMDLINE_FROM_BOOTLOADER
+ bool "Bootloader kernel arguments if available"
+endchoice
+
endmenu
config LOCKDEP_SUPPORT
@@ -2739,6 +2815,10 @@ config STACKTRACE_SUPPORT
bool
default y
+config HAVE_LATENCYTOP_SUPPORT
+ bool
+ default y
+
config PGTABLE_LEVELS
int
default 3 if 64BIT && !PAGE_SIZE_64KB
diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug
index e250524..f0e314c 100644
--- a/arch/mips/Kconfig.debug
+++ b/arch/mips/Kconfig.debug
@@ -113,4 +113,76 @@ config SPINLOCK_TEST
help
Add several files to the debugfs to test spinlock speed.
+if CPU_MIPSR6
+
+choice
+ prompt "Compact branch policy"
+ default MIPS_COMPACT_BRANCHES_OPTIMAL
+
+config MIPS_COMPACT_BRANCHES_NEVER
+ bool "Never (force delay slot branches)"
+ help
+ Pass the -mcompact-branches=never flag to the compiler in order to
+ force it to always emit branches with delay slots, and make no use
+ of the compact branch instructions introduced by MIPSr6. This is
+ useful if you suspect there may be an issue with compact branches in
+ either the compiler or the CPU.
+
+config MIPS_COMPACT_BRANCHES_OPTIMAL
+ bool "Optimal (use where beneficial)"
+ help
+ Pass the -mcompact-branches=optimal flag to the compiler in order for
+ it to make use of compact branch instructions where it deems them
+ beneficial, and use branches with delay slots elsewhere. This is the
+ default compiler behaviour, and should be used unless you have a
+ reason to choose otherwise.
+
+config MIPS_COMPACT_BRANCHES_ALWAYS
+ bool "Always (force compact branches)"
+ help
+ Pass the -mcompact-branches=always flag to the compiler in order to
+ force it to always emit compact branches, making no use of branch
+ instructions with delay slots. This can result in more compact code
+ which may be beneficial in some scenarios.
+
+endchoice
+
+endif # CPU_MIPSR6
+
+config SCACHE_DEBUGFS
+ bool "L2 cache debugfs entries"
+ depends on DEBUG_FS
+ help
+ Enable this to allow parts of the L2 cache configuration, such as
+ whether or not prefetching is enabled, to be exposed to userland
+ via debugfs.
+
+ If unsure, say N.
+
+menuconfig MIPS_CPS_NS16550
+ bool "CPS SMP NS16550 UART output"
+ depends on MIPS_CPS
+ help
+ Output debug information via an ns16550 compatible UART if exceptions
+ occur early in the boot process of a secondary core.
+
+if MIPS_CPS_NS16550
+
+config MIPS_CPS_NS16550_BASE
+ hex "UART Base Address"
+ default 0x1b0003f8 if MIPS_MALTA
+ help
+ The base address of the ns16550 compatible UART on which to output
+ debug information from the early stages of core startup.
+
+config MIPS_CPS_NS16550_SHIFT
+ int "UART Register Shift"
+ default 0 if MIPS_MALTA
+ help
+ The number of bits to shift ns16550 register indices by in order to
+ form their addresses. That is, log base 2 of the span between
+ adjacent ns16550 registers in the system.
+
+endif # MIPS_CPS_NS16550
+
endmenu
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 252e347..3f70ba5 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -204,6 +204,10 @@ toolchain-msa := $(call cc-option-yn,$(mips-cflags) -mhard-float -mfp64 -Wa$(
cflags-$(toolchain-msa) += -DTOOLCHAIN_SUPPORTS_MSA
endif
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_NEVER) += -mcompact-branches=never
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_OPTIMAL) += -mcompact-branches=optimal
+cflags-$(CONFIG_MIPS_COMPACT_BRANCHES_ALWAYS) += -mcompact-branches=always
+
#
# Firmware support
#
diff --git a/arch/mips/ath79/setup.c b/arch/mips/ath79/setup.c
index 1ba2120..8755d61 100644
--- a/arch/mips/ath79/setup.c
+++ b/arch/mips/ath79/setup.c
@@ -216,9 +216,9 @@ void __init plat_mem_setup(void)
AR71XX_RESET_SIZE);
ath79_pll_base = ioremap_nocache(AR71XX_PLL_BASE,
AR71XX_PLL_SIZE);
+ ath79_detect_sys_type();
ath79_ddr_ctrl_init();
- ath79_detect_sys_type();
if (mips_machtype != ATH79_MACH_GENERIC_OF)
detect_memory_region(0, ATH79_MEM_SIZE_MIN, ATH79_MEM_SIZE_MAX);
@@ -281,3 +281,8 @@ MIPS_MACHINE(ATH79_MACH_GENERIC,
"Generic",
"Generic AR71XX/AR724X/AR913X based board",
ath79_generic_init);
+
+MIPS_MACHINE(ATH79_MACH_GENERIC_OF,
+ "DTB",
+ "Generic AR71XX/AR724X/AR913X based board (DT)",
+ NULL);
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 17503a0..6d38948 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -105,11 +105,28 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
struct ssb_init_invariants *iv)
{
char buf[20];
+ int len, err;
/* Fill boardinfo structure */
memset(&iv->boardinfo, 0 , sizeof(struct ssb_boardinfo));
- bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
+ len = bcm47xx_nvram_getenv("boardvendor", buf, sizeof(buf));
+ if (len > 0) {
+ err = kstrtou16(strim(buf), 0, &iv->boardinfo.vendor);
+ if (err)
+ pr_warn("Couldn't parse nvram board vendor entry with value \"%s\"\n",
+ buf);
+ }
+ if (!iv->boardinfo.vendor)
+ iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
+
+ len = bcm47xx_nvram_getenv("boardtype", buf, sizeof(buf));
+ if (len > 0) {
+ err = kstrtou16(strim(buf), 0, &iv->boardinfo.type);
+ if (err)
+ pr_warn("Couldn't parse nvram board type entry with value \"%s\"\n",
+ buf);
+ }
memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom(&iv->sprom, NULL, false);
diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c
index 2d5c7a7..a7e569c 100644
--- a/arch/mips/bcm47xx/sprom.c
+++ b/arch/mips/bcm47xx/sprom.c
@@ -60,9 +60,9 @@ static int get_nvram_var(const char *prefix, const char *postfix,
}
#define NVRAM_READ_VAL(type) \
-static void nvram_read_ ## type (const char *prefix, \
- const char *postfix, const char *name, \
- type *val, type allset, bool fallback) \
+static void nvram_read_ ## type(const char *prefix, \
+ const char *postfix, const char *name, \
+ type *val, type allset, bool fallback) \
{ \
char buf[100]; \
int err; \
@@ -422,7 +422,10 @@ static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom,
int i;
for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
- struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ struct ssb_sprom_core_pwr_info *pwr_info;
+
+ pwr_info = &sprom->core_pwr_info[i];
+
snprintf(postfix, sizeof(postfix), "%i", i);
nvram_read_u8(prefix, postfix, "maxp2ga",
&pwr_info->maxpwr_2g, 0, fallback);
@@ -470,7 +473,10 @@ static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
int i;
for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
- struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ struct ssb_sprom_core_pwr_info *pwr_info;
+
+ pwr_info = &sprom->core_pwr_info[i];
+
snprintf(postfix, sizeof(postfix), "%i", i);
nvram_read_u16(prefix, postfix, "pa2gw3a",
&pwr_info->pa_2g[3], 0, fallback);
@@ -535,10 +541,11 @@ static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,
nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);
/* The address prefix 00:90:4C is used by Broadcom in their initial
- configuration. When a mac address with the prefix 00:90:4C is used
- all devices from the same series are sharing the same mac address.
- To prevent mac address collisions we replace them with a mac address
- based on the base address. */
+ * configuration. When a mac address with the prefix 00:90:4C is used
+ * all devices from the same series are sharing the same mac address.
+ * To prevent mac address collisions we replace them with a mac address
+ * based on the base address.
+ */
if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
u8 mac[6];
@@ -592,32 +599,23 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
bcm47xx_sprom_fill_auto(sprom, prefix, fallback);
}
-#ifdef CONFIG_BCM47XX_SSB
-void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
- const char *prefix)
-{
- nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0,
- true);
- if (!boardinfo->vendor)
- boardinfo->vendor = SSB_BOARDVENDOR_BCM;
-
- nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0, true);
-}
-#endif
-
#if defined(CONFIG_BCM47XX_SSB)
static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
{
char prefix[10];
- if (bus->bustype == SSB_BUSTYPE_PCI) {
+ switch (bus->bustype) {
+ case SSB_BUSTYPE_SSB:
+ bcm47xx_fill_sprom(out, NULL, false);
+ return 0;
+ case SSB_BUSTYPE_PCI:
memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
bcm47xx_fill_sprom(out, prefix, false);
return 0;
- } else {
+ default:
pr_warn("Unable to fill SPROM for given bustype.\n");
return -EINVAL;
}
diff --git a/arch/mips/bcm63xx/boards/board_bcm963xx.c b/arch/mips/bcm63xx/boards/board_bcm963xx.c
index 33727e7..b2097c0 100644
--- a/arch/mips/bcm63xx/boards/board_bcm963xx.c
+++ b/arch/mips/bcm63xx/boards/board_bcm963xx.c
@@ -7,6 +7,8 @@
* Copyright (C) 2008 Florian Fainelli <florian@openwrt.org>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -31,7 +33,6 @@
#include <uapi/linux/bcm933xx_hcs.h>
-#define PFX "board_bcm963xx: "
#define HCS_OFFSET_128K 0x20000
@@ -740,7 +741,7 @@ int bcm63xx_get_fallback_sprom(struct ssb_bus *bus, struct ssb_sprom *out)
memcpy(out, &bcm63xx_sprom, sizeof(struct ssb_sprom));
return 0;
} else {
- printk(KERN_ERR PFX "unable to fill SPROM for given bustype.\n");
+ pr_err("unable to fill SPROM for given bustype\n");
return -EINVAL;
}
}
@@ -784,7 +785,7 @@ void __init board_prom_init(void)
cfe[5], cfe[6], cfe[7], cfe[8], cfe[9]);
else
strcpy(cfe_version, "unknown");
- printk(KERN_INFO PFX "CFE version: %s\n", cfe_version);
+ pr_info("CFE version: %s\n", cfe_version);
bcm63xx_nvram_init(boot_addr + BCM963XX_NVRAM_OFFSET);
@@ -808,8 +809,7 @@ void __init board_prom_init(void)
char name[17];
memcpy(name, board_name, 16);
name[16] = 0;
- printk(KERN_ERR PFX "unknown bcm963xx board: %s\n",
- name);
+ pr_err("unknown bcm963xx board: %s\n", name);
return;
}
@@ -854,7 +854,7 @@ void __init board_setup(void)
{
if (!board.name[0])
panic("unable to detect bcm963xx board");
- printk(KERN_INFO PFX "board name: %s\n", board.name);
+ pr_info("board name: %s\n", board.name);
/* make sure we're running on expected cpu */
if (bcm63xx_get_cpu_id() != board.expected_cpu_id)
@@ -910,7 +910,7 @@ int __init board_register_devices(void)
memcpy(bcm63xx_sprom.et1mac, bcm63xx_sprom.il0mac, ETH_ALEN);
if (ssb_arch_register_fallback_sprom(
&bcm63xx_get_fallback_sprom) < 0)
- pr_err(PFX "failed to register fallback SPROM\n");
+ pr_err("failed to register fallback SPROM\n");
}
#endif
diff --git a/arch/mips/bcm63xx/cpu.c b/arch/mips/bcm63xx/cpu.c
index 307ec8b..1c7c3fb 100644
--- a/arch/mips/bcm63xx/cpu.c
+++ b/arch/mips/bcm63xx/cpu.c
@@ -376,10 +376,10 @@ void __init bcm63xx_cpu_init(void)
bcm63xx_cpu_freq = detect_cpu_clock();
bcm63xx_memory_size = detect_memory_size();
- printk(KERN_INFO "Detected Broadcom 0x%04x CPU revision %02x\n",
- bcm63xx_cpu_id, bcm63xx_cpu_rev);
- printk(KERN_INFO "CPU frequency is %u MHz\n",
- bcm63xx_cpu_freq / 1000000);
- printk(KERN_INFO "%uMB of RAM installed\n",
- bcm63xx_memory_size >> 20);
+ pr_info("Detected Broadcom 0x%04x CPU revision %02x\n",
+ bcm63xx_cpu_id, bcm63xx_cpu_rev);
+ pr_info("CPU frequency is %u MHz\n",
+ bcm63xx_cpu_freq / 1000000);
+ pr_info("%uMB of RAM installed\n",
+ bcm63xx_memory_size >> 20);
}
diff --git a/arch/mips/bcm63xx/dev-pcmcia.c b/arch/mips/bcm63xx/dev-pcmcia.c
index a551bab..9496cd2 100644
--- a/arch/mips/bcm63xx/dev-pcmcia.c
+++ b/arch/mips/bcm63xx/dev-pcmcia.c
@@ -139,6 +139,6 @@ int __init bcm63xx_pcmcia_register(void)
return platform_device_register(&bcm63xx_pcmcia_device);
out_err:
- printk(KERN_ERR "unable to set pcmcia chip select\n");
+ pr_err("unable to set pcmcia chip select\n");
return ret;
}
diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c
index 1a47ec2..c961390 100644
--- a/arch/mips/bcm63xx/irq.c
+++ b/arch/mips/bcm63xx/irq.c
@@ -311,7 +311,7 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d,
break;
default:
- printk(KERN_ERR "bogus flow type combination given !\n");
+ pr_err("bogus flow type combination given !\n");
return -EINVAL;
}
diff --git a/arch/mips/bcm63xx/setup.c b/arch/mips/bcm63xx/setup.c
index 240fb4f..2be9caa 100644
--- a/arch/mips/bcm63xx/setup.c
+++ b/arch/mips/bcm63xx/setup.c
@@ -24,7 +24,7 @@
void bcm63xx_machine_halt(void)
{
- printk(KERN_INFO "System halted\n");
+ pr_info("System halted\n");
while (1)
;
}
@@ -34,7 +34,7 @@ static void bcm6348_a1_reboot(void)
u32 reg;
/* soft reset all blocks */
- printk(KERN_INFO "soft-resetting all blocks ...\n");
+ pr_info("soft-resetting all blocks ...\n");
reg = bcm_perf_readl(PERF_SOFTRESET_REG);
reg &= ~SOFTRESET_6348_ALL;
bcm_perf_writel(reg, PERF_SOFTRESET_REG);
@@ -46,7 +46,7 @@ static void bcm6348_a1_reboot(void)
mdelay(10);
/* Jump to the power on address. */
- printk(KERN_INFO "jumping to reset vector.\n");
+ pr_info("jumping to reset vector.\n");
/* set high vectors (base at 0xbfc00000 */
set_c0_status(ST0_BEV | ST0_ERL);
/* run uncached in kseg0 */
@@ -110,7 +110,7 @@ void bcm63xx_machine_reboot(void)
if (BCMCPU_IS_6348() && (bcm63xx_get_cpu_rev() == 0xa1))
bcm6348_a1_reboot();
- printk(KERN_INFO "triggering watchdog soft-reset...\n");
+ pr_info("triggering watchdog soft-reset...\n");
if (BCMCPU_IS_6328()) {
bcm_wdt_writel(1, WDT_SOFTRESET_REG);
} else {
diff --git a/arch/mips/bcm63xx/timer.c b/arch/mips/bcm63xx/timer.c
index 5f11359..2110359 100644
--- a/arch/mips/bcm63xx/timer.c
+++ b/arch/mips/bcm63xx/timer.c
@@ -195,7 +195,7 @@ int bcm63xx_timer_init(void)
irq = bcm63xx_get_irq_number(IRQ_TIMER);
ret = request_irq(irq, timer_interrupt, 0, "bcm63xx_timer", NULL);
if (ret) {
- printk(KERN_ERR "bcm63xx_timer: failed to register irq\n");
+ pr_err("%s: failed to register irq\n", __func__);
return ret;
}
diff --git a/arch/mips/bmips/setup.c b/arch/mips/bmips/setup.c
index 526ec27..5b16d29 100644
--- a/arch/mips/bmips/setup.c
+++ b/arch/mips/bmips/setup.c
@@ -157,7 +157,6 @@ void __init plat_mem_setup(void)
panic("no dtb found");
__dt_setup_arch(dtb);
- strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
for (q = bmips_quirk_list; q->quirk_fn; q++) {
if (of_flat_dt_is_compatible(of_get_flat_dt_root(),
diff --git a/arch/mips/boot/dts/Makefile b/arch/mips/boot/dts/Makefile
index bac7b8d..a0bf516 100644
--- a/arch/mips/boot/dts/Makefile
+++ b/arch/mips/boot/dts/Makefile
@@ -6,6 +6,7 @@ dts-dirs += mti
dts-dirs += netlogic
dts-dirs += qca
dts-dirs += ralink
+dts-dirs += xilfpga
obj-y := $(addsuffix /, $(dts-dirs))
diff --git a/arch/mips/boot/dts/brcm/bcm6328.dtsi b/arch/mips/boot/dts/brcm/bcm6328.dtsi
index 41891c1..d52ce3d 100644
--- a/arch/mips/boot/dts/brcm/bcm6328.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm6328.dtsi
@@ -73,7 +73,6 @@
timer: timer@10000040 {
compatible = "syscon";
reg = <0x10000040 0x2c>;
- little-endian;
};
reboot {
diff --git a/arch/mips/boot/dts/brcm/bcm7125.dtsi b/arch/mips/boot/dts/brcm/bcm7125.dtsi
index 1a7efa8..4fc7ece 100644
--- a/arch/mips/boot/dts/brcm/bcm7125.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7125.dtsi
@@ -98,7 +98,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7125-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>;
- little-endian;
};
reboot {
diff --git a/arch/mips/boot/dts/brcm/bcm7346.dtsi b/arch/mips/boot/dts/brcm/bcm7346.dtsi
index d817bb4..a3039bb 100644
--- a/arch/mips/boot/dts/brcm/bcm7346.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7346.dtsi
@@ -87,20 +87,37 @@
compatible = "brcm,bcm7120-l2-intc";
reg = <0x406780 0x8>;
- brcm,int-map-mask = <0x44>;
+ brcm,int-map-mask = <0x44>, <0xf000000>;
brcm,int-fwd-mask = <0x70000>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&periph_intc>;
- interrupts = <59>;
+ interrupts = <59>, <57>;
+ interrupt-names = "upg_main", "upg_bsc";
+ };
+
+ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x408b80 0x8>;
+
+ brcm,int-map-mask = <0x40>, <0x8000000>, <0x100000>;
+ brcm,int-fwd-mask = <0>;
+ brcm,irq-can-wake;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <60>, <58>, <62>;
+ interrupt-names = "upg_main_aon", "upg_bsc_aon",
+ "upg_spi";
};
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7346-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
@@ -144,6 +161,56 @@
status = "disabled";
};
+ bsca: i2c@406200 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406200 0x58>;
+ interrupts = <24>;
+ interrupt-names = "upg_bsca";
+ status = "disabled";
+ };
+
+ bscb: i2c@406280 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406280 0x58>;
+ interrupts = <25>;
+ interrupt-names = "upg_bscb";
+ status = "disabled";
+ };
+
+ bscc: i2c@406300 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406300 0x58>;
+ interrupts = <26>;
+ interrupt-names = "upg_bscc";
+ status = "disabled";
+ };
+
+ bscd: i2c@406380 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406380 0x58>;
+ interrupts = <27>;
+ interrupt-names = "upg_bscd";
+ status = "disabled";
+ };
+
+ bsce: i2c@408980 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_aon_irq0_intc>;
+ reg = <0x408980 0x58>;
+ interrupts = <27>;
+ interrupt-names = "upg_bsce";
+ status = "disabled";
+ };
+
enet0: ethernet@430000 {
phy-mode = "internal";
phy-handle = <&phy1>;
@@ -246,5 +313,47 @@
interrupts = <76>;
status = "disabled";
};
+
+ sata: sata@181000 {
+ compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci";
+ reg-names = "ahci", "top-ctrl";
+ reg = <0x181000 0xa9c>, <0x180020 0x1c>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ brcm,broken-ncq;
+ brcm,broken-phy;
+ status = "disabled";
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy1>;
+ };
+ };
+
+ sata_phy: sata-phy@1800000 {
+ compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3";
+ reg = <0x180100 0x0eff>;
+ reg-names = "phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ sata_phy0: sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ sata_phy1: sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
};
};
diff --git a/arch/mips/boot/dts/brcm/bcm7358.dtsi b/arch/mips/boot/dts/brcm/bcm7358.dtsi
index 277a90a..4274ff4 100644
--- a/arch/mips/boot/dts/brcm/bcm7358.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7358.dtsi
@@ -81,20 +81,37 @@
compatible = "brcm,bcm7120-l2-intc";
reg = <0x406600 0x8>;
- brcm,int-map-mask = <0x44>;
+ brcm,int-map-mask = <0x44>, <0x7000000>;
brcm,int-fwd-mask = <0x70000>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&periph_intc>;
- interrupts = <56>;
+ interrupts = <56>, <54>;
+ interrupt-names = "upg_main", "upg_bsc";
+ };
+
+ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x408b80 0x8>;
+
+ brcm,int-map-mask = <0x40>, <0x8000000>, <0x100000>;
+ brcm,int-fwd-mask = <0>;
+ brcm,irq-can-wake;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <57>, <55>, <59>;
+ interrupt-names = "upg_main_aon", "upg_bsc_aon",
+ "upg_spi";
};
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7358-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
@@ -138,6 +155,46 @@
status = "disabled";
};
+ bsca: i2c@406200 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406200 0x58>;
+ interrupts = <24>;
+ interrupt-names = "upg_bsca";
+ status = "disabled";
+ };
+
+ bscb: i2c@406280 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406280 0x58>;
+ interrupts = <25>;
+ interrupt-names = "upg_bscb";
+ status = "disabled";
+ };
+
+ bscc: i2c@406300 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406300 0x58>;
+ interrupts = <26>;
+ interrupt-names = "upg_bscc";
+ status = "disabled";
+ };
+
+ bscd: i2c@408980 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_aon_irq0_intc>;
+ reg = <0x408980 0x58>;
+ interrupts = <27>;
+ interrupt-names = "upg_bscd";
+ status = "disabled";
+ };
+
enet0: ethernet@430000 {
phy-mode = "internal";
phy-handle = <&phy1>;
diff --git a/arch/mips/boot/dts/brcm/bcm7360.dtsi b/arch/mips/boot/dts/brcm/bcm7360.dtsi
index 9e1e571..0dcc9163 100644
--- a/arch/mips/boot/dts/brcm/bcm7360.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7360.dtsi
@@ -81,20 +81,37 @@
compatible = "brcm,bcm7120-l2-intc";
reg = <0x406600 0x8>;
- brcm,int-map-mask = <0x44>;
+ brcm,int-map-mask = <0x44>, <0x7000000>;
brcm,int-fwd-mask = <0x70000>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&periph_intc>;
- interrupts = <56>;
+ interrupts = <56>, <54>;
+ interrupt-names = "upg_main", "upg_bsc";
+ };
+
+ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x408b80 0x8>;
+
+ brcm,int-map-mask = <0x40>, <0x8000000>, <0x100000>;
+ brcm,int-fwd-mask = <0>;
+ brcm,irq-can-wake;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <57>, <55>, <59>;
+ interrupt-names = "upg_main_aon", "upg_bsc_aon",
+ "upg_spi";
};
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7360-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
@@ -138,6 +155,46 @@
status = "disabled";
};
+ bsca: i2c@406200 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406200 0x58>;
+ interrupts = <24>;
+ interrupt-names = "upg_bsca";
+ status = "disabled";
+ };
+
+ bscb: i2c@406280 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406280 0x58>;
+ interrupts = <25>;
+ interrupt-names = "upg_bscb";
+ status = "disabled";
+ };
+
+ bscc: i2c@406300 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406300 0x58>;
+ interrupts = <26>;
+ interrupt-names = "upg_bscc";
+ status = "disabled";
+ };
+
+ bscd: i2c@408980 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_aon_irq0_intc>;
+ reg = <0x408980 0x58>;
+ interrupts = <27>;
+ interrupt-names = "upg_bscd";
+ status = "disabled";
+ };
+
enet0: ethernet@430000 {
phy-mode = "internal";
phy-handle = <&phy1>;
diff --git a/arch/mips/boot/dts/brcm/bcm7362.dtsi b/arch/mips/boot/dts/brcm/bcm7362.dtsi
index 6e65db8..2f3f9fc 100644
--- a/arch/mips/boot/dts/brcm/bcm7362.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7362.dtsi
@@ -87,20 +87,37 @@
compatible = "brcm,bcm7120-l2-intc";
reg = <0x406600 0x8>;
- brcm,int-map-mask = <0x44>;
+ brcm,int-map-mask = <0x44>, <0x7000000>;
brcm,int-fwd-mask = <0x70000>;
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&periph_intc>;
- interrupts = <56>;
+ interrupts = <56>, <54>;
+ interrupt-names = "upg_main", "upg_bsc";
+ };
+
+ upg_aon_irq0_intc: upg_aon_irq0_intc@408b80 {
+ compatible = "brcm,bcm7120-l2-intc";
+ reg = <0x408b80 0x8>;
+
+ brcm,int-map-mask = <0x40>, <0x8000000>, <0x100000>;
+ brcm,int-fwd-mask = <0>;
+ brcm,irq-can-wake;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <57>, <55>, <59>;
+ interrupt-names = "upg_main_aon", "upg_bsc_aon",
+ "upg_spi";
};
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7362-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
@@ -144,6 +161,36 @@
status = "disabled";
};
+ bsca: i2c@406200 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406200 0x58>;
+ interrupts = <24>;
+ interrupt-names = "upg_bsca";
+ status = "disabled";
+ };
+
+ bscb: i2c@406280 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_irq0_intc>;
+ reg = <0x406280 0x58>;
+ interrupts = <25>;
+ interrupt-names = "upg_bscb";
+ status = "disabled";
+ };
+
+ bscd: i2c@408980 {
+ clock-frequency = <390000>;
+ compatible = "brcm,brcmstb-i2c";
+ interrupt-parent = <&upg_aon_irq0_intc>;
+ reg = <0x408980 0x58>;
+ interrupts = <27>;
+ interrupt-names = "upg_bscd";
+ status = "disabled";
+ };
+
enet0: ethernet@430000 {
phy-mode = "internal";
phy-handle = <&phy1>;
@@ -189,5 +236,47 @@
interrupts = <66>;
status = "disabled";
};
+
+ sata: sata@181000 {
+ compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci";
+ reg-names = "ahci", "top-ctrl";
+ reg = <0x181000 0xa9c>, <0x180020 0x1c>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <86>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ brcm,broken-ncq;
+ brcm,broken-phy;
+ status = "disabled";
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy1>;
+ };
+ };
+
+ sata_phy: sata-phy@1800000 {
+ compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3";
+ reg = <0x180100 0x0eff>;
+ reg-names = "phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ sata_phy0: sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ sata_phy1: sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
};
};
diff --git a/arch/mips/boot/dts/brcm/bcm7420.dtsi b/arch/mips/boot/dts/brcm/bcm7420.dtsi
index 5f55d0a..bee221b 100644
--- a/arch/mips/boot/dts/brcm/bcm7420.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7420.dtsi
@@ -99,7 +99,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7420-sun-top-ctrl", "syscon";
reg = <0x404000 0x60c>;
- little-endian;
};
reboot {
diff --git a/arch/mips/boot/dts/brcm/bcm7425.dtsi b/arch/mips/boot/dts/brcm/bcm7425.dtsi
index 5b660b6..571f30f 100644
--- a/arch/mips/boot/dts/brcm/bcm7425.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7425.dtsi
@@ -100,7 +100,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
@@ -221,5 +220,47 @@
interrupts = <73>;
status = "disabled";
};
+
+ sata: sata@181000 {
+ compatible = "brcm,bcm7425-ahci", "brcm,sata3-ahci";
+ reg-names = "ahci", "top-ctrl";
+ reg = <0x181000 0xa9c>, <0x180020 0x1c>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ brcm,broken-ncq;
+ brcm,broken-phy;
+ status = "disabled";
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy0>;
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy1>;
+ };
+ };
+
+ sata_phy: sata-phy@1800000 {
+ compatible = "brcm,bcm7425-sata-phy", "brcm,phy-sata3";
+ reg = <0x180100 0x0eff>;
+ reg-names = "phy";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ sata_phy0: sata-phy@0 {
+ reg = <0>;
+ #phy-cells = <0>;
+ };
+
+ sata_phy1: sata-phy@1 {
+ reg = <1>;
+ #phy-cells = <0>;
+ };
+ };
};
};
diff --git a/arch/mips/boot/dts/brcm/bcm7435.dtsi b/arch/mips/boot/dts/brcm/bcm7435.dtsi
index 8b9432c..614ee21 100644
--- a/arch/mips/boot/dts/brcm/bcm7435.dtsi
+++ b/arch/mips/boot/dts/brcm/bcm7435.dtsi
@@ -114,7 +114,6 @@
sun_top_ctrl: syscon@404000 {
compatible = "brcm,bcm7425-sun-top-ctrl", "syscon";
reg = <0x404000 0x51c>;
- little-endian;
};
reboot {
diff --git a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts
index 3fe0445..d3d2881 100644
--- a/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts
+++ b/arch/mips/boot/dts/brcm/bcm97346dbsmb.dts
@@ -29,6 +29,26 @@
status = "okay";
};
+&bsca {
+ status = "okay";
+};
+
+&bscb {
+ status = "okay";
+};
+
+&bscc {
+ status = "okay";
+};
+
+&bscd {
+ status = "okay";
+};
+
+&bsce {
+ status = "okay";
+};
+
&enet0 {
status = "okay";
};
@@ -64,3 +84,11 @@
&ohci3 {
status = "okay";
};
+
+&sata {
+ status = "okay";
+};
+
+&sata_phy {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/brcm/bcm97358svmb.dts b/arch/mips/boot/dts/brcm/bcm97358svmb.dts
index a8dc01e..02ce6b4 100644
--- a/arch/mips/boot/dts/brcm/bcm97358svmb.dts
+++ b/arch/mips/boot/dts/brcm/bcm97358svmb.dts
@@ -29,6 +29,22 @@
status = "okay";
};
+&bsca {
+ status = "okay";
+};
+
+&bscb {
+ status = "okay";
+};
+
+&bscc {
+ status = "okay";
+};
+
+&bscd {
+ status = "okay";
+};
+
&enet0 {
status = "okay";
};
diff --git a/arch/mips/boot/dts/brcm/bcm97360svmb.dts b/arch/mips/boot/dts/brcm/bcm97360svmb.dts
index eee8b0e..d48462e 100644
--- a/arch/mips/boot/dts/brcm/bcm97360svmb.dts
+++ b/arch/mips/boot/dts/brcm/bcm97360svmb.dts
@@ -29,6 +29,22 @@
status = "okay";
};
+&bsca {
+ status = "okay";
+};
+
+&bscb {
+ status = "okay";
+};
+
+&bscc {
+ status = "okay";
+};
+
+&bscd {
+ status = "okay";
+};
+
&enet0 {
status = "okay";
};
diff --git a/arch/mips/boot/dts/brcm/bcm97362svmb.dts b/arch/mips/boot/dts/brcm/bcm97362svmb.dts
index 739c2ef..3cfcaeb 100644
--- a/arch/mips/boot/dts/brcm/bcm97362svmb.dts
+++ b/arch/mips/boot/dts/brcm/bcm97362svmb.dts
@@ -29,6 +29,18 @@
status = "okay";
};
+&bsca {
+ status = "okay";
+};
+
+&bscb {
+ status = "okay";
+};
+
+&bscd {
+ status = "okay";
+};
+
&enet0 {
status = "okay";
};
@@ -40,3 +52,11 @@
&ohci0 {
status = "okay";
};
+
+&sata {
+ status = "okay";
+};
+
+&sata_phy {
+ status = "okay";
+};
diff --git a/arch/mips/boot/dts/mti/malta.dts b/arch/mips/boot/dts/mti/malta.dts
index c678115..b18c466 100644
--- a/arch/mips/boot/dts/mti/malta.dts
+++ b/arch/mips/boot/dts/mti/malta.dts
@@ -1,5 +1,9 @@
/dts-v1/;
+/memreserve/ 0x00000000 0x00001000; /* YAMON exception vectors */
+/memreserve/ 0x00001000 0x000ef000; /* YAMON */
+/memreserve/ 0x000f0000 0x00010000; /* PIIX4 ISA memory */
+
/ {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/mips/boot/dts/qca/ar9132.dtsi b/arch/mips/boot/dts/qca/ar9132.dtsi
index fb7734e..13d0439 100644
--- a/arch/mips/boot/dts/qca/ar9132.dtsi
+++ b/arch/mips/boot/dts/qca/ar9132.dtsi
@@ -107,7 +107,7 @@
miscintc: interrupt-controller@18060010 {
compatible = "qca,ar9132-misc-intc",
"qca,ar7100-misc-intc";
- reg = <0x18060010 0x4>;
+ reg = <0x18060010 0x8>;
interrupt-parent = <&cpuintc>;
interrupts = <6>;
diff --git a/arch/mips/boot/dts/xilfpga/Makefile b/arch/mips/boot/dts/xilfpga/Makefile
new file mode 100644
index 0000000..913a752
--- /dev/null
+++ b/arch/mips/boot/dts/xilfpga/Makefile
@@ -0,0 +1,9 @@
+dtb-$(CONFIG_XILFPGA_NEXYS4DDR) += nexys4ddr.dtb
+
+obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
+
+# Force kbuild to make empty built-in.o if necessary
+obj- += dummy.o
+
+always := $(dtb-y)
+clean-files := *.dtb *.dtb.S
diff --git a/arch/mips/boot/dts/xilfpga/microAptiv.dtsi b/arch/mips/boot/dts/xilfpga/microAptiv.dtsi
new file mode 100644
index 0000000..81d518e
--- /dev/null
+++ b/arch/mips/boot/dts/xilfpga/microAptiv.dtsi
@@ -0,0 +1,21 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "img,xilfpga";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "mips,m14Kc";
+ clocks = <&ext>;
+ reg = <0>;
+ };
+ };
+
+ ext: ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ };
+};
diff --git a/arch/mips/boot/dts/xilfpga/nexys4ddr.dts b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
new file mode 100644
index 0000000..686ebd1
--- /dev/null
+++ b/arch/mips/boot/dts/xilfpga/nexys4ddr.dts
@@ -0,0 +1,46 @@
+/dts-v1/;
+
+#include "microAptiv.dtsi"
+
+/ {
+ compatible = "digilent,nexys4ddr";
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x08000000>;
+ };
+
+ cpuintc: interrupt-controller@0 {
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ compatible = "mti,cpu-interrupt-controller";
+ };
+
+ axi_gpio: gpio@10600000 {
+ #gpio-cells = <1>;
+ compatible = "xlnx,xps-gpio-1.00.a";
+ gpio-controller;
+ reg = <0x10600000 0x10000>;
+ xlnx,all-inputs = <0x0>;
+ xlnx,dout-default = <0x0>;
+ xlnx,gpio-width = <0x16>;
+ xlnx,interrupt-present = <0x0>;
+ xlnx,is-dual = <0x0>;
+ xlnx,tri-default = <0xffffffff>;
+ } ;
+
+ axi_uart16550: serial@10400000 {
+ compatible = "ns16550a";
+ reg = <0x10400000 0x10000>;
+
+ reg-shift = <2>;
+ reg-offset = <0x1000>;
+
+ clocks = <&ext>;
+ };
+};
+
+&ext {
+ clock-frequency = <50000000>;
+};
diff --git a/arch/mips/cavium-octeon/setup.c b/arch/mips/cavium-octeon/setup.c
index bd63425..cd7101f 100644
--- a/arch/mips/cavium-octeon/setup.c
+++ b/arch/mips/cavium-octeon/setup.c
@@ -1081,6 +1081,7 @@ void __init prom_free_prom_memory(void)
int octeon_prune_device_tree(void);
+extern const char __appended_dtb;
extern const char __dtb_octeon_3xxx_begin;
extern const char __dtb_octeon_68xx_begin;
void __init device_tree_init(void)
@@ -1088,11 +1089,19 @@ void __init device_tree_init(void)
const void *fdt;
bool do_prune;
+#ifdef CONFIG_MIPS_ELF_APPENDED_DTB
+ if (!fdt_check_header(&__appended_dtb)) {
+ fdt = &__appended_dtb;
+ do_prune = false;
+ pr_info("Using appended Device Tree.\n");
+ } else
+#endif
if (octeon_bootinfo->minor_version >= 3 && octeon_bootinfo->fdt_addr) {
fdt = phys_to_virt(octeon_bootinfo->fdt_addr);
if (fdt_check_header(fdt))
panic("Corrupt Device Tree passed to kernel.");
do_prune = false;
+ pr_info("Using passed Device Tree.\n");
} else if (OCTEON_IS_MODEL(OCTEON_CN68XX)) {
fdt = &__dtb_octeon_68xx_begin;
do_prune = true;
@@ -1106,8 +1115,6 @@ void __init device_tree_init(void)
if (do_prune) {
octeon_prune_device_tree();
pr_info("Using internal Device Tree.\n");
- } else {
- pr_info("Using passed Device Tree.\n");
}
unflatten_and_copy_device_tree();
}
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 1cdff6b..b3e7a1b 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -122,20 +122,20 @@ CONFIG_EEPROM_MAX6875=y
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
CONFIG_BLK_DEV_IDETAPE=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
-CONFIG_BLK_DEV_IT8213=m
CONFIG_BLK_DEV_TC86C001=m
CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
CONFIG_CHR_DEV_SCH=m
CONFIG_ATA=y
CONFIG_SATA_SIL24=y
+CONFIG_PATA_CMD64X=y
+CONFIG_PATA_IT8213=m
CONFIG_PATA_SIL680=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
diff --git a/arch/mips/configs/bmips_be_defconfig b/arch/mips/configs/bmips_be_defconfig
index f5585c8..24dcb90 100644
--- a/arch/mips/configs/bmips_be_defconfig
+++ b/arch/mips/configs/bmips_be_defconfig
@@ -8,7 +8,7 @@ CONFIG_MIPS_O32_FP64_SUPPORT=y
# CONFIG_SWAP is not set
CONFIG_NO_HZ=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_RD_GZIP is not set
+CONFIG_RD_GZIP=y
CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_SLUB_DEBUG is not set
@@ -33,6 +33,7 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_PRINTK_TIME=y
CONFIG_BRCMSTB_GISB_ARB=y
CONFIG_MTD=y
CONFIG_MTD_CFI=y
diff --git a/arch/mips/configs/bmips_stb_defconfig b/arch/mips/configs/bmips_stb_defconfig
index 400a47e..4eb5d6e 100644
--- a/arch/mips/configs/bmips_stb_defconfig
+++ b/arch/mips/configs/bmips_stb_defconfig
@@ -9,7 +9,7 @@ CONFIG_MIPS_O32_FP64_SUPPORT=y
# CONFIG_SWAP is not set
CONFIG_NO_HZ=y
CONFIG_BLK_DEV_INITRD=y
-# CONFIG_RD_GZIP is not set
+CONFIG_RD_GZIP=y
CONFIG_EXPERT=y
# CONFIG_VM_EVENT_COUNTERS is not set
# CONFIG_SLUB_DEBUG is not set
@@ -34,6 +34,7 @@ CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_PRINTK_TIME=y
CONFIG_BRCMSTB_GISB_ARB=y
CONFIG_MTD=y
CONFIG_MTD_CFI=y
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index 5135dc0..2924ba3 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -31,9 +31,9 @@ CONFIG_NETWORK_SECMARK=y
CONFIG_IP_SCTP=m
CONFIG_FW_LOADER=m
CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
CONFIG_NETDEVICES=y
CONFIG_PHYLIB=m
CONFIG_MARVELL_PHY=m
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index 0126e66..e94d266 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -14,9 +14,9 @@ CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_BLK_DEV_RAM=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_KEYBOARD is not set
# CONFIG_INPUT_MOUSE is not set
diff --git a/arch/mips/configs/fuloong2e_defconfig b/arch/mips/configs/fuloong2e_defconfig
index a75c65d..8743589 100644
--- a/arch/mips/configs/fuloong2e_defconfig
+++ b/arch/mips/configs/fuloong2e_defconfig
@@ -34,7 +34,7 @@ CONFIG_MIPS32_N32=y
CONFIG_PM=y
# CONFIG_SUSPEND is not set
CONFIG_HIBERNATION=y
-CONFIG_PM_STD_PARTITION="/dev/hda3"
+CONFIG_PM_STD_PARTITION="/dev/sda3"
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -114,20 +114,16 @@ CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_RAM=m
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_TASK_IOCTL=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_VIA82CXXX=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_PATA_VIA=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_NETDEVICES=y
CONFIG_MACVLAN=m
CONFIG_VETH=m
diff --git a/arch/mips/configs/lasat_defconfig b/arch/mips/configs/lasat_defconfig
index 0179c7f..e620a2c 100644
--- a/arch/mips/configs/lasat_defconfig
+++ b/arch/mips/configs/lasat_defconfig
@@ -35,11 +35,11 @@ CONFIG_MTD_CHAR=y
CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_AMDSTD=y
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_CMD64X=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_CMD64X=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_NET_PCI=y
diff --git a/arch/mips/configs/lemote2f_defconfig b/arch/mips/configs/lemote2f_defconfig
index 54cc385..004cf52 100644
--- a/arch/mips/configs/lemote2f_defconfig
+++ b/arch/mips/configs/lemote2f_defconfig
@@ -108,16 +108,11 @@ CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_TASK_IOCTL=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_AMD74XX=y
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=m
-CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_PATA_AMD=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 61a4460..5afb484 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -241,14 +241,11 @@ CONFIG_BLK_DEV_NBD=m
CONFIG_BLK_DEV_RAM=y
CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
CONFIG_RAID_ATTRS=m
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_CONSTANTS=y
@@ -265,6 +262,7 @@ CONFIG_AIC7XXX_RESET_DELAY_MS=15000
# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
CONFIG_ATA=y
CONFIG_ATA_PIIX=y
+CONFIG_PATA_LEGACY=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
diff --git a/arch/mips/configs/malta_kvm_defconfig b/arch/mips/configs/malta_kvm_defconfig
index d41742d..98f1387 100644
--- a/arch/mips/configs/malta_kvm_defconfig
+++ b/arch/mips/configs/malta_kvm_defconfig
@@ -248,17 +248,12 @@ CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
CONFIG_BLK_DEV_TC86C001=m
CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_MULTI_LUN=y
@@ -274,6 +269,13 @@ CONFIG_SCSI_AACRAID=m
CONFIG_SCSI_AIC7XXX=m
CONFIG_AIC7XXX_RESET_DELAY_MS=15000
# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
diff --git a/arch/mips/configs/malta_kvm_guest_defconfig b/arch/mips/configs/malta_kvm_guest_defconfig
index a7806e8..3b5d591 100644
--- a/arch/mips/configs/malta_kvm_guest_defconfig
+++ b/arch/mips/configs/malta_kvm_guest_defconfig
@@ -248,17 +248,12 @@ CONFIG_ATA_OVER_ETH=m
CONFIG_VIRTIO_BLK=y
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
CONFIG_BLK_DEV_TC86C001=m
CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_MULTI_LUN=y
@@ -274,6 +269,13 @@ CONFIG_SCSI_AACRAID=m
CONFIG_SCSI_AIC7XXX=m
CONFIG_AIC7XXX_RESET_DELAY_MS=15000
# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
diff --git a/arch/mips/configs/malta_qemu_32r6_defconfig b/arch/mips/configs/malta_qemu_32r6_defconfig
index 4bce1f8..7f50dd6 100644
--- a/arch/mips/configs/malta_qemu_32r6_defconfig
+++ b/arch/mips/configs/malta_qemu_32r6_defconfig
@@ -80,15 +80,14 @@ CONFIG_NET_CLS_IND=y
CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
diff --git a/arch/mips/configs/maltaaprp_defconfig b/arch/mips/configs/maltaaprp_defconfig
index fb042ce..a9d433a 100644
--- a/arch/mips/configs/maltaaprp_defconfig
+++ b/arch/mips/configs/maltaaprp_defconfig
@@ -81,15 +81,14 @@ CONFIG_NET_CLS_IND=y
CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
diff --git a/arch/mips/configs/maltasmvp_eva_defconfig b/arch/mips/configs/maltasmvp_eva_defconfig
index c83338a..2774ef0 100644
--- a/arch/mips/configs/maltasmvp_eva_defconfig
+++ b/arch/mips/configs/maltasmvp_eva_defconfig
@@ -85,15 +85,14 @@ CONFIG_NET_CLS_IND=y
CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
diff --git a/arch/mips/configs/maltaup_defconfig b/arch/mips/configs/maltaup_defconfig
index 6234464..9bbd221 100644
--- a/arch/mips/configs/maltaup_defconfig
+++ b/arch/mips/configs/maltaup_defconfig
@@ -80,15 +80,14 @@ CONFIG_NET_CLS_IND=y
CONFIG_DEVTMPFS=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_IDE=y
-# CONFIG_IDE_PROC_FS is not set
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
CONFIG_NETDEVICES=y
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_NET_VENDOR_ADAPTEC is not set
diff --git a/arch/mips/configs/maltaup_xpa_defconfig b/arch/mips/configs/maltaup_xpa_defconfig
index c388bff..7322157 100644
--- a/arch/mips/configs/maltaup_xpa_defconfig
+++ b/arch/mips/configs/maltaup_xpa_defconfig
@@ -244,17 +244,12 @@ CONFIG_CDROM_PKTCDVD=m
CONFIG_ATA_OVER_ETH=m
CONFIG_IDE=y
CONFIG_BLK_DEV_IDECD=y
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_GENERIC=y
-CONFIG_BLK_DEV_PIIX=y
-CONFIG_BLK_DEV_IT8213=m
CONFIG_BLK_DEV_TC86C001=m
CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=m
-CONFIG_BLK_DEV_SD=m
+CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_ST=m
CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
CONFIG_SCSI_CONSTANTS=y
@@ -269,6 +264,13 @@ CONFIG_SCSI_AACRAID=m
CONFIG_SCSI_AIC7XXX=m
CONFIG_AIC7XXX_RESET_DELAY_MS=15000
# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_ATA=y
+CONFIG_ATA_PIIX=y
+CONFIG_PATA_IT8213=m
+CONFIG_PATA_OLDPIIX=y
+CONFIG_PATA_MPIIX=y
+CONFIG_ATA_GENERIC=y
+CONFIG_PATA_LEGACY=y
CONFIG_MD=y
CONFIG_BLK_DEV_MD=m
CONFIG_MD_LINEAR=m
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index 7a34660..a2c045f 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -27,9 +27,9 @@ CONFIG_INET_XFRM_MODE_BEET=m
CONFIG_NETWORK_SECMARK=y
CONFIG_CONNECTOR=m
CONFIG_ATA_OVER_ETH=m
-# CONFIG_MISC_DEVICES is not set
-CONFIG_IDE=y
-CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_SD=y
+CONFIG_ATA=y
+CONFIG_PATA_LEGACY=y
CONFIG_NETDEVICES=y
# CONFIG_NETDEV_1000 is not set
# CONFIG_NETDEV_10000 is not set
diff --git a/arch/mips/configs/xilfpga_defconfig b/arch/mips/configs/xilfpga_defconfig
new file mode 100644
index 0000000..ed1dce3
--- /dev/null
+++ b/arch/mips/configs/xilfpga_defconfig
@@ -0,0 +1,40 @@
+CONFIG_MACH_XILFPGA=y
+# CONFIG_COMPACTION is not set
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_BLOCK is not set
+# CONFIG_SUSPEND is not set
+# CONFIG_UEVENT_HELPER is not set
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_ALLOW_DEV_COREDUMP is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_UNIX98_PTYS is not set
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIO_XILINX=y
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_MIPS_PLATFORM_DEVICES is not set
+# CONFIG_IOMMU_SUPPORT is not set
+# CONFIG_PROC_PAGE_MONITOR is not set
+# CONFIG_MISC_FILESYSTEMS is not set
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_FTRACE is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200"
diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h
index 37f8407..9407608 100644
--- a/arch/mips/include/asm/abi.h
+++ b/arch/mips/include/asm/abi.h
@@ -11,19 +11,20 @@
#include <asm/signal.h>
#include <asm/siginfo.h>
+#include <asm/vdso.h>
struct mips_abi {
int (* const setup_frame)(void *sig_return, struct ksignal *ksig,
struct pt_regs *regs, sigset_t *set);
- const unsigned long signal_return_offset;
int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig,
struct pt_regs *regs, sigset_t *set);
- const unsigned long rt_signal_return_offset;
const unsigned long restart;
unsigned off_sc_fpregs;
unsigned off_sc_fpc_csr;
unsigned off_sc_used_math;
+
+ struct mips_vdso_image *vdso;
};
#endif /* _ASM_ABI_H */
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
index f82d3af..835b402 100644
--- a/arch/mips/include/asm/atomic.h
+++ b/arch/mips/include/asm/atomic.h
@@ -507,7 +507,7 @@ static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v)
* @u: ...unless v is equal to u.
*
* Atomically adds @a to @v, so long as it was not @u.
- * Returns the old value of @v.
+ * Returns true iff @v was not @u.
*/
static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
{
diff --git a/arch/mips/include/asm/bcache.h b/arch/mips/include/asm/bcache.h
index 8c34484..a00857b 100644
--- a/arch/mips/include/asm/bcache.h
+++ b/arch/mips/include/asm/bcache.h
@@ -9,6 +9,7 @@
#ifndef _ASM_BCACHE_H
#define _ASM_BCACHE_H
+#include <linux/types.h>
/* Some R4000 / R4400 / R4600 / R5000 machines may have a non-dma-coherent,
chipset implemented caches. On machines with other CPUs the CPU does the
@@ -18,6 +19,9 @@ struct bcache_ops {
void (*bc_disable)(void);
void (*bc_wback_inv)(unsigned long page, unsigned long size);
void (*bc_inv)(unsigned long page, unsigned long size);
+ void (*bc_prefetch_enable)(void);
+ void (*bc_prefetch_disable)(void);
+ bool (*bc_prefetch_is_enabled)(void);
};
extern void indy_sc_init(void);
@@ -46,6 +50,26 @@ static inline void bc_inv(unsigned long page, unsigned long size)
bcops->bc_inv(page, size);
}
+static inline void bc_prefetch_enable(void)
+{
+ if (bcops->bc_prefetch_enable)
+ bcops->bc_prefetch_enable();
+}
+
+static inline void bc_prefetch_disable(void)
+{
+ if (bcops->bc_prefetch_disable)
+ bcops->bc_prefetch_disable();
+}
+
+static inline bool bc_prefetch_is_enabled(void)
+{
+ if (bcops->bc_prefetch_is_enabled)
+ return bcops->bc_prefetch_is_enabled();
+
+ return false;
+}
+
#else /* !defined(CONFIG_BOARD_SCACHE) */
/* Not R4000 / R4400 / R4600 / R5000. */
@@ -54,6 +78,9 @@ static inline void bc_inv(unsigned long page, unsigned long size)
#define bc_disable() do { } while (0)
#define bc_wback_inv(page, size) do { } while (0)
#define bc_inv(page, size) do { } while (0)
+#define bc_prefetch_enable() do { } while (0)
+#define bc_prefetch_disable() do { } while (0)
+#define bc_prefetch_is_enabled() 0
#endif /* !defined(CONFIG_BOARD_SCACHE) */
diff --git a/arch/mips/include/asm/cdmm.h b/arch/mips/include/asm/cdmm.h
index bece206..c06dbf8b 100644
--- a/arch/mips/include/asm/cdmm.h
+++ b/arch/mips/include/asm/cdmm.h
@@ -84,6 +84,17 @@ void mips_cdmm_driver_unregister(struct mips_cdmm_driver *);
module_driver(__mips_cdmm_driver, mips_cdmm_driver_register, \
mips_cdmm_driver_unregister)
+/*
+ * builtin_mips_cdmm_driver() - Helper macro for drivers that don't do anything
+ * special in init and have no exit. This eliminates some boilerplate. Each
+ * driver may only use this macro once, and calling it replaces device_initcall
+ * (or in some cases, the legacy __initcall). This is meant to be a direct
+ * parallel of module_mips_cdmm_driver() above but without the __exit stuff that
+ * is not used for builtin cases.
+ */
+#define builtin_mips_cdmm_driver(__mips_cdmm_driver) \
+ builtin_driver(__mips_cdmm_driver, mips_cdmm_driver_register)
+
/* drivers/tty/mips_ejtag_fdc.c */
#ifdef CONFIG_MIPS_EJTAG_FDC_EARLYCON
diff --git a/arch/mips/include/asm/clocksource.h b/arch/mips/include/asm/clocksource.h
new file mode 100644
index 0000000..3deb1d0
--- /dev/null
+++ b/arch/mips/include/asm/clocksource.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_CLOCKSOURCE_H
+#define __ASM_CLOCKSOURCE_H
+
+#include <linux/types.h>
+
+/* VDSO clocksources. */
+#define VDSO_CLOCK_NONE 0 /* No suitable clocksource. */
+#define VDSO_CLOCK_R4K 1 /* Use the coprocessor 0 count. */
+#define VDSO_CLOCK_GIC 2 /* Use the GIC. */
+
+/**
+ * struct arch_clocksource_data - Architecture-specific clocksource information.
+ * @vdso_clock_mode: Method the VDSO should use to access the clocksource.
+ */
+struct arch_clocksource_data {
+ u8 vdso_clock_mode;
+};
+
+#endif /* __ASM_CLOCKSOURCE_H */
diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
index c4bd54a..a958009 100644
--- a/arch/mips/include/asm/compat.h
+++ b/arch/mips/include/asm/compat.h
@@ -130,6 +130,8 @@ typedef union compat_sigval {
compat_uptr_t sival_ptr;
} compat_sigval_t;
+/* Can't use the generic version because si_code and si_errno are swapped */
+
#define SI_PAD_SIZE32 (128/sizeof(int) - 3)
typedef struct compat_siginfo {
@@ -138,57 +140,61 @@ typedef struct compat_siginfo {
int si_errno;
union {
- int _pad[SI_PAD_SIZE32];
+ int _pad[128 / sizeof(int) - 3];
/* kill() */
struct {
compat_pid_t _pid; /* sender's pid */
- __compat_uid_t _uid; /* sender's uid */
+ __compat_uid32_t _uid; /* sender's uid */
} _kill;
+ /* POSIX.1b timers */
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ compat_sigval_t _sigval; /* same as below */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ compat_pid_t _pid; /* sender's pid */
+ __compat_uid32_t _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
/* SIGCHLD */
struct {
compat_pid_t _pid; /* which child */
- __compat_uid_t _uid; /* sender's uid */
+ __compat_uid32_t _uid; /* sender's uid */
int _status; /* exit code */
compat_clock_t _utime;
compat_clock_t _stime;
} _sigchld;
- /* IRIX SIGCHLD */
- struct {
- compat_pid_t _pid; /* which child */
- compat_clock_t _utime;
- int _status; /* exit code */
- compat_clock_t _stime;
- } _irix_sigchld;
-
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct {
- s32 _addr; /* faulting insn/memory ref. */
+ compat_uptr_t _addr; /* faulting insn/memory ref. */
+#ifdef __ARCH_SI_TRAPNO
+ int _trapno; /* TRAP # which caused the signal */
+#endif
+ short _addr_lsb; /* LSB of the reported address */
+ struct {
+ compat_uptr_t _lower;
+ compat_uptr_t _upper;
+ } _addr_bnd;
} _sigfault;
- /* SIGPOLL, SIGXFSZ (To do ...) */
+ /* SIGPOLL */
struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
- /* POSIX.1b timers */
- struct {
- timer_t _tid; /* timer id */
- int _overrun; /* overrun count */
- compat_sigval_t _sigval;/* same as below */
- int _sys_private; /* not to be passed to user */
- } _timer;
-
- /* POSIX.1b signals */
struct {
- compat_pid_t _pid; /* sender's pid */
- __compat_uid_t _uid; /* sender's uid */
- compat_sigval_t _sigval;
- } _rt;
-
+ compat_uptr_t _call_addr; /* calling insn */
+ int _syscall; /* triggering system call number */
+ compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */
+ } _sigsys;
} _sifields;
} compat_siginfo_t;
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h
index fe67f12..d1e04c9 100644
--- a/arch/mips/include/asm/cpu-features.h
+++ b/arch/mips/include/asm/cpu-features.h
@@ -131,11 +131,7 @@
#endif
#ifndef cpu_has_rixi
-# ifdef CONFIG_64BIT
-# define cpu_has_rixi (cpu_data[0].options & MIPS_CPU_RIXI)
-# else /* CONFIG_32BIT */
-# define cpu_has_rixi ((cpu_data[0].options & MIPS_CPU_RIXI) && !cpu_has_64bits)
-# endif
+#define cpu_has_rixi (cpu_data[0].options & MIPS_CPU_RIXI)
#endif
#ifndef cpu_has_mmips
diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h
new file mode 100644
index 0000000..254f00d
--- /dev/null
+++ b/arch/mips/include/asm/debug.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_DEBUG_H__
+#define __MIPS_ASM_DEBUG_H__
+
+#include <linux/dcache.h>
+
+/*
+ * mips_debugfs_dir corresponds to the "mips" directory at the top level
+ * of the DebugFS hierarchy. MIPS-specific DebugFS entires should be
+ * placed beneath this directory.
+ */
+extern struct dentry *mips_debugfs_dir;
+
+#endif /* __MIPS_ASM_DEBUG_H__ */
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index 53b2693..b01a6ff 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -8,6 +8,7 @@
#ifndef _ASM_ELF_H
#define _ASM_ELF_H
+#include <linux/auxvec.h>
#include <linux/fs.h>
#include <uapi/linux/elf.h>
@@ -419,6 +420,12 @@ extern const char *__elf_platform;
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
#endif
+#define ARCH_DLINFO \
+do { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, \
+ (unsigned long)current->mm->context.vdso); \
+} while (0)
+
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
struct linux_binprm;
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
diff --git a/arch/mips/include/asm/fw/fw.h b/arch/mips/include/asm/fw/fw.h
index f3e6978..d0ef8b4 100644
--- a/arch/mips/include/asm/fw/fw.h
+++ b/arch/mips/include/asm/fw/fw.h
@@ -10,21 +10,6 @@
#include <asm/bootinfo.h> /* For cleaner code... */
-enum fw_memtypes {
- fw_dontuse,
- fw_code,
- fw_free,
-};
-
-typedef struct {
- unsigned long base; /* Within KSEG0 */
- unsigned int size; /* bytes */
- enum fw_memtypes type; /* fw_memtypes */
-} fw_memblock_t;
-
-/* Maximum number of memory block descriptors. */
-#define FW_MAX_MEMBLOCKS 32
-
extern int fw_argc;
extern int *_fw_argv;
extern int *_fw_envp;
@@ -38,7 +23,6 @@ extern int *_fw_envp;
extern void fw_init_cmdline(void);
extern char *fw_getcmdline(void);
-extern fw_memblock_t *fw_getmdesc(int);
extern void fw_meminit(void);
extern char *fw_getenv(char *name);
extern unsigned long fw_getenvl(char *name);
diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
index 1461c10..71e4096 100644
--- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
+++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
@@ -48,11 +48,6 @@ extern enum bcm47xx_bus_type bcm47xx_bus_type;
void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
bool fallback);
-#ifdef CONFIG_BCM47XX_SSB
-void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
- const char *prefix);
-#endif
-
void bcm47xx_set_system_type(u16 chip_id);
#endif /* __ASM_BCM47XX_H */
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
index 133336b..dd6005b 100644
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -35,6 +35,17 @@
#define SOC_ID_VRX268_2 0x00C /* v1.2 */
#define SOC_ID_GRX288_2 0x00D /* v1.2 */
#define SOC_ID_GRX282_2 0x00E /* v1.2 */
+#define SOC_ID_VRX220 0x000
+
+#define SOC_ID_ARX362 0x004
+#define SOC_ID_ARX368 0x005
+#define SOC_ID_ARX382 0x007
+#define SOC_ID_ARX388 0x008
+#define SOC_ID_URX388 0x009
+#define SOC_ID_GRX383 0x010
+#define SOC_ID_GRX369 0x011
+#define SOC_ID_GRX387 0x00F
+#define SOC_ID_GRX389 0x012
/* SoC Types */
#define SOC_TYPE_DANUBE 0x01
@@ -43,6 +54,9 @@
#define SOC_TYPE_VR9 0x04 /* v1.1 */
#define SOC_TYPE_VR9_2 0x05 /* v1.2 */
#define SOC_TYPE_AMAZON_SE 0x06
+#define SOC_TYPE_AR10 0x07
+#define SOC_TYPE_GRX390 0x08
+#define SOC_TYPE_VRX220 0x09
/* BOOT_SEL - find what boot media we have */
#define BS_EXT_ROM 0x0
diff --git a/arch/mips/include/asm/mach-malta/malta-dtshim.h b/arch/mips/include/asm/mach-malta/malta-dtshim.h
new file mode 100644
index 0000000..cfd7776
--- /dev/null
+++ b/arch/mips/include/asm/mach-malta/malta-dtshim.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_MALTA_DTSHIM_H__
+#define __MIPS_MALTA_DTSHIM_H__
+
+#include <linux/init.h>
+
+#ifdef CONFIG_MIPS_MALTA
+
+extern void __init *malta_dt_shim(void *fdt);
+
+#else /* !CONFIG_MIPS_MALTA */
+
+static inline void *malta_dt_shim(void *fdt)
+{
+ return fdt;
+}
+
+#endif /* !CONFIG_MIPS_MALTA */
+
+#endif /* __MIPS_MALTA_DTSHIM_H__ */
diff --git a/arch/mips/include/asm/mach-ralink/mt7620.h b/arch/mips/include/asm/mach-ralink/mt7620.h
index 1976fb8..455d406 100644
--- a/arch/mips/include/asm/mach-ralink/mt7620.h
+++ b/arch/mips/include/asm/mach-ralink/mt7620.h
@@ -13,17 +13,11 @@
#ifndef _MT7620_REGS_H_
#define _MT7620_REGS_H_
-enum mt762x_soc_type {
- MT762X_SOC_UNKNOWN = 0,
- MT762X_SOC_MT7620A,
- MT762X_SOC_MT7620N,
- MT762X_SOC_MT7628AN,
-};
-
#define MT7620_SYSC_BASE 0x10000000
#define SYSC_REG_CHIP_NAME0 0x00
#define SYSC_REG_CHIP_NAME1 0x04
+#define SYSC_REG_EFUSE_CFG 0x08
#define SYSC_REG_CHIP_REV 0x0c
#define SYSC_REG_SYSTEM_CONFIG0 0x10
#define SYSC_REG_SYSTEM_CONFIG1 0x14
diff --git a/arch/mips/include/asm/mach-ralink/ralink_regs.h b/arch/mips/include/asm/mach-ralink/ralink_regs.h
index bd93014..4c9fba6 100644
--- a/arch/mips/include/asm/mach-ralink/ralink_regs.h
+++ b/arch/mips/include/asm/mach-ralink/ralink_regs.h
@@ -13,6 +13,23 @@
#ifndef _RALINK_REGS_H_
#define _RALINK_REGS_H_
+enum ralink_soc_type {
+ RALINK_UNKNOWN = 0,
+ RT2880_SOC,
+ RT3883_SOC,
+ RT305X_SOC_RT3050,
+ RT305X_SOC_RT3052,
+ RT305X_SOC_RT3350,
+ RT305X_SOC_RT3352,
+ RT305X_SOC_RT5350,
+ MT762X_SOC_MT7620A,
+ MT762X_SOC_MT7620N,
+ MT762X_SOC_MT7621AT,
+ MT762X_SOC_MT7628AN,
+ MT762X_SOC_MT7688,
+};
+extern enum ralink_soc_type ralink_soc;
+
extern __iomem void *rt_sysc_membase;
extern __iomem void *rt_memc_membase;
diff --git a/arch/mips/include/asm/mach-ralink/rt305x.h b/arch/mips/include/asm/mach-ralink/rt305x.h
index 96f731b..2eea793 100644
--- a/arch/mips/include/asm/mach-ralink/rt305x.h
+++ b/arch/mips/include/asm/mach-ralink/rt305x.h
@@ -13,25 +13,16 @@
#ifndef _RT305X_REGS_H_
#define _RT305X_REGS_H_
-enum rt305x_soc_type {
- RT305X_SOC_UNKNOWN = 0,
- RT305X_SOC_RT3050,
- RT305X_SOC_RT3052,
- RT305X_SOC_RT3350,
- RT305X_SOC_RT3352,
- RT305X_SOC_RT5350,
-};
-
-extern enum rt305x_soc_type rt305x_soc;
+extern enum ralink_soc_type ralink_soc;
static inline int soc_is_rt3050(void)
{
- return rt305x_soc == RT305X_SOC_RT3050;
+ return ralink_soc == RT305X_SOC_RT3050;
}
static inline int soc_is_rt3052(void)
{
- return rt305x_soc == RT305X_SOC_RT3052;
+ return ralink_soc == RT305X_SOC_RT3052;
}
static inline int soc_is_rt305x(void)
@@ -41,17 +32,17 @@ static inline int soc_is_rt305x(void)
static inline int soc_is_rt3350(void)
{
- return rt305x_soc == RT305X_SOC_RT3350;
+ return ralink_soc == RT305X_SOC_RT3350;
}
static inline int soc_is_rt3352(void)
{
- return rt305x_soc == RT305X_SOC_RT3352;
+ return ralink_soc == RT305X_SOC_RT3352;
}
static inline int soc_is_rt5350(void)
{
- return rt305x_soc == RT305X_SOC_RT5350;
+ return ralink_soc == RT305X_SOC_RT5350;
}
#define RT305X_SYSC_BASE 0x10000000
diff --git a/arch/mips/include/asm/mach-xilfpga/irq.h b/arch/mips/include/asm/mach-xilfpga/irq.h
new file mode 100644
index 0000000..0132a5b9
--- /dev/null
+++ b/arch/mips/include/asm/mach-xilfpga/irq.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __MIPS_ASM_MACH_XILFPGA_IRQ_H__
+#define __MIPS_ASM_MACH_XILFPGA_IRQ_H__
+
+#define NR_IRQS 32
+
+#include_next <irq.h>
+
+#endif /* __MIPS_ASM_MACH_XILFPGA_IRQ_H__ */
diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h
index 1f1927a..6516e9d 100644
--- a/arch/mips/include/asm/mips-cm.h
+++ b/arch/mips/include/asm/mips-cm.h
@@ -11,6 +11,7 @@
#ifndef __MIPS_ASM_MIPS_CM_H__
#define __MIPS_ASM_MIPS_CM_H__
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/types.h>
@@ -36,12 +37,12 @@ extern phys_addr_t __mips_cm_phys_base(void);
/*
* mips_cm_is64 - determine CM register width
*
- * The CM register width is processor and CM specific. A 64-bit processor
- * usually has a 64-bit CM and a 32-bit one has a 32-bit CM but a 64-bit
- * processor could come with a 32-bit CM. Moreover, accesses on 64-bit CMs
- * can be done either using regular 64-bit load/store instructions, or 32-bit
- * load/store instruction on 32-bit register pairs. We opt for using 64-bit
- * accesses on 64-bit CMs and kernels and 32-bit in any other case.
+ * The CM register width is determined by the version of the CM, with CM3
+ * introducing 64 bit GCRs and all prior CM versions having 32 bit GCRs.
+ * However we may run a kernel built for MIPS32 on a system with 64 bit GCRs,
+ * or vice-versa. This variable indicates the width of the memory accesses
+ * that the kernel will perform to GCRs, which may differ from the actual
+ * width of the GCRs.
*
* It's set to 0 for 32-bit accesses and 1 for 64-bit accesses.
*/
@@ -125,7 +126,17 @@ static inline u32 read32_gcr_##name(void) \
\
static inline u64 read64_gcr_##name(void) \
{ \
- return __raw_readq(addr_gcr_##name()); \
+ void __iomem *addr = addr_gcr_##name(); \
+ u64 ret; \
+ \
+ if (mips_cm_is64) { \
+ ret = __raw_readq(addr); \
+ } else { \
+ ret = __raw_readl(addr); \
+ ret |= (u64)__raw_readl(addr + 0x4) << 32; \
+ } \
+ \
+ return ret; \
} \
\
static inline unsigned long read_gcr_##name(void) \
@@ -195,6 +206,8 @@ BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0)
BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0)
BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130)
BUILD_CM_RW(sys_config2, MIPS_CM_GCB_OFS + 0x150)
+BUILD_CM_RW(l2_pft_control, MIPS_CM_GCB_OFS + 0x300)
+BUILD_CM_RW(l2_pft_control_b, MIPS_CM_GCB_OFS + 0x308)
/* Core Local & Core Other register accessor functions */
BUILD_CM_Cx_RW(reset_release, 0x00)
@@ -245,11 +258,14 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
((minor) << CM_GCR_REV_MINOR_SHF))
#define CM_REV_CM2 CM_ENCODE_REV(6, 0)
+#define CM_REV_CM2_5 CM_ENCODE_REV(7, 0)
#define CM_REV_CM3 CM_ENCODE_REV(8, 0)
/* GCR_ERROR_CAUSE register fields */
#define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27
#define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27)
+#define CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF 58
+#define CM3_GCR_ERROR_CAUSE_ERRTYPE_MSK GENMASK_ULL(63, 58)
#define CM_GCR_ERROR_CAUSE_ERRINFO_SHF 0
#define CM_GCR_ERROR_CAUSE_ERRINGO_MSK (_ULCAST_(0x7ffffff) << 0)
@@ -321,6 +337,20 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
#define CM_GCR_SYS_CONFIG2_MAXVPW_SHF 0
#define CM_GCR_SYS_CONFIG2_MAXVPW_MSK (_ULCAST_(0xf) << 0)
+/* GCR_L2_PFT_CONTROL register fields */
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_SHF 12
+#define CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK (_ULCAST_(0xfffff) << 12)
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_SHF 8
+#define CM_GCR_L2_PFT_CONTROL_PFTEN_MSK (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_NPFT_SHF 0
+#define CM_GCR_L2_PFT_CONTROL_NPFT_MSK (_ULCAST_(0xff) << 0)
+
+/* GCR_L2_PFT_CONTROL_B register fields */
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_SHF 8
+#define CM_GCR_L2_PFT_CONTROL_B_CEN_MSK (_ULCAST_(0x1) << 8)
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_SHF 0
+#define CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK (_ULCAST_(0xff) << 0)
+
/* GCR_Cx_COHERENCE register fields */
#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0
#define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0)
@@ -329,11 +359,15 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80)
#define CM_GCR_Cx_CONFIG_IOCUTYPE_SHF 10
#define CM_GCR_Cx_CONFIG_IOCUTYPE_MSK (_ULCAST_(0x3) << 10)
#define CM_GCR_Cx_CONFIG_PVPE_SHF 0
-#define CM_GCR_Cx_CONFIG_PVPE_MSK (_ULCAST_(0x1ff) << 0)
+#define CM_GCR_Cx_CONFIG_PVPE_MSK (_ULCAST_(0x3ff) << 0)
/* GCR_Cx_OTHER register fields */
#define CM_GCR_Cx_OTHER_CORENUM_SHF 16
#define CM_GCR_Cx_OTHER_CORENUM_MSK (_ULCAST_(0xffff) << 16)
+#define CM3_GCR_Cx_OTHER_CORE_SHF 8
+#define CM3_GCR_Cx_OTHER_CORE_MSK (_ULCAST_(0x3f) << 8)
+#define CM3_GCR_Cx_OTHER_VP_SHF 0
+#define CM3_GCR_Cx_OTHER_VP_MSK (_ULCAST_(0x7) << 0)
/* GCR_Cx_RESET_BASE register fields */
#define CM_GCR_Cx_RESET_BASE_BEVEXCBASE_SHF 12
@@ -444,4 +478,32 @@ static inline unsigned int mips_cm_vp_id(unsigned int cpu)
return (core * mips_cm_max_vp_width()) + vp;
}
+#ifdef CONFIG_MIPS_CM
+
+/**
+ * mips_cm_lock_other - lock access to another core
+ * @core: the other core to be accessed
+ * @vp: the VP within the other core to be accessed
+ *
+ * Call before operating upon a core via the 'other' register region in
+ * order to prevent the region being moved during access. Must be followed
+ * by a call to mips_cm_unlock_other.
+ */
+extern void mips_cm_lock_other(unsigned int core, unsigned int vp);
+
+/**
+ * mips_cm_unlock_other - unlock access to another core
+ *
+ * Call after operating upon another core via the 'other' register region.
+ * Must be called after mips_cm_lock_other.
+ */
+extern void mips_cm_unlock_other(void);
+
+#else /* !CONFIG_MIPS_CM */
+
+static inline void mips_cm_lock_other(unsigned int core) { }
+static inline void mips_cm_unlock_other(void) { }
+
+#endif /* !CONFIG_MIPS_CM */
+
#endif /* __MIPS_ASM_MIPS_CM_H__ */
diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h
index f386f32..e090352 100644
--- a/arch/mips/include/asm/mips-cpc.h
+++ b/arch/mips/include/asm/mips-cpc.h
@@ -149,7 +149,8 @@ BUILD_CPC_Cx_RW(other, 0x10)
* core: the other core to be accessed
*
* Call before operating upon a core via the 'other' register region in
- * order to prevent the region being moved during access. Must be followed
+ * order to prevent the region being moved during access. Must be called
+ * within the bounds of a mips_cm_{lock,unlock}_other pair, and followed
* by a call to mips_cpc_unlock_other.
*/
extern void mips_cpc_lock_other(unsigned int core);
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index c64781c..e43aca1 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -50,7 +50,9 @@
#define CP0_PAGEMASK $5
#define CP0_WIRED $6
#define CP0_INFO $7
+#define CP0_HWRENA $7, 0
#define CP0_BADVADDR $8
+#define CP0_BADINSTR $8, 1
#define CP0_COUNT $9
#define CP0_ENTRYHI $10
#define CP0_COMPARE $11
@@ -58,7 +60,11 @@
#define CP0_CAUSE $13
#define CP0_EPC $14
#define CP0_PRID $15
+#define CP0_EBASE $15, 1
+#define CP0_CMGCRBASE $15, 3
#define CP0_CONFIG $16
+#define CP0_CONFIG3 $16, 3
+#define CP0_CONFIG5 $16, 5
#define CP0_LLADDR $17
#define CP0_WATCHLO $18
#define CP0_WATCHHI $19
@@ -126,15 +132,9 @@
#define R3K_ENTRYLO_N (_ULCAST_(1) << 11)
/* MIPS32/64 EntryLo bit definitions */
-#ifdef CONFIG_64BIT
-/* as read by dmfc0 */
-#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62)
-#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63)
-#else
-/* as read by mfc0 */
-#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30)
-#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31)
-#endif
+#define MIPS_ENTRYLO_PFN_SHIFT 6
+#define MIPS_ENTRYLO_XI (_ULCAST_(1) << (BITS_PER_LONG - 2))
+#define MIPS_ENTRYLO_RI (_ULCAST_(1) << (BITS_PER_LONG - 1))
/*
* Values for PageMask register
diff --git a/arch/mips/include/asm/page.h b/arch/mips/include/asm/page.h
index 89dd7fe..2046c02 100644
--- a/arch/mips/include/asm/page.h
+++ b/arch/mips/include/asm/page.h
@@ -33,7 +33,7 @@
#define PAGE_SHIFT 16
#endif
#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK (~((1 << PAGE_SHIFT) - 1))
+#define PAGE_MASK (~(PAGE_SIZE - 1))
/*
* This is used for calculating the real page sizes
@@ -200,8 +200,9 @@ static inline int pfn_valid(unsigned long pfn)
{
/* avoid <linux/mm.h> include hell */
extern unsigned long max_mapnr;
+ unsigned long pfn_offset = ARCH_PFN_OFFSET;
- return pfn >= ARCH_PFN_OFFSET && pfn < max_mapnr;
+ return pfn >= pfn_offset && pfn < max_mapnr;
}
#elif defined(CONFIG_SPARSEMEM)
diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h
index 59ee6dc..3f832c3 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -36,12 +36,6 @@ extern unsigned int vced_count, vcei_count;
*/
#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
-/*
- * A special page (the vdso) is mapped into all processes at the very
- * top of the virtual memory space.
- */
-#define SPECIAL_PAGES_SIZE PAGE_SIZE
-
#ifdef CONFIG_32BIT
#ifdef CONFIG_KVM_GUEST
/* User space process size is limited to 1GB in KVM Guest Mode */
@@ -80,7 +74,7 @@ extern unsigned int vced_count, vcei_count;
#endif
-#define STACK_TOP ((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE)
+#define STACK_TOP (TASK_SIZE & PAGE_MASK)
/*
* This decides where the kernel will search for a free chunk of vm
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h
index 5305d69..095ecaf 100644
--- a/arch/mips/include/asm/uaccess.h
+++ b/arch/mips/include/asm/uaccess.h
@@ -599,7 +599,7 @@ extern void __put_user_unknown(void);
* On error, the variable @x is set to zero.
*/
#define __get_user_unaligned(x,ptr) \
- __get_user__unalignednocheck((x),(ptr),sizeof(*(ptr)))
+ __get_user_unaligned_nocheck((x),(ptr),sizeof(*(ptr)))
/*
* Yuck. We need two variants, one for 64bit operation and one
@@ -620,8 +620,8 @@ extern void __get_user_unaligned_unknown(void);
do { \
switch (size) { \
case 1: __get_data_asm(val, "lb", ptr); break; \
- case 2: __get_user_unaligned_asm(val, "ulh", ptr); break; \
- case 4: __get_user_unaligned_asm(val, "ulw", ptr); break; \
+ case 2: __get_data_unaligned_asm(val, "ulh", ptr); break; \
+ case 4: __get_data_unaligned_asm(val, "ulw", ptr); break; \
case 8: __GET_USER_UNALIGNED_DW(val, ptr); break; \
default: __get_user_unaligned_unknown(); break; \
} \
@@ -1122,9 +1122,15 @@ extern size_t __copy_in_user_eva(void *__to, const void *__from, size_t __n);
__cu_to = (to); \
__cu_from = (from); \
__cu_len = (n); \
- might_fault(); \
- __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
- __cu_len); \
+ if (eva_kernel_access()) { \
+ __cu_len = __invoke_copy_from_kernel(__cu_to, \
+ __cu_from, \
+ __cu_len); \
+ } else { \
+ might_fault(); \
+ __cu_len = __invoke_copy_from_user(__cu_to, __cu_from, \
+ __cu_len); \
+ } \
__cu_len; \
})
@@ -1229,16 +1235,28 @@ __clear_user(void __user *addr, __kernel_size_t size)
{
__kernel_size_t res;
- might_fault();
- __asm__ __volatile__(
- "move\t$4, %1\n\t"
- "move\t$5, $0\n\t"
- "move\t$6, %2\n\t"
- __MODULE_JAL(__bzero)
- "move\t%0, $6"
- : "=r" (res)
- : "r" (addr), "r" (size)
- : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ if (eva_kernel_access()) {
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, $0\n\t"
+ "move\t$6, %2\n\t"
+ __MODULE_JAL(__bzero_kernel)
+ "move\t%0, $6"
+ : "=r" (res)
+ : "r" (addr), "r" (size)
+ : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ } else {
+ might_fault();
+ __asm__ __volatile__(
+ "move\t$4, %1\n\t"
+ "move\t$5, $0\n\t"
+ "move\t$6, %2\n\t"
+ __MODULE_JAL(__bzero)
+ "move\t%0, $6"
+ : "=r" (res)
+ : "r" (addr), "r" (size)
+ : "$4", "$5", "$6", __UA_t0, __UA_t1, "$31");
+ }
return res;
}
@@ -1384,7 +1402,7 @@ static inline long strlen_user(const char __user *s)
might_fault();
__asm__ __volatile__(
"move\t$4, %1\n\t"
- __MODULE_JAL(__strlen_kernel_asm)
+ __MODULE_JAL(__strlen_user_asm)
"move\t%0, $2"
: "=r" (res)
: "r" (s)
diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h
index cca56aa..8f4ca5d 100644
--- a/arch/mips/include/asm/vdso.h
+++ b/arch/mips/include/asm/vdso.h
@@ -1,29 +1,136 @@
/*
- * 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) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
*
- * Copyright (C) 2009 Cavium Networks
+ * 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 __ASM_VDSO_H
#define __ASM_VDSO_H
-#include <linux/types.h>
+#include <linux/mm_types.h>
+#include <asm/barrier.h>
-#ifdef CONFIG_32BIT
-struct mips_vdso {
- u32 signal_trampoline[2];
- u32 rt_signal_trampoline[2];
+/**
+ * struct mips_vdso_image - Details of a VDSO image.
+ * @data: Pointer to VDSO image data (page-aligned).
+ * @size: Size of the VDSO image data (page-aligned).
+ * @off_sigreturn: Offset of the sigreturn() trampoline.
+ * @off_rt_sigreturn: Offset of the rt_sigreturn() trampoline.
+ * @mapping: Special mapping structure.
+ *
+ * This structure contains details of a VDSO image, including the image data
+ * and offsets of certain symbols required by the kernel. It is generated as
+ * part of the VDSO build process, aside from the mapping page array, which is
+ * populated at runtime.
+ */
+struct mips_vdso_image {
+ void *data;
+ unsigned long size;
+
+ unsigned long off_sigreturn;
+ unsigned long off_rt_sigreturn;
+
+ struct vm_special_mapping mapping;
};
-#else /* !CONFIG_32BIT */
-struct mips_vdso {
- u32 o32_signal_trampoline[2];
- u32 o32_rt_signal_trampoline[2];
- u32 rt_signal_trampoline[2];
- u32 n32_rt_signal_trampoline[2];
+
+/*
+ * The following structures are auto-generated as part of the build for each
+ * ABI by genvdso, see arch/mips/vdso/Makefile.
+ */
+
+extern struct mips_vdso_image vdso_image;
+
+#ifdef CONFIG_MIPS32_O32
+extern struct mips_vdso_image vdso_image_o32;
+#endif
+
+#ifdef CONFIG_MIPS32_N32
+extern struct mips_vdso_image vdso_image_n32;
+#endif
+
+/**
+ * union mips_vdso_data - Data provided by the kernel for the VDSO.
+ * @xtime_sec: Current real time (seconds part).
+ * @xtime_nsec: Current real time (nanoseconds part, shifted).
+ * @wall_to_mono_sec: Wall-to-monotonic offset (seconds part).
+ * @wall_to_mono_nsec: Wall-to-monotonic offset (nanoseconds part).
+ * @seq_count: Counter to synchronise updates (odd = updating).
+ * @cs_shift: Clocksource shift value.
+ * @clock_mode: Clocksource to use for time functions.
+ * @cs_mult: Clocksource multiplier value.
+ * @cs_cycle_last: Clock cycle value at last update.
+ * @cs_mask: Clocksource mask value.
+ * @tz_minuteswest: Minutes west of Greenwich (from timezone).
+ * @tz_dsttime: Type of DST correction (from timezone).
+ *
+ * This structure contains data needed by functions within the VDSO. It is
+ * populated by the kernel and mapped read-only into user memory. The time
+ * fields are mirrors of internal data from the timekeeping infrastructure.
+ *
+ * Note: Care should be taken when modifying as the layout must remain the same
+ * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel).
+ */
+union mips_vdso_data {
+ struct {
+ u64 xtime_sec;
+ u64 xtime_nsec;
+ u32 wall_to_mono_sec;
+ u32 wall_to_mono_nsec;
+ u32 seq_count;
+ u32 cs_shift;
+ u8 clock_mode;
+ u32 cs_mult;
+ u64 cs_cycle_last;
+ u64 cs_mask;
+ s32 tz_minuteswest;
+ s32 tz_dsttime;
+ };
+
+ u8 page[PAGE_SIZE];
};
-#endif /* CONFIG_32BIT */
+
+static inline u32 vdso_data_read_begin(const union mips_vdso_data *data)
+{
+ u32 seq;
+
+ while (true) {
+ seq = ACCESS_ONCE(data->seq_count);
+ if (likely(!(seq & 1))) {
+ /* Paired with smp_wmb() in vdso_data_write_*(). */
+ smp_rmb();
+ return seq;
+ }
+
+ cpu_relax();
+ }
+}
+
+static inline bool vdso_data_read_retry(const union mips_vdso_data *data,
+ u32 start_seq)
+{
+ /* Paired with smp_wmb() in vdso_data_write_*(). */
+ smp_rmb();
+ return unlikely(data->seq_count != start_seq);
+}
+
+static inline void vdso_data_write_begin(union mips_vdso_data *data)
+{
+ ++data->seq_count;
+
+ /* Ensure sequence update is written before other data page values. */
+ smp_wmb();
+}
+
+static inline void vdso_data_write_end(union mips_vdso_data *data)
+{
+ /* Ensure data values are written before updating sequence again. */
+ smp_wmb();
+ ++data->seq_count;
+}
#endif /* __ASM_VDSO_H */
diff --git a/arch/mips/include/uapi/asm/Kbuild b/arch/mips/include/uapi/asm/Kbuild
index 96fe739..f2cf414 100644
--- a/arch/mips/include/uapi/asm/Kbuild
+++ b/arch/mips/include/uapi/asm/Kbuild
@@ -1,9 +1,9 @@
# UAPI Header export list
include include/uapi/asm-generic/Kbuild.asm
-generic-y += auxvec.h
generic-y += ipcbuf.h
+header-y += auxvec.h
header-y += bitfield.h
header-y += bitsperlong.h
header-y += break.h
diff --git a/arch/mips/include/uapi/asm/auxvec.h b/arch/mips/include/uapi/asm/auxvec.h
new file mode 100644
index 0000000..c9c7195
--- /dev/null
+++ b/arch/mips/include/uapi/asm/auxvec.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __ASM_AUXVEC_H
+#define __ASM_AUXVEC_H
+
+/* Location of VDSO image. */
+#define AT_SYSINFO_EHDR 33
+
+#endif /* __ASM_AUXVEC_H */
diff --git a/arch/mips/jz4740/board-qi_lb60.c b/arch/mips/jz4740/board-qi_lb60.c
index 459cb01..934b15b 100644
--- a/arch/mips/jz4740/board-qi_lb60.c
+++ b/arch/mips/jz4740/board-qi_lb60.c
@@ -25,6 +25,7 @@
#include <linux/power_supply.h>
#include <linux/power/jz4740-battery.h>
#include <linux/power/gpio-charger.h>
+#include <linux/pwm.h>
#include <asm/mach-jz4740/gpio.h>
#include <asm/mach-jz4740/jz4740_fb.h>
@@ -34,8 +35,6 @@
#include <linux/regulator/fixed.h>
#include <linux/regulator/machine.h>
-#include <linux/leds_pwm.h>
-
#include <asm/mach-jz4740/platform.h>
#include "clock.h"
@@ -399,13 +398,15 @@ static struct platform_device avt2_usb_regulator_device = {
}
};
+static struct pwm_lookup qi_lb60_pwm_lookup[] = {
+ PWM_LOOKUP("jz4740-pwm", 4, "pwm-beeper", NULL, 0,
+ PWM_POLARITY_NORMAL),
+};
+
/* beeper */
static struct platform_device qi_lb60_pwm_beeper = {
.name = "pwm-beeper",
.id = -1,
- .dev = {
- .platform_data = (void *)4,
- },
};
/* charger */
@@ -491,6 +492,8 @@ static int __init qi_lb60_init_platform_devices(void)
platform_device_register(&jz4740_usb_ohci_device);
}
+ pwm_add_table(qi_lb60_pwm_lookup, ARRAY_SIZE(qi_lb60_pwm_lookup));
+
return platform_add_devices(jz_platform_devices,
ARRAY_SIZE(jz_platform_devices));
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index d982be1..68e2b7d 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_MIPS_MT_FPAFF) += mips-mt-fpaff.o
obj-$(CONFIG_MIPS_MT_SMP) += smp-mt.o
obj-$(CONFIG_MIPS_CMP) += smp-cmp.o
obj-$(CONFIG_MIPS_CPS) += smp-cps.o cps-vec.o
+obj-$(CONFIG_MIPS_CPS_NS16550) += cps-vec-ns16550.o
obj-$(CONFIG_MIPS_GIC_IPI) += smp-gic.o
obj-$(CONFIG_MIPS_SPRAM) += spram.o
diff --git a/arch/mips/kernel/cps-vec-ns16550.S b/arch/mips/kernel/cps-vec-ns16550.S
new file mode 100644
index 0000000..6d246ad
--- /dev/null
+++ b/arch/mips/kernel/cps-vec-ns16550.S
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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 <asm/addrspace.h>
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/mipsregs.h>
+#include <asm/regdef.h>
+#include <linux/serial_reg.h>
+
+#define UART_TX_OFS (UART_TX << CONFIG_MIPS_CPS_NS16550_SHIFT)
+#define UART_LSR_OFS (UART_LSR << CONFIG_MIPS_CPS_NS16550_SHIFT)
+
+/**
+ * _mips_cps_putc() - write a character to the UART
+ * @a0: ASCII character to write
+ * @t9: UART base address
+ */
+LEAF(_mips_cps_putc)
+1: lw t0, UART_LSR_OFS(t9)
+ andi t0, t0, UART_LSR_TEMT
+ beqz t0, 1b
+ sb a0, UART_TX_OFS(t9)
+ jr ra
+ END(_mips_cps_putc)
+
+/**
+ * _mips_cps_puts() - write a string to the UART
+ * @a0: pointer to NULL-terminated ASCII string
+ * @t9: UART base address
+ *
+ * Write a null-terminated ASCII string to the UART.
+ */
+NESTED(_mips_cps_puts, 0, ra)
+ move s7, ra
+ move s6, a0
+
+1: lb a0, 0(s6)
+ beqz a0, 2f
+ jal _mips_cps_putc
+ PTR_ADDIU s6, s6, 1
+ b 1b
+
+2: jr s7
+ END(_mips_cps_puts)
+
+/**
+ * _mips_cps_putx4 - write a 4b hex value to the UART
+ * @a0: the 4b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a single hexadecimal character to the UART.
+ */
+NESTED(_mips_cps_putx4, 0, ra)
+ andi a0, a0, 0xf
+ li t0, '0'
+ blt a0, 10, 1f
+ li t0, 'a'
+ addiu a0, a0, -10
+1: addu a0, a0, t0
+ b _mips_cps_putc
+ END(_mips_cps_putx4)
+
+/**
+ * _mips_cps_putx8 - write an 8b hex value to the UART
+ * @a0: the 8b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write an 8 bit value (ie. 2 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx8, 0, ra)
+ move s3, ra
+ move s2, a0
+ srl a0, a0, 4
+ jal _mips_cps_putx4
+ move a0, s2
+ move ra, s3
+ b _mips_cps_putx4
+ END(_mips_cps_putx8)
+
+/**
+ * _mips_cps_putx16 - write a 16b hex value to the UART
+ * @a0: the 16b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 16 bit value (ie. 4 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx16, 0, ra)
+ move s5, ra
+ move s4, a0
+ srl a0, a0, 8
+ jal _mips_cps_putx8
+ move a0, s4
+ move ra, s5
+ b _mips_cps_putx8
+ END(_mips_cps_putx16)
+
+/**
+ * _mips_cps_putx32 - write a 32b hex value to the UART
+ * @a0: the 32b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 32 bit value (ie. 8 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx32, 0, ra)
+ move s7, ra
+ move s6, a0
+ srl a0, a0, 16
+ jal _mips_cps_putx16
+ move a0, s6
+ move ra, s7
+ b _mips_cps_putx16
+ END(_mips_cps_putx32)
+
+#ifdef CONFIG_64BIT
+
+/**
+ * _mips_cps_putx64 - write a 64b hex value to the UART
+ * @a0: the 64b value to write to the UART
+ * @t9: UART base address
+ *
+ * Write a 64 bit value (ie. 16 hexadecimal characters) to the UART.
+ */
+NESTED(_mips_cps_putx64, 0, ra)
+ move sp, ra
+ move s8, a0
+ dsrl32 a0, a0, 0
+ jal _mips_cps_putx32
+ move a0, s8
+ move ra, sp
+ b _mips_cps_putx32
+ END(_mips_cps_putx64)
+
+#define _mips_cps_putxlong _mips_cps_putx64
+
+#else /* !CONFIG_64BIT */
+
+#define _mips_cps_putxlong _mips_cps_putx32
+
+#endif /* !CONFIG_64BIT */
+
+/**
+ * mips_cps_bev_dump() - dump relevant exception state to UART
+ * @a0: pointer to NULL-terminated ASCII string naming the exception
+ *
+ * Write information that may be useful in debugging an exception to the
+ * UART configured by CONFIG_MIPS_CPS_NS16550_*. As this BEV exception
+ * will only be run if something goes horribly wrong very early during
+ * the bringup of a core and it is very likely to be unsafe to perform
+ * memory accesses at that point (cache state indeterminate, EVA may not
+ * be configured, coherence may be disabled) let alone have a stack,
+ * this is all written in assembly using only registers & unmapped
+ * uncached access to the UART registers.
+ */
+LEAF(mips_cps_bev_dump)
+ move s0, ra
+ move s1, a0
+
+ li t9, CKSEG1ADDR(CONFIG_MIPS_CPS_NS16550_BASE)
+
+ PTR_LA a0, str_newline
+ jal _mips_cps_puts
+ PTR_LA a0, str_bev
+ jal _mips_cps_puts
+ move a0, s1
+ jal _mips_cps_puts
+ PTR_LA a0, str_newline
+ jal _mips_cps_puts
+ PTR_LA a0, str_newline
+ jal _mips_cps_puts
+
+#define DUMP_COP0_REG(reg, name, sz, _mfc0) \
+ PTR_LA a0, 8f; \
+ jal _mips_cps_puts; \
+ _mfc0 a0, reg; \
+ jal _mips_cps_putx##sz; \
+ PTR_LA a0, str_newline; \
+ jal _mips_cps_puts; \
+ TEXT(name)
+
+ DUMP_COP0_REG(CP0_CAUSE, "Cause: 0x", 32, mfc0)
+ DUMP_COP0_REG(CP0_STATUS, "Status: 0x", 32, mfc0)
+ DUMP_COP0_REG(CP0_EBASE, "EBase: 0x", long, MFC0)
+ DUMP_COP0_REG(CP0_BADVADDR, "BadVAddr: 0x", long, MFC0)
+ DUMP_COP0_REG(CP0_BADINSTR, "BadInstr: 0x", 32, mfc0)
+
+ PTR_LA a0, str_newline
+ jal _mips_cps_puts
+ jr s0
+ END(mips_cps_bev_dump)
+
+.pushsection .data
+str_bev: .asciiz "BEV Exception: "
+str_newline: .asciiz "\r\n"
+.popsection
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S
index 209ded1..ac81edd 100644
--- a/arch/mips/kernel/cps-vec.S
+++ b/arch/mips/kernel/cps-vec.S
@@ -25,14 +25,32 @@
.set noreorder
+#ifdef CONFIG_64BIT
+# define STATUS_BITDEPS ST0_KX
+#else
+# define STATUS_BITDEPS 0
+#endif
+
+#ifdef CONFIG_MIPS_CPS_NS16550
+
+#define DUMP_EXCEP(name) \
+ PTR_LA a0, 8f; \
+ jal mips_cps_bev_dump; \
+ nop; \
+ TEXT(name)
+
+#else /* !CONFIG_MIPS_CPS_NS16550 */
+
+#define DUMP_EXCEP(name)
+
+#endif /* !CONFIG_MIPS_CPS_NS16550 */
+
/*
* Set dest to non-zero if the core supports the MT ASE, else zero. If
* MT is not supported then branch to nomt.
*/
.macro has_mt dest, nomt
- mfc0 \dest, CP0_CONFIG
- bgez \dest, \nomt
- mfc0 \dest, CP0_CONFIG, 1
+ mfc0 \dest, CP0_CONFIG, 1
bgez \dest, \nomt
mfc0 \dest, CP0_CONFIG, 2
bgez \dest, \nomt
@@ -47,11 +65,9 @@
LEAF(mips_cps_core_entry)
/*
- * These first 12 bytes will be patched by cps_smp_setup to load the
- * base address of the CM GCRs into register v1 and the CCA to use into
- * register s0.
+ * These first 4 bytes will be patched by cps_smp_setup to load the
+ * CCA to use into register s0.
*/
- .quad 0
.word 0
/* Check whether we're here due to an NMI */
@@ -71,7 +87,7 @@ not_nmi:
mtc0 t0, CP0_CAUSE
/* Setup Status */
- li t0, ST0_CU1 | ST0_CU0
+ li t0, ST0_CU1 | ST0_CU0 | ST0_BEV | STATUS_BITDEPS
mtc0 t0, CP0_STATUS
/*
@@ -151,6 +167,12 @@ dcache_done:
mtc0 t0, CP0_CONFIG
ehb
+ /* Calculate an uncached address for the CM GCRs */
+ MFC0 v1, CP0_CMGCRBASE
+ PTR_SLL v1, v1, 4
+ PTR_LI t0, UNCAC_BASE
+ PTR_ADDU v1, v1, t0
+
/* Enter the coherent domain */
li t0, 0xff
sw t0, GCR_CL_COHERENCE_OFS(v1)
@@ -188,36 +210,42 @@ dcache_done:
.org 0x200
LEAF(excep_tlbfill)
+ DUMP_EXCEP("TLB Fill")
b .
nop
END(excep_tlbfill)
.org 0x280
LEAF(excep_xtlbfill)
+ DUMP_EXCEP("XTLB Fill")
b .
nop
END(excep_xtlbfill)
.org 0x300
LEAF(excep_cache)
+ DUMP_EXCEP("Cache")
b .
nop
END(excep_cache)
.org 0x380
LEAF(excep_genex)
+ DUMP_EXCEP("General")
b .
nop
END(excep_genex)
.org 0x400
LEAF(excep_intex)
+ DUMP_EXCEP("Interrupt")
b .
nop
END(excep_intex)
.org 0x480
LEAF(excep_ejtag)
+ DUMP_EXCEP("EJTAG")
PTR_LA k0, ejtag_debug_handler
jr k0
nop
@@ -229,7 +257,6 @@ LEAF(mips_cps_core_init)
has_mt t0, 3f
.set push
- .set mips64r2
.set mt
/* Only allow 1 TC per VPE to execute... */
@@ -348,7 +375,6 @@ LEAF(mips_cps_boot_vpes)
nop
.set push
- .set mips64r2
.set mt
1: /* Enter VPE configuration state */
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index 09a51d0..6b90644 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -536,8 +536,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_SEGMENTS;
if (config3 & MIPS_CONF3_MSA)
c->ases |= MIPS_ASE_MSA;
- /* Only tested on 32-bit cores */
- if ((config3 & MIPS_CONF3_PW) && config_enabled(CONFIG_32BIT)) {
+ if (config3 & MIPS_CONF3_PW) {
c->htw_seq = 0;
c->options |= MIPS_CPU_HTW;
}
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c
index e5ed7ad..1f91056 100644
--- a/arch/mips/kernel/csrc-r4k.c
+++ b/arch/mips/kernel/csrc-r4k.c
@@ -28,6 +28,43 @@ static u64 notrace r4k_read_sched_clock(void)
return read_c0_count();
}
+static inline unsigned int rdhwr_count(void)
+{
+ unsigned int count;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips32r2\n"
+ " rdhwr %0, $2\n"
+ " .set pop\n"
+ : "=r" (count));
+
+ return count;
+}
+
+static bool rdhwr_count_usable(void)
+{
+ unsigned int prev, curr, i;
+
+ /*
+ * Older QEMUs have a broken implementation of RDHWR for the CP0 count
+ * which always returns a constant value. Try to identify this and don't
+ * use it in the VDSO if it is broken. This workaround can be removed
+ * once the fix has been in QEMU stable for a reasonable amount of time.
+ */
+ for (i = 0, prev = rdhwr_count(); i < 100; i++) {
+ curr = rdhwr_count();
+
+ if (curr != prev)
+ return true;
+
+ prev = curr;
+ }
+
+ pr_warn("Not using R4K clocksource in VDSO due to broken RDHWR\n");
+ return false;
+}
+
int __init init_r4k_clocksource(void)
{
if (!cpu_has_counter || !mips_hpt_frequency)
@@ -36,6 +73,13 @@ int __init init_r4k_clocksource(void)
/* Calculate a somewhat reasonable rating value */
clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000;
+ /*
+ * R2 onwards makes the count accessible to user mode so it can be used
+ * by the VDSO (HWREna is configured by configure_hwrena()).
+ */
+ if (cpu_has_mips_r2_r6 && rdhwr_count_usable())
+ clocksource_mips.archdata.vdso_clock_mode = VDSO_CLOCK_R4K;
+
clocksource_register_hz(&clocksource_mips, mips_hpt_frequency);
sched_clock_register(r4k_read_sched_clock, 32, mips_hpt_frequency);
diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c
index ab1478d..46794d6 100644
--- a/arch/mips/kernel/idle.c
+++ b/arch/mips/kernel/idle.c
@@ -134,6 +134,16 @@ void __init check_wait(void)
return;
}
+ /*
+ * MIPSr6 specifies that masked interrupts should unblock an executing
+ * wait instruction, and thus that it is safe for us to use
+ * r4k_wait_irqoff. Yippee!
+ */
+ if (cpu_has_mips_r6) {
+ cpu_wait = r4k_wait_irqoff;
+ return;
+ }
+
switch (current_cpu_type()) {
case CPU_R3081:
case CPU_R3081E:
@@ -155,12 +165,12 @@ void __init check_wait(void)
case CPU_4KEC:
case CPU_4KSC:
case CPU_5KC:
+ case CPU_5KE:
case CPU_25KF:
case CPU_PR4450:
case CPU_BMIPS3300:
case CPU_BMIPS4350:
case CPU_BMIPS4380:
- case CPU_BMIPS5000:
case CPU_CAVIUM_OCTEON:
case CPU_CAVIUM_OCTEON_PLUS:
case CPU_CAVIUM_OCTEON2:
@@ -171,7 +181,9 @@ void __init check_wait(void)
case CPU_XLP:
cpu_wait = r4k_wait;
break;
-
+ case CPU_BMIPS5000:
+ cpu_wait = r4k_wait_irqoff;
+ break;
case CPU_RM7000:
cpu_wait = rm7k_wait_irqoff;
break;
@@ -196,7 +208,6 @@ void __init check_wait(void)
case CPU_INTERAPTIV:
case CPU_M5150:
case CPU_QEMU_GENERIC:
- case CPU_I6400:
cpu_wait = r4k_wait;
if (read_c0_config7() & MIPS_CONF7_WII)
cpu_wait = r4k_wait_irqoff;
diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c
index b8ceee5..1448c1f 100644
--- a/arch/mips/kernel/mips-cm.c
+++ b/arch/mips/kernel/mips-cm.c
@@ -9,6 +9,8 @@
*/
#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/spinlock.h>
#include <asm/mips-cm.h>
#include <asm/mipsregs.h>
@@ -136,6 +138,9 @@ static char *cm3_causes[32] = {
"0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f"
};
+static DEFINE_PER_CPU_ALIGNED(spinlock_t, cm_core_lock);
+static DEFINE_PER_CPU_ALIGNED(unsigned long, cm_core_lock_flags);
+
phys_addr_t __mips_cm_phys_base(void)
{
u32 config3 = read_c0_config3();
@@ -200,6 +205,7 @@ int mips_cm_probe(void)
{
phys_addr_t addr;
u32 base_reg;
+ unsigned cpu;
/*
* No need to probe again if we have already been
@@ -247,38 +253,70 @@ int mips_cm_probe(void)
/* determine register width for this CM */
mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3);
+ for_each_possible_cpu(cpu)
+ spin_lock_init(&per_cpu(cm_core_lock, cpu));
+
return 0;
}
-void mips_cm_error_report(void)
+void mips_cm_lock_other(unsigned int core, unsigned int vp)
{
- unsigned long revision = mips_cm_revision();
+ unsigned curr_core;
+ u32 val;
+
+ preempt_disable();
+ curr_core = current_cpu_data.core;
+ spin_lock_irqsave(&per_cpu(cm_core_lock, curr_core),
+ per_cpu(cm_core_lock_flags, curr_core));
+
+ if (mips_cm_revision() >= CM_REV_CM3) {
+ val = core << CM3_GCR_Cx_OTHER_CORE_SHF;
+ val |= vp << CM3_GCR_Cx_OTHER_VP_SHF;
+ } else {
+ BUG_ON(vp != 0);
+ val = core << CM_GCR_Cx_OTHER_CORENUM_SHF;
+ }
+
+ write_gcr_cl_other(val);
+
/*
- * CM3 has a 64-bit Error cause register with 0:57 containing the error
- * info and 63:58 the error type. For old CMs, everything is contained
- * in a single 32-bit register (0:26 and 31:27 respectively). Even
- * though the cm_error is u64, we will simply ignore the upper word
- * for CM2.
+ * Ensure the core-other region reflects the appropriate core &
+ * VP before any accesses to it occur.
*/
- u64 cm_error = read_gcr_error_cause();
- int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF +
- ((revision >= CM_REV_CM3) ? 31 : 0);
- unsigned long cm_addr = read_gcr_error_addr();
- unsigned long cm_other = read_gcr_error_mult();
+ mb();
+}
+
+void mips_cm_unlock_other(void)
+{
+ unsigned curr_core = current_cpu_data.core;
+
+ spin_unlock_irqrestore(&per_cpu(cm_core_lock, curr_core),
+ per_cpu(cm_core_lock_flags, curr_core));
+ preempt_enable();
+}
+
+void mips_cm_error_report(void)
+{
+ u64 cm_error, cm_addr, cm_other;
+ unsigned long revision;
int ocause, cause;
char buf[256];
if (!mips_cm_present())
return;
- cause = cm_error >> cm_error_cause_sft;
+ revision = mips_cm_revision();
- if (!cause)
- /* All good */
- return;
-
- ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
if (revision < CM_REV_CM3) { /* CM2 */
+ cm_error = read_gcr_error_cause();
+ cm_addr = read_gcr_error_addr();
+ cm_other = read_gcr_error_mult();
+ cause = cm_error >> CM_GCR_ERROR_CAUSE_ERRTYPE_SHF;
+ ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
+
+ if (!cause)
+ return;
+
if (cause < 16) {
unsigned long cca_bits = (cm_error >> 15) & 7;
unsigned long tr_bits = (cm_error >> 12) & 7;
@@ -310,18 +348,30 @@ void mips_cm_error_report(void)
}
pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error,
cm2_causes[cause], buf);
- pr_err("CM_ADDR =%08lx\n", cm_addr);
- pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]);
+ pr_err("CM_ADDR =%08llx\n", cm_addr);
+ pr_err("CM_OTHER=%08llx %s\n", cm_other, cm2_causes[ocause]);
} else { /* CM3 */
- /* Used by cause == {1,2,3} */
- unsigned long core_id_bits = (cm_error >> 22) & 0xf;
- unsigned long vp_id_bits = (cm_error >> 18) & 0xf;
- unsigned long cmd_bits = (cm_error >> 14) & 0xf;
- unsigned long cmd_group_bits = (cm_error >> 11) & 0xf;
- unsigned long cm3_cca_bits = (cm_error >> 8) & 7;
- unsigned long mcp_bits = (cm_error >> 5) & 0xf;
- unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf;
- unsigned long sched_bit = cm_error & 0x1;
+ ulong core_id_bits, vp_id_bits, cmd_bits, cmd_group_bits;
+ ulong cm3_cca_bits, mcp_bits, cm3_tr_bits, sched_bit;
+
+ cm_error = read64_gcr_error_cause();
+ cm_addr = read64_gcr_error_addr();
+ cm_other = read64_gcr_error_mult();
+ cause = cm_error >> CM3_GCR_ERROR_CAUSE_ERRTYPE_SHF;
+ ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF;
+
+ if (!cause)
+ return;
+
+ /* Used by cause == {1,2,3} */
+ core_id_bits = (cm_error >> 22) & 0xf;
+ vp_id_bits = (cm_error >> 18) & 0xf;
+ cmd_bits = (cm_error >> 14) & 0xf;
+ cmd_group_bits = (cm_error >> 11) & 0xf;
+ cm3_cca_bits = (cm_error >> 8) & 7;
+ mcp_bits = (cm_error >> 5) & 0xf;
+ cm3_tr_bits = (cm_error >> 1) & 0xf;
+ sched_bit = cm_error & 0x1;
if (cause == 1 || cause == 3) { /* Tag ECC */
unsigned long tag_ecc = (cm_error >> 57) & 0x1;
@@ -363,12 +413,14 @@ void mips_cm_error_report(void)
cm3_cmd_group[cmd_group_bits],
cm3_cca_bits, 1 << mcp_bits,
cm3_tr[cm3_tr_bits], sched_bit);
+ } else {
+ buf[0] = 0;
}
pr_err("CM_ERROR=%llx %s <%s>\n", cm_error,
cm3_causes[cause], buf);
- pr_err("CM_ADDR =%lx\n", cm_addr);
- pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]);
+ pr_err("CM_ADDR =%llx\n", cm_addr);
+ pr_err("CM_OTHER=%llx %s\n", cm_other, cm3_causes[ocause]);
}
/* reprime cause register */
diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c
index 8af4d62..566b8d2 100644
--- a/arch/mips/kernel/mips-cpc.c
+++ b/arch/mips/kernel/mips-cpc.c
@@ -76,6 +76,12 @@ void mips_cpc_lock_other(unsigned int core)
spin_lock_irqsave(&per_cpu(cpc_core_lock, curr_core),
per_cpu(cpc_core_lock_flags, curr_core));
write_cpc_cl_other(core << CPC_Cx_OTHER_CORENUM_SHF);
+
+ /*
+ * Ensure the core-other region reflects the appropriate core &
+ * VP before any accesses to it occur.
+ */
+ mb();
}
void mips_cpc_unlock_other(void)
diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c
index f2977f0..1f5aac7 100644
--- a/arch/mips/kernel/mips-r2-to-r6-emul.c
+++ b/arch/mips/kernel/mips-r2-to-r6-emul.c
@@ -22,6 +22,7 @@
#include <asm/asm.h>
#include <asm/branch.h>
#include <asm/break.h>
+#include <asm/debug.h>
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h>
@@ -2363,7 +2364,6 @@ static const struct file_operations mipsr2_clear_fops = {
static int __init mipsr2_init_debugfs(void)
{
- extern struct dentry *mips_debugfs_dir;
struct dentry *mipsr2_emul;
if (!mips_debugfs_dir)
diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c
index 291af0b..e2b6ab7 100644
--- a/arch/mips/kernel/mips_ksyms.c
+++ b/arch/mips/kernel/mips_ksyms.c
@@ -17,6 +17,7 @@
#include <asm/fpu.h>
#include <asm/msa.h>
+extern void *__bzero_kernel(void *__s, size_t __count);
extern void *__bzero(void *__s, size_t __count);
extern long __strncpy_from_kernel_nocheck_asm(char *__to,
const char *__from, long __len);
@@ -64,6 +65,7 @@ EXPORT_SYMBOL(__copy_from_user_eva);
EXPORT_SYMBOL(__copy_in_user_eva);
EXPORT_SYMBOL(__copy_to_user_eva);
EXPORT_SYMBOL(__copy_user_inatomic_eva);
+EXPORT_SYMBOL(__bzero_kernel);
#endif
EXPORT_SYMBOL(__bzero);
EXPORT_SYMBOL(__strncpy_from_kernel_nocheck_asm);
diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c
index 076ead2..87bc74a 100644
--- a/arch/mips/kernel/segment.c
+++ b/arch/mips/kernel/segment.c
@@ -10,6 +10,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <asm/cpu.h>
+#include <asm/debug.h>
#include <asm/mipsregs.h>
static void build_segment_config(char *str, unsigned int cfg)
@@ -91,7 +92,6 @@ static const struct file_operations segments_fops = {
static int __init segments_info(void)
{
- extern struct dentry *mips_debugfs_dir;
struct dentry *segments;
if (cpu_has_segments) {
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 4795151..66aac55 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -33,11 +33,16 @@
#include <asm/cache.h>
#include <asm/cdmm.h>
#include <asm/cpu.h>
+#include <asm/debug.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/smp-ops.h>
#include <asm/prom.h>
+#ifdef CONFIG_MIPS_ELF_APPENDED_DTB
+const char __section(.appended_dtb) __appended_dtb[0x100000];
+#endif /* CONFIG_MIPS_ELF_APPENDED_DTB */
+
struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_data);
@@ -616,6 +621,10 @@ static void __init request_crashkernel(struct resource *res)
}
#endif /* !defined(CONFIG_KEXEC) */
+#define USE_PROM_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_BOOTLOADER)
+#define USE_DTB_CMDLINE IS_ENABLED(CONFIG_MIPS_CMDLINE_FROM_DTB)
+#define EXTEND_WITH_PROM IS_ENABLED(CONFIG_MIPS_CMDLINE_EXTEND)
+
static void __init arch_mem_init(char **cmdline_p)
{
struct memblock_region *reg;
@@ -640,18 +649,24 @@ static void __init arch_mem_init(char **cmdline_p)
pr_info("Determined physical RAM map:\n");
print_memory_map();
-#ifdef CONFIG_CMDLINE_BOOL
-#ifdef CONFIG_CMDLINE_OVERRIDE
+#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE)
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
+ if ((USE_PROM_CMDLINE && arcs_cmdline[0]) ||
+ (USE_DTB_CMDLINE && !boot_command_line[0]))
+ strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+
+ if (EXTEND_WITH_PROM && arcs_cmdline[0]) {
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
+ }
+
+#if defined(CONFIG_CMDLINE_BOOL)
if (builtin_cmdline[0]) {
- strlcat(arcs_cmdline, " ", COMMAND_LINE_SIZE);
- strlcat(arcs_cmdline, builtin_cmdline, COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, " ", COMMAND_LINE_SIZE);
+ strlcat(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
}
- strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
#endif
-#else
- strlcpy(boot_command_line, arcs_cmdline, COMMAND_LINE_SIZE);
#endif
strlcpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 2fec67b..bf792e2 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -36,7 +36,6 @@
#include <asm/ucontext.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
-#include <asm/vdso.h>
#include <asm/dsp.h>
#include <asm/inst.h>
#include <asm/msa.h>
@@ -752,16 +751,15 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig,
struct mips_abi mips_abi = {
#ifdef CONFIG_TRAD_SIGNALS
.setup_frame = setup_frame,
- .signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
#endif
.setup_rt_frame = setup_rt_frame,
- .rt_signal_return_offset =
- offsetof(struct mips_vdso, rt_signal_trampoline),
.restart = __NR_restart_syscall,
.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
+
+ .vdso = &vdso_image,
};
static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
@@ -801,11 +799,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
}
if (sig_uses_siginfo(&ksig->ka))
- ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
+ ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn,
ksig, regs, oldset);
else
- ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig,
- regs, oldset);
+ ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn,
+ ksig, regs, oldset);
signal_setup_done(ret, ksig, 0);
}
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index f7e89524..4909639 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -31,7 +31,6 @@
#include <asm/ucontext.h>
#include <asm/fpu.h>
#include <asm/war.h>
-#include <asm/vdso.h>
#include <asm/dsp.h>
#include "signal-common.h"
@@ -406,14 +405,12 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
*/
struct mips_abi mips_abi_32 = {
.setup_frame = setup_frame_32,
- .signal_return_offset =
- offsetof(struct mips_vdso, o32_signal_trampoline),
.setup_rt_frame = setup_rt_frame_32,
- .rt_signal_return_offset =
- offsetof(struct mips_vdso, o32_rt_signal_trampoline),
.restart = __NR_O32_restart_syscall,
.off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
.off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
.off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
+
+ .vdso = &vdso_image_o32,
};
diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c
index 0d017fd..a7bc384 100644
--- a/arch/mips/kernel/signal_n32.c
+++ b/arch/mips/kernel/signal_n32.c
@@ -38,7 +38,6 @@
#include <asm/fpu.h>
#include <asm/cpu-features.h>
#include <asm/war.h>
-#include <asm/vdso.h>
#include "signal-common.h"
@@ -151,11 +150,11 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig,
struct mips_abi mips_abi_n32 = {
.setup_rt_frame = setup_rt_frame_n32,
- .rt_signal_return_offset =
- offsetof(struct mips_vdso, n32_rt_signal_trampoline),
.restart = __NR_N32_restart_syscall,
.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
+
+ .vdso = &vdso_image_n32,
};
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
index c889377..e04c805 100644
--- a/arch/mips/kernel/smp-cps.c
+++ b/arch/mips/kernel/smp-cps.c
@@ -8,6 +8,7 @@
* option) any later version.
*/
+#include <linux/delay.h>
#include <linux/io.h>
#include <linux/irqchip/mips-gic.h>
#include <linux/sched.h>
@@ -37,8 +38,9 @@ static unsigned core_vpe_count(unsigned core)
if (!config_enabled(CONFIG_MIPS_MT_SMP) || !cpu_has_mipsmt)
return 1;
- write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+ mips_cm_lock_other(core, 0);
cfg = read_gcr_co_config() & CM_GCR_Cx_CONFIG_PVPE_MSK;
+ mips_cm_unlock_other();
return (cfg >> CM_GCR_Cx_CONFIG_PVPE_SHF) + 1;
}
@@ -133,11 +135,9 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
/*
* Patch the start of mips_cps_core_entry to provide:
*
- * v1 = CM base address
* s0 = kseg0 CCA
*/
entry_code = (u32 *)&mips_cps_core_entry;
- UASM_i_LA(&entry_code, 3, (long)mips_cm_base);
uasm_i_addiu(&entry_code, 16, 0, cca);
blast_dcache_range((unsigned long)&mips_cps_core_entry,
(unsigned long)entry_code);
@@ -190,10 +190,11 @@ err_out:
static void boot_core(unsigned core)
{
- u32 access;
+ u32 access, stat, seq_state;
+ unsigned timeout;
/* Select the appropriate core */
- write_gcr_cl_other(core << CM_GCR_Cx_OTHER_CORENUM_SHF);
+ mips_cm_lock_other(core, 0);
/* Set its reset vector */
write_gcr_co_reset_base(CKSEG1ADDR((unsigned long)mips_cps_core_entry));
@@ -210,12 +211,36 @@ static void boot_core(unsigned core)
/* Reset the core */
mips_cpc_lock_other(core);
write_cpc_co_cmd(CPC_Cx_CMD_RESET);
+
+ timeout = 100;
+ while (true) {
+ stat = read_cpc_co_stat_conf();
+ seq_state = stat & CPC_Cx_STAT_CONF_SEQSTATE_MSK;
+
+ /* U6 == coherent execution, ie. the core is up */
+ if (seq_state == CPC_Cx_STAT_CONF_SEQSTATE_U6)
+ break;
+
+ /* Delay a little while before we start warning */
+ if (timeout) {
+ timeout--;
+ mdelay(10);
+ continue;
+ }
+
+ pr_warn("Waiting for core %u to start... STAT_CONF=0x%x\n",
+ core, stat);
+ mdelay(1000);
+ }
+
mips_cpc_unlock_other();
} else {
/* Take the core out of reset */
write_gcr_co_reset_release(0);
}
+ mips_cm_unlock_other();
+
/* The core is now powered up */
bitmap_set(core_power, core, 1);
}
diff --git a/arch/mips/kernel/smp-gic.c b/arch/mips/kernel/smp-gic.c
index 5f0ab5b..9b63829 100644
--- a/arch/mips/kernel/smp-gic.c
+++ b/arch/mips/kernel/smp-gic.c
@@ -46,9 +46,11 @@ void gic_send_ipi_single(int cpu, unsigned int action)
if (mips_cpc_present() && (core != current_cpu_data.core)) {
while (!cpumask_test_cpu(cpu, &cpu_coherent_mask)) {
+ mips_cm_lock_other(core, 0);
mips_cpc_lock_other(core);
write_cpc_co_cmd(CPC_Cx_CMD_PWRUP);
mips_cpc_unlock_other();
+ mips_cm_unlock_other();
}
}
diff --git a/arch/mips/kernel/spinlock_test.c b/arch/mips/kernel/spinlock_test.c
index 39f7ab7..f7d8695 100644
--- a/arch/mips/kernel/spinlock_test.c
+++ b/arch/mips/kernel/spinlock_test.c
@@ -5,7 +5,7 @@
#include <linux/debugfs.h>
#include <linux/export.h>
#include <linux/spinlock.h>
-
+#include <asm/debug.h>
static int ss_get(void *data, u64 *val)
{
@@ -115,8 +115,6 @@ static int multi_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(fops_multi, multi_get, NULL, "%llu\n");
-
-extern struct dentry *mips_debugfs_dir;
static int __init spinlock_test(void)
{
struct dentry *d;
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
index 1ba775d..506021f 100644
--- a/arch/mips/kernel/stacktrace.c
+++ b/arch/mips/kernel/stacktrace.c
@@ -12,14 +12,15 @@
* Save stack-backtrace addresses into a stack_trace buffer:
*/
static void save_raw_context_stack(struct stack_trace *trace,
- unsigned long reg29)
+ unsigned long reg29, int savesched)
{
unsigned long *sp = (unsigned long *)reg29;
unsigned long addr;
while (!kstack_end(sp)) {
addr = *sp++;
- if (__kernel_text_address(addr)) {
+ if (__kernel_text_address(addr) &&
+ (savesched || !in_sched_functions(addr))) {
if (trace->skip > 0)
trace->skip--;
else
@@ -31,7 +32,7 @@ static void save_raw_context_stack(struct stack_trace *trace,
}
static void save_context_stack(struct stack_trace *trace,
- struct task_struct *tsk, struct pt_regs *regs)
+ struct task_struct *tsk, struct pt_regs *regs, int savesched)
{
unsigned long sp = regs->regs[29];
#ifdef CONFIG_KALLSYMS
@@ -43,20 +44,22 @@ static void save_context_stack(struct stack_trace *trace,
(unsigned long)task_stack_page(tsk);
if (stack_page && sp >= stack_page &&
sp <= stack_page + THREAD_SIZE - 32)
- save_raw_context_stack(trace, sp);
+ save_raw_context_stack(trace, sp, savesched);
return;
}
do {
- if (trace->skip > 0)
- trace->skip--;
- else
- trace->entries[trace->nr_entries++] = pc;
- if (trace->nr_entries >= trace->max_entries)
- break;
+ if (savesched || !in_sched_functions(pc)) {
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = pc;
+ if (trace->nr_entries >= trace->max_entries)
+ break;
+ }
pc = unwind_stack(tsk, &sp, pc, &ra);
} while (pc);
#else
- save_raw_context_stack(trace, sp);
+ save_raw_context_stack(trace, sp, savesched);
#endif
}
@@ -82,6 +85,6 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
regs->cp0_epc = tsk->thread.reg31;
} else
prepare_frametrace(regs);
- save_context_stack(trace, tsk, regs);
+ save_context_stack(trace, tsk, regs, tsk == current);
}
EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index fdb392b..886cb19 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -37,6 +37,7 @@
#include <linux/irq.h>
#include <linux/perf_event.h>
+#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/branch.h>
#include <asm/break.h>
@@ -1856,12 +1857,14 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
{
char str[100];
+ nmi_enter();
raw_notifier_call_chain(&nmi_chain, 0, regs);
bust_spinlocks(1);
snprintf(str, 100, "CPU%d NMI taken, CP0_EPC=%lx\n",
smp_processor_id(), regs->cp0_epc);
regs->cp0_epc = read_c0_errorepc();
die(str, regs);
+ nmi_exit();
}
#define VECTORSPACING 0x100 /* for EI/VI mode */
@@ -2204,12 +2207,8 @@ void __init trap_init(void)
ebase = (unsigned long)
__alloc_bootmem(size, 1 << fls(size), 0);
} else {
-#ifdef CONFIG_KVM_GUEST
-#define KVM_GUEST_KSEG0 0x40000000
- ebase = KVM_GUEST_KSEG0;
-#else
- ebase = CKSEG0;
-#endif
+ ebase = CAC_BASE;
+
if (cpu_has_mips_r2_r6)
ebase += (read_c0_ebase() & 0x3ffff000);
}
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 990354d..490cea5 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -85,6 +85,7 @@
#include <asm/branch.h>
#include <asm/byteorder.h>
#include <asm/cop2.h>
+#include <asm/debug.h>
#include <asm/fpu.h>
#include <asm/fpu_emulator.h>
#include <asm/inst.h>
@@ -2295,7 +2296,6 @@ sigbus:
}
#ifdef CONFIG_DEBUG_FS
-extern struct dentry *mips_debugfs_dir;
static int __init debugfs_unaligned(void)
{
struct dentry *d;
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
index ed2a278..975e997 100644
--- a/arch/mips/kernel/vdso.c
+++ b/arch/mips/kernel/vdso.c
@@ -1,122 +1,175 @@
/*
- * 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) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
*
- * Copyright (C) 2009, 2010 Cavium Networks, Inc.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/init.h>
#include <linux/binfmts.h>
#include <linux/elf.h>
-#include <linux/vmalloc.h>
-#include <linux/unistd.h>
-#include <linux/random.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timekeeper_internal.h>
+#include <asm/abi.h>
#include <asm/vdso.h>
-#include <asm/uasm.h>
-#include <asm/processor.h>
+
+/* Kernel-provided data used by the VDSO. */
+static union mips_vdso_data vdso_data __page_aligned_data;
/*
- * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ * Mapping for the VDSO data/GIC pages. The real pages are mapped manually, as
+ * what we map and where within the area they are mapped is determined at
+ * runtime.
*/
-#define __NR_O32_sigreturn 4119
-#define __NR_O32_rt_sigreturn 4193
-#define __NR_N32_rt_sigreturn 6211
+static struct page *no_pages[] = { NULL };
+static struct vm_special_mapping vdso_vvar_mapping = {
+ .name = "[vvar]",
+ .pages = no_pages,
+};
-static struct page *vdso_page;
-
-static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
+static void __init init_vdso_image(struct mips_vdso_image *image)
{
- uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */
- uasm_i_syscall(&tramp, 0);
+ unsigned long num_pages, i;
+
+ BUG_ON(!PAGE_ALIGNED(image->data));
+ BUG_ON(!PAGE_ALIGNED(image->size));
+
+ num_pages = image->size / PAGE_SIZE;
+
+ for (i = 0; i < num_pages; i++) {
+ image->mapping.pages[i] =
+ virt_to_page(image->data + (i * PAGE_SIZE));
+ }
}
static int __init init_vdso(void)
{
- struct mips_vdso *vdso;
-
- vdso_page = alloc_page(GFP_KERNEL);
- if (!vdso_page)
- panic("Cannot allocate vdso");
-
- vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
- if (!vdso)
- panic("Cannot map vdso");
- clear_page(vdso);
-
- install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
-#ifdef CONFIG_32BIT
- install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
-#else
- install_trampoline(vdso->n32_rt_signal_trampoline,
- __NR_N32_rt_sigreturn);
- install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
- install_trampoline(vdso->o32_rt_signal_trampoline,
- __NR_O32_rt_sigreturn);
+ init_vdso_image(&vdso_image);
+
+#ifdef CONFIG_MIPS32_O32
+ init_vdso_image(&vdso_image_o32);
#endif
- vunmap(vdso);
+#ifdef CONFIG_MIPS32_N32
+ init_vdso_image(&vdso_image_n32);
+#endif
return 0;
}
subsys_initcall(init_vdso);
-static unsigned long vdso_addr(unsigned long start)
+void update_vsyscall(struct timekeeper *tk)
{
- unsigned long offset = 0UL;
-
- if (current->flags & PF_RANDOMIZE) {
- offset = get_random_int();
- offset <<= PAGE_SHIFT;
- if (TASK_IS_32BIT_ADDR)
- offset &= 0xfffffful;
- else
- offset &= 0xffffffful;
+ vdso_data_write_begin(&vdso_data);
+
+ vdso_data.xtime_sec = tk->xtime_sec;
+ vdso_data.xtime_nsec = tk->tkr_mono.xtime_nsec;
+ vdso_data.wall_to_mono_sec = tk->wall_to_monotonic.tv_sec;
+ vdso_data.wall_to_mono_nsec = tk->wall_to_monotonic.tv_nsec;
+ vdso_data.cs_shift = tk->tkr_mono.shift;
+
+ vdso_data.clock_mode = tk->tkr_mono.clock->archdata.vdso_clock_mode;
+ if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+ vdso_data.cs_mult = tk->tkr_mono.mult;
+ vdso_data.cs_cycle_last = tk->tkr_mono.cycle_last;
+ vdso_data.cs_mask = tk->tkr_mono.mask;
}
- return STACK_TOP + offset;
+ vdso_data_write_end(&vdso_data);
+}
+
+void update_vsyscall_tz(void)
+{
+ if (vdso_data.clock_mode != VDSO_CLOCK_NONE) {
+ vdso_data.tz_minuteswest = sys_tz.tz_minuteswest;
+ vdso_data.tz_dsttime = sys_tz.tz_dsttime;
+ }
}
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
{
- int ret;
- unsigned long addr;
+ struct mips_vdso_image *image = current->thread.abi->vdso;
struct mm_struct *mm = current->mm;
+ unsigned long gic_size, vvar_size, size, base, data_addr, vdso_addr;
+ struct vm_area_struct *vma;
+ struct resource gic_res;
+ int ret;
down_write(&mm->mmap_sem);
- addr = vdso_addr(mm->start_stack);
+ /*
+ * Determine total area size. This includes the VDSO data itself, the
+ * data page, and the GIC user page if present. Always create a mapping
+ * for the GIC user area if the GIC is present regardless of whether it
+ * is the current clocksource, in case it comes into use later on. We
+ * only map a page even though the total area is 64K, as we only need
+ * the counter registers at the start.
+ */
+ gic_size = gic_present ? PAGE_SIZE : 0;
+ vvar_size = gic_size + PAGE_SIZE;
+ size = vvar_size + image->size;
+
+ base = get_unmapped_area(NULL, 0, size, 0, 0);
+ if (IS_ERR_VALUE(base)) {
+ ret = base;
+ goto out;
+ }
+
+ data_addr = base + gic_size;
+ vdso_addr = data_addr + PAGE_SIZE;
- addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
- if (IS_ERR_VALUE(addr)) {
- ret = addr;
- goto up_fail;
+ vma = _install_special_mapping(mm, base, vvar_size,
+ VM_READ | VM_MAYREAD,
+ &vdso_vvar_mapping);
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto out;
}
- ret = install_special_mapping(mm, addr, PAGE_SIZE,
- VM_READ|VM_EXEC|
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
- &vdso_page);
+ /* Map GIC user page. */
+ if (gic_size) {
+ ret = gic_get_usm_range(&gic_res);
+ if (ret)
+ goto out;
+
+ ret = io_remap_pfn_range(vma, base,
+ gic_res.start >> PAGE_SHIFT,
+ gic_size,
+ pgprot_noncached(PAGE_READONLY));
+ if (ret)
+ goto out;
+ }
+ /* Map data page. */
+ ret = remap_pfn_range(vma, data_addr,
+ virt_to_phys(&vdso_data) >> PAGE_SHIFT,
+ PAGE_SIZE, PAGE_READONLY);
if (ret)
- goto up_fail;
+ goto out;
+
+ /* Map VDSO image. */
+ vma = _install_special_mapping(mm, vdso_addr, image->size,
+ VM_READ | VM_EXEC |
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
+ &image->mapping);
+ if (IS_ERR(vma)) {
+ ret = PTR_ERR(vma);
+ goto out;
+ }
- mm->context.vdso = (void *)addr;
+ mm->context.vdso = (void *)vdso_addr;
+ ret = 0;
-up_fail:
+out:
up_write(&mm->mmap_sem);
return ret;
}
-
-const char *arch_vma_name(struct vm_area_struct *vma)
-{
- if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
- return "[vdso]";
- return NULL;
-}
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 07d32a4..0a93e83 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -17,7 +17,9 @@ OUTPUT_ARCH(mips)
ENTRY(kernel_entry)
PHDRS {
text PT_LOAD FLAGS(7); /* RWX */
+#ifndef CONFIG_CAVIUM_OCTEON_SOC
note PT_NOTE FLAGS(4); /* R__ */
+#endif /* CAVIUM_OCTEON_SOC */
}
#ifdef CONFIG_32BIT
@@ -71,7 +73,12 @@ SECTIONS
__stop___dbe_table = .;
}
- NOTES :text :note
+#ifdef CONFIG_CAVIUM_OCTEON_SOC
+#define NOTES_HEADER
+#else /* CONFIG_CAVIUM_OCTEON_SOC */
+#define NOTES_HEADER :note
+#endif /* CONFIG_CAVIUM_OCTEON_SOC */
+ NOTES :text NOTES_HEADER
.dummy : { *(.dummy) } :text
_sdata = .; /* Start of data section */
@@ -132,6 +139,11 @@ SECTIONS
__appended_dtb = .;
/* leave space for appended DTB */
. += 0x100000;
+#elif defined(CONFIG_MIPS_ELF_APPENDED_DTB)
+ .appended_dtb : AT(ADDR(.appended_dtb) - LOAD_OFFSET) {
+ *(.appended_dtb)
+ KEEP(*(.appended_dtb))
+ }
#endif
/*
* Align to 64K in attempt to eliminate holes before the
@@ -181,6 +193,7 @@ SECTIONS
DISCARDS
/DISCARD/ : {
/* ABI crap starts here */
+ *(.MIPS.abiflags)
*(.MIPS.options)
*(.options)
*(.pdr)
diff --git a/arch/mips/kvm/emulate.c b/arch/mips/kvm/emulate.c
index d5fa3ea..41b1b09 100644
--- a/arch/mips/kvm/emulate.c
+++ b/arch/mips/kvm/emulate.c
@@ -1581,7 +1581,7 @@ enum emulation_result kvm_mips_emulate_cache(uint32_t inst, uint32_t *opc,
base = (inst >> 21) & 0x1f;
op_inst = (inst >> 16) & 0x1f;
- offset = inst & 0xffff;
+ offset = (int16_t)inst;
cache = (inst >> 16) & 0x3;
op = (inst >> 18) & 0x7;
diff --git a/arch/mips/kvm/locore.S b/arch/mips/kvm/locore.S
index c567240..7e22108 100644
--- a/arch/mips/kvm/locore.S
+++ b/arch/mips/kvm/locore.S
@@ -36,14 +36,6 @@
#define PT_HOST_USERLOCAL PT_EPC
#define CP0_DDATA_LO $28,3
-#define CP0_CONFIG3 $16,3
-#define CP0_CONFIG5 $16,5
-#define CP0_EBASE $15,1
-
-#define CP0_INTCTL $12,1
-#define CP0_SRSCTL $12,2
-#define CP0_SRSMAP $12,3
-#define CP0_HWRENA $7,0
/* Resume Flags */
#define RESUME_FLAG_HOST (1<<1) /* Resume host? */
@@ -165,9 +157,11 @@ FEXPORT(__kvm_mips_vcpu_run)
FEXPORT(__kvm_mips_load_asid)
/* Set the ASID for the Guest Kernel */
- INT_SLL t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */
- /* addresses shift to 0x80000000 */
- bltz t0, 1f /* If kernel */
+ PTR_L t0, VCPU_COP0(k1)
+ LONG_L t0, COP0_STATUS(t0)
+ andi t0, KSU_USER | ST0_ERL | ST0_EXL
+ xori t0, KSU_USER
+ bnez t0, 1f /* If kernel */
INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */
INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID /* else user */
1:
@@ -482,9 +476,11 @@ __kvm_mips_return_to_guest:
mtc0 t0, CP0_EPC
/* Set the ASID for the Guest Kernel */
- INT_SLL t0, t0, 1 /* with kseg0 @ 0x40000000, kernel */
- /* addresses shift to 0x80000000 */
- bltz t0, 1f /* If kernel */
+ PTR_L t0, VCPU_COP0(k1)
+ LONG_L t0, COP0_STATUS(t0)
+ andi t0, KSU_USER | ST0_ERL | ST0_EXL
+ xori t0, KSU_USER
+ bnez t0, 1f /* If kernel */
INT_ADDIU t1, k1, VCPU_GUEST_KERNEL_ASID /* (BD) */
INT_ADDIU t1, k1, VCPU_GUEST_USER_ASID /* else user */
1:
diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
index 49ff3bf..b9b803f 100644
--- a/arch/mips/kvm/mips.c
+++ b/arch/mips/kvm/mips.c
@@ -279,7 +279,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
if (!gebase) {
err = -ENOMEM;
- goto out_free_cpu;
+ goto out_uninit_cpu;
}
kvm_debug("Allocated %d bytes for KVM Exception Handlers @ %p\n",
ALIGN(size, PAGE_SIZE), gebase);
@@ -343,6 +343,9 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
out_free_gebase:
kfree(gebase);
+out_uninit_cpu:
+ kvm_vcpu_uninit(vcpu);
+
out_free_cpu:
kfree(vcpu);
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
index 3fc2e6d..a0706fd 100644
--- a/arch/mips/lantiq/clk.c
+++ b/arch/mips/lantiq/clk.c
@@ -99,6 +99,23 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL(clk_set_rate);
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ if (unlikely(!clk_good(clk)))
+ return 0;
+ if (clk->rates && *clk->rates) {
+ unsigned long *r = clk->rates;
+
+ while (*r && (*r != rate))
+ r++;
+ if (!*r) {
+ return clk->rate;
+ }
+ }
+ return rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
int clk_enable(struct clk *clk)
{
if (unlikely(!clk_good(clk)))
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
index 77e4bdb..7376ce8 100644
--- a/arch/mips/lantiq/clk.h
+++ b/arch/mips/lantiq/clk.h
@@ -31,13 +31,18 @@
#define CLOCK_240M 240000000
#define CLOCK_250M 250000000
#define CLOCK_266M 266666666
+#define CLOCK_288M 288888888
#define CLOCK_300M 300000000
#define CLOCK_333M 333333333
+#define CLOCK_360M 360000000
#define CLOCK_393M 393215332
#define CLOCK_400M 400000000
+#define CLOCK_432M 432000000
#define CLOCK_450M 450000000
#define CLOCK_500M 500000000
#define CLOCK_600M 600000000
+#define CLOCK_666M 666666666
+#define CLOCK_720M 720000000
/* clock out speeds */
#define CLOCK_32_768K 32768
@@ -80,4 +85,12 @@ extern unsigned long ltq_vr9_cpu_hz(void);
extern unsigned long ltq_vr9_fpi_hz(void);
extern unsigned long ltq_vr9_pp32_hz(void);
+extern unsigned long ltq_ar10_cpu_hz(void);
+extern unsigned long ltq_ar10_fpi_hz(void);
+extern unsigned long ltq_ar10_pp32_hz(void);
+
+extern unsigned long ltq_grx390_cpu_hz(void);
+extern unsigned long ltq_grx390_fpi_hz(void);
+extern unsigned long ltq_grx390_pp32_hz(void);
+
#endif
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c
index 2c218c3..2e7f60c 100644
--- a/arch/mips/lantiq/irq.c
+++ b/arch/mips/lantiq/irq.c
@@ -369,8 +369,8 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
if (of_address_to_resource(node, i, &res))
panic("Failed to get icu memory range");
- if (request_mem_region(res.start, resource_size(&res),
- res.name) < 0)
+ if (!request_mem_region(res.start, resource_size(&res),
+ res.name))
pr_err("Failed to request icu memory");
ltq_icu_membase[i] = ioremap_nocache(res.start,
@@ -449,8 +449,8 @@ int __init icu_of_init(struct device_node *node, struct device_node *parent)
if (ret != exin_avail)
panic("failed to load external irq resources");
- if (request_mem_region(res.start, resource_size(&res),
- res.name) < 0)
+ if (!request_mem_region(res.start, resource_size(&res),
+ res.name))
pr_err("Failed to request eiu memory");
ltq_eiu_membase = ioremap_nocache(res.start,
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c
index 0db099e..297bcaa 100644
--- a/arch/mips/lantiq/prom.c
+++ b/arch/mips/lantiq/prom.c
@@ -77,8 +77,6 @@ void __init plat_mem_setup(void)
* parsed resulting in our memory appearing
*/
__dt_setup_arch(__dtb_start);
-
- strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
}
void __init device_tree_init(void)
diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c
index 8750dc0..07f6d5b 100644
--- a/arch/mips/lantiq/xway/clk.c
+++ b/arch/mips/lantiq/xway/clk.c
@@ -4,6 +4,7 @@
* by the Free Software Foundation.
*
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
*/
#include <linux/io.h>
@@ -25,9 +26,9 @@ static unsigned int ram_clocks[] = {
/* legacy xway clock */
#define CGU_SYS 0x10
-/* vr9 clock */
-#define CGU_SYS_VR9 0x0c
-#define CGU_IF_CLK_VR9 0x24
+/* vr9, ar10/grx390 clock */
+#define CGU_SYS_XRX 0x0c
+#define CGU_IF_CLK_AR10 0x24
unsigned long ltq_danube_fpi_hz(void)
{
@@ -87,8 +88,9 @@ unsigned long ltq_ar9_fpi_hz(void)
unsigned long sys = ltq_ar9_sys_hz();
if (ltq_cgu_r32(CGU_SYS) & BIT(0))
- return sys;
- return sys >> 1;
+ return sys / 3;
+ else
+ return sys / 2;
}
unsigned long ltq_ar9_cpu_hz(void)
@@ -104,7 +106,7 @@ unsigned long ltq_vr9_cpu_hz(void)
unsigned int cpu_sel;
unsigned long clk;
- cpu_sel = (ltq_cgu_r32(CGU_SYS_VR9) >> 4) & 0xf;
+ cpu_sel = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0xf;
switch (cpu_sel) {
case 0:
@@ -145,7 +147,7 @@ unsigned long ltq_vr9_fpi_hz(void)
unsigned long clk;
cpu_clk = ltq_vr9_cpu_hz();
- ocp_sel = ltq_cgu_r32(CGU_SYS_VR9) & 0x3;
+ ocp_sel = ltq_cgu_r32(CGU_SYS_XRX) & 0x3;
switch (ocp_sel) {
case 0:
@@ -174,15 +176,18 @@ unsigned long ltq_vr9_fpi_hz(void)
unsigned long ltq_vr9_pp32_hz(void)
{
- unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 3;
+ unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
unsigned long clk;
switch (clksys) {
+ case 0:
+ clk = CLOCK_500M;
+ break;
case 1:
- clk = CLOCK_450M;
+ clk = CLOCK_432M;
break;
case 2:
- clk = CLOCK_300M;
+ clk = CLOCK_288M;
break;
default:
clk = CLOCK_500M;
@@ -191,3 +196,158 @@ unsigned long ltq_vr9_pp32_hz(void)
return clk;
}
+
+unsigned long ltq_ar10_cpu_hz(void)
+{
+ unsigned int clksys;
+ int cpu_fs = (ltq_cgu_r32(CGU_SYS_XRX) >> 8) & 0x1;
+ int freq_div = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7;
+
+ switch (cpu_fs) {
+ case 0:
+ clksys = CLOCK_500M;
+ break;
+ case 1:
+ clksys = CLOCK_600M;
+ break;
+ default:
+ clksys = CLOCK_500M;
+ break;
+ }
+
+ switch (freq_div) {
+ case 0:
+ return clksys;
+ case 1:
+ return clksys >> 1;
+ case 2:
+ return clksys >> 2;
+ default:
+ return clksys;
+ }
+}
+
+unsigned long ltq_ar10_fpi_hz(void)
+{
+ int freq_fpi = (ltq_cgu_r32(CGU_IF_CLK_AR10) >> 25) & 0xf;
+
+ switch (freq_fpi) {
+ case 1:
+ return CLOCK_300M;
+ case 5:
+ return CLOCK_250M;
+ case 2:
+ return CLOCK_150M;
+ case 6:
+ return CLOCK_125M;
+
+ default:
+ return CLOCK_125M;
+ }
+}
+
+unsigned long ltq_ar10_pp32_hz(void)
+{
+ unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
+ unsigned long clk;
+
+ switch (clksys) {
+ case 1:
+ clk = CLOCK_250M;
+ break;
+ case 4:
+ clk = CLOCK_400M;
+ break;
+ default:
+ clk = CLOCK_250M;
+ break;
+ }
+
+ return clk;
+}
+
+unsigned long ltq_grx390_cpu_hz(void)
+{
+ unsigned int clksys;
+ int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3);
+ int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7);
+
+ switch (cpu_fs) {
+ case 0:
+ clksys = CLOCK_600M;
+ break;
+ case 1:
+ clksys = CLOCK_666M;
+ break;
+ case 2:
+ clksys = CLOCK_720M;
+ break;
+ default:
+ clksys = CLOCK_600M;
+ break;
+ }
+
+ switch (freq_div) {
+ case 0:
+ return clksys;
+ case 1:
+ return clksys >> 1;
+ case 2:
+ return clksys >> 2;
+ default:
+ return clksys;
+ }
+}
+
+unsigned long ltq_grx390_fpi_hz(void)
+{
+ /* fpi clock is derived from ddr_clk */
+ unsigned int clksys;
+ int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3);
+ int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX)) & 0x7);
+ switch (cpu_fs) {
+ case 0:
+ clksys = CLOCK_600M;
+ break;
+ case 1:
+ clksys = CLOCK_666M;
+ break;
+ case 2:
+ clksys = CLOCK_720M;
+ break;
+ default:
+ clksys = CLOCK_600M;
+ break;
+ }
+
+ switch (freq_div) {
+ case 1:
+ return clksys >> 1;
+ case 2:
+ return clksys >> 2;
+ default:
+ return clksys >> 1;
+ }
+}
+
+unsigned long ltq_grx390_pp32_hz(void)
+{
+ unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7;
+ unsigned long clk;
+
+ switch (clksys) {
+ case 1:
+ clk = CLOCK_250M;
+ break;
+ case 2:
+ clk = CLOCK_432M;
+ break;
+ case 4:
+ clk = CLOCK_400M;
+ break;
+ default:
+ clk = CLOCK_250M;
+ break;
+ }
+ return clk;
+}
diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c
index 248429a..8f6e02f 100644
--- a/arch/mips/lantiq/xway/prom.c
+++ b/arch/mips/lantiq/xway/prom.c
@@ -4,6 +4,7 @@
* by the Free Software Foundation.
*
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
*/
#include <linux/export.h>
@@ -19,8 +20,11 @@
#define SOC_TWINPASS "Twinpass"
#define SOC_AMAZON_SE "Amazon_SE"
#define SOC_AR9 "AR9"
-#define SOC_GR9 "GR9"
-#define SOC_VR9 "VR9"
+#define SOC_GR9 "GRX200"
+#define SOC_VR9 "xRX200"
+#define SOC_VRX220 "xRX220"
+#define SOC_AR10 "xRX300"
+#define SOC_GRX390 "xRX330"
#define COMP_DANUBE "lantiq,danube"
#define COMP_TWINPASS "lantiq,twinpass"
@@ -28,6 +32,8 @@
#define COMP_AR9 "lantiq,ar9"
#define COMP_GR9 "lantiq,gr9"
#define COMP_VR9 "lantiq,vr9"
+#define COMP_AR10 "lantiq,ar10"
+#define COMP_GRX390 "lantiq,grx390"
#define PART_SHIFT 12
#define PART_MASK 0x0FFFFFFF
@@ -101,6 +107,12 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
i->compatible = COMP_VR9;
break;
+ case SOC_ID_VRX220:
+ i->name = SOC_VRX220;
+ i->type = SOC_TYPE_VRX220;
+ i->compatible = COMP_VR9;
+ break;
+
case SOC_ID_GRX282_2:
case SOC_ID_GRX288_2:
i->name = SOC_GR9;
@@ -108,6 +120,25 @@ void __init ltq_soc_detect(struct ltq_soc_info *i)
i->compatible = COMP_GR9;
break;
+ case SOC_ID_ARX362:
+ case SOC_ID_ARX368:
+ case SOC_ID_ARX382:
+ case SOC_ID_ARX388:
+ case SOC_ID_URX388:
+ i->name = SOC_AR10;
+ i->type = SOC_TYPE_AR10;
+ i->compatible = COMP_AR10;
+ break;
+
+ case SOC_ID_GRX383:
+ case SOC_ID_GRX369:
+ case SOC_ID_GRX387:
+ case SOC_ID_GRX389:
+ i->name = SOC_GRX390;
+ i->type = SOC_TYPE_GRX390;
+ i->compatible = COMP_GRX390;
+ break;
+
default:
unreachable();
break;
diff --git a/arch/mips/lantiq/xway/reset.c b/arch/mips/lantiq/xway/reset.c
index fe68f9a..bc29bb3 100644
--- a/arch/mips/lantiq/xway/reset.c
+++ b/arch/mips/lantiq/xway/reset.c
@@ -4,6 +4,7 @@
* by the Free Software Foundation.
*
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
*/
#include <linux/init.h>
@@ -22,9 +23,6 @@
#include "../prom.h"
-#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y))
-#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x))
-
/* reset request register */
#define RCU_RST_REQ 0x0010
/* reset status register */
@@ -32,11 +30,33 @@
/* vr9 gphy registers */
#define RCU_GFS_ADD0_XRX200 0x0020
#define RCU_GFS_ADD1_XRX200 0x0068
+/* xRX300 gphy registers */
+#define RCU_GFS_ADD0_XRX300 0x0020
+#define RCU_GFS_ADD1_XRX300 0x0058
+#define RCU_GFS_ADD2_XRX300 0x00AC
+/* xRX330 gphy registers */
+#define RCU_GFS_ADD0_XRX330 0x0020
+#define RCU_GFS_ADD1_XRX330 0x0058
+#define RCU_GFS_ADD2_XRX330 0x00AC
+#define RCU_GFS_ADD3_XRX330 0x0264
+
+/* xbar BE flag */
+#define RCU_AHB_ENDIAN 0x004C
+#define RCU_VR9_BE_AHB1S 0x00000008
/* reboot bit */
#define RCU_RD_GPHY0_XRX200 BIT(31)
#define RCU_RD_SRST BIT(30)
#define RCU_RD_GPHY1_XRX200 BIT(29)
+/* xRX300 bits */
+#define RCU_RD_GPHY0_XRX300 BIT(31)
+#define RCU_RD_GPHY1_XRX300 BIT(29)
+#define RCU_RD_GPHY2_XRX300 BIT(28)
+/* xRX330 bits */
+#define RCU_RD_GPHY0_XRX330 BIT(31)
+#define RCU_RD_GPHY1_XRX330 BIT(29)
+#define RCU_RD_GPHY2_XRX330 BIT(28)
+#define RCU_RD_GPHY3_XRX330 BIT(10)
/* reset cause */
#define RCU_STAT_SHIFT 26
@@ -44,9 +64,60 @@
#define RCU_BOOT_SEL(x) ((x >> 18) & 0x7)
#define RCU_BOOT_SEL_XRX200(x) (((x >> 17) & 0xf) | ((x >> 8) & 0x10))
+/* dwc2 USB configuration registers */
+#define RCU_USB1CFG 0x0018
+#define RCU_USB2CFG 0x0034
+
+/* USB DMA endianness bits */
+#define RCU_USBCFG_HDSEL_BIT BIT(11)
+#define RCU_USBCFG_HOST_END_BIT BIT(10)
+#define RCU_USBCFG_SLV_END_BIT BIT(9)
+
+/* USB reset bits */
+#define RCU_USBRESET 0x0010
+
+#define USBRESET_BIT BIT(4)
+
+#define RCU_USBRESET2 0x0048
+
+#define USB1RESET_BIT BIT(4)
+#define USB2RESET_BIT BIT(5)
+
+#define RCU_CFG1A 0x0038
+#define RCU_CFG1B 0x003C
+
+/* USB PMU devices */
+#define PMU_AHBM BIT(15)
+#define PMU_USB0 BIT(6)
+#define PMU_USB1 BIT(27)
+
+/* USB PHY PMU devices */
+#define PMU_USB0_P BIT(0)
+#define PMU_USB1_P BIT(26)
+
/* remapped base addr of the reset control unit */
static void __iomem *ltq_rcu_membase;
static struct device_node *ltq_rcu_np;
+static DEFINE_SPINLOCK(ltq_rcu_lock);
+
+static void ltq_rcu_w32(uint32_t val, uint32_t reg_off)
+{
+ ltq_w32(val, ltq_rcu_membase + reg_off);
+}
+
+static uint32_t ltq_rcu_r32(uint32_t reg_off)
+{
+ return ltq_r32(ltq_rcu_membase + reg_off);
+}
+
+static void ltq_rcu_w32_mask(uint32_t clr, uint32_t set, uint32_t reg_off)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ltq_rcu_lock, flags);
+ ltq_rcu_w32((ltq_rcu_r32(reg_off) & ~(clr)) | (set), reg_off);
+ spin_unlock_irqrestore(&ltq_rcu_lock, flags);
+}
/* This function is used by the watchdog driver */
int ltq_reset_cause(void)
@@ -67,15 +138,40 @@ unsigned char ltq_boot_select(void)
return RCU_BOOT_SEL(val);
}
-/* reset / boot a gphy */
-static struct ltq_xrx200_gphy_reset {
+struct ltq_gphy_reset {
u32 rd;
u32 addr;
-} xrx200_gphy[] = {
+};
+
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx200_gphy[] = {
{RCU_RD_GPHY0_XRX200, RCU_GFS_ADD0_XRX200},
{RCU_RD_GPHY1_XRX200, RCU_GFS_ADD1_XRX200},
};
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx300_gphy[] = {
+ {RCU_RD_GPHY0_XRX300, RCU_GFS_ADD0_XRX300},
+ {RCU_RD_GPHY1_XRX300, RCU_GFS_ADD1_XRX300},
+ {RCU_RD_GPHY2_XRX300, RCU_GFS_ADD2_XRX300},
+};
+
+/* reset / boot a gphy */
+static struct ltq_gphy_reset xrx330_gphy[] = {
+ {RCU_RD_GPHY0_XRX330, RCU_GFS_ADD0_XRX330},
+ {RCU_RD_GPHY1_XRX330, RCU_GFS_ADD1_XRX330},
+ {RCU_RD_GPHY2_XRX330, RCU_GFS_ADD2_XRX330},
+ {RCU_RD_GPHY3_XRX330, RCU_GFS_ADD3_XRX330},
+};
+
+static void xrx200_gphy_boot_addr(struct ltq_gphy_reset *phy_regs,
+ dma_addr_t dev_addr)
+{
+ ltq_rcu_w32_mask(0, phy_regs->rd, RCU_RST_REQ);
+ ltq_rcu_w32(dev_addr, phy_regs->addr);
+ ltq_rcu_w32_mask(phy_regs->rd, 0, RCU_RST_REQ);
+}
+
/* reset and boot a gphy. these phys only exist on xrx200 SoC */
int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
{
@@ -86,23 +182,34 @@ int xrx200_gphy_boot(struct device *dev, unsigned int id, dma_addr_t dev_addr)
return -EINVAL;
}
- clk = clk_get_sys("1f203000.rcu", "gphy");
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
- clk_enable(clk);
-
- if (id > 1) {
- dev_err(dev, "%u is an invalid gphy id\n", id);
- return -EINVAL;
+ if (of_machine_is_compatible("lantiq,vr9")) {
+ clk = clk_get_sys("1f203000.rcu", "gphy");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+ clk_enable(clk);
}
+
dev_info(dev, "booting GPHY%u firmware at %X\n", id, dev_addr);
- ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) | xrx200_gphy[id].rd,
- RCU_RST_REQ);
- ltq_rcu_w32(dev_addr, xrx200_gphy[id].addr);
- ltq_rcu_w32(ltq_rcu_r32(RCU_RST_REQ) & ~xrx200_gphy[id].rd,
- RCU_RST_REQ);
+ if (of_machine_is_compatible("lantiq,vr9")) {
+ if (id >= ARRAY_SIZE(xrx200_gphy)) {
+ dev_err(dev, "%u is an invalid gphy id\n", id);
+ return -EINVAL;
+ }
+ xrx200_gphy_boot_addr(&xrx200_gphy[id], dev_addr);
+ } else if (of_machine_is_compatible("lantiq,ar10")) {
+ if (id >= ARRAY_SIZE(xrx300_gphy)) {
+ dev_err(dev, "%u is an invalid gphy id\n", id);
+ return -EINVAL;
+ }
+ xrx200_gphy_boot_addr(&xrx300_gphy[id], dev_addr);
+ } else if (of_machine_is_compatible("lantiq,grx390")) {
+ if (id >= ARRAY_SIZE(xrx330_gphy)) {
+ dev_err(dev, "%u is an invalid gphy id\n", id);
+ return -EINVAL;
+ }
+ xrx200_gphy_boot_addr(&xrx330_gphy[id], dev_addr);
+ }
return 0;
}
@@ -200,6 +307,45 @@ static void ltq_machine_power_off(void)
unreachable();
}
+static void ltq_usb_init(void)
+{
+ /* Power for USB cores 1 & 2 */
+ ltq_pmu_enable(PMU_AHBM);
+ ltq_pmu_enable(PMU_USB0);
+ ltq_pmu_enable(PMU_USB1);
+
+ ltq_rcu_w32(ltq_rcu_r32(RCU_CFG1A) | BIT(0), RCU_CFG1A);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_CFG1B) | BIT(0), RCU_CFG1B);
+
+ /* Enable USB PHY power for cores 1 & 2 */
+ ltq_pmu_enable(PMU_USB0_P);
+ ltq_pmu_enable(PMU_USB1_P);
+
+ /* Configure cores to host mode */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USB1CFG) & ~RCU_USBCFG_HDSEL_BIT,
+ RCU_USB1CFG);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USB2CFG) & ~RCU_USBCFG_HDSEL_BIT,
+ RCU_USB2CFG);
+
+ /* Select DMA endianness (Host-endian: big-endian) */
+ ltq_rcu_w32((ltq_rcu_r32(RCU_USB1CFG) & ~RCU_USBCFG_SLV_END_BIT)
+ | RCU_USBCFG_HOST_END_BIT, RCU_USB1CFG);
+ ltq_rcu_w32(ltq_rcu_r32((RCU_USB2CFG) & ~RCU_USBCFG_SLV_END_BIT)
+ | RCU_USBCFG_HOST_END_BIT, RCU_USB2CFG);
+
+ /* Hard reset USB state machines */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET) | USBRESET_BIT, RCU_USBRESET);
+ udelay(50 * 1000);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET) & ~USBRESET_BIT, RCU_USBRESET);
+
+ /* Soft reset USB state machines */
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET2)
+ | USB1RESET_BIT | USB2RESET_BIT, RCU_USBRESET2);
+ udelay(50 * 1000);
+ ltq_rcu_w32(ltq_rcu_r32(RCU_USBRESET2)
+ & ~(USB1RESET_BIT | USB2RESET_BIT), RCU_USBRESET2);
+}
+
static int __init mips_reboot_setup(void)
{
struct resource res;
@@ -216,13 +362,21 @@ static int __init mips_reboot_setup(void)
if (of_address_to_resource(ltq_rcu_np, 0, &res))
panic("Failed to get rcu memory range");
- if (request_mem_region(res.start, resource_size(&res), res.name) < 0)
+ if (!request_mem_region(res.start, resource_size(&res), res.name))
pr_err("Failed to request rcu memory");
ltq_rcu_membase = ioremap_nocache(res.start, resource_size(&res));
if (!ltq_rcu_membase)
panic("Failed to remap core memory");
+ if (of_machine_is_compatible("lantiq,ar9") ||
+ of_machine_is_compatible("lantiq,vr9"))
+ ltq_usb_init();
+
+ if (of_machine_is_compatible("lantiq,vr9"))
+ ltq_rcu_w32(ltq_rcu_r32(RCU_AHB_ENDIAN) | RCU_VR9_BE_AHB1S,
+ RCU_AHB_ENDIAN);
+
_machine_restart = ltq_machine_restart;
_machine_halt = ltq_machine_halt;
pm_power_off = ltq_machine_power_off;
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
index 2b15491..80554e8 100644
--- a/arch/mips/lantiq/xway/sysctrl.c
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -4,11 +4,13 @@
* by the Free Software Foundation.
*
* Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG
*/
#include <linux/ioport.h>
#include <linux/export.h>
#include <linux/clkdev.h>
+#include <linux/spinlock.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
@@ -18,16 +20,18 @@
#include "../clk.h"
#include "../prom.h"
-/* clock control register */
+/* clock control register for legacy */
#define CGU_IFCCR 0x0018
#define CGU_IFCCR_VR9 0x0024
-/* system clock register */
+/* system clock register for legacy */
#define CGU_SYS 0x0010
/* pci control register */
#define CGU_PCICR 0x0034
#define CGU_PCICR_VR9 0x0038
/* ephy configuration register */
#define CGU_EPHY 0x10
+
+/* Legacy PMU register for ar9, ase, danube */
/* power control register */
#define PMU_PWDCR 0x1C
/* power status register */
@@ -41,13 +45,56 @@
/* power status register */
#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
+
+/* PMU register for ar10 and grx390 */
+
+/* First register set */
+#define PMU_CLK_SR 0x20 /* status */
+#define PMU_CLK_CR_A 0x24 /* Enable */
+#define PMU_CLK_CR_B 0x28 /* Disable */
+/* Second register set */
+#define PMU_CLK_SR1 0x30 /* status */
+#define PMU_CLK_CR1_A 0x34 /* Enable */
+#define PMU_CLK_CR1_B 0x38 /* Disable */
+/* Third register set */
+#define PMU_ANA_SR 0x40 /* status */
+#define PMU_ANA_CR_A 0x44 /* Enable */
+#define PMU_ANA_CR_B 0x48 /* Disable */
+
+/* Status */
+static u32 pmu_clk_sr[] = {
+ PMU_CLK_SR,
+ PMU_CLK_SR1,
+ PMU_ANA_SR,
+};
+
+/* Enable */
+static u32 pmu_clk_cr_a[] = {
+ PMU_CLK_CR_A,
+ PMU_CLK_CR1_A,
+ PMU_ANA_CR_A,
+};
+
+/* Disable */
+static u32 pmu_clk_cr_b[] = {
+ PMU_CLK_CR_B,
+ PMU_CLK_CR1_B,
+ PMU_ANA_CR_B,
+};
+
+#define PWDCR_EN_XRX(x) (pmu_clk_cr_a[(x)])
+#define PWDCR_DIS_XRX(x) (pmu_clk_cr_b[(x)])
+#define PWDSR_XRX(x) (pmu_clk_sr[(x)])
+
/* clock gates that we can en/disable */
#define PMU_USB0_P BIT(0)
+#define PMU_ASE_SDIO BIT(2) /* ASE special */
#define PMU_PCI BIT(4)
#define PMU_DMA BIT(5)
#define PMU_USB0 BIT(6)
#define PMU_ASC0 BIT(7)
#define PMU_EPHY BIT(7) /* ase */
+#define PMU_USIF BIT(7) /* from vr9 until grx390 */
#define PMU_SPI BIT(8)
#define PMU_DFE BIT(9)
#define PMU_EBU BIT(10)
@@ -56,12 +103,15 @@
#define PMU_AHBS BIT(13) /* vr9 */
#define PMU_FPI BIT(14)
#define PMU_AHBM BIT(15)
+#define PMU_SDIO BIT(16) /* danube, ar9, vr9 */
#define PMU_ASC1 BIT(17)
#define PMU_PPE_QSB BIT(18)
#define PMU_PPE_SLL01 BIT(19)
+#define PMU_DEU BIT(20)
#define PMU_PPE_TC BIT(21)
#define PMU_PPE_EMA BIT(22)
#define PMU_PPE_DPLUM BIT(23)
+#define PMU_PPE_DP BIT(23)
#define PMU_PPE_DPLUS BIT(24)
#define PMU_USB1_P BIT(26)
#define PMU_USB1 BIT(27)
@@ -70,30 +120,59 @@
#define PMU_GPHY BIT(30)
#define PMU_PCIE_CLK BIT(31)
-#define PMU1_PCIE_PHY BIT(0)
+#define PMU1_PCIE_PHY BIT(0) /* vr9-specific,moved in ar10/grx390 */
#define PMU1_PCIE_CTL BIT(1)
#define PMU1_PCIE_PDI BIT(4)
#define PMU1_PCIE_MSI BIT(5)
+#define PMU1_CKE BIT(6)
+#define PMU1_PCIE1_CTL BIT(17)
+#define PMU1_PCIE1_PDI BIT(20)
+#define PMU1_PCIE1_MSI BIT(21)
+#define PMU1_PCIE2_CTL BIT(25)
+#define PMU1_PCIE2_PDI BIT(26)
+#define PMU1_PCIE2_MSI BIT(27)
+
+#define PMU_ANALOG_USB0_P BIT(0)
+#define PMU_ANALOG_USB1_P BIT(1)
+#define PMU_ANALOG_PCIE0_P BIT(8)
+#define PMU_ANALOG_PCIE1_P BIT(9)
+#define PMU_ANALOG_PCIE2_P BIT(10)
+#define PMU_ANALOG_DSL_AFE BIT(16)
+#define PMU_ANALOG_DCDC_2V5 BIT(17)
+#define PMU_ANALOG_DCDC_1VX BIT(18)
+#define PMU_ANALOG_DCDC_1V0 BIT(19)
#define pmu_w32(x, y) ltq_w32((x), pmu_membase + (y))
#define pmu_r32(x) ltq_r32(pmu_membase + (x))
+#define XBAR_ALWAYS_LAST 0x430
+#define XBAR_FPI_BURST_EN BIT(1)
+#define XBAR_AHB_BURST_EN BIT(2)
+
+#define xbar_w32(x, y) ltq_w32((x), ltq_xbar_membase + (y))
+#define xbar_r32(x) ltq_r32(ltq_xbar_membase + (x))
+
static void __iomem *pmu_membase;
+static void __iomem *ltq_xbar_membase;
void __iomem *ltq_cgu_membase;
void __iomem *ltq_ebu_membase;
static u32 ifccr = CGU_IFCCR;
static u32 pcicr = CGU_PCICR;
+static DEFINE_SPINLOCK(g_pmu_lock);
+
/* legacy function kept alive to ease clkdev transition */
void ltq_pmu_enable(unsigned int module)
{
- int err = 1000000;
+ int retry = 1000000;
+ spin_lock(&g_pmu_lock);
pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR);
- do {} while (--err && (pmu_r32(PMU_PWDSR) & module));
+ do {} while (--retry && (pmu_r32(PMU_PWDSR) & module));
+ spin_unlock(&g_pmu_lock);
- if (!err)
+ if (!retry)
panic("activating PMU module failed!");
}
EXPORT_SYMBOL(ltq_pmu_enable);
@@ -101,7 +180,15 @@ EXPORT_SYMBOL(ltq_pmu_enable);
/* legacy function kept alive to ease clkdev transition */
void ltq_pmu_disable(unsigned int module)
{
+ int retry = 1000000;
+
+ spin_lock(&g_pmu_lock);
pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR);
+ do {} while (--retry && (!(pmu_r32(PMU_PWDSR) & module)));
+ spin_unlock(&g_pmu_lock);
+
+ if (!retry)
+ pr_warn("deactivating PMU module failed!");
}
EXPORT_SYMBOL(ltq_pmu_disable);
@@ -123,9 +210,20 @@ static int pmu_enable(struct clk *clk)
{
int retry = 1000000;
- pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits,
- PWDCR(clk->module));
- do {} while (--retry && (pmu_r32(PWDSR(clk->module)) & clk->bits));
+ if (of_machine_is_compatible("lantiq,ar10")
+ || of_machine_is_compatible("lantiq,grx390")) {
+ pmu_w32(clk->bits, PWDCR_EN_XRX(clk->module));
+ do {} while (--retry &&
+ (!(pmu_r32(PWDSR_XRX(clk->module)) & clk->bits)));
+
+ } else {
+ spin_lock(&g_pmu_lock);
+ pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits,
+ PWDCR(clk->module));
+ do {} while (--retry &&
+ (pmu_r32(PWDSR(clk->module)) & clk->bits));
+ spin_unlock(&g_pmu_lock);
+ }
if (!retry)
panic("activating PMU module failed!");
@@ -136,8 +234,24 @@ static int pmu_enable(struct clk *clk)
/* disable a clock gate */
static void pmu_disable(struct clk *clk)
{
- pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits,
- PWDCR(clk->module));
+ int retry = 1000000;
+
+ if (of_machine_is_compatible("lantiq,ar10")
+ || of_machine_is_compatible("lantiq,grx390")) {
+ pmu_w32(clk->bits, PWDCR_DIS_XRX(clk->module));
+ do {} while (--retry &&
+ (pmu_r32(PWDSR_XRX(clk->module)) & clk->bits));
+ } else {
+ spin_lock(&g_pmu_lock);
+ pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits,
+ PWDCR(clk->module));
+ do {} while (--retry &&
+ (!(pmu_r32(PWDSR(clk->module)) & clk->bits)));
+ spin_unlock(&g_pmu_lock);
+ }
+
+ if (!retry)
+ pr_warn("deactivating PMU module failed!");
}
/* the pci enable helper */
@@ -179,6 +293,16 @@ static void pci_ext_disable(struct clk *clk)
ltq_cgu_w32((1 << 31) | (1 << 30), pcicr);
}
+static void xbar_fpi_burst_disable(void)
+{
+ u32 reg;
+
+ /* bit 1 as 1 --burst; bit 1 as 0 -- single */
+ reg = xbar_r32(XBAR_ALWAYS_LAST);
+ reg &= ~XBAR_FPI_BURST_EN;
+ xbar_w32(reg, XBAR_ALWAYS_LAST);
+}
+
/* enable a clockout source */
static int clkout_enable(struct clk *clk)
{
@@ -202,8 +326,8 @@ static int clkout_enable(struct clk *clk)
}
/* manage the clock gates via PMU */
-static void clkdev_add_pmu(const char *dev, const char *con,
- unsigned int module, unsigned int bits)
+static void clkdev_add_pmu(const char *dev, const char *con, bool deactivate,
+ unsigned int module, unsigned int bits)
{
struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
@@ -214,6 +338,13 @@ static void clkdev_add_pmu(const char *dev, const char *con,
clk->disable = pmu_disable;
clk->module = module;
clk->bits = bits;
+ if (deactivate) {
+ /*
+ * Disable it during the initialization. Module should enable
+ * when used
+ */
+ pmu_disable(clk);
+ }
clkdev_add(&clk->cl);
}
@@ -312,12 +443,12 @@ void __init ltq_soc_init(void)
of_address_to_resource(np_ebu, 0, &res_ebu))
panic("Failed to get core resources");
- if ((request_mem_region(res_pmu.start, resource_size(&res_pmu),
- res_pmu.name) < 0) ||
- (request_mem_region(res_cgu.start, resource_size(&res_cgu),
- res_cgu.name) < 0) ||
- (request_mem_region(res_ebu.start, resource_size(&res_ebu),
- res_ebu.name) < 0))
+ if (!request_mem_region(res_pmu.start, resource_size(&res_pmu),
+ res_pmu.name) ||
+ !request_mem_region(res_cgu.start, resource_size(&res_cgu),
+ res_cgu.name) ||
+ !request_mem_region(res_ebu.start, resource_size(&res_ebu),
+ res_ebu.name))
pr_err("Failed to request core resources");
pmu_membase = ioremap_nocache(res_pmu.start, resource_size(&res_pmu));
@@ -328,17 +459,37 @@ void __init ltq_soc_init(void)
if (!pmu_membase || !ltq_cgu_membase || !ltq_ebu_membase)
panic("Failed to remap core resources");
+ if (of_machine_is_compatible("lantiq,vr9")) {
+ struct resource res_xbar;
+ struct device_node *np_xbar =
+ of_find_compatible_node(NULL, NULL,
+ "lantiq,xbar-xway");
+
+ if (!np_xbar)
+ panic("Failed to load xbar nodes from devicetree");
+ if (of_address_to_resource(np_pmu, 0, &res_xbar))
+ panic("Failed to get xbar resources");
+ if (request_mem_region(res_xbar.start, resource_size(&res_xbar),
+ res_xbar.name) < 0)
+ panic("Failed to get xbar resources");
+
+ ltq_xbar_membase = ioremap_nocache(res_xbar.start,
+ resource_size(&res_xbar));
+ if (!ltq_xbar_membase)
+ panic("Failed to remap xbar resources");
+ }
+
/* make sure to unprotect the memory region where flash is located */
ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
/* add our generic xway clocks */
- clkdev_add_pmu("10000000.fpi", NULL, 0, PMU_FPI);
- clkdev_add_pmu("1e100400.serial", NULL, 0, PMU_ASC0);
- clkdev_add_pmu("1e100a00.gptu", NULL, 0, PMU_GPT);
- clkdev_add_pmu("1e100bb0.stp", NULL, 0, PMU_STP);
- clkdev_add_pmu("1e104100.dma", NULL, 0, PMU_DMA);
- clkdev_add_pmu("1e100800.spi", NULL, 0, PMU_SPI);
- clkdev_add_pmu("1e105300.ebu", NULL, 0, PMU_EBU);
+ clkdev_add_pmu("10000000.fpi", NULL, 0, 0, PMU_FPI);
+ clkdev_add_pmu("1e100400.serial", NULL, 0, 0, PMU_ASC0);
+ clkdev_add_pmu("1e100a00.gptu", NULL, 1, 0, PMU_GPT);
+ clkdev_add_pmu("1e100bb0.stp", NULL, 1, 0, PMU_STP);
+ clkdev_add_pmu("1e104100.dma", NULL, 1, 0, PMU_DMA);
+ clkdev_add_pmu("1e100800.spi", NULL, 1, 0, PMU_SPI);
+ clkdev_add_pmu("1e105300.ebu", NULL, 0, 0, PMU_EBU);
clkdev_add_clkout();
/* add the soc dependent clocks */
@@ -346,14 +497,30 @@ void __init ltq_soc_init(void)
ifccr = CGU_IFCCR_VR9;
pcicr = CGU_PCICR_VR9;
} else {
- clkdev_add_pmu("1e180000.etop", NULL, 0, PMU_PPE);
+ clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE);
}
if (!of_machine_is_compatible("lantiq,ase")) {
- clkdev_add_pmu("1e100c00.serial", NULL, 0, PMU_ASC1);
+ clkdev_add_pmu("1e100c00.serial", NULL, 0, 0, PMU_ASC1);
clkdev_add_pci();
}
+ if (of_machine_is_compatible("lantiq,grx390") ||
+ of_machine_is_compatible("lantiq,ar10")) {
+ clkdev_add_pmu("1e101000.usb", "phy", 1, 2, PMU_ANALOG_USB0_P);
+ clkdev_add_pmu("1e106000.usb", "phy", 1, 2, PMU_ANALOG_USB1_P);
+ /* rc 0 */
+ clkdev_add_pmu("1d900000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE0_P);
+ clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI);
+ clkdev_add_pmu("1d900000.pcie", "pdi", 1, 1, PMU1_PCIE_PDI);
+ clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL);
+ /* rc 1 */
+ clkdev_add_pmu("19000000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE1_P);
+ clkdev_add_pmu("19000000.pcie", "msi", 1, 1, PMU1_PCIE1_MSI);
+ clkdev_add_pmu("19000000.pcie", "pdi", 1, 1, PMU1_PCIE1_PDI);
+ clkdev_add_pmu("19000000.pcie", "ctl", 1, 1, PMU1_PCIE1_CTL);
+ }
+
if (of_machine_is_compatible("lantiq,ase")) {
if (ltq_cgu_r32(CGU_SYS) & (1 << 5))
clkdev_add_static(CLOCK_266M, CLOCK_133M,
@@ -361,28 +528,84 @@ void __init ltq_soc_init(void)
else
clkdev_add_static(CLOCK_133M, CLOCK_133M,
CLOCK_133M, CLOCK_133M);
- clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY),
- clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY);
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+ clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE);
+ clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY);
+ clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY);
+ clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+ } else if (of_machine_is_compatible("lantiq,grx390")) {
+ clkdev_add_static(ltq_grx390_cpu_hz(), ltq_grx390_fpi_hz(),
+ ltq_grx390_fpi_hz(), ltq_grx390_pp32_hz());
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+ /* rc 2 */
+ clkdev_add_pmu("1a800000.pcie", "phy", 1, 2, PMU_ANALOG_PCIE2_P);
+ clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI);
+ clkdev_add_pmu("1a800000.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI);
+ clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL);
+ clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH | PMU_PPE_DP);
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ } else if (of_machine_is_compatible("lantiq,ar10")) {
+ clkdev_add_static(ltq_ar10_cpu_hz(), ltq_ar10_fpi_hz(),
+ ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz());
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+ clkdev_add_pmu("1e108000.eth", NULL, 1, 0, PMU_SWITCH |
+ PMU_PPE_DP | PMU_PPE_TC);
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+ clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ clkdev_add_pmu("1e116000.mei", "afe", 1, 2, PMU_ANALOG_DSL_AFE);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
} else if (of_machine_is_compatible("lantiq,vr9")) {
clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(),
ltq_vr9_fpi_hz(), ltq_vr9_pp32_hz());
- clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY);
- clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK);
- clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI);
- clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI);
- clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL);
- clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
- clkdev_add_pmu("1e108000.eth", NULL, 0,
+ clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0 | PMU_AHBM);
+ clkdev_add_pmu("1e106000.usb", "phy", 1, 0, PMU_USB1_P);
+ clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1 | PMU_AHBM);
+ clkdev_add_pmu("1d900000.pcie", "phy", 1, 1, PMU1_PCIE_PHY);
+ clkdev_add_pmu("1d900000.pcie", "bus", 1, 0, PMU_PCIE_CLK);
+ clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI);
+ clkdev_add_pmu("1d900000.pcie", "pdi", 1, 1, PMU1_PCIE_PDI);
+ clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL);
+ clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS);
+
+ clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF);
+ clkdev_add_pmu("1e108000.eth", NULL, 1, 0,
PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM |
PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 |
PMU_PPE_QSB | PMU_PPE_TOP);
- clkdev_add_pmu("1f203000.rcu", "gphy", 0, PMU_GPHY);
+ clkdev_add_pmu("1f203000.rcu", "gphy", 1, 0, PMU_GPHY);
+ clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
} else if (of_machine_is_compatible("lantiq,ar9")) {
clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
ltq_ar9_fpi_hz(), CLOCK_250M);
- clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH);
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+ clkdev_add_pmu("1e106000.usb", "ctl", 1, 0, PMU_USB1);
+ clkdev_add_pmu("1e106000.usb", "phy", 1, 0, PMU_USB1_P);
+ clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH);
+ clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+ clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0);
} else {
clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
ltq_danube_fpi_hz(), ltq_danube_pp32_hz());
+ clkdev_add_pmu("1e101000.usb", "ctl", 1, 0, PMU_USB0);
+ clkdev_add_pmu("1e101000.usb", "phy", 1, 0, PMU_USB0_P);
+ clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO);
+ clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU);
+ clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE);
+ clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0);
}
+
+ if (of_machine_is_compatible("lantiq,vr9"))
+ xbar_fpi_burst_disable();
}
diff --git a/arch/mips/lasat/picvue_proc.c b/arch/mips/lasat/picvue_proc.c
index 2bcd839..b420958 100644
--- a/arch/mips/lasat/picvue_proc.c
+++ b/arch/mips/lasat/picvue_proc.c
@@ -22,7 +22,6 @@
static DEFINE_MUTEX(pvc_mutex);
static char pvc_lines[PVC_NLINES][PVC_LINELEN+1];
static int pvc_linedata[PVC_NLINES];
-static struct proc_dir_entry *pvc_display_dir;
static char *pvc_linename[PVC_NLINES] = {"line1", "line2"};
#define DISPLAY_DIR_NAME "display"
static int scroll_dir, scroll_interval;
@@ -169,22 +168,17 @@ void pvc_proc_timerfunc(unsigned long data)
static void pvc_proc_cleanup(void)
{
- int i;
- for (i = 0; i < PVC_NLINES; i++)
- remove_proc_entry(pvc_linename[i], pvc_display_dir);
- remove_proc_entry("scroll", pvc_display_dir);
- remove_proc_entry(DISPLAY_DIR_NAME, NULL);
-
+ remove_proc_subtree(DISPLAY_DIR_NAME, NULL);
del_timer_sync(&timer);
}
static int __init pvc_proc_init(void)
{
- struct proc_dir_entry *proc_entry;
+ struct proc_dir_entry *dir, *proc_entry;
int i;
- pvc_display_dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
- if (pvc_display_dir == NULL)
+ dir = proc_mkdir(DISPLAY_DIR_NAME, NULL);
+ if (dir == NULL)
goto error;
for (i = 0; i < PVC_NLINES; i++) {
@@ -192,12 +186,12 @@ static int __init pvc_proc_init(void)
pvc_linedata[i] = i;
}
for (i = 0; i < PVC_NLINES; i++) {
- proc_entry = proc_create_data(pvc_linename[i], 0644, pvc_display_dir,
+ proc_entry = proc_create_data(pvc_linename[i], 0644, dir,
&pvc_line_proc_fops, &pvc_linedata[i]);
if (proc_entry == NULL)
goto error;
}
- proc_entry = proc_create("scroll", 0644, pvc_display_dir,
+ proc_entry = proc_create("scroll", 0644, dir,
&pvc_scroll_proc_fops);
if (proc_entry == NULL)
goto error;
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 1e9e900..0344e57 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_CPU_R3000) += r3k_dump_tlb.o
obj-$(CONFIG_CPU_TX39XX) += r3k_dump_tlb.o
# libgcc-style stuff needed in the kernel
-obj-y += ashldi3.o ashrdi3.o cmpdi2.o lshrdi3.o ucmpdi2.o
+obj-y += ashldi3.o ashrdi3.o bswapsi.o bswapdi.o cmpdi2.o lshrdi3.o ucmpdi2.o
diff --git a/arch/mips/lib/bswapdi.c b/arch/mips/lib/bswapdi.c
new file mode 100644
index 0000000..77e5f9c
--- /dev/null
+++ b/arch/mips/lib/bswapdi.c
@@ -0,0 +1,15 @@
+#include <linux/module.h>
+
+unsigned long long __bswapdi2(unsigned long long u)
+{
+ return (((u) & 0xff00000000000000ull) >> 56) |
+ (((u) & 0x00ff000000000000ull) >> 40) |
+ (((u) & 0x0000ff0000000000ull) >> 24) |
+ (((u) & 0x000000ff00000000ull) >> 8) |
+ (((u) & 0x00000000ff000000ull) << 8) |
+ (((u) & 0x0000000000ff0000ull) << 24) |
+ (((u) & 0x000000000000ff00ull) << 40) |
+ (((u) & 0x00000000000000ffull) << 56);
+}
+
+EXPORT_SYMBOL(__bswapdi2);
diff --git a/arch/mips/lib/bswapsi.c b/arch/mips/lib/bswapsi.c
new file mode 100644
index 0000000..2b302ff
--- /dev/null
+++ b/arch/mips/lib/bswapsi.c
@@ -0,0 +1,11 @@
+#include <linux/module.h>
+
+unsigned int __bswapsi2(unsigned int u)
+{
+ return (((u) & 0xff000000) >> 24) |
+ (((u) & 0x00ff0000) >> 8) |
+ (((u) & 0x0000ff00) << 8) |
+ (((u) & 0x000000ff) << 24);
+}
+
+EXPORT_SYMBOL(__bswapsi2);
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
index b8e63fd..8f0019a 100644
--- a/arch/mips/lib/memset.S
+++ b/arch/mips/lib/memset.S
@@ -283,6 +283,8 @@ LEAF(memset)
1:
#ifndef CONFIG_EVA
FEXPORT(__bzero)
+#else
+FEXPORT(__bzero_kernel)
#endif
__BUILD_BZERO LEGACY_MODE
diff --git a/arch/mips/loongson64/Kconfig b/arch/mips/loongson64/Kconfig
index 497912b..8e6e292 100644
--- a/arch/mips/loongson64/Kconfig
+++ b/arch/mips/loongson64/Kconfig
@@ -120,11 +120,6 @@ config RS780_HPET
If unsure, say Yes.
-config LOONGSON_SUSPEND
- bool
- default y
- depends on CPU_SUPPORTS_CPUFREQ && SUSPEND
-
config LOONGSON_UART_BASE
bool
default y
diff --git a/arch/mips/loongson64/common/Makefile b/arch/mips/loongson64/common/Makefile
index f2e8153..074d9cb 100644
--- a/arch/mips/loongson64/common/Makefile
+++ b/arch/mips/loongson64/common/Makefile
@@ -23,7 +23,7 @@ obj-$(CONFIG_CS5536) += cs5536/
# Suspend Support
#
-obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
+obj-$(CONFIG_SUSPEND) += pm.o
#
# Big Memory (SWIOTLB) Support
diff --git a/arch/mips/loongson64/lemote-2f/Makefile b/arch/mips/loongson64/lemote-2f/Makefile
index 4f9eaa3..08b8abc 100644
--- a/arch/mips/loongson64/lemote-2f/Makefile
+++ b/arch/mips/loongson64/lemote-2f/Makefile
@@ -8,4 +8,4 @@ obj-y += clock.o machtype.o irq.o reset.o ec_kb3310b.o
# Suspend Support
#
-obj-$(CONFIG_LOONGSON_SUSPEND) += pm.o
+obj-$(CONFIG_SUSPEND) += pm.o
diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c
index 506a67a..be650ed 100644
--- a/arch/mips/math-emu/me-debugfs.c
+++ b/arch/mips/math-emu/me-debugfs.c
@@ -4,6 +4,7 @@
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/types.h>
+#include <asm/debug.h>
#include <asm/fpu_emulator.h>
#include <asm/local.h>
@@ -27,7 +28,6 @@ static int fpuemu_stat_get(void *data, u64 *val)
}
DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
-extern struct dentry *mips_debugfs_dir;
static int __init debugfs_fpuemu(void)
{
struct dentry *d, *dir;
diff --git a/arch/mips/mm/Makefile b/arch/mips/mm/Makefile
index 67ede4e..b4c64bd 100644
--- a/arch/mips/mm/Makefile
+++ b/arch/mips/mm/Makefile
@@ -28,3 +28,4 @@ obj-$(CONFIG_IP22_CPU_SCACHE) += sc-ip22.o
obj-$(CONFIG_R5000_CPU_SCACHE) += sc-r5k.o
obj-$(CONFIG_RM7000_CPU_SCACHE) += sc-rm7k.o
obj-$(CONFIG_MIPS_CPU_SCACHE) += sc-mips.o
+obj-$(CONFIG_SCACHE_DEBUGFS) += sc-debugfs.o
diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c
index d8117be..730d394 100644
--- a/arch/mips/mm/dma-default.c
+++ b/arch/mips/mm/dma-default.c
@@ -145,7 +145,7 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size,
gfp = massage_gfp_flags(dev, gfp);
- if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC))
+ if (IS_ENABLED(CONFIG_DMA_CMA) && gfpflags_allow_blocking(gfp))
page = dma_alloc_from_contiguous(dev,
count, get_order(size));
if (!page)
diff --git a/arch/mips/mm/sc-debugfs.c b/arch/mips/mm/sc-debugfs.c
new file mode 100644
index 0000000..5eefe32
--- /dev/null
+++ b/arch/mips/mm/sc-debugfs.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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 <asm/bcache.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include <linux/debugfs.h>
+#include <linux/init.h>
+
+static ssize_t sc_prefetch_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ bool enabled = bc_prefetch_is_enabled();
+ char buf[3];
+
+ buf[0] = enabled ? 'Y' : 'N';
+ buf[1] = '\n';
+ buf[2] = 0;
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t sc_prefetch_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[32];
+ ssize_t buf_size;
+ bool enabled;
+ int err;
+
+ buf_size = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+
+ buf[buf_size] = '\0';
+ err = strtobool(buf, &enabled);
+ if (err)
+ return err;
+
+ if (enabled)
+ bc_prefetch_enable();
+ else
+ bc_prefetch_disable();
+
+ return count;
+}
+
+static const struct file_operations sc_prefetch_fops = {
+ .open = simple_open,
+ .llseek = default_llseek,
+ .read = sc_prefetch_read,
+ .write = sc_prefetch_write,
+};
+
+static int __init sc_debugfs_init(void)
+{
+ struct dentry *dir, *file;
+
+ if (!mips_debugfs_dir)
+ return -ENODEV;
+
+ dir = debugfs_create_dir("l2cache", mips_debugfs_dir);
+ if (IS_ERR(dir))
+ return PTR_ERR(dir);
+
+ file = debugfs_create_file("prefetch", S_IRUGO | S_IWUSR, dir,
+ NULL, &sc_prefetch_fops);
+ if (IS_ERR(file))
+ return PTR_ERR(file);
+
+ return 0;
+}
+late_initcall(sc_debugfs_init);
diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c
index 53ea839..3bd0597 100644
--- a/arch/mips/mm/sc-mips.c
+++ b/arch/mips/mm/sc-mips.c
@@ -51,11 +51,69 @@ static void mips_sc_disable(void)
/* L2 cache is permanently enabled */
}
+static void mips_sc_prefetch_enable(void)
+{
+ unsigned long pftctl;
+
+ if (mips_cm_revision() < CM_REV_CM2_5)
+ return;
+
+ /*
+ * If there is one or more L2 prefetch unit present then enable
+ * prefetching for both code & data, for all ports.
+ */
+ pftctl = read_gcr_l2_pft_control();
+ if (pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK) {
+ pftctl &= ~CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+ pftctl |= PAGE_MASK & CM_GCR_L2_PFT_CONTROL_PAGEMASK_MSK;
+ pftctl |= CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+ write_gcr_l2_pft_control(pftctl);
+
+ pftctl = read_gcr_l2_pft_control_b();
+ pftctl |= CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+ pftctl |= CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+ write_gcr_l2_pft_control_b(pftctl);
+ }
+}
+
+static void mips_sc_prefetch_disable(void)
+{
+ unsigned long pftctl;
+
+ if (mips_cm_revision() < CM_REV_CM2_5)
+ return;
+
+ pftctl = read_gcr_l2_pft_control();
+ pftctl &= ~CM_GCR_L2_PFT_CONTROL_PFTEN_MSK;
+ write_gcr_l2_pft_control(pftctl);
+
+ pftctl = read_gcr_l2_pft_control_b();
+ pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_PORTID_MSK;
+ pftctl &= ~CM_GCR_L2_PFT_CONTROL_B_CEN_MSK;
+ write_gcr_l2_pft_control_b(pftctl);
+}
+
+static bool mips_sc_prefetch_is_enabled(void)
+{
+ unsigned long pftctl;
+
+ if (mips_cm_revision() < CM_REV_CM2_5)
+ return false;
+
+ pftctl = read_gcr_l2_pft_control();
+ if (!(pftctl & CM_GCR_L2_PFT_CONTROL_NPFT_MSK))
+ return false;
+ return !!(pftctl & CM_GCR_L2_PFT_CONTROL_PFTEN_MSK);
+}
+
static struct bcache_ops mips_sc_ops = {
.bc_enable = mips_sc_enable,
.bc_disable = mips_sc_disable,
.bc_wback_inv = mips_sc_wback_inv,
- .bc_inv = mips_sc_inv
+ .bc_inv = mips_sc_inv,
+ .bc_prefetch_enable = mips_sc_prefetch_enable,
+ .bc_prefetch_disable = mips_sc_prefetch_disable,
+ .bc_prefetch_is_enabled = mips_sc_prefetch_is_enabled,
};
/*
@@ -162,13 +220,13 @@ static inline int __init mips_sc_probe(void)
return 0;
tmp = (config2 >> 8) & 0x0f;
- if (0 <= tmp && tmp <= 7)
+ if (tmp <= 7)
c->scache.sets = 64 << tmp;
else
return 0;
tmp = (config2 >> 0) & 0x0f;
- if (0 <= tmp && tmp <= 7)
+ if (tmp <= 7)
c->scache.ways = tmp + 1;
else
return 0;
@@ -186,6 +244,7 @@ int mips_sc_init(void)
int found = mips_sc_probe();
if (found) {
mips_sc_enable();
+ mips_sc_prefetch_enable();
bcops = &mips_sc_ops;
}
return found;
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 323d1d3..32e0be2 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -311,6 +311,7 @@ static struct uasm_label labels[128];
static struct uasm_reloc relocs[128];
static int check_for_high_segbits;
+static bool fill_includes_sw_bits;
static unsigned int kscratch_used_mask;
@@ -630,8 +631,14 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
static __maybe_unused void build_convert_pte_to_entrylo(u32 **p,
unsigned int reg)
{
- if (cpu_has_rixi) {
- UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+ if (cpu_has_rixi && _PAGE_NO_EXEC) {
+ if (fill_includes_sw_bits) {
+ UASM_i_ROTR(p, reg, reg, ilog2(_PAGE_GLOBAL));
+ } else {
+ UASM_i_SRL(p, reg, reg, ilog2(_PAGE_NO_EXEC));
+ UASM_i_ROTR(p, reg, reg,
+ ilog2(_PAGE_GLOBAL) - ilog2(_PAGE_NO_EXEC));
+ }
} else {
#ifdef CONFIG_PHYS_ADDR_T_64BIT
uasm_i_dsrl_safe(p, reg, reg, ilog2(_PAGE_GLOBAL));
@@ -1005,21 +1012,7 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
* 64bit address support (36bit on a 32bit CPU) in a 32bit
* Kernel is a special case. Only a few CPUs use it.
*/
-#ifdef CONFIG_PHYS_ADDR_T_64BIT
- if (cpu_has_64bits) {
- uasm_i_ld(p, tmp, 0, ptep); /* get even pte */
- uasm_i_ld(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
- if (cpu_has_rixi) {
- UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
- UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
- UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
- } else {
- uasm_i_dsrl_safe(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
- UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
- uasm_i_dsrl_safe(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */
- }
- UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
- } else {
+ if (config_enabled(CONFIG_PHYS_ADDR_T_64BIT) && !cpu_has_64bits) {
int pte_off_even = sizeof(pte_t) / 2;
int pte_off_odd = pte_off_even + sizeof(pte_t);
#ifdef CONFIG_XPA
@@ -1043,31 +1036,23 @@ static void build_update_entries(u32 **p, unsigned int tmp, unsigned int ptep)
uasm_i_mthc0(p, tmp, C0_ENTRYLO0);
uasm_i_mthc0(p, ptep, C0_ENTRYLO1);
#endif
+ return;
}
-#else
+
UASM_i_LW(p, tmp, 0, ptep); /* get even pte */
UASM_i_LW(p, ptep, sizeof(pte_t), ptep); /* get odd pte */
if (r45k_bvahwbug())
build_tlb_probe_entry(p);
- if (cpu_has_rixi) {
- UASM_i_ROTR(p, tmp, tmp, ilog2(_PAGE_GLOBAL));
- if (r4k_250MHZhwbug())
- UASM_i_MTC0(p, 0, C0_ENTRYLO0);
- UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
- UASM_i_ROTR(p, ptep, ptep, ilog2(_PAGE_GLOBAL));
- } else {
- UASM_i_SRL(p, tmp, tmp, ilog2(_PAGE_GLOBAL)); /* convert to entrylo0 */
- if (r4k_250MHZhwbug())
- UASM_i_MTC0(p, 0, C0_ENTRYLO0);
- UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
- UASM_i_SRL(p, ptep, ptep, ilog2(_PAGE_GLOBAL)); /* convert to entrylo1 */
- if (r45k_bvahwbug())
- uasm_i_mfc0(p, tmp, C0_INDEX);
- }
+ build_convert_pte_to_entrylo(p, tmp);
+ if (r4k_250MHZhwbug())
+ UASM_i_MTC0(p, 0, C0_ENTRYLO0);
+ UASM_i_MTC0(p, tmp, C0_ENTRYLO0); /* load it */
+ build_convert_pte_to_entrylo(p, ptep);
+ if (r45k_bvahwbug())
+ uasm_i_mfc0(p, tmp, C0_INDEX);
if (r4k_250MHZhwbug())
UASM_i_MTC0(p, 0, C0_ENTRYLO1);
UASM_i_MTC0(p, ptep, C0_ENTRYLO1); /* load it */
-#endif
}
struct mips_huge_tlb_info {
@@ -2299,6 +2284,10 @@ static void config_htw_params(void)
/* re-initialize the PTI field including the even/odd bit */
pwfield &= ~MIPS_PWFIELD_PTI_MASK;
pwfield |= PAGE_SHIFT << MIPS_PWFIELD_PTI_SHIFT;
+ if (CONFIG_PGTABLE_LEVELS >= 3) {
+ pwfield &= ~MIPS_PWFIELD_MDI_MASK;
+ pwfield |= PMD_SHIFT << MIPS_PWFIELD_MDI_SHIFT;
+ }
/* Set the PTEI right shift */
ptei = _PAGE_GLOBAL_SHIFT << MIPS_PWFIELD_PTEI_SHIFT;
pwfield |= ptei;
@@ -2320,9 +2309,11 @@ static void config_htw_params(void)
pwsize = ilog2(PTRS_PER_PGD) << MIPS_PWSIZE_GDW_SHIFT;
pwsize |= ilog2(PTRS_PER_PTE) << MIPS_PWSIZE_PTW_SHIFT;
+ if (CONFIG_PGTABLE_LEVELS >= 3)
+ pwsize |= ilog2(PTRS_PER_PMD) << MIPS_PWSIZE_MDW_SHIFT;
/* If XPA has been enabled, PTEs are 64-bit in size. */
- if (read_c0_pagegrain() & PG_ELPA)
+ if (config_enabled(CONFIG_64BITS) || (read_c0_pagegrain() & PG_ELPA))
pwsize |= 1;
write_c0_pwsize(pwsize);
@@ -2360,6 +2351,41 @@ static void config_xpa_params(void)
#endif
}
+static void check_pabits(void)
+{
+ unsigned long entry;
+ unsigned pabits, fillbits;
+
+ if (!cpu_has_rixi || !_PAGE_NO_EXEC) {
+ /*
+ * We'll only be making use of the fact that we can rotate bits
+ * into the fill if the CPU supports RIXI, so don't bother
+ * probing this for CPUs which don't.
+ */
+ return;
+ }
+
+ write_c0_entrylo0(~0ul);
+ back_to_back_c0_hazard();
+ entry = read_c0_entrylo0();
+
+ /* clear all non-PFN bits */
+ entry &= ~((1 << MIPS_ENTRYLO_PFN_SHIFT) - 1);
+ entry &= ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI);
+
+ /* find a lower bound on PABITS, and upper bound on fill bits */
+ pabits = fls_long(entry) + 6;
+ fillbits = max_t(int, (int)BITS_PER_LONG - pabits, 0);
+
+ /* minus the RI & XI bits */
+ fillbits -= min_t(unsigned, fillbits, 2);
+
+ if (fillbits >= ilog2(_PAGE_NO_EXEC))
+ fill_includes_sw_bits = true;
+
+ pr_debug("Entry* registers contain %u fill bits\n", fillbits);
+}
+
void build_tlb_refill_handler(void)
{
/*
@@ -2370,6 +2396,7 @@ void build_tlb_refill_handler(void)
static int run_once = 0;
output_pgtable_bits_defines();
+ check_pabits();
#ifdef CONFIG_64BIT
check_for_high_segbits = current_cpu_data.vmbits > (PGDIR_SHIFT + PGD_ORDER + PAGE_SHIFT - 3);
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile
index ea35587..5827af7 100644
--- a/arch/mips/mti-malta/Makefile
+++ b/arch/mips/mti-malta/Makefile
@@ -5,9 +5,18 @@
# Copyright (C) 2008 Wind River Systems, Inc.
# written by Ralf Baechle <ralf@linux-mips.org>
#
-obj-y := malta-display.o malta-dt.o malta-init.o \
- malta-int.o malta-memory.o malta-platform.o \
- malta-reset.o malta-setup.o malta-time.o
+obj-y += malta-display.o
+obj-y += malta-dt.o
+obj-y += malta-dtshim.o
+obj-y += malta-init.o
+obj-y += malta-int.o
+obj-y += malta-memory.o
+obj-y += malta-platform.o
+obj-y += malta-reset.o
+obj-y += malta-setup.o
+obj-y += malta-time.o
obj-$(CONFIG_MIPS_CMP) += malta-amon.o
obj-$(CONFIG_MIPS_MALTA_PM) += malta-pm.o
+
+CFLAGS_malta-dtshim.o = -I$(src)/../../../scripts/dtc/libfdt
diff --git a/arch/mips/mti-malta/malta-dtshim.c b/arch/mips/mti-malta/malta-dtshim.c
new file mode 100644
index 0000000..f7133ef
--- /dev/null
+++ b/arch/mips/mti-malta/malta-dtshim.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.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/bug.h>
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/of_fdt.h>
+#include <linux/sizes.h>
+#include <asm/bootinfo.h>
+#include <asm/fw/fw.h>
+#include <asm/page.h>
+
+static unsigned char fdt_buf[16 << 10] __initdata;
+
+/* determined physical memory size, not overridden by command line args */
+extern unsigned long physical_memsize;
+
+#define MAX_MEM_ARRAY_ENTRIES 1
+
+static unsigned __init gen_fdt_mem_array(__be32 *mem_array, unsigned long size)
+{
+ unsigned long size_preio;
+ unsigned entries;
+
+ entries = 1;
+ mem_array[0] = cpu_to_be32(PHYS_OFFSET);
+ if (config_enabled(CONFIG_EVA)) {
+ /*
+ * The current Malta EVA configuration is "special" in that it
+ * always makes use of addresses in the upper half of the 32 bit
+ * physical address map, which gives it a contiguous region of
+ * DDR but limits it to 2GB.
+ */
+ mem_array[1] = cpu_to_be32(size);
+ } else {
+ size_preio = min_t(unsigned long, size, SZ_256M);
+ mem_array[1] = cpu_to_be32(size_preio);
+ }
+
+ BUG_ON(entries > MAX_MEM_ARRAY_ENTRIES);
+ return entries;
+}
+
+static void __init append_memory(void *fdt, int root_off)
+{
+ __be32 mem_array[2 * MAX_MEM_ARRAY_ENTRIES];
+ unsigned long memsize;
+ unsigned mem_entries;
+ int i, err, mem_off;
+ char *var, param_name[10], *var_names[] = {
+ "ememsize", "memsize",
+ };
+
+ /* if a memory node already exists, leave it alone */
+ mem_off = fdt_path_offset(fdt, "/memory");
+ if (mem_off >= 0)
+ return;
+
+ /* find memory size from the bootloader environment */
+ for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+ var = fw_getenv(var_names[i]);
+ if (!var)
+ continue;
+
+ err = kstrtoul(var, 0, &physical_memsize);
+ if (!err)
+ break;
+
+ pr_warn("Failed to read the '%s' env variable '%s'\n",
+ var_names[i], var);
+ }
+
+ if (!physical_memsize) {
+ pr_warn("The bootloader didn't provide memsize: defaulting to 32MB\n");
+ physical_memsize = 32 << 20;
+ }
+
+ if (config_enabled(CONFIG_CPU_BIG_ENDIAN)) {
+ /*
+ * SOC-it swaps, or perhaps doesn't swap, when DMA'ing
+ * the last word of physical memory.
+ */
+ physical_memsize -= PAGE_SIZE;
+ }
+
+ /* default to using all available RAM */
+ memsize = physical_memsize;
+
+ /* allow the user to override the usable memory */
+ for (i = 0; i < ARRAY_SIZE(var_names); i++) {
+ snprintf(param_name, sizeof(param_name), "%s=", var_names[i]);
+ var = strstr(arcs_cmdline, param_name);
+ if (!var)
+ continue;
+
+ memsize = memparse(var + strlen(param_name), NULL);
+ }
+
+ /* if the user says there's more RAM than we thought, believe them */
+ physical_memsize = max_t(unsigned long, physical_memsize, memsize);
+
+ /* append memory to the DT */
+ mem_off = fdt_add_subnode(fdt, root_off, "memory");
+ if (mem_off < 0)
+ panic("Unable to add memory node to DT: %d", mem_off);
+
+ err = fdt_setprop_string(fdt, mem_off, "device_type", "memory");
+ if (err)
+ panic("Unable to set memory node device_type: %d", err);
+
+ mem_entries = gen_fdt_mem_array(mem_array, physical_memsize);
+ err = fdt_setprop(fdt, mem_off, "reg", mem_array,
+ mem_entries * 2 * sizeof(mem_array[0]));
+ if (err)
+ panic("Unable to set memory regs property: %d", err);
+
+ mem_entries = gen_fdt_mem_array(mem_array, memsize);
+ err = fdt_setprop(fdt, mem_off, "linux,usable-memory", mem_array,
+ mem_entries * 2 * sizeof(mem_array[0]));
+ if (err)
+ panic("Unable to set linux,usable-memory property: %d", err);
+}
+
+void __init *malta_dt_shim(void *fdt)
+{
+ int root_off, len, err;
+ const char *compat;
+
+ if (fdt_check_header(fdt))
+ panic("Corrupt DT");
+
+ err = fdt_open_into(fdt, fdt_buf, sizeof(fdt_buf));
+ if (err)
+ panic("Unable to open FDT: %d", err);
+
+ root_off = fdt_path_offset(fdt_buf, "/");
+ if (root_off < 0)
+ panic("No / node in DT");
+
+ compat = fdt_getprop(fdt_buf, root_off, "compatible", &len);
+ if (!compat)
+ panic("No root compatible property in DT: %d", len);
+
+ /* if this isn't Malta, leave the DT alone */
+ if (strncmp(compat, "mti,malta", len))
+ return fdt;
+
+ append_memory(fdt_buf, root_off);
+
+ err = fdt_pack(fdt_buf);
+ if (err)
+ panic("Unable to pack FDT: %d\n", err);
+
+ return fdt_buf;
+}
diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c
index 53c2478..571148c 100644
--- a/arch/mips/mti-malta/malta-init.c
+++ b/arch/mips/mti-malta/malta-init.c
@@ -302,6 +302,7 @@ mips_pci_controller:
return;
if (!register_vsmp_smp_ops())
return;
+ register_up_smp_ops();
}
void platform_early_l2_init(void)
diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c
index dadeb83..d5f8dae 100644
--- a/arch/mips/mti-malta/malta-memory.c
+++ b/arch/mips/mti-malta/malta-memory.c
@@ -21,147 +21,20 @@
#include <asm/sections.h>
#include <asm/fw/fw.h>
-static fw_memblock_t mdesc[FW_MAX_MEMBLOCKS];
-
/* determined physical memory size, not overridden by command line args */
unsigned long physical_memsize = 0L;
-fw_memblock_t * __init fw_getmdesc(int eva)
-{
- char *memsize_str, *ememsize_str = NULL, *ptr;
- unsigned long memsize = 0, ememsize = 0;
- static char cmdline[COMMAND_LINE_SIZE] __initdata;
- int tmp;
-
- /* otherwise look in the environment */
-
- memsize_str = fw_getenv("memsize");
- if (memsize_str) {
- tmp = kstrtoul(memsize_str, 0, &memsize);
- if (tmp)
- pr_warn("Failed to read the 'memsize' env variable.\n");
- }
- if (eva) {
- /* Look for ememsize for EVA */
- ememsize_str = fw_getenv("ememsize");
- if (ememsize_str) {
- tmp = kstrtoul(ememsize_str, 0, &ememsize);
- if (tmp)
- pr_warn("Failed to read the 'ememsize' env variable.\n");
- }
- }
- if (!memsize && !ememsize) {
- pr_warn("memsize not set in YAMON, set to default (32Mb)\n");
- physical_memsize = 0x02000000;
- } else {
- if (memsize > (256 << 20)) { /* memsize should be capped to 256M */
- pr_warn("Unsupported memsize value (0x%lx) detected! "
- "Using 0x10000000 (256M) instead\n",
- memsize);
- memsize = 256 << 20;
- }
- /* If ememsize is set, then set physical_memsize to that */
- physical_memsize = ememsize ? : memsize;
- }
-
-#ifdef CONFIG_CPU_BIG_ENDIAN
- /* SOC-it swaps, or perhaps doesn't swap, when DMA'ing the last
- word of physical memory */
- physical_memsize -= PAGE_SIZE;
-#endif
-
- /* Check the command line for a memsize directive that overrides
- the physical/default amount */
- strcpy(cmdline, arcs_cmdline);
- ptr = strstr(cmdline, "memsize=");
- if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
- ptr = strstr(ptr, " memsize=");
- /* And now look for ememsize */
- if (eva) {
- ptr = strstr(cmdline, "ememsize=");
- if (ptr && (ptr != cmdline) && (*(ptr - 1) != ' '))
- ptr = strstr(ptr, " ememsize=");
- }
-
- if (ptr)
- memsize = memparse(ptr + 8 + (eva ? 1 : 0), &ptr);
- else
- memsize = physical_memsize;
-
- /* Last 64K for HIGHMEM arithmetics */
- if (memsize > 0x7fff0000)
- memsize = 0x7fff0000;
-
- memset(mdesc, 0, sizeof(mdesc));
-
- mdesc[0].type = fw_dontuse;
- mdesc[0].base = PHYS_OFFSET;
- mdesc[0].size = 0x00001000;
-
- mdesc[1].type = fw_code;
- mdesc[1].base = mdesc[0].base + 0x00001000UL;
- mdesc[1].size = 0x000ef000;
-
- /*
- * The area 0x000f0000-0x000fffff is allocated for BIOS memory by the
- * south bridge and PCI access always forwarded to the ISA Bus and
- * BIOSCS# is always generated.
- * This mean that this area can't be used as DMA memory for PCI
- * devices.
- */
- mdesc[2].type = fw_dontuse;
- mdesc[2].base = mdesc[0].base + 0x000f0000UL;
- mdesc[2].size = 0x00010000;
-
- mdesc[3].type = fw_dontuse;
- mdesc[3].base = mdesc[0].base + 0x00100000UL;
- mdesc[3].size = CPHYSADDR(PFN_ALIGN((unsigned long)&_end)) -
- 0x00100000UL;
-
- mdesc[4].type = fw_free;
- mdesc[4].base = mdesc[0].base + CPHYSADDR(PFN_ALIGN(&_end));
- mdesc[4].size = memsize - CPHYSADDR(mdesc[4].base);
-
- return &mdesc[0];
-}
-
static void free_init_pages_eva_malta(void *begin, void *end)
{
free_init_pages("unused kernel", __pa_symbol((unsigned long *)begin),
__pa_symbol((unsigned long *)end));
}
-static int __init fw_memtype_classify(unsigned int type)
-{
- switch (type) {
- case fw_free:
- return BOOT_MEM_RAM;
- case fw_code:
- return BOOT_MEM_ROM_DATA;
- default:
- return BOOT_MEM_RESERVED;
- }
-}
-
void __init fw_meminit(void)
{
- fw_memblock_t *p;
-
- p = fw_getmdesc(config_enabled(CONFIG_EVA));
- free_init_pages_eva = (config_enabled(CONFIG_EVA) ?
- free_init_pages_eva_malta : NULL);
+ bool eva = config_enabled(CONFIG_EVA);
- while (p->size) {
- long type;
- unsigned long base, size;
-
- type = fw_memtype_classify(p->type);
- base = p->base;
- size = p->size;
-
- add_memory_region(base, size, type);
- p++;
- }
+ free_init_pages_eva = eva ? free_init_pages_eva_malta : NULL;
}
void __init prom_free_prom_memory(void)
diff --git a/arch/mips/mti-malta/malta-setup.c b/arch/mips/mti-malta/malta-setup.c
index 9d1e7f5..4740c82 100644
--- a/arch/mips/mti-malta/malta-setup.c
+++ b/arch/mips/mti-malta/malta-setup.c
@@ -27,6 +27,7 @@
#include <linux/time.h>
#include <asm/fw/fw.h>
+#include <asm/mach-malta/malta-dtshim.h>
#include <asm/mips-cm.h>
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/malta.h>
@@ -250,8 +251,10 @@ static void __init bonito_quirks_setup(void)
void __init plat_mem_setup(void)
{
unsigned int i;
+ void *fdt = __dtb_start;
- __dt_setup_arch(__dtb_start);
+ fdt = malta_dt_shim(fdt);
+ __dt_setup_arch(fdt);
if (config_enabled(CONFIG_EVA))
/* EVA has already been configured in mach-malta/kernel-init.h */
diff --git a/arch/mips/net/bpf_jit.c b/arch/mips/net/bpf_jit.c
index 77cb273..1a8c960 100644
--- a/arch/mips/net/bpf_jit.c
+++ b/arch/mips/net/bpf_jit.c
@@ -521,19 +521,6 @@ static inline u16 align_sp(unsigned int num)
return num;
}
-static bool is_load_to_a(u16 inst)
-{
- switch (inst) {
- case BPF_LD | BPF_W | BPF_LEN:
- case BPF_LD | BPF_W | BPF_ABS:
- case BPF_LD | BPF_H | BPF_ABS:
- case BPF_LD | BPF_B | BPF_ABS:
- return true;
- default:
- return false;
- }
-}
-
static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
{
int i = 0, real_off = 0;
@@ -614,7 +601,6 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx)
static void build_prologue(struct jit_ctx *ctx)
{
- u16 first_inst = ctx->skf->insns[0].code;
int sp_off;
/* Calculate the total offset for the stack pointer */
@@ -641,7 +627,7 @@ static void build_prologue(struct jit_ctx *ctx)
emit_jit_reg_move(r_X, r_zero, ctx);
/* Do not leak kernel data to userspace */
- if ((first_inst != (BPF_RET | BPF_K)) && !(is_load_to_a(first_inst)))
+ if (bpf_needs_clear_a(&ctx->skf->insns[0]))
emit_jit_reg_move(r_A, r_zero, ctx);
}
diff --git a/arch/mips/netlogic/xlp/dt.c b/arch/mips/netlogic/xlp/dt.c
index a625bdb..856a6e6 100644
--- a/arch/mips/netlogic/xlp/dt.c
+++ b/arch/mips/netlogic/xlp/dt.c
@@ -87,7 +87,6 @@ void __init *xlp_dt_init(void *fdtp)
void __init xlp_early_init_devtree(void)
{
__dt_setup_arch(xlp_fdt_blob);
- strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
}
void __init device_tree_init(void)
diff --git a/arch/mips/pci/pci-rt2880.c b/arch/mips/pci/pci-rt2880.c
index 8a97802..a245cad 100644
--- a/arch/mips/pci/pci-rt2880.c
+++ b/arch/mips/pci/pci-rt2880.c
@@ -11,6 +11,7 @@
* by the Free Software Foundation.
*/
+#include <linux/delay.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/io.h>
@@ -220,7 +221,6 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
static int rt288x_pci_probe(struct platform_device *pdev)
{
void __iomem *io_map_base;
- int i;
rt2880_pci_base = ioremap_nocache(RT2880_PCI_BASE, PAGE_SIZE);
@@ -232,8 +232,7 @@ static int rt288x_pci_probe(struct platform_device *pdev)
ioport_resource.end = RT2880_PCI_IO_BASE + RT2880_PCI_IO_SIZE - 1;
rt2880_pci_reg_write(0, RT2880_PCI_REG_PCICFG_ADDR);
- for (i = 0; i < 0xfffff; i++)
- ;
+ udelay(1);
rt2880_pci_reg_write(0x79, RT2880_PCI_REG_ARBCTL);
rt2880_pci_reg_write(0x07FF0001, RT2880_PCI_REG_BAR0SETUP_ADDR);
diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c
index ed6732f9..53a42b0 100644
--- a/arch/mips/pci/pci-rt3883.c
+++ b/arch/mips/pci/pci-rt3883.c
@@ -432,8 +432,7 @@ static int rt3883_pci_probe(struct platform_device *pdev)
/* find the interrupt controller child node */
for_each_child_of_node(np, child) {
- if (of_get_property(child, "interrupt-controller", NULL) &&
- of_node_get(child)) {
+ if (of_get_property(child, "interrupt-controller", NULL)) {
rpc->intc_of_node = child;
break;
}
@@ -449,8 +448,7 @@ static int rt3883_pci_probe(struct platform_device *pdev)
/* find the PCI host bridge child node */
for_each_child_of_node(np, child) {
if (child->type &&
- of_node_cmp(child->type, "pci") == 0 &&
- of_node_get(child)) {
+ of_node_cmp(child->type, "pci") == 0) {
rpc->pci_controller.of_node = child;
break;
}
diff --git a/arch/mips/pistachio/init.c b/arch/mips/pistachio/init.c
index 8bd8ebb..96ba2cc 100644
--- a/arch/mips/pistachio/init.c
+++ b/arch/mips/pistachio/init.c
@@ -58,7 +58,6 @@ void __init plat_mem_setup(void)
panic("Device-tree not present");
__dt_setup_arch((void *)fw_arg1);
- strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
plat_setup_iocoherency();
}
diff --git a/arch/mips/pmcs-msp71xx/msp_setup.c b/arch/mips/pmcs-msp71xx/msp_setup.c
index 4f925e0..9d293b3 100644
--- a/arch/mips/pmcs-msp71xx/msp_setup.c
+++ b/arch/mips/pmcs-msp71xx/msp_setup.c
@@ -10,6 +10,8 @@
* option) any later version.
*/
+#include <linux/delay.h>
+
#include <asm/bootinfo.h>
#include <asm/cacheflush.h>
#include <asm/idle.h>
@@ -37,7 +39,6 @@ extern void msp_serial_setup(void);
void msp7120_reset(void)
{
void *start, *end, *iptr;
- register int i;
/* Diasble all interrupts */
local_irq_disable();
@@ -77,7 +78,7 @@ void msp7120_reset(void)
*/
/* Wait a bit for the DDRC to settle */
- for (i = 0; i < 100000000; i++);
+ mdelay(125);
#if defined(CONFIG_PMC_MSP7120_GW)
/*
diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c
index a8e70a9..e46f91f 100644
--- a/arch/mips/ralink/cevt-rt3352.c
+++ b/arch/mips/ralink/cevt-rt3352.c
@@ -48,7 +48,7 @@ static int systick_next_event(unsigned long delta,
sdev = container_of(evt, struct systick_device, dev);
count = ioread32(sdev->membase + SYSTICK_COUNT);
count = (count + delta) % SYSTICK_FREQ;
- iowrite32(count + delta, sdev->membase + SYSTICK_COMPARE);
+ iowrite32(count, sdev->membase + SYSTICK_COMPARE);
return 0;
}
diff --git a/arch/mips/ralink/early_printk.c b/arch/mips/ralink/early_printk.c
index 255d695..3c59ffe 100644
--- a/arch/mips/ralink/early_printk.c
+++ b/arch/mips/ralink/early_printk.c
@@ -25,11 +25,13 @@
#define MT7628_CHIP_NAME1 0x20203832
#define UART_REG_TX 0x04
+#define UART_REG_LCR 0x0c
#define UART_REG_LSR 0x14
#define UART_REG_LSR_RT2880 0x1c
static __iomem void *uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE);
static __iomem void *chipid_membase = (__iomem void *) KSEG1ADDR(CHIPID_BASE);
+static int init_complete;
static inline void uart_w32(u32 val, unsigned reg)
{
@@ -47,8 +49,32 @@ static inline int soc_is_mt7628(void)
(__raw_readl(chipid_membase) == MT7628_CHIP_NAME1);
}
+static void find_uart_base(void)
+{
+ int i;
+
+ if (!soc_is_mt7628())
+ return;
+
+ for (i = 0; i < 3; i++) {
+ u32 reg = uart_r32(UART_REG_LCR + (0x100 * i));
+
+ if (!reg)
+ continue;
+
+ uart_membase = (__iomem void *) KSEG1ADDR(EARLY_UART_BASE +
+ (0x100 * i));
+ break;
+ }
+}
+
void prom_putchar(unsigned char ch)
{
+ if (!init_complete) {
+ find_uart_base();
+ init_complete = 1;
+ }
+
if (IS_ENABLED(CONFIG_SOC_MT7621) || soc_is_mt7628()) {
uart_w32(ch, UART_TX);
while ((uart_r32(UART_REG_LSR) & UART_LSR_THRE) == 0)
diff --git a/arch/mips/ralink/mt7620.c b/arch/mips/ralink/mt7620.c
index 2ea5ff6..dfb04fc 100644
--- a/arch/mips/ralink/mt7620.c
+++ b/arch/mips/ralink/mt7620.c
@@ -37,8 +37,17 @@
#define PMU1_CFG 0x8C
#define DIG_SW_SEL BIT(25)
-/* is this a MT7620 or a MT7628 */
-enum mt762x_soc_type mt762x_soc;
+/* clock scaling */
+#define CLKCFG_FDIV_MASK 0x1f00
+#define CLKCFG_FDIV_USB_VAL 0x0300
+#define CLKCFG_FFRAC_MASK 0x001f
+#define CLKCFG_FFRAC_USB_VAL 0x0003
+
+/* EFUSE bits */
+#define EFUSE_MT7688 0x100000
+
+/* DRAM type bit */
+#define DRAM_TYPE_MT7628_MASK 0x1
/* does the board have sdram or ddram */
static int dram_type;
@@ -227,6 +236,12 @@ static struct rt2880_pmx_group mt7628an_pinmux_data[] = {
{ 0 }
};
+static inline int is_mt76x8(void)
+{
+ return ralink_soc == MT762X_SOC_MT7628AN ||
+ ralink_soc == MT762X_SOC_MT7688;
+}
+
static __init u32
mt7620_calc_rate(u32 ref_rate, u32 mul, u32 div)
{
@@ -381,7 +396,7 @@ void __init ralink_clk_init(void)
#define RINT(x) ((x) / 1000000)
#define RFRAC(x) (((x) / 1000) % 1000)
- if (mt762x_soc == MT762X_SOC_MT7628AN) {
+ if (is_mt76x8()) {
if (xtal_rate == MHZ(40))
cpu_rate = MHZ(580);
else
@@ -423,6 +438,20 @@ void __init ralink_clk_init(void)
ralink_clk_add("10000b00.spi", sys_rate);
ralink_clk_add("10000c00.uartlite", periph_rate);
ralink_clk_add("10180000.wmac", xtal_rate);
+
+ if (IS_ENABLED(CONFIG_USB) && is_mt76x8()) {
+ /*
+ * When the CPU goes into sleep mode, the BUS clock will be
+ * too low for USB to function properly. Adjust the busses
+ * fractional divider to fix this
+ */
+ u32 val = rt_sysc_r32(SYSC_REG_CPU_SYS_CLKCFG);
+
+ val &= ~(CLKCFG_FDIV_MASK | CLKCFG_FFRAC_MASK);
+ val |= CLKCFG_FDIV_USB_VAL | CLKCFG_FFRAC_USB_VAL;
+
+ rt_sysc_w32(val, SYSC_REG_CPU_SYS_CLKCFG);
+ }
}
void __init ralink_of_remap(void)
@@ -499,20 +528,24 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
if (n0 == MT7620_CHIP_NAME0 && n1 == MT7620_CHIP_NAME1) {
if (bga) {
- mt762x_soc = MT762X_SOC_MT7620A;
+ ralink_soc = MT762X_SOC_MT7620A;
name = "MT7620A";
soc_info->compatible = "ralink,mt7620a-soc";
} else {
- mt762x_soc = MT762X_SOC_MT7620N;
+ ralink_soc = MT762X_SOC_MT7620N;
name = "MT7620N";
soc_info->compatible = "ralink,mt7620n-soc";
-#ifdef CONFIG_PCI
- panic("mt7620n is only supported for non pci kernels");
-#endif
}
} else if (n0 == MT7620_CHIP_NAME0 && n1 == MT7628_CHIP_NAME1) {
- mt762x_soc = MT762X_SOC_MT7628AN;
- name = "MT7628AN";
+ u32 efuse = __raw_readl(sysc + SYSC_REG_EFUSE_CFG);
+
+ if (efuse & EFUSE_MT7688) {
+ ralink_soc = MT762X_SOC_MT7688;
+ name = "MT7688";
+ } else {
+ ralink_soc = MT762X_SOC_MT7628AN;
+ name = "MT7628AN";
+ }
soc_info->compatible = "ralink,mt7628an-soc";
} else {
panic("mt762x: unknown SoC, n0:%08x n1:%08x\n", n0, n1);
@@ -525,10 +558,14 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
(rev & CHIP_REV_ECO_MASK));
cfg0 = __raw_readl(sysc + SYSC_REG_SYSTEM_CONFIG0);
- dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) & SYSCFG0_DRAM_TYPE_MASK;
+ if (is_mt76x8())
+ dram_type = cfg0 & DRAM_TYPE_MT7628_MASK;
+ else
+ dram_type = (cfg0 >> SYSCFG0_DRAM_TYPE_SHIFT) &
+ SYSCFG0_DRAM_TYPE_MASK;
soc_info->mem_base = MT7620_DRAM_BASE;
- if (mt762x_soc == MT762X_SOC_MT7628AN)
+ if (is_mt76x8())
mt7628_dram_init(soc_info);
else
mt7620_dram_init(soc_info);
@@ -541,7 +578,7 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
pr_info("Digital PMU set to %s control\n",
(pmu1 & DIG_SW_SEL) ? ("sw") : ("hw"));
- if (mt762x_soc == MT762X_SOC_MT7628AN)
+ if (is_mt76x8())
rt2880_pinmux_data = mt7628an_pinmux_data;
else
rt2880_pinmux_data = mt7620a_pinmux_data;
diff --git a/arch/mips/ralink/of.c b/arch/mips/ralink/of.c
index 0d30dcd..f9eda5d 100644
--- a/arch/mips/ralink/of.c
+++ b/arch/mips/ralink/of.c
@@ -74,8 +74,6 @@ void __init plat_mem_setup(void)
*/
__dt_setup_arch(__dtb_start);
- strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
-
of_scan_flat_dt(early_init_dt_find_memory, NULL);
if (memory_dtb)
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
diff --git a/arch/mips/ralink/prom.c b/arch/mips/ralink/prom.c
index 09419f6..39a9142f 100644
--- a/arch/mips/ralink/prom.c
+++ b/arch/mips/ralink/prom.c
@@ -15,11 +15,16 @@
#include <asm/bootinfo.h>
#include <asm/addrspace.h>
+#include <asm/mach-ralink/ralink_regs.h>
+
#include "common.h"
struct ralink_soc_info soc_info;
struct rt2880_pmx_group *rt2880_pinmux_data = NULL;
+enum ralink_soc_type ralink_soc;
+EXPORT_SYMBOL_GPL(ralink_soc);
+
const char *get_system_type(void)
{
return soc_info.sys_type;
diff --git a/arch/mips/ralink/reset.c b/arch/mips/ralink/reset.c
index 55c7ec5..ee117c4 100644
--- a/arch/mips/ralink/reset.c
+++ b/arch/mips/ralink/reset.c
@@ -11,6 +11,7 @@
#include <linux/pm.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/delay.h>
#include <linux/reset-controller.h>
#include <asm/reboot.h>
@@ -18,8 +19,10 @@
#include <asm/mach-ralink/ralink_regs.h>
/* Reset Control */
-#define SYSC_REG_RESET_CTRL 0x034
-#define RSTCTL_RESET_SYSTEM BIT(0)
+#define SYSC_REG_RESET_CTRL 0x034
+
+#define RSTCTL_RESET_PCI BIT(26)
+#define RSTCTL_RESET_SYSTEM BIT(0)
static int ralink_assert_device(struct reset_controller_dev *rcdev,
unsigned long id)
@@ -83,6 +86,11 @@ void ralink_rst_init(void)
static void ralink_restart(char *command)
{
+ if (IS_ENABLED(CONFIG_PCI)) {
+ rt_sysc_m32(0, RSTCTL_RESET_PCI, SYSC_REG_RESET_CTRL);
+ mdelay(50);
+ }
+
local_irq_disable();
rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL);
unreachable();
@@ -98,7 +106,6 @@ static int __init mips_reboot_setup(void)
{
_machine_restart = ralink_restart;
_machine_halt = ralink_halt;
- pm_power_off = ralink_halt;
return 0;
}
diff --git a/arch/mips/ralink/rt288x.c b/arch/mips/ralink/rt288x.c
index 738cec8..844f5cd 100644
--- a/arch/mips/ralink/rt288x.c
+++ b/arch/mips/ralink/rt288x.c
@@ -119,4 +119,5 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
soc_info->mem_size_max = RT2880_MEM_SIZE_MAX;
rt2880_pinmux_data = rt2880_pinmux_data_act;
+ ralink_soc == RT2880_SOC;
}
diff --git a/arch/mips/ralink/rt305x.c b/arch/mips/ralink/rt305x.c
index c40776a..9e45725 100644
--- a/arch/mips/ralink/rt305x.c
+++ b/arch/mips/ralink/rt305x.c
@@ -21,8 +21,6 @@
#include "common.h"
-enum rt305x_soc_type rt305x_soc;
-
static struct rt2880_pmx_func i2c_func[] = { FUNC("i2c", 0, 1, 2) };
static struct rt2880_pmx_func spi_func[] = { FUNC("spi", 0, 3, 4) };
static struct rt2880_pmx_func uartf_func[] = {
@@ -201,6 +199,7 @@ void __init ralink_clk_init(void)
}
ralink_clk_add("cpu", cpu_rate);
+ ralink_clk_add("sys", sys_rate);
ralink_clk_add("10000b00.spi", sys_rate);
ralink_clk_add("10000100.timer", wdt_rate);
ralink_clk_add("10000120.watchdog", wdt_rate);
@@ -235,24 +234,24 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
icache_sets = (read_c0_config1() >> 22) & 7;
if (icache_sets == 1) {
- rt305x_soc = RT305X_SOC_RT3050;
+ ralink_soc = RT305X_SOC_RT3050;
name = "RT3050";
soc_info->compatible = "ralink,rt3050-soc";
} else {
- rt305x_soc = RT305X_SOC_RT3052;
+ ralink_soc = RT305X_SOC_RT3052;
name = "RT3052";
soc_info->compatible = "ralink,rt3052-soc";
}
} else if (n0 == RT3350_CHIP_NAME0 && n1 == RT3350_CHIP_NAME1) {
- rt305x_soc = RT305X_SOC_RT3350;
+ ralink_soc = RT305X_SOC_RT3350;
name = "RT3350";
soc_info->compatible = "ralink,rt3350-soc";
} else if (n0 == RT3352_CHIP_NAME0 && n1 == RT3352_CHIP_NAME1) {
- rt305x_soc = RT305X_SOC_RT3352;
+ ralink_soc = RT305X_SOC_RT3352;
name = "RT3352";
soc_info->compatible = "ralink,rt3352-soc";
} else if (n0 == RT5350_CHIP_NAME0 && n1 == RT5350_CHIP_NAME1) {
- rt305x_soc = RT305X_SOC_RT5350;
+ ralink_soc = RT305X_SOC_RT5350;
name = "RT5350";
soc_info->compatible = "ralink,rt5350-soc";
} else {
diff --git a/arch/mips/ralink/rt3883.c b/arch/mips/ralink/rt3883.c
index 86a535c..582995a 100644
--- a/arch/mips/ralink/rt3883.c
+++ b/arch/mips/ralink/rt3883.c
@@ -153,4 +153,6 @@ void prom_soc_init(struct ralink_soc_info *soc_info)
soc_info->mem_size_max = RT3883_MEM_SIZE_MAX;
rt2880_pinmux_data = rt3883_pinmux_data;
+
+ ralink_soc == RT3883_SOC;
}
diff --git a/arch/mips/sni/reset.c b/arch/mips/sni/reset.c
index 244f942..6afa343 100644
--- a/arch/mips/sni/reset.c
+++ b/arch/mips/sni/reset.c
@@ -3,6 +3,8 @@
*
* Reset a SNI machine.
*/
+#include <linux/delay.h>
+
#include <asm/io.h>
#include <asm/reboot.h>
#include <asm/sni.h>
@@ -24,7 +26,7 @@ static inline void kb_wait(void)
/* XXX This ends up at the ARC firmware prompt ... */
void sni_machine_restart(char *command)
{
- int i, j;
+ int i;
/* This does a normal via the keyboard controller like a PC.
We can do that easier ... */
@@ -32,9 +34,9 @@ void sni_machine_restart(char *command)
for (;;) {
for (i = 0; i < 100; i++) {
kb_wait();
- for (j = 0; j < 100000 ; j++)
- /* nothing */;
+ udelay(50);
outb_p(0xfe, 0x64); /* pulse reset low */
+ udelay(50);
}
}
}
diff --git a/arch/mips/vdso/.gitignore b/arch/mips/vdso/.gitignore
new file mode 100644
index 0000000..5286a7d
--- /dev/null
+++ b/arch/mips/vdso/.gitignore
@@ -0,0 +1,4 @@
+*.so*
+vdso-*image.c
+genvdso
+vdso*.lds
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
new file mode 100644
index 0000000..ee3617c
--- /dev/null
+++ b/arch/mips/vdso/Makefile
@@ -0,0 +1,160 @@
+# Objects to go into the VDSO.
+obj-vdso-y := elf.o gettimeofday.o sigreturn.o
+
+# Common compiler flags between ABIs.
+ccflags-vdso := \
+ $(filter -I%,$(KBUILD_CFLAGS)) \
+ $(filter -E%,$(KBUILD_CFLAGS)) \
+ $(filter -march=%,$(KBUILD_CFLAGS))
+cflags-vdso := $(ccflags-vdso) \
+ $(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
+ -O2 -g -fPIC -fno-common -fno-builtin -G 0 -DDISABLE_BRANCH_PROFILING \
+ $(call cc-option, -fno-stack-protector)
+aflags-vdso := $(ccflags-vdso) \
+ $(filter -I%,$(KBUILD_CFLAGS)) \
+ $(filter -E%,$(KBUILD_CFLAGS)) \
+ -D__ASSEMBLY__ -Wa,-gdwarf-2
+
+#
+# For the pre-R6 code in arch/mips/vdso/vdso.h for locating
+# the base address of VDSO, the linker will emit a R_MIPS_PC32
+# relocation in binutils > 2.25 but it will fail with older versions
+# because that relocation is not supported for that symbol. As a result
+# of which we are forced to disable the VDSO symbols when building
+# with < 2.25 binutils on pre-R6 kernels. For more references on why we
+# can't use other methods to get the base address of VDSO please refer to
+# the comments on that file.
+#
+ifndef CONFIG_CPU_MIPSR6
+ ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
+ $(warning MIPS VDSO requires binutils >= 2.25)
+ obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
+ ccflags-vdso += -DDISABLE_MIPS_VDSO
+ endif
+endif
+
+# VDSO linker flags.
+VDSO_LDFLAGS := \
+ -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 \
+ -nostdlib -shared \
+ $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
+ $(call cc-ldoption, -Wl$(comma)--build-id)
+
+GCOV_PROFILE := n
+
+#
+# Shared build commands.
+#
+
+quiet_cmd_vdsold = VDSO $@
+ cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
+ -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+
+hostprogs-y := genvdso
+
+quiet_cmd_genvdso = GENVDSO $@
+define cmd_genvdso
+ cp $< $(<:%.dbg=%) && \
+ $(OBJCOPY) -S $< $(<:%.dbg=%) && \
+ $(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME)
+endef
+
+#
+# Build native VDSO.
+#
+
+native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS))
+
+targets += $(obj-vdso-y)
+targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c
+
+obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o)
+
+$(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
+$(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
+
+$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
+ $(call if_changed,vdsold)
+
+$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE
+ $(call if_changed,genvdso)
+
+obj-y += vdso-image.o
+
+#
+# Build O32 VDSO.
+#
+
+# Define these outside the ifdef to ensure they are picked up by clean.
+targets += $(obj-vdso-y:%.o=%-o32.o)
+targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c
+
+ifdef CONFIG_MIPS32_O32
+
+obj-vdso-o32 := $(obj-vdso-y:%.o=$(obj)/%-o32.o)
+
+$(obj-vdso-o32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=32
+$(obj-vdso-o32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=32
+
+$(obj)/%-o32.o: $(src)/%.S FORCE
+ $(call if_changed_dep,as_o_S)
+
+$(obj)/%-o32.o: $(src)/%.c FORCE
+ $(call cmd,force_checksrc)
+ $(call if_changed_rule,cc_o_c)
+
+$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
+$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
+$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
+ $(call if_changed,vdsold)
+
+$(obj)/vdso-o32-image.c: VDSO_NAME := o32
+$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE
+ $(call if_changed,genvdso)
+
+obj-y += vdso-o32-image.o
+
+endif
+
+#
+# Build N32 VDSO.
+#
+
+targets += $(obj-vdso-y:%.o=%-n32.o)
+targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c
+
+ifdef CONFIG_MIPS32_N32
+
+obj-vdso-n32 := $(obj-vdso-y:%.o=$(obj)/%-n32.o)
+
+$(obj-vdso-n32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=n32
+$(obj-vdso-n32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=n32
+
+$(obj)/%-n32.o: $(src)/%.S FORCE
+ $(call if_changed_dep,as_o_S)
+
+$(obj)/%-n32.o: $(src)/%.c FORCE
+ $(call cmd,force_checksrc)
+ $(call if_changed_rule,cc_o_c)
+
+$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
+$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
+ $(call if_changed_dep,cpp_lds_S)
+
+$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
+ $(call if_changed,vdsold)
+
+$(obj)/vdso-n32-image.c: VDSO_NAME := n32
+$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE
+ $(call if_changed,genvdso)
+
+obj-y += vdso-n32-image.o
+
+endif
+
+# FIXME: Need install rule for debug.
+# Needs to deal with dependency for generation of dbg by cmd_genvdso...
diff --git a/arch/mips/vdso/elf.S b/arch/mips/vdso/elf.S
new file mode 100644
index 0000000..be37bbb
--- /dev/null
+++ b/arch/mips/vdso/elf.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 "vdso.h"
+
+#include <linux/elfnote.h>
+#include <linux/version.h>
+
+ELFNOTE_START(Linux, 0, "a")
+ .long LINUX_VERSION_CODE
+ELFNOTE_END
+
+/*
+ * The .MIPS.abiflags section must be defined with the FP ABI flags set
+ * to 'any' to be able to link with both old and new libraries.
+ * Newer toolchains are capable of automatically generating this, but we want
+ * to work with older toolchains as well. Therefore, we define the contents of
+ * this section here (under different names), and then genvdso will patch
+ * it to have the correct name and type.
+ *
+ * We base the .MIPS.abiflags section on preprocessor definitions rather than
+ * CONFIG_* because we need to match the particular ABI we are building the
+ * VDSO for.
+ *
+ * See https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
+ * for the .MIPS.abiflags section description.
+ */
+
+ .section .mips_abiflags, "a"
+ .align 3
+__mips_abiflags:
+ .hword 0 /* version */
+ .byte __mips /* isa_level */
+
+ /* isa_rev */
+#ifdef __mips_isa_rev
+ .byte __mips_isa_rev
+#else
+ .byte 0
+#endif
+
+ /* gpr_size */
+#ifdef __mips64
+ .byte 2 /* AFL_REG_64 */
+#else
+ .byte 1 /* AFL_REG_32 */
+#endif
+
+ /* cpr1_size */
+#if (defined(__mips_isa_rev) && __mips_isa_rev >= 6) || defined(__mips64)
+ .byte 2 /* AFL_REG_64 */
+#else
+ .byte 1 /* AFL_REG_32 */
+#endif
+
+ .byte 0 /* cpr2_size (AFL_REG_NONE) */
+ .byte 0 /* fp_abi (Val_GNU_MIPS_ABI_FP_ANY) */
+ .word 0 /* isa_ext */
+ .word 0 /* ases */
+ .word 0 /* flags1 */
+ .word 0 /* flags2 */
diff --git a/arch/mips/vdso/genvdso.c b/arch/mips/vdso/genvdso.c
new file mode 100644
index 0000000..530a36f
--- /dev/null
+++ b/arch/mips/vdso/genvdso.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+/*
+ * This tool is used to generate the real VDSO images from the raw image. It
+ * first patches up the MIPS ABI flags and GNU attributes sections defined in
+ * elf.S to have the correct name and type. It then generates a C source file
+ * to be compiled into the kernel containing the VDSO image data and a
+ * mips_vdso_image struct for it, including symbol offsets extracted from the
+ * image.
+ *
+ * We need to be passed both a stripped and unstripped VDSO image. The stripped
+ * image is compiled into the kernel, but we must also patch up the unstripped
+ * image's ABI flags sections so that it can be installed and used for
+ * debugging.
+ */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <byteswap.h>
+#include <elf.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Define these in case the system elf.h is not new enough to have them. */
+#ifndef SHT_GNU_ATTRIBUTES
+# define SHT_GNU_ATTRIBUTES 0x6ffffff5
+#endif
+#ifndef SHT_MIPS_ABIFLAGS
+# define SHT_MIPS_ABIFLAGS 0x7000002a
+#endif
+
+enum {
+ ABI_O32 = (1 << 0),
+ ABI_N32 = (1 << 1),
+ ABI_N64 = (1 << 2),
+
+ ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
+};
+
+/* Symbols the kernel requires offsets for. */
+static struct {
+ const char *name;
+ const char *offset_name;
+ unsigned int abis;
+} vdso_symbols[] = {
+ { "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
+ { "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
+ {}
+};
+
+static const char *program_name;
+static const char *vdso_name;
+static unsigned char elf_class;
+static unsigned int elf_abi;
+static bool need_swap;
+static FILE *out_file;
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define HOST_ORDER ELFDATA2LSB
+#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define HOST_ORDER ELFDATA2MSB
+#endif
+
+#define BUILD_SWAP(bits) \
+ static uint##bits##_t swap_uint##bits(uint##bits##_t val) \
+ { \
+ return need_swap ? bswap_##bits(val) : val; \
+ }
+
+BUILD_SWAP(16)
+BUILD_SWAP(32)
+BUILD_SWAP(64)
+
+#define __FUNC(name, bits) name##bits
+#define _FUNC(name, bits) __FUNC(name, bits)
+#define FUNC(name) _FUNC(name, ELF_BITS)
+
+#define __ELF(x, bits) Elf##bits##_##x
+#define _ELF(x, bits) __ELF(x, bits)
+#define ELF(x) _ELF(x, ELF_BITS)
+
+/*
+ * Include genvdso.h twice with ELF_BITS defined differently to get functions
+ * for both ELF32 and ELF64.
+ */
+
+#define ELF_BITS 64
+#include "genvdso.h"
+#undef ELF_BITS
+
+#define ELF_BITS 32
+#include "genvdso.h"
+#undef ELF_BITS
+
+static void *map_vdso(const char *path, size_t *_size)
+{
+ int fd;
+ struct stat stat;
+ void *addr;
+ const Elf32_Ehdr *ehdr;
+
+ fd = open(path, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
+ path, strerror(errno));
+ return NULL;
+ }
+
+ if (fstat(fd, &stat) != 0) {
+ fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
+ path, strerror(errno));
+ return NULL;
+ }
+
+ addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
+ 0);
+ if (addr == MAP_FAILED) {
+ fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
+ path, strerror(errno));
+ return NULL;
+ }
+
+ /* ELF32/64 header formats are the same for the bits we're checking. */
+ ehdr = addr;
+
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+ fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
+ path);
+ return NULL;
+ }
+
+ elf_class = ehdr->e_ident[EI_CLASS];
+ switch (elf_class) {
+ case ELFCLASS32:
+ case ELFCLASS64:
+ break;
+ default:
+ fprintf(stderr, "%s: '%s' has invalid ELF class\n",
+ program_name, path);
+ return NULL;
+ }
+
+ switch (ehdr->e_ident[EI_DATA]) {
+ case ELFDATA2LSB:
+ case ELFDATA2MSB:
+ need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
+ break;
+ default:
+ fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
+ program_name, path);
+ return NULL;
+ }
+
+ if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
+ fprintf(stderr,
+ "%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
+ program_name, path);
+ return NULL;
+ } else if (swap_uint16(ehdr->e_type) != ET_DYN) {
+ fprintf(stderr,
+ "%s: '%s' has invalid ELF type (expected ET_DYN)\n",
+ program_name, path);
+ return NULL;
+ }
+
+ *_size = stat.st_size;
+ return addr;
+}
+
+static bool patch_vdso(const char *path, void *vdso)
+{
+ if (elf_class == ELFCLASS64)
+ return patch_vdso64(path, vdso);
+ else
+ return patch_vdso32(path, vdso);
+}
+
+static bool get_symbols(const char *path, void *vdso)
+{
+ if (elf_class == ELFCLASS64)
+ return get_symbols64(path, vdso);
+ else
+ return get_symbols32(path, vdso);
+}
+
+int main(int argc, char **argv)
+{
+ const char *dbg_vdso_path, *vdso_path, *out_path;
+ void *dbg_vdso, *vdso;
+ size_t dbg_vdso_size, vdso_size, i;
+
+ program_name = argv[0];
+
+ if (argc < 4 || argc > 5) {
+ fprintf(stderr,
+ "Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
+ program_name);
+ return EXIT_FAILURE;
+ }
+
+ dbg_vdso_path = argv[1];
+ vdso_path = argv[2];
+ out_path = argv[3];
+ vdso_name = (argc > 4) ? argv[4] : "";
+
+ dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
+ if (!dbg_vdso)
+ return EXIT_FAILURE;
+
+ vdso = map_vdso(vdso_path, &vdso_size);
+ if (!vdso)
+ return EXIT_FAILURE;
+
+ /* Patch both the VDSOs' ABI flags sections. */
+ if (!patch_vdso(dbg_vdso_path, dbg_vdso))
+ return EXIT_FAILURE;
+ if (!patch_vdso(vdso_path, vdso))
+ return EXIT_FAILURE;
+
+ if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
+ fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
+ dbg_vdso_path, strerror(errno));
+ return EXIT_FAILURE;
+ } else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
+ fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
+ vdso_path, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ out_file = fopen(out_path, "w");
+ if (!out_file) {
+ fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
+ out_path, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ fprintf(out_file, "/* Automatically generated - do not edit */\n");
+ fprintf(out_file, "#include <linux/linkage.h>\n");
+ fprintf(out_file, "#include <linux/mm.h>\n");
+ fprintf(out_file, "#include <asm/vdso.h>\n");
+
+ /* Write out the stripped VDSO data. */
+ fprintf(out_file,
+ "static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
+ vdso_size);
+ for (i = 0; i < vdso_size; i++) {
+ if (!(i % 10))
+ fprintf(out_file, "\n\t");
+ fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
+ }
+ fprintf(out_file, "\n};\n");
+
+ /* Preallocate a page array. */
+ fprintf(out_file,
+ "static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
+ vdso_size);
+
+ fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
+ (vdso_name[0]) ? "_" : "", vdso_name);
+ fprintf(out_file, "\t.data = vdso_data,\n");
+ fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
+ fprintf(out_file, "\t.mapping = {\n");
+ fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
+ fprintf(out_file, "\t\t.pages = vdso_pages,\n");
+ fprintf(out_file, "\t},\n");
+
+ /* Calculate and write symbol offsets to <output file> */
+ if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
+ unlink(out_path);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(out_file, "};\n");
+
+ return EXIT_SUCCESS;
+}
diff --git a/arch/mips/vdso/genvdso.h b/arch/mips/vdso/genvdso.h
new file mode 100644
index 0000000..9433472
--- /dev/null
+++ b/arch/mips/vdso/genvdso.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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.
+ */
+
+static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
+{
+ const ELF(Ehdr) *ehdr = vdso;
+ void *shdrs;
+ ELF(Shdr) *shdr;
+ char *shstrtab, *name;
+ uint16_t sh_count, sh_entsize, i;
+ unsigned int local_gotno, symtabno, gotsym;
+ ELF(Dyn) *dyn = NULL;
+
+ shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
+ sh_count = swap_uint16(ehdr->e_shnum);
+ sh_entsize = swap_uint16(ehdr->e_shentsize);
+
+ shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
+ shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+
+ for (i = 0; i < sh_count; i++) {
+ shdr = shdrs + (i * sh_entsize);
+ name = shstrtab + swap_uint32(shdr->sh_name);
+
+ /*
+ * Ensure there are no relocation sections - ld.so does not
+ * relocate the VDSO so if there are relocations things will
+ * break.
+ */
+ switch (swap_uint32(shdr->sh_type)) {
+ case SHT_REL:
+ case SHT_RELA:
+ fprintf(stderr,
+ "%s: '%s' contains relocation sections\n",
+ program_name, path);
+ return false;
+ case SHT_DYNAMIC:
+ dyn = vdso + FUNC(swap_uint)(shdr->sh_offset);
+ break;
+ }
+
+ /* Check for existing sections. */
+ if (strcmp(name, ".MIPS.abiflags") == 0) {
+ fprintf(stderr,
+ "%s: '%s' already contains a '.MIPS.abiflags' section\n",
+ program_name, path);
+ return false;
+ }
+
+ if (strcmp(name, ".mips_abiflags") == 0) {
+ strcpy(name, ".MIPS.abiflags");
+ shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
+ shdr->sh_entsize = shdr->sh_size;
+ }
+ }
+
+ /*
+ * Ensure the GOT has no entries other than the standard 2, for the same
+ * reason we check that there's no relocation sections above.
+ * The standard two entries are:
+ * - Lazy resolver
+ * - Module pointer
+ */
+ if (dyn) {
+ local_gotno = symtabno = gotsym = 0;
+
+ while (FUNC(swap_uint)(dyn->d_tag) != DT_NULL) {
+ switch (FUNC(swap_uint)(dyn->d_tag)) {
+ /*
+ * This member holds the number of local GOT entries.
+ */
+ case DT_MIPS_LOCAL_GOTNO:
+ local_gotno = FUNC(swap_uint)(dyn->d_un.d_val);
+ break;
+ /*
+ * This member holds the number of entries in the
+ * .dynsym section.
+ */
+ case DT_MIPS_SYMTABNO:
+ symtabno = FUNC(swap_uint)(dyn->d_un.d_val);
+ break;
+ /*
+ * This member holds the index of the first dynamic
+ * symbol table entry that corresponds to an entry in
+ * the GOT.
+ */
+ case DT_MIPS_GOTSYM:
+ gotsym = FUNC(swap_uint)(dyn->d_un.d_val);
+ break;
+ }
+
+ dyn++;
+ }
+
+ if (local_gotno > 2 || symtabno - gotsym) {
+ fprintf(stderr,
+ "%s: '%s' contains unexpected GOT entries\n",
+ program_name, path);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static inline bool FUNC(get_symbols)(const char *path, void *vdso)
+{
+ const ELF(Ehdr) *ehdr = vdso;
+ void *shdrs, *symtab;
+ ELF(Shdr) *shdr;
+ const ELF(Sym) *sym;
+ char *strtab, *name;
+ uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
+ uint64_t offset;
+ uint32_t flags;
+
+ shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
+ sh_count = swap_uint16(ehdr->e_shnum);
+ sh_entsize = swap_uint16(ehdr->e_shentsize);
+
+ for (i = 0; i < sh_count; i++) {
+ shdr = shdrs + (i * sh_entsize);
+
+ if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
+ break;
+ }
+
+ if (i == sh_count) {
+ fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
+ path);
+ return false;
+ }
+
+ /* Get flags */
+ flags = swap_uint32(ehdr->e_flags);
+ if (elf_class == ELFCLASS64)
+ elf_abi = ABI_N64;
+ else if (flags & EF_MIPS_ABI2)
+ elf_abi = ABI_N32;
+ else
+ elf_abi = ABI_O32;
+
+ /* Get symbol table. */
+ symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+ st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
+ st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
+
+ /* Get string table. */
+ shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
+ strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
+
+ /* Write offsets for symbols needed by the kernel. */
+ for (i = 0; vdso_symbols[i].name; i++) {
+ if (!(vdso_symbols[i].abis & elf_abi))
+ continue;
+
+ for (j = 0; j < st_count; j++) {
+ sym = symtab + (j * st_entsize);
+ name = strtab + swap_uint32(sym->st_name);
+
+ if (!strcmp(name, vdso_symbols[i].name)) {
+ offset = FUNC(swap_uint)(sym->st_value);
+
+ fprintf(out_file,
+ "\t.%s = 0x%" PRIx64 ",\n",
+ vdso_symbols[i].offset_name, offset);
+ break;
+ }
+ }
+
+ if (j == st_count) {
+ fprintf(stderr,
+ "%s: '%s' is missing required symbol '%s'\n",
+ program_name, path, vdso_symbols[i].name);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/arch/mips/vdso/gettimeofday.c b/arch/mips/vdso/gettimeofday.c
new file mode 100644
index 0000000..ce89c9e
--- /dev/null
+++ b/arch/mips/vdso/gettimeofday.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 "vdso.h"
+
+#include <linux/compiler.h>
+#include <linux/irqchip/mips-gic.h>
+#include <linux/time.h>
+
+#include <asm/clocksource.h>
+#include <asm/io.h>
+#include <asm/mips-cm.h>
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+static __always_inline int do_realtime_coarse(struct timespec *ts,
+ const union mips_vdso_data *data)
+{
+ u32 start_seq;
+
+ do {
+ start_seq = vdso_data_read_begin(data);
+
+ ts->tv_sec = data->xtime_sec;
+ ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+ } while (vdso_data_read_retry(data, start_seq));
+
+ return 0;
+}
+
+static __always_inline int do_monotonic_coarse(struct timespec *ts,
+ const union mips_vdso_data *data)
+{
+ u32 start_seq;
+ u32 to_mono_sec;
+ u32 to_mono_nsec;
+
+ do {
+ start_seq = vdso_data_read_begin(data);
+
+ ts->tv_sec = data->xtime_sec;
+ ts->tv_nsec = data->xtime_nsec >> data->cs_shift;
+
+ to_mono_sec = data->wall_to_mono_sec;
+ to_mono_nsec = data->wall_to_mono_nsec;
+ } while (vdso_data_read_retry(data, start_seq));
+
+ ts->tv_sec += to_mono_sec;
+ timespec_add_ns(ts, to_mono_nsec);
+
+ return 0;
+}
+
+#ifdef CONFIG_CSRC_R4K
+
+static __always_inline u64 read_r4k_count(void)
+{
+ unsigned int count;
+
+ __asm__ __volatile__(
+ " .set push\n"
+ " .set mips32r2\n"
+ " rdhwr %0, $2\n"
+ " .set pop\n"
+ : "=r" (count));
+
+ return count;
+}
+
+#endif
+
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static __always_inline u64 read_gic_count(const union mips_vdso_data *data)
+{
+ void __iomem *gic = get_gic(data);
+ u32 hi, hi2, lo;
+
+ do {
+ hi = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+ lo = __raw_readl(gic + GIC_UMV_SH_COUNTER_31_00_OFS);
+ hi2 = __raw_readl(gic + GIC_UMV_SH_COUNTER_63_32_OFS);
+ } while (hi2 != hi);
+
+ return (((u64)hi) << 32) + lo;
+}
+
+#endif
+
+static __always_inline u64 get_ns(const union mips_vdso_data *data)
+{
+ u64 cycle_now, delta, nsec;
+
+ switch (data->clock_mode) {
+#ifdef CONFIG_CSRC_R4K
+ case VDSO_CLOCK_R4K:
+ cycle_now = read_r4k_count();
+ break;
+#endif
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+ case VDSO_CLOCK_GIC:
+ cycle_now = read_gic_count(data);
+ break;
+#endif
+ default:
+ return 0;
+ }
+
+ delta = (cycle_now - data->cs_cycle_last) & data->cs_mask;
+
+ nsec = (delta * data->cs_mult) + data->xtime_nsec;
+ nsec >>= data->cs_shift;
+
+ return nsec;
+}
+
+static __always_inline int do_realtime(struct timespec *ts,
+ const union mips_vdso_data *data)
+{
+ u32 start_seq;
+ u64 ns;
+
+ do {
+ start_seq = vdso_data_read_begin(data);
+
+ if (data->clock_mode == VDSO_CLOCK_NONE)
+ return -ENOSYS;
+
+ ts->tv_sec = data->xtime_sec;
+ ns = get_ns(data);
+ } while (vdso_data_read_retry(data, start_seq));
+
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, ns);
+
+ return 0;
+}
+
+static __always_inline int do_monotonic(struct timespec *ts,
+ const union mips_vdso_data *data)
+{
+ u32 start_seq;
+ u64 ns;
+ u32 to_mono_sec;
+ u32 to_mono_nsec;
+
+ do {
+ start_seq = vdso_data_read_begin(data);
+
+ if (data->clock_mode == VDSO_CLOCK_NONE)
+ return -ENOSYS;
+
+ ts->tv_sec = data->xtime_sec;
+ ns = get_ns(data);
+
+ to_mono_sec = data->wall_to_mono_sec;
+ to_mono_nsec = data->wall_to_mono_nsec;
+ } while (vdso_data_read_retry(data, start_seq));
+
+ ts->tv_sec += to_mono_sec;
+ ts->tv_nsec = 0;
+ timespec_add_ns(ts, ns + to_mono_nsec);
+
+ return 0;
+}
+
+#ifdef CONFIG_MIPS_CLOCK_VSYSCALL
+
+/*
+ * This is behind the ifdef so that we don't provide the symbol when there's no
+ * possibility of there being a usable clocksource, because there's nothing we
+ * can do without it. When libc fails the symbol lookup it should fall back on
+ * the standard syscall path.
+ */
+int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ const union mips_vdso_data *data = get_vdso_data();
+ struct timespec ts;
+ int ret;
+
+ ret = do_realtime(&ts, data);
+ if (ret)
+ return ret;
+
+ if (tv) {
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / 1000;
+ }
+
+ if (tz) {
+ tz->tz_minuteswest = data->tz_minuteswest;
+ tz->tz_dsttime = data->tz_dsttime;
+ }
+
+ return 0;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
+int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+ const union mips_vdso_data *data = get_vdso_data();
+ int ret;
+
+ switch (clkid) {
+ case CLOCK_REALTIME_COARSE:
+ ret = do_realtime_coarse(ts, data);
+ break;
+ case CLOCK_MONOTONIC_COARSE:
+ ret = do_monotonic_coarse(ts, data);
+ break;
+ case CLOCK_REALTIME:
+ ret = do_realtime(ts, data);
+ break;
+ case CLOCK_MONOTONIC:
+ ret = do_monotonic(ts, data);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ /* If we return -ENOSYS libc should fall back to a syscall. */
+ return ret;
+}
diff --git a/arch/mips/vdso/sigreturn.S b/arch/mips/vdso/sigreturn.S
new file mode 100644
index 0000000..715bf59
--- /dev/null
+++ b/arch/mips/vdso/sigreturn.S
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 "vdso.h"
+
+#include <uapi/asm/unistd.h>
+
+#include <asm/regdef.h>
+#include <asm/asm.h>
+
+ .section .text
+ .cfi_sections .debug_frame
+
+LEAF(__vdso_rt_sigreturn)
+ .cfi_startproc
+ .frame sp, 0, ra
+ .mask 0x00000000, 0
+ .fmask 0x00000000, 0
+ .cfi_signal_frame
+
+ li v0, __NR_rt_sigreturn
+ syscall
+
+ .cfi_endproc
+ END(__vdso_rt_sigreturn)
+
+#if _MIPS_SIM == _MIPS_SIM_ABI32
+
+LEAF(__vdso_sigreturn)
+ .cfi_startproc
+ .frame sp, 0, ra
+ .mask 0x00000000, 0
+ .fmask 0x00000000, 0
+ .cfi_signal_frame
+
+ li v0, __NR_sigreturn
+ syscall
+
+ .cfi_endproc
+ END(__vdso_sigreturn)
+
+#endif
diff --git a/arch/mips/vdso/vdso.h b/arch/mips/vdso/vdso.h
new file mode 100644
index 0000000..cfb1be4
--- /dev/null
+++ b/arch/mips/vdso/vdso.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 <asm/sgidefs.h>
+
+#if _MIPS_SIM != _MIPS_SIM_ABI64 && defined(CONFIG_64BIT)
+
+/* Building 32-bit VDSO for the 64-bit kernel. Fake a 32-bit Kconfig. */
+#undef CONFIG_64BIT
+#define CONFIG_32BIT 1
+#ifndef __ASSEMBLY__
+#include <asm-generic/atomic64.h>
+#endif
+#endif
+
+#ifndef __ASSEMBLY__
+
+#include <asm/asm.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+static inline unsigned long get_vdso_base(void)
+{
+ unsigned long addr;
+
+ /*
+ * We can't use cpu_has_mips_r6 since it needs the cpu_data[]
+ * kernel symbol.
+ */
+#ifdef CONFIG_CPU_MIPSR6
+ /*
+ * lapc <symbol> is an alias to addiupc reg, <symbol> - .
+ *
+ * We can't use addiupc because there is no label-label
+ * support for the addiupc reloc
+ */
+ __asm__("lapc %0, _start \n"
+ : "=r" (addr) : :);
+#else
+ /*
+ * Get the base load address of the VDSO. We have to avoid generating
+ * relocations and references to the GOT because ld.so does not peform
+ * relocations on the VDSO. We use the current offset from the VDSO base
+ * and perform a PC-relative branch which gives the absolute address in
+ * ra, and take the difference. The assembler chokes on
+ * "li %0, _start - .", so embed the offset as a word and branch over
+ * it.
+ *
+ */
+
+ __asm__(
+ " .set push \n"
+ " .set noreorder \n"
+ " bal 1f \n"
+ " nop \n"
+ " .word _start - . \n"
+ "1: lw %0, 0($31) \n"
+ " " STR(PTR_ADDU) " %0, $31, %0 \n"
+ " .set pop \n"
+ : "=r" (addr)
+ :
+ : "$31");
+#endif /* CONFIG_CPU_MIPSR6 */
+
+ return addr;
+}
+
+static inline const union mips_vdso_data *get_vdso_data(void)
+{
+ return (const union mips_vdso_data *)(get_vdso_base() - PAGE_SIZE);
+}
+
+#ifdef CONFIG_CLKSRC_MIPS_GIC
+
+static inline void __iomem *get_gic(const union mips_vdso_data *data)
+{
+ return (void __iomem *)data - PAGE_SIZE;
+}
+
+#endif /* CONFIG_CLKSRC_MIPS_GIC */
+
+#endif /* __ASSEMBLY__ */
diff --git a/arch/mips/vdso/vdso.lds.S b/arch/mips/vdso/vdso.lds.S
new file mode 100644
index 0000000..8df7dd5
--- /dev/null
+++ b/arch/mips/vdso/vdso.lds.S
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.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 <asm/sgidefs.h>
+
+#if _MIPS_SIM == _MIPS_SIM_ABI64
+OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
+#elif _MIPS_SIM == _MIPS_SIM_NABI32
+OUTPUT_FORMAT("elf32-ntradlittlemips", "elf32-ntradbigmips", "elf32-ntradlittlemips")
+#else
+OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", "elf32-tradlittlemips")
+#endif
+
+OUTPUT_ARCH(mips)
+
+SECTIONS
+{
+ PROVIDE(_start = .);
+ . = SIZEOF_HEADERS;
+
+ /*
+ * In order to retain compatibility with older toolchains we provide the
+ * ABI flags section ourself. Newer assemblers will automatically
+ * generate .MIPS.abiflags sections so we discard such input sections,
+ * and then manually define our own section here. genvdso will patch
+ * this section to have the correct name/type.
+ */
+ .mips_abiflags : { *(.mips_abiflags) } :text :abiflags
+
+ .reginfo : { *(.reginfo) } :text :reginfo
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ .text : { *(.text*) } :text
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+
+ .rodata : { *(.rodata*) } :text
+
+ _end = .;
+ PROVIDE(end = .);
+
+ /DISCARD/ : {
+ *(.MIPS.abiflags)
+ *(.gnu.attributes)
+ *(.note.GNU-stack)
+ *(.data .data.* .gnu.linkonce.d.* .sdata*)
+ *(.bss .sbss .dynbss .dynsbss)
+ }
+}
+
+PHDRS
+{
+ /*
+ * Provide a PT_MIPS_ABIFLAGS header to assign the ABI flags section
+ * to. We can specify the header type directly here so no modification
+ * is needed later on.
+ */
+ abiflags 0x70000003;
+
+ /*
+ * The ABI flags header must exist directly after the PT_INTERP header,
+ * so we must explicitly place the PT_MIPS_REGINFO header after it to
+ * stop the linker putting one in at the start.
+ */
+ reginfo 0x70000000;
+
+ text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+ LINUX_2.6 {
+#ifndef DISABLE_MIPS_VDSO
+ global:
+ __vdso_clock_gettime;
+ __vdso_gettimeofday;
+#endif
+ local: *;
+ };
+}
diff --git a/arch/mips/xilfpga/Kconfig b/arch/mips/xilfpga/Kconfig
new file mode 100644
index 0000000..42a030a
--- /dev/null
+++ b/arch/mips/xilfpga/Kconfig
@@ -0,0 +1,9 @@
+choice
+ prompt "Machine type"
+ depends on MACH_XILFPGA
+ default XILFPGA_NEXYS4DDR
+
+config XILFPGA_NEXYS4DDR
+ bool "Nexys4DDR by Digilent"
+
+endchoice
diff --git a/arch/mips/xilfpga/Makefile b/arch/mips/xilfpga/Makefile
new file mode 100644
index 0000000..a4deec6
--- /dev/null
+++ b/arch/mips/xilfpga/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Xilfpga
+#
+
+obj-y += init.o
+obj-y += intc.o
+obj-y += time.o
diff --git a/arch/mips/xilfpga/Platform b/arch/mips/xilfpga/Platform
new file mode 100644
index 0000000..ed375af
--- /dev/null
+++ b/arch/mips/xilfpga/Platform
@@ -0,0 +1,3 @@
+platform-$(CONFIG_MACH_XILFPGA) += xilfpga/
+cflags-$(CONFIG_MACH_XILFPGA) += -I$(srctree)/arch/mips/include/asm/mach-xilfpga
+load-$(CONFIG_MACH_XILFPGA) += 0xffffffff80100000
diff --git a/arch/mips/xilfpga/init.c b/arch/mips/xilfpga/init.c
new file mode 100644
index 0000000..ce2aee2
--- /dev/null
+++ b/arch/mips/xilfpga/init.c
@@ -0,0 +1,57 @@
+/*
+ * Xilfpga platform setup
+ *
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/of_fdt.h>
+#include <linux/of_platform.h>
+
+#include <asm/prom.h>
+
+#define XILFPGA_UART_BASE 0xb0401000
+
+const char *get_system_type(void)
+{
+ return "MIPSfpga";
+}
+
+void __init plat_mem_setup(void)
+{
+ __dt_setup_arch(__dtb_start);
+ strlcpy(arcs_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+}
+
+void __init prom_init(void)
+{
+ setup_8250_early_printk_port(XILFPGA_UART_BASE, 2, 50000);
+}
+
+void __init prom_free_prom_memory(void)
+{
+}
+
+void __init device_tree_init(void)
+{
+ if (!initial_boot_params)
+ return;
+
+ unflatten_and_copy_device_tree();
+}
+
+static int __init plat_of_setup(void)
+{
+ if (!of_have_populated_dt())
+ panic("Device tree not present");
+
+ if (of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL))
+ panic("Failed to populate DT");
+
+ return 0;
+}
+arch_initcall(plat_of_setup);
diff --git a/arch/mips/xilfpga/intc.c b/arch/mips/xilfpga/intc.c
new file mode 100644
index 0000000..c4d1a71
--- /dev/null
+++ b/arch/mips/xilfpga/intc.c
@@ -0,0 +1,25 @@
+/*
+ * Xilfpga interrupt controller setup
+ *
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/of_irq.h>
+
+#include <asm/irq_cpu.h>
+
+static struct of_device_id of_irq_ids[] __initdata = {
+ { .compatible = "mti,cpu-interrupt-controller", .data = mips_cpu_irq_of_init },
+ {},
+};
+
+void __init arch_init_irq(void)
+{
+ of_irq_init(of_irq_ids);
+}
diff --git a/arch/mips/xilfpga/time.c b/arch/mips/xilfpga/time.c
new file mode 100644
index 0000000..cbb3fca
--- /dev/null
+++ b/arch/mips/xilfpga/time.c
@@ -0,0 +1,41 @@
+/*
+ * Xilfpga clocksource/timer setup
+ *
+ * Copyright (C) 2015 Imagination Technologies
+ * Author: Zubair Lutfullah Kakakhel <Zubair.Kakakhel@imgtec.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clocksource.h>
+#include <linux/of.h>
+
+#include <asm/time.h>
+
+void __init plat_time_init(void)
+{
+ struct device_node *np;
+ struct clk *clk;
+
+ of_clk_init(NULL);
+ clocksource_probe();
+
+ np = of_get_cpu_node(0, NULL);
+ if (!np) {
+ pr_err("Failed to get CPU node\n");
+ return;
+ }
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
+ return;
+ }
+
+ mips_hpt_frequency = clk_get_rate(clk) / 2;
+ clk_put(clk);
+}
diff --git a/arch/mn10300/Kconfig b/arch/mn10300/Kconfig
index 4434b54..78ae555 100644
--- a/arch/mn10300/Kconfig
+++ b/arch/mn10300/Kconfig
@@ -1,6 +1,7 @@
config MN10300
def_bool y
select HAVE_OPROFILE
+ select HAVE_UID16
select GENERIC_IRQ_SHOW
select ARCH_WANT_IPC_PARSE_VERSION
select HAVE_ARCH_TRACEHOOK
@@ -37,9 +38,6 @@ config HIGHMEM
config NUMA
def_bool n
-config UID16
- def_bool y
-
config RWSEM_GENERIC_SPINLOCK
def_bool y
diff --git a/arch/mn10300/include/asm/uaccess.h b/arch/mn10300/include/asm/uaccess.h
index 5372787..20f7bf6 100644
--- a/arch/mn10300/include/asm/uaccess.h
+++ b/arch/mn10300/include/asm/uaccess.h
@@ -110,21 +110,6 @@ extern int fixup_exception(struct pt_regs *regs);
#define __put_user(x, ptr) __put_user_nocheck((x), (ptr), sizeof(*(ptr)))
#define __get_user(x, ptr) __get_user_nocheck((x), (ptr), sizeof(*(ptr)))
-/*
- * The "xxx_ret" versions return constant specified in third argument, if
- * something bad happens. These macros can be optimized for the
- * case of just returning from the function xxx_ret is used.
- */
-
-#define put_user_ret(x, ptr, ret) \
- ({ if (put_user((x), (ptr))) return (ret); })
-#define get_user_ret(x, ptr, ret) \
- ({ if (get_user((x), (ptr))) return (ret); })
-#define __put_user_ret(x, ptr, ret) \
- ({ if (__put_user((x), (ptr))) return (ret); })
-#define __get_user_ret(x, ptr, ret) \
- ({ if (__get_user((x), (ptr))) return (ret); })
-
struct __large_struct { unsigned long buf[100]; };
#define __m(x) (*(struct __large_struct *)(x))
diff --git a/arch/nios2/mm/cacheflush.c b/arch/nios2/mm/cacheflush.c
index 223cdcc..87bf88e 100644
--- a/arch/nios2/mm/cacheflush.c
+++ b/arch/nios2/mm/cacheflush.c
@@ -23,22 +23,6 @@ static void __flush_dcache(unsigned long start, unsigned long end)
end += (cpuinfo.dcache_line_size - 1);
end &= ~(cpuinfo.dcache_line_size - 1);
- for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) {
- __asm__ __volatile__ (" flushda 0(%0)\n"
- : /* Outputs */
- : /* Inputs */ "r"(addr)
- /* : No clobber */);
- }
-}
-
-static void __flush_dcache_all(unsigned long start, unsigned long end)
-{
- unsigned long addr;
-
- start &= ~(cpuinfo.dcache_line_size - 1);
- end += (cpuinfo.dcache_line_size - 1);
- end &= ~(cpuinfo.dcache_line_size - 1);
-
if (end > start + cpuinfo.dcache_size)
end = start + cpuinfo.dcache_size;
@@ -112,7 +96,7 @@ static void flush_aliases(struct address_space *mapping, struct page *page)
void flush_cache_all(void)
{
- __flush_dcache_all(0, cpuinfo.dcache_size);
+ __flush_dcache(0, cpuinfo.dcache_size);
__flush_icache(0, cpuinfo.icache_size);
}
@@ -182,7 +166,7 @@ void __flush_dcache_page(struct address_space *mapping, struct page *page)
*/
unsigned long start = (unsigned long)page_address(page);
- __flush_dcache_all(start, start + PAGE_SIZE);
+ __flush_dcache(start, start + PAGE_SIZE);
}
void flush_dcache_page(struct page *page)
@@ -268,7 +252,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
{
flush_cache_page(vma, user_vaddr, page_to_pfn(page));
memcpy(dst, src, len);
- __flush_dcache_all((unsigned long)src, (unsigned long)src + len);
+ __flush_dcache((unsigned long)src, (unsigned long)src + len);
if (vma->vm_flags & VM_EXEC)
__flush_icache((unsigned long)src, (unsigned long)src + len);
}
@@ -279,7 +263,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
{
flush_cache_page(vma, user_vaddr, page_to_pfn(page));
memcpy(dst, src, len);
- __flush_dcache_all((unsigned long)dst, (unsigned long)dst + len);
+ __flush_dcache((unsigned long)dst, (unsigned long)dst + len);
if (vma->vm_flags & VM_EXEC)
__flush_icache((unsigned long)dst, (unsigned long)dst + len);
}
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index c365469..729f891 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -108,6 +108,9 @@ config PGTABLE_LEVELS
default 3 if 64BIT && PARISC_PAGE_SIZE_4KB
default 2
+config SYS_SUPPORTS_HUGETLBFS
+ def_bool y if PA20
+
source "init/Kconfig"
source "kernel/Kconfig.freezer"
diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h
new file mode 100644
index 0000000..7d56a9c
--- /dev/null
+++ b/arch/parisc/include/asm/hugetlb.h
@@ -0,0 +1,85 @@
+#ifndef _ASM_PARISC64_HUGETLB_H
+#define _ASM_PARISC64_HUGETLB_H
+
+#include <asm/page.h>
+#include <asm-generic/hugetlb.h>
+
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr,
+ unsigned long len) {
+ return 0;
+}
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(struct file *file,
+ unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor,
+ unsigned long ceiling)
+{
+ free_pgd_range(tlb, addr, end, floor, ceiling);
+}
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return pte_none(pte);
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ return pte_wrprotect(pte);
+}
+
+static inline void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t old_pte = *ptep;
+ set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+}
+
+static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ int changed = !pte_same(*ptep, pte);
+ if (changed) {
+ set_huge_pte_at(vma->vm_mm, addr, ptep, pte);
+ flush_tlb_page(vma, addr);
+ }
+ return changed;
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ return *ptep;
+}
+
+static inline void arch_clear_hugepage_flags(struct page *page)
+{
+}
+
+#endif /* _ASM_PARISC64_HUGETLB_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
index 60d5d17..80e742a 100644
--- a/arch/parisc/include/asm/page.h
+++ b/arch/parisc/include/asm/page.h
@@ -145,11 +145,22 @@ extern int npmem_ranges;
#endif /* CONFIG_DISCONTIGMEM */
#ifdef CONFIG_HUGETLB_PAGE
-#define HPAGE_SHIFT 22 /* 4MB (is this fixed?) */
+#define HPAGE_SHIFT PMD_SHIFT /* fixed for transparent huge pages */
#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE - 1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT 20 /* 20 = 1MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_1M
+#elif !defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT 22 /* 22 = 4MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4M
+#else
+# define REAL_HPAGE_SHIFT 24 /* 24 = 16MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_16M
#endif
+#endif /* CONFIG_HUGETLB_PAGE */
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h
index 3edbb9f..f2fd327 100644
--- a/arch/parisc/include/asm/pgalloc.h
+++ b/arch/parisc/include/asm/pgalloc.h
@@ -35,7 +35,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
PxD_FLAG_VALID |
PxD_FLAG_ATTACHED)
+ (__u32)(__pa((unsigned long)pgd) >> PxD_VALUE_SHIFT));
- /* The first pmd entry also is marked with _PAGE_GATEWAY as
+ /* The first pmd entry also is marked with PxD_FLAG_ATTACHED as
* a signal that this pmd may not be freed */
__pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
#endif
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index f93c4a4..291cee2 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -83,7 +83,11 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
/* This is the size of the initially mapped kernel memory */
-#define KERNEL_INITIAL_ORDER 24 /* 0 to 1<<24 = 16MB */
+#ifdef CONFIG_64BIT
+#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */
+#else
+#define KERNEL_INITIAL_ORDER 24 /* 1<<24 = 16MB */
+#endif
#define KERNEL_INITIAL_SIZE (1 << KERNEL_INITIAL_ORDER)
#if CONFIG_PGTABLE_LEVELS == 3
@@ -167,7 +171,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
#define _PAGE_NO_CACHE_BIT 24 /* (0x080) Uncached Page (U bit) */
#define _PAGE_ACCESSED_BIT 23 /* (0x100) Software: Page Accessed */
#define _PAGE_PRESENT_BIT 22 /* (0x200) Software: translation valid */
-/* bit 21 was formerly the FLUSH bit but is now unused */
+#define _PAGE_HPAGE_BIT 21 /* (0x400) Software: Huge Page */
#define _PAGE_USER_BIT 20 /* (0x800) Software: User accessible page */
/* N.B. The bits are defined in terms of a 32 bit word above, so the */
@@ -194,6 +198,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
#define _PAGE_NO_CACHE (1 << xlate_pabit(_PAGE_NO_CACHE_BIT))
#define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT))
#define _PAGE_PRESENT (1 << xlate_pabit(_PAGE_PRESENT_BIT))
+#define _PAGE_HUGE (1 << xlate_pabit(_PAGE_HPAGE_BIT))
#define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT))
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
@@ -217,7 +222,7 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
#define PxD_FLAG_VALID (1 << xlate_pabit(_PxD_VALID_BIT))
#define PxD_FLAG_MASK (0xf)
#define PxD_FLAG_SHIFT (4)
-#define PxD_VALUE_SHIFT (8) /* (PAGE_SHIFT-PxD_FLAG_SHIFT) */
+#define PxD_VALUE_SHIFT (PFN_PTE_SHIFT-PxD_FLAG_SHIFT)
#ifndef __ASSEMBLY__
@@ -363,6 +368,19 @@ static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; return
static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
/*
+ * Huge pte definitions.
+ */
+#ifdef CONFIG_HUGETLB_PAGE
+#define pte_huge(pte) (pte_val(pte) & _PAGE_HUGE)
+#define pte_mkhuge(pte) (__pte(pte_val(pte) | \
+ (parisc_requires_coherency() ? 0 : _PAGE_HUGE)))
+#else
+#define pte_huge(pte) (0)
+#define pte_mkhuge(pte) (pte)
+#endif
+
+
+/*
* Conversion functions: convert a page and protection to a page entry,
* and a page entry and page directory to the page they refer to.
*/
@@ -410,8 +428,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
/* Find an entry in the second-level page table.. */
#if CONFIG_PGTABLE_LEVELS == 3
+#define pmd_index(addr) (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))
#define pmd_offset(dir,address) \
-((pmd_t *) pgd_page_vaddr(*(dir)) + (((address)>>PMD_SHIFT) & (PTRS_PER_PMD-1)))
+((pmd_t *) pgd_page_vaddr(*(dir)) + pmd_index(address))
#else
#define pmd_offset(dir,addr) ((pmd_t *) dir)
#endif
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
index 54adb60..7e759ec 100644
--- a/arch/parisc/include/asm/processor.h
+++ b/arch/parisc/include/asm/processor.h
@@ -192,33 +192,6 @@ void show_trace(struct task_struct *task, unsigned long *stack);
*/
typedef unsigned int elf_caddr_t;
-#define start_thread_som(regs, new_pc, new_sp) do { \
- unsigned long *sp = (unsigned long *)new_sp; \
- __u32 spaceid = (__u32)current->mm->context; \
- unsigned long pc = (unsigned long)new_pc; \
- /* offset pc for priv. level */ \
- pc |= 3; \
- \
- regs->iasq[0] = spaceid; \
- regs->iasq[1] = spaceid; \
- regs->iaoq[0] = pc; \
- regs->iaoq[1] = pc + 4; \
- regs->sr[2] = LINUX_GATEWAY_SPACE; \
- regs->sr[3] = 0xffff; \
- regs->sr[4] = spaceid; \
- regs->sr[5] = spaceid; \
- regs->sr[6] = spaceid; \
- regs->sr[7] = spaceid; \
- regs->gr[ 0] = USER_PSW; \
- regs->gr[30] = ((new_sp)+63)&~63; \
- regs->gr[31] = pc; \
- \
- get_user(regs->gr[26],&sp[0]); \
- get_user(regs->gr[25],&sp[-1]); \
- get_user(regs->gr[24],&sp[-2]); \
- get_user(regs->gr[23],&sp[-3]); \
-} while(0)
-
/* The ELF abi wants things done a "wee bit" differently than
* som does. Supporting this behavior here avoids
* having our own version of create_elf_tables.
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
index ecc3ae1..dd4d187 100644
--- a/arch/parisc/include/uapi/asm/mman.h
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -49,16 +49,6 @@
#define MADV_DONTFORK 10 /* don't inherit across fork */
#define MADV_DOFORK 11 /* do inherit across fork */
-/* The range 12-64 is reserved for page size specification. */
-#define MADV_4K_PAGES 12 /* Use 4K pages */
-#define MADV_16K_PAGES 14 /* Use 16K pages */
-#define MADV_64K_PAGES 16 /* Use 64K pages */
-#define MADV_256K_PAGES 18 /* Use 256K pages */
-#define MADV_1M_PAGES 20 /* Use 1 Megabyte pages */
-#define MADV_4M_PAGES 22 /* Use 4 Megabyte pages */
-#define MADV_16M_PAGES 24 /* Use 16 Megabyte pages */
-#define MADV_64M_PAGES 26 /* Use 64 Megabyte pages */
-
#define MADV_MERGEABLE 65 /* KSM may merge identical pages */
#define MADV_UNMERGEABLE 66 /* KSM may not merge identical pages */
diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h
index 3317038..35bdccb 100644
--- a/arch/parisc/include/uapi/asm/unistd.h
+++ b/arch/parisc/include/uapi/asm/unistd.h
@@ -360,8 +360,9 @@
#define __NR_execveat (__NR_Linux + 342)
#define __NR_membarrier (__NR_Linux + 343)
#define __NR_userfaultfd (__NR_Linux + 344)
+#define __NR_mlock2 (__NR_Linux + 345)
-#define __NR_Linux_syscalls (__NR_userfaultfd + 1)
+#define __NR_Linux_syscalls (__NR_mlock2 + 1)
#define __IGNORE_select /* newselect */
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index 59001ce..d2f6257 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -290,6 +290,14 @@ int main(void)
DEFINE(ASM_PFN_PTE_SHIFT, PFN_PTE_SHIFT);
DEFINE(ASM_PT_INITIAL, PT_INITIAL);
BLANK();
+ /* HUGEPAGE_SIZE is only used in vmlinux.lds.S to align kernel text
+ * and kernel data on physical huge pages */
+#ifdef CONFIG_HUGETLB_PAGE
+ DEFINE(HUGEPAGE_SIZE, 1UL << REAL_HPAGE_SHIFT);
+#else
+ DEFINE(HUGEPAGE_SIZE, PAGE_SIZE);
+#endif
+ BLANK();
DEFINE(EXCDATA_IP, offsetof(struct exception_data, fault_ip));
DEFINE(EXCDATA_SPACE, offsetof(struct exception_data, fault_space));
DEFINE(EXCDATA_ADDR, offsetof(struct exception_data, fault_addr));
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index c5ef408..623496c 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -502,21 +502,38 @@
STREG \pte,0(\ptp)
.endm
+ /* We have (depending on the page size):
+ * - 38 to 52-bit Physical Page Number
+ * - 12 to 26-bit page offset
+ */
/* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
* to a CPU TLB 4k PFN (4k => 12 bits to shift) */
- #define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
+ #define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
+ #define PAGE_ADD_HUGE_SHIFT (REAL_HPAGE_SHIFT-12)
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
- .macro convert_for_tlb_insert20 pte
+ .macro convert_for_tlb_insert20 pte,tmp
+#ifdef CONFIG_HUGETLB_PAGE
+ copy \pte,\tmp
+ extrd,u \tmp,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
+ 64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
+
+ depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
+ (63-58)+PAGE_ADD_SHIFT,\pte
+ extrd,u,*= \tmp,_PAGE_HPAGE_BIT+32,1,%r0
+ depdi _HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\
+ (63-58)+PAGE_ADD_HUGE_SHIFT,\pte
+#else /* Huge pages disabled */
extrd,u \pte,(63-ASM_PFN_PTE_SHIFT)+(63-58)+PAGE_ADD_SHIFT,\
64-PAGE_SHIFT-PAGE_ADD_SHIFT,\pte
depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
(63-58)+PAGE_ADD_SHIFT,\pte
+#endif
.endm
/* Convert the pte and prot to tlb insertion values. How
* this happens is quite subtle, read below */
- .macro make_insert_tlb spc,pte,prot
+ .macro make_insert_tlb spc,pte,prot,tmp
space_to_prot \spc \prot /* create prot id from space */
/* The following is the real subtlety. This is depositing
* T <-> _PAGE_REFTRAP
@@ -553,7 +570,7 @@
depdi 1,12,1,\prot
/* Drop prot bits and convert to page addr for iitlbt and idtlbt */
- convert_for_tlb_insert20 \pte
+ convert_for_tlb_insert20 \pte \tmp
.endm
/* Identical macro to make_insert_tlb above, except it
@@ -646,17 +663,12 @@
/*
- * Align fault_vector_20 on 4K boundary so that both
- * fault_vector_11 and fault_vector_20 are on the
- * same page. This is only necessary as long as we
- * write protect the kernel text, which we may stop
- * doing once we use large page translations to cover
- * the static part of the kernel address space.
+ * Fault_vectors are architecturally required to be aligned on a 2K
+ * boundary
*/
.text
-
- .align 4096
+ .align 2048
ENTRY(fault_vector_20)
/* First vector is invalid (0) */
@@ -1147,7 +1159,7 @@ dtlb_miss_20w:
tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20w
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
idtlbt pte,prot
@@ -1173,7 +1185,7 @@ nadtlb_miss_20w:
tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
idtlbt pte,prot
@@ -1267,7 +1279,7 @@ dtlb_miss_20:
tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
f_extend pte,t1
@@ -1295,7 +1307,7 @@ nadtlb_miss_20:
tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
f_extend pte,t1
@@ -1404,7 +1416,7 @@ itlb_miss_20w:
tlb_lock spc,ptp,pte,t0,t1,itlb_fault
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
iitlbt pte,prot
@@ -1428,7 +1440,7 @@ naitlb_miss_20w:
tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20w
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
iitlbt pte,prot
@@ -1514,7 +1526,7 @@ itlb_miss_20:
tlb_lock spc,ptp,pte,t0,t1,itlb_fault
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
f_extend pte,t1
@@ -1534,7 +1546,7 @@ naitlb_miss_20:
tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20
update_accessed ptp,pte,t0,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
f_extend pte,t1
@@ -1566,7 +1578,7 @@ dbit_trap_20w:
tlb_lock spc,ptp,pte,t0,t1,dbit_fault
update_dirty ptp,pte,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
idtlbt pte,prot
@@ -1610,7 +1622,7 @@ dbit_trap_20:
tlb_lock spc,ptp,pte,t0,t1,dbit_fault
update_dirty ptp,pte,t1
- make_insert_tlb spc,pte,prot
+ make_insert_tlb spc,pte,prot,t1
f_extend pte,t1
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index e7d6452..75aa0db 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -69,7 +69,7 @@ $bss_loop:
stw,ma %arg2,4(%r1)
stw,ma %arg3,4(%r1)
- /* Initialize startup VM. Just map first 8/16 MB of memory */
+ /* Initialize startup VM. Just map first 16/32 MB of memory */
load32 PA(swapper_pg_dir),%r4
mtctl %r4,%cr24 /* Initialize kernel root pointer */
mtctl %r4,%cr25 /* Initialize user root pointer */
@@ -107,7 +107,7 @@ $bss_loop:
/* Now initialize the PTEs themselves. We use RWX for
* everything ... it will get remapped correctly later */
ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
- ldi (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
+ load32 (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
load32 PA(pg0),%r1
$pgt_fill_loop:
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 64f2764..c99f3dd 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -171,24 +171,6 @@ void pcibios_set_master(struct pci_dev *dev)
}
-void __init pcibios_init_bus(struct pci_bus *bus)
-{
- struct pci_dev *dev = bus->self;
- unsigned short bridge_ctl;
-
- /* We deal only with pci controllers and pci-pci bridges. */
- if (!dev || (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
- return;
-
- /* PCI-PCI bridge - set the cache line and default latency
- (32) for primary and secondary buses. */
- pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
-
- pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl);
- bridge_ctl |= PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR;
- pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl);
-}
-
/*
* pcibios align resources() is called every time generic PCI code
* wants to generate a new address. The process of looking for
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index 72a3c65..f7ea626 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -130,7 +130,16 @@ void __init setup_arch(char **cmdline_p)
printk(KERN_INFO "The 32-bit Kernel has started...\n");
#endif
- printk(KERN_INFO "Default page size is %dKB.\n", (int)(PAGE_SIZE / 1024));
+ printk(KERN_INFO "Kernel default page size is %d KB. Huge pages ",
+ (int)(PAGE_SIZE / 1024));
+#ifdef CONFIG_HUGETLB_PAGE
+ printk(KERN_CONT "enabled with %d MB physical and %d MB virtual size",
+ 1 << (REAL_HPAGE_SHIFT - 20), 1 << (HPAGE_SHIFT - 20));
+#else
+ printk(KERN_CONT "disabled");
+#endif
+ printk(KERN_CONT ".\n");
+
pdc_console_init();
@@ -377,6 +386,7 @@ arch_initcall(parisc_init);
void start_parisc(void)
{
extern void start_kernel(void);
+ extern void early_trap_init(void);
int ret, cpunum;
struct pdc_coproc_cfg coproc_cfg;
@@ -397,6 +407,8 @@ void start_parisc(void)
panic("must have an fpu to boot linux");
}
+ early_trap_init(); /* initialize checksum of fault_vector */
+
start_kernel();
// not reached
}
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index dc1ea79..2264f68 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -435,6 +435,55 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs, int in_syscall)
regs->gr[28]);
}
+/*
+ * Check how the syscall number gets loaded into %r20 within
+ * the delay branch in userspace and adjust as needed.
+ */
+
+static void check_syscallno_in_delay_branch(struct pt_regs *regs)
+{
+ u32 opcode, source_reg;
+ u32 __user *uaddr;
+ int err;
+
+ /* Usually we don't have to restore %r20 (the system call number)
+ * because it gets loaded in the delay slot of the branch external
+ * instruction via the ldi instruction.
+ * In some cases a register-to-register copy instruction might have
+ * been used instead, in which case we need to copy the syscall
+ * number into the source register before returning to userspace.
+ */
+
+ /* A syscall is just a branch, so all we have to do is fiddle the
+ * return pointer so that the ble instruction gets executed again.
+ */
+ regs->gr[31] -= 8; /* delayed branching */
+
+ /* Get assembler opcode of code in delay branch */
+ uaddr = (unsigned int *) ((regs->gr[31] & ~3) + 4);
+ err = get_user(opcode, uaddr);
+ if (err)
+ return;
+
+ /* Check if delay branch uses "ldi int,%r20" */
+ if ((opcode & 0xffff0000) == 0x34140000)
+ return; /* everything ok, just return */
+
+ /* Check if delay branch uses "nop" */
+ if (opcode == INSN_NOP)
+ return;
+
+ /* Check if delay branch uses "copy %rX,%r20" */
+ if ((opcode & 0xffe0ffff) == 0x08000254) {
+ source_reg = (opcode >> 16) & 31;
+ regs->gr[source_reg] = regs->gr[20];
+ return;
+ }
+
+ pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n",
+ current->comm, task_pid_nr(current), opcode);
+}
+
static inline void
syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
{
@@ -457,10 +506,7 @@ syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
}
/* fallthrough */
case -ERESTARTNOINTR:
- /* A syscall is just a branch, so all
- * we have to do is fiddle the return pointer.
- */
- regs->gr[31] -= 8; /* delayed branching */
+ check_syscallno_in_delay_branch(regs);
break;
}
}
@@ -510,15 +556,9 @@ insert_restart_trampoline(struct pt_regs *regs)
}
case -ERESTARTNOHAND:
case -ERESTARTSYS:
- case -ERESTARTNOINTR: {
- /* Hooray for delayed branching. We don't
- * have to restore %r20 (the system call
- * number) because it gets loaded in the delay
- * slot of the branch external instruction.
- */
- regs->gr[31] -= 8;
+ case -ERESTARTNOINTR:
+ check_syscallno_in_delay_branch(regs);
return;
- }
default:
break;
}
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 0b8d26d..3fbd725 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -369,7 +369,7 @@ tracesys_exit:
ldo -16(%r30),%r29 /* Reference param save area */
#endif
ldo TASK_REGS(%r1),%r26
- bl do_syscall_trace_exit,%r2
+ BL do_syscall_trace_exit,%r2
STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
LDREG TI_TASK(%r1), %r1
@@ -390,7 +390,7 @@ tracesys_sigexit:
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- bl do_syscall_trace_exit,%r2
+ BL do_syscall_trace_exit,%r2
ldo TASK_REGS(%r1),%r26
ldil L%syscall_exit_rfi,%r1
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 78c3ef8..d4ffcfb 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -440,6 +440,7 @@
ENTRY_COMP(execveat)
ENTRY_SAME(membarrier)
ENTRY_SAME(userfaultfd)
+ ENTRY_SAME(mlock2) /* 345 */
.ifne (. - 90b) - (__NR_Linux_syscalls * (91b - 90b))
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index b99b39f..553b098 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -807,7 +807,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)
}
-int __init check_ivt(void *iva)
+void __init initialize_ivt(const void *iva)
{
extern u32 os_hpmc_size;
extern const u32 os_hpmc[];
@@ -818,8 +818,8 @@ int __init check_ivt(void *iva)
u32 *hpmcp;
u32 length;
- if (strcmp((char *)iva, "cows can fly"))
- return -1;
+ if (strcmp((const char *)iva, "cows can fly"))
+ panic("IVT invalid");
ivap = (u32 *)iva;
@@ -839,28 +839,23 @@ int __init check_ivt(void *iva)
check += ivap[i];
ivap[5] = -check;
-
- return 0;
}
-#ifndef CONFIG_64BIT
-extern const void fault_vector_11;
-#endif
-extern const void fault_vector_20;
-void __init trap_init(void)
+/* early_trap_init() is called before we set up kernel mappings and
+ * write-protect the kernel */
+void __init early_trap_init(void)
{
- void *iva;
+ extern const void fault_vector_20;
- if (boot_cpu_data.cpu_type >= pcxu)
- iva = (void *) &fault_vector_20;
- else
-#ifdef CONFIG_64BIT
- panic("Can't boot 64-bit OS on PA1.1 processor!");
-#else
- iva = (void *) &fault_vector_11;
+#ifndef CONFIG_64BIT
+ extern const void fault_vector_11;
+ initialize_ivt(&fault_vector_11);
#endif
- if (check_ivt(iva))
- panic("IVT invalid");
+ initialize_ivt(&fault_vector_20);
+}
+
+void __init trap_init(void)
+{
}
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 0dacc5c..308f290 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -60,7 +60,7 @@ SECTIONS
EXIT_DATA
}
PERCPU_SECTION(8)
- . = ALIGN(PAGE_SIZE);
+ . = ALIGN(HUGEPAGE_SIZE);
__init_end = .;
/* freed after init ends here */
@@ -116,7 +116,7 @@ SECTIONS
* that we can properly leave these
* as writable
*/
- . = ALIGN(PAGE_SIZE);
+ . = ALIGN(HUGEPAGE_SIZE);
data_start = .;
EXCEPTION_TABLE(8)
@@ -135,8 +135,11 @@ SECTIONS
_edata = .;
/* BSS */
- BSS_SECTION(PAGE_SIZE, PAGE_SIZE, 8)
+ BSS_SECTION(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE)
+
+ /* bootmap is allocated in setup_bootmem() directly behind bss. */
+ . = ALIGN(HUGEPAGE_SIZE);
_end = . ;
STABS_DEBUG
diff --git a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile
index 758ceef..134393d 100644
--- a/arch/parisc/mm/Makefile
+++ b/arch/parisc/mm/Makefile
@@ -3,3 +3,4 @@
#
obj-y := init.o fault.o ioremap.o
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c
new file mode 100644
index 0000000..f6fdc77
--- /dev/null
+++ b/arch/parisc/mm/hugetlbpage.c
@@ -0,0 +1,161 @@
+/*
+ * PARISC64 Huge TLB page support.
+ *
+ * This parisc implementation is heavily based on the SPARC and x86 code.
+ *
+ * Copyright (C) 2015 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/sysctl.h>
+
+#include <asm/mman.h>
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+
+
+unsigned long
+hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct hstate *h = hstate_file(file);
+
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (flags & MAP_FIXED)
+ if (prepare_hugepage_range(file, addr, len))
+ return -EINVAL;
+
+ if (addr)
+ addr = ALIGN(addr, huge_page_size(h));
+
+ /* we need to make sure the colouring is OK */
+ return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
+
+pte_t *huge_pte_alloc(struct mm_struct *mm,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ /* We must align the address, because our caller will run
+ * set_huge_pte_at() on whatever we return, which writes out
+ * all of the sub-ptes for the hugepage range. So we have
+ * to give it the first such sub-pte.
+ */
+ addr &= HPAGE_MASK;
+
+ pgd = pgd_offset(mm, addr);
+ pud = pud_alloc(mm, pgd, addr);
+ if (pud) {
+ pmd = pmd_alloc(mm, pud, addr);
+ if (pmd)
+ pte = pte_alloc_map(mm, NULL, pmd, addr);
+ }
+ return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ addr &= HPAGE_MASK;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_none(*pgd)) {
+ pud = pud_offset(pgd, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd))
+ pte = pte_offset_map(pmd, addr);
+ }
+ }
+ return pte;
+}
+
+/* Purge data and instruction TLB entries. Must be called holding
+ * the pa_tlb_lock. The TLB purge instructions are slow on SMP
+ * machines since the purge must be broadcast to all CPUs.
+ */
+static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long addr)
+{
+ int i;
+
+ /* We may use multiple physical huge pages (e.g. 2x1 MB) to emulate
+ * Linux standard huge pages (e.g. 2 MB) */
+ BUILD_BUG_ON(REAL_HPAGE_SHIFT > HPAGE_SHIFT);
+
+ addr &= HPAGE_MASK;
+ addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
+
+ for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
+ mtsp(mm->context, 1);
+ pdtlb(addr);
+ if (unlikely(split_tlb))
+ pitlb(addr);
+ addr += (1UL << REAL_HPAGE_SHIFT);
+ }
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
+{
+ unsigned long addr_start;
+ int i;
+
+ addr &= HPAGE_MASK;
+ addr_start = addr;
+
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ /* Directly write pte entry. We could call set_pte_at(mm, addr, ptep, entry)
+ * instead, but then we get double locking on pa_tlb_lock. */
+ *ptep = entry;
+ ptep++;
+
+ /* Drop the PAGE_SIZE/non-huge tlb entry */
+ purge_tlb_entries(mm, addr);
+
+ addr += PAGE_SIZE;
+ pte_val(entry) += PAGE_SIZE;
+ }
+
+ purge_tlb_entries_huge(mm, addr_start);
+}
+
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t entry;
+
+ entry = *ptep;
+ set_huge_pte_at(mm, addr, ptep, __pte(0));
+
+ return entry;
+}
+
+int pmd_huge(pmd_t pmd)
+{
+ return 0;
+}
+
+int pud_huge(pud_t pud)
+{
+ return 0;
+}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index c5fec48..1b366c4 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -409,15 +409,11 @@ static void __init map_pages(unsigned long start_vaddr,
unsigned long vaddr;
unsigned long ro_start;
unsigned long ro_end;
- unsigned long fv_addr;
- unsigned long gw_addr;
- extern const unsigned long fault_vector_20;
- extern void * const linux_gateway_page;
+ unsigned long kernel_end;
ro_start = __pa((unsigned long)_text);
ro_end = __pa((unsigned long)&data_start);
- fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
- gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
+ kernel_end = __pa((unsigned long)&_end);
end_paddr = start_paddr + size;
@@ -475,24 +471,25 @@ static void __init map_pages(unsigned long start_vaddr,
for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
pte_t pte;
- /*
- * Map the fault vector writable so we can
- * write the HPMC checksum.
- */
if (force)
pte = __mk_pte(address, pgprot);
- else if (parisc_text_address(vaddr) &&
- address != fv_addr)
+ else if (parisc_text_address(vaddr)) {
pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+ if (address >= ro_start && address < kernel_end)
+ pte = pte_mkhuge(pte);
+ }
else
#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
- if (address >= ro_start && address < ro_end
- && address != fv_addr
- && address != gw_addr)
- pte = __mk_pte(address, PAGE_KERNEL_RO);
- else
+ if (address >= ro_start && address < ro_end) {
+ pte = __mk_pte(address, PAGE_KERNEL_EXEC);
+ pte = pte_mkhuge(pte);
+ } else
#endif
+ {
pte = __mk_pte(address, pgprot);
+ if (address >= ro_start && address < kernel_end)
+ pte = pte_mkhuge(pte);
+ }
if (address >= end_paddr) {
if (force)
@@ -536,15 +533,12 @@ void free_initmem(void)
/* force the kernel to see the new TLB entries */
__flush_tlb_range(0, init_begin, init_end);
- /* Attempt to catch anyone trying to execute code here
- * by filling the page with BRK insns.
- */
- memset((void *)init_begin, 0x00, init_end - init_begin);
+
/* finally dump all the instructions which were cached, since the
* pages are no-longer executable */
flush_icache_range(init_begin, init_end);
- free_initmem_default(-1);
+ free_initmem_default(POISON_FREE_INITMEM);
/* set up a new led state on systems shipped LED State panel */
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
@@ -728,8 +722,8 @@ static void __init pagetable_init(void)
unsigned long size;
start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
- end_paddr = start_paddr + (pmem_ranges[range].pages << PAGE_SHIFT);
size = pmem_ranges[range].pages << PAGE_SHIFT;
+ end_paddr = start_paddr + size;
map_pages((unsigned long)__va(start_paddr), start_paddr,
size, PAGE_KERNEL, 0);
diff --git a/arch/powerpc/boot/dts/sbc8641d.dts b/arch/powerpc/boot/dts/sbc8641d.dts
index 631ede7..68f0ed7 100644
--- a/arch/powerpc/boot/dts/sbc8641d.dts
+++ b/arch/powerpc/boot/dts/sbc8641d.dts
@@ -227,23 +227,15 @@
reg = <0x520 0x20>;
phy0: ethernet-phy@1f {
- interrupt-parent = <&mpic>;
- interrupts = <10 1>;
reg = <0x1f>;
};
phy1: ethernet-phy@0 {
- interrupt-parent = <&mpic>;
- interrupts = <10 1>;
reg = <0>;
};
phy2: ethernet-phy@1 {
- interrupt-parent = <&mpic>;
- interrupts = <10 1>;
reg = <1>;
};
phy3: ethernet-phy@2 {
- interrupt-parent = <&mpic>;
- interrupts = <10 1>;
reg = <2>;
};
tbi0: tbi-phy@11 {
diff --git a/arch/powerpc/include/asm/barrier.h b/arch/powerpc/include/asm/barrier.h
index 0eca6ef..a7af5fb 100644
--- a/arch/powerpc/include/asm/barrier.h
+++ b/arch/powerpc/include/asm/barrier.h
@@ -34,7 +34,7 @@
#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
#ifdef __SUBARCH_HAS_LWSYNC
# define SMPWMB LWSYNC
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index cfa758c..271fefb 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -50,6 +50,10 @@
#define KVM_NR_IRQCHIPS 1
#define KVM_IRQCHIP_NUM_PINS 256
+/* PPC-specific vcpu->requests bit members */
+#define KVM_REQ_WATCHDOG 8
+#define KVM_REQ_EPR_EXIT 9
+
#include <linux/mmu_notifier.h>
#define KVM_ARCH_WANT_MMU_NOTIFIER
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index a908ada..2220f7a 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -108,6 +108,7 @@
#define MSR_TS_T __MASK(MSR_TS_T_LG) /* Transaction Transactional */
#define MSR_TS_MASK (MSR_TS_T | MSR_TS_S) /* Transaction State bits */
#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
+#define MSR_TM_RESV(x) (((x) & MSR_TS_MASK) == MSR_TS_MASK) /* Reserved */
#define MSR_TM_TRANSACTIONAL(x) (((x) & MSR_TS_MASK) == MSR_TS_T)
#define MSR_TM_SUSPENDED(x) (((x) & MSR_TS_MASK) == MSR_TS_S)
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h
index c9e26cb..5654ece 100644
--- a/arch/powerpc/include/asm/systbl.h
+++ b/arch/powerpc/include/asm/systbl.h
@@ -370,15 +370,16 @@ COMPAT_SYS(execveat)
PPC64ONLY(switch_endian)
SYSCALL_SPU(userfaultfd)
SYSCALL_SPU(membarrier)
-SYSCALL(semop)
-SYSCALL(semget)
-COMPAT_SYS(semctl)
-COMPAT_SYS(semtimedop)
-COMPAT_SYS(msgsnd)
-COMPAT_SYS(msgrcv)
-SYSCALL(msgget)
-COMPAT_SYS(msgctl)
-COMPAT_SYS(shmat)
-SYSCALL(shmdt)
-SYSCALL(shmget)
-COMPAT_SYS(shmctl)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(ni_syscall)
+SYSCALL(mlock2)
diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
index 2a8ebae..b7c20f0 100644
--- a/arch/powerpc/include/asm/uaccess.h
+++ b/arch/powerpc/include/asm/uaccess.h
@@ -274,21 +274,6 @@ do { \
__gu_err; \
})
-#ifndef __powerpc64__
-#define __get_user64_nocheck(x, ptr, size) \
-({ \
- long __gu_err; \
- long long __gu_val; \
- __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
- __chk_user_ptr(ptr); \
- if (!is_kernel_addr((unsigned long)__gu_addr)) \
- might_fault(); \
- __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
- (x) = (__force __typeof__(*(ptr)))__gu_val; \
- __gu_err; \
-})
-#endif /* __powerpc64__ */
-
#define __get_user_check(x, ptr, size) \
({ \
long __gu_err = -EFAULT; \
diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h
index 6d8f802..4b6b8ac 100644
--- a/arch/powerpc/include/asm/unistd.h
+++ b/arch/powerpc/include/asm/unistd.h
@@ -12,7 +12,7 @@
#include <uapi/asm/unistd.h>
-#define __NR_syscalls 378
+#define __NR_syscalls 379
#define __NR__exit __NR_exit
#define NR_syscalls __NR_syscalls
diff --git a/arch/powerpc/include/uapi/asm/unistd.h b/arch/powerpc/include/uapi/asm/unistd.h
index 81579e9..12a0565 100644
--- a/arch/powerpc/include/uapi/asm/unistd.h
+++ b/arch/powerpc/include/uapi/asm/unistd.h
@@ -388,17 +388,6 @@
#define __NR_switch_endian 363
#define __NR_userfaultfd 364
#define __NR_membarrier 365
-#define __NR_semop 366
-#define __NR_semget 367
-#define __NR_semctl 368
-#define __NR_semtimedop 369
-#define __NR_msgsnd 370
-#define __NR_msgrcv 371
-#define __NR_msgget 372
-#define __NR_msgctl 373
-#define __NR_shmat 374
-#define __NR_shmdt 375
-#define __NR_shmget 376
-#define __NR_shmctl 377
+#define __NR_mlock2 378
#endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
diff --git a/arch/powerpc/kernel/eeh_driver.c b/arch/powerpc/kernel/eeh_driver.c
index 80dfe89..8d14feb 100644
--- a/arch/powerpc/kernel/eeh_driver.c
+++ b/arch/powerpc/kernel/eeh_driver.c
@@ -590,16 +590,10 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
eeh_ops->configure_bridge(pe);
eeh_pe_restore_bars(pe);
- /*
- * If it's PHB PE, the frozen state on all available PEs should have
- * been cleared by the PHB reset. Otherwise, we unfreeze the PE and its
- * child PEs because they might be in frozen state.
- */
- if (!(pe->type & EEH_PE_PHB)) {
- rc = eeh_clear_pe_frozen_state(pe, false);
- if (rc)
- return rc;
- }
+ /* Clear frozen state */
+ rc = eeh_clear_pe_frozen_state(pe, false);
+ if (rc)
+ return rc;
/* Give the system 5 seconds to finish running the user-space
* hotplug shutdown scripts, e.g. ifdown for ethernet. Yes,
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 32e2652..0cab9e8 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -27,6 +27,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/kmsg_dump.h>
+#include <linux/pagemap.h>
#include <linux/pstore.h>
#include <linux/zlib.h>
#include <asm/uaccess.h>
@@ -733,24 +734,10 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
{
- int size;
-
if (ppc_md.nvram_size == NULL)
return -ENODEV;
- size = ppc_md.nvram_size();
-
- switch (origin) {
- case 1:
- offset += file->f_pos;
- break;
- case 2:
- offset += size;
- break;
- }
- if (offset < 0)
- return -EINVAL;
- file->f_pos = offset;
- return file->f_pos;
+ return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
+ ppc_md.nvram_size());
}
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 75b6676..646bf4d 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -551,6 +551,24 @@ static void tm_reclaim_thread(struct thread_struct *thr,
msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
}
+ /*
+ * Use the current MSR TM suspended bit to track if we have
+ * checkpointed state outstanding.
+ * On signal delivery, we'd normally reclaim the checkpointed
+ * state to obtain stack pointer (see:get_tm_stackpointer()).
+ * This will then directly return to userspace without going
+ * through __switch_to(). However, if the stack frame is bad,
+ * we need to exit this thread which calls __switch_to() which
+ * will again attempt to reclaim the already saved tm state.
+ * Hence we need to check that we've not already reclaimed
+ * this state.
+ * We do this using the current MSR, rather tracking it in
+ * some specific thread_struct bit, as it has the additional
+ * benifit of checking for a potential TM bad thing exception.
+ */
+ if (!MSR_TM_SUSPENDED(mfmsr()))
+ return;
+
tm_reclaim(thr, thr->regs->msr, cause);
/* Having done the reclaim, we now have the checkpointed
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 0dbee46..ef7c24e 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -875,6 +875,15 @@ static long restore_tm_user_regs(struct pt_regs *regs,
return 1;
#endif /* CONFIG_SPE */
+ /* Get the top half of the MSR from the user context */
+ if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
+ return 1;
+ msr_hi <<= 32;
+ /* If TM bits are set to the reserved value, it's an invalid context */
+ if (MSR_TM_RESV(msr_hi))
+ return 1;
+ /* Pull in the MSR TM bits from the user context */
+ regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr_hi & MSR_TS_MASK);
/* Now, recheckpoint. This loads up all of the checkpointed (older)
* registers, including FP and V[S]Rs. After recheckpointing, the
* transactional versions should be loaded.
@@ -884,11 +893,6 @@ static long restore_tm_user_regs(struct pt_regs *regs,
current->thread.tm_texasr |= TEXASR_FS;
/* This loads the checkpointed FP/VEC state, if used */
tm_recheckpoint(&current->thread, msr);
- /* Get the top half of the MSR */
- if (__get_user(msr_hi, &tm_sr->mc_gregs[PT_MSR]))
- return 1;
- /* Pull in MSR TM from user context */
- regs->msr = (regs->msr & ~MSR_TS_MASK) | ((msr_hi<<32) & MSR_TS_MASK);
/* This loads the speculative FP/VEC state, if used */
if (msr & MSR_FP) {
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 20756df..c676ece 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -438,6 +438,10 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
/* get MSR separately, transfer the LE bit if doing signal return */
err |= __get_user(msr, &sc->gp_regs[PT_MSR]);
+ /* Don't allow reserved mode. */
+ if (MSR_TM_RESV(msr))
+ return -EINVAL;
+
/* pull in MSR TM from user context */
regs->msr = (regs->msr & ~MSR_TS_MASK) | (msr & MSR_TS_MASK);
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 9c26c5a..6b35269 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -224,6 +224,12 @@ static void kvmppc_core_vcpu_put_hv(struct kvm_vcpu *vcpu)
static void kvmppc_set_msr_hv(struct kvm_vcpu *vcpu, u64 msr)
{
+ /*
+ * Check for illegal transactional state bit combination
+ * and if we find it, force the TS field to a safe state.
+ */
+ if ((msr & MSR_TS_MASK) == MSR_TS_MASK)
+ msr &= ~MSR_TS_MASK;
vcpu->arch.shregs.msr = msr;
kvmppc_end_cede(vcpu);
}
@@ -308,16 +314,10 @@ static void kvmppc_dump_regs(struct kvm_vcpu *vcpu)
static struct kvm_vcpu *kvmppc_find_vcpu(struct kvm *kvm, int id)
{
- int r;
- struct kvm_vcpu *v, *ret = NULL;
+ struct kvm_vcpu *ret;
mutex_lock(&kvm->lock);
- kvm_for_each_vcpu(r, v, kvm) {
- if (v->vcpu_id == id) {
- ret = v;
- break;
- }
- }
+ ret = kvm_get_vcpu_by_id(kvm, id);
mutex_unlock(&kvm->lock);
return ret;
}
@@ -2019,7 +2019,7 @@ static bool can_split_piggybacked_subcores(struct core_info *cip)
return false;
n_subcores += (cip->subcore_threads[sub] - 1) >> 1;
}
- if (n_subcores > 3 || large_sub < 0)
+ if (large_sub < 0 || !subcore_config_ok(n_subcores + 1, 2))
return false;
/*
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index b1dab8d..3c6badc 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -1749,7 +1749,8 @@ kvmppc_hdsi:
beq 3f
clrrdi r0, r4, 28
PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */
- bne 1f /* if no SLB entry found */
+ li r0, BOOK3S_INTERRUPT_DATA_SEGMENT
+ bne 7f /* if no SLB entry found */
4: std r4, VCPU_FAULT_DAR(r9)
stw r6, VCPU_FAULT_DSISR(r9)
@@ -1768,14 +1769,15 @@ kvmppc_hdsi:
cmpdi r3, -2 /* MMIO emulation; need instr word */
beq 2f
- /* Synthesize a DSI for the guest */
+ /* Synthesize a DSI (or DSegI) for the guest */
ld r4, VCPU_FAULT_DAR(r9)
mr r6, r3
-1: mtspr SPRN_DAR, r4
+1: li r0, BOOK3S_INTERRUPT_DATA_STORAGE
mtspr SPRN_DSISR, r6
+7: mtspr SPRN_DAR, r4
mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
- li r10, BOOK3S_INTERRUPT_DATA_STORAGE
+ mr r10, r0
bl kvmppc_msr_interrupt
fast_interrupt_c_return:
6: ld r7, VCPU_CTR(r9)
@@ -1823,7 +1825,8 @@ kvmppc_hisi:
beq 3f
clrrdi r0, r10, 28
PPC_SLBFEE_DOT(R5, R0) /* if so, look up SLB */
- bne 1f /* if no SLB entry found */
+ li r0, BOOK3S_INTERRUPT_INST_SEGMENT
+ bne 7f /* if no SLB entry found */
4:
/* Search the hash table. */
mr r3, r9 /* vcpu pointer */
@@ -1840,11 +1843,12 @@ kvmppc_hisi:
cmpdi r3, -1 /* handle in kernel mode */
beq guest_exit_cont
- /* Synthesize an ISI for the guest */
+ /* Synthesize an ISI (or ISegI) for the guest */
mr r11, r3
-1: mtspr SPRN_SRR0, r10
+1: li r0, BOOK3S_INTERRUPT_INST_STORAGE
+7: mtspr SPRN_SRR0, r10
mtspr SPRN_SRR1, r11
- li r10, BOOK3S_INTERRUPT_INST_STORAGE
+ mr r10, r0
bl kvmppc_msr_interrupt
b fast_interrupt_c_return
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index 64891b0..70fb08d 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -512,7 +512,7 @@ static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte)
put_page(hpage);
}
-static int kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
+static bool kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
{
ulong mp_pa = vcpu->arch.magic_page_pa;
@@ -521,7 +521,7 @@ static int kvmppc_visible_gpa(struct kvm_vcpu *vcpu, gpa_t gpa)
gpa &= ~0xFFFULL;
if (unlikely(mp_pa) && unlikely((mp_pa & KVM_PAM) == (gpa & KVM_PAM))) {
- return 1;
+ return true;
}
return kvm_is_visible_gfn(vcpu->kvm, gpa >> PAGE_SHIFT);
diff --git a/arch/powerpc/net/bpf_jit_comp.c b/arch/powerpc/net/bpf_jit_comp.c
index 0478216..2d66a84 100644
--- a/arch/powerpc/net/bpf_jit_comp.c
+++ b/arch/powerpc/net/bpf_jit_comp.c
@@ -78,18 +78,9 @@ static void bpf_jit_build_prologue(struct bpf_prog *fp, u32 *image,
PPC_LI(r_X, 0);
}
- switch (filter[0].code) {
- case BPF_RET | BPF_K:
- case BPF_LD | BPF_W | BPF_LEN:
- case BPF_LD | BPF_W | BPF_ABS:
- case BPF_LD | BPF_H | BPF_ABS:
- case BPF_LD | BPF_B | BPF_ABS:
- /* first instruction sets A register (or is RET 'constant') */
- break;
- default:
- /* make sure we dont leak kernel information to user */
+ /* make sure we dont leak kernel information to user */
+ if (bpf_needs_clear_a(&filter[0]))
PPC_LI(r_A, 0);
- }
}
static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)
diff --git a/arch/powerpc/platforms/powernv/opal-irqchip.c b/arch/powerpc/platforms/powernv/opal-irqchip.c
index 6ccfb6c..e505223b 100644
--- a/arch/powerpc/platforms/powernv/opal-irqchip.c
+++ b/arch/powerpc/platforms/powernv/opal-irqchip.c
@@ -43,11 +43,34 @@ static unsigned int opal_irq_count;
static unsigned int *opal_irqs;
static void opal_handle_irq_work(struct irq_work *work);
-static __be64 last_outstanding_events;
+static u64 last_outstanding_events;
static struct irq_work opal_event_irq_work = {
.func = opal_handle_irq_work,
};
+void opal_handle_events(uint64_t events)
+{
+ int virq, hwirq = 0;
+ u64 mask = opal_event_irqchip.mask;
+
+ if (!in_irq() && (events & mask)) {
+ last_outstanding_events = events;
+ irq_work_queue(&opal_event_irq_work);
+ return;
+ }
+
+ while (events & mask) {
+ hwirq = fls64(events) - 1;
+ if (BIT_ULL(hwirq) & mask) {
+ virq = irq_find_mapping(opal_event_irqchip.domain,
+ hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+ }
+ events &= ~BIT_ULL(hwirq);
+ }
+}
+
static void opal_event_mask(struct irq_data *d)
{
clear_bit(d->hwirq, &opal_event_irqchip.mask);
@@ -55,9 +78,21 @@ static void opal_event_mask(struct irq_data *d)
static void opal_event_unmask(struct irq_data *d)
{
+ __be64 events;
+
set_bit(d->hwirq, &opal_event_irqchip.mask);
- opal_poll_events(&last_outstanding_events);
+ opal_poll_events(&events);
+ last_outstanding_events = be64_to_cpu(events);
+
+ /*
+ * We can't just handle the events now with opal_handle_events().
+ * If we did we would deadlock when opal_event_unmask() is called from
+ * handle_level_irq() with the irq descriptor lock held, because
+ * calling opal_handle_events() would call generic_handle_irq() and
+ * then handle_level_irq() which would try to take the descriptor lock
+ * again. Instead queue the events for later.
+ */
if (last_outstanding_events & opal_event_irqchip.mask)
/* Need to retrigger the interrupt */
irq_work_queue(&opal_event_irq_work);
@@ -96,29 +131,6 @@ static int opal_event_map(struct irq_domain *d, unsigned int irq,
return 0;
}
-void opal_handle_events(uint64_t events)
-{
- int virq, hwirq = 0;
- u64 mask = opal_event_irqchip.mask;
-
- if (!in_irq() && (events & mask)) {
- last_outstanding_events = events;
- irq_work_queue(&opal_event_irq_work);
- return;
- }
-
- while (events & mask) {
- hwirq = fls64(events) - 1;
- if (BIT_ULL(hwirq) & mask) {
- virq = irq_find_mapping(opal_event_irqchip.domain,
- hwirq);
- if (virq)
- generic_handle_irq(virq);
- }
- events &= ~BIT_ULL(hwirq);
- }
-}
-
static irqreturn_t opal_interrupt(int irq, void *data)
{
__be64 events;
@@ -131,7 +143,7 @@ static irqreturn_t opal_interrupt(int irq, void *data)
static void opal_handle_irq_work(struct irq_work *work)
{
- opal_handle_events(be64_to_cpu(last_outstanding_events));
+ opal_handle_events(last_outstanding_events);
}
static int opal_event_match(struct irq_domain *h, struct device_node *node,
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 4296d55..57cffb8 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -278,7 +278,7 @@ static void opal_handle_message(void)
/* Sanity check */
if (type >= OPAL_MSG_TYPE_MAX) {
- pr_warning("%s: Unknown message type: %u\n", __func__, type);
+ pr_warn_once("%s: Unknown message type: %u\n", __func__, type);
return;
}
opal_message_do_notify(type, (void *)&msg);
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c
index d2b79bc..7a399b4 100644
--- a/arch/powerpc/sysdev/axonram.c
+++ b/arch/powerpc/sysdev/axonram.c
@@ -103,7 +103,7 @@ axon_ram_irq_handler(int irq, void *dev)
* axon_ram_make_request - make_request() method for block device
* @queue, @bio: see blk_queue_make_request()
*/
-static void
+static blk_qc_t
axon_ram_make_request(struct request_queue *queue, struct bio *bio)
{
struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
@@ -120,7 +120,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
bio_for_each_segment(vec, bio, iter) {
if (unlikely(phys_mem + vec.bv_len > phys_end)) {
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
user_mem = page_address(vec.bv_page) + vec.bv_offset;
@@ -133,6 +133,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
transfered += vec.bv_len;
}
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
/**
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c
index 610f472..a1ac80b 100644
--- a/arch/powerpc/sysdev/fsl_pci.c
+++ b/arch/powerpc/sysdev/fsl_pci.c
@@ -21,10 +21,12 @@
#include <linux/pci.h>
#include <linux/delay.h>
#include <linux/string.h>
+#include <linux/fsl/edac.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/memblock.h>
#include <linux/log2.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/syscore_ops.h>
@@ -1255,6 +1257,25 @@ void fsl_pcibios_fixup_phb(struct pci_controller *phb)
#endif
}
+static int add_err_dev(struct platform_device *pdev)
+{
+ struct platform_device *errdev;
+ struct mpc85xx_edac_pci_plat_data pd = {
+ .of_node = pdev->dev.of_node
+ };
+
+ errdev = platform_device_register_resndata(&pdev->dev,
+ "mpc85xx-pci-edac",
+ PLATFORM_DEVID_AUTO,
+ pdev->resource,
+ pdev->num_resources,
+ &pd, sizeof(pd));
+ if (IS_ERR(errdev))
+ return PTR_ERR(errdev);
+
+ return 0;
+}
+
static int fsl_pci_probe(struct platform_device *pdev)
{
struct device_node *node;
@@ -1262,8 +1283,13 @@ static int fsl_pci_probe(struct platform_device *pdev)
node = pdev->dev.of_node;
ret = fsl_add_bridge(pdev, fsl_pci_primary == node);
+ if (ret)
+ return ret;
- mpc85xx_pci_err_probe(pdev);
+ ret = add_err_dev(pdev);
+ if (ret)
+ dev_err(&pdev->dev, "couldn't register error device: %d\n",
+ ret);
return 0;
}
diff --git a/arch/powerpc/sysdev/fsl_pci.h b/arch/powerpc/sysdev/fsl_pci.h
index c1cec77..1515885 100644
--- a/arch/powerpc/sysdev/fsl_pci.h
+++ b/arch/powerpc/sysdev/fsl_pci.h
@@ -130,15 +130,6 @@ void fsl_pci_assign_primary(void);
static inline void fsl_pci_assign_primary(void) {}
#endif
-#ifdef CONFIG_EDAC_MPC85XX
-int mpc85xx_pci_err_probe(struct platform_device *op);
-#else
-static inline int mpc85xx_pci_err_probe(struct platform_device *op)
-{
- return -ENOTSUPP;
-}
-#endif
-
#ifdef CONFIG_FSL_PCI
extern int fsl_pci_mcheck_exception(struct pt_regs *);
#else
diff --git a/arch/s390/include/asm/barrier.h b/arch/s390/include/asm/barrier.h
index d68e11e..7ffd0b1 100644
--- a/arch/s390/include/asm/barrier.h
+++ b/arch/s390/include/asm/barrier.h
@@ -36,7 +36,7 @@
#define smp_mb__before_atomic() smp_mb()
#define smp_mb__after_atomic() smp_mb()
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
#define smp_store_release(p, v) \
do { \
diff --git a/arch/s390/include/asm/cio.h b/arch/s390/include/asm/cio.h
index 0c5d8ee..d1e7b0a 100644
--- a/arch/s390/include/asm/cio.h
+++ b/arch/s390/include/asm/cio.h
@@ -312,6 +312,7 @@ extern void css_schedule_reprobe(void);
extern void reipl_ccw_dev(struct ccw_dev_id *id);
struct cio_iplinfo {
+ u8 ssid;
u16 devno;
int is_qdio;
};
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 3ad48f2..08e34a5 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -104,6 +104,9 @@
#define HWCAP_S390_TE 1024
#define HWCAP_S390_VXRS 2048
+/* Internal bits, not exposed via elf */
+#define HWCAP_INT_SIE 1UL
+
/*
* These are used to set parameters in the core dumps.
*/
@@ -169,6 +172,10 @@ extern unsigned int vdso_enabled;
extern unsigned long elf_hwcap;
#define ELF_HWCAP (elf_hwcap)
+/* Internal hardware capabilities, not exposed via elf */
+
+extern unsigned long int_hwcap;
+
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
intent than poking at uname or /proc/cpuinfo.
@@ -206,9 +213,16 @@ do { \
} while (0)
#endif /* CONFIG_COMPAT */
-extern unsigned long mmap_rnd_mask;
-
-#define STACK_RND_MASK (test_thread_flag(TIF_31BIT) ? 0x7ff : mmap_rnd_mask)
+/*
+ * Cache aliasing on the latest machines calls for a mapping granularity
+ * of 512KB. For 64-bit processes use a 512KB alignment and a randomization
+ * of up to 1GB. For 31-bit processes the virtual address space is limited,
+ * use no alignment and limit the randomization to 8MB.
+ */
+#define BRK_RND_MASK (is_32bit_task() ? 0x7ffUL : 0x3ffffUL)
+#define MMAP_RND_MASK (is_32bit_task() ? 0x7ffUL : 0x3ff80UL)
+#define MMAP_ALIGN_MASK (is_32bit_task() ? 0 : 0x7fUL)
+#define STACK_RND_MASK MMAP_RND_MASK
#define ARCH_DLINFO \
do { \
diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h
index 39ae6a3..86634e7 100644
--- a/arch/s390/include/asm/ipl.h
+++ b/arch/s390/include/asm/ipl.h
@@ -64,7 +64,8 @@ struct ipl_block_fcp {
struct ipl_block_ccw {
u8 reserved1[84];
- u8 reserved2[2];
+ u16 reserved2 : 13;
+ u8 ssid : 3;
u16 devno;
u8 vm_flags;
u8 reserved3[3];
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index efaac2c..6742414 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -25,7 +25,9 @@
#include <asm/fpu/api.h>
#include <asm/isc.h>
-#define KVM_MAX_VCPUS 64
+#define KVM_S390_BSCA_CPU_SLOTS 64
+#define KVM_S390_ESCA_CPU_SLOTS 248
+#define KVM_MAX_VCPUS KVM_S390_ESCA_CPU_SLOTS
#define KVM_USER_MEM_SLOTS 32
/*
@@ -37,12 +39,41 @@
#define KVM_IRQCHIP_NUM_PINS 4096
#define KVM_HALT_POLL_NS_DEFAULT 0
+/* s390-specific vcpu->requests bit members */
+#define KVM_REQ_ENABLE_IBS 8
+#define KVM_REQ_DISABLE_IBS 9
+
#define SIGP_CTRL_C 0x80
#define SIGP_CTRL_SCN_MASK 0x3f
-struct sca_entry {
+union bsca_sigp_ctrl {
+ __u8 value;
+ struct {
+ __u8 c : 1;
+ __u8 r : 1;
+ __u8 scn : 6;
+ };
+} __packed;
+
+union esca_sigp_ctrl {
+ __u16 value;
+ struct {
+ __u8 c : 1;
+ __u8 reserved: 7;
+ __u8 scn;
+ };
+} __packed;
+
+struct esca_entry {
+ union esca_sigp_ctrl sigp_ctrl;
+ __u16 reserved1[3];
+ __u64 sda;
+ __u64 reserved2[6];
+} __packed;
+
+struct bsca_entry {
__u8 reserved0;
- __u8 sigp_ctrl;
+ union bsca_sigp_ctrl sigp_ctrl;
__u16 reserved[3];
__u64 sda;
__u64 reserved2[2];
@@ -57,14 +88,22 @@ union ipte_control {
};
};
-struct sca_block {
+struct bsca_block {
union ipte_control ipte_control;
__u64 reserved[5];
__u64 mcn;
__u64 reserved2;
- struct sca_entry cpu[64];
+ struct bsca_entry cpu[KVM_S390_BSCA_CPU_SLOTS];
} __attribute__((packed));
+struct esca_block {
+ union ipte_control ipte_control;
+ __u64 reserved1[7];
+ __u64 mcn[4];
+ __u64 reserved2[20];
+ struct esca_entry cpu[KVM_S390_ESCA_CPU_SLOTS];
+} __packed;
+
#define CPUSTAT_STOPPED 0x80000000
#define CPUSTAT_WAIT 0x10000000
#define CPUSTAT_ECALL_PEND 0x08000000
@@ -182,7 +221,8 @@ struct kvm_s390_sie_block {
__u64 pp; /* 0x01de */
__u8 reserved1e6[2]; /* 0x01e6 */
__u64 itdba; /* 0x01e8 */
- __u8 reserved1f0[16]; /* 0x01f0 */
+ __u64 riccbd; /* 0x01f0 */
+ __u8 reserved1f8[8]; /* 0x01f8 */
} __attribute__((packed));
struct kvm_s390_itdb {
@@ -585,11 +625,14 @@ struct kvm_s390_crypto_cb {
};
struct kvm_arch{
- struct sca_block *sca;
+ void *sca;
+ int use_esca;
+ rwlock_t sca_lock;
debug_info_t *dbf;
struct kvm_s390_float_interrupt float_int;
struct kvm_device *flic;
struct gmap *gmap;
+ unsigned long mem_limit;
int css_support;
int use_irqchip;
int use_cmma;
diff --git a/arch/s390/include/asm/pci_dma.h b/arch/s390/include/asm/pci_dma.h
index 7a7abf1..1aac41e 100644
--- a/arch/s390/include/asm/pci_dma.h
+++ b/arch/s390/include/asm/pci_dma.h
@@ -195,5 +195,7 @@ void zpci_dma_exit_device(struct zpci_dev *);
void dma_free_seg_table(unsigned long);
unsigned long *dma_alloc_cpu_table(void);
void dma_cleanup_tables(unsigned long *);
-void dma_update_cpu_trans(unsigned long *, void *, dma_addr_t, int);
+unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr);
+void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags);
+
#endif
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h
index 821dde5..dea883f 100644
--- a/arch/s390/include/asm/sclp.h
+++ b/arch/s390/include/asm/sclp.h
@@ -29,7 +29,10 @@ struct sclp_ipl_info {
struct sclp_core_entry {
u8 core_id;
- u8 reserved0[2];
+ u8 reserved0;
+ u8 : 4;
+ u8 sief2 : 1;
+ u8 : 3;
u8 : 3;
u8 siif : 1;
u8 sigpif : 1;
@@ -53,6 +56,9 @@ struct sclp_info {
unsigned char has_sigpif : 1;
unsigned char has_core_type : 1;
unsigned char has_sprp : 1;
+ unsigned char has_hvs : 1;
+ unsigned char has_esca : 1;
+ unsigned char has_sief2 : 1;
unsigned int ibc;
unsigned int mtid;
unsigned int mtid_cp;
diff --git a/arch/s390/include/asm/trace/diag.h b/arch/s390/include/asm/trace/diag.h
index 776f307..cc6cfe7 100644
--- a/arch/s390/include/asm/trace/diag.h
+++ b/arch/s390/include/asm/trace/diag.h
@@ -19,7 +19,7 @@
#define TRACE_INCLUDE_PATH asm/trace
#define TRACE_INCLUDE_FILE diag
-TRACE_EVENT(diagnose,
+TRACE_EVENT(s390_diagnose,
TP_PROTO(unsigned short nr),
TP_ARGS(nr),
TP_STRUCT__entry(
@@ -32,9 +32,9 @@ TRACE_EVENT(diagnose,
);
#ifdef CONFIG_TRACEPOINTS
-void trace_diagnose_norecursion(int diag_nr);
+void trace_s390_diagnose_norecursion(int diag_nr);
#else
-static inline void trace_diagnose_norecursion(int diag_nr) { }
+static inline void trace_s390_diagnose_norecursion(int diag_nr) { }
#endif
#endif /* _TRACE_S390_DIAG_H */
diff --git a/arch/s390/include/uapi/asm/kvm.h b/arch/s390/include/uapi/asm/kvm.h
index ef1a5fc..fe84bd5 100644
--- a/arch/s390/include/uapi/asm/kvm.h
+++ b/arch/s390/include/uapi/asm/kvm.h
@@ -66,6 +66,8 @@ struct kvm_s390_io_adapter_req {
#define KVM_S390_VM_MEM_CLR_CMMA 1
#define KVM_S390_VM_MEM_LIMIT_SIZE 2
+#define KVM_S390_NO_MEM_LIMIT U64_MAX
+
/* kvm attributes for KVM_S390_VM_TOD */
#define KVM_S390_VM_TOD_LOW 0
#define KVM_S390_VM_TOD_HIGH 1
@@ -151,6 +153,7 @@ struct kvm_guest_debug_arch {
#define KVM_SYNC_ARCH0 (1UL << 4)
#define KVM_SYNC_PFAULT (1UL << 5)
#define KVM_SYNC_VRS (1UL << 6)
+#define KVM_SYNC_RICCB (1UL << 7)
/* definition of registers in kvm_run */
struct kvm_sync_regs {
__u64 prefix; /* prefix register */
@@ -168,6 +171,8 @@ struct kvm_sync_regs {
__u64 vrs[32][2]; /* vector registers */
__u8 reserved[512]; /* for future vector expansion */
__u32 fpc; /* only valid with vector registers */
+ __u8 padding[52]; /* riccb needs to be 64byte aligned */
+ __u8 riccb[64]; /* runtime instrumentation controls block */
};
#define KVM_REG_S390_TODPR (KVM_REG_S390 | KVM_REG_SIZE_U32 | 0x1)
diff --git a/arch/s390/include/uapi/asm/unistd.h b/arch/s390/include/uapi/asm/unistd.h
index a848adb..34ec202 100644
--- a/arch/s390/include/uapi/asm/unistd.h
+++ b/arch/s390/include/uapi/asm/unistd.h
@@ -192,14 +192,14 @@
#define __NR_set_tid_address 252
#define __NR_fadvise64 253
#define __NR_timer_create 254
-#define __NR_timer_settime (__NR_timer_create+1)
-#define __NR_timer_gettime (__NR_timer_create+2)
-#define __NR_timer_getoverrun (__NR_timer_create+3)
-#define __NR_timer_delete (__NR_timer_create+4)
-#define __NR_clock_settime (__NR_timer_create+5)
-#define __NR_clock_gettime (__NR_timer_create+6)
-#define __NR_clock_getres (__NR_timer_create+7)
-#define __NR_clock_nanosleep (__NR_timer_create+8)
+#define __NR_timer_settime 255
+#define __NR_timer_gettime 256
+#define __NR_timer_getoverrun 257
+#define __NR_timer_delete 258
+#define __NR_clock_settime 259
+#define __NR_clock_gettime 260
+#define __NR_clock_getres 261
+#define __NR_clock_nanosleep 262
/* Number 263 is reserved for vserver */
#define __NR_statfs64 265
#define __NR_fstatfs64 266
@@ -309,7 +309,8 @@
#define __NR_recvfrom 371
#define __NR_recvmsg 372
#define __NR_shutdown 373
-#define NR_syscalls 374
+#define __NR_mlock2 374
+#define NR_syscalls 375
/*
* There are some system calls that are not present on 64 bit, some
diff --git a/arch/s390/kernel/compat_wrapper.c b/arch/s390/kernel/compat_wrapper.c
index 09f1940..fac4eed 100644
--- a/arch/s390/kernel/compat_wrapper.c
+++ b/arch/s390/kernel/compat_wrapper.c
@@ -176,3 +176,4 @@ COMPAT_SYSCALL_WRAP4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr,
COMPAT_SYSCALL_WRAP3(getsockname, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len);
COMPAT_SYSCALL_WRAP3(getpeername, int, fd, struct sockaddr __user *, usockaddr, int __user *, usockaddr_len);
COMPAT_SYSCALL_WRAP6(sendto, int, fd, void __user *, buff, size_t, len, unsigned int, flags, struct sockaddr __user *, addr, int, addr_len);
+COMPAT_SYSCALL_WRAP3(mlock2, unsigned long, start, size_t, len, int, flags);
diff --git a/arch/s390/kernel/diag.c b/arch/s390/kernel/diag.c
index f98766e..48b37b8 100644
--- a/arch/s390/kernel/diag.c
+++ b/arch/s390/kernel/diag.c
@@ -121,14 +121,14 @@ device_initcall(show_diag_stat_init);
void diag_stat_inc(enum diag_stat_enum nr)
{
this_cpu_inc(diag_stat.counter[nr]);
- trace_diagnose(diag_map[nr].code);
+ trace_s390_diagnose(diag_map[nr].code);
}
EXPORT_SYMBOL(diag_stat_inc);
void diag_stat_inc_norecursion(enum diag_stat_enum nr)
{
this_cpu_inc(diag_stat.counter[nr]);
- trace_diagnose_norecursion(diag_map[nr].code);
+ trace_s390_diagnose_norecursion(diag_map[nr].code);
}
EXPORT_SYMBOL(diag_stat_inc_norecursion);
diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c
index 8140d10..6e72961 100644
--- a/arch/s390/kernel/dis.c
+++ b/arch/s390/kernel/dis.c
@@ -1920,16 +1920,23 @@ static int print_insn(char *buffer, unsigned char *code, unsigned long addr)
}
if (separator)
ptr += sprintf(ptr, "%c", separator);
+ /*
+ * Use four '%' characters below because of the
+ * following two conversions:
+ *
+ * 1) sprintf: %%%%r -> %%r
+ * 2) printk : %%r -> %r
+ */
if (operand->flags & OPERAND_GPR)
- ptr += sprintf(ptr, "%%r%i", value);
+ ptr += sprintf(ptr, "%%%%r%i", value);
else if (operand->flags & OPERAND_FPR)
- ptr += sprintf(ptr, "%%f%i", value);
+ ptr += sprintf(ptr, "%%%%f%i", value);
else if (operand->flags & OPERAND_AR)
- ptr += sprintf(ptr, "%%a%i", value);
+ ptr += sprintf(ptr, "%%%%a%i", value);
else if (operand->flags & OPERAND_CR)
- ptr += sprintf(ptr, "%%c%i", value);
+ ptr += sprintf(ptr, "%%%%c%i", value);
else if (operand->flags & OPERAND_VR)
- ptr += sprintf(ptr, "%%v%i", value);
+ ptr += sprintf(ptr, "%%%%v%i", value);
else if (operand->flags & OPERAND_PCREL)
ptr += sprintf(ptr, "%lx", (signed int) value
+ addr);
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 1255c6c..301ee9c 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -26,6 +26,7 @@
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/page.h>
+#include <asm/ptrace.h>
#define ARCH_OFFSET 4
@@ -59,19 +60,6 @@ __HEAD
.long 0x020006e0,0x20000050
.org 0x200
-#
-# subroutine to set architecture mode
-#
-.Lsetmode:
- mvi __LC_AR_MODE_ID,1 # set esame flag
- slr %r0,%r0 # set cpuid to zero
- lhi %r1,2 # mode 2 = esame (dump)
- sigp %r1,%r0,0x12 # switch to esame mode
- bras %r13,0f
- .fill 16,4,0x0
-0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
- sam31 # switch to 31 bit addressing mode
- br %r14
#
# subroutine to wait for end I/O
@@ -159,7 +147,14 @@ __HEAD
.long 0x02200050,0x00000000
iplstart:
- bas %r14,.Lsetmode # Immediately switch to 64 bit mode
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ lhi %r1,2 # mode 2 = esame (dump)
+ sigp %r1,%r0,0x12 # switch to esame mode
+ bras %r13,0f
+ .fill 16,4,0x0
+0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
+ sam31 # switch to 31 bit addressing mode
lh %r1,0xb8 # test if subchannel number
bct %r1,.Lnoload # is valid
l %r1,0xb8 # load ipl subchannel number
@@ -269,71 +264,6 @@ iplstart:
.Lcpuid:.fill 8,1,0
#
-# SALIPL loader support. Based on a patch by Rob van der Heij.
-# This entry point is called directly from the SALIPL loader and
-# doesn't need a builtin ipl record.
-#
- .org 0x800
-ENTRY(start)
- stm %r0,%r15,0x07b0 # store registers
- bas %r14,.Lsetmode # Immediately switch to 64 bit mode
- basr %r12,%r0
-.base:
- l %r11,.parm
- l %r8,.cmd # pointer to command buffer
-
- ltr %r9,%r9 # do we have SALIPL parameters?
- bp .sk8x8
-
- mvc 0(64,%r8),0x00b0 # copy saved registers
- xc 64(240-64,%r8),0(%r8) # remainder of buffer
- tr 0(64,%r8),.lowcase
- b .gotr
-.sk8x8:
- mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
-.gotr:
- slr %r0,%r0
- st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
- st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
- j startup # continue with startup
-.cmd: .long COMMAND_LINE # address of command line buffer
-.parm: .long PARMAREA
-.lowcase:
- .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
- .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
- .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
- .byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
- .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
- .byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
- .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
- .byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
- .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
- .byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
- .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
- .byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
- .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
- .byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
- .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
- .byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
-
- .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
- .byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
- .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
- .byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
- .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
- .byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
- .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
- .byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
- .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
- .byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
- .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
- .byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
- .byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
- .byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
- .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
- .byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
-
-#
# startup-code at 0x10000, running in absolute addressing mode
# this is called either by the ipl loader or directly by PSW restart
# or linload or SALIPL
@@ -364,7 +294,7 @@ ENTRY(startup_kdump)
bras %r13,0f
.fill 16,4,0x0
0: lmh %r0,%r15,0(%r13) # clear high-order half of gprs
- sam31 # switch to 31 bit addressing mode
+ sam64 # switch to 64 bit addressing mode
basr %r13,0 # get base
.LPG0:
xc 0x200(256),0x200 # partially clear lowcore
@@ -395,7 +325,7 @@ ENTRY(startup_kdump)
jnz 1b
j 4f
2: l %r15,.Lstack-.LPG0(%r13)
- ahi %r15,-96
+ ahi %r15,-STACK_FRAME_OVERHEAD
la %r2,.Lals_string-.LPG0(%r13)
l %r3,.Lsclp_print-.LPG0(%r13)
basr %r14,%r3
@@ -429,8 +359,7 @@ ENTRY(startup_kdump)
.long 1, 0xc0000000
#endif
4:
- /* Continue with 64bit startup code in head64.S */
- sam64 # switch to 64 bit mode
+ /* Continue with startup code in head64.S */
jg startup_continue
.align 8
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index f6d8acd..b1f0a90 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -121,6 +121,7 @@ static char *dump_type_str(enum dump_type type)
* Must be in data section since the bss section
* is not cleared when these are accessed.
*/
+static u8 ipl_ssid __attribute__((__section__(".data"))) = 0;
static u16 ipl_devno __attribute__((__section__(".data"))) = 0;
u32 ipl_flags __attribute__((__section__(".data"))) = 0;
@@ -197,6 +198,33 @@ static ssize_t sys_##_prefix##_##_name##_show(struct kobject *kobj, \
return snprintf(page, PAGE_SIZE, _format, ##args); \
}
+#define IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk) \
+static ssize_t sys_##_prefix##_##_name##_store(struct kobject *kobj, \
+ struct kobj_attribute *attr, \
+ const char *buf, size_t len) \
+{ \
+ unsigned long long ssid, devno; \
+ \
+ if (sscanf(buf, "0.%llx.%llx\n", &ssid, &devno) != 2) \
+ return -EINVAL; \
+ \
+ if (ssid > __MAX_SSID || devno > __MAX_SUBCHANNEL) \
+ return -EINVAL; \
+ \
+ _ipl_blk.ssid = ssid; \
+ _ipl_blk.devno = devno; \
+ return len; \
+}
+
+#define DEFINE_IPL_CCW_ATTR_RW(_prefix, _name, _ipl_blk) \
+IPL_ATTR_SHOW_FN(_prefix, _name, "0.%x.%04x\n", \
+ _ipl_blk.ssid, _ipl_blk.devno); \
+IPL_ATTR_CCW_STORE_FN(_prefix, _name, _ipl_blk); \
+static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
+ __ATTR(_name, (S_IRUGO | S_IWUSR), \
+ sys_##_prefix##_##_name##_show, \
+ sys_##_prefix##_##_name##_store) \
+
#define DEFINE_IPL_ATTR_RO(_prefix, _name, _format, _value) \
IPL_ATTR_SHOW_FN(_prefix, _name, _format, _value) \
static struct kobj_attribute sys_##_prefix##_##_name##_attr = \
@@ -395,7 +423,7 @@ static ssize_t sys_ipl_device_show(struct kobject *kobj,
switch (ipl_info.type) {
case IPL_TYPE_CCW:
- return sprintf(page, "0.0.%04x\n", ipl_devno);
+ return sprintf(page, "0.%x.%04x\n", ipl_ssid, ipl_devno);
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
return sprintf(page, "0.0.%04x\n", ipl->ipl_info.fcp.devno);
@@ -687,21 +715,14 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
+ size_t scpdata_len = count;
size_t padding;
- size_t scpdata_len;
-
- if (off < 0)
- return -EINVAL;
- if (off >= DIAG308_SCPDATA_SIZE)
- return -ENOSPC;
- if (count > DIAG308_SCPDATA_SIZE - off)
- count = DIAG308_SCPDATA_SIZE - off;
-
- memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf + off, count);
- scpdata_len = off + count;
+ if (off)
+ return -EINVAL;
+ memcpy(reipl_block_fcp->ipl_info.fcp.scp_data, buf, count);
if (scpdata_len % 8) {
padding = 8 - (scpdata_len % 8);
memset(reipl_block_fcp->ipl_info.fcp.scp_data + scpdata_len,
@@ -717,7 +738,7 @@ static ssize_t reipl_fcp_scpdata_write(struct file *filp, struct kobject *kobj,
}
static struct bin_attribute sys_reipl_fcp_scp_data_attr =
__BIN_ATTR(scp_data, (S_IRUGO | S_IWUSR), reipl_fcp_scpdata_read,
- reipl_fcp_scpdata_write, PAGE_SIZE);
+ reipl_fcp_scpdata_write, DIAG308_SCPDATA_SIZE);
static struct bin_attribute *reipl_fcp_bin_attrs[] = {
&sys_reipl_fcp_scp_data_attr,
@@ -814,9 +835,7 @@ static struct attribute_group reipl_fcp_attr_group = {
};
/* CCW reipl device attributes */
-
-DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
- reipl_block_ccw->ipl_info.ccw.devno);
+DEFINE_IPL_CCW_ATTR_RW(reipl_ccw, device, reipl_block_ccw->ipl_info.ccw);
/* NSS wrapper */
static ssize_t reipl_nss_loadparm_show(struct kobject *kobj,
@@ -1056,8 +1075,8 @@ static void __reipl_run(void *unused)
switch (reipl_method) {
case REIPL_METHOD_CCW_CIO:
+ devid.ssid = reipl_block_ccw->ipl_info.ccw.ssid;
devid.devno = reipl_block_ccw->ipl_info.ccw.devno;
- devid.ssid = 0;
reipl_ccw_dev(&devid);
break;
case REIPL_METHOD_CCW_VM:
@@ -1192,6 +1211,7 @@ static int __init reipl_ccw_init(void)
reipl_block_ccw_init(reipl_block_ccw);
if (ipl_info.type == IPL_TYPE_CCW) {
+ reipl_block_ccw->ipl_info.ccw.ssid = ipl_ssid;
reipl_block_ccw->ipl_info.ccw.devno = ipl_devno;
reipl_block_ccw_fill_parms(reipl_block_ccw);
}
@@ -1336,9 +1356,7 @@ static struct attribute_group dump_fcp_attr_group = {
};
/* CCW dump device attributes */
-
-DEFINE_IPL_ATTR_RW(dump_ccw, device, "0.0.%04llx\n", "0.0.%llx\n",
- dump_block_ccw->ipl_info.ccw.devno);
+DEFINE_IPL_CCW_ATTR_RW(dump_ccw, device, dump_block_ccw->ipl_info.ccw);
static struct attribute *dump_ccw_attrs[] = {
&sys_dump_ccw_device_attr.attr,
@@ -1418,8 +1436,8 @@ static void __dump_run(void *unused)
switch (dump_method) {
case DUMP_METHOD_CCW_CIO:
+ devid.ssid = dump_block_ccw->ipl_info.ccw.ssid;
devid.devno = dump_block_ccw->ipl_info.ccw.devno;
- devid.ssid = 0;
reipl_ccw_dev(&devid);
break;
case DUMP_METHOD_CCW_VM:
@@ -1939,14 +1957,14 @@ void __init setup_ipl(void)
ipl_info.type = get_ipl_type();
switch (ipl_info.type) {
case IPL_TYPE_CCW:
+ ipl_info.data.ccw.dev_id.ssid = ipl_ssid;
ipl_info.data.ccw.dev_id.devno = ipl_devno;
- ipl_info.data.ccw.dev_id.ssid = 0;
break;
case IPL_TYPE_FCP:
case IPL_TYPE_FCP_DUMP:
+ ipl_info.data.fcp.dev_id.ssid = 0;
ipl_info.data.fcp.dev_id.devno =
IPL_PARMBLOCK_START->ipl_info.fcp.devno;
- ipl_info.data.fcp.dev_id.ssid = 0;
ipl_info.data.fcp.wwpn = IPL_PARMBLOCK_START->ipl_info.fcp.wwpn;
ipl_info.data.fcp.lun = IPL_PARMBLOCK_START->ipl_info.fcp.lun;
break;
@@ -1978,6 +1996,7 @@ void __init ipl_save_parameters(void)
if (cio_get_iplinfo(&iplinfo))
return;
+ ipl_ssid = iplinfo.ssid;
ipl_devno = iplinfo.devno;
ipl_flags |= IPL_DEVNO_VALID;
if (!iplinfo.is_qdio)
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 688a3aa..114ee8b 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -243,11 +243,7 @@ unsigned long arch_align_stack(unsigned long sp)
static inline unsigned long brk_rnd(void)
{
- /* 8MB for 32bit, 1GB for 64bit */
- if (is_32bit_task())
- return (get_random_int() & 0x7ffUL) << PAGE_SHIFT;
- else
- return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT;
+ return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT;
}
unsigned long arch_randomize_brk(struct mm_struct *mm)
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index 7ce00e7..647128d 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -61,6 +61,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
"edat", "etf3eh", "highgprs", "te", "vx"
};
+ static const char * const int_hwcap_str[] = {
+ "sie"
+ };
unsigned long n = (unsigned long) v - 1;
int i;
@@ -75,6 +78,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
for (i = 0; i < ARRAY_SIZE(hwcap_str); i++)
if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
seq_printf(m, "%s ", hwcap_str[i]);
+ for (i = 0; i < ARRAY_SIZE(int_hwcap_str); i++)
+ if (int_hwcap_str[i] && (int_hwcap & (1UL << i)))
+ seq_printf(m, "%s ", int_hwcap_str[i]);
seq_puts(m, "\n");
show_cacheinfo(m);
}
diff --git a/arch/s390/kernel/sclp.c b/arch/s390/kernel/sclp.c
index fa0bdff..9fe7781 100644
--- a/arch/s390/kernel/sclp.c
+++ b/arch/s390/kernel/sclp.c
@@ -21,7 +21,7 @@ static void _sclp_wait_int(void)
__ctl_load(cr0_new, 0, 0);
psw_ext_save = S390_lowcore.external_new_psw;
- psw_mask = __extract_psw() & (PSW_MASK_EA | PSW_MASK_BA);
+ psw_mask = __extract_psw();
S390_lowcore.external_new_psw.mask = psw_mask;
psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
S390_lowcore.ext_int_code = 0;
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index ce0cbd6..dc83ae6 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -80,6 +80,8 @@ EXPORT_SYMBOL(console_irq);
unsigned long elf_hwcap __read_mostly = 0;
char elf_platform[ELF_PLATFORM_SIZE];
+unsigned long int_hwcap = 0;
+
int __initdata memory_end_set;
unsigned long __initdata memory_end;
unsigned long __initdata max_physmem_end;
@@ -764,9 +766,6 @@ static int __init setup_hwcaps(void)
get_cpu_id(&cpu_id);
add_device_randomness(&cpu_id, sizeof(cpu_id));
switch (cpu_id.machine) {
- case 0x9672:
- strcpy(elf_platform, "g5");
- break;
case 0x2064:
case 0x2066:
default: /* Use "z900" as default for 64 bit kernels. */
@@ -796,6 +795,13 @@ static int __init setup_hwcaps(void)
strcpy(elf_platform, "z13");
break;
}
+
+ /*
+ * Virtualization support HWCAP_INT_SIE is bit 0.
+ */
+ if (sclp.has_sief2)
+ int_hwcap |= HWCAP_INT_SIE;
+
return 0;
}
arch_initcall(setup_hwcaps);
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 8c56929..5378c3e 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -382,3 +382,4 @@ SYSCALL(sys_sendmsg,compat_sys_sendmsg) /* 370 */
SYSCALL(sys_recvfrom,compat_sys_recvfrom)
SYSCALL(sys_recvmsg,compat_sys_recvmsg)
SYSCALL(sys_shutdown,sys_shutdown)
+SYSCALL(sys_mlock2,compat_sys_mlock2)
diff --git a/arch/s390/kernel/trace.c b/arch/s390/kernel/trace.c
index 73239bb..21a5df9 100644
--- a/arch/s390/kernel/trace.c
+++ b/arch/s390/kernel/trace.c
@@ -9,11 +9,11 @@
#define CREATE_TRACE_POINTS
#include <asm/trace/diag.h>
-EXPORT_TRACEPOINT_SYMBOL(diagnose);
+EXPORT_TRACEPOINT_SYMBOL(s390_diagnose);
static DEFINE_PER_CPU(unsigned int, diagnose_trace_depth);
-void trace_diagnose_norecursion(int diag_nr)
+void trace_s390_diagnose_norecursion(int diag_nr)
{
unsigned long flags;
unsigned int *depth;
@@ -22,7 +22,7 @@ void trace_diagnose_norecursion(int diag_nr)
depth = this_cpu_ptr(&diagnose_trace_depth);
if (*depth == 0) {
(*depth)++;
- trace_diagnose(diag_nr);
+ trace_s390_diagnose(diag_nr);
(*depth)--;
}
local_irq_restore(flags);
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 5fbfb88..05f7de9 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -155,10 +155,8 @@ static int __diag_time_slice_end(struct kvm_vcpu *vcpu)
static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
{
- struct kvm *kvm = vcpu->kvm;
struct kvm_vcpu *tcpu;
int tid;
- int i;
tid = vcpu->run->s.regs.gprs[(vcpu->arch.sie_block->ipa & 0xf0) >> 4];
vcpu->stat.diagnose_9c++;
@@ -167,12 +165,9 @@ static int __diag_time_slice_end_directed(struct kvm_vcpu *vcpu)
if (tid == vcpu->vcpu_id)
return 0;
- kvm_for_each_vcpu(i, tcpu, kvm)
- if (tcpu->vcpu_id == tid) {
- kvm_vcpu_yield_to(tcpu);
- break;
- }
-
+ tcpu = kvm_get_vcpu_by_id(vcpu->kvm, tid);
+ if (tcpu)
+ kvm_vcpu_yield_to(tcpu);
return 0;
}
diff --git a/arch/s390/kvm/gaccess.c b/arch/s390/kvm/gaccess.c
index a7559f7..d30db40 100644
--- a/arch/s390/kvm/gaccess.c
+++ b/arch/s390/kvm/gaccess.c
@@ -259,10 +259,14 @@ struct aste {
int ipte_lock_held(struct kvm_vcpu *vcpu)
{
- union ipte_control *ic = &vcpu->kvm->arch.sca->ipte_control;
+ if (vcpu->arch.sie_block->eca & 1) {
+ int rc;
- if (vcpu->arch.sie_block->eca & 1)
- return ic->kh != 0;
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ rc = kvm_s390_get_ipte_control(vcpu->kvm)->kh != 0;
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+ return rc;
+ }
return vcpu->kvm->arch.ipte_lock_count != 0;
}
@@ -274,16 +278,20 @@ static void ipte_lock_simple(struct kvm_vcpu *vcpu)
vcpu->kvm->arch.ipte_lock_count++;
if (vcpu->kvm->arch.ipte_lock_count > 1)
goto out;
- ic = &vcpu->kvm->arch.sca->ipte_control;
+retry:
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ ic = kvm_s390_get_ipte_control(vcpu->kvm);
do {
old = READ_ONCE(*ic);
- while (old.k) {
+ if (old.k) {
+ read_unlock(&vcpu->kvm->arch.sca_lock);
cond_resched();
- old = READ_ONCE(*ic);
+ goto retry;
}
new = old;
new.k = 1;
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+ read_unlock(&vcpu->kvm->arch.sca_lock);
out:
mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
}
@@ -296,12 +304,14 @@ static void ipte_unlock_simple(struct kvm_vcpu *vcpu)
vcpu->kvm->arch.ipte_lock_count--;
if (vcpu->kvm->arch.ipte_lock_count)
goto out;
- ic = &vcpu->kvm->arch.sca->ipte_control;
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ ic = kvm_s390_get_ipte_control(vcpu->kvm);
do {
old = READ_ONCE(*ic);
new = old;
new.k = 0;
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+ read_unlock(&vcpu->kvm->arch.sca_lock);
wake_up(&vcpu->kvm->arch.ipte_wq);
out:
mutex_unlock(&vcpu->kvm->arch.ipte_mutex);
@@ -311,24 +321,29 @@ static void ipte_lock_siif(struct kvm_vcpu *vcpu)
{
union ipte_control old, new, *ic;
- ic = &vcpu->kvm->arch.sca->ipte_control;
+retry:
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ ic = kvm_s390_get_ipte_control(vcpu->kvm);
do {
old = READ_ONCE(*ic);
- while (old.kg) {
+ if (old.kg) {
+ read_unlock(&vcpu->kvm->arch.sca_lock);
cond_resched();
- old = READ_ONCE(*ic);
+ goto retry;
}
new = old;
new.k = 1;
new.kh++;
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+ read_unlock(&vcpu->kvm->arch.sca_lock);
}
static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
{
union ipte_control old, new, *ic;
- ic = &vcpu->kvm->arch.sca->ipte_control;
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ ic = kvm_s390_get_ipte_control(vcpu->kvm);
do {
old = READ_ONCE(*ic);
new = old;
@@ -336,6 +351,7 @@ static void ipte_unlock_siif(struct kvm_vcpu *vcpu)
if (!new.kh)
new.k = 0;
} while (cmpxchg(&ic->val, old.val, new.val) != old.val);
+ read_unlock(&vcpu->kvm->arch.sca_lock);
if (!new.kh)
wake_up(&vcpu->kvm->arch.ipte_wq);
}
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index b4a5aa1..d53c107 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -54,9 +54,6 @@ void kvm_s390_rewind_psw(struct kvm_vcpu *vcpu, int ilc)
static int handle_noop(struct kvm_vcpu *vcpu)
{
switch (vcpu->arch.sie_block->icptcode) {
- case 0x0:
- vcpu->stat.exit_null++;
- break;
case 0x10:
vcpu->stat.exit_external_request++;
break;
@@ -338,8 +335,10 @@ static int handle_partial_execution(struct kvm_vcpu *vcpu)
int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
{
+ if (kvm_is_ucontrol(vcpu->kvm))
+ return -EOPNOTSUPP;
+
switch (vcpu->arch.sie_block->icptcode) {
- case 0x00:
case 0x10:
case 0x18:
return handle_noop(vcpu);
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 373e323..62ec925 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -34,6 +34,106 @@
#define PFAULT_DONE 0x0680
#define VIRTIO_PARAM 0x0d00
+/* handle external calls via sigp interpretation facility */
+static int sca_ext_call_pending(struct kvm_vcpu *vcpu, int *src_id)
+{
+ int c, scn;
+
+ if (!(atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND))
+ return 0;
+
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ if (vcpu->kvm->arch.use_esca) {
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+ union esca_sigp_ctrl sigp_ctrl =
+ sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+
+ c = sigp_ctrl.c;
+ scn = sigp_ctrl.scn;
+ } else {
+ struct bsca_block *sca = vcpu->kvm->arch.sca;
+ union bsca_sigp_ctrl sigp_ctrl =
+ sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+
+ c = sigp_ctrl.c;
+ scn = sigp_ctrl.scn;
+ }
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+
+ if (src_id)
+ *src_id = scn;
+
+ return c;
+}
+
+static int sca_inject_ext_call(struct kvm_vcpu *vcpu, int src_id)
+{
+ int expect, rc;
+
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ if (vcpu->kvm->arch.use_esca) {
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+ union esca_sigp_ctrl *sigp_ctrl =
+ &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+ union esca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+
+ new_val.scn = src_id;
+ new_val.c = 1;
+ old_val.c = 0;
+
+ expect = old_val.value;
+ rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
+ } else {
+ struct bsca_block *sca = vcpu->kvm->arch.sca;
+ union bsca_sigp_ctrl *sigp_ctrl =
+ &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+ union bsca_sigp_ctrl new_val = {0}, old_val = *sigp_ctrl;
+
+ new_val.scn = src_id;
+ new_val.c = 1;
+ old_val.c = 0;
+
+ expect = old_val.value;
+ rc = cmpxchg(&sigp_ctrl->value, old_val.value, new_val.value);
+ }
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+
+ if (rc != expect) {
+ /* another external call is pending */
+ return -EBUSY;
+ }
+ atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
+ return 0;
+}
+
+static void sca_clear_ext_call(struct kvm_vcpu *vcpu)
+{
+ struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
+ int rc, expect;
+
+ atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ if (vcpu->kvm->arch.use_esca) {
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+ union esca_sigp_ctrl *sigp_ctrl =
+ &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+ union esca_sigp_ctrl old = *sigp_ctrl;
+
+ expect = old.value;
+ rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
+ } else {
+ struct bsca_block *sca = vcpu->kvm->arch.sca;
+ union bsca_sigp_ctrl *sigp_ctrl =
+ &(sca->cpu[vcpu->vcpu_id].sigp_ctrl);
+ union bsca_sigp_ctrl old = *sigp_ctrl;
+
+ expect = old.value;
+ rc = cmpxchg(&sigp_ctrl->value, old.value, 0);
+ }
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+ WARN_ON(rc != expect); /* cannot clear? */
+}
+
int psw_extint_disabled(struct kvm_vcpu *vcpu)
{
return !(vcpu->arch.sie_block->gpsw.mask & PSW_MASK_EXT);
@@ -792,13 +892,11 @@ static const deliver_irq_t deliver_irq_funcs[] = {
int kvm_s390_ext_call_pending(struct kvm_vcpu *vcpu)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
- uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
if (!sclp.has_sigpif)
return test_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs);
- return (sigp_ctrl & SIGP_CTRL_C) &&
- (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_ECALL_PEND);
+ return sca_ext_call_pending(vcpu, NULL);
}
int kvm_s390_vcpu_has_irq(struct kvm_vcpu *vcpu, int exclude_stop)
@@ -909,9 +1007,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
memset(&li->irq, 0, sizeof(li->irq));
spin_unlock(&li->lock);
- /* clear pending external calls set by sigp interpretation facility */
- atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags);
- vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0;
+ sca_clear_ext_call(vcpu);
}
int __must_check kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
@@ -1003,21 +1099,6 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
return 0;
}
-static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id)
-{
- unsigned char new_val, old_val;
- uint8_t *sigp_ctrl = &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
-
- new_val = SIGP_CTRL_C | (src_id & SIGP_CTRL_SCN_MASK);
- old_val = *sigp_ctrl & ~SIGP_CTRL_C;
- if (cmpxchg(sigp_ctrl, old_val, new_val) != old_val) {
- /* another external call is pending */
- return -EBUSY;
- }
- atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags);
- return 0;
-}
-
static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
{
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
@@ -1030,12 +1111,11 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq)
src_id, 0);
/* sending vcpu invalid */
- if (src_id >= KVM_MAX_VCPUS ||
- kvm_get_vcpu(vcpu->kvm, src_id) == NULL)
+ if (kvm_get_vcpu_by_id(vcpu->kvm, src_id) == NULL)
return -EINVAL;
if (sclp.has_sigpif)
- return __inject_extcall_sigpif(vcpu, src_id);
+ return sca_inject_ext_call(vcpu, src_id);
if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs))
return -EBUSY;
@@ -1110,6 +1190,10 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu,
trace_kvm_s390_inject_vcpu(vcpu->vcpu_id, KVM_S390_INT_EMERGENCY,
irq->u.emerg.code, 0);
+ /* sending vcpu invalid */
+ if (kvm_get_vcpu_by_id(vcpu->kvm, irq->u.emerg.code) == NULL)
+ return -EINVAL;
+
set_bit(irq->u.emerg.code, li->sigp_emerg_pending);
set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs);
atomic_or(CPUSTAT_EXT_INT, li->cpuflags);
@@ -2200,7 +2284,7 @@ static void store_local_irq(struct kvm_s390_local_interrupt *li,
int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
{
- uint8_t sigp_ctrl = vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl;
+ int scn;
unsigned long sigp_emerg_pending[BITS_TO_LONGS(KVM_MAX_VCPUS)];
struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
unsigned long pending_irqs;
@@ -2240,14 +2324,12 @@ int kvm_s390_get_irq_state(struct kvm_vcpu *vcpu, __u8 __user *buf, int len)
}
}
- if ((sigp_ctrl & SIGP_CTRL_C) &&
- (atomic_read(&vcpu->arch.sie_block->cpuflags) &
- CPUSTAT_ECALL_PEND)) {
+ if (sca_ext_call_pending(vcpu, &scn)) {
if (n + sizeof(irq) > len)
return -ENOBUFS;
memset(&irq, 0, sizeof(irq));
irq.type = KVM_S390_INT_EXTERNAL_CALL;
- irq.u.extcall.code = sigp_ctrl & SIGP_CTRL_SCN_MASK;
+ irq.u.extcall.code = scn;
if (copy_to_user(&buf[n], &irq, sizeof(irq)))
return -EFAULT;
n += sizeof(irq);
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 8fe2f1c..5927c61 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -246,7 +246,8 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
break;
case KVM_CAP_NR_VCPUS:
case KVM_CAP_MAX_VCPUS:
- r = KVM_MAX_VCPUS;
+ r = sclp.has_esca ? KVM_S390_ESCA_CPU_SLOTS
+ : KVM_S390_BSCA_CPU_SLOTS;
break;
case KVM_CAP_NR_MEMSLOTS:
r = KVM_USER_MEM_SLOTS;
@@ -257,6 +258,9 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_S390_VECTOR_REGISTERS:
r = MACHINE_HAS_VX;
break;
+ case KVM_CAP_S390_RI:
+ r = test_facility(64);
+ break;
default:
r = 0;
}
@@ -283,6 +287,8 @@ static void kvm_s390_sync_dirty_log(struct kvm *kvm,
}
/* Section: vm related */
+static void sca_del_vcpu(struct kvm_vcpu *vcpu);
+
/*
* Get (and clear) the dirty memory log for a memory slot.
*/
@@ -342,15 +348,33 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm, struct kvm_enable_cap *cap)
r = 0;
break;
case KVM_CAP_S390_VECTOR_REGISTERS:
- if (MACHINE_HAS_VX) {
+ mutex_lock(&kvm->lock);
+ if (atomic_read(&kvm->online_vcpus)) {
+ r = -EBUSY;
+ } else if (MACHINE_HAS_VX) {
set_kvm_facility(kvm->arch.model.fac->mask, 129);
set_kvm_facility(kvm->arch.model.fac->list, 129);
r = 0;
} else
r = -EINVAL;
+ mutex_unlock(&kvm->lock);
VM_EVENT(kvm, 3, "ENABLE: CAP_S390_VECTOR_REGISTERS %s",
r ? "(not available)" : "(success)");
break;
+ case KVM_CAP_S390_RI:
+ r = -EINVAL;
+ mutex_lock(&kvm->lock);
+ if (atomic_read(&kvm->online_vcpus)) {
+ r = -EBUSY;
+ } else if (test_facility(64)) {
+ set_kvm_facility(kvm->arch.model.fac->mask, 64);
+ set_kvm_facility(kvm->arch.model.fac->list, 64);
+ r = 0;
+ }
+ mutex_unlock(&kvm->lock);
+ VM_EVENT(kvm, 3, "ENABLE: CAP_S390_RI %s",
+ r ? "(not available)" : "(success)");
+ break;
case KVM_CAP_S390_USER_STSI:
VM_EVENT(kvm, 3, "%s", "ENABLE: CAP_S390_USER_STSI");
kvm->arch.user_stsi = 1;
@@ -371,8 +395,8 @@ static int kvm_s390_get_mem_control(struct kvm *kvm, struct kvm_device_attr *att
case KVM_S390_VM_MEM_LIMIT_SIZE:
ret = 0;
VM_EVENT(kvm, 3, "QUERY: max guest memory: %lu bytes",
- kvm->arch.gmap->asce_end);
- if (put_user(kvm->arch.gmap->asce_end, (u64 __user *)attr->addr))
+ kvm->arch.mem_limit);
+ if (put_user(kvm->arch.mem_limit, (u64 __user *)attr->addr))
ret = -EFAULT;
break;
default:
@@ -424,9 +448,17 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
if (get_user(new_limit, (u64 __user *)attr->addr))
return -EFAULT;
- if (new_limit > kvm->arch.gmap->asce_end)
+ if (kvm->arch.mem_limit != KVM_S390_NO_MEM_LIMIT &&
+ new_limit > kvm->arch.mem_limit)
return -E2BIG;
+ if (!new_limit)
+ return -EINVAL;
+
+ /* gmap_alloc takes last usable address */
+ if (new_limit != KVM_S390_NO_MEM_LIMIT)
+ new_limit -= 1;
+
ret = -EBUSY;
mutex_lock(&kvm->lock);
if (atomic_read(&kvm->online_vcpus) == 0) {
@@ -443,7 +475,9 @@ static int kvm_s390_set_mem_control(struct kvm *kvm, struct kvm_device_attr *att
}
}
mutex_unlock(&kvm->lock);
- VM_EVENT(kvm, 3, "SET: max guest memory: %lu bytes", new_limit);
+ VM_EVENT(kvm, 3, "SET: max guest address: %lu", new_limit);
+ VM_EVENT(kvm, 3, "New guest asce: 0x%pK",
+ (void *) kvm->arch.gmap->asce);
break;
}
default:
@@ -1020,7 +1054,7 @@ static int kvm_s390_apxa_installed(void)
u8 config[128];
int cc;
- if (test_facility(2) && test_facility(12)) {
+ if (test_facility(12)) {
cc = kvm_s390_query_ap_config(config);
if (cc)
@@ -1071,6 +1105,15 @@ static int kvm_s390_crypto_init(struct kvm *kvm)
return 0;
}
+static void sca_dispose(struct kvm *kvm)
+{
+ if (kvm->arch.use_esca)
+ free_pages_exact(kvm->arch.sca, sizeof(struct esca_block));
+ else
+ free_page((unsigned long)(kvm->arch.sca));
+ kvm->arch.sca = NULL;
+}
+
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{
int i, rc;
@@ -1094,14 +1137,17 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
rc = -ENOMEM;
- kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
+ kvm->arch.use_esca = 0; /* start with basic SCA */
+ rwlock_init(&kvm->arch.sca_lock);
+ kvm->arch.sca = (struct bsca_block *) get_zeroed_page(GFP_KERNEL);
if (!kvm->arch.sca)
goto out_err;
spin_lock(&kvm_lock);
sca_offset += 16;
- if (sca_offset + sizeof(struct sca_block) > PAGE_SIZE)
+ if (sca_offset + sizeof(struct bsca_block) > PAGE_SIZE)
sca_offset = 0;
- kvm->arch.sca = (struct sca_block *) ((char *) kvm->arch.sca + sca_offset);
+ kvm->arch.sca = (struct bsca_block *)
+ ((char *) kvm->arch.sca + sca_offset);
spin_unlock(&kvm_lock);
sprintf(debug_name, "kvm-%u", current->pid);
@@ -1153,8 +1199,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
if (type & KVM_VM_S390_UCONTROL) {
kvm->arch.gmap = NULL;
+ kvm->arch.mem_limit = KVM_S390_NO_MEM_LIMIT;
} else {
- kvm->arch.gmap = gmap_alloc(current->mm, (1UL << 44) - 1);
+ if (sclp.hamax == U64_MAX)
+ kvm->arch.mem_limit = TASK_MAX_SIZE;
+ else
+ kvm->arch.mem_limit = min_t(unsigned long, TASK_MAX_SIZE,
+ sclp.hamax + 1);
+ kvm->arch.gmap = gmap_alloc(current->mm, kvm->arch.mem_limit - 1);
if (!kvm->arch.gmap)
goto out_err;
kvm->arch.gmap->private = kvm;
@@ -1166,14 +1218,14 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
kvm->arch.epoch = 0;
spin_lock_init(&kvm->arch.start_stop_lock);
- KVM_EVENT(3, "vm 0x%p created by pid %u", kvm, current->pid);
+ KVM_EVENT(3, "vm 0x%pK created by pid %u", kvm, current->pid);
return 0;
out_err:
kfree(kvm->arch.crypto.crycb);
free_page((unsigned long)kvm->arch.model.fac);
debug_unregister(kvm->arch.dbf);
- free_page((unsigned long)(kvm->arch.sca));
+ sca_dispose(kvm);
KVM_EVENT(3, "creation of vm failed: %d", rc);
return rc;
}
@@ -1184,14 +1236,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
trace_kvm_s390_destroy_vcpu(vcpu->vcpu_id);
kvm_s390_clear_local_irqs(vcpu);
kvm_clear_async_pf_completion_queue(vcpu);
- if (!kvm_is_ucontrol(vcpu->kvm)) {
- clear_bit(63 - vcpu->vcpu_id,
- (unsigned long *) &vcpu->kvm->arch.sca->mcn);
- if (vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda ==
- (__u64) vcpu->arch.sie_block)
- vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sda = 0;
- }
- smp_mb();
+ if (!kvm_is_ucontrol(vcpu->kvm))
+ sca_del_vcpu(vcpu);
if (kvm_is_ucontrol(vcpu->kvm))
gmap_free(vcpu->arch.gmap);
@@ -1224,14 +1270,14 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
{
kvm_free_vcpus(kvm);
free_page((unsigned long)kvm->arch.model.fac);
- free_page((unsigned long)(kvm->arch.sca));
+ sca_dispose(kvm);
debug_unregister(kvm->arch.dbf);
kfree(kvm->arch.crypto.crycb);
if (!kvm_is_ucontrol(kvm))
gmap_free(kvm->arch.gmap);
kvm_s390_destroy_adapters(kvm);
kvm_s390_clear_float_irqs(kvm);
- KVM_EVENT(3, "vm 0x%p destroyed", kvm);
+ KVM_EVENT(3, "vm 0x%pK destroyed", kvm);
}
/* Section: vcpu related */
@@ -1245,6 +1291,117 @@ static int __kvm_ucontrol_vcpu_init(struct kvm_vcpu *vcpu)
return 0;
}
+static void sca_del_vcpu(struct kvm_vcpu *vcpu)
+{
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ if (vcpu->kvm->arch.use_esca) {
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+
+ clear_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
+ sca->cpu[vcpu->vcpu_id].sda = 0;
+ } else {
+ struct bsca_block *sca = vcpu->kvm->arch.sca;
+
+ clear_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
+ sca->cpu[vcpu->vcpu_id].sda = 0;
+ }
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+}
+
+static void sca_add_vcpu(struct kvm_vcpu *vcpu)
+{
+ read_lock(&vcpu->kvm->arch.sca_lock);
+ if (vcpu->kvm->arch.use_esca) {
+ struct esca_block *sca = vcpu->kvm->arch.sca;
+
+ sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
+ vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
+ vcpu->arch.sie_block->scaol = (__u32)(__u64)sca & ~0x3fU;
+ vcpu->arch.sie_block->ecb2 |= 0x04U;
+ set_bit_inv(vcpu->vcpu_id, (unsigned long *) sca->mcn);
+ } else {
+ struct bsca_block *sca = vcpu->kvm->arch.sca;
+
+ sca->cpu[vcpu->vcpu_id].sda = (__u64) vcpu->arch.sie_block;
+ vcpu->arch.sie_block->scaoh = (__u32)(((__u64)sca) >> 32);
+ vcpu->arch.sie_block->scaol = (__u32)(__u64)sca;
+ set_bit_inv(vcpu->vcpu_id, (unsigned long *) &sca->mcn);
+ }
+ read_unlock(&vcpu->kvm->arch.sca_lock);
+}
+
+/* Basic SCA to Extended SCA data copy routines */
+static inline void sca_copy_entry(struct esca_entry *d, struct bsca_entry *s)
+{
+ d->sda = s->sda;
+ d->sigp_ctrl.c = s->sigp_ctrl.c;
+ d->sigp_ctrl.scn = s->sigp_ctrl.scn;
+}
+
+static void sca_copy_b_to_e(struct esca_block *d, struct bsca_block *s)
+{
+ int i;
+
+ d->ipte_control = s->ipte_control;
+ d->mcn[0] = s->mcn;
+ for (i = 0; i < KVM_S390_BSCA_CPU_SLOTS; i++)
+ sca_copy_entry(&d->cpu[i], &s->cpu[i]);
+}
+
+static int sca_switch_to_extended(struct kvm *kvm)
+{
+ struct bsca_block *old_sca = kvm->arch.sca;
+ struct esca_block *new_sca;
+ struct kvm_vcpu *vcpu;
+ unsigned int vcpu_idx;
+ u32 scaol, scaoh;
+
+ new_sca = alloc_pages_exact(sizeof(*new_sca), GFP_KERNEL|__GFP_ZERO);
+ if (!new_sca)
+ return -ENOMEM;
+
+ scaoh = (u32)((u64)(new_sca) >> 32);
+ scaol = (u32)(u64)(new_sca) & ~0x3fU;
+
+ kvm_s390_vcpu_block_all(kvm);
+ write_lock(&kvm->arch.sca_lock);
+
+ sca_copy_b_to_e(new_sca, old_sca);
+
+ kvm_for_each_vcpu(vcpu_idx, vcpu, kvm) {
+ vcpu->arch.sie_block->scaoh = scaoh;
+ vcpu->arch.sie_block->scaol = scaol;
+ vcpu->arch.sie_block->ecb2 |= 0x04U;
+ }
+ kvm->arch.sca = new_sca;
+ kvm->arch.use_esca = 1;
+
+ write_unlock(&kvm->arch.sca_lock);
+ kvm_s390_vcpu_unblock_all(kvm);
+
+ free_page((unsigned long)old_sca);
+
+ VM_EVENT(kvm, 2, "Switched to ESCA (0x%pK -> 0x%pK)",
+ old_sca, kvm->arch.sca);
+ return 0;
+}
+
+static int sca_can_add_vcpu(struct kvm *kvm, unsigned int id)
+{
+ int rc;
+
+ if (id < KVM_S390_BSCA_CPU_SLOTS)
+ return true;
+ if (!sclp.has_esca)
+ return false;
+
+ mutex_lock(&kvm->lock);
+ rc = kvm->arch.use_esca ? 0 : sca_switch_to_extended(kvm);
+ mutex_unlock(&kvm->lock);
+
+ return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS;
+}
+
int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
{
vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
@@ -1255,6 +1412,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
KVM_SYNC_CRS |
KVM_SYNC_ARCH0 |
KVM_SYNC_PFAULT;
+ if (test_kvm_facility(vcpu->kvm, 64))
+ vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
if (test_kvm_facility(vcpu->kvm, 129))
vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
@@ -1365,8 +1524,11 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->epoch = vcpu->kvm->arch.epoch;
preempt_enable();
mutex_unlock(&vcpu->kvm->lock);
- if (!kvm_is_ucontrol(vcpu->kvm))
+ if (!kvm_is_ucontrol(vcpu->kvm)) {
vcpu->arch.gmap = vcpu->kvm->arch.gmap;
+ sca_add_vcpu(vcpu);
+ }
+
}
static void kvm_s390_vcpu_crypto_setup(struct kvm_vcpu *vcpu)
@@ -1435,10 +1597,13 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->eca |= 1;
if (sclp.has_sigpif)
vcpu->arch.sie_block->eca |= 0x10000000U;
+ if (test_kvm_facility(vcpu->kvm, 64))
+ vcpu->arch.sie_block->ecb3 |= 0x01;
if (test_kvm_facility(vcpu->kvm, 129)) {
vcpu->arch.sie_block->eca |= 0x00020000;
vcpu->arch.sie_block->ecd |= 0x20000000;
}
+ vcpu->arch.sie_block->riccbd = (unsigned long) &vcpu->run->s.regs.riccb;
vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
if (vcpu->kvm->arch.use_cmma) {
@@ -1461,7 +1626,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
struct sie_page *sie_page;
int rc = -EINVAL;
- if (id >= KVM_MAX_VCPUS)
+ if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id))
goto out;
rc = -ENOMEM;
@@ -1478,20 +1643,6 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
vcpu->arch.sie_block->icpua = id;
- if (!kvm_is_ucontrol(kvm)) {
- if (!kvm->arch.sca) {
- WARN_ON_ONCE(1);
- goto out_free_cpu;
- }
- if (!kvm->arch.sca->cpu[id].sda)
- kvm->arch.sca->cpu[id].sda =
- (__u64) vcpu->arch.sie_block;
- vcpu->arch.sie_block->scaoh =
- (__u32)(((__u64)kvm->arch.sca) >> 32);
- vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
- set_bit(63 - id, (unsigned long *) &kvm->arch.sca->mcn);
- }
-
spin_lock_init(&vcpu->arch.local_int.lock);
vcpu->arch.local_int.float_int = &kvm->arch.float_int;
vcpu->arch.local_int.wq = &vcpu->wq;
@@ -1505,15 +1656,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
*/
vcpu->arch.guest_fpregs.fprs = kzalloc(sizeof(freg_t) * __NUM_FPRS,
GFP_KERNEL);
- if (!vcpu->arch.guest_fpregs.fprs) {
- rc = -ENOMEM;
+ if (!vcpu->arch.guest_fpregs.fprs)
goto out_free_sie_block;
- }
rc = kvm_vcpu_init(vcpu, kvm, id);
if (rc)
goto out_free_sie_block;
- VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
+ VM_EVENT(kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", id, vcpu,
vcpu->arch.sie_block);
trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
@@ -2009,7 +2158,8 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
*/
kvm_check_async_pf_completion(vcpu);
- memcpy(&vcpu->arch.sie_block->gg14, &vcpu->run->s.regs.gprs[14], 16);
+ vcpu->arch.sie_block->gg14 = vcpu->run->s.regs.gprs[14];
+ vcpu->arch.sie_block->gg15 = vcpu->run->s.regs.gprs[15];
if (need_resched())
schedule();
@@ -2067,8 +2217,6 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
{
- int rc = -1;
-
VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
vcpu->arch.sie_block->icptcode);
trace_kvm_s390_sie_exit(vcpu, vcpu->arch.sie_block->icptcode);
@@ -2076,40 +2224,36 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
if (guestdbg_enabled(vcpu))
kvm_s390_restore_guest_per_regs(vcpu);
- if (exit_reason >= 0) {
- rc = 0;
+ vcpu->run->s.regs.gprs[14] = vcpu->arch.sie_block->gg14;
+ vcpu->run->s.regs.gprs[15] = vcpu->arch.sie_block->gg15;
+
+ if (vcpu->arch.sie_block->icptcode > 0) {
+ int rc = kvm_handle_sie_intercept(vcpu);
+
+ if (rc != -EOPNOTSUPP)
+ return rc;
+ vcpu->run->exit_reason = KVM_EXIT_S390_SIEIC;
+ vcpu->run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
+ vcpu->run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
+ vcpu->run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
+ return -EREMOTE;
+ } else if (exit_reason != -EFAULT) {
+ vcpu->stat.exit_null++;
+ return 0;
} else if (kvm_is_ucontrol(vcpu->kvm)) {
vcpu->run->exit_reason = KVM_EXIT_S390_UCONTROL;
vcpu->run->s390_ucontrol.trans_exc_code =
current->thread.gmap_addr;
vcpu->run->s390_ucontrol.pgm_code = 0x10;
- rc = -EREMOTE;
-
+ return -EREMOTE;
} else if (current->thread.gmap_pfault) {
trace_kvm_s390_major_guest_pfault(vcpu);
current->thread.gmap_pfault = 0;
- if (kvm_arch_setup_async_pf(vcpu)) {
- rc = 0;
- } else {
- gpa_t gpa = current->thread.gmap_addr;
- rc = kvm_arch_fault_in_page(vcpu, gpa, 1);
- }
+ if (kvm_arch_setup_async_pf(vcpu))
+ return 0;
+ return kvm_arch_fault_in_page(vcpu, current->thread.gmap_addr, 1);
}
-
- if (rc == -1)
- rc = vcpu_post_run_fault_in_sie(vcpu);
-
- memcpy(&vcpu->run->s.regs.gprs[14], &vcpu->arch.sie_block->gg14, 16);
-
- if (rc == 0) {
- if (kvm_is_ucontrol(vcpu->kvm))
- /* Don't exit for host interrupts. */
- rc = vcpu->arch.sie_block->icptcode ? -EOPNOTSUPP : 0;
- else
- rc = kvm_handle_sie_intercept(vcpu);
- }
-
- return rc;
+ return vcpu_post_run_fault_in_sie(vcpu);
}
static int __vcpu_run(struct kvm_vcpu *vcpu)
@@ -2229,18 +2373,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
rc = 0;
}
- if (rc == -EOPNOTSUPP) {
- /* intercept cannot be handled in-kernel, prepare kvm-run */
- kvm_run->exit_reason = KVM_EXIT_S390_SIEIC;
- kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
- kvm_run->s390_sieic.ipa = vcpu->arch.sie_block->ipa;
- kvm_run->s390_sieic.ipb = vcpu->arch.sie_block->ipb;
- rc = 0;
- }
-
if (rc == -EREMOTE) {
- /* intercept was handled, but userspace support is needed
- * kvm_run has been prepared by the handler */
+ /* userspace support is needed, kvm_run has been prepared */
rc = 0;
}
@@ -2732,6 +2866,9 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm,
if (mem->memory_size & 0xffffful)
return -EINVAL;
+ if (mem->guest_phys_addr + mem->memory_size > kvm->arch.mem_limit)
+ return -EINVAL;
+
return 0;
}
@@ -2763,6 +2900,11 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
static int __init kvm_s390_init(void)
{
+ if (!sclp.has_sief2) {
+ pr_info("SIE not available\n");
+ return -ENODEV;
+ }
+
return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE);
}
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 1e70e00..df1abad 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -340,4 +340,11 @@ void kvm_s390_clear_bp_data(struct kvm_vcpu *vcpu);
void kvm_s390_prepare_debug_exit(struct kvm_vcpu *vcpu);
void kvm_s390_handle_per_event(struct kvm_vcpu *vcpu);
+/* support for Basic/Extended SCA handling */
+static inline union ipte_control *kvm_s390_get_ipte_control(struct kvm *kvm)
+{
+ struct bsca_block *sca = kvm->arch.sca; /* SCA version doesn't matter */
+
+ return &sca->ipte_control;
+}
#endif
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 77191b8..d76b51c 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -660,7 +660,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
- if (!MACHINE_HAS_PFMF)
+ if (!test_kvm_facility(vcpu->kvm, 8))
return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c
index da690b6..77c22d6 100644
--- a/arch/s390/kvm/sigp.c
+++ b/arch/s390/kvm/sigp.c
@@ -291,12 +291,8 @@ static int handle_sigp_dst(struct kvm_vcpu *vcpu, u8 order_code,
u16 cpu_addr, u32 parameter, u64 *status_reg)
{
int rc;
- struct kvm_vcpu *dst_vcpu;
+ struct kvm_vcpu *dst_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
- if (cpu_addr >= KVM_MAX_VCPUS)
- return SIGP_CC_NOT_OPERATIONAL;
-
- dst_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
if (!dst_vcpu)
return SIGP_CC_NOT_OPERATIONAL;
@@ -478,7 +474,7 @@ int kvm_s390_handle_sigp_pei(struct kvm_vcpu *vcpu)
trace_kvm_s390_handle_sigp_pei(vcpu, order_code, cpu_addr);
if (order_code == SIGP_EXTERNAL_CALL) {
- dest_vcpu = kvm_get_vcpu(vcpu->kvm, cpu_addr);
+ dest_vcpu = kvm_get_vcpu_by_id(vcpu->kvm, cpu_addr);
BUG_ON(dest_vcpu == NULL);
kvm_s390_vcpu_wakeup(dest_vcpu);
diff --git a/arch/s390/kvm/trace-s390.h b/arch/s390/kvm/trace-s390.h
index cc1d6c6..396485b 100644
--- a/arch/s390/kvm/trace-s390.h
+++ b/arch/s390/kvm/trace-s390.h
@@ -55,8 +55,8 @@ TRACE_EVENT(kvm_s390_create_vcpu,
__entry->sie_block = sie_block;
),
- TP_printk("create cpu %d at %p, sie block at %p", __entry->id,
- __entry->vcpu, __entry->sie_block)
+ TP_printk("create cpu %d at 0x%pK, sie block at 0x%pK",
+ __entry->id, __entry->vcpu, __entry->sie_block)
);
TRACE_EVENT(kvm_s390_destroy_vcpu,
@@ -254,7 +254,7 @@ TRACE_EVENT(kvm_s390_enable_css,
__entry->kvm = kvm;
),
- TP_printk("enabling channel I/O support (kvm @ %p)\n",
+ TP_printk("enabling channel I/O support (kvm @ %pK)\n",
__entry->kvm)
);
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index c3c07d3..c722400 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -48,37 +48,13 @@ EXPORT_SYMBOL(zero_page_mask);
static void __init setup_zero_pages(void)
{
- struct cpuid cpu_id;
unsigned int order;
struct page *page;
int i;
- get_cpu_id(&cpu_id);
- switch (cpu_id.machine) {
- case 0x9672: /* g5 */
- case 0x2064: /* z900 */
- case 0x2066: /* z900 */
- case 0x2084: /* z990 */
- case 0x2086: /* z990 */
- case 0x2094: /* z9-109 */
- case 0x2096: /* z9-109 */
- order = 0;
- break;
- case 0x2097: /* z10 */
- case 0x2098: /* z10 */
- case 0x2817: /* z196 */
- case 0x2818: /* z196 */
- order = 2;
- break;
- case 0x2827: /* zEC12 */
- case 0x2828: /* zEC12 */
- order = 5;
- break;
- case 0x2964: /* z13 */
- default:
- order = 7;
- break;
- }
+ /* Latest machines require a mapping granularity of 512KB */
+ order = 7;
+
/* Limit number of empty zero pages for small memory sizes */
while (order > 2 && (totalram_pages >> 10) < (1UL << order))
order--;
diff --git a/arch/s390/mm/mmap.c b/arch/s390/mm/mmap.c
index 6e552af..ea01477 100644
--- a/arch/s390/mm/mmap.c
+++ b/arch/s390/mm/mmap.c
@@ -31,9 +31,6 @@
#include <linux/security.h>
#include <asm/pgalloc.h>
-unsigned long mmap_rnd_mask;
-static unsigned long mmap_align_mask;
-
static unsigned long stack_maxrandom_size(void)
{
if (!(current->flags & PF_RANDOMIZE))
@@ -62,10 +59,7 @@ static inline int mmap_is_legacy(void)
unsigned long arch_mmap_rnd(void)
{
- if (is_32bit_task())
- return (get_random_int() & 0x7ff) << PAGE_SHIFT;
- else
- return (get_random_int() & mmap_rnd_mask) << PAGE_SHIFT;
+ return (get_random_int() & MMAP_RND_MASK) << PAGE_SHIFT;
}
static unsigned long mmap_base_legacy(unsigned long rnd)
@@ -92,7 +86,6 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
struct vm_unmapped_area_info info;
- int do_color_align;
if (len > TASK_SIZE - mmap_min_addr)
return -ENOMEM;
@@ -108,15 +101,14 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
return addr;
}
- do_color_align = 0;
- if (filp || (flags & MAP_SHARED))
- do_color_align = !is_32bit_task();
-
info.flags = 0;
info.length = len;
info.low_limit = mm->mmap_base;
info.high_limit = TASK_SIZE;
- info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+ if (filp || (flags & MAP_SHARED))
+ info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
+ else
+ info.align_mask = 0;
info.align_offset = pgoff << PAGE_SHIFT;
return vm_unmapped_area(&info);
}
@@ -130,7 +122,6 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
struct mm_struct *mm = current->mm;
unsigned long addr = addr0;
struct vm_unmapped_area_info info;
- int do_color_align;
/* requested length too big for entire address space */
if (len > TASK_SIZE - mmap_min_addr)
@@ -148,15 +139,14 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
return addr;
}
- do_color_align = 0;
- if (filp || (flags & MAP_SHARED))
- do_color_align = !is_32bit_task();
-
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.length = len;
info.low_limit = max(PAGE_SIZE, mmap_min_addr);
info.high_limit = mm->mmap_base;
- info.align_mask = do_color_align ? (mmap_align_mask << PAGE_SHIFT) : 0;
+ if (filp || (flags & MAP_SHARED))
+ info.align_mask = MMAP_ALIGN_MASK << PAGE_SHIFT;
+ else
+ info.align_mask = 0;
info.align_offset = pgoff << PAGE_SHIFT;
addr = vm_unmapped_area(&info);
@@ -254,35 +244,3 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
mm->get_unmapped_area = s390_get_unmapped_area_topdown;
}
}
-
-static int __init setup_mmap_rnd(void)
-{
- struct cpuid cpu_id;
-
- get_cpu_id(&cpu_id);
- switch (cpu_id.machine) {
- case 0x9672:
- case 0x2064:
- case 0x2066:
- case 0x2084:
- case 0x2086:
- case 0x2094:
- case 0x2096:
- case 0x2097:
- case 0x2098:
- case 0x2817:
- case 0x2818:
- case 0x2827:
- case 0x2828:
- mmap_rnd_mask = 0x7ffUL;
- mmap_align_mask = 0UL;
- break;
- case 0x2964: /* z13 */
- default:
- mmap_rnd_mask = 0x3ff80UL;
- mmap_align_mask = 0x7fUL;
- break;
- }
- return 0;
-}
-early_initcall(setup_mmap_rnd);
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 54ef3bc..63b0398 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -133,7 +133,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
/**
* gmap_alloc - allocate a guest address space
* @mm: pointer to the parent mm_struct
- * @limit: maximum size of the gmap address space
+ * @limit: maximum address of the gmap address space
*
* Returns a guest address space structure.
*/
@@ -402,7 +402,7 @@ int gmap_map_segment(struct gmap *gmap, unsigned long from,
if ((from | to | len) & (PMD_SIZE - 1))
return -EINVAL;
if (len == 0 || from + len < from || to + len < to ||
- from + len > TASK_MAX_SIZE || to + len > gmap->asce_end)
+ from + len - 1 > TASK_MAX_SIZE || to + len - 1 > gmap->asce_end)
return -EINVAL;
flush = 0;
diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c
index 37d10f7..32da0a6 100644
--- a/arch/s390/pci/pci_dma.c
+++ b/arch/s390/pci/pci_dma.c
@@ -33,7 +33,7 @@ unsigned long *dma_alloc_cpu_table(void)
return NULL;
for (entry = table; entry < table + ZPCI_TABLE_ENTRIES; entry++)
- *entry = ZPCI_TABLE_INVALID | ZPCI_TABLE_PROTECTED;
+ *entry = ZPCI_TABLE_INVALID;
return table;
}
@@ -51,7 +51,7 @@ static unsigned long *dma_alloc_page_table(void)
return NULL;
for (entry = table; entry < table + ZPCI_PT_ENTRIES; entry++)
- *entry = ZPCI_PTE_INVALID | ZPCI_TABLE_PROTECTED;
+ *entry = ZPCI_PTE_INVALID;
return table;
}
@@ -95,7 +95,7 @@ static unsigned long *dma_get_page_table_origin(unsigned long *entry)
return pto;
}
-static unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
+unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr)
{
unsigned long *sto, *pto;
unsigned int rtx, sx, px;
@@ -114,20 +114,10 @@ static unsigned long *dma_walk_cpu_trans(unsigned long *rto, dma_addr_t dma_addr
return &pto[px];
}
-void dma_update_cpu_trans(unsigned long *dma_table, void *page_addr,
- dma_addr_t dma_addr, int flags)
+void dma_update_cpu_trans(unsigned long *entry, void *page_addr, int flags)
{
- unsigned long *entry;
-
- entry = dma_walk_cpu_trans(dma_table, dma_addr);
- if (!entry) {
- WARN_ON_ONCE(1);
- return;
- }
-
if (flags & ZPCI_PTE_INVALID) {
invalidate_pt_entry(entry);
- return;
} else {
set_pt_pfaa(entry, page_addr);
validate_pt_entry(entry);
@@ -146,18 +136,25 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
u8 *page_addr = (u8 *) (pa & PAGE_MASK);
dma_addr_t start_dma_addr = dma_addr;
unsigned long irq_flags;
+ unsigned long *entry;
int i, rc = 0;
if (!nr_pages)
return -EINVAL;
spin_lock_irqsave(&zdev->dma_table_lock, irq_flags);
- if (!zdev->dma_table)
+ if (!zdev->dma_table) {
+ rc = -EINVAL;
goto no_refresh;
+ }
for (i = 0; i < nr_pages; i++) {
- dma_update_cpu_trans(zdev->dma_table, page_addr, dma_addr,
- flags);
+ entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
+ if (!entry) {
+ rc = -ENOMEM;
+ goto undo_cpu_trans;
+ }
+ dma_update_cpu_trans(entry, page_addr, flags);
page_addr += PAGE_SIZE;
dma_addr += PAGE_SIZE;
}
@@ -176,6 +173,18 @@ static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
rc = zpci_refresh_trans((u64) zdev->fh << 32, start_dma_addr,
nr_pages * PAGE_SIZE);
+undo_cpu_trans:
+ if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
+ flags = ZPCI_PTE_INVALID;
+ while (i-- > 0) {
+ page_addr -= PAGE_SIZE;
+ dma_addr -= PAGE_SIZE;
+ entry = dma_walk_cpu_trans(zdev->dma_table, dma_addr);
+ if (!entry)
+ break;
+ dma_update_cpu_trans(entry, page_addr, flags);
+ }
+ }
no_refresh:
spin_unlock_irqrestore(&zdev->dma_table_lock, irq_flags);
@@ -260,6 +269,16 @@ out:
spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags);
}
+static inline void zpci_err_dma(unsigned long rc, unsigned long addr)
+{
+ struct {
+ unsigned long rc;
+ unsigned long addr;
+ } __packed data = {rc, addr};
+
+ zpci_err_hex(&data, sizeof(data));
+}
+
static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
unsigned long offset, size_t size,
enum dma_data_direction direction,
@@ -270,33 +289,40 @@ static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page,
unsigned long pa = page_to_phys(page) + offset;
int flags = ZPCI_PTE_VALID;
dma_addr_t dma_addr;
+ int ret;
/* This rounds up number of pages based on size and offset */
nr_pages = iommu_num_pages(pa, size, PAGE_SIZE);
iommu_page_index = dma_alloc_iommu(zdev, nr_pages);
- if (iommu_page_index == -1)
+ if (iommu_page_index == -1) {
+ ret = -ENOSPC;
goto out_err;
+ }
/* Use rounded up size */
size = nr_pages * PAGE_SIZE;
dma_addr = zdev->start_dma + iommu_page_index * PAGE_SIZE;
- if (dma_addr + size > zdev->end_dma)
+ if (dma_addr + size > zdev->end_dma) {
+ ret = -ERANGE;
goto out_free;
+ }
if (direction == DMA_NONE || direction == DMA_TO_DEVICE)
flags |= ZPCI_TABLE_PROTECTED;
- if (!dma_update_trans(zdev, pa, dma_addr, size, flags)) {
- atomic64_add(nr_pages, &zdev->mapped_pages);
- return dma_addr + (offset & ~PAGE_MASK);
- }
+ ret = dma_update_trans(zdev, pa, dma_addr, size, flags);
+ if (ret)
+ goto out_free;
+
+ atomic64_add(nr_pages, &zdev->mapped_pages);
+ return dma_addr + (offset & ~PAGE_MASK);
out_free:
dma_free_iommu(zdev, iommu_page_index, nr_pages);
out_err:
zpci_err("map error:\n");
- zpci_err_hex(&pa, sizeof(pa));
+ zpci_err_dma(ret, pa);
return DMA_ERROR_CODE;
}
@@ -306,14 +332,16 @@ static void s390_dma_unmap_pages(struct device *dev, dma_addr_t dma_addr,
{
struct zpci_dev *zdev = to_zpci(to_pci_dev(dev));
unsigned long iommu_page_index;
- int npages;
+ int npages, ret;
npages = iommu_num_pages(dma_addr, size, PAGE_SIZE);
dma_addr = dma_addr & PAGE_MASK;
- if (dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE,
- ZPCI_TABLE_PROTECTED | ZPCI_PTE_INVALID)) {
+ ret = dma_update_trans(zdev, 0, dma_addr, npages * PAGE_SIZE,
+ ZPCI_PTE_INVALID);
+ if (ret) {
zpci_err("unmap error:\n");
- zpci_err_hex(&dma_addr, sizeof(dma_addr));
+ zpci_err_dma(ret, dma_addr);
+ return;
}
atomic64_add(npages, &zdev->unmapped_pages);
@@ -338,8 +366,7 @@ static void *s390_dma_alloc(struct device *dev, size_t size,
pa = page_to_phys(page);
memset((void *) pa, 0, size);
- map = s390_dma_map_pages(dev, page, pa % PAGE_SIZE,
- size, DMA_BIDIRECTIONAL, NULL);
+ map = s390_dma_map_pages(dev, page, 0, size, DMA_BIDIRECTIONAL, NULL);
if (dma_mapping_error(dev, map)) {
free_pages(pa, get_order(size));
return NULL;
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index cbd2a9f..62c3b81 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -27,10 +27,10 @@
#include <linux/gpio.h>
#include <linux/videodev2.h>
#include <linux/sh_intc.h>
-#include <media/ov772x.h>
+#include <media/i2c/ov772x.h>
#include <media/soc_camera.h>
-#include <media/soc_camera_platform.h>
-#include <media/sh_mobile_ceu.h>
+#include <linux/platform_data/media/soc_camera_platform.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/io.h>
#include <asm/clock.h>
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index d531791..a9c0c07 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -38,10 +38,10 @@
#include <video/sh_mobile_lcdc.h>
#include <sound/sh_fsi.h>
#include <sound/simple_card.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
#include <media/soc_camera.h>
-#include <media/tw9910.h>
-#include <media/mt9t112.h>
+#include <media/i2c/tw9910.h>
+#include <media/i2c/mt9t112.h>
#include <asm/heartbeat.h>
#include <asm/clock.h>
#include <asm/suspend.h>
@@ -900,8 +900,8 @@ static struct platform_device irda_device = {
.resource = irda_resources,
};
-#include <media/ak881x.h>
-#include <media/sh_vou.h>
+#include <media/i2c/ak881x.h>
+#include <media/drv-intf/sh_vou.h>
static struct ak881x_pdata ak881x_pdata = {
.flags = AK881X_IF_MODE_SLAVE,
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 7d997ce..6bd9230 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -27,9 +27,9 @@
#include <linux/usb/r8a66597.h>
#include <linux/videodev2.h>
#include <linux/sh_intc.h>
-#include <media/rj54n1cb0c.h>
+#include <media/i2c/rj54n1cb0c.h>
#include <media/soc_camera.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
#include <video/sh_mobile_lcdc.h>
#include <asm/suspend.h>
#include <asm/clock.h>
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 29b7c0d..8f237a5 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -27,10 +27,10 @@
#include <linux/videodev2.h>
#include <linux/sh_intc.h>
#include <video/sh_mobile_lcdc.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/ov772x.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/i2c/ov772x.h>
#include <media/soc_camera.h>
-#include <media/tw9910.h>
+#include <media/i2c/tw9910.h>
#include <asm/clock.h>
#include <asm/machvec.h>
#include <asm/io.h>
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 4f6635a..e0e1df1 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -30,7 +30,7 @@
#include <linux/sh_intc.h>
#include <linux/videodev2.h>
#include <video/sh_mobile_lcdc.h>
-#include <media/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
#include <sound/sh_fsi.h>
#include <sound/simple_card.h>
#include <asm/io.h>
@@ -534,8 +534,8 @@ static struct platform_device irda_device = {
.resource = irda_resources,
};
-#include <media/ak881x.h>
-#include <media/sh_vou.h>
+#include <media/i2c/ak881x.h>
+#include <media/drv-intf/sh_vou.h>
static struct ak881x_pdata ak881x_pdata = {
.flags = AK881X_IF_MODE_SLAVE,
diff --git a/arch/sh/include/uapi/asm/unistd_64.h b/arch/sh/include/uapi/asm/unistd_64.h
index e6820c8..47ebd5b 100644
--- a/arch/sh/include/uapi/asm/unistd_64.h
+++ b/arch/sh/include/uapi/asm/unistd_64.h
@@ -278,7 +278,7 @@
#define __NR_fsetxattr 256
#define __NR_getxattr 257
#define __NR_lgetxattr 258
-#define __NR_fgetxattr 269
+#define __NR_fgetxattr 259
#define __NR_listxattr 260
#define __NR_llistxattr 261
#define __NR_flistxattr 262
diff --git a/arch/sh/kernel/perf_event.c b/arch/sh/kernel/perf_event.c
index 7cfd7f1..4dca183 100644
--- a/arch/sh/kernel/perf_event.c
+++ b/arch/sh/kernel/perf_event.c
@@ -10,7 +10,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
* Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
*
* ppc:
diff --git a/arch/sparc/include/asm/elf_64.h b/arch/sparc/include/asm/elf_64.h
index 370ca1e..9331083 100644
--- a/arch/sparc/include/asm/elf_64.h
+++ b/arch/sparc/include/asm/elf_64.h
@@ -95,6 +95,7 @@
* really available. So we simply advertise only "crypto" support.
*/
#define HWCAP_SPARC_CRYPTO 0x04000000 /* CRYPTO insns available */
+#define HWCAP_SPARC_ADI 0x08000000 /* ADI available */
#define CORE_DUMP_USE_REGSET
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
index 64ee103..57aca27 100644
--- a/arch/sparc/include/asm/uaccess_32.h
+++ b/arch/sparc/include/asm/uaccess_32.h
@@ -205,31 +205,6 @@ int __put_user_bad(void);
__gu_ret; \
})
-#define __get_user_check_ret(x, addr, size, type, retval) ({ \
- register unsigned long __gu_val __asm__ ("l1"); \
- if (__access_ok(addr, size)) { \
- switch (size) { \
- case 1: \
- __get_user_asm_ret(__gu_val, ub, addr, retval); \
- break; \
- case 2: \
- __get_user_asm_ret(__gu_val, uh, addr, retval); \
- break; \
- case 4: \
- __get_user_asm_ret(__gu_val, , addr, retval); \
- break; \
- case 8: \
- __get_user_asm_ret(__gu_val, d, addr, retval); \
- break; \
- default: \
- if (__get_user_bad()) \
- return retval; \
- } \
- x = (__force type) __gu_val; \
- } else \
- return retval; \
-})
-
#define __get_user_nocheck(x, addr, size, type) ({ \
register int __gu_ret; \
register unsigned long __gu_val; \
@@ -247,20 +222,6 @@ int __put_user_bad(void);
__gu_ret; \
})
-#define __get_user_nocheck_ret(x, addr, size, type, retval) ({ \
- register unsigned long __gu_val __asm__ ("l1"); \
- switch (size) { \
- case 1: __get_user_asm_ret(__gu_val, ub, addr, retval); break; \
- case 2: __get_user_asm_ret(__gu_val, uh, addr, retval); break; \
- case 4: __get_user_asm_ret(__gu_val, , addr, retval); break; \
- case 8: __get_user_asm_ret(__gu_val, d, addr, retval); break; \
- default: \
- if (__get_user_bad()) \
- return retval; \
- } \
- x = (__force type) __gu_val; \
-})
-
#define __get_user_asm(x, size, addr, ret) \
__asm__ __volatile__( \
"/* Get user asm, inline. */\n" \
@@ -281,32 +242,6 @@ __asm__ __volatile__( \
: "=&r" (ret), "=&r" (x) : "m" (*__m(addr)), \
"i" (-EFAULT))
-#define __get_user_asm_ret(x, size, addr, retval) \
-if (__builtin_constant_p(retval) && retval == -EFAULT) \
- __asm__ __volatile__( \
- "/* Get user asm ret, inline. */\n" \
- "1:\t" "ld"#size " %1, %0\n\n\t" \
- ".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b,__ret_efault\n\n\t" \
- ".previous\n\t" \
- : "=&r" (x) : "m" (*__m(addr))); \
-else \
- __asm__ __volatile__( \
- "/* Get user asm ret, inline. */\n" \
- "1:\t" "ld"#size " %1, %0\n\n\t" \
- ".section .fixup,#alloc,#execinstr\n\t" \
- ".align 4\n" \
- "3:\n\t" \
- "ret\n\t" \
- " restore %%g0, %2, %%o0\n\n\t" \
- ".previous\n\t" \
- ".section __ex_table,#alloc\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\n\t" \
- ".previous\n\t" \
- : "=&r" (x) : "m" (*__m(addr)), "i" (retval))
-
int __get_user_bad(void);
unsigned long __copy_user(void __user *to, const void __user *from, unsigned long size);
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index ea6e9a2..e9a51d6 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
@@ -179,20 +179,6 @@ int __put_user_bad(void);
__gu_ret; \
})
-#define __get_user_nocheck_ret(data, addr, size, type, retval) ({ \
- register unsigned long __gu_val __asm__ ("l1"); \
- switch (size) { \
- case 1: __get_user_asm_ret(__gu_val, ub, addr, retval); break; \
- case 2: __get_user_asm_ret(__gu_val, uh, addr, retval); break; \
- case 4: __get_user_asm_ret(__gu_val, uw, addr, retval); break; \
- case 8: __get_user_asm_ret(__gu_val, x, addr, retval); break; \
- default: \
- if (__get_user_bad()) \
- return retval; \
- } \
- data = (__force type) __gu_val; \
-})
-
#define __get_user_asm(x, size, addr, ret) \
__asm__ __volatile__( \
"/* Get user asm, inline. */\n" \
@@ -214,32 +200,6 @@ __asm__ __volatile__( \
: "=r" (ret), "=r" (x) : "r" (__m(addr)), \
"i" (-EFAULT))
-#define __get_user_asm_ret(x, size, addr, retval) \
-if (__builtin_constant_p(retval) && retval == -EFAULT) \
- __asm__ __volatile__( \
- "/* Get user asm ret, inline. */\n" \
- "1:\t" "ld"#size "a [%1] %%asi, %0\n\n\t" \
- ".section __ex_table,\"a\"\n\t" \
- ".align 4\n\t" \
- ".word 1b,__ret_efault\n\n\t" \
- ".previous\n\t" \
- : "=r" (x) : "r" (__m(addr))); \
-else \
- __asm__ __volatile__( \
- "/* Get user asm ret, inline. */\n" \
- "1:\t" "ld"#size "a [%1] %%asi, %0\n\n\t" \
- ".section .fixup,#alloc,#execinstr\n\t" \
- ".align 4\n" \
- "3:\n\t" \
- "ret\n\t" \
- " restore %%g0, %2, %%o0\n\n\t" \
- ".previous\n\t" \
- ".section __ex_table,\"a\"\n\t" \
- ".align 4\n\t" \
- ".word 1b, 3b\n\n\t" \
- ".previous\n\t" \
- : "=r" (x) : "r" (__m(addr)), "i" (retval))
-
int __get_user_bad(void);
unsigned long __must_check ___copy_from_user(void *to,
diff --git a/arch/sparc/include/uapi/asm/unistd.h b/arch/sparc/include/uapi/asm/unistd.h
index efe9479..1c26d44 100644
--- a/arch/sparc/include/uapi/asm/unistd.h
+++ b/arch/sparc/include/uapi/asm/unistd.h
@@ -417,8 +417,13 @@
#define __NR_bpf 349
#define __NR_execveat 350
#define __NR_membarrier 351
+#define __NR_userfaultfd 352
+#define __NR_bind 353
+#define __NR_listen 354
+#define __NR_setsockopt 355
+#define __NR_mlock2 356
-#define NR_syscalls 352
+#define NR_syscalls 357
/* Bitmask values returned from kern_features system call. */
#define KERN_FEATURE_MIXED_MODE_STACK 0x00000001
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index 3d61fca..f2d30ca 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -946,6 +946,12 @@ ENTRY(__retl_one)
mov 1, %o0
ENDPROC(__retl_one)
+ENTRY(__retl_one_fp)
+ VISExitHalf
+ retl
+ mov 1, %o0
+ENDPROC(__retl_one_fp)
+
ENTRY(__ret_one_asi)
wr %g0, ASI_AIUS, %asi
ret
@@ -958,6 +964,13 @@ ENTRY(__retl_one_asi)
mov 1, %o0
ENDPROC(__retl_one_asi)
+ENTRY(__retl_one_asi_fp)
+ wr %g0, ASI_AIUS, %asi
+ VISExitHalf
+ retl
+ mov 1, %o0
+ENDPROC(__retl_one_asi_fp)
+
ENTRY(__retl_o1)
retl
mov %o1, %o0
diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c
index 6f80936..1122886 100644
--- a/arch/sparc/kernel/mdesc.c
+++ b/arch/sparc/kernel/mdesc.c
@@ -1033,25 +1033,9 @@ static ssize_t mdesc_read(struct file *file, char __user *buf,
static loff_t mdesc_llseek(struct file *file, loff_t offset, int whence)
{
- struct mdesc_handle *hp;
-
- switch (whence) {
- case SEEK_CUR:
- offset += file->f_pos;
- break;
- case SEEK_SET:
- break;
- default:
- return -EINVAL;
- }
-
- hp = file->private_data;
- if (offset > hp->handle_size)
- return -EINVAL;
- else
- file->f_pos = offset;
+ struct mdesc_handle *hp = file->private_data;
- return offset;
+ return no_seek_end_llseek_size(file, offset, whence, hp->handle_size);
}
/* mdesc_close() - /dev/mdesc is being closed, release the reference to
diff --git a/arch/sparc/kernel/perf_event.c b/arch/sparc/kernel/perf_event.c
index b0da5ae..6596f66 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -9,7 +9,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
*/
#include <linux/perf_event.h>
@@ -1828,11 +1828,18 @@ static void perf_callchain_user_32(struct perf_callchain_entry *entry,
void
perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
{
+ u64 saved_fault_address = current_thread_info()->fault_address;
+ u8 saved_fault_code = get_thread_fault_code();
+ mm_segment_t old_fs;
+
perf_callchain_store(entry, regs->tpc);
if (!current->mm)
return;
+ old_fs = get_fs();
+ set_fs(USER_DS);
+
flushw_user();
pagefault_disable();
@@ -1843,4 +1850,8 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
perf_callchain_user_64(entry, regs);
pagefault_enable();
+
+ set_fs(old_fs);
+ set_thread_fault_code(saved_fault_code);
+ current_thread_info()->fault_address = saved_fault_address;
}
diff --git a/arch/sparc/kernel/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S
index 39f0c66..d08bdaf 100644
--- a/arch/sparc/kernel/rtrap_64.S
+++ b/arch/sparc/kernel/rtrap_64.S
@@ -73,7 +73,13 @@ rtrap_nmi: ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
andn %l1, %l4, %l1
srl %l4, 20, %l4
ba,pt %xcc, rtrap_no_irq_enable
- wrpr %l4, %pil
+ nop
+ /* Do not actually set the %pil here. We will do that
+ * below after we clear PSTATE_IE in the %pstate register.
+ * If we re-enable interrupts here, we can recurse down
+ * the hardirq stack potentially endlessly, causing a
+ * stack overflow.
+ */
.align 64
.globl rtrap_irq, rtrap, irqsz_patchme, rtrap_xcall
diff --git a/arch/sparc/kernel/setup_64.c b/arch/sparc/kernel/setup_64.c
index f7b2617..f3185e2 100644
--- a/arch/sparc/kernel/setup_64.c
+++ b/arch/sparc/kernel/setup_64.c
@@ -380,7 +380,8 @@ static const char *hwcaps[] = {
*/
"mul32", "div32", "fsmuld", "v8plus", "popc", "vis", "vis2",
"ASIBlkInit", "fmaf", "vis3", "hpc", "random", "trans", "fjfmau",
- "ima", "cspare", "pause", "cbcond",
+ "ima", "cspare", "pause", "cbcond", NULL /*reserved for crypto */,
+ "adp",
};
static const char *crypto_hwcaps[] = {
@@ -396,7 +397,7 @@ void cpucap_info(struct seq_file *m)
seq_puts(m, "cpucaps\t\t: ");
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
unsigned long bit = 1UL << i;
- if (caps & bit) {
+ if (hwcaps[i] && (caps & bit)) {
seq_printf(m, "%s%s",
printed ? "," : "", hwcaps[i]);
printed++;
@@ -450,7 +451,7 @@ static void __init report_hwcaps(unsigned long caps)
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
unsigned long bit = 1UL << i;
- if (caps & bit)
+ if (hwcaps[i] && (caps & bit))
report_one_hwcap(&printed, hwcaps[i]);
}
if (caps & HWCAP_SPARC_CRYPTO)
@@ -485,7 +486,7 @@ static unsigned long __init mdesc_cpu_hwcap_list(void)
for (i = 0; i < ARRAY_SIZE(hwcaps); i++) {
unsigned long bit = 1UL << i;
- if (!strcmp(prop, hwcaps[i])) {
+ if (hwcaps[i] && !strcmp(prop, hwcaps[i])) {
caps |= bit;
break;
}
diff --git a/arch/sparc/kernel/systbls_32.S b/arch/sparc/kernel/systbls_32.S
index cc23b62..e663b6c 100644
--- a/arch/sparc/kernel/systbls_32.S
+++ b/arch/sparc/kernel/systbls_32.S
@@ -35,18 +35,18 @@ sys_call_table:
/*80*/ .long sys_setgroups16, sys_getpgrp, sys_setgroups, sys_setitimer, sys_ftruncate64
/*85*/ .long sys_swapon, sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
/*90*/ .long sys_dup2, sys_setfsuid, sys_fcntl, sys_select, sys_setfsgid
-/*95*/ .long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*95*/ .long sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
/*100*/ .long sys_getpriority, sys_rt_sigreturn, sys_rt_sigaction, sys_rt_sigprocmask, sys_rt_sigpending
/*105*/ .long sys_rt_sigtimedwait, sys_rt_sigqueueinfo, sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/ .long sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
-/*115*/ .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/ .long sys_setresgid, sys_getresgid, sys_setregid, sys_recvmsg, sys_sendmsg
+/*115*/ .long sys_getgroups, sys_gettimeofday, sys_getrusage, sys_getsockopt, sys_getcwd
/*120*/ .long sys_readv, sys_writev, sys_settimeofday, sys_fchown16, sys_fchmod
-/*125*/ .long sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
-/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-/*135*/ .long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
-/*140*/ .long sys_sendfile64, sys_nis_syscall, sys_futex, sys_gettid, sys_getrlimit
+/*125*/ .long sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate
+/*130*/ .long sys_ftruncate, sys_flock, sys_lstat64, sys_sendto, sys_shutdown
+/*135*/ .long sys_socketpair, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
+/*140*/ .long sys_sendfile64, sys_getpeername, sys_futex, sys_gettid, sys_getrlimit
/*145*/ .long sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
-/*150*/ .long sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
+/*150*/ .long sys_getsockname, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
/*155*/ .long sys_fcntl64, sys_inotify_rm_watch, sys_statfs, sys_fstatfs, sys_oldumount
/*160*/ .long sys_sched_setaffinity, sys_sched_getaffinity, sys_getdomainname, sys_setdomainname, sys_nis_syscall
/*165*/ .long sys_quotactl, sys_set_tid_address, sys_mount, sys_ustat, sys_setxattr
@@ -87,4 +87,5 @@ sys_call_table:
/*335*/ .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
/*340*/ .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
/*345*/ .long sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/ .long sys_execveat, sys_membarrier
+/*350*/ .long sys_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+/*355*/ .long sys_setsockopt, sys_mlock2
diff --git a/arch/sparc/kernel/systbls_64.S b/arch/sparc/kernel/systbls_64.S
index f229468..1557121 100644
--- a/arch/sparc/kernel/systbls_64.S
+++ b/arch/sparc/kernel/systbls_64.S
@@ -37,15 +37,15 @@ sys_call_table32:
/*80*/ .word sys_setgroups16, sys_getpgrp, sys_setgroups, compat_sys_setitimer, sys32_ftruncate64
.word sys_swapon, compat_sys_getitimer, sys_setuid, sys_sethostname, sys_setgid
/*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid
- .word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+ .word sys_fsync, sys_setpriority, sys_socket, sys_connect, sys_accept
/*100*/ .word sys_getpriority, sys32_rt_sigreturn, compat_sys_rt_sigaction, compat_sys_rt_sigprocmask, compat_sys_rt_sigpending
.word compat_sys_rt_sigtimedwait, compat_sys_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid
-/*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall
- .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, sys_nis_syscall, sys_getcwd
+/*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, compat_sys_recvmsg, compat_sys_sendmsg
+ .word sys_getgroups, compat_sys_gettimeofday, compat_sys_getrusage, compat_sys_getsockopt, sys_getcwd
/*120*/ .word compat_sys_readv, compat_sys_writev, compat_sys_settimeofday, sys_fchown16, sys_fchmod
- .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
-/*130*/ .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
+ .word sys_recvfrom, sys_setreuid16, sys_setregid16, sys_rename, compat_sys_truncate
+/*130*/ .word compat_sys_ftruncate, sys_flock, compat_sys_lstat64, sys_sendto, sys_shutdown
+ .word sys_socketpair, sys_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
/*140*/ .word sys_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
.word compat_sys_setrlimit, sys_pivot_root, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
@@ -88,7 +88,8 @@ sys_call_table32:
.word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
.word sys32_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/ .word sys32_execveat, sys_membarrier
+/*350*/ .word sys32_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+ .word compat_sys_setsockopt, sys_mlock2
#endif /* CONFIG_COMPAT */
@@ -168,4 +169,5 @@ sys_call_table:
.word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
/*340*/ .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
.word sys_renameat2, sys_seccomp, sys_getrandom, sys_memfd_create, sys_bpf
-/*350*/ .word sys64_execveat, sys_membarrier
+/*350*/ .word sys64_execveat, sys_membarrier, sys_userfaultfd, sys_bind, sys_listen
+ .word sys_setsockopt, sys_mlock2
diff --git a/arch/sparc/lib/NG2copy_from_user.S b/arch/sparc/lib/NG2copy_from_user.S
index 119ccb9..d5242b8 100644
--- a/arch/sparc/lib/NG2copy_from_user.S
+++ b/arch/sparc/lib/NG2copy_from_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_LD_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_asi_fp;\
+ .text; \
+ .align 4;
+
#ifndef ASI_AIUS
#define ASI_AIUS 0x11
#endif
diff --git a/arch/sparc/lib/NG2copy_to_user.S b/arch/sparc/lib/NG2copy_to_user.S
index 7fe1cce..4e962d9 100644
--- a/arch/sparc/lib/NG2copy_to_user.S
+++ b/arch/sparc/lib/NG2copy_to_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_ST_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_asi_fp;\
+ .text; \
+ .align 4;
+
#ifndef ASI_AIUS
#define ASI_AIUS 0x11
#endif
diff --git a/arch/sparc/lib/NG2memcpy.S b/arch/sparc/lib/NG2memcpy.S
index 30eee6e..d5f585d 100644
--- a/arch/sparc/lib/NG2memcpy.S
+++ b/arch/sparc/lib/NG2memcpy.S
@@ -34,10 +34,16 @@
#ifndef EX_LD
#define EX_LD(x) x
#endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x) x
+#endif
#ifndef EX_ST
#define EX_ST(x) x
#endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x) x
+#endif
#ifndef EX_RETVAL
#define EX_RETVAL(x) x
@@ -134,40 +140,40 @@
fsrc2 %x6, %f12; \
fsrc2 %x7, %f14;
#define FREG_LOAD_1(base, x0) \
- EX_LD(LOAD(ldd, base + 0x00, %x0))
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0))
#define FREG_LOAD_2(base, x0, x1) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1));
#define FREG_LOAD_3(base, x0, x1, x2) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1)); \
- EX_LD(LOAD(ldd, base + 0x10, %x2));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+ EX_LD_FP(LOAD(ldd, base + 0x10, %x2));
#define FREG_LOAD_4(base, x0, x1, x2, x3) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1)); \
- EX_LD(LOAD(ldd, base + 0x10, %x2)); \
- EX_LD(LOAD(ldd, base + 0x18, %x3));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+ EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+ EX_LD_FP(LOAD(ldd, base + 0x18, %x3));
#define FREG_LOAD_5(base, x0, x1, x2, x3, x4) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1)); \
- EX_LD(LOAD(ldd, base + 0x10, %x2)); \
- EX_LD(LOAD(ldd, base + 0x18, %x3)); \
- EX_LD(LOAD(ldd, base + 0x20, %x4));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+ EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+ EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+ EX_LD_FP(LOAD(ldd, base + 0x20, %x4));
#define FREG_LOAD_6(base, x0, x1, x2, x3, x4, x5) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1)); \
- EX_LD(LOAD(ldd, base + 0x10, %x2)); \
- EX_LD(LOAD(ldd, base + 0x18, %x3)); \
- EX_LD(LOAD(ldd, base + 0x20, %x4)); \
- EX_LD(LOAD(ldd, base + 0x28, %x5));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+ EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+ EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+ EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
+ EX_LD_FP(LOAD(ldd, base + 0x28, %x5));
#define FREG_LOAD_7(base, x0, x1, x2, x3, x4, x5, x6) \
- EX_LD(LOAD(ldd, base + 0x00, %x0)); \
- EX_LD(LOAD(ldd, base + 0x08, %x1)); \
- EX_LD(LOAD(ldd, base + 0x10, %x2)); \
- EX_LD(LOAD(ldd, base + 0x18, %x3)); \
- EX_LD(LOAD(ldd, base + 0x20, %x4)); \
- EX_LD(LOAD(ldd, base + 0x28, %x5)); \
- EX_LD(LOAD(ldd, base + 0x30, %x6));
+ EX_LD_FP(LOAD(ldd, base + 0x00, %x0)); \
+ EX_LD_FP(LOAD(ldd, base + 0x08, %x1)); \
+ EX_LD_FP(LOAD(ldd, base + 0x10, %x2)); \
+ EX_LD_FP(LOAD(ldd, base + 0x18, %x3)); \
+ EX_LD_FP(LOAD(ldd, base + 0x20, %x4)); \
+ EX_LD_FP(LOAD(ldd, base + 0x28, %x5)); \
+ EX_LD_FP(LOAD(ldd, base + 0x30, %x6));
.register %g2,#scratch
.register %g3,#scratch
@@ -275,11 +281,11 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
nop
/* fall through for 0 < low bits < 8 */
110: sub %o4, 64, %g2
- EX_LD(LOAD_BLK(%g2, %f0))
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+ EX_LD_FP(LOAD_BLK(%g2, %f0))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f14, f16)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_8(f16, f18, f20, f22, f24, f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -290,10 +296,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
120: sub %o4, 56, %g2
FREG_LOAD_7(%g2, f0, f2, f4, f6, f8, f10, f12)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f6, f8, f10, f12, f16, f18)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_7(f18, f20, f22, f24, f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -304,10 +310,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
130: sub %o4, 48, %g2
FREG_LOAD_6(%g2, f0, f2, f4, f6, f8, f10)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f6, f8, f10, f16, f18, f20)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_6(f20, f22, f24, f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -318,10 +324,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
140: sub %o4, 40, %g2
FREG_LOAD_5(%g2, f0, f2, f4, f6, f8)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f6, f8, f16, f18, f20, f22)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_5(f22, f24, f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -332,10 +338,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
150: sub %o4, 32, %g2
FREG_LOAD_4(%g2, f0, f2, f4, f6)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f6, f16, f18, f20, f22, f24)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_4(f24, f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -346,10 +352,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
160: sub %o4, 24, %g2
FREG_LOAD_3(%g2, f0, f2, f4)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f4, f16, f18, f20, f22, f24, f26)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_3(f26, f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -360,10 +366,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
170: sub %o4, 16, %g2
FREG_LOAD_2(%g2, f0, f2)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f2, f16, f18, f20, f22, f24, f26, f28)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_2(f28, f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -374,10 +380,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
180: sub %o4, 8, %g2
FREG_LOAD_1(%g2, f0)
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
- EX_LD(LOAD_BLK(%o4, %f16))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f16))
FREG_FROB(f0, f16, f18, f20, f22, f24, f26, f28, f30)
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
FREG_MOVE_1(f30)
subcc %g1, 64, %g1
add %o4, 64, %o4
@@ -387,10 +393,10 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
nop
190:
-1: EX_ST(STORE_INIT(%g0, %o4 + %g3))
+1: EX_ST_FP(STORE_INIT(%g0, %o4 + %g3))
subcc %g1, 64, %g1
- EX_LD(LOAD_BLK(%o4, %f0))
- EX_ST(STORE_BLK(%f0, %o4 + %g3))
+ EX_LD_FP(LOAD_BLK(%o4, %f0))
+ EX_ST_FP(STORE_BLK(%f0, %o4 + %g3))
add %o4, 64, %o4
bne,pt %xcc, 1b
LOAD(prefetch, %o4 + 64, #one_read)
diff --git a/arch/sparc/lib/NG4copy_from_user.S b/arch/sparc/lib/NG4copy_from_user.S
index fd9f903..2e8ee7a 100644
--- a/arch/sparc/lib/NG4copy_from_user.S
+++ b/arch/sparc/lib/NG4copy_from_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_LD_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_asi_fp;\
+ .text; \
+ .align 4;
+
#ifndef ASI_AIUS
#define ASI_AIUS 0x11
#endif
diff --git a/arch/sparc/lib/NG4copy_to_user.S b/arch/sparc/lib/NG4copy_to_user.S
index 9744c454..be0bf45 100644
--- a/arch/sparc/lib/NG4copy_to_user.S
+++ b/arch/sparc/lib/NG4copy_to_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_ST_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_asi_fp;\
+ .text; \
+ .align 4;
+
#ifndef ASI_AIUS
#define ASI_AIUS 0x11
#endif
diff --git a/arch/sparc/lib/NG4memcpy.S b/arch/sparc/lib/NG4memcpy.S
index 83aeeb1..8e13ee1 100644
--- a/arch/sparc/lib/NG4memcpy.S
+++ b/arch/sparc/lib/NG4memcpy.S
@@ -48,10 +48,16 @@
#ifndef EX_LD
#define EX_LD(x) x
#endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x) x
+#endif
#ifndef EX_ST
#define EX_ST(x) x
#endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x) x
+#endif
#ifndef EX_RETVAL
#define EX_RETVAL(x) x
@@ -210,17 +216,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
sub %o2, %o4, %o2
alignaddr %o1, %g0, %g1
add %o1, %o4, %o1
- EX_LD(LOAD(ldd, %g1 + 0x00, %f0))
-1: EX_LD(LOAD(ldd, %g1 + 0x08, %f2))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x00, %f0))
+1: EX_LD_FP(LOAD(ldd, %g1 + 0x08, %f2))
subcc %o4, 0x40, %o4
- EX_LD(LOAD(ldd, %g1 + 0x10, %f4))
- EX_LD(LOAD(ldd, %g1 + 0x18, %f6))
- EX_LD(LOAD(ldd, %g1 + 0x20, %f8))
- EX_LD(LOAD(ldd, %g1 + 0x28, %f10))
- EX_LD(LOAD(ldd, %g1 + 0x30, %f12))
- EX_LD(LOAD(ldd, %g1 + 0x38, %f14))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x10, %f4))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x18, %f6))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x20, %f8))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x28, %f10))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x30, %f12))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x38, %f14))
faligndata %f0, %f2, %f16
- EX_LD(LOAD(ldd, %g1 + 0x40, %f0))
+ EX_LD_FP(LOAD(ldd, %g1 + 0x40, %f0))
faligndata %f2, %f4, %f18
add %g1, 0x40, %g1
faligndata %f4, %f6, %f20
@@ -229,14 +235,14 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
faligndata %f10, %f12, %f26
faligndata %f12, %f14, %f28
faligndata %f14, %f0, %f30
- EX_ST(STORE(std, %f16, %o0 + 0x00))
- EX_ST(STORE(std, %f18, %o0 + 0x08))
- EX_ST(STORE(std, %f20, %o0 + 0x10))
- EX_ST(STORE(std, %f22, %o0 + 0x18))
- EX_ST(STORE(std, %f24, %o0 + 0x20))
- EX_ST(STORE(std, %f26, %o0 + 0x28))
- EX_ST(STORE(std, %f28, %o0 + 0x30))
- EX_ST(STORE(std, %f30, %o0 + 0x38))
+ EX_ST_FP(STORE(std, %f16, %o0 + 0x00))
+ EX_ST_FP(STORE(std, %f18, %o0 + 0x08))
+ EX_ST_FP(STORE(std, %f20, %o0 + 0x10))
+ EX_ST_FP(STORE(std, %f22, %o0 + 0x18))
+ EX_ST_FP(STORE(std, %f24, %o0 + 0x20))
+ EX_ST_FP(STORE(std, %f26, %o0 + 0x28))
+ EX_ST_FP(STORE(std, %f28, %o0 + 0x30))
+ EX_ST_FP(STORE(std, %f30, %o0 + 0x38))
add %o0, 0x40, %o0
bne,pt %icc, 1b
LOAD(prefetch, %g1 + 0x200, #n_reads_strong)
diff --git a/arch/sparc/lib/U1copy_from_user.S b/arch/sparc/lib/U1copy_from_user.S
index a6ae2ea..ecc5692 100644
--- a/arch/sparc/lib/U1copy_from_user.S
+++ b/arch/sparc/lib/U1copy_from_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_LD_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_fp;\
+ .text; \
+ .align 4;
+
#define FUNC_NAME ___copy_from_user
#define LOAD(type,addr,dest) type##a [addr] %asi, dest
#define LOAD_BLK(addr,dest) ldda [addr] ASI_BLK_AIUS, dest
diff --git a/arch/sparc/lib/U1copy_to_user.S b/arch/sparc/lib/U1copy_to_user.S
index f4b970e..9eea392 100644
--- a/arch/sparc/lib/U1copy_to_user.S
+++ b/arch/sparc/lib/U1copy_to_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_ST_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_fp;\
+ .text; \
+ .align 4;
+
#define FUNC_NAME ___copy_to_user
#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS
#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS
diff --git a/arch/sparc/lib/U1memcpy.S b/arch/sparc/lib/U1memcpy.S
index b67142b..3e6209e 100644
--- a/arch/sparc/lib/U1memcpy.S
+++ b/arch/sparc/lib/U1memcpy.S
@@ -25,10 +25,16 @@
#ifndef EX_LD
#define EX_LD(x) x
#endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x) x
+#endif
#ifndef EX_ST
#define EX_ST(x) x
#endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x) x
+#endif
#ifndef EX_RETVAL
#define EX_RETVAL(x) x
@@ -73,8 +79,8 @@
faligndata %f8, %f9, %f62;
#define MAIN_LOOP_CHUNK(src, dest, fdest, fsrc, len, jmptgt) \
- EX_LD(LOAD_BLK(%src, %fdest)); \
- EX_ST(STORE_BLK(%fsrc, %dest)); \
+ EX_LD_FP(LOAD_BLK(%src, %fdest)); \
+ EX_ST_FP(STORE_BLK(%fsrc, %dest)); \
add %src, 0x40, %src; \
subcc %len, 0x40, %len; \
be,pn %xcc, jmptgt; \
@@ -89,12 +95,12 @@
#define DO_SYNC membar #Sync;
#define STORE_SYNC(dest, fsrc) \
- EX_ST(STORE_BLK(%fsrc, %dest)); \
+ EX_ST_FP(STORE_BLK(%fsrc, %dest)); \
add %dest, 0x40, %dest; \
DO_SYNC
#define STORE_JUMP(dest, fsrc, target) \
- EX_ST(STORE_BLK(%fsrc, %dest)); \
+ EX_ST_FP(STORE_BLK(%fsrc, %dest)); \
add %dest, 0x40, %dest; \
ba,pt %xcc, target; \
nop;
@@ -103,7 +109,7 @@
subcc %left, 8, %left;\
bl,pn %xcc, 95f; \
faligndata %f0, %f1, %f48; \
- EX_ST(STORE(std, %f48, %dest)); \
+ EX_ST_FP(STORE(std, %f48, %dest)); \
add %dest, 8, %dest;
#define UNEVEN_VISCHUNK_LAST(dest, f0, f1, left) \
@@ -160,8 +166,8 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
and %g2, 0x38, %g2
1: subcc %g1, 0x1, %g1
- EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
- EX_ST(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
+ EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
+ EX_ST_FP(STORE(stb, %o3, %o1 + %GLOBAL_SPARE))
bgu,pt %XCC, 1b
add %o1, 0x1, %o1
@@ -172,20 +178,20 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
be,pt %icc, 3f
alignaddr %o1, %g0, %o1
- EX_LD(LOAD(ldd, %o1, %f4))
-1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6))
+ EX_LD_FP(LOAD(ldd, %o1, %f4))
+1: EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f4, %f6, %f0
- EX_ST(STORE(std, %f0, %o0))
+ EX_ST_FP(STORE(std, %f0, %o0))
be,pn %icc, 3f
add %o0, 0x8, %o0
- EX_LD(LOAD(ldd, %o1 + 0x8, %f4))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f6, %f4, %f0
- EX_ST(STORE(std, %f0, %o0))
+ EX_ST_FP(STORE(std, %f0, %o0))
bne,pt %icc, 1b
add %o0, 0x8, %o0
@@ -208,13 +214,13 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
add %g1, %GLOBAL_SPARE, %g1
subcc %o2, %g3, %o2
- EX_LD(LOAD_BLK(%o1, %f0))
+ EX_LD_FP(LOAD_BLK(%o1, %f0))
add %o1, 0x40, %o1
add %g1, %g3, %g1
- EX_LD(LOAD_BLK(%o1, %f16))
+ EX_LD_FP(LOAD_BLK(%o1, %f16))
add %o1, 0x40, %o1
sub %GLOBAL_SPARE, 0x80, %GLOBAL_SPARE
- EX_LD(LOAD_BLK(%o1, %f32))
+ EX_LD_FP(LOAD_BLK(%o1, %f32))
add %o1, 0x40, %o1
/* There are 8 instances of the unrolled loop,
@@ -426,28 +432,28 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
62: FINISH_VISCHUNK(o0, f44, f46, g3)
63: UNEVEN_VISCHUNK_LAST(o0, f46, f0, g3)
-93: EX_LD(LOAD(ldd, %o1, %f2))
+93: EX_LD_FP(LOAD(ldd, %o1, %f2))
add %o1, 8, %o1
subcc %g3, 8, %g3
faligndata %f0, %f2, %f8
- EX_ST(STORE(std, %f8, %o0))
+ EX_ST_FP(STORE(std, %f8, %o0))
bl,pn %xcc, 95f
add %o0, 8, %o0
- EX_LD(LOAD(ldd, %o1, %f0))
+ EX_LD_FP(LOAD(ldd, %o1, %f0))
add %o1, 8, %o1
subcc %g3, 8, %g3
faligndata %f2, %f0, %f8
- EX_ST(STORE(std, %f8, %o0))
+ EX_ST_FP(STORE(std, %f8, %o0))
bge,pt %xcc, 93b
add %o0, 8, %o0
95: brz,pt %o2, 2f
mov %g1, %o1
-1: EX_LD(LOAD(ldub, %o1, %o3))
+1: EX_LD_FP(LOAD(ldub, %o1, %o3))
add %o1, 1, %o1
subcc %o2, 1, %o2
- EX_ST(STORE(stb, %o3, %o0))
+ EX_ST_FP(STORE(stb, %o3, %o0))
bne,pt %xcc, 1b
add %o0, 1, %o0
diff --git a/arch/sparc/lib/U3copy_from_user.S b/arch/sparc/lib/U3copy_from_user.S
index b1acd13..88ad73d 100644
--- a/arch/sparc/lib/U3copy_from_user.S
+++ b/arch/sparc/lib/U3copy_from_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_LD_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_fp;\
+ .text; \
+ .align 4;
+
#define FUNC_NAME U3copy_from_user
#define LOAD(type,addr,dest) type##a [addr] %asi, dest
#define EX_RETVAL(x) 0
diff --git a/arch/sparc/lib/U3copy_to_user.S b/arch/sparc/lib/U3copy_to_user.S
index ef1e493..845139d 100644
--- a/arch/sparc/lib/U3copy_to_user.S
+++ b/arch/sparc/lib/U3copy_to_user.S
@@ -11,6 +11,14 @@
.text; \
.align 4;
+#define EX_ST_FP(x) \
+98: x; \
+ .section __ex_table,"a";\
+ .align 4; \
+ .word 98b, __retl_one_fp;\
+ .text; \
+ .align 4;
+
#define FUNC_NAME U3copy_to_user
#define STORE(type,src,addr) type##a src, [addr] ASI_AIUS
#define STORE_BLK(src,addr) stda src, [addr] ASI_BLK_AIUS
diff --git a/arch/sparc/lib/U3memcpy.S b/arch/sparc/lib/U3memcpy.S
index 7cae9cc..491ee69 100644
--- a/arch/sparc/lib/U3memcpy.S
+++ b/arch/sparc/lib/U3memcpy.S
@@ -24,10 +24,16 @@
#ifndef EX_LD
#define EX_LD(x) x
#endif
+#ifndef EX_LD_FP
+#define EX_LD_FP(x) x
+#endif
#ifndef EX_ST
#define EX_ST(x) x
#endif
+#ifndef EX_ST_FP
+#define EX_ST_FP(x) x
+#endif
#ifndef EX_RETVAL
#define EX_RETVAL(x) x
@@ -120,8 +126,8 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
and %g2, 0x38, %g2
1: subcc %g1, 0x1, %g1
- EX_LD(LOAD(ldub, %o1 + 0x00, %o3))
- EX_ST(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
+ EX_LD_FP(LOAD(ldub, %o1 + 0x00, %o3))
+ EX_ST_FP(STORE(stb, %o3, %o1 + GLOBAL_SPARE))
bgu,pt %XCC, 1b
add %o1, 0x1, %o1
@@ -132,20 +138,20 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
be,pt %icc, 3f
alignaddr %o1, %g0, %o1
- EX_LD(LOAD(ldd, %o1, %f4))
-1: EX_LD(LOAD(ldd, %o1 + 0x8, %f6))
+ EX_LD_FP(LOAD(ldd, %o1, %f4))
+1: EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f6))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f4, %f6, %f0
- EX_ST(STORE(std, %f0, %o0))
+ EX_ST_FP(STORE(std, %f0, %o0))
be,pn %icc, 3f
add %o0, 0x8, %o0
- EX_LD(LOAD(ldd, %o1 + 0x8, %f4))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x8, %f4))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f6, %f4, %f2
- EX_ST(STORE(std, %f2, %o0))
+ EX_ST_FP(STORE(std, %f2, %o0))
bne,pt %icc, 1b
add %o0, 0x8, %o0
@@ -155,25 +161,25 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
LOAD(prefetch, %o1 + 0x080, #one_read)
LOAD(prefetch, %o1 + 0x0c0, #one_read)
LOAD(prefetch, %o1 + 0x100, #one_read)
- EX_LD(LOAD(ldd, %o1 + 0x000, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x000, %f0))
LOAD(prefetch, %o1 + 0x140, #one_read)
- EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
LOAD(prefetch, %o1 + 0x180, #one_read)
- EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
LOAD(prefetch, %o1 + 0x1c0, #one_read)
faligndata %f0, %f2, %f16
- EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
faligndata %f2, %f4, %f18
- EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
faligndata %f4, %f6, %f20
- EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
faligndata %f6, %f8, %f22
- EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
faligndata %f8, %f10, %f24
- EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
faligndata %f10, %f12, %f26
- EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
subcc GLOBAL_SPARE, 0x80, GLOBAL_SPARE
add %o1, 0x40, %o1
@@ -184,26 +190,26 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
.align 64
1:
- EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
faligndata %f12, %f14, %f28
- EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
faligndata %f14, %f0, %f30
- EX_ST(STORE_BLK(%f16, %o0))
- EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+ EX_ST_FP(STORE_BLK(%f16, %o0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
faligndata %f0, %f2, %f16
add %o0, 0x40, %o0
- EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
faligndata %f2, %f4, %f18
- EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
faligndata %f4, %f6, %f20
- EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
subcc %o3, 0x01, %o3
faligndata %f6, %f8, %f22
- EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
faligndata %f8, %f10, %f24
- EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
LOAD(prefetch, %o1 + 0x1c0, #one_read)
faligndata %f10, %f12, %f26
bg,pt %XCC, 1b
@@ -211,29 +217,29 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
/* Finally we copy the last full 64-byte block. */
2:
- EX_LD(LOAD(ldd, %o1 + 0x008, %f2))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x008, %f2))
faligndata %f12, %f14, %f28
- EX_LD(LOAD(ldd, %o1 + 0x010, %f4))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x010, %f4))
faligndata %f14, %f0, %f30
- EX_ST(STORE_BLK(%f16, %o0))
- EX_LD(LOAD(ldd, %o1 + 0x018, %f6))
+ EX_ST_FP(STORE_BLK(%f16, %o0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x018, %f6))
faligndata %f0, %f2, %f16
- EX_LD(LOAD(ldd, %o1 + 0x020, %f8))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x020, %f8))
faligndata %f2, %f4, %f18
- EX_LD(LOAD(ldd, %o1 + 0x028, %f10))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x028, %f10))
faligndata %f4, %f6, %f20
- EX_LD(LOAD(ldd, %o1 + 0x030, %f12))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x030, %f12))
faligndata %f6, %f8, %f22
- EX_LD(LOAD(ldd, %o1 + 0x038, %f14))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x038, %f14))
faligndata %f8, %f10, %f24
cmp %g1, 0
be,pt %XCC, 1f
add %o0, 0x40, %o0
- EX_LD(LOAD(ldd, %o1 + 0x040, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x040, %f0))
1: faligndata %f10, %f12, %f26
faligndata %f12, %f14, %f28
faligndata %f14, %f0, %f30
- EX_ST(STORE_BLK(%f16, %o0))
+ EX_ST_FP(STORE_BLK(%f16, %o0))
add %o0, 0x40, %o0
add %o1, 0x40, %o1
membar #Sync
@@ -253,20 +259,20 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
sub %o2, %g2, %o2
be,a,pt %XCC, 1f
- EX_LD(LOAD(ldd, %o1 + 0x00, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x00, %f0))
-1: EX_LD(LOAD(ldd, %o1 + 0x08, %f2))
+1: EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f2))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f0, %f2, %f8
- EX_ST(STORE(std, %f8, %o0))
+ EX_ST_FP(STORE(std, %f8, %o0))
be,pn %XCC, 2f
add %o0, 0x8, %o0
- EX_LD(LOAD(ldd, %o1 + 0x08, %f0))
+ EX_LD_FP(LOAD(ldd, %o1 + 0x08, %f0))
add %o1, 0x8, %o1
subcc %g2, 0x8, %g2
faligndata %f2, %f0, %f8
- EX_ST(STORE(std, %f8, %o0))
+ EX_ST_FP(STORE(std, %f8, %o0))
bne,pn %XCC, 1b
add %o0, 0x8, %o0
diff --git a/arch/sparc/net/bpf_jit_comp.c b/arch/sparc/net/bpf_jit_comp.c
index 22564f5..3e6e05a 100644
--- a/arch/sparc/net/bpf_jit_comp.c
+++ b/arch/sparc/net/bpf_jit_comp.c
@@ -420,22 +420,9 @@ void bpf_jit_compile(struct bpf_prog *fp)
}
emit_reg_move(O7, r_saved_O7);
- switch (filter[0].code) {
- case BPF_RET | BPF_K:
- case BPF_LD | BPF_W | BPF_LEN:
- case BPF_LD | BPF_W | BPF_ABS:
- case BPF_LD | BPF_H | BPF_ABS:
- case BPF_LD | BPF_B | BPF_ABS:
- /* The first instruction sets the A register (or is
- * a "RET 'constant'")
- */
- break;
- default:
- /* Make sure we dont leak kernel information to the
- * user.
- */
+ /* Make sure we dont leak kernel information to the user. */
+ if (bpf_needs_clear_a(&filter[0]))
emit_clear(r_A); /* A = 0 */
- }
for (i = 0; i < flen; i++) {
unsigned int K = filter[i].k;
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 106c21b..8ec7a45 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
@@ -176,8 +176,6 @@ config NR_CPUS
smaller kernel memory footprint results from using a smaller
value on chips with fewer tiles.
-if TILEGX
-
choice
prompt "Kernel page size"
default PAGE_SIZE_64KB
@@ -188,8 +186,11 @@ choice
connections, etc., it may be better to select 16KB, which uses
memory more efficiently at some cost in TLB performance.
- Note that this option is TILE-Gx specific; currently
- TILEPro page size is set by rebuilding the hypervisor.
+ Note that for TILEPro, you must also rebuild the hypervisor
+ with a matching page size.
+
+config PAGE_SIZE_4KB
+ bool "4KB" if TILEPRO
config PAGE_SIZE_16KB
bool "16KB"
@@ -199,8 +200,6 @@ config PAGE_SIZE_64KB
endchoice
-endif
-
source "kernel/Kconfig.hz"
config KEXEC
diff --git a/arch/tile/include/asm/cmpxchg.h b/arch/tile/include/asm/cmpxchg.h
index 0ccda3c..25d5899 100644
--- a/arch/tile/include/asm/cmpxchg.h
+++ b/arch/tile/include/asm/cmpxchg.h
@@ -127,8 +127,6 @@ long long _atomic64_cmpxchg(long long *v, long long o, long long n);
#endif
-#define tas(ptr) xchg((ptr), 1)
-
#endif /* __ASSEMBLY__ */
#endif /* _ASM_TILE_CMPXCHG_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index a213a8d..8eca6a0 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
@@ -20,15 +20,17 @@
#include <arch/chip.h>
/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
-#if defined(CONFIG_PAGE_SIZE_16KB)
+#if defined(CONFIG_PAGE_SIZE_4KB) /* tilepro only */
+#define PAGE_SHIFT 12
+#define CTX_PAGE_FLAG HV_CTX_PG_SM_4K
+#elif defined(CONFIG_PAGE_SIZE_16KB)
#define PAGE_SHIFT 14
#define CTX_PAGE_FLAG HV_CTX_PG_SM_16K
#elif defined(CONFIG_PAGE_SIZE_64KB)
#define PAGE_SHIFT 16
#define CTX_PAGE_FLAG HV_CTX_PG_SM_64K
#else
-#define PAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_SMALL
-#define CTX_PAGE_FLAG 0
+#error Page size not specified in Kconfig
#endif
#define HPAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_LARGE
diff --git a/arch/tile/kernel/perf_event.c b/arch/tile/kernel/perf_event.c
index bb509ce..8767060 100644
--- a/arch/tile/kernel/perf_event.c
+++ b/arch/tile/kernel/perf_event.c
@@ -21,7 +21,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
* Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
* Copyright (C) 2009 Google, Inc., Stephane Eranian
*/
diff --git a/arch/um/Kconfig.common b/arch/um/Kconfig.common
index d195a87..cc00134 100644
--- a/arch/um/Kconfig.common
+++ b/arch/um/Kconfig.common
@@ -2,6 +2,7 @@ config UML
bool
default y
select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_SECCOMP_FILTER
select HAVE_UID16
select HAVE_FUTEX_CMPXCHG if FUTEX
select GENERIC_IRQ_SHOW
diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um
index 28a9885..4b2ed58 100644
--- a/arch/um/Kconfig.um
+++ b/arch/um/Kconfig.um
@@ -104,3 +104,19 @@ config PGTABLE_LEVELS
int
default 3 if 3_LEVEL_PGTABLES
default 2
+
+config SECCOMP
+ def_bool y
+ prompt "Enable seccomp to safely compute untrusted bytecode"
+ ---help---
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
+ If unsure, say Y.
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index f6b911c..3a4b587 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -105,13 +105,9 @@ static ssize_t hostaudio_write(struct file *file, const char __user *buffer,
printk(KERN_DEBUG "hostaudio: write called, count = %d\n", count);
#endif
- kbuf = kmalloc(count, GFP_KERNEL);
- if (kbuf == NULL)
- return -ENOMEM;
-
- err = -EFAULT;
- if (copy_from_user(kbuf, buffer, count))
- goto out;
+ kbuf = memdup_user(buffer, count);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
err = os_write_file(state->fd, kbuf, count);
if (err < 0)
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 29880c9..b821b13 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -748,19 +748,11 @@ static ssize_t mconsole_proc_write(struct file *file,
{
char *buf;
- buf = kmalloc(count + 1, GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- if (copy_from_user(buf, buffer, count)) {
- count = -EFAULT;
- goto out;
- }
-
- buf[count] = '\0';
+ buf = memdup_user_nul(buffer, count);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
mconsole_notify(notify_socket, MCONSOLE_USER_NOTIFY, buf, count);
- out:
kfree(buf);
return count;
}
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index f70dd54..9ef669d 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -388,7 +388,7 @@ static const struct net_device_ops uml_netdev_ops = {
static int driver_registered;
static void eth_configure(int n, void *init, char *mac,
- struct transport *transport)
+ struct transport *transport, gfp_t gfp_mask)
{
struct uml_net *device;
struct net_device *dev;
@@ -397,7 +397,7 @@ static void eth_configure(int n, void *init, char *mac,
size = transport->private_size + sizeof(struct uml_net_private);
- device = kzalloc(sizeof(*device), GFP_KERNEL);
+ device = kzalloc(sizeof(*device), gfp_mask);
if (device == NULL) {
printk(KERN_ERR "eth_configure failed to allocate struct "
"uml_net\n");
@@ -568,7 +568,7 @@ static LIST_HEAD(transports);
static LIST_HEAD(eth_cmd_line);
static int check_transport(struct transport *transport, char *eth, int n,
- void **init_out, char **mac_out)
+ void **init_out, char **mac_out, gfp_t gfp_mask)
{
int len;
@@ -582,7 +582,7 @@ static int check_transport(struct transport *transport, char *eth, int n,
else if (*eth != '\0')
return 0;
- *init_out = kmalloc(transport->setup_size, GFP_KERNEL);
+ *init_out = kmalloc(transport->setup_size, gfp_mask);
if (*init_out == NULL)
return 1;
@@ -609,11 +609,11 @@ void register_transport(struct transport *new)
list_for_each_safe(ele, next, &eth_cmd_line) {
eth = list_entry(ele, struct eth_init, list);
match = check_transport(new, eth->init, eth->index, &init,
- &mac);
+ &mac, GFP_KERNEL);
if (!match)
continue;
else if (init != NULL) {
- eth_configure(eth->index, init, mac, new);
+ eth_configure(eth->index, init, mac, new, GFP_KERNEL);
kfree(init);
}
list_del(&eth->list);
@@ -631,10 +631,11 @@ static int eth_setup_common(char *str, int index)
spin_lock(&transports_lock);
list_for_each(ele, &transports) {
transport = list_entry(ele, struct transport, list);
- if (!check_transport(transport, str, index, &init, &mac))
+ if (!check_transport(transport, str, index, &init,
+ &mac, GFP_ATOMIC))
continue;
if (init != NULL) {
- eth_configure(index, init, mac, transport);
+ eth_configure(index, init, mac, transport, GFP_ATOMIC);
kfree(init);
}
found = 1;
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index e697a41..e9f8445 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -249,21 +249,23 @@ void close_addr(unsigned char *addr, unsigned char *netmask, void *arg)
char *split_if_spec(char *str, ...)
{
- char **arg, *end;
+ char **arg, *end, *ret = NULL;
va_list ap;
va_start(ap, str);
while ((arg = va_arg(ap, char **)) != NULL) {
if (*str == '\0')
- return NULL;
+ goto out;
end = strchr(str, ',');
if (end != str)
*arg = str;
if (end == NULL)
- return NULL;
+ goto out;
*end++ = '\0';
str = end;
}
+ ret = str;
+out:
va_end(ap);
- return str;
+ return ret;
}
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index e8ab93c..39ba207 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -535,11 +535,7 @@ static int read_cow_bitmap(int fd, void *buf, int offset, int len)
{
int err;
- err = os_seek_file(fd, offset);
- if (err < 0)
- return err;
-
- err = os_read_file(fd, buf, len);
+ err = os_pread_file(fd, buf, len, offset);
if (err < 0)
return err;
@@ -1377,14 +1373,8 @@ static int update_bitmap(struct io_thread_req *req)
if(req->cow_offset == -1)
return 0;
- n = os_seek_file(req->fds[1], req->cow_offset);
- if(n < 0){
- printk("do_io - bitmap lseek failed : err = %d\n", -n);
- return 1;
- }
-
- n = os_write_file(req->fds[1], &req->bitmap_words,
- sizeof(req->bitmap_words));
+ n = os_pwrite_file(req->fds[1], &req->bitmap_words,
+ sizeof(req->bitmap_words), req->cow_offset);
if(n != sizeof(req->bitmap_words)){
printk("do_io - bitmap update failed, err = %d fd = %d\n", -n,
req->fds[1]);
@@ -1399,7 +1389,6 @@ static void do_io(struct io_thread_req *req)
char *buf;
unsigned long len;
int n, nsectors, start, end, bit;
- int err;
__u64 off;
if (req->op == UBD_FLUSH) {
@@ -1428,18 +1417,12 @@ static void do_io(struct io_thread_req *req)
len = (end - start) * req->sectorsize;
buf = &req->buffer[start * req->sectorsize];
- err = os_seek_file(req->fds[bit], off);
- if(err < 0){
- printk("do_io - lseek failed : err = %d\n", -err);
- req->error = 1;
- return;
- }
if(req->op == UBD_READ){
n = 0;
do {
buf = &buf[n];
len -= n;
- n = os_read_file(req->fds[bit], buf, len);
+ n = os_pread_file(req->fds[bit], buf, len, off);
if (n < 0) {
printk("do_io - read failed, err = %d "
"fd = %d\n", -n, req->fds[bit]);
@@ -1449,7 +1432,7 @@ static void do_io(struct io_thread_req *req)
} while((n < len) && (n != 0));
if (n < len) memset(&buf[n], 0, len - n);
} else {
- n = os_write_file(req->fds[bit], buf, len);
+ n = os_pwrite_file(req->fds[bit], buf, len, off);
if(n != len){
printk("do_io - write failed err = %d "
"fd = %d\n", -n, req->fds[bit]);
diff --git a/arch/um/include/asm/hardirq.h b/arch/um/include/asm/hardirq.h
new file mode 100644
index 0000000..756f077
--- /dev/null
+++ b/arch/um/include/asm/hardirq.h
@@ -0,0 +1,23 @@
+#ifndef __ASM_UM_HARDIRQ_H
+#define __ASM_UM_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+#include <linux/irq.h>
+
+#ifndef ack_bad_irq
+static inline void ack_bad_irq(unsigned int irq)
+{
+ printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+#endif
+
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
+
+#endif /* __ASM_UM_HARDIRQ_H */
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h
index 2966adb..5ab2062 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -27,6 +27,8 @@ struct pt_regs {
#define instruction_pointer(regs) PT_REGS_IP(regs)
+#define PTRACE_OLDSETOPTIONS 21
+
struct task_struct;
extern long subarch_ptrace(struct task_struct *child, long request,
diff --git a/arch/um/include/asm/syscall-generic.h b/arch/um/include/asm/syscall-generic.h
new file mode 100644
index 0000000..9fb9cf8
--- /dev/null
+++ b/arch/um/include/asm/syscall-generic.h
@@ -0,0 +1,138 @@
+/*
+ * Access to user system call parameters and results
+ *
+ * See asm-generic/syscall.h for function descriptions.
+ *
+ * Copyright (C) 2015 Mickaël Salaün <mic@digikod.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __UM_SYSCALL_GENERIC_H
+#define __UM_SYSCALL_GENERIC_H
+
+#include <asm/ptrace.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <sysdep/ptrace.h>
+
+static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+
+ return PT_REGS_SYSCALL_NR(regs);
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* do nothing */
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ const long error = regs_return_value(regs);
+
+ return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs_return_value(regs);
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ PT_REGS_SET_SYSCALL_RETURN(regs, (long) error ?: val);
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ const struct uml_pt_regs *r = &regs->regs;
+
+ switch (i) {
+ case 0:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG1(r);
+ case 1:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG2(r);
+ case 2:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG3(r);
+ case 3:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG4(r);
+ case 4:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG5(r);
+ case 5:
+ if (!n--)
+ break;
+ *args++ = UPT_SYSCALL_ARG6(r);
+ case 6:
+ if (!n--)
+ break;
+ default:
+ BUG();
+ break;
+ }
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ struct uml_pt_regs *r = &regs->regs;
+
+ switch (i) {
+ case 0:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG1(r) = *args++;
+ case 1:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG2(r) = *args++;
+ case 2:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG3(r) = *args++;
+ case 3:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG4(r) = *args++;
+ case 4:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG5(r) = *args++;
+ case 5:
+ if (!n--)
+ break;
+ UPT_SYSCALL_ARG6(r) = *args++;
+ case 6:
+ if (!n--)
+ break;
+ default:
+ BUG();
+ break;
+ }
+}
+
+/* See arch/x86/um/asm/syscall.h for syscall_get_arch() definition. */
+
+#endif /* __UM_SYSCALL_GENERIC_H */
diff --git a/arch/um/include/asm/thread_info.h b/arch/um/include/asm/thread_info.h
index 53968aa..053baff 100644
--- a/arch/um/include/asm/thread_info.h
+++ b/arch/um/include/asm/thread_info.h
@@ -62,11 +62,13 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_SYSCALL_AUDIT 6
#define TIF_RESTORE_SIGMASK 7
#define TIF_NOTIFY_RESUME 8
+#define TIF_SECCOMP 9 /* secure computing */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
#define _TIF_MEMDIE (1 << TIF_MEMDIE)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_SECCOMP (1 << TIF_SECCOMP)
#endif
diff --git a/arch/um/include/shared/os.h b/arch/um/include/shared/os.h
index ad3fa3a..de5d572 100644
--- a/arch/um/include/shared/os.h
+++ b/arch/um/include/shared/os.h
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -144,6 +146,8 @@ extern int os_read_file(int fd, void *buf, int len);
extern int os_write_file(int fd, const void *buf, int count);
extern int os_sync_file(int fd);
extern int os_file_size(const char *file, unsigned long long *size_out);
+extern int os_pread_file(int fd, void *buf, int len, unsigned long long offset);
+extern int os_pwrite_file(int fd, const void *buf, int count, unsigned long long offset);
extern int os_file_modtime(const char *file, unsigned long *modtime);
extern int os_pipe(int *fd, int stream, int close_on_exec);
extern int os_set_fd_async(int fd);
@@ -183,6 +187,7 @@ extern int create_mem_file(unsigned long long len);
/* process.c */
extern unsigned long os_process_pc(int pid);
extern int os_process_parent(int pid);
+extern void os_alarm_process(int pid);
extern void os_stop_process(int pid);
extern void os_kill_process(int pid, int reap_child);
extern void os_kill_ptraced_process(int pid, int reap_child);
@@ -217,7 +222,7 @@ extern int set_umid(char *name);
extern char *get_umid(void);
/* signal.c */
-extern void timer_init(void);
+extern void timer_set_signal_handler(void);
extern void set_sigstack(void *sig_stack, int size);
extern void remove_sigstack(void);
extern void set_handler(int sig);
@@ -227,6 +232,7 @@ extern void unblock_signals(void);
extern int get_signals(void);
extern int set_signals(int enable);
extern int os_is_signal_stack(void);
+extern void deliver_alarm(void);
/* util.c */
extern void stack_protections(unsigned long address);
@@ -238,12 +244,16 @@ extern void um_early_printk(const char *s, unsigned int n);
extern void os_fix_helper_signals(void);
/* time.c */
-extern void idle_sleep(unsigned long long nsecs);
-extern int set_interval(void);
-extern int timer_one_shot(int ticks);
-extern long long disable_timer(void);
+extern void os_idle_sleep(unsigned long long nsecs);
+extern int os_timer_create(void* timer);
+extern int os_timer_set_interval(void* timer, void* its);
+extern int os_timer_one_shot(int ticks);
+extern long long os_timer_disable(void);
+extern long os_timer_remain(void* timer);
extern void uml_idle_timer(void);
+extern long long os_persistent_clock_emulation(void);
extern long long os_nsecs(void);
+extern long long os_vnsecs(void);
/* skas/mem.c */
extern long run_syscall_stub(struct mm_id * mm_idp,
diff --git a/arch/um/include/shared/skas/stub-data.h b/arch/um/include/shared/skas/stub-data.h
index f6ed92c..a9deece 100644
--- a/arch/um/include/shared/skas/stub-data.h
+++ b/arch/um/include/shared/skas/stub-data.h
@@ -1,4 +1,6 @@
/*
+
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -6,12 +8,11 @@
#ifndef __STUB_DATA_H
#define __STUB_DATA_H
-#include <sys/time.h>
+#include <time.h>
struct stub_data {
- long offset;
+ unsigned long offset;
int fd;
- struct itimerval timer;
long err;
};
diff --git a/arch/um/include/shared/timer-internal.h b/arch/um/include/shared/timer-internal.h
new file mode 100644
index 0000000..03e6f21
--- /dev/null
+++ b/arch/um/include/shared/timer-internal.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2012 - 2014 Cisco Systems
+ * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __TIMER_INTERNAL_H__
+#define __TIMER_INTERNAL_H__
+
+#define TIMER_MULTIPLIER 256
+#define TIMER_MIN_DELTA 500
+
+#endif
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index a6d9226..48af59a 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Copyright 2003 PathScale, Inc.
* Licensed under the GPL
@@ -27,6 +29,7 @@
#include <kern_util.h>
#include <os.h>
#include <skas.h>
+#include <timer-internal.h>
/*
* This is a per-cpu array. A processor only modifies its entry and it only
@@ -203,11 +206,8 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
void arch_cpu_idle(void)
{
- unsigned long long nsecs;
-
cpu_tasks[current_thread_info()->cpu].pid = os_getpid();
- nsecs = disable_timer();
- idle_sleep(nsecs);
+ os_idle_sleep(UM_NSEC_PER_SEC);
local_irq_enable();
}
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 57acbd6..fc8be0e 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -69,7 +69,7 @@ void do_signal(struct pt_regs *regs)
struct ksignal ksig;
int handled_sig = 0;
- while (get_signal(&ksig)) {
+ if (get_signal(&ksig)) {
handled_sig = 1;
/* Whee! Actually deliver the signal. */
handle_signal(&ksig, regs);
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
index 289771d..0f25d41 100644
--- a/arch/um/kernel/skas/clone.c
+++ b/arch/um/kernel/skas/clone.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -35,11 +36,6 @@ stub_clone_handler(void)
if (err)
goto out;
- err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
- (long) &data->timer, 0);
- if (err)
- goto out;
-
remap_stack(data->fd, data->offset);
goto done;
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index fda1deb..9591a66 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -61,10 +62,12 @@ int init_new_context(struct task_struct *task, struct mm_struct *mm)
if (current->mm != NULL && current->mm != &init_mm)
from_mm = &current->mm->context;
+ block_signals();
if (from_mm)
to_mm->id.u.pid = copy_context_skas0(stack,
from_mm->id.u.pid);
else to_mm->id.u.pid = start_userspace(stack);
+ unblock_signals();
if (to_mm->id.u.pid < 0) {
ret = to_mm->id.u.pid;
diff --git a/arch/um/kernel/skas/syscall.c b/arch/um/kernel/skas/syscall.c
index d9ec006..48b0dcb 100644
--- a/arch/um/kernel/skas/syscall.c
+++ b/arch/um/kernel/skas/syscall.c
@@ -5,40 +5,38 @@
#include <linux/kernel.h>
#include <linux/ptrace.h>
+#include <linux/seccomp.h>
#include <kern_util.h>
#include <sysdep/ptrace.h>
+#include <sysdep/ptrace_user.h>
#include <sysdep/syscalls.h>
-extern int syscall_table_size;
-#define NR_SYSCALLS (syscall_table_size / sizeof(void *))
-
void handle_syscall(struct uml_pt_regs *r)
{
struct pt_regs *regs = container_of(r, struct pt_regs, regs);
- long result;
int syscall;
- if (syscall_trace_enter(regs)) {
- result = -ENOSYS;
+ /* Initialize the syscall number and default return value. */
+ UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp);
+ PT_REGS_SET_SYSCALL_RETURN(regs, -ENOSYS);
+
+ /* Do the secure computing check first; failures should be fast. */
+ if (secure_computing() == -1)
+ return;
+
+ if (syscall_trace_enter(regs))
goto out;
- }
-
- /*
- * This should go in the declaration of syscall, but when I do that,
- * strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
- * children at all, sometimes hanging when bash doesn't see the first
- * ls exit.
- * The assembly looks functionally the same to me. This is
- * gcc version 4.0.1 20050727 (Red Hat 4.0.1-5)
- * in case it's a compiler bug.
+
+ /* Update the syscall number after orig_ax has potentially been updated
+ * with ptrace.
*/
+ UPT_SYSCALL_NR(r) = PT_SYSCALL_NR(r->gp);
syscall = UPT_SYSCALL_NR(r);
- if ((syscall >= NR_SYSCALLS) || (syscall < 0))
- result = -ENOSYS;
- else result = EXECUTE_SYSCALL(syscall, regs);
-out:
- PT_REGS_SET_SYSCALL_RETURN(regs, result);
+ if (syscall >= 0 && syscall <= __NR_syscall_max)
+ PT_REGS_SET_SYSCALL_RETURN(regs,
+ EXECUTE_SYSCALL(syscall, regs));
+out:
syscall_trace_leave(regs);
}
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 5af441e..25c2366 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
+ * Copyright (C) 2012-2014 Cisco Systems
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -7,11 +10,15 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
#include <linux/threads.h>
#include <asm/irq.h>
#include <asm/param.h>
#include <kern_util.h>
#include <os.h>
+#include <timer-internal.h>
void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
{
@@ -24,81 +31,97 @@ void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
static int itimer_shutdown(struct clock_event_device *evt)
{
- disable_timer();
+ os_timer_disable();
return 0;
}
static int itimer_set_periodic(struct clock_event_device *evt)
{
- set_interval();
+ os_timer_set_interval(NULL, NULL);
return 0;
}
static int itimer_next_event(unsigned long delta,
struct clock_event_device *evt)
{
- return timer_one_shot(delta + 1);
+ return os_timer_one_shot(delta);
}
-static struct clock_event_device itimer_clockevent = {
- .name = "itimer",
+static int itimer_one_shot(struct clock_event_device *evt)
+{
+ os_timer_one_shot(1);
+ return 0;
+}
+
+static struct clock_event_device timer_clockevent = {
+ .name = "posix-timer",
.rating = 250,
.cpumask = cpu_all_mask,
.features = CLOCK_EVT_FEAT_PERIODIC |
CLOCK_EVT_FEAT_ONESHOT,
.set_state_shutdown = itimer_shutdown,
.set_state_periodic = itimer_set_periodic,
- .set_state_oneshot = itimer_shutdown,
+ .set_state_oneshot = itimer_one_shot,
.set_next_event = itimer_next_event,
- .shift = 32,
+ .shift = 0,
+ .max_delta_ns = 0xffffffff,
+ .min_delta_ns = TIMER_MIN_DELTA, //microsecond resolution should be enough for anyone, same as 640K RAM
.irq = 0,
+ .mult = 1,
};
static irqreturn_t um_timer(int irq, void *dev)
{
- (*itimer_clockevent.event_handler)(&itimer_clockevent);
+ if (get_current()->mm != NULL)
+ {
+ /* userspace - relay signal, results in correct userspace timers */
+ os_alarm_process(get_current()->mm->context.id.u.pid);
+ }
+
+ (*timer_clockevent.event_handler)(&timer_clockevent);
return IRQ_HANDLED;
}
-static cycle_t itimer_read(struct clocksource *cs)
+static cycle_t timer_read(struct clocksource *cs)
{
- return os_nsecs() / 1000;
+ return os_nsecs() / TIMER_MULTIPLIER;
}
-static struct clocksource itimer_clocksource = {
- .name = "itimer",
+static struct clocksource timer_clocksource = {
+ .name = "timer",
.rating = 300,
- .read = itimer_read,
+ .read = timer_read,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
-static void __init setup_itimer(void)
+static void __init timer_setup(void)
{
int err;
- err = request_irq(TIMER_IRQ, um_timer, 0, "timer", NULL);
+ err = request_irq(TIMER_IRQ, um_timer, IRQF_TIMER, "hr timer", NULL);
if (err != 0)
printk(KERN_ERR "register_timer : request_irq failed - "
"errno = %d\n", -err);
- itimer_clockevent.mult = div_sc(HZ, NSEC_PER_SEC, 32);
- itimer_clockevent.max_delta_ns =
- clockevent_delta2ns(60 * HZ, &itimer_clockevent);
- itimer_clockevent.min_delta_ns =
- clockevent_delta2ns(1, &itimer_clockevent);
- err = clocksource_register_hz(&itimer_clocksource, USEC_PER_SEC);
+ err = os_timer_create(NULL);
+ if (err != 0) {
+ printk(KERN_ERR "creation of timer failed - errno = %d\n", -err);
+ return;
+ }
+
+ err = clocksource_register_hz(&timer_clocksource, NSEC_PER_SEC/TIMER_MULTIPLIER);
if (err) {
printk(KERN_ERR "clocksource_register_hz returned %d\n", err);
return;
}
- clockevents_register_device(&itimer_clockevent);
+ clockevents_register_device(&timer_clockevent);
}
void read_persistent_clock(struct timespec *ts)
{
- long long nsecs = os_nsecs();
+ long long nsecs = os_persistent_clock_emulation();
set_normalized_timespec(ts, nsecs / NSEC_PER_SEC,
nsecs % NSEC_PER_SEC);
@@ -106,6 +129,6 @@ void read_persistent_clock(struct timespec *ts)
void __init time_init(void)
{
- timer_init();
- late_time_init = setup_itimer;
+ timer_set_signal_handler();
+ late_time_init = timer_setup;
}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index 2077248..3777b82 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -50,6 +50,13 @@ struct host_vm_change {
.index = 0, \
.force = force })
+static void report_enomem(void)
+{
+ printk(KERN_ERR "UML ran out of memory on the host side! "
+ "This can happen due to a memory limitation or "
+ "vm.max_map_count has been reached.\n");
+}
+
static int do_ops(struct host_vm_change *hvc, int end,
int finished)
{
@@ -81,6 +88,9 @@ static int do_ops(struct host_vm_change *hvc, int end,
}
}
+ if (ret == -ENOMEM)
+ report_enomem();
+
return ret;
}
@@ -433,8 +443,12 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
else if (pte_newprot(*pte))
err = protect(mm_id, address, PAGE_SIZE, prot, 1, &flush);
- if (err)
+ if (err) {
+ if (err == -ENOMEM)
+ report_enomem();
+
goto kill;
+ }
*pte = pte_mkuptodate(*pte);
diff --git a/arch/um/os-Linux/file.c b/arch/um/os-Linux/file.c
index 26e0164..2db18cb 100644
--- a/arch/um/os-Linux/file.c
+++ b/arch/um/os-Linux/file.c
@@ -264,6 +264,15 @@ int os_read_file(int fd, void *buf, int len)
return n;
}
+int os_pread_file(int fd, void *buf, int len, unsigned long long offset)
+{
+ int n = pread(fd, buf, len, offset);
+
+ if (n < 0)
+ return -errno;
+ return n;
+}
+
int os_write_file(int fd, const void *buf, int len)
{
int n = write(fd, (void *) buf, len);
@@ -282,6 +291,16 @@ int os_sync_file(int fd)
return n;
}
+int os_pwrite_file(int fd, const void *buf, int len, unsigned long long offset)
+{
+ int n = pwrite(fd, (void *) buf, len, offset);
+
+ if (n < 0)
+ return -errno;
+ return n;
+}
+
+
int os_file_size(const char *file, unsigned long long *size_out)
{
struct uml_stat buf;
diff --git a/arch/um/os-Linux/internal.h b/arch/um/os-Linux/internal.h
deleted file mode 100644
index 0dc2c9f..0000000
--- a/arch/um/os-Linux/internal.h
+++ /dev/null
@@ -1 +0,0 @@
-void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index df9191a..9d499de 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -163,13 +164,13 @@ int __init main(int argc, char **argv, char **envp)
/*
* This signal stuff used to be in the reboot case. However,
- * sometimes a SIGVTALRM can come in when we're halting (reproducably
+ * sometimes a timer signal can come in when we're halting (reproducably
* when writing out gcov information, presumably because that takes
* some time) and cause a segfault.
*/
- /* stop timers and set SIGVTALRM to be ignored */
- disable_timer();
+ /* stop timers and set timer signal to be ignored */
+ os_timer_disable();
/* disable SIGIO for the fds and set SIGIO to be ignored */
err = deactivate_all_fds();
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index 897e9ad..8b17676 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -106,6 +106,17 @@ static int __init make_tempfile(const char *template)
}
}
+#ifdef O_TMPFILE
+ fd = open(tempdir, O_CLOEXEC | O_RDWR | O_EXCL | O_TMPFILE, 0700);
+ /*
+ * If the running system does not support O_TMPFILE flag then retry
+ * without it.
+ */
+ if (fd != -1 || (errno != EINVAL && errno != EISDIR &&
+ errno != EOPNOTSUPP))
+ return fd;
+#endif
+
tempname = malloc(strlen(tempdir) + strlen(template) + 1);
if (tempname == NULL)
return -1;
@@ -142,12 +153,6 @@ static int __init create_tmp_file(unsigned long long len)
if (fd < 0)
exit(1);
- err = fchmod(fd, 0777);
- if (err < 0) {
- perror("fchmod");
- exit(1);
- }
-
/*
* Seek to len - 1 because writing a character there will
* increase the file size by one byte, to the desired length.
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index 8408aba..b3e0d40 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -89,6 +90,11 @@ int os_process_parent(int pid)
return parent;
}
+void os_alarm_process(int pid)
+{
+ kill(pid, SIGALRM);
+}
+
void os_stop_process(int pid)
{
kill(pid, SIGSTOP);
diff --git a/arch/um/os-Linux/signal.c b/arch/um/os-Linux/signal.c
index 036d0db..7801666 100644
--- a/arch/um/os-Linux/signal.c
+++ b/arch/um/os-Linux/signal.c
@@ -1,4 +1,6 @@
/*
+ * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2004 PathScale, Inc
* Copyright (C) 2004 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
@@ -13,7 +15,6 @@
#include <kern_util.h>
#include <os.h>
#include <sysdep/mcontext.h>
-#include "internal.h"
void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
[SIGTRAP] = relay_signal,
@@ -23,7 +24,8 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
[SIGBUS] = bus_handler,
[SIGSEGV] = segv_handler,
[SIGIO] = sigio_handler,
- [SIGVTALRM] = timer_handler };
+ [SIGALRM] = timer_handler
+};
static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
{
@@ -38,7 +40,7 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
}
/* enable signals if sig isn't IRQ signal */
- if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
+ if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGALRM))
unblock_signals();
(*sig_info[sig])(sig, si, &r);
@@ -55,11 +57,12 @@ static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
#define SIGIO_BIT 0
#define SIGIO_MASK (1 << SIGIO_BIT)
-#define SIGVTALRM_BIT 1
-#define SIGVTALRM_MASK (1 << SIGVTALRM_BIT)
+#define SIGALRM_BIT 1
+#define SIGALRM_MASK (1 << SIGALRM_BIT)
static int signals_enabled;
static unsigned int signals_pending;
+static unsigned int signals_active = 0;
void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
{
@@ -78,36 +81,43 @@ void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
set_signals(enabled);
}
-static void real_alarm_handler(mcontext_t *mc)
+static void timer_real_alarm_handler(mcontext_t *mc)
{
struct uml_pt_regs regs;
if (mc != NULL)
get_regs_from_mc(&regs, mc);
- regs.is_user = 0;
- unblock_signals();
- timer_handler(SIGVTALRM, NULL, &regs);
+ timer_handler(SIGALRM, NULL, &regs);
}
-void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
+void timer_alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
{
int enabled;
enabled = signals_enabled;
if (!signals_enabled) {
- signals_pending |= SIGVTALRM_MASK;
+ signals_pending |= SIGALRM_MASK;
return;
}
block_signals();
- real_alarm_handler(mc);
+ signals_active |= SIGALRM_MASK;
+
+ timer_real_alarm_handler(mc);
+
+ signals_active &= ~SIGALRM_MASK;
+
set_signals(enabled);
}
-void timer_init(void)
+void deliver_alarm(void) {
+ timer_alarm_handler(SIGALRM, NULL, NULL);
+}
+
+void timer_set_signal_handler(void)
{
- set_handler(SIGVTALRM);
+ set_handler(SIGALRM);
}
void set_sigstack(void *sig_stack, int size)
@@ -131,10 +141,9 @@ static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
[SIGIO] = sig_handler,
[SIGWINCH] = sig_handler,
- [SIGVTALRM] = alarm_handler
+ [SIGALRM] = timer_alarm_handler
};
-
static void hard_handler(int sig, siginfo_t *si, void *p)
{
struct ucontext *uc = p;
@@ -188,9 +197,9 @@ void set_handler(int sig)
/* block irq ones */
sigemptyset(&action.sa_mask);
- sigaddset(&action.sa_mask, SIGVTALRM);
sigaddset(&action.sa_mask, SIGIO);
sigaddset(&action.sa_mask, SIGWINCH);
+ sigaddset(&action.sa_mask, SIGALRM);
if (sig == SIGSEGV)
flags |= SA_NODEFER;
@@ -283,8 +292,16 @@ void unblock_signals(void)
if (save_pending & SIGIO_MASK)
sig_handler_common(SIGIO, NULL, NULL);
- if (save_pending & SIGVTALRM_MASK)
- real_alarm_handler(NULL);
+ /* Do not reenter the handler */
+
+ if ((save_pending & SIGALRM_MASK) && (!(signals_active & SIGALRM_MASK)))
+ timer_real_alarm_handler(NULL);
+
+ /* Rerun the loop only if there is still pending SIGIO and not in TIMER handler */
+
+ if (!(signals_pending & SIGIO_MASK) && (signals_active & SIGALRM_MASK))
+ return;
+
}
}
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 3dddedb..23025d6 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
* Copyright (C) 2002- 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -45,7 +46,7 @@ static int ptrace_dump_regs(int pid)
* Signals that are OK to receive in the stub - we'll just continue it.
* SIGWINCH will happen when UML is inside a detached screen.
*/
-#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
+#define STUB_SIG_MASK ((1 << SIGALRM) | (1 << SIGWINCH))
/* Signals that the stub will finish with - anything else is an error */
#define STUB_DONE_MASK (1 << SIGTRAP)
@@ -137,9 +138,6 @@ static void handle_trap(int pid, struct uml_pt_regs *regs,
if ((UPT_IP(regs) >= STUB_START) && (UPT_IP(regs) < STUB_END))
fatal_sigsegv();
- /* Mark this as a syscall */
- UPT_SYSCALL_NR(regs) = PT_SYSCALL_NR(regs->gp);
-
if (!local_using_sysemu)
{
err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET,
@@ -179,19 +177,13 @@ extern char __syscall_stub_start[];
static int userspace_tramp(void *stack)
{
void *addr;
- int err, fd;
+ int fd;
unsigned long long offset;
ptrace(PTRACE_TRACEME, 0, 0, 0);
signal(SIGTERM, SIG_DFL);
signal(SIGWINCH, SIG_IGN);
- err = set_interval();
- if (err) {
- printk(UM_KERN_ERR "userspace_tramp - setting timer failed, "
- "errno = %d\n", err);
- exit(1);
- }
/*
* This has a pte, but it can't be mapped in with the usual
@@ -282,7 +274,7 @@ int start_userspace(unsigned long stub_stack)
"errno = %d\n", errno);
goto out_kill;
}
- } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM));
+ } while (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGALRM));
if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) {
err = -EINVAL;
@@ -315,8 +307,6 @@ int start_userspace(unsigned long stub_stack)
void userspace(struct uml_pt_regs *regs)
{
- struct itimerval timer;
- unsigned long long nsecs, now;
int err, status, op, pid = userspace_pid[0];
/* To prevent races if using_sysemu changes under us.*/
int local_using_sysemu;
@@ -325,13 +315,8 @@ void userspace(struct uml_pt_regs *regs)
/* Handle any immediate reschedules or signals */
interrupt_end();
- if (getitimer(ITIMER_VIRTUAL, &timer))
- printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno);
- nsecs = timer.it_value.tv_sec * UM_NSEC_PER_SEC +
- timer.it_value.tv_usec * UM_NSEC_PER_USEC;
- nsecs += os_nsecs();
-
while (1) {
+
/*
* This can legitimately fail if the process loads a
* bogus value into a segment register. It will
@@ -401,18 +386,7 @@ void userspace(struct uml_pt_regs *regs)
case SIGTRAP:
relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
break;
- case SIGVTALRM:
- now = os_nsecs();
- if (now < nsecs)
- break;
- block_signals();
- (*sig_info[sig])(sig, (struct siginfo *)&si, regs);
- unblock_signals();
- nsecs = timer.it_value.tv_sec *
- UM_NSEC_PER_SEC +
- timer.it_value.tv_usec *
- UM_NSEC_PER_USEC;
- nsecs += os_nsecs();
+ case SIGALRM:
break;
case SIGIO:
case SIGILL:
@@ -460,7 +434,6 @@ __initcall(init_thread_regs);
int copy_context_skas0(unsigned long new_stack, int pid)
{
- struct timeval tv = { .tv_sec = 0, .tv_usec = UM_USEC_PER_SEC / UM_HZ };
int err;
unsigned long current_stack = current_stub_stack();
struct stub_data *data = (struct stub_data *) current_stack;
@@ -472,11 +445,10 @@ int copy_context_skas0(unsigned long new_stack, int pid)
* prepare offset and fd of child's stack as argument for parent's
* and child's mmap2 calls
*/
- *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
- .fd = new_fd,
- .timer = ((struct itimerval)
- { .it_value = tv,
- .it_interval = tv }) });
+ *data = ((struct stub_data) {
+ .offset = MMAP_OFFSET(new_offset),
+ .fd = new_fd
+ });
err = ptrace_setregs(pid, thread_regs);
if (err < 0) {
diff --git a/arch/um/os-Linux/start_up.c b/arch/um/os-Linux/start_up.c
index 47f1ff0..22a358e 100644
--- a/arch/um/os-Linux/start_up.c
+++ b/arch/um/os-Linux/start_up.c
@@ -94,6 +94,8 @@ static int start_ptraced_child(void)
{
int pid, n, status;
+ fflush(stdout);
+
pid = fork();
if (pid == 0)
ptrace_child();
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index e9824d5..0e39b99 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2015 Anton Ivanov (aivanov@{brocade.com,kot-begemot.co.uk})
+ * Copyright (C) 2015 Thomas Meyer (thomas@m3y3r.de)
+ * Copyright (C) 2012-2014 Cisco Systems
* Copyright (C) 2000 - 2007 Jeff Dike (jdike{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
@@ -10,177 +13,177 @@
#include <sys/time.h>
#include <kern_util.h>
#include <os.h>
-#include "internal.h"
+#include <string.h>
+#include <timer-internal.h>
-int set_interval(void)
-{
- int usec = UM_USEC_PER_SEC / UM_HZ;
- struct itimerval interval = ((struct itimerval) { { 0, usec },
- { 0, usec } });
-
- if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
- return -errno;
+static timer_t event_high_res_timer = 0;
- return 0;
+static inline long long timeval_to_ns(const struct timeval *tv)
+{
+ return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
+ tv->tv_usec * UM_NSEC_PER_USEC;
}
-int timer_one_shot(int ticks)
+static inline long long timespec_to_ns(const struct timespec *ts)
{
- unsigned long usec = ticks * UM_USEC_PER_SEC / UM_HZ;
- unsigned long sec = usec / UM_USEC_PER_SEC;
- struct itimerval interval;
-
- usec %= UM_USEC_PER_SEC;
- interval = ((struct itimerval) { { 0, 0 }, { sec, usec } });
+ return ((long long) ts->tv_sec * UM_NSEC_PER_SEC) +
+ ts->tv_nsec;
+}
- if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
- return -errno;
+long long os_persistent_clock_emulation (void) {
+ struct timespec realtime_tp;
- return 0;
+ clock_gettime(CLOCK_REALTIME, &realtime_tp);
+ return timespec_to_ns(&realtime_tp);
}
/**
- * timeval_to_ns - Convert timeval to nanoseconds
- * @ts: pointer to the timeval variable to be converted
- *
- * Returns the scalar nanosecond representation of the timeval
- * parameter.
- *
- * Ripped from linux/time.h because it's a kernel header, and thus
- * unusable from here.
+ * os_timer_create() - create an new posix (interval) timer
*/
-static inline long long timeval_to_ns(const struct timeval *tv)
-{
- return ((long long) tv->tv_sec * UM_NSEC_PER_SEC) +
- tv->tv_usec * UM_NSEC_PER_USEC;
+int os_timer_create(void* timer) {
+
+ timer_t* t = timer;
+
+ if(t == NULL) {
+ t = &event_high_res_timer;
+ }
+
+ if (timer_create(
+ CLOCK_MONOTONIC,
+ NULL,
+ t) == -1) {
+ return -1;
+ }
+ return 0;
}
-long long disable_timer(void)
+int os_timer_set_interval(void* timer, void* i)
{
- struct itimerval time = ((struct itimerval) { { 0, 0 }, { 0, 0 } });
- long long remain, max = UM_NSEC_PER_SEC / UM_HZ;
+ struct itimerspec its;
+ unsigned long long nsec;
+ timer_t* t = timer;
+ struct itimerspec* its_in = i;
- if (setitimer(ITIMER_VIRTUAL, &time, &time) < 0)
- printk(UM_KERN_ERR "disable_timer - setitimer failed, "
- "errno = %d\n", errno);
+ if(t == NULL) {
+ t = &event_high_res_timer;
+ }
- remain = timeval_to_ns(&time.it_value);
- if (remain > max)
- remain = max;
+ nsec = UM_NSEC_PER_SEC / UM_HZ;
- return remain;
-}
+ if(its_in != NULL) {
+ its.it_value.tv_sec = its_in->it_value.tv_sec;
+ its.it_value.tv_nsec = its_in->it_value.tv_nsec;
+ } else {
+ its.it_value.tv_sec = 0;
+ its.it_value.tv_nsec = nsec;
+ }
-long long os_nsecs(void)
-{
- struct timeval tv;
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = nsec;
- gettimeofday(&tv, NULL);
- return timeval_to_ns(&tv);
-}
+ if(timer_settime(*t, 0, &its, NULL) == -1) {
+ return -errno;
+ }
-#ifdef UML_CONFIG_NO_HZ_COMMON
-static int after_sleep_interval(struct timespec *ts)
-{
return 0;
}
-static void deliver_alarm(void)
+/**
+ * os_timer_remain() - returns the remaining nano seconds of the given interval
+ * timer
+ * Because this is the remaining time of an interval timer, which correspondends
+ * to HZ, this value can never be bigger than one second. Just
+ * the nanosecond part of the timer is returned.
+ * The returned time is relative to the start time of the interval timer.
+ * Return an negative value in an error case.
+ */
+long os_timer_remain(void* timer)
{
- alarm_handler(SIGVTALRM, NULL, NULL);
-}
+ struct itimerspec its;
+ timer_t* t = timer;
-static unsigned long long sleep_time(unsigned long long nsecs)
-{
- return nsecs;
-}
+ if(t == NULL) {
+ t = &event_high_res_timer;
+ }
-#else
-unsigned long long last_tick;
-unsigned long long skew;
+ if(timer_gettime(t, &its) == -1) {
+ return -errno;
+ }
-static void deliver_alarm(void)
-{
- unsigned long long this_tick = os_nsecs();
- int one_tick = UM_NSEC_PER_SEC / UM_HZ;
+ return its.it_value.tv_nsec;
+}
- /* Protection against the host's time going backwards */
- if ((last_tick != 0) && (this_tick < last_tick))
- this_tick = last_tick;
+int os_timer_one_shot(int ticks)
+{
+ struct itimerspec its;
+ unsigned long long nsec;
+ unsigned long sec;
- if (last_tick == 0)
- last_tick = this_tick - one_tick;
+ nsec = (ticks + 1);
+ sec = nsec / UM_NSEC_PER_SEC;
+ nsec = nsec % UM_NSEC_PER_SEC;
- skew += this_tick - last_tick;
+ its.it_value.tv_sec = nsec / UM_NSEC_PER_SEC;
+ its.it_value.tv_nsec = nsec;
- while (skew >= one_tick) {
- alarm_handler(SIGVTALRM, NULL, NULL);
- skew -= one_tick;
- }
+ its.it_interval.tv_sec = 0;
+ its.it_interval.tv_nsec = 0; // we cheat here
- last_tick = this_tick;
+ timer_settime(event_high_res_timer, 0, &its, NULL);
+ return 0;
}
-static unsigned long long sleep_time(unsigned long long nsecs)
+/**
+ * os_timer_disable() - disable the posix (interval) timer
+ * Returns the remaining interval timer time in nanoseconds
+ */
+long long os_timer_disable(void)
{
- return nsecs > skew ? nsecs - skew : 0;
-}
+ struct itimerspec its;
-static inline long long timespec_to_us(const struct timespec *ts)
-{
- return ((long long) ts->tv_sec * UM_USEC_PER_SEC) +
- ts->tv_nsec / UM_NSEC_PER_USEC;
+ memset(&its, 0, sizeof(struct itimerspec));
+ timer_settime(event_high_res_timer, 0, &its, &its);
+
+ return its.it_value.tv_sec * UM_NSEC_PER_SEC + its.it_value.tv_nsec;
}
-static int after_sleep_interval(struct timespec *ts)
+long long os_vnsecs(void)
{
- int usec = UM_USEC_PER_SEC / UM_HZ;
- long long start_usecs = timespec_to_us(ts);
- struct timeval tv;
- struct itimerval interval;
-
- /*
- * It seems that rounding can increase the value returned from
- * setitimer to larger than the one passed in. Over time,
- * this will cause the remaining time to be greater than the
- * tick interval. If this happens, then just reduce the first
- * tick to the interval value.
- */
- if (start_usecs > usec)
- start_usecs = usec;
-
- start_usecs -= skew / UM_NSEC_PER_USEC;
- if (start_usecs < 0)
- start_usecs = 0;
+ struct timespec ts;
- tv = ((struct timeval) { .tv_sec = start_usecs / UM_USEC_PER_SEC,
- .tv_usec = start_usecs % UM_USEC_PER_SEC });
- interval = ((struct itimerval) { { 0, usec }, tv });
+ clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ts);
+ return timespec_to_ns(&ts);
+}
- if (setitimer(ITIMER_VIRTUAL, &interval, NULL) == -1)
- return -errno;
+long long os_nsecs(void)
+{
+ struct timespec ts;
- return 0;
+ clock_gettime(CLOCK_MONOTONIC,&ts);
+ return timespec_to_ns(&ts);
}
-#endif
-void idle_sleep(unsigned long long nsecs)
+/**
+ * os_idle_sleep() - sleep for a given time of nsecs
+ * @nsecs: nanoseconds to sleep
+ */
+void os_idle_sleep(unsigned long long nsecs)
{
struct timespec ts;
- /*
- * nsecs can come in as zero, in which case, this starts a
- * busy loop. To prevent this, reset nsecs to the tick
- * interval if it is zero.
- */
- if (nsecs == 0)
- nsecs = UM_NSEC_PER_SEC / UM_HZ;
+ if (nsecs <= 0) {
+ return;
+ }
- nsecs = sleep_time(nsecs);
- ts = ((struct timespec) { .tv_sec = nsecs / UM_NSEC_PER_SEC,
- .tv_nsec = nsecs % UM_NSEC_PER_SEC });
+ ts = ((struct timespec) {
+ .tv_sec = nsecs / UM_NSEC_PER_SEC,
+ .tv_nsec = nsecs % UM_NSEC_PER_SEC
+ });
- if (nanosleep(&ts, &ts) == 0)
+ /*
+ * Relay the signal if clock_nanosleep is interrupted.
+ */
+ if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL)) {
deliver_alarm();
- after_sleep_interval(&ts);
+ }
}
diff --git a/arch/unicore32/kernel/puv3-nb0916.c b/arch/unicore32/kernel/puv3-nb0916.c
index 46ebfdc..aab5f34 100644
--- a/arch/unicore32/kernel/puv3-nb0916.c
+++ b/arch/unicore32/kernel/puv3-nb0916.c
@@ -19,6 +19,7 @@
#include <linux/reboot.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
@@ -49,11 +50,14 @@ static struct resource puv3_i2c_resources[] = {
}
};
+static struct pwm_lookup nb0916_pwm_lookup[] = {
+ PWM_LOOKUP("PKUnity-v3-PWM", 0, "pwm-backlight", NULL, 70 * 1024,
+ PWM_POLARITY_NORMAL),
+};
+
static struct platform_pwm_backlight_data nb0916_backlight_data = {
- .pwm_id = 0,
.max_brightness = 100,
.dft_brightness = 100,
- .pwm_period_ns = 70 * 1024,
.enable_gpio = -1,
};
@@ -112,6 +116,8 @@ int __init mach_nb0916_init(void)
platform_device_register_simple("PKUnity-v3-I2C", -1,
puv3_i2c_resources, ARRAY_SIZE(puv3_i2c_resources));
+ pwm_add_table(nb0916_pwm_lookup, ARRAY_SIZE(nb0916_pwm_lookup));
+
platform_device_register_data(NULL, "pwm-backlight", -1,
&nb0916_backlight_data, sizeof(nb0916_backlight_data));
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index db3622f..258965d 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -349,6 +349,17 @@ config X86_FEATURE_NAMES
If in doubt, say Y.
+config X86_FAST_FEATURE_TESTS
+ bool "Fast CPU feature tests" if EMBEDDED
+ default y
+ ---help---
+ Some fast-paths in the kernel depend on the capabilities of the CPU.
+ Say Y here for the kernel to patch in the appropriate code at runtime
+ based on the capabilities of the CPU. The infrastructure for patching
+ code at runtime takes up some additional space; space-constrained
+ embedded systems may wish to say N here to produce smaller, slightly
+ slower code.
+
config X86_X2APIC
bool "Support x2apic"
depends on X86_LOCAL_APIC && X86_64 && (IRQ_REMAP || HYPERVISOR_GUEST)
@@ -687,6 +698,14 @@ config PARAVIRT_SPINLOCKS
If you are unsure how to answer this question, answer Y.
+config QUEUED_LOCK_STAT
+ bool "Paravirt queued spinlock statistics"
+ depends on PARAVIRT_SPINLOCKS && DEBUG_FS && QUEUED_SPINLOCKS
+ ---help---
+ Enable the collection of statistical data on the slowpath
+ behavior of paravirtualized queued spinlocks and report
+ them on debugfs.
+
source "arch/x86/xen/Kconfig"
config KVM_GUEST
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 137dfa9..110253c 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -69,7 +69,7 @@ config X86_PTDUMP_CORE
def_bool n
config X86_PTDUMP
- bool "Export kernel pagetable layout to userspace via debugfs"
+ tristate "Export kernel pagetable layout to userspace via debugfs"
depends on DEBUG_KERNEL
select DEBUG_FS
select X86_PTDUMP_CORE
diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h
index 0033e96..9011a88 100644
--- a/arch/x86/boot/boot.h
+++ b/arch/x86/boot/boot.h
@@ -23,7 +23,6 @@
#include <stdarg.h>
#include <linux/types.h>
#include <linux/edd.h>
-#include <asm/boot.h>
#include <asm/setup.h>
#include "bitops.h"
#include "ctype.h"
diff --git a/arch/x86/boot/video-mode.c b/arch/x86/boot/video-mode.c
index aa8a96b..95c7a81 100644
--- a/arch/x86/boot/video-mode.c
+++ b/arch/x86/boot/video-mode.c
@@ -19,6 +19,8 @@
#include "video.h"
#include "vesa.h"
+#include <uapi/asm/boot.h>
+
/*
* Common variables
*/
diff --git a/arch/x86/boot/video.c b/arch/x86/boot/video.c
index 05111bb..77780e3 100644
--- a/arch/x86/boot/video.c
+++ b/arch/x86/boot/video.c
@@ -13,6 +13,8 @@
* Select video mode
*/
+#include <uapi/asm/boot.h>
+
#include "boot.h"
#include "video.h"
#include "vesa.h"
diff --git a/arch/x86/crypto/chacha20_glue.c b/arch/x86/crypto/chacha20_glue.c
index 722bace..8baaff5 100644
--- a/arch/x86/crypto/chacha20_glue.c
+++ b/arch/x86/crypto/chacha20_glue.c
@@ -125,7 +125,7 @@ static struct crypto_alg alg = {
static int __init chacha20_simd_mod_init(void)
{
- if (!cpu_has_ssse3)
+ if (!boot_cpu_has(X86_FEATURE_SSSE3))
return -ENODEV;
#ifdef CONFIG_AS_AVX2
diff --git a/arch/x86/crypto/crc32c-intel_glue.c b/arch/x86/crypto/crc32c-intel_glue.c
index 81a595d..0e98716 100644
--- a/arch/x86/crypto/crc32c-intel_glue.c
+++ b/arch/x86/crypto/crc32c-intel_glue.c
@@ -257,7 +257,7 @@ static int __init crc32c_intel_mod_init(void)
if (!x86_match_cpu(crc32c_cpu_id))
return -ENODEV;
#ifdef CONFIG_X86_64
- if (cpu_has_pclmulqdq) {
+ if (boot_cpu_has(X86_FEATURE_PCLMULQDQ)) {
alg.update = crc32c_pcl_intel_update;
alg.finup = crc32c_pcl_intel_finup;
alg.digest = crc32c_pcl_intel_digest;
diff --git a/arch/x86/entry/calling.h b/arch/x86/entry/calling.h
index 3c71dd9..e32206e 100644
--- a/arch/x86/entry/calling.h
+++ b/arch/x86/entry/calling.h
@@ -1,3 +1,5 @@
+#include <linux/jump_label.h>
+
/*
x86 function call convention, 64-bit:
@@ -232,3 +234,16 @@ For 32-bit we have the following conventions - kernel is built with
#endif /* CONFIG_X86_64 */
+/*
+ * This does 'call enter_from_user_mode' unless we can avoid it based on
+ * kernel config or using the static jump infrastructure.
+ */
+.macro CALL_enter_from_user_mode
+#ifdef CONFIG_CONTEXT_TRACKING
+#ifdef HAVE_JUMP_LABEL
+ STATIC_JUMP_IF_FALSE .Lafter_call_\@, context_tracking_enabled, def=0
+#endif
+ call enter_from_user_mode
+.Lafter_call_\@:
+#endif
+.endm
diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c
index a89fdbc..0366374 100644
--- a/arch/x86/entry/common.c
+++ b/arch/x86/entry/common.c
@@ -421,7 +421,7 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
regs->ip = landing_pad;
/*
- * Fetch ECX from where the vDSO stashed it.
+ * Fetch EBP from where the vDSO stashed it.
*
* WARNING: We are in CONTEXT_USER and RCU isn't paying attention!
*/
@@ -432,10 +432,10 @@ __visible long do_fast_syscall_32(struct pt_regs *regs)
* Micro-optimization: the pointer we're following is explicitly
* 32 bits, so it can't be out of range.
*/
- __get_user(*(u32 *)&regs->cx,
+ __get_user(*(u32 *)&regs->bp,
(u32 __user __force *)(unsigned long)(u32)regs->sp)
#else
- get_user(*(u32 *)&regs->cx,
+ get_user(*(u32 *)&regs->bp,
(u32 __user __force *)(unsigned long)(u32)regs->sp)
#endif
) {
diff --git a/arch/x86/entry/entry_32.S b/arch/x86/entry/entry_32.S
index 3eb572e..77d8c51 100644
--- a/arch/x86/entry/entry_32.S
+++ b/arch/x86/entry/entry_32.S
@@ -292,7 +292,7 @@ ENTRY(entry_SYSENTER_32)
movl TSS_sysenter_sp0(%esp), %esp
sysenter_past_esp:
pushl $__USER_DS /* pt_regs->ss */
- pushl %ecx /* pt_regs->cx */
+ pushl %ebp /* pt_regs->sp (stashed in bp) */
pushfl /* pt_regs->flags (except IF = 0) */
orl $X86_EFLAGS_IF, (%esp) /* Fix IF */
pushl $__USER_CS /* pt_regs->cs */
@@ -308,8 +308,9 @@ sysenter_past_esp:
movl %esp, %eax
call do_fast_syscall_32
- testl %eax, %eax
- jz .Lsyscall_32_done
+ /* XEN PV guests always use IRET path */
+ ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+ "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
/* Opportunistic SYSEXIT */
TRACE_IRQS_ON /* User mode traces as IRQs on. */
@@ -328,7 +329,8 @@ sysenter_past_esp:
* Return back to the vDSO, which will pop ecx and edx.
* Don't bother with DS and ES (they already contain __USER_DS).
*/
- ENABLE_INTERRUPTS_SYSEXIT
+ sti
+ sysexit
.pushsection .fixup, "ax"
2: movl $0, PT_FS(%esp)
@@ -551,11 +553,6 @@ ENTRY(native_iret)
iret
_ASM_EXTABLE(native_iret, iret_exc)
END(native_iret)
-
-ENTRY(native_irq_enable_sysexit)
- sti
- sysexit
-END(native_irq_enable_sysexit)
#endif
ENTRY(overflow)
diff --git a/arch/x86/entry/entry_64.S b/arch/x86/entry/entry_64.S
index 53616ca..9d34d3c 100644
--- a/arch/x86/entry/entry_64.S
+++ b/arch/x86/entry/entry_64.S
@@ -509,9 +509,18 @@ END(irq_entries_start)
* tracking that we're in kernel mode.
*/
SWAPGS
-#ifdef CONFIG_CONTEXT_TRACKING
- call enter_from_user_mode
-#endif
+
+ /*
+ * We need to tell lockdep that IRQs are off. We can't do this until
+ * we fix gsbase, and we should do it before enter_from_user_mode
+ * (which can take locks). Since TRACE_IRQS_OFF idempotent,
+ * the simplest way to handle it is to just call it twice if
+ * we enter from user mode. There's no reason to optimize this since
+ * TRACE_IRQS_OFF is a no-op if lockdep is off.
+ */
+ TRACE_IRQS_OFF
+
+ CALL_enter_from_user_mode
1:
/*
@@ -1049,12 +1058,16 @@ ENTRY(error_entry)
SWAPGS
.Lerror_entry_from_usermode_after_swapgs:
-#ifdef CONFIG_CONTEXT_TRACKING
- call enter_from_user_mode
-#endif
+ /*
+ * We need to tell lockdep that IRQs are off. We can't do this until
+ * we fix gsbase, and we should do it before enter_from_user_mode
+ * (which can take locks).
+ */
+ TRACE_IRQS_OFF
+ CALL_enter_from_user_mode
+ ret
.Lerror_entry_done:
-
TRACE_IRQS_OFF
ret
diff --git a/arch/x86/entry/entry_64_compat.S b/arch/x86/entry/entry_64_compat.S
index c320183..ff1c6d6 100644
--- a/arch/x86/entry/entry_64_compat.S
+++ b/arch/x86/entry/entry_64_compat.S
@@ -18,13 +18,6 @@
.section .entry.text, "ax"
-#ifdef CONFIG_PARAVIRT
-ENTRY(native_usergs_sysret32)
- swapgs
- sysretl
-ENDPROC(native_usergs_sysret32)
-#endif
-
/*
* 32-bit SYSENTER instruction entry.
*
@@ -63,7 +56,7 @@ ENTRY(entry_SYSENTER_compat)
/* Construct struct pt_regs on stack */
pushq $__USER32_DS /* pt_regs->ss */
- pushq %rcx /* pt_regs->sp */
+ pushq %rbp /* pt_regs->sp (stashed in bp) */
/*
* Push flags. This is nasty. First, interrupts are currently
@@ -82,14 +75,14 @@ ENTRY(entry_SYSENTER_compat)
pushq %rdi /* pt_regs->di */
pushq %rsi /* pt_regs->si */
pushq %rdx /* pt_regs->dx */
- pushq %rcx /* pt_regs->cx (will be overwritten) */
+ pushq %rcx /* pt_regs->cx */
pushq $-ENOSYS /* pt_regs->ax */
pushq %r8 /* pt_regs->r8 = 0 */
pushq %r8 /* pt_regs->r9 = 0 */
pushq %r8 /* pt_regs->r10 = 0 */
pushq %r8 /* pt_regs->r11 = 0 */
pushq %rbx /* pt_regs->rbx */
- pushq %rbp /* pt_regs->rbp */
+ pushq %rbp /* pt_regs->rbp (will be overwritten) */
pushq %r8 /* pt_regs->r12 = 0 */
pushq %r8 /* pt_regs->r13 = 0 */
pushq %r8 /* pt_regs->r14 = 0 */
@@ -103,15 +96,15 @@ ENTRY(entry_SYSENTER_compat)
* This needs to happen before enabling interrupts so that
* we don't get preempted with NT set.
*
- * NB.: sysenter_fix_flags is a label with the code under it moved
+ * NB.: .Lsysenter_fix_flags is a label with the code under it moved
* out-of-line as an optimization: NT is unlikely to be set in the
* majority of the cases and instead of polluting the I$ unnecessarily,
* we're keeping that code behind a branch which will predict as
* not-taken and therefore its instructions won't be fetched.
*/
testl $X86_EFLAGS_NT, EFLAGS(%rsp)
- jnz sysenter_fix_flags
-sysenter_flags_fixed:
+ jnz .Lsysenter_fix_flags
+.Lsysenter_flags_fixed:
/*
* User mode is traced as though IRQs are on, and SYSENTER
@@ -121,14 +114,15 @@ sysenter_flags_fixed:
movq %rsp, %rdi
call do_fast_syscall_32
- testl %eax, %eax
- jz .Lsyscall_32_done
+ /* XEN PV guests always use IRET path */
+ ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+ "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
jmp sysret32_from_system_call
-sysenter_fix_flags:
+.Lsysenter_fix_flags:
pushq $X86_EFLAGS_FIXED
popfq
- jmp sysenter_flags_fixed
+ jmp .Lsysenter_flags_fixed
ENDPROC(entry_SYSENTER_compat)
/*
@@ -178,7 +172,7 @@ ENTRY(entry_SYSCALL_compat)
pushq %rdi /* pt_regs->di */
pushq %rsi /* pt_regs->si */
pushq %rdx /* pt_regs->dx */
- pushq %rcx /* pt_regs->cx (will be overwritten) */
+ pushq %rbp /* pt_regs->cx (stashed in bp) */
pushq $-ENOSYS /* pt_regs->ax */
xorq %r8,%r8
pushq %r8 /* pt_regs->r8 = 0 */
@@ -186,7 +180,7 @@ ENTRY(entry_SYSCALL_compat)
pushq %r8 /* pt_regs->r10 = 0 */
pushq %r8 /* pt_regs->r11 = 0 */
pushq %rbx /* pt_regs->rbx */
- pushq %rbp /* pt_regs->rbp */
+ pushq %rbp /* pt_regs->rbp (will be overwritten) */
pushq %r8 /* pt_regs->r12 = 0 */
pushq %r8 /* pt_regs->r13 = 0 */
pushq %r8 /* pt_regs->r14 = 0 */
@@ -200,8 +194,9 @@ ENTRY(entry_SYSCALL_compat)
movq %rsp, %rdi
call do_fast_syscall_32
- testl %eax, %eax
- jz .Lsyscall_32_done
+ /* XEN PV guests always use IRET path */
+ ALTERNATIVE "testl %eax, %eax; jz .Lsyscall_32_done", \
+ "jmp .Lsyscall_32_done", X86_FEATURE_XENPV
/* Opportunistic SYSRET */
sysret32_from_system_call:
@@ -236,7 +231,8 @@ sysret32_from_system_call:
xorq %r9, %r9
xorq %r10, %r10
movq RSP-ORIG_RAX(%rsp), %rsp
- USERGS_SYSRET32
+ swapgs
+ sysretl
END(entry_SYSCALL_compat)
/*
diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index f17705e..cb713df 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -383,3 +383,4 @@
374 i386 userfaultfd sys_userfaultfd
375 i386 membarrier sys_membarrier
376 i386 mlock2 sys_mlock2
+377 i386 copy_file_range sys_copy_file_range
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 314a90b..dc1040a 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -332,6 +332,7 @@
323 common userfaultfd sys_userfaultfd
324 common membarrier sys_membarrier
325 common mlock2 sys_mlock2
+326 common copy_file_range sys_copy_file_range
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/arch/x86/entry/vdso/vclock_gettime.c b/arch/x86/entry/vdso/vclock_gettime.c
index ca94fa6..8602f06 100644
--- a/arch/x86/entry/vdso/vclock_gettime.c
+++ b/arch/x86/entry/vdso/vclock_gettime.c
@@ -17,8 +17,10 @@
#include <asm/vvar.h>
#include <asm/unistd.h>
#include <asm/msr.h>
+#include <asm/pvclock.h>
#include <linux/math64.h>
#include <linux/time.h>
+#include <linux/kernel.h>
#define gtod (&VVAR(vsyscall_gtod_data))
@@ -36,12 +38,12 @@ static notrace cycle_t vread_hpet(void)
}
#endif
-#ifndef BUILD_VDSO32
+#ifdef CONFIG_PARAVIRT_CLOCK
+extern u8 pvclock_page
+ __attribute__((visibility("hidden")));
+#endif
-#include <linux/kernel.h>
-#include <asm/vsyscall.h>
-#include <asm/fixmap.h>
-#include <asm/pvclock.h>
+#ifndef BUILD_VDSO32
notrace static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
@@ -60,75 +62,6 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
return ret;
}
-#ifdef CONFIG_PARAVIRT_CLOCK
-
-static notrace const struct pvclock_vsyscall_time_info *get_pvti(int cpu)
-{
- const struct pvclock_vsyscall_time_info *pvti_base;
- int idx = cpu / (PAGE_SIZE/PVTI_SIZE);
- int offset = cpu % (PAGE_SIZE/PVTI_SIZE);
-
- BUG_ON(PVCLOCK_FIXMAP_BEGIN + idx > PVCLOCK_FIXMAP_END);
-
- pvti_base = (struct pvclock_vsyscall_time_info *)
- __fix_to_virt(PVCLOCK_FIXMAP_BEGIN+idx);
-
- return &pvti_base[offset];
-}
-
-static notrace cycle_t vread_pvclock(int *mode)
-{
- const struct pvclock_vsyscall_time_info *pvti;
- cycle_t ret;
- u64 last;
- u32 version;
- u8 flags;
- unsigned cpu, cpu1;
-
-
- /*
- * Note: hypervisor must guarantee that:
- * 1. cpu ID number maps 1:1 to per-CPU pvclock time info.
- * 2. that per-CPU pvclock time info is updated if the
- * underlying CPU changes.
- * 3. that version is increased whenever underlying CPU
- * changes.
- *
- */
- do {
- cpu = __getcpu() & VGETCPU_CPU_MASK;
- /* TODO: We can put vcpu id into higher bits of pvti.version.
- * This will save a couple of cycles by getting rid of
- * __getcpu() calls (Gleb).
- */
-
- pvti = get_pvti(cpu);
-
- version = __pvclock_read_cycles(&pvti->pvti, &ret, &flags);
-
- /*
- * Test we're still on the cpu as well as the version.
- * We could have been migrated just after the first
- * vgetcpu but before fetching the version, so we
- * wouldn't notice a version change.
- */
- cpu1 = __getcpu() & VGETCPU_CPU_MASK;
- } while (unlikely(cpu != cpu1 ||
- (pvti->pvti.version & 1) ||
- pvti->pvti.version != version));
-
- if (unlikely(!(flags & PVCLOCK_TSC_STABLE_BIT)))
- *mode = VCLOCK_NONE;
-
- /* refer to tsc.c read_tsc() comment for rationale */
- last = gtod->cycle_last;
-
- if (likely(ret >= last))
- return ret;
-
- return last;
-}
-#endif
#else
@@ -162,15 +95,77 @@ notrace static long vdso_fallback_gtod(struct timeval *tv, struct timezone *tz)
return ret;
}
+#endif
+
#ifdef CONFIG_PARAVIRT_CLOCK
+static notrace const struct pvclock_vsyscall_time_info *get_pvti0(void)
+{
+ return (const struct pvclock_vsyscall_time_info *)&pvclock_page;
+}
static notrace cycle_t vread_pvclock(int *mode)
{
- *mode = VCLOCK_NONE;
- return 0;
-}
-#endif
+ const struct pvclock_vcpu_time_info *pvti = &get_pvti0()->pvti;
+ cycle_t ret;
+ u64 tsc, pvti_tsc;
+ u64 last, delta, pvti_system_time;
+ u32 version, pvti_tsc_to_system_mul, pvti_tsc_shift;
+
+ /*
+ * Note: The kernel and hypervisor must guarantee that cpu ID
+ * number maps 1:1 to per-CPU pvclock time info.
+ *
+ * Because the hypervisor is entirely unaware of guest userspace
+ * preemption, it cannot guarantee that per-CPU pvclock time
+ * info is updated if the underlying CPU changes or that that
+ * version is increased whenever underlying CPU changes.
+ *
+ * On KVM, we are guaranteed that pvti updates for any vCPU are
+ * atomic as seen by *all* vCPUs. This is an even stronger
+ * guarantee than we get with a normal seqlock.
+ *
+ * On Xen, we don't appear to have that guarantee, but Xen still
+ * supplies a valid seqlock using the version field.
+
+ * We only do pvclock vdso timing at all if
+ * PVCLOCK_TSC_STABLE_BIT is set, and we interpret that bit to
+ * mean that all vCPUs have matching pvti and that the TSC is
+ * synced, so we can just look at vCPU 0's pvti.
+ */
+ if (unlikely(!(pvti->flags & PVCLOCK_TSC_STABLE_BIT))) {
+ *mode = VCLOCK_NONE;
+ return 0;
+ }
+
+ do {
+ version = pvti->version;
+
+ smp_rmb();
+
+ tsc = rdtsc_ordered();
+ pvti_tsc_to_system_mul = pvti->tsc_to_system_mul;
+ pvti_tsc_shift = pvti->tsc_shift;
+ pvti_system_time = pvti->system_time;
+ pvti_tsc = pvti->tsc_timestamp;
+
+ /* Make sure that the version double-check is last. */
+ smp_rmb();
+ } while (unlikely((version & 1) || version != pvti->version));
+
+ delta = tsc - pvti_tsc;
+ ret = pvti_system_time +
+ pvclock_scale_delta(delta, pvti_tsc_to_system_mul,
+ pvti_tsc_shift);
+
+ /* refer to vread_tsc() comment for rationale */
+ last = gtod->cycle_last;
+
+ if (likely(ret >= last))
+ return ret;
+
+ return last;
+}
#endif
notrace static cycle_t vread_tsc(void)
diff --git a/arch/x86/entry/vdso/vdso-layout.lds.S b/arch/x86/entry/vdso/vdso-layout.lds.S
index de2c921..4158acc 100644
--- a/arch/x86/entry/vdso/vdso-layout.lds.S
+++ b/arch/x86/entry/vdso/vdso-layout.lds.S
@@ -25,7 +25,7 @@ SECTIONS
* segment.
*/
- vvar_start = . - 2 * PAGE_SIZE;
+ vvar_start = . - 3 * PAGE_SIZE;
vvar_page = vvar_start;
/* Place all vvars at the offsets in asm/vvar.h. */
@@ -36,6 +36,7 @@ SECTIONS
#undef EMIT_VVAR
hpet_page = vvar_start + PAGE_SIZE;
+ pvclock_page = vvar_start + 2 * PAGE_SIZE;
. = SIZEOF_HEADERS;
diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c
index 785d992..491020b 100644
--- a/arch/x86/entry/vdso/vdso2c.c
+++ b/arch/x86/entry/vdso/vdso2c.c
@@ -73,6 +73,7 @@ enum {
sym_vvar_start,
sym_vvar_page,
sym_hpet_page,
+ sym_pvclock_page,
sym_VDSO_FAKE_SECTION_TABLE_START,
sym_VDSO_FAKE_SECTION_TABLE_END,
};
@@ -80,6 +81,7 @@ enum {
const int special_pages[] = {
sym_vvar_page,
sym_hpet_page,
+ sym_pvclock_page,
};
struct vdso_sym {
@@ -91,6 +93,7 @@ struct vdso_sym required_syms[] = {
[sym_vvar_start] = {"vvar_start", true},
[sym_vvar_page] = {"vvar_page", true},
[sym_hpet_page] = {"hpet_page", true},
+ [sym_pvclock_page] = {"pvclock_page", true},
[sym_VDSO_FAKE_SECTION_TABLE_START] = {
"VDSO_FAKE_SECTION_TABLE_START", false
},
diff --git a/arch/x86/entry/vdso/vdso32/system_call.S b/arch/x86/entry/vdso/vdso32/system_call.S
index 93bd845..3a1d929 100644
--- a/arch/x86/entry/vdso/vdso32/system_call.S
+++ b/arch/x86/entry/vdso/vdso32/system_call.S
@@ -1,5 +1,5 @@
/*
- * Code for the vDSO. This version uses the old int $0x80 method.
+ * AT_SYSINFO entry point
*/
#include <asm/dwarf2.h>
@@ -21,35 +21,67 @@ __kernel_vsyscall:
/*
* Reshuffle regs so that all of any of the entry instructions
* will preserve enough state.
+ *
+ * A really nice entry sequence would be:
+ * pushl %edx
+ * pushl %ecx
+ * movl %esp, %ecx
+ *
+ * Unfortunately, naughty Android versions between July and December
+ * 2015 actually hardcode the traditional Linux SYSENTER entry
+ * sequence. That is severely broken for a number of reasons (ask
+ * anyone with an AMD CPU, for example). Nonetheless, we try to keep
+ * it working approximately as well as it ever worked.
+ *
+ * This link may eludicate some of the history:
+ * https://android-review.googlesource.com/#/q/Iac3295376d61ef83e713ac9b528f3b50aa780cd7
+ * personally, I find it hard to understand what's going on there.
+ *
+ * Note to future user developers: DO NOT USE SYSENTER IN YOUR CODE.
+ * Execute an indirect call to the address in the AT_SYSINFO auxv
+ * entry. That is the ONLY correct way to make a fast 32-bit system
+ * call on Linux. (Open-coding int $0x80 is also fine, but it's
+ * slow.)
*/
+ pushl %ecx
+ CFI_ADJUST_CFA_OFFSET 4
+ CFI_REL_OFFSET ecx, 0
pushl %edx
CFI_ADJUST_CFA_OFFSET 4
CFI_REL_OFFSET edx, 0
- pushl %ecx
+ pushl %ebp
CFI_ADJUST_CFA_OFFSET 4
- CFI_REL_OFFSET ecx, 0
- movl %esp, %ecx
+ CFI_REL_OFFSET ebp, 0
+
+ #define SYSENTER_SEQUENCE "movl %esp, %ebp; sysenter"
+ #define SYSCALL_SEQUENCE "movl %ecx, %ebp; syscall"
#ifdef CONFIG_X86_64
/* If SYSENTER (Intel) or SYSCALL32 (AMD) is available, use it. */
- ALTERNATIVE_2 "", "sysenter", X86_FEATURE_SYSENTER32, \
- "syscall", X86_FEATURE_SYSCALL32
+ ALTERNATIVE_2 "", SYSENTER_SEQUENCE, X86_FEATURE_SYSENTER32, \
+ SYSCALL_SEQUENCE, X86_FEATURE_SYSCALL32
#else
- ALTERNATIVE "", "sysenter", X86_FEATURE_SEP
+ ALTERNATIVE "", SYSENTER_SEQUENCE, X86_FEATURE_SEP
#endif
/* Enter using int $0x80 */
- movl (%esp), %ecx
int $0x80
GLOBAL(int80_landing_pad)
- /* Restore ECX and EDX in case they were clobbered. */
- popl %ecx
- CFI_RESTORE ecx
+ /*
+ * Restore EDX and ECX in case they were clobbered. EBP is not
+ * clobbered (the kernel restores it), but it's cleaner and
+ * probably faster to pop it than to adjust ESP using addl.
+ */
+ popl %ebp
+ CFI_RESTORE ebp
CFI_ADJUST_CFA_OFFSET -4
popl %edx
CFI_RESTORE edx
CFI_ADJUST_CFA_OFFSET -4
+ popl %ecx
+ CFI_RESTORE ecx
+ CFI_ADJUST_CFA_OFFSET -4
ret
CFI_ENDPROC
diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
index 64df471..b8f69e2 100644
--- a/arch/x86/entry/vdso/vma.c
+++ b/arch/x86/entry/vdso/vma.c
@@ -12,6 +12,7 @@
#include <linux/random.h>
#include <linux/elf.h>
#include <linux/cpu.h>
+#include <asm/pvclock.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
#include <asm/vdso.h>
@@ -100,6 +101,7 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
.name = "[vvar]",
.pages = no_pages,
};
+ struct pvclock_vsyscall_time_info *pvti;
if (calculate_addr) {
addr = vdso_addr(current->mm->start_stack,
@@ -169,6 +171,18 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
}
#endif
+ pvti = pvclock_pvti_cpu0_va();
+ if (pvti && image->sym_pvclock_page) {
+ ret = remap_pfn_range(vma,
+ text_start + image->sym_pvclock_page,
+ __pa(pvti) >> PAGE_SHIFT,
+ PAGE_SIZE,
+ PAGE_READONLY);
+
+ if (ret)
+ goto up_fail;
+ }
+
up_fail:
if (ret)
current->mm->context.vdso = NULL;
diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index a30316b..c80f6b6 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -23,6 +23,11 @@
#define APIC_VERBOSE 1
#define APIC_DEBUG 2
+/* Macros for apic_extnmi which controls external NMI masking */
+#define APIC_EXTNMI_BSP 0 /* Default */
+#define APIC_EXTNMI_ALL 1
+#define APIC_EXTNMI_NONE 2
+
/*
* Define the default level of output to be very little
* This can be turned up by using apic=verbose for more
@@ -303,6 +308,7 @@ struct apic {
unsigned int *apicid);
/* ipi */
+ void (*send_IPI)(int cpu, int vector);
void (*send_IPI_mask)(const struct cpumask *mask, int vector);
void (*send_IPI_mask_allbutself)(const struct cpumask *mask,
int vector);
diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h
index ae5fb83..3e86742 100644
--- a/arch/x86/include/asm/atomic.h
+++ b/arch/x86/include/asm/atomic.h
@@ -3,7 +3,6 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#include <asm/processor.h>
#include <asm/alternative.h>
#include <asm/cmpxchg.h>
#include <asm/rmwcc.h>
diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h
index a11c30b..a984111 100644
--- a/arch/x86/include/asm/atomic64_32.h
+++ b/arch/x86/include/asm/atomic64_32.h
@@ -3,7 +3,6 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#include <asm/processor.h>
//#include <asm/cmpxchg.h>
/* An 64bit atomic type */
diff --git a/arch/x86/include/asm/calgary.h b/arch/x86/include/asm/calgary.h
index 0d467b3..a8303eb 100644
--- a/arch/x86/include/asm/calgary.h
+++ b/arch/x86/include/asm/calgary.h
@@ -31,7 +31,7 @@
#include <asm/types.h>
struct iommu_table {
- struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
+ const struct cal_chipset_ops *chip_ops; /* chipset specific funcs */
unsigned long it_base; /* mapped address of tce table */
unsigned long it_hint; /* Hint for next alloc */
unsigned long *it_map; /* A simple allocation bitmap for now */
diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h
index f7e1429..e4959d0 100644
--- a/arch/x86/include/asm/cmpxchg_32.h
+++ b/arch/x86/include/asm/cmpxchg_32.h
@@ -109,6 +109,6 @@ static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
#endif
-#define system_has_cmpxchg_double() cpu_has_cx8
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX8)
#endif /* _ASM_X86_CMPXCHG_32_H */
diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h
index 1af9469..caa23a3 100644
--- a/arch/x86/include/asm/cmpxchg_64.h
+++ b/arch/x86/include/asm/cmpxchg_64.h
@@ -18,6 +18,6 @@ static inline void set_64bit(volatile u64 *ptr, u64 val)
cmpxchg_local((ptr), (o), (n)); \
})
-#define system_has_cmpxchg_double() cpu_has_cx16
+#define system_has_cmpxchg_double() boot_cpu_has(X86_FEATURE_CX16)
#endif /* _ASM_X86_CMPXCHG_64_H */
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index bf2caa1..678637a 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -36,4 +36,7 @@ extern int _debug_hotplug_cpu(int cpu, int action);
int mwait_usable(const struct cpuinfo_x86 *);
+unsigned int x86_family(unsigned int sig);
+unsigned int x86_model(unsigned int sig);
+unsigned int x86_stepping(unsigned int sig);
#endif /* _ASM_X86_CPU_H */
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index e4f8010..7ad8c94 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -12,7 +12,7 @@
#include <asm/disabled-features.h>
#endif
-#define NCAPINTS 14 /* N 32-bit words worth of info */
+#define NCAPINTS 16 /* N 32-bit words worth of info */
#define NBUGINTS 1 /* N 32-bit bug flags */
/*
@@ -181,22 +181,17 @@
/*
* Auxiliary flags: Linux defined - For features scattered in various
- * CPUID levels like 0x6, 0xA etc, word 7
+ * CPUID levels like 0x6, 0xA etc, word 7.
+ *
+ * Reuse free bits when adding new feature flags!
*/
-#define X86_FEATURE_IDA ( 7*32+ 0) /* Intel Dynamic Acceleration */
-#define X86_FEATURE_ARAT ( 7*32+ 1) /* Always Running APIC Timer */
+
#define X86_FEATURE_CPB ( 7*32+ 2) /* AMD Core Performance Boost */
#define X86_FEATURE_EPB ( 7*32+ 3) /* IA32_ENERGY_PERF_BIAS support */
-#define X86_FEATURE_PLN ( 7*32+ 5) /* Intel Power Limit Notification */
-#define X86_FEATURE_PTS ( 7*32+ 6) /* Intel Package Thermal Status */
-#define X86_FEATURE_DTHERM ( 7*32+ 7) /* Digital Thermal Sensor */
+
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
-#define X86_FEATURE_HWP ( 7*32+ 10) /* "hwp" Intel HWP */
-#define X86_FEATURE_HWP_NOTIFY ( 7*32+ 11) /* Intel HWP_NOTIFY */
-#define X86_FEATURE_HWP_ACT_WINDOW ( 7*32+ 12) /* Intel HWP_ACT_WINDOW */
-#define X86_FEATURE_HWP_EPP ( 7*32+13) /* Intel HWP_EPP */
-#define X86_FEATURE_HWP_PKG_REQ ( 7*32+14) /* Intel HWP_PKG_REQ */
+
#define X86_FEATURE_INTEL_PT ( 7*32+15) /* Intel Processor Trace */
/* Virtualization flags: Linux defined, word 8 */
@@ -205,17 +200,9 @@
#define X86_FEATURE_FLEXPRIORITY ( 8*32+ 2) /* Intel FlexPriority */
#define X86_FEATURE_EPT ( 8*32+ 3) /* Intel Extended Page Table */
#define X86_FEATURE_VPID ( 8*32+ 4) /* Intel Virtual Processor ID */
-#define X86_FEATURE_NPT ( 8*32+ 5) /* AMD Nested Page Table support */
-#define X86_FEATURE_LBRV ( 8*32+ 6) /* AMD LBR Virtualization support */
-#define X86_FEATURE_SVML ( 8*32+ 7) /* "svm_lock" AMD SVM locking MSR */
-#define X86_FEATURE_NRIPS ( 8*32+ 8) /* "nrip_save" AMD SVM next_rip save */
-#define X86_FEATURE_TSCRATEMSR ( 8*32+ 9) /* "tsc_scale" AMD TSC scaling support */
-#define X86_FEATURE_VMCBCLEAN ( 8*32+10) /* "vmcb_clean" AMD VMCB clean bits support */
-#define X86_FEATURE_FLUSHBYASID ( 8*32+11) /* AMD flush-by-ASID support */
-#define X86_FEATURE_DECODEASSISTS ( 8*32+12) /* AMD Decode Assists support */
-#define X86_FEATURE_PAUSEFILTER ( 8*32+13) /* AMD filtered pause intercept */
-#define X86_FEATURE_PFTHRESHOLD ( 8*32+14) /* AMD pause filter threshold */
+
#define X86_FEATURE_VMMCALL ( 8*32+15) /* Prefer vmmcall to vmcall */
+#define X86_FEATURE_XENPV ( 8*32+16) /* "" Xen paravirtual guest */
/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
@@ -258,6 +245,30 @@
/* AMD-defined CPU features, CPUID level 0x80000008 (ebx), word 13 */
#define X86_FEATURE_CLZERO (13*32+0) /* CLZERO instruction */
+/* Thermal and Power Management Leaf, CPUID level 0x00000006 (eax), word 14 */
+#define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */
+#define X86_FEATURE_IDA (14*32+ 1) /* Intel Dynamic Acceleration */
+#define X86_FEATURE_ARAT (14*32+ 2) /* Always Running APIC Timer */
+#define X86_FEATURE_PLN (14*32+ 4) /* Intel Power Limit Notification */
+#define X86_FEATURE_PTS (14*32+ 6) /* Intel Package Thermal Status */
+#define X86_FEATURE_HWP (14*32+ 7) /* Intel Hardware P-states */
+#define X86_FEATURE_HWP_NOTIFY (14*32+ 8) /* HWP Notification */
+#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */
+#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */
+#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */
+
+/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx), word 15 */
+#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */
+#define X86_FEATURE_LBRV (15*32+ 1) /* LBR Virtualization support */
+#define X86_FEATURE_SVML (15*32+ 2) /* "svm_lock" SVM locking MSR */
+#define X86_FEATURE_NRIPS (15*32+ 3) /* "nrip_save" SVM next_rip save */
+#define X86_FEATURE_TSCRATEMSR (15*32+ 4) /* "tsc_scale" TSC scaling support */
+#define X86_FEATURE_VMCBCLEAN (15*32+ 5) /* "vmcb_clean" VMCB clean bits support */
+#define X86_FEATURE_FLUSHBYASID (15*32+ 6) /* flush-by-ASID support */
+#define X86_FEATURE_DECODEASSISTS (15*32+ 7) /* Decode Assists support */
+#define X86_FEATURE_PAUSEFILTER (15*32+10) /* filtered pause intercept */
+#define X86_FEATURE_PFTHRESHOLD (15*32+12) /* pause filter threshold */
+
/*
* BUG word(s)
*/
@@ -278,6 +289,26 @@
#include <asm/asm.h>
#include <linux/bitops.h>
+enum cpuid_leafs
+{
+ CPUID_1_EDX = 0,
+ CPUID_8000_0001_EDX,
+ CPUID_8086_0001_EDX,
+ CPUID_LNX_1,
+ CPUID_1_ECX,
+ CPUID_C000_0001_EDX,
+ CPUID_8000_0001_ECX,
+ CPUID_LNX_2,
+ CPUID_LNX_3,
+ CPUID_7_0_EBX,
+ CPUID_D_1_EAX,
+ CPUID_F_0_EDX,
+ CPUID_F_1_EDX,
+ CPUID_8000_0008_EBX,
+ CPUID_6_EAX,
+ CPUID_8000_000A_EDX,
+};
+
#ifdef CONFIG_X86_FEATURE_NAMES
extern const char * const x86_cap_flags[NCAPINTS*32];
extern const char * const x86_power_flags[32];
@@ -355,60 +386,31 @@ extern const char * const x86_bug_flags[NBUGINTS*32];
} while (0)
#define cpu_has_fpu boot_cpu_has(X86_FEATURE_FPU)
-#define cpu_has_de boot_cpu_has(X86_FEATURE_DE)
#define cpu_has_pse boot_cpu_has(X86_FEATURE_PSE)
#define cpu_has_tsc boot_cpu_has(X86_FEATURE_TSC)
#define cpu_has_pge boot_cpu_has(X86_FEATURE_PGE)
#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC)
-#define cpu_has_sep boot_cpu_has(X86_FEATURE_SEP)
-#define cpu_has_mtrr boot_cpu_has(X86_FEATURE_MTRR)
-#define cpu_has_mmx boot_cpu_has(X86_FEATURE_MMX)
#define cpu_has_fxsr boot_cpu_has(X86_FEATURE_FXSR)
#define cpu_has_xmm boot_cpu_has(X86_FEATURE_XMM)
#define cpu_has_xmm2 boot_cpu_has(X86_FEATURE_XMM2)
-#define cpu_has_xmm3 boot_cpu_has(X86_FEATURE_XMM3)
-#define cpu_has_ssse3 boot_cpu_has(X86_FEATURE_SSSE3)
#define cpu_has_aes boot_cpu_has(X86_FEATURE_AES)
#define cpu_has_avx boot_cpu_has(X86_FEATURE_AVX)
#define cpu_has_avx2 boot_cpu_has(X86_FEATURE_AVX2)
-#define cpu_has_ht boot_cpu_has(X86_FEATURE_HT)
-#define cpu_has_nx boot_cpu_has(X86_FEATURE_NX)
-#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE)
-#define cpu_has_xstore_enabled boot_cpu_has(X86_FEATURE_XSTORE_EN)
-#define cpu_has_xcrypt boot_cpu_has(X86_FEATURE_XCRYPT)
-#define cpu_has_xcrypt_enabled boot_cpu_has(X86_FEATURE_XCRYPT_EN)
-#define cpu_has_ace2 boot_cpu_has(X86_FEATURE_ACE2)
-#define cpu_has_ace2_enabled boot_cpu_has(X86_FEATURE_ACE2_EN)
-#define cpu_has_phe boot_cpu_has(X86_FEATURE_PHE)
-#define cpu_has_phe_enabled boot_cpu_has(X86_FEATURE_PHE_EN)
-#define cpu_has_pmm boot_cpu_has(X86_FEATURE_PMM)
-#define cpu_has_pmm_enabled boot_cpu_has(X86_FEATURE_PMM_EN)
-#define cpu_has_ds boot_cpu_has(X86_FEATURE_DS)
-#define cpu_has_pebs boot_cpu_has(X86_FEATURE_PEBS)
#define cpu_has_clflush boot_cpu_has(X86_FEATURE_CLFLUSH)
-#define cpu_has_bts boot_cpu_has(X86_FEATURE_BTS)
#define cpu_has_gbpages boot_cpu_has(X86_FEATURE_GBPAGES)
#define cpu_has_arch_perfmon boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
#define cpu_has_pat boot_cpu_has(X86_FEATURE_PAT)
-#define cpu_has_xmm4_1 boot_cpu_has(X86_FEATURE_XMM4_1)
-#define cpu_has_xmm4_2 boot_cpu_has(X86_FEATURE_XMM4_2)
#define cpu_has_x2apic boot_cpu_has(X86_FEATURE_X2APIC)
#define cpu_has_xsave boot_cpu_has(X86_FEATURE_XSAVE)
-#define cpu_has_xsaveopt boot_cpu_has(X86_FEATURE_XSAVEOPT)
#define cpu_has_xsaves boot_cpu_has(X86_FEATURE_XSAVES)
#define cpu_has_osxsave boot_cpu_has(X86_FEATURE_OSXSAVE)
#define cpu_has_hypervisor boot_cpu_has(X86_FEATURE_HYPERVISOR)
-#define cpu_has_pclmulqdq boot_cpu_has(X86_FEATURE_PCLMULQDQ)
-#define cpu_has_perfctr_core boot_cpu_has(X86_FEATURE_PERFCTR_CORE)
-#define cpu_has_perfctr_nb boot_cpu_has(X86_FEATURE_PERFCTR_NB)
-#define cpu_has_perfctr_l2 boot_cpu_has(X86_FEATURE_PERFCTR_L2)
-#define cpu_has_cx8 boot_cpu_has(X86_FEATURE_CX8)
-#define cpu_has_cx16 boot_cpu_has(X86_FEATURE_CX16)
-#define cpu_has_eager_fpu boot_cpu_has(X86_FEATURE_EAGER_FPU)
-#define cpu_has_topoext boot_cpu_has(X86_FEATURE_TOPOEXT)
-#define cpu_has_bpext boot_cpu_has(X86_FEATURE_BPEXT)
-
-#if __GNUC__ >= 4
+/*
+ * Do not add any more of those clumsy macros - use static_cpu_has_safe() for
+ * fast paths and boot_cpu_has() otherwise!
+ */
+
+#if __GNUC__ >= 4 && defined(CONFIG_X86_FAST_FEATURE_TESTS)
extern void warn_pre_alternatives(void);
extern bool __static_cpu_has_safe(u16 bit);
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index f80d700..6d7d0e5 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -19,7 +19,6 @@
#include <asm/acpi.h>
#include <asm/apicdef.h>
#include <asm/page.h>
-#include <asm/pvclock.h>
#ifdef CONFIG_X86_32
#include <linux/threads.h>
#include <asm/kmap_types.h>
@@ -72,10 +71,6 @@ enum fixed_addresses {
#ifdef CONFIG_X86_VSYSCALL_EMULATION
VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT,
#endif
-#ifdef CONFIG_PARAVIRT_CLOCK
- PVCLOCK_FIXMAP_BEGIN,
- PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1,
-#endif
#endif
FIX_DBGP_BASE,
FIX_EARLYCON_MEM_BASE,
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h
index 3c3550c..eadcdd5 100644
--- a/arch/x86/include/asm/fpu/internal.h
+++ b/arch/x86/include/asm/fpu/internal.h
@@ -224,18 +224,67 @@ static inline void copy_fxregs_to_kernel(struct fpu *fpu)
#define XRSTOR ".byte " REX_PREFIX "0x0f,0xae,0x2f"
#define XRSTORS ".byte " REX_PREFIX "0x0f,0xc7,0x1f"
-/* xstate instruction fault handler: */
-#define xstate_fault(__err) \
- \
- ".section .fixup,\"ax\"\n" \
- \
- "3: movl $-2,%[_err]\n" \
- " jmp 2b\n" \
- \
- ".previous\n" \
- \
- _ASM_EXTABLE(1b, 3b) \
- : [_err] "=r" (__err)
+#define XSTATE_OP(op, st, lmask, hmask, err) \
+ asm volatile("1:" op "\n\t" \
+ "xor %[err], %[err]\n" \
+ "2:\n\t" \
+ ".pushsection .fixup,\"ax\"\n\t" \
+ "3: movl $-2,%[err]\n\t" \
+ "jmp 2b\n\t" \
+ ".popsection\n\t" \
+ _ASM_EXTABLE(1b, 3b) \
+ : [err] "=r" (err) \
+ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
+ : "memory")
+
+/*
+ * If XSAVES is enabled, it replaces XSAVEOPT because it supports a compact
+ * format and supervisor states in addition to modified optimization in
+ * XSAVEOPT.
+ *
+ * Otherwise, if XSAVEOPT is enabled, XSAVEOPT replaces XSAVE because XSAVEOPT
+ * supports modified optimization which is not supported by XSAVE.
+ *
+ * We use XSAVE as a fallback.
+ *
+ * The 661 label is defined in the ALTERNATIVE* macros as the address of the
+ * original instruction which gets replaced. We need to use it here as the
+ * address of the instruction where we might get an exception at.
+ */
+#define XSTATE_XSAVE(st, lmask, hmask, err) \
+ asm volatile(ALTERNATIVE_2(XSAVE, \
+ XSAVEOPT, X86_FEATURE_XSAVEOPT, \
+ XSAVES, X86_FEATURE_XSAVES) \
+ "\n" \
+ "xor %[err], %[err]\n" \
+ "3:\n" \
+ ".pushsection .fixup,\"ax\"\n" \
+ "4: movl $-2, %[err]\n" \
+ "jmp 3b\n" \
+ ".popsection\n" \
+ _ASM_EXTABLE(661b, 4b) \
+ : [err] "=r" (err) \
+ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
+ : "memory")
+
+/*
+ * Use XRSTORS to restore context if it is enabled. XRSTORS supports compact
+ * XSAVE area format.
+ */
+#define XSTATE_XRESTORE(st, lmask, hmask, err) \
+ asm volatile(ALTERNATIVE(XRSTOR, \
+ XRSTORS, X86_FEATURE_XSAVES) \
+ "\n" \
+ "xor %[err], %[err]\n" \
+ "3:\n" \
+ ".pushsection .fixup,\"ax\"\n" \
+ "4: movl $-2, %[err]\n" \
+ "jmp 3b\n" \
+ ".popsection\n" \
+ _ASM_EXTABLE(661b, 4b) \
+ : [err] "=r" (err) \
+ : "D" (st), "m" (*st), "a" (lmask), "d" (hmask) \
+ : "memory")
/*
* This function is called only during boot time when x86 caps are not set
@@ -246,22 +295,14 @@ static inline void copy_xregs_to_kernel_booting(struct xregs_state *xstate)
u64 mask = -1;
u32 lmask = mask;
u32 hmask = mask >> 32;
- int err = 0;
+ int err;
WARN_ON(system_state != SYSTEM_BOOTING);
- if (boot_cpu_has(X86_FEATURE_XSAVES))
- asm volatile("1:"XSAVES"\n\t"
- "2:\n\t"
- xstate_fault(err)
- : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
- : "memory");
+ if (static_cpu_has_safe(X86_FEATURE_XSAVES))
+ XSTATE_OP(XSAVES, xstate, lmask, hmask, err);
else
- asm volatile("1:"XSAVE"\n\t"
- "2:\n\t"
- xstate_fault(err)
- : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
- : "memory");
+ XSTATE_OP(XSAVE, xstate, lmask, hmask, err);
/* We should never fault when copying to a kernel buffer: */
WARN_ON_FPU(err);
@@ -276,22 +317,14 @@ static inline void copy_kernel_to_xregs_booting(struct xregs_state *xstate)
u64 mask = -1;
u32 lmask = mask;
u32 hmask = mask >> 32;
- int err = 0;
+ int err;
WARN_ON(system_state != SYSTEM_BOOTING);
- if (boot_cpu_has(X86_FEATURE_XSAVES))
- asm volatile("1:"XRSTORS"\n\t"
- "2:\n\t"
- xstate_fault(err)
- : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
- : "memory");
+ if (static_cpu_has_safe(X86_FEATURE_XSAVES))
+ XSTATE_OP(XRSTORS, xstate, lmask, hmask, err);
else
- asm volatile("1:"XRSTOR"\n\t"
- "2:\n\t"
- xstate_fault(err)
- : "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask), "0" (err)
- : "memory");
+ XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
/* We should never fault when copying from a kernel buffer: */
WARN_ON_FPU(err);
@@ -305,33 +338,11 @@ static inline void copy_xregs_to_kernel(struct xregs_state *xstate)
u64 mask = -1;
u32 lmask = mask;
u32 hmask = mask >> 32;
- int err = 0;
+ int err;
WARN_ON(!alternatives_patched);
- /*
- * If xsaves is enabled, xsaves replaces xsaveopt because
- * it supports compact format and supervisor states in addition to
- * modified optimization in xsaveopt.
- *
- * Otherwise, if xsaveopt is enabled, xsaveopt replaces xsave
- * because xsaveopt supports modified optimization which is not
- * supported by xsave.
- *
- * If none of xsaves and xsaveopt is enabled, use xsave.
- */
- alternative_input_2(
- "1:"XSAVE,
- XSAVEOPT,
- X86_FEATURE_XSAVEOPT,
- XSAVES,
- X86_FEATURE_XSAVES,
- [xstate] "D" (xstate), "a" (lmask), "d" (hmask) :
- "memory");
- asm volatile("2:\n\t"
- xstate_fault(err)
- : "0" (err)
- : "memory");
+ XSTATE_XSAVE(xstate, lmask, hmask, err);
/* We should never fault when copying to a kernel buffer: */
WARN_ON_FPU(err);
@@ -344,23 +355,9 @@ static inline void copy_kernel_to_xregs(struct xregs_state *xstate, u64 mask)
{
u32 lmask = mask;
u32 hmask = mask >> 32;
- int err = 0;
+ int err;
- /*
- * Use xrstors to restore context if it is enabled. xrstors supports
- * compacted format of xsave area which is not supported by xrstor.
- */
- alternative_input(
- "1: " XRSTOR,
- XRSTORS,
- X86_FEATURE_XSAVES,
- "D" (xstate), "m" (*xstate), "a" (lmask), "d" (hmask)
- : "memory");
-
- asm volatile("2:\n"
- xstate_fault(err)
- : "0" (err)
- : "memory");
+ XSTATE_XRESTORE(xstate, lmask, hmask, err);
/* We should never fault when copying from a kernel buffer: */
WARN_ON_FPU(err);
@@ -388,12 +385,10 @@ static inline int copy_xregs_to_user(struct xregs_state __user *buf)
if (unlikely(err))
return -EFAULT;
- __asm__ __volatile__(ASM_STAC "\n"
- "1:"XSAVE"\n"
- "2: " ASM_CLAC "\n"
- xstate_fault(err)
- : "D" (buf), "a" (-1), "d" (-1), "0" (err)
- : "memory");
+ stac();
+ XSTATE_OP(XSAVE, buf, -1, -1, err);
+ clac();
+
return err;
}
@@ -405,14 +400,12 @@ static inline int copy_user_to_xregs(struct xregs_state __user *buf, u64 mask)
struct xregs_state *xstate = ((__force struct xregs_state *)buf);
u32 lmask = mask;
u32 hmask = mask >> 32;
- int err = 0;
-
- __asm__ __volatile__(ASM_STAC "\n"
- "1:"XRSTOR"\n"
- "2: " ASM_CLAC "\n"
- xstate_fault(err)
- : "D" (xstate), "a" (lmask), "d" (hmask), "0" (err)
- : "memory"); /* memory required? */
+ int err;
+
+ stac();
+ XSTATE_OP(XRSTOR, xstate, lmask, hmask, err);
+ clac();
+
return err;
}
diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h
index ccffa53..39bcefc 100644
--- a/arch/x86/include/asm/i8259.h
+++ b/arch/x86/include/asm/i8259.h
@@ -60,6 +60,7 @@ struct legacy_pic {
void (*mask_all)(void);
void (*restore_mask)(void);
void (*init)(int auto_eoi);
+ int (*probe)(void);
int (*irq_pending)(unsigned int irq);
void (*make_irq)(unsigned int irq);
};
diff --git a/arch/x86/include/asm/intel_pt.h b/arch/x86/include/asm/intel_pt.h
new file mode 100644
index 0000000..e1a4117
--- /dev/null
+++ b/arch/x86/include/asm/intel_pt.h
@@ -0,0 +1,10 @@
+#ifndef _ASM_X86_INTEL_PT_H
+#define _ASM_X86_INTEL_PT_H
+
+#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL)
+void cpu_emergency_stop_pt(void);
+#else
+static inline void cpu_emergency_stop_pt(void) {}
+#endif
+
+#endif /* _ASM_X86_INTEL_PT_H */
diff --git a/arch/x86/include/asm/ipi.h b/arch/x86/include/asm/ipi.h
index 615fa90..cfc9a0d 100644
--- a/arch/x86/include/asm/ipi.h
+++ b/arch/x86/include/asm/ipi.h
@@ -119,6 +119,8 @@ static inline void
native_apic_mem_write(APIC_ICR, cfg);
}
+extern void default_send_IPI_single(int cpu, int vector);
+extern void default_send_IPI_single_phys(int cpu, int vector);
extern void default_send_IPI_mask_sequence_phys(const struct cpumask *mask,
int vector);
extern void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_label.h
index 5daeca3..adc54c1 100644
--- a/arch/x86/include/asm/jump_label.h
+++ b/arch/x86/include/asm/jump_label.h
@@ -1,12 +1,18 @@
#ifndef _ASM_X86_JUMP_LABEL_H
#define _ASM_X86_JUMP_LABEL_H
-#ifndef __ASSEMBLY__
-
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <asm/nops.h>
-#include <asm/asm.h>
+#ifndef HAVE_JUMP_LABEL
+/*
+ * For better or for worse, if jump labels (the gcc extension) are missing,
+ * then the entire static branch patching infrastructure is compiled out.
+ * If that happens, the code in here will malfunction. Raise a compiler
+ * error instead.
+ *
+ * In theory, jump labels and the static branch patching infrastructure
+ * could be decoupled to fix this.
+ */
+#error asm/jump_label.h included on a non-jump-label kernel
+#endif
#define JUMP_LABEL_NOP_SIZE 5
@@ -16,6 +22,14 @@
# define STATIC_KEY_INIT_NOP GENERIC_NOP5_ATOMIC
#endif
+#include <asm/asm.h>
+#include <asm/nops.h>
+
+#ifndef __ASSEMBLY__
+
+#include <linux/stringify.h>
+#include <linux/types.h>
+
static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
{
asm_volatile_goto("1:"
@@ -59,5 +73,40 @@ struct jump_entry {
jump_label_t key;
};
-#endif /* __ASSEMBLY__ */
+#else /* __ASSEMBLY__ */
+
+.macro STATIC_JUMP_IF_TRUE target, key, def
+.Lstatic_jump_\@:
+ .if \def
+ /* Equivalent to "jmp.d32 \target" */
+ .byte 0xe9
+ .long \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+ .else
+ .byte STATIC_KEY_INIT_NOP
+ .endif
+ .pushsection __jump_table, "aw"
+ _ASM_ALIGN
+ _ASM_PTR .Lstatic_jump_\@, \target, \key
+ .popsection
+.endm
+
+.macro STATIC_JUMP_IF_FALSE target, key, def
+.Lstatic_jump_\@:
+ .if \def
+ .byte STATIC_KEY_INIT_NOP
+ .else
+ /* Equivalent to "jmp.d32 \target" */
+ .byte 0xe9
+ .long \target - .Lstatic_jump_after_\@
+.Lstatic_jump_after_\@:
+ .endif
+ .pushsection __jump_table, "aw"
+ _ASM_ALIGN
+ _ASM_PTR .Lstatic_jump_\@, \target, \key + 1
+ .popsection
+.endm
+
+#endif /* __ASSEMBLY__ */
+
#endif
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 9265196..44adbb8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -25,6 +25,7 @@
#include <linux/pvclock_gtod.h>
#include <linux/clocksource.h>
#include <linux/irqbypass.h>
+#include <linux/hyperv.h>
#include <asm/pvclock-abi.h>
#include <asm/desc.h>
@@ -45,6 +46,31 @@
#define KVM_IRQCHIP_NUM_PINS KVM_IOAPIC_NUM_PINS
+/* x86-specific vcpu->requests bit members */
+#define KVM_REQ_MIGRATE_TIMER 8
+#define KVM_REQ_REPORT_TPR_ACCESS 9
+#define KVM_REQ_TRIPLE_FAULT 10
+#define KVM_REQ_MMU_SYNC 11
+#define KVM_REQ_CLOCK_UPDATE 12
+#define KVM_REQ_DEACTIVATE_FPU 13
+#define KVM_REQ_EVENT 14
+#define KVM_REQ_APF_HALT 15
+#define KVM_REQ_STEAL_UPDATE 16
+#define KVM_REQ_NMI 17
+#define KVM_REQ_PMU 18
+#define KVM_REQ_PMI 19
+#define KVM_REQ_SMI 20
+#define KVM_REQ_MASTERCLOCK_UPDATE 21
+#define KVM_REQ_MCLOCK_INPROGRESS 22
+#define KVM_REQ_SCAN_IOAPIC 23
+#define KVM_REQ_GLOBAL_CLOCK_UPDATE 24
+#define KVM_REQ_APIC_PAGE_RELOAD 25
+#define KVM_REQ_HV_CRASH 26
+#define KVM_REQ_IOAPIC_EOI_EXIT 27
+#define KVM_REQ_HV_RESET 28
+#define KVM_REQ_HV_EXIT 29
+#define KVM_REQ_HV_STIMER 30
+
#define CR0_RESERVED_BITS \
(~(unsigned long)(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS \
| X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM \
@@ -213,6 +239,10 @@ union kvm_mmu_page_role {
};
};
+struct kvm_rmap_head {
+ unsigned long val;
+};
+
struct kvm_mmu_page {
struct list_head link;
struct hlist_node hash_link;
@@ -230,7 +260,7 @@ struct kvm_mmu_page {
bool unsync;
int root_count; /* Currently serving as active root */
unsigned int unsync_children;
- unsigned long parent_ptes; /* Reverse mapping for parent_pte */
+ struct kvm_rmap_head parent_ptes; /* rmap pointers to parent sptes */
/* The page is obsolete if mmu_valid_gen != kvm->arch.mmu_valid_gen. */
unsigned long mmu_valid_gen;
@@ -374,10 +404,38 @@ struct kvm_mtrr {
struct list_head head;
};
+/* Hyper-V SynIC timer */
+struct kvm_vcpu_hv_stimer {
+ struct hrtimer timer;
+ int index;
+ u64 config;
+ u64 count;
+ u64 exp_time;
+ struct hv_message msg;
+ bool msg_pending;
+};
+
+/* Hyper-V synthetic interrupt controller (SynIC)*/
+struct kvm_vcpu_hv_synic {
+ u64 version;
+ u64 control;
+ u64 msg_page;
+ u64 evt_page;
+ atomic64_t sint[HV_SYNIC_SINT_COUNT];
+ atomic_t sint_to_gsi[HV_SYNIC_SINT_COUNT];
+ DECLARE_BITMAP(auto_eoi_bitmap, 256);
+ DECLARE_BITMAP(vec_bitmap, 256);
+ bool active;
+};
+
/* Hyper-V per vcpu emulation context */
struct kvm_vcpu_hv {
u64 hv_vapic;
s64 runtime_offset;
+ struct kvm_vcpu_hv_synic synic;
+ struct kvm_hyperv_exit exit;
+ struct kvm_vcpu_hv_stimer stimer[HV_SYNIC_STIMER_COUNT];
+ DECLARE_BITMAP(stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
};
struct kvm_vcpu_arch {
@@ -400,7 +458,8 @@ struct kvm_vcpu_arch {
u64 efer;
u64 apic_base;
struct kvm_lapic *apic; /* kernel irqchip context */
- u64 eoi_exit_bitmap[4];
+ bool apicv_active;
+ DECLARE_BITMAP(ioapic_handled_vectors, 256);
unsigned long apic_attention;
int32_t apic_arb_prio;
int mp_state;
@@ -505,6 +564,7 @@ struct kvm_vcpu_arch {
u32 virtual_tsc_mult;
u32 virtual_tsc_khz;
s64 ia32_tsc_adjust_msr;
+ u64 tsc_scaling_ratio;
atomic_t nmi_queued; /* unprocessed asynchronous NMIs */
unsigned nmi_pending; /* NMI queued after currently running handler */
@@ -588,7 +648,7 @@ struct kvm_lpage_info {
};
struct kvm_arch_memory_slot {
- unsigned long *rmap[KVM_NR_PAGE_SIZES];
+ struct kvm_rmap_head *rmap[KVM_NR_PAGE_SIZES];
struct kvm_lpage_info *lpage_info[KVM_NR_PAGE_SIZES - 1];
};
@@ -777,7 +837,7 @@ struct kvm_x86_ops {
void (*vcpu_load)(struct kvm_vcpu *vcpu, int cpu);
void (*vcpu_put)(struct kvm_vcpu *vcpu);
- void (*update_db_bp_intercept)(struct kvm_vcpu *vcpu);
+ void (*update_bp_intercept)(struct kvm_vcpu *vcpu);
int (*get_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
int (*set_msr)(struct kvm_vcpu *vcpu, struct msr_data *msr);
u64 (*get_segment_base)(struct kvm_vcpu *vcpu, int seg);
@@ -830,10 +890,11 @@ struct kvm_x86_ops {
void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
void (*enable_irq_window)(struct kvm_vcpu *vcpu);
void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
- int (*cpu_uses_apicv)(struct kvm_vcpu *vcpu);
+ bool (*get_enable_apicv)(void);
+ void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu);
void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr);
void (*hwapic_isr_update)(struct kvm *kvm, int isr);
- void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu);
+ void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu, bool set);
void (*set_apic_access_page_addr)(struct kvm_vcpu *vcpu, hpa_t hpa);
void (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu, int vector);
@@ -844,7 +905,7 @@ struct kvm_x86_ops {
int (*get_lpage_level)(void);
bool (*rdtscp_supported)(void);
bool (*invpcid_supported)(void);
- void (*adjust_tsc_offset)(struct kvm_vcpu *vcpu, s64 adjustment, bool host);
+ void (*adjust_tsc_offset_guest)(struct kvm_vcpu *vcpu, s64 adjustment);
void (*set_tdp_cr3)(struct kvm_vcpu *vcpu, unsigned long cr3);
@@ -852,11 +913,9 @@ struct kvm_x86_ops {
bool (*has_wbinvd_exit)(void);
- void (*set_tsc_khz)(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale);
u64 (*read_tsc_offset)(struct kvm_vcpu *vcpu);
void (*write_tsc_offset)(struct kvm_vcpu *vcpu, u64 offset);
- u64 (*compute_tsc_offset)(struct kvm_vcpu *vcpu, u64 target_tsc);
u64 (*read_l1_tsc)(struct kvm_vcpu *vcpu, u64 host_tsc);
void (*get_exit_info)(struct kvm_vcpu *vcpu, u64 *info1, u64 *info2);
@@ -923,17 +982,6 @@ struct kvm_arch_async_pf {
extern struct kvm_x86_ops *kvm_x86_ops;
-static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
- s64 adjustment)
-{
- kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, false);
-}
-
-static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
-{
- kvm_x86_ops->adjust_tsc_offset(vcpu, adjustment, true);
-}
-
int kvm_mmu_module_init(void);
void kvm_mmu_module_exit(void);
@@ -986,10 +1034,12 @@ u64 vcpu_tsc_khz(struct kvm_vcpu *vcpu);
/* control of guest tsc rate supported? */
extern bool kvm_has_tsc_control;
-/* minimum supported tsc_khz for guests */
-extern u32 kvm_min_guest_tsc_khz;
/* maximum supported tsc_khz for guests */
extern u32 kvm_max_guest_tsc_khz;
+/* number of bits of the fractional part of the TSC scaling ratio */
+extern u8 kvm_tsc_scaling_ratio_frac_bits;
+/* maximum allowed value of TSC scaling ratio */
+extern u64 kvm_max_tsc_scaling_ratio;
enum emulation_result {
EMULATE_DONE, /* no further processing */
@@ -1096,6 +1146,8 @@ gpa_t kvm_mmu_gva_to_gpa_write(struct kvm_vcpu *vcpu, gva_t gva,
gpa_t kvm_mmu_gva_to_gpa_system(struct kvm_vcpu *vcpu, gva_t gva,
struct x86_exception *exception);
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu);
+
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu);
int kvm_mmu_page_fault(struct kvm_vcpu *vcpu, gva_t gva, u32 error_code,
@@ -1235,9 +1287,15 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
void kvm_define_shared_msr(unsigned index, u32 msr);
int kvm_set_shared_msr(unsigned index, u64 val, u64 mask);
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc);
+u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc);
+
unsigned long kvm_get_linear_rip(struct kvm_vcpu *vcpu);
bool kvm_is_linear_rip(struct kvm_vcpu *vcpu, unsigned long linear_rip);
+void kvm_make_mclock_inprogress_request(struct kvm *kvm);
+void kvm_make_scan_ioapic_request(struct kvm *kvm);
+
void kvm_arch_async_page_not_present(struct kvm_vcpu *vcpu,
struct kvm_async_pf *work);
void kvm_arch_async_page_present(struct kvm_vcpu *vcpu,
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 34e62b1..1e1b07a 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -1,6 +1,7 @@
#ifndef _ASM_X86_MICROCODE_H
#define _ASM_X86_MICROCODE_H
+#include <asm/cpu.h>
#include <linux/earlycpio.h>
#define native_rdmsr(msr, val1, val2) \
@@ -95,14 +96,14 @@ static inline void __exit exit_amd_microcode(void) {}
/*
* In early loading microcode phase on BSP, boot_cpu_data is not set up yet.
- * x86_vendor() gets vendor id for BSP.
+ * x86_cpuid_vendor() gets vendor id for BSP.
*
* In 32 bit AP case, accessing boot_cpu_data needs linear address. To simplify
- * coding, we still use x86_vendor() to get vendor id for AP.
+ * coding, we still use x86_cpuid_vendor() to get vendor id for AP.
*
- * x86_vendor() gets vendor information directly from CPUID.
+ * x86_cpuid_vendor() gets vendor information directly from CPUID.
*/
-static inline int x86_vendor(void)
+static inline int x86_cpuid_vendor(void)
{
u32 eax = 0x00000000;
u32 ebx, ecx = 0, edx;
@@ -118,40 +119,14 @@ static inline int x86_vendor(void)
return X86_VENDOR_UNKNOWN;
}
-static inline unsigned int __x86_family(unsigned int sig)
-{
- unsigned int x86;
-
- x86 = (sig >> 8) & 0xf;
-
- if (x86 == 0xf)
- x86 += (sig >> 20) & 0xff;
-
- return x86;
-}
-
-static inline unsigned int x86_family(void)
+static inline unsigned int x86_cpuid_family(void)
{
u32 eax = 0x00000001;
u32 ebx, ecx = 0, edx;
native_cpuid(&eax, &ebx, &ecx, &edx);
- return __x86_family(eax);
-}
-
-static inline unsigned int x86_model(unsigned int sig)
-{
- unsigned int x86, model;
-
- x86 = __x86_family(sig);
-
- model = (sig >> 4) & 0xf;
-
- if (x86 == 0x6 || x86 == 0xf)
- model += ((sig >> 16) & 0xf) << 4;
-
- return model;
+ return x86_family(eax);
}
#ifdef CONFIG_MICROCODE
diff --git a/arch/x86/include/asm/msi.h b/arch/x86/include/asm/msi.h
index 93724cc..eb4b09b 100644
--- a/arch/x86/include/asm/msi.h
+++ b/arch/x86/include/asm/msi.h
@@ -1,7 +1,13 @@
#ifndef _ASM_X86_MSI_H
#define _ASM_X86_MSI_H
#include <asm/hw_irq.h>
+#include <asm/irqdomain.h>
typedef struct irq_alloc_info msi_alloc_info_t;
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+ msi_alloc_info_t *arg);
+
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc);
+
#endif /* _ASM_X86_MSI_H */
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 9f39056..b05402e 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -35,7 +35,7 @@
#define MSR_IA32_PERFCTR0 0x000000c1
#define MSR_IA32_PERFCTR1 0x000000c2
#define MSR_FSB_FREQ 0x000000cd
-#define MSR_NHM_PLATFORM_INFO 0x000000ce
+#define MSR_PLATFORM_INFO 0x000000ce
#define MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2
#define NHM_C3_AUTO_DEMOTE (1UL << 25)
@@ -44,7 +44,6 @@
#define SNB_C1_AUTO_UNDEMOTE (1UL << 27)
#define SNB_C3_AUTO_UNDEMOTE (1UL << 28)
-#define MSR_PLATFORM_INFO 0x000000ce
#define MSR_MTRRcap 0x000000fe
#define MSR_IA32_BBL_CR_CTL 0x00000119
#define MSR_IA32_BBL_CR_CTL3 0x0000011e
@@ -322,6 +321,7 @@
#define MSR_F15H_PERF_CTR 0xc0010201
#define MSR_F15H_NB_PERF_CTL 0xc0010240
#define MSR_F15H_NB_PERF_CTR 0xc0010241
+#define MSR_F15H_IC_CFG 0xc0011021
/* Fam 10h MSRs */
#define MSR_FAM10H_MMIO_CONF_BASE 0xc0010058
diff --git a/arch/x86/include/asm/msr-trace.h b/arch/x86/include/asm/msr-trace.h
new file mode 100644
index 0000000..7567225
--- /dev/null
+++ b/arch/x86/include/asm/msr-trace.h
@@ -0,0 +1,57 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM msr
+
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_FILE msr-trace
+
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH asm/
+
+#if !defined(_TRACE_MSR_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_MSR_H
+
+#include <linux/tracepoint.h>
+
+/*
+ * Tracing for x86 model specific registers. Directly maps to the
+ * RDMSR/WRMSR instructions.
+ */
+
+DECLARE_EVENT_CLASS(msr_trace_class,
+ TP_PROTO(unsigned msr, u64 val, int failed),
+ TP_ARGS(msr, val, failed),
+ TP_STRUCT__entry(
+ __field( unsigned, msr )
+ __field( u64, val )
+ __field( int, failed )
+ ),
+ TP_fast_assign(
+ __entry->msr = msr;
+ __entry->val = val;
+ __entry->failed = failed;
+ ),
+ TP_printk("%x, value %llx%s",
+ __entry->msr,
+ __entry->val,
+ __entry->failed ? " #GP" : "")
+);
+
+DEFINE_EVENT(msr_trace_class, read_msr,
+ TP_PROTO(unsigned msr, u64 val, int failed),
+ TP_ARGS(msr, val, failed)
+);
+
+DEFINE_EVENT(msr_trace_class, write_msr,
+ TP_PROTO(unsigned msr, u64 val, int failed),
+ TP_ARGS(msr, val, failed)
+);
+
+DEFINE_EVENT(msr_trace_class, rdpmc,
+ TP_PROTO(unsigned msr, u64 val, int failed),
+ TP_ARGS(msr, val, failed)
+);
+
+#endif /* _TRACE_MSR_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 77d8b28..93fb7c1 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -32,6 +32,16 @@ struct msr_regs_info {
int err;
};
+struct saved_msr {
+ bool valid;
+ struct msr_info info;
+};
+
+struct saved_msrs {
+ unsigned int num;
+ struct saved_msr *array;
+};
+
static inline unsigned long long native_read_tscp(unsigned int *aux)
{
unsigned long low, high;
@@ -57,11 +67,34 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
#define EAX_EDX_RET(val, low, high) "=A" (val)
#endif
+#ifdef CONFIG_TRACEPOINTS
+/*
+ * Be very careful with includes. This header is prone to include loops.
+ */
+#include <asm/atomic.h>
+#include <linux/tracepoint-defs.h>
+
+extern struct tracepoint __tracepoint_read_msr;
+extern struct tracepoint __tracepoint_write_msr;
+extern struct tracepoint __tracepoint_rdpmc;
+#define msr_tracepoint_active(t) static_key_false(&(t).key)
+extern void do_trace_write_msr(unsigned msr, u64 val, int failed);
+extern void do_trace_read_msr(unsigned msr, u64 val, int failed);
+extern void do_trace_rdpmc(unsigned msr, u64 val, int failed);
+#else
+#define msr_tracepoint_active(t) false
+static inline void do_trace_write_msr(unsigned msr, u64 val, int failed) {}
+static inline void do_trace_read_msr(unsigned msr, u64 val, int failed) {}
+static inline void do_trace_rdpmc(unsigned msr, u64 val, int failed) {}
+#endif
+
static inline unsigned long long native_read_msr(unsigned int msr)
{
DECLARE_ARGS(val, low, high);
asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr));
+ if (msr_tracepoint_active(__tracepoint_read_msr))
+ do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), 0);
return EAX_EDX_VAL(val, low, high);
}
@@ -78,6 +111,8 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
_ASM_EXTABLE(2b, 3b)
: [err] "=r" (*err), EAX_EDX_RET(val, low, high)
: "c" (msr), [fault] "i" (-EIO));
+ if (msr_tracepoint_active(__tracepoint_read_msr))
+ do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), *err);
return EAX_EDX_VAL(val, low, high);
}
@@ -85,6 +120,8 @@ static inline void native_write_msr(unsigned int msr,
unsigned low, unsigned high)
{
asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
+ if (msr_tracepoint_active(__tracepoint_read_msr))
+ do_trace_write_msr(msr, ((u64)high << 32 | low), 0);
}
/* Can be uninlined because referenced by paravirt */
@@ -102,6 +139,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
: "c" (msr), "0" (low), "d" (high),
[fault] "i" (-EIO)
: "memory");
+ if (msr_tracepoint_active(__tracepoint_read_msr))
+ do_trace_write_msr(msr, ((u64)high << 32 | low), err);
return err;
}
@@ -160,6 +199,8 @@ static inline unsigned long long native_read_pmc(int counter)
DECLARE_ARGS(val, low, high);
asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter));
+ if (msr_tracepoint_active(__tracepoint_rdpmc))
+ do_trace_rdpmc(counter, EAX_EDX_VAL(val, low, high), 0);
return EAX_EDX_VAL(val, low, high);
}
@@ -190,7 +231,7 @@ static inline void wrmsr(unsigned msr, unsigned low, unsigned high)
static inline void wrmsrl(unsigned msr, u64 val)
{
- native_write_msr(msr, (u32)val, (u32)(val >> 32));
+ native_write_msr(msr, (u32)(val & 0xffffffffULL), (u32)(val >> 32));
}
/* wrmsr with exception handling */
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index c5b7fb2..7bd0099 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -5,23 +5,25 @@
#include <linux/types.h>
/* PAGE_SHIFT determines the page size */
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT)
+#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
+
+#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
+#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
#define __PHYSICAL_MASK ((phys_addr_t)((1ULL << __PHYSICAL_MASK_SHIFT) - 1))
#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
-/* Cast PAGE_MASK to a signed type so that it is sign-extended if
+/* Cast *PAGE_MASK to a signed type so that it is sign-extended if
virtual addresses are 32-bits but physical addresses are larger
(ie, 32-bit PAE). */
#define PHYSICAL_PAGE_MASK (((signed long)PAGE_MASK) & __PHYSICAL_MASK)
-
-#define PMD_PAGE_SIZE (_AC(1, UL) << PMD_SHIFT)
-#define PMD_PAGE_MASK (~(PMD_PAGE_SIZE-1))
-
-#define PUD_PAGE_SIZE (_AC(1, UL) << PUD_SHIFT)
-#define PUD_PAGE_MASK (~(PUD_PAGE_SIZE-1))
+#define PHYSICAL_PMD_PAGE_MASK (((signed long)PMD_PAGE_MASK) & __PHYSICAL_MASK)
+#define PHYSICAL_PUD_PAGE_MASK (((signed long)PUD_PAGE_MASK) & __PHYSICAL_MASK)
#define HPAGE_SHIFT PMD_SHIFT
#define HPAGE_SIZE (_AC(1,UL) << HPAGE_SHIFT)
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 10d0596..f619250 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -19,6 +19,12 @@ static inline int paravirt_enabled(void)
return pv_info.paravirt_enabled;
}
+static inline int paravirt_has_feature(unsigned int feature)
+{
+ WARN_ON_ONCE(!pv_info.paravirt_enabled);
+ return (pv_info.features & feature);
+}
+
static inline void load_sp0(struct tss_struct *tss,
struct thread_struct *thread)
{
@@ -285,15 +291,6 @@ static inline void slow_down_io(void)
#endif
}
-#ifdef CONFIG_SMP
-static inline void startup_ipi_hook(int phys_apicid, unsigned long start_eip,
- unsigned long start_esp)
-{
- PVOP_VCALL3(pv_apic_ops.startup_ipi_hook,
- phys_apicid, start_eip, start_esp);
-}
-#endif
-
static inline void paravirt_activate_mm(struct mm_struct *prev,
struct mm_struct *next)
{
@@ -375,23 +372,6 @@ static inline void pte_update(struct mm_struct *mm, unsigned long addr,
{
PVOP_VCALL3(pv_mmu_ops.pte_update, mm, addr, ptep);
}
-static inline void pmd_update(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp)
-{
- PVOP_VCALL3(pv_mmu_ops.pmd_update, mm, addr, pmdp);
-}
-
-static inline void pte_update_defer(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep)
-{
- PVOP_VCALL3(pv_mmu_ops.pte_update_defer, mm, addr, ptep);
-}
-
-static inline void pmd_update_defer(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp)
-{
- PVOP_VCALL3(pv_mmu_ops.pmd_update_defer, mm, addr, pmdp);
-}
static inline pte_t __pte(pteval_t val)
{
@@ -922,23 +902,11 @@ extern void default_banner(void);
call PARA_INDIRECT(pv_irq_ops+PV_IRQ_irq_enable); \
PV_RESTORE_REGS(clobbers | CLBR_CALLEE_SAVE);)
-#define USERGS_SYSRET32 \
- PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_usergs_sysret32), \
- CLBR_NONE, \
- jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_usergs_sysret32))
-
#ifdef CONFIG_X86_32
#define GET_CR0_INTO_EAX \
push %ecx; push %edx; \
call PARA_INDIRECT(pv_cpu_ops+PV_CPU_read_cr0); \
pop %edx; pop %ecx
-
-#define ENABLE_INTERRUPTS_SYSEXIT \
- PARA_SITE(PARA_PATCH(pv_cpu_ops, PV_CPU_irq_enable_sysexit), \
- CLBR_NONE, \
- jmp PARA_INDIRECT(pv_cpu_ops+PV_CPU_irq_enable_sysexit))
-
-
#else /* !CONFIG_X86_32 */
/*
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 31247b5..77db561 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -70,9 +70,14 @@ struct pv_info {
#endif
int paravirt_enabled;
+ unsigned int features; /* valid only if paravirt_enabled is set */
const char *name;
};
+#define paravirt_has(x) paravirt_has_feature(PV_SUPPORTED_##x)
+/* Supported features */
+#define PV_SUPPORTED_RTC (1<<0)
+
struct pv_init_ops {
/*
* Patch may replace one of the defined code sequences with
@@ -157,15 +162,6 @@ struct pv_cpu_ops {
u64 (*read_pmc)(int counter);
-#ifdef CONFIG_X86_32
- /*
- * Atomically enable interrupts and return to userspace. This
- * is only used in 32-bit kernels. 64-bit kernels use
- * usergs_sysret32 instead.
- */
- void (*irq_enable_sysexit)(void);
-#endif
-
/*
* Switch to usermode gs and return to 64-bit usermode using
* sysret. Only used in 64-bit kernels to return to 64-bit
@@ -174,14 +170,6 @@ struct pv_cpu_ops {
*/
void (*usergs_sysret64)(void);
- /*
- * Switch to usermode gs and return to 32-bit usermode using
- * sysret. Used to return to 32-on-64 compat processes.
- * Other usermode register state, including %esp, must already
- * be restored.
- */
- void (*usergs_sysret32)(void);
-
/* Normal iret. Jump to this with the standard iret stack
frame set up. */
void (*iret)(void);
@@ -215,14 +203,6 @@ struct pv_irq_ops {
#endif
};
-struct pv_apic_ops {
-#ifdef CONFIG_X86_LOCAL_APIC
- void (*startup_ipi_hook)(int phys_apicid,
- unsigned long start_eip,
- unsigned long start_esp);
-#endif
-};
-
struct pv_mmu_ops {
unsigned long (*read_cr2)(void);
void (*write_cr2)(unsigned long);
@@ -274,12 +254,6 @@ struct pv_mmu_ops {
pmd_t *pmdp, pmd_t pmdval);
void (*pte_update)(struct mm_struct *mm, unsigned long addr,
pte_t *ptep);
- void (*pte_update_defer)(struct mm_struct *mm,
- unsigned long addr, pte_t *ptep);
- void (*pmd_update)(struct mm_struct *mm, unsigned long addr,
- pmd_t *pmdp);
- void (*pmd_update_defer)(struct mm_struct *mm,
- unsigned long addr, pmd_t *pmdp);
pte_t (*ptep_modify_prot_start)(struct mm_struct *mm, unsigned long addr,
pte_t *ptep);
@@ -354,7 +328,6 @@ struct paravirt_patch_template {
struct pv_time_ops pv_time_ops;
struct pv_cpu_ops pv_cpu_ops;
struct pv_irq_ops pv_irq_ops;
- struct pv_apic_ops pv_apic_ops;
struct pv_mmu_ops pv_mmu_ops;
struct pv_lock_ops pv_lock_ops;
};
@@ -364,7 +337,6 @@ extern struct pv_init_ops pv_init_ops;
extern struct pv_time_ops pv_time_ops;
extern struct pv_cpu_ops pv_cpu_ops;
extern struct pv_irq_ops pv_irq_ops;
-extern struct pv_apic_ops pv_apic_ops;
extern struct pv_mmu_ops pv_mmu_ops;
extern struct pv_lock_ops pv_lock_ops;
@@ -402,10 +374,8 @@ extern struct pv_lock_ops pv_lock_ops;
__visible extern const char start_##ops##_##name[], end_##ops##_##name[]; \
asm(NATIVE_LABEL("start_", ops, name) code NATIVE_LABEL("end_", ops, name))
-unsigned paravirt_patch_nop(void);
unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len);
unsigned paravirt_patch_ident_64(void *insnbuf, unsigned len);
-unsigned paravirt_patch_ignore(unsigned len);
unsigned paravirt_patch_call(void *insnbuf,
const void *target, u16 tgt_clobbers,
unsigned long addr, u16 site_clobbers,
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index 6ec0c8b..d3eee66 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -69,9 +69,6 @@ extern struct mm_struct *pgd_page_get_mm(struct page *page);
#define pmd_clear(pmd) native_pmd_clear(pmd)
#define pte_update(mm, addr, ptep) do { } while (0)
-#define pte_update_defer(mm, addr, ptep) do { } while (0)
-#define pmd_update(mm, addr, ptep) do { } while (0)
-#define pmd_update_defer(mm, addr, ptep) do { } while (0)
#define pgd_val(x) native_pgd_val(x)
#define __pgd(x) native_make_pgd(x)
@@ -731,14 +728,9 @@ static inline void native_set_pmd_at(struct mm_struct *mm, unsigned long addr,
* updates should either be sets, clears, or set_pte_atomic for P->P
* transitions, which means this hook should only be called for user PTEs.
* This hook implies a P->P protection or access change has taken place, which
- * requires a subsequent TLB flush. The notification can optionally be delayed
- * until the TLB flush event by using the pte_update_defer form of the
- * interface, but care must be taken to assure that the flush happens while
- * still holding the same page table lock so that the shadow and primary pages
- * do not become out of sync on SMP.
+ * requires a subsequent TLB flush.
*/
#define pte_update(mm, addr, ptep) do { } while (0)
-#define pte_update_defer(mm, addr, ptep) do { } while (0)
#endif
/*
@@ -830,9 +822,7 @@ static inline int pmd_write(pmd_t pmd)
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp)
{
- pmd_t pmd = native_pmdp_get_and_clear(pmdp);
- pmd_update(mm, addr, pmdp);
- return pmd;
+ return native_pmdp_get_and_clear(pmdp);
}
#define __HAVE_ARCH_PMDP_SET_WRPROTECT
@@ -840,7 +830,6 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp)
{
clear_bit(_PAGE_BIT_RW, (unsigned long *)pmdp);
- pmd_update(mm, addr, pmdp);
}
/*
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index dd5b0aa..a471cad 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -279,17 +279,14 @@ static inline pmdval_t native_pmd_val(pmd_t pmd)
static inline pudval_t pud_pfn_mask(pud_t pud)
{
if (native_pud_val(pud) & _PAGE_PSE)
- return PUD_PAGE_MASK & PHYSICAL_PAGE_MASK;
+ return PHYSICAL_PUD_PAGE_MASK;
else
return PTE_PFN_MASK;
}
static inline pudval_t pud_flags_mask(pud_t pud)
{
- if (native_pud_val(pud) & _PAGE_PSE)
- return ~(PUD_PAGE_MASK & (pudval_t)PHYSICAL_PAGE_MASK);
- else
- return ~PTE_PFN_MASK;
+ return ~pud_pfn_mask(pud);
}
static inline pudval_t pud_flags(pud_t pud)
@@ -300,17 +297,14 @@ static inline pudval_t pud_flags(pud_t pud)
static inline pmdval_t pmd_pfn_mask(pmd_t pmd)
{
if (native_pmd_val(pmd) & _PAGE_PSE)
- return PMD_PAGE_MASK & PHYSICAL_PAGE_MASK;
+ return PHYSICAL_PMD_PAGE_MASK;
else
return PTE_PFN_MASK;
}
static inline pmdval_t pmd_flags_mask(pmd_t pmd)
{
- if (native_pmd_val(pmd) & _PAGE_PSE)
- return ~(PMD_PAGE_MASK & (pmdval_t)PHYSICAL_PAGE_MASK);
- else
- return ~PTE_PFN_MASK;
+ return ~pmd_pfn_mask(pmd);
}
static inline pmdval_t pmd_flags(pmd_t pmd)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 6752225..2d5a50c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -472,6 +472,7 @@ static inline unsigned long current_top_of_stack(void)
#else
#define __cpuid native_cpuid
#define paravirt_enabled() 0
+#define paravirt_has(x) 0
static inline void load_sp0(struct tss_struct *tss,
struct thread_struct *thread)
diff --git a/arch/x86/include/asm/pvclock.h b/arch/x86/include/asm/pvclock.h
index 7a6bed5..fdcc040 100644
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -4,6 +4,15 @@
#include <linux/clocksource.h>
#include <asm/pvclock-abi.h>
+#ifdef CONFIG_KVM_GUEST
+extern struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void);
+#else
+static inline struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+ return NULL;
+}
+#endif
+
/* some helper functions for xen and kvm pv clock sources */
cycle_t pvclock_clocksource_read(struct pvclock_vcpu_time_info *src);
u8 pvclock_read_flags(struct pvclock_vcpu_time_info *src);
@@ -91,10 +100,5 @@ struct pvclock_vsyscall_time_info {
} __attribute__((__aligned__(SMP_CACHE_BYTES)));
#define PVTI_SIZE sizeof(struct pvclock_vsyscall_time_info)
-#define PVCLOCK_VSYSCALL_NR_PAGES (((NR_CPUS-1)/(PAGE_SIZE/PVTI_SIZE))+1)
-
-int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
- int size);
-struct pvclock_vcpu_time_info *pvclock_get_vsyscall_time_info(int cpu);
#endif /* _ASM_X86_PVCLOCK_H */
diff --git a/arch/x86/include/asm/qspinlock_paravirt.h b/arch/x86/include/asm/qspinlock_paravirt.h
index b002e71..9f92c18 100644
--- a/arch/x86/include/asm/qspinlock_paravirt.h
+++ b/arch/x86/include/asm/qspinlock_paravirt.h
@@ -1,6 +1,65 @@
#ifndef __ASM_QSPINLOCK_PARAVIRT_H
#define __ASM_QSPINLOCK_PARAVIRT_H
+/*
+ * For x86-64, PV_CALLEE_SAVE_REGS_THUNK() saves and restores 8 64-bit
+ * registers. For i386, however, only 1 32-bit register needs to be saved
+ * and restored. So an optimized version of __pv_queued_spin_unlock() is
+ * hand-coded for 64-bit, but it isn't worthwhile to do it for 32-bit.
+ */
+#ifdef CONFIG_64BIT
+
+PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath);
+#define __pv_queued_spin_unlock __pv_queued_spin_unlock
+#define PV_UNLOCK "__raw_callee_save___pv_queued_spin_unlock"
+#define PV_UNLOCK_SLOWPATH "__raw_callee_save___pv_queued_spin_unlock_slowpath"
+
+/*
+ * Optimized assembly version of __raw_callee_save___pv_queued_spin_unlock
+ * which combines the registers saving trunk and the body of the following
+ * C code:
+ *
+ * void __pv_queued_spin_unlock(struct qspinlock *lock)
+ * {
+ * struct __qspinlock *l = (void *)lock;
+ * u8 lockval = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
+ *
+ * if (likely(lockval == _Q_LOCKED_VAL))
+ * return;
+ * pv_queued_spin_unlock_slowpath(lock, lockval);
+ * }
+ *
+ * For x86-64,
+ * rdi = lock (first argument)
+ * rsi = lockval (second argument)
+ * rdx = internal variable (set to 0)
+ */
+asm (".pushsection .text;"
+ ".globl " PV_UNLOCK ";"
+ ".align 4,0x90;"
+ PV_UNLOCK ": "
+ "push %rdx;"
+ "mov $0x1,%eax;"
+ "xor %edx,%edx;"
+ "lock cmpxchg %dl,(%rdi);"
+ "cmp $0x1,%al;"
+ "jne .slowpath;"
+ "pop %rdx;"
+ "ret;"
+ ".slowpath: "
+ "push %rsi;"
+ "movzbl %al,%esi;"
+ "call " PV_UNLOCK_SLOWPATH ";"
+ "pop %rsi;"
+ "pop %rdx;"
+ "ret;"
+ ".size " PV_UNLOCK ", .-" PV_UNLOCK ";"
+ ".popsection");
+
+#else /* CONFIG_64BIT */
+
+extern void __pv_queued_spin_unlock(struct qspinlock *lock);
PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock);
+#endif /* CONFIG_64BIT */
#endif
diff --git a/arch/x86/include/asm/reboot.h b/arch/x86/include/asm/reboot.h
index a82c4f1..2cb1cc2 100644
--- a/arch/x86/include/asm/reboot.h
+++ b/arch/x86/include/asm/reboot.h
@@ -25,5 +25,6 @@ void __noreturn machine_real_restart(unsigned int type);
typedef void (*nmi_shootdown_cb)(int, struct pt_regs*);
void nmi_shootdown_cpus(nmi_shootdown_cb callback);
+void run_crash_ipi_callback(struct pt_regs *regs);
#endif /* _ASM_X86_REBOOT_H */
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 222a6a3..dfcf072 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -21,15 +21,6 @@
extern int smp_num_siblings;
extern unsigned int num_processors;
-static inline bool cpu_has_ht_siblings(void)
-{
- bool has_siblings = false;
-#ifdef CONFIG_SMP
- has_siblings = cpu_has_ht && smp_num_siblings > 1;
-#endif
- return has_siblings;
-}
-
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_core_map);
/* cpus sharing the last level cache: */
@@ -74,9 +65,6 @@ struct smp_ops {
extern void set_cpu_sibling_map(int cpu);
#ifdef CONFIG_SMP
-#ifndef CONFIG_PARAVIRT
-#define startup_ipi_hook(phys_apicid, start_eip, start_esp) do { } while (0)
-#endif
extern struct smp_ops smp_ops;
static inline void smp_send_stop(void)
diff --git a/arch/x86/include/asm/suspend_32.h b/arch/x86/include/asm/suspend_32.h
index d1793f0..8e9dbe7 100644
--- a/arch/x86/include/asm/suspend_32.h
+++ b/arch/x86/include/asm/suspend_32.h
@@ -15,6 +15,7 @@ struct saved_context {
unsigned long cr0, cr2, cr3, cr4;
u64 misc_enable;
bool misc_enable_saved;
+ struct saved_msrs saved_msrs;
struct desc_ptr gdt_desc;
struct desc_ptr idt;
u16 ldt;
diff --git a/arch/x86/include/asm/suspend_64.h b/arch/x86/include/asm/suspend_64.h
index 7ebf0eb..6136a18 100644
--- a/arch/x86/include/asm/suspend_64.h
+++ b/arch/x86/include/asm/suspend_64.h
@@ -24,6 +24,7 @@ struct saved_context {
unsigned long cr0, cr2, cr3, cr4, cr8;
u64 misc_enable;
bool misc_enable_saved;
+ struct saved_msrs saved_msrs;
unsigned long efer;
u16 gdt_pad; /* Unused */
struct desc_ptr gdt_desc;
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 09b1b0a..660458a 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -745,5 +745,14 @@ copy_to_user(void __user *to, const void *from, unsigned long n)
#undef __copy_from_user_overflow
#undef __copy_to_user_overflow
+/*
+ * We rely on the nested NMI work to allow atomic faults from the NMI path; the
+ * nested NMI paths are careful to preserve CR2.
+ *
+ * Caller must use pagefault_enable/disable, or run in interrupt context,
+ * and also do a uaccess_ok() check
+ */
+#define __copy_from_user_nmi __copy_from_user_inatomic
+
#endif /* _ASM_X86_UACCESS_H */
diff --git a/arch/x86/include/asm/vdso.h b/arch/x86/include/asm/vdso.h
index 756de91..deabaf9 100644
--- a/arch/x86/include/asm/vdso.h
+++ b/arch/x86/include/asm/vdso.h
@@ -22,6 +22,7 @@ struct vdso_image {
long sym_vvar_page;
long sym_hpet_page;
+ long sym_pvclock_page;
long sym_VDSO32_NOTE_MASK;
long sym___kernel_sigreturn;
long sym___kernel_rt_sigreturn;
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index aa336ff..14c63c7 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -73,6 +73,7 @@
#define SECONDARY_EXEC_ENABLE_PML 0x00020000
#define SECONDARY_EXEC_XSAVES 0x00100000
#define SECONDARY_EXEC_PCOMMIT 0x00200000
+#define SECONDARY_EXEC_TSC_SCALING 0x02000000
#define PIN_BASED_EXT_INTR_MASK 0x00000001
#define PIN_BASED_NMI_EXITING 0x00000008
@@ -167,6 +168,8 @@ enum vmcs_field {
VMWRITE_BITMAP = 0x00002028,
XSS_EXIT_BITMAP = 0x0000202C,
XSS_EXIT_BITMAP_HIGH = 0x0000202D,
+ TSC_MULTIPLIER = 0x00002032,
+ TSC_MULTIPLIER_HIGH = 0x00002033,
GUEST_PHYSICAL_ADDRESS = 0x00002400,
GUEST_PHYSICAL_ADDRESS_HIGH = 0x00002401,
VMCS_LINK_POINTER = 0x00002800,
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index 48d34d2..1ae89a2 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -1,7 +1,6 @@
#ifndef _ASM_X86_PLATFORM_H
#define _ASM_X86_PLATFORM_H
-#include <asm/pgtable_types.h>
#include <asm/bootparam.h>
struct mpc_bus;
@@ -83,13 +82,11 @@ struct x86_init_paging {
* struct x86_init_timers - platform specific timer setup
* @setup_perpcu_clockev: set up the per cpu clock event device for the
* boot cpu
- * @tsc_pre_init: platform function called before TSC init
* @timer_init: initialize the platform timer (default PIT/HPET)
* @wallclock_init: init the wallclock device
*/
struct x86_init_timers {
void (*setup_percpu_clockev)(void);
- void (*tsc_pre_init)(void);
void (*timer_init)(void);
void (*wallclock_init)(void);
};
diff --git a/arch/x86/include/asm/xen/hypercall.h b/arch/x86/include/asm/xen/hypercall.h
index 4c20dd3..3bcdcc8 100644
--- a/arch/x86/include/asm/xen/hypercall.h
+++ b/arch/x86/include/asm/xen/hypercall.h
@@ -310,10 +310,10 @@ HYPERVISOR_mca(struct xen_mc *mc_op)
}
static inline int
-HYPERVISOR_dom0_op(struct xen_platform_op *platform_op)
+HYPERVISOR_platform_op(struct xen_platform_op *op)
{
- platform_op->interface_version = XENPF_INTERFACE_VERSION;
- return _hypercall1(int, dom0_op, platform_op);
+ op->interface_version = XENPF_INTERFACE_VERSION;
+ return _hypercall1(int, platform_op, op);
}
static inline int
diff --git a/arch/x86/include/asm/xor_32.h b/arch/x86/include/asm/xor_32.h
index 5a08bc8..c54beb4 100644
--- a/arch/x86/include/asm/xor_32.h
+++ b/arch/x86/include/asm/xor_32.h
@@ -553,7 +553,7 @@ do { \
if (cpu_has_xmm) { \
xor_speed(&xor_block_pIII_sse); \
xor_speed(&xor_block_sse_pf64); \
- } else if (cpu_has_mmx) { \
+ } else if (boot_cpu_has(X86_FEATURE_MMX)) { \
xor_speed(&xor_block_pII_mmx); \
xor_speed(&xor_block_p5_mmx); \
} else { \
diff --git a/arch/x86/include/uapi/asm/hyperv.h b/arch/x86/include/uapi/asm/hyperv.h
index 040d408..7956412 100644
--- a/arch/x86/include/uapi/asm/hyperv.h
+++ b/arch/x86/include/uapi/asm/hyperv.h
@@ -269,4 +269,96 @@ typedef struct _HV_REFERENCE_TSC_PAGE {
#define HV_SYNIC_SINT_AUTO_EOI (1ULL << 17)
#define HV_SYNIC_SINT_VECTOR_MASK (0xFF)
+#define HV_SYNIC_STIMER_COUNT (4)
+
+/* Define synthetic interrupt controller message constants. */
+#define HV_MESSAGE_SIZE (256)
+#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
+#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
+
+/* Define hypervisor message types. */
+enum hv_message_type {
+ HVMSG_NONE = 0x00000000,
+
+ /* Memory access messages. */
+ HVMSG_UNMAPPED_GPA = 0x80000000,
+ HVMSG_GPA_INTERCEPT = 0x80000001,
+
+ /* Timer notification messages. */
+ HVMSG_TIMER_EXPIRED = 0x80000010,
+
+ /* Error messages. */
+ HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
+ HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
+ HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
+
+ /* Trace buffer complete messages. */
+ HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
+
+ /* Platform-specific processor intercept messages. */
+ HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
+ HVMSG_X64_MSR_INTERCEPT = 0x80010001,
+ HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
+ HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
+ HVMSG_X64_APIC_EOI = 0x80010004,
+ HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
+};
+
+/* Define synthetic interrupt controller message flags. */
+union hv_message_flags {
+ __u8 asu8;
+ struct {
+ __u8 msg_pending:1;
+ __u8 reserved:7;
+ };
+};
+
+/* Define port identifier type. */
+union hv_port_id {
+ __u32 asu32;
+ struct {
+ __u32 id:24;
+ __u32 reserved:8;
+ } u;
+};
+
+/* Define synthetic interrupt controller message header. */
+struct hv_message_header {
+ __u32 message_type;
+ __u8 payload_size;
+ union hv_message_flags message_flags;
+ __u8 reserved[2];
+ union {
+ __u64 sender;
+ union hv_port_id port;
+ };
+};
+
+/* Define synthetic interrupt controller message format. */
+struct hv_message {
+ struct hv_message_header header;
+ union {
+ __u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
+ } u;
+};
+
+/* Define the synthetic interrupt message page layout. */
+struct hv_message_page {
+ struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
+};
+
+/* Define timer message payload structure. */
+struct hv_timer_message_payload {
+ __u32 timer_index;
+ __u32 reserved;
+ __u64 expiration_time; /* When the timer expired */
+ __u64 delivery_time; /* When the message was delivered */
+};
+
+#define HV_STIMER_ENABLE (1ULL << 0)
+#define HV_STIMER_PERIODIC (1ULL << 1)
+#define HV_STIMER_LAZY (1ULL << 2)
+#define HV_STIMER_AUTOENABLE (1ULL << 3)
+#define HV_STIMER_SINT(config) (__u8)(((config) >> 16) & 0x0F)
+
#endif
diff --git a/arch/x86/include/uapi/asm/mce.h b/arch/x86/include/uapi/asm/mce.h
index 03429da..2184943 100644
--- a/arch/x86/include/uapi/asm/mce.h
+++ b/arch/x86/include/uapi/asm/mce.h
@@ -16,7 +16,7 @@ struct mce {
__u8 cpuvendor; /* cpu vendor as encoded in system.h */
__u8 inject_flags; /* software inject flags */
__u8 severity;
- __u8 usable_addr;
+ __u8 pad;
__u32 cpuid; /* CPUID 1 EAX */
__u8 cs; /* code segment */
__u8 bank; /* machine check bank */
diff --git a/arch/x86/include/uapi/asm/svm.h b/arch/x86/include/uapi/asm/svm.h
index b5d7640..8a4add8 100644
--- a/arch/x86/include/uapi/asm/svm.h
+++ b/arch/x86/include/uapi/asm/svm.h
@@ -100,6 +100,7 @@
{ SVM_EXIT_EXCP_BASE + UD_VECTOR, "UD excp" }, \
{ SVM_EXIT_EXCP_BASE + PF_VECTOR, "PF excp" }, \
{ SVM_EXIT_EXCP_BASE + NM_VECTOR, "NM excp" }, \
+ { SVM_EXIT_EXCP_BASE + AC_VECTOR, "AC excp" }, \
{ SVM_EXIT_EXCP_BASE + MC_VECTOR, "MC excp" }, \
{ SVM_EXIT_INTR, "interrupt" }, \
{ SVM_EXIT_NMI, "nmi" }, \
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 2f69e3b..8a5cdda 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -82,6 +82,12 @@ physid_mask_t phys_cpu_present_map;
static unsigned int disabled_cpu_apicid __read_mostly = BAD_APICID;
/*
+ * This variable controls which CPUs receive external NMIs. By default,
+ * external NMIs are delivered only to the BSP.
+ */
+static int apic_extnmi = APIC_EXTNMI_BSP;
+
+/*
* Map cpu index to physical APIC ID
*/
DEFINE_EARLY_PER_CPU_READ_MOSTLY(u16, x86_cpu_to_apicid, BAD_APICID);
@@ -1161,6 +1167,8 @@ void __init init_bsp_APIC(void)
value = APIC_DM_NMI;
if (!lapic_is_integrated()) /* 82489DX */
value |= APIC_LVT_LEVEL_TRIGGER;
+ if (apic_extnmi == APIC_EXTNMI_NONE)
+ value |= APIC_LVT_MASKED;
apic_write(APIC_LVT1, value);
}
@@ -1378,9 +1386,11 @@ void setup_local_APIC(void)
apic_write(APIC_LVT0, value);
/*
- * only the BP should see the LINT1 NMI signal, obviously.
+ * Only the BSP sees the LINT1 NMI signal by default. This can be
+ * modified by apic_extnmi= boot option.
*/
- if (!cpu)
+ if ((!cpu && apic_extnmi != APIC_EXTNMI_NONE) ||
+ apic_extnmi == APIC_EXTNMI_ALL)
value = APIC_DM_NMI;
else
value = APIC_DM_NMI | APIC_LVT_MASKED;
@@ -2270,6 +2280,7 @@ static struct {
unsigned int apic_tmict;
unsigned int apic_tdcr;
unsigned int apic_thmr;
+ unsigned int apic_cmci;
} apic_pm_state;
static int lapic_suspend(void)
@@ -2299,6 +2310,10 @@ static int lapic_suspend(void)
if (maxlvt >= 5)
apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
#endif
+#ifdef CONFIG_X86_MCE_INTEL
+ if (maxlvt >= 6)
+ apic_pm_state.apic_cmci = apic_read(APIC_LVTCMCI);
+#endif
local_irq_save(flags);
disable_local_APIC();
@@ -2355,10 +2370,14 @@ static void lapic_resume(void)
apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-#if defined(CONFIG_X86_MCE_INTEL)
+#ifdef CONFIG_X86_THERMAL_VECTOR
if (maxlvt >= 5)
apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
#endif
+#ifdef CONFIG_X86_MCE_INTEL
+ if (maxlvt >= 6)
+ apic_write(APIC_LVTCMCI, apic_pm_state.apic_cmci);
+#endif
if (maxlvt >= 4)
apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
@@ -2548,3 +2567,23 @@ static int __init apic_set_disabled_cpu_apicid(char *arg)
return 0;
}
early_param("disable_cpu_apicid", apic_set_disabled_cpu_apicid);
+
+static int __init apic_set_extnmi(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ if (!strncmp("all", arg, 3))
+ apic_extnmi = APIC_EXTNMI_ALL;
+ else if (!strncmp("none", arg, 4))
+ apic_extnmi = APIC_EXTNMI_NONE;
+ else if (!strncmp("bsp", arg, 3))
+ apic_extnmi = APIC_EXTNMI_BSP;
+ else {
+ pr_warn("Unknown external NMI delivery mode `%s' ignored\n", arg);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+early_param("apic_extnmi", apic_set_extnmi);
diff --git a/arch/x86/kernel/apic/apic_flat_64.c b/arch/x86/kernel/apic/apic_flat_64.c
index f92ab36..9968f30 100644
--- a/arch/x86/kernel/apic/apic_flat_64.c
+++ b/arch/x86/kernel/apic/apic_flat_64.c
@@ -185,6 +185,7 @@ static struct apic apic_flat = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
+ .send_IPI = default_send_IPI_single,
.send_IPI_mask = flat_send_IPI_mask,
.send_IPI_mask_allbutself = flat_send_IPI_mask_allbutself,
.send_IPI_allbutself = flat_send_IPI_allbutself,
@@ -230,17 +231,6 @@ static int physflat_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return 0;
}
-static void physflat_send_IPI_mask(const struct cpumask *cpumask, int vector)
-{
- default_send_IPI_mask_sequence_phys(cpumask, vector);
-}
-
-static void physflat_send_IPI_mask_allbutself(const struct cpumask *cpumask,
- int vector)
-{
- default_send_IPI_mask_allbutself_phys(cpumask, vector);
-}
-
static void physflat_send_IPI_allbutself(int vector)
{
default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
@@ -248,7 +238,7 @@ static void physflat_send_IPI_allbutself(int vector)
static void physflat_send_IPI_all(int vector)
{
- physflat_send_IPI_mask(cpu_online_mask, vector);
+ default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
}
static int physflat_probe(void)
@@ -292,8 +282,9 @@ static struct apic apic_physflat = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
- .send_IPI_mask = physflat_send_IPI_mask,
- .send_IPI_mask_allbutself = physflat_send_IPI_mask_allbutself,
+ .send_IPI = default_send_IPI_single_phys,
+ .send_IPI_mask = default_send_IPI_mask_sequence_phys,
+ .send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_phys,
.send_IPI_allbutself = physflat_send_IPI_allbutself,
.send_IPI_all = physflat_send_IPI_all,
.send_IPI_self = apic_send_IPI_self,
diff --git a/arch/x86/kernel/apic/apic_noop.c b/arch/x86/kernel/apic/apic_noop.c
index 0d96749..331a7a0 100644
--- a/arch/x86/kernel/apic/apic_noop.c
+++ b/arch/x86/kernel/apic/apic_noop.c
@@ -30,6 +30,7 @@
#include <asm/e820.h>
static void noop_init_apic_ldr(void) { }
+static void noop_send_IPI(int cpu, int vector) { }
static void noop_send_IPI_mask(const struct cpumask *cpumask, int vector) { }
static void noop_send_IPI_mask_allbutself(const struct cpumask *cpumask, int vector) { }
static void noop_send_IPI_allbutself(int vector) { }
@@ -144,6 +145,7 @@ struct apic apic_noop = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
+ .send_IPI = noop_send_IPI,
.send_IPI_mask = noop_send_IPI_mask,
.send_IPI_mask_allbutself = noop_send_IPI_mask_allbutself,
.send_IPI_allbutself = noop_send_IPI_allbutself,
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 38dd5ef..c80c02c 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -193,20 +193,17 @@ static int __init numachip_system_init(void)
case 1:
init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE);
numachip_apic_icr_write = numachip1_apic_icr_write;
- x86_init.pci.arch_init = pci_numachip_init;
break;
case 2:
init_extra_mapping_uc(NUMACHIP2_LCSR_BASE, NUMACHIP2_LCSR_SIZE);
numachip_apic_icr_write = numachip2_apic_icr_write;
-
- /* Use MCFG config cycles rather than locked CF8 cycles */
- raw_pci_ops = &pci_mmcfg;
break;
default:
return 0;
}
x86_cpuinit.fixup_cpu_id = fixup_cpu_id;
+ x86_init.pci.arch_init = pci_numachip_init;
return 0;
}
@@ -276,6 +273,7 @@ static const struct apic apic_numachip1 __refconst = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
+ .send_IPI = numachip_send_IPI_one,
.send_IPI_mask = numachip_send_IPI_mask,
.send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
.send_IPI_allbutself = numachip_send_IPI_allbutself,
@@ -327,6 +325,7 @@ static const struct apic apic_numachip2 __refconst = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
+ .send_IPI = numachip_send_IPI_one,
.send_IPI_mask = numachip_send_IPI_mask,
.send_IPI_mask_allbutself = numachip_send_IPI_mask_allbutself,
.send_IPI_allbutself = numachip_send_IPI_allbutself,
diff --git a/arch/x86/kernel/apic/bigsmp_32.c b/arch/x86/kernel/apic/bigsmp_32.c
index 971cf88..cf9bd89 100644
--- a/arch/x86/kernel/apic/bigsmp_32.c
+++ b/arch/x86/kernel/apic/bigsmp_32.c
@@ -96,11 +96,6 @@ static int bigsmp_phys_pkg_id(int cpuid_apic, int index_msb)
return cpuid_apic >> index_msb;
}
-static inline void bigsmp_send_IPI_mask(const struct cpumask *mask, int vector)
-{
- default_send_IPI_mask_sequence_phys(mask, vector);
-}
-
static void bigsmp_send_IPI_allbutself(int vector)
{
default_send_IPI_mask_allbutself_phys(cpu_online_mask, vector);
@@ -108,7 +103,7 @@ static void bigsmp_send_IPI_allbutself(int vector)
static void bigsmp_send_IPI_all(int vector)
{
- bigsmp_send_IPI_mask(cpu_online_mask, vector);
+ default_send_IPI_mask_sequence_phys(cpu_online_mask, vector);
}
static int dmi_bigsmp; /* can be set by dmi scanners */
@@ -180,7 +175,8 @@ static struct apic apic_bigsmp = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
- .send_IPI_mask = bigsmp_send_IPI_mask,
+ .send_IPI = default_send_IPI_single_phys,
+ .send_IPI_mask = default_send_IPI_mask_sequence_phys,
.send_IPI_mask_allbutself = NULL,
.send_IPI_allbutself = bigsmp_send_IPI_allbutself,
.send_IPI_all = bigsmp_send_IPI_all,
diff --git a/arch/x86/kernel/apic/ipi.c b/arch/x86/kernel/apic/ipi.c
index 6207156..eb45fc9 100644
--- a/arch/x86/kernel/apic/ipi.c
+++ b/arch/x86/kernel/apic/ipi.c
@@ -18,6 +18,16 @@
#include <asm/proto.h>
#include <asm/ipi.h>
+void default_send_IPI_single_phys(int cpu, int vector)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ __default_send_IPI_dest_field(per_cpu(x86_cpu_to_apicid, cpu),
+ vector, APIC_DEST_PHYSICAL);
+ local_irq_restore(flags);
+}
+
void default_send_IPI_mask_sequence_phys(const struct cpumask *mask, int vector)
{
unsigned long query_cpu;
@@ -55,6 +65,14 @@ void default_send_IPI_mask_allbutself_phys(const struct cpumask *mask,
local_irq_restore(flags);
}
+/*
+ * Helper function for APICs which insist on cpumasks
+ */
+void default_send_IPI_single(int cpu, int vector)
+{
+ apic->send_IPI_mask(cpumask_of(cpu), vector);
+}
+
#ifdef CONFIG_X86_32
void default_send_IPI_mask_sequence_logical(const struct cpumask *mask,
diff --git a/arch/x86/kernel/apic/msi.c b/arch/x86/kernel/apic/msi.c
index 5f1feb6..ade2532 100644
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -96,8 +96,8 @@ static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info,
return arg->msi_hwirq;
}
-static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
- int nvec, msi_alloc_info_t *arg)
+int pci_msi_prepare(struct irq_domain *domain, struct device *dev, int nvec,
+ msi_alloc_info_t *arg)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct msi_desc *desc = first_pci_msi_entry(pdev);
@@ -113,11 +113,13 @@ static int pci_msi_prepare(struct irq_domain *domain, struct device *dev,
return 0;
}
+EXPORT_SYMBOL_GPL(pci_msi_prepare);
-static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
+void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc)
{
arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc);
}
+EXPORT_SYMBOL_GPL(pci_msi_set_desc);
static struct msi_domain_ops pci_msi_domain_ops = {
.get_hwirq = pci_msi_get_hwirq,
diff --git a/arch/x86/kernel/apic/probe_32.c b/arch/x86/kernel/apic/probe_32.c
index 7694ae6..f316e34 100644
--- a/arch/x86/kernel/apic/probe_32.c
+++ b/arch/x86/kernel/apic/probe_32.c
@@ -105,6 +105,7 @@ static struct apic apic_default = {
.cpu_mask_to_apicid_and = flat_cpu_mask_to_apicid_and,
+ .send_IPI = default_send_IPI_single,
.send_IPI_mask = default_send_IPI_mask_logical,
.send_IPI_mask_allbutself = default_send_IPI_mask_allbutself_logical,
.send_IPI_allbutself = default_send_IPI_allbutself,
diff --git a/arch/x86/kernel/apic/vector.c b/arch/x86/kernel/apic/vector.c
index 836d11b..908cb37 100644
--- a/arch/x86/kernel/apic/vector.c
+++ b/arch/x86/kernel/apic/vector.c
@@ -29,6 +29,7 @@ struct apic_chip_data {
};
struct irq_domain *x86_vector_domain;
+EXPORT_SYMBOL_GPL(x86_vector_domain);
static DEFINE_RAW_SPINLOCK(vector_lock);
static cpumask_var_t vector_cpumask;
static struct irq_chip lapic_controller;
@@ -66,6 +67,7 @@ struct irq_cfg *irqd_cfg(struct irq_data *irq_data)
return data ? &data->cfg : NULL;
}
+EXPORT_SYMBOL_GPL(irqd_cfg);
struct irq_cfg *irq_cfg(unsigned int irq)
{
@@ -361,7 +363,11 @@ int __init arch_probe_nr_irqs(void)
if (nr < nr_irqs)
nr_irqs = nr;
- return nr_legacy_irqs();
+ /*
+ * We don't know if PIC is present at this point so we need to do
+ * probe() to get the right number of legacy IRQs.
+ */
+ return legacy_pic->probe();
}
#ifdef CONFIG_X86_IO_APIC
diff --git a/arch/x86/kernel/apic/x2apic_cluster.c b/arch/x86/kernel/apic/x2apic_cluster.c
index cc8311c..aca8b75 100644
--- a/arch/x86/kernel/apic/x2apic_cluster.c
+++ b/arch/x86/kernel/apic/x2apic_cluster.c
@@ -23,6 +23,14 @@ static inline u32 x2apic_cluster(int cpu)
return per_cpu(x86_cpu_to_logical_apicid, cpu) >> 16;
}
+static void x2apic_send_IPI(int cpu, int vector)
+{
+ u32 dest = per_cpu(x86_cpu_to_logical_apicid, cpu);
+
+ x2apic_wrmsr_fence();
+ __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
+}
+
static void
__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{
@@ -266,6 +274,7 @@ static struct apic apic_x2apic_cluster = {
.cpu_mask_to_apicid_and = x2apic_cpu_mask_to_apicid_and,
+ .send_IPI = x2apic_send_IPI,
.send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself,
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index 662e915..a1242e2 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -36,6 +36,14 @@ static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
return x2apic_enabled() && (x2apic_phys || x2apic_fadt_phys());
}
+static void x2apic_send_IPI(int cpu, int vector)
+{
+ u32 dest = per_cpu(x86_cpu_to_apicid, cpu);
+
+ x2apic_wrmsr_fence();
+ __x2apic_send_IPI_dest(dest, vector, APIC_DEST_PHYSICAL);
+}
+
static void
__x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
{
@@ -122,6 +130,7 @@ static struct apic apic_x2apic_phys = {
.cpu_mask_to_apicid_and = default_cpu_mask_to_apicid_and,
+ .send_IPI = x2apic_send_IPI,
.send_IPI_mask = x2apic_send_IPI_mask,
.send_IPI_mask_allbutself = x2apic_send_IPI_mask_allbutself,
.send_IPI_allbutself = x2apic_send_IPI_allbutself,
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 4a13946..d760c6b 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -406,6 +406,7 @@ static struct apic __refdata apic_x2apic_uv_x = {
.cpu_mask_to_apicid_and = uv_cpu_mask_to_apicid_and,
+ .send_IPI = uv_send_IPI_one,
.send_IPI_mask = uv_send_IPI_mask,
.send_IPI_mask_allbutself = uv_send_IPI_mask_allbutself,
.send_IPI_allbutself = uv_send_IPI_allbutself,
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 439df97..84a7524 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -65,9 +65,6 @@ void common(void) {
OFFSET(PV_IRQ_irq_disable, pv_irq_ops, irq_disable);
OFFSET(PV_IRQ_irq_enable, pv_irq_ops, irq_enable);
OFFSET(PV_CPU_iret, pv_cpu_ops, iret);
-#ifdef CONFIG_X86_32
- OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit);
-#endif
OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0);
OFFSET(PV_MMU_read_cr2, pv_mmu_ops, read_cr2);
#endif
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index d8f42f9..f2edafb 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -23,7 +23,6 @@ int main(void)
{
#ifdef CONFIG_PARAVIRT
OFFSET(PV_IRQ_adjust_exception_frame, pv_irq_ops, adjust_exception_frame);
- OFFSET(PV_CPU_usergs_sysret32, pv_cpu_ops, usergs_sysret32);
OFFSET(PV_CPU_usergs_sysret64, pv_cpu_ops, usergs_sysret64);
OFFSET(PV_CPU_swapgs, pv_cpu_ops, swapgs);
BLANK();
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 4a70fc6..e678dde 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -304,7 +304,7 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
int cpu = smp_processor_id();
/* get information required for multi-node processors */
- if (cpu_has_topoext) {
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
u32 eax, ebx, ecx, edx;
cpuid(0x8000001e, &eax, &ebx, &ecx, &edx);
@@ -352,6 +352,7 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
#ifdef CONFIG_SMP
unsigned bits;
int cpu = smp_processor_id();
+ unsigned int socket_id, core_complex_id;
bits = c->x86_coreid_bits;
/* Low order bits define the core id (index of core in socket) */
@@ -361,6 +362,18 @@ static void amd_detect_cmp(struct cpuinfo_x86 *c)
/* use socket ID also for last level cache */
per_cpu(cpu_llc_id, cpu) = c->phys_proc_id;
amd_get_topology(c);
+
+ /*
+ * Fix percpu cpu_llc_id here as LLC topology is different
+ * for Fam17h systems.
+ */
+ if (c->x86 != 0x17 || !cpuid_edx(0x80000006))
+ return;
+
+ socket_id = (c->apicid >> bits) - 1;
+ core_complex_id = (c->apicid & ((1 << bits) - 1)) >> 3;
+
+ per_cpu(cpu_llc_id, cpu) = (socket_id << 3) | core_complex_id;
#endif
}
@@ -665,9 +678,9 @@ static void init_amd_bd(struct cpuinfo_x86 *c)
* Disable it on the affected CPUs.
*/
if ((c->x86_model >= 0x02) && (c->x86_model < 0x20)) {
- if (!rdmsrl_safe(0xc0011021, &value) && !(value & 0x1E)) {
+ if (!rdmsrl_safe(MSR_F15H_IC_CFG, &value) && !(value & 0x1E)) {
value |= 0x1E;
- wrmsrl_safe(0xc0011021, value);
+ wrmsrl_safe(MSR_F15H_IC_CFG, value);
}
}
}
@@ -909,7 +922,7 @@ static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)
void set_dr_addr_mask(unsigned long mask, int dr)
{
- if (!cpu_has_bpext)
+ if (!boot_cpu_has(X86_FEATURE_BPEXT))
return;
switch (dr) {
diff --git a/arch/x86/kernel/cpu/centaur.c b/arch/x86/kernel/cpu/centaur.c
index d8fba5c..ae20be6 100644
--- a/arch/x86/kernel/cpu/centaur.c
+++ b/arch/x86/kernel/cpu/centaur.c
@@ -43,7 +43,7 @@ static void init_c3(struct cpuinfo_x86 *c)
/* store Centaur Extended Feature Flags as
* word 5 of the CPU capability bit array
*/
- c->x86_capability[5] = cpuid_edx(0xC0000001);
+ c->x86_capability[CPUID_C000_0001_EDX] = cpuid_edx(0xC0000001);
}
#ifdef CONFIG_X86_32
/* Cyrix III family needs CX8 & PGE explicitly enabled. */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4ddd780..37830de 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -273,10 +273,9 @@ __setup("nosmap", setup_disable_smap);
static __always_inline void setup_smap(struct cpuinfo_x86 *c)
{
- unsigned long eflags;
+ unsigned long eflags = native_save_fl();
/* This should have been cleared long ago */
- raw_local_save_flags(eflags);
BUG_ON(eflags & X86_EFLAGS_AC);
if (cpu_has(c, X86_FEATURE_SMAP)) {
@@ -582,14 +581,9 @@ void cpu_detect(struct cpuinfo_x86 *c)
u32 junk, tfms, cap0, misc;
cpuid(0x00000001, &tfms, &misc, &junk, &cap0);
- c->x86 = (tfms >> 8) & 0xf;
- c->x86_model = (tfms >> 4) & 0xf;
- c->x86_mask = tfms & 0xf;
-
- if (c->x86 == 0xf)
- c->x86 += (tfms >> 20) & 0xff;
- if (c->x86 >= 0x6)
- c->x86_model += ((tfms >> 16) & 0xf) << 4;
+ c->x86 = x86_family(tfms);
+ c->x86_model = x86_model(tfms);
+ c->x86_mask = x86_stepping(tfms);
if (cap0 & (1<<19)) {
c->x86_clflush_size = ((misc >> 8) & 0xff) * 8;
@@ -600,50 +594,47 @@ void cpu_detect(struct cpuinfo_x86 *c)
void get_cpu_cap(struct cpuinfo_x86 *c)
{
- u32 tfms, xlvl;
- u32 ebx;
+ u32 eax, ebx, ecx, edx;
/* Intel-defined flags: level 0x00000001 */
if (c->cpuid_level >= 0x00000001) {
- u32 capability, excap;
+ cpuid(0x00000001, &eax, &ebx, &ecx, &edx);
- cpuid(0x00000001, &tfms, &ebx, &excap, &capability);
- c->x86_capability[0] = capability;
- c->x86_capability[4] = excap;
+ c->x86_capability[CPUID_1_ECX] = ecx;
+ c->x86_capability[CPUID_1_EDX] = edx;
}
/* Additional Intel-defined flags: level 0x00000007 */
if (c->cpuid_level >= 0x00000007) {
- u32 eax, ebx, ecx, edx;
-
cpuid_count(0x00000007, 0, &eax, &ebx, &ecx, &edx);
- c->x86_capability[9] = ebx;
+ c->x86_capability[CPUID_7_0_EBX] = ebx;
+
+ c->x86_capability[CPUID_6_EAX] = cpuid_eax(0x00000006);
}
/* Extended state features: level 0x0000000d */
if (c->cpuid_level >= 0x0000000d) {
- u32 eax, ebx, ecx, edx;
-
cpuid_count(0x0000000d, 1, &eax, &ebx, &ecx, &edx);
- c->x86_capability[10] = eax;
+ c->x86_capability[CPUID_D_1_EAX] = eax;
}
/* Additional Intel-defined flags: level 0x0000000F */
if (c->cpuid_level >= 0x0000000F) {
- u32 eax, ebx, ecx, edx;
/* QoS sub-leaf, EAX=0Fh, ECX=0 */
cpuid_count(0x0000000F, 0, &eax, &ebx, &ecx, &edx);
- c->x86_capability[11] = edx;
+ c->x86_capability[CPUID_F_0_EDX] = edx;
+
if (cpu_has(c, X86_FEATURE_CQM_LLC)) {
/* will be overridden if occupancy monitoring exists */
c->x86_cache_max_rmid = ebx;
/* QoS sub-leaf, EAX=0Fh, ECX=1 */
cpuid_count(0x0000000F, 1, &eax, &ebx, &ecx, &edx);
- c->x86_capability[12] = edx;
+ c->x86_capability[CPUID_F_1_EDX] = edx;
+
if (cpu_has(c, X86_FEATURE_CQM_OCCUP_LLC)) {
c->x86_cache_max_rmid = ecx;
c->x86_cache_occ_scale = ebx;
@@ -655,22 +646,24 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
}
/* AMD-defined flags: level 0x80000001 */
- xlvl = cpuid_eax(0x80000000);
- c->extended_cpuid_level = xlvl;
+ eax = cpuid_eax(0x80000000);
+ c->extended_cpuid_level = eax;
- if ((xlvl & 0xffff0000) == 0x80000000) {
- if (xlvl >= 0x80000001) {
- c->x86_capability[1] = cpuid_edx(0x80000001);
- c->x86_capability[6] = cpuid_ecx(0x80000001);
+ if ((eax & 0xffff0000) == 0x80000000) {
+ if (eax >= 0x80000001) {
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+
+ c->x86_capability[CPUID_8000_0001_ECX] = ecx;
+ c->x86_capability[CPUID_8000_0001_EDX] = edx;
}
}
if (c->extended_cpuid_level >= 0x80000008) {
- u32 eax = cpuid_eax(0x80000008);
+ cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
c->x86_virt_bits = (eax >> 8) & 0xff;
c->x86_phys_bits = eax & 0xff;
- c->x86_capability[13] = cpuid_ebx(0x80000008);
+ c->x86_capability[CPUID_8000_0008_EBX] = ebx;
}
#ifdef CONFIG_X86_32
else if (cpu_has(c, X86_FEATURE_PAE) || cpu_has(c, X86_FEATURE_PSE36))
@@ -680,6 +673,9 @@ void get_cpu_cap(struct cpuinfo_x86 *c)
if (c->extended_cpuid_level >= 0x80000007)
c->x86_power = cpuid_edx(0x80000007);
+ if (c->extended_cpuid_level >= 0x8000000a)
+ c->x86_capability[CPUID_8000_000A_EDX] = cpuid_edx(0x8000000a);
+
init_scattered_cpuid_features(c);
}
@@ -1186,7 +1182,7 @@ void syscall_init(void)
* They both write to the same internal register. STAR allows to
* set CS/DS but only a 32bit target. LSTAR sets the 64bit rip.
*/
- wrmsrl(MSR_STAR, ((u64)__USER32_CS)<<48 | ((u64)__KERNEL_CS)<<32);
+ wrmsr(MSR_STAR, 0, (__USER32_CS << 16) | __KERNEL_CS);
wrmsrl(MSR_LSTAR, (unsigned long)entry_SYSCALL_64);
#ifdef CONFIG_IA32_EMULATION
@@ -1444,7 +1440,9 @@ void cpu_init(void)
printk(KERN_INFO "Initializing CPU#%d\n", cpu);
- if (cpu_feature_enabled(X86_FEATURE_VME) || cpu_has_tsc || cpu_has_de)
+ if (cpu_feature_enabled(X86_FEATURE_VME) ||
+ cpu_has_tsc ||
+ boot_cpu_has(X86_FEATURE_DE))
cr4_clear_bits(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
load_current_idt();
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index 98a13db..565648b 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -97,6 +97,7 @@ static void early_init_intel(struct cpuinfo_x86 *c)
switch (c->x86_model) {
case 0x27: /* Penwell */
case 0x35: /* Cloverview */
+ case 0x4a: /* Merrifield */
set_cpu_cap(c, X86_FEATURE_NONSTOP_TSC_S3);
break;
default:
@@ -444,7 +445,8 @@ static void init_intel(struct cpuinfo_x86 *c)
if (cpu_has_xmm2)
set_cpu_cap(c, X86_FEATURE_LFENCE_RDTSC);
- if (cpu_has_ds) {
+
+ if (boot_cpu_has(X86_FEATURE_DS)) {
unsigned int l1;
rdmsr(MSR_IA32_MISC_ENABLE, l1, l2);
if (!(l1 & (1<<11)))
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index e38d338..0b6c523 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -591,7 +591,7 @@ cpuid4_cache_lookup_regs(int index, struct _cpuid4_info_regs *this_leaf)
unsigned edx;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
- if (cpu_has_topoext)
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT))
cpuid_count(0x8000001d, index, &eax.full,
&ebx.full, &ecx.full, &edx);
else
@@ -637,7 +637,7 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
void init_amd_cacheinfo(struct cpuinfo_x86 *c)
{
- if (cpu_has_topoext) {
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
num_cache_leaves = find_num_cache_leaves(c);
} else if (c->extended_cpuid_level >= 0x80000006) {
if (cpuid_edx(0x80000006) & 0xf000)
@@ -809,7 +809,7 @@ static int __cache_amd_cpumap_setup(unsigned int cpu, int index,
struct cacheinfo *this_leaf;
int i, sibling;
- if (cpu_has_topoext) {
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
unsigned int apicid, nshared, first, last;
this_leaf = this_cpu_ci->info_list + index;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index c5b0d56..a006f4c 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -114,7 +114,6 @@ static struct work_struct mce_work;
static struct irq_work mce_irq_work;
static void (*quirk_no_way_out)(int bank, struct mce *m, struct pt_regs *regs);
-static int mce_usable_address(struct mce *m);
/*
* CPU/chipset specific EDAC code can register a notifier call here to print
@@ -475,6 +474,28 @@ static void mce_report_event(struct pt_regs *regs)
irq_work_queue(&mce_irq_work);
}
+/*
+ * Check if the address reported by the CPU is in a format we can parse.
+ * It would be possible to add code for most other cases, but all would
+ * be somewhat complicated (e.g. segment offset would require an instruction
+ * parser). So only support physical addresses up to page granuality for now.
+ */
+static int mce_usable_address(struct mce *m)
+{
+ if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
+ return 0;
+
+ /* Checks after this one are Intel-specific: */
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
+ return 1;
+
+ if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT)
+ return 0;
+ if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
+ return 0;
+ return 1;
+}
+
static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
void *data)
{
@@ -484,7 +505,7 @@ static int srao_decode_notifier(struct notifier_block *nb, unsigned long val,
if (!mce)
return NOTIFY_DONE;
- if (mce->usable_addr && (mce->severity == MCE_AO_SEVERITY)) {
+ if (mce_usable_address(mce) && (mce->severity == MCE_AO_SEVERITY)) {
pfn = mce->addr >> PAGE_SHIFT;
memory_failure(pfn, MCE_VECTOR, 0);
}
@@ -522,10 +543,10 @@ static bool memory_error(struct mce *m)
struct cpuinfo_x86 *c = &boot_cpu_data;
if (c->x86_vendor == X86_VENDOR_AMD) {
- /*
- * coming soon
- */
- return false;
+ /* ErrCodeExt[20:16] */
+ u8 xec = (m->status >> 16) & 0x1f;
+
+ return (xec == 0x0 || xec == 0x8);
} else if (c->x86_vendor == X86_VENDOR_INTEL) {
/*
* Intel SDM Volume 3B - 15.9.2 Compound Error Codes
@@ -567,7 +588,7 @@ DEFINE_PER_CPU(unsigned, mce_poll_count);
*/
bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{
- bool error_logged = false;
+ bool error_seen = false;
struct mce m;
int severity;
int i;
@@ -601,6 +622,8 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
(m.status & (mca_cfg.ser ? MCI_STATUS_S : MCI_STATUS_UC)))
continue;
+ error_seen = true;
+
mce_read_aux(&m, i);
if (!(flags & MCP_TIMESTAMP))
@@ -608,27 +631,24 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
- /*
- * In the cases where we don't have a valid address after all,
- * do not add it into the ring buffer.
- */
- if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) {
- if (m.status & MCI_STATUS_ADDRV) {
+ if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m))
+ if (m.status & MCI_STATUS_ADDRV)
m.severity = severity;
- m.usable_addr = mce_usable_address(&m);
-
- if (!mce_gen_pool_add(&m))
- mce_schedule_work();
- }
- }
/*
* Don't get the IP here because it's unlikely to
* have anything to do with the actual error location.
*/
- if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce) {
- error_logged = true;
+ if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce)
mce_log(&m);
+ else if (mce_usable_address(&m)) {
+ /*
+ * Although we skipped logging this, we still want
+ * to take action. Add to the pool so the registered
+ * notifiers will see it.
+ */
+ if (!mce_gen_pool_add(&m))
+ mce_schedule_work();
}
/*
@@ -644,7 +664,7 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
sync_core();
- return error_logged;
+ return error_seen;
}
EXPORT_SYMBOL_GPL(machine_check_poll);
@@ -931,23 +951,6 @@ reset:
return ret;
}
-/*
- * Check if the address reported by the CPU is in a format we can parse.
- * It would be possible to add code for most other cases, but all would
- * be somewhat complicated (e.g. segment offset would require an instruction
- * parser). So only support physical addresses up to page granuality for now.
- */
-static int mce_usable_address(struct mce *m)
-{
- if (!(m->status & MCI_STATUS_MISCV) || !(m->status & MCI_STATUS_ADDRV))
- return 0;
- if (MCI_MISC_ADDR_LSB(m->misc) > PAGE_SHIFT)
- return 0;
- if (MCI_MISC_ADDR_MODE(m->misc) != MCI_MISC_ADDR_PHYS)
- return 0;
- return 1;
-}
-
static void mce_clear_state(unsigned long *toclear)
{
int i;
@@ -999,6 +1002,17 @@ void do_machine_check(struct pt_regs *regs, long error_code)
int flags = MF_ACTION_REQUIRED;
int lmce = 0;
+ /* If this CPU is offline, just bail out. */
+ if (cpu_is_offline(smp_processor_id())) {
+ u64 mcgstatus;
+
+ mcgstatus = mce_rdmsrl(MSR_IA32_MCG_STATUS);
+ if (mcgstatus & MCG_STATUS_RIPV) {
+ mce_wrmsrl(MSR_IA32_MCG_STATUS, 0);
+ return;
+ }
+ }
+
ist_enter(regs);
this_cpu_inc(mce_exception_count);
@@ -1089,7 +1103,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)
/* assuming valid severity level != 0 */
m.severity = severity;
- m.usable_addr = mce_usable_address(&m);
mce_log(&m);
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 7fc27f1..faec712 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -129,8 +129,8 @@ void __init load_ucode_bsp(void)
if (!have_cpuid_p())
return;
- vendor = x86_vendor();
- family = x86_family();
+ vendor = x86_cpuid_vendor();
+ family = x86_cpuid_family();
switch (vendor) {
case X86_VENDOR_INTEL:
@@ -165,8 +165,8 @@ void load_ucode_ap(void)
if (!have_cpuid_p())
return;
- vendor = x86_vendor();
- family = x86_family();
+ vendor = x86_cpuid_vendor();
+ family = x86_cpuid_family();
switch (vendor) {
case X86_VENDOR_INTEL:
@@ -206,8 +206,8 @@ void reload_early_microcode(void)
{
int vendor, family;
- vendor = x86_vendor();
- family = x86_family();
+ vendor = x86_cpuid_vendor();
+ family = x86_cpuid_family();
switch (vendor) {
case X86_VENDOR_INTEL:
@@ -698,3 +698,4 @@ int __init microcode_init(void)
return error;
}
+late_initcall(microcode_init);
diff --git a/arch/x86/kernel/cpu/microcode/intel.c b/arch/x86/kernel/cpu/microcode/intel.c
index ce47402..ee81c54 100644
--- a/arch/x86/kernel/cpu/microcode/intel.c
+++ b/arch/x86/kernel/cpu/microcode/intel.c
@@ -145,10 +145,10 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
int ext_sigcount, i;
struct extended_signature *ext_sig;
- fam = __x86_family(sig);
+ fam = x86_family(sig);
model = x86_model(sig);
- fam_ucode = __x86_family(mc_header->sig);
+ fam_ucode = x86_family(mc_header->sig);
model_ucode = x86_model(mc_header->sig);
if (fam == fam_ucode && model == model_ucode)
@@ -163,7 +163,7 @@ matching_model_microcode(struct microcode_header_intel *mc_header,
ext_sigcount = ext_header->count;
for (i = 0; i < ext_sigcount; i++) {
- fam_ucode = __x86_family(ext_sig->sig);
+ fam_ucode = x86_family(ext_sig->sig);
model_ucode = x86_model(ext_sig->sig);
if (fam == fam_ucode && model == model_ucode)
@@ -365,7 +365,7 @@ static int collect_cpu_info_early(struct ucode_cpu_info *uci)
native_cpuid(&eax, &ebx, &ecx, &edx);
csig.sig = eax;
- family = __x86_family(csig.sig);
+ family = x86_family(csig.sig);
model = x86_model(csig.sig);
if ((model >= 5) || (family > 6)) {
@@ -521,16 +521,12 @@ static bool __init load_builtin_intel_microcode(struct cpio_data *cp)
{
#ifdef CONFIG_X86_64
unsigned int eax = 0x00000001, ebx, ecx = 0, edx;
- unsigned int family, model, stepping;
char name[30];
native_cpuid(&eax, &ebx, &ecx, &edx);
- family = __x86_family(eax);
- model = x86_model(eax);
- stepping = eax & 0xf;
-
- sprintf(name, "intel-ucode/%02x-%02x-%02x", family, model, stepping);
+ sprintf(name, "intel-ucode/%02x-%02x-%02x",
+ x86_family(eax), x86_model(eax), x86_stepping(eax));
return get_builtin_firmware(cp, name);
#else
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
index 70d7c93..0d98503 100644
--- a/arch/x86/kernel/cpu/mtrr/cleanup.c
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -593,9 +593,16 @@ mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
unsigned long x_remove_base,
unsigned long x_remove_size, int i)
{
- static struct range range_new[RANGE_NUM];
+ /*
+ * range_new should really be an automatic variable, but
+ * putting 4096 bytes on the stack is frowned upon, to put it
+ * mildly. It is safe to make it a static __initdata variable,
+ * since mtrr_calc_range_state is only called during init and
+ * there's no way it will call itself recursively.
+ */
+ static struct range range_new[RANGE_NUM] __initdata;
unsigned long range_sums_new;
- static int nr_range_new;
+ int nr_range_new;
int num_reg;
/* Convert ranges to var ranges state: */
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 3b533cf..c870af1 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -349,7 +349,7 @@ static void get_fixed_ranges(mtrr_type *frs)
void mtrr_save_fixed_ranges(void *info)
{
- if (cpu_has_mtrr)
+ if (boot_cpu_has(X86_FEATURE_MTRR))
get_fixed_ranges(mtrr_state.fixed_ranges);
}
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index f891b47..5c3d149 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -682,7 +682,7 @@ void __init mtrr_bp_init(void)
phys_addr = 32;
- if (cpu_has_mtrr) {
+ if (boot_cpu_has(X86_FEATURE_MTRR)) {
mtrr_if = &generic_mtrr_ops;
size_or_mask = SIZE_OR_MASK_BITS(36);
size_and_mask = 0x00f00000;
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index 4562cf0..1b443db 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -5,7 +5,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
* Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
* Copyright (C) 2009 Google, Inc., Stephane Eranian
*
@@ -482,6 +482,9 @@ int x86_pmu_hw_config(struct perf_event *event)
/* Support for IP fixup */
if (x86_pmu.lbr_nr || x86_pmu.intel_cap.pebs_format >= 2)
precise++;
+
+ if (x86_pmu.pebs_prec_dist)
+ precise++;
}
if (event->attr.precise_ip > precise)
@@ -1531,6 +1534,7 @@ static void __init filter_events(struct attribute **attrs)
{
struct device_attribute *d;
struct perf_pmu_events_attr *pmu_attr;
+ int offset = 0;
int i, j;
for (i = 0; attrs[i]; i++) {
@@ -1539,7 +1543,7 @@ static void __init filter_events(struct attribute **attrs)
/* str trumps id */
if (pmu_attr->event_str)
continue;
- if (x86_pmu.event_map(i))
+ if (x86_pmu.event_map(i + offset))
continue;
for (j = i; attrs[j]; j++)
@@ -1547,6 +1551,14 @@ static void __init filter_events(struct attribute **attrs)
/* Check the shifted attr. */
i--;
+
+ /*
+ * event_map() is index based, the attrs array is organized
+ * by increasing event index. If we shift the events, then
+ * we need to compensate for the event_map(), otherwise
+ * we are looking up the wrong event in the map
+ */
+ offset++;
}
}
@@ -2250,12 +2262,19 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
ss_base = get_segment_base(regs->ss);
fp = compat_ptr(ss_base + regs->bp);
+ pagefault_disable();
while (entry->nr < PERF_MAX_STACK_DEPTH) {
unsigned long bytes;
frame.next_frame = 0;
frame.return_address = 0;
- bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+ if (!access_ok(VERIFY_READ, fp, 8))
+ break;
+
+ bytes = __copy_from_user_nmi(&frame.next_frame, fp, 4);
+ if (bytes != 0)
+ break;
+ bytes = __copy_from_user_nmi(&frame.return_address, fp+4, 4);
if (bytes != 0)
break;
@@ -2265,6 +2284,7 @@ perf_callchain_user32(struct pt_regs *regs, struct perf_callchain_entry *entry)
perf_callchain_store(entry, cs_base + frame.return_address);
fp = compat_ptr(ss_base + frame.next_frame);
}
+ pagefault_enable();
return 1;
}
#else
@@ -2302,12 +2322,19 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
if (perf_callchain_user32(regs, entry))
return;
+ pagefault_disable();
while (entry->nr < PERF_MAX_STACK_DEPTH) {
unsigned long bytes;
frame.next_frame = NULL;
frame.return_address = 0;
- bytes = copy_from_user_nmi(&frame, fp, sizeof(frame));
+ if (!access_ok(VERIFY_READ, fp, 16))
+ break;
+
+ bytes = __copy_from_user_nmi(&frame.next_frame, fp, 8);
+ if (bytes != 0)
+ break;
+ bytes = __copy_from_user_nmi(&frame.return_address, fp+8, 8);
if (bytes != 0)
break;
@@ -2315,8 +2342,9 @@ perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
break;
perf_callchain_store(entry, frame.return_address);
- fp = frame.next_frame;
+ fp = (void __user *)frame.next_frame;
}
+ pagefault_enable();
}
/*
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index 499f533..7bb61e3 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -5,7 +5,7 @@
* Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar
* Copyright (C) 2009 Jaswinder Singh Rajput
* Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter
- * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra
* Copyright (C) 2009 Intel Corporation, <markus.t.metzger@intel.com>
* Copyright (C) 2009 Google, Inc., Stephane Eranian
*
@@ -14,17 +14,7 @@
#include <linux/perf_event.h>
-#if 0
-#undef wrmsrl
-#define wrmsrl(msr, val) \
-do { \
- unsigned int _msr = (msr); \
- u64 _val = (val); \
- trace_printk("wrmsrl(%x, %Lx)\n", (unsigned int)(_msr), \
- (unsigned long long)(_val)); \
- native_write_msr((_msr), (u32)(_val), (u32)(_val >> 32)); \
-} while (0)
-#endif
+/* To enable MSR tracing please use the generic trace points. */
/*
* | NHM/WSM | SNB |
@@ -318,6 +308,10 @@ struct cpu_hw_events {
#define INTEL_UEVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+/* Constraint on specific umask bit only + event */
+#define INTEL_UBIT_EVENT_CONSTRAINT(c, n) \
+ EVENT_CONSTRAINT(c, n, ARCH_PERFMON_EVENTSEL_EVENT|(c))
+
/* Like UEVENT_CONSTRAINT, but match flags too */
#define INTEL_FLAGS_UEVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
@@ -387,7 +381,7 @@ struct cpu_hw_events {
/* Check flags and event code/umask, and set the HSW N/A flag */
#define INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(code, n) \
__EVENT_CONSTRAINT(code, n, \
- INTEL_ARCH_EVENT_MASK|INTEL_ARCH_EVENT_MASK, \
+ INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_NA_HSW)
@@ -589,7 +583,8 @@ struct x86_pmu {
bts_active :1,
pebs :1,
pebs_active :1,
- pebs_broken :1;
+ pebs_broken :1,
+ pebs_prec_dist :1;
int pebs_record_size;
void (*drain_pebs)(struct pt_regs *regs);
struct event_constraint *pebs_constraints;
@@ -627,6 +622,7 @@ struct x86_perf_task_context {
u64 lbr_from[MAX_LBR_ENTRIES];
u64 lbr_to[MAX_LBR_ENTRIES];
u64 lbr_info[MAX_LBR_ENTRIES];
+ int tos;
int lbr_callstack_users;
int lbr_stack_state;
};
@@ -906,6 +902,8 @@ void intel_pmu_lbr_init_hsw(void);
void intel_pmu_lbr_init_skl(void);
+void intel_pmu_lbr_init_knl(void);
+
int intel_pmu_setup_lbr_filter(struct perf_event *event);
void intel_pt_interrupt(void);
diff --git a/arch/x86/kernel/cpu/perf_event_amd.c b/arch/x86/kernel/cpu/perf_event_amd.c
index 1cee5d2..5861053 100644
--- a/arch/x86/kernel/cpu/perf_event_amd.c
+++ b/arch/x86/kernel/cpu/perf_event_amd.c
@@ -18,7 +18,7 @@ static __initconst const u64 amd_hw_cache_event_ids
[ C(RESULT_MISS) ] = 0x0141, /* Data Cache Misses */
},
[ C(OP_WRITE) ] = {
- [ C(RESULT_ACCESS) ] = 0x0142, /* Data Cache Refills :system */
+ [ C(RESULT_ACCESS) ] = 0,
[ C(RESULT_MISS) ] = 0,
},
[ C(OP_PREFETCH) ] = {
@@ -160,7 +160,7 @@ static inline int amd_pmu_addr_offset(int index, bool eventsel)
if (offset)
return offset;
- if (!cpu_has_perfctr_core)
+ if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
offset = index;
else
offset = index << 1;
@@ -652,7 +652,7 @@ static __initconst const struct x86_pmu amd_pmu = {
static int __init amd_core_pmu_init(void)
{
- if (!cpu_has_perfctr_core)
+ if (!boot_cpu_has(X86_FEATURE_PERFCTR_CORE))
return 0;
switch (boot_cpu_data.x86) {
diff --git a/arch/x86/kernel/cpu/perf_event_amd_uncore.c b/arch/x86/kernel/cpu/perf_event_amd_uncore.c
index cc6cedb..4974274 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_uncore.c
@@ -523,10 +523,10 @@ static int __init amd_uncore_init(void)
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
goto fail_nodev;
- if (!cpu_has_topoext)
+ if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
goto fail_nodev;
- if (cpu_has_perfctr_nb) {
+ if (boot_cpu_has(X86_FEATURE_PERFCTR_NB)) {
amd_uncore_nb = alloc_percpu(struct amd_uncore *);
if (!amd_uncore_nb) {
ret = -ENOMEM;
@@ -540,7 +540,7 @@ static int __init amd_uncore_init(void)
ret = 0;
}
- if (cpu_has_perfctr_l2) {
+ if (boot_cpu_has(X86_FEATURE_PERFCTR_L2)) {
amd_uncore_l2 = alloc_percpu(struct amd_uncore *);
if (!amd_uncore_l2) {
ret = -ENOMEM;
@@ -583,10 +583,11 @@ fail_online:
/* amd_uncore_nb/l2 should have been freed by cleanup_cpu_online */
amd_uncore_nb = amd_uncore_l2 = NULL;
- if (cpu_has_perfctr_l2)
+
+ if (boot_cpu_has(X86_FEATURE_PERFCTR_L2))
perf_pmu_unregister(&amd_l2_pmu);
fail_l2:
- if (cpu_has_perfctr_nb)
+ if (boot_cpu_has(X86_FEATURE_PERFCTR_NB))
perf_pmu_unregister(&amd_nb_pmu);
if (amd_uncore_l2)
free_percpu(amd_uncore_l2);
diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c
index f63360b..a667078 100644
--- a/arch/x86/kernel/cpu/perf_event_intel.c
+++ b/arch/x86/kernel/cpu/perf_event_intel.c
@@ -185,6 +185,14 @@ struct event_constraint intel_skl_event_constraints[] = {
EVENT_CONSTRAINT_END
};
+static struct extra_reg intel_knl_extra_regs[] __read_mostly = {
+ INTEL_UEVENT_EXTRA_REG(0x01b7,
+ MSR_OFFCORE_RSP_0, 0x7f9ffbffffull, RSP_0),
+ INTEL_UEVENT_EXTRA_REG(0x02b7,
+ MSR_OFFCORE_RSP_1, 0x3f9ffbffffull, RSP_1),
+ EVENT_EXTRA_END
+};
+
static struct extra_reg intel_snb_extra_regs[] __read_mostly = {
/* must define OFFCORE_RSP_X first, see intel_fixup_er() */
INTEL_UEVENT_EXTRA_REG(0x01b7, MSR_OFFCORE_RSP_0, 0x3f807f8fffull, RSP_0),
@@ -232,7 +240,7 @@ static struct event_constraint intel_hsw_event_constraints[] = {
FIXED_EVENT_CONSTRAINT(0x00c0, 0), /* INST_RETIRED.ANY */
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
- INTEL_EVENT_CONSTRAINT(0x48, 0x4), /* L1D_PEND_MISS.* */
+ INTEL_UEVENT_CONSTRAINT(0x148, 0x4), /* L1D_PEND_MISS.PENDING */
INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PREC_DIST */
INTEL_EVENT_CONSTRAINT(0xcd, 0x8), /* MEM_TRANS_RETIRED.LOAD_LATENCY */
/* CYCLE_ACTIVITY.CYCLES_L1D_PENDING */
@@ -255,7 +263,7 @@ struct event_constraint intel_bdw_event_constraints[] = {
FIXED_EVENT_CONSTRAINT(0x003c, 1), /* CPU_CLK_UNHALTED.CORE */
FIXED_EVENT_CONSTRAINT(0x0300, 2), /* CPU_CLK_UNHALTED.REF */
INTEL_UEVENT_CONSTRAINT(0x148, 0x4), /* L1D_PEND_MISS.PENDING */
- INTEL_UEVENT_CONSTRAINT(0x8a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_MISS */
+ INTEL_UBIT_EVENT_CONSTRAINT(0x8a3, 0x4), /* CYCLE_ACTIVITY.CYCLES_L1D_MISS */
EVENT_CONSTRAINT_END
};
@@ -1457,6 +1465,42 @@ static __initconst const u64 slm_hw_cache_event_ids
},
};
+#define KNL_OT_L2_HITE BIT_ULL(19) /* Other Tile L2 Hit */
+#define KNL_OT_L2_HITF BIT_ULL(20) /* Other Tile L2 Hit */
+#define KNL_MCDRAM_LOCAL BIT_ULL(21)
+#define KNL_MCDRAM_FAR BIT_ULL(22)
+#define KNL_DDR_LOCAL BIT_ULL(23)
+#define KNL_DDR_FAR BIT_ULL(24)
+#define KNL_DRAM_ANY (KNL_MCDRAM_LOCAL | KNL_MCDRAM_FAR | \
+ KNL_DDR_LOCAL | KNL_DDR_FAR)
+#define KNL_L2_READ SLM_DMND_READ
+#define KNL_L2_WRITE SLM_DMND_WRITE
+#define KNL_L2_PREFETCH SLM_DMND_PREFETCH
+#define KNL_L2_ACCESS SLM_LLC_ACCESS
+#define KNL_L2_MISS (KNL_OT_L2_HITE | KNL_OT_L2_HITF | \
+ KNL_DRAM_ANY | SNB_SNP_ANY | \
+ SNB_NON_DRAM)
+
+static __initconst const u64 knl_hw_cache_extra_regs
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+ [C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KNL_L2_READ | KNL_L2_ACCESS,
+ [C(RESULT_MISS)] = 0,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KNL_L2_WRITE | KNL_L2_ACCESS,
+ [C(RESULT_MISS)] = KNL_L2_WRITE | KNL_L2_MISS,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KNL_L2_PREFETCH | KNL_L2_ACCESS,
+ [C(RESULT_MISS)] = KNL_L2_PREFETCH | KNL_L2_MISS,
+ },
+ },
+};
+
/*
* Use from PMIs where the LBRs are already disabled.
*/
@@ -2475,6 +2519,44 @@ static void intel_pebs_aliases_snb(struct perf_event *event)
}
}
+static void intel_pebs_aliases_precdist(struct perf_event *event)
+{
+ if ((event->hw.config & X86_RAW_EVENT_MASK) == 0x003c) {
+ /*
+ * Use an alternative encoding for CPU_CLK_UNHALTED.THREAD_P
+ * (0x003c) so that we can use it with PEBS.
+ *
+ * The regular CPU_CLK_UNHALTED.THREAD_P event (0x003c) isn't
+ * PEBS capable. However we can use INST_RETIRED.PREC_DIST
+ * (0x01c0), which is a PEBS capable event, to get the same
+ * count.
+ *
+ * The PREC_DIST event has special support to minimize sample
+ * shadowing effects. One drawback is that it can be
+ * only programmed on counter 1, but that seems like an
+ * acceptable trade off.
+ */
+ u64 alt_config = X86_CONFIG(.event=0xc0, .umask=0x01, .inv=1, .cmask=16);
+
+ alt_config |= (event->hw.config & ~X86_RAW_EVENT_MASK);
+ event->hw.config = alt_config;
+ }
+}
+
+static void intel_pebs_aliases_ivb(struct perf_event *event)
+{
+ if (event->attr.precise_ip < 3)
+ return intel_pebs_aliases_snb(event);
+ return intel_pebs_aliases_precdist(event);
+}
+
+static void intel_pebs_aliases_skl(struct perf_event *event)
+{
+ if (event->attr.precise_ip < 3)
+ return intel_pebs_aliases_core2(event);
+ return intel_pebs_aliases_precdist(event);
+}
+
static unsigned long intel_pmu_free_running_flags(struct perf_event *event)
{
unsigned long flags = x86_pmu.free_running_flags;
@@ -3332,6 +3414,7 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_gen_event_constraints;
x86_pmu.pebs_constraints = intel_atom_pebs_event_constraints;
+ x86_pmu.pebs_aliases = intel_pebs_aliases_core2;
pr_cont("Atom events, ");
break;
@@ -3431,7 +3514,8 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_ivb_event_constraints;
x86_pmu.pebs_constraints = intel_ivb_pebs_event_constraints;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+ x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+ x86_pmu.pebs_prec_dist = true;
if (boot_cpu_data.x86_model == 62)
x86_pmu.extra_regs = intel_snbep_extra_regs;
else
@@ -3464,7 +3548,8 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_hsw_event_constraints;
x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
x86_pmu.extra_regs = intel_snbep_extra_regs;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+ x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+ x86_pmu.pebs_prec_dist = true;
/* all extra regs are per-cpu when HT is on */
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
@@ -3499,7 +3584,8 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_bdw_event_constraints;
x86_pmu.pebs_constraints = intel_hsw_pebs_event_constraints;
x86_pmu.extra_regs = intel_snbep_extra_regs;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+ x86_pmu.pebs_aliases = intel_pebs_aliases_ivb;
+ x86_pmu.pebs_prec_dist = true;
/* all extra regs are per-cpu when HT is on */
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
@@ -3511,6 +3597,24 @@ __init int intel_pmu_init(void)
pr_cont("Broadwell events, ");
break;
+ case 87: /* Knights Landing Xeon Phi */
+ memcpy(hw_cache_event_ids,
+ slm_hw_cache_event_ids, sizeof(hw_cache_event_ids));
+ memcpy(hw_cache_extra_regs,
+ knl_hw_cache_extra_regs, sizeof(hw_cache_extra_regs));
+ intel_pmu_lbr_init_knl();
+
+ x86_pmu.event_constraints = intel_slm_event_constraints;
+ x86_pmu.pebs_constraints = intel_slm_pebs_event_constraints;
+ x86_pmu.extra_regs = intel_knl_extra_regs;
+
+ /* all extra regs are per-cpu when HT is on */
+ x86_pmu.flags |= PMU_FL_HAS_RSP_1;
+ x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
+
+ pr_cont("Knights Landing events, ");
+ break;
+
case 78: /* 14nm Skylake Mobile */
case 94: /* 14nm Skylake Desktop */
x86_pmu.late_ack = true;
@@ -3521,7 +3625,8 @@ __init int intel_pmu_init(void)
x86_pmu.event_constraints = intel_skl_event_constraints;
x86_pmu.pebs_constraints = intel_skl_pebs_event_constraints;
x86_pmu.extra_regs = intel_skl_extra_regs;
- x86_pmu.pebs_aliases = intel_pebs_aliases_snb;
+ x86_pmu.pebs_aliases = intel_pebs_aliases_skl;
+ x86_pmu.pebs_prec_dist = true;
/* all extra regs are per-cpu when HT is on */
x86_pmu.flags |= PMU_FL_HAS_RSP_1;
x86_pmu.flags |= PMU_FL_NO_HT_SHARING;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_cqm.c b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
index 377e8f8..a316ca9 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_cqm.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_cqm.c
@@ -298,7 +298,7 @@ static bool __match_event(struct perf_event *a, struct perf_event *b)
static inline struct perf_cgroup *event_to_cgroup(struct perf_event *event)
{
if (event->attach_state & PERF_ATTACH_TASK)
- return perf_cgroup_from_task(event->hw.target);
+ return perf_cgroup_from_task(event->hw.target, event->ctx);
return event->cgrp;
}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 5db1c77..10602f0 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -620,6 +620,8 @@ struct event_constraint intel_atom_pebs_event_constraints[] = {
INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
/* INST_RETIRED.ANY_P, inv=1, cmask=16 (cycles:p). */
INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x01),
+ /* Allow all events as PEBS with no flags */
+ INTEL_ALL_EVENT_CONSTRAINT(0, 0x1),
EVENT_CONSTRAINT_END
};
@@ -686,6 +688,8 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */
/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+ /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
INTEL_EXCLEVT_CONSTRAINT(0xd0, 0xf), /* MEM_UOP_RETIRED.* */
INTEL_EXCLEVT_CONSTRAINT(0xd1, 0xf), /* MEM_LOAD_UOPS_RETIRED.* */
INTEL_EXCLEVT_CONSTRAINT(0xd2, 0xf), /* MEM_LOAD_UOPS_LLC_HIT_RETIRED.* */
@@ -700,6 +704,8 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {
INTEL_PLD_CONSTRAINT(0x01cd, 0xf), /* MEM_TRANS_RETIRED.* */
/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+ /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x11d0, 0xf), /* MEM_UOPS_RETIRED.STLB_MISS_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_XLD(0x21d0, 0xf), /* MEM_UOPS_RETIRED.LOCK_LOADS */
@@ -718,9 +724,10 @@ struct event_constraint intel_hsw_pebs_event_constraints[] = {
struct event_constraint intel_skl_pebs_event_constraints[] = {
INTEL_FLAGS_UEVENT_CONSTRAINT(0x1c0, 0x2), /* INST_RETIRED.PREC_DIST */
- INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_NA(0x01c2, 0xf), /* UOPS_RETIRED.ALL */
- /* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
- INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
+ /* INST_RETIRED.PREC_DIST, inv=1, cmask=16 (cycles:ppp). */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c0, 0x2),
+ /* INST_RETIRED.TOTAL_CYCLES_PS (inv=1, cmask=16) (cycles:p). */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x108000c0, 0x0f),
INTEL_PLD_CONSTRAINT(0x1cd, 0xf), /* MEM_TRANS_RETIRED.* */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */
INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */
@@ -1101,6 +1108,13 @@ get_next_pebs_record_by_bit(void *base, void *top, int bit)
void *at;
u64 pebs_status;
+ /*
+ * fmt0 does not have a status bitfield (does not use
+ * perf_record_nhm format)
+ */
+ if (x86_pmu.intel_cap.pebs_format < 1)
+ return base;
+
if (base == NULL)
return NULL;
@@ -1186,7 +1200,7 @@ static void intel_pmu_drain_pebs_core(struct pt_regs *iregs)
if (!event->attr.precise_ip)
return;
- n = (top - at) / x86_pmu.pebs_record_size;
+ n = top - at;
if (n <= 0)
return;
@@ -1230,12 +1244,21 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs)
pebs_status = p->status & cpuc->pebs_enabled;
pebs_status &= (1ULL << x86_pmu.max_pebs_events) - 1;
+ /*
+ * On some CPUs the PEBS status can be zero when PEBS is
+ * racing with clearing of GLOBAL_STATUS.
+ *
+ * Normally we would drop that record, but in the
+ * case when there is only a single active PEBS event
+ * we can assume it's for that event.
+ */
+ if (!pebs_status && cpuc->pebs_enabled &&
+ !(cpuc->pebs_enabled & (cpuc->pebs_enabled-1)))
+ pebs_status = cpuc->pebs_enabled;
+
bit = find_first_bit((unsigned long *)&pebs_status,
x86_pmu.max_pebs_events);
- if (WARN(bit >= x86_pmu.max_pebs_events,
- "PEBS record without PEBS event! status=%Lx pebs_enabled=%Lx active_mask=%Lx",
- (unsigned long long)p->status, (unsigned long long)cpuc->pebs_enabled,
- *(unsigned long long *)cpuc->active_mask))
+ if (bit >= x86_pmu.max_pebs_events)
continue;
/*
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index bfd0b71..653f88d 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -42,6 +42,13 @@ static enum {
#define LBR_FAR_BIT 8 /* do not capture far branches */
#define LBR_CALL_STACK_BIT 9 /* enable call stack */
+/*
+ * Following bit only exists in Linux; we mask it out before writing it to
+ * the actual MSR. But it helps the constraint perf code to understand
+ * that this is a separate configuration.
+ */
+#define LBR_NO_INFO_BIT 63 /* don't read LBR_INFO. */
+
#define LBR_KERNEL (1 << LBR_KERNEL_BIT)
#define LBR_USER (1 << LBR_USER_BIT)
#define LBR_JCC (1 << LBR_JCC_BIT)
@@ -52,6 +59,7 @@ static enum {
#define LBR_IND_JMP (1 << LBR_IND_JMP_BIT)
#define LBR_FAR (1 << LBR_FAR_BIT)
#define LBR_CALL_STACK (1 << LBR_CALL_STACK_BIT)
+#define LBR_NO_INFO (1ULL << LBR_NO_INFO_BIT)
#define LBR_PLM (LBR_KERNEL | LBR_USER)
@@ -152,8 +160,8 @@ static void __intel_pmu_lbr_enable(bool pmi)
* did not change.
*/
if (cpuc->lbr_sel)
- lbr_select = cpuc->lbr_sel->config;
- if (!pmi)
+ lbr_select = cpuc->lbr_sel->config & x86_pmu.lbr_sel_mask;
+ if (!pmi && cpuc->lbr_sel)
wrmsrl(MSR_LBR_SELECT, lbr_select);
rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
@@ -239,7 +247,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
}
mask = x86_pmu.lbr_nr - 1;
- tos = intel_pmu_lbr_tos();
+ tos = task_ctx->tos;
for (i = 0; i < tos; i++) {
lbr_idx = (tos - i) & mask;
wrmsrl(x86_pmu.lbr_from + lbr_idx, task_ctx->lbr_from[i]);
@@ -247,6 +255,7 @@ static void __intel_pmu_lbr_restore(struct x86_perf_task_context *task_ctx)
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
wrmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
}
+ wrmsrl(x86_pmu.lbr_tos, tos);
task_ctx->lbr_stack_state = LBR_NONE;
}
@@ -270,6 +279,7 @@ static void __intel_pmu_lbr_save(struct x86_perf_task_context *task_ctx)
if (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO)
rdmsrl(MSR_LBR_INFO_0 + lbr_idx, task_ctx->lbr_info[i]);
}
+ task_ctx->tos = tos;
task_ctx->lbr_stack_state = LBR_VALID;
}
@@ -420,6 +430,7 @@ static void intel_pmu_lbr_read_32(struct cpu_hw_events *cpuc)
*/
static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
{
+ bool need_info = false;
unsigned long mask = x86_pmu.lbr_nr - 1;
int lbr_format = x86_pmu.intel_cap.lbr_format;
u64 tos = intel_pmu_lbr_tos();
@@ -427,8 +438,11 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
int out = 0;
int num = x86_pmu.lbr_nr;
- if (cpuc->lbr_sel->config & LBR_CALL_STACK)
- num = tos;
+ if (cpuc->lbr_sel) {
+ need_info = !(cpuc->lbr_sel->config & LBR_NO_INFO);
+ if (cpuc->lbr_sel->config & LBR_CALL_STACK)
+ num = tos;
+ }
for (i = 0; i < num; i++) {
unsigned long lbr_idx = (tos - i) & mask;
@@ -440,7 +454,7 @@ static void intel_pmu_lbr_read_64(struct cpu_hw_events *cpuc)
rdmsrl(x86_pmu.lbr_from + lbr_idx, from);
rdmsrl(x86_pmu.lbr_to + lbr_idx, to);
- if (lbr_format == LBR_FORMAT_INFO) {
+ if (lbr_format == LBR_FORMAT_INFO && need_info) {
u64 info;
rdmsrl(MSR_LBR_INFO_0 + lbr_idx, info);
@@ -588,6 +602,7 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
if (v != LBR_IGN)
mask |= v;
}
+
reg = &event->hw.branch_reg;
reg->idx = EXTRA_REG_LBR;
@@ -598,6 +613,11 @@ static int intel_pmu_setup_hw_lbr_filter(struct perf_event *event)
*/
reg->config = mask ^ x86_pmu.lbr_sel_mask;
+ if ((br_type & PERF_SAMPLE_BRANCH_NO_CYCLES) &&
+ (br_type & PERF_SAMPLE_BRANCH_NO_FLAGS) &&
+ (x86_pmu.intel_cap.lbr_format == LBR_FORMAT_INFO))
+ reg->config |= LBR_NO_INFO;
+
return 0;
}
@@ -1026,3 +1046,17 @@ void __init intel_pmu_lbr_init_atom(void)
*/
pr_cont("8-deep LBR, ");
}
+
+/* Knights Landing */
+void intel_pmu_lbr_init_knl(void)
+{
+ x86_pmu.lbr_nr = 8;
+ x86_pmu.lbr_tos = MSR_LBR_TOS;
+ x86_pmu.lbr_from = MSR_LBR_NHM_FROM;
+ x86_pmu.lbr_to = MSR_LBR_NHM_TO;
+
+ x86_pmu.lbr_sel_mask = LBR_SEL_MASK;
+ x86_pmu.lbr_sel_map = snb_lbr_sel_map;
+
+ pr_cont("8-deep LBR, ");
+}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_pt.c b/arch/x86/kernel/cpu/perf_event_intel_pt.c
index 868e119..c0bbd10 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_pt.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_pt.c
@@ -27,6 +27,7 @@
#include <asm/perf_event.h>
#include <asm/insn.h>
#include <asm/io.h>
+#include <asm/intel_pt.h>
#include "perf_event.h"
#include "intel_pt.h"
@@ -1122,6 +1123,14 @@ static int pt_event_init(struct perf_event *event)
return 0;
}
+void cpu_emergency_stop_pt(void)
+{
+ struct pt *pt = this_cpu_ptr(&pt_ctx);
+
+ if (pt->handle.event)
+ pt_event_stop(pt->handle.event, PERF_EF_UPDATE);
+}
+
static __init int pt_init(void)
{
int ret, cpu, prior_warn = 0;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
index 81431c0..24a351a 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
@@ -63,7 +63,7 @@
#define INTEL_RAPL_PP1 0x4 /* pseudo-encoding */
#define NR_RAPL_DOMAINS 0x4
-static const char *rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
+static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
"pp0-core",
"package",
"dram",
@@ -107,19 +107,13 @@ static ssize_t __rapl_##_var##_show(struct kobject *kobj, \
static struct kobj_attribute format_attr_##_var = \
__ATTR(_name, 0444, __rapl_##_var##_show, NULL)
-#define RAPL_EVENT_DESC(_name, _config) \
-{ \
- .attr = __ATTR(_name, 0444, rapl_event_show, NULL), \
- .config = _config, \
-}
-
#define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */
-#define RAPL_EVENT_ATTR_STR(_name, v, str) \
-static struct perf_pmu_events_attr event_attr_##v = { \
- .attr = __ATTR(_name, 0444, rapl_sysfs_show, NULL), \
- .id = 0, \
- .event_str = str, \
+#define RAPL_EVENT_ATTR_STR(_name, v, str) \
+static struct perf_pmu_events_attr event_attr_##v = { \
+ .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \
+ .id = 0, \
+ .event_str = str, \
};
struct rapl_pmu {
@@ -411,19 +405,6 @@ static struct attribute_group rapl_pmu_attr_group = {
.attrs = rapl_pmu_attrs,
};
-static ssize_t rapl_sysfs_show(struct device *dev,
- struct device_attribute *attr,
- char *page)
-{
- struct perf_pmu_events_attr *pmu_attr = \
- container_of(attr, struct perf_pmu_events_attr, attr);
-
- if (pmu_attr->event_str)
- return sprintf(page, "%s", pmu_attr->event_str);
-
- return 0;
-}
-
RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02");
RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03");
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.c b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
index 61215a6..f97f807 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c
@@ -884,6 +884,15 @@ static int uncore_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id
* each box has a different function id.
*/
pmu = &type->pmus[UNCORE_PCI_DEV_IDX(id->driver_data)];
+ /* Knights Landing uses a common PCI device ID for multiple instances of
+ * an uncore PMU device type. There is only one entry per device type in
+ * the knl_uncore_pci_ids table inspite of multiple devices present for
+ * some device types. Hence PCI device idx would be 0 for all devices.
+ * So increment pmu pointer to point to an unused array element.
+ */
+ if (boot_cpu_data.x86_model == 87)
+ while (pmu->func_id >= 0)
+ pmu++;
if (pmu->func_id < 0)
pmu->func_id = pdev->devfn;
else
@@ -966,6 +975,7 @@ static int __init uncore_pci_init(void)
case 63: /* Haswell-EP */
ret = hswep_uncore_pci_init();
break;
+ case 79: /* BDX-EP */
case 86: /* BDX-DE */
ret = bdx_uncore_pci_init();
break;
@@ -982,6 +992,9 @@ static int __init uncore_pci_init(void)
case 61: /* Broadwell */
ret = bdw_uncore_pci_init();
break;
+ case 87: /* Knights Landing */
+ ret = knl_uncore_pci_init();
+ break;
default:
return 0;
}
@@ -1287,9 +1300,13 @@ static int __init uncore_cpu_init(void)
case 63: /* Haswell-EP */
hswep_uncore_cpu_init();
break;
+ case 79: /* BDX-EP */
case 86: /* BDX-DE */
bdx_uncore_cpu_init();
break;
+ case 87: /* Knights Landing */
+ knl_uncore_cpu_init();
+ break;
default:
return 0;
}
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore.h b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
index 2f0a4a9..07aa2d6 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore.h
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.h
@@ -338,6 +338,7 @@ int hsw_uncore_pci_init(void);
int bdw_uncore_pci_init(void);
void snb_uncore_cpu_init(void);
void nhm_uncore_cpu_init(void);
+int snb_pci2phy_map_init(int devid);
/* perf_event_intel_uncore_snbep.c */
int snbep_uncore_pci_init(void);
@@ -348,6 +349,8 @@ int hswep_uncore_pci_init(void);
void hswep_uncore_cpu_init(void);
int bdx_uncore_pci_init(void);
void bdx_uncore_cpu_init(void);
+int knl_uncore_pci_init(void);
+void knl_uncore_cpu_init(void);
/* perf_event_intel_uncore_nhmex.c */
void nhmex_uncore_cpu_init(void);
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
index 8452561..0b93482 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snb.c
@@ -417,7 +417,7 @@ static void snb_uncore_imc_event_del(struct perf_event *event, int flags)
}
}
-static int snb_pci2phy_map_init(int devid)
+int snb_pci2phy_map_init(int devid)
{
struct pci_dev *dev = NULL;
struct pci2phy_map *map;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
index f0f4fcb..33acb88 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
@@ -209,31 +209,98 @@
#define HSWEP_PCU_MSR_PMON_BOX_CTL 0x710
#define HSWEP_PCU_MSR_PMON_BOX_FILTER 0x715
+/* KNL Ubox */
+#define KNL_U_MSR_PMON_RAW_EVENT_MASK \
+ (SNBEP_U_MSR_PMON_RAW_EVENT_MASK | \
+ SNBEP_CBO_PMON_CTL_TID_EN)
+/* KNL CHA */
+#define KNL_CHA_MSR_OFFSET 0xc
+#define KNL_CHA_MSR_PMON_CTL_QOR (1 << 16)
+#define KNL_CHA_MSR_PMON_RAW_EVENT_MASK \
+ (SNBEP_CBO_MSR_PMON_RAW_EVENT_MASK | \
+ KNL_CHA_MSR_PMON_CTL_QOR)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_TID 0x1ff
+#define KNL_CHA_MSR_PMON_BOX_FILTER_STATE (7 << 18)
+#define KNL_CHA_MSR_PMON_BOX_FILTER_OP (0xfffffe2aULL << 32)
+
+/* KNL EDC/MC UCLK */
+#define KNL_UCLK_MSR_PMON_CTR0_LOW 0x400
+#define KNL_UCLK_MSR_PMON_CTL0 0x420
+#define KNL_UCLK_MSR_PMON_BOX_CTL 0x430
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW 0x44c
+#define KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL 0x454
+#define KNL_PMON_FIXED_CTL_EN 0x1
+
+/* KNL EDC */
+#define KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW 0xa00
+#define KNL_EDC0_ECLK_MSR_PMON_CTL0 0xa20
+#define KNL_EDC0_ECLK_MSR_PMON_BOX_CTL 0xa30
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW 0xa3c
+#define KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL 0xa44
+
+/* KNL MC */
+#define KNL_MC0_CH0_MSR_PMON_CTR0_LOW 0xb00
+#define KNL_MC0_CH0_MSR_PMON_CTL0 0xb20
+#define KNL_MC0_CH0_MSR_PMON_BOX_CTL 0xb30
+#define KNL_MC0_CH0_MSR_PMON_FIXED_LOW 0xb3c
+#define KNL_MC0_CH0_MSR_PMON_FIXED_CTL 0xb44
+
+/* KNL IRP */
+#define KNL_IRP_PCI_PMON_BOX_CTL 0xf0
+#define KNL_IRP_PCI_PMON_RAW_EVENT_MASK (SNBEP_PMON_RAW_EVENT_MASK | \
+ KNL_CHA_MSR_PMON_CTL_QOR)
+/* KNL PCU */
+#define KNL_PCU_PMON_CTL_EV_SEL_MASK 0x0000007f
+#define KNL_PCU_PMON_CTL_USE_OCC_CTR (1 << 7)
+#define KNL_PCU_MSR_PMON_CTL_TRESH_MASK 0x3f000000
+#define KNL_PCU_MSR_PMON_RAW_EVENT_MASK \
+ (KNL_PCU_PMON_CTL_EV_SEL_MASK | \
+ KNL_PCU_PMON_CTL_USE_OCC_CTR | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_SEL_MASK | \
+ SNBEP_PMON_CTL_EDGE_DET | \
+ SNBEP_CBO_PMON_CTL_TID_EN | \
+ SNBEP_PMON_CTL_EV_SEL_EXT | \
+ SNBEP_PMON_CTL_INVERT | \
+ KNL_PCU_MSR_PMON_CTL_TRESH_MASK | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_INVERT | \
+ SNBEP_PCU_MSR_PMON_CTL_OCC_EDGE_DET)
DEFINE_UNCORE_FORMAT_ATTR(event, event, "config:0-7");
+DEFINE_UNCORE_FORMAT_ATTR(event2, event, "config:0-6");
DEFINE_UNCORE_FORMAT_ATTR(event_ext, event, "config:0-7,21");
+DEFINE_UNCORE_FORMAT_ATTR(use_occ_ctr, use_occ_ctr, "config:7");
DEFINE_UNCORE_FORMAT_ATTR(umask, umask, "config:8-15");
+DEFINE_UNCORE_FORMAT_ATTR(qor, qor, "config:16");
DEFINE_UNCORE_FORMAT_ATTR(edge, edge, "config:18");
DEFINE_UNCORE_FORMAT_ATTR(tid_en, tid_en, "config:19");
DEFINE_UNCORE_FORMAT_ATTR(inv, inv, "config:23");
DEFINE_UNCORE_FORMAT_ATTR(thresh8, thresh, "config:24-31");
+DEFINE_UNCORE_FORMAT_ATTR(thresh6, thresh, "config:24-29");
DEFINE_UNCORE_FORMAT_ATTR(thresh5, thresh, "config:24-28");
DEFINE_UNCORE_FORMAT_ATTR(occ_sel, occ_sel, "config:14-15");
DEFINE_UNCORE_FORMAT_ATTR(occ_invert, occ_invert, "config:30");
DEFINE_UNCORE_FORMAT_ATTR(occ_edge, occ_edge, "config:14-51");
+DEFINE_UNCORE_FORMAT_ATTR(occ_edge_det, occ_edge_det, "config:31");
DEFINE_UNCORE_FORMAT_ATTR(filter_tid, filter_tid, "config1:0-4");
DEFINE_UNCORE_FORMAT_ATTR(filter_tid2, filter_tid, "config1:0");
DEFINE_UNCORE_FORMAT_ATTR(filter_tid3, filter_tid, "config1:0-5");
+DEFINE_UNCORE_FORMAT_ATTR(filter_tid4, filter_tid, "config1:0-8");
DEFINE_UNCORE_FORMAT_ATTR(filter_cid, filter_cid, "config1:5");
DEFINE_UNCORE_FORMAT_ATTR(filter_link, filter_link, "config1:5-8");
DEFINE_UNCORE_FORMAT_ATTR(filter_link2, filter_link, "config1:6-8");
+DEFINE_UNCORE_FORMAT_ATTR(filter_link3, filter_link, "config1:12");
DEFINE_UNCORE_FORMAT_ATTR(filter_nid, filter_nid, "config1:10-17");
DEFINE_UNCORE_FORMAT_ATTR(filter_nid2, filter_nid, "config1:32-47");
DEFINE_UNCORE_FORMAT_ATTR(filter_state, filter_state, "config1:18-22");
DEFINE_UNCORE_FORMAT_ATTR(filter_state2, filter_state, "config1:17-22");
DEFINE_UNCORE_FORMAT_ATTR(filter_state3, filter_state, "config1:17-23");
+DEFINE_UNCORE_FORMAT_ATTR(filter_state4, filter_state, "config1:18-20");
+DEFINE_UNCORE_FORMAT_ATTR(filter_local, filter_local, "config1:33");
+DEFINE_UNCORE_FORMAT_ATTR(filter_all_op, filter_all_op, "config1:35");
+DEFINE_UNCORE_FORMAT_ATTR(filter_nnm, filter_nnm, "config1:37");
DEFINE_UNCORE_FORMAT_ATTR(filter_opc, filter_opc, "config1:23-31");
DEFINE_UNCORE_FORMAT_ATTR(filter_opc2, filter_opc, "config1:52-60");
+DEFINE_UNCORE_FORMAT_ATTR(filter_opc3, filter_opc, "config1:41-60");
DEFINE_UNCORE_FORMAT_ATTR(filter_nc, filter_nc, "config1:62");
DEFINE_UNCORE_FORMAT_ATTR(filter_c6, filter_c6, "config1:61");
DEFINE_UNCORE_FORMAT_ATTR(filter_isoc, filter_isoc, "config1:63");
@@ -315,8 +382,9 @@ static u64 snbep_uncore_pci_read_counter(struct intel_uncore_box *box, struct pe
static void snbep_uncore_pci_init_box(struct intel_uncore_box *box)
{
struct pci_dev *pdev = box->pci_dev;
+ int box_ctl = uncore_pci_box_ctl(box);
- pci_write_config_dword(pdev, SNBEP_PCI_PMON_BOX_CTL, SNBEP_PMON_BOX_CTL_INT);
+ pci_write_config_dword(pdev, box_ctl, SNBEP_PMON_BOX_CTL_INT);
}
static void snbep_uncore_msr_disable_box(struct intel_uncore_box *box)
@@ -1728,6 +1796,419 @@ int ivbep_uncore_pci_init(void)
}
/* end of IvyTown uncore support */
+/* KNL uncore support */
+static struct attribute *knl_uncore_ubox_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_edge.attr,
+ &format_attr_tid_en.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh5.attr,
+ NULL,
+};
+
+static struct attribute_group knl_uncore_ubox_format_group = {
+ .name = "format",
+ .attrs = knl_uncore_ubox_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_ubox = {
+ .name = "ubox",
+ .num_counters = 2,
+ .num_boxes = 1,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = HSWEP_U_MSR_PMON_CTR0,
+ .event_ctl = HSWEP_U_MSR_PMON_CTL0,
+ .event_mask = KNL_U_MSR_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = HSWEP_U_MSR_PMON_UCLK_FIXED_CTR,
+ .fixed_ctl = HSWEP_U_MSR_PMON_UCLK_FIXED_CTL,
+ .ops = &snbep_uncore_msr_ops,
+ .format_group = &knl_uncore_ubox_format_group,
+};
+
+static struct attribute *knl_uncore_cha_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_qor.attr,
+ &format_attr_edge.attr,
+ &format_attr_tid_en.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh8.attr,
+ &format_attr_filter_tid4.attr,
+ &format_attr_filter_link3.attr,
+ &format_attr_filter_state4.attr,
+ &format_attr_filter_local.attr,
+ &format_attr_filter_all_op.attr,
+ &format_attr_filter_nnm.attr,
+ &format_attr_filter_opc3.attr,
+ &format_attr_filter_nc.attr,
+ &format_attr_filter_isoc.attr,
+ NULL,
+};
+
+static struct attribute_group knl_uncore_cha_format_group = {
+ .name = "format",
+ .attrs = knl_uncore_cha_formats_attr,
+};
+
+static struct event_constraint knl_uncore_cha_constraints[] = {
+ UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
+ UNCORE_EVENT_CONSTRAINT(0x1f, 0x1),
+ UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+ EVENT_CONSTRAINT_END
+};
+
+static struct extra_reg knl_uncore_cha_extra_regs[] = {
+ SNBEP_CBO_EVENT_EXTRA_REG(SNBEP_CBO_PMON_CTL_TID_EN,
+ SNBEP_CBO_PMON_CTL_TID_EN, 0x1),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x3d, 0xff, 0x2),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x35, 0xff, 0x4),
+ SNBEP_CBO_EVENT_EXTRA_REG(0x36, 0xff, 0x4),
+ EVENT_EXTRA_END
+};
+
+static u64 knl_cha_filter_mask(int fields)
+{
+ u64 mask = 0;
+
+ if (fields & 0x1)
+ mask |= KNL_CHA_MSR_PMON_BOX_FILTER_TID;
+ if (fields & 0x2)
+ mask |= KNL_CHA_MSR_PMON_BOX_FILTER_STATE;
+ if (fields & 0x4)
+ mask |= KNL_CHA_MSR_PMON_BOX_FILTER_OP;
+ return mask;
+}
+
+static struct event_constraint *
+knl_cha_get_constraint(struct intel_uncore_box *box, struct perf_event *event)
+{
+ return __snbep_cbox_get_constraint(box, event, knl_cha_filter_mask);
+}
+
+static int knl_cha_hw_config(struct intel_uncore_box *box,
+ struct perf_event *event)
+{
+ struct hw_perf_event_extra *reg1 = &event->hw.extra_reg;
+ struct extra_reg *er;
+ int idx = 0;
+
+ for (er = knl_uncore_cha_extra_regs; er->msr; er++) {
+ if (er->event != (event->hw.config & er->config_mask))
+ continue;
+ idx |= er->idx;
+ }
+
+ if (idx) {
+ reg1->reg = HSWEP_C0_MSR_PMON_BOX_FILTER0 +
+ KNL_CHA_MSR_OFFSET * box->pmu->pmu_idx;
+ reg1->config = event->attr.config1 & knl_cha_filter_mask(idx);
+ reg1->idx = idx;
+ }
+ return 0;
+}
+
+static void hswep_cbox_enable_event(struct intel_uncore_box *box,
+ struct perf_event *event);
+
+static struct intel_uncore_ops knl_uncore_cha_ops = {
+ .init_box = snbep_uncore_msr_init_box,
+ .disable_box = snbep_uncore_msr_disable_box,
+ .enable_box = snbep_uncore_msr_enable_box,
+ .disable_event = snbep_uncore_msr_disable_event,
+ .enable_event = hswep_cbox_enable_event,
+ .read_counter = uncore_msr_read_counter,
+ .hw_config = knl_cha_hw_config,
+ .get_constraint = knl_cha_get_constraint,
+ .put_constraint = snbep_cbox_put_constraint,
+};
+
+static struct intel_uncore_type knl_uncore_cha = {
+ .name = "cha",
+ .num_counters = 4,
+ .num_boxes = 38,
+ .perf_ctr_bits = 48,
+ .event_ctl = HSWEP_C0_MSR_PMON_CTL0,
+ .perf_ctr = HSWEP_C0_MSR_PMON_CTR0,
+ .event_mask = KNL_CHA_MSR_PMON_RAW_EVENT_MASK,
+ .box_ctl = HSWEP_C0_MSR_PMON_BOX_CTL,
+ .msr_offset = KNL_CHA_MSR_OFFSET,
+ .num_shared_regs = 1,
+ .constraints = knl_uncore_cha_constraints,
+ .ops = &knl_uncore_cha_ops,
+ .format_group = &knl_uncore_cha_format_group,
+};
+
+static struct attribute *knl_uncore_pcu_formats_attr[] = {
+ &format_attr_event2.attr,
+ &format_attr_use_occ_ctr.attr,
+ &format_attr_occ_sel.attr,
+ &format_attr_edge.attr,
+ &format_attr_tid_en.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh6.attr,
+ &format_attr_occ_invert.attr,
+ &format_attr_occ_edge_det.attr,
+ NULL,
+};
+
+static struct attribute_group knl_uncore_pcu_format_group = {
+ .name = "format",
+ .attrs = knl_uncore_pcu_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_pcu = {
+ .name = "pcu",
+ .num_counters = 4,
+ .num_boxes = 1,
+ .perf_ctr_bits = 48,
+ .perf_ctr = HSWEP_PCU_MSR_PMON_CTR0,
+ .event_ctl = HSWEP_PCU_MSR_PMON_CTL0,
+ .event_mask = KNL_PCU_MSR_PMON_RAW_EVENT_MASK,
+ .box_ctl = HSWEP_PCU_MSR_PMON_BOX_CTL,
+ .ops = &snbep_uncore_msr_ops,
+ .format_group = &knl_uncore_pcu_format_group,
+};
+
+static struct intel_uncore_type *knl_msr_uncores[] = {
+ &knl_uncore_ubox,
+ &knl_uncore_cha,
+ &knl_uncore_pcu,
+ NULL,
+};
+
+void knl_uncore_cpu_init(void)
+{
+ uncore_msr_uncores = knl_msr_uncores;
+}
+
+static void knl_uncore_imc_enable_box(struct intel_uncore_box *box)
+{
+ struct pci_dev *pdev = box->pci_dev;
+ int box_ctl = uncore_pci_box_ctl(box);
+
+ pci_write_config_dword(pdev, box_ctl, 0);
+}
+
+static void knl_uncore_imc_enable_event(struct intel_uncore_box *box,
+ struct perf_event *event)
+{
+ struct pci_dev *pdev = box->pci_dev;
+ struct hw_perf_event *hwc = &event->hw;
+
+ if ((event->attr.config & SNBEP_PMON_CTL_EV_SEL_MASK)
+ == UNCORE_FIXED_EVENT)
+ pci_write_config_dword(pdev, hwc->config_base,
+ hwc->config | KNL_PMON_FIXED_CTL_EN);
+ else
+ pci_write_config_dword(pdev, hwc->config_base,
+ hwc->config | SNBEP_PMON_CTL_EN);
+}
+
+static struct intel_uncore_ops knl_uncore_imc_ops = {
+ .init_box = snbep_uncore_pci_init_box,
+ .disable_box = snbep_uncore_pci_disable_box,
+ .enable_box = knl_uncore_imc_enable_box,
+ .read_counter = snbep_uncore_pci_read_counter,
+ .enable_event = knl_uncore_imc_enable_event,
+ .disable_event = snbep_uncore_pci_disable_event,
+};
+
+static struct intel_uncore_type knl_uncore_imc_uclk = {
+ .name = "imc_uclk",
+ .num_counters = 4,
+ .num_boxes = 2,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = KNL_UCLK_MSR_PMON_CTR0_LOW,
+ .event_ctl = KNL_UCLK_MSR_PMON_CTL0,
+ .event_mask = SNBEP_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+ .fixed_ctl = KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+ .box_ctl = KNL_UCLK_MSR_PMON_BOX_CTL,
+ .ops = &knl_uncore_imc_ops,
+ .format_group = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_imc_dclk = {
+ .name = "imc",
+ .num_counters = 4,
+ .num_boxes = 6,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = KNL_MC0_CH0_MSR_PMON_CTR0_LOW,
+ .event_ctl = KNL_MC0_CH0_MSR_PMON_CTL0,
+ .event_mask = SNBEP_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = KNL_MC0_CH0_MSR_PMON_FIXED_LOW,
+ .fixed_ctl = KNL_MC0_CH0_MSR_PMON_FIXED_CTL,
+ .box_ctl = KNL_MC0_CH0_MSR_PMON_BOX_CTL,
+ .ops = &knl_uncore_imc_ops,
+ .format_group = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_uclk = {
+ .name = "edc_uclk",
+ .num_counters = 4,
+ .num_boxes = 8,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = KNL_UCLK_MSR_PMON_CTR0_LOW,
+ .event_ctl = KNL_UCLK_MSR_PMON_CTL0,
+ .event_mask = SNBEP_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = KNL_UCLK_MSR_PMON_UCLK_FIXED_LOW,
+ .fixed_ctl = KNL_UCLK_MSR_PMON_UCLK_FIXED_CTL,
+ .box_ctl = KNL_UCLK_MSR_PMON_BOX_CTL,
+ .ops = &knl_uncore_imc_ops,
+ .format_group = &snbep_uncore_format_group,
+};
+
+static struct intel_uncore_type knl_uncore_edc_eclk = {
+ .name = "edc_eclk",
+ .num_counters = 4,
+ .num_boxes = 8,
+ .perf_ctr_bits = 48,
+ .fixed_ctr_bits = 48,
+ .perf_ctr = KNL_EDC0_ECLK_MSR_PMON_CTR0_LOW,
+ .event_ctl = KNL_EDC0_ECLK_MSR_PMON_CTL0,
+ .event_mask = SNBEP_PMON_RAW_EVENT_MASK,
+ .fixed_ctr = KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_LOW,
+ .fixed_ctl = KNL_EDC0_ECLK_MSR_PMON_ECLK_FIXED_CTL,
+ .box_ctl = KNL_EDC0_ECLK_MSR_PMON_BOX_CTL,
+ .ops = &knl_uncore_imc_ops,
+ .format_group = &snbep_uncore_format_group,
+};
+
+static struct event_constraint knl_uncore_m2pcie_constraints[] = {
+ UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+ EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type knl_uncore_m2pcie = {
+ .name = "m2pcie",
+ .num_counters = 4,
+ .num_boxes = 1,
+ .perf_ctr_bits = 48,
+ .constraints = knl_uncore_m2pcie_constraints,
+ SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
+static struct attribute *knl_uncore_irp_formats_attr[] = {
+ &format_attr_event.attr,
+ &format_attr_umask.attr,
+ &format_attr_qor.attr,
+ &format_attr_edge.attr,
+ &format_attr_inv.attr,
+ &format_attr_thresh8.attr,
+ NULL,
+};
+
+static struct attribute_group knl_uncore_irp_format_group = {
+ .name = "format",
+ .attrs = knl_uncore_irp_formats_attr,
+};
+
+static struct intel_uncore_type knl_uncore_irp = {
+ .name = "irp",
+ .num_counters = 2,
+ .num_boxes = 1,
+ .perf_ctr_bits = 48,
+ .perf_ctr = SNBEP_PCI_PMON_CTR0,
+ .event_ctl = SNBEP_PCI_PMON_CTL0,
+ .event_mask = KNL_IRP_PCI_PMON_RAW_EVENT_MASK,
+ .box_ctl = KNL_IRP_PCI_PMON_BOX_CTL,
+ .ops = &snbep_uncore_pci_ops,
+ .format_group = &knl_uncore_irp_format_group,
+};
+
+enum {
+ KNL_PCI_UNCORE_MC_UCLK,
+ KNL_PCI_UNCORE_MC_DCLK,
+ KNL_PCI_UNCORE_EDC_UCLK,
+ KNL_PCI_UNCORE_EDC_ECLK,
+ KNL_PCI_UNCORE_M2PCIE,
+ KNL_PCI_UNCORE_IRP,
+};
+
+static struct intel_uncore_type *knl_pci_uncores[] = {
+ [KNL_PCI_UNCORE_MC_UCLK] = &knl_uncore_imc_uclk,
+ [KNL_PCI_UNCORE_MC_DCLK] = &knl_uncore_imc_dclk,
+ [KNL_PCI_UNCORE_EDC_UCLK] = &knl_uncore_edc_uclk,
+ [KNL_PCI_UNCORE_EDC_ECLK] = &knl_uncore_edc_eclk,
+ [KNL_PCI_UNCORE_M2PCIE] = &knl_uncore_m2pcie,
+ [KNL_PCI_UNCORE_IRP] = &knl_uncore_irp,
+ NULL,
+};
+
+/*
+ * KNL uses a common PCI device ID for multiple instances of an Uncore PMU
+ * device type. prior to KNL, each instance of a PMU device type had a unique
+ * device ID.
+ *
+ * PCI Device ID Uncore PMU Devices
+ * ----------------------------------
+ * 0x7841 MC0 UClk, MC1 UClk
+ * 0x7843 MC0 DClk CH 0, MC0 DClk CH 1, MC0 DClk CH 2,
+ * MC1 DClk CH 0, MC1 DClk CH 1, MC1 DClk CH 2
+ * 0x7833 EDC0 UClk, EDC1 UClk, EDC2 UClk, EDC3 UClk,
+ * EDC4 UClk, EDC5 UClk, EDC6 UClk, EDC7 UClk
+ * 0x7835 EDC0 EClk, EDC1 EClk, EDC2 EClk, EDC3 EClk,
+ * EDC4 EClk, EDC5 EClk, EDC6 EClk, EDC7 EClk
+ * 0x7817 M2PCIe
+ * 0x7814 IRP
+*/
+
+static const struct pci_device_id knl_uncore_pci_ids[] = {
+ { /* MC UClk */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7841),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_UCLK, 0),
+ },
+ { /* MC DClk Channel */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7843),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_MC_DCLK, 0),
+ },
+ { /* EDC UClk */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7833),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_UCLK, 0),
+ },
+ { /* EDC EClk */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7835),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_EDC_ECLK, 0),
+ },
+ { /* M2PCIe */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7817),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_M2PCIE, 0),
+ },
+ { /* IRP */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x7814),
+ .driver_data = UNCORE_PCI_DEV_DATA(KNL_PCI_UNCORE_IRP, 0),
+ },
+ { /* end: all zeroes */ }
+};
+
+static struct pci_driver knl_uncore_pci_driver = {
+ .name = "knl_uncore",
+ .id_table = knl_uncore_pci_ids,
+};
+
+int knl_uncore_pci_init(void)
+{
+ int ret;
+
+ /* All KNL PCI based PMON units are on the same PCI bus except IRP */
+ ret = snb_pci2phy_map_init(0x7814); /* IRP */
+ if (ret)
+ return ret;
+ ret = snb_pci2phy_map_init(0x7817); /* M2PCIe */
+ if (ret)
+ return ret;
+ uncore_pci_uncores = knl_pci_uncores;
+ uncore_pci_driver = &knl_uncore_pci_driver;
+ return 0;
+}
+
+/* end of KNL uncore support */
+
/* Haswell-EP uncore support */
static struct attribute *hswep_uncore_ubox_formats_attr[] = {
&format_attr_event.attr,
@@ -2338,7 +2819,7 @@ int hswep_uncore_pci_init(void)
}
/* end of Haswell-EP uncore support */
-/* BDX-DE uncore support */
+/* BDX uncore support */
static struct intel_uncore_type bdx_uncore_ubox = {
.name = "ubox",
@@ -2360,13 +2841,14 @@ static struct event_constraint bdx_uncore_cbox_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x09, 0x3),
UNCORE_EVENT_CONSTRAINT(0x11, 0x1),
UNCORE_EVENT_CONSTRAINT(0x36, 0x1),
+ UNCORE_EVENT_CONSTRAINT(0x3e, 0x1),
EVENT_CONSTRAINT_END
};
static struct intel_uncore_type bdx_uncore_cbox = {
.name = "cbox",
.num_counters = 4,
- .num_boxes = 8,
+ .num_boxes = 24,
.perf_ctr_bits = 48,
.event_ctl = HSWEP_C0_MSR_PMON_CTL0,
.perf_ctr = HSWEP_C0_MSR_PMON_CTR0,
@@ -2379,9 +2861,24 @@ static struct intel_uncore_type bdx_uncore_cbox = {
.format_group = &hswep_uncore_cbox_format_group,
};
+static struct intel_uncore_type bdx_uncore_sbox = {
+ .name = "sbox",
+ .num_counters = 4,
+ .num_boxes = 4,
+ .perf_ctr_bits = 48,
+ .event_ctl = HSWEP_S0_MSR_PMON_CTL0,
+ .perf_ctr = HSWEP_S0_MSR_PMON_CTR0,
+ .event_mask = HSWEP_S_MSR_PMON_RAW_EVENT_MASK,
+ .box_ctl = HSWEP_S0_MSR_PMON_BOX_CTL,
+ .msr_offset = HSWEP_SBOX_MSR_OFFSET,
+ .ops = &hswep_uncore_sbox_msr_ops,
+ .format_group = &hswep_uncore_sbox_format_group,
+};
+
static struct intel_uncore_type *bdx_msr_uncores[] = {
&bdx_uncore_ubox,
&bdx_uncore_cbox,
+ &bdx_uncore_sbox,
&hswep_uncore_pcu,
NULL,
};
@@ -2396,7 +2893,7 @@ void bdx_uncore_cpu_init(void)
static struct intel_uncore_type bdx_uncore_ha = {
.name = "ha",
.num_counters = 4,
- .num_boxes = 1,
+ .num_boxes = 2,
.perf_ctr_bits = 48,
SNBEP_UNCORE_PCI_COMMON_INIT(),
};
@@ -2404,7 +2901,7 @@ static struct intel_uncore_type bdx_uncore_ha = {
static struct intel_uncore_type bdx_uncore_imc = {
.name = "imc",
.num_counters = 5,
- .num_boxes = 2,
+ .num_boxes = 8,
.perf_ctr_bits = 48,
.fixed_ctr_bits = 48,
.fixed_ctr = SNBEP_MC_CHy_PCI_PMON_FIXED_CTR,
@@ -2424,6 +2921,19 @@ static struct intel_uncore_type bdx_uncore_irp = {
.format_group = &snbep_uncore_format_group,
};
+static struct intel_uncore_type bdx_uncore_qpi = {
+ .name = "qpi",
+ .num_counters = 4,
+ .num_boxes = 3,
+ .perf_ctr_bits = 48,
+ .perf_ctr = SNBEP_PCI_PMON_CTR0,
+ .event_ctl = SNBEP_PCI_PMON_CTL0,
+ .event_mask = SNBEP_QPI_PCI_PMON_RAW_EVENT_MASK,
+ .box_ctl = SNBEP_PCI_PMON_BOX_CTL,
+ .num_shared_regs = 1,
+ .ops = &snbep_uncore_qpi_ops,
+ .format_group = &snbep_uncore_qpi_format_group,
+};
static struct event_constraint bdx_uncore_r2pcie_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
@@ -2432,6 +2942,8 @@ static struct event_constraint bdx_uncore_r2pcie_constraints[] = {
UNCORE_EVENT_CONSTRAINT(0x23, 0x1),
UNCORE_EVENT_CONSTRAINT(0x25, 0x1),
UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
EVENT_CONSTRAINT_END
};
@@ -2445,18 +2957,65 @@ static struct intel_uncore_type bdx_uncore_r2pcie = {
SNBEP_UNCORE_PCI_COMMON_INIT(),
};
+static struct event_constraint bdx_uncore_r3qpi_constraints[] = {
+ UNCORE_EVENT_CONSTRAINT(0x01, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x07, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x08, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x09, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x0a, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x0e, 0x7),
+ UNCORE_EVENT_CONSTRAINT(0x10, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x11, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x13, 0x1),
+ UNCORE_EVENT_CONSTRAINT(0x14, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x15, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x1f, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x20, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x21, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x22, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x23, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x25, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x26, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x28, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x29, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2c, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2d, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2e, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x2f, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x33, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x34, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x36, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x37, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x38, 0x3),
+ UNCORE_EVENT_CONSTRAINT(0x39, 0x3),
+ EVENT_CONSTRAINT_END
+};
+
+static struct intel_uncore_type bdx_uncore_r3qpi = {
+ .name = "r3qpi",
+ .num_counters = 3,
+ .num_boxes = 3,
+ .perf_ctr_bits = 48,
+ .constraints = bdx_uncore_r3qpi_constraints,
+ SNBEP_UNCORE_PCI_COMMON_INIT(),
+};
+
enum {
BDX_PCI_UNCORE_HA,
BDX_PCI_UNCORE_IMC,
BDX_PCI_UNCORE_IRP,
+ BDX_PCI_UNCORE_QPI,
BDX_PCI_UNCORE_R2PCIE,
+ BDX_PCI_UNCORE_R3QPI,
};
static struct intel_uncore_type *bdx_pci_uncores[] = {
[BDX_PCI_UNCORE_HA] = &bdx_uncore_ha,
[BDX_PCI_UNCORE_IMC] = &bdx_uncore_imc,
[BDX_PCI_UNCORE_IRP] = &bdx_uncore_irp,
+ [BDX_PCI_UNCORE_QPI] = &bdx_uncore_qpi,
[BDX_PCI_UNCORE_R2PCIE] = &bdx_uncore_r2pcie,
+ [BDX_PCI_UNCORE_R3QPI] = &bdx_uncore_r3qpi,
NULL,
};
@@ -2465,6 +3024,10 @@ static const struct pci_device_id bdx_uncore_pci_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f30),
.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 0),
},
+ { /* Home Agent 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f38),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_HA, 1),
+ },
{ /* MC0 Channel 0 */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb0),
.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 0),
@@ -2473,14 +3036,74 @@ static const struct pci_device_id bdx_uncore_pci_ids[] = {
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb1),
.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 1),
},
+ { /* MC0 Channel 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb4),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 2),
+ },
+ { /* MC0 Channel 3 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fb5),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 3),
+ },
+ { /* MC1 Channel 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd0),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 4),
+ },
+ { /* MC1 Channel 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd1),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 5),
+ },
+ { /* MC1 Channel 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd4),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 6),
+ },
+ { /* MC1 Channel 3 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6fd5),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IMC, 7),
+ },
{ /* IRP */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f39),
.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_IRP, 0),
},
+ { /* QPI0 Port 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f32),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 0),
+ },
+ { /* QPI0 Port 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f33),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 1),
+ },
+ { /* QPI1 Port 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3a),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_QPI, 2),
+ },
{ /* R2PCIe */
PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f34),
.driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R2PCIE, 0),
},
+ { /* R3QPI0 Link 0 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f36),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 0),
+ },
+ { /* R3QPI0 Link 1 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f37),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 1),
+ },
+ { /* R3QPI1 Link 2 */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f3e),
+ .driver_data = UNCORE_PCI_DEV_DATA(BDX_PCI_UNCORE_R3QPI, 2),
+ },
+ { /* QPI Port 0 filter */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f86),
+ .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 0),
+ },
+ { /* QPI Port 1 filter */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f96),
+ .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 1),
+ },
+ { /* QPI Port 2 filter */
+ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x6f46),
+ .driver_data = UNCORE_PCI_DEV_DATA(UNCORE_EXTRA_PCI_DEV, 2),
+ },
{ /* end: all zeroes */ }
};
@@ -2500,4 +3123,4 @@ int bdx_uncore_pci_init(void)
return 0;
}
-/* end of BDX-DE uncore support */
+/* end of BDX uncore support */
diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c
index 136ac74..819d949 100644
--- a/arch/x86/kernel/cpu/rdrand.c
+++ b/arch/x86/kernel/cpu/rdrand.c
@@ -33,28 +33,27 @@ static int __init x86_rdrand_setup(char *s)
__setup("nordrand", x86_rdrand_setup);
/*
- * Force a reseed cycle; we are architecturally guaranteed a reseed
- * after no more than 512 128-bit chunks of random data. This also
- * acts as a test of the CPU capability.
+ * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation.
+ * Run the instruction a few times as a sanity check.
+ * If it fails, it is simple to disable RDRAND here.
*/
-#define RESEED_LOOP ((512*128)/sizeof(unsigned long))
+#define SANITY_CHECK_LOOPS 8
void x86_init_rdrand(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_ARCH_RANDOM
unsigned long tmp;
- int i, count, ok;
+ int i;
if (!cpu_has(c, X86_FEATURE_RDRAND))
- return; /* Nothing to do */
+ return;
- for (count = i = 0; i < RESEED_LOOP; i++) {
- ok = rdrand_long(&tmp);
- if (ok)
- count++;
+ for (i = 0; i < SANITY_CHECK_LOOPS; i++) {
+ if (!rdrand_long(&tmp)) {
+ clear_cpu_cap(c, X86_FEATURE_RDRAND);
+ printk_once(KERN_WARNING "rdrand: disabled\n");
+ return;
+ }
}
-
- if (count != RESEED_LOOP)
- clear_cpu_cap(c, X86_FEATURE_RDRAND);
#endif
}
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 608fb26..8cb57df 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -31,32 +31,12 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
const struct cpuid_bit *cb;
static const struct cpuid_bit cpuid_bits[] = {
- { X86_FEATURE_DTHERM, CR_EAX, 0, 0x00000006, 0 },
- { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006, 0 },
- { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006, 0 },
- { X86_FEATURE_PLN, CR_EAX, 4, 0x00000006, 0 },
- { X86_FEATURE_PTS, CR_EAX, 6, 0x00000006, 0 },
- { X86_FEATURE_HWP, CR_EAX, 7, 0x00000006, 0 },
- { X86_FEATURE_HWP_NOTIFY, CR_EAX, 8, 0x00000006, 0 },
- { X86_FEATURE_HWP_ACT_WINDOW, CR_EAX, 9, 0x00000006, 0 },
- { X86_FEATURE_HWP_EPP, CR_EAX,10, 0x00000006, 0 },
- { X86_FEATURE_HWP_PKG_REQ, CR_EAX,11, 0x00000006, 0 },
{ X86_FEATURE_INTEL_PT, CR_EBX,25, 0x00000007, 0 },
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
{ X86_FEATURE_CPB, CR_EDX, 9, 0x80000007, 0 },
{ X86_FEATURE_PROC_FEEDBACK, CR_EDX,11, 0x80000007, 0 },
- { X86_FEATURE_NPT, CR_EDX, 0, 0x8000000a, 0 },
- { X86_FEATURE_LBRV, CR_EDX, 1, 0x8000000a, 0 },
- { X86_FEATURE_SVML, CR_EDX, 2, 0x8000000a, 0 },
- { X86_FEATURE_NRIPS, CR_EDX, 3, 0x8000000a, 0 },
- { X86_FEATURE_TSCRATEMSR, CR_EDX, 4, 0x8000000a, 0 },
- { X86_FEATURE_VMCBCLEAN, CR_EDX, 5, 0x8000000a, 0 },
- { X86_FEATURE_FLUSHBYASID, CR_EDX, 6, 0x8000000a, 0 },
- { X86_FEATURE_DECODEASSISTS, CR_EDX, 7, 0x8000000a, 0 },
- { X86_FEATURE_PAUSEFILTER, CR_EDX,10, 0x8000000a, 0 },
- { X86_FEATURE_PFTHRESHOLD, CR_EDX,12, 0x8000000a, 0 },
{ 0, 0, 0, 0, 0 }
};
diff --git a/arch/x86/kernel/cpu/transmeta.c b/arch/x86/kernel/cpu/transmeta.c
index 3fa0e5a..252da7a 100644
--- a/arch/x86/kernel/cpu/transmeta.c
+++ b/arch/x86/kernel/cpu/transmeta.c
@@ -12,7 +12,7 @@ static void early_init_transmeta(struct cpuinfo_x86 *c)
xlvl = cpuid_eax(0x80860000);
if ((xlvl & 0xffff0000) == 0x80860000) {
if (xlvl >= 0x80860001)
- c->x86_capability[2] = cpuid_edx(0x80860001);
+ c->x86_capability[CPUID_8086_0001_EDX] = cpuid_edx(0x80860001);
}
}
@@ -82,7 +82,7 @@ static void init_transmeta(struct cpuinfo_x86 *c)
/* Unhide possibly hidden capability flags */
rdmsr(0x80860004, cap_mask, uk);
wrmsr(0x80860004, ~0, uk);
- c->x86_capability[0] = cpuid_edx(0x00000001);
+ c->x86_capability[CPUID_1_EDX] = cpuid_edx(0x00000001);
wrmsr(0x80860004, cap_mask, uk);
/* All Transmeta CPUs have a constant TSC */
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index bd3507d..2836de3 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -58,28 +58,6 @@ static void cpuid_smp_cpuid(void *cmd_block)
&cmd->eax, &cmd->ebx, &cmd->ecx, &cmd->edx);
}
-static loff_t cpuid_seek(struct file *file, loff_t offset, int orig)
-{
- loff_t ret;
- struct inode *inode = file->f_mapping->host;
-
- mutex_lock(&inode->i_mutex);
- switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- default:
- ret = -EINVAL;
- }
- mutex_unlock(&inode->i_mutex);
- return ret;
-}
-
static ssize_t cpuid_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -132,7 +110,7 @@ static int cpuid_open(struct inode *inode, struct file *file)
*/
static const struct file_operations cpuid_fops = {
.owner = THIS_MODULE,
- .llseek = cpuid_seek,
+ .llseek = no_seek_end_llseek,
.read = cpuid_read,
.open = cpuid_open,
};
diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index 2c1910f..58f3431 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -35,6 +35,7 @@
#include <asm/cpu.h>
#include <asm/reboot.h>
#include <asm/virtext.h>
+#include <asm/intel_pt.h>
/* Alignment required for elf header segment */
#define ELF_CORE_HEADER_ALIGN 4096
@@ -125,6 +126,11 @@ static void kdump_nmi_callback(int cpu, struct pt_regs *regs)
cpu_emergency_vmxoff();
cpu_emergency_svm_disable();
+ /*
+ * Disable Intel PT to stop its logging
+ */
+ cpu_emergency_stop_pt();
+
disable_local_APIC();
}
@@ -169,6 +175,11 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
cpu_emergency_vmxoff();
cpu_emergency_svm_disable();
+ /*
+ * Disable Intel PT to stop its logging
+ */
+ cpu_emergency_stop_pt();
+
#ifdef CONFIG_X86_IO_APIC
/* Prevent crash_kexec() from deadlocking on ioapic_lock. */
ioapic_zap_locks();
diff --git a/arch/x86/kernel/fpu/init.c b/arch/x86/kernel/fpu/init.c
index be39b5f..7b2978a 100644
--- a/arch/x86/kernel/fpu/init.c
+++ b/arch/x86/kernel/fpu/init.c
@@ -12,7 +12,7 @@
*/
static void fpu__init_cpu_ctx_switch(void)
{
- if (!cpu_has_eager_fpu)
+ if (!boot_cpu_has(X86_FEATURE_EAGER_FPU))
stts();
else
clts();
@@ -143,9 +143,18 @@ static void __init fpu__init_system_generic(void)
unsigned int xstate_size;
EXPORT_SYMBOL_GPL(xstate_size);
-/* Enforce that 'MEMBER' is the last field of 'TYPE': */
+/* Get alignment of the TYPE. */
+#define TYPE_ALIGN(TYPE) offsetof(struct { char x; TYPE test; }, test)
+
+/*
+ * Enforce that 'MEMBER' is the last field of 'TYPE'.
+ *
+ * Align the computed size with alignment of the TYPE,
+ * because that's how C aligns structs.
+ */
#define CHECK_MEMBER_AT_END_OF(TYPE, MEMBER) \
- BUILD_BUG_ON(sizeof(TYPE) != offsetofend(TYPE, MEMBER))
+ BUILD_BUG_ON(sizeof(TYPE) != ALIGN(offsetofend(TYPE, MEMBER), \
+ TYPE_ALIGN(TYPE)))
/*
* We append the 'struct fpu' to the task_struct:
@@ -188,7 +197,7 @@ static void __init fpu__init_task_struct_size(void)
*/
static void __init fpu__init_system_xstate_size_legacy(void)
{
- static int on_boot_cpu = 1;
+ static int on_boot_cpu __initdata = 1;
WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0;
@@ -278,7 +287,7 @@ __setup("eagerfpu=", eager_fpu_setup);
*/
static void __init fpu__init_system_ctx_switch(void)
{
- static bool on_boot_cpu = 1;
+ static bool on_boot_cpu __initdata = 1;
WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0;
@@ -287,7 +296,7 @@ static void __init fpu__init_system_ctx_switch(void)
current_thread_info()->status = 0;
/* Auto enable eagerfpu for xsaveopt */
- if (cpu_has_xsaveopt && eagerfpu != DISABLE)
+ if (boot_cpu_has(X86_FEATURE_XSAVEOPT) && eagerfpu != DISABLE)
eagerfpu = ENABLE;
if (xfeatures_mask & XFEATURE_MASK_EAGER) {
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index ef29b74..31c6a60 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -385,20 +385,19 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
*/
void fpu__init_prepare_fx_sw_frame(void)
{
- int fsave_header_size = sizeof(struct fregs_state);
int size = xstate_size + FP_XSTATE_MAGIC2_SIZE;
- if (config_enabled(CONFIG_X86_32))
- size += fsave_header_size;
-
fx_sw_reserved.magic1 = FP_XSTATE_MAGIC1;
fx_sw_reserved.extended_size = size;
fx_sw_reserved.xfeatures = xfeatures_mask;
fx_sw_reserved.xstate_size = xstate_size;
- if (config_enabled(CONFIG_IA32_EMULATION)) {
+ if (config_enabled(CONFIG_IA32_EMULATION) ||
+ config_enabled(CONFIG_X86_32)) {
+ int fsave_header_size = sizeof(struct fregs_state);
+
fx_sw_reserved_ia32 = fx_sw_reserved;
- fx_sw_reserved_ia32.extended_size += fsave_header_size;
+ fx_sw_reserved_ia32.extended_size = size + fsave_header_size;
}
}
diff --git a/arch/x86/kernel/fpu/xstate.c b/arch/x86/kernel/fpu/xstate.c
index 6454f27..40f1002 100644
--- a/arch/x86/kernel/fpu/xstate.c
+++ b/arch/x86/kernel/fpu/xstate.c
@@ -297,7 +297,7 @@ static void __init setup_xstate_comp(void)
*/
static void __init setup_init_fpu_buf(void)
{
- static int on_boot_cpu = 1;
+ static int on_boot_cpu __initdata = 1;
WARN_ON_FPU(!on_boot_cpu);
on_boot_cpu = 0;
@@ -608,7 +608,7 @@ static void fpu__init_disable_system_xstate(void)
void __init fpu__init_system_xstate(void)
{
unsigned int eax, ebx, ecx, edx;
- static int on_boot_cpu = 1;
+ static int on_boot_cpu __initdata = 1;
int err;
WARN_ON_FPU(!on_boot_cpu);
@@ -694,7 +694,6 @@ void *get_xsave_addr(struct xregs_state *xsave, int xstate_feature)
if (!boot_cpu_has(X86_FEATURE_XSAVE))
return NULL;
- xsave = &current->thread.fpu.state.xsave;
/*
* We should not ever be requesting features that we
* have not enabled. Remember that pcntxt_mask is
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 1d40ca8..ffdc0e8 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -65,6 +65,9 @@ startup_64:
* tables and then reload them.
*/
+ /* Sanitize CPU configuration */
+ call verify_cpu
+
/*
* Compute the delta between the address I am compiled to run at and the
* address I am actually running at.
@@ -174,6 +177,9 @@ ENTRY(secondary_startup_64)
* after the boot processor executes this code.
*/
+ /* Sanitize CPU configuration */
+ call verify_cpu
+
movq $(init_level4_pgt - __START_KERNEL_map), %rax
1:
@@ -288,6 +294,8 @@ ENTRY(secondary_startup_64)
pushq %rax # target address in negative space
lretq
+#include "verify_cpu.S"
+
#ifdef CONFIG_HOTPLUG_CPU
/*
* Boot CPU0 entry point. It's called from play_dead(). Everything has been set
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index 50a3fad..2bcfb5f 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -300,6 +300,10 @@ static int arch_build_bp_info(struct perf_event *bp)
return -EINVAL;
if (bp->attr.bp_addr & (bp->attr.bp_len - 1))
return -EINVAL;
+
+ if (!boot_cpu_has(X86_FEATURE_BPEXT))
+ return -EOPNOTSUPP;
+
/*
* It's impossible to use a range breakpoint to fake out
* user vs kernel detection because bp_len - 1 can't
@@ -307,8 +311,6 @@ static int arch_build_bp_info(struct perf_event *bp)
* breakpoints, then we'll have to check for kprobe-blacklisted
* addresses anywhere in the range.
*/
- if (!cpu_has_bpext)
- return -EOPNOTSUPP;
info->mask = bp->attr.bp_len - 1;
info->len = X86_BREAKPOINT_LEN_1;
}
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index 16cb827..be22f5a 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -295,16 +295,11 @@ static void unmask_8259A(void)
raw_spin_unlock_irqrestore(&i8259A_lock, flags);
}
-static void init_8259A(int auto_eoi)
+static int probe_8259A(void)
{
unsigned long flags;
unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
unsigned char new_val;
-
- i8259A_auto_eoi = auto_eoi;
-
- raw_spin_lock_irqsave(&i8259A_lock, flags);
-
/*
* Check to see if we have a PIC.
* Mask all except the cascade and read
@@ -312,16 +307,28 @@ static void init_8259A(int auto_eoi)
* have a PIC, we will read 0xff as opposed to the
* value we wrote.
*/
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
+
outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */
outb(probe_val, PIC_MASTER_IMR);
new_val = inb(PIC_MASTER_IMR);
if (new_val != probe_val) {
printk(KERN_INFO "Using NULL legacy PIC\n");
legacy_pic = &null_legacy_pic;
- raw_spin_unlock_irqrestore(&i8259A_lock, flags);
- return;
}
+ raw_spin_unlock_irqrestore(&i8259A_lock, flags);
+ return nr_legacy_irqs();
+}
+
+static void init_8259A(int auto_eoi)
+{
+ unsigned long flags;
+
+ i8259A_auto_eoi = auto_eoi;
+
+ raw_spin_lock_irqsave(&i8259A_lock, flags);
+
outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */
/*
@@ -379,6 +386,10 @@ static int legacy_pic_irq_pending_noop(unsigned int irq)
{
return 0;
}
+static int legacy_pic_probe(void)
+{
+ return 0;
+}
struct legacy_pic null_legacy_pic = {
.nr_legacy_irqs = 0,
@@ -388,6 +399,7 @@ struct legacy_pic null_legacy_pic = {
.mask_all = legacy_pic_noop,
.restore_mask = legacy_pic_noop,
.init = legacy_pic_int_noop,
+ .probe = legacy_pic_probe,
.irq_pending = legacy_pic_irq_pending_noop,
.make_irq = legacy_pic_uint_noop,
};
@@ -400,6 +412,7 @@ struct legacy_pic default_legacy_pic = {
.mask_all = mask_8259A,
.restore_mask = unmask_8259A,
.init = init_8259A,
+ .probe = probe_8259A,
.irq_pending = i8259A_irq_pending,
.make_irq = make_8259A_irq,
};
diff --git a/arch/x86/kernel/irq_work.c b/arch/x86/kernel/irq_work.c
index dc5fa6a..3512ba6 100644
--- a/arch/x86/kernel/irq_work.c
+++ b/arch/x86/kernel/irq_work.c
@@ -1,7 +1,7 @@
/*
* x86 specific code for irq_work
*
- * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra
*/
#include <linux/kernel.h>
diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c
index 2bd81e3..72cef58 100644
--- a/arch/x86/kernel/kvmclock.c
+++ b/arch/x86/kernel/kvmclock.c
@@ -45,6 +45,11 @@ early_param("no-kvmclock", parse_no_kvmclock);
static struct pvclock_vsyscall_time_info *hv_clock;
static struct pvclock_wall_clock wall_clock;
+struct pvclock_vsyscall_time_info *pvclock_pvti_cpu0_va(void)
+{
+ return hv_clock;
+}
+
/*
* The wallclock is the time of day when we booted. Since then, some time may
* have elapsed since the hypervisor wrote the data. So we try to account for
@@ -305,7 +310,6 @@ int __init kvm_setup_vsyscall_timeinfo(void)
{
#ifdef CONFIG_X86_64
int cpu;
- int ret;
u8 flags;
struct pvclock_vcpu_time_info *vcpu_time;
unsigned int size;
@@ -325,11 +329,6 @@ int __init kvm_setup_vsyscall_timeinfo(void)
return 1;
}
- if ((ret = pvclock_init_vsyscall(hv_clock, size))) {
- put_cpu();
- return ret;
- }
-
put_cpu();
kvm_clock.archdata.vclock_mode = VCLOCK_PVCLOCK;
diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S
index 94ea120..87e1762 100644
--- a/arch/x86/kernel/mcount_64.S
+++ b/arch/x86/kernel/mcount_64.S
@@ -278,6 +278,12 @@ trace:
/* save_mcount_regs fills in first two parameters */
save_mcount_regs
+ /*
+ * When DYNAMIC_FTRACE is not defined, ARCH_SUPPORTS_FTRACE_OPS is not
+ * set (see include/asm/ftrace.h and include/linux/ftrace.h). Only the
+ * ip and parent ip are used and the list function is called when
+ * function tracing is enabled.
+ */
call *ftrace_trace_function
restore_mcount_regs
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index 113e707..64f9616 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -45,28 +45,6 @@
static struct class *msr_class;
-static loff_t msr_seek(struct file *file, loff_t offset, int orig)
-{
- loff_t ret;
- struct inode *inode = file_inode(file);
-
- mutex_lock(&inode->i_mutex);
- switch (orig) {
- case SEEK_SET:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case SEEK_CUR:
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- default:
- ret = -EINVAL;
- }
- mutex_unlock(&inode->i_mutex);
- return ret;
-}
-
static ssize_t msr_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -194,7 +172,7 @@ static int msr_open(struct inode *inode, struct file *file)
*/
static const struct file_operations msr_fops = {
.owner = THIS_MODULE,
- .llseek = msr_seek,
+ .llseek = no_seek_end_llseek,
.read = msr_read,
.write = msr_write,
.open = msr_open,
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 697f90d..8a2cdd7 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -29,6 +29,7 @@
#include <asm/mach_traps.h>
#include <asm/nmi.h>
#include <asm/x86_init.h>
+#include <asm/reboot.h>
#define CREATE_TRACE_POINTS
#include <trace/events/nmi.h>
@@ -231,7 +232,7 @@ pci_serr_error(unsigned char reason, struct pt_regs *regs)
#endif
if (panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
+ nmi_panic(regs, "NMI: Not continuing");
pr_emerg("Dazed and confused, but trying to continue\n");
@@ -255,8 +256,16 @@ io_check_error(unsigned char reason, struct pt_regs *regs)
reason, smp_processor_id());
show_regs(regs);
- if (panic_on_io_nmi)
- panic("NMI IOCK error: Not continuing");
+ if (panic_on_io_nmi) {
+ nmi_panic(regs, "NMI IOCK error: Not continuing");
+
+ /*
+ * If we end up here, it means we have received an NMI while
+ * processing panic(). Simply return without delaying and
+ * re-enabling NMIs.
+ */
+ return;
+ }
/* Re-enable the IOCK line, wait for a few seconds */
reason = (reason & NMI_REASON_CLEAR_MASK) | NMI_REASON_CLEAR_IOCHK;
@@ -297,7 +306,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs)
pr_emerg("Do you have a strange power saving mode enabled?\n");
if (unknown_nmi_panic || panic_on_unrecovered_nmi)
- panic("NMI: Not continuing");
+ nmi_panic(regs, "NMI: Not continuing");
pr_emerg("Dazed and confused, but trying to continue\n");
}
@@ -348,8 +357,19 @@ static void default_do_nmi(struct pt_regs *regs)
return;
}
- /* Non-CPU-specific NMI: NMI sources can be processed on any CPU */
- raw_spin_lock(&nmi_reason_lock);
+ /*
+ * Non-CPU-specific NMI: NMI sources can be processed on any CPU.
+ *
+ * Another CPU may be processing panic routines while holding
+ * nmi_reason_lock. Check if the CPU issued the IPI for crash dumping,
+ * and if so, call its callback directly. If there is no CPU preparing
+ * crash dump, we simply loop here.
+ */
+ while (!raw_spin_trylock(&nmi_reason_lock)) {
+ run_crash_ipi_callback(regs);
+ cpu_relax();
+ }
+
reason = x86_platform.get_nmi_reason();
if (reason & NMI_REASON_MASK) {
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index c2130ae..f08ac28 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -74,16 +74,6 @@ void __init default_banner(void)
/* Undefined instruction for dealing with missing ops pointers. */
static const unsigned char ud2a[] = { 0x0f, 0x0b };
-unsigned paravirt_patch_nop(void)
-{
- return 0;
-}
-
-unsigned paravirt_patch_ignore(unsigned len)
-{
- return len;
-}
-
struct branch {
unsigned char opcode;
u32 delta;
@@ -133,7 +123,6 @@ static void *get_call_destination(u8 type)
.pv_time_ops = pv_time_ops,
.pv_cpu_ops = pv_cpu_ops,
.pv_irq_ops = pv_irq_ops,
- .pv_apic_ops = pv_apic_ops,
.pv_mmu_ops = pv_mmu_ops,
#ifdef CONFIG_PARAVIRT_SPINLOCKS
.pv_lock_ops = pv_lock_ops,
@@ -152,8 +141,7 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
/* If there's no function, patch it with a ud2a (BUG) */
ret = paravirt_patch_insns(insnbuf, len, ud2a, ud2a+sizeof(ud2a));
else if (opfunc == _paravirt_nop)
- /* If the operation is a nop, then nop the callsite */
- ret = paravirt_patch_nop();
+ ret = 0;
/* identity functions just return their single argument */
else if (opfunc == _paravirt_ident_32)
@@ -162,10 +150,6 @@ unsigned paravirt_patch_default(u8 type, u16 clobbers, void *insnbuf,
ret = paravirt_patch_ident_64(insnbuf, len);
else if (type == PARAVIRT_PATCH(pv_cpu_ops.iret) ||
-#ifdef CONFIG_X86_32
- type == PARAVIRT_PATCH(pv_cpu_ops.irq_enable_sysexit) ||
-#endif
- type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret32) ||
type == PARAVIRT_PATCH(pv_cpu_ops.usergs_sysret64))
/* If operation requires a jmp, then jmp */
ret = paravirt_patch_jmp(insnbuf, opfunc, addr, len);
@@ -220,8 +204,6 @@ static u64 native_steal_clock(int cpu)
/* These are in entry.S */
extern void native_iret(void);
-extern void native_irq_enable_sysexit(void);
-extern void native_usergs_sysret32(void);
extern void native_usergs_sysret64(void);
static struct resource reserve_ioports = {
@@ -379,13 +361,7 @@ __visible struct pv_cpu_ops pv_cpu_ops = {
.load_sp0 = native_load_sp0,
-#if defined(CONFIG_X86_32)
- .irq_enable_sysexit = native_irq_enable_sysexit,
-#endif
#ifdef CONFIG_X86_64
-#ifdef CONFIG_IA32_EMULATION
- .usergs_sysret32 = native_usergs_sysret32,
-#endif
.usergs_sysret64 = native_usergs_sysret64,
#endif
.iret = native_iret,
@@ -403,12 +379,6 @@ NOKPROBE_SYMBOL(native_get_debugreg);
NOKPROBE_SYMBOL(native_set_debugreg);
NOKPROBE_SYMBOL(native_load_idt);
-struct pv_apic_ops pv_apic_ops = {
-#ifdef CONFIG_X86_LOCAL_APIC
- .startup_ipi_hook = paravirt_nop,
-#endif
-};
-
#if defined(CONFIG_X86_32) && !defined(CONFIG_X86_PAE)
/* 32-bit pagetable entries */
#define PTE_IDENT __PV_IS_CALLEE_SAVE(_paravirt_ident_32)
@@ -444,9 +414,6 @@ struct pv_mmu_ops pv_mmu_ops = {
.set_pmd = native_set_pmd,
.set_pmd_at = native_set_pmd_at,
.pte_update = paravirt_nop,
- .pte_update_defer = paravirt_nop,
- .pmd_update = paravirt_nop,
- .pmd_update_defer = paravirt_nop,
.ptep_modify_prot_start = __ptep_modify_prot_start,
.ptep_modify_prot_commit = __ptep_modify_prot_commit,
@@ -492,6 +459,5 @@ struct pv_mmu_ops pv_mmu_ops = {
EXPORT_SYMBOL_GPL(pv_time_ops);
EXPORT_SYMBOL (pv_cpu_ops);
EXPORT_SYMBOL (pv_mmu_ops);
-EXPORT_SYMBOL_GPL(pv_apic_ops);
EXPORT_SYMBOL_GPL(pv_info);
EXPORT_SYMBOL (pv_irq_ops);
diff --git a/arch/x86/kernel/paravirt_patch_32.c b/arch/x86/kernel/paravirt_patch_32.c
index c89f50a..158dc06 100644
--- a/arch/x86/kernel/paravirt_patch_32.c
+++ b/arch/x86/kernel/paravirt_patch_32.c
@@ -5,7 +5,6 @@ DEF_NATIVE(pv_irq_ops, irq_enable, "sti");
DEF_NATIVE(pv_irq_ops, restore_fl, "push %eax; popf");
DEF_NATIVE(pv_irq_ops, save_fl, "pushf; pop %eax");
DEF_NATIVE(pv_cpu_ops, iret, "iret");
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "sti; sysexit");
DEF_NATIVE(pv_mmu_ops, read_cr2, "mov %cr2, %eax");
DEF_NATIVE(pv_mmu_ops, write_cr3, "mov %eax, %cr3");
DEF_NATIVE(pv_mmu_ops, read_cr3, "mov %cr3, %eax");
@@ -46,7 +45,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
PATCH_SITE(pv_irq_ops, restore_fl);
PATCH_SITE(pv_irq_ops, save_fl);
PATCH_SITE(pv_cpu_ops, iret);
- PATCH_SITE(pv_cpu_ops, irq_enable_sysexit);
PATCH_SITE(pv_mmu_ops, read_cr2);
PATCH_SITE(pv_mmu_ops, read_cr3);
PATCH_SITE(pv_mmu_ops, write_cr3);
diff --git a/arch/x86/kernel/paravirt_patch_64.c b/arch/x86/kernel/paravirt_patch_64.c
index 8aa0558..e70087a 100644
--- a/arch/x86/kernel/paravirt_patch_64.c
+++ b/arch/x86/kernel/paravirt_patch_64.c
@@ -13,9 +13,7 @@ DEF_NATIVE(pv_mmu_ops, flush_tlb_single, "invlpg (%rdi)");
DEF_NATIVE(pv_cpu_ops, clts, "clts");
DEF_NATIVE(pv_cpu_ops, wbinvd, "wbinvd");
-DEF_NATIVE(pv_cpu_ops, irq_enable_sysexit, "swapgs; sti; sysexit");
DEF_NATIVE(pv_cpu_ops, usergs_sysret64, "swapgs; sysretq");
-DEF_NATIVE(pv_cpu_ops, usergs_sysret32, "swapgs; sysretl");
DEF_NATIVE(pv_cpu_ops, swapgs, "swapgs");
DEF_NATIVE(, mov32, "mov %edi, %eax");
@@ -55,7 +53,6 @@ unsigned native_patch(u8 type, u16 clobbers, void *ibuf,
PATCH_SITE(pv_irq_ops, save_fl);
PATCH_SITE(pv_irq_ops, irq_enable);
PATCH_SITE(pv_irq_ops, irq_disable);
- PATCH_SITE(pv_cpu_ops, usergs_sysret32);
PATCH_SITE(pv_cpu_ops, usergs_sysret64);
PATCH_SITE(pv_cpu_ops, swapgs);
PATCH_SITE(pv_mmu_ops, read_cr2);
diff --git a/arch/x86/kernel/pci-calgary_64.c b/arch/x86/kernel/pci-calgary_64.c
index 0497f71..833b1d3 100644
--- a/arch/x86/kernel/pci-calgary_64.c
+++ b/arch/x86/kernel/pci-calgary_64.c
@@ -180,13 +180,13 @@ static void calioc2_dump_error_regs(struct iommu_table *tbl);
static void calgary_init_bitmap_from_tce_table(struct iommu_table *tbl);
static void get_tce_space_from_tar(void);
-static struct cal_chipset_ops calgary_chip_ops = {
+static const struct cal_chipset_ops calgary_chip_ops = {
.handle_quirks = calgary_handle_quirks,
.tce_cache_blast = calgary_tce_cache_blast,
.dump_error_regs = calgary_dump_error_regs
};
-static struct cal_chipset_ops calioc2_chip_ops = {
+static const struct cal_chipset_ops calioc2_chip_ops = {
.handle_quirks = calioc2_handle_quirks,
.tce_cache_blast = calioc2_tce_cache_blast,
.dump_error_regs = calioc2_dump_error_regs
diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c
index adf0392..7c577a1 100644
--- a/arch/x86/kernel/pci-swiotlb.c
+++ b/arch/x86/kernel/pci-swiotlb.c
@@ -88,7 +88,7 @@ int __init pci_swiotlb_detect_4gb(void)
{
/* don't initialize swiotlb if iommu=off (no_iommu=1) */
#ifdef CONFIG_X86_64
- if (!no_iommu && max_pfn > MAX_DMA32_PFN)
+ if (!no_iommu && max_possible_pfn > MAX_DMA32_PFN)
swiotlb = 1;
#endif
return swiotlb;
diff --git a/arch/x86/kernel/pmem.c b/arch/x86/kernel/pmem.c
index 4f00b63..14415af 100644
--- a/arch/x86/kernel/pmem.c
+++ b/arch/x86/kernel/pmem.c
@@ -4,10 +4,22 @@
*/
#include <linux/platform_device.h>
#include <linux/module.h>
+#include <linux/ioport.h>
+
+static int found(u64 start, u64 end, void *data)
+{
+ return 1;
+}
static __init int register_e820_pmem(void)
{
+ char *pmem = "Persistent Memory (legacy)";
struct platform_device *pdev;
+ int rc;
+
+ rc = walk_iomem_res(pmem, IORESOURCE_MEM, 0, -1, NULL, found);
+ if (rc <= 0)
+ return 0;
/*
* See drivers/nvdimm/e820.c for the implementation, this is
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index e835d26..b9d99e0 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -125,7 +125,7 @@ void release_thread(struct task_struct *dead_task)
if (dead_task->mm->context.ldt) {
pr_warn("WARNING: dead process %s still has LDT? <%p/%d>\n",
dead_task->comm,
- dead_task->mm->context.ldt,
+ dead_task->mm->context.ldt->entries,
dead_task->mm->context.ldt->size);
BUG();
}
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 558f50e..32e9d9c 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -124,21 +124,6 @@ const char *regs_query_register_name(unsigned int offset)
return NULL;
}
-static const int arg_offs_table[] = {
-#ifdef CONFIG_X86_32
- [0] = offsetof(struct pt_regs, ax),
- [1] = offsetof(struct pt_regs, dx),
- [2] = offsetof(struct pt_regs, cx)
-#else /* CONFIG_X86_64 */
- [0] = offsetof(struct pt_regs, di),
- [1] = offsetof(struct pt_regs, si),
- [2] = offsetof(struct pt_regs, dx),
- [3] = offsetof(struct pt_regs, cx),
- [4] = offsetof(struct pt_regs, r8),
- [5] = offsetof(struct pt_regs, r9)
-#endif
-};
-
/*
* does not yet catch signals sent when the child dies.
* in exit.c or in signal.c.
diff --git a/arch/x86/kernel/pvclock.c b/arch/x86/kernel/pvclock.c
index 2f355d2..99bfc02 100644
--- a/arch/x86/kernel/pvclock.c
+++ b/arch/x86/kernel/pvclock.c
@@ -140,27 +140,3 @@ void pvclock_read_wallclock(struct pvclock_wall_clock *wall_clock,
set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
}
-
-#ifdef CONFIG_X86_64
-/*
- * Initialize the generic pvclock vsyscall state. This will allocate
- * a/some page(s) for the per-vcpu pvclock information, set up a
- * fixmap mapping for the page(s)
- */
-
-int __init pvclock_init_vsyscall(struct pvclock_vsyscall_time_info *i,
- int size)
-{
- int idx;
-
- WARN_ON (size != PVCLOCK_VSYSCALL_NR_PAGES*PAGE_SIZE);
-
- for (idx = 0; idx <= (PVCLOCK_FIXMAP_END-PVCLOCK_FIXMAP_BEGIN); idx++) {
- __set_fixmap(PVCLOCK_FIXMAP_BEGIN + idx,
- __pa(i) + (idx*PAGE_SIZE),
- PAGE_KERNEL_VVAR);
- }
-
- return 0;
-}
-#endif
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 02693dd..d64889a 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -718,6 +718,7 @@ static int crashing_cpu;
static nmi_shootdown_cb shootdown_callback;
static atomic_t waiting_for_crash_ipi;
+static int crash_ipi_issued;
static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
{
@@ -780,6 +781,9 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
smp_send_nmi_allbutself();
+ /* Kick CPUs looping in NMI context. */
+ WRITE_ONCE(crash_ipi_issued, 1);
+
msecs = 1000; /* Wait at most a second for the other cpus to stop */
while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
mdelay(1);
@@ -788,9 +792,35 @@ void nmi_shootdown_cpus(nmi_shootdown_cb callback)
/* Leave the nmi callback set */
}
+
+/*
+ * Check if the crash dumping IPI got issued and if so, call its callback
+ * directly. This function is used when we have already been in NMI handler.
+ * It doesn't return.
+ */
+void run_crash_ipi_callback(struct pt_regs *regs)
+{
+ if (crash_ipi_issued)
+ crash_nmi_callback(0, regs);
+}
+
+/* Override the weak function in kernel/panic.c */
+void nmi_panic_self_stop(struct pt_regs *regs)
+{
+ while (1) {
+ /* If no CPU is preparing crash dump, we simply loop here. */
+ run_crash_ipi_callback(regs);
+ cpu_relax();
+ }
+}
+
#else /* !CONFIG_SMP */
void nmi_shootdown_cpus(nmi_shootdown_cb callback)
{
/* No other CPUs to shoot down */
}
+
+void run_crash_ipi_callback(struct pt_regs *regs)
+{
+}
#endif
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index cd96852..4af8d06 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -200,6 +200,9 @@ static __init int add_rtc_cmos(void)
}
#endif
+ if (paravirt_enabled() && !paravirt_has(RTC))
+ return -ENODEV;
+
platform_device_register(&rtc_device);
dev_info(&rtc_device.dev,
"registered platform RTC device (no PNP device found)\n");
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index a1e4da9..d3d80e6 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1048,6 +1048,8 @@ void __init setup_arch(char **cmdline_p)
if (mtrr_trim_uncached_memory(max_pfn))
max_pfn = e820_end_of_ram_pfn();
+ max_possible_pfn = max_pfn;
+
#ifdef CONFIG_X86_32
/* max_low_pfn get updated here */
find_low_pfn_range();
@@ -1188,7 +1190,7 @@ void __init setup_arch(char **cmdline_p)
*/
clone_pgd_range(initial_page_table,
swapper_pg_dir + KERNEL_PGD_BOUNDARY,
- KERNEL_PGD_PTRS);
+ min(KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY));
#endif
tboot_probe();
@@ -1250,8 +1252,6 @@ void __init setup_arch(char **cmdline_p)
if (efi_enabled(EFI_BOOT))
efi_apply_memmap_quirks();
#endif
-
- microcode_init();
}
#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index b7ffb7c..cb6282c 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -690,12 +690,15 @@ handle_signal(struct ksignal *ksig, struct pt_regs *regs)
signal_setup_done(failed, ksig, stepping);
}
-#ifdef CONFIG_X86_32
-#define NR_restart_syscall __NR_restart_syscall
-#else /* !CONFIG_X86_32 */
-#define NR_restart_syscall \
- test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall : __NR_restart_syscall
-#endif /* CONFIG_X86_32 */
+static inline unsigned long get_nr_restart_syscall(const struct pt_regs *regs)
+{
+#if defined(CONFIG_X86_32) || !defined(CONFIG_X86_64)
+ return __NR_restart_syscall;
+#else /* !CONFIG_X86_32 && CONFIG_X86_64 */
+ return test_thread_flag(TIF_IA32) ? __NR_ia32_restart_syscall :
+ __NR_restart_syscall | (regs->orig_ax & __X32_SYSCALL_BIT);
+#endif /* CONFIG_X86_32 || !CONFIG_X86_64 */
+}
/*
* Note that 'init' is a special process: it doesn't get signals it doesn't
@@ -724,7 +727,7 @@ void do_signal(struct pt_regs *regs)
break;
case -ERESTART_RESTARTBLOCK:
- regs->ax = NR_restart_syscall;
+ regs->ax = get_nr_restart_syscall(regs);
regs->ip -= 2;
break;
}
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c
index 12c8286..658777c 100644
--- a/arch/x86/kernel/smp.c
+++ b/arch/x86/kernel/smp.c
@@ -125,12 +125,12 @@ static void native_smp_send_reschedule(int cpu)
WARN_ON(1);
return;
}
- apic->send_IPI_mask(cpumask_of(cpu), RESCHEDULE_VECTOR);
+ apic->send_IPI(cpu, RESCHEDULE_VECTOR);
}
void native_send_call_func_single_ipi(int cpu)
{
- apic->send_IPI_mask(cpumask_of(cpu), CALL_FUNCTION_SINGLE_VECTOR);
+ apic->send_IPI(cpu, CALL_FUNCTION_SINGLE_VECTOR);
}
void native_send_call_func_ipi(const struct cpumask *mask)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 892ee2e5..24d57f7 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -304,7 +304,7 @@ do { \
static bool match_smt(struct cpuinfo_x86 *c, struct cpuinfo_x86 *o)
{
- if (cpu_has_topoext) {
+ if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
int cpu1 = c->cpu_index, cpu2 = o->cpu_index;
if (c->phys_proc_id == o->phys_proc_id &&
@@ -509,7 +509,7 @@ void __inquire_remote_apic(int apicid)
*/
#define UDELAY_10MS_DEFAULT 10000
-static unsigned int init_udelay = INT_MAX;
+static unsigned int init_udelay = UINT_MAX;
static int __init cpu_init_udelay(char *str)
{
@@ -522,14 +522,15 @@ early_param("cpu_init_udelay", cpu_init_udelay);
static void __init smp_quirk_init_udelay(void)
{
/* if cmdline changed it from default, leave it alone */
- if (init_udelay != INT_MAX)
+ if (init_udelay != UINT_MAX)
return;
/* if modern processor, use no delay */
if (((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) && (boot_cpu_data.x86 == 6)) ||
- ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF)))
+ ((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && (boot_cpu_data.x86 >= 0xF))) {
init_udelay = 0;
-
+ return;
+ }
/* else, use legacy delay */
init_udelay = UDELAY_10MS_DEFAULT;
}
@@ -629,13 +630,6 @@ wakeup_secondary_cpu_via_init(int phys_apicid, unsigned long start_eip)
num_starts = 0;
/*
- * Paravirt / VMI wants a startup IPI hook here to set up the
- * target processor state.
- */
- startup_ipi_hook(phys_apicid, (unsigned long) start_secondary,
- stack_start);
-
- /*
* Run STARTUP IPI loop.
*/
pr_debug("#startup loops: %d\n", num_starts);
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index c7c4d9c..3d743da 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -1185,8 +1185,6 @@ void __init tsc_init(void)
u64 lpj;
int cpu;
- x86_init.timers.tsc_pre_init();
-
if (!cpu_has_tsc) {
setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
return;
diff --git a/arch/x86/kernel/verify_cpu.S b/arch/x86/kernel/verify_cpu.S
index b9242ba..4cf401f 100644
--- a/arch/x86/kernel/verify_cpu.S
+++ b/arch/x86/kernel/verify_cpu.S
@@ -34,10 +34,11 @@
#include <asm/msr-index.h>
verify_cpu:
- pushfl # Save caller passed flags
- pushl $0 # Kill any dangerous flags
- popfl
+ pushf # Save caller passed flags
+ push $0 # Kill any dangerous flags
+ popf
+#ifndef __x86_64__
pushfl # standard way to check for cpuid
popl %eax
movl %eax,%ebx
@@ -48,6 +49,7 @@ verify_cpu:
popl %eax
cmpl %eax,%ebx
jz verify_cpu_no_longmode # cpu has no cpuid
+#endif
movl $0x0,%eax # See if cpuid 1 is implemented
cpuid
@@ -130,10 +132,10 @@ verify_cpu_sse_test:
jmp verify_cpu_sse_test # try again
verify_cpu_no_longmode:
- popfl # Restore caller passed flags
+ popf # Restore caller passed flags
movl $1,%eax
ret
verify_cpu_sse_ok:
- popfl # Restore caller passed flags
+ popf # Restore caller passed flags
xorl %eax, %eax
ret
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 5246193..483231e 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -357,8 +357,10 @@ static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus)
tss = &per_cpu(cpu_tss, get_cpu());
/* make room for real-mode segments */
tsk->thread.sp0 += 16;
- if (cpu_has_sep)
+
+ if (static_cpu_has_safe(X86_FEATURE_SEP))
tsk->thread.sysenter_cs = 0;
+
load_sp0(tss, &tsk->thread);
put_cpu();
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index 3839628..dad5fe9 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -68,7 +68,6 @@ struct x86_init_ops x86_init __initdata = {
.timers = {
.setup_percpu_clockev = setup_boot_APIC_clock,
- .tsc_pre_init = x86_init_noop,
.timer_init = hpet_time_init,
.wallclock_init = x86_init_noop,
},
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 06332cb..c8eda14 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -2,6 +2,7 @@
#define ARCH_X86_KVM_CPUID_H
#include "x86.h"
+#include <asm/cpu.h>
int kvm_update_cpuid(struct kvm_vcpu *vcpu);
struct kvm_cpuid_entry2 *kvm_find_cpuid_entry(struct kvm_vcpu *vcpu,
@@ -38,6 +39,14 @@ static inline bool guest_cpuid_has_xsave(struct kvm_vcpu *vcpu)
return best && (best->ecx & bit(X86_FEATURE_XSAVE));
}
+static inline bool guest_cpuid_has_mtrr(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 1, 0);
+ return best && (best->edx & bit(X86_FEATURE_MTRR));
+}
+
static inline bool guest_cpuid_has_tsc_adjust(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best;
@@ -170,4 +179,37 @@ static inline bool guest_cpuid_has_nrips(struct kvm_vcpu *vcpu)
}
#undef BIT_NRIPS
+static inline int guest_cpuid_family(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+ if (!best)
+ return -1;
+
+ return x86_family(best->eax);
+}
+
+static inline int guest_cpuid_model(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+ if (!best)
+ return -1;
+
+ return x86_model(best->eax);
+}
+
+static inline int guest_cpuid_stepping(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *best;
+
+ best = kvm_find_cpuid_entry(vcpu, 0x1, 0);
+ if (!best)
+ return -1;
+
+ return x86_stepping(best->eax);
+}
+
#endif
diff --git a/arch/x86/kvm/hyperv.c b/arch/x86/kvm/hyperv.c
index 62cf8c9..c58ba67 100644
--- a/arch/x86/kvm/hyperv.c
+++ b/arch/x86/kvm/hyperv.c
@@ -23,13 +23,665 @@
#include "x86.h"
#include "lapic.h"
+#include "ioapic.h"
#include "hyperv.h"
#include <linux/kvm_host.h>
+#include <linux/highmem.h>
+#include <asm/apicdef.h>
#include <trace/events/kvm.h>
#include "trace.h"
+static inline u64 synic_read_sint(struct kvm_vcpu_hv_synic *synic, int sint)
+{
+ return atomic64_read(&synic->sint[sint]);
+}
+
+static inline int synic_get_sint_vector(u64 sint_value)
+{
+ if (sint_value & HV_SYNIC_SINT_MASKED)
+ return -1;
+ return sint_value & HV_SYNIC_SINT_VECTOR_MASK;
+}
+
+static bool synic_has_vector_connected(struct kvm_vcpu_hv_synic *synic,
+ int vector)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+ if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+ return true;
+ }
+ return false;
+}
+
+static bool synic_has_vector_auto_eoi(struct kvm_vcpu_hv_synic *synic,
+ int vector)
+{
+ int i;
+ u64 sint_value;
+
+ for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+ sint_value = synic_read_sint(synic, i);
+ if (synic_get_sint_vector(sint_value) == vector &&
+ sint_value & HV_SYNIC_SINT_AUTO_EOI)
+ return true;
+ }
+ return false;
+}
+
+static int synic_set_sint(struct kvm_vcpu_hv_synic *synic, int sint,
+ u64 data, bool host)
+{
+ int vector;
+
+ vector = data & HV_SYNIC_SINT_VECTOR_MASK;
+ if (vector < 16 && !host)
+ return 1;
+ /*
+ * Guest may configure multiple SINTs to use the same vector, so
+ * we maintain a bitmap of vectors handled by synic, and a
+ * bitmap of vectors with auto-eoi behavior. The bitmaps are
+ * updated here, and atomically queried on fast paths.
+ */
+
+ atomic64_set(&synic->sint[sint], data);
+
+ if (synic_has_vector_connected(synic, vector))
+ __set_bit(vector, synic->vec_bitmap);
+ else
+ __clear_bit(vector, synic->vec_bitmap);
+
+ if (synic_has_vector_auto_eoi(synic, vector))
+ __set_bit(vector, synic->auto_eoi_bitmap);
+ else
+ __clear_bit(vector, synic->auto_eoi_bitmap);
+
+ /* Load SynIC vectors into EOI exit bitmap */
+ kvm_make_request(KVM_REQ_SCAN_IOAPIC, synic_to_vcpu(synic));
+ return 0;
+}
+
+static struct kvm_vcpu_hv_synic *synic_get(struct kvm *kvm, u32 vcpu_id)
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_vcpu_hv_synic *synic;
+
+ if (vcpu_id >= atomic_read(&kvm->online_vcpus))
+ return NULL;
+ vcpu = kvm_get_vcpu(kvm, vcpu_id);
+ if (!vcpu)
+ return NULL;
+ synic = vcpu_to_synic(vcpu);
+ return (synic->active) ? synic : NULL;
+}
+
+static void synic_clear_sint_msg_pending(struct kvm_vcpu_hv_synic *synic,
+ u32 sint)
+{
+ struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+ struct page *page;
+ gpa_t gpa;
+ struct hv_message *msg;
+ struct hv_message_page *msg_page;
+
+ gpa = synic->msg_page & PAGE_MASK;
+ page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+ if (is_error_page(page)) {
+ vcpu_err(vcpu, "Hyper-V SynIC can't get msg page, gpa 0x%llx\n",
+ gpa);
+ return;
+ }
+ msg_page = kmap_atomic(page);
+
+ msg = &msg_page->sint_message[sint];
+ msg->header.message_flags.msg_pending = 0;
+
+ kunmap_atomic(msg_page);
+ kvm_release_page_dirty(page);
+ kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+}
+
+static void kvm_hv_notify_acked_sint(struct kvm_vcpu *vcpu, u32 sint)
+{
+ struct kvm *kvm = vcpu->kvm;
+ struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+ struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv_stimer *stimer;
+ int gsi, idx, stimers_pending;
+
+ trace_kvm_hv_notify_acked_sint(vcpu->vcpu_id, sint);
+
+ if (synic->msg_page & HV_SYNIC_SIMP_ENABLE)
+ synic_clear_sint_msg_pending(synic, sint);
+
+ /* Try to deliver pending Hyper-V SynIC timers messages */
+ stimers_pending = 0;
+ for (idx = 0; idx < ARRAY_SIZE(hv_vcpu->stimer); idx++) {
+ stimer = &hv_vcpu->stimer[idx];
+ if (stimer->msg_pending &&
+ (stimer->config & HV_STIMER_ENABLE) &&
+ HV_STIMER_SINT(stimer->config) == sint) {
+ set_bit(stimer->index,
+ hv_vcpu->stimer_pending_bitmap);
+ stimers_pending++;
+ }
+ }
+ if (stimers_pending)
+ kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+
+ idx = srcu_read_lock(&kvm->irq_srcu);
+ gsi = atomic_read(&synic->sint_to_gsi[sint]);
+ if (gsi != -1)
+ kvm_notify_acked_gsi(kvm, gsi);
+ srcu_read_unlock(&kvm->irq_srcu, idx);
+}
+
+static void synic_exit(struct kvm_vcpu_hv_synic *synic, u32 msr)
+{
+ struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+ struct kvm_vcpu_hv *hv_vcpu = &vcpu->arch.hyperv;
+
+ hv_vcpu->exit.type = KVM_EXIT_HYPERV_SYNIC;
+ hv_vcpu->exit.u.synic.msr = msr;
+ hv_vcpu->exit.u.synic.control = synic->control;
+ hv_vcpu->exit.u.synic.evt_page = synic->evt_page;
+ hv_vcpu->exit.u.synic.msg_page = synic->msg_page;
+
+ kvm_make_request(KVM_REQ_HV_EXIT, vcpu);
+}
+
+static int synic_set_msr(struct kvm_vcpu_hv_synic *synic,
+ u32 msr, u64 data, bool host)
+{
+ struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+ int ret;
+
+ if (!synic->active)
+ return 1;
+
+ trace_kvm_hv_synic_set_msr(vcpu->vcpu_id, msr, data, host);
+
+ ret = 0;
+ switch (msr) {
+ case HV_X64_MSR_SCONTROL:
+ synic->control = data;
+ if (!host)
+ synic_exit(synic, msr);
+ break;
+ case HV_X64_MSR_SVERSION:
+ if (!host) {
+ ret = 1;
+ break;
+ }
+ synic->version = data;
+ break;
+ case HV_X64_MSR_SIEFP:
+ if (data & HV_SYNIC_SIEFP_ENABLE)
+ if (kvm_clear_guest(vcpu->kvm,
+ data & PAGE_MASK, PAGE_SIZE)) {
+ ret = 1;
+ break;
+ }
+ synic->evt_page = data;
+ if (!host)
+ synic_exit(synic, msr);
+ break;
+ case HV_X64_MSR_SIMP:
+ if (data & HV_SYNIC_SIMP_ENABLE)
+ if (kvm_clear_guest(vcpu->kvm,
+ data & PAGE_MASK, PAGE_SIZE)) {
+ ret = 1;
+ break;
+ }
+ synic->msg_page = data;
+ if (!host)
+ synic_exit(synic, msr);
+ break;
+ case HV_X64_MSR_EOM: {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+ kvm_hv_notify_acked_sint(vcpu, i);
+ break;
+ }
+ case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+ ret = synic_set_sint(synic, msr - HV_X64_MSR_SINT0, data, host);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ return ret;
+}
+
+static int synic_get_msr(struct kvm_vcpu_hv_synic *synic, u32 msr, u64 *pdata)
+{
+ int ret;
+
+ if (!synic->active)
+ return 1;
+
+ ret = 0;
+ switch (msr) {
+ case HV_X64_MSR_SCONTROL:
+ *pdata = synic->control;
+ break;
+ case HV_X64_MSR_SVERSION:
+ *pdata = synic->version;
+ break;
+ case HV_X64_MSR_SIEFP:
+ *pdata = synic->evt_page;
+ break;
+ case HV_X64_MSR_SIMP:
+ *pdata = synic->msg_page;
+ break;
+ case HV_X64_MSR_EOM:
+ *pdata = 0;
+ break;
+ case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+ *pdata = atomic64_read(&synic->sint[msr - HV_X64_MSR_SINT0]);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+ return ret;
+}
+
+int synic_set_irq(struct kvm_vcpu_hv_synic *synic, u32 sint)
+{
+ struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+ struct kvm_lapic_irq irq;
+ int ret, vector;
+
+ if (sint >= ARRAY_SIZE(synic->sint))
+ return -EINVAL;
+
+ vector = synic_get_sint_vector(synic_read_sint(synic, sint));
+ if (vector < 0)
+ return -ENOENT;
+
+ memset(&irq, 0, sizeof(irq));
+ irq.dest_id = kvm_apic_id(vcpu->arch.apic);
+ irq.dest_mode = APIC_DEST_PHYSICAL;
+ irq.delivery_mode = APIC_DM_FIXED;
+ irq.vector = vector;
+ irq.level = 1;
+
+ ret = kvm_irq_delivery_to_apic(vcpu->kvm, NULL, &irq, NULL);
+ trace_kvm_hv_synic_set_irq(vcpu->vcpu_id, sint, irq.vector, ret);
+ return ret;
+}
+
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint)
+{
+ struct kvm_vcpu_hv_synic *synic;
+
+ synic = synic_get(kvm, vcpu_id);
+ if (!synic)
+ return -EINVAL;
+
+ return synic_set_irq(synic, sint);
+}
+
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector)
+{
+ struct kvm_vcpu_hv_synic *synic = vcpu_to_synic(vcpu);
+ int i;
+
+ trace_kvm_hv_synic_send_eoi(vcpu->vcpu_id, vector);
+
+ for (i = 0; i < ARRAY_SIZE(synic->sint); i++)
+ if (synic_get_sint_vector(synic_read_sint(synic, i)) == vector)
+ kvm_hv_notify_acked_sint(vcpu, i);
+}
+
+static int kvm_hv_set_sint_gsi(struct kvm *kvm, u32 vcpu_id, u32 sint, int gsi)
+{
+ struct kvm_vcpu_hv_synic *synic;
+
+ synic = synic_get(kvm, vcpu_id);
+ if (!synic)
+ return -EINVAL;
+
+ if (sint >= ARRAY_SIZE(synic->sint_to_gsi))
+ return -EINVAL;
+
+ atomic_set(&synic->sint_to_gsi[sint], gsi);
+ return 0;
+}
+
+void kvm_hv_irq_routing_update(struct kvm *kvm)
+{
+ struct kvm_irq_routing_table *irq_rt;
+ struct kvm_kernel_irq_routing_entry *e;
+ u32 gsi;
+
+ irq_rt = srcu_dereference_check(kvm->irq_routing, &kvm->irq_srcu,
+ lockdep_is_held(&kvm->irq_lock));
+
+ for (gsi = 0; gsi < irq_rt->nr_rt_entries; gsi++) {
+ hlist_for_each_entry(e, &irq_rt->map[gsi], link) {
+ if (e->type == KVM_IRQ_ROUTING_HV_SINT)
+ kvm_hv_set_sint_gsi(kvm, e->hv_sint.vcpu,
+ e->hv_sint.sint, gsi);
+ }
+ }
+}
+
+static void synic_init(struct kvm_vcpu_hv_synic *synic)
+{
+ int i;
+
+ memset(synic, 0, sizeof(*synic));
+ synic->version = HV_SYNIC_VERSION_1;
+ for (i = 0; i < ARRAY_SIZE(synic->sint); i++) {
+ atomic64_set(&synic->sint[i], HV_SYNIC_SINT_MASKED);
+ atomic_set(&synic->sint_to_gsi[i], -1);
+ }
+}
+
+static u64 get_time_ref_counter(struct kvm *kvm)
+{
+ return div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+}
+
+static void stimer_mark_pending(struct kvm_vcpu_hv_stimer *stimer,
+ bool vcpu_kick)
+{
+ struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+ set_bit(stimer->index,
+ vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ kvm_make_request(KVM_REQ_HV_STIMER, vcpu);
+ if (vcpu_kick)
+ kvm_vcpu_kick(vcpu);
+}
+
+static void stimer_cleanup(struct kvm_vcpu_hv_stimer *stimer)
+{
+ struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+
+ trace_kvm_hv_stimer_cleanup(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index);
+
+ hrtimer_cancel(&stimer->timer);
+ clear_bit(stimer->index,
+ vcpu_to_hv_vcpu(vcpu)->stimer_pending_bitmap);
+ stimer->msg_pending = false;
+ stimer->exp_time = 0;
+}
+
+static enum hrtimer_restart stimer_timer_callback(struct hrtimer *timer)
+{
+ struct kvm_vcpu_hv_stimer *stimer;
+
+ stimer = container_of(timer, struct kvm_vcpu_hv_stimer, timer);
+ trace_kvm_hv_stimer_callback(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index);
+ stimer_mark_pending(stimer, true);
+
+ return HRTIMER_NORESTART;
+}
+
+/*
+ * stimer_start() assumptions:
+ * a) stimer->count is not equal to 0
+ * b) stimer->config has HV_STIMER_ENABLE flag
+ */
+static int stimer_start(struct kvm_vcpu_hv_stimer *stimer)
+{
+ u64 time_now;
+ ktime_t ktime_now;
+
+ time_now = get_time_ref_counter(stimer_to_vcpu(stimer)->kvm);
+ ktime_now = ktime_get();
+
+ if (stimer->config & HV_STIMER_PERIODIC) {
+ if (stimer->exp_time) {
+ if (time_now >= stimer->exp_time) {
+ u64 remainder;
+
+ div64_u64_rem(time_now - stimer->exp_time,
+ stimer->count, &remainder);
+ stimer->exp_time =
+ time_now + (stimer->count - remainder);
+ }
+ } else
+ stimer->exp_time = time_now + stimer->count;
+
+ trace_kvm_hv_stimer_start_periodic(
+ stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index,
+ time_now, stimer->exp_time);
+
+ hrtimer_start(&stimer->timer,
+ ktime_add_ns(ktime_now,
+ 100 * (stimer->exp_time - time_now)),
+ HRTIMER_MODE_ABS);
+ return 0;
+ }
+ stimer->exp_time = stimer->count;
+ if (time_now >= stimer->count) {
+ /*
+ * Expire timer according to Hypervisor Top-Level Functional
+ * specification v4(15.3.1):
+ * "If a one shot is enabled and the specified count is in
+ * the past, it will expire immediately."
+ */
+ stimer_mark_pending(stimer, false);
+ return 0;
+ }
+
+ trace_kvm_hv_stimer_start_one_shot(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index,
+ time_now, stimer->count);
+
+ hrtimer_start(&stimer->timer,
+ ktime_add_ns(ktime_now, 100 * (stimer->count - time_now)),
+ HRTIMER_MODE_ABS);
+ return 0;
+}
+
+static int stimer_set_config(struct kvm_vcpu_hv_stimer *stimer, u64 config,
+ bool host)
+{
+ trace_kvm_hv_stimer_set_config(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index, config, host);
+
+ stimer_cleanup(stimer);
+ if ((stimer->config & HV_STIMER_ENABLE) && HV_STIMER_SINT(config) == 0)
+ config &= ~HV_STIMER_ENABLE;
+ stimer->config = config;
+ stimer_mark_pending(stimer, false);
+ return 0;
+}
+
+static int stimer_set_count(struct kvm_vcpu_hv_stimer *stimer, u64 count,
+ bool host)
+{
+ trace_kvm_hv_stimer_set_count(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index, count, host);
+
+ stimer_cleanup(stimer);
+ stimer->count = count;
+ if (stimer->count == 0)
+ stimer->config &= ~HV_STIMER_ENABLE;
+ else if (stimer->config & HV_STIMER_AUTOENABLE)
+ stimer->config |= HV_STIMER_ENABLE;
+ stimer_mark_pending(stimer, false);
+ return 0;
+}
+
+static int stimer_get_config(struct kvm_vcpu_hv_stimer *stimer, u64 *pconfig)
+{
+ *pconfig = stimer->config;
+ return 0;
+}
+
+static int stimer_get_count(struct kvm_vcpu_hv_stimer *stimer, u64 *pcount)
+{
+ *pcount = stimer->count;
+ return 0;
+}
+
+static int synic_deliver_msg(struct kvm_vcpu_hv_synic *synic, u32 sint,
+ struct hv_message *src_msg)
+{
+ struct kvm_vcpu *vcpu = synic_to_vcpu(synic);
+ struct page *page;
+ gpa_t gpa;
+ struct hv_message *dst_msg;
+ int r;
+ struct hv_message_page *msg_page;
+
+ if (!(synic->msg_page & HV_SYNIC_SIMP_ENABLE))
+ return -ENOENT;
+
+ gpa = synic->msg_page & PAGE_MASK;
+ page = kvm_vcpu_gfn_to_page(vcpu, gpa >> PAGE_SHIFT);
+ if (is_error_page(page))
+ return -EFAULT;
+
+ msg_page = kmap_atomic(page);
+ dst_msg = &msg_page->sint_message[sint];
+ if (sync_cmpxchg(&dst_msg->header.message_type, HVMSG_NONE,
+ src_msg->header.message_type) != HVMSG_NONE) {
+ dst_msg->header.message_flags.msg_pending = 1;
+ r = -EAGAIN;
+ } else {
+ memcpy(&dst_msg->u.payload, &src_msg->u.payload,
+ src_msg->header.payload_size);
+ dst_msg->header.message_type = src_msg->header.message_type;
+ dst_msg->header.payload_size = src_msg->header.payload_size;
+ r = synic_set_irq(synic, sint);
+ if (r >= 1)
+ r = 0;
+ else if (r == 0)
+ r = -EFAULT;
+ }
+ kunmap_atomic(msg_page);
+ kvm_release_page_dirty(page);
+ kvm_vcpu_mark_page_dirty(vcpu, gpa >> PAGE_SHIFT);
+ return r;
+}
+
+static int stimer_send_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+ struct kvm_vcpu *vcpu = stimer_to_vcpu(stimer);
+ struct hv_message *msg = &stimer->msg;
+ struct hv_timer_message_payload *payload =
+ (struct hv_timer_message_payload *)&msg->u.payload;
+
+ payload->expiration_time = stimer->exp_time;
+ payload->delivery_time = get_time_ref_counter(vcpu->kvm);
+ return synic_deliver_msg(vcpu_to_synic(vcpu),
+ HV_STIMER_SINT(stimer->config), msg);
+}
+
+static void stimer_expiration(struct kvm_vcpu_hv_stimer *stimer)
+{
+ int r;
+
+ stimer->msg_pending = true;
+ r = stimer_send_msg(stimer);
+ trace_kvm_hv_stimer_expiration(stimer_to_vcpu(stimer)->vcpu_id,
+ stimer->index, r);
+ if (!r) {
+ stimer->msg_pending = false;
+ if (!(stimer->config & HV_STIMER_PERIODIC))
+ stimer->config &= ~HV_STIMER_ENABLE;
+ }
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+ struct kvm_vcpu_hv_stimer *stimer;
+ u64 time_now, exp_time;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+ if (test_and_clear_bit(i, hv_vcpu->stimer_pending_bitmap)) {
+ stimer = &hv_vcpu->stimer[i];
+ if (stimer->config & HV_STIMER_ENABLE) {
+ exp_time = stimer->exp_time;
+
+ if (exp_time) {
+ time_now =
+ get_time_ref_counter(vcpu->kvm);
+ if (time_now >= exp_time)
+ stimer_expiration(stimer);
+ }
+
+ if ((stimer->config & HV_STIMER_ENABLE) &&
+ stimer->count)
+ stimer_start(stimer);
+ else
+ stimer_cleanup(stimer);
+ }
+ }
+}
+
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+ stimer_cleanup(&hv_vcpu->stimer[i]);
+}
+
+static void stimer_prepare_msg(struct kvm_vcpu_hv_stimer *stimer)
+{
+ struct hv_message *msg = &stimer->msg;
+ struct hv_timer_message_payload *payload =
+ (struct hv_timer_message_payload *)&msg->u.payload;
+
+ memset(&msg->header, 0, sizeof(msg->header));
+ msg->header.message_type = HVMSG_TIMER_EXPIRED;
+ msg->header.payload_size = sizeof(*payload);
+
+ payload->timer_index = stimer->index;
+ payload->expiration_time = 0;
+ payload->delivery_time = 0;
+}
+
+static void stimer_init(struct kvm_vcpu_hv_stimer *stimer, int timer_index)
+{
+ memset(stimer, 0, sizeof(*stimer));
+ stimer->index = timer_index;
+ hrtimer_init(&stimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ stimer->timer.function = stimer_timer_callback;
+ stimer_prepare_msg(stimer);
+}
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu)
+{
+ struct kvm_vcpu_hv *hv_vcpu = vcpu_to_hv_vcpu(vcpu);
+ int i;
+
+ synic_init(&hv_vcpu->synic);
+
+ bitmap_zero(hv_vcpu->stimer_pending_bitmap, HV_SYNIC_STIMER_COUNT);
+ for (i = 0; i < ARRAY_SIZE(hv_vcpu->stimer); i++)
+ stimer_init(&hv_vcpu->stimer[i], i);
+}
+
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu)
+{
+ /*
+ * Hyper-V SynIC auto EOI SINT's are
+ * not compatible with APICV, so deactivate APICV
+ */
+ kvm_vcpu_deactivate_apicv(vcpu);
+ vcpu_to_synic(vcpu)->active = true;
+ return 0;
+}
+
static bool kvm_hv_msr_partition_wide(u32 msr)
{
bool r = false;
@@ -226,6 +878,31 @@ static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host)
return 1;
hv->runtime_offset = data - current_task_runtime_100ns();
break;
+ case HV_X64_MSR_SCONTROL:
+ case HV_X64_MSR_SVERSION:
+ case HV_X64_MSR_SIEFP:
+ case HV_X64_MSR_SIMP:
+ case HV_X64_MSR_EOM:
+ case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+ return synic_set_msr(vcpu_to_synic(vcpu), msr, data, host);
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER3_CONFIG: {
+ int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+ return stimer_set_config(vcpu_to_stimer(vcpu, timer_index),
+ data, host);
+ }
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_COUNT: {
+ int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+ return stimer_set_count(vcpu_to_stimer(vcpu, timer_index),
+ data, host);
+ }
default:
vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n",
msr, data);
@@ -248,11 +925,9 @@ static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case HV_X64_MSR_HYPERCALL:
data = hv->hv_hypercall;
break;
- case HV_X64_MSR_TIME_REF_COUNT: {
- data =
- div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100);
+ case HV_X64_MSR_TIME_REF_COUNT:
+ data = get_time_ref_counter(kvm);
break;
- }
case HV_X64_MSR_REFERENCE_TSC:
data = hv->hv_tsc_page;
break;
@@ -304,6 +979,31 @@ static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
case HV_X64_MSR_VP_RUNTIME:
data = current_task_runtime_100ns() + hv->runtime_offset;
break;
+ case HV_X64_MSR_SCONTROL:
+ case HV_X64_MSR_SVERSION:
+ case HV_X64_MSR_SIEFP:
+ case HV_X64_MSR_SIMP:
+ case HV_X64_MSR_EOM:
+ case HV_X64_MSR_SINT0 ... HV_X64_MSR_SINT15:
+ return synic_get_msr(vcpu_to_synic(vcpu), msr, pdata);
+ case HV_X64_MSR_STIMER0_CONFIG:
+ case HV_X64_MSR_STIMER1_CONFIG:
+ case HV_X64_MSR_STIMER2_CONFIG:
+ case HV_X64_MSR_STIMER3_CONFIG: {
+ int timer_index = (msr - HV_X64_MSR_STIMER0_CONFIG)/2;
+
+ return stimer_get_config(vcpu_to_stimer(vcpu, timer_index),
+ pdata);
+ }
+ case HV_X64_MSR_STIMER0_COUNT:
+ case HV_X64_MSR_STIMER1_COUNT:
+ case HV_X64_MSR_STIMER2_COUNT:
+ case HV_X64_MSR_STIMER3_COUNT: {
+ int timer_index = (msr - HV_X64_MSR_STIMER0_COUNT)/2;
+
+ return stimer_get_count(vcpu_to_stimer(vcpu, timer_index),
+ pdata);
+ }
default:
vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr);
return 1;
diff --git a/arch/x86/kvm/hyperv.h b/arch/x86/kvm/hyperv.h
index c7bce55..60eccd4 100644
--- a/arch/x86/kvm/hyperv.h
+++ b/arch/x86/kvm/hyperv.h
@@ -24,9 +24,64 @@
#ifndef __ARCH_X86_KVM_HYPERV_H__
#define __ARCH_X86_KVM_HYPERV_H__
+static inline struct kvm_vcpu_hv *vcpu_to_hv_vcpu(struct kvm_vcpu *vcpu)
+{
+ return &vcpu->arch.hyperv;
+}
+
+static inline struct kvm_vcpu *hv_vcpu_to_vcpu(struct kvm_vcpu_hv *hv_vcpu)
+{
+ struct kvm_vcpu_arch *arch;
+
+ arch = container_of(hv_vcpu, struct kvm_vcpu_arch, hyperv);
+ return container_of(arch, struct kvm_vcpu, arch);
+}
+
+static inline struct kvm_vcpu_hv_synic *vcpu_to_synic(struct kvm_vcpu *vcpu)
+{
+ return &vcpu->arch.hyperv.synic;
+}
+
+static inline struct kvm_vcpu *synic_to_vcpu(struct kvm_vcpu_hv_synic *synic)
+{
+ return hv_vcpu_to_vcpu(container_of(synic, struct kvm_vcpu_hv, synic));
+}
+
int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host);
int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata);
+
bool kvm_hv_hypercall_enabled(struct kvm *kvm);
int kvm_hv_hypercall(struct kvm_vcpu *vcpu);
+void kvm_hv_irq_routing_update(struct kvm *kvm);
+int kvm_hv_synic_set_irq(struct kvm *kvm, u32 vcpu_id, u32 sint);
+void kvm_hv_synic_send_eoi(struct kvm_vcpu *vcpu, int vector);
+int kvm_hv_activate_synic(struct kvm_vcpu *vcpu);
+
+void kvm_hv_vcpu_init(struct kvm_vcpu *vcpu);
+void kvm_hv_vcpu_uninit(struct kvm_vcpu *vcpu);
+
+static inline struct kvm_vcpu_hv_stimer *vcpu_to_stimer(struct kvm_vcpu *vcpu,
+ int timer_index)
+{
+ return &vcpu_to_hv_vcpu(vcpu)->stimer[timer_index];
+}
+
+static inline struct kvm_vcpu *stimer_to_vcpu(struct kvm_vcpu_hv_stimer *stimer)
+{
+ struct kvm_vcpu_hv *hv_vcpu;
+
+ hv_vcpu = container_of(stimer - stimer->index, struct kvm_vcpu_hv,
+ stimer[0]);
+ return hv_vcpu_to_vcpu(hv_vcpu);
+}
+
+static inline bool kvm_hv_has_stimer_pending(struct kvm_vcpu *vcpu)
+{
+ return !bitmap_empty(vcpu->arch.hyperv.stimer_pending_bitmap,
+ HV_SYNIC_STIMER_COUNT);
+}
+
+void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
+
#endif
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 08116ff..b0ea42b 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -420,6 +420,7 @@ void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val, int hpet_legacy_s
u8 saved_mode;
if (hpet_legacy_start) {
/* save existing mode for later reenablement */
+ WARN_ON(channel != 0);
saved_mode = kvm->arch.vpit->pit_state.channels[0].mode;
kvm->arch.vpit->pit_state.channels[0].mode = 0xff; /* disable timer */
pit_load_count(kvm, channel, val);
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 88d0a92..1facfd6 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -233,7 +233,7 @@ static void kvm_ioapic_inject_all(struct kvm_ioapic *ioapic, unsigned long irr)
}
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
{
struct kvm_ioapic *ioapic = vcpu->kvm->arch.vioapic;
union kvm_ioapic_redirect_entry *e;
@@ -250,7 +250,7 @@ void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
(e->fields.trig_mode == IOAPIC_EDGE_TRIG &&
kvm_apic_pending_eoi(vcpu, e->fields.vector)))
__set_bit(e->fields.vector,
- (unsigned long *)eoi_exit_bitmap);
+ ioapic_handled_vectors);
}
}
spin_unlock(&ioapic->lock);
diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
index 084617d..2d16dc2 100644
--- a/arch/x86/kvm/ioapic.h
+++ b/arch/x86/kvm/ioapic.h
@@ -121,7 +121,8 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
struct kvm_lapic_irq *irq, unsigned long *dest_map);
int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state);
-void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap);
-
+void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu,
+ ulong *ioapic_handled_vectors);
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+ ulong *ioapic_handled_vectors);
#endif
diff --git a/arch/x86/kvm/irq.c b/arch/x86/kvm/irq.c
index 097060e..3982b47 100644
--- a/arch/x86/kvm/irq.c
+++ b/arch/x86/kvm/irq.c
@@ -76,7 +76,7 @@ int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v)
if (kvm_cpu_has_extint(v))
return 1;
- if (kvm_vcpu_apic_vid_enabled(v))
+ if (kvm_vcpu_apicv_active(v))
return 0;
return kvm_apic_has_interrupt(v) != -1; /* LAPIC */
diff --git a/arch/x86/kvm/irq_comm.c b/arch/x86/kvm/irq_comm.c
index 84b96d3..8fc89ef 100644
--- a/arch/x86/kvm/irq_comm.c
+++ b/arch/x86/kvm/irq_comm.c
@@ -33,6 +33,8 @@
#include "lapic.h"
+#include "hyperv.h"
+
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int irq_source_id, int level,
bool line_status)
@@ -219,6 +221,16 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
srcu_read_unlock(&kvm->irq_srcu, idx);
}
+static int kvm_hv_set_sint(struct kvm_kernel_irq_routing_entry *e,
+ struct kvm *kvm, int irq_source_id, int level,
+ bool line_status)
+{
+ if (!level)
+ return -1;
+
+ return kvm_hv_synic_set_irq(kvm, e->hv_sint.vcpu, e->hv_sint.sint);
+}
+
int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
const struct kvm_irq_routing_entry *ue)
{
@@ -257,6 +269,11 @@ int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
e->msi.address_hi = ue->u.msi.address_hi;
e->msi.data = ue->u.msi.data;
break;
+ case KVM_IRQ_ROUTING_HV_SINT:
+ e->set = kvm_hv_set_sint;
+ e->hv_sint.vcpu = ue->u.hv_sint.vcpu;
+ e->hv_sint.sint = ue->u.hv_sint.sint;
+ break;
default:
goto out;
}
@@ -332,14 +349,15 @@ int kvm_setup_empty_irq_routing(struct kvm *kvm)
return kvm_set_irq_routing(kvm, empty_routing, 0, 0);
}
-void kvm_arch_irq_routing_update(struct kvm *kvm)
+void kvm_arch_post_irq_routing_update(struct kvm *kvm)
{
if (ioapic_in_kernel(kvm) || !irqchip_in_kernel(kvm))
return;
kvm_make_scan_ioapic_request(kvm);
}
-void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
+void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu,
+ ulong *ioapic_handled_vectors)
{
struct kvm *kvm = vcpu->kvm;
struct kvm_kernel_irq_routing_entry *entry;
@@ -369,9 +387,26 @@ void kvm_scan_ioapic_routes(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
u32 vector = entry->msi.data & 0xff;
__set_bit(vector,
- (unsigned long *) eoi_exit_bitmap);
+ ioapic_handled_vectors);
}
}
}
srcu_read_unlock(&kvm->irq_srcu, idx);
}
+
+int kvm_arch_set_irq(struct kvm_kernel_irq_routing_entry *irq, struct kvm *kvm,
+ int irq_source_id, int level, bool line_status)
+{
+ switch (irq->type) {
+ case KVM_IRQ_ROUTING_HV_SINT:
+ return kvm_hv_set_sint(irq, kvm, irq_source_id, level,
+ line_status);
+ default:
+ return -EWOULDBLOCK;
+ }
+}
+
+void kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+ kvm_hv_irq_routing_update(kvm);
+}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index ecd4ea1..36591fa 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -41,6 +41,7 @@
#include "trace.h"
#include "x86.h"
#include "cpuid.h"
+#include "hyperv.h"
#ifndef CONFIG_X86_64
#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
@@ -128,11 +129,6 @@ static inline int apic_enabled(struct kvm_lapic *apic)
(LVT_MASK | APIC_MODE_MASK | APIC_INPUT_POLARITY | \
APIC_LVT_REMOTE_IRR | APIC_LVT_LEVEL_TRIGGER)
-static inline int kvm_apic_id(struct kvm_lapic *apic)
-{
- return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
-}
-
/* The logical map is definitely wrong if we have multiple
* modes at the same time. (Physical map is always right.)
*/
@@ -379,7 +375,8 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic)
if (!apic->irr_pending)
return -1;
- kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
+ if (apic->vcpu->arch.apicv_active)
+ kvm_x86_ops->sync_pir_to_irr(apic->vcpu);
result = apic_search_irr(apic);
ASSERT(result == -1 || result >= 16);
@@ -392,7 +389,7 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
vcpu = apic->vcpu;
- if (unlikely(kvm_vcpu_apic_vid_enabled(vcpu))) {
+ if (unlikely(vcpu->arch.apicv_active)) {
/* try to update RVI */
apic_clear_vector(vec, apic->regs + APIC_IRR);
kvm_make_request(KVM_REQ_EVENT, vcpu);
@@ -418,7 +415,7 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
* because the processor can modify ISR under the hood. Instead
* just set SVI.
*/
- if (unlikely(kvm_x86_ops->hwapic_isr_update))
+ if (unlikely(vcpu->arch.apicv_active))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec);
else {
++apic->isr_count;
@@ -466,7 +463,7 @@ static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
* on the other hand isr_count and highest_isr_cache are unused
* and must be left alone.
*/
- if (unlikely(kvm_x86_ops->hwapic_isr_update))
+ if (unlikely(vcpu->arch.apicv_active))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
apic_find_highest_isr(apic));
else {
@@ -852,7 +849,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
apic_clear_vector(vector, apic->regs + APIC_TMR);
}
- if (kvm_x86_ops->deliver_posted_interrupt)
+ if (vcpu->arch.apicv_active)
kvm_x86_ops->deliver_posted_interrupt(vcpu, vector);
else {
apic_set_irr(vector, apic);
@@ -932,7 +929,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
static bool kvm_ioapic_handles_vector(struct kvm_lapic *apic, int vector)
{
- return test_bit(vector, (ulong *)apic->vcpu->arch.eoi_exit_bitmap);
+ return test_bit(vector, apic->vcpu->arch.ioapic_handled_vectors);
}
static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector)
@@ -974,6 +971,9 @@ static int apic_set_eoi(struct kvm_lapic *apic)
apic_clear_isr(vector, apic);
apic_update_ppr(apic);
+ if (test_bit(vector, vcpu_to_synic(apic->vcpu)->vec_bitmap))
+ kvm_hv_synic_send_eoi(apic->vcpu, vector);
+
kvm_ioapic_send_eoi(apic, vector);
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
return vector;
@@ -1225,7 +1225,7 @@ static bool lapic_timer_int_injected(struct kvm_vcpu *vcpu)
int vec = reg & APIC_VECTOR_MASK;
void *bitmap = apic->regs + APIC_ISR;
- if (kvm_x86_ops->deliver_posted_interrupt)
+ if (vcpu->arch.apicv_active)
bitmap = apic->regs + APIC_IRR;
if (apic_test_vector(vec, bitmap))
@@ -1250,7 +1250,7 @@ void wait_lapic_expire(struct kvm_vcpu *vcpu)
tsc_deadline = apic->lapic_timer.expired_tscdeadline;
apic->lapic_timer.expired_tscdeadline = 0;
- guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc());
+ guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
trace_kvm_wait_lapic_expire(vcpu->vcpu_id, guest_tsc - tsc_deadline);
/* __delay is delay_tsc whenever the hardware has TSC, thus always. */
@@ -1318,7 +1318,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
local_irq_save(flags);
now = apic->lapic_timer.timer.base->get_time();
- guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu, rdtsc());
+ guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
if (likely(tscdeadline > guest_tsc)) {
ns = (tscdeadline - guest_tsc) * 1000000ULL;
do_div(ns, this_tsc_khz);
@@ -1693,8 +1693,8 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool init_event)
apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
}
- apic->irr_pending = kvm_vcpu_apic_vid_enabled(vcpu);
- apic->isr_count = kvm_x86_ops->hwapic_isr_update ? 1 : 0;
+ apic->irr_pending = vcpu->arch.apicv_active;
+ apic->isr_count = vcpu->arch.apicv_active ? 1 : 0;
apic->highest_isr_cache = -1;
update_divide_count(apic);
atomic_set(&apic->lapic_timer.pending, 0);
@@ -1883,6 +1883,12 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
apic_set_isr(vector, apic);
apic_update_ppr(apic);
apic_clear_irr(vector, apic);
+
+ if (test_bit(vector, vcpu_to_synic(vcpu)->auto_eoi_bitmap)) {
+ apic_clear_isr(vector, apic);
+ apic_update_ppr(apic);
+ }
+
return vector;
}
@@ -1906,15 +1912,15 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
update_divide_count(apic);
start_apic_timer(apic);
apic->irr_pending = true;
- apic->isr_count = kvm_x86_ops->hwapic_isr_update ?
+ apic->isr_count = vcpu->arch.apicv_active ?
1 : count_vectors(apic->regs + APIC_ISR);
apic->highest_isr_cache = -1;
- if (kvm_x86_ops->hwapic_irr_update)
+ if (vcpu->arch.apicv_active) {
kvm_x86_ops->hwapic_irr_update(vcpu,
apic_find_highest_irr(apic));
- if (unlikely(kvm_x86_ops->hwapic_isr_update))
kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
apic_find_highest_isr(apic));
+ }
kvm_make_request(KVM_REQ_EVENT, vcpu);
if (ioapic_in_kernel(vcpu->kvm))
kvm_rtc_eoi_tracking_restore_one(vcpu);
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index fde8e35d..41bdb35 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -143,9 +143,9 @@ static inline int apic_x2apic_mode(struct kvm_lapic *apic)
return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
}
-static inline bool kvm_vcpu_apic_vid_enabled(struct kvm_vcpu *vcpu)
+static inline bool kvm_vcpu_apicv_active(struct kvm_vcpu *vcpu)
{
- return kvm_x86_ops->cpu_uses_apicv(vcpu);
+ return vcpu->arch.apic && vcpu->arch.apicv_active;
}
static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
@@ -164,6 +164,11 @@ static inline int kvm_lapic_latched_init(struct kvm_vcpu *vcpu)
return kvm_vcpu_has_lapic(vcpu) && test_bit(KVM_APIC_INIT, &vcpu->arch.apic->pending_events);
}
+static inline int kvm_apic_id(struct kvm_lapic *apic)
+{
+ return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
+}
+
bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
void wait_lapic_expire(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 7d85bca..420a5ca 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -311,11 +311,6 @@ static int is_large_pte(u64 pte)
return pte & PT_PAGE_SIZE_MASK;
}
-static int is_rmap_spte(u64 pte)
-{
- return is_shadow_present_pte(pte);
-}
-
static int is_last_spte(u64 pte, int level)
{
if (level == PT_PAGE_TABLE_LEVEL)
@@ -540,7 +535,7 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte)
u64 old_spte = *sptep;
bool ret = false;
- WARN_ON(!is_rmap_spte(new_spte));
+ WARN_ON(!is_shadow_present_pte(new_spte));
if (!is_shadow_present_pte(old_spte)) {
mmu_spte_set(sptep, new_spte);
@@ -595,7 +590,7 @@ static int mmu_spte_clear_track_bits(u64 *sptep)
else
old_spte = __update_clear_spte_slow(sptep, 0ull);
- if (!is_rmap_spte(old_spte))
+ if (!is_shadow_present_pte(old_spte))
return 0;
pfn = spte_to_pfn(old_spte);
@@ -909,36 +904,35 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn,
}
/*
- * Pte mapping structures:
+ * About rmap_head encoding:
*
- * If pte_list bit zero is zero, then pte_list point to the spte.
- *
- * If pte_list bit zero is one, (then pte_list & ~1) points to a struct
+ * If the bit zero of rmap_head->val is clear, then it points to the only spte
+ * in this rmap chain. Otherwise, (rmap_head->val & ~1) points to a struct
* pte_list_desc containing more mappings.
- *
- * Returns the number of pte entries before the spte was added or zero if
- * the spte was not added.
- *
+ */
+
+/*
+ * Returns the number of pointers in the rmap chain, not counting the new one.
*/
static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
- unsigned long *pte_list)
+ struct kvm_rmap_head *rmap_head)
{
struct pte_list_desc *desc;
int i, count = 0;
- if (!*pte_list) {
+ if (!rmap_head->val) {
rmap_printk("pte_list_add: %p %llx 0->1\n", spte, *spte);
- *pte_list = (unsigned long)spte;
- } else if (!(*pte_list & 1)) {
+ rmap_head->val = (unsigned long)spte;
+ } else if (!(rmap_head->val & 1)) {
rmap_printk("pte_list_add: %p %llx 1->many\n", spte, *spte);
desc = mmu_alloc_pte_list_desc(vcpu);
- desc->sptes[0] = (u64 *)*pte_list;
+ desc->sptes[0] = (u64 *)rmap_head->val;
desc->sptes[1] = spte;
- *pte_list = (unsigned long)desc | 1;
+ rmap_head->val = (unsigned long)desc | 1;
++count;
} else {
rmap_printk("pte_list_add: %p %llx many->many\n", spte, *spte);
- desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+ desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
while (desc->sptes[PTE_LIST_EXT-1] && desc->more) {
desc = desc->more;
count += PTE_LIST_EXT;
@@ -955,8 +949,9 @@ static int pte_list_add(struct kvm_vcpu *vcpu, u64 *spte,
}
static void
-pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc,
- int i, struct pte_list_desc *prev_desc)
+pte_list_desc_remove_entry(struct kvm_rmap_head *rmap_head,
+ struct pte_list_desc *desc, int i,
+ struct pte_list_desc *prev_desc)
{
int j;
@@ -967,43 +962,43 @@ pte_list_desc_remove_entry(unsigned long *pte_list, struct pte_list_desc *desc,
if (j != 0)
return;
if (!prev_desc && !desc->more)
- *pte_list = (unsigned long)desc->sptes[0];
+ rmap_head->val = (unsigned long)desc->sptes[0];
else
if (prev_desc)
prev_desc->more = desc->more;
else
- *pte_list = (unsigned long)desc->more | 1;
+ rmap_head->val = (unsigned long)desc->more | 1;
mmu_free_pte_list_desc(desc);
}
-static void pte_list_remove(u64 *spte, unsigned long *pte_list)
+static void pte_list_remove(u64 *spte, struct kvm_rmap_head *rmap_head)
{
struct pte_list_desc *desc;
struct pte_list_desc *prev_desc;
int i;
- if (!*pte_list) {
+ if (!rmap_head->val) {
printk(KERN_ERR "pte_list_remove: %p 0->BUG\n", spte);
BUG();
- } else if (!(*pte_list & 1)) {
+ } else if (!(rmap_head->val & 1)) {
rmap_printk("pte_list_remove: %p 1->0\n", spte);
- if ((u64 *)*pte_list != spte) {
+ if ((u64 *)rmap_head->val != spte) {
printk(KERN_ERR "pte_list_remove: %p 1->BUG\n", spte);
BUG();
}
- *pte_list = 0;
+ rmap_head->val = 0;
} else {
rmap_printk("pte_list_remove: %p many->many\n", spte);
- desc = (struct pte_list_desc *)(*pte_list & ~1ul);
+ desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
prev_desc = NULL;
while (desc) {
- for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
+ for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i) {
if (desc->sptes[i] == spte) {
- pte_list_desc_remove_entry(pte_list,
- desc, i,
- prev_desc);
+ pte_list_desc_remove_entry(rmap_head,
+ desc, i, prev_desc);
return;
}
+ }
prev_desc = desc;
desc = desc->more;
}
@@ -1012,28 +1007,8 @@ static void pte_list_remove(u64 *spte, unsigned long *pte_list)
}
}
-typedef void (*pte_list_walk_fn) (u64 *spte);
-static void pte_list_walk(unsigned long *pte_list, pte_list_walk_fn fn)
-{
- struct pte_list_desc *desc;
- int i;
-
- if (!*pte_list)
- return;
-
- if (!(*pte_list & 1))
- return fn((u64 *)*pte_list);
-
- desc = (struct pte_list_desc *)(*pte_list & ~1ul);
- while (desc) {
- for (i = 0; i < PTE_LIST_EXT && desc->sptes[i]; ++i)
- fn(desc->sptes[i]);
- desc = desc->more;
- }
-}
-
-static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
- struct kvm_memory_slot *slot)
+static struct kvm_rmap_head *__gfn_to_rmap(gfn_t gfn, int level,
+ struct kvm_memory_slot *slot)
{
unsigned long idx;
@@ -1041,10 +1016,8 @@ static unsigned long *__gfn_to_rmap(gfn_t gfn, int level,
return &slot->arch.rmap[level - PT_PAGE_TABLE_LEVEL][idx];
}
-/*
- * Take gfn and return the reverse mapping to it.
- */
-static unsigned long *gfn_to_rmap(struct kvm *kvm, gfn_t gfn, struct kvm_mmu_page *sp)
+static struct kvm_rmap_head *gfn_to_rmap(struct kvm *kvm, gfn_t gfn,
+ struct kvm_mmu_page *sp)
{
struct kvm_memslots *slots;
struct kvm_memory_slot *slot;
@@ -1065,24 +1038,24 @@ static bool rmap_can_add(struct kvm_vcpu *vcpu)
static int rmap_add(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
{
struct kvm_mmu_page *sp;
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
sp = page_header(__pa(spte));
kvm_mmu_page_set_gfn(sp, spte - sp->spt, gfn);
- rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
- return pte_list_add(vcpu, spte, rmapp);
+ rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
+ return pte_list_add(vcpu, spte, rmap_head);
}
static void rmap_remove(struct kvm *kvm, u64 *spte)
{
struct kvm_mmu_page *sp;
gfn_t gfn;
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
sp = page_header(__pa(spte));
gfn = kvm_mmu_page_get_gfn(sp, spte - sp->spt);
- rmapp = gfn_to_rmap(kvm, gfn, sp);
- pte_list_remove(spte, rmapp);
+ rmap_head = gfn_to_rmap(kvm, gfn, sp);
+ pte_list_remove(spte, rmap_head);
}
/*
@@ -1102,19 +1075,26 @@ struct rmap_iterator {
*
* Returns sptep if found, NULL otherwise.
*/
-static u64 *rmap_get_first(unsigned long rmap, struct rmap_iterator *iter)
+static u64 *rmap_get_first(struct kvm_rmap_head *rmap_head,
+ struct rmap_iterator *iter)
{
- if (!rmap)
+ u64 *sptep;
+
+ if (!rmap_head->val)
return NULL;
- if (!(rmap & 1)) {
+ if (!(rmap_head->val & 1)) {
iter->desc = NULL;
- return (u64 *)rmap;
+ sptep = (u64 *)rmap_head->val;
+ goto out;
}
- iter->desc = (struct pte_list_desc *)(rmap & ~1ul);
+ iter->desc = (struct pte_list_desc *)(rmap_head->val & ~1ul);
iter->pos = 0;
- return iter->desc->sptes[iter->pos];
+ sptep = iter->desc->sptes[iter->pos];
+out:
+ BUG_ON(!is_shadow_present_pte(*sptep));
+ return sptep;
}
/*
@@ -1124,14 +1104,14 @@ static u64 *rmap_get_first(unsigned long rmap, struct rmap_iterator *iter)
*/
static u64 *rmap_get_next(struct rmap_iterator *iter)
{
+ u64 *sptep;
+
if (iter->desc) {
if (iter->pos < PTE_LIST_EXT - 1) {
- u64 *sptep;
-
++iter->pos;
sptep = iter->desc->sptes[iter->pos];
if (sptep)
- return sptep;
+ goto out;
}
iter->desc = iter->desc->more;
@@ -1139,17 +1119,20 @@ static u64 *rmap_get_next(struct rmap_iterator *iter)
if (iter->desc) {
iter->pos = 0;
/* desc->sptes[0] cannot be NULL */
- return iter->desc->sptes[iter->pos];
+ sptep = iter->desc->sptes[iter->pos];
+ goto out;
}
}
return NULL;
+out:
+ BUG_ON(!is_shadow_present_pte(*sptep));
+ return sptep;
}
-#define for_each_rmap_spte(_rmap_, _iter_, _spte_) \
- for (_spte_ = rmap_get_first(*_rmap_, _iter_); \
- _spte_ && ({BUG_ON(!is_shadow_present_pte(*_spte_)); 1;}); \
- _spte_ = rmap_get_next(_iter_))
+#define for_each_rmap_spte(_rmap_head_, _iter_, _spte_) \
+ for (_spte_ = rmap_get_first(_rmap_head_, _iter_); \
+ _spte_; _spte_ = rmap_get_next(_iter_))
static void drop_spte(struct kvm *kvm, u64 *sptep)
{
@@ -1207,14 +1190,15 @@ static bool spte_write_protect(struct kvm *kvm, u64 *sptep, bool pt_protect)
return mmu_spte_update(sptep, spte);
}
-static bool __rmap_write_protect(struct kvm *kvm, unsigned long *rmapp,
+static bool __rmap_write_protect(struct kvm *kvm,
+ struct kvm_rmap_head *rmap_head,
bool pt_protect)
{
u64 *sptep;
struct rmap_iterator iter;
bool flush = false;
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep)
flush |= spte_write_protect(kvm, sptep, pt_protect);
return flush;
@@ -1231,13 +1215,13 @@ static bool spte_clear_dirty(struct kvm *kvm, u64 *sptep)
return mmu_spte_update(sptep, spte);
}
-static bool __rmap_clear_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_clear_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
{
u64 *sptep;
struct rmap_iterator iter;
bool flush = false;
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep)
flush |= spte_clear_dirty(kvm, sptep);
return flush;
@@ -1254,13 +1238,13 @@ static bool spte_set_dirty(struct kvm *kvm, u64 *sptep)
return mmu_spte_update(sptep, spte);
}
-static bool __rmap_set_dirty(struct kvm *kvm, unsigned long *rmapp)
+static bool __rmap_set_dirty(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
{
u64 *sptep;
struct rmap_iterator iter;
bool flush = false;
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep)
flush |= spte_set_dirty(kvm, sptep);
return flush;
@@ -1280,12 +1264,12 @@ static void kvm_mmu_write_protect_pt_masked(struct kvm *kvm,
struct kvm_memory_slot *slot,
gfn_t gfn_offset, unsigned long mask)
{
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
while (mask) {
- rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
- PT_PAGE_TABLE_LEVEL, slot);
- __rmap_write_protect(kvm, rmapp, false);
+ rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+ PT_PAGE_TABLE_LEVEL, slot);
+ __rmap_write_protect(kvm, rmap_head, false);
/* clear the first set bit */
mask &= mask - 1;
@@ -1305,12 +1289,12 @@ void kvm_mmu_clear_dirty_pt_masked(struct kvm *kvm,
struct kvm_memory_slot *slot,
gfn_t gfn_offset, unsigned long mask)
{
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
while (mask) {
- rmapp = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
- PT_PAGE_TABLE_LEVEL, slot);
- __rmap_clear_dirty(kvm, rmapp);
+ rmap_head = __gfn_to_rmap(slot->base_gfn + gfn_offset + __ffs(mask),
+ PT_PAGE_TABLE_LEVEL, slot);
+ __rmap_clear_dirty(kvm, rmap_head);
/* clear the first set bit */
mask &= mask - 1;
@@ -1342,28 +1326,27 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
static bool rmap_write_protect(struct kvm_vcpu *vcpu, u64 gfn)
{
struct kvm_memory_slot *slot;
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
int i;
bool write_protected = false;
slot = kvm_vcpu_gfn_to_memslot(vcpu, gfn);
for (i = PT_PAGE_TABLE_LEVEL; i <= PT_MAX_HUGEPAGE_LEVEL; ++i) {
- rmapp = __gfn_to_rmap(gfn, i, slot);
- write_protected |= __rmap_write_protect(vcpu->kvm, rmapp, true);
+ rmap_head = __gfn_to_rmap(gfn, i, slot);
+ write_protected |= __rmap_write_protect(vcpu->kvm, rmap_head, true);
}
return write_protected;
}
-static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
+static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head)
{
u64 *sptep;
struct rmap_iterator iter;
bool flush = false;
- while ((sptep = rmap_get_first(*rmapp, &iter))) {
- BUG_ON(!(*sptep & PT_PRESENT_MASK));
+ while ((sptep = rmap_get_first(rmap_head, &iter))) {
rmap_printk("%s: spte %p %llx.\n", __func__, sptep, *sptep);
drop_spte(kvm, sptep);
@@ -1373,14 +1356,14 @@ static bool kvm_zap_rmapp(struct kvm *kvm, unsigned long *rmapp)
return flush;
}
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot, gfn_t gfn, int level,
unsigned long data)
{
- return kvm_zap_rmapp(kvm, rmapp);
+ return kvm_zap_rmapp(kvm, rmap_head);
}
-static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot, gfn_t gfn, int level,
unsigned long data)
{
@@ -1395,7 +1378,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp,
new_pfn = pte_pfn(*ptep);
restart:
- for_each_rmap_spte(rmapp, &iter, sptep) {
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
rmap_printk("kvm_set_pte_rmapp: spte %p %llx gfn %llx (%d)\n",
sptep, *sptep, gfn, level);
@@ -1433,11 +1416,11 @@ struct slot_rmap_walk_iterator {
/* output fields. */
gfn_t gfn;
- unsigned long *rmap;
+ struct kvm_rmap_head *rmap;
int level;
/* private field. */
- unsigned long *end_rmap;
+ struct kvm_rmap_head *end_rmap;
};
static void
@@ -1496,7 +1479,7 @@ static int kvm_handle_hva_range(struct kvm *kvm,
unsigned long end,
unsigned long data,
int (*handler)(struct kvm *kvm,
- unsigned long *rmapp,
+ struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot,
gfn_t gfn,
int level,
@@ -1540,7 +1523,8 @@ static int kvm_handle_hva_range(struct kvm *kvm,
static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
unsigned long data,
- int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+ int (*handler)(struct kvm *kvm,
+ struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot,
gfn_t gfn, int level,
unsigned long data))
@@ -1563,7 +1547,7 @@ void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
}
-static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot, gfn_t gfn, int level,
unsigned long data)
{
@@ -1573,18 +1557,19 @@ static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
BUG_ON(!shadow_accessed_mask);
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
if (*sptep & shadow_accessed_mask) {
young = 1;
clear_bit((ffs(shadow_accessed_mask) - 1),
(unsigned long *)sptep);
}
+ }
trace_kvm_age_page(gfn, level, slot, young);
return young;
}
-static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
+static int kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
struct kvm_memory_slot *slot, gfn_t gfn,
int level, unsigned long data)
{
@@ -1600,11 +1585,12 @@ static int kvm_test_age_rmapp(struct kvm *kvm, unsigned long *rmapp,
if (!shadow_accessed_mask)
goto out;
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
if (*sptep & shadow_accessed_mask) {
young = 1;
break;
}
+ }
out:
return young;
}
@@ -1613,14 +1599,14 @@ out:
static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
{
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
struct kvm_mmu_page *sp;
sp = page_header(__pa(spte));
- rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp);
+ rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
- kvm_unmap_rmapp(vcpu->kvm, rmapp, NULL, gfn, sp->role.level, 0);
+ kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, 0);
kvm_flush_remote_tlbs(vcpu->kvm);
}
@@ -1720,8 +1706,7 @@ static void drop_parent_pte(struct kvm_mmu_page *sp,
mmu_spte_clear_no_track(parent_pte);
}
-static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
- u64 *parent_pte, int direct)
+static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu, int direct)
{
struct kvm_mmu_page *sp;
@@ -1737,8 +1722,6 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
* this feature. See the comments in kvm_zap_obsolete_pages().
*/
list_add(&sp->link, &vcpu->kvm->arch.active_mmu_pages);
- sp->parent_ptes = 0;
- mmu_page_add_parent_pte(vcpu, sp, parent_pte);
kvm_mod_used_mmu_pages(vcpu->kvm, +1);
return sp;
}
@@ -1746,7 +1729,12 @@ static struct kvm_mmu_page *kvm_mmu_alloc_page(struct kvm_vcpu *vcpu,
static void mark_unsync(u64 *spte);
static void kvm_mmu_mark_parents_unsync(struct kvm_mmu_page *sp)
{
- pte_list_walk(&sp->parent_ptes, mark_unsync);
+ u64 *sptep;
+ struct rmap_iterator iter;
+
+ for_each_rmap_spte(&sp->parent_ptes, &iter, sptep) {
+ mark_unsync(sptep);
+ }
}
static void mark_unsync(u64 *spte)
@@ -1806,6 +1794,13 @@ static int mmu_pages_add(struct kvm_mmu_pages *pvec, struct kvm_mmu_page *sp,
return (pvec->nr == KVM_PAGE_ARRAY_NR);
}
+static inline void clear_unsync_child_bit(struct kvm_mmu_page *sp, int idx)
+{
+ --sp->unsync_children;
+ WARN_ON((int)sp->unsync_children < 0);
+ __clear_bit(idx, sp->unsync_child_bitmap);
+}
+
static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
struct kvm_mmu_pages *pvec)
{
@@ -1815,8 +1810,10 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
struct kvm_mmu_page *child;
u64 ent = sp->spt[i];
- if (!is_shadow_present_pte(ent) || is_large_pte(ent))
- goto clear_child_bitmap;
+ if (!is_shadow_present_pte(ent) || is_large_pte(ent)) {
+ clear_unsync_child_bit(sp, i);
+ continue;
+ }
child = page_header(ent & PT64_BASE_ADDR_MASK);
@@ -1825,28 +1822,21 @@ static int __mmu_unsync_walk(struct kvm_mmu_page *sp,
return -ENOSPC;
ret = __mmu_unsync_walk(child, pvec);
- if (!ret)
- goto clear_child_bitmap;
- else if (ret > 0)
+ if (!ret) {
+ clear_unsync_child_bit(sp, i);
+ continue;
+ } else if (ret > 0) {
nr_unsync_leaf += ret;
- else
+ } else
return ret;
} else if (child->unsync) {
nr_unsync_leaf++;
if (mmu_pages_add(pvec, child, i))
return -ENOSPC;
} else
- goto clear_child_bitmap;
-
- continue;
-
-clear_child_bitmap:
- __clear_bit(i, sp->unsync_child_bitmap);
- sp->unsync_children--;
- WARN_ON((int)sp->unsync_children < 0);
+ clear_unsync_child_bit(sp, i);
}
-
return nr_unsync_leaf;
}
@@ -2009,9 +1999,7 @@ static void mmu_pages_clear_parents(struct mmu_page_path *parents)
if (!sp)
return;
- --sp->unsync_children;
- WARN_ON((int)sp->unsync_children < 0);
- __clear_bit(idx, sp->unsync_child_bitmap);
+ clear_unsync_child_bit(sp, idx);
level++;
} while (level < PT64_ROOT_LEVEL-1 && !sp->unsync_children);
}
@@ -2053,14 +2041,6 @@ static void mmu_sync_children(struct kvm_vcpu *vcpu,
}
}
-static void init_shadow_page_table(struct kvm_mmu_page *sp)
-{
- int i;
-
- for (i = 0; i < PT64_ENT_PER_PAGE; ++i)
- sp->spt[i] = 0ull;
-}
-
static void __clear_sp_write_flooding_count(struct kvm_mmu_page *sp)
{
sp->write_flooding_count = 0;
@@ -2083,8 +2063,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
gva_t gaddr,
unsigned level,
int direct,
- unsigned access,
- u64 *parent_pte)
+ unsigned access)
{
union kvm_mmu_page_role role;
unsigned quadrant;
@@ -2116,21 +2095,18 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
if (sp->unsync && kvm_sync_page_transient(vcpu, sp))
break;
- mmu_page_add_parent_pte(vcpu, sp, parent_pte);
- if (sp->unsync_children) {
+ if (sp->unsync_children)
kvm_make_request(KVM_REQ_MMU_SYNC, vcpu);
- kvm_mmu_mark_parents_unsync(sp);
- } else if (sp->unsync)
- kvm_mmu_mark_parents_unsync(sp);
__clear_sp_write_flooding_count(sp);
trace_kvm_mmu_get_page(sp, false);
return sp;
}
+
++vcpu->kvm->stat.mmu_cache_miss;
- sp = kvm_mmu_alloc_page(vcpu, parent_pte, direct);
- if (!sp)
- return sp;
+
+ sp = kvm_mmu_alloc_page(vcpu, direct);
+
sp->gfn = gfn;
sp->role = role;
hlist_add_head(&sp->hash_link,
@@ -2144,7 +2120,7 @@ static struct kvm_mmu_page *kvm_mmu_get_page(struct kvm_vcpu *vcpu,
account_shadowed(vcpu->kvm, sp);
}
sp->mmu_valid_gen = vcpu->kvm->arch.mmu_valid_gen;
- init_shadow_page_table(sp);
+ clear_page(sp->spt);
trace_kvm_mmu_get_page(sp, true);
return sp;
}
@@ -2198,7 +2174,8 @@ static void shadow_walk_next(struct kvm_shadow_walk_iterator *iterator)
return __shadow_walk_next(iterator, *iterator->sptep);
}
-static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
+static void link_shadow_page(struct kvm_vcpu *vcpu, u64 *sptep,
+ struct kvm_mmu_page *sp)
{
u64 spte;
@@ -2206,12 +2183,14 @@ static void link_shadow_page(u64 *sptep, struct kvm_mmu_page *sp, bool accessed)
VMX_EPT_WRITABLE_MASK != PT_WRITABLE_MASK);
spte = __pa(sp->spt) | PT_PRESENT_MASK | PT_WRITABLE_MASK |
- shadow_user_mask | shadow_x_mask;
-
- if (accessed)
- spte |= shadow_accessed_mask;
+ shadow_user_mask | shadow_x_mask | shadow_accessed_mask;
mmu_spte_set(sptep, spte);
+
+ mmu_page_add_parent_pte(vcpu, sp, sptep);
+
+ if (sp->unsync_children || sp->unsync)
+ mark_unsync(sptep);
}
static void validate_direct_spte(struct kvm_vcpu *vcpu, u64 *sptep,
@@ -2270,17 +2249,12 @@ static void kvm_mmu_page_unlink_children(struct kvm *kvm,
mmu_page_zap_pte(kvm, sp, sp->spt + i);
}
-static void kvm_mmu_put_page(struct kvm_mmu_page *sp, u64 *parent_pte)
-{
- mmu_page_remove_parent_pte(sp, parent_pte);
-}
-
static void kvm_mmu_unlink_parents(struct kvm *kvm, struct kvm_mmu_page *sp)
{
u64 *sptep;
struct rmap_iterator iter;
- while ((sptep = rmap_get_first(sp->parent_ptes, &iter)))
+ while ((sptep = rmap_get_first(&sp->parent_ptes, &iter)))
drop_parent_pte(sp, sptep);
}
@@ -2564,18 +2538,18 @@ done:
return ret;
}
-static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
- unsigned pte_access, int write_fault, int *emulate,
- int level, gfn_t gfn, pfn_t pfn, bool speculative,
- bool host_writable)
+static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
+ int write_fault, int level, gfn_t gfn, pfn_t pfn,
+ bool speculative, bool host_writable)
{
int was_rmapped = 0;
int rmap_count;
+ bool emulate = false;
pgprintk("%s: spte %llx write_fault %d gfn %llx\n", __func__,
*sptep, write_fault, gfn);
- if (is_rmap_spte(*sptep)) {
+ if (is_shadow_present_pte(*sptep)) {
/*
* If we overwrite a PTE page pointer with a 2MB PMD, unlink
* the parent of the now unreachable PTE.
@@ -2600,12 +2574,12 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
if (set_spte(vcpu, sptep, pte_access, level, gfn, pfn, speculative,
true, host_writable)) {
if (write_fault)
- *emulate = 1;
+ emulate = true;
kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu);
}
- if (unlikely(is_mmio_spte(*sptep) && emulate))
- *emulate = 1;
+ if (unlikely(is_mmio_spte(*sptep)))
+ emulate = true;
pgprintk("%s: setting spte %llx\n", __func__, *sptep);
pgprintk("instantiating %s PTE (%s) at %llx (%llx) addr %p\n",
@@ -2624,6 +2598,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
}
kvm_release_pfn_clean(pfn);
+
+ return emulate;
}
static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
@@ -2658,9 +2634,8 @@ static int direct_pte_prefetch_many(struct kvm_vcpu *vcpu,
return -1;
for (i = 0; i < ret; i++, gfn++, start++)
- mmu_set_spte(vcpu, start, access, 0, NULL,
- sp->role.level, gfn, page_to_pfn(pages[i]),
- true, true);
+ mmu_set_spte(vcpu, start, access, 0, sp->role.level, gfn,
+ page_to_pfn(pages[i]), true, true);
return 0;
}
@@ -2708,9 +2683,8 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
__direct_pte_prefetch(vcpu, sp, sptep);
}
-static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
- int map_writable, int level, gfn_t gfn, pfn_t pfn,
- bool prefault)
+static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
+ int level, gfn_t gfn, pfn_t pfn, bool prefault)
{
struct kvm_shadow_walk_iterator iterator;
struct kvm_mmu_page *sp;
@@ -2722,9 +2696,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
for_each_shadow_entry(vcpu, (u64)gfn << PAGE_SHIFT, iterator) {
if (iterator.level == level) {
- mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
- write, &emulate, level, gfn, pfn,
- prefault, map_writable);
+ emulate = mmu_set_spte(vcpu, iterator.sptep, ACC_ALL,
+ write, level, gfn, pfn, prefault,
+ map_writable);
direct_pte_prefetch(vcpu, iterator.sptep);
++vcpu->stat.pf_fixed;
break;
@@ -2737,10 +2711,9 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
base_addr &= PT64_LVL_ADDR_MASK(iterator.level);
pseudo_gfn = base_addr >> PAGE_SHIFT;
sp = kvm_mmu_get_page(vcpu, pseudo_gfn, iterator.addr,
- iterator.level - 1,
- 1, ACC_ALL, iterator.sptep);
+ iterator.level - 1, 1, ACC_ALL);
- link_shadow_page(iterator.sptep, sp, true);
+ link_shadow_page(vcpu, iterator.sptep, sp);
}
}
return emulate;
@@ -2919,7 +2892,7 @@ static bool fast_page_fault(struct kvm_vcpu *vcpu, gva_t gva, int level,
* If the mapping has been changed, let the vcpu fault on the
* same address again.
*/
- if (!is_rmap_spte(spte)) {
+ if (!is_shadow_present_pte(spte)) {
ret = true;
goto exit;
}
@@ -3018,11 +2991,9 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
make_mmu_pages_available(vcpu);
if (likely(!force_pt_level))
transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
- r = __direct_map(vcpu, v, write, map_writable, level, gfn, pfn,
- prefault);
+ r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
spin_unlock(&vcpu->kvm->mmu_lock);
-
return r;
out_unlock:
@@ -3097,8 +3068,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
if (vcpu->arch.mmu.shadow_root_level == PT64_ROOT_LEVEL) {
spin_lock(&vcpu->kvm->mmu_lock);
make_mmu_pages_available(vcpu);
- sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL,
- 1, ACC_ALL, NULL);
+ sp = kvm_mmu_get_page(vcpu, 0, 0, PT64_ROOT_LEVEL, 1, ACC_ALL);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
vcpu->arch.mmu.root_hpa = __pa(sp->spt);
@@ -3110,9 +3080,7 @@ static int mmu_alloc_direct_roots(struct kvm_vcpu *vcpu)
spin_lock(&vcpu->kvm->mmu_lock);
make_mmu_pages_available(vcpu);
sp = kvm_mmu_get_page(vcpu, i << (30 - PAGE_SHIFT),
- i << 30,
- PT32_ROOT_LEVEL, 1, ACC_ALL,
- NULL);
+ i << 30, PT32_ROOT_LEVEL, 1, ACC_ALL);
root = __pa(sp->spt);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3149,7 +3117,7 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
spin_lock(&vcpu->kvm->mmu_lock);
make_mmu_pages_available(vcpu);
sp = kvm_mmu_get_page(vcpu, root_gfn, 0, PT64_ROOT_LEVEL,
- 0, ACC_ALL, NULL);
+ 0, ACC_ALL);
root = __pa(sp->spt);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3182,9 +3150,8 @@ static int mmu_alloc_shadow_roots(struct kvm_vcpu *vcpu)
}
spin_lock(&vcpu->kvm->mmu_lock);
make_mmu_pages_available(vcpu);
- sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30,
- PT32_ROOT_LEVEL, 0,
- ACC_ALL, NULL);
+ sp = kvm_mmu_get_page(vcpu, root_gfn, i << 30, PT32_ROOT_LEVEL,
+ 0, ACC_ALL);
root = __pa(sp->spt);
++sp->root_count;
spin_unlock(&vcpu->kvm->mmu_lock);
@@ -3359,7 +3326,7 @@ exit:
return reserved;
}
-int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
+int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct)
{
u64 spte;
bool reserved;
@@ -3368,7 +3335,7 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
return RET_MMIO_PF_EMULATE;
reserved = walk_shadow_page_get_mmio_spte(vcpu, addr, &spte);
- if (unlikely(reserved))
+ if (WARN_ON(reserved))
return RET_MMIO_PF_BUG;
if (is_mmio_spte(spte)) {
@@ -3392,17 +3359,7 @@ int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct)
*/
return RET_MMIO_PF_RETRY;
}
-EXPORT_SYMBOL_GPL(handle_mmio_page_fault_common);
-
-static int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr,
- u32 error_code, bool direct)
-{
- int ret;
-
- ret = handle_mmio_page_fault_common(vcpu, addr, direct);
- WARN_ON(ret == RET_MMIO_PF_BUG);
- return ret;
-}
+EXPORT_SYMBOL_GPL(handle_mmio_page_fault);
static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
u32 error_code, bool prefault)
@@ -3413,7 +3370,7 @@ static int nonpaging_page_fault(struct kvm_vcpu *vcpu, gva_t gva,
pgprintk("%s: gva %lx error %x\n", __func__, gva, error_code);
if (unlikely(error_code & PFERR_RSVD_MASK)) {
- r = handle_mmio_page_fault(vcpu, gva, error_code, true);
+ r = handle_mmio_page_fault(vcpu, gva, true);
if (likely(r != RET_MMIO_PF_INVALID))
return r;
@@ -3503,7 +3460,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
MMU_WARN_ON(!VALID_PAGE(vcpu->arch.mmu.root_hpa));
if (unlikely(error_code & PFERR_RSVD_MASK)) {
- r = handle_mmio_page_fault(vcpu, gpa, error_code, true);
+ r = handle_mmio_page_fault(vcpu, gpa, true);
if (likely(r != RET_MMIO_PF_INVALID))
return r;
@@ -3541,8 +3498,7 @@ static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
make_mmu_pages_available(vcpu);
if (likely(!force_pt_level))
transparent_hugepage_adjust(vcpu, &gfn, &pfn, &level);
- r = __direct_map(vcpu, gpa, write, map_writable,
- level, gfn, pfn, prefault);
+ r = __direct_map(vcpu, write, map_writable, level, gfn, pfn, prefault);
spin_unlock(&vcpu->kvm->mmu_lock);
return r;
@@ -4068,10 +4024,12 @@ static void init_kvm_nested_mmu(struct kvm_vcpu *vcpu)
g_context->inject_page_fault = kvm_inject_page_fault;
/*
- * Note that arch.mmu.gva_to_gpa translates l2_gva to l1_gpa. The
- * translation of l2_gpa to l1_gpa addresses is done using the
- * arch.nested_mmu.gva_to_gpa function. Basically the gva_to_gpa
- * functions between mmu and nested_mmu are swapped.
+ * Note that arch.mmu.gva_to_gpa translates l2_gpa to l1_gpa using
+ * L1's nested page tables (e.g. EPT12). The nested translation
+ * of l2_gva to l1_gpa is done by arch.nested_mmu.gva_to_gpa using
+ * L2's page tables as the first level of translation and L1's
+ * nested page tables as the second level of translation. Basically
+ * the gva_to_gpa functions between mmu and nested_mmu are swapped.
*/
if (!is_paging(vcpu)) {
g_context->nx = false;
@@ -4505,7 +4463,7 @@ void kvm_mmu_setup(struct kvm_vcpu *vcpu)
}
/* The return value indicates if tlb flush on all vcpus is needed. */
-typedef bool (*slot_level_handler) (struct kvm *kvm, unsigned long *rmap);
+typedef bool (*slot_level_handler) (struct kvm *kvm, struct kvm_rmap_head *rmap_head);
/* The caller should hold mmu-lock before calling this function. */
static bool
@@ -4599,9 +4557,10 @@ void kvm_zap_gfn_range(struct kvm *kvm, gfn_t gfn_start, gfn_t gfn_end)
spin_unlock(&kvm->mmu_lock);
}
-static bool slot_rmap_write_protect(struct kvm *kvm, unsigned long *rmapp)
+static bool slot_rmap_write_protect(struct kvm *kvm,
+ struct kvm_rmap_head *rmap_head)
{
- return __rmap_write_protect(kvm, rmapp, false);
+ return __rmap_write_protect(kvm, rmap_head, false);
}
void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
@@ -4637,7 +4596,7 @@ void kvm_mmu_slot_remove_write_access(struct kvm *kvm,
}
static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
- unsigned long *rmapp)
+ struct kvm_rmap_head *rmap_head)
{
u64 *sptep;
struct rmap_iterator iter;
@@ -4646,7 +4605,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
struct kvm_mmu_page *sp;
restart:
- for_each_rmap_spte(rmapp, &iter, sptep) {
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
sp = page_header(__pa(sptep));
pfn = spte_to_pfn(*sptep);
diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
index e4202e4..55ffb7b 100644
--- a/arch/x86/kvm/mmu.h
+++ b/arch/x86/kvm/mmu.h
@@ -56,13 +56,13 @@ void
reset_shadow_zero_bits_mask(struct kvm_vcpu *vcpu, struct kvm_mmu *context);
/*
- * Return values of handle_mmio_page_fault_common:
+ * Return values of handle_mmio_page_fault:
* RET_MMIO_PF_EMULATE: it is a real mmio page fault, emulate the instruction
* directly.
* RET_MMIO_PF_INVALID: invalid spte is detected then let the real page
* fault path update the mmio spte.
* RET_MMIO_PF_RETRY: let CPU fault again on the address.
- * RET_MMIO_PF_BUG: bug is detected.
+ * RET_MMIO_PF_BUG: a bug was detected (and a WARN was printed).
*/
enum {
RET_MMIO_PF_EMULATE = 1,
@@ -71,7 +71,7 @@ enum {
RET_MMIO_PF_BUG = -1
};
-int handle_mmio_page_fault_common(struct kvm_vcpu *vcpu, u64 addr, bool direct);
+int handle_mmio_page_fault(struct kvm_vcpu *vcpu, u64 addr, bool direct);
void kvm_init_shadow_mmu(struct kvm_vcpu *vcpu);
void kvm_init_shadow_ept_mmu(struct kvm_vcpu *vcpu, bool execonly);
diff --git a/arch/x86/kvm/mmu_audit.c b/arch/x86/kvm/mmu_audit.c
index 03d518e..1cee3ec 100644
--- a/arch/x86/kvm/mmu_audit.c
+++ b/arch/x86/kvm/mmu_audit.c
@@ -129,7 +129,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
{
static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10);
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
struct kvm_mmu_page *rev_sp;
struct kvm_memslots *slots;
struct kvm_memory_slot *slot;
@@ -150,8 +150,8 @@ static void inspect_spte_has_rmap(struct kvm *kvm, u64 *sptep)
return;
}
- rmapp = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
- if (!*rmapp) {
+ rmap_head = __gfn_to_rmap(gfn, rev_sp->role.level, slot);
+ if (!rmap_head->val) {
if (!__ratelimit(&ratelimit_state))
return;
audit_printk(kvm, "no rmap for writable spte %llx\n",
@@ -183,7 +183,7 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
return;
for (i = 0; i < PT64_ENT_PER_PAGE; ++i) {
- if (!is_rmap_spte(sp->spt[i]))
+ if (!is_shadow_present_pte(sp->spt[i]))
continue;
inspect_spte_has_rmap(kvm, sp->spt + i);
@@ -192,7 +192,7 @@ static void check_mappings_rmap(struct kvm *kvm, struct kvm_mmu_page *sp)
static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
{
- unsigned long *rmapp;
+ struct kvm_rmap_head *rmap_head;
u64 *sptep;
struct rmap_iterator iter;
struct kvm_memslots *slots;
@@ -203,13 +203,14 @@ static void audit_write_protection(struct kvm *kvm, struct kvm_mmu_page *sp)
slots = kvm_memslots_for_spte_role(kvm, sp->role);
slot = __gfn_to_memslot(slots, sp->gfn);
- rmapp = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
+ rmap_head = __gfn_to_rmap(sp->gfn, PT_PAGE_TABLE_LEVEL, slot);
- for_each_rmap_spte(rmapp, &iter, sptep)
+ for_each_rmap_spte(rmap_head, &iter, sptep) {
if (is_writable_pte(*sptep))
audit_printk(kvm, "shadow page has writable "
"mappings: gfn %llx role %x\n",
sp->gfn, sp->role.word);
+ }
}
static void audit_sp(struct kvm *kvm, struct kvm_mmu_page *sp)
diff --git a/arch/x86/kvm/mtrr.c b/arch/x86/kvm/mtrr.c
index 9e8bf13..3f8c732 100644
--- a/arch/x86/kvm/mtrr.c
+++ b/arch/x86/kvm/mtrr.c
@@ -120,14 +120,22 @@ static u8 mtrr_default_type(struct kvm_mtrr *mtrr_state)
return mtrr_state->deftype & IA32_MTRR_DEF_TYPE_TYPE_MASK;
}
-static u8 mtrr_disabled_type(void)
+static u8 mtrr_disabled_type(struct kvm_vcpu *vcpu)
{
/*
* Intel SDM 11.11.2.2: all MTRRs are disabled when
* IA32_MTRR_DEF_TYPE.E bit is cleared, and the UC
* memory type is applied to all of physical memory.
+ *
+ * However, virtual machines can be run with CPUID such that
+ * there are no MTRRs. In that case, the firmware will never
+ * enable MTRRs and it is obviously undesirable to run the
+ * guest entirely with UC memory and we use WB.
*/
- return MTRR_TYPE_UNCACHABLE;
+ if (guest_cpuid_has_mtrr(vcpu))
+ return MTRR_TYPE_UNCACHABLE;
+ else
+ return MTRR_TYPE_WRBACK;
}
/*
@@ -267,7 +275,7 @@ static int fixed_mtrr_addr_to_seg(u64 addr)
for (seg = 0; seg < seg_num; seg++) {
mtrr_seg = &fixed_seg_table[seg];
- if (mtrr_seg->start >= addr && addr < mtrr_seg->end)
+ if (mtrr_seg->start <= addr && addr < mtrr_seg->end)
return seg;
}
@@ -300,7 +308,6 @@ static void var_mtrr_range(struct kvm_mtrr_range *range, u64 *start, u64 *end)
*start = range->base & PAGE_MASK;
mask = range->mask & PAGE_MASK;
- mask |= ~0ULL << boot_cpu_data.x86_phys_bits;
/* This cannot overflow because writing to the reserved bits of
* variable MTRRs causes a #GP.
@@ -356,10 +363,14 @@ static void set_var_mtrr_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data)
if (var_mtrr_range_is_valid(cur))
list_del(&mtrr_state->var_ranges[index].node);
+ /* Extend the mask with all 1 bits to the left, since those
+ * bits must implicitly be 0. The bits are then cleared
+ * when reading them.
+ */
if (!is_mtrr_mask)
cur->base = data;
else
- cur->mask = data;
+ cur->mask = data | (-1LL << cpuid_maxphyaddr(vcpu));
/* add it to the list if it's enabled. */
if (var_mtrr_range_is_valid(cur)) {
@@ -426,6 +437,8 @@ int kvm_mtrr_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata)
*pdata = vcpu->arch.mtrr_state.var_ranges[index].base;
else
*pdata = vcpu->arch.mtrr_state.var_ranges[index].mask;
+
+ *pdata &= (1ULL << cpuid_maxphyaddr(vcpu)) - 1;
}
return 0;
@@ -670,7 +683,7 @@ u8 kvm_mtrr_get_guest_memory_type(struct kvm_vcpu *vcpu, gfn_t gfn)
}
if (iter.mtrr_disabled)
- return mtrr_disabled_type();
+ return mtrr_disabled_type(vcpu);
/* not contained in any MTRRs. */
if (type == -1)
diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index b41faa9..91e939b 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -475,8 +475,8 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
* we call mmu_set_spte() with host_writable = true because
* pte_prefetch_gfn_to_pfn always gets a writable pfn.
*/
- mmu_set_spte(vcpu, spte, pte_access, 0, NULL, PT_PAGE_TABLE_LEVEL,
- gfn, pfn, true, true);
+ mmu_set_spte(vcpu, spte, pte_access, 0, PT_PAGE_TABLE_LEVEL, gfn, pfn,
+ true, true);
return true;
}
@@ -556,7 +556,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
struct kvm_mmu_page *sp = NULL;
struct kvm_shadow_walk_iterator it;
unsigned direct_access, access = gw->pt_access;
- int top_level, emulate = 0;
+ int top_level, emulate;
direct_access = gw->pte_access;
@@ -587,7 +587,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
if (!is_shadow_present_pte(*it.sptep)) {
table_gfn = gw->table_gfn[it.level - 2];
sp = kvm_mmu_get_page(vcpu, table_gfn, addr, it.level-1,
- false, access, it.sptep);
+ false, access);
}
/*
@@ -598,7 +598,7 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
goto out_gpte_changed;
if (sp)
- link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+ link_shadow_page(vcpu, it.sptep, sp);
}
for (;
@@ -617,20 +617,18 @@ static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
direct_gfn = gw->gfn & ~(KVM_PAGES_PER_HPAGE(it.level) - 1);
sp = kvm_mmu_get_page(vcpu, direct_gfn, addr, it.level-1,
- true, direct_access, it.sptep);
- link_shadow_page(it.sptep, sp, PT_GUEST_ACCESSED_MASK);
+ true, direct_access);
+ link_shadow_page(vcpu, it.sptep, sp);
}
clear_sp_write_flooding_count(it.sptep);
- mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault, &emulate,
- it.level, gw->gfn, pfn, prefault, map_writable);
+ emulate = mmu_set_spte(vcpu, it.sptep, gw->pte_access, write_fault,
+ it.level, gw->gfn, pfn, prefault, map_writable);
FNAME(pte_prefetch)(vcpu, gw, it.sptep);
return emulate;
out_gpte_changed:
- if (sp)
- kvm_mmu_put_page(sp, it.sptep);
kvm_release_pfn_clean(pfn);
return 0;
}
@@ -705,8 +703,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
pgprintk("%s: addr %lx err %x\n", __func__, addr, error_code);
if (unlikely(error_code & PFERR_RSVD_MASK)) {
- r = handle_mmio_page_fault(vcpu, addr, error_code,
- mmu_is_nested(vcpu));
+ r = handle_mmio_page_fault(vcpu, addr, mmu_is_nested(vcpu));
if (likely(r != RET_MMIO_PF_INVALID))
return r;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index f2c8e49..c13a64b 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -86,6 +86,7 @@ static const u32 host_save_user_msrs[] = {
MSR_FS_BASE,
#endif
MSR_IA32_SYSENTER_CS, MSR_IA32_SYSENTER_ESP, MSR_IA32_SYSENTER_EIP,
+ MSR_TSC_AUX,
};
#define NR_HOST_SAVE_USER_MSRS ARRAY_SIZE(host_save_user_msrs)
@@ -135,6 +136,7 @@ struct vcpu_svm {
uint64_t asid_generation;
uint64_t sysenter_esp;
uint64_t sysenter_eip;
+ uint64_t tsc_aux;
u64 next_rip;
@@ -158,8 +160,6 @@ struct vcpu_svm {
unsigned long int3_rip;
u32 apf_reason;
- u64 tsc_ratio;
-
/* cached guest cpuid flags for faster access */
bool nrips_enabled : 1;
};
@@ -214,7 +214,6 @@ static int nested_svm_intercept(struct vcpu_svm *svm);
static int nested_svm_vmexit(struct vcpu_svm *svm);
static int nested_svm_check_exception(struct vcpu_svm *svm, unsigned nr,
bool has_error_code, u32 error_code);
-static u64 __scale_tsc(u64 ratio, u64 tsc);
enum {
VMCB_INTERCEPTS, /* Intercept vectors, TSC offset,
@@ -894,20 +893,9 @@ static __init int svm_hardware_setup(void)
kvm_enable_efer_bits(EFER_FFXSR);
if (boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
- u64 max;
-
kvm_has_tsc_control = true;
-
- /*
- * Make sure the user can only configure tsc_khz values that
- * fit into a signed integer.
- * A min value is not calculated needed because it will always
- * be 1 on all machines and a value of 0 is used to disable
- * tsc-scaling for the vcpu.
- */
- max = min(0x7fffffffULL, __scale_tsc(tsc_khz, TSC_RATIO_MAX));
-
- kvm_max_guest_tsc_khz = max;
+ kvm_max_tsc_scaling_ratio = TSC_RATIO_MAX;
+ kvm_tsc_scaling_ratio_frac_bits = 32;
}
if (nested) {
@@ -971,68 +959,6 @@ static void init_sys_seg(struct vmcb_seg *seg, uint32_t type)
seg->base = 0;
}
-static u64 __scale_tsc(u64 ratio, u64 tsc)
-{
- u64 mult, frac, _tsc;
-
- mult = ratio >> 32;
- frac = ratio & ((1ULL << 32) - 1);
-
- _tsc = tsc;
- _tsc *= mult;
- _tsc += (tsc >> 32) * frac;
- _tsc += ((tsc & ((1ULL << 32) - 1)) * frac) >> 32;
-
- return _tsc;
-}
-
-static u64 svm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
-{
- struct vcpu_svm *svm = to_svm(vcpu);
- u64 _tsc = tsc;
-
- if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
- _tsc = __scale_tsc(svm->tsc_ratio, tsc);
-
- return _tsc;
-}
-
-static void svm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
-{
- struct vcpu_svm *svm = to_svm(vcpu);
- u64 ratio;
- u64 khz;
-
- /* Guest TSC same frequency as host TSC? */
- if (!scale) {
- svm->tsc_ratio = TSC_RATIO_DEFAULT;
- return;
- }
-
- /* TSC scaling supported? */
- if (!boot_cpu_has(X86_FEATURE_TSCRATEMSR)) {
- if (user_tsc_khz > tsc_khz) {
- vcpu->arch.tsc_catchup = 1;
- vcpu->arch.tsc_always_catchup = 1;
- } else
- WARN(1, "user requested TSC rate below hardware speed\n");
- return;
- }
-
- khz = user_tsc_khz;
-
- /* TSC scaling required - calculate ratio */
- ratio = khz << 32;
- do_div(ratio, tsc_khz);
-
- if (ratio == 0 || ratio & TSC_RATIO_RSVD) {
- WARN_ONCE(1, "Invalid TSC ratio - virtual-tsc-khz=%u\n",
- user_tsc_khz);
- return;
- }
- svm->tsc_ratio = ratio;
-}
-
static u64 svm_read_tsc_offset(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1059,16 +985,10 @@ static void svm_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
}
-static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
+static void svm_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
{
struct vcpu_svm *svm = to_svm(vcpu);
- if (host) {
- if (svm->tsc_ratio != TSC_RATIO_DEFAULT)
- WARN_ON(adjustment < 0);
- adjustment = svm_scale_tsc(vcpu, (u64)adjustment);
- }
-
svm->vmcb->control.tsc_offset += adjustment;
if (is_guest_mode(vcpu))
svm->nested.hsave->control.tsc_offset += adjustment;
@@ -1080,15 +1000,6 @@ static void svm_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
mark_dirty(svm->vmcb, VMCB_INTERCEPTS);
}
-static u64 svm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
-{
- u64 tsc;
-
- tsc = svm_scale_tsc(vcpu, rdtsc());
-
- return target_tsc - tsc;
-}
-
static void init_vmcb(struct vcpu_svm *svm)
{
struct vmcb_control_area *control = &svm->vmcb->control;
@@ -1110,6 +1021,8 @@ static void init_vmcb(struct vcpu_svm *svm)
set_exception_intercept(svm, PF_VECTOR);
set_exception_intercept(svm, UD_VECTOR);
set_exception_intercept(svm, MC_VECTOR);
+ set_exception_intercept(svm, AC_VECTOR);
+ set_exception_intercept(svm, DB_VECTOR);
set_intercept(svm, INTERCEPT_INTR);
set_intercept(svm, INTERCEPT_NMI);
@@ -1235,8 +1148,6 @@ static struct kvm_vcpu *svm_create_vcpu(struct kvm *kvm, unsigned int id)
goto out;
}
- svm->tsc_ratio = TSC_RATIO_DEFAULT;
-
err = kvm_vcpu_init(&svm->vcpu, kvm, id);
if (err)
goto free_svm;
@@ -1322,11 +1233,16 @@ static void svm_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
for (i = 0; i < NR_HOST_SAVE_USER_MSRS; i++)
rdmsrl(host_save_user_msrs[i], svm->host_user_msrs[i]);
- if (static_cpu_has(X86_FEATURE_TSCRATEMSR) &&
- svm->tsc_ratio != __this_cpu_read(current_tsc_ratio)) {
- __this_cpu_write(current_tsc_ratio, svm->tsc_ratio);
- wrmsrl(MSR_AMD64_TSC_RATIO, svm->tsc_ratio);
+ if (static_cpu_has(X86_FEATURE_TSCRATEMSR)) {
+ u64 tsc_ratio = vcpu->arch.tsc_scaling_ratio;
+ if (tsc_ratio != __this_cpu_read(current_tsc_ratio)) {
+ __this_cpu_write(current_tsc_ratio, tsc_ratio);
+ wrmsrl(MSR_AMD64_TSC_RATIO, tsc_ratio);
+ }
}
+ /* This assumes that the kernel never uses MSR_TSC_AUX */
+ if (static_cpu_has(X86_FEATURE_RDTSCP))
+ wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
}
static void svm_vcpu_put(struct kvm_vcpu *vcpu)
@@ -1644,20 +1560,13 @@ static void svm_set_segment(struct kvm_vcpu *vcpu,
mark_dirty(svm->vmcb, VMCB_SEG);
}
-static void update_db_bp_intercept(struct kvm_vcpu *vcpu)
+static void update_bp_intercept(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
- clr_exception_intercept(svm, DB_VECTOR);
clr_exception_intercept(svm, BP_VECTOR);
- if (svm->nmi_singlestep)
- set_exception_intercept(svm, DB_VECTOR);
-
if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) {
- if (vcpu->guest_debug &
- (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))
- set_exception_intercept(svm, DB_VECTOR);
if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP)
set_exception_intercept(svm, BP_VECTOR);
} else
@@ -1763,7 +1672,6 @@ static int db_interception(struct vcpu_svm *svm)
if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP))
svm->vmcb->save.rflags &=
~(X86_EFLAGS_TF | X86_EFLAGS_RF);
- update_db_bp_intercept(&svm->vcpu);
}
if (svm->vcpu.guest_debug &
@@ -1798,6 +1706,12 @@ static int ud_interception(struct vcpu_svm *svm)
return 1;
}
+static int ac_interception(struct vcpu_svm *svm)
+{
+ kvm_queue_exception_e(&svm->vcpu, AC_VECTOR, 0);
+ return 1;
+}
+
static void svm_fpu_activate(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);
@@ -3075,8 +2989,7 @@ static int cr8_write_interception(struct vcpu_svm *svm)
static u64 svm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
{
struct vmcb *vmcb = get_host_vmcb(to_svm(vcpu));
- return vmcb->control.tsc_offset +
- svm_scale_tsc(vcpu, host_tsc);
+ return vmcb->control.tsc_offset + host_tsc;
}
static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
@@ -3086,7 +2999,7 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
switch (msr_info->index) {
case MSR_IA32_TSC: {
msr_info->data = svm->vmcb->control.tsc_offset +
- svm_scale_tsc(vcpu, rdtsc());
+ kvm_scale_tsc(vcpu, rdtsc());
break;
}
@@ -3116,6 +3029,11 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_SYSENTER_ESP:
msr_info->data = svm->sysenter_esp;
break;
+ case MSR_TSC_AUX:
+ if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+ return 1;
+ msr_info->data = svm->tsc_aux;
+ break;
/*
* Nobody will change the following 5 values in the VMCB so we can
* safely return them on rdmsr. They will always be 0 until LBRV is
@@ -3145,6 +3063,23 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_IA32_UCODE_REV:
msr_info->data = 0x01000065;
break;
+ case MSR_F15H_IC_CFG: {
+
+ int family, model;
+
+ family = guest_cpuid_family(vcpu);
+ model = guest_cpuid_model(vcpu);
+
+ if (family < 0 || model < 0)
+ return kvm_get_msr_common(vcpu, msr_info);
+
+ msr_info->data = 0;
+
+ if (family == 0x15 &&
+ (model >= 0x2 && model < 0x20))
+ msr_info->data = 0x1E;
+ }
+ break;
default:
return kvm_get_msr_common(vcpu, msr_info);
}
@@ -3237,6 +3172,18 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
svm->sysenter_esp = data;
svm->vmcb->save.sysenter_esp = data;
break;
+ case MSR_TSC_AUX:
+ if (!boot_cpu_has(X86_FEATURE_RDTSCP))
+ return 1;
+
+ /*
+ * This is rare, so we update the MSR here instead of using
+ * direct_access_msrs. Doing that would require a rdmsr in
+ * svm_vcpu_put.
+ */
+ svm->tsc_aux = data;
+ wrmsrl(MSR_TSC_AUX, svm->tsc_aux);
+ break;
case MSR_IA32_DEBUGCTLMSR:
if (!boot_cpu_has(X86_FEATURE_LBRV)) {
vcpu_unimpl(vcpu, "%s: MSR_IA32_DEBUGCTL 0x%llx, nop\n",
@@ -3362,6 +3309,7 @@ static int (*const svm_exit_handlers[])(struct vcpu_svm *svm) = {
[SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception,
[SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception,
[SVM_EXIT_EXCP_BASE + MC_VECTOR] = mc_interception,
+ [SVM_EXIT_EXCP_BASE + AC_VECTOR] = ac_interception,
[SVM_EXIT_INTR] = intr_interception,
[SVM_EXIT_NMI] = nmi_interception,
[SVM_EXIT_SMI] = nop_on_interception,
@@ -3513,6 +3461,8 @@ static int handle_exit(struct kvm_vcpu *vcpu)
struct kvm_run *kvm_run = vcpu->run;
u32 exit_code = svm->vmcb->control.exit_code;
+ trace_kvm_exit(exit_code, vcpu, KVM_ISA_SVM);
+
if (!is_cr_intercept(svm, INTERCEPT_CR0_WRITE))
vcpu->arch.cr0 = svm->vmcb->save.cr0;
if (npt_enabled)
@@ -3650,12 +3600,16 @@ static void svm_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
return;
}
-static int svm_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static bool svm_get_enable_apicv(void)
+{
+ return false;
+}
+
+static void svm_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
{
- return 0;
}
-static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void svm_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
{
return;
}
@@ -3745,7 +3699,6 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
*/
svm->nmi_singlestep = true;
svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
- update_db_bp_intercept(vcpu);
}
static int svm_set_tss_addr(struct kvm *kvm, unsigned int addr)
@@ -3984,8 +3937,6 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
vcpu->arch.regs[VCPU_REGS_RSP] = svm->vmcb->save.rsp;
vcpu->arch.regs[VCPU_REGS_RIP] = svm->vmcb->save.rip;
- trace_kvm_exit(svm->vmcb->control.exit_code, vcpu, KVM_ISA_SVM);
-
if (unlikely(svm->vmcb->control.exit_code == SVM_EXIT_NMI))
kvm_before_handle_nmi(&svm->vcpu);
@@ -4129,7 +4080,7 @@ static int svm_get_lpage_level(void)
static bool svm_rdtscp_supported(void)
{
- return false;
+ return boot_cpu_has(X86_FEATURE_RDTSCP);
}
static bool svm_invpcid_supported(void)
@@ -4371,7 +4322,7 @@ static struct kvm_x86_ops svm_x86_ops = {
.vcpu_load = svm_vcpu_load,
.vcpu_put = svm_vcpu_put,
- .update_db_bp_intercept = update_db_bp_intercept,
+ .update_bp_intercept = update_bp_intercept,
.get_msr = svm_get_msr,
.set_msr = svm_set_msr,
.get_segment_base = svm_get_segment_base,
@@ -4420,7 +4371,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.enable_irq_window = enable_irq_window,
.update_cr8_intercept = update_cr8_intercept,
.set_virtual_x2apic_mode = svm_set_virtual_x2apic_mode,
- .cpu_uses_apicv = svm_cpu_uses_apicv,
+ .get_enable_apicv = svm_get_enable_apicv,
+ .refresh_apicv_exec_ctrl = svm_refresh_apicv_exec_ctrl,
.load_eoi_exitmap = svm_load_eoi_exitmap,
.sync_pir_to_irr = svm_sync_pir_to_irr,
@@ -4443,11 +4395,9 @@ static struct kvm_x86_ops svm_x86_ops = {
.has_wbinvd_exit = svm_has_wbinvd_exit,
- .set_tsc_khz = svm_set_tsc_khz,
.read_tsc_offset = svm_read_tsc_offset,
.write_tsc_offset = svm_write_tsc_offset,
- .adjust_tsc_offset = svm_adjust_tsc_offset,
- .compute_tsc_offset = svm_compute_tsc_offset,
+ .adjust_tsc_offset_guest = svm_adjust_tsc_offset_guest,
.read_l1_tsc = svm_read_l1_tsc,
.set_tdp_cr3 = set_tdp_cr3,
diff --git a/arch/x86/kvm/trace.h b/arch/x86/kvm/trace.h
index 1203025..ad9f6a2 100644
--- a/arch/x86/kvm/trace.h
+++ b/arch/x86/kvm/trace.h
@@ -268,7 +268,7 @@ TRACE_EVENT(kvm_inj_virq,
#define kvm_trace_sym_exc \
EXS(DE), EXS(DB), EXS(BP), EXS(OF), EXS(BR), EXS(UD), EXS(NM), \
EXS(DF), EXS(TS), EXS(NP), EXS(SS), EXS(GP), EXS(PF), \
- EXS(MF), EXS(MC)
+ EXS(MF), EXS(AC), EXS(MC)
/*
* Tracepoint for kvm interrupt injection:
@@ -1025,6 +1025,269 @@ TRACE_EVENT(kvm_pi_irte_update,
__entry->pi_desc_addr)
);
+/*
+ * Tracepoint for kvm_hv_notify_acked_sint.
+ */
+TRACE_EVENT(kvm_hv_notify_acked_sint,
+ TP_PROTO(int vcpu_id, u32 sint),
+ TP_ARGS(vcpu_id, sint),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(u32, sint)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->sint = sint;
+ ),
+
+ TP_printk("vcpu_id %d sint %u", __entry->vcpu_id, __entry->sint)
+);
+
+/*
+ * Tracepoint for synic_set_irq.
+ */
+TRACE_EVENT(kvm_hv_synic_set_irq,
+ TP_PROTO(int vcpu_id, u32 sint, int vector, int ret),
+ TP_ARGS(vcpu_id, sint, vector, ret),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(u32, sint)
+ __field(int, vector)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->sint = sint;
+ __entry->vector = vector;
+ __entry->ret = ret;
+ ),
+
+ TP_printk("vcpu_id %d sint %u vector %d ret %d",
+ __entry->vcpu_id, __entry->sint, __entry->vector,
+ __entry->ret)
+);
+
+/*
+ * Tracepoint for kvm_hv_synic_send_eoi.
+ */
+TRACE_EVENT(kvm_hv_synic_send_eoi,
+ TP_PROTO(int vcpu_id, int vector),
+ TP_ARGS(vcpu_id, vector),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(u32, sint)
+ __field(int, vector)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->vector = vector;
+ ),
+
+ TP_printk("vcpu_id %d vector %d", __entry->vcpu_id, __entry->vector)
+);
+
+/*
+ * Tracepoint for synic_set_msr.
+ */
+TRACE_EVENT(kvm_hv_synic_set_msr,
+ TP_PROTO(int vcpu_id, u32 msr, u64 data, bool host),
+ TP_ARGS(vcpu_id, msr, data, host),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(u32, msr)
+ __field(u64, data)
+ __field(bool, host)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->msr = msr;
+ __entry->data = data;
+ __entry->host = host
+ ),
+
+ TP_printk("vcpu_id %d msr 0x%x data 0x%llx host %d",
+ __entry->vcpu_id, __entry->msr, __entry->data, __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_set_config.
+ */
+TRACE_EVENT(kvm_hv_stimer_set_config,
+ TP_PROTO(int vcpu_id, int timer_index, u64 config, bool host),
+ TP_ARGS(vcpu_id, timer_index, config, host),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ __field(u64, config)
+ __field(bool, host)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ __entry->config = config;
+ __entry->host = host;
+ ),
+
+ TP_printk("vcpu_id %d timer %d config 0x%llx host %d",
+ __entry->vcpu_id, __entry->timer_index, __entry->config,
+ __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_set_count.
+ */
+TRACE_EVENT(kvm_hv_stimer_set_count,
+ TP_PROTO(int vcpu_id, int timer_index, u64 count, bool host),
+ TP_ARGS(vcpu_id, timer_index, count, host),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ __field(u64, count)
+ __field(bool, host)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ __entry->count = count;
+ __entry->host = host;
+ ),
+
+ TP_printk("vcpu_id %d timer %d count %llu host %d",
+ __entry->vcpu_id, __entry->timer_index, __entry->count,
+ __entry->host)
+);
+
+/*
+ * Tracepoint for stimer_start(periodic timer case).
+ */
+TRACE_EVENT(kvm_hv_stimer_start_periodic,
+ TP_PROTO(int vcpu_id, int timer_index, u64 time_now, u64 exp_time),
+ TP_ARGS(vcpu_id, timer_index, time_now, exp_time),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ __field(u64, time_now)
+ __field(u64, exp_time)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ __entry->time_now = time_now;
+ __entry->exp_time = exp_time;
+ ),
+
+ TP_printk("vcpu_id %d timer %d time_now %llu exp_time %llu",
+ __entry->vcpu_id, __entry->timer_index, __entry->time_now,
+ __entry->exp_time)
+);
+
+/*
+ * Tracepoint for stimer_start(one-shot timer case).
+ */
+TRACE_EVENT(kvm_hv_stimer_start_one_shot,
+ TP_PROTO(int vcpu_id, int timer_index, u64 time_now, u64 count),
+ TP_ARGS(vcpu_id, timer_index, time_now, count),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ __field(u64, time_now)
+ __field(u64, count)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ __entry->time_now = time_now;
+ __entry->count = count;
+ ),
+
+ TP_printk("vcpu_id %d timer %d time_now %llu count %llu",
+ __entry->vcpu_id, __entry->timer_index, __entry->time_now,
+ __entry->count)
+);
+
+/*
+ * Tracepoint for stimer_timer_callback.
+ */
+TRACE_EVENT(kvm_hv_stimer_callback,
+ TP_PROTO(int vcpu_id, int timer_index),
+ TP_ARGS(vcpu_id, timer_index),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ ),
+
+ TP_printk("vcpu_id %d timer %d",
+ __entry->vcpu_id, __entry->timer_index)
+);
+
+/*
+ * Tracepoint for stimer_expiration.
+ */
+TRACE_EVENT(kvm_hv_stimer_expiration,
+ TP_PROTO(int vcpu_id, int timer_index, int msg_send_result),
+ TP_ARGS(vcpu_id, timer_index, msg_send_result),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ __field(int, msg_send_result)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ __entry->msg_send_result = msg_send_result;
+ ),
+
+ TP_printk("vcpu_id %d timer %d msg send result %d",
+ __entry->vcpu_id, __entry->timer_index,
+ __entry->msg_send_result)
+);
+
+/*
+ * Tracepoint for stimer_cleanup.
+ */
+TRACE_EVENT(kvm_hv_stimer_cleanup,
+ TP_PROTO(int vcpu_id, int timer_index),
+ TP_ARGS(vcpu_id, timer_index),
+
+ TP_STRUCT__entry(
+ __field(int, vcpu_id)
+ __field(int, timer_index)
+ ),
+
+ TP_fast_assign(
+ __entry->vcpu_id = vcpu_id;
+ __entry->timer_index = timer_index;
+ ),
+
+ TP_printk("vcpu_id %d timer %d",
+ __entry->vcpu_id, __entry->timer_index)
+);
+
#endif /* _TRACE_KVM_H */
#undef TRACE_INCLUDE_PATH
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 5eb56ed..04d61d4 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -19,6 +19,7 @@
#include "irq.h"
#include "mmu.h"
#include "cpuid.h"
+#include "lapic.h"
#include <linux/kvm_host.h>
#include <linux/module.h>
@@ -107,6 +108,8 @@ static u64 __read_mostly host_xss;
static bool __read_mostly enable_pml = 1;
module_param_named(pml, enable_pml, bool, S_IRUGO);
+#define KVM_VMX_TSC_MULTIPLIER_MAX 0xffffffffffffffffULL
+
#define KVM_GUEST_CR0_MASK (X86_CR0_NW | X86_CR0_CD)
#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST (X86_CR0_WP | X86_CR0_NE)
#define KVM_VM_CR0_ALWAYS_ON \
@@ -860,7 +863,6 @@ static void kvm_cpu_vmxon(u64 addr);
static void kvm_cpu_vmxoff(void);
static bool vmx_mpx_supported(void);
static bool vmx_xsaves_supported(void);
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu);
static int vmx_set_tss_addr(struct kvm *kvm, unsigned int addr);
static void vmx_set_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
@@ -868,7 +870,6 @@ static void vmx_get_segment(struct kvm_vcpu *vcpu,
struct kvm_segment *var, int seg);
static bool guest_state_valid(struct kvm_vcpu *vcpu);
static u32 vmx_segment_access_rights(struct kvm_segment *var);
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu);
static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx);
static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx);
static int alloc_identity_pagetable(struct kvm *kvm);
@@ -1172,6 +1173,12 @@ static inline bool cpu_has_vmx_pml(void)
return vmcs_config.cpu_based_2nd_exec_ctrl & SECONDARY_EXEC_ENABLE_PML;
}
+static inline bool cpu_has_vmx_tsc_scaling(void)
+{
+ return vmcs_config.cpu_based_2nd_exec_ctrl &
+ SECONDARY_EXEC_TSC_SCALING;
+}
+
static inline bool report_flexpriority(void)
{
return flexpriority_enabled;
@@ -1440,7 +1447,51 @@ static inline void ept_sync_context(u64 eptp)
}
}
-static __always_inline unsigned long vmcs_readl(unsigned long field)
+static __always_inline void vmcs_check16(unsigned long field)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
+ "16-bit accessor invalid for 64-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+ "16-bit accessor invalid for 64-bit high field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+ "16-bit accessor invalid for 32-bit high field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+ "16-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check32(unsigned long field)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+ "32-bit accessor invalid for 16-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+ "32-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_check64(unsigned long field)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+ "64-bit accessor invalid for 16-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+ "64-bit accessor invalid for 64-bit high field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+ "64-bit accessor invalid for 32-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x6000,
+ "64-bit accessor invalid for natural width field");
+}
+
+static __always_inline void vmcs_checkl(unsigned long field)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0,
+ "Natural width accessor invalid for 16-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2000,
+ "Natural width accessor invalid for 64-bit field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6001) == 0x2001,
+ "Natural width accessor invalid for 64-bit high field");
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x4000,
+ "Natural width accessor invalid for 32-bit field");
+}
+
+static __always_inline unsigned long __vmcs_readl(unsigned long field)
{
unsigned long value;
@@ -1451,23 +1502,32 @@ static __always_inline unsigned long vmcs_readl(unsigned long field)
static __always_inline u16 vmcs_read16(unsigned long field)
{
- return vmcs_readl(field);
+ vmcs_check16(field);
+ return __vmcs_readl(field);
}
static __always_inline u32 vmcs_read32(unsigned long field)
{
- return vmcs_readl(field);
+ vmcs_check32(field);
+ return __vmcs_readl(field);
}
static __always_inline u64 vmcs_read64(unsigned long field)
{
+ vmcs_check64(field);
#ifdef CONFIG_X86_64
- return vmcs_readl(field);
+ return __vmcs_readl(field);
#else
- return vmcs_readl(field) | ((u64)vmcs_readl(field+1) << 32);
+ return __vmcs_readl(field) | ((u64)__vmcs_readl(field+1) << 32);
#endif
}
+static __always_inline unsigned long vmcs_readl(unsigned long field)
+{
+ vmcs_checkl(field);
+ return __vmcs_readl(field);
+}
+
static noinline void vmwrite_error(unsigned long field, unsigned long value)
{
printk(KERN_ERR "vmwrite error: reg %lx value %lx (err %d)\n",
@@ -1475,7 +1535,7 @@ static noinline void vmwrite_error(unsigned long field, unsigned long value)
dump_stack();
}
-static void vmcs_writel(unsigned long field, unsigned long value)
+static __always_inline void __vmcs_writel(unsigned long field, unsigned long value)
{
u8 error;
@@ -1485,33 +1545,46 @@ static void vmcs_writel(unsigned long field, unsigned long value)
vmwrite_error(field, value);
}
-static void vmcs_write16(unsigned long field, u16 value)
+static __always_inline void vmcs_write16(unsigned long field, u16 value)
{
- vmcs_writel(field, value);
+ vmcs_check16(field);
+ __vmcs_writel(field, value);
}
-static void vmcs_write32(unsigned long field, u32 value)
+static __always_inline void vmcs_write32(unsigned long field, u32 value)
{
- vmcs_writel(field, value);
+ vmcs_check32(field);
+ __vmcs_writel(field, value);
}
-static void vmcs_write64(unsigned long field, u64 value)
+static __always_inline void vmcs_write64(unsigned long field, u64 value)
{
- vmcs_writel(field, value);
+ vmcs_check64(field);
+ __vmcs_writel(field, value);
#ifndef CONFIG_X86_64
asm volatile ("");
- vmcs_writel(field+1, value >> 32);
+ __vmcs_writel(field+1, value >> 32);
#endif
}
-static void vmcs_clear_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_writel(unsigned long field, unsigned long value)
{
- vmcs_writel(field, vmcs_readl(field) & ~mask);
+ vmcs_checkl(field);
+ __vmcs_writel(field, value);
}
-static void vmcs_set_bits(unsigned long field, u32 mask)
+static __always_inline void vmcs_clear_bits(unsigned long field, u32 mask)
{
- vmcs_writel(field, vmcs_readl(field) | mask);
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
+ "vmcs_clear_bits does not support 64-bit fields");
+ __vmcs_writel(field, __vmcs_readl(field) & ~mask);
+}
+
+static __always_inline void vmcs_set_bits(unsigned long field, u32 mask)
+{
+ BUILD_BUG_ON_MSG(__builtin_constant_p(field) && ((field) & 0x6000) == 0x2000,
+ "vmcs_set_bits does not support 64-bit fields");
+ __vmcs_writel(field, __vmcs_readl(field) | mask);
}
static inline void vm_entry_controls_init(struct vcpu_vmx *vmx, u32 val)
@@ -1631,7 +1704,7 @@ static void update_exception_bitmap(struct kvm_vcpu *vcpu)
u32 eb;
eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) |
- (1u << NM_VECTOR) | (1u << DB_VECTOR);
+ (1u << NM_VECTOR) | (1u << DB_VECTOR) | (1u << AC_VECTOR);
if ((vcpu->guest_debug &
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) ==
(KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP))
@@ -2053,6 +2126,12 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp);
vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */
+
+ /* Setup TSC multiplier */
+ if (cpu_has_vmx_tsc_scaling())
+ vmcs_write64(TSC_MULTIPLIER,
+ vcpu->arch.tsc_scaling_ratio);
+
vmx->loaded_vmcs->cpu = cpu;
}
@@ -2357,15 +2436,16 @@ static void setup_msrs(struct vcpu_vmx *vmx)
/*
* reads and returns guest's timestamp counter "register"
- * guest_tsc = host_tsc + tsc_offset -- 21.3
+ * guest_tsc = (host_tsc * tsc multiplier) >> 48 + tsc_offset
+ * -- Intel TSC Scaling for Virtualization White Paper, sec 1.3
*/
-static u64 guest_read_tsc(void)
+static u64 guest_read_tsc(struct kvm_vcpu *vcpu)
{
u64 host_tsc, tsc_offset;
host_tsc = rdtsc();
tsc_offset = vmcs_read64(TSC_OFFSET);
- return host_tsc + tsc_offset;
+ return kvm_scale_tsc(vcpu, host_tsc) + tsc_offset;
}
/*
@@ -2382,22 +2462,6 @@ static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
return host_tsc + tsc_offset;
}
-/*
- * Engage any workarounds for mis-matched TSC rates. Currently limited to
- * software catchup for faster rates on slower CPUs.
- */
-static void vmx_set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
-{
- if (!scale)
- return;
-
- if (user_tsc_khz > tsc_khz) {
- vcpu->arch.tsc_catchup = 1;
- vcpu->arch.tsc_always_catchup = 1;
- } else
- WARN(1, "user requested TSC rate below hardware speed\n");
-}
-
static u64 vmx_read_tsc_offset(struct kvm_vcpu *vcpu)
{
return vmcs_read64(TSC_OFFSET);
@@ -2429,7 +2493,7 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
}
}
-static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool host)
+static void vmx_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
{
u64 offset = vmcs_read64(TSC_OFFSET);
@@ -2442,11 +2506,6 @@ static void vmx_adjust_tsc_offset(struct kvm_vcpu *vcpu, s64 adjustment, bool ho
offset + adjustment);
}
-static u64 vmx_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
-{
- return target_tsc - rdtsc();
-}
-
static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
{
struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
@@ -2504,7 +2563,7 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx *vmx)
vmx->nested.nested_vmx_pinbased_ctls_high |=
PIN_BASED_ALWAYSON_WITHOUT_TRUE_MSR |
PIN_BASED_VMX_PREEMPTION_TIMER;
- if (vmx_cpu_uses_apicv(&vmx->vcpu))
+ if (kvm_vcpu_apicv_active(&vmx->vcpu))
vmx->nested.nested_vmx_pinbased_ctls_high |=
PIN_BASED_POSTED_INTR;
@@ -2778,7 +2837,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_EFER:
return kvm_get_msr_common(vcpu, msr_info);
case MSR_IA32_TSC:
- msr_info->data = guest_read_tsc();
+ msr_info->data = guest_read_tsc(vcpu);
break;
case MSR_IA32_SYSENTER_CS:
msr_info->data = vmcs_read32(GUEST_SYSENTER_CS);
@@ -2809,7 +2868,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
msr_info->data = vcpu->arch.ia32_xss;
break;
case MSR_TSC_AUX:
- if (!guest_cpuid_has_rdtscp(vcpu))
+ if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
return 1;
/* Otherwise falls through */
default:
@@ -2915,7 +2974,7 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
clear_atomic_switch_msr(vmx, MSR_IA32_XSS);
break;
case MSR_TSC_AUX:
- if (!guest_cpuid_has_rdtscp(vcpu))
+ if (!guest_cpuid_has_rdtscp(vcpu) && !msr_info->host_initiated)
return 1;
/* Check reserved bit, higher 32 bits should be zero */
if ((data >> 32) != 0)
@@ -3154,7 +3213,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
SECONDARY_EXEC_SHADOW_VMCS |
SECONDARY_EXEC_XSAVES |
SECONDARY_EXEC_ENABLE_PML |
- SECONDARY_EXEC_PCOMMIT;
+ SECONDARY_EXEC_PCOMMIT |
+ SECONDARY_EXEC_TSC_SCALING;
if (adjust_vmx_controls(min2, opt2,
MSR_IA32_VMX_PROCBASED_CTLS2,
&_cpu_based_2nd_exec_control) < 0)
@@ -4467,9 +4527,9 @@ static void vmx_disable_intercept_msr_write_x2apic(u32 msr)
msr, MSR_TYPE_W);
}
-static int vmx_cpu_uses_apicv(struct kvm_vcpu *vcpu)
+static bool vmx_get_enable_apicv(void)
{
- return enable_apicv && lapic_in_kernel(vcpu);
+ return enable_apicv;
}
static int vmx_complete_nested_posted_interrupt(struct kvm_vcpu *vcpu)
@@ -4591,11 +4651,6 @@ static void vmx_sync_pir_to_irr(struct kvm_vcpu *vcpu)
kvm_apic_update_irr(vcpu, vmx->pi_desc.pir);
}
-static void vmx_sync_pir_to_irr_dummy(struct kvm_vcpu *vcpu)
-{
- return;
-}
-
/*
* Set up the vmcs's constant host-state fields, i.e., host-state fields that
* will not change in the lifetime of the guest.
@@ -4665,11 +4720,18 @@ static u32 vmx_pin_based_exec_ctrl(struct vcpu_vmx *vmx)
{
u32 pin_based_exec_ctrl = vmcs_config.pin_based_exec_ctrl;
- if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+ if (!kvm_vcpu_apicv_active(&vmx->vcpu))
pin_based_exec_ctrl &= ~PIN_BASED_POSTED_INTR;
return pin_based_exec_ctrl;
}
+static void vmx_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu)
+{
+ struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+ vmcs_write32(PIN_BASED_VM_EXEC_CONTROL, vmx_pin_based_exec_ctrl(vmx));
+}
+
static u32 vmx_exec_control(struct vcpu_vmx *vmx)
{
u32 exec_control = vmcs_config.cpu_based_exec_ctrl;
@@ -4708,7 +4770,7 @@ static u32 vmx_secondary_exec_control(struct vcpu_vmx *vmx)
exec_control &= ~SECONDARY_EXEC_UNRESTRICTED_GUEST;
if (!ple_gap)
exec_control &= ~SECONDARY_EXEC_PAUSE_LOOP_EXITING;
- if (!vmx_cpu_uses_apicv(&vmx->vcpu))
+ if (!kvm_vcpu_apicv_active(&vmx->vcpu))
exec_control &= ~(SECONDARY_EXEC_APIC_REGISTER_VIRT |
SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY);
exec_control &= ~SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE;
@@ -4772,7 +4834,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
vmx_secondary_exec_control(vmx));
- if (vmx_cpu_uses_apicv(&vmx->vcpu)) {
+ if (kvm_vcpu_apicv_active(&vmx->vcpu)) {
vmcs_write64(EOI_EXIT_BITMAP0, 0);
vmcs_write64(EOI_EXIT_BITMAP1, 0);
vmcs_write64(EOI_EXIT_BITMAP2, 0);
@@ -4780,7 +4842,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
vmcs_write16(GUEST_INTR_STATUS, 0);
- vmcs_write64(POSTED_INTR_NV, POSTED_INTR_VECTOR);
+ vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
vmcs_write64(POSTED_INTR_DESC_ADDR, __pa((&vmx->pi_desc)));
}
@@ -4872,7 +4934,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
seg_setup(VCPU_SREG_CS);
vmcs_write16(GUEST_CS_SELECTOR, 0xf000);
- vmcs_write32(GUEST_CS_BASE, 0xffff0000);
+ vmcs_writel(GUEST_CS_BASE, 0xffff0000ul);
seg_setup(VCPU_SREG_DS);
seg_setup(VCPU_SREG_ES);
@@ -4908,7 +4970,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE);
vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, 0);
- vmcs_write32(GUEST_PENDING_DBG_EXCEPTIONS, 0);
+ vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, 0);
setup_msrs(vmx);
@@ -4924,7 +4986,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
- if (vmx_cpu_uses_apicv(vcpu))
+ if (kvm_vcpu_apicv_active(vcpu))
memset(&vmx->pi_desc, 0, sizeof(struct pi_desc));
if (vmx->vpid != 0)
@@ -5266,6 +5328,9 @@ static int handle_exception(struct kvm_vcpu *vcpu)
return handle_rmode_exception(vcpu, ex_no, error_code);
switch (ex_no) {
+ case AC_VECTOR:
+ kvm_queue_exception_e(vcpu, AC_VECTOR, error_code);
+ return 1;
case DB_VECTOR:
dr6 = vmcs_readl(EXIT_QUALIFICATION);
if (!(vcpu->guest_debug &
@@ -5908,7 +5973,7 @@ static int handle_ept_misconfig(struct kvm_vcpu *vcpu)
return 1;
}
- ret = handle_mmio_page_fault_common(vcpu, gpa, true);
+ ret = handle_mmio_page_fault(vcpu, gpa, true);
if (likely(ret == RET_MMIO_PF_EMULATE))
return x86_emulate_instruction(vcpu, gpa, 0, NULL, 0) ==
EMULATE_DONE;
@@ -6199,13 +6264,10 @@ static __init int hardware_setup(void)
if (!cpu_has_vmx_apicv())
enable_apicv = 0;
- if (enable_apicv)
- kvm_x86_ops->update_cr8_intercept = NULL;
- else {
- kvm_x86_ops->hwapic_irr_update = NULL;
- kvm_x86_ops->hwapic_isr_update = NULL;
- kvm_x86_ops->deliver_posted_interrupt = NULL;
- kvm_x86_ops->sync_pir_to_irr = vmx_sync_pir_to_irr_dummy;
+ if (cpu_has_vmx_tsc_scaling()) {
+ kvm_has_tsc_control = true;
+ kvm_max_tsc_scaling_ratio = KVM_VMX_TSC_MULTIPLIER_MAX;
+ kvm_tsc_scaling_ratio_frac_bits = 48;
}
vmx_disable_intercept_for_msr(MSR_FS_BASE, false);
@@ -7390,11 +7452,6 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
switch (type) {
case VMX_VPID_EXTENT_ALL_CONTEXT:
- if (get_vmcs12(vcpu)->virtual_processor_id == 0) {
- nested_vmx_failValid(vcpu,
- VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
- return 1;
- }
__vmx_flush_tlb(vcpu, to_vmx(vcpu)->nested.vpid02);
nested_vmx_succeed(vcpu);
break;
@@ -7902,7 +7959,7 @@ static void dump_vmcs(void)
u32 pin_based_exec_ctrl = vmcs_read32(PIN_BASED_VM_EXEC_CONTROL);
u32 secondary_exec_control = 0;
unsigned long cr4 = vmcs_readl(GUEST_CR4);
- u64 efer = vmcs_readl(GUEST_IA32_EFER);
+ u64 efer = vmcs_read64(GUEST_IA32_EFER);
int i, n;
if (cpu_has_secondary_exec_ctrls())
@@ -7918,10 +7975,10 @@ static void dump_vmcs(void)
if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT) &&
(cr4 & X86_CR4_PAE) && !(efer & EFER_LMA))
{
- pr_err("PDPTR0 = 0x%016lx PDPTR1 = 0x%016lx\n",
- vmcs_readl(GUEST_PDPTR0), vmcs_readl(GUEST_PDPTR1));
- pr_err("PDPTR2 = 0x%016lx PDPTR3 = 0x%016lx\n",
- vmcs_readl(GUEST_PDPTR2), vmcs_readl(GUEST_PDPTR3));
+ pr_err("PDPTR0 = 0x%016llx PDPTR1 = 0x%016llx\n",
+ vmcs_read64(GUEST_PDPTR0), vmcs_read64(GUEST_PDPTR1));
+ pr_err("PDPTR2 = 0x%016llx PDPTR3 = 0x%016llx\n",
+ vmcs_read64(GUEST_PDPTR2), vmcs_read64(GUEST_PDPTR3));
}
pr_err("RSP = 0x%016lx RIP = 0x%016lx\n",
vmcs_readl(GUEST_RSP), vmcs_readl(GUEST_RIP));
@@ -7942,16 +7999,16 @@ static void dump_vmcs(void)
vmx_dump_sel("TR: ", GUEST_TR_SELECTOR);
if ((vmexit_ctl & (VM_EXIT_SAVE_IA32_PAT | VM_EXIT_SAVE_IA32_EFER)) ||
(vmentry_ctl & (VM_ENTRY_LOAD_IA32_PAT | VM_ENTRY_LOAD_IA32_EFER)))
- pr_err("EFER = 0x%016llx PAT = 0x%016lx\n",
- efer, vmcs_readl(GUEST_IA32_PAT));
- pr_err("DebugCtl = 0x%016lx DebugExceptions = 0x%016lx\n",
- vmcs_readl(GUEST_IA32_DEBUGCTL),
+ pr_err("EFER = 0x%016llx PAT = 0x%016llx\n",
+ efer, vmcs_read64(GUEST_IA32_PAT));
+ pr_err("DebugCtl = 0x%016llx DebugExceptions = 0x%016lx\n",
+ vmcs_read64(GUEST_IA32_DEBUGCTL),
vmcs_readl(GUEST_PENDING_DBG_EXCEPTIONS));
if (vmentry_ctl & VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
- pr_err("PerfGlobCtl = 0x%016lx\n",
- vmcs_readl(GUEST_IA32_PERF_GLOBAL_CTRL));
+ pr_err("PerfGlobCtl = 0x%016llx\n",
+ vmcs_read64(GUEST_IA32_PERF_GLOBAL_CTRL));
if (vmentry_ctl & VM_ENTRY_LOAD_BNDCFGS)
- pr_err("BndCfgS = 0x%016lx\n", vmcs_readl(GUEST_BNDCFGS));
+ pr_err("BndCfgS = 0x%016llx\n", vmcs_read64(GUEST_BNDCFGS));
pr_err("Interruptibility = %08x ActivityState = %08x\n",
vmcs_read32(GUEST_INTERRUPTIBILITY_INFO),
vmcs_read32(GUEST_ACTIVITY_STATE));
@@ -7980,11 +8037,12 @@ static void dump_vmcs(void)
vmcs_read32(HOST_IA32_SYSENTER_CS),
vmcs_readl(HOST_IA32_SYSENTER_EIP));
if (vmexit_ctl & (VM_EXIT_LOAD_IA32_PAT | VM_EXIT_LOAD_IA32_EFER))
- pr_err("EFER = 0x%016lx PAT = 0x%016lx\n",
- vmcs_readl(HOST_IA32_EFER), vmcs_readl(HOST_IA32_PAT));
+ pr_err("EFER = 0x%016llx PAT = 0x%016llx\n",
+ vmcs_read64(HOST_IA32_EFER),
+ vmcs_read64(HOST_IA32_PAT));
if (vmexit_ctl & VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL)
- pr_err("PerfGlobCtl = 0x%016lx\n",
- vmcs_readl(HOST_IA32_PERF_GLOBAL_CTRL));
+ pr_err("PerfGlobCtl = 0x%016llx\n",
+ vmcs_read64(HOST_IA32_PERF_GLOBAL_CTRL));
pr_err("*** Control State ***\n");
pr_err("PinBased=%08x CPUBased=%08x SecondaryExec=%08x\n",
@@ -8007,13 +8065,16 @@ static void dump_vmcs(void)
pr_err("IDTVectoring: info=%08x errcode=%08x\n",
vmcs_read32(IDT_VECTORING_INFO_FIELD),
vmcs_read32(IDT_VECTORING_ERROR_CODE));
- pr_err("TSC Offset = 0x%016lx\n", vmcs_readl(TSC_OFFSET));
+ pr_err("TSC Offset = 0x%016llx\n", vmcs_read64(TSC_OFFSET));
+ if (secondary_exec_control & SECONDARY_EXEC_TSC_SCALING)
+ pr_err("TSC Multiplier = 0x%016llx\n",
+ vmcs_read64(TSC_MULTIPLIER));
if (cpu_based_exec_ctrl & CPU_BASED_TPR_SHADOW)
pr_err("TPR Threshold = 0x%02x\n", vmcs_read32(TPR_THRESHOLD));
if (pin_based_exec_ctrl & PIN_BASED_POSTED_INTR)
pr_err("PostedIntrVec = 0x%02x\n", vmcs_read16(POSTED_INTR_NV));
if ((secondary_exec_control & SECONDARY_EXEC_ENABLE_EPT))
- pr_err("EPT pointer = 0x%016lx\n", vmcs_readl(EPT_POINTER));
+ pr_err("EPT pointer = 0x%016llx\n", vmcs_read64(EPT_POINTER));
n = vmcs_read32(CR3_TARGET_COUNT);
for (i = 0; i + 1 < n; i += 4)
pr_err("CR3 target%u=%016lx target%u=%016lx\n",
@@ -8040,6 +8101,8 @@ static int vmx_handle_exit(struct kvm_vcpu *vcpu)
u32 exit_reason = vmx->exit_reason;
u32 vectoring_info = vmx->idt_vectoring_info;
+ trace_kvm_exit(exit_reason, vcpu, KVM_ISA_VMX);
+
/*
* Flush logged GPAs PML buffer, this will make dirty_bitmap more
* updated. Another good is, in kvm_vm_ioctl_get_dirty_log, before
@@ -8150,7 +8213,7 @@ static void vmx_set_virtual_x2apic_mode(struct kvm_vcpu *vcpu, bool set)
* apicv
*/
if (!cpu_has_vmx_virtualize_x2apic_mode() ||
- !vmx_cpu_uses_apicv(vcpu))
+ !kvm_vcpu_apicv_active(vcpu))
return;
if (!cpu_need_tpr_shadow(vcpu))
@@ -8255,10 +8318,9 @@ static void vmx_hwapic_irr_update(struct kvm_vcpu *vcpu, int max_irr)
}
}
-static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu)
+static void vmx_load_eoi_exitmap(struct kvm_vcpu *vcpu, u64 *eoi_exit_bitmap)
{
- u64 *eoi_exit_bitmap = vcpu->arch.eoi_exit_bitmap;
- if (!vmx_cpu_uses_apicv(vcpu))
+ if (!kvm_vcpu_apicv_active(vcpu))
return;
vmcs_write64(EOI_EXIT_BITMAP0, eoi_exit_bitmap[0]);
@@ -8666,7 +8728,6 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
vmx->loaded_vmcs->launched = 1;
vmx->exit_reason = vmcs_read32(VM_EXIT_REASON);
- trace_kvm_exit(vmx->exit_reason, vcpu, KVM_ISA_VMX);
/*
* the KVM_REQ_EVENT optimization bit is only on for one entry, and if
@@ -8929,7 +8990,8 @@ static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
best->ebx &= ~bit(X86_FEATURE_INVPCID);
}
- vmcs_set_secondary_exec_control(secondary_exec_ctl);
+ if (cpu_has_secondary_exec_ctrls())
+ vmcs_set_secondary_exec_control(secondary_exec_ctl);
if (static_cpu_has(X86_FEATURE_PCOMMIT) && nested) {
if (guest_cpuid_has_pcommit(vcpu))
@@ -9505,7 +9567,7 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
*/
vmx->nested.posted_intr_nv = vmcs12->posted_intr_nv;
vmx->nested.pi_pending = false;
- vmcs_write64(POSTED_INTR_NV, POSTED_INTR_VECTOR);
+ vmcs_write16(POSTED_INTR_NV, POSTED_INTR_VECTOR);
vmcs_write64(POSTED_INTR_DESC_ADDR,
page_to_phys(vmx->nested.pi_desc_page) +
(unsigned long)(vmcs12->posted_intr_desc_addr &
@@ -10166,7 +10228,7 @@ static void prepare_vmcs12(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
* Additionally, restore L2's PDPTR to vmcs12.
*/
if (enable_ept) {
- vmcs12->guest_cr3 = vmcs_read64(GUEST_CR3);
+ vmcs12->guest_cr3 = vmcs_readl(GUEST_CR3);
vmcs12->guest_pdptr0 = vmcs_read64(GUEST_PDPTR0);
vmcs12->guest_pdptr1 = vmcs_read64(GUEST_PDPTR1);
vmcs12->guest_pdptr2 = vmcs_read64(GUEST_PDPTR2);
@@ -10752,7 +10814,7 @@ static struct kvm_x86_ops vmx_x86_ops = {
.vcpu_load = vmx_vcpu_load,
.vcpu_put = vmx_vcpu_put,
- .update_db_bp_intercept = update_exception_bitmap,
+ .update_bp_intercept = update_exception_bitmap,
.get_msr = vmx_get_msr,
.set_msr = vmx_set_msr,
.get_segment_base = vmx_get_segment_base,
@@ -10802,7 +10864,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.update_cr8_intercept = update_cr8_intercept,
.set_virtual_x2apic_mode = vmx_set_virtual_x2apic_mode,
.set_apic_access_page_addr = vmx_set_apic_access_page_addr,
- .cpu_uses_apicv = vmx_cpu_uses_apicv,
+ .get_enable_apicv = vmx_get_enable_apicv,
+ .refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
.load_eoi_exitmap = vmx_load_eoi_exitmap,
.hwapic_irr_update = vmx_hwapic_irr_update,
.hwapic_isr_update = vmx_hwapic_isr_update,
@@ -10826,11 +10889,9 @@ static struct kvm_x86_ops vmx_x86_ops = {
.has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
- .set_tsc_khz = vmx_set_tsc_khz,
.read_tsc_offset = vmx_read_tsc_offset,
.write_tsc_offset = vmx_write_tsc_offset,
- .adjust_tsc_offset = vmx_adjust_tsc_offset,
- .compute_tsc_offset = vmx_compute_tsc_offset,
+ .adjust_tsc_offset_guest = vmx_adjust_tsc_offset_guest,
.read_l1_tsc = vmx_read_l1_tsc,
.set_tdp_cr3 = vmx_set_cr3,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4a6eff1..f53f5b1 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -93,10 +93,10 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu);
static void process_nmi(struct kvm_vcpu *vcpu);
static void __kvm_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags);
-struct kvm_x86_ops *kvm_x86_ops;
+struct kvm_x86_ops *kvm_x86_ops __read_mostly;
EXPORT_SYMBOL_GPL(kvm_x86_ops);
-static bool ignore_msrs = 0;
+static bool __read_mostly ignore_msrs = 0;
module_param(ignore_msrs, bool, S_IRUGO | S_IWUSR);
unsigned int min_timer_period_us = 500;
@@ -105,20 +105,25 @@ module_param(min_timer_period_us, uint, S_IRUGO | S_IWUSR);
static bool __read_mostly kvmclock_periodic_sync = true;
module_param(kvmclock_periodic_sync, bool, S_IRUGO);
-bool kvm_has_tsc_control;
+bool __read_mostly kvm_has_tsc_control;
EXPORT_SYMBOL_GPL(kvm_has_tsc_control);
-u32 kvm_max_guest_tsc_khz;
+u32 __read_mostly kvm_max_guest_tsc_khz;
EXPORT_SYMBOL_GPL(kvm_max_guest_tsc_khz);
+u8 __read_mostly kvm_tsc_scaling_ratio_frac_bits;
+EXPORT_SYMBOL_GPL(kvm_tsc_scaling_ratio_frac_bits);
+u64 __read_mostly kvm_max_tsc_scaling_ratio;
+EXPORT_SYMBOL_GPL(kvm_max_tsc_scaling_ratio);
+static u64 __read_mostly kvm_default_tsc_scaling_ratio;
/* tsc tolerance in parts per million - default to 1/2 of the NTP threshold */
-static u32 tsc_tolerance_ppm = 250;
+static u32 __read_mostly tsc_tolerance_ppm = 250;
module_param(tsc_tolerance_ppm, uint, S_IRUGO | S_IWUSR);
/* lapic timer advance (tscdeadline mode only) in nanoseconds */
-unsigned int lapic_timer_advance_ns = 0;
+unsigned int __read_mostly lapic_timer_advance_ns = 0;
module_param(lapic_timer_advance_ns, uint, S_IRUGO | S_IWUSR);
-static bool backwards_tsc_observed = false;
+static bool __read_mostly backwards_tsc_observed = false;
#define KVM_NR_SHARED_MSRS 16
@@ -946,7 +951,7 @@ static u32 msrs_to_save[] = {
MSR_CSTAR, MSR_KERNEL_GS_BASE, MSR_SYSCALL_MASK, MSR_LSTAR,
#endif
MSR_IA32_TSC, MSR_IA32_CR_PAT, MSR_VM_HSAVE_PA,
- MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS
+ MSR_IA32_FEATURE_CONTROL, MSR_IA32_BNDCFGS, MSR_TSC_AUX,
};
static unsigned num_msrs_to_save;
@@ -961,6 +966,8 @@ static u32 emulated_msrs[] = {
HV_X64_MSR_RESET,
HV_X64_MSR_VP_INDEX,
HV_X64_MSR_VP_RUNTIME,
+ HV_X64_MSR_SCONTROL,
+ HV_X64_MSR_STIMER0_CONFIG,
HV_X64_MSR_APIC_ASSIST_PAGE, MSR_KVM_ASYNC_PF_EN, MSR_KVM_STEAL_TIME,
MSR_KVM_PV_EOI_EN,
@@ -1162,7 +1169,8 @@ static void kvm_write_wall_clock(struct kvm *kvm, gpa_t wall_clock)
++version;
- kvm_write_guest(kvm, wall_clock, &version, sizeof(version));
+ if (kvm_write_guest(kvm, wall_clock, &version, sizeof(version)))
+ return;
/*
* The guest calculates current wall clock time by adding
@@ -1249,14 +1257,53 @@ static u32 adjust_tsc_khz(u32 khz, s32 ppm)
return v;
}
-static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
+static int set_tsc_khz(struct kvm_vcpu *vcpu, u32 user_tsc_khz, bool scale)
+{
+ u64 ratio;
+
+ /* Guest TSC same frequency as host TSC? */
+ if (!scale) {
+ vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+ return 0;
+ }
+
+ /* TSC scaling supported? */
+ if (!kvm_has_tsc_control) {
+ if (user_tsc_khz > tsc_khz) {
+ vcpu->arch.tsc_catchup = 1;
+ vcpu->arch.tsc_always_catchup = 1;
+ return 0;
+ } else {
+ WARN(1, "user requested TSC rate below hardware speed\n");
+ return -1;
+ }
+ }
+
+ /* TSC scaling required - calculate ratio */
+ ratio = mul_u64_u32_div(1ULL << kvm_tsc_scaling_ratio_frac_bits,
+ user_tsc_khz, tsc_khz);
+
+ if (ratio == 0 || ratio >= kvm_max_tsc_scaling_ratio) {
+ WARN_ONCE(1, "Invalid TSC scaling ratio - virtual-tsc-khz=%u\n",
+ user_tsc_khz);
+ return -1;
+ }
+
+ vcpu->arch.tsc_scaling_ratio = ratio;
+ return 0;
+}
+
+static int kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
{
u32 thresh_lo, thresh_hi;
int use_scaling = 0;
/* tsc_khz can be zero if TSC calibration fails */
- if (this_tsc_khz == 0)
- return;
+ if (this_tsc_khz == 0) {
+ /* set tsc_scaling_ratio to a safe value */
+ vcpu->arch.tsc_scaling_ratio = kvm_default_tsc_scaling_ratio;
+ return -1;
+ }
/* Compute a scale to convert nanoseconds in TSC cycles */
kvm_get_time_scale(this_tsc_khz, NSEC_PER_SEC / 1000,
@@ -1276,7 +1323,7 @@ static void kvm_set_tsc_khz(struct kvm_vcpu *vcpu, u32 this_tsc_khz)
pr_debug("kvm: requested TSC rate %u falls outside tolerance [%u,%u]\n", this_tsc_khz, thresh_lo, thresh_hi);
use_scaling = 1;
}
- kvm_x86_ops->set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
+ return set_tsc_khz(vcpu, this_tsc_khz, use_scaling);
}
static u64 compute_guest_tsc(struct kvm_vcpu *vcpu, s64 kernel_ns)
@@ -1322,6 +1369,48 @@ static void update_ia32_tsc_adjust_msr(struct kvm_vcpu *vcpu, s64 offset)
vcpu->arch.ia32_tsc_adjust_msr += offset - curr_offset;
}
+/*
+ * Multiply tsc by a fixed point number represented by ratio.
+ *
+ * The most significant 64-N bits (mult) of ratio represent the
+ * integral part of the fixed point number; the remaining N bits
+ * (frac) represent the fractional part, ie. ratio represents a fixed
+ * point number (mult + frac * 2^(-N)).
+ *
+ * N equals to kvm_tsc_scaling_ratio_frac_bits.
+ */
+static inline u64 __scale_tsc(u64 ratio, u64 tsc)
+{
+ return mul_u64_u64_shr(tsc, ratio, kvm_tsc_scaling_ratio_frac_bits);
+}
+
+u64 kvm_scale_tsc(struct kvm_vcpu *vcpu, u64 tsc)
+{
+ u64 _tsc = tsc;
+ u64 ratio = vcpu->arch.tsc_scaling_ratio;
+
+ if (ratio != kvm_default_tsc_scaling_ratio)
+ _tsc = __scale_tsc(ratio, tsc);
+
+ return _tsc;
+}
+EXPORT_SYMBOL_GPL(kvm_scale_tsc);
+
+static u64 kvm_compute_tsc_offset(struct kvm_vcpu *vcpu, u64 target_tsc)
+{
+ u64 tsc;
+
+ tsc = kvm_scale_tsc(vcpu, rdtsc());
+
+ return target_tsc - tsc;
+}
+
+u64 kvm_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
+{
+ return kvm_x86_ops->read_l1_tsc(vcpu, kvm_scale_tsc(vcpu, host_tsc));
+}
+EXPORT_SYMBOL_GPL(kvm_read_l1_tsc);
+
void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
{
struct kvm *kvm = vcpu->kvm;
@@ -1333,7 +1422,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
u64 data = msr->data;
raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags);
- offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
+ offset = kvm_compute_tsc_offset(vcpu, data);
ns = get_kernel_ns();
elapsed = ns - kvm->arch.last_tsc_nsec;
@@ -1390,7 +1479,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
} else {
u64 delta = nsec_to_cycles(vcpu, elapsed);
data += delta;
- offset = kvm_x86_ops->compute_tsc_offset(vcpu, data);
+ offset = kvm_compute_tsc_offset(vcpu, data);
pr_debug("kvm: adjusted tsc offset by %llu\n", delta);
}
matched = true;
@@ -1447,6 +1536,20 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, struct msr_data *msr)
EXPORT_SYMBOL_GPL(kvm_write_tsc);
+static inline void adjust_tsc_offset_guest(struct kvm_vcpu *vcpu,
+ s64 adjustment)
+{
+ kvm_x86_ops->adjust_tsc_offset_guest(vcpu, adjustment);
+}
+
+static inline void adjust_tsc_offset_host(struct kvm_vcpu *vcpu, s64 adjustment)
+{
+ if (vcpu->arch.tsc_scaling_ratio != kvm_default_tsc_scaling_ratio)
+ WARN_ON(adjustment < 0);
+ adjustment = kvm_scale_tsc(vcpu, (u64) adjustment);
+ kvm_x86_ops->adjust_tsc_offset_guest(vcpu, adjustment);
+}
+
#ifdef CONFIG_X86_64
static cycle_t read_tsc(void)
@@ -1583,6 +1686,11 @@ static void pvclock_update_vm_gtod_copy(struct kvm *kvm)
#endif
}
+void kvm_make_mclock_inprogress_request(struct kvm *kvm)
+{
+ kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
+}
+
static void kvm_gen_update_masterclock(struct kvm *kvm)
{
#ifdef CONFIG_X86_64
@@ -1608,7 +1716,7 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
static int kvm_guest_time_update(struct kvm_vcpu *v)
{
- unsigned long flags, this_tsc_khz;
+ unsigned long flags, this_tsc_khz, tgt_tsc_khz;
struct kvm_vcpu_arch *vcpu = &v->arch;
struct kvm_arch *ka = &v->kvm->arch;
s64 kernel_ns;
@@ -1645,7 +1753,7 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
kernel_ns = get_kernel_ns();
}
- tsc_timestamp = kvm_x86_ops->read_l1_tsc(v, host_tsc);
+ tsc_timestamp = kvm_read_l1_tsc(v, host_tsc);
/*
* We may have to catch up the TSC to match elapsed wall clock
@@ -1671,7 +1779,9 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
return 0;
if (unlikely(vcpu->hw_tsc_khz != this_tsc_khz)) {
- kvm_get_time_scale(NSEC_PER_SEC / 1000, this_tsc_khz,
+ tgt_tsc_khz = kvm_has_tsc_control ?
+ vcpu->virtual_tsc_khz : this_tsc_khz;
+ kvm_get_time_scale(NSEC_PER_SEC / 1000, tgt_tsc_khz,
&vcpu->hv_clock.tsc_shift,
&vcpu->hv_clock.tsc_to_system_mul);
vcpu->hw_tsc_khz = this_tsc_khz;
@@ -2096,6 +2206,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
case HV_X64_MSR_CRASH_CTL:
+ case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
return kvm_hv_set_msr_common(vcpu, msr, data,
msr_info->host_initiated);
case MSR_IA32_BBL_CR_CTL3:
@@ -2300,6 +2411,7 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case HV_X64_MSR_GUEST_OS_ID ... HV_X64_MSR_SINT15:
case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4:
case HV_X64_MSR_CRASH_CTL:
+ case HV_X64_MSR_STIMER0_CONFIG ... HV_X64_MSR_STIMER3_COUNT:
return kvm_hv_get_msr_common(vcpu,
msr_info->index, &msr_info->data);
break;
@@ -2439,6 +2551,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
case KVM_CAP_HYPERV:
case KVM_CAP_HYPERV_VAPIC:
case KVM_CAP_HYPERV_SPIN:
+ case KVM_CAP_HYPERV_SYNIC:
case KVM_CAP_PCI_SEGMENT:
case KVM_CAP_DEBUGREGS:
case KVM_CAP_X86_ROBUST_SINGLESTEP:
@@ -2591,6 +2704,11 @@ static bool need_emulate_wbinvd(struct kvm_vcpu *vcpu)
return kvm_arch_has_noncoherent_dma(vcpu->kvm);
}
+static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)
+{
+ set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);
+}
+
void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
{
/* Address WBINVD may be executed by guest */
@@ -2617,7 +2735,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (tsc_delta < 0)
mark_tsc_unstable("KVM discovered backwards TSC");
if (check_tsc_unstable()) {
- u64 offset = kvm_x86_ops->compute_tsc_offset(vcpu,
+ u64 offset = kvm_compute_tsc_offset(vcpu,
vcpu->arch.last_guest_tsc);
kvm_x86_ops->write_tsc_offset(vcpu, offset);
vcpu->arch.tsc_catchup = 1;
@@ -2646,7 +2764,9 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,
struct kvm_lapic_state *s)
{
- kvm_x86_ops->sync_pir_to_irr(vcpu);
+ if (vcpu->arch.apicv_active)
+ kvm_x86_ops->sync_pir_to_irr(vcpu);
+
memcpy(s->regs, vcpu->arch.apic->regs, sizeof *s);
return 0;
@@ -2661,6 +2781,26 @@ static int kvm_vcpu_ioctl_set_lapic(struct kvm_vcpu *vcpu,
return 0;
}
+static int kvm_cpu_accept_dm_intr(struct kvm_vcpu *vcpu)
+{
+ return (!lapic_in_kernel(vcpu) ||
+ kvm_apic_accept_pic_intr(vcpu));
+}
+
+/*
+ * if userspace requested an interrupt window, check that the
+ * interrupt window is open.
+ *
+ * No need to exit to userspace if we already have an interrupt queued.
+ */
+static int kvm_vcpu_ready_for_interrupt_injection(struct kvm_vcpu *vcpu)
+{
+ return kvm_arch_interrupt_allowed(vcpu) &&
+ !kvm_cpu_has_interrupt(vcpu) &&
+ !kvm_event_needs_reinjection(vcpu) &&
+ kvm_cpu_accept_dm_intr(vcpu);
+}
+
static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
struct kvm_interrupt *irq)
{
@@ -2684,6 +2824,7 @@ static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
return -EEXIST;
vcpu->arch.pending_external_vector = irq->irq;
+ kvm_make_request(KVM_REQ_EVENT, vcpu);
return 0;
}
@@ -3068,6 +3209,20 @@ static int kvm_set_guest_paused(struct kvm_vcpu *vcpu)
return 0;
}
+static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
+ struct kvm_enable_cap *cap)
+{
+ if (cap->flags)
+ return -EINVAL;
+
+ switch (cap->cap) {
+ case KVM_CAP_HYPERV_SYNIC:
+ return kvm_hv_activate_synic(vcpu);
+ default:
+ return -EINVAL;
+ }
+}
+
long kvm_arch_vcpu_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
@@ -3319,9 +3474,9 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
if (user_tsc_khz == 0)
user_tsc_khz = tsc_khz;
- kvm_set_tsc_khz(vcpu, user_tsc_khz);
+ if (!kvm_set_tsc_khz(vcpu, user_tsc_khz))
+ r = 0;
- r = 0;
goto out;
}
case KVM_GET_TSC_KHZ: {
@@ -3332,6 +3487,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = kvm_set_guest_paused(vcpu);
goto out;
}
+ case KVM_ENABLE_CAP: {
+ struct kvm_enable_cap cap;
+
+ r = -EFAULT;
+ if (copy_from_user(&cap, argp, sizeof(cap)))
+ goto out;
+ r = kvm_vcpu_ioctl_enable_cap(vcpu, &cap);
+ break;
+ }
default:
r = -EINVAL;
}
@@ -3449,9 +3613,11 @@ static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
{
+ int i;
mutex_lock(&kvm->arch.vpit->pit_state.lock);
memcpy(&kvm->arch.vpit->pit_state, ps, sizeof(struct kvm_pit_state));
- kvm_pit_load_count(kvm, 0, ps->channels[0].count, 0);
+ for (i = 0; i < 3; i++)
+ kvm_pit_load_count(kvm, i, ps->channels[i].count, 0);
mutex_unlock(&kvm->arch.vpit->pit_state.lock);
return 0;
}
@@ -3470,6 +3636,7 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
{
int start = 0;
+ int i;
u32 prev_legacy, cur_legacy;
mutex_lock(&kvm->arch.vpit->pit_state.lock);
prev_legacy = kvm->arch.vpit->pit_state.flags & KVM_PIT_FLAGS_HPET_LEGACY;
@@ -3479,7 +3646,9 @@ static int kvm_vm_ioctl_set_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
memcpy(&kvm->arch.vpit->pit_state.channels, &ps->channels,
sizeof(kvm->arch.vpit->pit_state.channels));
kvm->arch.vpit->pit_state.flags = ps->flags;
- kvm_pit_load_count(kvm, 0, kvm->arch.vpit->pit_state.channels[0].count, start);
+ for (i = 0; i < 3; i++)
+ kvm_pit_load_count(kvm, i, kvm->arch.vpit->pit_state.channels[i].count,
+ start && i == 0);
mutex_unlock(&kvm->arch.vpit->pit_state.lock);
return 0;
}
@@ -3878,16 +4047,17 @@ static void kvm_init_msr_list(void)
/*
* Even MSRs that are valid in the host may not be exposed
- * to the guests in some cases. We could work around this
- * in VMX with the generic MSR save/load machinery, but it
- * is not really worthwhile since it will really only
- * happen with nested virtualization.
+ * to the guests in some cases.
*/
switch (msrs_to_save[i]) {
case MSR_IA32_BNDCFGS:
if (!kvm_x86_ops->mpx_supported())
continue;
break;
+ case MSR_TSC_AUX:
+ if (!kvm_x86_ops->rdtscp_supported())
+ continue;
+ break;
default:
break;
}
@@ -5744,6 +5914,12 @@ static void kvm_pv_kick_cpu_op(struct kvm *kvm, unsigned long flags, int apicid)
kvm_irq_delivery_to_apic(kvm, NULL, &lapic_irq, NULL);
}
+void kvm_vcpu_deactivate_apicv(struct kvm_vcpu *vcpu)
+{
+ vcpu->arch.apicv_active = false;
+ kvm_x86_ops->refresh_apicv_exec_ctrl(vcpu);
+}
+
int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
{
unsigned long nr, a0, a1, a2, a3, ret;
@@ -5808,23 +5984,10 @@ static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt)
return emulator_write_emulated(ctxt, rip, instruction, 3, NULL);
}
-/*
- * Check if userspace requested an interrupt window, and that the
- * interrupt window is open.
- *
- * No need to exit to userspace if we already have an interrupt queued.
- */
static int dm_request_for_irq_injection(struct kvm_vcpu *vcpu)
{
- if (!vcpu->run->request_interrupt_window || pic_in_kernel(vcpu->kvm))
- return false;
-
- if (kvm_cpu_has_interrupt(vcpu))
- return false;
-
- return (irqchip_split(vcpu->kvm)
- ? kvm_apic_accept_pic_intr(vcpu)
- : kvm_arch_interrupt_allowed(vcpu));
+ return vcpu->run->request_interrupt_window &&
+ likely(!pic_in_kernel(vcpu->kvm));
}
static void post_kvm_run_save(struct kvm_vcpu *vcpu)
@@ -5835,17 +5998,9 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu)
kvm_run->flags = is_smm(vcpu) ? KVM_RUN_X86_SMM : 0;
kvm_run->cr8 = kvm_get_cr8(vcpu);
kvm_run->apic_base = kvm_get_apic_base(vcpu);
- if (!irqchip_in_kernel(vcpu->kvm))
- kvm_run->ready_for_interrupt_injection =
- kvm_arch_interrupt_allowed(vcpu) &&
- !kvm_cpu_has_interrupt(vcpu) &&
- !kvm_event_needs_reinjection(vcpu);
- else if (!pic_in_kernel(vcpu->kvm))
- kvm_run->ready_for_interrupt_injection =
- kvm_apic_accept_pic_intr(vcpu) &&
- !kvm_cpu_has_interrupt(vcpu);
- else
- kvm_run->ready_for_interrupt_injection = 1;
+ kvm_run->ready_for_interrupt_injection =
+ pic_in_kernel(vcpu->kvm) ||
+ kvm_vcpu_ready_for_interrupt_injection(vcpu);
}
static void update_cr8_intercept(struct kvm_vcpu *vcpu)
@@ -5858,6 +6013,9 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
if (!vcpu->arch.apic)
return;
+ if (vcpu->arch.apicv_active)
+ return;
+
if (!vcpu->arch.apic->vapic_addr)
max_irr = kvm_lapic_find_highest_irr(vcpu);
else
@@ -6194,20 +6352,30 @@ static void process_smi(struct kvm_vcpu *vcpu)
kvm_mmu_reset_context(vcpu);
}
+void kvm_make_scan_ioapic_request(struct kvm *kvm)
+{
+ kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
+}
+
static void vcpu_scan_ioapic(struct kvm_vcpu *vcpu)
{
+ u64 eoi_exit_bitmap[4];
+
if (!kvm_apic_hw_enabled(vcpu->arch.apic))
return;
- memset(vcpu->arch.eoi_exit_bitmap, 0, 256 / 8);
+ bitmap_zero(vcpu->arch.ioapic_handled_vectors, 256);
if (irqchip_split(vcpu->kvm))
- kvm_scan_ioapic_routes(vcpu, vcpu->arch.eoi_exit_bitmap);
+ kvm_scan_ioapic_routes(vcpu, vcpu->arch.ioapic_handled_vectors);
else {
- kvm_x86_ops->sync_pir_to_irr(vcpu);
- kvm_ioapic_scan_entry(vcpu, vcpu->arch.eoi_exit_bitmap);
+ if (vcpu->arch.apicv_active)
+ kvm_x86_ops->sync_pir_to_irr(vcpu);
+ kvm_ioapic_scan_entry(vcpu, vcpu->arch.ioapic_handled_vectors);
}
- kvm_x86_ops->load_eoi_exitmap(vcpu);
+ bitmap_or((ulong *)eoi_exit_bitmap, vcpu->arch.ioapic_handled_vectors,
+ vcpu_to_synic(vcpu)->vec_bitmap, 256);
+ kvm_x86_ops->load_eoi_exitmap(vcpu, eoi_exit_bitmap);
}
static void kvm_vcpu_flush_tlb(struct kvm_vcpu *vcpu)
@@ -6258,8 +6426,10 @@ void kvm_arch_mmu_notifier_invalidate_page(struct kvm *kvm,
static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
{
int r;
- bool req_int_win = !lapic_in_kernel(vcpu) &&
- vcpu->run->request_interrupt_window;
+ bool req_int_win =
+ dm_request_for_irq_injection(vcpu) &&
+ kvm_cpu_accept_dm_intr(vcpu);
+
bool req_immediate_exit = false;
if (vcpu->requests) {
@@ -6313,7 +6483,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (kvm_check_request(KVM_REQ_IOAPIC_EOI_EXIT, vcpu)) {
BUG_ON(vcpu->arch.pending_ioapic_eoi > 255);
if (test_bit(vcpu->arch.pending_ioapic_eoi,
- (void *) vcpu->arch.eoi_exit_bitmap)) {
+ vcpu->arch.ioapic_handled_vectors)) {
vcpu->run->exit_reason = KVM_EXIT_IOAPIC_EOI;
vcpu->run->eoi.vector =
vcpu->arch.pending_ioapic_eoi;
@@ -6337,6 +6507,20 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
r = 0;
goto out;
}
+ if (kvm_check_request(KVM_REQ_HV_EXIT, vcpu)) {
+ vcpu->run->exit_reason = KVM_EXIT_HYPERV;
+ vcpu->run->hyperv = vcpu->arch.hyperv.exit;
+ r = 0;
+ goto out;
+ }
+
+ /*
+ * KVM_REQ_HV_STIMER has to be processed after
+ * KVM_REQ_CLOCK_UPDATE, because Hyper-V SynIC timers
+ * depend on the guest clock being up-to-date
+ */
+ if (kvm_check_request(KVM_REQ_HV_STIMER, vcpu))
+ kvm_hv_process_stimers(vcpu);
}
/*
@@ -6348,7 +6532,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
* Update architecture specific hints for APIC
* virtual interrupt delivery.
*/
- if (kvm_x86_ops->hwapic_irr_update)
+ if (vcpu->arch.apicv_active)
kvm_x86_ops->hwapic_irr_update(vcpu,
kvm_lapic_find_highest_irr(vcpu));
}
@@ -6411,6 +6595,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (req_immediate_exit)
smp_send_reschedule(vcpu->cpu);
+ trace_kvm_entry(vcpu->vcpu_id);
+ wait_lapic_expire(vcpu);
__kvm_guest_enter();
if (unlikely(vcpu->arch.switch_db_regs)) {
@@ -6423,8 +6609,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
vcpu->arch.switch_db_regs &= ~KVM_DEBUGREG_RELOAD;
}
- trace_kvm_entry(vcpu->vcpu_id);
- wait_lapic_expire(vcpu);
kvm_x86_ops->run(vcpu);
/*
@@ -6452,8 +6636,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
if (hw_breakpoint_active())
hw_breakpoint_restore();
- vcpu->arch.last_guest_tsc = kvm_x86_ops->read_l1_tsc(vcpu,
- rdtsc());
+ vcpu->arch.last_guest_tsc = kvm_read_l1_tsc(vcpu, rdtsc());
vcpu->mode = OUTSIDE_GUEST_MODE;
smp_wmb();
@@ -6562,7 +6745,8 @@ static int vcpu_run(struct kvm_vcpu *vcpu)
if (kvm_cpu_has_pending_timer(vcpu))
kvm_inject_pending_timer_irqs(vcpu);
- if (dm_request_for_irq_injection(vcpu)) {
+ if (dm_request_for_irq_injection(vcpu) &&
+ kvm_vcpu_ready_for_interrupt_injection(vcpu)) {
r = 0;
vcpu->run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN;
++vcpu->stat.request_irq_exits;
@@ -7015,7 +7199,7 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu,
*/
kvm_set_rflags(vcpu, rflags);
- kvm_x86_ops->update_db_bp_intercept(vcpu);
+ kvm_x86_ops->update_bp_intercept(vcpu);
r = 0;
@@ -7364,6 +7548,20 @@ int kvm_arch_hardware_setup(void)
if (r != 0)
return r;
+ if (kvm_has_tsc_control) {
+ /*
+ * Make sure the user can only configure tsc_khz values that
+ * fit into a signed integer.
+ * A min value is not calculated needed because it will always
+ * be 1 on all machines.
+ */
+ u64 max = min(0x7fffffffULL,
+ __scale_tsc(kvm_max_tsc_scaling_ratio, tsc_khz));
+ kvm_max_guest_tsc_khz = max;
+
+ kvm_default_tsc_scaling_ratio = 1ULL << kvm_tsc_scaling_ratio_frac_bits;
+ }
+
kvm_init_msr_list();
return 0;
}
@@ -7405,6 +7603,7 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
BUG_ON(vcpu->kvm == NULL);
kvm = vcpu->kvm;
+ vcpu->arch.apicv_active = kvm_x86_ops->get_enable_apicv();
vcpu->arch.pv.pv_unhalted = false;
vcpu->arch.emulate_ctxt.ops = &emulate_ops;
if (!irqchip_in_kernel(kvm) || kvm_vcpu_is_reset_bsp(vcpu))
@@ -7462,6 +7661,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
vcpu->arch.pending_external_vector = -1;
+ kvm_hv_vcpu_init(vcpu);
+
return 0;
fail_free_mce_banks:
@@ -7480,6 +7681,7 @@ void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
{
int idx;
+ kvm_hv_vcpu_uninit(vcpu);
kvm_pmu_destroy(vcpu);
kfree(vcpu->arch.mce_banks);
kvm_free_lapic(vcpu);
@@ -7874,6 +8076,9 @@ static inline bool kvm_vcpu_has_events(struct kvm_vcpu *vcpu)
kvm_cpu_has_interrupt(vcpu))
return true;
+ if (kvm_hv_has_stimer_pending(vcpu))
+ return true;
+
return false;
}
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index a0d09f6..4ba229a 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -1414,6 +1414,7 @@ __init void lguest_init(void)
pv_info.kernel_rpl = 1;
/* Everyone except Xen runs with this set. */
pv_info.shared_kernel_pmd = 1;
+ pv_info.features = 0;
/*
* We set up all the lguest overrides for sensitive operations. These
@@ -1472,7 +1473,6 @@ __init void lguest_init(void)
pv_mmu_ops.lazy_mode.leave = lguest_leave_lazy_mmu_mode;
pv_mmu_ops.lazy_mode.flush = paravirt_flush_lazy_mmu;
pv_mmu_ops.pte_update = lguest_pte_update;
- pv_mmu_ops.pte_update_defer = lguest_pte_update;
#ifdef CONFIG_X86_LOCAL_APIC
/* APIC read/write intercepts */
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index f258788..a501fa2 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -16,7 +16,7 @@ clean-files := inat-tables.c
obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
-lib-y := delay.o misc.o cmdline.o
+lib-y := delay.o misc.o cmdline.o cpu.o
lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o
diff --git a/arch/x86/lib/cpu.c b/arch/x86/lib/cpu.c
new file mode 100644
index 0000000..aa417a9
--- /dev/null
+++ b/arch/x86/lib/cpu.c
@@ -0,0 +1,35 @@
+#include <linux/module.h>
+
+unsigned int x86_family(unsigned int sig)
+{
+ unsigned int x86;
+
+ x86 = (sig >> 8) & 0xf;
+
+ if (x86 == 0xf)
+ x86 += (sig >> 20) & 0xff;
+
+ return x86;
+}
+EXPORT_SYMBOL_GPL(x86_family);
+
+unsigned int x86_model(unsigned int sig)
+{
+ unsigned int fam, model;
+
+ fam = x86_family(sig);
+
+ model = (sig >> 4) & 0xf;
+
+ if (fam >= 0x6)
+ model += ((sig >> 16) & 0xf) << 4;
+
+ return model;
+}
+EXPORT_SYMBOL_GPL(x86_model);
+
+unsigned int x86_stepping(unsigned int sig)
+{
+ return sig & 0xf;
+}
+EXPORT_SYMBOL_GPL(x86_stepping);
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 4362373..004c861 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -1,6 +1,8 @@
#include <linux/module.h>
#include <linux/preempt.h>
#include <asm/msr.h>
+#define CREATE_TRACE_POINTS
+#include <asm/msr-trace.h>
struct msr *msrs_alloc(void)
{
@@ -108,3 +110,27 @@ int msr_clear_bit(u32 msr, u8 bit)
{
return __flip_bit(msr, bit, false);
}
+
+#ifdef CONFIG_TRACEPOINTS
+void do_trace_write_msr(unsigned msr, u64 val, int failed)
+{
+ trace_write_msr(msr, val, failed);
+}
+EXPORT_SYMBOL(do_trace_write_msr);
+EXPORT_TRACEPOINT_SYMBOL(write_msr);
+
+void do_trace_read_msr(unsigned msr, u64 val, int failed)
+{
+ trace_read_msr(msr, val, failed);
+}
+EXPORT_SYMBOL(do_trace_read_msr);
+EXPORT_TRACEPOINT_SYMBOL(read_msr);
+
+void do_trace_rdpmc(unsigned counter, u64 val, int failed)
+{
+ trace_rdpmc(counter, val, failed);
+}
+EXPORT_SYMBOL(do_trace_rdpmc);
+EXPORT_TRACEPOINT_SYMBOL(rdpmc);
+
+#endif
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 65c47fd..f9d38a4 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_X86_PTDUMP_CORE) += dump_pagetables.o
+obj-$(CONFIG_X86_PTDUMP) += debug_pagetables.o
obj-$(CONFIG_HIGHMEM) += highmem_32.o
diff --git a/arch/x86/mm/debug_pagetables.c b/arch/x86/mm/debug_pagetables.c
new file mode 100644
index 0000000..bfcffdf
--- /dev/null
+++ b/arch/x86/mm/debug_pagetables.c
@@ -0,0 +1,46 @@
+#include <linux/debugfs.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/pgtable.h>
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+ ptdump_walk_pgd_level(m, NULL);
+ return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, ptdump_show, NULL);
+}
+
+static const struct file_operations ptdump_fops = {
+ .owner = THIS_MODULE,
+ .open = ptdump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *pe;
+
+static int __init pt_dump_debug_init(void)
+{
+ pe = debugfs_create_file("kernel_page_tables", S_IRUSR, NULL, NULL,
+ &ptdump_fops);
+ if (!pe)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void __exit pt_dump_debug_exit(void)
+{
+ debugfs_remove_recursive(pe);
+}
+
+module_init(pt_dump_debug_init);
+module_exit(pt_dump_debug_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
+MODULE_DESCRIPTION("Kernel debugging helper that dumps pagetables");
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 1bf417e..4a6f1d9 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -89,7 +89,7 @@ static struct addr_marker address_markers[] = {
{ 0/* VMALLOC_START */, "vmalloc() Area" },
{ 0/*VMALLOC_END*/, "vmalloc() End" },
# ifdef CONFIG_HIGHMEM
- { 0/*PKMAP_BASE*/, "Persisent kmap() Area" },
+ { 0/*PKMAP_BASE*/, "Persistent kmap() Area" },
# endif
{ 0/*FIXADDR_START*/, "Fixmap Area" },
#endif
@@ -358,6 +358,21 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
#define pgd_none(a) pud_none(__pud(pgd_val(a)))
#endif
+#ifdef CONFIG_X86_64
+static inline bool is_hypervisor_range(int idx)
+{
+ /*
+ * ffff800000000000 - ffff87ffffffffff is reserved for
+ * the hypervisor.
+ */
+ return paravirt_enabled() &&
+ (idx >= pgd_index(__PAGE_OFFSET) - 16) &&
+ (idx < pgd_index(__PAGE_OFFSET));
+}
+#else
+static inline bool is_hypervisor_range(int idx) { return false; }
+#endif
+
static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
bool checkwx)
{
@@ -381,7 +396,7 @@ static void ptdump_walk_pgd_level_core(struct seq_file *m, pgd_t *pgd,
for (i = 0; i < PTRS_PER_PGD; i++) {
st.current_address = normalize_addr(i * PGD_LEVEL_MULT);
- if (!pgd_none(*start)) {
+ if (!pgd_none(*start) && !is_hypervisor_range(i)) {
if (pgd_large(*start) || !pgd_present(*start)) {
prot = pgd_flags(*start);
note_page(m, &st, __pgprot(prot), 1);
@@ -411,38 +426,15 @@ void ptdump_walk_pgd_level(struct seq_file *m, pgd_t *pgd)
{
ptdump_walk_pgd_level_core(m, pgd, false);
}
+EXPORT_SYMBOL_GPL(ptdump_walk_pgd_level);
void ptdump_walk_pgd_level_checkwx(void)
{
ptdump_walk_pgd_level_core(NULL, NULL, true);
}
-#ifdef CONFIG_X86_PTDUMP
-static int ptdump_show(struct seq_file *m, void *v)
-{
- ptdump_walk_pgd_level(m, NULL);
- return 0;
-}
-
-static int ptdump_open(struct inode *inode, struct file *filp)
+static int __init pt_dump_init(void)
{
- return single_open(filp, ptdump_show, NULL);
-}
-
-static const struct file_operations ptdump_fops = {
- .open = ptdump_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-#endif
-
-static int pt_dump_init(void)
-{
-#ifdef CONFIG_X86_PTDUMP
- struct dentry *pe;
-#endif
-
#ifdef CONFIG_X86_32
/* Not a compile-time constant on x86-32 */
address_markers[VMALLOC_START_NR].start_address = VMALLOC_START;
@@ -453,13 +445,6 @@ static int pt_dump_init(void)
address_markers[FIXADDR_START_NR].start_address = FIXADDR_START;
#endif
-#ifdef CONFIG_X86_PTDUMP
- pe = debugfs_create_file("kernel_page_tables", 0600, NULL, NULL,
- &ptdump_fops);
- if (!pe)
- return -ENOMEM;
-#endif
-
return 0;
}
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 1f37cb2..493f541 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -354,7 +354,7 @@ static int __meminit split_mem_range(struct map_range *mr, int nr_range,
}
for (i = 0; i < nr_range; i++)
- printk(KERN_DEBUG " [mem %#010lx-%#010lx] page %s\n",
+ pr_debug(" [mem %#010lx-%#010lx] page %s\n",
mr[i].start, mr[i].end - 1,
page_size_string(&mr[i]));
@@ -401,7 +401,7 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
unsigned long ret = 0;
int nr_range, i;
- pr_info("init_memory_mapping: [mem %#010lx-%#010lx]\n",
+ pr_debug("init_memory_mapping: [mem %#010lx-%#010lx]\n",
start, end - 1);
memset(mr, 0, sizeof(mr));
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 5ed62ef..ec081fe 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -1270,7 +1270,7 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
/* check to see if we have contiguous blocks */
if (p_end != p || node_start != node) {
if (p_start)
- printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
+ pr_debug(" [%lx-%lx] PMD -> [%p-%p] on node %d\n",
addr_start, addr_end-1, p_start, p_end-1, node_start);
addr_start = addr;
node_start = node;
@@ -1368,7 +1368,7 @@ void register_page_bootmem_memmap(unsigned long section_nr,
void __meminit vmemmap_populate_print_last(void)
{
if (p_start) {
- printk(KERN_DEBUG " [%lx-%lx] PMD -> [%p-%p] on node %d\n",
+ pr_debug(" [%lx-%lx] PMD -> [%p-%p] on node %d\n",
addr_start, addr_end-1, p_start, p_end-1, node_start);
p_start = NULL;
p_end = NULL;
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index b9c78f3..0d8d53d 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -194,8 +194,8 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
* Check if the request spans more than any BAR in the iomem resource
* tree.
*/
- WARN_ONCE(iomem_map_sanity_check(unaligned_phys_addr, unaligned_size),
- KERN_INFO "Info: mapping multiple BARs. Your kernel is fine.");
+ if (iomem_map_sanity_check(unaligned_phys_addr, unaligned_size))
+ pr_warn("caller %pS mapping multiple BARs\n", caller);
return ret_addr;
err_free_area:
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
index b0ae85f..b2fd67d 100644
--- a/arch/x86/mm/mpx.c
+++ b/arch/x86/mm/mpx.c
@@ -101,19 +101,19 @@ static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
switch (type) {
case REG_TYPE_RM:
regno = X86_MODRM_RM(insn->modrm.value);
- if (X86_REX_B(insn->rex_prefix.value) == 1)
+ if (X86_REX_B(insn->rex_prefix.value))
regno += 8;
break;
case REG_TYPE_INDEX:
regno = X86_SIB_INDEX(insn->sib.value);
- if (X86_REX_X(insn->rex_prefix.value) == 1)
+ if (X86_REX_X(insn->rex_prefix.value))
regno += 8;
break;
case REG_TYPE_BASE:
regno = X86_SIB_BASE(insn->sib.value);
- if (X86_REX_B(insn->rex_prefix.value) == 1)
+ if (X86_REX_B(insn->rex_prefix.value))
regno += 8;
break;
@@ -586,6 +586,29 @@ static unsigned long mpx_bd_entry_to_bt_addr(struct mm_struct *mm,
}
/*
+ * We only want to do a 4-byte get_user() on 32-bit. Otherwise,
+ * we might run off the end of the bounds table if we are on
+ * a 64-bit kernel and try to get 8 bytes.
+ */
+int get_user_bd_entry(struct mm_struct *mm, unsigned long *bd_entry_ret,
+ long __user *bd_entry_ptr)
+{
+ u32 bd_entry_32;
+ int ret;
+
+ if (is_64bit_mm(mm))
+ return get_user(*bd_entry_ret, bd_entry_ptr);
+
+ /*
+ * Note that get_user() uses the type of the *pointer* to
+ * establish the size of the get, not the destination.
+ */
+ ret = get_user(bd_entry_32, (u32 __user *)bd_entry_ptr);
+ *bd_entry_ret = bd_entry_32;
+ return ret;
+}
+
+/*
* Get the base of bounds tables pointed by specific bounds
* directory entry.
*/
@@ -605,7 +628,7 @@ static int get_bt_addr(struct mm_struct *mm,
int need_write = 0;
pagefault_disable();
- ret = get_user(bd_entry, bd_entry_ptr);
+ ret = get_user_bd_entry(mm, &bd_entry, bd_entry_ptr);
pagefault_enable();
if (!ret)
break;
@@ -700,11 +723,23 @@ static unsigned long mpx_get_bt_entry_offset_bytes(struct mm_struct *mm,
*/
static inline unsigned long bd_entry_virt_space(struct mm_struct *mm)
{
- unsigned long long virt_space = (1ULL << boot_cpu_data.x86_virt_bits);
- if (is_64bit_mm(mm))
- return virt_space / MPX_BD_NR_ENTRIES_64;
- else
- return virt_space / MPX_BD_NR_ENTRIES_32;
+ unsigned long long virt_space;
+ unsigned long long GB = (1ULL << 30);
+
+ /*
+ * This covers 32-bit emulation as well as 32-bit kernels
+ * running on 64-bit harware.
+ */
+ if (!is_64bit_mm(mm))
+ return (4ULL * GB) / MPX_BD_NR_ENTRIES_32;
+
+ /*
+ * 'x86_virt_bits' returns what the hardware is capable
+ * of, and returns the full >32-bit adddress space when
+ * running 32-bit kernels on 64-bit hardware.
+ */
+ virt_space = (1ULL << boot_cpu_data.x86_virt_bits);
+ return virt_space / MPX_BD_NR_ENTRIES_64;
}
/*
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index a3137a4..6000ad7 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -129,14 +129,16 @@ within(unsigned long addr, unsigned long start, unsigned long end)
*/
void clflush_cache_range(void *vaddr, unsigned int size)
{
- unsigned long clflush_mask = boot_cpu_data.x86_clflush_size - 1;
+ const unsigned long clflush_size = boot_cpu_data.x86_clflush_size;
+ void *p = (void *)((unsigned long)vaddr & ~(clflush_size - 1));
void *vend = vaddr + size;
- void *p;
+
+ if (p >= vend)
+ return;
mb();
- for (p = (void *)((unsigned long)vaddr & ~clflush_mask);
- p < vend; p += boot_cpu_data.x86_clflush_size)
+ for (; p < vend; p += clflush_size)
clflushopt(p);
mb();
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 188e3e0..031782e 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -586,7 +586,7 @@ int free_memtype(u64 start, u64 end)
entry = rbt_memtype_erase(start, end);
spin_unlock(&memtype_lock);
- if (!entry) {
+ if (IS_ERR(entry)) {
pr_info("x86/PAT: %s:%d freeing invalid memtype [mem %#010Lx-%#010Lx]\n",
current->comm, current->pid, start, end - 1);
return -EINVAL;
@@ -992,6 +992,16 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
vma->vm_flags &= ~VM_PAT;
}
+/*
+ * untrack_pfn_moved is called, while mremapping a pfnmap for a new region,
+ * with the old vma after its pfnmap page table has been removed. The new
+ * vma has a new pfnmap to the same pfn & cache type with VM_PAT set.
+ */
+void untrack_pfn_moved(struct vm_area_struct *vma)
+{
+ vma->vm_flags &= ~VM_PAT;
+}
+
pgprot_t pgprot_writecombine(pgprot_t prot)
{
return __pgprot(pgprot_val(prot) |
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c
index 6393108..2f77022 100644
--- a/arch/x86/mm/pat_rbtree.c
+++ b/arch/x86/mm/pat_rbtree.c
@@ -98,8 +98,13 @@ static struct memtype *memtype_rb_lowest_match(struct rb_root *root,
return last_lower; /* Returns NULL if there is no overlap */
}
-static struct memtype *memtype_rb_exact_match(struct rb_root *root,
- u64 start, u64 end)
+enum {
+ MEMTYPE_EXACT_MATCH = 0,
+ MEMTYPE_END_MATCH = 1
+};
+
+static struct memtype *memtype_rb_match(struct rb_root *root,
+ u64 start, u64 end, int match_type)
{
struct memtype *match;
@@ -107,7 +112,12 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root,
while (match != NULL && match->start < end) {
struct rb_node *node;
- if (match->start == start && match->end == end)
+ if ((match_type == MEMTYPE_EXACT_MATCH) &&
+ (match->start == start) && (match->end == end))
+ return match;
+
+ if ((match_type == MEMTYPE_END_MATCH) &&
+ (match->start < start) && (match->end == end))
return match;
node = rb_next(&match->rb);
@@ -117,7 +127,7 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root,
match = NULL;
}
- return NULL; /* Returns NULL if there is no exact match */
+ return NULL; /* Returns NULL if there is no match */
}
static int memtype_rb_check_conflict(struct rb_root *root,
@@ -210,12 +220,36 @@ struct memtype *rbt_memtype_erase(u64 start, u64 end)
{
struct memtype *data;
- data = memtype_rb_exact_match(&memtype_rbroot, start, end);
- if (!data)
- goto out;
+ /*
+ * Since the memtype_rbroot tree allows overlapping ranges,
+ * rbt_memtype_erase() checks with EXACT_MATCH first, i.e. free
+ * a whole node for the munmap case. If no such entry is found,
+ * it then checks with END_MATCH, i.e. shrink the size of a node
+ * from the end for the mremap case.
+ */
+ data = memtype_rb_match(&memtype_rbroot, start, end,
+ MEMTYPE_EXACT_MATCH);
+ if (!data) {
+ data = memtype_rb_match(&memtype_rbroot, start, end,
+ MEMTYPE_END_MATCH);
+ if (!data)
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (data->start == start) {
+ /* munmap: erase this node */
+ rb_erase_augmented(&data->rb, &memtype_rbroot,
+ &memtype_rb_augment_cb);
+ } else {
+ /* mremap: update the end value of this node */
+ rb_erase_augmented(&data->rb, &memtype_rbroot,
+ &memtype_rb_augment_cb);
+ data->end = start;
+ data->subtree_max_end = data->end;
+ memtype_rb_insert(&memtype_rbroot, data);
+ return NULL;
+ }
- rb_erase_augmented(&data->rb, &memtype_rbroot, &memtype_rb_augment_cb);
-out:
return data;
}
diff --git a/arch/x86/mm/pgtable.c b/arch/x86/mm/pgtable.c
index fb0a9dd..ee9c2e3 100644
--- a/arch/x86/mm/pgtable.c
+++ b/arch/x86/mm/pgtable.c
@@ -414,7 +414,7 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
if (changed && dirty) {
*ptep = entry;
- pte_update_defer(vma->vm_mm, address, ptep);
+ pte_update(vma->vm_mm, address, ptep);
}
return changed;
@@ -431,7 +431,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
if (changed && dirty) {
*pmdp = entry;
- pmd_update_defer(vma->vm_mm, address, pmdp);
/*
* We had a write-protection fault here and changed the pmd
* to to more permissive. No need to flush the TLB for that,
@@ -469,9 +468,6 @@ int pmdp_test_and_clear_young(struct vm_area_struct *vma,
ret = test_and_clear_bit(_PAGE_BIT_ACCESSED,
(unsigned long *)pmdp);
- if (ret)
- pmd_update(vma->vm_mm, addr, pmdp);
-
return ret;
}
#endif
@@ -518,7 +514,6 @@ void pmdp_splitting_flush(struct vm_area_struct *vma,
set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
(unsigned long *)pmdp);
if (set) {
- pmd_update(vma->vm_mm, address, pmdp);
/* need tlb flush only to serialize against gup-fast */
flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
}
diff --git a/arch/x86/mm/setup_nx.c b/arch/x86/mm/setup_nx.c
index 90555bf..92e2eac 100644
--- a/arch/x86/mm/setup_nx.c
+++ b/arch/x86/mm/setup_nx.c
@@ -31,7 +31,7 @@ early_param("noexec", noexec_setup);
void x86_configure_nx(void)
{
- if (cpu_has_nx && !disable_nx)
+ if (boot_cpu_has(X86_FEATURE_NX) && !disable_nx)
__supported_pte_mask |= _PAGE_NX;
else
__supported_pte_mask &= ~_PAGE_NX;
@@ -39,7 +39,7 @@ void x86_configure_nx(void)
void __init x86_report_nx(void)
{
- if (!cpu_has_nx) {
+ if (!boot_cpu_has(X86_FEATURE_NX)) {
printk(KERN_NOTICE "Notice: NX (Execute Disable) protection "
"missing in CPU!\n");
} else {
diff --git a/arch/x86/mm/srat.c b/arch/x86/mm/srat.c
index c2aea63..b5f8218 100644
--- a/arch/x86/mm/srat.c
+++ b/arch/x86/mm/srat.c
@@ -203,6 +203,8 @@ acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
pr_warn("SRAT: Failed to mark hotplug range [mem %#010Lx-%#010Lx] in memblock\n",
(unsigned long long)start, (unsigned long long)end - 1);
+ max_possible_pfn = max(max_possible_pfn, PFN_UP(end - 1));
+
return 0;
out_err_bad_srat:
bad_srat();
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c
index 7bcf06a..6eb3c8a 100644
--- a/arch/x86/pci/bus_numa.c
+++ b/arch/x86/pci/bus_numa.c
@@ -50,18 +50,9 @@ void x86_pci_root_bus_resources(int bus, struct list_head *resources)
if (!found)
pci_add_resource(resources, &info->busn);
- list_for_each_entry(root_res, &info->resources, list) {
- struct resource *res;
- struct resource *root;
+ list_for_each_entry(root_res, &info->resources, list)
+ pci_add_resource(resources, &root_res->res);
- res = &root_res->res;
- pci_add_resource(resources, res);
- if (res->flags & IORESOURCE_IO)
- root = &ioport_resource;
- else
- root = &iomem_resource;
- insert_resource(root, res);
- }
return;
default_resources:
diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c
index 327f21c..8dd8005 100644
--- a/arch/x86/platform/uv/uv_nmi.c
+++ b/arch/x86/platform/uv/uv_nmi.c
@@ -28,6 +28,7 @@
#include <linux/nmi.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/clocksource.h>
#include <asm/apic.h>
#include <asm/current.h>
diff --git a/arch/x86/power/cpu.c b/arch/x86/power/cpu.c
index 9ab5279..d5f6499 100644
--- a/arch/x86/power/cpu.c
+++ b/arch/x86/power/cpu.c
@@ -23,6 +23,7 @@
#include <asm/debugreg.h>
#include <asm/cpu.h>
#include <asm/mmu_context.h>
+#include <linux/dmi.h>
#ifdef CONFIG_X86_32
__visible unsigned long saved_context_ebx;
@@ -32,6 +33,29 @@ __visible unsigned long saved_context_eflags;
#endif
struct saved_context saved_context;
+static void msr_save_context(struct saved_context *ctxt)
+{
+ struct saved_msr *msr = ctxt->saved_msrs.array;
+ struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+ while (msr < end) {
+ msr->valid = !rdmsrl_safe(msr->info.msr_no, &msr->info.reg.q);
+ msr++;
+ }
+}
+
+static void msr_restore_context(struct saved_context *ctxt)
+{
+ struct saved_msr *msr = ctxt->saved_msrs.array;
+ struct saved_msr *end = msr + ctxt->saved_msrs.num;
+
+ while (msr < end) {
+ if (msr->valid)
+ wrmsrl(msr->info.msr_no, msr->info.reg.q);
+ msr++;
+ }
+}
+
/**
* __save_processor_state - save CPU registers before creating a
* hibernation image and before restoring the memory state from it
@@ -111,6 +135,7 @@ static void __save_processor_state(struct saved_context *ctxt)
#endif
ctxt->misc_enable_saved = !rdmsrl_safe(MSR_IA32_MISC_ENABLE,
&ctxt->misc_enable);
+ msr_save_context(ctxt);
}
/* Needed by apm.c */
@@ -229,6 +254,7 @@ static void notrace __restore_processor_state(struct saved_context *ctxt)
x86_platform.restore_sched_clock_state();
mtrr_bp_restore();
perf_restore_debug_store();
+ msr_restore_context(ctxt);
}
/* Needed by apm.c */
@@ -320,3 +346,69 @@ static int __init bsp_pm_check_init(void)
}
core_initcall(bsp_pm_check_init);
+
+static int msr_init_context(const u32 *msr_id, const int total_num)
+{
+ int i = 0;
+ struct saved_msr *msr_array;
+
+ if (saved_context.saved_msrs.array || saved_context.saved_msrs.num > 0) {
+ pr_err("x86/pm: MSR quirk already applied, please check your DMI match table.\n");
+ return -EINVAL;
+ }
+
+ msr_array = kmalloc_array(total_num, sizeof(struct saved_msr), GFP_KERNEL);
+ if (!msr_array) {
+ pr_err("x86/pm: Can not allocate memory to save/restore MSRs during suspend.\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < total_num; i++) {
+ msr_array[i].info.msr_no = msr_id[i];
+ msr_array[i].valid = false;
+ msr_array[i].info.reg.q = 0;
+ }
+ saved_context.saved_msrs.num = total_num;
+ saved_context.saved_msrs.array = msr_array;
+
+ return 0;
+}
+
+/*
+ * The following section is a quirk framework for problematic BIOSen:
+ * Sometimes MSRs are modified by the BIOSen after suspended to
+ * RAM, this might cause unexpected behavior after wakeup.
+ * Thus we save/restore these specified MSRs across suspend/resume
+ * in order to work around it.
+ *
+ * For any further problematic BIOSen/platforms,
+ * please add your own function similar to msr_initialize_bdw.
+ */
+static int msr_initialize_bdw(const struct dmi_system_id *d)
+{
+ /* Add any extra MSR ids into this array. */
+ u32 bdw_msr_id[] = { MSR_IA32_THERM_CONTROL };
+
+ pr_info("x86/pm: %s detected, MSR saving is needed during suspending.\n", d->ident);
+ return msr_init_context(bdw_msr_id, ARRAY_SIZE(bdw_msr_id));
+}
+
+static struct dmi_system_id msr_save_dmi_table[] = {
+ {
+ .callback = msr_initialize_bdw,
+ .ident = "BROADWELL BDX_EP",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "GRANTLEY"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "E63448-400"),
+ },
+ },
+ {}
+};
+
+static int pm_check_save_msr(void)
+{
+ dmi_check_system(msr_save_dmi_table);
+ return 0;
+}
+
+device_initcall(pm_check_save_msr);
diff --git a/arch/x86/um/Makefile b/arch/x86/um/Makefile
index a8fecc2..3ee2bb6 100644
--- a/arch/x86/um/Makefile
+++ b/arch/x86/um/Makefile
@@ -17,7 +17,7 @@ obj-y = bug.o bugs_$(BITS).o delay.o fault.o ksyms.o ldt.o \
ifeq ($(CONFIG_X86_32),y)
obj-y += checksum_32.o
-obj-$(CONFIG_BINFMT_ELF) += elfcore.o
+obj-$(CONFIG_ELF_CORE) += elfcore.o
subarch-y = ../lib/string_32.o ../lib/atomic64_32.o ../lib/atomic64_cx8_32.o
subarch-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += ../lib/rwsem.o
diff --git a/arch/x86/um/asm/syscall.h b/arch/x86/um/asm/syscall.h
index 81d6562..11ab90d 100644
--- a/arch/x86/um/asm/syscall.h
+++ b/arch/x86/um/asm/syscall.h
@@ -1,6 +1,7 @@
#ifndef __UM_ASM_SYSCALL_H
#define __UM_ASM_SYSCALL_H
+#include <asm/syscall-generic.h>
#include <uapi/linux/audit.h>
typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c
index a29756f2..47c78d5 100644
--- a/arch/x86/um/ptrace_32.c
+++ b/arch/x86/um/ptrace_32.c
@@ -68,6 +68,7 @@ static const int reg_offsets[] = {
[EFL] = HOST_EFLAGS,
[UESP] = HOST_SP,
[SS] = HOST_SS,
+ [ORIG_EAX] = HOST_ORIG_AX,
};
int putreg(struct task_struct *child, int regno, unsigned long value)
@@ -83,6 +84,7 @@ int putreg(struct task_struct *child, int regno, unsigned long value)
case EAX:
case EIP:
case UESP:
+ case ORIG_EAX:
break;
case FS:
if (value && (value & 3) != 3)
@@ -108,9 +110,6 @@ int putreg(struct task_struct *child, int regno, unsigned long value)
value &= FLAG_MASK;
child->thread.regs.regs.gp[HOST_EFLAGS] |= value;
return 0;
- case ORIG_EAX:
- child->thread.regs.regs.syscall = value;
- return 0;
default :
panic("Bad register in putreg() : %d\n", regno);
}
@@ -143,8 +142,6 @@ unsigned long getreg(struct task_struct *child, int regno)
regno >>= 2;
switch (regno) {
- case ORIG_EAX:
- return child->thread.regs.regs.syscall;
case FS:
case GS:
case DS:
@@ -163,6 +160,7 @@ unsigned long getreg(struct task_struct *child, int regno)
case EDI:
case EBP:
case EFL:
+ case ORIG_EAX:
break;
default:
panic("Bad register in getreg() : %d\n", regno);
diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c
index 06934a8..14fcd01 100644
--- a/arch/x86/um/signal.c
+++ b/arch/x86/um/signal.c
@@ -211,7 +211,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
if (err)
return 1;
- err = convert_fxsr_from_user(&fpx, sc.fpstate);
+ err = convert_fxsr_from_user(&fpx, (void *)sc.fpstate);
if (err)
return 1;
@@ -227,7 +227,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
{
struct user_i387_struct fp;
- err = copy_from_user(&fp, sc.fpstate,
+ err = copy_from_user(&fp, (void *)sc.fpstate,
sizeof(struct user_i387_struct));
if (err)
return 1;
@@ -291,7 +291,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
#endif
#undef PUTREG
sc.oldmask = mask;
- sc.fpstate = to_fp;
+ sc.fpstate = (unsigned long)to_fp;
err = copy_to_user(to, &sc, sizeof(struct sigcontext));
if (err)
@@ -468,12 +468,10 @@ long sys_sigreturn(void)
struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
sigset_t set;
struct sigcontext __user *sc = &frame->sc;
- unsigned long __user *oldmask = &sc->oldmask;
- unsigned long __user *extramask = frame->extramask;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
- if (copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
- copy_from_user(&set.sig[1], extramask, sig_size))
+ if (copy_from_user(&set.sig[0], &sc->oldmask, sizeof(set.sig[0])) ||
+ copy_from_user(&set.sig[1], frame->extramask, sig_size))
goto segfault;
set_current_blocked(&set);
@@ -505,6 +503,7 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
{
struct rt_sigframe __user *frame;
int err = 0, sig = ksig->sig;
+ unsigned long fp_to;
frame = (struct rt_sigframe __user *)
round_down(stack_top - sizeof(struct rt_sigframe), 16);
@@ -526,7 +525,10 @@ int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs));
err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
set->sig[0]);
- err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
+
+ fp_to = (unsigned long)&frame->fpstate;
+
+ err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate);
if (sizeof(*set) == 16) {
err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
diff --git a/arch/x86/um/stub_32.S b/arch/x86/um/stub_32.S
index b972649..9881680 100644
--- a/arch/x86/um/stub_32.S
+++ b/arch/x86/um/stub_32.S
@@ -1,6 +1,5 @@
#include <as-layout.h>
- .globl syscall_stub
.section .__syscall_stub, "ax"
.globl batch_syscall_stub
diff --git a/arch/x86/um/stub_64.S b/arch/x86/um/stub_64.S
index 7160b20..ba914b3 100644
--- a/arch/x86/um/stub_64.S
+++ b/arch/x86/um/stub_64.S
@@ -1,25 +1,9 @@
#include <as-layout.h>
- .globl syscall_stub
.section .__syscall_stub, "ax"
-syscall_stub:
- syscall
- /* We don't have 64-bit constants, so this constructs the address
- * we need.
- */
- movq $(STUB_DATA >> 32), %rbx
- salq $32, %rbx
- movq $(STUB_DATA & 0xffffffff), %rcx
- or %rcx, %rbx
- movq %rax, (%rbx)
- int3
-
.globl batch_syscall_stub
batch_syscall_stub:
- mov $(STUB_DATA >> 32), %rbx
- sal $32, %rbx
- mov $(STUB_DATA & 0xffffffff), %rax
- or %rax, %rbx
+ mov $(STUB_DATA), %rbx
/* load pointer to first operation */
mov %rbx, %rsp
add $0x10, %rsp
diff --git a/arch/x86/xen/apic.c b/arch/x86/xen/apic.c
index acda713..abf4901 100644
--- a/arch/x86/xen/apic.c
+++ b/arch/x86/xen/apic.c
@@ -64,7 +64,7 @@ static u32 xen_apic_read(u32 reg)
if (reg != APIC_ID)
return 0;
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
return 0;
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 5774800..d09e4c9 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -415,7 +415,7 @@ static bool __init xen_check_mwait(void)
set_xen_guest_handle(op.u.set_pminfo.pdc, buf);
- if ((HYPERVISOR_dom0_op(&op) == 0) &&
+ if ((HYPERVISOR_platform_op(&op) == 0) &&
(buf[2] & (ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH))) {
cpuid_leaf5_ecx_val = cx;
cpuid_leaf5_edx_val = dx;
@@ -1192,7 +1192,7 @@ static const struct pv_info xen_info __initconst = {
#ifdef CONFIG_X86_64
.extra_user_64bit_cs = FLAT_USER_CS64,
#endif
-
+ .features = 0,
.name = "Xen",
};
@@ -1229,10 +1229,7 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.iret = xen_iret,
#ifdef CONFIG_X86_64
- .usergs_sysret32 = xen_sysret32,
.usergs_sysret64 = xen_sysret64,
-#else
- .irq_enable_sysexit = xen_sysexit,
#endif
.load_tr_desc = paravirt_nop,
@@ -1265,12 +1262,6 @@ static const struct pv_cpu_ops xen_cpu_ops __initconst = {
.end_context_switch = xen_end_context_switch,
};
-static const struct pv_apic_ops xen_apic_ops __initconst = {
-#ifdef CONFIG_X86_LOCAL_APIC
- .startup_ipi_hook = paravirt_nop,
-#endif
-};
-
static void xen_reboot(int reason)
{
struct sched_shutdown r = { .reason = reason };
@@ -1374,7 +1365,7 @@ static void __init xen_boot_params_init_edd(void)
info->params.length = sizeof(info->params);
set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
&info->params);
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
break;
@@ -1392,7 +1383,7 @@ static void __init xen_boot_params_init_edd(void)
op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
for (nr = 0; nr < EDD_MBR_SIG_MAX; nr++) {
op.u.firmware_info.index = nr;
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
break;
mbr_signature[nr] = op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
@@ -1535,8 +1526,9 @@ asmlinkage __visible void __init xen_start_kernel(void)
/* Install Xen paravirt ops */
pv_info = xen_info;
+ if (xen_initial_domain())
+ pv_info.features |= PV_SUPPORTED_RTC;
pv_init_ops = xen_init_ops;
- pv_apic_ops = xen_apic_ops;
if (!xen_pvh_domain()) {
pv_cpu_ops = xen_cpu_ops;
@@ -1698,7 +1690,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
xen_start_info->console.domU.mfn = 0;
xen_start_info->console.domU.evtchn = 0;
- if (HYPERVISOR_dom0_op(&op) == 0)
+ if (HYPERVISOR_platform_op(&op) == 0)
boot_params.kbd_status = op.u.firmware_info.u.kbd_shift_flags;
/* Make sure ACS will be enabled */
@@ -1886,8 +1878,10 @@ EXPORT_SYMBOL_GPL(xen_hvm_need_lapic);
static void xen_set_cpu_features(struct cpuinfo_x86 *c)
{
- if (xen_pv_domain())
+ if (xen_pv_domain()) {
clear_cpu_bug(c, X86_BUG_SYSRET_SS_ATTRS);
+ set_cpu_cap(c, X86_FEATURE_XENPV);
+ }
}
const struct hypervisor_x86 x86_hyper_xen = {
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index ac161db..c913ca4 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2436,7 +2436,6 @@ static const struct pv_mmu_ops xen_mmu_ops __initconst = {
.flush_tlb_others = xen_flush_tlb_others,
.pte_update = paravirt_nop,
- .pte_update_defer = paravirt_nop,
.pgd_alloc = xen_pgd_alloc,
.pgd_free = xen_pgd_free,
@@ -2495,14 +2494,9 @@ void __init xen_init_mmu_ops(void)
{
x86_init.paging.pagetable_init = xen_pagetable_init;
- /* Optimization - we can use the HVM one but it has no idea which
- * VCPUs are descheduled - which means that it will needlessly IPI
- * them. Xen knows so let it do the job.
- */
- if (xen_feature(XENFEAT_auto_translated_physmap)) {
- pv_mmu_ops.flush_tlb_others = xen_flush_tlb_others;
+ if (xen_feature(XENFEAT_auto_translated_physmap))
return;
- }
+
pv_mmu_ops = xen_mmu_ops;
memset(dummy_mapping, 0xff, PAGE_SIZE);
diff --git a/arch/x86/xen/suspend.c b/arch/x86/xen/suspend.c
index feddabd..7f664c4 100644
--- a/arch/x86/xen/suspend.c
+++ b/arch/x86/xen/suspend.c
@@ -1,6 +1,7 @@
#include <linux/types.h>
#include <linux/tick.h>
+#include <xen/xen.h>
#include <xen/interface/xen.h>
#include <xen/grant_table.h>
#include <xen/events.h>
@@ -33,7 +34,8 @@ static void xen_hvm_post_suspend(int suspend_cancelled)
{
#ifdef CONFIG_XEN_PVHVM
int cpu;
- xen_hvm_init_shared_info();
+ if (!suspend_cancelled)
+ xen_hvm_init_shared_info();
xen_callback_vector();
xen_unplug_emulated_devices();
if (xen_feature(XENFEAT_hvm_safe_pvclock)) {
@@ -68,26 +70,16 @@ static void xen_pv_post_suspend(int suspend_cancelled)
void xen_arch_pre_suspend(void)
{
- int cpu;
-
- for_each_online_cpu(cpu)
- xen_pmu_finish(cpu);
-
if (xen_pv_domain())
xen_pv_pre_suspend();
}
void xen_arch_post_suspend(int cancelled)
{
- int cpu;
-
if (xen_pv_domain())
xen_pv_post_suspend(cancelled);
else
xen_hvm_post_suspend(cancelled);
-
- for_each_online_cpu(cpu)
- xen_pmu_init(cpu);
}
static void xen_vcpu_notify_restore(void *data)
@@ -106,10 +98,20 @@ static void xen_vcpu_notify_suspend(void *data)
void xen_arch_resume(void)
{
+ int cpu;
+
on_each_cpu(xen_vcpu_notify_restore, NULL, 1);
+
+ for_each_online_cpu(cpu)
+ xen_pmu_init(cpu);
}
void xen_arch_suspend(void)
{
+ int cpu;
+
+ for_each_online_cpu(cpu)
+ xen_pmu_finish(cpu);
+
on_each_cpu(xen_vcpu_notify_suspend, NULL, 1);
}
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index f1ba6a0..a0a4e55 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -16,6 +16,7 @@
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/pvclock_gtod.h>
+#include <linux/timekeeper_internal.h>
#include <asm/pvclock.h>
#include <asm/xen/hypervisor.h>
@@ -32,86 +33,12 @@
#define TIMER_SLOP 100000
#define NS_PER_TICK (1000000000LL / HZ)
-/* runstate info updated by Xen */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
-
/* snapshots of runstate info */
static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
/* unused ns of stolen time */
static DEFINE_PER_CPU(u64, xen_residual_stolen);
-/* return an consistent snapshot of 64-bit time/counter value */
-static u64 get64(const u64 *p)
-{
- u64 ret;
-
- if (BITS_PER_LONG < 64) {
- u32 *p32 = (u32 *)p;
- u32 h, l;
-
- /*
- * Read high then low, and then make sure high is
- * still the same; this will only loop if low wraps
- * and carries into high.
- * XXX some clean way to make this endian-proof?
- */
- do {
- h = p32[1];
- barrier();
- l = p32[0];
- barrier();
- } while (p32[1] != h);
-
- ret = (((u64)h) << 32) | l;
- } else
- ret = *p;
-
- return ret;
-}
-
-/*
- * Runstate accounting
- */
-static void get_runstate_snapshot(struct vcpu_runstate_info *res)
-{
- u64 state_time;
- struct vcpu_runstate_info *state;
-
- BUG_ON(preemptible());
-
- state = this_cpu_ptr(&xen_runstate);
-
- /*
- * The runstate info is always updated by the hypervisor on
- * the current CPU, so there's no need to use anything
- * stronger than a compiler barrier when fetching it.
- */
- do {
- state_time = get64(&state->state_entry_time);
- barrier();
- *res = *state;
- barrier();
- } while (get64(&state->state_entry_time) != state_time);
-}
-
-/* return true when a vcpu could run but has no real cpu to run on */
-bool xen_vcpu_stolen(int vcpu)
-{
- return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
-}
-
-void xen_setup_runstate_info(int cpu)
-{
- struct vcpu_register_runstate_memory_area area;
-
- area.addr.v = &per_cpu(xen_runstate, cpu);
-
- if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
- cpu, &area))
- BUG();
-}
-
static void do_stolen_accounting(void)
{
struct vcpu_runstate_info state;
@@ -119,7 +46,7 @@ static void do_stolen_accounting(void)
s64 runnable, offline, stolen;
cputime_t ticks;
- get_runstate_snapshot(&state);
+ xen_get_runstate_snapshot(&state);
WARN_ON(state.state != RUNSTATE_running);
@@ -194,26 +121,46 @@ static int xen_pvclock_gtod_notify(struct notifier_block *nb,
unsigned long was_set, void *priv)
{
/* Protected by the calling core code serialization */
- static struct timespec next_sync;
+ static struct timespec64 next_sync;
struct xen_platform_op op;
- struct timespec now;
+ struct timespec64 now;
+ struct timekeeper *tk = priv;
+ static bool settime64_supported = true;
+ int ret;
- now = __current_kernel_time();
+ now.tv_sec = tk->xtime_sec;
+ now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
/*
* We only take the expensive HV call when the clock was set
* or when the 11 minutes RTC synchronization time elapsed.
*/
- if (!was_set && timespec_compare(&now, &next_sync) < 0)
+ if (!was_set && timespec64_compare(&now, &next_sync) < 0)
return NOTIFY_OK;
- op.cmd = XENPF_settime;
- op.u.settime.secs = now.tv_sec;
- op.u.settime.nsecs = now.tv_nsec;
- op.u.settime.system_time = xen_clocksource_read();
+again:
+ if (settime64_supported) {
+ op.cmd = XENPF_settime64;
+ op.u.settime64.mbz = 0;
+ op.u.settime64.secs = now.tv_sec;
+ op.u.settime64.nsecs = now.tv_nsec;
+ op.u.settime64.system_time = xen_clocksource_read();
+ } else {
+ op.cmd = XENPF_settime32;
+ op.u.settime32.secs = now.tv_sec;
+ op.u.settime32.nsecs = now.tv_nsec;
+ op.u.settime32.system_time = xen_clocksource_read();
+ }
+
+ ret = HYPERVISOR_platform_op(&op);
- (void)HYPERVISOR_dom0_op(&op);
+ if (ret == -ENOSYS && settime64_supported) {
+ settime64_supported = false;
+ goto again;
+ }
+ if (ret < 0)
+ return NOTIFY_BAD;
/*
* Move the next drift compensation time 11 minutes
diff --git a/arch/x86/xen/xen-asm_32.S b/arch/x86/xen/xen-asm_32.S
index fd92a64..feb6d40 100644
--- a/arch/x86/xen/xen-asm_32.S
+++ b/arch/x86/xen/xen-asm_32.S
@@ -35,20 +35,6 @@ check_events:
ret
/*
- * We can't use sysexit directly, because we're not running in ring0.
- * But we can easily fake it up using iret. Assuming xen_sysexit is
- * jumped to with a standard stack frame, we can just strip it back to
- * a standard iret frame and use iret.
- */
-ENTRY(xen_sysexit)
- movl PT_EAX(%esp), %eax /* Shouldn't be necessary? */
- orl $X86_EFLAGS_IF, PT_EFLAGS(%esp)
- lea PT_EIP(%esp), %esp
-
- jmp xen_iret
-ENDPROC(xen_sysexit)
-
-/*
* This is run where a normal iret would be run, with the same stack setup:
* 8: eflags
* 4: cs
diff --git a/arch/x86/xen/xen-asm_64.S b/arch/x86/xen/xen-asm_64.S
index f22667a..cc8acc4 100644
--- a/arch/x86/xen/xen-asm_64.S
+++ b/arch/x86/xen/xen-asm_64.S
@@ -68,25 +68,6 @@ ENTRY(xen_sysret64)
ENDPATCH(xen_sysret64)
RELOC(xen_sysret64, 1b+1)
-ENTRY(xen_sysret32)
- /*
- * We're already on the usermode stack at this point, but
- * still with the kernel gs, so we can easily switch back
- */
- movq %rsp, PER_CPU_VAR(rsp_scratch)
- movq PER_CPU_VAR(cpu_current_top_of_stack), %rsp
-
- pushq $__USER32_DS
- pushq PER_CPU_VAR(rsp_scratch)
- pushq %r11
- pushq $__USER32_CS
- pushq %rcx
-
- pushq $0
-1: jmp hypercall_iret
-ENDPATCH(xen_sysret32)
-RELOC(xen_sysret32, 1b+1)
-
/*
* Xen handles syscall callbacks much like ordinary exceptions, which
* means we have:
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 1399423..4140b07 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -139,9 +139,6 @@ DECL_ASM(void, xen_restore_fl_direct, unsigned long);
/* These are not functions, and cannot be called normally */
__visible void xen_iret(void);
-#ifdef CONFIG_X86_32
-__visible void xen_sysexit(void);
-#endif
__visible void xen_sysret32(void);
__visible void xen_sysret64(void);
__visible void xen_adjust_exception_frame(void);
diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c
index fa84ca9..f58a4e6 100644
--- a/arch/xtensa/platforms/iss/simdisk.c
+++ b/arch/xtensa/platforms/iss/simdisk.c
@@ -101,7 +101,7 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector,
spin_unlock(&dev->lock);
}
-static void simdisk_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t simdisk_make_request(struct request_queue *q, struct bio *bio)
{
struct simdisk *dev = q->queuedata;
struct bio_vec bvec;
@@ -119,6 +119,7 @@ static void simdisk_make_request(struct request_queue *q, struct bio *bio)
}
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
static int simdisk_open(struct block_device *bdev, fmode_t mode)
@@ -226,16 +227,12 @@ static ssize_t proc_read_simdisk(struct file *file, char __user *buf,
static ssize_t proc_write_simdisk(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char *tmp = kmalloc(count + 1, GFP_KERNEL);
+ char *tmp = memdup_user_nul(buf, count);
struct simdisk *dev = PDE_DATA(file_inode(file));
int err;
- if (tmp == NULL)
- return -ENOMEM;
- if (copy_from_user(tmp, buf, count)) {
- err = -EFAULT;
- goto out_free;
- }
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
err = simdisk_detach(dev);
if (err != 0)
@@ -243,8 +240,6 @@ static ssize_t proc_write_simdisk(struct file *file, const char __user *buf,
if (count > 0 && tmp[count - 1] == '\n')
tmp[count - 1] = 0;
- else
- tmp[count] = 0;
if (tmp[0])
err = simdisk_attach(dev, tmp);
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 5bcdfc1..5a37188 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1127,15 +1127,15 @@ void blkcg_exit_queue(struct request_queue *q)
* of the main cic data structures. For now we allow a task to change
* its cgroup only if it's the only owner of its ioc.
*/
-static int blkcg_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int blkcg_can_attach(struct cgroup_taskset *tset)
{
struct task_struct *task;
+ struct cgroup_subsys_state *dst_css;
struct io_context *ioc;
int ret = 0;
/* task_lock() is needed to avoid races with exit_io_context() */
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, dst_css, tset) {
task_lock(task);
ioc = task->io_context;
if (ioc && atomic_read(&ioc->nr_tasks) > 1)
diff --git a/block/blk-core.c b/block/blk-core.c
index 590cca2..33e2f62 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -207,6 +207,22 @@ void blk_delay_queue(struct request_queue *q, unsigned long msecs)
EXPORT_SYMBOL(blk_delay_queue);
/**
+ * blk_start_queue_async - asynchronously restart a previously stopped queue
+ * @q: The &struct request_queue in question
+ *
+ * Description:
+ * blk_start_queue_async() will clear the stop flag on the queue, and
+ * ensure that the request_fn for the queue is run from an async
+ * context.
+ **/
+void blk_start_queue_async(struct request_queue *q)
+{
+ queue_flag_clear(QUEUE_FLAG_STOPPED, q);
+ blk_run_queue_async(q);
+}
+EXPORT_SYMBOL(blk_start_queue_async);
+
+/**
* blk_start_queue - restart a previously stopped queue
* @q: The &struct request_queue in question
*
@@ -809,7 +825,7 @@ blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
}
EXPORT_SYMBOL(blk_init_queue_node);
-static void blk_queue_bio(struct request_queue *q, struct bio *bio);
+static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio);
struct request_queue *
blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn,
@@ -1575,6 +1591,9 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
* @q: request_queue new bio is being queued at
* @bio: new bio being queued
* @request_count: out parameter for number of traversed plugged requests
+ * @same_queue_rq: pointer to &struct request that gets filled in when
+ * another request associated with @q is found on the plug list
+ * (optional, may be %NULL)
*
* Determine whether @bio being queued on @q can be merged with a request
* on %current's plugged list. Returns %true if merge was successful,
@@ -1678,7 +1697,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
blk_rq_bio_prep(req->q, req, bio);
}
-static void blk_queue_bio(struct request_queue *q, struct bio *bio)
+static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio)
{
const bool sync = !!(bio->bi_rw & REQ_SYNC);
struct blk_plug *plug;
@@ -1686,8 +1705,6 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
struct request *req;
unsigned int request_count = 0;
- blk_queue_split(q, &bio, q->bio_split);
-
/*
* low level driver can indicate that it wants pages above a
* certain limit bounced to low memory (ie for highmem, or even
@@ -1695,10 +1712,12 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
*/
blk_queue_bounce(q, &bio);
+ blk_queue_split(q, &bio, q->bio_split);
+
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
bio->bi_error = -EIO;
bio_endio(bio);
- return;
+ return BLK_QC_T_NONE;
}
if (bio->bi_rw & (REQ_FLUSH | REQ_FUA)) {
@@ -1713,7 +1732,7 @@ static void blk_queue_bio(struct request_queue *q, struct bio *bio)
*/
if (!blk_queue_nomerges(q)) {
if (blk_attempt_plug_merge(q, bio, &request_count, NULL))
- return;
+ return BLK_QC_T_NONE;
} else
request_count = blk_plug_queued_count(q);
@@ -1791,6 +1810,8 @@ get_rq:
out_unlock:
spin_unlock_irq(q->queue_lock);
}
+
+ return BLK_QC_T_NONE;
}
/*
@@ -1996,12 +2017,13 @@ end_io:
* a lower device by calling into generic_make_request recursively, which
* means the bio should NOT be touched after the call to ->make_request_fn.
*/
-void generic_make_request(struct bio *bio)
+blk_qc_t generic_make_request(struct bio *bio)
{
struct bio_list bio_list_on_stack;
+ blk_qc_t ret = BLK_QC_T_NONE;
if (!generic_make_request_checks(bio))
- return;
+ goto out;
/*
* We only want one ->make_request_fn to be active at a time, else
@@ -2015,7 +2037,7 @@ void generic_make_request(struct bio *bio)
*/
if (current->bio_list) {
bio_list_add(current->bio_list, bio);
- return;
+ goto out;
}
/* following loop may be a bit non-obvious, and so deserves some
@@ -2040,7 +2062,7 @@ void generic_make_request(struct bio *bio)
if (likely(blk_queue_enter(q, __GFP_DIRECT_RECLAIM) == 0)) {
- q->make_request_fn(q, bio);
+ ret = q->make_request_fn(q, bio);
blk_queue_exit(q);
@@ -2053,6 +2075,9 @@ void generic_make_request(struct bio *bio)
}
} while (bio);
current->bio_list = NULL; /* deactivate */
+
+out:
+ return ret;
}
EXPORT_SYMBOL(generic_make_request);
@@ -2066,7 +2091,7 @@ EXPORT_SYMBOL(generic_make_request);
* interfaces; @bio must be presetup and ready for I/O.
*
*/
-void submit_bio(int rw, struct bio *bio)
+blk_qc_t submit_bio(int rw, struct bio *bio)
{
bio->bi_rw |= rw;
@@ -2100,12 +2125,13 @@ void submit_bio(int rw, struct bio *bio)
}
}
- generic_make_request(bio);
+ return generic_make_request(bio);
}
EXPORT_SYMBOL(submit_bio);
/**
- * blk_rq_check_limits - Helper function to check a request for the queue limit
+ * blk_cloned_rq_check_limits - Helper function to check a cloned request
+ * for new the queue limits
* @q: the queue
* @rq: the request being checked
*
@@ -2116,20 +2142,13 @@ EXPORT_SYMBOL(submit_bio);
* after it is inserted to @q, it should be checked against @q before
* the insertion using this generic function.
*
- * This function should also be useful for request stacking drivers
- * in some cases below, so export this function.
* Request stacking drivers like request-based dm may change the queue
- * limits while requests are in the queue (e.g. dm's table swapping).
- * Such request stacking drivers should check those requests against
- * the new queue limits again when they dispatch those requests,
- * although such checkings are also done against the old queue limits
- * when submitting requests.
+ * limits when retrying requests on other queues. Those requests need
+ * to be checked against the new queue limits again during dispatch.
*/
-int blk_rq_check_limits(struct request_queue *q, struct request *rq)
+static int blk_cloned_rq_check_limits(struct request_queue *q,
+ struct request *rq)
{
- if (!rq_mergeable(rq))
- return 0;
-
if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, rq->cmd_flags)) {
printk(KERN_ERR "%s: over max size limit.\n", __func__);
return -EIO;
@@ -2149,7 +2168,6 @@ int blk_rq_check_limits(struct request_queue *q, struct request *rq)
return 0;
}
-EXPORT_SYMBOL_GPL(blk_rq_check_limits);
/**
* blk_insert_cloned_request - Helper for stacking drivers to submit a request
@@ -2161,7 +2179,7 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
unsigned long flags;
int where = ELEVATOR_INSERT_BACK;
- if (blk_rq_check_limits(q, rq))
+ if (blk_cloned_rq_check_limits(q, rq))
return -EIO;
if (rq->rq_disk &&
@@ -3306,6 +3324,47 @@ void blk_finish_plug(struct blk_plug *plug)
}
EXPORT_SYMBOL(blk_finish_plug);
+bool blk_poll(struct request_queue *q, blk_qc_t cookie)
+{
+ struct blk_plug *plug;
+ long state;
+
+ if (!q->mq_ops || !q->mq_ops->poll || !blk_qc_t_valid(cookie) ||
+ !test_bit(QUEUE_FLAG_POLL, &q->queue_flags))
+ return false;
+
+ plug = current->plug;
+ if (plug)
+ blk_flush_plug_list(plug, false);
+
+ state = current->state;
+ while (!need_resched()) {
+ unsigned int queue_num = blk_qc_t_to_queue_num(cookie);
+ struct blk_mq_hw_ctx *hctx = q->queue_hw_ctx[queue_num];
+ int ret;
+
+ hctx->poll_invoked++;
+
+ ret = q->mq_ops->poll(hctx, blk_qc_t_to_tag(cookie));
+ if (ret > 0) {
+ hctx->poll_success++;
+ set_current_state(TASK_RUNNING);
+ return true;
+ }
+
+ if (signal_pending_state(state, current))
+ set_current_state(TASK_RUNNING);
+
+ if (current->state == TASK_RUNNING)
+ return true;
+ if (ret < 0)
+ break;
+ cpu_relax();
+ }
+
+ return false;
+}
+
#ifdef CONFIG_PM
/**
* blk_pm_runtime_init - Block layer runtime PM initialization routine
@@ -3362,6 +3421,9 @@ int blk_pre_runtime_suspend(struct request_queue *q)
{
int ret = 0;
+ if (!q->dev)
+ return ret;
+
spin_lock_irq(q->queue_lock);
if (q->nr_pending) {
ret = -EBUSY;
@@ -3389,6 +3451,9 @@ EXPORT_SYMBOL(blk_pre_runtime_suspend);
*/
void blk_post_runtime_suspend(struct request_queue *q, int err)
{
+ if (!q->dev)
+ return;
+
spin_lock_irq(q->queue_lock);
if (!err) {
q->rpm_status = RPM_SUSPENDED;
@@ -3413,6 +3478,9 @@ EXPORT_SYMBOL(blk_post_runtime_suspend);
*/
void blk_pre_runtime_resume(struct request_queue *q)
{
+ if (!q->dev)
+ return;
+
spin_lock_irq(q->queue_lock);
q->rpm_status = RPM_RESUMING;
spin_unlock_irq(q->queue_lock);
@@ -3435,6 +3503,9 @@ EXPORT_SYMBOL(blk_pre_runtime_resume);
*/
void blk_post_runtime_resume(struct request_queue *q, int err)
{
+ if (!q->dev)
+ return;
+
spin_lock_irq(q->queue_lock);
if (!err) {
q->rpm_status = RPM_ACTIVE;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index de5716d8..e01405a 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -76,6 +76,9 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
struct bio_vec bv, bvprv, *bvprvp = NULL;
struct bvec_iter iter;
unsigned seg_size = 0, nsegs = 0, sectors = 0;
+ unsigned front_seg_size = bio->bi_seg_front_size;
+ bool do_split = true;
+ struct bio *new = NULL;
bio_for_each_segment(bv, bio, iter) {
if (sectors + (bv.bv_len >> 9) > queue_max_sectors(q))
@@ -98,8 +101,11 @@ static struct bio *blk_bio_segment_split(struct request_queue *q,
seg_size += bv.bv_len;
bvprv = bv;
- bvprvp = &bv;
+ bvprvp = &bvprv;
sectors += bv.bv_len >> 9;
+
+ if (nsegs == 1 && seg_size > front_seg_size)
+ front_seg_size = seg_size;
continue;
}
new_segment:
@@ -108,16 +114,29 @@ new_segment:
nsegs++;
bvprv = bv;
- bvprvp = &bv;
+ bvprvp = &bvprv;
seg_size = bv.bv_len;
sectors += bv.bv_len >> 9;
+
+ if (nsegs == 1 && seg_size > front_seg_size)
+ front_seg_size = seg_size;
}
- *segs = nsegs;
- return NULL;
+ do_split = false;
split:
*segs = nsegs;
- return bio_split(bio, sectors, GFP_NOIO, bs);
+
+ if (do_split) {
+ new = bio_split(bio, sectors, GFP_NOIO, bs);
+ if (new)
+ bio = new;
+ }
+
+ bio->bi_seg_front_size = front_seg_size;
+ if (seg_size > bio->bi_seg_back_size)
+ bio->bi_seg_back_size = seg_size;
+
+ return do_split ? new : NULL;
}
void blk_queue_split(struct request_queue *q, struct bio **bio,
@@ -412,6 +431,12 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
if (sg)
sg_mark_end(sg);
+ /*
+ * Something must have been wrong if the figured number of
+ * segment is bigger than number of req's physical segments
+ */
+ WARN_ON(nsegs > rq->nr_phys_segments);
+
return nsegs;
}
EXPORT_SYMBOL(blk_rq_map_sg);
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c
index 6f57a11..1cf1878 100644
--- a/block/blk-mq-sysfs.c
+++ b/block/blk-mq-sysfs.c
@@ -174,6 +174,11 @@ static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page)
return ret;
}
+static ssize_t blk_mq_hw_sysfs_poll_show(struct blk_mq_hw_ctx *hctx, char *page)
+{
+ return sprintf(page, "invoked=%lu, success=%lu\n", hctx->poll_invoked, hctx->poll_success);
+}
+
static ssize_t blk_mq_hw_sysfs_queued_show(struct blk_mq_hw_ctx *hctx,
char *page)
{
@@ -295,6 +300,10 @@ static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
.attr = {.name = "cpu_list", .mode = S_IRUGO },
.show = blk_mq_hw_sysfs_cpus_show,
};
+static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_poll = {
+ .attr = {.name = "io_poll", .mode = S_IRUGO },
+ .show = blk_mq_hw_sysfs_poll_show,
+};
static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_queued.attr,
@@ -304,6 +313,7 @@ static struct attribute *default_hw_ctx_attrs[] = {
&blk_mq_hw_sysfs_tags.attr,
&blk_mq_hw_sysfs_cpus.attr,
&blk_mq_hw_sysfs_active.attr,
+ &blk_mq_hw_sysfs_poll.attr,
NULL,
};
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 694f870..6d6f8fe 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -358,7 +358,7 @@ static void blk_mq_ipi_complete_request(struct request *rq)
put_cpu();
}
-void __blk_mq_complete_request(struct request *rq)
+static void __blk_mq_complete_request(struct request *rq)
{
struct request_queue *q = rq->q;
@@ -1198,7 +1198,7 @@ static struct request *blk_mq_map_request(struct request_queue *q,
return rq;
}
-static int blk_mq_direct_issue_request(struct request *rq)
+static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie)
{
int ret;
struct request_queue *q = rq->q;
@@ -1209,6 +1209,7 @@ static int blk_mq_direct_issue_request(struct request *rq)
.list = NULL,
.last = 1
};
+ blk_qc_t new_cookie = blk_tag_to_qc_t(rq->tag, hctx->queue_num);
/*
* For OK queue, we are done. For error, kill it. Any other
@@ -1216,18 +1217,21 @@ static int blk_mq_direct_issue_request(struct request *rq)
* would have done
*/
ret = q->mq_ops->queue_rq(hctx, &bd);
- if (ret == BLK_MQ_RQ_QUEUE_OK)
+ if (ret == BLK_MQ_RQ_QUEUE_OK) {
+ *cookie = new_cookie;
return 0;
- else {
- __blk_mq_requeue_request(rq);
+ }
- if (ret == BLK_MQ_RQ_QUEUE_ERROR) {
- rq->errors = -EIO;
- blk_mq_end_request(rq, rq->errors);
- return 0;
- }
- return -1;
+ __blk_mq_requeue_request(rq);
+
+ if (ret == BLK_MQ_RQ_QUEUE_ERROR) {
+ *cookie = BLK_QC_T_NONE;
+ rq->errors = -EIO;
+ blk_mq_end_request(rq, rq->errors);
+ return 0;
}
+
+ return -1;
}
/*
@@ -1235,7 +1239,7 @@ static int blk_mq_direct_issue_request(struct request *rq)
* but will attempt to bypass the hctx queueing if we can go straight to
* hardware for SYNC IO.
*/
-static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio)
{
const int is_sync = rw_is_sync(bio->bi_rw);
const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA);
@@ -1244,12 +1248,13 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
unsigned int request_count = 0;
struct blk_plug *plug;
struct request *same_queue_rq = NULL;
+ blk_qc_t cookie;
blk_queue_bounce(q, &bio);
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
blk_queue_split(q, &bio, q->bio_split);
@@ -1257,13 +1262,15 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
if (!is_flush_fua && !blk_queue_nomerges(q)) {
if (blk_attempt_plug_merge(q, bio, &request_count,
&same_queue_rq))
- return;
+ return BLK_QC_T_NONE;
} else
request_count = blk_plug_queued_count(q);
rq = blk_mq_map_request(q, bio, &data);
if (unlikely(!rq))
- return;
+ return BLK_QC_T_NONE;
+
+ cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num);
if (unlikely(is_flush_fua)) {
blk_mq_bio_to_request(rq, bio);
@@ -1284,15 +1291,16 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
blk_mq_bio_to_request(rq, bio);
/*
- * we do limited pluging. If bio can be merged, do merge.
+ * We do limited pluging. If the bio can be merged, do that.
* Otherwise the existing request in the plug list will be
* issued. So the plug list will have one request at most
*/
if (plug) {
/*
* The plug list might get flushed before this. If that
- * happens, same_queue_rq is invalid and plug list is empty
- **/
+ * happens, same_queue_rq is invalid and plug list is
+ * empty
+ */
if (same_queue_rq && !list_empty(&plug->mq_list)) {
old_rq = same_queue_rq;
list_del_init(&old_rq->queuelist);
@@ -1302,11 +1310,11 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
old_rq = rq;
blk_mq_put_ctx(data.ctx);
if (!old_rq)
- return;
- if (!blk_mq_direct_issue_request(old_rq))
- return;
+ goto done;
+ if (!blk_mq_direct_issue_request(old_rq, &cookie))
+ goto done;
blk_mq_insert_request(old_rq, false, true, true);
- return;
+ goto done;
}
if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
@@ -1320,13 +1328,15 @@ run_queue:
blk_mq_run_hw_queue(data.hctx, !is_sync || is_flush_fua);
}
blk_mq_put_ctx(data.ctx);
+done:
+ return cookie;
}
/*
* Single hardware queue variant. This will attempt to use any per-process
* plug for merging and IO deferral.
*/
-static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio)
{
const int is_sync = rw_is_sync(bio->bi_rw);
const int is_flush_fua = bio->bi_rw & (REQ_FLUSH | REQ_FUA);
@@ -1334,23 +1344,26 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
unsigned int request_count = 0;
struct blk_map_ctx data;
struct request *rq;
+ blk_qc_t cookie;
blk_queue_bounce(q, &bio);
if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) {
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
blk_queue_split(q, &bio, q->bio_split);
if (!is_flush_fua && !blk_queue_nomerges(q) &&
blk_attempt_plug_merge(q, bio, &request_count, NULL))
- return;
+ return BLK_QC_T_NONE;
rq = blk_mq_map_request(q, bio, &data);
if (unlikely(!rq))
- return;
+ return BLK_QC_T_NONE;
+
+ cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num);
if (unlikely(is_flush_fua)) {
blk_mq_bio_to_request(rq, bio);
@@ -1368,13 +1381,16 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
blk_mq_bio_to_request(rq, bio);
if (!request_count)
trace_block_plug(q);
- else if (request_count >= BLK_MAX_REQUEST_COUNT) {
+
+ blk_mq_put_ctx(data.ctx);
+
+ if (request_count >= BLK_MAX_REQUEST_COUNT) {
blk_flush_plug_list(plug, false);
trace_block_plug(q);
}
+
list_add_tail(&rq->queuelist, &plug->mq_list);
- blk_mq_put_ctx(data.ctx);
- return;
+ return cookie;
}
if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) {
@@ -1389,6 +1405,7 @@ run_queue:
}
blk_mq_put_ctx(data.ctx);
+ return cookie;
}
/*
diff --git a/block/blk-mq.h b/block/blk-mq.h
index b44dce1..713820b 100644
--- a/block/blk-mq.h
+++ b/block/blk-mq.h
@@ -25,7 +25,6 @@ struct blk_mq_ctx {
struct kobject kobj;
} ____cacheline_aligned_in_smp;
-void __blk_mq_complete_request(struct request *rq);
void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
void blk_mq_freeze_queue(struct request_queue *q);
void blk_mq_free_queue(struct request_queue *q);
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 7d8f129..dd49735 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -91,7 +91,8 @@ void blk_set_default_limits(struct queue_limits *lim)
lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK;
lim->virt_boundary_mask = 0;
lim->max_segment_size = BLK_MAX_SEGMENT_SIZE;
- lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS;
+ lim->max_sectors = lim->max_dev_sectors = lim->max_hw_sectors =
+ BLK_SAFE_MAX_SECTORS;
lim->chunk_sectors = 0;
lim->max_write_same_sectors = 0;
lim->max_discard_sectors = 0;
@@ -127,6 +128,7 @@ void blk_set_stacking_limits(struct queue_limits *lim)
lim->max_hw_sectors = UINT_MAX;
lim->max_segment_size = UINT_MAX;
lim->max_sectors = UINT_MAX;
+ lim->max_dev_sectors = UINT_MAX;
lim->max_write_same_sectors = UINT_MAX;
}
EXPORT_SYMBOL(blk_set_stacking_limits);
@@ -214,8 +216,8 @@ void blk_queue_bounce_limit(struct request_queue *q, u64 max_addr)
EXPORT_SYMBOL(blk_queue_bounce_limit);
/**
- * blk_limits_max_hw_sectors - set hard and soft limit of max sectors for request
- * @limits: the queue limits
+ * blk_queue_max_hw_sectors - set max sectors for a request for this queue
+ * @q: the request queue for the device
* @max_hw_sectors: max hardware sectors in the usual 512b unit
*
* Description:
@@ -224,13 +226,19 @@ EXPORT_SYMBOL(blk_queue_bounce_limit);
* the device driver based upon the capabilities of the I/O
* controller.
*
+ * max_dev_sectors is a hard limit imposed by the storage device for
+ * READ/WRITE requests. It is set by the disk driver.
+ *
* max_sectors is a soft limit imposed by the block layer for
* filesystem type requests. This value can be overridden on a
* per-device basis in /sys/block/<device>/queue/max_sectors_kb.
* The soft limit can not exceed max_hw_sectors.
**/
-void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_sectors)
+void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
{
+ struct queue_limits *limits = &q->limits;
+ unsigned int max_sectors;
+
if ((max_hw_sectors << 9) < PAGE_CACHE_SIZE) {
max_hw_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
printk(KERN_INFO "%s: set to minimum %d\n",
@@ -238,22 +246,9 @@ void blk_limits_max_hw_sectors(struct queue_limits *limits, unsigned int max_hw_
}
limits->max_hw_sectors = max_hw_sectors;
- limits->max_sectors = min_t(unsigned int, max_hw_sectors,
- BLK_DEF_MAX_SECTORS);
-}
-EXPORT_SYMBOL(blk_limits_max_hw_sectors);
-
-/**
- * blk_queue_max_hw_sectors - set max sectors for a request for this queue
- * @q: the request queue for the device
- * @max_hw_sectors: max hardware sectors in the usual 512b unit
- *
- * Description:
- * See description for blk_limits_max_hw_sectors().
- **/
-void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors)
-{
- blk_limits_max_hw_sectors(&q->limits, max_hw_sectors);
+ max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors);
+ max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS);
+ limits->max_sectors = max_sectors;
}
EXPORT_SYMBOL(blk_queue_max_hw_sectors);
@@ -527,6 +522,7 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+ t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
t->max_write_same_sectors = min(t->max_write_same_sectors,
b->max_write_same_sectors);
t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn);
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 31849e3..e140cc4 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -205,6 +205,9 @@ queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
if (ret < 0)
return ret;
+ max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb, (unsigned long)
+ q->limits.max_dev_sectors >> 1);
+
if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb)
return -EINVAL;
@@ -317,6 +320,34 @@ queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count)
return ret;
}
+static ssize_t queue_poll_show(struct request_queue *q, char *page)
+{
+ return queue_var_show(test_bit(QUEUE_FLAG_POLL, &q->queue_flags), page);
+}
+
+static ssize_t queue_poll_store(struct request_queue *q, const char *page,
+ size_t count)
+{
+ unsigned long poll_on;
+ ssize_t ret;
+
+ if (!q->mq_ops || !q->mq_ops->poll)
+ return -EINVAL;
+
+ ret = queue_var_store(&poll_on, page, count);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irq(q->queue_lock);
+ if (poll_on)
+ queue_flag_set(QUEUE_FLAG_POLL, q);
+ else
+ queue_flag_clear(QUEUE_FLAG_POLL, q);
+ spin_unlock_irq(q->queue_lock);
+
+ return ret;
+}
+
static struct queue_sysfs_entry queue_requests_entry = {
.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
.show = queue_requests_show,
@@ -442,6 +473,12 @@ static struct queue_sysfs_entry queue_random_entry = {
.store = queue_store_random,
};
+static struct queue_sysfs_entry queue_poll_entry = {
+ .attr = {.name = "io_poll", .mode = S_IRUGO | S_IWUSR },
+ .show = queue_poll_show,
+ .store = queue_poll_store,
+};
+
static struct attribute *default_attrs[] = {
&queue_requests_entry.attr,
&queue_ra_entry.attr,
@@ -466,6 +503,7 @@ static struct attribute *default_attrs[] = {
&queue_rq_affinity_entry.attr,
&queue_iostats_entry.attr,
&queue_random_entry.attr,
+ &queue_poll_entry.attr,
NULL,
};
diff --git a/block/blk-timeout.c b/block/blk-timeout.c
index 246dfb1..aa40aa9 100644
--- a/block/blk-timeout.c
+++ b/block/blk-timeout.c
@@ -158,11 +158,13 @@ void blk_abort_request(struct request *req)
{
if (blk_mark_rq_complete(req))
return;
- blk_delete_timer(req);
- if (req->q->mq_ops)
+
+ if (req->q->mq_ops) {
blk_mq_rq_timed_out(req, false);
- else
+ } else {
+ blk_delete_timer(req);
blk_rq_timed_out(req);
+ }
}
EXPORT_SYMBOL_GPL(blk_abort_request);
diff --git a/block/blk.h b/block/blk.h
index da722eb..c43926d 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -72,8 +72,6 @@ void blk_dequeue_request(struct request *rq);
void __blk_queue_free_tags(struct request_queue *q);
bool __blk_end_bidi_request(struct request *rq, int error,
unsigned int nr_bytes, unsigned int bidi_bytes);
-int blk_queue_enter(struct request_queue *q, gfp_t gfp);
-void blk_queue_exit(struct request_queue *q);
void blk_freeze_queue(struct request_queue *q);
static inline void blk_queue_enter_live(struct request_queue *q)
diff --git a/block/noop-iosched.c b/block/noop-iosched.c
index 3de89d4..a163c48 100644
--- a/block/noop-iosched.c
+++ b/block/noop-iosched.c
@@ -21,10 +21,10 @@ static void noop_merged_requests(struct request_queue *q, struct request *rq,
static int noop_dispatch(struct request_queue *q, int force)
{
struct noop_data *nd = q->elevator->elevator_data;
+ struct request *rq;
- if (!list_empty(&nd->queue)) {
- struct request *rq;
- rq = list_entry(nd->queue.next, struct request, queuelist);
+ rq = list_first_entry_or_null(&nd->queue, struct request, queuelist);
+ if (rq) {
list_del_init(&rq->queuelist);
elv_dispatch_sort(q, rq);
return 1;
@@ -46,7 +46,7 @@ noop_former_request(struct request_queue *q, struct request *rq)
if (rq->queuelist.prev == &nd->queue)
return NULL;
- return list_entry(rq->queuelist.prev, struct request, queuelist);
+ return list_prev_entry(rq, queuelist);
}
static struct request *
@@ -56,7 +56,7 @@ noop_latter_request(struct request_queue *q, struct request *rq)
if (rq->queuelist.next == &nd->queue)
return NULL;
- return list_entry(rq->queuelist.next, struct request, queuelist);
+ return list_next_entry(rq, queuelist);
}
static int noop_init_queue(struct request_queue *q, struct elevator_type *e)
diff --git a/block/partition-generic.c b/block/partition-generic.c
index 3b03015..746935a 100644
--- a/block/partition-generic.c
+++ b/block/partition-generic.c
@@ -397,7 +397,7 @@ static int drop_partitions(struct gendisk *disk, struct block_device *bdev)
struct hd_struct *part;
int res;
- if (bdev->bd_part_count)
+ if (bdev->bd_part_count || bdev->bd_super)
return -EBUSY;
res = invalidate_partition(disk, 0);
if (res)
diff --git a/block/partitions/mac.c b/block/partitions/mac.c
index c2c48ec..621317a 100644
--- a/block/partitions/mac.c
+++ b/block/partitions/mac.c
@@ -32,7 +32,7 @@ int mac_partition(struct parsed_partitions *state)
Sector sect;
unsigned char *data;
int slot, blocks_in_map;
- unsigned secsize;
+ unsigned secsize, datasize, partoffset;
#ifdef CONFIG_PPC_PMAC
int found_root = 0;
int found_root_goodness = 0;
@@ -50,10 +50,14 @@ int mac_partition(struct parsed_partitions *state)
}
secsize = be16_to_cpu(md->block_size);
put_dev_sector(sect);
- data = read_part_sector(state, secsize/512, &sect);
+ datasize = round_down(secsize, 512);
+ data = read_part_sector(state, datasize / 512, &sect);
if (!data)
return -1;
- part = (struct mac_partition *) (data + secsize%512);
+ partoffset = secsize % 512;
+ if (partoffset + sizeof(*part) > datasize)
+ return -1;
+ part = (struct mac_partition *) (data + partoffset);
if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) {
put_dev_sector(sect);
return 0; /* not a MacOS disk */
diff --git a/crypto/ablkcipher.c b/crypto/ablkcipher.c
index b4ffc5b..e5b5721 100644
--- a/crypto/ablkcipher.c
+++ b/crypto/ablkcipher.c
@@ -277,12 +277,12 @@ static int ablkcipher_walk_first(struct ablkcipher_request *req,
if (WARN_ON_ONCE(in_irq()))
return -EDEADLK;
+ walk->iv = req->info;
walk->nbytes = walk->total;
if (unlikely(!walk->total))
return 0;
walk->iv_buffer = NULL;
- walk->iv = req->info;
if (unlikely(((unsigned long)walk->iv & alignmask))) {
int err = ablkcipher_copy_iv(walk, tfm, alignmask);
diff --git a/crypto/algif_aead.c b/crypto/algif_aead.c
index 0aa6fdf..6d4d456 100644
--- a/crypto/algif_aead.c
+++ b/crypto/algif_aead.c
@@ -125,7 +125,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags)
if (flags & MSG_DONTWAIT)
return -EAGAIN;
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
for (;;) {
if (signal_pending(current))
@@ -139,7 +139,7 @@ static int aead_wait_for_data(struct sock *sk, unsigned flags)
}
finish_wait(sk_sleep(sk), &wait);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
return err;
}
diff --git a/crypto/algif_hash.c b/crypto/algif_hash.c
index 1396ad0..b4c24fe 100644
--- a/crypto/algif_hash.c
+++ b/crypto/algif_hash.c
@@ -181,9 +181,14 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags)
struct sock *sk2;
struct alg_sock *ask2;
struct hash_ctx *ctx2;
+ bool more;
int err;
- err = crypto_ahash_export(req, state);
+ lock_sock(sk);
+ more = ctx->more;
+ err = more ? crypto_ahash_export(req, state) : 0;
+ release_sock(sk);
+
if (err)
return err;
@@ -194,7 +199,10 @@ static int hash_accept(struct socket *sock, struct socket *newsock, int flags)
sk2 = newsock->sk;
ask2 = alg_sk(sk2);
ctx2 = ask2->private;
- ctx2->more = 1;
+ ctx2->more = more;
+
+ if (!more)
+ return err;
err = crypto_ahash_import(&ctx2->req, state);
if (err) {
diff --git a/crypto/algif_skcipher.c b/crypto/algif_skcipher.c
index af31a0e..634b4d1 100644
--- a/crypto/algif_skcipher.c
+++ b/crypto/algif_skcipher.c
@@ -47,7 +47,7 @@ struct skcipher_ctx {
bool merge;
bool enc;
- struct ablkcipher_request req;
+ struct skcipher_request req;
};
struct skcipher_async_rsgl {
@@ -64,13 +64,13 @@ struct skcipher_async_req {
};
#define GET_SREQ(areq, ctx) (struct skcipher_async_req *)((char *)areq + \
- crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req)))
+ crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req)))
#define GET_REQ_SIZE(ctx) \
- crypto_ablkcipher_reqsize(crypto_ablkcipher_reqtfm(&ctx->req))
+ crypto_skcipher_reqsize(crypto_skcipher_reqtfm(&ctx->req))
#define GET_IV_SIZE(ctx) \
- crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(&ctx->req))
+ crypto_skcipher_ivsize(crypto_skcipher_reqtfm(&ctx->req))
#define MAX_SGL_ENTS ((4096 - sizeof(struct skcipher_sg_list)) / \
sizeof(struct scatterlist) - 1)
@@ -212,7 +212,7 @@ static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags)
if (flags & MSG_DONTWAIT)
return -EAGAIN;
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
for (;;) {
if (signal_pending(current))
@@ -258,7 +258,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags)
return -EAGAIN;
}
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
for (;;) {
if (signal_pending(current))
@@ -272,7 +272,7 @@ static int skcipher_wait_for_data(struct sock *sk, unsigned flags)
}
finish_wait(sk_sleep(sk), &wait);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
return err;
}
@@ -302,8 +302,8 @@ static int skcipher_sendmsg(struct socket *sock, struct msghdr *msg,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct skcipher_ctx *ctx = ask->private;
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
- unsigned ivsize = crypto_ablkcipher_ivsize(tfm);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
+ unsigned ivsize = crypto_skcipher_ivsize(tfm);
struct skcipher_sg_list *sgl;
struct af_alg_control con = {};
long copied = 0;
@@ -507,7 +507,7 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
struct skcipher_sg_list *sgl;
struct scatterlist *sg;
struct skcipher_async_req *sreq;
- struct ablkcipher_request *req;
+ struct skcipher_request *req;
struct skcipher_async_rsgl *last_rsgl = NULL;
unsigned int txbufs = 0, len = 0, tx_nents = skcipher_all_sg_nents(ctx);
unsigned int reqlen = sizeof(struct skcipher_async_req) +
@@ -531,9 +531,9 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
}
sg_init_table(sreq->tsg, tx_nents);
memcpy(sreq->iv, ctx->iv, GET_IV_SIZE(ctx));
- ablkcipher_request_set_tfm(req, crypto_ablkcipher_reqtfm(&ctx->req));
- ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- skcipher_async_cb, sk);
+ skcipher_request_set_tfm(req, crypto_skcipher_reqtfm(&ctx->req));
+ skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ skcipher_async_cb, sk);
while (iov_iter_count(&msg->msg_iter)) {
struct skcipher_async_rsgl *rsgl;
@@ -608,10 +608,10 @@ static int skcipher_recvmsg_async(struct socket *sock, struct msghdr *msg,
if (mark)
sg_mark_end(sreq->tsg + txbufs - 1);
- ablkcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
- len, sreq->iv);
- err = ctx->enc ? crypto_ablkcipher_encrypt(req) :
- crypto_ablkcipher_decrypt(req);
+ skcipher_request_set_crypt(req, sreq->tsg, sreq->first_sgl.sgl.sg,
+ len, sreq->iv);
+ err = ctx->enc ? crypto_skcipher_encrypt(req) :
+ crypto_skcipher_decrypt(req);
if (err == -EINPROGRESS) {
atomic_inc(&ctx->inflight);
err = -EIOCBQUEUED;
@@ -632,7 +632,7 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
struct sock *sk = sock->sk;
struct alg_sock *ask = alg_sk(sk);
struct skcipher_ctx *ctx = ask->private;
- unsigned bs = crypto_ablkcipher_blocksize(crypto_ablkcipher_reqtfm(
+ unsigned bs = crypto_skcipher_blocksize(crypto_skcipher_reqtfm(
&ctx->req));
struct skcipher_sg_list *sgl;
struct scatterlist *sg;
@@ -669,14 +669,13 @@ static int skcipher_recvmsg_sync(struct socket *sock, struct msghdr *msg,
if (!used)
goto free;
- ablkcipher_request_set_crypt(&ctx->req, sg,
- ctx->rsgl.sg, used,
- ctx->iv);
+ skcipher_request_set_crypt(&ctx->req, sg, ctx->rsgl.sg, used,
+ ctx->iv);
err = af_alg_wait_for_completion(
ctx->enc ?
- crypto_ablkcipher_encrypt(&ctx->req) :
- crypto_ablkcipher_decrypt(&ctx->req),
+ crypto_skcipher_encrypt(&ctx->req) :
+ crypto_skcipher_decrypt(&ctx->req),
&ctx->completion);
free:
@@ -751,17 +750,17 @@ static struct proto_ops algif_skcipher_ops = {
static void *skcipher_bind(const char *name, u32 type, u32 mask)
{
- return crypto_alloc_ablkcipher(name, type, mask);
+ return crypto_alloc_skcipher(name, type, mask);
}
static void skcipher_release(void *private)
{
- crypto_free_ablkcipher(private);
+ crypto_free_skcipher(private);
}
static int skcipher_setkey(void *private, const u8 *key, unsigned int keylen)
{
- return crypto_ablkcipher_setkey(private, key, keylen);
+ return crypto_skcipher_setkey(private, key, keylen);
}
static void skcipher_wait(struct sock *sk)
@@ -778,13 +777,13 @@ static void skcipher_sock_destruct(struct sock *sk)
{
struct alg_sock *ask = alg_sk(sk);
struct skcipher_ctx *ctx = ask->private;
- struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(&ctx->req);
+ struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(&ctx->req);
if (atomic_read(&ctx->inflight))
skcipher_wait(sk);
skcipher_free_sgl(sk);
- sock_kzfree_s(sk, ctx->iv, crypto_ablkcipher_ivsize(tfm));
+ sock_kzfree_s(sk, ctx->iv, crypto_skcipher_ivsize(tfm));
sock_kfree_s(sk, ctx, ctx->len);
af_alg_release_parent(sk);
}
@@ -793,20 +792,20 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
{
struct skcipher_ctx *ctx;
struct alg_sock *ask = alg_sk(sk);
- unsigned int len = sizeof(*ctx) + crypto_ablkcipher_reqsize(private);
+ unsigned int len = sizeof(*ctx) + crypto_skcipher_reqsize(private);
ctx = sock_kmalloc(sk, len, GFP_KERNEL);
if (!ctx)
return -ENOMEM;
- ctx->iv = sock_kmalloc(sk, crypto_ablkcipher_ivsize(private),
+ ctx->iv = sock_kmalloc(sk, crypto_skcipher_ivsize(private),
GFP_KERNEL);
if (!ctx->iv) {
sock_kfree_s(sk, ctx, len);
return -ENOMEM;
}
- memset(ctx->iv, 0, crypto_ablkcipher_ivsize(private));
+ memset(ctx->iv, 0, crypto_skcipher_ivsize(private));
INIT_LIST_HEAD(&ctx->tsgl);
ctx->len = len;
@@ -819,9 +818,9 @@ static int skcipher_accept_parent(void *private, struct sock *sk)
ask->private = ctx;
- ablkcipher_request_set_tfm(&ctx->req, private);
- ablkcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
- af_alg_complete, &ctx->completion);
+ skcipher_request_set_tfm(&ctx->req, private);
+ skcipher_request_set_callback(&ctx->req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ af_alg_complete, &ctx->completion);
sk->sk_destruct = skcipher_sock_destruct;
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 3000ea3..021d39c 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -531,7 +531,11 @@ int x509_decode_time(time64_t *_t, size_t hdrlen,
if (*p != 'Z')
goto unsupported_time;
- mon_len = month_lengths[mon];
+ if (year < 1970 ||
+ mon < 1 || mon > 12)
+ goto invalid_time;
+
+ mon_len = month_lengths[mon - 1];
if (mon == 2) {
if (year % 4 == 0) {
mon_len = 29;
@@ -543,14 +547,12 @@ int x509_decode_time(time64_t *_t, size_t hdrlen,
}
}
- if (year < 1970 ||
- mon < 1 || mon > 12 ||
- day < 1 || day > mon_len ||
+ if (day < 1 || day > mon_len ||
hour > 23 ||
min > 59 ||
sec > 59)
goto invalid_time;
-
+
*_t = mktime64(year, mon, day, hour, min, sec);
return 0;
diff --git a/crypto/async_tx/async_memcpy.c b/crypto/async_tx/async_memcpy.c
index f8c0b8d..88bc8e6 100644
--- a/crypto/async_tx/async_memcpy.c
+++ b/crypto/async_tx/async_memcpy.c
@@ -53,7 +53,7 @@ async_memcpy(struct page *dest, struct page *src, unsigned int dest_offset,
struct dmaengine_unmap_data *unmap = NULL;
if (device)
- unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOWAIT);
if (unmap && is_dma_copy_aligned(device, src_offset, dest_offset, len)) {
unsigned long dma_prep_flags = 0;
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index 5d355e0..c0748bb 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -188,7 +188,7 @@ async_gen_syndrome(struct page **blocks, unsigned int offset, int disks,
BUG_ON(disks > 255 || !(P(blocks, disks) || Q(blocks, disks)));
if (device)
- unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT);
/* XORing P/Q is only implemented in software */
if (unmap && !(submit->flags & ASYNC_TX_PQ_XOR_DST) &&
@@ -307,7 +307,7 @@ async_syndrome_val(struct page **blocks, unsigned int offset, int disks,
BUG_ON(disks < 4);
if (device)
- unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(device->dev, disks, GFP_NOWAIT);
if (unmap && disks <= dma_maxpq(device, 0) &&
is_dma_pq_aligned(device, offset, 0, len)) {
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index 934a849..8fab627 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -41,7 +41,7 @@ async_sum_product(struct page *dest, struct page **srcs, unsigned char *coef,
u8 *a, *b, *c;
if (dma)
- unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOWAIT);
if (unmap) {
struct device *dev = dma->dev;
@@ -105,7 +105,7 @@ async_mult(struct page *dest, struct page *src, u8 coef, size_t len,
u8 *d, *s;
if (dma)
- unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(dma->dev, 3, GFP_NOWAIT);
if (unmap) {
dma_addr_t dma_dest[2];
diff --git a/crypto/async_tx/async_xor.c b/crypto/async_tx/async_xor.c
index e1bce26..da75777 100644
--- a/crypto/async_tx/async_xor.c
+++ b/crypto/async_tx/async_xor.c
@@ -182,7 +182,7 @@ async_xor(struct page *dest, struct page **src_list, unsigned int offset,
BUG_ON(src_cnt <= 1);
if (device)
- unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(device->dev, src_cnt+1, GFP_NOWAIT);
if (unmap && is_dma_xor_aligned(device, offset, 0, len)) {
struct dma_async_tx_descriptor *tx;
@@ -278,7 +278,7 @@ async_xor_val(struct page *dest, struct page **src_list, unsigned int offset,
BUG_ON(src_cnt <= 1);
if (device)
- unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOIO);
+ unmap = dmaengine_get_unmap_data(device->dev, src_cnt, GFP_NOWAIT);
if (unmap && src_cnt <= device->max_xor &&
is_dma_xor_aligned(device, offset, 0, len)) {
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 11b9814..8cc1622 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -326,12 +326,12 @@ static int blkcipher_walk_first(struct blkcipher_desc *desc,
if (WARN_ON_ONCE(in_irq()))
return -EDEADLK;
+ walk->iv = desc->info;
walk->nbytes = walk->total;
if (unlikely(!walk->total))
return 0;
walk->buffer = NULL;
- walk->iv = desc->info;
if (unlikely(((unsigned long)walk->iv & walk->alignmask))) {
int err = blkcipher_copy_iv(walk);
if (err)
diff --git a/drivers/Makefile b/drivers/Makefile
index 73d0391..795d0ca 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_FB_I810) += video/fbdev/i810/
obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/
obj-$(CONFIG_PARPORT) += parport/
+obj-$(CONFIG_NVM) += lightnvm/
obj-y += base/ block/ misc/ mfd/ nfc/
obj-$(CONFIG_LIBNVDIMM) += nvdimm/
obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/
@@ -70,7 +71,6 @@ obj-$(CONFIG_NUBUS) += nubus/
obj-y += macintosh/
obj-$(CONFIG_IDE) += ide/
obj-$(CONFIG_SCSI) += scsi/
-obj-$(CONFIG_NVM) += lightnvm/
obj-y += nvme/
obj-$(CONFIG_ATA) += ata/
obj-$(CONFIG_TARGET_CORE) += target/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 25dbb76..5eef4cb 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -58,10 +58,10 @@ config ACPI_CCA_REQUIRED
bool
config ACPI_DEBUGGER
- bool "In-kernel debugger (EXPERIMENTAL)"
+ bool "AML debugger interface (EXPERIMENTAL)"
select ACPI_DEBUG
help
- Enable in-kernel debugging facilities: statistics, internal
+ Enable in-kernel debugging of AML facilities: statistics, internal
object dump, single step control method execution.
This is still under development, currently enabling this only
results in the compilation of the ACPICA debugger files.
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 06a67d5..296b7a1 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -103,7 +103,12 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
pdevinfo.res = resources;
pdevinfo.num_res = count;
pdevinfo.fwnode = acpi_fwnode_handle(adev);
- pdevinfo.dma_mask = acpi_check_dma(adev, NULL) ? DMA_BIT_MASK(32) : 0;
+
+ if (acpi_dma_supported(adev))
+ pdevinfo.dma_mask = DMA_BIT_MASK(32);
+ else
+ pdevinfo.dma_mask = 0;
+
pdev = platform_device_register_full(&pdevinfo);
if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n",
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index 5778e8e..3405f7a 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -77,6 +77,12 @@ module_param(allow_duplicates, bool, 0644);
static int disable_backlight_sysfs_if = -1;
module_param(disable_backlight_sysfs_if, int, 0444);
+static bool device_id_scheme = false;
+module_param(device_id_scheme, bool, 0444);
+
+static bool only_lcd = false;
+module_param(only_lcd, bool, 0444);
+
static int register_count;
static DEFINE_MUTEX(register_count_mutex);
static struct mutex video_list_lock;
@@ -394,6 +400,18 @@ static int video_disable_backlight_sysfs_if(
return 0;
}
+static int video_set_device_id_scheme(const struct dmi_system_id *d)
+{
+ device_id_scheme = true;
+ return 0;
+}
+
+static int video_enable_only_lcd(const struct dmi_system_id *d)
+{
+ only_lcd = true;
+ return 0;
+}
+
static struct dmi_system_id video_dmi_table[] = {
/*
* Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
@@ -455,6 +473,33 @@ static struct dmi_system_id video_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
},
},
+ /*
+ * Some machine's _DOD IDs don't have bit 31(Device ID Scheme) set
+ * but the IDs actually follow the Device ID Scheme.
+ */
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */
+ .callback = video_set_device_id_scheme,
+ .ident = "ESPRIMO Mobile M9410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"),
+ },
+ },
+ /*
+ * Some machines have multiple video output devices, but only the one
+ * that is the type of LCD can do the backlight control so we should not
+ * register backlight interface for other video output devices.
+ */
+ {
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=104121 */
+ .callback = video_enable_only_lcd,
+ .ident = "ESPRIMO Mobile M9410",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "ESPRIMO Mobile M9410"),
+ },
+ },
{}
};
@@ -1003,7 +1048,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
attribute = acpi_video_get_device_attr(video, device_id);
- if (attribute && attribute->device_id_scheme) {
+ if (attribute && (attribute->device_id_scheme || device_id_scheme)) {
switch (attribute->display_type) {
case ACPI_VIDEO_DISPLAY_CRT:
data->flags.crt = 1;
@@ -1568,15 +1613,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
static int count;
char *name;
- /*
- * Do not create backlight device for video output
- * device that is not in the enumerated list.
- */
- if (!acpi_video_device_in_dod(device)) {
- dev_dbg(&device->dev->dev, "not in _DOD list, ignore\n");
- return;
- }
-
result = acpi_video_init_brightness(device);
if (result)
return;
@@ -1657,6 +1693,22 @@ static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
mutex_unlock(&video->device_list_lock);
}
+static bool acpi_video_should_register_backlight(struct acpi_video_device *dev)
+{
+ /*
+ * Do not create backlight device for video output
+ * device that is not in the enumerated list.
+ */
+ if (!acpi_video_device_in_dod(dev)) {
+ dev_dbg(&dev->dev->dev, "not in _DOD list, ignore\n");
+ return false;
+ }
+
+ if (only_lcd)
+ return dev->flags.lcd;
+ return true;
+}
+
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
@@ -1670,8 +1722,10 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
return 0;
mutex_lock(&video->device_list_lock);
- list_for_each_entry(dev, &video->video_device_list, entry)
- acpi_video_dev_register_backlight(dev);
+ list_for_each_entry(dev, &video->video_device_list, entry) {
+ if (acpi_video_should_register_backlight(dev))
+ acpi_video_dev_register_backlight(dev);
+ }
mutex_unlock(&video->device_list_lock);
video->backlight_registered = true;
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 3c083d2..6730f96 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -304,7 +304,7 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map);
static int register_pcc_channel(int pcc_subspace_idx)
{
- struct acpi_pcct_subspace *cppc_ss;
+ struct acpi_pcct_hw_reduced *cppc_ss;
unsigned int len;
if (pcc_subspace_idx >= 0) {
diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c
index 707cf62..b9afb47 100644
--- a/drivers/acpi/device_sysfs.c
+++ b/drivers/acpi/device_sysfs.c
@@ -104,7 +104,7 @@ static void acpi_expose_nondev_subnodes(struct kobject *kobj,
init_completion(&dn->kobj_done);
ret = kobject_init_and_add(&dn->kobj, &acpi_data_node_ktype,
- kobj, dn->name);
+ kobj, "%s", dn->name);
if (ret)
acpi_handle_err(dn->handle, "Failed to expose (%d)\n", ret);
else
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index f61a7c8..b420fb4 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1103,7 +1103,7 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
}
err_exit:
- if (result && q)
+ if (result)
acpi_ec_delete_query(q);
if (data)
*data = value;
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index 1470ae4..5ea5dc2 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -168,7 +168,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
struct list_head *physnode_list;
unsigned int node_id;
int retval = -EINVAL;
- bool coherent;
+ enum dev_dma_attr attr;
if (has_acpi_companion(dev)) {
if (acpi_dev) {
@@ -225,8 +225,10 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev)
if (!has_acpi_companion(dev))
ACPI_COMPANION_SET(dev, acpi_dev);
- if (acpi_check_dma(acpi_dev, &coherent))
- arch_setup_dma_ops(dev, 0, 0, NULL, coherent);
+ attr = acpi_get_dma_attr(acpi_dev);
+ if (attr != DEV_DMA_NOT_SUPPORTED)
+ arch_setup_dma_ops(dev, 0, 0, NULL,
+ attr == DEV_DMA_COHERENT);
acpi_physnode_link_name(physical_node_name, node_id);
retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c
index 6e26761..aa45d48 100644
--- a/drivers/acpi/nfit.c
+++ b/drivers/acpi/nfit.c
@@ -33,6 +33,15 @@ static bool force_enable_dimms;
module_param(force_enable_dimms, bool, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(force_enable_dimms, "Ignore _STA (ACPI DIMM device) status");
+struct nfit_table_prev {
+ struct list_head spas;
+ struct list_head memdevs;
+ struct list_head dcrs;
+ struct list_head bdws;
+ struct list_head idts;
+ struct list_head flushes;
+};
+
static u8 nfit_uuid[NFIT_UUID_MAX][16];
const u8 *to_nfit_uuid(enum nfit_uuids id)
@@ -221,12 +230,21 @@ static int nfit_spa_type(struct acpi_nfit_system_address *spa)
}
static bool add_spa(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_system_address *spa)
{
+ size_t length = min_t(size_t, sizeof(*spa), spa->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_spa *nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa),
- GFP_KERNEL);
+ struct nfit_spa *nfit_spa;
+
+ list_for_each_entry(nfit_spa, &prev->spas, list) {
+ if (memcmp(nfit_spa->spa, spa, length) == 0) {
+ list_move_tail(&nfit_spa->list, &acpi_desc->spas);
+ return true;
+ }
+ }
+ nfit_spa = devm_kzalloc(dev, sizeof(*nfit_spa), GFP_KERNEL);
if (!nfit_spa)
return false;
INIT_LIST_HEAD(&nfit_spa->list);
@@ -239,12 +257,20 @@ static bool add_spa(struct acpi_nfit_desc *acpi_desc,
}
static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_memory_map *memdev)
{
+ size_t length = min_t(size_t, sizeof(*memdev), memdev->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_memdev *nfit_memdev = devm_kzalloc(dev,
- sizeof(*nfit_memdev), GFP_KERNEL);
+ struct nfit_memdev *nfit_memdev;
+ list_for_each_entry(nfit_memdev, &prev->memdevs, list)
+ if (memcmp(nfit_memdev->memdev, memdev, length) == 0) {
+ list_move_tail(&nfit_memdev->list, &acpi_desc->memdevs);
+ return true;
+ }
+
+ nfit_memdev = devm_kzalloc(dev, sizeof(*nfit_memdev), GFP_KERNEL);
if (!nfit_memdev)
return false;
INIT_LIST_HEAD(&nfit_memdev->list);
@@ -257,12 +283,20 @@ static bool add_memdev(struct acpi_nfit_desc *acpi_desc,
}
static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_control_region *dcr)
{
+ size_t length = min_t(size_t, sizeof(*dcr), dcr->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_dcr *nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr),
- GFP_KERNEL);
+ struct nfit_dcr *nfit_dcr;
+
+ list_for_each_entry(nfit_dcr, &prev->dcrs, list)
+ if (memcmp(nfit_dcr->dcr, dcr, length) == 0) {
+ list_move_tail(&nfit_dcr->list, &acpi_desc->dcrs);
+ return true;
+ }
+ nfit_dcr = devm_kzalloc(dev, sizeof(*nfit_dcr), GFP_KERNEL);
if (!nfit_dcr)
return false;
INIT_LIST_HEAD(&nfit_dcr->list);
@@ -274,12 +308,20 @@ static bool add_dcr(struct acpi_nfit_desc *acpi_desc,
}
static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_data_region *bdw)
{
+ size_t length = min_t(size_t, sizeof(*bdw), bdw->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_bdw *nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw),
- GFP_KERNEL);
+ struct nfit_bdw *nfit_bdw;
+
+ list_for_each_entry(nfit_bdw, &prev->bdws, list)
+ if (memcmp(nfit_bdw->bdw, bdw, length) == 0) {
+ list_move_tail(&nfit_bdw->list, &acpi_desc->bdws);
+ return true;
+ }
+ nfit_bdw = devm_kzalloc(dev, sizeof(*nfit_bdw), GFP_KERNEL);
if (!nfit_bdw)
return false;
INIT_LIST_HEAD(&nfit_bdw->list);
@@ -291,12 +333,20 @@ static bool add_bdw(struct acpi_nfit_desc *acpi_desc,
}
static bool add_idt(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_interleave *idt)
{
+ size_t length = min_t(size_t, sizeof(*idt), idt->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_idt *nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt),
- GFP_KERNEL);
+ struct nfit_idt *nfit_idt;
+
+ list_for_each_entry(nfit_idt, &prev->idts, list)
+ if (memcmp(nfit_idt->idt, idt, length) == 0) {
+ list_move_tail(&nfit_idt->list, &acpi_desc->idts);
+ return true;
+ }
+ nfit_idt = devm_kzalloc(dev, sizeof(*nfit_idt), GFP_KERNEL);
if (!nfit_idt)
return false;
INIT_LIST_HEAD(&nfit_idt->list);
@@ -308,12 +358,20 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
}
static bool add_flush(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev,
struct acpi_nfit_flush_address *flush)
{
+ size_t length = min_t(size_t, sizeof(*flush), flush->header.length);
struct device *dev = acpi_desc->dev;
- struct nfit_flush *nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush),
- GFP_KERNEL);
+ struct nfit_flush *nfit_flush;
+ list_for_each_entry(nfit_flush, &prev->flushes, list)
+ if (memcmp(nfit_flush->flush, flush, length) == 0) {
+ list_move_tail(&nfit_flush->list, &acpi_desc->flushes);
+ return true;
+ }
+
+ nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush), GFP_KERNEL);
if (!nfit_flush)
return false;
INIT_LIST_HEAD(&nfit_flush->list);
@@ -324,8 +382,8 @@ static bool add_flush(struct acpi_nfit_desc *acpi_desc,
return true;
}
-static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
- const void *end)
+static void *add_table(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev, void *table, const void *end)
{
struct device *dev = acpi_desc->dev;
struct acpi_nfit_header *hdr;
@@ -335,29 +393,35 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
return NULL;
hdr = table;
+ if (!hdr->length) {
+ dev_warn(dev, "found a zero length table '%d' parsing nfit\n",
+ hdr->type);
+ return NULL;
+ }
+
switch (hdr->type) {
case ACPI_NFIT_TYPE_SYSTEM_ADDRESS:
- if (!add_spa(acpi_desc, table))
+ if (!add_spa(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_MEMORY_MAP:
- if (!add_memdev(acpi_desc, table))
+ if (!add_memdev(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_CONTROL_REGION:
- if (!add_dcr(acpi_desc, table))
+ if (!add_dcr(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_DATA_REGION:
- if (!add_bdw(acpi_desc, table))
+ if (!add_bdw(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_INTERLEAVE:
- if (!add_idt(acpi_desc, table))
+ if (!add_idt(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
- if (!add_flush(acpi_desc, table))
+ if (!add_flush(acpi_desc, prev, table))
return err;
break;
case ACPI_NFIT_TYPE_SMBIOS:
@@ -597,7 +661,7 @@ static ssize_t revision_show(struct device *dev,
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
- return sprintf(buf, "%d\n", acpi_desc->nfit->header.revision);
+ return sprintf(buf, "%d\n", acpi_desc->acpi_header.revision);
}
static DEVICE_ATTR_RO(revision);
@@ -802,12 +866,7 @@ static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc)
device_handle = __to_nfit_memdev(nfit_mem)->device_handle;
nvdimm = acpi_nfit_dimm_by_handle(acpi_desc, device_handle);
if (nvdimm) {
- /*
- * If for some reason we find multiple DCRs the
- * first one wins
- */
- dev_err(acpi_desc->dev, "duplicate DCR detected: %s\n",
- nvdimm_name(nvdimm));
+ dimm_count++;
continue;
}
@@ -1476,6 +1535,9 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
struct resource res;
int count = 0, rc;
+ if (nfit_spa->is_registered)
+ return 0;
+
if (spa->range_index == 0) {
dev_dbg(acpi_desc->dev, "%s: detected invalid spa index\n",
__func__);
@@ -1529,6 +1591,8 @@ static int acpi_nfit_register_region(struct acpi_nfit_desc *acpi_desc,
if (!nvdimm_volatile_region_create(nvdimm_bus, ndr_desc))
return -ENOMEM;
}
+
+ nfit_spa->is_registered = 1;
return 0;
}
@@ -1545,71 +1609,100 @@ static int acpi_nfit_register_regions(struct acpi_nfit_desc *acpi_desc)
return 0;
}
+static int acpi_nfit_check_deletions(struct acpi_nfit_desc *acpi_desc,
+ struct nfit_table_prev *prev)
+{
+ struct device *dev = acpi_desc->dev;
+
+ if (!list_empty(&prev->spas) ||
+ !list_empty(&prev->memdevs) ||
+ !list_empty(&prev->dcrs) ||
+ !list_empty(&prev->bdws) ||
+ !list_empty(&prev->idts) ||
+ !list_empty(&prev->flushes)) {
+ dev_err(dev, "new nfit deletes entries (unsupported)\n");
+ return -ENXIO;
+ }
+ return 0;
+}
+
int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
{
struct device *dev = acpi_desc->dev;
+ struct nfit_table_prev prev;
const void *end;
u8 *data;
int rc;
- INIT_LIST_HEAD(&acpi_desc->spa_maps);
- INIT_LIST_HEAD(&acpi_desc->spas);
- INIT_LIST_HEAD(&acpi_desc->dcrs);
- INIT_LIST_HEAD(&acpi_desc->bdws);
- INIT_LIST_HEAD(&acpi_desc->idts);
- INIT_LIST_HEAD(&acpi_desc->flushes);
- INIT_LIST_HEAD(&acpi_desc->memdevs);
- INIT_LIST_HEAD(&acpi_desc->dimms);
- mutex_init(&acpi_desc->spa_map_mutex);
+ mutex_lock(&acpi_desc->init_mutex);
+
+ INIT_LIST_HEAD(&prev.spas);
+ INIT_LIST_HEAD(&prev.memdevs);
+ INIT_LIST_HEAD(&prev.dcrs);
+ INIT_LIST_HEAD(&prev.bdws);
+ INIT_LIST_HEAD(&prev.idts);
+ INIT_LIST_HEAD(&prev.flushes);
+
+ list_cut_position(&prev.spas, &acpi_desc->spas,
+ acpi_desc->spas.prev);
+ list_cut_position(&prev.memdevs, &acpi_desc->memdevs,
+ acpi_desc->memdevs.prev);
+ list_cut_position(&prev.dcrs, &acpi_desc->dcrs,
+ acpi_desc->dcrs.prev);
+ list_cut_position(&prev.bdws, &acpi_desc->bdws,
+ acpi_desc->bdws.prev);
+ list_cut_position(&prev.idts, &acpi_desc->idts,
+ acpi_desc->idts.prev);
+ list_cut_position(&prev.flushes, &acpi_desc->flushes,
+ acpi_desc->flushes.prev);
data = (u8 *) acpi_desc->nfit;
end = data + sz;
- data += sizeof(struct acpi_table_nfit);
while (!IS_ERR_OR_NULL(data))
- data = add_table(acpi_desc, data, end);
+ data = add_table(acpi_desc, &prev, data, end);
if (IS_ERR(data)) {
dev_dbg(dev, "%s: nfit table parsing error: %ld\n", __func__,
PTR_ERR(data));
- return PTR_ERR(data);
+ rc = PTR_ERR(data);
+ goto out_unlock;
}
- if (nfit_mem_init(acpi_desc) != 0)
- return -ENOMEM;
+ rc = acpi_nfit_check_deletions(acpi_desc, &prev);
+ if (rc)
+ goto out_unlock;
+
+ if (nfit_mem_init(acpi_desc) != 0) {
+ rc = -ENOMEM;
+ goto out_unlock;
+ }
acpi_nfit_init_dsms(acpi_desc);
rc = acpi_nfit_register_dimms(acpi_desc);
if (rc)
- return rc;
+ goto out_unlock;
- return acpi_nfit_register_regions(acpi_desc);
+ rc = acpi_nfit_register_regions(acpi_desc);
+
+ out_unlock:
+ mutex_unlock(&acpi_desc->init_mutex);
+ return rc;
}
EXPORT_SYMBOL_GPL(acpi_nfit_init);
-static int acpi_nfit_add(struct acpi_device *adev)
+static struct acpi_nfit_desc *acpi_nfit_desc_init(struct acpi_device *adev)
{
struct nvdimm_bus_descriptor *nd_desc;
struct acpi_nfit_desc *acpi_desc;
struct device *dev = &adev->dev;
- struct acpi_table_header *tbl;
- acpi_status status = AE_OK;
- acpi_size sz;
- int rc;
-
- status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
- if (ACPI_FAILURE(status)) {
- dev_err(dev, "failed to find NFIT\n");
- return -ENXIO;
- }
acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL);
if (!acpi_desc)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
dev_set_drvdata(dev, acpi_desc);
acpi_desc->dev = dev;
- acpi_desc->nfit = (struct acpi_table_nfit *) tbl;
acpi_desc->blk_do_io = acpi_nfit_blk_region_do_io;
nd_desc = &acpi_desc->nd_desc;
nd_desc->provider_name = "ACPI.NFIT";
@@ -1617,8 +1710,73 @@ static int acpi_nfit_add(struct acpi_device *adev)
nd_desc->attr_groups = acpi_nfit_attribute_groups;
acpi_desc->nvdimm_bus = nvdimm_bus_register(dev, nd_desc);
- if (!acpi_desc->nvdimm_bus)
- return -ENXIO;
+ if (!acpi_desc->nvdimm_bus) {
+ devm_kfree(dev, acpi_desc);
+ return ERR_PTR(-ENXIO);
+ }
+
+ INIT_LIST_HEAD(&acpi_desc->spa_maps);
+ INIT_LIST_HEAD(&acpi_desc->spas);
+ INIT_LIST_HEAD(&acpi_desc->dcrs);
+ INIT_LIST_HEAD(&acpi_desc->bdws);
+ INIT_LIST_HEAD(&acpi_desc->idts);
+ INIT_LIST_HEAD(&acpi_desc->flushes);
+ INIT_LIST_HEAD(&acpi_desc->memdevs);
+ INIT_LIST_HEAD(&acpi_desc->dimms);
+ mutex_init(&acpi_desc->spa_map_mutex);
+ mutex_init(&acpi_desc->init_mutex);
+
+ return acpi_desc;
+}
+
+static int acpi_nfit_add(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_nfit_desc *acpi_desc;
+ struct device *dev = &adev->dev;
+ struct acpi_table_header *tbl;
+ acpi_status status = AE_OK;
+ acpi_size sz;
+ int rc;
+
+ status = acpi_get_table_with_size("NFIT", 0, &tbl, &sz);
+ if (ACPI_FAILURE(status)) {
+ /* This is ok, we could have an nvdimm hotplugged later */
+ dev_dbg(dev, "failed to find NFIT at startup\n");
+ return 0;
+ }
+
+ acpi_desc = acpi_nfit_desc_init(adev);
+ if (IS_ERR(acpi_desc)) {
+ dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
+ __func__, PTR_ERR(acpi_desc));
+ return PTR_ERR(acpi_desc);
+ }
+
+ /*
+ * Save the acpi header for later and then skip it,
+ * making nfit point to the first nfit table header.
+ */
+ acpi_desc->acpi_header = *tbl;
+ acpi_desc->nfit = (void *) tbl + sizeof(struct acpi_table_nfit);
+ sz -= sizeof(struct acpi_table_nfit);
+
+ /* Evaluate _FIT and override with that if present */
+ status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+ if (ACPI_SUCCESS(status) && buf.length > 0) {
+ union acpi_object *obj;
+ /*
+ * Adjust for the acpi_object header of the _FIT
+ */
+ obj = buf.pointer;
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ acpi_desc->nfit =
+ (struct acpi_nfit_header *)obj->buffer.pointer;
+ sz = obj->buffer.length;
+ } else
+ dev_dbg(dev, "%s invalid type %d, ignoring _FIT\n",
+ __func__, (int) obj->type);
+ }
rc = acpi_nfit_init(acpi_desc, sz);
if (rc) {
@@ -1636,6 +1794,62 @@ static int acpi_nfit_remove(struct acpi_device *adev)
return 0;
}
+static void acpi_nfit_notify(struct acpi_device *adev, u32 event)
+{
+ struct acpi_nfit_desc *acpi_desc = dev_get_drvdata(&adev->dev);
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_nfit_header *nfit_saved;
+ union acpi_object *obj;
+ struct device *dev = &adev->dev;
+ acpi_status status;
+ int ret;
+
+ dev_dbg(dev, "%s: event: %d\n", __func__, event);
+
+ device_lock(dev);
+ if (!dev->driver) {
+ /* dev->driver may be null if we're being removed */
+ dev_dbg(dev, "%s: no driver found for dev\n", __func__);
+ goto out_unlock;
+ }
+
+ if (!acpi_desc) {
+ acpi_desc = acpi_nfit_desc_init(adev);
+ if (IS_ERR(acpi_desc)) {
+ dev_err(dev, "%s: error initializing acpi_desc: %ld\n",
+ __func__, PTR_ERR(acpi_desc));
+ goto out_unlock;
+ }
+ }
+
+ /* Evaluate _FIT */
+ status = acpi_evaluate_object(adev->handle, "_FIT", NULL, &buf);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to evaluate _FIT\n");
+ goto out_unlock;
+ }
+
+ nfit_saved = acpi_desc->nfit;
+ obj = buf.pointer;
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ acpi_desc->nfit =
+ (struct acpi_nfit_header *)obj->buffer.pointer;
+ ret = acpi_nfit_init(acpi_desc, obj->buffer.length);
+ if (ret) {
+ /* Merge failed, restore old nfit, and exit */
+ acpi_desc->nfit = nfit_saved;
+ dev_err(dev, "failed to merge updated NFIT\n");
+ }
+ } else {
+ /* Bad _FIT, restore old nfit */
+ dev_err(dev, "Invalid _FIT\n");
+ }
+ kfree(buf.pointer);
+
+ out_unlock:
+ device_unlock(dev);
+}
+
static const struct acpi_device_id acpi_nfit_ids[] = {
{ "ACPI0012", 0 },
{ "", 0 },
@@ -1648,6 +1862,7 @@ static struct acpi_driver acpi_nfit_driver = {
.ops = {
.add = acpi_nfit_add,
.remove = acpi_nfit_remove,
+ .notify = acpi_nfit_notify,
},
};
diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h
index 329a1eb..3d549a3 100644
--- a/drivers/acpi/nfit.h
+++ b/drivers/acpi/nfit.h
@@ -48,6 +48,7 @@ enum {
struct nfit_spa {
struct acpi_nfit_system_address *spa;
struct list_head list;
+ int is_registered;
};
struct nfit_dcr {
@@ -95,8 +96,10 @@ struct nfit_mem {
struct acpi_nfit_desc {
struct nvdimm_bus_descriptor nd_desc;
- struct acpi_table_nfit *nfit;
+ struct acpi_table_header acpi_header;
+ struct acpi_nfit_header *nfit;
struct mutex spa_map_mutex;
+ struct mutex init_mutex;
struct list_head spa_maps;
struct list_head memdevs;
struct list_head flushes;
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 850d7bf..ae3fe4e 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -768,6 +768,13 @@ static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
else
continue;
+ /*
+ * Some legacy x86 host bridge drivers use iomem_resource and
+ * ioport_resource as default resource pool, skip it.
+ */
+ if (res == root)
+ continue;
+
conflict = insert_resource_conflict(root, res);
if (conflict) {
dev_info(&info->bridge->dev,
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index f4e02ae..11154a3 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -200,7 +200,8 @@ static int acpi_pss_perf_init(struct acpi_processor *pr,
goto err_remove_sysfs_thermal;
}
- sysfs_remove_link(&pr->cdev->device.kobj, "device");
+ return 0;
+
err_remove_sysfs_thermal:
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister:
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index bf034f8..2fa8304 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -14,7 +14,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/dmi.h>
#include "sbshc.h"
#define PREFIX "ACPI: "
@@ -30,6 +29,7 @@ struct acpi_smb_hc {
u8 query_bit;
smbus_alarm_callback callback;
void *context;
+ bool done;
};
static int acpi_smbus_hc_add(struct acpi_device *device);
@@ -88,8 +88,6 @@ enum acpi_smb_offset {
ACPI_SMB_ALARM_DATA = 0x26, /* 2 bytes alarm data */
};
-static bool macbook;
-
static inline int smb_hc_read(struct acpi_smb_hc *hc, u8 address, u8 *data)
{
return ec_read(hc->offset + address, data);
@@ -100,27 +98,11 @@ static inline int smb_hc_write(struct acpi_smb_hc *hc, u8 address, u8 data)
return ec_write(hc->offset + address, data);
}
-static inline int smb_check_done(struct acpi_smb_hc *hc)
-{
- union acpi_smb_status status = {.raw = 0};
- smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw);
- return status.fields.done && (status.fields.status == SMBUS_OK);
-}
-
static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
{
- if (wait_event_timeout(hc->wait, smb_check_done(hc),
- msecs_to_jiffies(timeout)))
+ if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout)))
return 0;
- /*
- * After the timeout happens, OS will try to check the status of SMbus.
- * If the status is what OS expected, it will be regarded as the bogus
- * timeout.
- */
- if (smb_check_done(hc))
- return 0;
- else
- return -ETIME;
+ return -ETIME;
}
static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
@@ -135,8 +117,7 @@ static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
}
mutex_lock(&hc->lock);
- if (macbook)
- udelay(5);
+ hc->done = false;
if (smb_hc_read(hc, ACPI_SMB_PROTOCOL, &temp))
goto end;
if (temp) {
@@ -235,8 +216,10 @@ static int smbus_alarm(void *context)
if (smb_hc_read(hc, ACPI_SMB_STATUS, &status.raw))
return 0;
/* Check if it is only a completion notify */
- if (status.fields.done)
+ if (status.fields.done && status.fields.status == SMBUS_OK) {
+ hc->done = true;
wake_up(&hc->wait);
+ }
if (!status.fields.alarm)
return 0;
mutex_lock(&hc->lock);
@@ -262,29 +245,12 @@ extern int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
acpi_handle handle, acpi_ec_query_func func,
void *data);
-static int macbook_dmi_match(const struct dmi_system_id *d)
-{
- pr_debug("Detected MacBook, enabling workaround\n");
- macbook = true;
- return 0;
-}
-
-static struct dmi_system_id acpi_smbus_dmi_table[] = {
- { macbook_dmi_match, "Apple MacBook", {
- DMI_MATCH(DMI_BOARD_VENDOR, "Apple"),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBook") },
- },
- { },
-};
-
static int acpi_smbus_hc_add(struct acpi_device *device)
{
int status;
unsigned long long val;
struct acpi_smb_hc *hc;
- dmi_check_system(acpi_smbus_dmi_table);
-
if (!device)
return -EINVAL;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index daf9fc8..78d5f02 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1308,6 +1308,48 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp)
kfree(pnp->unique_id);
}
+/**
+ * acpi_dma_supported - Check DMA support for the specified device.
+ * @adev: The pointer to acpi device
+ *
+ * Return false if DMA is not supported. Otherwise, return true
+ */
+bool acpi_dma_supported(struct acpi_device *adev)
+{
+ if (!adev)
+ return false;
+
+ if (adev->flags.cca_seen)
+ return true;
+
+ /*
+ * Per ACPI 6.0 sec 6.2.17, assume devices can do cache-coherent
+ * DMA on "Intel platforms". Presumably that includes all x86 and
+ * ia64, and other arches will set CONFIG_ACPI_CCA_REQUIRED=y.
+ */
+ if (!IS_ENABLED(CONFIG_ACPI_CCA_REQUIRED))
+ return true;
+
+ return false;
+}
+
+/**
+ * acpi_get_dma_attr - Check the supported DMA attr for the specified device.
+ * @adev: The pointer to acpi device
+ *
+ * Return enum dev_dma_attr.
+ */
+enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
+{
+ if (!acpi_dma_supported(adev))
+ return DEV_DMA_NOT_SUPPORTED;
+
+ if (adev->flags.coherent_dma)
+ return DEV_DMA_COHERENT;
+ else
+ return DEV_DMA_NON_COHERENT;
+}
+
static void acpi_init_coherency(struct acpi_device *adev)
{
unsigned long long cca = 0;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 30d8518..82707f9 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -315,7 +315,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (crt == -1) {
tz->trips.critical.flags.valid = 0;
} else if (crt > 0) {
- unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
+ unsigned long crt_k = CELSIUS_TO_DECI_KELVIN(crt);
/*
* Allow override critical threshold
*/
@@ -351,7 +351,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
if (psv == -1) {
status = AE_SUPPORT;
} else if (psv > 0) {
- tmp = CELSIUS_TO_KELVIN(psv);
+ tmp = CELSIUS_TO_DECI_KELVIN(psv);
status = AE_OK;
} else {
status = acpi_evaluate_integer(tz->device->handle,
@@ -431,7 +431,7 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
break;
if (i == 1)
tz->trips.active[0].temperature =
- CELSIUS_TO_KELVIN(act);
+ CELSIUS_TO_DECI_KELVIN(act);
else
/*
* Don't allow override higher than
@@ -439,9 +439,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
*/
tz->trips.active[i - 1].temperature =
(tz->trips.active[i - 2].temperature <
- CELSIUS_TO_KELVIN(act) ?
+ CELSIUS_TO_DECI_KELVIN(act) ?
tz->trips.active[i - 2].temperature :
- CELSIUS_TO_KELVIN(act));
+ CELSIUS_TO_DECI_KELVIN(act));
break;
} else {
tz->trips.active[i].temperature = tmp;
@@ -1105,7 +1105,7 @@ static int acpi_thermal_add(struct acpi_device *device)
INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
- acpi_device_bid(device), KELVIN_TO_CELSIUS(tz->temperature));
+ acpi_device_bid(device), DECI_KELVIN_TO_CELSIUS(tz->temperature));
goto end;
free_memory:
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 0d3a384..daaf1c4 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -233,6 +233,15 @@ static const struct dmi_system_id video_detect_dmi_table[] = {
},
},
{
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1272633 */
+ .callback = video_detect_force_video,
+ .ident = "Dell XPS14 L421X",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS L421X"),
+ },
+ },
+ {
/* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
.callback = video_detect_force_video,
.ident = "Dell XPS15 L521X",
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 6aaa3f8..861643ea 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -100,7 +100,7 @@ config SATA_AHCI_PLATFORM
config AHCI_BRCMSTB
tristate "Broadcom STB AHCI SATA support"
- depends on ARCH_BRCMSTB
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC
help
This option enables support for the AHCI SATA3 controller found on
STB SoC's.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index ff02bb4..594fcab 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -314,16 +314,6 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x1f37), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f3e), board_ahci_avn }, /* Avoton RAID */
{ PCI_VDEVICE(INTEL, 0x1f3f), board_ahci_avn }, /* Avoton RAID */
- { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
- { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
- { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
- { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
{ PCI_VDEVICE(INTEL, 0x2823), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x2827), board_ahci }, /* Wellsburg RAID */
{ PCI_VDEVICE(INTEL, 0x8d02), board_ahci }, /* Wellsburg AHCI */
@@ -350,10 +340,22 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
{ PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0xa102), board_ahci }, /* Sunrise Point-H AHCI */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
+ { PCI_VDEVICE(INTEL, 0xa106), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa107), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa10f), board_ahci }, /* Sunrise Point-H RAID */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0x2826), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa182), board_ahci }, /* Lewisburg AHCI*/
+ { PCI_VDEVICE(INTEL, 0xa184), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa186), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa18e), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa202), board_ahci }, /* Lewisburg AHCI*/
+ { PCI_VDEVICE(INTEL, 0xa204), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa206), board_ahci }, /* Lewisburg RAID*/
+ { PCI_VDEVICE(INTEL, 0xa20e), board_ahci }, /* Lewisburg RAID*/
/* JMicron 360/1/3/5/6, match class to avoid IDE function */
{ PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
@@ -1304,15 +1306,13 @@ static inline void ahci_gtf_filter_workaround(struct ata_host *host)
#endif
/*
- * ahci_init_msix() only implements single MSI-X support, not multiple
- * MSI-X per-port interrupts. This is needed for host controllers that only
- * have MSI-X support implemented, but no MSI or intx.
+ * ahci_init_msix() - optionally enable per-port MSI-X otherwise defer
+ * to single msi.
*/
static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
- struct ahci_host_priv *hpriv)
+ struct ahci_host_priv *hpriv, unsigned long flags)
{
- int rc, nvec;
- struct msix_entry entry = {};
+ int nvec, i, rc;
/* Do not init MSI-X if MSI is disabled for the device */
if (hpriv->flags & AHCI_HFLAG_NO_MSI)
@@ -1322,22 +1322,39 @@ static int ahci_init_msix(struct pci_dev *pdev, unsigned int n_ports,
if (nvec < 0)
return nvec;
- if (!nvec) {
+ /*
+ * Proper MSI-X implementations will have a vector per-port.
+ * Barring that, we prefer single-MSI over single-MSIX. If this
+ * check fails (not enough MSI-X vectors for all ports) we will
+ * be called again with the flag clear iff ahci_init_msi()
+ * fails.
+ */
+ if (flags & AHCI_HFLAG_MULTI_MSIX) {
+ if (nvec < n_ports)
+ return -ENODEV;
+ nvec = n_ports;
+ } else if (nvec) {
+ nvec = 1;
+ } else {
+ /*
+ * Emit dev_err() since this was the non-legacy irq
+ * method of last resort.
+ */
rc = -ENODEV;
goto fail;
}
- /*
- * There can be more than one vector (e.g. for error detection or
- * hdd hotplug). Only the first vector (entry.entry = 0) is used.
- */
- rc = pci_enable_msix_exact(pdev, &entry, 1);
+ for (i = 0; i < nvec; i++)
+ hpriv->msix[i].entry = i;
+ rc = pci_enable_msix_exact(pdev, hpriv->msix, nvec);
if (rc < 0)
goto fail;
- hpriv->irq = entry.vector;
+ if (nvec > 1)
+ hpriv->flags |= AHCI_HFLAG_MULTI_MSIX;
+ hpriv->irq = hpriv->msix[0].vector; /* for single msi-x */
- return 1;
+ return nvec;
fail:
dev_err(&pdev->dev,
"failed to enable MSI-X with error %d, # of vectors: %d\n",
@@ -1401,20 +1418,25 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports,
{
int nvec;
+ /*
+ * Try to enable per-port MSI-X. If the host is not capable
+ * fall back to single MSI before finally attempting single
+ * MSI-X.
+ */
+ nvec = ahci_init_msix(pdev, n_ports, hpriv, AHCI_HFLAG_MULTI_MSIX);
+ if (nvec >= 0)
+ return nvec;
+
nvec = ahci_init_msi(pdev, n_ports, hpriv);
if (nvec >= 0)
return nvec;
- /*
- * Currently, MSI-X support only implements single IRQ mode and
- * exists for controllers which can't do other types of IRQ. Only
- * set it up if MSI fails.
- */
- nvec = ahci_init_msix(pdev, n_ports, hpriv);
+ /* try single-msix */
+ nvec = ahci_init_msix(pdev, n_ports, hpriv, 0);
if (nvec >= 0)
return nvec;
- /* lagacy intx interrupts */
+ /* legacy intx interrupts */
pci_intx(pdev, 1);
hpriv->irq = pdev->irq;
@@ -1576,7 +1598,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!host)
return -ENOMEM;
host->private_data = hpriv;
-
+ hpriv->msix = devm_kzalloc(&pdev->dev,
+ sizeof(struct msix_entry) * n_ports, GFP_KERNEL);
+ if (!hpriv->msix)
+ return -ENOMEM;
ahci_init_interrupts(pdev, n_ports, hpriv);
if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss)
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 45586c1..a4faa43 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -35,6 +35,7 @@
#ifndef _AHCI_H
#define _AHCI_H
+#include <linux/pci.h>
#include <linux/clk.h>
#include <linux/libata.h>
#include <linux/phy/phy.h>
@@ -237,11 +238,18 @@ enum {
AHCI_HFLAG_DELAY_ENGINE = (1 << 15), /* do not start engine on
port start (wait until
error-handling stage) */
- AHCI_HFLAG_MULTI_MSI = (1 << 16), /* multiple PCI MSIs */
AHCI_HFLAG_NO_DEVSLP = (1 << 17), /* no device sleep */
AHCI_HFLAG_NO_FBS = (1 << 18), /* no FBS */
AHCI_HFLAG_EDGE_IRQ = (1 << 19), /* HOST_IRQ_STAT behaves as
Edge Triggered */
+#ifdef CONFIG_PCI_MSI
+ AHCI_HFLAG_MULTI_MSI = (1 << 20), /* multiple PCI MSIs */
+ AHCI_HFLAG_MULTI_MSIX = (1 << 21), /* per-port MSI-X */
+#else
+ /* compile out MSI infrastructure */
+ AHCI_HFLAG_MULTI_MSI = 0,
+ AHCI_HFLAG_MULTI_MSIX = 0,
+#endif
/* ap->flags bits */
@@ -308,7 +316,6 @@ struct ahci_port_priv {
unsigned int ncq_saw_d2h:1;
unsigned int ncq_saw_dmas:1;
unsigned int ncq_saw_sdb:1;
- atomic_t intr_status; /* interrupts to handle */
spinlock_t lock; /* protects parent ata_port */
u32 intr_mask; /* interrupts to enable */
bool fbs_supported; /* set iff FBS is supported */
@@ -343,6 +350,7 @@ struct ahci_host_priv {
* the PHY position in this array.
*/
struct phy **phys;
+ struct msix_entry *msix; /* Optional MSI-X support */
unsigned nports; /* Number of ports */
void *plat_data; /* Other platform data */
unsigned int irq; /* interrupt line */
@@ -354,6 +362,21 @@ struct ahci_host_priv {
void (*start_engine)(struct ata_port *ap);
};
+#ifdef CONFIG_PCI_MSI
+static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
+{
+ if (hpriv->flags & AHCI_HFLAG_MULTI_MSIX)
+ return hpriv->msix[port].vector;
+ else
+ return hpriv->irq + port;
+}
+#else
+static inline int ahci_irq_vector(struct ahci_host_priv *hpriv, int port)
+{
+ return hpriv->irq;
+}
+#endif
+
extern int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[];
diff --git a/drivers/ata/ahci_brcmstb.c b/drivers/ata/ahci_brcmstb.c
index 14b7305..b36cae2 100644
--- a/drivers/ata/ahci_brcmstb.c
+++ b/drivers/ata/ahci_brcmstb.c
@@ -52,8 +52,10 @@
#define SATA_TOP_CTRL_2_PHY_GLOBAL_RESET BIT(14)
#define SATA_TOP_CTRL_PHY_OFFS 0x8
#define SATA_TOP_MAX_PHYS 2
-#define SATA_TOP_CTRL_SATA_TP_OUT 0x1c
-#define SATA_TOP_CTRL_CLIENT_INIT_CTRL 0x20
+
+#define SATA_FIRST_PORT_CTRL 0x700
+#define SATA_NEXT_PORT_CTRL_OFFSET 0x80
+#define SATA_PORT_PCTRL6(reg_base) (reg_base + 0x18)
/* On big-endian MIPS, buses are reversed to big endian, so switch them back */
#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
@@ -69,14 +71,21 @@
(DATA_ENDIAN << DMADESC_ENDIAN_SHIFT) | \
(MMIO_ENDIAN << MMIO_ENDIAN_SHIFT))
+enum brcm_ahci_quirks {
+ BRCM_AHCI_QUIRK_NO_NCQ = BIT(0),
+ BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE = BIT(1),
+};
+
struct brcm_ahci_priv {
struct device *dev;
void __iomem *top_ctrl;
u32 port_mask;
+ u32 quirks;
};
static const struct ata_port_info ahci_brcm_port_info = {
- .flags = AHCI_FLAG_COMMON,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_NO_DIPM,
+ .link_flags = ATA_LFLAG_NO_DB_DELAY,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &ahci_platform_ops,
@@ -107,6 +116,34 @@ static inline void brcm_sata_writereg(u32 val, void __iomem *addr)
writel_relaxed(val, addr);
}
+static void brcm_sata_alpm_init(struct ahci_host_priv *hpriv)
+{
+ struct brcm_ahci_priv *priv = hpriv->plat_data;
+ u32 bus_ctrl, port_ctrl, host_caps;
+ int i;
+
+ /* Enable support for ALPM */
+ bus_ctrl = brcm_sata_readreg(priv->top_ctrl +
+ SATA_TOP_CTRL_BUS_CTRL);
+ brcm_sata_writereg(bus_ctrl | OVERRIDE_HWINIT,
+ priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+ host_caps = readl(hpriv->mmio + HOST_CAP);
+ writel(host_caps | HOST_CAP_ALPM, hpriv->mmio);
+ brcm_sata_writereg(bus_ctrl, priv->top_ctrl + SATA_TOP_CTRL_BUS_CTRL);
+
+ /*
+ * Adjust timeout to allow PLL sufficient time to lock while waking
+ * up from slumber mode.
+ */
+ for (i = 0, port_ctrl = SATA_FIRST_PORT_CTRL;
+ i < SATA_TOP_MAX_PHYS;
+ i++, port_ctrl += SATA_NEXT_PORT_CTRL_OFFSET) {
+ if (priv->port_mask & BIT(i))
+ writel(0xff1003fc,
+ hpriv->mmio + SATA_PORT_PCTRL6(port_ctrl));
+ }
+}
+
static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
{
void __iomem *phyctrl = priv->top_ctrl + SATA_TOP_CTRL_PHY_CTRL +
@@ -114,6 +151,9 @@ static void brcm_sata_phy_enable(struct brcm_ahci_priv *priv, int port)
void __iomem *p;
u32 reg;
+ if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+ return;
+
/* clear PHY_DEFAULT_POWER_STATE */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_1;
reg = brcm_sata_readreg(p);
@@ -143,6 +183,9 @@ static void brcm_sata_phy_disable(struct brcm_ahci_priv *priv, int port)
void __iomem *p;
u32 reg;
+ if (priv->quirks & BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE)
+ return;
+
/* power-off the PHY digital logic */
p = phyctrl + SATA_TOP_CTRL_PHY_CTRL_2;
reg = brcm_sata_readreg(p);
@@ -230,6 +273,7 @@ static int brcm_ahci_resume(struct device *dev)
brcm_sata_init(priv);
brcm_sata_phys_enable(priv);
+ brcm_sata_alpm_init(hpriv);
return ahci_platform_resume(dev);
}
#endif
@@ -256,6 +300,11 @@ static int brcm_ahci_probe(struct platform_device *pdev)
if (IS_ERR(priv->top_ctrl))
return PTR_ERR(priv->top_ctrl);
+ if (of_device_is_compatible(dev->of_node, "brcm,bcm7425-ahci")) {
+ priv->quirks |= BRCM_AHCI_QUIRK_NO_NCQ;
+ priv->quirks |= BRCM_AHCI_QUIRK_SKIP_PHY_ENABLE;
+ }
+
brcm_sata_init(priv);
priv->port_mask = brcm_ahci_get_portmask(pdev, priv);
@@ -269,10 +318,15 @@ static int brcm_ahci_probe(struct platform_device *pdev)
return PTR_ERR(hpriv);
hpriv->plat_data = priv;
+ brcm_sata_alpm_init(hpriv);
+
ret = ahci_platform_enable_resources(hpriv);
if (ret)
return ret;
+ if (priv->quirks & BRCM_AHCI_QUIRK_NO_NCQ)
+ hpriv->flags |= AHCI_HFLAG_NO_NCQ;
+
ret = ahci_platform_init_host(pdev, hpriv, &ahci_brcm_port_info,
&ahci_platform_sht);
if (ret)
@@ -300,6 +354,7 @@ static int brcm_ahci_remove(struct platform_device *pdev)
}
static const struct of_device_id ahci_of_match[] = {
+ {.compatible = "brcm,bcm7425-ahci"},
{.compatible = "brcm,bcm7445-ahci"},
{},
};
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c
index 8490d37..f7a7fa8 100644
--- a/drivers/ata/ahci_mvebu.c
+++ b/drivers/ata/ahci_mvebu.c
@@ -62,6 +62,7 @@ static void ahci_mvebu_regret_option(struct ahci_host_priv *hpriv)
writel(0x80, hpriv->mmio + AHCI_VENDOR_SPECIFIC_0_DATA);
}
+#ifdef CONFIG_PM_SLEEP
static int ahci_mvebu_suspend(struct platform_device *pdev, pm_message_t state)
{
return ahci_platform_suspend_host(&pdev->dev);
@@ -81,6 +82,10 @@ static int ahci_mvebu_resume(struct platform_device *pdev)
return ahci_platform_resume_host(&pdev->dev);
}
+#else
+#define ahci_mvebu_suspend NULL
+#define ahci_mvebu_resume NULL
+#endif
static const struct ata_port_info ahci_mvebu_port_info = {
.flags = AHCI_FLAG_COMMON,
diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c
index d0f9de9..7bdee9b 100644
--- a/drivers/ata/ahci_qoriq.c
+++ b/drivers/ata/ahci_qoriq.c
@@ -34,14 +34,20 @@
/* port register default value */
#define AHCI_PORT_PHY_1_CFG 0xa003fffe
-#define AHCI_PORT_PHY_2_CFG 0x28183411
-#define AHCI_PORT_PHY_3_CFG 0x0e081004
-#define AHCI_PORT_PHY_4_CFG 0x00480811
-#define AHCI_PORT_PHY_5_CFG 0x192c96a4
-#define AHCI_PORT_TRANS_CFG 0x08000025
+#define AHCI_PORT_TRANS_CFG 0x08000029
+
+/* for ls1021a */
+#define LS1021A_PORT_PHY2 0x28183414
+#define LS1021A_PORT_PHY3 0x0e080e06
+#define LS1021A_PORT_PHY4 0x064a080b
+#define LS1021A_PORT_PHY5 0x2aa86470
#define SATA_ECC_DISABLE 0x00020000
+/* for ls1043a */
+#define LS1043A_PORT_PHY2 0x28184d1f
+#define LS1043A_PORT_PHY3 0x0e081509
+
enum ahci_qoriq_type {
AHCI_LS1021A,
AHCI_LS1043A,
@@ -151,16 +157,23 @@ static int ahci_qoriq_phy_init(struct ahci_host_priv *hpriv)
case AHCI_LS1021A:
writel(SATA_ECC_DISABLE, qpriv->ecc_addr);
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
- writel(AHCI_PORT_PHY_2_CFG, reg_base + PORT_PHY2);
- writel(AHCI_PORT_PHY_3_CFG, reg_base + PORT_PHY3);
- writel(AHCI_PORT_PHY_4_CFG, reg_base + PORT_PHY4);
- writel(AHCI_PORT_PHY_5_CFG, reg_base + PORT_PHY5);
+ writel(LS1021A_PORT_PHY2, reg_base + PORT_PHY2);
+ writel(LS1021A_PORT_PHY3, reg_base + PORT_PHY3);
+ writel(LS1021A_PORT_PHY4, reg_base + PORT_PHY4);
+ writel(LS1021A_PORT_PHY5, reg_base + PORT_PHY5);
writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
break;
case AHCI_LS1043A:
+ writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(LS1043A_PORT_PHY2, reg_base + PORT_PHY2);
+ writel(LS1043A_PORT_PHY3, reg_base + PORT_PHY3);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
+ break;
+
case AHCI_LS2080A:
writel(AHCI_PORT_PHY_1_CFG, reg_base + PORT_PHY1);
+ writel(AHCI_PORT_TRANS_CFG, reg_base + PORT_TRANS);
break;
}
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
index 096064c..d61740e 100644
--- a/drivers/ata/libahci.c
+++ b/drivers/ata/libahci.c
@@ -43,6 +43,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <linux/libata.h>
+#include <linux/pci.h>
#include "ahci.h"
#include "libata.h"
@@ -1273,6 +1274,15 @@ static int ahci_exec_polled_cmd(struct ata_port *ap, int pmp,
ata_tf_to_fis(tf, pmp, is_cmd, fis);
ahci_fill_cmd_slot(pp, 0, cmd_fis_len | flags | (pmp << 12));
+ /* set port value for softreset of Port Multiplier */
+ if (pp->fbs_enabled && pp->fbs_last_dev != pmp) {
+ tmp = readl(port_mmio + PORT_FBS);
+ tmp &= ~(PORT_FBS_DEV_MASK | PORT_FBS_DEC);
+ tmp |= pmp << PORT_FBS_DEV_OFFSET;
+ writel(tmp, port_mmio + PORT_FBS);
+ pp->fbs_last_dev = pmp;
+ }
+
/* issue & wait */
writel(1, port_mmio + PORT_CMD_ISSUE);
@@ -1795,41 +1805,24 @@ static void ahci_port_intr(struct ata_port *ap)
ahci_handle_port_interrupt(ap, port_mmio, status);
}
-static irqreturn_t ahci_port_thread_fn(int irq, void *dev_instance)
+static irqreturn_t ahci_multi_irqs_intr_hard(int irq, void *dev_instance)
{
struct ata_port *ap = dev_instance;
- struct ahci_port_priv *pp = ap->private_data;
void __iomem *port_mmio = ahci_port_base(ap);
u32 status;
- status = atomic_xchg(&pp->intr_status, 0);
- if (!status)
- return IRQ_NONE;
-
- spin_lock_bh(ap->lock);
- ahci_handle_port_interrupt(ap, port_mmio, status);
- spin_unlock_bh(ap->lock);
-
- return IRQ_HANDLED;
-}
-
-static irqreturn_t ahci_multi_irqs_intr(int irq, void *dev_instance)
-{
- struct ata_port *ap = dev_instance;
- void __iomem *port_mmio = ahci_port_base(ap);
- struct ahci_port_priv *pp = ap->private_data;
- u32 status;
-
VPRINTK("ENTER\n");
status = readl(port_mmio + PORT_IRQ_STAT);
writel(status, port_mmio + PORT_IRQ_STAT);
- atomic_or(status, &pp->intr_status);
+ spin_lock(ap->lock);
+ ahci_handle_port_interrupt(ap, port_mmio, status);
+ spin_unlock(ap->lock);
VPRINTK("EXIT\n");
- return IRQ_WAKE_THREAD;
+ return IRQ_HANDLED;
}
static u32 ahci_handle_port_intr(struct ata_host *host, u32 irq_masked)
@@ -2470,9 +2463,10 @@ void ahci_set_em_messages(struct ahci_host_priv *hpriv,
}
EXPORT_SYMBOL_GPL(ahci_set_em_messages);
-static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
+static int ahci_host_activate_multi_irqs(struct ata_host *host,
struct scsi_host_template *sht)
{
+ struct ahci_host_priv *hpriv = host->private_data;
int i, rc;
rc = ata_host_start(host);
@@ -2484,6 +2478,7 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
*/
for (i = 0; i < host->n_ports; i++) {
struct ahci_port_priv *pp = host->ports[i]->private_data;
+ int irq = ahci_irq_vector(hpriv, i);
/* Do not receive interrupts sent by dummy ports */
if (!pp) {
@@ -2491,14 +2486,14 @@ static int ahci_host_activate_multi_irqs(struct ata_host *host, int irq,
continue;
}
- rc = devm_request_threaded_irq(host->dev, irq + i,
- ahci_multi_irqs_intr,
- ahci_port_thread_fn, 0,
- pp->irq_desc, host->ports[i]);
+ rc = devm_request_irq(host->dev, irq, ahci_multi_irqs_intr_hard,
+ 0, pp->irq_desc, host->ports[i]);
+
if (rc)
return rc;
- ata_port_desc(host->ports[i], "irq %d", irq + i);
+ ata_port_desc(host->ports[i], "irq %d", irq);
}
+
return ata_host_register(host, sht);
}
@@ -2519,8 +2514,8 @@ int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)
int irq = hpriv->irq;
int rc;
- if (hpriv->flags & AHCI_HFLAG_MULTI_MSI)
- rc = ahci_host_activate_multi_irqs(host, irq, sht);
+ if (hpriv->flags & (AHCI_HFLAG_MULTI_MSI | AHCI_HFLAG_MULTI_MSIX))
+ rc = ahci_host_activate_multi_irqs(host, sht);
else if (hpriv->flags & AHCI_HFLAG_EDGE_IRQ)
rc = ata_host_activate(host, irq, ahci_single_edge_irq_intr,
IRQF_SHARED, sht);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index b79cb10..cbb7471 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -50,6 +50,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/timer.h>
+#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
#include <linux/suspend.h>
@@ -3597,7 +3598,8 @@ int sata_link_resume(struct ata_link *link, const unsigned long *params,
* immediately after resuming. Delay 200ms before
* debouncing.
*/
- ata_msleep(link->ap, 200);
+ if (!(link->flags & ATA_LFLAG_NO_DB_DELAY))
+ ata_msleep(link->ap, 200);
/* is SControl restored correctly? */
if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
@@ -6223,6 +6225,7 @@ int ata_host_activate(struct ata_host *host, int irq,
struct scsi_host_template *sht)
{
int i, rc;
+ char *irq_desc;
rc = ata_host_start(host);
if (rc)
@@ -6234,8 +6237,14 @@ int ata_host_activate(struct ata_host *host, int irq,
return ata_host_register(host, sht);
}
+ irq_desc = devm_kasprintf(host->dev, GFP_KERNEL, "%s[%s]",
+ dev_driver_string(host->dev),
+ dev_name(host->dev));
+ if (!irq_desc)
+ return -ENOMEM;
+
rc = devm_request_irq(host->dev, irq, irq_handler, irq_flags,
- dev_name(host->dev), host);
+ irq_desc, host);
if (rc)
return rc;
@@ -6697,7 +6706,12 @@ void ata_msleep(struct ata_port *ap, unsigned int msecs)
if (owns_eh)
ata_eh_release(ap);
- msleep(msecs);
+ if (msecs < 20) {
+ unsigned long usecs = msecs * USEC_PER_MSEC;
+ usleep_range(usecs, usecs + 50);
+ } else {
+ msleep(msecs);
+ }
if (owns_eh)
ata_eh_acquire(ap);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index cb0508a..961acc7 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1505,12 +1505,20 @@ static const char *ata_err_string(unsigned int err_mask)
unsigned int ata_read_log_page(struct ata_device *dev, u8 log,
u8 page, void *buf, unsigned int sectors)
{
+ unsigned long ap_flags = dev->link->ap->flags;
struct ata_taskfile tf;
unsigned int err_mask;
bool dma = false;
DPRINTK("read log page - log 0x%x, page 0x%x\n", log, page);
+ /*
+ * Return error without actually issuing the command on controllers
+ * which e.g. lockup on a read log page.
+ */
+ if (ap_flags & ATA_FLAG_NO_LOG_PAGE)
+ return AC_ERR_DEV;
+
retry:
ata_tf_init(dev, &tf);
if (dev->dma_mode && ata_id_has_read_log_dma_ext(dev->id) &&
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 8b3a786..7e959f9 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -3696,9 +3696,6 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
*/
shost->max_host_blocked = 1;
- if (scsi_init_shared_tag_map(shost, host->n_tags))
- goto err_add;
-
rc = scsi_add_host_with_dma(ap->scsi_host,
&ap->tdev, ap->host->dev);
if (rc)
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 5389579..a723ae9 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -45,7 +45,8 @@ enum {
SATA_FSL_MAX_PRD_DIRECT = 16, /* Direct PRDT entries */
SATA_FSL_HOST_FLAGS = (ATA_FLAG_SATA | ATA_FLAG_PIO_DMA |
- ATA_FLAG_PMP | ATA_FLAG_NCQ | ATA_FLAG_AN),
+ ATA_FLAG_PMP | ATA_FLAG_NCQ |
+ ATA_FLAG_AN | ATA_FLAG_NO_LOG_PAGE),
SATA_FSL_MAX_CMDS = SATA_FSL_QUEUE_DEPTH,
SATA_FSL_CMD_HDR_SIZE = 16, /* 4 DWORDS */
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index 8804127..f72d601 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -854,17 +854,14 @@ static struct of_device_id sata_rcar_match[] = {
.compatible = "renesas,sata-r8a7793",
.data = (void *)RCAR_GEN2_SATA
},
+ {
+ .compatible = "renesas,sata-r8a7795",
+ .data = (void *)RCAR_GEN2_SATA
+ },
{ },
};
MODULE_DEVICE_TABLE(of, sata_rcar_match);
-static const struct platform_device_id sata_rcar_id_table[] = {
- { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */
- { "sata-r8a7779", RCAR_GEN1_SATA },
- { },
-};
-MODULE_DEVICE_TABLE(platform, sata_rcar_id_table);
-
static int sata_rcar_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id;
@@ -884,11 +881,10 @@ static int sata_rcar_probe(struct platform_device *pdev)
return -ENOMEM;
of_id = of_match_device(sata_rcar_match, &pdev->dev);
- if (of_id)
- priv->type = (enum sata_rcar_type)of_id->data;
- else
- priv->type = platform_get_device_id(pdev)->driver_data;
+ if (!of_id)
+ return -ENODEV;
+ priv->type = (enum sata_rcar_type)of_id->data;
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(&pdev->dev, "failed to get access to sata clock\n");
@@ -1018,7 +1014,6 @@ static const struct dev_pm_ops sata_rcar_pm_ops = {
static struct platform_driver sata_rcar_driver = {
.probe = sata_rcar_probe,
.remove = sata_rcar_remove,
- .id_table = sata_rcar_id_table,
.driver = {
.name = DRV_NAME,
.of_match_table = sata_rcar_match,
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index dea6edcb..29bcff0 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -630,6 +630,9 @@ static void sil_dev_config(struct ata_device *dev)
unsigned int n, quirks = 0;
unsigned char model_num[ATA_ID_PROD_LEN + 1];
+ /* This controller doesn't support trim */
+ dev->horkage |= ATA_HORKAGE_NOTRIM;
+
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
for (n = 0; sil_blacklist[n].product; n++)
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index fab504f..48301cb 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -1396,6 +1396,8 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
addr = 0;
length = size * 1024 * 1024;
buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
+ if (!buf)
+ return 1;
while (addr < length) {
pdc20621_put_to_dimm(host, buf, addr,
ECC_ERASE_BUF_SZ);
diff --git a/drivers/base/component.c b/drivers/base/component.c
index f748430..89f5cf68 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -18,18 +18,24 @@
#include <linux/mutex.h>
#include <linux/slab.h>
+struct component;
+
+struct component_match_array {
+ void *data;
+ int (*compare)(struct device *, void *);
+ void (*release)(struct device *, void *);
+ struct component *component;
+ bool duplicate;
+};
+
struct component_match {
size_t alloc;
size_t num;
- struct {
- void *data;
- int (*fn)(struct device *, void *);
- } compare[0];
+ struct component_match_array *compare;
};
struct master {
struct list_head node;
- struct list_head components;
bool bound;
const struct component_master_ops *ops;
@@ -39,7 +45,6 @@ struct master {
struct component {
struct list_head node;
- struct list_head master_node;
struct master *master;
bool bound;
@@ -63,48 +68,21 @@ static struct master *__master_find(struct device *dev,
return NULL;
}
-/* Attach an unattached component to a master. */
-static void component_attach_master(struct master *master, struct component *c)
-{
- c->master = master;
-
- list_add_tail(&c->master_node, &master->components);
-}
-
-/* Detach a component from a master. */
-static void component_detach_master(struct master *master, struct component *c)
-{
- list_del(&c->master_node);
-
- c->master = NULL;
-}
-
-/*
- * Add a component to a master, finding the component via the compare
- * function and compare data. This is safe to call for duplicate matches
- * and will not result in the same component being added multiple times.
- */
-int component_master_add_child(struct master *master,
+static struct component *find_component(struct master *master,
int (*compare)(struct device *, void *), void *compare_data)
{
struct component *c;
- int ret = -ENXIO;
list_for_each_entry(c, &component_list, node) {
if (c->master && c->master != master)
continue;
- if (compare(c->dev, compare_data)) {
- if (!c->master)
- component_attach_master(master, c);
- ret = 0;
- break;
- }
+ if (compare(c->dev, compare_data))
+ return c;
}
- return ret;
+ return NULL;
}
-EXPORT_SYMBOL_GPL(component_master_add_child);
static int find_components(struct master *master)
{
@@ -112,39 +90,44 @@ static int find_components(struct master *master)
size_t i;
int ret = 0;
- if (!match) {
- /*
- * Search the list of components, looking for components that
- * belong to this master, and attach them to the master.
- */
- return master->ops->add_components(master->dev, master);
- }
-
/*
* Scan the array of match functions and attach
* any components which are found to this master.
*/
for (i = 0; i < match->num; i++) {
- ret = component_master_add_child(master,
- match->compare[i].fn,
- match->compare[i].data);
- if (ret)
+ struct component_match_array *mc = &match->compare[i];
+ struct component *c;
+
+ dev_dbg(master->dev, "Looking for component %zu\n", i);
+
+ if (match->compare[i].component)
+ continue;
+
+ c = find_component(master, mc->compare, mc->data);
+ if (!c) {
+ ret = -ENXIO;
break;
+ }
+
+ dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master);
+
+ /* Attach this component to the master */
+ match->compare[i].duplicate = !!c->master;
+ match->compare[i].component = c;
+ c->master = master;
}
return ret;
}
-/* Detach all attached components from this master */
-static void master_remove_components(struct master *master)
+/* Detach component from associated master */
+static void remove_component(struct master *master, struct component *c)
{
- while (!list_empty(&master->components)) {
- struct component *c = list_first_entry(&master->components,
- struct component, master_node);
-
- WARN_ON(c->master != master);
+ size_t i;
- component_detach_master(master, c);
- }
+ /* Detach the component from this master. */
+ for (i = 0; i < master->match->num; i++)
+ if (master->match->compare[i].component == c)
+ master->match->compare[i].component = NULL;
}
/*
@@ -159,44 +142,32 @@ static int try_to_bring_up_master(struct master *master,
{
int ret;
- if (master->bound)
- return 0;
+ dev_dbg(master->dev, "trying to bring up master\n");
- /*
- * Search the list of components, looking for components that
- * belong to this master, and attach them to the master.
- */
if (find_components(master)) {
- /* Failed to find all components */
- ret = 0;
- goto out;
+ dev_dbg(master->dev, "master has incomplete components\n");
+ return 0;
}
if (component && component->master != master) {
- ret = 0;
- goto out;
+ dev_dbg(master->dev, "master is not for this component (%s)\n",
+ dev_name(component->dev));
+ return 0;
}
- if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) {
- ret = -ENOMEM;
- goto out;
- }
+ if (!devres_open_group(master->dev, NULL, GFP_KERNEL))
+ return -ENOMEM;
/* Found all components */
ret = master->ops->bind(master->dev);
if (ret < 0) {
devres_release_group(master->dev, NULL);
dev_info(master->dev, "master bind failed: %d\n", ret);
- goto out;
+ return ret;
}
master->bound = true;
return 1;
-
-out:
- master_remove_components(master);
-
- return ret;
}
static int try_to_bring_up_masters(struct component *component)
@@ -205,9 +176,11 @@ static int try_to_bring_up_masters(struct component *component)
int ret = 0;
list_for_each_entry(m, &masters, node) {
- ret = try_to_bring_up_master(m, component);
- if (ret != 0)
- break;
+ if (!m->bound) {
+ ret = try_to_bring_up_master(m, component);
+ if (ret != 0)
+ break;
+ }
}
return ret;
@@ -220,45 +193,57 @@ static void take_down_master(struct master *master)
devres_release_group(master->dev, NULL);
master->bound = false;
}
+}
- master_remove_components(master);
+static void component_match_release(struct device *master,
+ struct component_match *match)
+{
+ unsigned int i;
+
+ for (i = 0; i < match->num; i++) {
+ struct component_match_array *mc = &match->compare[i];
+
+ if (mc->release)
+ mc->release(master, mc->data);
+ }
}
-static size_t component_match_size(size_t num)
+static void devm_component_match_release(struct device *dev, void *res)
{
- return offsetof(struct component_match, compare[num]);
+ component_match_release(dev, res);
}
-static struct component_match *component_match_realloc(struct device *dev,
+static int component_match_realloc(struct device *dev,
struct component_match *match, size_t num)
{
- struct component_match *new;
+ struct component_match_array *new;
- if (match && match->alloc == num)
- return match;
+ if (match->alloc == num)
+ return 0;
- new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
+ new = devm_kmalloc_array(dev, num, sizeof(*new), GFP_KERNEL);
if (!new)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
- if (match) {
- memcpy(new, match, component_match_size(min(match->num, num)));
- devm_kfree(dev, match);
- } else {
- new->num = 0;
+ if (match->compare) {
+ memcpy(new, match->compare, sizeof(*new) *
+ min(match->num, num));
+ devm_kfree(dev, match->compare);
}
+ match->compare = new;
+ match->alloc = num;
- new->alloc = num;
-
- return new;
+ return 0;
}
/*
- * Add a component to be matched.
+ * Add a component to be matched, with a release function.
*
* The match array is first created or extended if necessary.
*/
-void component_match_add(struct device *dev, struct component_match **matchptr,
+void component_match_add_release(struct device *master,
+ struct component_match **matchptr,
+ void (*release)(struct device *, void *),
int (*compare)(struct device *, void *), void *compare_data)
{
struct component_match *match = *matchptr;
@@ -266,22 +251,37 @@ void component_match_add(struct device *dev, struct component_match **matchptr,
if (IS_ERR(match))
return;
- if (!match || match->num == match->alloc) {
- size_t new_size = match ? match->alloc + 16 : 15;
+ if (!match) {
+ match = devres_alloc(devm_component_match_release,
+ sizeof(*match), GFP_KERNEL);
+ if (!match) {
+ *matchptr = ERR_PTR(-ENOMEM);
+ return;
+ }
- match = component_match_realloc(dev, match, new_size);
+ devres_add(master, match);
*matchptr = match;
+ }
+
+ if (match->num == match->alloc) {
+ size_t new_size = match ? match->alloc + 16 : 15;
+ int ret;
- if (IS_ERR(match))
+ ret = component_match_realloc(master, match, new_size);
+ if (ret) {
+ *matchptr = ERR_PTR(ret);
return;
+ }
}
- match->compare[match->num].fn = compare;
+ match->compare[match->num].compare = compare;
+ match->compare[match->num].release = release;
match->compare[match->num].data = compare_data;
+ match->compare[match->num].component = NULL;
match->num++;
}
-EXPORT_SYMBOL(component_match_add);
+EXPORT_SYMBOL(component_match_add_release);
int component_master_add_with_match(struct device *dev,
const struct component_master_ops *ops,
@@ -290,15 +290,10 @@ int component_master_add_with_match(struct device *dev,
struct master *master;
int ret;
- if (ops->add_components && match)
- return -EINVAL;
-
- if (match) {
- /* Reallocate the match array for its true size */
- match = component_match_realloc(dev, match, match->num);
- if (IS_ERR(match))
- return PTR_ERR(match);
- }
+ /* Reallocate the match array for its true size */
+ ret = component_match_realloc(dev, match, match->num);
+ if (ret)
+ return ret;
master = kzalloc(sizeof(*master), GFP_KERNEL);
if (!master)
@@ -307,7 +302,6 @@ int component_master_add_with_match(struct device *dev,
master->dev = dev;
master->ops = ops;
master->match = match;
- INIT_LIST_HEAD(&master->components);
/* Add to the list of available masters. */
mutex_lock(&component_mutex);
@@ -326,24 +320,28 @@ int component_master_add_with_match(struct device *dev,
}
EXPORT_SYMBOL_GPL(component_master_add_with_match);
-int component_master_add(struct device *dev,
- const struct component_master_ops *ops)
-{
- return component_master_add_with_match(dev, ops, NULL);
-}
-EXPORT_SYMBOL_GPL(component_master_add);
-
void component_master_del(struct device *dev,
const struct component_master_ops *ops)
{
struct master *master;
+ int i;
mutex_lock(&component_mutex);
master = __master_find(dev, ops);
if (master) {
+ struct component_match *match = master->match;
+
take_down_master(master);
list_del(&master->node);
+
+ if (match) {
+ for (i = 0; i < match->num; i++) {
+ struct component *c = match->compare[i].component;
+ if (c)
+ c->master = NULL;
+ }
+ }
kfree(master);
}
mutex_unlock(&component_mutex);
@@ -366,6 +364,7 @@ void component_unbind_all(struct device *master_dev, void *data)
{
struct master *master;
struct component *c;
+ size_t i;
WARN_ON(!mutex_is_locked(&component_mutex));
@@ -373,8 +372,12 @@ void component_unbind_all(struct device *master_dev, void *data)
if (!master)
return;
- list_for_each_entry_reverse(c, &master->components, master_node)
- component_unbind(c, master, data);
+ /* Unbind components in reverse order */
+ for (i = master->match->num; i--; )
+ if (!master->match->compare[i].duplicate) {
+ c = master->match->compare[i].component;
+ component_unbind(c, master, data);
+ }
}
EXPORT_SYMBOL_GPL(component_unbind_all);
@@ -434,6 +437,7 @@ int component_bind_all(struct device *master_dev, void *data)
{
struct master *master;
struct component *c;
+ size_t i;
int ret = 0;
WARN_ON(!mutex_is_locked(&component_mutex));
@@ -442,16 +446,21 @@ int component_bind_all(struct device *master_dev, void *data)
if (!master)
return -EINVAL;
- list_for_each_entry(c, &master->components, master_node) {
- ret = component_bind(c, master, data);
- if (ret)
- break;
- }
+ /* Bind components in match order */
+ for (i = 0; i < master->match->num; i++)
+ if (!master->match->compare[i].duplicate) {
+ c = master->match->compare[i].component;
+ ret = component_bind(c, master, data);
+ if (ret)
+ break;
+ }
if (ret != 0) {
- list_for_each_entry_continue_reverse(c, &master->components,
- master_node)
- component_unbind(c, master, data);
+ for (; i--; )
+ if (!master->match->compare[i].duplicate) {
+ c = master->match->compare[i].component;
+ component_unbind(c, master, data);
+ }
}
return ret;
@@ -499,8 +508,10 @@ void component_del(struct device *dev, const struct component_ops *ops)
break;
}
- if (component && component->master)
+ if (component && component->master) {
take_down_master(component->master);
+ remove_component(component->master, component);
+ }
mutex_unlock(&component_mutex);
diff --git a/drivers/base/devres.c b/drivers/base/devres.c
index 8754646..8fc654f 100644
--- a/drivers/base/devres.c
+++ b/drivers/base/devres.c
@@ -82,12 +82,12 @@ static struct devres_group * node_to_group(struct devres_node *node)
}
static __always_inline struct devres * alloc_dr(dr_release_t release,
- size_t size, gfp_t gfp)
+ size_t size, gfp_t gfp, int nid)
{
size_t tot_size = sizeof(struct devres) + size;
struct devres *dr;
- dr = kmalloc_track_caller(tot_size, gfp);
+ dr = kmalloc_node_track_caller(tot_size, gfp, nid);
if (unlikely(!dr))
return NULL;
@@ -106,24 +106,25 @@ static void add_dr(struct device *dev, struct devres_node *node)
}
#ifdef CONFIG_DEBUG_DEVRES
-void * __devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
+void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid,
const char *name)
{
struct devres *dr;
- dr = alloc_dr(release, size, gfp | __GFP_ZERO);
+ dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
if (unlikely(!dr))
return NULL;
set_node_dbginfo(&dr->node, name, size);
return dr->data;
}
-EXPORT_SYMBOL_GPL(__devres_alloc);
+EXPORT_SYMBOL_GPL(__devres_alloc_node);
#else
/**
* devres_alloc - Allocate device resource data
* @release: Release function devres will be associated with
* @size: Allocation size
* @gfp: Allocation flags
+ * @nid: NUMA node
*
* Allocate devres of @size bytes. The allocated area is zeroed, then
* associated with @release. The returned pointer can be passed to
@@ -132,16 +133,16 @@ EXPORT_SYMBOL_GPL(__devres_alloc);
* RETURNS:
* Pointer to allocated devres on success, NULL on failure.
*/
-void * devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+void * devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid)
{
struct devres *dr;
- dr = alloc_dr(release, size, gfp | __GFP_ZERO);
+ dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid);
if (unlikely(!dr))
return NULL;
return dr->data;
}
-EXPORT_SYMBOL_GPL(devres_alloc);
+EXPORT_SYMBOL_GPL(devres_alloc_node);
#endif
/**
@@ -776,7 +777,7 @@ void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp)
struct devres *dr;
/* use raw alloc_dr for kmalloc caller tracing */
- dr = alloc_dr(devm_kmalloc_release, size, gfp);
+ dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev));
if (unlikely(!dr))
return NULL;
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 2804aed..25425d3 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -303,6 +303,10 @@ static int memory_subsys_offline(struct device *dev)
if (mem->state == MEM_OFFLINE)
return 0;
+ /* Can't offline block with non-present sections */
+ if (mem->section_count != sections_per_block)
+ return -EINVAL;
+
return memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE);
}
diff --git a/drivers/base/platform-msi.c b/drivers/base/platform-msi.c
index 5df4575..47c4338 100644
--- a/drivers/base/platform-msi.c
+++ b/drivers/base/platform-msi.c
@@ -24,13 +24,17 @@
#include <linux/msi.h>
#include <linux/slab.h>
-#define DEV_ID_SHIFT 24
+#define DEV_ID_SHIFT 21
+#define MAX_DEV_MSIS (1 << (32 - DEV_ID_SHIFT))
/*
* Internal data structure containing a (made up, but unique) devid
* and the callback to write the MSI message.
*/
struct platform_msi_priv_data {
+ struct device *dev;
+ void *host_data;
+ msi_alloc_info_t arg;
irq_write_msi_msg_t write_msg;
int devid;
};
@@ -110,39 +114,49 @@ static void platform_msi_update_chip_ops(struct msi_domain_info *info)
chip->irq_write_msi_msg = platform_msi_write_msg;
}
-static void platform_msi_free_descs(struct device *dev)
+static void platform_msi_free_descs(struct device *dev, int base, int nvec)
{
struct msi_desc *desc, *tmp;
list_for_each_entry_safe(desc, tmp, dev_to_msi_list(dev), list) {
- list_del(&desc->list);
- free_msi_entry(desc);
+ if (desc->platform.msi_index >= base &&
+ desc->platform.msi_index < (base + nvec)) {
+ list_del(&desc->list);
+ free_msi_entry(desc);
+ }
}
}
-static int platform_msi_alloc_descs(struct device *dev, int nvec,
- struct platform_msi_priv_data *data)
+static int platform_msi_alloc_descs_with_irq(struct device *dev, int virq,
+ int nvec,
+ struct platform_msi_priv_data *data)
{
- int i;
+ struct msi_desc *desc;
+ int i, base = 0;
- for (i = 0; i < nvec; i++) {
- struct msi_desc *desc;
+ if (!list_empty(dev_to_msi_list(dev))) {
+ desc = list_last_entry(dev_to_msi_list(dev),
+ struct msi_desc, list);
+ base = desc->platform.msi_index + 1;
+ }
+ for (i = 0; i < nvec; i++) {
desc = alloc_msi_entry(dev);
if (!desc)
break;
desc->platform.msi_priv_data = data;
- desc->platform.msi_index = i;
+ desc->platform.msi_index = base + i;
desc->nvec_used = 1;
+ desc->irq = virq ? virq + i : 0;
list_add_tail(&desc->list, dev_to_msi_list(dev));
}
if (i != nvec) {
/* Clean up the mess */
- platform_msi_free_descs(dev);
+ platform_msi_free_descs(dev, base, nvec);
return -ENOMEM;
}
@@ -150,6 +164,13 @@ static int platform_msi_alloc_descs(struct device *dev, int nvec,
return 0;
}
+static int platform_msi_alloc_descs(struct device *dev, int nvec,
+ struct platform_msi_priv_data *data)
+
+{
+ return platform_msi_alloc_descs_with_irq(dev, 0, nvec, data);
+}
+
/**
* platform_msi_create_irq_domain - Create a platform MSI interrupt domain
* @fwnode: Optional fwnode of the interrupt controller
@@ -180,56 +201,75 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
return domain;
}
-/**
- * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
- * @dev: The device for which to allocate interrupts
- * @nvec: The number of interrupts to allocate
- * @write_msi_msg: Callback to write an interrupt message for @dev
- *
- * Returns:
- * Zero for success, or an error code in case of failure
- */
-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
- irq_write_msi_msg_t write_msi_msg)
+static struct platform_msi_priv_data *
+platform_msi_alloc_priv_data(struct device *dev, unsigned int nvec,
+ irq_write_msi_msg_t write_msi_msg)
{
- struct platform_msi_priv_data *priv_data;
- int err;
-
+ struct platform_msi_priv_data *datap;
/*
* Limit the number of interrupts to 256 per device. Should we
* need to bump this up, DEV_ID_SHIFT should be adjusted
* accordingly (which would impact the max number of MSI
* capable devices).
*/
- if (!dev->msi_domain || !write_msi_msg || !nvec ||
- nvec > (1 << (32 - DEV_ID_SHIFT)))
- return -EINVAL;
+ if (!dev->msi_domain || !write_msi_msg || !nvec || nvec > MAX_DEV_MSIS)
+ return ERR_PTR(-EINVAL);
if (dev->msi_domain->bus_token != DOMAIN_BUS_PLATFORM_MSI) {
dev_err(dev, "Incompatible msi_domain, giving up\n");
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
/* Already had a helping of MSI? Greed... */
if (!list_empty(dev_to_msi_list(dev)))
- return -EBUSY;
+ return ERR_PTR(-EBUSY);
+
+ datap = kzalloc(sizeof(*datap), GFP_KERNEL);
+ if (!datap)
+ return ERR_PTR(-ENOMEM);
+
+ datap->devid = ida_simple_get(&platform_msi_devid_ida,
+ 0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
+ if (datap->devid < 0) {
+ int err = datap->devid;
+ kfree(datap);
+ return ERR_PTR(err);
+ }
- priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
- if (!priv_data)
- return -ENOMEM;
+ datap->write_msg = write_msi_msg;
+ datap->dev = dev;
- priv_data->devid = ida_simple_get(&platform_msi_devid_ida,
- 0, 1 << DEV_ID_SHIFT, GFP_KERNEL);
- if (priv_data->devid < 0) {
- err = priv_data->devid;
- goto out_free_data;
- }
+ return datap;
+}
+
+static void platform_msi_free_priv_data(struct platform_msi_priv_data *data)
+{
+ ida_simple_remove(&platform_msi_devid_ida, data->devid);
+ kfree(data);
+}
+
+/**
+ * platform_msi_domain_alloc_irqs - Allocate MSI interrupts for @dev
+ * @dev: The device for which to allocate interrupts
+ * @nvec: The number of interrupts to allocate
+ * @write_msi_msg: Callback to write an interrupt message for @dev
+ *
+ * Returns:
+ * Zero for success, or an error code in case of failure
+ */
+int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
+ irq_write_msi_msg_t write_msi_msg)
+{
+ struct platform_msi_priv_data *priv_data;
+ int err;
- priv_data->write_msg = write_msi_msg;
+ priv_data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
+ if (IS_ERR(priv_data))
+ return PTR_ERR(priv_data);
err = platform_msi_alloc_descs(dev, nvec, priv_data);
if (err)
- goto out_free_id;
+ goto out_free_priv_data;
err = msi_domain_alloc_irqs(dev->msi_domain, dev, nvec);
if (err)
@@ -238,11 +278,9 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
return 0;
out_free_desc:
- platform_msi_free_descs(dev);
-out_free_id:
- ida_simple_remove(&platform_msi_devid_ida, priv_data->devid);
-out_free_data:
- kfree(priv_data);
+ platform_msi_free_descs(dev, 0, nvec);
+out_free_priv_data:
+ platform_msi_free_priv_data(priv_data);
return err;
}
@@ -253,18 +291,126 @@ out_free_data:
*/
void platform_msi_domain_free_irqs(struct device *dev)
{
- struct msi_desc *desc;
+ if (!list_empty(dev_to_msi_list(dev))) {
+ struct msi_desc *desc;
+
+ desc = first_msi_entry(dev);
+ platform_msi_free_priv_data(desc->platform.msi_priv_data);
+ }
+
+ msi_domain_free_irqs(dev->msi_domain, dev);
+ platform_msi_free_descs(dev, 0, MAX_DEV_MSIS);
+}
+
+/**
+ * platform_msi_get_host_data - Query the private data associated with
+ * a platform-msi domain
+ * @domain: The platform-msi domain
+ *
+ * Returns the private data provided when calling
+ * platform_msi_create_device_domain.
+ */
+void *platform_msi_get_host_data(struct irq_domain *domain)
+{
+ struct platform_msi_priv_data *data = domain->host_data;
+ return data->host_data;
+}
+
+/**
+ * platform_msi_create_device_domain - Create a platform-msi domain
+ *
+ * @dev: The device generating the MSIs
+ * @nvec: The number of MSIs that need to be allocated
+ * @write_msi_msg: Callback to write an interrupt message for @dev
+ * @ops: The hierarchy domain operations to use
+ * @host_data: Private data associated to this domain
+ *
+ * Returns an irqdomain for @nvec interrupts
+ */
+struct irq_domain *
+platform_msi_create_device_domain(struct device *dev,
+ unsigned int nvec,
+ irq_write_msi_msg_t write_msi_msg,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct platform_msi_priv_data *data;
+ struct irq_domain *domain;
+ int err;
+
+ data = platform_msi_alloc_priv_data(dev, nvec, write_msi_msg);
+ if (IS_ERR(data))
+ return NULL;
+
+ data->host_data = host_data;
+ domain = irq_domain_create_hierarchy(dev->msi_domain, 0, nvec,
+ of_node_to_fwnode(dev->of_node),
+ ops, data);
+ if (!domain)
+ goto free_priv;
- desc = first_msi_entry(dev);
- if (desc) {
- struct platform_msi_priv_data *data;
+ err = msi_domain_prepare_irqs(domain->parent, dev, nvec, &data->arg);
+ if (err)
+ goto free_domain;
+
+ return domain;
- data = desc->platform.msi_priv_data;
+free_domain:
+ irq_domain_remove(domain);
+free_priv:
+ platform_msi_free_priv_data(data);
+ return NULL;
+}
+
+/**
+ * platform_msi_domain_free - Free interrupts associated with a platform-msi
+ * domain
+ *
+ * @domain: The platform-msi domain
+ * @virq: The base irq from which to perform the free operation
+ * @nvec: How many interrupts to free from @virq
+ */
+void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nvec)
+{
+ struct platform_msi_priv_data *data = domain->host_data;
+ struct msi_desc *desc;
+ for_each_msi_entry(desc, data->dev) {
+ if (WARN_ON(!desc->irq || desc->nvec_used != 1))
+ return;
+ if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+ continue;
- ida_simple_remove(&platform_msi_devid_ida, data->devid);
- kfree(data);
+ irq_domain_free_irqs_common(domain, desc->irq, 1);
}
+}
- msi_domain_free_irqs(dev->msi_domain, dev);
- platform_msi_free_descs(dev);
+/**
+ * platform_msi_domain_alloc - Allocate interrupts associated with
+ * a platform-msi domain
+ *
+ * @domain: The platform-msi domain
+ * @virq: The base irq from which to perform the allocate operation
+ * @nvec: How many interrupts to free from @virq
+ *
+ * Return 0 on success, or an error code on failure. Must be called
+ * with irq_domain_mutex held (which can only be done as part of a
+ * top-level interrupt allocation).
+ */
+int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct platform_msi_priv_data *data = domain->host_data;
+ int err;
+
+ err = platform_msi_alloc_descs_with_irq(data->dev, virq, nr_irqs, data);
+ if (err)
+ return err;
+
+ err = msi_domain_populate_irqs(domain->parent, data->dev,
+ virq, nr_irqs, &data->arg);
+ if (err)
+ platform_msi_domain_free(domain, virq, nr_irqs);
+
+ return err;
}
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 1dd6d3b..73e3994 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -117,6 +117,26 @@ int platform_get_irq(struct platform_device *dev, unsigned int num)
EXPORT_SYMBOL_GPL(platform_get_irq);
/**
+ * platform_irq_count - Count the number of IRQs a platform device uses
+ * @dev: platform device
+ *
+ * Return: Number of IRQs a platform device uses or EPROBE_DEFER
+ */
+int platform_irq_count(struct platform_device *dev)
+{
+ int ret, nr = 0;
+
+ while ((ret = platform_get_irq(dev, nr)) >= 0)
+ nr++;
+
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ return nr;
+}
+EXPORT_SYMBOL_GPL(platform_irq_count);
+
+/**
* platform_get_resource_byname - get a resource for a device by name
* @dev: platform device
* @type: resource type
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index fd0973b..60ee559 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -93,7 +93,7 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
return -ENOMEM;
}
} else {
- if (IS_ERR(clk) || !__clk_get(clk)) {
+ if (IS_ERR(clk)) {
kfree(ce);
return -ENOENT;
}
@@ -127,7 +127,9 @@ int pm_clk_add(struct device *dev, const char *con_id)
* @clk: Clock pointer
*
* Add the clock to the list of clocks used for the power management of @dev.
- * It will increment refcount on clock pointer, use clk_put() on it when done.
+ * The power-management code will take control of the clock reference, so
+ * callers should not call clk_put() on @clk after this function sucessfully
+ * returned.
*/
int pm_clk_add_clk(struct device *dev, struct clk *clk)
{
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 80e2988..65f50ec 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -321,8 +321,7 @@ static int genpd_poweroff(struct generic_pm_domain *genpd, bool is_async)
if (stat > PM_QOS_FLAGS_NONE)
return -EBUSY;
- if (pdd->dev->driver && (!pm_runtime_suspended(pdd->dev)
- || pdd->dev->power.irq_safe))
+ if (!pm_runtime_suspended(pdd->dev) || pdd->dev->power.irq_safe)
not_suspended++;
}
@@ -391,6 +390,7 @@ static int pm_genpd_runtime_suspend(struct device *dev)
struct generic_pm_domain *genpd;
bool (*stop_ok)(struct device *__dev);
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
int ret;
@@ -401,12 +401,19 @@ static int pm_genpd_runtime_suspend(struct device *dev)
if (IS_ERR(genpd))
return -EINVAL;
+ /*
+ * A runtime PM centric subsystem/driver may re-use the runtime PM
+ * callbacks for other purposes than runtime PM. In those scenarios
+ * runtime PM is disabled. Under these circumstances, we shall skip
+ * validating/measuring the PM QoS latency.
+ */
stop_ok = genpd->gov ? genpd->gov->stop_ok : NULL;
- if (stop_ok && !stop_ok(dev))
+ if (runtime_pm && stop_ok && !stop_ok(dev))
return -EBUSY;
/* Measure suspend latency. */
- time_start = ktime_get();
+ if (runtime_pm)
+ time_start = ktime_get();
ret = genpd_save_dev(genpd, dev);
if (ret)
@@ -419,13 +426,15 @@ static int pm_genpd_runtime_suspend(struct device *dev)
}
/* Update suspend latency value if the measured time exceeds it. */
- elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns > td->suspend_latency_ns) {
- td->suspend_latency_ns = elapsed_ns;
- dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
- elapsed_ns);
- genpd->max_off_time_changed = true;
- td->constraint_changed = true;
+ if (runtime_pm) {
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns > td->suspend_latency_ns) {
+ td->suspend_latency_ns = elapsed_ns;
+ dev_dbg(dev, "suspend latency exceeded, %lld ns\n",
+ elapsed_ns);
+ genpd->max_off_time_changed = true;
+ td->constraint_changed = true;
+ }
}
/*
@@ -454,6 +463,7 @@ static int pm_genpd_runtime_resume(struct device *dev)
{
struct generic_pm_domain *genpd;
struct gpd_timing_data *td = &dev_gpd_data(dev)->td;
+ bool runtime_pm = pm_runtime_enabled(dev);
ktime_t time_start;
s64 elapsed_ns;
int ret;
@@ -480,14 +490,14 @@ static int pm_genpd_runtime_resume(struct device *dev)
out:
/* Measure resume latency. */
- if (timed)
+ if (timed && runtime_pm)
time_start = ktime_get();
genpd_start_dev(genpd, dev);
genpd_restore_dev(genpd, dev);
/* Update resume latency value if the measured time exceeds it. */
- if (timed) {
+ if (timed && runtime_pm) {
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
if (elapsed_ns > td->resume_latency_ns) {
td->resume_latency_ns = elapsed_ns;
@@ -1312,13 +1322,17 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
struct generic_pm_domain *subdomain)
{
- struct gpd_link *link;
+ struct gpd_link *link, *itr;
int ret = 0;
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain)
|| genpd == subdomain)
return -EINVAL;
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+
mutex_lock(&genpd->lock);
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
@@ -1328,18 +1342,13 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
goto out;
}
- list_for_each_entry(link, &genpd->master_links, master_node) {
- if (link->slave == subdomain && link->master == genpd) {
+ list_for_each_entry(itr, &genpd->master_links, master_node) {
+ if (itr->slave == subdomain && itr->master == genpd) {
ret = -EINVAL;
goto out;
}
}
- link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link) {
- ret = -ENOMEM;
- goto out;
- }
link->master = genpd;
list_add_tail(&link->master_node, &genpd->master_links);
link->slave = subdomain;
@@ -1350,7 +1359,8 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
out:
mutex_unlock(&subdomain->lock);
mutex_unlock(&genpd->lock);
-
+ if (ret)
+ kfree(link);
return ret;
}
EXPORT_SYMBOL_GPL(pm_genpd_add_subdomain);
@@ -1776,10 +1786,10 @@ int genpd_dev_pm_attach(struct device *dev)
}
pd = of_genpd_get_from_provider(&pd_args);
+ of_node_put(pd_args.np);
if (IS_ERR(pd)) {
dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
__func__, PTR_ERR(pd));
- of_node_put(dev->of_node);
return -EPROBE_DEFER;
}
@@ -1797,7 +1807,6 @@ int genpd_dev_pm_attach(struct device *dev)
if (ret < 0) {
dev_err(dev, "failed to add to PM domain %s: %d",
pd->name, ret);
- of_node_put(dev->of_node);
goto out;
}
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index e60dd12..1e937ac 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -160,9 +160,6 @@ static bool default_power_down_ok(struct dev_pm_domain *pd)
struct gpd_timing_data *td;
s64 constraint_ns;
- if (!pdd->dev->driver)
- continue;
-
/*
* Check if the device is allowed to be off long enough for the
* domain to turn off and on (that's how much time it will
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index d5c1149..b8e76f7 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -11,6 +11,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/slab.h>
@@ -27,7 +29,7 @@
*/
static LIST_HEAD(dev_opp_list);
/* Lock to allow exclusive modification to the device and opp lists */
-static DEFINE_MUTEX(dev_opp_list_lock);
+DEFINE_MUTEX(dev_opp_list_lock);
#define opp_rcu_lockdep_assert() \
do { \
@@ -79,14 +81,18 @@ static struct device_opp *_managed_opp(const struct device_node *np)
* Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
* -EINVAL based on type of error.
*
- * Locking: This function must be called under rcu_read_lock(). device_opp
- * is a RCU protected pointer. This means that device_opp is valid as long
- * as we are under RCU lock.
+ * Locking: For readers, this function must be called under rcu_read_lock().
+ * device_opp is a RCU protected pointer, which means that device_opp is valid
+ * as long as we are under RCU lock.
+ *
+ * For Writers, this function must be called with dev_opp_list_lock held.
*/
struct device_opp *_find_device_opp(struct device *dev)
{
struct device_opp *dev_opp;
+ opp_rcu_lockdep_assert();
+
if (IS_ERR_OR_NULL(dev)) {
pr_err("%s: Invalid parameters\n", __func__);
return ERR_PTR(-EINVAL);
@@ -100,7 +106,7 @@ struct device_opp *_find_device_opp(struct device *dev)
}
/**
- * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp
+ * dev_pm_opp_get_voltage() - Gets the voltage corresponding to an opp
* @opp: opp for which voltage has to be returned for
*
* Return: voltage in micro volt corresponding to the opp, else
@@ -122,7 +128,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
opp_rcu_lockdep_assert();
tmp_opp = rcu_dereference(opp);
- if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available)
+ if (IS_ERR_OR_NULL(tmp_opp))
pr_err("%s: Invalid parameters\n", __func__);
else
v = tmp_opp->u_volt;
@@ -701,7 +707,7 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
}
/**
- * _opp_add_dynamic() - Allocate a dynamic OPP.
+ * _opp_add_v1() - Allocate a OPP based on v1 bindings.
* @dev: device for which we do this operation
* @freq: Frequency in Hz for this OPP
* @u_volt: Voltage in uVolts for this OPP
@@ -727,8 +733,8 @@ static int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
* Duplicate OPPs (both freq and volt are same) and !opp->available
* -ENOMEM Memory allocation failure
*/
-static int _opp_add_dynamic(struct device *dev, unsigned long freq,
- long u_volt, bool dynamic)
+static int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
+ bool dynamic)
{
struct device_opp *dev_opp;
struct dev_pm_opp *new_opp;
@@ -770,9 +776,10 @@ unlock:
}
/* TODO: Support multiple regulators */
-static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev)
+static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev)
{
u32 microvolt[3] = {0};
+ u32 val;
int count, ret;
/* Missing property isn't a problem, but an invalid entry is */
@@ -805,6 +812,9 @@ static int opp_get_microvolt(struct dev_pm_opp *opp, struct device *dev)
opp->u_volt_min = microvolt[1];
opp->u_volt_max = microvolt[2];
+ if (!of_property_read_u32(opp->np, "opp-microamp", &val))
+ opp->u_amp = val;
+
return 0;
}
@@ -869,13 +879,10 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
if (!of_property_read_u32(np, "clock-latency-ns", &val))
new_opp->clock_latency_ns = val;
- ret = opp_get_microvolt(new_opp, dev);
+ ret = opp_parse_supplies(new_opp, dev);
if (ret)
goto free_opp;
- if (!of_property_read_u32(new_opp->np, "opp-microamp", &val))
- new_opp->u_amp = val;
-
ret = _opp_add(dev, new_opp, dev_opp);
if (ret)
goto free_opp;
@@ -939,7 +946,7 @@ unlock:
*/
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
{
- return _opp_add_dynamic(dev, freq, u_volt, true);
+ return _opp_add_v1(dev, freq, u_volt, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
@@ -1172,13 +1179,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
struct device_opp *dev_opp;
int ret = 0, count = 0;
+ mutex_lock(&dev_opp_list_lock);
+
dev_opp = _managed_opp(opp_np);
if (dev_opp) {
/* OPPs are already managed */
if (!_add_list_dev(dev, dev_opp))
ret = -ENOMEM;
+ mutex_unlock(&dev_opp_list_lock);
return ret;
}
+ mutex_unlock(&dev_opp_list_lock);
/* We have opp-list node now, iterate over it and add OPPs */
for_each_available_child_of_node(opp_np, np) {
@@ -1196,15 +1207,20 @@ static int _of_add_opp_table_v2(struct device *dev, struct device_node *opp_np)
if (WARN_ON(!count))
return -ENOENT;
+ mutex_lock(&dev_opp_list_lock);
+
dev_opp = _find_device_opp(dev);
if (WARN_ON(IS_ERR(dev_opp))) {
ret = PTR_ERR(dev_opp);
+ mutex_unlock(&dev_opp_list_lock);
goto free_table;
}
dev_opp->np = opp_np;
dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared");
+ mutex_unlock(&dev_opp_list_lock);
+
return 0;
free_table:
@@ -1241,7 +1257,7 @@ static int _of_add_opp_table_v1(struct device *dev)
unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++);
- if (_opp_add_dynamic(dev, freq, volt, false))
+ if (_opp_add_v1(dev, freq, volt, false))
dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq);
nr -= 2;
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c
index 7654c56..7b445e8 100644
--- a/drivers/base/power/opp/cpu.c
+++ b/drivers/base/power/opp/cpu.c
@@ -10,6 +10,9 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/cpu.h>
#include <linux/cpufreq.h>
#include <linux/err.h>
@@ -124,12 +127,12 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
struct device *dev;
int cpu, ret = 0;
- rcu_read_lock();
+ mutex_lock(&dev_opp_list_lock);
dev_opp = _find_device_opp(cpu_dev);
if (IS_ERR(dev_opp)) {
ret = -EINVAL;
- goto out_rcu_read_unlock;
+ goto unlock;
}
for_each_cpu(cpu, cpumask) {
@@ -150,10 +153,10 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, cpumask_var_t cpumask)
continue;
}
}
-out_rcu_read_unlock:
- rcu_read_unlock();
+unlock:
+ mutex_unlock(&dev_opp_list_lock);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_set_sharing_cpus);
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index dcb38f7..7366b2a 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -21,6 +21,9 @@
#include <linux/rculist.h>
#include <linux/rcupdate.h>
+/* Lock to allow exclusive modification to the device and opp lists */
+extern struct mutex dev_opp_list_lock;
+
/*
* Internal data structure organization with the OPP layer library is as
* follows:
diff --git a/drivers/base/power/wakeirq.c b/drivers/base/power/wakeirq.c
index eb6e674..0d77cd6 100644
--- a/drivers/base/power/wakeirq.c
+++ b/drivers/base/power/wakeirq.c
@@ -68,6 +68,9 @@ int dev_pm_set_wake_irq(struct device *dev, int irq)
struct wake_irq *wirq;
int err;
+ if (irq < 0)
+ return -EINVAL;
+
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
if (!wirq)
return -ENOMEM;
@@ -167,6 +170,9 @@ int dev_pm_set_dedicated_wake_irq(struct device *dev, int irq)
struct wake_irq *wirq;
int err;
+ if (irq < 0)
+ return -EINVAL;
+
wirq = kzalloc(sizeof(*wirq), GFP_KERNEL);
if (!wirq)
return -ENOMEM;
diff --git a/drivers/base/property.c b/drivers/base/property.c
index de40623..1325ff2 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -598,18 +598,34 @@ unsigned int device_get_child_node_count(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_get_child_node_count);
-bool device_dma_is_coherent(struct device *dev)
+bool device_dma_supported(struct device *dev)
{
- bool coherent = false;
-
+ /* For DT, this is always supported.
+ * For ACPI, this depends on CCA, which
+ * is determined by the acpi_dma_supported().
+ */
if (IS_ENABLED(CONFIG_OF) && dev->of_node)
- coherent = of_dma_is_coherent(dev->of_node);
- else
- acpi_check_dma(ACPI_COMPANION(dev), &coherent);
+ return true;
+
+ return acpi_dma_supported(ACPI_COMPANION(dev));
+}
+EXPORT_SYMBOL_GPL(device_dma_supported);
- return coherent;
+enum dev_dma_attr device_get_dma_attr(struct device *dev)
+{
+ enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED;
+
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ if (of_dma_is_coherent(dev->of_node))
+ attr = DEV_DMA_COHERENT;
+ else
+ attr = DEV_DMA_NON_COHERENT;
+ } else
+ attr = acpi_get_dma_attr(ACPI_COMPANION(dev));
+
+ return attr;
}
-EXPORT_SYMBOL_GPL(device_dma_is_coherent);
+EXPORT_SYMBOL_GPL(device_get_dma_attr);
/**
* device_get_phy_mode - Get phy mode for given device
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
index 0246f44..686c9e0 100644
--- a/drivers/base/regmap/regcache-flat.c
+++ b/drivers/base/regmap/regcache-flat.c
@@ -21,7 +21,7 @@ static int regcache_flat_init(struct regmap *map)
int i;
unsigned int *cache;
- map->cache = kzalloc(sizeof(unsigned int) * (map->max_register + 1),
+ map->cache = kcalloc(map->max_register + 1, sizeof(unsigned int),
GFP_KERNEL);
if (!map->cache)
return -ENOMEM;
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index 736e0d3..6f77d73 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -139,7 +139,7 @@ static int regcache_lzo_init(struct regmap *map)
ret = 0;
blkcount = regcache_lzo_block_count(map);
- map->cache = kzalloc(blkcount * sizeof *lzo_blocks,
+ map->cache = kcalloc(blkcount, sizeof(*lzo_blocks),
GFP_KERNEL);
if (!map->cache)
return -ENOMEM;
@@ -152,8 +152,8 @@ static int regcache_lzo_init(struct regmap *map)
* that register.
*/
bmp_size = map->num_reg_defaults_raw;
- sync_bmp = kmalloc(BITS_TO_LONGS(bmp_size) * sizeof(long),
- GFP_KERNEL);
+ sync_bmp = kmalloc_array(BITS_TO_LONGS(bmp_size), sizeof(long),
+ GFP_KERNEL);
if (!sync_bmp) {
ret = -ENOMEM;
goto err;
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index 56486d9..aa56af8 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -361,13 +361,14 @@ regcache_rbtree_node_alloc(struct regmap *map, unsigned int reg)
rbnode->base_reg = reg;
}
- rbnode->block = kmalloc(rbnode->blklen * map->cache_word_size,
- GFP_KERNEL);
+ rbnode->block = kmalloc_array(rbnode->blklen, map->cache_word_size,
+ GFP_KERNEL);
if (!rbnode->block)
goto err_free;
- rbnode->cache_present = kzalloc(BITS_TO_LONGS(rbnode->blklen) *
- sizeof(*rbnode->cache_present), GFP_KERNEL);
+ rbnode->cache_present = kcalloc(BITS_TO_LONGS(rbnode->blklen),
+ sizeof(*rbnode->cache_present),
+ GFP_KERNEL);
if (!rbnode->cache_present)
goto err_free_block;
@@ -413,8 +414,8 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
max = reg + max_dist;
/* look for an adjacent register to the one we are about to add */
- for (node = rb_first(&rbtree_ctx->root); node;
- node = rb_next(node)) {
+ node = rbtree_ctx->root.rb_node;
+ while (node) {
rbnode_tmp = rb_entry(node, struct regcache_rbtree_node,
node);
@@ -425,6 +426,11 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg,
new_base_reg = min(reg, base_reg);
new_top_reg = max(reg, top_reg);
} else {
+ if (max < base_reg)
+ node = node->rb_left;
+ else
+ node = node->rb_right;
+
continue;
}
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index 4c07802..348be3a 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -100,15 +100,25 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
int i;
void *tmp_buf;
- for (i = 0; i < config->num_reg_defaults; i++)
- if (config->reg_defaults[i].reg % map->reg_stride)
- return -EINVAL;
-
if (map->cache_type == REGCACHE_NONE) {
+ if (config->reg_defaults || config->num_reg_defaults_raw)
+ dev_warn(map->dev,
+ "No cache used with register defaults set!\n");
+
map->cache_bypass = true;
return 0;
}
+ if (config->reg_defaults && !config->num_reg_defaults) {
+ dev_err(map->dev,
+ "Register defaults are set without the number!\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < config->num_reg_defaults; i++)
+ if (config->reg_defaults[i].reg % map->reg_stride)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(cache_types); i++)
if (cache_types[i]->type == map->cache_type)
break;
@@ -138,8 +148,6 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
* a copy of it.
*/
if (config->reg_defaults) {
- if (!map->num_reg_defaults)
- return -EINVAL;
tmp_buf = kmemdup(config->reg_defaults, map->num_reg_defaults *
sizeof(struct reg_default), GFP_KERNEL);
if (!tmp_buf)
@@ -535,19 +543,30 @@ bool regcache_set_val(struct regmap *map, void *base, unsigned int idx,
switch (map->cache_word_size) {
case 1: {
u8 *cache = base;
+
cache[idx] = val;
break;
}
case 2: {
u16 *cache = base;
+
cache[idx] = val;
break;
}
case 4: {
u32 *cache = base;
+
+ cache[idx] = val;
+ break;
+ }
+#ifdef CONFIG_64BIT
+ case 8: {
+ u64 *cache = base;
+
cache[idx] = val;
break;
}
+#endif
default:
BUG();
}
@@ -568,16 +587,26 @@ unsigned int regcache_get_val(struct regmap *map, const void *base,
switch (map->cache_word_size) {
case 1: {
const u8 *cache = base;
+
return cache[idx];
}
case 2: {
const u16 *cache = base;
+
return cache[idx];
}
case 4: {
const u32 *cache = base;
+
+ return cache[idx];
+ }
+#ifdef CONFIG_64BIT
+ case 8: {
+ const u64 *cache = base;
+
return cache[idx];
}
+#endif
default:
BUG();
}
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 3f0a7e2..1ee3d40 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -397,72 +397,39 @@ static const struct file_operations regmap_reg_ranges_fops = {
.llseek = default_llseek,
};
-static ssize_t regmap_access_read_file(struct file *file,
- char __user *user_buf, size_t count,
- loff_t *ppos)
+static int regmap_access_show(struct seq_file *s, void *ignored)
{
- int reg_len, tot_len;
- size_t buf_pos = 0;
- loff_t p = 0;
- ssize_t ret;
- int i;
- struct regmap *map = file->private_data;
- char *buf;
-
- if (*ppos < 0 || !count)
- return -EINVAL;
+ struct regmap *map = s->private;
+ int i, reg_len;
- buf = kmalloc(count, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /* Calculate the length of a fixed format */
reg_len = regmap_calc_reg_len(map->max_register);
- tot_len = reg_len + 10; /* ': R W V P\n' */
for (i = 0; i <= map->max_register; i += map->reg_stride) {
/* Ignore registers which are neither readable nor writable */
if (!regmap_readable(map, i) && !regmap_writeable(map, i))
continue;
- /* If we're in the region the user is trying to read */
- if (p >= *ppos) {
- /* ...but not beyond it */
- if (buf_pos + tot_len + 1 >= count)
- break;
-
- /* Format the register */
- snprintf(buf + buf_pos, count - buf_pos,
- "%.*x: %c %c %c %c\n",
- reg_len, i,
- regmap_readable(map, i) ? 'y' : 'n',
- regmap_writeable(map, i) ? 'y' : 'n',
- regmap_volatile(map, i) ? 'y' : 'n',
- regmap_precious(map, i) ? 'y' : 'n');
-
- buf_pos += tot_len;
- }
- p += tot_len;
- }
-
- ret = buf_pos;
-
- if (copy_to_user(user_buf, buf, buf_pos)) {
- ret = -EFAULT;
- goto out;
+ /* Format the register */
+ seq_printf(s, "%.*x: %c %c %c %c\n", reg_len, i,
+ regmap_readable(map, i) ? 'y' : 'n',
+ regmap_writeable(map, i) ? 'y' : 'n',
+ regmap_volatile(map, i) ? 'y' : 'n',
+ regmap_precious(map, i) ? 'y' : 'n');
}
- *ppos += buf_pos;
+ return 0;
+}
-out:
- kfree(buf);
- return ret;
+static int access_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, regmap_access_show, inode->i_private);
}
static const struct file_operations regmap_access_fops = {
- .open = simple_open,
- .read = regmap_access_read_file,
- .llseek = default_llseek,
+ .open = access_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
};
static ssize_t regmap_cache_only_write_file(struct file *file,
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index 8d16db5..9b0d202 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -39,8 +39,11 @@ struct regmap_irq_chip_data {
unsigned int *mask_buf;
unsigned int *mask_buf_def;
unsigned int *wake_buf;
+ unsigned int *type_buf;
+ unsigned int *type_buf_def;
unsigned int irq_reg_stride;
+ unsigned int type_reg_stride;
};
static inline const
@@ -144,6 +147,22 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
}
}
+ for (i = 0; i < d->chip->num_type_reg; i++) {
+ if (!d->type_buf_def[i])
+ continue;
+ reg = d->chip->type_base +
+ (i * map->reg_stride * d->type_reg_stride);
+ if (d->chip->type_invert)
+ ret = regmap_update_bits(d->map, reg,
+ d->type_buf_def[i], ~d->type_buf[i]);
+ else
+ ret = regmap_update_bits(d->map, reg,
+ d->type_buf_def[i], d->type_buf[i]);
+ if (ret != 0)
+ dev_err(d->map->dev, "Failed to sync type in %x\n",
+ reg);
+ }
+
if (d->chip->runtime_pm)
pm_runtime_put(map->dev);
@@ -178,6 +197,38 @@ static void regmap_irq_disable(struct irq_data *data)
d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
}
+static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
+{
+ struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
+ struct regmap *map = d->map;
+ const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
+ int reg = irq_data->type_reg_offset / map->reg_stride;
+
+ if (!(irq_data->type_rising_mask | irq_data->type_falling_mask))
+ return 0;
+
+ d->type_buf[reg] &= ~(irq_data->type_falling_mask |
+ irq_data->type_rising_mask);
+ switch (type) {
+ case IRQ_TYPE_EDGE_FALLING:
+ d->type_buf[reg] |= irq_data->type_falling_mask;
+ break;
+
+ case IRQ_TYPE_EDGE_RISING:
+ d->type_buf[reg] |= irq_data->type_rising_mask;
+ break;
+
+ case IRQ_TYPE_EDGE_BOTH:
+ d->type_buf[reg] |= (irq_data->type_falling_mask |
+ irq_data->type_rising_mask);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int regmap_irq_set_wake(struct irq_data *data, unsigned int on)
{
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
@@ -204,6 +255,7 @@ static const struct irq_chip regmap_irq_chip = {
.irq_bus_sync_unlock = regmap_irq_sync_unlock,
.irq_disable = regmap_irq_disable,
.irq_enable = regmap_irq_enable,
+ .irq_set_type = regmap_irq_set_type,
.irq_set_wake = regmap_irq_set_wake,
};
@@ -386,28 +438,40 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d)
return -ENOMEM;
- d->status_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+ d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->status_buf)
goto err_alloc;
- d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+ d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf)
goto err_alloc;
- d->mask_buf_def = kzalloc(sizeof(unsigned int) * chip->num_regs,
+ d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->mask_buf_def)
goto err_alloc;
if (chip->wake_base) {
- d->wake_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
+ d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
GFP_KERNEL);
if (!d->wake_buf)
goto err_alloc;
}
+ if (chip->num_type_reg) {
+ d->type_buf_def = kcalloc(chip->num_type_reg,
+ sizeof(unsigned int), GFP_KERNEL);
+ if (!d->type_buf_def)
+ goto err_alloc;
+
+ d->type_buf = kcalloc(chip->num_type_reg, sizeof(unsigned int),
+ GFP_KERNEL);
+ if (!d->type_buf)
+ goto err_alloc;
+ }
+
d->irq_chip = regmap_irq_chip;
d->irq_chip.name = chip->name;
d->irq = irq;
@@ -420,10 +484,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
else
d->irq_reg_stride = 1;
+ if (chip->type_reg_stride)
+ d->type_reg_stride = chip->type_reg_stride;
+ else
+ d->type_reg_stride = 1;
+
if (!map->use_single_read && map->reg_stride == 1 &&
d->irq_reg_stride == 1) {
- d->status_reg_buf = kmalloc(map->format.val_bytes *
- chip->num_regs, GFP_KERNEL);
+ d->status_reg_buf = kmalloc_array(chip->num_regs,
+ map->format.val_bytes,
+ GFP_KERNEL);
if (!d->status_reg_buf)
goto err_alloc;
}
@@ -511,6 +581,33 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
}
}
+ if (chip->num_type_reg) {
+ for (i = 0; i < chip->num_irqs; i++) {
+ reg = chip->irqs[i].type_reg_offset / map->reg_stride;
+ d->type_buf_def[reg] |= chip->irqs[i].type_rising_mask |
+ chip->irqs[i].type_falling_mask;
+ }
+ for (i = 0; i < chip->num_type_reg; ++i) {
+ if (!d->type_buf_def[i])
+ continue;
+
+ reg = chip->type_base +
+ (i * map->reg_stride * d->type_reg_stride);
+ if (chip->type_invert)
+ ret = regmap_update_bits(map, reg,
+ d->type_buf_def[i], 0xFF);
+ else
+ ret = regmap_update_bits(map, reg,
+ d->type_buf_def[i], 0x0);
+ if (ret != 0) {
+ dev_err(map->dev,
+ "Failed to set type in 0x%x: %x\n",
+ reg, ret);
+ goto err_alloc;
+ }
+ }
+ }
+
if (irq_base)
d->domain = irq_domain_add_legacy(map->dev->of_node,
chip->num_irqs, irq_base, 0,
@@ -541,6 +638,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_domain:
/* Should really dispose of the domain but... */
err_alloc:
+ kfree(d->type_buf);
+ kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
@@ -564,6 +663,8 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
free_irq(irq, d);
irq_domain_remove(d->domain);
+ kfree(d->type_buf);
+ kfree(d->type_buf_def);
kfree(d->wake_buf);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c
index 426a57e..8812bfb 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -61,6 +61,33 @@ static int regmap_mmio_regbits_check(size_t reg_bits)
}
}
+static int regmap_mmio_get_min_stride(size_t val_bits)
+{
+ int min_stride;
+
+ switch (val_bits) {
+ case 8:
+ /* The core treats 0 as 1 */
+ min_stride = 0;
+ return 0;
+ case 16:
+ min_stride = 2;
+ break;
+ case 32:
+ min_stride = 4;
+ break;
+#ifdef CONFIG_64BIT
+ case 64:
+ min_stride = 8;
+ break;
+#endif
+ default:
+ return -EINVAL;
+ }
+
+ return min_stride;
+}
+
static inline void regmap_mmio_count_check(size_t count, u32 offset)
{
BUG_ON(count <= offset);
@@ -106,17 +133,17 @@ static int regmap_mmio_gather_write(void *context,
while (val_size) {
switch (ctx->val_bytes) {
case 1:
- writeb(*(u8 *)val, ctx->regs + offset);
+ __raw_writeb(*(u8 *)val, ctx->regs + offset);
break;
case 2:
- writew(*(u16 *)val, ctx->regs + offset);
+ __raw_writew(*(u16 *)val, ctx->regs + offset);
break;
case 4:
- writel(*(u32 *)val, ctx->regs + offset);
+ __raw_writel(*(u32 *)val, ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
- writeq(*(u64 *)val, ctx->regs + offset);
+ __raw_writeq(*(u64 *)val, ctx->regs + offset);
break;
#endif
default:
@@ -166,17 +193,17 @@ static int regmap_mmio_read(void *context,
while (val_size) {
switch (ctx->val_bytes) {
case 1:
- *(u8 *)val = readb(ctx->regs + offset);
+ *(u8 *)val = __raw_readb(ctx->regs + offset);
break;
case 2:
- *(u16 *)val = readw(ctx->regs + offset);
+ *(u16 *)val = __raw_readw(ctx->regs + offset);
break;
case 4:
- *(u32 *)val = readl(ctx->regs + offset);
+ *(u32 *)val = __raw_readl(ctx->regs + offset);
break;
#ifdef CONFIG_64BIT
case 8:
- *(u64 *)val = readq(ctx->regs + offset);
+ *(u64 *)val = __raw_readq(ctx->regs + offset);
break;
#endif
default:
@@ -231,26 +258,9 @@ static struct regmap_mmio_context *regmap_mmio_gen_context(struct device *dev,
if (config->pad_bits)
return ERR_PTR(-EINVAL);
- switch (config->val_bits) {
- case 8:
- /* The core treats 0 as 1 */
- min_stride = 0;
- break;
- case 16:
- min_stride = 2;
- break;
- case 32:
- min_stride = 4;
- break;
-#ifdef CONFIG_64BIT
- case 64:
- min_stride = 8;
- break;
-#endif
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
+ min_stride = regmap_mmio_get_min_stride(config->val_bits);
+ if (min_stride < 0)
+ return ERR_PTR(min_stride);
if (config->reg_stride < min_stride)
return ERR_PTR(-EINVAL);
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 4ac63c0..ee54e84 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -245,6 +245,28 @@ static void regmap_format_32_native(void *buf, unsigned int val,
*(u32 *)buf = val << shift;
}
+#ifdef CONFIG_64BIT
+static void regmap_format_64_be(void *buf, unsigned int val, unsigned int shift)
+{
+ __be64 *b = buf;
+
+ b[0] = cpu_to_be64((u64)val << shift);
+}
+
+static void regmap_format_64_le(void *buf, unsigned int val, unsigned int shift)
+{
+ __le64 *b = buf;
+
+ b[0] = cpu_to_le64((u64)val << shift);
+}
+
+static void regmap_format_64_native(void *buf, unsigned int val,
+ unsigned int shift)
+{
+ *(u64 *)buf = (u64)val << shift;
+}
+#endif
+
static void regmap_parse_inplace_noop(void *buf)
{
}
@@ -332,6 +354,41 @@ static unsigned int regmap_parse_32_native(const void *buf)
return *(u32 *)buf;
}
+#ifdef CONFIG_64BIT
+static unsigned int regmap_parse_64_be(const void *buf)
+{
+ const __be64 *b = buf;
+
+ return be64_to_cpu(b[0]);
+}
+
+static unsigned int regmap_parse_64_le(const void *buf)
+{
+ const __le64 *b = buf;
+
+ return le64_to_cpu(b[0]);
+}
+
+static void regmap_parse_64_be_inplace(void *buf)
+{
+ __be64 *b = buf;
+
+ b[0] = be64_to_cpu(b[0]);
+}
+
+static void regmap_parse_64_le_inplace(void *buf)
+{
+ __le64 *b = buf;
+
+ b[0] = le64_to_cpu(b[0]);
+}
+
+static unsigned int regmap_parse_64_native(const void *buf)
+{
+ return *(u64 *)buf;
+}
+#endif
+
static void regmap_lock_mutex(void *__map)
{
struct regmap *map = __map;
@@ -712,6 +769,21 @@ struct regmap *__regmap_init(struct device *dev,
}
break;
+#ifdef CONFIG_64BIT
+ case 64:
+ switch (reg_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_reg = regmap_format_64_be;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_reg = regmap_format_64_native;
+ break;
+ default:
+ goto err_map;
+ }
+ break;
+#endif
+
default:
goto err_map;
}
@@ -771,6 +843,28 @@ struct regmap *__regmap_init(struct device *dev,
goto err_map;
}
break;
+#ifdef CONFIG_64BIT
+ case 64:
+ switch (val_endian) {
+ case REGMAP_ENDIAN_BIG:
+ map->format.format_val = regmap_format_64_be;
+ map->format.parse_val = regmap_parse_64_be;
+ map->format.parse_inplace = regmap_parse_64_be_inplace;
+ break;
+ case REGMAP_ENDIAN_LITTLE:
+ map->format.format_val = regmap_format_64_le;
+ map->format.parse_val = regmap_parse_64_le;
+ map->format.parse_inplace = regmap_parse_64_le_inplace;
+ break;
+ case REGMAP_ENDIAN_NATIVE:
+ map->format.format_val = regmap_format_64_native;
+ map->format.parse_val = regmap_parse_64_native;
+ break;
+ default:
+ goto err_map;
+ }
+ break;
+#endif
}
if (map->format.format_write) {
@@ -1513,7 +1607,7 @@ int regmap_write(struct regmap *map, unsigned int reg, unsigned int val)
{
int ret;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
@@ -1540,7 +1634,7 @@ int regmap_write_async(struct regmap *map, unsigned int reg, unsigned int val)
{
int ret;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
@@ -1714,7 +1808,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val,
if (map->bus && !map->format.parse_inplace)
return -EINVAL;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
/*
@@ -1983,7 +2077,7 @@ static int _regmap_multi_reg_write(struct regmap *map,
int reg = regs[i].reg;
if (!map->writeable_reg(map->dev, reg))
return -EINVAL;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
}
@@ -2133,7 +2227,7 @@ int regmap_raw_write_async(struct regmap *map, unsigned int reg,
if (val_len % map->format.val_bytes)
return -EINVAL;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
@@ -2260,7 +2354,7 @@ int regmap_read(struct regmap *map, unsigned int reg, unsigned int *val)
{
int ret;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
map->lock(map->lock_arg);
@@ -2296,7 +2390,7 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val,
return -EINVAL;
if (val_len % map->format.val_bytes)
return -EINVAL;
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (val_count == 0)
return -EINVAL;
@@ -2414,7 +2508,7 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
size_t val_bytes = map->format.val_bytes;
bool vol = regmap_volatile_range(map, reg, val_count);
- if (reg % map->reg_stride)
+ if (!IS_ALIGNED(reg, map->reg_stride))
return -EINVAL;
if (map->bus && map->format.parse_inplace && (vol || map->cache_type == REGCACHE_NONE)) {
@@ -2488,11 +2582,19 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val,
* we assume that the values are native
* endian.
*/
+#ifdef CONFIG_64BIT
+ u64 *u64 = val;
+#endif
u32 *u32 = val;
u16 *u16 = val;
u8 *u8 = val;
switch (map->format.val_bytes) {
+#ifdef CONFIG_64BIT
+ case 8:
+ u64[i] = ival;
+ break;
+#endif
case 4:
u32[i] = ival;
break;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index b9794ae..a5880f4 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -323,7 +323,7 @@ out:
return err;
}
-static void brd_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t brd_make_request(struct request_queue *q, struct bio *bio)
{
struct block_device *bdev = bio->bi_bdev;
struct brd_device *brd = bdev->bd_disk->private_data;
@@ -337,6 +337,9 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
goto io_error;
if (unlikely(bio->bi_rw & REQ_DISCARD)) {
+ if (sector & ((PAGE_SIZE >> SECTOR_SHIFT) - 1) ||
+ bio->bi_iter.bi_size & PAGE_MASK)
+ goto io_error;
discard_from_brd(brd, sector, bio->bi_iter.bi_size);
goto out;
}
@@ -358,9 +361,10 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
out:
bio_endio(bio);
- return;
+ return BLK_QC_T_NONE;
io_error:
bio_io_error(bio);
+ return BLK_QC_T_NONE;
}
static int brd_rw_page(struct block_device *bdev, sector_t sector,
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 0422c47..b38bd06 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -514,14 +514,9 @@ cciss_proc_write(struct file *file, const char __user *buf,
if (!buf || length > PAGE_SIZE - 1)
return -EINVAL;
- buffer = (char *)__get_free_page(GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- err = -EFAULT;
- if (copy_from_user(buffer, buf, length))
- goto out;
- buffer[length] = '\0';
+ buffer = memdup_user_nul(buf, length);
+ if (IS_ERR(buffer))
+ return PTR_ERR(buffer);
#ifdef CONFIG_CISS_SCSI_TAPE
if (strncmp(ENGAGE_SCSI, buffer, sizeof ENGAGE_SCSI - 1) == 0) {
@@ -537,8 +532,7 @@ cciss_proc_write(struct file *file, const char __user *buf,
/* might be nice to have "disengage" too, but it's not
safely possible. (only 1 module use count, lock issues.) */
-out:
- free_page((unsigned long)buffer);
+ kfree(buffer);
return err;
}
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h
index 015c6e9..e66d453 100644
--- a/drivers/block/drbd/drbd_int.h
+++ b/drivers/block/drbd/drbd_int.h
@@ -1448,7 +1448,7 @@ extern int proc_details;
/* drbd_req */
extern void do_submit(struct work_struct *ws);
extern void __drbd_make_request(struct drbd_device *, struct bio *, unsigned long);
-extern void drbd_make_request(struct request_queue *q, struct bio *bio);
+extern blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio);
extern int drbd_read_remote(struct drbd_device *device, struct drbd_request *req);
extern int is_valid_ar_handle(struct drbd_request *, sector_t);
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 2115926..3ae2c00 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -1494,7 +1494,7 @@ void do_submit(struct work_struct *ws)
}
}
-void drbd_make_request(struct request_queue *q, struct bio *bio)
+blk_qc_t drbd_make_request(struct request_queue *q, struct bio *bio)
{
struct drbd_device *device = (struct drbd_device *) q->queuedata;
unsigned long start_jif;
@@ -1510,6 +1510,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
inc_ap_bio(device);
__drbd_make_request(device, bio, start_jif);
+ return BLK_QC_T_NONE;
}
void request_timer_fn(unsigned long data)
diff --git a/drivers/block/mtip32xx/mtip32xx.c b/drivers/block/mtip32xx/mtip32xx.c
index a28a562..34997d8 100644
--- a/drivers/block/mtip32xx/mtip32xx.c
+++ b/drivers/block/mtip32xx/mtip32xx.c
@@ -2029,13 +2029,10 @@ static int exec_drive_taskfile(struct driver_data *dd,
}
if (taskout) {
- outbuf = kzalloc(taskout, GFP_KERNEL);
- if (outbuf == NULL) {
- err = -ENOMEM;
- goto abort;
- }
- if (copy_from_user(outbuf, buf + outtotal, taskout)) {
- err = -EFAULT;
+ outbuf = memdup_user(buf + outtotal, taskout);
+ if (IS_ERR(outbuf)) {
+ err = PTR_ERR(outbuf);
+ outbuf = NULL;
goto abort;
}
outbuf_dma = pci_map_single(dd->pdev,
@@ -2050,14 +2047,10 @@ static int exec_drive_taskfile(struct driver_data *dd,
}
if (taskin) {
- inbuf = kzalloc(taskin, GFP_KERNEL);
- if (inbuf == NULL) {
- err = -ENOMEM;
- goto abort;
- }
-
- if (copy_from_user(inbuf, buf + intotal, taskin)) {
- err = -EFAULT;
+ inbuf = memdup_user(buf + intotal, taskin);
+ if (IS_ERR(inbuf)) {
+ err = PTR_ERR(inbuf);
+ inbuf = NULL;
goto abort;
}
inbuf_dma = pci_map_single(dd->pdev,
@@ -3810,7 +3803,6 @@ static int mtip_block_initialize(struct driver_data *dd)
sector_t capacity;
unsigned int index = 0;
struct kobject *kobj;
- unsigned char thd_name[16];
if (dd->disk)
goto skip_create_disk; /* hw init done, before rebuild */
@@ -3958,10 +3950,9 @@ skip_create_disk:
}
start_service_thread:
- sprintf(thd_name, "mtip_svc_thd_%02d", index);
dd->mtip_svc_handler = kthread_create_on_node(mtip_service_thread,
- dd, dd->numa_node, "%s",
- thd_name);
+ dd, dd->numa_node,
+ "mtip_svc_thd_%02d", index);
if (IS_ERR(dd->mtip_svc_handler)) {
dev_err(&dd->pdev->dev, "service thread failed to start\n");
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 93b3f99..e4c5cc1 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -827,6 +827,7 @@ static const struct block_device_operations nbd_fops =
{
.owner = THIS_MODULE,
.ioctl = nbd_ioctl,
+ .compat_ioctl = nbd_ioctl,
};
#if IS_ENABLED(CONFIG_DEBUG_FS)
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index 1c9e4fe..09e3c0d 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/blk-mq.h>
#include <linux/hrtimer.h>
+#include <linux/lightnvm.h>
struct nullb_cmd {
struct list_head list;
@@ -17,6 +18,7 @@ struct nullb_cmd {
struct bio *bio;
unsigned int tag;
struct nullb_queue *nq;
+ struct hrtimer timer;
};
struct nullb_queue {
@@ -39,23 +41,14 @@ struct nullb {
struct nullb_queue *queues;
unsigned int nr_queues;
+ char disk_name[DISK_NAME_LEN];
};
static LIST_HEAD(nullb_list);
static struct mutex lock;
static int null_major;
static int nullb_indexes;
-
-struct completion_queue {
- struct llist_head list;
- struct hrtimer timer;
-};
-
-/*
- * These are per-cpu for now, they will need to be configured by the
- * complete_queues parameter and appropriately mapped.
- */
-static DEFINE_PER_CPU(struct completion_queue, completion_queues);
+static struct kmem_cache *ppa_cache;
enum {
NULL_IRQ_NONE = 0,
@@ -119,6 +112,10 @@ static int nr_devices = 2;
module_param(nr_devices, int, S_IRUGO);
MODULE_PARM_DESC(nr_devices, "Number of devices to register");
+static bool use_lightnvm;
+module_param(use_lightnvm, bool, S_IRUGO);
+MODULE_PARM_DESC(use_lightnvm, "Register as a LightNVM device");
+
static int irqmode = NULL_IRQ_SOFTIRQ;
static int null_set_irqmode(const char *str, const struct kernel_param *kp)
@@ -135,8 +132,8 @@ static const struct kernel_param_ops null_irqmode_param_ops = {
device_param_cb(irqmode, &null_irqmode_param_ops, &irqmode, S_IRUGO);
MODULE_PARM_DESC(irqmode, "IRQ completion handler. 0-none, 1-softirq, 2-timer");
-static int completion_nsec = 10000;
-module_param(completion_nsec, int, S_IRUGO);
+static unsigned long completion_nsec = 10000;
+module_param(completion_nsec, ulong, S_IRUGO);
MODULE_PARM_DESC(completion_nsec, "Time in ns to complete a request in hardware. Default: 10,000ns");
static int hw_queue_depth = 64;
@@ -173,6 +170,8 @@ static void free_cmd(struct nullb_cmd *cmd)
put_tag(cmd->nq, cmd->tag);
}
+static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer);
+
static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
{
struct nullb_cmd *cmd;
@@ -183,6 +182,11 @@ static struct nullb_cmd *__alloc_cmd(struct nullb_queue *nq)
cmd = &nq->cmds[tag];
cmd->tag = tag;
cmd->nq = nq;
+ if (irqmode == NULL_IRQ_TIMER) {
+ hrtimer_init(&cmd->timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_REL);
+ cmd->timer.function = null_cmd_timer_expired;
+ }
return cmd;
}
@@ -213,6 +217,11 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait)
static void end_cmd(struct nullb_cmd *cmd)
{
+ struct request_queue *q = NULL;
+
+ if (cmd->rq)
+ q = cmd->rq->q;
+
switch (queue_mode) {
case NULL_Q_MQ:
blk_mq_end_request(cmd->rq, 0);
@@ -227,51 +236,29 @@ static void end_cmd(struct nullb_cmd *cmd)
}
free_cmd(cmd);
+
+ /* Restart queue if needed, as we are freeing a tag */
+ if (queue_mode == NULL_Q_RQ && blk_queue_stopped(q)) {
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue_async(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ }
}
static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer)
{
- struct completion_queue *cq;
- struct llist_node *entry;
- struct nullb_cmd *cmd;
-
- cq = &per_cpu(completion_queues, smp_processor_id());
-
- while ((entry = llist_del_all(&cq->list)) != NULL) {
- entry = llist_reverse_order(entry);
- do {
- struct request_queue *q = NULL;
-
- cmd = container_of(entry, struct nullb_cmd, ll_list);
- entry = entry->next;
- if (cmd->rq)
- q = cmd->rq->q;
- end_cmd(cmd);
-
- if (q && !q->mq_ops && blk_queue_stopped(q)) {
- spin_lock(q->queue_lock);
- if (blk_queue_stopped(q))
- blk_start_queue(q);
- spin_unlock(q->queue_lock);
- }
- } while (entry);
- }
+ end_cmd(container_of(timer, struct nullb_cmd, timer));
return HRTIMER_NORESTART;
}
static void null_cmd_end_timer(struct nullb_cmd *cmd)
{
- struct completion_queue *cq = &per_cpu(completion_queues, get_cpu());
+ ktime_t kt = ktime_set(0, completion_nsec);
- cmd->ll_list.next = NULL;
- if (llist_add(&cmd->ll_list, &cq->list)) {
- ktime_t kt = ktime_set(0, completion_nsec);
-
- hrtimer_start(&cq->timer, kt, HRTIMER_MODE_REL_PINNED);
- }
-
- put_cpu();
+ hrtimer_start(&cmd->timer, kt, HRTIMER_MODE_REL);
}
static void null_softirq_done_fn(struct request *rq)
@@ -321,7 +308,7 @@ static struct nullb_queue *nullb_to_queue(struct nullb *nullb)
return &nullb->queues[index];
}
-static void null_queue_bio(struct request_queue *q, struct bio *bio)
+static blk_qc_t null_queue_bio(struct request_queue *q, struct bio *bio)
{
struct nullb *nullb = q->queuedata;
struct nullb_queue *nq = nullb_to_queue(nullb);
@@ -331,6 +318,7 @@ static void null_queue_bio(struct request_queue *q, struct bio *bio)
cmd->bio = bio;
null_handle_cmd(cmd);
+ return BLK_QC_T_NONE;
}
static int null_rq_prep_fn(struct request_queue *q, struct request *req)
@@ -368,6 +356,10 @@ static int null_queue_rq(struct blk_mq_hw_ctx *hctx,
{
struct nullb_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
+ if (irqmode == NULL_IRQ_TIMER) {
+ hrtimer_init(&cmd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+ cmd->timer.function = null_cmd_timer_expired;
+ }
cmd->rq = bd->rq;
cmd->nq = hctx->driver_data;
@@ -426,15 +418,157 @@ static void null_del_dev(struct nullb *nullb)
{
list_del_init(&nullb->list);
- del_gendisk(nullb->disk);
+ if (use_lightnvm)
+ nvm_unregister(nullb->disk_name);
+ else
+ del_gendisk(nullb->disk);
blk_cleanup_queue(nullb->q);
if (queue_mode == NULL_Q_MQ)
blk_mq_free_tag_set(&nullb->tag_set);
- put_disk(nullb->disk);
+ if (!use_lightnvm)
+ put_disk(nullb->disk);
cleanup_queues(nullb);
kfree(nullb);
}
+#ifdef CONFIG_NVM
+
+static void null_lnvm_end_io(struct request *rq, int error)
+{
+ struct nvm_rq *rqd = rq->end_io_data;
+ struct nvm_dev *dev = rqd->dev;
+
+ dev->mt->end_io(rqd, error);
+
+ blk_put_request(rq);
+}
+
+static int null_lnvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
+{
+ struct request_queue *q = dev->q;
+ struct request *rq;
+ struct bio *bio = rqd->bio;
+
+ rq = blk_mq_alloc_request(q, bio_rw(bio), GFP_KERNEL, 0);
+ if (IS_ERR(rq))
+ return -ENOMEM;
+
+ rq->cmd_type = REQ_TYPE_DRV_PRIV;
+ rq->__sector = bio->bi_iter.bi_sector;
+ rq->ioprio = bio_prio(bio);
+
+ if (bio_has_data(bio))
+ rq->nr_phys_segments = bio_phys_segments(q, bio);
+
+ rq->__data_len = bio->bi_iter.bi_size;
+ rq->bio = rq->biotail = bio;
+
+ rq->end_io_data = rqd;
+
+ blk_execute_rq_nowait(q, NULL, rq, 0, null_lnvm_end_io);
+
+ return 0;
+}
+
+static int null_lnvm_id(struct nvm_dev *dev, struct nvm_id *id)
+{
+ sector_t size = gb * 1024 * 1024 * 1024ULL;
+ sector_t blksize;
+ struct nvm_id_group *grp;
+
+ id->ver_id = 0x1;
+ id->vmnt = 0;
+ id->cgrps = 1;
+ id->cap = 0x3;
+ id->dom = 0x1;
+
+ id->ppaf.blk_offset = 0;
+ id->ppaf.blk_len = 16;
+ id->ppaf.pg_offset = 16;
+ id->ppaf.pg_len = 16;
+ id->ppaf.sect_offset = 32;
+ id->ppaf.sect_len = 8;
+ id->ppaf.pln_offset = 40;
+ id->ppaf.pln_len = 8;
+ id->ppaf.lun_offset = 48;
+ id->ppaf.lun_len = 8;
+ id->ppaf.ch_offset = 56;
+ id->ppaf.ch_len = 8;
+
+ do_div(size, bs); /* convert size to pages */
+ do_div(size, 256); /* concert size to pgs pr blk */
+ grp = &id->groups[0];
+ grp->mtype = 0;
+ grp->fmtype = 0;
+ grp->num_ch = 1;
+ grp->num_pg = 256;
+ blksize = size;
+ do_div(size, (1 << 16));
+ grp->num_lun = size + 1;
+ do_div(blksize, grp->num_lun);
+ grp->num_blk = blksize;
+ grp->num_pln = 1;
+
+ grp->fpg_sz = bs;
+ grp->csecs = bs;
+ grp->trdt = 25000;
+ grp->trdm = 25000;
+ grp->tprt = 500000;
+ grp->tprm = 500000;
+ grp->tbet = 1500000;
+ grp->tbem = 1500000;
+ grp->mpos = 0x010101; /* single plane rwe */
+ grp->cpar = hw_queue_depth;
+
+ return 0;
+}
+
+static void *null_lnvm_create_dma_pool(struct nvm_dev *dev, char *name)
+{
+ mempool_t *virtmem_pool;
+
+ virtmem_pool = mempool_create_slab_pool(64, ppa_cache);
+ if (!virtmem_pool) {
+ pr_err("null_blk: Unable to create virtual memory pool\n");
+ return NULL;
+ }
+
+ return virtmem_pool;
+}
+
+static void null_lnvm_destroy_dma_pool(void *pool)
+{
+ mempool_destroy(pool);
+}
+
+static void *null_lnvm_dev_dma_alloc(struct nvm_dev *dev, void *pool,
+ gfp_t mem_flags, dma_addr_t *dma_handler)
+{
+ return mempool_alloc(pool, mem_flags);
+}
+
+static void null_lnvm_dev_dma_free(void *pool, void *entry,
+ dma_addr_t dma_handler)
+{
+ mempool_free(entry, pool);
+}
+
+static struct nvm_dev_ops null_lnvm_dev_ops = {
+ .identity = null_lnvm_id,
+ .submit_io = null_lnvm_submit_io,
+
+ .create_dma_pool = null_lnvm_create_dma_pool,
+ .destroy_dma_pool = null_lnvm_destroy_dma_pool,
+ .dev_dma_alloc = null_lnvm_dev_dma_alloc,
+ .dev_dma_free = null_lnvm_dev_dma_free,
+
+ /* Simulate nvme protocol restriction */
+ .max_phys_sect = 64,
+};
+#else
+static struct nvm_dev_ops null_lnvm_dev_ops;
+#endif /* CONFIG_NVM */
+
static int null_open(struct block_device *bdev, fmode_t mode)
{
return 0;
@@ -574,11 +708,6 @@ static int null_add_dev(void)
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, nullb->q);
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, nullb->q);
- disk = nullb->disk = alloc_disk_node(1, home_node);
- if (!disk) {
- rv = -ENOMEM;
- goto out_cleanup_blk_queue;
- }
mutex_lock(&lock);
list_add_tail(&nullb->list, &nullb_list);
@@ -588,6 +717,21 @@ static int null_add_dev(void)
blk_queue_logical_block_size(nullb->q, bs);
blk_queue_physical_block_size(nullb->q, bs);
+ sprintf(nullb->disk_name, "nullb%d", nullb->index);
+
+ if (use_lightnvm) {
+ rv = nvm_register(nullb->q, nullb->disk_name,
+ &null_lnvm_dev_ops);
+ if (rv)
+ goto out_cleanup_blk_queue;
+ goto done;
+ }
+
+ disk = nullb->disk = alloc_disk_node(1, home_node);
+ if (!disk) {
+ rv = -ENOMEM;
+ goto out_cleanup_lightnvm;
+ }
size = gb * 1024 * 1024 * 1024ULL;
set_capacity(disk, size >> 9);
@@ -597,10 +741,15 @@ static int null_add_dev(void)
disk->fops = &null_fops;
disk->private_data = nullb;
disk->queue = nullb->q;
- sprintf(disk->disk_name, "nullb%d", nullb->index);
+ strncpy(disk->disk_name, nullb->disk_name, DISK_NAME_LEN);
+
add_disk(disk);
+done:
return 0;
+out_cleanup_lightnvm:
+ if (use_lightnvm)
+ nvm_unregister(nullb->disk_name);
out_cleanup_blk_queue:
blk_cleanup_queue(nullb->q);
out_cleanup_tags:
@@ -616,7 +765,9 @@ out:
static int __init null_init(void)
{
+ int ret = 0;
unsigned int i;
+ struct nullb *nullb;
if (bs > PAGE_SIZE) {
pr_warn("null_blk: invalid block size\n");
@@ -624,6 +775,18 @@ static int __init null_init(void)
bs = PAGE_SIZE;
}
+ if (use_lightnvm && bs != 4096) {
+ pr_warn("null_blk: LightNVM only supports 4k block size\n");
+ pr_warn("null_blk: defaults block size to 4k\n");
+ bs = 4096;
+ }
+
+ if (use_lightnvm && queue_mode != NULL_Q_MQ) {
+ pr_warn("null_blk: LightNVM only supported for blk-mq\n");
+ pr_warn("null_blk: defaults queue mode to blk-mq\n");
+ queue_mode = NULL_Q_MQ;
+ }
+
if (queue_mode == NULL_Q_MQ && use_per_node_hctx) {
if (submit_queues < nr_online_nodes) {
pr_warn("null_blk: submit_queues param is set to %u.",
@@ -637,32 +800,38 @@ static int __init null_init(void)
mutex_init(&lock);
- /* Initialize a separate list for each CPU for issuing softirqs */
- for_each_possible_cpu(i) {
- struct completion_queue *cq = &per_cpu(completion_queues, i);
-
- init_llist_head(&cq->list);
-
- if (irqmode != NULL_IRQ_TIMER)
- continue;
-
- hrtimer_init(&cq->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- cq->timer.function = null_cmd_timer_expired;
- }
-
null_major = register_blkdev(0, "nullb");
if (null_major < 0)
return null_major;
- for (i = 0; i < nr_devices; i++) {
- if (null_add_dev()) {
- unregister_blkdev(null_major, "nullb");
- return -EINVAL;
+ if (use_lightnvm) {
+ ppa_cache = kmem_cache_create("ppa_cache", 64 * sizeof(u64),
+ 0, 0, NULL);
+ if (!ppa_cache) {
+ pr_err("null_blk: unable to create ppa cache\n");
+ ret = -ENOMEM;
+ goto err_ppa;
}
}
+ for (i = 0; i < nr_devices; i++) {
+ ret = null_add_dev();
+ if (ret)
+ goto err_dev;
+ }
+
pr_info("null: module loaded\n");
return 0;
+
+err_dev:
+ while (!list_empty(&nullb_list)) {
+ nullb = list_entry(nullb_list.next, struct nullb, list);
+ null_del_dev(nullb);
+ }
+ kmem_cache_destroy(ppa_cache);
+err_ppa:
+ unregister_blkdev(null_major, "nullb");
+ return ret;
}
static void __exit null_exit(void)
@@ -677,6 +846,8 @@ static void __exit null_exit(void)
null_del_dev(nullb);
}
mutex_unlock(&lock);
+
+ kmem_cache_destroy(ppa_cache);
}
module_init(null_init);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 2f477d4..d06c62e 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -2441,7 +2441,7 @@ static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
}
}
-static void pkt_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t pkt_make_request(struct request_queue *q, struct bio *bio)
{
struct pktcdvd_device *pd;
char b[BDEVNAME_SIZE];
@@ -2467,7 +2467,7 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
*/
if (bio_data_dir(bio) == READ) {
pkt_make_request_read(pd, bio);
- return;
+ return BLK_QC_T_NONE;
}
if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
@@ -2499,13 +2499,12 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
pkt_make_request_write(q, split);
} while (split != bio);
- return;
+ return BLK_QC_T_NONE;
end_io:
bio_io_error(bio);
+ return BLK_QC_T_NONE;
}
-
-
static void pkt_init_queue(struct pktcdvd_device *pd)
{
struct request_queue *q = pd->disk->queue;
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c
index d89fcac..56847fc 100644
--- a/drivers/block/ps3vram.c
+++ b/drivers/block/ps3vram.c
@@ -598,7 +598,7 @@ out:
return next;
}
-static void ps3vram_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t ps3vram_make_request(struct request_queue *q, struct bio *bio)
{
struct ps3_system_bus_device *dev = q->queuedata;
struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
@@ -614,11 +614,13 @@ static void ps3vram_make_request(struct request_queue *q, struct bio *bio)
spin_unlock_irq(&priv->lock);
if (busy)
- return;
+ return BLK_QC_T_NONE;
do {
bio = ps3vram_do_bio(dev, bio);
} while (bio);
+
+ return BLK_QC_T_NONE;
}
static int ps3vram_probe(struct ps3_system_bus_device *dev)
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 128e7df..81ea69f 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -418,8 +418,6 @@ MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (d
static int rbd_img_request_submit(struct rbd_img_request *img_request);
-static void rbd_dev_device_release(struct device *dev);
-
static ssize_t rbd_add(struct bus_type *bus, const char *buf,
size_t count);
static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
@@ -3444,6 +3442,7 @@ static void rbd_queue_workfn(struct work_struct *work)
goto err_rq;
}
img_request->rq = rq;
+ snapc = NULL; /* img_request consumes a ref */
if (op_type == OBJ_OP_DISCARD)
result = rbd_img_request_fill(img_request, OBJ_REQUEST_NODATA,
@@ -3991,14 +3990,12 @@ static const struct attribute_group *rbd_attr_groups[] = {
NULL
};
-static void rbd_sysfs_dev_release(struct device *dev)
-{
-}
+static void rbd_dev_release(struct device *dev);
static struct device_type rbd_device_type = {
.name = "rbd",
.groups = rbd_attr_groups,
- .release = rbd_sysfs_dev_release,
+ .release = rbd_dev_release,
};
static struct rbd_spec *rbd_spec_get(struct rbd_spec *spec)
@@ -4041,6 +4038,25 @@ static void rbd_spec_free(struct kref *kref)
kfree(spec);
}
+static void rbd_dev_release(struct device *dev)
+{
+ struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
+ bool need_put = !!rbd_dev->opts;
+
+ rbd_put_client(rbd_dev->rbd_client);
+ rbd_spec_put(rbd_dev->spec);
+ kfree(rbd_dev->opts);
+ kfree(rbd_dev);
+
+ /*
+ * This is racy, but way better than putting module outside of
+ * the release callback. The race window is pretty small, so
+ * doing something similar to dm (dm-builtin.c) is overkill.
+ */
+ if (need_put)
+ module_put(THIS_MODULE);
+}
+
static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
struct rbd_spec *spec,
struct rbd_options *opts)
@@ -4057,6 +4073,11 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
INIT_LIST_HEAD(&rbd_dev->node);
init_rwsem(&rbd_dev->header_rwsem);
+ rbd_dev->dev.bus = &rbd_bus_type;
+ rbd_dev->dev.type = &rbd_device_type;
+ rbd_dev->dev.parent = &rbd_root_dev;
+ device_initialize(&rbd_dev->dev);
+
rbd_dev->rbd_client = rbdc;
rbd_dev->spec = spec;
rbd_dev->opts = opts;
@@ -4068,15 +4089,21 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
rbd_dev->layout.fl_object_size = cpu_to_le32(1 << RBD_MAX_OBJ_ORDER);
rbd_dev->layout.fl_pg_pool = cpu_to_le32((u32) spec->pool_id);
+ /*
+ * If this is a mapping rbd_dev (as opposed to a parent one),
+ * pin our module. We have a ref from do_rbd_add(), so use
+ * __module_get().
+ */
+ if (rbd_dev->opts)
+ __module_get(THIS_MODULE);
+
return rbd_dev;
}
static void rbd_dev_destroy(struct rbd_device *rbd_dev)
{
- rbd_put_client(rbd_dev->rbd_client);
- rbd_spec_put(rbd_dev->spec);
- kfree(rbd_dev->opts);
- kfree(rbd_dev);
+ if (rbd_dev)
+ put_device(&rbd_dev->dev);
}
/*
@@ -4702,27 +4729,6 @@ static int rbd_dev_header_info(struct rbd_device *rbd_dev)
return rbd_dev_v2_header_info(rbd_dev);
}
-static int rbd_bus_add_dev(struct rbd_device *rbd_dev)
-{
- struct device *dev;
- int ret;
-
- dev = &rbd_dev->dev;
- dev->bus = &rbd_bus_type;
- dev->type = &rbd_device_type;
- dev->parent = &rbd_root_dev;
- dev->release = rbd_dev_device_release;
- dev_set_name(dev, "%d", rbd_dev->dev_id);
- ret = device_register(dev);
-
- return ret;
-}
-
-static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
-{
- device_unregister(&rbd_dev->dev);
-}
-
/*
* Get a unique rbd identifier for the given new rbd_dev, and add
* the rbd_dev to the global list.
@@ -5225,7 +5231,8 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
set_capacity(rbd_dev->disk, rbd_dev->mapping.size / SECTOR_SIZE);
set_disk_ro(rbd_dev->disk, rbd_dev->mapping.read_only);
- ret = rbd_bus_add_dev(rbd_dev);
+ dev_set_name(&rbd_dev->dev, "%d", rbd_dev->dev_id);
+ ret = device_add(&rbd_dev->dev);
if (ret)
goto err_out_mapping;
@@ -5248,8 +5255,6 @@ err_out_blkdev:
unregister_blkdev(rbd_dev->major, rbd_dev->name);
err_out_id:
rbd_dev_id_put(rbd_dev);
- rbd_dev_mapping_clear(rbd_dev);
-
return ret;
}
@@ -5397,7 +5402,7 @@ static ssize_t do_rbd_add(struct bus_type *bus,
struct rbd_spec *spec = NULL;
struct rbd_client *rbdc;
bool read_only;
- int rc = -ENOMEM;
+ int rc;
if (!try_module_get(THIS_MODULE))
return -ENODEV;
@@ -5405,7 +5410,7 @@ static ssize_t do_rbd_add(struct bus_type *bus,
/* parse add command */
rc = rbd_add_parse_args(buf, &ceph_opts, &rbd_opts, &spec);
if (rc < 0)
- goto err_out_module;
+ goto out;
rbdc = rbd_get_client(ceph_opts);
if (IS_ERR(rbdc)) {
@@ -5432,8 +5437,10 @@ static ssize_t do_rbd_add(struct bus_type *bus,
}
rbd_dev = rbd_dev_create(rbdc, spec, rbd_opts);
- if (!rbd_dev)
+ if (!rbd_dev) {
+ rc = -ENOMEM;
goto err_out_client;
+ }
rbdc = NULL; /* rbd_dev now owns this */
spec = NULL; /* rbd_dev now owns this */
rbd_opts = NULL; /* rbd_dev now owns this */
@@ -5458,10 +5465,13 @@ static ssize_t do_rbd_add(struct bus_type *bus,
*/
rbd_dev_header_unwatch_sync(rbd_dev);
rbd_dev_image_release(rbd_dev);
- goto err_out_module;
+ goto out;
}
- return count;
+ rc = count;
+out:
+ module_put(THIS_MODULE);
+ return rc;
err_out_rbd_dev:
rbd_dev_destroy(rbd_dev);
@@ -5470,12 +5480,7 @@ err_out_client:
err_out_args:
rbd_spec_put(spec);
kfree(rbd_opts);
-err_out_module:
- module_put(THIS_MODULE);
-
- dout("Error adding device %s\n", buf);
-
- return (ssize_t)rc;
+ goto out;
}
static ssize_t rbd_add(struct bus_type *bus,
@@ -5495,17 +5500,15 @@ static ssize_t rbd_add_single_major(struct bus_type *bus,
return do_rbd_add(bus, buf, count);
}
-static void rbd_dev_device_release(struct device *dev)
+static void rbd_dev_device_release(struct rbd_device *rbd_dev)
{
- struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
-
rbd_free_disk(rbd_dev);
clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
+ device_del(&rbd_dev->dev);
rbd_dev_mapping_clear(rbd_dev);
if (!single_major)
unregister_blkdev(rbd_dev->major, rbd_dev->name);
rbd_dev_id_put(rbd_dev);
- rbd_dev_mapping_clear(rbd_dev);
}
static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
@@ -5590,9 +5593,8 @@ static ssize_t do_rbd_remove(struct bus_type *bus,
* rbd_bus_del_dev() will race with rbd_watch_cb(), resulting
* in a potential use after free of rbd_dev->disk or rbd_dev.
*/
- rbd_bus_del_dev(rbd_dev);
+ rbd_dev_device_release(rbd_dev);
rbd_dev_image_release(rbd_dev);
- module_put(THIS_MODULE);
return count;
}
@@ -5663,10 +5665,8 @@ static int rbd_slab_init(void)
if (rbd_segment_name_cache)
return 0;
out_err:
- if (rbd_obj_request_cache) {
- kmem_cache_destroy(rbd_obj_request_cache);
- rbd_obj_request_cache = NULL;
- }
+ kmem_cache_destroy(rbd_obj_request_cache);
+ rbd_obj_request_cache = NULL;
kmem_cache_destroy(rbd_img_request_cache);
rbd_img_request_cache = NULL;
diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c
index d8b2488..34997df 100644
--- a/drivers/block/rsxx/core.c
+++ b/drivers/block/rsxx/core.c
@@ -203,14 +203,11 @@ static ssize_t rsxx_cram_write(struct file *fp, const char __user *ubuf,
char *buf;
ssize_t st;
- buf = kzalloc(cnt, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ buf = memdup_user(ubuf, cnt);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- st = copy_from_user(buf, ubuf, cnt);
- if (!st)
- st = rsxx_creg_write(card, CREG_ADD_CRAM + (u32)*ppos, cnt,
- buf, 1);
+ st = rsxx_creg_write(card, CREG_ADD_CRAM + (u32)*ppos, cnt, buf, 1);
kfree(buf);
if (st)
return st;
diff --git a/drivers/block/rsxx/dev.c b/drivers/block/rsxx/dev.c
index 3163e4cdc..e1b8b70 100644
--- a/drivers/block/rsxx/dev.c
+++ b/drivers/block/rsxx/dev.c
@@ -145,7 +145,7 @@ static void bio_dma_done_cb(struct rsxx_cardinfo *card,
}
}
-static void rsxx_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t rsxx_make_request(struct request_queue *q, struct bio *bio)
{
struct rsxx_cardinfo *card = q->queuedata;
struct rsxx_bio_meta *bio_meta;
@@ -199,7 +199,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
if (st)
goto queue_err;
- return;
+ return BLK_QC_T_NONE;
queue_err:
kmem_cache_free(bio_meta_pool, bio_meta);
@@ -207,6 +207,7 @@ req_err:
if (st)
bio->bi_error = st;
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
/*----------------- Device Setup -------------------*/
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 04d6579..7939b9f 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -524,7 +524,7 @@ static int mm_check_plugged(struct cardinfo *card)
return !!blk_check_plugged(mm_unplug, card, sizeof(struct blk_plug_cb));
}
-static void mm_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t mm_make_request(struct request_queue *q, struct bio *bio)
{
struct cardinfo *card = q->queuedata;
pr_debug("mm_make_request %llu %u\n",
@@ -541,7 +541,7 @@ static void mm_make_request(struct request_queue *q, struct bio *bio)
activate(card);
spin_unlock_irq(&card->lock);
- return;
+ return BLK_QC_T_NONE;
}
static irqreturn_t mm_interrupt(int irq, void *__card)
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index f909994..41fb1a9 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -950,6 +950,8 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
goto unmap;
for (n = 0, i = 0; n < nseg; n++) {
+ uint8_t first_sect, last_sect;
+
if ((n % SEGS_PER_INDIRECT_FRAME) == 0) {
/* Map indirect segments */
if (segments)
@@ -957,15 +959,18 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req,
segments = kmap_atomic(pages[n/SEGS_PER_INDIRECT_FRAME]->page);
}
i = n % SEGS_PER_INDIRECT_FRAME;
+
pending_req->segments[n]->gref = segments[i].gref;
- seg[n].nsec = segments[i].last_sect -
- segments[i].first_sect + 1;
- seg[n].offset = (segments[i].first_sect << 9);
- if ((segments[i].last_sect >= (XEN_PAGE_SIZE >> 9)) ||
- (segments[i].last_sect < segments[i].first_sect)) {
+
+ first_sect = READ_ONCE(segments[i].first_sect);
+ last_sect = READ_ONCE(segments[i].last_sect);
+ if (last_sect >= (XEN_PAGE_SIZE >> 9) || last_sect < first_sect) {
rc = -EINVAL;
goto unmap;
}
+
+ seg[n].nsec = last_sect - first_sect + 1;
+ seg[n].offset = first_sect << 9;
preq->nr_sects += seg[n].nsec;
}
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index 68e87a0..c929ae2 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -408,8 +408,8 @@ static inline void blkif_get_x86_32_req(struct blkif_request *dst,
struct blkif_x86_32_request *src)
{
int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
- dst->operation = src->operation;
- switch (src->operation) {
+ dst->operation = READ_ONCE(src->operation);
+ switch (dst->operation) {
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER:
@@ -456,8 +456,8 @@ static inline void blkif_get_x86_64_req(struct blkif_request *dst,
struct blkif_x86_64_request *src)
{
int i, n = BLKIF_MAX_SEGMENTS_PER_REQUEST, j;
- dst->operation = src->operation;
- switch (src->operation) {
+ dst->operation = READ_ONCE(src->operation);
+ switch (dst->operation) {
case BLKIF_OP_READ:
case BLKIF_OP_WRITE:
case BLKIF_OP_WRITE_BARRIER:
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index 81a557c..47915d7 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -894,7 +894,7 @@ out:
/*
* Handler function for all zram I/O requests.
*/
-static void zram_make_request(struct request_queue *queue, struct bio *bio)
+static blk_qc_t zram_make_request(struct request_queue *queue, struct bio *bio)
{
struct zram *zram = queue->queuedata;
@@ -911,11 +911,12 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio)
__zram_make_request(zram, bio);
zram_meta_put(zram);
- return;
+ return BLK_QC_T_NONE;
put_zram:
zram_meta_put(zram);
error:
bio_io_error(bio);
+ return BLK_QC_T_NONE;
}
static void zram_slot_free_notify(struct block_device *bdev,
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index e33dacf..92f0ee3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1372,6 +1372,8 @@ static void btusb_work(struct work_struct *work)
}
if (data->isoc_altsetting != new_alts) {
+ unsigned long flags;
+
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
@@ -1384,10 +1386,10 @@ static void btusb_work(struct work_struct *work)
* Clear outstanding fragment when selecting a new
* alternate setting.
*/
- spin_lock(&data->rxlock);
+ spin_lock_irqsave(&data->rxlock, flags);
kfree_skb(data->sco_skb);
data->sco_skb = NULL;
- spin_unlock(&data->rxlock);
+ spin_unlock_irqrestore(&data->rxlock, flags);
if (__set_isoc_interface(hdev, new_alts) < 0)
return;
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 0ebca8b..116b363 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -120,6 +120,17 @@ config SIMPLE_PM_BUS
Controller (BSC, sometimes called "LBSC within Bus Bridge", or
"External Bus Interface") as found on several Renesas ARM SoCs.
+config SUNXI_RSB
+ tristate "Allwinner sunXi Reduced Serial Bus Driver"
+ default MACH_SUN8I || MACH_SUN9I
+ depends on ARCH_SUNXI
+ select REGMAP
+ help
+ Say y here to enable support for Allwinner's Reduced Serial Bus
+ (RSB) support. This controller is responsible for communicating
+ with various RSB based devices, such as AXP223, AXP8XX PMICs,
+ and AC100/AC200 ICs.
+
config VEXPRESS_CONFIG
bool "Versatile Express configuration bus"
default y if ARCH_VEXPRESS
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 790e7b9..fcb9f97 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -15,5 +15,6 @@ obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o
obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o
obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o
+obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
diff --git a/drivers/bus/omap-ocp2scp.c b/drivers/bus/omap-ocp2scp.c
index 9f18569..bf500e0 100644
--- a/drivers/bus/omap-ocp2scp.c
+++ b/drivers/bus/omap-ocp2scp.c
@@ -117,7 +117,7 @@ static struct platform_driver omap_ocp2scp_driver = {
module_platform_driver(omap_ocp2scp_driver);
-MODULE_ALIAS("platform: omap-ocp2scp");
+MODULE_ALIAS("platform:omap-ocp2scp");
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_DESCRIPTION("OMAP OCP2SCP driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c
new file mode 100644
index 0000000..25996e2
--- /dev/null
+++ b/drivers/bus/sunxi-rsb.c
@@ -0,0 +1,783 @@
+/*
+ * RSB (Reduced Serial Bus) driver.
+ *
+ * Author: Chen-Yu Tsai <wens@csie.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.
+ *
+ * The RSB controller looks like an SMBus controller which only supports
+ * byte and word data transfers. But, it differs from standard SMBus
+ * protocol on several aspects:
+ * - it uses addresses set at runtime to address slaves. Runtime addresses
+ * are sent to slaves using their 12bit hardware addresses. Up to 15
+ * runtime addresses are available.
+ * - it adds a parity bit every 8bits of data and address for read and
+ * write accesses; this replaces the ack bit
+ * - only one read access is required to read a byte (instead of a write
+ * followed by a read access in standard SMBus protocol)
+ * - there's no Ack bit after each read access
+ *
+ * This means this bus cannot be used to interface with standard SMBus
+ * devices. Devices known to support this interface include the AXP223,
+ * AXP809, and AXP806 PMICs, and the AC100 audio codec, all from X-Powers.
+ *
+ * A description of the operation and wire protocol can be found in the
+ * RSB section of Allwinner's A80 user manual, which can be found at
+ *
+ * https://github.com/allwinner-zh/documents/tree/master/A80
+ *
+ * This document is officially released by Allwinner.
+ *
+ * This driver is based on i2c-sun6i-p2wi.c, the P2WI bus driver.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/clk/clk-conf.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+#include <linux/slab.h>
+#include <linux/sunxi-rsb.h>
+#include <linux/types.h>
+
+/* RSB registers */
+#define RSB_CTRL 0x0 /* Global control */
+#define RSB_CCR 0x4 /* Clock control */
+#define RSB_INTE 0x8 /* Interrupt controls */
+#define RSB_INTS 0xc /* Interrupt status */
+#define RSB_ADDR 0x10 /* Address to send with read/write command */
+#define RSB_DATA 0x1c /* Data to read/write */
+#define RSB_LCR 0x24 /* Line control */
+#define RSB_DMCR 0x28 /* Device mode (init) control */
+#define RSB_CMD 0x2c /* RSB Command */
+#define RSB_DAR 0x30 /* Device address / runtime address */
+
+/* CTRL fields */
+#define RSB_CTRL_START_TRANS BIT(7)
+#define RSB_CTRL_ABORT_TRANS BIT(6)
+#define RSB_CTRL_GLOBAL_INT_ENB BIT(1)
+#define RSB_CTRL_SOFT_RST BIT(0)
+
+/* CLK CTRL fields */
+#define RSB_CCR_SDA_OUT_DELAY(v) (((v) & 0x7) << 8)
+#define RSB_CCR_MAX_CLK_DIV 0xff
+#define RSB_CCR_CLK_DIV(v) ((v) & RSB_CCR_MAX_CLK_DIV)
+
+/* STATUS fields */
+#define RSB_INTS_TRANS_ERR_ACK BIT(16)
+#define RSB_INTS_TRANS_ERR_DATA_BIT(v) (((v) >> 8) & 0xf)
+#define RSB_INTS_TRANS_ERR_DATA GENMASK(11, 8)
+#define RSB_INTS_LOAD_BSY BIT(2)
+#define RSB_INTS_TRANS_ERR BIT(1)
+#define RSB_INTS_TRANS_OVER BIT(0)
+
+/* LINE CTRL fields*/
+#define RSB_LCR_SCL_STATE BIT(5)
+#define RSB_LCR_SDA_STATE BIT(4)
+#define RSB_LCR_SCL_CTL BIT(3)
+#define RSB_LCR_SCL_CTL_EN BIT(2)
+#define RSB_LCR_SDA_CTL BIT(1)
+#define RSB_LCR_SDA_CTL_EN BIT(0)
+
+/* DEVICE MODE CTRL field values */
+#define RSB_DMCR_DEVICE_START BIT(31)
+#define RSB_DMCR_MODE_DATA (0x7c << 16)
+#define RSB_DMCR_MODE_REG (0x3e << 8)
+#define RSB_DMCR_DEV_ADDR 0x00
+
+/* CMD values */
+#define RSB_CMD_RD8 0x8b
+#define RSB_CMD_RD16 0x9c
+#define RSB_CMD_RD32 0xa6
+#define RSB_CMD_WR8 0x4e
+#define RSB_CMD_WR16 0x59
+#define RSB_CMD_WR32 0x63
+#define RSB_CMD_STRA 0xe8
+
+/* DAR fields */
+#define RSB_DAR_RTA(v) (((v) & 0xff) << 16)
+#define RSB_DAR_DA(v) ((v) & 0xffff)
+
+#define RSB_MAX_FREQ 20000000
+
+#define RSB_CTRL_NAME "sunxi-rsb"
+
+struct sunxi_rsb_addr_map {
+ u16 hwaddr;
+ u8 rtaddr;
+};
+
+struct sunxi_rsb {
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ struct reset_control *rstc;
+ struct completion complete;
+ struct mutex lock;
+ unsigned int status;
+};
+
+/* bus / slave device related functions */
+static struct bus_type sunxi_rsb_bus;
+
+static int sunxi_rsb_device_match(struct device *dev, struct device_driver *drv)
+{
+ return of_driver_match_device(dev, drv);
+}
+
+static int sunxi_rsb_device_probe(struct device *dev)
+{
+ const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver);
+ struct sunxi_rsb_device *rdev = to_sunxi_rsb_device(dev);
+ int ret;
+
+ if (!drv->probe)
+ return -ENODEV;
+
+ if (!rdev->irq) {
+ int irq = -ENOENT;
+
+ if (dev->of_node)
+ irq = of_irq_get(dev->of_node, 0);
+
+ if (irq == -EPROBE_DEFER)
+ return irq;
+ if (irq < 0)
+ irq = 0;
+
+ rdev->irq = irq;
+ }
+
+ ret = of_clk_set_defaults(dev->of_node, false);
+ if (ret < 0)
+ return ret;
+
+ return drv->probe(rdev);
+}
+
+static int sunxi_rsb_device_remove(struct device *dev)
+{
+ const struct sunxi_rsb_driver *drv = to_sunxi_rsb_driver(dev->driver);
+
+ return drv->remove(to_sunxi_rsb_device(dev));
+}
+
+static struct bus_type sunxi_rsb_bus = {
+ .name = RSB_CTRL_NAME,
+ .match = sunxi_rsb_device_match,
+ .probe = sunxi_rsb_device_probe,
+ .remove = sunxi_rsb_device_remove,
+};
+
+static void sunxi_rsb_dev_release(struct device *dev)
+{
+ struct sunxi_rsb_device *rdev = to_sunxi_rsb_device(dev);
+
+ kfree(rdev);
+}
+
+/**
+ * sunxi_rsb_device_create() - allocate and add an RSB device
+ * @rsb: RSB controller
+ * @node: RSB slave device node
+ * @hwaddr: RSB slave hardware address
+ * @rtaddr: RSB slave runtime address
+ */
+static struct sunxi_rsb_device *sunxi_rsb_device_create(struct sunxi_rsb *rsb,
+ struct device_node *node, u16 hwaddr, u8 rtaddr)
+{
+ int err;
+ struct sunxi_rsb_device *rdev;
+
+ rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);
+ if (!rdev)
+ return ERR_PTR(-ENOMEM);
+
+ rdev->rsb = rsb;
+ rdev->hwaddr = hwaddr;
+ rdev->rtaddr = rtaddr;
+ rdev->dev.bus = &sunxi_rsb_bus;
+ rdev->dev.parent = rsb->dev;
+ rdev->dev.of_node = node;
+ rdev->dev.release = sunxi_rsb_dev_release;
+
+ dev_set_name(&rdev->dev, "%s-%x", RSB_CTRL_NAME, hwaddr);
+
+ err = device_register(&rdev->dev);
+ if (err < 0) {
+ dev_err(&rdev->dev, "Can't add %s, status %d\n",
+ dev_name(&rdev->dev), err);
+ goto err_device_add;
+ }
+
+ dev_dbg(&rdev->dev, "device %s registered\n", dev_name(&rdev->dev));
+
+err_device_add:
+ put_device(&rdev->dev);
+
+ return ERR_PTR(err);
+}
+
+/**
+ * sunxi_rsb_device_unregister(): unregister an RSB device
+ * @rdev: rsb_device to be removed
+ */
+static void sunxi_rsb_device_unregister(struct sunxi_rsb_device *rdev)
+{
+ device_unregister(&rdev->dev);
+}
+
+static int sunxi_rsb_remove_devices(struct device *dev, void *data)
+{
+ struct sunxi_rsb_device *rdev = to_sunxi_rsb_device(dev);
+
+ if (dev->bus == &sunxi_rsb_bus)
+ sunxi_rsb_device_unregister(rdev);
+
+ return 0;
+}
+
+/**
+ * sunxi_rsb_driver_register() - Register device driver with RSB core
+ * @rdrv: device driver to be associated with slave-device.
+ *
+ * This API will register the client driver with the RSB framework.
+ * It is typically called from the driver's module-init function.
+ */
+int sunxi_rsb_driver_register(struct sunxi_rsb_driver *rdrv)
+{
+ rdrv->driver.bus = &sunxi_rsb_bus;
+ return driver_register(&rdrv->driver);
+}
+EXPORT_SYMBOL_GPL(sunxi_rsb_driver_register);
+
+/* common code that starts a transfer */
+static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
+{
+ if (readl(rsb->regs + RSB_CTRL) & RSB_CTRL_START_TRANS) {
+ dev_dbg(rsb->dev, "RSB transfer still in progress\n");
+ return -EBUSY;
+ }
+
+ reinit_completion(&rsb->complete);
+
+ writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
+ rsb->regs + RSB_INTE);
+ writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB,
+ rsb->regs + RSB_CTRL);
+
+ if (!wait_for_completion_io_timeout(&rsb->complete,
+ msecs_to_jiffies(100))) {
+ dev_dbg(rsb->dev, "RSB timeout\n");
+
+ /* abort the transfer */
+ writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL);
+
+ /* clear any interrupt flags */
+ writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS);
+
+ return -ETIMEDOUT;
+ }
+
+ if (rsb->status & RSB_INTS_LOAD_BSY) {
+ dev_dbg(rsb->dev, "RSB busy\n");
+ return -EBUSY;
+ }
+
+ if (rsb->status & RSB_INTS_TRANS_ERR) {
+ if (rsb->status & RSB_INTS_TRANS_ERR_ACK) {
+ dev_dbg(rsb->dev, "RSB slave nack\n");
+ return -EINVAL;
+ }
+
+ if (rsb->status & RSB_INTS_TRANS_ERR_DATA) {
+ dev_dbg(rsb->dev, "RSB transfer data error\n");
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+static int sunxi_rsb_read(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
+ u32 *buf, size_t len)
+{
+ u32 cmd;
+ int ret;
+
+ if (!buf)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ cmd = RSB_CMD_RD8;
+ break;
+ case 2:
+ cmd = RSB_CMD_RD16;
+ break;
+ case 4:
+ cmd = RSB_CMD_RD32;
+ break;
+ default:
+ dev_err(rsb->dev, "Invalid access width: %d\n", len);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rsb->lock);
+
+ writel(addr, rsb->regs + RSB_ADDR);
+ writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR);
+ writel(cmd, rsb->regs + RSB_CMD);
+
+ ret = _sunxi_rsb_run_xfer(rsb);
+ if (ret)
+ goto unlock;
+
+ *buf = readl(rsb->regs + RSB_DATA);
+
+unlock:
+ mutex_unlock(&rsb->lock);
+
+ return ret;
+}
+
+static int sunxi_rsb_write(struct sunxi_rsb *rsb, u8 rtaddr, u8 addr,
+ const u32 *buf, size_t len)
+{
+ u32 cmd;
+ int ret;
+
+ if (!buf)
+ return -EINVAL;
+
+ switch (len) {
+ case 1:
+ cmd = RSB_CMD_WR8;
+ break;
+ case 2:
+ cmd = RSB_CMD_WR16;
+ break;
+ case 4:
+ cmd = RSB_CMD_WR32;
+ break;
+ default:
+ dev_err(rsb->dev, "Invalid access width: %d\n", len);
+ return -EINVAL;
+ }
+
+ mutex_lock(&rsb->lock);
+
+ writel(addr, rsb->regs + RSB_ADDR);
+ writel(RSB_DAR_RTA(rtaddr), rsb->regs + RSB_DAR);
+ writel(*buf, rsb->regs + RSB_DATA);
+ writel(cmd, rsb->regs + RSB_CMD);
+ ret = _sunxi_rsb_run_xfer(rsb);
+
+ mutex_unlock(&rsb->lock);
+
+ return ret;
+}
+
+/* RSB regmap functions */
+struct sunxi_rsb_ctx {
+ struct sunxi_rsb_device *rdev;
+ int size;
+};
+
+static int regmap_sunxi_rsb_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct sunxi_rsb_ctx *ctx = context;
+ struct sunxi_rsb_device *rdev = ctx->rdev;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ return sunxi_rsb_read(rdev->rsb, rdev->rtaddr, reg, val, ctx->size);
+}
+
+static int regmap_sunxi_rsb_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct sunxi_rsb_ctx *ctx = context;
+ struct sunxi_rsb_device *rdev = ctx->rdev;
+
+ return sunxi_rsb_write(rdev->rsb, rdev->rtaddr, reg, &val, ctx->size);
+}
+
+static void regmap_sunxi_rsb_free_ctx(void *context)
+{
+ struct sunxi_rsb_ctx *ctx = context;
+
+ kfree(ctx);
+}
+
+static struct regmap_bus regmap_sunxi_rsb = {
+ .reg_write = regmap_sunxi_rsb_reg_write,
+ .reg_read = regmap_sunxi_rsb_reg_read,
+ .free_context = regmap_sunxi_rsb_free_ctx,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+static struct sunxi_rsb_ctx *regmap_sunxi_rsb_init_ctx(struct sunxi_rsb_device *rdev,
+ const struct regmap_config *config)
+{
+ struct sunxi_rsb_ctx *ctx;
+
+ switch (config->val_bits) {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return ERR_PTR(-ENOMEM);
+
+ ctx->rdev = rdev;
+ ctx->size = config->val_bits / 8;
+
+ return ctx;
+}
+
+struct regmap *__devm_regmap_init_sunxi_rsb(struct sunxi_rsb_device *rdev,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key,
+ const char *lock_name)
+{
+ struct sunxi_rsb_ctx *ctx = regmap_sunxi_rsb_init_ctx(rdev, config);
+
+ if (IS_ERR(ctx))
+ return ERR_CAST(ctx);
+
+ return __devm_regmap_init(&rdev->dev, &regmap_sunxi_rsb, ctx, config,
+ lock_key, lock_name);
+}
+EXPORT_SYMBOL_GPL(__devm_regmap_init_sunxi_rsb);
+
+/* RSB controller driver functions */
+static irqreturn_t sunxi_rsb_irq(int irq, void *dev_id)
+{
+ struct sunxi_rsb *rsb = dev_id;
+ u32 status;
+
+ status = readl(rsb->regs + RSB_INTS);
+ rsb->status = status;
+
+ /* Clear interrupts */
+ status &= (RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR |
+ RSB_INTS_TRANS_OVER);
+ writel(status, rsb->regs + RSB_INTS);
+
+ complete(&rsb->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int sunxi_rsb_init_device_mode(struct sunxi_rsb *rsb)
+{
+ int ret = 0;
+ u32 reg;
+
+ /* send init sequence */
+ writel(RSB_DMCR_DEVICE_START | RSB_DMCR_MODE_DATA |
+ RSB_DMCR_MODE_REG | RSB_DMCR_DEV_ADDR, rsb->regs + RSB_DMCR);
+
+ readl_poll_timeout(rsb->regs + RSB_DMCR, reg,
+ !(reg & RSB_DMCR_DEVICE_START), 100, 250000);
+ if (reg & RSB_DMCR_DEVICE_START)
+ ret = -ETIMEDOUT;
+
+ /* clear interrupt status bits */
+ writel(readl(rsb->regs + RSB_INTS), rsb->regs + RSB_INTS);
+
+ return ret;
+}
+
+/*
+ * There are 15 valid runtime addresses, though Allwinner typically
+ * skips the first, for unknown reasons, and uses the following three.
+ *
+ * 0x17, 0x2d, 0x3a, 0x4e, 0x59, 0x63, 0x74, 0x8b,
+ * 0x9c, 0xa6, 0xb1, 0xc5, 0xd2, 0xe8, 0xff
+ *
+ * No designs with 2 RSB slave devices sharing identical hardware
+ * addresses on the same bus have been seen in the wild. All designs
+ * use 0x2d for the primary PMIC, 0x3a for the secondary PMIC if
+ * there is one, and 0x45 for peripheral ICs.
+ *
+ * The hardware does not seem to support re-setting runtime addresses.
+ * Attempts to do so result in the slave devices returning a NACK.
+ * Hence we just hardcode the mapping here, like Allwinner does.
+ */
+
+static const struct sunxi_rsb_addr_map sunxi_rsb_addr_maps[] = {
+ { 0x3a3, 0x2d }, /* Primary PMIC: AXP223, AXP809, AXP81X, ... */
+ { 0x745, 0x3a }, /* Secondary PMIC: AXP806, ... */
+ { 0xe89, 0x4e }, /* Peripheral IC: AC100, ... */
+};
+
+static u8 sunxi_rsb_get_rtaddr(u16 hwaddr)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sunxi_rsb_addr_maps); i++)
+ if (hwaddr == sunxi_rsb_addr_maps[i].hwaddr)
+ return sunxi_rsb_addr_maps[i].rtaddr;
+
+ return 0; /* 0 is an invalid runtime address */
+}
+
+static int of_rsb_register_devices(struct sunxi_rsb *rsb)
+{
+ struct device *dev = rsb->dev;
+ struct device_node *child, *np = dev->of_node;
+ u32 hwaddr;
+ u8 rtaddr;
+ int ret;
+
+ if (!np)
+ return -EINVAL;
+
+ /* Runtime addresses for all slaves should be set first */
+ for_each_available_child_of_node(np, child) {
+ dev_dbg(dev, "setting child %s runtime address\n",
+ child->full_name);
+
+ ret = of_property_read_u32(child, "reg", &hwaddr);
+ if (ret) {
+ dev_err(dev, "%s: invalid 'reg' property: %d\n",
+ child->full_name, ret);
+ continue;
+ }
+
+ rtaddr = sunxi_rsb_get_rtaddr(hwaddr);
+ if (!rtaddr) {
+ dev_err(dev, "%s: unknown hardware device address\n",
+ child->full_name);
+ continue;
+ }
+
+ /*
+ * Since no devices have been registered yet, we are the
+ * only ones using the bus, we can skip locking the bus.
+ */
+
+ /* setup command parameters */
+ writel(RSB_CMD_STRA, rsb->regs + RSB_CMD);
+ writel(RSB_DAR_RTA(rtaddr) | RSB_DAR_DA(hwaddr),
+ rsb->regs + RSB_DAR);
+
+ /* send command */
+ ret = _sunxi_rsb_run_xfer(rsb);
+ if (ret)
+ dev_warn(dev, "%s: set runtime address failed: %d\n",
+ child->full_name, ret);
+ }
+
+ /* Then we start adding devices and probing them */
+ for_each_available_child_of_node(np, child) {
+ struct sunxi_rsb_device *rdev;
+
+ dev_dbg(dev, "adding child %s\n", child->full_name);
+
+ ret = of_property_read_u32(child, "reg", &hwaddr);
+ if (ret)
+ continue;
+
+ rtaddr = sunxi_rsb_get_rtaddr(hwaddr);
+ if (!rtaddr)
+ continue;
+
+ rdev = sunxi_rsb_device_create(rsb, child, hwaddr, rtaddr);
+ if (IS_ERR(rdev))
+ dev_err(dev, "failed to add child device %s: %ld\n",
+ child->full_name, PTR_ERR(rdev));
+ }
+
+ return 0;
+}
+
+static const struct of_device_id sunxi_rsb_of_match_table[] = {
+ { .compatible = "allwinner,sun8i-a23-rsb" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sunxi_rsb_of_match_table);
+
+static int sunxi_rsb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct resource *r;
+ struct sunxi_rsb *rsb;
+ unsigned long p_clk_freq;
+ u32 clk_delay, clk_freq = 3000000;
+ int clk_div, irq, ret;
+ u32 reg;
+
+ of_property_read_u32(np, "clock-frequency", &clk_freq);
+ if (clk_freq > RSB_MAX_FREQ) {
+ dev_err(dev,
+ "clock-frequency (%u Hz) is too high (max = 20MHz)\n",
+ clk_freq);
+ return -EINVAL;
+ }
+
+ rsb = devm_kzalloc(dev, sizeof(*rsb), GFP_KERNEL);
+ if (!rsb)
+ return -ENOMEM;
+
+ rsb->dev = dev;
+ platform_set_drvdata(pdev, rsb);
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rsb->regs = devm_ioremap_resource(dev, r);
+ if (IS_ERR(rsb->regs))
+ return PTR_ERR(rsb->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to retrieve irq: %d\n", irq);
+ return irq;
+ }
+
+ rsb->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(rsb->clk)) {
+ ret = PTR_ERR(rsb->clk);
+ dev_err(dev, "failed to retrieve clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(rsb->clk);
+ if (ret) {
+ dev_err(dev, "failed to enable clk: %d\n", ret);
+ return ret;
+ }
+
+ p_clk_freq = clk_get_rate(rsb->clk);
+
+ rsb->rstc = devm_reset_control_get(dev, NULL);
+ if (IS_ERR(rsb->rstc)) {
+ ret = PTR_ERR(rsb->rstc);
+ dev_err(dev, "failed to retrieve reset controller: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ ret = reset_control_deassert(rsb->rstc);
+ if (ret) {
+ dev_err(dev, "failed to deassert reset line: %d\n", ret);
+ goto err_clk_disable;
+ }
+
+ init_completion(&rsb->complete);
+ mutex_init(&rsb->lock);
+
+ /* reset the controller */
+ writel(RSB_CTRL_SOFT_RST, rsb->regs + RSB_CTRL);
+ readl_poll_timeout(rsb->regs + RSB_CTRL, reg,
+ !(reg & RSB_CTRL_SOFT_RST), 1000, 100000);
+
+ /*
+ * Clock frequency and delay calculation code is from
+ * Allwinner U-boot sources.
+ *
+ * From A83 user manual:
+ * bus clock frequency = parent clock frequency / (2 * (divider + 1))
+ */
+ clk_div = p_clk_freq / clk_freq / 2;
+ if (!clk_div)
+ clk_div = 1;
+ else if (clk_div > RSB_CCR_MAX_CLK_DIV + 1)
+ clk_div = RSB_CCR_MAX_CLK_DIV + 1;
+
+ clk_delay = clk_div >> 1;
+ if (!clk_delay)
+ clk_delay = 1;
+
+ dev_info(dev, "RSB running at %lu Hz\n", p_clk_freq / clk_div / 2);
+ writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1),
+ rsb->regs + RSB_CCR);
+
+ ret = devm_request_irq(dev, irq, sunxi_rsb_irq, 0, RSB_CTRL_NAME, rsb);
+ if (ret) {
+ dev_err(dev, "can't register interrupt handler irq %d: %d\n",
+ irq, ret);
+ goto err_reset_assert;
+ }
+
+ /* initialize all devices on the bus into RSB mode */
+ ret = sunxi_rsb_init_device_mode(rsb);
+ if (ret)
+ dev_warn(dev, "Initialize device mode failed: %d\n", ret);
+
+ of_rsb_register_devices(rsb);
+
+ return 0;
+
+err_reset_assert:
+ reset_control_assert(rsb->rstc);
+
+err_clk_disable:
+ clk_disable_unprepare(rsb->clk);
+
+ return ret;
+}
+
+static int sunxi_rsb_remove(struct platform_device *pdev)
+{
+ struct sunxi_rsb *rsb = platform_get_drvdata(pdev);
+
+ device_for_each_child(rsb->dev, NULL, sunxi_rsb_remove_devices);
+ reset_control_assert(rsb->rstc);
+ clk_disable_unprepare(rsb->clk);
+
+ return 0;
+}
+
+static struct platform_driver sunxi_rsb_driver = {
+ .probe = sunxi_rsb_probe,
+ .remove = sunxi_rsb_remove,
+ .driver = {
+ .name = RSB_CTRL_NAME,
+ .of_match_table = sunxi_rsb_of_match_table,
+ },
+};
+
+static int __init sunxi_rsb_init(void)
+{
+ int ret;
+
+ ret = bus_register(&sunxi_rsb_bus);
+ if (ret) {
+ pr_err("failed to register sunxi sunxi_rsb bus: %d\n", ret);
+ return ret;
+ }
+
+ return platform_driver_register(&sunxi_rsb_driver);
+}
+module_init(sunxi_rsb_init);
+
+static void __exit sunxi_rsb_exit(void)
+{
+ platform_driver_unregister(&sunxi_rsb_driver);
+ bus_unregister(&sunxi_rsb_bus);
+}
+module_exit(sunxi_rsb_exit);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner sunXi Reduced Serial Bus controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index c206ccd..1b257ea 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -3186,15 +3186,11 @@ static noinline int mmc_ioctl_dvd_read_struct(struct cdrom_device_info *cdi,
if (!CDROM_CAN(CDC_DVD))
return -ENOSYS;
- s = kmalloc(size, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
+ s = memdup_user(arg, size);
+ if (IS_ERR(s))
+ return PTR_ERR(s);
cd_dbg(CD_DO_IOCTL, "entering DVD_READ_STRUCT\n");
- if (copy_from_user(s, arg, size)) {
- kfree(s);
- return -EFAULT;
- }
ret = dvd_read_struct(cdi, s, cgc);
if (ret)
diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c
index 6c4f4b5..073db95 100644
--- a/drivers/char/generic_nvram.c
+++ b/drivers/char/generic_nvram.c
@@ -20,6 +20,7 @@
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/nvram.h>
#ifdef CONFIG_PPC_PMAC
@@ -33,24 +34,8 @@ static ssize_t nvram_len;
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
- switch (origin) {
- case 0:
- break;
- case 1:
- offset += file->f_pos;
- break;
- case 2:
- offset += nvram_len;
- break;
- default:
- offset = -1;
- }
- if (offset < 0)
- return -EINVAL;
-
- file->f_pos = offset;
-
- return file->f_pos;
+ return generic_file_llseek_size(file, offset, origin,
+ MAX_LFS_FILESIZE, nvram_len);
}
static ssize_t read_nvram(struct file *file, char __user *buf,
diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c
index 0c98a9d..44ce806 100644
--- a/drivers/char/hw_random/via-rng.c
+++ b/drivers/char/hw_random/via-rng.c
@@ -140,7 +140,7 @@ static int via_rng_init(struct hwrng *rng)
* RNG configuration like it used to be the case in this
* register */
if ((c->x86 == 6) && (c->x86_model >= 0x0f)) {
- if (!cpu_has_xstore_enabled) {
+ if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) {
pr_err(PFX "can't enable hardware RNG "
"if XSTORE is not enabled\n");
return -ENODEV;
@@ -200,8 +200,9 @@ static int __init mod_init(void)
{
int err;
- if (!cpu_has_xstore)
+ if (!boot_cpu_has(X86_FEATURE_XSTORE))
return -ENODEV;
+
pr_info("VIA RNG detected\n");
err = hwrng_register(&via_rng);
if (err) {
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 654f6f3..4cc72fa 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -412,18 +412,42 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
return rv;
}
-static void start_check_enables(struct smi_info *smi_info)
+static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
+{
+ smi_info->last_timeout_jiffies = jiffies;
+ mod_timer(&smi_info->si_timer, new_val);
+ smi_info->timer_running = true;
+}
+
+/*
+ * Start a new message and (re)start the timer and thread.
+ */
+static void start_new_msg(struct smi_info *smi_info, unsigned char *msg,
+ unsigned int size)
+{
+ smi_mod_timer(smi_info, jiffies + SI_TIMEOUT_JIFFIES);
+
+ if (smi_info->thread)
+ wake_up_process(smi_info->thread);
+
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, size);
+}
+
+static void start_check_enables(struct smi_info *smi_info, bool start_timer)
{
unsigned char msg[2];
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+ if (start_timer)
+ start_new_msg(smi_info, msg, 2);
+ else
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
smi_info->si_state = SI_CHECKING_ENABLES;
}
-static void start_clear_flags(struct smi_info *smi_info)
+static void start_clear_flags(struct smi_info *smi_info, bool start_timer)
{
unsigned char msg[3];
@@ -432,7 +456,10 @@ static void start_clear_flags(struct smi_info *smi_info)
msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
msg[2] = WDT_PRE_TIMEOUT_INT;
- smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+ if (start_timer)
+ start_new_msg(smi_info, msg, 3);
+ else
+ smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
smi_info->si_state = SI_CLEARING_FLAGS;
}
@@ -442,10 +469,8 @@ static void start_getting_msg_queue(struct smi_info *smi_info)
smi_info->curr_msg->data[1] = IPMI_GET_MSG_CMD;
smi_info->curr_msg->data_size = 2;
- smi_info->handlers->start_transaction(
- smi_info->si_sm,
- smi_info->curr_msg->data,
- smi_info->curr_msg->data_size);
+ start_new_msg(smi_info, smi_info->curr_msg->data,
+ smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_MESSAGES;
}
@@ -455,20 +480,11 @@ static void start_getting_events(struct smi_info *smi_info)
smi_info->curr_msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
smi_info->curr_msg->data_size = 2;
- smi_info->handlers->start_transaction(
- smi_info->si_sm,
- smi_info->curr_msg->data,
- smi_info->curr_msg->data_size);
+ start_new_msg(smi_info, smi_info->curr_msg->data,
+ smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
}
-static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
-{
- smi_info->last_timeout_jiffies = jiffies;
- mod_timer(&smi_info->si_timer, new_val);
- smi_info->timer_running = true;
-}
-
/*
* When we have a situtaion where we run out of memory and cannot
* allocate messages, we just leave them in the BMC and run the system
@@ -478,11 +494,11 @@ static void smi_mod_timer(struct smi_info *smi_info, unsigned long new_val)
* Note that we cannot just use disable_irq(), since the interrupt may
* be shared.
*/
-static inline bool disable_si_irq(struct smi_info *smi_info)
+static inline bool disable_si_irq(struct smi_info *smi_info, bool start_timer)
{
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
smi_info->interrupt_disabled = true;
- start_check_enables(smi_info);
+ start_check_enables(smi_info, start_timer);
return true;
}
return false;
@@ -492,7 +508,7 @@ static inline bool enable_si_irq(struct smi_info *smi_info)
{
if ((smi_info->irq) && (smi_info->interrupt_disabled)) {
smi_info->interrupt_disabled = false;
- start_check_enables(smi_info);
+ start_check_enables(smi_info, true);
return true;
}
return false;
@@ -510,7 +526,7 @@ static struct ipmi_smi_msg *alloc_msg_handle_irq(struct smi_info *smi_info)
msg = ipmi_alloc_smi_msg();
if (!msg) {
- if (!disable_si_irq(smi_info))
+ if (!disable_si_irq(smi_info, true))
smi_info->si_state = SI_NORMAL;
} else if (enable_si_irq(smi_info)) {
ipmi_free_smi_msg(msg);
@@ -526,7 +542,7 @@ static void handle_flags(struct smi_info *smi_info)
/* Watchdog pre-timeout */
smi_inc_stat(smi_info, watchdog_pretimeouts);
- start_clear_flags(smi_info);
+ start_clear_flags(smi_info, true);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
if (smi_info->intf)
ipmi_smi_watchdog_pretimeout(smi_info->intf);
@@ -879,8 +895,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_MSG_FLAGS_CMD;
- smi_info->handlers->start_transaction(
- smi_info->si_sm, msg, 2);
+ start_new_msg(smi_info, msg, 2);
smi_info->si_state = SI_GETTING_FLAGS;
goto restart;
}
@@ -910,7 +925,7 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
* disable and messages disabled.
*/
if (smi_info->supports_event_msg_buff || smi_info->irq) {
- start_check_enables(smi_info);
+ start_check_enables(smi_info, true);
} else {
smi_info->curr_msg = alloc_msg_handle_irq(smi_info);
if (!smi_info->curr_msg)
@@ -920,6 +935,13 @@ static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
}
goto restart;
}
+
+ if (si_sm_result == SI_SM_IDLE && smi_info->timer_running) {
+ /* Ok it if fails, the timer will just go off. */
+ if (del_timer(&smi_info->si_timer))
+ smi_info->timer_running = false;
+ }
+
out:
return si_sm_result;
}
@@ -1208,14 +1230,14 @@ static int smi_start_processing(void *send_info,
new_smi->intf = intf;
- /* Try to claim any interrupts. */
- if (new_smi->irq_setup)
- new_smi->irq_setup(new_smi);
-
/* Set up the timer that drives the interface. */
setup_timer(&new_smi->si_timer, smi_timeout, (long)new_smi);
smi_mod_timer(new_smi, jiffies + SI_TIMEOUT_JIFFIES);
+ /* Try to claim any interrupts. */
+ if (new_smi->irq_setup)
+ new_smi->irq_setup(new_smi);
+
/*
* Check if the user forcefully enabled the daemon.
*/
@@ -2560,6 +2582,7 @@ static const struct of_device_id of_ipmi_match[] = {
.data = (void *)(unsigned long) SI_BT },
{},
};
+MODULE_DEVICE_TABLE(of, of_ipmi_match);
static int of_ipmi_probe(struct platform_device *dev)
{
@@ -2646,7 +2669,6 @@ static int of_ipmi_probe(struct platform_device *dev)
}
return 0;
}
-MODULE_DEVICE_TABLE(of, of_ipmi_match);
#else
#define of_ipmi_match NULL
static int of_ipmi_probe(struct platform_device *dev)
@@ -3613,7 +3635,7 @@ static int try_smi_init(struct smi_info *new_smi)
* Start clearing the flags before we enable interrupts or the
* timer to avoid racing with the timer.
*/
- start_clear_flags(new_smi);
+ start_clear_flags(new_smi, false);
/*
* IRQ is defined to be set when non-zero. req_events will
@@ -3908,7 +3930,7 @@ static void cleanup_one_si(struct smi_info *to_clean)
poll(to_clean);
schedule_timeout_uninterruptible(1);
}
- disable_si_irq(to_clean);
+ disable_si_irq(to_clean, false);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
poll(to_clean);
schedule_timeout_uninterruptible(1);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index 0ac3bd1..096f0ce 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -153,6 +153,9 @@ static int timeout = 10;
/* The pre-timeout is disabled by default. */
static int pretimeout;
+/* Default timeout to set on panic */
+static int panic_wdt_timeout = 255;
+
/* Default action is to reset the board on a timeout. */
static unsigned char action_val = WDOG_TIMEOUT_RESET;
@@ -293,6 +296,9 @@ MODULE_PARM_DESC(timeout, "Timeout value in seconds.");
module_param(pretimeout, timeout, 0644);
MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds.");
+module_param(panic_wdt_timeout, timeout, 0644);
+MODULE_PARM_DESC(timeout, "Timeout value on kernel panic in seconds.");
+
module_param_cb(action, &param_ops_str, action_op, 0644);
MODULE_PARM_DESC(action, "Timeout action. One of: "
"reset, none, power_cycle, power_off.");
@@ -1189,7 +1195,7 @@ static int wdog_panic_handler(struct notifier_block *this,
/* Make sure we do this only once. */
panic_event_handled = 1;
- timeout = 255;
+ timeout = panic_wdt_timeout;
pretimeout = 0;
panic_halt_ipmi_set_timeout();
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index e5d3e3f..67d4264 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -26,6 +26,7 @@
#include <linux/uio.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/pagemap.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -451,31 +452,8 @@ mbcs_sram_write(struct file * fp, const char __user *buf, size_t len, loff_t * o
static loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
{
- loff_t newpos;
-
- switch (whence) {
- case SEEK_SET:
- newpos = off;
- break;
-
- case SEEK_CUR:
- newpos = filp->f_pos + off;
- break;
-
- case SEEK_END:
- newpos = MBCS_SRAM_SIZE + off;
- break;
-
- default: /* can't happen */
- return -EINVAL;
- }
-
- if (newpos < 0)
- return -EINVAL;
-
- filp->f_pos = newpos;
-
- return newpos;
+ return generic_file_llseek_size(filp, off, whence, MAX_LFS_FILESIZE,
+ MBCS_SRAM_SIZE);
}
static uint64_t mbcs_pioaddr(struct mbcs_soft *soft, uint64_t offset)
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index 97c2d8d..0129232 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -110,6 +110,7 @@
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/mutex.h>
+#include <linux/pagemap.h>
static DEFINE_MUTEX(nvram_mutex);
@@ -213,21 +214,8 @@ void nvram_set_checksum(void)
static loff_t nvram_llseek(struct file *file, loff_t offset, int origin)
{
- switch (origin) {
- case 0:
- /* nothing to do */
- break;
- case 1:
- offset += file->f_pos;
- break;
- case 2:
- offset += NVRAM_BYTES;
- break;
- default:
- return -EINVAL;
- }
-
- return (offset >= 0) ? (file->f_pos = offset) : -EINVAL;
+ return generic_file_llseek_size(file, offset, origin, MAX_LFS_FILESIZE,
+ NVRAM_BYTES);
}
static ssize_t nvram_read(struct file *file, char __user *buf,
diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c
index e371480..dbe598d 100644
--- a/drivers/char/nwflash.c
+++ b/drivers/char/nwflash.c
@@ -277,36 +277,7 @@ static loff_t flash_llseek(struct file *file, loff_t offset, int orig)
printk(KERN_DEBUG "flash_llseek: offset=0x%X, orig=0x%X.\n",
(unsigned int) offset, orig);
- switch (orig) {
- case 0:
- if (offset < 0) {
- ret = -EINVAL;
- break;
- }
-
- if ((unsigned int) offset > gbFlashSize) {
- ret = -EINVAL;
- break;
- }
-
- file->f_pos = (unsigned int) offset;
- ret = file->f_pos;
- break;
- case 1:
- if ((file->f_pos + offset) > gbFlashSize) {
- ret = -EINVAL;
- break;
- }
- if ((file->f_pos + offset) < 0) {
- ret = -EINVAL;
- break;
- }
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- default:
- ret = -EINVAL;
- }
+ ret = no_seek_end_llseek_size(file, offset, orig, gbFlashSize);
mutex_unlock(&flash_mutex);
return ret;
}
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index f26b0ae..45cc39a 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -226,21 +226,23 @@ int tpm_chip_register(struct tpm_chip *chip)
if (rc)
goto out_err;
- if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
- rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj,
- &chip->dev.kobj,
- "ppi");
- if (rc)
- goto out_err;
- }
-
/* Make the chip available. */
spin_lock(&driver_lock);
- list_add_rcu(&chip->list, &tpm_chip_list);
+ list_add_tail_rcu(&chip->list, &tpm_chip_list);
spin_unlock(&driver_lock);
chip->flags |= TPM_CHIP_FLAG_REGISTERED;
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+ rc = __compat_only_sysfs_link_entry_to_kobj(&chip->pdev->kobj,
+ &chip->dev.kobj,
+ "ppi");
+ if (rc && rc != -ENOENT) {
+ tpm_chip_unregister(chip);
+ return rc;
+ }
+ }
+
return 0;
out_err:
tpm1_chip_unregister(chip);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
index bd7039f..c121304 100644
--- a/drivers/char/tpm/tpm2-cmd.c
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -443,12 +443,13 @@ int tpm2_seal_trusted(struct tpm_chip *chip,
TPM_DIGEST_SIZE);
/* sensitive */
- tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len);
+ tpm_buf_append_u16(&buf, 4 + TPM_DIGEST_SIZE + payload->key_len + 1);
tpm_buf_append_u16(&buf, TPM_DIGEST_SIZE);
tpm_buf_append(&buf, options->blobauth, TPM_DIGEST_SIZE);
- tpm_buf_append_u16(&buf, payload->key_len);
+ tpm_buf_append_u16(&buf, payload->key_len + 1);
tpm_buf_append(&buf, payload->key, payload->key_len);
+ tpm_buf_append_u8(&buf, payload->migratable);
/* public */
tpm_buf_append_u16(&buf, 14);
@@ -573,6 +574,8 @@ static int tpm2_unseal(struct tpm_chip *chip,
u32 blob_handle)
{
struct tpm_buf buf;
+ u16 data_len;
+ u8 *data;
int rc;
rc = tpm_buf_init(&buf, TPM2_ST_SESSIONS, TPM2_CC_UNSEAL);
@@ -591,11 +594,13 @@ static int tpm2_unseal(struct tpm_chip *chip,
rc = -EPERM;
if (!rc) {
- payload->key_len = be16_to_cpup(
+ data_len = be16_to_cpup(
(__be16 *) &buf.data[TPM_HEADER_SIZE + 4]);
+ data = &buf.data[TPM_HEADER_SIZE + 6];
- memcpy(payload->key, &buf.data[TPM_HEADER_SIZE + 6],
- payload->key_len);
+ memcpy(payload->key, data, data_len - 1);
+ payload->key_len = data_len - 1;
+ payload->migratable = data[data_len - 1];
}
tpm_buf_destroy(&buf);
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
index 1141456..570f30c 100644
--- a/drivers/char/tpm/tpm_of.c
+++ b/drivers/char/tpm/tpm_of.c
@@ -53,17 +53,18 @@ int read_log(struct tpm_bios_log *log)
goto cleanup_eio;
}
- of_node_put(np);
log->bios_event_log = kmalloc(*sizep, GFP_KERNEL);
if (!log->bios_event_log) {
pr_err("%s: ERROR - Not enough memory for BIOS measurements\n",
__func__);
+ of_node_put(np);
return -ENOMEM;
}
log->bios_event_log_end = log->bios_event_log + *sizep;
memcpy(log->bios_event_log, __va(*basep), *sizep);
+ of_node_put(np);
return 0;
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 696ef1d..65f7eec 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -645,6 +645,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
{
u32 vendor, intfcaps, intmask;
int rc, i, irq_s, irq_e, probe;
+ int irq_r = -1;
struct tpm_chip *chip;
struct priv_data *priv;
@@ -751,6 +752,7 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
irq_s =
ioread8(chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
+ irq_r = irq_s;
if (irq_s) {
irq_e = irq_s;
} else {
@@ -805,6 +807,8 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
+
+ devm_free_irq(dev, i, chip);
}
}
if (chip->vendor.irq) {
@@ -831,7 +835,9 @@ static int tpm_tis_init(struct device *dev, struct tpm_info *tpm_info,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
}
- }
+ } else if (irq_r != -1)
+ iowrite8(irq_r, chip->vendor.iobase +
+ TPM_INT_VECTOR(chip->vendor.locality));
if (chip->flags & TPM_CHIP_FLAG_TPM2) {
chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 7a1ab24..c3e3a02 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -60,6 +60,16 @@ config COMMON_CLK_RK808
clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
by control register.
+config COMMON_CLK_SCPI
+ tristate "Clock driver controlled via SCPI interface"
+ depends on ARM_SCPI_PROTOCOL || COMPILE_TEST
+ ---help---
+ This driver provides support for clocks that are controlled
+ by firmware that implements the SCPI interface.
+
+ This driver uses SCPI Message Protocol to interact with the
+ firmware providing all the clock controls.
+
config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d3e1910..820714c 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
+obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
diff --git a/drivers/clk/berlin/bg2q.c b/drivers/clk/berlin/bg2q.c
index 243f421..f144547 100644
--- a/drivers/clk/berlin/bg2q.c
+++ b/drivers/clk/berlin/bg2q.c
@@ -45,7 +45,7 @@
#define REG_SDIO0XIN_CLKCTL 0x0158
#define REG_SDIO1XIN_CLKCTL 0x015c
-#define MAX_CLKS 27
+#define MAX_CLKS 28
static struct clk *clks[MAX_CLKS];
static struct clk_onecell_data clk_data;
static DEFINE_SPINLOCK(lock);
@@ -356,13 +356,13 @@ static void __init berlin2q_clock_setup(struct device_node *np)
gd->bit_idx, 0, &lock);
}
- /*
- * twdclk is derived from cpu/3
- * TODO: use cpupll until cpuclk is not available
- */
+ /* cpuclk divider is fixed to 1 */
+ clks[CLKID_CPU] =
+ clk_register_fixed_factor(NULL, "cpu", clk_names[CPUPLL],
+ 0, 1, 1);
+ /* twdclk is derived from cpu/3 */
clks[CLKID_TWD] =
- clk_register_fixed_factor(NULL, "twd", clk_names[CPUPLL],
- 0, 1, 3);
+ clk_register_fixed_factor(NULL, "twd", "cpu", 0, 1, 3);
/* check for errors on leaf clocks */
for (n = 0; n < MAX_CLKS; n++) {
diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 10819e2..335322d 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -209,6 +209,8 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_mux);
struct clk_gpio_delayed_register_data {
const char *gpio_name;
+ int num_parents;
+ const char **parent_names;
struct device_node *node;
struct mutex lock;
struct clk *clk;
@@ -222,8 +224,6 @@ static struct clk *of_clk_gpio_delayed_register_get(
{
struct clk_gpio_delayed_register_data *data = _data;
struct clk *clk;
- const char **parent_names;
- int i, num_parents;
int gpio;
enum of_gpio_flags of_flags;
@@ -248,26 +248,14 @@ static struct clk *of_clk_gpio_delayed_register_get(
return ERR_PTR(gpio);
}
- num_parents = of_clk_get_parent_count(data->node);
-
- parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
- if (!parent_names) {
- clk = ERR_PTR(-ENOMEM);
- goto out;
- }
-
- for (i = 0; i < num_parents; i++)
- parent_names[i] = of_clk_get_parent_name(data->node, i);
-
- clk = data->clk_register_get(data->node->name, parent_names,
- num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
+ clk = data->clk_register_get(data->node->name, data->parent_names,
+ data->num_parents, gpio, of_flags & OF_GPIO_ACTIVE_LOW);
if (IS_ERR(clk))
goto out;
data->clk = clk;
out:
mutex_unlock(&data->lock);
- kfree(parent_names);
return clk;
}
@@ -296,11 +284,24 @@ static void __init of_gpio_clk_setup(struct device_node *node,
unsigned gpio, bool active_low))
{
struct clk_gpio_delayed_register_data *data;
+ const char **parent_names;
+ int i, num_parents;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return;
+ num_parents = of_clk_get_parent_count(node);
+
+ parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ for (i = 0; i < num_parents; i++)
+ parent_names[i] = of_clk_get_parent_name(node, i);
+
+ data->num_parents = num_parents;
+ data->parent_names = parent_names;
data->node = node;
data->gpio_name = gpio_name;
data->clk_register_get = clk_register_get;
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
index 1ab0fb8..7bc1c45 100644
--- a/drivers/clk/clk-qoriq.c
+++ b/drivers/clk/clk-qoriq.c
@@ -778,8 +778,10 @@ static struct clk * __init create_one_cmux(struct clockgen *cg, int idx)
*/
clksel = (cg_in(cg, hwc->reg) & CLKSEL_MASK) >> CLKSEL_SHIFT;
div = get_pll_div(cg, hwc, clksel);
- if (!div)
+ if (!div) {
+ kfree(hwc);
return NULL;
+ }
pct80_rate = clk_get_rate(div->clk);
pct80_rate *= 8;
diff --git a/drivers/clk/clk-scpi.c b/drivers/clk/clk-scpi.c
new file mode 100644
index 0000000..cd0f272
--- /dev/null
+++ b/drivers/clk/clk-scpi.c
@@ -0,0 +1,326 @@
+/*
+ * System Control and Power Interface (SCPI) Protocol based clock driver
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/scpi_protocol.h>
+
+struct scpi_clk {
+ u32 id;
+ struct clk_hw hw;
+ struct scpi_dvfs_info *info;
+ struct scpi_ops *scpi_ops;
+};
+
+#define to_scpi_clk(clk) container_of(clk, struct scpi_clk, hw)
+
+static struct platform_device *cpufreq_dev;
+
+static unsigned long scpi_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct scpi_clk *clk = to_scpi_clk(hw);
+
+ return clk->scpi_ops->clk_get_val(clk->id);
+}
+
+static long scpi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ /*
+ * We can't figure out what rate it will be, so just return the
+ * rate back to the caller. scpi_clk_recalc_rate() will be called
+ * after the rate is set and we'll know what rate the clock is
+ * running at then.
+ */
+ return rate;
+}
+
+static int scpi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct scpi_clk *clk = to_scpi_clk(hw);
+
+ return clk->scpi_ops->clk_set_val(clk->id, rate);
+}
+
+static const struct clk_ops scpi_clk_ops = {
+ .recalc_rate = scpi_clk_recalc_rate,
+ .round_rate = scpi_clk_round_rate,
+ .set_rate = scpi_clk_set_rate,
+};
+
+/* find closest match to given frequency in OPP table */
+static int __scpi_dvfs_round_rate(struct scpi_clk *clk, unsigned long rate)
+{
+ int idx;
+ u32 fmin = 0, fmax = ~0, ftmp;
+ const struct scpi_opp *opp = clk->info->opps;
+
+ for (idx = 0; idx < clk->info->count; idx++, opp++) {
+ ftmp = opp->freq;
+ if (ftmp >= (u32)rate) {
+ if (ftmp <= fmax)
+ fmax = ftmp;
+ break;
+ } else if (ftmp >= fmin) {
+ fmin = ftmp;
+ }
+ }
+ return fmax != ~0 ? fmax : fmin;
+}
+
+static unsigned long scpi_dvfs_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct scpi_clk *clk = to_scpi_clk(hw);
+ int idx = clk->scpi_ops->dvfs_get_idx(clk->id);
+ const struct scpi_opp *opp;
+
+ if (idx < 0)
+ return 0;
+
+ opp = clk->info->opps + idx;
+ return opp->freq;
+}
+
+static long scpi_dvfs_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct scpi_clk *clk = to_scpi_clk(hw);
+
+ return __scpi_dvfs_round_rate(clk, rate);
+}
+
+static int __scpi_find_dvfs_index(struct scpi_clk *clk, unsigned long rate)
+{
+ int idx, max_opp = clk->info->count;
+ const struct scpi_opp *opp = clk->info->opps;
+
+ for (idx = 0; idx < max_opp; idx++, opp++)
+ if (opp->freq == rate)
+ return idx;
+ return -EINVAL;
+}
+
+static int scpi_dvfs_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct scpi_clk *clk = to_scpi_clk(hw);
+ int ret = __scpi_find_dvfs_index(clk, rate);
+
+ if (ret < 0)
+ return ret;
+ return clk->scpi_ops->dvfs_set_idx(clk->id, (u8)ret);
+}
+
+static const struct clk_ops scpi_dvfs_ops = {
+ .recalc_rate = scpi_dvfs_recalc_rate,
+ .round_rate = scpi_dvfs_round_rate,
+ .set_rate = scpi_dvfs_set_rate,
+};
+
+static const struct of_device_id scpi_clk_match[] = {
+ { .compatible = "arm,scpi-dvfs-clocks", .data = &scpi_dvfs_ops, },
+ { .compatible = "arm,scpi-variable-clocks", .data = &scpi_clk_ops, },
+ {}
+};
+
+static struct clk *
+scpi_clk_ops_init(struct device *dev, const struct of_device_id *match,
+ struct scpi_clk *sclk, const char *name)
+{
+ struct clk_init_data init;
+ struct clk *clk;
+ unsigned long min = 0, max = 0;
+
+ init.name = name;
+ init.flags = CLK_IS_ROOT;
+ init.num_parents = 0;
+ init.ops = match->data;
+ sclk->hw.init = &init;
+ sclk->scpi_ops = get_scpi_ops();
+
+ if (init.ops == &scpi_dvfs_ops) {
+ sclk->info = sclk->scpi_ops->dvfs_get_info(sclk->id);
+ if (IS_ERR(sclk->info))
+ return NULL;
+ } else if (init.ops == &scpi_clk_ops) {
+ if (sclk->scpi_ops->clk_get_range(sclk->id, &min, &max) || !max)
+ return NULL;
+ } else {
+ return NULL;
+ }
+
+ clk = devm_clk_register(dev, &sclk->hw);
+ if (!IS_ERR(clk) && max)
+ clk_hw_set_rate_range(&sclk->hw, min, max);
+ return clk;
+}
+
+struct scpi_clk_data {
+ struct scpi_clk **clk;
+ unsigned int clk_num;
+};
+
+static struct clk *
+scpi_of_clk_src_get(struct of_phandle_args *clkspec, void *data)
+{
+ struct scpi_clk *sclk;
+ struct scpi_clk_data *clk_data = data;
+ unsigned int idx = clkspec->args[0], count;
+
+ for (count = 0; count < clk_data->clk_num; count++) {
+ sclk = clk_data->clk[count];
+ if (idx == sclk->id)
+ return sclk->hw.clk;
+ }
+
+ return ERR_PTR(-EINVAL);
+}
+
+static int scpi_clk_add(struct device *dev, struct device_node *np,
+ const struct of_device_id *match)
+{
+ struct clk **clks;
+ int idx, count;
+ struct scpi_clk_data *clk_data;
+
+ count = of_property_count_strings(np, "clock-output-names");
+ if (count < 0) {
+ dev_err(dev, "%s: invalid clock output count\n", np->name);
+ return -EINVAL;
+ }
+
+ clk_data = devm_kmalloc(dev, sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return -ENOMEM;
+
+ clk_data->clk_num = count;
+ clk_data->clk = devm_kcalloc(dev, count, sizeof(*clk_data->clk),
+ GFP_KERNEL);
+ if (!clk_data->clk)
+ return -ENOMEM;
+
+ clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ for (idx = 0; idx < count; idx++) {
+ struct scpi_clk *sclk;
+ const char *name;
+ u32 val;
+
+ sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
+ if (!sclk)
+ return -ENOMEM;
+
+ if (of_property_read_string_index(np, "clock-output-names",
+ idx, &name)) {
+ dev_err(dev, "invalid clock name @ %s\n", np->name);
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32_index(np, "clock-indices",
+ idx, &val)) {
+ dev_err(dev, "invalid clock index @ %s\n", np->name);
+ return -EINVAL;
+ }
+
+ sclk->id = val;
+
+ clks[idx] = scpi_clk_ops_init(dev, match, sclk, name);
+ if (IS_ERR_OR_NULL(clks[idx]))
+ dev_err(dev, "failed to register clock '%s'\n", name);
+ else
+ dev_dbg(dev, "Registered clock '%s'\n", name);
+ clk_data->clk[idx] = sclk;
+ }
+
+ return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data);
+}
+
+static int scpi_clocks_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *child, *np = dev->of_node;
+
+ if (cpufreq_dev) {
+ platform_device_unregister(cpufreq_dev);
+ cpufreq_dev = NULL;
+ }
+
+ for_each_available_child_of_node(np, child)
+ of_clk_del_provider(np);
+ return 0;
+}
+
+static int scpi_clocks_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device *dev = &pdev->dev;
+ struct device_node *child, *np = dev->of_node;
+ const struct of_device_id *match;
+
+ if (!get_scpi_ops())
+ return -ENXIO;
+
+ for_each_available_child_of_node(np, child) {
+ match = of_match_node(scpi_clk_match, child);
+ if (!match)
+ continue;
+ ret = scpi_clk_add(dev, child, match);
+ if (ret) {
+ scpi_clocks_remove(pdev);
+ of_node_put(child);
+ return ret;
+ }
+ }
+ /* Add the virtual cpufreq device */
+ cpufreq_dev = platform_device_register_simple("scpi-cpufreq",
+ -1, NULL, 0);
+ if (!cpufreq_dev)
+ pr_warn("unable to register cpufreq device");
+
+ return 0;
+}
+
+static const struct of_device_id scpi_clocks_ids[] = {
+ { .compatible = "arm,scpi-clocks", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, scpi_clocks_ids);
+
+static struct platform_driver scpi_clocks_driver = {
+ .driver = {
+ .name = "scpi_clocks",
+ .of_match_table = scpi_clocks_ids,
+ },
+ .probe = scpi_clocks_probe,
+ .remove = scpi_clocks_remove,
+};
+module_platform_driver(scpi_clocks_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI clock driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/h8300/clk-div.c b/drivers/clk/h8300/clk-div.c
index 1dd5d14..d71d011 100644
--- a/drivers/clk/h8300/clk-div.c
+++ b/drivers/clk/h8300/clk-div.c
@@ -19,6 +19,7 @@ static void __init h8300_div_clk_setup(struct device_node *node)
const char *parent_name;
void __iomem *divcr = NULL;
int width;
+ int offset;
num_parents = of_clk_get_parent_count(node);
if (num_parents < 1) {
@@ -31,11 +32,14 @@ static void __init h8300_div_clk_setup(struct device_node *node)
pr_err("%s: failed to map divide register", clk_name);
goto error;
}
+ offset = (unsigned long)divcr & 3;
+ offset = (3 - offset) * 8;
+ divcr = (void *)((unsigned long)divcr & ~3);
parent_name = of_clk_get_parent_name(node, 0);
of_property_read_u32(node, "renesas,width", &width);
clk = clk_register_divider(NULL, clk_name, parent_name,
- CLK_SET_RATE_GATE, divcr, 0, width,
+ CLK_SET_RATE_GATE, divcr, offset, width,
CLK_DIVIDER_POWER_OF_TWO, &clklock);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c
index 8564e43..82fe366 100644
--- a/drivers/clk/imx/clk-pllv1.c
+++ b/drivers/clk/imx/clk-pllv1.c
@@ -52,7 +52,7 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_pllv1 *pll = to_clk_pllv1(hw);
- long long ll;
+ unsigned long long ull;
int mfn_abs;
unsigned int mfi, mfn, mfd, pd;
u32 reg;
@@ -94,16 +94,16 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw,
rate = parent_rate * 2;
rate /= pd + 1;
- ll = (unsigned long long)rate * mfn_abs;
+ ull = (unsigned long long)rate * mfn_abs;
- do_div(ll, mfd + 1);
+ do_div(ull, mfd + 1);
if (mfn_is_negative(pll, mfn))
- ll = -ll;
+ ull = (rate * mfi) - ull;
+ else
+ ull = (rate * mfi) + ull;
- ll = (rate * mfi) + ll;
-
- return ll;
+ return ull;
}
static struct clk_ops clk_pllv1_ops = {
diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c
index b18f875..4aeda56 100644
--- a/drivers/clk/imx/clk-pllv2.c
+++ b/drivers/clk/imx/clk-pllv2.c
@@ -79,7 +79,7 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
{
long mfi, mfn, mfd, pdf, ref_clk;
unsigned long dbl;
- s64 temp;
+ u64 temp;
dbl = dp_ctl & MXC_PLL_DP_CTL_DPDCK0_2_EN;
@@ -98,8 +98,9 @@ static unsigned long __clk_pllv2_recalc_rate(unsigned long parent_rate,
temp = (u64) ref_clk * abs(mfn);
do_div(temp, mfd + 1);
if (mfn < 0)
- temp = -temp;
- temp = (ref_clk * mfi) + temp;
+ temp = (ref_clk * mfi) - temp;
+ else
+ temp = (ref_clk * mfi) + temp;
return temp;
}
@@ -126,7 +127,7 @@ static int __clk_pllv2_set_rate(unsigned long rate, unsigned long parent_rate,
{
u32 reg;
long mfi, pdf, mfn, mfd = 999999;
- s64 temp64;
+ u64 temp64;
unsigned long quad_parent_rate;
quad_parent_rate = 4 * parent_rate;
diff --git a/drivers/clk/imx/clk-vf610.c b/drivers/clk/imx/clk-vf610.c
index d1b1c95..0a94d96 100644
--- a/drivers/clk/imx/clk-vf610.c
+++ b/drivers/clk/imx/clk-vf610.c
@@ -335,22 +335,22 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_SAI0_SEL] = imx_clk_mux("sai0_sel", CCM_CSCMR1, 0, 2, sai_sels, 4);
clk[VF610_CLK_SAI0_EN] = imx_clk_gate("sai0_en", "sai0_sel", CCM_CSCDR1, 16);
clk[VF610_CLK_SAI0_DIV] = imx_clk_divider("sai0_div", "sai0_en", CCM_CSCDR1, 0, 4);
- clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "sai0_div", CCM_CCGR0, CCM_CCGRx_CGn(15));
+ clk[VF610_CLK_SAI0] = imx_clk_gate2("sai0", "ipg_bus", CCM_CCGR0, CCM_CCGRx_CGn(15));
clk[VF610_CLK_SAI1_SEL] = imx_clk_mux("sai1_sel", CCM_CSCMR1, 2, 2, sai_sels, 4);
clk[VF610_CLK_SAI1_EN] = imx_clk_gate("sai1_en", "sai1_sel", CCM_CSCDR1, 17);
clk[VF610_CLK_SAI1_DIV] = imx_clk_divider("sai1_div", "sai1_en", CCM_CSCDR1, 4, 4);
- clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "sai1_div", CCM_CCGR1, CCM_CCGRx_CGn(0));
+ clk[VF610_CLK_SAI1] = imx_clk_gate2("sai1", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(0));
clk[VF610_CLK_SAI2_SEL] = imx_clk_mux("sai2_sel", CCM_CSCMR1, 4, 2, sai_sels, 4);
clk[VF610_CLK_SAI2_EN] = imx_clk_gate("sai2_en", "sai2_sel", CCM_CSCDR1, 18);
clk[VF610_CLK_SAI2_DIV] = imx_clk_divider("sai2_div", "sai2_en", CCM_CSCDR1, 8, 4);
- clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "sai2_div", CCM_CCGR1, CCM_CCGRx_CGn(1));
+ clk[VF610_CLK_SAI2] = imx_clk_gate2("sai2", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(1));
clk[VF610_CLK_SAI3_SEL] = imx_clk_mux("sai3_sel", CCM_CSCMR1, 6, 2, sai_sels, 4);
clk[VF610_CLK_SAI3_EN] = imx_clk_gate("sai3_en", "sai3_sel", CCM_CSCDR1, 19);
clk[VF610_CLK_SAI3_DIV] = imx_clk_divider("sai3_div", "sai3_en", CCM_CSCDR1, 12, 4);
- clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "sai3_div", CCM_CCGR1, CCM_CCGRx_CGn(2));
+ clk[VF610_CLK_SAI3] = imx_clk_gate2("sai3", "ipg_bus", CCM_CCGR1, CCM_CCGRx_CGn(2));
clk[VF610_CLK_NFC_SEL] = imx_clk_mux("nfc_sel", CCM_CSCMR1, 12, 2, nfc_sels, 4);
clk[VF610_CLK_NFC_EN] = imx_clk_gate("nfc_en", "nfc_sel", CCM_CSCDR2, 9);
diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c
index 09d2832..71fd293 100644
--- a/drivers/clk/mmp/clk-mmp2.c
+++ b/drivers/clk/mmp/clk-mmp2.c
@@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c
index 93e967c..7524491 100644
--- a/drivers/clk/mmp/clk-pxa168.c
+++ b/drivers/clk/mmp/clk-pxa168.c
@@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c
index 993abcd..37ba04b 100644
--- a/drivers/clk/mmp/clk-pxa910.c
+++ b/drivers/clk/mmp/clk-pxa910.c
@@ -9,6 +9,7 @@
* warranty of any kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spinlock.h>
diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c
index 55b83c7..5bebf8c 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -222,9 +222,13 @@ PNAME(mout_mpll_user_p) = { "fin_pll", "mout_mpll" };
PNAME(mout_bpll_user_p) = { "fin_pll", "mout_bpll" };
PNAME(mout_aclk166_p) = { "mout_cpll", "mout_mpll_user" };
PNAME(mout_aclk200_p) = { "mout_mpll_user", "mout_bpll_user" };
+PNAME(mout_aclk300_p) = { "mout_aclk300_disp1_mid",
+ "mout_aclk300_disp1_mid1" };
PNAME(mout_aclk400_p) = { "mout_aclk400_g3d_mid", "mout_gpll" };
PNAME(mout_aclk200_sub_p) = { "fin_pll", "div_aclk200" };
PNAME(mout_aclk266_sub_p) = { "fin_pll", "div_aclk266" };
+PNAME(mout_aclk300_sub_p) = { "fin_pll", "div_aclk300_disp" };
+PNAME(mout_aclk300_disp1_mid1_p) = { "mout_vpll", "mout_cpll" };
PNAME(mout_aclk333_sub_p) = { "fin_pll", "div_aclk333" };
PNAME(mout_aclk400_isp_sub_p) = { "fin_pll", "div_aclk400_isp" };
PNAME(mout_hdmi_p) = { "div_hdmi_pixel", "sclk_hdmiphy" };
@@ -303,9 +307,13 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
*/
MUX(0, "mout_aclk166", mout_aclk166_p, SRC_TOP0, 8, 1),
MUX(0, "mout_aclk200", mout_aclk200_p, SRC_TOP0, 12, 1),
+ MUX(0, "mout_aclk300_disp1_mid", mout_aclk200_p, SRC_TOP0, 14, 1),
+ MUX(0, "mout_aclk300", mout_aclk300_p, SRC_TOP0, 15, 1),
MUX(0, "mout_aclk333", mout_aclk166_p, SRC_TOP0, 16, 1),
MUX(0, "mout_aclk400_g3d_mid", mout_aclk200_p, SRC_TOP0, 20, 1),
+ MUX(0, "mout_aclk300_disp1_mid1", mout_aclk300_disp1_mid1_p, SRC_TOP1,
+ 8, 1),
MUX(0, "mout_aclk400_isp", mout_aclk200_p, SRC_TOP1, 24, 1),
MUX(0, "mout_aclk400_g3d", mout_aclk400_p, SRC_TOP1, 28, 1),
@@ -316,7 +324,10 @@ static struct samsung_mux_clock exynos5250_mux_clks[] __initdata = {
MUX(0, "mout_bpll_user", mout_bpll_user_p, SRC_TOP2, 24, 1),
MUX(CLK_MOUT_GPLL, "mout_gpll", mout_gpll_p, SRC_TOP2, 28, 1),
- MUX(0, "mout_aclk200_disp1_sub", mout_aclk200_sub_p, SRC_TOP3, 4, 1),
+ MUX(CLK_MOUT_ACLK200_DISP1_SUB, "mout_aclk200_disp1_sub",
+ mout_aclk200_sub_p, SRC_TOP3, 4, 1),
+ MUX(CLK_MOUT_ACLK300_DISP1_SUB, "mout_aclk300_disp1_sub",
+ mout_aclk300_sub_p, SRC_TOP3, 6, 1),
MUX(0, "mout_aclk266_gscl_sub", mout_aclk266_sub_p, SRC_TOP3, 8, 1),
MUX(0, "mout_aclk_266_isp_sub", mout_aclk266_sub_p, SRC_TOP3, 16, 1),
MUX(0, "mout_aclk_400_isp_sub", mout_aclk400_isp_sub_p,
@@ -392,6 +403,7 @@ static struct samsung_div_clock exynos5250_div_clks[] __initdata = {
DIV(0, "div_aclk333", "mout_aclk333", DIV_TOP0, 20, 3),
DIV(0, "div_aclk400_g3d", "mout_aclk400_g3d", DIV_TOP0,
24, 3),
+ DIV(0, "div_aclk300_disp", "mout_aclk300", DIV_TOP0, 28, 3),
DIV(0, "div_aclk400_isp", "mout_aclk400_isp", DIV_TOP1, 20, 3),
DIV(0, "div_aclk66_pre", "mout_mpll_user", DIV_TOP1, 24, 3),
diff --git a/drivers/clk/shmobile/clk-mstp.c b/drivers/clk/shmobile/clk-mstp.c
index 4abf211..3b09716 100644
--- a/drivers/clk/shmobile/clk-mstp.c
+++ b/drivers/clk/shmobile/clk-mstp.c
@@ -259,6 +259,10 @@ int cpg_mstp_attach_dev(struct generic_pm_domain *domain, struct device *dev)
"renesas,cpg-mstp-clocks"))
goto found;
+ /* BSC on r8a73a4/sh73a0 uses zb_clk instead of an mstp clock */
+ if (!strcmp(clkspec.np->name, "zb_clk"))
+ goto found;
+
of_node_put(clkspec.np);
i++;
}
diff --git a/drivers/clk/sunxi/clk-a10-pll2.c b/drivers/clk/sunxi/clk-a10-pll2.c
index 5484c31e..0ee1f36 100644
--- a/drivers/clk/sunxi/clk-a10-pll2.c
+++ b/drivers/clk/sunxi/clk-a10-pll2.c
@@ -41,15 +41,10 @@
#define SUN4I_PLL2_OUTPUTS 4
-struct sun4i_pll2_data {
- u32 post_div_offset;
- u32 pre_div_flags;
-};
-
static DEFINE_SPINLOCK(sun4i_a10_pll2_lock);
static void __init sun4i_pll2_setup(struct device_node *node,
- struct sun4i_pll2_data *data)
+ int post_div_offset)
{
const char *clk_name = node->name, *parent;
struct clk **clks, *base_clk, *prediv_clk;
@@ -76,7 +71,7 @@ static void __init sun4i_pll2_setup(struct device_node *node,
parent, 0, reg,
SUN4I_PLL2_PRE_DIV_SHIFT,
SUN4I_PLL2_PRE_DIV_WIDTH,
- data->pre_div_flags,
+ CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
&sun4i_a10_pll2_lock);
if (!prediv_clk) {
pr_err("Couldn't register the prediv clock\n");
@@ -127,7 +122,7 @@ static void __init sun4i_pll2_setup(struct device_node *node,
*/
val = readl(reg);
val &= ~(SUN4I_PLL2_POST_DIV_MASK << SUN4I_PLL2_POST_DIV_SHIFT);
- val |= (SUN4I_PLL2_POST_DIV_VALUE - data->post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT;
+ val |= (SUN4I_PLL2_POST_DIV_VALUE - post_div_offset) << SUN4I_PLL2_POST_DIV_SHIFT;
writel(val, reg);
of_property_read_string_index(node, "clock-output-names",
@@ -191,25 +186,17 @@ err_unmap:
iounmap(reg);
}
-static struct sun4i_pll2_data sun4i_a10_pll2_data = {
- .pre_div_flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
-};
-
static void __init sun4i_a10_pll2_setup(struct device_node *node)
{
- sun4i_pll2_setup(node, &sun4i_a10_pll2_data);
+ sun4i_pll2_setup(node, 0);
}
CLK_OF_DECLARE(sun4i_a10_pll2, "allwinner,sun4i-a10-pll2-clk",
sun4i_a10_pll2_setup);
-static struct sun4i_pll2_data sun5i_a13_pll2_data = {
- .post_div_offset = 1,
-};
-
static void __init sun5i_a13_pll2_setup(struct device_node *node)
{
- sun4i_pll2_setup(node, &sun5i_a13_pll2_data);
+ sun4i_pll2_setup(node, 1);
}
CLK_OF_DECLARE(sun5i_a13_pll2, "allwinner,sun5i-a13-pll2-clk",
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 413070d..9c79af0c 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1196,6 +1196,7 @@ static void __init sun5i_init_clocks(struct device_node *node)
}
CLK_OF_DECLARE(sun5i_a10s_clk_init, "allwinner,sun5i-a10s", sun5i_init_clocks);
CLK_OF_DECLARE(sun5i_a13_clk_init, "allwinner,sun5i-a13", sun5i_init_clocks);
+CLK_OF_DECLARE(sun5i_r8_clk_init, "allwinner,sun5i-r8", sun5i_init_clocks);
CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
static const char *sun6i_critical_clocks[] __initdata = {
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
index 1dfad0c..2a5d84f 100644
--- a/drivers/clk/ti/clk-816x.c
+++ b/drivers/clk/ti/clk-816x.c
@@ -20,6 +20,8 @@ static struct ti_dt_clk dm816x_clks[] = {
DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "timer_32k_ck", "sysclk18_ck"),
+ DT_CLK(NULL, "timer_ext_ck", "tclkin_ck"),
DT_CLK(NULL, "mpu_ck", "mpu_ck"),
DT_CLK(NULL, "timer1_fck", "timer1_fck"),
DT_CLK(NULL, "timer2_fck", "timer2_fck"),
diff --git a/drivers/clk/ti/clkt_dpll.c b/drivers/clk/ti/clkt_dpll.c
index 9023ca9..b5cc6f6 100644
--- a/drivers/clk/ti/clkt_dpll.c
+++ b/drivers/clk/ti/clkt_dpll.c
@@ -240,7 +240,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw)
*/
unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
{
- long long dpll_clk;
+ u64 dpll_clk;
u32 dpll_mult, dpll_div, v;
struct dpll_data *dd;
@@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
dpll_div = v & dd->div1_mask;
dpll_div >>= __ffs(dd->div1_mask);
- dpll_clk = (long long)clk_get_rate(dd->clk_ref) * dpll_mult;
+ dpll_clk = (u64)clk_get_rate(dd->clk_ref) * dpll_mult;
do_div(dpll_clk, dpll_div + 1);
return dpll_clk;
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index 5b17268..df25583 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -214,7 +214,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_divider *divider;
unsigned int div, value;
- unsigned long flags = 0;
u32 val;
if (!hw || !rate)
@@ -228,9 +227,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (value > div_mask(divider))
value = div_mask(divider);
- if (divider->lock)
- spin_lock_irqsave(divider->lock, flags);
-
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider) << (divider->shift + 16);
} else {
@@ -240,9 +236,6 @@ static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
val |= value << divider->shift;
ti_clk_ll_ops->clk_writel(val, divider->reg);
- if (divider->lock)
- spin_unlock_irqrestore(divider->lock, flags);
-
return 0;
}
@@ -256,8 +249,7 @@ static struct clk *_register_divider(struct device *dev, const char *name,
const char *parent_name,
unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u8 clk_divider_flags,
- const struct clk_div_table *table,
- spinlock_t *lock)
+ const struct clk_div_table *table)
{
struct clk_divider *div;
struct clk *clk;
@@ -288,7 +280,6 @@ static struct clk *_register_divider(struct device *dev, const char *name,
div->shift = shift;
div->width = width;
div->flags = clk_divider_flags;
- div->lock = lock;
div->hw.init = &init;
div->table = table;
@@ -421,7 +412,7 @@ struct clk *ti_clk_register_divider(struct ti_clk *setup)
clk = _register_divider(NULL, setup->name, div->parent,
flags, (void __iomem *)reg, div->bit_shift,
- width, div_flags, table, NULL);
+ width, div_flags, table);
if (IS_ERR(clk))
kfree(table);
@@ -584,8 +575,7 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
goto cleanup;
clk = _register_divider(NULL, node->name, parent_name, flags, reg,
- shift, width, clk_divider_flags, table,
- NULL);
+ shift, width, clk_divider_flags, table);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
index f4b2e98..66a0d0e 100644
--- a/drivers/clk/ti/fapll.c
+++ b/drivers/clk/ti/fapll.c
@@ -168,7 +168,7 @@ static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
{
struct fapll_data *fd = to_fapll(hw);
u32 fapll_n, fapll_p, v;
- long long rate;
+ u64 rate;
if (ti_fapll_clock_is_bypass(fd))
return parent_rate;
@@ -314,7 +314,7 @@ static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
{
struct fapll_synth *synth = to_synth(hw);
u32 synth_div_m;
- long long rate;
+ u64 rate;
/* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
if (!synth->div)
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index 69f08a1..dab9ba8 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -69,7 +69,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
struct clk_mux *mux = to_clk_mux(hw);
u32 val;
- unsigned long flags = 0;
if (mux->table) {
index = mux->table[index];
@@ -81,9 +80,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
index++;
}
- if (mux->lock)
- spin_lock_irqsave(mux->lock, flags);
-
if (mux->flags & CLK_MUX_HIWORD_MASK) {
val = mux->mask << (mux->shift + 16);
} else {
@@ -93,9 +89,6 @@ static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
val |= index << mux->shift;
ti_clk_ll_ops->clk_writel(val, mux->reg);
- if (mux->lock)
- spin_unlock_irqrestore(mux->lock, flags);
-
return 0;
}
@@ -109,7 +102,7 @@ static struct clk *_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents,
unsigned long flags, void __iomem *reg,
u8 shift, u32 mask, u8 clk_mux_flags,
- u32 *table, spinlock_t *lock)
+ u32 *table)
{
struct clk_mux *mux;
struct clk *clk;
@@ -133,7 +126,6 @@ static struct clk *_register_mux(struct device *dev, const char *name,
mux->shift = shift;
mux->mask = mask;
mux->flags = clk_mux_flags;
- mux->lock = lock;
mux->table = table;
mux->hw.init = &init;
@@ -175,7 +167,7 @@ struct clk *ti_clk_register_mux(struct ti_clk *setup)
return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
flags, (void __iomem *)reg, mux->bit_shift, mask,
- mux_flags, NULL, NULL);
+ mux_flags, NULL);
}
/**
@@ -227,8 +219,7 @@ static void of_mux_clk_setup(struct device_node *node)
mask = (1 << fls(mask)) - 1;
clk = _register_mux(NULL, node->name, parent_names, num_parents,
- flags, reg, shift, mask, clk_mux_flags, NULL,
- NULL);
+ flags, reg, shift, mask, clk_mux_flags, NULL);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9ceaef7..b251013 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -1,4 +1,5 @@
menu "Clock Source drivers"
+ depends on !ARCH_USES_GETTIMEOFFSET
config CLKSRC_OF
bool
@@ -27,10 +28,16 @@ config CLKSRC_MMIO
bool
config DIGICOLOR_TIMER
- bool
+ bool "Digicolor timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ Enables the support for the digicolor timer driver.
config DW_APB_TIMER
- bool
+ bool "DW APB timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ Enables the support for the dw_apb timer.
config DW_APB_TIMER_OF
bool
@@ -38,47 +45,77 @@ config DW_APB_TIMER_OF
select CLKSRC_OF
config ROCKCHIP_TIMER
- bool
+ bool "Rockchip timer driver" if COMPILE_TEST
+ depends on ARM || ARM64
select CLKSRC_OF
+ help
+ Enables the support for the rockchip timer driver.
config ARMADA_370_XP_TIMER
- bool
+ bool "Armada 370 and XP timer driver" if COMPILE_TEST
+ depends on ARM
select CLKSRC_OF
+ help
+ Enables the support for the Armada 370 and XP timer driver.
config MESON6_TIMER
- bool
+ bool "Meson6 timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
+ help
+ Enables the support for the Meson6 timer driver.
config ORION_TIMER
+ bool "Orion timer driver" if COMPILE_TEST
+ depends on ARM
select CLKSRC_OF
select CLKSRC_MMIO
- bool
+ help
+ Enables the support for the Orion timer driver
config SUN4I_TIMER
+ bool "Sun4i timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
- bool
+ help
+ Enables support for the Sun4i timer.
config SUN5I_HSTIMER
+ bool "Sun5i timer driver" if COMPILE_TEST
select CLKSRC_MMIO
- bool
+ depends on COMMON_CLK
+ help
+ Enables support the Sun5i timer.
config TEGRA_TIMER
- bool
+ bool "Tegra timer driver" if COMPILE_TEST
+ depends on ARM
+ help
+ Enables support for the Tegra driver.
config VT8500_TIMER
- bool
+ bool "VT8500 timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ Enables support for the VT8500 driver.
config CADENCE_TTC_TIMER
- bool
+ bool "Cadence TTC timer driver" if COMPILE_TEST
+ depends on COMMON_CLK
+ help
+ Enables support for the cadence ttc driver.
config ASM9260_TIMER
- bool
+ bool "ASM9260 timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
select CLKSRC_OF
+ help
+ Enables support for the ASM9260 timer.
config CLKSRC_NOMADIK_MTU
- bool
- depends on (ARCH_NOMADIK || ARCH_U8500)
+ bool "Nomakdik clocksource driver" if COMPILE_TEST
+ depends on ARM
select CLKSRC_MMIO
help
Support for Multi Timer Unit. MTU provides access
@@ -92,9 +129,8 @@ config CLKSRC_NOMADIK_MTU_SCHED_CLOCK
Use the Multi Timer Unit as the sched_clock.
config CLKSRC_DBX500_PRCMU
- bool "Clocksource PRCMU Timer"
- depends on UX500_SOC_DB8500
- default y
+ bool "Clocksource PRCMU Timer" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
help
Use the always on PRCMU Timer as clocksource
@@ -115,13 +151,26 @@ config CLKSRC_EFM32
event device.
config CLKSRC_LPC32XX
- bool
+ bool "Clocksource for LPC32XX" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
select CLKSRC_MMIO
select CLKSRC_OF
+ help
+ Support for the LPC32XX clocksource.
config CLKSRC_PISTACHIO
- bool
+ bool "Clocksource for Pistachio SoC" if COMPILE_TEST
select CLKSRC_OF
+ help
+ Enables the clocksource for the Pistachio SoC.
+
+config CLKSRC_TI_32K
+ bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST
+ depends on GENERIC_SCHED_CLOCK
+ select CLKSRC_OF if OF
+ help
+ This option enables support for Texas Instruments 32.768 Hz clocksource
+ available on many OMAP-like platforms.
config CLKSRC_STM32
bool "Clocksource for STM32 SoCs" if !ARCH_STM32
@@ -190,13 +239,14 @@ config CLKSRC_METAG_GENERIC
This option enables support for the Meta per-thread timers.
config CLKSRC_EXYNOS_MCT
- def_bool y if ARCH_EXYNOS
- depends on !ARM64
+ bool "Exynos multi core timer driver" if COMPILE_TEST
+ depends on ARM
help
Support for Multi Core Timer controller on Exynos SoCs.
config CLKSRC_SAMSUNG_PWM
- bool
+ bool "PWM timer drvier for Samsung S3C, S5P" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
help
This is a new clocksource driver for the PWM timer found in
Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver
@@ -204,7 +254,8 @@ config CLKSRC_SAMSUNG_PWM
needed only on systems that do not have the Exynos MCT available.
config FSL_FTM_TIMER
- bool
+ bool "Freescale FlexTimer Module driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
help
Support for Freescale FlexTimer Module (FTM) timer.
@@ -217,9 +268,12 @@ config SYS_SUPPORTS_SH_CMT
bool
config MTK_TIMER
+ bool "Mediatek timer driver" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
select CLKSRC_OF
select CLKSRC_MMIO
- bool
+ help
+ Support for Mediatek timer driver.
config SYS_SUPPORTS_SH_MTU2
bool
@@ -270,7 +324,12 @@ config EM_TIMER_STI
such as EMEV2 from former NEC Electronics.
config CLKSRC_QCOM
- bool
+ bool "Qualcomm MSM timer" if COMPILE_TEST
+ depends on ARM
+ select CLKSRC_OF
+ help
+ This enables the clocksource and the per CPU clockevent driver for the
+ Qualcomm SoCs.
config CLKSRC_VERSATILE
bool "ARM Versatile (Express) reference platforms clock source"
@@ -289,21 +348,40 @@ config CLKSRC_MIPS_GIC
select CLKSRC_OF
config CLKSRC_TANGO_XTAL
- bool
+ bool "Clocksource for Tango SoC" if COMPILE_TEST
+ depends on ARM
select CLKSRC_OF
+ select CLKSRC_MMIO
+ help
+ This enables the clocksource for Tango SoC
config CLKSRC_PXA
- def_bool y if ARCH_PXA || ARCH_SA1100
- select CLKSRC_OF if OF
+ bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ select CLKSRC_MMIO
help
This enables OST0 support available on PXA and SA-11x0
platforms.
+config H8300_TMR8
+ bool "Clockevent timer for the H8300 platform" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ This enables the 8 bits timer for the H8300 platform.
+
config H8300_TMR16
- bool
+ bool "Clockevent timer for the H83069 platform" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ This enables the 16 bits timer for the H8300 platform with the
+ H83069 cpu.
config H8300_TPU
- bool
+ bool "Clocksource for the H8300 platform" if COMPILE_TEST
+ depends on GENERIC_CLOCKEVENTS
+ help
+ This enables the clocksource for the H8300 platform with the
+ H8S2678 cpu.
config CLKSRC_IMX_GPT
bool "Clocksource using i.MX GPT" if COMPILE_TEST
@@ -311,8 +389,7 @@ config CLKSRC_IMX_GPT
select CLKSRC_MMIO
config CLKSRC_ST_LPC
- bool
- depends on ARCH_STI
+ bool "Low power clocksource found in the LPC" if COMPILE_TEST
select CLKSRC_OF if OF
help
Enable this option to use the Low Power controller timer
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index e8aec9d..dc2b899 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o
obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o
obj-$(CONFIG_MTK_TIMER) += mtk_timer.o
obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o
+obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o
obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o
obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
@@ -59,7 +60,7 @@ obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o
obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o
obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
-obj-$(CONFIG_H8300) += h8300_timer8.o
+obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o
obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o
obj-$(CONFIG_H8300_TPU) += h8300_tpu.o
obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 6eab889..28037d0 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -109,10 +109,8 @@ static void acpi_pm_check_blacklist(struct pci_dev *dev)
/* the bug has been fixed in PIIX4M */
if (dev->revision < 3) {
- printk(KERN_WARNING "* Found PM-Timer Bug on the chipset."
- " Due to workarounds for a bug,\n"
- "* this clock source is slow. Consider trying"
- " other clock sources\n");
+ pr_warn("* Found PM-Timer Bug on the chipset. Due to workarounds for a bug,\n"
+ "* this clock source is slow. Consider trying other clock sources\n");
acpi_pm_need_workaround();
}
@@ -125,12 +123,9 @@ static void acpi_pm_check_graylist(struct pci_dev *dev)
if (acpi_pm_good)
return;
- printk(KERN_WARNING "* The chipset may have PM-Timer Bug. Due to"
- " workarounds for a bug,\n"
- "* this clock source is slow. If you are sure your timer"
- " does not have\n"
- "* this bug, please use \"acpi_pm_good\" to disable the"
- " workaround\n");
+ pr_warn("* The chipset may have PM-Timer Bug. Due to workarounds for a bug,\n"
+ "* this clock source is slow. If you are sure your timer does not have\n"
+ "* this bug, please use \"acpi_pm_good\" to disable the workaround\n");
acpi_pm_need_workaround();
}
@@ -162,8 +157,7 @@ static int verify_pmtmr_rate(void)
/* Check that the PMTMR delta is within 5% of what we expect */
if (delta < (PMTMR_EXPECTED_RATE * 19) / 20 ||
delta > (PMTMR_EXPECTED_RATE * 21) / 20) {
- printk(KERN_INFO "PM-Timer running at invalid rate: %lu%% "
- "of normal - aborting.\n",
+ pr_info("PM-Timer running at invalid rate: %lu%% of normal - aborting.\n",
100UL * delta / PMTMR_EXPECTED_RATE);
return -1;
}
@@ -199,15 +193,14 @@ static int __init init_acpi_pm_clocksource(void)
break;
if ((value2 < value1) && ((value2) < 0xFFF))
break;
- printk(KERN_INFO "PM-Timer had inconsistent results:"
- " %#llx, %#llx - aborting.\n",
- value1, value2);
+ pr_info("PM-Timer had inconsistent results: %#llx, %#llx - aborting.\n",
+ value1, value2);
pmtmr_ioport = 0;
return -EINVAL;
}
if (i == ACPI_PM_READ_CHECKS) {
- printk(KERN_INFO "PM-Timer failed consistency check "
- " (%#llx) - aborting.\n", value1);
+ pr_info("PM-Timer failed consistency check (%#llx) - aborting.\n",
+ value1);
pmtmr_ioport = 0;
return -ENODEV;
}
diff --git a/drivers/clocksource/arm_global_timer.c b/drivers/clocksource/arm_global_timer.c
index a2cb6fa..d189d8c 100644
--- a/drivers/clocksource/arm_global_timer.c
+++ b/drivers/clocksource/arm_global_timer.c
@@ -99,17 +99,17 @@ static void gt_compare_set(unsigned long delta, int periodic)
counter += delta;
ctrl = GT_CONTROL_TIMER_ENABLE;
- writel(ctrl, gt_base + GT_CONTROL);
- writel(lower_32_bits(counter), gt_base + GT_COMP0);
- writel(upper_32_bits(counter), gt_base + GT_COMP1);
+ writel_relaxed(ctrl, gt_base + GT_CONTROL);
+ writel_relaxed(lower_32_bits(counter), gt_base + GT_COMP0);
+ writel_relaxed(upper_32_bits(counter), gt_base + GT_COMP1);
if (periodic) {
- writel(delta, gt_base + GT_AUTO_INC);
+ writel_relaxed(delta, gt_base + GT_AUTO_INC);
ctrl |= GT_CONTROL_AUTO_INC;
}
ctrl |= GT_CONTROL_COMP_ENABLE | GT_CONTROL_IRQ_ENABLE;
- writel(ctrl, gt_base + GT_CONTROL);
+ writel_relaxed(ctrl, gt_base + GT_CONTROL);
}
static int gt_clockevent_shutdown(struct clock_event_device *evt)
@@ -195,12 +195,23 @@ static cycle_t gt_clocksource_read(struct clocksource *cs)
return gt_counter_read();
}
+static void gt_resume(struct clocksource *cs)
+{
+ unsigned long ctrl;
+
+ ctrl = readl(gt_base + GT_CONTROL);
+ if (!(ctrl & GT_CONTROL_TIMER_ENABLE))
+ /* re-enable timer on resume */
+ writel(GT_CONTROL_TIMER_ENABLE, gt_base + GT_CONTROL);
+}
+
static struct clocksource gt_clocksource = {
.name = "arm_global_timer",
.rating = 300,
.read = gt_clocksource_read,
.mask = CLOCKSOURCE_MASK(64),
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .resume = gt_resume,
};
#ifdef CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
diff --git a/drivers/clocksource/dw_apb_timer.c b/drivers/clocksource/dw_apb_timer.c
index c76c750..6334526 100644
--- a/drivers/clocksource/dw_apb_timer.c
+++ b/drivers/clocksource/dw_apb_timer.c
@@ -49,20 +49,31 @@ clocksource_to_dw_apb_clocksource(struct clocksource *cs)
return container_of(cs, struct dw_apb_clocksource, cs);
}
-static unsigned long apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
+static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs)
{
return readl(timer->base + offs);
}
-static void apbt_writel(struct dw_apb_timer *timer, unsigned long val,
- unsigned long offs)
+static inline void apbt_writel(struct dw_apb_timer *timer, u32 val,
+ unsigned long offs)
{
writel(val, timer->base + offs);
}
+static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs)
+{
+ return readl_relaxed(timer->base + offs);
+}
+
+static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val,
+ unsigned long offs)
+{
+ writel_relaxed(val, timer->base + offs);
+}
+
static void apbt_disable_int(struct dw_apb_timer *timer)
{
- unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+ u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
ctrl |= APBTMR_CONTROL_INT;
apbt_writel(timer, ctrl, APBTMR_N_CONTROL);
@@ -81,7 +92,7 @@ void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced)
static void apbt_eoi(struct dw_apb_timer *timer)
{
- apbt_readl(timer, APBTMR_N_EOI);
+ apbt_readl_relaxed(timer, APBTMR_N_EOI);
}
static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
@@ -103,7 +114,7 @@ static irqreturn_t dw_apb_clockevent_irq(int irq, void *data)
static void apbt_enable_int(struct dw_apb_timer *timer)
{
- unsigned long ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
+ u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL);
/* clear pending intr */
apbt_readl(timer, APBTMR_N_EOI);
ctrl &= ~APBTMR_CONTROL_INT;
@@ -113,7 +124,7 @@ static void apbt_enable_int(struct dw_apb_timer *timer)
static int apbt_shutdown(struct clock_event_device *evt)
{
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
- unsigned long ctrl;
+ u32 ctrl;
pr_debug("%s CPU %d state=shutdown\n", __func__,
cpumask_first(evt->cpumask));
@@ -127,7 +138,7 @@ static int apbt_shutdown(struct clock_event_device *evt)
static int apbt_set_oneshot(struct clock_event_device *evt)
{
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
- unsigned long ctrl;
+ u32 ctrl;
pr_debug("%s CPU %d state=oneshot\n", __func__,
cpumask_first(evt->cpumask));
@@ -160,7 +171,7 @@ static int apbt_set_periodic(struct clock_event_device *evt)
{
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ);
- unsigned long ctrl;
+ u32 ctrl;
pr_debug("%s CPU %d state=periodic\n", __func__,
cpumask_first(evt->cpumask));
@@ -196,17 +207,17 @@ static int apbt_resume(struct clock_event_device *evt)
static int apbt_next_event(unsigned long delta,
struct clock_event_device *evt)
{
- unsigned long ctrl;
+ u32 ctrl;
struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt);
/* Disable timer */
- ctrl = apbt_readl(&dw_ced->timer, APBTMR_N_CONTROL);
+ ctrl = apbt_readl_relaxed(&dw_ced->timer, APBTMR_N_CONTROL);
ctrl &= ~APBTMR_CONTROL_ENABLE;
- apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+ apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
/* write new count */
- apbt_writel(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
+ apbt_writel_relaxed(&dw_ced->timer, delta, APBTMR_N_LOAD_COUNT);
ctrl |= APBTMR_CONTROL_ENABLE;
- apbt_writel(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
+ apbt_writel_relaxed(&dw_ced->timer, ctrl, APBTMR_N_CONTROL);
return 0;
}
@@ -323,7 +334,7 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
* start count down from 0xffff_ffff. this is done by toggling the
* enable bit then load initial load count to ~0.
*/
- unsigned long ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
+ u32 ctrl = apbt_readl(&dw_cs->timer, APBTMR_N_CONTROL);
ctrl &= ~APBTMR_CONTROL_ENABLE;
apbt_writel(&dw_cs->timer, ctrl, APBTMR_N_CONTROL);
@@ -338,11 +349,12 @@ void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs)
static cycle_t __apbt_read_clocksource(struct clocksource *cs)
{
- unsigned long current_count;
+ u32 current_count;
struct dw_apb_clocksource *dw_cs =
clocksource_to_dw_apb_clocksource(cs);
- current_count = apbt_readl(&dw_cs->timer, APBTMR_N_CURRENT_VALUE);
+ current_count = apbt_readl_relaxed(&dw_cs->timer,
+ APBTMR_N_CURRENT_VALUE);
return (cycle_t)~current_count;
}
diff --git a/drivers/clocksource/dw_apb_timer_of.c b/drivers/clocksource/dw_apb_timer_of.c
index a19a3f6..860843c 100644
--- a/drivers/clocksource/dw_apb_timer_of.c
+++ b/drivers/clocksource/dw_apb_timer_of.c
@@ -16,6 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/delay.h>
#include <linux/dw_apb_timer.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -130,6 +131,17 @@ static void __init init_sched_clock(void)
sched_clock_register(read_sched_clock, 32, sched_rate);
}
+#ifdef CONFIG_ARM
+static unsigned long dw_apb_delay_timer_read(void)
+{
+ return ~readl_relaxed(sched_io_base);
+}
+
+static struct delay_timer dw_apb_delay_timer = {
+ .read_current_timer = dw_apb_delay_timer_read,
+};
+#endif
+
static int num_called;
static void __init dw_apb_timer_init(struct device_node *timer)
{
@@ -142,6 +154,10 @@ static void __init dw_apb_timer_init(struct device_node *timer)
pr_debug("%s: found clocksource timer\n", __func__);
add_clocksource(timer);
init_sched_clock();
+#ifdef CONFIG_ARM
+ dw_apb_delay_timer.freq = sched_rate;
+ register_current_timer_delay(&dw_apb_delay_timer);
+#endif
break;
default:
break;
diff --git a/drivers/clocksource/fsl_ftm_timer.c b/drivers/clocksource/fsl_ftm_timer.c
index 10202f1..517e1c7 100644
--- a/drivers/clocksource/fsl_ftm_timer.c
+++ b/drivers/clocksource/fsl_ftm_timer.c
@@ -203,7 +203,7 @@ static int __init ftm_clockevent_init(unsigned long freq, int irq)
int err;
ftm_writel(0x00, priv->clkevt_base + FTM_CNTIN);
- ftm_writel(~0UL, priv->clkevt_base + FTM_MOD);
+ ftm_writel(~0u, priv->clkevt_base + FTM_MOD);
ftm_reset_counter(priv->clkevt_base);
@@ -230,7 +230,7 @@ static int __init ftm_clocksource_init(unsigned long freq)
int err;
ftm_writel(0x00, priv->clksrc_base + FTM_CNTIN);
- ftm_writel(~0UL, priv->clksrc_base + FTM_MOD);
+ ftm_writel(~0u, priv->clksrc_base + FTM_MOD);
ftm_reset_counter(priv->clksrc_base);
diff --git a/drivers/clocksource/h8300_timer16.c b/drivers/clocksource/h8300_timer16.c
index 0e076c6..75c4407 100644
--- a/drivers/clocksource/h8300_timer16.c
+++ b/drivers/clocksource/h8300_timer16.c
@@ -4,85 +4,56 @@
* Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
*/
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
#include <linux/clocksource.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
-
-#include <asm/segment.h>
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#define TSTR 0
-#define TSNC 1
-#define TMDR 2
-#define TOLR 3
-#define TISRA 4
-#define TISRB 5
#define TISRC 6
#define TCR 0
-#define TIOR 1
#define TCNT 2
-#define GRA 4
-#define GRB 6
-
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
-#define FLAG_STARTED (1 << 3)
-#define ONESHOT 0
-#define PERIODIC 1
-
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
struct timer16_priv {
- struct platform_device *pdev;
struct clocksource cs;
- struct irqaction irqaction;
unsigned long total_cycles;
- unsigned long mapbase;
- unsigned long mapcommon;
- unsigned long flags;
- unsigned short gra;
+ void __iomem *mapbase;
+ void __iomem *mapcommon;
unsigned short cs_enabled;
unsigned char enb;
- unsigned char imfa;
- unsigned char imiea;
unsigned char ovf;
- raw_spinlock_t lock;
- struct clk *clk;
+ unsigned char ovie;
};
static unsigned long timer16_get_counter(struct timer16_priv *p)
{
- unsigned long v1, v2, v3;
- int o1, o2;
+ unsigned short v1, v2, v3;
+ unsigned char o1, o2;
- o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+ o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
o2 = o1;
- v1 = ctrl_inw(p->mapbase + TCNT);
- v2 = ctrl_inw(p->mapbase + TCNT);
- v3 = ctrl_inw(p->mapbase + TCNT);
- o1 = ctrl_inb(p->mapcommon + TISRC) & p->ovf;
+ v1 = ioread16be(p->mapbase + TCNT);
+ v2 = ioread16be(p->mapbase + TCNT);
+ v3 = ioread16be(p->mapbase + TCNT);
+ o1 = ioread8(p->mapcommon + TISRC) & p->ovf;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
- v2 |= 0x10000;
- return v2;
+ if (likely(!o1))
+ return v2;
+ else
+ return v2 + 0x10000;
}
@@ -90,8 +61,7 @@ static irqreturn_t timer16_interrupt(int irq, void *dev_id)
{
struct timer16_priv *p = (struct timer16_priv *)dev_id;
- ctrl_outb(ctrl_inb(p->mapcommon + TISRA) & ~p->imfa,
- p->mapcommon + TISRA);
+ bclr(p->ovf, p->mapcommon + TISRC);
p->total_cycles += 0x10000;
return IRQ_HANDLED;
@@ -105,13 +75,10 @@ static inline struct timer16_priv *cs_to_priv(struct clocksource *cs)
static cycle_t timer16_clocksource_read(struct clocksource *cs)
{
struct timer16_priv *p = cs_to_priv(cs);
- unsigned long flags, raw;
- unsigned long value;
+ unsigned long raw, value;
- raw_spin_lock_irqsave(&p->lock, flags);
value = p->total_cycles;
raw = timer16_get_counter(p);
- raw_spin_unlock_irqrestore(&p->lock, flags);
return value + raw;
}
@@ -123,10 +90,10 @@ static int timer16_enable(struct clocksource *cs)
WARN_ON(p->cs_enabled);
p->total_cycles = 0;
- ctrl_outw(0x0000, p->mapbase + TCNT);
- ctrl_outb(0x83, p->mapbase + TCR);
- ctrl_outb(ctrl_inb(p->mapcommon + TSTR) | p->enb,
- p->mapcommon + TSTR);
+ iowrite16be(0x0000, p->mapbase + TCNT);
+ iowrite8(0x83, p->mapbase + TCR);
+ bset(p->ovie, p->mapcommon + TISRC);
+ bset(p->enb, p->mapcommon + TSTR);
p->cs_enabled = true;
return 0;
@@ -138,116 +105,83 @@ static void timer16_disable(struct clocksource *cs)
WARN_ON(!p->cs_enabled);
- ctrl_outb(ctrl_inb(p->mapcommon + TSTR) & ~p->enb,
- p->mapcommon + TSTR);
+ bclr(p->ovie, p->mapcommon + TISRC);
+ bclr(p->enb, p->mapcommon + TSTR);
p->cs_enabled = false;
}
+static struct timer16_priv timer16_priv = {
+ .cs = {
+ .name = "h8300_16timer",
+ .rating = 200,
+ .read = timer16_clocksource_read,
+ .enable = timer16_enable,
+ .disable = timer16_disable,
+ .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ },
+};
+
#define REG_CH 0
#define REG_COMM 1
-static int timer16_setup(struct timer16_priv *p, struct platform_device *pdev)
+static void __init h8300_16timer_init(struct device_node *node)
{
- struct resource *res[2];
+ void __iomem *base[2];
int ret, irq;
unsigned int ch;
+ struct clk *clk;
- p->pdev = pdev;
-
- res[REG_CH] = platform_get_resource(p->pdev,
- IORESOURCE_MEM, REG_CH);
- res[REG_COMM] = platform_get_resource(p->pdev,
- IORESOURCE_MEM, REG_COMM);
- if (!res[REG_CH] || !res[REG_COMM]) {
- dev_err(&p->pdev->dev, "failed to get I/O memory\n");
- return -ENXIO;
- }
- irq = platform_get_irq(p->pdev, 0);
- if (irq < 0) {
- dev_err(&p->pdev->dev, "failed to get irq\n");
- return irq;
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("failed to get clock for clocksource\n");
+ return;
}
- p->clk = clk_get(&p->pdev->dev, "fck");
- if (IS_ERR(p->clk)) {
- dev_err(&p->pdev->dev, "can't get clk\n");
- return PTR_ERR(p->clk);
+ base[REG_CH] = of_iomap(node, 0);
+ if (!base[REG_CH]) {
+ pr_err("failed to map registers for clocksource\n");
+ goto free_clk;
}
- of_property_read_u32(p->pdev->dev.of_node, "renesas,channel", &ch);
-
- p->pdev = pdev;
- p->mapbase = res[REG_CH]->start;
- p->mapcommon = res[REG_COMM]->start;
- p->enb = 1 << ch;
- p->imfa = 1 << ch;
- p->imiea = 1 << (4 + ch);
- p->cs.name = pdev->name;
- p->cs.rating = 200;
- p->cs.read = timer16_clocksource_read;
- p->cs.enable = timer16_enable;
- p->cs.disable = timer16_disable;
- p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
- p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
- ret = request_irq(irq, timer16_interrupt,
- IRQF_TIMER, pdev->name, p);
- if (ret < 0) {
- dev_err(&p->pdev->dev, "failed to request irq %d\n", irq);
- return ret;
+ base[REG_COMM] = of_iomap(node, 1);
+ if (!base[REG_COMM]) {
+ pr_err("failed to map registers for clocksource\n");
+ goto unmap_ch;
}
- clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 8);
-
- return 0;
-}
-
-static int timer16_probe(struct platform_device *pdev)
-{
- struct timer16_priv *p = platform_get_drvdata(pdev);
-
- if (p) {
- dev_info(&pdev->dev, "kept as earlytimer\n");
- return 0;
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ pr_err("failed to get irq for clockevent\n");
+ goto unmap_comm;
}
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
+ of_property_read_u32(node, "renesas,channel", &ch);
- return timer16_setup(p, pdev);
-}
-
-static int timer16_remove(struct platform_device *pdev)
-{
- return -EBUSY;
-}
+ timer16_priv.mapbase = base[REG_CH];
+ timer16_priv.mapcommon = base[REG_COMM];
+ timer16_priv.enb = ch;
+ timer16_priv.ovf = ch;
+ timer16_priv.ovie = 4 + ch;
-static const struct of_device_id timer16_of_table[] = {
- { .compatible = "renesas,16bit-timer" },
- { }
-};
-static struct platform_driver timer16_driver = {
- .probe = timer16_probe,
- .remove = timer16_remove,
- .driver = {
- .name = "h8300h-16timer",
- .of_match_table = of_match_ptr(timer16_of_table),
+ ret = request_irq(irq, timer16_interrupt,
+ IRQF_TIMER, timer16_priv.cs.name, &timer16_priv);
+ if (ret < 0) {
+ pr_err("failed to request irq %d of clocksource\n", irq);
+ goto unmap_comm;
}
-};
-static int __init timer16_init(void)
-{
- return platform_driver_register(&timer16_driver);
-}
+ clocksource_register_hz(&timer16_priv.cs,
+ clk_get_rate(clk) / 8);
+ return;
-static void __exit timer16_exit(void)
-{
- platform_driver_unregister(&timer16_driver);
+unmap_comm:
+ iounmap(base[REG_COMM]);
+unmap_ch:
+ iounmap(base[REG_CH]);
+free_clk:
+ clk_put(clk);
}
-subsys_initcall(timer16_init);
-module_exit(timer16_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300H 16bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_16bit, "renesas,16bit-timer", h8300_16timer_init);
diff --git a/drivers/clocksource/h8300_timer8.c b/drivers/clocksource/h8300_timer8.c
index 44375d8..c151941 100644
--- a/drivers/clocksource/h8300_timer8.c
+++ b/drivers/clocksource/h8300_timer8.c
@@ -8,19 +8,15 @@
*/
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
#include <linux/clockchips.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
-
-#include <asm/irq.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
#define _8TCR 0
#define _8TCSR 2
@@ -28,126 +24,74 @@
#define TCORB 6
#define _8TCNT 8
-#define FLAG_REPROGRAM (1 << 0)
-#define FLAG_SKIPEVENT (1 << 1)
-#define FLAG_IRQCONTEXT (1 << 2)
+#define CMIEA 6
+#define CMFA 6
+
#define FLAG_STARTED (1 << 3)
-#define ONESHOT 0
-#define PERIODIC 1
+#define SCALE 64
-#define RELATIVE 0
-#define ABSOLUTE 1
+#define bset(b, a) iowrite8(ioread8(a) | (1 << (b)), (a))
+#define bclr(b, a) iowrite8(ioread8(a) & ~(1 << (b)), (a))
struct timer8_priv {
- struct platform_device *pdev;
struct clock_event_device ced;
- struct irqaction irqaction;
- unsigned long mapbase;
- raw_spinlock_t lock;
+ void __iomem *mapbase;
unsigned long flags;
unsigned int rate;
- unsigned int tcora;
- struct clk *pclk;
};
-static unsigned long timer8_get_counter(struct timer8_priv *p)
-{
- unsigned long v1, v2, v3;
- int o1, o2;
-
- o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
-
- /* Make sure the timer value is stable. Stolen from acpi_pm.c */
- do {
- o2 = o1;
- v1 = ctrl_inw(p->mapbase + _8TCNT);
- v2 = ctrl_inw(p->mapbase + _8TCNT);
- v3 = ctrl_inw(p->mapbase + _8TCNT);
- o1 = ctrl_inb(p->mapbase + _8TCSR) & 0x20;
- } while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
- || (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
-
- v2 |= o1 << 10;
- return v2;
-}
-
static irqreturn_t timer8_interrupt(int irq, void *dev_id)
{
struct timer8_priv *p = dev_id;
- ctrl_outb(ctrl_inb(p->mapbase + _8TCSR) & ~0x40,
- p->mapbase + _8TCSR);
- p->flags |= FLAG_IRQCONTEXT;
- ctrl_outw(p->tcora, p->mapbase + TCORA);
- if (!(p->flags & FLAG_SKIPEVENT)) {
- if (clockevent_state_oneshot(&p->ced))
- ctrl_outw(0x0000, p->mapbase + _8TCR);
- p->ced.event_handler(&p->ced);
- }
- p->flags &= ~(FLAG_SKIPEVENT | FLAG_IRQCONTEXT);
+ if (clockevent_state_oneshot(&p->ced))
+ iowrite16be(0x0000, p->mapbase + _8TCR);
+
+ p->ced.event_handler(&p->ced);
+
+ bclr(CMFA, p->mapbase + _8TCSR);
return IRQ_HANDLED;
}
static void timer8_set_next(struct timer8_priv *p, unsigned long delta)
{
- unsigned long flags;
- unsigned long now;
-
- raw_spin_lock_irqsave(&p->lock, flags);
if (delta >= 0x10000)
- dev_warn(&p->pdev->dev, "delta out of range\n");
- now = timer8_get_counter(p);
- p->tcora = delta;
- ctrl_outb(ctrl_inb(p->mapbase + _8TCR) | 0x40, p->mapbase + _8TCR);
- if (delta > now)
- ctrl_outw(delta, p->mapbase + TCORA);
- else
- ctrl_outw(now + 1, p->mapbase + TCORA);
-
- raw_spin_unlock_irqrestore(&p->lock, flags);
+ pr_warn("delta out of range\n");
+ bclr(CMIEA, p->mapbase + _8TCR);
+ iowrite16be(delta, p->mapbase + TCORA);
+ iowrite16be(0x0000, p->mapbase + _8TCNT);
+ bclr(CMFA, p->mapbase + _8TCSR);
+ bset(CMIEA, p->mapbase + _8TCR);
}
static int timer8_enable(struct timer8_priv *p)
{
- p->rate = clk_get_rate(p->pclk) / 64;
- ctrl_outw(0xffff, p->mapbase + TCORA);
- ctrl_outw(0x0000, p->mapbase + _8TCNT);
- ctrl_outw(0x0c02, p->mapbase + _8TCR);
+ iowrite16be(0xffff, p->mapbase + TCORA);
+ iowrite16be(0x0000, p->mapbase + _8TCNT);
+ iowrite16be(0x0c02, p->mapbase + _8TCR);
return 0;
}
static int timer8_start(struct timer8_priv *p)
{
- int ret = 0;
- unsigned long flags;
-
- raw_spin_lock_irqsave(&p->lock, flags);
-
- if (!(p->flags & FLAG_STARTED))
- ret = timer8_enable(p);
+ int ret;
- if (ret)
- goto out;
- p->flags |= FLAG_STARTED;
+ if ((p->flags & FLAG_STARTED))
+ return 0;
- out:
- raw_spin_unlock_irqrestore(&p->lock, flags);
+ ret = timer8_enable(p);
+ if (!ret)
+ p->flags |= FLAG_STARTED;
return ret;
}
static void timer8_stop(struct timer8_priv *p)
{
- unsigned long flags;
-
- raw_spin_lock_irqsave(&p->lock, flags);
-
- ctrl_outw(0x0000, p->mapbase + _8TCR);
-
- raw_spin_unlock_irqrestore(&p->lock, flags);
+ iowrite16be(0x0000, p->mapbase + _8TCR);
}
static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
@@ -155,7 +99,7 @@ static inline struct timer8_priv *ced_to_priv(struct clock_event_device *ced)
return container_of(ced, struct timer8_priv, ced);
}
-static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
+static void timer8_clock_event_start(struct timer8_priv *p, unsigned long delta)
{
struct clock_event_device *ced = &p->ced;
@@ -166,7 +110,7 @@ static void timer8_clock_event_start(struct timer8_priv *p, int periodic)
ced->max_delta_ns = clockevent_delta2ns(0xffff, ced);
ced->min_delta_ns = clockevent_delta2ns(0x0001, ced);
- timer8_set_next(p, periodic?(p->rate + HZ/2) / HZ:0x10000);
+ timer8_set_next(p, delta);
}
static int timer8_clock_event_shutdown(struct clock_event_device *ced)
@@ -179,9 +123,9 @@ static int timer8_clock_event_periodic(struct clock_event_device *ced)
{
struct timer8_priv *p = ced_to_priv(ced);
- dev_info(&p->pdev->dev, "used for periodic clock events\n");
+ pr_info("%s: used for periodic clock events\n", ced->name);
timer8_stop(p);
- timer8_clock_event_start(p, PERIODIC);
+ timer8_clock_event_start(p, (p->rate + HZ/2) / HZ);
return 0;
}
@@ -190,9 +134,9 @@ static int timer8_clock_event_oneshot(struct clock_event_device *ced)
{
struct timer8_priv *p = ced_to_priv(ced);
- dev_info(&p->pdev->dev, "used for oneshot clock events\n");
+ pr_info("%s: used for oneshot clock events\n", ced->name);
timer8_stop(p);
- timer8_clock_event_start(p, ONESHOT);
+ timer8_clock_event_start(p, 0x10000);
return 0;
}
@@ -208,110 +152,64 @@ static int timer8_clock_event_next(unsigned long delta,
return 0;
}
-static int timer8_setup(struct timer8_priv *p,
- struct platform_device *pdev)
+static struct timer8_priv timer8_priv = {
+ .ced = {
+ .name = "h8300_8timer",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 200,
+ .set_next_event = timer8_clock_event_next,
+ .set_state_shutdown = timer8_clock_event_shutdown,
+ .set_state_periodic = timer8_clock_event_periodic,
+ .set_state_oneshot = timer8_clock_event_oneshot,
+ },
+};
+
+static void __init h8300_8timer_init(struct device_node *node)
{
- struct resource *res;
+ void __iomem *base;
int irq;
- int ret;
+ struct clk *clk;
- p->pdev = pdev;
-
- res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&p->pdev->dev, "failed to get I/O memory\n");
- return -ENXIO;
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("failed to get clock for clockevent\n");
+ return;
}
- irq = platform_get_irq(p->pdev, 0);
- if (irq < 0) {
- dev_err(&p->pdev->dev, "failed to get irq\n");
- return -ENXIO;
+ base = of_iomap(node, 0);
+ if (!base) {
+ pr_err("failed to map registers for clockevent\n");
+ goto free_clk;
}
- p->mapbase = res->start;
-
- p->irqaction.name = dev_name(&p->pdev->dev);
- p->irqaction.handler = timer8_interrupt;
- p->irqaction.dev_id = p;
- p->irqaction.flags = IRQF_TIMER;
-
- p->pclk = clk_get(&p->pdev->dev, "fck");
- if (IS_ERR(p->pclk)) {
- dev_err(&p->pdev->dev, "can't get clk\n");
- return PTR_ERR(p->pclk);
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ pr_err("failed to get irq for clockevent\n");
+ goto unmap_reg;
}
- p->ced.name = pdev->name;
- p->ced.features = CLOCK_EVT_FEAT_PERIODIC |
- CLOCK_EVT_FEAT_ONESHOT;
- p->ced.rating = 200;
- p->ced.cpumask = cpumask_of(0);
- p->ced.set_next_event = timer8_clock_event_next;
- p->ced.set_state_shutdown = timer8_clock_event_shutdown;
- p->ced.set_state_periodic = timer8_clock_event_periodic;
- p->ced.set_state_oneshot = timer8_clock_event_oneshot;
-
- ret = setup_irq(irq, &p->irqaction);
- if (ret < 0) {
- dev_err(&p->pdev->dev,
- "failed to request irq %d\n", irq);
- return ret;
- }
- clockevents_register_device(&p->ced);
- platform_set_drvdata(pdev, p);
+ timer8_priv.mapbase = base;
- return 0;
-}
-
-static int timer8_probe(struct platform_device *pdev)
-{
- struct timer8_priv *p = platform_get_drvdata(pdev);
-
- if (p) {
- dev_info(&pdev->dev, "kept as earlytimer\n");
- return 0;
+ timer8_priv.rate = clk_get_rate(clk) / SCALE;
+ if (!timer8_priv.rate) {
+ pr_err("Failed to get rate for the clocksource\n");
+ goto unmap_reg;
}
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
-
- return timer8_setup(p, pdev);
-}
-
-static int timer8_remove(struct platform_device *pdev)
-{
- return -EBUSY;
-}
-
-static const struct of_device_id timer8_of_table[] __maybe_unused = {
- { .compatible = "renesas,8bit-timer" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, timer8_of_table);
-static struct platform_driver timer8_driver = {
- .probe = timer8_probe,
- .remove = timer8_remove,
- .driver = {
- .name = "h8300-8timer",
- .of_match_table = of_match_ptr(timer8_of_table),
+ if (request_irq(irq, timer8_interrupt, IRQF_TIMER,
+ timer8_priv.ced.name, &timer8_priv) < 0) {
+ pr_err("failed to request irq %d for clockevent\n", irq);
+ goto unmap_reg;
}
-};
-static int __init timer8_init(void)
-{
- return platform_driver_register(&timer8_driver);
-}
+ clockevents_config_and_register(&timer8_priv.ced,
+ timer8_priv.rate, 1, 0x0000ffff);
-static void __exit timer8_exit(void)
-{
- platform_driver_unregister(&timer8_driver);
+ return;
+unmap_reg:
+ iounmap(base);
+free_clk:
+ clk_put(clk);
}
-subsys_initcall(timer8_init);
-module_exit(timer8_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8/300 8bit Timer Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_8bit, "renesas,8bit-timer", h8300_8timer_init);
diff --git a/drivers/clocksource/h8300_tpu.c b/drivers/clocksource/h8300_tpu.c
index 5487410..d4c1a28 100644
--- a/drivers/clocksource/h8300_tpu.c
+++ b/drivers/clocksource/h8300_tpu.c
@@ -1,42 +1,30 @@
/*
- * H8/300 TPU Driver
+ * H8S TPU Driver
*
* Copyright 2015 Yoshinori Sato <ysato@users.sourcefoge.jp>
*
*/
#include <linux/errno.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
#include <linux/clocksource.h>
-#include <linux/module.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
-#include <asm/irq.h>
+#define TCR 0x0
+#define TSR 0x5
+#define TCNT 0x6
-#define TCR 0
-#define TMDR 1
-#define TIOR 2
-#define TER 4
-#define TSR 5
-#define TCNT 6
-#define TGRA 8
-#define TGRB 10
-#define TGRC 12
-#define TGRD 14
+#define TCFV 0x10
struct tpu_priv {
- struct platform_device *pdev;
struct clocksource cs;
- struct clk *clk;
- unsigned long mapbase1;
- unsigned long mapbase2;
+ void __iomem *mapbase1;
+ void __iomem *mapbase2;
raw_spinlock_t lock;
unsigned int cs_enabled;
};
@@ -45,8 +33,8 @@ static inline unsigned long read_tcnt32(struct tpu_priv *p)
{
unsigned long tcnt;
- tcnt = ctrl_inw(p->mapbase1 + TCNT) << 16;
- tcnt |= ctrl_inw(p->mapbase2 + TCNT);
+ tcnt = ioread16be(p->mapbase1 + TCNT) << 16;
+ tcnt |= ioread16be(p->mapbase2 + TCNT);
return tcnt;
}
@@ -55,7 +43,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
unsigned long v1, v2, v3;
int o1, o2;
- o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+ o1 = ioread8(p->mapbase1 + TSR) & TCFV;
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
do {
@@ -63,7 +51,7 @@ static int tpu_get_counter(struct tpu_priv *p, unsigned long long *val)
v1 = read_tcnt32(p);
v2 = read_tcnt32(p);
v3 = read_tcnt32(p);
- o1 = ctrl_inb(p->mapbase1 + TSR) & 0x10;
+ o1 = ioread8(p->mapbase1 + TSR) & TCFV;
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
@@ -96,10 +84,10 @@ static int tpu_clocksource_enable(struct clocksource *cs)
WARN_ON(p->cs_enabled);
- ctrl_outw(0, p->mapbase1 + TCNT);
- ctrl_outw(0, p->mapbase2 + TCNT);
- ctrl_outb(0x0f, p->mapbase1 + TCR);
- ctrl_outb(0x03, p->mapbase2 + TCR);
+ iowrite16be(0, p->mapbase1 + TCNT);
+ iowrite16be(0, p->mapbase2 + TCNT);
+ iowrite8(0x0f, p->mapbase1 + TCR);
+ iowrite8(0x03, p->mapbase2 + TCR);
p->cs_enabled = true;
return 0;
@@ -111,96 +99,59 @@ static void tpu_clocksource_disable(struct clocksource *cs)
WARN_ON(!p->cs_enabled);
- ctrl_outb(0, p->mapbase1 + TCR);
- ctrl_outb(0, p->mapbase2 + TCR);
+ iowrite8(0, p->mapbase1 + TCR);
+ iowrite8(0, p->mapbase2 + TCR);
p->cs_enabled = false;
}
+static struct tpu_priv tpu_priv = {
+ .cs = {
+ .name = "H8S_TPU",
+ .rating = 200,
+ .read = tpu_clocksource_read,
+ .enable = tpu_clocksource_enable,
+ .disable = tpu_clocksource_disable,
+ .mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ },
+};
+
#define CH_L 0
#define CH_H 1
-static int __init tpu_setup(struct tpu_priv *p, struct platform_device *pdev)
+static void __init h8300_tpu_init(struct device_node *node)
{
- struct resource *res[2];
-
- p->pdev = pdev;
+ void __iomem *base[2];
+ struct clk *clk;
- res[CH_L] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_L);
- res[CH_H] = platform_get_resource(p->pdev, IORESOURCE_MEM, CH_H);
- if (!res[CH_L] || !res[CH_H]) {
- dev_err(&p->pdev->dev, "failed to get I/O memory\n");
- return -ENXIO;
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("failed to get clock for clocksource\n");
+ return;
}
- p->clk = clk_get(&p->pdev->dev, "fck");
- if (IS_ERR(p->clk)) {
- dev_err(&p->pdev->dev, "can't get clk\n");
- return PTR_ERR(p->clk);
+ base[CH_L] = of_iomap(node, CH_L);
+ if (!base[CH_L]) {
+ pr_err("failed to map registers for clocksource\n");
+ goto free_clk;
}
-
- p->mapbase1 = res[CH_L]->start;
- p->mapbase2 = res[CH_H]->start;
-
- p->cs.name = pdev->name;
- p->cs.rating = 200;
- p->cs.read = tpu_clocksource_read;
- p->cs.enable = tpu_clocksource_enable;
- p->cs.disable = tpu_clocksource_disable;
- p->cs.mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
- p->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
- clocksource_register_hz(&p->cs, clk_get_rate(p->clk) / 64);
- platform_set_drvdata(pdev, p);
-
- return 0;
-}
-
-static int tpu_probe(struct platform_device *pdev)
-{
- struct tpu_priv *p = platform_get_drvdata(pdev);
-
- if (p) {
- dev_info(&pdev->dev, "kept as earlytimer\n");
- return 0;
+ base[CH_H] = of_iomap(node, CH_H);
+ if (!base[CH_H]) {
+ pr_err("failed to map registers for clocksource\n");
+ goto unmap_L;
}
- p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
- if (!p)
- return -ENOMEM;
+ tpu_priv.mapbase1 = base[CH_L];
+ tpu_priv.mapbase2 = base[CH_H];
- return tpu_setup(p, pdev);
-}
-
-static int tpu_remove(struct platform_device *pdev)
-{
- return -EBUSY;
-}
-
-static const struct of_device_id tpu_of_table[] = {
- { .compatible = "renesas,tpu" },
- { }
-};
+ clocksource_register_hz(&tpu_priv.cs, clk_get_rate(clk) / 64);
-static struct platform_driver tpu_driver = {
- .probe = tpu_probe,
- .remove = tpu_remove,
- .driver = {
- .name = "h8s-tpu",
- .of_match_table = of_match_ptr(tpu_of_table),
- }
-};
-
-static int __init tpu_init(void)
-{
- return platform_driver_register(&tpu_driver);
-}
+ return;
-static void __exit tpu_exit(void)
-{
- platform_driver_unregister(&tpu_driver);
+unmap_L:
+ iounmap(base[CH_H]);
+free_clk:
+ clk_put(clk);
}
-subsys_initcall(tpu_init);
-module_exit(tpu_exit);
-MODULE_AUTHOR("Yoshinori Sato");
-MODULE_DESCRIPTION("H8S Timer Pulse Unit Driver");
-MODULE_LICENSE("GPL v2");
+CLOCKSOURCE_OF_DECLARE(h8300_tpu, "renesas,tpu", h8300_tpu_init);
diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c
index 02a1945..89d3e4d 100644
--- a/drivers/clocksource/mips-gic-timer.c
+++ b/drivers/clocksource/mips-gic-timer.c
@@ -140,9 +140,10 @@ static cycle_t gic_hpt_read(struct clocksource *cs)
}
static struct clocksource gic_clocksource = {
- .name = "GIC",
- .read = gic_hpt_read,
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .name = "GIC",
+ .read = gic_hpt_read,
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .archdata = { .vdso_clock_mode = VDSO_CLOCK_GIC },
};
static void __init __gic_clocksource_init(void)
diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c
index 1593ade..c4f7d7a 100644
--- a/drivers/clocksource/mmio.c
+++ b/drivers/clocksource/mmio.c
@@ -55,7 +55,7 @@ int __init clocksource_mmio_init(void __iomem *base, const char *name,
{
struct clocksource_mmio *cs;
- if (bits > 32 || bits < 16)
+ if (bits > 64 || bits < 16)
return -EINVAL;
cs = kzalloc(sizeof(struct clocksource_mmio), GFP_KERNEL);
diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c
index fbfc746..d67bc35 100644
--- a/drivers/clocksource/mtk_timer.c
+++ b/drivers/clocksource/mtk_timer.c
@@ -16,6 +16,8 @@
* GNU General Public License for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/interrupt.h>
@@ -187,10 +189,8 @@ static void __init mtk_timer_init(struct device_node *node)
struct clk *clk;
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
- if (!evt) {
- pr_warn("Can't allocate mtk clock event driver struct");
+ if (!evt)
return;
- }
evt->dev.name = "mtk_tick";
evt->dev.rating = 300;
@@ -204,31 +204,31 @@ static void __init mtk_timer_init(struct device_node *node)
evt->gpt_base = of_io_request_and_map(node, 0, "mtk-timer");
if (IS_ERR(evt->gpt_base)) {
- pr_warn("Can't get resource\n");
- return;
+ pr_err("Can't get resource\n");
+ goto err_kzalloc;
}
evt->dev.irq = irq_of_parse_and_map(node, 0);
if (evt->dev.irq <= 0) {
- pr_warn("Can't parse IRQ");
+ pr_err("Can't parse IRQ\n");
goto err_mem;
}
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
- pr_warn("Can't get timer clock");
+ pr_err("Can't get timer clock\n");
goto err_irq;
}
if (clk_prepare_enable(clk)) {
- pr_warn("Can't prepare clock");
+ pr_err("Can't prepare clock\n");
goto err_clk_put;
}
rate = clk_get_rate(clk);
if (request_irq(evt->dev.irq, mtk_timer_interrupt,
IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
- pr_warn("failed to setup irq %d\n", evt->dev.irq);
+ pr_err("failed to setup irq %d\n", evt->dev.irq);
goto err_clk_disable;
}
@@ -260,5 +260,7 @@ err_mem:
iounmap(evt->gpt_base);
of_address_to_resource(node, 0, &res);
release_mem_region(res.start, resource_size(&res));
+err_kzalloc:
+ kfree(evt);
}
CLOCKSOURCE_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer", mtk_timer_init);
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index d3c1742..8c77a52 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -17,16 +17,16 @@
#define TIMER_NAME "rk_timer"
-#define TIMER_LOAD_COUNT0 0x00
-#define TIMER_LOAD_COUNT1 0x04
-#define TIMER_CONTROL_REG 0x10
-#define TIMER_INT_STATUS 0x18
+#define TIMER_LOAD_COUNT0 0x00
+#define TIMER_LOAD_COUNT1 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_INT_STATUS 0x18
-#define TIMER_DISABLE 0x0
-#define TIMER_ENABLE 0x1
-#define TIMER_MODE_FREE_RUNNING (0 << 1)
-#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
-#define TIMER_INT_UNMASK (1 << 2)
+#define TIMER_DISABLE 0x0
+#define TIMER_ENABLE 0x1
+#define TIMER_MODE_FREE_RUNNING (0 << 1)
+#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
+#define TIMER_INT_UNMASK (1 << 2)
struct bc_timer {
struct clock_event_device ce;
@@ -49,14 +49,12 @@ static inline void __iomem *rk_base(struct clock_event_device *ce)
static inline void rk_timer_disable(struct clock_event_device *ce)
{
writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
- dsb();
}
static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
{
writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
rk_base(ce) + TIMER_CONTROL_REG);
- dsb();
}
static void rk_timer_update_counter(unsigned long cycles,
@@ -64,13 +62,11 @@ static void rk_timer_update_counter(unsigned long cycles,
{
writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
- dsb();
}
static void rk_timer_interrupt_clear(struct clock_event_device *ce)
{
writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
- dsb();
}
static inline int rk_timer_set_next_event(unsigned long cycles,
@@ -173,4 +169,5 @@ static void __init rk_timer_init(struct device_node *np)
clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
}
+
CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
diff --git a/drivers/clocksource/tango_xtal.c b/drivers/clocksource/tango_xtal.c
index d297b30..2bcecaf 100644
--- a/drivers/clocksource/tango_xtal.c
+++ b/drivers/clocksource/tango_xtal.c
@@ -19,19 +19,6 @@ static u64 notrace read_sched_clock(void)
return read_xtal_counter();
}
-static cycle_t read_clocksource(struct clocksource *cs)
-{
- return read_xtal_counter();
-}
-
-static struct clocksource tango_xtal = {
- .name = "tango-xtal",
- .rating = 350,
- .read = read_clocksource,
- .mask = CLOCKSOURCE_MASK(32),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
-};
-
static void __init tango_clocksource_init(struct device_node *np)
{
struct clk *clk;
@@ -53,8 +40,9 @@ static void __init tango_clocksource_init(struct device_node *np)
delay_timer.freq = xtal_freq;
delay_timer.read_current_timer = read_xtal_counter;
- ret = clocksource_register_hz(&tango_xtal, xtal_freq);
- if (ret != 0) {
+ ret = clocksource_mmio_init(xtal_in_cnt, "tango-xtal", xtal_freq, 350,
+ 32, clocksource_mmio_readl_up);
+ if (!ret) {
pr_err("%s: registration failed\n", np->full_name);
return;
}
diff --git a/drivers/clocksource/tcb_clksrc.c b/drivers/clocksource/tcb_clksrc.c
index d28d2fe..6ee9140 100644
--- a/drivers/clocksource/tcb_clksrc.c
+++ b/drivers/clocksource/tcb_clksrc.c
@@ -193,10 +193,17 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
struct clk *t2_clk = tc->clk[2];
int irq = tc->irq[2];
+ ret = clk_prepare_enable(tc->slow_clk);
+ if (ret)
+ return ret;
+
/* try to enable t2 clk to avoid future errors in mode change */
ret = clk_prepare_enable(t2_clk);
- if (ret)
+ if (ret) {
+ clk_disable_unprepare(tc->slow_clk);
return ret;
+ }
+
clk_disable(t2_clk);
clkevt.regs = tc->regs;
@@ -208,7 +215,8 @@ static int __init setup_clkevents(struct atmel_tc *tc, int clk32k_divisor_idx)
ret = request_irq(irq, ch2_irq, IRQF_TIMER, "tc_clkevt", &clkevt);
if (ret) {
- clk_disable_unprepare(t2_clk);
+ clk_unprepare(t2_clk);
+ clk_disable_unprepare(tc->slow_clk);
return ret;
}
diff --git a/drivers/clocksource/tegra20_timer.c b/drivers/clocksource/tegra20_timer.c
index 6ebda11..38333ab 100644
--- a/drivers/clocksource/tegra20_timer.c
+++ b/drivers/clocksource/tegra20_timer.c
@@ -96,7 +96,8 @@ static struct clock_event_device tegra_clockevent = {
.name = "timer0",
.rating = 300,
.features = CLOCK_EVT_FEAT_ONESHOT |
- CLOCK_EVT_FEAT_PERIODIC,
+ CLOCK_EVT_FEAT_PERIODIC |
+ CLOCK_EVT_FEAT_DYNIRQ,
.set_next_event = tegra_timer_set_next_event,
.set_state_shutdown = tegra_timer_shutdown,
.set_state_periodic = tegra_timer_set_periodic,
diff --git a/drivers/clocksource/time-lpc32xx.c b/drivers/clocksource/time-lpc32xx.c
index a1c06a2..1316876 100644
--- a/drivers/clocksource/time-lpc32xx.c
+++ b/drivers/clocksource/time-lpc32xx.c
@@ -125,7 +125,7 @@ static int __init lpc32xx_clocksource_init(struct device_node *np)
clk = of_clk_get_by_name(np, "timerclk");
if (IS_ERR(clk)) {
- pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+ pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
return PTR_ERR(clk);
}
@@ -184,7 +184,7 @@ static int __init lpc32xx_clockevent_init(struct device_node *np)
clk = of_clk_get_by_name(np, "timerclk");
if (IS_ERR(clk)) {
- pr_err("clock get failed (%lu)\n", PTR_ERR(clk));
+ pr_err("clock get failed (%ld)\n", PTR_ERR(clk));
return PTR_ERR(clk);
}
diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c
index bba6799..3269d9e 100644
--- a/drivers/clocksource/time-pistachio.c
+++ b/drivers/clocksource/time-pistachio.c
@@ -84,7 +84,7 @@ pistachio_clocksource_read_cycles(struct clocksource *cs)
counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0);
raw_spin_unlock_irqrestore(&pcs->lock, flags);
- return ~(cycle_t)counter;
+ return (cycle_t)~counter;
}
static u64 notrace pistachio_read_sched_clock(void)
diff --git a/drivers/clocksource/timer-atmel-st.c b/drivers/clocksource/timer-atmel-st.c
index 41b7b6d..29d21d6 100644
--- a/drivers/clocksource/timer-atmel-st.c
+++ b/drivers/clocksource/timer-atmel-st.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/clk.h>
#include <linux/clockchips.h>
#include <linux/export.h>
#include <linux/mfd/syscon.h>
@@ -33,9 +34,7 @@ static unsigned long last_crtr;
static u32 irqmask;
static struct clock_event_device clkevt;
static struct regmap *regmap_st;
-
-#define AT91_SLOW_CLOCK 32768
-#define RM9200_TIMER_LATCH ((AT91_SLOW_CLOCK + HZ/2) / HZ)
+static int timer_latch;
/*
* The ST_CRTR is updated asynchronously to the master clock ... but
@@ -82,8 +81,8 @@ static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
if (sr & AT91_ST_PITS) {
u32 crtr = read_CRTR();
- while (((crtr - last_crtr) & AT91_ST_CRTV) >= RM9200_TIMER_LATCH) {
- last_crtr += RM9200_TIMER_LATCH;
+ while (((crtr - last_crtr) & AT91_ST_CRTV) >= timer_latch) {
+ last_crtr += timer_latch;
clkevt.event_handler(&clkevt);
}
return IRQ_HANDLED;
@@ -144,7 +143,7 @@ static int clkevt32k_set_periodic(struct clock_event_device *dev)
/* PIT for periodic irqs; fixed rate of 1/HZ */
irqmask = AT91_ST_PITS;
- regmap_write(regmap_st, AT91_ST_PIMR, RM9200_TIMER_LATCH);
+ regmap_write(regmap_st, AT91_ST_PIMR, timer_latch);
regmap_write(regmap_st, AT91_ST_IER, irqmask);
return 0;
}
@@ -197,7 +196,8 @@ static struct clock_event_device clkevt = {
*/
static void __init atmel_st_timer_init(struct device_node *node)
{
- unsigned int val;
+ struct clk *sclk;
+ unsigned int sclk_rate, val;
int irq, ret;
regmap_st = syscon_node_to_regmap(node);
@@ -221,6 +221,19 @@ static void __init atmel_st_timer_init(struct device_node *node)
if (ret)
panic(pr_fmt("Unable to setup IRQ\n"));
+ sclk = of_clk_get(node, 0);
+ if (IS_ERR(sclk))
+ panic(pr_fmt("Unable to get slow clock\n"));
+
+ clk_prepare_enable(sclk);
+ if (ret)
+ panic(pr_fmt("Could not enable slow clock\n"));
+
+ sclk_rate = clk_get_rate(sclk);
+ if (!sclk_rate)
+ panic(pr_fmt("Invalid slow clock rate\n"));
+ timer_latch = (sclk_rate + HZ / 2) / HZ;
+
/* The 32KiHz "Slow Clock" (tick every 30517.58 nanoseconds) is used
* directly for the clocksource and all clockevents, after adjusting
* its prescaler from the 1 Hz default.
@@ -229,11 +242,11 @@ static void __init atmel_st_timer_init(struct device_node *node)
/* Setup timer clockevent, with minimum of two ticks (important!!) */
clkevt.cpumask = cpumask_of(0);
- clockevents_config_and_register(&clkevt, AT91_SLOW_CLOCK,
+ clockevents_config_and_register(&clkevt, sclk_rate,
2, AT91_ST_ALMV);
/* register clocksource */
- clocksource_register_hz(&clk32k, AT91_SLOW_CLOCK);
+ clocksource_register_hz(&clk32k, sclk_rate);
}
CLOCKSOURCE_OF_DECLARE(atmel_st_timer, "atmel,at91rm9200-st",
atmel_st_timer_init);
diff --git a/drivers/clocksource/timer-sun5i.c b/drivers/clocksource/timer-sun5i.c
index bca9573..24c83f9 100644
--- a/drivers/clocksource/timer-sun5i.c
+++ b/drivers/clocksource/timer-sun5i.c
@@ -152,13 +152,6 @@ static irqreturn_t sun5i_timer_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static cycle_t sun5i_clksrc_read(struct clocksource *clksrc)
-{
- struct sun5i_timer_clksrc *cs = to_sun5i_timer_clksrc(clksrc);
-
- return ~readl(cs->timer.base + TIMER_CNTVAL_LO_REG(1));
-}
-
static int sun5i_rate_cb_clksrc(struct notifier_block *nb,
unsigned long event, void *data)
{
@@ -217,13 +210,8 @@ static int __init sun5i_setup_clocksource(struct device_node *node,
writel(TIMER_CTL_ENABLE | TIMER_CTL_RELOAD,
base + TIMER_CTL_REG(1));
- cs->clksrc.name = node->name;
- cs->clksrc.rating = 340;
- cs->clksrc.read = sun5i_clksrc_read;
- cs->clksrc.mask = CLOCKSOURCE_MASK(32);
- cs->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS;
-
- ret = clocksource_register_hz(&cs->clksrc, rate);
+ ret = clocksource_mmio_init(base + TIMER_CNTVAL_LO_REG(1), node->name,
+ rate, 340, 32, clocksource_mmio_readl_down);
if (ret) {
pr_err("Couldn't register clock source.\n");
goto err_remove_notifier;
diff --git a/drivers/clocksource/timer-ti-32k.c b/drivers/clocksource/timer-ti-32k.c
new file mode 100644
index 0000000..8518d9d
--- /dev/null
+++ b/drivers/clocksource/timer-ti-32k.c
@@ -0,0 +1,126 @@
+/**
+ * timer-ti-32k.c - OMAP2 32k Timer Support
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Update to use new clocksource/clockevent layers
+ * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com>
+ * Copyright (C) 2007 MontaVista Software, Inc.
+ *
+ * Original driver:
+ * Copyright (C) 2005 Nokia Corporation
+ * Author: Paul Mundt <paul.mundt@nokia.com>
+ * Juha Yrjölä <juha.yrjola@nokia.com>
+ * OMAP Dual-mode timer framework support by Timo Teras
+ *
+ * Some parts based off of TI's 24xx code:
+ *
+ * Copyright (C) 2004-2009 Texas Instruments, Inc.
+ *
+ * Roughly modelled after the OMAP1 MPU timer code.
+ * Added OMAP4 support - Santosh Shilimkar <santosh.shilimkar@ti.com>
+ *
+ * Copyright (C) 2015 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 version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/sched_clock.h>
+#include <linux/clocksource.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+/*
+ * 32KHz clocksource ... always available, on pretty most chips except
+ * OMAP 730 and 1510. Other timers could be used as clocksources, with
+ * higher resolution in free-running counter modes (e.g. 12 MHz xtal),
+ * but systems won't necessarily want to spend resources that way.
+ */
+
+#define OMAP2_32KSYNCNT_REV_OFF 0x0
+#define OMAP2_32KSYNCNT_REV_SCHEME (0x3 << 30)
+#define OMAP2_32KSYNCNT_CR_OFF_LOW 0x10
+#define OMAP2_32KSYNCNT_CR_OFF_HIGH 0x30
+
+struct ti_32k {
+ void __iomem *base;
+ void __iomem *counter;
+ struct clocksource cs;
+};
+
+static inline struct ti_32k *to_ti_32k(struct clocksource *cs)
+{
+ return container_of(cs, struct ti_32k, cs);
+}
+
+static cycle_t ti_32k_read_cycles(struct clocksource *cs)
+{
+ struct ti_32k *ti = to_ti_32k(cs);
+
+ return (cycle_t)readl_relaxed(ti->counter);
+}
+
+static struct ti_32k ti_32k_timer = {
+ .cs = {
+ .name = "32k_counter",
+ .rating = 250,
+ .read = ti_32k_read_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS |
+ CLOCK_SOURCE_SUSPEND_NONSTOP,
+ },
+};
+
+static u64 notrace omap_32k_read_sched_clock(void)
+{
+ return ti_32k_read_cycles(&ti_32k_timer.cs);
+}
+
+static void __init ti_32k_timer_init(struct device_node *np)
+{
+ int ret;
+
+ ti_32k_timer.base = of_iomap(np, 0);
+ if (!ti_32k_timer.base) {
+ pr_err("Can't ioremap 32k timer base\n");
+ return;
+ }
+
+ ti_32k_timer.counter = ti_32k_timer.base;
+
+ /*
+ * 32k sync Counter IP register offsets vary between the highlander
+ * version and the legacy ones.
+ *
+ * The 'SCHEME' bits(30-31) of the revision register is used to identify
+ * the version.
+ */
+ if (readl_relaxed(ti_32k_timer.base + OMAP2_32KSYNCNT_REV_OFF) &
+ OMAP2_32KSYNCNT_REV_SCHEME)
+ ti_32k_timer.counter += OMAP2_32KSYNCNT_CR_OFF_HIGH;
+ else
+ ti_32k_timer.counter += OMAP2_32KSYNCNT_CR_OFF_LOW;
+
+ ret = clocksource_register_hz(&ti_32k_timer.cs, 32768);
+ if (ret) {
+ pr_err("32k_counter: can't register clocksource\n");
+ return;
+ }
+
+ sched_clock_register(omap_32k_read_sched_clock, 32, 32768);
+ pr_info("OMAP clocksource: 32k_counter at 32768 Hz\n");
+}
+CLOCKSOURCE_OF_DECLARE(ti_32k_timer, "ti,omap-counter32k",
+ ti_32k_timer_init);
diff --git a/drivers/clocksource/vt8500_timer.c b/drivers/clocksource/vt8500_timer.c
index a92e94b..de49805 100644
--- a/drivers/clocksource/vt8500_timer.c
+++ b/drivers/clocksource/vt8500_timer.c
@@ -30,7 +30,6 @@
#include <linux/clocksource.h>
#include <linux/clockchips.h>
#include <linux/delay.h>
-#include <asm/mach/time.h>
#include <linux/of.h>
#include <linux/of_address.h>
diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c
index d7373ca..25693b0 100644
--- a/drivers/connector/connector.c
+++ b/drivers/connector/connector.c
@@ -179,26 +179,21 @@ static int cn_call_callback(struct sk_buff *skb)
*
* It checks skb, netlink header and msg sizes, and calls callback helper.
*/
-static void cn_rx_skb(struct sk_buff *__skb)
+static void cn_rx_skb(struct sk_buff *skb)
{
struct nlmsghdr *nlh;
- struct sk_buff *skb;
int len, err;
- skb = skb_get(__skb);
-
if (skb->len >= NLMSG_HDRLEN) {
nlh = nlmsg_hdr(skb);
len = nlmsg_len(nlh);
if (len < (int)sizeof(struct cn_msg) ||
skb->len < nlh->nlmsg_len ||
- len > CONNECTOR_MAX_MSG_SIZE) {
- kfree_skb(skb);
+ len > CONNECTOR_MAX_MSG_SIZE)
return;
- }
- err = cn_call_callback(skb);
+ err = cn_call_callback(skb_get(skb));
if (err < 0)
kfree_skb(skb);
}
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 642fd49..b1f8a73 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -84,6 +84,7 @@ config ARM_KIRKWOOD_CPUFREQ
config ARM_MT8173_CPUFREQ
bool "Mediatek MT8173 CPUFreq support"
depends on ARCH_MEDIATEK && REGULATOR
+ depends on ARM64 || (ARM_CPU_TOPOLOGY && COMPILE_TEST)
depends on !CPU_THERMAL || THERMAL=y
select PM_OPP
help
@@ -199,6 +200,16 @@ config ARM_SA1100_CPUFREQ
config ARM_SA1110_CPUFREQ
bool
+config ARM_SCPI_CPUFREQ
+ tristate "SCPI based CPUfreq driver"
+ depends on ARM_BIG_LITTLE_CPUFREQ && ARM_SCPI_PROTOCOL && COMMON_CLK_SCPI
+ help
+ This adds the CPUfreq driver support for ARM big.LITTLE platforms
+ using SCPI protocol for CPU power management.
+
+ This driver uses SCPI Message Protocol driver to interact with the
+ firmware providing the CPU DVFS functionality.
+
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
depends on PLAT_SPEAR
@@ -215,7 +226,7 @@ config ARM_TEGRA20_CPUFREQ
config ARM_TEGRA124_CPUFREQ
tristate "Tegra124 CPUFreq support"
- depends on ARCH_TEGRA && CPUFREQ_DT
+ depends on ARCH_TEGRA && CPUFREQ_DT && REGULATOR
default y
help
This adds the CPUFreq driver support for Tegra124 SOCs.
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index adbd1de..c59bdcb 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -5,7 +5,6 @@
config X86_INTEL_PSTATE
bool "Intel P state control"
depends on X86
- select ACPI_PROCESSOR if ACPI
help
This driver provides a P state for Intel core processors.
The driver implements an internal governor and will become
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index d11309c..c0af1a1 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_ARM_S3C64XX_CPUFREQ) += s3c64xx-cpufreq.o
obj-$(CONFIG_ARM_S5PV210_CPUFREQ) += s5pv210-cpufreq.o
obj-$(CONFIG_ARM_SA1100_CPUFREQ) += sa1100-cpufreq.o
obj-$(CONFIG_ARM_SA1110_CPUFREQ) += sa1110-cpufreq.o
+obj-$(CONFIG_ARM_SCPI_CPUFREQ) += scpi-cpufreq.o
obj-$(CONFIG_ARM_SPEAR_CPUFREQ) += spear-cpufreq.o
obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o
obj-$(CONFIG_ARM_TEGRA124_CPUFREQ) += tegra124-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index f1e42f8..c5d256c 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -149,6 +149,19 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
__func__, cpu, old_cluster, new_cluster, new_rate);
ret = clk_set_rate(clk[new_cluster], new_rate * 1000);
+ if (!ret) {
+ /*
+ * FIXME: clk_set_rate hasn't returned an error here however it
+ * may be that clk_change_rate failed due to hardware or
+ * firmware issues and wasn't able to report that due to the
+ * current design of the clk core layer. To work around this
+ * problem we will read back the clock rate and check it is
+ * correct. This needs to be removed once clk core is fixed.
+ */
+ if (clk_get_rate(clk[new_cluster]) != new_rate * 1000)
+ ret = -EIO;
+ }
+
if (WARN_ON(ret)) {
pr_err("clk_set_rate failed: %d, new cluster: %d\n", ret,
new_cluster);
@@ -189,15 +202,6 @@ bL_cpufreq_set_rate(u32 cpu, u32 old_cluster, u32 new_cluster, u32 rate)
mutex_unlock(&cluster_lock[old_cluster]);
}
- /*
- * FIXME: clk_set_rate has to handle the case where clk_change_rate
- * can fail due to hardware or firmware issues. Until the clk core
- * layer is fixed, we can check here. In most of the cases we will
- * be reading only the cached value anyway. This needs to be removed
- * once clk core is fixed.
- */
- if (bL_cpufreq_get_rate(cpu) != new_rate)
- return -EIO;
return 0;
}
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 93c219f..7c0bdfb 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -98,10 +98,11 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
policy->max = cpu->perf_caps.highest_perf;
policy->cpuinfo.min_freq = policy->min;
policy->cpuinfo.max_freq = policy->max;
+ policy->shared_type = cpu->shared_type;
if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY)
cpumask_copy(policy->cpus, cpu->shared_cpu_map);
- else {
+ else if (policy->shared_type == CPUFREQ_SHARED_TYPE_ALL) {
/* Support only SW_ANY for now. */
pr_debug("Unsupported CPU co-ord type\n");
return -EFAULT;
@@ -166,8 +167,7 @@ static int __init cppc_cpufreq_init(void)
out:
for_each_possible_cpu(i)
- if (all_cpu_data[i])
- kfree(all_cpu_data[i]);
+ kfree(all_cpu_data[i]);
kfree(all_cpu_data);
return -ENODEV;
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 7c48e73..8412ce5 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -976,10 +976,14 @@ static int cpufreq_init_policy(struct cpufreq_policy *policy)
new_policy.governor = gov;
- /* Use the default policy if its valid. */
- if (cpufreq_driver->setpolicy)
- cpufreq_parse_governor(gov->name, &new_policy.policy, NULL);
-
+ /* Use the default policy if there is no last_policy. */
+ if (cpufreq_driver->setpolicy) {
+ if (policy->last_policy)
+ new_policy.policy = policy->last_policy;
+ else
+ cpufreq_parse_governor(gov->name, &new_policy.policy,
+ NULL);
+ }
/* set default policy */
return cpufreq_set_policy(policy, &new_policy);
}
@@ -1330,6 +1334,8 @@ static void cpufreq_offline_prepare(unsigned int cpu)
if (has_target())
strncpy(policy->last_governor, policy->governor->name,
CPUFREQ_NAME_LEN);
+ else
+ policy->last_policy = policy->policy;
} else if (cpu == policy->cpu) {
/* Nominate new CPU */
policy->cpu = cpumask_any(policy->cpus);
@@ -1401,13 +1407,10 @@ static void cpufreq_remove_dev(struct device *dev, struct subsys_interface *sif)
}
cpumask_clear_cpu(cpu, policy->real_cpus);
+ remove_cpu_dev_symlink(policy, cpu);
- if (cpumask_empty(policy->real_cpus)) {
+ if (cpumask_empty(policy->real_cpus))
cpufreq_policy_free(policy, true);
- return;
- }
-
- remove_cpu_dev_symlink(policy, cpu);
}
static void handle_update(struct work_struct *work)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 11258c4..b260576 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -171,10 +171,6 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
{
int i;
- mutex_lock(&cpufreq_governor_lock);
- if (!policy->governor_enabled)
- goto out_unlock;
-
if (!all_cpus) {
/*
* Use raw_smp_processor_id() to avoid preemptible warnings.
@@ -188,9 +184,6 @@ void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy,
for_each_cpu(i, policy->cpus)
__gov_queue_work(i, dbs_data, delay);
}
-
-out_unlock:
- mutex_unlock(&cpufreq_governor_lock);
}
EXPORT_SYMBOL_GPL(gov_queue_work);
@@ -229,13 +222,24 @@ static void dbs_timer(struct work_struct *work)
struct cpu_dbs_info *cdbs = container_of(work, struct cpu_dbs_info,
dwork.work);
struct cpu_common_dbs_info *shared = cdbs->shared;
- struct cpufreq_policy *policy = shared->policy;
- struct dbs_data *dbs_data = policy->governor_data;
+ struct cpufreq_policy *policy;
+ struct dbs_data *dbs_data;
unsigned int sampling_rate, delay;
bool modify_all = true;
mutex_lock(&shared->timer_mutex);
+ policy = shared->policy;
+
+ /*
+ * Governor might already be disabled and there is no point continuing
+ * with the work-handler.
+ */
+ if (!policy)
+ goto unlock;
+
+ dbs_data = policy->governor_data;
+
if (dbs_data->cdata->governor == GOV_CONSERVATIVE) {
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
@@ -252,6 +256,7 @@ static void dbs_timer(struct work_struct *work)
delay = dbs_data->cdata->gov_dbs_timer(cdbs, dbs_data, modify_all);
gov_queue_work(dbs_data, policy, delay, modify_all);
+unlock:
mutex_unlock(&shared->timer_mutex);
}
@@ -478,9 +483,17 @@ static int cpufreq_governor_stop(struct cpufreq_policy *policy,
if (!shared || !shared->policy)
return -EBUSY;
+ /*
+ * Work-handler must see this updated, as it should not proceed any
+ * further after governor is disabled. And so timer_mutex is taken while
+ * updating this value.
+ */
+ mutex_lock(&shared->timer_mutex);
+ shared->policy = NULL;
+ mutex_unlock(&shared->timer_mutex);
+
gov_cancel_work(dbs_data, policy);
- shared->policy = NULL;
mutex_destroy(&shared->timer_mutex);
return 0;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 93a3c63..98fb882 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -34,14 +34,10 @@
#include <asm/cpu_device_id.h>
#include <asm/cpufeature.h>
-#if IS_ENABLED(CONFIG_ACPI)
-#include <acpi/processor.h>
-#endif
-
-#define BYT_RATIOS 0x66a
-#define BYT_VIDS 0x66b
-#define BYT_TURBO_RATIOS 0x66c
-#define BYT_TURBO_VIDS 0x66d
+#define ATOM_RATIOS 0x66a
+#define ATOM_VIDS 0x66b
+#define ATOM_TURBO_RATIOS 0x66c
+#define ATOM_TURBO_VIDS 0x66d
#define FRAC_BITS 8
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
@@ -117,9 +113,6 @@ struct cpudata {
u64 prev_mperf;
u64 prev_tsc;
struct sample sample;
-#if IS_ENABLED(CONFIG_ACPI)
- struct acpi_processor_performance acpi_perf_data;
-#endif
};
static struct cpudata **all_cpu_data;
@@ -150,7 +143,6 @@ struct cpu_defaults {
static struct pstate_adjust_policy pid_params;
static struct pstate_funcs pstate_funcs;
static int hwp_active;
-static int no_acpi_perf;
struct perf_limits {
int no_turbo;
@@ -163,8 +155,6 @@ struct perf_limits {
int max_sysfs_pct;
int min_policy_pct;
int min_sysfs_pct;
- int max_perf_ctl;
- int min_perf_ctl;
};
static struct perf_limits performance_limits = {
@@ -191,8 +181,6 @@ static struct perf_limits powersave_limits = {
.max_sysfs_pct = 100,
.min_policy_pct = 0,
.min_sysfs_pct = 0,
- .max_perf_ctl = 0,
- .min_perf_ctl = 0,
};
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
@@ -201,153 +189,6 @@ static struct perf_limits *limits = &performance_limits;
static struct perf_limits *limits = &powersave_limits;
#endif
-#if IS_ENABLED(CONFIG_ACPI)
-/*
- * The max target pstate ratio is a 8 bit value in both PLATFORM_INFO MSR and
- * in TURBO_RATIO_LIMIT MSR, which pstate driver stores in max_pstate and
- * max_turbo_pstate fields. The PERF_CTL MSR contains 16 bit value for P state
- * ratio, out of it only high 8 bits are used. For example 0x1700 is setting
- * target ratio 0x17. The _PSS control value stores in a format which can be
- * directly written to PERF_CTL MSR. But in intel_pstate driver this shift
- * occurs during write to PERF_CTL (E.g. for cores core_set_pstate()).
- * This function converts the _PSS control value to intel pstate driver format
- * for comparison and assignment.
- */
-static int convert_to_native_pstate_format(struct cpudata *cpu, int index)
-{
- return cpu->acpi_perf_data.states[index].control >> 8;
-}
-
-static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
-{
- struct cpudata *cpu;
- int ret;
- bool turbo_absent = false;
- int max_pstate_index;
- int min_pss_ctl, max_pss_ctl, turbo_pss_ctl;
- int i;
-
- cpu = all_cpu_data[policy->cpu];
-
- pr_debug("intel_pstate: default limits 0x%x 0x%x 0x%x\n",
- cpu->pstate.min_pstate, cpu->pstate.max_pstate,
- cpu->pstate.turbo_pstate);
-
- if (!cpu->acpi_perf_data.shared_cpu_map &&
- zalloc_cpumask_var_node(&cpu->acpi_perf_data.shared_cpu_map,
- GFP_KERNEL, cpu_to_node(policy->cpu))) {
- return -ENOMEM;
- }
-
- ret = acpi_processor_register_performance(&cpu->acpi_perf_data,
- policy->cpu);
- if (ret)
- return ret;
-
- /*
- * Check if the control value in _PSS is for PERF_CTL MSR, which should
- * guarantee that the states returned by it map to the states in our
- * list directly.
- */
- if (cpu->acpi_perf_data.control_register.space_id !=
- ACPI_ADR_SPACE_FIXED_HARDWARE)
- return -EIO;
-
- pr_debug("intel_pstate: CPU%u - ACPI _PSS perf data\n", policy->cpu);
- for (i = 0; i < cpu->acpi_perf_data.state_count; i++)
- pr_debug(" %cP%d: %u MHz, %u mW, 0x%x\n",
- (i == cpu->acpi_perf_data.state ? '*' : ' '), i,
- (u32) cpu->acpi_perf_data.states[i].core_frequency,
- (u32) cpu->acpi_perf_data.states[i].power,
- (u32) cpu->acpi_perf_data.states[i].control);
-
- /*
- * If there is only one entry _PSS, simply ignore _PSS and continue as
- * usual without taking _PSS into account
- */
- if (cpu->acpi_perf_data.state_count < 2)
- return 0;
-
- turbo_pss_ctl = convert_to_native_pstate_format(cpu, 0);
- min_pss_ctl = convert_to_native_pstate_format(cpu,
- cpu->acpi_perf_data.state_count - 1);
- /* Check if there is a turbo freq in _PSS */
- if (turbo_pss_ctl <= cpu->pstate.max_pstate &&
- turbo_pss_ctl > cpu->pstate.min_pstate) {
- pr_debug("intel_pstate: no turbo range exists in _PSS\n");
- limits->no_turbo = limits->turbo_disabled = 1;
- cpu->pstate.turbo_pstate = cpu->pstate.max_pstate;
- turbo_absent = true;
- }
-
- /* Check if the max non turbo p state < Intel P state max */
- max_pstate_index = turbo_absent ? 0 : 1;
- max_pss_ctl = convert_to_native_pstate_format(cpu, max_pstate_index);
- if (max_pss_ctl < cpu->pstate.max_pstate &&
- max_pss_ctl > cpu->pstate.min_pstate)
- cpu->pstate.max_pstate = max_pss_ctl;
-
- /* check If min perf > Intel P State min */
- if (min_pss_ctl > cpu->pstate.min_pstate &&
- min_pss_ctl < cpu->pstate.max_pstate) {
- cpu->pstate.min_pstate = min_pss_ctl;
- policy->cpuinfo.min_freq = min_pss_ctl * cpu->pstate.scaling;
- }
-
- if (turbo_absent)
- policy->cpuinfo.max_freq = cpu->pstate.max_pstate *
- cpu->pstate.scaling;
- else {
- policy->cpuinfo.max_freq = cpu->pstate.turbo_pstate *
- cpu->pstate.scaling;
- /*
- * The _PSS table doesn't contain whole turbo frequency range.
- * This just contains +1 MHZ above the max non turbo frequency,
- * with control value corresponding to max turbo ratio. But
- * when cpufreq set policy is called, it will call with this
- * max frequency, which will cause a reduced performance as
- * this driver uses real max turbo frequency as the max
- * frequeny. So correct this frequency in _PSS table to
- * correct max turbo frequency based on the turbo ratio.
- * Also need to convert to MHz as _PSS freq is in MHz.
- */
- cpu->acpi_perf_data.states[0].core_frequency =
- turbo_pss_ctl * 100;
- }
-
- pr_debug("intel_pstate: Updated limits using _PSS 0x%x 0x%x 0x%x\n",
- cpu->pstate.min_pstate, cpu->pstate.max_pstate,
- cpu->pstate.turbo_pstate);
- pr_debug("intel_pstate: policy max_freq=%d Khz min_freq = %d KHz\n",
- policy->cpuinfo.max_freq, policy->cpuinfo.min_freq);
-
- return 0;
-}
-
-static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
-{
- struct cpudata *cpu;
-
- if (!no_acpi_perf)
- return 0;
-
- cpu = all_cpu_data[policy->cpu];
- acpi_processor_unregister_performance(policy->cpu);
- return 0;
-}
-
-#else
-static int intel_pstate_init_perf_limits(struct cpufreq_policy *policy)
-{
- return 0;
-}
-
-static int intel_pstate_exit_perf_limits(struct cpufreq_policy *policy)
-{
- return 0;
-}
-#endif
-
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
int deadband, int integral) {
pid->setpoint = setpoint;
@@ -684,36 +525,34 @@ static void __init intel_pstate_sysfs_expose_params(void)
static void intel_pstate_hwp_enable(struct cpudata *cpudata)
{
- pr_info("intel_pstate: HWP enabled\n");
-
wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
}
-static int byt_get_min_pstate(void)
+static int atom_get_min_pstate(void)
{
u64 value;
- rdmsrl(BYT_RATIOS, value);
+ rdmsrl(ATOM_RATIOS, value);
return (value >> 8) & 0x7F;
}
-static int byt_get_max_pstate(void)
+static int atom_get_max_pstate(void)
{
u64 value;
- rdmsrl(BYT_RATIOS, value);
+ rdmsrl(ATOM_RATIOS, value);
return (value >> 16) & 0x7F;
}
-static int byt_get_turbo_pstate(void)
+static int atom_get_turbo_pstate(void)
{
u64 value;
- rdmsrl(BYT_TURBO_RATIOS, value);
+ rdmsrl(ATOM_TURBO_RATIOS, value);
return value & 0x7F;
}
-static void byt_set_pstate(struct cpudata *cpudata, int pstate)
+static void atom_set_pstate(struct cpudata *cpudata, int pstate)
{
u64 val;
int32_t vid_fp;
@@ -738,27 +577,42 @@ static void byt_set_pstate(struct cpudata *cpudata, int pstate)
wrmsrl_on_cpu(cpudata->cpu, MSR_IA32_PERF_CTL, val);
}
-#define BYT_BCLK_FREQS 5
-static int byt_freq_table[BYT_BCLK_FREQS] = { 833, 1000, 1333, 1167, 800};
-
-static int byt_get_scaling(void)
+static int silvermont_get_scaling(void)
{
u64 value;
int i;
+ /* Defined in Table 35-6 from SDM (Sept 2015) */
+ static int silvermont_freq_table[] = {
+ 83300, 100000, 133300, 116700, 80000};
rdmsrl(MSR_FSB_FREQ, value);
- i = value & 0x3;
+ i = value & 0x7;
+ WARN_ON(i > 4);
+
+ return silvermont_freq_table[i];
+}
- BUG_ON(i > BYT_BCLK_FREQS);
+static int airmont_get_scaling(void)
+{
+ u64 value;
+ int i;
+ /* Defined in Table 35-10 from SDM (Sept 2015) */
+ static int airmont_freq_table[] = {
+ 83300, 100000, 133300, 116700, 80000,
+ 93300, 90000, 88900, 87500};
- return byt_freq_table[i] * 100;
+ rdmsrl(MSR_FSB_FREQ, value);
+ i = value & 0xF;
+ WARN_ON(i > 8);
+
+ return airmont_freq_table[i];
}
-static void byt_get_vid(struct cpudata *cpudata)
+static void atom_get_vid(struct cpudata *cpudata)
{
u64 value;
- rdmsrl(BYT_VIDS, value);
+ rdmsrl(ATOM_VIDS, value);
cpudata->vid.min = int_tofp((value >> 8) & 0x7f);
cpudata->vid.max = int_tofp((value >> 16) & 0x7f);
cpudata->vid.ratio = div_fp(
@@ -766,7 +620,7 @@ static void byt_get_vid(struct cpudata *cpudata)
int_tofp(cpudata->pstate.max_pstate -
cpudata->pstate.min_pstate));
- rdmsrl(BYT_TURBO_VIDS, value);
+ rdmsrl(ATOM_TURBO_VIDS, value);
cpudata->vid.turbo = value & 0x7f;
}
@@ -887,7 +741,7 @@ static struct cpu_defaults core_params = {
},
};
-static struct cpu_defaults byt_params = {
+static struct cpu_defaults silvermont_params = {
.pid_policy = {
.sample_rate_ms = 10,
.deadband = 0,
@@ -897,13 +751,33 @@ static struct cpu_defaults byt_params = {
.i_gain_pct = 4,
},
.funcs = {
- .get_max = byt_get_max_pstate,
- .get_max_physical = byt_get_max_pstate,
- .get_min = byt_get_min_pstate,
- .get_turbo = byt_get_turbo_pstate,
- .set = byt_set_pstate,
- .get_scaling = byt_get_scaling,
- .get_vid = byt_get_vid,
+ .get_max = atom_get_max_pstate,
+ .get_max_physical = atom_get_max_pstate,
+ .get_min = atom_get_min_pstate,
+ .get_turbo = atom_get_turbo_pstate,
+ .set = atom_set_pstate,
+ .get_scaling = silvermont_get_scaling,
+ .get_vid = atom_get_vid,
+ },
+};
+
+static struct cpu_defaults airmont_params = {
+ .pid_policy = {
+ .sample_rate_ms = 10,
+ .deadband = 0,
+ .setpoint = 60,
+ .p_gain_pct = 14,
+ .d_gain_pct = 0,
+ .i_gain_pct = 4,
+ },
+ .funcs = {
+ .get_max = atom_get_max_pstate,
+ .get_max_physical = atom_get_max_pstate,
+ .get_min = atom_get_min_pstate,
+ .get_turbo = atom_get_turbo_pstate,
+ .set = atom_set_pstate,
+ .get_scaling = airmont_get_scaling,
+ .get_vid = atom_get_vid,
},
};
@@ -940,23 +814,12 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
* policy, or by cpu specific default values determined through
* experimentation.
*/
- if (limits->max_perf_ctl && limits->max_sysfs_pct >=
- limits->max_policy_pct) {
- *max = limits->max_perf_ctl;
- } else {
- max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf),
- limits->max_perf));
- *max = clamp_t(int, max_perf_adj, cpu->pstate.min_pstate,
- cpu->pstate.turbo_pstate);
- }
+ max_perf_adj = fp_toint(mul_fp(int_tofp(max_perf), limits->max_perf));
+ *max = clamp_t(int, max_perf_adj,
+ cpu->pstate.min_pstate, cpu->pstate.turbo_pstate);
- if (limits->min_perf_ctl) {
- *min = limits->min_perf_ctl;
- } else {
- min_perf = fp_toint(mul_fp(int_tofp(max_perf),
- limits->min_perf));
- *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
- }
+ min_perf = fp_toint(mul_fp(int_tofp(max_perf), limits->min_perf));
+ *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
}
static void intel_pstate_set_pstate(struct cpudata *cpu, int pstate, bool force)
@@ -1155,7 +1018,7 @@ static void intel_pstate_timer_func(unsigned long __data)
static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x2a, core_params),
ICPU(0x2d, core_params),
- ICPU(0x37, byt_params),
+ ICPU(0x37, silvermont_params),
ICPU(0x3a, core_params),
ICPU(0x3c, core_params),
ICPU(0x3d, core_params),
@@ -1164,7 +1027,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x45, core_params),
ICPU(0x46, core_params),
ICPU(0x47, core_params),
- ICPU(0x4c, byt_params),
+ ICPU(0x4c, airmont_params),
ICPU(0x4e, core_params),
ICPU(0x4f, core_params),
ICPU(0x5e, core_params),
@@ -1231,12 +1094,6 @@ static unsigned int intel_pstate_get(unsigned int cpu_num)
static int intel_pstate_set_policy(struct cpufreq_policy *policy)
{
-#if IS_ENABLED(CONFIG_ACPI)
- struct cpudata *cpu;
- int i;
-#endif
- pr_debug("intel_pstate: %s max %u policy->max %u\n", __func__,
- policy->cpuinfo.max_freq, policy->max);
if (!policy->cpuinfo.max_freq)
return -ENODEV;
@@ -1244,6 +1101,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
policy->max >= policy->cpuinfo.max_freq) {
pr_debug("intel_pstate: set performance\n");
limits = &performance_limits;
+ if (hwp_active)
+ intel_pstate_hwp_set();
return 0;
}
@@ -1251,7 +1110,8 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits = &powersave_limits;
limits->min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
limits->min_policy_pct = clamp_t(int, limits->min_policy_pct, 0 , 100);
- limits->max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
+ limits->max_policy_pct = DIV_ROUND_UP(policy->max * 100,
+ policy->cpuinfo.max_freq);
limits->max_policy_pct = clamp_t(int, limits->max_policy_pct, 0 , 100);
/* Normalize user input to [min_policy_pct, max_policy_pct] */
@@ -1263,6 +1123,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits->max_sysfs_pct);
limits->max_perf_pct = max(limits->min_policy_pct,
limits->max_perf_pct);
+ limits->max_perf = round_up(limits->max_perf, FRAC_BITS);
/* Make sure min_perf_pct <= max_perf_pct */
limits->min_perf_pct = min(limits->max_perf_pct, limits->min_perf_pct);
@@ -1272,23 +1133,6 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits->max_perf = div_fp(int_tofp(limits->max_perf_pct),
int_tofp(100));
-#if IS_ENABLED(CONFIG_ACPI)
- cpu = all_cpu_data[policy->cpu];
- for (i = 0; i < cpu->acpi_perf_data.state_count; i++) {
- int control;
-
- control = convert_to_native_pstate_format(cpu, i);
- if (control * cpu->pstate.scaling == policy->max)
- limits->max_perf_ctl = control;
- if (control * cpu->pstate.scaling == policy->min)
- limits->min_perf_ctl = control;
- }
-
- pr_debug("intel_pstate: max %u policy_max %u perf_ctl [0x%x-0x%x]\n",
- policy->cpuinfo.max_freq, policy->max, limits->min_perf_ctl,
- limits->max_perf_ctl);
-#endif
-
if (hwp_active)
intel_pstate_hwp_set();
@@ -1343,30 +1187,18 @@ static int intel_pstate_cpu_init(struct cpufreq_policy *policy)
policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
policy->cpuinfo.max_freq =
cpu->pstate.turbo_pstate * cpu->pstate.scaling;
- if (!no_acpi_perf)
- intel_pstate_init_perf_limits(policy);
- /*
- * If there is no acpi perf data or error, we ignore and use Intel P
- * state calculated limits, So this is not fatal error.
- */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
cpumask_set_cpu(policy->cpu, policy->cpus);
return 0;
}
-static int intel_pstate_cpu_exit(struct cpufreq_policy *policy)
-{
- return intel_pstate_exit_perf_limits(policy);
-}
-
static struct cpufreq_driver intel_pstate_driver = {
.flags = CPUFREQ_CONST_LOOPS,
.verify = intel_pstate_verify_policy,
.setpolicy = intel_pstate_set_policy,
.get = intel_pstate_get,
.init = intel_pstate_cpu_init,
- .exit = intel_pstate_cpu_exit,
.stop_cpu = intel_pstate_stop_cpu,
.name = "intel_pstate",
};
@@ -1408,6 +1240,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs)
}
#if IS_ENABLED(CONFIG_ACPI)
+#include <acpi/processor.h>
static bool intel_pstate_no_acpi_pss(void)
{
@@ -1557,8 +1390,10 @@ static int __init intel_pstate_init(void)
if (!all_cpu_data)
return -ENOMEM;
- if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp)
+ if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) {
+ pr_info("intel_pstate: HWP enabled\n");
hwp_active++;
+ }
if (!hwp_active && hwp_only)
goto out;
@@ -1593,15 +1428,14 @@ static int __init intel_pstate_setup(char *str)
if (!strcmp(str, "disable"))
no_load = 1;
- if (!strcmp(str, "no_hwp"))
+ if (!strcmp(str, "no_hwp")) {
+ pr_info("intel_pstate: HWP disabled\n");
no_hwp = 1;
+ }
if (!strcmp(str, "force"))
force_load = 1;
if (!strcmp(str, "hwp_only"))
hwp_only = 1;
- if (!strcmp(str, "no_acpi"))
- no_acpi_perf = 1;
-
return 0;
}
early_param("intel_pstate", intel_pstate_setup);
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index 733aa51..68ef8fd 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -648,7 +648,7 @@ late_initcall(s3c_cpufreq_initcall);
*
* Register the given set of PLLs with the system.
*/
-int __init s3c_plltab_register(struct cpufreq_frequency_table *plls,
+int s3c_plltab_register(struct cpufreq_frequency_table *plls,
unsigned int plls_no)
{
struct cpufreq_frequency_table *vals;
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index 9e231f5..051a8a8 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -212,11 +212,11 @@ static void s5pv210_set_refresh(enum s5pv210_dmc_port ch, unsigned long freq)
/* Find current DRAM frequency */
tmp = s5pv210_dram_conf[ch].freq;
- do_div(tmp, freq);
+ tmp /= freq;
tmp1 = s5pv210_dram_conf[ch].refresh;
- do_div(tmp1, tmp);
+ tmp1 /= tmp;
__raw_writel(tmp1, reg);
}
diff --git a/drivers/cpufreq/scpi-cpufreq.c b/drivers/cpufreq/scpi-cpufreq.c
new file mode 100644
index 0000000..de5e89b
--- /dev/null
+++ b/drivers/cpufreq/scpi-cpufreq.c
@@ -0,0 +1,124 @@
+/*
+ * System Control and Power Interface (SCPI) based CPUFreq Interface driver
+ *
+ * It provides necessary ops to arm_big_little cpufreq driver.
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Sudeep Holla <sudeep.holla@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/cpufreq.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/scpi_protocol.h>
+#include <linux/types.h>
+
+#include "arm_big_little.h"
+
+static struct scpi_ops *scpi_ops;
+
+static struct scpi_dvfs_info *scpi_get_dvfs_info(struct device *cpu_dev)
+{
+ int domain = topology_physical_package_id(cpu_dev->id);
+
+ if (domain < 0)
+ return ERR_PTR(-EINVAL);
+ return scpi_ops->dvfs_get_info(domain);
+}
+
+static int scpi_opp_table_ops(struct device *cpu_dev, bool remove)
+{
+ int idx, ret = 0;
+ struct scpi_opp *opp;
+ struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
+
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+
+ if (!info->opps)
+ return -EIO;
+
+ for (opp = info->opps, idx = 0; idx < info->count; idx++, opp++) {
+ if (remove)
+ dev_pm_opp_remove(cpu_dev, opp->freq);
+ else
+ ret = dev_pm_opp_add(cpu_dev, opp->freq,
+ opp->m_volt * 1000);
+ if (ret) {
+ dev_warn(cpu_dev, "failed to add opp %uHz %umV\n",
+ opp->freq, opp->m_volt);
+ while (idx-- > 0)
+ dev_pm_opp_remove(cpu_dev, (--opp)->freq);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static int scpi_get_transition_latency(struct device *cpu_dev)
+{
+ struct scpi_dvfs_info *info = scpi_get_dvfs_info(cpu_dev);
+
+ if (IS_ERR(info))
+ return PTR_ERR(info);
+ return info->latency;
+}
+
+static int scpi_init_opp_table(struct device *cpu_dev)
+{
+ return scpi_opp_table_ops(cpu_dev, false);
+}
+
+static void scpi_free_opp_table(struct device *cpu_dev)
+{
+ scpi_opp_table_ops(cpu_dev, true);
+}
+
+static struct cpufreq_arm_bL_ops scpi_cpufreq_ops = {
+ .name = "scpi",
+ .get_transition_latency = scpi_get_transition_latency,
+ .init_opp_table = scpi_init_opp_table,
+ .free_opp_table = scpi_free_opp_table,
+};
+
+static int scpi_cpufreq_probe(struct platform_device *pdev)
+{
+ scpi_ops = get_scpi_ops();
+ if (!scpi_ops)
+ return -EIO;
+
+ return bL_cpufreq_register(&scpi_cpufreq_ops);
+}
+
+static int scpi_cpufreq_remove(struct platform_device *pdev)
+{
+ bL_cpufreq_unregister(&scpi_cpufreq_ops);
+ scpi_ops = NULL;
+ return 0;
+}
+
+static struct platform_driver scpi_cpufreq_platdrv = {
+ .driver = {
+ .name = "scpi-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = scpi_cpufreq_probe,
+ .remove = scpi_cpufreq_remove,
+};
+module_platform_driver(scpi_cpufreq_platdrv);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/crypto/ccp/ccp-platform.c b/drivers/crypto/ccp/ccp-platform.c
index 8b923b7..01b50cb 100644
--- a/drivers/crypto/ccp/ccp-platform.c
+++ b/drivers/crypto/ccp/ccp-platform.c
@@ -94,6 +94,7 @@ static int ccp_platform_probe(struct platform_device *pdev)
struct ccp_device *ccp;
struct ccp_platform *ccp_platform;
struct device *dev = &pdev->dev;
+ enum dev_dma_attr attr;
struct resource *ior;
int ret;
@@ -118,18 +119,24 @@ static int ccp_platform_probe(struct platform_device *pdev)
}
ccp->io_regs = ccp->io_map;
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
- if (ret) {
- dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
+ attr = device_get_dma_attr(dev);
+ if (attr == DEV_DMA_NOT_SUPPORTED) {
+ dev_err(dev, "DMA is not supported");
goto e_err;
}
- ccp_platform->coherent = device_dma_is_coherent(ccp->dev);
+ ccp_platform->coherent = (attr == DEV_DMA_COHERENT);
if (ccp_platform->coherent)
ccp->axcache = CACHE_WB_NO_ALLOC;
else
ccp->axcache = CACHE_NONE;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(48));
+ if (ret) {
+ dev_err(dev, "dma_set_mask_and_coherent failed (%d)\n", ret);
+ goto e_err;
+ }
+
dev_set_drvdata(dev, ccp);
ret = ccp_init(ccp);
diff --git a/drivers/crypto/nx/nx-aes-ccm.c b/drivers/crypto/nx/nx-aes-ccm.c
index 73ef499..7038f36 100644
--- a/drivers/crypto/nx/nx-aes-ccm.c
+++ b/drivers/crypto/nx/nx-aes-ccm.c
@@ -409,7 +409,7 @@ static int ccm_nx_decrypt(struct aead_request *req,
processed += to_process;
} while (processed < nbytes);
- rc = memcmp(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
+ rc = crypto_memneq(csbcpb->cpb.aes_ccm.out_pat_or_mac, priv->oauth_tag,
authsize) ? -EBADMSG : 0;
out:
spin_unlock_irqrestore(&nx_ctx->lock, irq_flags);
diff --git a/drivers/crypto/nx/nx-aes-gcm.c b/drivers/crypto/nx/nx-aes-gcm.c
index eee624f..abd465f 100644
--- a/drivers/crypto/nx/nx-aes-gcm.c
+++ b/drivers/crypto/nx/nx-aes-gcm.c
@@ -21,6 +21,7 @@
#include <crypto/internal/aead.h>
#include <crypto/aes.h>
+#include <crypto/algapi.h>
#include <crypto/scatterwalk.h>
#include <linux/module.h>
#include <linux/types.h>
@@ -418,7 +419,7 @@ mac:
itag, req->src, req->assoclen + nbytes,
crypto_aead_authsize(crypto_aead_reqtfm(req)),
SCATTERWALK_FROM_SG);
- rc = memcmp(itag, otag,
+ rc = crypto_memneq(itag, otag,
crypto_aead_authsize(crypto_aead_reqtfm(req))) ?
-EBADMSG : 0;
}
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index da2d677..97a3646 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -515,7 +515,7 @@ static int __init padlock_init(void)
if (!x86_match_cpu(padlock_cpu_id))
return -ENODEV;
- if (!cpu_has_xcrypt_enabled) {
+ if (!boot_cpu_has(X86_FEATURE_XCRYPT_EN)) {
printk(KERN_NOTICE PFX "VIA PadLock detected, but not enabled. Hmm, strange...\n");
return -ENODEV;
}
diff --git a/drivers/crypto/padlock-sha.c b/drivers/crypto/padlock-sha.c
index 4e154c9..8c5f906 100644
--- a/drivers/crypto/padlock-sha.c
+++ b/drivers/crypto/padlock-sha.c
@@ -540,7 +540,7 @@ static int __init padlock_init(void)
struct shash_alg *sha1;
struct shash_alg *sha256;
- if (!x86_match_cpu(padlock_sha_ids) || !cpu_has_phe_enabled)
+ if (!x86_match_cpu(padlock_sha_ids) || !boot_cpu_has(X86_FEATURE_PHE_EN))
return -ENODEV;
/* Register the newly added algorithm module if on *
diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
index 03856ad..473d36d 100644
--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -198,7 +198,7 @@ static int adf_copy_key_value_data(struct adf_accel_dev *accel_dev,
goto out_err;
}
- params_head = section_head->params;
+ params_head = section.params;
while (params_head) {
if (copy_from_user(&key_val, (void __user *)params_head,
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 46f531e..b6f9f42 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -977,7 +977,7 @@ static void ipsec_esp_decrypt_swauth_done(struct device *dev,
} else
oicv = (char *)&edesc->link_tbl[0];
- err = memcmp(oicv, icv, authsize) ? -EBADMSG : 0;
+ err = crypto_memneq(oicv, icv, authsize) ? -EBADMSG : 0;
}
kfree(edesc);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index 4e55239..53d22eb 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -729,8 +729,8 @@ atc_prep_dma_interleaved(struct dma_chan *chan,
return NULL;
dev_info(chan2dev(chan),
- "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
- __func__, xt->src_start, xt->dst_start, xt->numf,
+ "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
+ __func__, &xt->src_start, &xt->dst_start, xt->numf,
xt->frame_size, flags);
/*
@@ -824,8 +824,8 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
u32 ctrla;
u32 ctrlb;
- dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d0x%x s0x%x l0x%zx f0x%lx\n",
- dest, src, len, flags);
+ dev_vdbg(chan2dev(chan), "prep_dma_memcpy: d%pad s%pad l0x%zx f0x%lx\n",
+ &dest, &src, len, flags);
if (unlikely(!len)) {
dev_dbg(chan2dev(chan), "prep_dma_memcpy: length is zero!\n");
@@ -938,8 +938,8 @@ atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
void __iomem *vaddr;
dma_addr_t paddr;
- dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__,
- dest, value, len, flags);
+ dev_vdbg(chan2dev(chan), "%s: d%pad v0x%x l0x%zx f0x%lx\n", __func__,
+ &dest, value, len, flags);
if (unlikely(!len)) {
dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
@@ -1022,8 +1022,8 @@ atc_prep_dma_memset_sg(struct dma_chan *chan,
dma_addr_t dest = sg_dma_address(sg);
size_t len = sg_dma_len(sg);
- dev_vdbg(chan2dev(chan), "%s: d0x%08x, l0x%zx\n",
- __func__, dest, len);
+ dev_vdbg(chan2dev(chan), "%s: d%pad, l0x%zx\n",
+ __func__, &dest, len);
if (!is_dma_fill_aligned(chan->device, dest, 0, len)) {
dev_err(chan2dev(chan), "%s: buffer is not aligned\n",
@@ -1439,9 +1439,9 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
unsigned int periods = buf_len / period_len;
unsigned int i;
- dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@0x%08x - %d (%d/%d)\n",
+ dev_vdbg(chan2dev(chan), "prep_dma_cyclic: %s buf@%pad - %d (%d/%d)\n",
direction == DMA_MEM_TO_DEV ? "TO DEVICE" : "FROM DEVICE",
- buf_addr,
+ &buf_addr,
periods, buf_len, period_len);
if (unlikely(!atslave || !buf_len || !period_len)) {
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index d1cfc8c..7f58f06 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -385,9 +385,9 @@ static void vdbg_dump_regs(struct at_dma_chan *atchan) {}
static void atc_dump_lli(struct at_dma_chan *atchan, struct at_lli *lli)
{
dev_crit(chan2dev(&atchan->chan_common),
- " desc: s0x%x d0x%x ctrl0x%x:0x%x l0x%x\n",
- lli->saddr, lli->daddr,
- lli->ctrla, lli->ctrlb, lli->dscr);
+ " desc: s%pad d%pad ctrl0x%x:0x%x l0x%pad\n",
+ &lli->saddr, &lli->daddr,
+ lli->ctrla, lli->ctrlb, &lli->dscr);
}
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index b5e132d..370c661 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -156,7 +156,7 @@
#define AT_XDMAC_CC_WRIP (0x1 << 23) /* Write in Progress (read only) */
#define AT_XDMAC_CC_WRIP_DONE (0x0 << 23)
#define AT_XDMAC_CC_WRIP_IN_PROGRESS (0x1 << 23)
-#define AT_XDMAC_CC_PERID(i) (0x7f & (h) << 24) /* Channel Peripheral Identifier */
+#define AT_XDMAC_CC_PERID(i) (0x7f & (i) << 24) /* Channel Peripheral Identifier */
#define AT_XDMAC_CDS_MSP 0x2C /* Channel Data Stride Memory Set Pattern */
#define AT_XDMAC_CSUS 0x30 /* Channel Source Microblock Stride */
#define AT_XDMAC_CDUS 0x34 /* Channel Destination Microblock Stride */
@@ -920,8 +920,8 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan,
desc->lld.mbr_cfg = chan_cc;
dev_dbg(chan2dev(chan),
- "%s: lld: mbr_sa=0x%08x, mbr_da=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
- __func__, desc->lld.mbr_sa, desc->lld.mbr_da,
+ "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+ __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da,
desc->lld.mbr_ubc, desc->lld.mbr_cfg);
/* Chain lld. */
@@ -953,8 +953,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
if ((xt->numf > 1) && (xt->frame_size > 1))
return NULL;
- dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n",
- __func__, xt->src_start, xt->dst_start, xt->numf,
+ dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n",
+ __func__, &xt->src_start, &xt->dst_start, xt->numf,
xt->frame_size, flags);
src_addr = xt->src_start;
@@ -965,7 +965,9 @@ at_xdmac_prep_interleaved(struct dma_chan *chan,
NULL,
src_addr, dst_addr,
xt, xt->sgl);
- for (i = 0; i < xt->numf; i++)
+
+ /* Length of the block is (BLEN+1) microblocks. */
+ for (i = 0; i < xt->numf - 1; i++)
at_xdmac_increment_block_count(chan, first);
dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n",
@@ -1086,6 +1088,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
/* Check remaining length and change data width if needed. */
dwidth = at_xdmac_align_width(chan,
src_addr | dst_addr | xfer_size);
+ chan_cc &= ~AT_XDMAC_CC_DWIDTH_MASK;
chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth);
ublen = xfer_size >> dwidth;
@@ -1179,8 +1182,8 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan,
desc->lld.mbr_cfg = chan_cc;
dev_dbg(chan2dev(chan),
- "%s: lld: mbr_da=0x%08x, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
- __func__, desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc,
+ "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n",
+ __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc,
desc->lld.mbr_cfg);
return desc;
@@ -1193,8 +1196,8 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value,
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac_desc *desc;
- dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n",
- __func__, dest, len, value, flags);
+ dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
+ __func__, &dest, len, value, flags);
if (unlikely(!len))
return NULL;
@@ -1229,8 +1232,8 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* Prepare descriptors. */
for_each_sg(sgl, sg, sg_len, i) {
- dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n",
- __func__, sg_dma_address(sg), sg_dma_len(sg),
+ dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n",
+ __func__, &sg_dma_address(sg), sg_dma_len(sg),
value, flags);
desc = at_xdmac_memset_create_desc(chan, atchan,
sg_dma_address(sg),
@@ -1333,7 +1336,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl,
* since we don't care about the stride anymore.
*/
if ((i == (sg_len - 1)) &&
- sg_dma_len(ppsg) == sg_dma_len(psg)) {
+ sg_dma_len(psg) == sg_dma_len(sg)) {
dev_dbg(chan2dev(chan),
"%s: desc 0x%p can be merged with desc 0x%p\n",
__func__, desc, pdesc);
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index c92d6a7..996c4b0 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -31,6 +31,7 @@
*/
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -62,6 +63,11 @@ struct bcm2835_dma_cb {
uint32_t pad[2];
};
+struct bcm2835_cb_entry {
+ struct bcm2835_dma_cb *cb;
+ dma_addr_t paddr;
+};
+
struct bcm2835_chan {
struct virt_dma_chan vc;
struct list_head node;
@@ -72,18 +78,18 @@ struct bcm2835_chan {
int ch;
struct bcm2835_desc *desc;
+ struct dma_pool *cb_pool;
void __iomem *chan_base;
int irq_number;
};
struct bcm2835_desc {
+ struct bcm2835_chan *c;
struct virt_dma_desc vd;
enum dma_transfer_direction dir;
- unsigned int control_block_size;
- struct bcm2835_dma_cb *control_block_base;
- dma_addr_t control_block_base_phys;
+ struct bcm2835_cb_entry *cb_list;
unsigned int frames;
size_t size;
@@ -143,10 +149,13 @@ static inline struct bcm2835_desc *to_bcm2835_dma_desc(
static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
{
struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd);
- dma_free_coherent(desc->vd.tx.chan->device->dev,
- desc->control_block_size,
- desc->control_block_base,
- desc->control_block_base_phys);
+ int i;
+
+ for (i = 0; i < desc->frames; i++)
+ dma_pool_free(desc->c->cb_pool, desc->cb_list[i].cb,
+ desc->cb_list[i].paddr);
+
+ kfree(desc->cb_list);
kfree(desc);
}
@@ -199,7 +208,7 @@ static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
c->desc = d = to_bcm2835_dma_desc(&vd->tx);
- writel(d->control_block_base_phys, c->chan_base + BCM2835_DMA_ADDR);
+ writel(d->cb_list[0].paddr, c->chan_base + BCM2835_DMA_ADDR);
writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
}
@@ -232,9 +241,16 @@ static irqreturn_t bcm2835_dma_callback(int irq, void *data)
static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan)
{
struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+ struct device *dev = c->vc.chan.device->dev;
+
+ dev_dbg(dev, "Allocating DMA channel %d\n", c->ch);
- dev_dbg(c->vc.chan.device->dev,
- "Allocating DMA channel %d\n", c->ch);
+ c->cb_pool = dma_pool_create(dev_name(dev), dev,
+ sizeof(struct bcm2835_dma_cb), 0, 0);
+ if (!c->cb_pool) {
+ dev_err(dev, "unable to allocate descriptor pool\n");
+ return -ENOMEM;
+ }
return request_irq(c->irq_number,
bcm2835_dma_callback, 0, "DMA IRQ", c);
@@ -246,6 +262,7 @@ static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
vchan_free_chan_resources(&c->vc);
free_irq(c->irq_number, c);
+ dma_pool_destroy(c->cb_pool);
dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->ch);
}
@@ -261,8 +278,7 @@ static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr)
size_t size;
for (size = i = 0; i < d->frames; i++) {
- struct bcm2835_dma_cb *control_block =
- &d->control_block_base[i];
+ struct bcm2835_dma_cb *control_block = d->cb_list[i].cb;
size_t this_size = control_block->length;
dma_addr_t dma;
@@ -343,6 +359,7 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
dma_addr_t dev_addr;
unsigned int es, sync_type;
unsigned int frame;
+ int i;
/* Grab configuration */
if (!is_slave_direction(direction)) {
@@ -374,27 +391,31 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
if (!d)
return NULL;
+ d->c = c;
d->dir = direction;
d->frames = buf_len / period_len;
- /* Allocate memory for control blocks */
- d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
- d->control_block_base = dma_zalloc_coherent(chan->device->dev,
- d->control_block_size, &d->control_block_base_phys,
- GFP_NOWAIT);
-
- if (!d->control_block_base) {
+ d->cb_list = kcalloc(d->frames, sizeof(*d->cb_list), GFP_KERNEL);
+ if (!d->cb_list) {
kfree(d);
return NULL;
}
+ /* Allocate memory for control blocks */
+ for (i = 0; i < d->frames; i++) {
+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
+
+ cb_entry->cb = dma_pool_zalloc(c->cb_pool, GFP_ATOMIC,
+ &cb_entry->paddr);
+ if (!cb_entry->cb)
+ goto error_cb;
+ }
/*
* Iterate over all frames, create a control block
* for each frame and link them together.
*/
for (frame = 0; frame < d->frames; frame++) {
- struct bcm2835_dma_cb *control_block =
- &d->control_block_base[frame];
+ struct bcm2835_dma_cb *control_block = d->cb_list[frame].cb;
/* Setup adresses */
if (d->dir == DMA_DEV_TO_MEM) {
@@ -428,12 +449,21 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
* This DMA engine driver currently only supports cyclic DMA.
* Therefore, wrap around at number of frames.
*/
- control_block->next = d->control_block_base_phys +
- sizeof(struct bcm2835_dma_cb)
- * ((frame + 1) % d->frames);
+ control_block->next = d->cb_list[((frame + 1) % d->frames)].paddr;
}
return vchan_tx_prep(&c->vc, &d->vd, flags);
+error_cb:
+ i--;
+ for (; i >= 0; i--) {
+ struct bcm2835_cb_entry *cb_entry = &d->cb_list[i];
+
+ dma_pool_free(c->cb_pool, cb_entry->cb, cb_entry->paddr);
+ }
+
+ kfree(d->cb_list);
+ kfree(d);
+ return NULL;
}
static int bcm2835_dma_slave_config(struct dma_chan *chan,
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index 6b03e4e..16fe773 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -107,7 +107,7 @@
/* CCCFG register */
#define GET_NUM_DMACH(x) (x & 0x7) /* bits 0-2 */
-#define GET_NUM_QDMACH(x) (x & 0x70 >> 4) /* bits 4-6 */
+#define GET_NUM_QDMACH(x) ((x & 0x70) >> 4) /* bits 4-6 */
#define GET_NUM_PAENTRY(x) ((x & 0x7000) >> 12) /* bits 12-14 */
#define GET_NUM_EVQUE(x) ((x & 0x70000) >> 16) /* bits 16-18 */
#define GET_NUM_REGN(x) ((x & 0x300000) >> 20) /* bits 20-21 */
@@ -1565,7 +1565,7 @@ static void edma_tc_set_pm_state(struct edma_tc *tc, bool enable)
struct platform_device *tc_pdev;
int ret;
- if (!tc)
+ if (!IS_ENABLED(CONFIG_OF) || !tc)
return;
tc_pdev = of_find_device_by_node(tc->node);
@@ -1752,16 +1752,14 @@ static enum dma_status edma_tx_status(struct dma_chan *chan,
return ret;
}
-static bool edma_is_memcpy_channel(int ch_num, u16 *memcpy_channels)
+static bool edma_is_memcpy_channel(int ch_num, s32 *memcpy_channels)
{
- s16 *memcpy_ch = memcpy_channels;
-
if (!memcpy_channels)
return false;
- while (*memcpy_ch != -1) {
- if (*memcpy_ch == ch_num)
+ while (*memcpy_channels != -1) {
+ if (*memcpy_channels == ch_num)
return true;
- memcpy_ch++;
+ memcpy_channels++;
}
return false;
}
@@ -1775,7 +1773,7 @@ static void edma_dma_init(struct edma_cc *ecc, bool legacy_mode)
{
struct dma_device *s_ddev = &ecc->dma_slave;
struct dma_device *m_ddev = NULL;
- s16 *memcpy_channels = ecc->info->memcpy_channels;
+ s32 *memcpy_channels = ecc->info->memcpy_channels;
int i, j;
dma_cap_zero(s_ddev->cap_mask);
@@ -1996,16 +1994,16 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
prop = of_find_property(dev->of_node, "ti,edma-memcpy-channels", &sz);
if (prop) {
const char pname[] = "ti,edma-memcpy-channels";
- size_t nelm = sz / sizeof(s16);
- s16 *memcpy_ch;
+ size_t nelm = sz / sizeof(s32);
+ s32 *memcpy_ch;
- memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s16),
+ memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s32),
GFP_KERNEL);
if (!memcpy_ch)
return ERR_PTR(-ENOMEM);
- ret = of_property_read_u16_array(dev->of_node, pname,
- (u16 *)memcpy_ch, nelm);
+ ret = of_property_read_u32_array(dev->of_node, pname,
+ (u32 *)memcpy_ch, nelm);
if (ret)
return ERR_PTR(ret);
@@ -2017,31 +2015,50 @@ static struct edma_soc_info *edma_setup_info_from_dt(struct device *dev,
&sz);
if (prop) {
const char pname[] = "ti,edma-reserved-slot-ranges";
+ u32 (*tmp)[2];
s16 (*rsv_slots)[2];
- size_t nelm = sz / sizeof(*rsv_slots);
+ size_t nelm = sz / sizeof(*tmp);
struct edma_rsv_info *rsv_info;
+ int i;
if (!nelm)
return info;
+ tmp = kcalloc(nelm, sizeof(*tmp), GFP_KERNEL);
+ if (!tmp)
+ return ERR_PTR(-ENOMEM);
+
rsv_info = devm_kzalloc(dev, sizeof(*rsv_info), GFP_KERNEL);
- if (!rsv_info)
+ if (!rsv_info) {
+ kfree(tmp);
return ERR_PTR(-ENOMEM);
+ }
rsv_slots = devm_kcalloc(dev, nelm + 1, sizeof(*rsv_slots),
GFP_KERNEL);
- if (!rsv_slots)
+ if (!rsv_slots) {
+ kfree(tmp);
return ERR_PTR(-ENOMEM);
+ }
- ret = of_property_read_u16_array(dev->of_node, pname,
- (u16 *)rsv_slots, nelm * 2);
- if (ret)
+ ret = of_property_read_u32_array(dev->of_node, pname,
+ (u32 *)tmp, nelm * 2);
+ if (ret) {
+ kfree(tmp);
return ERR_PTR(ret);
+ }
+ for (i = 0; i < nelm; i++) {
+ rsv_slots[i][0] = tmp[i][0];
+ rsv_slots[i][1] = tmp[i][1];
+ }
rsv_slots[nelm][0] = -1;
rsv_slots[nelm][1] = -1;
+
info->rsv = rsv_info;
info->rsv->rsv_slots = (const s16 (*)[2])rsv_slots;
+
+ kfree(tmp);
}
return info;
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index 7058d58..0f6fd42 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -1462,7 +1462,7 @@ err_firmware:
#define EVENT_REMAP_CELLS 3
-static int __init sdma_event_remap(struct sdma_engine *sdma)
+static int sdma_event_remap(struct sdma_engine *sdma)
{
struct device_node *np = sdma->dev->of_node;
struct device_node *gpr_np = of_parse_phandle(np, "gpr", 0);
diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c
index ebd8a5f..f1bcc2a 100644
--- a/drivers/dma/sh/usb-dmac.c
+++ b/drivers/dma/sh/usb-dmac.c
@@ -679,8 +679,11 @@ static int usb_dmac_runtime_suspend(struct device *dev)
struct usb_dmac *dmac = dev_get_drvdata(dev);
int i;
- for (i = 0; i < dmac->n_channels; ++i)
+ for (i = 0; i < dmac->n_channels; ++i) {
+ if (!dmac->channels[i].iomem)
+ break;
usb_dmac_chan_halt(&dmac->channels[i]);
+ }
return 0;
}
@@ -799,11 +802,10 @@ static int usb_dmac_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (ret < 0) {
dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
- return ret;
+ goto error_pm;
}
ret = usb_dmac_init(dmac);
- pm_runtime_put(&pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to reset device\n");
@@ -851,10 +853,13 @@ static int usb_dmac_probe(struct platform_device *pdev)
if (ret < 0)
goto error;
+ pm_runtime_put(&pdev->dev);
return 0;
error:
of_dma_controller_free(pdev->dev.of_node);
+ pm_runtime_put(&pdev->dev);
+error_pm:
pm_runtime_disable(&pdev->dev);
return ret;
}
diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c
index 9dfa2b0..9cb93c5 100644
--- a/drivers/dma/xgene-dma.c
+++ b/drivers/dma/xgene-dma.c
@@ -29,6 +29,7 @@
#include <linux/dmapool.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -1610,6 +1611,7 @@ static int xgene_dma_request_irqs(struct xgene_dma *pdma)
/* Register DMA channel rx irq */
for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
chan = &pdma->chan[i];
+ irq_set_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
ret = devm_request_irq(chan->dev, chan->rx_irq,
xgene_dma_chan_ring_isr,
0, chan->name, chan);
@@ -1620,6 +1622,7 @@ static int xgene_dma_request_irqs(struct xgene_dma *pdma)
for (j = 0; j < i; j++) {
chan = &pdma->chan[i];
+ irq_clear_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
devm_free_irq(chan->dev, chan->rx_irq, chan);
}
@@ -1640,6 +1643,7 @@ static void xgene_dma_free_irqs(struct xgene_dma *pdma)
for (i = 0; i < XGENE_DMA_MAX_CHANNEL; i++) {
chan = &pdma->chan[i];
+ irq_clear_status_flags(chan->rx_irq, IRQ_DISABLE_UNLAZY);
devm_free_irq(chan->dev, chan->rx_irq, chan);
}
}
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index dbf53e0..be163e2 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -10,7 +10,7 @@ obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o
-edac_core-y += edac_module.o edac_device_sysfs.o
+edac_core-y += edac_module.o edac_device_sysfs.o wq.o
edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index 592af5f..a979003 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -390,11 +390,9 @@ static void edac_device_workq_function(struct work_struct *work_req)
* between integral seconds
*/
if (edac_dev->poll_msec == 1000)
- queue_delayed_work(edac_workqueue, &edac_dev->work,
- round_jiffies_relative(edac_dev->delay));
+ edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
else
- queue_delayed_work(edac_workqueue, &edac_dev->work,
- edac_dev->delay);
+ edac_queue_work(&edac_dev->work, edac_dev->delay);
}
/*
@@ -402,8 +400,8 @@ static void edac_device_workq_function(struct work_struct *work_req)
* initialize a workq item for this edac_device instance
* passing in the new delay period in msec
*/
-void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
- unsigned msec)
+static void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
+ unsigned msec)
{
edac_dbg(0, "\n");
@@ -422,29 +420,23 @@ void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
* to fire together on the 1 second exactly
*/
if (edac_dev->poll_msec == 1000)
- queue_delayed_work(edac_workqueue, &edac_dev->work,
- round_jiffies_relative(edac_dev->delay));
+ edac_queue_work(&edac_dev->work, round_jiffies_relative(edac_dev->delay));
else
- queue_delayed_work(edac_workqueue, &edac_dev->work,
- edac_dev->delay);
+ edac_queue_work(&edac_dev->work, edac_dev->delay);
}
/*
* edac_device_workq_teardown
* stop the workq processing on this edac_dev
*/
-void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
+static void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
{
- int status;
-
if (!edac_dev->edac_check)
return;
- status = cancel_delayed_work(&edac_dev->work);
- if (status == 0) {
- /* workq instance might be running, wait for it */
- flush_workqueue(edac_workqueue);
- }
+ edac_dev->op_state = OP_OFFLINE;
+
+ edac_stop_work(&edac_dev->work);
}
/*
@@ -457,16 +449,15 @@ void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev)
void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev,
unsigned long value)
{
- /* cancel the current workq request, without the mutex lock */
- edac_device_workq_teardown(edac_dev);
+ unsigned long jiffs = msecs_to_jiffies(value);
- /* acquire the mutex before doing the workq setup */
- mutex_lock(&device_ctls_mutex);
+ if (value == 1000)
+ jiffs = round_jiffies_relative(value);
- /* restart the workq request, with new delay value */
- edac_device_workq_setup(edac_dev, value);
+ edac_dev->poll_msec = value;
+ edac_dev->delay = jiffs;
- mutex_unlock(&device_ctls_mutex);
+ edac_mod_work(&edac_dev->work, jiffs);
}
/*
diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index fb68a06..93da1a4 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -237,11 +237,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
/* get the /sys/devices/system/edac reference */
edac_subsys = edac_get_sysfs_subsys();
- if (edac_subsys == NULL) {
- edac_dbg(1, "no edac_subsys error\n");
- err = -ENODEV;
- goto err_out;
- }
/* Point to the 'edac_subsys' this instance 'reports' to */
edac_dev->edac_subsys = edac_subsys;
@@ -256,7 +251,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
if (!try_module_get(edac_dev->owner)) {
err = -ENODEV;
- goto err_mod_get;
+ goto err_out;
}
/* register */
@@ -282,9 +277,6 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
err_kobj_reg:
module_put(edac_dev->owner);
-err_mod_get:
- edac_put_sysfs_subsys();
-
err_out:
return err;
}
@@ -306,7 +298,6 @@ void edac_device_unregister_sysfs_main_kobj(struct edac_device_ctl_info *dev)
* b) 'kfree' the memory
*/
kobject_put(&dev->kobj);
- edac_put_sysfs_subsys();
}
/* edac_dev -> instance information */
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 77ecd6a..8adfc16 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -548,8 +548,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
mutex_unlock(&mem_ctls_mutex);
/* Reschedule */
- queue_delayed_work(edac_workqueue, &mci->work,
- msecs_to_jiffies(edac_mc_get_poll_msec()));
+ edac_queue_work(&mci->work, msecs_to_jiffies(edac_mc_get_poll_msec()));
}
/*
@@ -561,8 +560,7 @@ static void edac_mc_workq_function(struct work_struct *work_req)
*
* called with the mem_ctls_mutex held
*/
-static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
- bool init)
+static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec)
{
edac_dbg(0, "\n");
@@ -570,10 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
if (mci->op_state != OP_RUNNING_POLL)
return;
- if (init)
- INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
+ INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function);
- mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec));
+ edac_queue_work(&mci->work, msecs_to_jiffies(msec));
}
/*
@@ -586,18 +583,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec,
*/
static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
{
- int status;
-
- if (mci->op_state != OP_RUNNING_POLL)
- return;
-
- status = cancel_delayed_work(&mci->work);
- if (status == 0) {
- edac_dbg(0, "not canceled, flush the queue\n");
+ mci->op_state = OP_OFFLINE;
- /* workq instance might be running, wait for it */
- flush_workqueue(edac_workqueue);
- }
+ edac_stop_work(&mci->work);
}
/*
@@ -616,9 +604,8 @@ void edac_mc_reset_delay_period(unsigned long value)
list_for_each(item, &mc_devices) {
mci = list_entry(item, struct mem_ctl_info, link);
- edac_mc_workq_setup(mci, value, false);
+ edac_mod_work(&mci->work, value);
}
-
mutex_unlock(&mem_ctls_mutex);
}
@@ -789,7 +776,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
/* This instance is NOW RUNNING */
mci->op_state = OP_RUNNING_POLL;
- edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true);
+ edac_mc_workq_setup(mci, edac_mc_get_poll_msec());
} else {
mci->op_state = OP_RUNNING_INTERRUPT;
}
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index a75acea..26e65ab 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -880,21 +880,26 @@ static struct device_type mci_attr_type = {
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
const struct attribute_group **groups)
{
+ char *name;
int i, err;
/*
* The memory controller needs its own bus, in order to avoid
* namespace conflicts at /sys/bus/edac.
*/
- mci->bus->name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
- if (!mci->bus->name)
+ name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
+ if (!name)
return -ENOMEM;
+ mci->bus->name = name;
+
edac_dbg(0, "creating bus %s\n", mci->bus->name);
err = bus_register(mci->bus);
- if (err < 0)
- goto fail_free_name;
+ if (err < 0) {
+ kfree(name);
+ return err;
+ }
/* get the /sys/devices/system/edac subsys reference */
mci->dev.type = &mci_attr_type;
@@ -961,8 +966,8 @@ fail_unregister_dimm:
device_unregister(&mci->dev);
fail_unregister_bus:
bus_unregister(mci->bus);
-fail_free_name:
- kfree(mci->bus->name);
+ kfree(name);
+
return err;
}
@@ -993,10 +998,12 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
void edac_unregister_sysfs(struct mem_ctl_info *mci)
{
+ const char *name = mci->bus->name;
+
edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
device_unregister(&mci->dev);
bus_unregister(mci->bus);
- kfree(mci->bus->name);
+ kfree(name);
}
static void mc_attr_release(struct device *dev)
@@ -1018,24 +1025,15 @@ static struct device_type mc_attr_type = {
*/
int __init edac_mc_sysfs_init(void)
{
- struct bus_type *edac_subsys;
int err;
- /* get the /sys/devices/system/edac subsys reference */
- edac_subsys = edac_get_sysfs_subsys();
- if (edac_subsys == NULL) {
- edac_dbg(1, "no edac_subsys\n");
- err = -EINVAL;
- goto out;
- }
-
mci_pdev = kzalloc(sizeof(*mci_pdev), GFP_KERNEL);
if (!mci_pdev) {
err = -ENOMEM;
- goto out_put_sysfs;
+ goto out;
}
- mci_pdev->bus = edac_subsys;
+ mci_pdev->bus = edac_get_sysfs_subsys();
mci_pdev->type = &mc_attr_type;
device_initialize(mci_pdev);
dev_set_name(mci_pdev, "mc");
@@ -1050,8 +1048,6 @@ int __init edac_mc_sysfs_init(void)
out_dev_free:
kfree(mci_pdev);
- out_put_sysfs:
- edac_put_sysfs_subsys();
out:
return err;
}
@@ -1059,5 +1055,4 @@ int __init edac_mc_sysfs_init(void)
void edac_mc_sysfs_exit(void)
{
device_unregister(mci_pdev);
- edac_put_sysfs_subsys();
}
diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c
index 9cb082a..5f8543b 100644
--- a/drivers/edac/edac_module.c
+++ b/drivers/edac/edac_module.c
@@ -43,9 +43,6 @@ module_param_call(edac_debug_level, edac_set_debug_level, param_get_int,
MODULE_PARM_DESC(edac_debug_level, "EDAC debug level: [0-4], default: 2");
#endif
-/* scope is to module level only */
-struct workqueue_struct *edac_workqueue;
-
/*
* edac_op_state_to_string()
*/
@@ -66,31 +63,37 @@ char *edac_op_state_to_string(int opstate)
}
/*
- * edac_workqueue_setup
- * initialize the edac work queue for polling operations
+ * sysfs object: /sys/devices/system/edac
+ * need to export to other files
*/
-static int edac_workqueue_setup(void)
+static struct bus_type edac_subsys = {
+ .name = "edac",
+ .dev_name = "edac",
+};
+
+static int edac_subsys_init(void)
{
- edac_workqueue = create_singlethread_workqueue("edac-poller");
- if (edac_workqueue == NULL)
- return -ENODEV;
- else
- return 0;
+ int err;
+
+ /* create the /sys/devices/system/edac directory */
+ err = subsys_system_register(&edac_subsys, NULL);
+ if (err)
+ printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
+
+ return err;
}
-/*
- * edac_workqueue_teardown
- * teardown the edac workqueue
- */
-static void edac_workqueue_teardown(void)
+static void edac_subsys_exit(void)
{
- if (edac_workqueue) {
- flush_workqueue(edac_workqueue);
- destroy_workqueue(edac_workqueue);
- edac_workqueue = NULL;
- }
+ bus_unregister(&edac_subsys);
}
+/* return pointer to the 'edac' node in sysfs */
+struct bus_type *edac_get_sysfs_subsys(void)
+{
+ return &edac_subsys;
+}
+EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
/*
* edac_init
* module initialization entry point
@@ -101,6 +104,10 @@ static int __init edac_init(void)
edac_printk(KERN_INFO, EDAC_MC, EDAC_VERSION "\n");
+ err = edac_subsys_init();
+ if (err)
+ return err;
+
/*
* Harvest and clear any boot/initialization PCI parity errors
*
@@ -129,6 +136,8 @@ err_wq:
edac_mc_sysfs_exit();
err_sysfs:
+ edac_subsys_exit();
+
return err;
}
@@ -144,6 +153,7 @@ static void __exit edac_exit(void)
edac_workqueue_teardown();
edac_mc_sysfs_exit();
edac_debugfs_exit();
+ edac_subsys_exit();
}
/*
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index b95a48f..cfaacb9 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -47,10 +47,12 @@ extern int edac_device_create_sysfs(struct edac_device_ctl_info *edac_dev);
extern void edac_device_remove_sysfs(struct edac_device_ctl_info *edac_dev);
/* edac core workqueue: single CPU mode */
-extern struct workqueue_struct *edac_workqueue;
-extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
- unsigned msec);
-extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
+int edac_workqueue_setup(void);
+void edac_workqueue_teardown(void);
+bool edac_queue_work(struct delayed_work *work, unsigned long delay);
+bool edac_stop_work(struct delayed_work *work);
+bool edac_mod_work(struct delayed_work *work, unsigned long delay);
+
extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(unsigned long value);
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 2cf44b4d..9968538 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -178,41 +178,6 @@ static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
INIT_LIST_HEAD(&pci->link);
}
-#if 0
-/* Older code, but might use in the future */
-
-/*
- * edac_pci_find()
- * Search for an edac_pci_ctl_info structure whose index is 'idx'
- *
- * If found, return a pointer to the structure
- * Else return NULL.
- *
- * Caller must hold pci_ctls_mutex.
- */
-struct edac_pci_ctl_info *edac_pci_find(int idx)
-{
- struct list_head *item;
- struct edac_pci_ctl_info *pci;
-
- /* Iterage over list, looking for exact match of ID */
- list_for_each(item, &edac_pci_list) {
- pci = list_entry(item, struct edac_pci_ctl_info, link);
-
- if (pci->pci_idx >= idx) {
- if (pci->pci_idx == idx)
- return pci;
-
- /* not on list, so terminate early */
- break;
- }
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(edac_pci_find);
-#endif
-
/*
* edac_pci_workq_function()
*
@@ -244,7 +209,7 @@ static void edac_pci_workq_function(struct work_struct *work_req)
delay = msecs_to_jiffies(msec);
/* Reschedule only if we are in POLL mode */
- queue_delayed_work(edac_workqueue, &pci->work, delay);
+ edac_queue_work(&pci->work, delay);
}
mutex_unlock(&edac_pci_ctls_mutex);
@@ -264,8 +229,8 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
edac_dbg(0, "\n");
INIT_DELAYED_WORK(&pci->work, edac_pci_workq_function);
- queue_delayed_work(edac_workqueue, &pci->work,
- msecs_to_jiffies(edac_pci_get_poll_msec()));
+
+ edac_queue_work(&pci->work, msecs_to_jiffies(edac_pci_get_poll_msec()));
}
/*
@@ -274,37 +239,12 @@ static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
*/
static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
{
- int status;
-
- edac_dbg(0, "\n");
-
- status = cancel_delayed_work(&pci->work);
- if (status == 0)
- flush_workqueue(edac_workqueue);
-}
-
-/*
- * edac_pci_reset_delay_period
- *
- * called with a new period value for the workq period
- * a) stop current workq timer
- * b) restart workq timer with new value
- */
-void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
- unsigned long value)
-{
edac_dbg(0, "\n");
- edac_pci_workq_teardown(pci);
-
- /* need to lock for the setup */
- mutex_lock(&edac_pci_ctls_mutex);
-
- edac_pci_workq_setup(pci, value);
+ pci->op_state = OP_OFFLINE;
- mutex_unlock(&edac_pci_ctls_mutex);
+ edac_stop_work(&pci->work);
}
-EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
/*
* edac_pci_alloc_index: Allocate a unique PCI index number
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 24d877f..6e3428b 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -331,10 +331,7 @@ static struct kobj_type ktype_edac_pci_main_kobj = {
};
/**
- * edac_pci_main_kobj_setup()
- *
- * setup the sysfs for EDAC PCI attributes
- * assumes edac_subsys has already been initialized
+ * edac_pci_main_kobj_setup: Setup the sysfs for EDAC PCI attributes.
*/
static int edac_pci_main_kobj_setup(void)
{
@@ -351,11 +348,6 @@ static int edac_pci_main_kobj_setup(void)
* controls and attributes
*/
edac_subsys = edac_get_sysfs_subsys();
- if (edac_subsys == NULL) {
- edac_dbg(1, "no edac_subsys\n");
- err = -ENODEV;
- goto decrement_count_fail;
- }
/* Bump the reference count on this module to ensure the
* modules isn't unloaded until we deconstruct the top
@@ -364,7 +356,7 @@ static int edac_pci_main_kobj_setup(void)
if (!try_module_get(THIS_MODULE)) {
edac_dbg(1, "try_module_get() failed\n");
err = -ENODEV;
- goto mod_get_fail;
+ goto decrement_count_fail;
}
edac_pci_top_main_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
@@ -399,9 +391,6 @@ kobject_init_and_add_fail:
kzalloc_fail:
module_put(THIS_MODULE);
-mod_get_fail:
- edac_put_sysfs_subsys();
-
decrement_count_fail:
/* if are on this error exit, nothing to tear down */
atomic_dec(&edac_pci_sysfs_refcount);
@@ -426,7 +415,6 @@ static void edac_pci_main_kobj_teardown(void)
if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
edac_dbg(0, "called kobject_put on main kobj\n");
kobject_put(edac_pci_top_main_kobj);
- edac_put_sysfs_subsys();
}
}
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index ff07aae..952e411 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -26,8 +26,6 @@ EXPORT_SYMBOL_GPL(edac_handlers);
int edac_err_assert = 0;
EXPORT_SYMBOL_GPL(edac_err_assert);
-static atomic_t edac_subsys_valid = ATOMIC_INIT(0);
-
int edac_report_status = EDAC_REPORTING_ENABLED;
EXPORT_SYMBOL_GPL(edac_report_status);
@@ -68,42 +66,3 @@ void edac_atomic_assert_error(void)
edac_err_assert++;
}
EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
-
-/*
- * sysfs object: /sys/devices/system/edac
- * need to export to other files
- */
-struct bus_type edac_subsys = {
- .name = "edac",
- .dev_name = "edac",
-};
-EXPORT_SYMBOL_GPL(edac_subsys);
-
-/* return pointer to the 'edac' node in sysfs */
-struct bus_type *edac_get_sysfs_subsys(void)
-{
- int err = 0;
-
- if (atomic_read(&edac_subsys_valid))
- goto out;
-
- /* create the /sys/devices/system/edac directory */
- err = subsys_system_register(&edac_subsys, NULL);
- if (err) {
- printk(KERN_ERR "Error registering toplevel EDAC sysfs dir\n");
- return NULL;
- }
-
-out:
- atomic_inc(&edac_subsys_valid);
- return &edac_subsys;
-}
-EXPORT_SYMBOL_GPL(edac_get_sysfs_subsys);
-
-void edac_put_sysfs_subsys(void)
-{
- /* last user unregisters it */
- if (atomic_dec_and_test(&edac_subsys_valid))
- bus_unregister(&edac_subsys);
-}
-EXPORT_SYMBOL_GPL(edac_put_sysfs_subsys);
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 4091777..c655162 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -575,9 +575,7 @@ static void i5100_check_error(struct mem_ctl_info *mci)
static void i5100_refresh_scrubbing(struct work_struct *work)
{
- struct delayed_work *i5100_scrubbing = container_of(work,
- struct delayed_work,
- work);
+ struct delayed_work *i5100_scrubbing = to_delayed_work(work);
struct i5100_priv *priv = container_of(i5100_scrubbing,
struct i5100_priv,
i5100_scrubbing);
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 23ef8e9..b7139c1 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -20,6 +20,7 @@
#include <linux/edac.h>
#include <linux/smp.h>
#include <linux/gfp.h>
+#include <linux/fsl/edac.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
@@ -238,10 +239,12 @@ static irqreturn_t mpc85xx_pci_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int mpc85xx_pci_err_probe(struct platform_device *op)
+static int mpc85xx_pci_err_probe(struct platform_device *op)
{
struct edac_pci_ctl_info *pci;
struct mpc85xx_pci_pdata *pdata;
+ struct mpc85xx_edac_pci_plat_data *plat_data;
+ struct device_node *of_node;
struct resource r;
int res = 0;
@@ -266,7 +269,15 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->name = "mpc85xx_pci_err";
pdata->irq = NO_IRQ;
- if (mpc85xx_pcie_find_capability(op->dev.of_node) > 0)
+ plat_data = op->dev.platform_data;
+ if (!plat_data) {
+ dev_err(&op->dev, "no platform data");
+ res = -ENXIO;
+ goto err;
+ }
+ of_node = plat_data->of_node;
+
+ if (mpc85xx_pcie_find_capability(of_node) > 0)
pdata->is_pcie = true;
dev_set_drvdata(&op->dev, pci);
@@ -284,7 +295,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
pdata->edac_idx = edac_pci_idx++;
- res = of_address_to_resource(op->dev.of_node, 0, &r);
+ res = of_address_to_resource(of_node, 0, &r);
if (res) {
printk(KERN_ERR "%s: Unable to get resource for "
"PCI err regs\n", __func__);
@@ -339,7 +350,7 @@ int mpc85xx_pci_err_probe(struct platform_device *op)
}
if (edac_op_state == EDAC_OPSTATE_INT) {
- pdata->irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ pdata->irq = irq_of_parse_and_map(of_node, 0);
res = devm_request_irq(&op->dev, pdata->irq,
mpc85xx_pci_isr,
IRQF_SHARED,
@@ -386,8 +397,22 @@ err:
devres_release_group(&op->dev, mpc85xx_pci_err_probe);
return res;
}
-EXPORT_SYMBOL(mpc85xx_pci_err_probe);
+static const struct platform_device_id mpc85xx_pci_err_match[] = {
+ {
+ .name = "mpc85xx-pci-edac"
+ },
+ {}
+};
+
+static struct platform_driver mpc85xx_pci_err_driver = {
+ .probe = mpc85xx_pci_err_probe,
+ .id_table = mpc85xx_pci_err_match,
+ .driver = {
+ .name = "mpc85xx_pci_err",
+ .suppress_bind_attrs = true,
+ },
+};
#endif /* CONFIG_PCI */
/**************************** L2 Err device ***************************/
@@ -1208,6 +1233,14 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
}
#endif
+static struct platform_driver * const drivers[] = {
+ &mpc85xx_mc_err_driver,
+ &mpc85xx_l2_err_driver,
+#ifdef CONFIG_PCI
+ &mpc85xx_pci_err_driver,
+#endif
+};
+
static int __init mpc85xx_mc_init(void)
{
int res = 0;
@@ -1226,13 +1259,9 @@ static int __init mpc85xx_mc_init(void)
break;
}
- res = platform_driver_register(&mpc85xx_mc_err_driver);
- if (res)
- printk(KERN_WARNING EDAC_MOD_STR "MC fails to register\n");
-
- res = platform_driver_register(&mpc85xx_l2_err_driver);
+ res = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (res)
- printk(KERN_WARNING EDAC_MOD_STR "L2 fails to register\n");
+ printk(KERN_WARNING EDAC_MOD_STR "drivers fail to register\n");
#ifdef CONFIG_FSL_SOC_BOOKE
pvr = mfspr(SPRN_PVR);
@@ -1270,8 +1299,7 @@ static void __exit mpc85xx_mc_exit(void)
on_each_cpu(mpc85xx_mc_restore_hid1, NULL, 0);
}
#endif
- platform_driver_unregister(&mpc85xx_l2_err_driver);
- platform_driver_unregister(&mpc85xx_mc_err_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(mpc85xx_mc_exit);
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index 0574e1b..6c54127 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -847,6 +847,15 @@ static struct platform_driver mv64x60_mc_err_driver = {
}
};
+static struct platform_driver * const drivers[] = {
+ &mv64x60_mc_err_driver,
+ &mv64x60_cpu_err_driver,
+ &mv64x60_sram_err_driver,
+#ifdef CONFIG_PCI
+ &mv64x60_pci_err_driver,
+#endif
+};
+
static int __init mv64x60_edac_init(void)
{
int ret = 0;
@@ -863,39 +872,13 @@ static int __init mv64x60_edac_init(void)
break;
}
- ret = platform_driver_register(&mv64x60_mc_err_driver);
- if (ret)
- printk(KERN_WARNING EDAC_MOD_STR "MC err failed to register\n");
-
- ret = platform_driver_register(&mv64x60_cpu_err_driver);
- if (ret)
- printk(KERN_WARNING EDAC_MOD_STR
- "CPU err failed to register\n");
-
- ret = platform_driver_register(&mv64x60_sram_err_driver);
- if (ret)
- printk(KERN_WARNING EDAC_MOD_STR
- "SRAM err failed to register\n");
-
-#ifdef CONFIG_PCI
- ret = platform_driver_register(&mv64x60_pci_err_driver);
- if (ret)
- printk(KERN_WARNING EDAC_MOD_STR
- "PCI err failed to register\n");
-#endif
-
- return ret;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(mv64x60_edac_init);
static void __exit mv64x60_edac_exit(void)
{
-#ifdef CONFIG_PCI
- platform_driver_unregister(&mv64x60_pci_err_driver);
-#endif
- platform_driver_unregister(&mv64x60_sram_err_driver);
- platform_driver_unregister(&mv64x60_cpu_err_driver);
- platform_driver_unregister(&mv64x60_mc_err_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(mv64x60_edac_exit);
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 429309c..e438ee5 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -65,15 +65,20 @@ static const u32 ibridge_dram_rule[] = {
0xd8, 0xe0, 0xe8, 0xf0, 0xf8,
};
-#define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff)
-#define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3)
-#define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1)
+static const u32 knl_dram_rule[] = {
+ 0x60, 0x68, 0x70, 0x78, 0x80, /* 0-4 */
+ 0x88, 0x90, 0x98, 0xa0, 0xa8, /* 5-9 */
+ 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, /* 10-14 */
+ 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, /* 15-19 */
+ 0x100, 0x108, 0x110, 0x118, /* 20-23 */
+};
+
#define DRAM_RULE_ENABLE(reg) GET_BITFIELD(reg, 0, 0)
#define A7MODE(reg) GET_BITFIELD(reg, 26, 26)
-static char *get_dram_attr(u32 reg)
+static char *show_dram_attr(u32 attr)
{
- switch(DRAM_ATTR(reg)) {
+ switch (attr) {
case 0:
return "DRAM";
case 1:
@@ -97,6 +102,14 @@ static const u32 ibridge_interleave_list[] = {
0xdc, 0xe4, 0xec, 0xf4, 0xfc,
};
+static const u32 knl_interleave_list[] = {
+ 0x64, 0x6c, 0x74, 0x7c, 0x84, /* 0-4 */
+ 0x8c, 0x94, 0x9c, 0xa4, 0xac, /* 5-9 */
+ 0xb4, 0xbc, 0xc4, 0xcc, 0xd4, /* 10-14 */
+ 0xdc, 0xe4, 0xec, 0xf4, 0xfc, /* 15-19 */
+ 0x104, 0x10c, 0x114, 0x11c, /* 20-23 */
+};
+
struct interleave_pkg {
unsigned char start;
unsigned char end;
@@ -134,10 +147,13 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
/* Devices 12 Function 7 */
#define TOLM 0x80
-#define TOHM 0x84
+#define TOHM 0x84
#define HASWELL_TOLM 0xd0
#define HASWELL_TOHM_0 0xd4
#define HASWELL_TOHM_1 0xd8
+#define KNL_TOLM 0xd0
+#define KNL_TOHM_0 0xd4
+#define KNL_TOHM_1 0xd8
#define GET_TOLM(reg) ((GET_BITFIELD(reg, 0, 3) << 28) | 0x3ffffff)
#define GET_TOHM(reg) ((GET_BITFIELD(reg, 0, 20) << 25) | 0x3ffffff)
@@ -148,6 +164,8 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
#define SOURCE_ID(reg) GET_BITFIELD(reg, 9, 11)
+#define SOURCE_ID_KNL(reg) GET_BITFIELD(reg, 12, 14)
+
#define SAD_CONTROL 0xf4
/* Device 14 function 0 */
@@ -170,6 +188,7 @@ static const u32 tad_dram_rule[] = {
/* Device 15, function 0 */
#define MCMTR 0x7c
+#define KNL_MCMTR 0x624
#define IS_ECC_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 2, 2)
#define IS_LOCKSTEP_ENABLED(mcmtr) GET_BITFIELD(mcmtr, 1, 1)
@@ -186,6 +205,8 @@ static const int mtr_regs[] = {
0x80, 0x84, 0x88,
};
+static const int knl_mtr_reg = 0xb60;
+
#define RANK_DISABLE(mtr) GET_BITFIELD(mtr, 16, 19)
#define IS_DIMM_PRESENT(mtr) GET_BITFIELD(mtr, 14, 14)
#define RANK_CNT_BITS(mtr) GET_BITFIELD(mtr, 12, 13)
@@ -256,6 +277,9 @@ static const u32 correrrthrsld[] = {
#define NUM_CHANNELS 8 /* 2MC per socket, four chan per MC */
#define MAX_DIMMS 3 /* Max DIMMS per channel */
+#define KNL_MAX_CHAS 38 /* KNL max num. of Cache Home Agents */
+#define KNL_MAX_CHANNELS 6 /* KNL max num. of PCI channels */
+#define KNL_MAX_EDCS 8 /* Embedded DRAM controllers */
#define CHANNEL_UNSPECIFIED 0xf /* Intel IA32 SDM 15-14 */
enum type {
@@ -263,6 +287,7 @@ enum type {
IVY_BRIDGE,
HASWELL,
BROADWELL,
+ KNIGHTS_LANDING,
};
struct sbridge_pvt;
@@ -273,6 +298,10 @@ struct sbridge_info {
u64 (*get_tolm)(struct sbridge_pvt *pvt);
u64 (*get_tohm)(struct sbridge_pvt *pvt);
u64 (*rir_limit)(u32 reg);
+ u64 (*sad_limit)(u32 reg);
+ u32 (*interleave_mode)(u32 reg);
+ char* (*show_interleave_mode)(u32 reg);
+ u32 (*dram_attr)(u32 reg);
const u32 *dram_rule;
const u32 *interleave_list;
const struct interleave_pkg *interleave_pkg;
@@ -308,6 +337,16 @@ struct sbridge_dev {
struct mem_ctl_info *mci;
};
+struct knl_pvt {
+ struct pci_dev *pci_cha[KNL_MAX_CHAS];
+ struct pci_dev *pci_channel[KNL_MAX_CHANNELS];
+ struct pci_dev *pci_mc0;
+ struct pci_dev *pci_mc1;
+ struct pci_dev *pci_mc0_misc;
+ struct pci_dev *pci_mc1_misc;
+ struct pci_dev *pci_mc_info; /* tolm, tohm */
+};
+
struct sbridge_pvt {
struct pci_dev *pci_ta, *pci_ddrio, *pci_ras;
struct pci_dev *pci_sad0, *pci_sad1;
@@ -336,6 +375,7 @@ struct sbridge_pvt {
/* Memory description */
u64 tolm, tohm;
+ struct knl_pvt knl;
};
#define PCI_DESCR(device_id, opt) \
@@ -509,6 +549,50 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
{0,} /* 0 terminated list. */
};
+/* Knight's Landing Support */
+/*
+ * KNL's memory channels are swizzled between memory controllers.
+ * MC0 is mapped to CH3,5,6 and MC1 is mapped to CH0,1,2
+ */
+#define knl_channel_remap(channel) ((channel + 3) % 6)
+
+/* Memory controller, TAD tables, error injection - 2-8-0, 2-9-0 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_MC 0x7840
+/* DRAM channel stuff; bank addrs, dimmmtr, etc.. 2-8-2 - 2-9-4 (6 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL 0x7843
+/* kdrwdbu TAD limits/offsets, MCMTR - 2-10-1, 2-11-1 (2 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TA 0x7844
+/* CHA broadcast registers, dram rules - 1-29-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0 0x782a
+/* SAD target - 1-29-1 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1 0x782b
+/* Caching / Home Agent */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_CHA 0x782c
+/* Device with TOLM and TOHM, 0-5-0 (1 of these) */
+#define PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM 0x7810
+
+/*
+ * KNL differs from SB, IB, and Haswell in that it has multiple
+ * instances of the same device with the same device ID, so we handle that
+ * by creating as many copies in the table as we expect to find.
+ * (Like device ID must be grouped together.)
+ */
+
+static const struct pci_id_descr pci_dev_descr_knl[] = {
+ [0] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0, 0) },
+ [1] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1, 0) },
+ [2 ... 3] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_MC, 0)},
+ [4 ... 41] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHA, 0) },
+ [42 ... 47] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL, 0) },
+ [48] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TA, 0) },
+ [49] = { PCI_DESCR(PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM, 0) },
+};
+
+static const struct pci_id_table pci_dev_descr_knl_table[] = {
+ PCI_ID_TABLE_ENTRY(pci_dev_descr_knl),
+ {0,}
+};
+
/*
* Broadwell support
*
@@ -585,6 +669,7 @@ static const struct pci_device_id sbridge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)},
{0,} /* 0 terminated list. */
};
@@ -598,7 +683,7 @@ static inline int numrank(enum type type, u32 mtr)
int ranks = (1 << RANK_CNT_BITS(mtr));
int max = 4;
- if (type == HASWELL || type == BROADWELL)
+ if (type == HASWELL || type == BROADWELL || type == KNIGHTS_LANDING)
max = 8;
if (ranks > max) {
@@ -636,10 +721,19 @@ static inline int numcol(u32 mtr)
return 1 << cols;
}
-static struct sbridge_dev *get_sbridge_dev(u8 bus)
+static struct sbridge_dev *get_sbridge_dev(u8 bus, int multi_bus)
{
struct sbridge_dev *sbridge_dev;
+ /*
+ * If we have devices scattered across several busses that pertain
+ * to the same memory controller, we'll lump them all together.
+ */
+ if (multi_bus) {
+ return list_first_entry_or_null(&sbridge_edac_list,
+ struct sbridge_dev, list);
+ }
+
list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
if (sbridge_dev->bus == bus)
return sbridge_dev;
@@ -718,6 +812,67 @@ static u64 rir_limit(u32 reg)
return ((u64)GET_BITFIELD(reg, 1, 10) << 29) | 0x1fffffff;
}
+static u64 sad_limit(u32 reg)
+{
+ return (GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff;
+}
+
+static u32 interleave_mode(u32 reg)
+{
+ return GET_BITFIELD(reg, 1, 1);
+}
+
+char *show_interleave_mode(u32 reg)
+{
+ return interleave_mode(reg) ? "8:6" : "[8:6]XOR[18:16]";
+}
+
+static u32 dram_attr(u32 reg)
+{
+ return GET_BITFIELD(reg, 2, 3);
+}
+
+static u64 knl_sad_limit(u32 reg)
+{
+ return (GET_BITFIELD(reg, 7, 26) << 26) | 0x3ffffff;
+}
+
+static u32 knl_interleave_mode(u32 reg)
+{
+ return GET_BITFIELD(reg, 1, 2);
+}
+
+static char *knl_show_interleave_mode(u32 reg)
+{
+ char *s;
+
+ switch (knl_interleave_mode(reg)) {
+ case 0:
+ s = "use address bits [8:6]";
+ break;
+ case 1:
+ s = "use address bits [10:8]";
+ break;
+ case 2:
+ s = "use address bits [14:12]";
+ break;
+ case 3:
+ s = "use address bits [32:30]";
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ return s;
+}
+
+static u32 dram_attr_knl(u32 reg)
+{
+ return GET_BITFIELD(reg, 3, 4);
+}
+
+
static enum mem_type get_memory_type(struct sbridge_pvt *pvt)
{
u32 reg;
@@ -769,6 +924,12 @@ out:
return mtype;
}
+static enum dev_type knl_get_width(struct sbridge_pvt *pvt, u32 mtr)
+{
+ /* for KNL value is fixed */
+ return DEV_X16;
+}
+
static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr)
{
/* there's no way to figure out */
@@ -812,6 +973,12 @@ static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr)
return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9));
}
+static enum mem_type knl_get_memory_type(struct sbridge_pvt *pvt)
+{
+ /* DDR4 RDIMMS and LRDIMMS are supported */
+ return MEM_RDDR4;
+}
+
static u8 get_node_id(struct sbridge_pvt *pvt)
{
u32 reg;
@@ -827,6 +994,15 @@ static u8 haswell_get_node_id(struct sbridge_pvt *pvt)
return GET_BITFIELD(reg, 0, 3);
}
+static u8 knl_get_node_id(struct sbridge_pvt *pvt)
+{
+ u32 reg;
+
+ pci_read_config_dword(pvt->pci_sad1, SAD_CONTROL, &reg);
+ return GET_BITFIELD(reg, 0, 2);
+}
+
+
static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
{
u32 reg;
@@ -848,6 +1024,26 @@ static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
return rc | 0x1ffffff;
}
+static u64 knl_get_tolm(struct sbridge_pvt *pvt)
+{
+ u32 reg;
+
+ pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOLM, &reg);
+ return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
+}
+
+static u64 knl_get_tohm(struct sbridge_pvt *pvt)
+{
+ u64 rc;
+ u32 reg_lo, reg_hi;
+
+ pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_0, &reg_lo);
+ pci_read_config_dword(pvt->knl.pci_mc_info, KNL_TOHM_1, &reg_hi);
+ rc = ((u64)reg_hi << 32) | reg_lo;
+ return rc | 0x3ffffff;
+}
+
+
static u64 haswell_rir_limit(u32 reg)
{
return (((u64)GET_BITFIELD(reg, 1, 11) + 1) << 29) - 1;
@@ -905,11 +1101,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
case BROADWELL:
id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
break;
+ case KNIGHTS_LANDING:
+ /*
+ * KNL doesn't group things by bus the same way
+ * SB/IB/Haswell does.
+ */
+ id = PCI_DEVICE_ID_INTEL_KNL_IMC_TA;
+ break;
default:
return -ENODEV;
}
- pdev = get_pdev_same_bus(bus, id);
+ if (type != KNIGHTS_LANDING)
+ pdev = get_pdev_same_bus(bus, id);
+ else
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, id, 0);
+
if (!pdev) {
sbridge_printk(KERN_ERR, "Couldn't find PCI device "
"%04x:%04x! on bus %02d\n",
@@ -917,7 +1124,8 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
return -ENODEV;
}
- pci_read_config_dword(pdev, MCMTR, &mcmtr);
+ pci_read_config_dword(pdev,
+ type == KNIGHTS_LANDING ? KNL_MCMTR : MCMTR, &mcmtr);
if (!IS_ECC_ENABLED(mcmtr)) {
sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
return -ENODEV;
@@ -925,6 +1133,476 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
return 0;
}
+/* Low bits of TAD limit, and some metadata. */
+static const u32 knl_tad_dram_limit_lo[] = {
+ 0x400, 0x500, 0x600, 0x700,
+ 0x800, 0x900, 0xa00, 0xb00,
+};
+
+/* Low bits of TAD offset. */
+static const u32 knl_tad_dram_offset_lo[] = {
+ 0x404, 0x504, 0x604, 0x704,
+ 0x804, 0x904, 0xa04, 0xb04,
+};
+
+/* High 16 bits of TAD limit and offset. */
+static const u32 knl_tad_dram_hi[] = {
+ 0x408, 0x508, 0x608, 0x708,
+ 0x808, 0x908, 0xa08, 0xb08,
+};
+
+/* Number of ways a tad entry is interleaved. */
+static const u32 knl_tad_ways[] = {
+ 8, 6, 4, 3, 2, 1,
+};
+
+/*
+ * Retrieve the n'th Target Address Decode table entry
+ * from the memory controller's TAD table.
+ *
+ * @pvt: driver private data
+ * @entry: which entry you want to retrieve
+ * @mc: which memory controller (0 or 1)
+ * @offset: output tad range offset
+ * @limit: output address of first byte above tad range
+ * @ways: output number of interleave ways
+ *
+ * The offset value has curious semantics. It's a sort of running total
+ * of the sizes of all the memory regions that aren't mapped in this
+ * tad table.
+ */
+static int knl_get_tad(const struct sbridge_pvt *pvt,
+ const int entry,
+ const int mc,
+ u64 *offset,
+ u64 *limit,
+ int *ways)
+{
+ u32 reg_limit_lo, reg_offset_lo, reg_hi;
+ struct pci_dev *pci_mc;
+ int way_id;
+
+ switch (mc) {
+ case 0:
+ pci_mc = pvt->knl.pci_mc0;
+ break;
+ case 1:
+ pci_mc = pvt->knl.pci_mc1;
+ break;
+ default:
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
+ pci_read_config_dword(pci_mc,
+ knl_tad_dram_limit_lo[entry], &reg_limit_lo);
+ pci_read_config_dword(pci_mc,
+ knl_tad_dram_offset_lo[entry], &reg_offset_lo);
+ pci_read_config_dword(pci_mc,
+ knl_tad_dram_hi[entry], &reg_hi);
+
+ /* Is this TAD entry enabled? */
+ if (!GET_BITFIELD(reg_limit_lo, 0, 0))
+ return -ENODEV;
+
+ way_id = GET_BITFIELD(reg_limit_lo, 3, 5);
+
+ if (way_id < ARRAY_SIZE(knl_tad_ways)) {
+ *ways = knl_tad_ways[way_id];
+ } else {
+ *ways = 0;
+ sbridge_printk(KERN_ERR,
+ "Unexpected value %d in mc_tad_limit_lo wayness field\n",
+ way_id);
+ return -ENODEV;
+ }
+
+ /*
+ * The least significant 6 bits of base and limit are truncated.
+ * For limit, we fill the missing bits with 1s.
+ */
+ *offset = ((u64) GET_BITFIELD(reg_offset_lo, 6, 31) << 6) |
+ ((u64) GET_BITFIELD(reg_hi, 0, 15) << 32);
+ *limit = ((u64) GET_BITFIELD(reg_limit_lo, 6, 31) << 6) | 63 |
+ ((u64) GET_BITFIELD(reg_hi, 16, 31) << 32);
+
+ return 0;
+}
+
+/* Determine which memory controller is responsible for a given channel. */
+static int knl_channel_mc(int channel)
+{
+ WARN_ON(channel < 0 || channel >= 6);
+
+ return channel < 3 ? 1 : 0;
+}
+
+/*
+ * Get the Nth entry from EDC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ * physical EDC modules.)
+ *
+ * entry 0: 0:2
+ * 1: 3:5
+ * 2: 6:8
+ * 3: 9:11
+ * 4: 12:14
+ * 5: 15:17
+ * 6: 18:20
+ * 7: 21:23
+ * reserved: 24:31
+ */
+static u32 knl_get_edc_route(int entry, u32 reg)
+{
+ WARN_ON(entry >= KNL_MAX_EDCS);
+ return GET_BITFIELD(reg, entry*3, (entry*3)+2);
+}
+
+/*
+ * Get the Nth entry from MC_ROUTE_TABLE register.
+ * (This is the per-tile mapping of logical interleave targets to
+ * physical DRAM channels modules.)
+ *
+ * entry 0: mc 0:2 channel 18:19
+ * 1: mc 3:5 channel 20:21
+ * 2: mc 6:8 channel 22:23
+ * 3: mc 9:11 channel 24:25
+ * 4: mc 12:14 channel 26:27
+ * 5: mc 15:17 channel 28:29
+ * reserved: 30:31
+ *
+ * Though we have 3 bits to identify the MC, we should only see
+ * the values 0 or 1.
+ */
+
+static u32 knl_get_mc_route(int entry, u32 reg)
+{
+ int mc, chan;
+
+ WARN_ON(entry >= KNL_MAX_CHANNELS);
+
+ mc = GET_BITFIELD(reg, entry*3, (entry*3)+2);
+ chan = GET_BITFIELD(reg, (entry*2) + 18, (entry*2) + 18 + 1);
+
+ return knl_channel_remap(mc*3 + chan);
+}
+
+/*
+ * Render the EDC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_EDCS*2 bytes.
+ */
+static void knl_show_edc_route(u32 reg, char *s)
+{
+ int i;
+
+ for (i = 0; i < KNL_MAX_EDCS; i++) {
+ s[i*2] = knl_get_edc_route(i, reg) + '0';
+ s[i*2+1] = '-';
+ }
+
+ s[KNL_MAX_EDCS*2 - 1] = '\0';
+}
+
+/*
+ * Render the MC_ROUTE register in human-readable form.
+ * Output string s should be at least KNL_MAX_CHANNELS*2 bytes.
+ */
+static void knl_show_mc_route(u32 reg, char *s)
+{
+ int i;
+
+ for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+ s[i*2] = knl_get_mc_route(i, reg) + '0';
+ s[i*2+1] = '-';
+ }
+
+ s[KNL_MAX_CHANNELS*2 - 1] = '\0';
+}
+
+#define KNL_EDC_ROUTE 0xb8
+#define KNL_MC_ROUTE 0xb4
+
+/* Is this dram rule backed by regular DRAM in flat mode? */
+#define KNL_EDRAM(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this dram rule cached? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule backed by edc ? */
+#define KNL_EDRAM_ONLY(reg) GET_BITFIELD(reg, 29, 29)
+
+/* Is this rule backed by DRAM, cacheable in EDRAM? */
+#define KNL_CACHEABLE(reg) GET_BITFIELD(reg, 28, 28)
+
+/* Is this rule mod3? */
+#define KNL_MOD3(reg) GET_BITFIELD(reg, 27, 27)
+
+/*
+ * Figure out how big our RAM modules are.
+ *
+ * The DIMMMTR register in KNL doesn't tell us the size of the DIMMs, so we
+ * have to figure this out from the SAD rules, interleave lists, route tables,
+ * and TAD rules.
+ *
+ * SAD rules can have holes in them (e.g. the 3G-4G hole), so we have to
+ * inspect the TAD rules to figure out how large the SAD regions really are.
+ *
+ * When we know the real size of a SAD region and how many ways it's
+ * interleaved, we know the individual contribution of each channel to
+ * TAD is size/ways.
+ *
+ * Finally, we have to check whether each channel participates in each SAD
+ * region.
+ *
+ * Fortunately, KNL only supports one DIMM per channel, so once we know how
+ * much memory the channel uses, we know the DIMM is at least that large.
+ * (The BIOS might possibly choose not to map all available memory, in which
+ * case we will underreport the size of the DIMM.)
+ *
+ * In theory, we could try to determine the EDC sizes as well, but that would
+ * only work in flat mode, not in cache mode.
+ *
+ * @mc_sizes: Output sizes of channels (must have space for KNL_MAX_CHANNELS
+ * elements)
+ */
+static int knl_get_dimm_capacity(struct sbridge_pvt *pvt, u64 *mc_sizes)
+{
+ u64 sad_base, sad_size, sad_limit = 0;
+ u64 tad_base, tad_size, tad_limit, tad_deadspace, tad_livespace;
+ int sad_rule = 0;
+ int tad_rule = 0;
+ int intrlv_ways, tad_ways;
+ u32 first_pkg, pkg;
+ int i;
+ u64 sad_actual_size[2]; /* sad size accounting for holes, per mc */
+ u32 dram_rule, interleave_reg;
+ u32 mc_route_reg[KNL_MAX_CHAS];
+ u32 edc_route_reg[KNL_MAX_CHAS];
+ int edram_only;
+ char edc_route_string[KNL_MAX_EDCS*2];
+ char mc_route_string[KNL_MAX_CHANNELS*2];
+ int cur_reg_start;
+ int mc;
+ int channel;
+ int way;
+ int participants[KNL_MAX_CHANNELS];
+ int participant_count = 0;
+
+ for (i = 0; i < KNL_MAX_CHANNELS; i++)
+ mc_sizes[i] = 0;
+
+ /* Read the EDC route table in each CHA. */
+ cur_reg_start = 0;
+ for (i = 0; i < KNL_MAX_CHAS; i++) {
+ pci_read_config_dword(pvt->knl.pci_cha[i],
+ KNL_EDC_ROUTE, &edc_route_reg[i]);
+
+ if (i > 0 && edc_route_reg[i] != edc_route_reg[i-1]) {
+ knl_show_edc_route(edc_route_reg[i-1],
+ edc_route_string);
+ if (cur_reg_start == i-1)
+ edac_dbg(0, "edc route table for CHA %d: %s\n",
+ cur_reg_start, edc_route_string);
+ else
+ edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+ cur_reg_start, i-1, edc_route_string);
+ cur_reg_start = i;
+ }
+ }
+ knl_show_edc_route(edc_route_reg[i-1], edc_route_string);
+ if (cur_reg_start == i-1)
+ edac_dbg(0, "edc route table for CHA %d: %s\n",
+ cur_reg_start, edc_route_string);
+ else
+ edac_dbg(0, "edc route table for CHA %d-%d: %s\n",
+ cur_reg_start, i-1, edc_route_string);
+
+ /* Read the MC route table in each CHA. */
+ cur_reg_start = 0;
+ for (i = 0; i < KNL_MAX_CHAS; i++) {
+ pci_read_config_dword(pvt->knl.pci_cha[i],
+ KNL_MC_ROUTE, &mc_route_reg[i]);
+
+ if (i > 0 && mc_route_reg[i] != mc_route_reg[i-1]) {
+ knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+ if (cur_reg_start == i-1)
+ edac_dbg(0, "mc route table for CHA %d: %s\n",
+ cur_reg_start, mc_route_string);
+ else
+ edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+ cur_reg_start, i-1, mc_route_string);
+ cur_reg_start = i;
+ }
+ }
+ knl_show_mc_route(mc_route_reg[i-1], mc_route_string);
+ if (cur_reg_start == i-1)
+ edac_dbg(0, "mc route table for CHA %d: %s\n",
+ cur_reg_start, mc_route_string);
+ else
+ edac_dbg(0, "mc route table for CHA %d-%d: %s\n",
+ cur_reg_start, i-1, mc_route_string);
+
+ /* Process DRAM rules */
+ for (sad_rule = 0; sad_rule < pvt->info.max_sad; sad_rule++) {
+ /* previous limit becomes the new base */
+ sad_base = sad_limit;
+
+ pci_read_config_dword(pvt->pci_sad0,
+ pvt->info.dram_rule[sad_rule], &dram_rule);
+
+ if (!DRAM_RULE_ENABLE(dram_rule))
+ break;
+
+ edram_only = KNL_EDRAM_ONLY(dram_rule);
+
+ sad_limit = pvt->info.sad_limit(dram_rule)+1;
+ sad_size = sad_limit - sad_base;
+
+ pci_read_config_dword(pvt->pci_sad0,
+ pvt->info.interleave_list[sad_rule], &interleave_reg);
+
+ /*
+ * Find out how many ways this dram rule is interleaved.
+ * We stop when we see the first channel again.
+ */
+ first_pkg = sad_pkg(pvt->info.interleave_pkg,
+ interleave_reg, 0);
+ for (intrlv_ways = 1; intrlv_ways < 8; intrlv_ways++) {
+ pkg = sad_pkg(pvt->info.interleave_pkg,
+ interleave_reg, intrlv_ways);
+
+ if ((pkg & 0x8) == 0) {
+ /*
+ * 0 bit means memory is non-local,
+ * which KNL doesn't support
+ */
+ edac_dbg(0, "Unexpected interleave target %d\n",
+ pkg);
+ return -1;
+ }
+
+ if (pkg == first_pkg)
+ break;
+ }
+ if (KNL_MOD3(dram_rule))
+ intrlv_ways *= 3;
+
+ edac_dbg(3, "dram rule %d (base 0x%llx, limit 0x%llx), %d way interleave%s\n",
+ sad_rule,
+ sad_base,
+ sad_limit,
+ intrlv_ways,
+ edram_only ? ", EDRAM" : "");
+
+ /*
+ * Find out how big the SAD region really is by iterating
+ * over TAD tables (SAD regions may contain holes).
+ * Each memory controller might have a different TAD table, so
+ * we have to look at both.
+ *
+ * Livespace is the memory that's mapped in this TAD table,
+ * deadspace is the holes (this could be the MMIO hole, or it
+ * could be memory that's mapped by the other TAD table but
+ * not this one).
+ */
+ for (mc = 0; mc < 2; mc++) {
+ sad_actual_size[mc] = 0;
+ tad_livespace = 0;
+ for (tad_rule = 0;
+ tad_rule < ARRAY_SIZE(
+ knl_tad_dram_limit_lo);
+ tad_rule++) {
+ if (knl_get_tad(pvt,
+ tad_rule,
+ mc,
+ &tad_deadspace,
+ &tad_limit,
+ &tad_ways))
+ break;
+
+ tad_size = (tad_limit+1) -
+ (tad_livespace + tad_deadspace);
+ tad_livespace += tad_size;
+ tad_base = (tad_limit+1) - tad_size;
+
+ if (tad_base < sad_base) {
+ if (tad_limit > sad_base)
+ edac_dbg(0, "TAD region overlaps lower SAD boundary -- TAD tables may be configured incorrectly.\n");
+ } else if (tad_base < sad_limit) {
+ if (tad_limit+1 > sad_limit) {
+ edac_dbg(0, "TAD region overlaps upper SAD boundary -- TAD tables may be configured incorrectly.\n");
+ } else {
+ /* TAD region is completely inside SAD region */
+ edac_dbg(3, "TAD region %d 0x%llx - 0x%llx (%lld bytes) table%d\n",
+ tad_rule, tad_base,
+ tad_limit, tad_size,
+ mc);
+ sad_actual_size[mc] += tad_size;
+ }
+ }
+ tad_base = tad_limit+1;
+ }
+ }
+
+ for (mc = 0; mc < 2; mc++) {
+ edac_dbg(3, " total TAD DRAM footprint in table%d : 0x%llx (%lld bytes)\n",
+ mc, sad_actual_size[mc], sad_actual_size[mc]);
+ }
+
+ /* Ignore EDRAM rule */
+ if (edram_only)
+ continue;
+
+ /* Figure out which channels participate in interleave. */
+ for (channel = 0; channel < KNL_MAX_CHANNELS; channel++)
+ participants[channel] = 0;
+
+ /* For each channel, does at least one CHA have
+ * this channel mapped to the given target?
+ */
+ for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+ for (way = 0; way < intrlv_ways; way++) {
+ int target;
+ int cha;
+
+ if (KNL_MOD3(dram_rule))
+ target = way;
+ else
+ target = 0x7 & sad_pkg(
+ pvt->info.interleave_pkg, interleave_reg, way);
+
+ for (cha = 0; cha < KNL_MAX_CHAS; cha++) {
+ if (knl_get_mc_route(target,
+ mc_route_reg[cha]) == channel
+ && participants[channel]) {
+ participant_count++;
+ participants[channel] = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ if (participant_count != intrlv_ways)
+ edac_dbg(0, "participant_count (%d) != interleave_ways (%d): DIMM size may be incorrect\n",
+ participant_count, intrlv_ways);
+
+ for (channel = 0; channel < KNL_MAX_CHANNELS; channel++) {
+ mc = knl_channel_mc(channel);
+ if (participants[channel]) {
+ edac_dbg(4, "mc channel %d contributes %lld bytes via sad entry %d\n",
+ channel,
+ sad_actual_size[mc]/intrlv_ways,
+ sad_rule);
+ mc_sizes[channel] +=
+ sad_actual_size[mc]/intrlv_ways;
+ }
+ }
+ }
+
+ return 0;
+}
+
static int get_dimm_config(struct mem_ctl_info *mci)
{
struct sbridge_pvt *pvt = mci->pvt_info;
@@ -934,13 +1612,20 @@ static int get_dimm_config(struct mem_ctl_info *mci)
u32 reg;
enum edac_type mode;
enum mem_type mtype;
+ int channels = pvt->info.type == KNIGHTS_LANDING ?
+ KNL_MAX_CHANNELS : NUM_CHANNELS;
+ u64 knl_mc_sizes[KNL_MAX_CHANNELS];
- if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL)
+ if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL ||
+ pvt->info.type == KNIGHTS_LANDING)
pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
else
pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
- pvt->sbridge_dev->source_id = SOURCE_ID(reg);
+ if (pvt->info.type == KNIGHTS_LANDING)
+ pvt->sbridge_dev->source_id = SOURCE_ID_KNL(reg);
+ else
+ pvt->sbridge_dev->source_id = SOURCE_ID(reg);
pvt->sbridge_dev->node_id = pvt->info.get_node_id(pvt);
edac_dbg(0, "mc#%d: Node ID: %d, source ID: %d\n",
@@ -948,31 +1633,42 @@ static int get_dimm_config(struct mem_ctl_info *mci)
pvt->sbridge_dev->node_id,
pvt->sbridge_dev->source_id);
- pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
- if (IS_MIRROR_ENABLED(reg)) {
- edac_dbg(0, "Memory mirror is enabled\n");
- pvt->is_mirrored = true;
- } else {
- edac_dbg(0, "Memory mirror is disabled\n");
+ /* KNL doesn't support mirroring or lockstep,
+ * and is always closed page
+ */
+ if (pvt->info.type == KNIGHTS_LANDING) {
+ mode = EDAC_S4ECD4ED;
pvt->is_mirrored = false;
- }
- pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
- if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
- edac_dbg(0, "Lockstep is enabled\n");
- mode = EDAC_S8ECD8ED;
- pvt->is_lockstep = true;
+ if (knl_get_dimm_capacity(pvt, knl_mc_sizes) != 0)
+ return -1;
} else {
- edac_dbg(0, "Lockstep is disabled\n");
- mode = EDAC_S4ECD4ED;
- pvt->is_lockstep = false;
- }
- if (IS_CLOSE_PG(pvt->info.mcmtr)) {
- edac_dbg(0, "address map is on closed page mode\n");
- pvt->is_close_pg = true;
- } else {
- edac_dbg(0, "address map is on open page mode\n");
- pvt->is_close_pg = false;
+ pci_read_config_dword(pvt->pci_ras, RASENABLES, &reg);
+ if (IS_MIRROR_ENABLED(reg)) {
+ edac_dbg(0, "Memory mirror is enabled\n");
+ pvt->is_mirrored = true;
+ } else {
+ edac_dbg(0, "Memory mirror is disabled\n");
+ pvt->is_mirrored = false;
+ }
+
+ pci_read_config_dword(pvt->pci_ta, MCMTR, &pvt->info.mcmtr);
+ if (IS_LOCKSTEP_ENABLED(pvt->info.mcmtr)) {
+ edac_dbg(0, "Lockstep is enabled\n");
+ mode = EDAC_S8ECD8ED;
+ pvt->is_lockstep = true;
+ } else {
+ edac_dbg(0, "Lockstep is disabled\n");
+ mode = EDAC_S4ECD4ED;
+ pvt->is_lockstep = false;
+ }
+ if (IS_CLOSE_PG(pvt->info.mcmtr)) {
+ edac_dbg(0, "address map is on closed page mode\n");
+ pvt->is_close_pg = true;
+ } else {
+ edac_dbg(0, "address map is on open page mode\n");
+ pvt->is_close_pg = false;
+ }
}
mtype = pvt->info.get_memory_type(pvt);
@@ -988,23 +1684,46 @@ static int get_dimm_config(struct mem_ctl_info *mci)
else
banks = 8;
- for (i = 0; i < NUM_CHANNELS; i++) {
+ for (i = 0; i < channels; i++) {
u32 mtr;
- if (!pvt->pci_tad[i])
- continue;
- for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
+ int max_dimms_per_channel;
+
+ if (pvt->info.type == KNIGHTS_LANDING) {
+ max_dimms_per_channel = 1;
+ if (!pvt->knl.pci_channel[i])
+ continue;
+ } else {
+ max_dimms_per_channel = ARRAY_SIZE(mtr_regs);
+ if (!pvt->pci_tad[i])
+ continue;
+ }
+
+ for (j = 0; j < max_dimms_per_channel; j++) {
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
i, j, 0);
- pci_read_config_dword(pvt->pci_tad[i],
- mtr_regs[j], &mtr);
+ if (pvt->info.type == KNIGHTS_LANDING) {
+ pci_read_config_dword(pvt->knl.pci_channel[i],
+ knl_mtr_reg, &mtr);
+ } else {
+ pci_read_config_dword(pvt->pci_tad[i],
+ mtr_regs[j], &mtr);
+ }
edac_dbg(4, "Channel #%d MTR%d = %x\n", i, j, mtr);
if (IS_DIMM_PRESENT(mtr)) {
pvt->channel[i].dimms++;
ranks = numrank(pvt->info.type, mtr);
- rows = numrow(mtr);
- cols = numcol(mtr);
+
+ if (pvt->info.type == KNIGHTS_LANDING) {
+ /* For DDR4, this is fixed. */
+ cols = 1 << 10;
+ rows = knl_mc_sizes[i] /
+ ((u64) cols * ranks * banks * 8);
+ } else {
+ rows = numrow(mtr);
+ cols = numcol(mtr);
+ }
size = ((u64)rows * cols * banks * ranks) >> (20 - 3);
npages = MiB_TO_PAGES(size);
@@ -1069,7 +1788,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
/* SAD_LIMIT Address range is 45:26 */
pci_read_config_dword(pvt->pci_sad0, pvt->info.dram_rule[n_sads],
&reg);
- limit = SAD_LIMIT(reg);
+ limit = pvt->info.sad_limit(reg);
if (!DRAM_RULE_ENABLE(reg))
continue;
@@ -1081,10 +1800,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
n_sads,
- get_dram_attr(reg),
+ show_dram_attr(pvt->info.dram_attr(reg)),
gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
- INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
+ pvt->info.show_interleave_mode(reg),
reg);
prv = limit;
@@ -1101,6 +1820,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
}
}
+ if (pvt->info.type == KNIGHTS_LANDING)
+ return;
+
/*
* Step 3) Get TAD range
*/
@@ -1248,7 +1970,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
if (!DRAM_RULE_ENABLE(reg))
continue;
- limit = SAD_LIMIT(reg);
+ limit = pvt->info.sad_limit(reg);
if (limit <= prv) {
sprintf(msg, "Can't discover the memory socket");
return -EINVAL;
@@ -1262,8 +1984,8 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
return -EINVAL;
}
dram_rule = reg;
- *area_type = get_dram_attr(dram_rule);
- interleave_mode = INTERLEAVE_MODE(dram_rule);
+ *area_type = show_dram_attr(pvt->info.dram_attr(dram_rule));
+ interleave_mode = pvt->info.interleave_mode(dram_rule);
pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads],
&reg);
@@ -1567,7 +2289,8 @@ static void sbridge_put_all_devices(void)
static int sbridge_get_onedevice(struct pci_dev **prev,
u8 *num_mc,
const struct pci_id_table *table,
- const unsigned devno)
+ const unsigned devno,
+ const int multi_bus)
{
struct sbridge_dev *sbridge_dev;
const struct pci_id_descr *dev_descr = &table->descr[devno];
@@ -1603,7 +2326,7 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
}
bus = pdev->bus->number;
- sbridge_dev = get_sbridge_dev(bus);
+ sbridge_dev = get_sbridge_dev(bus, multi_bus);
if (!sbridge_dev) {
sbridge_dev = alloc_sbridge_dev(bus, table);
if (!sbridge_dev) {
@@ -1652,21 +2375,32 @@ static int sbridge_get_onedevice(struct pci_dev **prev,
* @num_mc: pointer to the memory controllers count, to be incremented in case
* of success.
* @table: model specific table
+ * @allow_dups: allow for multiple devices to exist with the same device id
+ * (as implemented, this isn't expected to work correctly in the
+ * multi-socket case).
+ * @multi_bus: don't assume devices on different buses belong to different
+ * memory controllers.
*
* returns 0 in case of success or error code
*/
-static int sbridge_get_all_devices(u8 *num_mc,
- const struct pci_id_table *table)
+static int sbridge_get_all_devices_full(u8 *num_mc,
+ const struct pci_id_table *table,
+ int allow_dups,
+ int multi_bus)
{
int i, rc;
struct pci_dev *pdev = NULL;
while (table && table->descr) {
for (i = 0; i < table->n_devs; i++) {
- pdev = NULL;
+ if (!allow_dups || i == 0 ||
+ table->descr[i].dev_id !=
+ table->descr[i-1].dev_id) {
+ pdev = NULL;
+ }
do {
rc = sbridge_get_onedevice(&pdev, num_mc,
- table, i);
+ table, i, multi_bus);
if (rc < 0) {
if (i == 0) {
i = table->n_devs;
@@ -1675,7 +2409,7 @@ static int sbridge_get_all_devices(u8 *num_mc,
sbridge_put_all_devices();
return -ENODEV;
}
- } while (pdev);
+ } while (pdev && !allow_dups);
}
table++;
}
@@ -1683,6 +2417,11 @@ static int sbridge_get_all_devices(u8 *num_mc,
return 0;
}
+#define sbridge_get_all_devices(num_mc, table) \
+ sbridge_get_all_devices_full(num_mc, table, 0, 0)
+#define sbridge_get_all_devices_knl(num_mc, table) \
+ sbridge_get_all_devices_full(num_mc, table, 1, 1)
+
static int sbridge_mci_bind_devs(struct mem_ctl_info *mci,
struct sbridge_dev *sbridge_dev)
{
@@ -2038,6 +2777,131 @@ enodev:
return -ENODEV;
}
+static int knl_mci_bind_devs(struct mem_ctl_info *mci,
+ struct sbridge_dev *sbridge_dev)
+{
+ struct sbridge_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev;
+ int dev, func;
+
+ int i;
+ int devidx;
+
+ for (i = 0; i < sbridge_dev->n_devs; i++) {
+ pdev = sbridge_dev->pdev[i];
+ if (!pdev)
+ continue;
+
+ /* Extract PCI device and function. */
+ dev = (pdev->devfn >> 3) & 0x1f;
+ func = pdev->devfn & 0x7;
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_MC:
+ if (dev == 8)
+ pvt->knl.pci_mc0 = pdev;
+ else if (dev == 9)
+ pvt->knl.pci_mc1 = pdev;
+ else {
+ sbridge_printk(KERN_ERR,
+ "Memory controller in unexpected place! (dev %d, fn %d)\n",
+ dev, func);
+ continue;
+ }
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+ pvt->pci_sad0 = pdev;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD1:
+ pvt->pci_sad1 = pdev;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_CHA:
+ /* There are one of these per tile, and range from
+ * 1.14.0 to 1.18.5.
+ */
+ devidx = ((dev-14)*8)+func;
+
+ if (devidx < 0 || devidx >= KNL_MAX_CHAS) {
+ sbridge_printk(KERN_ERR,
+ "Caching and Home Agent in unexpected place! (dev %d, fn %d)\n",
+ dev, func);
+ continue;
+ }
+
+ WARN_ON(pvt->knl.pci_cha[devidx] != NULL);
+
+ pvt->knl.pci_cha[devidx] = pdev;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_CHANNEL:
+ devidx = -1;
+
+ /*
+ * MC0 channels 0-2 are device 9 function 2-4,
+ * MC1 channels 3-5 are device 8 function 2-4.
+ */
+
+ if (dev == 9)
+ devidx = func-2;
+ else if (dev == 8)
+ devidx = 3 + (func-2);
+
+ if (devidx < 0 || devidx >= KNL_MAX_CHANNELS) {
+ sbridge_printk(KERN_ERR,
+ "DRAM Channel Registers in unexpected place! (dev %d, fn %d)\n",
+ dev, func);
+ continue;
+ }
+
+ WARN_ON(pvt->knl.pci_channel[devidx] != NULL);
+ pvt->knl.pci_channel[devidx] = pdev;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_TOLHM:
+ pvt->knl.pci_mc_info = pdev;
+ break;
+
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_TA:
+ pvt->pci_ta = pdev;
+ break;
+
+ default:
+ sbridge_printk(KERN_ERR, "Unexpected device %d\n",
+ pdev->device);
+ break;
+ }
+ }
+
+ if (!pvt->knl.pci_mc0 || !pvt->knl.pci_mc1 ||
+ !pvt->pci_sad0 || !pvt->pci_sad1 ||
+ !pvt->pci_ta) {
+ goto enodev;
+ }
+
+ for (i = 0; i < KNL_MAX_CHANNELS; i++) {
+ if (!pvt->knl.pci_channel[i]) {
+ sbridge_printk(KERN_ERR, "Missing channel %d\n", i);
+ goto enodev;
+ }
+ }
+
+ for (i = 0; i < KNL_MAX_CHAS; i++) {
+ if (!pvt->knl.pci_cha[i]) {
+ sbridge_printk(KERN_ERR, "Missing CHA %d\n", i);
+ goto enodev;
+ }
+ }
+
+ return 0;
+
+enodev:
+ sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+ return -ENODEV;
+}
+
/****************************************************************************
Error check routines
****************************************************************************/
@@ -2127,8 +2991,36 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
if (!GET_BITFIELD(m->status, 58, 58))
return;
- rc = get_memory_error_data(mci, m->addr, &socket, &ha,
- &channel_mask, &rank, &area_type, msg);
+ if (pvt->info.type == KNIGHTS_LANDING) {
+ if (channel == 14) {
+ edac_dbg(0, "%s%s err_code:%04x:%04x EDRAM bank %d\n",
+ overflow ? " OVERFLOW" : "",
+ (uncorrected_error && recoverable)
+ ? " recoverable" : "",
+ mscod, errcode,
+ m->bank);
+ } else {
+ char A = *("A");
+
+ channel = knl_channel_remap(channel);
+ channel_mask = 1 << channel;
+ snprintf(msg, sizeof(msg),
+ "%s%s err_code:%04x:%04x channel:%d (DIMM_%c)",
+ overflow ? " OVERFLOW" : "",
+ (uncorrected_error && recoverable)
+ ? " recoverable" : " ",
+ mscod, errcode, channel, A + channel);
+ edac_mc_handle_error(tp_event, mci, core_err_cnt,
+ m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
+ channel, 0, -1,
+ optype, msg);
+ }
+ return;
+ } else {
+ rc = get_memory_error_data(mci, m->addr, &socket, &ha,
+ &channel_mask, &rank, &area_type, msg);
+ }
+
if (rc < 0)
goto err_parsing;
new_mci = get_mci_for_node_id(socket);
@@ -2359,10 +3251,11 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
/* allocate a new MC control structure */
layers[0].type = EDAC_MC_LAYER_CHANNEL;
- layers[0].size = NUM_CHANNELS;
+ layers[0].size = type == KNIGHTS_LANDING ?
+ KNL_MAX_CHANNELS : NUM_CHANNELS;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_SLOT;
- layers[1].size = MAX_DIMMS;
+ layers[1].size = type == KNIGHTS_LANDING ? 1 : MAX_DIMMS;
layers[1].is_virt_csrow = true;
mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
sizeof(*pvt));
@@ -2380,7 +3273,8 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->sbridge_dev = sbridge_dev;
sbridge_dev->mci = mci;
- mci->mtype_cap = MEM_FLAG_DDR3;
+ mci->mtype_cap = type == KNIGHTS_LANDING ?
+ MEM_FLAG_DDR4 : MEM_FLAG_DDR3;
mci->edac_ctl_cap = EDAC_FLAG_NONE;
mci->edac_cap = EDAC_FLAG_NONE;
mci->mod_name = "sbridge_edac.c";
@@ -2401,6 +3295,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
pvt->info.rir_limit = rir_limit;
+ pvt->info.sad_limit = sad_limit;
+ pvt->info.interleave_mode = interleave_mode;
+ pvt->info.show_interleave_mode = show_interleave_mode;
+ pvt->info.dram_attr = dram_attr;
pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
pvt->info.interleave_list = ibridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2421,6 +3319,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.get_memory_type = get_memory_type;
pvt->info.get_node_id = get_node_id;
pvt->info.rir_limit = rir_limit;
+ pvt->info.sad_limit = sad_limit;
+ pvt->info.interleave_mode = interleave_mode;
+ pvt->info.show_interleave_mode = show_interleave_mode;
+ pvt->info.dram_attr = dram_attr;
pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule);
pvt->info.interleave_list = sbridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list);
@@ -2441,6 +3343,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.get_memory_type = haswell_get_memory_type;
pvt->info.get_node_id = haswell_get_node_id;
pvt->info.rir_limit = haswell_rir_limit;
+ pvt->info.sad_limit = sad_limit;
+ pvt->info.interleave_mode = interleave_mode;
+ pvt->info.show_interleave_mode = show_interleave_mode;
+ pvt->info.dram_attr = dram_attr;
pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
pvt->info.interleave_list = ibridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2461,6 +3367,10 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
pvt->info.get_memory_type = haswell_get_memory_type;
pvt->info.get_node_id = haswell_get_node_id;
pvt->info.rir_limit = haswell_rir_limit;
+ pvt->info.sad_limit = sad_limit;
+ pvt->info.interleave_mode = interleave_mode;
+ pvt->info.show_interleave_mode = show_interleave_mode;
+ pvt->info.dram_attr = dram_attr;
pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
pvt->info.interleave_list = ibridge_interleave_list;
pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
@@ -2473,6 +3383,30 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
if (unlikely(rc < 0))
goto fail0;
break;
+ case KNIGHTS_LANDING:
+ /* pvt->info.rankcfgr == ??? */
+ pvt->info.get_tolm = knl_get_tolm;
+ pvt->info.get_tohm = knl_get_tohm;
+ pvt->info.dram_rule = knl_dram_rule;
+ pvt->info.get_memory_type = knl_get_memory_type;
+ pvt->info.get_node_id = knl_get_node_id;
+ pvt->info.rir_limit = NULL;
+ pvt->info.sad_limit = knl_sad_limit;
+ pvt->info.interleave_mode = knl_interleave_mode;
+ pvt->info.show_interleave_mode = knl_show_interleave_mode;
+ pvt->info.dram_attr = dram_attr_knl;
+ pvt->info.max_sad = ARRAY_SIZE(knl_dram_rule);
+ pvt->info.interleave_list = knl_interleave_list;
+ pvt->info.max_interleave = ARRAY_SIZE(knl_interleave_list);
+ pvt->info.interleave_pkg = ibridge_interleave_pkg;
+ pvt->info.get_width = knl_get_width;
+ mci->ctl_name = kasprintf(GFP_KERNEL,
+ "Knights Landing Socket#%d", mci->mc_idx);
+
+ rc = knl_mci_bind_devs(mci, sbridge_dev);
+ if (unlikely(rc < 0))
+ goto fail0;
+ break;
}
/* Get dimm basic config and the memory layout */
@@ -2527,20 +3461,29 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
switch (pdev->device) {
case PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA:
- rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
+ rc = sbridge_get_all_devices(&num_mc,
+ pci_dev_descr_ibridge_table);
type = IVY_BRIDGE;
break;
case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
- rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
+ rc = sbridge_get_all_devices(&num_mc,
+ pci_dev_descr_sbridge_table);
type = SANDY_BRIDGE;
break;
case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0:
- rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
+ rc = sbridge_get_all_devices(&num_mc,
+ pci_dev_descr_haswell_table);
type = HASWELL;
break;
case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
- rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table);
+ rc = sbridge_get_all_devices(&num_mc,
+ pci_dev_descr_broadwell_table);
type = BROADWELL;
+ break;
+ case PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0:
+ rc = sbridge_get_all_devices_knl(&num_mc,
+ pci_dev_descr_knl_table);
+ type = KNIGHTS_LANDING;
break;
}
if (unlikely(rc < 0)) {
diff --git a/drivers/edac/wq.c b/drivers/edac/wq.c
new file mode 100644
index 0000000..1b8c07e
--- /dev/null
+++ b/drivers/edac/wq.c
@@ -0,0 +1,42 @@
+#include "edac_module.h"
+
+static struct workqueue_struct *wq;
+
+bool edac_queue_work(struct delayed_work *work, unsigned long delay)
+{
+ return queue_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_queue_work);
+
+bool edac_mod_work(struct delayed_work *work, unsigned long delay)
+{
+ return mod_delayed_work(wq, work, delay);
+}
+EXPORT_SYMBOL_GPL(edac_mod_work);
+
+bool edac_stop_work(struct delayed_work *work)
+{
+ bool ret;
+
+ ret = cancel_delayed_work_sync(work);
+ flush_workqueue(wq);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(edac_stop_work);
+
+int edac_workqueue_setup(void)
+{
+ wq = create_singlethread_workqueue("edac-poller");
+ if (!wq)
+ return -ENODEV;
+ else
+ return 0;
+}
+
+void edac_workqueue_teardown(void)
+{
+ flush_workqueue(wq);
+ destroy_workqueue(wq);
+ wq = NULL;
+}
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index f51d376..c2f5117 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -3675,6 +3675,11 @@ static int pci_probe(struct pci_dev *dev,
reg_write(ohci, OHCI1394_IsoXmitIntMaskSet, ~0);
ohci->it_context_support = reg_read(ohci, OHCI1394_IsoXmitIntMaskSet);
+ /* JMicron JMB38x often shows 0 at first read, just ignore it */
+ if (!ohci->it_context_support) {
+ ohci_notice(ohci, "overriding IsoXmitIntMask\n");
+ ohci->it_context_support = 0xf;
+ }
reg_write(ohci, OHCI1394_IsoXmitIntMaskClear, ~0);
ohci->it_context_mask = ohci->it_context_support;
ohci->n_it = hweight32(ohci->it_context_mask);
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 665efca..49a3a11 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -8,6 +8,25 @@ menu "Firmware Drivers"
config ARM_PSCI_FW
bool
+config ARM_SCPI_PROTOCOL
+ tristate "ARM System Control and Power Interface (SCPI) Message Protocol"
+ depends on ARM_MHU
+ help
+ System Control and Power Interface (SCPI) Message Protocol is
+ defined for the purpose of communication between the Application
+ Cores(AP) and the System Control Processor(SCP). The MHU peripheral
+ provides a mechanism for inter-processor communication between SCP
+ and AP.
+
+ SCP controls most of the power managament on the Application
+ Processors. It offers control and management of: the core/cluster
+ power states, various power domain DVFS including the core/cluster,
+ certain system clocks configuration, thermal sensors and many
+ others.
+
+ This protocol library provides interface for all the client drivers
+ making use of the features offered by the SCP.
+
config EDD
tristate "BIOS Enhanced Disk Drive calls determine boot disk"
depends on X86
@@ -135,6 +154,13 @@ config ISCSI_IBFT
detect iSCSI boot parameters dynamically during system boot, say Y.
Otherwise, say N.
+config RASPBERRYPI_FIRMWARE
+ tristate "Raspberry Pi Firmware Driver"
+ depends on BCM2835_MBOX
+ help
+ This option enables support for communicating with the firmware on the
+ Raspberry Pi.
+
config QCOM_SCM
bool
depends on ARM || ARM64
@@ -147,6 +173,9 @@ config QCOM_SCM_64
def_bool y
depends on QCOM_SCM && ARM64
+config HAVE_ARM_SMCCC
+ bool
+
source "drivers/firmware/broadcom/Kconfig"
source "drivers/firmware/google/Kconfig"
source "drivers/firmware/efi/Kconfig"
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index 2ee8347..48dd417 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -2,6 +2,7 @@
# Makefile for the linux kernel.
#
obj-$(CONFIG_ARM_PSCI_FW) += psci.o
+obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o
obj-$(CONFIG_DMI) += dmi_scan.o
obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o
obj-$(CONFIG_EDD) += edd.o
@@ -12,10 +13,11 @@ obj-$(CONFIG_DMIID) += dmi-id.o
obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o
obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o
obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o
+obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o
obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
-CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-y += broadcom/
obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c
new file mode 100644
index 0000000..6174db8
--- /dev/null
+++ b/drivers/firmware/arm_scpi.c
@@ -0,0 +1,771 @@
+/*
+ * System Control and Power Interface (SCPI) Message Protocol driver
+ *
+ * SCPI Message Protocol is used between the System Control Processor(SCP)
+ * and the Application Processors(AP). The Message Handling Unit(MHU)
+ * provides a mechanism for inter-processor communication between SCP's
+ * Cortex M3 and AP.
+ *
+ * SCP offers control and management of the core/cluster power states,
+ * various power domain DVFS including the core/cluster, certain system
+ * clocks configuration, thermal sensors and many others.
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/bitmap.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/printk.h>
+#include <linux/scpi_protocol.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/spinlock.h>
+
+#define CMD_ID_SHIFT 0
+#define CMD_ID_MASK 0x7f
+#define CMD_TOKEN_ID_SHIFT 8
+#define CMD_TOKEN_ID_MASK 0xff
+#define CMD_DATA_SIZE_SHIFT 16
+#define CMD_DATA_SIZE_MASK 0x1ff
+#define PACK_SCPI_CMD(cmd_id, tx_sz) \
+ ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \
+ (((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
+#define ADD_SCPI_TOKEN(cmd, token) \
+ ((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT))
+
+#define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK)
+#define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK)
+#define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK)
+
+#define SCPI_SLOT 0
+
+#define MAX_DVFS_DOMAINS 8
+#define MAX_DVFS_OPPS 8
+#define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16)
+#define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff)
+
+#define PROTOCOL_REV_MINOR_BITS 16
+#define PROTOCOL_REV_MINOR_MASK ((1U << PROTOCOL_REV_MINOR_BITS) - 1)
+#define PROTOCOL_REV_MAJOR(x) ((x) >> PROTOCOL_REV_MINOR_BITS)
+#define PROTOCOL_REV_MINOR(x) ((x) & PROTOCOL_REV_MINOR_MASK)
+
+#define FW_REV_MAJOR_BITS 24
+#define FW_REV_MINOR_BITS 16
+#define FW_REV_PATCH_MASK ((1U << FW_REV_MINOR_BITS) - 1)
+#define FW_REV_MINOR_MASK ((1U << FW_REV_MAJOR_BITS) - 1)
+#define FW_REV_MAJOR(x) ((x) >> FW_REV_MAJOR_BITS)
+#define FW_REV_MINOR(x) (((x) & FW_REV_MINOR_MASK) >> FW_REV_MINOR_BITS)
+#define FW_REV_PATCH(x) ((x) & FW_REV_PATCH_MASK)
+
+#define MAX_RX_TIMEOUT (msecs_to_jiffies(20))
+
+enum scpi_error_codes {
+ SCPI_SUCCESS = 0, /* Success */
+ SCPI_ERR_PARAM = 1, /* Invalid parameter(s) */
+ SCPI_ERR_ALIGN = 2, /* Invalid alignment */
+ SCPI_ERR_SIZE = 3, /* Invalid size */
+ SCPI_ERR_HANDLER = 4, /* Invalid handler/callback */
+ SCPI_ERR_ACCESS = 5, /* Invalid access/permission denied */
+ SCPI_ERR_RANGE = 6, /* Value out of range */
+ SCPI_ERR_TIMEOUT = 7, /* Timeout has occurred */
+ SCPI_ERR_NOMEM = 8, /* Invalid memory area or pointer */
+ SCPI_ERR_PWRSTATE = 9, /* Invalid power state */
+ SCPI_ERR_SUPPORT = 10, /* Not supported or disabled */
+ SCPI_ERR_DEVICE = 11, /* Device error */
+ SCPI_ERR_BUSY = 12, /* Device busy */
+ SCPI_ERR_MAX
+};
+
+enum scpi_std_cmd {
+ SCPI_CMD_INVALID = 0x00,
+ SCPI_CMD_SCPI_READY = 0x01,
+ SCPI_CMD_SCPI_CAPABILITIES = 0x02,
+ SCPI_CMD_SET_CSS_PWR_STATE = 0x03,
+ SCPI_CMD_GET_CSS_PWR_STATE = 0x04,
+ SCPI_CMD_SET_SYS_PWR_STATE = 0x05,
+ SCPI_CMD_SET_CPU_TIMER = 0x06,
+ SCPI_CMD_CANCEL_CPU_TIMER = 0x07,
+ SCPI_CMD_DVFS_CAPABILITIES = 0x08,
+ SCPI_CMD_GET_DVFS_INFO = 0x09,
+ SCPI_CMD_SET_DVFS = 0x0a,
+ SCPI_CMD_GET_DVFS = 0x0b,
+ SCPI_CMD_GET_DVFS_STAT = 0x0c,
+ SCPI_CMD_CLOCK_CAPABILITIES = 0x0d,
+ SCPI_CMD_GET_CLOCK_INFO = 0x0e,
+ SCPI_CMD_SET_CLOCK_VALUE = 0x0f,
+ SCPI_CMD_GET_CLOCK_VALUE = 0x10,
+ SCPI_CMD_PSU_CAPABILITIES = 0x11,
+ SCPI_CMD_GET_PSU_INFO = 0x12,
+ SCPI_CMD_SET_PSU = 0x13,
+ SCPI_CMD_GET_PSU = 0x14,
+ SCPI_CMD_SENSOR_CAPABILITIES = 0x15,
+ SCPI_CMD_SENSOR_INFO = 0x16,
+ SCPI_CMD_SENSOR_VALUE = 0x17,
+ SCPI_CMD_SENSOR_CFG_PERIODIC = 0x18,
+ SCPI_CMD_SENSOR_CFG_BOUNDS = 0x19,
+ SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1a,
+ SCPI_CMD_SET_DEVICE_PWR_STATE = 0x1b,
+ SCPI_CMD_GET_DEVICE_PWR_STATE = 0x1c,
+ SCPI_CMD_COUNT
+};
+
+struct scpi_xfer {
+ u32 slot; /* has to be first element */
+ u32 cmd;
+ u32 status;
+ const void *tx_buf;
+ void *rx_buf;
+ unsigned int tx_len;
+ unsigned int rx_len;
+ struct list_head node;
+ struct completion done;
+};
+
+struct scpi_chan {
+ struct mbox_client cl;
+ struct mbox_chan *chan;
+ void __iomem *tx_payload;
+ void __iomem *rx_payload;
+ struct list_head rx_pending;
+ struct list_head xfers_list;
+ struct scpi_xfer *xfers;
+ spinlock_t rx_lock; /* locking for the rx pending list */
+ struct mutex xfers_lock;
+ u8 token;
+};
+
+struct scpi_drvinfo {
+ u32 protocol_version;
+ u32 firmware_version;
+ int num_chans;
+ atomic_t next_chan;
+ struct scpi_ops *scpi_ops;
+ struct scpi_chan *channels;
+ struct scpi_dvfs_info *dvfs[MAX_DVFS_DOMAINS];
+};
+
+/*
+ * The SCP firmware only executes in little-endian mode, so any buffers
+ * shared through SCPI should have their contents converted to little-endian
+ */
+struct scpi_shared_mem {
+ __le32 command;
+ __le32 status;
+ u8 payload[0];
+} __packed;
+
+struct scp_capabilities {
+ __le32 protocol_version;
+ __le32 event_version;
+ __le32 platform_version;
+ __le32 commands[4];
+} __packed;
+
+struct clk_get_info {
+ __le16 id;
+ __le16 flags;
+ __le32 min_rate;
+ __le32 max_rate;
+ u8 name[20];
+} __packed;
+
+struct clk_get_value {
+ __le32 rate;
+} __packed;
+
+struct clk_set_value {
+ __le16 id;
+ __le16 reserved;
+ __le32 rate;
+} __packed;
+
+struct dvfs_info {
+ __le32 header;
+ struct {
+ __le32 freq;
+ __le32 m_volt;
+ } opps[MAX_DVFS_OPPS];
+} __packed;
+
+struct dvfs_get {
+ u8 index;
+} __packed;
+
+struct dvfs_set {
+ u8 domain;
+ u8 index;
+} __packed;
+
+struct sensor_capabilities {
+ __le16 sensors;
+} __packed;
+
+struct _scpi_sensor_info {
+ __le16 sensor_id;
+ u8 class;
+ u8 trigger_type;
+ char name[20];
+};
+
+struct sensor_value {
+ __le32 val;
+} __packed;
+
+static struct scpi_drvinfo *scpi_info;
+
+static int scpi_linux_errmap[SCPI_ERR_MAX] = {
+ /* better than switch case as long as return value is continuous */
+ 0, /* SCPI_SUCCESS */
+ -EINVAL, /* SCPI_ERR_PARAM */
+ -ENOEXEC, /* SCPI_ERR_ALIGN */
+ -EMSGSIZE, /* SCPI_ERR_SIZE */
+ -EINVAL, /* SCPI_ERR_HANDLER */
+ -EACCES, /* SCPI_ERR_ACCESS */
+ -ERANGE, /* SCPI_ERR_RANGE */
+ -ETIMEDOUT, /* SCPI_ERR_TIMEOUT */
+ -ENOMEM, /* SCPI_ERR_NOMEM */
+ -EINVAL, /* SCPI_ERR_PWRSTATE */
+ -EOPNOTSUPP, /* SCPI_ERR_SUPPORT */
+ -EIO, /* SCPI_ERR_DEVICE */
+ -EBUSY, /* SCPI_ERR_BUSY */
+};
+
+static inline int scpi_to_linux_errno(int errno)
+{
+ if (errno >= SCPI_SUCCESS && errno < SCPI_ERR_MAX)
+ return scpi_linux_errmap[errno];
+ return -EIO;
+}
+
+static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd)
+{
+ unsigned long flags;
+ struct scpi_xfer *t, *match = NULL;
+
+ spin_lock_irqsave(&ch->rx_lock, flags);
+ if (list_empty(&ch->rx_pending)) {
+ spin_unlock_irqrestore(&ch->rx_lock, flags);
+ return;
+ }
+
+ list_for_each_entry(t, &ch->rx_pending, node)
+ if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) {
+ list_del(&t->node);
+ match = t;
+ break;
+ }
+ /* check if wait_for_completion is in progress or timed-out */
+ if (match && !completion_done(&match->done)) {
+ struct scpi_shared_mem *mem = ch->rx_payload;
+ unsigned int len = min(match->rx_len, CMD_SIZE(cmd));
+
+ match->status = le32_to_cpu(mem->status);
+ memcpy_fromio(match->rx_buf, mem->payload, len);
+ if (match->rx_len > len)
+ memset(match->rx_buf + len, 0, match->rx_len - len);
+ complete(&match->done);
+ }
+ spin_unlock_irqrestore(&ch->rx_lock, flags);
+}
+
+static void scpi_handle_remote_msg(struct mbox_client *c, void *msg)
+{
+ struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
+ struct scpi_shared_mem *mem = ch->rx_payload;
+ u32 cmd = le32_to_cpu(mem->command);
+
+ scpi_process_cmd(ch, cmd);
+}
+
+static void scpi_tx_prepare(struct mbox_client *c, void *msg)
+{
+ unsigned long flags;
+ struct scpi_xfer *t = msg;
+ struct scpi_chan *ch = container_of(c, struct scpi_chan, cl);
+ struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload;
+
+ if (t->tx_buf)
+ memcpy_toio(mem->payload, t->tx_buf, t->tx_len);
+ if (t->rx_buf) {
+ if (!(++ch->token))
+ ++ch->token;
+ ADD_SCPI_TOKEN(t->cmd, ch->token);
+ spin_lock_irqsave(&ch->rx_lock, flags);
+ list_add_tail(&t->node, &ch->rx_pending);
+ spin_unlock_irqrestore(&ch->rx_lock, flags);
+ }
+ mem->command = cpu_to_le32(t->cmd);
+}
+
+static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch)
+{
+ struct scpi_xfer *t;
+
+ mutex_lock(&ch->xfers_lock);
+ if (list_empty(&ch->xfers_list)) {
+ mutex_unlock(&ch->xfers_lock);
+ return NULL;
+ }
+ t = list_first_entry(&ch->xfers_list, struct scpi_xfer, node);
+ list_del(&t->node);
+ mutex_unlock(&ch->xfers_lock);
+ return t;
+}
+
+static void put_scpi_xfer(struct scpi_xfer *t, struct scpi_chan *ch)
+{
+ mutex_lock(&ch->xfers_lock);
+ list_add_tail(&t->node, &ch->xfers_list);
+ mutex_unlock(&ch->xfers_lock);
+}
+
+static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len,
+ void *rx_buf, unsigned int rx_len)
+{
+ int ret;
+ u8 chan;
+ struct scpi_xfer *msg;
+ struct scpi_chan *scpi_chan;
+
+ chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans;
+ scpi_chan = scpi_info->channels + chan;
+
+ msg = get_scpi_xfer(scpi_chan);
+ if (!msg)
+ return -ENOMEM;
+
+ msg->slot = BIT(SCPI_SLOT);
+ msg->cmd = PACK_SCPI_CMD(cmd, tx_len);
+ msg->tx_buf = tx_buf;
+ msg->tx_len = tx_len;
+ msg->rx_buf = rx_buf;
+ msg->rx_len = rx_len;
+ init_completion(&msg->done);
+
+ ret = mbox_send_message(scpi_chan->chan, msg);
+ if (ret < 0 || !rx_buf)
+ goto out;
+
+ if (!wait_for_completion_timeout(&msg->done, MAX_RX_TIMEOUT))
+ ret = -ETIMEDOUT;
+ else
+ /* first status word */
+ ret = le32_to_cpu(msg->status);
+out:
+ if (ret < 0 && rx_buf) /* remove entry from the list if timed-out */
+ scpi_process_cmd(scpi_chan, msg->cmd);
+
+ put_scpi_xfer(msg, scpi_chan);
+ /* SCPI error codes > 0, translate them to Linux scale*/
+ return ret > 0 ? scpi_to_linux_errno(ret) : ret;
+}
+
+static u32 scpi_get_version(void)
+{
+ return scpi_info->protocol_version;
+}
+
+static int
+scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max)
+{
+ int ret;
+ struct clk_get_info clk;
+ __le16 le_clk_id = cpu_to_le16(clk_id);
+
+ ret = scpi_send_message(SCPI_CMD_GET_CLOCK_INFO, &le_clk_id,
+ sizeof(le_clk_id), &clk, sizeof(clk));
+ if (!ret) {
+ *min = le32_to_cpu(clk.min_rate);
+ *max = le32_to_cpu(clk.max_rate);
+ }
+ return ret;
+}
+
+static unsigned long scpi_clk_get_val(u16 clk_id)
+{
+ int ret;
+ struct clk_get_value clk;
+ __le16 le_clk_id = cpu_to_le16(clk_id);
+
+ ret = scpi_send_message(SCPI_CMD_GET_CLOCK_VALUE, &le_clk_id,
+ sizeof(le_clk_id), &clk, sizeof(clk));
+ return ret ? ret : le32_to_cpu(clk.rate);
+}
+
+static int scpi_clk_set_val(u16 clk_id, unsigned long rate)
+{
+ int stat;
+ struct clk_set_value clk = {
+ .id = cpu_to_le16(clk_id),
+ .rate = cpu_to_le32(rate)
+ };
+
+ return scpi_send_message(SCPI_CMD_SET_CLOCK_VALUE, &clk, sizeof(clk),
+ &stat, sizeof(stat));
+}
+
+static int scpi_dvfs_get_idx(u8 domain)
+{
+ int ret;
+ struct dvfs_get dvfs;
+
+ ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain),
+ &dvfs, sizeof(dvfs));
+ return ret ? ret : dvfs.index;
+}
+
+static int scpi_dvfs_set_idx(u8 domain, u8 index)
+{
+ int stat;
+ struct dvfs_set dvfs = {domain, index};
+
+ return scpi_send_message(SCPI_CMD_SET_DVFS, &dvfs, sizeof(dvfs),
+ &stat, sizeof(stat));
+}
+
+static int opp_cmp_func(const void *opp1, const void *opp2)
+{
+ const struct scpi_opp *t1 = opp1, *t2 = opp2;
+
+ return t1->freq - t2->freq;
+}
+
+static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain)
+{
+ struct scpi_dvfs_info *info;
+ struct scpi_opp *opp;
+ struct dvfs_info buf;
+ int ret, i;
+
+ if (domain >= MAX_DVFS_DOMAINS)
+ return ERR_PTR(-EINVAL);
+
+ if (scpi_info->dvfs[domain]) /* data already populated */
+ return scpi_info->dvfs[domain];
+
+ ret = scpi_send_message(SCPI_CMD_GET_DVFS_INFO, &domain, sizeof(domain),
+ &buf, sizeof(buf));
+
+ if (ret)
+ return ERR_PTR(ret);
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ info->count = DVFS_OPP_COUNT(buf.header);
+ info->latency = DVFS_LATENCY(buf.header) * 1000; /* uS to nS */
+
+ info->opps = kcalloc(info->count, sizeof(*opp), GFP_KERNEL);
+ if (!info->opps) {
+ kfree(info);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (i = 0, opp = info->opps; i < info->count; i++, opp++) {
+ opp->freq = le32_to_cpu(buf.opps[i].freq);
+ opp->m_volt = le32_to_cpu(buf.opps[i].m_volt);
+ }
+
+ sort(info->opps, info->count, sizeof(*opp), opp_cmp_func, NULL);
+
+ scpi_info->dvfs[domain] = info;
+ return info;
+}
+
+static int scpi_sensor_get_capability(u16 *sensors)
+{
+ struct sensor_capabilities cap_buf;
+ int ret;
+
+ ret = scpi_send_message(SCPI_CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf,
+ sizeof(cap_buf));
+ if (!ret)
+ *sensors = le16_to_cpu(cap_buf.sensors);
+
+ return ret;
+}
+
+static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info)
+{
+ __le16 id = cpu_to_le16(sensor_id);
+ struct _scpi_sensor_info _info;
+ int ret;
+
+ ret = scpi_send_message(SCPI_CMD_SENSOR_INFO, &id, sizeof(id),
+ &_info, sizeof(_info));
+ if (!ret) {
+ memcpy(info, &_info, sizeof(*info));
+ info->sensor_id = le16_to_cpu(_info.sensor_id);
+ }
+
+ return ret;
+}
+
+int scpi_sensor_get_value(u16 sensor, u32 *val)
+{
+ struct sensor_value buf;
+ int ret;
+
+ ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &sensor, sizeof(sensor),
+ &buf, sizeof(buf));
+ if (!ret)
+ *val = le32_to_cpu(buf.val);
+
+ return ret;
+}
+
+static struct scpi_ops scpi_ops = {
+ .get_version = scpi_get_version,
+ .clk_get_range = scpi_clk_get_range,
+ .clk_get_val = scpi_clk_get_val,
+ .clk_set_val = scpi_clk_set_val,
+ .dvfs_get_idx = scpi_dvfs_get_idx,
+ .dvfs_set_idx = scpi_dvfs_set_idx,
+ .dvfs_get_info = scpi_dvfs_get_info,
+ .sensor_get_capability = scpi_sensor_get_capability,
+ .sensor_get_info = scpi_sensor_get_info,
+ .sensor_get_value = scpi_sensor_get_value,
+};
+
+struct scpi_ops *get_scpi_ops(void)
+{
+ return scpi_info ? scpi_info->scpi_ops : NULL;
+}
+EXPORT_SYMBOL_GPL(get_scpi_ops);
+
+static int scpi_init_versions(struct scpi_drvinfo *info)
+{
+ int ret;
+ struct scp_capabilities caps;
+
+ ret = scpi_send_message(SCPI_CMD_SCPI_CAPABILITIES, NULL, 0,
+ &caps, sizeof(caps));
+ if (!ret) {
+ info->protocol_version = le32_to_cpu(caps.protocol_version);
+ info->firmware_version = le32_to_cpu(caps.platform_version);
+ }
+ return ret;
+}
+
+static ssize_t protocol_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d.%d\n",
+ PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
+ PROTOCOL_REV_MINOR(scpi_info->protocol_version));
+}
+static DEVICE_ATTR_RO(protocol_version);
+
+static ssize_t firmware_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct scpi_drvinfo *scpi_info = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d.%d.%d\n",
+ FW_REV_MAJOR(scpi_info->firmware_version),
+ FW_REV_MINOR(scpi_info->firmware_version),
+ FW_REV_PATCH(scpi_info->firmware_version));
+}
+static DEVICE_ATTR_RO(firmware_version);
+
+static struct attribute *versions_attrs[] = {
+ &dev_attr_firmware_version.attr,
+ &dev_attr_protocol_version.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(versions);
+
+static void
+scpi_free_channels(struct device *dev, struct scpi_chan *pchan, int count)
+{
+ int i;
+
+ for (i = 0; i < count && pchan->chan; i++, pchan++) {
+ mbox_free_channel(pchan->chan);
+ devm_kfree(dev, pchan->xfers);
+ devm_iounmap(dev, pchan->rx_payload);
+ }
+}
+
+static int scpi_remove(struct platform_device *pdev)
+{
+ int i;
+ struct device *dev = &pdev->dev;
+ struct scpi_drvinfo *info = platform_get_drvdata(pdev);
+
+ scpi_info = NULL; /* stop exporting SCPI ops through get_scpi_ops */
+
+ of_platform_depopulate(dev);
+ sysfs_remove_groups(&dev->kobj, versions_groups);
+ scpi_free_channels(dev, info->channels, info->num_chans);
+ platform_set_drvdata(pdev, NULL);
+
+ for (i = 0; i < MAX_DVFS_DOMAINS && info->dvfs[i]; i++) {
+ kfree(info->dvfs[i]->opps);
+ kfree(info->dvfs[i]);
+ }
+ devm_kfree(dev, info->channels);
+ devm_kfree(dev, info);
+
+ return 0;
+}
+
+#define MAX_SCPI_XFERS 10
+static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch)
+{
+ int i;
+ struct scpi_xfer *xfers;
+
+ xfers = devm_kzalloc(dev, MAX_SCPI_XFERS * sizeof(*xfers), GFP_KERNEL);
+ if (!xfers)
+ return -ENOMEM;
+
+ ch->xfers = xfers;
+ for (i = 0; i < MAX_SCPI_XFERS; i++, xfers++)
+ list_add_tail(&xfers->node, &ch->xfers_list);
+ return 0;
+}
+
+static int scpi_probe(struct platform_device *pdev)
+{
+ int count, idx, ret;
+ struct resource res;
+ struct scpi_chan *scpi_chan;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ scpi_info = devm_kzalloc(dev, sizeof(*scpi_info), GFP_KERNEL);
+ if (!scpi_info)
+ return -ENOMEM;
+
+ count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells");
+ if (count < 0) {
+ dev_err(dev, "no mboxes property in '%s'\n", np->full_name);
+ return -ENODEV;
+ }
+
+ scpi_chan = devm_kcalloc(dev, count, sizeof(*scpi_chan), GFP_KERNEL);
+ if (!scpi_chan)
+ return -ENOMEM;
+
+ for (idx = 0; idx < count; idx++) {
+ resource_size_t size;
+ struct scpi_chan *pchan = scpi_chan + idx;
+ struct mbox_client *cl = &pchan->cl;
+ struct device_node *shmem = of_parse_phandle(np, "shmem", idx);
+
+ if (of_address_to_resource(shmem, 0, &res)) {
+ dev_err(dev, "failed to get SCPI payload mem resource\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ size = resource_size(&res);
+ pchan->rx_payload = devm_ioremap(dev, res.start, size);
+ if (!pchan->rx_payload) {
+ dev_err(dev, "failed to ioremap SCPI payload\n");
+ ret = -EADDRNOTAVAIL;
+ goto err;
+ }
+ pchan->tx_payload = pchan->rx_payload + (size >> 1);
+
+ cl->dev = dev;
+ cl->rx_callback = scpi_handle_remote_msg;
+ cl->tx_prepare = scpi_tx_prepare;
+ cl->tx_block = true;
+ cl->tx_tout = 50;
+ cl->knows_txdone = false; /* controller can't ack */
+
+ INIT_LIST_HEAD(&pchan->rx_pending);
+ INIT_LIST_HEAD(&pchan->xfers_list);
+ spin_lock_init(&pchan->rx_lock);
+ mutex_init(&pchan->xfers_lock);
+
+ ret = scpi_alloc_xfer_list(dev, pchan);
+ if (!ret) {
+ pchan->chan = mbox_request_channel(cl, idx);
+ if (!IS_ERR(pchan->chan))
+ continue;
+ ret = PTR_ERR(pchan->chan);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to get channel%d err %d\n",
+ idx, ret);
+ }
+err:
+ scpi_free_channels(dev, scpi_chan, idx);
+ scpi_info = NULL;
+ return ret;
+ }
+
+ scpi_info->channels = scpi_chan;
+ scpi_info->num_chans = count;
+ platform_set_drvdata(pdev, scpi_info);
+
+ ret = scpi_init_versions(scpi_info);
+ if (ret) {
+ dev_err(dev, "incorrect or no SCP firmware found\n");
+ scpi_remove(pdev);
+ return ret;
+ }
+
+ _dev_info(dev, "SCP Protocol %d.%d Firmware %d.%d.%d version\n",
+ PROTOCOL_REV_MAJOR(scpi_info->protocol_version),
+ PROTOCOL_REV_MINOR(scpi_info->protocol_version),
+ FW_REV_MAJOR(scpi_info->firmware_version),
+ FW_REV_MINOR(scpi_info->firmware_version),
+ FW_REV_PATCH(scpi_info->firmware_version));
+ scpi_info->scpi_ops = &scpi_ops;
+
+ ret = sysfs_create_groups(&dev->kobj, versions_groups);
+ if (ret)
+ dev_err(dev, "unable to create sysfs version group\n");
+
+ return of_platform_populate(dev->of_node, NULL, NULL, dev);
+}
+
+static const struct of_device_id scpi_of_match[] = {
+ {.compatible = "arm,scpi"},
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, scpi_of_match);
+
+static struct platform_driver scpi_driver = {
+ .driver = {
+ .name = "scpi_protocol",
+ .of_match_table = scpi_of_match,
+ },
+ .probe = scpi_probe,
+ .remove = scpi_remove,
+};
+module_platform_driver(scpi_driver);
+
+MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI mailbox protocol driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index ac1ce4a..0e08e66 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -521,6 +521,7 @@ static int __init dmi_present(const u8 *buf)
dmi_ver = smbios_ver;
else
dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F);
+ dmi_ver <<= 8;
dmi_num = get_unaligned_le16(buf + 12);
dmi_len = get_unaligned_le16(buf + 6);
dmi_base = get_unaligned_le32(buf + 8);
@@ -528,15 +529,14 @@ static int __init dmi_present(const u8 *buf)
if (dmi_walk_early(dmi_decode) == 0) {
if (smbios_ver) {
pr_info("SMBIOS %d.%d present.\n",
- dmi_ver >> 8, dmi_ver & 0xFF);
+ dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
} else {
smbios_entry_point_size = 15;
memcpy(smbios_entry_point, buf,
smbios_entry_point_size);
pr_info("Legacy DMI %d.%d present.\n",
- dmi_ver >> 8, dmi_ver & 0xFF);
+ dmi_ver >> 16, (dmi_ver >> 8) & 0xFF);
}
- dmi_ver <<= 8;
dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string);
return 0;
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index ec379a4..62e654f 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -18,3 +18,7 @@ obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
obj-$(CONFIG_EFI_STUB) += libstub/
obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o
+
+arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o
+obj-$(CONFIG_ARM) += $(arm-obj-y)
+obj-$(CONFIG_ARM64) += $(arm-obj-y)
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
new file mode 100644
index 0000000..9e15d57
--- /dev/null
+++ b/drivers/firmware/efi/arm-init.c
@@ -0,0 +1,209 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013 - 2015 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/init.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+
+#include <asm/efi.h>
+
+struct efi_memory_map memmap;
+
+u64 efi_system_table;
+
+static int __init is_normal_ram(efi_memory_desc_t *md)
+{
+ if (md->attribute & EFI_MEMORY_WB)
+ return 1;
+ return 0;
+}
+
+/*
+ * Translate a EFI virtual address into a physical address: this is necessary,
+ * as some data members of the EFI system table are virtually remapped after
+ * SetVirtualAddressMap() has been called.
+ */
+static phys_addr_t efi_to_phys(unsigned long addr)
+{
+ efi_memory_desc_t *md;
+
+ for_each_efi_memory_desc(&memmap, md) {
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+ if (md->virt_addr == 0)
+ /* no virtual mapping has been installed by the stub */
+ break;
+ if (md->virt_addr <= addr &&
+ (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT))
+ return md->phys_addr + addr - md->virt_addr;
+ }
+ return addr;
+}
+
+static int __init uefi_init(void)
+{
+ efi_char16_t *c16;
+ void *config_tables;
+ size_t table_size;
+ char vendor[100] = "unknown";
+ int i, retval;
+
+ efi.systab = early_memremap(efi_system_table,
+ sizeof(efi_system_table_t));
+ if (efi.systab == NULL) {
+ pr_warn("Unable to map EFI system table.\n");
+ return -ENOMEM;
+ }
+
+ set_bit(EFI_BOOT, &efi.flags);
+ if (IS_ENABLED(CONFIG_64BIT))
+ set_bit(EFI_64BIT, &efi.flags);
+
+ /*
+ * Verify the EFI Table
+ */
+ if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) {
+ pr_err("System table signature incorrect\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if ((efi.systab->hdr.revision >> 16) < 2)
+ pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff);
+
+ /* Show what we know for posterity */
+ c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor),
+ sizeof(vendor) * sizeof(efi_char16_t));
+ if (c16) {
+ for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i)
+ vendor[i] = c16[i];
+ vendor[i] = '\0';
+ early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t));
+ }
+
+ pr_info("EFI v%u.%.02u by %s\n",
+ efi.systab->hdr.revision >> 16,
+ efi.systab->hdr.revision & 0xffff, vendor);
+
+ table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables;
+ config_tables = early_memremap(efi_to_phys(efi.systab->tables),
+ table_size);
+ if (config_tables == NULL) {
+ pr_warn("Unable to map EFI config table array.\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables,
+ sizeof(efi_config_table_t), NULL);
+
+ early_memunmap(config_tables, table_size);
+out:
+ early_memunmap(efi.systab, sizeof(efi_system_table_t));
+ return retval;
+}
+
+/*
+ * Return true for RAM regions we want to permanently reserve.
+ */
+static __init int is_reserve_region(efi_memory_desc_t *md)
+{
+ switch (md->type) {
+ case EFI_LOADER_CODE:
+ case EFI_LOADER_DATA:
+ case EFI_BOOT_SERVICES_CODE:
+ case EFI_BOOT_SERVICES_DATA:
+ case EFI_CONVENTIONAL_MEMORY:
+ case EFI_PERSISTENT_MEMORY:
+ return 0;
+ default:
+ break;
+ }
+ return is_normal_ram(md);
+}
+
+static __init void reserve_regions(void)
+{
+ efi_memory_desc_t *md;
+ u64 paddr, npages, size;
+
+ if (efi_enabled(EFI_DBG))
+ pr_info("Processing EFI memory map:\n");
+
+ for_each_efi_memory_desc(&memmap, md) {
+ paddr = md->phys_addr;
+ npages = md->num_pages;
+
+ if (efi_enabled(EFI_DBG)) {
+ char buf[64];
+
+ pr_info(" 0x%012llx-0x%012llx %s",
+ paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1,
+ efi_md_typeattr_format(buf, sizeof(buf), md));
+ }
+
+ memrange_efi_to_native(&paddr, &npages);
+ size = npages << PAGE_SHIFT;
+
+ if (is_normal_ram(md))
+ early_init_dt_add_memory_arch(paddr, size);
+
+ if (is_reserve_region(md)) {
+ memblock_mark_nomap(paddr, size);
+ if (efi_enabled(EFI_DBG))
+ pr_cont("*");
+ }
+
+ if (efi_enabled(EFI_DBG))
+ pr_cont("\n");
+ }
+
+ set_bit(EFI_MEMMAP, &efi.flags);
+}
+
+void __init efi_init(void)
+{
+ struct efi_fdt_params params;
+
+ /* Grab UEFI information placed in FDT by stub */
+ if (!efi_get_fdt_params(&params))
+ return;
+
+ efi_system_table = params.system_table;
+
+ memmap.phys_map = params.mmap;
+ memmap.map = early_memremap(params.mmap, params.mmap_size);
+ if (memmap.map == NULL) {
+ /*
+ * If we are booting via UEFI, the UEFI memory map is the only
+ * description of memory we have, so there is little point in
+ * proceeding if we cannot access it.
+ */
+ panic("Unable to map EFI memory map.\n");
+ }
+ memmap.map_end = memmap.map + params.mmap_size;
+ memmap.desc_size = params.desc_size;
+ memmap.desc_version = params.desc_ver;
+
+ if (uefi_init() < 0)
+ return;
+
+ reserve_regions();
+ early_memunmap(memmap.map, params.mmap_size);
+ memblock_mark_nomap(params.mmap & PAGE_MASK,
+ PAGE_ALIGN(params.mmap_size +
+ (params.mmap & ~PAGE_MASK)));
+}
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c
new file mode 100644
index 0000000..6ae21e4
--- /dev/null
+++ b/drivers/firmware/efi/arm-runtime.c
@@ -0,0 +1,135 @@
+/*
+ * Extensible Firmware Interface
+ *
+ * Based on Extensible Firmware Interface Specification version 2.4
+ *
+ * Copyright (C) 2013, 2014 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/efi.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/mm_types.h>
+#include <linux/preempt.h>
+#include <linux/rbtree.h>
+#include <linux/rwsem.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include <asm/cacheflush.h>
+#include <asm/efi.h>
+#include <asm/mmu.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+extern u64 efi_system_table;
+
+static struct mm_struct efi_mm = {
+ .mm_rb = RB_ROOT,
+ .mm_users = ATOMIC_INIT(2),
+ .mm_count = ATOMIC_INIT(1),
+ .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem),
+ .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock),
+ .mmlist = LIST_HEAD_INIT(efi_mm.mmlist),
+};
+
+static bool __init efi_virtmap_init(void)
+{
+ efi_memory_desc_t *md;
+
+ efi_mm.pgd = pgd_alloc(&efi_mm);
+ init_new_context(NULL, &efi_mm);
+
+ for_each_efi_memory_desc(&memmap, md) {
+ phys_addr_t phys = md->phys_addr;
+ int ret;
+
+ if (!(md->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+ if (md->virt_addr == 0)
+ return false;
+
+ ret = efi_create_mapping(&efi_mm, md);
+ if (!ret) {
+ pr_info(" EFI remap %pa => %p\n",
+ &phys, (void *)(unsigned long)md->virt_addr);
+ } else {
+ pr_warn(" EFI remap %pa: failed to create mapping (%d)\n",
+ &phys, ret);
+ return false;
+ }
+ }
+ return true;
+}
+
+/*
+ * Enable the UEFI Runtime Services if all prerequisites are in place, i.e.,
+ * non-early mapping of the UEFI system table and virtual mappings for all
+ * EFI_MEMORY_RUNTIME regions.
+ */
+static int __init arm_enable_runtime_services(void)
+{
+ u64 mapsize;
+
+ if (!efi_enabled(EFI_BOOT)) {
+ pr_info("EFI services will not be available.\n");
+ return 0;
+ }
+
+ if (efi_runtime_disabled()) {
+ pr_info("EFI runtime services will be disabled.\n");
+ return 0;
+ }
+
+ pr_info("Remapping and enabling EFI services.\n");
+
+ mapsize = memmap.map_end - memmap.map;
+ memmap.map = (__force void *)ioremap_cache(memmap.phys_map,
+ mapsize);
+ if (!memmap.map) {
+ pr_err("Failed to remap EFI memory map\n");
+ return -ENOMEM;
+ }
+ memmap.map_end = memmap.map + mapsize;
+ efi.memmap = &memmap;
+
+ efi.systab = (__force void *)ioremap_cache(efi_system_table,
+ sizeof(efi_system_table_t));
+ if (!efi.systab) {
+ pr_err("Failed to remap EFI System Table\n");
+ return -ENOMEM;
+ }
+ set_bit(EFI_SYSTEM_TABLES, &efi.flags);
+
+ if (!efi_virtmap_init()) {
+ pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n");
+ return -ENOMEM;
+ }
+
+ /* Set up runtime services function pointers */
+ efi_native_runtime_setup();
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+
+ efi.runtime_version = efi.systab->hdr.revision;
+
+ return 0;
+}
+early_initcall(arm_enable_runtime_services);
+
+void efi_virtmap_load(void)
+{
+ preempt_disable();
+ efi_set_pgd(&efi_mm);
+}
+
+void efi_virtmap_unload(void)
+{
+ efi_set_pgd(current->active_mm);
+ preempt_enable();
+}
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 027ca21..cffa89b 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -25,6 +25,8 @@
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <asm/efi.h>
+
struct efi __read_mostly efi = {
.mps = EFI_INVALID_TABLE_ADDR,
.acpi = EFI_INVALID_TABLE_ADDR,
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 3c0467d..9c12e18 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -8,7 +8,7 @@ cflags-$(CONFIG_X86_32) := -march=i386
cflags-$(CONFIG_X86_64) := -mcmodel=small
cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \
-fPIC -fno-strict-aliasing -mno-red-zone \
- -mno-mmx -mno-sse -DDISABLE_BRANCH_PROFILING
+ -mno-mmx -mno-sse
cflags-$(CONFIG_ARM64) := $(subst -pg,,$(KBUILD_CFLAGS))
cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
@@ -16,7 +16,7 @@ cflags-$(CONFIG_ARM) := $(subst -pg,,$(KBUILD_CFLAGS)) \
cflags-$(CONFIG_EFI_ARMSTUB) += -I$(srctree)/scripts/dtc/libfdt
-KBUILD_CFLAGS := $(cflags-y) \
+KBUILD_CFLAGS := $(cflags-y) -DDISABLE_BRANCH_PROFILING \
$(call cc-option,-ffreestanding) \
$(call cc-option,-fno-stack-protector)
@@ -34,6 +34,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \
$(patsubst %.c,lib-%.o,$(arm-deps))
+lib-$(CONFIG_ARM) += arm32-stub.o
lib-$(CONFIG_ARM64) += arm64-stub.o
CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
@@ -67,3 +68,11 @@ quiet_cmd_stubcopy = STUBCPY $@
$(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \
&& (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \
rm -f $@; /bin/false); else /bin/false; fi
+
+#
+# ARM discards the .data section because it disallows r/w data in the
+# decompressor. So move our .data to .data.efistub, which is preserved
+# explicitly by the decompressor linker script.
+#
+STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub
+STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 950c87f..3397902 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -303,8 +303,10 @@ fail:
* The value chosen is the largest non-zero power of 2 suitable for this purpose
* both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
* be mapped efficiently.
+ * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split,
+ * map everything below 1 GB.
*/
-#define EFI_RT_VIRTUAL_BASE 0x40000000
+#define EFI_RT_VIRTUAL_BASE SZ_512M
static int cmp_mem_desc(const void *l, const void *r)
{
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
new file mode 100644
index 0000000..495ebd6
--- /dev/null
+++ b/drivers/firmware/efi/libstub/arm32-stub.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2013 Linaro Ltd; <roy.franz@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/efi.h>
+#include <asm/efi.h>
+
+efi_status_t handle_kernel_image(efi_system_table_t *sys_table,
+ unsigned long *image_addr,
+ unsigned long *image_size,
+ unsigned long *reserve_addr,
+ unsigned long *reserve_size,
+ unsigned long dram_base,
+ efi_loaded_image_t *image)
+{
+ unsigned long nr_pages;
+ efi_status_t status;
+ /* Use alloc_addr to tranlsate between types */
+ efi_physical_addr_t alloc_addr;
+
+ /*
+ * Verify that the DRAM base address is compatible with the ARM
+ * boot protocol, which determines the base of DRAM by masking
+ * off the low 27 bits of the address at which the zImage is
+ * loaded. These assumptions are made by the decompressor,
+ * before any memory map is available.
+ */
+ dram_base = round_up(dram_base, SZ_128M);
+
+ /*
+ * Reserve memory for the uncompressed kernel image. This is
+ * all that prevents any future allocations from conflicting
+ * with the kernel. Since we can't tell from the compressed
+ * image how much DRAM the kernel actually uses (due to BSS
+ * size uncertainty) we allocate the maximum possible size.
+ * Do this very early, as prints can cause memory allocations
+ * that may conflict with this.
+ */
+ alloc_addr = dram_base;
+ *reserve_size = MAX_UNCOMP_KERNEL_SIZE;
+ nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ status = sys_table->boottime->allocate_pages(EFI_ALLOCATE_ADDRESS,
+ EFI_LOADER_DATA,
+ nr_pages, &alloc_addr);
+ if (status != EFI_SUCCESS) {
+ *reserve_size = 0;
+ pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n");
+ return status;
+ }
+ *reserve_addr = alloc_addr;
+
+ /*
+ * Relocate the zImage, so that it appears in the lowest 128 MB
+ * memory window.
+ */
+ *image_size = image->image_size;
+ status = efi_relocate_kernel(sys_table, image_addr, *image_size,
+ *image_size,
+ dram_base + MAX_UNCOMP_KERNEL_SIZE, 0);
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table, "Failed to relocate kernel.\n");
+ efi_free(sys_table, *reserve_size, *reserve_addr);
+ *reserve_size = 0;
+ return status;
+ }
+
+ /*
+ * Check to see if we were able to allocate memory low enough
+ * in memory. The kernel determines the base of DRAM from the
+ * address at which the zImage is loaded.
+ */
+ if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) {
+ pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n");
+ efi_free(sys_table, *reserve_size, *reserve_addr);
+ *reserve_size = 0;
+ efi_free(sys_table, *image_size, *image_addr);
+ *image_size = 0;
+ return EFI_LOAD_ERROR;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 42700f0..f25cd79 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -13,6 +13,7 @@
#define pr_fmt(fmt) "psci: " fmt
+#include <linux/arm-smccc.h>
#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/of.h>
@@ -20,23 +21,25 @@
#include <linux/printk.h>
#include <linux/psci.h>
#include <linux/reboot.h>
+#include <linux/suspend.h>
#include <uapi/linux/psci.h>
#include <asm/cputype.h>
#include <asm/system_misc.h>
#include <asm/smp_plat.h>
+#include <asm/suspend.h>
/*
* While a 64-bit OS can make calls with SMC32 calling conventions, for some
- * calls it is necessary to use SMC64 to pass or return 64-bit values. For such
- * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width)
- * function ID.
+ * calls it is necessary to use SMC64 to pass or return 64-bit values.
+ * For such calls PSCI_FN_NATIVE(version, name) will choose the appropriate
+ * (native-width) function ID.
*/
#ifdef CONFIG_64BIT
-#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name
#else
-#define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name
+#define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name
#endif
/*
@@ -56,8 +59,6 @@ struct psci_operations psci_ops;
typedef unsigned long (psci_fn)(unsigned long, unsigned long,
unsigned long, unsigned long);
-asmlinkage psci_fn __invoke_psci_fn_hvc;
-asmlinkage psci_fn __invoke_psci_fn_smc;
static psci_fn *invoke_psci_fn;
enum psci_function {
@@ -70,6 +71,61 @@ enum psci_function {
static u32 psci_function_id[PSCI_FN_MAX];
+#define PSCI_0_2_POWER_STATE_MASK \
+ (PSCI_0_2_POWER_STATE_ID_MASK | \
+ PSCI_0_2_POWER_STATE_TYPE_MASK | \
+ PSCI_0_2_POWER_STATE_AFFL_MASK)
+
+#define PSCI_1_0_EXT_POWER_STATE_MASK \
+ (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \
+ PSCI_1_0_EXT_POWER_STATE_TYPE_MASK)
+
+static u32 psci_cpu_suspend_feature;
+
+static inline bool psci_has_ext_power_state(void)
+{
+ return psci_cpu_suspend_feature &
+ PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
+}
+
+bool psci_power_state_loses_context(u32 state)
+{
+ const u32 mask = psci_has_ext_power_state() ?
+ PSCI_1_0_EXT_POWER_STATE_TYPE_MASK :
+ PSCI_0_2_POWER_STATE_TYPE_MASK;
+
+ return state & mask;
+}
+
+bool psci_power_state_is_valid(u32 state)
+{
+ const u32 valid_mask = psci_has_ext_power_state() ?
+ PSCI_1_0_EXT_POWER_STATE_MASK :
+ PSCI_0_2_POWER_STATE_MASK;
+
+ return !(state & ~valid_mask);
+}
+
+static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
+ unsigned long arg0, unsigned long arg1,
+ unsigned long arg2)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
+static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
+ unsigned long arg0, unsigned long arg1,
+ unsigned long arg2)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
+ return res.a0;
+}
+
static int psci_to_linux_errno(int errno)
{
switch (errno) {
@@ -78,6 +134,7 @@ static int psci_to_linux_errno(int errno)
case PSCI_RET_NOT_SUPPORTED:
return -EOPNOTSUPP;
case PSCI_RET_INVALID_PARAMS:
+ case PSCI_RET_INVALID_ADDRESS:
return -EINVAL;
case PSCI_RET_DENIED:
return -EPERM;
@@ -134,7 +191,7 @@ static int psci_migrate(unsigned long cpuid)
static int psci_affinity_info(unsigned long target_affinity,
unsigned long lowest_affinity_level)
{
- return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO),
+ return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO),
target_affinity, lowest_affinity_level, 0);
}
@@ -145,7 +202,7 @@ static int psci_migrate_info_type(void)
static unsigned long psci_migrate_info_up_cpu(void)
{
- return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU),
+ return invoke_psci_fn(PSCI_FN_NATIVE(0_2, MIGRATE_INFO_UP_CPU),
0, 0, 0);
}
@@ -181,6 +238,49 @@ static void psci_sys_poweroff(void)
invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
}
+static int __init psci_features(u32 psci_func_id)
+{
+ return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES,
+ psci_func_id, 0, 0);
+}
+
+static int psci_system_suspend(unsigned long unused)
+{
+ return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
+ virt_to_phys(cpu_resume), 0, 0);
+}
+
+static int psci_system_suspend_enter(suspend_state_t state)
+{
+ return cpu_suspend(0, psci_system_suspend);
+}
+
+static const struct platform_suspend_ops psci_suspend_ops = {
+ .valid = suspend_valid_only_mem,
+ .enter = psci_system_suspend_enter,
+};
+
+static void __init psci_init_system_suspend(void)
+{
+ int ret;
+
+ if (!IS_ENABLED(CONFIG_SUSPEND))
+ return;
+
+ ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
+
+ if (ret != PSCI_RET_NOT_SUPPORTED)
+ suspend_set_ops(&psci_suspend_ops);
+}
+
+static void __init psci_init_cpu_suspend(void)
+{
+ int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]);
+
+ if (feature != PSCI_RET_NOT_SUPPORTED)
+ psci_cpu_suspend_feature = feature;
+}
+
/*
* Detect the presence of a resident Trusted OS which may cause CPU_OFF to
* return DENIED (which would be fatal).
@@ -224,16 +324,17 @@ static void __init psci_init_migrate(void)
static void __init psci_0_2_set_functions(void)
{
pr_info("Using standard PSCI v0.2 function IDs\n");
- psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND);
+ psci_function_id[PSCI_FN_CPU_SUSPEND] =
+ PSCI_FN_NATIVE(0_2, CPU_SUSPEND);
psci_ops.cpu_suspend = psci_cpu_suspend;
psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
psci_ops.cpu_off = psci_cpu_off;
- psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON);
+ psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON);
psci_ops.cpu_on = psci_cpu_on;
- psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE);
+ psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE);
psci_ops.migrate = psci_migrate;
psci_ops.affinity_info = psci_affinity_info;
@@ -265,6 +366,11 @@ static int __init psci_probe(void)
psci_init_migrate();
+ if (PSCI_VERSION_MAJOR(ver) >= 1) {
+ psci_init_cpu_suspend();
+ psci_init_system_suspend();
+ }
+
return 0;
}
@@ -340,6 +446,7 @@ out_put_node:
static const struct of_device_id const psci_of_match[] __initconst = {
{ .compatible = "arm,psci", .data = psci_0_1_init},
{ .compatible = "arm,psci-0.2", .data = psci_0_2_init},
+ { .compatible = "arm,psci-1.0", .data = psci_0_2_init},
{},
};
diff --git a/drivers/firmware/qcom_scm-32.c b/drivers/firmware/qcom_scm-32.c
index 29e6850..0883292 100644
--- a/drivers/firmware/qcom_scm-32.c
+++ b/drivers/firmware/qcom_scm-32.c
@@ -480,15 +480,15 @@ void __qcom_scm_cpu_power_down(u32 flags)
int __qcom_scm_is_call_available(u32 svc_id, u32 cmd_id)
{
int ret;
- u32 svc_cmd = (svc_id << 10) | cmd_id;
- u32 ret_val = 0;
+ __le32 svc_cmd = cpu_to_le32((svc_id << 10) | cmd_id);
+ __le32 ret_val = 0;
ret = qcom_scm_call(QCOM_SCM_SVC_INFO, QCOM_IS_CALL_AVAIL_CMD, &svc_cmd,
sizeof(svc_cmd), &ret_val, sizeof(ret_val));
if (ret)
return ret;
- return ret_val;
+ return le32_to_cpu(ret_val);
}
int __qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt, u32 *resp)
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
new file mode 100644
index 0000000..dd506cd
--- /dev/null
+++ b/drivers/firmware/raspberrypi.c
@@ -0,0 +1,260 @@
+/*
+ * Defines interfaces for interacting wtih the Raspberry Pi firmware's
+ * property channel.
+ *
+ * Copyright © 2015 Broadcom
+ *
+ * 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/dma-mapping.h>
+#include <linux/mailbox_client.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <soc/bcm2835/raspberrypi-firmware.h>
+
+#define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf))
+#define MBOX_CHAN(msg) ((msg) & 0xf)
+#define MBOX_DATA28(msg) ((msg) & ~0xf)
+#define MBOX_CHAN_PROPERTY 8
+
+struct rpi_firmware {
+ struct mbox_client cl;
+ struct mbox_chan *chan; /* The property channel. */
+ struct completion c;
+ u32 enabled;
+};
+
+static DEFINE_MUTEX(transaction_lock);
+
+static void response_callback(struct mbox_client *cl, void *msg)
+{
+ struct rpi_firmware *fw = container_of(cl, struct rpi_firmware, cl);
+ complete(&fw->c);
+}
+
+/*
+ * Sends a request to the firmware through the BCM2835 mailbox driver,
+ * and synchronously waits for the reply.
+ */
+static int
+rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data)
+{
+ u32 message = MBOX_MSG(chan, data);
+ int ret;
+
+ WARN_ON(data & 0xf);
+
+ mutex_lock(&transaction_lock);
+ reinit_completion(&fw->c);
+ ret = mbox_send_message(fw->chan, &message);
+ if (ret >= 0) {
+ wait_for_completion(&fw->c);
+ ret = 0;
+ } else {
+ dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret);
+ }
+ mutex_unlock(&transaction_lock);
+
+ return ret;
+}
+
+/**
+ * rpi_firmware_property_list - Submit firmware property list
+ * @fw: Pointer to firmware structure from rpi_firmware_get().
+ * @data: Buffer holding tags.
+ * @tag_size: Size of tags buffer.
+ *
+ * Submits a set of concatenated tags to the VPU firmware through the
+ * mailbox property interface.
+ *
+ * The buffer header and the ending tag are added by this function and
+ * don't need to be supplied, just the actual tags for your operation.
+ * See struct rpi_firmware_property_tag_header for the per-tag
+ * structure.
+ */
+int rpi_firmware_property_list(struct rpi_firmware *fw,
+ void *data, size_t tag_size)
+{
+ size_t size = tag_size + 12;
+ u32 *buf;
+ dma_addr_t bus_addr;
+ int ret;
+
+ /* Packets are processed a dword at a time. */
+ if (size & 3)
+ return -EINVAL;
+
+ buf = dma_alloc_coherent(fw->cl.dev, PAGE_ALIGN(size), &bus_addr,
+ GFP_ATOMIC);
+ if (!buf)
+ return -ENOMEM;
+
+ /* The firmware will error out without parsing in this case. */
+ WARN_ON(size >= 1024 * 1024);
+
+ buf[0] = size;
+ buf[1] = RPI_FIRMWARE_STATUS_REQUEST;
+ memcpy(&buf[2], data, tag_size);
+ buf[size / 4 - 1] = RPI_FIRMWARE_PROPERTY_END;
+ wmb();
+
+ ret = rpi_firmware_transaction(fw, MBOX_CHAN_PROPERTY, bus_addr);
+
+ rmb();
+ memcpy(data, &buf[2], tag_size);
+ if (ret == 0 && buf[1] != RPI_FIRMWARE_STATUS_SUCCESS) {
+ /*
+ * The tag name here might not be the one causing the
+ * error, if there were multiple tags in the request.
+ * But single-tag is the most common, so go with it.
+ */
+ dev_err(fw->cl.dev, "Request 0x%08x returned status 0x%08x\n",
+ buf[2], buf[1]);
+ ret = -EINVAL;
+ }
+
+ dma_free_coherent(fw->cl.dev, PAGE_ALIGN(size), buf, bus_addr);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_property_list);
+
+/**
+ * rpi_firmware_property - Submit single firmware property
+ * @fw: Pointer to firmware structure from rpi_firmware_get().
+ * @tag: One of enum_mbox_property_tag.
+ * @tag_data: Tag data buffer.
+ * @buf_size: Buffer size.
+ *
+ * Submits a single tag to the VPU firmware through the mailbox
+ * property interface.
+ *
+ * This is a convenience wrapper around
+ * rpi_firmware_property_list() to avoid some of the
+ * boilerplate in property calls.
+ */
+int rpi_firmware_property(struct rpi_firmware *fw,
+ u32 tag, void *tag_data, size_t buf_size)
+{
+ /* Single tags are very small (generally 8 bytes), so the
+ * stack should be safe.
+ */
+ u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)];
+ struct rpi_firmware_property_tag_header *header =
+ (struct rpi_firmware_property_tag_header *)data;
+ int ret;
+
+ header->tag = tag;
+ header->buf_size = buf_size;
+ header->req_resp_size = 0;
+ memcpy(data + sizeof(struct rpi_firmware_property_tag_header),
+ tag_data, buf_size);
+
+ ret = rpi_firmware_property_list(fw, &data, sizeof(data));
+ memcpy(tag_data,
+ data + sizeof(struct rpi_firmware_property_tag_header),
+ buf_size);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_property);
+
+static void
+rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
+{
+ u32 packet;
+ int ret = rpi_firmware_property(fw,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION,
+ &packet, sizeof(packet));
+
+ if (ret == 0) {
+ struct tm tm;
+
+ time_to_tm(packet, 0, &tm);
+
+ dev_info(fw->cl.dev,
+ "Attached to firmware from %04ld-%02d-%02d %02d:%02d\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min);
+ }
+}
+
+static int rpi_firmware_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rpi_firmware *fw;
+
+ fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return -ENOMEM;
+
+ fw->cl.dev = dev;
+ fw->cl.rx_callback = response_callback;
+ fw->cl.tx_block = true;
+
+ fw->chan = mbox_request_channel(&fw->cl, 0);
+ if (IS_ERR(fw->chan)) {
+ int ret = PTR_ERR(fw->chan);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Failed to get mbox channel: %d\n", ret);
+ return ret;
+ }
+
+ init_completion(&fw->c);
+
+ platform_set_drvdata(pdev, fw);
+
+ rpi_firmware_print_firmware_revision(fw);
+
+ return 0;
+}
+
+static int rpi_firmware_remove(struct platform_device *pdev)
+{
+ struct rpi_firmware *fw = platform_get_drvdata(pdev);
+
+ mbox_free_channel(fw->chan);
+
+ return 0;
+}
+
+/**
+ * rpi_firmware_get - Get pointer to rpi_firmware structure.
+ * @firmware_node: Pointer to the firmware Device Tree node.
+ *
+ * Returns NULL is the firmware device is not ready.
+ */
+struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node)
+{
+ struct platform_device *pdev = of_find_device_by_node(firmware_node);
+
+ if (!pdev)
+ return NULL;
+
+ return platform_get_drvdata(pdev);
+}
+EXPORT_SYMBOL_GPL(rpi_firmware_get);
+
+static const struct of_device_id rpi_firmware_of_match[] = {
+ { .compatible = "raspberrypi,bcm2835-firmware", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, rpi_firmware_of_match);
+
+static struct platform_driver rpi_firmware_driver = {
+ .driver = {
+ .name = "raspberrypi-firmware",
+ .of_match_table = rpi_firmware_of_match,
+ },
+ .probe = rpi_firmware_probe,
+ .remove = rpi_firmware_remove,
+};
+module_platform_driver(rpi_firmware_driver);
+
+MODULE_AUTHOR("Eric Anholt <eric@anholt.net>");
+MODULE_DESCRIPTION("Raspberry Pi firmware driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/fpga/fpga-mgr.c b/drivers/fpga/fpga-mgr.c
index a24f5cb..953dc91 100644
--- a/drivers/fpga/fpga-mgr.c
+++ b/drivers/fpga/fpga-mgr.c
@@ -122,12 +122,10 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
}
ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size);
- if (ret)
- return ret;
release_firmware(fw);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(fpga_mgr_firmware_load);
@@ -256,7 +254,6 @@ int fpga_mgr_register(struct device *dev, const char *name,
void *priv)
{
struct fpga_manager *mgr;
- const char *dt_label;
int id, ret;
if (!mops || !mops->write_init || !mops->write ||
@@ -300,11 +297,9 @@ int fpga_mgr_register(struct device *dev, const char *name,
mgr->dev.id = id;
dev_set_drvdata(dev, mgr);
- dt_label = of_get_property(mgr->dev.of_node, "label", NULL);
- if (dt_label)
- ret = dev_set_name(&mgr->dev, "%s", dt_label);
- else
- ret = dev_set_name(&mgr->dev, "fpga%d", id);
+ ret = dev_set_name(&mgr->dev, "fpga%d", id);
+ if (ret)
+ goto error_device;
ret = device_add(&mgr->dev);
if (ret)
diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c
index 6ed7c0f..6b18682 100644
--- a/drivers/gpio/gpio-74xx-mmio.c
+++ b/drivers/gpio/gpio-74xx-mmio.c
@@ -113,13 +113,16 @@ static int mmio_74xx_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
static int mmio_74xx_gpio_probe(struct platform_device *pdev)
{
- const struct of_device_id *of_id =
- of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
+ const struct of_device_id *of_id;
struct mmio_74xx_gpio_priv *priv;
struct resource *res;
void __iomem *dat;
int err;
+ of_id = of_match_device(mmio_74xx_gpio_ids, &pdev->dev);
+ if (!of_id)
+ return -ENODEV;
+
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index e5827a5..5eaea8b 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -113,7 +113,7 @@ static int ar934x_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
__raw_writel(BIT(offset), ctrl->base + AR71XX_GPIO_REG_CLEAR);
__raw_writel(
- __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & BIT(offset),
+ __raw_readl(ctrl->base + AR71XX_GPIO_REG_OE) & ~BIT(offset),
ctrl->base + AR71XX_GPIO_REG_OE);
spin_unlock_irqrestore(&ctrl->lock, flags);
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index bd5193c..88ae70d 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -141,9 +141,9 @@ static int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio)
unsigned long pinmask = bgc->pin2mask(bgc, gpio);
if (bgc->dir & pinmask)
- return bgc->read_reg(bgc->reg_set) & pinmask;
+ return !!(bgc->read_reg(bgc->reg_set) & pinmask);
else
- return bgc->read_reg(bgc->reg_dat) & pinmask;
+ return !!(bgc->read_reg(bgc->reg_dat) & pinmask);
}
static int bgpio_get(struct gpio_chip *gc, unsigned int gpio)
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 56d2d02..f7fbb46 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1122,8 +1122,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
/* MPUIO is a bit different, reading IRQ status clears it */
if (bank->is_mpuio) {
irqc->irq_ack = dummy_irq_chip.irq_ack;
- irqc->irq_mask = irq_gc_mask_set_bit;
- irqc->irq_unmask = irq_gc_mask_clr_bit;
if (!bank->regs->wkup_en)
irqc->irq_set_wake = NULL;
}
diff --git a/drivers/gpio/gpio-palmas.c b/drivers/gpio/gpio-palmas.c
index 171a638..52b447c 100644
--- a/drivers/gpio/gpio-palmas.c
+++ b/drivers/gpio/gpio-palmas.c
@@ -167,6 +167,8 @@ static int palmas_gpio_probe(struct platform_device *pdev)
const struct palmas_device_data *dev_data;
match = of_match_device(of_palmas_gpio_match, &pdev->dev);
+ if (!match)
+ return -ENODEV;
dev_data = match->data;
if (!dev_data)
dev_data = &palmas_dev_data;
diff --git a/drivers/gpio/gpio-syscon.c b/drivers/gpio/gpio-syscon.c
index 045a952..7b25fdf 100644
--- a/drivers/gpio/gpio-syscon.c
+++ b/drivers/gpio/gpio-syscon.c
@@ -187,11 +187,15 @@ MODULE_DEVICE_TABLE(of, syscon_gpio_ids);
static int syscon_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- const struct of_device_id *of_id = of_match_device(syscon_gpio_ids, dev);
+ const struct of_device_id *of_id;
struct syscon_gpio_priv *priv;
struct device_node *np = dev->of_node;
int ret;
+ of_id = of_match_device(syscon_gpio_ids, dev);
+ if (!of_id)
+ return -ENODEV;
+
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c
index 027e5f4..896bf29 100644
--- a/drivers/gpio/gpio-tegra.c
+++ b/drivers/gpio/gpio-tegra.c
@@ -375,6 +375,60 @@ static int tegra_gpio_irq_set_wake(struct irq_data *d, unsigned int enable)
}
#endif
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static int dbg_gpio_show(struct seq_file *s, void *unused)
+{
+ int i;
+ int j;
+
+ for (i = 0; i < tegra_gpio_bank_count; i++) {
+ for (j = 0; j < 4; j++) {
+ int gpio = tegra_gpio_compose(i, j, 0);
+ seq_printf(s,
+ "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
+ i, j,
+ tegra_gpio_readl(GPIO_CNF(gpio)),
+ tegra_gpio_readl(GPIO_OE(gpio)),
+ tegra_gpio_readl(GPIO_OUT(gpio)),
+ tegra_gpio_readl(GPIO_IN(gpio)),
+ tegra_gpio_readl(GPIO_INT_STA(gpio)),
+ tegra_gpio_readl(GPIO_INT_ENB(gpio)),
+ tegra_gpio_readl(GPIO_INT_LVL(gpio)));
+ }
+ }
+ return 0;
+}
+
+static int dbg_gpio_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dbg_gpio_show, &inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+ .open = dbg_gpio_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void tegra_gpio_debuginit(void)
+{
+ (void) debugfs_create_file("tegra_gpio", S_IRUGO,
+ NULL, NULL, &debug_fops);
+}
+
+#else
+
+static inline void tegra_gpio_debuginit(void)
+{
+}
+
+#endif
+
static struct irq_chip tegra_gpio_irq_chip = {
.name = "GPIO",
.irq_ack = tegra_gpio_irq_ack,
@@ -519,6 +573,8 @@ static int tegra_gpio_probe(struct platform_device *pdev)
spin_lock_init(&bank->lvl_lock[j]);
}
+ tegra_gpio_debuginit();
+
return 0;
}
@@ -536,52 +592,3 @@ static int __init tegra_gpio_init(void)
return platform_driver_register(&tegra_gpio_driver);
}
postcore_initcall(tegra_gpio_init);
-
-#ifdef CONFIG_DEBUG_FS
-
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-
-static int dbg_gpio_show(struct seq_file *s, void *unused)
-{
- int i;
- int j;
-
- for (i = 0; i < tegra_gpio_bank_count; i++) {
- for (j = 0; j < 4; j++) {
- int gpio = tegra_gpio_compose(i, j, 0);
- seq_printf(s,
- "%d:%d %02x %02x %02x %02x %02x %02x %06x\n",
- i, j,
- tegra_gpio_readl(GPIO_CNF(gpio)),
- tegra_gpio_readl(GPIO_OE(gpio)),
- tegra_gpio_readl(GPIO_OUT(gpio)),
- tegra_gpio_readl(GPIO_IN(gpio)),
- tegra_gpio_readl(GPIO_INT_STA(gpio)),
- tegra_gpio_readl(GPIO_INT_ENB(gpio)),
- tegra_gpio_readl(GPIO_INT_LVL(gpio)));
- }
- }
- return 0;
-}
-
-static int dbg_gpio_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dbg_gpio_show, &inode->i_private);
-}
-
-static const struct file_operations debug_fops = {
- .open = dbg_gpio_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init tegra_gpio_debuginit(void)
-{
- (void) debugfs_create_file("tegra_gpio", S_IRUGO,
- NULL, NULL, &debug_fops);
- return 0;
-}
-late_initcall(tegra_gpio_debuginit);
-#endif
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a18f00f..4e4c308 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -233,7 +233,7 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
for (i = 0; i != chip->ngpio; ++i) {
struct gpio_desc *gpio = &chip->desc[i];
- if (!gpio->name)
+ if (!gpio->name || !name)
continue;
if (!strcmp(gpio->name, name)) {
@@ -1279,7 +1279,13 @@ static int _gpiod_get_raw_value(const struct gpio_desc *desc)
chip = desc->chip;
offset = gpio_chip_hwgpio(desc);
value = chip->get ? chip->get(chip, offset) : -EIO;
- value = value < 0 ? value : !!value;
+ /*
+ * FIXME: fix all drivers to clamp to [0,1] or return negative,
+ * then change this to:
+ * value = value < 0 ? value : !!value;
+ * so we can properly propagate error codes.
+ */
+ value = !!value;
trace_gpio_value(desc_to_gpio(desc), 1, value);
return value;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
index 615ce6d..048cfe0 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
@@ -389,7 +389,6 @@ struct amdgpu_clock {
* Fences.
*/
struct amdgpu_fence_driver {
- struct amdgpu_ring *ring;
uint64_t gpu_addr;
volatile uint32_t *cpu_addr;
/* sync_seq is protected by ring emission lock */
@@ -398,7 +397,7 @@ struct amdgpu_fence_driver {
bool initialized;
struct amdgpu_irq_src *irq_src;
unsigned irq_type;
- struct delayed_work lockup_work;
+ struct timer_list fallback_timer;
wait_queue_head_t fence_queue;
};
@@ -497,6 +496,7 @@ struct amdgpu_bo_va_mapping {
/* bo virtual addresses in a specific vm */
struct amdgpu_bo_va {
+ struct mutex mutex;
/* protected by bo being reserved */
struct list_head bo_list;
struct fence *last_pt_update;
@@ -539,6 +539,7 @@ struct amdgpu_bo {
/* Constant after initialization */
struct amdgpu_device *adev;
struct drm_gem_object gem_base;
+ struct amdgpu_bo *parent;
struct ttm_bo_kmap_obj dma_buf_vmap;
pid_t pid;
@@ -917,8 +918,8 @@ struct amdgpu_ring {
#define AMDGPU_VM_FAULT_STOP_ALWAYS 2
struct amdgpu_vm_pt {
- struct amdgpu_bo *bo;
- uint64_t addr;
+ struct amdgpu_bo *bo;
+ uint64_t addr;
};
struct amdgpu_vm_id {
@@ -926,13 +927,9 @@ struct amdgpu_vm_id {
uint64_t pd_gpu_addr;
/* last flushed PD/PT update */
struct fence *flushed_updates;
- /* last use of vmid */
- struct fence *last_id_use;
};
struct amdgpu_vm {
- struct mutex mutex;
-
struct rb_root va;
/* protecting invalidated */
@@ -957,24 +954,72 @@ struct amdgpu_vm {
/* for id and flush management per ring */
struct amdgpu_vm_id ids[AMDGPU_MAX_RINGS];
+ /* for interval tree */
+ spinlock_t it_lock;
+ /* protecting freed */
+ spinlock_t freed_lock;
};
struct amdgpu_vm_manager {
- struct fence *active[AMDGPU_NUM_VM];
- uint32_t max_pfn;
+ struct {
+ struct fence *active;
+ atomic_long_t owner;
+ } ids[AMDGPU_NUM_VM];
+
+ uint32_t max_pfn;
/* number of VMIDs */
- unsigned nvm;
+ unsigned nvm;
/* vram base address for page table entry */
- u64 vram_base_offset;
+ u64 vram_base_offset;
/* is vm enabled? */
- bool enabled;
- /* for hw to save the PD addr on suspend/resume */
- uint32_t saved_table_addr[AMDGPU_NUM_VM];
+ bool enabled;
/* vm pte handling */
const struct amdgpu_vm_pte_funcs *vm_pte_funcs;
struct amdgpu_ring *vm_pte_funcs_ring;
};
+void amdgpu_vm_manager_fini(struct amdgpu_device *adev);
+int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
+struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct list_head *head);
+int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
+ struct amdgpu_sync *sync);
+void amdgpu_vm_flush(struct amdgpu_ring *ring,
+ struct amdgpu_vm *vm,
+ struct fence *updates);
+void amdgpu_vm_fence(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct fence *fence);
+uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr);
+int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm);
+int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm);
+int amdgpu_vm_clear_invalids(struct amdgpu_device *adev, struct amdgpu_vm *vm,
+ struct amdgpu_sync *sync);
+int amdgpu_vm_bo_update(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ struct ttm_mem_reg *mem);
+void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
+ struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo);
+struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ struct amdgpu_bo *bo);
+int amdgpu_vm_bo_map(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t addr, uint64_t offset,
+ uint64_t size, uint32_t flags);
+int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va,
+ uint64_t addr);
+void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
+ struct amdgpu_bo_va *bo_va);
+int amdgpu_vm_free_job(struct amdgpu_job *job);
+
/*
* context related structures
*/
@@ -1211,6 +1256,7 @@ struct amdgpu_cs_parser {
/* relocations */
struct amdgpu_bo_list_entry *vm_bos;
struct list_head validated;
+ struct fence *fence;
struct amdgpu_ib *ibs;
uint32_t num_ibs;
@@ -1218,7 +1264,8 @@ struct amdgpu_cs_parser {
struct ww_acquire_ctx ticket;
/* user fence */
- struct amdgpu_user_fence uf;
+ struct amdgpu_user_fence uf;
+ struct amdgpu_bo_list_entry uf_entry;
};
struct amdgpu_job {
@@ -1226,7 +1273,7 @@ struct amdgpu_job {
struct amdgpu_device *adev;
struct amdgpu_ib *ibs;
uint32_t num_ibs;
- struct mutex job_lock;
+ void *owner;
struct amdgpu_user_fence uf;
int (*free_job)(struct amdgpu_job *job);
};
@@ -2257,11 +2304,6 @@ void amdgpu_pci_config_reset(struct amdgpu_device *adev);
bool amdgpu_card_posted(struct amdgpu_device *adev);
void amdgpu_update_display_priority(struct amdgpu_device *adev);
bool amdgpu_boot_test_post_card(struct amdgpu_device *adev);
-struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
- struct drm_file *filp,
- struct amdgpu_ctx *ctx,
- struct amdgpu_ib *ibs,
- uint32_t num_ibs);
int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data);
int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
@@ -2319,49 +2361,6 @@ long amdgpu_kms_compat_ioctl(struct file *filp, unsigned int cmd,
unsigned long arg);
/*
- * vm
- */
-int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm);
-struct amdgpu_bo_list_entry *amdgpu_vm_get_bos(struct amdgpu_device *adev,
- struct amdgpu_vm *vm,
- struct list_head *head);
-int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
- struct amdgpu_sync *sync);
-void amdgpu_vm_flush(struct amdgpu_ring *ring,
- struct amdgpu_vm *vm,
- struct fence *updates);
-void amdgpu_vm_fence(struct amdgpu_device *adev,
- struct amdgpu_vm *vm,
- struct amdgpu_fence *fence);
-uint64_t amdgpu_vm_map_gart(struct amdgpu_device *adev, uint64_t addr);
-int amdgpu_vm_update_page_directory(struct amdgpu_device *adev,
- struct amdgpu_vm *vm);
-int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
- struct amdgpu_vm *vm);
-int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
- struct amdgpu_vm *vm, struct amdgpu_sync *sync);
-int amdgpu_vm_bo_update(struct amdgpu_device *adev,
- struct amdgpu_bo_va *bo_va,
- struct ttm_mem_reg *mem);
-void amdgpu_vm_bo_invalidate(struct amdgpu_device *adev,
- struct amdgpu_bo *bo);
-struct amdgpu_bo_va *amdgpu_vm_bo_find(struct amdgpu_vm *vm,
- struct amdgpu_bo *bo);
-struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
- struct amdgpu_vm *vm,
- struct amdgpu_bo *bo);
-int amdgpu_vm_bo_map(struct amdgpu_device *adev,
- struct amdgpu_bo_va *bo_va,
- uint64_t addr, uint64_t offset,
- uint64_t size, uint32_t flags);
-int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
- struct amdgpu_bo_va *bo_va,
- uint64_t addr);
-void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
- struct amdgpu_bo_va *bo_va);
-int amdgpu_vm_free_job(struct amdgpu_job *job);
-/*
* functions used by amdgpu_encoder.c
*/
struct amdgpu_afmt_acr {
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
index dfc4d02..25a3e248 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c
@@ -127,28 +127,35 @@ int amdgpu_cs_get_ring(struct amdgpu_device *adev, u32 ip_type,
return 0;
}
-struct amdgpu_cs_parser *amdgpu_cs_parser_create(struct amdgpu_device *adev,
- struct drm_file *filp,
- struct amdgpu_ctx *ctx,
- struct amdgpu_ib *ibs,
- uint32_t num_ibs)
+static int amdgpu_cs_user_fence_chunk(struct amdgpu_cs_parser *p,
+ struct drm_amdgpu_cs_chunk_fence *fence_data)
{
- struct amdgpu_cs_parser *parser;
- int i;
+ struct drm_gem_object *gobj;
+ uint32_t handle;
+
+ handle = fence_data->handle;
+ gobj = drm_gem_object_lookup(p->adev->ddev, p->filp,
+ fence_data->handle);
+ if (gobj == NULL)
+ return -EINVAL;
+
+ p->uf.bo = amdgpu_bo_ref(gem_to_amdgpu_bo(gobj));
+ p->uf.offset = fence_data->offset;
- parser = kzalloc(sizeof(struct amdgpu_cs_parser), GFP_KERNEL);
- if (!parser)
- return NULL;
+ if (amdgpu_ttm_tt_has_userptr(p->uf.bo->tbo.ttm)) {
+ drm_gem_object_unreference_unlocked(gobj);
+ return -EINVAL;
+ }
- parser->adev = adev;
- parser->filp = filp;
- parser->ctx = ctx;
- parser->ibs = ibs;
- parser->num_ibs = num_ibs;
- for (i = 0; i < num_ibs; i++)
- ibs[i].ctx = ctx;
+ p->uf_entry.robj = amdgpu_bo_ref(p->uf.bo);
+ p->uf_entry.prefered_domains = AMDGPU_GEM_DOMAIN_GTT;
+ p->uf_entry.allowed_domains = AMDGPU_GEM_DOMAIN_GTT;
+ p->uf_entry.priority = 0;
+ p->uf_entry.tv.bo = &p->uf_entry.robj->tbo;
+ p->uf_entry.tv.shared = true;
- return parser;
+ drm_gem_object_unreference_unlocked(gobj);
+ return 0;
}
int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
@@ -231,26 +238,15 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data)
case AMDGPU_CHUNK_ID_FENCE:
size = sizeof(struct drm_amdgpu_cs_chunk_fence);
- if (p->chunks[i].length_dw * sizeof(uint32_t) >= size) {
- uint32_t handle;
- struct drm_gem_object *gobj;
- struct drm_amdgpu_cs_chunk_fence *fence_data;
-
- fence_data = (void *)p->chunks[i].kdata;
- handle = fence_data->handle;
- gobj = drm_gem_object_lookup(p->adev->ddev,
- p->filp, handle);
- if (gobj == NULL) {
- ret = -EINVAL;
- goto free_partial_kdata;
- }
-
- p->uf.bo = gem_to_amdgpu_bo(gobj);
- p->uf.offset = fence_data->offset;
- } else {
+ if (p->chunks[i].length_dw * sizeof(uint32_t) < size) {
ret = -EINVAL;
goto free_partial_kdata;
}
+
+ ret = amdgpu_cs_user_fence_chunk(p, (void *)p->chunks[i].kdata);
+ if (ret)
+ goto free_partial_kdata;
+
break;
case AMDGPU_CHUNK_ID_DEPENDENCIES:
@@ -413,6 +409,9 @@ static int amdgpu_cs_parser_relocs(struct amdgpu_cs_parser *p)
p->vm_bos = amdgpu_vm_get_bos(p->adev, &fpriv->vm,
&p->validated);
+ if (p->uf.bo)
+ list_add(&p->uf_entry.tv.head, &p->validated);
+
if (need_mmap_lock)
down_read(&current->mm->mmap_sem);
@@ -463,8 +462,18 @@ static int cmp_size_smaller_first(void *priv, struct list_head *a,
return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
}
-static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int error, bool backoff)
+/**
+ * cs_parser_fini() - clean parser states
+ * @parser: parser structure holding parsing context.
+ * @error: error number
+ *
+ * If error is set than unvalidate buffer, otherwise just free memory
+ * used by parsing context.
+ **/
+static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
{
+ unsigned i;
+
if (!error) {
/* Sort the buffer list from the smallest to largest buffer,
* which affects the order of buffers in the LRU list.
@@ -479,17 +488,14 @@ static void amdgpu_cs_parser_fini_early(struct amdgpu_cs_parser *parser, int err
list_sort(NULL, &parser->validated, cmp_size_smaller_first);
ttm_eu_fence_buffer_objects(&parser->ticket,
- &parser->validated,
- &parser->ibs[parser->num_ibs-1].fence->base);
+ &parser->validated,
+ parser->fence);
} else if (backoff) {
ttm_eu_backoff_reservation(&parser->ticket,
&parser->validated);
}
-}
+ fence_put(parser->fence);
-static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser)
-{
- unsigned i;
if (parser->ctx)
amdgpu_ctx_put(parser->ctx);
if (parser->bo_list)
@@ -499,31 +505,12 @@ static void amdgpu_cs_parser_fini_late(struct amdgpu_cs_parser *parser)
for (i = 0; i < parser->nchunks; i++)
drm_free_large(parser->chunks[i].kdata);
kfree(parser->chunks);
- if (!amdgpu_enable_scheduler)
- {
- if (parser->ibs)
- for (i = 0; i < parser->num_ibs; i++)
- amdgpu_ib_free(parser->adev, &parser->ibs[i]);
- kfree(parser->ibs);
- if (parser->uf.bo)
- drm_gem_object_unreference_unlocked(&parser->uf.bo->gem_base);
- }
-
- kfree(parser);
-}
-
-/**
- * cs_parser_fini() - clean parser states
- * @parser: parser structure holding parsing context.
- * @error: error number
- *
- * If error is set than unvalidate buffer, otherwise just free memory
- * used by parsing context.
- **/
-static void amdgpu_cs_parser_fini(struct amdgpu_cs_parser *parser, int error, bool backoff)
-{
- amdgpu_cs_parser_fini_early(parser, error, backoff);
- amdgpu_cs_parser_fini_late(parser);
+ if (parser->ibs)
+ for (i = 0; i < parser->num_ibs; i++)
+ amdgpu_ib_free(parser->adev, &parser->ibs[i]);
+ kfree(parser->ibs);
+ amdgpu_bo_unref(&parser->uf.bo);
+ amdgpu_bo_unref(&parser->uf_entry.robj);
}
static int amdgpu_bo_vm_update_pte(struct amdgpu_cs_parser *p,
@@ -610,15 +597,9 @@ static int amdgpu_cs_ib_vm_chunk(struct amdgpu_device *adev,
}
r = amdgpu_bo_vm_update_pte(parser, vm);
- if (r) {
- goto out;
- }
- amdgpu_cs_sync_rings(parser);
- if (!amdgpu_enable_scheduler)
- r = amdgpu_ib_schedule(adev, parser->num_ibs, parser->ibs,
- parser->filp);
+ if (!r)
+ amdgpu_cs_sync_rings(parser);
-out:
return r;
}
@@ -818,7 +799,7 @@ static int amdgpu_cs_free_job(struct amdgpu_job *job)
amdgpu_ib_free(job->adev, &job->ibs[i]);
kfree(job->ibs);
if (job->uf.bo)
- drm_gem_object_unreference_unlocked(&job->uf.bo->gem_base);
+ amdgpu_bo_unref(&job->uf.bo);
return 0;
}
@@ -826,38 +807,35 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
{
struct amdgpu_device *adev = dev->dev_private;
union drm_amdgpu_cs *cs = data;
- struct amdgpu_fpriv *fpriv = filp->driver_priv;
- struct amdgpu_vm *vm = &fpriv->vm;
- struct amdgpu_cs_parser *parser;
+ struct amdgpu_cs_parser parser = {};
bool reserved_buffers = false;
int i, r;
if (!adev->accel_working)
return -EBUSY;
- parser = amdgpu_cs_parser_create(adev, filp, NULL, NULL, 0);
- if (!parser)
- return -ENOMEM;
- r = amdgpu_cs_parser_init(parser, data);
+ parser.adev = adev;
+ parser.filp = filp;
+
+ r = amdgpu_cs_parser_init(&parser, data);
if (r) {
DRM_ERROR("Failed to initialize parser !\n");
- amdgpu_cs_parser_fini(parser, r, false);
+ amdgpu_cs_parser_fini(&parser, r, false);
r = amdgpu_cs_handle_lockup(adev, r);
return r;
}
- mutex_lock(&vm->mutex);
- r = amdgpu_cs_parser_relocs(parser);
+ r = amdgpu_cs_parser_relocs(&parser);
if (r == -ENOMEM)
DRM_ERROR("Not enough memory for command submission!\n");
else if (r && r != -ERESTARTSYS)
DRM_ERROR("Failed to process the buffer list %d!\n", r);
else if (!r) {
reserved_buffers = true;
- r = amdgpu_cs_ib_fill(adev, parser);
+ r = amdgpu_cs_ib_fill(adev, &parser);
}
if (!r) {
- r = amdgpu_cs_dependencies(adev, parser);
+ r = amdgpu_cs_dependencies(adev, &parser);
if (r)
DRM_ERROR("Failed in the dependencies handling %d!\n", r);
}
@@ -865,63 +843,71 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
if (r)
goto out;
- for (i = 0; i < parser->num_ibs; i++)
- trace_amdgpu_cs(parser, i);
+ for (i = 0; i < parser.num_ibs; i++)
+ trace_amdgpu_cs(&parser, i);
- r = amdgpu_cs_ib_vm_chunk(adev, parser);
+ r = amdgpu_cs_ib_vm_chunk(adev, &parser);
if (r)
goto out;
- if (amdgpu_enable_scheduler && parser->num_ibs) {
+ if (amdgpu_enable_scheduler && parser.num_ibs) {
+ struct amdgpu_ring * ring = parser.ibs->ring;
+ struct amd_sched_fence *fence;
struct amdgpu_job *job;
- struct amdgpu_ring * ring = parser->ibs->ring;
+
job = kzalloc(sizeof(struct amdgpu_job), GFP_KERNEL);
if (!job) {
r = -ENOMEM;
goto out;
}
+
job->base.sched = &ring->sched;
- job->base.s_entity = &parser->ctx->rings[ring->idx].entity;
- job->adev = parser->adev;
- job->ibs = parser->ibs;
- job->num_ibs = parser->num_ibs;
- job->base.owner = parser->filp;
- mutex_init(&job->job_lock);
+ job->base.s_entity = &parser.ctx->rings[ring->idx].entity;
+ job->adev = parser.adev;
+ job->owner = parser.filp;
+ job->free_job = amdgpu_cs_free_job;
+
+ job->ibs = parser.ibs;
+ job->num_ibs = parser.num_ibs;
+ parser.ibs = NULL;
+ parser.num_ibs = 0;
+
if (job->ibs[job->num_ibs - 1].user) {
- memcpy(&job->uf, &parser->uf,
- sizeof(struct amdgpu_user_fence));
+ job->uf = parser.uf;
job->ibs[job->num_ibs - 1].user = &job->uf;
+ parser.uf.bo = NULL;
}
- job->free_job = amdgpu_cs_free_job;
- mutex_lock(&job->job_lock);
- r = amd_sched_entity_push_job(&job->base);
- if (r) {
- mutex_unlock(&job->job_lock);
+ fence = amd_sched_fence_create(job->base.s_entity,
+ parser.filp);
+ if (!fence) {
+ r = -ENOMEM;
amdgpu_cs_free_job(job);
kfree(job);
goto out;
}
- cs->out.handle =
- amdgpu_ctx_add_fence(parser->ctx, ring,
- &job->base.s_fence->base);
- parser->ibs[parser->num_ibs - 1].sequence = cs->out.handle;
+ job->base.s_fence = fence;
+ parser.fence = fence_get(&fence->base);
- list_sort(NULL, &parser->validated, cmp_size_smaller_first);
- ttm_eu_fence_buffer_objects(&parser->ticket,
- &parser->validated,
- &job->base.s_fence->base);
+ cs->out.handle = amdgpu_ctx_add_fence(parser.ctx, ring,
+ &fence->base);
+ job->ibs[job->num_ibs - 1].sequence = cs->out.handle;
- mutex_unlock(&job->job_lock);
- amdgpu_cs_parser_fini_late(parser);
- mutex_unlock(&vm->mutex);
- return 0;
+ trace_amdgpu_cs_ioctl(job);
+ amd_sched_entity_push_job(&job->base);
+
+ } else {
+ struct amdgpu_fence *fence;
+
+ r = amdgpu_ib_schedule(adev, parser.num_ibs, parser.ibs,
+ parser.filp);
+ fence = parser.ibs[parser.num_ibs - 1].fence;
+ parser.fence = fence_get(&fence->base);
+ cs->out.handle = parser.ibs[parser.num_ibs - 1].sequence;
}
- cs->out.handle = parser->ibs[parser->num_ibs - 1].sequence;
out:
- amdgpu_cs_parser_fini(parser, r, reserved_buffers);
- mutex_unlock(&vm->mutex);
+ amdgpu_cs_parser_fini(&parser, r, reserved_buffers);
r = amdgpu_cs_handle_lockup(adev, r);
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
index e173a5a..5580d34 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
@@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
struct drm_crtc *crtc = &amdgpuCrtc->base;
unsigned long flags;
unsigned i;
+ int vpos, hpos, stat, min_udelay;
+ struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
amdgpu_flip_wait_fence(adev, &work->excl);
for (i = 0; i < work->shared_count; ++i)
@@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
/* We borrow the event spin lock for protecting flip_status */
spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ /* If this happens to execute within the "virtually extended" vblank
+ * interval before the start of the real vblank interval then it needs
+ * to delay programming the mmio flip until the real vblank is entered.
+ * This prevents completing a flip too early due to the way we fudge
+ * our vblank counter and vblank timestamps in order to work around the
+ * problem that the hw fires vblank interrupts before actual start of
+ * vblank (when line buffer refilling is done for a frame). It
+ * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
+ * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
+ *
+ * In practice this won't execute very often unless on very fast
+ * machines because the time window for this to happen is very small.
+ */
+ for (;;) {
+ /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
+ * start in hpos, and to the "fudged earlier" vblank start in
+ * vpos.
+ */
+ stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
+ GET_DISTANCE_TO_VBLANKSTART,
+ &vpos, &hpos, NULL, NULL,
+ &crtc->hwmode);
+
+ if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
+ !(vpos >= 0 && hpos <= 0))
+ break;
+
+ /* Sleep at least until estimated real start of hw vblank */
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+ min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+ usleep_range(min_udelay, 2 * min_udelay);
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ };
+
/* do the flip (mmio) */
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base);
/* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
} else
DRM_ERROR("failed to reserve buffer after flip\n");
- drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+ amdgpu_bo_unref(&work->old_rbo);
kfree(work->shared);
kfree(work);
}
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
obj = old_amdgpu_fb->obj;
/* take a reference to the old object */
- drm_gem_object_reference(obj);
work->old_rbo = gem_to_amdgpu_bo(obj);
+ amdgpu_bo_ref(work->old_rbo);
new_amdgpu_fb = to_amdgpu_framebuffer(fb);
obj = new_amdgpu_fb->obj;
@@ -222,7 +259,7 @@ pflip_cleanup:
amdgpu_bo_unreserve(new_rbo);
cleanup:
- drm_gem_object_unreference_unlocked(&work->old_rbo->gem_base);
+ amdgpu_bo_unref(&work->old_rbo);
fence_put(work->excl);
for (i = 0; i < work->shared_count; ++i)
fence_put(work->shared[i]);
@@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
* \param dev Device to query.
* \param pipe Crtc to query.
* \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
+ * For driver internal use only also supports these flags:
+ *
+ * USE_REAL_VBLANKSTART to use the real start of vblank instead
+ * of a fudged earlier start of vblank.
+ *
+ * GET_DISTANCE_TO_VBLANKSTART to return distance to the
+ * fudged earlier start of vblank in *vpos and the distance
+ * to true start of vblank in *hpos.
+ *
* \param *vpos Location where vertical scanout position should be stored.
* \param *hpos Location where horizontal scanout position should go.
* \param *stime Target location for timestamp taken immediately before
@@ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
vbl_end = 0;
}
+ /* Called from driver internal vblank counter query code? */
+ if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+ /* Caller wants distance from real vbl_start in *hpos */
+ *hpos = *vpos - vbl_start;
+ }
+
+ /* Fudge vblank to start a few scanlines earlier to handle the
+ * problem that vblank irqs fire a few scanlines before start
+ * of vblank. Some driver internal callers need the true vblank
+ * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
+ *
+ * The cause of the "early" vblank irq is that the irq is triggered
+ * by the line buffer logic when the line buffer read position enters
+ * the vblank, whereas our crtc scanout position naturally lags the
+ * line buffer read position.
+ */
+ if (!(flags & USE_REAL_VBLANKSTART))
+ vbl_start -= adev->mode_info.crtcs[pipe]->lb_vblank_lead_lines;
+
/* Test scanout position against vblank region. */
if ((*vpos < vbl_start) && (*vpos >= vbl_end))
in_vbl = false;
+ /* In vblank? */
+ if (in_vbl)
+ ret |= DRM_SCANOUTPOS_IN_VBLANK;
+
+ /* Called from driver internal vblank counter query code? */
+ if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+ /* Caller wants distance from fudged earlier vbl_start */
+ *vpos -= vbl_start;
+ return ret;
+ }
+
/* Check if inside vblank area and apply corrective offsets:
* vpos will then be >=0 in video scanout area, but negative
* within vblank area, counting down the number of lines until
@@ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
/* Correct for shifted end of vbl at vbl_end. */
*vpos = *vpos - vbl_end;
- /* In vblank? */
- if (in_vbl)
- ret |= DRM_SCANOUTPOS_IN_VBLANK;
-
- /* Is vpos outside nominal vblank area, but less than
- * 1/100 of a frame height away from start of vblank?
- * If so, assume this isn't a massively delayed vblank
- * interrupt, but a vblank interrupt that fired a few
- * microseconds before true start of vblank. Compensate
- * by adding a full frame duration to the final timestamp.
- * Happens, e.g., on ATI R500, R600.
- *
- * We only do this if DRM_CALLED_FROM_VBLIRQ.
- */
- if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
- vbl_start = mode->crtc_vdisplay;
- vtotal = mode->crtc_vtotal;
-
- if (vbl_start - *vpos < vtotal / 100) {
- *vpos -= vtotal;
-
- /* Signal this correction as "applied". */
- ret |= 0x8;
- }
- }
-
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
index 257d722..3671f9f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c
@@ -47,6 +47,9 @@
* that the the relevant GPU caches have been flushed.
*/
+static struct kmem_cache *amdgpu_fence_slab;
+static atomic_t amdgpu_fence_slab_ref = ATOMIC_INIT(0);
+
/**
* amdgpu_fence_write - write a fence value
*
@@ -85,24 +88,6 @@ static u32 amdgpu_fence_read(struct amdgpu_ring *ring)
}
/**
- * amdgpu_fence_schedule_check - schedule lockup check
- *
- * @ring: pointer to struct amdgpu_ring
- *
- * Queues a delayed work item to check for lockups.
- */
-static void amdgpu_fence_schedule_check(struct amdgpu_ring *ring)
-{
- /*
- * Do not reset the timer here with mod_delayed_work,
- * this can livelock in an interaction with TTM delayed destroy.
- */
- queue_delayed_work(system_power_efficient_wq,
- &ring->fence_drv.lockup_work,
- AMDGPU_FENCE_JIFFIES_TIMEOUT);
-}
-
-/**
* amdgpu_fence_emit - emit a fence on the requested ring
*
* @ring: ring the fence is associated with
@@ -118,7 +103,7 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
struct amdgpu_device *adev = ring->adev;
/* we are protected by the ring emission mutex */
- *fence = kmalloc(sizeof(struct amdgpu_fence), GFP_KERNEL);
+ *fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_KERNEL);
if ((*fence) == NULL) {
return -ENOMEM;
}
@@ -132,11 +117,23 @@ int amdgpu_fence_emit(struct amdgpu_ring *ring, void *owner,
amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr,
(*fence)->seq,
AMDGPU_FENCE_FLAG_INT);
- trace_amdgpu_fence_emit(ring->adev->ddev, ring->idx, (*fence)->seq);
return 0;
}
/**
+ * amdgpu_fence_schedule_fallback - schedule fallback check
+ *
+ * @ring: pointer to struct amdgpu_ring
+ *
+ * Start a timer as fallback to our interrupts.
+ */
+static void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring)
+{
+ mod_timer(&ring->fence_drv.fallback_timer,
+ jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT);
+}
+
+/**
* amdgpu_fence_activity - check for fence activity
*
* @ring: pointer to struct amdgpu_ring
@@ -202,45 +199,38 @@ static bool amdgpu_fence_activity(struct amdgpu_ring *ring)
} while (atomic64_xchg(&ring->fence_drv.last_seq, seq) > seq);
if (seq < last_emitted)
- amdgpu_fence_schedule_check(ring);
+ amdgpu_fence_schedule_fallback(ring);
return wake;
}
/**
- * amdgpu_fence_check_lockup - check for hardware lockup
+ * amdgpu_fence_process - process a fence
*
- * @work: delayed work item
+ * @adev: amdgpu_device pointer
+ * @ring: ring index the fence is associated with
*
- * Checks for fence activity and if there is none probe
- * the hardware if a lockup occured.
+ * Checks the current fence value and wakes the fence queue
+ * if the sequence number has increased (all asics).
*/
-static void amdgpu_fence_check_lockup(struct work_struct *work)
+void amdgpu_fence_process(struct amdgpu_ring *ring)
{
- struct amdgpu_fence_driver *fence_drv;
- struct amdgpu_ring *ring;
-
- fence_drv = container_of(work, struct amdgpu_fence_driver,
- lockup_work.work);
- ring = fence_drv->ring;
-
if (amdgpu_fence_activity(ring))
wake_up_all(&ring->fence_drv.fence_queue);
}
/**
- * amdgpu_fence_process - process a fence
+ * amdgpu_fence_fallback - fallback for hardware interrupts
*
- * @adev: amdgpu_device pointer
- * @ring: ring index the fence is associated with
+ * @work: delayed work item
*
- * Checks the current fence value and wakes the fence queue
- * if the sequence number has increased (all asics).
+ * Checks for fence activity.
*/
-void amdgpu_fence_process(struct amdgpu_ring *ring)
+static void amdgpu_fence_fallback(unsigned long arg)
{
- if (amdgpu_fence_activity(ring))
- wake_up_all(&ring->fence_drv.fence_queue);
+ struct amdgpu_ring *ring = (void *)arg;
+
+ amdgpu_fence_process(ring);
}
/**
@@ -290,7 +280,7 @@ static int amdgpu_fence_ring_wait_seq(struct amdgpu_ring *ring, uint64_t seq)
if (atomic64_read(&ring->fence_drv.last_seq) >= seq)
return 0;
- amdgpu_fence_schedule_check(ring);
+ amdgpu_fence_schedule_fallback(ring);
wait_event(ring->fence_drv.fence_queue, (
(signaled = amdgpu_fence_seq_signaled(ring, seq))));
@@ -491,9 +481,8 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
atomic64_set(&ring->fence_drv.last_seq, 0);
ring->fence_drv.initialized = false;
- INIT_DELAYED_WORK(&ring->fence_drv.lockup_work,
- amdgpu_fence_check_lockup);
- ring->fence_drv.ring = ring;
+ setup_timer(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback,
+ (unsigned long)ring);
init_waitqueue_head(&ring->fence_drv.fence_queue);
@@ -536,6 +525,13 @@ int amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring)
*/
int amdgpu_fence_driver_init(struct amdgpu_device *adev)
{
+ if (atomic_inc_return(&amdgpu_fence_slab_ref) == 1) {
+ amdgpu_fence_slab = kmem_cache_create(
+ "amdgpu_fence", sizeof(struct amdgpu_fence), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!amdgpu_fence_slab)
+ return -ENOMEM;
+ }
if (amdgpu_debugfs_fence_init(adev))
dev_err(adev->dev, "fence debugfs file creation failed\n");
@@ -554,9 +550,12 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
{
int i, r;
+ if (atomic_dec_and_test(&amdgpu_fence_slab_ref))
+ kmem_cache_destroy(amdgpu_fence_slab);
mutex_lock(&adev->ring_lock);
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
struct amdgpu_ring *ring = adev->rings[i];
+
if (!ring || !ring->fence_drv.initialized)
continue;
r = amdgpu_fence_wait_empty(ring);
@@ -568,6 +567,7 @@ void amdgpu_fence_driver_fini(struct amdgpu_device *adev)
amdgpu_irq_put(adev, ring->fence_drv.irq_src,
ring->fence_drv.irq_type);
amd_sched_fini(&ring->sched);
+ del_timer_sync(&ring->fence_drv.fallback_timer);
ring->fence_drv.initialized = false;
}
mutex_unlock(&adev->ring_lock);
@@ -751,18 +751,25 @@ static bool amdgpu_fence_enable_signaling(struct fence *f)
fence->fence_wake.func = amdgpu_fence_check_signaled;
__add_wait_queue(&ring->fence_drv.fence_queue, &fence->fence_wake);
fence_get(f);
- amdgpu_fence_schedule_check(ring);
+ if (!timer_pending(&ring->fence_drv.fallback_timer))
+ amdgpu_fence_schedule_fallback(ring);
FENCE_TRACE(&fence->base, "armed on ring %i!\n", ring->idx);
return true;
}
+static void amdgpu_fence_release(struct fence *f)
+{
+ struct amdgpu_fence *fence = to_amdgpu_fence(f);
+ kmem_cache_free(amdgpu_fence_slab, fence);
+}
+
const struct fence_ops amdgpu_fence_ops = {
.get_driver_name = amdgpu_fence_get_driver_name,
.get_timeline_name = amdgpu_fence_get_timeline_name,
.enable_signaling = amdgpu_fence_enable_signaling,
.signaled = amdgpu_fence_is_signaled,
.wait = fence_default_wait,
- .release = NULL,
+ .release = amdgpu_fence_release,
};
/*
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
index 0873328..9c253c5 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c
@@ -115,12 +115,9 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_bo_va *bo_va;
int r;
- mutex_lock(&vm->mutex);
r = amdgpu_bo_reserve(rbo, false);
- if (r) {
- mutex_unlock(&vm->mutex);
+ if (r)
return r;
- }
bo_va = amdgpu_vm_bo_find(vm, rbo);
if (!bo_va) {
@@ -129,7 +126,6 @@ int amdgpu_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri
++bo_va->ref_count;
}
amdgpu_bo_unreserve(rbo);
- mutex_unlock(&vm->mutex);
return 0;
}
@@ -142,10 +138,8 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
struct amdgpu_vm *vm = &fpriv->vm;
struct amdgpu_bo_va *bo_va;
int r;
- mutex_lock(&vm->mutex);
r = amdgpu_bo_reserve(rbo, true);
if (r) {
- mutex_unlock(&vm->mutex);
dev_err(adev->dev, "leaking bo va because "
"we fail to reserve bo (%d)\n", r);
return;
@@ -157,7 +151,6 @@ void amdgpu_gem_object_close(struct drm_gem_object *obj,
}
}
amdgpu_bo_unreserve(rbo);
- mutex_unlock(&vm->mutex);
}
static int amdgpu_gem_handle_lockup(struct amdgpu_device *adev, int r)
@@ -242,8 +235,9 @@ int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data,
AMDGPU_GEM_USERPTR_REGISTER))
return -EINVAL;
- if (!(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
- !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) {
+ if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && (
+ !(args->flags & AMDGPU_GEM_USERPTR_ANONONLY) ||
+ !(args->flags & AMDGPU_GEM_USERPTR_REGISTER))) {
/* if we want to write to it we must require anonymous
memory and install a MMU notifier */
@@ -483,6 +477,17 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
if (domain == AMDGPU_GEM_DOMAIN_CPU)
goto error_unreserve;
}
+ list_for_each_entry(entry, &duplicates, head) {
+ domain = amdgpu_mem_type_to_domain(entry->bo->mem.mem_type);
+ /* if anything is swapped out don't swap it in here,
+ just abort and wait for the next CS */
+ if (domain == AMDGPU_GEM_DOMAIN_CPU)
+ goto error_unreserve;
+ }
+
+ r = amdgpu_vm_update_page_directory(adev, bo_va->vm);
+ if (r)
+ goto error_unreserve;
r = amdgpu_vm_clear_freed(adev, bo_va->vm);
if (r)
@@ -512,6 +517,9 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
struct amdgpu_fpriv *fpriv = filp->driver_priv;
struct amdgpu_bo *rbo;
struct amdgpu_bo_va *bo_va;
+ struct ttm_validate_buffer tv, tv_pd;
+ struct ww_acquire_ctx ticket;
+ struct list_head list, duplicates;
uint32_t invalid_flags, va_flags = 0;
int r = 0;
@@ -547,19 +555,28 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
gobj = drm_gem_object_lookup(dev, filp, args->handle);
if (gobj == NULL)
return -ENOENT;
- mutex_lock(&fpriv->vm.mutex);
rbo = gem_to_amdgpu_bo(gobj);
- r = amdgpu_bo_reserve(rbo, false);
+ INIT_LIST_HEAD(&list);
+ INIT_LIST_HEAD(&duplicates);
+ tv.bo = &rbo->tbo;
+ tv.shared = true;
+ list_add(&tv.head, &list);
+
+ if (args->operation == AMDGPU_VA_OP_MAP) {
+ tv_pd.bo = &fpriv->vm.page_directory->tbo;
+ tv_pd.shared = true;
+ list_add(&tv_pd.head, &list);
+ }
+ r = ttm_eu_reserve_buffers(&ticket, &list, true, &duplicates);
if (r) {
- mutex_unlock(&fpriv->vm.mutex);
drm_gem_object_unreference_unlocked(gobj);
return r;
}
bo_va = amdgpu_vm_bo_find(&fpriv->vm, rbo);
if (!bo_va) {
- amdgpu_bo_unreserve(rbo);
- mutex_unlock(&fpriv->vm.mutex);
+ ttm_eu_backoff_reservation(&ticket, &list);
+ drm_gem_object_unreference_unlocked(gobj);
return -ENOENT;
}
@@ -581,10 +598,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
default:
break;
}
-
+ ttm_eu_backoff_reservation(&ticket, &list);
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE))
amdgpu_gem_va_update_vm(adev, bo_va, args->operation);
- mutex_unlock(&fpriv->vm.mutex);
+
drm_gem_object_unreference_unlocked(gobj);
return r;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
index e659877..9e25eda 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c
@@ -62,7 +62,7 @@ int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm,
int r;
if (size) {
- r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+ r = amdgpu_sa_bo_new(&adev->ring_tmp_bo,
&ib->sa_bo, size, 256);
if (r) {
dev_err(adev->dev, "failed to get a new IB (%d)\n", r);
@@ -216,7 +216,7 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs,
}
if (ib->vm)
- amdgpu_vm_fence(adev, ib->vm, ib->fence);
+ amdgpu_vm_fence(adev, ib->vm, &ib->fence->base);
amdgpu_ring_unlock_commit(ring);
return 0;
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
index 1618e22..e23843f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
@@ -611,13 +611,59 @@ void amdgpu_driver_preclose_kms(struct drm_device *dev,
u32 amdgpu_get_vblank_counter_kms(struct drm_device *dev, unsigned int pipe)
{
struct amdgpu_device *adev = dev->dev_private;
+ int vpos, hpos, stat;
+ u32 count;
if (pipe >= adev->mode_info.num_crtc) {
DRM_ERROR("Invalid crtc %u\n", pipe);
return -EINVAL;
}
- return amdgpu_display_vblank_get_counter(adev, pipe);
+ /* The hw increments its frame counter at start of vsync, not at start
+ * of vblank, as is required by DRM core vblank counter handling.
+ * Cook the hw count here to make it appear to the caller as if it
+ * incremented at start of vblank. We measure distance to start of
+ * vblank in vpos. vpos therefore will be >= 0 between start of vblank
+ * and start of vsync, so vpos >= 0 means to bump the hw frame counter
+ * result by 1 to give the proper appearance to caller.
+ */
+ if (adev->mode_info.crtcs[pipe]) {
+ /* Repeat readout if needed to provide stable result if
+ * we cross start of vsync during the queries.
+ */
+ do {
+ count = amdgpu_display_vblank_get_counter(adev, pipe);
+ /* Ask amdgpu_get_crtc_scanoutpos to return vpos as
+ * distance to start of vblank, instead of regular
+ * vertical scanout pos.
+ */
+ stat = amdgpu_get_crtc_scanoutpos(
+ dev, pipe, GET_DISTANCE_TO_VBLANKSTART,
+ &vpos, &hpos, NULL, NULL,
+ &adev->mode_info.crtcs[pipe]->base.hwmode);
+ } while (count != amdgpu_display_vblank_get_counter(adev, pipe));
+
+ if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
+ DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
+ } else {
+ DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
+ pipe, vpos);
+
+ /* Bump counter if we are at >= leading edge of vblank,
+ * but before vsync where vpos would turn negative and
+ * the hw counter really increments.
+ */
+ if (vpos >= 0)
+ count++;
+ }
+ } else {
+ /* Fallback to use value as is. */
+ count = amdgpu_display_vblank_get_counter(adev, pipe);
+ DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
+ }
+
+ return count;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
index b62c171..064ebb3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
@@ -407,6 +407,7 @@ struct amdgpu_crtc {
u32 line_time;
u32 wm_low;
u32 wm_high;
+ u32 lb_vblank_lead_lines;
struct drm_display_mode hw_mode;
};
@@ -528,6 +529,10 @@ struct amdgpu_framebuffer {
#define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
((em) == ATOM_ENCODER_MODE_DP_MST))
+/* Driver internal use only flags of amdgpu_get_crtc_scanoutpos() */
+#define USE_REAL_VBLANKSTART (1 << 30)
+#define GET_DISTANCE_TO_VBLANKSTART (1 << 31)
+
void amdgpu_link_encoder_connector(struct drm_device *dev);
struct drm_connector *
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
index 0d52438..c3ce103 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c
@@ -100,6 +100,7 @@ static void amdgpu_ttm_bo_destroy(struct ttm_buffer_object *tbo)
list_del_init(&bo->list);
mutex_unlock(&bo->adev->gem.mutex);
drm_gem_object_release(&bo->gem_base);
+ amdgpu_bo_unref(&bo->parent);
kfree(bo->metadata);
kfree(bo);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
index 3c2ff45..ea756e7 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h
@@ -189,10 +189,9 @@ int amdgpu_sa_bo_manager_start(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev,
struct amdgpu_sa_manager *sa_manager);
-int amdgpu_sa_bo_new(struct amdgpu_device *adev,
- struct amdgpu_sa_manager *sa_manager,
- struct amdgpu_sa_bo **sa_bo,
- unsigned size, unsigned align);
+int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
+ struct amdgpu_sa_bo **sa_bo,
+ unsigned size, unsigned align);
void amdgpu_sa_bo_free(struct amdgpu_device *adev,
struct amdgpu_sa_bo **sa_bo,
struct fence *fence);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
index 0212b31..8b88edb 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c
@@ -311,8 +311,7 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager,
return false;
}
-int amdgpu_sa_bo_new(struct amdgpu_device *adev,
- struct amdgpu_sa_manager *sa_manager,
+int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager,
struct amdgpu_sa_bo **sa_bo,
unsigned size, unsigned align)
{
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
index dcf4a8a..438c052 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c
@@ -26,6 +26,7 @@
#include <linux/sched.h>
#include <drm/drmP.h>
#include "amdgpu.h"
+#include "amdgpu_trace.h"
static struct fence *amdgpu_sched_dependency(struct amd_sched_job *sched_job)
{
@@ -44,11 +45,8 @@ static struct fence *amdgpu_sched_run_job(struct amd_sched_job *sched_job)
return NULL;
}
job = to_amdgpu_job(sched_job);
- mutex_lock(&job->job_lock);
- r = amdgpu_ib_schedule(job->adev,
- job->num_ibs,
- job->ibs,
- job->base.owner);
+ trace_amdgpu_sched_run_job(job);
+ r = amdgpu_ib_schedule(job->adev, job->num_ibs, job->ibs, job->owner);
if (r) {
DRM_ERROR("Error scheduling IBs (%d)\n", r);
goto err;
@@ -61,8 +59,6 @@ err:
if (job->free_job)
job->free_job(job);
- mutex_unlock(&job->job_lock);
- fence_put(&job->base.s_fence->base);
kfree(job);
return fence ? &fence->base : NULL;
}
@@ -88,21 +84,19 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev,
return -ENOMEM;
job->base.sched = &ring->sched;
job->base.s_entity = &adev->kernel_ctx.rings[ring->idx].entity;
+ job->base.s_fence = amd_sched_fence_create(job->base.s_entity, owner);
+ if (!job->base.s_fence) {
+ kfree(job);
+ return -ENOMEM;
+ }
+ *f = fence_get(&job->base.s_fence->base);
+
job->adev = adev;
job->ibs = ibs;
job->num_ibs = num_ibs;
- job->base.owner = owner;
- mutex_init(&job->job_lock);
+ job->owner = owner;
job->free_job = free_job;
- mutex_lock(&job->job_lock);
- r = amd_sched_entity_push_job(&job->base);
- if (r) {
- mutex_unlock(&job->job_lock);
- kfree(job);
- return r;
- }
- *f = fence_get(&job->base.s_fence->base);
- mutex_unlock(&job->job_lock);
+ amd_sched_entity_push_job(&job->base);
} else {
r = amdgpu_ib_schedule(adev, num_ibs, ibs, owner);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
index ff3ca52..1caaf20 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c
@@ -40,7 +40,7 @@ int amdgpu_semaphore_create(struct amdgpu_device *adev,
if (*semaphore == NULL) {
return -ENOMEM;
}
- r = amdgpu_sa_bo_new(adev, &adev->ring_tmp_bo,
+ r = amdgpu_sa_bo_new(&adev->ring_tmp_bo,
&(*semaphore)->sa_bo, 8, 8);
if (r) {
kfree(*semaphore);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
index a6697fd..dd005c3 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c
@@ -302,8 +302,14 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync,
return -EINVAL;
}
- if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores ||
- (count >= AMDGPU_NUM_SYNCS)) {
+ if (amdgpu_enable_scheduler || !amdgpu_enable_semaphores) {
+ r = fence_wait(&fence->base, true);
+ if (r)
+ return r;
+ continue;
+ }
+
+ if (count >= AMDGPU_NUM_SYNCS) {
/* not enough room, wait manually */
r = fence_wait(&fence->base, false);
if (r)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
index 76ecbaf..8f9834ab 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_trace.h
@@ -48,6 +48,57 @@ TRACE_EVENT(amdgpu_cs,
__entry->fences)
);
+TRACE_EVENT(amdgpu_cs_ioctl,
+ TP_PROTO(struct amdgpu_job *job),
+ TP_ARGS(job),
+ TP_STRUCT__entry(
+ __field(struct amdgpu_device *, adev)
+ __field(struct amd_sched_job *, sched_job)
+ __field(struct amdgpu_ib *, ib)
+ __field(struct fence *, fence)
+ __field(char *, ring_name)
+ __field(u32, num_ibs)
+ ),
+
+ TP_fast_assign(
+ __entry->adev = job->adev;
+ __entry->sched_job = &job->base;
+ __entry->ib = job->ibs;
+ __entry->fence = &job->base.s_fence->base;
+ __entry->ring_name = job->ibs[0].ring->name;
+ __entry->num_ibs = job->num_ibs;
+ ),
+ TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
+ __entry->adev, __entry->sched_job, __entry->ib,
+ __entry->fence, __entry->ring_name, __entry->num_ibs)
+);
+
+TRACE_EVENT(amdgpu_sched_run_job,
+ TP_PROTO(struct amdgpu_job *job),
+ TP_ARGS(job),
+ TP_STRUCT__entry(
+ __field(struct amdgpu_device *, adev)
+ __field(struct amd_sched_job *, sched_job)
+ __field(struct amdgpu_ib *, ib)
+ __field(struct fence *, fence)
+ __field(char *, ring_name)
+ __field(u32, num_ibs)
+ ),
+
+ TP_fast_assign(
+ __entry->adev = job->adev;
+ __entry->sched_job = &job->base;
+ __entry->ib = job->ibs;
+ __entry->fence = &job->base.s_fence->base;
+ __entry->ring_name = job->ibs[0].ring->name;
+ __entry->num_ibs = job->num_ibs;
+ ),
+ TP_printk("adev=%p, sched_job=%p, first ib=%p, sched fence=%p, ring name:%s, num_ibs:%u",
+ __entry->adev, __entry->sched_job, __entry->ib,
+ __entry->fence, __entry->ring_name, __entry->num_ibs)
+);
+
+
TRACE_EVENT(amdgpu_vm_grab_id,
TP_PROTO(unsigned vmid, int ring),
TP_ARGS(vmid, ring),
@@ -196,49 +247,6 @@ TRACE_EVENT(amdgpu_bo_list_set,
TP_printk("list=%p, bo=%p", __entry->list, __entry->bo)
);
-DECLARE_EVENT_CLASS(amdgpu_fence_request,
-
- TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
- TP_ARGS(dev, ring, seqno),
-
- TP_STRUCT__entry(
- __field(u32, dev)
- __field(int, ring)
- __field(u32, seqno)
- ),
-
- TP_fast_assign(
- __entry->dev = dev->primary->index;
- __entry->ring = ring;
- __entry->seqno = seqno;
- ),
-
- TP_printk("dev=%u, ring=%d, seqno=%u",
- __entry->dev, __entry->ring, __entry->seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_emit,
-
- TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
- TP_ARGS(dev, ring, seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_begin,
-
- TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
- TP_ARGS(dev, ring, seqno)
-);
-
-DEFINE_EVENT(amdgpu_fence_request, amdgpu_fence_wait_end,
-
- TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
-
- TP_ARGS(dev, ring, seqno)
-);
-
DECLARE_EVENT_CLASS(amdgpu_semaphore_request,
TP_PROTO(int ring, struct amdgpu_semaphore *sem),
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
index 81bb8e9..8a1752f 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
@@ -587,9 +587,13 @@ static int amdgpu_ttm_backend_bind(struct ttm_tt *ttm,
uint32_t flags = amdgpu_ttm_tt_pte_flags(gtt->adev, ttm, bo_mem);
int r;
- if (gtt->userptr)
- amdgpu_ttm_tt_pin_userptr(ttm);
-
+ if (gtt->userptr) {
+ r = amdgpu_ttm_tt_pin_userptr(ttm);
+ if (r) {
+ DRM_ERROR("failed to pin userptr\n");
+ return r;
+ }
+ }
gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
if (!ttm->num_pages) {
WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
@@ -797,11 +801,12 @@ uint32_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
if (mem && mem->mem_type != TTM_PL_SYSTEM)
flags |= AMDGPU_PTE_VALID;
- if (mem && mem->mem_type == TTM_PL_TT)
+ if (mem && mem->mem_type == TTM_PL_TT) {
flags |= AMDGPU_PTE_SYSTEM;
- if (!ttm || ttm->caching_state == tt_cached)
- flags |= AMDGPU_PTE_SNOOPED;
+ if (ttm->caching_state == tt_cached)
+ flags |= AMDGPU_PTE_SNOOPED;
+ }
if (adev->asic_type >= CHIP_TOPAZ)
flags |= AMDGPU_PTE_EXECUTABLE;
@@ -1073,10 +1078,10 @@ static int amdgpu_mm_dump_table(struct seq_file *m, void *data)
ret = drm_mm_dump_table(m, mm);
spin_unlock(&glob->lru_lock);
if (ttm_pl == TTM_PL_VRAM)
- seq_printf(m, "man size:%llu pages, ram usage:%luMB, vis usage:%luMB\n",
+ seq_printf(m, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n",
adev->mman.bdev.man[ttm_pl].size,
- atomic64_read(&adev->vram_usage) >> 20,
- atomic64_read(&adev->vram_vis_usage) >> 20);
+ (u64)atomic64_read(&adev->vram_usage) >> 20,
+ (u64)atomic64_read(&adev->vram_vis_usage) >> 20);
return ret;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
index 03f0c3b..a745eee 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c
@@ -392,7 +392,10 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
ib->ptr[ib->length_dw++] = 0x00000001; /* session cmd */
ib->ptr[ib->length_dw++] = handle;
- ib->ptr[ib->length_dw++] = 0x00000030; /* len */
+ if ((ring->adev->vce.fw_version >> 24) >= 52)
+ ib->ptr[ib->length_dw++] = 0x00000040; /* len */
+ else
+ ib->ptr[ib->length_dw++] = 0x00000030; /* len */
ib->ptr[ib->length_dw++] = 0x01000001; /* create cmd */
ib->ptr[ib->length_dw++] = 0x00000000;
ib->ptr[ib->length_dw++] = 0x00000042;
@@ -404,6 +407,12 @@ int amdgpu_vce_get_create_msg(struct amdgpu_ring *ring, uint32_t handle,
ib->ptr[ib->length_dw++] = 0x00000100;
ib->ptr[ib->length_dw++] = 0x0000000c;
ib->ptr[ib->length_dw++] = 0x00000000;
+ if ((ring->adev->vce.fw_version >> 24) >= 52) {
+ ib->ptr[ib->length_dw++] = 0x00000000;
+ ib->ptr[ib->length_dw++] = 0x00000000;
+ ib->ptr[ib->length_dw++] = 0x00000000;
+ ib->ptr[ib->length_dw++] = 0x00000000;
+ }
ib->ptr[ib->length_dw++] = 0x00000014; /* len */
ib->ptr[ib->length_dw++] = 0x05000005; /* feedback buffer */
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 633a32a..b53d273 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -143,10 +143,15 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
unsigned i;
/* check if the id is still valid */
- if (vm_id->id && vm_id->last_id_use &&
- vm_id->last_id_use == adev->vm_manager.active[vm_id->id]) {
- trace_amdgpu_vm_grab_id(vm_id->id, ring->idx);
- return 0;
+ if (vm_id->id) {
+ unsigned id = vm_id->id;
+ long owner;
+
+ owner = atomic_long_read(&adev->vm_manager.ids[id].owner);
+ if (owner == (long)vm) {
+ trace_amdgpu_vm_grab_id(vm_id->id, ring->idx);
+ return 0;
+ }
}
/* we definately need to flush */
@@ -154,7 +159,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
/* skip over VMID 0, since it is the system VM */
for (i = 1; i < adev->vm_manager.nvm; ++i) {
- struct fence *fence = adev->vm_manager.active[i];
+ struct fence *fence = adev->vm_manager.ids[i].active;
struct amdgpu_ring *fring;
if (fence == NULL) {
@@ -176,7 +181,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
if (choices[i]) {
struct fence *fence;
- fence = adev->vm_manager.active[choices[i]];
+ fence = adev->vm_manager.ids[choices[i]].active;
vm_id->id = choices[i];
trace_amdgpu_vm_grab_id(choices[i], ring->idx);
@@ -207,24 +212,21 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring,
uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory);
struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx];
struct fence *flushed_updates = vm_id->flushed_updates;
- bool is_earlier = false;
+ bool is_later;
- if (flushed_updates && updates) {
- BUG_ON(flushed_updates->context != updates->context);
- is_earlier = (updates->seqno - flushed_updates->seqno <=
- INT_MAX) ? true : false;
- }
-
- if (pd_addr != vm_id->pd_gpu_addr || !flushed_updates ||
- is_earlier) {
+ if (!flushed_updates)
+ is_later = true;
+ else if (!updates)
+ is_later = false;
+ else
+ is_later = fence_is_later(updates, flushed_updates);
+ if (pd_addr != vm_id->pd_gpu_addr || is_later) {
trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id);
- if (is_earlier) {
+ if (is_later) {
vm_id->flushed_updates = fence_get(updates);
fence_put(flushed_updates);
}
- if (!flushed_updates)
- vm_id->flushed_updates = fence_get(updates);
vm_id->pd_gpu_addr = pd_addr;
amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr);
}
@@ -244,16 +246,14 @@ void amdgpu_vm_flush(struct amdgpu_ring *ring,
*/
void amdgpu_vm_fence(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
- struct amdgpu_fence *fence)
+ struct fence *fence)
{
- unsigned ridx = fence->ring->idx;
- unsigned vm_id = vm->ids[ridx].id;
-
- fence_put(adev->vm_manager.active[vm_id]);
- adev->vm_manager.active[vm_id] = fence_get(&fence->base);
+ struct amdgpu_ring *ring = amdgpu_ring_from_fence(fence);
+ unsigned vm_id = vm->ids[ring->idx].id;
- fence_put(vm->ids[ridx].last_id_use);
- vm->ids[ridx].last_id_use = fence_get(&fence->base);
+ fence_put(adev->vm_manager.ids[vm_id].active);
+ adev->vm_manager.ids[vm_id].active = fence_get(fence);
+ atomic_long_set(&adev->vm_manager.ids[vm_id].owner, (long)vm);
}
/**
@@ -332,6 +332,8 @@ int amdgpu_vm_free_job(struct amdgpu_job *job)
*
* @adev: amdgpu_device pointer
* @bo: bo to clear
+ *
+ * need to reserve bo first before calling it.
*/
static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
struct amdgpu_bo *bo)
@@ -343,24 +345,20 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
uint64_t addr;
int r;
- r = amdgpu_bo_reserve(bo, false);
- if (r)
- return r;
-
r = reservation_object_reserve_shared(bo->tbo.resv);
if (r)
return r;
r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
if (r)
- goto error_unreserve;
+ goto error;
addr = amdgpu_bo_gpu_offset(bo);
entries = amdgpu_bo_size(bo) / 8;
ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL);
if (!ib)
- goto error_unreserve;
+ goto error;
r = amdgpu_ib_get(ring, NULL, entries * 2 + 64, ib);
if (r)
@@ -378,16 +376,14 @@ static int amdgpu_vm_clear_bo(struct amdgpu_device *adev,
if (!r)
amdgpu_bo_fence(bo, fence, true);
fence_put(fence);
- if (amdgpu_enable_scheduler) {
- amdgpu_bo_unreserve(bo);
+ if (amdgpu_enable_scheduler)
return 0;
- }
+
error_free:
amdgpu_ib_free(adev, ib);
kfree(ib);
-error_unreserve:
- amdgpu_bo_unreserve(bo);
+error:
return r;
}
@@ -889,17 +885,21 @@ int amdgpu_vm_clear_freed(struct amdgpu_device *adev,
struct amdgpu_bo_va_mapping *mapping;
int r;
+ spin_lock(&vm->freed_lock);
while (!list_empty(&vm->freed)) {
mapping = list_first_entry(&vm->freed,
struct amdgpu_bo_va_mapping, list);
list_del(&mapping->list);
-
+ spin_unlock(&vm->freed_lock);
r = amdgpu_vm_bo_update_mapping(adev, vm, mapping, 0, 0, NULL);
kfree(mapping);
if (r)
return r;
+ spin_lock(&vm->freed_lock);
}
+ spin_unlock(&vm->freed_lock);
+
return 0;
}
@@ -926,8 +926,9 @@ int amdgpu_vm_clear_invalids(struct amdgpu_device *adev,
bo_va = list_first_entry(&vm->invalidated,
struct amdgpu_bo_va, vm_status);
spin_unlock(&vm->status_lock);
-
+ mutex_lock(&bo_va->mutex);
r = amdgpu_vm_bo_update(adev, bo_va, NULL);
+ mutex_unlock(&bo_va->mutex);
if (r)
return r;
@@ -971,7 +972,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
INIT_LIST_HEAD(&bo_va->valids);
INIT_LIST_HEAD(&bo_va->invalids);
INIT_LIST_HEAD(&bo_va->vm_status);
-
+ mutex_init(&bo_va->mutex);
list_add_tail(&bo_va->bo_list, &bo->va);
return bo_va;
@@ -989,7 +990,7 @@ struct amdgpu_bo_va *amdgpu_vm_bo_add(struct amdgpu_device *adev,
* Add a mapping of the BO at the specefied addr into the VM.
* Returns 0 for success, error for failure.
*
- * Object has to be reserved and gets unreserved by this function!
+ * Object has to be reserved and unreserved outside!
*/
int amdgpu_vm_bo_map(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
@@ -1005,30 +1006,27 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
/* validate the parameters */
if (saddr & AMDGPU_GPU_PAGE_MASK || offset & AMDGPU_GPU_PAGE_MASK ||
- size == 0 || size & AMDGPU_GPU_PAGE_MASK) {
- amdgpu_bo_unreserve(bo_va->bo);
+ size == 0 || size & AMDGPU_GPU_PAGE_MASK)
return -EINVAL;
- }
/* make sure object fit at this offset */
eaddr = saddr + size;
- if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo))) {
- amdgpu_bo_unreserve(bo_va->bo);
+ if ((saddr >= eaddr) || (offset + size > amdgpu_bo_size(bo_va->bo)))
return -EINVAL;
- }
last_pfn = eaddr / AMDGPU_GPU_PAGE_SIZE;
if (last_pfn > adev->vm_manager.max_pfn) {
dev_err(adev->dev, "va above limit (0x%08X > 0x%08X)\n",
last_pfn, adev->vm_manager.max_pfn);
- amdgpu_bo_unreserve(bo_va->bo);
return -EINVAL;
}
saddr /= AMDGPU_GPU_PAGE_SIZE;
eaddr /= AMDGPU_GPU_PAGE_SIZE;
+ spin_lock(&vm->it_lock);
it = interval_tree_iter_first(&vm->va, saddr, eaddr - 1);
+ spin_unlock(&vm->it_lock);
if (it) {
struct amdgpu_bo_va_mapping *tmp;
tmp = container_of(it, struct amdgpu_bo_va_mapping, it);
@@ -1036,14 +1034,12 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
dev_err(adev->dev, "bo %p va 0x%010Lx-0x%010Lx conflict with "
"0x%010lx-0x%010lx\n", bo_va->bo, saddr, eaddr,
tmp->it.start, tmp->it.last + 1);
- amdgpu_bo_unreserve(bo_va->bo);
r = -EINVAL;
goto error;
}
mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
if (!mapping) {
- amdgpu_bo_unreserve(bo_va->bo);
r = -ENOMEM;
goto error;
}
@@ -1054,8 +1050,12 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
mapping->offset = offset;
mapping->flags = flags;
+ mutex_lock(&bo_va->mutex);
list_add(&mapping->list, &bo_va->invalids);
+ mutex_unlock(&bo_va->mutex);
+ spin_lock(&vm->it_lock);
interval_tree_insert(&mapping->it, &vm->va);
+ spin_unlock(&vm->it_lock);
trace_amdgpu_vm_bo_map(bo_va, mapping);
/* Make sure the page tables are allocated */
@@ -1067,8 +1067,6 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
if (eaddr > vm->max_pde_used)
vm->max_pde_used = eaddr;
- amdgpu_bo_unreserve(bo_va->bo);
-
/* walk over the address space and allocate the page tables */
for (pt_idx = saddr; pt_idx <= eaddr; ++pt_idx) {
struct reservation_object *resv = vm->page_directory->tbo.resv;
@@ -1077,16 +1075,19 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
if (vm->page_tables[pt_idx].bo)
continue;
- ww_mutex_lock(&resv->lock, NULL);
r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8,
AMDGPU_GPU_PAGE_SIZE, true,
AMDGPU_GEM_DOMAIN_VRAM,
AMDGPU_GEM_CREATE_NO_CPU_ACCESS,
NULL, resv, &pt);
- ww_mutex_unlock(&resv->lock);
if (r)
goto error_free;
+ /* Keep a reference to the page table to avoid freeing
+ * them up in the wrong order.
+ */
+ pt->parent = amdgpu_bo_ref(vm->page_directory);
+
r = amdgpu_vm_clear_bo(adev, pt);
if (r) {
amdgpu_bo_unref(&pt);
@@ -1101,7 +1102,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
error_free:
list_del(&mapping->list);
+ spin_lock(&vm->it_lock);
interval_tree_remove(&mapping->it, &vm->va);
+ spin_unlock(&vm->it_lock);
trace_amdgpu_vm_bo_unmap(bo_va, mapping);
kfree(mapping);
@@ -1119,7 +1122,7 @@ error:
* Remove a mapping of the BO at the specefied addr from the VM.
* Returns 0 for success, error for failure.
*
- * Object has to be reserved and gets unreserved by this function!
+ * Object has to be reserved and unreserved outside!
*/
int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va,
@@ -1130,7 +1133,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
bool valid = true;
saddr /= AMDGPU_GPU_PAGE_SIZE;
-
+ mutex_lock(&bo_va->mutex);
list_for_each_entry(mapping, &bo_va->valids, list) {
if (mapping->it.start == saddr)
break;
@@ -1145,20 +1148,24 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
}
if (&mapping->list == &bo_va->invalids) {
- amdgpu_bo_unreserve(bo_va->bo);
+ mutex_unlock(&bo_va->mutex);
return -ENOENT;
}
}
-
+ mutex_unlock(&bo_va->mutex);
list_del(&mapping->list);
+ spin_lock(&vm->it_lock);
interval_tree_remove(&mapping->it, &vm->va);
+ spin_unlock(&vm->it_lock);
trace_amdgpu_vm_bo_unmap(bo_va, mapping);
- if (valid)
+ if (valid) {
+ spin_lock(&vm->freed_lock);
list_add(&mapping->list, &vm->freed);
- else
+ spin_unlock(&vm->freed_lock);
+ } else {
kfree(mapping);
- amdgpu_bo_unreserve(bo_va->bo);
+ }
return 0;
}
@@ -1187,17 +1194,23 @@ void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
list_for_each_entry_safe(mapping, next, &bo_va->valids, list) {
list_del(&mapping->list);
+ spin_lock(&vm->it_lock);
interval_tree_remove(&mapping->it, &vm->va);
+ spin_unlock(&vm->it_lock);
trace_amdgpu_vm_bo_unmap(bo_va, mapping);
+ spin_lock(&vm->freed_lock);
list_add(&mapping->list, &vm->freed);
+ spin_unlock(&vm->freed_lock);
}
list_for_each_entry_safe(mapping, next, &bo_va->invalids, list) {
list_del(&mapping->list);
+ spin_lock(&vm->it_lock);
interval_tree_remove(&mapping->it, &vm->va);
+ spin_unlock(&vm->it_lock);
kfree(mapping);
}
-
fence_put(bo_va->last_pt_update);
+ mutex_destroy(&bo_va->mutex);
kfree(bo_va);
}
@@ -1241,15 +1254,14 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
vm->ids[i].id = 0;
vm->ids[i].flushed_updates = NULL;
- vm->ids[i].last_id_use = NULL;
}
- mutex_init(&vm->mutex);
vm->va = RB_ROOT;
spin_lock_init(&vm->status_lock);
INIT_LIST_HEAD(&vm->invalidated);
INIT_LIST_HEAD(&vm->cleared);
INIT_LIST_HEAD(&vm->freed);
-
+ spin_lock_init(&vm->it_lock);
+ spin_lock_init(&vm->freed_lock);
pd_size = amdgpu_vm_directory_size(adev);
pd_entries = amdgpu_vm_num_pdes(adev);
@@ -1269,8 +1281,14 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
NULL, NULL, &vm->page_directory);
if (r)
return r;
-
+ r = amdgpu_bo_reserve(vm->page_directory, false);
+ if (r) {
+ amdgpu_bo_unref(&vm->page_directory);
+ vm->page_directory = NULL;
+ return r;
+ }
r = amdgpu_vm_clear_bo(adev, vm->page_directory);
+ amdgpu_bo_unreserve(vm->page_directory);
if (r) {
amdgpu_bo_unref(&vm->page_directory);
vm->page_directory = NULL;
@@ -1313,11 +1331,27 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
amdgpu_bo_unref(&vm->page_directory);
fence_put(vm->page_directory_fence);
-
for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
+ unsigned id = vm->ids[i].id;
+
+ atomic_long_cmpxchg(&adev->vm_manager.ids[id].owner,
+ (long)vm, 0);
fence_put(vm->ids[i].flushed_updates);
- fence_put(vm->ids[i].last_id_use);
}
- mutex_destroy(&vm->mutex);
+}
+
+/**
+ * amdgpu_vm_manager_fini - cleanup VM manager
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Cleanup the VM manager and free resources.
+ */
+void amdgpu_vm_manager_fini(struct amdgpu_device *adev)
+{
+ unsigned i;
+
+ for (i = 0; i < AMDGPU_NUM_VM; ++i)
+ fence_put(adev->vm_manager.ids[i].active);
}
diff --git a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
index a1a35a5..57a2e34 100644
--- a/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
+++ b/drivers/gpu/drm/amd/amdgpu/ci_dpm.c
@@ -6569,12 +6569,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
break;
case AMDGPU_IRQ_STATE_ENABLE:
cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTH_MASK_MASK;
WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
break;
default:
@@ -6586,12 +6586,12 @@ static int ci_dpm_set_interrupt_state(struct amdgpu_device *adev,
switch (state) {
case AMDGPU_IRQ_STATE_DISABLE:
cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
break;
case AMDGPU_IRQ_STATE_ENABLE:
cg_thermal_int = RREG32_SMC(ixCG_THERMAL_INT);
- cg_thermal_int |= CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
+ cg_thermal_int &= ~CG_THERMAL_INT_CTRL__THERM_INTL_MASK_MASK;
WREG32_SMC(ixCG_THERMAL_INT, cg_thermal_int);
break;
default:
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
index cb0f774..4dcc8fb 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c
@@ -1250,7 +1250,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
u32 pixel_period;
u32 line_time = 0;
u32 latency_watermark_a = 0, latency_watermark_b = 0;
- u32 tmp, wm_mask;
+ u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
if (amdgpu_crtc->base.enabled && num_heads && mode) {
pixel_period = 1000000 / (u32)mode->clock;
@@ -1333,6 +1333,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
(adev->mode_info.disp_priority == 2)) {
DRM_DEBUG_KMS("force priority to high\n");
}
+ lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
@@ -1357,6 +1358,8 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev,
amdgpu_crtc->line_time = line_time;
amdgpu_crtc->wm_high = latency_watermark_a;
amdgpu_crtc->wm_low = latency_watermark_b;
+ /* Save number of lines the linebuffer leads before the scanout */
+ amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
index 5af3721..8f1e511 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c
@@ -1238,7 +1238,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
u32 pixel_period;
u32 line_time = 0;
u32 latency_watermark_a = 0, latency_watermark_b = 0;
- u32 tmp, wm_mask;
+ u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
if (amdgpu_crtc->base.enabled && num_heads && mode) {
pixel_period = 1000000 / (u32)mode->clock;
@@ -1321,6 +1321,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
(adev->mode_info.disp_priority == 2)) {
DRM_DEBUG_KMS("force priority to high\n");
}
+ lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
@@ -1345,6 +1346,8 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev,
amdgpu_crtc->line_time = line_time;
amdgpu_crtc->wm_high = latency_watermark_a;
amdgpu_crtc->wm_low = latency_watermark_b;
+ /* Save number of lines the linebuffer leads before the scanout */
+ amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
index 4f7b49a..42d954d 100644
--- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c
@@ -1193,7 +1193,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
u32 pixel_period;
u32 line_time = 0;
u32 latency_watermark_a = 0, latency_watermark_b = 0;
- u32 tmp, wm_mask;
+ u32 tmp, wm_mask, lb_vblank_lead_lines = 0;
if (amdgpu_crtc->base.enabled && num_heads && mode) {
pixel_period = 1000000 / (u32)mode->clock;
@@ -1276,6 +1276,7 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
(adev->mode_info.disp_priority == 2)) {
DRM_DEBUG_KMS("force priority to high\n");
}
+ lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
@@ -1302,6 +1303,8 @@ static void dce_v8_0_program_watermarks(struct amdgpu_device *adev,
amdgpu_crtc->line_time = line_time;
amdgpu_crtc->wm_high = latency_watermark_a;
amdgpu_crtc->wm_low = latency_watermark_b;
+ /* Save number of lines the linebuffer leads before the scanout */
+ amdgpu_crtc->lb_vblank_lead_lines = lb_vblank_lead_lines;
}
/**
diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
index 6776cf7..e1dcab9 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c
@@ -268,7 +268,6 @@ static const u32 fiji_mgcg_cgcg_init[] =
mmCGTT_CP_CLK_CTRL, 0xffffffff, 0x00000100,
mmCGTT_CPC_CLK_CTRL, 0xffffffff, 0x00000100,
mmCGTT_CPF_CLK_CTRL, 0xffffffff, 0x40000100,
- mmCGTT_DRM_CLK_CTRL0, 0xffffffff, 0x00600100,
mmCGTT_GDS_CLK_CTRL, 0xffffffff, 0x00000100,
mmCGTT_IA_CLK_CTRL, 0xffffffff, 0x06000100,
mmCGTT_PA_CLK_CTRL, 0xffffffff, 0x00000100,
@@ -296,10 +295,6 @@ static const u32 fiji_mgcg_cgcg_init[] =
mmCGTS_SM_CTRL_REG, 0xffffffff, 0x96e00200,
mmCP_RB_WPTR_POLL_CNTL, 0xffffffff, 0x00900100,
mmRLC_CGCG_CGLS_CTRL, 0xffffffff, 0x0020003c,
- mmPCIE_INDEX, 0xffffffff, 0x0140001c,
- mmPCIE_DATA, 0x000f0000, 0x00000000,
- mmCGTT_DRM_CLK_CTRL0, 0xff000fff, 0x00000100,
- mmHDP_XDP_CGTT_BLK_CTRL, 0xc0000fff, 0x00000104,
mmCP_MEM_SLP_CNTL, 0x00000001, 0x00000001,
};
@@ -1000,7 +995,7 @@ static void gfx_v8_0_gpu_early_init(struct amdgpu_device *adev)
adev->gfx.config.max_cu_per_sh = 16;
adev->gfx.config.max_sh_per_se = 1;
adev->gfx.config.max_backends_per_se = 4;
- adev->gfx.config.max_texture_channel_caches = 8;
+ adev->gfx.config.max_texture_channel_caches = 16;
adev->gfx.config.max_gprs = 256;
adev->gfx.config.max_gs_threads = 32;
adev->gfx.config.max_hw_contexts = 8;
@@ -1613,6 +1608,296 @@ static void gfx_v8_0_tiling_mode_table_init(struct amdgpu_device *adev)
WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
}
case CHIP_FIJI:
+ for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 1:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 2:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 3:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 4:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 5:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 6:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 7:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
+ break;
+ case 8:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16));
+ break;
+ case 9:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 10:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 11:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ case 12:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ case 13:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 14:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 15:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 16:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ case 17:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ case 18:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 19:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 20:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 21:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 22:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 23:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 24:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 25:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 26:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_3D_TILED_XTHICK) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_THICK_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_1));
+ break;
+ case 27:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 28:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_2));
+ break;
+ case 29:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ case 30:
+ gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_TILED_THIN1) |
+ PIPE_CONFIG(ADDR_SURF_P4_16x16) |
+ MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+ SAMPLE_SPLIT(ADDR_SURF_SAMPLE_SPLIT_8));
+ break;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden);
+ }
+ for (reg_offset = 0; reg_offset < num_secondary_tile_mode_states; reg_offset++) {
+ switch (reg_offset) {
+ case 0:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 1:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 2:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 3:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 4:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 5:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 6:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 8:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 9:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 10:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 11:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 12:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 13:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) |
+ NUM_BANKS(ADDR_SURF_8_BANK));
+ break;
+ case 14:
+ gb_tile_moden = (BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) |
+ BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) |
+ MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) |
+ NUM_BANKS(ADDR_SURF_4_BANK));
+ break;
+ case 7:
+ /* unused idx */
+ continue;
+ default:
+ gb_tile_moden = 0;
+ break;
+ }
+ adev->gfx.config.macrotile_mode_array[reg_offset] = gb_tile_moden;
+ WREG32(mmGB_MACROTILE_MODE0 + reg_offset, gb_tile_moden);
+ }
+ break;
case CHIP_TONGA:
for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) {
switch (reg_offset) {
@@ -2971,10 +3256,13 @@ static int gfx_v8_0_cp_gfx_start(struct amdgpu_device *adev)
amdgpu_ring_write(ring, mmPA_SC_RASTER_CONFIG - PACKET3_SET_CONTEXT_REG_START);
switch (adev->asic_type) {
case CHIP_TONGA:
- case CHIP_FIJI:
amdgpu_ring_write(ring, 0x16000012);
amdgpu_ring_write(ring, 0x0000002A);
break;
+ case CHIP_FIJI:
+ amdgpu_ring_write(ring, 0x3a00161a);
+ amdgpu_ring_write(ring, 0x0000002e);
+ break;
case CHIP_TOPAZ:
case CHIP_CARRIZO:
amdgpu_ring_write(ring, 0x00000002);
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
index 85bbcdc..ed8abb5 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c
@@ -40,7 +40,7 @@
static void gmc_v7_0_set_gart_funcs(struct amdgpu_device *adev);
static void gmc_v7_0_set_irq_funcs(struct amdgpu_device *adev);
-MODULE_FIRMWARE("radeon/boniare_mc.bin");
+MODULE_FIRMWARE("radeon/bonaire_mc.bin");
MODULE_FIRMWARE("radeon/hawaii_mc.bin");
/**
@@ -501,6 +501,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1);
+ tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1);
WREG32(mmVM_L2_CNTL, tmp);
tmp = REG_SET_FIELD(0, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_L2_CACHE, 1);
@@ -512,7 +513,7 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev)
WREG32(mmVM_L2_CNTL3, tmp);
/* setup context0 */
WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12);
- WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1);
+ WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12);
WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12);
WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
(u32)(adev->dummy_page.addr >> 12));
@@ -960,12 +961,10 @@ static int gmc_v7_0_sw_init(void *handle)
static int gmc_v7_0_sw_fini(void *handle)
{
- int i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- for (i = 0; i < AMDGPU_NUM_VM; ++i)
- fence_put(adev->vm_manager.active[i]);
+ amdgpu_vm_manager_fini(adev);
gmc_v7_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
@@ -1010,12 +1009,10 @@ static int gmc_v7_0_hw_fini(void *handle)
static int gmc_v7_0_suspend(void *handle)
{
- int i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- for (i = 0; i < AMDGPU_NUM_VM; ++i)
- fence_put(adev->vm_manager.active[i]);
+ amdgpu_vm_manager_fini(adev);
gmc_v7_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
index 1bcc4e7..d390284 100644
--- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c
@@ -629,6 +629,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_L2_PDE0_CACHE_LRU_UPDATE_BY_WRITE, 1);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, EFFECTIVE_L2_QUEUE_SIZE, 7);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, CONTEXT1_IDENTITY_ACCESS_MODE, 1);
+ tmp = REG_SET_FIELD(tmp, VM_L2_CNTL, ENABLE_DEFAULT_PAGE_OUT_TO_SYSTEM_MEMORY, 1);
WREG32(mmVM_L2_CNTL, tmp);
tmp = RREG32(mmVM_L2_CNTL2);
tmp = REG_SET_FIELD(tmp, VM_L2_CNTL2, INVALIDATE_ALL_L1_TLBS, 1);
@@ -656,7 +657,7 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev)
WREG32(mmVM_L2_CNTL4, tmp);
/* setup context0 */
WREG32(mmVM_CONTEXT0_PAGE_TABLE_START_ADDR, adev->mc.gtt_start >> 12);
- WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, (adev->mc.gtt_end >> 12) - 1);
+ WREG32(mmVM_CONTEXT0_PAGE_TABLE_END_ADDR, adev->mc.gtt_end >> 12);
WREG32(mmVM_CONTEXT0_PAGE_TABLE_BASE_ADDR, adev->gart.table_addr >> 12);
WREG32(mmVM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR,
(u32)(adev->dummy_page.addr >> 12));
@@ -979,12 +980,10 @@ static int gmc_v8_0_sw_init(void *handle)
static int gmc_v8_0_sw_fini(void *handle)
{
- int i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- for (i = 0; i < AMDGPU_NUM_VM; ++i)
- fence_put(adev->vm_manager.active[i]);
+ amdgpu_vm_manager_fini(adev);
gmc_v8_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
@@ -1031,12 +1030,10 @@ static int gmc_v8_0_hw_fini(void *handle)
static int gmc_v8_0_suspend(void *handle)
{
- int i;
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
if (adev->vm_manager.enabled) {
- for (i = 0; i < AMDGPU_NUM_VM; ++i)
- fence_put(adev->vm_manager.active[i]);
+ amdgpu_vm_manager_fini(adev);
gmc_v8_0_vm_fini(adev);
adev->vm_manager.enabled = false;
}
diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
index 6a52db6..370c6c9 100644
--- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c
@@ -40,6 +40,9 @@
#define GRBM_GFX_INDEX__VCE_INSTANCE__SHIFT 0x04
#define GRBM_GFX_INDEX__VCE_INSTANCE_MASK 0x10
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR0 0x8616
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR1 0x8617
+#define mmVCE_LMI_VCPU_CACHE_40BIT_BAR2 0x8618
#define VCE_V3_0_FW_SIZE (384 * 1024)
#define VCE_V3_0_STACK_SIZE (64 * 1024)
@@ -130,9 +133,11 @@ static int vce_v3_0_start(struct amdgpu_device *adev)
/* set BUSY flag */
WREG32_P(mmVCE_STATUS, 1, ~1);
-
- WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
- ~VCE_VCPU_CNTL__CLK_EN_MASK);
+ if (adev->asic_type >= CHIP_STONEY)
+ WREG32_P(mmVCE_VCPU_CNTL, 1, ~0x200001);
+ else
+ WREG32_P(mmVCE_VCPU_CNTL, VCE_VCPU_CNTL__CLK_EN_MASK,
+ ~VCE_VCPU_CNTL__CLK_EN_MASK);
WREG32_P(mmVCE_SOFT_RESET,
VCE_SOFT_RESET__ECPU_SOFT_RESET_MASK,
@@ -391,8 +396,12 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx)
WREG32(mmVCE_LMI_SWAP_CNTL, 0);
WREG32(mmVCE_LMI_SWAP_CNTL1, 0);
WREG32(mmVCE_LMI_VM_CTRL, 0);
-
- WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
+ if (adev->asic_type >= CHIP_STONEY) {
+ WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR0, (adev->vce.gpu_addr >> 8));
+ WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR1, (adev->vce.gpu_addr >> 8));
+ WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR2, (adev->vce.gpu_addr >> 8));
+ } else
+ WREG32(mmVCE_LMI_VCPU_CACHE_40BIT_BAR, (adev->vce.gpu_addr >> 8));
offset = AMDGPU_VCE_FIRMWARE_OFFSET;
size = VCE_V3_0_FW_SIZE;
WREG32(mmVCE_VCPU_CACHE_OFFSET0, offset & 0x7fffffff);
@@ -576,6 +585,11 @@ static int vce_v3_0_process_interrupt(struct amdgpu_device *adev,
struct amdgpu_iv_entry *entry)
{
DRM_DEBUG("IH: VCE\n");
+
+ WREG32_P(mmVCE_SYS_INT_STATUS,
+ VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK,
+ ~VCE_SYS_INT_STATUS__VCE_SYS_INT_TRAP_INTERRUPT_INT_MASK);
+
switch (entry->src_data) {
case 0:
amdgpu_fence_process(&adev->vce.ring[0]);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index c6a1b4c..d321222 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -559,19 +559,10 @@ static int kfd_ioctl_dbg_address_watch(struct file *filep,
/* this is the actual buffer to work with */
- args_buff = kmalloc(args->buf_size_in_bytes -
- sizeof(*args), GFP_KERNEL);
- if (args_buff == NULL)
- return -ENOMEM;
-
- status = copy_from_user(args_buff, cmd_from_user,
+ args_buff = memdup_user(args_buff,
args->buf_size_in_bytes - sizeof(*args));
-
- if (status != 0) {
- pr_debug("Failed to copy address watch user data\n");
- kfree(args_buff);
- return -EINVAL;
- }
+ if (IS_ERR(args_buff))
+ return PTR_ERR(args_buff);
aw_info.process = p;
@@ -677,22 +668,12 @@ static int kfd_ioctl_dbg_wave_control(struct file *filep,
if (cmd_from_user == NULL)
return -EINVAL;
- /* this is the actual buffer to work with */
+ /* copy the entire buffer from user */
- args_buff = kmalloc(args->buf_size_in_bytes - sizeof(*args),
- GFP_KERNEL);
-
- if (args_buff == NULL)
- return -ENOMEM;
-
- /* Now copy the entire buffer from user */
- status = copy_from_user(args_buff, cmd_from_user,
+ args_buff = memdup_user(cmd_from_user,
args->buf_size_in_bytes - sizeof(*args));
- if (status != 0) {
- pr_debug("Failed to copy wave control user data\n");
- kfree(args_buff);
- return -EINVAL;
- }
+ if (IS_ERR(args_buff))
+ return PTR_ERR(args_buff);
/* move ptr to the start of the "pay-load" area */
wac_info.process = p;
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
index 144f50a..c89dc77 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_sched_trace.h
@@ -16,6 +16,8 @@ TRACE_EVENT(amd_sched_job,
TP_ARGS(sched_job),
TP_STRUCT__entry(
__field(struct amd_sched_entity *, entity)
+ __field(struct amd_sched_job *, sched_job)
+ __field(struct fence *, fence)
__field(const char *, name)
__field(u32, job_count)
__field(int, hw_job_count)
@@ -23,16 +25,32 @@ TRACE_EVENT(amd_sched_job,
TP_fast_assign(
__entry->entity = sched_job->s_entity;
+ __entry->sched_job = sched_job;
+ __entry->fence = &sched_job->s_fence->base;
__entry->name = sched_job->sched->name;
__entry->job_count = kfifo_len(
&sched_job->s_entity->job_queue) / sizeof(sched_job);
__entry->hw_job_count = atomic_read(
&sched_job->sched->hw_rq_count);
),
- TP_printk("entity=%p, ring=%s, job count:%u, hw job count:%d",
- __entry->entity, __entry->name, __entry->job_count,
- __entry->hw_job_count)
+ TP_printk("entity=%p, sched job=%p, fence=%p, ring=%s, job count:%u, hw job count:%d",
+ __entry->entity, __entry->sched_job, __entry->fence, __entry->name,
+ __entry->job_count, __entry->hw_job_count)
);
+
+TRACE_EVENT(amd_sched_process_job,
+ TP_PROTO(struct amd_sched_fence *fence),
+ TP_ARGS(fence),
+ TP_STRUCT__entry(
+ __field(struct fence *, fence)
+ ),
+
+ TP_fast_assign(
+ __entry->fence = &fence->base;
+ ),
+ TP_printk("fence=%p signaled", __entry->fence)
+);
+
#endif
/* This part must be outside protection */
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
index 89619a5..3a4820e 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c
@@ -30,10 +30,12 @@
#define CREATE_TRACE_POINTS
#include "gpu_sched_trace.h"
-static struct amd_sched_job *
-amd_sched_entity_pop_job(struct amd_sched_entity *entity);
+static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity);
static void amd_sched_wakeup(struct amd_gpu_scheduler *sched);
+struct kmem_cache *sched_fence_slab;
+atomic_t sched_fence_slab_ref = ATOMIC_INIT(0);
+
/* Initialize a given run queue struct */
static void amd_sched_rq_init(struct amd_sched_rq *rq)
{
@@ -61,36 +63,36 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq,
}
/**
- * Select next job from a specified run queue with round robin policy.
- * Return NULL if nothing available.
+ * Select an entity which could provide a job to run
+ *
+ * @rq The run queue to check.
+ *
+ * Try to find a ready entity, returns NULL if none found.
*/
-static struct amd_sched_job *
-amd_sched_rq_select_job(struct amd_sched_rq *rq)
+static struct amd_sched_entity *
+amd_sched_rq_select_entity(struct amd_sched_rq *rq)
{
struct amd_sched_entity *entity;
- struct amd_sched_job *sched_job;
spin_lock(&rq->lock);
entity = rq->current_entity;
if (entity) {
list_for_each_entry_continue(entity, &rq->entities, list) {
- sched_job = amd_sched_entity_pop_job(entity);
- if (sched_job) {
+ if (amd_sched_entity_is_ready(entity)) {
rq->current_entity = entity;
spin_unlock(&rq->lock);
- return sched_job;
+ return entity;
}
}
}
list_for_each_entry(entity, &rq->entities, list) {
- sched_job = amd_sched_entity_pop_job(entity);
- if (sched_job) {
+ if (amd_sched_entity_is_ready(entity)) {
rq->current_entity = entity;
spin_unlock(&rq->lock);
- return sched_job;
+ return entity;
}
if (entity == rq->current_entity)
@@ -174,6 +176,24 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity)
}
/**
+ * Check if entity is ready
+ *
+ * @entity The pointer to a valid scheduler entity
+ *
+ * Return true if entity could provide a job.
+ */
+static bool amd_sched_entity_is_ready(struct amd_sched_entity *entity)
+{
+ if (kfifo_is_empty(&entity->job_queue))
+ return false;
+
+ if (ACCESS_ONCE(entity->dependency))
+ return false;
+
+ return true;
+}
+
+/**
* Destroy a context entity
*
* @sched Pointer to scheduler instance
@@ -208,32 +228,53 @@ static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb)
amd_sched_wakeup(entity->sched);
}
+static bool amd_sched_entity_add_dependency_cb(struct amd_sched_entity *entity)
+{
+ struct amd_gpu_scheduler *sched = entity->sched;
+ struct fence * fence = entity->dependency;
+ struct amd_sched_fence *s_fence;
+
+ if (fence->context == entity->fence_context) {
+ /* We can ignore fences from ourself */
+ fence_put(entity->dependency);
+ return false;
+ }
+
+ s_fence = to_amd_sched_fence(fence);
+ if (s_fence && s_fence->sched == sched) {
+ /* Fence is from the same scheduler */
+ if (test_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &fence->flags)) {
+ /* Ignore it when it is already scheduled */
+ fence_put(entity->dependency);
+ return false;
+ }
+
+ /* Wait for fence to be scheduled */
+ entity->cb.func = amd_sched_entity_wakeup;
+ list_add_tail(&entity->cb.node, &s_fence->scheduled_cb);
+ return true;
+ }
+
+ if (!fence_add_callback(entity->dependency, &entity->cb,
+ amd_sched_entity_wakeup))
+ return true;
+
+ fence_put(entity->dependency);
+ return false;
+}
+
static struct amd_sched_job *
amd_sched_entity_pop_job(struct amd_sched_entity *entity)
{
struct amd_gpu_scheduler *sched = entity->sched;
struct amd_sched_job *sched_job;
- if (ACCESS_ONCE(entity->dependency))
- return NULL;
-
if (!kfifo_out_peek(&entity->job_queue, &sched_job, sizeof(sched_job)))
return NULL;
- while ((entity->dependency = sched->ops->dependency(sched_job))) {
-
- if (entity->dependency->context == entity->fence_context) {
- /* We can ignore fences from ourself */
- fence_put(entity->dependency);
- continue;
- }
-
- if (fence_add_callback(entity->dependency, &entity->cb,
- amd_sched_entity_wakeup))
- fence_put(entity->dependency);
- else
+ while ((entity->dependency = sched->ops->dependency(sched_job)))
+ if (amd_sched_entity_add_dependency_cb(entity))
return NULL;
- }
return sched_job;
}
@@ -247,6 +288,7 @@ amd_sched_entity_pop_job(struct amd_sched_entity *entity)
*/
static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
{
+ struct amd_gpu_scheduler *sched = sched_job->sched;
struct amd_sched_entity *entity = sched_job->s_entity;
bool added, first = false;
@@ -261,7 +303,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
/* first job wakes up scheduler */
if (first)
- amd_sched_wakeup(sched_job->sched);
+ amd_sched_wakeup(sched);
return added;
}
@@ -273,22 +315,13 @@ static bool amd_sched_entity_in(struct amd_sched_job *sched_job)
*
* Returns 0 for success, negative error code otherwise.
*/
-int amd_sched_entity_push_job(struct amd_sched_job *sched_job)
+void amd_sched_entity_push_job(struct amd_sched_job *sched_job)
{
struct amd_sched_entity *entity = sched_job->s_entity;
- struct amd_sched_fence *fence = amd_sched_fence_create(
- entity, sched_job->owner);
-
- if (!fence)
- return -ENOMEM;
-
- fence_get(&fence->base);
- sched_job->s_fence = fence;
+ trace_amd_sched_job(sched_job);
wait_event(entity->sched->job_scheduled,
amd_sched_entity_in(sched_job));
- trace_amd_sched_job(sched_job);
- return 0;
}
/**
@@ -310,22 +343,22 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched)
}
/**
- * Select next to run
+ * Select next entity to process
*/
-static struct amd_sched_job *
-amd_sched_select_job(struct amd_gpu_scheduler *sched)
+static struct amd_sched_entity *
+amd_sched_select_entity(struct amd_gpu_scheduler *sched)
{
- struct amd_sched_job *sched_job;
+ struct amd_sched_entity *entity;
if (!amd_sched_ready(sched))
return NULL;
/* Kernel run queue has higher priority than normal run queue*/
- sched_job = amd_sched_rq_select_job(&sched->kernel_rq);
- if (sched_job == NULL)
- sched_job = amd_sched_rq_select_job(&sched->sched_rq);
+ entity = amd_sched_rq_select_entity(&sched->kernel_rq);
+ if (entity == NULL)
+ entity = amd_sched_rq_select_entity(&sched->sched_rq);
- return sched_job;
+ return entity;
}
static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
@@ -343,6 +376,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb)
list_del_init(&s_fence->list);
spin_unlock_irqrestore(&sched->fence_list_lock, flags);
}
+ trace_amd_sched_process_job(s_fence);
fence_put(&s_fence->base);
wake_up_interruptible(&sched->wake_up_worker);
}
@@ -386,13 +420,16 @@ static int amd_sched_main(void *param)
unsigned long flags;
wait_event_interruptible(sched->wake_up_worker,
- kthread_should_stop() ||
- (sched_job = amd_sched_select_job(sched)));
+ (entity = amd_sched_select_entity(sched)) ||
+ kthread_should_stop());
+ if (!entity)
+ continue;
+
+ sched_job = amd_sched_entity_pop_job(entity);
if (!sched_job)
continue;
- entity = sched_job->s_entity;
s_fence = sched_job->s_fence;
if (sched->timeout != MAX_SCHEDULE_TIMEOUT) {
@@ -405,6 +442,7 @@ static int amd_sched_main(void *param)
atomic_inc(&sched->hw_rq_count);
fence = sched->ops->run_job(sched_job);
+ amd_sched_fence_scheduled(s_fence);
if (fence) {
r = fence_add_callback(fence, &s_fence->cb,
amd_sched_process_job);
@@ -450,6 +488,13 @@ int amd_sched_init(struct amd_gpu_scheduler *sched,
init_waitqueue_head(&sched->wake_up_worker);
init_waitqueue_head(&sched->job_scheduled);
atomic_set(&sched->hw_rq_count, 0);
+ if (atomic_inc_return(&sched_fence_slab_ref) == 1) {
+ sched_fence_slab = kmem_cache_create(
+ "amd_sched_fence", sizeof(struct amd_sched_fence), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!sched_fence_slab)
+ return -ENOMEM;
+ }
/* Each scheduler will run on a seperate kernel thread */
sched->thread = kthread_run(amd_sched_main, sched, sched->name);
@@ -470,4 +515,6 @@ void amd_sched_fini(struct amd_gpu_scheduler *sched)
{
if (sched->thread)
kthread_stop(sched->thread);
+ if (atomic_dec_and_test(&sched_fence_slab_ref))
+ kmem_cache_destroy(sched_fence_slab);
}
diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
index 929e9ac..a0f0ae5 100644
--- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
+++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h
@@ -27,9 +27,14 @@
#include <linux/kfifo.h>
#include <linux/fence.h>
+#define AMD_SCHED_FENCE_SCHEDULED_BIT FENCE_FLAG_USER_BITS
+
struct amd_gpu_scheduler;
struct amd_sched_rq;
+extern struct kmem_cache *sched_fence_slab;
+extern atomic_t sched_fence_slab_ref;
+
/**
* A scheduler entity is a wrapper around a job queue or a group
* of other entities. Entities take turns emitting jobs from their
@@ -65,6 +70,7 @@ struct amd_sched_rq {
struct amd_sched_fence {
struct fence base;
struct fence_cb cb;
+ struct list_head scheduled_cb;
struct amd_gpu_scheduler *sched;
spinlock_t lock;
void *owner;
@@ -76,7 +82,6 @@ struct amd_sched_job {
struct amd_gpu_scheduler *sched;
struct amd_sched_entity *s_entity;
struct amd_sched_fence *s_fence;
- void *owner;
};
extern const struct fence_ops amd_sched_fence_ops;
@@ -128,11 +133,11 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched,
uint32_t jobs);
void amd_sched_entity_fini(struct amd_gpu_scheduler *sched,
struct amd_sched_entity *entity);
-int amd_sched_entity_push_job(struct amd_sched_job *sched_job);
+void amd_sched_entity_push_job(struct amd_sched_job *sched_job);
struct amd_sched_fence *amd_sched_fence_create(
struct amd_sched_entity *s_entity, void *owner);
+void amd_sched_fence_scheduled(struct amd_sched_fence *fence);
void amd_sched_fence_signal(struct amd_sched_fence *fence);
-
#endif
diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c
index d802638..87c78ee 100644
--- a/drivers/gpu/drm/amd/scheduler/sched_fence.c
+++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c
@@ -32,9 +32,11 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity
struct amd_sched_fence *fence = NULL;
unsigned seq;
- fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL);
+ fence = kmem_cache_zalloc(sched_fence_slab, GFP_KERNEL);
if (fence == NULL)
return NULL;
+
+ INIT_LIST_HEAD(&fence->scheduled_cb);
fence->owner = owner;
fence->sched = s_entity->sched;
spin_lock_init(&fence->lock);
@@ -55,6 +57,17 @@ void amd_sched_fence_signal(struct amd_sched_fence *fence)
FENCE_TRACE(&fence->base, "was already signaled\n");
}
+void amd_sched_fence_scheduled(struct amd_sched_fence *s_fence)
+{
+ struct fence_cb *cur, *tmp;
+
+ set_bit(AMD_SCHED_FENCE_SCHEDULED_BIT, &s_fence->base.flags);
+ list_for_each_entry_safe(cur, tmp, &s_fence->scheduled_cb, node) {
+ list_del_init(&cur->node);
+ cur->func(&s_fence->base, cur);
+ }
+}
+
static const char *amd_sched_fence_get_driver_name(struct fence *fence)
{
return "amd_sched";
@@ -71,11 +84,17 @@ static bool amd_sched_fence_enable_signaling(struct fence *f)
return true;
}
+static void amd_sched_fence_release(struct fence *f)
+{
+ struct amd_sched_fence *fence = to_amd_sched_fence(f);
+ kmem_cache_free(sched_fence_slab, fence);
+}
+
const struct fence_ops amd_sched_fence_ops = {
.get_driver_name = amd_sched_fence_get_driver_name,
.get_timeline_name = amd_sched_fence_get_timeline_name,
.enable_signaling = amd_sched_fence_enable_signaling,
.signaled = NULL,
.wait = fence_default_wait,
- .release = NULL,
+ .release = amd_sched_fence_release,
};
diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 86205a2..05f6522 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -315,6 +315,7 @@ int ast_framebuffer_init(struct drm_device *dev,
int ast_fbdev_init(struct drm_device *dev);
void ast_fbdev_fini(struct drm_device *dev);
void ast_fbdev_set_suspend(struct drm_device *dev, int state);
+void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr);
struct ast_bo {
struct ttm_buffer_object bo;
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index f31db28..a37e7ea 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -365,3 +365,10 @@ void ast_fbdev_set_suspend(struct drm_device *dev, int state)
drm_fb_helper_set_suspend(&ast->fbdev->helper, state);
}
+
+void ast_fbdev_set_base(struct ast_private *ast, unsigned long gpu_addr)
+{
+ ast->fbdev->helper.fbdev->fix.smem_start =
+ ast->fbdev->helper.fbdev->apertures->ranges[0].base + gpu_addr;
+ ast->fbdev->helper.fbdev->fix.smem_len = ast->vram_size - gpu_addr;
+}
diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index 838217f..541a610 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -448,6 +448,7 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags)
dev->mode_config.min_height = 0;
dev->mode_config.preferred_depth = 24;
dev->mode_config.prefer_shadow = 1;
+ dev->mode_config.fb_base = pci_resource_start(ast->dev->pdev, 0);
if (ast->chip == AST2100 ||
ast->chip == AST2200 ||
diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c
index b7ee263..69d19f3 100644
--- a/drivers/gpu/drm/ast/ast_mode.c
+++ b/drivers/gpu/drm/ast/ast_mode.c
@@ -547,6 +547,8 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, &bo->kmap);
if (ret)
DRM_ERROR("failed to kmap fbcon\n");
+ else
+ ast_fbdev_set_base(ast, gpu_addr);
}
ast_bo_unreserve(bo);
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 7bb3845..aeee083 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -1432,6 +1432,45 @@ static int atomic_set_prop(struct drm_atomic_state *state,
return ret;
}
+/**
+ * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers.
+ *
+ * @dev: drm device to check.
+ * @plane_mask: plane mask for planes that were updated.
+ * @ret: return value, can be -EDEADLK for a retry.
+ *
+ * Before doing an update plane->old_fb is set to plane->fb,
+ * but before dropping the locks old_fb needs to be set to NULL
+ * and plane->fb updated. This is a common operation for each
+ * atomic update, so this call is split off as a helper.
+ */
+void drm_atomic_clean_old_fb(struct drm_device *dev,
+ unsigned plane_mask,
+ int ret)
+{
+ struct drm_plane *plane;
+
+ /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
+ * locks (ie. while it is still safe to deref plane->state). We
+ * need to do this here because the driver entry points cannot
+ * distinguish between legacy and atomic ioctls.
+ */
+ drm_for_each_plane_mask(plane, dev, plane_mask) {
+ if (ret == 0) {
+ struct drm_framebuffer *new_fb = plane->state->fb;
+ if (new_fb)
+ drm_framebuffer_reference(new_fb);
+ plane->fb = new_fb;
+ plane->crtc = plane->state->crtc;
+
+ if (plane->old_fb)
+ drm_framebuffer_unreference(plane->old_fb);
+ }
+ plane->old_fb = NULL;
+ }
+}
+EXPORT_SYMBOL(drm_atomic_clean_old_fb);
+
int drm_mode_atomic_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
@@ -1446,7 +1485,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_crtc_state *crtc_state;
- unsigned plane_mask = 0;
+ unsigned plane_mask;
int ret = 0;
unsigned int i, j;
@@ -1486,6 +1525,7 @@ int drm_mode_atomic_ioctl(struct drm_device *dev,
state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
retry:
+ plane_mask = 0;
copied_objs = 0;
copied_props = 0;
@@ -1576,24 +1616,7 @@ retry:
}
out:
- /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
- * locks (ie. while it is still safe to deref plane->state). We
- * need to do this here because the driver entry points cannot
- * distinguish between legacy and atomic ioctls.
- */
- drm_for_each_plane_mask(plane, dev, plane_mask) {
- if (ret == 0) {
- struct drm_framebuffer *new_fb = plane->state->fb;
- if (new_fb)
- drm_framebuffer_reference(new_fb);
- plane->fb = new_fb;
- plane->crtc = plane->state->crtc;
-
- if (plane->old_fb)
- drm_framebuffer_unreference(plane->old_fb);
- }
- plane->old_fb = NULL;
- }
+ drm_atomic_clean_old_fb(dev, plane_mask, ret);
if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
/*
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index 0c6f621..e5aec45 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -210,6 +210,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx)
return -EINVAL;
}
+ if (!drm_encoder_crtc_ok(new_encoder, connector_state->crtc)) {
+ DRM_DEBUG_ATOMIC("[ENCODER:%d:%s] incompatible with [CRTC:%d]\n",
+ new_encoder->base.id,
+ new_encoder->name,
+ connector_state->crtc->base.id);
+ return -EINVAL;
+ }
+
if (new_encoder == connector_state->best_encoder) {
DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] keeps [ENCODER:%d:%s], now on [CRTC:%d]\n",
connector->base.id,
@@ -1553,6 +1561,9 @@ retry:
goto fail;
}
+ if (plane_state->crtc && (plane == plane->crtc->cursor))
+ plane_state->state->legacy_cursor_update = true;
+
ret = __drm_atomic_helper_disable_plane(plane, plane_state);
if (ret != 0)
goto fail;
@@ -1605,9 +1616,6 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane,
plane_state->src_h = 0;
plane_state->src_w = 0;
- if (plane->crtc && (plane == plane->crtc->cursor))
- plane_state->state->legacy_cursor_update = true;
-
return 0;
}
@@ -1741,6 +1749,7 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
struct drm_crtc_state *crtc_state;
struct drm_plane_state *primary_state;
struct drm_crtc *crtc = set->crtc;
+ int hdisplay, vdisplay;
int ret;
crtc_state = drm_atomic_get_crtc_state(state, crtc);
@@ -1783,19 +1792,21 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set,
if (ret != 0)
return ret;
+ drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+
drm_atomic_set_fb_for_plane(primary_state, set->fb);
primary_state->crtc_x = 0;
primary_state->crtc_y = 0;
- primary_state->crtc_h = set->mode->vdisplay;
- primary_state->crtc_w = set->mode->hdisplay;
+ primary_state->crtc_h = vdisplay;
+ primary_state->crtc_w = hdisplay;
primary_state->src_x = set->x << 16;
primary_state->src_y = set->y << 16;
if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
- primary_state->src_h = set->mode->hdisplay << 16;
- primary_state->src_w = set->mode->vdisplay << 16;
+ primary_state->src_h = hdisplay << 16;
+ primary_state->src_w = vdisplay << 16;
} else {
- primary_state->src_h = set->mode->vdisplay << 16;
- primary_state->src_w = set->mode->hdisplay << 16;
+ primary_state->src_h = vdisplay << 16;
+ primary_state->src_w = hdisplay << 16;
}
commit:
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 9362609..7dd6728 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -160,6 +160,11 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
goto out_unlock;
}
+ if (!file_priv->allowed_master) {
+ ret = drm_new_set_master(dev, file_priv);
+ goto out_unlock;
+ }
+
file_priv->minor->master = drm_master_get(file_priv->master);
file_priv->is_master = 1;
if (dev->driver->master_set) {
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index e673c13..69cbab5 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -342,6 +342,7 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
struct drm_plane *plane;
struct drm_atomic_state *state;
int i, ret;
+ unsigned plane_mask;
state = drm_atomic_state_alloc(dev);
if (!state)
@@ -349,11 +350,10 @@ static int restore_fbdev_mode_atomic(struct drm_fb_helper *fb_helper)
state->acquire_ctx = dev->mode_config.acquire_ctx;
retry:
+ plane_mask = 0;
drm_for_each_plane(plane, dev) {
struct drm_plane_state *plane_state;
- plane->old_fb = plane->fb;
-
plane_state = drm_atomic_get_plane_state(state, plane);
if (IS_ERR(plane_state)) {
ret = PTR_ERR(plane_state);
@@ -362,6 +362,9 @@ retry:
plane_state->rotation = BIT(DRM_ROTATE_0);
+ plane->old_fb = plane->fb;
+ plane_mask |= 1 << drm_plane_index(plane);
+
/* disable non-primary: */
if (plane->type == DRM_PLANE_TYPE_PRIMARY)
continue;
@@ -382,19 +385,7 @@ retry:
ret = drm_atomic_commit(state);
fail:
- drm_for_each_plane(plane, dev) {
- if (ret == 0) {
- struct drm_framebuffer *new_fb = plane->state->fb;
- if (new_fb)
- drm_framebuffer_reference(new_fb);
- plane->fb = new_fb;
- plane->crtc = plane->state->crtc;
-
- if (plane->old_fb)
- drm_framebuffer_unreference(plane->old_fb);
- }
- plane->old_fb = NULL;
- }
+ drm_atomic_clean_old_fb(dev, plane_mask, ret);
if (ret == -EDEADLK)
goto backoff;
@@ -1236,7 +1227,9 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
struct drm_fb_helper *fb_helper = info->par;
struct drm_device *dev = fb_helper->dev;
struct drm_atomic_state *state;
+ struct drm_plane *plane;
int i, ret;
+ unsigned plane_mask;
state = drm_atomic_state_alloc(dev);
if (!state)
@@ -1244,19 +1237,22 @@ static int pan_display_atomic(struct fb_var_screeninfo *var,
state->acquire_ctx = dev->mode_config.acquire_ctx;
retry:
+ plane_mask = 0;
for(i = 0; i < fb_helper->crtc_count; i++) {
struct drm_mode_set *mode_set;
mode_set = &fb_helper->crtc_info[i].mode_set;
- mode_set->crtc->primary->old_fb = mode_set->crtc->primary->fb;
-
mode_set->x = var->xoffset;
mode_set->y = var->yoffset;
ret = __drm_atomic_helper_set_config(mode_set, state);
if (ret != 0)
goto fail;
+
+ plane = mode_set->crtc->primary;
+ plane_mask |= drm_plane_index(plane);
+ plane->old_fb = plane->fb;
}
ret = drm_atomic_commit(state);
@@ -1268,26 +1264,7 @@ retry:
fail:
- for(i = 0; i < fb_helper->crtc_count; i++) {
- struct drm_mode_set *mode_set;
- struct drm_plane *plane;
-
- mode_set = &fb_helper->crtc_info[i].mode_set;
- plane = mode_set->crtc->primary;
-
- if (ret == 0) {
- struct drm_framebuffer *new_fb = plane->state->fb;
-
- if (new_fb)
- drm_framebuffer_reference(new_fb);
- plane->fb = new_fb;
- plane->crtc = plane->state->crtc;
-
- if (plane->old_fb)
- drm_framebuffer_unreference(plane->old_fb);
- }
- plane->old_fb = NULL;
- }
+ drm_atomic_clean_old_fb(dev, plane_mask, ret);
if (ret == -EDEADLK)
goto backoff;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index c59ce4d..6b5625e 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -126,6 +126,60 @@ static int drm_cpu_valid(void)
}
/**
+ * drm_new_set_master - Allocate a new master object and become master for the
+ * associated master realm.
+ *
+ * @dev: The associated device.
+ * @fpriv: File private identifying the client.
+ *
+ * This function must be called with dev::struct_mutex held.
+ * Returns negative error code on failure. Zero on success.
+ */
+int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv)
+{
+ struct drm_master *old_master;
+ int ret;
+
+ lockdep_assert_held_once(&dev->master_mutex);
+
+ /* create a new master */
+ fpriv->minor->master = drm_master_create(fpriv->minor);
+ if (!fpriv->minor->master)
+ return -ENOMEM;
+
+ /* take another reference for the copy in the local file priv */
+ old_master = fpriv->master;
+ fpriv->master = drm_master_get(fpriv->minor->master);
+
+ if (dev->driver->master_create) {
+ ret = dev->driver->master_create(dev, fpriv->master);
+ if (ret)
+ goto out_err;
+ }
+ if (dev->driver->master_set) {
+ ret = dev->driver->master_set(dev, fpriv, true);
+ if (ret)
+ goto out_err;
+ }
+
+ fpriv->is_master = 1;
+ fpriv->allowed_master = 1;
+ fpriv->authenticated = 1;
+ if (old_master)
+ drm_master_put(&old_master);
+
+ return 0;
+
+out_err:
+ /* drop both references and restore old master on failure */
+ drm_master_put(&fpriv->minor->master);
+ drm_master_put(&fpriv->master);
+ fpriv->master = old_master;
+
+ return ret;
+}
+
+/**
* Called whenever a process opens /dev/drm.
*
* \param filp file pointer.
@@ -189,35 +243,9 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor)
mutex_lock(&dev->master_mutex);
if (drm_is_primary_client(priv) && !priv->minor->master) {
/* create a new master */
- priv->minor->master = drm_master_create(priv->minor);
- if (!priv->minor->master) {
- ret = -ENOMEM;
+ ret = drm_new_set_master(dev, priv);
+ if (ret)
goto out_close;
- }
-
- priv->is_master = 1;
- /* take another reference for the copy in the local file priv */
- priv->master = drm_master_get(priv->minor->master);
- priv->authenticated = 1;
-
- if (dev->driver->master_create) {
- ret = dev->driver->master_create(dev, priv->master);
- if (ret) {
- /* drop both references if this fails */
- drm_master_put(&priv->minor->master);
- drm_master_put(&priv->master);
- goto out_close;
- }
- }
- if (dev->driver->master_set) {
- ret = dev->driver->master_set(dev, priv, true);
- if (ret) {
- /* drop both references if this fails */
- drm_master_put(&priv->minor->master);
- drm_master_put(&priv->master);
- goto out_close;
- }
- }
} else if (drm_is_primary_client(priv)) {
/* get a reference to the master */
priv->master = drm_master_get(priv->minor->master);
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index eba6337..607f493 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -616,10 +616,18 @@ int drm_control(struct drm_device *dev, void *data,
void drm_calc_timestamping_constants(struct drm_crtc *crtc,
const struct drm_display_mode *mode)
{
- struct drm_vblank_crtc *vblank = &crtc->dev->vblank[drm_crtc_index(crtc)];
+ struct drm_device *dev = crtc->dev;
+ unsigned int pipe = drm_crtc_index(crtc);
+ struct drm_vblank_crtc *vblank = &dev->vblank[pipe];
int linedur_ns = 0, framedur_ns = 0;
int dotclock = mode->crtc_clock;
+ if (!dev->num_crtcs)
+ return;
+
+ if (WARN_ON(pipe >= dev->num_crtcs))
+ return;
+
/* Valid dotclock? */
if (dotclock > 0) {
int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
@@ -972,7 +980,8 @@ static void send_vblank_event(struct drm_device *dev,
struct drm_pending_vblank_event *e,
unsigned long seq, struct timeval *now)
{
- WARN_ON_SMP(!spin_is_locked(&dev->event_lock));
+ assert_spin_locked(&dev->event_lock);
+
e->event.sequence = seq;
e->event.tv_sec = now->tv_sec;
e->event.tv_usec = now->tv_usec;
@@ -985,6 +994,57 @@ static void send_vblank_event(struct drm_device *dev,
}
/**
+ * drm_arm_vblank_event - arm vblank event after pageflip
+ * @dev: DRM device
+ * @pipe: CRTC index
+ * @e: the event to prepare to send
+ *
+ * A lot of drivers need to generate vblank events for the very next vblank
+ * interrupt. For example when the page flip interrupt happens when the page
+ * flip gets armed, but not when it actually executes within the next vblank
+ * period. This helper function implements exactly the required vblank arming
+ * behaviour.
+ *
+ * Caller must hold event lock. Caller must also hold a vblank reference for
+ * the event @e, which will be dropped when the next vblank arrives.
+ *
+ * This is the legacy version of drm_crtc_arm_vblank_event().
+ */
+void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
+ struct drm_pending_vblank_event *e)
+{
+ assert_spin_locked(&dev->event_lock);
+
+ e->pipe = pipe;
+ e->event.sequence = drm_vblank_count(dev, pipe);
+ list_add_tail(&e->base.link, &dev->vblank_event_list);
+}
+EXPORT_SYMBOL(drm_arm_vblank_event);
+
+/**
+ * drm_crtc_arm_vblank_event - arm vblank event after pageflip
+ * @crtc: the source CRTC of the vblank event
+ * @e: the event to send
+ *
+ * A lot of drivers need to generate vblank events for the very next vblank
+ * interrupt. For example when the page flip interrupt happens when the page
+ * flip gets armed, but not when it actually executes within the next vblank
+ * period. This helper function implements exactly the required vblank arming
+ * behaviour.
+ *
+ * Caller must hold event lock. Caller must also hold a vblank reference for
+ * the event @e, which will be dropped when the next vblank arrives.
+ *
+ * This is the native KMS version of drm_arm_vblank_event().
+ */
+void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
+ struct drm_pending_vblank_event *e)
+{
+ drm_arm_vblank_event(crtc->dev, drm_crtc_index(crtc), e);
+}
+EXPORT_SYMBOL(drm_crtc_arm_vblank_event);
+
+/**
* drm_send_vblank_event - helper to send vblank event after pageflip
* @dev: DRM device
* @pipe: CRTC index
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index a18164f..f8b5fcf 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -229,7 +229,8 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
mode_flags |= DRM_MODE_FLAG_3D_MASK;
list_for_each_entry(mode, &connector->modes, head) {
- mode->status = drm_mode_validate_basic(mode);
+ if (mode->status == MODE_OK)
+ mode->status = drm_mode_validate_basic(mode);
if (mode->status == MODE_OK)
mode->status = drm_mode_validate_size(mode, maxX, maxY);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index b3ba27f..e693571 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -55,6 +55,9 @@ static int exynos_crtc_atomic_check(struct drm_crtc *crtc,
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ if (!state->enable)
+ return 0;
+
if (exynos_crtc->ops->atomic_check)
return exynos_crtc->ops->atomic_check(exynos_crtc, state);
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index a3b22bd..8aab974 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -2734,6 +2734,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
return "AUX_C";
case POWER_DOMAIN_AUX_D:
return "AUX_D";
+ case POWER_DOMAIN_GMBUS:
+ return "GMBUS";
case POWER_DOMAIN_INIT:
return "INIT";
default:
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8afda45..f4af19a 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -199,6 +199,7 @@ enum intel_display_power_domain {
POWER_DOMAIN_AUX_B,
POWER_DOMAIN_AUX_C,
POWER_DOMAIN_AUX_D,
+ POWER_DOMAIN_GMBUS,
POWER_DOMAIN_INIT,
POWER_DOMAIN_NUM,
@@ -351,6 +352,8 @@ enum intel_dpll_id {
/* hsw/bdw */
DPLL_ID_WRPLL1 = 0,
DPLL_ID_WRPLL2 = 1,
+ DPLL_ID_SPLL = 2,
+
/* skl */
DPLL_ID_SKL_DPLL1 = 0,
DPLL_ID_SKL_DPLL2 = 1,
@@ -367,6 +370,7 @@ struct intel_dpll_hw_state {
/* hsw, bdw */
uint32_t wrpll;
+ uint32_t spll;
/* skl */
/*
@@ -2189,8 +2193,17 @@ struct drm_i915_gem_request {
struct drm_i915_private *i915;
struct intel_engine_cs *ring;
- /** GEM sequence number associated with this request. */
- uint32_t seqno;
+ /** GEM sequence number associated with the previous request,
+ * when the HWS breadcrumb is equal to this the GPU is processing
+ * this request.
+ */
+ u32 previous_seqno;
+
+ /** GEM sequence number associated with this request,
+ * when the HWS breadcrumb is equal or greater than this the GPU
+ * has finished processing this request.
+ */
+ u32 seqno;
/** Position in the ringbuffer of the start of the request */
u32 head;
@@ -2648,6 +2661,7 @@ struct i915_params {
int enable_cmd_parser;
/* leave bools at the end to not create holes */
bool enable_hangcheck;
+ bool fastboot;
bool prefault_disable;
bool load_detect_test;
bool reset;
@@ -2834,6 +2848,7 @@ i915_gem_object_ggtt_pin(struct drm_i915_gem_object *obj,
int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
u32 flags);
+void __i915_vma_set_map_and_fenceable(struct i915_vma *vma);
int __must_check i915_vma_unbind(struct i915_vma *vma);
/*
* BEWARE: Do not use the function below unless you can _absolutely_
@@ -2905,15 +2920,17 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1 - seq2) >= 0;
}
+static inline bool i915_gem_request_started(struct drm_i915_gem_request *req,
+ bool lazy_coherency)
+{
+ u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency);
+ return i915_seqno_passed(seqno, req->previous_seqno);
+}
+
static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
bool lazy_coherency)
{
- u32 seqno;
-
- BUG_ON(req == NULL);
-
- seqno = req->ring->get_seqno(req->ring, lazy_coherency);
-
+ u32 seqno = req->ring->get_seqno(req->ring, lazy_coherency);
return i915_seqno_passed(seqno, req->seqno);
}
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 5cf4a19..f56af0a 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1146,23 +1146,74 @@ static bool missed_irq(struct drm_i915_private *dev_priv,
return test_bit(ring->id, &dev_priv->gpu_error.missed_irq_rings);
}
-static int __i915_spin_request(struct drm_i915_gem_request *req)
+static unsigned long local_clock_us(unsigned *cpu)
+{
+ unsigned long t;
+
+ /* Cheaply and approximately convert from nanoseconds to microseconds.
+ * The result and subsequent calculations are also defined in the same
+ * approximate microseconds units. The principal source of timing
+ * error here is from the simple truncation.
+ *
+ * Note that local_clock() is only defined wrt to the current CPU;
+ * the comparisons are no longer valid if we switch CPUs. Instead of
+ * blocking preemption for the entire busywait, we can detect the CPU
+ * switch and use that as indicator of system load and a reason to
+ * stop busywaiting, see busywait_stop().
+ */
+ *cpu = get_cpu();
+ t = local_clock() >> 10;
+ put_cpu();
+
+ return t;
+}
+
+static bool busywait_stop(unsigned long timeout, unsigned cpu)
+{
+ unsigned this_cpu;
+
+ if (time_after(local_clock_us(&this_cpu), timeout))
+ return true;
+
+ return this_cpu != cpu;
+}
+
+static int __i915_spin_request(struct drm_i915_gem_request *req, int state)
{
unsigned long timeout;
+ unsigned cpu;
+
+ /* When waiting for high frequency requests, e.g. during synchronous
+ * rendering split between the CPU and GPU, the finite amount of time
+ * required to set up the irq and wait upon it limits the response
+ * rate. By busywaiting on the request completion for a short while we
+ * can service the high frequency waits as quick as possible. However,
+ * if it is a slow request, we want to sleep as quickly as possible.
+ * The tradeoff between waiting and sleeping is roughly the time it
+ * takes to sleep on a request, on the order of a microsecond.
+ */
- if (i915_gem_request_get_ring(req)->irq_refcount)
+ if (req->ring->irq_refcount)
return -EBUSY;
- timeout = jiffies + 1;
+ /* Only spin if we know the GPU is processing this request */
+ if (!i915_gem_request_started(req, true))
+ return -EAGAIN;
+
+ timeout = local_clock_us(&cpu) + 5;
while (!need_resched()) {
if (i915_gem_request_completed(req, true))
return 0;
- if (time_after_eq(jiffies, timeout))
+ if (signal_pending_state(state, current))
+ break;
+
+ if (busywait_stop(timeout, cpu))
break;
cpu_relax_lowlatency();
}
+
if (i915_gem_request_completed(req, false))
return 0;
@@ -1197,6 +1248,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
struct drm_i915_private *dev_priv = dev->dev_private;
const bool irq_test_in_progress =
ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
+ int state = interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
DEFINE_WAIT(wait);
unsigned long timeout_expire;
s64 before, now;
@@ -1210,8 +1262,16 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
if (i915_gem_request_completed(req, true))
return 0;
- timeout_expire = timeout ?
- jiffies + nsecs_to_jiffies_timeout((u64)*timeout) : 0;
+ timeout_expire = 0;
+ if (timeout) {
+ if (WARN_ON(*timeout < 0))
+ return -EINVAL;
+
+ if (*timeout == 0)
+ return -ETIME;
+
+ timeout_expire = jiffies + nsecs_to_jiffies_timeout(*timeout);
+ }
if (INTEL_INFO(dev_priv)->gen >= 6)
gen6_rps_boost(dev_priv, rps, req->emitted_jiffies);
@@ -1221,7 +1281,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
before = ktime_get_raw_ns();
/* Optimistic spin for the next jiffie before touching IRQs */
- ret = __i915_spin_request(req);
+ ret = __i915_spin_request(req, state);
if (ret == 0)
goto out;
@@ -1233,8 +1293,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
for (;;) {
struct timer_list timer;
- prepare_to_wait(&ring->irq_queue, &wait,
- interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ prepare_to_wait(&ring->irq_queue, &wait, state);
/* We need to check whether any gpu reset happened in between
* the caller grabbing the seqno and now ... */
@@ -1252,7 +1311,7 @@ int __i915_wait_request(struct drm_i915_gem_request *req,
break;
}
- if (interruptible && signal_pending(current)) {
+ if (signal_pending_state(state, current)) {
ret = -ERESTARTSYS;
break;
}
@@ -2546,6 +2605,7 @@ void __i915_add_request(struct drm_i915_gem_request *request,
request->batch_obj = obj;
request->emitted_jiffies = jiffies;
+ request->previous_seqno = ring->last_submitted_seqno;
ring->last_submitted_seqno = request->seqno;
list_add_tail(&request->list, &ring->request_list);
@@ -3809,6 +3869,7 @@ int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_caching *args = data;
struct drm_i915_gem_object *obj;
enum i915_cache_level level;
@@ -3837,9 +3898,11 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
return -EINVAL;
}
+ intel_runtime_pm_get(dev_priv);
+
ret = i915_mutex_lock_interruptible(dev);
if (ret)
- return ret;
+ goto rpm_put;
obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
if (&obj->base == NULL) {
@@ -3852,6 +3915,9 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data,
drm_gem_object_unreference(&obj->base);
unlock:
mutex_unlock(&dev->struct_mutex);
+rpm_put:
+ intel_runtime_pm_put(dev_priv);
+
return ret;
}
@@ -4066,6 +4132,29 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
return false;
}
+void __i915_vma_set_map_and_fenceable(struct i915_vma *vma)
+{
+ struct drm_i915_gem_object *obj = vma->obj;
+ bool mappable, fenceable;
+ u32 fence_size, fence_alignment;
+
+ fence_size = i915_gem_get_gtt_size(obj->base.dev,
+ obj->base.size,
+ obj->tiling_mode);
+ fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
+ obj->base.size,
+ obj->tiling_mode,
+ true);
+
+ fenceable = (vma->node.size == fence_size &&
+ (vma->node.start & (fence_alignment - 1)) == 0);
+
+ mappable = (vma->node.start + fence_size <=
+ to_i915(obj->base.dev)->gtt.mappable_end);
+
+ obj->map_and_fenceable = mappable && fenceable;
+}
+
static int
i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
@@ -4133,25 +4222,7 @@ i915_gem_object_do_pin(struct drm_i915_gem_object *obj,
if (ggtt_view && ggtt_view->type == I915_GGTT_VIEW_NORMAL &&
(bound ^ vma->bound) & GLOBAL_BIND) {
- bool mappable, fenceable;
- u32 fence_size, fence_alignment;
-
- fence_size = i915_gem_get_gtt_size(obj->base.dev,
- obj->base.size,
- obj->tiling_mode);
- fence_alignment = i915_gem_get_gtt_alignment(obj->base.dev,
- obj->base.size,
- obj->tiling_mode,
- true);
-
- fenceable = (vma->node.size == fence_size &&
- (vma->node.start & (fence_alignment - 1)) == 0);
-
- mappable = (vma->node.start + fence_size <=
- dev_priv->gtt.mappable_end);
-
- obj->map_and_fenceable = mappable && fenceable;
-
+ __i915_vma_set_map_and_fenceable(vma);
WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 8c688a5..02ceb7a 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -141,8 +141,6 @@ static void i915_gem_context_clean(struct intel_context *ctx)
if (!ppgtt)
return;
- WARN_ON(!list_empty(&ppgtt->base.active_list));
-
list_for_each_entry_safe(vma, next, &ppgtt->base.inactive_list,
mm_list) {
if (WARN_ON(__i915_vma_unbind_no_wait(vma)))
diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c
index 40a10b2..f010391 100644
--- a/drivers/gpu/drm/i915/i915_gem_fence.c
+++ b/drivers/gpu/drm/i915/i915_gem_fence.c
@@ -642,11 +642,10 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
}
/* check for L-shaped memory aka modified enhanced addressing */
- if (IS_GEN4(dev)) {
- uint32_t ddc2 = I915_READ(DCC2);
-
- if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE))
- dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
+ if (IS_GEN4(dev) &&
+ !(I915_READ(DCC2) & DCC2_MODIFIED_ENHANCED_DISABLE)) {
+ swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
+ swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
}
if (dcc == 0xffffffff) {
@@ -675,16 +674,35 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
* matching, which was the case for the swizzling required in
* the table above, or from the 1-ch value being less than
* the minimum size of a rank.
+ *
+ * Reports indicate that the swizzling actually
+ * varies depending upon page placement inside the
+ * channels, i.e. we see swizzled pages where the
+ * banks of memory are paired and unswizzled on the
+ * uneven portion, so leave that as unknown.
*/
- if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) {
- swizzle_x = I915_BIT_6_SWIZZLE_NONE;
- swizzle_y = I915_BIT_6_SWIZZLE_NONE;
- } else {
+ if (I915_READ16(C0DRB3) == I915_READ16(C1DRB3)) {
swizzle_x = I915_BIT_6_SWIZZLE_9_10;
swizzle_y = I915_BIT_6_SWIZZLE_9;
}
}
+ if (swizzle_x == I915_BIT_6_SWIZZLE_UNKNOWN ||
+ swizzle_y == I915_BIT_6_SWIZZLE_UNKNOWN) {
+ /* Userspace likes to explode if it sees unknown swizzling,
+ * so lie. We will finish the lie when reporting through
+ * the get-tiling-ioctl by reporting the physical swizzle
+ * mode as unknown instead.
+ *
+ * As we don't strictly know what the swizzling is, it may be
+ * bit17 dependent, and so we need to also prevent the pages
+ * from being moved.
+ */
+ dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES;
+ swizzle_x = I915_BIT_6_SWIZZLE_NONE;
+ swizzle_y = I915_BIT_6_SWIZZLE_NONE;
+ }
+
dev_priv->mm.bit_6_swizzle_x = swizzle_x;
dev_priv->mm.bit_6_swizzle_y = swizzle_y;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 43f35d1..86c7500 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2676,6 +2676,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev,
return ret;
}
vma->bound |= GLOBAL_BIND;
+ __i915_vma_set_map_and_fenceable(vma);
list_add_tail(&vma->mm_list, &ggtt_vm->inactive_list);
}
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index cdacf3f..87e919a 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -687,6 +687,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
}
vma->bound |= GLOBAL_BIND;
+ __i915_vma_set_map_and_fenceable(vma);
list_add_tail(&vma->mm_list, &ggtt->inactive_list);
}
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index 96bb238..4be13a5 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -40,6 +40,7 @@ struct i915_params i915 __read_mostly = {
.preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
.disable_power_well = -1,
.enable_ips = 1,
+ .fastboot = 0,
.prefault_disable = 0,
.load_detect_test = 0,
.reset = true,
@@ -133,6 +134,10 @@ MODULE_PARM_DESC(disable_power_well,
module_param_named_unsafe(enable_ips, i915.enable_ips, int, 0600);
MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
+module_param_named(fastboot, i915.fastboot, bool, 0600);
+MODULE_PARM_DESC(fastboot,
+ "Try to skip unnecessary mode sets at boot time (default: false)");
+
module_param_named_unsafe(prefault_disable, i915.prefault_disable, bool, 0600);
MODULE_PARM_DESC(prefault_disable,
"Disable page prefaulting for pread/pwrite/reloc (default:false). "
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index b84aaa0..6a2c76e 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -138,18 +138,6 @@ static void hsw_crt_get_config(struct intel_encoder *encoder,
pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
}
-static void hsw_crt_pre_enable(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL already enabled\n");
- I915_WRITE(SPLL_CTL,
- SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC);
- POSTING_READ(SPLL_CTL);
- udelay(20);
-}
-
/* Note: The caller is required to filter out dpms modes not supported by the
* platform. */
static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
@@ -216,19 +204,6 @@ static void pch_post_disable_crt(struct intel_encoder *encoder)
intel_disable_crt(encoder);
}
-static void hsw_crt_post_disable(struct intel_encoder *encoder)
-{
- struct drm_device *dev = encoder->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- uint32_t val;
-
- DRM_DEBUG_KMS("Disabling SPLL\n");
- val = I915_READ(SPLL_CTL);
- WARN_ON(!(val & SPLL_PLL_ENABLE));
- I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
- POSTING_READ(SPLL_CTL);
-}
-
static void intel_enable_crt(struct intel_encoder *encoder)
{
struct intel_crt *crt = intel_encoder_to_crt(encoder);
@@ -280,6 +255,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
if (HAS_DDI(dev)) {
pipe_config->ddi_pll_sel = PORT_CLK_SEL_SPLL;
pipe_config->port_clock = 135000 * 2;
+
+ pipe_config->dpll_hw_state.wrpll = 0;
+ pipe_config->dpll_hw_state.spll =
+ SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
}
return true;
@@ -860,8 +839,6 @@ void intel_crt_init(struct drm_device *dev)
if (HAS_DDI(dev)) {
crt->base.get_config = hsw_crt_get_config;
crt->base.get_hw_state = intel_ddi_get_hw_state;
- crt->base.pre_enable = hsw_crt_pre_enable;
- crt->base.post_disable = hsw_crt_post_disable;
} else {
crt->base.get_config = intel_crt_get_config;
crt->base.get_hw_state = intel_crt_get_hw_state;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index b25e99a..a6752a6 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -1286,6 +1286,18 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
}
crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+ } else if (crtc_state->ddi_pll_sel == PORT_CLK_SEL_SPLL) {
+ struct drm_atomic_state *state = crtc_state->base.state;
+ struct intel_shared_dpll_config *spll =
+ &intel_atomic_get_shared_dpll_state(state)[DPLL_ID_SPLL];
+
+ if (spll->crtc_mask &&
+ WARN_ON(spll->hw_state.spll != crtc_state->dpll_hw_state.spll))
+ return false;
+
+ crtc_state->shared_dpll = DPLL_ID_SPLL;
+ spll->hw_state.spll = crtc_state->dpll_hw_state.spll;
+ spll->crtc_mask |= 1 << intel_crtc->pipe;
}
return true;
@@ -2437,7 +2449,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
}
}
-static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
+static void hsw_ddi_wrpll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
I915_WRITE(WRPLL_CTL(pll->id), pll->config.hw_state.wrpll);
@@ -2445,9 +2457,17 @@ static void hsw_ddi_pll_enable(struct drm_i915_private *dev_priv,
udelay(20);
}
-static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
+static void hsw_ddi_spll_enable(struct drm_i915_private *dev_priv,
struct intel_shared_dpll *pll)
{
+ I915_WRITE(SPLL_CTL, pll->config.hw_state.spll);
+ POSTING_READ(SPLL_CTL);
+ udelay(20);
+}
+
+static void hsw_ddi_wrpll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
uint32_t val;
val = I915_READ(WRPLL_CTL(pll->id));
@@ -2455,9 +2475,19 @@ static void hsw_ddi_pll_disable(struct drm_i915_private *dev_priv,
POSTING_READ(WRPLL_CTL(pll->id));
}
-static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
- struct intel_shared_dpll *pll,
- struct intel_dpll_hw_state *hw_state)
+static void hsw_ddi_spll_disable(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll)
+{
+ uint32_t val;
+
+ val = I915_READ(SPLL_CTL);
+ I915_WRITE(SPLL_CTL, val & ~SPLL_PLL_ENABLE);
+ POSTING_READ(SPLL_CTL);
+}
+
+static bool hsw_ddi_wrpll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
{
uint32_t val;
@@ -2470,25 +2500,50 @@ static bool hsw_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv,
return val & WRPLL_PLL_ENABLE;
}
+static bool hsw_ddi_spll_get_hw_state(struct drm_i915_private *dev_priv,
+ struct intel_shared_dpll *pll,
+ struct intel_dpll_hw_state *hw_state)
+{
+ uint32_t val;
+
+ if (!intel_display_power_is_enabled(dev_priv, POWER_DOMAIN_PLLS))
+ return false;
+
+ val = I915_READ(SPLL_CTL);
+ hw_state->spll = val;
+
+ return val & SPLL_PLL_ENABLE;
+}
+
+
static const char * const hsw_ddi_pll_names[] = {
"WRPLL 1",
"WRPLL 2",
+ "SPLL"
};
static void hsw_shared_dplls_init(struct drm_i915_private *dev_priv)
{
int i;
- dev_priv->num_shared_dpll = 2;
+ dev_priv->num_shared_dpll = 3;
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ for (i = 0; i < 2; i++) {
dev_priv->shared_dplls[i].id = i;
dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
- dev_priv->shared_dplls[i].disable = hsw_ddi_pll_disable;
- dev_priv->shared_dplls[i].enable = hsw_ddi_pll_enable;
+ dev_priv->shared_dplls[i].disable = hsw_ddi_wrpll_disable;
+ dev_priv->shared_dplls[i].enable = hsw_ddi_wrpll_enable;
dev_priv->shared_dplls[i].get_hw_state =
- hsw_ddi_pll_get_hw_state;
+ hsw_ddi_wrpll_get_hw_state;
}
+
+ /* SPLL is special, but needs to be initialized anyway.. */
+ dev_priv->shared_dplls[i].id = i;
+ dev_priv->shared_dplls[i].name = hsw_ddi_pll_names[i];
+ dev_priv->shared_dplls[i].disable = hsw_ddi_spll_disable;
+ dev_priv->shared_dplls[i].enable = hsw_ddi_spll_enable;
+ dev_priv->shared_dplls[i].get_hw_state = hsw_ddi_spll_get_hw_state;
+
}
static const char * const skl_ddi_pll_names[] = {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index f62ffc0..32cf973 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -116,6 +116,7 @@ static void skylake_pfit_enable(struct intel_crtc *crtc);
static void ironlake_pfit_disable(struct intel_crtc *crtc, bool force);
static void ironlake_pfit_enable(struct intel_crtc *crtc);
static void intel_modeset_setup_hw_state(struct drm_device *dev);
+static void intel_pre_disable_primary(struct drm_crtc *crtc);
typedef struct {
int min, max;
@@ -2607,6 +2608,8 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
struct drm_i915_gem_object *obj;
struct drm_plane *primary = intel_crtc->base.primary;
struct drm_plane_state *plane_state = primary->state;
+ struct drm_crtc_state *crtc_state = intel_crtc->base.state;
+ struct intel_plane *intel_plane = to_intel_plane(primary);
struct drm_framebuffer *fb;
if (!plane_config->fb)
@@ -2643,14 +2646,28 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc,
}
}
+ /*
+ * We've failed to reconstruct the BIOS FB. Current display state
+ * indicates that the primary plane is visible, but has a NULL FB,
+ * which will lead to problems later if we don't fix it up. The
+ * simplest solution is to just disable the primary plane now and
+ * pretend the BIOS never had it enabled.
+ */
+ to_intel_plane_state(plane_state)->visible = false;
+ crtc_state->plane_mask &= ~(1 << drm_plane_index(primary));
+ intel_pre_disable_primary(&intel_crtc->base);
+ intel_plane->disable_plane(primary, &intel_crtc->base);
+
return;
valid_fb:
- plane_state->src_x = plane_state->src_y = 0;
+ plane_state->src_x = 0;
+ plane_state->src_y = 0;
plane_state->src_w = fb->width << 16;
plane_state->src_h = fb->height << 16;
- plane_state->crtc_x = plane_state->src_y = 0;
+ plane_state->crtc_x = 0;
+ plane_state->crtc_y = 0;
plane_state->crtc_w = fb->width;
plane_state->crtc_h = fb->height;
@@ -4237,6 +4254,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
struct intel_shared_dpll *pll;
struct intel_shared_dpll_config *shared_dpll;
enum intel_dpll_id i;
+ int max = dev_priv->num_shared_dpll;
shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state);
@@ -4271,9 +4289,11 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
WARN_ON(shared_dpll[i].crtc_mask);
goto found;
- }
+ } else if (INTEL_INFO(dev_priv)->gen < 9 && HAS_DDI(dev_priv))
+ /* Do not consider SPLL */
+ max = 2;
- for (i = 0; i < dev_priv->num_shared_dpll; i++) {
+ for (i = 0; i < max; i++) {
pll = &dev_priv->shared_dplls[i];
/* Only want to check enabled timings first */
@@ -5189,11 +5209,31 @@ static enum intel_display_power_domain port_to_power_domain(enum port port)
case PORT_E:
return POWER_DOMAIN_PORT_DDI_E_2_LANES;
default:
- WARN_ON_ONCE(1);
+ MISSING_CASE(port);
return POWER_DOMAIN_PORT_OTHER;
}
}
+static enum intel_display_power_domain port_to_aux_power_domain(enum port port)
+{
+ switch (port) {
+ case PORT_A:
+ return POWER_DOMAIN_AUX_A;
+ case PORT_B:
+ return POWER_DOMAIN_AUX_B;
+ case PORT_C:
+ return POWER_DOMAIN_AUX_C;
+ case PORT_D:
+ return POWER_DOMAIN_AUX_D;
+ case PORT_E:
+ /* FIXME: Check VBT for actual wiring of PORT E */
+ return POWER_DOMAIN_AUX_D;
+ default:
+ MISSING_CASE(port);
+ return POWER_DOMAIN_AUX_A;
+ }
+}
+
#define for_each_power_domain(domain, mask) \
for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \
if ((1 << (domain)) & (mask))
@@ -5225,6 +5265,36 @@ intel_display_port_power_domain(struct intel_encoder *intel_encoder)
}
}
+enum intel_display_power_domain
+intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder)
+{
+ struct drm_device *dev = intel_encoder->base.dev;
+ struct intel_digital_port *intel_dig_port;
+
+ switch (intel_encoder->type) {
+ case INTEL_OUTPUT_UNKNOWN:
+ case INTEL_OUTPUT_HDMI:
+ /*
+ * Only DDI platforms should ever use these output types.
+ * We can get here after the HDMI detect code has already set
+ * the type of the shared encoder. Since we can't be sure
+ * what's the status of the given connectors, play safe and
+ * run the DP detection too.
+ */
+ WARN_ON_ONCE(!HAS_DDI(dev));
+ case INTEL_OUTPUT_DISPLAYPORT:
+ case INTEL_OUTPUT_EDP:
+ intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+ return port_to_aux_power_domain(intel_dig_port->port);
+ case INTEL_OUTPUT_DP_MST:
+ intel_dig_port = enc_to_mst(&intel_encoder->base)->primary;
+ return port_to_aux_power_domain(intel_dig_port->port);
+ default:
+ MISSING_CASE(intel_encoder->type);
+ return POWER_DOMAIN_AUX_A;
+ }
+}
+
static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -6254,9 +6324,11 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc)
if (to_intel_plane_state(crtc->primary->state)->visible) {
intel_crtc_wait_for_pending_flips(crtc);
intel_pre_disable_primary(crtc);
+
+ intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary));
+ to_intel_plane_state(crtc->primary->state)->visible = false;
}
- intel_crtc_disable_planes(crtc, crtc->state->plane_mask);
dev_priv->display.crtc_disable(crtc);
intel_crtc->active = false;
intel_update_watermarks(crtc);
@@ -9723,6 +9795,8 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
case PORT_CLK_SEL_WRPLL2:
pipe_config->shared_dpll = DPLL_ID_WRPLL2;
break;
+ case PORT_CLK_SEL_SPLL:
+ pipe_config->shared_dpll = DPLL_ID_SPLL;
}
}
@@ -9851,14 +9925,14 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
return true;
}
-static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i845_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
uint32_t cntl = 0, size = 0;
- if (base) {
+ if (on) {
unsigned int width = intel_crtc->base.cursor->state->crtc_w;
unsigned int height = intel_crtc->base.cursor->state->crtc_h;
unsigned int stride = roundup_pow_of_two(width) * 4;
@@ -9913,16 +9987,15 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
}
}
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base, bool on)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_crtc->pipe;
- uint32_t cntl;
+ uint32_t cntl = 0;
- cntl = 0;
- if (base) {
+ if (on) {
cntl = MCURSOR_GAMMA_ENABLE;
switch (intel_crtc->base.cursor->state->crtc_w) {
case 64:
@@ -9973,18 +10046,17 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
int y = cursor_state->crtc_y;
u32 base = 0, pos = 0;
- if (on)
- base = intel_crtc->cursor_addr;
+ base = intel_crtc->cursor_addr;
if (x >= intel_crtc->config->pipe_src_w)
- base = 0;
+ on = false;
if (y >= intel_crtc->config->pipe_src_h)
- base = 0;
+ on = false;
if (x < 0) {
if (x + cursor_state->crtc_w <= 0)
- base = 0;
+ on = false;
pos |= CURSOR_POS_SIGN << CURSOR_X_SHIFT;
x = -x;
@@ -9993,16 +10065,13 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
if (y < 0) {
if (y + cursor_state->crtc_h <= 0)
- base = 0;
+ on = false;
pos |= CURSOR_POS_SIGN << CURSOR_Y_SHIFT;
y = -y;
}
pos |= y << CURSOR_Y_SHIFT;
- if (base == 0 && intel_crtc->cursor_base == 0)
- return;
-
I915_WRITE(CURPOS(pipe), pos);
/* ILK+ do this automagically */
@@ -10013,9 +10082,9 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
}
if (IS_845G(dev) || IS_I865G(dev))
- i845_update_cursor(crtc, base);
+ i845_update_cursor(crtc, base, on);
else
- i9xx_update_cursor(crtc, base);
+ i9xx_update_cursor(crtc, base, on);
}
static bool cursor_size_ok(struct drm_device *dev,
@@ -12003,9 +12072,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->dpll_hw_state.cfgcr1,
pipe_config->dpll_hw_state.cfgcr2);
} else if (HAS_DDI(dev)) {
- DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x\n",
+ DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: wrpll: 0x%x spll: 0x%x\n",
pipe_config->ddi_pll_sel,
- pipe_config->dpll_hw_state.wrpll);
+ pipe_config->dpll_hw_state.wrpll,
+ pipe_config->dpll_hw_state.spll);
} else {
DRM_DEBUG_KMS("dpll_hw_state: dpll: 0x%x, dpll_md: 0x%x, "
"fp0: 0x%x, fp1: 0x%x\n",
@@ -12053,18 +12123,22 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
static bool check_digital_port_conflicts(struct drm_atomic_state *state)
{
struct drm_device *dev = state->dev;
- struct intel_encoder *encoder;
struct drm_connector *connector;
- struct drm_connector_state *connector_state;
unsigned int used_ports = 0;
- int i;
/*
* Walk the connector list instead of the encoder
* list to detect the problem on ddi platforms
* where there's just one encoder per digital port.
*/
- for_each_connector_in_state(state, connector, connector_state, i) {
+ drm_for_each_connector(connector, dev) {
+ struct drm_connector_state *connector_state;
+ struct intel_encoder *encoder;
+
+ connector_state = drm_atomic_get_existing_connector_state(state, connector);
+ if (!connector_state)
+ connector_state = connector->state;
+
if (!connector_state->best_encoder)
continue;
@@ -12452,7 +12526,6 @@ intel_pipe_config_compare(struct drm_device *dev,
if (INTEL_INFO(dev)->gen < 8) {
PIPE_CONF_CHECK_M_N(dp_m_n);
- PIPE_CONF_CHECK_I(has_drrs);
if (current_config->has_drrs)
PIPE_CONF_CHECK_M_N(dp_m2_n2);
} else
@@ -12528,6 +12601,7 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_X(dpll_hw_state.fp0);
PIPE_CONF_CHECK_X(dpll_hw_state.fp1);
PIPE_CONF_CHECK_X(dpll_hw_state.wrpll);
+ PIPE_CONF_CHECK_X(dpll_hw_state.spll);
PIPE_CONF_CHECK_X(dpll_hw_state.ctrl1);
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr1);
PIPE_CONF_CHECK_X(dpll_hw_state.cfgcr2);
@@ -13032,6 +13106,9 @@ static int intel_atomic_check(struct drm_device *dev,
struct intel_crtc_state *pipe_config =
to_intel_crtc_state(crtc_state);
+ memset(&to_intel_crtc(crtc)->atomic, 0,
+ sizeof(struct intel_crtc_atomic_commit));
+
/* Catch I915_MODE_FLAG_INHERITED */
if (crtc_state->mode.private_flags != crtc->state->mode.private_flags)
crtc_state->mode_changed = true;
@@ -13056,7 +13133,8 @@ static int intel_atomic_check(struct drm_device *dev,
if (ret)
return ret;
- if (intel_pipe_config_compare(state->dev,
+ if (i915.fastboot &&
+ intel_pipe_config_compare(state->dev,
to_intel_crtc_state(crtc->state),
pipe_config, true)) {
crtc_state->mode_changed = false;
@@ -13654,6 +13732,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
struct drm_crtc *crtc = crtc_state->base.crtc;
struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ enum pipe pipe = to_intel_plane(plane)->pipe;
unsigned stride;
int ret;
@@ -13687,6 +13766,22 @@ intel_check_cursor_plane(struct drm_plane *plane,
return -EINVAL;
}
+ /*
+ * There's something wrong with the cursor on CHV pipe C.
+ * If it straddles the left edge of the screen then
+ * moving it away from the edge or disabling it often
+ * results in a pipe underrun, and often that can lead to
+ * dead pipe (constant underrun reported, and it scans
+ * out just a solid color). To recover from that, the
+ * display power well must be turned off and on again.
+ * Refuse the put the cursor into that compromised position.
+ */
+ if (IS_CHERRYVIEW(plane->dev) && pipe == PIPE_C &&
+ state->visible && state->base.crtc_x < 0) {
+ DRM_DEBUG_KMS("CHV cursor C not allowed to straddle the left screen edge\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -13710,9 +13805,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
crtc = crtc ? crtc : plane->crtc;
intel_crtc = to_intel_crtc(crtc);
- if (intel_crtc->cursor_bo == obj)
- goto update;
-
if (!obj)
addr = 0;
else if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -13721,9 +13813,7 @@ intel_commit_cursor_plane(struct drm_plane *plane,
addr = obj->phys_handle->busaddr;
intel_crtc->cursor_addr = addr;
- intel_crtc->cursor_bo = obj;
-update:
if (crtc->state->active)
intel_crtc_update_cursor(crtc, state->visible);
}
@@ -14364,16 +14454,17 @@ static int intel_framebuffer_init(struct drm_device *dev,
static struct drm_framebuffer *
intel_user_framebuffer_create(struct drm_device *dev,
struct drm_file *filp,
- struct drm_mode_fb_cmd2 *mode_cmd)
+ struct drm_mode_fb_cmd2 *user_mode_cmd)
{
struct drm_i915_gem_object *obj;
+ struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd;
obj = to_intel_bo(drm_gem_object_lookup(dev, filp,
- mode_cmd->handles[0]));
+ mode_cmd.handles[0]));
if (&obj->base == NULL)
return ERR_PTR(-ENOENT);
- return intel_framebuffer_create(dev, mode_cmd, obj);
+ return intel_framebuffer_create(dev, &mode_cmd, obj);
}
#ifndef CONFIG_DRM_FBDEV_EMULATION
@@ -14705,6 +14796,9 @@ static struct intel_quirk intel_quirks[] = {
/* Apple Macbook 2,1 (Core 2 T7400) */
{ 0x27a2, 0x8086, 0x7270, quirk_backlight_present },
+ /* Apple Macbook 4,1 */
+ { 0x2a02, 0x106b, 0x00a1, quirk_backlight_present },
+
/* Toshiba CB35 Chromebook (Celeron 2955U) */
{ 0x0a06, 0x1179, 0x0a88, quirk_backlight_present },
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 09bdd94..78b8ec8 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -277,7 +277,7 @@ static void pps_lock(struct intel_dp *intel_dp)
* See vlv_power_sequencer_reset() why we need
* a power domain reference here.
*/
- power_domain = intel_display_port_power_domain(encoder);
+ power_domain = intel_display_port_aux_power_domain(encoder);
intel_display_power_get(dev_priv, power_domain);
mutex_lock(&dev_priv->pps_mutex);
@@ -293,7 +293,7 @@ static void pps_unlock(struct intel_dp *intel_dp)
mutex_unlock(&dev_priv->pps_mutex);
- power_domain = intel_display_port_power_domain(encoder);
+ power_domain = intel_display_port_aux_power_domain(encoder);
intel_display_power_put(dev_priv, power_domain);
}
@@ -816,8 +816,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
intel_dp_check_edp(intel_dp);
- intel_aux_display_runtime_get(dev_priv);
-
/* Try to wait for any previous AUX channel activity */
for (try = 0; try < 3; try++) {
status = I915_READ_NOTRACE(ch_ctl);
@@ -926,7 +924,6 @@ done:
ret = recv_bytes;
out:
pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
- intel_aux_display_runtime_put(dev_priv);
if (vdd)
edp_panel_vdd_off(intel_dp, false);
@@ -1784,7 +1781,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp)
if (edp_have_panel_vdd(intel_dp))
return need_to_disable;
- power_domain = intel_display_port_power_domain(intel_encoder);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
intel_display_power_get(dev_priv, power_domain);
DRM_DEBUG_KMS("Turning eDP port %c VDD on\n",
@@ -1874,7 +1871,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
if ((pp & POWER_TARGET_ON) == 0)
intel_dp->last_power_cycle = jiffies;
- power_domain = intel_display_port_power_domain(intel_encoder);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
intel_display_power_put(dev_priv, power_domain);
}
@@ -2025,7 +2022,7 @@ static void edp_panel_off(struct intel_dp *intel_dp)
wait_panel_off(intel_dp);
/* We got a reference when we enabled the VDD. */
- power_domain = intel_display_port_power_domain(intel_encoder);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
intel_display_power_put(dev_priv, power_domain);
}
@@ -4765,26 +4762,6 @@ intel_dp_unset_edid(struct intel_dp *intel_dp)
intel_dp->has_audio = false;
}
-static enum intel_display_power_domain
-intel_dp_power_get(struct intel_dp *dp)
-{
- struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
- enum intel_display_power_domain power_domain;
-
- power_domain = intel_display_port_power_domain(encoder);
- intel_display_power_get(to_i915(encoder->base.dev), power_domain);
-
- return power_domain;
-}
-
-static void
-intel_dp_power_put(struct intel_dp *dp,
- enum intel_display_power_domain power_domain)
-{
- struct intel_encoder *encoder = &dp_to_dig_port(dp)->base;
- intel_display_power_put(to_i915(encoder->base.dev), power_domain);
-}
-
static enum drm_connector_status
intel_dp_detect(struct drm_connector *connector, bool force)
{
@@ -4808,7 +4785,8 @@ intel_dp_detect(struct drm_connector *connector, bool force)
return connector_status_disconnected;
}
- power_domain = intel_dp_power_get(intel_dp);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
+ intel_display_power_get(to_i915(dev), power_domain);
/* Can't disconnect eDP, but you can close the lid... */
if (is_edp(intel_dp))
@@ -4853,7 +4831,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
}
out:
- intel_dp_power_put(intel_dp, power_domain);
+ intel_display_power_put(to_i915(dev), power_domain);
return status;
}
@@ -4862,6 +4840,7 @@ intel_dp_force(struct drm_connector *connector)
{
struct intel_dp *intel_dp = intel_attached_dp(connector);
struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
+ struct drm_i915_private *dev_priv = to_i915(intel_encoder->base.dev);
enum intel_display_power_domain power_domain;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
@@ -4871,11 +4850,12 @@ intel_dp_force(struct drm_connector *connector)
if (connector->status != connector_status_connected)
return;
- power_domain = intel_dp_power_get(intel_dp);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
+ intel_display_power_get(dev_priv, power_domain);
intel_dp_set_edid(intel_dp);
- intel_dp_power_put(intel_dp, power_domain);
+ intel_display_power_put(dev_priv, power_domain);
if (intel_encoder->type != INTEL_OUTPUT_EDP)
intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
@@ -5091,7 +5071,7 @@ static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp)
* indefinitely.
*/
DRM_DEBUG_KMS("VDD left on by BIOS, adjusting state tracking\n");
- power_domain = intel_display_port_power_domain(&intel_dig_port->base);
+ power_domain = intel_display_port_aux_power_domain(&intel_dig_port->base);
intel_display_power_get(dev_priv, power_domain);
edp_panel_vdd_schedule_off(intel_dp);
@@ -5153,7 +5133,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
enum intel_display_power_domain power_domain;
enum irqreturn ret = IRQ_NONE;
- if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
+ if (intel_dig_port->base.type != INTEL_OUTPUT_EDP &&
+ intel_dig_port->base.type != INTEL_OUTPUT_HDMI)
intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
if (long_hpd && intel_dig_port->base.type == INTEL_OUTPUT_EDP) {
@@ -5172,7 +5153,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
port_name(intel_dig_port->port),
long_hpd ? "long" : "short");
- power_domain = intel_display_port_power_domain(intel_encoder);
+ power_domain = intel_display_port_aux_power_domain(intel_encoder);
intel_display_power_get(dev_priv, power_domain);
if (long_hpd) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 0598932..0d00f07 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -550,7 +550,6 @@ struct intel_crtc {
int adjusted_x;
int adjusted_y;
- struct drm_i915_gem_object *cursor_bo;
uint32_t cursor_addr;
uint32_t cursor_cntl;
uint32_t cursor_size;
@@ -1169,6 +1168,8 @@ void hsw_enable_ips(struct intel_crtc *crtc);
void hsw_disable_ips(struct intel_crtc *crtc);
enum intel_display_power_domain
intel_display_port_power_domain(struct intel_encoder *intel_encoder);
+enum intel_display_power_domain
+intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder);
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
struct intel_crtc_state *pipe_config);
void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
@@ -1377,8 +1378,6 @@ void intel_display_power_get(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
void intel_display_power_put(struct drm_i915_private *dev_priv,
enum intel_display_power_domain domain);
-void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
-void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 9eafa19..e6c035b 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1335,21 +1335,17 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
{
struct drm_i915_private *dev_priv = to_i915(connector->dev);
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
- struct intel_encoder *intel_encoder =
- &hdmi_to_dig_port(intel_hdmi)->base;
- enum intel_display_power_domain power_domain;
struct edid *edid = NULL;
bool connected = false;
- power_domain = intel_display_port_power_domain(intel_encoder);
- intel_display_power_get(dev_priv, power_domain);
+ intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
if (force)
edid = drm_get_edid(connector,
intel_gmbus_get_adapter(dev_priv,
intel_hdmi->ddc_bus));
- intel_display_power_put(dev_priv, power_domain);
+ intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
to_intel_connector(connector)->detect_edid = edid;
if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
@@ -1378,15 +1374,18 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
struct drm_i915_private *dev_priv = to_i915(connector->dev);
bool live_status = false;
- unsigned int retry = 3;
+ unsigned int try;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
connector->base.id, connector->name);
- while (!live_status && --retry) {
+ intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
+
+ for (try = 0; !live_status && try < 9; try++) {
+ if (try)
+ msleep(10);
live_status = intel_digital_port_connected(dev_priv,
hdmi_to_dig_port(intel_hdmi));
- mdelay(10);
}
if (!live_status)
@@ -1402,6 +1401,8 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
} else
status = connector_status_disconnected;
+ intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+
return status;
}
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c
index 1369fc4..8324654 100644
--- a/drivers/gpu/drm/i915/intel_i2c.c
+++ b/drivers/gpu/drm/i915/intel_i2c.c
@@ -483,7 +483,7 @@ gmbus_xfer(struct i2c_adapter *adapter,
int i = 0, inc, try = 0;
int ret = 0;
- intel_aux_display_runtime_get(dev_priv);
+ intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
mutex_lock(&dev_priv->gmbus_mutex);
if (bus->force_bit) {
@@ -595,7 +595,9 @@ timeout:
out:
mutex_unlock(&dev_priv->gmbus_mutex);
- intel_aux_display_runtime_put(dev_priv);
+
+ intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
+
return ret;
}
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index d52a15d..f091ad1 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -4449,7 +4449,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
POSTING_READ(GEN6_RPNSWREQ);
dev_priv->rps.cur_freq = val;
- trace_intel_gpu_freq_change(val * 50);
+ trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
}
static void valleyview_set_rps(struct drm_device *dev, u8 val)
@@ -4782,8 +4782,7 @@ static void gen9_enable_rc6(struct drm_device *dev)
/* 2b: Program RC6 thresholds.*/
/* WaRsDoubleRc6WrlWithCoarsePowerGating: Doubling WRL only when CPG is enabled */
- if (IS_SKYLAKE(dev) && !((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) &&
- (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ if (IS_SKYLAKE(dev))
I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 108 << 16);
else
I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 54 << 16);
@@ -4825,7 +4824,7 @@ static void gen9_enable_rc6(struct drm_device *dev)
* WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
*/
if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
- ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_E0)))
+ ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0)))
I915_WRITE(GEN9_PG_ENABLE, 0);
else
I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
@@ -7255,7 +7254,8 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
{
if (IS_GEN9(dev_priv->dev))
- return (val * GT_FREQUENCY_MULTIPLIER) / GEN9_FREQ_SCALER;
+ return DIV_ROUND_CLOSEST(val * GT_FREQUENCY_MULTIPLIER,
+ GEN9_FREQ_SCALER);
else if (IS_CHERRYVIEW(dev_priv->dev))
return chv_gpu_freq(dev_priv, val);
else if (IS_VALLEYVIEW(dev_priv->dev))
@@ -7267,13 +7267,14 @@ int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
{
if (IS_GEN9(dev_priv->dev))
- return (val * GEN9_FREQ_SCALER) / GT_FREQUENCY_MULTIPLIER;
+ return DIV_ROUND_CLOSEST(val * GEN9_FREQ_SCALER,
+ GT_FREQUENCY_MULTIPLIER);
else if (IS_CHERRYVIEW(dev_priv->dev))
return chv_freq_opcode(dev_priv, val);
else if (IS_VALLEYVIEW(dev_priv->dev))
return byt_freq_opcode(dev_priv, val);
else
- return val / GT_FREQUENCY_MULTIPLIER;
+ return DIV_ROUND_CLOSEST(val, GT_FREQUENCY_MULTIPLIER);
}
struct request_boost {
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index d89c1d0..7e23d65 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -362,6 +362,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_AUDIO) | \
BIT(POWER_DOMAIN_VGA) | \
+ BIT(POWER_DOMAIN_GMBUS) | \
BIT(POWER_DOMAIN_INIT))
#define BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS ( \
BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \
@@ -1483,6 +1484,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_AUX_D) | \
+ BIT(POWER_DOMAIN_GMBUS) | \
BIT(POWER_DOMAIN_INIT))
#define HSW_DISPLAY_POWER_DOMAINS ( \
(POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \
@@ -1845,6 +1847,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
i915.disable_power_well = sanitize_disable_power_well_option(dev_priv,
i915.disable_power_well);
+ BUILD_BUG_ON(POWER_DOMAIN_NUM > 31);
+
mutex_init(&power_domains->lock);
/*
@@ -2064,36 +2068,6 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
}
/**
- * intel_aux_display_runtime_get - grab an auxiliary power domain reference
- * @dev_priv: i915 device instance
- *
- * This function grabs a power domain reference for the auxiliary power domain
- * (for access to the GMBUS and DP AUX blocks) and ensures that it and all its
- * parents are powered up. Therefore users should only grab a reference to the
- * innermost power domain they need.
- *
- * Any power domain reference obtained by this function must have a symmetric
- * call to intel_aux_display_runtime_put() to release the reference again.
- */
-void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
-{
- intel_runtime_pm_get(dev_priv);
-}
-
-/**
- * intel_aux_display_runtime_put - release an auxiliary power domain reference
- * @dev_priv: i915 device instance
- *
- * This function drops the auxiliary power domain reference obtained by
- * intel_aux_display_runtime_get() and might power down the corresponding
- * hardware block right away if this is the last reference.
- */
-void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
-{
- intel_runtime_pm_put(dev_priv);
-}
-
-/**
* intel_runtime_pm_get - grab a runtime pm reference
* @dev_priv: i915 device instance
*
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index 64f16ea..7b990b4 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -63,8 +63,7 @@ static void imx_drm_driver_lastclose(struct drm_device *drm)
#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER)
struct imx_drm_device *imxdrm = drm->dev_private;
- if (imxdrm->fbhelper)
- drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
+ drm_fbdev_cma_restore_mode(imxdrm->fbhelper);
#endif
}
@@ -340,7 +339,7 @@ err_kms:
* imx_drm_add_crtc - add a new crtc
*/
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
- struct imx_drm_crtc **new_crtc,
+ struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs,
struct device_node *port)
{
@@ -379,7 +378,7 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
drm_crtc_helper_add(crtc,
imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
- drm_crtc_init(drm, crtc,
+ drm_crtc_init_with_planes(drm, crtc, primary_plane, NULL,
imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
return 0;
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 28e776d..83284b4 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -9,6 +9,7 @@ struct drm_display_mode;
struct drm_encoder;
struct drm_fbdev_cma;
struct drm_framebuffer;
+struct drm_plane;
struct imx_drm_crtc;
struct platform_device;
@@ -24,7 +25,7 @@ struct imx_drm_crtc_helper_funcs {
};
int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
- struct imx_drm_crtc **new_crtc,
+ struct imx_drm_crtc **new_crtc, struct drm_plane *primary_plane,
const struct imx_drm_crtc_helper_funcs *imx_helper_funcs,
struct device_node *port);
int imx_drm_remove_crtc(struct imx_drm_crtc *);
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index e671ad3..f959714 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -721,6 +721,7 @@ static const struct of_device_id imx_tve_dt_ids[] = {
{ .compatible = "fsl,imx53-tve", },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, imx_tve_dt_ids);
static struct platform_driver imx_tve_driver = {
.probe = imx_tve_probe,
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index 7bc8301..4ab841e 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -212,7 +212,8 @@ static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc)
spin_lock_irqsave(&drm->event_lock, flags);
if (ipu_crtc->page_flip_event)
- drm_send_vblank_event(drm, -1, ipu_crtc->page_flip_event);
+ drm_crtc_send_vblank_event(&ipu_crtc->base,
+ ipu_crtc->page_flip_event);
ipu_crtc->page_flip_event = NULL;
imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc);
spin_unlock_irqrestore(&drm->event_lock, flags);
@@ -349,7 +350,6 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent);
int dp = -EINVAL;
int ret;
- int id;
ret = ipu_get_resources(ipu_crtc, pdata);
if (ret) {
@@ -358,18 +358,23 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
return ret;
}
+ if (pdata->dp >= 0)
+ dp = IPU_DP_FLOW_SYNC_BG;
+ ipu_crtc->plane[0] = ipu_plane_init(drm, ipu, pdata->dma[0], dp, 0,
+ DRM_PLANE_TYPE_PRIMARY);
+ if (IS_ERR(ipu_crtc->plane[0])) {
+ ret = PTR_ERR(ipu_crtc->plane[0]);
+ goto err_put_resources;
+ }
+
ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc,
- &ipu_crtc_helper_funcs, ipu_crtc->dev->of_node);
+ &ipu_crtc->plane[0]->base, &ipu_crtc_helper_funcs,
+ ipu_crtc->dev->of_node);
if (ret) {
dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret);
goto err_put_resources;
}
- if (pdata->dp >= 0)
- dp = IPU_DP_FLOW_SYNC_BG;
- id = imx_drm_crtc_id(ipu_crtc->imx_crtc);
- ipu_crtc->plane[0] = ipu_plane_init(ipu_crtc->base.dev, ipu,
- pdata->dma[0], dp, BIT(id), true);
ret = ipu_plane_get_resources(ipu_crtc->plane[0]);
if (ret) {
dev_err(ipu_crtc->dev, "getting plane 0 resources failed with %d.\n",
@@ -379,10 +384,10 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc,
/* If this crtc is using the DP, add an overlay plane */
if (pdata->dp >= 0 && pdata->dma[1] > 0) {
- ipu_crtc->plane[1] = ipu_plane_init(ipu_crtc->base.dev, ipu,
- pdata->dma[1],
- IPU_DP_FLOW_SYNC_FG,
- BIT(id), false);
+ ipu_crtc->plane[1] = ipu_plane_init(drm, ipu, pdata->dma[1],
+ IPU_DP_FLOW_SYNC_FG,
+ drm_crtc_mask(&ipu_crtc->base),
+ DRM_PLANE_TYPE_OVERLAY);
if (IS_ERR(ipu_crtc->plane[1]))
ipu_crtc->plane[1] = NULL;
}
@@ -407,28 +412,6 @@ err_put_resources:
return ret;
}
-static struct device_node *ipu_drm_get_port_by_id(struct device_node *parent,
- int port_id)
-{
- struct device_node *port;
- int id, ret;
-
- port = of_get_child_by_name(parent, "port");
- while (port) {
- ret = of_property_read_u32(port, "reg", &id);
- if (!ret && id == port_id)
- return port;
-
- do {
- port = of_get_next_child(parent, port);
- if (!port)
- return NULL;
- } while (of_node_cmp(port->name, "port"));
- }
-
- return NULL;
-}
-
static int ipu_drm_bind(struct device *dev, struct device *master, void *data)
{
struct ipu_client_platformdata *pdata = dev->platform_data;
@@ -470,23 +453,11 @@ static const struct component_ops ipu_crtc_ops = {
static int ipu_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct ipu_client_platformdata *pdata = dev->platform_data;
int ret;
if (!dev->platform_data)
return -EINVAL;
- if (!dev->of_node) {
- /* Associate crtc device with the corresponding DI port node */
- dev->of_node = ipu_drm_get_port_by_id(dev->parent->of_node,
- pdata->di + 2);
- if (!dev->of_node) {
- dev_err(dev, "missing port@%d node in %s\n",
- pdata->di + 2, dev->parent->of_node->full_name);
- return -ENODEV;
- }
- }
-
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret)
return ret;
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c
index 575f4c8..e2ff410 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.c
+++ b/drivers/gpu/drm/imx/ipuv3-plane.c
@@ -381,7 +381,7 @@ static struct drm_plane_funcs ipu_plane_funcs = {
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
int dma, int dp, unsigned int possible_crtcs,
- bool priv)
+ enum drm_plane_type type)
{
struct ipu_plane *ipu_plane;
int ret;
@@ -399,10 +399,9 @@ struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
ipu_plane->dma = dma;
ipu_plane->dp_flow = dp;
- ret = drm_plane_init(dev, &ipu_plane->base, possible_crtcs,
- &ipu_plane_funcs, ipu_plane_formats,
- ARRAY_SIZE(ipu_plane_formats),
- priv);
+ ret = drm_universal_plane_init(dev, &ipu_plane->base, possible_crtcs,
+ &ipu_plane_funcs, ipu_plane_formats,
+ ARRAY_SIZE(ipu_plane_formats), type);
if (ret) {
DRM_ERROR("failed to initialize plane\n");
kfree(ipu_plane);
diff --git a/drivers/gpu/drm/imx/ipuv3-plane.h b/drivers/gpu/drm/imx/ipuv3-plane.h
index 9b5eff1..3a443b4 100644
--- a/drivers/gpu/drm/imx/ipuv3-plane.h
+++ b/drivers/gpu/drm/imx/ipuv3-plane.h
@@ -34,7 +34,7 @@ struct ipu_plane {
struct ipu_plane *ipu_plane_init(struct drm_device *dev, struct ipu_soc *ipu,
int dma, int dp, unsigned int possible_crtcs,
- bool priv);
+ enum drm_plane_type type);
/* Init IDMAC, DMFC, DP */
int ipu_plane_mode_set(struct ipu_plane *plane, struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index b4deb9c..2e9b9f1 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -54,7 +54,11 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
if (imxpd->panel && imxpd->panel->funcs &&
imxpd->panel->funcs->get_modes) {
+ struct drm_display_info *di = &connector->display_info;
+
num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
+ if (!imxpd->bus_format && di->num_bus_formats)
+ imxpd->bus_format = di->bus_formats[0];
if (num_modes > 0)
return num_modes;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_cursor.c b/drivers/gpu/drm/mgag200/mgag200_cursor.c
index 4f2068f..a7bf6a9 100644
--- a/drivers/gpu/drm/mgag200/mgag200_cursor.c
+++ b/drivers/gpu/drm/mgag200/mgag200_cursor.c
@@ -70,6 +70,11 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
BUG_ON(pixels_2 != pixels_current && pixels_2 != pixels_prev);
BUG_ON(pixels_current == pixels_prev);
+ if (!handle || !file_priv) {
+ mga_hide_cursor(mdev);
+ return 0;
+ }
+
obj = drm_gem_object_lookup(dev, file_priv, handle);
if (!obj)
return -ENOENT;
@@ -88,12 +93,6 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
goto out_unreserve1;
}
- if (!handle) {
- mga_hide_cursor(mdev);
- ret = 0;
- goto out1;
- }
-
/* Move cursor buffers into VRAM if they aren't already */
if (!pixels_1->pin_count) {
ret = mgag200_bo_pin(pixels_1, TTM_PL_FLAG_VRAM,
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
index 8f76000..913192c 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -159,7 +159,6 @@ struct nvkm_device_func {
struct nvkm_device_quirk {
u8 tv_pin_mask;
u8 tv_gpio;
- bool War00C800_0;
};
struct nvkm_device_chip {
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
index 28bc202..40f845e 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
@@ -7,6 +7,7 @@ struct nvkm_instmem {
const struct nvkm_instmem_func *func;
struct nvkm_subdev subdev;
+ spinlock_t lock;
struct list_head list;
u32 reserved;
diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c
index 8b8332e..d5e6938 100644
--- a/drivers/gpu/drm/nouveau/nouveau_acpi.c
+++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c
@@ -367,6 +367,7 @@ static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
return -ENODEV;
}
obj = (union acpi_object *)buffer.pointer;
+ len = min(len, (int)obj->buffer.length);
memcpy(bios+offset, obj->buffer.pointer, len);
kfree(buffer.pointer);
return len;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index db6bc67..64c8d93 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -829,7 +829,6 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
struct drm_device *dev = drm->dev;
struct nouveau_page_flip_state *s;
unsigned long flags;
- int crtcid = -1;
spin_lock_irqsave(&dev->event_lock, flags);
@@ -841,15 +840,19 @@ nouveau_finish_page_flip(struct nouveau_channel *chan,
s = list_first_entry(&fctx->flip, struct nouveau_page_flip_state, head);
if (s->event) {
- /* Vblank timestamps/counts are only correct on >= NV-50 */
- if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA)
- crtcid = s->crtc;
+ if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA) {
+ drm_arm_vblank_event(dev, s->crtc, s->event);
+ } else {
+ drm_send_vblank_event(dev, s->crtc, s->event);
- drm_send_vblank_event(dev, crtcid, s->event);
+ /* Give up ownership of vblank for page-flipped crtc */
+ drm_vblank_put(dev, s->crtc);
+ }
+ }
+ else {
+ /* Give up ownership of vblank for page-flipped crtc */
+ drm_vblank_put(dev, s->crtc);
}
-
- /* Give up ownership of vblank for page-flipped crtc */
- drm_vblank_put(dev, s->crtc);
list_del(&s->head);
if (ps)
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 3050042e..a02813e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -39,6 +39,7 @@
#include <nvif/client.h>
#include <nvif/device.h>
+#include <nvif/ioctl.h>
#include <drmP.h>
@@ -65,9 +66,10 @@ struct nouveau_drm_tile {
};
enum nouveau_drm_object_route {
- NVDRM_OBJECT_NVIF = 0,
+ NVDRM_OBJECT_NVIF = NVIF_IOCTL_V0_OWNER_NVIF,
NVDRM_OBJECT_USIF,
NVDRM_OBJECT_ABI16,
+ NVDRM_OBJECT_ANY = NVIF_IOCTL_V0_OWNER_ANY,
};
enum nouveau_drm_notify_route {
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 3f713c1..d2e7d20 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -353,8 +353,7 @@ nouveau_ttm_init(struct nouveau_drm *drm)
bits = nvxx_mmu(&drm->device)->dma_bits;
if (nvxx_device(&drm->device)->func->pci) {
- if (drm->agp.bridge ||
- !dma_supported(dev->dev, DMA_BIT_MASK(bits)))
+ if (drm->agp.bridge)
bits = 32;
} else if (device->func->tegra) {
struct nvkm_device_tegra *tegra = device->func->tegra(device);
@@ -369,6 +368,10 @@ nouveau_ttm_init(struct nouveau_drm *drm)
}
ret = dma_set_mask(dev->dev, DMA_BIT_MASK(bits));
+ if (ret && bits != 32) {
+ bits = 32;
+ ret = dma_set_mask(dev->dev, DMA_BIT_MASK(bits));
+ }
if (ret)
return ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c
index 89dc4ce..6ae1b34 100644
--- a/drivers/gpu/drm/nouveau/nouveau_usif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_usif.c
@@ -313,7 +313,10 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc)
if (nvif_unpack(argv->v0, 0, 0, true)) {
/* block access to objects not created via this interface */
owner = argv->v0.owner;
- argv->v0.owner = NVDRM_OBJECT_USIF;
+ if (argv->v0.object == 0ULL)
+ argv->v0.owner = NVDRM_OBJECT_ANY; /* except client */
+ else
+ argv->v0.owner = NVDRM_OBJECT_USIF;
} else
goto done;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
index e3c783d..62ad030 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c
@@ -259,12 +259,6 @@ nvkm_device_pci_10de_0df4[] = {
};
static const struct nvkm_device_pci_vendor
-nvkm_device_pci_10de_0fcd[] = {
- { 0x17aa, 0x3801, NULL, { .War00C800_0 = true } }, /* Lenovo Y510P */
- {}
-};
-
-static const struct nvkm_device_pci_vendor
nvkm_device_pci_10de_0fd2[] = {
{ 0x1028, 0x0595, "GeForce GT 640M LE" },
{ 0x1028, 0x05b2, "GeForce GT 640M LE" },
@@ -684,7 +678,6 @@ nvkm_device_pci_10de_1189[] = {
static const struct nvkm_device_pci_vendor
nvkm_device_pci_10de_1199[] = {
{ 0x1458, 0xd001, "GeForce GTX 760" },
- { 0x1462, 0x1106, "GeForce GTX 780M", { .War00C800_0 = true } }, /* Medion Erazer X7827 */
{}
};
@@ -695,14 +688,6 @@ nvkm_device_pci_10de_11e3[] = {
};
static const struct nvkm_device_pci_vendor
-nvkm_device_pci_10de_11fc[] = {
- { 0x1179, 0x0001, NULL, { .War00C800_0 = true } }, /* Toshiba Tecra W50 */
- { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */
- { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */
- {}
-};
-
-static const struct nvkm_device_pci_vendor
nvkm_device_pci_10de_1247[] = {
{ 0x1043, 0x212a, "GeForce GT 635M" },
{ 0x1043, 0x212b, "GeForce GT 635M" },
@@ -1356,7 +1341,7 @@ nvkm_device_pci_10de[] = {
{ 0x0fc6, "GeForce GTX 650" },
{ 0x0fc8, "GeForce GT 740" },
{ 0x0fc9, "GeForce GT 730" },
- { 0x0fcd, "GeForce GT 755M", nvkm_device_pci_10de_0fcd },
+ { 0x0fcd, "GeForce GT 755M" },
{ 0x0fce, "GeForce GT 640M LE" },
{ 0x0fd1, "GeForce GT 650M" },
{ 0x0fd2, "GeForce GT 640M", nvkm_device_pci_10de_0fd2 },
@@ -1490,7 +1475,7 @@ nvkm_device_pci_10de[] = {
{ 0x11e2, "GeForce GTX 765M" },
{ 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 },
{ 0x11fa, "Quadro K4000" },
- { 0x11fc, "Quadro K2100M", nvkm_device_pci_10de_11fc },
+ { 0x11fc, "Quadro K2100M" },
{ 0x1200, "GeForce GTX 560 Ti" },
{ 0x1201, "GeForce GTX 560" },
{ 0x1203, "GeForce GTX 460 SE v2" },
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
index b5b8759..74de7a9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
@@ -207,6 +207,8 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info)
const u32 b = beta * gr->ppc_tpc_nr[gpc][ppc];
const u32 t = timeslice_mode;
const u32 o = PPC_UNIT(gpc, ppc, 0);
+ if (!(gr->ppc_mask[gpc] & (1 << ppc)))
+ continue;
mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc];
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
index 194afe9..7dacb3c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
@@ -52,10 +52,12 @@ mmio_list_base:
#endif
#ifdef INCLUDE_CODE
+#define gpc_addr(reg,addr) /*
+*/ imm32(reg,addr) /*
+*/ or reg NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE
#define gpc_wr32(addr,reg) /*
+*/ gpc_addr($r14,addr) /*
*/ mov b32 $r15 reg /*
-*/ imm32($r14, addr) /*
-*/ or $r14 NV_PGRAPH_GPCX_GPCCS_MMIO_CTRL_BASE_ENABLE /*
*/ call(nv_wr32)
// reports an exception to the host
@@ -161,7 +163,7 @@ init:
#if NV_PGRAPH_GPCX_UNK__SIZE > 0
// figure out which, and how many, UNKs are actually present
- imm32($r14, 0x500c30)
+ gpc_addr($r14, 0x500c30)
clear b32 $r2
clear b32 $r3
clear b32 $r4
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
index 64d07df..bb820ff 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
@@ -314,7 +314,7 @@ uint32_t gf117_grgpc_code[] = {
0x03f01200,
0x0002d000,
0x17f104bd,
- 0x10fe0542,
+ 0x10fe0545,
0x0007f100,
0x0003f007,
0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gf117_grgpc_code[] = {
0x02d00103,
0xf104bd00,
0xf00c30e7,
- 0x24bd50e3,
- 0x44bd34bd,
-/* 0x0430: init_unk_loop */
- 0xb06821f4,
- 0x0bf400f6,
- 0x01f7f00f,
- 0xfd04f2bb,
- 0x30b6054f,
-/* 0x0445: init_unk_next */
- 0x0120b601,
- 0xb004e0b6,
- 0x1bf40126,
-/* 0x0451: init_unk_done */
- 0x070380e2,
- 0xf1080480,
- 0xf0010027,
- 0x22cf0223,
- 0x9534bd00,
- 0x07f10825,
- 0x03f0c000,
- 0x0005d001,
- 0x07f104bd,
- 0x03f0c100,
- 0x0005d001,
- 0x0e9804bd,
- 0x010f9800,
- 0x015021f5,
- 0xbb002fbb,
- 0x0e98003f,
- 0x020f9801,
- 0x015021f5,
- 0xfd050e98,
- 0x2ebb00ef,
- 0x003ebb00,
- 0x98020e98,
- 0x21f5030f,
- 0x0e980150,
- 0x00effd07,
- 0xbb002ebb,
- 0x35b6003e,
- 0x0007f102,
- 0x0103f0d3,
- 0xbd0003d0,
- 0x0825b604,
- 0xb60635b6,
- 0x30b60120,
- 0x0824b601,
- 0xb90834b6,
- 0x21f5022f,
- 0x2fbb02d3,
- 0x003fbb00,
- 0x010007f1,
- 0xd00203f0,
+ 0xe5f050e3,
+ 0xbd24bd01,
+/* 0x0433: init_unk_loop */
+ 0xf444bd34,
+ 0xf6b06821,
+ 0x0f0bf400,
+ 0xbb01f7f0,
+ 0x4ffd04f2,
+ 0x0130b605,
+/* 0x0448: init_unk_next */
+ 0xb60120b6,
+ 0x26b004e0,
+ 0xe21bf401,
+/* 0x0454: init_unk_done */
+ 0x80070380,
+ 0x27f10804,
+ 0x23f00100,
+ 0x0022cf02,
+ 0x259534bd,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0005d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0005d0,
+ 0x000e9804,
+ 0xf5010f98,
+ 0xbb015021,
+ 0x3fbb002f,
+ 0x010e9800,
+ 0xf5020f98,
+ 0x98015021,
+ 0xeffd050e,
+ 0x002ebb00,
+ 0x98003ebb,
+ 0x0f98020e,
+ 0x5021f503,
+ 0x070e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x0235b600,
+ 0xd30007f1,
+ 0xd00103f0,
0x04bd0003,
- 0x29f024bd,
- 0x0007f11f,
- 0x0203f008,
- 0xbd0002d0,
-/* 0x0505: main */
- 0x0031f404,
- 0xf00028f4,
- 0x21f424d7,
- 0xf401f439,
- 0xf404e4b0,
- 0x81fe1e18,
- 0x0627f001,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x21f50018,
- 0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
- 0x10ef94d3,
- 0xf501f5f0,
- 0xf4037e21,
-/* 0x0542: ih */
- 0x80f9c60e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0xf104bdf0,
- 0xf00200a7,
- 0xaacf00a3,
- 0x04abc400,
- 0xf02c0bf4,
- 0xe7f124d7,
- 0xe3f01a00,
- 0x00eecf00,
- 0x1900f7f1,
- 0xcf00f3f0,
- 0x21f400ff,
- 0x01e7f004,
- 0x1d0007f1,
- 0xd00003f0,
- 0x04bd000e,
-/* 0x0590: ih_no_fifo */
- 0x010007f1,
- 0xd00003f0,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x05b4: hub_barrier_done */
- 0x9801f7f0,
- 0xfebb040e,
- 0x02ffb904,
- 0x9418e7f1,
- 0xf440e3f0,
- 0x00f89d21,
-/* 0x05cc: ctx_redswitch */
- 0xf120f7f0,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb90834,
+ 0xd321f502,
+ 0x002fbb02,
+ 0xf1003fbb,
+ 0xf0010007,
+ 0x03d00203,
+ 0xbd04bd00,
+ 0x1f29f024,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+/* 0x0508: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f424,
+ 0xb0f401f4,
+ 0x18f404e4,
+ 0x0181fe1e,
+ 0xbd0627f0,
+ 0x0412fd20,
+ 0xfd01e4b6,
+ 0x18fe051e,
+ 0xfd21f500,
+ 0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+ 0xf010ef94,
+ 0x21f501f5,
+ 0x0ef4037e,
+/* 0x0545: ih */
+ 0xfe80f9c6,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0xa7f104bd,
+ 0xa3f00200,
+ 0x00aacf00,
+ 0xf404abc4,
+ 0xd7f02c0b,
+ 0x00e7f124,
+ 0x00e3f01a,
+ 0xf100eecf,
+ 0xf01900f7,
+ 0xffcf00f3,
+ 0x0421f400,
+ 0xf101e7f0,
+ 0xf01d0007,
+ 0x0ed00003,
+/* 0x0593: ih_no_fifo */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+ 0xf001f800,
+ 0x0e9801f7,
+ 0x04febb04,
+ 0xf102ffb9,
+ 0xf09418e7,
+ 0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+ 0xf000f89d,
+ 0x07f120f7,
+ 0x03f08500,
+ 0x000fd001,
+ 0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+ 0x01e2b608,
+ 0xf1fd1bf4,
+ 0xf10800f5,
+ 0xf10200f5,
0xf0850007,
0x0fd00103,
- 0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
- 0xe2b608e7,
- 0xfd1bf401,
- 0x0800f5f1,
- 0x0200f5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000f,
-/* 0x05fa: ctx_xfer */
- 0x07f100f8,
- 0x03f08100,
- 0x000fd002,
- 0x11f404bd,
- 0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
- 0x6a21f505,
- 0xf124bd02,
- 0xf047fc07,
- 0x02d00203,
- 0xf004bd00,
- 0x20b6012c,
- 0xfc07f103,
- 0x0203f04a,
- 0xbd0002d0,
- 0x01acf004,
- 0xf102a5f0,
- 0xf00000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf101acf0,
- 0xf04000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98010c,
- 0x060f9802,
- 0x0800e7f1,
- 0x016f21f5,
+ 0xf804bd00,
+/* 0x05fd: ctx_xfer */
+ 0x0007f100,
+ 0x0203f081,
+ 0xbd000fd0,
+ 0x0711f404,
+ 0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+ 0x026a21f5,
+ 0x07f124bd,
+ 0x03f047fc,
+ 0x0002d002,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
0xf001acf0,
- 0xb7f104a5,
- 0xb3f03000,
+ 0xb7f102a5,
+ 0xb3f00000,
0x040c9850,
0xbb0fc4b6,
0x0c9800bc,
- 0x030d9802,
- 0xf1080f98,
- 0xf50200e7,
- 0xf5016f21,
- 0xf4025e21,
- 0x12f40601,
-/* 0x06a9: ctx_xfer_post */
- 0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
- 0xb421f502,
- 0x0000f805,
- 0x00000000,
+ 0x010d9800,
+ 0xf500e7f0,
+ 0xf0016f21,
+ 0xb7f101ac,
+ 0xb3f04000,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0xf1060f98,
+ 0xf50800e7,
+ 0xf0016f21,
+ 0xa5f001ac,
+ 0x00b7f104,
+ 0x50b3f030,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x020c9800,
+ 0x98030d98,
+ 0xe7f1080f,
+ 0x21f50200,
+ 0x21f5016f,
+ 0x01f4025e,
+ 0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+ 0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+ 0x05b721f5,
+ 0x000000f8,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
index 2f59643..911976d 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
@@ -314,7 +314,7 @@ uint32_t gk104_grgpc_code[] = {
0x03f01200,
0x0002d000,
0x17f104bd,
- 0x10fe0542,
+ 0x10fe0545,
0x0007f100,
0x0003f007,
0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gk104_grgpc_code[] = {
0x02d00103,
0xf104bd00,
0xf00c30e7,
- 0x24bd50e3,
- 0x44bd34bd,
-/* 0x0430: init_unk_loop */
- 0xb06821f4,
- 0x0bf400f6,
- 0x01f7f00f,
- 0xfd04f2bb,
- 0x30b6054f,
-/* 0x0445: init_unk_next */
- 0x0120b601,
- 0xb004e0b6,
- 0x1bf40126,
-/* 0x0451: init_unk_done */
- 0x070380e2,
- 0xf1080480,
- 0xf0010027,
- 0x22cf0223,
- 0x9534bd00,
- 0x07f10825,
- 0x03f0c000,
- 0x0005d001,
- 0x07f104bd,
- 0x03f0c100,
- 0x0005d001,
- 0x0e9804bd,
- 0x010f9800,
- 0x015021f5,
- 0xbb002fbb,
- 0x0e98003f,
- 0x020f9801,
- 0x015021f5,
- 0xfd050e98,
- 0x2ebb00ef,
- 0x003ebb00,
- 0x98020e98,
- 0x21f5030f,
- 0x0e980150,
- 0x00effd07,
- 0xbb002ebb,
- 0x35b6003e,
- 0x0007f102,
- 0x0103f0d3,
- 0xbd0003d0,
- 0x0825b604,
- 0xb60635b6,
- 0x30b60120,
- 0x0824b601,
- 0xb90834b6,
- 0x21f5022f,
- 0x2fbb02d3,
- 0x003fbb00,
- 0x010007f1,
- 0xd00203f0,
+ 0xe5f050e3,
+ 0xbd24bd01,
+/* 0x0433: init_unk_loop */
+ 0xf444bd34,
+ 0xf6b06821,
+ 0x0f0bf400,
+ 0xbb01f7f0,
+ 0x4ffd04f2,
+ 0x0130b605,
+/* 0x0448: init_unk_next */
+ 0xb60120b6,
+ 0x26b004e0,
+ 0xe21bf401,
+/* 0x0454: init_unk_done */
+ 0x80070380,
+ 0x27f10804,
+ 0x23f00100,
+ 0x0022cf02,
+ 0x259534bd,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0005d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0005d0,
+ 0x000e9804,
+ 0xf5010f98,
+ 0xbb015021,
+ 0x3fbb002f,
+ 0x010e9800,
+ 0xf5020f98,
+ 0x98015021,
+ 0xeffd050e,
+ 0x002ebb00,
+ 0x98003ebb,
+ 0x0f98020e,
+ 0x5021f503,
+ 0x070e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x0235b600,
+ 0xd30007f1,
+ 0xd00103f0,
0x04bd0003,
- 0x29f024bd,
- 0x0007f11f,
- 0x0203f008,
- 0xbd0002d0,
-/* 0x0505: main */
- 0x0031f404,
- 0xf00028f4,
- 0x21f424d7,
- 0xf401f439,
- 0xf404e4b0,
- 0x81fe1e18,
- 0x0627f001,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x21f50018,
- 0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
- 0x10ef94d3,
- 0xf501f5f0,
- 0xf4037e21,
-/* 0x0542: ih */
- 0x80f9c60e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0xf104bdf0,
- 0xf00200a7,
- 0xaacf00a3,
- 0x04abc400,
- 0xf02c0bf4,
- 0xe7f124d7,
- 0xe3f01a00,
- 0x00eecf00,
- 0x1900f7f1,
- 0xcf00f3f0,
- 0x21f400ff,
- 0x01e7f004,
- 0x1d0007f1,
- 0xd00003f0,
- 0x04bd000e,
-/* 0x0590: ih_no_fifo */
- 0x010007f1,
- 0xd00003f0,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x05b4: hub_barrier_done */
- 0x9801f7f0,
- 0xfebb040e,
- 0x02ffb904,
- 0x9418e7f1,
- 0xf440e3f0,
- 0x00f89d21,
-/* 0x05cc: ctx_redswitch */
- 0xf120f7f0,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb90834,
+ 0xd321f502,
+ 0x002fbb02,
+ 0xf1003fbb,
+ 0xf0010007,
+ 0x03d00203,
+ 0xbd04bd00,
+ 0x1f29f024,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+/* 0x0508: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f424,
+ 0xb0f401f4,
+ 0x18f404e4,
+ 0x0181fe1e,
+ 0xbd0627f0,
+ 0x0412fd20,
+ 0xfd01e4b6,
+ 0x18fe051e,
+ 0xfd21f500,
+ 0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+ 0xf010ef94,
+ 0x21f501f5,
+ 0x0ef4037e,
+/* 0x0545: ih */
+ 0xfe80f9c6,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0xa7f104bd,
+ 0xa3f00200,
+ 0x00aacf00,
+ 0xf404abc4,
+ 0xd7f02c0b,
+ 0x00e7f124,
+ 0x00e3f01a,
+ 0xf100eecf,
+ 0xf01900f7,
+ 0xffcf00f3,
+ 0x0421f400,
+ 0xf101e7f0,
+ 0xf01d0007,
+ 0x0ed00003,
+/* 0x0593: ih_no_fifo */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+ 0xf001f800,
+ 0x0e9801f7,
+ 0x04febb04,
+ 0xf102ffb9,
+ 0xf09418e7,
+ 0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+ 0xf000f89d,
+ 0x07f120f7,
+ 0x03f08500,
+ 0x000fd001,
+ 0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+ 0x01e2b608,
+ 0xf1fd1bf4,
+ 0xf10800f5,
+ 0xf10200f5,
0xf0850007,
0x0fd00103,
- 0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
- 0xe2b608e7,
- 0xfd1bf401,
- 0x0800f5f1,
- 0x0200f5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000f,
-/* 0x05fa: ctx_xfer */
- 0x07f100f8,
- 0x03f08100,
- 0x000fd002,
- 0x11f404bd,
- 0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
- 0x6a21f505,
- 0xf124bd02,
- 0xf047fc07,
- 0x02d00203,
- 0xf004bd00,
- 0x20b6012c,
- 0xfc07f103,
- 0x0203f04a,
- 0xbd0002d0,
- 0x01acf004,
- 0xf102a5f0,
- 0xf00000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf101acf0,
- 0xf04000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98010c,
- 0x060f9802,
- 0x0800e7f1,
- 0x016f21f5,
+ 0xf804bd00,
+/* 0x05fd: ctx_xfer */
+ 0x0007f100,
+ 0x0203f081,
+ 0xbd000fd0,
+ 0x0711f404,
+ 0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+ 0x026a21f5,
+ 0x07f124bd,
+ 0x03f047fc,
+ 0x0002d002,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
0xf001acf0,
- 0xb7f104a5,
- 0xb3f03000,
+ 0xb7f102a5,
+ 0xb3f00000,
0x040c9850,
0xbb0fc4b6,
0x0c9800bc,
- 0x030d9802,
- 0xf1080f98,
- 0xf50200e7,
- 0xf5016f21,
- 0xf4025e21,
- 0x12f40601,
-/* 0x06a9: ctx_xfer_post */
- 0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
- 0xb421f502,
- 0x0000f805,
- 0x00000000,
+ 0x010d9800,
+ 0xf500e7f0,
+ 0xf0016f21,
+ 0xb7f101ac,
+ 0xb3f04000,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0xf1060f98,
+ 0xf50800e7,
+ 0xf0016f21,
+ 0xa5f001ac,
+ 0x00b7f104,
+ 0x50b3f030,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x020c9800,
+ 0x98030d98,
+ 0xe7f1080f,
+ 0x21f50200,
+ 0x21f5016f,
+ 0x01f4025e,
+ 0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+ 0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+ 0x05b721f5,
+ 0x000000f8,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
index ee8e54d..1c6e11b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
@@ -314,7 +314,7 @@ uint32_t gk110_grgpc_code[] = {
0x03f01200,
0x0002d000,
0x17f104bd,
- 0x10fe0542,
+ 0x10fe0545,
0x0007f100,
0x0003f007,
0xbd0000d0,
@@ -338,184 +338,184 @@ uint32_t gk110_grgpc_code[] = {
0x02d00103,
0xf104bd00,
0xf00c30e7,
- 0x24bd50e3,
- 0x44bd34bd,
-/* 0x0430: init_unk_loop */
- 0xb06821f4,
- 0x0bf400f6,
- 0x01f7f00f,
- 0xfd04f2bb,
- 0x30b6054f,
-/* 0x0445: init_unk_next */
- 0x0120b601,
- 0xb004e0b6,
- 0x1bf40226,
-/* 0x0451: init_unk_done */
- 0x070380e2,
- 0xf1080480,
- 0xf0010027,
- 0x22cf0223,
- 0x9534bd00,
- 0x07f10825,
- 0x03f0c000,
- 0x0005d001,
- 0x07f104bd,
- 0x03f0c100,
- 0x0005d001,
- 0x0e9804bd,
- 0x010f9800,
- 0x015021f5,
- 0xbb002fbb,
- 0x0e98003f,
- 0x020f9801,
- 0x015021f5,
- 0xfd050e98,
- 0x2ebb00ef,
- 0x003ebb00,
- 0x98020e98,
- 0x21f5030f,
- 0x0e980150,
- 0x00effd07,
- 0xbb002ebb,
- 0x35b6003e,
- 0x0007f102,
- 0x0103f0d3,
- 0xbd0003d0,
- 0x0825b604,
- 0xb60635b6,
- 0x30b60120,
- 0x0824b601,
- 0xb90834b6,
- 0x21f5022f,
- 0x2fbb02d3,
- 0x003fbb00,
- 0x010007f1,
- 0xd00203f0,
+ 0xe5f050e3,
+ 0xbd24bd01,
+/* 0x0433: init_unk_loop */
+ 0xf444bd34,
+ 0xf6b06821,
+ 0x0f0bf400,
+ 0xbb01f7f0,
+ 0x4ffd04f2,
+ 0x0130b605,
+/* 0x0448: init_unk_next */
+ 0xb60120b6,
+ 0x26b004e0,
+ 0xe21bf402,
+/* 0x0454: init_unk_done */
+ 0x80070380,
+ 0x27f10804,
+ 0x23f00100,
+ 0x0022cf02,
+ 0x259534bd,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0005d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0005d0,
+ 0x000e9804,
+ 0xf5010f98,
+ 0xbb015021,
+ 0x3fbb002f,
+ 0x010e9800,
+ 0xf5020f98,
+ 0x98015021,
+ 0xeffd050e,
+ 0x002ebb00,
+ 0x98003ebb,
+ 0x0f98020e,
+ 0x5021f503,
+ 0x070e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x0235b600,
+ 0xd30007f1,
+ 0xd00103f0,
0x04bd0003,
- 0x29f024bd,
- 0x0007f11f,
- 0x0203f030,
- 0xbd0002d0,
-/* 0x0505: main */
- 0x0031f404,
- 0xf00028f4,
- 0x21f424d7,
- 0xf401f439,
- 0xf404e4b0,
- 0x81fe1e18,
- 0x0627f001,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x21f50018,
- 0x0ef405fa,
-/* 0x0535: main_not_ctx_xfer */
- 0x10ef94d3,
- 0xf501f5f0,
- 0xf4037e21,
-/* 0x0542: ih */
- 0x80f9c60e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0xf104bdf0,
- 0xf00200a7,
- 0xaacf00a3,
- 0x04abc400,
- 0xf02c0bf4,
- 0xe7f124d7,
- 0xe3f01a00,
- 0x00eecf00,
- 0x1900f7f1,
- 0xcf00f3f0,
- 0x21f400ff,
- 0x01e7f004,
- 0x1d0007f1,
- 0xd00003f0,
- 0x04bd000e,
-/* 0x0590: ih_no_fifo */
- 0x010007f1,
- 0xd00003f0,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x05b4: hub_barrier_done */
- 0x9801f7f0,
- 0xfebb040e,
- 0x02ffb904,
- 0x9418e7f1,
- 0xf440e3f0,
- 0x00f89d21,
-/* 0x05cc: ctx_redswitch */
- 0xf120f7f0,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb90834,
+ 0xd321f502,
+ 0x002fbb02,
+ 0xf1003fbb,
+ 0xf0010007,
+ 0x03d00203,
+ 0xbd04bd00,
+ 0x1f29f024,
+ 0x300007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+/* 0x0508: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f424,
+ 0xb0f401f4,
+ 0x18f404e4,
+ 0x0181fe1e,
+ 0xbd0627f0,
+ 0x0412fd20,
+ 0xfd01e4b6,
+ 0x18fe051e,
+ 0xfd21f500,
+ 0xd30ef405,
+/* 0x0538: main_not_ctx_xfer */
+ 0xf010ef94,
+ 0x21f501f5,
+ 0x0ef4037e,
+/* 0x0545: ih */
+ 0xfe80f9c6,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0xa7f104bd,
+ 0xa3f00200,
+ 0x00aacf00,
+ 0xf404abc4,
+ 0xd7f02c0b,
+ 0x00e7f124,
+ 0x00e3f01a,
+ 0xf100eecf,
+ 0xf01900f7,
+ 0xffcf00f3,
+ 0x0421f400,
+ 0xf101e7f0,
+ 0xf01d0007,
+ 0x0ed00003,
+/* 0x0593: ih_no_fifo */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x05b7: hub_barrier_done */
+ 0xf001f800,
+ 0x0e9801f7,
+ 0x04febb04,
+ 0xf102ffb9,
+ 0xf09418e7,
+ 0x21f440e3,
+/* 0x05cf: ctx_redswitch */
+ 0xf000f89d,
+ 0x07f120f7,
+ 0x03f08500,
+ 0x000fd001,
+ 0xe7f004bd,
+/* 0x05e1: ctx_redswitch_delay */
+ 0x01e2b608,
+ 0xf1fd1bf4,
+ 0xf10800f5,
+ 0xf10200f5,
0xf0850007,
0x0fd00103,
- 0xf004bd00,
-/* 0x05de: ctx_redswitch_delay */
- 0xe2b608e7,
- 0xfd1bf401,
- 0x0800f5f1,
- 0x0200f5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000f,
-/* 0x05fa: ctx_xfer */
- 0x07f100f8,
- 0x03f08100,
- 0x000fd002,
- 0x11f404bd,
- 0xcc21f507,
-/* 0x060d: ctx_xfer_not_load */
- 0x6a21f505,
- 0xf124bd02,
- 0xf047fc07,
- 0x02d00203,
- 0xf004bd00,
- 0x20b6012c,
- 0xfc07f103,
- 0x0203f04a,
- 0xbd0002d0,
- 0x01acf004,
- 0xf102a5f0,
- 0xf00000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf101acf0,
- 0xf04000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98010c,
- 0x060f9802,
- 0x0800e7f1,
- 0x016f21f5,
+ 0xf804bd00,
+/* 0x05fd: ctx_xfer */
+ 0x0007f100,
+ 0x0203f081,
+ 0xbd000fd0,
+ 0x0711f404,
+ 0x05cf21f5,
+/* 0x0610: ctx_xfer_not_load */
+ 0x026a21f5,
+ 0x07f124bd,
+ 0x03f047fc,
+ 0x0002d002,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
0xf001acf0,
- 0xb7f104a5,
- 0xb3f03000,
+ 0xb7f102a5,
+ 0xb3f00000,
0x040c9850,
0xbb0fc4b6,
0x0c9800bc,
- 0x030d9802,
- 0xf1080f98,
- 0xf50200e7,
- 0xf5016f21,
- 0xf4025e21,
- 0x12f40601,
-/* 0x06a9: ctx_xfer_post */
- 0x7f21f507,
-/* 0x06ad: ctx_xfer_done */
- 0xb421f502,
- 0x0000f805,
- 0x00000000,
+ 0x010d9800,
+ 0xf500e7f0,
+ 0xf0016f21,
+ 0xb7f101ac,
+ 0xb3f04000,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0xf1060f98,
+ 0xf50800e7,
+ 0xf0016f21,
+ 0xa5f001ac,
+ 0x00b7f104,
+ 0x50b3f030,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x020c9800,
+ 0x98030d98,
+ 0xe7f1080f,
+ 0x21f50200,
+ 0x21f5016f,
+ 0x01f4025e,
+ 0x0712f406,
+/* 0x06ac: ctx_xfer_post */
+ 0x027f21f5,
+/* 0x06b0: ctx_xfer_done */
+ 0x05b721f5,
+ 0x000000f8,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
index fbcc342..84af7ec 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
@@ -276,7 +276,7 @@ uint32_t gk208_grgpc_code[] = {
0x02020014,
0xf6120040,
0x04bd0002,
- 0xfe048141,
+ 0xfe048441,
0x00400010,
0x0000f607,
0x040204bd,
@@ -295,165 +295,165 @@ uint32_t gk208_grgpc_code[] = {
0x01c90080,
0xbd0002f6,
0x0c308e04,
- 0xbd24bd50,
-/* 0x0383: init_unk_loop */
- 0x7e44bd34,
- 0xb0000065,
- 0x0bf400f6,
- 0xbb010f0e,
- 0x4ffd04f2,
- 0x0130b605,
-/* 0x0398: init_unk_next */
- 0xb60120b6,
- 0x26b004e0,
- 0xe21bf401,
-/* 0x03a4: init_unk_done */
- 0xb50703b5,
- 0x00820804,
- 0x22cf0201,
- 0x9534bd00,
- 0x00800825,
- 0x05f601c0,
- 0x8004bd00,
- 0xf601c100,
- 0x04bd0005,
- 0x98000e98,
- 0x207e010f,
- 0x2fbb0001,
- 0x003fbb00,
- 0x98010e98,
- 0x207e020f,
- 0x0e980001,
- 0x00effd05,
- 0xbb002ebb,
- 0x0e98003e,
- 0x030f9802,
- 0x0001207e,
- 0xfd070e98,
- 0x2ebb00ef,
- 0x003ebb00,
- 0x800235b6,
- 0xf601d300,
- 0x04bd0003,
- 0xb60825b6,
- 0x20b60635,
- 0x0130b601,
- 0xb60824b6,
- 0x2fb20834,
- 0x0002687e,
- 0xbb002fbb,
- 0x0080003f,
- 0x03f60201,
- 0xbd04bd00,
- 0x1f29f024,
- 0x02300080,
- 0xbd0002f6,
-/* 0x0445: main */
- 0x0031f404,
- 0x0d0028f4,
- 0x00377e24,
- 0xf401f400,
- 0xf404e4b0,
- 0x81fe1d18,
- 0xbd060201,
- 0x0412fd20,
- 0xfd01e4b6,
- 0x18fe051e,
- 0x05187e00,
- 0xd40ef400,
-/* 0x0474: main_not_ctx_xfer */
- 0xf010ef94,
- 0xf87e01f5,
- 0x0ef40002,
-/* 0x0481: ih */
- 0xfe80f9c7,
- 0x80f90188,
- 0xa0f990f9,
- 0xd0f9b0f9,
- 0xf0f9e0f9,
- 0x004a04bd,
- 0x00aacf02,
- 0xf404abc4,
- 0x240d1f0b,
- 0xcf1a004e,
- 0x004f00ee,
- 0x00ffcf19,
- 0x0000047e,
- 0x0040010e,
- 0x000ef61d,
-/* 0x04be: ih_no_fifo */
- 0x004004bd,
- 0x000af601,
- 0xf0fc04bd,
- 0xd0fce0fc,
- 0xa0fcb0fc,
- 0x80fc90fc,
- 0xfc0088fe,
- 0x0032f480,
-/* 0x04de: hub_barrier_done */
- 0x010f01f8,
- 0xbb040e98,
- 0xffb204fe,
- 0x4094188e,
- 0x00008f7e,
-/* 0x04f2: ctx_redswitch */
- 0x200f00f8,
+ 0x01e5f050,
+ 0x34bd24bd,
+/* 0x0386: init_unk_loop */
+ 0x657e44bd,
+ 0xf6b00000,
+ 0x0e0bf400,
+ 0xf2bb010f,
+ 0x054ffd04,
+/* 0x039b: init_unk_next */
+ 0xb60130b6,
+ 0xe0b60120,
+ 0x0126b004,
+/* 0x03a7: init_unk_done */
+ 0xb5e21bf4,
+ 0x04b50703,
+ 0x01008208,
+ 0x0022cf02,
+ 0x259534bd,
+ 0xc0008008,
+ 0x0005f601,
+ 0x008004bd,
+ 0x05f601c1,
+ 0x9804bd00,
+ 0x0f98000e,
+ 0x01207e01,
+ 0x002fbb00,
+ 0x98003fbb,
+ 0x0f98010e,
+ 0x01207e02,
+ 0x050e9800,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x020e9800,
+ 0x7e030f98,
+ 0x98000120,
+ 0xeffd070e,
+ 0x002ebb00,
+ 0xb6003ebb,
+ 0x00800235,
+ 0x03f601d3,
+ 0xb604bd00,
+ 0x35b60825,
+ 0x0120b606,
+ 0xb60130b6,
+ 0x34b60824,
+ 0x7e2fb208,
+ 0xbb000268,
+ 0x3fbb002f,
+ 0x01008000,
+ 0x0003f602,
+ 0x24bd04bd,
+ 0x801f29f0,
+ 0xf6023000,
+ 0x04bd0002,
+/* 0x0448: main */
+ 0xf40031f4,
+ 0x240d0028,
+ 0x0000377e,
+ 0xb0f401f4,
+ 0x18f404e4,
+ 0x0181fe1d,
+ 0x20bd0602,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x00051b7e,
+/* 0x0477: main_not_ctx_xfer */
+ 0x94d40ef4,
+ 0xf5f010ef,
+ 0x02f87e01,
+ 0xc70ef400,
+/* 0x0484: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x02004a04,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x4e240d1f,
+ 0xeecf1a00,
+ 0x19004f00,
+ 0x7e00ffcf,
+ 0x0e000004,
+ 0x1d004001,
+ 0xbd000ef6,
+/* 0x04c1: ih_no_fifo */
+ 0x01004004,
+ 0xbd000af6,
+ 0xfcf0fc04,
+ 0xfcd0fce0,
+ 0xfca0fcb0,
+ 0xfe80fc90,
+ 0x80fc0088,
+ 0xf80032f4,
+/* 0x04e1: hub_barrier_done */
+ 0x98010f01,
+ 0xfebb040e,
+ 0x8effb204,
+ 0x7e409418,
+ 0xf800008f,
+/* 0x04f5: ctx_redswitch */
+ 0x80200f00,
+ 0xf6018500,
+ 0x04bd000f,
+/* 0x0502: ctx_redswitch_delay */
+ 0xe2b6080e,
+ 0xfd1bf401,
+ 0x0800f5f1,
+ 0x0200f5f1,
0x01850080,
0xbd000ff6,
-/* 0x04ff: ctx_redswitch_delay */
- 0xb6080e04,
- 0x1bf401e2,
- 0x00f5f1fd,
- 0x00f5f108,
- 0x85008002,
- 0x000ff601,
- 0x00f804bd,
-/* 0x0518: ctx_xfer */
- 0x02810080,
- 0xbd000ff6,
- 0x0711f404,
- 0x0004f27e,
-/* 0x0528: ctx_xfer_not_load */
- 0x0002167e,
- 0xfc8024bd,
- 0x02f60247,
- 0xf004bd00,
- 0x20b6012c,
- 0x4afc8003,
+/* 0x051b: ctx_xfer */
+ 0x8000f804,
+ 0xf6028100,
+ 0x04bd000f,
+ 0x7e0711f4,
+/* 0x052b: ctx_xfer_not_load */
+ 0x7e0004f5,
+ 0xbd000216,
+ 0x47fc8024,
0x0002f602,
- 0xacf004bd,
- 0x02a5f001,
- 0x5000008b,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x000c9800,
- 0x0e010d98,
- 0x013d7e00,
- 0x01acf000,
- 0x5040008b,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x010c9800,
- 0x98020d98,
- 0x004e060f,
- 0x013d7e08,
- 0x01acf000,
- 0x8b04a5f0,
- 0x98503000,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x024afc80,
+ 0xbd0002f6,
+ 0x01acf004,
+ 0x8b02a5f0,
+ 0x98500000,
0xc4b6040c,
0x00bcbb0f,
- 0x98020c98,
- 0x0f98030d,
- 0x02004e08,
+ 0x98000c98,
+ 0x000e010d,
0x00013d7e,
- 0x00020a7e,
- 0xf40601f4,
-/* 0x05b2: ctx_xfer_post */
- 0x277e0712,
-/* 0x05b6: ctx_xfer_done */
- 0xde7e0002,
- 0x00f80004,
- 0x00000000,
+ 0x8b01acf0,
+ 0x98504000,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98010c98,
+ 0x0f98020d,
+ 0x08004e06,
+ 0x00013d7e,
+ 0xf001acf0,
+ 0x008b04a5,
+ 0x0c985030,
+ 0x0fc4b604,
+ 0x9800bcbb,
+ 0x0d98020c,
+ 0x080f9803,
+ 0x7e02004e,
+ 0x7e00013d,
+ 0xf400020a,
+ 0x12f40601,
+/* 0x05b5: ctx_xfer_post */
+ 0x02277e07,
+/* 0x05b9: ctx_xfer_done */
+ 0x04e17e00,
+ 0x0000f800,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
index 51f5c3c..11bf363 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
@@ -289,7 +289,7 @@ uint32_t gm107_grgpc_code[] = {
0x020014fe,
0x12004002,
0xbd0002f6,
- 0x05b04104,
+ 0x05b34104,
0x400010fe,
0x00f60700,
0x0204bd00,
@@ -308,259 +308,259 @@ uint32_t gm107_grgpc_code[] = {
0xc900800f,
0x0002f601,
0x308e04bd,
- 0x24bd500c,
- 0x44bd34bd,
-/* 0x03b0: init_unk_loop */
- 0x0000657e,
- 0xf400f6b0,
- 0x010f0e0b,
- 0xfd04f2bb,
- 0x30b6054f,
-/* 0x03c5: init_unk_next */
- 0x0120b601,
- 0xb004e0b6,
- 0x1bf40226,
-/* 0x03d1: init_unk_done */
- 0x0703b5e2,
- 0x820804b5,
- 0xcf020100,
- 0x34bd0022,
- 0x80082595,
- 0xf601c000,
+ 0xe5f0500c,
+ 0xbd24bd01,
+/* 0x03b3: init_unk_loop */
+ 0x7e44bd34,
+ 0xb0000065,
+ 0x0bf400f6,
+ 0xbb010f0e,
+ 0x4ffd04f2,
+ 0x0130b605,
+/* 0x03c8: init_unk_next */
+ 0xb60120b6,
+ 0x26b004e0,
+ 0xe21bf402,
+/* 0x03d4: init_unk_done */
+ 0xb50703b5,
+ 0x00820804,
+ 0x22cf0201,
+ 0x9534bd00,
+ 0x00800825,
+ 0x05f601c0,
+ 0x8004bd00,
+ 0xf601c100,
0x04bd0005,
- 0x01c10080,
- 0xbd0005f6,
- 0x000e9804,
- 0x7e010f98,
- 0xbb000120,
- 0x3fbb002f,
- 0x010e9800,
- 0x7e020f98,
- 0x98000120,
- 0xeffd050e,
- 0x002ebb00,
- 0x98003ebb,
- 0x0f98020e,
- 0x01207e03,
- 0x070e9800,
- 0xbb00effd,
- 0x3ebb002e,
- 0x0235b600,
- 0x01d30080,
- 0xbd0003f6,
- 0x0825b604,
- 0xb60635b6,
- 0x30b60120,
- 0x0824b601,
- 0xb20834b6,
- 0x02687e2f,
- 0x002fbb00,
- 0x0f003fbb,
- 0x8effb23f,
- 0xf0501d60,
- 0x8f7e01e5,
- 0x0c0f0000,
- 0xa88effb2,
- 0xe5f0501d,
- 0x008f7e01,
- 0x03147e00,
- 0xb23f0f00,
- 0x1d608eff,
- 0x01e5f050,
- 0x00008f7e,
- 0xffb2000f,
- 0x501d9c8e,
- 0x7e01e5f0,
- 0x0f00008f,
- 0x03147e01,
- 0x8effb200,
+ 0x98000e98,
+ 0x207e010f,
+ 0x2fbb0001,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x207e020f,
+ 0x0e980001,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x0e98003e,
+ 0x030f9802,
+ 0x0001207e,
+ 0xfd070e98,
+ 0x2ebb00ef,
+ 0x003ebb00,
+ 0x800235b6,
+ 0xf601d300,
+ 0x04bd0003,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb20834,
+ 0x0002687e,
+ 0xbb002fbb,
+ 0x3f0f003f,
+ 0x501d608e,
+ 0xb201e5f0,
+ 0x008f7eff,
+ 0x8e0c0f00,
0xf0501da8,
- 0x8f7e01e5,
- 0xff0f0000,
- 0x988effb2,
+ 0xffb201e5,
+ 0x00008f7e,
+ 0x0003147e,
+ 0x608e3f0f,
0xe5f0501d,
- 0x008f7e01,
- 0xb2020f00,
- 0x1da88eff,
+ 0x7effb201,
+ 0x0f00008f,
+ 0x1d9c8e00,
0x01e5f050,
- 0x00008f7e,
+ 0x8f7effb2,
+ 0x010f0000,
0x0003147e,
- 0x85050498,
- 0x98504000,
- 0x64b60406,
- 0x0056bb0f,
-/* 0x04e0: tpc_strand_init_tpc_loop */
- 0x05705eb8,
- 0x00657e00,
- 0xbdf6b200,
-/* 0x04ed: tpc_strand_init_idx_loop */
- 0x605eb874,
- 0x7fb20005,
- 0x00008f7e,
- 0x05885eb8,
- 0x082f9500,
- 0x00008f7e,
- 0x058c5eb8,
- 0x082f9500,
+ 0x501da88e,
+ 0xb201e5f0,
+ 0x008f7eff,
+ 0x8eff0f00,
+ 0xf0501d98,
+ 0xffb201e5,
0x00008f7e,
- 0x05905eb8,
- 0x00657e00,
- 0x06f5b600,
- 0xb601f0b6,
- 0x2fbb08f4,
- 0x003fbb00,
- 0xb60170b6,
- 0x1bf40162,
- 0x0050b7bf,
- 0x0142b608,
- 0x0fa81bf4,
- 0x8effb23f,
- 0xf0501d60,
- 0x8f7e01e5,
- 0x0d0f0000,
- 0xa88effb2,
+ 0xa88e020f,
0xe5f0501d,
- 0x008f7e01,
- 0x03147e00,
- 0x01008000,
- 0x0003f602,
- 0x24bd04bd,
- 0x801f29f0,
- 0xf6023000,
- 0x04bd0002,
-/* 0x0574: main */
- 0xf40031f4,
- 0x240d0028,
- 0x0000377e,
- 0xb0f401f4,
- 0x18f404e4,
- 0x0181fe1d,
- 0x20bd0602,
- 0xb60412fd,
- 0x1efd01e4,
- 0x0018fe05,
- 0x0006477e,
-/* 0x05a3: main_not_ctx_xfer */
- 0x94d40ef4,
- 0xf5f010ef,
- 0x02f87e01,
- 0xc70ef400,
-/* 0x05b0: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x02004a04,
- 0xc400aacf,
- 0x0bf404ab,
- 0x4e240d1f,
- 0xeecf1a00,
- 0x19004f00,
- 0x7e00ffcf,
- 0x0e000004,
- 0x1d004001,
- 0xbd000ef6,
-/* 0x05ed: ih_no_fifo */
- 0x01004004,
- 0xbd000af6,
- 0xfcf0fc04,
- 0xfcd0fce0,
- 0xfca0fcb0,
- 0xfe80fc90,
- 0x80fc0088,
- 0xf80032f4,
-/* 0x060d: hub_barrier_done */
- 0x98010f01,
- 0xfebb040e,
- 0x8effb204,
- 0x7e409418,
- 0xf800008f,
-/* 0x0621: ctx_redswitch */
- 0x80200f00,
+ 0x7effb201,
+ 0x7e00008f,
+ 0x98000314,
+ 0x00850504,
+ 0x06985040,
+ 0x0f64b604,
+/* 0x04e3: tpc_strand_init_tpc_loop */
+ 0xb80056bb,
+ 0x0005705e,
+ 0x0000657e,
+ 0x74bdf6b2,
+/* 0x04f0: tpc_strand_init_idx_loop */
+ 0x05605eb8,
+ 0x7e7fb200,
+ 0xb800008f,
+ 0x0005885e,
+ 0x7e082f95,
+ 0xb800008f,
+ 0x00058c5e,
+ 0x7e082f95,
+ 0xb800008f,
+ 0x0005905e,
+ 0x0000657e,
+ 0xb606f5b6,
+ 0xf4b601f0,
+ 0x002fbb08,
+ 0xb6003fbb,
+ 0x62b60170,
+ 0xbf1bf401,
+ 0x080050b7,
+ 0xf40142b6,
+ 0x3f0fa81b,
+ 0x501d608e,
+ 0xb201e5f0,
+ 0x008f7eff,
+ 0x8e0d0f00,
+ 0xf0501da8,
+ 0xffb201e5,
+ 0x00008f7e,
+ 0x0003147e,
+ 0x02010080,
+ 0xbd0003f6,
+ 0xf024bd04,
+ 0x00801f29,
+ 0x02f60230,
+/* 0x0577: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x7e240d00,
+ 0xf4000037,
+ 0xe4b0f401,
+ 0x1d18f404,
+ 0x020181fe,
+ 0xfd20bd06,
+ 0xe4b60412,
+ 0x051efd01,
+ 0x7e0018fe,
+ 0xf400064a,
+/* 0x05a6: main_not_ctx_xfer */
+ 0xef94d40e,
+ 0x01f5f010,
+ 0x0002f87e,
+/* 0x05b3: ih */
+ 0xf9c70ef4,
+ 0x0188fe80,
+ 0x90f980f9,
+ 0xb0f9a0f9,
+ 0xe0f9d0f9,
+ 0x04bdf0f9,
+ 0xcf02004a,
+ 0xabc400aa,
+ 0x1f0bf404,
+ 0x004e240d,
+ 0x00eecf1a,
+ 0xcf19004f,
+ 0x047e00ff,
+ 0x010e0000,
+ 0xf61d0040,
+ 0x04bd000e,
+/* 0x05f0: ih_no_fifo */
+ 0xf6010040,
+ 0x04bd000a,
+ 0xe0fcf0fc,
+ 0xb0fcd0fc,
+ 0x90fca0fc,
+ 0x88fe80fc,
+ 0xf480fc00,
+ 0x01f80032,
+/* 0x0610: hub_barrier_done */
+ 0x0e98010f,
+ 0x04febb04,
+ 0x188effb2,
+ 0x8f7e4094,
+ 0x00f80000,
+/* 0x0624: ctx_redswitch */
+ 0x0080200f,
+ 0x0ff60185,
+ 0x0e04bd00,
+/* 0x0631: ctx_redswitch_delay */
+ 0x01e2b608,
+ 0xf1fd1bf4,
+ 0xf10800f5,
+ 0x800200f5,
0xf6018500,
0x04bd000f,
-/* 0x062e: ctx_redswitch_delay */
- 0xe2b6080e,
- 0xfd1bf401,
- 0x0800f5f1,
- 0x0200f5f1,
- 0x01850080,
- 0xbd000ff6,
-/* 0x0647: ctx_xfer */
- 0x8000f804,
- 0xf6028100,
- 0x04bd000f,
- 0xc48effb2,
- 0xe5f0501d,
- 0x008f7e01,
- 0x0711f400,
- 0x0006217e,
-/* 0x0664: ctx_xfer_not_load */
- 0x0002167e,
- 0xfc8024bd,
- 0x02f60247,
- 0xf004bd00,
- 0x20b6012c,
- 0x4afc8003,
+/* 0x064a: ctx_xfer */
+ 0x008000f8,
+ 0x0ff60281,
+ 0x8e04bd00,
+ 0xf0501dc4,
+ 0xffb201e5,
+ 0x00008f7e,
+ 0x7e0711f4,
+/* 0x0667: ctx_xfer_not_load */
+ 0x7e000624,
+ 0xbd000216,
+ 0x47fc8024,
0x0002f602,
- 0x0c0f04bd,
- 0xa88effb2,
- 0xe5f0501d,
- 0x008f7e01,
- 0x03147e00,
- 0xb23f0f00,
- 0x1d608eff,
- 0x01e5f050,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x024afc80,
+ 0xbd0002f6,
+ 0x8e0c0f04,
+ 0xf0501da8,
+ 0xffb201e5,
0x00008f7e,
- 0xffb2000f,
- 0x501d9c8e,
- 0x7e01e5f0,
+ 0x0003147e,
+ 0x608e3f0f,
+ 0xe5f0501d,
+ 0x7effb201,
0x0f00008f,
- 0x03147e01,
- 0x01fcf000,
- 0xb203f0b6,
- 0x1da88eff,
+ 0x1d9c8e00,
0x01e5f050,
- 0x00008f7e,
- 0xf001acf0,
- 0x008b02a5,
- 0x0c985000,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98000c,
- 0x7e000e01,
- 0xf000013d,
- 0x008b01ac,
- 0x0c985040,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98010c,
- 0x060f9802,
- 0x7e08004e,
- 0xf000013d,
+ 0x8f7effb2,
+ 0x010f0000,
+ 0x0003147e,
+ 0xb601fcf0,
+ 0xa88e03f0,
+ 0xe5f0501d,
+ 0x7effb201,
+ 0xf000008f,
0xa5f001ac,
- 0x30008b04,
+ 0x00008b02,
0x040c9850,
0xbb0fc4b6,
0x0c9800bc,
- 0x030d9802,
- 0x4e080f98,
- 0x3d7e0200,
- 0x0a7e0001,
- 0x147e0002,
- 0x01f40003,
- 0x1a12f406,
-/* 0x073c: ctx_xfer_post */
- 0x0002277e,
- 0xffb20d0f,
- 0x501da88e,
- 0x7e01e5f0,
- 0x7e00008f,
-/* 0x0753: ctx_xfer_done */
- 0x7e000314,
- 0xf800060d,
- 0x00000000,
+ 0x010d9800,
+ 0x3d7e000e,
+ 0xacf00001,
+ 0x40008b01,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0x4e060f98,
+ 0x3d7e0800,
+ 0xacf00001,
+ 0x04a5f001,
+ 0x5030008b,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x020c9800,
+ 0x98030d98,
+ 0x004e080f,
+ 0x013d7e02,
+ 0x020a7e00,
+ 0x03147e00,
+ 0x0601f400,
+/* 0x073f: ctx_xfer_post */
+ 0x7e1a12f4,
+ 0x0f000227,
+ 0x1da88e0d,
+ 0x01e5f050,
+ 0x8f7effb2,
+ 0x147e0000,
+/* 0x0756: ctx_xfer_done */
+ 0x107e0003,
+ 0x00f80006,
0x00000000,
0x00000000,
0x00000000,
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
index dda7a7d..9f5dfc8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -143,7 +143,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format,
static int
gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
{
- struct gf100_gr *gr = (void *)object->engine;
+ struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine));
union {
struct fermi_a_zbc_color_v0 v0;
} *args = data;
@@ -189,7 +189,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
static int
gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
{
- struct gf100_gr *gr = (void *)object->engine;
+ struct gf100_gr *gr = gf100_gr(nvkm_gr(object->engine));
union {
struct fermi_a_zbc_depth_v0 v0;
} *args = data;
@@ -1530,6 +1530,8 @@ gf100_gr_oneinit(struct nvkm_gr *base)
gr->ppc_nr[i] = gr->func->ppc_nr;
for (j = 0; j < gr->ppc_nr[i]; j++) {
u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4)));
+ if (mask)
+ gr->ppc_mask[i] |= (1 << j);
gr->ppc_tpc_nr[i][j] = hweight8(mask);
}
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
index 4611961..02e78b8 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -97,6 +97,7 @@ struct gf100_gr {
u8 tpc_nr[GPC_MAX];
u8 tpc_total;
u8 ppc_nr[GPC_MAX];
+ u8 ppc_mask[GPC_MAX];
u8 ppc_tpc_nr[GPC_MAX][4];
struct nvkm_memory *unk4188b4;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
index ffa902e..05a8954 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
@@ -156,6 +156,7 @@ nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch,
return -ENOMEM;
nvkm_object_ctor(&nv40_gr_chan, oclass, &chan->object);
chan->gr = gr;
+ chan->fifo = fifoch;
*pobject = &chan->object;
spin_lock_irqsave(&chan->gr->base.engine.lock, flags);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
index 43006db..80fed7e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
@@ -83,6 +83,7 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
fan->type = NVBIOS_THERM_FAN_UNK;
}
+ fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
fan->min_duty = nvbios_rd08(bios, data + 0x02);
fan->max_duty = nvbios_rd08(bios, data + 0x03);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
index 895ba74..1d7dd38 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
@@ -97,7 +97,9 @@ static void *
nvkm_instobj_dtor(struct nvkm_memory *memory)
{
struct nvkm_instobj *iobj = nvkm_instobj(memory);
+ spin_lock(&iobj->imem->lock);
list_del(&iobj->head);
+ spin_unlock(&iobj->imem->lock);
nvkm_memory_del(&iobj->parent);
return iobj;
}
@@ -190,7 +192,9 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero,
nvkm_memory_ctor(&nvkm_instobj_func_slow, &iobj->memory);
iobj->parent = memory;
iobj->imem = imem;
+ spin_lock(&iobj->imem->lock);
list_add_tail(&iobj->head, &imem->list);
+ spin_unlock(&iobj->imem->lock);
memory = &iobj->memory;
}
@@ -309,5 +313,6 @@ nvkm_instmem_ctor(const struct nvkm_instmem_func *func,
{
nvkm_subdev_ctor(&nvkm_instmem, device, index, 0, &imem->subdev);
imem->func = func;
+ spin_lock_init(&imem->lock);
INIT_LIST_HEAD(&imem->list);
}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
index fc419bb..14107b5 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c
@@ -133,18 +133,24 @@ gk20a_instobj_size(struct nvkm_memory *memory)
static void __iomem *
gk20a_instobj_cpu_map_dma(struct nvkm_memory *memory)
{
+#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
struct gk20a_instobj_dma *node = gk20a_instobj_dma(memory);
struct device *dev = node->base.imem->base.subdev.device->dev;
int npages = nvkm_memory_size(memory) >> 12;
struct page *pages[npages];
int i;
+ /* we shouldn't see a gk20a on anything but arm/arm64 anyways */
/* phys_to_page does not exist on all platforms... */
pages[0] = pfn_to_page(dma_to_phys(dev, node->handle) >> PAGE_SHIFT);
for (i = 1; i < npages; i++)
pages[i] = pages[0] + i;
return vmap(pages, npages, VM_MAP, pgprot_writecombine(PAGE_KERNEL));
+#else
+ BUG();
+ return NULL;
+#endif
}
static void __iomem *
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
index d942fa7..86f9f3b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
@@ -81,9 +81,7 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
nvkm_mask(device, 0x000200, 0x00001000, 0x00001000);
nvkm_rd32(device, 0x000200);
- if ( nvkm_boolopt(device->cfgopt, "War00C800_0",
- device->quirk ? device->quirk->War00C800_0 : false)) {
- nvkm_info(&pmu->subdev, "hw bug workaround enabled\n");
+ if (nvkm_boolopt(device->cfgopt, "War00C800_0", true)) {
switch (device->chipset) {
case 0xe4:
magic(device, 0x04000000);
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
index b61509e..b735173 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk104.c
@@ -59,7 +59,7 @@ gk104_volt_set(struct nvkm_volt *base, u32 uv)
duty = (uv - bios->base) * div / bios->pwm_range;
nvkm_wr32(device, 0x20340, div);
- nvkm_wr32(device, 0x20344, 0x8000000 | duty);
+ nvkm_wr32(device, 0x20344, 0x80000000 | duty);
return 0;
}
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index b8e4cde..24f92be 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -112,11 +112,8 @@ static int omap_fbdev_create(struct drm_fb_helper *helper,
dma_addr_t paddr;
int ret;
- /* only doing ARGB32 since this is what is needed to alpha-blend
- * with video overlays:
- */
sizes->surface_bpp = 32;
- sizes->surface_depth = 32;
+ sizes->surface_depth = 24;
DBG("create fbdev: %dx%d@%d (%dx%d)", sizes->surface_width,
sizes->surface_height, sizes->surface_bpp,
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 248953d..f81fb26 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -4173,11 +4173,7 @@ void cik_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
control |= ib->length_dw | (vm_id << 24);
radeon_ring_write(ring, header);
- radeon_ring_write(ring,
-#ifdef __BIG_ENDIAN
- (2 << 0) |
-#endif
- (ib->gpu_addr & 0xFFFFFFFC));
+ radeon_ring_write(ring, (ib->gpu_addr & 0xFFFFFFFC));
radeon_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xFFFF);
radeon_ring_write(ring, control);
}
@@ -8472,7 +8468,7 @@ restart_ih:
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_reset) {
rdev->needs_reset = true;
wake_up_all(&rdev->fence_queue);
@@ -9630,6 +9626,9 @@ static void dce8_program_watermarks(struct radeon_device *rdev,
(rdev->disp_priority == 2)) {
DRM_DEBUG_KMS("force priority to high\n");
}
+
+ /* Save number of lines the linebuffer leads before the scanout */
+ radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 7f33767..2ad4628 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -2372,6 +2372,9 @@ static void evergreen_program_watermarks(struct radeon_device *rdev,
c.full = dfixed_div(c, a);
priority_b_mark = dfixed_trunc(c);
priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+
+ /* Save number of lines the linebuffer leads before the scanout */
+ radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
@@ -5344,7 +5347,7 @@ restart_ih:
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
if (queue_thermal && rdev->pm.dpm_enabled)
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 238b13f..9e7e2bf 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -806,7 +806,7 @@ int r100_irq_process(struct radeon_device *rdev)
status = r100_irq_ack(rdev);
}
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (rdev->msi_enabled) {
switch (rdev->family) {
case CHIP_RS400:
@@ -3217,6 +3217,9 @@ void r100_bandwidth_update(struct radeon_device *rdev)
uint32_t pixel_bytes1 = 0;
uint32_t pixel_bytes2 = 0;
+ /* Guess line buffer size to be 8192 pixels */
+ u32 lb_size = 8192;
+
if (!rdev->mode_info.mode_config_initialized)
return;
@@ -3631,6 +3634,13 @@ void r100_bandwidth_update(struct radeon_device *rdev)
DRM_DEBUG_KMS("GRPH2_BUFFER_CNTL from to %x\n",
(unsigned int)RREG32(RADEON_GRPH2_BUFFER_CNTL));
}
+
+ /* Save number of lines the linebuffer leads before the scanout */
+ if (mode1)
+ rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay);
+
+ if (mode2)
+ rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay);
}
int r100_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 4ea5b10..cc2fdf0 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -4276,7 +4276,7 @@ restart_ih:
WREG32(IH_RB_RPTR, rptr);
}
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
if (queue_thermal && rdev->pm.dpm_enabled)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index b6cbd81..87db649 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -2414,7 +2414,7 @@ struct radeon_device {
struct r600_ih ih; /* r6/700 interrupt ring */
struct radeon_rlc rlc;
struct radeon_mec mec;
- struct work_struct hotplug_work;
+ struct delayed_work hotplug_work;
struct work_struct dp_work;
struct work_struct audio_work;
int num_crtc; /* number of crtcs */
diff --git a/drivers/gpu/drm/radeon/radeon_agp.c b/drivers/gpu/drm/radeon/radeon_agp.c
index fe994aa..c77d349 100644
--- a/drivers/gpu/drm/radeon/radeon_agp.c
+++ b/drivers/gpu/drm/radeon/radeon_agp.c
@@ -54,6 +54,9 @@ static struct radeon_agpmode_quirk radeon_agpmode_quirk_list[] = {
/* Intel 82855PM host bridge / Mobility 9600 M10 RV350 Needs AGPMode 1 (lp #195051) */
{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4e50,
PCI_VENDOR_ID_IBM, 0x0550, 1},
+ /* Intel 82855PM host bridge / RV250/M9 GL [Mobility FireGL 9000/Radeon 9000] needs AGPMode 1 (Thinkpad T40p) */
+ { PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c66,
+ PCI_VENDOR_ID_IBM, 0x054d, 1},
/* Intel 82855PM host bridge / Mobility M7 needs AGPMode 1 */
{ PCI_VENDOR_ID_INTEL, 0x3340, PCI_VENDOR_ID_ATI, 0x4c57,
PCI_VENDOR_ID_IBM, 0x0530, 1},
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 5a2cafb..340f3f5 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -1234,13 +1234,32 @@ radeon_dvi_detect(struct drm_connector *connector, bool force)
if (r < 0)
return connector_status_disconnected;
+ if (radeon_connector->detected_hpd_without_ddc) {
+ force = true;
+ radeon_connector->detected_hpd_without_ddc = false;
+ }
+
if (!force && radeon_check_hpd_status_unchanged(connector)) {
ret = connector->status;
goto exit;
}
- if (radeon_connector->ddc_bus)
+ if (radeon_connector->ddc_bus) {
dret = radeon_ddc_probe(radeon_connector, false);
+
+ /* Sometimes the pins required for the DDC probe on DVI
+ * connectors don't make contact at the same time that the ones
+ * for HPD do. If the DDC probe fails even though we had an HPD
+ * signal, try again later */
+ if (!dret && !force &&
+ connector->status != connector_status_connected) {
+ DRM_DEBUG_KMS("hpd detected without ddc, retrying in 1 second\n");
+ radeon_connector->detected_hpd_without_ddc = true;
+ schedule_delayed_work(&rdev->hotplug_work,
+ msecs_to_jiffies(1000));
+ goto exit;
+ }
+ }
if (dret) {
radeon_connector->detected_by_load = false;
radeon_connector_free_edid(connector);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index a8d9927..1eca0ac 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -322,7 +322,9 @@ void radeon_crtc_handle_vblank(struct radeon_device *rdev, int crtc_id)
* to complete in this vblank?
*/
if (update_pending &&
- (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
+ (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev,
+ crtc_id,
+ USE_REAL_VBLANKSTART,
&vpos, &hpos, NULL, NULL,
&rdev->mode_info.crtcs[crtc_id]->base.hwmode)) &&
((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
@@ -401,6 +403,8 @@ static void radeon_flip_work_func(struct work_struct *__work)
struct drm_crtc *crtc = &radeon_crtc->base;
unsigned long flags;
int r;
+ int vpos, hpos, stat, min_udelay;
+ struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
down_read(&rdev->exclusive_lock);
if (work->fence) {
@@ -437,6 +441,41 @@ static void radeon_flip_work_func(struct work_struct *__work)
/* set the proper interrupt */
radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id);
+ /* If this happens to execute within the "virtually extended" vblank
+ * interval before the start of the real vblank interval then it needs
+ * to delay programming the mmio flip until the real vblank is entered.
+ * This prevents completing a flip too early due to the way we fudge
+ * our vblank counter and vblank timestamps in order to work around the
+ * problem that the hw fires vblank interrupts before actual start of
+ * vblank (when line buffer refilling is done for a frame). It
+ * complements the fudging logic in radeon_get_crtc_scanoutpos() for
+ * timestamping and radeon_get_vblank_counter_kms() for vblank counts.
+ *
+ * In practice this won't execute very often unless on very fast
+ * machines because the time window for this to happen is very small.
+ */
+ for (;;) {
+ /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
+ * start in hpos, and to the "fudged earlier" vblank start in
+ * vpos.
+ */
+ stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id,
+ GET_DISTANCE_TO_VBLANKSTART,
+ &vpos, &hpos, NULL, NULL,
+ &crtc->hwmode);
+
+ if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
+ !(vpos >= 0 && hpos <= 0))
+ break;
+
+ /* Sleep at least until estimated real start of hw vblank */
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+ min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
+ usleep_range(min_udelay, 2 * min_udelay);
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ };
+
/* do the flip (mmio) */
radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base);
@@ -1768,6 +1807,15 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
* \param dev Device to query.
* \param crtc Crtc to query.
* \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
+ * For driver internal use only also supports these flags:
+ *
+ * USE_REAL_VBLANKSTART to use the real start of vblank instead
+ * of a fudged earlier start of vblank.
+ *
+ * GET_DISTANCE_TO_VBLANKSTART to return distance to the
+ * fudged earlier start of vblank in *vpos and the distance
+ * to true start of vblank in *hpos.
+ *
* \param *vpos Location where vertical scanout position should be stored.
* \param *hpos Location where horizontal scanout position should go.
* \param *stime Target location for timestamp taken immediately before
@@ -1911,10 +1959,40 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
vbl_end = 0;
}
+ /* Called from driver internal vblank counter query code? */
+ if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+ /* Caller wants distance from real vbl_start in *hpos */
+ *hpos = *vpos - vbl_start;
+ }
+
+ /* Fudge vblank to start a few scanlines earlier to handle the
+ * problem that vblank irqs fire a few scanlines before start
+ * of vblank. Some driver internal callers need the true vblank
+ * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
+ *
+ * The cause of the "early" vblank irq is that the irq is triggered
+ * by the line buffer logic when the line buffer read position enters
+ * the vblank, whereas our crtc scanout position naturally lags the
+ * line buffer read position.
+ */
+ if (!(flags & USE_REAL_VBLANKSTART))
+ vbl_start -= rdev->mode_info.crtcs[pipe]->lb_vblank_lead_lines;
+
/* Test scanout position against vblank region. */
if ((*vpos < vbl_start) && (*vpos >= vbl_end))
in_vbl = false;
+ /* In vblank? */
+ if (in_vbl)
+ ret |= DRM_SCANOUTPOS_IN_VBLANK;
+
+ /* Called from driver internal vblank counter query code? */
+ if (flags & GET_DISTANCE_TO_VBLANKSTART) {
+ /* Caller wants distance from fudged earlier vbl_start */
+ *vpos -= vbl_start;
+ return ret;
+ }
+
/* Check if inside vblank area and apply corrective offsets:
* vpos will then be >=0 in video scanout area, but negative
* within vblank area, counting down the number of lines until
@@ -1930,31 +2008,5 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
/* Correct for shifted end of vbl at vbl_end. */
*vpos = *vpos - vbl_end;
- /* In vblank? */
- if (in_vbl)
- ret |= DRM_SCANOUTPOS_IN_VBLANK;
-
- /* Is vpos outside nominal vblank area, but less than
- * 1/100 of a frame height away from start of vblank?
- * If so, assume this isn't a massively delayed vblank
- * interrupt, but a vblank interrupt that fired a few
- * microseconds before true start of vblank. Compensate
- * by adding a full frame duration to the final timestamp.
- * Happens, e.g., on ATI R500, R600.
- *
- * We only do this if DRM_CALLED_FROM_VBLIRQ.
- */
- if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
- vbl_start = mode->crtc_vdisplay;
- vtotal = mode->crtc_vtotal;
-
- if (vbl_start - *vpos < vtotal / 100) {
- *vpos -= vtotal;
-
- /* Signal this correction as "applied". */
- ret |= 0x8;
- }
- }
-
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 171d3e4..979f3bf 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -74,7 +74,7 @@ irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
static void radeon_hotplug_work_func(struct work_struct *work)
{
struct radeon_device *rdev = container_of(work, struct radeon_device,
- hotplug_work);
+ hotplug_work.work);
struct drm_device *dev = rdev->ddev;
struct drm_mode_config *mode_config = &dev->mode_config;
struct drm_connector *connector;
@@ -302,7 +302,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
}
}
- INIT_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
+ INIT_DELAYED_WORK(&rdev->hotplug_work, radeon_hotplug_work_func);
INIT_WORK(&rdev->dp_work, radeon_dp_work_func);
INIT_WORK(&rdev->audio_work, r600_audio_update_hdmi);
@@ -310,7 +310,7 @@ int radeon_irq_kms_init(struct radeon_device *rdev)
r = drm_irq_install(rdev->ddev, rdev->ddev->pdev->irq);
if (r) {
rdev->irq.installed = false;
- flush_work(&rdev->hotplug_work);
+ flush_delayed_work(&rdev->hotplug_work);
return r;
}
@@ -333,7 +333,7 @@ void radeon_irq_kms_fini(struct radeon_device *rdev)
rdev->irq.installed = false;
if (rdev->msi_enabled)
pci_disable_msi(rdev->pdev);
- flush_work(&rdev->hotplug_work);
+ flush_delayed_work(&rdev->hotplug_work);
}
}
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 0ec6fcc..d290a8a 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -755,6 +755,8 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
*/
u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
{
+ int vpos, hpos, stat;
+ u32 count;
struct radeon_device *rdev = dev->dev_private;
if (crtc < 0 || crtc >= rdev->num_crtc) {
@@ -762,7 +764,53 @@ u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc)
return -EINVAL;
}
- return radeon_get_vblank_counter(rdev, crtc);
+ /* The hw increments its frame counter at start of vsync, not at start
+ * of vblank, as is required by DRM core vblank counter handling.
+ * Cook the hw count here to make it appear to the caller as if it
+ * incremented at start of vblank. We measure distance to start of
+ * vblank in vpos. vpos therefore will be >= 0 between start of vblank
+ * and start of vsync, so vpos >= 0 means to bump the hw frame counter
+ * result by 1 to give the proper appearance to caller.
+ */
+ if (rdev->mode_info.crtcs[crtc]) {
+ /* Repeat readout if needed to provide stable result if
+ * we cross start of vsync during the queries.
+ */
+ do {
+ count = radeon_get_vblank_counter(rdev, crtc);
+ /* Ask radeon_get_crtc_scanoutpos to return vpos as
+ * distance to start of vblank, instead of regular
+ * vertical scanout pos.
+ */
+ stat = radeon_get_crtc_scanoutpos(
+ dev, crtc, GET_DISTANCE_TO_VBLANKSTART,
+ &vpos, &hpos, NULL, NULL,
+ &rdev->mode_info.crtcs[crtc]->base.hwmode);
+ } while (count != radeon_get_vblank_counter(rdev, crtc));
+
+ if (((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE))) {
+ DRM_DEBUG_VBL("Query failed! stat %d\n", stat);
+ }
+ else {
+ DRM_DEBUG_VBL("crtc %d: dist from vblank start %d\n",
+ crtc, vpos);
+
+ /* Bump counter if we are at >= leading edge of vblank,
+ * but before vsync where vpos would turn negative and
+ * the hw counter really increments.
+ */
+ if (vpos >= 0)
+ count++;
+ }
+ }
+ else {
+ /* Fallback to use value as is. */
+ count = radeon_get_vblank_counter(rdev, crtc);
+ DRM_DEBUG_VBL("NULL mode info! Returned count may be wrong.\n");
+ }
+
+ return count;
}
/**
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 830e171..bba1126 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -367,6 +367,7 @@ struct radeon_crtc {
u32 line_time;
u32 wm_low;
u32 wm_high;
+ u32 lb_vblank_lead_lines;
struct drm_display_mode hw_mode;
enum radeon_output_csc output_csc;
};
@@ -553,6 +554,7 @@ struct radeon_connector {
void *con_priv;
bool dac_load_detect;
bool detected_by_load; /* if the connection status was determined by load */
+ bool detected_hpd_without_ddc; /* if an HPD signal was detected on DVI, but ddc probing failed */
uint16_t connector_object_id;
struct radeon_hpd hpd;
struct radeon_router router;
@@ -686,6 +688,9 @@ struct atom_voltage_table
struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
};
+/* Driver internal use only flags of radeon_get_crtc_scanoutpos() */
+#define USE_REAL_VBLANKSTART (1 << 30)
+#define GET_DISTANCE_TO_VBLANKSTART (1 << 31)
extern void
radeon_add_atom_connector(struct drm_device *dev,
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index d302488..84d4563 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -221,11 +221,17 @@ int radeon_bo_create(struct radeon_device *rdev,
if (!(rdev->flags & RADEON_IS_PCIE))
bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+ /* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx
+ * See https://bugs.freedesktop.org/show_bug.cgi?id=91268
+ */
+ if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635)
+ bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
+
#ifdef CONFIG_X86_32
/* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
* See https://bugs.freedesktop.org/show_bug.cgi?id=84627
*/
- bo->flags &= ~RADEON_GEM_GTT_WC;
+ bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
/* Don't try to enable write-combining when it can't work, or things
* may be slow
@@ -235,9 +241,10 @@ int radeon_bo_create(struct radeon_device *rdev,
#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
thanks to write-combining
- DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
- "better performance thanks to write-combining\n");
- bo->flags &= ~RADEON_GEM_GTT_WC;
+ if (bo->flags & RADEON_GEM_GTT_WC)
+ DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
+ "better performance thanks to write-combining\n");
+ bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
#endif
radeon_ttm_placement_from_domain(bo, domain);
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index 6d80dde..59abebd 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -1542,8 +1542,7 @@ int radeon_pm_late_init(struct radeon_device *rdev)
ret = device_create_file(rdev->dev, &dev_attr_power_method);
if (ret)
DRM_ERROR("failed to create device file for power method\n");
- if (!ret)
- rdev->pm.sysfs_initialized = true;
+ rdev->pm.sysfs_initialized = true;
}
mutex_lock(&rdev->pm.mutex);
@@ -1757,7 +1756,9 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
*/
for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
if (rdev->pm.active_crtcs & (1 << crtc)) {
- vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, 0,
+ vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev,
+ crtc,
+ USE_REAL_VBLANKSTART,
&vpos, &hpos, NULL, NULL,
&rdev->mode_info.crtcs[crtc]->base.hwmode);
if ((vbl_status & DRM_SCANOUTPOS_VALID) &&
diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c
index 574f62b..7eb1ae7 100644
--- a/drivers/gpu/drm/radeon/radeon_vce.c
+++ b/drivers/gpu/drm/radeon/radeon_vce.c
@@ -361,31 +361,31 @@ int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
/* stitch together an VCE create msg */
ib.length_dw = 0;
- ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
- ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
- ib.ptr[ib.length_dw++] = handle;
-
- ib.ptr[ib.length_dw++] = 0x00000030; /* len */
- ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
- ib.ptr[ib.length_dw++] = 0x00000000;
- ib.ptr[ib.length_dw++] = 0x00000042;
- ib.ptr[ib.length_dw++] = 0x0000000a;
- ib.ptr[ib.length_dw++] = 0x00000001;
- ib.ptr[ib.length_dw++] = 0x00000080;
- ib.ptr[ib.length_dw++] = 0x00000060;
- ib.ptr[ib.length_dw++] = 0x00000100;
- ib.ptr[ib.length_dw++] = 0x00000100;
- ib.ptr[ib.length_dw++] = 0x0000000c;
- ib.ptr[ib.length_dw++] = 0x00000000;
-
- ib.ptr[ib.length_dw++] = 0x00000014; /* len */
- ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
- ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
- ib.ptr[ib.length_dw++] = dummy;
- ib.ptr[ib.length_dw++] = 0x00000001;
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
+
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000030); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x01000001); /* create cmd */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000042);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000a);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000080);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000060);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000100);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000000);
+
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
+ ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
for (i = ib.length_dw; i < ib_size_dw; ++i)
- ib.ptr[i] = 0x0;
+ ib.ptr[i] = cpu_to_le32(0x0);
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r) {
@@ -428,21 +428,21 @@ int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
/* stitch together an VCE destroy msg */
ib.length_dw = 0;
- ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
- ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
- ib.ptr[ib.length_dw++] = handle;
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x0000000c); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001); /* session cmd */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(handle);
- ib.ptr[ib.length_dw++] = 0x00000014; /* len */
- ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
- ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
- ib.ptr[ib.length_dw++] = dummy;
- ib.ptr[ib.length_dw++] = 0x00000001;
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000014); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x05000005); /* feedback buffer */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(upper_32_bits(dummy));
+ ib.ptr[ib.length_dw++] = cpu_to_le32(dummy);
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000001);
- ib.ptr[ib.length_dw++] = 0x00000008; /* len */
- ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x00000008); /* len */
+ ib.ptr[ib.length_dw++] = cpu_to_le32(0x02000001); /* destroy cmd */
for (i = ib.length_dw; i < ib_size_dw; ++i)
- ib.ptr[i] = 0x0;
+ ib.ptr[i] = cpu_to_le32(0x0);
r = radeon_ib_schedule(rdev, &ib, NULL, false);
if (r) {
@@ -699,12 +699,12 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
{
uint64_t addr = semaphore->gpu_addr;
- radeon_ring_write(ring, VCE_CMD_SEMAPHORE);
- radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
- radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
- radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0));
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_SEMAPHORE));
+ radeon_ring_write(ring, cpu_to_le32((addr >> 3) & 0x000FFFFF));
+ radeon_ring_write(ring, cpu_to_le32((addr >> 23) & 0x000FFFFF));
+ radeon_ring_write(ring, cpu_to_le32(0x01003000 | (emit_wait ? 1 : 0)));
if (!emit_wait)
- radeon_ring_write(ring, VCE_CMD_END);
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
return true;
}
@@ -719,10 +719,10 @@ bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
{
struct radeon_ring *ring = &rdev->ring[ib->ring];
- radeon_ring_write(ring, VCE_CMD_IB);
- radeon_ring_write(ring, ib->gpu_addr);
- radeon_ring_write(ring, upper_32_bits(ib->gpu_addr));
- radeon_ring_write(ring, ib->length_dw);
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_IB));
+ radeon_ring_write(ring, cpu_to_le32(ib->gpu_addr));
+ radeon_ring_write(ring, cpu_to_le32(upper_32_bits(ib->gpu_addr)));
+ radeon_ring_write(ring, cpu_to_le32(ib->length_dw));
}
/**
@@ -738,12 +738,12 @@ void radeon_vce_fence_emit(struct radeon_device *rdev,
struct radeon_ring *ring = &rdev->ring[fence->ring];
uint64_t addr = rdev->fence_drv[fence->ring].gpu_addr;
- radeon_ring_write(ring, VCE_CMD_FENCE);
- radeon_ring_write(ring, addr);
- radeon_ring_write(ring, upper_32_bits(addr));
- radeon_ring_write(ring, fence->seq);
- radeon_ring_write(ring, VCE_CMD_TRAP);
- radeon_ring_write(ring, VCE_CMD_END);
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_FENCE));
+ radeon_ring_write(ring, cpu_to_le32(addr));
+ radeon_ring_write(ring, cpu_to_le32(upper_32_bits(addr)));
+ radeon_ring_write(ring, cpu_to_le32(fence->seq));
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_TRAP));
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
}
/**
@@ -765,7 +765,7 @@ int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
ring->idx, r);
return r;
}
- radeon_ring_write(ring, VCE_CMD_END);
+ radeon_ring_write(ring, cpu_to_le32(VCE_CMD_END));
radeon_ring_unlock_commit(rdev, ring, false);
for (i = 0; i < rdev->usec_timeout; i++) {
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 97a9048..6244f4e 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -813,7 +813,7 @@ int rs600_irq_process(struct radeon_device *rdev)
status = rs600_irq_ack(rdev);
}
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_hdmi)
schedule_work(&rdev->audio_work);
if (rdev->msi_enabled) {
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 516ca27..6bc44c2 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -207,6 +207,9 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev,
{
u32 tmp;
+ /* Guess line buffer size to be 8192 pixels */
+ u32 lb_size = 8192;
+
/*
* Line Buffer Setup
* There is a single line buffer shared by both display controllers.
@@ -243,6 +246,13 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev,
tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
}
WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp);
+
+ /* Save number of lines the linebuffer leads before the scanout */
+ if (mode1)
+ rdev->mode_info.crtcs[0]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode1->crtc_hdisplay);
+
+ if (mode2)
+ rdev->mode_info.crtcs[1]->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode2->crtc_hdisplay);
}
struct rs690_watermark {
diff --git a/drivers/gpu/drm/radeon/rv730_dpm.c b/drivers/gpu/drm/radeon/rv730_dpm.c
index 3f5e1cf..d37ba2c 100644
--- a/drivers/gpu/drm/radeon/rv730_dpm.c
+++ b/drivers/gpu/drm/radeon/rv730_dpm.c
@@ -464,7 +464,7 @@ void rv730_stop_dpm(struct radeon_device *rdev)
result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
if (result != PPSMC_Result_OK)
- DRM_ERROR("Could not force DPM to low\n");
+ DRM_DEBUG("Could not force DPM to low\n");
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index b9c7707..e830c89 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -193,7 +193,7 @@ void rv770_stop_dpm(struct radeon_device *rdev)
result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_TwoLevelsDisabled);
if (result != PPSMC_Result_OK)
- DRM_ERROR("Could not force DPM to low.\n");
+ DRM_DEBUG("Could not force DPM to low.\n");
WREG32_P(GENERAL_PWRMGT, 0, ~GLOBAL_PWRMGT_EN);
@@ -1418,7 +1418,7 @@ int rv770_resume_smc(struct radeon_device *rdev)
int rv770_set_sw_state(struct radeon_device *rdev)
{
if (rv770_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToSwState) != PPSMC_Result_OK)
- return -EINVAL;
+ DRM_DEBUG("rv770_set_sw_state failed\n");
return 0;
}
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 07037e3..f878d69 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -2376,6 +2376,9 @@ static void dce6_program_watermarks(struct radeon_device *rdev,
c.full = dfixed_div(c, a);
priority_b_mark = dfixed_trunc(c);
priority_b_cnt |= priority_b_mark & PRIORITY_MARK_MASK;
+
+ /* Save number of lines the linebuffer leads before the scanout */
+ radeon_crtc->lb_vblank_lead_lines = DIV_ROUND_UP(lb_size, mode->crtc_hdisplay);
}
/* select wm A */
@@ -6848,7 +6851,7 @@ restart_ih:
if (queue_dp)
schedule_work(&rdev->dp_work);
if (queue_hotplug)
- schedule_work(&rdev->hotplug_work);
+ schedule_delayed_work(&rdev->hotplug_work, 0);
if (queue_thermal && rdev->pm.dpm_enabled)
schedule_work(&rdev->pm.dpm.thermal.work);
rdev->ih.rptr = rptr;
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index e72bf46..a82b891 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -2927,7 +2927,7 @@ static struct si_dpm_quirk si_dpm_quirk_list[] = {
{ PCI_VENDOR_ID_ATI, 0x6810, 0x1462, 0x3036, 0, 120000 },
{ PCI_VENDOR_ID_ATI, 0x6811, 0x174b, 0xe271, 0, 120000 },
{ PCI_VENDOR_ID_ATI, 0x6810, 0x174b, 0xe271, 85000, 90000 },
- { PCI_VENDOR_ID_ATI, 0x6811, 0x1762, 0x2015, 0, 120000 },
+ { PCI_VENDOR_ID_ATI, 0x6811, 0x1462, 0x2015, 0, 120000 },
{ PCI_VENDOR_ID_ATI, 0x6811, 0x1043, 0x2015, 0, 120000 },
{ 0, 0, 0, 0 },
};
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index d26e0cc..f22e1e1 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -19,7 +19,6 @@
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_fb_helper.h>
-#include <drm/drm_of.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/module.h>
@@ -419,6 +418,29 @@ static int compare_of(struct device *dev, void *data)
return dev->of_node == np;
}
+static void rockchip_add_endpoints(struct device *dev,
+ struct component_match **match,
+ struct device_node *port)
+{
+ struct device_node *ep, *remote;
+
+ for_each_child_of_node(port, ep) {
+ remote = of_graph_get_remote_port_parent(ep);
+ if (!remote || !of_device_is_available(remote)) {
+ of_node_put(remote);
+ continue;
+ } else if (!of_device_is_available(remote->parent)) {
+ dev_warn(dev, "parent device of %s is not available\n",
+ remote->full_name);
+ of_node_put(remote);
+ continue;
+ }
+
+ component_match_add(dev, match, compare_of, remote);
+ of_node_put(remote);
+ }
+}
+
static int rockchip_drm_bind(struct device *dev)
{
struct drm_device *drm;
@@ -461,14 +483,61 @@ static const struct component_master_ops rockchip_drm_ops = {
static int rockchip_drm_platform_probe(struct platform_device *pdev)
{
- int ret = drm_of_component_probe(&pdev->dev, compare_of,
- &rockchip_drm_ops);
+ struct device *dev = &pdev->dev;
+ struct component_match *match = NULL;
+ struct device_node *np = dev->of_node;
+ struct device_node *port;
+ int i;
- /* keep compatibility with old code that was returning -ENODEV */
- if (ret == -EINVAL)
+ if (!np)
return -ENODEV;
+ /*
+ * Bind the crtc ports first, so that
+ * drm_of_find_possible_crtcs called from encoder .bind callbacks
+ * works as expected.
+ */
+ for (i = 0;; i++) {
+ port = of_parse_phandle(np, "ports", i);
+ if (!port)
+ break;
+
+ if (!of_device_is_available(port->parent)) {
+ of_node_put(port);
+ continue;
+ }
- return ret;
+ component_match_add(dev, &match, compare_of, port->parent);
+ of_node_put(port);
+ }
+
+ if (i == 0) {
+ dev_err(dev, "missing 'ports' property\n");
+ return -ENODEV;
+ }
+
+ if (!match) {
+ dev_err(dev, "No available vop found for display-subsystem.\n");
+ return -ENODEV;
+ }
+ /*
+ * For each bound crtc, bind the encoders attached to its
+ * remote endpoint.
+ */
+ for (i = 0;; i++) {
+ port = of_parse_phandle(np, "ports", i);
+ if (!port)
+ break;
+
+ if (!of_device_is_available(port->parent)) {
+ of_node_put(port);
+ continue;
+ }
+
+ rockchip_add_endpoints(dev, &match, port);
+ of_node_put(port);
+ }
+
+ return component_master_add_with_match(dev, &rockchip_drm_ops, match);
}
static int rockchip_drm_platform_remove(struct platform_device *pdev)
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index 8caea0a..d908321 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -67,6 +67,7 @@ static int rockchip_drm_gem_object_mmap(struct drm_gem_object *obj,
* VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
*/
vma->vm_flags &= ~VM_PFNMAP;
+ vma->vm_pgoff = 0;
ret = dma_mmap_attrs(drm->dev, vma, rk_obj->kvaddr, rk_obj->dma_addr,
obj->size, &rk_obj->dma_attrs);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 5d8ae5e..03c47ee 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -374,6 +374,7 @@ static const struct of_device_id vop_driver_dt_match[] = {
.data = &rk3288_vop },
{},
};
+MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
static inline void vop_writel(struct vop *vop, uint32_t offset, uint32_t v)
{
@@ -959,8 +960,8 @@ static int vop_update_plane_event(struct drm_plane *plane,
val = (dest.y2 - dest.y1 - 1) << 16;
val |= (dest.x2 - dest.x1 - 1) & 0xffff;
VOP_WIN_SET(vop, win, dsp_info, val);
- val = (dsp_sty - 1) << 16;
- val |= (dsp_stx - 1) & 0xffff;
+ val = dsp_sty << 16;
+ val |= dsp_stx & 0xffff;
VOP_WIN_SET(vop, win, dsp_st, val);
VOP_WIN_SET(vop, win, rb_swap, rb_swap);
@@ -1289,7 +1290,7 @@ static void vop_win_state_complete(struct vop_win *vop_win,
if (state->event) {
spin_lock_irqsave(&drm->event_lock, flags);
- drm_send_vblank_event(drm, -1, state->event);
+ drm_crtc_send_vblank_event(crtc, state->event);
spin_unlock_irqrestore(&drm->event_lock, flags);
}
@@ -1575,32 +1576,25 @@ static int vop_initial(struct vop *vop)
return PTR_ERR(vop->dclk);
}
- ret = clk_prepare(vop->hclk);
- if (ret < 0) {
- dev_err(vop->dev, "failed to prepare hclk\n");
- return ret;
- }
-
ret = clk_prepare(vop->dclk);
if (ret < 0) {
dev_err(vop->dev, "failed to prepare dclk\n");
- goto err_unprepare_hclk;
+ return ret;
}
- ret = clk_prepare(vop->aclk);
+ /* Enable both the hclk and aclk to setup the vop */
+ ret = clk_prepare_enable(vop->hclk);
if (ret < 0) {
- dev_err(vop->dev, "failed to prepare aclk\n");
+ dev_err(vop->dev, "failed to prepare/enable hclk\n");
goto err_unprepare_dclk;
}
- /*
- * enable hclk, so that we can config vop register.
- */
- ret = clk_enable(vop->hclk);
+ ret = clk_prepare_enable(vop->aclk);
if (ret < 0) {
- dev_err(vop->dev, "failed to prepare aclk\n");
- goto err_unprepare_aclk;
+ dev_err(vop->dev, "failed to prepare/enable aclk\n");
+ goto err_disable_hclk;
}
+
/*
* do hclk_reset, reset all vop registers.
*/
@@ -1608,7 +1602,7 @@ static int vop_initial(struct vop *vop)
if (IS_ERR(ahb_rst)) {
dev_err(vop->dev, "failed to get ahb reset\n");
ret = PTR_ERR(ahb_rst);
- goto err_disable_hclk;
+ goto err_disable_aclk;
}
reset_control_assert(ahb_rst);
usleep_range(10, 20);
@@ -1634,26 +1628,25 @@ static int vop_initial(struct vop *vop)
if (IS_ERR(vop->dclk_rst)) {
dev_err(vop->dev, "failed to get dclk reset\n");
ret = PTR_ERR(vop->dclk_rst);
- goto err_unprepare_aclk;
+ goto err_disable_aclk;
}
reset_control_assert(vop->dclk_rst);
usleep_range(10, 20);
reset_control_deassert(vop->dclk_rst);
clk_disable(vop->hclk);
+ clk_disable(vop->aclk);
vop->is_enabled = false;
return 0;
+err_disable_aclk:
+ clk_disable_unprepare(vop->aclk);
err_disable_hclk:
- clk_disable(vop->hclk);
-err_unprepare_aclk:
- clk_unprepare(vop->aclk);
+ clk_disable_unprepare(vop->hclk);
err_unprepare_dclk:
clk_unprepare(vop->dclk);
-err_unprepare_hclk:
- clk_unprepare(vop->hclk);
return ret;
}
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig
index fbccc10..10c1b19 100644
--- a/drivers/gpu/drm/sti/Kconfig
+++ b/drivers/gpu/drm/sti/Kconfig
@@ -6,12 +6,6 @@ config DRM_STI
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
select DRM_PANEL
- select FW_LOADER_USER_HELPER_FALLBACK
+ select FW_LOADER
help
Choose this option to enable DRM on STM stiH41x chipset
-
-config DRM_STI_FBDEV
- bool "DRM frame buffer device for STMicroelectronics SoC stiH41x Serie"
- depends on DRM_STI
- help
- Choose this option to enable FBDEV on top of DRM for STM stiH41x chipset
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
index e27490b..b805762 100644
--- a/drivers/gpu/drm/sti/Makefile
+++ b/drivers/gpu/drm/sti/Makefile
@@ -1,26 +1,23 @@
-sticompositor-y := \
+sti-drm-y := \
sti_mixer.o \
sti_gdp.o \
sti_vid.o \
sti_cursor.o \
sti_compositor.o \
sti_crtc.o \
- sti_plane.o
-
-stihdmi-y := sti_hdmi.o \
+ sti_plane.o \
+ sti_crtc.o \
+ sti_plane.o \
+ sti_hdmi.o \
sti_hdmi_tx3g0c55phy.o \
sti_hdmi_tx3g4c28phy.o \
-
-stidvo-y := sti_dvo.o \
- sti_awg_utils.o
-
-obj-$(CONFIG_DRM_STI) = \
+ sti_dvo.o \
+ sti_awg_utils.o \
sti_vtg.o \
sti_vtac.o \
- stihdmi.o \
sti_hda.o \
sti_tvout.o \
- sticompositor.o \
sti_hqvdp.o \
- stidvo.o \
sti_drv.o
+
+obj-$(CONFIG_DRM_STI) = sti-drm.o
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c
index 6029a2e..00d0698 100644
--- a/drivers/gpu/drm/sti/sti_awg_utils.c
+++ b/drivers/gpu/drm/sti/sti_awg_utils.c
@@ -65,7 +65,6 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0;
data_enable = 0;
- arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case REPEAT:
@@ -77,14 +76,12 @@ static int awg_generate_instr(enum opcode opcode,
mux = 0;
data_enable = 0;
- arg = (arg << 22) >> 22;
arg &= (0x3ff);
break;
case JUMP:
mux = 0;
data_enable = 0;
arg |= 0x40; /* for jump instruction 7th bit is 1 */
- arg = (arg << 22) >> 22;
arg &= 0x3ff;
break;
case STOP:
@@ -94,7 +91,6 @@ static int awg_generate_instr(enum opcode opcode,
case RPTSET:
case RPLSET:
case HOLD:
- arg = (arg << 24) >> 24;
arg &= (0x0ff);
break;
default:
diff --git a/drivers/gpu/drm/sti/sti_compositor.c b/drivers/gpu/drm/sti/sti_compositor.c
index c652627..afed217 100644
--- a/drivers/gpu/drm/sti/sti_compositor.c
+++ b/drivers/gpu/drm/sti/sti_compositor.c
@@ -263,7 +263,7 @@ static int sti_compositor_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver sti_compositor_driver = {
+struct platform_driver sti_compositor_driver = {
.driver = {
.name = "sti-compositor",
.of_match_table = compositor_of_match,
@@ -272,8 +272,6 @@ static struct platform_driver sti_compositor_driver = {
.remove = sti_compositor_remove,
};
-module_platform_driver(sti_compositor_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_crtc.c b/drivers/gpu/drm/sti/sti_crtc.c
index 493c4a3..3ae09dc 100644
--- a/drivers/gpu/drm/sti/sti_crtc.c
+++ b/drivers/gpu/drm/sti/sti_crtc.c
@@ -226,7 +226,7 @@ static void sti_crtc_atomic_flush(struct drm_crtc *crtc,
}
}
-static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
+static const struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.enable = sti_crtc_enable,
.disable = sti_crtc_disabling,
.mode_fixup = sti_crtc_mode_fixup,
@@ -254,15 +254,17 @@ static int sti_crtc_set_property(struct drm_crtc *crtc,
int sti_crtc_vblank_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
- struct drm_device *drm_dev;
struct sti_compositor *compo =
container_of(nb, struct sti_compositor, vtg_vblank_nb);
- int *crtc = data;
+ struct drm_crtc *crtc = data;
+ struct sti_mixer *mixer;
unsigned long flags;
struct sti_private *priv;
+ unsigned int pipe;
- drm_dev = compo->mixer[*crtc]->drm_crtc.dev;
- priv = drm_dev->dev_private;
+ priv = crtc->dev->dev_private;
+ pipe = drm_crtc_index(crtc);
+ mixer = compo->mixer[pipe];
if ((event != VTG_TOP_FIELD_EVENT) &&
(event != VTG_BOTTOM_FIELD_EVENT)) {
@@ -270,30 +272,30 @@ int sti_crtc_vblank_cb(struct notifier_block *nb,
return -EINVAL;
}
- drm_handle_vblank(drm_dev, *crtc);
+ drm_crtc_handle_vblank(crtc);
- spin_lock_irqsave(&drm_dev->event_lock, flags);
- if (compo->mixer[*crtc]->pending_event) {
- drm_send_vblank_event(drm_dev, -1,
- compo->mixer[*crtc]->pending_event);
- drm_vblank_put(drm_dev, *crtc);
- compo->mixer[*crtc]->pending_event = NULL;
+ spin_lock_irqsave(&crtc->dev->event_lock, flags);
+ if (mixer->pending_event) {
+ drm_crtc_send_vblank_event(crtc, mixer->pending_event);
+ drm_crtc_vblank_put(crtc);
+ mixer->pending_event = NULL;
}
- spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+ spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
- if (compo->mixer[*crtc]->status == STI_MIXER_DISABLING) {
+ if (mixer->status == STI_MIXER_DISABLING) {
struct drm_plane *p;
/* Disable mixer only if all overlay planes (GDP and VDP)
* are disabled */
- list_for_each_entry(p, &drm_dev->mode_config.plane_list, head) {
+ list_for_each_entry(p, &crtc->dev->mode_config.plane_list,
+ head) {
struct sti_plane *plane = to_sti_plane(p);
if ((plane->desc & STI_PLANE_TYPE_MASK) <= STI_VDP)
if (plane->status != STI_PLANE_DISABLED)
return 0;
}
- sti_crtc_disable(&compo->mixer[*crtc]->drm_crtc);
+ sti_crtc_disable(crtc);
}
return 0;
@@ -304,25 +306,26 @@ int sti_crtc_enable_vblank(struct drm_device *dev, unsigned int pipe)
struct sti_private *dev_priv = dev->dev_private;
struct sti_compositor *compo = dev_priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
+ struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
DRM_DEBUG_DRIVER("\n");
if (sti_vtg_register_client(pipe == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux,
- vtg_vblank_nb, pipe)) {
+ vtg_vblank_nb, crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return -EINVAL;
}
return 0;
}
-EXPORT_SYMBOL(sti_crtc_enable_vblank);
void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
{
struct sti_private *priv = drm_dev->dev_private;
struct sti_compositor *compo = priv->compo;
struct notifier_block *vtg_vblank_nb = &compo->vtg_vblank_nb;
+ struct drm_crtc *crtc = &compo->mixer[pipe]->drm_crtc;
DRM_DEBUG_DRIVER("\n");
@@ -332,13 +335,12 @@ void sti_crtc_disable_vblank(struct drm_device *drm_dev, unsigned int pipe)
/* free the resources of the pending requests */
if (compo->mixer[pipe]->pending_event) {
- drm_vblank_put(drm_dev, pipe);
+ drm_crtc_vblank_put(crtc);
compo->mixer[pipe]->pending_event = NULL;
}
}
-EXPORT_SYMBOL(sti_crtc_disable_vblank);
-static struct drm_crtc_funcs sti_crtc_funcs = {
+static const struct drm_crtc_funcs sti_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.page_flip = drm_atomic_helper_page_flip,
.destroy = sti_crtc_destroy,
@@ -357,7 +359,6 @@ bool sti_crtc_is_main(struct drm_crtc *crtc)
return false;
}
-EXPORT_SYMBOL(sti_crtc_is_main);
int sti_crtc_init(struct drm_device *drm_dev, struct sti_mixer *mixer,
struct drm_plane *primary, struct drm_plane *cursor)
diff --git a/drivers/gpu/drm/sti/sti_drv.c b/drivers/gpu/drm/sti/sti_drv.c
index f846996..1469987 100644
--- a/drivers/gpu/drm/sti/sti_drv.c
+++ b/drivers/gpu/drm/sti/sti_drv.c
@@ -107,7 +107,7 @@ static int sti_atomic_commit(struct drm_device *drm,
return 0;
}
-static struct drm_mode_config_funcs sti_mode_config_funcs = {
+static const struct drm_mode_config_funcs sti_mode_config_funcs = {
.fb_create = drm_fb_cma_create,
.atomic_check = drm_atomic_helper_check,
.atomic_commit = sti_atomic_commit,
@@ -123,8 +123,8 @@ static void sti_mode_config_init(struct drm_device *dev)
* this value would be used to check framebuffer size limitation
* at drm_mode_addfb().
*/
- dev->mode_config.max_width = STI_MAX_FB_HEIGHT;
- dev->mode_config.max_height = STI_MAX_FB_WIDTH;
+ dev->mode_config.max_width = STI_MAX_FB_WIDTH;
+ dev->mode_config.max_height = STI_MAX_FB_HEIGHT;
dev->mode_config.funcs = &sti_mode_config_funcs;
}
@@ -160,11 +160,10 @@ static int sti_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_reset(dev);
-#ifdef CONFIG_DRM_STI_FBDEV
drm_fbdev_cma_init(dev, 32,
dev->mode_config.num_crtc,
dev->mode_config.num_connector);
-#endif
+
return 0;
}
@@ -287,7 +286,29 @@ static struct platform_driver sti_platform_driver = {
},
};
-module_platform_driver(sti_platform_driver);
+static struct platform_driver * const drivers[] = {
+ &sti_tvout_driver,
+ &sti_vtac_driver,
+ &sti_hqvdp_driver,
+ &sti_hdmi_driver,
+ &sti_hda_driver,
+ &sti_dvo_driver,
+ &sti_vtg_driver,
+ &sti_compositor_driver,
+ &sti_platform_driver,
+};
+
+static int sti_drm_init(void)
+{
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_init(sti_drm_init);
+
+static void sti_drm_exit(void)
+{
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
+}
+module_exit(sti_drm_exit);
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
diff --git a/drivers/gpu/drm/sti/sti_drv.h b/drivers/gpu/drm/sti/sti_drv.h
index 9372f69..30ddc20 100644
--- a/drivers/gpu/drm/sti/sti_drv.h
+++ b/drivers/gpu/drm/sti/sti_drv.h
@@ -32,4 +32,13 @@ struct sti_private {
} commit;
};
+extern struct platform_driver sti_tvout_driver;
+extern struct platform_driver sti_vtac_driver;
+extern struct platform_driver sti_hqvdp_driver;
+extern struct platform_driver sti_hdmi_driver;
+extern struct platform_driver sti_hda_driver;
+extern struct platform_driver sti_dvo_driver;
+extern struct platform_driver sti_vtg_driver;
+extern struct platform_driver sti_compositor_driver;
+
#endif
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index d141d64..45cbe2b 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -329,7 +329,8 @@ struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
return dvo_connector->encoder;
}
-static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
+static const
+struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
.get_modes = sti_dvo_connector_get_modes,
.mode_valid = sti_dvo_connector_mode_valid,
.best_encoder = sti_dvo_best_encoder,
@@ -364,7 +365,7 @@ static void sti_dvo_connector_destroy(struct drm_connector *connector)
kfree(dvo_connector);
}
-static struct drm_connector_funcs sti_dvo_connector_funcs = {
+static const struct drm_connector_funcs sti_dvo_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_dvo_connector_detect,
@@ -557,8 +558,6 @@ struct platform_driver sti_dvo_driver = {
.remove = sti_dvo_remove,
};
-module_platform_driver(sti_dvo_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index 9365670..c85dc7d 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -492,7 +492,7 @@ static void sti_gdp_atomic_update(struct drm_plane *drm_plane,
/* Register gdp callback */
if (sti_vtg_register_client(mixer->id == STI_MIXER_MAIN ?
compo->vtg_main : compo->vtg_aux,
- &gdp->vtg_field_nb, mixer->id)) {
+ &gdp->vtg_field_nb, crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return;
}
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 598cd78..d735dac 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -589,7 +589,8 @@ struct drm_encoder *sti_hda_best_encoder(struct drm_connector *connector)
return hda_connector->encoder;
}
-static struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = {
+static const
+struct drm_connector_helper_funcs sti_hda_connector_helper_funcs = {
.get_modes = sti_hda_connector_get_modes,
.mode_valid = sti_hda_connector_mode_valid,
.best_encoder = sti_hda_best_encoder,
@@ -611,7 +612,7 @@ static void sti_hda_connector_destroy(struct drm_connector *connector)
kfree(hda_connector);
}
-static struct drm_connector_funcs sti_hda_connector_funcs = {
+static const struct drm_connector_funcs sti_hda_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hda_connector_detect,
@@ -784,8 +785,6 @@ struct platform_driver sti_hda_driver = {
.remove = sti_hda_remove,
};
-module_platform_driver(sti_hda_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 09e29e4..cd50156 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -628,7 +628,8 @@ struct drm_encoder *sti_hdmi_best_encoder(struct drm_connector *connector)
return hdmi_connector->encoder;
}
-static struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
+static const
+struct drm_connector_helper_funcs sti_hdmi_connector_helper_funcs = {
.get_modes = sti_hdmi_connector_get_modes,
.mode_valid = sti_hdmi_connector_mode_valid,
.best_encoder = sti_hdmi_best_encoder,
@@ -663,7 +664,7 @@ static void sti_hdmi_connector_destroy(struct drm_connector *connector)
kfree(hdmi_connector);
}
-static struct drm_connector_funcs sti_hdmi_connector_funcs = {
+static const struct drm_connector_funcs sti_hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = sti_hdmi_connector_detect,
@@ -700,18 +701,17 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
encoder = sti_hdmi_find_encoder(drm_dev);
if (!encoder)
- goto err_adapt;
+ return -EINVAL;
connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
if (!connector)
- goto err_adapt;
-
+ return -EINVAL;
connector->hdmi = hdmi;
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
if (!bridge)
- goto err_adapt;
+ return -EINVAL;
bridge->driver_private = hdmi;
bridge->funcs = &sti_hdmi_bridge_funcs;
@@ -748,8 +748,7 @@ err_sysfs:
drm_connector_unregister(drm_connector);
err_connector:
drm_connector_cleanup(drm_connector);
-err_adapt:
- put_device(&hdmi->ddc_adapt->dev);
+
return -EINVAL;
}
@@ -794,13 +793,10 @@ static int sti_hdmi_probe(struct platform_device *pdev)
ddc = of_parse_phandle(pdev->dev.of_node, "ddc", 0);
if (ddc) {
- hdmi->ddc_adapt = of_find_i2c_adapter_by_node(ddc);
- if (!hdmi->ddc_adapt) {
- of_node_put(ddc);
- return -EPROBE_DEFER;
- }
-
+ hdmi->ddc_adapt = of_get_i2c_adapter_by_node(ddc);
of_node_put(ddc);
+ if (!hdmi->ddc_adapt)
+ return -EPROBE_DEFER;
}
hdmi->dev = pdev->dev;
@@ -809,24 +805,29 @@ static int sti_hdmi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "hdmi-reg");
if (!res) {
DRM_ERROR("Invalid hdmi resource\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto release_adapter;
}
hdmi->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
- if (!hdmi->regs)
- return -ENOMEM;
+ if (!hdmi->regs) {
+ ret = -ENOMEM;
+ goto release_adapter;
+ }
if (of_device_is_compatible(np, "st,stih416-hdmi")) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"syscfg");
if (!res) {
DRM_ERROR("Invalid syscfg resource\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto release_adapter;
}
hdmi->syscfg = devm_ioremap_nocache(dev, res->start,
resource_size(res));
- if (!hdmi->syscfg)
- return -ENOMEM;
-
+ if (!hdmi->syscfg) {
+ ret = -ENOMEM;
+ goto release_adapter;
+ }
}
hdmi->phy_ops = (struct hdmi_phy_ops *)
@@ -836,25 +837,29 @@ static int sti_hdmi_probe(struct platform_device *pdev)
hdmi->clk_pix = devm_clk_get(dev, "pix");
if (IS_ERR(hdmi->clk_pix)) {
DRM_ERROR("Cannot get hdmi_pix clock\n");
- return PTR_ERR(hdmi->clk_pix);
+ ret = PTR_ERR(hdmi->clk_pix);
+ goto release_adapter;
}
hdmi->clk_tmds = devm_clk_get(dev, "tmds");
if (IS_ERR(hdmi->clk_tmds)) {
DRM_ERROR("Cannot get hdmi_tmds clock\n");
- return PTR_ERR(hdmi->clk_tmds);
+ ret = PTR_ERR(hdmi->clk_tmds);
+ goto release_adapter;
}
hdmi->clk_phy = devm_clk_get(dev, "phy");
if (IS_ERR(hdmi->clk_phy)) {
DRM_ERROR("Cannot get hdmi_phy clock\n");
- return PTR_ERR(hdmi->clk_phy);
+ ret = PTR_ERR(hdmi->clk_phy);
+ goto release_adapter;
}
hdmi->clk_audio = devm_clk_get(dev, "audio");
if (IS_ERR(hdmi->clk_audio)) {
DRM_ERROR("Cannot get hdmi_audio clock\n");
- return PTR_ERR(hdmi->clk_audio);
+ ret = PTR_ERR(hdmi->clk_audio);
+ goto release_adapter;
}
hdmi->hpd = readl(hdmi->regs + HDMI_STA) & HDMI_STA_HOT_PLUG;
@@ -867,7 +872,7 @@ static int sti_hdmi_probe(struct platform_device *pdev)
hdmi_irq_thread, IRQF_ONESHOT, dev_name(dev), hdmi);
if (ret) {
DRM_ERROR("Failed to register HDMI interrupt\n");
- return ret;
+ goto release_adapter;
}
hdmi->reset = devm_reset_control_get(dev, "hdmi");
@@ -878,16 +883,20 @@ static int sti_hdmi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, hdmi);
return component_add(&pdev->dev, &sti_hdmi_ops);
+
+ release_adapter:
+ i2c_put_adapter(hdmi->ddc_adapt);
+
+ return ret;
}
static int sti_hdmi_remove(struct platform_device *pdev)
{
struct sti_hdmi *hdmi = dev_get_drvdata(&pdev->dev);
- if (hdmi->ddc_adapt)
- put_device(&hdmi->ddc_adapt->dev);
-
+ i2c_put_adapter(hdmi->ddc_adapt);
component_del(&pdev->dev, &sti_hdmi_ops);
+
return 0;
}
@@ -901,8 +910,6 @@ struct platform_driver sti_hdmi_driver = {
.remove = sti_hdmi_remove,
};
-module_platform_driver(sti_hdmi_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index 7c8f9b8..ea0690b 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -628,6 +628,153 @@ static void sti_hqvdp_init(struct sti_hqvdp *hqvdp)
memset(hqvdp->hqvdp_cmd, 0, size);
}
+static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
+{
+ /* Configure Plugs (same for RD & WR) */
+ writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE);
+ writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC);
+ writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC);
+ writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK);
+ writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG);
+ writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE);
+ writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL);
+
+ writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE);
+ writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC);
+ writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC);
+ writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK);
+ writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG);
+ writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE);
+ writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL);
+}
+
+/**
+ * sti_hqvdp_start_xp70
+ * @hqvdp: hqvdp pointer
+ *
+ * Run the xP70 initialization sequence
+ */
+static void sti_hqvdp_start_xp70(struct sti_hqvdp *hqvdp)
+{
+ const struct firmware *firmware;
+ u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem;
+ u8 *data;
+ int i;
+ struct fw_header {
+ int rd_size;
+ int wr_size;
+ int pmem_size;
+ int dmem_size;
+ } *header;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (hqvdp->xp70_initialized) {
+ DRM_INFO("HQVDP XP70 already initialized\n");
+ return;
+ }
+
+ /* Request firmware */
+ if (request_firmware(&firmware, HQVDP_FMW_NAME, hqvdp->dev)) {
+ DRM_ERROR("Can't get HQVDP firmware\n");
+ return;
+ }
+
+ /* Check firmware parts */
+ if (!firmware) {
+ DRM_ERROR("Firmware not available\n");
+ return;
+ }
+
+ header = (struct fw_header *)firmware->data;
+ if (firmware->size < sizeof(*header)) {
+ DRM_ERROR("Invalid firmware size (%d)\n", firmware->size);
+ goto out;
+ }
+ if ((sizeof(*header) + header->rd_size + header->wr_size +
+ header->pmem_size + header->dmem_size) != firmware->size) {
+ DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n",
+ sizeof(*header), header->rd_size, header->wr_size,
+ header->pmem_size, header->dmem_size,
+ firmware->size);
+ goto out;
+ }
+
+ data = (u8 *)firmware->data;
+ data += sizeof(*header);
+ fw_rd_plug = (void *)data;
+ data += header->rd_size;
+ fw_wr_plug = (void *)data;
+ data += header->wr_size;
+ fw_pmem = (void *)data;
+ data += header->pmem_size;
+ fw_dmem = (void *)data;
+
+ /* Enable clock */
+ if (clk_prepare_enable(hqvdp->clk))
+ DRM_ERROR("Failed to prepare/enable HQVDP clk\n");
+
+ /* Reset */
+ writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL);
+
+ for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
+ if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1)
+ & STARTUP_CTRL1_RST_DONE)
+ break;
+ msleep(POLL_DELAY_MS);
+ }
+ if (i == POLL_MAX_ATTEMPT) {
+ DRM_ERROR("Could not reset\n");
+ goto out;
+ }
+
+ /* Init Read & Write plugs */
+ for (i = 0; i < header->rd_size / 4; i++)
+ writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4);
+ for (i = 0; i < header->wr_size / 4; i++)
+ writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4);
+
+ sti_hqvdp_init_plugs(hqvdp);
+
+ /* Authorize Idle Mode */
+ writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1);
+
+ /* Prevent VTG interruption during the boot */
+ writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
+ writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
+
+ /* Download PMEM & DMEM */
+ for (i = 0; i < header->pmem_size / 4; i++)
+ writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4);
+ for (i = 0; i < header->dmem_size / 4; i++)
+ writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4);
+
+ /* Enable fetch */
+ writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2);
+
+ /* Wait end of boot */
+ for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
+ if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70)
+ & INFO_XP70_FW_READY)
+ break;
+ msleep(POLL_DELAY_MS);
+ }
+ if (i == POLL_MAX_ATTEMPT) {
+ DRM_ERROR("Could not boot\n");
+ goto out;
+ }
+
+ /* Launch Vsync */
+ writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
+
+ DRM_INFO("HQVDP XP70 initialized\n");
+
+ hqvdp->xp70_initialized = true;
+
+out:
+ release_firmware(firmware);
+}
+
static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
struct drm_plane_state *oldstate)
{
@@ -754,6 +901,9 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
sti_hqvdp_update_hvsrc(HVSRC_VERT, scale_v, &cmd->hvsrc);
if (first_prepare) {
+ /* Start HQVDP XP70 coprocessor */
+ sti_hqvdp_start_xp70(hqvdp);
+
/* Prevent VTG shutdown */
if (clk_prepare_enable(hqvdp->clk_pix_main)) {
DRM_ERROR("Failed to prepare/enable pix main clk\n");
@@ -763,7 +913,7 @@ static void sti_hqvdp_atomic_update(struct drm_plane *drm_plane,
/* Register VTG Vsync callback to handle bottom fields */
if (sti_vtg_register_client(hqvdp->vtg,
&hqvdp->vtg_nb,
- mixer->id)) {
+ crtc)) {
DRM_ERROR("Cannot register VTG notifier\n");
return;
}
@@ -836,168 +986,16 @@ static struct drm_plane *sti_hqvdp_create(struct drm_device *drm_dev,
return &hqvdp->plane.drm_plane;
}
-static void sti_hqvdp_init_plugs(struct sti_hqvdp *hqvdp)
-{
- /* Configure Plugs (same for RD & WR) */
- writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_RD_PLUG_PAGE_SIZE);
- writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_RD_PLUG_MIN_OPC);
- writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_RD_PLUG_MAX_OPC);
- writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_RD_PLUG_MAX_CHK);
- writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_RD_PLUG_MAX_MSG);
- writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_RD_PLUG_MIN_SPACE);
- writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_RD_PLUG_CONTROL);
-
- writel(PLUG_PAGE_SIZE_256, hqvdp->regs + HQVDP_WR_PLUG_PAGE_SIZE);
- writel(PLUG_MIN_OPC_8, hqvdp->regs + HQVDP_WR_PLUG_MIN_OPC);
- writel(PLUG_MAX_OPC_64, hqvdp->regs + HQVDP_WR_PLUG_MAX_OPC);
- writel(PLUG_MAX_CHK_2X, hqvdp->regs + HQVDP_WR_PLUG_MAX_CHK);
- writel(PLUG_MAX_MSG_1X, hqvdp->regs + HQVDP_WR_PLUG_MAX_MSG);
- writel(PLUG_MIN_SPACE_1, hqvdp->regs + HQVDP_WR_PLUG_MIN_SPACE);
- writel(PLUG_CONTROL_ENABLE, hqvdp->regs + HQVDP_WR_PLUG_CONTROL);
-}
-
-/**
- * sti_hqvdp_start_xp70
- * @firmware: firmware found
- * @ctxt: hqvdp structure
- *
- * Run the xP70 initialization sequence
- */
-static void sti_hqvdp_start_xp70(const struct firmware *firmware, void *ctxt)
-{
- struct sti_hqvdp *hqvdp = ctxt;
- u32 *fw_rd_plug, *fw_wr_plug, *fw_pmem, *fw_dmem;
- u8 *data;
- int i;
- struct fw_header {
- int rd_size;
- int wr_size;
- int pmem_size;
- int dmem_size;
- } *header;
-
- DRM_DEBUG_DRIVER("\n");
-
- if (hqvdp->xp70_initialized) {
- DRM_INFO("HQVDP XP70 already initialized\n");
- return;
- }
-
- /* Check firmware parts */
- if (!firmware) {
- DRM_ERROR("Firmware not available\n");
- return;
- }
-
- header = (struct fw_header *) firmware->data;
- if (firmware->size < sizeof(*header)) {
- DRM_ERROR("Invalid firmware size (%d)\n", firmware->size);
- goto out;
- }
- if ((sizeof(*header) + header->rd_size + header->wr_size +
- header->pmem_size + header->dmem_size) != firmware->size) {
- DRM_ERROR("Invalid fmw structure (%d+%d+%d+%d+%d != %d)\n",
- sizeof(*header), header->rd_size, header->wr_size,
- header->pmem_size, header->dmem_size,
- firmware->size);
- goto out;
- }
-
- data = (u8 *) firmware->data;
- data += sizeof(*header);
- fw_rd_plug = (void *) data;
- data += header->rd_size;
- fw_wr_plug = (void *) data;
- data += header->wr_size;
- fw_pmem = (void *) data;
- data += header->pmem_size;
- fw_dmem = (void *) data;
-
- /* Enable clock */
- if (clk_prepare_enable(hqvdp->clk))
- DRM_ERROR("Failed to prepare/enable HQVDP clk\n");
-
- /* Reset */
- writel(SW_RESET_CTRL_FULL, hqvdp->regs + HQVDP_MBX_SW_RESET_CTRL);
-
- for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
- if (readl(hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1)
- & STARTUP_CTRL1_RST_DONE)
- break;
- msleep(POLL_DELAY_MS);
- }
- if (i == POLL_MAX_ATTEMPT) {
- DRM_ERROR("Could not reset\n");
- goto out;
- }
-
- /* Init Read & Write plugs */
- for (i = 0; i < header->rd_size / 4; i++)
- writel(fw_rd_plug[i], hqvdp->regs + HQVDP_RD_PLUG + i * 4);
- for (i = 0; i < header->wr_size / 4; i++)
- writel(fw_wr_plug[i], hqvdp->regs + HQVDP_WR_PLUG + i * 4);
-
- sti_hqvdp_init_plugs(hqvdp);
-
- /* Authorize Idle Mode */
- writel(STARTUP_CTRL1_AUTH_IDLE, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL1);
-
- /* Prevent VTG interruption during the boot */
- writel(SOFT_VSYNC_SW_CTRL_IRQ, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
- writel(0, hqvdp->regs + HQVDP_MBX_NEXT_CMD);
-
- /* Download PMEM & DMEM */
- for (i = 0; i < header->pmem_size / 4; i++)
- writel(fw_pmem[i], hqvdp->regs + HQVDP_PMEM + i * 4);
- for (i = 0; i < header->dmem_size / 4; i++)
- writel(fw_dmem[i], hqvdp->regs + HQVDP_DMEM + i * 4);
-
- /* Enable fetch */
- writel(STARTUP_CTRL2_FETCH_EN, hqvdp->regs + HQVDP_MBX_STARTUP_CTRL2);
-
- /* Wait end of boot */
- for (i = 0; i < POLL_MAX_ATTEMPT; i++) {
- if (readl(hqvdp->regs + HQVDP_MBX_INFO_XP70)
- & INFO_XP70_FW_READY)
- break;
- msleep(POLL_DELAY_MS);
- }
- if (i == POLL_MAX_ATTEMPT) {
- DRM_ERROR("Could not boot\n");
- goto out;
- }
-
- /* Launch Vsync */
- writel(SOFT_VSYNC_HW, hqvdp->regs + HQVDP_MBX_SOFT_VSYNC);
-
- DRM_INFO("HQVDP XP70 initialized\n");
-
- hqvdp->xp70_initialized = true;
-
-out:
- release_firmware(firmware);
-}
-
int sti_hqvdp_bind(struct device *dev, struct device *master, void *data)
{
struct sti_hqvdp *hqvdp = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
struct drm_plane *plane;
- int err;
DRM_DEBUG_DRIVER("\n");
hqvdp->drm_dev = drm_dev;
- /* Request for firmware */
- err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
- HQVDP_FMW_NAME, hqvdp->dev,
- GFP_KERNEL, hqvdp, sti_hqvdp_start_xp70);
- if (err) {
- DRM_ERROR("Can't get HQVDP firmware\n");
- return err;
- }
-
/* Create HQVDP plane once xp70 is initialized */
plane = sti_hqvdp_create(drm_dev, hqvdp->dev, STI_HQVDP_0);
if (!plane)
@@ -1090,8 +1088,6 @@ struct platform_driver sti_hqvdp_driver = {
.remove = sti_hqvdp_remove,
};
-module_platform_driver(sti_hqvdp_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_mixer.c b/drivers/gpu/drm/sti/sti_mixer.c
index 0182e93..49db835 100644
--- a/drivers/gpu/drm/sti/sti_mixer.c
+++ b/drivers/gpu/drm/sti/sti_mixer.c
@@ -10,6 +10,11 @@
#include "sti_mixer.h"
#include "sti_vtg.h"
+/* Module parameter to set the background color of the mixer */
+static unsigned int bkg_color = 0x000000;
+MODULE_PARM_DESC(bkgcolor, "Value of the background color 0xRRGGBB");
+module_param_named(bkgcolor, bkg_color, int, 0644);
+
/* Identity: G=Y , B=Cb , R=Cr */
static const u32 mixerColorSpaceMatIdentity[] = {
0x10000000, 0x00000000, 0x10000000, 0x00001000,
@@ -58,7 +63,6 @@ const char *sti_mixer_to_str(struct sti_mixer *mixer)
return "<UNKNOWN MIXER>";
}
}
-EXPORT_SYMBOL(sti_mixer_to_str);
static inline u32 sti_mixer_reg_read(struct sti_mixer *mixer, u32 reg_id)
{
@@ -81,11 +85,9 @@ void sti_mixer_set_background_status(struct sti_mixer *mixer, bool enable)
}
static void sti_mixer_set_background_color(struct sti_mixer *mixer,
- u8 red, u8 green, u8 blue)
+ unsigned int rgb)
{
- u32 val = (red << 16) | (green << 8) | blue;
-
- sti_mixer_reg_write(mixer, GAM_MIXER_BKC, val);
+ sti_mixer_reg_write(mixer, GAM_MIXER_BKC, rgb);
}
static void sti_mixer_set_background_area(struct sti_mixer *mixer,
@@ -175,7 +177,7 @@ int sti_mixer_active_video_area(struct sti_mixer *mixer,
sti_mixer_reg_write(mixer, GAM_MIXER_AVO, ydo << 16 | xdo);
sti_mixer_reg_write(mixer, GAM_MIXER_AVS, yds << 16 | xds);
- sti_mixer_set_background_color(mixer, 0xFF, 0, 0);
+ sti_mixer_set_background_color(mixer, bkg_color);
sti_mixer_set_background_area(mixer, mode);
sti_mixer_set_background_status(mixer, true);
diff --git a/drivers/gpu/drm/sti/sti_plane.c b/drivers/gpu/drm/sti/sti_plane.c
index d5c5e91..2e5c751 100644
--- a/drivers/gpu/drm/sti/sti_plane.c
+++ b/drivers/gpu/drm/sti/sti_plane.c
@@ -42,7 +42,6 @@ const char *sti_plane_to_str(struct sti_plane *plane)
return "<UNKNOWN PLANE>";
}
}
-EXPORT_SYMBOL(sti_plane_to_str);
static void sti_plane_destroy(struct drm_plane *drm_plane)
{
@@ -108,7 +107,6 @@ void sti_plane_init_property(struct sti_plane *plane,
plane->drm_plane.base.id,
sti_plane_to_str(plane), plane->zorder);
}
-EXPORT_SYMBOL(sti_plane_init_property);
struct drm_plane_funcs sti_plane_helpers_funcs = {
.update_plane = drm_atomic_helper_update_plane,
@@ -119,4 +117,3 @@ struct drm_plane_funcs sti_plane_helpers_funcs = {
.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
};
-EXPORT_SYMBOL(sti_plane_helpers_funcs);
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index c1aac8e..c8a4c5d 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -735,8 +735,6 @@ struct platform_driver sti_tvout_driver = {
.remove = sti_tvout_remove,
};
-module_platform_driver(sti_tvout_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vtac.c b/drivers/gpu/drm/sti/sti_vtac.c
index 97bcdac..b1eb0d7 100644
--- a/drivers/gpu/drm/sti/sti_vtac.c
+++ b/drivers/gpu/drm/sti/sti_vtac.c
@@ -216,8 +216,6 @@ struct platform_driver sti_vtac_driver = {
.remove = sti_vtac_remove,
};
-module_platform_driver(sti_vtac_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vtg.c b/drivers/gpu/drm/sti/sti_vtg.c
index aa80971..d56630c 100644
--- a/drivers/gpu/drm/sti/sti_vtg.c
+++ b/drivers/gpu/drm/sti/sti_vtg.c
@@ -79,7 +79,7 @@ LIST_HEAD(vtg_lookup);
* @irq: VTG irq
* @type: VTG type (main or aux)
* @notifier_list: notifier callback
- * @crtc_id: the crtc id for vblank event
+ * @crtc: the CRTC for vblank event
* @slave: slave vtg
* @link: List node to link the structure in lookup list
*/
@@ -90,7 +90,7 @@ struct sti_vtg {
int irq;
u32 irq_status;
struct raw_notifier_head notifier_list;
- int crtc_id;
+ struct drm_crtc *crtc;
struct sti_vtg *slave;
struct list_head link;
};
@@ -110,7 +110,6 @@ struct sti_vtg *of_vtg_find(struct device_node *np)
}
return NULL;
}
-EXPORT_SYMBOL(of_vtg_find);
static void vtg_reset(struct sti_vtg *vtg)
{
@@ -242,7 +241,6 @@ void sti_vtg_set_config(struct sti_vtg *vtg,
else
vtg_enable_irq(vtg);
}
-EXPORT_SYMBOL(sti_vtg_set_config);
/**
* sti_vtg_get_line_number
@@ -265,7 +263,6 @@ u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y)
return start_line + y;
}
-EXPORT_SYMBOL(sti_vtg_get_line_number);
/**
* sti_vtg_get_pixel_number
@@ -281,18 +278,16 @@ u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x)
{
return mode.htotal - mode.hsync_start + x;
}
-EXPORT_SYMBOL(sti_vtg_get_pixel_number);
-int sti_vtg_register_client(struct sti_vtg *vtg,
- struct notifier_block *nb, int crtc_id)
+int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
+ struct drm_crtc *crtc)
{
if (vtg->slave)
- return sti_vtg_register_client(vtg->slave, nb, crtc_id);
+ return sti_vtg_register_client(vtg->slave, nb, crtc);
- vtg->crtc_id = crtc_id;
+ vtg->crtc = crtc;
return raw_notifier_chain_register(&vtg->notifier_list, nb);
}
-EXPORT_SYMBOL(sti_vtg_register_client);
int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
{
@@ -301,7 +296,6 @@ int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
return raw_notifier_chain_unregister(&vtg->notifier_list, nb);
}
-EXPORT_SYMBOL(sti_vtg_unregister_client);
static irqreturn_t vtg_irq_thread(int irq, void *arg)
{
@@ -311,7 +305,7 @@ static irqreturn_t vtg_irq_thread(int irq, void *arg)
event = (vtg->irq_status & VTG_IRQ_TOP) ?
VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT;
- raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id);
+ raw_notifier_call_chain(&vtg->notifier_list, event, vtg->crtc);
return IRQ_HANDLED;
}
@@ -406,8 +400,6 @@ struct platform_driver sti_vtg_driver = {
.remove = vtg_remove,
};
-module_platform_driver(sti_vtg_driver);
-
MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_vtg.h b/drivers/gpu/drm/sti/sti_vtg.h
index e84d23f..cd2439f 100644
--- a/drivers/gpu/drm/sti/sti_vtg.h
+++ b/drivers/gpu/drm/sti/sti_vtg.h
@@ -17,8 +17,8 @@ struct notifier_block;
struct sti_vtg *of_vtg_find(struct device_node *np);
void sti_vtg_set_config(struct sti_vtg *vtg,
const struct drm_display_mode *mode);
-int sti_vtg_register_client(struct sti_vtg *vtg,
- struct notifier_block *nb, int crtc_id);
+int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb,
+ struct drm_crtc *crtc);
int sti_vtg_unregister_client(struct sti_vtg *vtg,
struct notifier_block *nb);
diff --git a/drivers/gpu/drm/ttm/ttm_lock.c b/drivers/gpu/drm/ttm/ttm_lock.c
index 6a95454..f154fb1 100644
--- a/drivers/gpu/drm/ttm/ttm_lock.c
+++ b/drivers/gpu/drm/ttm/ttm_lock.c
@@ -180,7 +180,7 @@ int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
spin_unlock(&lock->lock);
}
} else
- wait_event(lock->queue, __ttm_read_lock(lock));
+ wait_event(lock->queue, __ttm_write_lock(lock));
return ret;
}
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index e502802..2d7d115 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -1,9 +1,10 @@
config DRM_VC4
tristate "Broadcom VC4 Graphics"
depends on ARCH_BCM2835 || COMPILE_TEST
- depends on DRM
+ depends on DRM && HAVE_DMA_ATTRS
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
+ select DRM_GEM_CMA_HELPER
help
Choose this option if you have a system that has a Broadcom
VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835.
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7a9f476..265064c 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -168,7 +168,7 @@ static int vc4_get_clock_select(struct drm_crtc *crtc)
struct drm_connector *connector;
drm_for_each_connector(connector, crtc->dev) {
- if (connector && connector->state->crtc == crtc) {
+ if (connector->state->crtc == crtc) {
struct drm_encoder *encoder = connector->encoder;
struct vc4_encoder *vc4_encoder =
to_vc4_encoder(encoder);
@@ -401,7 +401,8 @@ static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
dlist_next++;
HVS_WRITE(SCALER_DISPLISTX(vc4_crtc->channel),
- (u32 *)vc4_crtc->dlist - (u32 *)vc4->hvs->dlist);
+ (u32 __iomem *)vc4_crtc->dlist -
+ (u32 __iomem *)vc4->hvs->dlist);
/* Make the next display list start after ours. */
vc4_crtc->dlist_size -= (dlist_next - vc4_crtc->dlist);
@@ -591,14 +592,14 @@ static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
* that will take too much.
*/
primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
- if (!primary_plane) {
+ if (IS_ERR(primary_plane)) {
dev_err(dev, "failed to construct primary plane\n");
ret = PTR_ERR(primary_plane);
goto err;
}
cursor_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
- if (!cursor_plane) {
+ if (IS_ERR(cursor_plane)) {
dev_err(dev, "failed to construct cursor plane\n");
ret = PTR_ERR(cursor_plane);
goto err_primary;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 6e73060..d5db9e0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -259,7 +259,6 @@ static struct platform_driver vc4_platform_driver = {
.remove = vc4_platform_drm_remove,
.driver = {
.name = "vc4-drm",
- .owner = THIS_MODULE,
.of_match_table = vc4_of_match,
},
};
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index ab1673f..8098c5b 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -75,10 +75,10 @@ void vc4_hvs_dump_state(struct drm_device *dev)
for (i = 0; i < 64; i += 4) {
DRM_INFO("0x%08x (%s): 0x%08x 0x%08x 0x%08x 0x%08x\n",
i * 4, i < HVS_BOOTLOADER_DLIST_END ? "B" : "D",
- ((uint32_t *)vc4->hvs->dlist)[i + 0],
- ((uint32_t *)vc4->hvs->dlist)[i + 1],
- ((uint32_t *)vc4->hvs->dlist)[i + 2],
- ((uint32_t *)vc4->hvs->dlist)[i + 3]);
+ readl((u32 __iomem *)vc4->hvs->dlist + i + 0),
+ readl((u32 __iomem *)vc4->hvs->dlist + i + 1),
+ readl((u32 __iomem *)vc4->hvs->dlist + i + 2),
+ readl((u32 __iomem *)vc4->hvs->dlist + i + 3));
}
}
diff --git a/drivers/gpu/drm/vc4/vc4_plane.c b/drivers/gpu/drm/vc4/vc4_plane.c
index cdd8b10..887f3ca 100644
--- a/drivers/gpu/drm/vc4/vc4_plane.c
+++ b/drivers/gpu/drm/vc4/vc4_plane.c
@@ -70,7 +70,7 @@ static bool plane_enabled(struct drm_plane_state *state)
return state->fb && state->crtc;
}
-struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
+static struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
{
struct vc4_plane_state *vc4_state;
@@ -97,8 +97,8 @@ struct drm_plane_state *vc4_plane_duplicate_state(struct drm_plane *plane)
return &vc4_state->base;
}
-void vc4_plane_destroy_state(struct drm_plane *plane,
- struct drm_plane_state *state)
+static void vc4_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
struct vc4_plane_state *vc4_state = to_vc4_plane_state(state);
@@ -108,7 +108,7 @@ void vc4_plane_destroy_state(struct drm_plane *plane,
}
/* Called during init to allocate the plane's atomic state. */
-void vc4_plane_reset(struct drm_plane *plane)
+static void vc4_plane_reset(struct drm_plane *plane)
{
struct vc4_plane_state *vc4_state;
@@ -157,6 +157,16 @@ static int vc4_plane_mode_set(struct drm_plane *plane,
int crtc_w = state->crtc_w;
int crtc_h = state->crtc_h;
+ if (state->crtc_w << 16 != state->src_w ||
+ state->crtc_h << 16 != state->src_h) {
+ /* We don't support scaling yet, which involves
+ * allocating the LBM memory for scaling temporary
+ * storage, and putting filter kernels in the HVS
+ * context.
+ */
+ return -EINVAL;
+ }
+
if (crtc_x < 0) {
offset += drm_format_plane_cpp(fb->pixel_format, 0) * -crtc_x;
crtc_w += crtc_x;
diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c
index f545913..578fe0a 100644
--- a/drivers/gpu/drm/virtio/virtgpu_display.c
+++ b/drivers/gpu/drm/virtio/virtgpu_display.c
@@ -412,7 +412,7 @@ static const struct drm_connector_funcs virtio_gpu_connector_funcs = {
.save = virtio_gpu_conn_save,
.restore = virtio_gpu_conn_restore,
.detect = virtio_gpu_conn_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
+ .fill_modes = drm_helper_probe_single_connector_modes_nomerge,
.destroy = virtio_gpu_conn_destroy,
.reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index a09cf85..c49812b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -1233,6 +1233,7 @@ static void vmw_master_drop(struct drm_device *dev,
vmw_fp->locked_master = drm_master_get(file_priv->master);
ret = ttm_vt_lock(&vmaster->lock, false, vmw_fp->tfile);
+ vmw_kms_legacy_hotspot_clear(dev_priv);
if (unlikely((ret != 0))) {
DRM_ERROR("Unable to lock TTM at VT switch.\n");
drm_master_put(&vmw_fp->locked_master);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
index a8ae9df..469cdd5 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
@@ -925,6 +925,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
uint32_t num_clips);
int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv);
int vmw_dumb_create(struct drm_file *file_priv,
struct drm_device *dev,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
index a8baf5f..b6a0806 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
@@ -390,7 +390,7 @@ void *vmw_fifo_reserve_dx(struct vmw_private *dev_priv, uint32_t bytes,
else if (ctx_id == SVGA3D_INVALID_ID)
ret = vmw_local_fifo_reserve(dev_priv, bytes);
else {
- WARN_ON("Command buffer has not been allocated.\n");
+ WARN(1, "Command buffer has not been allocated.\n");
ret = NULL;
}
if (IS_ERR_OR_NULL(ret)) {
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 9fcd7f8..9b4bb9e 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -133,13 +133,19 @@ void vmw_cursor_update_position(struct vmw_private *dev_priv,
vmw_mmio_write(++count, fifo_mem + SVGA_FIFO_CURSOR_COUNT);
}
-int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
- uint32_t handle, uint32_t width, uint32_t height)
+
+/*
+ * vmw_du_crtc_cursor_set2 - Driver cursor_set2 callback.
+ */
+int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height,
+ int32_t hot_x, int32_t hot_y)
{
struct vmw_private *dev_priv = vmw_priv(crtc->dev);
struct vmw_display_unit *du = vmw_crtc_to_du(crtc);
struct vmw_surface *surface = NULL;
struct vmw_dma_buffer *dmabuf = NULL;
+ s32 hotspot_x, hotspot_y;
int ret;
/*
@@ -151,6 +157,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
*/
drm_modeset_unlock_crtc(crtc);
drm_modeset_lock_all(dev_priv->dev);
+ hotspot_x = hot_x + du->hotspot_x;
+ hotspot_y = hot_y + du->hotspot_y;
/* A lot of the code assumes this */
if (handle && (width != 64 || height != 64)) {
@@ -187,31 +195,34 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
vmw_dmabuf_unreference(&du->cursor_dmabuf);
/* setup new image */
+ ret = 0;
if (surface) {
/* vmw_user_surface_lookup takes one reference */
du->cursor_surface = surface;
du->cursor_surface->snooper.crtc = crtc;
du->cursor_age = du->cursor_surface->snooper.age;
- vmw_cursor_update_image(dev_priv, surface->snooper.image,
- 64, 64, du->hotspot_x, du->hotspot_y);
+ ret = vmw_cursor_update_image(dev_priv, surface->snooper.image,
+ 64, 64, hotspot_x, hotspot_y);
} else if (dmabuf) {
/* vmw_user_surface_lookup takes one reference */
du->cursor_dmabuf = dmabuf;
ret = vmw_cursor_update_dmabuf(dev_priv, dmabuf, width, height,
- du->hotspot_x, du->hotspot_y);
+ hotspot_x, hotspot_y);
} else {
vmw_cursor_update_position(dev_priv, false, 0, 0);
- ret = 0;
goto out;
}
- vmw_cursor_update_position(dev_priv, true,
- du->cursor_x + du->hotspot_x,
- du->cursor_y + du->hotspot_y);
+ if (!ret) {
+ vmw_cursor_update_position(dev_priv, true,
+ du->cursor_x + hotspot_x,
+ du->cursor_y + hotspot_y);
+ du->core_hotspot_x = hot_x;
+ du->core_hotspot_y = hot_y;
+ }
- ret = 0;
out:
drm_modeset_unlock_all(dev_priv->dev);
drm_modeset_lock_crtc(crtc, crtc->cursor);
@@ -239,8 +250,10 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
drm_modeset_lock_all(dev_priv->dev);
vmw_cursor_update_position(dev_priv, shown,
- du->cursor_x + du->hotspot_x,
- du->cursor_y + du->hotspot_y);
+ du->cursor_x + du->hotspot_x +
+ du->core_hotspot_x,
+ du->cursor_y + du->hotspot_y +
+ du->core_hotspot_y);
drm_modeset_unlock_all(dev_priv->dev);
drm_modeset_lock_crtc(crtc, crtc->cursor);
@@ -334,6 +347,29 @@ err_unreserve:
ttm_bo_unreserve(bo);
}
+/**
+ * vmw_kms_legacy_hotspot_clear - Clear legacy hotspots
+ *
+ * @dev_priv: Pointer to the device private struct.
+ *
+ * Clears all legacy hotspots.
+ */
+void vmw_kms_legacy_hotspot_clear(struct vmw_private *dev_priv)
+{
+ struct drm_device *dev = dev_priv->dev;
+ struct vmw_display_unit *du;
+ struct drm_crtc *crtc;
+
+ drm_modeset_lock_all(dev);
+ drm_for_each_crtc(crtc, dev) {
+ du = vmw_crtc_to_du(crtc);
+
+ du->hotspot_x = 0;
+ du->hotspot_y = 0;
+ }
+ drm_modeset_unlock_all(dev);
+}
+
void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
@@ -351,7 +387,9 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
du->cursor_age = du->cursor_surface->snooper.age;
vmw_cursor_update_image(dev_priv,
du->cursor_surface->snooper.image,
- 64, 64, du->hotspot_x, du->hotspot_y);
+ 64, 64,
+ du->hotspot_x + du->core_hotspot_x,
+ du->hotspot_y + du->core_hotspot_y);
}
mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
index 782df7c..edd8150 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h
@@ -159,6 +159,8 @@ struct vmw_display_unit {
int hotspot_x;
int hotspot_y;
+ s32 core_hotspot_x;
+ s32 core_hotspot_y;
unsigned unit;
@@ -193,8 +195,9 @@ void vmw_du_crtc_restore(struct drm_crtc *crtc);
void vmw_du_crtc_gamma_set(struct drm_crtc *crtc,
u16 *r, u16 *g, u16 *b,
uint32_t start, uint32_t size);
-int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
- uint32_t handle, uint32_t width, uint32_t height);
+int vmw_du_crtc_cursor_set2(struct drm_crtc *crtc, struct drm_file *file_priv,
+ uint32_t handle, uint32_t width, uint32_t height,
+ int32_t hot_x, int32_t hot_y);
int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y);
int vmw_du_connector_dpms(struct drm_connector *connector, int mode);
void vmw_du_connector_save(struct drm_connector *connector);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
index bb63e4d..52caecb 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
@@ -297,7 +297,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
static struct drm_crtc_funcs vmw_legacy_crtc_funcs = {
.save = vmw_du_crtc_save,
.restore = vmw_du_crtc_restore,
- .cursor_set = vmw_du_crtc_cursor_set,
+ .cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_ldu_crtc_destroy,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
index b96d1ab..13926ff 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
@@ -533,7 +533,7 @@ out_no_fence:
static struct drm_crtc_funcs vmw_screen_object_crtc_funcs = {
.save = vmw_du_crtc_save,
.restore = vmw_du_crtc_restore,
- .cursor_set = vmw_du_crtc_cursor_set,
+ .cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_sou_crtc_destroy,
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
index b1fc1c0..f823fc3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_stdu.c
@@ -1043,7 +1043,7 @@ out_finish:
static struct drm_crtc_funcs vmw_stdu_crtc_funcs = {
.save = vmw_du_crtc_save,
.restore = vmw_du_crtc_restore,
- .cursor_set = vmw_du_crtc_cursor_set,
+ .cursor_set2 = vmw_du_crtc_cursor_set2,
.cursor_move = vmw_du_crtc_cursor_move,
.gamma_set = vmw_du_crtc_gamma_set,
.destroy = vmw_stdu_crtc_destroy,
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index ba47b30..f2e13eb 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -28,6 +28,7 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/of_device.h>
+#include <linux/of_graph.h>
#include <drm/drm_fourcc.h>
@@ -993,12 +994,26 @@ static void platform_device_unregister_children(struct platform_device *pdev)
struct ipu_platform_reg {
struct ipu_client_platformdata pdata;
const char *name;
- int reg_offset;
};
+/* These must be in the order of the corresponding device tree port nodes */
static const struct ipu_platform_reg client_reg[] = {
{
.pdata = {
+ .csi = 0,
+ .dma[0] = IPUV3_CHANNEL_CSI0,
+ .dma[1] = -EINVAL,
+ },
+ .name = "imx-ipuv3-camera",
+ }, {
+ .pdata = {
+ .csi = 1,
+ .dma[0] = IPUV3_CHANNEL_CSI1,
+ .dma[1] = -EINVAL,
+ },
+ .name = "imx-ipuv3-camera",
+ }, {
+ .pdata = {
.di = 0,
.dc = 5,
.dp = IPU_DP_FLOW_SYNC_BG,
@@ -1015,22 +1030,6 @@ static const struct ipu_platform_reg client_reg[] = {
.dma[1] = -EINVAL,
},
.name = "imx-ipuv3-crtc",
- }, {
- .pdata = {
- .csi = 0,
- .dma[0] = IPUV3_CHANNEL_CSI0,
- .dma[1] = -EINVAL,
- },
- .reg_offset = IPU_CM_CSI0_REG_OFS,
- .name = "imx-ipuv3-camera",
- }, {
- .pdata = {
- .csi = 1,
- .dma[0] = IPUV3_CHANNEL_CSI1,
- .dma[1] = -EINVAL,
- },
- .reg_offset = IPU_CM_CSI1_REG_OFS,
- .name = "imx-ipuv3-camera",
},
};
@@ -1051,22 +1050,30 @@ static int ipu_add_client_devices(struct ipu_soc *ipu, unsigned long ipu_base)
for (i = 0; i < ARRAY_SIZE(client_reg); i++) {
const struct ipu_platform_reg *reg = &client_reg[i];
struct platform_device *pdev;
- struct resource res;
-
- if (reg->reg_offset) {
- memset(&res, 0, sizeof(res));
- res.flags = IORESOURCE_MEM;
- res.start = ipu_base + ipu->devtype->cm_ofs + reg->reg_offset;
- res.end = res.start + PAGE_SIZE - 1;
- pdev = platform_device_register_resndata(dev, reg->name,
- id++, &res, 1, &reg->pdata, sizeof(reg->pdata));
- } else {
- pdev = platform_device_register_data(dev, reg->name,
- id++, &reg->pdata, sizeof(reg->pdata));
+
+ pdev = platform_device_alloc(reg->name, id++);
+ if (!pdev) {
+ ret = -ENOMEM;
+ goto err_register;
+ }
+
+ pdev->dev.parent = dev;
+
+ /* Associate subdevice with the corresponding port node */
+ pdev->dev.of_node = of_graph_get_port_by_id(dev->of_node, i);
+ if (!pdev->dev.of_node) {
+ dev_err(dev, "missing port@%d node in %s\n", i,
+ dev->of_node->full_name);
+ ret = -ENODEV;
+ goto err_register;
}
- if (IS_ERR(pdev)) {
- ret = PTR_ERR(pdev);
+ ret = platform_device_add_data(pdev, &reg->pdata,
+ sizeof(reg->pdata));
+ if (!ret)
+ ret = platform_device_add(pdev);
+ if (ret) {
+ platform_device_put(pdev);
goto err_register;
}
}
diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c
index 63eb16b..883a314 100644
--- a/drivers/gpu/ipu-v3/ipu-cpmem.c
+++ b/drivers/gpu/ipu-v3/ipu-cpmem.c
@@ -161,7 +161,7 @@ static u32 ipu_ch_param_read_field(struct ipuv3_channel *ch, u32 wbs)
* The DRM pixel formats and IPU internal representation are ordered the other
* way around, with the first named component ordered at the most significant
* bits. Further, V4L2 formats are not well defined:
- * http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
+ * https://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html
* We choose the interpretation which matches GStreamer behavior.
*/
static int v4l2_pix_fmt_to_drm_fourcc(u32 pixelformat)
diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c
index 3166e4b..f17cb04 100644
--- a/drivers/gpu/vga/vgaarb.c
+++ b/drivers/gpu/vga/vgaarb.c
@@ -395,8 +395,10 @@ int vga_get(struct pci_dev *pdev, unsigned int rsrc, int interruptible)
set_current_state(interruptible ?
TASK_INTERRUPTIBLE :
TASK_UNINTERRUPTIBLE);
- if (signal_pending(current)) {
- rc = -EINTR;
+ if (interruptible && signal_pending(current)) {
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&vga_wait_queue, &wait);
+ rc = -ERESTARTSYS;
break;
}
schedule();
@@ -1161,12 +1163,8 @@ done:
static unsigned int vga_arb_fpoll(struct file *file, poll_table *wait)
{
- struct vga_arb_private *priv = file->private_data;
-
pr_debug("%s\n", __func__);
- if (priv == NULL)
- return -ENODEV;
poll_wait(file, &vga_wait_queue, wait);
return POLLIN;
}
@@ -1207,9 +1205,6 @@ static int vga_arb_release(struct inode *inode, struct file *file)
pr_debug("%s\n", __func__);
- if (priv == NULL)
- return -ENODEV;
-
spin_lock_irqsave(&vga_user_lock, flags);
list_del(&priv->list);
for (i = 0; i < MAX_USER_CARDS; i++) {
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index ac1feea..8b78a7f 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -316,11 +316,6 @@
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
#define USB_VENDOR_ID_ELAN 0x04f3
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN 0x0089
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B 0x009b
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103 0x0103
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c 0x010c
-#define USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F 0x016f
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -609,6 +604,7 @@
#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f
#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
+#define USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS 0xc24d
#define USB_DEVICE_ID_LOGITECH_MOUSE_C01A 0xc01a
#define USB_DEVICE_ID_LOGITECH_MOUSE_C05A 0xc05a
#define USB_DEVICE_ID_LOGITECH_MOUSE_C06A 0xc06a
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index c20ac76..c690fae 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -665,8 +665,9 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct lg_drv_data *drv_data;
int ret;
- /* Only work with the 1st interface (G29 presents multiple) */
- if (iface_num != 0) {
+ /* G29 only work with the 1st interface */
+ if ((hdev->product == USB_DEVICE_ID_LOGITECH_G29_WHEEL) &&
+ (iface_num != 0)) {
dbg_hid("%s: ignoring ifnum %d\n", __func__, iface_num);
return -ENODEV;
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 94bb137..7dd0953 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -72,11 +72,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL },
- { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL },
- { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_0103, HID_QUIRK_ALWAYS_POLL },
- { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_010c, HID_QUIRK_ALWAYS_POLL },
- { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_016F, HID_QUIRK_ALWAYS_POLL },
+ { USB_VENDOR_ID_ELAN, HID_ANY_ID, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
@@ -84,6 +80,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
+ { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C01A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL },
@@ -339,7 +336,8 @@ static const struct hid_blacklist *usbhid_exists_squirk(const u16 idVendor,
for (; hid_blacklist[n].idVendor; n++)
if (hid_blacklist[n].idVendor == idVendor &&
- hid_blacklist[n].idProduct == idProduct)
+ (hid_blacklist[n].idProduct == (__u16) HID_ANY_ID ||
+ hid_blacklist[n].idProduct == idProduct))
bl_entry = &hid_blacklist[n];
if (bl_entry != NULL)
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 8b29949..01a4f05 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -2481,7 +2481,7 @@ void wacom_setup_device_quirks(struct wacom *wacom)
if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
if (features->touch_max)
features->device_type |= WACOM_DEVICETYPE_TOUCH;
- if (features->type >= INTUOSHT || features->type <= BAMBOO_PT)
+ if (features->type >= INTUOSHT && features->type <= BAMBOO_PT)
features->device_type |= WACOM_DEVICETYPE_PAD;
features->x_max = 4096;
@@ -3213,7 +3213,8 @@ static const struct wacom_features wacom_features_0x32F =
WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
static const struct wacom_features wacom_features_0x336 =
{ "Wacom DTU1141", 23472, 13203, 1023, 0,
- DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 };
+ DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4,
+ WACOM_DTU_OFFSET, WACOM_DTU_OFFSET };
static const struct wacom_features wacom_features_0x57 =
{ "Wacom DTK2241", 95640, 54060, 2047, 63,
DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6,
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index 3782636..678663e 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -63,10 +63,6 @@ enum hv_cpuid_function {
/* Define version of the synthetic interrupt controller. */
#define HV_SYNIC_VERSION (1)
-/* Define synthetic interrupt controller message constants. */
-#define HV_MESSAGE_SIZE (256)
-#define HV_MESSAGE_PAYLOAD_BYTE_COUNT (240)
-#define HV_MESSAGE_PAYLOAD_QWORD_COUNT (30)
#define HV_ANY_VP (0xFFFFFFFF)
/* Define synthetic interrupt controller flag constants. */
@@ -74,48 +70,9 @@ enum hv_cpuid_function {
#define HV_EVENT_FLAGS_BYTE_COUNT (256)
#define HV_EVENT_FLAGS_DWORD_COUNT (256 / sizeof(u32))
-/* Define hypervisor message types. */
-enum hv_message_type {
- HVMSG_NONE = 0x00000000,
-
- /* Memory access messages. */
- HVMSG_UNMAPPED_GPA = 0x80000000,
- HVMSG_GPA_INTERCEPT = 0x80000001,
-
- /* Timer notification messages. */
- HVMSG_TIMER_EXPIRED = 0x80000010,
-
- /* Error messages. */
- HVMSG_INVALID_VP_REGISTER_VALUE = 0x80000020,
- HVMSG_UNRECOVERABLE_EXCEPTION = 0x80000021,
- HVMSG_UNSUPPORTED_FEATURE = 0x80000022,
-
- /* Trace buffer complete messages. */
- HVMSG_EVENTLOG_BUFFERCOMPLETE = 0x80000040,
-
- /* Platform-specific processor intercept messages. */
- HVMSG_X64_IOPORT_INTERCEPT = 0x80010000,
- HVMSG_X64_MSR_INTERCEPT = 0x80010001,
- HVMSG_X64_CPUID_INTERCEPT = 0x80010002,
- HVMSG_X64_EXCEPTION_INTERCEPT = 0x80010003,
- HVMSG_X64_APIC_EOI = 0x80010004,
- HVMSG_X64_LEGACY_FP_ERROR = 0x80010005
-};
-
-#define HV_SYNIC_STIMER_COUNT (4)
-
/* Define invalid partition identifier. */
#define HV_PARTITION_ID_INVALID ((u64)0x0)
-/* Define port identifier type. */
-union hv_port_id {
- u32 asu32;
- struct {
- u32 id:24;
- u32 reserved:8;
- } u ;
-};
-
/* Define port type. */
enum hv_port_type {
HVPORT_MSG = 1,
@@ -163,27 +120,6 @@ struct hv_connection_info {
};
};
-/* Define synthetic interrupt controller message flags. */
-union hv_message_flags {
- u8 asu8;
- struct {
- u8 msg_pending:1;
- u8 reserved:7;
- };
-};
-
-/* Define synthetic interrupt controller message header. */
-struct hv_message_header {
- enum hv_message_type message_type;
- u8 payload_size;
- union hv_message_flags message_flags;
- u8 reserved[2];
- union {
- u64 sender;
- union hv_port_id port;
- };
-};
-
/*
* Timer configuration register.
*/
@@ -200,31 +136,9 @@ union hv_timer_config {
};
};
-
-/* Define timer message payload structure. */
-struct hv_timer_message_payload {
- u32 timer_index;
- u32 reserved;
- u64 expiration_time; /* When the timer expired */
- u64 delivery_time; /* When the message was delivered */
-};
-
-/* Define synthetic interrupt controller message format. */
-struct hv_message {
- struct hv_message_header header;
- union {
- u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
- } u ;
-};
-
/* Define the number of message buffers associated with each port. */
#define HV_PORT_MESSAGE_BUFFER_COUNT (16)
-/* Define the synthetic interrupt message page layout. */
-struct hv_message_page {
- struct hv_message sint_message[HV_SYNIC_SINT_COUNT];
-};
-
/* Define the synthetic interrupt controller event flags format. */
union hv_synic_event_flags {
u8 flags8[HV_EVENT_FLAGS_BYTE_COUNT];
@@ -347,7 +261,7 @@ enum hv_call_code {
struct hv_input_post_message {
union hv_connection_id connectionid;
u32 reserved;
- enum hv_message_type message_type;
+ u32 message_type;
u32 payload_size;
u64 payload[HV_MESSAGE_PAYLOAD_QWORD_COUNT];
};
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 796569ee..60fb80b 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -321,6 +321,15 @@ config SENSORS_APPLESMC
Say Y here if you have an applicable laptop and want to experience
the awesome power of applesmc.
+config SENSORS_ARM_SCPI
+ tristate "ARM SCPI Sensors"
+ depends on ARM_SCPI_PROTOCOL
+ depends on THERMAL || !THERMAL_OF
+ help
+ This driver provides support for temperature, voltage, current
+ and power sensors available on ARM Ltd's SCP based platforms. The
+ actual number and type of sensors exported depend on the platform.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on X86 && I2C
@@ -850,16 +859,6 @@ config SENSORS_MAX31790
This driver can also be built as a module. If so, the module
will be called max31790.
-config SENSORS_HTU21
- tristate "Measurement Specialties HTU21D humidity/temperature sensors"
- depends on I2C
- help
- If you say yes here you get support for the Measurement Specialties
- HTU21D humidity and temperature sensors.
-
- This driver can also be built as a module. If so, the module
- will be called htu21.
-
config SENSORS_MCP3021
tristate "Microchip MCP3021 and compatibles"
depends on I2C
@@ -1208,6 +1207,7 @@ config SENSORS_PWM_FAN
config SENSORS_SHT15
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
depends on GPIOLIB || COMPILE_TEST
+ select BITREVERSE
help
If you say yes here you get support for the Sensiron SHT10, SHT11,
SHT15, SHT71, SHT75 humidity and temperature sensors.
@@ -1463,6 +1463,7 @@ config SENSORS_INA209
config SENSORS_INA2XX
tristate "Texas Instruments INA219 and compatibles"
depends on I2C
+ select REGMAP_I2C
help
If you say yes here you get support for INA219, INA220, INA226,
INA230, and INA231 power monitor chips.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 01855ee..30c94df 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -44,6 +44,7 @@ obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o
obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o
obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
+obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o
obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o
obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
@@ -67,7 +68,6 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o
obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o
-obj-$(CONFIG_SENSORS_HTU21) += htu21.o
obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o
obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 1f5e956..0af7fd3 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -537,7 +537,7 @@ static int applesmc_init_index(struct applesmc_registers *s)
static int applesmc_init_smcreg_try(void)
{
struct applesmc_registers *s = &smcreg;
- bool left_light_sensor, right_light_sensor;
+ bool left_light_sensor = 0, right_light_sensor = 0;
unsigned int count;
u8 tmp[1];
int ret;
diff --git a/drivers/hwmon/fam15h_power.c b/drivers/hwmon/fam15h_power.c
index 5f7067d..f77eb97 100644
--- a/drivers/hwmon/fam15h_power.c
+++ b/drivers/hwmon/fam15h_power.c
@@ -47,6 +47,8 @@ MODULE_LICENSE("GPL");
#define MSR_F15H_CU_MAX_PWR_ACCUMULATOR 0xc001007b
+#define PCI_DEVICE_ID_AMD_15H_M70H_NB_F4 0x15b4
+
struct fam15h_power_data {
struct pci_dev *pdev;
unsigned int tdp_to_watts;
@@ -124,7 +126,7 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev,
if (c->x86 == 0x15 &&
(c->x86_model <= 0xf ||
- (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+ (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
n += 1;
fam15h_power_attrs = devm_kcalloc(&pdev->dev, n,
@@ -138,7 +140,7 @@ static int fam15h_power_init_attrs(struct pci_dev *pdev,
fam15h_power_attrs[n++] = &dev_attr_power1_crit.attr;
if (c->x86 == 0x15 &&
(c->x86_model <= 0xf ||
- (c->x86_model >= 0x60 && c->x86_model <= 0x6f)))
+ (c->x86_model >= 0x60 && c->x86_model <= 0x7f)))
fam15h_power_attrs[n++] = &dev_attr_power1_input.attr;
data->group.attrs = fam15h_power_attrs;
@@ -296,6 +298,7 @@ static const struct pci_device_id fam15h_power_id_table[] = {
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M70H_NB_F4) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{}
diff --git a/drivers/hwmon/htu21.c b/drivers/hwmon/htu21.c
deleted file mode 100644
index 4c3bbb7..0000000
--- a/drivers/hwmon/htu21.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Measurement Specialties HTU21D humidity and temperature sensor driver
- *
- * Copyright (C) 2013 William Markezana <william.markezana@meas-spec.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/err.h>
-#include <linux/mutex.h>
-#include <linux/device.h>
-#include <linux/jiffies.h>
-
-/* HTU21 Commands */
-#define HTU21_T_MEASUREMENT_HM 0xE3
-#define HTU21_RH_MEASUREMENT_HM 0xE5
-
-struct htu21 {
- struct i2c_client *client;
- struct mutex lock;
- bool valid;
- unsigned long last_update;
- int temperature;
- int humidity;
-};
-
-static inline int htu21_temp_ticks_to_millicelsius(int ticks)
-{
- ticks &= ~0x0003; /* clear status bits */
- /*
- * Formula T = -46.85 + 175.72 * ST / 2^16 from datasheet p14,
- * optimized for integer fixed point (3 digits) arithmetic
- */
- return ((21965 * ticks) >> 13) - 46850;
-}
-
-static inline int htu21_rh_ticks_to_per_cent_mille(int ticks)
-{
- ticks &= ~0x0003; /* clear status bits */
- /*
- * Formula RH = -6 + 125 * SRH / 2^16 from datasheet p14,
- * optimized for integer fixed point (3 digits) arithmetic
- */
- return ((15625 * ticks) >> 13) - 6000;
-}
-
-static int htu21_update_measurements(struct device *dev)
-{
- struct htu21 *htu21 = dev_get_drvdata(dev);
- struct i2c_client *client = htu21->client;
- int ret = 0;
-
- mutex_lock(&htu21->lock);
-
- if (time_after(jiffies, htu21->last_update + HZ / 2) ||
- !htu21->valid) {
- ret = i2c_smbus_read_word_swapped(client,
- HTU21_T_MEASUREMENT_HM);
- if (ret < 0)
- goto out;
- htu21->temperature = htu21_temp_ticks_to_millicelsius(ret);
- ret = i2c_smbus_read_word_swapped(client,
- HTU21_RH_MEASUREMENT_HM);
- if (ret < 0)
- goto out;
- htu21->humidity = htu21_rh_ticks_to_per_cent_mille(ret);
- htu21->last_update = jiffies;
- htu21->valid = true;
- }
-out:
- mutex_unlock(&htu21->lock);
-
- return ret >= 0 ? 0 : ret;
-}
-
-static ssize_t htu21_show_temperature(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct htu21 *htu21 = dev_get_drvdata(dev);
- int ret;
-
- ret = htu21_update_measurements(dev);
- if (ret < 0)
- return ret;
- return sprintf(buf, "%d\n", htu21->temperature);
-}
-
-static ssize_t htu21_show_humidity(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct htu21 *htu21 = dev_get_drvdata(dev);
- int ret;
-
- ret = htu21_update_measurements(dev);
- if (ret < 0)
- return ret;
- return sprintf(buf, "%d\n", htu21->humidity);
-}
-
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO,
- htu21_show_temperature, NULL, 0);
-static SENSOR_DEVICE_ATTR(humidity1_input, S_IRUGO,
- htu21_show_humidity, NULL, 0);
-
-static struct attribute *htu21_attrs[] = {
- &sensor_dev_attr_temp1_input.dev_attr.attr,
- &sensor_dev_attr_humidity1_input.dev_attr.attr,
- NULL
-};
-
-ATTRIBUTE_GROUPS(htu21);
-
-static int htu21_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct device *dev = &client->dev;
- struct htu21 *htu21;
- struct device *hwmon_dev;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_READ_WORD_DATA)) {
- dev_err(&client->dev,
- "adapter does not support SMBus word transactions\n");
- return -ENODEV;
- }
-
- htu21 = devm_kzalloc(dev, sizeof(*htu21), GFP_KERNEL);
- if (!htu21)
- return -ENOMEM;
-
- htu21->client = client;
- mutex_init(&htu21->lock);
-
- hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- htu21,
- htu21_groups);
- return PTR_ERR_OR_ZERO(hwmon_dev);
-}
-
-static const struct i2c_device_id htu21_id[] = {
- { "htu21", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, htu21_id);
-
-static struct i2c_driver htu21_driver = {
- .class = I2C_CLASS_HWMON,
- .driver = {
- .name = "htu21",
- },
- .probe = htu21_probe,
- .id_table = htu21_id,
-};
-
-module_i2c_driver(htu21_driver);
-
-MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>");
-MODULE_DESCRIPTION("MEAS HTU21D humidity and temperature sensor driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c
index 7a8a6fb..1f64378 100644
--- a/drivers/hwmon/ibmaem.c
+++ b/drivers/hwmon/ibmaem.c
@@ -920,8 +920,8 @@ static ssize_t aem_set_power_period(struct device *dev,
/* Discover sensors on an AEM device */
static int aem_register_sensors(struct aem_data *data,
- struct aem_ro_sensor_template *ro,
- struct aem_rw_sensor_template *rw)
+ const struct aem_ro_sensor_template *ro,
+ const struct aem_rw_sensor_template *rw)
{
struct device *dev = &data->pdev->dev;
struct sensor_device_attribute *sensors = data->sensors;
@@ -1020,19 +1020,19 @@ static void aem_remove_sensors(struct aem_data *data)
/* Sensor probe functions */
/* Description of AEM1 sensors */
-static struct aem_ro_sensor_template aem1_ro_sensors[] = {
+static const struct aem_ro_sensor_template aem1_ro_sensors[] = {
{"energy1_input", aem_show_energy, 0},
{"power1_average", aem_show_power, 0},
{NULL, NULL, 0},
};
-static struct aem_rw_sensor_template aem1_rw_sensors[] = {
+static const struct aem_rw_sensor_template aem1_rw_sensors[] = {
{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
{NULL, NULL, NULL, 0},
};
/* Description of AEM2 sensors */
-static struct aem_ro_sensor_template aem2_ro_sensors[] = {
+static const struct aem_ro_sensor_template aem2_ro_sensors[] = {
{"energy1_input", aem_show_energy, 0},
{"energy2_input", aem_show_energy, 1},
{"power1_average", aem_show_power, 0},
@@ -1050,7 +1050,7 @@ static struct aem_ro_sensor_template aem2_ro_sensors[] = {
{NULL, NULL, 0},
};
-static struct aem_rw_sensor_template aem2_rw_sensors[] = {
+static const struct aem_rw_sensor_template aem2_rw_sensors[] = {
{"power1_average_interval", aem_show_power_period, aem_set_power_period, 0},
{"power2_average_interval", aem_show_power_period, aem_set_power_period, 1},
{NULL, NULL, NULL, 0},
diff --git a/drivers/hwmon/nct6683.c b/drivers/hwmon/nct6683.c
index 37f0170..559c596 100644
--- a/drivers/hwmon/nct6683.c
+++ b/drivers/hwmon/nct6683.c
@@ -29,7 +29,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
-#include <linux/dmi.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -45,7 +45,7 @@ enum kinds { nct6683 };
static bool force;
module_param(force, bool, 0);
-MODULE_PARM_DESC(force, "Set to one to enable detection on non-Intel boards");
+MODULE_PARM_DESC(force, "Set to one to enable support for unknown vendors");
static const char * const nct6683_device_names[] = {
"nct6683",
@@ -141,6 +141,7 @@ superio_exit(int ioreg)
#define NCT6683_REG_MON(x) (0x100 + (x) * 2)
#define NCT6683_REG_FAN_RPM(x) (0x140 + (x) * 2)
#define NCT6683_REG_PWM(x) (0x160 + (x))
+#define NCT6683_REG_PWM_WRITE(x) (0xa28 + (x))
#define NCT6683_REG_MON_STS(x) (0x174 + (x))
#define NCT6683_REG_IDLE(x) (0x178 + (x))
@@ -165,8 +166,13 @@ superio_exit(int ioreg)
#define NCT6683_REG_FAN_MIN(x) (0x3b8 + (x) * 2) /* 16 bit */
+#define NCT6683_REG_FAN_CFG_CTRL 0xa01
+#define NCT6683_FAN_CFG_REQ 0x80
+#define NCT6683_FAN_CFG_DONE 0x40
+
#define NCT6683_REG_CUSTOMER_ID 0x602
#define NCT6683_CUSTOMER_ID_INTEL 0x805
+#define NCT6683_CUSTOMER_ID_MITAC 0xa0e
#define NCT6683_REG_BUILD_YEAR 0x604
#define NCT6683_REG_BUILD_MONTH 0x605
@@ -394,7 +400,8 @@ struct sensor_template_group {
};
static struct attribute_group *
-nct6683_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+nct6683_create_attr_group(struct device *dev,
+ const struct sensor_template_group *tg,
int repeat)
{
struct sensor_device_attribute_2 *a2;
@@ -559,6 +566,7 @@ static int get_temp_reg(struct nct6683_data *data, int nr, int index)
break;
}
break;
+ case NCT6683_CUSTOMER_ID_MITAC:
default:
switch (nr) {
default:
@@ -703,7 +711,7 @@ static struct sensor_device_template *nct6683_attributes_in_template[] = {
NULL
};
-static struct sensor_template_group nct6683_in_template_group = {
+static const struct sensor_template_group nct6683_in_template_group = {
.templates = nct6683_attributes_in_template,
.is_visible = nct6683_in_is_visible,
};
@@ -774,7 +782,7 @@ static struct sensor_device_template *nct6683_attributes_fan_template[] = {
NULL
};
-static struct sensor_template_group nct6683_fan_template_group = {
+static const struct sensor_template_group nct6683_fan_template_group = {
.templates = nct6683_attributes_fan_template,
.is_visible = nct6683_fan_is_visible,
.base = 1,
@@ -902,7 +910,7 @@ static struct sensor_device_template *nct6683_attributes_temp_template[] = {
NULL
};
-static struct sensor_template_group nct6683_temp_template_group = {
+static const struct sensor_template_group nct6683_temp_template_group = {
.templates = nct6683_attributes_temp_template,
.is_visible = nct6683_temp_is_visible,
.base = 1,
@@ -918,7 +926,29 @@ show_pwm(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%d\n", data->pwm[index]);
}
-SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, NULL, 0);
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct6683_data *data = dev_get_drvdata(dev);
+ int index = sattr->index;
+ unsigned long val;
+
+ if (kstrtoul(buf, 10, &val) || val > 255)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_REQ);
+ usleep_range(1000, 2000);
+ nct6683_write(data, NCT6683_REG_PWM_WRITE(index), val);
+ nct6683_write(data, NCT6683_REG_FAN_CFG_CTRL, NCT6683_FAN_CFG_DONE);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+SENSOR_TEMPLATE(pwm, "pwm%d", S_IRUGO, show_pwm, store_pwm, 0);
static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
struct attribute *attr, int index)
@@ -930,6 +960,10 @@ static umode_t nct6683_pwm_is_visible(struct kobject *kobj,
if (!(data->have_pwm & (1 << pwm)))
return 0;
+ /* Only update pwm values for Mitac boards */
+ if (data->customer_id == NCT6683_CUSTOMER_ID_MITAC)
+ return attr->mode | S_IWUSR;
+
return attr->mode;
}
@@ -938,7 +972,7 @@ static struct sensor_device_template *nct6683_attributes_pwm_template[] = {
NULL
};
-static struct sensor_template_group nct6683_pwm_template_group = {
+static const struct sensor_template_group nct6683_pwm_template_group = {
.templates = nct6683_attributes_pwm_template,
.is_visible = nct6683_pwm_is_visible,
.base = 1,
@@ -1170,6 +1204,7 @@ static int nct6683_probe(struct platform_device *pdev)
struct device *hwmon_dev;
struct resource *res;
int groups = 0;
+ char build[16];
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!devm_request_region(dev, res->start, IOREGION_LENGTH, DRVNAME))
@@ -1187,6 +1222,17 @@ static int nct6683_probe(struct platform_device *pdev)
data->customer_id = nct6683_read16(data, NCT6683_REG_CUSTOMER_ID);
+ /* By default only instantiate driver if the customer ID is known */
+ switch (data->customer_id) {
+ case NCT6683_CUSTOMER_ID_INTEL:
+ break;
+ case NCT6683_CUSTOMER_ID_MITAC:
+ break;
+ default:
+ if (!force)
+ return -ENODEV;
+ }
+
nct6683_init_device(data);
nct6683_setup_fans(data);
nct6683_setup_sensors(data);
@@ -1230,13 +1276,22 @@ static int nct6683_probe(struct platform_device *pdev)
}
data->groups[groups++] = &nct6683_group_other;
- dev_info(dev, "%s EC firmware version %d.%d build %02x/%02x/%02x\n",
+ if (data->customer_id == NCT6683_CUSTOMER_ID_INTEL)
+ scnprintf(build, sizeof(build), "%02x/%02x/%02x",
+ nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+ nct6683_read(data, NCT6683_REG_BUILD_DAY),
+ nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+ else
+ scnprintf(build, sizeof(build), "%02d/%02d/%02d",
+ nct6683_read(data, NCT6683_REG_BUILD_MONTH),
+ nct6683_read(data, NCT6683_REG_BUILD_DAY),
+ nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+
+ dev_info(dev, "%s EC firmware version %d.%d build %s\n",
nct6683_chip_names[data->kind],
nct6683_read(data, NCT6683_REG_VERSION_HI),
nct6683_read(data, NCT6683_REG_VERSION_LO),
- nct6683_read(data, NCT6683_REG_BUILD_MONTH),
- nct6683_read(data, NCT6683_REG_BUILD_DAY),
- nct6683_read(data, NCT6683_REG_BUILD_YEAR));
+ build);
hwmon_dev = devm_hwmon_device_register_with_groups(dev,
nct6683_device_names[data->kind], data, data->groups);
@@ -1292,20 +1347,10 @@ static struct platform_driver nct6683_driver = {
static int __init nct6683_find(int sioaddr, struct nct6683_sio_data *sio_data)
{
- const char *board_vendor;
int addr;
u16 val;
int err;
- /*
- * Only run on Intel boards unless the 'force' module parameter is set
- */
- if (!force) {
- board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR);
- if (!board_vendor || strcmp(board_vendor, "Intel Corporation"))
- return -ENODEV;
- }
-
err = superio_enter(sioaddr);
if (err)
return err;
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index d7ebdf8..d087a8e 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -1045,7 +1045,8 @@ struct sensor_template_group {
};
static struct attribute_group *
-nct6775_create_attr_group(struct device *dev, struct sensor_template_group *tg,
+nct6775_create_attr_group(struct device *dev,
+ const struct sensor_template_group *tg,
int repeat)
{
struct attribute_group *group;
@@ -1827,7 +1828,7 @@ static struct sensor_device_template *nct6775_attributes_in_template[] = {
NULL
};
-static struct sensor_template_group nct6775_in_template_group = {
+static const struct sensor_template_group nct6775_in_template_group = {
.templates = nct6775_attributes_in_template,
.is_visible = nct6775_in_is_visible,
};
@@ -2046,7 +2047,7 @@ static struct sensor_device_template *nct6775_attributes_fan_template[] = {
NULL
};
-static struct sensor_template_group nct6775_fan_template_group = {
+static const struct sensor_template_group nct6775_fan_template_group = {
.templates = nct6775_attributes_fan_template,
.is_visible = nct6775_fan_is_visible,
.base = 1,
@@ -2255,7 +2256,7 @@ static struct sensor_device_template *nct6775_attributes_temp_template[] = {
NULL
};
-static struct sensor_template_group nct6775_temp_template_group = {
+static const struct sensor_template_group nct6775_temp_template_group = {
.templates = nct6775_attributes_temp_template,
.is_visible = nct6775_temp_is_visible,
.base = 1,
@@ -3117,7 +3118,7 @@ static struct sensor_device_template *nct6775_attributes_pwm_template[] = {
NULL
};
-static struct sensor_template_group nct6775_pwm_template_group = {
+static const struct sensor_template_group nct6775_pwm_template_group = {
.templates = nct6775_attributes_pwm_template,
.is_visible = nct6775_pwm_is_visible,
.base = 1,
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index df6ebb2..7e5cc3d 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -65,6 +65,16 @@ config SENSORS_LTC2978_REGULATOR
If you say yes here you get regulator support for Linear
Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
+config SENSORS_LTC3815
+ tristate "Linear Technologies LTC3815"
+ default n
+ help
+ If you say yes here you get hardware monitoring support for Linear
+ Technology LTC3815.
+
+ This driver can also be built as a module. If so, the module will
+ be called ltc3815.
+
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile
index bce046d..5621320 100644
--- a/drivers/hwmon/pmbus/Makefile
+++ b/drivers/hwmon/pmbus/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o
obj-$(CONFIG_SENSORS_LM25066) += lm25066.o
obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o
+obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o
obj-$(CONFIG_SENSORS_MAX16064) += max16064.o
obj-$(CONFIG_SENSORS_MAX20751) += max20751.o
obj-$(CONFIG_SENSORS_MAX34440) += max34440.o
diff --git a/drivers/hwmon/pmbus/ltc3815.c b/drivers/hwmon/pmbus/ltc3815.c
new file mode 100644
index 0000000..bb32e62
--- /dev/null
+++ b/drivers/hwmon/pmbus/ltc3815.c
@@ -0,0 +1,215 @@
+/*
+ * Hardware monitoring driver for LTC3815
+ *
+ * Copyright (c) 2015 Linear Technology
+ * Copyright (c) 2015 Guenter Roeck
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include "pmbus.h"
+
+#define LTC3815_MFR_IOUT_PEAK 0xd7
+#define LTC3815_MFR_VOUT_PEAK 0xdd
+#define LTC3815_MFR_VIN_PEAK 0xde
+#define LTC3815_MFR_TEMP_PEAK 0xdf
+#define LTC3815_MFR_IIN_PEAK 0xe1
+#define LTC3815_MFR_SPECIAL_ID 0xe7
+
+#define LTC3815_ID 0x8000
+#define LTC3815_ID_MASK 0xff00
+
+static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VOUT_MODE:
+ /*
+ * The chip returns 0x3e, suggesting VID mode with manufacturer
+ * specific VID codes. Since the output voltage is reported
+ * with a LSB of 0.5mV, override and report direct mode with
+ * appropriate coefficients.
+ */
+ ret = 0x40;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_CLEAR_FAULTS:
+ /*
+ * LTC3815 does not support the CLEAR_FAULTS command.
+ * Emulate it by clearing the status register.
+ */
+ ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
+ if (ret > 0) {
+ pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
+ ret);
+ ret = 0;
+ }
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_READ_VIN_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
+ break;
+ case PMBUS_VIRT_READ_VOUT_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
+ break;
+ case PMBUS_VIRT_READ_TEMP_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
+ break;
+ case PMBUS_VIRT_READ_IOUT_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
+ break;
+ case PMBUS_VIRT_READ_IIN_MAX:
+ ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
+ break;
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ ret = 0;
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static int ltc3815_write_word_data(struct i2c_client *client, int page,
+ int reg, u16 word)
+{
+ int ret;
+
+ switch (reg) {
+ case PMBUS_VIRT_RESET_IIN_HISTORY:
+ ret = pmbus_write_word_data(client, page,
+ LTC3815_MFR_IIN_PEAK, 0);
+ break;
+ case PMBUS_VIRT_RESET_IOUT_HISTORY:
+ ret = pmbus_write_word_data(client, page,
+ LTC3815_MFR_IOUT_PEAK, 0);
+ break;
+ case PMBUS_VIRT_RESET_VOUT_HISTORY:
+ ret = pmbus_write_word_data(client, page,
+ LTC3815_MFR_VOUT_PEAK, 0);
+ break;
+ case PMBUS_VIRT_RESET_VIN_HISTORY:
+ ret = pmbus_write_word_data(client, page,
+ LTC3815_MFR_VIN_PEAK, 0);
+ break;
+ case PMBUS_VIRT_RESET_TEMP_HISTORY:
+ ret = pmbus_write_word_data(client, page,
+ LTC3815_MFR_TEMP_PEAK, 0);
+ break;
+ default:
+ ret = -ENODATA;
+ break;
+ }
+ return ret;
+}
+
+static const struct i2c_device_id ltc3815_id[] = {
+ {"ltc3815", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ltc3815_id);
+
+static struct pmbus_driver_info ltc3815_info = {
+ .pages = 1,
+ .format[PSC_VOLTAGE_IN] = direct,
+ .format[PSC_VOLTAGE_OUT] = direct,
+ .format[PSC_CURRENT_IN] = direct,
+ .format[PSC_CURRENT_OUT] = direct,
+ .format[PSC_TEMPERATURE] = direct,
+ .m[PSC_VOLTAGE_IN] = 250,
+ .b[PSC_VOLTAGE_IN] = 0,
+ .R[PSC_VOLTAGE_IN] = 0,
+ .m[PSC_VOLTAGE_OUT] = 2,
+ .b[PSC_VOLTAGE_OUT] = 0,
+ .R[PSC_VOLTAGE_OUT] = 3,
+ .m[PSC_CURRENT_IN] = 1,
+ .b[PSC_CURRENT_IN] = 0,
+ .R[PSC_CURRENT_IN] = 2,
+ .m[PSC_CURRENT_OUT] = 1,
+ .b[PSC_CURRENT_OUT] = 0,
+ .R[PSC_CURRENT_OUT] = 2,
+ .m[PSC_TEMPERATURE] = 1,
+ .b[PSC_TEMPERATURE] = 0,
+ .R[PSC_TEMPERATURE] = 0,
+ .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
+ PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
+ .read_byte_data = ltc3815_read_byte_data,
+ .read_word_data = ltc3815_read_word_data,
+ .write_byte = ltc3815_write_byte,
+ .write_word_data = ltc3815_write_word_data,
+};
+
+static int ltc3815_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int chip_id;
+
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_READ_WORD_DATA))
+ return -ENODEV;
+
+ chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
+ if (chip_id < 0)
+ return chip_id;
+ if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
+ return -ENODEV;
+
+ return pmbus_do_probe(client, id, &ltc3815_info);
+}
+
+static struct i2c_driver ltc3815_driver = {
+ .driver = {
+ .name = "ltc3815",
+ },
+ .probe = ltc3815_probe,
+ .remove = pmbus_do_remove,
+ .id_table = ltc3815_id,
+};
+
+module_i2c_driver(ltc3815_driver);
+
+MODULE_AUTHOR("Guenter Roeck");
+MODULE_DESCRIPTION("PMBus driver for LTC3815");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/scpi-hwmon.c b/drivers/hwmon/scpi-hwmon.c
new file mode 100644
index 0000000..7e20567
--- /dev/null
+++ b/drivers/hwmon/scpi-hwmon.c
@@ -0,0 +1,289 @@
+/*
+ * System Control and Power Interface(SCPI) based hwmon sensor driver
+ *
+ * Copyright (C) 2015 ARM Ltd.
+ * Punit Agrawal <punit.agrawal@arm.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/hwmon.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/scpi_protocol.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+
+struct sensor_data {
+ struct scpi_sensor_info info;
+ struct device_attribute dev_attr_input;
+ struct device_attribute dev_attr_label;
+ char input[20];
+ char label[20];
+};
+
+struct scpi_thermal_zone {
+ struct list_head list;
+ int sensor_id;
+ struct scpi_sensors *scpi_sensors;
+ struct thermal_zone_device *tzd;
+};
+
+struct scpi_sensors {
+ struct scpi_ops *scpi_ops;
+ struct sensor_data *data;
+ struct list_head thermal_zones;
+ struct attribute **attrs;
+ struct attribute_group group;
+ const struct attribute_group *groups[2];
+};
+
+static int scpi_read_temp(void *dev, int *temp)
+{
+ struct scpi_thermal_zone *zone = dev;
+ struct scpi_sensors *scpi_sensors = zone->scpi_sensors;
+ struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
+ struct sensor_data *sensor = &scpi_sensors->data[zone->sensor_id];
+ u32 value;
+ int ret;
+
+ ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
+ if (ret)
+ return ret;
+
+ *temp = value;
+ return 0;
+}
+
+/* hwmon callback functions */
+static ssize_t
+scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct scpi_sensors *scpi_sensors = dev_get_drvdata(dev);
+ struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
+ struct sensor_data *sensor;
+ u32 value;
+ int ret;
+
+ sensor = container_of(attr, struct sensor_data, dev_attr_input);
+
+ ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%u\n", value);
+}
+
+static ssize_t
+scpi_show_label(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_data *sensor;
+
+ sensor = container_of(attr, struct sensor_data, dev_attr_label);
+
+ return sprintf(buf, "%s\n", sensor->info.name);
+}
+
+static void
+unregister_thermal_zones(struct platform_device *pdev,
+ struct scpi_sensors *scpi_sensors)
+{
+ struct list_head *pos;
+
+ list_for_each(pos, &scpi_sensors->thermal_zones) {
+ struct scpi_thermal_zone *zone;
+
+ zone = list_entry(pos, struct scpi_thermal_zone, list);
+ thermal_zone_of_sensor_unregister(&pdev->dev, zone->tzd);
+ }
+}
+
+static struct thermal_zone_of_device_ops scpi_sensor_ops = {
+ .get_temp = scpi_read_temp,
+};
+
+static int scpi_hwmon_probe(struct platform_device *pdev)
+{
+ u16 nr_sensors, i;
+ int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0;
+ struct scpi_ops *scpi_ops;
+ struct device *hwdev, *dev = &pdev->dev;
+ struct scpi_sensors *scpi_sensors;
+ int ret, idx;
+
+ scpi_ops = get_scpi_ops();
+ if (!scpi_ops)
+ return -EPROBE_DEFER;
+
+ ret = scpi_ops->sensor_get_capability(&nr_sensors);
+ if (ret)
+ return ret;
+
+ if (!nr_sensors)
+ return -ENODEV;
+
+ scpi_sensors = devm_kzalloc(dev, sizeof(*scpi_sensors), GFP_KERNEL);
+ if (!scpi_sensors)
+ return -ENOMEM;
+
+ scpi_sensors->data = devm_kcalloc(dev, nr_sensors,
+ sizeof(*scpi_sensors->data), GFP_KERNEL);
+ if (!scpi_sensors->data)
+ return -ENOMEM;
+
+ scpi_sensors->attrs = devm_kcalloc(dev, (nr_sensors * 2) + 1,
+ sizeof(*scpi_sensors->attrs), GFP_KERNEL);
+ if (!scpi_sensors->attrs)
+ return -ENOMEM;
+
+ scpi_sensors->scpi_ops = scpi_ops;
+
+ for (i = 0, idx = 0; i < nr_sensors; i++) {
+ struct sensor_data *sensor = &scpi_sensors->data[idx];
+
+ ret = scpi_ops->sensor_get_info(i, &sensor->info);
+ if (ret)
+ return ret;
+
+ switch (sensor->info.class) {
+ case TEMPERATURE:
+ snprintf(sensor->input, sizeof(sensor->input),
+ "temp%d_input", num_temp + 1);
+ snprintf(sensor->label, sizeof(sensor->input),
+ "temp%d_label", num_temp + 1);
+ num_temp++;
+ break;
+ case VOLTAGE:
+ snprintf(sensor->input, sizeof(sensor->input),
+ "in%d_input", num_volt);
+ snprintf(sensor->label, sizeof(sensor->input),
+ "in%d_label", num_volt);
+ num_volt++;
+ break;
+ case CURRENT:
+ snprintf(sensor->input, sizeof(sensor->input),
+ "curr%d_input", num_current + 1);
+ snprintf(sensor->label, sizeof(sensor->input),
+ "curr%d_label", num_current + 1);
+ num_current++;
+ break;
+ case POWER:
+ snprintf(sensor->input, sizeof(sensor->input),
+ "power%d_input", num_power + 1);
+ snprintf(sensor->label, sizeof(sensor->input),
+ "power%d_label", num_power + 1);
+ num_power++;
+ break;
+ default:
+ continue;
+ }
+
+ sensor->dev_attr_input.attr.mode = S_IRUGO;
+ sensor->dev_attr_input.show = scpi_show_sensor;
+ sensor->dev_attr_input.attr.name = sensor->input;
+
+ sensor->dev_attr_label.attr.mode = S_IRUGO;
+ sensor->dev_attr_label.show = scpi_show_label;
+ sensor->dev_attr_label.attr.name = sensor->label;
+
+ scpi_sensors->attrs[idx << 1] = &sensor->dev_attr_input.attr;
+ scpi_sensors->attrs[(idx << 1) + 1] = &sensor->dev_attr_label.attr;
+
+ sysfs_attr_init(scpi_sensors->attrs[idx << 1]);
+ sysfs_attr_init(scpi_sensors->attrs[(idx << 1) + 1]);
+ idx++;
+ }
+
+ scpi_sensors->group.attrs = scpi_sensors->attrs;
+ scpi_sensors->groups[0] = &scpi_sensors->group;
+
+ platform_set_drvdata(pdev, scpi_sensors);
+
+ hwdev = devm_hwmon_device_register_with_groups(dev,
+ "scpi_sensors", scpi_sensors, scpi_sensors->groups);
+
+ if (IS_ERR(hwdev))
+ return PTR_ERR(hwdev);
+
+ /*
+ * Register the temperature sensors with the thermal framework
+ * to allow their usage in setting up the thermal zones from
+ * device tree.
+ *
+ * NOTE: Not all temperature sensors maybe used for thermal
+ * control
+ */
+ INIT_LIST_HEAD(&scpi_sensors->thermal_zones);
+ for (i = 0; i < nr_sensors; i++) {
+ struct sensor_data *sensor = &scpi_sensors->data[i];
+ struct scpi_thermal_zone *zone;
+
+ if (sensor->info.class != TEMPERATURE)
+ continue;
+
+ zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL);
+ if (!zone) {
+ ret = -ENOMEM;
+ goto unregister_tzd;
+ }
+
+ zone->sensor_id = i;
+ zone->scpi_sensors = scpi_sensors;
+ zone->tzd = thermal_zone_of_sensor_register(dev,
+ sensor->info.sensor_id, zone, &scpi_sensor_ops);
+ /*
+ * The call to thermal_zone_of_sensor_register returns
+ * an error for sensors that are not associated with
+ * any thermal zones or if the thermal subsystem is
+ * not configured.
+ */
+ if (IS_ERR(zone->tzd)) {
+ devm_kfree(dev, zone);
+ continue;
+ }
+ list_add(&zone->list, &scpi_sensors->thermal_zones);
+ }
+
+ return 0;
+
+unregister_tzd:
+ unregister_thermal_zones(pdev, scpi_sensors);
+ return ret;
+}
+
+static int scpi_hwmon_remove(struct platform_device *pdev)
+{
+ struct scpi_sensors *scpi_sensors = platform_get_drvdata(pdev);
+
+ unregister_thermal_zones(pdev, scpi_sensors);
+
+ return 0;
+}
+
+static const struct of_device_id scpi_of_match[] = {
+ {.compatible = "arm,scpi-sensors"},
+ {},
+};
+
+static struct platform_driver scpi_hwmon_platdrv = {
+ .driver = {
+ .name = "scpi-hwmon",
+ .owner = THIS_MODULE,
+ .of_match_table = scpi_of_match,
+ },
+ .probe = scpi_hwmon_probe,
+ .remove = scpi_hwmon_remove,
+};
+module_platform_driver(scpi_hwmon_platdrv);
+
+MODULE_AUTHOR("Punit Agrawal <punit.agrawal@arm.com>");
+MODULE_DESCRIPTION("ARM SCPI HWMON interface driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index 6548262..5289aa0 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -58,6 +58,7 @@ struct tmp102 {
u16 config_orig;
unsigned long last_update;
int temp[3];
+ bool first_time;
};
/* convert left adjusted 13-bit TMP102 register value to milliCelsius */
@@ -93,6 +94,7 @@ static struct tmp102 *tmp102_update_device(struct device *dev)
tmp102->temp[i] = tmp102_reg_to_mC(status);
}
tmp102->last_update = jiffies;
+ tmp102->first_time = false;
}
mutex_unlock(&tmp102->lock);
return tmp102;
@@ -102,6 +104,12 @@ static int tmp102_read_temp(void *dev, int *temp)
{
struct tmp102 *tmp102 = tmp102_update_device(dev);
+ /* Is it too early even to return a conversion? */
+ if (tmp102->first_time) {
+ dev_dbg(dev, "%s: Conversion not ready yet..\n", __func__);
+ return -EAGAIN;
+ }
+
*temp = tmp102->temp[0];
return 0;
@@ -114,6 +122,10 @@ static ssize_t tmp102_show_temp(struct device *dev,
struct sensor_device_attribute *sda = to_sensor_dev_attr(attr);
struct tmp102 *tmp102 = tmp102_update_device(dev);
+ /* Is it too early even to return a read? */
+ if (tmp102->first_time)
+ return -EAGAIN;
+
return sprintf(buf, "%d\n", tmp102->temp[sda->index]);
}
@@ -207,7 +219,9 @@ static int tmp102_probe(struct i2c_client *client,
status = -ENODEV;
goto fail_restore_config;
}
- tmp102->last_update = jiffies - HZ;
+ tmp102->last_update = jiffies;
+ /* Mark that we are not ready with data until conversion is complete */
+ tmp102->first_time = true;
mutex_init(&tmp102->lock);
hwmon_dev = hwmon_device_register_with_groups(dev, client->name,
diff --git a/drivers/hwtracing/stm/policy.c b/drivers/hwtracing/stm/policy.c
index 6498a9d..11ab6d0 100644
--- a/drivers/hwtracing/stm/policy.c
+++ b/drivers/hwtracing/stm/policy.c
@@ -76,9 +76,10 @@ to_stp_policy_node(struct config_item *item)
NULL;
}
-static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node,
- char *page)
+static ssize_t
+stp_policy_node_masters_show(struct config_item *item, char *page)
{
+ struct stp_policy_node *policy_node = to_stp_policy_node(item);
ssize_t count;
count = sprintf(page, "%u %u\n", policy_node->first_master,
@@ -88,9 +89,10 @@ static ssize_t stp_policy_node_masters_show(struct stp_policy_node *policy_node,
}
static ssize_t
-stp_policy_node_masters_store(struct stp_policy_node *policy_node,
- const char *page, size_t count)
+stp_policy_node_masters_store(struct config_item *item, const char *page,
+ size_t count)
{
+ struct stp_policy_node *policy_node = to_stp_policy_node(item);
unsigned int first, last;
struct stm_device *stm;
char *p = (char *)page;
@@ -123,8 +125,9 @@ unlock:
}
static ssize_t
-stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page)
+stp_policy_node_channels_show(struct config_item *item, char *page)
{
+ struct stp_policy_node *policy_node = to_stp_policy_node(item);
ssize_t count;
count = sprintf(page, "%u %u\n", policy_node->first_channel,
@@ -134,9 +137,10 @@ stp_policy_node_channels_show(struct stp_policy_node *policy_node, char *page)
}
static ssize_t
-stp_policy_node_channels_store(struct stp_policy_node *policy_node,
- const char *page, size_t count)
+stp_policy_node_channels_store(struct config_item *item, const char *page,
+ size_t count)
{
+ struct stp_policy_node *policy_node = to_stp_policy_node(item);
unsigned int first, last;
struct stm_device *stm;
char *p = (char *)page;
@@ -171,71 +175,16 @@ static void stp_policy_node_release(struct config_item *item)
kfree(to_stp_policy_node(item));
}
-struct stp_policy_node_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct stp_policy_node *, char *);
- ssize_t (*store)(struct stp_policy_node *, const char *, size_t);
-};
-
-static ssize_t stp_policy_node_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct stp_policy_node *policy_node = to_stp_policy_node(item);
- struct stp_policy_node_attribute *pn_attr =
- container_of(attr, struct stp_policy_node_attribute, attr);
- ssize_t count = 0;
-
- if (pn_attr->show)
- count = pn_attr->show(policy_node, page);
-
- return count;
-}
-
-static ssize_t stp_policy_node_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t len)
-{
- struct stp_policy_node *policy_node = to_stp_policy_node(item);
- struct stp_policy_node_attribute *pn_attr =
- container_of(attr, struct stp_policy_node_attribute, attr);
- ssize_t count = -EINVAL;
-
- if (pn_attr->store)
- count = pn_attr->store(policy_node, page, len);
-
- return count;
-}
-
static struct configfs_item_operations stp_policy_node_item_ops = {
.release = stp_policy_node_release,
- .show_attribute = stp_policy_node_attr_show,
- .store_attribute = stp_policy_node_attr_store,
};
-static struct stp_policy_node_attribute stp_policy_node_attr_range = {
- .attr = {
- .ca_owner = THIS_MODULE,
- .ca_name = "masters",
- .ca_mode = S_IRUGO | S_IWUSR,
- },
- .show = stp_policy_node_masters_show,
- .store = stp_policy_node_masters_store,
-};
-
-static struct stp_policy_node_attribute stp_policy_node_attr_channels = {
- .attr = {
- .ca_owner = THIS_MODULE,
- .ca_name = "channels",
- .ca_mode = S_IRUGO | S_IWUSR,
- },
- .show = stp_policy_node_channels_show,
- .store = stp_policy_node_channels_store,
-};
+CONFIGFS_ATTR(stp_policy_node_, masters);
+CONFIGFS_ATTR(stp_policy_node_, channels);
static struct configfs_attribute *stp_policy_node_attrs[] = {
- &stp_policy_node_attr_range.attr,
- &stp_policy_node_attr_channels.attr,
+ &stp_policy_node_attr_masters,
+ &stp_policy_node_attr_channels,
NULL,
};
@@ -298,20 +247,8 @@ static struct config_item_type stp_policy_node_type = {
/*
* Root group: policies.
*/
-static struct configfs_attribute stp_policy_attr_device = {
- .ca_owner = THIS_MODULE,
- .ca_name = "device",
- .ca_mode = S_IRUGO,
-};
-
-static struct configfs_attribute *stp_policy_attrs[] = {
- &stp_policy_attr_device,
- NULL,
-};
-
-static ssize_t stp_policy_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
+static ssize_t stp_policy_device_show(struct config_item *item,
+ char *page)
{
struct stp_policy *policy = to_stp_policy(item);
ssize_t count;
@@ -324,6 +261,13 @@ static ssize_t stp_policy_attr_show(struct config_item *item,
return count;
}
+CONFIGFS_ATTR_RO(stp_policy_, device);
+
+static struct configfs_attribute *stp_policy_attrs[] = {
+ &stp_policy_attr_device,
+ NULL,
+};
+
void stp_policy_unbind(struct stp_policy *policy)
{
struct stm_device *stm = policy->stm;
@@ -350,7 +294,6 @@ static void stp_policy_release(struct config_item *item)
static struct configfs_item_operations stp_policy_item_ops = {
.release = stp_policy_release,
- .show_attribute = stp_policy_attr_show,
};
static struct configfs_group_operations stp_policy_group_ops = {
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 08b8617..7b0aa82 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -124,6 +124,9 @@ config I2C_I801
BayTrail (SOC)
Sunrise Point-H (PCH)
Sunrise Point-LP (PCH)
+ DNV (SOC)
+ Broxton (SOC)
+ Lewisburg (PCH)
This driver can also be built as a module. If so, the module
will be called i2c-i801.
@@ -422,7 +425,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
config I2C_CADENCE
tristate "Cadence I2C Controller"
- depends on ARCH_ZYNQ
+ depends on ARCH_ZYNQ || ARM64
help
Say yes here to select Cadence I2C Host Controller. This controller is
e.g. used by Xilinx Zynq.
@@ -582,10 +585,10 @@ config I2C_IMG
config I2C_IMX
tristate "IMX I2C interface"
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_LAYERSCAPE
help
Say Y here if you want to use the IIC bus controller on
- the Freescale i.MX/MXC processors.
+ the Freescale i.MX/MXC or Layerscape processors.
This driver can also be built as a module. If so, the module
will be called i2c-imx.
@@ -902,6 +905,22 @@ config I2C_TEGRA
If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs
+config I2C_UNIPHIER
+ tristate "UniPhier FIFO-less I2C controller"
+ depends on ARCH_UNIPHIER
+ help
+ If you say yes to this option, support will be included for
+ the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8,
+ or older UniPhier SoCs.
+
+config I2C_UNIPHIER_F
+ tristate "UniPhier FIFO-builtin I2C controller"
+ depends on ARCH_UNIPHIER
+ help
+ If you say yes to this option, support will be included for
+ the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4,
+ PH1-Pro5, or newer UniPhier SoCs.
+
config I2C_VERSATILE
tristate "ARM Versatile/Realview I2C bus support"
depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 6df3b30..37f2819 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -87,6 +87,8 @@ obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
+obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
+obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
obj-$(CONFIG_I2C_WMT) += i2c-wmt.o
obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 1c758cd..10835d1 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -347,8 +347,14 @@ error:
static void at91_twi_read_next_byte(struct at91_twi_dev *dev)
{
- if (!dev->buf_len)
+ /*
+ * If we are in this case, it means there is garbage data in RHR, so
+ * delete them.
+ */
+ if (!dev->buf_len) {
+ at91_twi_read(dev, AT91_TWI_RHR);
return;
+ }
/* 8bit read works with and without FIFO */
*dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR);
@@ -465,19 +471,73 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
if (!irqstatus)
return IRQ_NONE;
- else if (irqstatus & AT91_TWI_RXRDY)
+ /*
+ * In reception, the behavior of the twi device (before sama5d2) is
+ * weird. There is some magic about RXRDY flag! When a data has been
+ * almost received, the reception of a new one is anticipated if there
+ * is no stop command to send. That is the reason why ask for sending
+ * the stop command not on the last data but on the second last one.
+ *
+ * Unfortunately, we could still have the RXRDY flag set even if the
+ * transfer is done and we have read the last data. It might happen
+ * when the i2c slave device sends too quickly data after receiving the
+ * ack from the master. The data has been almost received before having
+ * the order to send stop. In this case, sending the stop command could
+ * cause a RXRDY interrupt with a TXCOMP one. It is better to manage
+ * the RXRDY interrupt first in order to not keep garbage data in the
+ * Receive Holding Register for the next transfer.
+ */
+ if (irqstatus & AT91_TWI_RXRDY)
at91_twi_read_next_byte(dev);
- else if (irqstatus & AT91_TWI_TXRDY)
- at91_twi_write_next_byte(dev);
-
- /* catch error flags */
- dev->transfer_status |= status;
+ /*
+ * When a NACK condition is detected, the I2C controller sets the NACK,
+ * TXCOMP and TXRDY bits all together in the Status Register (SR).
+ *
+ * 1 - Handling NACK errors with CPU write transfer.
+ *
+ * In such case, we should not write the next byte into the Transmit
+ * Holding Register (THR) otherwise the I2C controller would start a new
+ * transfer and the I2C slave is likely to reply by another NACK.
+ *
+ * 2 - Handling NACK errors with DMA write transfer.
+ *
+ * By setting the TXRDY bit in the SR, the I2C controller also triggers
+ * the DMA controller to write the next data into the THR. Then the
+ * result depends on the hardware version of the I2C controller.
+ *
+ * 2a - Without support of the Alternative Command mode.
+ *
+ * This is the worst case: the DMA controller is triggered to write the
+ * next data into the THR, hence starting a new transfer: the I2C slave
+ * is likely to reply by another NACK.
+ * Concurrently, this interrupt handler is likely to be called to manage
+ * the first NACK before the I2C controller detects the second NACK and
+ * sets once again the NACK bit into the SR.
+ * When handling the first NACK, this interrupt handler disables the I2C
+ * controller interruptions, especially the NACK interrupt.
+ * Hence, the NACK bit is pending into the SR. This is why we should
+ * read the SR to clear all pending interrupts at the beginning of
+ * at91_do_twi_transfer() before actually starting a new transfer.
+ *
+ * 2b - With support of the Alternative Command mode.
+ *
+ * When a NACK condition is detected, the I2C controller also locks the
+ * THR (and sets the LOCK bit in the SR): even though the DMA controller
+ * is triggered by the TXRDY bit to write the next data into the THR,
+ * this data actually won't go on the I2C bus hence a second NACK is not
+ * generated.
+ */
if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) {
at91_disable_twi_interrupts(dev);
complete(&dev->cmd_complete);
+ } else if (irqstatus & AT91_TWI_TXRDY) {
+ at91_twi_write_next_byte(dev);
}
+ /* catch error flags */
+ dev->transfer_status |= status;
+
return IRQ_HANDLED;
}
@@ -537,6 +597,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
reinit_completion(&dev->cmd_complete);
dev->transfer_status = 0;
+ /* Clear pending interrupts, such as NACK. */
+ at91_twi_read(dev, AT91_TWI_SR);
+
if (dev->fifo_size) {
unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR);
@@ -558,11 +621,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
} 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) {
- dev_err(dev->dev, "RXRDY still set!");
- at91_twi_read(dev, AT91_TWI_RHR);
- }
-
/* if only one byte is to be read, immediately stop transfer */
if (!has_alt_cmd && dev->buf_len <= 1 &&
!(dev->msg->flags & I2C_M_RECV_LEN))
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index a6aae84..5bcb1f0 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -48,7 +48,6 @@ struct i2c_au1550_data {
void __iomem *psc_base;
int xfer_timeout;
struct i2c_adapter adap;
- struct resource *ioarea;
};
static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v)
@@ -284,10 +283,10 @@ static void i2c_au1550_setup(struct i2c_au1550_data *priv)
/* Set the protocol timer values. See Table 71 in the
* Au1550 Data Book for standard timing values.
*/
- WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \
- PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \
- PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \
- PSC_SMBTMR_SET_CH(15));
+ WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(20) | \
+ PSC_SMBTMR_SET_PU(20) | PSC_SMBTMR_SET_SH(20) | \
+ PSC_SMBTMR_SET_SU(20) | PSC_SMBTMR_SET_CL(20) | \
+ PSC_SMBTMR_SET_CH(20));
cfg |= PSC_SMBCFG_DE_ENABLE;
WR(priv, PSC_SMBCFG, cfg);
@@ -315,30 +314,16 @@ i2c_au1550_probe(struct platform_device *pdev)
struct resource *r;
int ret;
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- ret = -ENODEV;
- goto out;
- }
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- priv = kzalloc(sizeof(struct i2c_au1550_data), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto out;
- }
-
- priv->ioarea = request_mem_region(r->start, resource_size(r),
- pdev->name);
- if (!priv->ioarea) {
- ret = -EBUSY;
- goto out_mem;
- }
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->psc_base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->psc_base))
+ return PTR_ERR(priv->psc_base);
- priv->psc_base = ioremap(r->start, resource_size(r));
- if (!priv->psc_base) {
- ret = -EIO;
- goto out_map;
- }
priv->xfer_timeout = 200;
priv->adap.nr = pdev->id;
@@ -351,20 +336,13 @@ i2c_au1550_probe(struct platform_device *pdev)
i2c_au1550_setup(priv);
ret = i2c_add_numbered_adapter(&priv->adap);
- if (ret == 0) {
- platform_set_drvdata(pdev, priv);
- return 0;
+ if (ret) {
+ i2c_au1550_disable(priv);
+ return ret;
}
- i2c_au1550_disable(priv);
- iounmap(priv->psc_base);
-out_map:
- release_resource(priv->ioarea);
- kfree(priv->ioarea);
-out_mem:
- kfree(priv);
-out:
- return ret;
+ platform_set_drvdata(pdev, priv);
+ return 0;
}
static int i2c_au1550_remove(struct platform_device *pdev)
@@ -373,10 +351,6 @@ static int i2c_au1550_remove(struct platform_device *pdev)
i2c_del_adapter(&priv->adap);
i2c_au1550_disable(priv);
- iounmap(priv->psc_base);
- release_resource(priv->ioarea);
- kfree(priv->ioarea);
- kfree(priv);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 3fbb9a0..a8bdcb5 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -181,6 +181,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
u32 clkh;
u32 clkl;
u32 input_clock = clk_get_rate(dev->clk);
+ struct device_node *of_node = dev->dev->of_node;
/* NOTE: I2C Clock divider programming info
* As per I2C specs the following formulas provide prescaler
@@ -196,14 +197,27 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)
* where if PSC == 0, d = 7,
* if PSC == 1, d = 6
* if PSC > 1 , d = 5
+ *
+ * Note:
+ * d is always 6 on Keystone I2C controller
*/
- /* get minimum of 7 MHz clock, but max of 12 MHz */
- psc = (input_clock / 7000000) - 1;
+ /*
+ * Both Davinci and current Keystone User Guides recommend a value
+ * between 7MHz and 12MHz. In reality 7MHz module clock doesn't
+ * always produce enough margin between SDA and SCL transitions.
+ * Measurements show that the higher the module clock is, the
+ * bigger is the margin, providing more reliable communication.
+ * So we better target for 12MHz.
+ */
+ psc = (input_clock / 12000000) - 1;
if ((input_clock / (psc + 1)) > 12000000)
psc++; /* better to run under spec than over */
d = (psc >= 2) ? 5 : 7 - psc;
+ if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c"))
+ d = 6;
+
clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000));
/* Avoid driving the bus too fast because of rounding errors above */
if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000)
@@ -726,6 +740,7 @@ static struct i2c_algorithm i2c_davinci_algo = {
static const struct of_device_id davinci_i2c_of_match[] = {
{.compatible = "ti,davinci-i2c", },
+ {.compatible = "ti,keystone-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, davinci_i2c_of_match);
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 7441cdc..de7fbbb 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -165,7 +165,7 @@ static char *abort_sources[] = {
"lost arbitration",
};
-u32 dw_readl(struct dw_i2c_dev *dev, int offset)
+static u32 dw_readl(struct dw_i2c_dev *dev, int offset)
{
u32 value;
@@ -181,7 +181,7 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
return value;
}
-void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
+static void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
{
if (dev->accessor_flags & ACCESS_SWAP)
b = swab32(b);
@@ -438,7 +438,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev)
__i2c_dw_enable(dev, true);
/* Clear and enable interrupts */
- i2c_dw_clear_int(dev);
+ dw_readl(dev, DW_IC_CLR_INTR);
dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK);
}
@@ -618,7 +618,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
/*
* Prepare controller for a transaction and call i2c_dw_xfer_msg
*/
-int
+static int
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
@@ -702,14 +702,17 @@ done_nolock:
return ret;
}
-EXPORT_SYMBOL_GPL(i2c_dw_xfer);
-u32 i2c_dw_func(struct i2c_adapter *adap)
+static u32 i2c_dw_func(struct i2c_adapter *adap)
{
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
return dev->functionality;
}
-EXPORT_SYMBOL_GPL(i2c_dw_func);
+
+static struct i2c_algorithm i2c_dw_algo = {
+ .master_xfer = i2c_dw_xfer,
+ .functionality = i2c_dw_func,
+};
static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
{
@@ -770,7 +773,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev)
* Interrupt service routine. This gets called whenever an I2C interrupt
* occurs.
*/
-irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
+static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
{
struct dw_i2c_dev *dev = dev_id;
u32 stat, enabled;
@@ -810,23 +813,15 @@ irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
tx_aborted:
if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err)
complete(&dev->cmd_complete);
+ else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) {
+ /* workaround to trigger pending interrupt */
+ stat = dw_readl(dev, DW_IC_INTR_MASK);
+ i2c_dw_disable_int(dev);
+ dw_writel(dev, stat, DW_IC_INTR_MASK);
+ }
return IRQ_HANDLED;
}
-EXPORT_SYMBOL_GPL(i2c_dw_isr);
-
-void i2c_dw_enable(struct dw_i2c_dev *dev)
-{
- /* Enable the adapter */
- __i2c_dw_enable(dev, true);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_enable);
-
-u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev)
-{
- return dw_readl(dev, DW_IC_ENABLE);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_is_enabled);
void i2c_dw_disable(struct dw_i2c_dev *dev)
{
@@ -839,12 +834,6 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_disable);
-void i2c_dw_clear_int(struct dw_i2c_dev *dev)
-{
- dw_readl(dev, DW_IC_CLR_INTR);
-}
-EXPORT_SYMBOL_GPL(i2c_dw_clear_int);
-
void i2c_dw_disable_int(struct dw_i2c_dev *dev)
{
dw_writel(dev, 0, DW_IC_INTR_MASK);
@@ -857,5 +846,40 @@ u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev)
}
EXPORT_SYMBOL_GPL(i2c_dw_read_comp_param);
+int i2c_dw_probe(struct dw_i2c_dev *dev)
+{
+ struct i2c_adapter *adap = &dev->adapter;
+ int r;
+
+ init_completion(&dev->cmd_complete);
+ mutex_init(&dev->lock);
+
+ r = i2c_dw_init(dev);
+ if (r)
+ return r;
+
+ snprintf(adap->name, sizeof(adap->name),
+ "Synopsys DesignWare I2C adapter");
+ adap->algo = &i2c_dw_algo;
+ adap->dev.parent = dev->dev;
+ i2c_set_adapdata(adap, dev);
+
+ i2c_dw_disable_int(dev);
+ r = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
+ dev_name(dev->dev), dev);
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i: %d\n",
+ dev->irq, r);
+ return r;
+ }
+
+ r = i2c_add_numbered_adapter(adap);
+ if (r)
+ dev_err(dev->dev, "failure adding adapter: %d\n", r);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(i2c_dw_probe);
+
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 9630222..9ffb63a 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -111,20 +111,13 @@ struct dw_i2c_dev {
#define ACCESS_SWAP 0x00000001
#define ACCESS_16BIT 0x00000002
+#define ACCESS_INTR_MASK 0x00000004
-extern u32 dw_readl(struct dw_i2c_dev *dev, int offset);
-extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset);
extern int i2c_dw_init(struct dw_i2c_dev *dev);
-extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
- int num);
-extern u32 i2c_dw_func(struct i2c_adapter *adap);
-extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id);
-extern void i2c_dw_enable(struct dw_i2c_dev *dev);
-extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev);
extern void i2c_dw_disable(struct dw_i2c_dev *dev);
-extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+extern int i2c_dw_probe(struct dw_i2c_dev *dev);
#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index df23e8c..1543d35d 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -35,6 +35,7 @@
#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
#include "i2c-designware-core.h"
#define DRIVER_NAME "i2c-designware-pci"
@@ -158,11 +159,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
},
};
-static struct i2c_algorithm i2c_dw_algo = {
- .master_xfer = i2c_dw_xfer,
- .functionality = i2c_dw_func,
-};
-
#ifdef CONFIG_PM
static int i2c_dw_pci_suspend(struct device *dev)
{
@@ -222,13 +218,12 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
if (!dev)
return -ENOMEM;
- init_completion(&dev->cmd_complete);
- mutex_init(&dev->lock);
dev->clk = NULL;
dev->controller = controller;
dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
dev->base = pcim_iomap_table(pdev)[0];
dev->dev = &pdev->dev;
+ dev->irq = pdev->irq;
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
@@ -246,34 +241,16 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->tx_fifo_depth = controller->tx_fifo_depth;
dev->rx_fifo_depth = controller->rx_fifo_depth;
- r = i2c_dw_init(dev);
- if (r)
- return r;
adap = &dev->adapter;
- i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = 0;
- adap->algo = &i2c_dw_algo;
- adap->dev.parent = &pdev->dev;
+ ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->nr = controller->bus_num;
- snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
-
- r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr,
- IRQF_SHARED | IRQF_COND_SUSPEND, adap->name, dev);
- if (r) {
- dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
- return r;
- }
-
- i2c_dw_disable_int(dev);
- i2c_dw_clear_int(dev);
- r = i2c_add_numbered_adapter(adap);
- if (r) {
- dev_err(&pdev->dev, "failure adding adapter\n");
+ r = i2c_dw_probe(dev);
+ if (r)
return r;
- }
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
pm_runtime_use_autosuspend(&pdev->dev);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 472b882..6b00061c 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -42,10 +42,6 @@
#include <linux/platform_data/i2c-designware.h>
#include "i2c-designware-core.h"
-static struct i2c_algorithm i2c_dw_algo = {
- .master_xfer = i2c_dw_xfer,
- .functionality = i2c_dw_func,
-};
static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
{
return clk_get_rate(dev->clk)/1000;
@@ -111,29 +107,13 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev)
dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt,
&dev->sda_hold_time);
- /*
- * Provide a way for Designware I2C host controllers that are not
- * based on Intel LPSS to specify their input clock frequency via
- * id->driver_data.
- */
id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
if (id && id->driver_data)
- clk_register_fixed_rate(&pdev->dev, dev_name(&pdev->dev), NULL,
- CLK_IS_ROOT, id->driver_data);
+ dev->accessor_flags |= (u32)id->driver_data;
return 0;
}
-static void dw_i2c_acpi_unconfigure(struct platform_device *pdev)
-{
- struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
- const struct acpi_device_id *id;
-
- id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev);
- if (id && id->driver_data)
- clk_unregister(dev->clk);
-}
-
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "INT33C3", 0 },
@@ -141,7 +121,7 @@ static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT3433", 0 },
{ "80860F41", 0 },
{ "808622C1", 0 },
- { "AMD0010", 133 * 1000 * 1000 },
+ { "AMD0010", ACCESS_INTR_MASK },
{ }
};
MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match);
@@ -150,10 +130,9 @@ static inline int dw_i2c_acpi_configure(struct platform_device *pdev)
{
return -ENODEV;
}
-static inline void dw_i2c_acpi_unconfigure(struct platform_device *pdev) { }
#endif
-static int dw_i2c_probe(struct platform_device *pdev)
+static int dw_i2c_plat_probe(struct platform_device *pdev)
{
struct dw_i2c_dev *dev;
struct i2c_adapter *adap;
@@ -175,8 +154,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
if (IS_ERR(dev->base))
return PTR_ERR(dev->base);
- init_completion(&dev->cmd_complete);
- mutex_init(&dev->lock);
dev->dev = &pdev->dev;
dev->irq = irq;
platform_set_drvdata(pdev, dev);
@@ -251,26 +228,11 @@ static int dw_i2c_probe(struct platform_device *pdev)
dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1;
dev->adapter.nr = pdev->id;
}
- r = i2c_dw_init(dev);
- if (r)
- return r;
-
- i2c_dw_disable_int(dev);
- r = devm_request_irq(&pdev->dev, dev->irq, i2c_dw_isr, IRQF_SHARED,
- pdev->name, dev);
- if (r) {
- dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq);
- return r;
- }
adap = &dev->adapter;
- i2c_set_adapdata(adap, dev);
adap->owner = THIS_MODULE;
adap->class = I2C_CLASS_DEPRECATED;
- strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
- sizeof(adap->name));
- adap->algo = &i2c_dw_algo;
- adap->dev.parent = &pdev->dev;
+ ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
if (dev->pm_runtime_disabled) {
@@ -282,17 +244,14 @@ static int dw_i2c_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
}
- r = i2c_add_numbered_adapter(adap);
- if (r) {
- dev_err(&pdev->dev, "failure adding adapter\n");
+ r = i2c_dw_probe(dev);
+ if (r && !dev->pm_runtime_disabled)
pm_runtime_disable(&pdev->dev);
- return r;
- }
- return 0;
+ return r;
}
-static int dw_i2c_remove(struct platform_device *pdev)
+static int dw_i2c_plat_remove(struct platform_device *pdev)
{
struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
@@ -304,10 +263,8 @@ static int dw_i2c_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_put_sync(&pdev->dev);
- pm_runtime_disable(&pdev->dev);
-
- if (has_acpi_companion(&pdev->dev))
- dw_i2c_acpi_unconfigure(pdev);
+ if (!dev->pm_runtime_disabled)
+ pm_runtime_disable(&pdev->dev);
return 0;
}
@@ -321,23 +278,23 @@ MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
#ifdef CONFIG_PM_SLEEP
-static int dw_i2c_prepare(struct device *dev)
+static int dw_i2c_plat_prepare(struct device *dev)
{
return pm_runtime_suspended(dev);
}
-static void dw_i2c_complete(struct device *dev)
+static void dw_i2c_plat_complete(struct device *dev)
{
if (dev->power.direct_complete)
pm_request_resume(dev);
}
#else
-#define dw_i2c_prepare NULL
-#define dw_i2c_complete NULL
+#define dw_i2c_plat_prepare NULL
+#define dw_i2c_plat_complete NULL
#endif
#ifdef CONFIG_PM
-static int dw_i2c_suspend(struct device *dev)
+static int dw_i2c_plat_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -348,7 +305,7 @@ static int dw_i2c_suspend(struct device *dev)
return 0;
}
-static int dw_i2c_resume(struct device *dev)
+static int dw_i2c_plat_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
@@ -362,10 +319,10 @@ static int dw_i2c_resume(struct device *dev)
}
static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
- .prepare = dw_i2c_prepare,
- .complete = dw_i2c_complete,
- SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_suspend, dw_i2c_resume)
- SET_RUNTIME_PM_OPS(dw_i2c_suspend, dw_i2c_resume, NULL)
+ .prepare = dw_i2c_plat_prepare,
+ .complete = dw_i2c_plat_complete,
+ SET_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume)
+ SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume, NULL)
};
#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops)
@@ -377,8 +334,8 @@ static const struct dev_pm_ops dw_i2c_dev_pm_ops = {
MODULE_ALIAS("platform:i2c_designware");
static struct platform_driver dw_i2c_driver = {
- .probe = dw_i2c_probe,
- .remove = dw_i2c_remove,
+ .probe = dw_i2c_plat_probe,
+ .remove = dw_i2c_plat_remove,
.driver = {
.name = "i2c_designware",
.of_match_table = of_match_ptr(dw_i2c_of_match),
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index eaef9bc..f62d697 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -60,6 +60,10 @@
* BayTrail (SOC) 0x0f12 32 hard yes yes yes
* Sunrise Point-H (PCH) 0xa123 32 hard yes yes yes
* Sunrise Point-LP (PCH) 0x9d23 32 hard yes yes yes
+ * DNV (SOC) 0x19df 32 hard yes yes yes
+ * Broxton (SOC) 0x5ad4 32 hard yes yes yes
+ * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
+ * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
*
* Features supported by this driver:
* Software PEC no
@@ -202,6 +206,10 @@
#define PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS 0x9ca2
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123
#define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS 0x9d23
+#define PCI_DEVICE_ID_INTEL_DNV_SMBUS 0x19df
+#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3
+#define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223
struct i801_mux_config {
char *gpio_chip;
@@ -863,6 +871,10 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) },
{ 0, }
};
@@ -1251,11 +1263,15 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
priv->adapter.owner = THIS_MODULE;
priv->adapter.class = i801_get_adapter_class(priv);
priv->adapter.algo = &smbus_algorithm;
+ priv->adapter.dev.parent = &dev->dev;
+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev));
+ priv->adapter.retries = 3;
priv->pci_dev = dev;
switch (dev->device) {
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS:
case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS:
+ case PCI_DEVICE_ID_INTEL_DNV_SMBUS:
priv->features |= FEATURE_I2C_BLOCK_READ;
priv->features |= FEATURE_IRQ;
priv->features |= FEATURE_SMBUS_PEC;
@@ -1381,12 +1397,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
i801_add_tco(priv);
- /* set up the sysfs linkage to our parent device */
- priv->adapter.dev.parent = &dev->dev;
-
- /* Retry up to 3 times on lost arbitration */
- priv->adapter.retries = 3;
-
snprintf(priv->adapter.name, sizeof(priv->adapter.name),
"SMBus I801 adapter at %04lx", priv->smba);
err = i2c_add_adapter(&priv->adapter);
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 722f839..ab49230 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -798,6 +798,7 @@ static const struct of_device_id ibm_iic_match[] = {
{ .compatible = "ibm,iic", },
{}
};
+MODULE_DEVICE_TABLE(of, ibm_iic_match);
static struct platform_driver ibm_iic_driver = {
.driver = {
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 00ffd66..3795fe1 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -278,8 +278,6 @@
#define ISR_COMPLETE(err) (ISR_COMPLETE_M | (ISR_STATUS_M & (err)))
#define ISR_FATAL(err) (ISR_COMPLETE(err) | ISR_FATAL_M)
-#define REL_SOC_IP_SCB_2_2_1 0x00020201
-
enum img_i2c_mode {
MODE_INACTIVE,
MODE_RAW,
@@ -536,6 +534,7 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
u32 fifo_status;
u8 data;
+ img_i2c_wr_rd_fence(i2c);
fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
if (fifo_status & FIFO_READ_EMPTY)
break;
@@ -544,7 +543,6 @@ static void img_i2c_read_fifo(struct img_i2c *i2c)
*i2c->msg.buf = data;
img_i2c_writel(i2c, SCB_READ_FIFO_REG, 0xff);
- img_i2c_wr_rd_fence(i2c);
i2c->msg.len--;
i2c->msg.buf++;
}
@@ -556,12 +554,12 @@ static void img_i2c_write_fifo(struct img_i2c *i2c)
while (i2c->msg.len) {
u32 fifo_status;
+ img_i2c_wr_rd_fence(i2c);
fifo_status = img_i2c_readl(i2c, SCB_FIFO_STATUS_REG);
if (fifo_status & FIFO_WRITE_FULL)
break;
img_i2c_writel(i2c, SCB_WRITE_DATA_REG, *i2c->msg.buf);
- img_i2c_wr_rd_fence(i2c);
i2c->msg.len--;
i2c->msg.buf++;
}
@@ -859,7 +857,7 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c,
}
/* Enable transaction halt on start bit */
- if (!i2c->last_msg && i2c->line_status & LINESTAT_START_BIT_DET) {
+ if (!i2c->last_msg && line_status & LINESTAT_START_BIT_DET) {
img_i2c_transaction_halt(i2c, true);
/* we're no longer interested in the slave event */
i2c->int_enable &= ~INT_SLAVE_EVENT;
@@ -1062,6 +1060,15 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
i2c->last_msg = (i == num - 1);
reinit_completion(&i2c->msg_complete);
+ /*
+ * Clear line status and all interrupts before starting a
+ * transfer, as we may have unserviced interrupts from
+ * previous transfers that might be handled in the context
+ * of the new transfer.
+ */
+ img_i2c_writel(i2c, SCB_INT_CLEAR_REG, ~0);
+ img_i2c_writel(i2c, SCB_CLEAR_REG, ~0);
+
if (atomic)
img_i2c_atomic_start(i2c);
else if (msg->flags & I2C_M_RD)
@@ -1120,13 +1127,8 @@ static int img_i2c_init(struct img_i2c *i2c)
return -EINVAL;
}
- if (rev == REL_SOC_IP_SCB_2_2_1) {
- i2c->need_wr_rd_fence = true;
- dev_info(i2c->adap.dev.parent, "fence quirk enabled");
- }
-
- bitrate_khz = i2c->bitrate / 1000;
- clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
+ /* Fencing enabled by default. */
+ i2c->need_wr_rd_fence = true;
/* Determine what mode we're in from the bitrate */
timing = timings[0];
@@ -1136,6 +1138,17 @@ static int img_i2c_init(struct img_i2c *i2c)
break;
}
}
+ if (i2c->bitrate > timings[ARRAY_SIZE(timings) - 1].max_bitrate) {
+ dev_warn(i2c->adap.dev.parent,
+ "requested bitrate (%u) is higher than the max bitrate supported (%u)\n",
+ i2c->bitrate,
+ timings[ARRAY_SIZE(timings) - 1].max_bitrate);
+ timing = timings[ARRAY_SIZE(timings) - 1];
+ i2c->bitrate = timing.max_bitrate;
+ }
+
+ bitrate_khz = i2c->bitrate / 1000;
+ clk_khz = clk_get_rate(i2c->scb_clk) / 1000;
/* Find the prescale that would give us that inc (approx delay = 0) */
prescale = SCB_OPT_INC * clk_khz / (256 * 16 * bitrate_khz);
@@ -1182,32 +1195,32 @@ static int img_i2c_init(struct img_i2c *i2c)
((bitrate_khz * clk_period) / 2))
int_bitrate++;
- /* Setup TCKH value */
- tckh = timing.tckh / clk_period;
- if (timing.tckh % clk_period)
- tckh++;
+ /*
+ * Setup clock duty cycle, start with 50% and adjust TCKH and TCKL
+ * values from there if they don't meet minimum timing requirements
+ */
+ tckh = int_bitrate / 2;
+ tckl = int_bitrate - tckh;
- if (tckh > 0)
- data = tckh - 1;
- else
- data = 0;
+ /* Adjust TCKH and TCKL values */
+ data = DIV_ROUND_UP(timing.tckl, clk_period);
- img_i2c_writel(i2c, SCB_TIME_TCKH_REG, data);
+ if (tckl < data) {
+ tckl = data;
+ tckh = int_bitrate - tckl;
+ }
- /* Setup TCKL value */
- tckl = int_bitrate - tckh;
+ if (tckh > 0)
+ --tckh;
if (tckl > 0)
- data = tckl - 1;
- else
- data = 0;
+ --tckl;
- img_i2c_writel(i2c, SCB_TIME_TCKL_REG, data);
+ img_i2c_writel(i2c, SCB_TIME_TCKH_REG, tckh);
+ img_i2c_writel(i2c, SCB_TIME_TCKL_REG, tckl);
/* Setup TSDH value */
- tsdh = timing.tsdh / clk_period;
- if (timing.tsdh % clk_period)
- tsdh++;
+ tsdh = DIV_ROUND_UP(timing.tsdh, clk_period);
if (tsdh > 1)
data = tsdh - 1;
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 785aa67..d4d8536 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -49,6 +49,8 @@
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
+#include <linux/of_gpio.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_data/i2c-imx.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
@@ -207,6 +209,11 @@ struct imx_i2c_struct {
unsigned int cur_clk;
unsigned int bitrate;
const struct imx_i2c_hwdata *hwdata;
+ struct i2c_bus_recovery_info rinfo;
+
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pinctrl_pins_default;
+ struct pinctrl_state *pinctrl_pins_gpio;
struct imx_i2c_dma *dma;
};
@@ -461,7 +468,7 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx)
{
if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) {
dev_dbg(&i2c_imx->adapter.dev, "<%s> No ACK\n", __func__);
- return -EIO; /* No ACK */
+ return -ENXIO; /* No ACK */
}
dev_dbg(&i2c_imx->adapter.dev, "<%s> ACK received\n", __func__);
@@ -896,6 +903,13 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* Start I2C transfer */
result = i2c_imx_start(i2c_imx);
+ if (result) {
+ if (i2c_imx->adapter.bus_recovery_info) {
+ i2c_recover_bus(&i2c_imx->adapter);
+ result = i2c_imx_start(i2c_imx);
+ }
+ }
+
if (result)
goto fail0;
@@ -956,6 +970,55 @@ fail0:
return (result < 0) ? result : num;
}
+static void i2c_imx_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct imx_i2c_struct *i2c_imx;
+
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio);
+}
+
+static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct imx_i2c_struct *i2c_imx;
+
+ i2c_imx = container_of(adap, struct imx_i2c_struct, adapter);
+
+ pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default);
+}
+
+static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx,
+ struct platform_device *pdev)
+{
+ struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo;
+
+ i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl,
+ PINCTRL_STATE_DEFAULT);
+ i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl,
+ "gpio");
+ rinfo->sda_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+ "sda-gpios", 0, NULL);
+ rinfo->scl_gpio = of_get_named_gpio_flags(pdev->dev.of_node,
+ "scl-gpios", 0, NULL);
+
+ if (!gpio_is_valid(rinfo->sda_gpio) ||
+ !gpio_is_valid(rinfo->scl_gpio) ||
+ IS_ERR(i2c_imx->pinctrl_pins_default) ||
+ IS_ERR(i2c_imx->pinctrl_pins_gpio)) {
+ dev_dbg(&pdev->dev, "recovery information incomplete\n");
+ return;
+ }
+
+ dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n",
+ rinfo->sda_gpio, rinfo->scl_gpio);
+
+ rinfo->prepare_recovery = i2c_imx_prepare_recovery;
+ rinfo->unprepare_recovery = i2c_imx_unprepare_recovery;
+ rinfo->recover_bus = i2c_generic_gpio_recovery;
+ i2c_imx->adapter.bus_recovery_info = rinfo;
+}
+
static u32 i2c_imx_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -1023,6 +1086,13 @@ static int i2c_imx_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can't enable I2C clock\n");
return ret;
}
+
+ i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(i2c_imx->pinctrl)) {
+ ret = PTR_ERR(i2c_imx->pinctrl);
+ goto clk_disable;
+ }
+
/* Request IRQ */
ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0,
pdev->name, i2c_imx);
@@ -1049,6 +1119,8 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx, IMX_I2C_I2CR);
imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR);
+ i2c_imx_init_recovery_info(i2c_imx, pdev);
+
/* Add I2C adapter */
ret = i2c_add_numbered_adapter(&i2c_imx->adapter);
if (ret < 0) {
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index 39becbb..7ba795b 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -165,14 +165,13 @@ struct ismt_desc {
struct ismt_priv {
struct i2c_adapter adapter;
- void *smba; /* PCI BAR */
+ void __iomem *smba; /* PCI BAR */
struct pci_dev *pci_dev;
struct ismt_desc *hw; /* descriptor virt base addr */
dma_addr_t io_rng_dma; /* descriptor HW base addr */
u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */
u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* temp R/W data buffer */
- bool using_msi; /* type of interrupt flag */
};
/**
@@ -398,7 +397,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);
/* Initialize common control bits */
- if (likely(priv->using_msi))
+ if (likely(pci_dev_msi_enabled(priv->pci_dev)))
desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
else
desc->control = ISMT_DESC_FAIR;
@@ -789,11 +788,8 @@ static int ismt_int_init(struct ismt_priv *priv)
/* Try using MSI interrupts */
err = pci_enable_msi(priv->pci_dev);
- if (err) {
- dev_warn(&priv->pci_dev->dev,
- "Unable to use MSI interrupts, falling back to legacy\n");
+ if (err)
goto intx;
- }
err = devm_request_irq(&priv->pci_dev->dev,
priv->pci_dev->irq,
@@ -806,11 +802,13 @@ static int ismt_int_init(struct ismt_priv *priv)
goto intx;
}
- priv->using_msi = true;
- goto done;
+ return 0;
/* Try using legacy interrupts */
intx:
+ dev_warn(&priv->pci_dev->dev,
+ "Unable to use MSI interrupts, falling back to legacy\n");
+
err = devm_request_irq(&priv->pci_dev->dev,
priv->pci_dev->irq,
ismt_do_interrupt,
@@ -819,12 +817,9 @@ intx:
priv);
if (err) {
dev_err(&priv->pci_dev->dev, "no usable interrupts\n");
- return -ENODEV;
+ return err;
}
- priv->using_msi = false;
-
-done:
return 0;
}
@@ -847,17 +842,13 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
pci_set_drvdata(pdev, priv);
+
i2c_set_adapdata(&priv->adapter, priv);
priv->adapter.owner = THIS_MODULE;
-
priv->adapter.class = I2C_CLASS_HWMON;
-
priv->adapter.algo = &smbus_algorithm;
-
- /* set up the sysfs linkage to our parent device */
priv->adapter.dev.parent = &pdev->dev;
-
- /* number of retries on lost arbitration */
+ ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
priv->adapter.retries = ISMT_MAX_RETRIES;
priv->pci_dev = pdev;
@@ -904,8 +895,7 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
priv->smba = pcim_iomap(pdev, SMBBAR, len);
if (!priv->smba) {
dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n");
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) ||
@@ -915,32 +905,26 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
DMA_BIT_MASK(32)) != 0)) {
dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n",
pdev);
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
}
err = ismt_dev_init(priv);
if (err)
- goto fail;
+ return err;
ismt_hw_init(priv);
err = ismt_int_init(priv);
if (err)
- goto fail;
+ return err;
err = i2c_add_adapter(&priv->adapter);
if (err) {
dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n");
- err = -ENODEV;
- goto fail;
+ return -ENODEV;
}
return 0;
-
-fail:
- pci_release_region(pdev, SMBBAR);
- return err;
}
/**
@@ -952,47 +936,13 @@ static void ismt_remove(struct pci_dev *pdev)
struct ismt_priv *priv = pci_get_drvdata(pdev);
i2c_del_adapter(&priv->adapter);
- pci_release_region(pdev, SMBBAR);
}
-/**
- * ismt_suspend() - place the device in suspend
- * @pdev: PCI-Express device
- * @mesg: PM message
- */
-#ifdef CONFIG_PM
-static int ismt_suspend(struct pci_dev *pdev, pm_message_t mesg)
-{
- pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, mesg));
- return 0;
-}
-
-/**
- * ismt_resume() - PCI resume code
- * @pdev: PCI-Express device
- */
-static int ismt_resume(struct pci_dev *pdev)
-{
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
- return pci_enable_device(pdev);
-}
-
-#else
-
-#define ismt_suspend NULL
-#define ismt_resume NULL
-
-#endif
-
static struct pci_driver ismt_driver = {
.name = "ismt_smbus",
.id_table = ismt_ids,
.probe = ismt_probe,
.remove = ismt_remove,
- .suspend = ismt_suspend,
- .resume = ismt_resume,
};
module_pci_driver(ismt_driver);
diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c
index 5e176adc..71d3929 100644
--- a/drivers/i2c/busses/i2c-meson.c
+++ b/drivers/i2c/busses/i2c-meson.c
@@ -475,6 +475,7 @@ static const struct of_device_id meson_i2c_match[] = {
{ .compatible = "amlogic,meson6-i2c" },
{ },
};
+MODULE_DEVICE_TABLE(of, meson_i2c_match);
static struct platform_driver meson_i2c_driver = {
.probe = meson_i2c_probe,
diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c
index c02e6c0..9b86716 100644
--- a/drivers/i2c/busses/i2c-mt65xx.c
+++ b/drivers/i2c/busses/i2c-mt65xx.c
@@ -728,11 +728,27 @@ static int mtk_i2c_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int mtk_i2c_resume(struct device *dev)
+{
+ struct mtk_i2c *i2c = dev_get_drvdata(dev);
+
+ mtk_i2c_init_hw(i2c);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops mtk_i2c_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, mtk_i2c_resume)
+};
+
static struct platform_driver mtk_i2c_driver = {
.probe = mtk_i2c_probe,
.remove = mtk_i2c_remove,
.driver = {
.name = I2C_DRV_NAME,
+ .pm = &mtk_i2c_pm,
.of_match_table = of_match_ptr(mtk_i2c_of_match),
},
};
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index 5801227..43207f5 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -146,6 +146,8 @@ struct mv64xxx_i2c_data {
bool errata_delay;
struct reset_control *rstc;
bool irq_clear_inverted;
+ /* Clk div is 2 to the power n, not 2 to the power n + 1 */
+ bool clk_n_base_0;
};
static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -757,25 +759,29 @@ MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table);
#ifdef CONFIG_OF
#ifdef CONFIG_HAVE_CLK
static int
-mv64xxx_calc_freq(const int tclk, const int n, const int m)
+mv64xxx_calc_freq(struct mv64xxx_i2c_data *drv_data,
+ const int tclk, const int n, const int m)
{
- return tclk / (10 * (m + 1) * (2 << n));
+ if (drv_data->clk_n_base_0)
+ return tclk / (10 * (m + 1) * (1 << n));
+ else
+ return tclk / (10 * (m + 1) * (2 << n));
}
static bool
-mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n,
- u32 *best_m)
+mv64xxx_find_baud_factors(struct mv64xxx_i2c_data *drv_data,
+ const u32 req_freq, const u32 tclk)
{
int freq, delta, best_delta = INT_MAX;
int m, n;
for (n = 0; n <= 7; n++)
for (m = 0; m <= 15; m++) {
- freq = mv64xxx_calc_freq(tclk, n, m);
+ freq = mv64xxx_calc_freq(drv_data, tclk, n, m);
delta = req_freq - freq;
if (delta >= 0 && delta < best_delta) {
- *best_m = m;
- *best_n = n;
+ drv_data->freq_m = m;
+ drv_data->freq_n = n;
best_delta = delta;
}
if (best_delta == 0)
@@ -813,8 +819,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
if (of_property_read_u32(np, "clock-frequency", &bus_freq))
bus_freq = 100000; /* 100kHz by default */
- if (!mv64xxx_find_baud_factors(bus_freq, tclk,
- &drv_data->freq_n, &drv_data->freq_m)) {
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-i2c") ||
+ of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+ drv_data->clk_n_base_0 = true;
+
+ if (!mv64xxx_find_baud_factors(drv_data, bus_freq, tclk)) {
rc = -EINVAL;
goto out;
}
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index abf5db7..11b7b87 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -92,6 +92,16 @@ static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value)
iowrite32(value, i2c->base + (reg << i2c->reg_shift));
}
+static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite16be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
+static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value)
+{
+ iowrite32be(value, i2c->base + (reg << i2c->reg_shift));
+}
+
static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg)
{
return ioread8(i2c->base + (reg << i2c->reg_shift));
@@ -107,6 +117,16 @@ static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg)
return ioread32(i2c->base + (reg << i2c->reg_shift));
}
+static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg)
+{
+ return ioread16be(i2c->base + (reg << i2c->reg_shift));
+}
+
+static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg)
+{
+ return ioread32be(i2c->base + (reg << i2c->reg_shift));
+}
+
static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value)
{
i2c->setreg(i2c, reg, value);
@@ -428,6 +448,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
i2c->reg_io_width = 1; /* Set to default value */
if (!i2c->setreg || !i2c->getreg) {
+ bool be = pdata ? pdata->big_endian :
+ of_device_is_big_endian(pdev->dev.of_node);
+
switch (i2c->reg_io_width) {
case 1:
i2c->setreg = oc_setreg_8;
@@ -435,13 +458,13 @@ static int ocores_i2c_probe(struct platform_device *pdev)
break;
case 2:
- i2c->setreg = oc_setreg_16;
- i2c->getreg = oc_getreg_16;
+ i2c->setreg = be ? oc_setreg_16be : oc_setreg_16;
+ i2c->getreg = be ? oc_getreg_16be : oc_getreg_16;
break;
case 4:
- i2c->setreg = oc_setreg_32;
- i2c->getreg = oc_getreg_32;
+ i2c->setreg = be ? oc_setreg_32be : oc_setreg_32;
+ i2c->getreg = be ? oc_getreg_32be : oc_getreg_32;
break;
default:
diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c
index 6f8b446..7ea67aa 100644
--- a/drivers/i2c/busses/i2c-pnx.c
+++ b/drivers/i2c/busses/i2c-pnx.c
@@ -496,7 +496,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_msg *pmsg;
int rc = 0, completed = 0, i;
struct i2c_pnx_algo_data *alg_data = adap->algo_data;
- u32 stat = ioread32(I2C_REG_STS(alg_data));
+ u32 stat;
dev_dbg(&alg_data->adapter.dev,
"%s(): entering: %d messages, stat = %04x.\n",
@@ -659,9 +659,8 @@ static int i2c_pnx_probe(struct platform_device *pdev)
if (IS_ERR(alg_data->clk))
return PTR_ERR(alg_data->clk);
- init_timer(&alg_data->mif.timer);
- alg_data->mif.timer.function = i2c_pnx_timeout;
- alg_data->mif.timer.data = (unsigned long)alg_data;
+ setup_timer(&alg_data->mif.timer, i2c_pnx_timeout,
+ (unsigned long)alg_data);
snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name),
"%s", pdev->name);
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index 645e4b7..0d35195 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -46,12 +46,15 @@ struct pxa_reg_layout {
u32 icr;
u32 isr;
u32 isar;
+ u32 ilcr;
+ u32 iwcr;
};
enum pxa_i2c_types {
REGS_PXA2XX,
REGS_PXA3XX,
REGS_CE4100,
+ REGS_PXA910,
};
/*
@@ -79,12 +82,22 @@ static struct pxa_reg_layout pxa_reg_layout[] = {
.isr = 0x04,
/* no isar register */
},
+ [REGS_PXA910] = {
+ .ibmr = 0x00,
+ .idbr = 0x08,
+ .icr = 0x10,
+ .isr = 0x18,
+ .isar = 0x20,
+ .ilcr = 0x28,
+ .iwcr = 0x30,
+ },
};
static const struct platform_device_id i2c_pxa_id_table[] = {
{ "pxa2xx-i2c", REGS_PXA2XX },
{ "pxa3xx-pwri2c", REGS_PXA3XX },
{ "ce4100-i2c", REGS_CE4100 },
+ { "pxa910-i2c", REGS_PXA910 },
{ },
};
MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
@@ -124,6 +137,23 @@ MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table);
#define ISR_SAD (1 << 9) /* slave address detected */
#define ISR_BED (1 << 10) /* bus error no ACK/NAK */
+/* bit field shift & mask */
+#define ILCR_SLV_SHIFT 0
+#define ILCR_SLV_MASK (0x1FF << ILCR_SLV_SHIFT)
+#define ILCR_FLV_SHIFT 9
+#define ILCR_FLV_MASK (0x1FF << ILCR_FLV_SHIFT)
+#define ILCR_HLVL_SHIFT 18
+#define ILCR_HLVL_MASK (0x1FF << ILCR_HLVL_SHIFT)
+#define ILCR_HLVH_SHIFT 27
+#define ILCR_HLVH_MASK (0x1F << ILCR_HLVH_SHIFT)
+
+#define IWCR_CNT_SHIFT 0
+#define IWCR_CNT_MASK (0x1F << IWCR_CNT_SHIFT)
+#define IWCR_HS_CNT1_SHIFT 5
+#define IWCR_HS_CNT1_MASK (0x1F << IWCR_HS_CNT1_SHIFT)
+#define IWCR_HS_CNT2_SHIFT 10
+#define IWCR_HS_CNT2_MASK (0x1F << IWCR_HS_CNT2_SHIFT)
+
struct pxa_i2c {
spinlock_t lock;
wait_queue_head_t wait;
@@ -150,6 +180,8 @@ struct pxa_i2c {
void __iomem *reg_icr;
void __iomem *reg_isr;
void __iomem *reg_isar;
+ void __iomem *reg_ilcr;
+ void __iomem *reg_iwcr;
unsigned long iobase;
unsigned long iosize;
@@ -168,6 +200,8 @@ struct pxa_i2c {
#define _ICR(i2c) ((i2c)->reg_icr)
#define _ISR(i2c) ((i2c)->reg_isr)
#define _ISAR(i2c) ((i2c)->reg_isar)
+#define _ILCR(i2c) ((i2c)->reg_ilcr)
+#define _IWCR(i2c) ((i2c)->reg_iwcr)
/*
* I2C Slave mode address
@@ -1102,7 +1136,7 @@ static const struct i2c_algorithm i2c_pxa_pio_algorithm = {
static const struct of_device_id i2c_pxa_dt_ids[] = {
{ .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX },
{ .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX },
- { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA2XX },
+ { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 },
{}
};
MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids);
@@ -1203,6 +1237,11 @@ static int i2c_pxa_probe(struct platform_device *dev)
if (i2c_type != REGS_CE4100)
i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar;
+ if (i2c_type == REGS_PXA910) {
+ i2c->reg_ilcr = i2c->reg_base + pxa_reg_layout[i2c_type].ilcr;
+ i2c->reg_iwcr = i2c->reg_base + pxa_reg_layout[i2c_type].iwcr;
+ }
+
i2c->iobase = res->start;
i2c->iosize = resource_size(res);
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index d8b5a8f..599c0d7 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -27,7 +27,6 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/i2c.h>
-#include <linux/i2c/i2c-rcar.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -103,6 +102,7 @@
enum rcar_i2c_type {
I2C_RCAR_GEN1,
I2C_RCAR_GEN2,
+ I2C_RCAR_GEN3,
};
struct rcar_i2c_priv {
@@ -178,6 +178,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
cdf_width = 2;
break;
case I2C_RCAR_GEN2:
+ case I2C_RCAR_GEN3:
cdf_width = 3;
break;
default:
@@ -575,7 +576,7 @@ static int rcar_reg_slave(struct i2c_client *slave)
if (slave->flags & I2C_CLIENT_TEN)
return -EAFNOSUPPORT;
- pm_runtime_forbid(rcar_i2c_priv_to_dev(priv));
+ pm_runtime_get_sync(rcar_i2c_priv_to_dev(priv));
priv->slave = slave;
rcar_i2c_write(priv, ICSAR, slave->addr);
@@ -597,7 +598,7 @@ static int rcar_unreg_slave(struct i2c_client *slave)
priv->slave = NULL;
- pm_runtime_allow(rcar_i2c_priv_to_dev(priv));
+ pm_runtime_put(rcar_i2c_priv_to_dev(priv));
return 0;
}
@@ -625,13 +626,13 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
{ .compatible = "renesas,i2c-r8a7792", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 },
{ .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 },
+ { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 },
{},
};
MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
static int rcar_i2c_probe(struct platform_device *pdev)
{
- struct i2c_rcar_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct rcar_i2c_priv *priv;
struct i2c_adapter *adap;
struct resource *res;
@@ -650,15 +651,9 @@ static int rcar_i2c_probe(struct platform_device *pdev)
}
bus_speed = 100000; /* default 100 kHz */
- ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
- if (ret < 0 && pdata && pdata->bus_speed)
- bus_speed = pdata->bus_speed;
+ of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
- if (pdev->dev.of_node)
- priv->devtype = (long)of_match_device(rcar_i2c_dt_ids,
- dev)->data;
- else
- priv->devtype = platform_get_device_id(pdev)->driver_data;
+ priv->devtype = (enum rcar_i2c_type)of_match_device(rcar_i2c_dt_ids, dev)->data;
ret = rcar_i2c_clock_calculate(priv, bus_speed, dev);
if (ret < 0)
@@ -716,14 +711,6 @@ static int rcar_i2c_remove(struct platform_device *pdev)
return 0;
}
-static const struct platform_device_id rcar_i2c_id_table[] = {
- { "i2c-rcar", I2C_RCAR_GEN1 },
- { "i2c-rcar_gen1", I2C_RCAR_GEN1 },
- { "i2c-rcar_gen2", I2C_RCAR_GEN2 },
- {},
-};
-MODULE_DEVICE_TABLE(platform, rcar_i2c_id_table);
-
static struct platform_driver rcar_i2c_driver = {
.driver = {
.name = "i2c-rcar",
@@ -731,7 +718,6 @@ static struct platform_driver rcar_i2c_driver = {
},
.probe = rcar_i2c_probe,
.remove = rcar_i2c_remove,
- .id_table = rcar_i2c_id_table,
};
module_platform_driver(rcar_i2c_driver);
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 72e97e30..9096d17 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -858,6 +858,7 @@ static const struct of_device_id rk3x_i2c_match[] = {
{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
{},
};
+MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
static int rk3x_i2c_probe(struct platform_device *pdev)
{
@@ -907,7 +908,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
&i2c->scl_fall_ns))
i2c->scl_fall_ns = 300;
if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
- &i2c->scl_fall_ns))
+ &i2c->sda_fall_ns))
i2c->sda_fall_ns = i2c->scl_fall_ns;
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 47659a9..7d2bd3e 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -836,6 +836,7 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = {
{ .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config },
+ { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config },
{ .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config },
{},
};
diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c
index 1092d4e..13e51ef 100644
--- a/drivers/i2c/busses/i2c-sirf.c
+++ b/drivers/i2c/busses/i2c-sirf.c
@@ -358,11 +358,29 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
if (err < 0)
bitrate = SIRFSOC_I2C_DEFAULT_SPEED;
- if (bitrate < 100000)
- regval =
- (2 * ctrl_speed) / (bitrate * 11);
- else
+ /*
+ * Due to some hardware design issues, we need to tune the formula.
+ * Since i2c is open drain interface that allows the slave to
+ * stall the transaction by holding the SCL line at '0', the RTL
+ * implementation is waiting for SCL feedback from the pin after
+ * setting it to High-Z ('1'). This wait adds to the high-time
+ * interval counter few cycles of the input synchronization
+ * (depending on the SCL_FILTER_REG field), and also the time it
+ * takes for the board pull-up resistor to rise the SCL line.
+ * For slow SCL settings these additions are negligible,
+ * but they start to affect the speed when clock is set to faster
+ * frequencies.
+ * Through the actual tests, use the different user_div value(which
+ * in the divider formular 'Fio / (Fi2c * user_div)') to adapt
+ * the different ranges of i2c bus clock frequency, to make the SCL
+ * more accurate.
+ */
+ if (bitrate <= 30000)
regval = ctrl_speed / (bitrate * 5);
+ else if (bitrate > 30000 && bitrate <= 280000)
+ regval = (2 * ctrl_speed) / (bitrate * 11);
+ else
+ regval = ctrl_speed / (bitrate * 6);
writel(regval, siic->base + SIRFSOC_I2C_CLK_CTRL);
if (regval > 0xFF)
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index ea72dca..25020ec 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -822,7 +822,7 @@ static int st_i2c_probe(struct platform_device *pdev)
adap = &i2c_dev->adap;
i2c_set_adapdata(adap, i2c_dev);
- snprintf(adap->name, sizeof(adap->name), "ST I2C(0x%pa)", &res->start);
+ snprintf(adap->name, sizeof(adap->name), "ST I2C(%pa)", &res->start);
adap->owner = THIS_MODULE;
adap->timeout = 2 * HZ;
adap->retries = 0;
diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c
index 4885da9..460c134 100644
--- a/drivers/i2c/busses/i2c-stu300.c
+++ b/drivers/i2c/busses/i2c-stu300.c
@@ -977,6 +977,7 @@ static const struct of_device_id stu300_dt_match[] = {
{ .compatible = "st,ddci2c" },
{},
};
+MODULE_DEVICE_TABLE(of, stu300_dt_match);
static struct platform_driver stu300_i2c_driver = {
.driver = {
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index b7e1a36..a0522fc 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -873,7 +873,6 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_dev->adapter.class = I2C_CLASS_DEPRECATED;
strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
sizeof(i2c_dev->adapter.name));
- i2c_dev->adapter.algo = &tegra_i2c_algo;
i2c_dev->adapter.dev.parent = &pdev->dev;
i2c_dev->adapter.nr = pdev->id;
i2c_dev->adapter.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c
new file mode 100644
index 0000000..e8d03bc
--- /dev/null
+++ b/drivers/i2c/busses/i2c-uniphier-f.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_FI2C_CR 0x00 /* control register */
+#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */
+#define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */
+#define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */
+#define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */
+#define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */
+#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */
+#define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */
+#define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */
+#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */
+#define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */
+#define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */
+#define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */
+#define UNIPHIER_FI2C_DSUT 0x1c /* data setup time control */
+#define UNIPHIER_FI2C_INT 0x20 /* interrupt status */
+#define UNIPHIER_FI2C_IE 0x24 /* interrupt enable */
+#define UNIPHIER_FI2C_IC 0x28 /* interrupt clear */
+#define UNIPHIER_FI2C_INT_TE BIT(9) /* TX FIFO empty */
+#define UNIPHIER_FI2C_INT_RF BIT(8) /* RX FIFO full */
+#define UNIPHIER_FI2C_INT_TC BIT(7) /* send complete (STOP) */
+#define UNIPHIER_FI2C_INT_RC BIT(6) /* receive complete (STOP) */
+#define UNIPHIER_FI2C_INT_TB BIT(5) /* sent specified bytes */
+#define UNIPHIER_FI2C_INT_RB BIT(4) /* received specified bytes */
+#define UNIPHIER_FI2C_INT_NA BIT(2) /* no ACK */
+#define UNIPHIER_FI2C_INT_AL BIT(1) /* arbitration lost */
+#define UNIPHIER_FI2C_SR 0x2c /* status register */
+#define UNIPHIER_FI2C_SR_DB BIT(12) /* device busy */
+#define UNIPHIER_FI2C_SR_STS BIT(11) /* stop condition detected */
+#define UNIPHIER_FI2C_SR_BB BIT(8) /* bus busy */
+#define UNIPHIER_FI2C_SR_RFF BIT(3) /* RX FIFO full */
+#define UNIPHIER_FI2C_SR_RNE BIT(2) /* RX FIFO not empty */
+#define UNIPHIER_FI2C_SR_TNF BIT(1) /* TX FIFO not full */
+#define UNIPHIER_FI2C_SR_TFE BIT(0) /* TX FIFO empty */
+#define UNIPHIER_FI2C_RST 0x34 /* reset control */
+#define UNIPHIER_FI2C_RST_TBRST BIT(2) /* clear TX FIFO */
+#define UNIPHIER_FI2C_RST_RBRST BIT(1) /* clear RX FIFO */
+#define UNIPHIER_FI2C_RST_RST BIT(0) /* forcible bus reset */
+#define UNIPHIER_FI2C_BM 0x38 /* bus monitor */
+#define UNIPHIER_FI2C_BM_SDAO BIT(3) /* output for SDA line */
+#define UNIPHIER_FI2C_BM_SDAS BIT(2) /* readback of SDA line */
+#define UNIPHIER_FI2C_BM_SCLO BIT(1) /* output for SCL line */
+#define UNIPHIER_FI2C_BM_SCLS BIT(0) /* readback of SCL line */
+#define UNIPHIER_FI2C_NOISE 0x3c /* noise filter control */
+#define UNIPHIER_FI2C_TBC 0x40 /* TX byte count setting */
+#define UNIPHIER_FI2C_RBC 0x44 /* RX byte count setting */
+#define UNIPHIER_FI2C_TBCM 0x48 /* TX byte count monitor */
+#define UNIPHIER_FI2C_RBCM 0x4c /* RX byte count monitor */
+#define UNIPHIER_FI2C_BRST 0x50 /* bus reset */
+#define UNIPHIER_FI2C_BRST_FOEN BIT(1) /* normal operation */
+#define UNIPHIER_FI2C_BRST_RSCL BIT(0) /* release SCL */
+
+#define UNIPHIER_FI2C_INT_FAULTS \
+ (UNIPHIER_FI2C_INT_NA | UNIPHIER_FI2C_INT_AL)
+#define UNIPHIER_FI2C_INT_STOP \
+ (UNIPHIER_FI2C_INT_TC | UNIPHIER_FI2C_INT_RC)
+
+#define UNIPHIER_FI2C_RD BIT(0)
+#define UNIPHIER_FI2C_STOP BIT(1)
+#define UNIPHIER_FI2C_MANUAL_NACK BIT(2)
+#define UNIPHIER_FI2C_BYTE_WISE BIT(3)
+#define UNIPHIER_FI2C_DEFER_STOP_COMP BIT(4)
+
+#define UNIPHIER_FI2C_DEFAULT_SPEED 100000
+#define UNIPHIER_FI2C_MAX_SPEED 400000
+#define UNIPHIER_FI2C_FIFO_SIZE 8
+
+struct uniphier_fi2c_priv {
+ struct completion comp;
+ struct i2c_adapter adap;
+ void __iomem *membase;
+ struct clk *clk;
+ unsigned int len;
+ u8 *buf;
+ u32 enabled_irqs;
+ int error;
+ unsigned int flags;
+ unsigned int busy_cnt;
+};
+
+static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv,
+ bool first)
+{
+ int fifo_space = UNIPHIER_FI2C_FIFO_SIZE;
+
+ /*
+ * TX-FIFO stores slave address in it for the first access.
+ * Decrement the counter.
+ */
+ if (first)
+ fifo_space--;
+
+ while (priv->len) {
+ if (fifo_space-- <= 0)
+ break;
+
+ dev_dbg(&priv->adap.dev, "write data: %02x\n", *priv->buf);
+ writel(*priv->buf++, priv->membase + UNIPHIER_FI2C_DTTX);
+ priv->len--;
+ }
+}
+
+static void uniphier_fi2c_drain_rxfifo(struct uniphier_fi2c_priv *priv)
+{
+ int fifo_left = priv->flags & UNIPHIER_FI2C_BYTE_WISE ?
+ 1 : UNIPHIER_FI2C_FIFO_SIZE;
+
+ while (priv->len) {
+ if (fifo_left-- <= 0)
+ break;
+
+ *priv->buf++ = readl(priv->membase + UNIPHIER_FI2C_DTRX);
+ dev_dbg(&priv->adap.dev, "read data: %02x\n", priv->buf[-1]);
+ priv->len--;
+ }
+}
+
+static void uniphier_fi2c_set_irqs(struct uniphier_fi2c_priv *priv)
+{
+ writel(priv->enabled_irqs, priv->membase + UNIPHIER_FI2C_IE);
+}
+
+static void uniphier_fi2c_clear_irqs(struct uniphier_fi2c_priv *priv)
+{
+ writel(-1, priv->membase + UNIPHIER_FI2C_IC);
+}
+
+static void uniphier_fi2c_stop(struct uniphier_fi2c_priv *priv)
+{
+ dev_dbg(&priv->adap.dev, "stop condition\n");
+
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_STOP;
+ uniphier_fi2c_set_irqs(priv);
+ writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STO,
+ priv->membase + UNIPHIER_FI2C_CR);
+}
+
+static irqreturn_t uniphier_fi2c_interrupt(int irq, void *dev_id)
+{
+ struct uniphier_fi2c_priv *priv = dev_id;
+ u32 irq_status;
+
+ irq_status = readl(priv->membase + UNIPHIER_FI2C_INT);
+
+ dev_dbg(&priv->adap.dev,
+ "interrupt: enabled_irqs=%04x, irq_status=%04x\n",
+ priv->enabled_irqs, irq_status);
+
+ if (irq_status & UNIPHIER_FI2C_INT_STOP)
+ goto complete;
+
+ if (unlikely(irq_status & UNIPHIER_FI2C_INT_AL)) {
+ dev_dbg(&priv->adap.dev, "arbitration lost\n");
+ priv->error = -EAGAIN;
+ goto complete;
+ }
+
+ if (unlikely(irq_status & UNIPHIER_FI2C_INT_NA)) {
+ dev_dbg(&priv->adap.dev, "could not get ACK\n");
+ priv->error = -ENXIO;
+ if (priv->flags & UNIPHIER_FI2C_RD) {
+ /*
+ * work around a hardware bug:
+ * The receive-completed interrupt is never set even if
+ * STOP condition is detected after the address phase
+ * of read transaction fails to get ACK.
+ * To avoid time-out error, we issue STOP here,
+ * but do not wait for its completion.
+ * It should be checked after exiting this handler.
+ */
+ uniphier_fi2c_stop(priv);
+ priv->flags |= UNIPHIER_FI2C_DEFER_STOP_COMP;
+ goto complete;
+ }
+ goto stop;
+ }
+
+ if (irq_status & UNIPHIER_FI2C_INT_TE) {
+ if (!priv->len)
+ goto data_done;
+
+ uniphier_fi2c_fill_txfifo(priv, false);
+ goto handled;
+ }
+
+ if (irq_status & (UNIPHIER_FI2C_INT_RF | UNIPHIER_FI2C_INT_RB)) {
+ uniphier_fi2c_drain_rxfifo(priv);
+ if (!priv->len)
+ goto data_done;
+
+ if (unlikely(priv->flags & UNIPHIER_FI2C_MANUAL_NACK)) {
+ if (priv->len <= UNIPHIER_FI2C_FIFO_SIZE &&
+ !(priv->flags & UNIPHIER_FI2C_BYTE_WISE)) {
+ dev_dbg(&priv->adap.dev,
+ "enable read byte count IRQ\n");
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RB;
+ uniphier_fi2c_set_irqs(priv);
+ priv->flags |= UNIPHIER_FI2C_BYTE_WISE;
+ }
+ if (priv->len <= 1) {
+ dev_dbg(&priv->adap.dev, "set NACK\n");
+ writel(UNIPHIER_FI2C_CR_MST |
+ UNIPHIER_FI2C_CR_NACK,
+ priv->membase + UNIPHIER_FI2C_CR);
+ }
+ }
+
+ goto handled;
+ }
+
+ return IRQ_NONE;
+
+data_done:
+ if (priv->flags & UNIPHIER_FI2C_STOP) {
+stop:
+ uniphier_fi2c_stop(priv);
+ } else {
+complete:
+ priv->enabled_irqs = 0;
+ uniphier_fi2c_set_irqs(priv);
+ complete(&priv->comp);
+ }
+
+handled:
+ uniphier_fi2c_clear_irqs(priv);
+
+ return IRQ_HANDLED;
+}
+
+static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_TE;
+ /* do not use TX byte counter */
+ writel(0, priv->membase + UNIPHIER_FI2C_TBC);
+ /* set slave address */
+ writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1,
+ priv->membase + UNIPHIER_FI2C_DTTX);
+ /* first chunk of data */
+ uniphier_fi2c_fill_txfifo(priv, true);
+}
+
+static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr)
+{
+ priv->flags |= UNIPHIER_FI2C_RD;
+
+ if (likely(priv->len < 256)) {
+ /*
+ * If possible, use RX byte counter.
+ * It can automatically handle NACK for the last byte.
+ */
+ writel(priv->len, priv->membase + UNIPHIER_FI2C_RBC);
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF |
+ UNIPHIER_FI2C_INT_RB;
+ } else {
+ /*
+ * The byte counter can not count over 256. In this case,
+ * do not use it at all. Drain data when FIFO gets full,
+ * but treat the last portion as a special case.
+ */
+ writel(0, priv->membase + UNIPHIER_FI2C_RBC);
+ priv->flags |= UNIPHIER_FI2C_MANUAL_NACK;
+ priv->enabled_irqs |= UNIPHIER_FI2C_INT_RF;
+ }
+
+ /* set slave address with RD bit */
+ writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1,
+ priv->membase + UNIPHIER_FI2C_DTTX);
+}
+
+static void uniphier_fi2c_reset(struct uniphier_fi2c_priv *priv)
+{
+ writel(UNIPHIER_FI2C_RST_RST, priv->membase + UNIPHIER_FI2C_RST);
+}
+
+static void uniphier_fi2c_prepare_operation(struct uniphier_fi2c_priv *priv)
+{
+ writel(UNIPHIER_FI2C_BRST_FOEN | UNIPHIER_FI2C_BRST_RSCL,
+ priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv)
+{
+ uniphier_fi2c_reset(priv);
+ i2c_recover_bus(&priv->adap);
+}
+
+static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap,
+ struct i2c_msg *msg, bool stop)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+ bool is_read = msg->flags & I2C_M_RD;
+ unsigned long time_left;
+
+ dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
+ is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+
+ priv->len = msg->len;
+ priv->buf = msg->buf;
+ priv->enabled_irqs = UNIPHIER_FI2C_INT_FAULTS;
+ priv->error = 0;
+ priv->flags = 0;
+
+ if (stop)
+ priv->flags |= UNIPHIER_FI2C_STOP;
+
+ reinit_completion(&priv->comp);
+ uniphier_fi2c_clear_irqs(priv);
+ writel(UNIPHIER_FI2C_RST_TBRST | UNIPHIER_FI2C_RST_RBRST,
+ priv->membase + UNIPHIER_FI2C_RST); /* reset TX/RX FIFO */
+
+ if (is_read)
+ uniphier_fi2c_rx_init(priv, msg->addr);
+ else
+ uniphier_fi2c_tx_init(priv, msg->addr);
+
+ uniphier_fi2c_set_irqs(priv);
+
+ dev_dbg(&adap->dev, "start condition\n");
+ writel(UNIPHIER_FI2C_CR_MST | UNIPHIER_FI2C_CR_STA,
+ priv->membase + UNIPHIER_FI2C_CR);
+
+ time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+ if (!time_left) {
+ dev_err(&adap->dev, "transaction timeout.\n");
+ uniphier_fi2c_recover(priv);
+ return -ETIMEDOUT;
+ }
+ dev_dbg(&adap->dev, "complete\n");
+
+ if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) {
+ u32 status = readl(priv->membase + UNIPHIER_FI2C_SR);
+
+ if (!(status & UNIPHIER_FI2C_SR_STS) ||
+ status & UNIPHIER_FI2C_SR_BB) {
+ dev_err(&adap->dev,
+ "stop condition was not completed.\n");
+ uniphier_fi2c_recover(priv);
+ return -EBUSY;
+ }
+ }
+
+ return priv->error;
+}
+
+static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (readl(priv->membase + UNIPHIER_FI2C_SR) & UNIPHIER_FI2C_SR_DB) {
+ if (priv->busy_cnt++ > 3) {
+ /*
+ * If bus busy continues too long, it is probably
+ * in a wrong state. Try bus recovery.
+ */
+ uniphier_fi2c_recover(priv);
+ priv->busy_cnt = 0;
+ }
+
+ return -EAGAIN;
+ }
+
+ priv->busy_cnt = 0;
+ return 0;
+}
+
+static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *msg, *emsg = msgs + num;
+ int ret;
+
+ ret = uniphier_fi2c_check_bus_busy(adap);
+ if (ret)
+ return ret;
+
+ for (msg = msgs; msg < emsg; msg++) {
+ /* If next message is read, skip the stop condition */
+ bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
+ /* but, force it if I2C_M_STOP is set */
+ if (msg->flags & I2C_M_STOP)
+ stop = true;
+
+ ret = uniphier_fi2c_master_xfer_one(adap, msg, stop);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_fi2c_algo = {
+ .master_xfer = uniphier_fi2c_master_xfer,
+ .functionality = uniphier_fi2c_functionality,
+};
+
+static int uniphier_fi2c_get_scl(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+ UNIPHIER_FI2C_BM_SCLS);
+}
+
+static void uniphier_fi2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ writel(val ? UNIPHIER_FI2C_BRST_RSCL : 0,
+ priv->membase + UNIPHIER_FI2C_BRST);
+}
+
+static int uniphier_fi2c_get_sda(struct i2c_adapter *adap)
+{
+ struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_FI2C_BM) &
+ UNIPHIER_FI2C_BM_SDAS);
+}
+
+static void uniphier_fi2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ uniphier_fi2c_prepare_operation(i2c_get_adapdata(adap));
+}
+
+static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = uniphier_fi2c_get_scl,
+ .set_scl = uniphier_fi2c_set_scl,
+ .get_sda = uniphier_fi2c_get_sda,
+ .unprepare_recovery = uniphier_fi2c_unprepare_recovery,
+};
+
+static int uniphier_fi2c_clk_init(struct device *dev,
+ struct uniphier_fi2c_priv *priv)
+{
+ struct device_node *np = dev->of_node;
+ unsigned long clk_rate;
+ u32 bus_speed, clk_count;
+ int ret;
+
+ if (of_property_read_u32(np, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED;
+
+ if (bus_speed > UNIPHIER_FI2C_MAX_SPEED)
+ bus_speed = UNIPHIER_FI2C_MAX_SPEED;
+
+ /* Get input clk rate through clk driver */
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+
+ uniphier_fi2c_reset(priv);
+
+ clk_count = clk_rate / bus_speed;
+
+ writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC);
+ writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL);
+ writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT);
+ writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT);
+
+ uniphier_fi2c_prepare_operation(priv);
+
+ return 0;
+}
+
+static int uniphier_fi2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_fi2c_priv *priv;
+ struct resource *regs;
+ int irq;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number");
+ return irq;
+ }
+
+ init_completion(&priv->comp);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &uniphier_fi2c_algo;
+ priv->adap.dev.parent = dev;
+ priv->adap.dev.of_node = dev->of_node;
+ strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name));
+ priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info;
+ i2c_set_adapdata(&priv->adap, priv);
+ platform_set_drvdata(pdev, priv);
+
+ ret = uniphier_fi2c_clk_init(dev, priv);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0,
+ pdev->name, priv);
+ if (ret) {
+ dev_err(dev, "failed to request irq %d\n", irq);
+ goto err;
+ }
+
+ ret = i2c_add_adapter(&priv->adap);
+ if (ret) {
+ dev_err(dev, "failed to add I2C adapter\n");
+ goto err;
+ }
+
+err:
+ if (ret)
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int uniphier_fi2c_remove(struct platform_device *pdev)
+{
+ struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_fi2c_match[] = {
+ { .compatible = "socionext,uniphier-fi2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_fi2c_match);
+
+static struct platform_driver uniphier_fi2c_drv = {
+ .probe = uniphier_fi2c_probe,
+ .remove = uniphier_fi2c_remove,
+ .driver = {
+ .name = "uniphier-fi2c",
+ .of_match_table = uniphier_fi2c_match,
+ },
+};
+module_platform_driver(uniphier_fi2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier FIFO-builtin I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c
new file mode 100644
index 0000000..e3c3861
--- /dev/null
+++ b/drivers/i2c/busses/i2c-uniphier.c
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define UNIPHIER_I2C_DTRM 0x00 /* TX register */
+#define UNIPHIER_I2C_DTRM_IRQEN BIT(11) /* enable interrupt */
+#define UNIPHIER_I2C_DTRM_STA BIT(10) /* start condition */
+#define UNIPHIER_I2C_DTRM_STO BIT(9) /* stop condition */
+#define UNIPHIER_I2C_DTRM_NACK BIT(8) /* do not return ACK */
+#define UNIPHIER_I2C_DTRM_RD BIT(0) /* read transaction */
+#define UNIPHIER_I2C_DREC 0x04 /* RX register */
+#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = master, 0 = slave */
+#define UNIPHIER_I2C_DREC_TX BIT(13) /* 1 = transmit, 0 = receive */
+#define UNIPHIER_I2C_DREC_STS BIT(12) /* stop condition detected */
+#define UNIPHIER_I2C_DREC_LRB BIT(11) /* no ACK */
+#define UNIPHIER_I2C_DREC_LAB BIT(9) /* arbitration lost */
+#define UNIPHIER_I2C_DREC_BBN BIT(8) /* bus not busy */
+#define UNIPHIER_I2C_MYAD 0x08 /* slave address */
+#define UNIPHIER_I2C_CLK 0x0c /* clock frequency control */
+#define UNIPHIER_I2C_BRST 0x10 /* bus reset */
+#define UNIPHIER_I2C_BRST_FOEN BIT(1) /* normal operation */
+#define UNIPHIER_I2C_BRST_RSCL BIT(0) /* release SCL */
+#define UNIPHIER_I2C_HOLD 0x14 /* hold time control */
+#define UNIPHIER_I2C_BSTS 0x18 /* bus status monitor */
+#define UNIPHIER_I2C_BSTS_SDA BIT(1) /* readback of SDA line */
+#define UNIPHIER_I2C_BSTS_SCL BIT(0) /* readback of SCL line */
+#define UNIPHIER_I2C_NOISE 0x1c /* noise filter control */
+#define UNIPHIER_I2C_SETUP 0x20 /* setup time control */
+
+#define UNIPHIER_I2C_DEFAULT_SPEED 100000
+#define UNIPHIER_I2C_MAX_SPEED 400000
+
+struct uniphier_i2c_priv {
+ struct completion comp;
+ struct i2c_adapter adap;
+ void __iomem *membase;
+ struct clk *clk;
+ unsigned int busy_cnt;
+};
+
+static irqreturn_t uniphier_i2c_interrupt(int irq, void *dev_id)
+{
+ struct uniphier_i2c_priv *priv = dev_id;
+
+ /*
+ * This hardware uses edge triggered interrupt. Do not touch the
+ * hardware registers in this handler to make sure to catch the next
+ * interrupt edge. Just send a complete signal and return.
+ */
+ complete(&priv->comp);
+
+ return IRQ_HANDLED;
+}
+
+static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata,
+ u32 *rxdatap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+ unsigned long time_left;
+ u32 rxdata;
+
+ reinit_completion(&priv->comp);
+
+ txdata |= UNIPHIER_I2C_DTRM_IRQEN;
+ dev_dbg(&adap->dev, "write data: 0x%04x\n", txdata);
+ writel(txdata, priv->membase + UNIPHIER_I2C_DTRM);
+
+ time_left = wait_for_completion_timeout(&priv->comp, adap->timeout);
+ if (unlikely(!time_left)) {
+ dev_err(&adap->dev, "transaction timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ rxdata = readl(priv->membase + UNIPHIER_I2C_DREC);
+ dev_dbg(&adap->dev, "read data: 0x%04x\n", rxdata);
+
+ if (rxdatap)
+ *rxdatap = rxdata;
+
+ return 0;
+}
+
+static int uniphier_i2c_send_byte(struct i2c_adapter *adap, u32 txdata)
+{
+ u32 rxdata;
+ int ret;
+
+ ret = uniphier_i2c_xfer_byte(adap, txdata, &rxdata);
+ if (ret)
+ return ret;
+
+ if (unlikely(rxdata & UNIPHIER_I2C_DREC_LAB)) {
+ dev_dbg(&adap->dev, "arbitration lost\n");
+ return -EAGAIN;
+ }
+ if (unlikely(rxdata & UNIPHIER_I2C_DREC_LRB)) {
+ dev_dbg(&adap->dev, "could not get ACK\n");
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_tx(struct i2c_adapter *adap, u16 addr, u16 len,
+ const u8 *buf)
+{
+ int ret;
+
+ dev_dbg(&adap->dev, "start condition\n");
+ ret = uniphier_i2c_send_byte(adap, addr << 1 |
+ UNIPHIER_I2C_DTRM_STA |
+ UNIPHIER_I2C_DTRM_NACK);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ ret = uniphier_i2c_send_byte(adap,
+ UNIPHIER_I2C_DTRM_NACK | *buf++);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_rx(struct i2c_adapter *adap, u16 addr, u16 len,
+ u8 *buf)
+{
+ int ret;
+
+ dev_dbg(&adap->dev, "start condition\n");
+ ret = uniphier_i2c_send_byte(adap, addr << 1 |
+ UNIPHIER_I2C_DTRM_STA |
+ UNIPHIER_I2C_DTRM_NACK |
+ UNIPHIER_I2C_DTRM_RD);
+ if (ret)
+ return ret;
+
+ while (len--) {
+ u32 rxdata;
+
+ ret = uniphier_i2c_xfer_byte(adap,
+ len ? 0 : UNIPHIER_I2C_DTRM_NACK,
+ &rxdata);
+ if (ret)
+ return ret;
+ *buf++ = rxdata;
+ }
+
+ return 0;
+}
+
+static int uniphier_i2c_stop(struct i2c_adapter *adap)
+{
+ dev_dbg(&adap->dev, "stop condition\n");
+ return uniphier_i2c_send_byte(adap, UNIPHIER_I2C_DTRM_STO |
+ UNIPHIER_I2C_DTRM_NACK);
+}
+
+static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap,
+ struct i2c_msg *msg, bool stop)
+{
+ bool is_read = msg->flags & I2C_M_RD;
+ bool recovery = false;
+ int ret;
+
+ dev_dbg(&adap->dev, "%s: addr=0x%02x, len=%d, stop=%d\n",
+ is_read ? "receive" : "transmit", msg->addr, msg->len, stop);
+
+ if (is_read)
+ ret = uniphier_i2c_rx(adap, msg->addr, msg->len, msg->buf);
+ else
+ ret = uniphier_i2c_tx(adap, msg->addr, msg->len, msg->buf);
+
+ if (ret == -EAGAIN) /* could not acquire bus. bail out without STOP */
+ return ret;
+
+ if (ret == -ETIMEDOUT) {
+ /* This error is fatal. Needs recovery. */
+ stop = false;
+ recovery = true;
+ }
+
+ if (stop) {
+ int ret2 = uniphier_i2c_stop(adap);
+
+ if (ret2) {
+ /* Failed to issue STOP. The bus needs recovery. */
+ recovery = true;
+ ret = ret ?: ret2;
+ }
+ }
+
+ if (recovery)
+ i2c_recover_bus(adap);
+
+ return ret;
+}
+
+static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ if (!(readl(priv->membase + UNIPHIER_I2C_DREC) &
+ UNIPHIER_I2C_DREC_BBN)) {
+ if (priv->busy_cnt++ > 3) {
+ /*
+ * If bus busy continues too long, it is probably
+ * in a wrong state. Try bus recovery.
+ */
+ i2c_recover_bus(adap);
+ priv->busy_cnt = 0;
+ }
+
+ return -EAGAIN;
+ }
+
+ priv->busy_cnt = 0;
+ return 0;
+}
+
+static int uniphier_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct i2c_msg *msg, *emsg = msgs + num;
+ int ret;
+
+ ret = uniphier_i2c_check_bus_busy(adap);
+ if (ret)
+ return ret;
+
+ for (msg = msgs; msg < emsg; msg++) {
+ /* If next message is read, skip the stop condition */
+ bool stop = !(msg + 1 < emsg && msg[1].flags & I2C_M_RD);
+ /* but, force it if I2C_M_STOP is set */
+ if (msg->flags & I2C_M_STOP)
+ stop = true;
+
+ ret = uniphier_i2c_master_xfer_one(adap, msg, stop);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 uniphier_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm uniphier_i2c_algo = {
+ .master_xfer = uniphier_i2c_master_xfer,
+ .functionality = uniphier_i2c_functionality,
+};
+
+static void uniphier_i2c_reset(struct uniphier_i2c_priv *priv, bool reset_on)
+{
+ u32 val = UNIPHIER_I2C_BRST_RSCL;
+
+ val |= reset_on ? 0 : UNIPHIER_I2C_BRST_FOEN;
+ writel(val, priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+ UNIPHIER_I2C_BSTS_SCL);
+}
+
+static void uniphier_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ writel(val ? UNIPHIER_I2C_BRST_RSCL : 0,
+ priv->membase + UNIPHIER_I2C_BRST);
+}
+
+static int uniphier_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct uniphier_i2c_priv *priv = i2c_get_adapdata(adap);
+
+ return !!(readl(priv->membase + UNIPHIER_I2C_BSTS) &
+ UNIPHIER_I2C_BSTS_SDA);
+}
+
+static void uniphier_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ uniphier_i2c_reset(i2c_get_adapdata(adap), false);
+}
+
+static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .get_scl = uniphier_i2c_get_scl,
+ .set_scl = uniphier_i2c_set_scl,
+ .get_sda = uniphier_i2c_get_sda,
+ .unprepare_recovery = uniphier_i2c_unprepare_recovery,
+};
+
+static int uniphier_i2c_clk_init(struct device *dev,
+ struct uniphier_i2c_priv *priv)
+{
+ struct device_node *np = dev->of_node;
+ unsigned long clk_rate;
+ u32 bus_speed;
+ int ret;
+
+ if (of_property_read_u32(np, "clock-frequency", &bus_speed))
+ bus_speed = UNIPHIER_I2C_DEFAULT_SPEED;
+
+ if (bus_speed > UNIPHIER_I2C_MAX_SPEED)
+ bus_speed = UNIPHIER_I2C_MAX_SPEED;
+
+ /* Get input clk rate through clk driver */
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(dev, "failed to get clock\n");
+ return PTR_ERR(priv->clk);
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ return ret;
+
+ clk_rate = clk_get_rate(priv->clk);
+
+ uniphier_i2c_reset(priv, true);
+
+ writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed),
+ priv->membase + UNIPHIER_I2C_CLK);
+
+ uniphier_i2c_reset(priv, false);
+
+ return 0;
+}
+
+static int uniphier_i2c_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct uniphier_i2c_priv *priv;
+ struct resource *regs;
+ int irq;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->membase = devm_ioremap_resource(dev, regs);
+ if (IS_ERR(priv->membase))
+ return PTR_ERR(priv->membase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "failed to get IRQ number");
+ return irq;
+ }
+
+ init_completion(&priv->comp);
+ priv->adap.owner = THIS_MODULE;
+ priv->adap.algo = &uniphier_i2c_algo;
+ priv->adap.dev.parent = dev;
+ priv->adap.dev.of_node = dev->of_node;
+ strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name));
+ priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info;
+ i2c_set_adapdata(&priv->adap, priv);
+ platform_set_drvdata(pdev, priv);
+
+ ret = uniphier_i2c_clk_init(dev, priv);
+ if (ret)
+ return ret;
+
+ ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name,
+ priv);
+ if (ret) {
+ dev_err(dev, "failed to request irq %d\n", irq);
+ goto err;
+ }
+
+ ret = i2c_add_adapter(&priv->adap);
+ if (ret) {
+ dev_err(dev, "failed to add I2C adapter\n");
+ goto err;
+ }
+
+err:
+ if (ret)
+ clk_disable_unprepare(priv->clk);
+
+ return ret;
+}
+
+static int uniphier_i2c_remove(struct platform_device *pdev)
+{
+ struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&priv->adap);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static const struct of_device_id uniphier_i2c_match[] = {
+ { .compatible = "socionext,uniphier-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, uniphier_i2c_match);
+
+static struct platform_driver uniphier_i2c_drv = {
+ .probe = uniphier_i2c_probe,
+ .remove = uniphier_i2c_remove,
+ .driver = {
+ .name = "uniphier-i2c",
+ .of_match_table = uniphier_i2c_match,
+ },
+};
+module_platform_driver(uniphier_i2c_drv);
+
+MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
+MODULE_DESCRIPTION("UniPhier I2C bus driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c
index e23a7b0..0b20449 100644
--- a/drivers/i2c/busses/i2c-xiic.c
+++ b/drivers/i2c/busses/i2c-xiic.c
@@ -662,8 +662,10 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c)
static void xiic_start_xfer(struct xiic_i2c *i2c)
{
-
+ spin_lock(&i2c->lock);
+ xiic_reinit(i2c);
__xiic_start_xfer(i2c);
+ spin_unlock(&i2c->lock);
}
static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a59c311..ba8eb08 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -99,27 +99,40 @@ struct gsb_buffer {
};
} __packed;
-static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
+struct acpi_i2c_lookup {
+ struct i2c_board_info *info;
+ acpi_handle adapter_handle;
+ acpi_handle device_handle;
+};
+
+static int acpi_i2c_find_address(struct acpi_resource *ares, void *data)
{
- struct i2c_board_info *info = data;
+ struct acpi_i2c_lookup *lookup = data;
+ struct i2c_board_info *info = lookup->info;
+ struct acpi_resource_i2c_serialbus *sb;
+ acpi_handle adapter_handle;
+ acpi_status status;
- if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
- struct acpi_resource_i2c_serialbus *sb;
+ if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
- sb = &ares->data.i2c_serial_bus;
- if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
- info->addr = sb->slave_address;
- if (sb->access_mode == ACPI_I2C_10BIT_MODE)
- info->flags |= I2C_CLIENT_TEN;
- }
- } else if (!info->irq) {
- struct resource r;
+ sb = &ares->data.i2c_serial_bus;
+ if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
+ return 1;
- if (acpi_dev_resource_interrupt(ares, 0, &r))
- info->irq = r.start;
+ /*
+ * Extract the ResourceSource and make sure that the handle matches
+ * with the I2C adapter handle.
+ */
+ status = acpi_get_handle(lookup->device_handle,
+ sb->resource_source.string_ptr,
+ &adapter_handle);
+ if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) {
+ info->addr = sb->slave_address;
+ if (sb->access_mode == ACPI_I2C_10BIT_MODE)
+ info->flags |= I2C_CLIENT_TEN;
}
- /* Tell the ACPI core to skip this resource */
return 1;
}
@@ -128,6 +141,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
{
struct i2c_adapter *adapter = data;
struct list_head resource_list;
+ struct acpi_i2c_lookup lookup;
+ struct resource_entry *entry;
struct i2c_board_info info;
struct acpi_device *adev;
int ret;
@@ -140,14 +155,37 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
memset(&info, 0, sizeof(info));
info.fwnode = acpi_fwnode_handle(adev);
+ memset(&lookup, 0, sizeof(lookup));
+ lookup.adapter_handle = ACPI_HANDLE(&adapter->dev);
+ lookup.device_handle = handle;
+ lookup.info = &info;
+
+ /*
+ * Look up for I2cSerialBus resource with ResourceSource that
+ * matches with this adapter.
+ */
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list,
- acpi_i2c_add_resource, &info);
+ acpi_i2c_find_address, &lookup);
acpi_dev_free_resource_list(&resource_list);
if (ret < 0 || !info.addr)
return AE_OK;
+ /* Then fill IRQ number if any */
+ ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
+ if (ret < 0)
+ return AE_OK;
+
+ resource_list_for_each_entry(entry, &resource_list) {
+ if (resource_type(entry->res) == IORESOURCE_IRQ) {
+ info.irq = entry->res->start;
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&resource_list);
+
adev->power.flags.ignore_parent = true;
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
if (!i2c_new_device(adapter, &info)) {
@@ -160,6 +198,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
return AE_OK;
}
+#define ACPI_I2C_MAX_SCAN_DEPTH 32
+
/**
* acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
* @adap: pointer to adapter
@@ -170,17 +210,13 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
*/
static void acpi_i2c_register_devices(struct i2c_adapter *adap)
{
- acpi_handle handle;
acpi_status status;
- if (!adap->dev.parent)
- return;
-
- handle = ACPI_HANDLE(adap->dev.parent);
- if (!handle)
+ if (!has_acpi_companion(&adap->dev))
return;
- status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_I2C_MAX_SCAN_DEPTH,
acpi_i2c_add_device, NULL,
adap, NULL);
if (ACPI_FAILURE(status))
@@ -679,7 +715,7 @@ static int i2c_device_probe(struct device *dev)
if (wakeirq > 0 && wakeirq != client->irq)
status = dev_pm_set_dedicated_wake_irq(dev, wakeirq);
else if (client->irq > 0)
- status = dev_pm_set_wake_irq(dev, wakeirq);
+ status = dev_pm_set_wake_irq(dev, client->irq);
else
status = 0;
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 71c7a39..2413ec9 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -235,7 +235,7 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
return result;
}
-static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
+static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client,
unsigned long arg)
{
struct i2c_rdwr_ioctl_data rdwr_arg;
@@ -250,7 +250,7 @@ static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
/* Put an arbitrary limit on the number of messages that can
* be sent at once */
- if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+ if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL;
rdwr_pa = memdup_user(rdwr_arg.msgs,
@@ -421,16 +421,6 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case I2C_SLAVE:
case I2C_SLAVE_FORCE:
- /* NOTE: devices set up to work with "new style" drivers
- * can't use I2C_SLAVE, even when the device node is not
- * bound to a driver. Only I2C_SLAVE_FORCE will work.
- *
- * Setting the PEC flag here won't affect kernel drivers,
- * which will be using the i2c_client node registered with
- * the driver model core. Likewise, when that client has
- * the PEC flag already set, the i2c-dev driver won't see
- * (or use) this setting.
- */
if ((arg > 0x3ff) ||
(((client->flags & I2C_M_TEN) == 0) && arg > 0x7f))
return -EINVAL;
@@ -446,6 +436,13 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
client->flags &= ~I2C_M_TEN;
return 0;
case I2C_PEC:
+ /*
+ * Setting the PEC flag here won't affect kernel drivers,
+ * which will be using the i2c_client node registered with
+ * the driver model core. Likewise, when that client has
+ * the PEC flag already set, the i2c-dev driver won't see
+ * (or use) this setting.
+ */
if (arg)
client->flags |= I2C_CLIENT_PEC;
else
@@ -456,7 +453,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return put_user(funcs, (unsigned long __user *)arg);
case I2C_RDWR:
- return i2cdev_ioctl_rdrw(client, arg);
+ return i2cdev_ioctl_rdwr(client, arg);
case I2C_SMBUS:
return i2cdev_ioctl_smbus(client, arg);
diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c
index 2ba7c0f..00fc5b1 100644
--- a/drivers/i2c/i2c-mux.c
+++ b/drivers/i2c/i2c-mux.c
@@ -25,6 +25,7 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/of.h>
+#include <linux/acpi.h>
/* multiplexer per channel data */
struct i2c_mux_priv {
@@ -173,6 +174,13 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,
}
}
+ /*
+ * Associate the mux channel with an ACPI node.
+ */
+ if (has_acpi_companion(mux_dev))
+ acpi_preset_companion(&priv->adap.dev, ACPI_COMPANION(mux_dev),
+ chan_id);
+
if (force_nr) {
priv->adap.nr = force_nr;
ret = i2c_add_numbered_adapter(&priv->adap);
diff --git a/drivers/iio/adc/ad7793.c b/drivers/iio/adc/ad7793.c
index eea0c79..4d960d3 100644
--- a/drivers/iio/adc/ad7793.c
+++ b/drivers/iio/adc/ad7793.c
@@ -101,7 +101,7 @@
#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */
/* ID Register Bit Designations (AD7793_REG_ID) */
-#define AD7785_ID 0xB
+#define AD7785_ID 0x3
#define AD7792_ID 0xA
#define AD7793_ID 0xB
#define AD7794_ID 0xF
diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c
index 0c4618b..c2babe5 100644
--- a/drivers/iio/adc/qcom-spmi-vadc.c
+++ b/drivers/iio/adc/qcom-spmi-vadc.c
@@ -839,8 +839,10 @@ static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
for_each_available_child_of_node(node, child) {
ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
- if (ret)
+ if (ret) {
+ of_node_put(child);
return ret;
+ }
vadc->chan_props[index] = prop;
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 599cde3..b10f629 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -106,6 +106,13 @@
#define DEFAULT_SAMPLE_TIME 1000
+/* V at 25°C of 696 mV */
+#define VF610_VTEMP25_3V0 950
+/* V at 25°C of 699 mV */
+#define VF610_VTEMP25_3V3 867
+/* Typical sensor slope coefficient at all temperatures */
+#define VF610_TEMP_SLOPE_COEFF 1840
+
enum clk_sel {
VF610_ADCIOC_BUSCLK_SET,
VF610_ADCIOC_ALTCLK_SET,
@@ -197,6 +204,8 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
adc_feature->clk_div = 8;
}
+ adck_rate = ipg_rate / adc_feature->clk_div;
+
/*
* Determine the long sample time adder value to be used based
* on the default minimum sample time provided.
@@ -221,7 +230,6 @@ static inline void vf610_adc_calculate_rates(struct vf610_adc *info)
* BCT (Base Conversion Time): fixed to 25 ADCK cycles for 12 bit mode
* LSTAdder(Long Sample Time): 3, 5, 7, 9, 13, 17, 21, 25 ADCK cycles
*/
- adck_rate = ipg_rate / info->adc_feature.clk_div;
for (i = 0; i < ARRAY_SIZE(vf610_hw_avgs); i++)
info->sample_freq_avail[i] =
adck_rate / (6 + vf610_hw_avgs[i] *
@@ -663,11 +671,13 @@ static int vf610_read_raw(struct iio_dev *indio_dev,
break;
case IIO_TEMP:
/*
- * Calculate in degree Celsius times 1000
- * Using sensor slope of 1.84 mV/°C and
- * V at 25°C of 696 mV
- */
- *val = 25000 - ((int)info->value - 864) * 1000000 / 1840;
+ * Calculate in degree Celsius times 1000
+ * Using the typical sensor slope of 1.84 mV/°C
+ * and VREFH_ADC at 3.3V, V at 25°C of 699 mV
+ */
+ *val = 25000 - ((int)info->value - VF610_VTEMP25_3V3) *
+ 1000000 / VF610_TEMP_SLOPE_COEFF;
+
break;
default:
mutex_unlock(&indio_dev->mlock);
diff --git a/drivers/iio/adc/xilinx-xadc-core.c b/drivers/iio/adc/xilinx-xadc-core.c
index 0370624..02e636a 100644
--- a/drivers/iio/adc/xilinx-xadc-core.c
+++ b/drivers/iio/adc/xilinx-xadc-core.c
@@ -841,6 +841,7 @@ static int xadc_read_raw(struct iio_dev *indio_dev,
case XADC_REG_VCCINT:
case XADC_REG_VCCAUX:
case XADC_REG_VREFP:
+ case XADC_REG_VREFN:
case XADC_REG_VCCBRAM:
case XADC_REG_VCCPINT:
case XADC_REG_VCCPAUX:
diff --git a/drivers/iio/dac/ad5064.c b/drivers/iio/dac/ad5064.c
index 9e4d2c1..81ca008 100644
--- a/drivers/iio/dac/ad5064.c
+++ b/drivers/iio/dac/ad5064.c
@@ -113,12 +113,16 @@ enum ad5064_type {
ID_AD5065,
ID_AD5628_1,
ID_AD5628_2,
+ ID_AD5629_1,
+ ID_AD5629_2,
ID_AD5648_1,
ID_AD5648_2,
ID_AD5666_1,
ID_AD5666_2,
ID_AD5668_1,
ID_AD5668_2,
+ ID_AD5669_1,
+ ID_AD5669_2,
};
static int ad5064_write(struct ad5064_state *st, unsigned int cmd,
@@ -291,7 +295,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
{ },
};
-#define AD5064_CHANNEL(chan, addr, bits) { \
+#define AD5064_CHANNEL(chan, addr, bits, _shift) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
@@ -303,36 +307,39 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info[] = {
.sign = 'u', \
.realbits = (bits), \
.storagebits = 16, \
- .shift = 20 - bits, \
+ .shift = (_shift), \
}, \
.ext_info = ad5064_ext_info, \
}
-#define DECLARE_AD5064_CHANNELS(name, bits) \
+#define DECLARE_AD5064_CHANNELS(name, bits, shift) \
const struct iio_chan_spec name[] = { \
- AD5064_CHANNEL(0, 0, bits), \
- AD5064_CHANNEL(1, 1, bits), \
- AD5064_CHANNEL(2, 2, bits), \
- AD5064_CHANNEL(3, 3, bits), \
- AD5064_CHANNEL(4, 4, bits), \
- AD5064_CHANNEL(5, 5, bits), \
- AD5064_CHANNEL(6, 6, bits), \
- AD5064_CHANNEL(7, 7, bits), \
+ AD5064_CHANNEL(0, 0, bits, shift), \
+ AD5064_CHANNEL(1, 1, bits, shift), \
+ AD5064_CHANNEL(2, 2, bits, shift), \
+ AD5064_CHANNEL(3, 3, bits, shift), \
+ AD5064_CHANNEL(4, 4, bits, shift), \
+ AD5064_CHANNEL(5, 5, bits, shift), \
+ AD5064_CHANNEL(6, 6, bits, shift), \
+ AD5064_CHANNEL(7, 7, bits, shift), \
}
-#define DECLARE_AD5065_CHANNELS(name, bits) \
+#define DECLARE_AD5065_CHANNELS(name, bits, shift) \
const struct iio_chan_spec name[] = { \
- AD5064_CHANNEL(0, 0, bits), \
- AD5064_CHANNEL(1, 3, bits), \
+ AD5064_CHANNEL(0, 0, bits, shift), \
+ AD5064_CHANNEL(1, 3, bits, shift), \
}
-static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
-static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
-static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
+static DECLARE_AD5064_CHANNELS(ad5024_channels, 12, 8);
+static DECLARE_AD5064_CHANNELS(ad5044_channels, 14, 6);
+static DECLARE_AD5064_CHANNELS(ad5064_channels, 16, 4);
-static DECLARE_AD5065_CHANNELS(ad5025_channels, 12);
-static DECLARE_AD5065_CHANNELS(ad5045_channels, 14);
-static DECLARE_AD5065_CHANNELS(ad5065_channels, 16);
+static DECLARE_AD5065_CHANNELS(ad5025_channels, 12, 8);
+static DECLARE_AD5065_CHANNELS(ad5045_channels, 14, 6);
+static DECLARE_AD5065_CHANNELS(ad5065_channels, 16, 4);
+
+static DECLARE_AD5064_CHANNELS(ad5629_channels, 12, 4);
+static DECLARE_AD5064_CHANNELS(ad5669_channels, 16, 0);
static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
[ID_AD5024] = {
@@ -382,6 +389,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
.channels = ad5024_channels,
.num_channels = 8,
},
+ [ID_AD5629_1] = {
+ .shared_vref = true,
+ .internal_vref = 2500000,
+ .channels = ad5629_channels,
+ .num_channels = 8,
+ },
+ [ID_AD5629_2] = {
+ .shared_vref = true,
+ .internal_vref = 5000000,
+ .channels = ad5629_channels,
+ .num_channels = 8,
+ },
[ID_AD5648_1] = {
.shared_vref = true,
.internal_vref = 2500000,
@@ -418,6 +437,18 @@ static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
.channels = ad5064_channels,
.num_channels = 8,
},
+ [ID_AD5669_1] = {
+ .shared_vref = true,
+ .internal_vref = 2500000,
+ .channels = ad5669_channels,
+ .num_channels = 8,
+ },
+ [ID_AD5669_2] = {
+ .shared_vref = true,
+ .internal_vref = 5000000,
+ .channels = ad5669_channels,
+ .num_channels = 8,
+ },
};
static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
@@ -597,10 +628,16 @@ static int ad5064_i2c_write(struct ad5064_state *st, unsigned int cmd,
unsigned int addr, unsigned int val)
{
struct i2c_client *i2c = to_i2c_client(st->dev);
+ int ret;
st->data.i2c[0] = (cmd << 4) | addr;
put_unaligned_be16(val, &st->data.i2c[1]);
- return i2c_master_send(i2c, st->data.i2c, 3);
+
+ ret = i2c_master_send(i2c, st->data.i2c, 3);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static int ad5064_i2c_probe(struct i2c_client *i2c,
@@ -616,12 +653,12 @@ static int ad5064_i2c_remove(struct i2c_client *i2c)
}
static const struct i2c_device_id ad5064_i2c_ids[] = {
- {"ad5629-1", ID_AD5628_1},
- {"ad5629-2", ID_AD5628_2},
- {"ad5629-3", ID_AD5628_2}, /* similar enough to ad5629-2 */
- {"ad5669-1", ID_AD5668_1},
- {"ad5669-2", ID_AD5668_2},
- {"ad5669-3", ID_AD5668_2}, /* similar enough to ad5669-2 */
+ {"ad5629-1", ID_AD5629_1},
+ {"ad5629-2", ID_AD5629_2},
+ {"ad5629-3", ID_AD5629_2}, /* similar enough to ad5629-2 */
+ {"ad5669-1", ID_AD5669_1},
+ {"ad5669-2", ID_AD5669_2},
+ {"ad5669-3", ID_AD5669_2}, /* similar enough to ad5669-2 */
{}
};
MODULE_DEVICE_TABLE(i2c, ad5064_i2c_ids);
diff --git a/drivers/iio/humidity/si7020.c b/drivers/iio/humidity/si7020.c
index 12128d1..71991b5 100644
--- a/drivers/iio/humidity/si7020.c
+++ b/drivers/iio/humidity/si7020.c
@@ -50,10 +50,10 @@ static int si7020_read_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- ret = i2c_smbus_read_word_data(*client,
- chan->type == IIO_TEMP ?
- SI7020CMD_TEMP_HOLD :
- SI7020CMD_RH_HOLD);
+ ret = i2c_smbus_read_word_swapped(*client,
+ chan->type == IIO_TEMP ?
+ SI7020CMD_TEMP_HOLD :
+ SI7020CMD_RH_HOLD);
if (ret < 0)
return ret;
*val = ret >> 2;
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index d7e908a..0f6f63b 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -302,7 +302,7 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
if (trialmask == NULL)
return -ENOMEM;
if (!indio_dev->masklength) {
- WARN_ON("Trying to set scanmask prior to registering buffer\n");
+ WARN(1, "Trying to set scanmask prior to registering buffer\n");
goto err_invalid_mask;
}
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 208358f..159ede6 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -655,7 +655,7 @@ int __iio_device_attr_init(struct device_attribute *dev_attr,
break;
case IIO_SEPARATE:
if (!chan->indexed) {
- WARN_ON("Differential channels must be indexed\n");
+ WARN(1, "Differential channels must be indexed\n");
ret = -EINVAL;
goto error_free_full_postfix;
}
diff --git a/drivers/iio/light/apds9960.c b/drivers/iio/light/apds9960.c
index 7d269ef..f6a07dc 100644
--- a/drivers/iio/light/apds9960.c
+++ b/drivers/iio/light/apds9960.c
@@ -453,6 +453,7 @@ static int apds9960_set_power_state(struct apds9960_data *data, bool on)
usleep_range(data->als_adc_int_us,
APDS9960_MAX_INT_TIME_IN_US);
} else {
+ pm_runtime_mark_last_busy(dev);
ret = pm_runtime_put_autosuspend(dev);
}
diff --git a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
index 961f9f99..e544fcf 100644
--- a/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
+++ b/drivers/iio/proximity/pulsedlight-lidar-lite-v2.c
@@ -130,10 +130,10 @@ static int lidar_get_measurement(struct lidar_data *data, u16 *reg)
if (ret < 0)
break;
- /* return 0 since laser is likely pointed out of range */
+ /* return -EINVAL since laser is likely pointed out of range */
if (ret & LIDAR_REG_STATUS_INVALID) {
*reg = 0;
- ret = 0;
+ ret = -EINVAL;
break;
}
@@ -197,7 +197,7 @@ static irqreturn_t lidar_trigger_handler(int irq, void *private)
if (!ret) {
iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
iio_get_time_ns());
- } else {
+ } else if (ret != -EINVAL) {
dev_err(&data->client->dev, "cannot read LIDAR measurement");
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 944cd90..2d762a2 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -1126,10 +1126,7 @@ static bool validate_ipv4_net_dev(struct net_device *net_dev,
rcu_read_lock();
err = fib_lookup(dev_net(net_dev), &fl4, &res, 0);
- if (err)
- return false;
-
- ret = FIB_RES_DEV(res) == net_dev;
+ ret = err == 0 && FIB_RES_DEV(res) == net_dev;
rcu_read_unlock();
return ret;
@@ -1268,15 +1265,17 @@ static bool cma_protocol_roce(const struct rdma_cm_id *id)
return cma_protocol_roce_dev_port(device, port_num);
}
-static bool cma_match_net_dev(const struct rdma_id_private *id_priv,
- const struct net_device *net_dev)
+static bool cma_match_net_dev(const struct rdma_cm_id *id,
+ const struct net_device *net_dev,
+ u8 port_num)
{
- const struct rdma_addr *addr = &id_priv->id.route.addr;
+ const struct rdma_addr *addr = &id->route.addr;
if (!net_dev)
/* This request is an AF_IB request or a RoCE request */
- return addr->src_addr.ss_family == AF_IB ||
- cma_protocol_roce(&id_priv->id);
+ return (!id->port_num || id->port_num == port_num) &&
+ (addr->src_addr.ss_family == AF_IB ||
+ cma_protocol_roce_dev_port(id->device, port_num));
return !addr->dev_addr.bound_dev_if ||
(net_eq(dev_net(net_dev), addr->dev_addr.net) &&
@@ -1298,13 +1297,13 @@ static struct rdma_id_private *cma_find_listener(
hlist_for_each_entry(id_priv, &bind_list->owners, node) {
if (cma_match_private_data(id_priv, ib_event->private_data)) {
if (id_priv->id.device == cm_id->device &&
- cma_match_net_dev(id_priv, net_dev))
+ cma_match_net_dev(&id_priv->id, net_dev, req->port))
return id_priv;
list_for_each_entry(id_priv_dev,
&id_priv->listen_list,
listen_list) {
if (id_priv_dev->id.device == cm_id->device &&
- cma_match_net_dev(id_priv_dev, net_dev))
+ cma_match_net_dev(&id_priv_dev->id, net_dev, req->port))
return id_priv_dev;
}
}
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 8d8af7a..2281de1 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -1811,6 +1811,11 @@ static int validate_mad(const struct ib_mad_hdr *mad_hdr,
if (qp_num == 0)
valid = 1;
} else {
+ /* CM attributes other than ClassPortInfo only use Send method */
+ if ((mad_hdr->mgmt_class == IB_MGMT_CLASS_CM) &&
+ (mad_hdr->attr_id != IB_MGMT_CLASSPORTINFO_ATTR_ID) &&
+ (mad_hdr->method != IB_MGMT_METHOD_SEND))
+ goto out;
/* Filter GSI packets sent to QP0 */
if (qp_num != 0)
valid = 1;
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 2aba774..a95a32b 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -512,7 +512,7 @@ static int ib_nl_get_path_rec_attrs_len(ib_sa_comp_mask comp_mask)
return len;
}
-static int ib_nl_send_msg(struct ib_sa_query *query)
+static int ib_nl_send_msg(struct ib_sa_query *query, gfp_t gfp_mask)
{
struct sk_buff *skb = NULL;
struct nlmsghdr *nlh;
@@ -526,7 +526,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
if (len <= 0)
return -EMSGSIZE;
- skb = nlmsg_new(len, GFP_KERNEL);
+ skb = nlmsg_new(len, gfp_mask);
if (!skb)
return -ENOMEM;
@@ -544,7 +544,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
/* Repair the nlmsg header length */
nlmsg_end(skb, nlh);
- ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL);
+ ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, gfp_mask);
if (!ret)
ret = len;
else
@@ -553,7 +553,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query)
return ret;
}
-static int ib_nl_make_request(struct ib_sa_query *query)
+static int ib_nl_make_request(struct ib_sa_query *query, gfp_t gfp_mask)
{
unsigned long flags;
unsigned long delay;
@@ -562,25 +562,27 @@ static int ib_nl_make_request(struct ib_sa_query *query)
INIT_LIST_HEAD(&query->list);
query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq);
+ /* Put the request on the list first.*/
spin_lock_irqsave(&ib_nl_request_lock, flags);
- ret = ib_nl_send_msg(query);
- if (ret <= 0) {
- ret = -EIO;
- goto request_out;
- } else {
- ret = 0;
- }
-
delay = msecs_to_jiffies(sa_local_svc_timeout_ms);
query->timeout = delay + jiffies;
list_add_tail(&query->list, &ib_nl_request_list);
/* Start the timeout if this is the only request */
if (ib_nl_request_list.next == &query->list)
queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay);
-
-request_out:
spin_unlock_irqrestore(&ib_nl_request_lock, flags);
+ ret = ib_nl_send_msg(query, gfp_mask);
+ if (ret <= 0) {
+ ret = -EIO;
+ /* Remove the request */
+ spin_lock_irqsave(&ib_nl_request_lock, flags);
+ list_del(&query->list);
+ spin_unlock_irqrestore(&ib_nl_request_lock, flags);
+ } else {
+ ret = 0;
+ }
+
return ret;
}
@@ -1108,7 +1110,7 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask)
if (query->flags & IB_SA_ENABLE_LOCAL_SERVICE) {
if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) {
- if (!ib_nl_make_request(query))
+ if (!ib_nl_make_request(query, gfp_mask))
return id;
}
ib_sa_disable_local_svc(query);
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 94816ae..1c02dea 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -62,9 +62,11 @@ static struct uverbs_lock_class rule_lock_class = { .name = "RULE-uobj" };
* The ib_uobject locking scheme is as follows:
*
* - ib_uverbs_idr_lock protects the uverbs idrs themselves, so it
- * needs to be held during all idr operations. When an object is
+ * needs to be held during all idr write operations. When an object is
* looked up, a reference must be taken on the object's kref before
- * dropping this lock.
+ * dropping this lock. For read operations, the rcu_read_lock()
+ * and rcu_write_lock() but similarly the kref reference is grabbed
+ * before the rcu_read_unlock().
*
* - Each object also has an rwsem. This rwsem must be held for
* reading while an operation that uses the object is performed.
@@ -96,7 +98,7 @@ static void init_uobj(struct ib_uobject *uobj, u64 user_handle,
static void release_uobj(struct kref *kref)
{
- kfree(container_of(kref, struct ib_uobject, ref));
+ kfree_rcu(container_of(kref, struct ib_uobject, ref), rcu);
}
static void put_uobj(struct ib_uobject *uobj)
@@ -145,7 +147,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
{
struct ib_uobject *uobj;
- spin_lock(&ib_uverbs_idr_lock);
+ rcu_read_lock();
uobj = idr_find(idr, id);
if (uobj) {
if (uobj->context == context)
@@ -153,7 +155,7 @@ static struct ib_uobject *__idr_get_uobj(struct idr *idr, int id,
else
uobj = NULL;
}
- spin_unlock(&ib_uverbs_idr_lock);
+ rcu_read_unlock();
return uobj;
}
@@ -2446,6 +2448,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
int i, sg_ind;
int is_ud;
ssize_t ret = -EINVAL;
+ size_t next_size;
if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT;
@@ -2490,7 +2493,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
goto out_put;
}
- ud = alloc_wr(sizeof(*ud), user_wr->num_sge);
+ next_size = sizeof(*ud);
+ ud = alloc_wr(next_size, user_wr->num_sge);
if (!ud) {
ret = -ENOMEM;
goto out_put;
@@ -2511,7 +2515,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
user_wr->opcode == IB_WR_RDMA_READ) {
struct ib_rdma_wr *rdma;
- rdma = alloc_wr(sizeof(*rdma), user_wr->num_sge);
+ next_size = sizeof(*rdma);
+ rdma = alloc_wr(next_size, user_wr->num_sge);
if (!rdma) {
ret = -ENOMEM;
goto out_put;
@@ -2525,7 +2530,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
user_wr->opcode == IB_WR_ATOMIC_FETCH_AND_ADD) {
struct ib_atomic_wr *atomic;
- atomic = alloc_wr(sizeof(*atomic), user_wr->num_sge);
+ next_size = sizeof(*atomic);
+ atomic = alloc_wr(next_size, user_wr->num_sge);
if (!atomic) {
ret = -ENOMEM;
goto out_put;
@@ -2540,7 +2546,8 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
} else if (user_wr->opcode == IB_WR_SEND ||
user_wr->opcode == IB_WR_SEND_WITH_IMM ||
user_wr->opcode == IB_WR_SEND_WITH_INV) {
- next = alloc_wr(sizeof(*next), user_wr->num_sge);
+ next_size = sizeof(*next);
+ next = alloc_wr(next_size, user_wr->num_sge);
if (!next) {
ret = -ENOMEM;
goto out_put;
@@ -2572,7 +2579,7 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file,
if (next->num_sge) {
next->sg_list = (void *) next +
- ALIGN(sizeof *next, sizeof (struct ib_sge));
+ ALIGN(next_size, sizeof(struct ib_sge));
if (copy_from_user(next->sg_list,
buf + sizeof cmd +
cmd.wr_count * cmd.wqe_size +
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 043a60e..545906d 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -1516,7 +1516,7 @@ EXPORT_SYMBOL(ib_map_mr_sg);
* @sg_nents: number of entries in sg
* @set_page: driver page assignment function pointer
*
- * Core service helper for drivers to covert the largest
+ * Core service helper for drivers to convert the largest
* prefix of given sg list to a page vector. The sg list
* prefix converted is the prefix that meet the requirements
* of ib_map_mr_sg.
@@ -1533,7 +1533,7 @@ int ib_sg_to_pages(struct ib_mr *mr,
u64 last_end_dma_addr = 0, last_page_addr = 0;
unsigned int last_page_off = 0;
u64 page_mask = ~((u64)mr->page_size - 1);
- int i;
+ int i, ret;
mr->iova = sg_dma_address(&sgl[0]);
mr->length = 0;
@@ -1544,27 +1544,29 @@ int ib_sg_to_pages(struct ib_mr *mr,
u64 end_dma_addr = dma_addr + dma_len;
u64 page_addr = dma_addr & page_mask;
- if (i && page_addr != dma_addr) {
- if (last_end_dma_addr != dma_addr) {
- /* gap */
- goto done;
-
- } else if (last_page_off + dma_len <= mr->page_size) {
- /* chunk this fragment with the last */
- mr->length += dma_len;
- last_end_dma_addr += dma_len;
- last_page_off += dma_len;
- continue;
- } else {
- /* map starting from the next page */
- page_addr = last_page_addr + mr->page_size;
- dma_len -= mr->page_size - last_page_off;
- }
+ /*
+ * For the second and later elements, check whether either the
+ * end of element i-1 or the start of element i is not aligned
+ * on a page boundary.
+ */
+ if (i && (last_page_off != 0 || page_addr != dma_addr)) {
+ /* Stop mapping if there is a gap. */
+ if (last_end_dma_addr != dma_addr)
+ break;
+
+ /*
+ * Coalesce this element with the last. If it is small
+ * enough just update mr->length. Otherwise start
+ * mapping from the next page.
+ */
+ goto next_page;
}
do {
- if (unlikely(set_page(mr, page_addr)))
- goto done;
+ ret = set_page(mr, page_addr);
+ if (unlikely(ret < 0))
+ return i ? : ret;
+next_page:
page_addr += mr->page_size;
} while (page_addr < end_dma_addr);
@@ -1574,7 +1576,6 @@ int ib_sg_to_pages(struct ib_mr *mr,
last_page_off = end_dma_addr & ~page_mask;
}
-done:
return i;
}
EXPORT_SYMBOL(ib_sg_to_pages);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index f567160..97d6878 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -456,7 +456,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE;
props->max_sge = min(dev->dev->caps.max_sq_sg,
dev->dev->caps.max_rq_sg);
- props->max_sge_rd = props->max_sge;
+ props->max_sge_rd = MLX4_MAX_SGE_RD;
props->max_cq = dev->dev->quotas.cq;
props->max_cqe = dev->dev->caps.max_cqes;
props->max_mr = dev->dev->quotas.mpt;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index a2e4ca5..13eaaf4 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -34,6 +34,7 @@
#include <linux/log2.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
+#include <linux/vmalloc.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_pack.h>
@@ -795,8 +796,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
if (err)
goto err_mtt;
- qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof (u64), gfp);
- qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof (u64), gfp);
+ qp->sq.wrid = kmalloc(qp->sq.wqe_cnt * sizeof(u64), gfp);
+ if (!qp->sq.wrid)
+ qp->sq.wrid = __vmalloc(qp->sq.wqe_cnt * sizeof(u64),
+ gfp, PAGE_KERNEL);
+ qp->rq.wrid = kmalloc(qp->rq.wqe_cnt * sizeof(u64), gfp);
+ if (!qp->rq.wrid)
+ qp->rq.wrid = __vmalloc(qp->rq.wqe_cnt * sizeof(u64),
+ gfp, PAGE_KERNEL);
if (!qp->sq.wrid || !qp->rq.wrid) {
err = -ENOMEM;
goto err_wrid;
@@ -886,8 +893,8 @@ err_wrid:
if (qp_has_rq(init_attr))
mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &qp->db);
} else {
- kfree(qp->sq.wrid);
- kfree(qp->rq.wrid);
+ kvfree(qp->sq.wrid);
+ kvfree(qp->rq.wrid);
}
err_mtt:
@@ -1062,8 +1069,8 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
&qp->db);
ib_umem_release(qp->umem);
} else {
- kfree(qp->sq.wrid);
- kfree(qp->rq.wrid);
+ kvfree(qp->sq.wrid);
+ kvfree(qp->rq.wrid);
if (qp->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER |
MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI))
free_proxy_bufs(&dev->ib_dev, qp);
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index dce5dfe..c394376 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -34,6 +34,7 @@
#include <linux/mlx4/qp.h>
#include <linux/mlx4/srq.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include "mlx4_ib.h"
#include "user.h"
@@ -172,8 +173,12 @@ struct ib_srq *mlx4_ib_create_srq(struct ib_pd *pd,
srq->wrid = kmalloc(srq->msrq.max * sizeof (u64), GFP_KERNEL);
if (!srq->wrid) {
- err = -ENOMEM;
- goto err_mtt;
+ srq->wrid = __vmalloc(srq->msrq.max * sizeof(u64),
+ GFP_KERNEL, PAGE_KERNEL);
+ if (!srq->wrid) {
+ err = -ENOMEM;
+ goto err_mtt;
+ }
}
}
@@ -204,7 +209,7 @@ err_wrid:
if (pd->uobject)
mlx4_ib_db_unmap_user(to_mucontext(pd->uobject->context), &srq->db);
else
- kfree(srq->wrid);
+ kvfree(srq->wrid);
err_mtt:
mlx4_mtt_cleanup(dev->dev, &srq->mtt);
@@ -281,7 +286,7 @@ int mlx4_ib_destroy_srq(struct ib_srq *srq)
mlx4_ib_db_unmap_user(to_mucontext(srq->uobject->context), &msrq->db);
ib_umem_release(msrq->umem);
} else {
- kfree(msrq->wrid);
+ kvfree(msrq->wrid);
mlx4_buf_free(dev->dev, msrq->msrq.max << msrq->msrq.wqe_shift,
&msrq->buf);
mlx4_db_free(dev->dev, &msrq->db);
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index ec8993a..6000f7a 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -381,7 +381,19 @@ static void __cache_work_func(struct mlx5_cache_ent *ent)
}
}
} else if (ent->cur > 2 * ent->limit) {
- if (!someone_adding(cache) &&
+ /*
+ * The remove_keys() logic is performed as garbage collection
+ * task. Such task is intended to be run when no other active
+ * processes are running.
+ *
+ * The need_resched() will return TRUE if there are user tasks
+ * to be activated in near future.
+ *
+ * In such case, we don't execute remove_keys() and postpone
+ * the garbage collection work to try to run in next cycle,
+ * in order to free CPU resources to other tasks.
+ */
+ if (!need_resched() && !someone_adding(cache) &&
time_after(jiffies, cache->last_add + 300 * HZ)) {
remove_keys(dev, i, 1);
if (ent->cur > ent->limit)
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index ae80590..040bb8b 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -232,6 +232,10 @@ struct phy_info {
u16 interface_type;
};
+enum ocrdma_flags {
+ OCRDMA_FLAGS_LINK_STATUS_INIT = 0x01
+};
+
struct ocrdma_dev {
struct ib_device ibdev;
struct ocrdma_dev_attr attr;
@@ -287,6 +291,7 @@ struct ocrdma_dev {
atomic_t update_sl;
u16 pvid;
u32 asic_id;
+ u32 flags;
ulong last_stats_time;
struct mutex stats_lock; /* provide synch for debugfs operations */
@@ -591,4 +596,9 @@ static inline u8 ocrdma_is_enabled_and_synced(u32 state)
(state & OCRDMA_STATE_FLAG_SYNC);
}
+static inline u8 ocrdma_get_ae_link_state(u32 ae_state)
+{
+ return ((ae_state & OCRDMA_AE_LSC_LS_MASK) >> OCRDMA_AE_LSC_LS_SHIFT);
+}
+
#endif
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 30f67be..283ca84 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -579,6 +579,8 @@ static int ocrdma_mbx_create_mq(struct ocrdma_dev *dev,
cmd->async_event_bitmap = BIT(OCRDMA_ASYNC_GRP5_EVE_CODE);
cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_RDMA_EVE_CODE);
+ /* Request link events on this MQ. */
+ cmd->async_event_bitmap |= BIT(OCRDMA_ASYNC_LINK_EVE_CODE);
cmd->async_cqid_ringsize = cq->id;
cmd->async_cqid_ringsize |= (ocrdma_encoded_q_len(mq->len) <<
@@ -819,20 +821,42 @@ static void ocrdma_process_grp5_aync(struct ocrdma_dev *dev,
}
}
+static void ocrdma_process_link_state(struct ocrdma_dev *dev,
+ struct ocrdma_ae_mcqe *cqe)
+{
+ struct ocrdma_ae_lnkst_mcqe *evt;
+ u8 lstate;
+
+ evt = (struct ocrdma_ae_lnkst_mcqe *)cqe;
+ lstate = ocrdma_get_ae_link_state(evt->speed_state_ptn);
+
+ if (!(lstate & OCRDMA_AE_LSC_LLINK_MASK))
+ return;
+
+ if (dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)
+ ocrdma_update_link_state(dev, (lstate & OCRDMA_LINK_ST_MASK));
+}
+
static void ocrdma_process_acqe(struct ocrdma_dev *dev, void *ae_cqe)
{
/* async CQE processing */
struct ocrdma_ae_mcqe *cqe = ae_cqe;
u32 evt_code = (cqe->valid_ae_event & OCRDMA_AE_MCQE_EVENT_CODE_MASK) >>
OCRDMA_AE_MCQE_EVENT_CODE_SHIFT;
-
- if (evt_code == OCRDMA_ASYNC_RDMA_EVE_CODE)
+ switch (evt_code) {
+ case OCRDMA_ASYNC_LINK_EVE_CODE:
+ ocrdma_process_link_state(dev, cqe);
+ break;
+ case OCRDMA_ASYNC_RDMA_EVE_CODE:
ocrdma_dispatch_ibevent(dev, cqe);
- else if (evt_code == OCRDMA_ASYNC_GRP5_EVE_CODE)
+ break;
+ case OCRDMA_ASYNC_GRP5_EVE_CODE:
ocrdma_process_grp5_aync(dev, cqe);
- else
+ break;
+ default:
pr_err("%s(%d) invalid evt code=0x%x\n", __func__,
dev->id, evt_code);
+ }
}
static void ocrdma_process_mcqe(struct ocrdma_dev *dev, struct ocrdma_mcqe *cqe)
@@ -1363,7 +1387,8 @@ mbx_err:
return status;
}
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+ u8 *lnk_state)
{
int status = -ENOMEM;
struct ocrdma_get_link_speed_rsp *rsp;
@@ -1384,8 +1409,11 @@ int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed)
goto mbx_err;
rsp = (struct ocrdma_get_link_speed_rsp *)cmd;
- *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
- >> OCRDMA_PHY_PS_SHIFT;
+ if (lnk_speed)
+ *lnk_speed = (rsp->pflt_pps_ld_pnum & OCRDMA_PHY_PS_MASK)
+ >> OCRDMA_PHY_PS_SHIFT;
+ if (lnk_state)
+ *lnk_state = (rsp->res_lnk_st & OCRDMA_LINK_ST_MASK);
mbx_err:
kfree(cmd);
@@ -2515,9 +2543,10 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
ocrdma_cpu_to_le32(&cmd->params.sgid[0], sizeof(cmd->params.sgid));
cmd->params.vlan_dmac_b4_to_b5 = mac_addr[4] | (mac_addr[5] << 8);
- if (vlan_id < 0x1000) {
- if (dev->pfc_state) {
- vlan_id = 0;
+ if (vlan_id == 0xFFFF)
+ vlan_id = 0;
+ if (vlan_id || dev->pfc_state) {
+ if (!vlan_id) {
pr_err("ocrdma%d:Using VLAN with PFC is recommended\n",
dev->id);
pr_err("ocrdma%d:Using VLAN 0 for this connection\n",
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 7ed885c..ebc1f44 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -106,7 +106,8 @@ void ocrdma_ring_cq_db(struct ocrdma_dev *, u16 cq_id, bool armed,
bool solicited, u16 cqe_popped);
/* verbs specific mailbox commands */
-int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed);
+int ocrdma_mbx_get_link_speed(struct ocrdma_dev *dev, u8 *lnk_speed,
+ u8 *lnk_st);
int ocrdma_query_config(struct ocrdma_dev *,
struct ocrdma_mbx_query_config *config);
@@ -153,5 +154,6 @@ char *port_speed_string(struct ocrdma_dev *dev);
void ocrdma_init_service_level(struct ocrdma_dev *);
void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
void ocrdma_free_pd_range(struct ocrdma_dev *dev);
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate);
#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index 62b7009..3afb40b 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -290,6 +290,7 @@ static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev)
static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
{
int status = 0, i;
+ u8 lstate = 0;
struct ocrdma_dev *dev;
dev = (struct ocrdma_dev *)ib_alloc_device(sizeof(struct ocrdma_dev));
@@ -319,6 +320,11 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
if (status)
goto alloc_err;
+ /* Query Link state and update */
+ status = ocrdma_mbx_get_link_speed(dev, NULL, &lstate);
+ if (!status)
+ ocrdma_update_link_state(dev, lstate);
+
for (i = 0; i < ARRAY_SIZE(ocrdma_attributes); i++)
if (device_create_file(&dev->ibdev.dev, ocrdma_attributes[i]))
goto sysfs_err;
@@ -373,7 +379,7 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
ocrdma_remove_free(dev);
}
-static int ocrdma_open(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_active(struct ocrdma_dev *dev)
{
struct ib_event port_event;
@@ -384,32 +390,9 @@ static int ocrdma_open(struct ocrdma_dev *dev)
return 0;
}
-static int ocrdma_close(struct ocrdma_dev *dev)
+static int ocrdma_dispatch_port_error(struct ocrdma_dev *dev)
{
- int i;
- struct ocrdma_qp *qp, **cur_qp;
struct ib_event err_event;
- struct ib_qp_attr attrs;
- int attr_mask = IB_QP_STATE;
-
- attrs.qp_state = IB_QPS_ERR;
- mutex_lock(&dev->dev_lock);
- if (dev->qp_tbl) {
- cur_qp = dev->qp_tbl;
- for (i = 0; i < OCRDMA_MAX_QP; i++) {
- qp = cur_qp[i];
- if (qp && qp->ibqp.qp_type != IB_QPT_GSI) {
- /* change the QP state to ERROR */
- _ocrdma_modify_qp(&qp->ibqp, &attrs, attr_mask);
-
- err_event.event = IB_EVENT_QP_FATAL;
- err_event.element.qp = &qp->ibqp;
- err_event.device = &dev->ibdev;
- ib_dispatch_event(&err_event);
- }
- }
- }
- mutex_unlock(&dev->dev_lock);
err_event.event = IB_EVENT_PORT_ERR;
err_event.element.port_num = 1;
@@ -420,7 +403,7 @@ static int ocrdma_close(struct ocrdma_dev *dev)
static void ocrdma_shutdown(struct ocrdma_dev *dev)
{
- ocrdma_close(dev);
+ ocrdma_dispatch_port_error(dev);
ocrdma_remove(dev);
}
@@ -431,18 +414,28 @@ static void ocrdma_shutdown(struct ocrdma_dev *dev)
static void ocrdma_event_handler(struct ocrdma_dev *dev, u32 event)
{
switch (event) {
- case BE_DEV_UP:
- ocrdma_open(dev);
- break;
- case BE_DEV_DOWN:
- ocrdma_close(dev);
- break;
case BE_DEV_SHUTDOWN:
ocrdma_shutdown(dev);
break;
+ default:
+ break;
}
}
+void ocrdma_update_link_state(struct ocrdma_dev *dev, u8 lstate)
+{
+ if (!(dev->flags & OCRDMA_FLAGS_LINK_STATUS_INIT)) {
+ dev->flags |= OCRDMA_FLAGS_LINK_STATUS_INIT;
+ if (!lstate)
+ return;
+ }
+
+ if (!lstate)
+ ocrdma_dispatch_port_error(dev);
+ else
+ ocrdma_dispatch_port_active(dev);
+}
+
static struct ocrdma_driver ocrdma_drv = {
.name = "ocrdma_driver",
.add = ocrdma_add,
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 6a38268..99dd6fd 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -465,8 +465,11 @@ struct ocrdma_ae_qp_mcqe {
u32 valid_ae_event;
};
-#define OCRDMA_ASYNC_RDMA_EVE_CODE 0x14
-#define OCRDMA_ASYNC_GRP5_EVE_CODE 0x5
+enum ocrdma_async_event_code {
+ OCRDMA_ASYNC_LINK_EVE_CODE = 0x01,
+ OCRDMA_ASYNC_GRP5_EVE_CODE = 0x05,
+ OCRDMA_ASYNC_RDMA_EVE_CODE = 0x14
+};
enum ocrdma_async_grp5_events {
OCRDMA_ASYNC_EVENT_QOS_VALUE = 0x01,
@@ -489,6 +492,44 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
OCRDMA_MAX_ASYNC_ERRORS
};
+struct ocrdma_ae_lnkst_mcqe {
+ u32 speed_state_ptn;
+ u32 qos_reason_falut;
+ u32 evt_tag;
+ u32 valid_ae_event;
+};
+
+enum {
+ OCRDMA_AE_LSC_PORT_NUM_MASK = 0x3F,
+ OCRDMA_AE_LSC_PT_SHIFT = 0x06,
+ OCRDMA_AE_LSC_PT_MASK = (0x03 <<
+ OCRDMA_AE_LSC_PT_SHIFT),
+ OCRDMA_AE_LSC_LS_SHIFT = 0x08,
+ OCRDMA_AE_LSC_LS_MASK = (0xFF <<
+ OCRDMA_AE_LSC_LS_SHIFT),
+ OCRDMA_AE_LSC_LD_SHIFT = 0x10,
+ OCRDMA_AE_LSC_LD_MASK = (0xFF <<
+ OCRDMA_AE_LSC_LD_SHIFT),
+ OCRDMA_AE_LSC_PPS_SHIFT = 0x18,
+ OCRDMA_AE_LSC_PPS_MASK = (0xFF <<
+ OCRDMA_AE_LSC_PPS_SHIFT),
+ OCRDMA_AE_LSC_PPF_MASK = 0xFF,
+ OCRDMA_AE_LSC_ER_SHIFT = 0x08,
+ OCRDMA_AE_LSC_ER_MASK = (0xFF <<
+ OCRDMA_AE_LSC_ER_SHIFT),
+ OCRDMA_AE_LSC_QOS_SHIFT = 0x10,
+ OCRDMA_AE_LSC_QOS_MASK = (0xFFFF <<
+ OCRDMA_AE_LSC_QOS_SHIFT)
+};
+
+enum {
+ OCRDMA_AE_LSC_PLINK_DOWN = 0x00,
+ OCRDMA_AE_LSC_PLINK_UP = 0x01,
+ OCRDMA_AE_LSC_LLINK_DOWN = 0x02,
+ OCRDMA_AE_LSC_LLINK_MASK = 0x02,
+ OCRDMA_AE_LSC_LLINK_UP = 0x03
+};
+
/* mailbox command request and responses */
enum {
OCRDMA_MBX_QUERY_CFG_CQ_OVERFLOW_SHIFT = 2,
@@ -676,7 +717,7 @@ enum {
OCRDMA_PHY_PFLT_SHIFT = 0x18,
OCRDMA_QOS_LNKSP_MASK = 0xFFFF0000,
OCRDMA_QOS_LNKSP_SHIFT = 0x10,
- OCRDMA_LLST_MASK = 0xFF,
+ OCRDMA_LINK_ST_MASK = 0x01,
OCRDMA_PLFC_MASK = 0x00000400,
OCRDMA_PLFC_SHIFT = 0x8,
OCRDMA_PLRFC_MASK = 0x00000200,
@@ -691,7 +732,7 @@ struct ocrdma_get_link_speed_rsp {
u32 pflt_pps_ld_pnum;
u32 qos_lsp;
- u32 res_lls;
+ u32 res_lnk_st;
};
enum {
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index 583001b..76e96f9 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -171,7 +171,7 @@ static inline void get_link_speed_and_width(struct ocrdma_dev *dev,
int status;
u8 speed;
- status = ocrdma_mbx_get_link_speed(dev, &speed);
+ status = ocrdma_mbx_get_link_speed(dev, &speed, NULL);
if (status)
speed = OCRDMA_PHYS_LINK_SPEED_ZERO;
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c
index 5e27f76..4c7c3c8 100644
--- a/drivers/infiniband/hw/qib/qib_qsfp.c
+++ b/drivers/infiniband/hw/qib/qib_qsfp.c
@@ -292,7 +292,7 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp)
qib_dev_porterr(ppd->dd, ppd->port,
"QSFP byte0 is 0x%02X, S/B 0x0C/D\n", peek[0]);
- if ((peek[2] & 2) == 0) {
+ if ((peek[2] & 4) == 0) {
/*
* If cable is paged, rather than "flat memory", we need to
* set the page to zero, Even if it already appears to be zero.
@@ -538,7 +538,7 @@ int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len)
sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n",
QSFP_DATE_LEN, cd.date);
sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n",
- QSFP_LOT_LEN, cd.date);
+ QSFP_LOT_LEN, cd.lot);
while (bidx < QSFP_DEFAULT_HDR_CNT) {
int iidx;
diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h
index 2baf5ad..bc803f3 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.h
+++ b/drivers/infiniband/hw/qib/qib_verbs.h
@@ -329,9 +329,9 @@ struct qib_sge {
struct qib_mr {
struct ib_mr ibmr;
struct ib_umem *umem;
- struct qib_mregion mr; /* must be last */
u64 *pages;
u32 npages;
+ struct qib_mregion mr; /* must be last */
};
/*
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index a930702..42f4da6 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -1293,7 +1293,7 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task,
if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) {
sector_t sector_off = mr_status.sig_err.sig_err_offset;
- do_div(sector_off, sector_size + 8);
+ sector_div(sector_off, sector_size + 8);
*sector = scsi_get_lba(iser_task->sc) + sector_off;
pr_err("PI error found type %d at sector %llx "
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index dfbbbb2..8a51c3b 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -157,16 +157,9 @@ isert_create_qp(struct isert_conn *isert_conn,
attr.recv_cq = comp->cq;
attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS;
attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1;
- /*
- * FIXME: Use devattr.max_sge - 2 for max_send_sge as
- * work-around for RDMA_READs with ConnectX-2.
- *
- * Also, still make sure to have at least two SGEs for
- * outgoing control PDU responses.
- */
- attr.cap.max_send_sge = max(2, device->dev_attr.max_sge - 2);
- isert_conn->max_sge = attr.cap.max_send_sge;
-
+ attr.cap.max_send_sge = device->dev_attr.max_sge;
+ isert_conn->max_sge = min(device->dev_attr.max_sge,
+ device->dev_attr.max_sge_rd);
attr.cap.max_recv_sge = 1;
attr.sq_sig_type = IB_SIGNAL_REQ_WR;
attr.qp_type = IB_QPT_RC;
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 32f7962..3db9a65 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -488,7 +488,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch)
struct ib_qp *qp;
struct ib_fmr_pool *fmr_pool = NULL;
struct srp_fr_pool *fr_pool = NULL;
- const int m = 1 + dev->use_fast_reg;
+ const int m = dev->use_fast_reg ? 3 : 1;
struct ib_cq_init_attr cq_attr = {};
int ret;
@@ -994,16 +994,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
ret = srp_lookup_path(ch);
if (ret)
- return ret;
+ goto out;
while (1) {
init_completion(&ch->done);
ret = srp_send_req(ch, multich);
if (ret)
- return ret;
+ goto out;
ret = wait_for_completion_interruptible(&ch->done);
if (ret < 0)
- return ret;
+ goto out;
/*
* The CM event handling code will set status to
@@ -1011,15 +1011,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
* back, or SRP_DLID_REDIRECT if we get a lid/qp
* redirect REJ back.
*/
- switch (ch->status) {
+ ret = ch->status;
+ switch (ret) {
case 0:
ch->connected = true;
- return 0;
+ goto out;
case SRP_PORT_REDIRECT:
ret = srp_lookup_path(ch);
if (ret)
- return ret;
+ goto out;
break;
case SRP_DLID_REDIRECT:
@@ -1028,13 +1029,16 @@ static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
case SRP_STALE_CONN:
shost_printk(KERN_ERR, target->scsi_host, PFX
"giving up on stale connection\n");
- ch->status = -ECONNRESET;
- return ch->status;
+ ret = -ECONNRESET;
+ goto out;
default:
- return ch->status;
+ goto out;
}
}
+
+out:
+ return ret <= 0 ? ret : -ENODEV;
}
static int srp_inv_rkey(struct srp_rdma_ch *ch, u32 rkey)
@@ -1309,7 +1313,7 @@ reset_state:
}
static int srp_map_finish_fr(struct srp_map_state *state,
- struct srp_rdma_ch *ch)
+ struct srp_rdma_ch *ch, int sg_nents)
{
struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
@@ -1324,10 +1328,10 @@ static int srp_map_finish_fr(struct srp_map_state *state,
WARN_ON_ONCE(!dev->use_fast_reg);
- if (state->sg_nents == 0)
+ if (sg_nents == 0)
return 0;
- if (state->sg_nents == 1 && target->global_mr) {
+ if (sg_nents == 1 && target->global_mr) {
srp_map_desc(state, sg_dma_address(state->sg),
sg_dma_len(state->sg),
target->global_mr->rkey);
@@ -1341,8 +1345,7 @@ static int srp_map_finish_fr(struct srp_map_state *state,
rkey = ib_inc_rkey(desc->mr->rkey);
ib_update_fast_reg_key(desc->mr, rkey);
- n = ib_map_mr_sg(desc->mr, state->sg, state->sg_nents,
- dev->mr_page_size);
+ n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, dev->mr_page_size);
if (unlikely(n < 0))
return n;
@@ -1448,16 +1451,15 @@ static int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
state->fr.next = req->fr_list;
state->fr.end = req->fr_list + ch->target->cmd_sg_cnt;
state->sg = scat;
- state->sg_nents = scsi_sg_count(req->scmnd);
- while (state->sg_nents) {
+ while (count) {
int i, n;
- n = srp_map_finish_fr(state, ch);
+ n = srp_map_finish_fr(state, ch, count);
if (unlikely(n < 0))
return n;
- state->sg_nents -= n;
+ count -= n;
for (i = 0; i < n; i++)
state->sg = sg_next(state->sg);
}
@@ -1517,10 +1519,12 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
if (dev->use_fast_reg) {
state.sg = idb_sg;
- state.sg_nents = 1;
sg_set_buf(idb_sg, req->indirect_desc, idb_len);
idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
- ret = srp_map_finish_fr(&state, ch);
+#ifdef CONFIG_NEED_SG_DMA_LENGTH
+ idb_sg->dma_length = idb_sg->length; /* hack^2 */
+#endif
+ ret = srp_map_finish_fr(&state, ch, 1);
if (ret < 0)
return ret;
} else if (dev->use_fmr) {
@@ -1655,7 +1659,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
return ret;
req->nmdesc++;
} else {
- idb_rkey = target->global_mr->rkey;
+ idb_rkey = cpu_to_be32(target->global_mr->rkey);
}
indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
@@ -2798,7 +2802,6 @@ static struct scsi_host_template srp_template = {
.cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = srp_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -3229,10 +3232,6 @@ static ssize_t srp_create_target(struct device *dev,
if (ret)
goto out;
- ret = scsi_init_shared_tag_map(target_host, target_host->can_queue);
- if (ret)
- goto out;
-
target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE;
if (!srp_conn_unique(target->srp_host, target)) {
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 87a2a91..f6af531 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -300,10 +300,7 @@ struct srp_map_state {
dma_addr_t base_dma_addr;
u32 dma_len;
u32 total_len;
- union {
- unsigned int npages;
- int sg_nents;
- };
+ unsigned int npages;
unsigned int nmdesc;
unsigned int ndesc;
};
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 47c4022..2e2fe81 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -43,9 +43,7 @@
#include <linux/atomic.h>
#include <scsi/scsi_proto.h>
#include <scsi/scsi_tcq.h>
-#include <target/configfs_macros.h>
#include <target/target_core_base.h>
-#include <target/target_core_fabric_configfs.h>
#include <target/target_core_fabric.h>
#include "ib_srpt.h"
@@ -3546,20 +3544,19 @@ static void srpt_cleanup_nodeacl(struct se_node_acl *se_nacl)
spin_unlock_irq(&sport->port_acl_lock);
}
-static ssize_t srpt_tpg_attrib_show_srp_max_rdma_size(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t srpt_tpg_attrib_srp_max_rdma_size_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
return sprintf(page, "%u\n", sport->port_attrib.srp_max_rdma_size);
}
-static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t srpt_tpg_attrib_srp_max_rdma_size_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
unsigned long val;
int ret;
@@ -3584,22 +3581,19 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size(
return count;
}
-TF_TPG_ATTRIB_ATTR(srpt, srp_max_rdma_size, S_IRUGO | S_IWUSR);
-
-static ssize_t srpt_tpg_attrib_show_srp_max_rsp_size(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t srpt_tpg_attrib_srp_max_rsp_size_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
return sprintf(page, "%u\n", sport->port_attrib.srp_max_rsp_size);
}
-static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t srpt_tpg_attrib_srp_max_rsp_size_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
unsigned long val;
int ret;
@@ -3624,22 +3618,19 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size(
return count;
}
-TF_TPG_ATTRIB_ATTR(srpt, srp_max_rsp_size, S_IRUGO | S_IWUSR);
-
-static ssize_t srpt_tpg_attrib_show_srp_sq_size(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t srpt_tpg_attrib_srp_sq_size_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
return sprintf(page, "%u\n", sport->port_attrib.srp_sq_size);
}
-static ssize_t srpt_tpg_attrib_store_srp_sq_size(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t srpt_tpg_attrib_srp_sq_size_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
unsigned long val;
int ret;
@@ -3664,29 +3655,29 @@ static ssize_t srpt_tpg_attrib_store_srp_sq_size(
return count;
}
-TF_TPG_ATTRIB_ATTR(srpt, srp_sq_size, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(srpt_tpg_attrib_, srp_max_rdma_size);
+CONFIGFS_ATTR(srpt_tpg_attrib_, srp_max_rsp_size);
+CONFIGFS_ATTR(srpt_tpg_attrib_, srp_sq_size);
static struct configfs_attribute *srpt_tpg_attrib_attrs[] = {
- &srpt_tpg_attrib_srp_max_rdma_size.attr,
- &srpt_tpg_attrib_srp_max_rsp_size.attr,
- &srpt_tpg_attrib_srp_sq_size.attr,
+ &srpt_tpg_attrib_attr_srp_max_rdma_size,
+ &srpt_tpg_attrib_attr_srp_max_rsp_size,
+ &srpt_tpg_attrib_attr_srp_sq_size,
NULL,
};
-static ssize_t srpt_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t srpt_tpg_enable_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
return snprintf(page, PAGE_SIZE, "%d\n", (sport->enabled) ? 1: 0);
}
-static ssize_t srpt_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t srpt_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct srpt_port *sport = container_of(se_tpg, struct srpt_port, port_tpg_1);
unsigned long tmp;
int ret;
@@ -3709,10 +3700,10 @@ static ssize_t srpt_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(srpt, enable, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(srpt_tpg_, enable);
static struct configfs_attribute *srpt_tpg_attrs[] = {
- &srpt_tpg_enable.attr,
+ &srpt_tpg_attr_enable,
NULL,
};
@@ -3782,16 +3773,15 @@ static void srpt_drop_tport(struct se_wwn *wwn)
pr_debug("drop_tport(%s\n", config_item_name(&sport->port_wwn.wwn_group.cg_item));
}
-static ssize_t srpt_wwn_show_attr_version(struct target_fabric_configfs *tf,
- char *buf)
+static ssize_t srpt_wwn_version_show(struct config_item *item, char *buf)
{
return scnprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION);
}
-TF_WWN_ATTR_RO(srpt, version);
+CONFIGFS_ATTR_RO(srpt_wwn_, version);
static struct configfs_attribute *srpt_wwn_attrs[] = {
- &srpt_wwn_version.attr,
+ &srpt_wwn_attr_version,
NULL,
};
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 932d073..da32609 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -592,6 +592,7 @@ static void db9_attach(struct parport *pp)
return;
}
+ memset(&db9_parport_cb, 0, sizeof(db9_parport_cb));
db9_parport_cb.flags = PARPORT_FLAG_EXCL;
pd = parport_register_dev_model(pp, "db9", &db9_parport_cb, port_idx);
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 5a672dc..eae14d5 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -951,6 +951,7 @@ static void gc_attach(struct parport *pp)
pads = gc_cfg[port_idx].args + 1;
n_pads = gc_cfg[port_idx].nargs - 1;
+ memset(&gc_parport_cb, 0, sizeof(gc_parport_cb));
gc_parport_cb.flags = PARPORT_FLAG_EXCL;
pd = parport_register_dev_model(pp, "gamecon", &gc_parport_cb,
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index 9f5bca2..77f575d 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -181,6 +181,7 @@ static void tgfx_attach(struct parport *pp)
n_buttons = tgfx_cfg[port_idx].args + 1;
n_devs = tgfx_cfg[port_idx].nargs - 1;
+ memset(&tgfx_parport_cb, 0, sizeof(tgfx_parport_cb));
tgfx_parport_cb.flags = PARPORT_FLAG_EXCL;
pd = parport_register_dev_model(pp, "turbografx", &tgfx_parport_cb,
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index 9c07fe9..70a893a 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -218,6 +218,7 @@ static void walkera0701_attach(struct parport *pp)
w->parport = pp;
+ memset(&walkera0701_parport_cb, 0, sizeof(walkera0701_parport_cb));
walkera0701_parport_cb.flags = PARPORT_FLAG_EXCL;
walkera0701_parport_cb.irq_func = walkera0701_irq_handler;
walkera0701_parport_cb.private = w;
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 4bf6785..d5994a7 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -97,8 +97,7 @@ static void arizona_haptics_work(struct work_struct *work)
ret = regmap_update_bits(arizona->regmap,
ARIZONA_HAPTICS_CONTROL_1,
- ARIZONA_HAP_CTRL_MASK,
- 1 << ARIZONA_HAP_CTRL_SHIFT);
+ ARIZONA_HAP_CTRL_MASK, 0);
if (ret != 0) {
dev_err(arizona->dev, "Failed to stop haptics: %d\n",
ret);
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 5e1665b..2f58985 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -41,6 +41,7 @@
#define DRIVER_NAME "elan_i2c"
#define ELAN_DRIVER_VERSION "1.6.1"
+#define ELAN_VENDOR_ID 0x04f3
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
#define ETP_FINGER_WIDTH 15
@@ -914,6 +915,8 @@ static int elan_setup_input_device(struct elan_tp_data *data)
input->name = "Elan Touchpad";
input->id.bustype = BUS_I2C;
+ input->id.vendor = ELAN_VENDOR_ID;
+ input->id.product = data->product_id;
input_set_drvdata(input, data);
error = input_mt_init_slots(input, ETP_MAX_FINGERS,
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 2955f1d..537ebb0 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1520,6 +1520,13 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
},
},
+ {
+ /* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK U745"),
+ },
+ },
#endif
{ }
};
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index 74bb172..1edfac7 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -145,6 +145,7 @@ static int parkbd_getport(struct parport *pp)
{
struct pardev_cb parkbd_parport_cb;
+ memset(&parkbd_parport_cb, 0, sizeof(parkbd_parport_cb));
parkbd_parport_cb.irq_func = parkbd_interrupt;
parkbd_parport_cb.flags = PARPORT_FLAG_EXCL;
@@ -164,7 +165,7 @@ static int parkbd_getport(struct parport *pp)
return 0;
}
-static struct serio * __init parkbd_allocate_serio(void)
+static struct serio *parkbd_allocate_serio(void)
{
struct serio *serio;
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index e7f966d..78ca448 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -1819,6 +1819,14 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0);
input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0);
+ /* Verify that a device really has an endpoint */
+ if (intf->altsetting[0].desc.bNumEndpoints < 1) {
+ dev_err(&intf->dev,
+ "interface has %d endpoints, but must have minimum 1\n",
+ intf->altsetting[0].desc.bNumEndpoints);
+ err = -EINVAL;
+ goto fail3;
+ }
endpoint = &intf->altsetting[0].endpoint[0].desc;
/* Go set up our URB, which is called when the tablet receives
@@ -1861,6 +1869,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (i == ARRAY_SIZE(speeds)) {
dev_info(&intf->dev,
"Aiptek tried all speeds, no sane response\n");
+ err = -EINVAL;
goto fail3;
}
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 80cc698..ae33da7 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -939,10 +939,27 @@ config TOUCHSCREEN_TSC_SERIO
To compile this driver as a module, choose M here: the
module will be called tsc40.
+config TOUCHSCREEN_TSC200X_CORE
+ tristate
+
+config TOUCHSCREEN_TSC2004
+ tristate "TSC2004 based touchscreens"
+ depends on I2C
+ select REGMAP_I2C
+ select TOUCHSCREEN_TSC200X_CORE
+ help
+ Say Y here if you have a TSC2004 based touchscreen.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tsc2004.
+
config TOUCHSCREEN_TSC2005
tristate "TSC2005 based touchscreens"
depends on SPI_MASTER
select REGMAP_SPI
+ select TOUCHSCREEN_TSC200X_CORE
help
Say Y here if you have a TSC2005 based touchscreen.
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 17435c7..cbaa6ab 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -69,6 +69,8 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
obj-$(CONFIG_TOUCHSCREEN_TSC_SERIO) += tsc40.o
+obj-$(CONFIG_TOUCHSCREEN_TSC200X_CORE) += tsc200x-core.o
+obj-$(CONFIG_TOUCHSCREEN_TSC2004) += tsc2004.o
obj-$(CONFIG_TOUCHSCREEN_TSC2005) += tsc2005.o
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index c562205..2d5794e 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2487,6 +2487,31 @@ static struct mxt_acpi_platform_data samus_platform_data[] = {
{ }
};
+static unsigned int chromebook_tp_buttons[] = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ BTN_LEFT
+};
+
+static struct mxt_acpi_platform_data chromebook_platform_data[] = {
+ {
+ /* Touchpad */
+ .hid = "ATML0000",
+ .pdata = {
+ .t19_num_keys = ARRAY_SIZE(chromebook_tp_buttons),
+ .t19_keymap = chromebook_tp_buttons,
+ },
+ },
+ {
+ /* Touchscreen */
+ .hid = "ATML0001",
+ },
+ { }
+};
+
static const struct dmi_system_id mxt_dmi_table[] = {
{
/* 2015 Google Pixel */
@@ -2497,6 +2522,14 @@ static const struct dmi_system_id mxt_dmi_table[] = {
},
.driver_data = samus_platform_data,
},
+ {
+ /* Other Google Chromebooks */
+ .ident = "Chromebook",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+ },
+ .driver_data = chromebook_platform_data,
+ },
{ }
};
@@ -2701,6 +2734,7 @@ static const struct i2c_device_id mxt_id[] = {
{ "qt602240_ts", 0 },
{ "atmel_mxt_ts", 0 },
{ "atmel_mxt_tp", 0 },
+ { "maxtouch", 0 },
{ "mXT224", 0 },
{ }
};
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 17cc20e..ac09855 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -1316,7 +1316,13 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
disable_irq(client->irq);
- if (device_may_wakeup(dev) || ts->keep_power_in_suspend) {
+ if (device_may_wakeup(dev)) {
+ /*
+ * The device will automatically enter idle mode
+ * that has reduced power consumption.
+ */
+ ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0);
+ } else if (ts->keep_power_in_suspend) {
for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
error = elants_i2c_send(client, set_sleep_cmd,
sizeof(set_sleep_cmd));
@@ -1326,10 +1332,6 @@ static int __maybe_unused elants_i2c_suspend(struct device *dev)
dev_err(&client->dev,
"suspend command failed: %d\n", error);
}
-
- if (device_may_wakeup(dev))
- ts->wake_irq_enabled =
- (enable_irq_wake(client->irq) == 0);
} else {
elants_i2c_power_off(ts);
}
@@ -1345,10 +1347,11 @@ static int __maybe_unused elants_i2c_resume(struct device *dev)
int retry_cnt;
int error;
- if (device_may_wakeup(dev) && ts->wake_irq_enabled)
- disable_irq_wake(client->irq);
-
- if (ts->keep_power_in_suspend) {
+ if (device_may_wakeup(dev)) {
+ if (ts->wake_irq_enabled)
+ disable_irq_wake(client->irq);
+ elants_i2c_sw_reset(client);
+ } else if (ts->keep_power_in_suspend) {
for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
error = elants_i2c_send(client, set_active_cmd,
sizeof(set_active_cmd));
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index d214f22..b6c4d03 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -444,7 +444,7 @@ static void sur40_process_video(struct sur40_state *sur40)
goto err_poll;
/* mark as finished */
- v4l2_get_timestamp(&new_buf->vb.timestamp);
+ new_buf->vb.vb2_buf.timestamp = ktime_get_ns();
new_buf->vb.sequence = sur40->sequence++;
new_buf->vb.field = V4L2_FIELD_NONE;
vb2_buffer_done(&new_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -644,22 +644,21 @@ static void sur40_disconnect(struct usb_interface *interface)
* minimum number: many DMA engines need a minimum of 2 buffers in the
* queue and you need to have another available for userspace processing.
*/
-static int sur40_queue_setup(struct vb2_queue *q, const void *parg,
+static int sur40_queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct sur40_state *sur40 = vb2_get_drv_priv(q);
if (q->num_buffers + *nbuffers < 3)
*nbuffers = 3 - q->num_buffers;
+ alloc_ctxs[0] = sur40->alloc_ctx;
- if (fmt && fmt->fmt.pix.sizeimage < sur40_video_format.sizeimage)
- return -EINVAL;
+ if (*nplanes)
+ return sizes[0] < sur40_video_format.sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : sur40_video_format.sizeimage;
- alloc_ctxs[0] = sur40->alloc_ctx;
+ sizes[0] = sur40_video_format.sizeimage;
return 0;
}
diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c
new file mode 100644
index 0000000..7295c19
--- /dev/null
+++ b/drivers/input/touchscreen/tsc2004.c
@@ -0,0 +1,83 @@
+/*
+ * TSC2004 touchscreen driver
+ *
+ * Copyright (C) 2015 QWERTY Embedded Design
+ * Copyright (C) 2015 EMAC Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include "tsc200x-core.h"
+
+static int tsc2004_cmd(struct device *dev, u8 cmd)
+{
+ u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
+ s32 data;
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ data = i2c_smbus_write_byte(i2c, tx);
+ if (data < 0) {
+ dev_err(dev, "%s: failed, command: %x i2c error: %d\n",
+ __func__, cmd, data);
+ return data;
+ }
+
+ return 0;
+}
+
+static int tsc2004_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+
+{
+ return tsc200x_probe(&i2c->dev, i2c->irq, BUS_I2C,
+ devm_regmap_init_i2c(i2c, &tsc200x_regmap_config),
+ tsc2004_cmd);
+}
+
+static int tsc2004_remove(struct i2c_client *i2c)
+{
+ return tsc200x_remove(&i2c->dev);
+}
+
+static const struct i2c_device_id tsc2004_idtable[] = {
+ { "tsc2004", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tsc2004_idtable);
+
+#ifdef CONFIG_OF
+static const struct of_device_id tsc2004_of_match[] = {
+ { .compatible = "ti,tsc2004" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, tsc2004_of_match);
+#endif
+
+static struct i2c_driver tsc2004_driver = {
+ .driver = {
+ .name = "tsc2004",
+ .of_match_table = of_match_ptr(tsc2004_of_match),
+ .pm = &tsc200x_pm_ops,
+ },
+ .id_table = tsc2004_idtable,
+ .probe = tsc2004_probe,
+ .remove = tsc2004_remove,
+};
+module_i2c_driver(tsc2004_driver);
+
+MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
+MODULE_DESCRIPTION("TSC2004 Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index f41f233..b9f593d 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -2,9 +2,10 @@
* TSC2005 touchscreen driver
*
* Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2015 QWERTY Embedded Design
+ * Copyright (C) 2015 EMAC Inc.
*
- * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
- * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ * Based on original tsc2005.c by Lauri Leukkunen <lauri.leukkunen@nokia.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
@@ -15,192 +16,32 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
-#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
-#include <linux/input/touchscreen.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/of.h>
#include <linux/spi/spi.h>
-#include <linux/spi/tsc2005.h>
-#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
-#include <linux/gpio/consumer.h>
-
-/*
- * The touchscreen interface operates as follows:
- *
- * 1) Pen is pressed against the touchscreen.
- * 2) TSC2005 performs AD conversion.
- * 3) After the conversion is done TSC2005 drives DAV line down.
- * 4) GPIO IRQ is received and tsc2005_irq_thread() is scheduled.
- * 5) tsc2005_irq_thread() queues up an spi transfer to fetch the x, y, z1, z2
- * values.
- * 6) tsc2005_irq_thread() reports coordinates to input layer and sets up
- * tsc2005_penup_timer() to be called after TSC2005_PENUP_TIME_MS (40ms).
- * 7) When the penup timer expires, there have not been touch or DAV interrupts
- * during the last 40ms which means the pen has been lifted.
- *
- * ESD recovery via a hardware reset is done if the TSC2005 doesn't respond
- * after a configurable period (in ms) of activity. If esd_timeout is 0, the
- * watchdog is disabled.
- */
-
-/* control byte 1 */
-#define TSC2005_CMD 0x80
-#define TSC2005_CMD_NORMAL 0x00
-#define TSC2005_CMD_STOP 0x01
-#define TSC2005_CMD_12BIT 0x04
-
-/* control byte 0 */
-#define TSC2005_REG_READ 0x01 /* R/W access */
-#define TSC2005_REG_PND0 0x02 /* Power Not Down Control */
-#define TSC2005_REG_X (0x0 << 3)
-#define TSC2005_REG_Y (0x1 << 3)
-#define TSC2005_REG_Z1 (0x2 << 3)
-#define TSC2005_REG_Z2 (0x3 << 3)
-#define TSC2005_REG_AUX (0x4 << 3)
-#define TSC2005_REG_TEMP1 (0x5 << 3)
-#define TSC2005_REG_TEMP2 (0x6 << 3)
-#define TSC2005_REG_STATUS (0x7 << 3)
-#define TSC2005_REG_AUX_HIGH (0x8 << 3)
-#define TSC2005_REG_AUX_LOW (0x9 << 3)
-#define TSC2005_REG_TEMP_HIGH (0xA << 3)
-#define TSC2005_REG_TEMP_LOW (0xB << 3)
-#define TSC2005_REG_CFR0 (0xC << 3)
-#define TSC2005_REG_CFR1 (0xD << 3)
-#define TSC2005_REG_CFR2 (0xE << 3)
-#define TSC2005_REG_CONV_FUNC (0xF << 3)
-
-/* configuration register 0 */
-#define TSC2005_CFR0_PRECHARGE_276US 0x0040
-#define TSC2005_CFR0_STABTIME_1MS 0x0300
-#define TSC2005_CFR0_CLOCK_1MHZ 0x1000
-#define TSC2005_CFR0_RESOLUTION12 0x2000
-#define TSC2005_CFR0_PENMODE 0x8000
-#define TSC2005_CFR0_INITVALUE (TSC2005_CFR0_STABTIME_1MS | \
- TSC2005_CFR0_CLOCK_1MHZ | \
- TSC2005_CFR0_RESOLUTION12 | \
- TSC2005_CFR0_PRECHARGE_276US | \
- TSC2005_CFR0_PENMODE)
-
-/* bits common to both read and write of configuration register 0 */
-#define TSC2005_CFR0_RW_MASK 0x3fff
-
-/* configuration register 1 */
-#define TSC2005_CFR1_BATCHDELAY_4MS 0x0003
-#define TSC2005_CFR1_INITVALUE TSC2005_CFR1_BATCHDELAY_4MS
-
-/* configuration register 2 */
-#define TSC2005_CFR2_MAVE_Z 0x0004
-#define TSC2005_CFR2_MAVE_Y 0x0008
-#define TSC2005_CFR2_MAVE_X 0x0010
-#define TSC2005_CFR2_AVG_7 0x0800
-#define TSC2005_CFR2_MEDIUM_15 0x3000
-#define TSC2005_CFR2_INITVALUE (TSC2005_CFR2_MAVE_X | \
- TSC2005_CFR2_MAVE_Y | \
- TSC2005_CFR2_MAVE_Z | \
- TSC2005_CFR2_MEDIUM_15 | \
- TSC2005_CFR2_AVG_7)
-
-#define MAX_12BIT 0xfff
-#define TSC2005_DEF_X_FUZZ 4
-#define TSC2005_DEF_Y_FUZZ 8
-#define TSC2005_DEF_P_FUZZ 2
-#define TSC2005_DEF_RESISTOR 280
-
-#define TSC2005_SPI_MAX_SPEED_HZ 10000000
-#define TSC2005_PENUP_TIME_MS 40
-
-static const struct regmap_range tsc2005_writable_ranges[] = {
- regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2),
-};
-
-static const struct regmap_access_table tsc2005_writable_table = {
- .yes_ranges = tsc2005_writable_ranges,
- .n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges),
-};
-
-static struct regmap_config tsc2005_regmap_config = {
- .reg_bits = 8,
- .val_bits = 16,
- .reg_stride = 0x08,
- .max_register = 0x78,
- .read_flag_mask = TSC2005_REG_READ,
- .write_flag_mask = TSC2005_REG_PND0,
- .wr_table = &tsc2005_writable_table,
- .use_single_rw = true,
-};
-
-struct tsc2005_data {
- u16 x;
- u16 y;
- u16 z1;
- u16 z2;
-} __packed;
-#define TSC2005_DATA_REGS 4
-
-struct tsc2005 {
- struct spi_device *spi;
- struct regmap *regmap;
-
- struct input_dev *idev;
- char phys[32];
-
- struct mutex mutex;
-
- /* raw copy of previous x,y,z */
- int in_x;
- int in_y;
- int in_z1;
- int in_z2;
-
- spinlock_t lock;
- struct timer_list penup_timer;
+#include "tsc200x-core.h"
- unsigned int esd_timeout;
- struct delayed_work esd_work;
- unsigned long last_valid_interrupt;
-
- unsigned int x_plate_ohm;
-
- bool opened;
- bool suspended;
-
- bool pen_down;
-
- struct regulator *vio;
-
- struct gpio_desc *reset_gpio;
- void (*set_reset)(bool enable);
-};
-
-static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
+static int tsc2005_cmd(struct device *dev, u8 cmd)
{
- u8 tx = TSC2005_CMD | TSC2005_CMD_12BIT | cmd;
+ u8 tx = TSC200X_CMD | TSC200X_CMD_12BIT | cmd;
struct spi_transfer xfer = {
- .tx_buf = &tx,
- .len = 1,
- .bits_per_word = 8,
+ .tx_buf = &tx,
+ .len = 1,
+ .bits_per_word = 8,
};
struct spi_message msg;
+ struct spi_device *spi = to_spi_device(dev);
int error;
spi_message_init(&msg);
spi_message_add_tail(&xfer, &msg);
- error = spi_sync(ts->spi, &msg);
+ error = spi_sync(spi, &msg);
if (error) {
- dev_err(&ts->spi->dev, "%s: failed, command: %x, error: %d\n",
+ dev_err(dev, "%s: failed, command: %x, spi error: %d\n",
__func__, cmd, error);
return error;
}
@@ -208,382 +49,10 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd)
return 0;
}
-static void tsc2005_update_pen_state(struct tsc2005 *ts,
- int x, int y, int pressure)
-{
- if (pressure) {
- input_report_abs(ts->idev, ABS_X, x);
- input_report_abs(ts->idev, ABS_Y, y);
- input_report_abs(ts->idev, ABS_PRESSURE, pressure);
- if (!ts->pen_down) {
- input_report_key(ts->idev, BTN_TOUCH, !!pressure);
- ts->pen_down = true;
- }
- } else {
- input_report_abs(ts->idev, ABS_PRESSURE, 0);
- if (ts->pen_down) {
- input_report_key(ts->idev, BTN_TOUCH, 0);
- ts->pen_down = false;
- }
- }
- input_sync(ts->idev);
- dev_dbg(&ts->spi->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
- pressure);
-}
-
-static irqreturn_t tsc2005_irq_thread(int irq, void *_ts)
-{
- struct tsc2005 *ts = _ts;
- unsigned long flags;
- unsigned int pressure;
- struct tsc2005_data tsdata;
- int error;
-
- /* read the coordinates */
- error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata,
- TSC2005_DATA_REGS);
- if (unlikely(error))
- goto out;
-
- /* validate position */
- if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT))
- goto out;
-
- /* Skip reading if the pressure components are out of range */
- if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT))
- goto out;
- if (unlikely(tsdata.z1 >= tsdata.z2))
- goto out;
-
- /*
- * Skip point if this is a pen down with the exact same values as
- * the value before pen-up - that implies SPI fed us stale data
- */
- if (!ts->pen_down &&
- ts->in_x == tsdata.x && ts->in_y == tsdata.y &&
- ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) {
- goto out;
- }
-
- /*
- * At this point we are happy we have a valid and useful reading.
- * Remember it for later comparisons. We may now begin downsampling.
- */
- ts->in_x = tsdata.x;
- ts->in_y = tsdata.y;
- ts->in_z1 = tsdata.z1;
- ts->in_z2 = tsdata.z2;
-
- /* Compute touch pressure resistance using equation #1 */
- pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1;
- pressure = pressure * ts->x_plate_ohm / 4096;
- if (unlikely(pressure > MAX_12BIT))
- goto out;
-
- spin_lock_irqsave(&ts->lock, flags);
-
- tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
- mod_timer(&ts->penup_timer,
- jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS));
-
- spin_unlock_irqrestore(&ts->lock, flags);
-
- ts->last_valid_interrupt = jiffies;
-out:
- return IRQ_HANDLED;
-}
-
-static void tsc2005_penup_timer(unsigned long data)
-{
- struct tsc2005 *ts = (struct tsc2005 *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&ts->lock, flags);
- tsc2005_update_pen_state(ts, 0, 0, 0);
- spin_unlock_irqrestore(&ts->lock, flags);
-}
-
-static void tsc2005_start_scan(struct tsc2005 *ts)
-{
- regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE);
- regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE);
- regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE);
- tsc2005_cmd(ts, TSC2005_CMD_NORMAL);
-}
-
-static void tsc2005_stop_scan(struct tsc2005 *ts)
-{
- tsc2005_cmd(ts, TSC2005_CMD_STOP);
-}
-
-static void tsc2005_set_reset(struct tsc2005 *ts, bool enable)
-{
- if (ts->reset_gpio)
- gpiod_set_value_cansleep(ts->reset_gpio, enable);
- else if (ts->set_reset)
- ts->set_reset(enable);
-}
-
-/* must be called with ts->mutex held */
-static void __tsc2005_disable(struct tsc2005 *ts)
-{
- tsc2005_stop_scan(ts);
-
- disable_irq(ts->spi->irq);
- del_timer_sync(&ts->penup_timer);
-
- cancel_delayed_work_sync(&ts->esd_work);
-
- enable_irq(ts->spi->irq);
-}
-
-/* must be called with ts->mutex held */
-static void __tsc2005_enable(struct tsc2005 *ts)
-{
- tsc2005_start_scan(ts);
-
- if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {
- ts->last_valid_interrupt = jiffies;
- schedule_delayed_work(&ts->esd_work,
- round_jiffies_relative(
- msecs_to_jiffies(ts->esd_timeout)));
- }
-
-}
-
-static ssize_t tsc2005_selftest_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct tsc2005 *ts = dev_get_drvdata(dev);
- unsigned int temp_high;
- unsigned int temp_high_orig;
- unsigned int temp_high_test;
- bool success = true;
- int error;
-
- mutex_lock(&ts->mutex);
-
- /*
- * Test TSC2005 communications via temp high register.
- */
- __tsc2005_disable(ts);
-
- error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig);
- if (error) {
- dev_warn(dev, "selftest failed: read error %d\n", error);
- success = false;
- goto out;
- }
-
- temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
-
- error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test);
- if (error) {
- dev_warn(dev, "selftest failed: write error %d\n", error);
- success = false;
- goto out;
- }
-
- error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high);
- if (error) {
- dev_warn(dev, "selftest failed: read error %d after write\n",
- error);
- success = false;
- goto out;
- }
-
- if (temp_high != temp_high_test) {
- dev_warn(dev, "selftest failed: %d != %d\n",
- temp_high, temp_high_test);
- success = false;
- }
-
- /* hardware reset */
- tsc2005_set_reset(ts, false);
- usleep_range(100, 500); /* only 10us required */
- tsc2005_set_reset(ts, true);
-
- if (!success)
- goto out;
-
- /* test that the reset really happened */
- error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high);
- if (error) {
- dev_warn(dev, "selftest failed: read error %d after reset\n",
- error);
- success = false;
- goto out;
- }
-
- if (temp_high != temp_high_orig) {
- dev_warn(dev, "selftest failed after reset: %d != %d\n",
- temp_high, temp_high_orig);
- success = false;
- }
-
-out:
- __tsc2005_enable(ts);
- mutex_unlock(&ts->mutex);
-
- return sprintf(buf, "%d\n", success);
-}
-
-static DEVICE_ATTR(selftest, S_IRUGO, tsc2005_selftest_show, NULL);
-
-static struct attribute *tsc2005_attrs[] = {
- &dev_attr_selftest.attr,
- NULL
-};
-
-static umode_t tsc2005_attr_is_visible(struct kobject *kobj,
- struct attribute *attr, int n)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct tsc2005 *ts = dev_get_drvdata(dev);
- umode_t mode = attr->mode;
-
- if (attr == &dev_attr_selftest.attr) {
- if (!ts->set_reset && !ts->reset_gpio)
- mode = 0;
- }
-
- return mode;
-}
-
-static const struct attribute_group tsc2005_attr_group = {
- .is_visible = tsc2005_attr_is_visible,
- .attrs = tsc2005_attrs,
-};
-
-static void tsc2005_esd_work(struct work_struct *work)
-{
- struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work);
- int error;
- unsigned int r;
-
- if (!mutex_trylock(&ts->mutex)) {
- /*
- * If the mutex is taken, it means that disable or enable is in
- * progress. In that case just reschedule the work. If the work
- * is not needed, it will be canceled by disable.
- */
- goto reschedule;
- }
-
- if (time_is_after_jiffies(ts->last_valid_interrupt +
- msecs_to_jiffies(ts->esd_timeout)))
- goto out;
-
- /* We should be able to read register without disabling interrupts. */
- error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r);
- if (!error &&
- !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) {
- goto out;
- }
-
- /*
- * If we could not read our known value from configuration register 0
- * then we should reset the controller as if from power-up and start
- * scanning again.
- */
- dev_info(&ts->spi->dev, "TSC2005 not responding - resetting\n");
-
- disable_irq(ts->spi->irq);
- del_timer_sync(&ts->penup_timer);
-
- tsc2005_update_pen_state(ts, 0, 0, 0);
-
- tsc2005_set_reset(ts, false);
- usleep_range(100, 500); /* only 10us required */
- tsc2005_set_reset(ts, true);
-
- enable_irq(ts->spi->irq);
- tsc2005_start_scan(ts);
-
-out:
- mutex_unlock(&ts->mutex);
-reschedule:
- /* re-arm the watchdog */
- schedule_delayed_work(&ts->esd_work,
- round_jiffies_relative(
- msecs_to_jiffies(ts->esd_timeout)));
-}
-
-static int tsc2005_open(struct input_dev *input)
-{
- struct tsc2005 *ts = input_get_drvdata(input);
-
- mutex_lock(&ts->mutex);
-
- if (!ts->suspended)
- __tsc2005_enable(ts);
-
- ts->opened = true;
-
- mutex_unlock(&ts->mutex);
-
- return 0;
-}
-
-static void tsc2005_close(struct input_dev *input)
-{
- struct tsc2005 *ts = input_get_drvdata(input);
-
- mutex_lock(&ts->mutex);
-
- if (!ts->suspended)
- __tsc2005_disable(ts);
-
- ts->opened = false;
-
- mutex_unlock(&ts->mutex);
-}
-
static int tsc2005_probe(struct spi_device *spi)
{
- const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev);
- struct device_node *np = spi->dev.of_node;
-
- struct tsc2005 *ts;
- struct input_dev *input_dev;
- unsigned int max_x = MAX_12BIT;
- unsigned int max_y = MAX_12BIT;
- unsigned int max_p = MAX_12BIT;
- unsigned int fudge_x = TSC2005_DEF_X_FUZZ;
- unsigned int fudge_y = TSC2005_DEF_Y_FUZZ;
- unsigned int fudge_p = TSC2005_DEF_P_FUZZ;
- unsigned int x_plate_ohm = TSC2005_DEF_RESISTOR;
- unsigned int esd_timeout;
int error;
- if (!np && !pdata) {
- dev_err(&spi->dev, "no platform data\n");
- return -ENODEV;
- }
-
- if (spi->irq <= 0) {
- dev_err(&spi->dev, "no irq\n");
- return -ENODEV;
- }
-
- if (pdata) {
- fudge_x = pdata->ts_x_fudge;
- fudge_y = pdata->ts_y_fudge;
- fudge_p = pdata->ts_pressure_fudge;
- max_x = pdata->ts_x_max;
- max_y = pdata->ts_y_max;
- max_p = pdata->ts_pressure_max;
- x_plate_ohm = pdata->ts_x_plate_ohm;
- esd_timeout = pdata->esd_timeout_ms;
- } else {
- x_plate_ohm = TSC2005_DEF_RESISTOR;
- of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm);
- esd_timeout = 0;
- of_property_read_u32(np, "ti,esd-recovery-timeout-ms",
- &esd_timeout);
- }
-
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
if (!spi->max_speed_hz)
@@ -593,174 +62,27 @@ static int tsc2005_probe(struct spi_device *spi)
if (error)
return error;
- ts = devm_kzalloc(&spi->dev, sizeof(*ts), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- input_dev = devm_input_allocate_device(&spi->dev);
- if (!input_dev)
- return -ENOMEM;
-
- ts->spi = spi;
- ts->idev = input_dev;
-
- ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config);
- if (IS_ERR(ts->regmap))
- return PTR_ERR(ts->regmap);
-
- ts->x_plate_ohm = x_plate_ohm;
- ts->esd_timeout = esd_timeout;
-
- ts->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
- GPIOD_OUT_HIGH);
- if (IS_ERR(ts->reset_gpio)) {
- error = PTR_ERR(ts->reset_gpio);
- dev_err(&spi->dev, "error acquiring reset gpio: %d\n", error);
- return error;
- }
-
- ts->vio = devm_regulator_get_optional(&spi->dev, "vio");
- if (IS_ERR(ts->vio)) {
- error = PTR_ERR(ts->vio);
- dev_err(&spi->dev, "vio regulator missing (%d)", error);
- return error;
- }
-
- if (!ts->reset_gpio && pdata)
- ts->set_reset = pdata->set_reset;
-
- mutex_init(&ts->mutex);
-
- spin_lock_init(&ts->lock);
- setup_timer(&ts->penup_timer, tsc2005_penup_timer, (unsigned long)ts);
-
- INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work);
-
- snprintf(ts->phys, sizeof(ts->phys),
- "%s/input-ts", dev_name(&spi->dev));
-
- input_dev->name = "TSC2005 touchscreen";
- input_dev->phys = ts->phys;
- input_dev->id.bustype = BUS_SPI;
- input_dev->dev.parent = &spi->dev;
- input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
-
- if (np)
- touchscreen_parse_properties(input_dev, false);
-
- input_dev->open = tsc2005_open;
- input_dev->close = tsc2005_close;
-
- input_set_drvdata(input_dev, ts);
-
- /* Ensure the touchscreen is off */
- tsc2005_stop_scan(ts);
-
- error = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
- tsc2005_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "tsc2005", ts);
- if (error) {
- dev_err(&spi->dev, "Failed to request irq, err: %d\n", error);
- return error;
- }
-
- /* enable regulator for DT */
- if (ts->vio) {
- error = regulator_enable(ts->vio);
- if (error)
- return error;
- }
-
- dev_set_drvdata(&spi->dev, ts);
- error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group);
- if (error) {
- dev_err(&spi->dev,
- "Failed to create sysfs attributes, err: %d\n", error);
- goto disable_regulator;
- }
-
- error = input_register_device(ts->idev);
- if (error) {
- dev_err(&spi->dev,
- "Failed to register input device, err: %d\n", error);
- goto err_remove_sysfs;
- }
-
- irq_set_irq_wake(spi->irq, 1);
- return 0;
-
-err_remove_sysfs:
- sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
-disable_regulator:
- if (ts->vio)
- regulator_disable(ts->vio);
- return error;
+ return tsc200x_probe(&spi->dev, spi->irq, BUS_SPI,
+ devm_regmap_init_spi(spi, &tsc200x_regmap_config),
+ tsc2005_cmd);
}
static int tsc2005_remove(struct spi_device *spi)
{
- struct tsc2005 *ts = dev_get_drvdata(&spi->dev);
-
- sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group);
-
- if (ts->vio)
- regulator_disable(ts->vio);
-
- return 0;
-}
-
-static int __maybe_unused tsc2005_suspend(struct device *dev)
-{
- struct tsc2005 *ts = dev_get_drvdata(dev);
-
- mutex_lock(&ts->mutex);
-
- if (!ts->suspended && ts->opened)
- __tsc2005_disable(ts);
-
- ts->suspended = true;
-
- mutex_unlock(&ts->mutex);
-
- return 0;
-}
-
-static int __maybe_unused tsc2005_resume(struct device *dev)
-{
- struct tsc2005 *ts = dev_get_drvdata(dev);
-
- mutex_lock(&ts->mutex);
-
- if (ts->suspended && ts->opened)
- __tsc2005_enable(ts);
-
- ts->suspended = false;
-
- mutex_unlock(&ts->mutex);
-
- return 0;
+ return tsc200x_remove(&spi->dev);
}
-static SIMPLE_DEV_PM_OPS(tsc2005_pm_ops, tsc2005_suspend, tsc2005_resume);
-
static struct spi_driver tsc2005_driver = {
.driver = {
.name = "tsc2005",
- .pm = &tsc2005_pm_ops,
+ .pm = &tsc200x_pm_ops,
},
.probe = tsc2005_probe,
.remove = tsc2005_remove,
};
-
module_spi_driver(tsc2005_driver);
-MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_AUTHOR("Michael Welling <mwelling@ieee.org>");
MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:tsc2005");
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
new file mode 100644
index 0000000..15240c1
--- /dev/null
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -0,0 +1,665 @@
+/*
+ * TSC2004/TSC2005 touchscreen driver core
+ *
+ * Copyright (C) 2006-2010 Nokia Corporation
+ * Copyright (C) 2015 QWERTY Embedded Design
+ * Copyright (C) 2015 EMAC Inc.
+ *
+ * Author: Lauri Leukkunen <lauri.leukkunen@nokia.com>
+ * based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/of.h>
+#include <linux/spi/tsc2005.h>
+#include <linux/regulator/consumer.h>
+#include <linux/regmap.h>
+#include <linux/gpio/consumer.h>
+#include "tsc200x-core.h"
+
+/*
+ * The touchscreen interface operates as follows:
+ *
+ * 1) Pen is pressed against the touchscreen.
+ * 2) TSC200X performs AD conversion.
+ * 3) After the conversion is done TSC200X drives DAV line down.
+ * 4) GPIO IRQ is received and tsc200x_irq_thread() is scheduled.
+ * 5) tsc200x_irq_thread() queues up a transfer to fetch the x, y, z1, z2
+ * values.
+ * 6) tsc200x_irq_thread() reports coordinates to input layer and sets up
+ * tsc200x_penup_timer() to be called after TSC200X_PENUP_TIME_MS (40ms).
+ * 7) When the penup timer expires, there have not been touch or DAV interrupts
+ * during the last 40ms which means the pen has been lifted.
+ *
+ * ESD recovery via a hardware reset is done if the TSC200X doesn't respond
+ * after a configurable period (in ms) of activity. If esd_timeout is 0, the
+ * watchdog is disabled.
+ */
+
+static const struct regmap_range tsc200x_writable_ranges[] = {
+ regmap_reg_range(TSC200X_REG_AUX_HIGH, TSC200X_REG_CFR2),
+};
+
+static const struct regmap_access_table tsc200x_writable_table = {
+ .yes_ranges = tsc200x_writable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(tsc200x_writable_ranges),
+};
+
+const struct regmap_config tsc200x_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .reg_stride = 0x08,
+ .max_register = 0x78,
+ .read_flag_mask = TSC200X_REG_READ,
+ .write_flag_mask = TSC200X_REG_PND0,
+ .wr_table = &tsc200x_writable_table,
+ .use_single_rw = true,
+};
+EXPORT_SYMBOL_GPL(tsc200x_regmap_config);
+
+struct tsc200x_data {
+ u16 x;
+ u16 y;
+ u16 z1;
+ u16 z2;
+} __packed;
+#define TSC200X_DATA_REGS 4
+
+struct tsc200x {
+ struct device *dev;
+ struct regmap *regmap;
+ __u16 bustype;
+
+ struct input_dev *idev;
+ char phys[32];
+
+ struct mutex mutex;
+
+ /* raw copy of previous x,y,z */
+ int in_x;
+ int in_y;
+ int in_z1;
+ int in_z2;
+
+ spinlock_t lock;
+ struct timer_list penup_timer;
+
+ unsigned int esd_timeout;
+ struct delayed_work esd_work;
+ unsigned long last_valid_interrupt;
+
+ unsigned int x_plate_ohm;
+
+ bool opened;
+ bool suspended;
+
+ bool pen_down;
+
+ struct regulator *vio;
+
+ struct gpio_desc *reset_gpio;
+ void (*set_reset)(bool enable);
+ int (*tsc200x_cmd)(struct device *dev, u8 cmd);
+ int irq;
+};
+
+static void tsc200x_update_pen_state(struct tsc200x *ts,
+ int x, int y, int pressure)
+{
+ if (pressure) {
+ input_report_abs(ts->idev, ABS_X, x);
+ input_report_abs(ts->idev, ABS_Y, y);
+ input_report_abs(ts->idev, ABS_PRESSURE, pressure);
+ if (!ts->pen_down) {
+ input_report_key(ts->idev, BTN_TOUCH, !!pressure);
+ ts->pen_down = true;
+ }
+ } else {
+ input_report_abs(ts->idev, ABS_PRESSURE, 0);
+ if (ts->pen_down) {
+ input_report_key(ts->idev, BTN_TOUCH, 0);
+ ts->pen_down = false;
+ }
+ }
+ input_sync(ts->idev);
+ dev_dbg(ts->dev, "point(%4d,%4d), pressure (%4d)\n", x, y,
+ pressure);
+}
+
+static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
+{
+ struct tsc200x *ts = _ts;
+ unsigned long flags;
+ unsigned int pressure;
+ struct tsc200x_data tsdata;
+ int error;
+
+ /* read the coordinates */
+ error = regmap_bulk_read(ts->regmap, TSC200X_REG_X, &tsdata,
+ TSC200X_DATA_REGS);
+ if (unlikely(error))
+ goto out;
+
+ /* validate position */
+ if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT))
+ goto out;
+
+ /* Skip reading if the pressure components are out of range */
+ if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT))
+ goto out;
+ if (unlikely(tsdata.z1 >= tsdata.z2))
+ goto out;
+
+ /*
+ * Skip point if this is a pen down with the exact same values as
+ * the value before pen-up - that implies SPI fed us stale data
+ */
+ if (!ts->pen_down &&
+ ts->in_x == tsdata.x && ts->in_y == tsdata.y &&
+ ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) {
+ goto out;
+ }
+
+ /*
+ * At this point we are happy we have a valid and useful reading.
+ * Remember it for later comparisons. We may now begin downsampling.
+ */
+ ts->in_x = tsdata.x;
+ ts->in_y = tsdata.y;
+ ts->in_z1 = tsdata.z1;
+ ts->in_z2 = tsdata.z2;
+
+ /* Compute touch pressure resistance using equation #1 */
+ pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1;
+ pressure = pressure * ts->x_plate_ohm / 4096;
+ if (unlikely(pressure > MAX_12BIT))
+ goto out;
+
+ spin_lock_irqsave(&ts->lock, flags);
+
+ tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
+
+ spin_unlock_irqrestore(&ts->lock, flags);
+
+ ts->last_valid_interrupt = jiffies;
+out:
+ return IRQ_HANDLED;
+}
+
+static void tsc200x_penup_timer(unsigned long data)
+{
+ struct tsc200x *ts = (struct tsc200x *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ts->lock, flags);
+ tsc200x_update_pen_state(ts, 0, 0, 0);
+ spin_unlock_irqrestore(&ts->lock, flags);
+}
+
+static void tsc200x_start_scan(struct tsc200x *ts)
+{
+ regmap_write(ts->regmap, TSC200X_REG_CFR0, TSC200X_CFR0_INITVALUE);
+ regmap_write(ts->regmap, TSC200X_REG_CFR1, TSC200X_CFR1_INITVALUE);
+ regmap_write(ts->regmap, TSC200X_REG_CFR2, TSC200X_CFR2_INITVALUE);
+ ts->tsc200x_cmd(ts->dev, TSC200X_CMD_NORMAL);
+}
+
+static void tsc200x_stop_scan(struct tsc200x *ts)
+{
+ ts->tsc200x_cmd(ts->dev, TSC200X_CMD_STOP);
+}
+
+static void tsc200x_set_reset(struct tsc200x *ts, bool enable)
+{
+ if (ts->reset_gpio)
+ gpiod_set_value_cansleep(ts->reset_gpio, enable);
+ else if (ts->set_reset)
+ ts->set_reset(enable);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc200x_disable(struct tsc200x *ts)
+{
+ tsc200x_stop_scan(ts);
+
+ disable_irq(ts->irq);
+ del_timer_sync(&ts->penup_timer);
+
+ cancel_delayed_work_sync(&ts->esd_work);
+
+ enable_irq(ts->irq);
+}
+
+/* must be called with ts->mutex held */
+static void __tsc200x_enable(struct tsc200x *ts)
+{
+ tsc200x_start_scan(ts);
+
+ if (ts->esd_timeout && (ts->set_reset || ts->reset_gpio)) {
+ ts->last_valid_interrupt = jiffies;
+ schedule_delayed_work(&ts->esd_work,
+ round_jiffies_relative(
+ msecs_to_jiffies(ts->esd_timeout)));
+ }
+}
+
+static ssize_t tsc200x_selftest_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+ unsigned int temp_high;
+ unsigned int temp_high_orig;
+ unsigned int temp_high_test;
+ bool success = true;
+ int error;
+
+ mutex_lock(&ts->mutex);
+
+ /*
+ * Test TSC200X communications via temp high register.
+ */
+ __tsc200x_disable(ts);
+
+ error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high_orig);
+ if (error) {
+ dev_warn(dev, "selftest failed: read error %d\n", error);
+ success = false;
+ goto out;
+ }
+
+ temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
+
+ error = regmap_write(ts->regmap, TSC200X_REG_TEMP_HIGH, temp_high_test);
+ if (error) {
+ dev_warn(dev, "selftest failed: write error %d\n", error);
+ success = false;
+ goto out;
+ }
+
+ error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
+ if (error) {
+ dev_warn(dev, "selftest failed: read error %d after write\n",
+ error);
+ success = false;
+ goto out;
+ }
+
+ if (temp_high != temp_high_test) {
+ dev_warn(dev, "selftest failed: %d != %d\n",
+ temp_high, temp_high_test);
+ success = false;
+ }
+
+ /* hardware reset */
+ tsc200x_set_reset(ts, false);
+ usleep_range(100, 500); /* only 10us required */
+ tsc200x_set_reset(ts, true);
+
+ if (!success)
+ goto out;
+
+ /* test that the reset really happened */
+ error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
+ if (error) {
+ dev_warn(dev, "selftest failed: read error %d after reset\n",
+ error);
+ success = false;
+ goto out;
+ }
+
+ if (temp_high != temp_high_orig) {
+ dev_warn(dev, "selftest failed after reset: %d != %d\n",
+ temp_high, temp_high_orig);
+ success = false;
+ }
+
+out:
+ __tsc200x_enable(ts);
+ mutex_unlock(&ts->mutex);
+
+ return sprintf(buf, "%d\n", success);
+}
+
+static DEVICE_ATTR(selftest, S_IRUGO, tsc200x_selftest_show, NULL);
+
+static struct attribute *tsc200x_attrs[] = {
+ &dev_attr_selftest.attr,
+ NULL
+};
+
+static umode_t tsc200x_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct tsc200x *ts = dev_get_drvdata(dev);
+ umode_t mode = attr->mode;
+
+ if (attr == &dev_attr_selftest.attr) {
+ if (!ts->set_reset && !ts->reset_gpio)
+ mode = 0;
+ }
+
+ return mode;
+}
+
+static const struct attribute_group tsc200x_attr_group = {
+ .is_visible = tsc200x_attr_is_visible,
+ .attrs = tsc200x_attrs,
+};
+
+static void tsc200x_esd_work(struct work_struct *work)
+{
+ struct tsc200x *ts = container_of(work, struct tsc200x, esd_work.work);
+ int error;
+ unsigned int r;
+
+ if (!mutex_trylock(&ts->mutex)) {
+ /*
+ * If the mutex is taken, it means that disable or enable is in
+ * progress. In that case just reschedule the work. If the work
+ * is not needed, it will be canceled by disable.
+ */
+ goto reschedule;
+ }
+
+ if (time_is_after_jiffies(ts->last_valid_interrupt +
+ msecs_to_jiffies(ts->esd_timeout)))
+ goto out;
+
+ /* We should be able to read register without disabling interrupts. */
+ error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
+ if (!error &&
+ !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
+ goto out;
+ }
+
+ /*
+ * If we could not read our known value from configuration register 0
+ * then we should reset the controller as if from power-up and start
+ * scanning again.
+ */
+ dev_info(ts->dev, "TSC200X not responding - resetting\n");
+
+ disable_irq(ts->irq);
+ del_timer_sync(&ts->penup_timer);
+
+ tsc200x_update_pen_state(ts, 0, 0, 0);
+
+ tsc200x_set_reset(ts, false);
+ usleep_range(100, 500); /* only 10us required */
+ tsc200x_set_reset(ts, true);
+
+ enable_irq(ts->irq);
+ tsc200x_start_scan(ts);
+
+out:
+ mutex_unlock(&ts->mutex);
+reschedule:
+ /* re-arm the watchdog */
+ schedule_delayed_work(&ts->esd_work,
+ round_jiffies_relative(
+ msecs_to_jiffies(ts->esd_timeout)));
+}
+
+static int tsc200x_open(struct input_dev *input)
+{
+ struct tsc200x *ts = input_get_drvdata(input);
+
+ mutex_lock(&ts->mutex);
+
+ if (!ts->suspended)
+ __tsc200x_enable(ts);
+
+ ts->opened = true;
+
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+static void tsc200x_close(struct input_dev *input)
+{
+ struct tsc200x *ts = input_get_drvdata(input);
+
+ mutex_lock(&ts->mutex);
+
+ if (!ts->suspended)
+ __tsc200x_disable(ts);
+
+ ts->opened = false;
+
+ mutex_unlock(&ts->mutex);
+}
+
+int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+ struct regmap *regmap,
+ int (*tsc200x_cmd)(struct device *dev, u8 cmd))
+{
+ const struct tsc2005_platform_data *pdata = dev_get_platdata(dev);
+ struct device_node *np = dev->of_node;
+
+ struct tsc200x *ts;
+ struct input_dev *input_dev;
+ unsigned int max_x = MAX_12BIT;
+ unsigned int max_y = MAX_12BIT;
+ unsigned int max_p = MAX_12BIT;
+ unsigned int fudge_x = TSC200X_DEF_X_FUZZ;
+ unsigned int fudge_y = TSC200X_DEF_Y_FUZZ;
+ unsigned int fudge_p = TSC200X_DEF_P_FUZZ;
+ unsigned int x_plate_ohm = TSC200X_DEF_RESISTOR;
+ unsigned int esd_timeout;
+ int error;
+
+ if (!np && !pdata) {
+ dev_err(dev, "no platform data\n");
+ return -ENODEV;
+ }
+
+ if (irq <= 0) {
+ dev_err(dev, "no irq\n");
+ return -ENODEV;
+ }
+
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ if (!tsc200x_cmd) {
+ dev_err(dev, "no cmd function\n");
+ return -ENODEV;
+ }
+
+ if (pdata) {
+ fudge_x = pdata->ts_x_fudge;
+ fudge_y = pdata->ts_y_fudge;
+ fudge_p = pdata->ts_pressure_fudge;
+ max_x = pdata->ts_x_max;
+ max_y = pdata->ts_y_max;
+ max_p = pdata->ts_pressure_max;
+ x_plate_ohm = pdata->ts_x_plate_ohm;
+ esd_timeout = pdata->esd_timeout_ms;
+ } else {
+ x_plate_ohm = TSC200X_DEF_RESISTOR;
+ of_property_read_u32(np, "ti,x-plate-ohms", &x_plate_ohm);
+ esd_timeout = 0;
+ of_property_read_u32(np, "ti,esd-recovery-timeout-ms",
+ &esd_timeout);
+ }
+
+ ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL);
+ if (!ts)
+ return -ENOMEM;
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ ts->irq = irq;
+ ts->dev = dev;
+ ts->idev = input_dev;
+ ts->regmap = regmap;
+ ts->tsc200x_cmd = tsc200x_cmd;
+ ts->x_plate_ohm = x_plate_ohm;
+ ts->esd_timeout = esd_timeout;
+
+ ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(ts->reset_gpio)) {
+ error = PTR_ERR(ts->reset_gpio);
+ dev_err(dev, "error acquiring reset gpio: %d\n", error);
+ return error;
+ }
+
+ ts->vio = devm_regulator_get_optional(dev, "vio");
+ if (IS_ERR(ts->vio)) {
+ error = PTR_ERR(ts->vio);
+ dev_err(dev, "vio regulator missing (%d)", error);
+ return error;
+ }
+
+ if (!ts->reset_gpio && pdata)
+ ts->set_reset = pdata->set_reset;
+
+ mutex_init(&ts->mutex);
+
+ spin_lock_init(&ts->lock);
+ setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts);
+
+ INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
+
+ snprintf(ts->phys, sizeof(ts->phys),
+ "%s/input-ts", dev_name(dev));
+
+ input_dev->name = "TSC200X touchscreen";
+ input_dev->phys = ts->phys;
+ input_dev->id.bustype = bustype;
+ input_dev->dev.parent = dev;
+ input_dev->evbit[0] = BIT(EV_ABS) | BIT(EV_KEY);
+ input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+
+ input_set_abs_params(input_dev, ABS_X, 0, max_x, fudge_x, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, max_y, fudge_y, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0);
+
+ if (np)
+ touchscreen_parse_properties(input_dev, false);
+
+ input_dev->open = tsc200x_open;
+ input_dev->close = tsc200x_close;
+
+ input_set_drvdata(input_dev, ts);
+
+ /* Ensure the touchscreen is off */
+ tsc200x_stop_scan(ts);
+
+ error = devm_request_threaded_irq(dev, irq, NULL,
+ tsc200x_irq_thread,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "tsc200x", ts);
+ if (error) {
+ dev_err(dev, "Failed to request irq, err: %d\n", error);
+ return error;
+ }
+
+ /* enable regulator for DT */
+ if (ts->vio) {
+ error = regulator_enable(ts->vio);
+ if (error)
+ return error;
+ }
+
+ dev_set_drvdata(dev, ts);
+ error = sysfs_create_group(&dev->kobj, &tsc200x_attr_group);
+ if (error) {
+ dev_err(dev,
+ "Failed to create sysfs attributes, err: %d\n", error);
+ goto disable_regulator;
+ }
+
+ error = input_register_device(ts->idev);
+ if (error) {
+ dev_err(dev,
+ "Failed to register input device, err: %d\n", error);
+ goto err_remove_sysfs;
+ }
+
+ irq_set_irq_wake(irq, 1);
+ return 0;
+
+err_remove_sysfs:
+ sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
+disable_regulator:
+ if (ts->vio)
+ regulator_disable(ts->vio);
+ return error;
+}
+EXPORT_SYMBOL_GPL(tsc200x_probe);
+
+int tsc200x_remove(struct device *dev)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+
+ sysfs_remove_group(&dev->kobj, &tsc200x_attr_group);
+
+ if (ts->vio)
+ regulator_disable(ts->vio);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tsc200x_remove);
+
+static int __maybe_unused tsc200x_suspend(struct device *dev)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+
+ mutex_lock(&ts->mutex);
+
+ if (!ts->suspended && ts->opened)
+ __tsc200x_disable(ts);
+
+ ts->suspended = true;
+
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused tsc200x_resume(struct device *dev)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+
+ mutex_lock(&ts->mutex);
+
+ if (ts->suspended && ts->opened)
+ __tsc200x_enable(ts);
+
+ ts->suspended = false;
+
+ mutex_unlock(&ts->mutex);
+
+ return 0;
+}
+
+SIMPLE_DEV_PM_OPS(tsc200x_pm_ops, tsc200x_suspend, tsc200x_resume);
+EXPORT_SYMBOL_GPL(tsc200x_pm_ops);
+
+MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
+MODULE_DESCRIPTION("TSC200x Touchscreen Driver Core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h
new file mode 100644
index 0000000..7a482d1
--- /dev/null
+++ b/drivers/input/touchscreen/tsc200x-core.h
@@ -0,0 +1,78 @@
+#ifndef _TSC200X_CORE_H
+#define _TSC200X_CORE_H
+
+/* control byte 1 */
+#define TSC200X_CMD 0x80
+#define TSC200X_CMD_NORMAL 0x00
+#define TSC200X_CMD_STOP 0x01
+#define TSC200X_CMD_12BIT 0x04
+
+/* control byte 0 */
+#define TSC200X_REG_READ 0x01 /* R/W access */
+#define TSC200X_REG_PND0 0x02 /* Power Not Down Control */
+#define TSC200X_REG_X (0x0 << 3)
+#define TSC200X_REG_Y (0x1 << 3)
+#define TSC200X_REG_Z1 (0x2 << 3)
+#define TSC200X_REG_Z2 (0x3 << 3)
+#define TSC200X_REG_AUX (0x4 << 3)
+#define TSC200X_REG_TEMP1 (0x5 << 3)
+#define TSC200X_REG_TEMP2 (0x6 << 3)
+#define TSC200X_REG_STATUS (0x7 << 3)
+#define TSC200X_REG_AUX_HIGH (0x8 << 3)
+#define TSC200X_REG_AUX_LOW (0x9 << 3)
+#define TSC200X_REG_TEMP_HIGH (0xA << 3)
+#define TSC200X_REG_TEMP_LOW (0xB << 3)
+#define TSC200X_REG_CFR0 (0xC << 3)
+#define TSC200X_REG_CFR1 (0xD << 3)
+#define TSC200X_REG_CFR2 (0xE << 3)
+#define TSC200X_REG_CONV_FUNC (0xF << 3)
+
+/* configuration register 0 */
+#define TSC200X_CFR0_PRECHARGE_276US 0x0040
+#define TSC200X_CFR0_STABTIME_1MS 0x0300
+#define TSC200X_CFR0_CLOCK_1MHZ 0x1000
+#define TSC200X_CFR0_RESOLUTION12 0x2000
+#define TSC200X_CFR0_PENMODE 0x8000
+#define TSC200X_CFR0_INITVALUE (TSC200X_CFR0_STABTIME_1MS | \
+ TSC200X_CFR0_CLOCK_1MHZ | \
+ TSC200X_CFR0_RESOLUTION12 | \
+ TSC200X_CFR0_PRECHARGE_276US | \
+ TSC200X_CFR0_PENMODE)
+
+/* bits common to both read and write of configuration register 0 */
+#define TSC200X_CFR0_RW_MASK 0x3fff
+
+/* configuration register 1 */
+#define TSC200X_CFR1_BATCHDELAY_4MS 0x0003
+#define TSC200X_CFR1_INITVALUE TSC200X_CFR1_BATCHDELAY_4MS
+
+/* configuration register 2 */
+#define TSC200X_CFR2_MAVE_Z 0x0004
+#define TSC200X_CFR2_MAVE_Y 0x0008
+#define TSC200X_CFR2_MAVE_X 0x0010
+#define TSC200X_CFR2_AVG_7 0x0800
+#define TSC200X_CFR2_MEDIUM_15 0x3000
+#define TSC200X_CFR2_INITVALUE (TSC200X_CFR2_MAVE_X | \
+ TSC200X_CFR2_MAVE_Y | \
+ TSC200X_CFR2_MAVE_Z | \
+ TSC200X_CFR2_MEDIUM_15 | \
+ TSC200X_CFR2_AVG_7)
+
+#define MAX_12BIT 0xfff
+#define TSC200X_DEF_X_FUZZ 4
+#define TSC200X_DEF_Y_FUZZ 8
+#define TSC200X_DEF_P_FUZZ 2
+#define TSC200X_DEF_RESISTOR 280
+
+#define TSC2005_SPI_MAX_SPEED_HZ 10000000
+#define TSC200X_PENUP_TIME_MS 40
+
+extern const struct regmap_config tsc200x_regmap_config;
+extern const struct dev_pm_ops tsc200x_pm_ops;
+
+int tsc200x_probe(struct device *dev, int irq, __u16 bustype,
+ struct regmap *regmap,
+ int (*tsc200x_cmd)(struct device *dev, u8 cmd));
+int tsc200x_remove(struct device *dev);
+
+#endif
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index d21d4ed..7caf2fa 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -494,6 +494,22 @@ static void handle_fault_error(struct fault *fault)
}
}
+static bool access_error(struct vm_area_struct *vma, struct fault *fault)
+{
+ unsigned long requested = 0;
+
+ if (fault->flags & PPR_FAULT_EXEC)
+ requested |= VM_EXEC;
+
+ if (fault->flags & PPR_FAULT_READ)
+ requested |= VM_READ;
+
+ if (fault->flags & PPR_FAULT_WRITE)
+ requested |= VM_WRITE;
+
+ return (requested & ~vma->vm_flags) != 0;
+}
+
static void do_fault(struct work_struct *work)
{
struct fault *fault = container_of(work, struct fault, work);
@@ -516,8 +532,8 @@ static void do_fault(struct work_struct *work)
goto out;
}
- if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) {
- /* handle_mm_fault would BUG_ON() */
+ /* Check if we have the right permissions on the vma */
+ if (access_error(vma, fault)) {
up_read(&mm->mmap_sem);
handle_fault_error(fault);
goto out;
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 3a20db4..72d6182 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -21,10 +21,13 @@
#include <linux/device.h>
#include <linux/dma-iommu.h>
+#include <linux/gfp.h>
#include <linux/huge_mm.h>
#include <linux/iommu.h>
#include <linux/iova.h>
#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/vmalloc.h>
int iommu_dma_init(void)
{
@@ -191,6 +194,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, gfp_t gfp)
{
struct page **pages;
unsigned int i = 0, array_size = count * sizeof(*pages);
+ unsigned int order = MAX_ORDER;
if (array_size <= PAGE_SIZE)
pages = kzalloc(array_size, GFP_KERNEL);
@@ -204,14 +208,15 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count, gfp_t gfp)
while (count) {
struct page *page = NULL;
- int j, order = __fls(count);
+ int j;
/*
* Higher-order allocations are a convenience rather
* than a necessity, hence using __GFP_NORETRY until
* falling back to single-page allocations.
*/
- for (order = min(order, MAX_ORDER); order > 0; order--) {
+ for (order = min_t(unsigned int, order, __fls(count));
+ order > 0; order--) {
page = alloc_pages(gfp | __GFP_NORETRY, order);
if (!page)
continue;
@@ -453,7 +458,7 @@ int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
size_t s_offset = iova_offset(iovad, s->offset);
size_t s_length = s->length;
- sg_dma_address(s) = s->offset;
+ sg_dma_address(s) = s_offset;
sg_dma_len(s) = s_length;
s->offset -= s_offset;
s_length = iova_align(iovad, s_length + s_offset);
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index f1042da..ac73876 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -2159,7 +2159,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
sg_res = aligned_nrpages(sg->offset, sg->length);
sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
sg->dma_length = sg->length;
- pteval = (sg_phys(sg) & PAGE_MASK) | prot;
+ pteval = page_to_phys(sg_page(sg)) | prot;
phys_pfn = pteval >> VTD_PAGE_SHIFT;
}
@@ -3704,7 +3704,7 @@ static int intel_nontranslate_map_sg(struct device *hddev,
for_each_sg(sglist, sg, nelems, i) {
BUG_ON(!sg_page(sg));
- sg->dma_address = sg_phys(sg);
+ sg->dma_address = page_to_phys(sg_page(sg)) + sg->offset;
sg->dma_length = sg->length;
}
return nelems;
diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c
index c69e3f9..5046483 100644
--- a/drivers/iommu/intel-svm.c
+++ b/drivers/iommu/intel-svm.c
@@ -484,6 +484,23 @@ struct page_req_dsc {
};
#define PRQ_RING_MASK ((0x1000 << PRQ_ORDER) - 0x10)
+
+static bool access_error(struct vm_area_struct *vma, struct page_req_dsc *req)
+{
+ unsigned long requested = 0;
+
+ if (req->exe_req)
+ requested |= VM_EXEC;
+
+ if (req->rd_req)
+ requested |= VM_READ;
+
+ if (req->wr_req)
+ requested |= VM_WRITE;
+
+ return (requested & ~vma->vm_flags) != 0;
+}
+
static irqreturn_t prq_event_thread(int irq, void *d)
{
struct intel_iommu *iommu = d;
@@ -539,6 +556,9 @@ static irqreturn_t prq_event_thread(int irq, void *d)
if (!vma || address < vma->vm_start)
goto invalid;
+ if (access_error(vma, req))
+ goto invalid;
+
ret = handle_mm_fault(svm->mm, vma, address,
req->wr_req ? FAULT_FLAG_WRITE : 0);
if (ret & VM_FAULT_ERROR)
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index 1fae188..c12ba45 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -753,7 +753,7 @@ static inline void set_irq_posting_cap(void)
* should have X86_FEATURE_CX16 support, this has been confirmed
* with Intel hardware guys.
*/
- if ( cpu_has_cx16 )
+ if (boot_cpu_has(X86_FEATURE_CX16))
intel_irq_remap_ops.capability |= 1 << IRQ_POSTING_CAP;
for_each_iommu(iommu, drhd)
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index abae363..0e3b009 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1430,7 +1430,7 @@ size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
min_pagesz = 1 << __ffs(domain->ops->pgsize_bitmap);
for_each_sg(sg, s, nents, i) {
- phys_addr_t phys = sg_phys(s);
+ phys_addr_t phys = page_to_phys(sg_page(s)) + s->offset;
/*
* We are mapping on IOMMU page boundaries, so offset within
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 8cf605f..dfb868e 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -295,7 +295,7 @@ static struct iommu_gather_ops ipmmu_gather_ops = {
static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
{
- phys_addr_t ttbr;
+ u64 ttbr;
/*
* Allocate the page table operations.
diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
index cbe198c..471ee36 100644
--- a/drivers/iommu/s390-iommu.c
+++ b/drivers/iommu/s390-iommu.c
@@ -216,6 +216,7 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
u8 *page_addr = (u8 *) (pa & PAGE_MASK);
dma_addr_t start_dma_addr = dma_addr;
unsigned long irq_flags, nr_pages, i;
+ unsigned long *entry;
int rc = 0;
if (dma_addr < s390_domain->domain.geometry.aperture_start ||
@@ -228,8 +229,12 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
spin_lock_irqsave(&s390_domain->dma_table_lock, irq_flags);
for (i = 0; i < nr_pages; i++) {
- dma_update_cpu_trans(s390_domain->dma_table, page_addr,
- dma_addr, flags);
+ entry = dma_walk_cpu_trans(s390_domain->dma_table, dma_addr);
+ if (!entry) {
+ rc = -ENOMEM;
+ goto undo_cpu_trans;
+ }
+ dma_update_cpu_trans(entry, page_addr, flags);
page_addr += PAGE_SIZE;
dma_addr += PAGE_SIZE;
}
@@ -242,6 +247,20 @@ static int s390_iommu_update_trans(struct s390_domain *s390_domain,
break;
}
spin_unlock(&s390_domain->list_lock);
+
+undo_cpu_trans:
+ if (rc && ((flags & ZPCI_PTE_VALID_MASK) == ZPCI_PTE_VALID)) {
+ flags = ZPCI_PTE_INVALID;
+ while (i-- > 0) {
+ page_addr -= PAGE_SIZE;
+ dma_addr -= PAGE_SIZE;
+ entry = dma_walk_cpu_trans(s390_domain->dma_table,
+ dma_addr);
+ if (!entry)
+ break;
+ dma_update_cpu_trans(entry, page_addr, flags);
+ }
+ }
spin_unlock_irqrestore(&s390_domain->dma_table_lock, irq_flags);
return rc;
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 4d7294e..11fc2a2 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -8,6 +8,11 @@ config ARM_GIC
select IRQ_DOMAIN_HIERARCHY
select MULTI_IRQ_HANDLER
+config ARM_GIC_MAX_NR
+ int
+ default 2 if ARCH_REALVIEW
+ default 1
+
config ARM_GIC_V2M
bool
depends on ARM_GIC
@@ -27,6 +32,14 @@ config ARM_GIC_V3_ITS
bool
select PCI_MSI_IRQ_DOMAIN
+config HISILICON_IRQ_MBIGEN
+ bool "Support mbigen interrupt controller"
+ default n
+ depends on ARM_GIC_V3 && ARM_GIC_V3_ITS && GENERIC_MSI_IRQ_DOMAIN
+ help
+ Enable the mbigen interrupt controller used on
+ Hisilicon platform.
+
config ARM_NVIC
bool
select IRQ_DOMAIN
@@ -138,6 +151,12 @@ config TB10X_IRQC
select IRQ_DOMAIN
select GENERIC_IRQ_CHIP
+config TS4800_IRQ
+ tristate "TS-4800 IRQ controller"
+ select IRQ_DOMAIN
+ help
+ Support for the TS-4800 FPGA IRQ controller
+
config VERSATILE_FPGA_IRQ
bool
select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 177f78f..d4c2e4e 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -21,9 +21,11 @@ obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o
obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o
obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o
obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o
+obj-$(CONFIG_REALVIEW_DT) += irq-gic-realview.o
obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o
obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o
obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o
+obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o
obj-$(CONFIG_ARM_NVIC) += irq-nvic.o
obj-$(CONFIG_ARM_VIC) += irq-vic.o
obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o
@@ -39,6 +41,7 @@ obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o
obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o
obj-$(CONFIG_ST_IRQCHIP) += irq-st.o
obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
+obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c
index f687082..963065a 100644
--- a/drivers/irqchip/irq-bcm2836.c
+++ b/drivers/irqchip/irq-bcm2836.c
@@ -21,6 +21,9 @@
#include <linux/irqdomain.h>
#include <asm/exception.h>
+#define LOCAL_CONTROL 0x000
+#define LOCAL_PRESCALER 0x008
+
/*
* The low 2 bits identify the CPU that the GPU IRQ goes to, and the
* next 2 bits identify the CPU that the GPU FIQ goes to.
@@ -50,14 +53,16 @@
/* Same status bits as above, but for FIQ. */
#define LOCAL_FIQ_PENDING0 0x070
/*
- * Mailbox0 write-to-set bits. There are 16 mailboxes, 4 per CPU, and
+ * Mailbox write-to-set bits. There are 16 mailboxes, 4 per CPU, and
* these bits are organized by mailbox number and then CPU number. We
* use mailbox 0 for IPIs. The mailbox's interrupt is raised while
* any bit is set.
*/
#define LOCAL_MAILBOX0_SET0 0x080
-/* Mailbox0 write-to-clear bits. */
+#define LOCAL_MAILBOX3_SET0 0x08c
+/* Mailbox write-to-clear bits. */
#define LOCAL_MAILBOX0_CLR0 0x0c0
+#define LOCAL_MAILBOX3_CLR0 0x0cc
#define LOCAL_IRQ_CNTPSIRQ 0
#define LOCAL_IRQ_CNTPNSIRQ 1
@@ -162,7 +167,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
u32 stat;
stat = readl_relaxed(intc.base + LOCAL_IRQ_PENDING0 + 4 * cpu);
- if (stat & 0x10) {
+ if (stat & BIT(LOCAL_IRQ_MAILBOX0)) {
#ifdef CONFIG_SMP
void __iomem *mailbox0 = (intc.base +
LOCAL_MAILBOX0_CLR0 + 16 * cpu);
@@ -172,7 +177,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs)
writel(1 << ipi, mailbox0);
handle_IPI(ipi, regs);
#endif
- } else {
+ } else if (stat) {
u32 hwirq = ffs(stat) - 1;
handle_IRQ(irq_linear_revmap(intc.domain, hwirq), regs);
@@ -217,6 +222,24 @@ static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
.notifier_call = bcm2836_arm_irqchip_cpu_notify,
.priority = 100,
};
+
+int __init bcm2836_smp_boot_secondary(unsigned int cpu,
+ struct task_struct *idle)
+{
+ unsigned long secondary_startup_phys =
+ (unsigned long)virt_to_phys((void *)secondary_startup);
+
+ dsb();
+ writel(secondary_startup_phys,
+ intc.base + LOCAL_MAILBOX3_SET0 + 16 * cpu);
+
+ return 0;
+}
+
+static const struct smp_operations bcm2836_smp_ops __initconst = {
+ .smp_boot_secondary = bcm2836_smp_boot_secondary,
+};
+
#endif
static const struct irq_domain_ops bcm2836_arm_irqchip_intc_ops = {
@@ -234,9 +257,31 @@ bcm2836_arm_irqchip_smp_init(void)
register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);
+ smp_set_ops(&bcm2836_smp_ops);
#endif
}
+/*
+ * The LOCAL_IRQ_CNT* timer firings are based off of the external
+ * oscillator with some scaling. The firmware sets up CNTFRQ to
+ * report 19.2Mhz, but doesn't set up the scaling registers.
+ */
+static void bcm2835_init_local_timer_frequency(void)
+{
+ /*
+ * Set the timer to source from the 19.2Mhz crystal clock (bit
+ * 8 unset), and only increment by 1 instead of 2 (bit 9
+ * unset).
+ */
+ writel(0, intc.base + LOCAL_CONTROL);
+
+ /*
+ * Set the timer prescaler to 1:1 (timer freq = input freq *
+ * 2**31 / prescaler)
+ */
+ writel(0x80000000, intc.base + LOCAL_PRESCALER);
+}
+
static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
struct device_node *parent)
{
@@ -246,6 +291,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node,
node->full_name);
}
+ bcm2835_init_local_timer_frequency();
+
intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1,
&bcm2836_arm_irqchip_intc_ops,
NULL);
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 44a077f..f174ce0 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -84,12 +84,15 @@ void __init gic_dist_config(void __iomem *base, int gic_irqs,
writel_relaxed(GICD_INT_DEF_PRI_X4, base + GIC_DIST_PRI + i);
/*
- * Disable all interrupts. Leave the PPI and SGIs alone
- * as they are enabled by redistributor registers.
+ * Deactivate and disable all SPIs. Leave the PPI and SGIs
+ * alone as they are in the redistributor registers on GICv3.
*/
- for (i = 32; i < gic_irqs; i += 32)
+ for (i = 32; i < gic_irqs; i += 32) {
writel_relaxed(GICD_INT_EN_CLR_X32,
- base + GIC_DIST_ENABLE_CLEAR + i / 8);
+ base + GIC_DIST_ACTIVE_CLEAR + i / 8);
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ base + GIC_DIST_ENABLE_CLEAR + i / 8);
+ }
if (sync_access)
sync_access();
@@ -102,7 +105,9 @@ void gic_cpu_config(void __iomem *base, void (*sync_access)(void))
/*
* Deal with the banked PPI and SGI interrupts - disable all
* PPI interrupts, ensure all SGI interrupts are enabled.
+ * Make sure everything is deactivated.
*/
+ writel_relaxed(GICD_INT_EN_CLR_X32, base + GIC_DIST_ACTIVE_CLEAR);
writel_relaxed(GICD_INT_EN_CLR_PPI, base + GIC_DIST_ENABLE_CLEAR);
writel_relaxed(GICD_INT_EN_SET_SGI, base + GIC_DIST_ENABLE_SET);
diff --git a/drivers/irqchip/irq-gic-realview.c b/drivers/irqchip/irq-gic-realview.c
new file mode 100644
index 0000000..aa46eb2
--- /dev/null
+++ b/drivers/irqchip/irq-gic-realview.c
@@ -0,0 +1,43 @@
+/*
+ * Special GIC quirks for the ARM RealView
+ * Copyright (C) 2015 Linus Walleij
+ */
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/bitops.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/arm-gic.h>
+
+#define REALVIEW_SYS_LOCK_OFFSET 0x20
+#define REALVIEW_PB11MP_SYS_PLD_CTRL1 0x74
+#define VERSATILE_LOCK_VAL 0xA05F
+#define PLD_INTMODE_MASK BIT(22)|BIT(23)|BIT(24)
+#define PLD_INTMODE_LEGACY 0x0
+#define PLD_INTMODE_NEW_DCC BIT(22)
+#define PLD_INTMODE_NEW_NO_DCC BIT(23)
+#define PLD_INTMODE_FIQ_ENABLE BIT(24)
+
+static int __init
+realview_gic_of_init(struct device_node *node, struct device_node *parent)
+{
+ static struct regmap *map;
+
+ /* The PB11MPCore GIC needs to be configured in the syscon */
+ map = syscon_regmap_lookup_by_compatible("arm,realview-pb11mp-syscon");
+ if (!IS_ERR(map)) {
+ /* new irq mode with no DCC */
+ regmap_write(map, REALVIEW_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
+ regmap_update_bits(map, REALVIEW_PB11MP_SYS_PLD_CTRL1,
+ PLD_INTMODE_NEW_NO_DCC,
+ PLD_INTMODE_MASK);
+ regmap_write(map, REALVIEW_SYS_LOCK_OFFSET, 0x0000);
+ pr_info("TC11MP GIC: set up interrupt controller to NEW mode, no DCC\n");
+ } else {
+ pr_err("TC11MP GIC setup: could not find syscon\n");
+ return -ENXIO;
+ }
+ return gic_of_init(node, parent);
+}
+IRQCHIP_DECLARE(armtc11mp_gic, "arm,tc11mp-gic", realview_gic_of_init);
diff --git a/drivers/irqchip/irq-gic-v2m.c b/drivers/irqchip/irq-gic-v2m.c
index 87f8d10..c779f83 100644
--- a/drivers/irqchip/irq-gic-v2m.c
+++ b/drivers/irqchip/irq-gic-v2m.c
@@ -15,9 +15,11 @@
#define pr_fmt(fmt) "GICv2m: " fmt
+#include <linux/acpi.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/kernel.h>
+#include <linux/msi.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
@@ -55,7 +57,7 @@ static DEFINE_SPINLOCK(v2m_lock);
struct v2m_data {
struct list_head entry;
- struct device_node *node;
+ struct fwnode_handle *fwnode;
struct resource res; /* GICv2m resource */
void __iomem *base; /* GICv2m virt address */
u32 spi_start; /* The SPI number that MSIs start */
@@ -138,6 +140,11 @@ static int gicv2m_irq_gic_domain_alloc(struct irq_domain *domain,
fwspec.param[0] = 0;
fwspec.param[1] = hwirq - 32;
fwspec.param[2] = IRQ_TYPE_EDGE_RISING;
+ } else if (is_fwnode_irqchip(domain->parent->fwnode)) {
+ fwspec.fwnode = domain->parent->fwnode;
+ fwspec.param_count = 2;
+ fwspec.param[0] = hwirq;
+ fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
} else {
return -EINVAL;
}
@@ -254,7 +261,9 @@ static void gicv2m_teardown(void)
list_del(&v2m->entry);
kfree(v2m->bm);
iounmap(v2m->base);
- of_node_put(v2m->node);
+ of_node_put(to_of_node(v2m->fwnode));
+ if (is_fwnode_irqchip(v2m->fwnode))
+ irq_domain_free_fwnode(v2m->fwnode);
kfree(v2m);
}
}
@@ -268,7 +277,7 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
if (!v2m)
return 0;
- inner_domain = irq_domain_create_tree(of_node_to_fwnode(v2m->node),
+ inner_domain = irq_domain_create_tree(v2m->fwnode,
&gicv2m_domain_ops, v2m);
if (!inner_domain) {
pr_err("Failed to create GICv2m domain\n");
@@ -277,10 +286,10 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
inner_domain->bus_token = DOMAIN_BUS_NEXUS;
inner_domain->parent = parent;
- pci_domain = pci_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+ pci_domain = pci_msi_create_irq_domain(v2m->fwnode,
&gicv2m_msi_domain_info,
inner_domain);
- plat_domain = platform_msi_create_irq_domain(of_node_to_fwnode(v2m->node),
+ plat_domain = platform_msi_create_irq_domain(v2m->fwnode,
&gicv2m_pmsi_domain_info,
inner_domain);
if (!pci_domain || !plat_domain) {
@@ -296,8 +305,9 @@ static int gicv2m_allocate_domains(struct irq_domain *parent)
return 0;
}
-static int __init gicv2m_init_one(struct device_node *node,
- struct irq_domain *parent)
+static int __init gicv2m_init_one(struct fwnode_handle *fwnode,
+ u32 spi_start, u32 nr_spis,
+ struct resource *res)
{
int ret;
struct v2m_data *v2m;
@@ -309,13 +319,9 @@ static int __init gicv2m_init_one(struct device_node *node,
}
INIT_LIST_HEAD(&v2m->entry);
- v2m->node = node;
+ v2m->fwnode = fwnode;
- ret = of_address_to_resource(node, 0, &v2m->res);
- if (ret) {
- pr_err("Failed to allocate v2m resource.\n");
- goto err_free_v2m;
- }
+ memcpy(&v2m->res, res, sizeof(struct resource));
v2m->base = ioremap(v2m->res.start, resource_size(&v2m->res));
if (!v2m->base) {
@@ -324,10 +330,9 @@ static int __init gicv2m_init_one(struct device_node *node,
goto err_free_v2m;
}
- if (!of_property_read_u32(node, "arm,msi-base-spi", &v2m->spi_start) &&
- !of_property_read_u32(node, "arm,msi-num-spis", &v2m->nr_spis)) {
- pr_info("Overriding V2M MSI_TYPER (base:%u, num:%u)\n",
- v2m->spi_start, v2m->nr_spis);
+ if (spi_start && nr_spis) {
+ v2m->spi_start = spi_start;
+ v2m->nr_spis = nr_spis;
} else {
u32 typer = readl_relaxed(v2m->base + V2M_MSI_TYPER);
@@ -359,10 +364,9 @@ static int __init gicv2m_init_one(struct device_node *node,
}
list_add_tail(&v2m->entry, &v2m_nodes);
- pr_info("Node %s: range[%#lx:%#lx], SPI[%d:%d]\n", node->name,
- (unsigned long)v2m->res.start, (unsigned long)v2m->res.end,
- v2m->spi_start, (v2m->spi_start + v2m->nr_spis));
+ pr_info("range%pR, SPI[%d:%d]\n", res,
+ v2m->spi_start, (v2m->spi_start + v2m->nr_spis - 1));
return 0;
err_iounmap:
@@ -377,19 +381,36 @@ static struct of_device_id gicv2m_device_id[] = {
{},
};
-int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
+static int __init gicv2m_of_init(struct fwnode_handle *parent_handle,
+ struct irq_domain *parent)
{
int ret = 0;
+ struct device_node *node = to_of_node(parent_handle);
struct device_node *child;
for (child = of_find_matching_node(node, gicv2m_device_id); child;
child = of_find_matching_node(child, gicv2m_device_id)) {
+ u32 spi_start = 0, nr_spis = 0;
+ struct resource res;
+
if (!of_find_property(child, "msi-controller", NULL))
continue;
- ret = gicv2m_init_one(child, parent);
+ ret = of_address_to_resource(child, 0, &res);
+ if (ret) {
+ pr_err("Failed to allocate v2m resource.\n");
+ break;
+ }
+
+ if (!of_property_read_u32(child, "arm,msi-base-spi",
+ &spi_start) &&
+ !of_property_read_u32(child, "arm,msi-num-spis", &nr_spis))
+ pr_info("DT overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+ spi_start, nr_spis);
+
+ ret = gicv2m_init_one(&child->fwnode, spi_start, nr_spis, &res);
if (ret) {
- of_node_put(node);
+ of_node_put(child);
break;
}
}
@@ -400,3 +421,101 @@ int __init gicv2m_of_init(struct device_node *node, struct irq_domain *parent)
gicv2m_teardown();
return ret;
}
+
+#ifdef CONFIG_ACPI
+static int acpi_num_msi;
+
+static struct fwnode_handle *gicv2m_get_fwnode(struct device *dev)
+{
+ struct v2m_data *data;
+
+ if (WARN_ON(acpi_num_msi <= 0))
+ return NULL;
+
+ /* We only return the fwnode of the first MSI frame. */
+ data = list_first_entry_or_null(&v2m_nodes, struct v2m_data, entry);
+ if (!data)
+ return NULL;
+
+ return data->fwnode;
+}
+
+static int __init
+acpi_parse_madt_msi(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ int ret;
+ struct resource res;
+ u32 spi_start = 0, nr_spis = 0;
+ struct acpi_madt_generic_msi_frame *m;
+ struct fwnode_handle *fwnode;
+
+ m = (struct acpi_madt_generic_msi_frame *)header;
+ if (BAD_MADT_ENTRY(m, end))
+ return -EINVAL;
+
+ res.start = m->base_address;
+ res.end = m->base_address + SZ_4K - 1;
+ res.flags = IORESOURCE_MEM;
+
+ if (m->flags & ACPI_MADT_OVERRIDE_SPI_VALUES) {
+ spi_start = m->spi_base;
+ nr_spis = m->spi_count;
+
+ pr_info("ACPI overriding V2M MSI_TYPER (base:%u, num:%u)\n",
+ spi_start, nr_spis);
+ }
+
+ fwnode = irq_domain_alloc_fwnode((void *)m->base_address);
+ if (!fwnode) {
+ pr_err("Unable to allocate GICv2m domain token\n");
+ return -EINVAL;
+ }
+
+ ret = gicv2m_init_one(fwnode, spi_start, nr_spis, &res);
+ if (ret)
+ irq_domain_free_fwnode(fwnode);
+
+ return ret;
+}
+
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+ int ret;
+
+ if (acpi_num_msi > 0)
+ return 0;
+
+ acpi_num_msi = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_MSI_FRAME,
+ acpi_parse_madt_msi, 0);
+
+ if (acpi_num_msi <= 0)
+ goto err_out;
+
+ ret = gicv2m_allocate_domains(parent);
+ if (ret)
+ goto err_out;
+
+ pci_msi_register_fwnode_provider(&gicv2m_get_fwnode);
+
+ return 0;
+
+err_out:
+ gicv2m_teardown();
+ return -EINVAL;
+}
+#else /* CONFIG_ACPI */
+static int __init gicv2m_acpi_init(struct irq_domain *parent)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_ACPI */
+
+int __init gicv2m_init(struct fwnode_handle *parent_handle,
+ struct irq_domain *parent)
+{
+ if (is_of_node(parent_handle))
+ return gicv2m_of_init(parent_handle, parent);
+
+ return gicv2m_acpi_init(parent);
+}
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 515c823..911758c 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -69,13 +69,16 @@ union gic_base {
};
struct gic_chip_data {
+ struct irq_chip chip;
union gic_base dist_base;
union gic_base cpu_base;
#ifdef CONFIG_CPU_PM
u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
u32 __percpu *saved_ppi_enable;
+ u32 __percpu *saved_ppi_active;
u32 __percpu *saved_ppi_conf;
#endif
struct irq_domain *domain;
@@ -97,11 +100,7 @@ static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
-#ifndef MAX_GIC_NR
-#define MAX_GIC_NR 1
-#endif
-
-static struct gic_chip_data gic_data[MAX_GIC_NR] __read_mostly;
+static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
#ifdef CONFIG_GIC_NON_BANKED
static void __iomem *gic_get_percpu_base(union gic_base *base)
@@ -334,7 +333,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
- if (likely(irqnr > 15 && irqnr < 1021)) {
+ if (likely(irqnr > 15 && irqnr < 1020)) {
if (static_key_true(&supports_deactivate))
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);
handle_domain_irq(gic->domain, irqnr, regs);
@@ -381,7 +380,6 @@ static void gic_handle_cascade_irq(struct irq_desc *desc)
}
static struct irq_chip gic_chip = {
- .name = "GIC",
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
.irq_eoi = gic_eoi_irq,
@@ -415,8 +413,7 @@ static struct irq_chip gic_eoimode1_chip = {
void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
{
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq,
&gic_data[gic_nr]);
}
@@ -522,7 +519,7 @@ int gic_cpu_if_down(unsigned int gic_nr)
void __iomem *cpu_base;
u32 val = 0;
- if (gic_nr >= MAX_GIC_NR)
+ if (gic_nr >= CONFIG_ARM_GIC_MAX_NR)
return -EINVAL;
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -546,8 +543,7 @@ static void gic_dist_save(unsigned int gic_nr)
void __iomem *dist_base;
int i;
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
gic_irqs = gic_data[gic_nr].gic_irqs;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
@@ -566,6 +562,10 @@ static void gic_dist_save(unsigned int gic_nr)
for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
gic_data[gic_nr].saved_spi_enable[i] =
readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ gic_data[gic_nr].saved_spi_active[i] =
+ readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
}
/*
@@ -581,8 +581,7 @@ static void gic_dist_restore(unsigned int gic_nr)
unsigned int i;
void __iomem *dist_base;
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
gic_irqs = gic_data[gic_nr].gic_irqs;
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
@@ -604,9 +603,19 @@ static void gic_dist_restore(unsigned int gic_nr)
writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
dist_base + GIC_DIST_TARGET + i * 4);
- for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
dist_base + GIC_DIST_ENABLE_SET + i * 4);
+ }
+
+ for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
+ writel_relaxed(gic_data[gic_nr].saved_spi_active[i],
+ dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+ }
writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
}
@@ -618,8 +627,7 @@ static void gic_cpu_save(unsigned int gic_nr)
void __iomem *dist_base;
void __iomem *cpu_base;
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -631,6 +639,10 @@ static void gic_cpu_save(unsigned int gic_nr)
for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
+ ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+
ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
@@ -644,8 +656,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
void __iomem *dist_base;
void __iomem *cpu_base;
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
@@ -654,8 +665,18 @@ static void gic_cpu_restore(unsigned int gic_nr)
return;
ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
- for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
+ }
+
+ ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+ for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
+ writel_relaxed(GICD_INT_EN_CLR_X32,
+ dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
+ writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4);
+ }
ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
@@ -673,7 +694,7 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
int i;
- for (i = 0; i < MAX_GIC_NR; i++) {
+ for (i = 0; i < CONFIG_ARM_GIC_MAX_NR; i++) {
#ifdef CONFIG_GIC_NON_BANKED
/* Skip over unused GICs */
if (!gic_data[i].get_base)
@@ -710,6 +731,10 @@ static void __init gic_pm_init(struct gic_chip_data *gic)
sizeof(u32));
BUG_ON(!gic->saved_ppi_enable);
+ gic->saved_ppi_active = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
+ sizeof(u32));
+ BUG_ON(!gic->saved_ppi_active);
+
gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
sizeof(u32));
BUG_ON(!gic->saved_ppi_conf);
@@ -801,8 +826,7 @@ void gic_migrate_target(unsigned int new_cpu_id)
int i, ror_val, cpu = smp_processor_id();
u32 val, cur_target_mask, active_mask;
- if (gic_nr >= MAX_GIC_NR)
- BUG();
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
dist_base = gic_data_dist_base(&gic_data[gic_nr]);
if (!dist_base)
@@ -891,20 +915,15 @@ void __init gic_init_physaddr(struct device_node *node)
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
- struct irq_chip *chip = &gic_chip;
-
- if (static_key_true(&supports_deactivate)) {
- if (d->host_data == (void *)&gic_data[0])
- chip = &gic_eoimode1_chip;
- }
+ struct gic_chip_data *gic = d->host_data;
if (hw < 32) {
irq_set_percpu_devid(irq);
- irq_domain_set_info(d, irq, hw, chip, d->host_data,
+ irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
handle_percpu_devid_irq, NULL, NULL);
irq_set_status_flags(irq, IRQ_NOAUTOEN);
} else {
- irq_domain_set_info(d, irq, hw, chip, d->host_data,
+ irq_domain_set_info(d, irq, hw, &gic->chip, d->host_data,
handle_fasteoi_irq, NULL, NULL);
irq_set_probe(irq);
}
@@ -938,7 +957,7 @@ static int gic_irq_domain_translate(struct irq_domain *d,
return 0;
}
- if (fwspec->fwnode->type == FWNODE_IRQCHIP) {
+ if (is_fwnode_irqchip(fwspec->fwnode)) {
if(fwspec->param_count != 2)
return -EINVAL;
@@ -1006,11 +1025,20 @@ static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
struct gic_chip_data *gic;
int gic_irqs, irq_base, i;
- BUG_ON(gic_nr >= MAX_GIC_NR);
+ BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
gic_check_cpu_features();
gic = &gic_data[gic_nr];
+
+ /* Initialize irq_chip */
+ if (static_key_true(&supports_deactivate) && gic_nr == 0) {
+ gic->chip = gic_eoimode1_chip;
+ } else {
+ gic->chip = gic_chip;
+ gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
+ }
+
#ifdef CONFIG_GIC_NON_BANKED
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;
@@ -1162,7 +1190,7 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
return true;
}
-static int __init
+int __init
gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
@@ -1200,7 +1228,7 @@ gic_of_init(struct device_node *node, struct device_node *parent)
}
if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
- gicv2m_of_init(node, gic_data[gic_cnt].domain);
+ gicv2m_init(&node->fwnode, gic_data[gic_cnt].domain);
gic_cnt++;
return 0;
@@ -1325,6 +1353,10 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
__gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, domain_handle);
+
+ if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
+ gicv2m_init(NULL, gic_data[0].domain);
+
return 0;
}
IRQCHIP_ACPI_DECLARE(gic_v2, ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR,
diff --git a/drivers/irqchip/irq-mbigen.c b/drivers/irqchip/irq-mbigen.c
new file mode 100644
index 0000000..4dd3eb8
--- /dev/null
+++ b/drivers/irqchip/irq-mbigen.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2015 Hisilicon Limited, All Rights Reserved.
+ * Author: Jun Ma <majun258@huawei.com>
+ * Author: Yun Wu <wuyun.wu@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+/* Interrupt numbers per mbigen node supported */
+#define IRQS_PER_MBIGEN_NODE 128
+
+/* 64 irqs (Pin0-pin63) are reserved for each mbigen chip */
+#define RESERVED_IRQ_PER_MBIGEN_CHIP 64
+
+/* The maximum IRQ pin number of mbigen chip(start from 0) */
+#define MAXIMUM_IRQ_PIN_NUM 1407
+
+/**
+ * In mbigen vector register
+ * bit[21:12]: event id value
+ * bit[11:0]: device id
+ */
+#define IRQ_EVENT_ID_SHIFT 12
+#define IRQ_EVENT_ID_MASK 0x3ff
+
+/* register range of each mbigen node */
+#define MBIGEN_NODE_OFFSET 0x1000
+
+/* offset of vector register in mbigen node */
+#define REG_MBIGEN_VEC_OFFSET 0x200
+
+/**
+ * offset of clear register in mbigen node
+ * This register is used to clear the status
+ * of interrupt
+ */
+#define REG_MBIGEN_CLEAR_OFFSET 0xa000
+
+/**
+ * offset of interrupt type register
+ * This register is used to configure interrupt
+ * trigger type
+ */
+#define REG_MBIGEN_TYPE_OFFSET 0x0
+
+/**
+ * struct mbigen_device - holds the information of mbigen device.
+ *
+ * @pdev: pointer to the platform device structure of mbigen chip.
+ * @base: mapped address of this mbigen chip.
+ */
+struct mbigen_device {
+ struct platform_device *pdev;
+ void __iomem *base;
+};
+
+static inline unsigned int get_mbigen_vec_reg(irq_hw_number_t hwirq)
+{
+ unsigned int nid, pin;
+
+ hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+ nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+ pin = hwirq % IRQS_PER_MBIGEN_NODE;
+
+ return pin * 4 + nid * MBIGEN_NODE_OFFSET
+ + REG_MBIGEN_VEC_OFFSET;
+}
+
+static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
+ u32 *mask, u32 *addr)
+{
+ unsigned int nid, irq_ofst, ofst;
+
+ hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+ nid = hwirq / IRQS_PER_MBIGEN_NODE + 1;
+ irq_ofst = hwirq % IRQS_PER_MBIGEN_NODE;
+
+ *mask = 1 << (irq_ofst % 32);
+ ofst = irq_ofst / 32 * 4;
+
+ *addr = ofst + nid * MBIGEN_NODE_OFFSET
+ + REG_MBIGEN_TYPE_OFFSET;
+}
+
+static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
+ u32 *mask, u32 *addr)
+{
+ unsigned int ofst;
+
+ hwirq -= RESERVED_IRQ_PER_MBIGEN_CHIP;
+ ofst = hwirq / 32 * 4;
+
+ *mask = 1 << (hwirq % 32);
+ *addr = ofst + REG_MBIGEN_CLEAR_OFFSET;
+}
+
+static void mbigen_eoi_irq(struct irq_data *data)
+{
+ void __iomem *base = data->chip_data;
+ u32 mask, addr;
+
+ get_mbigen_clear_reg(data->hwirq, &mask, &addr);
+
+ writel_relaxed(mask, base + addr);
+
+ irq_chip_eoi_parent(data);
+}
+
+static int mbigen_set_type(struct irq_data *data, unsigned int type)
+{
+ void __iomem *base = data->chip_data;
+ u32 mask, addr, val;
+
+ if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+ return -EINVAL;
+
+ get_mbigen_type_reg(data->hwirq, &mask, &addr);
+
+ val = readl_relaxed(base + addr);
+
+ if (type == IRQ_TYPE_LEVEL_HIGH)
+ val |= mask;
+ else
+ val &= ~mask;
+
+ writel_relaxed(val, base + addr);
+
+ return 0;
+}
+
+static struct irq_chip mbigen_irq_chip = {
+ .name = "mbigen-v2",
+ .irq_mask = irq_chip_mask_parent,
+ .irq_unmask = irq_chip_unmask_parent,
+ .irq_eoi = mbigen_eoi_irq,
+ .irq_set_type = mbigen_set_type,
+ .irq_set_affinity = irq_chip_set_affinity_parent,
+};
+
+static void mbigen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+ struct irq_data *d = irq_get_irq_data(desc->irq);
+ void __iomem *base = d->chip_data;
+ u32 val;
+
+ base += get_mbigen_vec_reg(d->hwirq);
+ val = readl_relaxed(base);
+
+ val &= ~(IRQ_EVENT_ID_MASK << IRQ_EVENT_ID_SHIFT);
+ val |= (msg->data << IRQ_EVENT_ID_SHIFT);
+
+ /* The address of doorbell is encoded in mbigen register by default
+ * So,we don't need to program the doorbell address at here
+ */
+ writel_relaxed(val, base);
+}
+
+static int mbigen_domain_translate(struct irq_domain *d,
+ struct irq_fwspec *fwspec,
+ unsigned long *hwirq,
+ unsigned int *type)
+{
+ if (is_of_node(fwspec->fwnode)) {
+ if (fwspec->param_count != 2)
+ return -EINVAL;
+
+ if ((fwspec->param[0] > MAXIMUM_IRQ_PIN_NUM) ||
+ (fwspec->param[0] < RESERVED_IRQ_PER_MBIGEN_CHIP))
+ return -EINVAL;
+ else
+ *hwirq = fwspec->param[0];
+
+ /* If there is no valid irq type, just use the default type */
+ if ((fwspec->param[1] == IRQ_TYPE_EDGE_RISING) ||
+ (fwspec->param[1] == IRQ_TYPE_LEVEL_HIGH))
+ *type = fwspec->param[1];
+ else
+ return -EINVAL;
+
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int mbigen_irq_domain_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs,
+ void *args)
+{
+ struct irq_fwspec *fwspec = args;
+ irq_hw_number_t hwirq;
+ unsigned int type;
+ struct mbigen_device *mgn_chip;
+ int i, err;
+
+ err = mbigen_domain_translate(domain, fwspec, &hwirq, &type);
+ if (err)
+ return err;
+
+ err = platform_msi_domain_alloc(domain, virq, nr_irqs);
+ if (err)
+ return err;
+
+ mgn_chip = platform_msi_get_host_data(domain);
+
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &mbigen_irq_chip, mgn_chip->base);
+
+ return 0;
+}
+
+static struct irq_domain_ops mbigen_domain_ops = {
+ .translate = mbigen_domain_translate,
+ .alloc = mbigen_irq_domain_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static int mbigen_device_probe(struct platform_device *pdev)
+{
+ struct mbigen_device *mgn_chip;
+ struct resource *res;
+ struct irq_domain *domain;
+ u32 num_pins;
+
+ mgn_chip = devm_kzalloc(&pdev->dev, sizeof(*mgn_chip), GFP_KERNEL);
+ if (!mgn_chip)
+ return -ENOMEM;
+
+ mgn_chip->pdev = pdev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mgn_chip->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mgn_chip->base))
+ return PTR_ERR(mgn_chip->base);
+
+ if (of_property_read_u32(pdev->dev.of_node, "num-pins", &num_pins) < 0) {
+ dev_err(&pdev->dev, "No num-pins property\n");
+ return -EINVAL;
+ }
+
+ domain = platform_msi_create_device_domain(&pdev->dev, num_pins,
+ mbigen_write_msg,
+ &mbigen_domain_ops,
+ mgn_chip);
+
+ if (!domain)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mgn_chip);
+
+ dev_info(&pdev->dev, "Allocated %d MSIs\n", num_pins);
+
+ return 0;
+}
+
+static const struct of_device_id mbigen_of_match[] = {
+ { .compatible = "hisilicon,mbigen-v2" },
+ { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, mbigen_of_match);
+
+static struct platform_driver mbigen_platform_driver = {
+ .driver = {
+ .name = "Hisilicon MBIGEN-V2",
+ .owner = THIS_MODULE,
+ .of_match_table = mbigen_of_match,
+ },
+ .probe = mbigen_device_probe,
+};
+
+module_platform_driver(mbigen_platform_driver);
+
+MODULE_AUTHOR("Jun Ma <majun258@huawei.com>");
+MODULE_AUTHOR("Yun Wu <wuyun.wu@huawei.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Hisilicon MBI Generator driver");
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index aeaa061..9e17ef2 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -29,6 +29,7 @@ struct gic_pcpu_mask {
DECLARE_BITMAP(pcpu_mask, GIC_MAX_INTRS);
};
+static unsigned long __gic_base_addr;
static void __iomem *gic_base;
static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
static DEFINE_SPINLOCK(gic_lock);
@@ -301,6 +302,17 @@ int gic_get_c0_fdc_int(void)
GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_FDC));
}
+int gic_get_usm_range(struct resource *gic_usm_res)
+{
+ if (!gic_present)
+ return -1;
+
+ gic_usm_res->start = __gic_base_addr + USM_VISIBLE_SECTION_OFS;
+ gic_usm_res->end = gic_usm_res->start + (USM_VISIBLE_SECTION_SIZE - 1);
+
+ return 0;
+}
+
static void gic_handle_shared_int(bool chained)
{
unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4;
@@ -798,6 +810,8 @@ static void __init __gic_init(unsigned long gic_base_addr,
{
unsigned int gicconfig;
+ __gic_base_addr = gic_base_addr;
+
gic_base = ioremap_nocache(gic_base_addr, gic_addrspace_size);
gicconfig = gic_read(GIC_REG(SHARED, GIC_SH_CONFIG));
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c
index 8587d0f..9d1bcfc 100644
--- a/drivers/irqchip/irq-omap-intc.c
+++ b/drivers/irqchip/irq-omap-intc.c
@@ -47,6 +47,7 @@
#define INTC_ILR0 0x0100
#define ACTIVEIRQ_MASK 0x7f /* omap2/3 active interrupt bits */
+#define SPURIOUSIRQ_MASK (0x1ffffff << 7)
#define INTCPS_NR_ILR_REGS 128
#define INTCPS_NR_MIR_REGS 4
@@ -207,7 +208,6 @@ static int __init omap_alloc_gc_of(struct irq_domain *d, void __iomem *base)
ct = gc->chip_types;
ct->type = IRQ_TYPE_LEVEL_MASK;
- ct->handler = handle_level_irq;
ct->chip.irq_ack = omap_mask_ack_irq;
ct->chip.irq_mask = irq_gc_mask_disable_reg;
@@ -330,11 +330,35 @@ static int __init omap_init_irq(u32 base, struct device_node *node)
static asmlinkage void __exception_irq_entry
omap_intc_handle_irq(struct pt_regs *regs)
{
+ extern unsigned long irq_err_count;
u32 irqnr;
irqnr = intc_readl(INTC_SIR);
+
+ /*
+ * A spurious IRQ can result if interrupt that triggered the
+ * sorting is no longer active during the sorting (10 INTC
+ * functional clock cycles after interrupt assertion). Or a
+ * change in interrupt mask affected the result during sorting
+ * time. There is no special handling required except ignoring
+ * the SIR register value just read and retrying.
+ * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K
+ *
+ * Many a times, a spurious interrupt situation has been fixed
+ * by adding a flush for the posted write acking the IRQ in
+ * the device driver. Typically, this is going be the device
+ * driver whose interrupt was handled just before the spurious
+ * IRQ occurred. Pay attention to those device drivers if you
+ * run into hitting the spurious IRQ condition below.
+ */
+ if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) {
+ pr_err_once("%s: spurious irq!\n", __func__);
+ irq_err_count++;
+ omap_ack_irq(NULL);
+ return;
+ }
+
irqnr &= ACTIVEIRQ_MASK;
- WARN_ONCE(!irqnr, "Spurious IRQ ?\n");
handle_domain_irq(domain, irqnr, regs);
}
diff --git a/drivers/irqchip/irq-renesas-h8300h.c b/drivers/irqchip/irq-renesas-h8300h.c
index 6fd30d5..c378768 100644
--- a/drivers/irqchip/irq-renesas-h8300h.c
+++ b/drivers/irqchip/irq-renesas-h8300h.c
@@ -21,9 +21,9 @@ static const char ipr_bit[] = {
10, 10, 10, 10, 9, 9, 9, 9,
};
-static void *intc_baseaddr;
+static void __iomem *intc_baseaddr;
-#define IPR ((unsigned long)intc_baseaddr + 6)
+#define IPR (intc_baseaddr + 6)
static void h8300h_disable_irq(struct irq_data *data)
{
@@ -81,8 +81,8 @@ static int __init h8300h_intc_of_init(struct device_node *intc,
BUG_ON(!intc_baseaddr);
/* All interrupt priority low */
- ctrl_outb(0x00, IPR + 0);
- ctrl_outb(0x00, IPR + 1);
+ writeb(0x00, IPR + 0);
+ writeb(0x00, IPR + 1);
domain = irq_domain_add_linear(intc, NR_IRQS, &irq_ops, NULL);
BUG_ON(!domain);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index c325806..713177d 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/of_device.h>
-#include <linux/platform_data/irq-renesas-intc-irqpin.h>
#include <linux/pm_runtime.h>
#define INTC_IRQPIN_MAX 8 /* maximum 8 interrupts per driver instance */
@@ -75,18 +74,20 @@ struct intc_irqpin_irq {
struct intc_irqpin_priv {
struct intc_irqpin_iomem iomem[INTC_IRQPIN_REG_NR];
struct intc_irqpin_irq irq[INTC_IRQPIN_MAX];
- struct renesas_intc_irqpin_config config;
- unsigned int number_of_irqs;
+ unsigned int sense_bitfield_width;
struct platform_device *pdev;
struct irq_chip irq_chip;
struct irq_domain *irq_domain;
struct clk *clk;
- bool shared_irqs;
+ unsigned shared_irqs:1;
+ unsigned needs_clk:1;
u8 shared_irq_mask;
};
-struct intc_irqpin_irlm_config {
+struct intc_irqpin_config {
unsigned int irlm_bit;
+ unsigned needs_irlm:1;
+ unsigned needs_clk:1;
};
static unsigned long intc_irqpin_read32(void __iomem *iomem)
@@ -171,7 +172,7 @@ static void intc_irqpin_mask_unmask_prio(struct intc_irqpin_priv *p,
static int intc_irqpin_set_sense(struct intc_irqpin_priv *p, int irq, int value)
{
/* The SENSE register is assumed to be 32-bit. */
- int bitfield_width = p->config.sense_bitfield_width;
+ int bitfield_width = p->sense_bitfield_width;
int shift = 32 - (irq + 1) * bitfield_width;
dev_dbg(&p->pdev->dev, "sense irq = %d, mode = %d\n", irq, value);
@@ -361,8 +362,15 @@ static const struct irq_domain_ops intc_irqpin_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
-static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a777x = {
+static const struct intc_irqpin_config intc_irqpin_irlm_r8a777x = {
.irlm_bit = 23, /* ICR0.IRLM0 */
+ .needs_irlm = 1,
+ .needs_clk = 0,
+};
+
+static const struct intc_irqpin_config intc_irqpin_rmobile = {
+ .needs_irlm = 0,
+ .needs_clk = 1,
};
static const struct of_device_id intc_irqpin_dt_ids[] = {
@@ -371,14 +379,18 @@ static const struct of_device_id intc_irqpin_dt_ids[] = {
.data = &intc_irqpin_irlm_r8a777x },
{ .compatible = "renesas,intc-irqpin-r8a7779",
.data = &intc_irqpin_irlm_r8a777x },
+ { .compatible = "renesas,intc-irqpin-r8a7740",
+ .data = &intc_irqpin_rmobile },
+ { .compatible = "renesas,intc-irqpin-sh73a0",
+ .data = &intc_irqpin_rmobile },
{},
};
MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
static int intc_irqpin_probe(struct platform_device *pdev)
{
+ const struct intc_irqpin_config *config = NULL;
struct device *dev = &pdev->dev;
- struct renesas_intc_irqpin_config *pdata = dev->platform_data;
const struct of_device_id *of_id;
struct intc_irqpin_priv *p;
struct intc_irqpin_iomem *i;
@@ -388,6 +400,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
void (*enable_fn)(struct irq_data *d);
void (*disable_fn)(struct irq_data *d);
const char *name = dev_name(dev);
+ bool control_parent;
+ unsigned int nirqs;
int ref_irq;
int ret;
int k;
@@ -399,23 +413,28 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
/* deal with driver instance configuration */
- if (pdata) {
- memcpy(&p->config, pdata, sizeof(*pdata));
- } else {
- of_property_read_u32(dev->of_node, "sense-bitfield-width",
- &p->config.sense_bitfield_width);
- p->config.control_parent = of_property_read_bool(dev->of_node,
- "control-parent");
- }
- if (!p->config.sense_bitfield_width)
- p->config.sense_bitfield_width = 4; /* default to 4 bits */
+ of_property_read_u32(dev->of_node, "sense-bitfield-width",
+ &p->sense_bitfield_width);
+ control_parent = of_property_read_bool(dev->of_node, "control-parent");
+ if (!p->sense_bitfield_width)
+ p->sense_bitfield_width = 4; /* default to 4 bits */
p->pdev = pdev;
platform_set_drvdata(pdev, p);
+ of_id = of_match_device(intc_irqpin_dt_ids, dev);
+ if (of_id && of_id->data) {
+ config = of_id->data;
+ p->needs_clk = config->needs_clk;
+ }
+
p->clk = devm_clk_get(dev, NULL);
if (IS_ERR(p->clk)) {
- dev_warn(dev, "unable to get clock\n");
+ if (p->needs_clk) {
+ dev_err(dev, "unable to get clock\n");
+ ret = PTR_ERR(p->clk);
+ goto err0;
+ }
p->clk = NULL;
}
@@ -443,8 +462,8 @@ static int intc_irqpin_probe(struct platform_device *pdev)
p->irq[k].requested_irq = irq->start;
}
- p->number_of_irqs = k;
- if (p->number_of_irqs < 1) {
+ nirqs = k;
+ if (nirqs < 1) {
dev_err(dev, "not enough IRQ resources\n");
ret = -EINVAL;
goto err0;
@@ -485,20 +504,16 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
/* configure "individual IRQ mode" where needed */
- of_id = of_match_device(intc_irqpin_dt_ids, dev);
- if (of_id && of_id->data) {
- const struct intc_irqpin_irlm_config *irlm_config = of_id->data;
-
+ if (config && config->needs_irlm) {
if (io[INTC_IRQPIN_REG_IRLM])
intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
- irlm_config->irlm_bit,
- 1, 1);
+ config->irlm_bit, 1, 1);
else
dev_warn(dev, "unable to select IRLM mode\n");
}
/* mask all interrupts using priority */
- for (k = 0; k < p->number_of_irqs; k++)
+ for (k = 0; k < nirqs; k++)
intc_irqpin_mask_unmask_prio(p, k, 1);
/* clear all pending interrupts */
@@ -506,16 +521,16 @@ static int intc_irqpin_probe(struct platform_device *pdev)
/* scan for shared interrupt lines */
ref_irq = p->irq[0].requested_irq;
- p->shared_irqs = true;
- for (k = 1; k < p->number_of_irqs; k++) {
+ p->shared_irqs = 1;
+ for (k = 1; k < nirqs; k++) {
if (ref_irq != p->irq[k].requested_irq) {
- p->shared_irqs = false;
+ p->shared_irqs = 0;
break;
}
}
/* use more severe masking method if requested */
- if (p->config.control_parent) {
+ if (control_parent) {
enable_fn = intc_irqpin_irq_enable_force;
disable_fn = intc_irqpin_irq_disable_force;
} else if (!p->shared_irqs) {
@@ -534,9 +549,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
irq_chip->irq_set_wake = intc_irqpin_irq_set_wake;
irq_chip->flags = IRQCHIP_MASK_ON_SUSPEND;
- p->irq_domain = irq_domain_add_simple(dev->of_node,
- p->number_of_irqs,
- p->config.irq_base,
+ p->irq_domain = irq_domain_add_simple(dev->of_node, nirqs, 0,
&intc_irqpin_irq_domain_ops, p);
if (!p->irq_domain) {
ret = -ENXIO;
@@ -555,7 +568,7 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
} else {
/* request interrupts one by one */
- for (k = 0; k < p->number_of_irqs; k++) {
+ for (k = 0; k < nirqs; k++) {
if (devm_request_irq(dev, p->irq[k].requested_irq,
intc_irqpin_irq_handler, 0, name,
&p->irq[k])) {
@@ -567,17 +580,10 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
/* unmask all interrupts on prio level */
- for (k = 0; k < p->number_of_irqs; k++)
+ for (k = 0; k < nirqs; k++)
intc_irqpin_mask_unmask_prio(p, k, 0);
- dev_info(dev, "driving %d irqs\n", p->number_of_irqs);
-
- /* warn in case of mismatch if irq base is specified */
- if (p->config.irq_base) {
- if (p->config.irq_base != p->irq[0].domain_irq)
- dev_warn(dev, "irq base mismatch (%d/%d)\n",
- p->config.irq_base, p->irq[0].domain_irq);
- }
+ dev_info(dev, "driving %d irqs\n", nirqs);
return 0;
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index 4ef1780..0820f67 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -50,6 +50,12 @@ static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
.enable = 0x34,
};
+static struct sunxi_sc_nmi_reg_offs sun9i_reg_offs = {
+ .ctrl = 0x00,
+ .pend = 0x08,
+ .enable = 0x04,
+};
+
static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
u32 val)
{
@@ -207,3 +213,10 @@ static int __init sun7i_sc_nmi_irq_init(struct device_node *node,
return sunxi_sc_nmi_irq_init(node, &sun7i_reg_offs);
}
IRQCHIP_DECLARE(sun7i_sc_nmi, "allwinner,sun7i-a20-sc-nmi", sun7i_sc_nmi_irq_init);
+
+static int __init sun9i_nmi_irq_init(struct device_node *node,
+ struct device_node *parent)
+{
+ return sunxi_sc_nmi_irq_init(node, &sun9i_reg_offs);
+}
+IRQCHIP_DECLARE(sun9i_nmi, "allwinner,sun9i-a80-nmi", sun9i_nmi_irq_init);
diff --git a/drivers/irqchip/irq-ts4800.c b/drivers/irqchip/irq-ts4800.c
new file mode 100644
index 0000000..4192bdc
--- /dev/null
+++ b/drivers/irqchip/irq-ts4800.c
@@ -0,0 +1,163 @@
+/*
+ * Multiplexed-IRQs driver for TS-4800's FPGA
+ *
+ * Copyright (c) 2015 - Savoir-faire Linux
+ *
+ * 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/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+
+#define IRQ_MASK 0x4
+#define IRQ_STATUS 0x8
+
+struct ts4800_irq_data {
+ void __iomem *base;
+ struct irq_domain *domain;
+ struct irq_chip irq_chip;
+};
+
+static void ts4800_irq_mask(struct irq_data *d)
+{
+ struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d);
+ u16 reg = readw(data->base + IRQ_MASK);
+ u16 mask = 1 << d->hwirq;
+
+ writew(reg | mask, data->base + IRQ_MASK);
+}
+
+static void ts4800_irq_unmask(struct irq_data *d)
+{
+ struct ts4800_irq_data *data = irq_data_get_irq_chip_data(d);
+ u16 reg = readw(data->base + IRQ_MASK);
+ u16 mask = 1 << d->hwirq;
+
+ writew(reg & ~mask, data->base + IRQ_MASK);
+}
+
+static int ts4800_irqdomain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct ts4800_irq_data *data = d->host_data;
+
+ irq_set_chip_and_handler(irq, &data->irq_chip, handle_simple_irq);
+ irq_set_chip_data(irq, data);
+ irq_set_noprobe(irq);
+
+ return 0;
+}
+
+struct irq_domain_ops ts4800_ic_ops = {
+ .map = ts4800_irqdomain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static void ts4800_ic_chained_handle_irq(struct irq_desc *desc)
+{
+ struct ts4800_irq_data *data = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ u16 status = readw(data->base + IRQ_STATUS);
+
+ chained_irq_enter(chip, desc);
+
+ if (unlikely(status == 0)) {
+ handle_bad_irq(desc);
+ goto out;
+ }
+
+ do {
+ unsigned int bit = __ffs(status);
+ int irq = irq_find_mapping(data->domain, bit);
+
+ status &= ~(1 << bit);
+ generic_handle_irq(irq);
+ } while (status);
+
+out:
+ chained_irq_exit(chip, desc);
+}
+
+static int ts4800_ic_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct ts4800_irq_data *data;
+ struct irq_chip *irq_chip;
+ struct resource *res;
+ int parent_irq;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ data->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(data->base))
+ return PTR_ERR(data->base);
+
+ writew(0xFFFF, data->base + IRQ_MASK);
+
+ parent_irq = irq_of_parse_and_map(node, 0);
+ if (!parent_irq) {
+ dev_err(&pdev->dev, "failed to get parent IRQ\n");
+ return -EINVAL;
+ }
+
+ irq_chip = &data->irq_chip;
+ irq_chip->name = dev_name(&pdev->dev);
+ irq_chip->irq_mask = ts4800_irq_mask;
+ irq_chip->irq_unmask = ts4800_irq_unmask;
+
+ data->domain = irq_domain_add_linear(node, 8, &ts4800_ic_ops, data);
+ if (!data->domain) {
+ dev_err(&pdev->dev, "cannot add IRQ domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler_and_data(parent_irq,
+ ts4800_ic_chained_handle_irq, data);
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+}
+
+static int ts4800_ic_remove(struct platform_device *pdev)
+{
+ struct ts4800_irq_data *data = platform_get_drvdata(pdev);
+
+ irq_domain_remove(data->domain);
+
+ return 0;
+}
+
+static const struct of_device_id ts4800_ic_of_match[] = {
+ { .compatible = "technologic,ts4800-irqc", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ts4800_ic_of_match);
+
+static struct platform_driver ts4800_ic_driver = {
+ .probe = ts4800_ic_probe,
+ .remove = ts4800_ic_remove,
+ .driver = {
+ .name = "ts4800-irqc",
+ .of_match_table = ts4800_ic_of_match,
+ },
+};
+module_platform_driver(ts4800_ic_driver);
+
+MODULE_AUTHOR("Damien Riegel <damien.riegel@savoirfairelinux.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ts4800_irqc");
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index 598ab3f..cadf104 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -210,7 +210,12 @@ int __init fpga_irq_of_init(struct device_node *node,
parent_irq = -1;
}
+#ifdef CONFIG_ARCH_VERSATILE
+ fpga_irq_init(base, node->name, IRQ_SIC_START, parent_irq, valid_mask,
+ node);
+#else
fpga_irq_init(base, node->name, 0, parent_irq, valid_mask, node);
+#endif
writel(clear_mask, base + IRQ_ENABLE_CLEAR);
writel(clear_mask, base + FIQ_ENABLE_CLEAR);
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index 4c48fa8..cb9d8ec 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -43,8 +43,7 @@ static void __iomem *zevio_irq_io;
static void zevio_irq_ack(struct irq_data *irqd)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(irqd);
- struct irq_chip_regs *regs =
- &container_of(irqd->chip, struct irq_chip_type, chip)->regs;
+ struct irq_chip_regs *regs = &irq_data_get_chip_type(irqd)->regs;
readl(gc->reg_base + regs->ack);
}
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index 375be50..2a506fe 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -67,8 +67,7 @@ static int write_modem(struct cardstate *cs)
struct sk_buff *skb = bcs->tx_skb;
int sent = -EOPNOTSUPP;
- if (!tty || !tty->driver || !skb)
- return -EINVAL;
+ WARN_ON(!tty || !tty->ops || !skb);
if (!skb->len) {
dev_kfree_skb_any(skb);
@@ -109,8 +108,7 @@ static int send_cb(struct cardstate *cs)
unsigned long flags;
int sent = 0;
- if (!tty || !tty->driver)
- return -EFAULT;
+ WARN_ON(!tty || !tty->ops);
cb = cs->cmdbuf;
if (!cb)
@@ -370,19 +368,18 @@ static void gigaset_freecshw(struct cardstate *cs)
tasklet_kill(&cs->write_tasklet);
if (!cs->hw.ser)
return;
- dev_set_drvdata(&cs->hw.ser->dev.dev, NULL);
platform_device_unregister(&cs->hw.ser->dev);
- kfree(cs->hw.ser);
- cs->hw.ser = NULL;
}
static void gigaset_device_release(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
+ struct cardstate *cs = dev_get_drvdata(dev);
- /* adapted from platform_device_release() in drivers/base/platform.c */
- kfree(dev->platform_data);
- kfree(pdev->resource);
+ if (!cs)
+ return;
+ dev_set_drvdata(dev, NULL);
+ kfree(cs->hw.ser);
+ cs->hw.ser = NULL;
}
/*
@@ -432,7 +429,9 @@ static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear;
- if (!tty || !tty->driver || !tty->ops->tiocmset)
+ WARN_ON(!tty || !tty->ops);
+ /* tiocmset is an optional tty driver method */
+ if (!tty->ops->tiocmset)
return -EINVAL;
set = new_state & ~old_state;
clear = old_state & ~new_state;
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index a77eea5..cb428b9 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -1170,7 +1170,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
if (ipac->type & IPAC_TYPE_IPACX) {
ista = ReadIPAC(ipac, ISACX_ISTA);
- while (ista && cnt--) {
+ while (ista && --cnt) {
pr_debug("%s: ISTA %02x\n", ipac->name, ista);
if (ista & IPACX__ICA)
ipac_irq(&ipac->hscx[0], ista);
@@ -1182,7 +1182,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
}
} else if (ipac->type & IPAC_TYPE_IPAC) {
ista = ReadIPAC(ipac, IPAC_ISTA);
- while (ista && cnt--) {
+ while (ista && --cnt) {
pr_debug("%s: ISTA %02x\n", ipac->name, ista);
if (ista & (IPAC__ICD | IPAC__EXD)) {
istad = ReadISAC(isac, ISAC_ISTA);
@@ -1200,7 +1200,7 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
ista = ReadIPAC(ipac, IPAC_ISTA);
}
} else if (ipac->type & IPAC_TYPE_HSCX) {
- while (cnt) {
+ while (--cnt) {
ista = ReadIPAC(ipac, IPAC_ISTAB + ipac->hscx[1].off);
pr_debug("%s: B2 ISTA %02x\n", ipac->name, ista);
if (ista)
@@ -1211,7 +1211,6 @@ mISDNipac_irq(struct ipac_hw *ipac, int maxloop)
mISDNisac_irq(isac, istad);
if (0 == (ista | istad))
break;
- cnt--;
}
}
if (cnt > maxloop) /* only for ISAC/HSCX without PCI IRQ test */
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index b33f53b..bf04d2a 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -1896,7 +1896,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
ptr--;
*ptr++ = '\n';
*ptr = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
} else
HiSax_putstatus(cs, "LogEcho: ",
"warning Frame too big (%d)",
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 4a48255..90449e1 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -901,7 +901,7 @@ Begin:
ptr--;
*ptr++ = '\n';
*ptr = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
} else
HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", total - 3);
}
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index b1fad81..13b2151 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -674,7 +674,7 @@ receive_emsg(struct IsdnCardState *cs)
ptr--;
*ptr++ = '\n';
*ptr = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
} else
HiSax_putstatus(cs, "LogEcho: ", "warning Frame too big (%d)", skb->len);
}
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index b420f8b..ba4beb2 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -1179,7 +1179,7 @@ LogFrame(struct IsdnCardState *cs, u_char *buf, int size)
dp--;
*dp++ = '\n';
*dp = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
} else
HiSax_putstatus(cs, "LogFrame: ", "warning Frame too big (%d)", size);
}
@@ -1246,7 +1246,7 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
}
if (finish) {
*dp = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
return;
}
if ((0xfe & buf[0]) == PROTO_DIS_N0) { /* 1TR6 */
@@ -1509,5 +1509,5 @@ dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir)
dp += sprintf(dp, "Unknown protocol %x!", buf[0]);
}
*dp = 0;
- HiSax_putstatus(cs, NULL, "%s", cs->dlog);
+ HiSax_putstatus(cs, NULL, cs->dlog);
}
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index b1ab8bd..7f940c2 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -52,6 +52,7 @@ config LEDS_AAT1290
config LEDS_BCM6328
tristate "LED Support for Broadcom BCM6328"
depends on LEDS_CLASS
+ depends on HAS_IOMEM
depends on OF
help
This option enables support for LEDs connected to the BCM6328
@@ -60,6 +61,7 @@ config LEDS_BCM6328
config LEDS_BCM6358
tristate "LED Support for Broadcom BCM6358"
depends on LEDS_CLASS
+ depends on HAS_IOMEM
depends on OF
help
This option enables support for LEDs connected to the BCM6358
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
index 3b25734..cf39827 100644
--- a/drivers/leds/led-class-flash.c
+++ b/drivers/leds/led-class-flash.c
@@ -108,7 +108,7 @@ static ssize_t flash_strobe_store(struct device *dev,
if (ret)
goto unlock;
- if (state < 0 || state > 1) {
+ if (state > 1) {
ret = -EINVAL;
goto unlock;
}
@@ -298,7 +298,7 @@ int led_classdev_flash_register(struct device *parent,
led_cdev = &fled_cdev->led_cdev;
if (led_cdev->flags & LED_DEV_CAP_FLASH) {
- if (!led_cdev->brightness_set_sync)
+ if (!led_cdev->brightness_set_blocking)
return -EINVAL;
ops = fled_cdev->ops;
@@ -316,10 +316,6 @@ int led_classdev_flash_register(struct device *parent,
if (ret < 0)
return ret;
- /* Setting a torch brightness needs to have immediate effect */
- led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
- led_cdev->flags |= SET_BRIGHTNESS_SYNC;
-
return 0;
}
EXPORT_SYMBOL_GPL(led_classdev_flash_register);
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index 7385f98..14139c3 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -109,7 +109,7 @@ static const struct attribute_group *led_groups[] = {
void led_classdev_suspend(struct led_classdev *led_cdev)
{
led_cdev->flags |= LED_SUSPENDED;
- led_cdev->brightness_set(led_cdev, 0);
+ led_set_brightness_nopm(led_cdev, 0);
}
EXPORT_SYMBOL_GPL(led_classdev_suspend);
@@ -119,7 +119,7 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
*/
void led_classdev_resume(struct led_classdev *led_cdev)
{
- led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+ led_set_brightness_nopm(led_cdev, led_cdev->brightness);
if (led_cdev->flash_resume)
led_cdev->flash_resume(led_cdev);
@@ -215,8 +215,6 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
if (!led_cdev->max_brightness)
led_cdev->max_brightness = LED_FULL;
- led_cdev->flags |= SET_BRIGHTNESS_ASYNC;
-
led_update_brightness(led_cdev);
led_init_core(led_cdev);
@@ -247,12 +245,13 @@ void led_classdev_unregister(struct led_classdev *led_cdev)
up_write(&led_cdev->trigger_lock);
#endif
- cancel_work_sync(&led_cdev->set_brightness_work);
-
/* Stop blinking */
led_stop_software_blink(led_cdev);
+
led_set_brightness(led_cdev, LED_OFF);
+ flush_work(&led_cdev->set_brightness_work);
+
device_unregister(led_cdev->dev);
down_write(&leds_list_lock);
diff --git a/drivers/leds/led-core.c b/drivers/leds/led-core.c
index c1c3af0..19e1e60d 100644
--- a/drivers/leds/led-core.c
+++ b/drivers/leds/led-core.c
@@ -32,7 +32,7 @@ static void led_timer_function(unsigned long data)
unsigned long delay;
if (!led_cdev->blink_delay_on || !led_cdev->blink_delay_off) {
- led_set_brightness_async(led_cdev, LED_OFF);
+ led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
@@ -44,23 +44,23 @@ static void led_timer_function(unsigned long data)
brightness = led_get_brightness(led_cdev);
if (!brightness) {
/* Time to switch the LED on. */
- if (led_cdev->delayed_set_value) {
- led_cdev->blink_brightness =
- led_cdev->delayed_set_value;
- led_cdev->delayed_set_value = 0;
- }
brightness = led_cdev->blink_brightness;
delay = led_cdev->blink_delay_on;
} else {
/* Store the current brightness value to be able
* to restore it when the delay_off period is over.
+ * Do it only if there is no pending blink brightness
+ * change, to avoid overwriting the new value.
*/
- led_cdev->blink_brightness = brightness;
+ if (!(led_cdev->flags & LED_BLINK_BRIGHTNESS_CHANGE))
+ led_cdev->blink_brightness = brightness;
+ else
+ led_cdev->flags &= ~LED_BLINK_BRIGHTNESS_CHANGE;
brightness = LED_OFF;
delay = led_cdev->blink_delay_off;
}
- led_set_brightness_async(led_cdev, brightness);
+ led_set_brightness_nosleep(led_cdev, brightness);
/* Return in next iteration if led is in one-shot mode and we are in
* the final blink state so that the led is toggled each delay_on +
@@ -83,10 +83,24 @@ static void set_brightness_delayed(struct work_struct *ws)
{
struct led_classdev *led_cdev =
container_of(ws, struct led_classdev, set_brightness_work);
+ int ret = 0;
- led_stop_software_blink(led_cdev);
+ if (led_cdev->flags & LED_BLINK_DISABLE) {
+ led_cdev->delayed_set_value = LED_OFF;
+ led_stop_software_blink(led_cdev);
+ led_cdev->flags &= ~LED_BLINK_DISABLE;
+ }
- led_set_brightness_async(led_cdev, led_cdev->delayed_set_value);
+ if (led_cdev->brightness_set)
+ led_cdev->brightness_set(led_cdev, led_cdev->delayed_set_value);
+ else if (led_cdev->brightness_set_blocking)
+ ret = led_cdev->brightness_set_blocking(led_cdev,
+ led_cdev->delayed_set_value);
+ else
+ ret = -ENOTSUPP;
+ if (ret < 0)
+ dev_err(led_cdev->dev,
+ "Setting an LED's brightness failed (%d)\n", ret);
}
static void led_set_software_blink(struct led_classdev *led_cdev,
@@ -106,13 +120,14 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
/* never on - just set to off */
if (!delay_on) {
- led_set_brightness_async(led_cdev, LED_OFF);
+ led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
/* never off - just set to brightness */
if (!delay_off) {
- led_set_brightness_async(led_cdev, led_cdev->blink_brightness);
+ led_set_brightness_nosleep(led_cdev,
+ led_cdev->blink_brightness);
return;
}
@@ -156,7 +171,7 @@ void led_blink_set(struct led_classdev *led_cdev,
led_blink_setup(led_cdev, delay_on, delay_off);
}
-EXPORT_SYMBOL(led_blink_set);
+EXPORT_SYMBOL_GPL(led_blink_set);
void led_blink_set_oneshot(struct led_classdev *led_cdev,
unsigned long *delay_on,
@@ -177,7 +192,7 @@ void led_blink_set_oneshot(struct led_classdev *led_cdev,
led_blink_setup(led_cdev, delay_on, delay_off);
}
-EXPORT_SYMBOL(led_blink_set_oneshot);
+EXPORT_SYMBOL_GPL(led_blink_set_oneshot);
void led_stop_software_blink(struct led_classdev *led_cdev)
{
@@ -190,29 +205,74 @@ EXPORT_SYMBOL_GPL(led_stop_software_blink);
void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
- int ret = 0;
-
- /* delay brightness if soft-blink is active */
+ /*
+ * In case blinking is on delay brightness setting
+ * until the next timer tick.
+ */
if (led_cdev->blink_delay_on || led_cdev->blink_delay_off) {
- led_cdev->delayed_set_value = brightness;
- if (brightness == LED_OFF)
+ /*
+ * If we need to disable soft blinking delegate this to the
+ * work queue task to avoid problems in case we are called
+ * from hard irq context.
+ */
+ if (brightness == LED_OFF) {
+ led_cdev->flags |= LED_BLINK_DISABLE;
schedule_work(&led_cdev->set_brightness_work);
+ } else {
+ led_cdev->flags |= LED_BLINK_BRIGHTNESS_CHANGE;
+ led_cdev->blink_brightness = brightness;
+ }
return;
}
- if (led_cdev->flags & SET_BRIGHTNESS_ASYNC) {
- led_set_brightness_async(led_cdev, brightness);
+ led_set_brightness_nosleep(led_cdev, brightness);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness);
+
+void led_set_brightness_nopm(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ /* Use brightness_set op if available, it is guaranteed not to sleep */
+ if (led_cdev->brightness_set) {
+ led_cdev->brightness_set(led_cdev, value);
return;
- } else if (led_cdev->flags & SET_BRIGHTNESS_SYNC)
- ret = led_set_brightness_sync(led_cdev, brightness);
- else
- ret = -EINVAL;
+ }
- if (ret < 0)
- dev_dbg(led_cdev->dev, "Setting LED brightness failed (%d)\n",
- ret);
+ /* If brightness setting can sleep, delegate it to a work queue task */
+ led_cdev->delayed_set_value = value;
+ schedule_work(&led_cdev->set_brightness_work);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness_nopm);
+
+void led_set_brightness_nosleep(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+ if (led_cdev->flags & LED_SUSPENDED)
+ return;
+
+ led_set_brightness_nopm(led_cdev, led_cdev->brightness);
+}
+EXPORT_SYMBOL_GPL(led_set_brightness_nosleep);
+
+int led_set_brightness_sync(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ if (led_cdev->blink_delay_on || led_cdev->blink_delay_off)
+ return -EBUSY;
+
+ led_cdev->brightness = min(value, led_cdev->max_brightness);
+
+ if (led_cdev->flags & LED_SUSPENDED)
+ return 0;
+
+ if (led_cdev->brightness_set_blocking)
+ return led_cdev->brightness_set_blocking(led_cdev,
+ led_cdev->brightness);
+ return -ENOTSUPP;
}
-EXPORT_SYMBOL(led_set_brightness);
+EXPORT_SYMBOL_GPL(led_set_brightness_sync);
int led_update_brightness(struct led_classdev *led_cdev)
{
@@ -228,7 +288,7 @@ int led_update_brightness(struct led_classdev *led_cdev)
return ret;
}
-EXPORT_SYMBOL(led_update_brightness);
+EXPORT_SYMBOL_GPL(led_update_brightness);
/* Caller must ensure led_cdev->led_access held */
void led_sysfs_disable(struct led_classdev *led_cdev)
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index e8b1120..e1e9334 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -249,6 +249,34 @@ void led_trigger_unregister(struct led_trigger *trig)
}
EXPORT_SYMBOL_GPL(led_trigger_unregister);
+static void devm_led_trigger_release(struct device *dev, void *res)
+{
+ led_trigger_unregister(*(struct led_trigger **)res);
+}
+
+int devm_led_trigger_register(struct device *dev,
+ struct led_trigger *trig)
+{
+ struct led_trigger **dr;
+ int rc;
+
+ dr = devres_alloc(devm_led_trigger_release, sizeof(*dr),
+ GFP_KERNEL);
+ if (!dr)
+ return -ENOMEM;
+
+ *dr = trig;
+
+ rc = led_trigger_register(trig);
+ if (rc)
+ devres_free(dr);
+ else
+ devres_add(dev, dr);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(devm_led_trigger_register);
+
/* Simple LED Tigger Interface */
void led_trigger_event(struct led_trigger *trig,
diff --git a/drivers/leds/leds-88pm860x.c b/drivers/leds/leds-88pm860x.c
index 7870840..1ad4d03 100644
--- a/drivers/leds/leds-88pm860x.c
+++ b/drivers/leds/leds-88pm860x.c
@@ -16,7 +16,6 @@
#include <linux/i2c.h>
#include <linux/leds.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/mfd/88pm860x.h>
#include <linux/module.h>
@@ -33,7 +32,6 @@
struct pm860x_led {
struct led_classdev cdev;
struct i2c_client *i2c;
- struct work_struct work;
struct pm860x_chip *chip;
struct mutex lock;
char name[MFD_NAME_SIZE];
@@ -69,17 +67,18 @@ static int led_power_set(struct pm860x_chip *chip, int port, int on)
return ret;
}
-static void pm860x_led_work(struct work_struct *work)
+static int pm860x_led_set(struct led_classdev *cdev,
+ enum led_brightness value)
{
-
- struct pm860x_led *led;
+ struct pm860x_led *led = container_of(cdev, struct pm860x_led, cdev);
struct pm860x_chip *chip;
unsigned char buf[3];
int ret;
- led = container_of(work, struct pm860x_led, work);
chip = led->chip;
mutex_lock(&led->lock);
+ led->brightness = value >> 3;
+
if ((led->current_brightness == 0) && led->brightness) {
led_power_set(chip, led->port, 1);
if (led->iset) {
@@ -112,15 +111,8 @@ static void pm860x_led_work(struct work_struct *work)
dev_dbg(chip->dev, "Update LED. (reg:%d, brightness:%d)\n",
led->reg_control, led->brightness);
mutex_unlock(&led->lock);
-}
-static void pm860x_led_set(struct led_classdev *cdev,
- enum led_brightness value)
-{
- struct pm860x_led *data = container_of(cdev, struct pm860x_led, cdev);
-
- data->brightness = value >> 3;
- schedule_work(&data->work);
+ return 0;
}
#ifdef CONFIG_OF
@@ -213,9 +205,8 @@ static int pm860x_led_probe(struct platform_device *pdev)
data->current_brightness = 0;
data->cdev.name = data->name;
- data->cdev.brightness_set = pm860x_led_set;
+ data->cdev.brightness_set_blocking = pm860x_led_set;
mutex_init(&data->lock);
- INIT_WORK(&data->work, pm860x_led_work);
ret = led_classdev_register(chip->dev, &data->cdev);
if (ret < 0) {
diff --git a/drivers/leds/leds-aat1290.c b/drivers/leds/leds-aat1290.c
index ac77d36..def3cf9 100644
--- a/drivers/leds/leds-aat1290.c
+++ b/drivers/leds/leds-aat1290.c
@@ -20,7 +20,6 @@
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <media/v4l2-flash-led-class.h>
#define AAT1290_MOVIE_MODE_CURRENT_ADDR 17
@@ -82,8 +81,6 @@ struct aat1290_led {
/* brightness cache */
unsigned int torch_brightness;
- /* assures led-triggers compatibility */
- struct work_struct work_brightness_set;
};
static struct aat1290_led *fled_cdev_to_led(
@@ -92,6 +89,12 @@ static struct aat1290_led *fled_cdev_to_led(
return container_of(fled_cdev, struct aat1290_led, fled_cdev);
}
+static struct led_classdev_flash *led_cdev_to_fled_cdev(
+ struct led_classdev *led_cdev)
+{
+ return container_of(led_cdev, struct led_classdev_flash, led_cdev);
+}
+
static void aat1290_as2cwire_write(struct aat1290_led *led, int addr, int value)
{
int i;
@@ -134,9 +137,14 @@ static void aat1290_set_flash_safety_timer(struct aat1290_led *led,
flash_tm_reg);
}
-static void aat1290_brightness_set(struct aat1290_led *led,
+/* LED subsystem callbacks */
+
+static int aat1290_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
+ struct led_classdev_flash *fled_cdev = led_cdev_to_fled_cdev(led_cdev);
+ struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
+
mutex_lock(&led->lock);
if (brightness == 0) {
@@ -158,35 +166,6 @@ static void aat1290_brightness_set(struct aat1290_led *led,
}
mutex_unlock(&led->lock);
-}
-
-/* LED subsystem callbacks */
-
-static void aat1290_brightness_set_work(struct work_struct *work)
-{
- struct aat1290_led *led =
- container_of(work, struct aat1290_led, work_brightness_set);
-
- aat1290_brightness_set(led, led->torch_brightness);
-}
-
-static void aat1290_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
-
- led->torch_brightness = brightness;
- schedule_work(&led->work_brightness_set);
-}
-
-static int aat1290_led_brightness_set_sync(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct aat1290_led *led = fled_cdev_to_led(fled_cdev);
-
- aat1290_brightness_set(led, brightness);
return 0;
}
@@ -296,7 +275,7 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
if (ret < 0) {
dev_err(dev,
"flash-max-microamp DT property missing\n");
- return ret;
+ goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
@@ -304,13 +283,14 @@ static int aat1290_led_parse_dt(struct aat1290_led *led,
if (ret < 0) {
dev_err(dev,
"flash-max-timeout-us DT property missing\n");
- return ret;
+ goto err_parse_dt;
}
- of_node_put(child_node);
-
*sub_node = child_node;
+err_parse_dt:
+ of_node_put(child_node);
+
return ret;
}
@@ -509,11 +489,9 @@ static int aat1290_led_probe(struct platform_device *pdev)
mutex_init(&led->lock);
/* Initialize LED Flash class device */
- led_cdev->brightness_set = aat1290_led_brightness_set;
- led_cdev->brightness_set_sync = aat1290_led_brightness_set_sync;
+ led_cdev->brightness_set_blocking = aat1290_led_brightness_set;
led_cdev->max_brightness = led_cfg.max_brightness;
led_cdev->flags |= LED_DEV_CAP_FLASH;
- INIT_WORK(&led->work_brightness_set, aat1290_brightness_set_work);
aat1290_init_flash_timeout(led, &led_cfg);
@@ -548,7 +526,6 @@ static int aat1290_led_remove(struct platform_device *pdev)
v4l2_flash_release(led->v4l2_flash);
led_classdev_flash_unregister(&led->fled_cdev);
- cancel_work_sync(&led->work_brightness_set);
mutex_destroy(&led->lock);
diff --git a/drivers/leds/leds-adp5520.c b/drivers/leds/leds-adp5520.c
index 07e66ca..853b2d3 100644
--- a/drivers/leds/leds-adp5520.c
+++ b/drivers/leds/leds-adp5520.c
@@ -17,34 +17,24 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <linux/workqueue.h>
#include <linux/mfd/adp5520.h>
#include <linux/slab.h>
struct adp5520_led {
struct led_classdev cdev;
- struct work_struct work;
struct device *master;
- enum led_brightness new_brightness;
int id;
int flags;
};
-static void adp5520_led_work(struct work_struct *work)
-{
- struct adp5520_led *led = container_of(work, struct adp5520_led, work);
- adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
- led->new_brightness >> 2);
-}
-
-static void adp5520_led_set(struct led_classdev *led_cdev,
+static int adp5520_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct adp5520_led *led;
led = container_of(led_cdev, struct adp5520_led, cdev);
- led->new_brightness = value;
- schedule_work(&led->work);
+ return adp5520_write(led->master, ADP5520_LED1_CURRENT + led->id - 1,
+ value >> 2);
}
static int adp5520_led_setup(struct adp5520_led *led)
@@ -135,7 +125,7 @@ static int adp5520_led_probe(struct platform_device *pdev)
led_dat->cdev.name = cur_led->name;
led_dat->cdev.default_trigger = cur_led->default_trigger;
- led_dat->cdev.brightness_set = adp5520_led_set;
+ led_dat->cdev.brightness_set_blocking = adp5520_led_set;
led_dat->cdev.brightness = LED_OFF;
if (cur_led->flags & ADP5520_FLAG_LED_MASK)
@@ -146,9 +136,6 @@ static int adp5520_led_probe(struct platform_device *pdev)
led_dat->id = led_dat->flags & ADP5520_FLAG_LED_MASK;
led_dat->master = pdev->dev.parent;
- led_dat->new_brightness = LED_OFF;
-
- INIT_WORK(&led_dat->work, adp5520_led_work);
ret = led_classdev_register(led_dat->master, &led_dat->cdev);
if (ret) {
@@ -170,10 +157,8 @@ static int adp5520_led_probe(struct platform_device *pdev)
err:
if (i > 0) {
- for (i = i - 1; i >= 0; i--) {
+ for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
- }
}
return ret;
@@ -192,7 +177,6 @@ static int adp5520_led_remove(struct platform_device *pdev)
for (i = 0; i < pdata->num_leds; i++) {
led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
}
return 0;
diff --git a/drivers/leds/leds-bcm6328.c b/drivers/leds/leds-bcm6328.c
index c7ea5c6..1548259 100644
--- a/drivers/leds/leds-bcm6328.c
+++ b/drivers/leds/leds-bcm6328.c
@@ -42,16 +42,16 @@
#define BCM6328_LED_SHIFT_TEST BIT(30)
#define BCM6328_LED_TEST BIT(31)
#define BCM6328_INIT_MASK (BCM6328_SERIAL_LED_EN | \
- BCM6328_SERIAL_LED_MUX | \
+ BCM6328_SERIAL_LED_MUX | \
BCM6328_SERIAL_LED_CLK_NPOL | \
BCM6328_SERIAL_LED_DATA_PPOL | \
BCM6328_SERIAL_LED_SHIFT_DIR)
#define BCM6328_LED_MODE_MASK 3
-#define BCM6328_LED_MODE_OFF 0
+#define BCM6328_LED_MODE_ON 0
#define BCM6328_LED_MODE_FAST 1
#define BCM6328_LED_MODE_BLINK 2
-#define BCM6328_LED_MODE_ON 3
+#define BCM6328_LED_MODE_OFF 3
#define BCM6328_LED_SHIFT(X) ((X) << 1)
/**
@@ -76,12 +76,20 @@ struct bcm6328_led {
static void bcm6328_led_write(void __iomem *reg, unsigned long data)
{
+#ifdef CONFIG_CPU_BIG_ENDIAN
iowrite32be(data, reg);
+#else
+ writel(data, reg);
+#endif
}
static unsigned long bcm6328_led_read(void __iomem *reg)
{
+#ifdef CONFIG_CPU_BIG_ENDIAN
return ioread32be(reg);
+#else
+ return readl(reg);
+#endif
}
/**
@@ -126,34 +134,45 @@ static void bcm6328_led_set(struct led_classdev *led_cdev,
*(led->blink_leds) &= ~BIT(led->pin);
if ((led->active_low && value == LED_OFF) ||
(!led->active_low && value != LED_OFF))
- bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
- else
bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
+ else
+ bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
spin_unlock_irqrestore(led->lock, flags);
}
+static unsigned long bcm6328_blink_delay(unsigned long delay)
+{
+ unsigned long bcm6328_delay;
+
+ bcm6328_delay = delay + BCM6328_LED_INTERVAL_MS / 2;
+ bcm6328_delay = bcm6328_delay / BCM6328_LED_INTERVAL_MS;
+ if (bcm6328_delay == 0)
+ bcm6328_delay = 1;
+
+ return bcm6328_delay;
+}
+
static int bcm6328_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
struct bcm6328_led *led =
container_of(led_cdev, struct bcm6328_led, cdev);
unsigned long delay, flags;
+ int rc;
if (!*delay_on)
*delay_on = BCM6328_LED_DEF_DELAY;
if (!*delay_off)
*delay_off = BCM6328_LED_DEF_DELAY;
- if (*delay_on != *delay_off) {
+ delay = bcm6328_blink_delay(*delay_on);
+ if (delay != bcm6328_blink_delay(*delay_off)) {
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay_on != delay_off)\n");
return -EINVAL;
}
- delay = *delay_on / BCM6328_LED_INTERVAL_MS;
- if (delay == 0)
- delay = 1;
- else if (delay > BCM6328_LED_INTV_MASK) {
+ if (delay > BCM6328_LED_INTV_MASK) {
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay > %ums)\n",
BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
@@ -175,16 +194,15 @@ static int bcm6328_blink_set(struct led_classdev *led_cdev,
bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
-
- spin_unlock_irqrestore(led->lock, flags);
+ rc = 0;
} else {
- spin_unlock_irqrestore(led->lock, flags);
dev_dbg(led_cdev->dev,
"fallback to soft blinking (delay already set)\n");
- return -EINVAL;
+ rc = -EINVAL;
}
+ spin_unlock_irqrestore(led->lock, flags);
- return 0;
+ return rc;
}
static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
@@ -264,7 +282,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
unsigned long *blink_leds, unsigned long *blink_delay)
{
struct bcm6328_led *led;
- unsigned long flags;
const char *state;
int rc;
@@ -286,7 +303,6 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
"linux,default-trigger",
NULL);
- spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
@@ -303,8 +319,8 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
val = bcm6328_led_read(mode) >>
BCM6328_LED_SHIFT(shift % 16);
val &= BCM6328_LED_MODE_MASK;
- if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
- (!led->active_low && val == BCM6328_LED_MODE_OFF))
+ if ((led->active_low && val == BCM6328_LED_MODE_OFF) ||
+ (!led->active_low && val == BCM6328_LED_MODE_ON))
led->cdev.brightness = LED_FULL;
else
led->cdev.brightness = LED_OFF;
@@ -315,12 +331,7 @@ static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
led->cdev.brightness = LED_OFF;
}
- if ((led->active_low && led->cdev.brightness == LED_FULL) ||
- (!led->active_low && led->cdev.brightness == LED_OFF))
- bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
- else
- bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
- spin_unlock_irqrestore(lock, flags);
+ bcm6328_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6328_led_set;
led->cdev.blink_set = bcm6328_blink_set;
@@ -341,7 +352,7 @@ static int bcm6328_leds_probe(struct platform_device *pdev)
struct device_node *child;
struct resource *mem_r;
void __iomem *mem;
- spinlock_t *lock;
+ spinlock_t *lock; /* memory lock */
unsigned long val, *blink_leds, *blink_delay;
mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
diff --git a/drivers/leds/leds-bcm6358.c b/drivers/leds/leds-bcm6358.c
index 82b4ee1..b2cc066 100644
--- a/drivers/leds/leds-bcm6358.c
+++ b/drivers/leds/leds-bcm6358.c
@@ -49,12 +49,20 @@ struct bcm6358_led {
static void bcm6358_led_write(void __iomem *reg, unsigned long data)
{
+#ifdef CONFIG_CPU_BIG_ENDIAN
iowrite32be(data, reg);
+#else
+ writel(data, reg);
+#endif
}
static unsigned long bcm6358_led_read(void __iomem *reg)
{
+#ifdef CONFIG_CPU_BIG_ENDIAN
return ioread32be(reg);
+#else
+ return readl(reg);
+#endif
}
static unsigned long bcm6358_led_busy(void __iomem *mem)
@@ -68,12 +76,15 @@ static unsigned long bcm6358_led_busy(void __iomem *mem)
return val;
}
-static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
+static void bcm6358_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- unsigned long val;
+ struct bcm6358_led *led =
+ container_of(led_cdev, struct bcm6358_led, cdev);
+ unsigned long flags, val;
+ spin_lock_irqsave(led->lock, flags);
bcm6358_led_busy(led->mem);
-
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
if ((led->active_low && value == LED_OFF) ||
(!led->active_low && value != LED_OFF))
@@ -81,17 +92,6 @@ static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
else
val &= ~(BIT(led->pin));
bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
-}
-
-static void bcm6358_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct bcm6358_led *led =
- container_of(led_cdev, struct bcm6358_led, cdev);
- unsigned long flags;
-
- spin_lock_irqsave(led->lock, flags);
- bcm6358_led_mode(led, value);
spin_unlock_irqrestore(led->lock, flags);
}
@@ -99,7 +99,6 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
void __iomem *mem, spinlock_t *lock)
{
struct bcm6358_led *led;
- unsigned long flags;
const char *state;
int rc;
@@ -119,15 +118,11 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
"linux,default-trigger",
NULL);
- spin_lock_irqsave(lock, flags);
if (!of_property_read_string(nc, "default-state", &state)) {
if (!strcmp(state, "on")) {
led->cdev.brightness = LED_FULL;
} else if (!strcmp(state, "keep")) {
unsigned long val;
-
- bcm6358_led_busy(led->mem);
-
val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
val &= BIT(led->pin);
if ((led->active_low && !val) ||
@@ -141,8 +136,8 @@ static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
} else {
led->cdev.brightness = LED_OFF;
}
- bcm6358_led_mode(led, led->cdev.brightness);
- spin_unlock_irqrestore(lock, flags);
+
+ bcm6358_led_set(&led->cdev, led->cdev.brightness);
led->cdev.brightness_set = bcm6358_led_set;
diff --git a/drivers/leds/leds-bd2802.c b/drivers/leds/leds-bd2802.c
index 6078c15..6b4de76 100644
--- a/drivers/leds/leds-bd2802.c
+++ b/drivers/leds/leds-bd2802.c
@@ -72,7 +72,6 @@ struct bd2802_led {
struct bd2802_led_platform_data *pdata;
struct i2c_client *client;
struct rw_semaphore rwsem;
- struct work_struct work;
struct led_state led[2];
@@ -518,29 +517,22 @@ static struct device_attribute *bd2802_attributes[] = {
&bd2802_rgb_current_attr,
};
-static void bd2802_led_work(struct work_struct *work)
-{
- struct bd2802_led *led = container_of(work, struct bd2802_led, work);
-
- if (led->state)
- bd2802_turn_on(led, led->led_id, led->color, led->state);
- else
- bd2802_turn_off(led, led->led_id, led->color);
-}
-
#define BD2802_CONTROL_RGBS(name, id, clr) \
-static void bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
+static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
enum led_brightness value) \
{ \
struct bd2802_led *led = \
container_of(led_cdev, struct bd2802_led, cdev_##name); \
led->led_id = id; \
led->color = clr; \
- if (value == LED_OFF) \
+ if (value == LED_OFF) { \
led->state = BD2802_OFF; \
- else \
+ bd2802_turn_off(led, led->led_id, led->color); \
+ } else { \
led->state = BD2802_ON; \
- schedule_work(&led->work); \
+ bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
+ } \
+ return 0; \
} \
static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
unsigned long *delay_on, unsigned long *delay_off) \
@@ -552,7 +544,7 @@ static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
led->led_id = id; \
led->color = clr; \
led->state = BD2802_BLINK; \
- schedule_work(&led->work); \
+ bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK); \
return 0; \
}
@@ -567,11 +559,9 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
{
int ret;
- INIT_WORK(&led->work, bd2802_led_work);
-
led->cdev_led1r.name = "led1_R";
led->cdev_led1r.brightness = LED_OFF;
- led->cdev_led1r.brightness_set = bd2802_set_led1r_brightness;
+ led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
@@ -583,7 +573,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1g.name = "led1_G";
led->cdev_led1g.brightness = LED_OFF;
- led->cdev_led1g.brightness_set = bd2802_set_led1g_brightness;
+ led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
@@ -595,7 +585,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led1b.name = "led1_B";
led->cdev_led1b.brightness = LED_OFF;
- led->cdev_led1b.brightness_set = bd2802_set_led1b_brightness;
+ led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
@@ -607,7 +597,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2r.name = "led2_R";
led->cdev_led2r.brightness = LED_OFF;
- led->cdev_led2r.brightness_set = bd2802_set_led2r_brightness;
+ led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
@@ -619,7 +609,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2g.name = "led2_G";
led->cdev_led2g.brightness = LED_OFF;
- led->cdev_led2g.brightness_set = bd2802_set_led2g_brightness;
+ led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
@@ -631,7 +621,7 @@ static int bd2802_register_led_classdev(struct bd2802_led *led)
led->cdev_led2b.name = "led2_B";
led->cdev_led2b.brightness = LED_OFF;
- led->cdev_led2b.brightness_set = bd2802_set_led2b_brightness;
+ led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
@@ -661,7 +651,6 @@ failed_unregister_led1_R:
static void bd2802_unregister_led_classdev(struct bd2802_led *led)
{
- cancel_work_sync(&led->work);
led_classdev_unregister(&led->cdev_led2b);
led_classdev_unregister(&led->cdev_led2g);
led_classdev_unregister(&led->cdev_led2r);
diff --git a/drivers/leds/leds-blinkm.c b/drivers/leds/leds-blinkm.c
index d0452b0..617fe97 100644
--- a/drivers/leds/leds-blinkm.c
+++ b/drivers/leds/leds-blinkm.c
@@ -39,16 +39,9 @@ struct blinkm_led {
struct i2c_client *i2c_client;
struct led_classdev led_cdev;
int id;
- atomic_t active;
-};
-
-struct blinkm_work {
- struct blinkm_led *blinkm_led;
- struct work_struct work;
};
#define cdev_to_blmled(c) container_of(c, struct blinkm_led, led_cdev)
-#define work_to_blmwork(c) container_of(c, struct blinkm_work, work)
struct blinkm_data {
struct i2c_client *i2c_client;
@@ -439,65 +432,30 @@ static int blinkm_transfer_hw(struct i2c_client *client, int cmd)
return 0;
}
-static void led_work(struct work_struct *work)
-{
- int ret;
- struct blinkm_led *led;
- struct blinkm_data *data;
- struct blinkm_work *blm_work = work_to_blmwork(work);
-
- led = blm_work->blinkm_led;
- data = i2c_get_clientdata(led->i2c_client);
- ret = blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
- atomic_dec(&led->active);
- dev_dbg(&led->i2c_client->dev,
- "# DONE # next_red = %d, next_green = %d,"
- " next_blue = %d, active = %d\n",
- data->next_red, data->next_green,
- data->next_blue, atomic_read(&led->active));
- kfree(blm_work);
-}
-
static int blinkm_led_common_set(struct led_classdev *led_cdev,
enum led_brightness value, int color)
{
/* led_brightness is 0, 127 or 255 - we just use it here as-is */
struct blinkm_led *led = cdev_to_blmled(led_cdev);
struct blinkm_data *data = i2c_get_clientdata(led->i2c_client);
- struct blinkm_work *bl_work;
switch (color) {
case RED:
/* bail out if there's no change */
if (data->next_red == (u8) value)
return 0;
- /* we assume a quite fast sequence here ([off]->on->off)
- * think of network led trigger - we cannot blink that fast, so
- * in case we already have a off->on->off transition queued up,
- * we refuse to queue up more.
- * Revisit: fast-changing brightness. */
- if (atomic_read(&led->active) > 1)
- return 0;
data->next_red = (u8) value;
break;
case GREEN:
/* bail out if there's no change */
if (data->next_green == (u8) value)
return 0;
- /* we assume a quite fast sequence here ([off]->on->off)
- * Revisit: fast-changing brightness. */
- if (atomic_read(&led->active) > 1)
- return 0;
data->next_green = (u8) value;
break;
case BLUE:
/* bail out if there's no change */
if (data->next_blue == (u8) value)
return 0;
- /* we assume a quite fast sequence here ([off]->on->off)
- * Revisit: fast-changing brightness. */
- if (atomic_read(&led->active) > 1)
- return 0;
data->next_blue = (u8) value;
break;
@@ -506,42 +464,31 @@ static int blinkm_led_common_set(struct led_classdev *led_cdev,
return -EINVAL;
}
- bl_work = kzalloc(sizeof(*bl_work), GFP_ATOMIC);
- if (!bl_work)
- return -ENOMEM;
-
- atomic_inc(&led->active);
+ blinkm_transfer_hw(led->i2c_client, BLM_GO_RGB);
dev_dbg(&led->i2c_client->dev,
- "#TO_SCHED# next_red = %d, next_green = %d,"
- " next_blue = %d, active = %d\n",
+ "# DONE # next_red = %d, next_green = %d,"
+ " next_blue = %d\n",
data->next_red, data->next_green,
- data->next_blue, atomic_read(&led->active));
-
- /* a fresh work _item_ for each change */
- bl_work->blinkm_led = led;
- INIT_WORK(&bl_work->work, led_work);
- /* queue work in own queue for easy sync on exit*/
- schedule_work(&bl_work->work);
-
+ data->next_blue);
return 0;
}
-static void blinkm_led_red_set(struct led_classdev *led_cdev,
+static int blinkm_led_red_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- blinkm_led_common_set(led_cdev, value, RED);
+ return blinkm_led_common_set(led_cdev, value, RED);
}
-static void blinkm_led_green_set(struct led_classdev *led_cdev,
+static int blinkm_led_green_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- blinkm_led_common_set(led_cdev, value, GREEN);
+ return blinkm_led_common_set(led_cdev, value, GREEN);
}
-static void blinkm_led_blue_set(struct led_classdev *led_cdev,
+static int blinkm_led_blue_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- blinkm_led_common_set(led_cdev, value, BLUE);
+ return blinkm_led_common_set(led_cdev, value, BLUE);
}
static void blinkm_init_hw(struct i2c_client *client)
@@ -669,7 +616,6 @@ static int blinkm_probe(struct i2c_client *client,
led[i]->id = i;
led[i]->led_cdev.max_brightness = 255;
led[i]->led_cdev.flags = LED_CORE_SUSPENDRESUME;
- atomic_set(&led[i]->active, 0);
switch (i) {
case RED:
snprintf(blinkm_led_name, sizeof(blinkm_led_name),
@@ -677,7 +623,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
- led[i]->led_cdev.brightness_set = blinkm_led_red_set;
+ led[i]->led_cdev.brightness_set_blocking =
+ blinkm_led_red_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
@@ -693,7 +640,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
- led[i]->led_cdev.brightness_set = blinkm_led_green_set;
+ led[i]->led_cdev.brightness_set_blocking =
+ blinkm_led_green_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
@@ -709,7 +657,8 @@ static int blinkm_probe(struct i2c_client *client,
client->adapter->nr,
client->addr);
led[i]->led_cdev.name = blinkm_led_name;
- led[i]->led_cdev.brightness_set = blinkm_led_blue_set;
+ led[i]->led_cdev.brightness_set_blocking =
+ blinkm_led_blue_set;
err = led_classdev_register(&client->dev,
&led[i]->led_cdev);
if (err < 0) {
@@ -746,10 +695,8 @@ static int blinkm_remove(struct i2c_client *client)
int i;
/* make sure no workqueue entries are pending */
- for (i = 0; i < 3; i++) {
- flush_scheduled_work();
+ for (i = 0; i < 3; i++)
led_classdev_unregister(&data->blinkm_leds[i].led_cdev);
- }
/* reset rgb */
data->next_red = 0x00;
diff --git a/drivers/leds/leds-da903x.c b/drivers/leds/leds-da903x.c
index 952ba96e..4752a2b 100644
--- a/drivers/leds/leds-da903x.c
+++ b/drivers/leds/leds-da903x.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <linux/workqueue.h>
#include <linux/mfd/da903x.h>
#include <linux/slab.h>
@@ -33,9 +32,7 @@
struct da903x_led {
struct led_classdev cdev;
- struct work_struct work;
struct device *master;
- enum led_brightness new_brightness;
int id;
int flags;
};
@@ -43,11 +40,13 @@ struct da903x_led {
#define DA9030_LED_OFFSET(id) ((id) - DA9030_ID_LED_1)
#define DA9034_LED_OFFSET(id) ((id) - DA9034_ID_LED_1)
-static void da903x_led_work(struct work_struct *work)
+static int da903x_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- struct da903x_led *led = container_of(work, struct da903x_led, work);
+ struct da903x_led *led =
+ container_of(led_cdev, struct da903x_led, cdev);
uint8_t val;
- int offset;
+ int offset, ret = -EINVAL;
switch (led->id) {
case DA9030_ID_LED_1:
@@ -57,37 +56,31 @@ static void da903x_led_work(struct work_struct *work)
case DA9030_ID_LED_PC:
offset = DA9030_LED_OFFSET(led->id);
val = led->flags & ~0x87;
- val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
- val |= (0x7 - (led->new_brightness >> 5)) & 0x7; /* PWM<2:0> */
- da903x_write(led->master, DA9030_LED1_CONTROL + offset, val);
+ val |= value ? 0x80 : 0; /* EN bit */
+ val |= (0x7 - (value >> 5)) & 0x7; /* PWM<2:0> */
+ ret = da903x_write(led->master, DA9030_LED1_CONTROL + offset,
+ val);
break;
case DA9030_ID_VIBRA:
val = led->flags & ~0x80;
- val |= (led->new_brightness) ? 0x80 : 0; /* EN bit */
- da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
+ val |= value ? 0x80 : 0; /* EN bit */
+ ret = da903x_write(led->master, DA9030_MISC_CONTROL_A, val);
break;
case DA9034_ID_LED_1:
case DA9034_ID_LED_2:
offset = DA9034_LED_OFFSET(led->id);
- val = (led->new_brightness * 0x5f / LED_FULL) & 0x7f;
+ val = (value * 0x5f / LED_FULL) & 0x7f;
val |= (led->flags & DA9034_LED_RAMP) ? 0x80 : 0;
- da903x_write(led->master, DA9034_LED1_CONTROL + offset, val);
+ ret = da903x_write(led->master, DA9034_LED1_CONTROL + offset,
+ val);
break;
case DA9034_ID_VIBRA:
- val = led->new_brightness & 0xfe;
- da903x_write(led->master, DA9034_VIBRA, val);
+ val = value & 0xfe;
+ ret = da903x_write(led->master, DA9034_VIBRA, val);
break;
}
-}
-static void da903x_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct da903x_led *led;
-
- led = container_of(led_cdev, struct da903x_led, cdev);
- led->new_brightness = value;
- schedule_work(&led->work);
+ return ret;
}
static int da903x_led_probe(struct platform_device *pdev)
@@ -113,15 +106,12 @@ static int da903x_led_probe(struct platform_device *pdev)
led->cdev.name = pdata->name;
led->cdev.default_trigger = pdata->default_trigger;
- led->cdev.brightness_set = da903x_led_set;
+ led->cdev.brightness_set_blocking = da903x_led_set;
led->cdev.brightness = LED_OFF;
led->id = id;
led->flags = pdata->flags;
led->master = pdev->dev.parent;
- led->new_brightness = LED_OFF;
-
- INIT_WORK(&led->work, da903x_led_work);
ret = led_classdev_register(led->master, &led->cdev);
if (ret) {
diff --git a/drivers/leds/leds-da9052.c b/drivers/leds/leds-da9052.c
index 28291b6..f8c7d82 100644
--- a/drivers/leds/leds-da9052.c
+++ b/drivers/leds/leds-da9052.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/mfd/da9052/reg.h>
@@ -32,11 +31,9 @@
struct da9052_led {
struct led_classdev cdev;
- struct work_struct work;
struct da9052 *da9052;
unsigned char led_index;
unsigned char id;
- int brightness;
};
static unsigned char led_reg[] = {
@@ -44,12 +41,13 @@ static unsigned char led_reg[] = {
DA9052_LED_CONT_5_REG,
};
-static int da9052_set_led_brightness(struct da9052_led *led)
+static int da9052_set_led_brightness(struct da9052_led *led,
+ enum led_brightness brightness)
{
u8 val;
int error;
- val = (led->brightness & 0x7f) | DA9052_LED_CONT_DIM;
+ val = (brightness & 0x7f) | DA9052_LED_CONT_DIM;
error = da9052_reg_write(led->da9052, led_reg[led->led_index], val);
if (error < 0)
@@ -58,21 +56,13 @@ static int da9052_set_led_brightness(struct da9052_led *led)
return error;
}
-static void da9052_led_work(struct work_struct *work)
-{
- struct da9052_led *led = container_of(work, struct da9052_led, work);
-
- da9052_set_led_brightness(led);
-}
-
-static void da9052_led_set(struct led_classdev *led_cdev,
+static int da9052_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- struct da9052_led *led;
+ struct da9052_led *led =
+ container_of(led_cdev, struct da9052_led, cdev);
- led = container_of(led_cdev, struct da9052_led, cdev);
- led->brightness = value;
- schedule_work(&led->work);
+ return da9052_set_led_brightness(led, value);
}
static int da9052_configure_leds(struct da9052 *da9052)
@@ -133,13 +123,11 @@ static int da9052_led_probe(struct platform_device *pdev)
for (i = 0; i < pled->num_leds; i++) {
led[i].cdev.name = pled->leds[i].name;
- led[i].cdev.brightness_set = da9052_led_set;
+ led[i].cdev.brightness_set_blocking = da9052_led_set;
led[i].cdev.brightness = LED_OFF;
led[i].cdev.max_brightness = DA9052_MAX_BRIGHTNESS;
- led[i].brightness = LED_OFF;
led[i].led_index = pled->leds[i].flags;
led[i].da9052 = dev_get_drvdata(pdev->dev.parent);
- INIT_WORK(&led[i].work, da9052_led_work);
error = led_classdev_register(pdev->dev.parent, &led[i].cdev);
if (error) {
@@ -148,7 +136,8 @@ static int da9052_led_probe(struct platform_device *pdev)
goto err_register;
}
- error = da9052_set_led_brightness(&led[i]);
+ error = da9052_set_led_brightness(&led[i],
+ led[i].cdev.brightness);
if (error) {
dev_err(&pdev->dev, "Unable to init led %d\n",
led[i].led_index);
@@ -166,10 +155,8 @@ static int da9052_led_probe(struct platform_device *pdev)
return 0;
err_register:
- for (i = i - 1; i >= 0; i--) {
+ for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
- }
err:
return error;
}
@@ -187,10 +174,8 @@ static int da9052_led_remove(struct platform_device *pdev)
pled = pdata->pled;
for (i = 0; i < pled->num_leds; i++) {
- led[i].brightness = 0;
- da9052_set_led_brightness(&led[i]);
+ da9052_set_led_brightness(&led[i], LED_OFF);
led_classdev_unregister(&led[i].cdev);
- cancel_work_sync(&led[i].work);
}
return 0;
diff --git a/drivers/leds/leds-dac124s085.c b/drivers/leds/leds-dac124s085.c
index 3141596..5a5a86d 100644
--- a/drivers/leds/leds-dac124s085.c
+++ b/drivers/leds/leds-dac124s085.c
@@ -13,20 +13,15 @@
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
#include <linux/spi/spi.h>
struct dac124s085_led {
struct led_classdev ldev;
struct spi_device *spi;
int id;
- int brightness;
char name[sizeof("dac124s085-3")];
struct mutex mutex;
- struct work_struct work;
- spinlock_t lock;
};
struct dac124s085 {
@@ -38,29 +33,21 @@ struct dac124s085 {
#define ALL_WRITE_UPDATE (2 << 12)
#define POWER_DOWN_OUTPUT (3 << 12)
-static void dac124s085_led_work(struct work_struct *work)
+static int dac124s085_set_brightness(struct led_classdev *ldev,
+ enum led_brightness brightness)
{
- struct dac124s085_led *led = container_of(work, struct dac124s085_led,
- work);
+ struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
+ ldev);
u16 word;
+ int ret;
mutex_lock(&led->mutex);
word = cpu_to_le16(((led->id) << 14) | REG_WRITE_UPDATE |
- (led->brightness & 0xfff));
- spi_write(led->spi, (const u8 *)&word, sizeof(word));
+ (brightness & 0xfff));
+ ret = spi_write(led->spi, (const u8 *)&word, sizeof(word));
mutex_unlock(&led->mutex);
-}
-
-static void dac124s085_set_brightness(struct led_classdev *ldev,
- enum led_brightness brightness)
-{
- struct dac124s085_led *led = container_of(ldev, struct dac124s085_led,
- ldev);
- spin_lock(&led->lock);
- led->brightness = brightness;
- schedule_work(&led->work);
- spin_unlock(&led->lock);
+ return ret;
}
static int dac124s085_probe(struct spi_device *spi)
@@ -78,16 +65,13 @@ static int dac124s085_probe(struct spi_device *spi)
for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
led = dac->leds + i;
led->id = i;
- led->brightness = LED_OFF;
led->spi = spi;
snprintf(led->name, sizeof(led->name), "dac124s085-%d", i);
- spin_lock_init(&led->lock);
- INIT_WORK(&led->work, dac124s085_led_work);
mutex_init(&led->mutex);
led->ldev.name = led->name;
led->ldev.brightness = LED_OFF;
led->ldev.max_brightness = 0xfff;
- led->ldev.brightness_set = dac124s085_set_brightness;
+ led->ldev.brightness_set_blocking = dac124s085_set_brightness;
ret = led_classdev_register(&spi->dev, &led->ldev);
if (ret < 0)
goto eledcr;
@@ -109,10 +93,8 @@ static int dac124s085_remove(struct spi_device *spi)
struct dac124s085 *dac = spi_get_drvdata(spi);
int i;
- for (i = 0; i < ARRAY_SIZE(dac->leds); i++) {
+ for (i = 0; i < ARRAY_SIZE(dac->leds); i++)
led_classdev_unregister(&dac->leds[i].ldev);
- cancel_work_sync(&dac->leds[i].work);
- }
return 0;
}
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 5db4515..7bc5328 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -20,32 +20,16 @@
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
struct gpio_desc *gpiod;
- struct work_struct work;
- u8 new_level;
u8 can_sleep;
u8 blinking;
int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
-static void gpio_led_work(struct work_struct *work)
-{
- struct gpio_led_data *led_dat =
- container_of(work, struct gpio_led_data, work);
-
- if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpiod,
- led_dat->new_level, NULL, NULL);
- led_dat->blinking = 0;
- } else
- gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
-}
-
static void gpio_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
@@ -58,23 +42,25 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
- /* Setting GPIOs with I2C/etc requires a task context, and we don't
- * seem to have a reliable way to know if we're already in one; so
- * let's just assume the worst.
- */
- if (led_dat->can_sleep) {
- led_dat->new_level = level;
- schedule_work(&led_dat->work);
+ if (led_dat->blinking) {
+ led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
+ NULL, NULL);
+ led_dat->blinking = 0;
} else {
- if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
- NULL, NULL);
- led_dat->blinking = 0;
- } else
+ if (led_dat->can_sleep)
+ gpiod_set_value_cansleep(led_dat->gpiod, level);
+ else
gpiod_set_value(led_dat->gpiod, level);
}
}
+static int gpio_led_set_blocking(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ gpio_led_set(led_cdev, value);
+ return 0;
+}
+
static int gpio_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on, unsigned long *delay_off)
{
@@ -125,12 +111,15 @@ static int create_gpio_led(const struct gpio_led *template,
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
+ if (!led_dat->can_sleep)
+ led_dat->cdev.brightness_set = gpio_led_set;
+ else
+ led_dat->cdev.brightness_set_blocking = gpio_led_set_blocking;
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
led_dat->cdev.blink_set = gpio_blink_set;
}
- led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
@@ -143,17 +132,9 @@ static int create_gpio_led(const struct gpio_led *template,
if (ret < 0)
return ret;
- INIT_WORK(&led_dat->work, gpio_led_work);
-
return led_classdev_register(parent, &led_dat->cdev);
}
-static void delete_gpio_led(struct gpio_led_data *led)
-{
- led_classdev_unregister(&led->cdev);
- cancel_work_sync(&led->work);
-}
-
struct gpio_leds_priv {
int num_leds;
struct gpio_led_data leds[];
@@ -233,7 +214,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
err:
for (count = priv->num_leds - 1; count >= 0; count--)
- delete_gpio_led(&priv->leds[count]);
+ led_classdev_unregister(&priv->leds[count].cdev);
return ERR_PTR(ret);
}
@@ -265,7 +246,8 @@ static int gpio_led_probe(struct platform_device *pdev)
if (ret < 0) {
/* On failure: unwind the led creations */
for (i = i - 1; i >= 0; i--)
- delete_gpio_led(&priv->leds[i]);
+ led_classdev_unregister(
+ &priv->leds[i].cdev);
return ret;
}
}
@@ -286,7 +268,7 @@ static int gpio_led_remove(struct platform_device *pdev)
int i;
for (i = 0; i < priv->num_leds; i++)
- delete_gpio_led(&priv->leds[i]);
+ led_classdev_unregister(&priv->leds[i].cdev);
return 0;
}
diff --git a/drivers/leds/leds-ipaq-micro.c b/drivers/leds/leds-ipaq-micro.c
index fa262b6..02f1733 100644
--- a/drivers/leds/leds-ipaq-micro.c
+++ b/drivers/leds/leds-ipaq-micro.c
@@ -20,7 +20,7 @@
#define LED_AUTOSTOP (1 << 5) /* LED ON/OFF auto stop set 0:disable, 1:enable */
#define LED_ALWAYS (1 << 6) /* LED Interrupt Mask 0:No mask, 1:mask */
-static void micro_leds_brightness_set(struct led_classdev *led_cdev,
+static int micro_leds_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct ipaq_micro *micro = dev_get_drvdata(led_cdev->dev->parent->parent);
@@ -50,7 +50,7 @@ static void micro_leds_brightness_set(struct led_classdev *led_cdev,
msg.tx_data[2] = 1;
msg.tx_data[3] = 0; /* Duty cycle 256 */
}
- ipaq_micro_tx_msg_sync(micro, &msg);
+ return ipaq_micro_tx_msg_sync(micro, &msg);
}
/* Maximum duty cycle in ms 256/10 sec = 25600 ms */
@@ -102,7 +102,7 @@ static int micro_leds_blink_set(struct led_classdev *led_cdev,
static struct led_classdev micro_led = {
.name = "led-ipaq-micro",
- .brightness_set = micro_leds_brightness_set,
+ .brightness_set_blocking = micro_leds_brightness_set,
.blink_set = micro_leds_blink_set,
.flags = LED_CORE_SUSPENDRESUME,
};
diff --git a/drivers/leds/leds-ktd2692.c b/drivers/leds/leds-ktd2692.c
index feca07b..bf23ba1 100644
--- a/drivers/leds/leds-ktd2692.c
+++ b/drivers/leds/leds-ktd2692.c
@@ -18,7 +18,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
/* Value related the movie mode */
#define KTD2692_MOVIE_MODE_CURRENT_LEVELS 16
@@ -82,7 +81,6 @@ struct ktd2692_context {
/* secures access to the device */
struct mutex lock;
struct regulator *regulator;
- struct work_struct work_brightness_set;
struct gpio_desc *aux_gpio;
struct gpio_desc *ctrl_gpio;
@@ -158,9 +156,12 @@ static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
ktd2692_expresswire_end(led);
}
-static void ktd2692_brightness_set(struct ktd2692_context *led,
- enum led_brightness brightness)
+static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
+
mutex_lock(&led->lock);
if (brightness == LED_OFF) {
@@ -174,33 +175,6 @@ static void ktd2692_brightness_set(struct ktd2692_context *led,
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
mutex_unlock(&led->lock);
-}
-
-static void ktd2692_brightness_set_work(struct work_struct *work)
-{
- struct ktd2692_context *led =
- container_of(work, struct ktd2692_context, work_brightness_set);
-
- ktd2692_brightness_set(led, led->torch_brightness);
-}
-
-static void ktd2692_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
-
- led->torch_brightness = brightness;
- schedule_work(&led->work_brightness_set);
-}
-
-static int ktd2692_led_brightness_set_sync(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct ktd2692_context *led = fled_cdev_to_led(fled_cdev);
-
- ktd2692_brightness_set(led, brightness);
return 0;
}
@@ -332,21 +306,24 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
&cfg->movie_max_microamp);
if (ret) {
dev_err(dev, "failed to parse led-max-microamp\n");
- return ret;
+ goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-microamp",
&cfg->flash_max_microamp);
if (ret) {
dev_err(dev, "failed to parse flash-max-microamp\n");
- return ret;
+ goto err_parse_dt;
}
ret = of_property_read_u32(child_node, "flash-max-timeout-us",
&cfg->flash_max_timeout);
- if (ret)
+ if (ret) {
dev_err(dev, "failed to parse flash-max-timeout-us\n");
+ goto err_parse_dt;
+ }
+err_parse_dt:
of_node_put(child_node);
return ret;
}
@@ -381,12 +358,10 @@ static int ktd2692_probe(struct platform_device *pdev)
fled_cdev->ops = &flash_ops;
led_cdev->max_brightness = led_cfg.max_brightness;
- led_cdev->brightness_set = ktd2692_led_brightness_set;
- led_cdev->brightness_set_sync = ktd2692_led_brightness_set_sync;
+ led_cdev->brightness_set_blocking = ktd2692_led_brightness_set;
led_cdev->flags |= LED_CORE_SUSPENDRESUME | LED_DEV_CAP_FLASH;
mutex_init(&led->lock);
- INIT_WORK(&led->work_brightness_set, ktd2692_brightness_set_work);
platform_set_drvdata(pdev, led);
@@ -408,7 +383,6 @@ static int ktd2692_remove(struct platform_device *pdev)
int ret;
led_classdev_flash_unregister(&led->fled_cdev);
- cancel_work_sync(&led->work_brightness_set);
if (led->regulator) {
ret = regulator_disable(led->regulator);
diff --git a/drivers/leds/leds-lm3533.c b/drivers/leds/leds-lm3533.c
index 6e2e020..196dcb5 100644
--- a/drivers/leds/leds-lm3533.c
+++ b/drivers/leds/leds-lm3533.c
@@ -17,7 +17,6 @@
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/mfd/lm3533.h>
@@ -53,9 +52,6 @@ struct lm3533_led {
struct mutex mutex;
unsigned long flags;
-
- struct work_struct work;
- u8 new_brightness;
};
@@ -123,27 +119,17 @@ out:
return ret;
}
-static void lm3533_led_work(struct work_struct *work)
-{
- struct lm3533_led *led = container_of(work, struct lm3533_led, work);
-
- dev_dbg(led->cdev.dev, "%s - %u\n", __func__, led->new_brightness);
-
- if (led->new_brightness == 0)
- lm3533_led_pattern_enable(led, 0); /* disable blink */
-
- lm3533_ctrlbank_set_brightness(&led->cb, led->new_brightness);
-}
-
-static void lm3533_led_set(struct led_classdev *cdev,
+static int lm3533_led_set(struct led_classdev *cdev,
enum led_brightness value)
{
struct lm3533_led *led = to_lm3533_led(cdev);
dev_dbg(led->cdev.dev, "%s - %d\n", __func__, value);
- led->new_brightness = value;
- schedule_work(&led->work);
+ if (value == 0)
+ lm3533_led_pattern_enable(led, 0); /* disable blink */
+
+ return lm3533_ctrlbank_set_brightness(&led->cb, value);
}
static enum led_brightness lm3533_led_get(struct led_classdev *cdev)
@@ -693,7 +679,7 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->lm3533 = lm3533;
led->cdev.name = pdata->name;
led->cdev.default_trigger = pdata->default_trigger;
- led->cdev.brightness_set = lm3533_led_set;
+ led->cdev.brightness_set_blocking = lm3533_led_set;
led->cdev.brightness_get = lm3533_led_get;
led->cdev.blink_set = lm3533_led_blink_set;
led->cdev.brightness = LED_OFF;
@@ -701,7 +687,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
led->id = pdev->id;
mutex_init(&led->mutex);
- INIT_WORK(&led->work, lm3533_led_work);
/* The class framework makes a callback to get brightness during
* registration so use parent device (for error reporting) until
@@ -733,7 +718,6 @@ static int lm3533_led_probe(struct platform_device *pdev)
err_unregister:
led_classdev_unregister(&led->cdev);
- flush_work(&led->work);
return ret;
}
@@ -746,7 +730,6 @@ static int lm3533_led_remove(struct platform_device *pdev)
lm3533_ctrlbank_disable(&led->cb);
led_classdev_unregister(&led->cdev);
- flush_work(&led->work);
return 0;
}
@@ -760,7 +743,6 @@ static void lm3533_led_shutdown(struct platform_device *pdev)
lm3533_ctrlbank_disable(&led->cb);
lm3533_led_set(&led->cdev, LED_OFF); /* disable blink */
- flush_work(&led->work);
}
static struct platform_driver lm3533_led_driver = {
diff --git a/drivers/leds/leds-lm355x.c b/drivers/leds/leds-lm355x.c
index 48872997..6cb94f9 100644
--- a/drivers/leds/leds-lm355x.c
+++ b/drivers/leds/leds-lm355x.c
@@ -16,7 +16,6 @@
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/regmap.h>
-#include <linux/workqueue.h>
#include <linux/platform_data/leds-lm355x.h>
enum lm355x_type {
@@ -59,14 +58,6 @@ struct lm355x_chip_data {
struct led_classdev cdev_torch;
struct led_classdev cdev_indicator;
- struct work_struct work_flash;
- struct work_struct work_torch;
- struct work_struct work_indicator;
-
- u8 br_flash;
- u8 br_torch;
- u8 br_indicator;
-
struct lm355x_platform_data *pdata;
struct regmap *regmap;
struct mutex lock;
@@ -204,7 +195,7 @@ out:
}
/* chip control */
-static void lm355x_control(struct lm355x_chip_data *chip,
+static int lm355x_control(struct lm355x_chip_data *chip,
u8 brightness, enum lm355x_mode opmode)
{
int ret;
@@ -301,7 +292,7 @@ static void lm355x_control(struct lm355x_chip_data *chip,
case MODE_SHDN:
break;
default:
- return;
+ return -EINVAL;
}
/* operation mode control */
ret = regmap_update_bits(chip->regmap, preg[REG_OPMODE].regno,
@@ -309,73 +300,55 @@ static void lm355x_control(struct lm355x_chip_data *chip,
opmode << preg[REG_OPMODE].shift);
if (ret < 0)
goto out;
- return;
+ return ret;
out:
dev_err(chip->dev, "%s:i2c access fail to register\n", __func__);
- return;
+ return ret;
}
/* torch */
-static void lm355x_deferred_torch_brightness_set(struct work_struct *work)
-{
- struct lm355x_chip_data *chip =
- container_of(work, struct lm355x_chip_data, work_torch);
- mutex_lock(&chip->lock);
- lm355x_control(chip, chip->br_torch, MODE_TORCH);
- mutex_unlock(&chip->lock);
-}
-
-static void lm355x_torch_brightness_set(struct led_classdev *cdev,
+static int lm355x_torch_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_torch);
-
- chip->br_torch = brightness;
- schedule_work(&chip->work_torch);
-}
-
-/* flash */
-static void lm355x_deferred_strobe_brightness_set(struct work_struct *work)
-{
- struct lm355x_chip_data *chip =
- container_of(work, struct lm355x_chip_data, work_flash);
+ int ret;
mutex_lock(&chip->lock);
- lm355x_control(chip, chip->br_flash, MODE_FLASH);
+ ret = lm355x_control(chip, brightness, MODE_TORCH);
mutex_unlock(&chip->lock);
+ return ret;
}
-static void lm355x_strobe_brightness_set(struct led_classdev *cdev,
+/* flash */
+
+static int lm355x_strobe_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_flash);
-
- chip->br_flash = brightness;
- schedule_work(&chip->work_flash);
-}
-
-/* indicator */
-static void lm355x_deferred_indicator_brightness_set(struct work_struct *work)
-{
- struct lm355x_chip_data *chip =
- container_of(work, struct lm355x_chip_data, work_indicator);
+ int ret;
mutex_lock(&chip->lock);
- lm355x_control(chip, chip->br_indicator, MODE_INDIC);
+ ret = lm355x_control(chip, brightness, MODE_FLASH);
mutex_unlock(&chip->lock);
+ return ret;
}
-static void lm355x_indicator_brightness_set(struct led_classdev *cdev,
+/* indicator */
+
+static int lm355x_indicator_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm355x_chip_data *chip =
container_of(cdev, struct lm355x_chip_data, cdev_indicator);
+ int ret;
- chip->br_indicator = brightness;
- schedule_work(&chip->work_indicator);
+ mutex_lock(&chip->lock);
+ ret = lm355x_control(chip, brightness, MODE_INDIC);
+ mutex_unlock(&chip->lock);
+ return ret;
}
/* indicator pattern only for lm3556*/
@@ -479,34 +452,31 @@ static int lm355x_probe(struct i2c_client *client,
goto err_out;
/* flash */
- INIT_WORK(&chip->work_flash, lm355x_deferred_strobe_brightness_set);
chip->cdev_flash.name = "flash";
chip->cdev_flash.max_brightness = 16;
- chip->cdev_flash.brightness_set = lm355x_strobe_brightness_set;
+ chip->cdev_flash.brightness_set_blocking = lm355x_strobe_brightness_set;
chip->cdev_flash.default_trigger = "flash";
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_flash);
if (err < 0)
goto err_out;
/* torch */
- INIT_WORK(&chip->work_torch, lm355x_deferred_torch_brightness_set);
chip->cdev_torch.name = "torch";
chip->cdev_torch.max_brightness = 8;
- chip->cdev_torch.brightness_set = lm355x_torch_brightness_set;
+ chip->cdev_torch.brightness_set_blocking = lm355x_torch_brightness_set;
chip->cdev_torch.default_trigger = "torch";
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_torch);
if (err < 0)
goto err_create_torch_file;
/* indicator */
- INIT_WORK(&chip->work_indicator,
- lm355x_deferred_indicator_brightness_set);
chip->cdev_indicator.name = "indicator";
if (id->driver_data == CHIP_LM3554)
chip->cdev_indicator.max_brightness = 4;
else
chip->cdev_indicator.max_brightness = 8;
- chip->cdev_indicator.brightness_set = lm355x_indicator_brightness_set;
+ chip->cdev_indicator.brightness_set_blocking =
+ lm355x_indicator_brightness_set;
/* indicator pattern control only for LM3556 */
if (id->driver_data == CHIP_LM3556)
chip->cdev_indicator.groups = lm355x_indicator_groups;
@@ -534,11 +504,8 @@ static int lm355x_remove(struct i2c_client *client)
regmap_write(chip->regmap, preg[REG_OPMODE].regno, 0);
led_classdev_unregister(&chip->cdev_indicator);
- flush_work(&chip->work_indicator);
led_classdev_unregister(&chip->cdev_torch);
- flush_work(&chip->work_torch);
led_classdev_unregister(&chip->cdev_flash);
- flush_work(&chip->work_flash);
dev_info(&client->dev, "%s is removed\n", lm355x_name[chip->type]);
return 0;
diff --git a/drivers/leds/leds-lm3642.c b/drivers/leds/leds-lm3642.c
index 02ebe34..cada084 100644
--- a/drivers/leds/leds-lm3642.c
+++ b/drivers/leds/leds-lm3642.c
@@ -15,7 +15,6 @@
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/regmap.h>
-#include <linux/workqueue.h>
#include <linux/platform_data/leds-lm3642.h>
#define REG_FILT_TIME (0x0)
@@ -73,10 +72,6 @@ struct lm3642_chip_data {
struct led_classdev cdev_torch;
struct led_classdev cdev_indicator;
- struct work_struct work_flash;
- struct work_struct work_torch;
- struct work_struct work_indicator;
-
u8 br_flash;
u8 br_torch;
u8 br_indicator;
@@ -209,24 +204,18 @@ out_strtoint:
static DEVICE_ATTR(torch_pin, S_IWUSR, NULL, lm3642_torch_pin_store);
-static void lm3642_deferred_torch_brightness_set(struct work_struct *work)
-{
- struct lm3642_chip_data *chip =
- container_of(work, struct lm3642_chip_data, work_torch);
-
- mutex_lock(&chip->lock);
- lm3642_control(chip, chip->br_torch, MODES_TORCH);
- mutex_unlock(&chip->lock);
-}
-
-static void lm3642_torch_brightness_set(struct led_classdev *cdev,
+static int lm3642_torch_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_torch);
+ int ret;
+ mutex_lock(&chip->lock);
chip->br_torch = brightness;
- schedule_work(&chip->work_torch);
+ ret = lm3642_control(chip, chip->br_torch, MODES_TORCH);
+ mutex_unlock(&chip->lock);
+ return ret;
}
/* flash */
@@ -266,45 +255,33 @@ out_strtoint:
static DEVICE_ATTR(strobe_pin, S_IWUSR, NULL, lm3642_strobe_pin_store);
-static void lm3642_deferred_strobe_brightness_set(struct work_struct *work)
-{
- struct lm3642_chip_data *chip =
- container_of(work, struct lm3642_chip_data, work_flash);
-
- mutex_lock(&chip->lock);
- lm3642_control(chip, chip->br_flash, MODES_FLASH);
- mutex_unlock(&chip->lock);
-}
-
-static void lm3642_strobe_brightness_set(struct led_classdev *cdev,
+static int lm3642_strobe_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_flash);
-
- chip->br_flash = brightness;
- schedule_work(&chip->work_flash);
-}
-
-/* indicator */
-static void lm3642_deferred_indicator_brightness_set(struct work_struct *work)
-{
- struct lm3642_chip_data *chip =
- container_of(work, struct lm3642_chip_data, work_indicator);
+ int ret;
mutex_lock(&chip->lock);
- lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+ chip->br_flash = brightness;
+ ret = lm3642_control(chip, chip->br_flash, MODES_FLASH);
mutex_unlock(&chip->lock);
+ return ret;
}
-static void lm3642_indicator_brightness_set(struct led_classdev *cdev,
+/* indicator */
+static int lm3642_indicator_brightness_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lm3642_chip_data *chip =
container_of(cdev, struct lm3642_chip_data, cdev_indicator);
+ int ret;
+ mutex_lock(&chip->lock);
chip->br_indicator = brightness;
- schedule_work(&chip->work_indicator);
+ ret = lm3642_control(chip, chip->br_indicator, MODES_INDIC);
+ mutex_unlock(&chip->lock);
+ return ret;
}
static const struct regmap_config lm3642_regmap = {
@@ -371,10 +348,9 @@ static int lm3642_probe(struct i2c_client *client,
goto err_out;
/* flash */
- INIT_WORK(&chip->work_flash, lm3642_deferred_strobe_brightness_set);
chip->cdev_flash.name = "flash";
chip->cdev_flash.max_brightness = 16;
- chip->cdev_flash.brightness_set = lm3642_strobe_brightness_set;
+ chip->cdev_flash.brightness_set_blocking = lm3642_strobe_brightness_set;
chip->cdev_flash.default_trigger = "flash";
chip->cdev_flash.groups = lm3642_flash_groups,
err = led_classdev_register((struct device *)
@@ -385,10 +361,9 @@ static int lm3642_probe(struct i2c_client *client,
}
/* torch */
- INIT_WORK(&chip->work_torch, lm3642_deferred_torch_brightness_set);
chip->cdev_torch.name = "torch";
chip->cdev_torch.max_brightness = 8;
- chip->cdev_torch.brightness_set = lm3642_torch_brightness_set;
+ chip->cdev_torch.brightness_set_blocking = lm3642_torch_brightness_set;
chip->cdev_torch.default_trigger = "torch";
chip->cdev_torch.groups = lm3642_torch_groups,
err = led_classdev_register((struct device *)
@@ -399,11 +374,10 @@ static int lm3642_probe(struct i2c_client *client,
}
/* indicator */
- INIT_WORK(&chip->work_indicator,
- lm3642_deferred_indicator_brightness_set);
chip->cdev_indicator.name = "indicator";
chip->cdev_indicator.max_brightness = 8;
- chip->cdev_indicator.brightness_set = lm3642_indicator_brightness_set;
+ chip->cdev_indicator.brightness_set_blocking =
+ lm3642_indicator_brightness_set;
err = led_classdev_register((struct device *)
&client->dev, &chip->cdev_indicator);
if (err < 0) {
@@ -427,11 +401,8 @@ static int lm3642_remove(struct i2c_client *client)
struct lm3642_chip_data *chip = i2c_get_clientdata(client);
led_classdev_unregister(&chip->cdev_indicator);
- flush_work(&chip->work_indicator);
led_classdev_unregister(&chip->cdev_torch);
- flush_work(&chip->work_torch);
led_classdev_unregister(&chip->cdev_flash);
- flush_work(&chip->work_flash);
regmap_write(chip->regmap, REG_ENABLE, 0);
return 0;
}
diff --git a/drivers/leds/leds-lp3944.c b/drivers/leds/leds-lp3944.c
index 53144fb..6c758ae 100644
--- a/drivers/leds/leds-lp3944.c
+++ b/drivers/leds/leds-lp3944.c
@@ -31,7 +31,6 @@
#include <linux/slab.h>
#include <linux/leds.h>
#include <linux/mutex.h>
-#include <linux/workqueue.h>
#include <linux/leds-lp3944.h>
/* Read Only Registers */
@@ -68,10 +67,8 @@
struct lp3944_led_data {
u8 id;
enum lp3944_type type;
- enum lp3944_status status;
struct led_classdev ldev;
struct i2c_client *client;
- struct work_struct work;
};
struct lp3944_data {
@@ -275,13 +272,12 @@ static int lp3944_led_set_blink(struct led_classdev *led_cdev,
dev_dbg(&led->client->dev, "%s: OK hardware accelerated blink!\n",
__func__);
- led->status = LP3944_LED_STATUS_DIM0;
- schedule_work(&led->work);
+ lp3944_led_set(led, LP3944_LED_STATUS_DIM0);
return 0;
}
-static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
+static int lp3944_led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct lp3944_led_data *led = ldev_to_led(led_cdev);
@@ -289,16 +285,7 @@ static void lp3944_led_set_brightness(struct led_classdev *led_cdev,
dev_dbg(&led->client->dev, "%s: %s, %d\n",
__func__, led_cdev->name, brightness);
- led->status = !!brightness;
- schedule_work(&led->work);
-}
-
-static void lp3944_led_work(struct work_struct *work)
-{
- struct lp3944_led_data *led;
-
- led = container_of(work, struct lp3944_led_data, work);
- lp3944_led_set(led, led->status);
+ return lp3944_led_set(led, !!brightness);
}
static int lp3944_configure(struct i2c_client *client,
@@ -318,14 +305,13 @@ static int lp3944_configure(struct i2c_client *client,
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led->type = pled->type;
- led->status = pled->status;
led->ldev.name = pled->name;
led->ldev.max_brightness = 1;
- led->ldev.brightness_set = lp3944_led_set_brightness;
+ led->ldev.brightness_set_blocking =
+ lp3944_led_set_brightness;
led->ldev.blink_set = lp3944_led_set_blink;
led->ldev.flags = LED_CORE_SUSPENDRESUME;
- INIT_WORK(&led->work, lp3944_led_work);
err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) {
dev_err(&client->dev,
@@ -336,14 +322,14 @@ static int lp3944_configure(struct i2c_client *client,
/* to expose the default value to userspace */
led->ldev.brightness =
- (enum led_brightness) led->status;
+ (enum led_brightness) pled->status;
/* Set the default led status */
- err = lp3944_led_set(led, led->status);
+ err = lp3944_led_set(led, pled->status);
if (err < 0) {
dev_err(&client->dev,
"%s couldn't set STATUS %d\n",
- led->ldev.name, led->status);
+ led->ldev.name, pled->status);
goto exit;
}
break;
@@ -364,7 +350,6 @@ exit:
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
break;
case LP3944_LED_TYPE_NONE:
@@ -424,7 +409,6 @@ static int lp3944_remove(struct i2c_client *client)
case LP3944_LED_TYPE_LED:
case LP3944_LED_TYPE_LED_INVERTED:
led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
break;
case LP3944_LED_TYPE_NONE:
diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c
index 63a9254..549b315 100644
--- a/drivers/leds/leds-lp5521.c
+++ b/drivers/leds/leds-lp5521.c
@@ -362,16 +362,17 @@ static int lp5521_run_selftest(struct lp55xx_chip *chip, char *buf)
return 0;
}
-static void lp5521_led_brightness_work(struct work_struct *work)
+static int lp5521_led_brightness(struct lp55xx_led *led)
{
- struct lp55xx_led *led = container_of(work, struct lp55xx_led,
- brightness_work);
struct lp55xx_chip *chip = led->chip;
+ int ret;
mutex_lock(&chip->lock);
- lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
+ ret = lp55xx_write(chip, LP5521_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
+
+ return ret;
}
static ssize_t show_engine_mode(struct device *dev,
@@ -501,7 +502,7 @@ static struct lp55xx_device_config lp5521_cfg = {
},
.max_channel = LP5521_MAX_LEDS,
.post_init_device = lp5521_post_init_device,
- .brightness_work_fn = lp5521_led_brightness_work,
+ .brightness_fn = lp5521_led_brightness,
.set_led_current = lp5521_set_led_current,
.firmware_cb = lp5521_firmware_loaded,
.run_engine = lp5521_run_engine,
diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c
index 1d0187f..c5b30f0 100644
--- a/drivers/leds/leds-lp5523.c
+++ b/drivers/leds/leds-lp5523.c
@@ -802,16 +802,16 @@ leave:
return ret;
}
-static void lp5523_led_brightness_work(struct work_struct *work)
+static int lp5523_led_brightness(struct lp55xx_led *led)
{
- struct lp55xx_led *led = container_of(work, struct lp55xx_led,
- brightness_work);
struct lp55xx_chip *chip = led->chip;
+ int ret;
mutex_lock(&chip->lock);
- lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
+ ret = lp55xx_write(chip, LP5523_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
+ return ret;
}
static LP55XX_DEV_ATTR_RW(engine1_mode, show_engine1_mode, store_engine1_mode);
@@ -867,7 +867,7 @@ static struct lp55xx_device_config lp5523_cfg = {
},
.max_channel = LP5523_MAX_LEDS,
.post_init_device = lp5523_post_init_device,
- .brightness_work_fn = lp5523_led_brightness_work,
+ .brightness_fn = lp5523_led_brightness,
.set_led_current = lp5523_set_led_current,
.firmware_cb = lp5523_firmware_loaded,
.run_engine = lp5523_run_engine,
diff --git a/drivers/leds/leds-lp5562.c b/drivers/leds/leds-lp5562.c
index 0360c59..b753338 100644
--- a/drivers/leds/leds-lp5562.c
+++ b/drivers/leds/leds-lp5562.c
@@ -311,10 +311,8 @@ static int lp5562_post_init_device(struct lp55xx_chip *chip)
return 0;
}
-static void lp5562_led_brightness_work(struct work_struct *work)
+static int lp5562_led_brightness(struct lp55xx_led *led)
{
- struct lp55xx_led *led = container_of(work, struct lp55xx_led,
- brightness_work);
struct lp55xx_chip *chip = led->chip;
u8 addr[] = {
LP5562_REG_R_PWM,
@@ -322,10 +320,13 @@ static void lp5562_led_brightness_work(struct work_struct *work)
LP5562_REG_B_PWM,
LP5562_REG_W_PWM,
};
+ int ret;
mutex_lock(&chip->lock);
- lp55xx_write(chip, addr[led->chan_nr], led->brightness);
+ ret = lp55xx_write(chip, addr[led->chan_nr], led->brightness);
mutex_unlock(&chip->lock);
+
+ return ret;
}
static void lp5562_write_program_memory(struct lp55xx_chip *chip,
@@ -503,7 +504,7 @@ static struct lp55xx_device_config lp5562_cfg = {
},
.post_init_device = lp5562_post_init_device,
.set_led_current = lp5562_set_led_current,
- .brightness_work_fn = lp5562_led_brightness_work,
+ .brightness_fn = lp5562_led_brightness,
.run_engine = lp5562_run_engine,
.firmware_cb = lp5562_firmware_loaded,
.dev_attr_group = &lp5562_group,
diff --git a/drivers/leds/leds-lp55xx-common.c b/drivers/leds/leds-lp55xx-common.c
index 59b7683..5377f22 100644
--- a/drivers/leds/leds-lp55xx-common.c
+++ b/drivers/leds/leds-lp55xx-common.c
@@ -134,13 +134,14 @@ static struct attribute *lp55xx_led_attrs[] = {
};
ATTRIBUTE_GROUPS(lp55xx_led);
-static void lp55xx_set_brightness(struct led_classdev *cdev,
+static int lp55xx_set_brightness(struct led_classdev *cdev,
enum led_brightness brightness)
{
struct lp55xx_led *led = cdev_to_lp55xx_led(cdev);
+ struct lp55xx_device_config *cfg = led->chip->cfg;
led->brightness = (u8)brightness;
- schedule_work(&led->brightness_work);
+ return cfg->brightness_fn(led);
}
static int lp55xx_init_led(struct lp55xx_led *led,
@@ -172,7 +173,7 @@ static int lp55xx_init_led(struct lp55xx_led *led,
return -EINVAL;
}
- led->cdev.brightness_set = lp55xx_set_brightness;
+ led->cdev.brightness_set_blocking = lp55xx_set_brightness;
led->cdev.groups = lp55xx_led_groups;
if (pdata->led_config[chan].name) {
@@ -464,7 +465,7 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
int ret;
int i;
- if (!cfg->brightness_work_fn) {
+ if (!cfg->brightness_fn) {
dev_err(&chip->cl->dev, "empty brightness configuration\n");
return -EINVAL;
}
@@ -481,8 +482,6 @@ int lp55xx_register_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
if (ret)
goto err_init_led;
- INIT_WORK(&each->brightness_work, cfg->brightness_work_fn);
-
chip->num_leds++;
each->chip = chip;
@@ -507,7 +506,6 @@ void lp55xx_unregister_leds(struct lp55xx_led *led, struct lp55xx_chip *chip)
for (i = 0; i < chip->num_leds; i++) {
each = led + i;
led_classdev_unregister(&each->cdev);
- flush_work(&each->brightness_work);
}
}
EXPORT_SYMBOL_GPL(lp55xx_unregister_leds);
diff --git a/drivers/leds/leds-lp55xx-common.h b/drivers/leds/leds-lp55xx-common.h
index c7f1e61..abf1fb5 100644
--- a/drivers/leds/leds-lp55xx-common.h
+++ b/drivers/leds/leds-lp55xx-common.h
@@ -95,7 +95,7 @@ struct lp55xx_reg {
* @enable : Chip specific enable command
* @max_channel : Maximum number of channels
* @post_init_device : Chip specific initialization code
- * @brightness_work_fn : Brightness work function
+ * @brightness_fn : Brightness function
* @set_led_current : LED current set function
* @firmware_cb : Call function when the firmware is loaded
* @run_engine : Run internal engine for pattern
@@ -110,7 +110,7 @@ struct lp55xx_device_config {
int (*post_init_device) (struct lp55xx_chip *chip);
/* access brightness register */
- void (*brightness_work_fn)(struct work_struct *work);
+ int (*brightness_fn)(struct lp55xx_led *led);
/* current setting function */
void (*set_led_current) (struct lp55xx_led *led, u8 led_current);
@@ -164,7 +164,6 @@ struct lp55xx_chip {
* @cdev : LED class device
* @led_current : Current setting at each led channel
* @max_current : Maximun current at each led channel
- * @brightness_work : Workqueue for brightness control
* @brightness : Brightness value
* @chip : The lp55xx chip data
*/
@@ -173,7 +172,6 @@ struct lp55xx_led {
struct led_classdev cdev;
u8 led_current;
u8 max_current;
- struct work_struct brightness_work;
u8 brightness;
struct lp55xx_chip *chip;
};
diff --git a/drivers/leds/leds-lp8501.c b/drivers/leds/leds-lp8501.c
index 3f54f6f..3f9675b 100644
--- a/drivers/leds/leds-lp8501.c
+++ b/drivers/leds/leds-lp8501.c
@@ -272,16 +272,17 @@ static void lp8501_firmware_loaded(struct lp55xx_chip *chip)
lp8501_update_program_memory(chip, fw->data, fw->size);
}
-static void lp8501_led_brightness_work(struct work_struct *work)
+static int lp8501_led_brightness(struct lp55xx_led *led)
{
- struct lp55xx_led *led = container_of(work, struct lp55xx_led,
- brightness_work);
struct lp55xx_chip *chip = led->chip;
+ int ret;
mutex_lock(&chip->lock);
- lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
+ ret = lp55xx_write(chip, LP8501_REG_LED_PWM_BASE + led->chan_nr,
led->brightness);
mutex_unlock(&chip->lock);
+
+ return ret;
}
/* Chip specific configurations */
@@ -296,7 +297,7 @@ static struct lp55xx_device_config lp8501_cfg = {
},
.max_channel = LP8501_MAX_LEDS,
.post_init_device = lp8501_post_init_device,
- .brightness_work_fn = lp8501_led_brightness_work,
+ .brightness_fn = lp8501_led_brightness,
.set_led_current = lp8501_set_led_current,
.firmware_cb = lp8501_firmware_loaded,
.run_engine = lp8501_run_engine,
diff --git a/drivers/leds/leds-lp8788.c b/drivers/leds/leds-lp8788.c
index 3409f03..0eee38f 100644
--- a/drivers/leds/leds-lp8788.c
+++ b/drivers/leds/leds-lp8788.c
@@ -26,10 +26,8 @@
struct lp8788_led {
struct lp8788 *lp;
struct mutex lock;
- struct work_struct work;
struct led_classdev led_dev;
enum lp8788_isink_number isink_num;
- enum led_brightness brightness;
int on;
};
@@ -76,24 +74,29 @@ static int lp8788_led_init_device(struct lp8788_led *led,
return lp8788_update_bits(led->lp, addr, mask, val);
}
-static void lp8788_led_enable(struct lp8788_led *led,
+static int lp8788_led_enable(struct lp8788_led *led,
enum lp8788_isink_number num, int on)
{
+ int ret;
+
u8 mask = 1 << num;
u8 val = on << num;
- if (lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val))
- return;
+ ret = lp8788_update_bits(led->lp, LP8788_ISINK_CTRL, mask, val);
+ if (ret == 0)
+ led->on = on;
- led->on = on;
+ return ret;
}
-static void lp8788_led_work(struct work_struct *work)
+static int lp8788_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness val)
{
- struct lp8788_led *led = container_of(work, struct lp8788_led, work);
+ struct lp8788_led *led =
+ container_of(led_cdev, struct lp8788_led, led_dev);
+
enum lp8788_isink_number num = led->isink_num;
- int enable;
- u8 val = led->brightness;
+ int enable, ret;
mutex_lock(&led->lock);
@@ -101,28 +104,21 @@ static void lp8788_led_work(struct work_struct *work)
case LP8788_ISINK_1:
case LP8788_ISINK_2:
case LP8788_ISINK_3:
- lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
+ ret = lp8788_write_byte(led->lp, lp8788_pwm_addr[num], val);
+ if (ret < 0)
+ goto unlock;
break;
default:
mutex_unlock(&led->lock);
- return;
+ return -EINVAL;
}
enable = (val > 0) ? 1 : 0;
if (enable != led->on)
- lp8788_led_enable(led, num, enable);
-
+ ret = lp8788_led_enable(led, num, enable);
+unlock:
mutex_unlock(&led->lock);
-}
-
-static void lp8788_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brt_val)
-{
- struct lp8788_led *led =
- container_of(led_cdev, struct lp8788_led, led_dev);
-
- led->brightness = brt_val;
- schedule_work(&led->work);
+ return ret;
}
static int lp8788_led_probe(struct platform_device *pdev)
@@ -139,7 +135,7 @@ static int lp8788_led_probe(struct platform_device *pdev)
led->lp = lp;
led->led_dev.max_brightness = MAX_BRIGHTNESS;
- led->led_dev.brightness_set = lp8788_brightness_set;
+ led->led_dev.brightness_set_blocking = lp8788_brightness_set;
led_pdata = lp->pdata ? lp->pdata->led_pdata : NULL;
@@ -149,7 +145,6 @@ static int lp8788_led_probe(struct platform_device *pdev)
led->led_dev.name = led_pdata->name;
mutex_init(&led->lock);
- INIT_WORK(&led->work, lp8788_led_work);
platform_set_drvdata(pdev, led);
@@ -173,7 +168,6 @@ static int lp8788_led_remove(struct platform_device *pdev)
struct lp8788_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->led_dev);
- flush_work(&led->work);
return 0;
}
diff --git a/drivers/leds/leds-lp8860.c b/drivers/leds/leds-lp8860.c
index 79f0843..3e70775 100644
--- a/drivers/leds/leds-lp8860.c
+++ b/drivers/leds/leds-lp8860.c
@@ -91,26 +91,22 @@
/**
* struct lp8860_led -
* @lock - Lock for reading/writing the device
- * @work - Work item used to off load the brightness register writes
* @client - Pointer to the I2C client
* @led_dev - led class device pointer
* @regmap - Devices register map
* @eeprom_regmap - EEPROM register map
* @enable_gpio - VDDIO/EN gpio to enable communication interface
* @regulator - LED supply regulator pointer
- * @brightness - Current brightness value requested
* @label - LED label
**/
struct lp8860_led {
struct mutex lock;
- struct work_struct work;
struct i2c_client *client;
struct led_classdev led_dev;
struct regmap *regmap;
struct regmap *eeprom_regmap;
struct gpio_desc *enable_gpio;
struct regulator *regulator;
- enum led_brightness brightness;
const char *label;
};
@@ -212,11 +208,13 @@ out:
return ret;
}
-static void lp8860_led_brightness_work(struct work_struct *work)
+static int lp8860_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brt_val)
{
- struct lp8860_led *led = container_of(work, struct lp8860_led, work);
+ struct lp8860_led *led =
+ container_of(led_cdev, struct lp8860_led, led_dev);
+ int disp_brightness = brt_val * 255;
int ret;
- int disp_brightness = led->brightness * 255;
mutex_lock(&led->lock);
@@ -241,16 +239,7 @@ static void lp8860_led_brightness_work(struct work_struct *work)
}
out:
mutex_unlock(&led->lock);
-}
-
-static void lp8860_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brt_val)
-{
- struct lp8860_led *led =
- container_of(led_cdev, struct lp8860_led, led_dev);
-
- led->brightness = brt_val;
- schedule_work(&led->work);
+ return ret;
}
static int lp8860_init(struct lp8860_led *led)
@@ -406,10 +395,9 @@ static int lp8860_probe(struct i2c_client *client,
led->client = client;
led->led_dev.name = led->label;
led->led_dev.max_brightness = LED_FULL;
- led->led_dev.brightness_set = lp8860_brightness_set;
+ led->led_dev.brightness_set_blocking = lp8860_brightness_set;
mutex_init(&led->lock);
- INIT_WORK(&led->work, lp8860_led_brightness_work);
i2c_set_clientdata(client, led);
@@ -448,7 +436,6 @@ static int lp8860_remove(struct i2c_client *client)
int ret;
led_classdev_unregister(&led->led_dev);
- cancel_work_sync(&led->work);
if (led->enable_gpio)
gpiod_direction_output(led->enable_gpio, 0);
diff --git a/drivers/leds/leds-lt3593.c b/drivers/leds/leds-lt3593.c
index 9f41124..a7ff510 100644
--- a/drivers/leds/leds-lt3593.c
+++ b/drivers/leds/leds-lt3593.c
@@ -19,7 +19,6 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
-#include <linux/workqueue.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/slab.h>
@@ -28,15 +27,14 @@
struct lt3593_led_data {
struct led_classdev cdev;
unsigned gpio;
- struct work_struct work;
- u8 new_level;
};
-static void lt3593_led_work(struct work_struct *work)
+static int lt3593_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- int pulses;
struct lt3593_led_data *led_dat =
- container_of(work, struct lt3593_led_data, work);
+ container_of(led_cdev, struct lt3593_led_data, cdev);
+ int pulses;
/*
* The LT3593 resets its internal current level register to the maximum
@@ -47,18 +45,18 @@ static void lt3593_led_work(struct work_struct *work)
* applied is to the output driver.
*/
- if (led_dat->new_level == 0) {
+ if (value == 0) {
gpio_set_value_cansleep(led_dat->gpio, 0);
- return;
+ return 0;
}
- pulses = 32 - (led_dat->new_level * 32) / 255;
+ pulses = 32 - (value * 32) / 255;
if (pulses == 0) {
gpio_set_value_cansleep(led_dat->gpio, 0);
mdelay(1);
gpio_set_value_cansleep(led_dat->gpio, 1);
- return;
+ return 0;
}
gpio_set_value_cansleep(led_dat->gpio, 1);
@@ -69,16 +67,8 @@ static void lt3593_led_work(struct work_struct *work)
gpio_set_value_cansleep(led_dat->gpio, 1);
udelay(1);
}
-}
-static void lt3593_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct lt3593_led_data *led_dat =
- container_of(led_cdev, struct lt3593_led_data, cdev);
-
- led_dat->new_level = value;
- schedule_work(&led_dat->work);
+ return 0;
}
static int create_lt3593_led(const struct gpio_led *template,
@@ -97,7 +87,7 @@ static int create_lt3593_led(const struct gpio_led *template,
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->gpio = template->gpio;
- led_dat->cdev.brightness_set = lt3593_led_set;
+ led_dat->cdev.brightness_set_blocking = lt3593_led_set;
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
@@ -111,8 +101,6 @@ static int create_lt3593_led(const struct gpio_led *template,
if (ret < 0)
return ret;
- INIT_WORK(&led_dat->work, lt3593_led_work);
-
ret = led_classdev_register(parent, &led_dat->cdev);
if (ret < 0)
return ret;
@@ -129,7 +117,6 @@ static void delete_lt3593_led(struct lt3593_led_data *led)
return;
led_classdev_unregister(&led->cdev);
- cancel_work_sync(&led->work);
}
static int lt3593_led_probe(struct platform_device *pdev)
diff --git a/drivers/leds/leds-max77693.c b/drivers/leds/leds-max77693.c
index afbb140..1eb58ef 100644
--- a/drivers/leds/leds-max77693.c
+++ b/drivers/leds/leds-max77693.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <media/v4l2-flash-led-class.h>
#define MODE_OFF 0
@@ -62,8 +61,6 @@ struct max77693_sub_led {
int fled_id;
/* corresponding LED Flash class device */
struct led_classdev_flash fled_cdev;
- /* assures led-triggers compatibility */
- struct work_struct work_brightness_set;
/* V4L2 Flash device */
struct v4l2_flash *v4l2_flash;
@@ -463,10 +460,14 @@ static int max77693_setup(struct max77693_led_device *led,
return max77693_set_mode_reg(led, MODE_OFF);
}
-static int __max77693_led_brightness_set(struct max77693_led_device *led,
- int fled_id, enum led_brightness value)
+/* LED subsystem callbacks */
+static int max77693_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- int ret;
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
+ struct max77693_led_device *led = sub_led_to_led(sub_led);
+ int fled_id = sub_led->fled_id, ret;
mutex_lock(&led->lock);
@@ -494,43 +495,8 @@ static int __max77693_led_brightness_set(struct max77693_led_device *led,
ret);
unlock:
mutex_unlock(&led->lock);
- return ret;
-}
-
-static void max77693_led_brightness_set_work(
- struct work_struct *work)
-{
- struct max77693_sub_led *sub_led =
- container_of(work, struct max77693_sub_led,
- work_brightness_set);
- struct max77693_led_device *led = sub_led_to_led(sub_led);
-
- __max77693_led_brightness_set(led, sub_led->fled_id,
- sub_led->torch_brightness);
-}
-
-/* LED subsystem callbacks */
-
-static int max77693_led_brightness_set_sync(
- struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
- struct max77693_led_device *led = sub_led_to_led(sub_led);
-
- return __max77693_led_brightness_set(led, sub_led->fled_id, value);
-}
-static void max77693_led_brightness_set(
- struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
- struct max77693_sub_led *sub_led = flcdev_to_sub_led(fled_cdev);
-
- sub_led->torch_brightness = value;
- schedule_work(&sub_led->work_brightness_set);
+ return ret;
}
static int max77693_led_flash_brightness_set(
@@ -682,6 +648,7 @@ static int max77693_led_parse_dt(struct max77693_led_device *led,
if (sub_nodes[fled_id]) {
dev_err(dev,
"Conflicting \"led-sources\" DT properties\n");
+ of_node_put(child_node);
return -EINVAL;
}
@@ -931,16 +898,13 @@ static void max77693_init_fled_cdev(struct max77693_sub_led *sub_led,
led_cdev->name = led_cfg->label[fled_id];
- led_cdev->brightness_set = max77693_led_brightness_set;
- led_cdev->brightness_set_sync = max77693_led_brightness_set_sync;
+ led_cdev->brightness_set_blocking = max77693_led_brightness_set;
led_cdev->max_brightness = (led->iout_joint ?
led_cfg->iout_torch_max[FLED1] +
led_cfg->iout_torch_max[FLED2] :
led_cfg->iout_torch_max[fled_id]) /
TORCH_IOUT_STEP;
led_cdev->flags |= LED_DEV_CAP_FLASH;
- INIT_WORK(&sub_led->work_brightness_set,
- max77693_led_brightness_set_work);
max77693_init_flash_settings(sub_led, led_cfg);
@@ -1062,13 +1026,11 @@ static int max77693_led_remove(struct platform_device *pdev)
if (led->iout_joint || max77693_fled_used(led, FLED1)) {
v4l2_flash_release(sub_leds[FLED1].v4l2_flash);
led_classdev_flash_unregister(&sub_leds[FLED1].fled_cdev);
- cancel_work_sync(&sub_leds[FLED1].work_brightness_set);
}
if (!led->iout_joint && max77693_fled_used(led, FLED2)) {
v4l2_flash_release(sub_leds[FLED2].v4l2_flash);
led_classdev_flash_unregister(&sub_leds[FLED2].fled_cdev);
- cancel_work_sync(&sub_leds[FLED2].work_brightness_set);
}
mutex_destroy(&led->lock);
diff --git a/drivers/leds/leds-max8997.c b/drivers/leds/leds-max8997.c
index c592aa5..01b45906 100644
--- a/drivers/leds/leds-max8997.c
+++ b/drivers/leds/leds-max8997.c
@@ -13,7 +13,6 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/mfd/max8997.h>
#include <linux/mfd/max8997-private.h>
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index e2b847f..a2e4c17 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -20,7 +20,6 @@
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/of.h>
-#include <linux/workqueue.h>
#include <linux/mfd/mc13xxx.h>
struct mc13xxx_led_devtype {
@@ -32,8 +31,6 @@ struct mc13xxx_led_devtype {
struct mc13xxx_led {
struct led_classdev cdev;
- struct work_struct work;
- enum led_brightness new_brightness;
int id;
struct mc13xxx_leds *leds;
};
@@ -55,9 +52,11 @@ static unsigned int mc13xxx_max_brightness(int id)
return 0x3f;
}
-static void mc13xxx_led_work(struct work_struct *work)
+static int mc13xxx_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
+ struct mc13xxx_led *led =
+ container_of(led_cdev, struct mc13xxx_led, cdev);
struct mc13xxx_leds *leds = led->leds;
unsigned int reg, bank, off, shift;
@@ -105,19 +104,9 @@ static void mc13xxx_led_work(struct work_struct *work)
BUG();
}
- mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
+ return mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
mc13xxx_max_brightness(led->id) << shift,
- led->new_brightness << shift);
-}
-
-static void mc13xxx_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct mc13xxx_led *led =
- container_of(led_cdev, struct mc13xxx_led, cdev);
-
- led->new_brightness = value;
- schedule_work(&led->work);
+ value << shift);
}
#ifdef CONFIG_OF
@@ -257,11 +246,9 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
leds->led[i].cdev.name = name;
leds->led[i].cdev.default_trigger = trig;
leds->led[i].cdev.flags = LED_CORE_SUSPENDRESUME;
- leds->led[i].cdev.brightness_set = mc13xxx_led_set;
+ leds->led[i].cdev.brightness_set_blocking = mc13xxx_led_set;
leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);
- INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
-
ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
if (ret) {
dev_err(dev, "Failed to register LED %i\n", id);
@@ -270,10 +257,8 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
}
if (ret)
- while (--i >= 0) {
+ while (--i >= 0)
led_classdev_unregister(&leds->led[i].cdev);
- cancel_work_sync(&leds->led[i].work);
- }
return ret;
}
@@ -283,10 +268,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < leds->num_leds; i++) {
+ for (i = 0; i < leds->num_leds; i++)
led_classdev_unregister(&leds->led[i].cdev);
- cancel_work_sync(&leds->led[i].work);
- }
return 0;
}
diff --git a/drivers/leds/leds-ns2.c b/drivers/leds/leds-ns2.c
index a95a612..506b75b 100644
--- a/drivers/leds/leds-ns2.c
+++ b/drivers/leds/leds-ns2.c
@@ -45,24 +45,12 @@ struct ns2_led_data {
unsigned cmd;
unsigned slow;
bool can_sleep;
- int mode_index;
unsigned char sata; /* True when SATA mode active. */
rwlock_t rw_lock; /* Lock GPIOs. */
- struct work_struct work;
int num_modes;
struct ns2_led_modval *modval;
};
-static void ns2_led_work(struct work_struct *work)
-{
- struct ns2_led_data *led_dat =
- container_of(work, struct ns2_led_data, work);
- int i = led_dat->mode_index;
-
- gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
- gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
-}
-
static int ns2_led_get_mode(struct ns2_led_data *led_dat,
enum ns2_led_modes *mode)
{
@@ -112,8 +100,8 @@ static void ns2_led_set_mode(struct ns2_led_data *led_dat,
goto exit_unlock;
}
- led_dat->mode_index = i;
- schedule_work(&led_dat->work);
+ gpio_set_value_cansleep(led_dat->cmd, led_dat->modval[i].cmd_level);
+ gpio_set_value_cansleep(led_dat->slow, led_dat->modval[i].slow_level);
exit_unlock:
write_unlock_irqrestore(&led_dat->rw_lock, flags);
@@ -136,6 +124,13 @@ static void ns2_led_set(struct led_classdev *led_cdev,
ns2_led_set_mode(led_dat, mode);
}
+static int ns2_led_set_blocking(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ ns2_led_set(led_cdev, value);
+ return 0;
+}
+
static ssize_t ns2_led_sata_store(struct device *dev,
struct device_attribute *attr,
const char *buff, size_t count)
@@ -219,13 +214,16 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
led_dat->cdev.blink_set = NULL;
- led_dat->cdev.brightness_set = ns2_led_set;
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
led_dat->cdev.groups = ns2_led_groups;
led_dat->cmd = template->cmd;
led_dat->slow = template->slow;
led_dat->can_sleep = gpio_cansleep(led_dat->cmd) |
gpio_cansleep(led_dat->slow);
+ if (led_dat->can_sleep)
+ led_dat->cdev.brightness_set_blocking = ns2_led_set_blocking;
+ else
+ led_dat->cdev.brightness_set = ns2_led_set;
led_dat->modval = template->modval;
led_dat->num_modes = template->num_modes;
@@ -238,8 +236,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
led_dat->cdev.brightness =
(mode == NS_V2_LED_OFF) ? LED_OFF : LED_FULL;
- INIT_WORK(&led_dat->work, ns2_led_work);
-
ret = led_classdev_register(&pdev->dev, &led_dat->cdev);
if (ret < 0)
return ret;
@@ -250,7 +246,6 @@ create_ns2_led(struct platform_device *pdev, struct ns2_led_data *led_dat,
static void delete_ns2_led(struct ns2_led_data *led_dat)
{
led_classdev_unregister(&led_dat->cdev);
- cancel_work_sync(&led_dat->work);
}
#ifdef CONFIG_OF_GPIO
diff --git a/drivers/leds/leds-pca9532.c b/drivers/leds/leds-pca9532.c
index 5a6363d..17c63ec 100644
--- a/drivers/leds/leds-pca9532.c
+++ b/drivers/leds/leds-pca9532.c
@@ -158,7 +158,7 @@ static void pca9532_setled(struct pca9532_led *led)
mutex_unlock(&data->update_lock);
}
-static void pca9532_set_brightness(struct led_classdev *led_cdev,
+static int pca9532_set_brightness(struct led_classdev *led_cdev,
enum led_brightness value)
{
int err = 0;
@@ -172,9 +172,12 @@ static void pca9532_set_brightness(struct led_classdev *led_cdev,
led->state = PCA9532_PWM0; /* Thecus: hardcode one pwm */
err = pca9532_calcpwm(led->client, 0, 0, value);
if (err)
- return; /* XXX: led api doesn't allow error code? */
+ return err;
}
- schedule_work(&led->work);
+ if (led->state == PCA9532_PWM0)
+ pca9532_setpwm(led->client, 0);
+ pca9532_setled(led);
+ return err;
}
static int pca9532_set_blink(struct led_classdev *led_cdev,
@@ -198,7 +201,10 @@ static int pca9532_set_blink(struct led_classdev *led_cdev,
err = pca9532_calcpwm(client, 0, psc, led_cdev->brightness);
if (err)
return err;
- schedule_work(&led->work);
+ if (led->state == PCA9532_PWM0)
+ pca9532_setpwm(led->client, 0);
+ pca9532_setled(led);
+
return 0;
}
@@ -233,15 +239,6 @@ static void pca9532_input_work(struct work_struct *work)
mutex_unlock(&data->update_lock);
}
-static void pca9532_led_work(struct work_struct *work)
-{
- struct pca9532_led *led;
- led = container_of(work, struct pca9532_led, work);
- if (led->state == PCA9532_PWM0)
- pca9532_setpwm(led->client, 0);
- pca9532_setled(led);
-}
-
#ifdef CONFIG_LEDS_PCA9532_GPIO
static int pca9532_gpio_request_pin(struct gpio_chip *gc, unsigned offset)
{
@@ -307,7 +304,6 @@ static int pca9532_destroy_devices(struct pca9532_data *data, int n_devs)
break;
case PCA9532_TYPE_LED:
led_classdev_unregister(&data->leds[i].ldev);
- cancel_work_sync(&data->leds[i].work);
break;
case PCA9532_TYPE_N2100_BEEP:
if (data->idev != NULL) {
@@ -359,9 +355,9 @@ static int pca9532_configure(struct i2c_client *client,
led->name = pled->name;
led->ldev.name = led->name;
led->ldev.brightness = LED_OFF;
- led->ldev.brightness_set = pca9532_set_brightness;
+ led->ldev.brightness_set_blocking =
+ pca9532_set_brightness;
led->ldev.blink_set = pca9532_set_blink;
- INIT_WORK(&led->work, pca9532_led_work);
err = led_classdev_register(&client->dev, &led->ldev);
if (err < 0) {
dev_err(&client->dev,
diff --git a/drivers/leds/leds-pca955x.c b/drivers/leds/leds-pca955x.c
index b775e1e..840401a 100644
--- a/drivers/leds/leds-pca955x.c
+++ b/drivers/leds/leds-pca955x.c
@@ -47,7 +47,6 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/workqueue.h>
#include <linux/slab.h>
/* LED select registers determine the source that drives LED outputs */
@@ -110,8 +109,6 @@ struct pca955x {
struct pca955x_led {
struct pca955x *pca955x;
- struct work_struct work;
- enum led_brightness brightness;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
char name[32];
@@ -193,7 +190,8 @@ static u8 pca955x_read_ls(struct i2c_client *client, int n)
pca95xx_num_input_regs(pca955x->chipdef->bits) + 4 + n);
}
-static void pca955x_led_work(struct work_struct *work)
+static int pca955x_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
struct pca955x_led *pca955x_led;
struct pca955x *pca955x;
@@ -201,7 +199,7 @@ static void pca955x_led_work(struct work_struct *work)
int chip_ls; /* which LSx to use (0-3 potentially) */
int ls_led; /* which set of bits within LSx to use (0-3) */
- pca955x_led = container_of(work, struct pca955x_led, work);
+ pca955x_led = container_of(led_cdev, struct pca955x_led, led_cdev);
pca955x = pca955x_led->pca955x;
chip_ls = pca955x_led->led_num / 4;
@@ -211,7 +209,7 @@ static void pca955x_led_work(struct work_struct *work)
ls = pca955x_read_ls(pca955x->client, chip_ls);
- switch (pca955x_led->brightness) {
+ switch (value) {
case LED_FULL:
ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_LED_ON);
break;
@@ -230,7 +228,7 @@ static void pca955x_led_work(struct work_struct *work)
* just turning off for all other values.
*/
pca955x_write_pwm(pca955x->client, 1,
- 255 - pca955x_led->brightness);
+ 255 - value);
ls = pca955x_ledsel(ls, ls_led, PCA955X_LS_BLINK1);
break;
}
@@ -238,21 +236,8 @@ static void pca955x_led_work(struct work_struct *work)
pca955x_write_ls(pca955x->client, chip_ls, ls);
mutex_unlock(&pca955x->lock);
-}
-
-static void pca955x_led_set(struct led_classdev *led_cdev, enum led_brightness value)
-{
- struct pca955x_led *pca955x;
-
- pca955x = container_of(led_cdev, struct pca955x_led, led_cdev);
-
- pca955x->brightness = value;
- /*
- * Must use workqueue for the actual I/O since I2C operations
- * can sleep.
- */
- schedule_work(&pca955x->work);
+ return 0;
}
static int pca955x_probe(struct i2c_client *client,
@@ -328,9 +313,7 @@ static int pca955x_probe(struct i2c_client *client,
}
pca955x_led->led_cdev.name = pca955x_led->name;
- pca955x_led->led_cdev.brightness_set = pca955x_led_set;
-
- INIT_WORK(&pca955x_led->work, pca955x_led_work);
+ pca955x_led->led_cdev.brightness_set_blocking = pca955x_led_set;
err = led_classdev_register(&client->dev,
&pca955x_led->led_cdev);
@@ -355,10 +338,8 @@ static int pca955x_probe(struct i2c_client *client,
return 0;
exit:
- while (i--) {
+ while (i--)
led_classdev_unregister(&pca955x->leds[i].led_cdev);
- cancel_work_sync(&pca955x->leds[i].work);
- }
return err;
}
@@ -368,10 +349,8 @@ static int pca955x_remove(struct i2c_client *client)
struct pca955x *pca955x = i2c_get_clientdata(client);
int i;
- for (i = 0; i < pca955x->chipdef->bits; i++) {
+ for (i = 0; i < pca955x->chipdef->bits; i++)
led_classdev_unregister(&pca955x->leds[i].led_cdev);
- cancel_work_sync(&pca955x->leds[i].work);
- }
return 0;
}
diff --git a/drivers/leds/leds-pca963x.c b/drivers/leds/leds-pca963x.c
index 41f269f..407eba1 100644
--- a/drivers/leds/leds-pca963x.c
+++ b/drivers/leds/leds-pca963x.c
@@ -32,7 +32,6 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/i2c.h>
-#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/platform_data/leds-pca963x.h>
@@ -96,11 +95,6 @@ static const struct i2c_device_id pca963x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca963x_id);
-enum pca963x_cmd {
- BRIGHTNESS_SET,
- BLINK_SET,
-};
-
struct pca963x_led;
struct pca963x {
@@ -112,47 +106,52 @@ struct pca963x {
struct pca963x_led {
struct pca963x *chip;
- struct work_struct work;
- enum led_brightness brightness;
struct led_classdev led_cdev;
int led_num; /* 0 .. 15 potentially */
- enum pca963x_cmd cmd;
char name[32];
u8 gdc;
u8 gfrq;
};
-static void pca963x_brightness_work(struct pca963x_led *pca963x)
+static int pca963x_brightness(struct pca963x_led *pca963x,
+ enum led_brightness brightness)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base
+ (pca963x->led_num / 4);
u8 ledout;
int shift = 2 * (pca963x->led_num % 4);
u8 mask = 0x3 << shift;
+ int ret;
mutex_lock(&pca963x->chip->mutex);
ledout = i2c_smbus_read_byte_data(pca963x->chip->client, ledout_addr);
- switch (pca963x->brightness) {
+ switch (brightness) {
case LED_FULL:
- i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+ ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+ ledout_addr,
(ledout & ~mask) | (PCA963X_LED_ON << shift));
break;
case LED_OFF:
- i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
- ledout & ~mask);
+ ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+ ledout_addr, ledout & ~mask);
break;
default:
- i2c_smbus_write_byte_data(pca963x->chip->client,
+ ret = i2c_smbus_write_byte_data(pca963x->chip->client,
PCA963X_PWM_BASE + pca963x->led_num,
- pca963x->brightness);
- i2c_smbus_write_byte_data(pca963x->chip->client, ledout_addr,
+ brightness);
+ if (ret < 0)
+ goto unlock;
+ ret = i2c_smbus_write_byte_data(pca963x->chip->client,
+ ledout_addr,
(ledout & ~mask) | (PCA963X_LED_PWM << shift));
break;
}
+unlock:
mutex_unlock(&pca963x->chip->mutex);
+ return ret;
}
-static void pca963x_blink_work(struct pca963x_led *pca963x)
+static void pca963x_blink(struct pca963x_led *pca963x)
{
u8 ledout_addr = pca963x->chip->chipdef->ledout_base +
(pca963x->led_num / 4);
@@ -180,36 +179,14 @@ static void pca963x_blink_work(struct pca963x_led *pca963x)
mutex_unlock(&pca963x->chip->mutex);
}
-static void pca963x_work(struct work_struct *work)
-{
- struct pca963x_led *pca963x = container_of(work,
- struct pca963x_led, work);
-
- switch (pca963x->cmd) {
- case BRIGHTNESS_SET:
- pca963x_brightness_work(pca963x);
- break;
- case BLINK_SET:
- pca963x_blink_work(pca963x);
- break;
- }
-}
-
-static void pca963x_led_set(struct led_classdev *led_cdev,
+static int pca963x_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct pca963x_led *pca963x;
pca963x = container_of(led_cdev, struct pca963x_led, led_cdev);
- pca963x->cmd = BRIGHTNESS_SET;
- pca963x->brightness = value;
-
- /*
- * Must use workqueue for the actual I/O since I2C operations
- * can sleep.
- */
- schedule_work(&pca963x->work);
+ return pca963x_brightness(pca963x, value);
}
static int pca963x_blink_set(struct led_classdev *led_cdev,
@@ -254,15 +231,10 @@ static int pca963x_blink_set(struct led_classdev *led_cdev,
*/
gfrq = (period * 24 / 1000) - 1;
- pca963x->cmd = BLINK_SET;
pca963x->gdc = gdc;
pca963x->gfrq = gfrq;
- /*
- * Must use workqueue for the actual I/O since I2C operations
- * can sleep.
- */
- schedule_work(&pca963x->work);
+ pca963x_blink(pca963x);
*delay_on = time_on;
*delay_off = time_off;
@@ -409,13 +381,11 @@ static int pca963x_probe(struct i2c_client *client,
client->addr, i);
pca963x[i].led_cdev.name = pca963x[i].name;
- pca963x[i].led_cdev.brightness_set = pca963x_led_set;
+ pca963x[i].led_cdev.brightness_set_blocking = pca963x_led_set;
if (pdata && pdata->blink_type == PCA963X_HW_BLINK)
pca963x[i].led_cdev.blink_set = pca963x_blink_set;
- INIT_WORK(&pca963x[i].work, pca963x_work);
-
err = led_classdev_register(&client->dev, &pca963x[i].led_cdev);
if (err < 0)
goto exit;
@@ -435,10 +405,8 @@ static int pca963x_probe(struct i2c_client *client,
return 0;
exit:
- while (i--) {
+ while (i--)
led_classdev_unregister(&pca963x[i].led_cdev);
- cancel_work_sync(&pca963x[i].work);
- }
return err;
}
@@ -448,10 +416,8 @@ static int pca963x_remove(struct i2c_client *client)
struct pca963x *pca963x = i2c_get_clientdata(client);
int i;
- for (i = 0; i < pca963x->chipdef->n_leds; i++) {
+ for (i = 0; i < pca963x->chipdef->n_leds; i++)
led_classdev_unregister(&pca963x->leds[i].led_cdev);
- cancel_work_sync(&pca963x->leds[i].work);
- }
return 0;
}
diff --git a/drivers/leds/leds-powernv.c b/drivers/leds/leds-powernv.c
index 1e75e1f..dfb8bd3 100644
--- a/drivers/leds/leds-powernv.c
+++ b/drivers/leds/leds-powernv.c
@@ -77,7 +77,7 @@ static int powernv_get_led_type(const char *led_type_desc)
* This function is called from work queue task context when ever it gets
* scheduled. This function can sleep at opal_async_wait_response call.
*/
-static void powernv_led_set(struct powernv_led_data *powernv_led,
+static int powernv_led_set(struct powernv_led_data *powernv_led,
enum led_brightness value)
{
int rc, token;
@@ -99,7 +99,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
if (token != -ERESTARTSYS)
dev_err(dev, "%s: Couldn't get OPAL async token\n",
__func__);
- return;
+ return token;
}
rc = opal_leds_set_ind(token, powernv_led->loc_code,
@@ -125,6 +125,7 @@ static void powernv_led_set(struct powernv_led_data *powernv_led,
out_token:
opal_async_release_token(token);
+ return rc;
}
/*
@@ -173,20 +174,23 @@ static enum led_brightness powernv_led_get(struct powernv_led_data *powernv_led)
* LED classdev 'brightness_get' function. This schedules work
* to update LED state.
*/
-static void powernv_brightness_set(struct led_classdev *led_cdev,
+static int powernv_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct powernv_led_data *powernv_led =
container_of(led_cdev, struct powernv_led_data, cdev);
struct powernv_led_common *powernv_led_common = powernv_led->common;
+ int rc;
/* Do not modify LED in unload path */
if (powernv_led_common->led_disabled)
- return;
+ return 0;
mutex_lock(&powernv_led_common->lock);
- powernv_led_set(powernv_led, value);
+ rc = powernv_led_set(powernv_led, value);
mutex_unlock(&powernv_led_common->lock);
+
+ return rc;
}
/* LED classdev 'brightness_get' function */
@@ -227,7 +231,7 @@ static int powernv_led_create(struct device *dev,
return -ENOMEM;
}
- powernv_led->cdev.brightness_set = powernv_brightness_set;
+ powernv_led->cdev.brightness_set_blocking = powernv_brightness_set;
powernv_led->cdev.brightness_get = powernv_brightness_get;
powernv_led->cdev.brightness = LED_OFF;
powernv_led->cdev.max_brightness = LED_FULL;
@@ -256,8 +260,6 @@ static int powernv_led_classdev(struct platform_device *pdev,
for_each_child_of_node(led_node, np) {
p = of_find_property(np, "led-types", NULL);
- if (!p)
- continue;
while ((cur = of_prop_next_string(p, cur)) != NULL) {
powernv_led = devm_kzalloc(dev, sizeof(*powernv_led),
diff --git a/drivers/leds/leds-pwm.c b/drivers/leds/leds-pwm.c
index 1d07e3e..4783bac 100644
--- a/drivers/leds/leds-pwm.c
+++ b/drivers/leds/leds-pwm.c
@@ -22,12 +22,10 @@
#include <linux/pwm.h>
#include <linux/leds_pwm.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
struct led_pwm_data {
struct led_classdev cdev;
struct pwm_device *pwm;
- struct work_struct work;
unsigned int active_low;
unsigned int period;
int duty;
@@ -51,14 +49,6 @@ static void __led_pwm_set(struct led_pwm_data *led_dat)
pwm_enable(led_dat->pwm);
}
-static void led_pwm_work(struct work_struct *work)
-{
- struct led_pwm_data *led_dat =
- container_of(work, struct led_pwm_data, work);
-
- __led_pwm_set(led_dat);
-}
-
static void led_pwm_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
@@ -75,10 +65,14 @@ static void led_pwm_set(struct led_classdev *led_cdev,
led_dat->duty = duty;
- if (led_dat->can_sleep)
- schedule_work(&led_dat->work);
- else
- __led_pwm_set(led_dat);
+ __led_pwm_set(led_dat);
+}
+
+static int led_pwm_set_blocking(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ led_pwm_set(led_cdev, brightness);
+ return 0;
}
static inline size_t sizeof_pwm_leds_priv(int num_leds)
@@ -89,11 +83,8 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
static void led_pwm_cleanup(struct led_pwm_priv *priv)
{
- while (priv->num_leds--) {
+ while (priv->num_leds--)
led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
- if (priv->leds[priv->num_leds].can_sleep)
- cancel_work_sync(&priv->leds[priv->num_leds].work);
- }
}
static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
@@ -105,7 +96,6 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
led_data->active_low = led->active_low;
led_data->cdev.name = led->name;
led_data->cdev.default_trigger = led->default_trigger;
- led_data->cdev.brightness_set = led_pwm_set;
led_data->cdev.brightness = LED_OFF;
led_data->cdev.max_brightness = led->max_brightness;
led_data->cdev.flags = LED_CORE_SUSPENDRESUME;
@@ -122,8 +112,10 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
}
led_data->can_sleep = pwm_can_sleep(led_data->pwm);
- if (led_data->can_sleep)
- INIT_WORK(&led_data->work, led_pwm_work);
+ if (!led_data->can_sleep)
+ led_data->cdev.brightness_set = led_pwm_set;
+ else
+ led_data->cdev.brightness_set_blocking = led_pwm_set_blocking;
led_data->period = pwm_get_period(led_data->pwm);
if (!led_data->period && (led->pwm_period_ns > 0))
@@ -132,6 +124,7 @@ static int led_pwm_add(struct device *dev, struct led_pwm_priv *priv,
ret = led_classdev_register(dev, &led_data->cdev);
if (ret == 0) {
priv->num_leds++;
+ led_pwm_set(&led_data->cdev, led_data->cdev.brightness);
} else {
dev_err(dev, "failed to register PWM led for %s: %d\n",
led->name, ret);
@@ -236,6 +229,6 @@ static struct platform_driver led_pwm_driver = {
module_platform_driver(led_pwm_driver);
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
-MODULE_DESCRIPTION("PWM LED driver for PXA");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("generic PWM LED driver");
+MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:leds-pwm");
diff --git a/drivers/leds/leds-regulator.c b/drivers/leds/leds-regulator.c
index ffc2139..acf77ca 100644
--- a/drivers/leds/leds-regulator.c
+++ b/drivers/leds/leds-regulator.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#include <linux/leds.h>
#include <linux/leds-regulator.h>
#include <linux/platform_device.h>
@@ -25,10 +24,8 @@
struct regulator_led {
struct led_classdev cdev;
- enum led_brightness value;
int enabled;
struct mutex mutex;
- struct work_struct work;
struct regulator *vcc;
};
@@ -94,22 +91,24 @@ static void regulator_led_disable(struct regulator_led *led)
led->enabled = 0;
}
-static void regulator_led_set_value(struct regulator_led *led)
+static int regulator_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
+ struct regulator_led *led = to_regulator_led(led_cdev);
int voltage;
- int ret;
+ int ret = 0;
mutex_lock(&led->mutex);
- if (led->value == LED_OFF) {
+ if (value == LED_OFF) {
regulator_led_disable(led);
goto out;
}
if (led->cdev.max_brightness > 1) {
- voltage = led_regulator_get_voltage(led->vcc, led->value);
+ voltage = led_regulator_get_voltage(led->vcc, value);
dev_dbg(led->cdev.dev, "brightness: %d voltage: %d\n",
- led->value, voltage);
+ value, voltage);
ret = regulator_set_voltage(led->vcc, voltage, voltage);
if (ret != 0)
@@ -121,23 +120,7 @@ static void regulator_led_set_value(struct regulator_led *led)
out:
mutex_unlock(&led->mutex);
-}
-
-static void led_work(struct work_struct *work)
-{
- struct regulator_led *led;
-
- led = container_of(work, struct regulator_led, work);
- regulator_led_set_value(led);
-}
-
-static void regulator_led_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct regulator_led *led = to_regulator_led(led_cdev);
-
- led->value = value;
- schedule_work(&led->work);
+ return ret;
}
static int regulator_led_probe(struct platform_device *pdev)
@@ -169,9 +152,8 @@ static int regulator_led_probe(struct platform_device *pdev)
pdata->brightness);
return -EINVAL;
}
- led->value = pdata->brightness;
- led->cdev.brightness_set = regulator_led_brightness_set;
+ led->cdev.brightness_set_blocking = regulator_led_brightness_set;
led->cdev.name = pdata->name;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
led->vcc = vcc;
@@ -181,21 +163,18 @@ static int regulator_led_probe(struct platform_device *pdev)
led->enabled = 1;
mutex_init(&led->mutex);
- INIT_WORK(&led->work, led_work);
platform_set_drvdata(pdev, led);
ret = led_classdev_register(&pdev->dev, &led->cdev);
- if (ret < 0) {
- cancel_work_sync(&led->work);
+ if (ret < 0)
return ret;
- }
/* to expose the default value to userspace */
- led->cdev.brightness = led->value;
+ led->cdev.brightness = pdata->brightness;
/* Set the default led status */
- regulator_led_set_value(led);
+ regulator_led_brightness_set(&led->cdev, led->cdev.brightness);
return 0;
}
@@ -205,7 +184,6 @@ static int regulator_led_remove(struct platform_device *pdev)
struct regulator_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
- cancel_work_sync(&led->work);
regulator_led_disable(led);
return 0;
}
diff --git a/drivers/leds/leds-sunfire.c b/drivers/leds/leds-sunfire.c
index c2553c5..7c09db8 100644
--- a/drivers/leds/leds-sunfire.c
+++ b/drivers/leds/leds-sunfire.c
@@ -234,28 +234,19 @@ static struct platform_driver sunfire_fhc_led_driver = {
},
};
+static struct platform_driver * const drivers[] = {
+ &sunfire_clockboard_led_driver,
+ &sunfire_fhc_led_driver,
+};
+
static int __init sunfire_leds_init(void)
{
- int err = platform_driver_register(&sunfire_clockboard_led_driver);
-
- if (err) {
- pr_err("Could not register clock board LED driver\n");
- return err;
- }
-
- err = platform_driver_register(&sunfire_fhc_led_driver);
- if (err) {
- pr_err("Could not register FHC LED driver\n");
- platform_driver_unregister(&sunfire_clockboard_led_driver);
- }
-
- return err;
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
static void __exit sunfire_leds_exit(void)
{
- platform_driver_unregister(&sunfire_clockboard_led_driver);
- platform_driver_unregister(&sunfire_fhc_led_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_init(sunfire_leds_init);
diff --git a/drivers/leds/leds-syscon.c b/drivers/leds/leds-syscon.c
index b88900d..3be40f7 100644
--- a/drivers/leds/leds-syscon.c
+++ b/drivers/leds/leds-syscon.c
@@ -20,7 +20,7 @@
* MA 02111-1307 USA
*/
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/init.h>
#include <linux/of_device.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
@@ -139,29 +139,17 @@ static int syscon_led_probe(struct platform_device *pdev)
return 0;
}
-static int syscon_led_remove(struct platform_device *pdev)
-{
- struct syscon_led *sled = platform_get_drvdata(pdev);
-
- led_classdev_unregister(&sled->cdev);
- /* Turn it off */
- regmap_update_bits(sled->map, sled->offset, sled->mask, 0);
- return 0;
-}
-
static const struct of_device_id of_syscon_leds_match[] = {
{ .compatible = "register-bit-led", },
{},
};
-MODULE_DEVICE_TABLE(of, of_syscon_leds_match);
-
static struct platform_driver syscon_led_driver = {
.probe = syscon_led_probe,
- .remove = syscon_led_remove,
.driver = {
.name = "leds-syscon",
.of_match_table = of_syscon_leds_match,
+ .suppress_bind_attrs = true,
},
};
-module_platform_driver(syscon_led_driver);
+builtin_platform_driver(syscon_led_driver);
diff --git a/drivers/leds/leds-tlc591xx.c b/drivers/leds/leds-tlc591xx.c
index b806eca..30453164 100644
--- a/drivers/leds/leds-tlc591xx.c
+++ b/drivers/leds/leds-tlc591xx.c
@@ -14,7 +14,6 @@
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#include <linux/workqueue.h>
#define TLC591XX_MAX_LEDS 16
@@ -42,13 +41,11 @@
#define LEDOUT_MASK 0x3
#define ldev_to_led(c) container_of(c, struct tlc591xx_led, ldev)
-#define work_to_led(work) container_of(work, struct tlc591xx_led, work)
struct tlc591xx_led {
bool active;
unsigned int led_no;
struct led_classdev ldev;
- struct work_struct work;
struct tlc591xx_priv *priv;
};
@@ -110,12 +107,12 @@ tlc591xx_set_pwm(struct tlc591xx_priv *priv, struct tlc591xx_led *led,
return regmap_write(priv->regmap, pwm, brightness);
}
-static void
-tlc591xx_led_work(struct work_struct *work)
+static int
+tlc591xx_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
{
- struct tlc591xx_led *led = work_to_led(work);
+ struct tlc591xx_led *led = ldev_to_led(led_cdev);
struct tlc591xx_priv *priv = led->priv;
- enum led_brightness brightness = led->ldev.brightness;
int err;
switch (brightness) {
@@ -131,18 +128,7 @@ tlc591xx_led_work(struct work_struct *work)
err = tlc591xx_set_pwm(priv, led, brightness);
}
- if (err)
- dev_err(led->ldev.dev, "Failed setting brightness\n");
-}
-
-static void
-tlc591xx_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
-{
- struct tlc591xx_led *led = ldev_to_led(led_cdev);
-
- led->ldev.brightness = brightness;
- schedule_work(&led->work);
+ return err;
}
static void
@@ -151,10 +137,8 @@ tlc591xx_destroy_devices(struct tlc591xx_priv *priv, unsigned int j)
int i = j;
while (--i >= 0) {
- if (priv->leds[i].active) {
+ if (priv->leds[i].active)
led_classdev_unregister(&priv->leds[i].ldev);
- cancel_work_sync(&priv->leds[i].work);
- }
}
}
@@ -175,9 +159,8 @@ tlc591xx_configure(struct device *dev,
led->priv = priv;
led->led_no = i;
- led->ldev.brightness_set = tlc591xx_brightness_set;
+ led->ldev.brightness_set_blocking = tlc591xx_brightness_set;
led->ldev.max_brightness = LED_FULL;
- INIT_WORK(&led->work, tlc591xx_led_work);
err = led_classdev_register(dev, &led->ldev);
if (err < 0) {
dev_err(dev, "couldn't register LED %s\n",
diff --git a/drivers/leds/leds-wm831x-status.c b/drivers/leds/leds-wm831x-status.c
index 56027ef..64a2226 100644
--- a/drivers/leds/leds-wm831x-status.c
+++ b/drivers/leds/leds-wm831x-status.c
@@ -23,7 +23,6 @@
struct wm831x_status {
struct led_classdev cdev;
struct wm831x *wm831x;
- struct work_struct work;
struct mutex mutex;
spinlock_t value_lock;
@@ -40,10 +39,8 @@ struct wm831x_status {
#define to_wm831x_status(led_cdev) \
container_of(led_cdev, struct wm831x_status, cdev)
-static void wm831x_status_work(struct work_struct *work)
+static void wm831x_status_set(struct wm831x_status *led)
{
- struct wm831x_status *led = container_of(work, struct wm831x_status,
- work);
unsigned long flags;
mutex_lock(&led->mutex);
@@ -70,8 +67,8 @@ static void wm831x_status_work(struct work_struct *work)
mutex_unlock(&led->mutex);
}
-static void wm831x_status_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static int wm831x_status_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
struct wm831x_status *led = to_wm831x_status(led_cdev);
unsigned long flags;
@@ -80,8 +77,10 @@ static void wm831x_status_set(struct led_classdev *led_cdev,
led->brightness = value;
if (value == LED_OFF)
led->blink = 0;
- schedule_work(&led->work);
spin_unlock_irqrestore(&led->value_lock, flags);
+ wm831x_status_set(led);
+
+ return 0;
}
static int wm831x_status_blink_set(struct led_classdev *led_cdev,
@@ -147,11 +146,8 @@ static int wm831x_status_blink_set(struct led_classdev *led_cdev,
else
led->blink = 0;
- /* Always update; if we fail turn off blinking since we expect
- * a software fallback. */
- schedule_work(&led->work);
-
spin_unlock_irqrestore(&led->value_lock, flags);
+ wm831x_status_set(led);
return ret;
}
@@ -206,11 +202,9 @@ static ssize_t wm831x_status_src_store(struct device *dev,
for (i = 0; i < ARRAY_SIZE(led_src_texts); i++) {
if (!strcmp(name, led_src_texts[i])) {
mutex_lock(&led->mutex);
-
led->src = i;
- schedule_work(&led->work);
-
mutex_unlock(&led->mutex);
+ wm831x_status_set(led);
}
}
@@ -262,7 +256,6 @@ static int wm831x_status_probe(struct platform_device *pdev)
pdata.name = dev_name(&pdev->dev);
mutex_init(&drvdata->mutex);
- INIT_WORK(&drvdata->work, wm831x_status_work);
spin_lock_init(&drvdata->value_lock);
/* We cache the configuration register and read startup values
@@ -287,7 +280,7 @@ static int wm831x_status_probe(struct platform_device *pdev)
drvdata->cdev.name = pdata.name;
drvdata->cdev.default_trigger = pdata.default_trigger;
- drvdata->cdev.brightness_set = wm831x_status_set;
+ drvdata->cdev.brightness_set_blocking = wm831x_status_brightness_set;
drvdata->cdev.blink_set = wm831x_status_blink_set;
drvdata->cdev.groups = wm831x_status_groups;
diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c
index 0d12183..e1e4e9d 100644
--- a/drivers/leds/leds-wm8350.c
+++ b/drivers/leds/leds-wm8350.c
@@ -89,40 +89,42 @@ static const int isink_cur[] = {
#define to_wm8350_led(led_cdev) \
container_of(led_cdev, struct wm8350_led, cdev)
-static void wm8350_led_enable(struct wm8350_led *led)
+static int wm8350_led_enable(struct wm8350_led *led)
{
- int ret;
+ int ret = 0;
if (led->enabled)
- return;
+ return ret;
ret = regulator_enable(led->isink);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to enable ISINK: %d\n", ret);
- return;
+ return ret;
}
ret = regulator_enable(led->dcdc);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to enable DCDC: %d\n", ret);
regulator_disable(led->isink);
- return;
+ return ret;
}
led->enabled = 1;
+
+ return ret;
}
-static void wm8350_led_disable(struct wm8350_led *led)
+static int wm8350_led_disable(struct wm8350_led *led)
{
- int ret;
+ int ret = 0;
if (!led->enabled)
- return;
+ return ret;
ret = regulator_disable(led->dcdc);
if (ret != 0) {
dev_err(led->cdev.dev, "Failed to disable DCDC: %d\n", ret);
- return;
+ return ret;
}
ret = regulator_disable(led->isink);
@@ -132,27 +134,29 @@ static void wm8350_led_disable(struct wm8350_led *led)
if (ret != 0)
dev_err(led->cdev.dev, "Failed to reenable DCDC: %d\n",
ret);
- return;
+ return ret;
}
led->enabled = 0;
+
+ return ret;
}
-static void led_work(struct work_struct *work)
+static int wm8350_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
{
- struct wm8350_led *led = container_of(work, struct wm8350_led, work);
+ struct wm8350_led *led = to_wm8350_led(led_cdev);
+ unsigned long flags;
int ret;
int uA;
- unsigned long flags;
- mutex_lock(&led->mutex);
+ led->value = value;
spin_lock_irqsave(&led->value_lock, flags);
if (led->value == LED_OFF) {
spin_unlock_irqrestore(&led->value_lock, flags);
- wm8350_led_disable(led);
- goto out;
+ return wm8350_led_disable(led);
}
/* This scales linearly into the index of valid current
@@ -166,36 +170,21 @@ static void led_work(struct work_struct *work)
ret = regulator_set_current_limit(led->isink, isink_cur[uA],
isink_cur[uA]);
- if (ret != 0)
+ if (ret != 0) {
dev_err(led->cdev.dev, "Failed to set %duA: %d\n",
isink_cur[uA], ret);
+ return ret;
+ }
- wm8350_led_enable(led);
-
-out:
- mutex_unlock(&led->mutex);
-}
-
-static void wm8350_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- struct wm8350_led *led = to_wm8350_led(led_cdev);
- unsigned long flags;
-
- spin_lock_irqsave(&led->value_lock, flags);
- led->value = value;
- schedule_work(&led->work);
- spin_unlock_irqrestore(&led->value_lock, flags);
+ return wm8350_led_enable(led);
}
static void wm8350_led_shutdown(struct platform_device *pdev)
{
struct wm8350_led *led = platform_get_drvdata(pdev);
- mutex_lock(&led->mutex);
led->value = LED_OFF;
wm8350_led_disable(led);
- mutex_unlock(&led->mutex);
}
static int wm8350_led_probe(struct platform_device *pdev)
@@ -232,7 +221,7 @@ static int wm8350_led_probe(struct platform_device *pdev)
if (led == NULL)
return -ENOMEM;
- led->cdev.brightness_set = wm8350_led_set;
+ led->cdev.brightness_set_blocking = wm8350_led_set;
led->cdev.default_trigger = pdata->default_trigger;
led->cdev.name = pdata->name;
led->cdev.flags |= LED_CORE_SUSPENDRESUME;
@@ -251,8 +240,6 @@ static int wm8350_led_probe(struct platform_device *pdev)
pdata->max_uA);
spin_lock_init(&led->value_lock);
- mutex_init(&led->mutex);
- INIT_WORK(&led->work, led_work);
led->value = LED_OFF;
platform_set_drvdata(pdev, led);
@@ -264,7 +251,6 @@ static int wm8350_led_remove(struct platform_device *pdev)
struct wm8350_led *led = platform_get_drvdata(pdev);
led_classdev_unregister(&led->cdev);
- flush_work(&led->work);
wm8350_led_disable(led);
return 0;
}
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 4238fbc..db3f20d 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -16,29 +16,6 @@
#include <linux/rwsem.h>
#include <linux/leds.h>
-static inline void led_set_brightness_async(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- value = min(value, led_cdev->max_brightness);
- led_cdev->brightness = value;
-
- if (!(led_cdev->flags & LED_SUSPENDED))
- led_cdev->brightness_set(led_cdev, value);
-}
-
-static inline int led_set_brightness_sync(struct led_classdev *led_cdev,
- enum led_brightness value)
-{
- int ret = 0;
-
- led_cdev->brightness = min(value, led_cdev->max_brightness);
-
- if (!(led_cdev->flags & LED_SUSPENDED))
- ret = led_cdev->brightness_set_sync(led_cdev,
- led_cdev->brightness);
- return ret;
-}
-
static inline int led_get_brightness(struct led_classdev *led_cdev)
{
return led_cdev->brightness;
@@ -46,6 +23,10 @@ static inline int led_get_brightness(struct led_classdev *led_cdev)
void led_init_core(struct led_classdev *led_cdev);
void led_stop_software_blink(struct led_classdev *led_cdev);
+void led_set_brightness_nopm(struct led_classdev *led_cdev,
+ enum led_brightness value);
+void led_set_brightness_nosleep(struct led_classdev *led_cdev,
+ enum led_brightness value);
extern struct rw_semaphore leds_list_lock;
extern struct list_head leds_list;
diff --git a/drivers/leds/trigger/ledtrig-backlight.c b/drivers/leds/trigger/ledtrig-backlight.c
index 59eca17..1ca1f16 100644
--- a/drivers/leds/trigger/ledtrig-backlight.c
+++ b/drivers/leds/trigger/ledtrig-backlight.c
@@ -51,9 +51,9 @@ static int fb_notifier_callback(struct notifier_block *p,
if ((n->old_status == UNBLANK) ^ n->invert) {
n->brightness = led->brightness;
- led_set_brightness_async(led, LED_OFF);
+ led_set_brightness_nosleep(led, LED_OFF);
} else {
- led_set_brightness_async(led, n->brightness);
+ led_set_brightness_nosleep(led, n->brightness);
}
n->old_status = new_status;
@@ -89,9 +89,9 @@ static ssize_t bl_trig_invert_store(struct device *dev,
/* After inverting, we need to update the LED. */
if ((n->old_status == BLANK) ^ n->invert)
- led_set_brightness_async(led, LED_OFF);
+ led_set_brightness_nosleep(led, LED_OFF);
else
- led_set_brightness_async(led, n->brightness);
+ led_set_brightness_nosleep(led, n->brightness);
return num;
}
diff --git a/drivers/leds/trigger/ledtrig-cpu.c b/drivers/leds/trigger/ledtrig-cpu.c
index aec0f02..938467f 100644
--- a/drivers/leds/trigger/ledtrig-cpu.c
+++ b/drivers/leds/trigger/ledtrig-cpu.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -140,27 +139,4 @@ static int __init ledtrig_cpu_init(void)
return 0;
}
-module_init(ledtrig_cpu_init);
-
-static void __exit ledtrig_cpu_exit(void)
-{
- int cpu;
-
- unregister_cpu_notifier(&ledtrig_cpu_nb);
-
- for_each_possible_cpu(cpu) {
- struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
-
- led_trigger_unregister_simple(trig->_trig);
- trig->_trig = NULL;
- memset(trig->name, 0, MAX_NAME_LEN);
- }
-
- unregister_syscore_ops(&ledtrig_cpu_syscore_ops);
-}
-module_exit(ledtrig_cpu_exit);
-
-MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
-MODULE_AUTHOR("Bryan Wu <bryan.wu@canonical.com>");
-MODULE_DESCRIPTION("CPU LED trigger");
-MODULE_LICENSE("GPL");
+device_initcall(ledtrig_cpu_init);
diff --git a/drivers/leds/trigger/ledtrig-default-on.c b/drivers/leds/trigger/ledtrig-default-on.c
index 6f38f88..ff455cb 100644
--- a/drivers/leds/trigger/ledtrig-default-on.c
+++ b/drivers/leds/trigger/ledtrig-default-on.c
@@ -19,7 +19,7 @@
static void defon_trig_activate(struct led_classdev *led_cdev)
{
- led_set_brightness_async(led_cdev, led_cdev->max_brightness);
+ led_set_brightness_nosleep(led_cdev, led_cdev->max_brightness);
}
static struct led_trigger defon_led_trigger = {
diff --git a/drivers/leds/trigger/ledtrig-gpio.c b/drivers/leds/trigger/ledtrig-gpio.c
index 4cc7040..51288a4 100644
--- a/drivers/leds/trigger/ledtrig-gpio.c
+++ b/drivers/leds/trigger/ledtrig-gpio.c
@@ -54,12 +54,12 @@ static void gpio_trig_work(struct work_struct *work)
if (tmp) {
if (gpio_data->desired_brightness)
- led_set_brightness_async(gpio_data->led,
+ led_set_brightness_nosleep(gpio_data->led,
gpio_data->desired_brightness);
else
- led_set_brightness_async(gpio_data->led, LED_FULL);
+ led_set_brightness_nosleep(gpio_data->led, LED_FULL);
} else {
- led_set_brightness_async(gpio_data->led, LED_OFF);
+ led_set_brightness_nosleep(gpio_data->led, LED_OFF);
}
}
diff --git a/drivers/leds/trigger/ledtrig-heartbeat.c b/drivers/leds/trigger/ledtrig-heartbeat.c
index 8622ce6..410c39c 100644
--- a/drivers/leds/trigger/ledtrig-heartbeat.c
+++ b/drivers/leds/trigger/ledtrig-heartbeat.c
@@ -38,7 +38,7 @@ static void led_heartbeat_function(unsigned long data)
unsigned long delay = 0;
if (unlikely(panic_heartbeats)) {
- led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_nosleep(led_cdev, LED_OFF);
return;
}
@@ -81,7 +81,7 @@ static void led_heartbeat_function(unsigned long data)
break;
}
- led_set_brightness_async(led_cdev, brightness);
+ led_set_brightness_nosleep(led_cdev, brightness);
mod_timer(&heartbeat_data->timer, jiffies + delay);
}
diff --git a/drivers/leds/trigger/ledtrig-ide-disk.c b/drivers/leds/trigger/ledtrig-ide-disk.c
index 2cd7c0c..c02a3ac 100644
--- a/drivers/leds/trigger/ledtrig-ide-disk.c
+++ b/drivers/leds/trigger/ledtrig-ide-disk.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/leds.h>
@@ -33,15 +32,4 @@ static int __init ledtrig_ide_init(void)
led_trigger_register_simple("ide-disk", &ledtrig_ide);
return 0;
}
-
-static void __exit ledtrig_ide_exit(void)
-{
- led_trigger_unregister_simple(ledtrig_ide);
-}
-
-module_init(ledtrig_ide_init);
-module_exit(ledtrig_ide_exit);
-
-MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
-MODULE_DESCRIPTION("LED IDE Disk Activity Trigger");
-MODULE_LICENSE("GPL");
+device_initcall(ledtrig_ide_init);
diff --git a/drivers/leds/trigger/ledtrig-oneshot.c b/drivers/leds/trigger/ledtrig-oneshot.c
index fbd02cd..b8ea9f0 100644
--- a/drivers/leds/trigger/ledtrig-oneshot.c
+++ b/drivers/leds/trigger/ledtrig-oneshot.c
@@ -63,9 +63,9 @@ static ssize_t led_invert_store(struct device *dev,
oneshot_data->invert = !!state;
if (oneshot_data->invert)
- led_set_brightness_async(led_cdev, LED_FULL);
+ led_set_brightness_nosleep(led_cdev, LED_FULL);
else
- led_set_brightness_async(led_cdev, LED_OFF);
+ led_set_brightness_nosleep(led_cdev, LED_OFF);
return size;
}
@@ -201,4 +201,4 @@ module_exit(oneshot_trig_exit);
MODULE_AUTHOR("Fabio Baltieri <fabio.baltieri@gmail.com>");
MODULE_DESCRIPTION("One-shot LED trigger");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/trigger/ledtrig-transient.c b/drivers/leds/trigger/ledtrig-transient.c
index 3c34de4..7e6011b 100644
--- a/drivers/leds/trigger/ledtrig-transient.c
+++ b/drivers/leds/trigger/ledtrig-transient.c
@@ -41,7 +41,7 @@ static void transient_timer_function(unsigned long data)
struct transient_trig_data *transient_data = led_cdev->trigger_data;
transient_data->activate = 0;
- led_set_brightness_async(led_cdev, transient_data->restore_state);
+ led_set_brightness_nosleep(led_cdev, transient_data->restore_state);
}
static ssize_t transient_activate_show(struct device *dev,
@@ -72,7 +72,7 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 0 && transient_data->activate == 1) {
del_timer(&transient_data->timer);
transient_data->activate = state;
- led_set_brightness_async(led_cdev,
+ led_set_brightness_nosleep(led_cdev,
transient_data->restore_state);
return size;
}
@@ -81,11 +81,11 @@ static ssize_t transient_activate_store(struct device *dev,
if (state == 1 && transient_data->activate == 0 &&
transient_data->duration != 0) {
transient_data->activate = state;
- led_set_brightness_async(led_cdev, transient_data->state);
+ led_set_brightness_nosleep(led_cdev, transient_data->state);
transient_data->restore_state =
(transient_data->state == LED_FULL) ? LED_OFF : LED_FULL;
mod_timer(&transient_data->timer,
- jiffies + transient_data->duration);
+ jiffies + msecs_to_jiffies(transient_data->duration));
}
/* state == 0 && transient_data->activate == 0
@@ -204,7 +204,7 @@ static void transient_trig_deactivate(struct led_classdev *led_cdev)
if (led_cdev->activated) {
del_timer_sync(&transient_data->timer);
- led_set_brightness_async(led_cdev,
+ led_set_brightness_nosleep(led_cdev,
transient_data->restore_state);
device_remove_file(led_cdev->dev, &dev_attr_activate);
device_remove_file(led_cdev->dev, &dev_attr_duration);
diff --git a/drivers/lightnvm/Kconfig b/drivers/lightnvm/Kconfig
index a16bf56..85a3390 100644
--- a/drivers/lightnvm/Kconfig
+++ b/drivers/lightnvm/Kconfig
@@ -18,6 +18,7 @@ if NVM
config NVM_DEBUG
bool "Open-Channel SSD debugging support"
+ default n
---help---
Exposes a debug management interface to create/remove targets at:
diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c
index f659e60..8f41b24 100644
--- a/drivers/lightnvm/core.c
+++ b/drivers/lightnvm/core.c
@@ -74,7 +74,7 @@ EXPORT_SYMBOL(nvm_unregister_target);
void *nvm_dev_dma_alloc(struct nvm_dev *dev, gfp_t mem_flags,
dma_addr_t *dma_handler)
{
- return dev->ops->dev_dma_alloc(dev->q, dev->ppalist_pool, mem_flags,
+ return dev->ops->dev_dma_alloc(dev, dev->ppalist_pool, mem_flags,
dma_handler);
}
EXPORT_SYMBOL(nvm_dev_dma_alloc);
@@ -97,15 +97,47 @@ static struct nvmm_type *nvm_find_mgr_type(const char *name)
return NULL;
}
+struct nvmm_type *nvm_init_mgr(struct nvm_dev *dev)
+{
+ struct nvmm_type *mt;
+ int ret;
+
+ lockdep_assert_held(&nvm_lock);
+
+ list_for_each_entry(mt, &nvm_mgrs, list) {
+ ret = mt->register_mgr(dev);
+ if (ret < 0) {
+ pr_err("nvm: media mgr failed to init (%d) on dev %s\n",
+ ret, dev->name);
+ return NULL; /* initialization failed */
+ } else if (ret > 0)
+ return mt;
+ }
+
+ return NULL;
+}
+
int nvm_register_mgr(struct nvmm_type *mt)
{
+ struct nvm_dev *dev;
int ret = 0;
down_write(&nvm_lock);
- if (nvm_find_mgr_type(mt->name))
+ if (nvm_find_mgr_type(mt->name)) {
ret = -EEXIST;
- else
+ goto finish;
+ } else {
list_add(&mt->list, &nvm_mgrs);
+ }
+
+ /* try to register media mgr if any device have none configured */
+ list_for_each_entry(dev, &nvm_devices, devices) {
+ if (dev->mt)
+ continue;
+
+ dev->mt = nvm_init_mgr(dev);
+ }
+finish:
up_write(&nvm_lock);
return ret;
@@ -160,11 +192,6 @@ int nvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk)
}
EXPORT_SYMBOL(nvm_erase_blk);
-static void nvm_core_free(struct nvm_dev *dev)
-{
- kfree(dev);
-}
-
static int nvm_core_init(struct nvm_dev *dev)
{
struct nvm_id *id = &dev->identity;
@@ -179,12 +206,21 @@ static int nvm_core_init(struct nvm_dev *dev)
dev->sec_size = grp->csecs;
dev->oob_size = grp->sos;
dev->sec_per_pg = grp->fpg_sz / grp->csecs;
- dev->addr_mode = id->ppat;
- dev->addr_format = id->ppaf;
+ memcpy(&dev->ppaf, &id->ppaf, sizeof(struct nvm_addr_format));
dev->plane_mode = NVM_PLANE_SINGLE;
dev->max_rq_size = dev->ops->max_phys_sect * dev->sec_size;
+ if (grp->mtype != 0) {
+ pr_err("nvm: memory type not supported\n");
+ return -EINVAL;
+ }
+
+ if (grp->fmtype != 0 && grp->fmtype != 1) {
+ pr_err("nvm: flash type not supported\n");
+ return -EINVAL;
+ }
+
if (grp->mpos & 0x020202)
dev->plane_mode = NVM_PLANE_DOUBLE;
if (grp->mpos & 0x040404)
@@ -213,21 +249,17 @@ static void nvm_free(struct nvm_dev *dev)
if (dev->mt)
dev->mt->unregister_mgr(dev);
-
- nvm_core_free(dev);
}
static int nvm_init(struct nvm_dev *dev)
{
- struct nvmm_type *mt;
- int ret = 0;
+ int ret = -EINVAL;
if (!dev->q || !dev->ops)
- return -EINVAL;
+ return ret;
- if (dev->ops->identity(dev->q, &dev->identity)) {
+ if (dev->ops->identity(dev, &dev->identity)) {
pr_err("nvm: device could not be identified\n");
- ret = -EINVAL;
goto err;
}
@@ -251,29 +283,12 @@ static int nvm_init(struct nvm_dev *dev)
goto err;
}
- /* register with device with a supported manager */
- list_for_each_entry(mt, &nvm_mgrs, list) {
- ret = mt->register_mgr(dev);
- if (ret < 0)
- goto err; /* initialization failed */
- if (ret > 0) {
- dev->mt = mt;
- break; /* successfully initialized */
- }
- }
-
- if (!ret) {
- pr_info("nvm: no compatible manager found.\n");
- return 0;
- }
-
pr_info("nvm: registered %s [%u/%u/%u/%u/%u/%u]\n",
dev->name, dev->sec_per_pg, dev->nr_planes,
dev->pgs_per_blk, dev->blks_per_lun, dev->nr_luns,
dev->nr_chnls);
return 0;
err:
- nvm_free(dev);
pr_err("nvm: failed to initialize nvm\n");
return ret;
}
@@ -308,22 +323,27 @@ int nvm_register(struct request_queue *q, char *disk_name,
if (ret)
goto err_init;
- down_write(&nvm_lock);
- list_add(&dev->devices, &nvm_devices);
- up_write(&nvm_lock);
+ if (dev->ops->max_phys_sect > 256) {
+ pr_info("nvm: max sectors supported is 256.\n");
+ ret = -EINVAL;
+ goto err_init;
+ }
if (dev->ops->max_phys_sect > 1) {
- dev->ppalist_pool = dev->ops->create_dma_pool(dev->q,
- "ppalist");
+ dev->ppalist_pool = dev->ops->create_dma_pool(dev, "ppalist");
if (!dev->ppalist_pool) {
pr_err("nvm: could not create ppa pool\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_init;
}
- } else if (dev->ops->max_phys_sect > 256) {
- pr_info("nvm: max sectors supported is 256.\n");
- return -EINVAL;
}
+ /* register device with a supported media manager */
+ down_write(&nvm_lock);
+ dev->mt = nvm_init_mgr(dev);
+ list_add(&dev->devices, &nvm_devices);
+ up_write(&nvm_lock);
+
return 0;
err_init:
kfree(dev);
@@ -333,19 +353,22 @@ EXPORT_SYMBOL(nvm_register);
void nvm_unregister(char *disk_name)
{
- struct nvm_dev *dev = nvm_find_nvm_dev(disk_name);
+ struct nvm_dev *dev;
+ down_write(&nvm_lock);
+ dev = nvm_find_nvm_dev(disk_name);
if (!dev) {
pr_err("nvm: could not find device %s to unregister\n",
disk_name);
+ up_write(&nvm_lock);
return;
}
- nvm_exit(dev);
-
- down_write(&nvm_lock);
list_del(&dev->devices);
up_write(&nvm_lock);
+
+ nvm_exit(dev);
+ kfree(dev);
}
EXPORT_SYMBOL(nvm_unregister);
@@ -358,38 +381,24 @@ static int nvm_create_target(struct nvm_dev *dev,
{
struct nvm_ioctl_create_simple *s = &create->conf.s;
struct request_queue *tqueue;
- struct nvmm_type *mt;
struct gendisk *tdisk;
struct nvm_tgt_type *tt;
struct nvm_target *t;
void *targetdata;
- int ret = 0;
if (!dev->mt) {
- /* register with device with a supported NVM manager */
- list_for_each_entry(mt, &nvm_mgrs, list) {
- ret = mt->register_mgr(dev);
- if (ret < 0)
- return ret; /* initialization failed */
- if (ret > 0) {
- dev->mt = mt;
- break; /* successfully initialized */
- }
- }
-
- if (!ret) {
- pr_info("nvm: no compatible nvm manager found.\n");
- return -ENODEV;
- }
+ pr_info("nvm: device has no media manager registered.\n");
+ return -ENODEV;
}
+ down_write(&nvm_lock);
tt = nvm_find_target_type(create->tgttype);
if (!tt) {
pr_err("nvm: target type %s not found\n", create->tgttype);
+ up_write(&nvm_lock);
return -EINVAL;
}
- down_write(&nvm_lock);
list_for_each_entry(t, &dev->online_targets, list) {
if (!strcmp(create->tgtname, t->disk->disk_name)) {
pr_err("nvm: target name already exists.\n");
@@ -457,11 +466,11 @@ static void nvm_remove_target(struct nvm_target *t)
lockdep_assert_held(&nvm_lock);
del_gendisk(tdisk);
+ blk_cleanup_queue(q);
+
if (tt->exit)
tt->exit(tdisk->private_data);
- blk_cleanup_queue(q);
-
put_disk(tdisk);
list_del(&t->list);
@@ -473,7 +482,9 @@ static int __nvm_configure_create(struct nvm_ioctl_create *create)
struct nvm_dev *dev;
struct nvm_ioctl_create_simple *s;
+ down_write(&nvm_lock);
dev = nvm_find_nvm_dev(create->dev);
+ up_write(&nvm_lock);
if (!dev) {
pr_err("nvm: device not found\n");
return -EINVAL;
@@ -532,7 +543,9 @@ static int nvm_configure_show(const char *val)
return -EINVAL;
}
+ down_write(&nvm_lock);
dev = nvm_find_nvm_dev(devname);
+ up_write(&nvm_lock);
if (!dev) {
pr_err("nvm: device not found\n");
return -EINVAL;
@@ -541,7 +554,7 @@ static int nvm_configure_show(const char *val)
if (!dev->mt)
return 0;
- dev->mt->free_blocks_print(dev);
+ dev->mt->lun_info_print(dev);
return 0;
}
@@ -677,8 +690,10 @@ static long nvm_ioctl_info(struct file *file, void __user *arg)
info->tgtsize = tgt_iter;
up_write(&nvm_lock);
- if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info)))
+ if (copy_to_user(arg, info, sizeof(struct nvm_ioctl_info))) {
+ kfree(info);
return -EFAULT;
+ }
kfree(info);
return 0;
@@ -721,8 +736,11 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg)
devices->nr_devices = i;
- if (copy_to_user(arg, devices, sizeof(struct nvm_ioctl_get_devices)))
+ if (copy_to_user(arg, devices,
+ sizeof(struct nvm_ioctl_get_devices))) {
+ kfree(devices);
return -EFAULT;
+ }
kfree(devices);
return 0;
diff --git a/drivers/lightnvm/gennvm.c b/drivers/lightnvm/gennvm.c
index ae1fb2b..a54b339 100644
--- a/drivers/lightnvm/gennvm.c
+++ b/drivers/lightnvm/gennvm.c
@@ -60,23 +60,27 @@ static int gennvm_luns_init(struct nvm_dev *dev, struct gen_nvm *gn)
lun->vlun.lun_id = i % dev->luns_per_chnl;
lun->vlun.chnl_id = i / dev->luns_per_chnl;
lun->vlun.nr_free_blocks = dev->blks_per_lun;
+ lun->vlun.nr_inuse_blocks = 0;
+ lun->vlun.nr_bad_blocks = 0;
}
return 0;
}
-static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks,
+static int gennvm_block_bb(struct ppa_addr ppa, int nr_blocks, u8 *blks,
void *private)
{
struct gen_nvm *gn = private;
- struct gen_lun *lun = &gn->luns[lun_id];
+ struct nvm_dev *dev = gn->dev;
+ struct gen_lun *lun;
struct nvm_block *blk;
int i;
- if (unlikely(bitmap_empty(bb_bitmap, nr_blocks)))
- return 0;
+ lun = &gn->luns[(dev->luns_per_chnl * ppa.g.ch) + ppa.g.lun];
+
+ for (i = 0; i < nr_blocks; i++) {
+ if (blks[i] == 0)
+ continue;
- i = -1;
- while ((i = find_next_bit(bb_bitmap, nr_blocks, i + 1)) < nr_blocks) {
blk = &lun->vlun.blocks[i];
if (!blk) {
pr_err("gennvm: BB data is out of bounds.\n");
@@ -84,6 +88,7 @@ static int gennvm_block_bb(u32 lun_id, void *bb_bitmap, unsigned int nr_blocks,
}
list_move_tail(&blk->list, &lun->bb_list);
+ lun->vlun.nr_bad_blocks++;
}
return 0;
@@ -136,6 +141,7 @@ static int gennvm_block_map(u64 slba, u32 nlb, __le64 *entries, void *private)
list_move_tail(&blk->list, &lun->used_list);
blk->type = 1;
lun->vlun.nr_free_blocks--;
+ lun->vlun.nr_inuse_blocks++;
}
}
@@ -164,22 +170,32 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
block->id = cur_block_id++;
/* First block is reserved for device */
- if (unlikely(lun_iter == 0 && blk_iter == 0))
+ if (unlikely(lun_iter == 0 && blk_iter == 0)) {
+ lun->vlun.nr_free_blocks--;
continue;
+ }
list_add_tail(&block->list, &lun->free_list);
}
if (dev->ops->get_bb_tbl) {
- ret = dev->ops->get_bb_tbl(dev->q, lun->vlun.id,
- dev->blks_per_lun, gennvm_block_bb, gn);
+ struct ppa_addr ppa;
+
+ ppa.ppa = 0;
+ ppa.g.ch = lun->vlun.chnl_id;
+ ppa.g.lun = lun->vlun.id;
+ ppa = generic_to_dev_addr(dev, ppa);
+
+ ret = dev->ops->get_bb_tbl(dev, ppa,
+ dev->blks_per_lun,
+ gennvm_block_bb, gn);
if (ret)
pr_err("gennvm: could not read BB table\n");
}
}
if (dev->ops->get_l2p_tbl) {
- ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages,
+ ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages,
gennvm_block_map, dev);
if (ret) {
pr_err("gennvm: could not read L2P table.\n");
@@ -190,15 +206,27 @@ static int gennvm_blocks_init(struct nvm_dev *dev, struct gen_nvm *gn)
return 0;
}
+static void gennvm_free(struct nvm_dev *dev)
+{
+ gennvm_blocks_free(dev);
+ gennvm_luns_free(dev);
+ kfree(dev->mp);
+ dev->mp = NULL;
+}
+
static int gennvm_register(struct nvm_dev *dev)
{
struct gen_nvm *gn;
int ret;
+ if (!try_module_get(THIS_MODULE))
+ return -ENODEV;
+
gn = kzalloc(sizeof(struct gen_nvm), GFP_KERNEL);
if (!gn)
return -ENOMEM;
+ gn->dev = dev;
gn->nr_luns = dev->nr_luns;
dev->mp = gn;
@@ -216,16 +244,15 @@ static int gennvm_register(struct nvm_dev *dev)
return 1;
err:
- kfree(gn);
+ gennvm_free(dev);
+ module_put(THIS_MODULE);
return ret;
}
static void gennvm_unregister(struct nvm_dev *dev)
{
- gennvm_blocks_free(dev);
- gennvm_luns_free(dev);
- kfree(dev->mp);
- dev->mp = NULL;
+ gennvm_free(dev);
+ module_put(THIS_MODULE);
}
static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
@@ -240,23 +267,21 @@ static struct nvm_block *gennvm_get_blk(struct nvm_dev *dev,
if (list_empty(&lun->free_list)) {
pr_err_ratelimited("gennvm: lun %u have no free pages available",
lun->vlun.id);
- spin_unlock(&vlun->lock);
goto out;
}
- while (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks) {
- spin_unlock(&vlun->lock);
+ if (!is_gc && lun->vlun.nr_free_blocks < lun->reserved_blocks)
goto out;
- }
blk = list_first_entry(&lun->free_list, struct nvm_block, list);
list_move_tail(&blk->list, &lun->used_list);
blk->type = 1;
lun->vlun.nr_free_blocks--;
+ lun->vlun.nr_inuse_blocks++;
- spin_unlock(&vlun->lock);
out:
+ spin_unlock(&vlun->lock);
return blk;
}
@@ -271,16 +296,21 @@ static void gennvm_put_blk(struct nvm_dev *dev, struct nvm_block *blk)
case 1:
list_move_tail(&blk->list, &lun->free_list);
lun->vlun.nr_free_blocks++;
+ lun->vlun.nr_inuse_blocks--;
blk->type = 0;
break;
case 2:
list_move_tail(&blk->list, &lun->bb_list);
+ lun->vlun.nr_bad_blocks++;
+ lun->vlun.nr_inuse_blocks--;
break;
default:
WARN_ON_ONCE(1);
pr_err("gennvm: erroneous block type (%lu -> %u)\n",
blk->id, blk->type);
list_move_tail(&blk->list, &lun->bb_list);
+ lun->vlun.nr_bad_blocks++;
+ lun->vlun.nr_inuse_blocks--;
}
spin_unlock(&vlun->lock);
@@ -292,10 +322,10 @@ static void gennvm_addr_to_generic_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
if (rqd->nr_pages > 1) {
for (i = 0; i < rqd->nr_pages; i++)
- rqd->ppa_list[i] = addr_to_generic_mode(dev,
+ rqd->ppa_list[i] = dev_to_generic_addr(dev,
rqd->ppa_list[i]);
} else {
- rqd->ppa_addr = addr_to_generic_mode(dev, rqd->ppa_addr);
+ rqd->ppa_addr = dev_to_generic_addr(dev, rqd->ppa_addr);
}
}
@@ -305,10 +335,10 @@ static void gennvm_generic_to_addr_mode(struct nvm_dev *dev, struct nvm_rq *rqd)
if (rqd->nr_pages > 1) {
for (i = 0; i < rqd->nr_pages; i++)
- rqd->ppa_list[i] = generic_to_addr_mode(dev,
+ rqd->ppa_list[i] = generic_to_dev_addr(dev,
rqd->ppa_list[i]);
} else {
- rqd->ppa_addr = generic_to_addr_mode(dev, rqd->ppa_addr);
+ rqd->ppa_addr = generic_to_dev_addr(dev, rqd->ppa_addr);
}
}
@@ -321,7 +351,7 @@ static int gennvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
gennvm_generic_to_addr_mode(dev, rqd);
rqd->dev = dev;
- return dev->ops->submit_io(dev->q, rqd);
+ return dev->ops->submit_io(dev, rqd);
}
static void gennvm_blk_set_type(struct nvm_dev *dev, struct ppa_addr *ppa,
@@ -354,10 +384,10 @@ static void gennvm_mark_blk_bad(struct nvm_dev *dev, struct nvm_rq *rqd)
{
int i;
- if (!dev->ops->set_bb)
+ if (!dev->ops->set_bb_tbl)
return;
- if (dev->ops->set_bb(dev->q, rqd, 1))
+ if (dev->ops->set_bb_tbl(dev, rqd, 1))
return;
gennvm_addr_to_generic_mode(dev, rqd);
@@ -425,7 +455,7 @@ static int gennvm_erase_blk(struct nvm_dev *dev, struct nvm_block *blk,
gennvm_generic_to_addr_mode(dev, &rqd);
- ret = dev->ops->erase_block(dev->q, &rqd);
+ ret = dev->ops->erase_block(dev, &rqd);
if (plane_cnt)
nvm_dev_dma_free(dev, rqd.ppa_list, rqd.dma_ppa_list);
@@ -440,15 +470,24 @@ static struct nvm_lun *gennvm_get_lun(struct nvm_dev *dev, int lunid)
return &gn->luns[lunid].vlun;
}
-static void gennvm_free_blocks_print(struct nvm_dev *dev)
+static void gennvm_lun_info_print(struct nvm_dev *dev)
{
struct gen_nvm *gn = dev->mp;
struct gen_lun *lun;
unsigned int i;
- gennvm_for_each_lun(gn, lun, i)
- pr_info("%s: lun%8u\t%u\n",
- dev->name, i, lun->vlun.nr_free_blocks);
+
+ gennvm_for_each_lun(gn, lun, i) {
+ spin_lock(&lun->vlun.lock);
+
+ pr_info("%s: lun%8u\t%u\t%u\t%u\n",
+ dev->name, i,
+ lun->vlun.nr_free_blocks,
+ lun->vlun.nr_inuse_blocks,
+ lun->vlun.nr_bad_blocks);
+
+ spin_unlock(&lun->vlun.lock);
+ }
}
static struct nvmm_type gennvm = {
@@ -466,7 +505,7 @@ static struct nvmm_type gennvm = {
.erase_blk = gennvm_erase_blk,
.get_lun = gennvm_get_lun,
- .free_blocks_print = gennvm_free_blocks_print,
+ .lun_info_print = gennvm_lun_info_print,
};
static int __init gennvm_module_init(void)
diff --git a/drivers/lightnvm/gennvm.h b/drivers/lightnvm/gennvm.h
index d23bd35..9c24b5b 100644
--- a/drivers/lightnvm/gennvm.h
+++ b/drivers/lightnvm/gennvm.h
@@ -35,6 +35,8 @@ struct gen_lun {
};
struct gen_nvm {
+ struct nvm_dev *dev;
+
int nr_luns;
struct gen_lun *luns;
};
diff --git a/drivers/lightnvm/rrpc.c b/drivers/lightnvm/rrpc.c
index 64a888a..134e4fa 100644
--- a/drivers/lightnvm/rrpc.c
+++ b/drivers/lightnvm/rrpc.c
@@ -123,12 +123,42 @@ static u64 block_to_addr(struct rrpc *rrpc, struct rrpc_block *rblk)
return blk->id * rrpc->dev->pgs_per_blk;
}
+static struct ppa_addr linear_to_generic_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
+{
+ struct ppa_addr l;
+ int secs, pgs, blks, luns;
+ sector_t ppa = r.ppa;
+
+ l.ppa = 0;
+
+ div_u64_rem(ppa, dev->sec_per_pg, &secs);
+ l.g.sec = secs;
+
+ sector_div(ppa, dev->sec_per_pg);
+ div_u64_rem(ppa, dev->sec_per_blk, &pgs);
+ l.g.pg = pgs;
+
+ sector_div(ppa, dev->pgs_per_blk);
+ div_u64_rem(ppa, dev->blks_per_lun, &blks);
+ l.g.blk = blks;
+
+ sector_div(ppa, dev->blks_per_lun);
+ div_u64_rem(ppa, dev->luns_per_chnl, &luns);
+ l.g.lun = luns;
+
+ sector_div(ppa, dev->luns_per_chnl);
+ l.g.ch = ppa;
+
+ return l;
+}
+
static struct ppa_addr rrpc_ppa_to_gaddr(struct nvm_dev *dev, u64 addr)
{
struct ppa_addr paddr;
paddr.ppa = addr;
- return __linear_to_generic_addr(dev, paddr);
+ return linear_to_generic_addr(dev, paddr);
}
/* requires lun->lock taken */
@@ -152,7 +182,7 @@ static struct rrpc_block *rrpc_get_blk(struct rrpc *rrpc, struct rrpc_lun *rlun,
struct nvm_block *blk;
struct rrpc_block *rblk;
- blk = nvm_get_blk(rrpc->dev, rlun->parent, 0);
+ blk = nvm_get_blk(rrpc->dev, rlun->parent, flags);
if (!blk)
return NULL;
@@ -172,6 +202,20 @@ static void rrpc_put_blk(struct rrpc *rrpc, struct rrpc_block *rblk)
nvm_put_blk(rrpc->dev, rblk->parent);
}
+static void rrpc_put_blks(struct rrpc *rrpc)
+{
+ struct rrpc_lun *rlun;
+ int i;
+
+ for (i = 0; i < rrpc->nr_luns; i++) {
+ rlun = &rrpc->luns[i];
+ if (rlun->cur)
+ rrpc_put_blk(rrpc, rlun->cur);
+ if (rlun->gc_cur)
+ rrpc_put_blk(rrpc, rlun->gc_cur);
+ }
+}
+
static struct rrpc_lun *get_next_lun(struct rrpc *rrpc)
{
int next = atomic_inc_return(&rrpc->next_lun);
@@ -803,7 +847,7 @@ static int rrpc_submit_io(struct rrpc *rrpc, struct bio *bio,
return NVM_IO_OK;
}
-static void rrpc_make_rq(struct request_queue *q, struct bio *bio)
+static blk_qc_t rrpc_make_rq(struct request_queue *q, struct bio *bio)
{
struct rrpc *rrpc = q->queuedata;
struct nvm_rq *rqd;
@@ -811,21 +855,21 @@ static void rrpc_make_rq(struct request_queue *q, struct bio *bio)
if (bio->bi_rw & REQ_DISCARD) {
rrpc_discard(rrpc, bio);
- return;
+ return BLK_QC_T_NONE;
}
rqd = mempool_alloc(rrpc->rq_pool, GFP_KERNEL);
if (!rqd) {
pr_err_ratelimited("rrpc: not able to queue bio.");
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
memset(rqd, 0, sizeof(struct nvm_rq));
err = rrpc_submit_io(rrpc, bio, rqd, NVM_IOTYPE_NONE);
switch (err) {
case NVM_IO_OK:
- return;
+ return BLK_QC_T_NONE;
case NVM_IO_ERR:
bio_io_error(bio);
break;
@@ -841,6 +885,7 @@ static void rrpc_make_rq(struct request_queue *q, struct bio *bio)
}
mempool_free(rqd, rrpc->rq_pool);
+ return BLK_QC_T_NONE;
}
static void rrpc_requeue(struct work_struct *work)
@@ -971,7 +1016,7 @@ static int rrpc_map_init(struct rrpc *rrpc)
return 0;
/* Bring up the mapping table from device */
- ret = dev->ops->get_l2p_tbl(dev->q, 0, dev->total_pages,
+ ret = dev->ops->get_l2p_tbl(dev, 0, dev->total_pages,
rrpc_l2p_update, rrpc);
if (ret) {
pr_err("nvm: rrpc: could not read L2P table.\n");
@@ -1193,18 +1238,21 @@ static int rrpc_luns_configure(struct rrpc *rrpc)
rblk = rrpc_get_blk(rrpc, rlun, 0);
if (!rblk)
- return -EINVAL;
+ goto err;
rrpc_set_lun_cur(rlun, rblk);
/* Emergency gc block */
rblk = rrpc_get_blk(rrpc, rlun, 1);
if (!rblk)
- return -EINVAL;
+ goto err;
rlun->gc_cur = rblk;
}
return 0;
+err:
+ rrpc_put_blks(rrpc);
+ return -EINVAL;
}
static struct nvm_tgt_type tt_rrpc;
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 3e01e6f..0a2e727 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -123,6 +123,7 @@ config MD_RAID456
tristate "RAID-4/RAID-5/RAID-6 mode"
depends on BLK_DEV_MD
select RAID6_PQ
+ select LIBCRC32C
select ASYNC_MEMCPY
select ASYNC_XOR
select ASYNC_PQ
@@ -239,6 +240,15 @@ config DM_BUFIO
as a cache, holding recently-read blocks in memory and performing
delayed writes.
+config DM_DEBUG_BLOCK_STACK_TRACING
+ bool "Keep stack trace of persistent data block lock holders"
+ depends on STACKTRACE_SUPPORT && DM_BUFIO
+ select STACKTRACE
+ ---help---
+ Enable this for messages that may help debug problems with the
+ block manager locking used by thin provisioning and caching.
+
+ If unsure, say N.
config DM_BIO_PRISON
tristate
depends on BLK_DEV_DM
@@ -457,6 +467,18 @@ config DM_VERITY
If unsure, say N.
+config DM_VERITY_FEC
+ bool "Verity forward error correction support"
+ depends on DM_VERITY
+ select REED_SOLOMON
+ select REED_SOLOMON_DEC8
+ ---help---
+ Add forward error correction support to dm-verity. This option
+ makes it possible to use pre-generated error correction data to
+ recover from corrupted blocks.
+
+ If unsure, say N.
+
config DM_SWITCH
tristate "Switch target support (EXPERIMENTAL)"
depends on BLK_DEV_DM
diff --git a/drivers/md/Makefile b/drivers/md/Makefile
index f34979c..62a6576 100644
--- a/drivers/md/Makefile
+++ b/drivers/md/Makefile
@@ -16,6 +16,7 @@ dm-cache-mq-y += dm-cache-policy-mq.o
dm-cache-smq-y += dm-cache-policy-smq.o
dm-cache-cleaner-y += dm-cache-policy-cleaner.o
dm-era-y += dm-era-target.o
+dm-verity-y += dm-verity-target.o
md-mod-y += md.o bitmap.o
raid456-y += raid5.o raid5-cache.o
@@ -63,3 +64,7 @@ obj-$(CONFIG_DM_LOG_WRITES) += dm-log-writes.o
ifeq ($(CONFIG_DM_UEVENT),y)
dm-mod-objs += dm-uevent.o
endif
+
+ifeq ($(CONFIG_DM_VERITY_FEC),y)
+dm-verity-objs += dm-verity-fec.o
+endif
diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c
index 8e9877b..25fa844 100644
--- a/drivers/md/bcache/request.c
+++ b/drivers/md/bcache/request.c
@@ -958,7 +958,8 @@ static void cached_dev_nodata(struct closure *cl)
/* Cached devices - read & write stuff */
-static void cached_dev_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t cached_dev_make_request(struct request_queue *q,
+ struct bio *bio)
{
struct search *s;
struct bcache_device *d = bio->bi_bdev->bd_disk->private_data;
@@ -997,6 +998,8 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio)
else
generic_make_request(bio);
}
+
+ return BLK_QC_T_NONE;
}
static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode,
@@ -1070,7 +1073,8 @@ static void flash_dev_nodata(struct closure *cl)
continue_at(cl, search_free, NULL);
}
-static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t flash_dev_make_request(struct request_queue *q,
+ struct bio *bio)
{
struct search *s;
struct closure *cl;
@@ -1093,7 +1097,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
continue_at_nobarrier(&s->cl,
flash_dev_nodata,
bcache_wq);
- return;
+ return BLK_QC_T_NONE;
} else if (rw) {
bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys,
&KEY(d->id, bio->bi_iter.bi_sector, 0),
@@ -1109,6 +1113,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
}
continue_at(cl, search_free, NULL);
+ return BLK_QC_T_NONE;
}
static int flash_dev_ioctl(struct bcache_device *d, fmode_t mode,
diff --git a/drivers/md/bcache/util.c b/drivers/md/bcache/util.c
index db3ae4c..dde6172 100644
--- a/drivers/md/bcache/util.c
+++ b/drivers/md/bcache/util.c
@@ -230,7 +230,7 @@ void bch_bio_map(struct bio *bio, void *base)
BUG_ON(!bio->bi_iter.bi_size);
BUG_ON(bio->bi_vcnt);
- bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0;
+ bv->bv_offset = base ? offset_in_page(base) : 0;
goto start;
for (; size; bio->bi_vcnt++, bv++) {
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index 2dd3308..cd77216 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -16,6 +16,7 @@
#include <linux/shrinker.h>
#include <linux/module.h>
#include <linux/rbtree.h>
+#include <linux/stacktrace.h>
#define DM_MSG_PREFIX "bufio"
@@ -149,6 +150,11 @@ struct dm_buffer {
struct list_head write_list;
struct bio bio;
struct bio_vec bio_vec[DM_BUFIO_INLINE_VECS];
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+#define MAX_STACK 10
+ struct stack_trace stack_trace;
+ unsigned long stack_entries[MAX_STACK];
+#endif
};
/*----------------------------------------------------------------*/
@@ -253,6 +259,17 @@ static LIST_HEAD(dm_bufio_all_clients);
*/
static DEFINE_MUTEX(dm_bufio_clients_lock);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+static void buffer_record_stack(struct dm_buffer *b)
+{
+ b->stack_trace.nr_entries = 0;
+ b->stack_trace.max_entries = MAX_STACK;
+ b->stack_trace.entries = b->stack_entries;
+ b->stack_trace.skip = 2;
+ save_stack_trace(&b->stack_trace);
+}
+#endif
+
/*----------------------------------------------------------------
* A red/black tree acts as an index for all the buffers.
*--------------------------------------------------------------*/
@@ -454,6 +471,9 @@ static struct dm_buffer *alloc_buffer(struct dm_bufio_client *c, gfp_t gfp_mask)
adjust_total_allocated(b->data_mode, (long)c->block_size);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+ memset(&b->stack_trace, 0, sizeof(b->stack_trace));
+#endif
return b;
}
@@ -630,7 +650,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block,
do {
if (!bio_add_page(&b->bio, virt_to_page(ptr),
len < PAGE_SIZE ? len : PAGE_SIZE,
- virt_to_phys(ptr) & (PAGE_SIZE - 1))) {
+ offset_in_page(ptr))) {
BUG_ON(b->c->block_size <= PAGE_SIZE);
use_dmio(b, rw, block, end_io);
return;
@@ -1063,12 +1083,16 @@ static void *new_read(struct dm_bufio_client *c, sector_t block,
dm_bufio_lock(c);
b = __bufio_new(c, block, nf, &need_submit, &write_list);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+ if (b && b->hold_count == 1)
+ buffer_record_stack(b);
+#endif
dm_bufio_unlock(c);
__flush_write_list(&write_list);
if (!b)
- return b;
+ return NULL;
if (need_submit)
submit_io(b, READ, b->block, read_endio);
@@ -1462,6 +1486,7 @@ static void drop_buffers(struct dm_bufio_client *c)
{
struct dm_buffer *b;
int i;
+ bool warned = false;
BUG_ON(dm_bufio_in_request());
@@ -1476,9 +1501,21 @@ static void drop_buffers(struct dm_bufio_client *c)
__free_buffer_wake(b);
for (i = 0; i < LIST_SIZE; i++)
- list_for_each_entry(b, &c->lru[i], lru_list)
+ list_for_each_entry(b, &c->lru[i], lru_list) {
+ WARN_ON(!warned);
+ warned = true;
DMERR("leaked buffer %llx, hold count %u, list %d",
(unsigned long long)b->block, b->hold_count, i);
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+ print_stack_trace(&b->stack_trace, 1);
+ b->hold_count = 0; /* mark unclaimed to avoid BUG_ON below */
+#endif
+ }
+
+#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
+ while ((b = __get_unclaimed_buffer(c)))
+ __free_buffer_wake(b);
+#endif
for (i = 0; i < LIST_SIZE; i++)
BUG_ON(!list_empty(&c->lru[i]));
@@ -1891,8 +1928,7 @@ static void __exit dm_bufio_exit(void)
bug = 1;
}
- if (bug)
- BUG();
+ BUG_ON(bug);
}
module_init(dm_bufio_init)
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 2fd4c82..5780acc 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -118,14 +118,12 @@ static void iot_io_end(struct io_tracker *iot, sector_t len)
*/
struct dm_hook_info {
bio_end_io_t *bi_end_io;
- void *bi_private;
};
static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
bio_end_io_t *bi_end_io, void *bi_private)
{
h->bi_end_io = bio->bi_end_io;
- h->bi_private = bio->bi_private;
bio->bi_end_io = bi_end_io;
bio->bi_private = bi_private;
@@ -134,7 +132,6 @@ static void dm_hook_bio(struct dm_hook_info *h, struct bio *bio,
static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
{
bio->bi_end_io = h->bi_end_io;
- bio->bi_private = h->bi_private;
}
/*----------------------------------------------------------------*/
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 917d47e..3147c8d 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -112,7 +112,8 @@ struct iv_tcw_private {
* and encrypts / decrypts at the same time.
*/
enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
- DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
+ DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD,
+ DM_CRYPT_EXIT_THREAD};
/*
* The fields in here must be read only after initialization.
@@ -1203,20 +1204,18 @@ continue_locked:
if (!RB_EMPTY_ROOT(&cc->write_tree))
goto pop_from_list;
+ if (unlikely(test_bit(DM_CRYPT_EXIT_THREAD, &cc->flags))) {
+ spin_unlock_irq(&cc->write_thread_wait.lock);
+ break;
+ }
+
__set_current_state(TASK_INTERRUPTIBLE);
__add_wait_queue(&cc->write_thread_wait, &wait);
spin_unlock_irq(&cc->write_thread_wait.lock);
- if (unlikely(kthread_should_stop())) {
- set_task_state(current, TASK_RUNNING);
- remove_wait_queue(&cc->write_thread_wait, &wait);
- break;
- }
-
schedule();
- set_task_state(current, TASK_RUNNING);
spin_lock_irq(&cc->write_thread_wait.lock);
__remove_wait_queue(&cc->write_thread_wait, &wait);
goto continue_locked;
@@ -1531,8 +1530,13 @@ static void crypt_dtr(struct dm_target *ti)
if (!cc)
return;
- if (cc->write_thread)
+ if (cc->write_thread) {
+ spin_lock_irq(&cc->write_thread_wait.lock);
+ set_bit(DM_CRYPT_EXIT_THREAD, &cc->flags);
+ wake_up_locked(&cc->write_thread_wait);
+ spin_unlock_irq(&cc->write_thread_wait.lock);
kthread_stop(cc->write_thread);
+ }
if (cc->io_queue)
destroy_workqueue(cc->io_queue);
diff --git a/drivers/md/dm-exception-store.h b/drivers/md/dm-exception-store.h
index fae34e7..12b5216 100644
--- a/drivers/md/dm-exception-store.h
+++ b/drivers/md/dm-exception-store.h
@@ -69,7 +69,7 @@ struct dm_exception_store_type {
* Update the metadata with this exception.
*/
void (*commit_exception) (struct dm_exception_store *store,
- struct dm_exception *e,
+ struct dm_exception *e, int valid,
void (*callback) (void *, int success),
void *callback_context);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index 81c5e1a..06d426e 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -246,7 +246,7 @@ static void vm_dp_init(struct dpages *dp, void *data)
{
dp->get_page = vm_get_page;
dp->next_page = vm_next_page;
- dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+ dp->context_u = offset_in_page(data);
dp->context_ptr = data;
}
@@ -271,7 +271,7 @@ static void km_dp_init(struct dpages *dp, void *data)
{
dp->get_page = km_get_page;
dp->next_page = km_next_page;
- dp->context_u = ((unsigned long) data) & (PAGE_SIZE - 1);
+ dp->context_u = offset_in_page(data);
dp->context_ptr = data;
}
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index aaa6caa..cfa29f5 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -1537,32 +1537,34 @@ static int multipath_prepare_ioctl(struct dm_target *ti,
struct block_device **bdev, fmode_t *mode)
{
struct multipath *m = ti->private;
- struct pgpath *pgpath;
unsigned long flags;
int r;
- r = 0;
-
spin_lock_irqsave(&m->lock, flags);
if (!m->current_pgpath)
__choose_pgpath(m, 0);
- pgpath = m->current_pgpath;
-
- if (pgpath) {
- *bdev = pgpath->path.dev->bdev;
- *mode = pgpath->path.dev->mode;
+ if (m->current_pgpath) {
+ if (!m->queue_io) {
+ *bdev = m->current_pgpath->path.dev->bdev;
+ *mode = m->current_pgpath->path.dev->mode;
+ r = 0;
+ } else {
+ /* pg_init has not started or completed */
+ r = -ENOTCONN;
+ }
+ } else {
+ /* No path is available */
+ if (m->queue_if_no_path)
+ r = -ENOTCONN;
+ else
+ r = -EIO;
}
- if ((pgpath && m->queue_io) || (!pgpath && m->queue_if_no_path))
- r = -ENOTCONN;
- else if (!*bdev)
- r = -EIO;
-
spin_unlock_irqrestore(&m->lock, flags);
- if (r == -ENOTCONN && !fatal_signal_pending(current)) {
+ if (r == -ENOTCONN) {
spin_lock_irqsave(&m->lock, flags);
if (!m->current_pg) {
/* Path status changed, redo selection */
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index 3164b8b..4d39093 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -695,7 +695,7 @@ static int persistent_prepare_exception(struct dm_exception_store *store,
}
static void persistent_commit_exception(struct dm_exception_store *store,
- struct dm_exception *e,
+ struct dm_exception *e, int valid,
void (*callback) (void *, int success),
void *callback_context)
{
@@ -704,6 +704,9 @@ static void persistent_commit_exception(struct dm_exception_store *store,
struct core_exception ce;
struct commit_callback *cb;
+ if (!valid)
+ ps->valid = 0;
+
ce.old_chunk = e->old_chunk;
ce.new_chunk = e->new_chunk;
write_exception(ps, ps->current_committed++, &ce);
diff --git a/drivers/md/dm-snap-transient.c b/drivers/md/dm-snap-transient.c
index 9b7c8c8..4d50a12 100644
--- a/drivers/md/dm-snap-transient.c
+++ b/drivers/md/dm-snap-transient.c
@@ -52,12 +52,12 @@ static int transient_prepare_exception(struct dm_exception_store *store,
}
static void transient_commit_exception(struct dm_exception_store *store,
- struct dm_exception *e,
+ struct dm_exception *e, int valid,
void (*callback) (void *, int success),
void *callback_context)
{
/* Just succeed */
- callback(callback_context, 1);
+ callback(callback_context, valid);
}
static void transient_usage(struct dm_exception_store *store,
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index c06b74e..376638608 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -207,7 +207,6 @@ struct dm_snap_pending_exception {
*/
struct bio *full_bio;
bio_end_io_t *full_bio_end_io;
- void *full_bio_private;
};
/*
@@ -1438,8 +1437,9 @@ static void __invalidate_snapshot(struct dm_snapshot *s, int err)
dm_table_event(s->ti->table);
}
-static void pending_complete(struct dm_snap_pending_exception *pe, int success)
+static void pending_complete(void *context, int success)
{
+ struct dm_snap_pending_exception *pe = context;
struct dm_exception *e;
struct dm_snapshot *s = pe->snap;
struct bio *origin_bios = NULL;
@@ -1485,10 +1485,8 @@ out:
snapshot_bios = bio_list_get(&pe->snapshot_bios);
origin_bios = bio_list_get(&pe->origin_bios);
full_bio = pe->full_bio;
- if (full_bio) {
+ if (full_bio)
full_bio->bi_end_io = pe->full_bio_end_io;
- full_bio->bi_private = pe->full_bio_private;
- }
increment_pending_exceptions_done_count();
up_write(&s->lock);
@@ -1509,24 +1507,13 @@ out:
free_pending_exception(pe);
}
-static void commit_callback(void *context, int success)
-{
- struct dm_snap_pending_exception *pe = context;
-
- pending_complete(pe, success);
-}
-
static void complete_exception(struct dm_snap_pending_exception *pe)
{
struct dm_snapshot *s = pe->snap;
- if (unlikely(pe->copy_error))
- pending_complete(pe, 0);
-
- else
- /* Update the metadata if we are persistent */
- s->store->type->commit_exception(s->store, &pe->e,
- commit_callback, pe);
+ /* Update the metadata if we are persistent */
+ s->store->type->commit_exception(s->store, &pe->e, !pe->copy_error,
+ pending_complete, pe);
}
/*
@@ -1605,7 +1592,6 @@ static void start_full_bio(struct dm_snap_pending_exception *pe,
pe->full_bio = bio;
pe->full_bio_end_io = bio->bi_end_io;
- pe->full_bio_private = bio->bi_private;
callback_data = dm_kcopyd_prepare_callback(s->kcopyd_client,
copy_callback, pe);
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 1fa4569..f962d64 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1207,6 +1207,12 @@ static int __reserve_metadata_snap(struct dm_pool_metadata *pmd)
dm_block_t held_root;
/*
+ * We commit to ensure the btree roots which we increment in a
+ * moment are up to date.
+ */
+ __commit_transaction(pmd);
+
+ /*
* Copy the superblock.
*/
dm_sm_inc_block(pmd->metadata_sm, THIN_SUPERBLOCK_LOCATION);
@@ -1389,8 +1395,21 @@ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
return td->snapshotted_time > time;
}
-int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
- int can_issue_io, struct dm_thin_lookup_result *result)
+static void unpack_lookup_result(struct dm_thin_device *td, __le64 value,
+ struct dm_thin_lookup_result *result)
+{
+ uint64_t block_time = 0;
+ dm_block_t exception_block;
+ uint32_t exception_time;
+
+ block_time = le64_to_cpu(value);
+ unpack_block_time(block_time, &exception_block, &exception_time);
+ result->block = exception_block;
+ result->shared = __snapshotted_since(td, exception_time);
+}
+
+static int __find_block(struct dm_thin_device *td, dm_block_t block,
+ int can_issue_io, struct dm_thin_lookup_result *result)
{
int r;
__le64 value;
@@ -1398,39 +1417,56 @@ int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
dm_block_t keys[2] = { td->id, block };
struct dm_btree_info *info;
- down_read(&pmd->root_lock);
- if (pmd->fail_io) {
- up_read(&pmd->root_lock);
- return -EINVAL;
- }
-
if (can_issue_io) {
info = &pmd->info;
} else
info = &pmd->nb_info;
r = dm_btree_lookup(info, pmd->root, keys, &value);
- if (!r) {
- uint64_t block_time = 0;
- dm_block_t exception_block;
- uint32_t exception_time;
-
- block_time = le64_to_cpu(value);
- unpack_block_time(block_time, &exception_block,
- &exception_time);
- result->block = exception_block;
- result->shared = __snapshotted_since(td, exception_time);
+ if (!r)
+ unpack_lookup_result(td, value, result);
+
+ return r;
+}
+
+int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
+ int can_issue_io, struct dm_thin_lookup_result *result)
+{
+ int r;
+ struct dm_pool_metadata *pmd = td->pmd;
+
+ down_read(&pmd->root_lock);
+ if (pmd->fail_io) {
+ up_read(&pmd->root_lock);
+ return -EINVAL;
}
+ r = __find_block(td, block, can_issue_io, result);
+
up_read(&pmd->root_lock);
return r;
}
-/* FIXME: write a more efficient one in btree */
-int dm_thin_find_mapped_range(struct dm_thin_device *td,
- dm_block_t begin, dm_block_t end,
- dm_block_t *thin_begin, dm_block_t *thin_end,
- dm_block_t *pool_begin, bool *maybe_shared)
+static int __find_next_mapped_block(struct dm_thin_device *td, dm_block_t block,
+ dm_block_t *vblock,
+ struct dm_thin_lookup_result *result)
+{
+ int r;
+ __le64 value;
+ struct dm_pool_metadata *pmd = td->pmd;
+ dm_block_t keys[2] = { td->id, block };
+
+ r = dm_btree_lookup_next(&pmd->info, pmd->root, keys, vblock, &value);
+ if (!r)
+ unpack_lookup_result(td, value, result);
+
+ return r;
+}
+
+static int __find_mapped_range(struct dm_thin_device *td,
+ dm_block_t begin, dm_block_t end,
+ dm_block_t *thin_begin, dm_block_t *thin_end,
+ dm_block_t *pool_begin, bool *maybe_shared)
{
int r;
dm_block_t pool_end;
@@ -1439,21 +1475,11 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
if (end < begin)
return -ENODATA;
- /*
- * Find first mapped block.
- */
- while (begin < end) {
- r = dm_thin_find_block(td, begin, true, &lookup);
- if (r) {
- if (r != -ENODATA)
- return r;
- } else
- break;
-
- begin++;
- }
+ r = __find_next_mapped_block(td, begin, &begin, &lookup);
+ if (r)
+ return r;
- if (begin == end)
+ if (begin >= end)
return -ENODATA;
*thin_begin = begin;
@@ -1463,7 +1489,7 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
begin++;
pool_end = *pool_begin + 1;
while (begin != end) {
- r = dm_thin_find_block(td, begin, true, &lookup);
+ r = __find_block(td, begin, true, &lookup);
if (r) {
if (r == -ENODATA)
break;
@@ -1483,6 +1509,24 @@ int dm_thin_find_mapped_range(struct dm_thin_device *td,
return 0;
}
+int dm_thin_find_mapped_range(struct dm_thin_device *td,
+ dm_block_t begin, dm_block_t end,
+ dm_block_t *thin_begin, dm_block_t *thin_end,
+ dm_block_t *pool_begin, bool *maybe_shared)
+{
+ int r = -EINVAL;
+ struct dm_pool_metadata *pmd = td->pmd;
+
+ down_read(&pmd->root_lock);
+ if (!pmd->fail_io) {
+ r = __find_mapped_range(td, begin, end, thin_begin, thin_end,
+ pool_begin, maybe_shared);
+ }
+ up_read(&pmd->root_lock);
+
+ return r;
+}
+
static int __insert(struct dm_thin_device *td, dm_block_t block,
dm_block_t data_block)
{
@@ -1538,7 +1582,7 @@ static int __remove(struct dm_thin_device *td, dm_block_t block)
static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_t end)
{
int r;
- unsigned count;
+ unsigned count, total_count = 0;
struct dm_pool_metadata *pmd = td->pmd;
dm_block_t keys[1] = { td->id };
__le64 value;
@@ -1561,11 +1605,29 @@ static int __remove_range(struct dm_thin_device *td, dm_block_t begin, dm_block_
if (r)
return r;
- r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
- if (r)
- return r;
+ /*
+ * Remove leaves stops at the first unmapped entry, so we have to
+ * loop round finding mapped ranges.
+ */
+ while (begin < end) {
+ r = dm_btree_lookup_next(&pmd->bl_info, mapping_root, &begin, &begin, &value);
+ if (r == -ENODATA)
+ break;
+
+ if (r)
+ return r;
+
+ if (begin >= end)
+ break;
+
+ r = dm_btree_remove_leaves(&pmd->bl_info, mapping_root, &begin, end, &mapping_root, &count);
+ if (r)
+ return r;
+
+ total_count += count;
+ }
- td->mapped_blocks -= count;
+ td->mapped_blocks -= total_count;
td->changed = 1;
/*
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 3897b90..72d91f4 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -2432,6 +2432,7 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
case PM_WRITE:
if (old_mode != new_mode)
notify_of_pool_mode_change(pool, "write");
+ pool->pf.error_if_no_space = pt->requested_pf.error_if_no_space;
dm_pool_metadata_read_write(pool->pmd);
pool->process_bio = process_bio;
pool->process_discard = process_discard_bio;
@@ -3452,8 +3453,8 @@ static void pool_postsuspend(struct dm_target *ti)
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
- cancel_delayed_work(&pool->waker);
- cancel_delayed_work(&pool->no_space_timeout);
+ cancel_delayed_work_sync(&pool->waker);
+ cancel_delayed_work_sync(&pool->no_space_timeout);
flush_workqueue(pool->wq);
(void) commit(pool);
}
@@ -3885,7 +3886,7 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 16, 0},
+ .version = {1, 17, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
@@ -4249,10 +4250,9 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
{
struct thin_c *tc = ti->private;
struct pool *pool = tc->pool;
- struct queue_limits *pool_limits = dm_get_queue_limits(pool->pool_md);
- if (!pool_limits->discard_granularity)
- return; /* pool's discard support is disabled */
+ if (!pool->pf.discard_enabled)
+ return;
limits->discard_granularity = pool->sectors_per_block << SECTOR_SHIFT;
limits->max_discard_sectors = 2048 * 1024 * 16; /* 16G */
@@ -4260,7 +4260,7 @@ static void thin_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 16, 0},
+ .version = {1, 17, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
diff --git a/drivers/md/dm-verity-fec.c b/drivers/md/dm-verity-fec.c
new file mode 100644
index 0000000..1cc10c4
--- /dev/null
+++ b/drivers/md/dm-verity-fec.c
@@ -0,0 +1,818 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include "dm-verity-fec.h"
+#include <linux/math64.h>
+
+#define DM_MSG_PREFIX "verity-fec"
+
+/*
+ * If error correction has been configured, returns true.
+ */
+bool verity_fec_is_enabled(struct dm_verity *v)
+{
+ return v->fec && v->fec->dev;
+}
+
+/*
+ * Return a pointer to dm_verity_fec_io after dm_verity_io and its variable
+ * length fields.
+ */
+static inline struct dm_verity_fec_io *fec_io(struct dm_verity_io *io)
+{
+ return (struct dm_verity_fec_io *) verity_io_digest_end(io->v, io);
+}
+
+/*
+ * Return an interleaved offset for a byte in RS block.
+ */
+static inline u64 fec_interleave(struct dm_verity *v, u64 offset)
+{
+ u32 mod;
+
+ mod = do_div(offset, v->fec->rsn);
+ return offset + mod * (v->fec->rounds << v->data_dev_block_bits);
+}
+
+/*
+ * Decode an RS block using Reed-Solomon.
+ */
+static int fec_decode_rs8(struct dm_verity *v, struct dm_verity_fec_io *fio,
+ u8 *data, u8 *fec, int neras)
+{
+ int i;
+ uint16_t par[DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN];
+
+ for (i = 0; i < v->fec->roots; i++)
+ par[i] = fec[i];
+
+ return decode_rs8(fio->rs, data, par, v->fec->rsn, NULL, neras,
+ fio->erasures, 0, NULL);
+}
+
+/*
+ * Read error-correcting codes for the requested RS block. Returns a pointer
+ * to the data block. Caller is responsible for releasing buf.
+ */
+static u8 *fec_read_parity(struct dm_verity *v, u64 rsb, int index,
+ unsigned *offset, struct dm_buffer **buf)
+{
+ u64 position, block;
+ u8 *res;
+
+ position = (index + rsb) * v->fec->roots;
+ block = position >> v->data_dev_block_bits;
+ *offset = (unsigned)(position - (block << v->data_dev_block_bits));
+
+ res = dm_bufio_read(v->fec->bufio, v->fec->start + block, buf);
+ if (unlikely(IS_ERR(res))) {
+ DMERR("%s: FEC %llu: parity read failed (block %llu): %ld",
+ v->data_dev->name, (unsigned long long)rsb,
+ (unsigned long long)(v->fec->start + block),
+ PTR_ERR(res));
+ *buf = NULL;
+ }
+
+ return res;
+}
+
+/* Loop over each preallocated buffer slot. */
+#define fec_for_each_prealloc_buffer(__i) \
+ for (__i = 0; __i < DM_VERITY_FEC_BUF_PREALLOC; __i++)
+
+/* Loop over each extra buffer slot. */
+#define fec_for_each_extra_buffer(io, __i) \
+ for (__i = DM_VERITY_FEC_BUF_PREALLOC; __i < DM_VERITY_FEC_BUF_MAX; __i++)
+
+/* Loop over each allocated buffer. */
+#define fec_for_each_buffer(io, __i) \
+ for (__i = 0; __i < (io)->nbufs; __i++)
+
+/* Loop over each RS block in each allocated buffer. */
+#define fec_for_each_buffer_rs_block(io, __i, __j) \
+ fec_for_each_buffer(io, __i) \
+ for (__j = 0; __j < 1 << DM_VERITY_FEC_BUF_RS_BITS; __j++)
+
+/*
+ * Return a pointer to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline u8 *fec_buffer_rs_block(struct dm_verity *v,
+ struct dm_verity_fec_io *fio,
+ unsigned i, unsigned j)
+{
+ return &fio->bufs[i][j * v->fec->rsn];
+}
+
+/*
+ * Return an index to the current RS block when called inside
+ * fec_for_each_buffer_rs_block.
+ */
+static inline unsigned fec_buffer_rs_index(unsigned i, unsigned j)
+{
+ return (i << DM_VERITY_FEC_BUF_RS_BITS) + j;
+}
+
+/*
+ * Decode all RS blocks from buffers and copy corrected bytes into fio->output
+ * starting from block_offset.
+ */
+static int fec_decode_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio,
+ u64 rsb, int byte_index, unsigned block_offset,
+ int neras)
+{
+ int r, corrected = 0, res;
+ struct dm_buffer *buf;
+ unsigned n, i, offset;
+ u8 *par, *block;
+
+ par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+ if (IS_ERR(par))
+ return PTR_ERR(par);
+
+ /*
+ * Decode the RS blocks we have in bufs. Each RS block results in
+ * one corrected target byte and consumes fec->roots parity bytes.
+ */
+ fec_for_each_buffer_rs_block(fio, n, i) {
+ block = fec_buffer_rs_block(v, fio, n, i);
+ res = fec_decode_rs8(v, fio, block, &par[offset], neras);
+ if (res < 0) {
+ dm_bufio_release(buf);
+
+ r = res;
+ goto error;
+ }
+
+ corrected += res;
+ fio->output[block_offset] = block[byte_index];
+
+ block_offset++;
+ if (block_offset >= 1 << v->data_dev_block_bits)
+ goto done;
+
+ /* read the next block when we run out of parity bytes */
+ offset += v->fec->roots;
+ if (offset >= 1 << v->data_dev_block_bits) {
+ dm_bufio_release(buf);
+
+ par = fec_read_parity(v, rsb, block_offset, &offset, &buf);
+ if (unlikely(IS_ERR(par)))
+ return PTR_ERR(par);
+ }
+ }
+done:
+ r = corrected;
+error:
+ if (r < 0 && neras)
+ DMERR_LIMIT("%s: FEC %llu: failed to correct: %d",
+ v->data_dev->name, (unsigned long long)rsb, r);
+ else if (r > 0)
+ DMWARN_LIMIT("%s: FEC %llu: corrected %d errors",
+ v->data_dev->name, (unsigned long long)rsb, r);
+
+ return r;
+}
+
+/*
+ * Locate data block erasures using verity hashes.
+ */
+static int fec_is_erasure(struct dm_verity *v, struct dm_verity_io *io,
+ u8 *want_digest, u8 *data)
+{
+ if (unlikely(verity_hash(v, verity_io_hash_desc(v, io),
+ data, 1 << v->data_dev_block_bits,
+ verity_io_real_digest(v, io))))
+ return 0;
+
+ return memcmp(verity_io_real_digest(v, io), want_digest,
+ v->digest_size) != 0;
+}
+
+/*
+ * Read data blocks that are part of the RS block and deinterleave as much as
+ * fits into buffers. Check for erasure locations if @neras is non-NULL.
+ */
+static int fec_read_bufs(struct dm_verity *v, struct dm_verity_io *io,
+ u64 rsb, u64 target, unsigned block_offset,
+ int *neras)
+{
+ bool is_zero;
+ int i, j, target_index = -1;
+ struct dm_buffer *buf;
+ struct dm_bufio_client *bufio;
+ struct dm_verity_fec_io *fio = fec_io(io);
+ u64 block, ileaved;
+ u8 *bbuf, *rs_block;
+ u8 want_digest[v->digest_size];
+ unsigned n, k;
+
+ if (neras)
+ *neras = 0;
+
+ /*
+ * read each of the rsn data blocks that are part of the RS block, and
+ * interleave contents to available bufs
+ */
+ for (i = 0; i < v->fec->rsn; i++) {
+ ileaved = fec_interleave(v, rsb * v->fec->rsn + i);
+
+ /*
+ * target is the data block we want to correct, target_index is
+ * the index of this block within the rsn RS blocks
+ */
+ if (ileaved == target)
+ target_index = i;
+
+ block = ileaved >> v->data_dev_block_bits;
+ bufio = v->fec->data_bufio;
+
+ if (block >= v->data_blocks) {
+ block -= v->data_blocks;
+
+ /*
+ * blocks outside the area were assumed to contain
+ * zeros when encoding data was generated
+ */
+ if (unlikely(block >= v->fec->hash_blocks))
+ continue;
+
+ block += v->hash_start;
+ bufio = v->bufio;
+ }
+
+ bbuf = dm_bufio_read(bufio, block, &buf);
+ if (unlikely(IS_ERR(bbuf))) {
+ DMWARN_LIMIT("%s: FEC %llu: read failed (%llu): %ld",
+ v->data_dev->name,
+ (unsigned long long)rsb,
+ (unsigned long long)block, PTR_ERR(bbuf));
+
+ /* assume the block is corrupted */
+ if (neras && *neras <= v->fec->roots)
+ fio->erasures[(*neras)++] = i;
+
+ continue;
+ }
+
+ /* locate erasures if the block is on the data device */
+ if (bufio == v->fec->data_bufio &&
+ verity_hash_for_block(v, io, block, want_digest,
+ &is_zero) == 0) {
+ /* skip known zero blocks entirely */
+ if (is_zero)
+ continue;
+
+ /*
+ * skip if we have already found the theoretical
+ * maximum number (i.e. fec->roots) of erasures
+ */
+ if (neras && *neras <= v->fec->roots &&
+ fec_is_erasure(v, io, want_digest, bbuf))
+ fio->erasures[(*neras)++] = i;
+ }
+
+ /*
+ * deinterleave and copy the bytes that fit into bufs,
+ * starting from block_offset
+ */
+ fec_for_each_buffer_rs_block(fio, n, j) {
+ k = fec_buffer_rs_index(n, j) + block_offset;
+
+ if (k >= 1 << v->data_dev_block_bits)
+ goto done;
+
+ rs_block = fec_buffer_rs_block(v, fio, n, j);
+ rs_block[i] = bbuf[k];
+ }
+done:
+ dm_bufio_release(buf);
+ }
+
+ return target_index;
+}
+
+/*
+ * Allocate RS control structure and FEC buffers from preallocated mempools,
+ * and attempt to allocate as many extra buffers as available.
+ */
+static int fec_alloc_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+ unsigned n;
+
+ if (!fio->rs) {
+ fio->rs = mempool_alloc(v->fec->rs_pool, 0);
+ if (unlikely(!fio->rs)) {
+ DMERR("failed to allocate RS");
+ return -ENOMEM;
+ }
+ }
+
+ fec_for_each_prealloc_buffer(n) {
+ if (fio->bufs[n])
+ continue;
+
+ fio->bufs[n] = mempool_alloc(v->fec->prealloc_pool, GFP_NOIO);
+ if (unlikely(!fio->bufs[n])) {
+ DMERR("failed to allocate FEC buffer");
+ return -ENOMEM;
+ }
+ }
+
+ /* try to allocate the maximum number of buffers */
+ fec_for_each_extra_buffer(fio, n) {
+ if (fio->bufs[n])
+ continue;
+
+ fio->bufs[n] = mempool_alloc(v->fec->extra_pool, GFP_NOIO);
+ /* we can manage with even one buffer if necessary */
+ if (unlikely(!fio->bufs[n]))
+ break;
+ }
+ fio->nbufs = n;
+
+ if (!fio->output) {
+ fio->output = mempool_alloc(v->fec->output_pool, GFP_NOIO);
+
+ if (!fio->output) {
+ DMERR("failed to allocate FEC page");
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize buffers and clear erasures. fec_read_bufs() assumes buffers are
+ * zeroed before deinterleaving.
+ */
+static void fec_init_bufs(struct dm_verity *v, struct dm_verity_fec_io *fio)
+{
+ unsigned n;
+
+ fec_for_each_buffer(fio, n)
+ memset(fio->bufs[n], 0, v->fec->rsn << DM_VERITY_FEC_BUF_RS_BITS);
+
+ memset(fio->erasures, 0, sizeof(fio->erasures));
+}
+
+/*
+ * Decode all RS blocks in a single data block and return the target block
+ * (indicated by @offset) in fio->output. If @use_erasures is non-zero, uses
+ * hashes to locate erasures.
+ */
+static int fec_decode_rsb(struct dm_verity *v, struct dm_verity_io *io,
+ struct dm_verity_fec_io *fio, u64 rsb, u64 offset,
+ bool use_erasures)
+{
+ int r, neras = 0;
+ unsigned pos;
+
+ r = fec_alloc_bufs(v, fio);
+ if (unlikely(r < 0))
+ return r;
+
+ for (pos = 0; pos < 1 << v->data_dev_block_bits; ) {
+ fec_init_bufs(v, fio);
+
+ r = fec_read_bufs(v, io, rsb, offset, pos,
+ use_erasures ? &neras : NULL);
+ if (unlikely(r < 0))
+ return r;
+
+ r = fec_decode_bufs(v, fio, rsb, r, pos, neras);
+ if (r < 0)
+ return r;
+
+ pos += fio->nbufs << DM_VERITY_FEC_BUF_RS_BITS;
+ }
+
+ /* Always re-validate the corrected block against the expected hash */
+ r = verity_hash(v, verity_io_hash_desc(v, io), fio->output,
+ 1 << v->data_dev_block_bits,
+ verity_io_real_digest(v, io));
+ if (unlikely(r < 0))
+ return r;
+
+ if (memcmp(verity_io_real_digest(v, io), verity_io_want_digest(v, io),
+ v->digest_size)) {
+ DMERR_LIMIT("%s: FEC %llu: failed to correct (%d erasures)",
+ v->data_dev->name, (unsigned long long)rsb, neras);
+ return -EILSEQ;
+ }
+
+ return 0;
+}
+
+static int fec_bv_copy(struct dm_verity *v, struct dm_verity_io *io, u8 *data,
+ size_t len)
+{
+ struct dm_verity_fec_io *fio = fec_io(io);
+
+ memcpy(data, &fio->output[fio->output_pos], len);
+ fio->output_pos += len;
+
+ return 0;
+}
+
+/*
+ * Correct errors in a block. Copies corrected block to dest if non-NULL,
+ * otherwise to a bio_vec starting from iter.
+ */
+int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+ enum verity_block_type type, sector_t block, u8 *dest,
+ struct bvec_iter *iter)
+{
+ int r;
+ struct dm_verity_fec_io *fio = fec_io(io);
+ u64 offset, res, rsb;
+
+ if (!verity_fec_is_enabled(v))
+ return -EOPNOTSUPP;
+
+ if (type == DM_VERITY_BLOCK_TYPE_METADATA)
+ block += v->data_blocks;
+
+ /*
+ * For RS(M, N), the continuous FEC data is divided into blocks of N
+ * bytes. Since block size may not be divisible by N, the last block
+ * is zero padded when decoding.
+ *
+ * Each byte of the block is covered by a different RS(M, N) code,
+ * and each code is interleaved over N blocks to make it less likely
+ * that bursty corruption will leave us in unrecoverable state.
+ */
+
+ offset = block << v->data_dev_block_bits;
+
+ res = offset;
+ div64_u64(res, v->fec->rounds << v->data_dev_block_bits);
+
+ /*
+ * The base RS block we can feed to the interleaver to find out all
+ * blocks required for decoding.
+ */
+ rsb = offset - res * (v->fec->rounds << v->data_dev_block_bits);
+
+ /*
+ * Locating erasures is slow, so attempt to recover the block without
+ * them first. Do a second attempt with erasures if the corruption is
+ * bad enough.
+ */
+ r = fec_decode_rsb(v, io, fio, rsb, offset, false);
+ if (r < 0) {
+ r = fec_decode_rsb(v, io, fio, rsb, offset, true);
+ if (r < 0)
+ return r;
+ }
+
+ if (dest)
+ memcpy(dest, fio->output, 1 << v->data_dev_block_bits);
+ else if (iter) {
+ fio->output_pos = 0;
+ r = verity_for_bv_block(v, io, iter, fec_bv_copy);
+ }
+
+ return r;
+}
+
+/*
+ * Clean up per-bio data.
+ */
+void verity_fec_finish_io(struct dm_verity_io *io)
+{
+ unsigned n;
+ struct dm_verity_fec *f = io->v->fec;
+ struct dm_verity_fec_io *fio = fec_io(io);
+
+ if (!verity_fec_is_enabled(io->v))
+ return;
+
+ mempool_free(fio->rs, f->rs_pool);
+
+ fec_for_each_prealloc_buffer(n)
+ mempool_free(fio->bufs[n], f->prealloc_pool);
+
+ fec_for_each_extra_buffer(fio, n)
+ mempool_free(fio->bufs[n], f->extra_pool);
+
+ mempool_free(fio->output, f->output_pool);
+}
+
+/*
+ * Initialize per-bio data.
+ */
+void verity_fec_init_io(struct dm_verity_io *io)
+{
+ struct dm_verity_fec_io *fio = fec_io(io);
+
+ if (!verity_fec_is_enabled(io->v))
+ return;
+
+ fio->rs = NULL;
+ memset(fio->bufs, 0, sizeof(fio->bufs));
+ fio->nbufs = 0;
+ fio->output = NULL;
+}
+
+/*
+ * Append feature arguments and values to the status table.
+ */
+unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+ char *result, unsigned maxlen)
+{
+ if (!verity_fec_is_enabled(v))
+ return sz;
+
+ DMEMIT(" " DM_VERITY_OPT_FEC_DEV " %s "
+ DM_VERITY_OPT_FEC_BLOCKS " %llu "
+ DM_VERITY_OPT_FEC_START " %llu "
+ DM_VERITY_OPT_FEC_ROOTS " %d",
+ v->fec->dev->name,
+ (unsigned long long)v->fec->blocks,
+ (unsigned long long)v->fec->start,
+ v->fec->roots);
+
+ return sz;
+}
+
+void verity_fec_dtr(struct dm_verity *v)
+{
+ struct dm_verity_fec *f = v->fec;
+
+ if (!verity_fec_is_enabled(v))
+ goto out;
+
+ mempool_destroy(f->rs_pool);
+ mempool_destroy(f->prealloc_pool);
+ mempool_destroy(f->extra_pool);
+ kmem_cache_destroy(f->cache);
+
+ if (f->data_bufio)
+ dm_bufio_client_destroy(f->data_bufio);
+ if (f->bufio)
+ dm_bufio_client_destroy(f->bufio);
+
+ if (f->dev)
+ dm_put_device(v->ti, f->dev);
+out:
+ kfree(f);
+ v->fec = NULL;
+}
+
+static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data)
+{
+ struct dm_verity *v = (struct dm_verity *)pool_data;
+
+ return init_rs(8, 0x11d, 0, 1, v->fec->roots);
+}
+
+static void fec_rs_free(void *element, void *pool_data)
+{
+ struct rs_control *rs = (struct rs_control *)element;
+
+ if (rs)
+ free_rs(rs);
+}
+
+bool verity_is_fec_opt_arg(const char *arg_name)
+{
+ return (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV) ||
+ !strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS) ||
+ !strcasecmp(arg_name, DM_VERITY_OPT_FEC_START) ||
+ !strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS));
+}
+
+int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
+ unsigned *argc, const char *arg_name)
+{
+ int r;
+ struct dm_target *ti = v->ti;
+ const char *arg_value;
+ unsigned long long num_ll;
+ unsigned char num_c;
+ char dummy;
+
+ if (!*argc) {
+ ti->error = "FEC feature arguments require a value";
+ return -EINVAL;
+ }
+
+ arg_value = dm_shift_arg(as);
+ (*argc)--;
+
+ if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) {
+ r = dm_get_device(ti, arg_value, FMODE_READ, &v->fec->dev);
+ if (r) {
+ ti->error = "FEC device lookup failed";
+ return r;
+ }
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_BLOCKS)) {
+ if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+ ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT))
+ >> (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+ ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+ return -EINVAL;
+ }
+ v->fec->blocks = num_ll;
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_START)) {
+ if (sscanf(arg_value, "%llu%c", &num_ll, &dummy) != 1 ||
+ ((sector_t)(num_ll << (v->data_dev_block_bits - SECTOR_SHIFT)) >>
+ (v->data_dev_block_bits - SECTOR_SHIFT) != num_ll)) {
+ ti->error = "Invalid " DM_VERITY_OPT_FEC_START;
+ return -EINVAL;
+ }
+ v->fec->start = num_ll;
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_ROOTS)) {
+ if (sscanf(arg_value, "%hhu%c", &num_c, &dummy) != 1 || !num_c ||
+ num_c < (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MAX_RSN) ||
+ num_c > (DM_VERITY_FEC_RSM - DM_VERITY_FEC_MIN_RSN)) {
+ ti->error = "Invalid " DM_VERITY_OPT_FEC_ROOTS;
+ return -EINVAL;
+ }
+ v->fec->roots = num_c;
+
+ } else {
+ ti->error = "Unrecognized verity FEC feature request";
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Allocate dm_verity_fec for v->fec. Must be called before verity_fec_ctr.
+ */
+int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+ struct dm_verity_fec *f;
+
+ f = kzalloc(sizeof(struct dm_verity_fec), GFP_KERNEL);
+ if (!f) {
+ v->ti->error = "Cannot allocate FEC structure";
+ return -ENOMEM;
+ }
+ v->fec = f;
+
+ return 0;
+}
+
+/*
+ * Validate arguments and preallocate memory. Must be called after arguments
+ * have been parsed using verity_fec_parse_opt_args.
+ */
+int verity_fec_ctr(struct dm_verity *v)
+{
+ struct dm_verity_fec *f = v->fec;
+ struct dm_target *ti = v->ti;
+ u64 hash_blocks;
+
+ if (!verity_fec_is_enabled(v)) {
+ verity_fec_dtr(v);
+ return 0;
+ }
+
+ /*
+ * FEC is computed over data blocks, possible metadata, and
+ * hash blocks. In other words, FEC covers total of fec_blocks
+ * blocks consisting of the following:
+ *
+ * data blocks | hash blocks | metadata (optional)
+ *
+ * We allow metadata after hash blocks to support a use case
+ * where all data is stored on the same device and FEC covers
+ * the entire area.
+ *
+ * If metadata is included, we require it to be available on the
+ * hash device after the hash blocks.
+ */
+
+ hash_blocks = v->hash_blocks - v->hash_start;
+
+ /*
+ * Require matching block sizes for data and hash devices for
+ * simplicity.
+ */
+ if (v->data_dev_block_bits != v->hash_dev_block_bits) {
+ ti->error = "Block sizes must match to use FEC";
+ return -EINVAL;
+ }
+
+ if (!f->roots) {
+ ti->error = "Missing " DM_VERITY_OPT_FEC_ROOTS;
+ return -EINVAL;
+ }
+ f->rsn = DM_VERITY_FEC_RSM - f->roots;
+
+ if (!f->blocks) {
+ ti->error = "Missing " DM_VERITY_OPT_FEC_BLOCKS;
+ return -EINVAL;
+ }
+
+ f->rounds = f->blocks;
+ if (sector_div(f->rounds, f->rsn))
+ f->rounds++;
+
+ /*
+ * Due to optional metadata, f->blocks can be larger than
+ * data_blocks and hash_blocks combined.
+ */
+ if (f->blocks < v->data_blocks + hash_blocks || !f->rounds) {
+ ti->error = "Invalid " DM_VERITY_OPT_FEC_BLOCKS;
+ return -EINVAL;
+ }
+
+ /*
+ * Metadata is accessed through the hash device, so we require
+ * it to be large enough.
+ */
+ f->hash_blocks = f->blocks - v->data_blocks;
+ if (dm_bufio_get_device_size(v->bufio) < f->hash_blocks) {
+ ti->error = "Hash device is too small for "
+ DM_VERITY_OPT_FEC_BLOCKS;
+ return -E2BIG;
+ }
+
+ f->bufio = dm_bufio_client_create(f->dev->bdev,
+ 1 << v->data_dev_block_bits,
+ 1, 0, NULL, NULL);
+ if (IS_ERR(f->bufio)) {
+ ti->error = "Cannot initialize FEC bufio client";
+ return PTR_ERR(f->bufio);
+ }
+
+ if (dm_bufio_get_device_size(f->bufio) <
+ ((f->start + f->rounds * f->roots) >> v->data_dev_block_bits)) {
+ ti->error = "FEC device is too small";
+ return -E2BIG;
+ }
+
+ f->data_bufio = dm_bufio_client_create(v->data_dev->bdev,
+ 1 << v->data_dev_block_bits,
+ 1, 0, NULL, NULL);
+ if (IS_ERR(f->data_bufio)) {
+ ti->error = "Cannot initialize FEC data bufio client";
+ return PTR_ERR(f->data_bufio);
+ }
+
+ if (dm_bufio_get_device_size(f->data_bufio) < v->data_blocks) {
+ ti->error = "Data device is too small";
+ return -E2BIG;
+ }
+
+ /* Preallocate an rs_control structure for each worker thread */
+ f->rs_pool = mempool_create(num_online_cpus(), fec_rs_alloc,
+ fec_rs_free, (void *) v);
+ if (!f->rs_pool) {
+ ti->error = "Cannot allocate RS pool";
+ return -ENOMEM;
+ }
+
+ f->cache = kmem_cache_create("dm_verity_fec_buffers",
+ f->rsn << DM_VERITY_FEC_BUF_RS_BITS,
+ 0, 0, NULL);
+ if (!f->cache) {
+ ti->error = "Cannot create FEC buffer cache";
+ return -ENOMEM;
+ }
+
+ /* Preallocate DM_VERITY_FEC_BUF_PREALLOC buffers for each thread */
+ f->prealloc_pool = mempool_create_slab_pool(num_online_cpus() *
+ DM_VERITY_FEC_BUF_PREALLOC,
+ f->cache);
+ if (!f->prealloc_pool) {
+ ti->error = "Cannot allocate FEC buffer prealloc pool";
+ return -ENOMEM;
+ }
+
+ f->extra_pool = mempool_create_slab_pool(0, f->cache);
+ if (!f->extra_pool) {
+ ti->error = "Cannot allocate FEC buffer extra pool";
+ return -ENOMEM;
+ }
+
+ /* Preallocate an output buffer for each thread */
+ f->output_pool = mempool_create_kmalloc_pool(num_online_cpus(),
+ 1 << v->data_dev_block_bits);
+ if (!f->output_pool) {
+ ti->error = "Cannot allocate FEC output pool";
+ return -ENOMEM;
+ }
+
+ /* Reserve space for our per-bio data */
+ ti->per_bio_data_size += sizeof(struct dm_verity_fec_io);
+
+ return 0;
+}
diff --git a/drivers/md/dm-verity-fec.h b/drivers/md/dm-verity-fec.h
new file mode 100644
index 0000000..7fa0298
--- /dev/null
+++ b/drivers/md/dm-verity-fec.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Sami Tolvanen <samitolvanen@google.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#ifndef DM_VERITY_FEC_H
+#define DM_VERITY_FEC_H
+
+#include "dm-verity.h"
+#include <linux/rslib.h>
+
+/* Reed-Solomon(M, N) parameters */
+#define DM_VERITY_FEC_RSM 255
+#define DM_VERITY_FEC_MAX_RSN 253
+#define DM_VERITY_FEC_MIN_RSN 231 /* ~10% space overhead */
+
+/* buffers for deinterleaving and decoding */
+#define DM_VERITY_FEC_BUF_PREALLOC 1 /* buffers to preallocate */
+#define DM_VERITY_FEC_BUF_RS_BITS 4 /* 1 << RS blocks per buffer */
+/* we need buffers for at most 1 << block size RS blocks */
+#define DM_VERITY_FEC_BUF_MAX \
+ (1 << (PAGE_SHIFT - DM_VERITY_FEC_BUF_RS_BITS))
+
+#define DM_VERITY_OPT_FEC_DEV "use_fec_from_device"
+#define DM_VERITY_OPT_FEC_BLOCKS "fec_blocks"
+#define DM_VERITY_OPT_FEC_START "fec_start"
+#define DM_VERITY_OPT_FEC_ROOTS "fec_roots"
+
+/* configuration */
+struct dm_verity_fec {
+ struct dm_dev *dev; /* parity data device */
+ struct dm_bufio_client *data_bufio; /* for data dev access */
+ struct dm_bufio_client *bufio; /* for parity data access */
+ sector_t start; /* parity data start in blocks */
+ sector_t blocks; /* number of blocks covered */
+ sector_t rounds; /* number of interleaving rounds */
+ sector_t hash_blocks; /* blocks covered after v->hash_start */
+ unsigned char roots; /* number of parity bytes, M-N of RS(M, N) */
+ unsigned char rsn; /* N of RS(M, N) */
+ mempool_t *rs_pool; /* mempool for fio->rs */
+ mempool_t *prealloc_pool; /* mempool for preallocated buffers */
+ mempool_t *extra_pool; /* mempool for extra buffers */
+ mempool_t *output_pool; /* mempool for output */
+ struct kmem_cache *cache; /* cache for buffers */
+};
+
+/* per-bio data */
+struct dm_verity_fec_io {
+ struct rs_control *rs; /* Reed-Solomon state */
+ int erasures[DM_VERITY_FEC_MAX_RSN]; /* erasures for decode_rs8 */
+ u8 *bufs[DM_VERITY_FEC_BUF_MAX]; /* bufs for deinterleaving */
+ unsigned nbufs; /* number of buffers allocated */
+ u8 *output; /* buffer for corrected output */
+ size_t output_pos;
+};
+
+#ifdef CONFIG_DM_VERITY_FEC
+
+/* each feature parameter requires a value */
+#define DM_VERITY_OPTS_FEC 8
+
+extern bool verity_fec_is_enabled(struct dm_verity *v);
+
+extern int verity_fec_decode(struct dm_verity *v, struct dm_verity_io *io,
+ enum verity_block_type type, sector_t block,
+ u8 *dest, struct bvec_iter *iter);
+
+extern unsigned verity_fec_status_table(struct dm_verity *v, unsigned sz,
+ char *result, unsigned maxlen);
+
+extern void verity_fec_finish_io(struct dm_verity_io *io);
+extern void verity_fec_init_io(struct dm_verity_io *io);
+
+extern bool verity_is_fec_opt_arg(const char *arg_name);
+extern int verity_fec_parse_opt_args(struct dm_arg_set *as,
+ struct dm_verity *v, unsigned *argc,
+ const char *arg_name);
+
+extern void verity_fec_dtr(struct dm_verity *v);
+
+extern int verity_fec_ctr_alloc(struct dm_verity *v);
+extern int verity_fec_ctr(struct dm_verity *v);
+
+#else /* !CONFIG_DM_VERITY_FEC */
+
+#define DM_VERITY_OPTS_FEC 0
+
+static inline bool verity_fec_is_enabled(struct dm_verity *v)
+{
+ return false;
+}
+
+static inline int verity_fec_decode(struct dm_verity *v,
+ struct dm_verity_io *io,
+ enum verity_block_type type,
+ sector_t block, u8 *dest,
+ struct bvec_iter *iter)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline unsigned verity_fec_status_table(struct dm_verity *v,
+ unsigned sz, char *result,
+ unsigned maxlen)
+{
+ return sz;
+}
+
+static inline void verity_fec_finish_io(struct dm_verity_io *io)
+{
+}
+
+static inline void verity_fec_init_io(struct dm_verity_io *io)
+{
+}
+
+static inline bool verity_is_fec_opt_arg(const char *arg_name)
+{
+ return false;
+}
+
+static inline int verity_fec_parse_opt_args(struct dm_arg_set *as,
+ struct dm_verity *v,
+ unsigned *argc,
+ const char *arg_name)
+{
+ return -EINVAL;
+}
+
+static inline void verity_fec_dtr(struct dm_verity *v)
+{
+}
+
+static inline int verity_fec_ctr_alloc(struct dm_verity *v)
+{
+ return 0;
+}
+
+static inline int verity_fec_ctr(struct dm_verity *v)
+{
+ return 0;
+}
+
+#endif /* CONFIG_DM_VERITY_FEC */
+
+#endif /* DM_VERITY_FEC_H */
diff --git a/drivers/md/dm-verity.c b/drivers/md/dm-verity-target.c
index ccf4188..5c5d30c 100644
--- a/drivers/md/dm-verity.c
+++ b/drivers/md/dm-verity-target.c
@@ -14,12 +14,11 @@
* access behavior.
*/
-#include "dm-bufio.h"
+#include "dm-verity.h"
+#include "dm-verity-fec.h"
#include <linux/module.h>
-#include <linux/device-mapper.h>
#include <linux/reboot.h>
-#include <crypto/hash.h>
#define DM_MSG_PREFIX "verity"
@@ -28,83 +27,18 @@
#define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144
-#define DM_VERITY_MAX_LEVELS 63
#define DM_VERITY_MAX_CORRUPTED_ERRS 100
#define DM_VERITY_OPT_LOGGING "ignore_corruption"
#define DM_VERITY_OPT_RESTART "restart_on_corruption"
+#define DM_VERITY_OPT_IGN_ZEROES "ignore_zero_blocks"
+
+#define DM_VERITY_OPTS_MAX (2 + DM_VERITY_OPTS_FEC)
static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
-enum verity_mode {
- DM_VERITY_MODE_EIO,
- DM_VERITY_MODE_LOGGING,
- DM_VERITY_MODE_RESTART
-};
-
-enum verity_block_type {
- DM_VERITY_BLOCK_TYPE_DATA,
- DM_VERITY_BLOCK_TYPE_METADATA
-};
-
-struct dm_verity {
- struct dm_dev *data_dev;
- struct dm_dev *hash_dev;
- struct dm_target *ti;
- struct dm_bufio_client *bufio;
- char *alg_name;
- struct crypto_shash *tfm;
- u8 *root_digest; /* digest of the root block */
- u8 *salt; /* salt: its size is salt_size */
- unsigned salt_size;
- sector_t data_start; /* data offset in 512-byte sectors */
- sector_t hash_start; /* hash start in blocks */
- sector_t data_blocks; /* the number of data blocks */
- sector_t hash_blocks; /* the number of hash blocks */
- unsigned char data_dev_block_bits; /* log2(data blocksize) */
- unsigned char hash_dev_block_bits; /* log2(hash blocksize) */
- unsigned char hash_per_block_bits; /* log2(hashes in hash block) */
- unsigned char levels; /* the number of tree levels */
- unsigned char version;
- unsigned digest_size; /* digest size for the current hash algorithm */
- unsigned shash_descsize;/* the size of temporary space for crypto */
- int hash_failed; /* set to 1 if hash of any block failed */
- enum verity_mode mode; /* mode for handling verification errors */
- unsigned corrupted_errs;/* Number of errors for corrupted blocks */
-
- struct workqueue_struct *verify_wq;
-
- /* starting blocks for each tree level. 0 is the lowest level. */
- sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
-};
-
-struct dm_verity_io {
- struct dm_verity *v;
-
- /* original values of bio->bi_end_io and bio->bi_private */
- bio_end_io_t *orig_bi_end_io;
- void *orig_bi_private;
-
- sector_t block;
- unsigned n_blocks;
-
- struct bvec_iter iter;
-
- struct work_struct work;
-
- /*
- * Three variably-size fields follow this struct:
- *
- * u8 hash_desc[v->shash_descsize];
- * u8 real_digest[v->digest_size];
- * u8 want_digest[v->digest_size];
- *
- * To access them use: io_hash_desc(), io_real_digest() and io_want_digest().
- */
-};
-
struct dm_verity_prefetch_work {
struct work_struct work;
struct dm_verity *v;
@@ -112,21 +46,6 @@ struct dm_verity_prefetch_work {
unsigned n_blocks;
};
-static struct shash_desc *io_hash_desc(struct dm_verity *v, struct dm_verity_io *io)
-{
- return (struct shash_desc *)(io + 1);
-}
-
-static u8 *io_real_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
- return (u8 *)(io + 1) + v->shash_descsize;
-}
-
-static u8 *io_want_digest(struct dm_verity *v, struct dm_verity_io *io)
-{
- return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
-}
-
/*
* Auxiliary structure appended to each dm-bufio buffer. If the value
* hash_verified is nonzero, hash of the block has been verified.
@@ -173,6 +92,84 @@ static sector_t verity_position_at_level(struct dm_verity *v, sector_t block,
return block >> (level * v->hash_per_block_bits);
}
+/*
+ * Wrapper for crypto_shash_init, which handles verity salting.
+ */
+static int verity_hash_init(struct dm_verity *v, struct shash_desc *desc)
+{
+ int r;
+
+ desc->tfm = v->tfm;
+ desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ r = crypto_shash_init(desc);
+
+ if (unlikely(r < 0)) {
+ DMERR("crypto_shash_init failed: %d", r);
+ return r;
+ }
+
+ if (likely(v->version >= 1)) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+ if (unlikely(r < 0)) {
+ DMERR("crypto_shash_update failed: %d", r);
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+static int verity_hash_update(struct dm_verity *v, struct shash_desc *desc,
+ const u8 *data, size_t len)
+{
+ int r = crypto_shash_update(desc, data, len);
+
+ if (unlikely(r < 0))
+ DMERR("crypto_shash_update failed: %d", r);
+
+ return r;
+}
+
+static int verity_hash_final(struct dm_verity *v, struct shash_desc *desc,
+ u8 *digest)
+{
+ int r;
+
+ if (unlikely(!v->version)) {
+ r = crypto_shash_update(desc, v->salt, v->salt_size);
+
+ if (r < 0) {
+ DMERR("crypto_shash_update failed: %d", r);
+ return r;
+ }
+ }
+
+ r = crypto_shash_final(desc, digest);
+
+ if (unlikely(r < 0))
+ DMERR("crypto_shash_final failed: %d", r);
+
+ return r;
+}
+
+int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+ const u8 *data, size_t len, u8 *digest)
+{
+ int r;
+
+ r = verity_hash_init(v, desc);
+ if (unlikely(r < 0))
+ return r;
+
+ r = verity_hash_update(v, desc, data, len);
+ if (unlikely(r < 0))
+ return r;
+
+ return verity_hash_final(v, desc, digest);
+}
+
static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
sector_t *hash_block, unsigned *offset)
{
@@ -246,17 +243,17 @@ out:
* Verify hash of a metadata block pertaining to the specified data block
* ("block" argument) at a specified level ("level" argument).
*
- * On successful return, io_want_digest(v, io) contains the hash value for
- * a lower tree level or for the data block (if we're at the lowest leve).
+ * On successful return, verity_io_want_digest(v, io) contains the hash value
+ * for a lower tree level or for the data block (if we're at the lowest level).
*
* If "skip_unverified" is true, unverified buffer is skipped and 1 is returned.
* If "skip_unverified" is false, unverified buffer is hashed and verified
- * against current value of io_want_digest(v, io).
+ * against current value of verity_io_want_digest(v, io).
*/
-static int verity_verify_level(struct dm_verity_io *io, sector_t block,
- int level, bool skip_unverified)
+static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
+ sector_t block, int level, bool skip_unverified,
+ u8 *want_digest)
{
- struct dm_verity *v = io->v;
struct dm_buffer *buf;
struct buffer_aux *aux;
u8 *data;
@@ -273,72 +270,128 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block,
aux = dm_bufio_get_aux_data(buf);
if (!aux->hash_verified) {
- struct shash_desc *desc;
- u8 *result;
-
if (skip_unverified) {
r = 1;
goto release_ret_r;
}
- desc = io_hash_desc(v, io);
- desc->tfm = v->tfm;
- desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- r = crypto_shash_init(desc);
- if (r < 0) {
- DMERR("crypto_shash_init failed: %d", r);
+ r = verity_hash(v, verity_io_hash_desc(v, io),
+ data, 1 << v->hash_dev_block_bits,
+ verity_io_real_digest(v, io));
+ if (unlikely(r < 0))
goto release_ret_r;
- }
-
- if (likely(v->version >= 1)) {
- r = crypto_shash_update(desc, v->salt, v->salt_size);
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
- goto release_ret_r;
- }
- }
- r = crypto_shash_update(desc, data, 1 << v->hash_dev_block_bits);
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
+ if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
+ v->digest_size) == 0))
+ aux->hash_verified = 1;
+ else if (verity_fec_decode(v, io,
+ DM_VERITY_BLOCK_TYPE_METADATA,
+ hash_block, data, NULL) == 0)
+ aux->hash_verified = 1;
+ else if (verity_handle_err(v,
+ DM_VERITY_BLOCK_TYPE_METADATA,
+ hash_block)) {
+ r = -EIO;
goto release_ret_r;
}
+ }
- if (!v->version) {
- r = crypto_shash_update(desc, v->salt, v->salt_size);
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
- goto release_ret_r;
- }
- }
+ data += offset;
+ memcpy(want_digest, data, v->digest_size);
+ r = 0;
- result = io_real_digest(v, io);
- r = crypto_shash_final(desc, result);
- if (r < 0) {
- DMERR("crypto_shash_final failed: %d", r);
- goto release_ret_r;
- }
- if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
- if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA,
- hash_block)) {
- r = -EIO;
- goto release_ret_r;
- }
- } else
- aux->hash_verified = 1;
+release_ret_r:
+ dm_bufio_release(buf);
+ return r;
+}
+
+/*
+ * Find a hash for a given block, write it to digest and verify the integrity
+ * of the hash tree if necessary.
+ */
+int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+ sector_t block, u8 *digest, bool *is_zero)
+{
+ int r = 0, i;
+
+ if (likely(v->levels)) {
+ /*
+ * First, we try to get the requested hash for
+ * the current block. If the hash block itself is
+ * verified, zero is returned. If it isn't, this
+ * function returns 1 and we fall back to whole
+ * chain verification.
+ */
+ r = verity_verify_level(v, io, block, 0, true, digest);
+ if (likely(r <= 0))
+ goto out;
}
- data += offset;
+ memcpy(digest, v->root_digest, v->digest_size);
- memcpy(io_want_digest(v, io), data, v->digest_size);
+ for (i = v->levels - 1; i >= 0; i--) {
+ r = verity_verify_level(v, io, block, i, false, digest);
+ if (unlikely(r))
+ goto out;
+ }
+out:
+ if (!r && v->zero_digest)
+ *is_zero = !memcmp(v->zero_digest, digest, v->digest_size);
+ else
+ *is_zero = false;
+
+ return r;
+}
+
+/*
+ * Calls function process for 1 << v->data_dev_block_bits bytes in the bio_vec
+ * starting from iter.
+ */
+int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+ struct bvec_iter *iter,
+ int (*process)(struct dm_verity *v,
+ struct dm_verity_io *io, u8 *data,
+ size_t len))
+{
+ unsigned todo = 1 << v->data_dev_block_bits;
+ struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
+
+ do {
+ int r;
+ u8 *page;
+ unsigned len;
+ struct bio_vec bv = bio_iter_iovec(bio, *iter);
+
+ page = kmap_atomic(bv.bv_page);
+ len = bv.bv_len;
+
+ if (likely(len >= todo))
+ len = todo;
+
+ r = process(v, io, page + bv.bv_offset, len);
+ kunmap_atomic(page);
+
+ if (r < 0)
+ return r;
+
+ bio_advance_iter(bio, iter, len);
+ todo -= len;
+ } while (todo);
- dm_bufio_release(buf);
return 0;
+}
-release_ret_r:
- dm_bufio_release(buf);
+static int verity_bv_hash_update(struct dm_verity *v, struct dm_verity_io *io,
+ u8 *data, size_t len)
+{
+ return verity_hash_update(v, verity_io_hash_desc(v, io), data, len);
+}
- return r;
+static int verity_bv_zero(struct dm_verity *v, struct dm_verity_io *io,
+ u8 *data, size_t len)
+{
+ memset(data, 0, len);
+ return 0;
}
/*
@@ -346,99 +399,56 @@ release_ret_r:
*/
static int verity_verify_io(struct dm_verity_io *io)
{
+ bool is_zero;
struct dm_verity *v = io->v;
- struct bio *bio = dm_bio_from_per_bio_data(io,
- v->ti->per_bio_data_size);
+ struct bvec_iter start;
unsigned b;
- int i;
for (b = 0; b < io->n_blocks; b++) {
- struct shash_desc *desc;
- u8 *result;
int r;
- unsigned todo;
+ struct shash_desc *desc = verity_io_hash_desc(v, io);
+
+ r = verity_hash_for_block(v, io, io->block + b,
+ verity_io_want_digest(v, io),
+ &is_zero);
+ if (unlikely(r < 0))
+ return r;
- if (likely(v->levels)) {
+ if (is_zero) {
/*
- * First, we try to get the requested hash for
- * the current block. If the hash block itself is
- * verified, zero is returned. If it isn't, this
- * function returns 0 and we fall back to whole
- * chain verification.
+ * If we expect a zero block, don't validate, just
+ * return zeros.
*/
- int r = verity_verify_level(io, io->block + b, 0, true);
- if (likely(!r))
- goto test_block_hash;
- if (r < 0)
+ r = verity_for_bv_block(v, io, &io->iter,
+ verity_bv_zero);
+ if (unlikely(r < 0))
return r;
- }
- memcpy(io_want_digest(v, io), v->root_digest, v->digest_size);
-
- for (i = v->levels - 1; i >= 0; i--) {
- int r = verity_verify_level(io, io->block + b, i, false);
- if (unlikely(r))
- return r;
+ continue;
}
-test_block_hash:
- desc = io_hash_desc(v, io);
- desc->tfm = v->tfm;
- desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- r = crypto_shash_init(desc);
- if (r < 0) {
- DMERR("crypto_shash_init failed: %d", r);
+ r = verity_hash_init(v, desc);
+ if (unlikely(r < 0))
return r;
- }
-
- if (likely(v->version >= 1)) {
- r = crypto_shash_update(desc, v->salt, v->salt_size);
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
- return r;
- }
- }
- todo = 1 << v->data_dev_block_bits;
- do {
- u8 *page;
- unsigned len;
- struct bio_vec bv = bio_iter_iovec(bio, io->iter);
-
- page = kmap_atomic(bv.bv_page);
- len = bv.bv_len;
- if (likely(len >= todo))
- len = todo;
- r = crypto_shash_update(desc, page + bv.bv_offset, len);
- kunmap_atomic(page);
-
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
- return r;
- }
-
- bio_advance_iter(bio, &io->iter, len);
- todo -= len;
- } while (todo);
- if (!v->version) {
- r = crypto_shash_update(desc, v->salt, v->salt_size);
- if (r < 0) {
- DMERR("crypto_shash_update failed: %d", r);
- return r;
- }
- }
+ start = io->iter;
+ r = verity_for_bv_block(v, io, &io->iter, verity_bv_hash_update);
+ if (unlikely(r < 0))
+ return r;
- result = io_real_digest(v, io);
- r = crypto_shash_final(desc, result);
- if (r < 0) {
- DMERR("crypto_shash_final failed: %d", r);
+ r = verity_hash_final(v, desc, verity_io_real_digest(v, io));
+ if (unlikely(r < 0))
return r;
- }
- if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
- if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
- io->block + b))
- return -EIO;
- }
+
+ if (likely(memcmp(verity_io_real_digest(v, io),
+ verity_io_want_digest(v, io), v->digest_size) == 0))
+ continue;
+ else if (verity_fec_decode(v, io, DM_VERITY_BLOCK_TYPE_DATA,
+ io->block + b, NULL, &start) == 0)
+ continue;
+ else if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
+ io->block + b))
+ return -EIO;
}
return 0;
@@ -453,9 +463,10 @@ static void verity_finish_io(struct dm_verity_io *io, int error)
struct bio *bio = dm_bio_from_per_bio_data(io, v->ti->per_bio_data_size);
bio->bi_end_io = io->orig_bi_end_io;
- bio->bi_private = io->orig_bi_private;
bio->bi_error = error;
+ verity_fec_finish_io(io);
+
bio_endio(bio);
}
@@ -470,7 +481,7 @@ static void verity_end_io(struct bio *bio)
{
struct dm_verity_io *io = bio->bi_private;
- if (bio->bi_error) {
+ if (bio->bi_error && !verity_fec_is_enabled(io->v)) {
verity_finish_io(io, bio->bi_error);
return;
}
@@ -566,7 +577,6 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
io = dm_per_bio_data(bio, ti->per_bio_data_size);
io->v = v;
io->orig_bi_end_io = bio->bi_end_io;
- io->orig_bi_private = bio->bi_private;
io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
@@ -574,6 +584,8 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
bio->bi_private = io;
io->iter = bio->bi_iter;
+ verity_fec_init_io(io);
+
verity_submit_prefetch(v, io);
generic_make_request(bio);
@@ -588,6 +600,7 @@ static void verity_status(struct dm_target *ti, status_type_t type,
unsigned status_flags, char *result, unsigned maxlen)
{
struct dm_verity *v = ti->private;
+ unsigned args = 0;
unsigned sz = 0;
unsigned x;
@@ -614,8 +627,17 @@ static void verity_status(struct dm_target *ti, status_type_t type,
else
for (x = 0; x < v->salt_size; x++)
DMEMIT("%02x", v->salt[x]);
+ if (v->mode != DM_VERITY_MODE_EIO)
+ args++;
+ if (verity_fec_is_enabled(v))
+ args += DM_VERITY_OPTS_FEC;
+ if (v->zero_digest)
+ args++;
+ if (!args)
+ return;
+ DMEMIT(" %u", args);
if (v->mode != DM_VERITY_MODE_EIO) {
- DMEMIT(" 1 ");
+ DMEMIT(" ");
switch (v->mode) {
case DM_VERITY_MODE_LOGGING:
DMEMIT(DM_VERITY_OPT_LOGGING);
@@ -627,6 +649,9 @@ static void verity_status(struct dm_target *ti, status_type_t type,
BUG();
}
}
+ if (v->zero_digest)
+ DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
+ sz = verity_fec_status_table(v, sz, result, maxlen);
break;
}
}
@@ -677,6 +702,7 @@ static void verity_dtr(struct dm_target *ti)
kfree(v->salt);
kfree(v->root_digest);
+ kfree(v->zero_digest);
if (v->tfm)
crypto_free_shash(v->tfm);
@@ -689,9 +715,94 @@ static void verity_dtr(struct dm_target *ti)
if (v->data_dev)
dm_put_device(ti, v->data_dev);
+ verity_fec_dtr(v);
+
kfree(v);
}
+static int verity_alloc_zero_digest(struct dm_verity *v)
+{
+ int r = -ENOMEM;
+ struct shash_desc *desc;
+ u8 *zero_data;
+
+ v->zero_digest = kmalloc(v->digest_size, GFP_KERNEL);
+
+ if (!v->zero_digest)
+ return r;
+
+ desc = kmalloc(v->shash_descsize, GFP_KERNEL);
+
+ if (!desc)
+ return r; /* verity_dtr will free zero_digest */
+
+ zero_data = kzalloc(1 << v->data_dev_block_bits, GFP_KERNEL);
+
+ if (!zero_data)
+ goto out;
+
+ r = verity_hash(v, desc, zero_data, 1 << v->data_dev_block_bits,
+ v->zero_digest);
+
+out:
+ kfree(desc);
+ kfree(zero_data);
+
+ return r;
+}
+
+static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v)
+{
+ int r;
+ unsigned argc;
+ struct dm_target *ti = v->ti;
+ const char *arg_name;
+
+ static struct dm_arg _args[] = {
+ {0, DM_VERITY_OPTS_MAX, "Invalid number of feature args"},
+ };
+
+ r = dm_read_arg_group(_args, as, &argc, &ti->error);
+ if (r)
+ return -EINVAL;
+
+ if (!argc)
+ return 0;
+
+ do {
+ arg_name = dm_shift_arg(as);
+ argc--;
+
+ if (!strcasecmp(arg_name, DM_VERITY_OPT_LOGGING)) {
+ v->mode = DM_VERITY_MODE_LOGGING;
+ continue;
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_RESTART)) {
+ v->mode = DM_VERITY_MODE_RESTART;
+ continue;
+
+ } else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
+ r = verity_alloc_zero_digest(v);
+ if (r) {
+ ti->error = "Cannot allocate zero digest";
+ return r;
+ }
+ continue;
+
+ } else if (verity_is_fec_opt_arg(arg_name)) {
+ r = verity_fec_parse_opt_args(as, v, &argc, arg_name);
+ if (r)
+ return r;
+ continue;
+ }
+
+ ti->error = "Unrecognized verity feature request";
+ return -EINVAL;
+ } while (argc && !r);
+
+ return r;
+}
+
/*
* Target parameters:
* <version> The current format is version 1.
@@ -710,18 +821,13 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
{
struct dm_verity *v;
struct dm_arg_set as;
- const char *opt_string;
- unsigned int num, opt_params;
+ unsigned int num;
unsigned long long num_ll;
int r;
int i;
sector_t hash_position;
char dummy;
- static struct dm_arg _args[] = {
- {0, 1, "Invalid number of feature args"},
- };
-
v = kzalloc(sizeof(struct dm_verity), GFP_KERNEL);
if (!v) {
ti->error = "Cannot allocate verity structure";
@@ -730,6 +836,10 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->private = v;
v->ti = ti;
+ r = verity_fec_ctr_alloc(v);
+ if (r)
+ goto bad;
+
if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) {
ti->error = "Device must be readonly";
r = -EINVAL;
@@ -866,29 +976,9 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
as.argc = argc;
as.argv = argv;
- r = dm_read_arg_group(_args, &as, &opt_params, &ti->error);
- if (r)
+ r = verity_parse_opt_args(&as, v);
+ if (r < 0)
goto bad;
-
- while (opt_params) {
- opt_params--;
- opt_string = dm_shift_arg(&as);
- if (!opt_string) {
- ti->error = "Not enough feature arguments";
- r = -EINVAL;
- goto bad;
- }
-
- if (!strcasecmp(opt_string, DM_VERITY_OPT_LOGGING))
- v->mode = DM_VERITY_MODE_LOGGING;
- else if (!strcasecmp(opt_string, DM_VERITY_OPT_RESTART))
- v->mode = DM_VERITY_MODE_RESTART;
- else {
- ti->error = "Invalid feature arguments";
- r = -EINVAL;
- goto bad;
- }
- }
}
v->hash_per_block_bits =
@@ -938,8 +1028,6 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
- ti->per_bio_data_size = roundup(sizeof(struct dm_verity_io) + v->shash_descsize + v->digest_size * 2, __alignof__(struct dm_verity_io));
-
/* WQ_UNBOUND greatly improves performance when running on ramdisk */
v->verify_wq = alloc_workqueue("kverityd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND, num_online_cpus());
if (!v->verify_wq) {
@@ -948,6 +1036,16 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
goto bad;
}
+ ti->per_bio_data_size = sizeof(struct dm_verity_io) +
+ v->shash_descsize + v->digest_size * 2;
+
+ r = verity_fec_ctr(v);
+ if (r)
+ goto bad;
+
+ ti->per_bio_data_size = roundup(ti->per_bio_data_size,
+ __alignof__(struct dm_verity_io));
+
return 0;
bad:
@@ -958,7 +1056,7 @@ bad:
static struct target_type verity_target = {
.name = "verity",
- .version = {1, 2, 0},
+ .version = {1, 3, 0},
.module = THIS_MODULE,
.ctr = verity_ctr,
.dtr = verity_dtr,
diff --git a/drivers/md/dm-verity.h b/drivers/md/dm-verity.h
new file mode 100644
index 0000000..fb419f4
--- /dev/null
+++ b/drivers/md/dm-verity.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc.
+ * Copyright (C) 2015 Google, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ *
+ * This file is released under the GPLv2.
+ */
+
+#ifndef DM_VERITY_H
+#define DM_VERITY_H
+
+#include "dm-bufio.h"
+#include <linux/device-mapper.h>
+#include <crypto/hash.h>
+
+#define DM_VERITY_MAX_LEVELS 63
+
+enum verity_mode {
+ DM_VERITY_MODE_EIO,
+ DM_VERITY_MODE_LOGGING,
+ DM_VERITY_MODE_RESTART
+};
+
+enum verity_block_type {
+ DM_VERITY_BLOCK_TYPE_DATA,
+ DM_VERITY_BLOCK_TYPE_METADATA
+};
+
+struct dm_verity_fec;
+
+struct dm_verity {
+ struct dm_dev *data_dev;
+ struct dm_dev *hash_dev;
+ struct dm_target *ti;
+ struct dm_bufio_client *bufio;
+ char *alg_name;
+ struct crypto_shash *tfm;
+ u8 *root_digest; /* digest of the root block */
+ u8 *salt; /* salt: its size is salt_size */
+ u8 *zero_digest; /* digest for a zero block */
+ unsigned salt_size;
+ sector_t data_start; /* data offset in 512-byte sectors */
+ sector_t hash_start; /* hash start in blocks */
+ sector_t data_blocks; /* the number of data blocks */
+ sector_t hash_blocks; /* the number of hash blocks */
+ unsigned char data_dev_block_bits; /* log2(data blocksize) */
+ unsigned char hash_dev_block_bits; /* log2(hash blocksize) */
+ unsigned char hash_per_block_bits; /* log2(hashes in hash block) */
+ unsigned char levels; /* the number of tree levels */
+ unsigned char version;
+ unsigned digest_size; /* digest size for the current hash algorithm */
+ unsigned shash_descsize;/* the size of temporary space for crypto */
+ int hash_failed; /* set to 1 if hash of any block failed */
+ enum verity_mode mode; /* mode for handling verification errors */
+ unsigned corrupted_errs;/* Number of errors for corrupted blocks */
+
+ struct workqueue_struct *verify_wq;
+
+ /* starting blocks for each tree level. 0 is the lowest level. */
+ sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+
+ struct dm_verity_fec *fec; /* forward error correction */
+};
+
+struct dm_verity_io {
+ struct dm_verity *v;
+
+ /* original value of bio->bi_end_io */
+ bio_end_io_t *orig_bi_end_io;
+
+ sector_t block;
+ unsigned n_blocks;
+
+ struct bvec_iter iter;
+
+ struct work_struct work;
+
+ /*
+ * Three variably-size fields follow this struct:
+ *
+ * u8 hash_desc[v->shash_descsize];
+ * u8 real_digest[v->digest_size];
+ * u8 want_digest[v->digest_size];
+ *
+ * To access them use: verity_io_hash_desc(), verity_io_real_digest()
+ * and verity_io_want_digest().
+ */
+};
+
+static inline struct shash_desc *verity_io_hash_desc(struct dm_verity *v,
+ struct dm_verity_io *io)
+{
+ return (struct shash_desc *)(io + 1);
+}
+
+static inline u8 *verity_io_real_digest(struct dm_verity *v,
+ struct dm_verity_io *io)
+{
+ return (u8 *)(io + 1) + v->shash_descsize;
+}
+
+static inline u8 *verity_io_want_digest(struct dm_verity *v,
+ struct dm_verity_io *io)
+{
+ return (u8 *)(io + 1) + v->shash_descsize + v->digest_size;
+}
+
+static inline u8 *verity_io_digest_end(struct dm_verity *v,
+ struct dm_verity_io *io)
+{
+ return verity_io_want_digest(v, io) + v->digest_size;
+}
+
+extern int verity_for_bv_block(struct dm_verity *v, struct dm_verity_io *io,
+ struct bvec_iter *iter,
+ int (*process)(struct dm_verity *v,
+ struct dm_verity_io *io,
+ u8 *data, size_t len));
+
+extern int verity_hash(struct dm_verity *v, struct shash_desc *desc,
+ const u8 *data, size_t len, u8 *digest);
+
+extern int verity_hash_for_block(struct dm_verity *v, struct dm_verity_io *io,
+ sector_t block, u8 *digest, bool *is_zero);
+
+#endif /* DM_VERITY_H */
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 32440ad..5df4048 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -591,7 +591,7 @@ retry:
out:
dm_put_live_table(md, *srcu_idx);
- if (r == -ENOTCONN) {
+ if (r == -ENOTCONN && !fatal_signal_pending(current)) {
msleep(10);
goto retry;
}
@@ -603,9 +603,10 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
{
struct mapped_device *md = bdev->bd_disk->private_data;
struct dm_target *tgt;
+ struct block_device *tgt_bdev = NULL;
int srcu_idx, r;
- r = dm_get_live_table_for_ioctl(md, &tgt, &bdev, &mode, &srcu_idx);
+ r = dm_get_live_table_for_ioctl(md, &tgt, &tgt_bdev, &mode, &srcu_idx);
if (r < 0)
return r;
@@ -620,7 +621,7 @@ static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode,
goto out;
}
- r = __blkdev_driver_ioctl(bdev, mode, cmd, arg);
+ r = __blkdev_driver_ioctl(tgt_bdev, mode, cmd, arg);
out:
dm_put_live_table(md, srcu_idx);
return r;
@@ -1755,7 +1756,7 @@ static void __split_and_process_bio(struct mapped_device *md,
* The request function that just remaps the bio built up by
* dm_merge_bvec.
*/
-static void dm_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t dm_make_request(struct request_queue *q, struct bio *bio)
{
int rw = bio_data_dir(bio);
struct mapped_device *md = q->queuedata;
@@ -1774,12 +1775,12 @@ static void dm_make_request(struct request_queue *q, struct bio *bio)
queue_io(md, bio);
else
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
__split_and_process_bio(md, map, bio);
dm_put_live_table(md, srcu_idx);
- return;
+ return BLK_QC_T_NONE;
}
int dm_request_based(struct mapped_device *md)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 3f9a514..61aacab 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -250,7 +250,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
* call has finished, the bio has been linked into some internal structure
* and so is visible to ->quiesce(), so we don't need the refcount any more.
*/
-static void md_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t md_make_request(struct request_queue *q, struct bio *bio)
{
const int rw = bio_data_dir(bio);
struct mddev *mddev = q->queuedata;
@@ -262,13 +262,13 @@ static void md_make_request(struct request_queue *q, struct bio *bio)
if (mddev == NULL || mddev->pers == NULL
|| !mddev->ready) {
bio_io_error(bio);
- return;
+ return BLK_QC_T_NONE;
}
if (mddev->ro == 1 && unlikely(rw == WRITE)) {
if (bio_sectors(bio) != 0)
bio->bi_error = -EROFS;
bio_endio(bio);
- return;
+ return BLK_QC_T_NONE;
}
smp_rmb(); /* Ensure implications of 'active' are visible */
rcu_read_lock();
@@ -302,6 +302,8 @@ static void md_make_request(struct request_queue *q, struct bio *bio)
if (atomic_dec_and_test(&mddev->active_io) && mddev->suspended)
wake_up(&mddev->sb_wait);
+
+ return BLK_QC_T_NONE;
}
/* mddev_suspend makes sure no new requests are submitted
@@ -312,8 +314,8 @@ static void md_make_request(struct request_queue *q, struct bio *bio)
*/
void mddev_suspend(struct mddev *mddev)
{
- BUG_ON(mddev->suspended);
- mddev->suspended = 1;
+ if (mddev->suspended++)
+ return;
synchronize_rcu();
wait_event(mddev->sb_wait, atomic_read(&mddev->active_io) == 0);
mddev->pers->quiesce(mddev, 1);
@@ -324,7 +326,8 @@ EXPORT_SYMBOL_GPL(mddev_suspend);
void mddev_resume(struct mddev *mddev)
{
- mddev->suspended = 0;
+ if (--mddev->suspended)
+ return;
wake_up(&mddev->sb_wait);
mddev->pers->quiesce(mddev, 0);
@@ -1650,7 +1653,7 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
rdev->journal_tail = le64_to_cpu(sb->journal_tail);
if (mddev->recovery_cp == MaxSector)
set_bit(MD_JOURNAL_CLEAN, &mddev->flags);
- rdev->raid_disk = mddev->raid_disks;
+ rdev->raid_disk = 0;
break;
default:
rdev->saved_raid_disk = role;
@@ -2771,6 +2774,7 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
/* Activating a spare .. or possibly reactivating
* if we ever get bitmaps working here.
*/
+ int err;
if (rdev->raid_disk != -1)
return -EBUSY;
@@ -2792,9 +2796,15 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
rdev->saved_raid_disk = -1;
clear_bit(In_sync, &rdev->flags);
clear_bit(Bitmap_sync, &rdev->flags);
- remove_and_add_spares(rdev->mddev, rdev);
- if (rdev->raid_disk == -1)
- return -EBUSY;
+ err = rdev->mddev->pers->
+ hot_add_disk(rdev->mddev, rdev);
+ if (err) {
+ rdev->raid_disk = -1;
+ return err;
+ } else
+ sysfs_notify_dirent_safe(rdev->sysfs_state);
+ if (sysfs_link_rdev(rdev->mddev, rdev))
+ /* failure here is OK */;
/* don't wakeup anyone, leave that to userspace. */
} else {
if (slot >= rdev->mddev->raid_disks &&
@@ -4316,8 +4326,7 @@ action_store(struct mddev *mddev, const char *page, size_t len)
}
mddev_unlock(mddev);
}
- } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
- test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+ } else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
return -EBUSY;
else if (cmd_match(page, "resync"))
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
@@ -4330,8 +4339,12 @@ action_store(struct mddev *mddev, const char *page, size_t len)
return -EINVAL;
err = mddev_lock(mddev);
if (!err) {
- clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
- err = mddev->pers->start_reshape(mddev);
+ if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
+ err = -EBUSY;
+ else {
+ clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
+ err = mddev->pers->start_reshape(mddev);
+ }
mddev_unlock(mddev);
}
if (err)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 2bea51e..ca0b643 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -566,7 +566,9 @@ static inline char * mdname (struct mddev * mddev)
static inline int sysfs_link_rdev(struct mddev *mddev, struct md_rdev *rdev)
{
char nm[20];
- if (!test_bit(Replacement, &rdev->flags) && mddev->kobj.sd) {
+ if (!test_bit(Replacement, &rdev->flags) &&
+ !test_bit(Journal, &rdev->flags) &&
+ mddev->kobj.sd) {
sprintf(nm, "rd%d", rdev->raid_disk);
return sysfs_create_link(&mddev->kobj, &rdev->kobj, nm);
} else
@@ -576,7 +578,9 @@ static inline int sysfs_link_rdev(struct mddev *mddev, struct md_rdev *rdev)
static inline void sysfs_unlink_rdev(struct mddev *mddev, struct md_rdev *rdev)
{
char nm[20];
- if (!test_bit(Replacement, &rdev->flags) && mddev->kobj.sd) {
+ if (!test_bit(Replacement, &rdev->flags) &&
+ !test_bit(Journal, &rdev->flags) &&
+ mddev->kobj.sd) {
sprintf(nm, "rd%d", rdev->raid_disk);
sysfs_remove_link(&mddev->kobj, nm);
}
diff --git a/drivers/md/persistent-data/Kconfig b/drivers/md/persistent-data/Kconfig
index 78c74bb..a53cbc9 100644
--- a/drivers/md/persistent-data/Kconfig
+++ b/drivers/md/persistent-data/Kconfig
@@ -7,12 +7,3 @@ config DM_PERSISTENT_DATA
Library providing immutable on-disk data structure support for
device-mapper targets such as the thin provisioning target.
-config DM_DEBUG_BLOCK_STACK_TRACING
- bool "Keep stack trace of persistent data block lock holders"
- depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
- select STACKTRACE
- ---help---
- Enable this for messages that may help debug problems with the
- block manager locking used by thin provisioning and caching.
-
- If unsure, say N.
diff --git a/drivers/md/persistent-data/dm-block-manager.c b/drivers/md/persistent-data/dm-block-manager.c
index f2393ba..1e33dd5 100644
--- a/drivers/md/persistent-data/dm-block-manager.c
+++ b/drivers/md/persistent-data/dm-block-manager.c
@@ -97,10 +97,6 @@ static void __del_holder(struct block_lock *lock, struct task_struct *task)
static int __check_holder(struct block_lock *lock)
{
unsigned i;
-#ifdef CONFIG_DM_DEBUG_BLOCK_STACK_TRACING
- static struct stack_trace t;
- static stack_entries entries;
-#endif
for (i = 0; i < MAX_HOLDERS; i++) {
if (lock->holders[i] == current) {
@@ -110,12 +106,7 @@ static int __check_holder(struct block_lock *lock)
print_stack_trace(lock->traces + i, 4);
DMERR("subsequent acquisition attempted here:");
- t.nr_entries = 0;
- t.max_entries = MAX_STACK;
- t.entries = entries;
- t.skip = 3;
- save_stack_trace(&t);
- print_stack_trace(&t, 4);
+ dump_stack();
#endif
return -EINVAL;
}
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c
index c573402..ea3d3b6 100644
--- a/drivers/md/persistent-data/dm-btree.c
+++ b/drivers/md/persistent-data/dm-btree.c
@@ -63,6 +63,11 @@ int lower_bound(struct btree_node *n, uint64_t key)
return bsearch(n, key, 0);
}
+static int upper_bound(struct btree_node *n, uint64_t key)
+{
+ return bsearch(n, key, 1);
+}
+
void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
struct dm_btree_value_type *vt)
{
@@ -252,6 +257,16 @@ static void pop_frame(struct del_stack *s)
dm_tm_unlock(s->tm, f->b);
}
+static void unlock_all_frames(struct del_stack *s)
+{
+ struct frame *f;
+
+ while (unprocessed_frames(s)) {
+ f = s->spine + s->top--;
+ dm_tm_unlock(s->tm, f->b);
+ }
+}
+
int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
{
int r;
@@ -308,9 +323,13 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
pop_frame(s);
}
}
-
out:
+ if (r) {
+ /* cleanup all frames of del_stack */
+ unlock_all_frames(s);
+ }
kfree(s);
+
return r;
}
EXPORT_SYMBOL_GPL(dm_btree_del);
@@ -392,6 +411,82 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
}
EXPORT_SYMBOL_GPL(dm_btree_lookup);
+static int dm_btree_lookup_next_single(struct dm_btree_info *info, dm_block_t root,
+ uint64_t key, uint64_t *rkey, void *value_le)
+{
+ int r, i;
+ uint32_t flags, nr_entries;
+ struct dm_block *node;
+ struct btree_node *n;
+
+ r = bn_read_lock(info, root, &node);
+ if (r)
+ return r;
+
+ n = dm_block_data(node);
+ flags = le32_to_cpu(n->header.flags);
+ nr_entries = le32_to_cpu(n->header.nr_entries);
+
+ if (flags & INTERNAL_NODE) {
+ i = lower_bound(n, key);
+ if (i < 0 || i >= nr_entries) {
+ r = -ENODATA;
+ goto out;
+ }
+
+ r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le);
+ if (r == -ENODATA && i < (nr_entries - 1)) {
+ i++;
+ r = dm_btree_lookup_next_single(info, value64(n, i), key, rkey, value_le);
+ }
+
+ } else {
+ i = upper_bound(n, key);
+ if (i < 0 || i >= nr_entries) {
+ r = -ENODATA;
+ goto out;
+ }
+
+ *rkey = le64_to_cpu(n->keys[i]);
+ memcpy(value_le, value_ptr(n, i), info->value_type.size);
+ }
+out:
+ dm_tm_unlock(info->tm, node);
+ return r;
+}
+
+int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
+ uint64_t *keys, uint64_t *rkey, void *value_le)
+{
+ unsigned level;
+ int r = -ENODATA;
+ __le64 internal_value_le;
+ struct ro_spine spine;
+
+ init_ro_spine(&spine, info);
+ for (level = 0; level < info->levels - 1u; level++) {
+ r = btree_lookup_raw(&spine, root, keys[level],
+ lower_bound, rkey,
+ &internal_value_le, sizeof(uint64_t));
+ if (r)
+ goto out;
+
+ if (*rkey != keys[level]) {
+ r = -ENODATA;
+ goto out;
+ }
+
+ root = le64_to_cpu(internal_value_le);
+ }
+
+ r = dm_btree_lookup_next_single(info, root, keys[level], rkey, value_le);
+out:
+ exit_ro_spine(&spine);
+ return r;
+}
+
+EXPORT_SYMBOL_GPL(dm_btree_lookup_next);
+
/*
* Splits a node by creating a sibling node and shifting half the nodes
* contents across. Assumes there is a parent node, and it has room for
@@ -473,8 +568,10 @@ static int btree_split_sibling(struct shadow_spine *s, unsigned parent_index,
r = insert_at(sizeof(__le64), pn, parent_index + 1,
le64_to_cpu(rn->keys[0]), &location);
- if (r)
+ if (r) {
+ unlock_block(s->info, right);
return r;
+ }
if (key < le64_to_cpu(rn->keys[0])) {
unlock_block(s->info, right);
@@ -657,12 +754,19 @@ static int btree_insert_raw(struct shadow_spine *s, dm_block_t root,
return 0;
}
+static bool need_insert(struct btree_node *node, uint64_t *keys,
+ unsigned level, unsigned index)
+{
+ return ((index >= le32_to_cpu(node->header.nr_entries)) ||
+ (le64_to_cpu(node->keys[index]) != keys[level]));
+}
+
static int insert(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value, dm_block_t *new_root,
int *inserted)
__dm_written_to_disk(value)
{
- int r, need_insert;
+ int r;
unsigned level, index = -1, last_level = info->levels - 1;
dm_block_t block = root;
struct shadow_spine spine;
@@ -678,10 +782,8 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
goto bad;
n = dm_block_data(shadow_current(&spine));
- need_insert = ((index >= le32_to_cpu(n->header.nr_entries)) ||
- (le64_to_cpu(n->keys[index]) != keys[level]));
- if (need_insert) {
+ if (need_insert(n, keys, level, index)) {
dm_block_t new_tree;
__le64 new_le;
@@ -708,10 +810,8 @@ static int insert(struct dm_btree_info *info, dm_block_t root,
goto bad;
n = dm_block_data(shadow_current(&spine));
- need_insert = ((index >= le32_to_cpu(n->header.nr_entries)) ||
- (le64_to_cpu(n->keys[index]) != keys[level]));
- if (need_insert) {
+ if (need_insert(n, keys, level, index)) {
if (inserted)
*inserted = 1;
diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h
index 11d8cf7..c74301f 100644
--- a/drivers/md/persistent-data/dm-btree.h
+++ b/drivers/md/persistent-data/dm-btree.h
@@ -110,6 +110,13 @@ int dm_btree_lookup(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, void *value_le);
/*
+ * Tries to find the first key where the bottom level key is >= to that
+ * given. Useful for skipping empty sections of the btree.
+ */
+int dm_btree_lookup_next(struct dm_btree_info *info, dm_block_t root,
+ uint64_t *keys, uint64_t *rkey, void *value_le);
+
+/*
* Insertion (or overwrite an existing value). O(ln(n))
*/
int dm_btree_insert(struct dm_btree_info *info, dm_block_t root,
@@ -135,9 +142,10 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, dm_block_t *new_root);
/*
- * Removes values between 'keys' and keys2, where keys2 is keys with the
- * final key replaced with 'end_key'. 'end_key' is the one-past-the-end
- * value. 'keys' may be altered.
+ * Removes a _contiguous_ run of values starting from 'keys' and not
+ * reaching keys2 (where keys2 is keys with the final key replaced with
+ * 'end_key'). 'end_key' is the one-past-the-end value. 'keys' may be
+ * altered.
*/
int dm_btree_remove_leaves(struct dm_btree_info *info, dm_block_t root,
uint64_t *keys, uint64_t end_key,
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 5309129..7e44005 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -136,7 +136,7 @@ static int brb_push(struct bop_ring_buffer *brb,
return 0;
}
-static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
+static int brb_peek(struct bop_ring_buffer *brb, struct block_op *result)
{
struct block_op *bop;
@@ -147,6 +147,14 @@ static int brb_pop(struct bop_ring_buffer *brb, struct block_op *result)
result->type = bop->type;
result->block = bop->block;
+ return 0;
+}
+
+static int brb_pop(struct bop_ring_buffer *brb)
+{
+ if (brb_empty(brb))
+ return -ENODATA;
+
brb->begin = brb_next(brb, brb->begin);
return 0;
@@ -211,7 +219,7 @@ static int apply_bops(struct sm_metadata *smm)
while (!brb_empty(&smm->uncommitted)) {
struct block_op bop;
- r = brb_pop(&smm->uncommitted, &bop);
+ r = brb_peek(&smm->uncommitted, &bop);
if (r) {
DMERR("bug in bop ring buffer");
break;
@@ -220,6 +228,8 @@ static int apply_bops(struct sm_metadata *smm)
r = commit_bop(smm, &bop);
if (r)
break;
+
+ brb_pop(&smm->uncommitted);
}
return r;
@@ -683,7 +693,6 @@ static struct dm_space_map bootstrap_ops = {
static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
{
int r, i;
- enum allocation_event ev;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
dm_block_t old_len = smm->ll.nr_blocks;
@@ -705,11 +714,12 @@ static int sm_metadata_extend(struct dm_space_map *sm, dm_block_t extra_blocks)
* allocate any new blocks.
*/
do {
- for (i = old_len; !r && i < smm->begin; i++) {
- r = sm_ll_inc(&smm->ll, i, &ev);
- if (r)
- goto out;
- }
+ for (i = old_len; !r && i < smm->begin; i++)
+ r = add_bop(smm, BOP_INC, i);
+
+ if (r)
+ goto out;
+
old_len = smm->begin;
r = apply_bops(smm);
@@ -754,7 +764,6 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
{
int r;
dm_block_t i;
- enum allocation_event ev;
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
smm->begin = superblock + 1;
@@ -782,7 +791,7 @@ int dm_sm_metadata_create(struct dm_space_map *sm,
* allocated blocks that they were built from.
*/
for (i = superblock; !r && i < smm->begin; i++)
- r = sm_ll_inc(&smm->ll, i, &ev);
+ r = add_bop(smm, BOP_INC, i);
if (r)
return r;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 41d70bc..84e597e 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -1946,6 +1946,8 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
first = i;
fbio = r10_bio->devs[i].bio;
+ fbio->bi_iter.bi_size = r10_bio->sectors << 9;
+ fbio->bi_iter.bi_idx = 0;
vcnt = (r10_bio->sectors + (PAGE_SIZE >> 9) - 1) >> (PAGE_SHIFT - 9);
/* now find blocks with errors */
@@ -1989,7 +1991,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
bio_reset(tbio);
tbio->bi_vcnt = vcnt;
- tbio->bi_iter.bi_size = r10_bio->sectors << 9;
+ tbio->bi_iter.bi_size = fbio->bi_iter.bi_size;
tbio->bi_rw = WRITE;
tbio->bi_private = r10_bio;
tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 3ef3d6c..9264ea7 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -9,7 +9,7 @@ menuconfig MEDIA_SUPPORT
If you want to use Webcams, Video grabber devices and/or TV devices
enable this option and other options below.
Additional info and docs are available on the web at
- <http://linuxtv.org>
+ <https://linuxtv.org>
if MEDIA_SUPPORT
@@ -51,7 +51,7 @@ config MEDIA_RADIO_SUPPORT
Enable AM/FM radio support.
Additional info and docs are available on the web at
- <http://linuxtv.org>
+ <https://linuxtv.org>
Say Y when you have a board with radio support.
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
index c07b9db..5e4afa0 100644
--- a/drivers/media/common/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
@@ -27,7 +27,7 @@
#include <linux/videodev2.h>
#include <media/tuner.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include <media/v4l2-common.h>
MODULE_DESCRIPTION("cx23415/6/8 driver");
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index 1ff9f53..9f7c5b0 100644
--- a/drivers/media/common/saa7146/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -20,7 +20,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <media/saa7146.h>
+#include <media/drv-intf/saa7146.h>
#include <linux/module.h>
static int saa7146_num;
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index df1e8c9..930d2c9 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -1,6 +1,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
/****************************************************************************/
diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c
index 3dc6a83..6ebcbc6 100644
--- a/drivers/media/common/saa7146/saa7146_hlp.c
+++ b/drivers/media/common/saa7146/saa7146_hlp.c
@@ -2,7 +2,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
static void calculate_output_format_register(struct saa7146_dev* saa, u32 palette, u32* clip_format)
{
diff --git a/drivers/media/common/saa7146/saa7146_i2c.c b/drivers/media/common/saa7146/saa7146_i2c.c
index 2202719..239a2db 100644
--- a/drivers/media/common/saa7146/saa7146_i2c.c
+++ b/drivers/media/common/saa7146/saa7146_i2c.c
@@ -1,6 +1,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
static u32 saa7146_i2c_func(struct i2c_adapter *adapter)
{
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index 2da9957..4923751 100644
--- a/drivers/media/common/saa7146/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -1,4 +1,4 @@
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
static int vbi_pixel_to_capture = 720 * 2;
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 3077949..d5837be 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -1,6 +1,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <linux/module.h>
diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h
index fc8b792..d9abd96 100644
--- a/drivers/media/common/siano/smsir.h
+++ b/drivers/media/common/siano/smsir.h
@@ -30,8 +30,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <linux/input.h>
#include <media/rc-core.h>
-#define IR_DEFAULT_TIMEOUT 100
-
struct smscore_device_t;
struct ir_t {
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
index ccc1f43..6d3b95b 100644
--- a/drivers/media/dvb-core/demux.h
+++ b/drivers/media/dvb-core/demux.h
@@ -32,6 +32,49 @@
#include <linux/time.h>
#include <linux/dvb/dmx.h>
+/**
+ * DOC: Digital TV Demux
+ *
+ * The Kernel Digital TV Demux kABI defines a driver-internal interface for
+ * registering low-level, hardware specific driver to a hardware independent
+ * demux layer. It is only of interest for Digital TV device driver writers.
+ * The header file for this kABI is named demux.h and located in
+ * drivers/media/dvb-core.
+ *
+ * The demux kABI should be implemented for each demux in the system. It is
+ * used to select the TS source of a demux and to manage the demux resources.
+ * When the demux client allocates a resource via the demux kABI, it receives
+ * a pointer to the kABI of that resource.
+ *
+ * Each demux receives its TS input from a DVB front-end or from memory, as
+ * set via this demux kABI. In a system with more than one front-end, the kABI
+ * can be used to select one of the DVB front-ends as a TS source for a demux,
+ * unless this is fixed in the HW platform.
+ *
+ * The demux kABI only controls front-ends regarding to their connections with
+ * demuxes; the kABI used to set the other front-end parameters, such as
+ * tuning, are devined via the Digital TV Frontend kABI.
+ *
+ * The functions that implement the abstract interface demux should be defined
+ * static or module private and registered to the Demux core for external
+ * access. It is not necessary to implement every function in the struct
+ * &dmx_demux. For example, a demux interface might support Section filtering,
+ * but not PES filtering. The kABI client is expected to check the value of any
+ * function pointer before calling the function: the value of NULL means
+ * that the function is not available.
+ *
+ * Whenever the functions of the demux API modify shared data, the
+ * possibilities of lost update and race condition problems should be
+ * addressed, e.g. by protecting parts of code with mutexes.
+ *
+ * Note that functions called from a bottom half context must not sleep.
+ * Even a simple memory allocation without using %GFP_ATOMIC can result in a
+ * kernel thread being put to sleep if swapping is needed. For example, the
+ * Linux Kernel calls the functions of a network device interface from a
+ * bottom half context. Thus, if a demux kABI function is called from network
+ * device code, the function must not sleep.
+ */
+
/*
* Common definitions
*/
@@ -187,8 +230,28 @@ struct dmx_section_feed {
int (*stop_filtering)(struct dmx_section_feed *feed);
};
-/*
- * Callback functions
+/**
+ * DOC: Demux Callback
+ *
+ * This kernel-space API comprises the callback functions that deliver filtered
+ * data to the demux client. Unlike the other DVB kABIs, these functions are
+ * provided by the client and called from the demux code.
+ *
+ * The function pointers of this abstract interface are not packed into a
+ * structure as in the other demux APIs, because the callback functions are
+ * registered and used independent of each other. As an example, it is possible
+ * for the API client to provide several callback functions for receiving TS
+ * packets and no callbacks for PES packets or sections.
+ *
+ * The functions that implement the callback API need not be re-entrant: when
+ * a demux driver calls one of these functions, the driver is not allowed to
+ * call the function again before the original call returns. If a callback is
+ * triggered by a hardware interrupt, it is recommended to use the Linux
+ * bottom half mechanism or start a tasklet instead of making the callback
+ * function call directly from a hardware interrupt.
+ *
+ * This mechanism is implemented by dmx_ts_cb() and dmx_section_cb()
+ * callbacks.
*/
/**
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 0a46580..1c1c298 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -389,4 +389,5 @@
#define USB_PID_PCTV_2002E_SE 0x025d
#define USB_PID_SVEON_STV27 0xd3af
#define USB_PID_TURBOX_DTT_2000 0xd3a4
+#define USB_PID_WINTV_SOLOHD 0x0264
#endif
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index c38ef1a..b64f337 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -891,21 +891,21 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
}
/*
- * Sleep until gettimeofday() > waketime + add_usec
- * This needs to be as precise as possible, but as the delay is
- * usually between 2ms and 32ms, it is done using a scheduled msleep
- * followed by usleep (normally a busy-wait loop) for the remainder
+ * Sleep for the amount of time given by add_usec parameter
+ *
+ * This needs to be as precise as possible, as it affects the detection of
+ * the dish tone command at the satellite subsystem. The precision is improved
+ * by using a scheduled msleep followed by udelay for the remainder.
*/
void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec)
{
- s32 delta, newdelta;
+ s32 delta;
- ktime_add_us(*waketime, add_usec);
+ *waketime = ktime_add_us(*waketime, add_usec);
delta = ktime_us_delta(ktime_get_real(), *waketime);
if (delta > 2500) {
msleep((delta - 1500) / 1000);
- newdelta = ktime_us_delta(ktime_get_real(), *waketime);
- delta = (newdelta > delta) ? 0 : newdelta;
+ delta = ktime_us_delta(ktime_get_real(), *waketime);
}
if (delta > 0)
udelay(delta);
@@ -2313,9 +2313,9 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n",
__func__, c->delivery_system, fe->ops.info.type);
- /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
- * do it, it is done for it. */
- info->caps |= FE_CAN_INVERSION_AUTO;
+ /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */
+ if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT))
+ info->caps |= FE_CAN_INVERSION_AUTO;
err = 0;
break;
}
@@ -2710,6 +2710,11 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
else if (fe->ops.tuner_ops.init)
ret = fe->ops.tuner_ops.init(fe);
+ if (fe->ops.set_tone && fepriv->tone != -1)
+ fe->ops.set_tone(fe, fepriv->tone);
+ if (fe->ops.set_voltage && fepriv->voltage != -1)
+ fe->ops.set_voltage(fe, fepriv->voltage);
+
fe->exit = DVB_FE_NO_EXIT;
fepriv->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe);
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index 97661b2..458bcce 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -42,6 +42,29 @@
#include "dvbdev.h"
+/**
+ * DOC: Digital TV Frontend
+ *
+ * The Digital TV Frontend kABI defines a driver-internal interface for
+ * registering low-level, hardware specific driver to a hardware independent
+ * frontend layer. It is only of interest for Digital TV device driver writers.
+ * The header file for this API is named dvb_frontend.h and located in
+ * drivers/media/dvb-core.
+ *
+ * Before using the Digital TV frontend core, the bridge driver should attach
+ * the frontend demod, tuner and SEC devices and call dvb_register_frontend(),
+ * in order to register the new frontend at the subsystem. At device
+ * detach/removal, the bridge driver should call dvb_unregister_frontend() to
+ * remove the frontend from the core and then dvb_frontend_detach() to free the
+ * memory allocated by the frontend drivers.
+ *
+ * The drivers should also call dvb_frontend_suspend() as part of their
+ * handler for the &device_driver.suspend(), and dvb_frontend_resume() as
+ * part of their handler for &device_driver.resume().
+ *
+ * A few other optional functions are provided to handle some special cases.
+ */
+
/*
* Maximum number of Delivery systems per frontend. It
* should be smaller or equal to 32
@@ -112,16 +135,6 @@ struct analog_parameters {
u64 std;
};
-enum tuner_param {
- DVBFE_TUNER_FREQUENCY = (1 << 0),
- DVBFE_TUNER_TUNERSTEP = (1 << 1),
- DVBFE_TUNER_IFFREQ = (1 << 2),
- DVBFE_TUNER_BANDWIDTH = (1 << 3),
- DVBFE_TUNER_REFCLOCK = (1 << 4),
- DVBFE_TUNER_IQSENSE = (1 << 5),
- DVBFE_TUNER_DUMMY = (1 << 31)
-};
-
/**
* enum dvbfe_algo - defines the algorithm used to tune into a channel
*
@@ -152,15 +165,6 @@ enum dvbfe_algo {
DVBFE_ALGO_RECOVERY = (1 << 31)
};
-struct tuner_state {
- u32 frequency;
- u32 tunerstep;
- u32 ifreq;
- u32 bandwidth;
- u32 iqsense;
- u32 refclock;
-};
-
/**
* enum dvbfe_search - search callback possible return status
*
@@ -209,12 +213,12 @@ enum dvbfe_search {
* are stored at @dvb_frontend.dtv_property_cache;. The
* tuner demod can change the parameters to reflect the
* changes needed for the channel to be tuned, and
- * update statistics.
+ * update statistics. This is the recommended way to set
+ * the tuner parameters and should be used on newer
+ * drivers.
* @set_analog_params: callback function used to tune into an analog TV
* channel on hybrid tuners. It passes @analog_parameters;
* to the driver.
- * @calc_regs: callback function used to pass register data settings
- * for simple tuners.
* @set_config: callback function used to send some tuner-specific
* parameters.
* @get_frequency: get the actual tuned frequency
@@ -227,16 +231,10 @@ enum dvbfe_search {
* via DVBv5 API (@dvb_frontend.dtv_property_cache;).
* @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC.
- * @set_frequency: Set a new frequency. Please notice that using
- * set_params is preferred.
- * @set_bandwidth: Set a new frequency. Please notice that using
- * set_params is preferred.
- * @set_state: callback function used on some legacy drivers that
- * don't implement set_params in order to set properties.
- * Shouldn't be used on new drivers.
- * @get_state: callback function used to get properties by some
- * legacy drivers that don't implement set_params.
- * Shouldn't be used on new drivers.
+ * @calc_regs: callback function used to pass register data settings
+ * for simple tuners. Shouldn't be used on newer drivers.
+ * @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
+ * @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
*
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for
* terrestrial/cable or kHz for satellite.
@@ -252,14 +250,10 @@ struct dvb_tuner_ops {
int (*suspend)(struct dvb_frontend *fe);
int (*resume)(struct dvb_frontend *fe);
- /** This is for simple PLLs - set all parameters in one go. */
+ /* This is the recomended way to set the tuner */
int (*set_params)(struct dvb_frontend *fe);
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
- /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
- int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
-
- /** This is to allow setting tuner-specific configs */
int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
@@ -272,17 +266,23 @@ struct dvb_tuner_ops {
int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
- /** These are provided separately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter separately. */
- int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
- int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+ /*
+ * This is support for demods like the mt352 - fills out the supplied
+ * buffer with what to write.
+ *
+ * Don't use on newer drivers.
+ */
+ int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
/*
- * These are provided separately from set_params in order to facilitate silicon
- * tuners which require sophisticated tuning loops, controlling each parameter separately.
+ * These are provided separately from set_params in order to
+ * facilitate silicon tuners which require sophisticated tuning loops,
+ * controlling each parameter separately.
+ *
+ * Don't use on newer drivers.
*/
- int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
- int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
};
/**
@@ -404,6 +404,11 @@ struct dtv_frontend_properties;
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
* @dishnetwork_send_legacy_command: callback function to implement the
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
+ * Drivers should not use this, except when the DVB
+ * core emulation fails to provide proper support (e.g.
+ * if set_voltage() takes more than 8ms to work), and
+ * when backward compatibility with this legacy API is
+ * required.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead.
* @ts_bus_ctrl: callback function used to take control of the TS bus.
@@ -466,7 +471,8 @@ struct dvb_frontend_ops {
int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
int (*set_lna)(struct dvb_frontend *);
- /* These callbacks are for devices that implement their own
+ /*
+ * These callbacks are for devices that implement their own
* tuning algorithms, rather than a simple swzigzag
*/
enum dvbfe_search (*search)(struct dvb_frontend *fe);
@@ -682,17 +688,126 @@ struct dvb_frontend {
unsigned int exit;
};
-extern int dvb_register_frontend(struct dvb_adapter *dvb,
+/**
+ * dvb_register_frontend() - Registers a DVB frontend at the adapter
+ *
+ * @dvb: pointer to the dvb adapter
+ * @fe: pointer to the frontend struct
+ *
+ * Allocate and initialize the private data needed by the frontend core to
+ * manage the frontend and calls dvb_register_device() to register a new
+ * frontend. It also cleans the property cache that stores the frontend
+ * parameters and selects the first available delivery system.
+ */
+int dvb_register_frontend(struct dvb_adapter *dvb,
struct dvb_frontend *fe);
-extern int dvb_unregister_frontend(struct dvb_frontend *fe);
+/**
+ * dvb_unregister_frontend() - Unregisters a DVB frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * Stops the frontend kthread, calls dvb_unregister_device() and frees the
+ * private frontend data allocated by dvb_register_frontend().
+ *
+ * NOTE: This function doesn't frees the memory allocated by the demod,
+ * by the SEC driver and by the tuner. In order to free it, an explicit call to
+ * dvb_frontend_detach() is needed, after calling this function.
+ */
+int dvb_unregister_frontend(struct dvb_frontend *fe);
-extern void dvb_frontend_detach(struct dvb_frontend *fe);
+/**
+ * dvb_frontend_detach() - Detaches and frees frontend specific data
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function should be called after dvb_unregister_frontend(). It
+ * calls the SEC, tuner and demod release functions:
+ * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
+ * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
+ *
+ * If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
+ * the module reference count, needed to allow userspace to remove the
+ * previously used DVB frontend modules.
+ */
+void dvb_frontend_detach(struct dvb_frontend *fe);
+
+/**
+ * dvb_frontend_suspend() - Suspends a Digital TV frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function prepares a Digital TV frontend to suspend.
+ *
+ * In order to prepare the tuner to suspend, if
+ * &dvb_frontend_ops.tuner_ops.suspend() is available, it calls it. Otherwise,
+ * it will call &dvb_frontend_ops.tuner_ops.sleep(), if available.
+ *
+ * It will also call &dvb_frontend_ops.sleep() to put the demod to suspend.
+ *
+ * The drivers should also call dvb_frontend_suspend() as part of their
+ * handler for the &device_driver.suspend().
+ */
+int dvb_frontend_suspend(struct dvb_frontend *fe);
+
+/**
+ * dvb_frontend_resume() - Resumes a Digital TV frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * This function resumes the usual operation of the tuner after resume.
+ *
+ * In order to resume the frontend, it calls the demod &dvb_frontend_ops.init().
+ *
+ * If &dvb_frontend_ops.tuner_ops.resume() is available, It, it calls it.
+ * Otherwise,t will call &dvb_frontend_ops.tuner_ops.init(), if available.
+ *
+ * Once tuner and demods are resumed, it will enforce that the SEC voltage and
+ * tone are restored to their previous values and wake up the frontend's
+ * kthread in order to retune the frontend.
+ *
+ * The drivers should also call dvb_frontend_resume() as part of their
+ * handler for the &device_driver.resume().
+ */
+int dvb_frontend_resume(struct dvb_frontend *fe);
-extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-extern int dvb_frontend_suspend(struct dvb_frontend *fe);
-extern int dvb_frontend_resume(struct dvb_frontend *fe);
+/**
+ * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
+ *
+ * @fe: pointer to the frontend struct
+ *
+ * Calls &dvb_frontend_ops.init() and &dvb_frontend_ops.tuner_ops.init(),
+ * and resets SEC tone and voltage (for Satellite systems).
+ *
+ * NOTE: Currently, this function is used only by one driver (budget-av).
+ * It seems to be due to address some special issue with that specific
+ * frontend.
+ */
+void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-extern void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
+/**
+ * dvb_frontend_sleep_until() - Sleep for the amount of time given by
+ * add_usec parameter
+ *
+ * @waketime: pointer to a struct ktime_t
+ * @add_usec: time to sleep, in microseconds
+ *
+ * This function is used to measure the time required for the
+ * %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
+ * as possible, as it affects the detection of the dish tone command at the
+ * satellite subsystem.
+ *
+ * Its used internally by the DVB frontend core, in order to emulate
+ * %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage()
+ * callback.
+ *
+ * NOTE: it should not be used at the drivers, as the emulation for the
+ * legacy callback is provided by the Kernel. The only situation where this
+ * should be at the drivers is when there are some bugs at the hardware that
+ * would prevent the core emulation to work. On such cases, the driver would
+ * be writing a &dvb_frontend_ops.dishnetwork_send_legacy_command() and
+ * calling this function directly.
+ */
+void dvb_frontend_sleep_until(ktime_t *waketime, u32 add_usec);
#endif
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 292c947..310e4b8 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -264,7 +264,7 @@ config DVB_MB86A16
config DVB_TDA10071
tristate "NXP TDA10071"
depends on DVB_CORE && I2C
- select REGMAP
+ select REGMAP_I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
diff --git a/drivers/media/dvb-frontends/au8522_common.c b/drivers/media/dvb-frontends/au8522_common.c
index 3559ff2..f135126 100644
--- a/drivers/media/dvb-frontends/au8522_common.c
+++ b/drivers/media/dvb-frontends/au8522_common.c
@@ -44,7 +44,7 @@ int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
int ret;
u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
- struct i2c_msg msg = { .addr = state->config->demod_address,
+ struct i2c_msg msg = { .addr = state->config.demod_address,
.flags = 0, .buf = buf, .len = 3 };
ret = i2c_transfer(state->i2c, &msg, 1);
@@ -64,9 +64,9 @@ u8 au8522_readreg(struct au8522_state *state, u16 reg)
u8 b1[] = { 0 };
struct i2c_msg msg[] = {
- { .addr = state->config->demod_address, .flags = 0,
+ { .addr = state->config.demod_address, .flags = 0,
.buf = b0, .len = 2 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ { .addr = state->config.demod_address, .flags = I2C_M_RD,
.buf = b1, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
@@ -140,7 +140,7 @@ EXPORT_SYMBOL(au8522_release_state);
static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
{
- struct au8522_led_config *led_config = state->config->led_cfg;
+ struct au8522_led_config *led_config = state->config.led_cfg;
u8 val;
/* bail out if we can't control an LED */
@@ -170,7 +170,7 @@ static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
*/
int au8522_led_ctrl(struct au8522_state *state, int led)
{
- struct au8522_led_config *led_config = state->config->led_cfg;
+ struct au8522_led_config *led_config = state->config.led_cfg;
int i, ret = 0;
/* bail out if we can't control an LED */
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index 28d7dc2..c8f13d8 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -730,7 +730,6 @@ static int au8522_probe(struct i2c_client *client,
struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
int instance;
- struct au8522_config *demod_config;
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter,
@@ -754,15 +753,7 @@ static int au8522_probe(struct i2c_client *client,
break;
}
- demod_config = kzalloc(sizeof(struct au8522_config), GFP_KERNEL);
- if (demod_config == NULL) {
- if (instance == 1)
- kfree(state);
- return -ENOMEM;
- }
- demod_config->demod_address = 0x8e >> 1;
-
- state->config = demod_config;
+ state->config.demod_address = 0x8e >> 1;
state->i2c = client->adapter;
sd = &state->sd;
@@ -784,8 +775,7 @@ static int au8522_probe(struct i2c_client *client,
int err = hdl->error;
v4l2_ctrl_handler_free(hdl);
- kfree(demod_config);
- kfree(state);
+ au8522_release_state(state);
return err;
}
diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c
index f956f13..6c1e976 100644
--- a/drivers/media/dvb-frontends/au8522_dig.c
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -566,7 +566,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
VSB_mod_tab[i].reg,
VSB_mod_tab[i].data);
- au8522_set_if(fe, state->config->vsb_if);
+ au8522_set_if(fe, state->config.vsb_if);
break;
case QAM_64:
dprintk("%s() QAM 64\n", __func__);
@@ -574,7 +574,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM64_mod_tab[i].reg,
QAM64_mod_tab[i].data);
- au8522_set_if(fe, state->config->qam_if);
+ au8522_set_if(fe, state->config.qam_if);
break;
case QAM_256:
if (zv_mode) {
@@ -583,7 +583,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM256_mod_tab_zv_mode[i].reg,
QAM256_mod_tab_zv_mode[i].data);
- au8522_set_if(fe, state->config->qam_if);
+ au8522_set_if(fe, state->config.qam_if);
msleep(100);
au8522_writereg(state, 0x821a, 0x00);
} else {
@@ -592,7 +592,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_writereg(state,
QAM256_mod_tab[i].reg,
QAM256_mod_tab[i].data);
- au8522_set_if(fe, state->config->qam_if);
+ au8522_set_if(fe, state->config.qam_if);
}
break;
default:
@@ -666,7 +666,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status)
*status |= FE_HAS_LOCK | FE_HAS_SYNC;
}
- switch (state->config->status_mode) {
+ switch (state->config.status_mode) {
case AU8522_DEMODLOCKING:
dprintk("%s() DEMODLOCKING\n", __func__);
if (*status & FE_HAS_VITERBI)
@@ -704,7 +704,7 @@ static int au8522_read_status(struct dvb_frontend *fe, enum fe_status *status)
static int au8522_led_status(struct au8522_state *state, const u16 *snr)
{
- struct au8522_led_config *led_config = state->config->led_cfg;
+ struct au8522_led_config *led_config = state->config.led_cfg;
int led;
u16 strong;
@@ -758,7 +758,7 @@ static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
au8522_readreg(state, 0x4311),
snr);
- if (state->config->led_cfg)
+ if (state->config.led_cfg)
au8522_led_status(state, snr);
return ret;
@@ -866,7 +866,7 @@ struct dvb_frontend *au8522_attach(const struct au8522_config *config,
}
/* setup the state */
- state->config = config;
+ state->config = *config;
state->i2c = i2c;
state->operational_mode = AU8522_DIGITAL_MODE;
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index 951b384..ee330c6 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -50,7 +50,7 @@ struct au8522_state {
struct list_head hybrid_tuner_instance_list;
/* configuration settings */
- const struct au8522_config *config;
+ struct au8522_config config;
struct dvb_frontend frontend;
diff --git a/drivers/media/dvb-frontends/bsbe1-d01a.h b/drivers/media/dvb-frontends/bsbe1-d01a.h
index 7ed3c42..baaf89e 100644
--- a/drivers/media/dvb-frontends/bsbe1-d01a.h
+++ b/drivers/media/dvb-frontends/bsbe1-d01a.h
@@ -21,7 +21,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef BSBE1_D01A_H
diff --git a/drivers/media/dvb-frontends/bsbe1.h b/drivers/media/dvb-frontends/bsbe1.h
index 53e4d0d..4ad7661 100644
--- a/drivers/media/dvb-frontends/bsbe1.h
+++ b/drivers/media/dvb-frontends/bsbe1.h
@@ -19,7 +19,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef BSBE1_H
diff --git a/drivers/media/dvb-frontends/bsru6.h b/drivers/media/dvb-frontends/bsru6.h
index c2a578e..275c178 100644
--- a/drivers/media/dvb-frontends/bsru6.h
+++ b/drivers/media/dvb-frontends/bsru6.h
@@ -19,7 +19,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef BSRU6_H
diff --git a/drivers/media/dvb-frontends/isl6405.c b/drivers/media/dvb-frontends/isl6405.c
index b46450a..6913cd6 100644
--- a/drivers/media/dvb-frontends/isl6405.c
+++ b/drivers/media/dvb-frontends/isl6405.c
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#include <linux/delay.h>
#include <linux/errno.h>
diff --git a/drivers/media/dvb-frontends/isl6405.h b/drivers/media/dvb-frontends/isl6405.h
index 3c148b8..4a23d3b 100644
--- a/drivers/media/dvb-frontends/isl6405.h
+++ b/drivers/media/dvb-frontends/isl6405.h
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef _ISL6405_H
diff --git a/drivers/media/dvb-frontends/isl6421.c b/drivers/media/dvb-frontends/isl6421.c
index 3a4d460..0b6d383 100644
--- a/drivers/media/dvb-frontends/isl6421.c
+++ b/drivers/media/dvb-frontends/isl6421.c
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#include <linux/delay.h>
#include <linux/errno.h>
diff --git a/drivers/media/dvb-frontends/isl6421.h b/drivers/media/dvb-frontends/isl6421.h
index 3273597..00f9874 100644
--- a/drivers/media/dvb-frontends/isl6421.h
+++ b/drivers/media/dvb-frontends/isl6421.h
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef _ISL6421_H
diff --git a/drivers/media/dvb-frontends/lnbp21.c b/drivers/media/dvb-frontends/lnbp21.c
index 4aca0fb..6261460 100644
--- a/drivers/media/dvb-frontends/lnbp21.c
+++ b/drivers/media/dvb-frontends/lnbp21.c
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#include <linux/delay.h>
#include <linux/errno.h>
diff --git a/drivers/media/dvb-frontends/lnbp21.h b/drivers/media/dvb-frontends/lnbp21.h
index a9b530d..cd9101f 100644
--- a/drivers/media/dvb-frontends/lnbp21.h
+++ b/drivers/media/dvb-frontends/lnbp21.h
@@ -21,7 +21,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef _LNBP21_H
diff --git a/drivers/media/dvb-frontends/lnbp22.c b/drivers/media/dvb-frontends/lnbp22.c
index d7ca0fd..5c5fd04 100644
--- a/drivers/media/dvb-frontends/lnbp22.c
+++ b/drivers/media/dvb-frontends/lnbp22.c
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#include <linux/delay.h>
#include <linux/errno.h>
diff --git a/drivers/media/dvb-frontends/lnbp22.h b/drivers/media/dvb-frontends/lnbp22.h
index 6281483..5d01d92 100644
--- a/drivers/media/dvb-frontends/lnbp22.h
+++ b/drivers/media/dvb-frontends/lnbp22.h
@@ -22,7 +22,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org
+ * the project's page is at https://linuxtv.org
*/
#ifndef _LNBP22_H
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 78b87b2..10f2119 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -976,7 +976,8 @@ static int rtl2832_regmap_read(void *context, const void *reg_buf,
ret = __i2c_transfer(client->adapter, msg, 2);
if (ret != 2) {
- dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+ dev_warn(&client->dev, "i2c reg read failed %d reg %02x\n",
+ ret, *(u8 *)reg_buf);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
@@ -999,7 +1000,8 @@ static int rtl2832_regmap_write(void *context, const void *data, size_t count)
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1) {
- dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
+ ret, *(u8 *)data);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
@@ -1028,7 +1030,8 @@ static int rtl2832_regmap_gather_write(void *context, const void *reg,
ret = __i2c_transfer(client->adapter, msg, 1);
if (ret != 1) {
- dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ dev_warn(&client->dev, "i2c reg write failed %d reg %02x\n",
+ ret, *(u8 const *)reg);
if (ret >= 0)
ret = -EREMOTEIO;
return ret;
@@ -1097,18 +1100,6 @@ static int rtl2832_enable_slave_ts(struct i2c_client *client)
if (ret)
goto err;
- ret = rtl2832_bulk_write(client, 0x022, "\x01", 1);
- if (ret)
- goto err;
-
- ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1);
- if (ret)
- goto err;
-
- ret = rtl2832_bulk_write(client, 0x027, "\xff", 1);
- if (ret)
- goto err;
-
ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
if (ret)
goto err;
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index dcd8d94..b860f02 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -310,7 +310,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer,
urb->actual_length);
vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len);
- v4l2_get_timestamp(&fbuf->vb.timestamp);
+ fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
fbuf->vb.sequence = dev->sequence++;
vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -490,7 +490,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
/* Videobuf2 operations */
static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *nbuffers,
+ unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
index 7c2eeee..1cf6e52 100644
--- a/drivers/media/dvb-frontends/si2165.c
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -1,21 +1,21 @@
/*
- Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
-
- Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- References:
- http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
-*/
+ * Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator
+ *
+ * Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * References:
+ * http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+ */
#include <linux/delay.h>
#include <linux/errno.h>
@@ -31,16 +31,18 @@
#include "si2165_priv.h"
#include "si2165.h"
-/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
- * uses 16 MHz xtal */
-
-/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
- * uses 24 MHz clock provided by tuner */
+/*
+ * Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
+ * uses 16 MHz xtal
+ *
+ * Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
+ * uses 24 MHz clock provided by tuner
+ */
struct si2165_state {
struct i2c_adapter *i2c;
- struct dvb_frontend frontend;
+ struct dvb_frontend fe;
struct si2165_config config;
@@ -241,6 +243,27 @@ err:
return ret;
}
+#define REG16(reg, val) { (reg), (val) & 0xff }, { (reg)+1, (val)>>8 & 0xff }
+struct si2165_reg_value_pair {
+ u16 reg;
+ u8 val;
+};
+
+static int si2165_write_reg_list(struct si2165_state *state,
+ const struct si2165_reg_value_pair *regs,
+ int count)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < count; i++) {
+ ret = si2165_writereg8(state, regs[i].reg, regs[i].val);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
static int si2165_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
@@ -258,8 +281,10 @@ static int si2165_init_pll(struct si2165_state *state)
u8 divl = 12;
u8 buf[4];
- /* hardcoded values can be deleted if calculation is verified
- * or it yields the same values as the windows driver */
+ /*
+ * hardcoded values can be deleted if calculation is verified
+ * or it yields the same values as the windows driver
+ */
switch (ref_freq_Hz) {
case 16000000u:
divn = 56;
@@ -274,8 +299,10 @@ static int si2165_init_pll(struct si2165_state *state)
if (ref_freq_Hz > 16000000u)
divr = 2;
- /* now select divn and divp such that
- * fvco is in 1624..1824 MHz */
+ /*
+ * now select divn and divp such that
+ * fvco is in 1624..1824 MHz
+ */
if (1624000000u * divr > ref_freq_Hz * 2u * 63u)
divp = 4;
@@ -341,10 +368,12 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
if (len % 4 != 0)
return -EINVAL;
- deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
+ deb_fw_load(
+ "si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
len, offset, block_count);
while (offset+12 <= len && cur_block < block_count) {
- deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ deb_fw_load(
+ "si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
len, offset, cur_block, block_count);
wordcount = data[offset];
if (wordcount < 1 || data[offset+1] ||
@@ -383,7 +412,8 @@ static int si2165_upload_firmware_block(struct si2165_state *state,
cur_block++;
}
- deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ deb_fw_load(
+ "si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
len, offset, cur_block, block_count);
if (poffset)
@@ -633,7 +663,7 @@ static int si2165_init(struct dvb_frontend *fe)
goto error;
/* ber_pkt */
- ret = si2165_writereg16(state, 0x0470 , 0x7530);
+ ret = si2165_writereg16(state, 0x0470, 0x7530);
if (ret < 0)
goto error;
@@ -660,22 +690,19 @@ static int si2165_init(struct dvb_frontend *fe)
goto error;
}
- /* write adc values after each reset*/
- ret = si2165_writereg8(state, 0x012a, 0x46);
- if (ret < 0)
- goto error;
- ret = si2165_writereg8(state, 0x012c, 0x00);
+ /* ts output config */
+ ret = si2165_writereg8(state, 0x04e4, 0x20);
if (ret < 0)
- goto error;
- ret = si2165_writereg8(state, 0x012e, 0x0a);
+ return ret;
+ ret = si2165_writereg16(state, 0x04ef, 0x00fe);
if (ret < 0)
- goto error;
- ret = si2165_writereg8(state, 0x012f, 0xff);
+ return ret;
+ ret = si2165_writereg24(state, 0x04f4, 0x555555);
if (ret < 0)
- goto error;
- ret = si2165_writereg8(state, 0x0123, 0x70);
+ return ret;
+ ret = si2165_writereg8(state, 0x04e5, 0x01);
if (ret < 0)
- goto error;
+ return ret;
return 0;
error:
@@ -733,16 +760,26 @@ static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
do_div(oversamp, dvb_rate);
reg_value = oversamp & 0x3fffffff;
- /* oversamp, usbdump contained 0x03100000; */
+ dprintk("%s: Write oversamp=%#x\n", __func__, reg_value);
return si2165_writereg32(state, 0x00e4, reg_value);
}
-static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
+static int si2165_set_if_freq_shift(struct si2165_state *state)
{
+ struct dvb_frontend *fe = &state->fe;
u64 if_freq_shift;
s32 reg_value = 0;
u32 fe_clk = si2165_get_fe_clk(state);
+ u32 IF = 0;
+ if (!fe->ops.tuner_ops.get_if_frequency) {
+ dev_err(&state->i2c->dev,
+ "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ fe->ops.tuner_ops.get_if_frequency(fe, &IF);
if_freq_shift = IF;
if_freq_shift <<= 29;
@@ -758,25 +795,39 @@ static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
return si2165_writereg32(state, 0x00e8, reg_value);
}
-static int si2165_set_parameters(struct dvb_frontend *fe)
+static const struct si2165_reg_value_pair dvbt_regs[] = {
+ /* standard = DVB-T */
+ { 0x00ec, 0x01 },
+ { 0x08f8, 0x00 },
+ /* impulsive_noise_remover */
+ { 0x031c, 0x01 },
+ { 0x00cb, 0x00 },
+ /* agc2 */
+ { 0x016e, 0x41 },
+ { 0x016c, 0x0e },
+ { 0x016d, 0x10 },
+ /* agc */
+ { 0x015b, 0x03 },
+ { 0x0150, 0x78 },
+ /* agc */
+ { 0x01a0, 0x78 },
+ { 0x01c8, 0x68 },
+ /* freq_sync_range */
+ REG16(0x030c, 0x0064),
+ /* gp_reg0 */
+ { 0x0387, 0x00 }
+};
+
+static int si2165_set_frontend_dvbt(struct dvb_frontend *fe)
{
int ret;
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
struct si2165_state *state = fe->demodulator_priv;
- u8 val[3];
- u32 IF;
u32 dvb_rate = 0;
u16 bw10k;
dprintk("%s: called\n", __func__);
- if (!fe->ops.tuner_ops.get_if_frequency) {
- dev_err(&state->i2c->dev,
- "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
- KBUILD_MODNAME);
- return -EINVAL;
- }
-
if (!state->has_dvbt)
return -EINVAL;
@@ -788,34 +839,10 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
bw10k = 800;
}
- /* standard = DVB-T */
- ret = si2165_writereg8(state, 0x00ec, 0x01);
- if (ret < 0)
- return ret;
ret = si2165_adjust_pll_divl(state, 12);
if (ret < 0)
return ret;
- fe->ops.tuner_ops.get_if_frequency(fe, &IF);
- ret = si2165_set_if_freq_shift(state, IF);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x08f8, 0x00);
- if (ret < 0)
- return ret;
- /* ts output config */
- ret = si2165_writereg8(state, 0x04e4, 0x20);
- if (ret < 0)
- return ret;
- ret = si2165_writereg16(state, 0x04ef, 0x00fe);
- if (ret < 0)
- return ret;
- ret = si2165_writereg24(state, 0x04f4, 0x555555);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x04e5, 0x01);
- if (ret < 0)
- return ret;
/* bandwidth in 10KHz steps */
ret = si2165_writereg16(state, 0x0308, bw10k);
if (ret < 0)
@@ -823,48 +850,115 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
ret = si2165_set_oversamp(state, dvb_rate);
if (ret < 0)
return ret;
- /* impulsive_noise_remover */
- ret = si2165_writereg8(state, 0x031c, 0x01);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x00cb, 0x00);
+
+ ret = si2165_write_reg_list(state, dvbt_regs, ARRAY_SIZE(dvbt_regs));
if (ret < 0)
return ret;
+
+ return 0;
+}
+
+static const struct si2165_reg_value_pair dvbc_regs[] = {
+ /* standard = DVB-C */
+ { 0x00ec, 0x05 },
+ { 0x08f8, 0x00 },
+
/* agc2 */
- ret = si2165_writereg8(state, 0x016e, 0x41);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x016c, 0x0e);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x016d, 0x10);
- if (ret < 0)
- return ret;
+ { 0x016e, 0x50 },
+ { 0x016c, 0x0e },
+ { 0x016d, 0x10 },
/* agc */
- ret = si2165_writereg8(state, 0x015b, 0x03);
- if (ret < 0)
- return ret;
- ret = si2165_writereg8(state, 0x0150, 0x78);
- if (ret < 0)
- return ret;
+ { 0x015b, 0x03 },
+ { 0x0150, 0x68 },
/* agc */
- ret = si2165_writereg8(state, 0x01a0, 0x78);
+ { 0x01a0, 0x68 },
+ { 0x01c8, 0x50 },
+
+ { 0x0278, 0x0d },
+
+ { 0x023a, 0x05 },
+ { 0x0261, 0x09 },
+ REG16(0x0350, 0x3e80),
+ { 0x02f4, 0x00 },
+
+ { 0x00cb, 0x01 },
+ REG16(0x024c, 0x0000),
+ REG16(0x027c, 0x0000),
+ { 0x0232, 0x03 },
+ { 0x02f4, 0x0b },
+ { 0x018b, 0x00 },
+};
+
+static int si2165_set_frontend_dvbc(struct dvb_frontend *fe)
+{
+ struct si2165_state *state = fe->demodulator_priv;
+ int ret;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ const u32 dvb_rate = p->symbol_rate;
+ const u32 bw_hz = p->bandwidth_hz;
+
+ if (!state->has_dvbc)
+ return -EINVAL;
+
+ if (dvb_rate == 0)
+ return -EINVAL;
+
+ ret = si2165_adjust_pll_divl(state, 14);
if (ret < 0)
return ret;
- ret = si2165_writereg8(state, 0x01c8, 0x68);
+
+ /* Oversampling */
+ ret = si2165_set_oversamp(state, dvb_rate);
if (ret < 0)
return ret;
- /* freq_sync_range */
- ret = si2165_writereg16(state, 0x030c, 0x0064);
+
+ ret = si2165_writereg32(state, 0x00c4, bw_hz);
if (ret < 0)
return ret;
- /* gp_reg0 */
- ret = si2165_readreg8(state, 0x0387, val);
+
+ ret = si2165_write_reg_list(state, dvbc_regs, ARRAY_SIZE(dvbc_regs));
if (ret < 0)
return ret;
- ret = si2165_writereg8(state, 0x0387, 0x00);
+
+ return 0;
+}
+
+static const struct si2165_reg_value_pair agc_rewrite[] = {
+ { 0x012a, 0x46 },
+ { 0x012c, 0x00 },
+ { 0x012e, 0x0a },
+ { 0x012f, 0xff },
+ { 0x0123, 0x70 }
+};
+
+static int si2165_set_frontend(struct dvb_frontend *fe)
+{
+ struct si2165_state *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 delsys = p->delivery_system;
+ int ret;
+ u8 val[3];
+
+ /* initial setting of if freq shift */
+ ret = si2165_set_if_freq_shift(state);
if (ret < 0)
return ret;
+
+ switch (delsys) {
+ case SYS_DVBT:
+ ret = si2165_set_frontend_dvbt(fe);
+ if (ret < 0)
+ return ret;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = si2165_set_frontend_dvbc(fe);
+ if (ret < 0)
+ return ret;
+ break;
+ default:
+ return -EINVAL;
+ }
+
/* dsp_addr_jump */
ret = si2165_writereg32(state, 0x0348, 0xf4000000);
if (ret < 0)
@@ -874,8 +968,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
fe->ops.tuner_ops.set_params(fe);
/* recalc if_freq_shift if IF might has changed */
- fe->ops.tuner_ops.get_if_frequency(fe, &IF);
- ret = si2165_set_if_freq_shift(state, IF);
+ ret = si2165_set_if_freq_shift(state);
if (ret < 0)
return ret;
@@ -886,6 +979,7 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
ret = si2165_writereg8(state, 0x0341, 0x00);
if (ret < 0)
return ret;
+
/* reset all */
ret = si2165_writereg8(state, 0x00c0, 0x00);
if (ret < 0)
@@ -894,6 +988,13 @@ static int si2165_set_parameters(struct dvb_frontend *fe)
ret = si2165_writereg32(state, 0x0384, 0x00000000);
if (ret < 0)
return ret;
+
+ /* write adc values after each reset*/
+ ret = si2165_write_reg_list(state, agc_rewrite,
+ ARRAY_SIZE(agc_rewrite));
+ if (ret < 0)
+ return ret;
+
/* start_synchro */
ret = si2165_writereg8(state, 0x02e0, 0x01);
if (ret < 0)
@@ -917,7 +1018,12 @@ static void si2165_release(struct dvb_frontend *fe)
static struct dvb_frontend_ops si2165_ops = {
.info = {
.name = "Silicon Labs ",
- .caps = FE_CAN_FEC_1_2 |
+ /* For DVB-C */
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 7200000,
+ /* For DVB-T */
+ .frequency_stepsize = 166667,
+ .caps = FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 |
@@ -930,7 +1036,6 @@ static struct dvb_frontend_ops si2165_ops = {
FE_CAN_QAM_128 |
FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_MUTE_TS |
@@ -943,7 +1048,7 @@ static struct dvb_frontend_ops si2165_ops = {
.init = si2165_init,
.sleep = si2165_sleep,
- .set_frontend = si2165_set_parameters,
+ .set_frontend = si2165_set_frontend,
.read_status = si2165_read_status,
.release = si2165_release,
@@ -979,9 +1084,9 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
}
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &si2165_ops,
+ memcpy(&state->fe.ops, &si2165_ops,
sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
+ state->fe.demodulator_priv = state;
/* powerup */
io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
@@ -1033,20 +1138,22 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config,
KBUILD_MODNAME, chip_name, rev_char, state->chip_type,
state->chip_revcode);
- strlcat(state->frontend.ops.info.name, chip_name,
- sizeof(state->frontend.ops.info.name));
+ strlcat(state->fe.ops.info.name, chip_name,
+ sizeof(state->fe.ops.info.name));
n = 0;
if (state->has_dvbt) {
- state->frontend.ops.delsys[n++] = SYS_DVBT;
- strlcat(state->frontend.ops.info.name, " DVB-T",
- sizeof(state->frontend.ops.info.name));
+ state->fe.ops.delsys[n++] = SYS_DVBT;
+ strlcat(state->fe.ops.info.name, " DVB-T",
+ sizeof(state->fe.ops.info.name));
+ }
+ if (state->has_dvbc) {
+ state->fe.ops.delsys[n++] = SYS_DVBC_ANNEX_A;
+ strlcat(state->fe.ops.info.name, " DVB-C",
+ sizeof(state->fe.ops.info.name));
}
- if (state->has_dvbc)
- dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n",
- KBUILD_MODNAME);
- return &state->frontend;
+ return &state->fe;
error:
kfree(state);
diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c
index 4ef8a5c..c978c80 100644
--- a/drivers/media/dvb-frontends/stb6100.c
+++ b/drivers/media/dvb-frontends/stb6100.c
@@ -252,6 +252,7 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
int rc;
u8 f;
+ u32 bw;
struct stb6100_state *state = fe->tuner_priv;
rc = stb6100_read_reg(state, STB6100_F);
@@ -259,9 +260,9 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
return rc;
f = rc & STB6100_F_F;
- state->status.bandwidth = (f + 5) * 2000; /* x2 for ZIF */
+ bw = (f + 5) * 2000; /* x2 for ZIF */
- *bandwidth = state->bandwidth = state->status.bandwidth * 1000;
+ *bandwidth = state->bandwidth = bw * 1000;
dprintk(verbose, FE_DEBUG, 1, "bandwidth = %u Hz", state->bandwidth);
return 0;
}
@@ -495,68 +496,28 @@ static int stb6100_sleep(struct dvb_frontend *fe)
static int stb6100_init(struct dvb_frontend *fe)
{
struct stb6100_state *state = fe->tuner_priv;
- struct tuner_state *status = &state->status;
+ int refclk = 27000000; /* Hz */
- status->tunerstep = 125000;
- status->ifreq = 0;
- status->refclock = 27000000; /* Hz */
- status->iqsense = 1;
- status->bandwidth = 36000; /* kHz */
- state->bandwidth = status->bandwidth * 1000; /* Hz */
- state->reference = status->refclock / 1000; /* kHz */
+ /*
+ * iqsense = 1
+ * tunerstep = 125000
+ */
+ state->bandwidth = 36000000; /* Hz */
+ state->reference = refclk / 1000; /* kHz */
/* Set default bandwidth. Modified, PN 13-May-10 */
return 0;
}
-static int stb6100_get_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *state)
+static int stb6100_set_params(struct dvb_frontend *fe)
{
- switch (param) {
- case DVBFE_TUNER_FREQUENCY:
- stb6100_get_frequency(fe, &state->frequency);
- break;
- case DVBFE_TUNER_TUNERSTEP:
- break;
- case DVBFE_TUNER_IFFREQ:
- break;
- case DVBFE_TUNER_BANDWIDTH:
- stb6100_get_bandwidth(fe, &state->bandwidth);
- break;
- case DVBFE_TUNER_REFCLOCK:
- break;
- default:
- break;
- }
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- return 0;
-}
+ if (c->frequency > 0)
+ stb6100_set_frequency(fe, c->frequency);
-static int stb6100_set_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *state)
-{
- struct stb6100_state *tstate = fe->tuner_priv;
-
- switch (param) {
- case DVBFE_TUNER_FREQUENCY:
- stb6100_set_frequency(fe, state->frequency);
- tstate->frequency = state->frequency;
- break;
- case DVBFE_TUNER_TUNERSTEP:
- break;
- case DVBFE_TUNER_IFFREQ:
- break;
- case DVBFE_TUNER_BANDWIDTH:
- stb6100_set_bandwidth(fe, state->bandwidth);
- tstate->bandwidth = state->bandwidth;
- break;
- case DVBFE_TUNER_REFCLOCK:
- break;
- default:
- break;
- }
+ if (c->bandwidth_hz > 0)
+ stb6100_set_bandwidth(fe, c->bandwidth_hz);
return 0;
}
@@ -572,8 +533,9 @@ static struct dvb_tuner_ops stb6100_ops = {
.init = stb6100_init,
.sleep = stb6100_sleep,
.get_status = stb6100_get_status,
- .get_state = stb6100_get_state,
- .set_state = stb6100_set_state,
+ .set_params = stb6100_set_params,
+ .get_frequency = stb6100_get_frequency,
+ .get_bandwidth = stb6100_get_bandwidth,
.release = stb6100_release
};
diff --git a/drivers/media/dvb-frontends/stb6100.h b/drivers/media/dvb-frontends/stb6100.h
index 218c818..f7b468b 100644
--- a/drivers/media/dvb-frontends/stb6100.h
+++ b/drivers/media/dvb-frontends/stb6100.h
@@ -86,7 +86,6 @@ struct stb6100_state {
const struct stb6100_config *config;
struct dvb_tuner_ops ops;
struct dvb_frontend *frontend;
- struct tuner_state status;
u32 frequency;
u32 srate;
diff --git a/drivers/media/dvb-frontends/stb6100_cfg.h b/drivers/media/dvb-frontends/stb6100_cfg.h
index 6edc153..2ef67aa 100644
--- a/drivers/media/dvb-frontends/stb6100_cfg.h
+++ b/drivers/media/dvb-frontends/stb6100_cfg.h
@@ -19,20 +19,21 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
int err = 0;
- if (tuner_ops->get_state) {
- err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (tuner_ops->get_frequency) {
+ err = tuner_ops->get_frequency(fe, frequency);
if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
- *frequency = t_state.frequency;
}
return 0;
}
@@ -41,13 +42,16 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 bw = c->bandwidth_hz;
int err = 0;
- t_state.frequency = frequency;
+ c->frequency = frequency;
+ c->bandwidth_hz = 0; /* Don't adjust the bandwidth */
- if (tuner_ops->set_state) {
- err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (tuner_ops->set_params) {
+ err = tuner_ops->set_params(fe);
+ c->bandwidth_hz = bw;
if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
@@ -60,16 +64,14 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
int err = 0;
- if (tuner_ops->get_state) {
- err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+ if (tuner_ops->get_bandwidth) {
+ err = tuner_ops->get_bandwidth(fe, bandwidth);
if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
- *bandwidth = t_state.bandwidth;
}
return 0;
}
@@ -78,13 +80,16 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 freq = c->frequency;
int err = 0;
- t_state.bandwidth = bandwidth;
+ c->bandwidth_hz = bandwidth;
+ c->frequency = 0; /* Don't adjust the frequency */
- if (tuner_ops->set_state) {
- err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+ if (tuner_ops->set_params) {
+ err = tuner_ops->set_params(fe);
+ c->frequency = freq;
if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
diff --git a/drivers/media/dvb-frontends/stb6100_proc.h b/drivers/media/dvb-frontends/stb6100_proc.h
index bd8a0ec..50ffa21 100644
--- a/drivers/media/dvb-frontends/stb6100_proc.h
+++ b/drivers/media/dvb-frontends/stb6100_proc.h
@@ -17,27 +17,27 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/dvb/frontend.h>
+#include "dvb_frontend.h"
+
static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state state;
int err = 0;
- if (tuner_ops->get_state) {
+ if (tuner_ops->get_frequency) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
- err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+ err = tuner_ops->get_frequency(fe, frequency);
if (err < 0) {
- printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+ printk("%s: Invalid parameter\n", __func__);
return err;
}
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 0);
-
- *frequency = state.frequency;
}
return 0;
@@ -47,18 +47,21 @@ static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state state;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 bw = c->bandwidth_hz;
int err = 0;
- state.frequency = frequency;
+ c->frequency = frequency;
+ c->bandwidth_hz = 0; /* Don't adjust the bandwidth */
- if (tuner_ops->set_state) {
+ if (tuner_ops->set_params) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
- err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &state);
+ err = tuner_ops->set_params(fe);
+ c->bandwidth_hz = bw;
if (err < 0) {
- printk(KERN_ERR "%s: Invalid parameter\n", __func__);
+ printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -74,14 +77,13 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state state;
int err = 0;
- if (tuner_ops->get_state) {
+ if (tuner_ops->get_bandwidth) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
- err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+ err = tuner_ops->get_bandwidth(fe, bandwidth);
if (err < 0) {
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
return err;
@@ -89,8 +91,6 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 0);
-
- *bandwidth = state.bandwidth;
}
return 0;
@@ -100,16 +100,19 @@ static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state state;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u32 freq = c->frequency;
int err = 0;
- state.bandwidth = bandwidth;
+ c->bandwidth_hz = bandwidth;
+ c->frequency = 0; /* Don't adjust the frequency */
- if (tuner_ops->set_state) {
+ if (tuner_ops->set_params) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
- err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &state);
+ err = tuner_ops->set_params(fe);
+ c->frequency = freq;
if (err < 0) {
printk(KERN_ERR "%s: Invalid parameter\n", __func__);
return err;
diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c
index 63cc123..82f8cc5 100644
--- a/drivers/media/dvb-frontends/tda665x.c
+++ b/drivers/media/dvb-frontends/tda665x.c
@@ -66,26 +66,13 @@ exit:
return err;
}
-static int tda665x_get_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *tstate)
+static int tda665x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct tda665x_state *state = fe->tuner_priv;
- int err = 0;
- switch (param) {
- case DVBFE_TUNER_FREQUENCY:
- tstate->frequency = state->frequency;
- break;
- case DVBFE_TUNER_BANDWIDTH:
- break;
- default:
- printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
- err = -EINVAL;
- break;
- }
+ *frequency = state->frequency;
- return err;
+ return 0;
}
static int tda665x_get_status(struct dvb_frontend *fe, u32 *status)
@@ -111,9 +98,8 @@ exit:
return err;
}
-static int tda665x_set_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *tstate)
+static int tda665x_set_frequency(struct dvb_frontend *fe,
+ u32 new_frequency)
{
struct tda665x_state *state = fe->tuner_priv;
const struct tda665x_config *config = state->config;
@@ -121,88 +107,96 @@ static int tda665x_set_state(struct dvb_frontend *fe,
u8 buf[4];
int err = 0;
- if (param & DVBFE_TUNER_FREQUENCY) {
-
- frequency = tstate->frequency;
- if ((frequency < config->frequency_max) || (frequency > config->frequency_min)) {
- printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
- return -EINVAL;
- }
-
- frequency += config->frequency_offst;
- frequency *= config->ref_multiplier;
- frequency += config->ref_divider >> 1;
- frequency /= config->ref_divider;
-
- buf[0] = (u8) ((frequency & 0x7f00) >> 8);
- buf[1] = (u8) (frequency & 0x00ff) >> 0;
- buf[2] = 0x80 | 0x40 | 0x02;
- buf[3] = 0x00;
-
- /* restore frequency */
- frequency = tstate->frequency;
-
- if (frequency < 153000000) {
- /* VHF-L */
- buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
- if (frequency < 68000000)
- buf[3] |= 0x40; /* 83uA */
- if (frequency < 1040000000)
- buf[3] |= 0x60; /* 122uA */
- if (frequency < 1250000000)
- buf[3] |= 0x80; /* 163uA */
- else
- buf[3] |= 0xa0; /* 254uA */
- } else if (frequency < 438000000) {
- /* VHF-H */
- buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
- if (frequency < 230000000)
- buf[3] |= 0x40;
- if (frequency < 300000000)
- buf[3] |= 0x60;
- else
- buf[3] |= 0x80;
- } else {
- /* UHF */
- buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
- if (frequency < 470000000)
- buf[3] |= 0x60;
- if (frequency < 526000000)
- buf[3] |= 0x80;
- else
- buf[3] |= 0xa0;
- }
-
- /* Set params */
- err = tda665x_write(state, buf, 5);
- if (err < 0)
- goto exit;
-
- /* sleep for some time */
- printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
- msleep(20);
- /* check status */
- err = tda665x_get_status(fe, &status);
- if (err < 0)
- goto exit;
-
- if (status == 1) {
- printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n", __func__, status);
- state->frequency = frequency; /* cache successful state */
- } else {
- printk(KERN_ERR "%s: No Phase lock: status=%d\n", __func__, status);
- }
- } else {
- printk(KERN_ERR "%s: Unknown parameter (param=%d)\n", __func__, param);
+ if ((new_frequency < config->frequency_max)
+ || (new_frequency > config->frequency_min)) {
+ printk(KERN_ERR "%s: Frequency beyond limits, frequency=%d\n",
+ __func__, new_frequency);
return -EINVAL;
}
+ frequency = new_frequency;
+
+ frequency += config->frequency_offst;
+ frequency *= config->ref_multiplier;
+ frequency += config->ref_divider >> 1;
+ frequency /= config->ref_divider;
+
+ buf[0] = (u8) ((frequency & 0x7f00) >> 8);
+ buf[1] = (u8) (frequency & 0x00ff) >> 0;
+ buf[2] = 0x80 | 0x40 | 0x02;
+ buf[3] = 0x00;
+
+ /* restore frequency */
+ frequency = new_frequency;
+
+ if (frequency < 153000000) {
+ /* VHF-L */
+ buf[3] |= 0x01; /* fc, Low Band, 47 - 153 MHz */
+ if (frequency < 68000000)
+ buf[3] |= 0x40; /* 83uA */
+ if (frequency < 1040000000)
+ buf[3] |= 0x60; /* 122uA */
+ if (frequency < 1250000000)
+ buf[3] |= 0x80; /* 163uA */
+ else
+ buf[3] |= 0xa0; /* 254uA */
+ } else if (frequency < 438000000) {
+ /* VHF-H */
+ buf[3] |= 0x02; /* fc, Mid Band, 153 - 438 MHz */
+ if (frequency < 230000000)
+ buf[3] |= 0x40;
+ if (frequency < 300000000)
+ buf[3] |= 0x60;
+ else
+ buf[3] |= 0x80;
+ } else {
+ /* UHF */
+ buf[3] |= 0x04; /* fc, High Band, 438 - 862 MHz */
+ if (frequency < 470000000)
+ buf[3] |= 0x60;
+ if (frequency < 526000000)
+ buf[3] |= 0x80;
+ else
+ buf[3] |= 0xa0;
+ }
+
+ /* Set params */
+ err = tda665x_write(state, buf, 5);
+ if (err < 0)
+ goto exit;
+
+ /* sleep for some time */
+ printk(KERN_DEBUG "%s: Waiting to Phase LOCK\n", __func__);
+ msleep(20);
+ /* check status */
+ err = tda665x_get_status(fe, &status);
+ if (err < 0)
+ goto exit;
+
+ if (status == 1) {
+ printk(KERN_DEBUG "%s: Tuner Phase locked: status=%d\n",
+ __func__, status);
+ state->frequency = frequency; /* cache successful state */
+ } else {
+ printk(KERN_ERR "%s: No Phase lock: status=%d\n",
+ __func__, status);
+ }
+
return 0;
exit:
printk(KERN_ERR "%s: I/O Error\n", __func__);
return err;
}
+static int tda665x_set_params(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ tda665x_set_frequency(fe, c->frequency);
+
+ return 0;
+}
+
static int tda665x_release(struct dvb_frontend *fe)
{
struct tda665x_state *state = fe->tuner_priv;
@@ -213,10 +207,9 @@ static int tda665x_release(struct dvb_frontend *fe)
}
static struct dvb_tuner_ops tda665x_ops = {
-
- .set_state = tda665x_set_state,
- .get_state = tda665x_get_state,
.get_status = tda665x_get_status,
+ .set_params = tda665x_set_params,
+ .get_frequency = tda665x_get_frequency,
.release = tda665x_release
};
diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c
index 19c4888..3285b1b 100644
--- a/drivers/media/dvb-frontends/tda8261.c
+++ b/drivers/media/dvb-frontends/tda8261.c
@@ -83,88 +83,71 @@ static int tda8261_get_status(struct dvb_frontend *fe, u32 *status)
static const u32 div_tab[] = { 2000, 1000, 500, 250, 125 }; /* kHz */
static const u8 ref_div[] = { 0x00, 0x01, 0x02, 0x05, 0x07 };
-static int tda8261_get_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *tstate)
+static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct tda8261_state *state = fe->tuner_priv;
- int err = 0;
- switch (param) {
- case DVBFE_TUNER_FREQUENCY:
- tstate->frequency = state->frequency;
- break;
- case DVBFE_TUNER_BANDWIDTH:
- tstate->bandwidth = 40000000; /* FIXME! need to calculate Bandwidth */
- break;
- default:
- pr_err("%s: Unknown parameter (param=%d)\n", __func__, param);
- err = -EINVAL;
- break;
- }
+ *frequency = state->frequency;
- return err;
+ return 0;
}
-static int tda8261_set_state(struct dvb_frontend *fe,
- enum tuner_param param,
- struct tuner_state *tstate)
+static int tda8261_set_params(struct dvb_frontend *fe)
{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct tda8261_state *state = fe->tuner_priv;
const struct tda8261_config *config = state->config;
u32 frequency, N, status = 0;
u8 buf[4];
int err = 0;
- if (param & DVBFE_TUNER_FREQUENCY) {
- /**
- * N = Max VCO Frequency / Channel Spacing
- * Max VCO Frequency = VCO frequency + (channel spacing - 1)
- * (to account for half channel spacing on either side)
- */
- frequency = tstate->frequency;
- if ((frequency < 950000) || (frequency > 2150000)) {
- pr_warn("%s: Frequency beyond limits, frequency=%d\n", __func__, frequency);
- return -EINVAL;
- }
- N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
- pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
- __func__, config->step_size, div_tab[config->step_size], N, N);
-
- buf[0] = (N >> 8) & 0xff;
- buf[1] = N & 0xff;
- buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
-
- if (frequency < 1450000)
- buf[3] = 0x00;
- else if (frequency < 2000000)
- buf[3] = 0x40;
- else if (frequency < 2150000)
- buf[3] = 0x80;
-
- /* Set params */
- if ((err = tda8261_write(state, buf)) < 0) {
- pr_err("%s: I/O Error\n", __func__);
- return err;
- }
- /* sleep for some time */
- pr_debug("%s: Waiting to Phase LOCK\n", __func__);
- msleep(20);
- /* check status */
- if ((err = tda8261_get_status(fe, &status)) < 0) {
- pr_err("%s: I/O Error\n", __func__);
- return err;
- }
- if (status == 1) {
- pr_debug("%s: Tuner Phase locked: status=%d\n", __func__, status);
- state->frequency = frequency; /* cache successful state */
- } else {
- pr_debug("%s: No Phase lock: status=%d\n", __func__, status);
- }
- } else {
- pr_err("%s: Unknown parameter (param=%d)\n", __func__, param);
+ /*
+ * N = Max VCO Frequency / Channel Spacing
+ * Max VCO Frequency = VCO frequency + (channel spacing - 1)
+ * (to account for half channel spacing on either side)
+ */
+ frequency = c->frequency;
+ if ((frequency < 950000) || (frequency > 2150000)) {
+ pr_warn("%s: Frequency beyond limits, frequency=%d\n",
+ __func__, frequency);
return -EINVAL;
}
+ N = (frequency + (div_tab[config->step_size] - 1)) / div_tab[config->step_size];
+ pr_debug("%s: Step size=%d, Divider=%d, PG=0x%02x (%d)\n",
+ __func__, config->step_size, div_tab[config->step_size], N, N);
+
+ buf[0] = (N >> 8) & 0xff;
+ buf[1] = N & 0xff;
+ buf[2] = (0x01 << 7) | ((ref_div[config->step_size] & 0x07) << 1);
+
+ if (frequency < 1450000)
+ buf[3] = 0x00;
+ else if (frequency < 2000000)
+ buf[3] = 0x40;
+ else if (frequency < 2150000)
+ buf[3] = 0x80;
+
+ /* Set params */
+ err = tda8261_write(state, buf);
+ if (err < 0) {
+ pr_err("%s: I/O Error\n", __func__);
+ return err;
+ }
+ /* sleep for some time */
+ pr_debug("%s: Waiting to Phase LOCK\n", __func__);
+ msleep(20);
+ /* check status */
+ if ((err = tda8261_get_status(fe, &status)) < 0) {
+ pr_err("%s: I/O Error\n", __func__);
+ return err;
+ }
+ if (status == 1) {
+ pr_debug("%s: Tuner Phase locked: status=%d\n", __func__,
+ status);
+ state->frequency = frequency; /* cache successful state */
+ } else {
+ pr_debug("%s: No Phase lock: status=%d\n", __func__, status);
+ }
return 0;
}
@@ -182,14 +165,13 @@ static struct dvb_tuner_ops tda8261_ops = {
.info = {
.name = "TDA8261",
-// .tuner_name = NULL,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_step = 0
},
- .set_state = tda8261_set_state,
- .get_state = tda8261_get_state,
+ .set_params = tda8261_set_params,
+ .get_frequency = tda8261_get_frequency,
.get_status = tda8261_get_status,
.release = tda8261_release
};
@@ -210,10 +192,7 @@ struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe,
fe->ops.tuner_ops = tda8261_ops;
fe->ops.tuner_ops.info.frequency_step = div_tab[config->step_size];
-// fe->ops.tuner_ops.tuner_name = &config->buf;
-// printk("%s: Attaching %s TDA8261 8PSK/QPSK tuner\n",
-// __func__, fe->ops.tuner_ops.tuner_name);
pr_info("%s: Attaching TDA8261 8PSK/QPSK tuner\n", __func__);
return fe;
diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
index 04a19e1..fe527ff 100644
--- a/drivers/media/dvb-frontends/tda8261_cfg.h
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
@@ -21,17 +21,15 @@ static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
int err = 0;
- if (tuner_ops->get_state) {
- err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (tuner_ops->get_frequency) {
+ err = tuner_ops->get_frequency(fe, frequency);
if (err < 0) {
- printk("%s: Invalid parameter\n", __func__);
+ pr_err("%s: Invalid parameter\n", __func__);
return err;
}
- *frequency = t_state.frequency;
- printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+ pr_debug("%s: Frequency=%d\n", __func__, *frequency);
}
return 0;
}
@@ -40,37 +38,24 @@ static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
struct dvb_frontend_ops *frontend_ops = &fe->ops;
struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int err = 0;
- t_state.frequency = frequency;
-
- if (tuner_ops->set_state) {
- err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (tuner_ops->set_params) {
+ err = tuner_ops->set_params(fe);
if (err < 0) {
- printk("%s: Invalid parameter\n", __func__);
+ pr_err("%s: Invalid parameter\n", __func__);
return err;
}
}
- printk("%s: Frequency=%d\n", __func__, t_state.frequency);
+ pr_debug("%s: Frequency=%d\n", __func__, c->frequency);
return 0;
}
static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
- struct dvb_frontend_ops *frontend_ops = &fe->ops;
- struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
- struct tuner_state t_state;
- int err = 0;
+ /* FIXME! need to calculate Bandwidth */
+ *bandwidth = 40000000;
- if (tuner_ops->get_state) {
- err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
- if (err < 0) {
- printk("%s: Invalid parameter\n", __func__);
- return err;
- }
- *bandwidth = t_state.bandwidth;
- printk("%s: Bandwidth=%d\n", __func__, t_state.bandwidth);
- }
return 0;
}
diff --git a/drivers/media/dvb-frontends/tdhd1.h b/drivers/media/dvb-frontends/tdhd1.h
index 1775098..2b9e873 100644
--- a/drivers/media/dvb-frontends/tdhd1.h
+++ b/drivers/media/dvb-frontends/tdhd1.h
@@ -20,7 +20,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * The project's page is at http://www.linuxtv.org
+ * The project's page is at https://linuxtv.org
*/
#ifndef TDHD1_H
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 521bbf1..993dc50 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -83,6 +83,16 @@ config VIDEO_MSP3400
To compile this driver as a module, choose M here: the
module will be called msp3400.
+config VIDEO_CS3308
+ tristate "Cirrus Logic CS3308 audio ADC"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Cirrus Logic CS3308 High Performance 8-Channel
+ Analog Volume Control
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs3308.
+
config VIDEO_CS5345
tristate "Cirrus Logic CS5345 audio ADC"
depends on VIDEO_V4L2 && I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 07db257..94f2c99 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o
obj-$(CONFIG_VIDEO_TW2804) += tw2804.o
obj-$(CONFIG_VIDEO_TW9903) += tw9903.o
obj-$(CONFIG_VIDEO_TW9906) += tw9906.o
+obj-$(CONFIG_VIDEO_CS3308) += cs3308.o
obj-$(CONFIG_VIDEO_CS5345) += cs5345.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 69094ab..0494a78 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -35,7 +35,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-dv-timings.h>
#include <media/v4l2-ctrls.h>
-#include <media/ad9389b.h>
+#include <media/i2c/ad9389b.h>
static int debug;
module_param(debug, int, 0644);
diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c
index 5dd3977..f00745b 100644
--- a/drivers/media/i2c/adp1653.c
+++ b/drivers/media/i2c/adp1653.c
@@ -37,7 +37,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/gpio/consumer.h>
-#include <media/adp1653.h>
+#include <media/i2c/adp1653.h>
#include <media/v4l2-device.h>
#define TIMEOUT_MAX 820000
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index f82c8aa..3c3c4bf 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1112,7 +1112,7 @@ static int init_device(struct adv7180_state *state)
mutex_lock(&state->mutex);
adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
- usleep_range(2000, 10000);
+ usleep_range(5000, 10000);
ret = state->chip_info->init(state);
if (ret)
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index e2dd161..2bec737 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -27,7 +27,7 @@
#include <linux/types.h>
#include <linux/videodev2.h>
-#include <media/adv7183.h>
+#include <media/i2c/adv7183.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c
index f89d0af..11f9029 100644
--- a/drivers/media/i2c/adv7343.c
+++ b/drivers/media/i2c/adv7343.c
@@ -28,7 +28,7 @@
#include <linux/of.h>
#include <linux/of_graph.h>
-#include <media/adv7343.h>
+#include <media/i2c/adv7343.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c
index 0215f95..76d9874 100644
--- a/drivers/media/i2c/adv7393.c
+++ b/drivers/media/i2c/adv7393.c
@@ -31,7 +31,7 @@
#include <linux/videodev2.h>
#include <linux/uaccess.h>
-#include <media/adv7393.h>
+#include <media/i2c/adv7393.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index e4900df..eeb2cd8 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -32,7 +32,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dv-timings.h>
-#include <media/adv7511.h>
+#include <media/i2c/adv7511.h>
static int debug;
module_param(debug, int, 0644);
@@ -1116,7 +1116,7 @@ static int adv7511_set_fmt(struct v4l2_subdev *sd,
adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2));
- adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4);
+ adv7511_wr_and_or(sd, 0x59, 0x3f, yq << 6);
adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
return 0;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 5631ec0..7452862 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -39,7 +39,7 @@
#include <linux/workqueue.h>
#include <linux/regmap.h>
-#include <media/adv7604.h>
+#include <media/i2c/adv7604.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-event.h>
@@ -905,7 +905,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
- is_digital_input(sd) ? 250000 : 1000000))
+ is_digital_input(sd) ? 250000 : 1000000, false))
continue;
io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
@@ -1479,7 +1479,7 @@ static void adv76xx_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
for (i = 0; adv76xx_timings[i].bt.width; i++) {
if (v4l2_match_dv_timings(timings, &adv76xx_timings[i],
- is_digital_input(sd) ? 250000 : 1000000)) {
+ is_digital_input(sd) ? 250000 : 1000000, false)) {
*timings = adv76xx_timings[i];
break;
}
@@ -1644,7 +1644,7 @@ static int adv76xx_s_dv_timings(struct v4l2_subdev *sd,
if (!timings)
return -EINVAL;
- if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+ if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
return 0;
}
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index b7269b8..69378e4 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -43,7 +43,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dv-timings.h>
-#include <media/adv7842.h>
+#include <media/i2c/adv7842.h>
static int debug;
module_param(debug, int, 0644);
@@ -155,7 +155,7 @@ static bool adv7842_check_dv_timings(const struct v4l2_dv_timings *t, void *hdl)
int i;
for (i = 0; adv7842_timings_exceptions[i].bt.width; i++)
- if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0))
+ if (v4l2_match_dv_timings(t, adv7842_timings_exceptions + i, 0, false))
return false;
return true;
}
@@ -1008,7 +1008,7 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
- is_digital_input(sd) ? 250000 : 1000000))
+ is_digital_input(sd) ? 250000 : 1000000, false))
continue;
/* video std */
io_write(sd, 0x00, predef_vid_timings[i].vid_std);
@@ -1659,7 +1659,7 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd,
if (state->mode == ADV7842_MODE_SDP)
return -ENODATA;
- if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+ if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
return 0;
}
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index d3b965e..d9f2b6b 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -15,7 +15,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <media/ak881x.h>
+#include <media/i2c/ak881x.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/as3645a.c b/drivers/media/i2c/as3645a.c
index 301084b..29a2e70 100644
--- a/drivers/media/i2c/as3645a.c
+++ b/drivers/media/i2c/as3645a.c
@@ -31,7 +31,7 @@
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <media/as3645a.h>
+#include <media/i2c/as3645a.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
index e00e310..7907bcf 100644
--- a/drivers/media/i2c/bt819.c
+++ b/drivers/media/i2c/bt819.c
@@ -37,7 +37,7 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/bt819.h>
+#include <media/i2c/bt819.h>
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
diff --git a/drivers/media/i2c/cs3308.c b/drivers/media/i2c/cs3308.c
new file mode 100644
index 0000000..d28b4f3
--- /dev/null
+++ b/drivers/media/i2c/cs3308.c
@@ -0,0 +1,138 @@
+/*
+ * Cirrus Logic cs3308 8-Channel Analog Volume Control
+ *
+ * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+ * Copyright (C) 2012 Steven Toth <stoth@kernellabs.com>
+ *
+ * Derived from cs5345.c Copyright (C) 2007 Hans Verkuil
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+
+MODULE_DESCRIPTION("i2c device driver for cs3308 8-channel volume control");
+MODULE_AUTHOR("Devin Heitmueller");
+MODULE_LICENSE("GPL");
+
+static inline int cs3308_write(struct v4l2_subdev *sd, u8 reg, u8 value)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static inline int cs3308_read(struct v4l2_subdev *sd, u8 reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ return i2c_smbus_read_byte_data(client, reg);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int cs3308_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
+{
+ reg->val = cs3308_read(sd, reg->reg & 0xffff);
+ reg->size = 1;
+ return 0;
+}
+
+static int cs3308_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
+{
+ cs3308_write(sd, reg->reg & 0xffff, reg->val & 0xff);
+ return 0;
+}
+#endif
+
+/* ----------------------------------------------------------------------- */
+
+static const struct v4l2_subdev_core_ops cs3308_core_ops = {
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = cs3308_g_register,
+ .s_register = cs3308_s_register,
+#endif
+};
+
+static const struct v4l2_subdev_ops cs3308_ops = {
+ .core = &cs3308_core_ops,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static int cs3308_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct v4l2_subdev *sd;
+ unsigned i;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ if ((i2c_smbus_read_byte_data(client, 0x1c) & 0xf0) != 0xe0)
+ return -ENODEV;
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n",
+ client->addr << 1, client->adapter->name);
+
+ sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
+ if (sd == NULL)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(sd, client, &cs3308_ops);
+
+ /* Set some reasonable defaults */
+ cs3308_write(sd, 0x0d, 0x00); /* Power up all channels */
+ cs3308_write(sd, 0x0e, 0x00); /* Master Power */
+ cs3308_write(sd, 0x0b, 0x00); /* Device Configuration */
+ /* Set volume for each channel */
+ for (i = 1; i <= 8; i++)
+ cs3308_write(sd, i, 0xd2);
+ cs3308_write(sd, 0x0a, 0x00); /* Unmute all channels */
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int cs3308_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(sd);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static const struct i2c_device_id cs3308_id[] = {
+ { "cs3308", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs3308_id);
+
+static struct i2c_driver cs3308_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cs3308",
+ },
+ .probe = cs3308_probe,
+ .remove = cs3308_remove,
+ .id_table = cs3308_id,
+};
+
+module_i2c_driver(cs3308_driver);
diff --git a/drivers/media/i2c/cx25840/cx25840-audio.c b/drivers/media/i2c/cx25840/cx25840-audio.c
index 34b96c7..baf3d9c 100644
--- a/drivers/media/i2c/cx25840/cx25840-audio.c
+++ b/drivers/media/i2c/cx25840/cx25840-audio.c
@@ -19,7 +19,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include "cx25840-core.h"
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index fe6eb78..f2e2c34 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -45,7 +45,7 @@
#include <linux/delay.h>
#include <linux/math64.h>
#include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include "cx25840-core.h"
@@ -559,7 +559,10 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x414, 0x00107d12);
/* Chroma */
- cx25840_write4(client, 0x420, 0x3d008282);
+ if (is_cx23888(state))
+ cx25840_write4(client, 0x418, 0x1d008282);
+ else
+ cx25840_write4(client, 0x420, 0x3d008282);
/*
* Aux PLL
@@ -666,14 +669,17 @@ static void cx23885_initialize(struct i2c_client *client)
cx25840_write4(client, 0x404, 0x0010253e);
/* CC on - Undocumented Register */
- cx25840_write(client, 0x42f, 0x66);
+ cx25840_write(client, state->vbi_regs_offset + 0x42f, 0x66);
/* HVR-1250 / HVR1850 DIF related */
/* Power everything up */
cx25840_write4(client, 0x130, 0x0);
/* Undocumented */
- cx25840_write4(client, 0x478, 0x6628021F);
+ if (is_cx23888(state))
+ cx25840_write4(client, 0x454, 0x6628021F);
+ else
+ cx25840_write4(client, 0x478, 0x6628021F);
/* AFE_CLK_OUT_CTRL - Select the clock output source as output */
cx25840_write4(client, 0x144, 0x5);
@@ -1106,31 +1112,15 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
cx25840_write4(client, 0x410, 0xffff0dbf);
cx25840_write4(client, 0x414, 0x00137d03);
- /* on the 887, 0x418 is HSCALE_CTRL, on the 888 it is
- CHROMA_CTRL */
- if (is_cx23888(state))
- cx25840_write4(client, 0x418, 0x01008080);
- else
- cx25840_write4(client, 0x418, 0x01000000);
+ cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000);
+ cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b);
+ cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000);
- cx25840_write4(client, 0x41c, 0x00000000);
-
- /* on the 887, 0x420 is CHROMA_CTRL, on the 888 it is
- CRUSH_CTRL */
- if (is_cx23888(state))
- cx25840_write4(client, 0x420, 0x001c3e0f);
- else
- cx25840_write4(client, 0x420, 0x001c8282);
-
- cx25840_write4(client, 0x42c, 0x42600000);
- cx25840_write4(client, 0x430, 0x0000039b);
- cx25840_write4(client, 0x438, 0x00000000);
-
- cx25840_write4(client, 0x440, 0xF8E3E824);
- cx25840_write4(client, 0x444, 0x401040dc);
- cx25840_write4(client, 0x448, 0xcd3f02a0);
- cx25840_write4(client, 0x44c, 0x161f1000);
- cx25840_write4(client, 0x450, 0x00000802);
+ cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824);
+ cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc);
+ cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0);
+ cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000);
+ cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802);
cx25840_write4(client, 0x91c, 0x01000000);
cx25840_write4(client, 0x8e0, 0x03063870);
@@ -1400,8 +1390,14 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
Vlines = fmt->height + (is_50Hz ? 4 : 7);
+ /*
+ * We keep 1 margin for the Vsrc < Vlines check since the
+ * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC
+ * height. Without that margin the cx23885 fails in this
+ * check.
+ */
if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) {
v4l_err(client, "%dx%d is not a valid size!\n",
fmt->width, fmt->height);
return -ERANGE;
@@ -1426,14 +1422,20 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd,
fmt->width, fmt->height, HSC, VSC);
/* HSCALE=HSC */
- cx25840_write(client, 0x418, HSC & 0xff);
- cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
- cx25840_write(client, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx25840_write(client, 0x41c, VSC & 0xff);
- cx25840_write(client, 0x41d, VSC >> 8);
- /* VS_INTRLACE=1 VFILT=filter */
- cx25840_write(client, 0x41e, 0x8 | filter);
+ if (is_cx23888(state)) {
+ cx25840_write4(client, 0x434, HSC | (1 << 24));
+ /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */
+ cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16));
+ } else {
+ cx25840_write(client, 0x418, HSC & 0xff);
+ cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+ cx25840_write(client, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx25840_write(client, 0x41c, VSC & 0xff);
+ cx25840_write(client, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx25840_write(client, 0x41e, 0x8 | filter);
+ }
return 0;
}
@@ -1714,26 +1716,27 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
v4l_dbg(1, cx25840_debug, client, "%s video output\n",
enable ? "enable" : "disable");
+
+ /*
+ * It's not clear what should be done for these devices.
+ * The original code used the same addresses as for the cx25840, but
+ * those addresses do something else entirely on the cx2388x and
+ * cx231xx. Since it never did anything in the first place, just do
+ * nothing.
+ */
+ if (is_cx2388x(state) || is_cx231xx(state))
+ return 0;
+
if (enable) {
- if (is_cx2388x(state) || is_cx231xx(state)) {
- v = cx25840_read(client, 0x421) | 0x0b;
- cx25840_write(client, 0x421, v);
- } else {
- v = cx25840_read(client, 0x115) | 0x0c;
- cx25840_write(client, 0x115, v);
- v = cx25840_read(client, 0x116) | 0x04;
- cx25840_write(client, 0x116, v);
- }
+ v = cx25840_read(client, 0x115) | 0x0c;
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) | 0x04;
+ cx25840_write(client, 0x116, v);
} else {
- if (is_cx2388x(state) || is_cx231xx(state)) {
- v = cx25840_read(client, 0x421) & ~(0x0b);
- cx25840_write(client, 0x421, v);
- } else {
- v = cx25840_read(client, 0x115) & ~(0x0c);
- cx25840_write(client, 0x115, v);
- v = cx25840_read(client, 0x116) & ~(0x04);
- cx25840_write(client, 0x116, v);
- }
+ v = cx25840_read(client, 0x115) & ~(0x0c);
+ cx25840_write(client, 0x115, v);
+ v = cx25840_read(client, 0x116) & ~(0x04);
+ cx25840_write(client, 0x116, v);
}
return 0;
}
@@ -4974,7 +4977,7 @@ static void cx23888_std_setup(struct i2c_client *client)
cx25840_write4(client, 0x4b4, 0x20524030);
cx25840_write4(client, 0x47c, 0x010a8263);
- if (std & V4L2_STD_NTSC) {
+ if (std & V4L2_STD_525_60) {
v4l_dbg(1, cx25840_debug, client, "%s() Selecting NTSC",
__func__);
@@ -5264,6 +5267,8 @@ static int cx25840_probe(struct i2c_client *client,
state->vbi_line_offset = 8;
state->id = id;
state->rev = device_id;
+ state->vbi_regs_offset = id == CX23888_AV ? 0x500 - 0x424 : 0;
+ state->std = V4L2_STD_NTSC_M;
v4l2_ctrl_handler_init(&state->hdl, 9);
v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h
index fdea48c..254ef45 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.h
+++ b/drivers/media/i2c/cx25840/cx25840-core.h
@@ -69,6 +69,7 @@ struct cx25840_state {
enum cx25840_model id;
u32 rev;
int is_initialized;
+ unsigned vbi_regs_offset;
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
struct work_struct fw_work; /* work entry for fw load */
struct cx25840_ir_state *ir_state;
diff --git a/drivers/media/i2c/cx25840/cx25840-firmware.c b/drivers/media/i2c/cx25840/cx25840-firmware.c
index 9bbb31a..37e0529 100644
--- a/drivers/media/i2c/cx25840/cx25840-firmware.c
+++ b/drivers/media/i2c/cx25840/cx25840-firmware.c
@@ -19,7 +19,7 @@
#include <linux/i2c.h>
#include <linux/firmware.h>
#include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include "cx25840-core.h"
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 4cf8f18..4b78201 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <linux/module.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include <media/rc-core.h>
#include "cx25840-core.h"
diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c
index c39e91d..0470bb6 100644
--- a/drivers/media/i2c/cx25840/cx25840-vbi.c
+++ b/drivers/media/i2c/cx25840/cx25840-vbi.c
@@ -19,7 +19,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include "cx25840-core.h"
@@ -104,7 +104,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
if (is_pal) {
for (i = 7; i <= 23; i++) {
- u8 v = cx25840_read(client, 0x424 + i - 7);
+ u8 v = cx25840_read(client,
+ state->vbi_regs_offset + 0x424 + i - 7);
svbi->service_lines[0][i] = lcr2vbi[v >> 4];
svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -113,7 +114,8 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
}
} else {
for (i = 10; i <= 21; i++) {
- u8 v = cx25840_read(client, 0x424 + i - 10);
+ u8 v = cx25840_read(client,
+ state->vbi_regs_offset + 0x424 + i - 10);
svbi->service_lines[0][i] = lcr2vbi[v >> 4];
svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -135,7 +137,10 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
cx25840_std_setup(client);
/* VBI Offset */
- cx25840_write(client, 0x47f, vbi_offset);
+ if (is_cx23888(state))
+ cx25840_write(client, 0x54f, vbi_offset);
+ else
+ cx25840_write(client, 0x47f, vbi_offset);
cx25840_write(client, 0x404, 0x2e);
return 0;
}
@@ -158,7 +163,10 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
/* Sliced VBI */
cx25840_write(client, 0x404, 0x32); /* Ancillary data */
cx25840_write(client, 0x406, 0x13);
- cx25840_write(client, 0x47f, vbi_offset);
+ if (is_cx23888(state))
+ cx25840_write(client, 0x54f, vbi_offset);
+ else
+ cx25840_write(client, 0x47f, vbi_offset);
if (is_pal) {
for (i = 0; i <= 6; i++)
@@ -194,17 +202,23 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
}
if (is_pal) {
- for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+ for (x = 1, i = state->vbi_regs_offset + 0x424;
+ i <= state->vbi_regs_offset + 0x434; i++, x++)
cx25840_write(client, i, lcr[6 + x]);
} else {
- for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+ for (x = 1, i = state->vbi_regs_offset + 0x424;
+ i <= state->vbi_regs_offset + 0x430; i++, x++)
cx25840_write(client, i, lcr[9 + x]);
- for (i = 0x431; i <= 0x434; i++)
+ for (i = state->vbi_regs_offset + 0x431;
+ i <= state->vbi_regs_offset + 0x434; i++)
cx25840_write(client, i, 0);
}
- cx25840_write(client, 0x43c, 0x16);
- cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
+ cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16);
+ if (is_cx23888(state))
+ cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22);
+ else
+ cx25840_write(client, 0x474, is_pal ? 0x2a : 0x22);
return 0;
}
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 728d2cc..8304919 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -47,7 +47,7 @@
#include <linux/workqueue.h>
#include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
/* ----------------------------------------------------------------------- */
/* insmod parameters */
diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c
index d9ece4b..19ecb88 100644
--- a/drivers/media/i2c/lm3560.c
+++ b/drivers/media/i2c/lm3560.c
@@ -24,7 +24,7 @@
#include <linux/mutex.h>
#include <linux/regmap.h>
#include <linux/videodev2.h>
-#include <media/lm3560.h>
+#include <media/i2c/lm3560.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/lm3646.c b/drivers/media/i2c/lm3646.c
index 626fb46..7fbe6ff 100644
--- a/drivers/media/i2c/lm3646.c
+++ b/drivers/media/i2c/lm3646.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include <linux/regmap.h>
#include <linux/videodev2.h>
-#include <media/lm3646.h>
+#include <media/i2c/lm3646.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c
index 77eb07e..81171d8 100644
--- a/drivers/media/i2c/m52790.c
+++ b/drivers/media/i2c/m52790.c
@@ -27,7 +27,7 @@
#include <asm/uaccess.h>
#include <linux/i2c.h>
#include <linux/videodev2.h>
-#include <media/m52790.h>
+#include <media/i2c/m52790.h>
#include <media/v4l2-device.h>
MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
index 1a03d02..a0cd6dc 100644
--- a/drivers/media/i2c/m5mols/m5mols_capture.c
+++ b/drivers/media/i2c/m5mols/m5mols_capture.c
@@ -25,8 +25,8 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include <media/m5mols.h>
-#include <media/exynos-fimc.h>
+#include <media/i2c/m5mols.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "m5mols.h"
#include "m5mols_reg.h"
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 6404c0d..f899393 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -25,7 +25,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include <media/m5mols.h>
+#include <media/i2c/m5mols.h>
#include "m5mols.h"
#include "m5mols_reg.h"
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index bdb9400..a84561d 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -56,8 +56,8 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/msp3400.h>
-#include <media/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/tvaudio.h>
#include "msp3400-driver.h"
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/msp3400-driver.h b/drivers/media/i2c/msp3400-driver.h
index fbe5e07..6cae213 100644
--- a/drivers/media/i2c/msp3400-driver.h
+++ b/drivers/media/i2c/msp3400-driver.h
@@ -4,7 +4,7 @@
#ifndef MSP3400_DRIVER_H
#define MSP3400_DRIVER_H
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c
index f8b5171..1712080 100644
--- a/drivers/media/i2c/msp3400-kthreads.c
+++ b/drivers/media/i2c/msp3400-kthreads.c
@@ -26,7 +26,7 @@
#include <linux/freezer.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <linux/kthread.h>
#include <linux/suspend.h>
#include "msp3400-driver.h"
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index c7747bd..101cb26 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -31,7 +31,7 @@
#include <linux/v4l2-mediabus.h>
#include <media/media-entity.h>
-#include <media/mt9m032.h>
+#include <media/i2c/mt9m032.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
@@ -671,7 +671,7 @@ static int mt9m032_set_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9m032_ctrl_ops = {
.s_ctrl = mt9m032_set_ctrl,
.try_ctrl = mt9m032_try_ctrl,
};
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 0db15f5..a3da0e9 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
-#include <media/mt9p031.h>
+#include <media/i2c/mt9p031.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -817,7 +817,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9p031_ctrl_ops = {
.s_ctrl = mt9p031_s_ctrl,
};
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index 8ae99f7..b28fdff 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -21,7 +21,7 @@
#include <linux/videodev2.h>
#include <linux/v4l2-mediabus.h>
-#include <media/mt9t001.h>
+#include <media/i2c/mt9t001.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
@@ -626,7 +626,7 @@ static int mt9t001_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9t001_ctrl_ops = {
.s_ctrl = mt9t001_s_ctrl,
};
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index a4a5c39..b9fea11 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -13,7 +13,7 @@
#include <asm/div64.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/mt9v011.h>
+#include <media/i2c/mt9v011.h>
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
MODULE_AUTHOR("Mauro Carvalho Chehab");
@@ -454,7 +454,7 @@ static int mt9v011_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9v011_ctrl_ops = {
.s_ctrl = mt9v011_s_ctrl,
};
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index a68ce94..1dbbd23 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -25,7 +25,7 @@
#include <linux/v4l2-mediabus.h>
#include <linux/module.h>
-#include <media/mt9v032.h>
+#include <media/i2c/mt9v032.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-of.h>
@@ -703,7 +703,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
+static const struct v4l2_ctrl_ops mt9v032_ctrl_ops = {
.s_ctrl = mt9v032_s_ctrl,
};
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index f197b6c..69e4f30 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -18,7 +18,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
-#include <media/noon010pc30.h>
+#include <media/i2c/noon010pc30.h>
#include <linux/videodev2.h>
#include <linux/module.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c
index 49109f4..82c7ac1 100644
--- a/drivers/media/i2c/ov2659.c
+++ b/drivers/media/i2c/ov2659.c
@@ -37,7 +37,7 @@
#include <linux/videodev2.h>
#include <media/media-entity.h>
-#include <media/ov2659.h>
+#include <media/i2c/ov2659.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -1249,7 +1249,7 @@ static int ov2659_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static struct v4l2_ctrl_ops ov2659_ctrl_ops = {
+static const struct v4l2_ctrl_ops ov2659_ctrl_ops = {
.s_ctrl = ov2659_s_ctrl,
};
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index e1b5dc8..56cfb5c 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -20,7 +20,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-image-sizes.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 1ee6a55..9fe9006 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -29,7 +29,7 @@
#include <media/v4l2-image-sizes.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/ov9650.h>
+#include <media/i2c/ov9650.h>
static int debug;
module_param(debug, int, 0644);
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
index 51b2601..25f5e79 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c
@@ -34,7 +34,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
#include <media/v4l2-of.h>
#include "s5c73m3.h"
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index 8001cde..0a06033 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -32,7 +32,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
#include "s5c73m3.h"
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
index 72ef9f9..7d65b36 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-spi.c
@@ -37,6 +37,7 @@ enum spi_direction {
SPI_DIR_RX,
SPI_DIR_TX
};
+MODULE_DEVICE_TABLE(of, s5c73m3_spi_ids);
static int spi_xmit(struct spi_device *spi_dev, void *addr, const int len,
enum spi_direction dir)
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index 13aed59..653f68e 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -23,7 +23,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/s5c73m3.h>
+#include <media/i2c/s5c73m3.h>
#define DRIVER_NAME "S5C73M3"
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 9708423..6757aca 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -27,7 +27,7 @@
#include <asm/unaligned.h>
#include <media/media-entity.h>
-#include <media/s5k4ecgx.h>
+#include <media/i2c/s5k4ecgx.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index d0ad6a2..60aaff7 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -28,7 +28,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5k6aa.h>
+#include <media/i2c/s5k6aa.h>
static int debug;
module_param(debug, int, 0644);
diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c
index 37e65f6..89e458c 100644
--- a/drivers/media/i2c/saa6588.c
+++ b/drivers/media/i2c/saa6588.c
@@ -31,7 +31,7 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 91e7522..24d2b76 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -46,7 +46,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <asm/div64.h>
#define VRES_60HZ (480+16)
diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c
index a43d96d..8d94dcb 100644
--- a/drivers/media/i2c/saa7127.c
+++ b/drivers/media/i2c/saa7127.c
@@ -54,7 +54,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
static int debug;
static int test_image;
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index ed010a8..f6af0cc 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -22,7 +22,7 @@
#include <linux/mutex.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-subdev.h>
-#include <media/smiapp.h>
+#include <media/i2c/smiapp.h>
#include "smiapp-pll.h"
#include "smiapp-reg.h"
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index 4fbdd1e..2e14e52 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 2f35d31..6a1b2a9 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -25,7 +25,7 @@
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
-#include <media/mt9t112.h>
+#include <media/i2c/mt9t112.h>
#include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index f313774..c2ba1fb 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -15,9 +15,9 @@
#include <linux/log2.h>
#include <linux/module.h>
-#include <media/mt9v022.h>
+#include <media/i2c/mt9v022.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index f150a8b..a43410c 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -24,7 +24,7 @@
#include <linux/v4l2-mediabus.h>
#include <linux/videodev2.h>
-#include <media/ov772x.h>
+#include <media/i2c/ov772x.h>
#include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
index c769cf6..aa7bfbb 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -15,7 +15,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <media/rj54n1cb0c.h>
+#include <media/i2c/rj54n1cb0c.h>
#include <media/soc_camera.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index e939c24..06aff81 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -26,7 +26,7 @@
#include <linux/videodev2.h>
#include <media/soc_camera.h>
-#include <media/tw9910.h>
+#include <media/i2c/tw9910.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index b04c09d..0bf031b 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -24,7 +24,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-ctrls.h>
-#include <media/sr030pc30.h>
+#include <media/i2c/sr030pc30.h>
static int debug;
module_param(debug, int, 0644);
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 9ef5baa..77b8011 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -42,7 +42,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-of.h>
-#include <media/tc358743.h>
+#include <media/i2c/tc358743.h>
#include "tc358743_regs.h"
@@ -862,7 +862,7 @@ static void tc358743_format_change(struct v4l2_subdev *sd)
v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n",
__func__);
} else {
- if (!v4l2_match_dv_timings(&state->timings, &timings, 0))
+ if (!v4l2_match_dv_timings(&state->timings, &timings, 0, false))
enable_stream(sd, false);
v4l2_print_dv_timings(sd->name,
@@ -1366,7 +1366,7 @@ static int tc358743_s_dv_timings(struct v4l2_subdev *sd,
v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ",
timings, false);
- if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+ if (v4l2_match_dv_timings(&state->timings, timings, 0, false)) {
v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
return 0;
}
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index bda3a65..5bbfcab 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -25,7 +25,7 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <media/ths7303.h>
+#include <media/i2c/ths7303.h>
#include <media/v4l2-device.h>
#define THS7303_CHANNEL_1 1
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 2a8114a..fece2a4 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -36,7 +36,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index a93985a..b5dba5b 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -44,7 +44,7 @@
#include <media/v4l2-mediabus.h>
#include <media/v4l2-of.h>
#include <media/v4l2-ctrls.h>
-#include <media/tvp514x.h>
+#include <media/i2c/tvp514x.h>
#include <media/media-entity.h>
#include "tvp514x_regs.h"
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 3c5fb25..6c3769d 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
-#include <media/tvp5150.h>
+#include <media/i2c/tvp5150.h>
#include <media/v4l2-ctrls.h>
#include "tvp5150_reg.h"
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index f617d8b..772a304 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -32,7 +32,7 @@
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/v4l2-dv-timings.h>
-#include <media/tvp7002.h>
+#include <media/i2c/tvp7002.h>
#include <media/v4l2-async.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c
index 081786d..8e17a83 100644
--- a/drivers/media/i2c/uda1342.c
+++ b/drivers/media/i2c/uda1342.c
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/uda1342.h>
+#include <media/i2c/uda1342.h>
#include <linux/slab.h>
static int write_reg(struct i2c_client *client, int reg, int value)
diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c
index 2c0f955..c03567e 100644
--- a/drivers/media/i2c/upd64031a.c
+++ b/drivers/media/i2c/upd64031a.c
@@ -27,7 +27,7 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/upd64031a.h>
+#include <media/i2c/upd64031a.h>
/* --------------------- read registers functions define -------------------- */
diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c
index f2057a4..77f122f 100644
--- a/drivers/media/i2c/upd64083.c
+++ b/drivers/media/i2c/upd64083.c
@@ -27,7 +27,7 @@
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
-#include <media/upd64083.h>
+#include <media/i2c/upd64083.h>
MODULE_DESCRIPTION("uPD64083 driver");
MODULE_AUTHOR("T. Adachi, Takeru KOMORIYA, Hans Verkuil");
diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c
index d33d2cd6..6e00f14 100644
--- a/drivers/media/i2c/wm8775.c
+++ b/drivers/media/i2c/wm8775.c
@@ -34,7 +34,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index 4654fb6..8a17cc0 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -41,7 +41,7 @@
#include "bttvp.h"
#include <media/v4l2-common.h>
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
#include "bttv-audio-hook.h"
/* fwd decl */
@@ -3808,7 +3808,7 @@ static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output)
gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren));
}
-static struct snd_tea575x_ops bttv_tea_ops = {
+static const struct snd_tea575x_ops bttv_tea_ops = {
.set_pins = bttv_tea575x_set_pins,
.get_pins = bttv_tea575x_get_pins,
.set_direction = bttv_tea575x_set_direction,
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 15a4ebc..9400e99 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -50,15 +50,15 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/tvaudio.h>
-#include <media/msp3400.h>
+#include <media/i2c/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
#define BTTV_VERSION "0.9.19"
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 31bf79d..b1e0023 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -41,8 +41,8 @@
#include <media/videobuf-dma-sg.h>
#include <media/tveeprom.h>
#include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/tea575x.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/drv-intf/tea575x.h>
#include "bt848.h"
#include "bttv.h"
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 8fed61e..8d6f04f 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -21,9 +21,9 @@
*/
#include <linux/delay.h>
-#include <media/adv7604.h>
-#include <media/adv7842.h>
-#include <media/adv7511.h>
+#include <media/i2c/adv7604.h>
+#include <media/i2c/adv7842.h>
+#include <media/i2c/adv7511.h>
#include <media/v4l2-event.h>
#include <media/v4l2-ctrls.h>
diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c
index 3de26d0..b190d4f 100644
--- a/drivers/media/pci/cobalt/cobalt-irq.c
+++ b/drivers/media/pci/cobalt/cobalt-irq.c
@@ -18,7 +18,7 @@
* SOFTWARE.
*/
-#include <media/adv7604.h>
+#include <media/i2c/adv7604.h>
#include "cobalt-driver.h"
#include "cobalt-irq.h"
@@ -134,7 +134,7 @@ done:
skip = true;
s->skip_first_frames--;
}
- v4l2_get_timestamp(&cb->vb.timestamp);
+ cb->vb.vb2_buf.timestamp = ktime_get_ns();
/* TODO: the sequence number should be read from the FPGA so we
also know about dropped frames. */
cb->vb.sequence = s->sequence++;
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index ff46e42..c0ba458 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -29,8 +29,8 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
#include <media/v4l2-dv-timings.h>
-#include <media/adv7604.h>
-#include <media/adv7842.h>
+#include <media/i2c/adv7604.h>
+#include <media/i2c/adv7842.h>
#include "cobalt-alsa.h"
#include "cobalt-cpld.h"
@@ -43,11 +43,10 @@ static const struct v4l2_dv_timings cea1080p60 = V4L2_DV_BT_CEA_1920X1080P60;
/* vb2 DMA streaming ops */
-static int cobalt_queue_setup(struct vb2_queue *q, const void *parg,
+static int cobalt_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct cobalt_stream *s = q->drv_priv;
unsigned size = s->stride * s->height;
@@ -55,14 +54,11 @@ static int cobalt_queue_setup(struct vb2_queue *q, const void *parg,
*num_buffers = 3;
if (*num_buffers > NR_BUFS)
*num_buffers = NR_BUFS;
+ alloc_ctxs[0] = s->cobalt->alloc_ctx;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
- if (fmt) {
- if (fmt->fmt.pix.sizeimage < size)
- return -EINVAL;
- size = fmt->fmt.pix.sizeimage;
- }
sizes[0] = size;
- alloc_ctxs[0] = s->cobalt->alloc_ctx;
return 0;
}
@@ -649,7 +645,7 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh,
return 0;
}
- if (v4l2_match_dv_timings(timings, &s->timings, 0))
+ if (v4l2_match_dv_timings(timings, &s->timings, 0, false))
return 0;
if (vb2_is_busy(&s->q))
diff --git a/drivers/media/pci/cx18/cx18-cards.c b/drivers/media/pci/cx18/cx18-cards.c
index c07c849..5e01ea4 100644
--- a/drivers/media/pci/cx18/cx18-cards.c
+++ b/drivers/media/pci/cx18/cx18-cards.c
@@ -26,7 +26,7 @@
#include "cx18-cards.h"
#include "cx18-av-core.h"
#include "cx18-i2c.h"
-#include <media/cs5345.h>
+#include <media/i2c/cs5345.h>
#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM)
diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c
index 71227a1..adb5a8c 100644
--- a/drivers/media/pci/cx18/cx18-controls.c
+++ b/drivers/media/pci/cx18/cx18-controls.c
@@ -126,7 +126,7 @@ static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
return 0;
}
-struct cx2341x_handler_ops cx18_cxhdl_ops = {
+const struct cx2341x_handler_ops cx18_cxhdl_ops = {
.s_audio_mode = cx18_s_audio_mode,
.s_audio_sampling_freq = cx18_s_audio_sampling_freq,
.s_video_encoding = cx18_s_video_encoding,
diff --git a/drivers/media/pci/cx18/cx18-controls.h b/drivers/media/pci/cx18/cx18-controls.h
index cb5dfc7..3267948 100644
--- a/drivers/media/pci/cx18/cx18-controls.h
+++ b/drivers/media/pci/cx18/cx18-controls.h
@@ -21,4 +21,4 @@
* 02111-1307 USA
*/
-extern struct cx2341x_handler_ops cx18_cxhdl_ops;
+extern const struct cx2341x_handler_ops cx18_cxhdl_ops;
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
index b15beed..7e31f2a 100644
--- a/drivers/media/pci/cx18/cx18-driver.h
+++ b/drivers/media/pci/cx18/cx18-driver.h
@@ -49,7 +49,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/tuner.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include "cx18-mailbox.h"
#include "cx18-av-core.h"
#include "cx23418.h"
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 55525af..eeb741c 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -453,8 +453,8 @@ static int cx18_cropcap(struct file *file, void *fh,
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 54 : 11;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 59 : 10;
return 0;
}
diff --git a/drivers/media/pci/cx18/cx23418.h b/drivers/media/pci/cx18/cx23418.h
index 767a8d2..67ffe65 100644
--- a/drivers/media/pci/cx18/cx23418.h
+++ b/drivers/media/pci/cx18/cx23418.h
@@ -22,7 +22,7 @@
#ifndef CX23418_H
#define CX23418_H
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#define MGR_CMD_MASK 0x40000000
/* The MSB of the command code indicates that this is the completion of a
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index 2e1b88c..3435bba 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_CX23885
select VIDEOBUF2_DMA_SG
select VIDEO_CX25840
select VIDEO_CX2341X
+ select VIDEO_CS3308
select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT
select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 88a3afb..bd33387 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -30,7 +30,7 @@
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include "cx23885.h"
#include "cx23885-ioctl.h"
@@ -1138,7 +1138,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder)
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index f384f29..310ee76 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -19,7 +19,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/delay.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include <linux/firmware.h>
#include <misc/altera.h>
@@ -715,6 +715,56 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_VIEWCAST_260E] = {
+ .name = "ViewCast 260e",
+ .porta = CX23885_ANALOG_VIDEO,
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN5_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN6_CH2 |
+ CX25840_VIN5_CH1 |
+ CX25840_COMPONENT_ON,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
+ [CX23885_BOARD_VIEWCAST_460E] = {
+ .name = "ViewCast 460e",
+ .porta = CX23885_ANALOG_VIDEO,
+ .force_bff = 1,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN4_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN6_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_COMPONENT,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN6_CH1 |
+ CX25840_VIN5_CH2 |
+ CX25840_COMPONENT_ON,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE2,
+ .vmux = CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -1002,6 +1052,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0xf038,
.card = CX23885_BOARD_HAUPPAUGE_HVR5525,
+ }, {
+ .subvendor = 0x1576,
+ .subdevice = 0x0260,
+ .card = CX23885_BOARD_VIEWCAST_260E,
+ }, {
+ .subvendor = 0x1576,
+ .subdevice = 0x0460,
+ .card = CX23885_BOARD_VIEWCAST_460E,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1034,6 +1092,28 @@ void cx23885_card_list(struct cx23885_dev *dev)
dev->name, i, cx23885_boards[i].name);
}
+static void viewcast_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
+{
+ u32 sn;
+
+ /* The serial number record begins with tag 0x59 */
+ if (*(eeprom_data + 0x00) != 0x59) {
+ pr_info("%s() eeprom records are undefined, no serial number\n",
+ __func__);
+ return;
+ }
+
+ sn = (*(eeprom_data + 0x06) << 24) |
+ (*(eeprom_data + 0x05) << 16) |
+ (*(eeprom_data + 0x04) << 8) |
+ (*(eeprom_data + 0x03));
+
+ pr_info("%s: card '%s' sn# MM%d\n",
+ dev->name,
+ cx23885_boards[dev->board].name,
+ sn);
+}
+
static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
{
struct tveeprom tv;
@@ -1671,6 +1751,12 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
msleep(100);
break;
+ case CX23885_BOARD_VIEWCAST_260E:
+ case CX23885_BOARD_VIEWCAST_460E:
+ /* For documentation purposes, it's worth noting that this
+ * card does not have any GPIO's connected to subcomponents.
+ */
+ break;
}
}
@@ -1917,6 +2003,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
+ case CX23885_BOARD_VIEWCAST_260E:
+ case CX23885_BOARD_VIEWCAST_460E:
+ dev->i2c_bus[1].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[1].i2c_client,
+ eeprom, sizeof(eeprom));
+ if (dev->i2c_bus[0].i2c_rc == 0)
+ viewcast_eeprom(dev, eeprom);
+ break;
}
switch (dev->board) {
@@ -2120,6 +2214,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_DVBSKY_S950:
case CX23885_BOARD_DVBSKY_S952:
case CX23885_BOARD_DVBSKY_T982:
+ case CX23885_BOARD_VIEWCAST_260E:
+ case CX23885_BOARD_VIEWCAST_460E:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
@@ -2130,6 +2226,24 @@ void cx23885_card_setup(struct cx23885_dev *dev)
break;
}
+ switch (dev->board) {
+ case CX23885_BOARD_VIEWCAST_260E:
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_bus[0].i2c_adap,
+ "cs3308", 0x82 >> 1, NULL);
+ break;
+ case CX23885_BOARD_VIEWCAST_460E:
+ /* This cs3308 controls the audio from the breakout cable */
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_bus[0].i2c_adap,
+ "cs3308", 0x80 >> 1, NULL);
+ /* This cs3308 controls the audio from the onboard header */
+ v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_bus[0].i2c_adap,
+ "cs3308", 0x82 >> 1, NULL);
+ break;
+ }
+
/* AUX-PLL 27MHz CLK */
switch (dev->board) {
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index bc1c960..813c217 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -427,7 +427,7 @@ static void cx23885_wakeup(struct cx23885_tsport *port,
buf = list_entry(q->active.next,
struct cx23885_buffer, queue);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = q->count++;
dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
buf->vb.vb2_buf.index,
@@ -968,6 +968,16 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
call_all(dev, core, s_power, 0);
cx23885_ir_init(dev);
+ if (dev->board == CX23885_BOARD_VIEWCAST_460E) {
+ /*
+ * GPIOs 9/8 are input detection bits for the breakout video
+ * (gpio 8) and audio (gpio 9) cables. When they're attached,
+ * this gpios are pulled high. Make sure these GPIOs are marked
+ * as inputs.
+ */
+ cx23885_gpio_enable(dev, 0x300, 0);
+ }
+
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
if (cx23885_video_register(dev) < 0) {
printk(KERN_ERR "%s() Failed to register analog "
@@ -1992,9 +2002,9 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
(unsigned long long)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ err = pci_set_dma_mask(pci_dev, 0xffffffff);
+ if (err) {
printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
- err = -EIO;
goto fail_context;
}
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index c4307ad..80319bb 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -92,7 +92,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -2168,11 +2168,12 @@ static int dvb_register(struct cx23885_tsport *port)
}
port->i2c_client_tuner = client_tuner;
break;
- case CX23885_BOARD_HAUPPAUGE_HVR5525:
- switch (port->nr) {
+ case CX23885_BOARD_HAUPPAUGE_HVR5525: {
struct m88rs6000t_config m88rs6000t_config;
struct a8293_platform_data a8293_pdata = {};
+ switch (port->nr) {
+
/* port b - satellite */
case 1:
/* attach frontend */
@@ -2267,6 +2268,7 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ }
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index 1135ea3..ae061b3 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -279,6 +279,8 @@ static char *i2c_devs[128] = {
[0x10 >> 1] = "tda10048",
[0x12 >> 1] = "dib7000pc",
[0x1c >> 1] = "lgdt3303",
+ [0x80 >> 1] = "cs3308",
+ [0x82 >> 1] = "cs3308",
[0x86 >> 1] = "tda9887",
[0x32 >> 1] = "cx24227",
[0x88 >> 1] = "cx25837",
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 088799c..64328d0 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -268,7 +268,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
struct rc_dev *rc;
char *rc_map;
enum rc_driver_type driver_type;
- unsigned long allowed_protos;
+ u64 allowed_protos;
int ret;
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index cf3cb13..39750eb 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -83,7 +83,7 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status)
if (status & VID_BC_MSK_VBI_RISCI1) {
dprintk(1, "%s() VID_BC_MSK_VBI_RISCI1\n", __func__);
spin_lock(&dev->slock);
- count = cx_read(VID_A_GPCNT);
+ count = cx_read(VBI_A_GPCNT);
cx23885_video_wakeup(dev, &dev->vbiq, count);
spin_unlock(&dev->slock);
handled++;
@@ -103,7 +103,6 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
VBI_LINE_LENGTH, buf->risc.dma);
/* reset counter */
- cx_write(VID_A_GPCNT_CTL, 3);
cx_write(VID_A_VBI_CTRL, 3);
cx_write(VBI_A_GPCNT_CTL, 3);
q->count = 0;
@@ -121,7 +120,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 71a80e2..e1d7d08 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -35,7 +35,7 @@
#include "cx23885-ioctl.h"
#include "tuner-xc2028.h"
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards");
MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>");
@@ -105,7 +105,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
struct cx23885_buffer, queue);
buf->vb.sequence = q->count++;
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf,
buf->vb.vb2_buf.index, count, q->count);
list_del(&buf->queue);
@@ -114,11 +114,19 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
+ struct v4l2_subdev_format format = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ .format.code = MEDIA_BUS_FMT_FIXED,
+ };
+
dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
__func__,
(unsigned int)norm,
v4l2_norm_to_name(norm));
+ if (dev->tvnorm == norm)
+ return 0;
+
if (dev->tvnorm != norm) {
if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) ||
vb2_is_busy(&dev->vb2_mpegq))
@@ -126,9 +134,17 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
}
dev->tvnorm = norm;
+ dev->width = 720;
+ dev->height = norm_maxh(norm);
+ dev->field = V4L2_FIELD_INTERLACED;
call_all(dev, video, s_std, norm);
+ format.format.width = dev->width;
+ format.format.height = dev->height;
+ format.format.field = dev->field;
+ call_all(dev, pad, set_fmt, NULL, &format);
+
return 0;
}
@@ -247,7 +263,9 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
(dev->board == CX23885_BOARD_MYGICA_X8507) ||
- (dev->board == CX23885_BOARD_AVERMEDIA_HC81R)) {
+ (dev->board == CX23885_BOARD_AVERMEDIA_HC81R) ||
+ (dev->board == CX23885_BOARD_VIEWCAST_260E) ||
+ (dev->board == CX23885_BOARD_VIEWCAST_460E)) {
/* Configure audio routing */
v4l2_subdev_call(dev->sd_cx25840, audio, s_routing,
INPUT(input)->amux, 0, 0);
@@ -315,7 +333,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
return 0;
}
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -545,7 +563,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
field = f->fmt.pix.field;
- maxw = norm_maxw(dev->tvnorm);
+ maxw = 720;
maxh = norm_maxh(dev->tvnorm);
if (V4L2_FIELD_ANY == field) {
@@ -648,6 +666,26 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct cx23885_dev *dev = video_drvdata(file);
+ bool is_50hz = dev->tvnorm & V4L2_STD_625_50;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = 720;
+ cc->bounds.height = norm_maxh(dev->tvnorm);
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+ cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+
+ return 0;
+}
+
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct cx23885_dev *dev = video_drvdata(file);
@@ -1082,6 +1120,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_cropcap = vidioc_cropcap,
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_std,
.vidioc_enum_input = vidioc_enum_input,
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index c5ba083..b1a5409 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -30,7 +30,7 @@
#include <media/rc-core.h>
#include "cx23885-reg.h"
-#include "media/cx2341x.h"
+#include "media/drv-intf/cx2341x.h"
#include <linux/mutex.h>
@@ -101,6 +101,8 @@
#define CX23885_BOARD_DVBSKY_T982 51
#define CX23885_BOARD_HAUPPAUGE_HVR5525 52
#define CX23885_BOARD_HAUPPAUGE_STARBURST 53
+#define CX23885_BOARD_VIEWCAST_260E 54
+#define CX23885_BOARD_VIEWCAST_460E 55
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -627,11 +629,6 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci,
/* ----------------------------------------------------------- */
/* tv norms */
-static inline unsigned int norm_maxw(v4l2_std_id norm)
-{
- return (norm & V4L2_STD_525_60) ? 720 : 768;
-}
-
static inline unsigned int norm_maxh(v4l2_std_id norm)
{
return (norm & V4L2_STD_525_60) ? 480 : 576;
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index 559f829..0042803 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -1319,7 +1319,8 @@ static int cx25821_initdev(struct pci_dev *pci_dev,
dev->pci_lat, (unsigned long long)dev->base_io_addr);
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ err = pci_set_dma_mask(pci_dev, 0xffffffff);
+ if (err) {
pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
err = -EIO;
goto fail_irq;
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 26e3e29..c48bba9 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -130,7 +130,7 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
buf = list_entry(dmaq->active.next,
struct cx25821_buffer, queue);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.sequence = dmaq->count++;
list_del(&buf->queue);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -141,20 +141,20 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
return handled;
}
-static int cx25821_queue_setup(struct vb2_queue *q, const void *parg,
+static int cx25821_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct cx25821_channel *chan = q->drv_priv;
unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
- if (fmt && fmt->fmt.pix.sizeimage < size)
- return -EINVAL;
+ alloc_ctxs[0] = chan->dev->alloc_ctx;
+
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
- alloc_ctxs[0] = chan->dev->alloc_ctx;
+ sizes[0] = size;
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index 57ddf8a..e158a1d 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -40,7 +40,7 @@
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/tlv.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
#include "cx88.h"
#include "cx88-reg.h"
@@ -890,9 +890,9 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,
return err;
}
- if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pci,DMA_BIT_MASK(32));
+ if (err) {
dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name);
- err = -EIO;
cx88_core_put(core, pci);
return err;
}
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 8b88913..3233d45 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -36,7 +36,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include "cx88.h"
@@ -637,7 +637,7 @@ static int blackbird_stop_codec(struct cx8802_dev *dev)
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 9a43c78..46fe8c1 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -518,7 +518,7 @@ void cx88_wakeup(struct cx88_core *core,
buf = list_entry(q->active.next,
struct cx88_buffer, list);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.field = core->field;
buf->vb.sequence = q->count++;
list_del(&buf->list);
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index f048350..afb2075 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -82,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index 9961b22..f34c229 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -393,7 +393,8 @@ static int cx8802_init_common(struct cx8802_dev *dev)
if (pci_enable_device(dev->pci))
return -EIO;
pci_set_master(dev->pci);
- if (!pci_dma_supported(dev->pci,DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32));
+ if (err) {
printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name);
return -EIO;
}
diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
index 007a5ee..ccc646d 100644
--- a/drivers/media/pci/cx88/cx88-vbi.c
+++ b/drivers/media/pci/cx88/cx88-vbi.c
@@ -107,7 +107,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index f3b12db..5f331df 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -41,7 +41,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/wm8775.h>
+#include <media/i2c/wm8775.h>
MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -429,7 +429,7 @@ static int restart_video_queue(struct cx8800_dev *dev,
/* ------------------------------------------------------------------ */
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -1314,9 +1314,9 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev,DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32));
+ if (err) {
printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name);
- err = -EIO;
goto fail_core;
}
dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index 2996eb3..78f817e 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -30,10 +30,10 @@
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/videobuf2-dma-sg.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include <media/videobuf2-dvb.h>
-#include <media/ir-kbd-i2c.h>
-#include <media/wm8775.h>
+#include <media/i2c/ir-kbd-i2c.h>
+#include <media/i2c/wm8775.h>
#include "cx88-reg.h"
#include "tuner-xc2028.h"
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 0ac2dd3..fba5b40 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -81,13 +81,13 @@ static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
{
struct ddb *dev = i2c->dev;
- int stat;
+ long stat;
u32 val;
i2c->done = 0;
ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND);
stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ);
- if (stat <= 0) {
+ if (stat == 0) {
printk(KERN_ERR "I2C timeout\n");
{ /* MSI debugging*/
u32 istat = ddbreadl(INTERRUPT_STATUS);
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index 88915fb..5dd5047 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -1206,7 +1206,6 @@ static void dm1105_remove(struct pci_dev *pdev)
i2c_del_adapter(&dev->i2c_adap);
dm1105_hw_exit(dev);
- synchronize_irq(pdev->irq);
free_irq(pdev->irq, dev);
pci_iounmap(pdev, dev->io_mem);
pci_release_regions(pdev);
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index d84abde..568c0c8 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -131,22 +131,21 @@ static int wait_i2c_reg(void __iomem *addr)
}
static int
-dt3155_queue_setup(struct vb2_queue *vq, const void *parg,
+dt3155_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct dt3155_priv *pd = vb2_get_drv_priv(vq);
unsigned size = pd->width * pd->height;
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
- if (fmt && fmt->fmt.pix.sizeimage < size)
- return -EINVAL;
- *num_planes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
alloc_ctxs[0] = pd->alloc_ctx;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+ *num_planes = 1;
+ sizes[0] = size;
return 0;
}
@@ -271,7 +270,7 @@ static irqreturn_t dt3155_irq_handler_even(int irq, void *dev_id)
spin_lock(&ipd->lock);
if (ipd->curr_buf && !list_empty(&ipd->dmaq)) {
- v4l2_get_timestamp(&ipd->curr_buf->timestamp);
+ ipd->curr_buf->vb2_buf.timestamp = ktime_get_ns();
ipd->curr_buf->sequence = ipd->sequence++;
ipd->curr_buf->field = V4L2_FIELD_NONE;
vb2_buffer_done(&ipd->curr_buf->vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/pci/ivtv/ivtv-cards.c b/drivers/media/pci/ivtv/ivtv-cards.c
index 145e474..410d97b 100644
--- a/drivers/media/pci/ivtv/ivtv-cards.c
+++ b/drivers/media/pci/ivtv/ivtv-cards.c
@@ -22,12 +22,12 @@
#include "ivtv-cards.h"
#include "ivtv-i2c.h"
-#include <media/msp3400.h>
-#include <media/m52790.h>
-#include <media/wm8775.h>
-#include <media/cs53l32a.h>
-#include <media/cx25840.h>
-#include <media/upd64031a.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/m52790.h>
+#include <media/i2c/wm8775.h>
+#include <media/i2c/cs53l32a.h>
+#include <media/drv-intf/cx25840.h>
+#include <media/i2c/upd64031a.h>
#define MSP_TUNER MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, \
MSP_DSP_IN_TUNER, MSP_DSP_IN_TUNER)
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index 8a55ccb..9666ca0 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -96,7 +96,7 @@ static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
return 0;
}
-struct cx2341x_handler_ops ivtv_cxhdl_ops = {
+const struct cx2341x_handler_ops ivtv_cxhdl_ops = {
.s_audio_mode = ivtv_s_audio_mode,
.s_audio_sampling_freq = ivtv_s_audio_sampling_freq,
.s_video_encoding = ivtv_s_video_encoding,
diff --git a/drivers/media/pci/ivtv/ivtv-controls.h b/drivers/media/pci/ivtv/ivtv-controls.h
index 3999e63..ea397ba 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.h
+++ b/drivers/media/pci/ivtv/ivtv-controls.h
@@ -21,7 +21,7 @@
#ifndef IVTV_CONTROLS_H
#define IVTV_CONTROLS_H
-extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
+extern const struct cx2341x_handler_ops ivtv_cxhdl_ops;
extern const struct v4l2_ctrl_ops ivtv_hdl_out_ops;
int ivtv_g_pts_frame(struct ivtv *itv, s64 *pts, s64 *frame);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index 8616fa8..374033a 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -57,7 +57,7 @@
#include "ivtv-gpio.h"
#include <linux/dma-mapping.h>
#include <media/tveeprom.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include "tuner-xc2028.h"
/* If you have already X v4l cards, then set this to X. This way
@@ -805,11 +805,11 @@ static void ivtv_init_struct2(struct ivtv *itv)
{
int i;
- for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS - 1; i++)
+ for (i = 0; i < IVTV_CARD_MAX_VIDEO_INPUTS; i++)
if (itv->card->video_inputs[i].video_type == 0)
break;
itv->nof_inputs = i;
- for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS - 1; i++)
+ for (i = 0; i < IVTV_CARD_MAX_AUDIO_INPUTS; i++)
if (itv->card->audio_inputs[i].audio_type == 0)
break;
itv->nof_audio_inputs = i;
@@ -826,7 +826,7 @@ static void ivtv_init_struct2(struct ivtv *itv)
IVTV_CARD_INPUT_VID_TUNER)
break;
}
- if (i == itv->nof_inputs)
+ if (i >= itv->nof_inputs)
i = 0;
itv->active_input = i;
itv->audio_input = itv->card->video_inputs[i].audio_index;
diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h
index ee0ef6e..6c08dae 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.h
+++ b/drivers/media/pci/ivtv/ivtv-driver.h
@@ -64,8 +64,8 @@
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/tuner.h>
-#include <media/cx2341x.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/drv-intf/cx2341x.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include <linux/ivtv.h>
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
index 605d280..c9bd018 100644
--- a/drivers/media/pci/ivtv/ivtv-fileops.c
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -34,7 +34,7 @@
#include "ivtv-cards.h"
#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
/* This function tries to claim the stream for a specific file descriptor.
If no one else is using this stream then the stream is claimed and
diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c
index 4b0e758..5b3095f 100644
--- a/drivers/media/pci/ivtv/ivtv-firmware.c
+++ b/drivers/media/pci/ivtv/ivtv-firmware.c
@@ -26,7 +26,7 @@
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include <linux/firmware.h>
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index 1a41ba5..bccbf2d 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -63,7 +63,7 @@
#include "ivtv-cards.h"
#include "ivtv-gpio.h"
#include "ivtv-i2c.h"
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
/* i2c implementation for cx23415/6 chip, ivtv project.
* Author: Kevin Thayer (nufan_wfk at yahoo.com)
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 9a21c17..2dc4b20 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -32,7 +32,7 @@
#include "ivtv-gpio.h"
#include "ivtv-controls.h"
#include "ivtv-cards.h"
-#include <media/saa7127.h>
+#include <media/i2c/saa7127.h>
#include <media/tveeprom.h>
#include <media/v4l2-event.h>
#include <linux/dvb/audio.h>
@@ -831,11 +831,11 @@ static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropca
struct ivtv *itv = id->itv;
if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
+ cropcap->pixelaspect.numerator = itv->is_50hz ? 54 : 11;
+ cropcap->pixelaspect.denominator = itv->is_50hz ? 59 : 10;
} else if (cropcap->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
- cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
+ cropcap->pixelaspect.numerator = itv->is_out_50hz ? 54 : 11;
+ cropcap->pixelaspect.denominator = itv->is_out_50hz ? 59 : 10;
} else {
return -EINVAL;
}
diff --git a/drivers/media/pci/ivtv/ivtv-routing.c b/drivers/media/pci/ivtv/ivtv-routing.c
index 8898c56..0c168f2 100644
--- a/drivers/media/pci/ivtv/ivtv-routing.c
+++ b/drivers/media/pci/ivtv/ivtv-routing.c
@@ -24,10 +24,10 @@
#include "ivtv-gpio.h"
#include "ivtv-routing.h"
-#include <media/msp3400.h>
-#include <media/m52790.h>
-#include <media/upd64031a.h>
-#include <media/upd64083.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/m52790.h>
+#include <media/i2c/upd64031a.h>
+#include <media/i2c/upd64083.h>
/* Selects the audio input and output according to the current
settings. */
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
index 83c90d3..81e1a5e 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -277,7 +277,6 @@ static irqreturn_t netup_unidvb_isr(int irq, void *dev_id)
}
static int netup_unidvb_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers,
unsigned int *nplanes,
unsigned int sizes[],
@@ -580,7 +579,7 @@ static void netup_unidvb_dma_worker(struct work_struct *work)
dev_dbg(&ndev->pci_dev->dev,
"%s(): buffer %p done, size %d\n",
__func__, buf, buf->size);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -810,7 +809,7 @@ static int netup_unidvb_initdev(struct pci_dev *pci_dev,
"%s(): board vendor 0x%x, revision 0x%x\n",
__func__, board_vendor, board_revision);
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ if (pci_set_dma_mask(pci_dev, 0xffffffff) < 0) {
dev_err(&pci_dev->dev,
"%s(): 32bit PCI DMA is not supported\n", __func__);
goto pci_detect_err;
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 87f39f9..e227b02 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -309,7 +309,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
core_dbg("buffer_finish %p\n", q->curr);
/* finish current buffer */
- v4l2_get_timestamp(&q->curr->vb2.timestamp);
+ q->curr->vb2.vb2_buf.timestamp = ktime_get_ns();
q->curr->vb2.sequence = q->seq_nr++;
vb2_buffer_done(&q->curr->vb2.vb2_buf, state);
q->curr = NULL;
@@ -951,9 +951,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0));
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+ if (err) {
pr_warn("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
- err = -EIO;
goto fail1;
}
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 7fb5ee7..0584a2a 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -116,7 +116,7 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
-int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg,
+int saa7134_ts_queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index 6271b0e..e76da37 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -138,7 +138,7 @@ static int buffer_prepare(struct vb2_buffer *vb2)
saa7134_buffer_startpage(buf));
}
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 518086c..a63c136 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -32,7 +32,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
-#include <media/saa6588.h>
+#include <media/i2c/saa6588.h>
/* ------------------------------------------------------------------ */
@@ -904,7 +904,7 @@ static int buffer_prepare(struct vb2_buffer *vb2)
saa7134_buffer_startpage(buf));
}
-static int queue_setup(struct vb2_queue *q, const void *parg,
+static int queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 6b6d234..5938bc7 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -42,7 +42,7 @@
#include <media/v4l2-ctrls.h>
#include <media/tuner.h>
#include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include <media/videobuf2-dma-sg.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -820,7 +820,7 @@ void saa7134_video_fini(struct saa7134_dev *dev);
int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
-int saa7134_ts_queue_setup(struct vb2_queue *q, const void *parg,
+int saa7134_ts_queue_setup(struct vb2_queue *q,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[]);
int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count);
diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c
index 03cbcd2..c889ec9 100644
--- a/drivers/media/pci/saa7146/hexium_gemini.c
+++ b/drivers/media/pci/saa7146/hexium_gemini.c
@@ -25,7 +25,7 @@
#define DEBUG_VARIABLE debug
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
static int debug;
diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c
index 15f0d66..c306a92 100644
--- a/drivers/media/pci/saa7146/hexium_orion.c
+++ b/drivers/media/pci/saa7146/hexium_orion.c
@@ -25,7 +25,7 @@
#define DEBUG_VARIABLE debug
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
static int debug;
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 0ca1e07..504d788 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -25,10 +25,10 @@
#define DEBUG_VARIABLE debug
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <media/tuner.h>
#include <media/v4l2-common.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <linux/module.h>
#include "tea6415c.h"
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 3206a82..8bbd092 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -1264,9 +1264,9 @@ static int saa7164_initdev(struct pci_dev *pci_dev,
pci_set_master(pci_dev);
/* TODO */
- if (!pci_dma_supported(pci_dev, 0xffffffff)) {
+ err = pci_set_dma_mask(pci_dev, 0xffffffff);
+ if (err) {
printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
- err = -EIO;
goto fail_irq;
}
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 4432fd6..67a14c4 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -531,8 +531,7 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
if (!ret) {
vbuf->sequence = solo_enc->sequence++;
- vbuf->timestamp.tv_sec = vop_sec(vh);
- vbuf->timestamp.tv_usec = vop_usec(vh);
+ vb->timestamp = ktime_get_ns();
/* Check for motion flags */
if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
@@ -663,7 +662,6 @@ static int solo_ring_thread(void *data)
}
static int solo_enc_queue_setup(struct vb2_queue *q,
- const void *parg,
unsigned int *num_buffers,
unsigned int *num_planes, unsigned int sizes[],
void *alloc_ctxs[])
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
index f7ce493..721ff53 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -225,7 +225,7 @@ finish_buf:
vb2_set_plane_payload(vb, 0,
solo_vlines(solo_dev) * solo_bytesperline(solo_dev));
vbuf->sequence = solo_dev->sequence++;
- v4l2_get_timestamp(&vbuf->timestamp);
+ vb->timestamp = ktime_get_ns();
}
vb2_buffer_done(vb, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
@@ -313,7 +313,7 @@ static void solo_stop_thread(struct solo_dev *solo_dev)
solo_dev->kthread = NULL;
}
-static int solo_queue_setup(struct vb2_queue *q, const void *parg,
+static int solo_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 6367b45..753411c 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -265,7 +265,7 @@ static void vip_active_buf_next(struct sta2x11_vip *vip)
/* Videobuf2 Operations */
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -817,7 +817,7 @@ static irqreturn_t vip_irq(int irq, struct sta2x11_vip *vip)
/* Disable acquisition */
reg_write(vip, DVP_CTL, reg_read(vip, DVP_CTL) & ~DVP_CTL_ENA);
/* Remove the active buffer from the list */
- v4l2_get_timestamp(&vip->active->vb.timestamp);
+ vip->active->vb.vb2_buf.timestamp = ktime_get_ns();
vip->active->vb.sequence = vip->sequence++;
vb2_buffer_done(&vip->active->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index f893649..5e18b67 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -26,7 +26,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
@@ -1537,7 +1537,7 @@ static int get_firmware(struct av7110* av7110)
printk(KERN_ERR "dvb-ttpci: usually this should be in "
"/usr/lib/hotplug/firmware or /lib/firmware\n");
printk(KERN_ERR "dvb-ttpci: and can be downloaded from"
- " http://www.linuxtv.org/download/dvb/firmware/\n");
+ " https://linuxtv.org/download/dvb/firmware/\n");
} else
printk(KERN_ERR "dvb-ttpci: cannot request firmware"
" (error %i)\n", ret);
@@ -2314,7 +2314,7 @@ static int frontend_init(struct av7110 *av7110)
/* Budgetpatch note:
* Original hardware design by Roberto Deza:
* There is a DVB_Wiki at
- * http://www.linuxtv.org/
+ * https://linuxtv.org
*
* New software triggering design by Emard that works on
* original Roberto Deza's hardware:
diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h
index 3a55927..3707ccd 100644
--- a/drivers/media/pci/ttpci/av7110.h
+++ b/drivers/media/pci/ttpci/av7110.h
@@ -32,7 +32,7 @@
#include "stv0297.h"
#include "l64781.h"
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#define ANALOG_TUNER_VES1820 1
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 9ed1ec7..6fc748e 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#include <linux/types.h>
@@ -280,9 +280,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
}
-int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
+int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
+ unsigned int volright)
{
- int err, vol, val, balance = 0;
+ unsigned int vol, val, balance = 0;
+ int err;
dprintk(2, "av7110:%p, \n", av7110);
@@ -1043,6 +1045,9 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
dprintk(2, "av7110:%p, \n", av7110);
+ if (len == 0)
+ return 0;
+
if (!(av7110->playing & RP_VIDEO)) {
if (av7110_av_start_play(av7110, RP_VIDEO) < 0)
return -EBUSY;
diff --git a/drivers/media/pci/ttpci/av7110_av.h b/drivers/media/pci/ttpci/av7110_av.h
index 5f02ef8..f52276f 100644
--- a/drivers/media/pci/ttpci/av7110_av.h
+++ b/drivers/media/pci/ttpci/av7110_av.h
@@ -10,7 +10,8 @@ extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
-extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
+extern int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
+ unsigned int volright);
extern int av7110_av_stop(struct av7110 *av7110, int av);
extern int av7110_av_start_record(struct av7110 *av7110, int av,
struct dvb_demux_feed *dvbdmxfeed);
diff --git a/drivers/media/pci/ttpci/av7110_ca.c b/drivers/media/pci/ttpci/av7110_ca.c
index a6079b9..bc4c65f 100644
--- a/drivers/media/pci/ttpci/av7110_ca.c
+++ b/drivers/media/pci/ttpci/av7110_ca.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#include <linux/kernel.h>
diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c
index 300bd3c..0583d56 100644
--- a/drivers/media/pci/ttpci/av7110_hw.c
+++ b/drivers/media/pci/ttpci/av7110_hw.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
/* for debugging ARM communication: */
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
index 6c4076a..479aff0 100644
--- a/drivers/media/pci/ttpci/av7110_v4l.c
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 3e469d4..6f0d016 100644
--- a/drivers/media/pci/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -30,7 +30,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -46,7 +46,7 @@
#include "tda1004x.h"
#include "tua6100.h"
#include "dvb-pll.h"
-#include <media/saa7146_vv.h>
+#include <media/drv-intf/saa7146_vv.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 1feeeff..7b27af4 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -26,7 +26,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#include <linux/module.h>
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index e9674b4..6d42dcf 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c
index b5b6596..591dbdf 100644
--- a/drivers/media/pci/ttpci/budget-patch.c
+++ b/drivers/media/pci/ttpci/budget-patch.c
@@ -27,7 +27,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#include "av7110.h"
diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c
index 99972be..de54310 100644
--- a/drivers/media/pci/ttpci/budget.c
+++ b/drivers/media/pci/ttpci/budget.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/
+ * the project's page is at https://linuxtv.org
*/
#include "budget.h"
diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index 1ccbe1a..655eef5 100644
--- a/drivers/media/pci/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
@@ -13,7 +13,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
-#include <media/saa7146.h>
+#include <media/drv-intf/saa7146.h>
extern int budget_debug;
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
index 04706cc..4e77618 100644
--- a/drivers/media/pci/tw68/tw68-core.c
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -257,9 +257,9 @@ static int tw68_initdev(struct pci_dev *pci_dev,
dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
dev->pci_lat, (u64)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
- if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) {
+ err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
+ if (err) {
pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name);
- err = -EIO;
goto fail1;
}
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 46642ef..07116a8 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -376,28 +376,28 @@ static int tw68_buffer_count(unsigned int size, unsigned int count)
/* ------------------------------------------------------------- */
/* vb2 queue operations */
-static int tw68_queue_setup(struct vb2_queue *q, const void *parg,
+static int tw68_queue_setup(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct tw68_dev *dev = vb2_get_drv_priv(q);
unsigned tot_bufs = q->num_buffers + *num_buffers;
+ unsigned size = (dev->fmt->depth * dev->width * dev->height) >> 3;
- sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+ if (tot_bufs < 2)
+ tot_bufs = 2;
+ tot_bufs = tw68_buffer_count(size, tot_bufs);
+ *num_buffers = tot_bufs - q->num_buffers;
alloc_ctxs[0] = dev->alloc_ctx;
/*
- * We allow create_bufs, but only if the sizeimage is the same as the
+ * We allow create_bufs, but only if the sizeimage is >= as the
* current sizeimage. The tw68_buffer_count calculation becomes quite
* difficult otherwise.
*/
- if (fmt && fmt->fmt.pix.sizeimage < sizes[0])
- return -EINVAL;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
*num_planes = 1;
- if (tot_bufs < 2)
- tot_bufs = 2;
- tot_bufs = tw68_buffer_count(sizes[0], tot_bufs);
- *num_buffers = tot_bufs - q->num_buffers;
+ sizes[0] = size;
return 0;
}
@@ -1016,7 +1016,7 @@ void tw68_irq_video_done(struct tw68_dev *dev, unsigned long status)
buf = list_entry(dev->active.next, struct tw68_buf, list);
list_del(&buf->list);
spin_unlock(&dev->slock);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.field = dev->field;
buf->vb.sequence = dev->seqnr++;
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/pci/zoran/zoran_card.c b/drivers/media/pci/zoran/zoran_card.c
index 1136d92..9d2697f 100644
--- a/drivers/media/pci/zoran/zoran_card.c
+++ b/drivers/media/pci/zoran/zoran_card.c
@@ -50,7 +50,7 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <media/v4l2-common.h>
-#include <media/bt819.h>
+#include <media/i2c/bt819.h>
#include "videocodec.h"
#include "zoran.h"
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index ccbc974..0c53805 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -38,7 +38,7 @@ config VIDEO_SH_VOU
depends on MEDIA_CAMERA_SUPPORT
depends on VIDEO_DEV && I2C && HAS_DMA
depends on ARCH_SHMOBILE || COMPILE_TEST
- select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF2_DMA_CONTIG
help
Support for the Video Output Unit (VOU) on SuperH SoCs.
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index f0480d6..de32e3a 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -1281,7 +1281,7 @@ static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe)
*/
static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe)
{
- v4l2_get_timestamp(&vpfe->cur_frm->vb.timestamp);
+ vpfe->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
vpfe->cur_frm->vb.field = vpfe->fmt.fmt.pix.field;
vpfe->cur_frm->vb.sequence = vpfe->sequence++;
vb2_buffer_done(&vpfe->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -1898,7 +1898,6 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
/*
* vpfe_queue_setup - Callback function for buffer setup.
* @vq: vb2_queue ptr
- * @fmt: v4l2 format
* @nbuffers: ptr to number of buffers requested by application
* @nplanes:: contains number of distinct video planes needed to hold a frame
* @sizes[]: contains the size (in bytes) of each plane.
@@ -1908,22 +1907,24 @@ static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
* the buffer count and buffer size
*/
static int vpfe_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
-
- if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage)
- return -EINVAL;
+ unsigned size = vpfe->fmt.fmt.pix.sizeimage;
if (vq->num_buffers + *nbuffers < 3)
*nbuffers = 3 - vq->num_buffers;
+ alloc_ctxs[0] = vpfe->alloc_ctx;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ size = sizes[0];
+ }
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage;
- alloc_ctxs[0] = vpfe->alloc_ctx;
+ sizes[0] = size;
vpfe_dbg(1, vpfe,
"nbuffers=%d, size=%u\n", *nbuffers, sizes[0]);
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 7764b9c..d0092da 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -202,22 +202,20 @@ static void bcap_free_sensor_formats(struct bcap_device *bcap_dev)
}
static int bcap_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
- if (fmt && fmt->fmt.pix.sizeimage < bcap_dev->fmt.sizeimage)
- return -EINVAL;
-
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2;
+ alloc_ctxs[0] = bcap_dev->alloc_ctx;
+
+ if (*nplanes)
+ return sizes[0] < bcap_dev->fmt.sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : bcap_dev->fmt.sizeimage;
- alloc_ctxs[0] = bcap_dev->alloc_ctx;
+ sizes[0] = bcap_dev->fmt.sizeimage;
return 0;
}
@@ -406,7 +404,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
spin_lock(&bcap_dev->lock);
if (!list_empty(&bcap_dev->dma_queue)) {
- v4l2_get_timestamp(&vbuf->timestamp);
+ vb->timestamp = ktime_get_ns();
if (ppi->err) {
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
ppi->err = false;
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 654e964..7d28899 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -246,7 +246,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming)
/* Drop frames that do not start/end with a SOI/EOI markers */
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
- !coda_jpeg_check_buffer(ctx, src_buf)) {
+ !coda_jpeg_check_buffer(ctx, &src_buf->vb2_buf)) {
v4l2_err(&ctx->dev->v4l2_dev,
"dropping invalid JPEG frame %d\n",
ctx->qsequence);
@@ -279,7 +279,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming)
if (meta) {
meta->sequence = src_buf->sequence;
meta->timecode = src_buf->timecode;
- meta->timestamp = src_buf->timestamp;
+ meta->timestamp = src_buf->vb2_buf.timestamp;
meta->start = start;
meta->end = ctx->bitstream_fifo.kfifo.in &
ctx->bitstream_fifo.kfifo.mask;
@@ -1364,7 +1364,7 @@ static void coda_finish_encode(struct coda_ctx *ctx)
dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME;
}
- dst_buf->timestamp = src_buf->timestamp;
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_buf->flags |=
src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -2040,7 +2040,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
dst_buf->flags |= ctx->frame_types[ctx->display_idx];
meta = &ctx->frame_metas[ctx->display_idx];
dst_buf->timecode = meta->timecode;
- dst_buf->timestamp = meta->timestamp;
+ dst_buf->vb2_buf.timestamp = meta->timestamp;
trace_coda_dec_rot_done(ctx, dst_buf, meta);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 15516a6..2d782ce 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -28,7 +28,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/of.h>
-#include <linux/platform_data/coda.h>
+#include <linux/platform_data/media/coda.h>
#include <linux/reset.h>
#include <media/v4l2-ctrls.h>
@@ -131,6 +131,7 @@ static const struct coda_codec coda7_codecs[] = {
CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192),
CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA7_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192),
};
@@ -139,6 +140,7 @@ static const struct coda_codec coda9_codecs[] = {
CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1088),
CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1088),
CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA9_MODE_DECODE_MP2, V4L2_PIX_FMT_MPEG2, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
};
@@ -187,6 +189,7 @@ static const struct coda_video_device coda_bit_decoder = {
.ops = &coda_bit_decode_ops,
.src_formats = {
V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_MPEG2,
V4L2_PIX_FMT_MPEG4,
},
.dst_formats = {
@@ -293,7 +296,8 @@ static void coda_get_max_dimensions(struct coda_dev *dev,
*max_h = h;
}
-const struct coda_video_device *to_coda_video_device(struct video_device *vdev)
+static const struct coda_video_device *to_coda_video_device(struct video_device
+ *vdev)
{
struct coda_dev *dev = video_get_drvdata(vdev);
unsigned int i = vdev - dev->vfd;
@@ -469,6 +473,7 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
/* fallthrough */
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
+ case V4L2_PIX_FMT_MPEG2:
f->fmt.pix.bytesperline = 0;
f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx,
f->fmt.pix.sizeimage,
@@ -920,6 +925,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
@@ -1131,7 +1137,7 @@ static void set_default_params(struct coda_ctx *ctx)
/*
* Queue operations
*/
-static int coda_queue_setup(struct vb2_queue *vq, const void *parg,
+static int coda_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -1250,6 +1256,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
struct vb2_v4l2_buffer *buf;
int ret = 0;
+ if (count < 1)
+ return -EINVAL;
+
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) {
@@ -1262,20 +1271,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
ret = -EINVAL;
goto err;
}
- } else {
- if (count < 1) {
- ret = -EINVAL;
- goto err;
- }
}
ctx->streamon_out = 1;
} else {
- if (count < 1) {
- ret = -EINVAL;
- goto err;
- }
-
ctx->streamon_cap = 1;
}
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c
index 96cd42a..9f899a6 100644
--- a/drivers/media/platform/coda/coda-jpeg.c
+++ b/drivers/media/platform/coda/coda-jpeg.c
@@ -178,14 +178,28 @@ int coda_jpeg_write_tables(struct coda_ctx *ctx)
return 0;
}
-bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb)
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb)
{
- void *vaddr = vb2_plane_vaddr(&vb->vb2_buf, 0);
- u16 soi = be16_to_cpup((__be16 *)vaddr);
- u16 eoi = be16_to_cpup((__be16 *)(vaddr +
- vb2_get_plane_payload(&vb->vb2_buf, 0) - 2));
+ void *vaddr = vb2_plane_vaddr(vb, 0);
+ u16 soi, eoi;
+ int len, i;
+
+ soi = be16_to_cpup((__be16 *)vaddr);
+ if (soi != SOI_MARKER)
+ return false;
+
+ len = vb2_get_plane_payload(vb, 0);
+ vaddr += len - 2;
+ for (i = 0; i < 32; i++) {
+ eoi = be16_to_cpup((__be16 *)(vaddr - i));
+ if (eoi == EOI_MARKER) {
+ if (i > 0)
+ vb2_set_plane_payload(vb, 0, len - i);
+ return true;
+ }
+ }
- return soi == SOI_MARKER && eoi == EOI_MARKER;
+ return false;
}
/*
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 96532b0..d08e984 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -138,7 +138,7 @@ struct coda_buffer_meta {
struct list_head list;
u32 sequence;
struct v4l2_timecode timecode;
- struct timeval timestamp;
+ u64 timestamp;
u32 start;
u32 end;
};
@@ -289,7 +289,7 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf,
int coda_h264_padding(int size, char *p);
-bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_v4l2_buffer *vb);
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_write_tables(struct coda_ctx *ctx);
void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index 469e9d2..554e710 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -3,6 +3,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY
depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF2_DMA_CONTIG
select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT
@@ -19,6 +20,7 @@ config VIDEO_DAVINCI_VPIF_CAPTURE
depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF2_DMA_CONTIG
help
Enables Davinci VPIF module used for capture devices.
@@ -33,6 +35,7 @@ config VIDEO_DM6446_CCDC
depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF_DMA_CONTIG
help
Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
@@ -49,6 +52,7 @@ config VIDEO_DM355_CCDC
depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF_DMA_CONTIG
help
Enables DM355 CCD hw module. DM355 CCDC hw interfaces
@@ -64,6 +68,7 @@ config VIDEO_DM365_ISIF
tristate "TI DM365 ISIF video capture driver"
depends on VIDEO_V4L2 && ARCH_DAVINCI
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF_DMA_CONTIG
help
Enables ISIF hw module. This is the hardware module for
@@ -77,6 +82,7 @@ config VIDEO_DAVINCI_VPBE_DISPLAY
tristate "TI DaVinci VPBE V4L2-Display driver"
depends on VIDEO_V4L2 && ARCH_DAVINCI
depends on HAS_DMA
+ depends on I2C
select VIDEOBUF2_DMA_CONTIG
help
Enables Davinci VPBE module used for display devices.
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 6d91422..0abcdfe 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -74,7 +74,7 @@ static void vpbe_isr_even_field(struct vpbe_display *disp_obj,
if (layer->cur_frm == layer->next_frm)
return;
- v4l2_get_timestamp(&layer->cur_frm->vb.timestamp);
+ layer->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&layer->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
/* Make cur_frm pointing to next_frm */
layer->cur_frm = layer->next_frm;
@@ -228,28 +228,27 @@ static int vpbe_buffer_prepare(struct vb2_buffer *vb)
* This function allocates memory for the buffers
*/
static int
-vpbe_buffer_queue_setup(struct vb2_queue *vq, const void *parg,
+vpbe_buffer_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
/* Get the file handle object and layer object */
struct vpbe_layer *layer = vb2_get_drv_priv(vq);
struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
- if (fmt && fmt->fmt.pix.sizeimage < layer->pix_fmt.sizeimage)
- return -EINVAL;
-
/* Store number of buffers allocated in numbuffer member */
if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS)
*nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers;
+ alloc_ctxs[0] = layer->alloc_ctx;
+
+ if (*nplanes)
+ return sizes[0] < layer->pix_fmt.sizeimage ? -EINVAL : 0;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : layer->pix_fmt.sizeimage;
- alloc_ctxs[0] = layer->alloc_ctx;
+ sizes[0] = layer->pix_fmt.sizeimage;
return 0;
}
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index c1e573b..08f7028 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -104,7 +104,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
/**
* vpif_buffer_queue_setup : Callback function for buffer setup.
* @vq: vb2_queue ptr
- * @fmt: v4l2 format
* @nbuffers: ptr to number of buffers requested by application
* @nplanes:: contains number of distinct video planes needed to hold a frame
* @sizes[]: contains the size (in bytes) of each plane.
@@ -114,26 +113,26 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
* the buffer count and buffer size
*/
static int vpif_buffer_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct channel_obj *ch = vb2_get_drv_priv(vq);
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ unsigned size = common->fmt.fmt.pix.sizeimage;
vpif_dbg(2, debug, "vpif_buffer_setup\n");
- if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
- return -EINVAL;
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ size = sizes[0];
+ }
if (vq->num_buffers + *nbuffers < 3)
*nbuffers = 3 - vq->num_buffers;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
+ sizes[0] = size;
alloc_ctxs[0] = common->alloc_ctx;
/* Calculate the offset for Y and C data in the buffer */
@@ -331,7 +330,7 @@ static struct vb2_ops video_qops = {
*/
static void vpif_process_buffer_complete(struct common_obj *common)
{
- v4l2_get_timestamp(&common->cur_frm->vb.timestamp);
+ common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
/* Make curFrm pointing to nextFrm */
common->cur_frm = common->next_frm;
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index fd27803..f40755c 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -99,7 +99,6 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
/**
* vpif_buffer_queue_setup : Callback function for buffer setup.
* @vq: vb2_queue ptr
- * @fmt: v4l2 format
* @nbuffers: ptr to number of buffers requested by application
* @nplanes:: contains number of distinct video planes needed to hold a frame
* @sizes[]: contains the size (in bytes) of each plane.
@@ -109,22 +108,24 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
* the buffer count and buffer size
*/
static int vpif_buffer_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ unsigned size = common->fmt.fmt.pix.sizeimage;
- if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
- return -EINVAL;
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ size = sizes[0];
+ }
if (vq->num_buffers + *nbuffers < 3)
*nbuffers = 3 - vq->num_buffers;
*nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
+ sizes[0] = size;
alloc_ctxs[0] = common->alloc_ctx;
/* Calculate the offset for Y and C data in the buffer */
@@ -330,7 +331,7 @@ static void process_interlaced_mode(int fid, struct common_obj *common)
/* one frame is displayed If next frame is
* available, release cur_frm and move on */
/* Copy frame display time */
- v4l2_get_timestamp(&common->cur_frm->vb.timestamp);
+ common->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
/* Change status of the cur_frm */
vb2_buffer_done(&common->cur_frm->vb.vb2_buf,
VB2_BUF_STATE_DONE);
@@ -386,8 +387,8 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
if (!channel_first_int[i][channel_id]) {
/* Mark status of the cur_frm to
* done and unlock semaphore on it */
- v4l2_get_timestamp(
- &common->cur_frm->vb.timestamp);
+ common->cur_frm->vb.vb2_buf.timestamp =
+ ktime_get_ns();
vb2_buffer_done(&common->cur_frm->vb.vb2_buf,
VB2_BUF_STATE_DONE);
/* Make cur_frm pointing to next_frm */
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index d82e717..93782f1 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -86,7 +86,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
if (src_vb && dst_vb) {
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->timecode = src_vb->timecode;
dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_vb->flags |=
@@ -125,7 +125,7 @@ static int gsc_get_bufs(struct gsc_ctx *ctx)
if (ret)
return ret;
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
return 0;
}
@@ -212,7 +212,6 @@ put_device:
}
static int gsc_m2m_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
index 0eb34ec..b6716c5 100644
--- a/drivers/media/platform/exynos4-is/common.c
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -10,7 +10,7 @@
*/
#include <linux/module.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "common.h"
/* Called with the media graph mutex held or entity->stream_count > 0. */
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 99e5732..0d549a6 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -193,7 +193,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf)
test_bit(ST_CAPT_RUN, &fimc->state) && deq_buf) {
v_buf = fimc_active_queue_pop(cap);
- v4l2_get_timestamp(&v_buf->vb.timestamp);
+ v_buf->vb.vb2_buf.timestamp = ktime_get_ns();
v_buf->vb.sequence = cap->frame_count++;
vb2_buffer_done(&v_buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -338,37 +338,36 @@ int fimc_capture_resume(struct fimc_dev *fimc)
}
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
- const struct v4l2_format *pfmt = parg;
- const struct v4l2_pix_format_mplane *pixm = NULL;
struct fimc_ctx *ctx = vq->drv_priv;
struct fimc_frame *frame = &ctx->d_frame;
struct fimc_fmt *fmt = frame->fmt;
- unsigned long wh;
+ unsigned long wh = frame->f_width * frame->f_height;
int i;
- if (pfmt) {
- pixm = &pfmt->fmt.pix_mp;
- fmt = fimc_find_format(&pixm->pixelformat, NULL,
- FMT_FLAGS_CAM | FMT_FLAGS_M2M, -1);
- wh = pixm->width * pixm->height;
- } else {
- wh = frame->f_width * frame->f_height;
- }
-
if (fmt == NULL)
return -EINVAL;
+ if (*num_planes) {
+ if (*num_planes != fmt->memplanes)
+ return -EINVAL;
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < (wh * fmt->depth[i]) / 8)
+ return -EINVAL;
+ allocators[i] = ctx->fimc_dev->alloc_ctx;
+ }
+ return 0;
+ }
+
*num_planes = fmt->memplanes;
for (i = 0; i < fmt->memplanes; i++) {
unsigned int size = (wh * fmt->depth[i]) / 8;
- if (pixm)
- sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
- else if (fimc_fmt_is_user_defined(fmt->color))
+
+ if (fimc_fmt_is_user_defined(fmt->color))
sizes[i] = frame->payload[i];
else
sizes[i] = max_t(u32, size, frame->payload[i]);
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index d336fa2..6b74354 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -27,7 +27,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#define dbg(fmt, args...) \
pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args)
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index 6e66484..0dd22ec 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -30,7 +30,7 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "common.h"
#include "media-dev.h"
@@ -39,39 +39,36 @@
#include "fimc-is-param.h"
static int isp_video_capture_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
- const struct v4l2_format *pfmt = parg;
struct fimc_isp *isp = vb2_get_drv_priv(vq);
struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt;
- const struct v4l2_pix_format_mplane *pixm = NULL;
- const struct fimc_fmt *fmt;
+ const struct fimc_fmt *fmt = isp->video_capture.format;
unsigned int wh, i;
- if (pfmt) {
- pixm = &pfmt->fmt.pix_mp;
- fmt = fimc_isp_find_format(&pixm->pixelformat, NULL, -1);
- wh = pixm->width * pixm->height;
- } else {
- fmt = isp->video_capture.format;
- wh = vid_fmt->width * vid_fmt->height;
- }
+ wh = vid_fmt->width * vid_fmt->height;
if (fmt == NULL)
return -EINVAL;
*num_buffers = clamp_t(u32, *num_buffers, FIMC_ISP_REQ_BUFS_MIN,
FIMC_ISP_REQ_BUFS_MAX);
+ if (*num_planes) {
+ if (*num_planes != fmt->memplanes)
+ return -EINVAL;
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < (wh * fmt->depth[i]) / 8)
+ return -EINVAL;
+ allocators[i] = isp->alloc_ctx;
+ }
+ return 0;
+ }
+
*num_planes = fmt->memplanes;
for (i = 0; i < fmt->memplanes; i++) {
- unsigned int size = (wh * fmt->depth[i]) / 8;
- if (pixm)
- sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
- else
- sizes[i] = size;
+ sizes[i] = (wh * fmt->depth[i]) / 8;
allocators[i] = isp->alloc_ctx;
}
@@ -254,7 +251,7 @@ void fimc_isp_video_irq_handler(struct fimc_is *is)
buf_index = (is->i2h_cmd.args[1] - 1) % video->buf_count;
vbuf = &video->buffers[buf_index]->vb;
- v4l2_get_timestamp(&vbuf->timestamp);
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
video->buf_mask &= ~BIT(buf_index);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h
index c2d25df..e0686b5 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.h
+++ b/drivers/media/platform/exynos4-is/fimc-isp.h
@@ -24,7 +24,7 @@
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
extern int fimc_isp_debug;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index 0477716..f0acc55 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -12,7 +12,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "fimc-lite-reg.h"
#include "fimc-lite.h"
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 60660c3..639ee71 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -30,7 +30,7 @@
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "common.h"
#include "fimc-core.h"
@@ -292,7 +292,7 @@ static irqreturn_t flite_irq_handler(int irq, void *priv)
test_bit(ST_FLITE_RUN, &fimc->state) &&
!list_empty(&fimc->active_buf_q)) {
vbuf = fimc_lite_active_queue_pop(fimc);
- v4l2_get_timestamp(&vbuf->vb.timestamp);
+ vbuf->vb.vb2_buf.timestamp = ktime_get_ns();
vbuf->vb.sequence = fimc->frame_count++;
flite_hw_mask_dma_buffer(fimc, vbuf->index);
vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -355,37 +355,34 @@ static void stop_streaming(struct vb2_queue *q)
fimc_lite_stop_capture(fimc, false);
}
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
- const struct v4l2_format *pfmt = parg;
- const struct v4l2_pix_format_mplane *pixm = NULL;
struct fimc_lite *fimc = vq->drv_priv;
struct flite_frame *frame = &fimc->out_frame;
const struct fimc_fmt *fmt = frame->fmt;
- unsigned long wh;
+ unsigned long wh = frame->f_width * frame->f_height;
int i;
- if (pfmt) {
- pixm = &pfmt->fmt.pix_mp;
- fmt = fimc_lite_find_format(&pixm->pixelformat, NULL, 0, -1);
- wh = pixm->width * pixm->height;
- } else {
- wh = frame->f_width * frame->f_height;
- }
-
if (fmt == NULL)
return -EINVAL;
+ if (*num_planes) {
+ if (*num_planes != fmt->memplanes)
+ return -EINVAL;
+ for (i = 0; i < *num_planes; i++) {
+ if (sizes[i] < (wh * fmt->depth[i]) / 8)
+ return -EINVAL;
+ allocators[i] = fimc->alloc_ctx;
+ }
+ return 0;
+ }
+
*num_planes = fmt->memplanes;
for (i = 0; i < fmt->memplanes; i++) {
- unsigned int size = (wh * fmt->depth[i]) / 8;
- if (pixm)
- sizes[i] = max(size, pixm->plane_fmt[i].sizeimage);
- else
- sizes[i] = size;
+ sizes[i] = (wh * fmt->depth[i]) / 8;
allocators[i] = fimc->alloc_ctx;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index b302305..11690d5 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -23,7 +23,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#define FIMC_LITE_DRV_NAME "exynos-fimc-lite"
#define FLITE_CLK_NAME "flite"
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 4d1d64a4..5aa857c 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -132,7 +132,7 @@ static void fimc_device_run(void *priv)
if (ret)
goto dma_unlock;
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_vb->flags |=
src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -176,7 +176,7 @@ static void fimc_job_abort(void *priv)
fimc_m2m_shutdown(priv);
}
-static int fimc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int fimc_queue_setup(struct vb2_queue *vq,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index df0cbcb..0806724 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/regmap.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "media-dev.h"
#include "fimc-reg.h"
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 4f5586a..9481ce3 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -31,7 +31,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-of.h>
#include <media/media-device.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "media-dev.h"
#include "fimc-core.h"
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 0321454..93a96126 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -19,7 +19,7 @@
#include <media/media-entity.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include "fimc-core.h"
#include "fimc-lite.h"
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 4b85105..ff5dabf 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -29,7 +29,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/videodev2.h>
-#include <media/exynos-fimc.h>
+#include <media/drv-intf/exynos-fimc.h>
#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 29973f9..7383818 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -207,7 +207,7 @@ static void dma_callback(void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_vb->flags |=
src_vb->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -798,7 +798,6 @@ struct vb2_dc_conf {
};
static int deinterlace_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index aa2b440..9b878de 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -25,7 +25,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
#include <media/videobuf2-vmalloc.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-dma-sg.h>
@@ -226,7 +226,7 @@ static void mcam_buffer_done(struct mcam_camera *cam, int frame,
vbuf->vb2_buf.planes[0].bytesused = cam->pix_format.sizeimage;
vbuf->sequence = cam->buf_seq[frame];
vbuf->field = V4L2_FIELD_NONE;
- v4l2_get_timestamp(&vbuf->timestamp);
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&vbuf->vb2_buf, 0, cam->pix_format.sizeimage);
vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -1049,24 +1049,25 @@ static int mcam_read_setup(struct mcam_camera *cam)
*/
static int mcam_vb_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *nbufs,
+ unsigned int *nbufs,
unsigned int *num_planes, unsigned int sizes[],
void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct mcam_camera *cam = vb2_get_drv_priv(vq);
int minbufs = (cam->buffer_mode == B_DMA_contig) ? 3 : 2;
+ unsigned size = cam->pix_format.sizeimage;
- if (fmt && fmt->fmt.pix.sizeimage < cam->pix_format.sizeimage)
- return -EINVAL;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : cam->pix_format.sizeimage;
- *num_planes = 1; /* Someday we have to support planar formats... */
if (*nbufs < minbufs)
*nbufs = minbufs;
if (cam->buffer_mode == B_DMA_contig)
alloc_ctxs[0] = cam->vb_alloc_ctx;
else if (cam->buffer_mode == B_DMA_sg)
alloc_ctxs[0] = cam->vb_alloc_ctx_sg;
+
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+ sizes[0] = size;
+ *num_planes = 1; /* Someday we have to support planar formats... */
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index b5f165a..816f4b6 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/mmp-camera.h>
+#include <linux/platform_data/media/mmp-camera.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 03a1b60..3c4012d 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -375,7 +375,7 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data)
src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->flags &=
~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_vb->flags |=
@@ -689,7 +689,6 @@ static const struct v4l2_ioctl_ops emmaprp_ioctl_ops = {
* Queue operations
*/
static int emmaprp_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c
index c6e2527..b8638e4 100644
--- a/drivers/media/platform/omap/omap_vout_vrfb.c
+++ b/drivers/media/platform/omap/omap_vout_vrfb.c
@@ -79,10 +79,12 @@ void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
int j;
for (j = 0; j < VRFB_NUM_BUFS; j++) {
- omap_vout_free_buffer(vout->smsshado_virt_addr[j],
- vout->smsshado_size);
- vout->smsshado_virt_addr[j] = 0;
- vout->smsshado_phy_addr[j] = 0;
+ if (vout->smsshado_virt_addr[j]) {
+ omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+ vout->smsshado_size);
+ vout->smsshado_virt_addr[j] = 0;
+ vout->smsshado_phy_addr[j] = 0;
+ }
}
}
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index f4f5916..ecadca3 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -320,7 +320,6 @@ isp_video_check_format(struct isp_video *video, struct isp_video_fh *vfh)
*/
static int isp_video_queue_setup(struct vb2_queue *queue,
- const void *parg,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -467,7 +466,7 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
list_del(&buf->irqlist);
spin_unlock_irqrestore(&video->irqlock, flags);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
/* Do frame number propagation only if this is the output video node.
* Frame number either comes from the CSI receivers or it gets
diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c
index f8e3e83..485f525 100644
--- a/drivers/media/platform/rcar_jpu.c
+++ b/drivers/media/platform/rcar_jpu.c
@@ -1015,28 +1015,33 @@ error_free:
* ============================================================================
*/
static int jpu_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct jpu_ctx *ctx = vb2_get_drv_priv(vq);
struct jpu_q_data *q_data;
unsigned int i;
q_data = jpu_get_q_data(ctx, vq->type);
- *nplanes = q_data->format.num_planes;
+ if (*nplanes) {
+ if (*nplanes != q_data->format.num_planes)
+ return -EINVAL;
- for (i = 0; i < *nplanes; i++) {
- unsigned int q_size = q_data->format.plane_fmt[i].sizeimage;
- unsigned int f_size = fmt ?
- fmt->fmt.pix_mp.plane_fmt[i].sizeimage : 0;
+ for (i = 0; i < *nplanes; i++) {
+ unsigned int q_size = q_data->format.plane_fmt[i].sizeimage;
- if (fmt && f_size < q_size)
- return -EINVAL;
+ if (sizes[i] < q_size)
+ return -EINVAL;
+ alloc_ctxs[i] = ctx->jpu->alloc_ctx;
+ }
+ return 0;
+ }
- sizes[i] = fmt ? f_size : q_size;
+ *nplanes = q_data->format.num_planes;
+
+ for (i = 0; i < *nplanes; i++) {
+ sizes[i] = q_data->format.plane_fmt[i].sizeimage;
alloc_ctxs[i] = ctx->jpu->alloc_ctx;
}
@@ -1300,17 +1305,17 @@ static int jpu_release(struct file *file)
struct jpu *jpu = video_drvdata(file);
struct jpu_ctx *ctx = fh_to_ctx(file->private_data);
- mutex_lock(&jpu->mutex);
- if (--jpu->ref_count == 0)
- clk_disable_unprepare(jpu->clk);
- mutex_unlock(&jpu->mutex);
-
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
v4l2_ctrl_handler_free(&ctx->ctrl_handler);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
kfree(ctx);
+ mutex_lock(&jpu->mutex);
+ if (--jpu->ref_count == 0)
+ clk_disable_unprepare(jpu->clk);
+ mutex_unlock(&jpu->mutex);
+
return 0;
}
@@ -1560,12 +1565,9 @@ static irqreturn_t jpu_irq_handler(int irq, void *dev_id)
}
dst_buf->field = src_buf->field;
- dst_buf->timestamp = src_buf->timestamp;
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
if (src_buf->flags & V4L2_BUF_FLAG_TIMECODE)
dst_buf->timecode = src_buf->timecode;
- dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
- dst_buf->flags |= src_buf->flags &
- V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_buf->flags = src_buf->flags &
(V4L2_BUF_FLAG_TIMECODE | V4L2_BUF_FLAG_KEYFRAME |
V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME |
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 537b858..ec3abbe 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -338,7 +338,7 @@ irqreturn_t s3c_camif_irq_handler(int irq, void *priv)
if (!WARN_ON(vbuf == NULL)) {
/* Dequeue a filled buffer */
- v4l2_get_timestamp(&vbuf->vb.timestamp);
+ vbuf->vb.vb2_buf.timestamp = ktime_get_ns();
vbuf->vb.sequence = vp->frame_sequence++;
vb2_buffer_done(&vbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
@@ -435,39 +435,28 @@ static void stop_streaming(struct vb2_queue *vq)
camif_stop_capture(vp);
}
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *allocators[])
{
- const struct v4l2_format *pfmt = parg;
- const struct v4l2_pix_format *pix = NULL;
struct camif_vp *vp = vb2_get_drv_priv(vq);
struct camif_dev *camif = vp->camif;
struct camif_frame *frame = &vp->out_frame;
- const struct camif_fmt *fmt;
+ const struct camif_fmt *fmt = vp->out_fmt;
unsigned int size;
- if (pfmt) {
- pix = &pfmt->fmt.pix;
- fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1);
- if (fmt == NULL)
- return -EINVAL;
- size = (pix->width * pix->height * fmt->depth) / 8;
- } else {
- fmt = vp->out_fmt;
- if (fmt == NULL)
- return -EINVAL;
- size = (frame->f_width * frame->f_height * fmt->depth) / 8;
- }
-
- *num_planes = 1;
+ if (fmt == NULL)
+ return -EINVAL;
- if (pix)
- sizes[0] = max(size, pix->sizeimage);
- else
- sizes[0] = size;
+ size = (frame->f_width * frame->f_height * fmt->depth) / 8;
allocators[0] = camif->alloc_ctx;
+ if (*num_planes)
+ return sizes[0] < size ? -EINVAL : 0;
+
+ *num_planes = 1;
+ sizes[0] = size;
+
pr_debug("size: %u\n", sizes[0]);
return 0;
}
diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h
index adaf196..57cbc3d 100644
--- a/drivers/media/platform/s3c-camif/camif-core.h
+++ b/drivers/media/platform/s3c-camif/camif-core.h
@@ -26,7 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
#include <media/videobuf2-v4l2.h>
-#include <media/s3c_camif.h>
+#include <media/drv-intf/s3c_camif.h>
#define S3C_CAMIF_DRIVER_NAME "s3c-camif"
#define CAMIF_REQ_BUFS_MIN 3
diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h
index af2d472..5ad36c1 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.h
+++ b/drivers/media/platform/s3c-camif/camif-regs.h
@@ -13,7 +13,7 @@
#define CAMIF_REGS_H_
#include "camif-core.h"
-#include <media/s3c_camif.h>
+#include <media/drv-intf/s3c_camif.h>
/*
* The id argument indicates the processing path:
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index e1936d9..74bd46c 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -101,7 +101,7 @@ static struct g2d_frame *get_frame(struct g2d_ctx *ctx,
}
}
-static int g2d_queue_setup(struct vb2_queue *vq, const void *parg,
+static int g2d_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -552,7 +552,7 @@ static irqreturn_t g2d_isr(int irq, void *prv)
BUG_ON(dst == NULL);
dst->timecode = src->timecode;
- dst->timestamp = src->timestamp;
+ dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst->flags |=
src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 4a608cb..c3b13a6 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -2430,7 +2430,6 @@ static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
*/
static int s5p_jpeg_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -2621,7 +2620,7 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
}
dst_buf->timecode = src_buf->timecode;
- dst_buf->timestamp = src_buf->timestamp;
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_buf->flags |=
src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
@@ -2752,7 +2751,7 @@ static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
dst_buf->timecode = src_buf->timecode;
- dst_buf->timestamp = src_buf->timestamp;
+ dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp;
v4l2_m2m_buf_done(src_buf, state);
if (curr_ctx->mode == S5P_JPEG_ENCODE)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 3ffe2ec..927ab49 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -85,6 +85,26 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx)
spin_unlock_irqrestore(&dev->condlock, flags);
}
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
+{
+ unsigned long flags;
+ int ctx;
+
+ spin_lock_irqsave(&dev->condlock, flags);
+ ctx = dev->curr_ctx;
+ do {
+ ctx = (ctx + 1) % MFC_NUM_CONTEXTS;
+ if (ctx == dev->curr_ctx) {
+ if (!test_bit(ctx, &dev->ctx_work_bits))
+ ctx = -EAGAIN;
+ break;
+ }
+ } while (!test_bit(ctx, &dev->ctx_work_bits));
+ spin_unlock_irqrestore(&dev->condlock, flags);
+
+ return ctx;
+}
+
/* Wake up context wait_queue */
static void wake_up_ctx(struct s5p_mfc_ctx *ctx, unsigned int reason,
unsigned int err)
@@ -105,6 +125,20 @@ static void wake_up_dev(struct s5p_mfc_dev *dev, unsigned int reason,
wake_up(&dev->queue);
}
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq)
+{
+ struct s5p_mfc_buf *b;
+ int i;
+
+ while (!list_empty(lh)) {
+ b = list_entry(lh->next, struct s5p_mfc_buf, list);
+ for (i = 0; i < b->b->vb2_buf.num_planes; i++)
+ vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
+ vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
+ list_del(&b->list);
+ }
+}
+
static void s5p_mfc_watchdog(unsigned long arg)
{
struct s5p_mfc_dev *dev = (struct s5p_mfc_dev *)arg;
@@ -150,10 +184,8 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
if (!ctx)
continue;
ctx->state = MFCINST_ERROR;
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->dst_queue, &ctx->vq_dst);
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->src_queue, &ctx->vq_src);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
clear_work_bit(ctx);
wake_up_ctx(ctx, S5P_MFC_R2H_CMD_ERR_RET, 0);
}
@@ -233,8 +265,8 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
== dec_y_addr) {
dst_buf->b->timecode =
src_buf->b->timecode;
- dst_buf->b->timestamp =
- src_buf->b->timestamp;
+ dst_buf->b->vb2_buf.timestamp =
+ src_buf->b->vb2_buf.timestamp;
dst_buf->b->flags &=
~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_buf->b->flags |=
@@ -327,7 +359,6 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
unsigned int dst_frame_status;
unsigned int dec_frame_status;
struct s5p_mfc_buf *src_buf;
- unsigned long flags;
unsigned int res_change;
dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
@@ -343,17 +374,16 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
if (res_change == S5P_FIMV_RES_INCREASE ||
res_change == S5P_FIMV_RES_DECREASE) {
ctx->state = MFCINST_RES_CHANGE_INIT;
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
return;
}
if (ctx->dpb_flush_flag)
ctx->dpb_flush_flag = 0;
- spin_lock_irqsave(&dev->irqlock, flags);
/* All frames remaining in the buffer have been extracted */
if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
@@ -413,11 +443,10 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
}
}
leave_handle_frame:
- spin_unlock_irqrestore(&dev->irqlock, flags);
if ((ctx->src_queue_cnt == 0 && ctx->state != MFCINST_FINISHING)
|| ctx->dst_queue_cnt < ctx->pb_count)
clear_work_bit(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
@@ -425,15 +454,13 @@ leave_handle_frame:
if (test_bit(0, &dev->enter_suspend))
wake_up_dev(dev, reason, err);
else
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
/* Error handling for interrupt */
static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
struct s5p_mfc_ctx *ctx, unsigned int reason, unsigned int err)
{
- unsigned long flags;
-
mfc_err("Interrupt Error: %08x\n", err);
if (ctx != NULL) {
@@ -450,13 +477,9 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
clear_work_bit(ctx);
ctx->state = MFCINST_ERROR;
/* Mark all dst buffers as having an error */
- spin_lock_irqsave(&dev->irqlock, flags);
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->dst_queue, &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
/* Mark all src buffers as having an error */
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->src_queue, &ctx->vq_src);
- spin_unlock_irqrestore(&dev->irqlock, flags);
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
wake_up_ctx(ctx, reason, err);
break;
default:
@@ -467,7 +490,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
}
}
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
s5p_mfc_clock_off();
wake_up_dev(dev, reason, err);
return;
@@ -491,7 +514,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
ctx->img_height = s5p_mfc_hw_call(dev->mfc_ops, get_img_height,
dev);
- s5p_mfc_hw_call_void(dev->mfc_ops, dec_calc_dpb_size, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, dec_calc_dpb_size, ctx);
ctx->pb_count = s5p_mfc_hw_call(dev->mfc_ops, get_dpb_count,
dev);
@@ -518,11 +541,11 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
ctx->head_processed = 1;
}
}
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
clear_work_bit(ctx);
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
wake_up_ctx(ctx, reason, err);
}
@@ -532,12 +555,11 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
{
struct s5p_mfc_buf *src_buf;
struct s5p_mfc_dev *dev;
- unsigned long flags;
if (ctx == NULL)
return;
dev = ctx->dev;
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
ctx->int_type = reason;
ctx->int_err = err;
ctx->int_cond = 1;
@@ -545,7 +567,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
if (err == 0) {
ctx->state = MFCINST_RUNNING;
if (!ctx->dpb_flush_flag && ctx->head_processed) {
- spin_lock_irqsave(&dev->irqlock, flags);
if (!list_empty(&ctx->src_queue)) {
src_buf = list_entry(ctx->src_queue.next,
struct s5p_mfc_buf, list);
@@ -554,7 +575,6 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
vb2_buffer_done(&src_buf->b->vb2_buf,
VB2_BUF_STATE_DONE);
}
- spin_unlock_irqrestore(&dev->irqlock, flags);
} else {
ctx->dpb_flush_flag = 0;
}
@@ -563,7 +583,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
s5p_mfc_clock_off();
wake_up(&ctx->queue);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
@@ -582,7 +602,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
ctx->state = MFCINST_FINISHED;
- spin_lock(&dev->irqlock);
if (!list_empty(&ctx->dst_queue)) {
mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
list);
@@ -591,7 +610,6 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, 0);
vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
}
- spin_unlock(&dev->irqlock);
clear_work_bit(ctx);
@@ -599,7 +617,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx)
s5p_mfc_clock_off();
wake_up(&ctx->queue);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
/* Interrupt processing */
@@ -613,6 +631,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
mfc_debug_enter();
/* Reset the timeout watchdog */
atomic_set(&dev->watchdog_cnt, 0);
+ spin_lock(&dev->irqlock);
ctx = dev->ctx[dev->curr_ctx];
/* Get the reason of interrupt and the error code */
reason = s5p_mfc_hw_call(dev->mfc_ops, get_int_reason, dev);
@@ -639,15 +658,15 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
if (ctx->state == MFCINST_FINISHING &&
list_empty(&ctx->ref_queue)) {
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
s5p_mfc_handle_stream_complete(ctx);
break;
}
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
s5p_mfc_handle_frame(ctx, reason, err);
}
@@ -677,7 +696,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
case S5P_MFC_R2H_CMD_WAKEUP_RET:
if (ctx)
clear_work_bit(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
wake_up_dev(dev, reason, err);
clear_bit(0, &dev->hw_lock);
clear_bit(0, &dev->enter_suspend);
@@ -688,7 +707,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
break;
case S5P_MFC_R2H_CMD_COMPLETE_SEQ_RET:
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
ctx->int_type = reason;
ctx->int_err = err;
s5p_mfc_handle_stream_complete(ctx);
@@ -702,12 +721,13 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
default:
mfc_debug(2, "Unknown int reason\n");
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
}
+ spin_unlock(&dev->irqlock);
mfc_debug_leave();
return IRQ_HANDLED;
irq_cleanup_hw:
- s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev);
ctx->int_type = reason;
ctx->int_err = err;
ctx->int_cond = 1;
@@ -716,7 +736,8 @@ irq_cleanup_hw:
s5p_mfc_clock_off();
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ spin_unlock(&dev->irqlock);
mfc_debug(2, "Exit via irq_cleanup_hw\n");
return IRQ_HANDLED;
}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index d1a3f9b..9eb2481 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -308,7 +308,7 @@ struct s5p_mfc_dev {
struct s5p_mfc_pm pm;
struct s5p_mfc_variant *variant;
int num_inst;
- spinlock_t irqlock; /* lock when operating on videobuf2 queues */
+ spinlock_t irqlock; /* lock when operating on context */
spinlock_t condlock; /* lock when changing/checking if a context is
ready to be processed */
struct mutex mfc_mutex; /* video_device lock */
@@ -653,7 +653,7 @@ struct s5p_mfc_ctx {
unsigned int bits;
} slice_size;
- struct s5p_mfc_codec_ops *c_ops;
+ const struct s5p_mfc_codec_ops *c_ops;
struct v4l2_ctrl *ctrls[MFC_MAX_CTRLS];
struct v4l2_ctrl_handler ctrl_handler;
@@ -694,13 +694,7 @@ struct mfc_control {
/* Macro for making hardware specific calls */
#define s5p_mfc_hw_call(f, op, args...) \
- ((f && f->op) ? f->op(args) : -ENODEV)
-
-#define s5p_mfc_hw_call_void(f, op, args...) \
-do { \
- if (f && f->op) \
- f->op(args); \
-} while (0)
+ ((f && f->op) ? f->op(args) : (typeof(f->op(args)))(-ENODEV))
#define fh_to_ctx(__fh) container_of(__fh, struct s5p_mfc_ctx, fh)
#define ctrl_to_ctx(__ctrl) \
@@ -710,6 +704,8 @@ void clear_work_bit(struct s5p_mfc_ctx *ctx);
void set_work_bit(struct s5p_mfc_ctx *ctx);
void clear_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
+int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev);
+void s5p_mfc_cleanup_queue(struct list_head *lh, struct vb2_queue *vq);
#define HAS_PORTNUM(dev) (dev ? (dev->variant ? \
(dev->variant->port_num ? 1 : 0) : 0) : 0)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index 40d8a03..cc88871 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -319,7 +319,7 @@ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
s5p_mfc_clock_on();
s5p_mfc_reset(dev);
- s5p_mfc_hw_call_void(dev->mfc_ops, release_dev_context_buffer, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
s5p_mfc_clock_off();
}
@@ -468,7 +468,7 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
}
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
if (s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
/* Error or timeout */
@@ -482,9 +482,9 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
err_free_desc_buf:
if (ctx->type == MFCINST_DECODER)
- s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
err_free_inst_buf:
- s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
err:
return ret;
}
@@ -493,17 +493,17 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
{
ctx->state = MFCINST_RETURN_INST;
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
/* Wait until instance is returned or timeout occurred */
if (s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
mfc_err("Err returning instance\n");
/* Free resources */
- s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, release_instance_buffer, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
if (ctx->type == MFCINST_DECODER)
- s5p_mfc_hw_call_void(dev->mfc_ops, release_dec_desc_buffer, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
ctx->inst_no = MFC_NO_INSTANCE_SET;
ctx->state = MFCINST_FREE;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 8c5060a..f2d6376 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -252,7 +252,7 @@ static int s5p_mfc_ctx_ready(struct s5p_mfc_ctx *ctx)
return 0;
}
-static struct s5p_mfc_codec_ops decoder_codec_ops = {
+static const struct s5p_mfc_codec_ops decoder_codec_ops = {
.pre_seq_start = NULL,
.post_seq_start = NULL,
.pre_frame_start = NULL,
@@ -523,7 +523,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
if (ret)
goto out;
- s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
ctx->dst_bufs_cnt = 0;
} else if (ctx->capture_state == QUEUE_FREE) {
WARN_ON(ctx->dst_bufs_cnt != 0);
@@ -551,7 +551,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
0);
} else {
@@ -831,7 +831,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
spin_unlock_irqrestore(&dev->irqlock, flags);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
mfc_err("EOS: marking last buffer of stream");
buf = list_entry(ctx->src_queue.prev,
@@ -888,7 +888,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = {
};
static int s5p_mfc_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *buf_count,
+ unsigned int *buf_count,
unsigned int *plane_count, unsigned int psize[],
void *allocators[])
{
@@ -1012,7 +1012,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
/* If context is ready then dev = work->data;schedule it to run */
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
return 0;
}
@@ -1023,42 +1023,41 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
struct s5p_mfc_dev *dev = ctx->dev;
int aborted = 0;
+ spin_lock_irqsave(&dev->irqlock, flags);
if ((ctx->state == MFCINST_FINISHING ||
ctx->state == MFCINST_RUNNING) &&
dev->curr_ctx == ctx->num && dev->hw_lock) {
ctx->state = MFCINST_ABORT;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_FRAME_DONE_RET, 0);
aborted = 1;
+ spin_lock_irqsave(&dev->irqlock, flags);
}
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- spin_lock_irqsave(&dev->irqlock, flags);
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->dst_queue, &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
INIT_LIST_HEAD(&ctx->dst_queue);
ctx->dst_queue_cnt = 0;
ctx->dpb_flush_flag = 1;
ctx->dec_dst_flag = 0;
- spin_unlock_irqrestore(&dev->irqlock, flags);
if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) {
ctx->state = MFCINST_FLUSH;
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ spin_unlock_irqrestore(&dev->irqlock, flags);
if (s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
mfc_err("Err flushing buffers\n");
+ spin_lock_irqsave(&dev->irqlock, flags);
}
- }
- if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- spin_lock_irqsave(&dev->irqlock, flags);
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->src_queue, &ctx->vq_src);
+ } else if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
INIT_LIST_HEAD(&ctx->src_queue);
ctx->src_queue_cnt = 0;
- spin_unlock_irqrestore(&dev->irqlock, flags);
}
if (aborted)
ctx->state = MFCINST_RUNNING;
+ spin_unlock_irqrestore(&dev->irqlock, flags);
}
@@ -1091,7 +1090,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
}
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
static struct vb2_ops s5p_mfc_dec_qops = {
@@ -1104,7 +1103,7 @@ static struct vb2_ops s5p_mfc_dec_qops = {
.buf_queue = s5p_mfc_buf_queue,
};
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
+const struct s5p_mfc_codec_ops *get_dec_codec_ops(void)
{
return &decoder_codec_ops;
}
@@ -1119,7 +1118,7 @@ const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void)
return &s5p_mfc_dec_ioctl_ops;
}
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \
&& V4L2_CTRL_DRIVER_PRIV(x))
int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
index d06a7ca..886628b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.h
@@ -13,7 +13,7 @@
#ifndef S5P_MFC_DEC_H_
#define S5P_MFC_DEC_H_
-struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
+const struct s5p_mfc_codec_ops *get_dec_codec_ops(void);
struct vb2_ops *get_dec_queue_ops(void);
const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void);
struct s5p_mfc_fmt *get_dec_def_fmt(bool src);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 5c678ec..0434f02 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -769,15 +769,12 @@ static int enc_pre_seq_start(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_buf *dst_mb;
unsigned long dst_addr;
unsigned int dst_size;
- unsigned long flags;
- spin_lock_irqsave(&dev->irqlock, flags);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
- s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+ s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
return 0;
}
@@ -786,11 +783,9 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_buf *dst_mb;
- unsigned long flags;
unsigned int enc_pb_count;
if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
- spin_lock_irqsave(&dev->irqlock, flags);
if (!list_empty(&ctx->dst_queue)) {
dst_mb = list_entry(ctx->dst_queue.next,
struct s5p_mfc_buf, list);
@@ -802,14 +797,13 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
vb2_buffer_done(&dst_mb->b->vb2_buf,
VB2_BUF_STATE_DONE);
}
- spin_unlock_irqrestore(&dev->irqlock, flags);
}
if (!IS_MFCV6_PLUS(dev)) {
ctx->state = MFCINST_RUNNING;
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
enc_pb_count = s5p_mfc_hw_call(dev->mfc_ops,
get_enc_dpb_count, dev);
@@ -826,25 +820,20 @@ static int enc_pre_frame_start(struct s5p_mfc_ctx *ctx)
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
- unsigned long flags;
unsigned long src_y_addr, src_c_addr, dst_addr;
unsigned int dst_size;
- spin_lock_irqsave(&dev->irqlock, flags);
src_mb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
src_y_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 0);
src_c_addr = vb2_dma_contig_plane_dma_addr(&src_mb->b->vb2_buf, 1);
- s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_frame_buffer, ctx,
+ s5p_mfc_hw_call(dev->mfc_ops, set_enc_frame_buffer, ctx,
src_y_addr, src_c_addr);
- spin_unlock_irqrestore(&dev->irqlock, flags);
- spin_lock_irqsave(&dev->irqlock, flags);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
- s5p_mfc_hw_call_void(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
+ s5p_mfc_hw_call(dev->mfc_ops, set_enc_stream_buffer, ctx, dst_addr,
dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
return 0;
}
@@ -857,7 +846,6 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
unsigned long mb_y_addr, mb_c_addr;
int slice_type;
unsigned int strm_size;
- unsigned long flags;
slice_type = s5p_mfc_hw_call(dev->mfc_ops, get_enc_slice_type, dev);
strm_size = s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev);
@@ -865,9 +853,8 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Encoded stream size: %d\n", strm_size);
mfc_debug(2, "Display order: %d\n",
mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT));
- spin_lock_irqsave(&dev->irqlock, flags);
if (slice_type >= 0) {
- s5p_mfc_hw_call_void(dev->mfc_ops, get_enc_frame_buffer, ctx,
+ s5p_mfc_hw_call(dev->mfc_ops, get_enc_frame_buffer, ctx,
&enc_y_addr, &enc_c_addr);
list_for_each_entry(mb_entry, &ctx->src_queue, list) {
mb_y_addr = vb2_dma_contig_plane_dma_addr(
@@ -929,14 +916,13 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
vb2_set_plane_payload(&mb_entry->b->vb2_buf, 0, strm_size);
vb2_buffer_done(&mb_entry->b->vb2_buf, VB2_BUF_STATE_DONE);
}
- spin_unlock_irqrestore(&dev->irqlock, flags);
if ((ctx->src_queue_cnt == 0) || (ctx->dst_queue_cnt == 0))
clear_work_bit(ctx);
return 0;
}
-static struct s5p_mfc_codec_ops encoder_codec_ops = {
+static const struct s5p_mfc_codec_ops encoder_codec_ops = {
.pre_seq_start = enc_pre_seq_start,
.post_seq_start = enc_post_seq_start,
.pre_frame_start = enc_pre_frame_start,
@@ -1120,7 +1106,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt_mp->width, pix_fmt_mp->height,
ctx->img_width, ctx->img_height);
- s5p_mfc_hw_call_void(dev->mfc_ops, enc_calc_src_size, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, enc_calc_src_size, ctx);
pix_fmt_mp->plane_fmt[0].sizeimage = ctx->luma_size;
pix_fmt_mp->plane_fmt[0].bytesperline = ctx->buf_width;
pix_fmt_mp->plane_fmt[1].sizeimage = ctx->chroma_size;
@@ -1178,7 +1164,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
if (reqbufs->count == 0) {
mfc_debug(2, "Freeing buffers\n");
ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers,
+ s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
ctx);
ctx->output_state = QUEUE_FREE;
return ret;
@@ -1741,7 +1727,7 @@ static int vidioc_encoder_cmd(struct file *file, void *priv,
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
spin_unlock_irqrestore(&dev->irqlock, flags);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
} else {
mfc_debug(2, "EOS: marking last buffer of stream\n");
buf = list_entry(ctx->src_queue.prev,
@@ -1818,7 +1804,6 @@ static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb)
}
static int s5p_mfc_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *buf_count, unsigned int *plane_count,
unsigned int psize[], void *allocators[])
{
@@ -1969,7 +1954,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
/* If context is ready then dev = work->data;schedule it to run */
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
return 0;
}
@@ -1990,15 +1975,13 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
ctx->state = MFCINST_FINISHED;
spin_lock_irqsave(&dev->irqlock, flags);
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue,
- &ctx->dst_queue, &ctx->vq_dst);
+ s5p_mfc_cleanup_queue(&ctx->dst_queue, &ctx->vq_dst);
INIT_LIST_HEAD(&ctx->dst_queue);
ctx->dst_queue_cnt = 0;
}
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
cleanup_ref_queue(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, cleanup_queue, &ctx->src_queue,
- &ctx->vq_src);
+ s5p_mfc_cleanup_queue(&ctx->src_queue, &ctx->vq_src);
INIT_LIST_HEAD(&ctx->src_queue);
ctx->src_queue_cnt = 0;
}
@@ -2038,7 +2021,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
}
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
- s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
}
static struct vb2_ops s5p_mfc_enc_qops = {
@@ -2052,7 +2035,7 @@ static struct vb2_ops s5p_mfc_enc_qops = {
.buf_queue = s5p_mfc_buf_queue,
};
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
+const struct s5p_mfc_codec_ops *get_enc_codec_ops(void)
{
return &encoder_codec_ops;
}
@@ -2067,7 +2050,7 @@ const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void)
return &s5p_mfc_enc_ioctl_ops;
}
-#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2CLASS(x) == V4L2_CTRL_CLASS_MPEG) \
+#define IS_MFC51_PRIV(x) ((V4L2_CTRL_ID2WHICH(x) == V4L2_CTRL_CLASS_MPEG) \
&& V4L2_CTRL_DRIVER_PRIV(x))
int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
index 5118d46..d0d42f8 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.h
@@ -13,7 +13,7 @@
#ifndef S5P_MFC_ENC_H_
#define S5P_MFC_ENC_H_
-struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
+const struct s5p_mfc_codec_ops *get_enc_codec_ops(void);
struct vb2_ops *get_enc_queue_ops(void);
const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void);
struct s5p_mfc_fmt *get_enc_def_fmt(bool src);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 77a08b1..b6ac417 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -20,254 +20,254 @@
struct s5p_mfc_regs {
/* codec common registers */
- volatile void __iomem *risc_on;
- volatile void __iomem *risc2host_int;
- volatile void __iomem *host2risc_int;
- volatile void __iomem *risc_base_address;
- volatile void __iomem *mfc_reset;
- volatile void __iomem *host2risc_command;
- volatile void __iomem *risc2host_command;
- volatile void __iomem *mfc_bus_reset_ctrl;
- volatile void __iomem *firmware_version;
- volatile void __iomem *instance_id;
- volatile void __iomem *codec_type;
- volatile void __iomem *context_mem_addr;
- volatile void __iomem *context_mem_size;
- volatile void __iomem *pixel_format;
- volatile void __iomem *metadata_enable;
- volatile void __iomem *mfc_version;
- volatile void __iomem *dbg_info_enable;
- volatile void __iomem *dbg_buffer_addr;
- volatile void __iomem *dbg_buffer_size;
- volatile void __iomem *hed_control;
- volatile void __iomem *mfc_timeout_value;
- volatile void __iomem *hed_shared_mem_addr;
- volatile void __iomem *dis_shared_mem_addr;/* only v7 */
- volatile void __iomem *ret_instance_id;
- volatile void __iomem *error_code;
- volatile void __iomem *dbg_buffer_output_size;
- volatile void __iomem *metadata_status;
- volatile void __iomem *metadata_addr_mb_info;
- volatile void __iomem *metadata_size_mb_info;
- volatile void __iomem *dbg_info_stage_counter;
+ void __iomem *risc_on;
+ void __iomem *risc2host_int;
+ void __iomem *host2risc_int;
+ void __iomem *risc_base_address;
+ void __iomem *mfc_reset;
+ void __iomem *host2risc_command;
+ void __iomem *risc2host_command;
+ void __iomem *mfc_bus_reset_ctrl;
+ void __iomem *firmware_version;
+ void __iomem *instance_id;
+ void __iomem *codec_type;
+ void __iomem *context_mem_addr;
+ void __iomem *context_mem_size;
+ void __iomem *pixel_format;
+ void __iomem *metadata_enable;
+ void __iomem *mfc_version;
+ void __iomem *dbg_info_enable;
+ void __iomem *dbg_buffer_addr;
+ void __iomem *dbg_buffer_size;
+ void __iomem *hed_control;
+ void __iomem *mfc_timeout_value;
+ void __iomem *hed_shared_mem_addr;
+ void __iomem *dis_shared_mem_addr;/* only v7 */
+ void __iomem *ret_instance_id;
+ void __iomem *error_code;
+ void __iomem *dbg_buffer_output_size;
+ void __iomem *metadata_status;
+ void __iomem *metadata_addr_mb_info;
+ void __iomem *metadata_size_mb_info;
+ void __iomem *dbg_info_stage_counter;
/* decoder registers */
- volatile void __iomem *d_crc_ctrl;
- volatile void __iomem *d_dec_options;
- volatile void __iomem *d_display_delay;
- volatile void __iomem *d_set_frame_width;
- volatile void __iomem *d_set_frame_height;
- volatile void __iomem *d_sei_enable;
- volatile void __iomem *d_min_num_dpb;
- volatile void __iomem *d_min_first_plane_dpb_size;
- volatile void __iomem *d_min_second_plane_dpb_size;
- volatile void __iomem *d_min_third_plane_dpb_size;/* only v8 */
- volatile void __iomem *d_min_num_mv;
- volatile void __iomem *d_mvc_num_views;
- volatile void __iomem *d_min_num_dis;/* only v7 */
- volatile void __iomem *d_min_first_dis_size;/* only v7 */
- volatile void __iomem *d_min_second_dis_size;/* only v7 */
- volatile void __iomem *d_min_third_dis_size;/* only v7 */
- volatile void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */
- volatile void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
- volatile void __iomem *d_post_filter_luma_dpb2;/* only v7 */
- volatile void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
- volatile void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
- volatile void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
- volatile void __iomem *d_num_dpb;
- volatile void __iomem *d_num_mv;
- volatile void __iomem *d_init_buffer_options;
- volatile void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
- volatile void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
- volatile void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
- volatile void __iomem *d_first_plane_dpb_size;
- volatile void __iomem *d_second_plane_dpb_size;
- volatile void __iomem *d_third_plane_dpb_size;/* only v8 */
- volatile void __iomem *d_mv_buffer_size;
- volatile void __iomem *d_first_plane_dpb;
- volatile void __iomem *d_second_plane_dpb;
- volatile void __iomem *d_third_plane_dpb;
- volatile void __iomem *d_mv_buffer;
- volatile void __iomem *d_scratch_buffer_addr;
- volatile void __iomem *d_scratch_buffer_size;
- volatile void __iomem *d_metadata_buffer_addr;
- volatile void __iomem *d_metadata_buffer_size;
- volatile void __iomem *d_nal_start_options;/* v7 and v8 */
- volatile void __iomem *d_cpb_buffer_addr;
- volatile void __iomem *d_cpb_buffer_size;
- volatile void __iomem *d_available_dpb_flag_upper;
- volatile void __iomem *d_available_dpb_flag_lower;
- volatile void __iomem *d_cpb_buffer_offset;
- volatile void __iomem *d_slice_if_enable;
- volatile void __iomem *d_picture_tag;
- volatile void __iomem *d_stream_data_size;
- volatile void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
- volatile void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
- volatile void __iomem *d_display_frame_width;
- volatile void __iomem *d_display_frame_height;
- volatile void __iomem *d_display_status;
- volatile void __iomem *d_display_first_plane_addr;
- volatile void __iomem *d_display_second_plane_addr;
- volatile void __iomem *d_display_third_plane_addr;/* only v8 */
- volatile void __iomem *d_display_frame_type;
- volatile void __iomem *d_display_crop_info1;
- volatile void __iomem *d_display_crop_info2;
- volatile void __iomem *d_display_picture_profile;
- volatile void __iomem *d_display_luma_crc;/* v7 and v8 */
- volatile void __iomem *d_display_chroma0_crc;/* v7 and v8 */
- volatile void __iomem *d_display_chroma1_crc;/* only v8 */
- volatile void __iomem *d_display_luma_crc_top;/* only v6 */
- volatile void __iomem *d_display_chroma_crc_top;/* only v6 */
- volatile void __iomem *d_display_luma_crc_bot;/* only v6 */
- volatile void __iomem *d_display_chroma_crc_bot;/* only v6 */
- volatile void __iomem *d_display_aspect_ratio;
- volatile void __iomem *d_display_extended_ar;
- volatile void __iomem *d_decoded_frame_width;
- volatile void __iomem *d_decoded_frame_height;
- volatile void __iomem *d_decoded_status;
- volatile void __iomem *d_decoded_first_plane_addr;
- volatile void __iomem *d_decoded_second_plane_addr;
- volatile void __iomem *d_decoded_third_plane_addr;/* only v8 */
- volatile void __iomem *d_decoded_frame_type;
- volatile void __iomem *d_decoded_crop_info1;
- volatile void __iomem *d_decoded_crop_info2;
- volatile void __iomem *d_decoded_picture_profile;
- volatile void __iomem *d_decoded_nal_size;
- volatile void __iomem *d_decoded_luma_crc;
- volatile void __iomem *d_decoded_chroma0_crc;
- volatile void __iomem *d_decoded_chroma1_crc;/* only v8 */
- volatile void __iomem *d_ret_picture_tag_top;
- volatile void __iomem *d_ret_picture_tag_bot;
- volatile void __iomem *d_ret_picture_time_top;
- volatile void __iomem *d_ret_picture_time_bot;
- volatile void __iomem *d_chroma_format;
- volatile void __iomem *d_vc1_info;/* v7 and v8 */
- volatile void __iomem *d_mpeg4_info;
- volatile void __iomem *d_h264_info;
- volatile void __iomem *d_metadata_addr_concealed_mb;
- volatile void __iomem *d_metadata_size_concealed_mb;
- volatile void __iomem *d_metadata_addr_vc1_param;
- volatile void __iomem *d_metadata_size_vc1_param;
- volatile void __iomem *d_metadata_addr_sei_nal;
- volatile void __iomem *d_metadata_size_sei_nal;
- volatile void __iomem *d_metadata_addr_vui;
- volatile void __iomem *d_metadata_size_vui;
- volatile void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
- volatile void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
- volatile void __iomem *d_mvc_view_id;
- volatile void __iomem *d_frame_pack_sei_avail;
- volatile void __iomem *d_frame_pack_arrgment_id;
- volatile void __iomem *d_frame_pack_sei_info;
- volatile void __iomem *d_frame_pack_grid_pos;
- volatile void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
- volatile void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
- volatile void __iomem *d_display_first_addr;/* only v7 */
- volatile void __iomem *d_display_second_addr;/* only v7 */
- volatile void __iomem *d_display_third_addr;/* only v7 */
- volatile void __iomem *d_decoded_first_addr;/* only v7 */
- volatile void __iomem *d_decoded_second_addr;/* only v7 */
- volatile void __iomem *d_decoded_third_addr;/* only v7 */
- volatile void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
- volatile void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
+ void __iomem *d_crc_ctrl;
+ void __iomem *d_dec_options;
+ void __iomem *d_display_delay;
+ void __iomem *d_set_frame_width;
+ void __iomem *d_set_frame_height;
+ void __iomem *d_sei_enable;
+ void __iomem *d_min_num_dpb;
+ void __iomem *d_min_first_plane_dpb_size;
+ void __iomem *d_min_second_plane_dpb_size;
+ void __iomem *d_min_third_plane_dpb_size;/* only v8 */
+ void __iomem *d_min_num_mv;
+ void __iomem *d_mvc_num_views;
+ void __iomem *d_min_num_dis;/* only v7 */
+ void __iomem *d_min_first_dis_size;/* only v7 */
+ void __iomem *d_min_second_dis_size;/* only v7 */
+ void __iomem *d_min_third_dis_size;/* only v7 */
+ void __iomem *d_post_filter_luma_dpb0;/* v7 and v8 */
+ void __iomem *d_post_filter_luma_dpb1;/* v7 and v8 */
+ void __iomem *d_post_filter_luma_dpb2;/* only v7 */
+ void __iomem *d_post_filter_chroma_dpb0;/* v7 and v8 */
+ void __iomem *d_post_filter_chroma_dpb1;/* v7 and v8 */
+ void __iomem *d_post_filter_chroma_dpb2;/* only v7 */
+ void __iomem *d_num_dpb;
+ void __iomem *d_num_mv;
+ void __iomem *d_init_buffer_options;
+ void __iomem *d_first_plane_dpb_stride_size;/* only v8 */
+ void __iomem *d_second_plane_dpb_stride_size;/* only v8 */
+ void __iomem *d_third_plane_dpb_stride_size;/* only v8 */
+ void __iomem *d_first_plane_dpb_size;
+ void __iomem *d_second_plane_dpb_size;
+ void __iomem *d_third_plane_dpb_size;/* only v8 */
+ void __iomem *d_mv_buffer_size;
+ void __iomem *d_first_plane_dpb;
+ void __iomem *d_second_plane_dpb;
+ void __iomem *d_third_plane_dpb;
+ void __iomem *d_mv_buffer;
+ void __iomem *d_scratch_buffer_addr;
+ void __iomem *d_scratch_buffer_size;
+ void __iomem *d_metadata_buffer_addr;
+ void __iomem *d_metadata_buffer_size;
+ void __iomem *d_nal_start_options;/* v7 and v8 */
+ void __iomem *d_cpb_buffer_addr;
+ void __iomem *d_cpb_buffer_size;
+ void __iomem *d_available_dpb_flag_upper;
+ void __iomem *d_available_dpb_flag_lower;
+ void __iomem *d_cpb_buffer_offset;
+ void __iomem *d_slice_if_enable;
+ void __iomem *d_picture_tag;
+ void __iomem *d_stream_data_size;
+ void __iomem *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+ void __iomem *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+ void __iomem *d_display_frame_width;
+ void __iomem *d_display_frame_height;
+ void __iomem *d_display_status;
+ void __iomem *d_display_first_plane_addr;
+ void __iomem *d_display_second_plane_addr;
+ void __iomem *d_display_third_plane_addr;/* only v8 */
+ void __iomem *d_display_frame_type;
+ void __iomem *d_display_crop_info1;
+ void __iomem *d_display_crop_info2;
+ void __iomem *d_display_picture_profile;
+ void __iomem *d_display_luma_crc;/* v7 and v8 */
+ void __iomem *d_display_chroma0_crc;/* v7 and v8 */
+ void __iomem *d_display_chroma1_crc;/* only v8 */
+ void __iomem *d_display_luma_crc_top;/* only v6 */
+ void __iomem *d_display_chroma_crc_top;/* only v6 */
+ void __iomem *d_display_luma_crc_bot;/* only v6 */
+ void __iomem *d_display_chroma_crc_bot;/* only v6 */
+ void __iomem *d_display_aspect_ratio;
+ void __iomem *d_display_extended_ar;
+ void __iomem *d_decoded_frame_width;
+ void __iomem *d_decoded_frame_height;
+ void __iomem *d_decoded_status;
+ void __iomem *d_decoded_first_plane_addr;
+ void __iomem *d_decoded_second_plane_addr;
+ void __iomem *d_decoded_third_plane_addr;/* only v8 */
+ void __iomem *d_decoded_frame_type;
+ void __iomem *d_decoded_crop_info1;
+ void __iomem *d_decoded_crop_info2;
+ void __iomem *d_decoded_picture_profile;
+ void __iomem *d_decoded_nal_size;
+ void __iomem *d_decoded_luma_crc;
+ void __iomem *d_decoded_chroma0_crc;
+ void __iomem *d_decoded_chroma1_crc;/* only v8 */
+ void __iomem *d_ret_picture_tag_top;
+ void __iomem *d_ret_picture_tag_bot;
+ void __iomem *d_ret_picture_time_top;
+ void __iomem *d_ret_picture_time_bot;
+ void __iomem *d_chroma_format;
+ void __iomem *d_vc1_info;/* v7 and v8 */
+ void __iomem *d_mpeg4_info;
+ void __iomem *d_h264_info;
+ void __iomem *d_metadata_addr_concealed_mb;
+ void __iomem *d_metadata_size_concealed_mb;
+ void __iomem *d_metadata_addr_vc1_param;
+ void __iomem *d_metadata_size_vc1_param;
+ void __iomem *d_metadata_addr_sei_nal;
+ void __iomem *d_metadata_size_sei_nal;
+ void __iomem *d_metadata_addr_vui;
+ void __iomem *d_metadata_size_vui;
+ void __iomem *d_metadata_addr_mvcvui;/* v7 and v8 */
+ void __iomem *d_metadata_size_mvcvui;/* v7 and v8 */
+ void __iomem *d_mvc_view_id;
+ void __iomem *d_frame_pack_sei_avail;
+ void __iomem *d_frame_pack_arrgment_id;
+ void __iomem *d_frame_pack_sei_info;
+ void __iomem *d_frame_pack_grid_pos;
+ void __iomem *d_display_recovery_sei_info;/* v7 and v8 */
+ void __iomem *d_decoded_recovery_sei_info;/* v7 and v8 */
+ void __iomem *d_display_first_addr;/* only v7 */
+ void __iomem *d_display_second_addr;/* only v7 */
+ void __iomem *d_display_third_addr;/* only v7 */
+ void __iomem *d_decoded_first_addr;/* only v7 */
+ void __iomem *d_decoded_second_addr;/* only v7 */
+ void __iomem *d_decoded_third_addr;/* only v7 */
+ void __iomem *d_used_dpb_flag_upper;/* v7 and v8 */
+ void __iomem *d_used_dpb_flag_lower;/* v7 and v8 */
/* encoder registers */
- volatile void __iomem *e_frame_width;
- volatile void __iomem *e_frame_height;
- volatile void __iomem *e_cropped_frame_width;
- volatile void __iomem *e_cropped_frame_height;
- volatile void __iomem *e_frame_crop_offset;
- volatile void __iomem *e_enc_options;
- volatile void __iomem *e_picture_profile;
- volatile void __iomem *e_vbv_buffer_size;
- volatile void __iomem *e_vbv_init_delay;
- volatile void __iomem *e_fixed_picture_qp;
- volatile void __iomem *e_rc_config;
- volatile void __iomem *e_rc_qp_bound;
- volatile void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
- volatile void __iomem *e_rc_mode;
- volatile void __iomem *e_mb_rc_config;
- volatile void __iomem *e_padding_ctrl;
- volatile void __iomem *e_air_threshold;
- volatile void __iomem *e_mv_hor_range;
- volatile void __iomem *e_mv_ver_range;
- volatile void __iomem *e_num_dpb;
- volatile void __iomem *e_luma_dpb;
- volatile void __iomem *e_chroma_dpb;
- volatile void __iomem *e_me_buffer;
- volatile void __iomem *e_scratch_buffer_addr;
- volatile void __iomem *e_scratch_buffer_size;
- volatile void __iomem *e_tmv_buffer0;
- volatile void __iomem *e_tmv_buffer1;
- volatile void __iomem *e_ir_buffer_addr;/* v7 and v8 */
- volatile void __iomem *e_source_first_plane_addr;
- volatile void __iomem *e_source_second_plane_addr;
- volatile void __iomem *e_source_third_plane_addr;/* v7 and v8 */
- volatile void __iomem *e_source_first_plane_stride;/* v7 and v8 */
- volatile void __iomem *e_source_second_plane_stride;/* v7 and v8 */
- volatile void __iomem *e_source_third_plane_stride;/* v7 and v8 */
- volatile void __iomem *e_stream_buffer_addr;
- volatile void __iomem *e_stream_buffer_size;
- volatile void __iomem *e_roi_buffer_addr;
- volatile void __iomem *e_param_change;
- volatile void __iomem *e_ir_size;
- volatile void __iomem *e_gop_config;
- volatile void __iomem *e_mslice_mode;
- volatile void __iomem *e_mslice_size_mb;
- volatile void __iomem *e_mslice_size_bits;
- volatile void __iomem *e_frame_insertion;
- volatile void __iomem *e_rc_frame_rate;
- volatile void __iomem *e_rc_bit_rate;
- volatile void __iomem *e_rc_roi_ctrl;
- volatile void __iomem *e_picture_tag;
- volatile void __iomem *e_bit_count_enable;
- volatile void __iomem *e_max_bit_count;
- volatile void __iomem *e_min_bit_count;
- volatile void __iomem *e_metadata_buffer_addr;
- volatile void __iomem *e_metadata_buffer_size;
- volatile void __iomem *e_encoded_source_first_plane_addr;
- volatile void __iomem *e_encoded_source_second_plane_addr;
- volatile void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
- volatile void __iomem *e_stream_size;
- volatile void __iomem *e_slice_type;
- volatile void __iomem *e_picture_count;
- volatile void __iomem *e_ret_picture_tag;
- volatile void __iomem *e_stream_buffer_write_pointer; /* only v6 */
- volatile void __iomem *e_recon_luma_dpb_addr;
- volatile void __iomem *e_recon_chroma_dpb_addr;
- volatile void __iomem *e_metadata_addr_enc_slice;
- volatile void __iomem *e_metadata_size_enc_slice;
- volatile void __iomem *e_mpeg4_options;
- volatile void __iomem *e_mpeg4_hec_period;
- volatile void __iomem *e_aspect_ratio;
- volatile void __iomem *e_extended_sar;
- volatile void __iomem *e_h264_options;
- volatile void __iomem *e_h264_options_2;/* v7 and v8 */
- volatile void __iomem *e_h264_lf_alpha_offset;
- volatile void __iomem *e_h264_lf_beta_offset;
- volatile void __iomem *e_h264_i_period;
- volatile void __iomem *e_h264_fmo_slice_grp_map_type;
- volatile void __iomem *e_h264_fmo_num_slice_grp_minus1;
- volatile void __iomem *e_h264_fmo_slice_grp_change_dir;
- volatile void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
- volatile void __iomem *e_h264_fmo_run_length_minus1_0;
- volatile void __iomem *e_h264_aso_slice_order_0;
- volatile void __iomem *e_h264_chroma_qp_offset;
- volatile void __iomem *e_h264_num_t_layer;
- volatile void __iomem *e_h264_hierarchical_qp_layer0;
- volatile void __iomem *e_h264_frame_packing_sei_info;
- volatile void __iomem *e_h264_nal_control;/* v7 and v8 */
- volatile void __iomem *e_mvc_frame_qp_view1;
- volatile void __iomem *e_mvc_rc_bit_rate_view1;
- volatile void __iomem *e_mvc_rc_qbound_view1;
- volatile void __iomem *e_mvc_rc_mode_view1;
- volatile void __iomem *e_mvc_inter_view_prediction_on;
- volatile void __iomem *e_vp8_options;/* v7 and v8 */
- volatile void __iomem *e_vp8_filter_options;/* v7 and v8 */
- volatile void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
- volatile void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
- volatile void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
- volatile void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
- volatile void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+ void __iomem *e_frame_width;
+ void __iomem *e_frame_height;
+ void __iomem *e_cropped_frame_width;
+ void __iomem *e_cropped_frame_height;
+ void __iomem *e_frame_crop_offset;
+ void __iomem *e_enc_options;
+ void __iomem *e_picture_profile;
+ void __iomem *e_vbv_buffer_size;
+ void __iomem *e_vbv_init_delay;
+ void __iomem *e_fixed_picture_qp;
+ void __iomem *e_rc_config;
+ void __iomem *e_rc_qp_bound;
+ void __iomem *e_rc_qp_bound_pb;/* v7 and v8 */
+ void __iomem *e_rc_mode;
+ void __iomem *e_mb_rc_config;
+ void __iomem *e_padding_ctrl;
+ void __iomem *e_air_threshold;
+ void __iomem *e_mv_hor_range;
+ void __iomem *e_mv_ver_range;
+ void __iomem *e_num_dpb;
+ void __iomem *e_luma_dpb;
+ void __iomem *e_chroma_dpb;
+ void __iomem *e_me_buffer;
+ void __iomem *e_scratch_buffer_addr;
+ void __iomem *e_scratch_buffer_size;
+ void __iomem *e_tmv_buffer0;
+ void __iomem *e_tmv_buffer1;
+ void __iomem *e_ir_buffer_addr;/* v7 and v8 */
+ void __iomem *e_source_first_plane_addr;
+ void __iomem *e_source_second_plane_addr;
+ void __iomem *e_source_third_plane_addr;/* v7 and v8 */
+ void __iomem *e_source_first_plane_stride;/* v7 and v8 */
+ void __iomem *e_source_second_plane_stride;/* v7 and v8 */
+ void __iomem *e_source_third_plane_stride;/* v7 and v8 */
+ void __iomem *e_stream_buffer_addr;
+ void __iomem *e_stream_buffer_size;
+ void __iomem *e_roi_buffer_addr;
+ void __iomem *e_param_change;
+ void __iomem *e_ir_size;
+ void __iomem *e_gop_config;
+ void __iomem *e_mslice_mode;
+ void __iomem *e_mslice_size_mb;
+ void __iomem *e_mslice_size_bits;
+ void __iomem *e_frame_insertion;
+ void __iomem *e_rc_frame_rate;
+ void __iomem *e_rc_bit_rate;
+ void __iomem *e_rc_roi_ctrl;
+ void __iomem *e_picture_tag;
+ void __iomem *e_bit_count_enable;
+ void __iomem *e_max_bit_count;
+ void __iomem *e_min_bit_count;
+ void __iomem *e_metadata_buffer_addr;
+ void __iomem *e_metadata_buffer_size;
+ void __iomem *e_encoded_source_first_plane_addr;
+ void __iomem *e_encoded_source_second_plane_addr;
+ void __iomem *e_encoded_source_third_plane_addr;/* v7 and v8 */
+ void __iomem *e_stream_size;
+ void __iomem *e_slice_type;
+ void __iomem *e_picture_count;
+ void __iomem *e_ret_picture_tag;
+ void __iomem *e_stream_buffer_write_pointer; /* only v6 */
+ void __iomem *e_recon_luma_dpb_addr;
+ void __iomem *e_recon_chroma_dpb_addr;
+ void __iomem *e_metadata_addr_enc_slice;
+ void __iomem *e_metadata_size_enc_slice;
+ void __iomem *e_mpeg4_options;
+ void __iomem *e_mpeg4_hec_period;
+ void __iomem *e_aspect_ratio;
+ void __iomem *e_extended_sar;
+ void __iomem *e_h264_options;
+ void __iomem *e_h264_options_2;/* v7 and v8 */
+ void __iomem *e_h264_lf_alpha_offset;
+ void __iomem *e_h264_lf_beta_offset;
+ void __iomem *e_h264_i_period;
+ void __iomem *e_h264_fmo_slice_grp_map_type;
+ void __iomem *e_h264_fmo_num_slice_grp_minus1;
+ void __iomem *e_h264_fmo_slice_grp_change_dir;
+ void __iomem *e_h264_fmo_slice_grp_change_rate_minus1;
+ void __iomem *e_h264_fmo_run_length_minus1_0;
+ void __iomem *e_h264_aso_slice_order_0;
+ void __iomem *e_h264_chroma_qp_offset;
+ void __iomem *e_h264_num_t_layer;
+ void __iomem *e_h264_hierarchical_qp_layer0;
+ void __iomem *e_h264_frame_packing_sei_info;
+ void __iomem *e_h264_nal_control;/* v7 and v8 */
+ void __iomem *e_mvc_frame_qp_view1;
+ void __iomem *e_mvc_rc_bit_rate_view1;
+ void __iomem *e_mvc_rc_qbound_view1;
+ void __iomem *e_mvc_rc_mode_view1;
+ void __iomem *e_mvc_inter_view_prediction_on;
+ void __iomem *e_vp8_options;/* v7 and v8 */
+ void __iomem *e_vp8_filter_options;/* v7 and v8 */
+ void __iomem *e_vp8_golden_frame_option;/* v7 and v8 */
+ void __iomem *e_vp8_num_t_layer;/* v7 and v8 */
+ void __iomem *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+ void __iomem *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+ void __iomem *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
};
struct s5p_mfc_hw_ops {
@@ -281,28 +281,14 @@ struct s5p_mfc_hw_ops {
void (*release_dev_context_buffer)(struct s5p_mfc_dev *dev);
void (*dec_calc_dpb_size)(struct s5p_mfc_ctx *ctx);
void (*enc_calc_src_size)(struct s5p_mfc_ctx *ctx);
- int (*set_dec_stream_buffer)(struct s5p_mfc_ctx *ctx,
- int buf_addr, unsigned int start_num_byte,
- unsigned int buf_size);
- int (*set_dec_frame_buffer)(struct s5p_mfc_ctx *ctx);
int (*set_enc_stream_buffer)(struct s5p_mfc_ctx *ctx,
unsigned long addr, unsigned int size);
void (*set_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
unsigned long y_addr, unsigned long c_addr);
void (*get_enc_frame_buffer)(struct s5p_mfc_ctx *ctx,
unsigned long *y_addr, unsigned long *c_addr);
- int (*set_enc_ref_buffer)(struct s5p_mfc_ctx *ctx);
- int (*init_decode)(struct s5p_mfc_ctx *ctx);
- int (*init_encode)(struct s5p_mfc_ctx *ctx);
- int (*encode_one_frame)(struct s5p_mfc_ctx *ctx);
void (*try_run)(struct s5p_mfc_dev *dev);
- void (*cleanup_queue)(struct list_head *lh,
- struct vb2_queue *vq);
void (*clear_int_flags)(struct s5p_mfc_dev *dev);
- void (*write_info)(struct s5p_mfc_ctx *ctx, unsigned int data,
- unsigned int ofs);
- unsigned int (*read_info)(struct s5p_mfc_ctx *ctx,
- unsigned long ofs);
int (*get_dspl_y_adr)(struct s5p_mfc_dev *dev);
int (*get_dec_y_adr)(struct s5p_mfc_dev *dev);
int (*get_dspl_status)(struct s5p_mfc_dev *dev);
@@ -313,7 +299,6 @@ struct s5p_mfc_hw_ops {
int (*get_int_reason)(struct s5p_mfc_dev *dev);
int (*get_int_err)(struct s5p_mfc_dev *dev);
int (*err_dec)(unsigned int err);
- int (*err_dspl)(unsigned int err);
int (*get_img_width)(struct s5p_mfc_dev *dev);
int (*get_img_height)(struct s5p_mfc_dev *dev);
int (*get_dpb_count)(struct s5p_mfc_dev *dev);
@@ -322,10 +307,6 @@ struct s5p_mfc_hw_ops {
int (*get_enc_strm_size)(struct s5p_mfc_dev *dev);
int (*get_enc_slice_type)(struct s5p_mfc_dev *dev);
int (*get_enc_dpb_count)(struct s5p_mfc_dev *dev);
- int (*get_enc_pic_count)(struct s5p_mfc_dev *dev);
- int (*get_sei_avail_status)(struct s5p_mfc_ctx *ctx);
- int (*get_mvc_num_views)(struct s5p_mfc_dev *dev);
- int (*get_mvc_view_id)(struct s5p_mfc_dev *dev);
unsigned int (*get_pic_type_top)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_pic_type_bot)(struct s5p_mfc_ctx *ctx);
unsigned int (*get_crop_info_h)(struct s5p_mfc_ctx *ctx);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 873c933..81e1e4c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1153,27 +1153,6 @@ static int s5p_mfc_encode_one_frame_v5(struct s5p_mfc_ctx *ctx)
return 0;
}
-static int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
- unsigned long flags;
- int new_ctx;
- int cnt;
-
- spin_lock_irqsave(&dev->condlock, flags);
- new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
- cnt = 0;
- while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
- new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
- if (++cnt > MFC_NUM_CONTEXTS) {
- /* No contexts to run */
- spin_unlock_irqrestore(&dev->condlock, flags);
- return -EAGAIN;
- }
- }
- spin_unlock_irqrestore(&dev->condlock, flags);
- return new_ctx;
-}
-
static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1187,7 +1166,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *temp_vb;
- unsigned long flags;
if (ctx->state == MFCINST_FINISHING) {
last_frame = MFC_DEC_LAST_FRAME;
@@ -1197,11 +1175,9 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
return 0;
}
- spin_lock_irqsave(&dev->irqlock, flags);
/* Frames are being decoded */
if (list_empty(&ctx->src_queue)) {
mfc_debug(2, "No src buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
/* Get the next source buffer */
@@ -1210,7 +1186,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
s5p_mfc_set_dec_stream_buffer_v5(ctx,
vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
ctx->consumed_stream, temp_vb->b->vb2_buf.planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) {
last_frame = MFC_DEC_LAST_FRAME;
@@ -1224,21 +1199,17 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
unsigned long src_y_addr, src_c_addr, dst_addr;
unsigned int dst_size;
- spin_lock_irqsave(&dev->irqlock, flags);
if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) {
mfc_debug(2, "no src buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
if (list_empty(&ctx->dst_queue)) {
mfc_debug(2, "no dst buffers\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
if (list_empty(&ctx->src_queue)) {
@@ -1270,7 +1241,6 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
mfc_debug(2, "encoding buffer with index=%d state=%d\n",
src_mb ? src_mb->b->vb2_buf.index : -1, ctx->state);
@@ -1281,11 +1251,9 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *temp_vb;
/* Initializing decoding - parsing header */
- spin_lock_irqsave(&dev->irqlock, flags);
mfc_debug(2, "Preparing to init decoding\n");
temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
s5p_mfc_set_dec_desc_buffer(ctx);
@@ -1294,7 +1262,6 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_dec_stream_buffer_v5(ctx,
vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
0, temp_vb->b->vb2_buf.planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
s5p_mfc_init_decode_v5(ctx);
}
@@ -1302,18 +1269,15 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *dst_mb;
unsigned long dst_addr;
unsigned int dst_size;
s5p_mfc_set_enc_ref_buffer_v5(ctx);
- spin_lock_irqsave(&dev->irqlock, flags);
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
s5p_mfc_init_encode_v5(ctx);
}
@@ -1321,7 +1285,6 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *temp_vb;
int ret;
@@ -1335,11 +1298,9 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
"before starting processing\n");
return -EAGAIN;
}
- spin_lock_irqsave(&dev->irqlock, flags);
if (list_empty(&ctx->src_queue)) {
mfc_err("Header has been deallocated in the middle of"
" initialization\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EIO;
}
temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
@@ -1348,7 +1309,6 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_dec_stream_buffer_v5(ctx,
vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
0, temp_vb->b->vb2_buf.planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
ret = s5p_mfc_set_dec_frame_buffer_v5(ctx);
if (ret) {
@@ -1472,21 +1432,6 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
}
}
-
-static void s5p_mfc_cleanup_queue_v5(struct list_head *lh, struct vb2_queue *vq)
-{
- struct s5p_mfc_buf *b;
- int i;
-
- while (!list_empty(lh)) {
- b = list_entry(lh->next, struct s5p_mfc_buf, list);
- for (i = 0; i < b->b->vb2_buf.num_planes; i++)
- vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
- vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&b->list);
- }
-}
-
static void s5p_mfc_clear_int_flags_v5(struct s5p_mfc_dev *dev)
{
mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
@@ -1590,11 +1535,6 @@ static int s5p_mfc_err_dec_v5(unsigned int err)
return (err & S5P_FIMV_ERR_DEC_MASK) >> S5P_FIMV_ERR_DEC_SHIFT;
}
-static int s5p_mfc_err_dspl_v5(unsigned int err)
-{
- return (err & S5P_FIMV_ERR_DSPL_MASK) >> S5P_FIMV_ERR_DSPL_SHIFT;
-}
-
static int s5p_mfc_get_img_width_v5(struct s5p_mfc_dev *dev)
{
return mfc_read(dev, S5P_FIMV_SI_HRESOL);
@@ -1636,26 +1576,6 @@ static int s5p_mfc_get_enc_dpb_count_v5(struct s5p_mfc_dev *dev)
return -1;
}
-static int s5p_mfc_get_enc_pic_count_v5(struct s5p_mfc_dev *dev)
-{
- return mfc_read(dev, S5P_FIMV_ENC_SI_PIC_CNT);
-}
-
-static int s5p_mfc_get_sei_avail_status_v5(struct s5p_mfc_ctx *ctx)
-{
- return s5p_mfc_read_info_v5(ctx, FRAME_PACK_SEI_AVAIL);
-}
-
-static int s5p_mfc_get_mvc_num_views_v5(struct s5p_mfc_dev *dev)
-{
- return -1;
-}
-
-static int s5p_mfc_get_mvc_view_id_v5(struct s5p_mfc_dev *dev)
-{
- return -1;
-}
-
static unsigned int s5p_mfc_get_pic_type_top_v5(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v5(ctx, PIC_TIME_TOP);
@@ -1688,20 +1608,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
.release_dev_context_buffer = s5p_mfc_release_dev_context_buffer_v5,
.dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v5,
.enc_calc_src_size = s5p_mfc_enc_calc_src_size_v5,
- .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v5,
- .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v5,
.set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v5,
.set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v5,
.get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v5,
- .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v5,
- .init_decode = s5p_mfc_init_decode_v5,
- .init_encode = s5p_mfc_init_encode_v5,
- .encode_one_frame = s5p_mfc_encode_one_frame_v5,
.try_run = s5p_mfc_try_run_v5,
- .cleanup_queue = s5p_mfc_cleanup_queue_v5,
.clear_int_flags = s5p_mfc_clear_int_flags_v5,
- .write_info = s5p_mfc_write_info_v5,
- .read_info = s5p_mfc_read_info_v5,
.get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v5,
.get_dec_y_adr = s5p_mfc_get_dec_y_adr_v5,
.get_dspl_status = s5p_mfc_get_dspl_status_v5,
@@ -1712,7 +1623,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
.get_int_reason = s5p_mfc_get_int_reason_v5,
.get_int_err = s5p_mfc_get_int_err_v5,
.err_dec = s5p_mfc_err_dec_v5,
- .err_dspl = s5p_mfc_err_dspl_v5,
.get_img_width = s5p_mfc_get_img_width_v5,
.get_img_height = s5p_mfc_get_img_height_v5,
.get_dpb_count = s5p_mfc_get_dpb_count_v5,
@@ -1721,10 +1631,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = {
.get_enc_strm_size = s5p_mfc_get_enc_strm_size_v5,
.get_enc_slice_type = s5p_mfc_get_enc_slice_type_v5,
.get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v5,
- .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v5,
- .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v5,
- .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v5,
- .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v5,
.get_pic_type_top = s5p_mfc_get_pic_type_top_v5,
.get_pic_type_bot = s5p_mfc_get_pic_type_bot_v5,
.get_crop_info_h = s5p_mfc_get_crop_info_h_v5,
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 b958453..d6f207e 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -505,7 +505,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
}
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_INIT_BUFS_V6, NULL);
mfc_debug(2, "After setting buffers.\n");
@@ -603,7 +603,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
}
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_INIT_BUFS_V6, NULL);
mfc_debug_leave();
@@ -1378,7 +1378,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
writel(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
mfc_debug_leave();
@@ -1393,7 +1393,7 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
if (flush) {
dev->curr_ctx = ctx->num;
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
}
}
@@ -1413,11 +1413,11 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
* is the last frame or not. */
switch (last_frame) {
case 0:
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_FRAME_START_V6, NULL);
break;
case 1:
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_LAST_FRAME_V6, NULL);
break;
default:
@@ -1455,7 +1455,7 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
}
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
return 0;
@@ -1500,37 +1500,13 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
cmd = S5P_FIMV_CH_LAST_FRAME_V6;
writel(ctx->inst_no, mfc_regs->instance_id);
- s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL);
+ s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev, cmd, NULL);
mfc_debug(2, "--\n");
return 0;
}
-static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
-{
- unsigned long flags;
- int new_ctx;
- int cnt;
-
- spin_lock_irqsave(&dev->condlock, flags);
- mfc_debug(2, "Previous context: %d (bits %08lx)\n", dev->curr_ctx,
- dev->ctx_work_bits);
- new_ctx = (dev->curr_ctx + 1) % MFC_NUM_CONTEXTS;
- cnt = 0;
- while (!test_bit(new_ctx, &dev->ctx_work_bits)) {
- new_ctx = (new_ctx + 1) % MFC_NUM_CONTEXTS;
- cnt++;
- if (cnt > MFC_NUM_CONTEXTS) {
- /* No contexts to run */
- spin_unlock_irqrestore(&dev->condlock, flags);
- return -EAGAIN;
- }
- }
- spin_unlock_irqrestore(&dev->condlock, flags);
- return new_ctx;
-}
-
static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
@@ -1544,7 +1520,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
struct s5p_mfc_buf *temp_vb;
- unsigned long flags;
int last_frame = 0;
if (ctx->state == MFCINST_FINISHING) {
@@ -1556,11 +1531,9 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
return 0;
}
- spin_lock_irqsave(&dev->irqlock, flags);
/* Frames are being decoded */
if (list_empty(&ctx->src_queue)) {
mfc_debug(2, "No src buffers.\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
/* Get the next source buffer */
@@ -1570,7 +1543,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0),
ctx->consumed_stream,
temp_vb->b->vb2_buf.planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
if (temp_vb->b->vb2_buf.planes[0].bytesused == 0) {
@@ -1586,7 +1558,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *dst_mb;
struct s5p_mfc_buf *src_mb;
unsigned long src_y_addr, src_c_addr, dst_addr;
@@ -1595,17 +1566,13 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
*/
unsigned int dst_size;
- spin_lock_irqsave(&dev->irqlock, flags);
-
if (list_empty(&ctx->src_queue) && ctx->state != MFCINST_FINISHING) {
mfc_debug(2, "no src buffers.\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
if (list_empty(&ctx->dst_queue)) {
mfc_debug(2, "no dst buffers.\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
return -EAGAIN;
}
@@ -1639,8 +1606,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
-
dev->curr_ctx = ctx->num;
s5p_mfc_encode_one_frame_v6(ctx);
@@ -1650,18 +1615,15 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *temp_vb;
/* Initializing decoding - parsing header */
- spin_lock_irqsave(&dev->irqlock, flags);
mfc_debug(2, "Preparing to init decoding.\n");
temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
mfc_debug(2, "Header size: %d\n", temp_vb->b->vb2_buf.planes[0].bytesused);
s5p_mfc_set_dec_stream_buffer_v6(ctx,
vb2_dma_contig_plane_dma_addr(&temp_vb->b->vb2_buf, 0), 0,
temp_vb->b->vb2_buf.planes[0].bytesused);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
s5p_mfc_init_decode_v6(ctx);
}
@@ -1669,18 +1631,14 @@ static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- unsigned long flags;
struct s5p_mfc_buf *dst_mb;
unsigned long dst_addr;
unsigned int dst_size;
- spin_lock_irqsave(&dev->irqlock, flags);
-
dst_mb = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf, list);
dst_addr = vb2_dma_contig_plane_dma_addr(&dst_mb->b->vb2_buf, 0);
dst_size = vb2_plane_size(&dst_mb->b->vb2_buf, 0);
s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size);
- spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
s5p_mfc_init_encode_v6(ctx);
}
@@ -1846,21 +1804,6 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
}
}
-
-static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
-{
- struct s5p_mfc_buf *b;
- int i;
-
- while (!list_empty(lh)) {
- b = list_entry(lh->next, struct s5p_mfc_buf, list);
- for (i = 0; i < b->b->vb2_buf.num_planes; i++)
- vb2_set_plane_payload(&b->b->vb2_buf, i, 0);
- vb2_buffer_done(&b->b->vb2_buf, VB2_BUF_STATE_ERROR);
- list_del(&b->list);
- }
-}
-
static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
{
const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
@@ -1868,14 +1811,6 @@ static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
writel(0, mfc_regs->risc2host_int);
}
-static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
- unsigned int ofs)
-{
- s5p_mfc_clock_on();
- writel(data, (void __iomem *)((unsigned long)ofs));
- s5p_mfc_clock_off();
-}
-
static unsigned int
s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs)
{
@@ -1942,11 +1877,6 @@ static int s5p_mfc_err_dec_v6(unsigned int err)
return (err & S5P_FIMV_ERR_DEC_MASK_V6) >> S5P_FIMV_ERR_DEC_SHIFT_V6;
}
-static int s5p_mfc_err_dspl_v6(unsigned int err)
-{
- return (err & S5P_FIMV_ERR_DSPL_MASK_V6) >> S5P_FIMV_ERR_DSPL_SHIFT_V6;
-}
-
static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
{
return readl(dev->mfc_regs->d_display_frame_width);
@@ -1987,27 +1917,6 @@ static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
return readl(dev->mfc_regs->e_slice_type);
}
-static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
-{
- return readl(dev->mfc_regs->e_picture_count);
-}
-
-static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
-{
- struct s5p_mfc_dev *dev = ctx->dev;
- return readl(dev->mfc_regs->d_frame_pack_sei_avail);
-}
-
-static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
-{
- return readl(dev->mfc_regs->d_mvc_num_views);
-}
-
-static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
-{
- return readl(dev->mfc_regs->d_mvc_view_id);
-}
-
static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
{
return s5p_mfc_read_info_v6(ctx,
@@ -2282,20 +2191,11 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
s5p_mfc_release_dev_context_buffer_v6,
.dec_calc_dpb_size = s5p_mfc_dec_calc_dpb_size_v6,
.enc_calc_src_size = s5p_mfc_enc_calc_src_size_v6,
- .set_dec_stream_buffer = s5p_mfc_set_dec_stream_buffer_v6,
- .set_dec_frame_buffer = s5p_mfc_set_dec_frame_buffer_v6,
.set_enc_stream_buffer = s5p_mfc_set_enc_stream_buffer_v6,
.set_enc_frame_buffer = s5p_mfc_set_enc_frame_buffer_v6,
.get_enc_frame_buffer = s5p_mfc_get_enc_frame_buffer_v6,
- .set_enc_ref_buffer = s5p_mfc_set_enc_ref_buffer_v6,
- .init_decode = s5p_mfc_init_decode_v6,
- .init_encode = s5p_mfc_init_encode_v6,
- .encode_one_frame = s5p_mfc_encode_one_frame_v6,
.try_run = s5p_mfc_try_run_v6,
- .cleanup_queue = s5p_mfc_cleanup_queue_v6,
.clear_int_flags = s5p_mfc_clear_int_flags_v6,
- .write_info = s5p_mfc_write_info_v6,
- .read_info = s5p_mfc_read_info_v6,
.get_dspl_y_adr = s5p_mfc_get_dspl_y_adr_v6,
.get_dec_y_adr = s5p_mfc_get_dec_y_adr_v6,
.get_dspl_status = s5p_mfc_get_dspl_status_v6,
@@ -2306,7 +2206,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
.get_int_reason = s5p_mfc_get_int_reason_v6,
.get_int_err = s5p_mfc_get_int_err_v6,
.err_dec = s5p_mfc_err_dec_v6,
- .err_dspl = s5p_mfc_err_dspl_v6,
.get_img_width = s5p_mfc_get_img_width_v6,
.get_img_height = s5p_mfc_get_img_height_v6,
.get_dpb_count = s5p_mfc_get_dpb_count_v6,
@@ -2315,10 +2214,6 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = {
.get_enc_strm_size = s5p_mfc_get_enc_strm_size_v6,
.get_enc_slice_type = s5p_mfc_get_enc_slice_type_v6,
.get_enc_dpb_count = s5p_mfc_get_enc_dpb_count_v6,
- .get_enc_pic_count = s5p_mfc_get_enc_pic_count_v6,
- .get_sei_avail_status = s5p_mfc_get_sei_avail_status_v6,
- .get_mvc_num_views = s5p_mfc_get_mvc_num_views_v6,
- .get_mvc_view_id = s5p_mfc_get_mvc_view_id_v6,
.get_pic_type_top = s5p_mfc_get_pic_type_top_v6,
.get_pic_type_bot = s5p_mfc_get_pic_type_bot_v6,
.get_crop_info_h = s5p_mfc_get_crop_info_h_v6,
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 7994075..e71b13e 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -33,7 +33,7 @@
#include <linux/regulator/consumer.h>
#include <linux/v4l2-dv-timings.h>
-#include <media/s5p_hdmi.h>
+#include <linux/platform_data/media/s5p_hdmi.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
@@ -627,7 +627,7 @@ static int hdmi_s_dv_timings(struct v4l2_subdev *sd,
for (i = 0; i < ARRAY_SIZE(hdmi_timings); i++)
if (v4l2_match_dv_timings(&hdmi_timings[i].dv_timings,
- timings, 0))
+ timings, 0, false))
break;
if (i == ARRAY_SIZE(hdmi_timings)) {
dev_err(dev, "timings not supported\n");
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index dc1c679..d9e7f03 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -881,7 +881,7 @@ static const struct v4l2_file_operations mxr_fops = {
.unlocked_ioctl = video_ioctl2,
};
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes, unsigned int sizes[],
void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/s5p-tv/sii9234_drv.c b/drivers/media/platform/s5p-tv/sii9234_drv.c
index 8d17131..0a97f9a 100644
--- a/drivers/media/platform/s5p-tv/sii9234_drv.c
+++ b/drivers/media/platform/s5p-tv/sii9234_drv.c
@@ -23,7 +23,7 @@
#include <linux/regulator/machine.h>
#include <linux/slab.h>
-#include <media/sii9234.h>
+#include <linux/platform_data/media/sii9234.h>
#include <media/v4l2-subdev.h>
MODULE_AUTHOR("Tomasz Stanislawski <t.stanislaws@samsung.com>");
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index d6ab33e..82b5d69 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -865,32 +865,14 @@ static const struct v4l2_ioctl_ops sh_veu_ioctl_ops = {
/* ========== Queue operations ========== */
static int sh_veu_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *f = parg;
struct sh_veu_dev *veu = vb2_get_drv_priv(vq);
- struct sh_veu_vfmt *vfmt;
- unsigned int size, count = *nbuffers;
-
- if (f) {
- const struct v4l2_pix_format *pix = &f->fmt.pix;
- const struct sh_veu_format *fmt = sh_veu_find_fmt(f);
- struct v4l2_format ftmp = *f;
-
- if (fmt->fourcc != pix->pixelformat)
- return -EINVAL;
- sh_veu_try_fmt(&ftmp, fmt);
- if (ftmp.fmt.pix.width != pix->width ||
- ftmp.fmt.pix.height != pix->height)
- return -EINVAL;
- size = pix->bytesperline ? pix->bytesperline * pix->height * fmt->depth / fmt->ydepth :
- pix->width * pix->height * fmt->depth / fmt->ydepth;
- } else {
- vfmt = sh_veu_get_vfmt(veu, vq->type);
- size = vfmt->bytesperline * vfmt->frame.height * vfmt->fmt->depth / vfmt->fmt->ydepth;
- }
+ struct sh_veu_vfmt *vfmt = sh_veu_get_vfmt(veu, vq->type);
+ unsigned int count = *nbuffers;
+ unsigned int size = vfmt->bytesperline * vfmt->frame.height *
+ vfmt->fmt->depth / vfmt->fmt->ydepth;
if (count < 2)
*nbuffers = count = 2;
@@ -900,6 +882,11 @@ static int sh_veu_queue_setup(struct vb2_queue *vq,
*nbuffers = count;
}
+ if (*nplanes) {
+ alloc_ctxs[0] = veu->alloc_ctx;
+ return sizes[0] < size ? -EINVAL : 0;
+ }
+
*nplanes = 1;
sizes[0] = size;
alloc_ctxs[0] = veu->alloc_ctx;
@@ -1107,7 +1094,7 @@ static irqreturn_t sh_veu_isr(int irq, void *dev_id)
if (!src || !dst)
return IRQ_NONE;
- dst->timestamp = src->timestamp;
+ dst->vb2_buf.timestamp = src->vb2_buf.timestamp;
dst->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst->flags |=
src->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index 2231f89..1157404 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -22,7 +22,7 @@
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <media/sh_vou.h>
+#include <media/drv-intf/sh_vou.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
@@ -243,22 +243,21 @@ static void sh_vou_stream_config(struct sh_vou_device *vou_dev)
}
/* Locking: caller holds fop_lock mutex */
-static int sh_vou_queue_setup(struct vb2_queue *vq, const void *parg,
+static int sh_vou_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq);
struct v4l2_pix_format *pix = &vou_dev->pix;
int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8;
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
- if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line)
- return -EINVAL;
- *nplanes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line;
alloc_ctxs[0] = vou_dev->alloc_ctx;
+ if (*nplanes)
+ return sizes[0] < pix->height * bytes_per_line ? -EINVAL : 0;
+ *nplanes = 1;
+ sizes[0] = pix->height * bytes_per_line;
return 0;
}
@@ -1071,7 +1070,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id)
list_del(&vb->list);
- v4l2_get_timestamp(&vb->vb.timestamp);
+ vb->vb.vb2_buf.timestamp = ktime_get_ns();
vb->vb.sequence = vou_dev->sequence++;
vb->vb.field = V4L2_FIELD_INTERLACED;
vb2_buffer_done(&vb->vb.vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 454f68f..c398b28 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-of.h>
#include <media/videobuf2-dma-contig.h>
@@ -79,6 +79,7 @@ struct atmel_isi {
dma_addr_t fb_descriptors_phys;
struct list_head dma_desc_head;
struct isi_dma_desc dma_desc[MAX_BUFFER_NUM];
+ bool enable_preview_path;
struct completion complete;
/* ISI peripherial clock */
@@ -103,13 +104,55 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg)
return readl(isi->regs + reg);
}
+static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi,
+ const struct soc_camera_format_xlate *xlate)
+{
+ if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) {
+ /* all convert to YUYV */
+ switch (xlate->code) {
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_3;
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_2;
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_1;
+ }
+ } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) {
+ /*
+ * Preview path is enabled, it will convert UYVY to RGB format.
+ * But if sensor output format is not UYVY, we need to set
+ * YCC_SWAP_MODE to convert it as UYVY.
+ */
+ switch (xlate->code) {
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_1;
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_2;
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ return ISI_CFG2_YCC_SWAP_MODE_3;
+ }
+ }
+
+ /*
+ * By default, no swap for the codec path of Atmel ISI. So codec
+ * output is same as sensor's output.
+ * For instance, if sensor's output is YUYV, then codec outputs YUYV.
+ * And if sensor's output is UYVY, then codec outputs UYVY.
+ */
+ return ISI_CFG2_YCC_SWAP_DEFAULT;
+}
+
static void configure_geometry(struct atmel_isi *isi, u32 width,
- u32 height, u32 code)
+ u32 height, const struct soc_camera_format_xlate *xlate)
{
- u32 cfg2;
+ u32 cfg2, psize;
+ u32 fourcc = xlate->host_fmt->fourcc;
+
+ isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 ||
+ fourcc == V4L2_PIX_FMT_RGB32;
/* According to sensor's output format to set cfg2 */
- switch (code) {
+ switch (xlate->code) {
default:
/* Grey */
case MEDIA_BUS_FMT_Y8_1X8:
@@ -117,16 +160,11 @@ static void configure_geometry(struct atmel_isi *isi, u32 width,
break;
/* YUV */
case MEDIA_BUS_FMT_VYUY8_2X8:
- cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr;
- break;
case MEDIA_BUS_FMT_UYVY8_2X8:
- cfg2 = ISI_CFG2_YCC_SWAP_MODE_2 | ISI_CFG2_COL_SPACE_YCbCr;
- break;
case MEDIA_BUS_FMT_YVYU8_2X8:
- cfg2 = ISI_CFG2_YCC_SWAP_MODE_1 | ISI_CFG2_COL_SPACE_YCbCr;
- break;
case MEDIA_BUS_FMT_YUYV8_2X8:
- cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr;
+ cfg2 = ISI_CFG2_COL_SPACE_YCbCr |
+ setup_cfg2_yuv_swap(isi, xlate);
break;
/* RGB, TODO */
}
@@ -139,6 +177,16 @@ static void configure_geometry(struct atmel_isi *isi, u32 width,
cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
& ISI_CFG2_IM_VSIZE_MASK;
isi_writel(isi, ISI_CFG2, cfg2);
+
+ /* No down sampling, preview size equal to sensor output size */
+ psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) &
+ ISI_PSIZE_PREV_HSIZE_MASK;
+ psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) &
+ ISI_PSIZE_PREV_VSIZE_MASK;
+ isi_writel(isi, ISI_PSIZE, psize);
+ isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING);
+
+ return;
}
static bool is_supported(struct soc_camera_device *icd,
@@ -151,8 +199,9 @@ static bool is_supported(struct soc_camera_device *icd,
case V4L2_PIX_FMT_UYVY:
case V4L2_PIX_FMT_YVYU:
case V4L2_PIX_FMT_VYUY:
+ /* RGB */
+ case V4L2_PIX_FMT_RGB565:
return true;
- /* RGB, TODO */
default:
return false;
}
@@ -165,7 +214,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
struct frame_buffer *buf = isi->active;
list_del_init(&buf->list);
- v4l2_get_timestamp(&vbuf->timestamp);
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
vbuf->sequence = isi->sequence++;
vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -176,11 +225,19 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
/* start next dma frame. */
isi->active = list_entry(isi->video_buffer_list.next,
struct frame_buffer, list);
- isi_writel(isi, ISI_DMA_C_DSCR,
- (u32)isi->active->p_dma_desc->fbd_phys);
- isi_writel(isi, ISI_DMA_C_CTRL,
- ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
- isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+ if (!isi->enable_preview_path) {
+ isi_writel(isi, ISI_DMA_C_DSCR,
+ (u32)isi->active->p_dma_desc->fbd_phys);
+ isi_writel(isi, ISI_DMA_C_CTRL,
+ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+ } else {
+ isi_writel(isi, ISI_DMA_P_DSCR,
+ (u32)isi->active->p_dma_desc->fbd_phys);
+ isi_writel(isi, ISI_DMA_P_CTRL,
+ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
+ }
}
return IRQ_HANDLED;
}
@@ -207,7 +264,8 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id)
isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
ret = IRQ_HANDLED;
} else {
- if (likely(pending & ISI_SR_CXFR_DONE))
+ if (likely(pending & ISI_SR_CXFR_DONE) ||
+ likely(pending & ISI_SR_PXFR_DONE))
ret = atmel_isi_handle_streaming(isi);
}
@@ -245,7 +303,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -352,21 +410,35 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
/* Check if already in a frame */
- if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
- dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
- return;
- }
+ if (!isi->enable_preview_path) {
+ if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
+ dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
+ return;
+ }
- isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys);
- isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
- isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+ isi_writel(isi, ISI_DMA_C_DSCR,
+ (u32)buffer->p_dma_desc->fbd_phys);
+ isi_writel(isi, ISI_DMA_C_CTRL,
+ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
+ } else {
+ isi_writel(isi, ISI_DMA_P_DSCR,
+ (u32)buffer->p_dma_desc->fbd_phys);
+ isi_writel(isi, ISI_DMA_P_CTRL,
+ ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
+ isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
+ }
cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;
/* Enable linked list */
cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR;
- /* Enable codec path and ISI */
- ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
+ /* Enable ISI */
+ ctrl = ISI_CTRL_EN;
+
+ if (!isi->enable_preview_path)
+ ctrl |= ISI_CTRL_CDC;
+
isi_writel(isi, ISI_CTRL, ctrl);
isi_writel(isi, ISI_CFG1, cfg1);
}
@@ -411,7 +483,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
isi_writel(isi, ISI_INTDIS, (u32)~0UL);
configure_geometry(isi, icd->user_width, icd->user_height,
- icd->current_fmt->code);
+ icd->current_fmt);
spin_lock_irq(&isi->lock);
/* Clear any pending interrupt */
@@ -443,15 +515,17 @@ static void stop_streaming(struct vb2_queue *vq)
}
spin_unlock_irq(&isi->lock);
- timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
- /* Wait until the end of the current frame. */
- while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
- time_before(jiffies, timeout))
- msleep(1);
+ if (!isi->enable_preview_path) {
+ timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
+ /* Wait until the end of the current frame. */
+ while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
+ time_before(jiffies, timeout))
+ msleep(1);
- if (time_after(jiffies, timeout))
- dev_err(icd->parent,
- "Timeout waiting for finishing codec request\n");
+ if (time_after(jiffies, timeout))
+ dev_err(icd->parent,
+ "Timeout waiting for finishing codec request\n");
+ }
/* Disable interrupts */
isi_writel(isi, ISI_INTDIS,
@@ -617,6 +691,14 @@ static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
.order = SOC_MBUS_ORDER_LE,
.layout = SOC_MBUS_LAYOUT_PACKED,
},
+ {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .name = "RGB565",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_LE,
+ .layout = SOC_MBUS_LAYOUT_PACKED,
+ },
};
/* This will be corrected as we get more formats */
@@ -673,7 +755,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- int formats = 0, ret;
+ int formats = 0, ret, i, n;
/* sensor format */
struct v4l2_subdev_mbus_code_enum code = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -707,11 +789,11 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
case MEDIA_BUS_FMT_VYUY8_2X8:
case MEDIA_BUS_FMT_YUYV8_2X8:
case MEDIA_BUS_FMT_YVYU8_2X8:
- formats++;
- if (xlate) {
- xlate->host_fmt = &isi_camera_formats[0];
+ n = ARRAY_SIZE(isi_camera_formats);
+ formats += n;
+ for (i = 0; xlate && i < n; i++, xlate++) {
+ xlate->host_fmt = &isi_camera_formats[i];
xlate->code = code.code;
- xlate++;
dev_dbg(icd->parent, "Providing format %s using code %d\n",
isi_camera_formats[0].name, code.code);
}
diff --git a/drivers/media/platform/soc_camera/atmel-isi.h b/drivers/media/platform/soc_camera/atmel-isi.h
index 5acc771..0acb32a 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.h
+++ b/drivers/media/platform/soc_camera/atmel-isi.h
@@ -79,6 +79,16 @@
#define ISI_CFG2_IM_VSIZE_MASK (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
#define ISI_CFG2_IM_HSIZE_MASK (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET)
+/* Bitfields in PSIZE */
+#define ISI_PSIZE_PREV_VSIZE_OFFSET 0
+#define ISI_PSIZE_PREV_HSIZE_OFFSET 16
+#define ISI_PSIZE_PREV_VSIZE_MASK (0x3FF << ISI_PSIZE_PREV_VSIZE_OFFSET)
+#define ISI_PSIZE_PREV_HSIZE_MASK (0x3FF << ISI_PSIZE_PREV_HSIZE_OFFSET)
+
+/* Bitfields in PDECF */
+#define ISI_PDECF_DEC_FACTOR_MASK (0xFF << 0)
+#define ISI_PDECF_NO_SAMPLING (16)
+
/* Bitfields in CTRL */
/* Also using in SR(ISI_V2) */
#define ISI_CTRL_EN (1 << 0)
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 1f28d21..48dd5b7 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -35,11 +35,11 @@
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-dma-contig.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <linux/videodev2.h>
-#include <linux/platform_data/camera-mx2.h>
+#include <linux/platform_data/media/camera-mx2.h>
#include <asm/dma.h>
@@ -469,21 +469,15 @@ static void mx2_camera_clock_stop(struct soc_camera_host *ici)
* Videobuf operations
*/
static int mx2_videobuf_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx2_camera_dev *pcdev = ici->priv;
dev_dbg(icd->parent, "count=%d, size=%d\n", *count, sizes[0]);
- /* TODO: support for VIDIOC_CREATE_BUFS not ready */
- if (fmt != NULL)
- return -ENOTTY;
-
alloc_ctxs[0] = pcdev->alloc_ctx;
sizes[0] = icd->sizeimage;
@@ -1351,7 +1345,7 @@ static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
vb2_get_plane_payload(vb, 0));
list_del_init(&buf->internal.queue);
- v4l2_get_timestamp(&vbuf->timestamp);
+ vb->timestamp = ktime_get_ns();
vbuf->sequence = pcdev->frame_count;
if (err)
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 49c3a25..169ed11 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -23,9 +23,9 @@
#include <media/v4l2-dev.h>
#include <media/videobuf2-dma-contig.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
-#include <linux/platform_data/camera-mx3.h>
+#include <linux/platform_data/media/camera-mx3.h>
#include <linux/platform_data/dma-imx.h>
#define MX3_CAM_DRV_NAME "mx3-camera"
@@ -155,7 +155,7 @@ static void mx3_cam_dma_done(void *arg)
struct mx3_camera_buffer *buf = to_mx3_vb(vb);
list_del_init(&buf->queue);
- v4l2_get_timestamp(&vb->timestamp);
+ vb->vb2_buf.timestamp = ktime_get_ns();
vb->field = mx3_cam->field;
vb->sequence = mx3_cam->sequence++;
vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE);
@@ -185,11 +185,9 @@ static void mx3_cam_dma_done(void *arg)
* Calculate the __buffer__ (not data) size and number of buffers.
*/
static int mx3_videobuf_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct mx3_camera_dev *mx3_cam = ici->priv;
@@ -197,33 +195,6 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
if (!mx3_cam->idmac_channel[0])
return -EINVAL;
- if (fmt) {
- const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
- fmt->fmt.pix.pixelformat);
- unsigned int bytes_per_line;
- int ret;
-
- if (!xlate)
- return -EINVAL;
-
- ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- if (ret < 0)
- return ret;
-
- bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
- ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
- fmt->fmt.pix.height);
- if (ret < 0)
- return ret;
-
- sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
- } else {
- /* Called from VIDIOC_REQBUFS or in compatibility mode */
- sizes[0] = icd->sizeimage;
- }
-
alloc_ctxs[0] = mx3_cam->alloc_ctx;
if (!vq->num_buffers)
@@ -232,9 +203,14 @@ static int mx3_videobuf_setup(struct vb2_queue *vq,
if (!*count)
*count = 2;
+ /* Called from VIDIOC_REQBUFS or in compatibility mode */
+ if (!*num_planes)
+ sizes[0] = icd->sizeimage;
+ else if (sizes[0] < icd->sizeimage)
+ return -EINVAL;
+
/* If *num_planes != 0, we have already verified *count. */
- if (!*num_planes &&
- sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
+ if (sizes[0] * *count + mx3_cam->buf_total > MAX_VIDEO_MEM * 1024 * 1024)
*count = (MAX_VIDEO_MEM * 1024 * 1024 - mx3_cam->buf_total) /
sizes[0];
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index ba8dcd1..bd721e3 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -28,9 +28,9 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <media/omap1_camera.h>
+#include <linux/platform_data/media/omap1_camera.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/videobuf-dma-contig.h>
#include <media/videobuf-dma-sg.h>
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index fcb942d..415f3bd 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -33,13 +33,13 @@
#include <media/v4l2-dev.h>
#include <media/videobuf-dma-sg.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-of.h>
#include <linux/videodev2.h>
#include <mach/dma.h>
-#include <linux/platform_data/camera-pxa.h>
+#include <linux/platform_data/media/camera-pxa.h>
#define PXA_CAM_VERSION "0.0.6"
#define PXA_CAM_DRV_NAME "pxa27x-camera"
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index efe57b2..b7fd695 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -21,14 +21,13 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
-#include <linux/platform_data/camera-rcar.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
@@ -138,6 +137,11 @@
#define TIMEOUT_MS 100
+#define RCAR_VIN_HSYNC_ACTIVE_LOW (1 << 0)
+#define RCAR_VIN_VSYNC_ACTIVE_LOW (1 << 1)
+#define RCAR_VIN_BT601 (1 << 2)
+#define RCAR_VIN_BT656 (1 << 3)
+
enum chip_id {
RCAR_GEN2,
RCAR_H1,
@@ -527,46 +531,14 @@ struct rcar_vin_cam {
* required
*/
static int rcar_vin_videobuf_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *count,
unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct rcar_vin_priv *priv = ici->priv;
- if (fmt) {
- const struct soc_camera_format_xlate *xlate;
- unsigned int bytes_per_line;
- int ret;
-
- if (fmt->fmt.pix.sizeimage < icd->sizeimage)
- return -EINVAL;
-
- xlate = soc_camera_xlate_by_fourcc(icd,
- fmt->fmt.pix.pixelformat);
- if (!xlate)
- return -EINVAL;
- ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- if (ret < 0)
- return ret;
-
- bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
- ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
- fmt->fmt.pix.height);
- if (ret < 0)
- return ret;
-
- sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
- } else {
- /* Called from VIDIOC_REQBUFS or in compatibility mode */
- sizes[0] = icd->sizeimage;
- }
-
alloc_ctxs[0] = priv->alloc_ctx;
if (!vq->num_buffers)
@@ -576,14 +548,18 @@ static int rcar_vin_videobuf_setup(struct vb2_queue *vq,
*count = 2;
priv->vb_count = *count;
- *num_planes = 1;
-
/* Number of hardware slots */
if (is_continuous_transfer(priv))
priv->nr_hw_slots = MAX_BUFFER_NUM;
else
priv->nr_hw_slots = 1;
+ if (*num_planes)
+ return sizes[0] < icd->sizeimage ? -EINVAL : 0;
+
+ sizes[0] = icd->sizeimage;
+ *num_planes = 1;
+
dev_dbg(icd->parent, "count=%d, size=%u\n", *count, sizes[0]);
return 0;
@@ -912,7 +888,7 @@ static irqreturn_t rcar_vin_irq(int irq, void *data)
priv->queue_buf[slot]->field = priv->field;
priv->queue_buf[slot]->sequence = priv->sequence++;
- v4l2_get_timestamp(&priv->queue_buf[slot]->timestamp);
+ priv->queue_buf[slot]->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&priv->queue_buf[slot]->vb2_buf,
VB2_BUF_STATE_DONE);
priv->queue_buf[slot] = NULL;
@@ -1853,63 +1829,43 @@ static const struct of_device_id rcar_vin_of_table[] = {
MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
#endif
-static struct platform_device_id rcar_vin_id_table[] = {
- { "r8a7779-vin", RCAR_H1 },
- { "r8a7778-vin", RCAR_M1 },
- { "uPD35004-vin", RCAR_E1 },
- {},
-};
-MODULE_DEVICE_TABLE(platform, rcar_vin_id_table);
-
static int rcar_vin_probe(struct platform_device *pdev)
{
const struct of_device_id *match = NULL;
struct rcar_vin_priv *priv;
+ struct v4l2_of_endpoint ep;
+ struct device_node *np;
struct resource *mem;
- struct rcar_vin_platform_data *pdata;
unsigned int pdata_flags;
int irq, ret;
- if (pdev->dev.of_node) {
- struct v4l2_of_endpoint ep;
- struct device_node *np;
+ match = of_match_device(of_match_ptr(rcar_vin_of_table), &pdev->dev);
- match = of_match_device(of_match_ptr(rcar_vin_of_table),
- &pdev->dev);
-
- np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
- if (!np) {
- dev_err(&pdev->dev, "could not find endpoint\n");
- return -EINVAL;
- }
+ np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
+ if (!np) {
+ dev_err(&pdev->dev, "could not find endpoint\n");
+ return -EINVAL;
+ }
- ret = v4l2_of_parse_endpoint(np, &ep);
- if (ret) {
- dev_err(&pdev->dev, "could not parse endpoint\n");
- return ret;
- }
+ ret = v4l2_of_parse_endpoint(np, &ep);
+ if (ret) {
+ dev_err(&pdev->dev, "could not parse endpoint\n");
+ return ret;
+ }
- if (ep.bus_type == V4L2_MBUS_BT656)
- pdata_flags = RCAR_VIN_BT656;
- else {
- pdata_flags = 0;
- if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
- pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW;
- if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW;
- }
+ if (ep.bus_type == V4L2_MBUS_BT656)
+ pdata_flags = RCAR_VIN_BT656;
+ else {
+ pdata_flags = 0;
+ if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW;
+ if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW;
+ }
- of_node_put(np);
+ of_node_put(np);
- dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags);
- } else {
- pdata = pdev->dev.platform_data;
- if (!pdata || !pdata->flags) {
- dev_err(&pdev->dev, "platform data not set\n");
- return -EINVAL;
- }
- pdata_flags = pdata->flags;
- }
+ dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags);
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (mem == NULL)
@@ -1992,7 +1948,6 @@ static struct platform_driver rcar_vin_driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(rcar_vin_of_table),
},
- .id_table = rcar_vin_id_table,
};
module_platform_driver(rcar_vin_driver);
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 67a669d..90c87f2 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -40,11 +40,11 @@
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/soc_camera.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/sh_mobile_csi2.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_csi2.h>
#include <media/videobuf2-dma-contig.h>
#include <media/v4l2-mediabus.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include "soc_scale_crop.h"
@@ -210,43 +210,14 @@ static int sh_mobile_ceu_soft_reset(struct sh_mobile_ceu_dev *pcdev)
* for the current frame format if required
*/
static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct soc_camera_device *icd = container_of(vq,
struct soc_camera_device, vb2_vidq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct sh_mobile_ceu_dev *pcdev = ici->priv;
- if (fmt) {
- const struct soc_camera_format_xlate *xlate = soc_camera_xlate_by_fourcc(icd,
- fmt->fmt.pix.pixelformat);
- unsigned int bytes_per_line;
- int ret;
-
- if (!xlate)
- return -EINVAL;
-
- ret = soc_mbus_bytes_per_line(fmt->fmt.pix.width,
- xlate->host_fmt);
- if (ret < 0)
- return ret;
-
- bytes_per_line = max_t(u32, fmt->fmt.pix.bytesperline, ret);
-
- ret = soc_mbus_image_size(xlate->host_fmt, bytes_per_line,
- fmt->fmt.pix.height);
- if (ret < 0)
- return ret;
-
- sizes[0] = max_t(u32, fmt->fmt.pix.sizeimage, ret);
- } else {
- /* Called from VIDIOC_REQBUFS or in compatibility mode */
- sizes[0] = icd->sizeimage;
- }
-
alloc_ctxs[0] = pcdev->alloc_ctx;
if (!vq->num_buffers)
@@ -255,8 +226,14 @@ static int sh_mobile_ceu_videobuf_setup(struct vb2_queue *vq,
if (!*count)
*count = 2;
+ /* Called from VIDIOC_REQBUFS or in compatibility mode */
+ if (!*num_planes)
+ sizes[0] = icd->sizeimage;
+ else if (sizes[0] < icd->sizeimage)
+ return -EINVAL;
+
/* If *num_planes != 0, we have already verified *count. */
- if (pcdev->video_limit && !*num_planes) {
+ if (pcdev->video_limit) {
size_t size = PAGE_ALIGN(sizes[0]) * *count;
if (size + pcdev->buf_total > pcdev->video_limit)
@@ -533,7 +510,7 @@ static irqreturn_t sh_mobile_ceu_irq(int irq, void *data)
pcdev->active = NULL;
ret = sh_mobile_ceu_capture(pcdev);
- v4l2_get_timestamp(&vbuf->timestamp);
+ vbuf->vb2_buf.timestamp = ktime_get_ns();
if (!ret) {
vbuf->field = pcdev->field;
vbuf->sequence = pcdev->sequence++;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index 12d3626..09b1836 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -18,10 +18,10 @@
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/sh_mobile_csi2.h>
+#include <media/drv-intf/sh_mobile_ceu.h>
+#include <media/drv-intf/sh_mobile_csi2.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index dc98122..cc84c6d 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -30,7 +30,7 @@
#include <linux/vmalloc.h>
#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
#include <media/v4l2-async.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
@@ -1360,7 +1360,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
struct soc_camera_host_desc *shd = &sdesc->host_desc;
struct i2c_adapter *adap;
struct v4l2_subdev *subdev;
- char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ char clk_name[V4L2_CLK_NAME_SIZE];
int ret;
/* First find out how we link the main client */
@@ -1391,8 +1391,8 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd,
ssdd->sd_pdata.regulators = NULL;
shd->board_info->platform_data = ssdd;
- snprintf(clk_name, sizeof(clk_name), "%d-%04x",
- shd->i2c_adapter_id, shd->board_info->addr);
+ v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+ shd->i2c_adapter_id, shd->board_info->addr);
icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
@@ -1526,7 +1526,7 @@ static int scan_async_group(struct soc_camera_host *ici,
struct soc_camera_async_client *sasc;
struct soc_camera_device *icd;
struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
- char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ char clk_name[V4L2_CLK_NAME_SIZE];
unsigned int i;
int ret;
@@ -1572,8 +1572,9 @@ static int scan_async_group(struct soc_camera_host *ici,
icd->sasc = sasc;
icd->parent = ici->v4l2_dev.dev;
- snprintf(clk_name, sizeof(clk_name), "%d-%04x",
- sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address);
+ v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+ sasd->asd.match.i2c.adapter_id,
+ sasd->asd.match.i2c.address);
icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
@@ -1631,7 +1632,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
struct soc_camera_async_client *sasc;
struct soc_of_info *info;
struct i2c_client *client;
- char clk_name[V4L2_SUBDEV_NAME_SIZE + 32];
+ char clk_name[V4L2_CLK_NAME_SIZE];
int ret;
/* allocate a new subdev and add match info to it */
@@ -1674,11 +1675,11 @@ static int soc_of_bind(struct soc_camera_host *ici,
client = of_find_i2c_device_by_node(remote);
if (client)
- snprintf(clk_name, sizeof(clk_name), "%d-%04x",
- client->adapter->nr, client->addr);
+ v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
+ client->adapter->nr, client->addr);
else
- snprintf(clk_name, sizeof(clk_name), "of-%s",
- of_node_full_name(remote));
+ v4l2_clk_name_of(clk_name, sizeof(clk_name),
+ of_node_full_name(remote));
icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd);
if (IS_ERR(icd->clk)) {
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index cc8eb07..a51d2a4 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -18,7 +18,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-subdev.h>
#include <media/soc_camera.h>
-#include <media/soc_camera_platform.h>
+#include <linux/platform_data/media/soc_camera_platform.h>
struct soc_camera_platform_priv {
struct v4l2_subdev subdev;
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index 1dbcd42..e3e665e 100644
--- a/drivers/media/platform/soc_camera/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
@@ -13,7 +13,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
-#include <media/soc_mediabus.h>
+#include <media/drv-intf/soc_mediabus.h>
static const struct soc_mbus_lookup mbus_fmt[] = {
{
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
index a0d267e..d12a419 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -191,7 +191,7 @@ static void bdisp_job_finish(struct bdisp_ctx *ctx, int vb_state)
dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (src_vb && dst_vb) {
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
dst_vb->timecode = src_vb->timecode;
dst_vb->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK;
dst_vb->flags |= src_vb->flags &
@@ -297,7 +297,7 @@ static int bdisp_get_bufs(struct bdisp_ctx *ctx)
if (ret)
return ret;
- dst_vb->timestamp = src_vb->timestamp;
+ dst_vb->vb2_buf.timestamp = src_vb->vb2_buf.timestamp;
return 0;
}
@@ -438,11 +438,9 @@ static void bdisp_ctrls_delete(struct bdisp_ctx *ctx)
}
static int bdisp_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nb_buf, unsigned int *nb_planes,
unsigned int sizes[], void *allocators[])
{
- const struct v4l2_format *fmt = parg;
struct bdisp_ctx *ctx = vb2_get_drv_priv(vq);
struct bdisp_frame *frame = ctx_get_frame(ctx, vq->type);
@@ -455,13 +453,13 @@ static int bdisp_queue_setup(struct vb2_queue *vq,
dev_err(ctx->bdisp_dev->dev, "Invalid format\n");
return -EINVAL;
}
+ allocators[0] = ctx->bdisp_dev->alloc_ctx;
- if (fmt && fmt->fmt.pix.sizeimage < frame->sizeimage)
- return -EINVAL;
+ if (*nb_planes)
+ return sizes[0] < frame->sizeimage ? -EINVAL : 0;
*nb_planes = 1;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : frame->sizeimage;
- allocators[0] = ctx->bdisp_dev->alloc_ctx;
+ sizes[0] = frame->sizeimage;
return 0;
}
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c
index 95223ab..2dfbe8a 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-common.c
@@ -209,18 +209,18 @@ void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
tsin = fei->channel_data[n];
- if (tsin && tsin->frontend) {
- dvb_unregister_frontend(tsin->frontend);
- dvb_frontend_detach(tsin->frontend);
- }
+ if (tsin) {
+ if (tsin->frontend) {
+ dvb_unregister_frontend(tsin->frontend);
+ dvb_frontend_detach(tsin->frontend);
+ }
- if (tsin && tsin->i2c_adapter)
i2c_put_adapter(tsin->i2c_adapter);
- if (tsin && tsin->i2c_client) {
- if (tsin->i2c_client->dev.driver->owner)
+ if (tsin->i2c_client) {
module_put(tsin->i2c_client->dev.driver->owner);
- i2c_unregister_device(tsin->i2c_client);
+ i2c_unregister_device(tsin->i2c_client);
+ }
}
}
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
index 8490a65..78e3cb9 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -823,7 +823,7 @@ static int c8sectpfe_probe(struct platform_device *pdev)
}
of_node_put(i2c_bus);
- tsin->rst_gpio = of_get_named_gpio(child, "rst-gpio", 0);
+ tsin->rst_gpio = of_get_named_gpio(child, "reset-gpios", 0);
ret = gpio_is_valid(tsin->rst_gpio);
if (!ret) {
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index de24eff..1fa00c2 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -1288,7 +1288,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
d_vb = ctx->dst_vb;
d_vb->flags = s_vb->flags;
- d_vb->timestamp = s_vb->timestamp;
+ d_vb->vb2_buf.timestamp = s_vb->vb2_buf.timestamp;
if (s_vb->flags & V4L2_BUF_FLAG_TIMECODE)
d_vb->timecode = s_vb->timecode;
@@ -1796,7 +1796,6 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
* Queue operations
*/
static int vpe_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index 5820e45..113c9f3 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -31,7 +31,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/videobuf-dma-contig.h>
-#include <media/timb_video.h>
+#include <linux/platform_data/media/timb_video.h>
#define DRIVER_NAME "timb-video"
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index 32e4ff4..1254f7e 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -19,7 +19,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-image-sizes.h>
-#include <media/ov7670.h>
+#include <media/i2c/ov7670.h>
#include <media/videobuf-dma-sg.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c
index e18fb9f..418113c 100644
--- a/drivers/media/platform/vim2m.c
+++ b/drivers/media/platform/vim2m.c
@@ -235,7 +235,7 @@ static int device_process(struct vim2m_ctx *ctx,
out_vb->sequence =
get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE)->sequence++;
in_vb->sequence = q_data->sequence++;
- out_vb->timestamp = in_vb->timestamp;
+ out_vb->vb2_buf.timestamp = in_vb->vb2_buf.timestamp;
if (in_vb->flags & V4L2_BUF_FLAG_TIMECODE)
out_vb->timecode = in_vb->timecode;
@@ -710,11 +710,9 @@ static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
*/
static int vim2m_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
struct vim2m_q_data *q_data;
unsigned int size, count = *nbuffers;
@@ -723,17 +721,14 @@ static int vim2m_queue_setup(struct vb2_queue *vq,
size = q_data->width * q_data->height * q_data->fmt->depth >> 3;
- if (fmt) {
- if (fmt->fmt.pix.sizeimage < size)
- return -EINVAL;
- size = fmt->fmt.pix.sizeimage;
- }
-
while (size * count > MEM2MEM_VID_MEM_LIMIT)
(count)--;
+ *nbuffers = count;
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
- *nbuffers = count;
sizes[0] = size;
/*
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 55b304a..751c1ba 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -264,6 +264,7 @@ struct vivid_dev {
bool vflip;
bool vbi_cap_interlaced;
bool loop_video;
+ bool reduced_fps;
/* Framebuffer */
unsigned long video_pbase;
@@ -285,7 +286,7 @@ struct vivid_dev {
bool dqbuf_error;
bool seq_wrap;
bool time_wrap;
- __kernel_time_t time_wrap_offset;
+ u64 time_wrap_offset;
unsigned perc_dropped_buffers;
enum vivid_signal_mode std_signal_mode;
unsigned query_std_last;
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index f41ac0b..b98089c 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -78,6 +78,7 @@
#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39)
#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40)
#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41)
+#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42)
#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)
#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)
@@ -424,6 +425,10 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
dev->sensor_vflip = ctrl->val;
tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip);
break;
+ case VIVID_CID_REDUCED_FPS:
+ dev->reduced_fps = ctrl->val;
+ vivid_update_format_cap(dev, true);
+ break;
case VIVID_CID_HAS_CROP_CAP:
dev->has_crop_cap = ctrl->val;
vivid_update_format_cap(dev, true);
@@ -601,6 +606,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_vflip = {
.step = 1,
};
+static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_REDUCED_FPS,
+ .name = "Reduced Framerate",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .max = 1,
+ .step = 1,
+};
+
static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = {
.ops = &vivid_vid_cap_ctrl_ops,
.id = VIVID_CID_HAS_CROP_CAP,
@@ -940,7 +954,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming);
- struct timeval tv;
+ u64 rem;
switch (ctrl->id) {
case VIVID_CID_DQBUF_ERROR:
@@ -979,8 +993,16 @@ static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
dev->time_wrap_offset = 0;
break;
}
- v4l2_get_timestamp(&tv);
- dev->time_wrap_offset = -tv.tv_sec - 16;
+ /*
+ * We want to set the time 16 seconds before the 32 bit tv_sec
+ * value of struct timeval would wrap around. So first we
+ * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and
+ * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC).
+ */
+ div64_u64_rem(ktime_get_ns(),
+ 0x100000000ULL * NSEC_PER_SEC, &rem);
+ dev->time_wrap_offset =
+ (0x100000000ULL - 16) * NSEC_PER_SEC - rem;
break;
}
return 0;
@@ -1340,11 +1362,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_handler_init(hdl_vid_cap, 55);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_vid_out, 26);
- v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
+ if (!no_error_inj)
+ v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_vbi_cap, 21);
v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_vbi_out, 19);
- v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
+ if (!no_error_inj)
+ v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_radio_rx, 17);
v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL);
v4l2_ctrl_handler_init(hdl_radio_tx, 17);
@@ -1414,6 +1438,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL);
+ v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL);
if (show_ccs_cap) {
dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_has_crop_cap, NULL);
diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c
index 83cc6d3..9034281 100644
--- a/drivers/media/platform/vivid/vivid-kthread-cap.c
+++ b/drivers/media/platform/vivid/vivid-kthread-cap.c
@@ -441,7 +441,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
* "Start of Exposure".
*/
if (dev->tstamp_src_is_soe)
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
if (dev->field_cap == V4L2_FIELD_ALTERNATE) {
/*
* 60 Hz standards start with the bottom field, 50 Hz standards
@@ -558,8 +558,8 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
* the timestamp now.
*/
if (!dev->tstamp_src_is_soe)
- v4l2_get_timestamp(&buf->vb.timestamp);
- buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ buf->vb.vb2_buf.timestamp += dev->time_wrap_offset;
}
/*
diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c
index c2c46dc..98eed58 100644
--- a/drivers/media/platform/vivid/vivid-kthread-out.c
+++ b/drivers/media/platform/vivid/vivid-kthread-out.c
@@ -95,8 +95,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
*/
vid_out_buf->vb.sequence /= 2;
}
- v4l2_get_timestamp(&vid_out_buf->vb.timestamp);
- vid_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ vid_out_buf->vb.vb2_buf.timestamp =
+ ktime_get_ns() + dev->time_wrap_offset;
vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "vid_out buffer %d done\n",
@@ -108,8 +108,8 @@ static void vivid_thread_vid_out_tick(struct vivid_dev *dev)
vivid_sliced_vbi_out_process(dev, vbi_out_buf);
vbi_out_buf->vb.sequence = dev->vbi_out_seq_count;
- v4l2_get_timestamp(&vbi_out_buf->vb.timestamp);
- vbi_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ vbi_out_buf->vb.vb2_buf.timestamp =
+ ktime_get_ns() + dev->time_wrap_offset;
vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dprintk(dev, 2, "vbi_out buffer %d done\n",
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 082c401..3d1604c 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -117,8 +117,8 @@ static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev)
if (sdr_cap_buf) {
sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count;
vivid_sdr_cap_process(dev, sdr_cap_buf);
- v4l2_get_timestamp(&sdr_cap_buf->vb.timestamp);
- sdr_cap_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ sdr_cap_buf->vb.vb2_buf.timestamp =
+ ktime_get_ns() + dev->time_wrap_offset;
vb2_buffer_done(&sdr_cap_buf->vb.vb2_buf, dev->dqbuf_error ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
dev->dqbuf_error = false;
@@ -213,7 +213,7 @@ static int vivid_thread_sdr_cap(void *data)
return 0;
}
-static int sdr_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int sdr_cap_queue_setup(struct vb2_queue *vq,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index e903d02..cda45a5 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -108,8 +108,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode))
vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf);
- v4l2_get_timestamp(&buf->vb.timestamp);
- buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
}
@@ -133,11 +132,10 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev,
vbuf[i] = dev->vbi_gen.data[i];
}
- v4l2_get_timestamp(&buf->vb.timestamp);
- buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset;
}
-static int vbi_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_cap_queue_setup(struct vb2_queue *vq,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
index 75c5709..3c5a469 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.c
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -27,7 +27,7 @@
#include "vivid-vbi-out.h"
#include "vivid-vbi-cap.h"
-static int vbi_out_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_out_queue_setup(struct vb2_queue *vq,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index ef54123..b84f081 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -95,11 +95,10 @@ static const struct v4l2_discrete_probe webcam_probe = {
VIVID_WEBCAM_SIZES
};
-static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vid_cap_queue_setup(struct vb2_queue *vq,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct vivid_dev *dev = vb2_get_drv_priv(vq);
unsigned buffers = tpg_g_buffers(&dev->tpg);
unsigned h = dev->fmt_cap_rect.height;
@@ -122,27 +121,16 @@ static int vid_cap_queue_setup(struct vb2_queue *vq, const void *parg,
dev->queue_setup_error = false;
return -EINVAL;
}
- if (fmt) {
- const struct v4l2_pix_format_mplane *mp;
- struct v4l2_format mp_fmt;
- const struct vivid_fmt *vfmt;
-
- if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
- fmt_sp2mp(fmt, &mp_fmt);
- fmt = &mp_fmt;
- }
- mp = &fmt->fmt.pix_mp;
+ if (*nplanes) {
/*
- * Check if the number of planes in the specified format match
+ * Check if the number of requested planes match
* the number of buffers in the current format. You can't mix that.
*/
- if (mp->num_planes != buffers)
+ if (*nplanes != buffers)
return -EINVAL;
- vfmt = vivid_get_format(dev, mp->pixelformat);
for (p = 0; p < buffers; p++) {
- sizes[p] = mp->plane_fmt[p].sizeimage;
if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
- vfmt->data_offset[p])
+ dev->fmt_cap->data_offset[p])
return -EINVAL;
}
} else {
@@ -405,6 +393,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
{
struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt;
unsigned size;
+ u64 pixelclock;
switch (dev->input_type[dev->input]) {
case WEBCAM:
@@ -434,8 +423,15 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
dev->src_rect.width = bt->width;
dev->src_rect.height = bt->height;
size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+ if (dev->reduced_fps && can_reduce_fps(bt)) {
+ pixelclock = div_u64(bt->pixelclock * 1000, 1001);
+ bt->flags |= V4L2_DV_FL_REDUCED_FPS;
+ } else {
+ pixelclock = bt->pixelclock;
+ bt->flags &= ~V4L2_DV_FL_REDUCED_FPS;
+ }
dev->timeperframe_vid_cap = (struct v4l2_fract) {
- size / 100, (u32)bt->pixelclock / 100
+ size / 100, (u32)pixelclock / 100
};
if (bt->interlaced)
dev->field_cap = V4L2_FIELD_ALTERNATE;
@@ -1662,7 +1658,7 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh,
!valid_cvt_gtf_timings(timings))
return -EINVAL;
- if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0))
+ if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false))
return 0;
if (vb2_is_busy(&dev->vb_vid_cap_q))
return -EBUSY;
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index b77acb6..64e4d66 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -31,11 +31,10 @@
#include "vivid-kthread-out.h"
#include "vivid-vid-out.h"
-static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vid_out_queue_setup(struct vb2_queue *vq,
unsigned *nbuffers, unsigned *nplanes,
unsigned sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct vivid_dev *dev = vb2_get_drv_priv(vq);
const struct vivid_fmt *vfmt = dev->fmt_out;
unsigned planes = vfmt->buffers;
@@ -64,26 +63,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq, const void *parg,
return -EINVAL;
}
- if (fmt) {
- const struct v4l2_pix_format_mplane *mp;
- struct v4l2_format mp_fmt;
-
- if (!V4L2_TYPE_IS_MULTIPLANAR(fmt->type)) {
- fmt_sp2mp(fmt, &mp_fmt);
- fmt = &mp_fmt;
- }
- mp = &fmt->fmt.pix_mp;
+ if (*nplanes) {
/*
- * Check if the number of planes in the specified format match
+ * Check if the number of requested planes match
* the number of planes in the current format. You can't mix that.
*/
- if (mp->num_planes != planes)
+ if (*nplanes != planes)
return -EINVAL;
- sizes[0] = mp->plane_fmt[0].sizeimage;
if (sizes[0] < size)
return -EINVAL;
for (p = 1; p < planes; p++) {
- sizes[p] = mp->plane_fmt[p].sizeimage;
if (sizes[p] < dev->bytesperline_out[p] * h)
return -EINVAL;
}
@@ -224,6 +213,7 @@ void vivid_update_format_out(struct vivid_dev *dev)
{
struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
unsigned size, p;
+ u64 pixelclock;
switch (dev->output_type[dev->output]) {
case SVID:
@@ -245,8 +235,14 @@ void vivid_update_format_out(struct vivid_dev *dev)
dev->sink_rect.width = bt->width;
dev->sink_rect.height = bt->height;
size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt);
+
+ if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS))
+ pixelclock = div_u64(bt->pixelclock * 1000, 1001);
+ else
+ pixelclock = bt->pixelclock;
+
dev->timeperframe_vid_out = (struct v4l2_fract) {
- size / 100, (u32)bt->pixelclock / 100
+ size / 100, (u32)pixelclock / 100
};
if (bt->interlaced)
dev->field_out = V4L2_FIELD_ALTERNATE;
@@ -1149,7 +1145,7 @@ int vivid_vid_out_s_dv_timings(struct file *file, void *_fh,
0, NULL, NULL) &&
!valid_cvt_gtf_timings(timings))
return -EINVAL;
- if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0))
+ if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true))
return 0;
if (vb2_is_busy(&dev->vb_vid_out_q))
return -EBUSY;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 5ce88e1..45eb65f 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -274,35 +274,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
return 0;
}
-static bool
-vsp1_video_format_adjust(struct vsp1_video *video,
- const struct v4l2_pix_format_mplane *format,
- struct v4l2_pix_format_mplane *adjust)
-{
- unsigned int i;
-
- *adjust = *format;
- __vsp1_video_try_format(video, adjust, NULL);
-
- if (format->width != adjust->width ||
- format->height != adjust->height ||
- format->pixelformat != adjust->pixelformat ||
- format->num_planes != adjust->num_planes)
- return false;
-
- for (i = 0; i < format->num_planes; ++i) {
- if (format->plane_fmt[i].bytesperline !=
- adjust->plane_fmt[i].bytesperline)
- return false;
-
- adjust->plane_fmt[i].sizeimage =
- max(adjust->plane_fmt[i].sizeimage,
- format->plane_fmt[i].sizeimage);
- }
-
- return true;
-}
-
/* -----------------------------------------------------------------------------
* Pipeline Management
*/
@@ -611,7 +582,7 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
spin_unlock_irqrestore(&video->irqlock, flags);
done->buf.sequence = video->sequence++;
- v4l2_get_timestamp(&done->buf.timestamp);
+ done->buf.vb2_buf.timestamp = ktime_get_ns();
for (i = 0; i < done->buf.vb2_buf.num_planes; ++i)
vb2_set_plane_payload(&done->buf.vb2_buf, i, done->length[i]);
vb2_buffer_done(&done->buf.vb2_buf, VB2_BUF_STATE_DONE);
@@ -787,26 +758,24 @@ void vsp1_pipelines_resume(struct vsp1_device *vsp1)
*/
static int
-vsp1_video_queue_setup(struct vb2_queue *vq, const void *parg,
+vsp1_video_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct vsp1_video *video = vb2_get_drv_priv(vq);
- const struct v4l2_pix_format_mplane *format;
- struct v4l2_pix_format_mplane pix_mp;
+ const struct v4l2_pix_format_mplane *format = &video->format;
unsigned int i;
- if (fmt) {
- /* Make sure the format is valid and adjust the sizeimage field
- * if needed.
- */
- if (!vsp1_video_format_adjust(video, &fmt->fmt.pix_mp, &pix_mp))
+ if (*nplanes) {
+ if (*nplanes != format->num_planes)
return -EINVAL;
- format = &pix_mp;
- } else {
- format = &video->format;
+ for (i = 0; i < *nplanes; i++) {
+ if (sizes[i] < format->plane_fmt[i].sizeimage)
+ return -EINVAL;
+ alloc_ctxs[i] = video->alloc_ctx;
+ }
+ return 0;
}
*nplanes = format->num_planes;
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index d11cc70..722758f 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -303,27 +303,25 @@ static void xvip_dma_complete(void *param)
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = dma->sequence++;
- v4l2_get_timestamp(&buf->buf.timestamp);
+ buf->buf.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, dma->format.sizeimage);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
}
static int
-xvip_dma_queue_setup(struct vb2_queue *vq, const void *parg,
+xvip_dma_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct xvip_dma *dma = vb2_get_drv_priv(vq);
+ alloc_ctxs[0] = dma->alloc_ctx;
/* Make sure the image size is large enough. */
- if (fmt && fmt->fmt.pix.sizeimage < dma->format.sizeimage)
- return -EINVAL;
+ if (*nplanes)
+ return sizes[0] < dma->format.sizeimage ? -EINVAL : 0;
*nplanes = 1;
-
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : dma->format.sizeimage;
- alloc_ctxs[0] = dma->alloc_ctx;
+ sizes[0] = dma->format.sizeimage;
return 0;
}
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index b5f7d5e..8bd7e37 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -731,6 +731,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
format = xvip_of_get_format(port);
if (IS_ERR(format)) {
dev_err(dev, "invalid format in DT");
+ of_node_put(port);
return PTR_ERR(format);
}
@@ -739,6 +740,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
xtpg->vip_format = format;
} else if (xtpg->vip_format != format) {
dev_err(dev, "in/out format mismatch in DT");
+ of_node_put(port);
return -EINVAL;
}
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index 7b7cb9c..b9bf24f 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -476,8 +476,10 @@ static int xvip_graph_dma_init(struct xvip_composite_device *xdev)
for_each_child_of_node(ports, port) {
ret = xvip_graph_dma_init_one(xdev, port);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(port);
return ret;
+ }
}
return 0;
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 5236035..70fd8e8 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -42,7 +42,7 @@
#include <linux/videodev2.h>
#include <linux/io.h>
#include <linux/slab.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fh.h>
@@ -108,7 +108,7 @@ static void maxiradio_tea575x_set_direction(struct snd_tea575x *tea, bool output
{
}
-static struct snd_tea575x_ops maxiradio_tea_ops = {
+static const struct snd_tea575x_ops maxiradio_tea_ops = {
.set_pins = maxiradio_tea575x_set_pins,
.get_pins = maxiradio_tea575x_get_pins,
.set_direction = maxiradio_tea575x_set_direction,
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index b8d61cb..dc81d42 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -14,7 +14,7 @@
#include <linux/io.h> /* outb, outb_p */
#include <linux/isa.h>
#include <linux/pnp.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
MODULE_AUTHOR("Ondrej Zary");
MODULE_DESCRIPTION("MediaForte SF16-FMR2 and SF16-FMD2 FM radio card driver");
@@ -82,7 +82,7 @@ static void fmr2_tea575x_set_direction(struct snd_tea575x *tea, bool output)
{
}
-static struct snd_tea575x_ops fmr2_tea_ops = {
+static const struct snd_tea575x_ops fmr2_tea_ops = {
.set_pins = fmr2_tea575x_set_pins,
.get_pins = fmr2_tea575x_get_pins,
.set_direction = fmr2_tea575x_set_direction,
diff --git a/drivers/media/radio/radio-shark.c b/drivers/media/radio/radio-shark.c
index 050b3bb..85667a9 100644
--- a/drivers/media/radio/radio-shark.c
+++ b/drivers/media/radio/radio-shark.c
@@ -33,7 +33,7 @@
#include <linux/usb.h>
#include <linux/workqueue.h>
#include <media/v4l2-device.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
#if defined(CONFIG_LEDS_CLASS) || \
(defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE))
@@ -150,7 +150,7 @@ static u32 shark_read_val(struct snd_tea575x *tea)
return val;
}
-static struct snd_tea575x_ops shark_tea_ops = {
+static const struct snd_tea575x_ops shark_tea_ops = {
.write_val = shark_write_val,
.read_val = shark_read_val,
};
diff --git a/drivers/media/radio/radio-shark2.c b/drivers/media/radio/radio-shark2.c
index 8654e0d..0e65a85 100644
--- a/drivers/media/radio/radio-shark2.c
+++ b/drivers/media/radio/radio-shark2.c
@@ -137,7 +137,7 @@ static int shark_read_reg(struct radio_tea5777 *tea, u32 *reg_ret)
return 0;
}
-static struct radio_tea5777_ops shark_tea_ops = {
+static const struct radio_tea5777_ops shark_tea_ops = {
.write_reg = shark_write_reg,
.read_reg = shark_read_reg,
};
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 9cbb8cd..859f0c0 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -31,7 +31,7 @@
#include <media/v4l2-event.h>
#include <media/v4l2-device.h>
-#include <media/si476x.h>
+#include <media/drv-intf/si476x.h>
#include <linux/mfd/si476x-core.h>
#define FM_FREQ_RANGE_LOW 64000000
diff --git a/drivers/media/radio/radio-tea5777.h b/drivers/media/radio/radio-tea5777.h
index 4ea43a9..4bd9425 100644
--- a/drivers/media/radio/radio-tea5777.h
+++ b/drivers/media/radio/radio-tea5777.h
@@ -76,7 +76,7 @@ struct radio_tea5777 {
u32 read_reg;
u64 write_reg;
struct mutex mutex;
- struct radio_tea5777_ops *ops;
+ const struct radio_tea5777_ops *ops;
void *private_data;
u8 card[32];
u8 bus_info[32];
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 04baafe..a82eb96 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/module.h>
-#include <media/timb_radio.h>
+#include <linux/platform_data/media/timb_radio.h>
#define DRIVER_NAME "timb-radio"
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index a77319d..5146be2 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -31,7 +31,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
#include "si4713.h"
diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h
index 8a376e1..29d0e1f 100644
--- a/drivers/media/radio/si4713/si4713.h
+++ b/drivers/media/radio/si4713/si4713.h
@@ -20,7 +20,7 @@
#include <linux/gpio/consumer.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
-#include <media/si4713.h>
+#include <linux/platform_data/media/si4713.h>
#define SI4713_PRODUCT_NUMBER 0x0D
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index 43d1ea5..3e08475 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -31,7 +31,7 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
MODULE_DESCRIPTION("Routines for control of TEA5757/5759 Philips AM/FM radio tuner chips");
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index b6e1311..bd4d685 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -101,7 +101,8 @@ config IR_SHARP_DECODER
---help---
Enable this option if you have an infrared remote control which
- uses the Sharp protocol, and you need software decoding support.
+ uses the Sharp protocol (Sharp, Denon), and you need software
+ decoding support.
config IR_MCE_KBD_DECODER
tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol"
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 7dbc9ca..5b63b1f 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -21,7 +21,7 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <media/rc-core.h>
-#include <media/gpio-ir-recv.h>
+#include <linux/platform_data/media/gpio-ir-recv.h>
#define GPIO_IR_DRIVER_NAME "gpio-rc-recv"
#define GPIO_IR_DEVICE_NAME "gpio_ir_recv"
@@ -30,6 +30,7 @@ struct gpio_rc_dev {
struct rc_dev *rcdev;
int gpio_nr;
bool active_low;
+ struct timer_list flush_timer;
};
#ifdef CONFIG_OF
@@ -93,12 +94,26 @@ static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
if (rc < 0)
goto err_get_value;
+ mod_timer(&gpio_dev->flush_timer,
+ jiffies + nsecs_to_jiffies(gpio_dev->rcdev->timeout));
+
ir_raw_event_handle(gpio_dev->rcdev);
err_get_value:
return IRQ_HANDLED;
}
+static void flush_timer(unsigned long arg)
+{
+ struct gpio_rc_dev *gpio_dev = (struct gpio_rc_dev *)arg;
+ DEFINE_IR_RAW_EVENT(ev);
+
+ ev.timeout = true;
+ ev.duration = gpio_dev->rcdev->timeout;
+ ir_raw_event_store(gpio_dev->rcdev, &ev);
+ ir_raw_event_handle(gpio_dev->rcdev);
+}
+
static int gpio_ir_recv_probe(struct platform_device *pdev)
{
struct gpio_rc_dev *gpio_dev;
@@ -144,6 +159,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
rcdev->input_id.version = 0x0100;
rcdev->dev.parent = &pdev->dev;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
+ rcdev->min_timeout = 0;
+ rcdev->timeout = IR_DEFAULT_TIMEOUT;
+ rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
if (pdata->allowed_protos)
rcdev->allowed_protocols = pdata->allowed_protos;
else
@@ -154,6 +172,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
gpio_dev->gpio_nr = pdata->gpio_nr;
gpio_dev->active_low = pdata->active_low;
+ setup_timer(&gpio_dev->flush_timer, flush_timer,
+ (unsigned long)gpio_dev);
+
rc = gpio_request(pdata->gpio_nr, "gpio-ir-recv");
if (rc < 0)
goto err_gpio_request;
@@ -196,6 +217,7 @@ static int gpio_ir_recv_remove(struct platform_device *pdev)
struct gpio_rc_dev *gpio_dev = platform_get_drvdata(pdev);
free_irq(gpio_to_irq(gpio_dev->gpio_nr), gpio_dev);
+ del_timer_sync(&gpio_dev->flush_timer);
rc_unregister_device(gpio_dev->rcdev);
gpio_free(gpio_dev->gpio_nr);
kfree(gpio_dev);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 30bcf18..182402f 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,9 +47,6 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!(dev->enabled_protocols & RC_BIT_JVC))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index a32659f..5effc65 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -415,6 +415,7 @@ static int ir_lirc_unregister(struct rc_dev *dev)
lirc_unregister_driver(lirc->drv->minor);
lirc_buffer_free(lirc->drv->rbuf);
+ kfree(lirc->drv->rbuf);
kfree(lirc->drv);
return 0;
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 9f3c9b5..d809862 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,9 +216,6 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 7b81fec..bea0d1e 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -52,9 +52,6 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!(dev->enabled_protocols & RC_BIT_NEC))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 84fa6e9..6ffe776 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -53,9 +53,6 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
enum rc_type protocol;
- if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ)))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index d16bc67..e0e2ede 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -90,11 +90,6 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 toggle;
enum rc_type protocol;
- if (!(dev->enabled_protocols &
- (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
- RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c
index b1e19a2..4e1711a 100644
--- a/drivers/media/rc/ir-rx51.c
+++ b/drivers/media/rc/ir-rx51.c
@@ -31,7 +31,7 @@
#include <media/lirc.h>
#include <media/lirc_dev.h>
-#include <media/ir-rx51.h>
+#include <linux/platform_data/media/ir-rx51.h>
#define LIRC_RX51_DRIVER_FEATURES (LIRC_CAN_SET_SEND_DUTY_CYCLE | \
LIRC_CAN_SET_SEND_CARRIER | \
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index ad1dc6a..7331e5e7 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,9 +58,6 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!(dev->enabled_protocols & RC_BIT_SANYO))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset) {
IR_dprintk(1, "SANYO event reset received. reset to state 0\n");
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index b7acdba..317677f 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -48,9 +48,6 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct sharp_dec *data = &dev->raw->sharp;
u32 msg, echo, address, command, scancode;
- if (!(dev->enabled_protocols & RC_BIT_SHARP))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
@@ -118,7 +115,9 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (data->count == SHARP_NBITS) {
/* exp,chk bits should be 1,0 */
- if ((data->bits & 0x3) != 0x2)
+ if ((data->bits & 0x3) != 0x2 &&
+ /* DENON variant, both chk bits 0 */
+ (data->bits & 0x3) != 0x0)
break;
data->state = STATE_ECHO_SPACE;
} else {
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 58ef06f..baa972c 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -46,10 +46,6 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 device, subdevice, function;
- if (!(dev->enabled_protocols &
- (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c
index 1017d48..1859619 100644
--- a/drivers/media/rc/ir-xmp-decoder.c
+++ b/drivers/media/rc/ir-xmp-decoder.c
@@ -43,9 +43,6 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct xmp_dec *data = &dev->raw->xmp;
- if (!(dev->enabled_protocols & RC_BIT_XMP))
- return 0;
-
if (!is_timing_event(ev)) {
if (ev.reset)
data->state = STATE_INACTIVE;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 85af7a8..18adf58 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -39,6 +39,18 @@
#include "nuvoton-cir.h"
+static const struct nvt_chip nvt_chips[] = {
+ { "w83667hg", NVT_W83667HG },
+ { "NCT6775F", NVT_6775F },
+ { "NCT6776F", NVT_6776F },
+ { "NCT6779D", NVT_6779D },
+};
+
+static inline bool is_w83667hg(struct nvt_dev *nvt)
+{
+ return nvt->chip_ver == NVT_W83667HG;
+}
+
/* write val to config reg */
static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
{
@@ -224,74 +236,60 @@ static void cir_wake_dump_regs(struct nvt_dev *nvt)
pr_cont("\n");
}
+static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nvt_chips); i++)
+ if ((id & SIO_ID_MASK) == nvt_chips[i].chip_ver) {
+ nvt->chip_ver = nvt_chips[i].chip_ver;
+ return nvt_chips[i].name;
+ }
+
+ return NULL;
+}
+
+
/* detect hardware features */
-static int nvt_hw_detect(struct nvt_dev *nvt)
+static void nvt_hw_detect(struct nvt_dev *nvt)
{
- unsigned long flags;
- u8 chip_major, chip_minor;
- char chip_id[12];
- bool chip_unknown = false;
+ const char *chip_name;
+ int chip_id;
nvt_efm_enable(nvt);
/* Check if we're wired for the alternate EFER setup */
- chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
- if (chip_major == 0xff) {
+ nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ if (nvt->chip_major == 0xff) {
nvt->cr_efir = CR_EFIR2;
nvt->cr_efdr = CR_EFDR2;
nvt_efm_enable(nvt);
- chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ nvt->chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
}
- chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
-
- /* these are the known working chip revisions... */
- switch (chip_major) {
- case CHIP_ID_HIGH_667:
- strcpy(chip_id, "w83667hg\0");
- if (chip_minor != CHIP_ID_LOW_667)
- chip_unknown = true;
- break;
- case CHIP_ID_HIGH_677B:
- strcpy(chip_id, "w83677hg\0");
- if (chip_minor != CHIP_ID_LOW_677B2 &&
- chip_minor != CHIP_ID_LOW_677B3)
- chip_unknown = true;
- break;
- case CHIP_ID_HIGH_677C:
- strcpy(chip_id, "w83677hg-c\0");
- if (chip_minor != CHIP_ID_LOW_677C)
- chip_unknown = true;
- break;
- default:
- strcpy(chip_id, "w836x7hg\0");
- chip_unknown = true;
- break;
- }
+ nvt->chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+
+ chip_id = nvt->chip_major << 8 | nvt->chip_minor;
+ chip_name = nvt_find_chip(nvt, chip_id);
/* warn, but still let the driver load, if we don't know this chip */
- if (chip_unknown)
- nvt_pr(KERN_WARNING, "%s: unknown chip, id: 0x%02x 0x%02x, "
- "it may not work...", chip_id, chip_major, chip_minor);
+ if (!chip_name)
+ dev_warn(&nvt->pdev->dev,
+ "unknown chip, id: 0x%02x 0x%02x, it may not work...",
+ nvt->chip_major, nvt->chip_minor);
else
- nvt_dbg("%s: chip id: 0x%02x 0x%02x",
- chip_id, chip_major, chip_minor);
+ dev_info(&nvt->pdev->dev,
+ "found %s or compatible: chip id: 0x%02x 0x%02x",
+ chip_name, nvt->chip_major, nvt->chip_minor);
nvt_efm_disable(nvt);
-
- spin_lock_irqsave(&nvt->nvt_lock, flags);
- nvt->chip_major = chip_major;
- nvt->chip_minor = chip_minor;
- spin_unlock_irqrestore(&nvt->nvt_lock, flags);
-
- return 0;
}
static void nvt_cir_ldev_init(struct nvt_dev *nvt)
{
u8 val, psreg, psmask, psval;
- if (nvt->chip_major == CHIP_ID_HIGH_667) {
+ if (is_w83667hg(nvt)) {
psreg = CR_MULTIFUNC_PIN_SEL;
psmask = MULTIFUNC_PIN_SEL_MASK;
psval = MULTIFUNC_ENABLE_CIR | MULTIFUNC_ENABLE_CIRWB;
@@ -485,8 +483,9 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
duration *= SAMPLE_PERIOD;
if (!count || !duration) {
- nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
- count, duration);
+ dev_notice(&nvt->pdev->dev,
+ "Unable to determine carrier! (c:%u, d:%u)",
+ count, duration);
return 0;
}
@@ -661,7 +660,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
{
- nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+ dev_warn(&nvt->pdev->dev, "RX FIFO overrun detected, flushing data!");
nvt->pkts = 0;
nvt_clear_cir_fifo(nvt);
@@ -719,7 +718,7 @@ static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
static void nvt_cir_log_irqs(u8 status, u8 iren)
{
- nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
+ nvt_dbg("IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
status, iren,
status & CIR_IRSTS_RDR ? " RDR" : "",
status & CIR_IRSTS_RTR ? " RTR" : "",
@@ -779,7 +778,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
if (!status) {
nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
- return IRQ_RETVAL(IRQ_NONE);
+ return IRQ_NONE;
}
/* ack/clear all irq flags we've got */
@@ -790,11 +789,10 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
iren = nvt_cir_reg_read(nvt, CIR_IREN);
if (!iren) {
nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
- return IRQ_RETVAL(IRQ_NONE);
+ return IRQ_NONE;
}
- if (debug)
- nvt_cir_log_irqs(status, iren);
+ nvt_cir_log_irqs(status, iren);
if (status & CIR_IRSTS_RTR) {
/* FIXME: add code for study/learn mode */
@@ -853,7 +851,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data)
}
nvt_dbg_verbose("%s done", __func__);
- return IRQ_RETVAL(IRQ_HANDLED);
+ return IRQ_HANDLED;
}
/* Interrupt service routine for CIR Wake */
@@ -867,7 +865,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
if (!status)
- return IRQ_RETVAL(IRQ_NONE);
+ return IRQ_NONE;
if (status & CIR_WAKE_IRSTS_IR_PENDING)
nvt_clear_cir_wake_fifo(nvt);
@@ -879,7 +877,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
if (!iren) {
nvt_dbg_wake("%s exiting, wake not enabled", __func__);
- return IRQ_RETVAL(IRQ_HANDLED);
+ return IRQ_HANDLED;
}
if ((status & CIR_WAKE_IRSTS_PE) &&
@@ -896,7 +894,7 @@ static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
}
nvt_dbg_wake("%s done", __func__);
- return IRQ_RETVAL(IRQ_HANDLED);
+ return IRQ_HANDLED;
}
static void nvt_enable_cir(struct nvt_dev *nvt)
@@ -974,7 +972,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
struct rc_dev *rdev;
int ret = -ENOMEM;
- nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+ nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL);
if (!nvt)
return ret;
@@ -1026,9 +1024,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
init_waitqueue_head(&nvt->tx.queue);
- ret = nvt_hw_detect(nvt);
- if (ret)
- goto exit_free_dev_rdev;
+ nvt_hw_detect(nvt);
/* Initialize CIR & CIR Wake Logical Devices */
nvt_efm_enable(nvt);
@@ -1074,25 +1070,26 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
ret = -EBUSY;
/* now claim resources */
- if (!request_region(nvt->cir_addr,
+ if (!devm_request_region(&pdev->dev, nvt->cir_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
goto exit_unregister_device;
- if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
- NVT_DRIVER_NAME, (void *)nvt))
- goto exit_release_cir_addr;
+ if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr,
+ IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt))
+ goto exit_unregister_device;
- if (!request_region(nvt->cir_wake_addr,
+ if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr,
CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
- goto exit_free_irq;
+ goto exit_unregister_device;
- if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
- NVT_DRIVER_NAME, (void *)nvt))
- goto exit_release_cir_wake_addr;
+ if (devm_request_irq(&pdev->dev, nvt->cir_wake_irq,
+ nvt_cir_wake_isr, IRQF_SHARED,
+ NVT_DRIVER_NAME, (void *)nvt))
+ goto exit_unregister_device;
device_init_wakeup(&pdev->dev, true);
- nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+ dev_notice(&pdev->dev, "driver has been successfully loaded\n");
if (debug) {
cir_dump_regs(nvt);
cir_wake_dump_regs(nvt);
@@ -1100,18 +1097,11 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
return 0;
-exit_release_cir_wake_addr:
- release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-exit_free_irq:
- free_irq(nvt->cir_irq, nvt);
-exit_release_cir_addr:
- release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
exit_unregister_device:
rc_unregister_device(rdev);
rdev = NULL;
exit_free_dev_rdev:
rc_free_device(rdev);
- kfree(nvt);
return ret;
}
@@ -1129,15 +1119,7 @@ static void nvt_remove(struct pnp_dev *pdev)
nvt_enable_wake(nvt);
spin_unlock_irqrestore(&nvt->nvt_lock, flags);
- /* free resources */
- free_irq(nvt->cir_irq, nvt);
- free_irq(nvt->cir_wake_irq, nvt);
- release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
- release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
-
rc_unregister_device(nvt->rdev);
-
- kfree(nvt);
}
static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index e1cf23c..0ad15d3 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -35,9 +35,6 @@
static int debug;
-#define nvt_pr(level, text, ...) \
- printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
-
#define nvt_dbg(text, ...) \
if (debug) \
printk(KERN_DEBUG \
@@ -64,6 +61,21 @@ static int debug;
#define TX_BUF_LEN 256
#define RX_BUF_LEN 32
+#define SIO_ID_MASK 0xfff0
+
+enum nvt_chip_ver {
+ NVT_UNKNOWN = 0,
+ NVT_W83667HG = 0xa510,
+ NVT_6775F = 0xb470,
+ NVT_6776F = 0xc330,
+ NVT_6779D = 0xc560
+};
+
+struct nvt_chip {
+ const char *name;
+ enum nvt_chip_ver chip_ver;
+};
+
struct nvt_dev {
struct pnp_dev *pdev;
struct rc_dev *rdev;
@@ -93,6 +105,7 @@ struct nvt_dev {
int cir_irq;
int cir_wake_irq;
+ enum nvt_chip_ver chip_ver;
/* hardware id */
u8 chip_major;
u8 chip_minor;
@@ -326,15 +339,6 @@ struct nvt_dev {
#define EFER_EFM_ENABLE 0x87
#define EFER_EFM_DISABLE 0xaa
-/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
-#define CHIP_ID_HIGH_667 0xa5
-#define CHIP_ID_HIGH_677B 0xb4
-#define CHIP_ID_HIGH_677C 0xc3
-#define CHIP_ID_LOW_667 0x13
-#define CHIP_ID_LOW_677B2 0x72
-#define CHIP_ID_LOW_677B3 0x73
-#define CHIP_ID_LOW_677C 0x33
-
/* Config regs we need to care about */
#define CR_SOFTWARE_RESET 0x02
#define CR_LOGICAL_DEV_SEL 0x07
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index b68d4f76..7359f3d 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -167,75 +167,4 @@ void ir_raw_init(void);
* loads the compiled decoders for their usage with IR raw events
*/
-/* from ir-nec-decoder.c */
-#ifdef CONFIG_IR_NEC_DECODER_MODULE
-#define load_nec_decode() request_module_nowait("ir-nec-decoder")
-#else
-static inline void load_nec_decode(void) { }
-#endif
-
-/* from ir-rc5-decoder.c */
-#ifdef CONFIG_IR_RC5_DECODER_MODULE
-#define load_rc5_decode() request_module_nowait("ir-rc5-decoder")
-#else
-static inline void load_rc5_decode(void) { }
-#endif
-
-/* from ir-rc6-decoder.c */
-#ifdef CONFIG_IR_RC6_DECODER_MODULE
-#define load_rc6_decode() request_module_nowait("ir-rc6-decoder")
-#else
-static inline void load_rc6_decode(void) { }
-#endif
-
-/* from ir-jvc-decoder.c */
-#ifdef CONFIG_IR_JVC_DECODER_MODULE
-#define load_jvc_decode() request_module_nowait("ir-jvc-decoder")
-#else
-static inline void load_jvc_decode(void) { }
-#endif
-
-/* from ir-sony-decoder.c */
-#ifdef CONFIG_IR_SONY_DECODER_MODULE
-#define load_sony_decode() request_module_nowait("ir-sony-decoder")
-#else
-static inline void load_sony_decode(void) { }
-#endif
-
-/* from ir-sanyo-decoder.c */
-#ifdef CONFIG_IR_SANYO_DECODER_MODULE
-#define load_sanyo_decode() request_module_nowait("ir-sanyo-decoder")
-#else
-static inline void load_sanyo_decode(void) { }
-#endif
-
-/* from ir-sharp-decoder.c */
-#ifdef CONFIG_IR_SHARP_DECODER_MODULE
-#define load_sharp_decode() request_module_nowait("ir-sharp-decoder")
-#else
-static inline void load_sharp_decode(void) { }
-#endif
-
-/* from ir-mce_kbd-decoder.c */
-#ifdef CONFIG_IR_MCE_KBD_DECODER_MODULE
-#define load_mce_kbd_decode() request_module_nowait("ir-mce_kbd-decoder")
-#else
-static inline void load_mce_kbd_decode(void) { }
-#endif
-
-/* from ir-lirc-codec.c */
-#ifdef CONFIG_IR_LIRC_CODEC_MODULE
-#define load_lirc_codec() request_module_nowait("ir-lirc-codec")
-#else
-static inline void load_lirc_codec(void) { }
-#endif
-
-/* from ir-xmp-decoder.c */
-#ifdef CONFIG_IR_XMP_DECODER_MODULE
-#define load_xmp_decode() request_module_nowait("ir-xmp-decoder")
-#else
-static inline void load_xmp_decode(void) { }
-#endif
-
-
#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index ad26052..c69807f 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -59,7 +59,9 @@ static int ir_raw_event_thread(void *data)
mutex_lock(&ir_raw_handler_lock);
list_for_each_entry(handler, &ir_raw_handler_list, list)
- handler->decode(raw->dev, ev);
+ if (raw->dev->enabled_protocols & handler->protocols ||
+ !handler->protocols)
+ handler->decode(raw->dev, ev);
raw->prev_ev = ev;
mutex_unlock(&ir_raw_handler_lock);
}
@@ -246,6 +248,14 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_type)
return 0;
}
+static void ir_raw_disable_protocols(struct rc_dev *dev, u64 protocols)
+{
+ mutex_lock(&dev->lock);
+ dev->enabled_protocols &= ~protocols;
+ dev->enabled_wakeup_protocols &= ~protocols;
+ mutex_unlock(&dev->lock);
+}
+
/*
* Used to (un)register raw event clients
*/
@@ -337,33 +347,16 @@ EXPORT_SYMBOL(ir_raw_handler_register);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
{
struct ir_raw_event_ctrl *raw;
+ u64 protocols = ir_raw_handler->protocols;
mutex_lock(&ir_raw_handler_lock);
list_del(&ir_raw_handler->list);
- if (ir_raw_handler->raw_unregister)
- list_for_each_entry(raw, &ir_raw_client_list, list)
+ list_for_each_entry(raw, &ir_raw_client_list, list) {
+ ir_raw_disable_protocols(raw->dev, protocols);
+ if (ir_raw_handler->raw_unregister)
ir_raw_handler->raw_unregister(raw->dev);
- available_protocols &= ~ir_raw_handler->protocols;
+ }
+ available_protocols &= ~protocols;
mutex_unlock(&ir_raw_handler_lock);
}
EXPORT_SYMBOL(ir_raw_handler_unregister);
-
-void ir_raw_init(void)
-{
- /* Load the decoder modules */
-
- load_nec_decode();
- load_rc5_decode();
- load_rc6_decode();
- load_jvc_decode();
- load_sony_decode();
- load_sanyo_decode();
- load_sharp_decode();
- load_mce_kbd_decode();
- load_lirc_codec();
- load_xmp_decode();
-
- /* If needed, we may later add some init code. In this case,
- it is needed to change the CONFIG_MODULE test at rc-core.h
- */
-}
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 3f0f71a..1042fa3 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -61,7 +61,7 @@ struct rc_map *rc_map_get(const char *name)
struct rc_map_list *map;
map = seek_rc_map(name);
-#ifdef MODULE
+#ifdef CONFIG_MODULES
if (!map) {
int rc = request_module("%s", name);
if (rc < 0) {
@@ -777,30 +777,31 @@ static struct class rc_class = {
* used by the sysfs protocols file. Note that the order
* of the entries is relevant.
*/
-static struct {
+static const struct {
u64 type;
- char *name;
+ const char *name;
+ const char *module_name;
} proto_names[] = {
- { RC_BIT_NONE, "none" },
- { RC_BIT_OTHER, "other" },
- { RC_BIT_UNKNOWN, "unknown" },
+ { RC_BIT_NONE, "none", NULL },
+ { RC_BIT_OTHER, "other", NULL },
+ { RC_BIT_UNKNOWN, "unknown", NULL },
{ RC_BIT_RC5 |
- RC_BIT_RC5X, "rc-5" },
- { RC_BIT_NEC, "nec" },
+ RC_BIT_RC5X, "rc-5", "ir-rc5-decoder" },
+ { RC_BIT_NEC, "nec", "ir-nec-decoder" },
{ RC_BIT_RC6_0 |
RC_BIT_RC6_6A_20 |
RC_BIT_RC6_6A_24 |
RC_BIT_RC6_6A_32 |
- RC_BIT_RC6_MCE, "rc-6" },
- { RC_BIT_JVC, "jvc" },
+ RC_BIT_RC6_MCE, "rc-6", "ir-rc6-decoder" },
+ { RC_BIT_JVC, "jvc", "ir-jvc-decoder" },
{ RC_BIT_SONY12 |
RC_BIT_SONY15 |
- RC_BIT_SONY20, "sony" },
- { RC_BIT_RC5_SZ, "rc-5-sz" },
- { RC_BIT_SANYO, "sanyo" },
- { RC_BIT_SHARP, "sharp" },
- { RC_BIT_MCE_KBD, "mce_kbd" },
- { RC_BIT_XMP, "xmp" },
+ RC_BIT_SONY20, "sony", "ir-sony-decoder" },
+ { RC_BIT_RC5_SZ, "rc-5-sz", "ir-rc5-decoder" },
+ { RC_BIT_SANYO, "sanyo", "ir-sanyo-decoder" },
+ { RC_BIT_SHARP, "sharp", "ir-sharp-decoder" },
+ { RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" },
+ { RC_BIT_XMP, "xmp", "ir-xmp-decoder" },
};
/**
@@ -979,6 +980,48 @@ static int parse_protocol_change(u64 *protocols, const char *buf)
return count;
}
+static void ir_raw_load_modules(u64 *protocols)
+
+{
+ u64 available;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (proto_names[i].type == RC_BIT_NONE ||
+ proto_names[i].type & (RC_BIT_OTHER | RC_BIT_UNKNOWN))
+ continue;
+
+ available = ir_raw_get_allowed_protocols();
+ if (!(*protocols & proto_names[i].type & ~available))
+ continue;
+
+ if (!proto_names[i].module_name) {
+ pr_err("Can't enable IR protocol %s\n",
+ proto_names[i].name);
+ *protocols &= ~proto_names[i].type;
+ continue;
+ }
+
+ ret = request_module("%s", proto_names[i].module_name);
+ if (ret < 0) {
+ pr_err("Couldn't load IR protocol module %s\n",
+ proto_names[i].module_name);
+ *protocols &= ~proto_names[i].type;
+ continue;
+ }
+ msleep(20);
+ available = ir_raw_get_allowed_protocols();
+ if (!(*protocols & proto_names[i].type & ~available))
+ continue;
+
+ pr_err("Loaded IR protocol module %s, \
+ but protocol %s still not available\n",
+ proto_names[i].module_name,
+ proto_names[i].name);
+ *protocols &= ~proto_names[i].type;
+ }
+}
+
/**
* store_protocols() - changes the current/wakeup IR protocol(s)
* @device: the device descriptor
@@ -1045,6 +1088,9 @@ static ssize_t store_protocols(struct device *device,
goto out;
}
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_load_modules(&new_protocols);
+
if (new_protocols != old_protocols) {
*current_protocols = new_protocols;
IR_dprintk(1, "Protocols changed to 0x%llx\n",
@@ -1420,17 +1466,13 @@ int rc_register_device(struct rc_dev *dev)
dev->input_dev->rep[REP_PERIOD] = 125;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "%s: %s as %s\n",
- dev_name(&dev->dev),
- dev->input_name ? dev->input_name : "Unspecified device",
- path ? path : "N/A");
+ dev_info(&dev->dev, "%s as %s\n",
+ dev->input_name ?: "Unspecified device", path ?: "N/A");
kfree(path);
if (dev->driver_type == RC_DRIVER_IR_RAW) {
- /* Load raw decoders, if they aren't already */
if (!raw_init) {
- IR_dprintk(1, "Loading raw decoders\n");
- ir_raw_init();
+ request_module_nowait("ir-lirc-codec");
raw_init = true;
}
/* calls ir_register_device so unlock mutex here*/
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 37d0401..1fa0c9d 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -16,6 +16,7 @@
#include <linux/reset.h>
#include <media/rc-core.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_wakeirq.h>
struct st_rc_device {
struct device *dev;
@@ -190,6 +191,9 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
static int st_rc_remove(struct platform_device *pdev)
{
struct st_rc_device *rc_dev = platform_get_drvdata(pdev);
+
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
clk_disable_unprepare(rc_dev->sys_clock);
rc_unregister_device(rc_dev->rdev);
return 0;
@@ -298,22 +302,22 @@ static int st_rc_probe(struct platform_device *pdev)
rdev->map_name = RC_MAP_LIRC;
rdev->input_name = "ST Remote Control Receiver";
- /* enable wake via this device */
- device_set_wakeup_capable(dev, true);
- device_set_wakeup_enable(dev, true);
-
ret = rc_register_device(rdev);
if (ret < 0)
goto clkerr;
rc_dev->rdev = rdev;
if (devm_request_irq(dev, rc_dev->irq, st_rc_rx_interrupt,
- IRQF_NO_SUSPEND, IR_ST_NAME, rc_dev) < 0) {
+ 0, IR_ST_NAME, rc_dev) < 0) {
dev_err(dev, "IRQ %d register failed\n", rc_dev->irq);
ret = -EINVAL;
goto rcerr;
}
+ /* enable wake via this device */
+ device_init_wakeup(dev, true);
+ dev_pm_set_wake_irq(dev, rc_dev->irq);
+
/**
* for LIRC_MODE_MODE2 or LIRC_MODE_PULSE or LIRC_MODE_RAW
* lircd expects a long space first before a signal train to sync.
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 5a17cb8..815243c 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -34,6 +34,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/ktime.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
#include <media/rc-core.h>
@@ -96,8 +97,8 @@ struct streamzap_ir {
/* sum of signal lengths received since signal start */
unsigned long sum;
/* start time of signal; necessary for gap tracking */
- struct timeval signal_last;
- struct timeval signal_start;
+ ktime_t signal_last;
+ ktime_t signal_start;
bool timeout_enabled;
char name[128];
@@ -136,20 +137,18 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
DEFINE_IR_RAW_EVENT(rawir);
if (sz->idle) {
- long deltv;
+ int delta;
sz->signal_last = sz->signal_start;
- do_gettimeofday(&sz->signal_start);
+ sz->signal_start = ktime_get_real();
- deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
+ delta = ktime_us_delta(sz->signal_start, sz->signal_last);
rawir.pulse = false;
- if (deltv > 15) {
+ if (delta > (15 * USEC_PER_SEC)) {
/* really long time */
rawir.duration = IR_MAX_DURATION;
} else {
- rawir.duration = (int)(deltv * 1000000 +
- sz->signal_start.tv_usec -
- sz->signal_last.tv_usec);
+ rawir.duration = delta;
rawir.duration -= sz->sum;
rawir.duration = US_TO_NS(rawir.duration);
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
@@ -428,7 +427,7 @@ static int streamzap_probe(struct usb_interface *intf,
sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
#endif
- do_gettimeofday(&sz->signal_start);
+ sz->signal_start = ktime_get_real();
/* Complete final initialisations */
usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 7830aef..40f7768 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -153,6 +153,8 @@ static int sunxi_ir_probe(struct platform_device *pdev)
if (!ir)
return -ENOMEM;
+ spin_lock_init(&ir->ir_lock);
+
if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir"))
ir->fifo_size = 64;
else
diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c
index 95ed46f..353b178 100644
--- a/drivers/media/tuners/max2165.c
+++ b/drivers/media/tuners/max2165.c
@@ -385,7 +385,7 @@ static const struct dvb_tuner_ops max2165_tuner_ops = {
.info = {
.name = "Maxim MAX2165",
.frequency_min = 470000000,
- .frequency_max = 780000000,
+ .frequency_max = 862000000,
.frequency_step = 50000,
},
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index 9e9c5eb..6457ac9 100644
--- a/drivers/media/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
@@ -225,7 +225,6 @@ struct mt2063_state {
const struct mt2063_config *config;
struct dvb_tuner_ops ops;
struct dvb_frontend *frontend;
- struct tuner_state status;
u32 frequency;
u32 srate;
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index ce157ed..0e1ca2b 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -168,6 +168,7 @@ static int si2157_init(struct dvb_frontend *fe)
len = fw->data[fw->size - remaining];
if (len > SI2157_ARGLEN) {
dev_err(&client->dev, "Bad firmware length\n");
+ ret = -EINVAL;
goto err_release_firmware;
}
memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index fcbb497..0d4ac59 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -134,7 +134,7 @@ struct airspy {
int urbs_submitted;
/* USB control message buffer */
- #define BUF_SIZE 24
+ #define BUF_SIZE 128
u8 buf[BUF_SIZE];
/* Current configuration */
@@ -316,7 +316,7 @@ static void airspy_urb_complete(struct urb *urb)
len = airspy_convert_stream(s, ptr, urb->transfer_buffer,
urb->actual_length);
vb2_set_plane_payload(&fbuf->vb.vb2_buf, 0, len);
- v4l2_get_timestamp(&fbuf->vb.timestamp);
+ fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
fbuf->vb.sequence = s->sequence++;
vb2_buffer_done(&fbuf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -488,7 +488,7 @@ static void airspy_disconnect(struct usb_interface *intf)
/* Videobuf2 operations */
static int airspy_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *nbuffers,
+ unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
struct airspy *s = vb2_get_drv_priv(vq);
diff --git a/drivers/media/usb/as102/as102_fw.c b/drivers/media/usb/as102/as102_fw.c
index 07d08c4..5a28ce3 100644
--- a/drivers/media/usb/as102/as102_fw.c
+++ b/drivers/media/usb/as102/as102_fw.c
@@ -198,6 +198,7 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
pr_info("%s: firmware: %s loaded with success\n",
DRIVER_NAME, fw1);
release_firmware(firmware);
+ firmware = NULL;
/* wait for boot to complete */
mdelay(100);
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index 130c8b4..b4efc10 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -30,23 +30,17 @@
/* ------------------------------------------------------------------ */
-static int vbi_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct au0828_dev *dev = vb2_get_drv_priv(vq);
- unsigned long img_size = dev->vbi_width * dev->vbi_height * 2;
- unsigned long size;
-
- size = fmt ? (fmt->fmt.vbi.samples_per_line *
- (fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1])) : img_size;
- if (size < img_size)
- return -EINVAL;
+ unsigned long size = dev->vbi_width * dev->vbi_height * 2;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
-
return 0;
}
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 45c622e..0a725a1 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -314,7 +314,7 @@ static inline void buffer_filled(struct au0828_dev *dev,
vb->sequence = dev->vbi_frame_count++;
vb->field = V4L2_FIELD_INTERLACED;
- v4l2_get_timestamp(&vb->timestamp);
+ vb->vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&vb->vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -638,19 +638,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
return rc;
}
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct au0828_dev *dev = vb2_get_drv_priv(vq);
- unsigned long img_size = dev->height * dev->bytesperline;
- unsigned long size;
-
- size = fmt ? fmt->fmt.pix.sizeimage : img_size;
- if (size < img_size)
- return -EINVAL;
+ unsigned long size = dev->height * dev->bytesperline;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c
index 351a78a..c1aa1ab 100644
--- a/drivers/media/usb/cpia2/cpia2_usb.c
+++ b/drivers/media/usb/cpia2/cpia2_usb.c
@@ -890,8 +890,7 @@ static void cpia2_usb_disconnect(struct usb_interface *intf)
DBG("Wakeup waiting processes\n");
cam->curbuff->status = FRAME_READY;
cam->curbuff->length = 0;
- if (waitqueue_active(&cam->wq_stream))
- wake_up_interruptible(&cam->wq_stream);
+ wake_up_interruptible(&cam->wq_stream);
}
DBG("Releasing interface\n");
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 47a98a2..48643b9 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -37,7 +37,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include <media/tuner.h>
#define CX231xx_FIRM_IMAGE_SIZE 376836
@@ -1492,6 +1492,27 @@ static struct videobuf_queue_ops cx231xx_qops = {
/* ------------------------------------------------------------------ */
+static int vidioc_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *cc)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ bool is_50hz = dev->encodernorm.id & V4L2_STD_625_50;
+
+ if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ cc->bounds.left = 0;
+ cc->bounds.top = 0;
+ cc->bounds.width = dev->ts1.width;
+ cc->bounds.height = dev->ts1.height;
+ cc->defrect = cc->bounds;
+ cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+ cc->pixelaspect.denominator = is_50hz ? 59 : 10;
+
+ return 0;
+}
+
static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
{
struct cx231xx_fh *fh = file->private_data;
@@ -1834,6 +1855,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_g_input = cx231xx_g_input,
.vidioc_s_input = cx231xx_s_input,
.vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_cropcap = vidioc_cropcap,
.vidioc_querycap = cx231xx_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
@@ -1901,7 +1923,7 @@ static int cx231xx_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
return 0;
}
-static struct cx2341x_handler_ops cx231xx_ops = {
+static const struct cx2341x_handler_ops cx231xx_ops = {
/* needed for the video clock freq */
.s_audio_sampling_freq = cx231xx_s_audio_sampling_freq,
/* needed for setting up the video resolution */
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 4a117a5..89dc695 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -30,7 +30,7 @@
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include "dvb-usb-ids.h"
#include "xc5000.h"
#include "tda18271.h"
@@ -352,7 +352,7 @@ struct cx231xx_board cx231xx_boards[] = {
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
.tuner_i2c_master = I2C_1_MUX_1,
- .demod_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_1,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_NTSC,
@@ -713,7 +713,7 @@ struct cx231xx_board cx231xx_boards[] = {
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
.tuner_i2c_master = I2C_1_MUX_3,
- .demod_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_PAL,
@@ -752,7 +752,7 @@ struct cx231xx_board cx231xx_boards[] = {
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
.tuner_i2c_master = I2C_1_MUX_3,
- .demod_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_PAL,
@@ -791,7 +791,7 @@ struct cx231xx_board cx231xx_boards[] = {
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
.tuner_i2c_master = I2C_1_MUX_3,
- .demod_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_NTSC,
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index a2fd49b..f497888 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -914,6 +914,7 @@ EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
*/
void cx231xx_uninit_bulk(struct cx231xx *dev)
{
+ struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
@@ -931,7 +932,7 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
if (dev->video_mode.bulk_ctl.transfer_buffer[i]) {
usb_free_coherent(dev->udev,
urb->transfer_buffer_length,
- dev->video_mode.isoc_ctl.
+ dev->video_mode.bulk_ctl.
transfer_buffer[i],
urb->transfer_dma);
}
@@ -943,10 +944,12 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
kfree(dev->video_mode.bulk_ctl.urb);
kfree(dev->video_mode.bulk_ctl.transfer_buffer);
+ kfree(dma_q->p_left_data);
dev->video_mode.bulk_ctl.urb = NULL;
dev->video_mode.bulk_ctl.transfer_buffer = NULL;
dev->video_mode.bulk_ctl.num_bufs = 0;
+ dma_q->p_left_data = NULL;
if (dev->mode_tv == 0)
cx231xx_capture_start(dev, 0, Raw_Video);
@@ -1196,6 +1199,16 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
sb_size, cx231xx_bulk_irq_callback, dma_q);
}
+ /* clear halt */
+ rc = usb_clear_halt(dev->udev, dev->video_mode.bulk_ctl.urb[0]->pipe);
+ if (rc < 0) {
+ dev_err(dev->dev,
+ "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n",
+ rc);
+ cx231xx_uninit_bulk(dev);
+ return rc;
+ }
+
init_waitqueue_head(&dma_q->wq);
/* submit urbs and enables IRQ */
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 66ee161..e3594b9 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -725,7 +725,7 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(lgdt3305_attach,
&hcw_lgdt3305_config,
- tuner_i2c);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
dev_err(dev->dev,
@@ -746,7 +746,7 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(si2165_attach,
&hauppauge_930C_HD_1113xx_si2165_config,
- tuner_i2c
+ demod_i2c
);
if (dev->dvb->frontend == NULL) {
@@ -779,7 +779,7 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(si2165_attach,
&pctv_quatro_stick_1114xx_si2165_config,
- tuner_i2c
+ demod_i2c
);
if (dev->dvb->frontend == NULL) {
@@ -835,7 +835,7 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(lgdt3306a_attach,
&hauppauge_955q_lgdt3306a_config,
- tuner_i2c
+ demod_i2c
);
if (dev->dvb->frontend == NULL) {
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index a08014d..15bb573 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -32,7 +32,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/tuner.h>
#include "cx231xx-vbi.h"
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index d0d8f08..a70850f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -36,7 +36,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/tuner.h>
#include "dvb_frontend.h"
@@ -1444,6 +1444,7 @@ static int vidioc_cropcap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+ bool is_50hz = dev->norm & V4L2_STD_625_50;
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -1453,8 +1454,8 @@ static int vidioc_cropcap(struct file *file, void *priv,
cc->bounds.width = dev->width;
cc->bounds.height = dev->height;
cc->defrect = cc->bounds;
- cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */
- cc->pixelaspect.denominator = 59;
+ cc->pixelaspect.numerator = is_50hz ? 54 : 11;
+ cc->pixelaspect.denominator = is_50hz ? 59 : 10;
return 0;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 54790fb..ec6d3f5 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -30,14 +30,14 @@
#include <linux/mutex.h>
#include <linux/usb.h>
-#include <media/cx2341x.h>
+#include <media/drv-intf/cx2341x.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/rc-core.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include <media/videobuf-dvb.h>
#include "cx231xx-reg.h"
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 9facc92..3dc8ef0 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -9,7 +9,7 @@ config DVB_USB_V2
<file:Documentation/dvb/README.dvb-usb>.
For a complete list of supported USB devices see the LinuxTV DVB Wiki:
- <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+ <https://linuxtv.org/wiki/index.php/DVB_USB>
Say Y if you own a USB DVB device.
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
index ea37536..84f6de6 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
@@ -35,7 +35,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able)).");
struct mxl111sf_demod_state {
struct mxl111sf_state *mxl_state;
- struct mxl111sf_demod_config *cfg;
+ const struct mxl111sf_demod_config *cfg;
struct dvb_frontend fe;
};
@@ -579,7 +579,7 @@ static struct dvb_frontend_ops mxl111sf_demod_ops = {
};
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
- struct mxl111sf_demod_config *cfg)
+ const struct mxl111sf_demod_config *cfg)
{
struct mxl111sf_demod_state *state = NULL;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 0bd83e5..7065aca 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -35,11 +35,11 @@ struct mxl111sf_demod_config {
#if IS_ENABLED(CONFIG_DVB_USB_MXL111SF)
extern
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
- struct mxl111sf_demod_config *cfg);
+ const struct mxl111sf_demod_config *cfg);
#else
static inline
struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
- struct mxl111sf_demod_config *cfg)
+ const struct mxl111sf_demod_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index bec12b0..1710f90 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -288,9 +288,9 @@ static int mxl111sf_adap_fe_init(struct dvb_frontend *fe)
err = mxl1x1sf_set_device_mode(state, adap_state->device_mode);
mxl_fail(err);
- mxl111sf_enable_usb_output(state);
+ err = mxl111sf_enable_usb_output(state);
mxl_fail(err);
- mxl1x1sf_top_master_ctrl(state, 1);
+ err = mxl1x1sf_top_master_ctrl(state, 1);
mxl_fail(err);
if ((MXL111SF_GPIO_MOD_DVBT != adap_state->gpio_mode) &&
@@ -731,7 +731,7 @@ fail:
return ret;
}
-static struct mxl111sf_demod_config mxl_demod_config = {
+static const struct mxl111sf_demod_config mxl_demod_config = {
.read_reg = mxl111sf_read_reg,
.write_reg = mxl111sf_write_reg,
.program_regs = mxl111sf_ctrl_program_regs,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 5a503a6..eb5787a 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -181,11 +181,17 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
goto err_mutex_unlock;
} else if (msg[0].addr == 0x10) {
/* method 1 - integrated demod */
- req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
- req.index = CMD_DEMOD_RD | dev->page;
- req.size = msg[1].len;
- req.data = &msg[1].buf[0];
- ret = rtl28xxu_ctrl_msg(d, &req);
+ if (msg[0].buf[0] == 0x00) {
+ /* return demod page from driver cache */
+ msg[1].buf[0] = dev->page;
+ ret = 0;
+ } else {
+ req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
+ req.index = CMD_DEMOD_RD | dev->page;
+ req.size = msg[1].len;
+ req.data = &msg[1].buf[0];
+ ret = rtl28xxu_ctrl_msg(d, &req);
+ }
} else if (msg[0].len < 2) {
/* method 2 - old I2C */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 128eee6..f03b0b7 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -9,7 +9,7 @@ config DVB_USB
<file:Documentation/dvb/README.dvb-usb>.
For a complete list of supported USB devices see the LinuxTV DVB Wiki:
- <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+ <https://linuxtv.org/wiki/index.php/DVB_USB>
Say Y if you own a USB DVB device.
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index ed0b3a8..b58acd3 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -21,7 +21,7 @@
#include <linux/i2c.h>
#include <media/soc_camera.h>
-#include <media/mt9v011.h>
+#include <media/i2c/mt9v011.h>
#include <media/v4l2-clk.h>
#include <media/v4l2-common.h>
@@ -322,7 +322,7 @@ int em28xx_detect_sensor(struct em28xx *dev)
int em28xx_init_camera(struct em28xx *dev)
{
- char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ char clk_name[V4L2_CLK_NAME_SIZE];
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
struct em28xx_v4l2 *v4l2 = dev->v4l2;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 3940046..a1b6ef5 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -30,10 +30,10 @@
#include <linux/i2c.h>
#include <linux/usb.h>
#include <media/tuner.h>
-#include <media/msp3400.h>
-#include <media/saa7115.h>
-#include <media/tvp5150.h>
-#include <media/tvaudio.h>
+#include <media/drv-intf/msp3400.h>
+#include <media/i2c/saa7115.h>
+#include <media/i2c/tvp5150.h>
+#include <media/i2c/tvaudio.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -1051,8 +1051,12 @@ struct em28xx_board em28xx_boards[] = {
},
[EM2870_BOARD_TERRATEC_XS_MT2060] = {
.name = "Terratec Cinergy T XS (MT2060)",
- .valid = EM28XX_BOARD_NOT_VALIDATED,
+ .xclk = EM28XX_XCLK_IR_RC5_MODE |
+ EM28XX_XCLK_FREQUENCY_12MHZ,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE,
.tuner_type = TUNER_ABSENT, /* MT2060 */
+ .has_dvb = 1,
+ .tuner_gpio = default_tuner_gpio,
},
[EM2870_BOARD_KWORLD_350U] = {
.name = "Kworld 350 U DVB-T",
@@ -2368,7 +2372,7 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x0ccd, 0x0042),
.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0043),
- .driver_info = EM2870_BOARD_TERRATEC_XS },
+ .driver_info = EM2870_BOARD_TERRATEC_XS_MT2060 },
{ USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */
.driver_info = EM2884_BOARD_TERRATEC_HTC_USB_XS },
{ USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */
@@ -2471,6 +2475,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28178_BOARD_PCTV_461E },
{ USB_DEVICE(0x2013, 0x025f),
.driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x2040, 0x0264), /* Hauppauge WinTV-soloHD */
+ .driver_info = EM28178_BOARD_PCTV_292E },
{ USB_DEVICE(0x0413, 0x6f07),
.driver_info = EM2861_BOARD_LEADTEK_VC100 },
{ USB_DEVICE(0xeb1a, 0x8179),
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 357be76..bf5c244 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -38,6 +38,7 @@
#include "lgdt3305.h"
#include "zl10353.h"
#include "s5h1409.h"
+#include "mt2060.h"
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
@@ -815,6 +816,10 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
.parallel_ts = 1,
};
+static struct mt2060_config em28xx_mt2060_config = {
+ .i2c_address = 0x60,
+};
+
static struct qt1010_config em28xx_qt1010_config = {
.i2c_address = 0x62
};
@@ -1142,6 +1147,16 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
break;
+ case EM2870_BOARD_TERRATEC_XS_MT2060:
+ dvb->fe[0] = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_no_i2c_gate_dev,
+ &dev->i2c_adap[dev->def_i2c_bus]);
+ if (dvb->fe[0] != NULL) {
+ dvb_attach(mt2060_attach, dvb->fe[0],
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &em28xx_mt2060_config, 1220);
+ }
+ break;
case EM2870_BOARD_KWORLD_355U:
dvb->fe[0] = dvb_attach(zl10353_attach,
&em28xx_zl10353_no_i2c_gate_dev,
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index e23c285..fe94c92 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -31,26 +31,22 @@
/* ------------------------------------------------------------------ */
-static int vbi_queue_setup(struct vb2_queue *vq, const void *parg,
+static int vbi_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct em28xx *dev = vb2_get_drv_priv(vq);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- unsigned long size;
+ unsigned long size = v4l2->vbi_width * v4l2->vbi_height * 2;
- if (fmt)
- size = fmt->fmt.pix.sizeimage;
- else
- size = v4l2->vbi_width * v4l2->vbi_height * 2;
-
- if (0 == *nbuffers)
- *nbuffers = 32;
if (*nbuffers < 2)
*nbuffers = 2;
- if (*nbuffers > 32)
- *nbuffers = 32;
+
+ if (*nplanes) {
+ if (sizes[0] < size)
+ return -EINVAL;
+ size = sizes[0];
+ }
*nplanes = 1;
sizes[0] = size;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 6a3cf34..0e86ff4 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -43,7 +43,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
#include <media/v4l2-clk.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/tuner.h>
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
@@ -438,7 +438,7 @@ static inline void finish_buffer(struct em28xx *dev,
buf->vb.field = V4L2_FIELD_NONE;
else
buf->vb.field = V4L2_FIELD_INTERLACED;
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
@@ -871,30 +871,19 @@ static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
Videobuf2 operations
------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct em28xx *dev = vb2_get_drv_priv(vq);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
- unsigned long size;
-
- if (fmt)
- size = fmt->fmt.pix.sizeimage;
- else
- size =
+ unsigned long size =
(v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
- if (size == 0)
- return -EINVAL;
-
- if (0 == *nbuffers)
- *nbuffers = 32;
-
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
sizes[0] = size;
-
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 76bf8ba..8ff066c 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -40,7 +40,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include <media/rc-core.h>
#include "tuner-xc2028.h"
#include "xc5000.h"
diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
index ae1cfa7..05b1126 100644
--- a/drivers/media/usb/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -466,7 +466,7 @@ static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buf
else
go7007_set_motion_regions(go, vb, 0);
- v4l2_get_timestamp(&vb->vb.timestamp);
+ vb->vb.vb2_buf.timestamp = ktime_get_ns();
vb_tmp = vb;
spin_lock(&go->spinlock);
list_del(&vb->list);
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
index 4857c46..3dbf14c 100644
--- a/drivers/media/usb/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -23,9 +23,9 @@
#include <linux/usb.h>
#include <linux/i2c.h>
#include <asm/byteorder.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <media/tuner.h>
-#include <media/uda1342.h>
+#include <media/i2c/uda1342.h>
#include "go7007-priv.h"
@@ -1289,7 +1289,7 @@ static int go7007_usb_probe(struct usb_interface *intf,
/* Allocate the URBs and buffers for receiving the audio stream */
if ((board->flags & GO7007_USB_EZUSB) &&
- (board->flags & GO7007_BOARD_HAS_AUDIO)) {
+ (board->main_info.flags & GO7007_BOARD_HAS_AUDIO)) {
for (i = 0; i < 8; ++i) {
usb->audio_urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
if (usb->audio_urbs[i] == NULL)
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index f3d187d..358c1c1 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -30,7 +30,7 @@
#include <media/v4l2-subdev.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include "go7007-priv.h"
@@ -369,7 +369,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
}
static int go7007_queue_setup(struct vb2_queue *q,
- const void *parg,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index 146071b..bfff1d1 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -1491,8 +1491,13 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev,
struct v4l2_fract *tpf = &cp->timeperframe;
struct sd *sd = (struct sd *) gspca_dev;
- /* Set requested framerate */
- sd->frame_rate = tpf->denominator / tpf->numerator;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ /* Set default framerate */
+ sd->frame_rate = 30;
+ else
+ /* Set requested framerate */
+ sd->frame_rate = tpf->denominator / tpf->numerator;
+
if (gspca_dev->streaming)
set_frame_rate(gspca_dev);
diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c
index c70ff40..c028a5c 100644
--- a/drivers/media/usb/gspca/topro.c
+++ b/drivers/media/usb/gspca/topro.c
@@ -4802,7 +4802,11 @@ static void sd_set_streamparm(struct gspca_dev *gspca_dev,
struct v4l2_fract *tpf = &cp->timeperframe;
int fr, i;
- sd->framerate = tpf->denominator / tpf->numerator;
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ sd->framerate = 30;
+ else
+ sd->framerate = tpf->denominator / tpf->numerator;
+
if (gspca_dev->streaming)
setframerate(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index e05bfec..9e700ca 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -24,6 +24,15 @@
#include <media/videobuf2-v4l2.h>
#include <media/videobuf2-vmalloc.h>
+/*
+ * Used Avago MGA-81563 RF amplifier could be destroyed pretty easily with too
+ * strong signal or transmitting to bad antenna.
+ * Set RF gain control to 'grabbed' state by default for sure.
+ */
+static bool hackrf_enable_rf_gain_ctrl;
+module_param_named(enable_rf_gain_ctrl, hackrf_enable_rf_gain_ctrl, bool, 0644);
+MODULE_PARM_DESC(enable_rf_gain_ctrl, "enable RX/TX RF amplifier control (warn: could damage amplifier)");
+
/* HackRF USB API commands (from HackRF Library) */
enum {
CMD_SET_TRANSCEIVER_MODE = 0x01,
@@ -517,7 +526,7 @@ static void hackrf_urb_complete_in(struct urb *urb)
urb->transfer_buffer, len);
vb2_set_plane_payload(&buffer->vb.vb2_buf, 0, len);
buffer->vb.sequence = dev->sequence++;
- v4l2_get_timestamp(&buffer->vb.timestamp);
+ buffer->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE);
exit_usb_submit_urb:
usb_submit_urb(urb, GFP_ATOMIC);
@@ -562,7 +571,7 @@ static void hackrf_urb_complete_out(struct urb *urb)
vb2_plane_vaddr(&buffer->vb.vb2_buf, 0), len);
urb->actual_length = len;
buffer->vb.sequence = dev->sequence++;
- v4l2_get_timestamp(&buffer->vb.timestamp);
+ buffer->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&buffer->vb.vb2_buf, VB2_BUF_STATE_DONE);
exit_usb_submit_urb:
usb_submit_urb(urb, GFP_ATOMIC);
@@ -750,7 +759,7 @@ static void hackrf_return_all_buffers(struct vb2_queue *vq,
}
static int hackrf_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *nbuffers,
+ unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
struct hackrf_dev *dev = vb2_get_drv_priv(vq);
@@ -1451,6 +1460,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev_err(dev->dev, "Could not initialize controls\n");
goto err_v4l2_ctrl_handler_free_rx;
}
+ v4l2_ctrl_grab(dev->rx_rf_gain, !hackrf_enable_rf_gain_ctrl);
v4l2_ctrl_handler_setup(&dev->rx_ctrl_handler);
/* Register controls for transmitter */
@@ -1471,6 +1481,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev_err(dev->dev, "Could not initialize controls\n");
goto err_v4l2_ctrl_handler_free_tx;
}
+ v4l2_ctrl_grab(dev->tx_rf_gain, !hackrf_enable_rf_gain_ctrl);
v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
/* Register the v4l2_device structure */
@@ -1530,7 +1541,7 @@ err_v4l2_ctrl_handler_free_rx:
err_kfree:
kfree(dev);
err:
- dev_dbg(dev->dev, "failed=%d\n", ret);
+ dev_dbg(&intf->dev, "failed=%d\n", ret);
return ret;
}
diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c
index d8d8c0f..7dee22d 100644
--- a/drivers/media/usb/hdpvr/hdpvr-video.c
+++ b/drivers/media/usb/hdpvr/hdpvr-video.c
@@ -642,7 +642,7 @@ static int vidioc_s_dv_timings(struct file *file, void *_fh,
if (dev->status != STATUS_IDLE)
return -EBUSY;
for (i = 0; i < ARRAY_SIZE(hdpvr_dv_timings); i++)
- if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0))
+ if (v4l2_match_dv_timings(timings, hdpvr_dv_timings + i, 0, false))
break;
if (i == ARRAY_SIZE(hdpvr_dv_timings))
return -EINVAL;
diff --git a/drivers/media/usb/hdpvr/hdpvr.h b/drivers/media/usb/hdpvr/hdpvr.h
index a319430..78e8154 100644
--- a/drivers/media/usb/hdpvr/hdpvr.h
+++ b/drivers/media/usb/hdpvr/hdpvr.h
@@ -17,7 +17,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#define HDPVR_MAX 8
#define HDPVR_I2C_MAX_SIZE 128
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index e06a21a..c104315 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -616,7 +616,6 @@ static int msi2500_querycap(struct file *file, void *fh,
/* Videobuf2 operations */
static int msi2500_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[],
void *alloc_ctxs[])
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
index 45276c6..5f953d8 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
@@ -23,7 +23,7 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
#include <linux/videodev2.h>
-#include <media/msp3400.h>
+#include <media/drv-intf/msp3400.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
index 1a81aa7..7d675fa 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -32,7 +32,7 @@
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
-#include <media/cx25840.h>
+#include <media/drv-intf/cx25840.h>
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/errno.h>
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
index 1f9c028..60141b1 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
@@ -39,8 +39,8 @@
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
#include <media/v4l2-device.h>
-#include <media/cx2341x.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/drv-intf/cx2341x.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include "pvrusb2-devattr.h"
/* Legal values for PVR2_CID_HSM */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index 4baa9d6..14321d0 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
-#include <media/ir-kbd-i2c.h>
+#include <media/i2c/ir-kbd-i2c.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 1c5f85b..81f788b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -628,6 +628,7 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv,
struct pvr2_v4l2_fh *fh = file->private_data;
struct pvr2_hdw *hdw = fh->channel.mc_head->hdw;
struct v4l2_ext_control *ctrl;
+ struct pvr2_ctrl *cptr;
unsigned int idx;
int val;
int ret;
@@ -635,8 +636,15 @@ static int pvr2_g_ext_ctrls(struct file *file, void *priv,
ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
- ret = pvr2_ctrl_get_value(
- pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id), &val);
+ cptr = pvr2_hdw_get_ctrl_v4l(hdw, ctrl->id);
+ if (cptr) {
+ if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
+ pvr2_ctrl_get_def(cptr, &val);
+ else
+ ret = pvr2_ctrl_get_value(cptr, &val);
+ } else
+ ret = -EINVAL;
+
if (ret) {
ctls->error_idx = idx;
return ret;
@@ -658,6 +666,10 @@ static int pvr2_s_ext_ctrls(struct file *file, void *priv,
unsigned int idx;
int ret;
+ /* Default value cannot be changed */
+ if (ctls->which == V4L2_CTRL_WHICH_DEF_VAL)
+ return -EINVAL;
+
ret = 0;
for (idx = 0; idx < ctls->count; idx++) {
ctrl = ctls->controls + idx;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
index 139b397..105123a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
@@ -35,7 +35,7 @@
#include "pvrusb2-debug.h"
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <linux/errno.h>
struct routing_scheme {
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index b79c36f..086cf1c 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -316,8 +316,7 @@ static void pwc_isoc_handler(struct urb *urb)
struct pwc_frame_buf *fbuf = pdev->fill_buf;
if (pdev->vsync == 1) {
- v4l2_get_timestamp(
- &fbuf->vb.timestamp);
+ fbuf->vb.vb2_buf.timestamp = ktime_get_ns();
pdev->vsync = 2;
}
@@ -571,7 +570,7 @@ static void pwc_video_release(struct v4l2_device *v)
/***************************************************************************/
/* Videobuf2 operations */
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index e7acb12..9acdaa3 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -574,7 +574,7 @@ static void s2255_got_frame(struct s2255_vc *vc, int jpgsize)
buf = list_entry(vc->buf_list.next,
struct s2255_buffer, list);
list_del(&buf->list);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.field = vc->field;
buf->vb.sequence = vc->frame_count;
spin_unlock_irqrestore(&vc->qlock, flags);
@@ -660,7 +660,7 @@ static void s2255_fillbuff(struct s2255_vc *vc,
Videobuf operations
------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c
index 1b6836f..bc02947 100644
--- a/drivers/media/usb/stk1160/stk1160-core.c
+++ b/drivers/media/usb/stk1160/stk1160-core.c
@@ -34,7 +34,7 @@
#include <linux/usb.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include "stk1160.h"
#include "stk1160-reg.h"
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 0bd34f1..77131fd 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -33,7 +33,7 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include "stk1160.h"
#include "stk1160-reg.h"
@@ -664,7 +664,7 @@ static const struct v4l2_ioctl_ops stk1160_ioctl_ops = {
/*
* Videobuf2 operations
*/
-static int queue_setup(struct vb2_queue *vq, const void *parg,
+static int queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c
index 75654e6..46191d5 100644
--- a/drivers/media/usb/stk1160/stk1160-video.c
+++ b/drivers/media/usb/stk1160/stk1160-video.c
@@ -99,7 +99,7 @@ void stk1160_buffer_done(struct stk1160 *dev)
buf->vb.sequence = dev->sequence++;
buf->vb.field = V4L2_FIELD_INTERLACED;
buf->vb.vb2_buf.planes[0].bytesused = buf->bytesused;
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->bytesused);
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 2e8c3af..8902ee3 100644
--- a/drivers/media/usb/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -26,7 +26,7 @@
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
-#include <media/tvaudio.h>
+#include <media/i2c/tvaudio.h>
#include <media/i2c-addr.h>
#include <media/rc-map.h>
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index a5de46f..4e36e24 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -1606,7 +1606,7 @@ static int fe_send_command(struct dvb_frontend* fe, const u8 command,
return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result);
}
-static struct ttusbdecfe_config fe_config = {
+static const struct ttusbdecfe_config fe_config = {
.send_command = fe_send_command
};
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index e645c9d..4ebb339 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -322,7 +322,7 @@ static void usbtv_image_chunk(struct usbtv *usbtv, __be32 *chunk)
buf->vb.field = V4L2_FIELD_INTERLACED;
buf->vb.sequence = usbtv->sequence++;
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
vb2_buffer_done(&buf->vb.vb2_buf, state);
list_del(&buf->list);
@@ -599,19 +599,18 @@ static struct v4l2_file_operations usbtv_fops = {
};
static int usbtv_queue_setup(struct vb2_queue *vq,
- const void *parg, unsigned int *nbuffers,
+ unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct usbtv *usbtv = vb2_get_drv_priv(vq);
unsigned size = USBTV_CHUNK * usbtv->n_chunks * 2 * sizeof(u32);
if (vq->num_buffers + *nbuffers < 2)
*nbuffers = 2 - vq->num_buffers;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
- if (fmt && fmt->fmt.pix.sizeimage < size)
- return -EINVAL;
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
+ sizes[0] = size;
return 0;
}
diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c
index dc3b4d5..1ea04e7 100644
--- a/drivers/media/usb/usbvision/usbvision-core.c
+++ b/drivers/media/usb/usbvision/usbvision-core.c
@@ -37,7 +37,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index b693206..de9ff3b 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -59,7 +59,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
-#include <media/saa7115.h>
+#include <media/i2c/saa7115.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h>
@@ -1461,11 +1461,32 @@ static int usbvision_probe(struct usb_interface *intf,
printk(KERN_INFO "%s: %s found\n", __func__,
usbvision_device_data[model].model_string);
+ /*
+ * this is a security check.
+ * an exploit using an incorrect bInterfaceNumber is known
+ */
+ if (ifnum >= USB_MAXINTERFACES || !dev->actconfig->interface[ifnum])
+ return -ENODEV;
+
if (usbvision_device_data[model].interface >= 0)
interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
- else
+ else if (ifnum < dev->actconfig->desc.bNumInterfaces)
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
+ else {
+ dev_err(&intf->dev, "interface %d is invalid, max is %d\n",
+ ifnum, dev->actconfig->desc.bNumInterfaces - 1);
+ ret = -ENODEV;
+ goto err_usb;
+ }
+
+ if (interface->desc.bNumEndpoints < 2) {
+ dev_err(&intf->dev, "interface %d has %d endpoints, but must"
+ " have minimum 2\n", ifnum, interface->desc.bNumEndpoints);
+ ret = -ENODEV;
+ goto err_usb;
+ }
endpoint = &interface->endpoint[1].desc;
+
if (!usb_endpoint_xfer_isoc(endpoint)) {
dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
__func__, ifnum);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 3e59b28..c2ee6e3 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -227,7 +227,8 @@ static struct uvc_control_info uvc_ctrls[] = {
.size = 4,
.flags = UVC_CTRL_FLAG_SET_CUR
| UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
+ | UVC_CTRL_FLAG_RESTORE
+ | UVC_CTRL_FLAG_AUTO_UPDATE,
},
{
.entity = UVC_GUID_UVC_CAMERA,
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index d11fd6a..39abbaf 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -2540,7 +2540,8 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_FORCE_Y8 },
/* Generic USB Video Class */
- { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
+ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
+ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
{}
};
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index cfb868a..5439472 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -69,23 +69,19 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
* videobuf2 queue operations
*/
-static int uvc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int uvc_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- const struct v4l2_format *fmt = parg;
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
struct uvc_streaming *stream = uvc_queue_to_stream(queue);
+ unsigned size = stream->ctrl.dwMaxVideoFrameSize;
/* Make sure the image size is large enough. */
- if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize)
- return -EINVAL;
-
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
*nplanes = 1;
-
- sizes[0] = fmt ? fmt->fmt.pix.sizeimage
- : stream->ctrl.dwMaxVideoFrameSize;
-
+ sizes[0] = size;
return 0;
}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 2764f43..d7723ce 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -983,6 +983,22 @@ static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
unsigned int i;
int ret;
+ if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL) {
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ struct v4l2_queryctrl qc = { .id = ctrl->id };
+
+ ret = uvc_query_v4l2_ctrl(chain, &qc);
+ if (ret < 0) {
+ ctrls->error_idx = i;
+ return ret;
+ }
+
+ ctrl->value = qc.default_value;
+ }
+
+ return 0;
+ }
+
ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
@@ -1010,6 +1026,10 @@ static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
unsigned int i;
int ret;
+ /* Default value cannot be changed */
+ if (ctrls->which == V4L2_CTRL_WHICH_DEF_VAL)
+ return -EINVAL;
+
ret = uvc_ctrl_begin(chain);
if (ret < 0)
return ret;
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 2b276ab..075a0fe 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -694,22 +694,19 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
ts.tv_nsec -= NSEC_PER_SEC;
}
- uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu "
- "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+ uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %llu "
+ "buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
stream->dev->name,
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
- y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
- vbuf->timestamp.tv_sec,
- (unsigned long)vbuf->timestamp.tv_usec,
+ y, timespec_to_ns(&ts), vbuf->vb2_buf.timestamp,
x1, first->host_sof, first->dev_sof,
x2, last->host_sof, last->dev_sof, y1, y2);
/* Update the V4L2 buffer. */
- vbuf->timestamp.tv_sec = ts.tv_sec;
- vbuf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ vbuf->vb2_buf.timestamp = timespec_to_ns(&ts);
done:
- spin_unlock_irqrestore(&stream->clock.lock, flags);
+ spin_unlock_irqrestore(&clock->lock, flags);
}
/* ------------------------------------------------------------------------
@@ -1034,9 +1031,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = stream->sequence;
- buf->buf.timestamp.tv_sec = ts.tv_sec;
- buf->buf.timestamp.tv_usec =
- ts.tv_nsec / NSEC_PER_USEC;
+ buf->buf.vb2_buf.timestamp = timespec_to_ns(&ts);
/* TODO: Handle PTS and SCR. */
buf->state = UVC_BUF_STATE_ACTIVE;
diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c
index 34e416a..297e10e 100644
--- a/drivers/media/v4l2-core/v4l2-clk.c
+++ b/drivers/media/v4l2-core/v4l2-clk.c
@@ -15,6 +15,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <linux/string.h>
@@ -39,6 +40,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
{
struct v4l2_clk *clk;
struct clk *ccf_clk = clk_get(dev, id);
+ char clk_name[V4L2_CLK_NAME_SIZE];
if (PTR_ERR(ccf_clk) == -EPROBE_DEFER)
return ERR_PTR(-EPROBE_DEFER);
@@ -57,6 +59,13 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id)
mutex_lock(&clk_lock);
clk = v4l2_clk_find(dev_name(dev));
+ /* if dev_name is not found, try use the OF name to find again */
+ if (PTR_ERR(clk) == -ENODEV && dev->of_node) {
+ v4l2_clk_name_of(clk_name, sizeof(clk_name),
+ of_node_full_name(dev->of_node));
+ clk = v4l2_clk_find(clk_name);
+ }
+
if (!IS_ERR(clk))
atomic_inc(&clk->use_count);
mutex_unlock(&clk_lock);
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 327e83a..8fd84a6 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -630,7 +630,7 @@ static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __
}
struct v4l2_ext_controls32 {
- __u32 ctrl_class;
+ __u32 which;
__u32 count;
__u32 error_idx;
__u32 reserved[2];
@@ -673,7 +673,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
compat_caddr_t p;
if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
- get_user(kp->ctrl_class, &up->ctrl_class) ||
+ get_user(kp->which, &up->which) ||
get_user(kp->count, &up->count) ||
get_user(kp->error_idx, &up->error_idx) ||
copy_from_user(kp->reserved, up->reserved,
@@ -723,7 +723,7 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
compat_caddr_t p;
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
- put_user(kp->ctrl_class, &up->ctrl_class) ||
+ put_user(kp->which, &up->which) ||
put_user(kp->count, &up->count) ||
put_user(kp->error_idx, &up->error_idx) ||
copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 4a1d9fd..c9d5537 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1491,6 +1491,17 @@ static int new_to_user(struct v4l2_ext_control *c,
return ptr_to_user(c, ctrl, ctrl->p_new);
}
+/* Helper function: copy the initial control value back to the caller */
+static int def_to_user(struct v4l2_ext_control *c, struct v4l2_ctrl *ctrl)
+{
+ int idx;
+
+ for (idx = 0; idx < ctrl->elems; idx++)
+ ctrl->type_ops->init(ctrl, idx, ctrl->p_new);
+
+ return ptr_to_user(c, ctrl, ctrl->p_new);
+}
+
/* Helper function: copy the caller-provider value to the given control value */
static int user_to_ptr(struct v4l2_ext_control *c,
struct v4l2_ctrl *ctrl,
@@ -1762,7 +1773,7 @@ static struct v4l2_ctrl_ref *find_private_ref(
list_for_each_entry(ref, &hdl->ctrl_refs, node) {
/* Search for private user controls that are compatible with
VIDIOC_G/S_CTRL. */
- if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+ if (V4L2_CTRL_ID2WHICH(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
if (!ref->ctrl->is_int)
continue;
@@ -1831,7 +1842,7 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
struct v4l2_ctrl_ref *ref;
struct v4l2_ctrl_ref *new_ref;
u32 id = ctrl->id;
- u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1;
+ u32 class_ctrl = V4L2_CTRL_ID2WHICH(id) | 1;
int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
/*
@@ -2253,9 +2264,9 @@ EXPORT_SYMBOL(v4l2_ctrl_add_handler);
bool v4l2_ctrl_radio_filter(const struct v4l2_ctrl *ctrl)
{
- if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
+ if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_TX)
return true;
- if (V4L2_CTRL_ID2CLASS(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
+ if (V4L2_CTRL_ID2WHICH(ctrl->id) == V4L2_CTRL_CLASS_FM_RX)
return true;
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
@@ -2710,7 +2721,9 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
cs->error_idx = i;
- if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+ if (cs->which &&
+ cs->which != V4L2_CTRL_WHICH_DEF_VAL &&
+ V4L2_CTRL_ID2WHICH(id) != cs->which)
return -EINVAL;
/* Old-style private controls are not allowed for
@@ -2787,11 +2800,11 @@ static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
/* Handles the corner case where cs->count == 0. It checks whether the
specified control class exists. If that class ID is 0, then it checks
whether there are any controls at all. */
-static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 which)
{
- if (ctrl_class == 0)
+ if (which == 0 || which == V4L2_CTRL_WHICH_DEF_VAL)
return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0;
- return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL;
+ return find_ref_lock(hdl, which | 1) ? 0 : -EINVAL;
}
@@ -2803,15 +2816,18 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
struct v4l2_ctrl_helper *helpers = helper;
int ret;
int i, j;
+ bool def_value;
+
+ def_value = (cs->which == V4L2_CTRL_WHICH_DEF_VAL);
cs->error_idx = cs->count;
- cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+ cs->which = V4L2_CTRL_ID2WHICH(cs->which);
if (hdl == NULL)
return -EINVAL;
if (cs->count == 0)
- return class_check(hdl, cs->ctrl_class);
+ return class_check(hdl, cs->which);
if (cs->count > ARRAY_SIZE(helper)) {
helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -2829,9 +2845,11 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
for (i = 0; !ret && i < cs->count; i++) {
int (*ctrl_to_user)(struct v4l2_ext_control *c,
- struct v4l2_ctrl *ctrl) = cur_to_user;
+ struct v4l2_ctrl *ctrl);
struct v4l2_ctrl *master;
+ ctrl_to_user = def_value ? def_to_user : cur_to_user;
+
if (helpers[i].mref == NULL)
continue;
@@ -2841,8 +2859,9 @@ int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs
v4l2_ctrl_lock(master);
/* g_volatile_ctrl will update the new control values */
- if ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
- (master->has_volatiles && !is_cur_manual(master))) {
+ if (!def_value &&
+ ((master->flags & V4L2_CTRL_FLAG_VOLATILE) ||
+ (master->has_volatiles && !is_cur_manual(master)))) {
for (j = 0; j < master->ncontrols; j++)
cur_to_new(master->cluster[j]);
ret = call_op(master, g_volatile_ctrl);
@@ -3064,13 +3083,18 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
int ret;
cs->error_idx = cs->count;
- cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+ /* Default value cannot be changed */
+ if (cs->which == V4L2_CTRL_WHICH_DEF_VAL)
+ return -EINVAL;
+
+ cs->which = V4L2_CTRL_ID2WHICH(cs->which);
if (hdl == NULL)
return -EINVAL;
if (cs->count == 0)
- return class_check(hdl, cs->ctrl_class);
+ return class_check(hdl, cs->which);
if (cs->count > ARRAY_SIZE(helper)) {
helpers = kmalloc_array(cs->count, sizeof(helper[0]),
@@ -3300,7 +3324,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
s64 min, s64 max, u64 step, s64 def)
{
- bool changed;
+ bool value_changed;
+ bool range_changed = false;
int ret;
lockdep_assert_held(ctrl->handler->lock);
@@ -3324,10 +3349,14 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
default:
return -EINVAL;
}
- ctrl->minimum = min;
- ctrl->maximum = max;
- ctrl->step = step;
- ctrl->default_value = def;
+ if ((ctrl->minimum != min) || (ctrl->maximum != max) ||
+ (ctrl->step != step) || ctrl->default_value != def) {
+ range_changed = true;
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->default_value = def;
+ }
cur_to_new(ctrl);
if (validate_new(ctrl, ctrl->p_new)) {
if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
@@ -3337,12 +3366,12 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
}
if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
- changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
+ value_changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
else
- changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
- if (changed)
+ value_changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
+ if (value_changed)
ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
- else
+ else if (range_changed)
send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
return ret;
}
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 5b0a30b..7129e43 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -118,11 +118,20 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
- /* We need to unregister the i2c client explicitly.
- We cannot rely on i2c_del_adapter to always
- unregister clients for us, since if the i2c bus
- is a platform bus, then it is never deleted. */
- if (client)
+ /*
+ * We need to unregister the i2c client
+ * explicitly. We cannot rely on
+ * i2c_del_adapter to always unregister
+ * clients for us, since if the i2c bus is a
+ * platform bus, then it is never deleted.
+ *
+ * Device tree or ACPI based devices must not
+ * be unregistered as they have not been
+ * registered by us, and would not be
+ * re-created by just probing the V4L2 driver.
+ */
+ if (client &&
+ !client->dev.of_node && !client->dev.fwnode)
i2c_unregister_device(client);
continue;
}
@@ -131,7 +140,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
if (sd->flags & V4L2_SUBDEV_FL_IS_SPI) {
struct spi_device *spi = v4l2_get_subdevdata(sd);
- if (spi)
+ if (spi && !spi->dev.of_node && !spi->dev.fwnode)
spi_unregister_device(spi);
continue;
}
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index 6a83d61..ec258b7 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -209,8 +209,13 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t,
if (v4l2_valid_dv_timings(v4l2_dv_timings_presets + i, cap,
fnc, fnc_handle) &&
v4l2_match_dv_timings(t, v4l2_dv_timings_presets + i,
- pclock_delta)) {
+ pclock_delta, false)) {
+ u32 flags = t->bt.flags & V4L2_DV_FL_REDUCED_FPS;
+
*t = v4l2_dv_timings_presets[i];
+ if (can_reduce_fps(&t->bt))
+ t->bt.flags |= flags;
+
return true;
}
}
@@ -223,12 +228,14 @@ EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap);
* @t1 - compare this v4l2_dv_timings struct...
* @t2 - with this struct.
* @pclock_delta - the allowed pixelclock deviation.
+ * @match_reduced_fps - if true, then fail if V4L2_DV_FL_REDUCED_FPS does not
+ * match.
*
* Compare t1 with t2 with a given margin of error for the pixelclock.
*/
bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1,
const struct v4l2_dv_timings *t2,
- unsigned pclock_delta)
+ unsigned pclock_delta, bool match_reduced_fps)
{
if (t1->type != t2->type || t1->type != V4L2_DV_BT_656_1120)
return false;
@@ -239,9 +246,14 @@ bool v4l2_match_dv_timings(const struct v4l2_dv_timings *t1,
t1->bt.pixelclock >= t2->bt.pixelclock - pclock_delta &&
t1->bt.pixelclock <= t2->bt.pixelclock + pclock_delta &&
t1->bt.hfrontporch == t2->bt.hfrontporch &&
+ t1->bt.hsync == t2->bt.hsync &&
+ t1->bt.hbackporch == t2->bt.hbackporch &&
t1->bt.vfrontporch == t2->bt.vfrontporch &&
t1->bt.vsync == t2->bt.vsync &&
t1->bt.vbackporch == t2->bt.vbackporch &&
+ (!match_reduced_fps ||
+ (t1->bt.flags & V4L2_DV_FL_REDUCED_FPS) ==
+ (t2->bt.flags & V4L2_DV_FL_REDUCED_FPS)) &&
(!t1->bt.interlaced ||
(t1->bt.il_vfrontporch == t2->bt.il_vfrontporch &&
t1->bt.il_vsync == t2->bt.il_vsync &&
diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c
index 5bdfb8d..5d67335 100644
--- a/drivers/media/v4l2-core/v4l2-flash-led-class.c
+++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c
@@ -107,10 +107,10 @@ static void v4l2_flash_set_led_brightness(struct v4l2_flash *v4l2_flash,
if (ctrls[LED_MODE]->val != V4L2_FLASH_LED_MODE_TORCH)
return;
- led_set_brightness(&v4l2_flash->fled_cdev->led_cdev,
+ led_set_brightness_sync(&v4l2_flash->fled_cdev->led_cdev,
brightness);
} else {
- led_set_brightness(&v4l2_flash->iled_cdev->led_cdev,
+ led_set_brightness_sync(&v4l2_flash->iled_cdev->led_cdev,
brightness);
}
}
@@ -206,11 +206,11 @@ static int v4l2_flash_s_ctrl(struct v4l2_ctrl *c)
case V4L2_CID_FLASH_LED_MODE:
switch (c->val) {
case V4L2_FLASH_LED_MODE_NONE:
- led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_sync(led_cdev, LED_OFF);
return led_set_flash_strobe(fled_cdev, false);
case V4L2_FLASH_LED_MODE_FLASH:
/* Turn the torch LED off */
- led_set_brightness(led_cdev, LED_OFF);
+ led_set_brightness_sync(led_cdev, LED_OFF);
if (ctrls[STROBE_SOURCE]) {
external_strobe = (ctrls[STROBE_SOURCE]->val ==
V4L2_FLASH_STROBE_SOURCE_EXTERNAL);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 7486af2..8a018c6 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -565,8 +565,8 @@ static void v4l_print_ext_controls(const void *arg, bool write_only)
const struct v4l2_ext_controls *p = arg;
int i;
- pr_cont("class=0x%x, count=%d, error_idx=%d",
- p->ctrl_class, p->count, p->error_idx);
+ pr_cont("which=0x%x, count=%d, error_idx=%d",
+ p->which, p->count, p->error_idx);
for (i = 0; i < p->count; i++) {
if (!p->controls[i].size)
pr_cont(", id/val=0x%x/0x%x",
@@ -902,13 +902,13 @@ static int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv)
Only when passed in through VIDIOC_G_CTRL and VIDIOC_S_CTRL
is it allowed for backwards compatibility.
*/
- if (!allow_priv && c->ctrl_class == V4L2_CID_PRIVATE_BASE)
+ if (!allow_priv && c->which == V4L2_CID_PRIVATE_BASE)
return 0;
- if (c->ctrl_class == 0)
+ if (!c->which)
return 1;
/* Check that all controls are from the same control class. */
for (i = 0; i < c->count; i++) {
- if (V4L2_CTRL_ID2CLASS(c->controls[i].id) != c->ctrl_class) {
+ if (V4L2_CTRL_ID2WHICH(c->controls[i].id) != c->which) {
c->error_idx = i;
return 0;
}
@@ -1969,7 +1969,7 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
if (ops->vidioc_g_ext_ctrls == NULL)
return -ENOTTY;
- ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+ ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
ctrls.count = 1;
ctrls.controls = &ctrl;
ctrl.id = p->id;
@@ -2003,7 +2003,7 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
if (ops->vidioc_s_ext_ctrls == NULL)
return -ENOTTY;
- ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id);
+ ctrls.which = V4L2_CTRL_ID2WHICH(p->id);
ctrls.count = 1;
ctrls.controls = &ctrl;
ctrl.id = p->id;
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 33bdd81..c5d49d7 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -28,11 +28,161 @@
#include <trace/events/vb2.h>
-#include "videobuf2-internal.h"
+static int debug;
+module_param(debug, int, 0644);
-int vb2_debug;
-EXPORT_SYMBOL_GPL(vb2_debug);
-module_param_named(debug, vb2_debug, int, 0644);
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (debug >= level) \
+ pr_info("vb2-core: %s: " fmt, __func__, ## arg); \
+ } while (0)
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+
+/*
+ * If advanced debugging is on, then count how often each op is called
+ * successfully, which can either be per-buffer or per-queue.
+ *
+ * This makes it easy to check that the 'init' and 'cleanup'
+ * (and variations thereof) stay balanced.
+ */
+
+#define log_memop(vb, op) \
+ dprintk(2, "call_memop(%p, %d, %s)%s\n", \
+ (vb)->vb2_queue, (vb)->index, #op, \
+ (vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
+
+#define call_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ int err; \
+ \
+ log_memop(vb, op); \
+ err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
+ if (!err) \
+ (vb)->cnt_mem_ ## op++; \
+ err; \
+})
+
+#define call_ptr_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ void *ptr; \
+ \
+ log_memop(vb, op); \
+ ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
+ if (!IS_ERR_OR_NULL(ptr)) \
+ (vb)->cnt_mem_ ## op++; \
+ ptr; \
+})
+
+#define call_void_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ \
+ log_memop(vb, op); \
+ if (_q->mem_ops->op) \
+ _q->mem_ops->op(args); \
+ (vb)->cnt_mem_ ## op++; \
+})
+
+#define log_qop(q, op) \
+ dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
+ (q)->ops->op ? "" : " (nop)")
+
+#define call_qop(q, op, args...) \
+({ \
+ int err; \
+ \
+ log_qop(q, op); \
+ err = (q)->ops->op ? (q)->ops->op(args) : 0; \
+ if (!err) \
+ (q)->cnt_ ## op++; \
+ err; \
+})
+
+#define call_void_qop(q, op, args...) \
+({ \
+ log_qop(q, op); \
+ if ((q)->ops->op) \
+ (q)->ops->op(args); \
+ (q)->cnt_ ## op++; \
+})
+
+#define log_vb_qop(vb, op, args...) \
+ dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
+ (vb)->vb2_queue, (vb)->index, #op, \
+ (vb)->vb2_queue->ops->op ? "" : " (nop)")
+
+#define call_vb_qop(vb, op, args...) \
+({ \
+ int err; \
+ \
+ log_vb_qop(vb, op); \
+ err = (vb)->vb2_queue->ops->op ? \
+ (vb)->vb2_queue->ops->op(args) : 0; \
+ if (!err) \
+ (vb)->cnt_ ## op++; \
+ err; \
+})
+
+#define call_void_vb_qop(vb, op, args...) \
+({ \
+ log_vb_qop(vb, op); \
+ if ((vb)->vb2_queue->ops->op) \
+ (vb)->vb2_queue->ops->op(args); \
+ (vb)->cnt_ ## op++; \
+})
+
+#else
+
+#define call_memop(vb, op, args...) \
+ ((vb)->vb2_queue->mem_ops->op ? \
+ (vb)->vb2_queue->mem_ops->op(args) : 0)
+
+#define call_ptr_memop(vb, op, args...) \
+ ((vb)->vb2_queue->mem_ops->op ? \
+ (vb)->vb2_queue->mem_ops->op(args) : NULL)
+
+#define call_void_memop(vb, op, args...) \
+ do { \
+ if ((vb)->vb2_queue->mem_ops->op) \
+ (vb)->vb2_queue->mem_ops->op(args); \
+ } while (0)
+
+#define call_qop(q, op, args...) \
+ ((q)->ops->op ? (q)->ops->op(args) : 0)
+
+#define call_void_qop(q, op, args...) \
+ do { \
+ if ((q)->ops->op) \
+ (q)->ops->op(args); \
+ } while (0)
+
+#define call_vb_qop(vb, op, args...) \
+ ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
+
+#define call_void_vb_qop(vb, op, args...) \
+ do { \
+ if ((vb)->vb2_queue->ops->op) \
+ (vb)->vb2_queue->ops->op(args); \
+ } while (0)
+
+#endif
+
+#define call_bufop(q, op, args...) \
+({ \
+ int ret = 0; \
+ if (q && q->buf_ops && q->buf_ops->op) \
+ ret = q->buf_ops->op(args); \
+ ret; \
+})
+
+#define call_void_bufop(q, op, args...) \
+({ \
+ if (q && q->buf_ops && q->buf_ops->op) \
+ q->buf_ops->op(args); \
+})
static void __vb2_queue_cancel(struct vb2_queue *q);
static void __enqueue_in_driver(struct vb2_buffer *vb);
@@ -53,7 +203,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
* NOTE: mmapped areas should be page aligned
*/
for (plane = 0; plane < vb->num_planes; ++plane) {
- unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
+ unsigned long size = PAGE_ALIGN(vb->planes[plane].length);
mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
size, dma_dir, q->gfp_flags);
@@ -62,7 +212,6 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
/* Associate allocator private data with this plane */
vb->planes[plane].mem_priv = mem_priv;
- vb->planes[plane].length = q->plane_sizes[plane];
}
return 0;
@@ -137,57 +286,30 @@ static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb)
}
/**
- * __setup_lengths() - setup initial lengths for every plane in
- * every buffer on the queue
- */
-static void __setup_lengths(struct vb2_queue *q, unsigned int n)
-{
- unsigned int buffer, plane;
- struct vb2_buffer *vb;
-
- for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
- vb = q->bufs[buffer];
- if (!vb)
- continue;
-
- for (plane = 0; plane < vb->num_planes; ++plane)
- vb->planes[plane].length = q->plane_sizes[plane];
- }
-}
-
-/**
* __setup_offsets() - setup unique offsets ("cookies") for every plane in
- * every buffer on the queue
+ * the buffer.
*/
-static void __setup_offsets(struct vb2_queue *q, unsigned int n)
+static void __setup_offsets(struct vb2_buffer *vb)
{
- unsigned int buffer, plane;
- struct vb2_buffer *vb;
- unsigned long off;
+ struct vb2_queue *q = vb->vb2_queue;
+ unsigned int plane;
+ unsigned long off = 0;
+
+ if (vb->index) {
+ struct vb2_buffer *prev = q->bufs[vb->index - 1];
+ struct vb2_plane *p = &prev->planes[prev->num_planes - 1];
- if (q->num_buffers) {
- struct vb2_plane *p;
- vb = q->bufs[q->num_buffers - 1];
- p = &vb->planes[vb->num_planes - 1];
off = PAGE_ALIGN(p->m.offset + p->length);
- } else {
- off = 0;
}
- for (buffer = q->num_buffers; buffer < q->num_buffers + n; ++buffer) {
- vb = q->bufs[buffer];
- if (!vb)
- continue;
-
- for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->planes[plane].m.offset = off;
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ vb->planes[plane].m.offset = off;
- dprintk(3, "buffer %d, plane %d offset 0x%08lx\n",
- buffer, plane, off);
+ dprintk(3, "buffer %d, plane %d offset 0x%08lx\n",
+ vb->index, plane, off);
- off += vb->planes[plane].length;
- off = PAGE_ALIGN(off);
- }
+ off += vb->planes[plane].length;
+ off = PAGE_ALIGN(off);
}
}
@@ -199,9 +321,10 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n)
* Returns the number of buffers successfully allocated.
*/
static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
- unsigned int num_buffers, unsigned int num_planes)
+ unsigned int num_buffers, unsigned int num_planes,
+ const unsigned plane_sizes[VB2_MAX_PLANES])
{
- unsigned int buffer;
+ unsigned int buffer, plane;
struct vb2_buffer *vb;
int ret;
@@ -219,6 +342,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
vb->index = q->num_buffers + buffer;
vb->type = q->type;
vb->memory = memory;
+ for (plane = 0; plane < num_planes; ++plane) {
+ vb->planes[plane].length = plane_sizes[plane];
+ vb->planes[plane].min_length = plane_sizes[plane];
+ }
+ q->bufs[vb->index] = vb;
/* Allocate video buffer memory for the MMAP type */
if (memory == VB2_MEMORY_MMAP) {
@@ -226,9 +354,11 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
if (ret) {
dprintk(1, "failed allocating memory for "
"buffer %d\n", buffer);
+ q->bufs[vb->index] = NULL;
kfree(vb);
break;
}
+ __setup_offsets(vb);
/*
* Call the driver-provided buffer initialization
* callback, if given. An error in initialization
@@ -239,18 +369,13 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
dprintk(1, "buffer %d %p initialization"
" failed\n", buffer, vb);
__vb2_buf_mem_free(vb);
+ q->bufs[vb->index] = NULL;
kfree(vb);
break;
}
}
-
- q->bufs[q->num_buffers + buffer] = vb;
}
- __setup_lengths(q, buffer);
- if (memory == VB2_MEMORY_MMAP)
- __setup_offsets(q, buffer);
-
dprintk(1, "allocated %d buffers, %d plane(s) each\n",
buffer, num_planes);
@@ -330,7 +455,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
bool unbalanced = q->cnt_start_streaming != q->cnt_stop_streaming ||
q->cnt_wait_prepare != q->cnt_wait_finish;
- if (unbalanced || vb2_debug) {
+ if (unbalanced || debug) {
pr_info("vb2: counters for queue %p:%s\n", q,
unbalanced ? " UNBALANCED!" : "");
pr_info("vb2: setup: %u start_streaming: %u stop_streaming: %u\n",
@@ -356,7 +481,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
vb->cnt_buf_prepare != vb->cnt_buf_finish ||
vb->cnt_buf_init != vb->cnt_buf_cleanup;
- if (unbalanced || vb2_debug) {
+ if (unbalanced || debug) {
pr_info("vb2: counters for queue %p, buffer %d:%s\n",
q, buffer, unbalanced ? " UNBALANCED!" : "");
pr_info("vb2: buf_init: %u buf_cleanup: %u buf_prepare: %u buf_finish: %u\n",
@@ -442,13 +567,10 @@ static bool __buffers_in_use(struct vb2_queue *q)
* Should be called from vidioc_querybuf ioctl handler in driver.
* The passed buffer should have been verified.
* This function fills the relevant information for the userspace.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_querybuf handler in driver.
*/
-int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
+void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb)
{
- return call_bufop(q, fill_user_buffer, q->bufs[index], pb);
+ call_void_bufop(q, fill_user_buffer, q->bufs[index], pb);
}
EXPORT_SYMBOL_GPL(vb2_core_querybuf);
@@ -570,6 +692,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int *count)
{
unsigned int num_buffers, allocated_buffers, num_planes = 0;
+ unsigned plane_sizes[VB2_MAX_PLANES] = { };
int ret;
if (q->streaming) {
@@ -613,7 +736,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
*/
num_buffers = min_t(unsigned int, *count, VB2_MAX_FRAME);
num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
- memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
q->memory = memory;
@@ -621,14 +743,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
* Ask the driver how many buffers and planes per buffer it requires.
* Driver also sets the size and allocator context for each plane.
*/
- ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
- q->plane_sizes, q->alloc_ctx);
+ ret = call_qop(q, queue_setup, q, &num_buffers, &num_planes,
+ plane_sizes, q->alloc_ctx);
if (ret)
return ret;
/* Finally, allocate buffers and video memory */
allocated_buffers =
- __vb2_queue_alloc(q, memory, num_buffers, num_planes);
+ __vb2_queue_alloc(q, memory, num_buffers, num_planes, plane_sizes);
if (allocated_buffers == 0) {
dprintk(1, "memory allocation failed\n");
return -ENOMEM;
@@ -646,9 +768,16 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
*/
if (!ret && allocated_buffers < num_buffers) {
num_buffers = allocated_buffers;
+ /*
+ * num_planes is set by the previous queue_setup(), but since it
+ * signals to queue_setup() whether it is called from create_bufs()
+ * vs reqbufs() we zero it here to signal that queue_setup() is
+ * called for the reqbufs() case.
+ */
+ num_planes = 0;
- ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
+ ret = call_qop(q, queue_setup, q, &num_buffers,
+ &num_planes, plane_sizes, q->alloc_ctx);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -701,9 +830,11 @@ EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
* from vidioc_create_bufs handler in driver.
*/
int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
- unsigned int *count, const void *parg)
+ unsigned int *count, unsigned requested_planes,
+ const unsigned requested_sizes[])
{
unsigned int num_planes = 0, num_buffers, allocated_buffers;
+ unsigned plane_sizes[VB2_MAX_PLANES] = { };
int ret;
if (q->num_buffers == VB2_MAX_FRAME) {
@@ -712,7 +843,6 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
}
if (!q->num_buffers) {
- memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
q->memory = memory;
q->waiting_for_buffers = !q->is_output;
@@ -720,18 +850,23 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
+ if (requested_planes && requested_sizes) {
+ num_planes = requested_planes;
+ memcpy(plane_sizes, requested_sizes, sizeof(plane_sizes));
+ }
+
/*
* Ask the driver, whether the requested number of buffers, planes per
* buffer and their sizes are acceptable
*/
- ret = call_qop(q, queue_setup, q, parg, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
+ ret = call_qop(q, queue_setup, q, &num_buffers,
+ &num_planes, plane_sizes, q->alloc_ctx);
if (ret)
return ret;
/* Finally, allocate buffers and video memory */
allocated_buffers = __vb2_queue_alloc(q, memory, num_buffers,
- num_planes);
+ num_planes, plane_sizes);
if (allocated_buffers == 0) {
dprintk(1, "memory allocation failed\n");
return -ENOMEM;
@@ -747,8 +882,8 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
* q->num_buffers contains the total number of buffers, that the
* queue driver has set up
*/
- ret = call_qop(q, queue_setup, q, parg, &num_buffers,
- &num_planes, q->plane_sizes, q->alloc_ctx);
+ ret = call_qop(q, queue_setup, q, &num_buffers,
+ &num_planes, plane_sizes, q->alloc_ctx);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -964,11 +1099,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb)
"reacquiring memory\n", plane);
/* Check if the provided plane buffer is large enough */
- if (planes[plane].length < q->plane_sizes[plane]) {
+ if (planes[plane].length < vb->planes[plane].min_length) {
dprintk(1, "provided buffer size %u is less than "
"setup size %u for plane %d\n",
planes[plane].length,
- q->plane_sizes[plane], plane);
+ vb->planes[plane].min_length,
+ plane);
ret = -EINVAL;
goto err;
}
@@ -1081,7 +1217,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb)
if (planes[plane].length == 0)
planes[plane].length = dbuf->size;
- if (planes[plane].length < q->plane_sizes[plane]) {
+ if (planes[plane].length < vb->planes[plane].min_length) {
dprintk(1, "invalid dmabuf length for plane %d\n",
plane);
ret = -EINVAL;
@@ -1263,9 +1399,7 @@ int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb)
return ret;
/* Fill buffer information for the userspace */
- ret = call_bufop(q, fill_user_buffer, vb, pb);
- if (ret)
- return ret;
+ call_void_bufop(q, fill_user_buffer, vb, pb);
dprintk(1, "prepare of buffer %d succeeded\n", vb->index);
@@ -1386,7 +1520,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
q->waiting_for_buffers = false;
vb->state = VB2_BUF_STATE_QUEUED;
- call_bufop(q, set_timestamp, vb, pb);
+ call_void_bufop(q, copy_timestamp, vb, pb);
trace_vb2_qbuf(q, vb);
@@ -1398,9 +1532,7 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb)
__enqueue_in_driver(vb);
/* Fill buffer information for the userspace */
- ret = call_bufop(q, fill_user_buffer, vb, pb);
- if (ret)
- return ret;
+ call_void_bufop(q, fill_user_buffer, vb, pb);
/*
* If streamon has been called, and we haven't yet called
@@ -1623,9 +1755,7 @@ int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking)
call_void_vb_qop(vb, buf_finish, vb);
/* Fill buffer information for the userspace */
- ret = call_bufop(q, fill_user_buffer, vb, pb);
- if (ret)
- return ret;
+ call_void_bufop(q, fill_user_buffer, vb, pb);
/* Remove from videobuf queue */
list_del(&vb->queued_entry);
@@ -2073,6 +2203,8 @@ int vb2_core_queue_init(struct vb2_queue *q)
}
EXPORT_SYMBOL_GPL(vb2_core_queue_init);
+static int __vb2_init_fileio(struct vb2_queue *q, int read);
+static int __vb2_cleanup_fileio(struct vb2_queue *q);
/**
* vb2_core_queue_release() - stop streaming, release the queue and free memory
* @q: videobuf2 queue
@@ -2083,6 +2215,7 @@ EXPORT_SYMBOL_GPL(vb2_core_queue_init);
*/
void vb2_core_queue_release(struct vb2_queue *q)
{
+ __vb2_cleanup_fileio(q);
__vb2_queue_cancel(q);
mutex_lock(&q->mmap_lock);
__vb2_queue_free(q, q->num_buffers);
@@ -2090,6 +2223,619 @@ void vb2_core_queue_release(struct vb2_queue *q)
}
EXPORT_SYMBOL_GPL(vb2_core_queue_release);
-MODULE_DESCRIPTION("Driver helper framework for Video for Linux 2");
+/**
+ * vb2_core_poll() - implements poll userspace operation
+ * @q: videobuf2 queue
+ * @file: file argument passed to the poll file operation handler
+ * @wait: wait argument passed to the poll file operation handler
+ *
+ * This function implements poll file operation handler for a driver.
+ * For CAPTURE queues, if a buffer is ready to be dequeued, the userspace will
+ * be informed that the file descriptor of a video device is available for
+ * reading.
+ * For OUTPUT queues, if a buffer is ready to be dequeued, the file descriptor
+ * will be reported as available for writing.
+ *
+ * The return values from this function are intended to be directly returned
+ * from poll handler in driver.
+ */
+unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
+ poll_table *wait)
+{
+ unsigned long req_events = poll_requested_events(wait);
+ struct vb2_buffer *vb = NULL;
+ unsigned long flags;
+
+ if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
+ return 0;
+ if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
+ return 0;
+
+ /*
+ * Start file I/O emulator only if streaming API has not been used yet.
+ */
+ if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
+ if (!q->is_output && (q->io_modes & VB2_READ) &&
+ (req_events & (POLLIN | POLLRDNORM))) {
+ if (__vb2_init_fileio(q, 1))
+ return POLLERR;
+ }
+ if (q->is_output && (q->io_modes & VB2_WRITE) &&
+ (req_events & (POLLOUT | POLLWRNORM))) {
+ if (__vb2_init_fileio(q, 0))
+ return POLLERR;
+ /*
+ * Write to OUTPUT queue can be done immediately.
+ */
+ return POLLOUT | POLLWRNORM;
+ }
+ }
+
+ /*
+ * There is nothing to wait for if the queue isn't streaming, or if the
+ * error flag is set.
+ */
+ if (!vb2_is_streaming(q) || q->error)
+ return POLLERR;
+
+ /*
+ * For output streams you can call write() as long as there are fewer
+ * buffers queued than there are buffers available.
+ */
+ if (q->is_output && q->fileio && q->queued_count < q->num_buffers)
+ return POLLOUT | POLLWRNORM;
+
+ if (list_empty(&q->done_list)) {
+ /*
+ * If the last buffer was dequeued from a capture queue,
+ * return immediately. DQBUF will return -EPIPE.
+ */
+ if (q->last_buffer_dequeued)
+ return POLLIN | POLLRDNORM;
+
+ poll_wait(file, &q->done_wq, wait);
+ }
+
+ /*
+ * Take first buffer available for dequeuing.
+ */
+ spin_lock_irqsave(&q->done_lock, flags);
+ if (!list_empty(&q->done_list))
+ vb = list_first_entry(&q->done_list, struct vb2_buffer,
+ done_entry);
+ spin_unlock_irqrestore(&q->done_lock, flags);
+
+ if (vb && (vb->state == VB2_BUF_STATE_DONE
+ || vb->state == VB2_BUF_STATE_ERROR)) {
+ return (q->is_output) ?
+ POLLOUT | POLLWRNORM :
+ POLLIN | POLLRDNORM;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(vb2_core_poll);
+
+/**
+ * struct vb2_fileio_buf - buffer context used by file io emulator
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. This structure is used for
+ * tracking context related to the buffers.
+ */
+struct vb2_fileio_buf {
+ void *vaddr;
+ unsigned int size;
+ unsigned int pos;
+ unsigned int queued:1;
+};
+
+/**
+ * struct vb2_fileio_data - queue context used by file io emulator
+ *
+ * @cur_index: the index of the buffer currently being read from or
+ * written to. If equal to q->num_buffers then a new buffer
+ * must be dequeued.
+ * @initial_index: in the read() case all buffers are queued up immediately
+ * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
+ * buffers. However, in the write() case no buffers are initially
+ * queued, instead whenever a buffer is full it is queued up by
+ * __vb2_perform_fileio(). Only once all available buffers have
+ * been queued up will __vb2_perform_fileio() start to dequeue
+ * buffers. This means that initially __vb2_perform_fileio()
+ * needs to know what buffer index to use when it is queuing up
+ * the buffers for the first time. That initial index is stored
+ * in this field. Once it is equal to q->num_buffers all
+ * available buffers have been queued and __vb2_perform_fileio()
+ * should start the normal dequeue/queue cycle.
+ *
+ * vb2 provides a compatibility layer and emulator of file io (read and
+ * write) calls on top of streaming API. For proper operation it required
+ * this structure to save the driver state between each call of the read
+ * or write function.
+ */
+struct vb2_fileio_data {
+ unsigned int count;
+ unsigned int type;
+ unsigned int memory;
+ struct vb2_buffer *b;
+ struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
+ unsigned int cur_index;
+ unsigned int initial_index;
+ unsigned int q_count;
+ unsigned int dq_count;
+ unsigned read_once:1;
+ unsigned write_immediately:1;
+};
+
+/**
+ * __vb2_init_fileio() - initialize file io emulator
+ * @q: videobuf2 queue
+ * @read: mode selector (1 means read, 0 means write)
+ */
+static int __vb2_init_fileio(struct vb2_queue *q, int read)
+{
+ struct vb2_fileio_data *fileio;
+ int i, ret;
+ unsigned int count = 0;
+
+ /*
+ * Sanity check
+ */
+ if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
+ (!read && !(q->io_modes & VB2_WRITE))))
+ return -EINVAL;
+
+ /*
+ * Check if device supports mapping buffers to kernel virtual space.
+ */
+ if (!q->mem_ops->vaddr)
+ return -EBUSY;
+
+ /*
+ * Check if streaming api has not been already activated.
+ */
+ if (q->streaming || q->num_buffers > 0)
+ return -EBUSY;
+
+ /*
+ * Start with count 1, driver can increase it in queue_setup()
+ */
+ count = 1;
+
+ dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
+ (read) ? "read" : "write", count, q->fileio_read_once,
+ q->fileio_write_immediately);
+
+ fileio = kzalloc(sizeof(*fileio), GFP_KERNEL);
+ if (fileio == NULL)
+ return -ENOMEM;
+
+ fileio->b = kzalloc(q->buf_struct_size, GFP_KERNEL);
+ if (fileio->b == NULL) {
+ kfree(fileio);
+ return -ENOMEM;
+ }
+
+ fileio->read_once = q->fileio_read_once;
+ fileio->write_immediately = q->fileio_write_immediately;
+
+ /*
+ * Request buffers and use MMAP type to force driver
+ * to allocate buffers by itself.
+ */
+ fileio->count = count;
+ fileio->memory = VB2_MEMORY_MMAP;
+ fileio->type = q->type;
+ q->fileio = fileio;
+ ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+ if (ret)
+ goto err_kfree;
+
+ /*
+ * Check if plane_count is correct
+ * (multiplane buffers are not supported).
+ */
+ if (q->bufs[0]->num_planes != 1) {
+ ret = -EBUSY;
+ goto err_reqbufs;
+ }
+
+ /*
+ * Get kernel address of each buffer.
+ */
+ for (i = 0; i < q->num_buffers; i++) {
+ fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
+ if (fileio->bufs[i].vaddr == NULL) {
+ ret = -EINVAL;
+ goto err_reqbufs;
+ }
+ fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
+ }
+
+ /*
+ * Read mode requires pre queuing of all buffers.
+ */
+ if (read) {
+ /*
+ * Queue all buffers.
+ */
+ for (i = 0; i < q->num_buffers; i++) {
+ struct vb2_buffer *b = fileio->b;
+
+ memset(b, 0, q->buf_struct_size);
+ b->type = q->type;
+ b->memory = q->memory;
+ b->index = i;
+ ret = vb2_core_qbuf(q, i, b);
+ if (ret)
+ goto err_reqbufs;
+ fileio->bufs[i].queued = 1;
+ }
+ /*
+ * All buffers have been queued, so mark that by setting
+ * initial_index to q->num_buffers
+ */
+ fileio->initial_index = q->num_buffers;
+ fileio->cur_index = q->num_buffers;
+ }
+
+ /*
+ * Start streaming.
+ */
+ ret = vb2_core_streamon(q, q->type);
+ if (ret)
+ goto err_reqbufs;
+
+ return ret;
+
+err_reqbufs:
+ fileio->count = 0;
+ vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+
+err_kfree:
+ q->fileio = NULL;
+ kfree(fileio);
+ return ret;
+}
+
+/**
+ * __vb2_cleanup_fileio() - free resourced used by file io emulator
+ * @q: videobuf2 queue
+ */
+static int __vb2_cleanup_fileio(struct vb2_queue *q)
+{
+ struct vb2_fileio_data *fileio = q->fileio;
+
+ if (fileio) {
+ vb2_core_streamoff(q, q->type);
+ q->fileio = NULL;
+ fileio->count = 0;
+ vb2_core_reqbufs(q, fileio->memory, &fileio->count);
+ kfree(fileio->b);
+ kfree(fileio);
+ dprintk(3, "file io emulator closed\n");
+ }
+ return 0;
+}
+
+/**
+ * __vb2_perform_fileio() - perform a single file io (read or write) operation
+ * @q: videobuf2 queue
+ * @data: pointed to target userspace buffer
+ * @count: number of bytes to read or write
+ * @ppos: file handle position tracking pointer
+ * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
+ * @read: access mode selector (1 means read, 0 means write)
+ */
+static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblock, int read)
+{
+ struct vb2_fileio_data *fileio;
+ struct vb2_fileio_buf *buf;
+ bool is_multiplanar = q->is_multiplanar;
+ /*
+ * When using write() to write data to an output video node the vb2 core
+ * should copy timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
+ * else is able to provide this information with the write() operation.
+ */
+ bool copy_timestamp = !read && q->copy_timestamp;
+ int ret, index;
+
+ dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
+ read ? "read" : "write", (long)*ppos, count,
+ nonblock ? "non" : "");
+
+ if (!data)
+ return -EINVAL;
+
+ /*
+ * Initialize emulator on first call.
+ */
+ if (!vb2_fileio_is_active(q)) {
+ ret = __vb2_init_fileio(q, read);
+ dprintk(3, "vb2_init_fileio result: %d\n", ret);
+ if (ret)
+ return ret;
+ }
+ fileio = q->fileio;
+
+ /*
+ * Check if we need to dequeue the buffer.
+ */
+ index = fileio->cur_index;
+ if (index >= q->num_buffers) {
+ struct vb2_buffer *b = fileio->b;
+
+ /*
+ * Call vb2_dqbuf to get buffer back.
+ */
+ memset(b, 0, q->buf_struct_size);
+ b->type = q->type;
+ b->memory = q->memory;
+ ret = vb2_core_dqbuf(q, b, nonblock);
+ dprintk(5, "vb2_dqbuf result: %d\n", ret);
+ if (ret)
+ return ret;
+ fileio->dq_count += 1;
+
+ fileio->cur_index = index = b->index;
+ buf = &fileio->bufs[index];
+
+ /*
+ * Get number of bytes filled by the driver
+ */
+ buf->pos = 0;
+ buf->queued = 0;
+ buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
+ : vb2_plane_size(q->bufs[index], 0);
+ /* Compensate for data_offset on read in the multiplanar case. */
+ if (is_multiplanar && read &&
+ b->planes[0].data_offset < buf->size) {
+ buf->pos = b->planes[0].data_offset;
+ buf->size -= buf->pos;
+ }
+ } else {
+ buf = &fileio->bufs[index];
+ }
+
+ /*
+ * Limit count on last few bytes of the buffer.
+ */
+ if (buf->pos + count > buf->size) {
+ count = buf->size - buf->pos;
+ dprintk(5, "reducing read count: %zd\n", count);
+ }
+
+ /*
+ * Transfer data to userspace.
+ */
+ dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
+ count, index, buf->pos);
+ if (read)
+ ret = copy_to_user(data, buf->vaddr + buf->pos, count);
+ else
+ ret = copy_from_user(buf->vaddr + buf->pos, data, count);
+ if (ret) {
+ dprintk(3, "error copying data\n");
+ return -EFAULT;
+ }
+
+ /*
+ * Update counters.
+ */
+ buf->pos += count;
+ *ppos += count;
+
+ /*
+ * Queue next buffer if required.
+ */
+ if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
+ struct vb2_buffer *b = fileio->b;
+
+ /*
+ * Check if this is the last buffer to read.
+ */
+ if (read && fileio->read_once && fileio->dq_count == 1) {
+ dprintk(3, "read limit reached\n");
+ return __vb2_cleanup_fileio(q);
+ }
+
+ /*
+ * Call vb2_qbuf and give buffer to the driver.
+ */
+ memset(b, 0, q->buf_struct_size);
+ b->type = q->type;
+ b->memory = q->memory;
+ b->index = index;
+ b->planes[0].bytesused = buf->pos;
+
+ if (copy_timestamp)
+ b->timestamp = ktime_get_ns();
+ ret = vb2_core_qbuf(q, index, b);
+ dprintk(5, "vb2_dbuf result: %d\n", ret);
+ if (ret)
+ return ret;
+
+ /*
+ * Buffer has been queued, update the status
+ */
+ buf->pos = 0;
+ buf->queued = 1;
+ buf->size = vb2_plane_size(q->bufs[index], 0);
+ fileio->q_count += 1;
+ /*
+ * If we are queuing up buffers for the first time, then
+ * increase initial_index by one.
+ */
+ if (fileio->initial_index < q->num_buffers)
+ fileio->initial_index++;
+ /*
+ * The next buffer to use is either a buffer that's going to be
+ * queued for the first time (initial_index < q->num_buffers)
+ * or it is equal to q->num_buffers, meaning that the next
+ * time we need to dequeue a buffer since we've now queued up
+ * all the 'first time' buffers.
+ */
+ fileio->cur_index = fileio->initial_index;
+ }
+
+ /*
+ * Return proper number of bytes processed.
+ */
+ if (ret == 0)
+ ret = count;
+ return ret;
+}
+
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblocking)
+{
+ return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
+}
+EXPORT_SYMBOL_GPL(vb2_read);
+
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+ loff_t *ppos, int nonblocking)
+{
+ return __vb2_perform_fileio(q, (char __user *) data, count,
+ ppos, nonblocking, 0);
+}
+EXPORT_SYMBOL_GPL(vb2_write);
+
+struct vb2_threadio_data {
+ struct task_struct *thread;
+ vb2_thread_fnc fnc;
+ void *priv;
+ bool stop;
+};
+
+static int vb2_thread(void *data)
+{
+ struct vb2_queue *q = data;
+ struct vb2_threadio_data *threadio = q->threadio;
+ struct vb2_fileio_data *fileio = q->fileio;
+ bool copy_timestamp = false;
+ int prequeue = 0;
+ int index = 0;
+ int ret = 0;
+
+ if (q->is_output) {
+ prequeue = q->num_buffers;
+ copy_timestamp = q->copy_timestamp;
+ }
+
+ set_freezable();
+
+ for (;;) {
+ struct vb2_buffer *vb;
+ struct vb2_buffer *b = fileio->b;
+
+ /*
+ * Call vb2_dqbuf to get buffer back.
+ */
+ memset(b, 0, q->buf_struct_size);
+ b->type = q->type;
+ b->memory = q->memory;
+ if (prequeue) {
+ b->index = index++;
+ prequeue--;
+ } else {
+ call_void_qop(q, wait_finish, q);
+ if (!threadio->stop)
+ ret = vb2_core_dqbuf(q, b, 0);
+ call_void_qop(q, wait_prepare, q);
+ dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+ }
+ if (ret || threadio->stop)
+ break;
+ try_to_freeze();
+
+ vb = q->bufs[b->index];
+ if (b->state == VB2_BUF_STATE_DONE)
+ if (threadio->fnc(vb, threadio->priv))
+ break;
+ call_void_qop(q, wait_finish, q);
+ if (copy_timestamp)
+ b->timestamp = ktime_get_ns();;
+ if (!threadio->stop)
+ ret = vb2_core_qbuf(q, b->index, b);
+ call_void_qop(q, wait_prepare, q);
+ if (ret || threadio->stop)
+ break;
+ }
+
+ /* Hmm, linux becomes *very* unhappy without this ... */
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ return 0;
+}
+
+/*
+ * This function should not be used for anything else but the videobuf2-dvb
+ * support. If you think you have another good use-case for this, then please
+ * contact the linux-media mailinglist first.
+ */
+int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
+ const char *thread_name)
+{
+ struct vb2_threadio_data *threadio;
+ int ret = 0;
+
+ if (q->threadio)
+ return -EBUSY;
+ if (vb2_is_busy(q))
+ return -EBUSY;
+ if (WARN_ON(q->fileio))
+ return -EBUSY;
+
+ threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
+ if (threadio == NULL)
+ return -ENOMEM;
+ threadio->fnc = fnc;
+ threadio->priv = priv;
+
+ ret = __vb2_init_fileio(q, !q->is_output);
+ dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+ if (ret)
+ goto nomem;
+ q->threadio = threadio;
+ threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
+ if (IS_ERR(threadio->thread)) {
+ ret = PTR_ERR(threadio->thread);
+ threadio->thread = NULL;
+ goto nothread;
+ }
+ return 0;
+
+nothread:
+ __vb2_cleanup_fileio(q);
+nomem:
+ kfree(threadio);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_start);
+
+int vb2_thread_stop(struct vb2_queue *q)
+{
+ struct vb2_threadio_data *threadio = q->threadio;
+ int err;
+
+ if (threadio == NULL)
+ return 0;
+ threadio->stop = true;
+ /* Wake up all pending sleeps in the thread */
+ vb2_queue_error(q);
+ err = kthread_stop(threadio->thread);
+ __vb2_cleanup_fileio(q);
+ threadio->thread = NULL;
+ kfree(threadio);
+ q->threadio = NULL;
+ return err;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_stop);
+
+MODULE_DESCRIPTION("Media buffer core framework");
MODULE_AUTHOR("Pawel Osciak <pawel@osciak.com>, Marek Szyprowski");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/videobuf2-internal.h b/drivers/media/v4l2-core/videobuf2-internal.h
deleted file mode 100644
index 79018c7..0000000
--- a/drivers/media/v4l2-core/videobuf2-internal.h
+++ /dev/null
@@ -1,161 +0,0 @@
-#ifndef _MEDIA_VIDEOBUF2_INTERNAL_H
-#define _MEDIA_VIDEOBUF2_INTERNAL_H
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <media/videobuf2-core.h>
-
-extern int vb2_debug;
-
-#define dprintk(level, fmt, arg...) \
- do { \
- if (vb2_debug >= level) \
- pr_info("vb2: %s: " fmt, __func__, ## arg); \
- } while (0)
-
-#ifdef CONFIG_VIDEO_ADV_DEBUG
-
-/*
- * If advanced debugging is on, then count how often each op is called
- * successfully, which can either be per-buffer or per-queue.
- *
- * This makes it easy to check that the 'init' and 'cleanup'
- * (and variations thereof) stay balanced.
- */
-
-#define log_memop(vb, op) \
- dprintk(2, "call_memop(%p, %d, %s)%s\n", \
- (vb)->vb2_queue, (vb)->index, #op, \
- (vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
-
-#define call_memop(vb, op, args...) \
-({ \
- struct vb2_queue *_q = (vb)->vb2_queue; \
- int err; \
- \
- log_memop(vb, op); \
- err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
- if (!err) \
- (vb)->cnt_mem_ ## op++; \
- err; \
-})
-
-#define call_ptr_memop(vb, op, args...) \
-({ \
- struct vb2_queue *_q = (vb)->vb2_queue; \
- void *ptr; \
- \
- log_memop(vb, op); \
- ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
- if (!IS_ERR_OR_NULL(ptr)) \
- (vb)->cnt_mem_ ## op++; \
- ptr; \
-})
-
-#define call_void_memop(vb, op, args...) \
-({ \
- struct vb2_queue *_q = (vb)->vb2_queue; \
- \
- log_memop(vb, op); \
- if (_q->mem_ops->op) \
- _q->mem_ops->op(args); \
- (vb)->cnt_mem_ ## op++; \
-})
-
-#define log_qop(q, op) \
- dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
- (q)->ops->op ? "" : " (nop)")
-
-#define call_qop(q, op, args...) \
-({ \
- int err; \
- \
- log_qop(q, op); \
- err = (q)->ops->op ? (q)->ops->op(args) : 0; \
- if (!err) \
- (q)->cnt_ ## op++; \
- err; \
-})
-
-#define call_void_qop(q, op, args...) \
-({ \
- log_qop(q, op); \
- if ((q)->ops->op) \
- (q)->ops->op(args); \
- (q)->cnt_ ## op++; \
-})
-
-#define log_vb_qop(vb, op, args...) \
- dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
- (vb)->vb2_queue, (vb)->index, #op, \
- (vb)->vb2_queue->ops->op ? "" : " (nop)")
-
-#define call_vb_qop(vb, op, args...) \
-({ \
- int err; \
- \
- log_vb_qop(vb, op); \
- err = (vb)->vb2_queue->ops->op ? \
- (vb)->vb2_queue->ops->op(args) : 0; \
- if (!err) \
- (vb)->cnt_ ## op++; \
- err; \
-})
-
-#define call_void_vb_qop(vb, op, args...) \
-({ \
- log_vb_qop(vb, op); \
- if ((vb)->vb2_queue->ops->op) \
- (vb)->vb2_queue->ops->op(args); \
- (vb)->cnt_ ## op++; \
-})
-
-#else
-
-#define call_memop(vb, op, args...) \
- ((vb)->vb2_queue->mem_ops->op ? \
- (vb)->vb2_queue->mem_ops->op(args) : 0)
-
-#define call_ptr_memop(vb, op, args...) \
- ((vb)->vb2_queue->mem_ops->op ? \
- (vb)->vb2_queue->mem_ops->op(args) : NULL)
-
-#define call_void_memop(vb, op, args...) \
- do { \
- if ((vb)->vb2_queue->mem_ops->op) \
- (vb)->vb2_queue->mem_ops->op(args); \
- } while (0)
-
-#define call_qop(q, op, args...) \
- ((q)->ops->op ? (q)->ops->op(args) : 0)
-
-#define call_void_qop(q, op, args...) \
- do { \
- if ((q)->ops->op) \
- (q)->ops->op(args); \
- } while (0)
-
-#define call_vb_qop(vb, op, args...) \
- ((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
-
-#define call_void_vb_qop(vb, op, args...) \
- do { \
- if ((vb)->vb2_queue->ops->op) \
- (vb)->vb2_queue->ops->op(args); \
- } while (0)
-
-#endif
-
-#define call_bufop(q, op, args...) \
-({ \
- int ret = 0; \
- if (q && q->buf_ops && q->buf_ops->op) \
- ret = q->buf_ops->op(args); \
- ret; \
-})
-
-bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
-int vb2_verify_memory_type(struct vb2_queue *q,
- enum vb2_memory memory, unsigned int type);
-#endif /* _MEDIA_VIDEOBUF2_INTERNAL_H */
diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c
index 27b4b9e..c9a2860 100644
--- a/drivers/media/v4l2-core/videobuf2-v4l2.c
+++ b/drivers/media/v4l2-core/videobuf2-v4l2.c
@@ -31,7 +31,14 @@
#include <media/videobuf2-v4l2.h>
-#include "videobuf2-internal.h"
+static int debug;
+module_param(debug, int, 0644);
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (debug >= level) \
+ pr_info("vb2-v4l2: %s: " fmt, __func__, ## arg); \
+ } while (0)
/* Flags that are set by the vb2 core */
#define V4L2_BUFFER_MASK_FLAGS (V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_QUEUED | \
@@ -52,7 +59,7 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
return 0;
/* Is memory for copying plane information present? */
- if (NULL == b->m.planes) {
+ if (b->m.planes == NULL) {
dprintk(1, "multi-planar buffer passed but "
"planes array not provided\n");
return -EINVAL;
@@ -107,7 +114,7 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b)
return 0;
}
-static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
+static void __copy_timestamp(struct vb2_buffer *vb, const void *pb)
{
const struct v4l2_buffer *b = pb;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -118,14 +125,12 @@ static int __set_timestamp(struct vb2_buffer *vb, const void *pb)
* For output buffers copy the timestamp if needed,
* and the timecode field and flag if needed.
*/
- if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
- V4L2_BUF_FLAG_TIMESTAMP_COPY)
- vbuf->timestamp = b->timestamp;
+ if (q->copy_timestamp)
+ vb->timestamp = timeval_to_ns(&b->timestamp);
vbuf->flags |= b->flags & V4L2_BUF_FLAG_TIMECODE;
if (b->flags & V4L2_BUF_FLAG_TIMECODE)
vbuf->timecode = b->timecode;
}
- return 0;
};
static void vb2_warn_zero_bytesused(struct vb2_buffer *vb)
@@ -176,7 +181,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
* __fill_v4l2_buffer() - fill in a struct v4l2_buffer with information to be
* returned to userspace
*/
-static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
+static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
{
struct v4l2_buffer *b = pb;
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
@@ -191,7 +196,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
b->flags = vbuf->flags;
b->field = vbuf->field;
- b->timestamp = vbuf->timestamp;
+ b->timestamp = ns_to_timeval(vb->timestamp);
b->timecode = vbuf->timecode;
b->sequence = vbuf->sequence;
b->reserved2 = 0;
@@ -238,8 +243,7 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
*/
b->flags &= ~V4L2_BUFFER_MASK_FLAGS;
b->flags |= q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK;
- if ((q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
- V4L2_BUF_FLAG_TIMESTAMP_COPY) {
+ if (!q->copy_timestamp) {
/*
* For non-COPY timestamps, drop timestamp source bits
* and obtain the timestamp source from the queue.
@@ -272,7 +276,10 @@ static int __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
if (vb2_buffer_in_use(q, vb))
b->flags |= V4L2_BUF_FLAG_MAPPED;
- return 0;
+ if (!q->is_output &&
+ b->flags & V4L2_BUF_FLAG_DONE &&
+ b->flags & V4L2_BUF_FLAG_LAST)
+ q->last_buffer_dequeued = true;
}
/**
@@ -308,8 +315,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
"for an output buffer\n");
return -EINVAL;
}
- vbuf->timestamp.tv_sec = 0;
- vbuf->timestamp.tv_usec = 0;
+ vb->timestamp = 0;
vbuf->sequence = 0;
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
@@ -404,8 +410,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
/* Zero flags that the vb2 core handles */
vbuf->flags = b->flags & ~V4L2_BUFFER_MASK_FLAGS;
- if ((vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) !=
- V4L2_BUF_FLAG_TIMESTAMP_COPY || !V4L2_TYPE_IS_OUTPUT(b->type)) {
+ if (!vb->vb2_queue->copy_timestamp || !V4L2_TYPE_IS_OUTPUT(b->type)) {
/*
* Non-COPY timestamps and non-OUTPUT queues will get
* their timestamp and timestamp source flags from the
@@ -434,7 +439,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb,
static const struct vb2_buf_ops v4l2_buf_ops = {
.fill_user_buffer = __fill_v4l2_buffer,
.fill_vb2_buffer = __fill_vb2_buffer,
- .set_timestamp = __set_timestamp,
+ .copy_timestamp = __copy_timestamp,
};
/**
@@ -466,8 +471,9 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
}
vb = q->bufs[b->index];
ret = __verify_planes_array(vb, b);
-
- return ret ? ret : vb2_core_querybuf(q, b->index, b);
+ if (!ret)
+ vb2_core_querybuf(q, b->index, b);
+ return ret;
}
EXPORT_SYMBOL(vb2_querybuf);
@@ -525,14 +531,52 @@ EXPORT_SYMBOL_GPL(vb2_prepare_buf);
*/
int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
{
- int ret = vb2_verify_memory_type(q, create->memory,
- create->format.type);
+ unsigned requested_planes = 1;
+ unsigned requested_sizes[VIDEO_MAX_PLANES];
+ struct v4l2_format *f = &create->format;
+ int ret = vb2_verify_memory_type(q, create->memory, f->type);
+ unsigned i;
create->index = q->num_buffers;
if (create->count == 0)
return ret != -EBUSY ? ret : 0;
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ requested_planes = f->fmt.pix_mp.num_planes;
+ if (requested_planes == 0 ||
+ requested_planes > VIDEO_MAX_PLANES)
+ return -EINVAL;
+ for (i = 0; i < requested_planes; i++)
+ requested_sizes[i] =
+ f->fmt.pix_mp.plane_fmt[i].sizeimage;
+ break;
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ requested_sizes[0] = f->fmt.pix.sizeimage;
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ requested_sizes[0] = f->fmt.vbi.samples_per_line *
+ (f->fmt.vbi.count[0] + f->fmt.vbi.count[1]);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ requested_sizes[0] = f->fmt.sliced.io_size;
+ break;
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+ requested_sizes[0] = f->fmt.sdr.buffersize;
+ break;
+ default:
+ return -EINVAL;
+ }
+ for (i = 0; i < requested_planes; i++)
+ if (requested_sizes[i] == 0)
+ return -EINVAL;
return ret ? ret : vb2_core_create_bufs(q, create->memory,
- &create->count, &create->format);
+ &create->count, requested_planes, requested_sizes);
}
EXPORT_SYMBOL_GPL(vb2_create_bufs);
@@ -583,10 +627,6 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b,
ret = vb2_core_dqbuf(q, b, nonblocking);
- if (!ret && !q->is_output &&
- b->flags & V4L2_BUF_FLAG_LAST)
- q->last_buffer_dequeued = true;
-
return ret;
}
@@ -723,14 +763,13 @@ int vb2_queue_init(struct vb2_queue *q)
q->buf_ops = &v4l2_buf_ops;
q->is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
q->is_output = V4L2_TYPE_IS_OUTPUT(q->type);
+ q->copy_timestamp = (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK)
+ == V4L2_BUF_FLAG_TIMESTAMP_COPY;
return vb2_core_queue_init(q);
}
EXPORT_SYMBOL_GPL(vb2_queue_init);
-static int __vb2_init_fileio(struct vb2_queue *q, int read);
-static int __vb2_cleanup_fileio(struct vb2_queue *q);
-
/**
* vb2_queue_release() - stop streaming, release the queue and free memory
* @q: videobuf2 queue
@@ -741,7 +780,6 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q);
*/
void vb2_queue_release(struct vb2_queue *q)
{
- __vb2_cleanup_fileio(q);
vb2_core_queue_release(q);
}
EXPORT_SYMBOL_GPL(vb2_queue_release);
@@ -769,9 +807,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
{
struct video_device *vfd = video_devdata(file);
unsigned long req_events = poll_requested_events(wait);
- struct vb2_buffer *vb = NULL;
unsigned int res = 0;
- unsigned long flags;
if (test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags)) {
struct v4l2_fh *fh = file->private_data;
@@ -782,611 +818,18 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
poll_wait(file, &fh->wait, wait);
}
- if (!q->is_output && !(req_events & (POLLIN | POLLRDNORM)))
- return res;
- if (q->is_output && !(req_events & (POLLOUT | POLLWRNORM)))
- return res;
-
- /*
- * Start file I/O emulator only if streaming API has not been used yet.
- */
- if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
- if (!q->is_output && (q->io_modes & VB2_READ) &&
- (req_events & (POLLIN | POLLRDNORM))) {
- if (__vb2_init_fileio(q, 1))
- return res | POLLERR;
- }
- if (q->is_output && (q->io_modes & VB2_WRITE) &&
- (req_events & (POLLOUT | POLLWRNORM))) {
- if (__vb2_init_fileio(q, 0))
- return res | POLLERR;
- /*
- * Write to OUTPUT queue can be done immediately.
- */
- return res | POLLOUT | POLLWRNORM;
- }
- }
-
- /*
- * There is nothing to wait for if the queue isn't streaming, or if the
- * error flag is set.
- */
- if (!vb2_is_streaming(q) || q->error)
- return res | POLLERR;
/*
* For compatibility with vb1: if QBUF hasn't been called yet, then
* return POLLERR as well. This only affects capture queues, output
* queues will always initialize waiting_for_buffers to false.
*/
- if (q->waiting_for_buffers)
- return res | POLLERR;
-
- /*
- * For output streams you can write as long as there are fewer buffers
- * queued than there are buffers available.
- */
- if (q->is_output && q->queued_count < q->num_buffers)
- return res | POLLOUT | POLLWRNORM;
-
- if (list_empty(&q->done_list)) {
- /*
- * If the last buffer was dequeued from a capture queue,
- * return immediately. DQBUF will return -EPIPE.
- */
- if (q->last_buffer_dequeued)
- return res | POLLIN | POLLRDNORM;
-
- poll_wait(file, &q->done_wq, wait);
- }
+ if (q->waiting_for_buffers && (req_events & (POLLIN | POLLRDNORM)))
+ return POLLERR;
- /*
- * Take first buffer available for dequeuing.
- */
- spin_lock_irqsave(&q->done_lock, flags);
- if (!list_empty(&q->done_list))
- vb = list_first_entry(&q->done_list, struct vb2_buffer,
- done_entry);
- spin_unlock_irqrestore(&q->done_lock, flags);
-
- if (vb && (vb->state == VB2_BUF_STATE_DONE
- || vb->state == VB2_BUF_STATE_ERROR)) {
- return (q->is_output) ?
- res | POLLOUT | POLLWRNORM :
- res | POLLIN | POLLRDNORM;
- }
- return res;
+ return res | vb2_core_poll(q, file, wait);
}
EXPORT_SYMBOL_GPL(vb2_poll);
-/**
- * struct vb2_fileio_buf - buffer context used by file io emulator
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. This structure is used for
- * tracking context related to the buffers.
- */
-struct vb2_fileio_buf {
- void *vaddr;
- unsigned int size;
- unsigned int pos;
- unsigned int queued:1;
-};
-
-/**
- * struct vb2_fileio_data - queue context used by file io emulator
- *
- * @cur_index: the index of the buffer currently being read from or
- * written to. If equal to q->num_buffers then a new buffer
- * must be dequeued.
- * @initial_index: in the read() case all buffers are queued up immediately
- * in __vb2_init_fileio() and __vb2_perform_fileio() just cycles
- * buffers. However, in the write() case no buffers are initially
- * queued, instead whenever a buffer is full it is queued up by
- * __vb2_perform_fileio(). Only once all available buffers have
- * been queued up will __vb2_perform_fileio() start to dequeue
- * buffers. This means that initially __vb2_perform_fileio()
- * needs to know what buffer index to use when it is queuing up
- * the buffers for the first time. That initial index is stored
- * in this field. Once it is equal to q->num_buffers all
- * available buffers have been queued and __vb2_perform_fileio()
- * should start the normal dequeue/queue cycle.
- *
- * vb2 provides a compatibility layer and emulator of file io (read and
- * write) calls on top of streaming API. For proper operation it required
- * this structure to save the driver state between each call of the read
- * or write function.
- */
-struct vb2_fileio_data {
- struct v4l2_requestbuffers req;
- struct v4l2_plane p;
- struct v4l2_buffer b;
- struct vb2_fileio_buf bufs[VB2_MAX_FRAME];
- unsigned int cur_index;
- unsigned int initial_index;
- unsigned int q_count;
- unsigned int dq_count;
- unsigned read_once:1;
- unsigned write_immediately:1;
-};
-
-/**
- * __vb2_init_fileio() - initialize file io emulator
- * @q: videobuf2 queue
- * @read: mode selector (1 means read, 0 means write)
- */
-static int __vb2_init_fileio(struct vb2_queue *q, int read)
-{
- struct vb2_fileio_data *fileio;
- int i, ret;
- unsigned int count = 0;
-
- /*
- * Sanity check
- */
- if (WARN_ON((read && !(q->io_modes & VB2_READ)) ||
- (!read && !(q->io_modes & VB2_WRITE))))
- return -EINVAL;
-
- /*
- * Check if device supports mapping buffers to kernel virtual space.
- */
- if (!q->mem_ops->vaddr)
- return -EBUSY;
-
- /*
- * Check if streaming api has not been already activated.
- */
- if (q->streaming || q->num_buffers > 0)
- return -EBUSY;
-
- /*
- * Start with count 1, driver can increase it in queue_setup()
- */
- count = 1;
-
- dprintk(3, "setting up file io: mode %s, count %d, read_once %d, write_immediately %d\n",
- (read) ? "read" : "write", count, q->fileio_read_once,
- q->fileio_write_immediately);
-
- fileio = kzalloc(sizeof(struct vb2_fileio_data), GFP_KERNEL);
- if (fileio == NULL)
- return -ENOMEM;
-
- fileio->read_once = q->fileio_read_once;
- fileio->write_immediately = q->fileio_write_immediately;
-
- /*
- * Request buffers and use MMAP type to force driver
- * to allocate buffers by itself.
- */
- fileio->req.count = count;
- fileio->req.memory = VB2_MEMORY_MMAP;
- fileio->req.type = q->type;
- q->fileio = fileio;
- ret = vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
- if (ret)
- goto err_kfree;
-
- /*
- * Check if plane_count is correct
- * (multiplane buffers are not supported).
- */
- if (q->bufs[0]->num_planes != 1) {
- ret = -EBUSY;
- goto err_reqbufs;
- }
-
- /*
- * Get kernel address of each buffer.
- */
- for (i = 0; i < q->num_buffers; i++) {
- fileio->bufs[i].vaddr = vb2_plane_vaddr(q->bufs[i], 0);
- if (fileio->bufs[i].vaddr == NULL) {
- ret = -EINVAL;
- goto err_reqbufs;
- }
- fileio->bufs[i].size = vb2_plane_size(q->bufs[i], 0);
- }
-
- /*
- * Read mode requires pre queuing of all buffers.
- */
- if (read) {
- bool is_multiplanar = q->is_multiplanar;
-
- /*
- * Queue all buffers.
- */
- for (i = 0; i < q->num_buffers; i++) {
- struct v4l2_buffer *b = &fileio->b;
-
- memset(b, 0, sizeof(*b));
- b->type = q->type;
- if (is_multiplanar) {
- memset(&fileio->p, 0, sizeof(fileio->p));
- b->m.planes = &fileio->p;
- b->length = 1;
- }
- b->memory = q->memory;
- b->index = i;
- ret = vb2_internal_qbuf(q, b);
- if (ret)
- goto err_reqbufs;
- fileio->bufs[i].queued = 1;
- }
- /*
- * All buffers have been queued, so mark that by setting
- * initial_index to q->num_buffers
- */
- fileio->initial_index = q->num_buffers;
- fileio->cur_index = q->num_buffers;
- }
-
- /*
- * Start streaming.
- */
- ret = vb2_core_streamon(q, q->type);
- if (ret)
- goto err_reqbufs;
-
- return ret;
-
-err_reqbufs:
- fileio->req.count = 0;
- vb2_core_reqbufs(q, fileio->req.memory, &fileio->req.count);
-
-err_kfree:
- q->fileio = NULL;
- kfree(fileio);
- return ret;
-}
-
-/**
- * __vb2_cleanup_fileio() - free resourced used by file io emulator
- * @q: videobuf2 queue
- */
-static int __vb2_cleanup_fileio(struct vb2_queue *q)
-{
- struct vb2_fileio_data *fileio = q->fileio;
-
- if (fileio) {
- vb2_core_streamoff(q, q->type);
- q->fileio = NULL;
- fileio->req.count = 0;
- vb2_reqbufs(q, &fileio->req);
- kfree(fileio);
- dprintk(3, "file io emulator closed\n");
- }
- return 0;
-}
-
-/**
- * __vb2_perform_fileio() - perform a single file io (read or write) operation
- * @q: videobuf2 queue
- * @data: pointed to target userspace buffer
- * @count: number of bytes to read or write
- * @ppos: file handle position tracking pointer
- * @nonblock: mode selector (1 means blocking calls, 0 means nonblocking)
- * @read: access mode selector (1 means read, 0 means write)
- */
-static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblock, int read)
-{
- struct vb2_fileio_data *fileio;
- struct vb2_fileio_buf *buf;
- bool is_multiplanar = q->is_multiplanar;
- /*
- * When using write() to write data to an output video node the vb2 core
- * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
- * else is able to provide this information with the write() operation.
- */
- bool set_timestamp = !read &&
- (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
- V4L2_BUF_FLAG_TIMESTAMP_COPY;
- int ret, index;
-
- dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
- read ? "read" : "write", (long)*ppos, count,
- nonblock ? "non" : "");
-
- if (!data)
- return -EINVAL;
-
- /*
- * Initialize emulator on first call.
- */
- if (!vb2_fileio_is_active(q)) {
- ret = __vb2_init_fileio(q, read);
- dprintk(3, "vb2_init_fileio result: %d\n", ret);
- if (ret)
- return ret;
- }
- fileio = q->fileio;
-
- /*
- * Check if we need to dequeue the buffer.
- */
- index = fileio->cur_index;
- if (index >= q->num_buffers) {
- /*
- * Call vb2_dqbuf to get buffer back.
- */
- memset(&fileio->b, 0, sizeof(fileio->b));
- fileio->b.type = q->type;
- fileio->b.memory = q->memory;
- if (is_multiplanar) {
- memset(&fileio->p, 0, sizeof(fileio->p));
- fileio->b.m.planes = &fileio->p;
- fileio->b.length = 1;
- }
- ret = vb2_internal_dqbuf(q, &fileio->b, nonblock);
- dprintk(5, "vb2_dqbuf result: %d\n", ret);
- if (ret)
- return ret;
- fileio->dq_count += 1;
-
- fileio->cur_index = index = fileio->b.index;
- buf = &fileio->bufs[index];
-
- /*
- * Get number of bytes filled by the driver
- */
- buf->pos = 0;
- buf->queued = 0;
- buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
- : vb2_plane_size(q->bufs[index], 0);
- /* Compensate for data_offset on read in the multiplanar case. */
- if (is_multiplanar && read &&
- fileio->b.m.planes[0].data_offset < buf->size) {
- buf->pos = fileio->b.m.planes[0].data_offset;
- buf->size -= buf->pos;
- }
- } else {
- buf = &fileio->bufs[index];
- }
-
- /*
- * Limit count on last few bytes of the buffer.
- */
- if (buf->pos + count > buf->size) {
- count = buf->size - buf->pos;
- dprintk(5, "reducing read count: %zd\n", count);
- }
-
- /*
- * Transfer data to userspace.
- */
- dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
- count, index, buf->pos);
- if (read)
- ret = copy_to_user(data, buf->vaddr + buf->pos, count);
- else
- ret = copy_from_user(buf->vaddr + buf->pos, data, count);
- if (ret) {
- dprintk(3, "error copying data\n");
- return -EFAULT;
- }
-
- /*
- * Update counters.
- */
- buf->pos += count;
- *ppos += count;
-
- /*
- * Queue next buffer if required.
- */
- if (buf->pos == buf->size || (!read && fileio->write_immediately)) {
- /*
- * Check if this is the last buffer to read.
- */
- if (read && fileio->read_once && fileio->dq_count == 1) {
- dprintk(3, "read limit reached\n");
- return __vb2_cleanup_fileio(q);
- }
-
- /*
- * Call vb2_qbuf and give buffer to the driver.
- */
- memset(&fileio->b, 0, sizeof(fileio->b));
- fileio->b.type = q->type;
- fileio->b.memory = q->memory;
- fileio->b.index = index;
- fileio->b.bytesused = buf->pos;
- if (is_multiplanar) {
- memset(&fileio->p, 0, sizeof(fileio->p));
- fileio->p.bytesused = buf->pos;
- fileio->b.m.planes = &fileio->p;
- fileio->b.length = 1;
- }
- if (set_timestamp)
- v4l2_get_timestamp(&fileio->b.timestamp);
- ret = vb2_internal_qbuf(q, &fileio->b);
- dprintk(5, "vb2_dbuf result: %d\n", ret);
- if (ret)
- return ret;
-
- /*
- * Buffer has been queued, update the status
- */
- buf->pos = 0;
- buf->queued = 1;
- buf->size = vb2_plane_size(q->bufs[index], 0);
- fileio->q_count += 1;
- /*
- * If we are queuing up buffers for the first time, then
- * increase initial_index by one.
- */
- if (fileio->initial_index < q->num_buffers)
- fileio->initial_index++;
- /*
- * The next buffer to use is either a buffer that's going to be
- * queued for the first time (initial_index < q->num_buffers)
- * or it is equal to q->num_buffers, meaning that the next
- * time we need to dequeue a buffer since we've now queued up
- * all the 'first time' buffers.
- */
- fileio->cur_index = fileio->initial_index;
- }
-
- /*
- * Return proper number of bytes processed.
- */
- if (ret == 0)
- ret = count;
- return ret;
-}
-
-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblocking)
-{
- return __vb2_perform_fileio(q, data, count, ppos, nonblocking, 1);
-}
-EXPORT_SYMBOL_GPL(vb2_read);
-
-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
- loff_t *ppos, int nonblocking)
-{
- return __vb2_perform_fileio(q, (char __user *) data, count,
- ppos, nonblocking, 0);
-}
-EXPORT_SYMBOL_GPL(vb2_write);
-
-struct vb2_threadio_data {
- struct task_struct *thread;
- vb2_thread_fnc fnc;
- void *priv;
- bool stop;
-};
-
-static int vb2_thread(void *data)
-{
- struct vb2_queue *q = data;
- struct vb2_threadio_data *threadio = q->threadio;
- struct vb2_fileio_data *fileio = q->fileio;
- bool set_timestamp = false;
- int prequeue = 0;
- int index = 0;
- int ret = 0;
-
- if (q->is_output) {
- prequeue = q->num_buffers;
- set_timestamp =
- (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
- V4L2_BUF_FLAG_TIMESTAMP_COPY;
- }
-
- set_freezable();
-
- for (;;) {
- struct vb2_buffer *vb;
-
- /*
- * Call vb2_dqbuf to get buffer back.
- */
- memset(&fileio->b, 0, sizeof(fileio->b));
- fileio->b.type = q->type;
- fileio->b.memory = q->memory;
- if (prequeue) {
- fileio->b.index = index++;
- prequeue--;
- } else {
- call_void_qop(q, wait_finish, q);
- if (!threadio->stop)
- ret = vb2_internal_dqbuf(q, &fileio->b, 0);
- call_void_qop(q, wait_prepare, q);
- dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
- }
- if (ret || threadio->stop)
- break;
- try_to_freeze();
-
- vb = q->bufs[fileio->b.index];
- if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR))
- if (threadio->fnc(vb, threadio->priv))
- break;
- call_void_qop(q, wait_finish, q);
- if (set_timestamp)
- v4l2_get_timestamp(&fileio->b.timestamp);
- if (!threadio->stop)
- ret = vb2_internal_qbuf(q, &fileio->b);
- call_void_qop(q, wait_prepare, q);
- if (ret || threadio->stop)
- break;
- }
-
- /* Hmm, linux becomes *very* unhappy without this ... */
- while (!kthread_should_stop()) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- }
- return 0;
-}
-
-/*
- * This function should not be used for anything else but the videobuf2-dvb
- * support. If you think you have another good use-case for this, then please
- * contact the linux-media mailinglist first.
- */
-int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
- const char *thread_name)
-{
- struct vb2_threadio_data *threadio;
- int ret = 0;
-
- if (q->threadio)
- return -EBUSY;
- if (vb2_is_busy(q))
- return -EBUSY;
- if (WARN_ON(q->fileio))
- return -EBUSY;
-
- threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
- if (threadio == NULL)
- return -ENOMEM;
- threadio->fnc = fnc;
- threadio->priv = priv;
-
- ret = __vb2_init_fileio(q, !q->is_output);
- dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
- if (ret)
- goto nomem;
- q->threadio = threadio;
- threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
- if (IS_ERR(threadio->thread)) {
- ret = PTR_ERR(threadio->thread);
- threadio->thread = NULL;
- goto nothread;
- }
- return 0;
-
-nothread:
- __vb2_cleanup_fileio(q);
-nomem:
- kfree(threadio);
- return ret;
-}
-EXPORT_SYMBOL_GPL(vb2_thread_start);
-
-int vb2_thread_stop(struct vb2_queue *q)
-{
- struct vb2_threadio_data *threadio = q->threadio;
- int err;
-
- if (threadio == NULL)
- return 0;
- threadio->stop = true;
- /* Wake up all pending sleeps in the thread */
- vb2_queue_error(q);
- err = kthread_stop(threadio->thread);
- __vb2_cleanup_fileio(q);
- threadio->thread = NULL;
- kfree(threadio);
- q->threadio = NULL;
- return err;
-}
-EXPORT_SYMBOL_GPL(vb2_thread_stop);
-
/*
* The following functions are not part of the vb2 core API, but are helper
* functions that plug into struct v4l2_ioctl_ops, struct v4l2_file_operations
@@ -1440,8 +883,8 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
return res;
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
- res = vb2_core_create_bufs(vdev->queue, p->memory, &p->count,
- &p->format);
+
+ res = vb2_create_bufs(vdev->queue, p);
if (res == 0)
vdev->queue->owner = file->private_data;
return res;
diff --git a/drivers/memory/fsl_ifc.c b/drivers/memory/fsl_ifc.c
index e87459f..acd1460 100644
--- a/drivers/memory/fsl_ifc.c
+++ b/drivers/memory/fsl_ifc.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/compiler.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/slab.h>
diff --git a/drivers/memory/pl172.c b/drivers/memory/pl172.c
index b2ef607..ff57195 100644
--- a/drivers/memory/pl172.c
+++ b/drivers/memory/pl172.c
@@ -118,7 +118,8 @@ static int pl172_setup_static(struct amba_device *adev,
if (of_property_read_bool(np, "mpmc,extended-wait"))
cfg |= MPMC_STATIC_CFG_EW;
- if (of_property_read_bool(np, "mpmc,buffer-enable"))
+ if (amba_part(adev) == 0x172 &&
+ of_property_read_bool(np, "mpmc,buffer-enable"))
cfg |= MPMC_STATIC_CFG_B;
if (of_property_read_bool(np, "mpmc,write-protect"))
@@ -190,6 +191,8 @@ static int pl172_parse_cs_config(struct amba_device *adev,
}
static const char * const pl172_revisions[] = {"r1", "r2", "r2p3", "r2p4"};
+static const char * const pl175_revisions[] = {"r1"};
+static const char * const pl176_revisions[] = {"r0"};
static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
{
@@ -202,6 +205,12 @@ static int pl172_probe(struct amba_device *adev, const struct amba_id *id)
if (amba_part(adev) == 0x172) {
if (amba_rev(adev) < ARRAY_SIZE(pl172_revisions))
rev = pl172_revisions[amba_rev(adev)];
+ } else if (amba_part(adev) == 0x175) {
+ if (amba_rev(adev) < ARRAY_SIZE(pl175_revisions))
+ rev = pl175_revisions[amba_rev(adev)];
+ } else if (amba_part(adev) == 0x176) {
+ if (amba_rev(adev) < ARRAY_SIZE(pl176_revisions))
+ rev = pl176_revisions[amba_rev(adev)];
}
dev_info(dev, "ARM PL%x revision %s\n", amba_part(adev), rev);
@@ -278,9 +287,20 @@ static int pl172_remove(struct amba_device *adev)
}
static const struct amba_id pl172_ids[] = {
+ /* PrimeCell MPMC PL172, EMC found on NXP LPC18xx and LPC43xx */
{
- .id = 0x07341172,
- .mask = 0xffffffff,
+ .id = 0x07041172,
+ .mask = 0x3f0fffff,
+ },
+ /* PrimeCell MPMC PL175, EMC found on NXP LPC32xx */
+ {
+ .id = 0x07041175,
+ .mask = 0x3f0fffff,
+ },
+ /* PrimeCell MPMC PL176 */
+ {
+ .id = 0x89041176,
+ .mask = 0xff0fffff,
},
{ 0, 0 },
};
diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c
index fc73937..02b5f69 100644
--- a/drivers/message/fusion/mptctl.c
+++ b/drivers/message/fusion/mptctl.c
@@ -1038,6 +1038,10 @@ kbuf_alloc_2_sgl(int bytes, u32 sgdir, int sge_offset, int *frags,
int i, buflist_ent;
int sg_spill = MAX_FRAGS_SPILL1;
int dir;
+
+ if (bytes < 0)
+ return NULL;
+
/* initialization */
*frags = 0;
*blp = NULL;
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 005a88b..7ebccfa 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1994,7 +1994,6 @@ static struct scsi_host_template mptsas_driver_template = {
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = mptscsih_host_attrs,
- .use_blk_tags = 1,
};
static int mptsas_get_linkerrors(struct sas_phy *phy)
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
index 6ce36d6..c9339f8 100644
--- a/drivers/mfd/timberdale.c
+++ b/drivers/mfd/timberdale.c
@@ -39,8 +39,8 @@
#include <linux/spi/max7301.h>
#include <linux/spi/mc33880.h>
-#include <media/timb_radio.h>
-#include <media/timb_video.h>
+#include <linux/platform_data/media/timb_radio.h>
+#include <linux/platform_data/media/timb_video.h>
#include <linux/timb_dma.h>
diff --git a/drivers/misc/atmel_tclib.c b/drivers/misc/atmel_tclib.c
index 0ca05c3..ac24a4b 100644
--- a/drivers/misc/atmel_tclib.c
+++ b/drivers/misc/atmel_tclib.c
@@ -125,6 +125,10 @@ static int __init tc_probe(struct platform_device *pdev)
if (IS_ERR(clk))
return PTR_ERR(clk);
+ tc->slow_clk = devm_clk_get(&pdev->dev, "slow_clk");
+ if (IS_ERR(tc->slow_clk))
+ return PTR_ERR(tc->slow_clk);
+
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tc->regs = devm_ioremap_resource(&pdev->dev, r);
if (IS_ERR(tc->regs))
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index d2e75c8..f409097 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -497,6 +497,7 @@ static u64 calculate_sr(struct cxl_context *ctx)
{
u64 sr = 0;
+ set_endian(sr);
if (ctx->master)
sr |= CXL_PSL_SR_An_MP;
if (mfspr(SPRN_LPCR) & LPCR_TC)
@@ -506,7 +507,6 @@ static u64 calculate_sr(struct cxl_context *ctx)
sr |= CXL_PSL_SR_An_HV;
} else {
sr |= CXL_PSL_SR_An_PR | CXL_PSL_SR_An_R;
- set_endian(sr);
sr &= ~(CXL_PSL_SR_An_HV);
if (!test_tsk_thread_flag(current, TIF_32BIT))
sr |= CXL_PSL_SR_An_SF;
diff --git a/drivers/misc/spear13xx_pcie_gadget.c b/drivers/misc/spear13xx_pcie_gadget.c
index b8374cd..ee120dc 100644
--- a/drivers/misc/spear13xx_pcie_gadget.c
+++ b/drivers/misc/spear13xx_pcie_gadget.c
@@ -220,11 +220,17 @@ static irqreturn_t spear_pcie_gadget_irq(int irq, void *dev_id)
/*
* configfs interfaces show/store functions
*/
-static ssize_t pcie_gadget_show_link(
- struct spear_pcie_gadget_config *config,
- char *buf)
+
+static struct pcie_gadget_target *to_target(struct config_item *item)
{
- struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+ return item ?
+ container_of(to_configfs_subsystem(to_config_group(item)),
+ struct pcie_gadget_target, subsys) : NULL;
+}
+
+static ssize_t pcie_gadget_link_show(struct config_item *item, char *buf)
+{
+ struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base;
if (readl(&app_reg->app_status_1) & ((u32)1 << XMLH_LINK_UP_ID))
return sprintf(buf, "UP");
@@ -232,11 +238,10 @@ static ssize_t pcie_gadget_show_link(
return sprintf(buf, "DOWN");
}
-static ssize_t pcie_gadget_store_link(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_link_store(struct config_item *item,
const char *buf, size_t count)
{
- struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+ struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base;
if (sysfs_streq(buf, "UP"))
writel(readl(&app_reg->app_ctrl_0) | (1 << APP_LTSSM_ENABLE_ID),
@@ -250,17 +255,15 @@ static ssize_t pcie_gadget_store_link(
return count;
}
-static ssize_t pcie_gadget_show_int_type(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_int_type_show(struct config_item *item, char *buf)
{
- return sprintf(buf, "%s", config->int_type);
+ return sprintf(buf, "%s", to_target(item)->int_type);
}
-static ssize_t pcie_gadget_store_int_type(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_int_type_store(struct config_item *item,
const char *buf, size_t count)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
u32 cap, vec, flags;
ulong vector;
@@ -288,11 +291,10 @@ static ssize_t pcie_gadget_store_int_type(
return count;
}
-static ssize_t pcie_gadget_show_no_of_msi(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_no_of_msi_show(struct config_item *item, char *buf)
{
- struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+ struct spear_pcie_gadget_config *config = to_target(item)
+ struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base;
u32 cap, vec, flags;
ulong vector;
@@ -313,13 +315,12 @@ static ssize_t pcie_gadget_show_no_of_msi(
return sprintf(buf, "%lu", vector);
}
-static ssize_t pcie_gadget_store_no_of_msi(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_no_of_msi_store(struct config_item *item,
const char *buf, size_t count)
{
int ret;
- ret = kstrtoul(buf, 0, &config->requested_msi);
+ ret = kstrtoul(buf, 0, &to_target(item)->requested_msi);
if (ret)
return ret;
@@ -329,11 +330,10 @@ static ssize_t pcie_gadget_store_no_of_msi(
return count;
}
-static ssize_t pcie_gadget_store_inta(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_inta_store(struct config_item *item,
const char *buf, size_t count)
{
- struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+ struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base;
ulong en;
int ret;
@@ -351,10 +351,10 @@ static ssize_t pcie_gadget_store_inta(
return count;
}
-static ssize_t pcie_gadget_store_send_msi(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_send_msi_store(struct config_item *item,
const char *buf, size_t count)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
struct pcie_app_reg __iomem *app_reg = config->va_app_base;
ulong vector;
u32 ven_msi;
@@ -388,19 +388,16 @@ static ssize_t pcie_gadget_store_send_msi(
return count;
}
-static ssize_t pcie_gadget_show_vendor_id(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_vendor_id_show(struct config_item *item, char *buf)
{
u32 id;
- spear_dbi_read_reg(config, PCI_VENDOR_ID, 2, &id);
+ spear_dbi_read_reg(to_target(item), PCI_VENDOR_ID, 2, &id);
return sprintf(buf, "%x", id);
}
-static ssize_t pcie_gadget_store_vendor_id(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_vendor_id_store(struct config_item *item,
const char *buf, size_t count)
{
ulong id;
@@ -410,24 +407,21 @@ static ssize_t pcie_gadget_store_vendor_id(
if (ret)
return ret;
- spear_dbi_write_reg(config, PCI_VENDOR_ID, 2, id);
+ spear_dbi_write_reg(to_target(item), PCI_VENDOR_ID, 2, id);
return count;
}
-static ssize_t pcie_gadget_show_device_id(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_device_id_show(struct config_item *item, char *buf)
{
u32 id;
- spear_dbi_read_reg(config, PCI_DEVICE_ID, 2, &id);
+ spear_dbi_read_reg(to_target(item), PCI_DEVICE_ID, 2, &id);
return sprintf(buf, "%x", id);
}
-static ssize_t pcie_gadget_store_device_id(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_device_id_store(struct config_item *item,
const char *buf, size_t count)
{
ulong id;
@@ -437,22 +431,20 @@ static ssize_t pcie_gadget_store_device_id(
if (ret)
return ret;
- spear_dbi_write_reg(config, PCI_DEVICE_ID, 2, id);
+ spear_dbi_write_reg(to_target(item), PCI_DEVICE_ID, 2, id);
return count;
}
-static ssize_t pcie_gadget_show_bar0_size(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_bar0_size_show(struct config_item *item, char *buf)
{
- return sprintf(buf, "%lx", config->bar0_size);
+ return sprintf(buf, "%lx", to_target(item)->bar0_size);
}
-static ssize_t pcie_gadget_store_bar0_size(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_size_store(struct config_item *item,
const char *buf, size_t count)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
ulong size;
u32 pos, pos1;
u32 no_of_bit = 0;
@@ -489,21 +481,20 @@ static ssize_t pcie_gadget_store_bar0_size(
return count;
}
-static ssize_t pcie_gadget_show_bar0_address(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_address_show(struct config_item *item,
char *buf)
{
- struct pcie_app_reg __iomem *app_reg = config->va_app_base;
+ struct pcie_app_reg __iomem *app_reg = to_target(item)->va_app_base;
u32 address = readl(&app_reg->pim0_mem_addr_start);
return sprintf(buf, "%x", address);
}
-static ssize_t pcie_gadget_store_bar0_address(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_address_store(struct config_item *item,
const char *buf, size_t count)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
struct pcie_app_reg __iomem *app_reg = config->va_app_base;
ulong address;
int ret;
@@ -524,15 +515,13 @@ static ssize_t pcie_gadget_store_bar0_address(
return count;
}
-static ssize_t pcie_gadget_show_bar0_rw_offset(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_rw_offset_show(struct config_item *item,
char *buf)
{
- return sprintf(buf, "%lx", config->bar0_rw_offset);
+ return sprintf(buf, "%lx", to_target(item)->bar0_rw_offset);
}
-static ssize_t pcie_gadget_store_bar0_rw_offset(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_rw_offset_store(struct config_item *item,
const char *buf, size_t count)
{
ulong offset;
@@ -545,15 +534,14 @@ static ssize_t pcie_gadget_store_bar0_rw_offset(
if (offset % 4)
return -EINVAL;
- config->bar0_rw_offset = offset;
+ to_target(item)->bar0_rw_offset = offset;
return count;
}
-static ssize_t pcie_gadget_show_bar0_data(
- struct spear_pcie_gadget_config *config,
- char *buf)
+static ssize_t pcie_gadget_bar0_data_show(struct config_item *item, char *buf)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
ulong data;
if (!config->va_bar0_address)
@@ -564,10 +552,10 @@ static ssize_t pcie_gadget_show_bar0_data(
return sprintf(buf, "%lx", data);
}
-static ssize_t pcie_gadget_store_bar0_data(
- struct spear_pcie_gadget_config *config,
+static ssize_t pcie_gadget_bar0_data_store(struct config_item *item,
const char *buf, size_t count)
{
+ struct spear_pcie_gadget_config *config = to_target(item)
ulong data;
int ret;
@@ -583,97 +571,35 @@ static ssize_t pcie_gadget_store_bar0_data(
return count;
}
-/*
- * Attribute definitions.
- */
-
-#define PCIE_GADGET_TARGET_ATTR_RO(_name) \
-static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \
- __CONFIGFS_ATTR(_name, S_IRUGO, pcie_gadget_show_##_name, NULL)
-
-#define PCIE_GADGET_TARGET_ATTR_WO(_name) \
-static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \
- __CONFIGFS_ATTR(_name, S_IWUSR, NULL, pcie_gadget_store_##_name)
-
-#define PCIE_GADGET_TARGET_ATTR_RW(_name) \
-static struct pcie_gadget_target_attr pcie_gadget_target_##_name = \
- __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, pcie_gadget_show_##_name, \
- pcie_gadget_store_##_name)
-PCIE_GADGET_TARGET_ATTR_RW(link);
-PCIE_GADGET_TARGET_ATTR_RW(int_type);
-PCIE_GADGET_TARGET_ATTR_RW(no_of_msi);
-PCIE_GADGET_TARGET_ATTR_WO(inta);
-PCIE_GADGET_TARGET_ATTR_WO(send_msi);
-PCIE_GADGET_TARGET_ATTR_RW(vendor_id);
-PCIE_GADGET_TARGET_ATTR_RW(device_id);
-PCIE_GADGET_TARGET_ATTR_RW(bar0_size);
-PCIE_GADGET_TARGET_ATTR_RW(bar0_address);
-PCIE_GADGET_TARGET_ATTR_RW(bar0_rw_offset);
-PCIE_GADGET_TARGET_ATTR_RW(bar0_data);
+CONFIGFS_ATTR(pcie_gadget_, link);
+CONFIGFS_ATTR(pcie_gadget_, int_type);
+CONFIGFS_ATTR(pcie_gadget_, no_of_msi);
+CONFIGFS_ATTR_WO(pcie_gadget_, inta);
+CONFIGFS_ATTR_WO(pcie_gadget_, send_msi);
+CONFIGFS_ATTR(pcie_gadget_, vendor_id);
+CONFIGFS_ATTR(pcie_gadget_, device_id);
+CONFIGFS_ATTR(pcie_gadget_, bar0_size);
+CONFIGFS_ATTR(pcie_gadget_, bar0_address);
+CONFIGFS_ATTR(pcie_gadget_, bar0_rw_offset);
+CONFIGFS_ATTR(pcie_gadget_, bar0_data);
static struct configfs_attribute *pcie_gadget_target_attrs[] = {
- &pcie_gadget_target_link.attr,
- &pcie_gadget_target_int_type.attr,
- &pcie_gadget_target_no_of_msi.attr,
- &pcie_gadget_target_inta.attr,
- &pcie_gadget_target_send_msi.attr,
- &pcie_gadget_target_vendor_id.attr,
- &pcie_gadget_target_device_id.attr,
- &pcie_gadget_target_bar0_size.attr,
- &pcie_gadget_target_bar0_address.attr,
- &pcie_gadget_target_bar0_rw_offset.attr,
- &pcie_gadget_target_bar0_data.attr,
+ &pcie_gadget_attr_link,
+ &pcie_gadget_attr_int_type,
+ &pcie_gadget_attr_no_of_msi,
+ &pcie_gadget_attr_inta,
+ &pcie_gadget_attr_send_msi,
+ &pcie_gadget_attr_vendor_id,
+ &pcie_gadget_attr_device_id,
+ &pcie_gadget_attr_bar0_size,
+ &pcie_gadget_attr_bar0_address,
+ &pcie_gadget_attr_bar0_rw_offset,
+ &pcie_gadget_attr_bar0_data,
NULL,
};
-static struct pcie_gadget_target *to_target(struct config_item *item)
-{
- return item ?
- container_of(to_configfs_subsystem(to_config_group(item)),
- struct pcie_gadget_target, subsys) : NULL;
-}
-
-/*
- * Item operations and type for pcie_gadget_target.
- */
-
-static ssize_t pcie_gadget_target_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *buf)
-{
- ssize_t ret = -EINVAL;
- struct pcie_gadget_target *target = to_target(item);
- struct pcie_gadget_target_attr *t_attr =
- container_of(attr, struct pcie_gadget_target_attr, attr);
-
- if (t_attr->show)
- ret = t_attr->show(&target->config, buf);
- return ret;
-}
-
-static ssize_t pcie_gadget_target_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *buf,
- size_t count)
-{
- ssize_t ret = -EINVAL;
- struct pcie_gadget_target *target = to_target(item);
- struct pcie_gadget_target_attr *t_attr =
- container_of(attr, struct pcie_gadget_target_attr, attr);
-
- if (t_attr->store)
- ret = t_attr->store(&target->config, buf, count);
- return ret;
-}
-
-static struct configfs_item_operations pcie_gadget_target_item_ops = {
- .show_attribute = pcie_gadget_target_attr_show,
- .store_attribute = pcie_gadget_target_attr_store,
-};
-
static struct config_item_type pcie_gadget_target_type = {
.ct_attrs = pcie_gadget_target_attrs,
- .ct_item_ops = &pcie_gadget_target_item_ops,
.ct_owner = THIS_MODULE,
};
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 23b6c8e..5914263 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -65,8 +65,7 @@ MODULE_ALIAS("mmc:block");
#define MMC_SANITIZE_REQ_TIMEOUT 240000
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
-#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
- (req->cmd_flags & REQ_META)) && \
+#define mmc_req_rel_wr(req) ((req->cmd_flags & REQ_FUA) && \
(rq_data_dir(req) == WRITE))
#define PACKED_CMD_VER 0x01
#define PACKED_CMD_WR 0x02
@@ -172,11 +171,7 @@ static struct mmc_blk_data *mmc_blk_get(struct gendisk *disk)
static inline int mmc_get_devidx(struct gendisk *disk)
{
- int devmaj = MAJOR(disk_devt(disk));
- int devidx = MINOR(disk_devt(disk)) / perdev_minors;
-
- if (!devmaj)
- devidx = disk->first_minor / perdev_minors;
+ int devidx = disk->first_minor / perdev_minors;
return devidx;
}
@@ -345,7 +340,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
struct mmc_blk_ioc_data *idata;
int err;
- idata = kzalloc(sizeof(*idata), GFP_KERNEL);
+ idata = kmalloc(sizeof(*idata), GFP_KERNEL);
if (!idata) {
err = -ENOMEM;
goto out;
@@ -365,7 +360,7 @@ static struct mmc_blk_ioc_data *mmc_blk_ioctl_copy_from_user(
if (!idata->buf_bytes)
return idata;
- idata->buf = kzalloc(idata->buf_bytes, GFP_KERNEL);
+ idata->buf = kmalloc(idata->buf_bytes, GFP_KERNEL);
if (!idata->buf) {
err = -ENOMEM;
goto idata_err;
@@ -1467,13 +1462,9 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
/*
* Reliable writes are used to implement Forced Unit Access and
- * REQ_META accesses, and are supported only on MMCs.
- *
- * XXX: this really needs a good explanation of why REQ_META
- * is treated special.
+ * are supported only on MMCs.
*/
- bool do_rel_wr = ((req->cmd_flags & REQ_FUA) ||
- (req->cmd_flags & REQ_META)) &&
+ bool do_rel_wr = (req->cmd_flags & REQ_FUA) &&
(rq_data_dir(req) == WRITE) &&
(md->flags & MMC_BLK_REL_WR);
@@ -2249,6 +2240,7 @@ 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);
+ md->disk->flags = GENHD_FL_EXT_DEVT;
if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
md->disk->flags |= GENHD_FL_NO_PART_SCAN;
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 972ff84..4bc48f1 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -349,6 +349,8 @@ int mmc_add_card(struct mmc_card *card)
card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+ device_enable_async_suspend(&card->dev);
+
ret = device_add(&card->dev);
if (ret)
return ret;
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 5ae89e4..f95d41f 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -55,7 +55,6 @@
*/
#define MMC_BKOPS_MAX_TIMEOUT (4 * 60 * 1000) /* max time to wait in ms */
-static struct workqueue_struct *workqueue;
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
/*
@@ -66,21 +65,16 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
bool use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);
-/*
- * Internal function. Schedule delayed work in the MMC work queue.
- */
static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
- return queue_delayed_work(workqueue, work, delay);
-}
-
-/*
- * Internal function. Flush all scheduled work from the MMC work queue.
- */
-static void mmc_flush_scheduled_work(void)
-{
- flush_workqueue(workqueue);
+ /*
+ * We use the system_freezable_wq, because of two reasons.
+ * First, it allows several works (not the same work item) to be
+ * executed simultaneously. Second, the queue becomes frozen when
+ * userspace becomes frozen during system PM.
+ */
+ return queue_delayed_work(system_freezable_wq, work, delay);
}
#ifdef CONFIG_FAIL_MMC_REQUEST
@@ -1485,7 +1479,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
if (IS_ERR(mmc->supply.vmmc)) {
if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- dev_info(dev, "No vmmc regulator found\n");
+ dev_dbg(dev, "No vmmc regulator found\n");
} else {
ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
if (ret > 0)
@@ -1497,7 +1491,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc)
if (IS_ERR(mmc->supply.vqmmc)) {
if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
- dev_info(dev, "No vqmmc regulator found\n");
+ dev_dbg(dev, "No vqmmc regulator found\n");
}
return 0;
@@ -2476,15 +2470,20 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
* sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52
* should be ignored by SD/eMMC cards.
+ * Skip it if we already know that we do not support SDIO commands
*/
- sdio_reset(host);
+ if (!(host->caps2 & MMC_CAP2_NO_SDIO))
+ sdio_reset(host);
+
mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
- if (!mmc_attach_sdio(host))
- return 0;
+ if (!(host->caps2 & MMC_CAP2_NO_SDIO))
+ if (!mmc_attach_sdio(host))
+ return 0;
+
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
@@ -2498,9 +2497,6 @@ int _mmc_detect_card_removed(struct mmc_host *host)
{
int ret;
- if (host->caps & MMC_CAP_NONREMOVABLE)
- return 0;
-
if (!host->card || mmc_card_removed(host->card))
return 1;
@@ -2536,6 +2532,9 @@ int mmc_detect_card_removed(struct mmc_host *host)
if (!card)
return 1;
+ if (host->caps & MMC_CAP_NONREMOVABLE)
+ return 0;
+
ret = mmc_card_removed(card);
/*
* The card will be considered unchanged unless we have been asked to
@@ -2567,11 +2566,6 @@ void mmc_rescan(struct work_struct *work)
container_of(work, struct mmc_host, detect.work);
int i;
- if (host->trigger_card_event && host->ops->card_event) {
- host->ops->card_event(host);
- host->trigger_card_event = false;
- }
-
if (host->rescan_disable)
return;
@@ -2580,6 +2574,13 @@ void mmc_rescan(struct work_struct *work)
return;
host->rescan_entered = 1;
+ if (host->trigger_card_event && host->ops->card_event) {
+ mmc_claim_host(host);
+ host->ops->card_event(host);
+ mmc_release_host(host);
+ host->trigger_card_event = false;
+ }
+
mmc_bus_get(host);
/*
@@ -2611,15 +2612,14 @@ void mmc_rescan(struct work_struct *work)
*/
mmc_bus_put(host);
+ mmc_claim_host(host);
if (!(host->caps & MMC_CAP_NONREMOVABLE) && host->ops->get_cd &&
host->ops->get_cd(host) == 0) {
- mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
goto out;
}
- mmc_claim_host(host);
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min)))
break;
@@ -2663,7 +2663,6 @@ void mmc_stop_host(struct mmc_host *host)
host->rescan_disable = 1;
cancel_delayed_work_sync(&host->detect);
- mmc_flush_scheduled_work();
/* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0;
@@ -2759,14 +2758,13 @@ int mmc_flush_cache(struct mmc_card *card)
}
EXPORT_SYMBOL(mmc_flush_cache);
-#ifdef CONFIG_PM
-
+#ifdef CONFIG_PM_SLEEP
/* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
to sync the card.
*/
-int mmc_pm_notify(struct notifier_block *notify_block,
- unsigned long mode, void *unused)
+static int mmc_pm_notify(struct notifier_block *notify_block,
+ unsigned long mode, void *unused)
{
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
@@ -2813,6 +2811,17 @@ int mmc_pm_notify(struct notifier_block *notify_block,
return 0;
}
+
+void mmc_register_pm_notifier(struct mmc_host *host)
+{
+ host->pm_notify.notifier_call = mmc_pm_notify;
+ register_pm_notifier(&host->pm_notify);
+}
+
+void mmc_unregister_pm_notifier(struct mmc_host *host)
+{
+ unregister_pm_notifier(&host->pm_notify);
+}
#endif
/**
@@ -2836,13 +2845,9 @@ static int __init mmc_init(void)
{
int ret;
- workqueue = alloc_ordered_workqueue("kmmcd", 0);
- if (!workqueue)
- return -ENOMEM;
-
ret = mmc_register_bus();
if (ret)
- goto destroy_workqueue;
+ return ret;
ret = mmc_register_host_class();
if (ret)
@@ -2858,9 +2863,6 @@ unregister_host_class:
mmc_unregister_host_class();
unregister_bus:
mmc_unregister_bus();
-destroy_workqueue:
- destroy_workqueue(workqueue);
-
return ret;
}
@@ -2869,7 +2871,6 @@ static void __exit mmc_exit(void)
sdio_unregister_bus();
mmc_unregister_host_class();
mmc_unregister_bus();
- destroy_workqueue(workqueue);
}
subsys_initcall(mmc_init);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 09241e5..0fa86a2 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -90,5 +90,13 @@ int mmc_execute_tuning(struct mmc_card *card);
int mmc_hs200_to_hs400(struct mmc_card *card);
int mmc_hs400_to_hs200(struct mmc_card *card);
+#ifdef CONFIG_PM_SLEEP
+void mmc_register_pm_notifier(struct mmc_host *host);
+void mmc_unregister_pm_notifier(struct mmc_host *host);
+#else
+static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
+static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
+#endif
+
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index da950c4..0aecd5c 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -21,7 +21,6 @@
#include <linux/export.h>
#include <linux/leds.h>
#include <linux/slab.h>
-#include <linux/suspend.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
@@ -275,7 +274,8 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_property_read_bool(np, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER;
- if (of_property_read_bool(np, "enable-sdio-wakeup"))
+ if (of_property_read_bool(np, "wakeup-source") ||
+ of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
if (of_property_read_bool(np, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR;
@@ -348,9 +348,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
-#ifdef CONFIG_PM
- host->pm_notify.notifier_call = mmc_pm_notify;
-#endif
setup_timer(&host->retune_timer, mmc_retune_timer, (unsigned long)host);
/*
@@ -395,7 +392,7 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_start_host(host);
- register_pm_notifier(&host->pm_notify);
+ mmc_register_pm_notifier(host);
return 0;
}
@@ -412,7 +409,7 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
- unregister_pm_notifier(&host->pm_notify);
+ mmc_unregister_pm_notifier(host);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c793fda..bf49e44 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1040,9 +1040,24 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
return err;
}
+/* Caller must hold re-tuning */
+static int mmc_switch_status(struct mmc_card *card)
+{
+ u32 status;
+ int err;
+
+ err = mmc_send_status(card, &status);
+ if (err)
+ return err;
+
+ return mmc_switch_status_error(card->host, status);
+}
+
static int mmc_select_hs400(struct mmc_card *card)
{
struct mmc_host *host = card->host;
+ bool send_status = true;
+ unsigned int max_dtr;
int err = 0;
u8 val;
@@ -1053,25 +1068,35 @@ static int mmc_select_hs400(struct mmc_card *card)
host->ios.bus_width == MMC_BUS_WIDTH_8))
return 0;
- /*
- * Before switching to dual data rate operation for HS400,
- * it is required to convert from HS200 mode to HS mode.
- */
- mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
- mmc_set_bus_speed(card);
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ send_status = false;
- val = EXT_CSD_TIMING_HS |
- card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+ /* Reduce frequency to HS frequency */
+ max_dtr = card->ext_csd.hs_max_dtr;
+ mmc_set_clock(host, max_dtr);
+
+ /* Switch card to HS mode */
+ val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
- true, true, true);
+ true, send_status, true);
if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
+ /* Set host controller to HS timing */
+ mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
+
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ if (err)
+ goto out_err;
+ }
+
+ /* Switch card to DDR */
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_DDR_BUS_WIDTH_8,
@@ -1082,22 +1107,35 @@ static int mmc_select_hs400(struct mmc_card *card)
return err;
}
+ /* Switch card to HS400 */
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
- true, true, true);
+ true, send_status, true);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
+ /* Set host controller to HS400 timing and frequency */
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ if (err)
+ goto out_err;
+ }
+
return 0;
+
+out_err:
+ pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+ __func__, err);
+ return err;
}
int mmc_hs200_to_hs400(struct mmc_card *card)
@@ -1105,19 +1143,6 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
return mmc_select_hs400(card);
}
-/* Caller must hold re-tuning */
-static int mmc_switch_status(struct mmc_card *card)
-{
- u32 status;
- int err;
-
- err = mmc_send_status(card, &status);
- if (err)
- return err;
-
- return mmc_switch_status_error(card->host, status);
-}
-
int mmc_hs400_to_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@@ -1134,8 +1159,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
mmc_set_clock(host, max_dtr);
/* Switch HS400 to HS DDR */
- val = EXT_CSD_TIMING_HS |
- card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+ val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time,
true, send_status, true);
@@ -1219,6 +1243,8 @@ static void mmc_select_driver_type(struct mmc_card *card)
static int mmc_select_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
+ bool send_status = true;
+ unsigned int old_timing;
int err = -EINVAL;
u8 val;
@@ -1234,6 +1260,9 @@ static int mmc_select_hs200(struct mmc_card *card)
mmc_select_driver_type(card);
+ if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+ send_status = false;
+
/*
* Set the bus width(4 or 8) with host's support and
* switch to HS200 mode if bus width is set successfully.
@@ -1245,11 +1274,25 @@ static int mmc_select_hs200(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time,
- true, true, true);
- if (!err)
- mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+ true, send_status, true);
+ if (err)
+ goto err;
+ old_timing = host->ios.timing;
+ mmc_set_timing(host, MMC_TIMING_MMC_HS200);
+ if (!send_status) {
+ err = mmc_switch_status(card);
+ /*
+ * mmc_select_timing() assumes timing has not changed if
+ * it is a switch error.
+ */
+ if (err == -EBADMSG)
+ mmc_set_timing(host, old_timing);
+ }
}
err:
+ if (err)
+ pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+ __func__, err);
return err;
}
@@ -1862,16 +1905,8 @@ static int mmc_shutdown(struct mmc_host *host)
*/
static int mmc_resume(struct mmc_host *host)
{
- int err = 0;
-
- if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
- err = _mmc_resume(host);
- pm_runtime_set_active(&host->card->dev);
- pm_runtime_mark_last_busy(&host->card->dev);
- }
pm_runtime_enable(&host->card->dev);
-
- return err;
+ return 0;
}
/*
@@ -1899,12 +1934,9 @@ static int mmc_runtime_resume(struct mmc_host *host)
{
int err;
- if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
- return 0;
-
err = _mmc_resume(host);
- if (err)
- pr_err("%s: error %d doing aggressive resume\n",
+ if (err && err != -ENOMEDIUM)
+ pr_err("%s: error %d doing runtime resume\n",
mmc_hostname(host), err);
return 0;
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 1f44426..2c90635 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -489,6 +489,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned long timeout;
u32 status = 0;
bool use_r1b_resp = use_busy_signal;
+ bool expired = false;
mmc_retune_hold(host);
@@ -545,6 +546,12 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
timeout = jiffies + msecs_to_jiffies(timeout_ms);
do {
if (send_status) {
+ /*
+ * Due to the possibility of being preempted after
+ * sending the status command, check the expiration
+ * time first.
+ */
+ expired = time_after(jiffies, timeout);
err = __mmc_send_status(card, &status, ignore_crc);
if (err)
goto out;
@@ -565,7 +572,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
/* Timeout if the device never leaves the program state. */
- if (time_after(jiffies, timeout)) {
+ if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
pr_err("%s: Card stuck in programming state! %s\n",
mmc_hostname(host), __func__);
err = -ETIMEDOUT;
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
index 096da48..133de04 100644
--- a/drivers/mmc/core/pwrseq.h
+++ b/drivers/mmc/core/pwrseq.h
@@ -16,7 +16,7 @@ struct mmc_pwrseq_ops {
};
struct mmc_pwrseq {
- struct mmc_pwrseq_ops *ops;
+ const struct mmc_pwrseq_ops *ops;
};
#ifdef CONFIG_OF
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
index ad4f94e..4a82bc7 100644
--- a/drivers/mmc/core/pwrseq_emmc.c
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -51,7 +51,7 @@ static void mmc_pwrseq_emmc_free(struct mmc_host *host)
kfree(pwrseq);
}
-static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
+static const struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
.post_power_on = mmc_pwrseq_emmc_reset,
.free = mmc_pwrseq_emmc_free,
};
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index d10538b..2b16263 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -87,7 +87,7 @@ static void mmc_pwrseq_simple_free(struct mmc_host *host)
kfree(pwrseq);
}
-static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
+static const struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
.pre_power_on = mmc_pwrseq_simple_pre_power_on,
.post_power_on = mmc_pwrseq_simple_post_power_on,
.power_off = mmc_pwrseq_simple_power_off,
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 141eaa9..f2b164b 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -1128,16 +1128,8 @@ out:
*/
static int mmc_sd_resume(struct mmc_host *host)
{
- int err = 0;
-
- if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
- err = _mmc_sd_resume(host);
- pm_runtime_set_active(&host->card->dev);
- pm_runtime_mark_last_busy(&host->card->dev);
- }
pm_runtime_enable(&host->card->dev);
-
- return err;
+ return 0;
}
/*
@@ -1165,12 +1157,9 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
{
int err;
- if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
- return 0;
-
err = _mmc_sd_resume(host);
- if (err)
- pr_err("%s: error %d doing aggressive resume\n",
+ if (err && err != -ENOMEDIUM)
+ pr_err("%s: error %d doing runtime resume\n",
mmc_hostname(host), err);
return 0;
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 16d838e..d61ba1a 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -630,7 +630,7 @@ try_again:
*/
if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
- ocr);
+ ocr_card);
if (err == -EAGAIN) {
sdio_reset(host);
mmc_go_idle(host);
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 7e327a6..86f5b32 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -322,6 +322,7 @@ int sdio_add_func(struct sdio_func *func)
sdio_set_of_node(func);
sdio_acpi_set_handle(func);
+ device_enable_async_suspend(&func->dev);
ret = device_add(&func->dev);
if (ret == 0)
sdio_func_set_present(func);
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index af71de5..1526b8a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -455,6 +455,7 @@ config MMC_TIFM_SD
config MMC_MVSDIO
tristate "Marvell MMC/SD/SDIO host driver"
depends on PLAT_ORION
+ depends on OF
---help---
This selects the Marvell SDIO host driver.
SDIO may currently be found on the Kirkwood 88F6281 and 88F6192
@@ -473,6 +474,7 @@ config MMC_DAVINCI
config MMC_GOLDFISH
tristate "goldfish qemu Multimedia Card Interface support"
+ depends on HAS_DMA
depends on GOLDFISH || COMPILE_TEST
help
This selects the Goldfish Multimedia card Interface emulation
diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h
deleted file mode 100644
index 0aa44e6..0000000
--- a/drivers/mmc/host/atmel-mci-regs.h
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Atmel MultiMedia Card Interface driver
- *
- * Copyright (C) 2004-2006 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-/*
- * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
- * Registers and bitfields marked with [2] are only available in MCI2
- */
-
-#ifndef __DRIVERS_MMC_ATMEL_MCI_H__
-#define __DRIVERS_MMC_ATMEL_MCI_H__
-
-/* MCI Register Definitions */
-#define ATMCI_CR 0x0000 /* Control */
-# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */
-# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */
-# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */
-# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */
-# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */
-#define ATMCI_MR 0x0004 /* Mode */
-# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */
-# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */
-# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */
-# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */
-# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */
-# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */
-# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */
-# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */
-#define ATMCI_DTOR 0x0008 /* Data Timeout */
-# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
-# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
-#define ATMCI_SDCR 0x000c /* SD Card / SDIO */
-# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */
-# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */
-# define ATMCI_SDCSEL_MASK ( 3 << 0)
-# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */
-# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */
-# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */
-# define ATMCI_SDCBUS_MASK ( 3 << 6)
-#define ATMCI_ARGR 0x0010 /* Command Argument */
-#define ATMCI_CMDR 0x0014 /* Command */
-# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
-# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */
-# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */
-# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */
-# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */
-# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */
-# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */
-# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */
-# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */
-# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */
-# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */
-# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */
-# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */
-# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */
-# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */
-# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */
-# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */
-# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */
-# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */
-# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */
-# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */
-# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */
-#define ATMCI_BLKR 0x0018 /* Block */
-# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */
-# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */
-#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */
-# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */
-# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */
-#define ATMCI_RSPR 0x0020 /* Response 0 */
-#define ATMCI_RSPR1 0x0024 /* Response 1 */
-#define ATMCI_RSPR2 0x0028 /* Response 2 */
-#define ATMCI_RSPR3 0x002c /* Response 3 */
-#define ATMCI_RDR 0x0030 /* Receive Data */
-#define ATMCI_TDR 0x0034 /* Transmit Data */
-#define ATMCI_SR 0x0040 /* Status */
-#define ATMCI_IER 0x0044 /* Interrupt Enable */
-#define ATMCI_IDR 0x0048 /* Interrupt Disable */
-#define ATMCI_IMR 0x004c /* Interrupt Mask */
-# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */
-# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */
-# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */
-# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */
-# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */
-# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */
-# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */
-# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */
-# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */
-# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */
-# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */
-# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */
-# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */
-# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */
-# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */
-# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */
-# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */
-# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */
-# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */
-# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */
-# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */
-# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */
-# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */
-# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */
-# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */
-# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */
-# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */
-# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */
-# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */
-# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */
-#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */
-# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */
-# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */
-# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */
-#define ATMCI_CFG 0x0054 /* Configuration[2] */
-# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */
-# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */
-# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */
-# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */
-#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */
-# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */
-# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */
-#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */
-# define ATMCI_GET_WP_VS(x) ((x) & 0x0f)
-# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff)
-#define ATMCI_VERSION 0x00FC /* Version */
-#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */
-
-/* This is not including the FIFO Aperture on MCI2 */
-#define ATMCI_REGS_SIZE 0x100
-
-/* Register access macros */
-#ifdef CONFIG_AVR32
-#define atmci_readl(port, reg) \
- __raw_readl((port)->regs + reg)
-#define atmci_writel(port, reg, value) \
- __raw_writel((value), (port)->regs + reg)
-#else
-#define atmci_readl(port, reg) \
- readl_relaxed((port)->regs + reg)
-#define atmci_writel(port, reg, value) \
- writel_relaxed((value), (port)->regs + reg)
-#endif
-
-/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
-#ifdef CONFIG_AVR32
-# define ATMCI_PDC_CONNECTED 0
-#else
-# define ATMCI_PDC_CONNECTED 1
-#endif
-
-/*
- * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
- * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
- *
- * This can be done by finding most significant bit set.
- */
-static inline unsigned int atmci_convert_chksize(unsigned int maxburst)
-{
- if (maxburst > 1)
- return fls(maxburst) - 2;
- else
- return 0;
-}
-
-#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index bf62e42..a36ebda 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -44,7 +44,141 @@
#include <asm/io.h>
#include <asm/unaligned.h>
-#include "atmel-mci-regs.h"
+/*
+ * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors
+ * Registers and bitfields marked with [2] are only available in MCI2
+ */
+
+/* MCI Register Definitions */
+#define ATMCI_CR 0x0000 /* Control */
+#define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */
+#define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */
+#define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */
+#define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */
+#define ATMCI_CR_SWRST BIT(7) /* Software Reset */
+#define ATMCI_MR 0x0004 /* Mode */
+#define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */
+#define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */
+#define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */
+#define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */
+#define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */
+#define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */
+#define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */
+#define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */
+#define ATMCI_DTOR 0x0008 /* Data Timeout */
+#define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
+#define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
+#define ATMCI_SDCR 0x000c /* SD Card / SDIO */
+#define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */
+#define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */
+#define ATMCI_SDCSEL_MASK (3 << 0)
+#define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */
+#define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */
+#define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */
+#define ATMCI_SDCBUS_MASK (3 << 6)
+#define ATMCI_ARGR 0x0010 /* Command Argument */
+#define ATMCI_CMDR 0x0014 /* Command */
+#define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */
+#define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */
+#define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */
+#define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */
+#define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */
+#define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */
+#define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */
+#define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */
+#define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */
+#define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */
+#define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */
+#define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */
+#define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */
+#define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */
+#define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */
+#define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */
+#define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */
+#define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */
+#define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */
+#define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */
+#define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */
+#define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */
+#define ATMCI_BLKR 0x0018 /* Block */
+#define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */
+#define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */
+#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */
+#define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */
+#define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */
+#define ATMCI_RSPR 0x0020 /* Response 0 */
+#define ATMCI_RSPR1 0x0024 /* Response 1 */
+#define ATMCI_RSPR2 0x0028 /* Response 2 */
+#define ATMCI_RSPR3 0x002c /* Response 3 */
+#define ATMCI_RDR 0x0030 /* Receive Data */
+#define ATMCI_TDR 0x0034 /* Transmit Data */
+#define ATMCI_SR 0x0040 /* Status */
+#define ATMCI_IER 0x0044 /* Interrupt Enable */
+#define ATMCI_IDR 0x0048 /* Interrupt Disable */
+#define ATMCI_IMR 0x004c /* Interrupt Mask */
+#define ATMCI_CMDRDY BIT(0) /* Command Ready */
+#define ATMCI_RXRDY BIT(1) /* Receiver Ready */
+#define ATMCI_TXRDY BIT(2) /* Transmitter Ready */
+#define ATMCI_BLKE BIT(3) /* Data Block Ended */
+#define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */
+#define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */
+#define ATMCI_ENDRX BIT(6) /* End of RX Buffer */
+#define ATMCI_ENDTX BIT(7) /* End of TX Buffer */
+#define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */
+#define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */
+#define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */
+#define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */
+#define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */
+#define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */
+#define ATMCI_RINDE BIT(16) /* Response Index Error */
+#define ATMCI_RDIRE BIT(17) /* Response Direction Error */
+#define ATMCI_RCRCE BIT(18) /* Response CRC Error */
+#define ATMCI_RENDE BIT(19) /* Response End Bit Error */
+#define ATMCI_RTOE BIT(20) /* Response Time-Out Error */
+#define ATMCI_DCRCE BIT(21) /* Data CRC Error */
+#define ATMCI_DTOE BIT(22) /* Data Time-Out Error */
+#define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */
+#define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */
+#define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */
+#define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */
+#define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */
+#define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */
+#define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */
+#define ATMCI_OVRE BIT(30) /* RX Overrun Error */
+#define ATMCI_UNRE BIT(31) /* TX Underrun Error */
+#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */
+#define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */
+#define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */
+#define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */
+#define ATMCI_CFG 0x0054 /* Configuration[2] */
+#define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */
+#define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */
+#define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */
+#define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */
+#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */
+#define ATMCI_WP_EN BIT(0) /* WP Enable */
+#define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */
+#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */
+#define ATMCI_GET_WP_VS(x) ((x) & 0x0f)
+#define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff)
+#define ATMCI_VERSION 0x00FC /* Version */
+#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */
+
+/* This is not including the FIFO Aperture on MCI2 */
+#define ATMCI_REGS_SIZE 0x100
+
+/* Register access macros */
+#define atmci_readl(port, reg) \
+ __raw_readl((port)->regs + reg)
+#define atmci_writel(port, reg, value) \
+ __raw_writel((value), (port)->regs + reg)
+
+/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */
+#ifdef CONFIG_AVR32
+# define ATMCI_PDC_CONNECTED 0
+#else
+# define ATMCI_PDC_CONNECTED 1
+#endif
#define AUTOSUSPEND_DELAY 50
@@ -584,6 +718,29 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host)
return atmci_readl(host, ATMCI_VERSION) & 0x00000fff;
}
+/*
+ * Fix sconfig's burst size according to atmel MCI. We need to convert them as:
+ * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3.
+ * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2,
+ * 8 -> 3, 16 -> 4.
+ *
+ * This can be done by finding most significant bit set.
+ */
+static inline unsigned int atmci_convert_chksize(struct atmel_mci *host,
+ unsigned int maxburst)
+{
+ unsigned int version = atmci_get_version(host);
+ unsigned int offset = 2;
+
+ if (version >= 0x600)
+ offset = 1;
+
+ if (maxburst > 1)
+ return fls(maxburst) - offset;
+ else
+ return 0;
+}
+
static void atmci_timeout_timer(unsigned long data)
{
struct atmel_mci *host;
@@ -1034,11 +1191,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data)
if (data->flags & MMC_DATA_READ) {
direction = DMA_FROM_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM;
- maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst);
+ maxburst = atmci_convert_chksize(host,
+ host->dma_conf.src_maxburst);
} else {
direction = DMA_TO_DEVICE;
host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV;
- maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst);
+ maxburst = atmci_convert_chksize(host,
+ host->dma_conf.dst_maxburst);
}
if (host->caps.has_dma_conf_reg)
diff --git a/drivers/mmc/host/cb710-mmc.h b/drivers/mmc/host/cb710-mmc.h
index 8984ec8..8ecd9e5 100644
--- a/drivers/mmc/host/cb710-mmc.h
+++ b/drivers/mmc/host/cb710-mmc.h
@@ -29,8 +29,7 @@ static inline struct mmc_host *cb710_slot_to_mmc(struct cb710_slot *slot)
static inline struct cb710_slot *cb710_mmc_to_slot(struct mmc_host *mmc)
{
- struct platform_device *pdev = container_of(mmc_dev(mmc),
- struct platform_device, dev);
+ struct platform_device *pdev = to_platform_device(mmc_dev(mmc));
return cb710_pdev_to_slot(pdev);
}
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 7e1d13b..81bdeeb 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -60,7 +60,7 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
/* Get registers' physical base address */
- host->phy_regs = (void *)(regs->start);
+ host->phy_regs = regs->start;
host->regs = devm_ioremap_resource(&pdev->dev, regs);
if (IS_ERR(host->regs))
return PTR_ERR(host->regs);
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 9becebe..d9c92f3 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -239,20 +239,12 @@ static int dw_mci_rockchip_init(struct dw_mci *host)
return 0;
}
-/* Common capabilities of RK3288 SoC */
-static unsigned long dw_mci_rk3288_dwmmc_caps[4] = {
- MMC_CAP_RUNTIME_RESUME, /* emmc */
- MMC_CAP_RUNTIME_RESUME, /* sdmmc */
- MMC_CAP_RUNTIME_RESUME, /* sdio0 */
- MMC_CAP_RUNTIME_RESUME, /* sdio1 */
-};
static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command,
.init = dw_mci_rockchip_init,
};
static const struct dw_mci_drv_data rk3288_drv_data = {
- .caps = dw_mci_rk3288_dwmmc_caps,
.prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios,
.execute_tuning = dw_mci_rk3288_execute_tuning,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 7a6cedb..7128351 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -699,7 +699,7 @@ static int dw_mci_edmac_start_dma(struct dw_mci *host,
int ret = 0;
/* Set external dma config: burst size, burst width */
- cfg.dst_addr = (dma_addr_t)(host->phy_regs + fifo_offset);
+ cfg.dst_addr = host->phy_regs + fifo_offset;
cfg.src_addr = cfg.dst_addr;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
@@ -1634,12 +1634,6 @@ static int dw_mci_command_complete(struct dw_mci *host, struct mmc_command *cmd)
else
cmd->error = 0;
- if (cmd->error) {
- /* newer ip versions need a delay between retries */
- if (host->quirks & DW_MCI_QUIRK_RETRY_DELAY)
- mdelay(20);
- }
-
return cmd->error;
}
@@ -2355,16 +2349,6 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
pending = mci_readl(host, MINTSTS); /* read-only mask reg */
- /*
- * DTO fix - version 2.10a and below, and only if internal DMA
- * is configured.
- */
- if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO) {
- if (!pending &&
- ((mci_readl(host, STATUS) >> 17) & 0x1fff))
- pending |= SDMMC_INT_DATA_OVER;
- }
-
if (pending) {
/* Check volt switch first, since it can look like an error */
if ((host->state == STATE_SENDING_CMD11) &&
@@ -3165,9 +3149,6 @@ int dw_mci_probe(struct dw_mci *host)
/* Now that slots are all setup, we can enable card detect */
dw_mci_enable_cd(host);
- if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
- dev_info(host->dev, "Internal DMAC interrupt fix enabled.\n");
-
return 0;
err_dmaunmap:
diff --git a/drivers/mmc/host/mtk-sd.c b/drivers/mmc/host/mtk-sd.c
index 39568cc..82a97ac 100644
--- a/drivers/mmc/host/mtk-sd.c
+++ b/drivers/mmc/host/mtk-sd.c
@@ -972,7 +972,7 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
if ((events & MSDC_INT_XFER_COMPL) && (!stop || !stop->error)) {
data->bytes_xfered = data->blocks * data->blksz;
} else {
- dev_err(host->dev, "interrupt events: %x\n", events);
+ dev_dbg(host->dev, "interrupt events: %x\n", events);
msdc_reset_hw(host);
host->error |= REQ_DAT_ERR;
data->bytes_xfered = 0;
@@ -982,10 +982,10 @@ static bool msdc_data_xfer_done(struct msdc_host *host, u32 events,
else if (events & MSDC_INT_DATCRCERR)
data->error = -EILSEQ;
- dev_err(host->dev, "%s: cmd=%d; blocks=%d",
+ dev_dbg(host->dev, "%s: cmd=%d; blocks=%d",
__func__, mrq->cmd->opcode, data->blocks);
- dev_err(host->dev, "data_error=%d xfer_size=%d\n",
- (int)data->error, data->bytes_xfered);
+ dev_dbg(host->dev, "data_error=%d xfer_size=%d\n",
+ (int)data->error, data->bytes_xfered);
}
msdc_data_xfer_next(host, mrq, data);
@@ -1276,7 +1276,7 @@ static struct msdc_delay_phase get_best_delay(struct msdc_host *host, u32 delay)
int start = 0, len = 0;
int start_final = 0, len_final = 0;
u8 final_phase = 0xff;
- struct msdc_delay_phase delay_phase;
+ struct msdc_delay_phase delay_phase = { 0, };
if (delay == 0) {
dev_err(host->dev, "phase error: [map:%x]\n", delay);
@@ -1543,7 +1543,6 @@ static int msdc_drv_probe(struct platform_device *pdev)
mmc->f_min = host->src_clk_freq / (4 * 255);
mmc->caps |= MMC_CAP_ERASE | MMC_CAP_CMD23;
- mmc->caps |= MMC_CAP_RUNTIME_RESUME;
/* MMC core transfer sizes tunable parameters */
mmc->max_segs = MAX_BD_NUM;
mmc->max_seg_size = BDMA_DESC_BUFLEN;
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index a448498..42296e5 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -20,15 +20,12 @@
#include <linux/scatterlist.h>
#include <linux/irq.h>
#include <linux/clk.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
#include <asm/sizes.h>
#include <asm/unaligned.h>
-#include <linux/platform_data/mmc-mvsdio.h>
#include "mvsdio.h"
@@ -704,6 +701,10 @@ static int mvsd_probe(struct platform_device *pdev)
struct resource *r;
int ret, irq;
+ if (!np) {
+ dev_err(&pdev->dev, "no DT node\n");
+ return -ENODEV;
+ }
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!r || irq < 0)
@@ -727,8 +728,12 @@ static int mvsd_probe(struct platform_device *pdev)
* fixed rate clock).
*/
host->clk = devm_clk_get(&pdev->dev, NULL);
- if (!IS_ERR(host->clk))
- clk_prepare_enable(host->clk);
+ if (IS_ERR(host->clk)) {
+ dev_err(&pdev->dev, "no clock associated\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ clk_prepare_enable(host->clk);
mmc->ops = &mvsd_ops;
@@ -744,45 +749,10 @@ static int mvsd_probe(struct platform_device *pdev)
mmc->max_seg_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
- if (np) {
- if (IS_ERR(host->clk)) {
- dev_err(&pdev->dev, "DT platforms must have a clock associated\n");
- ret = -EINVAL;
- goto out;
- }
-
- host->base_clock = clk_get_rate(host->clk) / 2;
- ret = mmc_of_parse(mmc);
- if (ret < 0)
- goto out;
- } else {
- const struct mvsdio_platform_data *mvsd_data;
-
- mvsd_data = pdev->dev.platform_data;
- if (!mvsd_data) {
- ret = -ENXIO;
- goto out;
- }
- mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ |
- MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
- host->base_clock = mvsd_data->clock / 2;
- /* GPIO 0 regarded as invalid for backward compatibility */
- if (mvsd_data->gpio_card_detect &&
- gpio_is_valid(mvsd_data->gpio_card_detect)) {
- ret = mmc_gpio_request_cd(mmc,
- mvsd_data->gpio_card_detect,
- 0);
- if (ret)
- goto out;
- } else {
- mmc->caps |= MMC_CAP_NEEDS_POLL;
- }
-
- if (mvsd_data->gpio_write_protect &&
- gpio_is_valid(mvsd_data->gpio_write_protect))
- mmc_gpio_request_ro(mmc, mvsd_data->gpio_write_protect);
- }
-
+ host->base_clock = clk_get_rate(host->clk) / 2;
+ ret = mmc_of_parse(mmc);
+ if (ret < 0)
+ goto out;
if (maxfreq)
mmc->f_max = maxfreq;
diff --git a/drivers/mmc/host/of_mmc_spi.c b/drivers/mmc/host/of_mmc_spi.c
index 6e218fb..660170c 100644
--- a/drivers/mmc/host/of_mmc_spi.c
+++ b/drivers/mmc/host/of_mmc_spi.c
@@ -55,8 +55,8 @@ static int of_mmc_spi_init(struct device *dev,
{
struct of_mmc_spi *oms = to_of_mmc_spi(dev);
- return request_threaded_irq(oms->detect_irq, NULL, irqhandler, 0,
- dev_name(dev), mmc);
+ return request_threaded_irq(oms->detect_irq, NULL, irqhandler,
+ IRQF_ONESHOT, dev_name(dev), mmc);
}
static void of_mmc_spi_exit(struct device *dev, void *mmc)
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 7fb0753..b6639ea 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -2250,10 +2250,8 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_get_sync(host->dev);
mmc_remove_host(host->mmc);
- if (host->tx_chan)
- dma_release_channel(host->tx_chan);
- if (host->rx_chan)
- dma_release_channel(host->rx_chan);
+ dma_release_channel(host->tx_chan);
+ dma_release_channel(host->rx_chan);
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 8cadd74..ce08896 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -805,7 +805,7 @@ static int pxamci_probe(struct platform_device *pdev)
goto out;
} else {
mmc->caps |= host->pdata->gpio_card_ro_invert ?
- MMC_CAP2_RO_ACTIVE_HIGH : 0;
+ 0 : MMC_CAP2_RO_ACTIVE_HIGH;
}
if (gpio_is_valid(gpio_cd))
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 1f1582f..f25f292 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -76,6 +76,7 @@
#define ESDHC_STD_TUNING_EN (1 << 24)
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1
+#define ESDHC_TUNING_STEP_MASK 0x00070000
#define ESDHC_TUNING_STEP_SHIFT 16
/* pinctrl state */
@@ -489,9 +490,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
m |= ESDHC_MIX_CTRL_FBCLK_SEL;
tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL);
tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP;
- if (imx_data->boarddata.tuning_step)
+ if (imx_data->boarddata.tuning_step) {
+ tuning_ctrl &= ~ESDHC_TUNING_STEP_MASK;
tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT;
- writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
+ }
+ writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL);
} else {
v &= ~ESDHC_MIX_CTRL_EXE_TUNE;
}
diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c
index 06d0b50..7e7d8f0 100644
--- a/drivers/mmc/host/sdhci-of-at91.c
+++ b/drivers/mmc/host/sdhci-of-at91.c
@@ -21,6 +21,8 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include "sdhci-pltfm.h"
@@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = {
{}
};
+#ifdef CONFIG_PM
+static int sdhci_at91_runtime_suspend(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_at91_priv *priv = pltfm_host->priv;
+ int ret;
+
+ ret = sdhci_runtime_suspend_host(host);
+
+ clk_disable_unprepare(priv->gck);
+ clk_disable_unprepare(priv->hclock);
+ clk_disable_unprepare(priv->mainck);
+
+ return ret;
+}
+
+static int sdhci_at91_runtime_resume(struct device *dev)
+{
+ struct sdhci_host *host = dev_get_drvdata(dev);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_at91_priv *priv = pltfm_host->priv;
+ int ret;
+
+ ret = clk_prepare_enable(priv->mainck);
+ if (ret) {
+ dev_err(dev, "can't enable mainck\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->hclock);
+ if (ret) {
+ dev_err(dev, "can't enable hclock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(priv->gck);
+ if (ret) {
+ dev_err(dev, "can't enable gck\n");
+ return ret;
+ }
+
+ return sdhci_runtime_resume_host(host);
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops sdhci_at91_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend,
+ sdhci_at91_runtime_resume,
+ NULL)
+};
+
static int sdhci_at91_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -144,12 +200,23 @@ static int sdhci_at91_probe(struct platform_device *pdev)
sdhci_get_of_property(pdev);
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+ pm_runtime_use_autosuspend(&pdev->dev);
+
ret = sdhci_add_host(host);
if (ret)
- goto clocks_disable_unprepare;
+ goto pm_runtime_disable;
+
+ pm_runtime_put_autosuspend(&pdev->dev);
return 0;
+pm_runtime_disable:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
clocks_disable_unprepare:
clk_disable_unprepare(priv->gck);
clk_disable_unprepare(priv->mainck);
@@ -165,6 +232,10 @@ static int sdhci_at91_remove(struct platform_device *pdev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_at91_priv *priv = pltfm_host->priv;
+ pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
sdhci_pltfm_unregister(pdev);
clk_disable_unprepare(priv->gck);
@@ -178,7 +249,7 @@ static struct platform_driver sdhci_at91_driver = {
.driver = {
.name = "sdhci-at91",
.of_match_table = sdhci_at91_dt_match,
- .pm = SDHCI_PLTFM_PMOPS,
+ .pm = &sdhci_at91_dev_pm_ops,
},
.probe = sdhci_at91_probe,
.remove = sdhci_at91_remove,
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 90e94a0..83b1226 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -584,6 +584,8 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
{
struct sdhci_host *host;
struct device_node *np;
+ struct sdhci_pltfm_host *pltfm_host;
+ struct sdhci_esdhc *esdhc;
int ret;
np = pdev->dev.of_node;
@@ -600,6 +602,14 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
sdhci_get_of_property(pdev);
+ pltfm_host = sdhci_priv(host);
+ esdhc = pltfm_host->priv;
+ if (esdhc->vendor_ver == VENDOR_V_22)
+ host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
+
+ if (esdhc->vendor_ver > VENDOR_V_22)
+ host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
+
if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
of_device_is_compatible(np, "fsl,p5020-esdhc") ||
of_device_is_compatible(np, "fsl,p4080-esdhc") ||
diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
index cf7ad45..cc851b0 100644
--- a/drivers/mmc/host/sdhci-pci-core.c
+++ b/drivers/mmc/host/sdhci-pci-core.c
@@ -277,7 +277,7 @@ static int spt_select_drive_strength(struct sdhci_host *host,
if (sdhci_pci_spt_drive_strength > 0)
drive_strength = sdhci_pci_spt_drive_strength & 0xf;
else
- drive_strength = 1; /* 33-ohm */
+ drive_strength = 0; /* Default 50-ohm */
if ((mmc_driver_type_mask(drive_strength) & card_drv) == 0)
drive_strength = 0; /* Default 50-ohm */
@@ -1464,7 +1464,7 @@ static int sdhci_pci_resume(struct device *dev)
static int sdhci_pci_runtime_suspend(struct device *dev)
{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
int i, ret;
@@ -1500,7 +1500,7 @@ err_pci_runtime_suspend:
static int sdhci_pci_runtime_resume(struct device *dev)
{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
struct sdhci_pci_chip *chip;
struct sdhci_pci_slot *slot;
int i, ret;
diff --git a/drivers/mmc/host/sdhci-pltfm.c b/drivers/mmc/host/sdhci-pltfm.c
index 87fb5ea..072bb27 100644
--- a/drivers/mmc/host/sdhci-pltfm.c
+++ b/drivers/mmc/host/sdhci-pltfm.c
@@ -104,7 +104,8 @@ void sdhci_get_of_property(struct platform_device *pdev)
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))
+ if (of_property_read_bool(np, "wakeup-source") ||
+ of_property_read_bool(np, "enable-sdio-wakeup")) /* legacy */
host->mmc->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
}
#else
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index ad28b49..83c4bf7 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -22,12 +22,20 @@
#include <linux/of_device.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/gpio/consumer.h>
#include "sdhci-pltfm.h"
/* Tegra SDHOST controller vendor register definitions */
+#define SDHCI_TEGRA_VENDOR_CLOCK_CTRL 0x100
+#define SDHCI_CLOCK_CTRL_TAP_MASK 0x00ff0000
+#define SDHCI_CLOCK_CTRL_TAP_SHIFT 16
+#define SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE BIT(5)
+#define SDHCI_CLOCK_CTRL_PADPIPE_CLKEN_OVERRIDE BIT(3)
+#define SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE BIT(2)
+
#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
@@ -37,9 +45,9 @@
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
-#define NVQUIRK_DISABLE_SDR50 BIT(3)
-#define NVQUIRK_DISABLE_SDR104 BIT(4)
-#define NVQUIRK_DISABLE_DDR50 BIT(5)
+#define NVQUIRK_ENABLE_SDR50 BIT(3)
+#define NVQUIRK_ENABLE_SDR104 BIT(4)
+#define NVQUIRK_ENABLE_DDR50 BIT(5)
struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata;
@@ -49,6 +57,7 @@ struct sdhci_tegra_soc_data {
struct sdhci_tegra {
const struct sdhci_tegra_soc_data *soc_data;
struct gpio_desc *power_gpio;
+ bool ddr_signaling;
};
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
@@ -124,25 +133,33 @@ static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv;
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
- u32 misc_ctrl;
+ u32 misc_ctrl, clk_ctrl;
sdhci_reset(host, mask);
if (!(mask & SDHCI_RESET_ALL))
return;
- misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+ misc_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
/* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
- /* Don't advertise UHS modes which aren't supported yet */
- if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)
- misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
- if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)
- misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
- if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104)
- misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
- sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+ /* Advertise UHS modes as supported by host */
+ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR50)
+ misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR50;
+ if (soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
+ misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_DDR50;
+ if (soc_data->nvquirks & NVQUIRK_ENABLE_SDR104)
+ misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDR104;
+ sdhci_writel(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
+
+ clk_ctrl = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+ clk_ctrl &= ~SDHCI_CLOCK_CTRL_SPI_MODE_CLKEN_OVERRIDE;
+ if (soc_data->nvquirks & SDHCI_MISC_CTRL_ENABLE_SDR50)
+ clk_ctrl |= SDHCI_CLOCK_CTRL_SDR50_TUNING_OVERRIDE;
+ sdhci_writel(host, clk_ctrl, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+
+ tegra_host->ddr_signaling = false;
}
static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
@@ -164,15 +181,99 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
+static void tegra_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ unsigned long host_clk;
+
+ if (!clock)
+ return;
+
+ host_clk = tegra_host->ddr_signaling ? clock * 2 : clock;
+ clk_set_rate(pltfm_host->clk, host_clk);
+ host->max_clk = clk_get_rate(pltfm_host->clk);
+
+ return sdhci_set_clock(host, clock);
+}
+
+static void tegra_sdhci_set_uhs_signaling(struct sdhci_host *host,
+ unsigned timing)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+
+ if (timing == MMC_TIMING_UHS_DDR50)
+ tegra_host->ddr_signaling = true;
+
+ return sdhci_set_uhs_signaling(host, timing);
+}
+
+static unsigned int tegra_sdhci_get_max_clock(struct sdhci_host *host)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+
+ /*
+ * DDR modes require the host to run at double the card frequency, so
+ * the maximum rate we can support is half of the module input clock.
+ */
+ return clk_round_rate(pltfm_host->clk, UINT_MAX) / 2;
+}
+
+static void tegra_sdhci_set_tap(struct sdhci_host *host, unsigned int tap)
+{
+ u32 reg;
+
+ reg = sdhci_readl(host, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+ reg &= ~SDHCI_CLOCK_CTRL_TAP_MASK;
+ reg |= tap << SDHCI_CLOCK_CTRL_TAP_SHIFT;
+ sdhci_writel(host, reg, SDHCI_TEGRA_VENDOR_CLOCK_CTRL);
+}
+
+static int tegra_sdhci_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ unsigned int min, max;
+
+ /*
+ * Start search for minimum tap value at 10, as smaller values are
+ * may wrongly be reported as working but fail at higher speeds,
+ * according to the TRM.
+ */
+ min = 10;
+ while (min < 255) {
+ tegra_sdhci_set_tap(host, min);
+ if (!mmc_send_tuning(host->mmc, opcode, NULL))
+ break;
+ min++;
+ }
+
+ /* Find the maximum tap value that still passes. */
+ max = min + 1;
+ while (max < 255) {
+ tegra_sdhci_set_tap(host, max);
+ if (mmc_send_tuning(host->mmc, opcode, NULL)) {
+ max--;
+ break;
+ }
+ max++;
+ }
+
+ /* The TRM states the ideal tap value is at 75% in the passing range. */
+ tegra_sdhci_set_tap(host, min + ((max - min) * 3 / 4));
+
+ return mmc_send_tuning(host->mmc, opcode, NULL);
+}
+
static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro,
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
- .set_clock = sdhci_set_clock,
+ .set_clock = tegra_sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width,
.reset = tegra_sdhci_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .platform_execute_tuning = tegra_sdhci_execute_tuning,
+ .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+ .get_max_clock = tegra_sdhci_get_max_clock,
};
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
@@ -184,7 +285,7 @@ static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
.ops = &tegra_sdhci_ops,
};
-static struct sdhci_tegra_soc_data soc_data_tegra20 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra20 = {
.pdata = &sdhci_tegra20_pdata,
.nvquirks = NVQUIRK_FORCE_SDHCI_SPEC_200 |
NVQUIRK_ENABLE_BLOCK_GAP_DET,
@@ -197,14 +298,15 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.ops = &tegra_sdhci_ops,
};
-static struct sdhci_tegra_soc_data soc_data_tegra30 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata,
.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
- NVQUIRK_DISABLE_SDR50 |
- NVQUIRK_DISABLE_SDR104,
+ NVQUIRK_ENABLE_SDR50 |
+ NVQUIRK_ENABLE_SDR104,
};
static const struct sdhci_ops tegra114_sdhci_ops = {
@@ -212,11 +314,12 @@ static const struct sdhci_ops tegra114_sdhci_ops = {
.read_w = tegra_sdhci_readw,
.write_w = tegra_sdhci_writew,
.write_l = tegra_sdhci_writel,
- .set_clock = sdhci_set_clock,
+ .set_clock = tegra_sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width,
.reset = tegra_sdhci_reset,
- .set_uhs_signaling = sdhci_set_uhs_signaling,
- .get_max_clock = sdhci_pltfm_clk_get_max_clock,
+ .platform_execute_tuning = tegra_sdhci_execute_tuning,
+ .set_uhs_signaling = tegra_sdhci_set_uhs_signaling,
+ .get_max_clock = tegra_sdhci_get_max_clock,
};
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
@@ -226,17 +329,34 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.ops = &tegra114_sdhci_ops,
};
-static struct sdhci_tegra_soc_data soc_data_tegra114 = {
+static const struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata,
- .nvquirks = NVQUIRK_DISABLE_SDR50 |
- NVQUIRK_DISABLE_DDR50 |
- NVQUIRK_DISABLE_SDR104,
+ .nvquirks = NVQUIRK_ENABLE_SDR50 |
+ NVQUIRK_ENABLE_DDR50 |
+ NVQUIRK_ENABLE_SDR104,
+};
+
+static const struct sdhci_pltfm_data sdhci_tegra210_pdata = {
+ .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
+ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
+ SDHCI_QUIRK_SINGLE_POWER_WRITE |
+ SDHCI_QUIRK_NO_HISPD_BIT |
+ SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
+ SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
+ .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
+ .ops = &tegra114_sdhci_ops,
+};
+
+static const struct sdhci_tegra_soc_data soc_data_tegra210 = {
+ .pdata = &sdhci_tegra210_pdata,
};
static const struct of_device_id sdhci_tegra_dt_match[] = {
+ { .compatible = "nvidia,tegra210-sdhci", .data = &soc_data_tegra210 },
{ .compatible = "nvidia,tegra124-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra114-sdhci", .data = &soc_data_tegra114 },
{ .compatible = "nvidia,tegra30-sdhci", .data = &soc_data_tegra30 },
@@ -271,6 +391,7 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
rc = -ENOMEM;
goto err_alloc_tegra_host;
}
+ tegra_host->ddr_signaling = false;
tegra_host->soc_data = soc_data;
pltfm_host->priv = tegra_host;
@@ -278,6 +399,9 @@ static int sdhci_tegra_probe(struct platform_device *pdev)
if (rc)
goto err_parse_dt;
+ if (tegra_host->soc_data->nvquirks & NVQUIRK_ENABLE_DDR50)
+ host->mmc->caps |= MMC_CAP_1_8V_DDR;
+
tegra_host->power_gpio = devm_gpiod_get_optional(&pdev->dev, "power",
GPIOD_OUT_HIGH);
if (IS_ERR(tegra_host->power_gpio)) {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index b48565e..d622435 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -492,7 +492,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
host->align_buffer, host->align_buffer_sz, direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
- BUG_ON(host->align_addr & host->align_mask);
+ BUG_ON(host->align_addr & SDHCI_ADMA2_MASK);
host->sg_count = sdhci_pre_dma_transfer(host, data);
if (host->sg_count < 0)
@@ -514,8 +514,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
* the (up to three) bytes that screw up the
* alignment.
*/
- offset = (host->align_sz - (addr & host->align_mask)) &
- host->align_mask;
+ offset = (SDHCI_ADMA2_ALIGN - (addr & SDHCI_ADMA2_MASK)) &
+ SDHCI_ADMA2_MASK;
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
@@ -529,8 +529,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(offset > 65536);
- align += host->align_sz;
- align_addr += host->align_sz;
+ align += SDHCI_ADMA2_ALIGN;
+ align_addr += SDHCI_ADMA2_ALIGN;
desc += host->desc_sz;
@@ -540,9 +540,12 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(len > 65536);
- /* tran, valid */
- sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
- desc += host->desc_sz;
+ if (len) {
+ /* tran, valid */
+ sdhci_adma_write_desc(host, desc, addr, len,
+ ADMA2_TRAN_VALID);
+ desc += host->desc_sz;
+ }
/*
* If this triggers then we have a calculation bug
@@ -608,7 +611,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
/* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned = false;
for_each_sg(data->sg, sg, host->sg_count, i)
- if (sg_dma_address(sg) & host->align_mask) {
+ if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
has_unaligned = true;
break;
}
@@ -620,15 +623,15 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
- if (sg_dma_address(sg) & host->align_mask) {
- size = host->align_sz -
- (sg_dma_address(sg) & host->align_mask);
+ if (sg_dma_address(sg) & SDHCI_ADMA2_MASK) {
+ size = SDHCI_ADMA2_ALIGN -
+ (sg_dma_address(sg) & SDHCI_ADMA2_MASK);
buffer = sdhci_kmap_atomic(sg, &flags);
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
- align += host->align_sz;
+ align += SDHCI_ADMA2_ALIGN;
}
}
}
@@ -768,8 +771,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
if (unlikely(broken)) {
for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->length & 0x3) {
- DBG("Reverting to PIO because of "
- "transfer size (%d)\n",
+ DBG("Reverting to PIO because of transfer size (%d)\n",
sg->length);
host->flags &= ~SDHCI_REQ_USE_DMA;
break;
@@ -803,8 +805,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
if (unlikely(broken)) {
for_each_sg(data->sg, sg, data->sg_len, i) {
if (sg->offset & 0x3) {
- DBG("Reverting to PIO because of "
- "bad alignment\n");
+ DBG("Reverting to PIO because of bad alignment\n");
host->flags &= ~SDHCI_REQ_USE_DMA;
break;
}
@@ -1016,8 +1017,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
while (sdhci_readl(host, SDHCI_PRESENT_STATE) & mask) {
if (timeout == 0) {
- pr_err("%s: Controller never released "
- "inhibit bit(s).\n", mmc_hostname(host->mmc));
+ pr_err("%s: Controller never released inhibit bit(s).\n",
+ mmc_hostname(host->mmc));
sdhci_dumpregs(host);
cmd->error = -EIO;
tasklet_schedule(&host->finish_tasklet);
@@ -1254,8 +1255,8 @@ clock_set:
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
& SDHCI_CLOCK_INT_STABLE)) {
if (timeout == 0) {
- pr_err("%s: Internal clock never "
- "stabilised.\n", mmc_hostname(host->mmc));
+ pr_err("%s: Internal clock never stabilised.\n",
+ mmc_hostname(host->mmc));
sdhci_dumpregs(host);
return;
}
@@ -1274,19 +1275,6 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
struct mmc_host *mmc = host->mmc;
u8 pwr = 0;
- if (!IS_ERR(mmc->supply.vmmc)) {
- spin_unlock_irq(&host->lock);
- mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
- spin_lock_irq(&host->lock);
-
- if (mode != MMC_POWER_OFF)
- sdhci_writeb(host, SDHCI_POWER_ON, SDHCI_POWER_CONTROL);
- else
- sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
-
- return;
- }
-
if (mode != MMC_POWER_OFF) {
switch (1 << vdd) {
case MMC_VDD_165_195:
@@ -1301,7 +1289,9 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
pwr = SDHCI_POWER_330;
break;
default:
- BUG();
+ WARN(1, "%s: Invalid vdd %#x\n",
+ mmc_hostname(host->mmc), vdd);
+ break;
}
}
@@ -1345,6 +1335,12 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
mdelay(10);
}
+
+ if (!IS_ERR(mmc->supply.vmmc)) {
+ spin_unlock_irq(&host->lock);
+ mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd);
+ spin_lock_irq(&host->lock);
+ }
}
/*****************************************************************************\
@@ -1540,8 +1536,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
else if (ios->drv_type == MMC_SET_DRIVER_TYPE_D)
ctrl_2 |= SDHCI_CTRL_DRV_TYPE_D;
else {
- pr_warn("%s: invalid driver type, default to "
- "driver type B\n", mmc_hostname(mmc));
+ pr_warn("%s: invalid driver type, default to driver type B\n",
+ mmc_hostname(mmc));
ctrl_2 |= SDHCI_CTRL_DRV_TYPE_B;
}
@@ -2015,10 +2011,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
spin_lock_irqsave(&host->lock, flags);
if (!host->tuning_done) {
- pr_info(DRIVER_NAME ": Timeout waiting for "
- "Buffer Read Ready interrupt during tuning "
- "procedure, falling back to fixed sampling "
- "clock\n");
+ pr_info(DRIVER_NAME ": Timeout waiting for Buffer Read Ready interrupt during tuning procedure, falling back to fixed sampling clock\n");
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl &= ~SDHCI_CTRL_TUNED_CLK;
ctrl &= ~SDHCI_CTRL_EXEC_TUNING;
@@ -2046,9 +2039,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
}
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
- pr_info(DRIVER_NAME ": Tuning procedure"
- " failed, falling back to fixed sampling"
- " clock\n");
+ pr_info(DRIVER_NAME ": Tuning procedure failed, falling back to fixed sampling clock\n");
err = -EIO;
}
@@ -2293,8 +2284,8 @@ static void sdhci_timeout_timer(unsigned long data)
spin_lock_irqsave(&host->lock, flags);
if (host->mrq) {
- pr_err("%s: Timeout waiting for hardware "
- "interrupt.\n", mmc_hostname(host->mmc));
+ pr_err("%s: Timeout waiting for hardware interrupt.\n",
+ mmc_hostname(host->mmc));
sdhci_dumpregs(host);
if (host->data) {
@@ -2325,9 +2316,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
BUG_ON(intmask == 0);
if (!host->cmd) {
- pr_err("%s: Got command interrupt 0x%08x even "
- "though no command operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
+ pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
}
@@ -2356,8 +2346,7 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
*/
if (host->cmd->flags & MMC_RSP_BUSY) {
if (host->cmd->data)
- DBG("Cannot wait for busy signal when also "
- "doing a data transfer");
+ DBG("Cannot wait for busy signal when also doing a data transfer");
else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ)
&& !host->busy_handle) {
/* Mark that command complete before busy is ended */
@@ -2451,9 +2440,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
- pr_err("%s: Got data interrupt 0x%08x even "
- "though no data operation was in progress.\n",
- mmc_hostname(host->mmc), (unsigned)intmask);
+ pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n",
+ mmc_hostname(host->mmc), (unsigned)intmask);
sdhci_dumpregs(host);
return;
@@ -2760,7 +2748,7 @@ static int sdhci_runtime_pm_put(struct sdhci_host *host)
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
{
- if (host->runtime_suspended || host->bus_on)
+ if (host->bus_on)
return;
host->bus_on = true;
pm_runtime_get_noresume(host->mmc->parent);
@@ -2768,7 +2756,7 @@ static void sdhci_runtime_pm_bus_on(struct sdhci_host *host)
static void sdhci_runtime_pm_bus_off(struct sdhci_host *host)
{
- if (host->runtime_suspended || !host->bus_on)
+ if (!host->bus_on)
return;
host->bus_on = false;
pm_runtime_put_noidle(host->mmc->parent);
@@ -2896,9 +2884,8 @@ int sdhci_add_host(struct sdhci_host *host)
host->version = (host->version & SDHCI_SPEC_VER_MASK)
>> SDHCI_SPEC_VER_SHIFT;
if (host->version > SDHCI_SPEC_300) {
- pr_err("%s: Unknown controller version (%d). "
- "You may experience problems.\n", mmc_hostname(mmc),
- host->version);
+ pr_err("%s: Unknown controller version (%d). You may experience problems.\n",
+ mmc_hostname(mmc), host->version);
}
caps[0] = (host->quirks & SDHCI_QUIRK_MISSING_CAPS) ? host->caps :
@@ -2967,24 +2954,17 @@ int sdhci_add_host(struct sdhci_host *host)
if (host->flags & SDHCI_USE_64_BIT_DMA) {
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
SDHCI_ADMA2_64_DESC_SZ;
- host->align_buffer_sz = SDHCI_MAX_SEGS *
- SDHCI_ADMA2_64_ALIGN;
host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
- host->align_sz = SDHCI_ADMA2_64_ALIGN;
- host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
} else {
host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
SDHCI_ADMA2_32_DESC_SZ;
- host->align_buffer_sz = SDHCI_MAX_SEGS *
- SDHCI_ADMA2_32_ALIGN;
host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
- host->align_sz = SDHCI_ADMA2_32_ALIGN;
- host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
}
host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
host->adma_table_sz,
&host->adma_addr,
GFP_KERNEL);
+ host->align_buffer_sz = SDHCI_MAX_SEGS * SDHCI_ADMA2_ALIGN;
host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
if (!host->adma_table || !host->align_buffer) {
if (host->adma_table)
@@ -2998,7 +2978,7 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_ADMA;
host->adma_table = NULL;
host->align_buffer = NULL;
- } else if (host->adma_addr & host->align_mask) {
+ } else if (host->adma_addr & (SDHCI_ADMA2_DESC_ALIGN - 1)) {
pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA;
@@ -3031,8 +3011,8 @@ int sdhci_add_host(struct sdhci_host *host)
if (host->max_clk == 0 || host->quirks &
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN) {
if (!host->ops->get_max_clock) {
- pr_err("%s: Hardware doesn't specify base clock "
- "frequency.\n", mmc_hostname(mmc));
+ pr_err("%s: Hardware doesn't specify base clock frequency.\n",
+ mmc_hostname(mmc));
return -ENODEV;
}
host->max_clk = host->ops->get_max_clock(host);
@@ -3294,8 +3274,8 @@ int sdhci_add_host(struct sdhci_host *host)
mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
if (mmc->ocr_avail == 0) {
- pr_err("%s: Hardware doesn't report any "
- "support voltages.\n", mmc_hostname(mmc));
+ pr_err("%s: Hardware doesn't report any support voltages.\n",
+ mmc_hostname(mmc));
return -ENODEV;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 9d4aa31..7654ae5 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -272,22 +272,27 @@
/* ADMA2 32-bit DMA descriptor size */
#define SDHCI_ADMA2_32_DESC_SZ 8
-/* ADMA2 32-bit DMA alignment */
-#define SDHCI_ADMA2_32_ALIGN 4
-
/* ADMA2 32-bit descriptor */
struct sdhci_adma2_32_desc {
__le16 cmd;
__le16 len;
__le32 addr;
-} __packed __aligned(SDHCI_ADMA2_32_ALIGN);
+} __packed __aligned(4);
+
+/* ADMA2 data alignment */
+#define SDHCI_ADMA2_ALIGN 4
+#define SDHCI_ADMA2_MASK (SDHCI_ADMA2_ALIGN - 1)
+
+/*
+ * ADMA2 descriptor alignment. Some controllers (e.g. Intel) require 8 byte
+ * alignment for the descriptor table even in 32-bit DMA mode. Memory
+ * allocation is at least 8 byte aligned anyway, so just stipulate 8 always.
+ */
+#define SDHCI_ADMA2_DESC_ALIGN 8
/* ADMA2 64-bit DMA descriptor size */
#define SDHCI_ADMA2_64_DESC_SZ 12
-/* ADMA2 64-bit DMA alignment */
-#define SDHCI_ADMA2_64_ALIGN 8
-
/*
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
* aligned.
@@ -482,8 +487,6 @@ struct sdhci_host {
dma_addr_t align_addr; /* Mapped bounce buffer */
unsigned int desc_sz; /* ADMA descriptor size */
- unsigned int align_sz; /* ADMA alignment */
- unsigned int align_mask; /* ADMA alignment mask */
struct tasklet_struct finish_tasklet; /* Tasklet structures */
diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index ad9ffea..1ca8a13 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -397,38 +397,26 @@ static void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host)
}
static struct dma_chan *
-sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
- struct sh_mmcif_plat_data *pdata,
- enum dma_transfer_direction direction)
+sh_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id)
{
- struct dma_slave_config cfg = { 0, };
- struct dma_chan *chan;
- void *slave_data = NULL;
- struct resource *res;
- struct device *dev = sh_mmcif_host_to_dev(host);
dma_cap_mask_t mask;
- int ret;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
+ if (slave_id <= 0)
+ return NULL;
- if (pdata)
- slave_data = direction == DMA_MEM_TO_DEV ?
- (void *)pdata->slave_id_tx :
- (void *)pdata->slave_id_rx;
-
- chan = dma_request_slave_channel_compat(mask, shdma_chan_filter,
- slave_data, dev,
- direction == DMA_MEM_TO_DEV ? "tx" : "rx");
-
- dev_dbg(dev, "%s: %s: got channel %p\n", __func__,
- direction == DMA_MEM_TO_DEV ? "TX" : "RX", chan);
+ return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id);
+}
- if (!chan)
- return NULL;
+static int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host,
+ struct dma_chan *chan,
+ enum dma_transfer_direction direction)
+{
+ struct resource *res;
+ struct dma_slave_config cfg = { 0, };
res = platform_get_resource(host->pd, IORESOURCE_MEM, 0);
-
cfg.direction = direction;
if (direction == DMA_DEV_TO_MEM) {
@@ -439,38 +427,42 @@ sh_mmcif_request_dma_one(struct sh_mmcif_host *host,
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
}
- ret = dmaengine_slave_config(chan, &cfg);
- if (ret < 0) {
- dma_release_channel(chan);
- return NULL;
- }
-
- return chan;
+ return dmaengine_slave_config(chan, &cfg);
}
-static void sh_mmcif_request_dma(struct sh_mmcif_host *host,
- struct sh_mmcif_plat_data *pdata)
+static void sh_mmcif_request_dma(struct sh_mmcif_host *host)
{
struct device *dev = sh_mmcif_host_to_dev(host);
host->dma_active = false;
- if (pdata) {
- if (pdata->slave_id_tx <= 0 || pdata->slave_id_rx <= 0)
- return;
- } else if (!dev->of_node) {
- return;
+ /* We can only either use DMA for both Tx and Rx or not use it at all */
+ if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) {
+ struct sh_mmcif_plat_data *pdata = dev->platform_data;
+
+ host->chan_tx = sh_mmcif_request_dma_pdata(host,
+ pdata->slave_id_tx);
+ host->chan_rx = sh_mmcif_request_dma_pdata(host,
+ pdata->slave_id_rx);
+ } else {
+ host->chan_tx = dma_request_slave_channel(dev, "tx");
+ host->chan_tx = dma_request_slave_channel(dev, "rx");
}
+ dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx,
+ host->chan_rx);
- /* We can only either use DMA for both Tx and Rx or not use it at all */
- host->chan_tx = sh_mmcif_request_dma_one(host, pdata, DMA_MEM_TO_DEV);
- if (!host->chan_tx)
- return;
+ if (!host->chan_tx || !host->chan_rx ||
+ sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) ||
+ sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM))
+ goto error;
- host->chan_rx = sh_mmcif_request_dma_one(host, pdata, DMA_DEV_TO_MEM);
- if (!host->chan_rx) {
+ return;
+
+error:
+ if (host->chan_tx)
dma_release_channel(host->chan_tx);
- host->chan_tx = NULL;
- }
+ if (host->chan_rx)
+ dma_release_channel(host->chan_rx);
+ host->chan_tx = host->chan_rx = NULL;
}
static void sh_mmcif_release_dma(struct sh_mmcif_host *host)
@@ -1102,7 +1094,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->power_mode == MMC_POWER_UP) {
if (!host->card_present) {
/* See if we also get DMA */
- sh_mmcif_request_dma(host, dev->platform_data);
+ sh_mmcif_request_dma(host);
host->card_present = true;
}
sh_mmcif_set_power(host, ios);
diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
index 4498e92..b47122d 100644
--- a/drivers/mmc/host/usdhi6rol0.c
+++ b/drivers/mmc/host/usdhi6rol0.c
@@ -1634,7 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
struct mmc_request *mrq = host->mrq;
struct mmc_data *data = mrq ? mrq->data : NULL;
- struct scatterlist *sg = host->sg ?: data->sg;
+ struct scatterlist *sg;
dev_warn(mmc_dev(host->mmc),
"%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
@@ -1666,6 +1666,7 @@ static void usdhi6_timeout_work(struct work_struct *work)
case USDHI6_WAIT_FOR_MWRITE:
case USDHI6_WAIT_FOR_READ:
case USDHI6_WAIT_FOR_WRITE:
+ sg = host->sg ?: data->sg;
dev_dbg(mmc_dev(host->mmc),
"%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n",
data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index 3dad211..70bb403 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -30,7 +30,7 @@
struct pcmciamtd_dev {
struct pcmcia_device *p_dev;
- caddr_t win_base; /* ioremapped address of PCMCIA window */
+ void __iomem *win_base; /* ioremapped address of PCMCIA window */
unsigned int win_size; /* size of window */
unsigned int offset; /* offset into card the window currently points at */
struct map_info pcmcia_map;
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)")
/* read/write{8,16} copy_{from,to} routines with window remapping
* to access whole card
*/
-static caddr_t remap_window(struct map_info *map, unsigned long to)
+static void __iomem *remap_window(struct map_info *map, unsigned long to)
{
struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
struct resource *win = (struct resource *) map->map_priv_2;
@@ -107,7 +107,7 @@ static caddr_t remap_window(struct map_info *map, unsigned long to)
static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
{
- caddr_t addr;
+ void __iomem *addr;
map_word d = {{0}};
addr = remap_window(map, ofs);
@@ -122,7 +122,7 @@ static map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
static map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
{
- caddr_t addr;
+ void __iomem *addr;
map_word d = {{0}};
addr = remap_window(map, ofs);
@@ -143,7 +143,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long
pr_debug("to = %p from = %lu len = %zd\n", to, from, len);
while(len) {
int toread = win_size - (from & (win_size-1));
- caddr_t addr;
+ void __iomem *addr;
if(toread > len)
toread = len;
@@ -163,7 +163,7 @@ static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long
static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long adr)
{
- caddr_t addr = remap_window(map, adr);
+ void __iomem *addr = remap_window(map, adr);
if(!addr)
return;
@@ -175,7 +175,7 @@ static void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long
static void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long adr)
{
- caddr_t addr = remap_window(map, adr);
+ void __iomem *addr = remap_window(map, adr);
if(!addr)
return;
@@ -192,7 +192,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v
pr_debug("to = %lu from = %p len = %zd\n", to, from, len);
while(len) {
int towrite = win_size - (to & (win_size-1));
- caddr_t addr;
+ void __iomem *addr;
if(towrite > len)
towrite = len;
@@ -216,7 +216,7 @@ static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const v
static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
map_word d = {{0}};
if(DEV_REMOVED(map))
@@ -231,7 +231,7 @@ static map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
map_word d = {{0}};
if(DEV_REMOVED(map))
@@ -246,7 +246,7 @@ static map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
if(DEV_REMOVED(map))
return;
@@ -258,7 +258,7 @@ static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from,
static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
if(DEV_REMOVED(map))
return;
@@ -271,7 +271,7 @@ static void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr)
static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
if(DEV_REMOVED(map))
return;
@@ -284,7 +284,7 @@ static void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr)
static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
- caddr_t win_base = (caddr_t)map->map_priv_2;
+ void __iomem *win_base = (void __iomem *)map->map_priv_2;
if(DEV_REMOVED(map))
return;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 95c13b2..ffa2884 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -426,15 +426,6 @@ int add_mtd_device(struct mtd_info *mtd)
mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
- if (mtd->dev.parent) {
- if (!mtd->owner && mtd->dev.parent->driver)
- mtd->owner = mtd->dev.parent->driver->owner;
- if (!mtd->name)
- mtd->name = dev_name(mtd->dev.parent);
- } else {
- pr_debug("mtd device won't show a device symlink in sysfs\n");
- }
-
/* Some chips always power up locked. Unlock them now */
if ((mtd->flags & MTD_WRITEABLE) && (mtd->flags & MTD_POWERUP_LOCK)) {
error = mtd_unlock(mtd, 0, mtd->size);
@@ -549,6 +540,21 @@ static int mtd_add_device_partitions(struct mtd_info *mtd,
return 0;
}
+/*
+ * Set a few defaults based on the parent devices, if not provided by the
+ * driver
+ */
+static void mtd_set_dev_defaults(struct mtd_info *mtd)
+{
+ if (mtd->dev.parent) {
+ if (!mtd->owner && mtd->dev.parent->driver)
+ mtd->owner = mtd->dev.parent->driver->owner;
+ if (!mtd->name)
+ mtd->name = dev_name(mtd->dev.parent);
+ } else {
+ pr_debug("mtd device won't show a device symlink in sysfs\n");
+ }
+}
/**
* mtd_device_parse_register - parse partitions and register an MTD device.
@@ -587,6 +593,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
int ret;
struct mtd_partition *real_parts = NULL;
+ mtd_set_dev_defaults(mtd);
+
ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
if (ret <= 0 && nr_parts && parts) {
real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index dc4e844..5a99a93 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -25,6 +25,7 @@
#include <linux/gpio.h>
+#include <asm/mach-jz4740/gpio.h>
#include <asm/mach-jz4740/jz4740_nand.h>
#define JZ_REG_NAND_CTRL 0x50
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index cc74142..ece544e 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -3110,7 +3110,7 @@ static void nand_resume(struct mtd_info *mtd)
*/
static void nand_shutdown(struct mtd_info *mtd)
{
- nand_get_device(mtd, FL_SHUTDOWN);
+ nand_get_device(mtd, FL_PM_SUSPENDED);
}
/* Set default functions */
diff --git a/drivers/mtd/ofpart.c b/drivers/mtd/ofpart.c
index 669c345..9ed6038 100644
--- a/drivers/mtd/ofpart.c
+++ b/drivers/mtd/ofpart.c
@@ -46,10 +46,18 @@ static int parse_ofpart_partitions(struct mtd_info *master,
ofpart_node = of_get_child_by_name(mtd_node, "partitions");
if (!ofpart_node) {
- pr_warn("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
- master->name, mtd_node->full_name);
+ /*
+ * We might get here even when ofpart isn't used at all (e.g.,
+ * when using another parser), so don't be louder than
+ * KERN_DEBUG
+ */
+ pr_debug("%s: 'partitions' subnode not found on %s. Trying to parse direct subnodes as partitions.\n",
+ master->name, mtd_node->full_name);
ofpart_node = mtd_node;
dedicated = false;
+ } else if (!of_device_is_compatible(ofpart_node, "fixed-partitions")) {
+ /* The 'partitions' subnode might be used by another parser */
+ return 0;
}
/* First count the subnodes */
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4988390..32477c4 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -516,8 +516,8 @@ static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
status_old = read_sr(nor);
/* Cannot unlock; would unlock larger region than requested */
- if (stm_is_locked_sr(nor, status_old, ofs - mtd->erasesize,
- mtd->erasesize))
+ if (stm_is_locked_sr(nor, ofs - mtd->erasesize, mtd->erasesize,
+ status_old))
return -EINVAL;
/*
@@ -1200,8 +1200,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
- JEDEC_MFR(info) == SNOR_MFR_SST ||
- JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+ JEDEC_MFR(info) == SNOR_MFR_SST) {
write_enable(nor);
write_sr(nor, 0);
}
@@ -1217,8 +1216,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
mtd->_read = spi_nor_read;
/* NOR protection support for STmicro/Micron chips and similar */
- if (JEDEC_MFR(info) == SNOR_MFR_MICRON ||
- JEDEC_MFR(info) == SNOR_MFR_WINBOND) {
+ if (JEDEC_MFR(info) == SNOR_MFR_MICRON) {
nor->flash_lock = stm_lock;
nor->flash_unlock = stm_unlock;
nor->flash_is_locked = stm_is_locked;
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
index 68eea5b..c1aaf03 100644
--- a/drivers/mtd/ubi/attach.c
+++ b/drivers/mtd/ubi/attach.c
@@ -1209,9 +1209,7 @@ static void destroy_ai(struct ubi_attach_info *ai)
}
}
- if (ai->aeb_slab_cache)
- kmem_cache_destroy(ai->aeb_slab_cache);
-
+ kmem_cache_destroy(ai->aeb_slab_cache);
kfree(ai);
}
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index d16fccf..54e056d 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -949,7 +949,7 @@ static long ubi_cdev_ioctl(struct file *file, unsigned int cmd,
if (!req) {
err = -ENOMEM;
break;
- };
+ }
err = copy_from_user(req, argp, sizeof(struct ubi_rnvol_req));
if (err) {
diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c
index b077e43..c4cb15a 100644
--- a/drivers/mtd/ubi/debug.c
+++ b/drivers/mtd/ubi/debug.c
@@ -236,7 +236,7 @@ int ubi_debugfs_init(void)
dfs_rootdir = debugfs_create_dir("ubi", NULL);
if (IS_ERR_OR_NULL(dfs_rootdir)) {
- int err = dfs_rootdir ? -ENODEV : PTR_ERR(dfs_rootdir);
+ int err = dfs_rootdir ? PTR_ERR(dfs_rootdir) : -ENODEV;
pr_err("UBI error: cannot create \"ubi\" debugfs directory, error %d\n",
err);
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index 51bca03..5b9834c 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -1358,7 +1358,7 @@ int self_check_eba(struct ubi_device *ubi, struct ubi_attach_info *ai_fastmap,
continue;
ubi_err(ubi, "LEB:%i:%i is PEB:%i instead of %i!",
- vol->vol_id, i, fm_eba[i][j],
+ vol->vol_id, j, fm_eba[i][j],
scan_eba[i][j]);
ubi_assert(0);
}
diff --git a/drivers/mtd/ubi/fastmap-wl.c b/drivers/mtd/ubi/fastmap-wl.c
index b2a6653..30d3999 100644
--- a/drivers/mtd/ubi/fastmap-wl.c
+++ b/drivers/mtd/ubi/fastmap-wl.c
@@ -172,6 +172,30 @@ void ubi_refill_pools(struct ubi_device *ubi)
}
/**
+ * produce_free_peb - produce a free physical eraseblock.
+ * @ubi: UBI device description object
+ *
+ * This function tries to make a free PEB by means of synchronous execution of
+ * pending works. This may be needed if, for example the background thread is
+ * disabled. Returns zero in case of success and a negative error code in case
+ * of failure.
+ */
+static int produce_free_peb(struct ubi_device *ubi)
+{
+ int err;
+
+ while (!ubi->free.rb_node && ubi->works_count) {
+ dbg_wl("do one work synchronously");
+ err = do_work(ubi);
+
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/**
* ubi_wl_get_peb - get a physical eraseblock.
* @ubi: UBI device description object
*
@@ -213,6 +237,11 @@ again:
}
retried = 1;
up_read(&ubi->fm_eba_sem);
+ ret = produce_free_peb(ubi);
+ if (ret < 0) {
+ down_read(&ubi->fm_eba_sem);
+ goto out;
+ }
goto again;
}
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index 4aa2fd8..263b439 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -450,7 +450,7 @@ static void unmap_peb(struct ubi_attach_info *ai, int pnum)
* < 0 indicates an internal error.
*/
static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai,
- int *pebs, int pool_size, unsigned long long *max_sqnum,
+ __be32 *pebs, int pool_size, unsigned long long *max_sqnum,
struct list_head *free)
{
struct ubi_vid_hdr *vh;
@@ -775,7 +775,7 @@ static int ubi_attach_fastmap(struct ubi_device *ubi,
for (j = 0; j < be32_to_cpu(fm_eba->reserved_pebs); j++) {
int pnum = be32_to_cpu(fm_eba->pnum[j]);
- if ((int)be32_to_cpu(fm_eba->pnum[j]) < 0)
+ if (pnum < 0)
continue;
aeb = NULL;
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 1fc23e4..10cf3b5 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1299,7 +1299,7 @@ static int self_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum)
if (err && err != UBI_IO_BITFLIPS && !mtd_is_eccerr(err))
goto exit;
- crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC);
+ crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC);
hdr_crc = be32_to_cpu(vid_hdr->hdr_crc);
if (hdr_crc != crc) {
ubi_err(ubi, "bad VID header CRC at PEB %d, calculated %#08x, read %#08x",
diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h
index d0d072e..22ed3f6 100644
--- a/drivers/mtd/ubi/ubi-media.h
+++ b/drivers/mtd/ubi/ubi-media.h
@@ -500,7 +500,7 @@ struct ubi_fm_volhdr {
/* struct ubi_fm_volhdr is followed by one struct ubi_fm_eba records */
/**
- * struct ubi_fm_eba - denotes an association beween a PEB and LEB
+ * struct ubi_fm_eba - denotes an association between a PEB and LEB
* @magic: EBA table magic number
* @reserved_pebs: number of table entries
* @pnum: PEB number of LEB (LEB is the index)
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index eb4489f9..5606563 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -603,6 +603,7 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
return 0;
}
+static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk);
/**
* do_sync_erase - run the erase worker synchronously.
* @ubi: UBI device description object
@@ -615,20 +616,16 @@ static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
static int do_sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e,
int vol_id, int lnum, int torture)
{
- struct ubi_work *wl_wrk;
+ struct ubi_work wl_wrk;
dbg_wl("sync erase of PEB %i", e->pnum);
- wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS);
- if (!wl_wrk)
- return -ENOMEM;
-
- wl_wrk->e = e;
- wl_wrk->vol_id = vol_id;
- wl_wrk->lnum = lnum;
- wl_wrk->torture = torture;
+ wl_wrk.e = e;
+ wl_wrk.vol_id = vol_id;
+ wl_wrk.lnum = lnum;
+ wl_wrk.torture = torture;
- return erase_worker(ubi, wl_wrk, 0);
+ return __erase_worker(ubi, &wl_wrk);
}
/**
@@ -1014,7 +1011,7 @@ out_unlock:
}
/**
- * erase_worker - physical eraseblock erase worker function.
+ * __erase_worker - physical eraseblock erase worker function.
* @ubi: UBI device description object
* @wl_wrk: the work object
* @shutdown: non-zero if the worker has to free memory and exit
@@ -1025,8 +1022,7 @@ out_unlock:
* needed. Returns zero in case of success and a negative error code in case of
* failure.
*/
-static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
- int shutdown)
+static int __erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk)
{
struct ubi_wl_entry *e = wl_wrk->e;
int pnum = e->pnum;
@@ -1034,21 +1030,11 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
int lnum = wl_wrk->lnum;
int err, available_consumed = 0;
- if (shutdown) {
- dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec);
- kfree(wl_wrk);
- wl_entry_destroy(ubi, e);
- return 0;
- }
-
dbg_wl("erase PEB %d EC %d LEB %d:%d",
pnum, e->ec, wl_wrk->vol_id, wl_wrk->lnum);
err = sync_erase(ubi, e, wl_wrk->torture);
if (!err) {
- /* Fine, we've erased it successfully */
- kfree(wl_wrk);
-
spin_lock(&ubi->wl_lock);
wl_tree_add(e, &ubi->free);
ubi->free_count++;
@@ -1066,7 +1052,6 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
}
ubi_err(ubi, "failed to erase PEB %d, error %d", pnum, err);
- kfree(wl_wrk);
if (err == -EINTR || err == -ENOMEM || err == -EAGAIN ||
err == -EBUSY) {
@@ -1075,6 +1060,7 @@ static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
/* Re-schedule the LEB for erasure */
err1 = schedule_erase(ubi, e, vol_id, lnum, 0);
if (err1) {
+ wl_entry_destroy(ubi, e);
err = err1;
goto out_ro;
}
@@ -1150,6 +1136,25 @@ out_ro:
return err;
}
+static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk,
+ int shutdown)
+{
+ int ret;
+
+ if (shutdown) {
+ struct ubi_wl_entry *e = wl_wrk->e;
+
+ dbg_wl("cancel erasure of PEB %d EC %d", e->pnum, e->ec);
+ kfree(wl_wrk);
+ wl_entry_destroy(ubi, e);
+ return 0;
+ }
+
+ ret = __erase_worker(ubi, wl_wrk);
+ kfree(wl_wrk);
+ return ret;
+}
+
/**
* ubi_wl_put_peb - return a PEB to the wear-leveling sub-system.
* @ubi: UBI device description object
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index b4351ca..9e0f8a7 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -1749,6 +1749,7 @@ err_undo_flags:
slave_dev->dev_addr))
eth_hw_addr_random(bond_dev);
if (bond_dev->type != ARPHRD_ETHER) {
+ dev_close(bond_dev);
ether_setup(bond_dev);
bond_dev->flags |= IFF_MASTER;
bond_dev->priv_flags &= ~IFF_TX_SKB_SHARING;
diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c
index de39620..4721948 100644
--- a/drivers/net/caif/caif_spi.c
+++ b/drivers/net/caif/caif_spi.c
@@ -730,11 +730,14 @@ int cfspi_spi_probe(struct platform_device *pdev)
int res;
dev = (struct cfspi_dev *)pdev->dev.platform_data;
- ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d",
- NET_NAME_UNKNOWN, cfspi_setup);
if (!dev)
return -ENODEV;
+ ndev = alloc_netdev(sizeof(struct cfspi), "cfspi%d",
+ NET_NAME_UNKNOWN, cfspi_setup);
+ if (!ndev)
+ return -ENOMEM;
+
cfspi = netdev_priv(ndev);
netif_stop_queue(ndev);
cfspi->ndev = ndev;
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 57dadd5..1deb8ff 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -501,8 +501,6 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
cf->data[2] |= CAN_ERR_PROT_FORM;
else if (status & SER)
cf->data[2] |= CAN_ERR_PROT_STUFF;
- else
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
}
priv->can.state = state;
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index 5d214d1..f91b094 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -962,7 +962,6 @@ static int c_can_handle_bus_err(struct net_device *dev,
* type of the last error to occur on the CAN bus
*/
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
switch (lec_type) {
case LEC_STUFF_ERROR:
@@ -975,8 +974,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
break;
case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n");
- cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
- CAN_ERR_PROT_LOC_ACK_DEL);
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
break;
case LEC_BIT1_ERROR:
netdev_dbg(dev, "bit1 error\n");
@@ -988,8 +986,7 @@ static int c_can_handle_bus_err(struct net_device *dev,
break;
case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n");
- cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL);
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
break;
default:
break;
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index 70a8cbb..1e37313 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -578,7 +578,7 @@ static int cc770_err(struct net_device *dev, u8 status)
cf->data[2] |= CAN_ERR_PROT_BIT0;
break;
case STAT_LEC_CRC:
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
break;
}
}
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 868fe94..41c0fc9 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -535,13 +535,13 @@ static void do_bus_err(struct net_device *dev,
if (reg_esr & FLEXCAN_ESR_ACK_ERR) {
netdev_dbg(dev, "ACK_ERR irq\n");
cf->can_id |= CAN_ERR_ACK;
- cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
tx_errors = 1;
}
if (reg_esr & FLEXCAN_ESR_CRC_ERR) {
netdev_dbg(dev, "CRC_ERR irq\n");
cf->data[2] |= CAN_ERR_PROT_BIT;
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
rx_errors = 1;
}
if (reg_esr & FLEXCAN_ESR_FRM_ERR) {
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index c1e8536..5d04f54 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1096,7 +1096,6 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & ECC_SEG;
break;
}
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index ef65517..39cf911 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -487,7 +487,6 @@ static int m_can_handle_lec_err(struct net_device *dev,
* type of the last error to occur on the CAN bus
*/
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
switch (lec_type) {
case LEC_STUFF_ERROR:
@@ -500,8 +499,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
break;
case LEC_ACK_ERROR:
netdev_dbg(dev, "ack error\n");
- cf->data[3] |= (CAN_ERR_PROT_LOC_ACK |
- CAN_ERR_PROT_LOC_ACK_DEL);
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
break;
case LEC_BIT1_ERROR:
netdev_dbg(dev, "bit1 error\n");
@@ -513,8 +511,7 @@ static int m_can_handle_lec_err(struct net_device *dev,
break;
case LEC_CRC_ERROR:
netdev_dbg(dev, "CRC error\n");
- cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL);
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
break;
default:
break;
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index e187ca7..c131788 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -559,8 +559,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
stats->rx_errors++;
break;
case PCH_CRC_ERR:
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
priv->can.can_stats.bus_error++;
stats->rx_errors++;
break;
diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c
index 7bd5419..bc46be3 100644
--- a/drivers/net/can/rcar_can.c
+++ b/drivers/net/can/rcar_can.c
@@ -241,17 +241,16 @@ static void rcar_can_error(struct net_device *ndev)
u8 ecsr;
netdev_dbg(priv->ndev, "Bus error interrupt:\n");
- if (skb) {
+ if (skb)
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
- cf->data[2] = CAN_ERR_PROT_UNSPEC;
- }
+
ecsr = readb(&priv->regs->ecsr);
if (ecsr & RCAR_CAN_ECSR_ADEF) {
netdev_dbg(priv->ndev, "ACK Delimiter Error\n");
tx_errors++;
writeb(~RCAR_CAN_ECSR_ADEF, &priv->regs->ecsr);
if (skb)
- cf->data[3] |= CAN_ERR_PROT_LOC_ACK_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK_DEL;
}
if (ecsr & RCAR_CAN_ECSR_BE0F) {
netdev_dbg(priv->ndev, "Bit Error (dominant)\n");
@@ -272,7 +271,7 @@ static void rcar_can_error(struct net_device *ndev)
rx_errors++;
writeb(~RCAR_CAN_ECSR_CEF, &priv->regs->ecsr);
if (skb)
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
}
if (ecsr & RCAR_CAN_ECSR_AEF) {
netdev_dbg(priv->ndev, "ACK Error\n");
@@ -280,7 +279,7 @@ static void rcar_can_error(struct net_device *ndev)
writeb(~RCAR_CAN_ECSR_AEF, &priv->regs->ecsr);
if (skb) {
cf->can_id |= CAN_ERR_ACK;
- cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
}
}
if (ecsr & RCAR_CAN_ECSR_FEF) {
diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c
index 7b92e91..8dda3b7 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -218,6 +218,9 @@ static void sja1000_start(struct net_device *dev)
priv->write_reg(priv, SJA1000_RXERR, 0x0);
priv->read_reg(priv, SJA1000_ECC);
+ /* clear interrupt flags */
+ priv->read_reg(priv, SJA1000_IR);
+
/* leave reset mode */
set_normal_mode(dev);
}
@@ -446,7 +449,6 @@ static int sja1000_err(struct net_device *dev, uint8_t isrc, uint8_t status)
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & ECC_SEG;
break;
}
diff --git a/drivers/net/can/sun4i_can.c b/drivers/net/can/sun4i_can.c
index d9a42c6..68ef0a4 100644
--- a/drivers/net/can/sun4i_can.c
+++ b/drivers/net/can/sun4i_can.c
@@ -575,7 +575,6 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = (ecc & SUN4I_STA_ERR_SEG_CODE)
>> 16;
break;
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index cf345cb..680d1ff 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -722,7 +722,6 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
if (err_status & HECC_BUS_ERROR) {
++priv->can.can_stats.bus_error;
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
if (err_status & HECC_CANES_FE) {
hecc_set_bit(priv, HECC_CANES, HECC_CANES_FE);
cf->data[2] |= CAN_ERR_PROT_FORM;
@@ -737,13 +736,11 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
}
if (err_status & HECC_CANES_CRCE) {
hecc_set_bit(priv, HECC_CANES, HECC_CANES_CRCE);
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
}
if (err_status & HECC_CANES_ACKE) {
hecc_set_bit(priv, HECC_CANES, HECC_CANES_ACKE);
- cf->data[3] |= CAN_ERR_PROT_LOC_ACK |
- CAN_ERR_PROT_LOC_ACK_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
}
}
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 2d39038..fc5b756 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -377,7 +377,6 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & SJA1000_ECC_SEG;
break;
}
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index 0e5a449..113e64f 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -282,7 +282,6 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
cf->data[2] |= CAN_ERR_PROT_STUFF;
break;
default:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
cf->data[3] = ecc & SJA1000_ECC_SEG;
break;
}
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 8b17a90..022bfa1 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -944,10 +944,9 @@ static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
if (es->leaf.error_factor & M16C_EF_ACKE)
- cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
if (es->leaf.error_factor & M16C_EF_CRCE)
- cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL);
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
if (es->leaf.error_factor & M16C_EF_FORME)
cf->data[2] |= CAN_ERR_PROT_FORM;
if (es->leaf.error_factor & M16C_EF_STFE)
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index de95b1c..a731720 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -401,9 +401,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
tx_errors = 1;
break;
case USB_8DEV_STATUSMSG_CRC:
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
- cf->data[3] |= CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
rx_errors = 1;
break;
case USB_8DEV_STATUSMSG_BIT0:
diff --git a/drivers/net/can/xilinx_can.c b/drivers/net/can/xilinx_can.c
index fc55e8e..51670b3 100644
--- a/drivers/net/can/xilinx_can.c
+++ b/drivers/net/can/xilinx_can.c
@@ -608,17 +608,15 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
/* Check for error interrupt */
if (isr & XCAN_IXR_ERROR_MASK) {
- if (skb) {
+ if (skb)
cf->can_id |= CAN_ERR_PROT | CAN_ERR_BUSERROR;
- cf->data[2] |= CAN_ERR_PROT_UNSPEC;
- }
/* Check for Ack error interrupt */
if (err_status & XCAN_ESR_ACKER_MASK) {
stats->tx_errors++;
if (skb) {
cf->can_id |= CAN_ERR_ACK;
- cf->data[3] |= CAN_ERR_PROT_LOC_ACK;
+ cf->data[3] = CAN_ERR_PROT_LOC_ACK;
}
}
@@ -654,8 +652,7 @@ static void xcan_err_interrupt(struct net_device *ndev, u32 isr)
stats->rx_errors++;
if (skb) {
cf->can_id |= CAN_ERR_PROT;
- cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL;
+ cf->data[3] = CAN_ERR_PROT_LOC_CRC_SEQ;
}
}
priv->can.can_stats.bus_error++;
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 9093577..0527f48 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -15,9 +15,7 @@
#include <linux/netdevice.h>
#include <linux/phy.h>
#include <net/dsa.h>
-
-#define REG_PORT(p) (8 + (p))
-#define REG_GLOBAL 0x0f
+#include "mv88e6060.h"
static int reg_read(struct dsa_switch *ds, int addr, int reg)
{
@@ -67,13 +65,14 @@ static char *mv88e6060_probe(struct device *host_dev, int sw_addr)
if (bus == NULL)
return NULL;
- ret = mdiobus_read(bus, sw_addr + REG_PORT(0), 0x03);
+ ret = mdiobus_read(bus, sw_addr + REG_PORT(0), PORT_SWITCH_ID);
if (ret >= 0) {
- if (ret == 0x0600)
+ if (ret == PORT_SWITCH_ID_6060)
return "Marvell 88E6060 (A0)";
- if (ret == 0x0601 || ret == 0x0602)
+ if (ret == PORT_SWITCH_ID_6060_R1 ||
+ ret == PORT_SWITCH_ID_6060_R2)
return "Marvell 88E6060 (B0)";
- if ((ret & 0xfff0) == 0x0600)
+ if ((ret & PORT_SWITCH_ID_6060_MASK) == PORT_SWITCH_ID_6060)
return "Marvell 88E6060";
}
@@ -87,22 +86,26 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
unsigned long timeout;
/* Set all ports to the disabled state. */
- for (i = 0; i < 6; i++) {
- ret = REG_READ(REG_PORT(i), 0x04);
- REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
+ for (i = 0; i < MV88E6060_PORTS; i++) {
+ ret = REG_READ(REG_PORT(i), PORT_CONTROL);
+ REG_WRITE(REG_PORT(i), PORT_CONTROL,
+ ret & ~PORT_CONTROL_STATE_MASK);
}
/* Wait for transmit queues to drain. */
usleep_range(2000, 4000);
/* Reset the switch. */
- REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
+ REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
+ GLOBAL_ATU_CONTROL_SWRESET |
+ GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
+ GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
/* Wait up to one second for reset to complete. */
timeout = jiffies + 1 * HZ;
while (time_before(jiffies, timeout)) {
- ret = REG_READ(REG_GLOBAL, 0x00);
- if ((ret & 0x8000) == 0x0000)
+ ret = REG_READ(REG_GLOBAL, GLOBAL_STATUS);
+ if (ret & GLOBAL_STATUS_INIT_READY)
break;
usleep_range(1000, 2000);
@@ -119,13 +122,15 @@ static int mv88e6060_setup_global(struct dsa_switch *ds)
* set the maximum frame size to 1536 bytes, and mask all
* interrupt sources.
*/
- REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
+ REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
/* Enable automatic address learning, set the address
* database size to 1024 entries, and set the default aging
* time to 5 minutes.
*/
- REG_WRITE(REG_GLOBAL, 0x0a, 0x2130);
+ REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
+ GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
+ GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
return 0;
}
@@ -139,25 +144,30 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
* state to Forwarding. Additionally, if this is the CPU
* port, enable Ingress and Egress Trailer tagging mode.
*/
- REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
+ REG_WRITE(addr, PORT_CONTROL,
+ dsa_is_cpu_port(ds, p) ?
+ PORT_CONTROL_TRAILER |
+ PORT_CONTROL_INGRESS_MODE |
+ PORT_CONTROL_STATE_FORWARDING :
+ PORT_CONTROL_STATE_FORWARDING);
/* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the CPU port.
*/
- REG_WRITE(addr, 0x06,
- ((p & 0xf) << 12) |
- (dsa_is_cpu_port(ds, p) ?
- ds->phys_port_mask :
- (1 << ds->dst->cpu_port)));
+ REG_WRITE(addr, PORT_VLAN_MAP,
+ ((p & 0xf) << PORT_VLAN_MAP_DBNUM_SHIFT) |
+ (dsa_is_cpu_port(ds, p) ?
+ ds->phys_port_mask :
+ BIT(ds->dst->cpu_port)));
/* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
*/
- REG_WRITE(addr, 0x0b, 1 << p);
+ REG_WRITE(addr, PORT_ASSOC_VECTOR, BIT(p));
return 0;
}
@@ -177,7 +187,7 @@ static int mv88e6060_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < MV88E6060_PORTS; i++) {
ret = mv88e6060_setup_port(ds, i);
if (ret < 0)
return ret;
@@ -188,16 +198,17 @@ static int mv88e6060_setup(struct dsa_switch *ds)
static int mv88e6060_set_addr(struct dsa_switch *ds, u8 *addr)
{
- REG_WRITE(REG_GLOBAL, 0x01, (addr[0] << 8) | addr[1]);
- REG_WRITE(REG_GLOBAL, 0x02, (addr[2] << 8) | addr[3]);
- REG_WRITE(REG_GLOBAL, 0x03, (addr[4] << 8) | addr[5]);
+ /* Use the same MAC Address as FD Pause frames for all ports */
+ REG_WRITE(REG_GLOBAL, GLOBAL_MAC_01, (addr[0] << 9) | addr[1]);
+ REG_WRITE(REG_GLOBAL, GLOBAL_MAC_23, (addr[2] << 8) | addr[3]);
+ REG_WRITE(REG_GLOBAL, GLOBAL_MAC_45, (addr[4] << 8) | addr[5]);
return 0;
}
static int mv88e6060_port_to_phy_addr(int port)
{
- if (port >= 0 && port <= 5)
+ if (port >= 0 && port < MV88E6060_PORTS)
return port;
return -1;
}
@@ -225,54 +236,6 @@ mv88e6060_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
return reg_write(ds, addr, regnum, val);
}
-static void mv88e6060_poll_link(struct dsa_switch *ds)
-{
- int i;
-
- for (i = 0; i < DSA_MAX_PORTS; i++) {
- struct net_device *dev;
- int uninitialized_var(port_status);
- int link;
- int speed;
- int duplex;
- int fc;
-
- dev = ds->ports[i];
- if (dev == NULL)
- continue;
-
- link = 0;
- if (dev->flags & IFF_UP) {
- port_status = reg_read(ds, REG_PORT(i), 0x00);
- if (port_status < 0)
- continue;
-
- link = !!(port_status & 0x1000);
- }
-
- if (!link) {
- if (netif_carrier_ok(dev)) {
- netdev_info(dev, "link down\n");
- netif_carrier_off(dev);
- }
- continue;
- }
-
- speed = (port_status & 0x0100) ? 100 : 10;
- duplex = (port_status & 0x0200) ? 1 : 0;
- fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
-
- if (!netif_carrier_ok(dev)) {
- netdev_info(dev,
- "link up, %d Mb/s, %s duplex, flow control %sabled\n",
- speed,
- duplex ? "full" : "half",
- fc ? "en" : "dis");
- netif_carrier_on(dev);
- }
- }
-}
-
static struct dsa_switch_driver mv88e6060_switch_driver = {
.tag_protocol = DSA_TAG_PROTO_TRAILER,
.probe = mv88e6060_probe,
@@ -280,7 +243,6 @@ static struct dsa_switch_driver mv88e6060_switch_driver = {
.set_addr = mv88e6060_set_addr,
.phy_read = mv88e6060_phy_read,
.phy_write = mv88e6060_phy_write,
- .poll_link = mv88e6060_poll_link,
};
static int __init mv88e6060_init(void)
diff --git a/drivers/net/dsa/mv88e6060.h b/drivers/net/dsa/mv88e6060.h
new file mode 100644
index 0000000..cc9b2ed
--- /dev/null
+++ b/drivers/net/dsa/mv88e6060.h
@@ -0,0 +1,111 @@
+/*
+ * drivers/net/dsa/mv88e6060.h - Marvell 88e6060 switch chip support
+ * Copyright (c) 2015 Neil Armstrong
+ *
+ * Based on mv88e6xxx.h
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * 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 __MV88E6060_H
+#define __MV88E6060_H
+
+#define MV88E6060_PORTS 6
+
+#define REG_PORT(p) (0x8 + (p))
+#define PORT_STATUS 0x00
+#define PORT_STATUS_PAUSE_EN BIT(15)
+#define PORT_STATUS_MY_PAUSE BIT(14)
+#define PORT_STATUS_FC (PORT_STATUS_MY_PAUSE | PORT_STATUS_PAUSE_EN)
+#define PORT_STATUS_RESOLVED BIT(13)
+#define PORT_STATUS_LINK BIT(12)
+#define PORT_STATUS_PORTMODE BIT(11)
+#define PORT_STATUS_PHYMODE BIT(10)
+#define PORT_STATUS_DUPLEX BIT(9)
+#define PORT_STATUS_SPEED BIT(8)
+#define PORT_SWITCH_ID 0x03
+#define PORT_SWITCH_ID_6060 0x0600
+#define PORT_SWITCH_ID_6060_MASK 0xfff0
+#define PORT_SWITCH_ID_6060_R1 0x0601
+#define PORT_SWITCH_ID_6060_R2 0x0602
+#define PORT_CONTROL 0x04
+#define PORT_CONTROL_FORCE_FLOW_CTRL BIT(15)
+#define PORT_CONTROL_TRAILER BIT(14)
+#define PORT_CONTROL_HEADER BIT(11)
+#define PORT_CONTROL_INGRESS_MODE BIT(8)
+#define PORT_CONTROL_VLAN_TUNNEL BIT(7)
+#define PORT_CONTROL_STATE_MASK 0x03
+#define PORT_CONTROL_STATE_DISABLED 0x00
+#define PORT_CONTROL_STATE_BLOCKING 0x01
+#define PORT_CONTROL_STATE_LEARNING 0x02
+#define PORT_CONTROL_STATE_FORWARDING 0x03
+#define PORT_VLAN_MAP 0x06
+#define PORT_VLAN_MAP_DBNUM_SHIFT 12
+#define PORT_VLAN_MAP_TABLE_MASK 0x1f
+#define PORT_ASSOC_VECTOR 0x0b
+#define PORT_ASSOC_VECTOR_MONITOR BIT(15)
+#define PORT_ASSOC_VECTOR_PAV_MASK 0x1f
+#define PORT_RX_CNTR 0x10
+#define PORT_TX_CNTR 0x11
+
+#define REG_GLOBAL 0x0f
+#define GLOBAL_STATUS 0x00
+#define GLOBAL_STATUS_SW_MODE_MASK (0x3 << 12)
+#define GLOBAL_STATUS_SW_MODE_0 (0x0 << 12)
+#define GLOBAL_STATUS_SW_MODE_1 (0x1 << 12)
+#define GLOBAL_STATUS_SW_MODE_2 (0x2 << 12)
+#define GLOBAL_STATUS_SW_MODE_3 (0x3 << 12)
+#define GLOBAL_STATUS_INIT_READY BIT(11)
+#define GLOBAL_STATUS_ATU_FULL BIT(3)
+#define GLOBAL_STATUS_ATU_DONE BIT(2)
+#define GLOBAL_STATUS_PHY_INT BIT(1)
+#define GLOBAL_STATUS_EEINT BIT(0)
+#define GLOBAL_MAC_01 0x01
+#define GLOBAL_MAC_01_DIFF_ADDR BIT(8)
+#define GLOBAL_MAC_23 0x02
+#define GLOBAL_MAC_45 0x03
+#define GLOBAL_CONTROL 0x04
+#define GLOBAL_CONTROL_DISCARD_EXCESS BIT(13)
+#define GLOBAL_CONTROL_MAX_FRAME_1536 BIT(10)
+#define GLOBAL_CONTROL_RELOAD_EEPROM BIT(9)
+#define GLOBAL_CONTROL_CTRMODE BIT(8)
+#define GLOBAL_CONTROL_ATU_FULL_EN BIT(3)
+#define GLOBAL_CONTROL_ATU_DONE_EN BIT(2)
+#define GLOBAL_CONTROL_PHYINT_EN BIT(1)
+#define GLOBAL_CONTROL_EEPROM_DONE_EN BIT(0)
+#define GLOBAL_ATU_CONTROL 0x0a
+#define GLOBAL_ATU_CONTROL_SWRESET BIT(15)
+#define GLOBAL_ATU_CONTROL_LEARNDIS BIT(14)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_256 (0x0 << 12)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_512 (0x1 << 12)
+#define GLOBAL_ATU_CONTROL_ATUSIZE_1024 (0x2 << 12)
+#define GLOBAL_ATU_CONTROL_ATE_AGE_SHIFT 4
+#define GLOBAL_ATU_CONTROL_ATE_AGE_MASK (0xff << 4)
+#define GLOBAL_ATU_CONTROL_ATE_AGE_5MIN (0x13 << 4)
+#define GLOBAL_ATU_OP 0x0b
+#define GLOBAL_ATU_OP_BUSY BIT(15)
+#define GLOBAL_ATU_OP_NOP (0 << 12)
+#define GLOBAL_ATU_OP_FLUSH_ALL ((1 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_UNLOCKED ((2 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_LOAD_DB ((3 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_GET_NEXT_DB ((4 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_DB ((5 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_OP_FLUSH_UNLOCKED_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
+#define GLOBAL_ATU_DATA 0x0c
+#define GLOBAL_ATU_DATA_PORT_VECTOR_MASK 0x3f0
+#define GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT 4
+#define GLOBAL_ATU_DATA_STATE_MASK 0x0f
+#define GLOBAL_ATU_DATA_STATE_UNUSED 0x00
+#define GLOBAL_ATU_DATA_STATE_UC_STATIC 0x0e
+#define GLOBAL_ATU_DATA_STATE_UC_LOCKED 0x0f
+#define GLOBAL_ATU_DATA_STATE_MC_STATIC 0x07
+#define GLOBAL_ATU_DATA_STATE_MC_LOCKED 0x0e
+#define GLOBAL_ATU_MAC_01 0x0d
+#define GLOBAL_ATU_MAC_23 0x0e
+#define GLOBAL_ATU_MAC_45 0x0f
+
+#endif
diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c
index 54aa000..6e18213 100644
--- a/drivers/net/dsa/mv88e6171.c
+++ b/drivers/net/dsa/mv88e6171.c
@@ -103,6 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = {
#endif
.get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs,
+ .port_join_bridge = mv88e6xxx_port_bridge_join,
+ .port_leave_bridge = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update,
.port_pvid_get = mv88e6xxx_port_pvid_get,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index ff846d0..cc6c545 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -323,6 +323,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = {
.set_eeprom = mv88e6352_set_eeprom,
.get_regs_len = mv88e6xxx_get_regs_len,
.get_regs = mv88e6xxx_get_regs,
+ .port_join_bridge = mv88e6xxx_port_bridge_join,
+ .port_leave_bridge = mv88e6xxx_port_bridge_leave,
.port_stp_update = mv88e6xxx_port_stp_update,
.port_pvid_get = mv88e6xxx_port_pvid_get,
.port_vlan_prepare = mv88e6xxx_port_vlan_prepare,
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 04cff58..b06dba0 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -1462,6 +1462,10 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct switchdev_trans *trans)
{
+ /* We reserve a few VLANs to isolate unbridged ports */
+ if (vlan->vid_end >= 4000)
+ return -EOPNOTSUPP;
+
/* We don't need any dynamic resource from the kernel (yet),
* so skip the prepare phase.
*/
@@ -1870,6 +1874,36 @@ unlock:
return err;
}
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
+ int err;
+
+ /* The port joined a bridge, so leave its reserved VLAN */
+ mutex_lock(&ps->smi_mutex);
+ err = _mv88e6xxx_port_vlan_del(ds, port, pvid);
+ if (!err)
+ err = _mv88e6xxx_port_pvid_set(ds, port, 0);
+ mutex_unlock(&ps->smi_mutex);
+ return err;
+}
+
+int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
+{
+ struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
+ const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
+ int err;
+
+ /* The port left the bridge, so join its reserved VLAN */
+ mutex_lock(&ps->smi_mutex);
+ err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
+ if (!err)
+ err = _mv88e6xxx_port_pvid_set(ds, port, pvid);
+ mutex_unlock(&ps->smi_mutex);
+ return err;
+}
+
static void mv88e6xxx_bridge_work(struct work_struct *work)
{
struct mv88e6xxx_priv_state *ps;
@@ -2140,6 +2174,14 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds)
ret = mv88e6xxx_setup_port(ds, i);
if (ret < 0)
return ret;
+
+ if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
+ continue;
+
+ /* setup the unbridged state */
+ ret = mv88e6xxx_port_bridge_leave(ds, i, 0);
+ if (ret < 0)
+ return ret;
}
return 0;
}
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index fb9a873..21c8daa 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -468,6 +468,8 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum,
int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e);
int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
struct phy_device *phydev, struct ethtool_eee *e);
+int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members);
+int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members);
int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state);
int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig
index 05aa759..31c5e47 100644
--- a/drivers/net/ethernet/Kconfig
+++ b/drivers/net/ethernet/Kconfig
@@ -29,6 +29,7 @@ source "drivers/net/ethernet/apm/Kconfig"
source "drivers/net/ethernet/apple/Kconfig"
source "drivers/net/ethernet/arc/Kconfig"
source "drivers/net/ethernet/atheros/Kconfig"
+source "drivers/net/ethernet/aurora/Kconfig"
source "drivers/net/ethernet/cadence/Kconfig"
source "drivers/net/ethernet/adi/Kconfig"
source "drivers/net/ethernet/broadcom/Kconfig"
@@ -78,7 +79,6 @@ source "drivers/net/ethernet/ibm/Kconfig"
source "drivers/net/ethernet/intel/Kconfig"
source "drivers/net/ethernet/i825xx/Kconfig"
source "drivers/net/ethernet/xscale/Kconfig"
-source "drivers/net/ethernet/icplus/Kconfig"
config JME
tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile
index ddfc808..071f84e 100644
--- a/drivers/net/ethernet/Makefile
+++ b/drivers/net/ethernet/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_NET_XGENE) += apm/
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
obj-$(CONFIG_NET_VENDOR_ARC) += arc/
obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
+obj-$(CONFIG_NET_VENDOR_AURORA) += aurora/
obj-$(CONFIG_NET_CADENCE) += cadence/
obj-$(CONFIG_NET_BFIN) += adi/
obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/
@@ -41,7 +42,6 @@ obj-$(CONFIG_NET_VENDOR_IBM) += ibm/
obj-$(CONFIG_NET_VENDOR_INTEL) += intel/
obj-$(CONFIG_NET_VENDOR_I825XX) += i825xx/
obj-$(CONFIG_NET_VENDOR_XSCALE) += xscale/
-obj-$(CONFIG_IP1000) += icplus/
obj-$(CONFIG_JME) += jme.o
obj-$(CONFIG_KORINA) += korina.o
obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index bc8b04f..7ccebae 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -1500,10 +1500,11 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent)
return -ENODEV;
}
- if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) {
+ err = pci_set_dma_mask(pdev, PCNET32_DMA_MASK);
+ if (err) {
if (pcnet32_debug & NETIF_MSG_PROBE)
pr_err("architecture does not support 32bit PCI busmaster DMA\n");
- return -ENODEV;
+ return err;
}
if (!request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci")) {
if (pcnet32_debug & NETIF_MSG_PROBE)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 970781a..f6a7161 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -1849,7 +1849,7 @@ static int xgbe_exit(struct xgbe_prv_data *pdata)
usleep_range(10, 15);
/* Poll Until Poll Condition */
- while (count-- && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
+ while (--count && XGMAC_IOREAD_BITS(pdata, DMA_MR, SWR))
usleep_range(500, 600);
if (!count)
@@ -1873,7 +1873,7 @@ static int xgbe_flush_tx_queues(struct xgbe_prv_data *pdata)
/* Poll Until Poll Condition */
for (i = 0; i < pdata->tx_q_count; i++) {
count = 2000;
- while (count-- && XGMAC_MTL_IOREAD_BITS(pdata, i,
+ while (--count && XGMAC_MTL_IOREAD_BITS(pdata, i,
MTL_Q_TQOMR, FTQ))
usleep_range(500, 600);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index 7dd8933..618d952 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -342,6 +342,7 @@ static int xgbe_probe(struct platform_device *pdev)
struct resource *res;
const char *phy_mode;
unsigned int i, phy_memnum, phy_irqnum;
+ enum dev_dma_attr attr;
int ret;
DBGPR("--> xgbe_probe\n");
@@ -609,7 +610,12 @@ static int xgbe_probe(struct platform_device *pdev)
goto err_io;
/* Set the DMA coherency values */
- pdata->coherent = device_dma_is_coherent(pdata->dev);
+ attr = device_get_dma_attr(dev);
+ if (attr == DEV_DMA_NOT_SUPPORTED) {
+ dev_err(dev, "DMA is not supported");
+ goto err_io;
+ }
+ pdata->coherent = (attr == DEV_DMA_COHERENT);
if (pdata->coherent) {
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
pdata->arcache = XGBE_DMA_OS_ARCACHE;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
index 33850a0..c31e691 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -459,6 +459,45 @@ static void xgene_gmac_reset(struct xgene_enet_pdata *pdata)
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_1_ADDR, 0);
}
+static void xgene_enet_configure_clock(struct xgene_enet_pdata *pdata)
+{
+ struct device *dev = &pdata->pdev->dev;
+
+ if (dev->of_node) {
+ struct clk *parent = clk_get_parent(pdata->clk);
+
+ switch (pdata->phy_speed) {
+ case SPEED_10:
+ clk_set_rate(parent, 2500000);
+ break;
+ case SPEED_100:
+ clk_set_rate(parent, 25000000);
+ break;
+ default:
+ clk_set_rate(parent, 125000000);
+ break;
+ }
+ }
+#ifdef CONFIG_ACPI
+ else {
+ switch (pdata->phy_speed) {
+ case SPEED_10:
+ acpi_evaluate_object(ACPI_HANDLE(dev),
+ "S10", NULL, NULL);
+ break;
+ case SPEED_100:
+ acpi_evaluate_object(ACPI_HANDLE(dev),
+ "S100", NULL, NULL);
+ break;
+ default:
+ acpi_evaluate_object(ACPI_HANDLE(dev),
+ "S1G", NULL, NULL);
+ break;
+ }
+ }
+#endif
+}
+
static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
{
struct device *dev = &pdata->pdev->dev;
@@ -477,12 +516,14 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
switch (pdata->phy_speed) {
case SPEED_10:
ENET_INTERFACE_MODE2_SET(&mc2, 1);
+ intf_ctl &= ~(ENET_LHD_MODE | ENET_GHD_MODE);
CFG_MACMODE_SET(&icm0, 0);
CFG_WAITASYNCRD_SET(&icm2, 500);
rgmii &= ~CFG_SPEED_1250;
break;
case SPEED_100:
ENET_INTERFACE_MODE2_SET(&mc2, 1);
+ intf_ctl &= ~ENET_GHD_MODE;
intf_ctl |= ENET_LHD_MODE;
CFG_MACMODE_SET(&icm0, 1);
CFG_WAITASYNCRD_SET(&icm2, 80);
@@ -490,12 +531,15 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
break;
default:
ENET_INTERFACE_MODE2_SET(&mc2, 2);
+ intf_ctl &= ~ENET_LHD_MODE;
intf_ctl |= ENET_GHD_MODE;
-
+ CFG_MACMODE_SET(&icm0, 2);
+ CFG_WAITASYNCRD_SET(&icm2, 0);
if (dev->of_node) {
CFG_TXCLK_MUXSEL0_SET(&rgmii, pdata->tx_delay);
CFG_RXCLK_MUXSEL0_SET(&rgmii, pdata->rx_delay);
}
+ rgmii |= CFG_SPEED_1250;
xgene_enet_rd_csr(pdata, DEBUG_REG_ADDR, &value);
value |= CFG_BYPASS_UNISEC_TX | CFG_BYPASS_UNISEC_RX;
@@ -503,7 +547,7 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
break;
}
- mc2 |= FULL_DUPLEX2;
+ mc2 |= FULL_DUPLEX2 | PAD_CRC;
xgene_enet_wr_mcx_mac(pdata, MAC_CONFIG_2_ADDR, mc2);
xgene_enet_wr_mcx_mac(pdata, INTERFACE_CONTROL_ADDR, intf_ctl);
@@ -522,6 +566,7 @@ static void xgene_gmac_init(struct xgene_enet_pdata *pdata)
/* Rtype should be copied from FP */
xgene_enet_wr_csr(pdata, RSIF_RAM_DBG_REG0_ADDR, 0);
xgene_enet_wr_csr(pdata, RGMII_REG_0_ADDR, rgmii);
+ xgene_enet_configure_clock(pdata);
/* Rx-Tx traffic resume */
xgene_enet_wr_csr(pdata, CFG_LINK_AGGR_RESUME_0_ADDR, TX_PORT0);
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
index 6dee73c..c153a1d 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h
@@ -181,6 +181,7 @@ enum xgene_enet_rm {
#define ENET_LHD_MODE BIT(25)
#define ENET_GHD_MODE BIT(26)
#define FULL_DUPLEX2 BIT(0)
+#define PAD_CRC BIT(2)
#define SCAN_AUTO_INCR BIT(5)
#define TBYT_ADDR 0x38
#define TPKT_ADDR 0x39
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index ce10687..d0ae1a6 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -289,6 +289,7 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring,
struct sk_buff *skb)
{
struct device *dev = ndev_to_dev(tx_ring->ndev);
+ struct xgene_enet_pdata *pdata = netdev_priv(tx_ring->ndev);
struct xgene_enet_raw_desc *raw_desc;
__le64 *exp_desc = NULL, *exp_bufs = NULL;
dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr;
@@ -419,6 +420,7 @@ out:
raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) |
SET_VAL(USERINFO, tx_ring->tail));
tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb;
+ pdata->tx_level += count;
tx_ring->tail = tail;
return count;
@@ -429,14 +431,13 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring;
- struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring;
- u32 tx_level, cq_level;
+ u32 tx_level = pdata->tx_level;
int count;
- tx_level = pdata->ring_ops->len(tx_ring);
- cq_level = pdata->ring_ops->len(cp_ring);
- if (unlikely(tx_level > pdata->tx_qcnt_hi ||
- cq_level > pdata->cp_qcnt_hi)) {
+ if (tx_level < pdata->txc_level)
+ tx_level += ((typeof(pdata->tx_level))~0U);
+
+ if ((tx_level - pdata->txc_level) > pdata->tx_qcnt_hi) {
netif_stop_queue(ndev);
return NETDEV_TX_BUSY;
}
@@ -450,12 +451,12 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- pdata->ring_ops->wr_cmd(tx_ring, count);
skb_tx_timestamp(skb);
pdata->stats.tx_packets++;
pdata->stats.tx_bytes += skb->len;
+ pdata->ring_ops->wr_cmd(tx_ring, count);
return NETDEV_TX_OK;
}
@@ -539,10 +540,13 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
struct xgene_enet_raw_desc *raw_desc, *exp_desc;
u16 head = ring->head;
u16 slots = ring->slots - 1;
- int ret, count = 0, processed = 0;
+ int ret, desc_count, count = 0, processed = 0;
+ bool is_completion;
do {
raw_desc = &ring->raw_desc[head];
+ desc_count = 0;
+ is_completion = false;
exp_desc = NULL;
if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc)))
break;
@@ -559,18 +563,24 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
}
dma_rmb();
count++;
+ desc_count++;
}
- if (is_rx_desc(raw_desc))
+ if (is_rx_desc(raw_desc)) {
ret = xgene_enet_rx_frame(ring, raw_desc);
- else
+ } else {
ret = xgene_enet_tx_completion(ring, raw_desc);
+ is_completion = true;
+ }
xgene_enet_mark_desc_slot_empty(raw_desc);
if (exp_desc)
xgene_enet_mark_desc_slot_empty(exp_desc);
head = (head + 1) & slots;
count++;
+ desc_count++;
processed++;
+ if (is_completion)
+ pdata->txc_level += desc_count;
if (ret)
break;
@@ -580,10 +590,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
pdata->ring_ops->wr_cmd(ring, -count);
ring->head = head;
- if (netif_queue_stopped(ring->ndev)) {
- if (pdata->ring_ops->len(ring) < pdata->cp_qcnt_low)
- netif_wake_queue(ring->ndev);
- }
+ if (netif_queue_stopped(ring->ndev))
+ netif_start_queue(ring->ndev);
}
return processed;
@@ -688,17 +696,16 @@ static int xgene_enet_open(struct net_device *ndev)
mac_ops->tx_enable(pdata);
mac_ops->rx_enable(pdata);
+ xgene_enet_napi_enable(pdata);
ret = xgene_enet_register_irq(ndev);
if (ret)
return ret;
- xgene_enet_napi_enable(pdata);
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
phy_start(pdata->phy_dev);
else
schedule_delayed_work(&pdata->link_work, PHY_POLL_LINK_OFF);
- netif_carrier_off(ndev);
netif_start_queue(ndev);
return ret;
@@ -716,13 +723,13 @@ static int xgene_enet_close(struct net_device *ndev)
else
cancel_delayed_work_sync(&pdata->link_work);
- xgene_enet_napi_disable(pdata);
- xgene_enet_free_irq(ndev);
- xgene_enet_process_ring(pdata->rx_ring, -1);
-
mac_ops->tx_disable(pdata);
mac_ops->rx_disable(pdata);
+ xgene_enet_free_irq(ndev);
+ xgene_enet_napi_disable(pdata);
+ xgene_enet_process_ring(pdata->rx_ring, -1);
+
return 0;
}
@@ -1034,9 +1041,7 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
pdata->tx_ring->cp_ring = cp_ring;
pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring);
- pdata->tx_qcnt_hi = pdata->tx_ring->slots / 2;
- pdata->cp_qcnt_hi = pdata->rx_ring->slots / 2;
- pdata->cp_qcnt_low = pdata->cp_qcnt_hi / 2;
+ pdata->tx_qcnt_hi = pdata->tx_ring->slots - 128;
return 0;
@@ -1475,15 +1480,15 @@ static int xgene_enet_probe(struct platform_device *pdev)
}
ndev->hw_features = ndev->features;
- ret = register_netdev(ndev);
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret) {
- netdev_err(ndev, "Failed to register netdev\n");
+ netdev_err(ndev, "No usable DMA configuration\n");
goto err;
}
- ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ ret = register_netdev(ndev);
if (ret) {
- netdev_err(ndev, "No usable DMA configuration\n");
+ netdev_err(ndev, "Failed to register netdev\n");
goto err;
}
@@ -1491,14 +1496,17 @@ static int xgene_enet_probe(struct platform_device *pdev)
if (ret)
goto err;
- xgene_enet_napi_add(pdata);
mac_ops = pdata->mac_ops;
- if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII) {
ret = xgene_enet_mdio_config(pdata);
- else
+ if (ret)
+ goto err;
+ } else {
INIT_DELAYED_WORK(&pdata->link_work, mac_ops->link_state);
+ }
- return ret;
+ xgene_enet_napi_add(pdata);
+ return 0;
err:
unregister_netdev(ndev);
free_netdev(ndev);
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
index a6e56b8..1aa72c7 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -155,11 +155,11 @@ struct xgene_enet_pdata {
enum xgene_enet_id enet_id;
struct xgene_enet_desc_ring *tx_ring;
struct xgene_enet_desc_ring *rx_ring;
+ u16 tx_level;
+ u16 txc_level;
char *dev_name;
u32 rx_buff_cnt;
u32 tx_qcnt_hi;
- u32 cp_qcnt_hi;
- u32 cp_qcnt_low;
u32 rx_irq;
u32 txc_irq;
u8 cq_cnt;
diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c
index c8af3ce..bd377a6 100644
--- a/drivers/net/ethernet/atheros/alx/main.c
+++ b/drivers/net/ethernet/atheros/alx/main.c
@@ -1534,6 +1534,8 @@ static const struct pci_device_id alx_pci_tbl[] = {
.driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
{ PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2200),
.driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
+ { PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_E2400),
+ .driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
{ PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8162),
.driver_data = ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG },
{ PCI_VDEVICE(ATTANSIC, ALX_DEV_ID_AR8171) },
diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h
index af006b4..0959e68 100644
--- a/drivers/net/ethernet/atheros/alx/reg.h
+++ b/drivers/net/ethernet/atheros/alx/reg.h
@@ -37,6 +37,7 @@
#define ALX_DEV_ID_AR8161 0x1091
#define ALX_DEV_ID_E2200 0xe091
+#define ALX_DEV_ID_E2400 0xe0a1
#define ALX_DEV_ID_AR8162 0x1090
#define ALX_DEV_ID_AR8171 0x10A1
#define ALX_DEV_ID_AR8172 0x10A0
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index 2795d6d..8b5988e 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -1016,13 +1016,12 @@ static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
sizeof(struct atl1c_recv_ret_status) * rx_desc_count +
8 * 4;
- ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
- &ring_header->dma);
+ ring_header->desc = dma_zalloc_coherent(&pdev->dev, ring_header->size,
+ &ring_header->dma, GFP_KERNEL);
if (unlikely(!ring_header->desc)) {
- dev_err(&pdev->dev, "pci_alloc_consistend failed\n");
+ dev_err(&pdev->dev, "could not get memory for DMA buffer\n");
goto err_nomem;
}
- memset(ring_header->desc, 0, ring_header->size);
/* init TPD ring */
tpd_ring[0].dma = roundup(ring_header->dma, 8);
diff --git a/drivers/net/ethernet/aurora/Kconfig b/drivers/net/ethernet/aurora/Kconfig
new file mode 100644
index 0000000..8ba7f8f
--- /dev/null
+++ b/drivers/net/ethernet/aurora/Kconfig
@@ -0,0 +1,21 @@
+config NET_VENDOR_AURORA
+ bool "Aurora VLSI devices"
+ help
+ If you have a network (Ethernet) device belonging to this class,
+ say Y.
+
+ Note that the answer to this question doesn't directly affect the
+ kernel: saying N will just cause the configurator to skip all
+ questions about Aurora devices. If you say Y, you will be asked
+ for your specific device in the following questions.
+
+if NET_VENDOR_AURORA
+
+config AURORA_NB8800
+ tristate "Aurora AU-NB8800 support"
+ depends on HAS_DMA
+ select PHYLIB
+ help
+ Support for the AU-NB8800 gigabit Ethernet controller.
+
+endif
diff --git a/drivers/net/ethernet/aurora/Makefile b/drivers/net/ethernet/aurora/Makefile
new file mode 100644
index 0000000..6cb528a
--- /dev/null
+++ b/drivers/net/ethernet/aurora/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_AURORA_NB8800) += nb8800.o
diff --git a/drivers/net/ethernet/aurora/nb8800.c b/drivers/net/ethernet/aurora/nb8800.c
new file mode 100644
index 0000000..ecc4a33
--- /dev/null
+++ b/drivers/net/ethernet/aurora/nb8800.c
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (C) 2015 Mans Rullgard <mans@mansr.com>
+ *
+ * Mostly rewritten, based on driver from Sigma Designs. Original
+ * copyright notice below.
+ *
+ *
+ * Driver for tangox SMP864x/SMP865x/SMP867x/SMP868x builtin Ethernet Mac.
+ *
+ * Copyright (C) 2005 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/dma-mapping.h>
+#include <linux/phy.h>
+#include <linux/cache.h>
+#include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <asm/barrier.h>
+
+#include "nb8800.h"
+
+static void nb8800_tx_done(struct net_device *dev);
+static int nb8800_dma_stop(struct net_device *dev);
+
+static inline u8 nb8800_readb(struct nb8800_priv *priv, int reg)
+{
+ return readb_relaxed(priv->base + reg);
+}
+
+static inline u32 nb8800_readl(struct nb8800_priv *priv, int reg)
+{
+ return readl_relaxed(priv->base + reg);
+}
+
+static inline void nb8800_writeb(struct nb8800_priv *priv, int reg, u8 val)
+{
+ writeb_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_writew(struct nb8800_priv *priv, int reg, u16 val)
+{
+ writew_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_writel(struct nb8800_priv *priv, int reg, u32 val)
+{
+ writel_relaxed(val, priv->base + reg);
+}
+
+static inline void nb8800_maskb(struct nb8800_priv *priv, int reg,
+ u32 mask, u32 val)
+{
+ u32 old = nb8800_readb(priv, reg);
+ u32 new = (old & ~mask) | (val & mask);
+
+ if (new != old)
+ nb8800_writeb(priv, reg, new);
+}
+
+static inline void nb8800_maskl(struct nb8800_priv *priv, int reg,
+ u32 mask, u32 val)
+{
+ u32 old = nb8800_readl(priv, reg);
+ u32 new = (old & ~mask) | (val & mask);
+
+ if (new != old)
+ nb8800_writel(priv, reg, new);
+}
+
+static inline void nb8800_modb(struct nb8800_priv *priv, int reg, u8 bits,
+ bool set)
+{
+ nb8800_maskb(priv, reg, bits, set ? bits : 0);
+}
+
+static inline void nb8800_setb(struct nb8800_priv *priv, int reg, u8 bits)
+{
+ nb8800_maskb(priv, reg, bits, bits);
+}
+
+static inline void nb8800_clearb(struct nb8800_priv *priv, int reg, u8 bits)
+{
+ nb8800_maskb(priv, reg, bits, 0);
+}
+
+static inline void nb8800_modl(struct nb8800_priv *priv, int reg, u32 bits,
+ bool set)
+{
+ nb8800_maskl(priv, reg, bits, set ? bits : 0);
+}
+
+static inline void nb8800_setl(struct nb8800_priv *priv, int reg, u32 bits)
+{
+ nb8800_maskl(priv, reg, bits, bits);
+}
+
+static inline void nb8800_clearl(struct nb8800_priv *priv, int reg, u32 bits)
+{
+ nb8800_maskl(priv, reg, bits, 0);
+}
+
+static int nb8800_mdio_wait(struct mii_bus *bus)
+{
+ struct nb8800_priv *priv = bus->priv;
+ u32 val;
+
+ return readl_poll_timeout_atomic(priv->base + NB8800_MDIO_CMD,
+ val, !(val & MDIO_CMD_GO), 1, 1000);
+}
+
+static int nb8800_mdio_cmd(struct mii_bus *bus, u32 cmd)
+{
+ struct nb8800_priv *priv = bus->priv;
+ int err;
+
+ err = nb8800_mdio_wait(bus);
+ if (err)
+ return err;
+
+ nb8800_writel(priv, NB8800_MDIO_CMD, cmd);
+ udelay(10);
+ nb8800_writel(priv, NB8800_MDIO_CMD, cmd | MDIO_CMD_GO);
+
+ return nb8800_mdio_wait(bus);
+}
+
+static int nb8800_mdio_read(struct mii_bus *bus, int phy_id, int reg)
+{
+ struct nb8800_priv *priv = bus->priv;
+ u32 val;
+ int err;
+
+ err = nb8800_mdio_cmd(bus, MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg));
+ if (err)
+ return err;
+
+ val = nb8800_readl(priv, NB8800_MDIO_STS);
+ if (val & MDIO_STS_ERR)
+ return 0xffff;
+
+ return val & 0xffff;
+}
+
+static int nb8800_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 val)
+{
+ u32 cmd = MDIO_CMD_ADDR(phy_id) | MDIO_CMD_REG(reg) |
+ MDIO_CMD_DATA(val) | MDIO_CMD_WR;
+
+ return nb8800_mdio_cmd(bus, cmd);
+}
+
+static void nb8800_mac_tx(struct net_device *dev, bool enable)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ while (nb8800_readl(priv, NB8800_TXC_CR) & TCR_EN)
+ cpu_relax();
+
+ nb8800_modb(priv, NB8800_TX_CTL1, TX_EN, enable);
+}
+
+static void nb8800_mac_rx(struct net_device *dev, bool enable)
+{
+ nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_EN, enable);
+}
+
+static void nb8800_mac_af(struct net_device *dev, bool enable)
+{
+ nb8800_modb(netdev_priv(dev), NB8800_RX_CTL, RX_AF_EN, enable);
+}
+
+static void nb8800_start_rx(struct net_device *dev)
+{
+ nb8800_setl(netdev_priv(dev), NB8800_RXC_CR, RCR_EN);
+}
+
+static int nb8800_alloc_rx(struct net_device *dev, unsigned int i, bool napi)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_rx_desc *rxd = &priv->rx_descs[i];
+ struct nb8800_rx_buf *rxb = &priv->rx_bufs[i];
+ int size = L1_CACHE_ALIGN(RX_BUF_SIZE);
+ dma_addr_t dma_addr;
+ struct page *page;
+ unsigned long offset;
+ void *data;
+
+ data = napi ? napi_alloc_frag(size) : netdev_alloc_frag(size);
+ if (!data)
+ return -ENOMEM;
+
+ page = virt_to_head_page(data);
+ offset = data - page_address(page);
+
+ dma_addr = dma_map_page(&dev->dev, page, offset, RX_BUF_SIZE,
+ DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(&dev->dev, dma_addr)) {
+ skb_free_frag(data);
+ return -ENOMEM;
+ }
+
+ rxb->page = page;
+ rxb->offset = offset;
+ rxd->desc.s_addr = dma_addr;
+
+ return 0;
+}
+
+static void nb8800_receive(struct net_device *dev, unsigned int i,
+ unsigned int len)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_rx_desc *rxd = &priv->rx_descs[i];
+ struct page *page = priv->rx_bufs[i].page;
+ int offset = priv->rx_bufs[i].offset;
+ void *data = page_address(page) + offset;
+ dma_addr_t dma = rxd->desc.s_addr;
+ struct sk_buff *skb;
+ unsigned int size;
+ int err;
+
+ size = len <= RX_COPYBREAK ? len : RX_COPYHDR;
+
+ skb = napi_alloc_skb(&priv->napi, size);
+ if (!skb) {
+ netdev_err(dev, "rx skb allocation failed\n");
+ dev->stats.rx_dropped++;
+ return;
+ }
+
+ if (len <= RX_COPYBREAK) {
+ dma_sync_single_for_cpu(&dev->dev, dma, len, DMA_FROM_DEVICE);
+ memcpy(skb_put(skb, len), data, len);
+ dma_sync_single_for_device(&dev->dev, dma, len,
+ DMA_FROM_DEVICE);
+ } else {
+ err = nb8800_alloc_rx(dev, i, true);
+ if (err) {
+ netdev_err(dev, "rx buffer allocation failed\n");
+ dev->stats.rx_dropped++;
+ return;
+ }
+
+ dma_unmap_page(&dev->dev, dma, RX_BUF_SIZE, DMA_FROM_DEVICE);
+ memcpy(skb_put(skb, RX_COPYHDR), data, RX_COPYHDR);
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+ offset + RX_COPYHDR, len - RX_COPYHDR,
+ RX_BUF_SIZE);
+ }
+
+ skb->protocol = eth_type_trans(skb, dev);
+ napi_gro_receive(&priv->napi, skb);
+}
+
+static void nb8800_rx_error(struct net_device *dev, u32 report)
+{
+ if (report & RX_LENGTH_ERR)
+ dev->stats.rx_length_errors++;
+
+ if (report & RX_FCS_ERR)
+ dev->stats.rx_crc_errors++;
+
+ if (report & RX_FIFO_OVERRUN)
+ dev->stats.rx_fifo_errors++;
+
+ if (report & RX_ALIGNMENT_ERROR)
+ dev->stats.rx_frame_errors++;
+
+ dev->stats.rx_errors++;
+}
+
+static int nb8800_poll(struct napi_struct *napi, int budget)
+{
+ struct net_device *dev = napi->dev;
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_rx_desc *rxd;
+ unsigned int last = priv->rx_eoc;
+ unsigned int next;
+ int work = 0;
+
+ nb8800_tx_done(dev);
+
+again:
+ while (work < budget) {
+ struct nb8800_rx_buf *rxb;
+ unsigned int len;
+
+ next = (last + 1) % RX_DESC_COUNT;
+
+ rxb = &priv->rx_bufs[next];
+ rxd = &priv->rx_descs[next];
+
+ if (!rxd->report)
+ break;
+
+ len = RX_BYTES_TRANSFERRED(rxd->report);
+
+ if (IS_RX_ERROR(rxd->report))
+ nb8800_rx_error(dev, rxd->report);
+ else
+ nb8800_receive(dev, next, len);
+
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += len;
+
+ if (rxd->report & RX_MULTICAST_PKT)
+ dev->stats.multicast++;
+
+ rxd->report = 0;
+ last = next;
+ work++;
+ }
+
+ if (work) {
+ priv->rx_descs[last].desc.config |= DESC_EOC;
+ wmb(); /* ensure new EOC is written before clearing old */
+ priv->rx_descs[priv->rx_eoc].desc.config &= ~DESC_EOC;
+ priv->rx_eoc = last;
+ nb8800_start_rx(dev);
+ }
+
+ if (work < budget) {
+ nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq);
+
+ /* If a packet arrived after we last checked but
+ * before writing RX_ITR, the interrupt will be
+ * delayed, so we retrieve it now.
+ */
+ if (priv->rx_descs[next].report)
+ goto again;
+
+ napi_complete_done(napi, work);
+ }
+
+ return work;
+}
+
+static void __nb8800_tx_dma_start(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_tx_buf *txb;
+ u32 txc_cr;
+
+ txb = &priv->tx_bufs[priv->tx_queue];
+ if (!txb->ready)
+ return;
+
+ txc_cr = nb8800_readl(priv, NB8800_TXC_CR);
+ if (txc_cr & TCR_EN)
+ return;
+
+ nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc);
+ wmb(); /* ensure desc addr is written before starting DMA */
+ nb8800_writel(priv, NB8800_TXC_CR, txc_cr | TCR_EN);
+
+ priv->tx_queue = (priv->tx_queue + txb->chain_len) % TX_DESC_COUNT;
+}
+
+static void nb8800_tx_dma_start(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ spin_lock_irq(&priv->tx_lock);
+ __nb8800_tx_dma_start(dev);
+ spin_unlock_irq(&priv->tx_lock);
+}
+
+static void nb8800_tx_dma_start_irq(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ spin_lock(&priv->tx_lock);
+ __nb8800_tx_dma_start(dev);
+ spin_unlock(&priv->tx_lock);
+}
+
+static int nb8800_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_tx_desc *txd;
+ struct nb8800_tx_buf *txb;
+ struct nb8800_dma_desc *desc;
+ dma_addr_t dma_addr;
+ unsigned int dma_len;
+ unsigned int align;
+ unsigned int next;
+
+ if (atomic_read(&priv->tx_free) <= NB8800_DESC_LOW) {
+ netif_stop_queue(dev);
+ return NETDEV_TX_BUSY;
+ }
+
+ align = (8 - (uintptr_t)skb->data) & 7;
+
+ dma_len = skb->len - align;
+ dma_addr = dma_map_single(&dev->dev, skb->data + align,
+ dma_len, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(&dev->dev, dma_addr)) {
+ netdev_err(dev, "tx dma mapping error\n");
+ kfree_skb(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ if (atomic_dec_return(&priv->tx_free) <= NB8800_DESC_LOW) {
+ netif_stop_queue(dev);
+ skb->xmit_more = 0;
+ }
+
+ next = priv->tx_next;
+ txb = &priv->tx_bufs[next];
+ txd = &priv->tx_descs[next];
+ desc = &txd->desc[0];
+
+ next = (next + 1) % TX_DESC_COUNT;
+
+ if (align) {
+ memcpy(txd->buf, skb->data, align);
+
+ desc->s_addr =
+ txb->dma_desc + offsetof(struct nb8800_tx_desc, buf);
+ desc->n_addr = txb->dma_desc + sizeof(txd->desc[0]);
+ desc->config = DESC_BTS(2) | DESC_DS | align;
+
+ desc++;
+ }
+
+ desc->s_addr = dma_addr;
+ desc->n_addr = priv->tx_bufs[next].dma_desc;
+ desc->config = DESC_BTS(2) | DESC_DS | DESC_EOF | dma_len;
+
+ if (!skb->xmit_more)
+ desc->config |= DESC_EOC;
+
+ txb->skb = skb;
+ txb->dma_addr = dma_addr;
+ txb->dma_len = dma_len;
+
+ if (!priv->tx_chain) {
+ txb->chain_len = 1;
+ priv->tx_chain = txb;
+ } else {
+ priv->tx_chain->chain_len++;
+ }
+
+ netdev_sent_queue(dev, skb->len);
+
+ priv->tx_next = next;
+
+ if (!skb->xmit_more) {
+ smp_wmb();
+ priv->tx_chain->ready = true;
+ priv->tx_chain = NULL;
+ nb8800_tx_dma_start(dev);
+ }
+
+ return NETDEV_TX_OK;
+}
+
+static void nb8800_tx_error(struct net_device *dev, u32 report)
+{
+ if (report & TX_LATE_COLLISION)
+ dev->stats.collisions++;
+
+ if (report & TX_PACKET_DROPPED)
+ dev->stats.tx_dropped++;
+
+ if (report & TX_FIFO_UNDERRUN)
+ dev->stats.tx_fifo_errors++;
+
+ dev->stats.tx_errors++;
+}
+
+static void nb8800_tx_done(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ unsigned int limit = priv->tx_next;
+ unsigned int done = priv->tx_done;
+ unsigned int packets = 0;
+ unsigned int len = 0;
+
+ while (done != limit) {
+ struct nb8800_tx_desc *txd = &priv->tx_descs[done];
+ struct nb8800_tx_buf *txb = &priv->tx_bufs[done];
+ struct sk_buff *skb;
+
+ if (!txd->report)
+ break;
+
+ skb = txb->skb;
+ len += skb->len;
+
+ dma_unmap_single(&dev->dev, txb->dma_addr, txb->dma_len,
+ DMA_TO_DEVICE);
+
+ if (IS_TX_ERROR(txd->report)) {
+ nb8800_tx_error(dev, txd->report);
+ kfree_skb(skb);
+ } else {
+ consume_skb(skb);
+ }
+
+ dev->stats.tx_packets++;
+ dev->stats.tx_bytes += TX_BYTES_TRANSFERRED(txd->report);
+ dev->stats.collisions += TX_EARLY_COLLISIONS(txd->report);
+
+ txb->skb = NULL;
+ txb->ready = false;
+ txd->report = 0;
+
+ done = (done + 1) % TX_DESC_COUNT;
+ packets++;
+ }
+
+ if (packets) {
+ smp_mb__before_atomic();
+ atomic_add(packets, &priv->tx_free);
+ netdev_completed_queue(dev, packets, len);
+ netif_wake_queue(dev);
+ priv->tx_done = done;
+ }
+}
+
+static irqreturn_t nb8800_irq(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct nb8800_priv *priv = netdev_priv(dev);
+ irqreturn_t ret = IRQ_NONE;
+ u32 val;
+
+ /* tx interrupt */
+ val = nb8800_readl(priv, NB8800_TXC_SR);
+ if (val) {
+ nb8800_writel(priv, NB8800_TXC_SR, val);
+
+ if (val & TSR_DI)
+ nb8800_tx_dma_start_irq(dev);
+
+ if (val & TSR_TI)
+ napi_schedule_irqoff(&priv->napi);
+
+ if (unlikely(val & TSR_DE))
+ netdev_err(dev, "TX DMA error\n");
+
+ /* should never happen with automatic status retrieval */
+ if (unlikely(val & TSR_TO))
+ netdev_err(dev, "TX Status FIFO overflow\n");
+
+ ret = IRQ_HANDLED;
+ }
+
+ /* rx interrupt */
+ val = nb8800_readl(priv, NB8800_RXC_SR);
+ if (val) {
+ nb8800_writel(priv, NB8800_RXC_SR, val);
+
+ if (likely(val & (RSR_RI | RSR_DI))) {
+ nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_poll);
+ napi_schedule_irqoff(&priv->napi);
+ }
+
+ if (unlikely(val & RSR_DE))
+ netdev_err(dev, "RX DMA error\n");
+
+ /* should never happen with automatic status retrieval */
+ if (unlikely(val & RSR_RO))
+ netdev_err(dev, "RX Status FIFO overflow\n");
+
+ ret = IRQ_HANDLED;
+ }
+
+ return ret;
+}
+
+static void nb8800_mac_config(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ bool gigabit = priv->speed == SPEED_1000;
+ u32 mac_mode_mask = RGMII_MODE | HALF_DUPLEX | GMAC_MODE;
+ u32 mac_mode = 0;
+ u32 slot_time;
+ u32 phy_clk;
+ u32 ict;
+
+ if (!priv->duplex)
+ mac_mode |= HALF_DUPLEX;
+
+ if (gigabit) {
+ if (priv->phy_mode == PHY_INTERFACE_MODE_RGMII)
+ mac_mode |= RGMII_MODE;
+
+ mac_mode |= GMAC_MODE;
+ phy_clk = 125000000;
+
+ /* Should be 512 but register is only 8 bits */
+ slot_time = 255;
+ } else {
+ phy_clk = 25000000;
+ slot_time = 128;
+ }
+
+ ict = DIV_ROUND_UP(phy_clk, clk_get_rate(priv->clk));
+
+ nb8800_writeb(priv, NB8800_IC_THRESHOLD, ict);
+ nb8800_writeb(priv, NB8800_SLOT_TIME, slot_time);
+ nb8800_maskb(priv, NB8800_MAC_MODE, mac_mode_mask, mac_mode);
+}
+
+static void nb8800_pause_config(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ u32 rxcr;
+
+ if (priv->pause_aneg) {
+ if (!phydev || !phydev->link)
+ return;
+
+ priv->pause_rx = phydev->pause;
+ priv->pause_tx = phydev->pause ^ phydev->asym_pause;
+ }
+
+ nb8800_modb(priv, NB8800_RX_CTL, RX_PAUSE_EN, priv->pause_rx);
+
+ rxcr = nb8800_readl(priv, NB8800_RXC_CR);
+ if (!!(rxcr & RCR_FL) == priv->pause_tx)
+ return;
+
+ if (netif_running(dev)) {
+ napi_disable(&priv->napi);
+ netif_tx_lock_bh(dev);
+ nb8800_dma_stop(dev);
+ nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx);
+ nb8800_start_rx(dev);
+ netif_tx_unlock_bh(dev);
+ napi_enable(&priv->napi);
+ } else {
+ nb8800_modl(priv, NB8800_RXC_CR, RCR_FL, priv->pause_tx);
+ }
+}
+
+static void nb8800_link_reconfigure(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ int change = 0;
+
+ if (phydev->link) {
+ if (phydev->speed != priv->speed) {
+ priv->speed = phydev->speed;
+ change = 1;
+ }
+
+ if (phydev->duplex != priv->duplex) {
+ priv->duplex = phydev->duplex;
+ change = 1;
+ }
+
+ if (change)
+ nb8800_mac_config(dev);
+
+ nb8800_pause_config(dev);
+ }
+
+ if (phydev->link != priv->link) {
+ priv->link = phydev->link;
+ change = 1;
+ }
+
+ if (change)
+ phy_print_status(priv->phydev);
+}
+
+static void nb8800_update_mac_addr(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ int i;
+
+ for (i = 0; i < ETH_ALEN; i++)
+ nb8800_writeb(priv, NB8800_SRC_ADDR(i), dev->dev_addr[i]);
+
+ for (i = 0; i < ETH_ALEN; i++)
+ nb8800_writeb(priv, NB8800_UC_ADDR(i), dev->dev_addr[i]);
+}
+
+static int nb8800_set_mac_address(struct net_device *dev, void *addr)
+{
+ struct sockaddr *sock = addr;
+
+ if (netif_running(dev))
+ return -EBUSY;
+
+ ether_addr_copy(dev->dev_addr, sock->sa_data);
+ nb8800_update_mac_addr(dev);
+
+ return 0;
+}
+
+static void nb8800_mc_init(struct net_device *dev, int val)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ nb8800_writeb(priv, NB8800_MC_INIT, val);
+ readb_poll_timeout_atomic(priv->base + NB8800_MC_INIT, val, !val,
+ 1, 1000);
+}
+
+static void nb8800_set_rx_mode(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct netdev_hw_addr *ha;
+ int i;
+
+ if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) {
+ nb8800_mac_af(dev, false);
+ return;
+ }
+
+ nb8800_mac_af(dev, true);
+ nb8800_mc_init(dev, 0);
+
+ netdev_for_each_mc_addr(ha, dev) {
+ for (i = 0; i < ETH_ALEN; i++)
+ nb8800_writeb(priv, NB8800_MC_ADDR(i), ha->addr[i]);
+
+ nb8800_mc_init(dev, 0xff);
+ }
+}
+
+#define RX_DESC_SIZE (RX_DESC_COUNT * sizeof(struct nb8800_rx_desc))
+#define TX_DESC_SIZE (TX_DESC_COUNT * sizeof(struct nb8800_tx_desc))
+
+static void nb8800_dma_free(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ unsigned int i;
+
+ if (priv->rx_bufs) {
+ for (i = 0; i < RX_DESC_COUNT; i++)
+ if (priv->rx_bufs[i].page)
+ put_page(priv->rx_bufs[i].page);
+
+ kfree(priv->rx_bufs);
+ priv->rx_bufs = NULL;
+ }
+
+ if (priv->tx_bufs) {
+ for (i = 0; i < TX_DESC_COUNT; i++)
+ kfree_skb(priv->tx_bufs[i].skb);
+
+ kfree(priv->tx_bufs);
+ priv->tx_bufs = NULL;
+ }
+
+ if (priv->rx_descs) {
+ dma_free_coherent(dev->dev.parent, RX_DESC_SIZE, priv->rx_descs,
+ priv->rx_desc_dma);
+ priv->rx_descs = NULL;
+ }
+
+ if (priv->tx_descs) {
+ dma_free_coherent(dev->dev.parent, TX_DESC_SIZE, priv->tx_descs,
+ priv->tx_desc_dma);
+ priv->tx_descs = NULL;
+ }
+}
+
+static void nb8800_dma_reset(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_rx_desc *rxd;
+ struct nb8800_tx_desc *txd;
+ unsigned int i;
+
+ for (i = 0; i < RX_DESC_COUNT; i++) {
+ dma_addr_t rx_dma = priv->rx_desc_dma + i * sizeof(*rxd);
+
+ rxd = &priv->rx_descs[i];
+ rxd->desc.n_addr = rx_dma + sizeof(*rxd);
+ rxd->desc.r_addr =
+ rx_dma + offsetof(struct nb8800_rx_desc, report);
+ rxd->desc.config = priv->rx_dma_config;
+ rxd->report = 0;
+ }
+
+ rxd->desc.n_addr = priv->rx_desc_dma;
+ rxd->desc.config |= DESC_EOC;
+
+ priv->rx_eoc = RX_DESC_COUNT - 1;
+
+ for (i = 0; i < TX_DESC_COUNT; i++) {
+ struct nb8800_tx_buf *txb = &priv->tx_bufs[i];
+ dma_addr_t r_dma = txb->dma_desc +
+ offsetof(struct nb8800_tx_desc, report);
+
+ txd = &priv->tx_descs[i];
+ txd->desc[0].r_addr = r_dma;
+ txd->desc[1].r_addr = r_dma;
+ txd->report = 0;
+ }
+
+ priv->tx_next = 0;
+ priv->tx_queue = 0;
+ priv->tx_done = 0;
+ atomic_set(&priv->tx_free, TX_DESC_COUNT);
+
+ nb8800_writel(priv, NB8800_RX_DESC_ADDR, priv->rx_desc_dma);
+
+ wmb(); /* ensure all setup is written before starting */
+}
+
+static int nb8800_dma_init(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ unsigned int n_rx = RX_DESC_COUNT;
+ unsigned int n_tx = TX_DESC_COUNT;
+ unsigned int i;
+ int err;
+
+ priv->rx_descs = dma_alloc_coherent(dev->dev.parent, RX_DESC_SIZE,
+ &priv->rx_desc_dma, GFP_KERNEL);
+ if (!priv->rx_descs)
+ goto err_out;
+
+ priv->rx_bufs = kcalloc(n_rx, sizeof(*priv->rx_bufs), GFP_KERNEL);
+ if (!priv->rx_bufs)
+ goto err_out;
+
+ for (i = 0; i < n_rx; i++) {
+ err = nb8800_alloc_rx(dev, i, false);
+ if (err)
+ goto err_out;
+ }
+
+ priv->tx_descs = dma_alloc_coherent(dev->dev.parent, TX_DESC_SIZE,
+ &priv->tx_desc_dma, GFP_KERNEL);
+ if (!priv->tx_descs)
+ goto err_out;
+
+ priv->tx_bufs = kcalloc(n_tx, sizeof(*priv->tx_bufs), GFP_KERNEL);
+ if (!priv->tx_bufs)
+ goto err_out;
+
+ for (i = 0; i < n_tx; i++)
+ priv->tx_bufs[i].dma_desc =
+ priv->tx_desc_dma + i * sizeof(struct nb8800_tx_desc);
+
+ nb8800_dma_reset(dev);
+
+ return 0;
+
+err_out:
+ nb8800_dma_free(dev);
+
+ return -ENOMEM;
+}
+
+static int nb8800_dma_stop(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ struct nb8800_tx_buf *txb = &priv->tx_bufs[0];
+ struct nb8800_tx_desc *txd = &priv->tx_descs[0];
+ int retry = 5;
+ u32 txcr;
+ u32 rxcr;
+ int err;
+ unsigned int i;
+
+ /* wait for tx to finish */
+ err = readl_poll_timeout_atomic(priv->base + NB8800_TXC_CR, txcr,
+ !(txcr & TCR_EN) &&
+ priv->tx_done == priv->tx_next,
+ 1000, 1000000);
+ if (err)
+ return err;
+
+ /* The rx DMA only stops if it reaches the end of chain.
+ * To make this happen, we set the EOC flag on all rx
+ * descriptors, put the device in loopback mode, and send
+ * a few dummy frames. The interrupt handler will ignore
+ * these since NAPI is disabled and no real frames are in
+ * the tx queue.
+ */
+
+ for (i = 0; i < RX_DESC_COUNT; i++)
+ priv->rx_descs[i].desc.config |= DESC_EOC;
+
+ txd->desc[0].s_addr =
+ txb->dma_desc + offsetof(struct nb8800_tx_desc, buf);
+ txd->desc[0].config = DESC_BTS(2) | DESC_DS | DESC_EOF | DESC_EOC | 8;
+ memset(txd->buf, 0, sizeof(txd->buf));
+
+ nb8800_mac_af(dev, false);
+ nb8800_setb(priv, NB8800_MAC_MODE, LOOPBACK_EN);
+
+ do {
+ nb8800_writel(priv, NB8800_TX_DESC_ADDR, txb->dma_desc);
+ wmb();
+ nb8800_writel(priv, NB8800_TXC_CR, txcr | TCR_EN);
+
+ err = readl_poll_timeout_atomic(priv->base + NB8800_RXC_CR,
+ rxcr, !(rxcr & RCR_EN),
+ 1000, 100000);
+ } while (err && --retry);
+
+ nb8800_mac_af(dev, true);
+ nb8800_clearb(priv, NB8800_MAC_MODE, LOOPBACK_EN);
+ nb8800_dma_reset(dev);
+
+ return retry ? 0 : -ETIMEDOUT;
+}
+
+static void nb8800_pause_adv(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ u32 adv = 0;
+
+ if (!priv->phydev)
+ return;
+
+ if (priv->pause_rx)
+ adv |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+ if (priv->pause_tx)
+ adv ^= ADVERTISED_Asym_Pause;
+
+ priv->phydev->supported |= adv;
+ priv->phydev->advertising |= adv;
+}
+
+static int nb8800_open(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ int err;
+
+ /* clear any pending interrupts */
+ nb8800_writel(priv, NB8800_RXC_SR, 0xf);
+ nb8800_writel(priv, NB8800_TXC_SR, 0xf);
+
+ err = nb8800_dma_init(dev);
+ if (err)
+ return err;
+
+ err = request_irq(dev->irq, nb8800_irq, 0, dev_name(&dev->dev), dev);
+ if (err)
+ goto err_free_dma;
+
+ nb8800_mac_rx(dev, true);
+ nb8800_mac_tx(dev, true);
+
+ priv->phydev = of_phy_connect(dev, priv->phy_node,
+ nb8800_link_reconfigure, 0,
+ priv->phy_mode);
+ if (!priv->phydev)
+ goto err_free_irq;
+
+ nb8800_pause_adv(dev);
+
+ netdev_reset_queue(dev);
+ napi_enable(&priv->napi);
+ netif_start_queue(dev);
+
+ nb8800_start_rx(dev);
+ phy_start(priv->phydev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_free_dma:
+ nb8800_dma_free(dev);
+
+ return err;
+}
+
+static int nb8800_stop(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ phy_stop(priv->phydev);
+
+ netif_stop_queue(dev);
+ napi_disable(&priv->napi);
+
+ nb8800_dma_stop(dev);
+ nb8800_mac_rx(dev, false);
+ nb8800_mac_tx(dev, false);
+
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+
+ free_irq(dev->irq, dev);
+
+ nb8800_dma_free(dev);
+
+ return 0;
+}
+
+static int nb8800_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ return phy_mii_ioctl(priv->phydev, rq, cmd);
+}
+
+static const struct net_device_ops nb8800_netdev_ops = {
+ .ndo_open = nb8800_open,
+ .ndo_stop = nb8800_stop,
+ .ndo_start_xmit = nb8800_xmit,
+ .ndo_set_mac_address = nb8800_set_mac_address,
+ .ndo_set_rx_mode = nb8800_set_rx_mode,
+ .ndo_do_ioctl = nb8800_ioctl,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
+static int nb8800_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_gset(priv->phydev, cmd);
+}
+
+static int nb8800_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return phy_ethtool_sset(priv->phydev, cmd);
+}
+
+static int nb8800_nway_reset(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ if (!priv->phydev)
+ return -ENODEV;
+
+ return genphy_restart_aneg(priv->phydev);
+}
+
+static void nb8800_get_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pp)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ pp->autoneg = priv->pause_aneg;
+ pp->rx_pause = priv->pause_rx;
+ pp->tx_pause = priv->pause_tx;
+}
+
+static int nb8800_set_pauseparam(struct net_device *dev,
+ struct ethtool_pauseparam *pp)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ priv->pause_aneg = pp->autoneg;
+ priv->pause_rx = pp->rx_pause;
+ priv->pause_tx = pp->tx_pause;
+
+ nb8800_pause_adv(dev);
+
+ if (!priv->pause_aneg)
+ nb8800_pause_config(dev);
+ else if (priv->phydev)
+ phy_start_aneg(priv->phydev);
+
+ return 0;
+}
+
+static const char nb8800_stats_names[][ETH_GSTRING_LEN] = {
+ "rx_bytes_ok",
+ "rx_frames_ok",
+ "rx_undersize_frames",
+ "rx_fragment_frames",
+ "rx_64_byte_frames",
+ "rx_127_byte_frames",
+ "rx_255_byte_frames",
+ "rx_511_byte_frames",
+ "rx_1023_byte_frames",
+ "rx_max_size_frames",
+ "rx_oversize_frames",
+ "rx_bad_fcs_frames",
+ "rx_broadcast_frames",
+ "rx_multicast_frames",
+ "rx_control_frames",
+ "rx_pause_frames",
+ "rx_unsup_control_frames",
+ "rx_align_error_frames",
+ "rx_overrun_frames",
+ "rx_jabber_frames",
+ "rx_bytes",
+ "rx_frames",
+
+ "tx_bytes_ok",
+ "tx_frames_ok",
+ "tx_64_byte_frames",
+ "tx_127_byte_frames",
+ "tx_255_byte_frames",
+ "tx_511_byte_frames",
+ "tx_1023_byte_frames",
+ "tx_max_size_frames",
+ "tx_oversize_frames",
+ "tx_broadcast_frames",
+ "tx_multicast_frames",
+ "tx_control_frames",
+ "tx_pause_frames",
+ "tx_underrun_frames",
+ "tx_single_collision_frames",
+ "tx_multi_collision_frames",
+ "tx_deferred_collision_frames",
+ "tx_late_collision_frames",
+ "tx_excessive_collision_frames",
+ "tx_bytes",
+ "tx_frames",
+ "tx_collisions",
+};
+
+#define NB8800_NUM_STATS ARRAY_SIZE(nb8800_stats_names)
+
+static int nb8800_get_sset_count(struct net_device *dev, int sset)
+{
+ if (sset == ETH_SS_STATS)
+ return NB8800_NUM_STATS;
+
+ return -EOPNOTSUPP;
+}
+
+static void nb8800_get_strings(struct net_device *dev, u32 sset, u8 *buf)
+{
+ if (sset == ETH_SS_STATS)
+ memcpy(buf, &nb8800_stats_names, sizeof(nb8800_stats_names));
+}
+
+static u32 nb8800_read_stat(struct net_device *dev, int index)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+
+ nb8800_writeb(priv, NB8800_STAT_INDEX, index);
+
+ return nb8800_readl(priv, NB8800_STAT_DATA);
+}
+
+static void nb8800_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *estats, u64 *st)
+{
+ unsigned int i;
+ u32 rx, tx;
+
+ for (i = 0; i < NB8800_NUM_STATS / 2; i++) {
+ rx = nb8800_read_stat(dev, i);
+ tx = nb8800_read_stat(dev, i | 0x80);
+ st[i] = rx;
+ st[i + NB8800_NUM_STATS / 2] = tx;
+ }
+}
+
+static const struct ethtool_ops nb8800_ethtool_ops = {
+ .get_settings = nb8800_get_settings,
+ .set_settings = nb8800_set_settings,
+ .nway_reset = nb8800_nway_reset,
+ .get_link = ethtool_op_get_link,
+ .get_pauseparam = nb8800_get_pauseparam,
+ .set_pauseparam = nb8800_set_pauseparam,
+ .get_sset_count = nb8800_get_sset_count,
+ .get_strings = nb8800_get_strings,
+ .get_ethtool_stats = nb8800_get_ethtool_stats,
+};
+
+static int nb8800_hw_init(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ u32 val;
+
+ val = TX_RETRY_EN | TX_PAD_EN | TX_APPEND_FCS;
+ nb8800_writeb(priv, NB8800_TX_CTL1, val);
+
+ /* Collision retry count */
+ nb8800_writeb(priv, NB8800_TX_CTL2, 5);
+
+ val = RX_PAD_STRIP | RX_AF_EN;
+ nb8800_writeb(priv, NB8800_RX_CTL, val);
+
+ /* Chosen by fair dice roll */
+ nb8800_writeb(priv, NB8800_RANDOM_SEED, 4);
+
+ /* TX cycles per deferral period */
+ nb8800_writeb(priv, NB8800_TX_SDP, 12);
+
+ /* The following three threshold values have been
+ * experimentally determined for good results.
+ */
+
+ /* RX/TX FIFO threshold for partial empty (64-bit entries) */
+ nb8800_writeb(priv, NB8800_PE_THRESHOLD, 0);
+
+ /* RX/TX FIFO threshold for partial full (64-bit entries) */
+ nb8800_writeb(priv, NB8800_PF_THRESHOLD, 255);
+
+ /* Buffer size for transmit (64-bit entries) */
+ nb8800_writeb(priv, NB8800_TX_BUFSIZE, 64);
+
+ /* Configure tx DMA */
+
+ val = nb8800_readl(priv, NB8800_TXC_CR);
+ val &= TCR_LE; /* keep endian setting */
+ val |= TCR_DM; /* DMA descriptor mode */
+ val |= TCR_RS; /* automatically store tx status */
+ val |= TCR_DIE; /* interrupt on DMA chain completion */
+ val |= TCR_TFI(7); /* interrupt after 7 frames transmitted */
+ val |= TCR_BTS(2); /* 32-byte bus transaction size */
+ nb8800_writel(priv, NB8800_TXC_CR, val);
+
+ /* TX complete interrupt after 10 ms or 7 frames (see above) */
+ val = clk_get_rate(priv->clk) / 100;
+ nb8800_writel(priv, NB8800_TX_ITR, val);
+
+ /* Configure rx DMA */
+
+ val = nb8800_readl(priv, NB8800_RXC_CR);
+ val &= RCR_LE; /* keep endian setting */
+ val |= RCR_DM; /* DMA descriptor mode */
+ val |= RCR_RS; /* automatically store rx status */
+ val |= RCR_DIE; /* interrupt at end of DMA chain */
+ val |= RCR_RFI(7); /* interrupt after 7 frames received */
+ val |= RCR_BTS(2); /* 32-byte bus transaction size */
+ nb8800_writel(priv, NB8800_RXC_CR, val);
+
+ /* The rx interrupt can fire before the DMA has completed
+ * unless a small delay is added. 50 us is hopefully enough.
+ */
+ priv->rx_itr_irq = clk_get_rate(priv->clk) / 20000;
+
+ /* In NAPI poll mode we want to disable interrupts, but the
+ * hardware does not permit this. Delay 10 ms instead.
+ */
+ priv->rx_itr_poll = clk_get_rate(priv->clk) / 100;
+
+ nb8800_writel(priv, NB8800_RX_ITR, priv->rx_itr_irq);
+
+ priv->rx_dma_config = RX_BUF_SIZE | DESC_BTS(2) | DESC_DS | DESC_EOF;
+
+ /* Flow control settings */
+
+ /* Pause time of 0.1 ms */
+ val = 100000 / 512;
+ nb8800_writeb(priv, NB8800_PQ1, val >> 8);
+ nb8800_writeb(priv, NB8800_PQ2, val & 0xff);
+
+ /* Auto-negotiate by default */
+ priv->pause_aneg = true;
+ priv->pause_rx = true;
+ priv->pause_tx = true;
+
+ nb8800_mc_init(dev, 0);
+
+ return 0;
+}
+
+static int nb8800_tangox_init(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ u32 pad_mode = PAD_MODE_MII;
+
+ switch (priv->phy_mode) {
+ case PHY_INTERFACE_MODE_MII:
+ case PHY_INTERFACE_MODE_GMII:
+ pad_mode = PAD_MODE_MII;
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII:
+ pad_mode = PAD_MODE_RGMII;
+ break;
+
+ case PHY_INTERFACE_MODE_RGMII_TXID:
+ pad_mode = PAD_MODE_RGMII | PAD_MODE_GTX_CLK_DELAY;
+ break;
+
+ default:
+ dev_err(dev->dev.parent, "unsupported phy mode %s\n",
+ phy_modes(priv->phy_mode));
+ return -EINVAL;
+ }
+
+ nb8800_writeb(priv, NB8800_TANGOX_PAD_MODE, pad_mode);
+
+ return 0;
+}
+
+static int nb8800_tangox_reset(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ int clk_div;
+
+ nb8800_writeb(priv, NB8800_TANGOX_RESET, 0);
+ usleep_range(1000, 10000);
+ nb8800_writeb(priv, NB8800_TANGOX_RESET, 1);
+
+ wmb(); /* ensure reset is cleared before proceeding */
+
+ clk_div = DIV_ROUND_UP(clk_get_rate(priv->clk), 2 * MAX_MDC_CLOCK);
+ nb8800_writew(priv, NB8800_TANGOX_MDIO_CLKDIV, clk_div);
+
+ return 0;
+}
+
+static const struct nb8800_ops nb8800_tangox_ops = {
+ .init = nb8800_tangox_init,
+ .reset = nb8800_tangox_reset,
+};
+
+static int nb8800_tango4_init(struct net_device *dev)
+{
+ struct nb8800_priv *priv = netdev_priv(dev);
+ int err;
+
+ err = nb8800_tangox_init(dev);
+ if (err)
+ return err;
+
+ /* On tango4 interrupt on DMA completion per frame works and gives
+ * better performance despite generating more rx interrupts.
+ */
+
+ /* Disable unnecessary interrupt on rx completion */
+ nb8800_clearl(priv, NB8800_RXC_CR, RCR_RFI(7));
+
+ /* Request interrupt on descriptor DMA completion */
+ priv->rx_dma_config |= DESC_ID;
+
+ return 0;
+}
+
+static const struct nb8800_ops nb8800_tango4_ops = {
+ .init = nb8800_tango4_init,
+ .reset = nb8800_tangox_reset,
+};
+
+static const struct of_device_id nb8800_dt_ids[] = {
+ {
+ .compatible = "aurora,nb8800",
+ },
+ {
+ .compatible = "sigma,smp8642-ethernet",
+ .data = &nb8800_tangox_ops,
+ },
+ {
+ .compatible = "sigma,smp8734-ethernet",
+ .data = &nb8800_tango4_ops,
+ },
+ { }
+};
+
+static int nb8800_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ const struct nb8800_ops *ops = NULL;
+ struct nb8800_priv *priv;
+ struct resource *res;
+ struct net_device *dev;
+ struct mii_bus *bus;
+ const unsigned char *mac;
+ void __iomem *base;
+ int irq;
+ int ret;
+
+ match = of_match_device(nb8800_dt_ids, &pdev->dev);
+ if (match)
+ ops = match->data;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(&pdev->dev, "No IRQ\n");
+ return -EINVAL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ dev_dbg(&pdev->dev, "AU-NB8800 Ethernet at %pa\n", &res->start);
+
+ dev = alloc_etherdev(sizeof(*priv));
+ if (!dev)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, dev);
+ SET_NETDEV_DEV(dev, &pdev->dev);
+
+ priv = netdev_priv(dev);
+ priv->base = base;
+
+ priv->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+ if (priv->phy_mode < 0)
+ priv->phy_mode = PHY_INTERFACE_MODE_RGMII;
+
+ priv->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(priv->clk)) {
+ dev_err(&pdev->dev, "failed to get clock\n");
+ ret = PTR_ERR(priv->clk);
+ goto err_free_dev;
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ goto err_free_dev;
+
+ spin_lock_init(&priv->tx_lock);
+
+ if (ops && ops->reset) {
+ ret = ops->reset(dev);
+ if (ret)
+ goto err_free_dev;
+ }
+
+ bus = devm_mdiobus_alloc(&pdev->dev);
+ if (!bus) {
+ ret = -ENOMEM;
+ goto err_disable_clk;
+ }
+
+ bus->name = "nb8800-mii";
+ bus->read = nb8800_mdio_read;
+ bus->write = nb8800_mdio_write;
+ bus->parent = &pdev->dev;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%lx.nb8800-mii",
+ (unsigned long)res->start);
+ bus->priv = priv;
+
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register MII bus\n");
+ goto err_disable_clk;
+ }
+
+ priv->phy_node = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0);
+ if (!priv->phy_node) {
+ dev_err(&pdev->dev, "no PHY specified\n");
+ ret = -ENODEV;
+ goto err_free_bus;
+ }
+
+ priv->mii_bus = bus;
+
+ ret = nb8800_hw_init(dev);
+ if (ret)
+ goto err_free_bus;
+
+ if (ops && ops->init) {
+ ret = ops->init(dev);
+ if (ret)
+ goto err_free_bus;
+ }
+
+ dev->netdev_ops = &nb8800_netdev_ops;
+ dev->ethtool_ops = &nb8800_ethtool_ops;
+ dev->flags |= IFF_MULTICAST;
+ dev->irq = irq;
+
+ mac = of_get_mac_address(pdev->dev.of_node);
+ if (mac)
+ ether_addr_copy(dev->dev_addr, mac);
+
+ if (!is_valid_ether_addr(dev->dev_addr))
+ eth_hw_addr_random(dev);
+
+ nb8800_update_mac_addr(dev);
+
+ netif_carrier_off(dev);
+
+ ret = register_netdev(dev);
+ if (ret) {
+ netdev_err(dev, "failed to register netdev\n");
+ goto err_free_dma;
+ }
+
+ netif_napi_add(dev, &priv->napi, nb8800_poll, NAPI_POLL_WEIGHT);
+
+ netdev_info(dev, "MAC address %pM\n", dev->dev_addr);
+
+ return 0;
+
+err_free_dma:
+ nb8800_dma_free(dev);
+err_free_bus:
+ mdiobus_unregister(bus);
+err_disable_clk:
+ clk_disable_unprepare(priv->clk);
+err_free_dev:
+ free_netdev(dev);
+
+ return ret;
+}
+
+static int nb8800_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct nb8800_priv *priv = netdev_priv(ndev);
+
+ unregister_netdev(ndev);
+
+ mdiobus_unregister(priv->mii_bus);
+
+ clk_disable_unprepare(priv->clk);
+
+ nb8800_dma_free(ndev);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static struct platform_driver nb8800_driver = {
+ .driver = {
+ .name = "nb8800",
+ .of_match_table = nb8800_dt_ids,
+ },
+ .probe = nb8800_probe,
+ .remove = nb8800_remove,
+};
+
+module_platform_driver(nb8800_driver);
+
+MODULE_DESCRIPTION("Aurora AU-NB8800 Ethernet driver");
+MODULE_AUTHOR("Mans Rullgard <mans@mansr.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/aurora/nb8800.h b/drivers/net/ethernet/aurora/nb8800.h
new file mode 100644
index 0000000..e5adbc2
--- /dev/null
+++ b/drivers/net/ethernet/aurora/nb8800.h
@@ -0,0 +1,316 @@
+#ifndef _NB8800_H_
+#define _NB8800_H_
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <linux/phy.h>
+#include <linux/clk.h>
+#include <linux/bitops.h>
+
+#define RX_DESC_COUNT 256
+#define TX_DESC_COUNT 256
+
+#define NB8800_DESC_LOW 4
+
+#define RX_BUF_SIZE 1552
+
+#define RX_COPYBREAK 256
+#define RX_COPYHDR 128
+
+#define MAX_MDC_CLOCK 2500000
+
+/* Stargate Solutions SSN8800 core registers */
+#define NB8800_TX_CTL1 0x000
+#define TX_TPD BIT(5)
+#define TX_APPEND_FCS BIT(4)
+#define TX_PAD_EN BIT(3)
+#define TX_RETRY_EN BIT(2)
+#define TX_EN BIT(0)
+
+#define NB8800_TX_CTL2 0x001
+
+#define NB8800_RX_CTL 0x004
+#define RX_BC_DISABLE BIT(7)
+#define RX_RUNT BIT(6)
+#define RX_AF_EN BIT(5)
+#define RX_PAUSE_EN BIT(3)
+#define RX_SEND_CRC BIT(2)
+#define RX_PAD_STRIP BIT(1)
+#define RX_EN BIT(0)
+
+#define NB8800_RANDOM_SEED 0x008
+#define NB8800_TX_SDP 0x14
+#define NB8800_TX_TPDP1 0x18
+#define NB8800_TX_TPDP2 0x19
+#define NB8800_SLOT_TIME 0x1c
+
+#define NB8800_MDIO_CMD 0x020
+#define MDIO_CMD_GO BIT(31)
+#define MDIO_CMD_WR BIT(26)
+#define MDIO_CMD_ADDR(x) ((x) << 21)
+#define MDIO_CMD_REG(x) ((x) << 16)
+#define MDIO_CMD_DATA(x) ((x) << 0)
+
+#define NB8800_MDIO_STS 0x024
+#define MDIO_STS_ERR BIT(31)
+
+#define NB8800_MC_ADDR(i) (0x028 + (i))
+#define NB8800_MC_INIT 0x02e
+#define NB8800_UC_ADDR(i) (0x03c + (i))
+
+#define NB8800_MAC_MODE 0x044
+#define RGMII_MODE BIT(7)
+#define HALF_DUPLEX BIT(4)
+#define BURST_EN BIT(3)
+#define LOOPBACK_EN BIT(2)
+#define GMAC_MODE BIT(0)
+
+#define NB8800_IC_THRESHOLD 0x050
+#define NB8800_PE_THRESHOLD 0x051
+#define NB8800_PF_THRESHOLD 0x052
+#define NB8800_TX_BUFSIZE 0x054
+#define NB8800_FIFO_CTL 0x056
+#define NB8800_PQ1 0x060
+#define NB8800_PQ2 0x061
+#define NB8800_SRC_ADDR(i) (0x06a + (i))
+#define NB8800_STAT_DATA 0x078
+#define NB8800_STAT_INDEX 0x07c
+#define NB8800_STAT_CLEAR 0x07d
+
+#define NB8800_SLEEP_MODE 0x07e
+#define SLEEP_MODE BIT(0)
+
+#define NB8800_WAKEUP 0x07f
+#define WAKEUP BIT(0)
+
+/* Aurora NB8800 host interface registers */
+#define NB8800_TXC_CR 0x100
+#define TCR_LK BIT(12)
+#define TCR_DS BIT(11)
+#define TCR_BTS(x) (((x) & 0x7) << 8)
+#define TCR_DIE BIT(7)
+#define TCR_TFI(x) (((x) & 0x7) << 4)
+#define TCR_LE BIT(3)
+#define TCR_RS BIT(2)
+#define TCR_DM BIT(1)
+#define TCR_EN BIT(0)
+
+#define NB8800_TXC_SR 0x104
+#define TSR_DE BIT(3)
+#define TSR_DI BIT(2)
+#define TSR_TO BIT(1)
+#define TSR_TI BIT(0)
+
+#define NB8800_TX_SAR 0x108
+#define NB8800_TX_DESC_ADDR 0x10c
+
+#define NB8800_TX_REPORT_ADDR 0x110
+#define TX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xffff)
+#define TX_FIRST_DEFERRAL BIT(7)
+#define TX_EARLY_COLLISIONS(x) (((x) >> 3) & 0xf)
+#define TX_LATE_COLLISION BIT(2)
+#define TX_PACKET_DROPPED BIT(1)
+#define TX_FIFO_UNDERRUN BIT(0)
+#define IS_TX_ERROR(r) ((r) & 0x07)
+
+#define NB8800_TX_FIFO_SR 0x114
+#define NB8800_TX_ITR 0x118
+
+#define NB8800_RXC_CR 0x200
+#define RCR_FL BIT(13)
+#define RCR_LK BIT(12)
+#define RCR_DS BIT(11)
+#define RCR_BTS(x) (((x) & 7) << 8)
+#define RCR_DIE BIT(7)
+#define RCR_RFI(x) (((x) & 7) << 4)
+#define RCR_LE BIT(3)
+#define RCR_RS BIT(2)
+#define RCR_DM BIT(1)
+#define RCR_EN BIT(0)
+
+#define NB8800_RXC_SR 0x204
+#define RSR_DE BIT(3)
+#define RSR_DI BIT(2)
+#define RSR_RO BIT(1)
+#define RSR_RI BIT(0)
+
+#define NB8800_RX_SAR 0x208
+#define NB8800_RX_DESC_ADDR 0x20c
+
+#define NB8800_RX_REPORT_ADDR 0x210
+#define RX_BYTES_TRANSFERRED(x) (((x) >> 16) & 0xFFFF)
+#define RX_MULTICAST_PKT BIT(9)
+#define RX_BROADCAST_PKT BIT(8)
+#define RX_LENGTH_ERR BIT(7)
+#define RX_FCS_ERR BIT(6)
+#define RX_RUNT_PKT BIT(5)
+#define RX_FIFO_OVERRUN BIT(4)
+#define RX_LATE_COLLISION BIT(3)
+#define RX_ALIGNMENT_ERROR BIT(2)
+#define RX_ERROR_MASK 0xfc
+#define IS_RX_ERROR(r) ((r) & RX_ERROR_MASK)
+
+#define NB8800_RX_FIFO_SR 0x214
+#define NB8800_RX_ITR 0x218
+
+/* Sigma Designs SMP86xx additional registers */
+#define NB8800_TANGOX_PAD_MODE 0x400
+#define PAD_MODE_MASK 0x7
+#define PAD_MODE_MII 0x0
+#define PAD_MODE_RGMII 0x1
+#define PAD_MODE_GTX_CLK_INV BIT(3)
+#define PAD_MODE_GTX_CLK_DELAY BIT(4)
+
+#define NB8800_TANGOX_MDIO_CLKDIV 0x420
+#define NB8800_TANGOX_RESET 0x424
+
+/* Hardware DMA descriptor */
+struct nb8800_dma_desc {
+ u32 s_addr; /* start address */
+ u32 n_addr; /* next descriptor address */
+ u32 r_addr; /* report address */
+ u32 config;
+} __aligned(8);
+
+#define DESC_ID BIT(23)
+#define DESC_EOC BIT(22)
+#define DESC_EOF BIT(21)
+#define DESC_LK BIT(20)
+#define DESC_DS BIT(19)
+#define DESC_BTS(x) (((x) & 0x7) << 16)
+
+/* DMA descriptor and associated data for rx.
+ * Allocated from coherent memory.
+ */
+struct nb8800_rx_desc {
+ /* DMA descriptor */
+ struct nb8800_dma_desc desc;
+
+ /* Status report filled in by hardware */
+ u32 report;
+};
+
+/* Address of buffer on rx ring */
+struct nb8800_rx_buf {
+ struct page *page;
+ unsigned long offset;
+};
+
+/* DMA descriptors and associated data for tx.
+ * Allocated from coherent memory.
+ */
+struct nb8800_tx_desc {
+ /* DMA descriptor. The second descriptor is used if packet
+ * data is unaligned.
+ */
+ struct nb8800_dma_desc desc[2];
+
+ /* Status report filled in by hardware */
+ u32 report;
+
+ /* Bounce buffer for initial unaligned part of packet */
+ u8 buf[8] __aligned(8);
+};
+
+/* Packet in tx queue */
+struct nb8800_tx_buf {
+ /* Currently queued skb */
+ struct sk_buff *skb;
+
+ /* DMA address of the first descriptor */
+ dma_addr_t dma_desc;
+
+ /* DMA address of packet data */
+ dma_addr_t dma_addr;
+
+ /* Length of DMA mapping, less than skb->len if alignment
+ * buffer is used.
+ */
+ unsigned int dma_len;
+
+ /* Number of packets in chain starting here */
+ unsigned int chain_len;
+
+ /* Packet chain ready to be submitted to hardware */
+ bool ready;
+};
+
+struct nb8800_priv {
+ struct napi_struct napi;
+
+ void __iomem *base;
+
+ /* RX DMA descriptors */
+ struct nb8800_rx_desc *rx_descs;
+
+ /* RX buffers referenced by DMA descriptors */
+ struct nb8800_rx_buf *rx_bufs;
+
+ /* Current end of chain */
+ u32 rx_eoc;
+
+ /* Value for rx interrupt time register in NAPI interrupt mode */
+ u32 rx_itr_irq;
+
+ /* Value for rx interrupt time register in NAPI poll mode */
+ u32 rx_itr_poll;
+
+ /* Value for config field of rx DMA descriptors */
+ u32 rx_dma_config;
+
+ /* TX DMA descriptors */
+ struct nb8800_tx_desc *tx_descs;
+
+ /* TX packet queue */
+ struct nb8800_tx_buf *tx_bufs;
+
+ /* Number of free tx queue entries */
+ atomic_t tx_free;
+
+ /* First free tx queue entry */
+ u32 tx_next;
+
+ /* Next buffer to transmit */
+ u32 tx_queue;
+
+ /* Start of current packet chain */
+ struct nb8800_tx_buf *tx_chain;
+
+ /* Next buffer to reclaim */
+ u32 tx_done;
+
+ /* Lock for DMA activation */
+ spinlock_t tx_lock;
+
+ struct mii_bus *mii_bus;
+ struct device_node *phy_node;
+ struct phy_device *phydev;
+
+ /* PHY connection type from DT */
+ int phy_mode;
+
+ /* Current link status */
+ int speed;
+ int duplex;
+ int link;
+
+ /* Pause settings */
+ bool pause_aneg;
+ bool pause_rx;
+ bool pause_tx;
+
+ /* DMA base address of rx descriptors, see rx_descs above */
+ dma_addr_t rx_desc_dma;
+
+ /* DMA base address of tx descriptors, see tx_descs above */
+ dma_addr_t tx_desc_dma;
+
+ struct clk *clk;
+};
+
+struct nb8800_ops {
+ int (*init)(struct net_device *dev);
+ int (*reset)(struct net_device *dev);
+};
+
+#endif /* _NB8800_H_ */
diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig
index 67a7d52..8550df1 100644
--- a/drivers/net/ethernet/broadcom/Kconfig
+++ b/drivers/net/ethernet/broadcom/Kconfig
@@ -173,6 +173,7 @@ config SYSTEMPORT
config BNXT
tristate "Broadcom NetXtreme-C/E support"
depends on PCI
+ depends on VXLAN || VXLAN=n
select FW_LOADER
select LIBCRC32C
---help---
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index f8d7a2f..c82ab87 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -3430,25 +3430,29 @@ static u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb)
return rc;
}
-#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - 3)
+/* VXLAN: 4 = 1 (for linear data BD) + 3 (2 for PBD and last BD) */
+#define BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS 4
+
+/* Regular: 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
+#define BNX2X_NUM_TSO_WIN_SUB_BDS 3
+
+#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT)
/* check if packet requires linearization (packet is too fragmented)
no need to check fragmentation if page size > 8K (there will be no
violation to FW restrictions) */
static int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb,
u32 xmit_type)
{
- int to_copy = 0;
- int hlen = 0;
- int first_bd_sz = 0;
+ int first_bd_sz = 0, num_tso_win_sub = BNX2X_NUM_TSO_WIN_SUB_BDS;
+ int to_copy = 0, hlen = 0;
- /* 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */
- if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - 3)) {
+ if (xmit_type & XMIT_GSO_ENC)
+ num_tso_win_sub = BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS;
+ if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - num_tso_win_sub)) {
if (xmit_type & XMIT_GSO) {
unsigned short lso_mss = skb_shinfo(skb)->gso_size;
- /* Check if LSO packet needs to be copied:
- 3 = 1 (for headers BD) + 2 (for PBD and last BD) */
- int wnd_size = MAX_FETCH_BD - 3;
+ int wnd_size = MAX_FETCH_BD - num_tso_win_sub;
/* Number of windows to check */
int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size;
int wnd_idx = 0;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index f1d62d5..2e611dc 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -10139,8 +10139,8 @@ static void __bnx2x_del_vxlan_port(struct bnx2x *bp, u16 port)
DP(BNX2X_MSG_SP, "Invalid vxlan port\n");
return;
}
- bp->vxlan_dst_port--;
- if (bp->vxlan_dst_port)
+ bp->vxlan_dst_port_count--;
+ if (bp->vxlan_dst_port_count)
return;
if (netif_running(bp->dev)) {
@@ -13207,7 +13207,7 @@ static int bnx2x_init_dev(struct bnx2x *bp, struct pci_dev *pdev,
/* VF with OLD Hypervisor or old PF do not support filtering */
if (IS_PF(bp)) {
- if (CHIP_IS_E1x(bp))
+ if (chip_is_e1x)
bp->accept_any_vlan = true;
else
dev->hw_features |= NETIF_F_HW_VLAN_CTAG_FILTER;
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 6c2e0c6..07f5f23 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -1292,8 +1292,6 @@ static inline int bnxt_has_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr)
return TX_CMP_VALID(txcmp, raw_cons);
}
-#define CAG_LEGACY_INT_STATUS 0x2014
-
static irqreturn_t bnxt_inta(int irq, void *dev_instance)
{
struct bnxt_napi *bnapi = dev_instance;
@@ -1305,7 +1303,7 @@ static irqreturn_t bnxt_inta(int irq, void *dev_instance)
prefetch(&cpr->cp_desc_ring[CP_RING(cons)][CP_IDX(cons)]);
if (!bnxt_has_work(bp, cpr)) {
- int_status = readl(bp->bar0 + CAG_LEGACY_INT_STATUS);
+ int_status = readl(bp->bar0 + BNXT_CAG_REG_LEGACY_INT_STATUS);
/* return if erroneous interrupt */
if (!(int_status & (0x10000 << cpr->cp_ring_struct.fw_ring_id)))
return IRQ_NONE;
@@ -2695,17 +2693,16 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
req.ver_upd = DRV_VER_UPD;
if (BNXT_PF(bp)) {
- unsigned long vf_req_snif_bmap[4];
+ DECLARE_BITMAP(vf_req_snif_bmap, 256);
u32 *data = (u32 *)vf_req_snif_bmap;
- memset(vf_req_snif_bmap, 0, 32);
+ memset(vf_req_snif_bmap, 0, sizeof(vf_req_snif_bmap));
for (i = 0; i < ARRAY_SIZE(bnxt_vf_req_snif); i++)
__set_bit(bnxt_vf_req_snif[i], vf_req_snif_bmap);
- for (i = 0; i < 8; i++) {
- req.vf_req_fwd[i] = cpu_to_le32(*data);
- data++;
- }
+ for (i = 0; i < 8; i++)
+ req.vf_req_fwd[i] = cpu_to_le32(data[i]);
+
req.enables |=
cpu_to_le32(FUNC_DRV_RGTR_REQ_ENABLES_VF_REQ_FWD);
}
@@ -3627,6 +3624,7 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
pf->fw_fid = le16_to_cpu(resp->fid);
pf->port_id = le16_to_cpu(resp->port_id);
memcpy(pf->mac_addr, resp->perm_mac_address, ETH_ALEN);
+ memcpy(bp->dev->dev_addr, pf->mac_addr, ETH_ALEN);
pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
pf->max_tx_rings = le16_to_cpu(resp->max_tx_rings);
@@ -3650,8 +3648,11 @@ static int bnxt_hwrm_func_qcaps(struct bnxt *bp)
vf->fw_fid = le16_to_cpu(resp->fid);
memcpy(vf->mac_addr, resp->perm_mac_address, ETH_ALEN);
- if (!is_valid_ether_addr(vf->mac_addr))
- random_ether_addr(vf->mac_addr);
+ if (is_valid_ether_addr(vf->mac_addr))
+ /* overwrite netdev dev_adr with admin VF MAC */
+ memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN);
+ else
+ random_ether_addr(bp->dev->dev_addr);
vf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
vf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
@@ -3882,6 +3883,8 @@ static int bnxt_alloc_rfs_vnics(struct bnxt *bp)
#endif
}
+static int bnxt_cfg_rx_mode(struct bnxt *);
+
static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
{
int rc = 0;
@@ -3948,11 +3951,9 @@ static int bnxt_init_chip(struct bnxt *bp, bool irq_re_init)
bp->vnic_info[0].rx_mask |=
CFA_L2_SET_RX_MASK_REQ_MASK_PROMISCUOUS;
- rc = bnxt_hwrm_cfa_l2_set_rx_mask(bp, 0);
- if (rc) {
- netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n", rc);
+ rc = bnxt_cfg_rx_mode(bp);
+ if (rc)
goto err_out;
- }
rc = bnxt_hwrm_set_coal(bp);
if (rc)
@@ -4527,10 +4528,25 @@ static int bnxt_update_phy_setting(struct bnxt *bp)
return rc;
}
+/* Common routine to pre-map certain register block to different GRC window.
+ * A PF has 16 4K windows and a VF has 4 4K windows. However, only 15 windows
+ * in PF and 3 windows in VF that can be customized to map in different
+ * register blocks.
+ */
+static void bnxt_preset_reg_win(struct bnxt *bp)
+{
+ if (BNXT_PF(bp)) {
+ /* CAG registers map to GRC window #4 */
+ writel(BNXT_CAG_REG_BASE,
+ bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT + 12);
+ }
+}
+
static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
{
int rc = 0;
+ bnxt_preset_reg_win(bp);
netif_carrier_off(bp->dev);
if (irq_re_init) {
rc = bnxt_setup_int_mode(bp);
@@ -4586,7 +4602,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
bp->nge_port_cnt = 1;
}
- bp->state = BNXT_STATE_OPEN;
+ set_bit(BNXT_STATE_OPEN, &bp->state);
bnxt_enable_int(bp);
/* Enable TX queues */
bnxt_tx_enable(bp);
@@ -4662,8 +4678,10 @@ int bnxt_close_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init)
/* Change device state to avoid TX queue wake up's */
bnxt_tx_disable(bp);
- bp->state = BNXT_STATE_CLOSED;
- cancel_work_sync(&bp->sp_task);
+ clear_bit(BNXT_STATE_OPEN, &bp->state);
+ smp_mb__after_atomic();
+ while (test_bit(BNXT_STATE_IN_SP_TASK, &bp->state))
+ msleep(20);
/* Flush rings before disabling interrupts */
bnxt_shutdown_nic(bp, irq_re_init);
@@ -4852,7 +4870,7 @@ static void bnxt_set_rx_mode(struct net_device *dev)
}
}
-static void bnxt_cfg_rx_mode(struct bnxt *bp)
+static int bnxt_cfg_rx_mode(struct bnxt *bp)
{
struct net_device *dev = bp->dev;
struct bnxt_vnic_info *vnic = &bp->vnic_info[0];
@@ -4901,6 +4919,7 @@ static void bnxt_cfg_rx_mode(struct bnxt *bp)
netdev_err(bp->dev, "HWRM vnic filter failure rc: %x\n",
rc);
vnic->uc_filter_count = i;
+ return rc;
}
}
@@ -4909,6 +4928,8 @@ skip_uc:
if (rc)
netdev_err(bp->dev, "HWRM cfa l2 rx mask failure rc: %x\n",
rc);
+
+ return rc;
}
static netdev_features_t bnxt_fix_features(struct net_device *dev,
@@ -5010,8 +5031,10 @@ static void bnxt_dbg_dump_states(struct bnxt *bp)
static void bnxt_reset_task(struct bnxt *bp)
{
bnxt_dbg_dump_states(bp);
- if (netif_running(bp->dev))
- bnxt_tx_disable(bp); /* prevent tx timout again */
+ if (netif_running(bp->dev)) {
+ bnxt_close_nic(bp, false, false);
+ bnxt_open_nic(bp, false, false);
+ }
}
static void bnxt_tx_timeout(struct net_device *dev)
@@ -5061,8 +5084,12 @@ static void bnxt_sp_task(struct work_struct *work)
struct bnxt *bp = container_of(work, struct bnxt, sp_task);
int rc;
- if (bp->state != BNXT_STATE_OPEN)
+ set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+ smp_mb__after_atomic();
+ if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
+ clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
return;
+ }
if (test_and_clear_bit(BNXT_RX_MASK_SP_EVENT, &bp->sp_event))
bnxt_cfg_rx_mode(bp);
@@ -5086,8 +5113,19 @@ static void bnxt_sp_task(struct work_struct *work)
bnxt_hwrm_tunnel_dst_port_free(
bp, TUNNEL_DST_PORT_FREE_REQ_TUNNEL_TYPE_VXLAN);
}
- if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event))
+ if (test_and_clear_bit(BNXT_RESET_TASK_SP_EVENT, &bp->sp_event)) {
+ /* bnxt_reset_task() calls bnxt_close_nic() which waits
+ * for BNXT_STATE_IN_SP_TASK to clear.
+ */
+ clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+ rtnl_lock();
bnxt_reset_task(bp);
+ set_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
+ rtnl_unlock();
+ }
+
+ smp_mb__before_atomic();
+ clear_bit(BNXT_STATE_IN_SP_TASK, &bp->state);
}
static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
@@ -5166,7 +5204,7 @@ static int bnxt_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->timer.function = bnxt_timer;
bp->current_interval = BNXT_TIMER_INTERVAL;
- bp->state = BNXT_STATE_CLOSED;
+ clear_bit(BNXT_STATE_OPEN, &bp->state);
return 0;
@@ -5199,13 +5237,27 @@ init_err:
static int bnxt_change_mac_addr(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
+ struct bnxt *bp = netdev_priv(dev);
+ int rc = 0;
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
+#ifdef CONFIG_BNXT_SRIOV
+ if (BNXT_VF(bp) && is_valid_ether_addr(bp->vf.mac_addr))
+ return -EADDRNOTAVAIL;
+#endif
+
+ if (ether_addr_equal(addr->sa_data, dev->dev_addr))
+ return 0;
+
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+ if (netif_running(dev)) {
+ bnxt_close_nic(bp, false, false);
+ rc = bnxt_open_nic(bp, false, false);
+ }
- return 0;
+ return rc;
}
/* rtnl_lock held */
@@ -5294,7 +5346,7 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
struct bnxt_ntuple_filter *fltr, *new_fltr;
struct flow_keys *fkeys;
struct ethhdr *eth = (struct ethhdr *)skb_mac_header(skb);
- int rc = 0, idx;
+ int rc = 0, idx, bit_id;
struct hlist_head *head;
if (skb->encapsulation)
@@ -5332,14 +5384,15 @@ static int bnxt_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
rcu_read_unlock();
spin_lock_bh(&bp->ntp_fltr_lock);
- new_fltr->sw_id = bitmap_find_free_region(bp->ntp_fltr_bmap,
- BNXT_NTP_FLTR_MAX_FLTR, 0);
- if (new_fltr->sw_id < 0) {
+ bit_id = bitmap_find_free_region(bp->ntp_fltr_bmap,
+ BNXT_NTP_FLTR_MAX_FLTR, 0);
+ if (bit_id < 0) {
spin_unlock_bh(&bp->ntp_fltr_lock);
rc = -ENOMEM;
goto err_free;
}
+ new_fltr->sw_id = (u16)bit_id;
new_fltr->flow_id = flow_id;
new_fltr->rxq = rxq_index;
hlist_add_head_rcu(&new_fltr->hash, head);
@@ -5672,15 +5725,12 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
bnxt_set_tpa_flags(bp);
bnxt_set_ring_params(bp);
dflt_rings = netif_get_num_default_rss_queues();
- if (BNXT_PF(bp)) {
- memcpy(dev->dev_addr, bp->pf.mac_addr, ETH_ALEN);
+ if (BNXT_PF(bp))
bp->pf.max_irqs = max_irqs;
- } else {
#if defined(CONFIG_BNXT_SRIOV)
- memcpy(dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
+ else
bp->vf.max_irqs = max_irqs;
#endif
- }
bnxt_get_max_rings(bp, &max_rx_rings, &max_tx_rings);
bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings);
bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings);
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index 4f2267c..f199f4c 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
@@ -166,9 +166,11 @@ struct rx_cmp {
#define RX_CMP_HASH_VALID(rxcmp) \
((rxcmp)->rx_cmp_len_flags_type & cpu_to_le32(RX_CMP_FLAGS_RSS_VALID))
+#define RSS_PROFILE_ID_MASK 0x1f
+
#define RX_CMP_HASH_TYPE(rxcmp) \
- ((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
- RX_CMP_RSS_HASH_TYPE_SHIFT)
+ (((le32_to_cpu((rxcmp)->rx_cmp_misc_v1) & RX_CMP_RSS_HASH_TYPE) >>\
+ RX_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
struct rx_cmp_ext {
__le32 rx_cmp_flags2;
@@ -282,9 +284,9 @@ struct rx_tpa_start_cmp {
cpu_to_le32(RX_TPA_START_CMP_FLAGS_RSS_VALID))
#define TPA_START_HASH_TYPE(rx_tpa_start) \
- ((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
- RX_TPA_START_CMP_RSS_HASH_TYPE) >> \
- RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT)
+ (((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
+ RX_TPA_START_CMP_RSS_HASH_TYPE) >> \
+ RX_TPA_START_CMP_RSS_HASH_TYPE_SHIFT) & RSS_PROFILE_ID_MASK)
#define TPA_START_AGG_ID(rx_tpa_start) \
((le32_to_cpu((rx_tpa_start)->rx_tpa_start_cmp_misc_v1) & \
@@ -839,6 +841,10 @@ struct bnxt_queue_info {
u8 queue_profile;
};
+#define BNXT_GRCPF_REG_WINDOW_BASE_OUT 0x400
+#define BNXT_CAG_REG_LEGACY_INT_STATUS 0x4014
+#define BNXT_CAG_REG_BASE 0x300000
+
struct bnxt {
void __iomem *bar0;
void __iomem *bar1;
@@ -919,9 +925,9 @@ struct bnxt {
struct timer_list timer;
- int state;
-#define BNXT_STATE_CLOSED 0
-#define BNXT_STATE_OPEN 1
+ unsigned long state;
+#define BNXT_STATE_OPEN 0
+#define BNXT_STATE_IN_SP_TASK 1
struct bnxt_irq *irq_tbl;
u8 mac_addr[ETH_ALEN];
@@ -959,11 +965,11 @@ struct bnxt {
#define BNXT_RX_MASK_SP_EVENT 0
#define BNXT_RX_NTP_FLTR_SP_EVENT 1
#define BNXT_LINK_CHNG_SP_EVENT 2
-#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 4
-#define BNXT_VXLAN_ADD_PORT_SP_EVENT 8
-#define BNXT_VXLAN_DEL_PORT_SP_EVENT 16
-#define BNXT_RESET_TASK_SP_EVENT 32
-#define BNXT_RST_RING_SP_EVENT 64
+#define BNXT_HWRM_EXEC_FWD_REQ_SP_EVENT 3
+#define BNXT_VXLAN_ADD_PORT_SP_EVENT 4
+#define BNXT_VXLAN_DEL_PORT_SP_EVENT 5
+#define BNXT_RESET_TASK_SP_EVENT 6
+#define BNXT_RST_RING_SP_EVENT 7
struct bnxt_pf_info pf;
#ifdef CONFIG_BNXT_SRIOV
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
index 60989e7..ea044bb 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_sriov.c
@@ -21,7 +21,7 @@
#ifdef CONFIG_BNXT_SRIOV
static int bnxt_vf_ndo_prep(struct bnxt *bp, int vf_id)
{
- if (bp->state != BNXT_STATE_OPEN) {
+ if (!test_bit(BNXT_STATE_OPEN, &bp->state)) {
netdev_err(bp->dev, "vf ndo called though PF is down\n");
return -EINVAL;
}
@@ -258,7 +258,7 @@ static int bnxt_set_vf_attr(struct bnxt *bp, int num_vfs)
return 0;
}
-static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp)
+static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp, int num_vfs)
{
int i, rc = 0;
struct bnxt_pf_info *pf = &bp->pf;
@@ -267,7 +267,7 @@ static int bnxt_hwrm_func_vf_resource_free(struct bnxt *bp)
bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_VF_RESC_FREE, -1, -1);
mutex_lock(&bp->hwrm_cmd_lock);
- for (i = pf->first_vf_id; i < pf->first_vf_id + pf->active_vfs; i++) {
+ for (i = pf->first_vf_id; i < pf->first_vf_id + num_vfs; i++) {
req.vf_id = cpu_to_le16(i);
rc = _hwrm_send_message(bp, &req, sizeof(req),
HWRM_CMD_TIMEOUT);
@@ -509,7 +509,7 @@ static int bnxt_sriov_enable(struct bnxt *bp, int *num_vfs)
err_out2:
/* Free the resources reserved for various VF's */
- bnxt_hwrm_func_vf_resource_free(bp);
+ bnxt_hwrm_func_vf_resource_free(bp, *num_vfs);
err_out1:
bnxt_free_vf_resources(bp);
@@ -519,13 +519,19 @@ err_out1:
void bnxt_sriov_disable(struct bnxt *bp)
{
- if (!bp->pf.active_vfs)
- return;
+ u16 num_vfs = pci_num_vf(bp->pdev);
- pci_disable_sriov(bp->pdev);
+ if (!num_vfs)
+ return;
- /* Free the resources reserved for various VF's */
- bnxt_hwrm_func_vf_resource_free(bp);
+ if (pci_vfs_assigned(bp->pdev)) {
+ netdev_warn(bp->dev, "Unable to free %d VFs because some are assigned to VMs.\n",
+ num_vfs);
+ } else {
+ pci_disable_sriov(bp->pdev);
+ /* Free the HW resources reserved for various VF's */
+ bnxt_hwrm_func_vf_resource_free(bp, num_vfs);
+ }
bnxt_free_vf_resources(bp);
@@ -552,17 +558,25 @@ int bnxt_sriov_configure(struct pci_dev *pdev, int num_vfs)
}
bp->sriov_cfg = true;
rtnl_unlock();
- if (!num_vfs) {
- bnxt_sriov_disable(bp);
- return 0;
+
+ if (pci_vfs_assigned(bp->pdev)) {
+ netdev_warn(dev, "Unable to configure SRIOV since some VFs are assigned to VMs.\n");
+ num_vfs = 0;
+ goto sriov_cfg_exit;
}
/* Check if enabled VFs is same as requested */
- if (num_vfs == bp->pf.active_vfs)
- return 0;
+ if (num_vfs && num_vfs == bp->pf.active_vfs)
+ goto sriov_cfg_exit;
+
+ /* if there are previous existing VFs, clean them up */
+ bnxt_sriov_disable(bp);
+ if (!num_vfs)
+ goto sriov_cfg_exit;
bnxt_sriov_enable(bp, &num_vfs);
+sriov_cfg_exit:
bp->sriov_cfg = false;
wake_up(&bp->sriov_cfg_wait);
@@ -790,10 +804,9 @@ void bnxt_update_vf_mac(struct bnxt *bp)
if (!is_valid_ether_addr(resp->perm_mac_address))
goto update_vf_mac_exit;
- if (ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr))
- goto update_vf_mac_exit;
-
- memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN);
+ if (!ether_addr_equal(resp->perm_mac_address, bp->vf.mac_addr))
+ memcpy(bp->vf.mac_addr, resp->perm_mac_address, ETH_ALEN);
+ /* overwrite netdev dev_adr with admin VF MAC */
memcpy(bp->dev->dev_addr, bp->vf.mac_addr, ETH_ALEN);
update_vf_mac_exit:
mutex_unlock(&bp->hwrm_cmd_lock);
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 88c1e1a..169059c 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -1682,6 +1682,8 @@ static void macb_init_hw(struct macb *bp)
macb_set_hwaddr(bp);
config = macb_mdc_clk_div(bp);
+ if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ config |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */
config |= MACB_BIT(PAE); /* PAuse Enable */
config |= MACB_BIT(DRFCS); /* Discard Rx FCS */
@@ -2416,6 +2418,8 @@ static int macb_init(struct platform_device *pdev)
/* Set MII management clock divider */
val = macb_mdc_clk_div(bp);
val |= macb_dbw(bp);
+ if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII)
+ val |= GEM_BIT(SGMIIEN) | GEM_BIT(PCSSEL);
macb_writel(bp, NCFGR, val);
return 0;
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 6e1faea..d83b0db 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -215,12 +215,17 @@
/* GEM specific NCFGR bitfields. */
#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */
#define GEM_GBE_SIZE 1
+#define GEM_PCSSEL_OFFSET 11
+#define GEM_PCSSEL_SIZE 1
#define GEM_CLK_OFFSET 18 /* MDC clock division */
#define GEM_CLK_SIZE 3
#define GEM_DBW_OFFSET 21 /* Data bus width */
#define GEM_DBW_SIZE 2
#define GEM_RXCOEN_OFFSET 24
#define GEM_RXCOEN_SIZE 1
+#define GEM_SGMIIEN_OFFSET 27
+#define GEM_SGMIIEN_SIZE 1
+
/* Constants for data bus width. */
#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */
diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c
index f683d97..b895044 100644
--- a/drivers/net/ethernet/cavium/liquidio/lio_main.c
+++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c
@@ -560,7 +560,7 @@ static int liquidio_resume(struct pci_dev *pdev)
#endif
/* For PCI-E Advanced Error Recovery (AER) Interface */
-static struct pci_error_handlers liquidio_err_handler = {
+static const struct pci_error_handlers liquidio_err_handler = {
.error_detected = liquidio_pcie_error_detected,
.mmio_enabled = liquidio_pcie_mmio_enabled,
.slot_reset = liquidio_pcie_slot_reset,
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index d3950b2..39ca674 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -120,10 +120,9 @@
* Calculated for SCLK of 700Mhz
* value written should be a 1/16th of what is expected
*
- * 1 tick per 0.05usec = value of 2.2
- * This 10% would be covered in CQ timer thresh value
+ * 1 tick per 0.025usec
*/
-#define NICPF_CLK_PER_INT_TICK 2
+#define NICPF_CLK_PER_INT_TICK 1
/* Time to wait before we decide that a SQ is stuck.
*
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index c561fdc..5f24d11 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -615,6 +615,21 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
return 0;
}
+static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
+{
+ int bgx, lmac;
+
+ nic->vf_enabled[vf] = enable;
+
+ if (vf >= nic->num_vf_en)
+ return;
+
+ bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+ lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]);
+
+ bgx_lmac_rx_tx_enable(nic->node, bgx, lmac, enable);
+}
+
/* Interrupt handler to handle mailbox messages from VFs */
static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
{
@@ -714,14 +729,14 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
break;
case NIC_MBOX_MSG_CFG_DONE:
/* Last message of VF config msg sequence */
- nic->vf_enabled[vf] = true;
+ nic_enable_vf(nic, vf, true);
goto unlock;
case NIC_MBOX_MSG_SHUTDOWN:
/* First msg in VF teardown sequence */
- nic->vf_enabled[vf] = false;
if (vf >= nic->num_vf_en)
nic->sqs_used[vf - nic->num_vf_en] = false;
nic->pqs_vf[vf] = 0;
+ nic_enable_vf(nic, vf, false);
break;
case NIC_MBOX_MSG_ALLOC_SQS:
nic_alloc_sqs(nic, &mbx.sqs_alloc);
@@ -1074,8 +1089,7 @@ static void nic_remove(struct pci_dev *pdev)
if (nic->check_link) {
/* Destroy work Queue */
- cancel_delayed_work(&nic->dwork);
- flush_workqueue(nic->check_link);
+ cancel_delayed_work_sync(&nic->dwork);
destroy_workqueue(nic->check_link);
}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
index af54c10..a12b2e3 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c
@@ -112,6 +112,13 @@ static int nicvf_get_settings(struct net_device *netdev,
cmd->supported = 0;
cmd->transceiver = XCVR_EXTERNAL;
+
+ if (!nic->link_up) {
+ cmd->duplex = DUPLEX_UNKNOWN;
+ ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN);
+ return 0;
+ }
+
if (nic->speed <= 1000) {
cmd->port = PORT_MII;
cmd->autoneg = AUTONEG_ENABLE;
@@ -125,6 +132,13 @@ static int nicvf_get_settings(struct net_device *netdev,
return 0;
}
+static u32 nicvf_get_link(struct net_device *netdev)
+{
+ struct nicvf *nic = netdev_priv(netdev);
+
+ return nic->link_up;
+}
+
static void nicvf_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *info)
{
@@ -660,7 +674,7 @@ static int nicvf_set_channels(struct net_device *dev,
static const struct ethtool_ops nicvf_ethtool_ops = {
.get_settings = nicvf_get_settings,
- .get_link = ethtool_op_get_link,
+ .get_link = nicvf_get_link,
.get_drvinfo = nicvf_get_drvinfo,
.get_msglevel = nicvf_get_msglevel,
.set_msglevel = nicvf_set_msglevel,
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index a937772..dde8dc7 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -1057,6 +1057,7 @@ int nicvf_stop(struct net_device *netdev)
netif_carrier_off(netdev);
netif_tx_stop_all_queues(nic->netdev);
+ nic->link_up = false;
/* Teardown secondary qsets first */
if (!nic->sqs_mode) {
@@ -1211,9 +1212,6 @@ int nicvf_open(struct net_device *netdev)
nic->drv_stats.txq_stop = 0;
nic->drv_stats.txq_wake = 0;
- netif_carrier_on(netdev);
- netif_tx_start_all_queues(netdev);
-
return 0;
cleanup:
nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0);
@@ -1583,8 +1581,14 @@ err_disable_device:
static void nicvf_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct nicvf *nic = netdev_priv(netdev);
- struct net_device *pnetdev = nic->pnicvf->netdev;
+ struct nicvf *nic;
+ struct net_device *pnetdev;
+
+ if (!netdev)
+ return;
+
+ nic = netdev_priv(netdev);
+ pnetdev = nic->pnicvf->netdev;
/* Check if this Qset is assigned to different VF.
* If yes, clean primary and all secondary Qsets.
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
index e404ea8..206b6a7 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c
@@ -592,7 +592,7 @@ void nicvf_cmp_queue_config(struct nicvf *nic, struct queue_set *qs,
/* Set threshold value for interrupt generation */
nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_THRESH, qidx, cq->thresh);
nicvf_queue_reg_write(nic, NIC_QSET_CQ_0_7_CFG2,
- qidx, nic->cq_coalesce_usecs);
+ qidx, CMP_QUEUE_TIMER_THRESH);
}
/* Configures transmit queue */
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
index fb4957d..033e830 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h
@@ -76,7 +76,7 @@
#define CMP_QSIZE CMP_QUEUE_SIZE2
#define CMP_QUEUE_LEN (1ULL << (CMP_QSIZE + 10))
#define CMP_QUEUE_CQE_THRESH 0
-#define CMP_QUEUE_TIMER_THRESH 220 /* 10usec */
+#define CMP_QUEUE_TIMER_THRESH 80 /* ~2usec */
#define RBDR_SIZE RBDR_SIZE0
#define RCV_BUF_COUNT (1ULL << (RBDR_SIZE + 13))
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
index 180aa9f..9df26c2 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c
@@ -186,6 +186,23 @@ void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac)
}
EXPORT_SYMBOL(bgx_set_lmac_mac);
+void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable)
+{
+ struct bgx *bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx];
+ u64 cfg;
+
+ if (!bgx)
+ return;
+
+ cfg = bgx_reg_read(bgx, lmacid, BGX_CMRX_CFG);
+ if (enable)
+ cfg |= CMR_PKT_RX_EN | CMR_PKT_TX_EN;
+ else
+ cfg &= ~(CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+ bgx_reg_write(bgx, lmacid, BGX_CMRX_CFG, cfg);
+}
+EXPORT_SYMBOL(bgx_lmac_rx_tx_enable);
+
static void bgx_sgmii_change_link_state(struct lmac *lmac)
{
struct bgx *bgx = lmac->bgx;
@@ -612,6 +629,8 @@ static void bgx_poll_for_link(struct work_struct *work)
lmac->last_duplex = 1;
} else {
lmac->link_up = 0;
+ lmac->last_speed = SPEED_UNKNOWN;
+ lmac->last_duplex = DUPLEX_UNKNOWN;
}
if (lmac->last_link != lmac->link_up) {
@@ -654,8 +673,7 @@ static int bgx_lmac_enable(struct bgx *bgx, u8 lmacid)
}
/* Enable lmac */
- bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG,
- CMR_EN | CMR_PKT_RX_EN | CMR_PKT_TX_EN);
+ bgx_reg_modify(bgx, lmacid, BGX_CMRX_CFG, CMR_EN);
/* Restore default cfg, incase low level firmware changed it */
bgx_reg_write(bgx, lmacid, BGX_CMRX_RX_DMAC_CTL, 0x03);
@@ -695,8 +713,7 @@ static void bgx_lmac_disable(struct bgx *bgx, u8 lmacid)
lmac = &bgx->lmac[lmacid];
if (lmac->check_link) {
/* Destroy work queue */
- cancel_delayed_work(&lmac->dwork);
- flush_workqueue(lmac->check_link);
+ cancel_delayed_work_sync(&lmac->dwork);
destroy_workqueue(lmac->check_link);
}
@@ -1009,6 +1026,9 @@ static int bgx_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct bgx *bgx = NULL;
u8 lmac;
+ /* Load octeon mdio driver */
+ octeon_mdiobus_force_mod_depencency();
+
bgx = devm_kzalloc(dev, sizeof(*bgx), GFP_KERNEL);
if (!bgx)
return -ENOMEM;
diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
index 07b7ec66..149e179 100644
--- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
+++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h
@@ -182,6 +182,8 @@ enum MCAST_MODE {
#define BCAST_ACCEPT 1
#define CAM_ACCEPT 1
+void octeon_mdiobus_force_mod_depencency(void);
+void bgx_lmac_rx_tx_enable(int node, int bgx_idx, int lmacid, bool enable);
void bgx_add_dmac_addr(u64 dmac, int node, int bgx_idx, int lmac);
unsigned bgx_get_map(int node);
int bgx_get_lmac_count(int node, int bgx);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
index c308429..11dd91e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
@@ -295,6 +295,10 @@ struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
INIT_LIST_HEAD(&ctbl->hash_list[i]);
cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry));
+ if (!cl_list) {
+ t4_free_mem(ctbl);
+ return NULL;
+ }
ctbl->cl_list = (void *)cl_list;
for (i = 0; i < clipt_size; i++) {
diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c
index ed41559..b553409 100644
--- a/drivers/net/ethernet/dec/tulip/tulip_core.c
+++ b/drivers/net/ethernet/dec/tulip/tulip_core.c
@@ -98,8 +98,7 @@ static int csr0 = 0x01A00000 | 0x4800;
#elif defined(__mips__)
static int csr0 = 0x00200000 | 0x4000;
#else
-#warning Processor architecture undefined!
-static int csr0 = 0x00A00000 | 0x4800;
+static int csr0;
#endif
/* Operational parameters that usually are not changed. */
@@ -1982,6 +1981,12 @@ static int __init tulip_init (void)
pr_info("%s", version);
#endif
+ if (!csr0) {
+ pr_warn("tulip: unknown CPU architecture, using default csr0\n");
+ /* default to 8 longword cache line alignment */
+ csr0 = 0x00A00000 | 0x4800;
+ }
+
/* copy module parms into globals */
tulip_rx_copybreak = rx_copybreak;
tulip_max_interrupt_work = max_interrupt_work;
diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
index 9beb3d3..3c0e4d5 100644
--- a/drivers/net/ethernet/dec/tulip/winbond-840.c
+++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -907,7 +907,7 @@ static void init_registers(struct net_device *dev)
#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM)
i |= 0x4800;
#else
-#warning Processor architecture undefined
+ dev_warn(&dev->dev, "unknown CPU architecture, using default csr0 setting\n");
i |= 0x4800;
#endif
iowrite32(i, ioaddr + PCIBusCfg);
diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig
index f6e858d..ebdc832 100644
--- a/drivers/net/ethernet/dlink/Kconfig
+++ b/drivers/net/ethernet/dlink/Kconfig
@@ -17,15 +17,16 @@ config NET_VENDOR_DLINK
if NET_VENDOR_DLINK
config DL2K
- tristate "DL2000/TC902x-based Gigabit Ethernet support"
+ tristate "DL2000/TC902x/IP1000A-based Gigabit Ethernet support"
depends on PCI
select CRC32
---help---
- This driver supports DL2000/TC902x-based Gigabit ethernet cards,
+ This driver supports DL2000/TC902x/IP1000A-based Gigabit ethernet cards,
which includes
D-Link DGE-550T Gigabit Ethernet Adapter.
D-Link DL2000-based Gigabit Ethernet Adapter.
Sundance/Tamarack TC902x Gigabit Ethernet Adapter.
+ ICPlus IP1000A-based cards
To compile this driver as a module, choose M here: the
module will be called dl2k.
diff --git a/drivers/net/ethernet/dlink/dl2k.c b/drivers/net/ethernet/dlink/dl2k.c
index cf0a5fc..ccca479 100644
--- a/drivers/net/ethernet/dlink/dl2k.c
+++ b/drivers/net/ethernet/dlink/dl2k.c
@@ -253,6 +253,19 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_out_unmap_rx;
+ if (np->chip_id == CHIP_IP1000A &&
+ (np->pdev->revision == 0x40 || np->pdev->revision == 0x41)) {
+ /* PHY magic taken from ipg driver, undocumented registers */
+ mii_write(dev, np->phy_addr, 31, 0x0001);
+ mii_write(dev, np->phy_addr, 27, 0x01e0);
+ mii_write(dev, np->phy_addr, 31, 0x0002);
+ mii_write(dev, np->phy_addr, 27, 0xeb8e);
+ mii_write(dev, np->phy_addr, 31, 0x0000);
+ mii_write(dev, np->phy_addr, 30, 0x005e);
+ /* advertise 1000BASE-T half & full duplex, prefer MASTER */
+ mii_write(dev, np->phy_addr, MII_CTRL1000, 0x0700);
+ }
+
/* Fiber device? */
np->phy_media = (dr16(ASICCtrl) & PhyMedia) ? 1 : 0;
np->link_status = 0;
@@ -361,6 +374,11 @@ parse_eeprom (struct net_device *dev)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = psrom->mac_addr[i];
+ if (np->chip_id == CHIP_IP1000A) {
+ np->led_mode = psrom->led_mode;
+ return 0;
+ }
+
if (np->pdev->vendor != PCI_VENDOR_ID_DLINK) {
return 0;
}
@@ -406,6 +424,28 @@ parse_eeprom (struct net_device *dev)
return 0;
}
+static void rio_set_led_mode(struct net_device *dev)
+{
+ struct netdev_private *np = netdev_priv(dev);
+ void __iomem *ioaddr = np->ioaddr;
+ u32 mode;
+
+ if (np->chip_id != CHIP_IP1000A)
+ return;
+
+ mode = dr32(ASICCtrl);
+ mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
+
+ if (np->led_mode & 0x01)
+ mode |= IPG_AC_LED_MODE;
+ if (np->led_mode & 0x02)
+ mode |= IPG_AC_LED_MODE_BIT_1;
+ if (np->led_mode & 0x08)
+ mode |= IPG_AC_LED_SPEED;
+
+ dw32(ASICCtrl, mode);
+}
+
static int
rio_open (struct net_device *dev)
{
@@ -424,6 +464,8 @@ rio_open (struct net_device *dev)
GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset);
mdelay(10);
+ rio_set_led_mode(dev);
+
/* DebugCtrl bit 4, 5, 9 must set */
dw32(DebugCtrl, dr32(DebugCtrl) | 0x0230);
@@ -433,9 +475,13 @@ rio_open (struct net_device *dev)
alloc_list (dev);
- /* Get station address */
- for (i = 0; i < 6; i++)
- dw8(StationAddr0 + i, dev->dev_addr[i]);
+ /* Set station address */
+ /* 16 or 32-bit access is required by TC9020 datasheet but 8-bit works
+ * too. However, it doesn't work on IP1000A so we use 16-bit access.
+ */
+ for (i = 0; i < 3; i++)
+ dw16(StationAddr0 + 2 * i,
+ cpu_to_le16(((u16 *)dev->dev_addr)[i]));
set_multicast (dev);
if (np->coalesce) {
@@ -780,6 +826,7 @@ tx_error (struct net_device *dev, int tx_status)
break;
mdelay (1);
}
+ rio_set_led_mode(dev);
rio_free_tx (dev, 1);
/* Reset TFDListPtr */
dw32(TFDListPtr0, np->tx_ring_dma +
@@ -799,6 +846,7 @@ tx_error (struct net_device *dev, int tx_status)
break;
mdelay (1);
}
+ rio_set_led_mode(dev);
/* Let TxStartThresh stay default value */
}
/* Maximum Collisions */
@@ -965,6 +1013,7 @@ rio_error (struct net_device *dev, int int_status)
dev->name, int_status);
dw16(ASICCtrl + 2, GlobalReset | HostReset);
mdelay (500);
+ rio_set_led_mode(dev);
}
}
diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h
index 23c07b0..8f4f612 100644
--- a/drivers/net/ethernet/dlink/dl2k.h
+++ b/drivers/net/ethernet/dlink/dl2k.h
@@ -211,6 +211,10 @@ enum ASICCtrl_HiWord_bits {
ResetBusy = 0x0400,
};
+#define IPG_AC_LED_MODE BIT(14)
+#define IPG_AC_LED_SPEED BIT(27)
+#define IPG_AC_LED_MODE_BIT_1 BIT(29)
+
/* Transmit Frame Control bits */
enum TFC_bits {
DwordAlign = 0x00000000,
@@ -332,7 +336,10 @@ typedef struct t_SROM {
u16 asic_ctrl; /* 0x02 */
u16 sub_vendor_id; /* 0x04 */
u16 sub_system_id; /* 0x06 */
- u16 reserved1[12]; /* 0x08-0x1f */
+ u16 pci_base_1; /* 0x08 (IP1000A only) */
+ u16 pci_base_2; /* 0x0a (IP1000A only) */
+ u16 led_mode; /* 0x0c (IP1000A only) */
+ u16 reserved1[9]; /* 0x0e-0x1f */
u8 mac_addr[6]; /* 0x20-0x25 */
u8 reserved2[10]; /* 0x26-0x2f */
u8 sib[204]; /* 0x30-0xfb */
@@ -397,6 +404,7 @@ struct netdev_private {
u16 advertising; /* NWay media advertisement */
u16 negotiate; /* Negotiated media */
int phy_addr; /* PHY addresses. */
+ u16 led_mode; /* LED mode read from EEPROM (IP1000A only) */
};
/* The station address location in the EEPROM. */
@@ -407,10 +415,15 @@ struct netdev_private {
class_mask of the class are honored during the comparison.
driver_data Data private to the driver.
*/
+#define CHIP_IP1000A 1
static const struct pci_device_id rio_pci_tbl[] = {
{0x1186, 0x4000, PCI_ANY_ID, PCI_ANY_ID, },
{0x13f0, 0x1021, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VDEVICE(SUNDANCE, 0x1023), CHIP_IP1000A },
+ { PCI_VDEVICE(SUNDANCE, 0x2021), CHIP_IP1000A },
+ { PCI_VDEVICE(DLINK, 0x9021), CHIP_IP1000A },
+ { PCI_VDEVICE(DLINK, 0x4020), CHIP_IP1000A },
{ }
};
MODULE_DEVICE_TABLE (pci, rio_pci_tbl);
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index d463563..6ee78c2 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -848,8 +848,6 @@ void be_roce_dev_remove(struct be_adapter *);
/*
* internal function to open-close roce device during ifup-ifdown.
*/
-void be_roce_dev_open(struct be_adapter *);
-void be_roce_dev_close(struct be_adapter *);
void be_roce_dev_shutdown(struct be_adapter *);
#endif /* BE_H */
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index f4cb8e4..734f655 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -1062,9 +1062,7 @@ static int be_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd,
static int be_set_rss_hash_opts(struct be_adapter *adapter,
struct ethtool_rxnfc *cmd)
{
- struct be_rx_obj *rxo;
- int status = 0, i, j;
- u8 rsstable[128];
+ int status;
u32 rss_flags = adapter->rss_info.rss_flags;
if (cmd->data != L3_RSS_FLAGS &&
@@ -1113,20 +1111,11 @@ static int be_set_rss_hash_opts(struct be_adapter *adapter,
}
if (rss_flags == adapter->rss_info.rss_flags)
- return status;
-
- if (be_multi_rxq(adapter)) {
- for (j = 0; j < 128; j += adapter->num_rss_qs) {
- for_all_rss_queues(adapter, rxo, i) {
- if ((j + i) >= 128)
- break;
- rsstable[j + i] = rxo->rss_id;
- }
- }
- }
+ return 0;
status = be_cmd_rss_config(adapter, adapter->rss_info.rsstable,
- rss_flags, 128, adapter->rss_info.rss_hkey);
+ rss_flags, RSS_INDIR_TABLE_LEN,
+ adapter->rss_info.rss_hkey);
if (!status)
adapter->rss_info.rss_flags = rss_flags;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index eb48a97..8a1d9ff 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -3299,8 +3299,10 @@ static int be_msix_register(struct be_adapter *adapter)
return 0;
err_msix:
- for (i--, eqo = &adapter->eq_obj[i]; i >= 0; i--, eqo--)
+ for (i--; i >= 0; i--) {
+ eqo = &adapter->eq_obj[i];
free_irq(be_msix_vec_get(adapter, eqo), eqo);
+ }
dev_warn(&adapter->pdev->dev, "MSIX Request IRQ failed - err %d\n",
status);
be_msix_disable(adapter);
@@ -3432,8 +3434,6 @@ static int be_close(struct net_device *netdev)
be_disable_if_filters(adapter);
- be_roce_dev_close(adapter);
-
if (adapter->flags & BE_FLAGS_NAPI_ENABLED) {
for_all_evt_queues(adapter, eqo, i) {
napi_disable(&eqo->napi);
@@ -3518,7 +3518,7 @@ static int be_rx_qs_create(struct be_adapter *adapter)
netdev_rss_key_fill(rss_key, RSS_HASH_KEY_LEN);
rc = be_cmd_rss_config(adapter, rss->rsstable, rss->rss_flags,
- 128, rss_key);
+ RSS_INDIR_TABLE_LEN, rss_key);
if (rc) {
rss->rss_flags = RSS_ENABLE_NONE;
return rc;
@@ -3601,8 +3601,6 @@ static int be_open(struct net_device *netdev)
be_link_status_update(adapter, link_status);
netif_tx_start_all_queues(netdev);
- be_roce_dev_open(adapter);
-
#ifdef CONFIG_BE2NET_VXLAN
if (skyhawk_chip(adapter))
vxlan_get_rx_port(netdev);
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c
index 6036820..4089156 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.c
+++ b/drivers/net/ethernet/emulex/benet/be_roce.c
@@ -116,40 +116,6 @@ void be_roce_dev_remove(struct be_adapter *adapter)
}
}
-static void _be_roce_dev_open(struct be_adapter *adapter)
-{
- if (ocrdma_drv && adapter->ocrdma_dev &&
- ocrdma_drv->state_change_handler)
- ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
- BE_DEV_UP);
-}
-
-void be_roce_dev_open(struct be_adapter *adapter)
-{
- if (be_roce_supported(adapter)) {
- mutex_lock(&be_adapter_list_lock);
- _be_roce_dev_open(adapter);
- mutex_unlock(&be_adapter_list_lock);
- }
-}
-
-static void _be_roce_dev_close(struct be_adapter *adapter)
-{
- if (ocrdma_drv && adapter->ocrdma_dev &&
- ocrdma_drv->state_change_handler)
- ocrdma_drv->state_change_handler(adapter->ocrdma_dev,
- BE_DEV_DOWN);
-}
-
-void be_roce_dev_close(struct be_adapter *adapter)
-{
- if (be_roce_supported(adapter)) {
- mutex_lock(&be_adapter_list_lock);
- _be_roce_dev_close(adapter);
- mutex_unlock(&be_adapter_list_lock);
- }
-}
-
void be_roce_dev_shutdown(struct be_adapter *adapter)
{
if (be_roce_supported(adapter)) {
@@ -177,8 +143,6 @@ int be_roce_register_driver(struct ocrdma_driver *drv)
_be_roce_dev_add(dev);
netdev = dev->netdev;
- if (netif_running(netdev) && netif_oper_up(netdev))
- _be_roce_dev_open(dev);
}
mutex_unlock(&be_adapter_list_lock);
return 0;
diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h
index cde6ef9..fde6097 100644
--- a/drivers/net/ethernet/emulex/benet/be_roce.h
+++ b/drivers/net/ethernet/emulex/benet/be_roce.h
@@ -60,9 +60,7 @@ struct ocrdma_driver {
void (*state_change_handler) (struct ocrdma_dev *, u32 new_state);
};
-enum {
- BE_DEV_UP = 0,
- BE_DEV_DOWN = 1,
+enum be_roce_event {
BE_DEV_SHUTDOWN = 2
};
diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c
index 63c2bcf..b102668 100644
--- a/drivers/net/ethernet/ezchip/nps_enet.c
+++ b/drivers/net/ethernet/ezchip/nps_enet.c
@@ -48,21 +48,15 @@ static void nps_enet_read_rx_fifo(struct net_device *ndev,
*reg = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
else { /* !dst_is_aligned */
for (i = 0; i < len; i++, reg++) {
- u32 buf =
- nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-
- /* to accommodate word-unaligned address of "reg"
- * we have to do memcpy_toio() instead of simple "=".
- */
- memcpy_toio((void __iomem *)reg, &buf, sizeof(buf));
+ u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
+ put_unaligned(buf, reg);
}
}
/* copy last bytes (if any) */
if (last) {
u32 buf = nps_enet_reg_get(priv, NPS_ENET_REG_RX_BUF);
-
- memcpy_toio((void __iomem *)reg, &buf, last);
+ memcpy((u8*)reg, &buf, last);
}
}
@@ -367,7 +361,7 @@ static void nps_enet_send_frame(struct net_device *ndev,
struct nps_enet_tx_ctl tx_ctrl;
short length = skb->len;
u32 i, len = DIV_ROUND_UP(length, sizeof(u32));
- u32 *src = (u32 *)virt_to_phys(skb->data);
+ u32 *src = (void *)skb->data;
bool src_is_aligned = IS_ALIGNED((unsigned long)src, sizeof(u32));
tx_ctrl.value = 0;
@@ -375,17 +369,11 @@ static void nps_enet_send_frame(struct net_device *ndev,
if (src_is_aligned)
for (i = 0; i < len; i++, src++)
nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, *src);
- else { /* !src_is_aligned */
- for (i = 0; i < len; i++, src++) {
- u32 buf;
-
- /* to accommodate word-unaligned address of "src"
- * we have to do memcpy_fromio() instead of simple "="
- */
- memcpy_fromio(&buf, (void __iomem *)src, sizeof(buf));
- nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF, buf);
- }
- }
+ else /* !src_is_aligned */
+ for (i = 0; i < len; i++, src++)
+ nps_enet_reg_set(priv, NPS_ENET_REG_TX_BUF,
+ get_unaligned(src));
+
/* Write the length of the Frame */
tx_ctrl.nt = length;
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index ff76d4e..bee32a9 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -7,7 +7,8 @@ config NET_VENDOR_FREESCALE
default y
depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \
M523x || M527x || M5272 || M528x || M520x || M532x || \
- ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM)
+ ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \
+ ARCH_LAYERSCAPE
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
index 08f5b91..52e0091 100644
--- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
+++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c
@@ -552,7 +552,7 @@ static void tx_restart(struct net_device *dev)
cbd_t __iomem *prev_bd;
cbd_t __iomem *last_tx_bd;
- last_tx_bd = fep->tx_bd_base + (fpi->tx_ring * sizeof(cbd_t));
+ last_tx_bd = fep->tx_bd_base + ((fpi->tx_ring - 1) * sizeof(cbd_t));
/* get the current bd held in TBPTR and scan back from this point */
recheck_bd = curr_tbptr = (cbd_t __iomem *)
diff --git a/drivers/net/ethernet/freescale/fsl_pq_mdio.c b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
index 55c3623..40071da 100644
--- a/drivers/net/ethernet/freescale/fsl_pq_mdio.c
+++ b/drivers/net/ethernet/freescale/fsl_pq_mdio.c
@@ -464,7 +464,7 @@ static int fsl_pq_mdio_probe(struct platform_device *pdev)
* address). Print error message but continue anyway.
*/
if ((void *)tbipa > priv->map + resource_size(&res) - 4)
- dev_err(&pdev->dev, "invalid register map (should be at least 0x%04x to contain TBI address)\n",
+ dev_err(&pdev->dev, "invalid register map (should be at least 0x%04zx to contain TBI address)\n",
((void *)tbipa - priv->map) + 4);
iowrite32be(be32_to_cpup(prop), tbipa);
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3e6b9b4..3e233d9 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -647,9 +647,9 @@ static int gfar_parse_group(struct device_node *np,
if (model && strcasecmp(model, "FEC")) {
gfar_irq(grp, RX)->irq = irq_of_parse_and_map(np, 1);
gfar_irq(grp, ER)->irq = irq_of_parse_and_map(np, 2);
- if (gfar_irq(grp, TX)->irq == NO_IRQ ||
- gfar_irq(grp, RX)->irq == NO_IRQ ||
- gfar_irq(grp, ER)->irq == NO_IRQ)
+ if (!gfar_irq(grp, TX)->irq ||
+ !gfar_irq(grp, RX)->irq ||
+ !gfar_irq(grp, ER)->irq)
return -EINVAL;
}
@@ -894,7 +894,8 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
FSL_GIANFAR_DEV_HAS_VLAN |
FSL_GIANFAR_DEV_HAS_MAGIC_PACKET |
FSL_GIANFAR_DEV_HAS_EXTENDED_HASH |
- FSL_GIANFAR_DEV_HAS_TIMER;
+ FSL_GIANFAR_DEV_HAS_TIMER |
+ FSL_GIANFAR_DEV_HAS_RX_FILER;
err = of_property_read_string(np, "phy-connection-type", &ctype);
@@ -1396,8 +1397,9 @@ static int gfar_probe(struct platform_device *ofdev)
priv->rx_queue[i]->rxic = DEFAULT_RXIC;
}
- /* always enable rx filer */
- priv->rx_filer_enable = 1;
+ /* Always enable rx filer if available */
+ priv->rx_filer_enable =
+ (priv->device_flags & FSL_GIANFAR_DEV_HAS_RX_FILER) ? 1 : 0;
/* Enable most messages by default */
priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
/* use pritority h/w tx queue scheduling for single queue devices */
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index f266b20..cb77667 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -923,6 +923,7 @@ struct gfar {
#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400
#define FSL_GIANFAR_DEV_HAS_TIMER 0x00000800
#define FSL_GIANFAR_DEV_HAS_WAKE_ON_FILER 0x00001000
+#define FSL_GIANFAR_DEV_HAS_RX_FILER 0x00002000
#if (MAXGROUPS == 2)
#define DEFAULT_MAPPING 0xAA
diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c
index 664d0c2..b40fba9 100644
--- a/drivers/net/ethernet/freescale/gianfar_ptp.c
+++ b/drivers/net/ethernet/freescale/gianfar_ptp.c
@@ -467,7 +467,7 @@ static int gianfar_ptp_probe(struct platform_device *dev)
etsects->irq = platform_get_irq(dev, 0);
- if (etsects->irq == NO_IRQ) {
+ if (etsects->irq < 0) {
pr_err("irq not in device tree\n");
goto no_node;
}
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index f250dec..74beb18 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -5,7 +5,8 @@
config NET_VENDOR_HISILICON
bool "Hisilicon devices"
default y
- depends on OF && (ARM || ARM64 || COMPILE_TEST)
+ depends on OF && HAS_DMA
+ depends on ARM || ARM64 || COMPILE_TEST
---help---
If you have a network (Ethernet) card belonging to this class, say Y.
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
index 2a98eba..b674414 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_main.c
@@ -1259,12 +1259,8 @@ int hns_dsaf_set_mac_uc_entry(
if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
MAC_IS_BROADCAST(mac_entry->addr) ||
MAC_IS_MULTICAST(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "set_uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n",
- dsaf_dev->ae_dev.name, mac_entry->addr[0],
- mac_entry->addr[1], mac_entry->addr[2],
- mac_entry->addr[3], mac_entry->addr[4],
- mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "set_uc %s Mac %pM err!\n",
+ dsaf_dev->ae_dev.name, mac_entry->addr);
return -EINVAL;
}
@@ -1331,12 +1327,8 @@ int hns_dsaf_set_mac_mc_entry(
/* mac addr check */
if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "set uc %s Mac %02x:%02x:%02x:%02x:%02x:%02x err!\n",
- dsaf_dev->ae_dev.name, mac_entry->addr[0],
- mac_entry->addr[1], mac_entry->addr[2],
- mac_entry->addr[3],
- mac_entry->addr[4], mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "set uc %s Mac %pM err!\n",
+ dsaf_dev->ae_dev.name, mac_entry->addr);
return -EINVAL;
}
@@ -1410,11 +1402,8 @@ int hns_dsaf_add_mac_mc_port(struct dsaf_device *dsaf_dev,
/*chechk mac addr */
if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "set_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
- mac_entry->addr[0], mac_entry->addr[1],
- mac_entry->addr[2], mac_entry->addr[3],
- mac_entry->addr[4], mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "set_entry failed,addr %pM!\n",
+ mac_entry->addr);
return -EINVAL;
}
@@ -1497,9 +1486,8 @@ int hns_dsaf_del_mac_entry(struct dsaf_device *dsaf_dev, u16 vlan_id,
/*check mac addr */
if (MAC_IS_ALL_ZEROS(addr) || MAC_IS_BROADCAST(addr)) {
- dev_err(dsaf_dev->dev,
- "del_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+ dev_err(dsaf_dev->dev, "del_entry failed,addr %pM!\n",
+ addr);
return -EINVAL;
}
@@ -1563,11 +1551,8 @@ int hns_dsaf_del_mac_mc_port(struct dsaf_device *dsaf_dev,
/*check mac addr */
if (MAC_IS_ALL_ZEROS(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "del_port failed, addr %02x:%02x:%02x:%02x:%02x:%02x!\n",
- mac_entry->addr[0], mac_entry->addr[1],
- mac_entry->addr[2], mac_entry->addr[3],
- mac_entry->addr[4], mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "del_port failed, addr %pM!\n",
+ mac_entry->addr);
return -EINVAL;
}
@@ -1644,11 +1629,8 @@ int hns_dsaf_get_mac_uc_entry(struct dsaf_device *dsaf_dev,
/* check macaddr */
if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
MAC_IS_BROADCAST(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- mac_entry->addr[0], mac_entry->addr[1],
- mac_entry->addr[2], mac_entry->addr[3],
- mac_entry->addr[4], mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n",
+ mac_entry->addr);
return -EINVAL;
}
@@ -1695,11 +1677,8 @@ int hns_dsaf_get_mac_mc_entry(struct dsaf_device *dsaf_dev,
/*check mac addr */
if (MAC_IS_ALL_ZEROS(mac_entry->addr) ||
MAC_IS_BROADCAST(mac_entry->addr)) {
- dev_err(dsaf_dev->dev,
- "get_entry failed,addr %02x:%02x:%02x:%02x:%02x:%02x\n",
- mac_entry->addr[0], mac_entry->addr[1],
- mac_entry->addr[2], mac_entry->addr[3],
- mac_entry->addr[4], mac_entry->addr[5]);
+ dev_err(dsaf_dev->dev, "get_entry failed,addr %pM\n",
+ mac_entry->addr);
return -EINVAL;
}
diff --git a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
index b475e1b..bdbd804 100644
--- a/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
+++ b/drivers/net/ethernet/hisilicon/hns/hns_dsaf_reg.h
@@ -898,7 +898,7 @@
#define XGMAC_PAUSE_CTL_RSP_MODE_B 2
#define XGMAC_PAUSE_CTL_TX_XOFF_B 3
-static inline void dsaf_write_reg(void *base, u32 reg, u32 value)
+static inline void dsaf_write_reg(void __iomem *base, u32 reg, u32 value)
{
u8 __iomem *reg_addr = ACCESS_ONCE(base);
@@ -908,7 +908,7 @@ static inline void dsaf_write_reg(void *base, u32 reg, u32 value)
#define dsaf_write_dev(a, reg, value) \
dsaf_write_reg((a)->io_base, (reg), (value))
-static inline u32 dsaf_read_reg(u8 *base, u32 reg)
+static inline u32 dsaf_read_reg(u8 __iomem *base, u32 reg)
{
u8 __iomem *reg_addr = ACCESS_ONCE(base);
@@ -927,8 +927,8 @@ static inline u32 dsaf_read_reg(u8 *base, u32 reg)
#define dsaf_set_bit(origin, shift, val) \
dsaf_set_field((origin), (1ull << (shift)), (shift), (val))
-static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift,
- u32 val)
+static inline void dsaf_set_reg_field(void __iomem *base, u32 reg, u32 mask,
+ u32 shift, u32 val)
{
u32 origin = dsaf_read_reg(base, reg);
@@ -947,7 +947,8 @@ static inline void dsaf_set_reg_field(void *base, u32 reg, u32 mask, u32 shift,
#define dsaf_get_bit(origin, shift) \
dsaf_get_field((origin), (1ull << (shift)), (shift))
-static inline u32 dsaf_get_reg_field(void *base, u32 reg, u32 mask, u32 shift)
+static inline u32 dsaf_get_reg_field(void __iomem *base, u32 reg, u32 mask,
+ u32 shift)
{
u32 origin;
diff --git a/drivers/net/ethernet/icplus/Kconfig b/drivers/net/ethernet/icplus/Kconfig
deleted file mode 100644
index 14a66e9..0000000
--- a/drivers/net/ethernet/icplus/Kconfig
+++ /dev/null
@@ -1,13 +0,0 @@
-#
-# IC Plus device configuration
-#
-
-config IP1000
- tristate "IP1000 Gigabit Ethernet support"
- depends on PCI
- select MII
- ---help---
- This driver supports IP1000 gigabit Ethernet cards.
-
- To compile this driver as a module, choose M here: the module
- will be called ipg. This is recommended.
diff --git a/drivers/net/ethernet/icplus/Makefile b/drivers/net/ethernet/icplus/Makefile
deleted file mode 100644
index 5bc87c1..0000000
--- a/drivers/net/ethernet/icplus/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-#
-# Makefile for the IC Plus device drivers
-#
-
-obj-$(CONFIG_IP1000) += ipg.o
diff --git a/drivers/net/ethernet/icplus/ipg.c b/drivers/net/ethernet/icplus/ipg.c
deleted file mode 100644
index c3b6af8..0000000
--- a/drivers/net/ethernet/icplus/ipg.c
+++ /dev/null
@@ -1,2300 +0,0 @@
-/*
- * ipg.c: Device Driver for the IP1000 Gigabit Ethernet Adapter
- *
- * Copyright (C) 2003, 2007 IC Plus Corp
- *
- * Original Author:
- *
- * Craig Rich
- * Sundance Technology, Inc.
- * www.sundanceti.com
- * craig_rich@sundanceti.com
- *
- * Current Maintainer:
- *
- * Sorbica Shieh.
- * http://www.icplus.com.tw
- * sorbica@icplus.com.tw
- *
- * Jesse Huang
- * http://www.icplus.com.tw
- * jesse@icplus.com.tw
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/crc32.h>
-#include <linux/ethtool.h>
-#include <linux/interrupt.h>
-#include <linux/gfp.h>
-#include <linux/mii.h>
-#include <linux/mutex.h>
-
-#include <asm/div64.h>
-
-#define IPG_RX_RING_BYTES (sizeof(struct ipg_rx) * IPG_RFDLIST_LENGTH)
-#define IPG_TX_RING_BYTES (sizeof(struct ipg_tx) * IPG_TFDLIST_LENGTH)
-#define IPG_RESET_MASK \
- (IPG_AC_GLOBAL_RESET | IPG_AC_RX_RESET | IPG_AC_TX_RESET | \
- IPG_AC_DMA | IPG_AC_FIFO | IPG_AC_NETWORK | IPG_AC_HOST | \
- IPG_AC_AUTO_INIT)
-
-#define ipg_w32(val32, reg) iowrite32((val32), ioaddr + (reg))
-#define ipg_w16(val16, reg) iowrite16((val16), ioaddr + (reg))
-#define ipg_w8(val8, reg) iowrite8((val8), ioaddr + (reg))
-
-#define ipg_r32(reg) ioread32(ioaddr + (reg))
-#define ipg_r16(reg) ioread16(ioaddr + (reg))
-#define ipg_r8(reg) ioread8(ioaddr + (reg))
-
-enum {
- netdev_io_size = 128
-};
-
-#include "ipg.h"
-#define DRV_NAME "ipg"
-
-MODULE_AUTHOR("IC Plus Corp. 2003");
-MODULE_DESCRIPTION("IC Plus IP1000 Gigabit Ethernet Adapter Linux Driver");
-MODULE_LICENSE("GPL");
-
-/*
- * Defaults
- */
-#define IPG_MAX_RXFRAME_SIZE 0x0600
-#define IPG_RXFRAG_SIZE 0x0600
-#define IPG_RXSUPPORT_SIZE 0x0600
-#define IPG_IS_JUMBO false
-
-/*
- * Variable record -- index by leading revision/length
- * Revision/Length(=N*4), Address1, Data1, Address2, Data2,...,AddressN,DataN
- */
-static const unsigned short DefaultPhyParam[] = {
- /* 11/12/03 IP1000A v1-3 rev=0x40 */
- /*--------------------------------------------------------------------------
- (0x4000|(15*4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 22, 0x85bd, 24, 0xfff2,
- 27, 0x0c10, 28, 0x0c10, 29, 0x2c10, 31, 0x0003, 23, 0x92f6,
- 31, 0x0000, 23, 0x003d, 30, 0x00de, 20, 0x20e7, 9, 0x0700,
- --------------------------------------------------------------------------*/
- /* 12/17/03 IP1000A v1-4 rev=0x40 */
- (0x4000 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
- 0x0000,
- 30, 0x005e, 9, 0x0700,
- /* 01/09/04 IP1000A v1-5 rev=0x41 */
- (0x4100 | (07 * 4)), 31, 0x0001, 27, 0x01e0, 31, 0x0002, 27, 0xeb8e, 31,
- 0x0000,
- 30, 0x005e, 9, 0x0700,
- 0x0000
-};
-
-static const char * const ipg_brand_name[] = {
- "IC PLUS IP1000 1000/100/10 based NIC",
- "Sundance Technology ST2021 based NIC",
- "Tamarack Microelectronics TC9020/9021 based NIC",
- "D-Link NIC IP1000A"
-};
-
-static const struct pci_device_id ipg_pci_tbl[] = {
- { PCI_VDEVICE(SUNDANCE, 0x1023), 0 },
- { PCI_VDEVICE(SUNDANCE, 0x2021), 1 },
- { PCI_VDEVICE(DLINK, 0x9021), 2 },
- { PCI_VDEVICE(DLINK, 0x4020), 3 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, ipg_pci_tbl);
-
-static inline void __iomem *ipg_ioaddr(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- return sp->ioaddr;
-}
-
-#ifdef IPG_DEBUG
-static void ipg_dump_rfdlist(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
- u32 offset;
-
- IPG_DEBUG_MSG("_dump_rfdlist\n");
-
- netdev_info(dev, "rx_current = %02x\n", sp->rx_current);
- netdev_info(dev, "rx_dirty = %02x\n", sp->rx_dirty);
- netdev_info(dev, "RFDList start address = %016lx\n",
- (unsigned long)sp->rxd_map);
- netdev_info(dev, "RFDListPtr register = %08x%08x\n",
- ipg_r32(IPG_RFDLISTPTR1), ipg_r32(IPG_RFDLISTPTR0));
-
- for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
- offset = (u32) &sp->rxd[i].next_desc - (u32) sp->rxd;
- netdev_info(dev, "%02x %04x RFDNextPtr = %016lx\n",
- i, offset, (unsigned long)sp->rxd[i].next_desc);
- offset = (u32) &sp->rxd[i].rfs - (u32) sp->rxd;
- netdev_info(dev, "%02x %04x RFS = %016lx\n",
- i, offset, (unsigned long)sp->rxd[i].rfs);
- offset = (u32) &sp->rxd[i].frag_info - (u32) sp->rxd;
- netdev_info(dev, "%02x %04x frag_info = %016lx\n",
- i, offset, (unsigned long)sp->rxd[i].frag_info);
- }
-}
-
-static void ipg_dump_tfdlist(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
- u32 offset;
-
- IPG_DEBUG_MSG("_dump_tfdlist\n");
-
- netdev_info(dev, "tx_current = %02x\n", sp->tx_current);
- netdev_info(dev, "tx_dirty = %02x\n", sp->tx_dirty);
- netdev_info(dev, "TFDList start address = %016lx\n",
- (unsigned long) sp->txd_map);
- netdev_info(dev, "TFDListPtr register = %08x%08x\n",
- ipg_r32(IPG_TFDLISTPTR1), ipg_r32(IPG_TFDLISTPTR0));
-
- for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
- offset = (u32) &sp->txd[i].next_desc - (u32) sp->txd;
- netdev_info(dev, "%02x %04x TFDNextPtr = %016lx\n",
- i, offset, (unsigned long)sp->txd[i].next_desc);
-
- offset = (u32) &sp->txd[i].tfc - (u32) sp->txd;
- netdev_info(dev, "%02x %04x TFC = %016lx\n",
- i, offset, (unsigned long) sp->txd[i].tfc);
- offset = (u32) &sp->txd[i].frag_info - (u32) sp->txd;
- netdev_info(dev, "%02x %04x frag_info = %016lx\n",
- i, offset, (unsigned long) sp->txd[i].frag_info);
- }
-}
-#endif
-
-static void ipg_write_phy_ctl(void __iomem *ioaddr, u8 data)
-{
- ipg_w8(IPG_PC_RSVD_MASK & data, PHY_CTRL);
- ndelay(IPG_PC_PHYCTRLWAIT_NS);
-}
-
-static void ipg_drive_phy_ctl_low_high(void __iomem *ioaddr, u8 data)
-{
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | data);
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | data);
-}
-
-static void send_three_state(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
- phyctrlpolarity |= (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR;
-
- ipg_drive_phy_ctl_low_high(ioaddr, phyctrlpolarity);
-}
-
-static void send_end(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
- ipg_w8((IPG_PC_MGMTCLK_LO | (IPG_PC_MGMTDATA & 0) | IPG_PC_MGMTDIR |
- phyctrlpolarity) & IPG_PC_RSVD_MASK, PHY_CTRL);
-}
-
-static u16 read_phy_bit(void __iomem *ioaddr, u8 phyctrlpolarity)
-{
- u16 bit_data;
-
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | phyctrlpolarity);
-
- bit_data = ((ipg_r8(PHY_CTRL) & IPG_PC_MGMTDATA) >> 1) & 1;
-
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | phyctrlpolarity);
-
- return bit_data;
-}
-
-/*
- * Read a register from the Physical Layer device located
- * on the IPG NIC, using the IPG PHYCTRL register.
- */
-static int mdio_read(struct net_device *dev, int phy_id, int phy_reg)
-{
- void __iomem *ioaddr = ipg_ioaddr(dev);
- /*
- * The GMII mangement frame structure for a read is as follows:
- *
- * |Preamble|st|op|phyad|regad|ta| data |idle|
- * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
- *
- * <32 1s> = 32 consecutive logic 1 values
- * A = bit of Physical Layer device address (MSB first)
- * R = bit of register address (MSB first)
- * z = High impedance state
- * D = bit of read data (MSB first)
- *
- * Transmission order is 'Preamble' field first, bits transmitted
- * left to right (first to last).
- */
- struct {
- u32 field;
- unsigned int len;
- } p[] = {
- { GMII_PREAMBLE, 32 }, /* Preamble */
- { GMII_ST, 2 }, /* ST */
- { GMII_READ, 2 }, /* OP */
- { phy_id, 5 }, /* PHYAD */
- { phy_reg, 5 }, /* REGAD */
- { 0x0000, 2 }, /* TA */
- { 0x0000, 16 }, /* DATA */
- { 0x0000, 1 } /* IDLE */
- };
- unsigned int i, j;
- u8 polarity, data;
-
- polarity = ipg_r8(PHY_CTRL);
- polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
-
- /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
- for (j = 0; j < 5; j++) {
- for (i = 0; i < p[j].len; i++) {
- /* For each variable length field, the MSB must be
- * transmitted first. Rotate through the field bits,
- * starting with the MSB, and move each bit into the
- * the 1st (2^1) bit position (this is the bit position
- * corresponding to the MgmtData bit of the PhyCtrl
- * register for the IPG).
- *
- * Example: ST = 01;
- *
- * First write a '0' to bit 1 of the PhyCtrl
- * register, then write a '1' to bit 1 of the
- * PhyCtrl register.
- *
- * To do this, right shift the MSB of ST by the value:
- * [field length - 1 - #ST bits already written]
- * then left shift this result by 1.
- */
- data = (p[j].field >> (p[j].len - 1 - i)) << 1;
- data &= IPG_PC_MGMTDATA;
- data |= polarity | IPG_PC_MGMTDIR;
-
- ipg_drive_phy_ctl_low_high(ioaddr, data);
- }
- }
-
- send_three_state(ioaddr, polarity);
-
- read_phy_bit(ioaddr, polarity);
-
- /*
- * For a read cycle, the bits for the next two fields (TA and
- * DATA) are driven by the PHY (the IPG reads these bits).
- */
- for (i = 0; i < p[6].len; i++) {
- p[6].field |=
- (read_phy_bit(ioaddr, polarity) << (p[6].len - 1 - i));
- }
-
- send_three_state(ioaddr, polarity);
- send_three_state(ioaddr, polarity);
- send_three_state(ioaddr, polarity);
- send_end(ioaddr, polarity);
-
- /* Return the value of the DATA field. */
- return p[6].field;
-}
-
-/*
- * Write to a register from the Physical Layer device located
- * on the IPG NIC, using the IPG PHYCTRL register.
- */
-static void mdio_write(struct net_device *dev, int phy_id, int phy_reg, int val)
-{
- void __iomem *ioaddr = ipg_ioaddr(dev);
- /*
- * The GMII mangement frame structure for a read is as follows:
- *
- * |Preamble|st|op|phyad|regad|ta| data |idle|
- * |< 32 1s>|01|10|AAAAA|RRRRR|z0|DDDDDDDDDDDDDDDD|z |
- *
- * <32 1s> = 32 consecutive logic 1 values
- * A = bit of Physical Layer device address (MSB first)
- * R = bit of register address (MSB first)
- * z = High impedance state
- * D = bit of write data (MSB first)
- *
- * Transmission order is 'Preamble' field first, bits transmitted
- * left to right (first to last).
- */
- struct {
- u32 field;
- unsigned int len;
- } p[] = {
- { GMII_PREAMBLE, 32 }, /* Preamble */
- { GMII_ST, 2 }, /* ST */
- { GMII_WRITE, 2 }, /* OP */
- { phy_id, 5 }, /* PHYAD */
- { phy_reg, 5 }, /* REGAD */
- { 0x0002, 2 }, /* TA */
- { val & 0xffff, 16 }, /* DATA */
- { 0x0000, 1 } /* IDLE */
- };
- unsigned int i, j;
- u8 polarity, data;
-
- polarity = ipg_r8(PHY_CTRL);
- polarity &= (IPG_PC_DUPLEX_POLARITY | IPG_PC_LINK_POLARITY);
-
- /* Create the Preamble, ST, OP, PHYAD, and REGAD field. */
- for (j = 0; j < 7; j++) {
- for (i = 0; i < p[j].len; i++) {
- /* For each variable length field, the MSB must be
- * transmitted first. Rotate through the field bits,
- * starting with the MSB, and move each bit into the
- * the 1st (2^1) bit position (this is the bit position
- * corresponding to the MgmtData bit of the PhyCtrl
- * register for the IPG).
- *
- * Example: ST = 01;
- *
- * First write a '0' to bit 1 of the PhyCtrl
- * register, then write a '1' to bit 1 of the
- * PhyCtrl register.
- *
- * To do this, right shift the MSB of ST by the value:
- * [field length - 1 - #ST bits already written]
- * then left shift this result by 1.
- */
- data = (p[j].field >> (p[j].len - 1 - i)) << 1;
- data &= IPG_PC_MGMTDATA;
- data |= polarity | IPG_PC_MGMTDIR;
-
- ipg_drive_phy_ctl_low_high(ioaddr, data);
- }
- }
-
- /* The last cycle is a tri-state, so read from the PHY. */
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_LO | polarity);
- ipg_r8(PHY_CTRL);
- ipg_write_phy_ctl(ioaddr, IPG_PC_MGMTCLK_HI | polarity);
-}
-
-static void ipg_set_led_mode(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- u32 mode;
-
- mode = ipg_r32(ASIC_CTRL);
- mode &= ~(IPG_AC_LED_MODE_BIT_1 | IPG_AC_LED_MODE | IPG_AC_LED_SPEED);
-
- if ((sp->led_mode & 0x03) > 1)
- mode |= IPG_AC_LED_MODE_BIT_1; /* Write Asic Control Bit 29 */
-
- if ((sp->led_mode & 0x01) == 1)
- mode |= IPG_AC_LED_MODE; /* Write Asic Control Bit 14 */
-
- if ((sp->led_mode & 0x08) == 8)
- mode |= IPG_AC_LED_SPEED; /* Write Asic Control Bit 27 */
-
- ipg_w32(mode, ASIC_CTRL);
-}
-
-static void ipg_set_phy_set(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- int physet;
-
- physet = ipg_r8(PHY_SET);
- physet &= ~(IPG_PS_MEM_LENB9B | IPG_PS_MEM_LEN9 | IPG_PS_NON_COMPDET);
- physet |= ((sp->led_mode & 0x70) >> 4);
- ipg_w8(physet, PHY_SET);
-}
-
-static int ipg_reset(struct net_device *dev, u32 resetflags)
-{
- /* Assert functional resets via the IPG AsicCtrl
- * register as specified by the 'resetflags' input
- * parameter.
- */
- void __iomem *ioaddr = ipg_ioaddr(dev);
- unsigned int timeout_count = 0;
-
- IPG_DEBUG_MSG("_reset\n");
-
- ipg_w32(ipg_r32(ASIC_CTRL) | resetflags, ASIC_CTRL);
-
- /* Delay added to account for problem with 10Mbps reset. */
- mdelay(IPG_AC_RESETWAIT);
-
- while (IPG_AC_RESET_BUSY & ipg_r32(ASIC_CTRL)) {
- mdelay(IPG_AC_RESETWAIT);
- if (++timeout_count > IPG_AC_RESET_TIMEOUT)
- return -ETIME;
- }
- /* Set LED Mode in Asic Control */
- ipg_set_led_mode(dev);
-
- /* Set PHYSet Register Value */
- ipg_set_phy_set(dev);
- return 0;
-}
-
-/* Find the GMII PHY address. */
-static int ipg_find_phyaddr(struct net_device *dev)
-{
- unsigned int phyaddr, i;
-
- for (i = 0; i < 32; i++) {
- u32 status;
-
- /* Search for the correct PHY address among 32 possible. */
- phyaddr = (IPG_NIC_PHY_ADDRESS + i) % 32;
-
- /* 10/22/03 Grace change verify from GMII_PHY_STATUS to
- GMII_PHY_ID1
- */
-
- status = mdio_read(dev, phyaddr, MII_BMSR);
-
- if ((status != 0xFFFF) && (status != 0))
- return phyaddr;
- }
-
- return 0x1f;
-}
-
-/*
- * Configure IPG based on result of IEEE 802.3 PHY
- * auto-negotiation.
- */
-static int ipg_config_autoneg(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int txflowcontrol;
- unsigned int rxflowcontrol;
- unsigned int fullduplex;
- u32 mac_ctrl_val;
- u32 asicctrl;
- u8 phyctrl;
- const char *speed;
- const char *duplex;
- const char *tx_desc;
- const char *rx_desc;
-
- IPG_DEBUG_MSG("_config_autoneg\n");
-
- asicctrl = ipg_r32(ASIC_CTRL);
- phyctrl = ipg_r8(PHY_CTRL);
- mac_ctrl_val = ipg_r32(MAC_CTRL);
-
- /* Set flags for use in resolving auto-negotiation, assuming
- * non-1000Mbps, half duplex, no flow control.
- */
- fullduplex = 0;
- txflowcontrol = 0;
- rxflowcontrol = 0;
-
- /* To accommodate a problem in 10Mbps operation,
- * set a global flag if PHY running in 10Mbps mode.
- */
- sp->tenmbpsmode = 0;
-
- /* Determine actual speed of operation. */
- switch (phyctrl & IPG_PC_LINK_SPEED) {
- case IPG_PC_LINK_SPEED_10MBPS:
- speed = "10Mbps";
- sp->tenmbpsmode = 1;
- break;
- case IPG_PC_LINK_SPEED_100MBPS:
- speed = "100Mbps";
- break;
- case IPG_PC_LINK_SPEED_1000MBPS:
- speed = "1000Mbps";
- break;
- default:
- speed = "undefined!";
- return 0;
- }
-
- netdev_info(dev, "Link speed = %s\n", speed);
- if (sp->tenmbpsmode == 1)
- netdev_info(dev, "10Mbps operational mode enabled\n");
-
- if (phyctrl & IPG_PC_DUPLEX_STATUS) {
- fullduplex = 1;
- txflowcontrol = 1;
- rxflowcontrol = 1;
- }
-
- /* Configure full duplex, and flow control. */
- if (fullduplex == 1) {
-
- /* Configure IPG for full duplex operation. */
-
- duplex = "full";
-
- mac_ctrl_val |= IPG_MC_DUPLEX_SELECT_FD;
-
- if (txflowcontrol == 1) {
- tx_desc = "";
- mac_ctrl_val |= IPG_MC_TX_FLOW_CONTROL_ENABLE;
- } else {
- tx_desc = "no ";
- mac_ctrl_val &= ~IPG_MC_TX_FLOW_CONTROL_ENABLE;
- }
-
- if (rxflowcontrol == 1) {
- rx_desc = "";
- mac_ctrl_val |= IPG_MC_RX_FLOW_CONTROL_ENABLE;
- } else {
- rx_desc = "no ";
- mac_ctrl_val &= ~IPG_MC_RX_FLOW_CONTROL_ENABLE;
- }
- } else {
- duplex = "half";
- tx_desc = "no ";
- rx_desc = "no ";
- mac_ctrl_val &= (~IPG_MC_DUPLEX_SELECT_FD &
- ~IPG_MC_TX_FLOW_CONTROL_ENABLE &
- ~IPG_MC_RX_FLOW_CONTROL_ENABLE);
- }
-
- netdev_info(dev, "setting %s duplex, %sTX, %sRX flow control\n",
- duplex, tx_desc, rx_desc);
- ipg_w32(mac_ctrl_val, MAC_CTRL);
-
- return 0;
-}
-
-/* Determine and configure multicast operation and set
- * receive mode for IPG.
- */
-static void ipg_nic_set_multicast_list(struct net_device *dev)
-{
- void __iomem *ioaddr = ipg_ioaddr(dev);
- struct netdev_hw_addr *ha;
- unsigned int hashindex;
- u32 hashtable[2];
- u8 receivemode;
-
- IPG_DEBUG_MSG("_nic_set_multicast_list\n");
-
- receivemode = IPG_RM_RECEIVEUNICAST | IPG_RM_RECEIVEBROADCAST;
-
- if (dev->flags & IFF_PROMISC) {
- /* NIC to be configured in promiscuous mode. */
- receivemode = IPG_RM_RECEIVEALLFRAMES;
- } else if ((dev->flags & IFF_ALLMULTI) ||
- ((dev->flags & IFF_MULTICAST) &&
- (netdev_mc_count(dev) > IPG_MULTICAST_HASHTABLE_SIZE))) {
- /* NIC to be configured to receive all multicast
- * frames. */
- receivemode |= IPG_RM_RECEIVEMULTICAST;
- } else if ((dev->flags & IFF_MULTICAST) && !netdev_mc_empty(dev)) {
- /* NIC to be configured to receive selected
- * multicast addresses. */
- receivemode |= IPG_RM_RECEIVEMULTICASTHASH;
- }
-
- /* Calculate the bits to set for the 64 bit, IPG HASHTABLE.
- * The IPG applies a cyclic-redundancy-check (the same CRC
- * used to calculate the frame data FCS) to the destination
- * address all incoming multicast frames whose destination
- * address has the multicast bit set. The least significant
- * 6 bits of the CRC result are used as an addressing index
- * into the hash table. If the value of the bit addressed by
- * this index is a 1, the frame is passed to the host system.
- */
-
- /* Clear hashtable. */
- hashtable[0] = 0x00000000;
- hashtable[1] = 0x00000000;
-
- /* Cycle through all multicast addresses to filter. */
- netdev_for_each_mc_addr(ha, dev) {
- /* Calculate CRC result for each multicast address. */
- hashindex = crc32_le(0xffffffff, ha->addr,
- ETH_ALEN);
-
- /* Use only the least significant 6 bits. */
- hashindex = hashindex & 0x3F;
-
- /* Within "hashtable", set bit number "hashindex"
- * to a logic 1.
- */
- set_bit(hashindex, (void *)hashtable);
- }
-
- /* Write the value of the hashtable, to the 4, 16 bit
- * HASHTABLE IPG registers.
- */
- ipg_w32(hashtable[0], HASHTABLE_0);
- ipg_w32(hashtable[1], HASHTABLE_1);
-
- ipg_w8(IPG_RM_RSVD_MASK & receivemode, RECEIVE_MODE);
-
- IPG_DEBUG_MSG("ReceiveMode = %x\n", ipg_r8(RECEIVE_MODE));
-}
-
-static int ipg_io_config(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = ipg_ioaddr(dev);
- u32 origmacctrl;
- u32 restoremacctrl;
-
- IPG_DEBUG_MSG("_io_config\n");
-
- origmacctrl = ipg_r32(MAC_CTRL);
-
- restoremacctrl = origmacctrl | IPG_MC_STATISTICS_ENABLE;
-
- /* Based on compilation option, determine if FCS is to be
- * stripped on receive frames by IPG.
- */
- if (!IPG_STRIP_FCS_ON_RX)
- restoremacctrl |= IPG_MC_RCV_FCS;
-
- /* Determine if transmitter and/or receiver are
- * enabled so we may restore MACCTRL correctly.
- */
- if (origmacctrl & IPG_MC_TX_ENABLED)
- restoremacctrl |= IPG_MC_TX_ENABLE;
-
- if (origmacctrl & IPG_MC_RX_ENABLED)
- restoremacctrl |= IPG_MC_RX_ENABLE;
-
- /* Transmitter and receiver must be disabled before setting
- * IFSSelect.
- */
- ipg_w32((origmacctrl & (IPG_MC_RX_DISABLE | IPG_MC_TX_DISABLE)) &
- IPG_MC_RSVD_MASK, MAC_CTRL);
-
- /* Now that transmitter and receiver are disabled, write
- * to IFSSelect.
- */
- ipg_w32((origmacctrl & IPG_MC_IFS_96BIT) & IPG_MC_RSVD_MASK, MAC_CTRL);
-
- /* Set RECEIVEMODE register. */
- ipg_nic_set_multicast_list(dev);
-
- ipg_w16(sp->max_rxframe_size, MAX_FRAME_SIZE);
-
- ipg_w8(IPG_RXDMAPOLLPERIOD_VALUE, RX_DMA_POLL_PERIOD);
- ipg_w8(IPG_RXDMAURGENTTHRESH_VALUE, RX_DMA_URGENT_THRESH);
- ipg_w8(IPG_RXDMABURSTTHRESH_VALUE, RX_DMA_BURST_THRESH);
- ipg_w8(IPG_TXDMAPOLLPERIOD_VALUE, TX_DMA_POLL_PERIOD);
- ipg_w8(IPG_TXDMAURGENTTHRESH_VALUE, TX_DMA_URGENT_THRESH);
- ipg_w8(IPG_TXDMABURSTTHRESH_VALUE, TX_DMA_BURST_THRESH);
- ipg_w16((IPG_IE_HOST_ERROR | IPG_IE_TX_DMA_COMPLETE |
- IPG_IE_TX_COMPLETE | IPG_IE_INT_REQUESTED |
- IPG_IE_UPDATE_STATS | IPG_IE_LINK_EVENT |
- IPG_IE_RX_DMA_COMPLETE | IPG_IE_RX_DMA_PRIORITY), INT_ENABLE);
- ipg_w16(IPG_FLOWONTHRESH_VALUE, FLOW_ON_THRESH);
- ipg_w16(IPG_FLOWOFFTHRESH_VALUE, FLOW_OFF_THRESH);
-
- /* IPG multi-frag frame bug workaround.
- * Per silicon revision B3 eratta.
- */
- ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0200, DEBUG_CTRL);
-
- /* IPG TX poll now bug workaround.
- * Per silicon revision B3 eratta.
- */
- ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0010, DEBUG_CTRL);
-
- /* IPG RX poll now bug workaround.
- * Per silicon revision B3 eratta.
- */
- ipg_w16(ipg_r16(DEBUG_CTRL) | 0x0020, DEBUG_CTRL);
-
- /* Now restore MACCTRL to original setting. */
- ipg_w32(IPG_MC_RSVD_MASK & restoremacctrl, MAC_CTRL);
-
- /* Disable unused RMON statistics. */
- ipg_w32(IPG_RZ_ALL, RMON_STATISTICS_MASK);
-
- /* Disable unused MIB statistics. */
- ipg_w32(IPG_SM_MACCONTROLFRAMESXMTD | IPG_SM_MACCONTROLFRAMESRCVD |
- IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK | IPG_SM_TXJUMBOFRAMES |
- IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK | IPG_SM_RXJUMBOFRAMES |
- IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK |
- IPG_SM_UDPCHECKSUMERRORS | IPG_SM_TCPCHECKSUMERRORS |
- IPG_SM_IPCHECKSUMERRORS, STATISTICS_MASK);
-
- return 0;
-}
-
-/*
- * Create a receive buffer within system memory and update
- * NIC private structure appropriately.
- */
-static int ipg_get_rxbuff(struct net_device *dev, int entry)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- struct ipg_rx *rxfd = sp->rxd + entry;
- struct sk_buff *skb;
- u64 rxfragsize;
-
- IPG_DEBUG_MSG("_get_rxbuff\n");
-
- skb = netdev_alloc_skb_ip_align(dev, sp->rxsupport_size);
- if (!skb) {
- sp->rx_buff[entry] = NULL;
- return -ENOMEM;
- }
-
- /* Save the address of the sk_buff structure. */
- sp->rx_buff[entry] = skb;
-
- rxfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE));
-
- /* Set the RFD fragment length. */
- rxfragsize = sp->rxfrag_size;
- rxfd->frag_info |= cpu_to_le64((rxfragsize << 48) & IPG_RFI_FRAGLEN);
-
- return 0;
-}
-
-static int init_rfdlist(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
-
- IPG_DEBUG_MSG("_init_rfdlist\n");
-
- for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
- struct ipg_rx *rxfd = sp->rxd + i;
-
- if (sp->rx_buff[i]) {
- pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(sp->rx_buff[i]);
- sp->rx_buff[i] = NULL;
- }
-
- /* Clear out the RFS field. */
- rxfd->rfs = 0x0000000000000000;
-
- if (ipg_get_rxbuff(dev, i) < 0) {
- /*
- * A receive buffer was not ready, break the
- * RFD list here.
- */
- IPG_DEBUG_MSG("Cannot allocate Rx buffer\n");
-
- /* Just in case we cannot allocate a single RFD.
- * Should not occur.
- */
- if (i == 0) {
- netdev_err(dev, "No memory available for RFD list\n");
- return -ENOMEM;
- }
- }
-
- rxfd->next_desc = cpu_to_le64(sp->rxd_map +
- sizeof(struct ipg_rx)*(i + 1));
- }
- sp->rxd[i - 1].next_desc = cpu_to_le64(sp->rxd_map);
-
- sp->rx_current = 0;
- sp->rx_dirty = 0;
-
- /* Write the location of the RFDList to the IPG. */
- ipg_w32((u32) sp->rxd_map, RFD_LIST_PTR_0);
- ipg_w32(0x00000000, RFD_LIST_PTR_1);
-
- return 0;
-}
-
-static void init_tfdlist(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
-
- IPG_DEBUG_MSG("_init_tfdlist\n");
-
- for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
- struct ipg_tx *txfd = sp->txd + i;
-
- txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
-
- if (sp->tx_buff[i]) {
- dev_kfree_skb_irq(sp->tx_buff[i]);
- sp->tx_buff[i] = NULL;
- }
-
- txfd->next_desc = cpu_to_le64(sp->txd_map +
- sizeof(struct ipg_tx)*(i + 1));
- }
- sp->txd[i - 1].next_desc = cpu_to_le64(sp->txd_map);
-
- sp->tx_current = 0;
- sp->tx_dirty = 0;
-
- /* Write the location of the TFDList to the IPG. */
- IPG_DDEBUG_MSG("Starting TFDListPtr = %08x\n",
- (u32) sp->txd_map);
- ipg_w32((u32) sp->txd_map, TFD_LIST_PTR_0);
- ipg_w32(0x00000000, TFD_LIST_PTR_1);
-
- sp->reset_current_tfd = 1;
-}
-
-/*
- * Free all transmit buffers which have already been transferred
- * via DMA to the IPG.
- */
-static void ipg_nic_txfree(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- unsigned int released, pending, dirty;
-
- IPG_DEBUG_MSG("_nic_txfree\n");
-
- pending = sp->tx_current - sp->tx_dirty;
- dirty = sp->tx_dirty % IPG_TFDLIST_LENGTH;
-
- for (released = 0; released < pending; released++) {
- struct sk_buff *skb = sp->tx_buff[dirty];
- struct ipg_tx *txfd = sp->txd + dirty;
-
- IPG_DEBUG_MSG("TFC = %016lx\n", (unsigned long) txfd->tfc);
-
- /* Look at each TFD's TFC field beginning
- * at the last freed TFD up to the current TFD.
- * If the TFDDone bit is set, free the associated
- * buffer.
- */
- if (!(txfd->tfc & cpu_to_le64(IPG_TFC_TFDDONE)))
- break;
-
- /* Free the transmit buffer. */
- if (skb) {
- pci_unmap_single(sp->pdev,
- le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
- skb->len, PCI_DMA_TODEVICE);
-
- dev_kfree_skb_irq(skb);
-
- sp->tx_buff[dirty] = NULL;
- }
- dirty = (dirty + 1) % IPG_TFDLIST_LENGTH;
- }
-
- sp->tx_dirty += released;
-
- if (netif_queue_stopped(dev) &&
- (sp->tx_current != (sp->tx_dirty + IPG_TFDLIST_LENGTH))) {
- netif_wake_queue(dev);
- }
-}
-
-static void ipg_tx_timeout(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
-
- ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA | IPG_AC_NETWORK |
- IPG_AC_FIFO);
-
- spin_lock_irq(&sp->lock);
-
- /* Re-configure after DMA reset. */
- if (ipg_io_config(dev) < 0)
- netdev_info(dev, "Error during re-configuration\n");
-
- init_tfdlist(dev);
-
- spin_unlock_irq(&sp->lock);
-
- ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) & IPG_MC_RSVD_MASK,
- MAC_CTRL);
-}
-
-/*
- * For TxComplete interrupts, free all transmit
- * buffers which have already been transferred via DMA
- * to the IPG.
- */
-static void ipg_nic_txcleanup(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
-
- IPG_DEBUG_MSG("_nic_txcleanup\n");
-
- for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
- /* Reading the TXSTATUS register clears the
- * TX_COMPLETE interrupt.
- */
- u32 txstatusdword = ipg_r32(TX_STATUS);
-
- IPG_DEBUG_MSG("TxStatus = %08x\n", txstatusdword);
-
- /* Check for Transmit errors. Error bits only valid if
- * TX_COMPLETE bit in the TXSTATUS register is a 1.
- */
- if (!(txstatusdword & IPG_TS_TX_COMPLETE))
- break;
-
- /* If in 10Mbps mode, indicate transmit is ready. */
- if (sp->tenmbpsmode) {
- netif_wake_queue(dev);
- }
-
- /* Transmit error, increment stat counters. */
- if (txstatusdword & IPG_TS_TX_ERROR) {
- IPG_DEBUG_MSG("Transmit error\n");
- sp->stats.tx_errors++;
- }
-
- /* Late collision, re-enable transmitter. */
- if (txstatusdword & IPG_TS_LATE_COLLISION) {
- IPG_DEBUG_MSG("Late collision on transmit\n");
- ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
- IPG_MC_RSVD_MASK, MAC_CTRL);
- }
-
- /* Maximum collisions, re-enable transmitter. */
- if (txstatusdword & IPG_TS_TX_MAX_COLL) {
- IPG_DEBUG_MSG("Maximum collisions on transmit\n");
- ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
- IPG_MC_RSVD_MASK, MAC_CTRL);
- }
-
- /* Transmit underrun, reset and re-enable
- * transmitter.
- */
- if (txstatusdword & IPG_TS_TX_UNDERRUN) {
- IPG_DEBUG_MSG("Transmitter underrun\n");
- sp->stats.tx_fifo_errors++;
- ipg_reset(dev, IPG_AC_TX_RESET | IPG_AC_DMA |
- IPG_AC_NETWORK | IPG_AC_FIFO);
-
- /* Re-configure after DMA reset. */
- if (ipg_io_config(dev) < 0) {
- netdev_info(dev, "Error during re-configuration\n");
- }
- init_tfdlist(dev);
-
- ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_TX_ENABLE) &
- IPG_MC_RSVD_MASK, MAC_CTRL);
- }
- }
-
- ipg_nic_txfree(dev);
-}
-
-/* Provides statistical information about the IPG NIC. */
-static struct net_device_stats *ipg_nic_get_stats(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- u16 temp1;
- u16 temp2;
-
- IPG_DEBUG_MSG("_nic_get_stats\n");
-
- /* Check to see if the NIC has been initialized via nic_open,
- * before trying to read statistic registers.
- */
- if (!netif_running(dev))
- return &sp->stats;
-
- sp->stats.rx_packets += ipg_r32(IPG_FRAMESRCVDOK);
- sp->stats.tx_packets += ipg_r32(IPG_FRAMESXMTDOK);
- sp->stats.rx_bytes += ipg_r32(IPG_OCTETRCVOK);
- sp->stats.tx_bytes += ipg_r32(IPG_OCTETXMTOK);
- temp1 = ipg_r16(IPG_FRAMESLOSTRXERRORS);
- sp->stats.rx_errors += temp1;
- sp->stats.rx_missed_errors += temp1;
- temp1 = ipg_r32(IPG_SINGLECOLFRAMES) + ipg_r32(IPG_MULTICOLFRAMES) +
- ipg_r32(IPG_LATECOLLISIONS);
- temp2 = ipg_r16(IPG_CARRIERSENSEERRORS);
- sp->stats.collisions += temp1;
- sp->stats.tx_dropped += ipg_r16(IPG_FRAMESABORTXSCOLLS);
- sp->stats.tx_errors += ipg_r16(IPG_FRAMESWEXDEFERRAL) +
- ipg_r32(IPG_FRAMESWDEFERREDXMT) + temp1 + temp2;
- sp->stats.multicast += ipg_r32(IPG_MCSTOCTETRCVDOK);
-
- /* detailed tx_errors */
- sp->stats.tx_carrier_errors += temp2;
-
- /* detailed rx_errors */
- sp->stats.rx_length_errors += ipg_r16(IPG_INRANGELENGTHERRORS) +
- ipg_r16(IPG_FRAMETOOLONGERRORS);
- sp->stats.rx_crc_errors += ipg_r16(IPG_FRAMECHECKSEQERRORS);
-
- /* Unutilized IPG statistic registers. */
- ipg_r32(IPG_MCSTFRAMESRCVDOK);
-
- return &sp->stats;
-}
-
-/* Restore used receive buffers. */
-static int ipg_nic_rxrestore(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- const unsigned int curr = sp->rx_current;
- unsigned int dirty = sp->rx_dirty;
-
- IPG_DEBUG_MSG("_nic_rxrestore\n");
-
- for (dirty = sp->rx_dirty; curr - dirty > 0; dirty++) {
- unsigned int entry = dirty % IPG_RFDLIST_LENGTH;
-
- /* rx_copybreak may poke hole here and there. */
- if (sp->rx_buff[entry])
- continue;
-
- /* Generate a new receive buffer to replace the
- * current buffer (which will be released by the
- * Linux system).
- */
- if (ipg_get_rxbuff(dev, entry) < 0) {
- IPG_DEBUG_MSG("Cannot allocate new Rx buffer\n");
-
- break;
- }
-
- /* Reset the RFS field. */
- sp->rxd[entry].rfs = 0x0000000000000000;
- }
- sp->rx_dirty = dirty;
-
- return 0;
-}
-
-/* use jumboindex and jumbosize to control jumbo frame status
- * initial status is jumboindex=-1 and jumbosize=0
- * 1. jumboindex = -1 and jumbosize=0 : previous jumbo frame has been done.
- * 2. jumboindex != -1 and jumbosize != 0 : jumbo frame is not over size and receiving
- * 3. jumboindex = -1 and jumbosize != 0 : jumbo frame is over size, already dump
- * previous receiving and need to continue dumping the current one
- */
-enum {
- NORMAL_PACKET,
- ERROR_PACKET
-};
-
-enum {
- FRAME_NO_START_NO_END = 0,
- FRAME_WITH_START = 1,
- FRAME_WITH_END = 10,
- FRAME_WITH_START_WITH_END = 11
-};
-
-static void ipg_nic_rx_free_skb(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
-
- if (sp->rx_buff[entry]) {
- struct ipg_rx *rxfd = sp->rxd + entry;
-
- pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(sp->rx_buff[entry]);
- sp->rx_buff[entry] = NULL;
- }
-}
-
-static int ipg_nic_rx_check_frame_type(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- struct ipg_rx *rxfd = sp->rxd + (sp->rx_current % IPG_RFDLIST_LENGTH);
- int type = FRAME_NO_START_NO_END;
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART)
- type += FRAME_WITH_START;
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND)
- type += FRAME_WITH_END;
- return type;
-}
-
-static int ipg_nic_rx_check_error(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- unsigned int entry = sp->rx_current % IPG_RFDLIST_LENGTH;
- struct ipg_rx *rxfd = sp->rxd + entry;
-
- if (IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
- (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
- IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
- IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR))) {
- IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
- (unsigned long) rxfd->rfs);
-
- /* Increment general receive error statistic. */
- sp->stats.rx_errors++;
-
- /* Increment detailed receive error statistics. */
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
- IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
-
- sp->stats.rx_fifo_errors++;
- }
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
- IPG_DEBUG_MSG("RX runt occurred\n");
- sp->stats.rx_length_errors++;
- }
-
- /* Do nothing for IPG_RFS_RXOVERSIZEDFRAME,
- * error count handled by a IPG statistic register.
- */
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
- IPG_DEBUG_MSG("RX alignment error occurred\n");
- sp->stats.rx_frame_errors++;
- }
-
- /* Do nothing for IPG_RFS_RXFCSERROR, error count
- * handled by a IPG statistic register.
- */
-
- /* Free the memory associated with the RX
- * buffer since it is erroneous and we will
- * not pass it to higher layer processes.
- */
- if (sp->rx_buff[entry]) {
- pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
- dev_kfree_skb_irq(sp->rx_buff[entry]);
- sp->rx_buff[entry] = NULL;
- }
- return ERROR_PACKET;
- }
- return NORMAL_PACKET;
-}
-
-static void ipg_nic_rx_with_start_and_end(struct net_device *dev,
- struct ipg_nic_private *sp,
- struct ipg_rx *rxfd, unsigned entry)
-{
- struct ipg_jumbo *jumbo = &sp->jumbo;
- struct sk_buff *skb;
- int framelen;
-
- if (jumbo->found_start) {
- dev_kfree_skb_irq(jumbo->skb);
- jumbo->found_start = 0;
- jumbo->current_size = 0;
- jumbo->skb = NULL;
- }
-
- /* 1: found error, 0 no error */
- if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
- return;
-
- skb = sp->rx_buff[entry];
- if (!skb)
- return;
-
- /* accept this frame and send to upper layer */
- framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
- if (framelen > sp->rxfrag_size)
- framelen = sp->rxfrag_size;
-
- skb_put(skb, framelen);
- skb->protocol = eth_type_trans(skb, dev);
- skb_checksum_none_assert(skb);
- netif_rx(skb);
- sp->rx_buff[entry] = NULL;
-}
-
-static void ipg_nic_rx_with_start(struct net_device *dev,
- struct ipg_nic_private *sp,
- struct ipg_rx *rxfd, unsigned entry)
-{
- struct ipg_jumbo *jumbo = &sp->jumbo;
- struct pci_dev *pdev = sp->pdev;
- struct sk_buff *skb;
-
- /* 1: found error, 0 no error */
- if (ipg_nic_rx_check_error(dev) != NORMAL_PACKET)
- return;
-
- /* accept this frame and send to upper layer */
- skb = sp->rx_buff[entry];
- if (!skb)
- return;
-
- if (jumbo->found_start)
- dev_kfree_skb_irq(jumbo->skb);
-
- pci_unmap_single(pdev, le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
- skb_put(skb, sp->rxfrag_size);
-
- jumbo->found_start = 1;
- jumbo->current_size = sp->rxfrag_size;
- jumbo->skb = skb;
-
- sp->rx_buff[entry] = NULL;
-}
-
-static void ipg_nic_rx_with_end(struct net_device *dev,
- struct ipg_nic_private *sp,
- struct ipg_rx *rxfd, unsigned entry)
-{
- struct ipg_jumbo *jumbo = &sp->jumbo;
-
- /* 1: found error, 0 no error */
- if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
- struct sk_buff *skb = sp->rx_buff[entry];
-
- if (!skb)
- return;
-
- if (jumbo->found_start) {
- int framelen, endframelen;
-
- framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
-
- endframelen = framelen - jumbo->current_size;
- if (framelen > sp->rxsupport_size)
- dev_kfree_skb_irq(jumbo->skb);
- else {
- memcpy(skb_put(jumbo->skb, endframelen),
- skb->data, endframelen);
-
- jumbo->skb->protocol =
- eth_type_trans(jumbo->skb, dev);
-
- skb_checksum_none_assert(jumbo->skb);
- netif_rx(jumbo->skb);
- }
- }
-
- jumbo->found_start = 0;
- jumbo->current_size = 0;
- jumbo->skb = NULL;
-
- ipg_nic_rx_free_skb(dev);
- } else {
- dev_kfree_skb_irq(jumbo->skb);
- jumbo->found_start = 0;
- jumbo->current_size = 0;
- jumbo->skb = NULL;
- }
-}
-
-static void ipg_nic_rx_no_start_no_end(struct net_device *dev,
- struct ipg_nic_private *sp,
- struct ipg_rx *rxfd, unsigned entry)
-{
- struct ipg_jumbo *jumbo = &sp->jumbo;
-
- /* 1: found error, 0 no error */
- if (ipg_nic_rx_check_error(dev) == NORMAL_PACKET) {
- struct sk_buff *skb = sp->rx_buff[entry];
-
- if (skb) {
- if (jumbo->found_start) {
- jumbo->current_size += sp->rxfrag_size;
- if (jumbo->current_size <= sp->rxsupport_size) {
- memcpy(skb_put(jumbo->skb,
- sp->rxfrag_size),
- skb->data, sp->rxfrag_size);
- }
- }
- ipg_nic_rx_free_skb(dev);
- }
- } else {
- dev_kfree_skb_irq(jumbo->skb);
- jumbo->found_start = 0;
- jumbo->current_size = 0;
- jumbo->skb = NULL;
- }
-}
-
-static int ipg_nic_rx_jumbo(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- unsigned int curr = sp->rx_current;
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
-
- IPG_DEBUG_MSG("_nic_rx\n");
-
- for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
- unsigned int entry = curr % IPG_RFDLIST_LENGTH;
- struct ipg_rx *rxfd = sp->rxd + entry;
-
- if (!(rxfd->rfs & cpu_to_le64(IPG_RFS_RFDDONE)))
- break;
-
- switch (ipg_nic_rx_check_frame_type(dev)) {
- case FRAME_WITH_START_WITH_END:
- ipg_nic_rx_with_start_and_end(dev, sp, rxfd, entry);
- break;
- case FRAME_WITH_START:
- ipg_nic_rx_with_start(dev, sp, rxfd, entry);
- break;
- case FRAME_WITH_END:
- ipg_nic_rx_with_end(dev, sp, rxfd, entry);
- break;
- case FRAME_NO_START_NO_END:
- ipg_nic_rx_no_start_no_end(dev, sp, rxfd, entry);
- break;
- }
- }
-
- sp->rx_current = curr;
-
- if (i == IPG_MAXRFDPROCESS_COUNT) {
- /* There are more RFDs to process, however the
- * allocated amount of RFD processing time has
- * expired. Assert Interrupt Requested to make
- * sure we come back to process the remaining RFDs.
- */
- ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
- }
-
- ipg_nic_rxrestore(dev);
-
- return 0;
-}
-
-static int ipg_nic_rx(struct net_device *dev)
-{
- /* Transfer received Ethernet frames to higher network layers. */
- struct ipg_nic_private *sp = netdev_priv(dev);
- unsigned int curr = sp->rx_current;
- void __iomem *ioaddr = sp->ioaddr;
- struct ipg_rx *rxfd;
- unsigned int i;
-
- IPG_DEBUG_MSG("_nic_rx\n");
-
-#define __RFS_MASK \
- cpu_to_le64(IPG_RFS_RFDDONE | IPG_RFS_FRAMESTART | IPG_RFS_FRAMEEND)
-
- for (i = 0; i < IPG_MAXRFDPROCESS_COUNT; i++, curr++) {
- unsigned int entry = curr % IPG_RFDLIST_LENGTH;
- struct sk_buff *skb = sp->rx_buff[entry];
- unsigned int framelen;
-
- rxfd = sp->rxd + entry;
-
- if (((rxfd->rfs & __RFS_MASK) != __RFS_MASK) || !skb)
- break;
-
- /* Get received frame length. */
- framelen = le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFRAMELEN;
-
- /* Check for jumbo frame arrival with too small
- * RXFRAG_SIZE.
- */
- if (framelen > sp->rxfrag_size) {
- IPG_DEBUG_MSG
- ("RFS FrameLen > allocated fragment size\n");
-
- framelen = sp->rxfrag_size;
- }
-
- if ((IPG_DROP_ON_RX_ETH_ERRORS && (le64_to_cpu(rxfd->rfs) &
- (IPG_RFS_RXFIFOOVERRUN | IPG_RFS_RXRUNTFRAME |
- IPG_RFS_RXALIGNMENTERROR | IPG_RFS_RXFCSERROR |
- IPG_RFS_RXOVERSIZEDFRAME | IPG_RFS_RXLENGTHERROR)))) {
-
- IPG_DEBUG_MSG("Rx error, RFS = %016lx\n",
- (unsigned long int) rxfd->rfs);
-
- /* Increment general receive error statistic. */
- sp->stats.rx_errors++;
-
- /* Increment detailed receive error statistics. */
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFIFOOVERRUN) {
- IPG_DEBUG_MSG("RX FIFO overrun occurred\n");
- sp->stats.rx_fifo_errors++;
- }
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXRUNTFRAME) {
- IPG_DEBUG_MSG("RX runt occurred\n");
- sp->stats.rx_length_errors++;
- }
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXOVERSIZEDFRAME) ;
- /* Do nothing, error count handled by a IPG
- * statistic register.
- */
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXALIGNMENTERROR) {
- IPG_DEBUG_MSG("RX alignment error occurred\n");
- sp->stats.rx_frame_errors++;
- }
-
- if (le64_to_cpu(rxfd->rfs) & IPG_RFS_RXFCSERROR) ;
- /* Do nothing, error count handled by a IPG
- * statistic register.
- */
-
- /* Free the memory associated with the RX
- * buffer since it is erroneous and we will
- * not pass it to higher layer processes.
- */
- if (skb) {
- __le64 info = rxfd->frag_info;
-
- pci_unmap_single(sp->pdev,
- le64_to_cpu(info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
- dev_kfree_skb_irq(skb);
- }
- } else {
-
- /* Adjust the new buffer length to accommodate the size
- * of the received frame.
- */
- skb_put(skb, framelen);
-
- /* Set the buffer's protocol field to Ethernet. */
- skb->protocol = eth_type_trans(skb, dev);
-
- /* The IPG encountered an error with (or
- * there were no) IP/TCP/UDP checksums.
- * This may or may not indicate an invalid
- * IP/TCP/UDP frame was received. Let the
- * upper layer decide.
- */
- skb_checksum_none_assert(skb);
-
- /* Hand off frame for higher layer processing.
- * The function netif_rx() releases the sk_buff
- * when processing completes.
- */
- netif_rx(skb);
- }
-
- /* Assure RX buffer is not reused by IPG. */
- sp->rx_buff[entry] = NULL;
- }
-
- /*
- * If there are more RFDs to process and the allocated amount of RFD
- * processing time has expired, assert Interrupt Requested to make
- * sure we come back to process the remaining RFDs.
- */
- if (i == IPG_MAXRFDPROCESS_COUNT)
- ipg_w32(ipg_r32(ASIC_CTRL) | IPG_AC_INT_REQUEST, ASIC_CTRL);
-
-#ifdef IPG_DEBUG
- /* Check if the RFD list contained no receive frame data. */
- if (!i)
- sp->EmptyRFDListCount++;
-#endif
- while ((le64_to_cpu(rxfd->rfs) & IPG_RFS_RFDDONE) &&
- !((le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMESTART) &&
- (le64_to_cpu(rxfd->rfs) & IPG_RFS_FRAMEEND))) {
- unsigned int entry = curr++ % IPG_RFDLIST_LENGTH;
-
- rxfd = sp->rxd + entry;
-
- IPG_DEBUG_MSG("Frame requires multiple RFDs\n");
-
- /* An unexpected event, additional code needed to handle
- * properly. So for the time being, just disregard the
- * frame.
- */
-
- /* Free the memory associated with the RX
- * buffer since it is erroneous and we will
- * not pass it to higher layer processes.
- */
- if (sp->rx_buff[entry]) {
- pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- dev_kfree_skb_irq(sp->rx_buff[entry]);
- }
-
- /* Assure RX buffer is not reused by IPG. */
- sp->rx_buff[entry] = NULL;
- }
-
- sp->rx_current = curr;
-
- /* Check to see if there are a minimum number of used
- * RFDs before restoring any (should improve performance.)
- */
- if ((curr - sp->rx_dirty) >= IPG_MINUSEDRFDSTOFREE)
- ipg_nic_rxrestore(dev);
-
- return 0;
-}
-
-static void ipg_reset_after_host_error(struct work_struct *work)
-{
- struct ipg_nic_private *sp =
- container_of(work, struct ipg_nic_private, task.work);
- struct net_device *dev = sp->dev;
-
- /*
- * Acknowledge HostError interrupt by resetting
- * IPG DMA and HOST.
- */
- ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
-
- init_rfdlist(dev);
- init_tfdlist(dev);
-
- if (ipg_io_config(dev) < 0) {
- netdev_info(dev, "Cannot recover from PCI error\n");
- schedule_delayed_work(&sp->task, HZ);
- }
-}
-
-static irqreturn_t ipg_interrupt_handler(int irq, void *dev_inst)
-{
- struct net_device *dev = dev_inst;
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int handled = 0;
- u16 status;
-
- IPG_DEBUG_MSG("_interrupt_handler\n");
-
- if (sp->is_jumbo)
- ipg_nic_rxrestore(dev);
-
- spin_lock(&sp->lock);
-
- /* Get interrupt source information, and acknowledge
- * some (i.e. TxDMAComplete, RxDMAComplete, RxEarly,
- * IntRequested, MacControlFrame, LinkEvent) interrupts
- * if issued. Also, all IPG interrupts are disabled by
- * reading IntStatusAck.
- */
- status = ipg_r16(INT_STATUS_ACK);
-
- IPG_DEBUG_MSG("IntStatusAck = %04x\n", status);
-
- /* Shared IRQ of remove event. */
- if (!(status & IPG_IS_RSVD_MASK))
- goto out_enable;
-
- handled = 1;
-
- if (unlikely(!netif_running(dev)))
- goto out_unlock;
-
- /* If RFDListEnd interrupt, restore all used RFDs. */
- if (status & IPG_IS_RFD_LIST_END) {
- IPG_DEBUG_MSG("RFDListEnd Interrupt\n");
-
- /* The RFD list end indicates an RFD was encountered
- * with a 0 NextPtr, or with an RFDDone bit set to 1
- * (indicating the RFD is not read for use by the
- * IPG.) Try to restore all RFDs.
- */
- ipg_nic_rxrestore(dev);
-
-#ifdef IPG_DEBUG
- /* Increment the RFDlistendCount counter. */
- sp->RFDlistendCount++;
-#endif
- }
-
- /* If RFDListEnd, RxDMAPriority, RxDMAComplete, or
- * IntRequested interrupt, process received frames. */
- if ((status & IPG_IS_RX_DMA_PRIORITY) ||
- (status & IPG_IS_RFD_LIST_END) ||
- (status & IPG_IS_RX_DMA_COMPLETE) ||
- (status & IPG_IS_INT_REQUESTED)) {
-#ifdef IPG_DEBUG
- /* Increment the RFD list checked counter if interrupted
- * only to check the RFD list. */
- if (status & (~(IPG_IS_RX_DMA_PRIORITY | IPG_IS_RFD_LIST_END |
- IPG_IS_RX_DMA_COMPLETE | IPG_IS_INT_REQUESTED) &
- (IPG_IS_HOST_ERROR | IPG_IS_TX_DMA_COMPLETE |
- IPG_IS_LINK_EVENT | IPG_IS_TX_COMPLETE |
- IPG_IS_UPDATE_STATS)))
- sp->RFDListCheckedCount++;
-#endif
-
- if (sp->is_jumbo)
- ipg_nic_rx_jumbo(dev);
- else
- ipg_nic_rx(dev);
- }
-
- /* If TxDMAComplete interrupt, free used TFDs. */
- if (status & IPG_IS_TX_DMA_COMPLETE)
- ipg_nic_txfree(dev);
-
- /* TxComplete interrupts indicate one of numerous actions.
- * Determine what action to take based on TXSTATUS register.
- */
- if (status & IPG_IS_TX_COMPLETE)
- ipg_nic_txcleanup(dev);
-
- /* If UpdateStats interrupt, update Linux Ethernet statistics */
- if (status & IPG_IS_UPDATE_STATS)
- ipg_nic_get_stats(dev);
-
- /* If HostError interrupt, reset IPG. */
- if (status & IPG_IS_HOST_ERROR) {
- IPG_DDEBUG_MSG("HostError Interrupt\n");
-
- schedule_delayed_work(&sp->task, 0);
- }
-
- /* If LinkEvent interrupt, resolve autonegotiation. */
- if (status & IPG_IS_LINK_EVENT) {
- if (ipg_config_autoneg(dev) < 0)
- netdev_info(dev, "Auto-negotiation error\n");
- }
-
- /* If MACCtrlFrame interrupt, do nothing. */
- if (status & IPG_IS_MAC_CTRL_FRAME)
- IPG_DEBUG_MSG("MACCtrlFrame interrupt\n");
-
- /* If RxComplete interrupt, do nothing. */
- if (status & IPG_IS_RX_COMPLETE)
- IPG_DEBUG_MSG("RxComplete interrupt\n");
-
- /* If RxEarly interrupt, do nothing. */
- if (status & IPG_IS_RX_EARLY)
- IPG_DEBUG_MSG("RxEarly interrupt\n");
-
-out_enable:
- /* Re-enable IPG interrupts. */
- ipg_w16(IPG_IE_TX_DMA_COMPLETE | IPG_IE_RX_DMA_COMPLETE |
- IPG_IE_HOST_ERROR | IPG_IE_INT_REQUESTED | IPG_IE_TX_COMPLETE |
- IPG_IE_LINK_EVENT | IPG_IE_UPDATE_STATS, INT_ENABLE);
-out_unlock:
- spin_unlock(&sp->lock);
-
- return IRQ_RETVAL(handled);
-}
-
-static void ipg_rx_clear(struct ipg_nic_private *sp)
-{
- unsigned int i;
-
- for (i = 0; i < IPG_RFDLIST_LENGTH; i++) {
- if (sp->rx_buff[i]) {
- struct ipg_rx *rxfd = sp->rxd + i;
-
- dev_kfree_skb_irq(sp->rx_buff[i]);
- sp->rx_buff[i] = NULL;
- pci_unmap_single(sp->pdev,
- le64_to_cpu(rxfd->frag_info) & ~IPG_RFI_FRAGLEN,
- sp->rx_buf_sz, PCI_DMA_FROMDEVICE);
- }
- }
-}
-
-static void ipg_tx_clear(struct ipg_nic_private *sp)
-{
- unsigned int i;
-
- for (i = 0; i < IPG_TFDLIST_LENGTH; i++) {
- if (sp->tx_buff[i]) {
- struct ipg_tx *txfd = sp->txd + i;
-
- pci_unmap_single(sp->pdev,
- le64_to_cpu(txfd->frag_info) & ~IPG_TFI_FRAGLEN,
- sp->tx_buff[i]->len, PCI_DMA_TODEVICE);
-
- dev_kfree_skb_irq(sp->tx_buff[i]);
-
- sp->tx_buff[i] = NULL;
- }
- }
-}
-
-static int ipg_nic_open(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- struct pci_dev *pdev = sp->pdev;
- int rc;
-
- IPG_DEBUG_MSG("_nic_open\n");
-
- sp->rx_buf_sz = sp->rxsupport_size;
-
- /* Check for interrupt line conflicts, and request interrupt
- * line for IPG.
- *
- * IMPORTANT: Disable IPG interrupts prior to registering
- * IRQ.
- */
- ipg_w16(0x0000, INT_ENABLE);
-
- /* Register the interrupt line to be used by the IPG within
- * the Linux system.
- */
- rc = request_irq(pdev->irq, ipg_interrupt_handler, IRQF_SHARED,
- dev->name, dev);
- if (rc < 0) {
- netdev_info(dev, "Error when requesting interrupt\n");
- goto out;
- }
-
- dev->irq = pdev->irq;
-
- rc = -ENOMEM;
-
- sp->rxd = dma_alloc_coherent(&pdev->dev, IPG_RX_RING_BYTES,
- &sp->rxd_map, GFP_KERNEL);
- if (!sp->rxd)
- goto err_free_irq_0;
-
- sp->txd = dma_alloc_coherent(&pdev->dev, IPG_TX_RING_BYTES,
- &sp->txd_map, GFP_KERNEL);
- if (!sp->txd)
- goto err_free_rx_1;
-
- rc = init_rfdlist(dev);
- if (rc < 0) {
- netdev_info(dev, "Error during configuration\n");
- goto err_free_tx_2;
- }
-
- init_tfdlist(dev);
-
- rc = ipg_io_config(dev);
- if (rc < 0) {
- netdev_info(dev, "Error during configuration\n");
- goto err_release_tfdlist_3;
- }
-
- /* Resolve autonegotiation. */
- if (ipg_config_autoneg(dev) < 0)
- netdev_info(dev, "Auto-negotiation error\n");
-
- /* initialize JUMBO Frame control variable */
- sp->jumbo.found_start = 0;
- sp->jumbo.current_size = 0;
- sp->jumbo.skb = NULL;
-
- /* Enable transmit and receive operation of the IPG. */
- ipg_w32((ipg_r32(MAC_CTRL) | IPG_MC_RX_ENABLE | IPG_MC_TX_ENABLE) &
- IPG_MC_RSVD_MASK, MAC_CTRL);
-
- netif_start_queue(dev);
-out:
- return rc;
-
-err_release_tfdlist_3:
- ipg_tx_clear(sp);
- ipg_rx_clear(sp);
-err_free_tx_2:
- dma_free_coherent(&pdev->dev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
-err_free_rx_1:
- dma_free_coherent(&pdev->dev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
-err_free_irq_0:
- free_irq(pdev->irq, dev);
- goto out;
-}
-
-static int ipg_nic_stop(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- struct pci_dev *pdev = sp->pdev;
-
- IPG_DEBUG_MSG("_nic_stop\n");
-
- netif_stop_queue(dev);
-
- IPG_DUMPTFDLIST(dev);
-
- do {
- (void) ipg_r16(INT_STATUS_ACK);
-
- ipg_reset(dev, IPG_AC_GLOBAL_RESET | IPG_AC_HOST | IPG_AC_DMA);
-
- synchronize_irq(pdev->irq);
- } while (ipg_r16(INT_ENABLE) & IPG_IE_RSVD_MASK);
-
- ipg_rx_clear(sp);
-
- ipg_tx_clear(sp);
-
- pci_free_consistent(pdev, IPG_RX_RING_BYTES, sp->rxd, sp->rxd_map);
- pci_free_consistent(pdev, IPG_TX_RING_BYTES, sp->txd, sp->txd_map);
-
- free_irq(pdev->irq, dev);
-
- return 0;
-}
-
-static netdev_tx_t ipg_nic_hard_start_xmit(struct sk_buff *skb,
- struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int entry = sp->tx_current % IPG_TFDLIST_LENGTH;
- unsigned long flags;
- struct ipg_tx *txfd;
-
- IPG_DDEBUG_MSG("_nic_hard_start_xmit\n");
-
- /* If in 10Mbps mode, stop the transmit queue so
- * no more transmit frames are accepted.
- */
- if (sp->tenmbpsmode)
- netif_stop_queue(dev);
-
- if (sp->reset_current_tfd) {
- sp->reset_current_tfd = 0;
- entry = 0;
- }
-
- txfd = sp->txd + entry;
-
- sp->tx_buff[entry] = skb;
-
- /* Clear all TFC fields, except TFDDONE. */
- txfd->tfc = cpu_to_le64(IPG_TFC_TFDDONE);
-
- /* Specify the TFC field within the TFD. */
- txfd->tfc |= cpu_to_le64(IPG_TFC_WORDALIGNDISABLED |
- (IPG_TFC_FRAMEID & sp->tx_current) |
- (IPG_TFC_FRAGCOUNT & (1 << 24)));
- /*
- * 16--17 (WordAlign) <- 3 (disable),
- * 0--15 (FrameId) <- sp->tx_current,
- * 24--27 (FragCount) <- 1
- */
-
- /* Request TxComplete interrupts at an interval defined
- * by the constant IPG_FRAMESBETWEENTXCOMPLETES.
- * Request TxComplete interrupt for every frame
- * if in 10Mbps mode to accommodate problem with 10Mbps
- * processing.
- */
- if (sp->tenmbpsmode)
- txfd->tfc |= cpu_to_le64(IPG_TFC_TXINDICATE);
- txfd->tfc |= cpu_to_le64(IPG_TFC_TXDMAINDICATE);
- /* Based on compilation option, determine if FCS is to be
- * appended to transmit frame by IPG.
- */
- if (!(IPG_APPEND_FCS_ON_TX))
- txfd->tfc |= cpu_to_le64(IPG_TFC_FCSAPPENDDISABLE);
-
- /* Based on compilation option, determine if IP, TCP and/or
- * UDP checksums are to be added to transmit frame by IPG.
- */
- if (IPG_ADD_IPCHECKSUM_ON_TX)
- txfd->tfc |= cpu_to_le64(IPG_TFC_IPCHECKSUMENABLE);
-
- if (IPG_ADD_TCPCHECKSUM_ON_TX)
- txfd->tfc |= cpu_to_le64(IPG_TFC_TCPCHECKSUMENABLE);
-
- if (IPG_ADD_UDPCHECKSUM_ON_TX)
- txfd->tfc |= cpu_to_le64(IPG_TFC_UDPCHECKSUMENABLE);
-
- /* Based on compilation option, determine if VLAN tag info is to be
- * inserted into transmit frame by IPG.
- */
- if (IPG_INSERT_MANUAL_VLAN_TAG) {
- txfd->tfc |= cpu_to_le64(IPG_TFC_VLANTAGINSERT |
- ((u64) IPG_MANUAL_VLAN_VID << 32) |
- ((u64) IPG_MANUAL_VLAN_CFI << 44) |
- ((u64) IPG_MANUAL_VLAN_USERPRIORITY << 45));
- }
-
- /* The fragment start location within system memory is defined
- * by the sk_buff structure's data field. The physical address
- * of this location within the system's virtual memory space
- * is determined using the IPG_HOST2BUS_MAP function.
- */
- txfd->frag_info = cpu_to_le64(pci_map_single(sp->pdev, skb->data,
- skb->len, PCI_DMA_TODEVICE));
-
- /* The length of the fragment within system memory is defined by
- * the sk_buff structure's len field.
- */
- txfd->frag_info |= cpu_to_le64(IPG_TFI_FRAGLEN &
- ((u64) (skb->len & 0xffff) << 48));
-
- /* Clear the TFDDone bit last to indicate the TFD is ready
- * for transfer to the IPG.
- */
- txfd->tfc &= cpu_to_le64(~IPG_TFC_TFDDONE);
-
- spin_lock_irqsave(&sp->lock, flags);
-
- sp->tx_current++;
-
- mmiowb();
-
- ipg_w32(IPG_DC_TX_DMA_POLL_NOW, DMA_CTRL);
-
- if (sp->tx_current == (sp->tx_dirty + IPG_TFDLIST_LENGTH))
- netif_stop_queue(dev);
-
- spin_unlock_irqrestore(&sp->lock, flags);
-
- return NETDEV_TX_OK;
-}
-
-static void ipg_set_phy_default_param(unsigned char rev,
- struct net_device *dev, int phy_address)
-{
- unsigned short length;
- unsigned char revision;
- const unsigned short *phy_param;
- unsigned short address, value;
-
- phy_param = &DefaultPhyParam[0];
- length = *phy_param & 0x00FF;
- revision = (unsigned char)((*phy_param) >> 8);
- phy_param++;
- while (length != 0) {
- if (rev == revision) {
- while (length > 1) {
- address = *phy_param;
- value = *(phy_param + 1);
- phy_param += 2;
- mdio_write(dev, phy_address, address, value);
- length -= 4;
- }
- break;
- } else {
- phy_param += length / 2;
- length = *phy_param & 0x00FF;
- revision = (unsigned char)((*phy_param) >> 8);
- phy_param++;
- }
- }
-}
-
-static int read_eeprom(struct net_device *dev, int eep_addr)
-{
- void __iomem *ioaddr = ipg_ioaddr(dev);
- unsigned int i;
- int ret = 0;
- u16 value;
-
- value = IPG_EC_EEPROM_READOPCODE | (eep_addr & 0xff);
- ipg_w16(value, EEPROM_CTRL);
-
- for (i = 0; i < 1000; i++) {
- u16 data;
-
- mdelay(10);
- data = ipg_r16(EEPROM_CTRL);
- if (!(data & IPG_EC_EEPROM_BUSY)) {
- ret = ipg_r16(EEPROM_DATA);
- break;
- }
- }
- return ret;
-}
-
-static void ipg_init_mii(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- struct mii_if_info *mii_if = &sp->mii_if;
- int phyaddr;
-
- mii_if->dev = dev;
- mii_if->mdio_read = mdio_read;
- mii_if->mdio_write = mdio_write;
- mii_if->phy_id_mask = 0x1f;
- mii_if->reg_num_mask = 0x1f;
-
- mii_if->phy_id = phyaddr = ipg_find_phyaddr(dev);
-
- if (phyaddr != 0x1f) {
- u16 mii_phyctrl, mii_1000cr;
-
- mii_1000cr = mdio_read(dev, phyaddr, MII_CTRL1000);
- mii_1000cr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF |
- GMII_PHY_1000BASETCONTROL_PreferMaster;
- mdio_write(dev, phyaddr, MII_CTRL1000, mii_1000cr);
-
- mii_phyctrl = mdio_read(dev, phyaddr, MII_BMCR);
-
- /* Set default phyparam */
- ipg_set_phy_default_param(sp->pdev->revision, dev, phyaddr);
-
- /* Reset PHY */
- mii_phyctrl |= BMCR_RESET | BMCR_ANRESTART;
- mdio_write(dev, phyaddr, MII_BMCR, mii_phyctrl);
-
- }
-}
-
-static int ipg_hw_init(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- void __iomem *ioaddr = sp->ioaddr;
- unsigned int i;
- int rc;
-
- /* Read/Write and Reset EEPROM Value */
- /* Read LED Mode Configuration from EEPROM */
- sp->led_mode = read_eeprom(dev, 6);
-
- /* Reset all functions within the IPG. Do not assert
- * RST_OUT as not compatible with some PHYs.
- */
- rc = ipg_reset(dev, IPG_RESET_MASK);
- if (rc < 0)
- goto out;
-
- ipg_init_mii(dev);
-
- /* Read MAC Address from EEPROM */
- for (i = 0; i < 3; i++)
- sp->station_addr[i] = read_eeprom(dev, 16 + i);
-
- for (i = 0; i < 3; i++)
- ipg_w16(sp->station_addr[i], STATION_ADDRESS_0 + 2*i);
-
- /* Set station address in ethernet_device structure. */
- dev->dev_addr[0] = ipg_r16(STATION_ADDRESS_0) & 0x00ff;
- dev->dev_addr[1] = (ipg_r16(STATION_ADDRESS_0) & 0xff00) >> 8;
- dev->dev_addr[2] = ipg_r16(STATION_ADDRESS_1) & 0x00ff;
- dev->dev_addr[3] = (ipg_r16(STATION_ADDRESS_1) & 0xff00) >> 8;
- dev->dev_addr[4] = ipg_r16(STATION_ADDRESS_2) & 0x00ff;
- dev->dev_addr[5] = (ipg_r16(STATION_ADDRESS_2) & 0xff00) >> 8;
-out:
- return rc;
-}
-
-static int ipg_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- int rc;
-
- mutex_lock(&sp->mii_mutex);
- rc = generic_mii_ioctl(&sp->mii_if, if_mii(ifr), cmd, NULL);
- mutex_unlock(&sp->mii_mutex);
-
- return rc;
-}
-
-static int ipg_nic_change_mtu(struct net_device *dev, int new_mtu)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- int err;
-
- /* Function to accommodate changes to Maximum Transfer Unit
- * (or MTU) of IPG NIC. Cannot use default function since
- * the default will not allow for MTU > 1500 bytes.
- */
-
- IPG_DEBUG_MSG("_nic_change_mtu\n");
-
- /*
- * Check that the new MTU value is between 68 (14 byte header, 46 byte
- * payload, 4 byte FCS) and 10 KB, which is the largest supported MTU.
- */
- if (new_mtu < 68 || new_mtu > 10240)
- return -EINVAL;
-
- err = ipg_nic_stop(dev);
- if (err)
- return err;
-
- dev->mtu = new_mtu;
-
- sp->max_rxframe_size = new_mtu;
-
- sp->rxfrag_size = new_mtu;
- if (sp->rxfrag_size > 4088)
- sp->rxfrag_size = 4088;
-
- sp->rxsupport_size = sp->max_rxframe_size;
-
- if (new_mtu > 0x0600)
- sp->is_jumbo = true;
- else
- sp->is_jumbo = false;
-
- return ipg_nic_open(dev);
-}
-
-static int ipg_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- int rc;
-
- mutex_lock(&sp->mii_mutex);
- rc = mii_ethtool_gset(&sp->mii_if, cmd);
- mutex_unlock(&sp->mii_mutex);
-
- return rc;
-}
-
-static int ipg_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- int rc;
-
- mutex_lock(&sp->mii_mutex);
- rc = mii_ethtool_sset(&sp->mii_if, cmd);
- mutex_unlock(&sp->mii_mutex);
-
- return rc;
-}
-
-static int ipg_nway_reset(struct net_device *dev)
-{
- struct ipg_nic_private *sp = netdev_priv(dev);
- int rc;
-
- mutex_lock(&sp->mii_mutex);
- rc = mii_nway_restart(&sp->mii_if);
- mutex_unlock(&sp->mii_mutex);
-
- return rc;
-}
-
-static const struct ethtool_ops ipg_ethtool_ops = {
- .get_settings = ipg_get_settings,
- .set_settings = ipg_set_settings,
- .nway_reset = ipg_nway_reset,
-};
-
-static void ipg_remove(struct pci_dev *pdev)
-{
- struct net_device *dev = pci_get_drvdata(pdev);
- struct ipg_nic_private *sp = netdev_priv(dev);
-
- IPG_DEBUG_MSG("_remove\n");
-
- /* Un-register Ethernet device. */
- unregister_netdev(dev);
-
- pci_iounmap(pdev, sp->ioaddr);
-
- pci_release_regions(pdev);
-
- free_netdev(dev);
- pci_disable_device(pdev);
-}
-
-static const struct net_device_ops ipg_netdev_ops = {
- .ndo_open = ipg_nic_open,
- .ndo_stop = ipg_nic_stop,
- .ndo_start_xmit = ipg_nic_hard_start_xmit,
- .ndo_get_stats = ipg_nic_get_stats,
- .ndo_set_rx_mode = ipg_nic_set_multicast_list,
- .ndo_do_ioctl = ipg_ioctl,
- .ndo_tx_timeout = ipg_tx_timeout,
- .ndo_change_mtu = ipg_nic_change_mtu,
- .ndo_set_mac_address = eth_mac_addr,
- .ndo_validate_addr = eth_validate_addr,
-};
-
-static int ipg_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- unsigned int i = id->driver_data;
- struct ipg_nic_private *sp;
- struct net_device *dev;
- void __iomem *ioaddr;
- int rc;
-
- rc = pci_enable_device(pdev);
- if (rc < 0)
- goto out;
-
- pr_info("%s: %s\n", pci_name(pdev), ipg_brand_name[i]);
-
- pci_set_master(pdev);
-
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(40));
- if (rc < 0) {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
- if (rc < 0) {
- pr_err("%s: DMA config failed\n", pci_name(pdev));
- goto err_disable_0;
- }
- }
-
- /*
- * Initialize net device.
- */
- dev = alloc_etherdev(sizeof(struct ipg_nic_private));
- if (!dev) {
- rc = -ENOMEM;
- goto err_disable_0;
- }
-
- sp = netdev_priv(dev);
- spin_lock_init(&sp->lock);
- mutex_init(&sp->mii_mutex);
-
- sp->is_jumbo = IPG_IS_JUMBO;
- sp->rxfrag_size = IPG_RXFRAG_SIZE;
- sp->rxsupport_size = IPG_RXSUPPORT_SIZE;
- sp->max_rxframe_size = IPG_MAX_RXFRAME_SIZE;
-
- /* Declare IPG NIC functions for Ethernet device methods.
- */
- dev->netdev_ops = &ipg_netdev_ops;
- SET_NETDEV_DEV(dev, &pdev->dev);
- dev->ethtool_ops = &ipg_ethtool_ops;
-
- rc = pci_request_regions(pdev, DRV_NAME);
- if (rc)
- goto err_free_dev_1;
-
- ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1));
- if (!ioaddr) {
- pr_err("%s: cannot map MMIO\n", pci_name(pdev));
- rc = -EIO;
- goto err_release_regions_2;
- }
-
- /* Save the pointer to the PCI device information. */
- sp->ioaddr = ioaddr;
- sp->pdev = pdev;
- sp->dev = dev;
-
- INIT_DELAYED_WORK(&sp->task, ipg_reset_after_host_error);
-
- pci_set_drvdata(pdev, dev);
-
- rc = ipg_hw_init(dev);
- if (rc < 0)
- goto err_unmap_3;
-
- rc = register_netdev(dev);
- if (rc < 0)
- goto err_unmap_3;
-
- netdev_info(dev, "Ethernet device registered\n");
-out:
- return rc;
-
-err_unmap_3:
- pci_iounmap(pdev, ioaddr);
-err_release_regions_2:
- pci_release_regions(pdev);
-err_free_dev_1:
- free_netdev(dev);
-err_disable_0:
- pci_disable_device(pdev);
- goto out;
-}
-
-static struct pci_driver ipg_pci_driver = {
- .name = IPG_DRIVER_NAME,
- .id_table = ipg_pci_tbl,
- .probe = ipg_probe,
- .remove = ipg_remove,
-};
-
-module_pci_driver(ipg_pci_driver);
diff --git a/drivers/net/ethernet/icplus/ipg.h b/drivers/net/ethernet/icplus/ipg.h
deleted file mode 100644
index de60628..0000000
--- a/drivers/net/ethernet/icplus/ipg.h
+++ /dev/null
@@ -1,748 +0,0 @@
-/*
- * Include file for Gigabit Ethernet device driver for Network
- * Interface Cards (NICs) utilizing the Tamarack Microelectronics
- * Inc. IPG Gigabit or Triple Speed Ethernet Media Access
- * Controller.
- */
-#ifndef __LINUX_IPG_H
-#define __LINUX_IPG_H
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <linux/errno.h>
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <asm/bitops.h>
-
-/*
- * Constants
- */
-
-/* GMII based PHY IDs */
-#define NS 0x2000
-#define MARVELL 0x0141
-#define ICPLUS_PHY 0x243
-
-/* NIC Physical Layer Device MII register fields. */
-#define MII_PHY_SELECTOR_IEEE8023 0x0001
-#define MII_PHY_TECHABILITYFIELD 0x1FE0
-
-/* GMII_PHY_1000 need to set to prefer master */
-#define GMII_PHY_1000BASETCONTROL_PreferMaster 0x0400
-
-/* NIC Physical Layer Device GMII constants. */
-#define GMII_PREAMBLE 0xFFFFFFFF
-#define GMII_ST 0x1
-#define GMII_READ 0x2
-#define GMII_WRITE 0x1
-#define GMII_TA_READ_MASK 0x1
-#define GMII_TA_WRITE 0x2
-
-/* I/O register offsets. */
-enum ipg_regs {
- DMA_CTRL = 0x00,
- RX_DMA_STATUS = 0x08, /* Unused + reserved */
- TFD_LIST_PTR_0 = 0x10,
- TFD_LIST_PTR_1 = 0x14,
- TX_DMA_BURST_THRESH = 0x18,
- TX_DMA_URGENT_THRESH = 0x19,
- TX_DMA_POLL_PERIOD = 0x1a,
- RFD_LIST_PTR_0 = 0x1c,
- RFD_LIST_PTR_1 = 0x20,
- RX_DMA_BURST_THRESH = 0x24,
- RX_DMA_URGENT_THRESH = 0x25,
- RX_DMA_POLL_PERIOD = 0x26,
- DEBUG_CTRL = 0x2c,
- ASIC_CTRL = 0x30,
- FIFO_CTRL = 0x38, /* Unused */
- FLOW_OFF_THRESH = 0x3c,
- FLOW_ON_THRESH = 0x3e,
- EEPROM_DATA = 0x48,
- EEPROM_CTRL = 0x4a,
- EXPROM_ADDR = 0x4c, /* Unused */
- EXPROM_DATA = 0x50, /* Unused */
- WAKE_EVENT = 0x51, /* Unused */
- COUNTDOWN = 0x54, /* Unused */
- INT_STATUS_ACK = 0x5a,
- INT_ENABLE = 0x5c,
- INT_STATUS = 0x5e, /* Unused */
- TX_STATUS = 0x60,
- MAC_CTRL = 0x6c,
- VLAN_TAG = 0x70, /* Unused */
- PHY_SET = 0x75,
- PHY_CTRL = 0x76,
- STATION_ADDRESS_0 = 0x78,
- STATION_ADDRESS_1 = 0x7a,
- STATION_ADDRESS_2 = 0x7c,
- MAX_FRAME_SIZE = 0x86,
- RECEIVE_MODE = 0x88,
- HASHTABLE_0 = 0x8c,
- HASHTABLE_1 = 0x90,
- RMON_STATISTICS_MASK = 0x98,
- STATISTICS_MASK = 0x9c,
- RX_JUMBO_FRAMES = 0xbc, /* Unused */
- TCP_CHECKSUM_ERRORS = 0xc0, /* Unused */
- IP_CHECKSUM_ERRORS = 0xc2, /* Unused */
- UDP_CHECKSUM_ERRORS = 0xc4, /* Unused */
- TX_JUMBO_FRAMES = 0xf4 /* Unused */
-};
-
-/* Ethernet MIB statistic register offsets. */
-#define IPG_OCTETRCVOK 0xA8
-#define IPG_MCSTOCTETRCVDOK 0xAC
-#define IPG_BCSTOCTETRCVOK 0xB0
-#define IPG_FRAMESRCVDOK 0xB4
-#define IPG_MCSTFRAMESRCVDOK 0xB8
-#define IPG_BCSTFRAMESRCVDOK 0xBE
-#define IPG_MACCONTROLFRAMESRCVD 0xC6
-#define IPG_FRAMETOOLONGERRORS 0xC8
-#define IPG_INRANGELENGTHERRORS 0xCA
-#define IPG_FRAMECHECKSEQERRORS 0xCC
-#define IPG_FRAMESLOSTRXERRORS 0xCE
-#define IPG_OCTETXMTOK 0xD0
-#define IPG_MCSTOCTETXMTOK 0xD4
-#define IPG_BCSTOCTETXMTOK 0xD8
-#define IPG_FRAMESXMTDOK 0xDC
-#define IPG_MCSTFRAMESXMTDOK 0xE0
-#define IPG_FRAMESWDEFERREDXMT 0xE4
-#define IPG_LATECOLLISIONS 0xE8
-#define IPG_MULTICOLFRAMES 0xEC
-#define IPG_SINGLECOLFRAMES 0xF0
-#define IPG_BCSTFRAMESXMTDOK 0xF6
-#define IPG_CARRIERSENSEERRORS 0xF8
-#define IPG_MACCONTROLFRAMESXMTDOK 0xFA
-#define IPG_FRAMESABORTXSCOLLS 0xFC
-#define IPG_FRAMESWEXDEFERRAL 0xFE
-
-/* RMON statistic register offsets. */
-#define IPG_ETHERSTATSCOLLISIONS 0x100
-#define IPG_ETHERSTATSOCTETSTRANSMIT 0x104
-#define IPG_ETHERSTATSPKTSTRANSMIT 0x108
-#define IPG_ETHERSTATSPKTS64OCTESTSTRANSMIT 0x10C
-#define IPG_ETHERSTATSPKTS65TO127OCTESTSTRANSMIT 0x110
-#define IPG_ETHERSTATSPKTS128TO255OCTESTSTRANSMIT 0x114
-#define IPG_ETHERSTATSPKTS256TO511OCTESTSTRANSMIT 0x118
-#define IPG_ETHERSTATSPKTS512TO1023OCTESTSTRANSMIT 0x11C
-#define IPG_ETHERSTATSPKTS1024TO1518OCTESTSTRANSMIT 0x120
-#define IPG_ETHERSTATSCRCALIGNERRORS 0x124
-#define IPG_ETHERSTATSUNDERSIZEPKTS 0x128
-#define IPG_ETHERSTATSFRAGMENTS 0x12C
-#define IPG_ETHERSTATSJABBERS 0x130
-#define IPG_ETHERSTATSOCTETS 0x134
-#define IPG_ETHERSTATSPKTS 0x138
-#define IPG_ETHERSTATSPKTS64OCTESTS 0x13C
-#define IPG_ETHERSTATSPKTS65TO127OCTESTS 0x140
-#define IPG_ETHERSTATSPKTS128TO255OCTESTS 0x144
-#define IPG_ETHERSTATSPKTS256TO511OCTESTS 0x148
-#define IPG_ETHERSTATSPKTS512TO1023OCTESTS 0x14C
-#define IPG_ETHERSTATSPKTS1024TO1518OCTESTS 0x150
-
-/* RMON statistic register equivalents. */
-#define IPG_ETHERSTATSMULTICASTPKTSTRANSMIT 0xE0
-#define IPG_ETHERSTATSBROADCASTPKTSTRANSMIT 0xF6
-#define IPG_ETHERSTATSMULTICASTPKTS 0xB8
-#define IPG_ETHERSTATSBROADCASTPKTS 0xBE
-#define IPG_ETHERSTATSOVERSIZEPKTS 0xC8
-#define IPG_ETHERSTATSDROPEVENTS 0xCE
-
-/* Serial EEPROM offsets */
-#define IPG_EEPROM_CONFIGPARAM 0x00
-#define IPG_EEPROM_ASICCTRL 0x01
-#define IPG_EEPROM_SUBSYSTEMVENDORID 0x02
-#define IPG_EEPROM_SUBSYSTEMID 0x03
-#define IPG_EEPROM_STATIONADDRESS0 0x10
-#define IPG_EEPROM_STATIONADDRESS1 0x11
-#define IPG_EEPROM_STATIONADDRESS2 0x12
-
-/* Register & data structure bit masks */
-
-/* PCI register masks. */
-
-/* IOBaseAddress */
-#define IPG_PIB_RSVD_MASK 0xFFFFFE01
-#define IPG_PIB_IOBASEADDRESS 0xFFFFFF00
-#define IPG_PIB_IOBASEADDRIND 0x00000001
-
-/* MemBaseAddress */
-#define IPG_PMB_RSVD_MASK 0xFFFFFE07
-#define IPG_PMB_MEMBASEADDRIND 0x00000001
-#define IPG_PMB_MEMMAPTYPE 0x00000006
-#define IPG_PMB_MEMMAPTYPE0 0x00000002
-#define IPG_PMB_MEMMAPTYPE1 0x00000004
-#define IPG_PMB_MEMBASEADDRESS 0xFFFFFE00
-
-/* ConfigStatus */
-#define IPG_CS_RSVD_MASK 0xFFB0
-#define IPG_CS_CAPABILITIES 0x0010
-#define IPG_CS_66MHZCAPABLE 0x0020
-#define IPG_CS_FASTBACK2BACK 0x0080
-#define IPG_CS_DATAPARITYREPORTED 0x0100
-#define IPG_CS_DEVSELTIMING 0x0600
-#define IPG_CS_SIGNALEDTARGETABORT 0x0800
-#define IPG_CS_RECEIVEDTARGETABORT 0x1000
-#define IPG_CS_RECEIVEDMASTERABORT 0x2000
-#define IPG_CS_SIGNALEDSYSTEMERROR 0x4000
-#define IPG_CS_DETECTEDPARITYERROR 0x8000
-
-/* TFD data structure masks. */
-
-/* TFDList, TFC */
-#define IPG_TFC_RSVD_MASK 0x0000FFFF9FFFFFFFULL
-#define IPG_TFC_FRAMEID 0x000000000000FFFFULL
-#define IPG_TFC_WORDALIGN 0x0000000000030000ULL
-#define IPG_TFC_WORDALIGNTODWORD 0x0000000000000000ULL
-#define IPG_TFC_WORDALIGNTOWORD 0x0000000000020000ULL
-#define IPG_TFC_WORDALIGNDISABLED 0x0000000000030000ULL
-#define IPG_TFC_TCPCHECKSUMENABLE 0x0000000000040000ULL
-#define IPG_TFC_UDPCHECKSUMENABLE 0x0000000000080000ULL
-#define IPG_TFC_IPCHECKSUMENABLE 0x0000000000100000ULL
-#define IPG_TFC_FCSAPPENDDISABLE 0x0000000000200000ULL
-#define IPG_TFC_TXINDICATE 0x0000000000400000ULL
-#define IPG_TFC_TXDMAINDICATE 0x0000000000800000ULL
-#define IPG_TFC_FRAGCOUNT 0x000000000F000000ULL
-#define IPG_TFC_VLANTAGINSERT 0x0000000010000000ULL
-#define IPG_TFC_TFDDONE 0x0000000080000000ULL
-#define IPG_TFC_VID 0x00000FFF00000000ULL
-#define IPG_TFC_CFI 0x0000100000000000ULL
-#define IPG_TFC_USERPRIORITY 0x0000E00000000000ULL
-
-/* TFDList, FragInfo */
-#define IPG_TFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL
-#define IPG_TFI_FRAGADDR 0x000000FFFFFFFFFFULL
-#define IPG_TFI_FRAGLEN 0xFFFF000000000000ULL
-
-/* RFD data structure masks. */
-
-/* RFDList, RFS */
-#define IPG_RFS_RSVD_MASK 0x0000FFFFFFFFFFFFULL
-#define IPG_RFS_RXFRAMELEN 0x000000000000FFFFULL
-#define IPG_RFS_RXFIFOOVERRUN 0x0000000000010000ULL
-#define IPG_RFS_RXRUNTFRAME 0x0000000000020000ULL
-#define IPG_RFS_RXALIGNMENTERROR 0x0000000000040000ULL
-#define IPG_RFS_RXFCSERROR 0x0000000000080000ULL
-#define IPG_RFS_RXOVERSIZEDFRAME 0x0000000000100000ULL
-#define IPG_RFS_RXLENGTHERROR 0x0000000000200000ULL
-#define IPG_RFS_VLANDETECTED 0x0000000000400000ULL
-#define IPG_RFS_TCPDETECTED 0x0000000000800000ULL
-#define IPG_RFS_TCPERROR 0x0000000001000000ULL
-#define IPG_RFS_UDPDETECTED 0x0000000002000000ULL
-#define IPG_RFS_UDPERROR 0x0000000004000000ULL
-#define IPG_RFS_IPDETECTED 0x0000000008000000ULL
-#define IPG_RFS_IPERROR 0x0000000010000000ULL
-#define IPG_RFS_FRAMESTART 0x0000000020000000ULL
-#define IPG_RFS_FRAMEEND 0x0000000040000000ULL
-#define IPG_RFS_RFDDONE 0x0000000080000000ULL
-#define IPG_RFS_TCI 0x0000FFFF00000000ULL
-
-/* RFDList, FragInfo */
-#define IPG_RFI_RSVD_MASK 0xFFFF00FFFFFFFFFFULL
-#define IPG_RFI_FRAGADDR 0x000000FFFFFFFFFFULL
-#define IPG_RFI_FRAGLEN 0xFFFF000000000000ULL
-
-/* I/O Register masks. */
-
-/* RMON Statistics Mask */
-#define IPG_RZ_ALL 0x0FFFFFFF
-
-/* Statistics Mask */
-#define IPG_SM_ALL 0x0FFFFFFF
-#define IPG_SM_OCTETRCVOK_FRAMESRCVDOK 0x00000001
-#define IPG_SM_MCSTOCTETRCVDOK_MCSTFRAMESRCVDOK 0x00000002
-#define IPG_SM_BCSTOCTETRCVDOK_BCSTFRAMESRCVDOK 0x00000004
-#define IPG_SM_RXJUMBOFRAMES 0x00000008
-#define IPG_SM_TCPCHECKSUMERRORS 0x00000010
-#define IPG_SM_IPCHECKSUMERRORS 0x00000020
-#define IPG_SM_UDPCHECKSUMERRORS 0x00000040
-#define IPG_SM_MACCONTROLFRAMESRCVD 0x00000080
-#define IPG_SM_FRAMESTOOLONGERRORS 0x00000100
-#define IPG_SM_INRANGELENGTHERRORS 0x00000200
-#define IPG_SM_FRAMECHECKSEQERRORS 0x00000400
-#define IPG_SM_FRAMESLOSTRXERRORS 0x00000800
-#define IPG_SM_OCTETXMTOK_FRAMESXMTOK 0x00001000
-#define IPG_SM_MCSTOCTETXMTOK_MCSTFRAMESXMTDOK 0x00002000
-#define IPG_SM_BCSTOCTETXMTOK_BCSTFRAMESXMTDOK 0x00004000
-#define IPG_SM_FRAMESWDEFERREDXMT 0x00008000
-#define IPG_SM_LATECOLLISIONS 0x00010000
-#define IPG_SM_MULTICOLFRAMES 0x00020000
-#define IPG_SM_SINGLECOLFRAMES 0x00040000
-#define IPG_SM_TXJUMBOFRAMES 0x00080000
-#define IPG_SM_CARRIERSENSEERRORS 0x00100000
-#define IPG_SM_MACCONTROLFRAMESXMTD 0x00200000
-#define IPG_SM_FRAMESABORTXSCOLLS 0x00400000
-#define IPG_SM_FRAMESWEXDEFERAL 0x00800000
-
-/* Countdown */
-#define IPG_CD_RSVD_MASK 0x0700FFFF
-#define IPG_CD_COUNT 0x0000FFFF
-#define IPG_CD_COUNTDOWNSPEED 0x01000000
-#define IPG_CD_COUNTDOWNMODE 0x02000000
-#define IPG_CD_COUNTINTENABLED 0x04000000
-
-/* TxDMABurstThresh */
-#define IPG_TB_RSVD_MASK 0xFF
-
-/* TxDMAUrgentThresh */
-#define IPG_TU_RSVD_MASK 0xFF
-
-/* TxDMAPollPeriod */
-#define IPG_TP_RSVD_MASK 0xFF
-
-/* RxDMAUrgentThresh */
-#define IPG_RU_RSVD_MASK 0xFF
-
-/* RxDMAPollPeriod */
-#define IPG_RP_RSVD_MASK 0xFF
-
-/* ReceiveMode */
-#define IPG_RM_RSVD_MASK 0x3F
-#define IPG_RM_RECEIVEUNICAST 0x01
-#define IPG_RM_RECEIVEMULTICAST 0x02
-#define IPG_RM_RECEIVEBROADCAST 0x04
-#define IPG_RM_RECEIVEALLFRAMES 0x08
-#define IPG_RM_RECEIVEMULTICASTHASH 0x10
-#define IPG_RM_RECEIVEIPMULTICAST 0x20
-
-/* PhySet */
-#define IPG_PS_MEM_LENB9B 0x01
-#define IPG_PS_MEM_LEN9 0x02
-#define IPG_PS_NON_COMPDET 0x04
-
-/* PhyCtrl */
-#define IPG_PC_RSVD_MASK 0xFF
-#define IPG_PC_MGMTCLK_LO 0x00
-#define IPG_PC_MGMTCLK_HI 0x01
-#define IPG_PC_MGMTCLK 0x01
-#define IPG_PC_MGMTDATA 0x02
-#define IPG_PC_MGMTDIR 0x04
-#define IPG_PC_DUPLEX_POLARITY 0x08
-#define IPG_PC_DUPLEX_STATUS 0x10
-#define IPG_PC_LINK_POLARITY 0x20
-#define IPG_PC_LINK_SPEED 0xC0
-#define IPG_PC_LINK_SPEED_10MBPS 0x40
-#define IPG_PC_LINK_SPEED_100MBPS 0x80
-#define IPG_PC_LINK_SPEED_1000MBPS 0xC0
-
-/* DMACtrl */
-#define IPG_DC_RSVD_MASK 0xC07D9818
-#define IPG_DC_RX_DMA_COMPLETE 0x00000008
-#define IPG_DC_RX_DMA_POLL_NOW 0x00000010
-#define IPG_DC_TX_DMA_COMPLETE 0x00000800
-#define IPG_DC_TX_DMA_POLL_NOW 0x00001000
-#define IPG_DC_TX_DMA_IN_PROG 0x00008000
-#define IPG_DC_RX_EARLY_DISABLE 0x00010000
-#define IPG_DC_MWI_DISABLE 0x00040000
-#define IPG_DC_TX_WRITE_BACK_DISABLE 0x00080000
-#define IPG_DC_TX_BURST_LIMIT 0x00700000
-#define IPG_DC_TARGET_ABORT 0x40000000
-#define IPG_DC_MASTER_ABORT 0x80000000
-
-/* ASICCtrl */
-#define IPG_AC_RSVD_MASK 0x07FFEFF2
-#define IPG_AC_EXP_ROM_SIZE 0x00000002
-#define IPG_AC_PHY_SPEED10 0x00000010
-#define IPG_AC_PHY_SPEED100 0x00000020
-#define IPG_AC_PHY_SPEED1000 0x00000040
-#define IPG_AC_PHY_MEDIA 0x00000080
-#define IPG_AC_FORCED_CFG 0x00000700
-#define IPG_AC_D3RESETDISABLE 0x00000800
-#define IPG_AC_SPEED_UP_MODE 0x00002000
-#define IPG_AC_LED_MODE 0x00004000
-#define IPG_AC_RST_OUT_POLARITY 0x00008000
-#define IPG_AC_GLOBAL_RESET 0x00010000
-#define IPG_AC_RX_RESET 0x00020000
-#define IPG_AC_TX_RESET 0x00040000
-#define IPG_AC_DMA 0x00080000
-#define IPG_AC_FIFO 0x00100000
-#define IPG_AC_NETWORK 0x00200000
-#define IPG_AC_HOST 0x00400000
-#define IPG_AC_AUTO_INIT 0x00800000
-#define IPG_AC_RST_OUT 0x01000000
-#define IPG_AC_INT_REQUEST 0x02000000
-#define IPG_AC_RESET_BUSY 0x04000000
-#define IPG_AC_LED_SPEED 0x08000000
-#define IPG_AC_LED_MODE_BIT_1 0x20000000
-
-/* EepromCtrl */
-#define IPG_EC_RSVD_MASK 0x83FF
-#define IPG_EC_EEPROM_ADDR 0x00FF
-#define IPG_EC_EEPROM_OPCODE 0x0300
-#define IPG_EC_EEPROM_SUBCOMMAD 0x0000
-#define IPG_EC_EEPROM_WRITEOPCODE 0x0100
-#define IPG_EC_EEPROM_READOPCODE 0x0200
-#define IPG_EC_EEPROM_ERASEOPCODE 0x0300
-#define IPG_EC_EEPROM_BUSY 0x8000
-
-/* FIFOCtrl */
-#define IPG_FC_RSVD_MASK 0xC001
-#define IPG_FC_RAM_TEST_MODE 0x0001
-#define IPG_FC_TRANSMITTING 0x4000
-#define IPG_FC_RECEIVING 0x8000
-
-/* TxStatus */
-#define IPG_TS_RSVD_MASK 0xFFFF00DD
-#define IPG_TS_TX_ERROR 0x00000001
-#define IPG_TS_LATE_COLLISION 0x00000004
-#define IPG_TS_TX_MAX_COLL 0x00000008
-#define IPG_TS_TX_UNDERRUN 0x00000010
-#define IPG_TS_TX_IND_REQD 0x00000040
-#define IPG_TS_TX_COMPLETE 0x00000080
-#define IPG_TS_TX_FRAMEID 0xFFFF0000
-
-/* WakeEvent */
-#define IPG_WE_WAKE_PKT_ENABLE 0x01
-#define IPG_WE_MAGIC_PKT_ENABLE 0x02
-#define IPG_WE_LINK_EVT_ENABLE 0x04
-#define IPG_WE_WAKE_POLARITY 0x08
-#define IPG_WE_WAKE_PKT_EVT 0x10
-#define IPG_WE_MAGIC_PKT_EVT 0x20
-#define IPG_WE_LINK_EVT 0x40
-#define IPG_WE_WOL_ENABLE 0x80
-
-/* IntEnable */
-#define IPG_IE_RSVD_MASK 0x1FFE
-#define IPG_IE_HOST_ERROR 0x0002
-#define IPG_IE_TX_COMPLETE 0x0004
-#define IPG_IE_MAC_CTRL_FRAME 0x0008
-#define IPG_IE_RX_COMPLETE 0x0010
-#define IPG_IE_RX_EARLY 0x0020
-#define IPG_IE_INT_REQUESTED 0x0040
-#define IPG_IE_UPDATE_STATS 0x0080
-#define IPG_IE_LINK_EVENT 0x0100
-#define IPG_IE_TX_DMA_COMPLETE 0x0200
-#define IPG_IE_RX_DMA_COMPLETE 0x0400
-#define IPG_IE_RFD_LIST_END 0x0800
-#define IPG_IE_RX_DMA_PRIORITY 0x1000
-
-/* IntStatus */
-#define IPG_IS_RSVD_MASK 0x1FFF
-#define IPG_IS_INTERRUPT_STATUS 0x0001
-#define IPG_IS_HOST_ERROR 0x0002
-#define IPG_IS_TX_COMPLETE 0x0004
-#define IPG_IS_MAC_CTRL_FRAME 0x0008
-#define IPG_IS_RX_COMPLETE 0x0010
-#define IPG_IS_RX_EARLY 0x0020
-#define IPG_IS_INT_REQUESTED 0x0040
-#define IPG_IS_UPDATE_STATS 0x0080
-#define IPG_IS_LINK_EVENT 0x0100
-#define IPG_IS_TX_DMA_COMPLETE 0x0200
-#define IPG_IS_RX_DMA_COMPLETE 0x0400
-#define IPG_IS_RFD_LIST_END 0x0800
-#define IPG_IS_RX_DMA_PRIORITY 0x1000
-
-/* MACCtrl */
-#define IPG_MC_RSVD_MASK 0x7FE33FA3
-#define IPG_MC_IFS_SELECT 0x00000003
-#define IPG_MC_IFS_4352BIT 0x00000003
-#define IPG_MC_IFS_1792BIT 0x00000002
-#define IPG_MC_IFS_1024BIT 0x00000001
-#define IPG_MC_IFS_96BIT 0x00000000
-#define IPG_MC_DUPLEX_SELECT 0x00000020
-#define IPG_MC_DUPLEX_SELECT_FD 0x00000020
-#define IPG_MC_DUPLEX_SELECT_HD 0x00000000
-#define IPG_MC_TX_FLOW_CONTROL_ENABLE 0x00000080
-#define IPG_MC_RX_FLOW_CONTROL_ENABLE 0x00000100
-#define IPG_MC_RCV_FCS 0x00000200
-#define IPG_MC_FIFO_LOOPBACK 0x00000400
-#define IPG_MC_MAC_LOOPBACK 0x00000800
-#define IPG_MC_AUTO_VLAN_TAGGING 0x00001000
-#define IPG_MC_AUTO_VLAN_UNTAGGING 0x00002000
-#define IPG_MC_COLLISION_DETECT 0x00010000
-#define IPG_MC_CARRIER_SENSE 0x00020000
-#define IPG_MC_STATISTICS_ENABLE 0x00200000
-#define IPG_MC_STATISTICS_DISABLE 0x00400000
-#define IPG_MC_STATISTICS_ENABLED 0x00800000
-#define IPG_MC_TX_ENABLE 0x01000000
-#define IPG_MC_TX_DISABLE 0x02000000
-#define IPG_MC_TX_ENABLED 0x04000000
-#define IPG_MC_RX_ENABLE 0x08000000
-#define IPG_MC_RX_DISABLE 0x10000000
-#define IPG_MC_RX_ENABLED 0x20000000
-#define IPG_MC_PAUSED 0x40000000
-
-/*
- * Tune
- */
-
-/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS append on TX. */
-#define IPG_APPEND_FCS_ON_TX 1
-
-/* Assign IPG_APPEND_FCS_ON_TX > 0 for auto FCS strip on RX. */
-#define IPG_STRIP_FCS_ON_RX 1
-
-/* Assign IPG_DROP_ON_RX_ETH_ERRORS > 0 to drop RX frames with
- * Ethernet errors.
- */
-#define IPG_DROP_ON_RX_ETH_ERRORS 1
-
-/* Assign IPG_INSERT_MANUAL_VLAN_TAG > 0 to insert VLAN tags manually
- * (via TFC).
- */
-#define IPG_INSERT_MANUAL_VLAN_TAG 0
-
-/* Assign IPG_ADD_IPCHECKSUM_ON_TX > 0 for auto IP checksum on TX. */
-#define IPG_ADD_IPCHECKSUM_ON_TX 0
-
-/* Assign IPG_ADD_TCPCHECKSUM_ON_TX > 0 for auto TCP checksum on TX.
- * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
- */
-#define IPG_ADD_TCPCHECKSUM_ON_TX 0
-
-/* Assign IPG_ADD_UDPCHECKSUM_ON_TX > 0 for auto UDP checksum on TX.
- * DO NOT USE FOR SILICON REVISIONS B3 AND EARLIER.
- */
-#define IPG_ADD_UDPCHECKSUM_ON_TX 0
-
-/* If inserting VLAN tags manually, assign the IPG_MANUAL_VLAN_xx
- * constants as desired.
- */
-#define IPG_MANUAL_VLAN_VID 0xABC
-#define IPG_MANUAL_VLAN_CFI 0x1
-#define IPG_MANUAL_VLAN_USERPRIORITY 0x5
-
-#define IPG_IO_REG_RANGE 0xFF
-#define IPG_MEM_REG_RANGE 0x154
-#define IPG_DRIVER_NAME "Sundance Technology IPG Triple-Speed Ethernet"
-#define IPG_NIC_PHY_ADDRESS 0x01
-#define IPG_DMALIST_ALIGN_PAD 0x07
-#define IPG_MULTICAST_HASHTABLE_SIZE 0x40
-
-/* Number of milliseconds to wait after issuing a software reset.
- * 0x05 <= IPG_AC_RESETWAIT to account for proper 10Mbps operation.
- */
-#define IPG_AC_RESETWAIT 0x05
-
-/* Number of IPG_AC_RESETWAIT timeperiods before declaring timeout. */
-#define IPG_AC_RESET_TIMEOUT 0x0A
-
-/* Minimum number of nanoseconds used to toggle MDC clock during
- * MII/GMII register access.
- */
-#define IPG_PC_PHYCTRLWAIT_NS 200
-
-#define IPG_TFDLIST_LENGTH 0x100
-
-/* Number of frames between TxDMAComplete interrupt.
- * 0 < IPG_FRAMESBETWEENTXDMACOMPLETES <= IPG_TFDLIST_LENGTH
- */
-#define IPG_FRAMESBETWEENTXDMACOMPLETES 0x1
-
-#define IPG_RFDLIST_LENGTH 0x100
-
-/* Maximum number of RFDs to process per interrupt.
- * 1 < IPG_MAXRFDPROCESS_COUNT < IPG_RFDLIST_LENGTH
- */
-#define IPG_MAXRFDPROCESS_COUNT 0x80
-
-/* Minimum margin between last freed RFD, and current RFD.
- * 1 < IPG_MINUSEDRFDSTOFREE < IPG_RFDLIST_LENGTH
- */
-#define IPG_MINUSEDRFDSTOFREE 0x80
-
-/* specify the jumbo frame maximum size
- * per unit is 0x600 (the rx_buffer size that one RFD can carry)
- */
-#define MAX_JUMBOSIZE 0x8 /* max is 12K */
-
-/* Key register values loaded at driver start up. */
-
-/* TXDMAPollPeriod is specified in 320ns increments.
- *
- * Value Time
- * ---------------------
- * 0x00-0x01 320ns
- * 0x03 ~1us
- * 0x1F ~10us
- * 0xFF ~82us
- */
-#define IPG_TXDMAPOLLPERIOD_VALUE 0x26
-
-/* TxDMAUrgentThresh specifies the minimum amount of
- * data in the transmit FIFO before asserting an
- * urgent transmit DMA request.
- *
- * Value Min TxFIFO occupied space before urgent TX request
- * ---------------------------------------------------------------
- * 0x00-0x04 128 bytes (1024 bits)
- * 0x27 1248 bytes (~10000 bits)
- * 0x30 1536 bytes (12288 bits)
- * 0xFF 8192 bytes (65535 bits)
- */
-#define IPG_TXDMAURGENTTHRESH_VALUE 0x04
-
-/* TxDMABurstThresh specifies the minimum amount of
- * free space in the transmit FIFO before asserting an
- * transmit DMA request.
- *
- * Value Min TxFIFO free space before TX request
- * ----------------------------------------------------
- * 0x00-0x08 256 bytes
- * 0x30 1536 bytes
- * 0xFF 8192 bytes
- */
-#define IPG_TXDMABURSTTHRESH_VALUE 0x30
-
-/* RXDMAPollPeriod is specified in 320ns increments.
- *
- * Value Time
- * ---------------------
- * 0x00-0x01 320ns
- * 0x03 ~1us
- * 0x1F ~10us
- * 0xFF ~82us
- */
-#define IPG_RXDMAPOLLPERIOD_VALUE 0x01
-
-/* RxDMAUrgentThresh specifies the minimum amount of
- * free space within the receive FIFO before asserting
- * a urgent receive DMA request.
- *
- * Value Min RxFIFO free space before urgent RX request
- * ---------------------------------------------------------------
- * 0x00-0x04 128 bytes (1024 bits)
- * 0x27 1248 bytes (~10000 bits)
- * 0x30 1536 bytes (12288 bits)
- * 0xFF 8192 bytes (65535 bits)
- */
-#define IPG_RXDMAURGENTTHRESH_VALUE 0x30
-
-/* RxDMABurstThresh specifies the minimum amount of
- * occupied space within the receive FIFO before asserting
- * a receive DMA request.
- *
- * Value Min TxFIFO free space before TX request
- * ----------------------------------------------------
- * 0x00-0x08 256 bytes
- * 0x30 1536 bytes
- * 0xFF 8192 bytes
- */
-#define IPG_RXDMABURSTTHRESH_VALUE 0x30
-
-/* FlowOnThresh specifies the maximum amount of occupied
- * space in the receive FIFO before a PAUSE frame with
- * maximum pause time transmitted.
- *
- * Value Max RxFIFO occupied space before PAUSE
- * ---------------------------------------------------
- * 0x0000 0 bytes
- * 0x0740 29,696 bytes
- * 0x07FF 32,752 bytes
- */
-#define IPG_FLOWONTHRESH_VALUE 0x0740
-
-/* FlowOffThresh specifies the minimum amount of occupied
- * space in the receive FIFO before a PAUSE frame with
- * zero pause time is transmitted.
- *
- * Value Max RxFIFO occupied space before PAUSE
- * ---------------------------------------------------
- * 0x0000 0 bytes
- * 0x00BF 3056 bytes
- * 0x07FF 32,752 bytes
- */
-#define IPG_FLOWOFFTHRESH_VALUE 0x00BF
-
-/*
- * Miscellaneous macros.
- */
-
-/* Macros for printing debug statements. */
-#ifdef IPG_DEBUG
-# define IPG_DEBUG_MSG(fmt, args...) \
-do { \
- if (0) \
- printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-# define IPG_DDEBUG_MSG(fmt, args...) \
- printk(KERN_DEBUG "IPG: " fmt, ##args)
-# define IPG_DUMPRFDLIST(args) ipg_dump_rfdlist(args)
-# define IPG_DUMPTFDLIST(args) ipg_dump_tfdlist(args)
-#else
-# define IPG_DEBUG_MSG(fmt, args...) \
-do { \
- if (0) \
- printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-# define IPG_DDEBUG_MSG(fmt, args...) \
-do { \
- if (0) \
- printk(KERN_DEBUG "IPG: " fmt, ##args); \
-} while (0)
-# define IPG_DUMPRFDLIST(args)
-# define IPG_DUMPTFDLIST(args)
-#endif
-
-/*
- * End miscellaneous macros.
- */
-
-/* Transmit Frame Descriptor. The IPG supports 15 fragments,
- * however Linux requires only a single fragment. Note, each
- * TFD field is 64 bits wide.
- */
-struct ipg_tx {
- __le64 next_desc;
- __le64 tfc;
- __le64 frag_info;
-};
-
-/* Receive Frame Descriptor. Note, each RFD field is 64 bits wide.
- */
-struct ipg_rx {
- __le64 next_desc;
- __le64 rfs;
- __le64 frag_info;
-};
-
-struct ipg_jumbo {
- int found_start;
- int current_size;
- struct sk_buff *skb;
-};
-
-/* Structure of IPG NIC specific data. */
-struct ipg_nic_private {
- void __iomem *ioaddr;
- struct ipg_tx *txd;
- struct ipg_rx *rxd;
- dma_addr_t txd_map;
- dma_addr_t rxd_map;
- struct sk_buff *tx_buff[IPG_TFDLIST_LENGTH];
- struct sk_buff *rx_buff[IPG_RFDLIST_LENGTH];
- unsigned int tx_current;
- unsigned int tx_dirty;
- unsigned int rx_current;
- unsigned int rx_dirty;
- bool is_jumbo;
- struct ipg_jumbo jumbo;
- unsigned long rxfrag_size;
- unsigned long rxsupport_size;
- unsigned long max_rxframe_size;
- unsigned int rx_buf_sz;
- struct pci_dev *pdev;
- struct net_device *dev;
- struct net_device_stats stats;
- spinlock_t lock;
- int tenmbpsmode;
-
- u16 led_mode;
- u16 station_addr[3]; /* Station Address in EEPROM Reg 0x10..0x12 */
-
- struct mutex mii_mutex;
- struct mii_if_info mii_if;
- int reset_current_tfd;
-#ifdef IPG_DEBUG
- int RFDlistendCount;
- int RFDListCheckedCount;
- int EmptyRFDListCount;
-#endif
- struct delayed_work task;
-};
-
-#endif /* __LINUX_IPG_H */
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
index 639263d..7781e80 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
@@ -627,8 +627,10 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev)
/* verify the skb head is not shared */
err = skb_cow_head(skb, 0);
- if (err)
+ if (err) {
+ dev_kfree_skb(skb);
return NETDEV_TX_OK;
+ }
/* locate vlan header */
vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
index 0ff8f01..1fd5ea8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c
@@ -567,10 +567,6 @@ i40e_status i40e_init_adminq(struct i40e_hw *hw)
goto init_adminq_exit;
}
- /* initialize locks */
- mutex_init(&hw->aq.asq_mutex);
- mutex_init(&hw->aq.arq_mutex);
-
/* Set up register offsets */
i40e_adminq_init_regs(hw);
@@ -664,8 +660,6 @@ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw)
i40e_shutdown_asq(hw);
i40e_shutdown_arq(hw);
- /* destroy the locks */
-
if (hw->nvm_buff.va)
i40e_free_virt_mem(hw, &hw->nvm_buff);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index b825f97..4a9873ec 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -10295,6 +10295,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* set up a default setting for link flow control */
pf->hw.fc.requested_mode = I40E_FC_NONE;
+ /* set up the locks for the AQ, do this only once in probe
+ * and destroy them only once in remove
+ */
+ mutex_init(&hw->aq.asq_mutex);
+ mutex_init(&hw->aq.arq_mutex);
+
err = i40e_init_adminq(hw);
/* provide nvm, fw, api versions */
@@ -10697,7 +10703,6 @@ static void i40e_remove(struct pci_dev *pdev)
set_bit(__I40E_DOWN, &pf->state);
del_timer_sync(&pf->service_timer);
cancel_work_sync(&pf->service_task);
- i40e_fdir_teardown(pf);
if (pf->flags & I40E_FLAG_SRIOV_ENABLED) {
i40e_free_vfs(pf);
@@ -10740,6 +10745,10 @@ static void i40e_remove(struct pci_dev *pdev)
"Failed to destroy the Admin Queue resources: %d\n",
ret_code);
+ /* destroy the locks only once, here */
+ mutex_destroy(&hw->aq.arq_mutex);
+ mutex_destroy(&hw->aq.asq_mutex);
+
/* Clear all dynamic memory lists of rings, q_vectors, and VSIs */
i40e_clear_interrupt_scheme(pf);
for (i = 0; i < pf->num_alloc_vsi; i++) {
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
index fd123ca..3f65e39 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c
@@ -551,10 +551,6 @@ i40e_status i40evf_init_adminq(struct i40e_hw *hw)
goto init_adminq_exit;
}
- /* initialize locks */
- mutex_init(&hw->aq.asq_mutex);
- mutex_init(&hw->aq.arq_mutex);
-
/* Set up register offsets */
i40e_adminq_init_regs(hw);
@@ -596,8 +592,6 @@ i40e_status i40evf_shutdown_adminq(struct i40e_hw *hw)
i40e_shutdown_asq(hw);
i40e_shutdown_arq(hw);
- /* destroy the locks */
-
if (hw->nvm_buff.va)
i40e_free_virt_mem(hw, &hw->nvm_buff);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index d962164..99d2cff 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -2476,6 +2476,12 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->bus.device = PCI_SLOT(pdev->devfn);
hw->bus.func = PCI_FUNC(pdev->devfn);
+ /* set up the locks for the AQ, do this only once in probe
+ * and destroy them only once in remove
+ */
+ mutex_init(&hw->aq.asq_mutex);
+ mutex_init(&hw->aq.arq_mutex);
+
INIT_LIST_HEAD(&adapter->mac_filter_list);
INIT_LIST_HEAD(&adapter->vlan_filter_list);
@@ -2629,6 +2635,10 @@ static void i40evf_remove(struct pci_dev *pdev)
if (hw->aq.asq.count)
i40evf_shutdown_adminq(hw);
+ /* destroy the locks only once, here */
+ mutex_destroy(&hw->aq.arq_mutex);
+ mutex_destroy(&hw->aq.asq_mutex);
+
iounmap(hw->hw_addr);
pci_release_regions(pdev);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 47395ff..aed8d02 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -7920,6 +7920,9 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc)
*/
if (netif_running(dev))
ixgbe_close(dev);
+ else
+ ixgbe_reset(adapter);
+
ixgbe_clear_interrupt_scheme(adapter);
#ifdef CONFIG_IXGBE_DCB
diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig
index 80af9ff..a1c862b 100644
--- a/drivers/net/ethernet/marvell/Kconfig
+++ b/drivers/net/ethernet/marvell/Kconfig
@@ -44,6 +44,7 @@ config MVNETA
tristate "Marvell Armada 370/38x/XP network interface support"
depends on PLAT_ORION
select MVMDIO
+ select FIXED_PHY
---help---
This driver supports the network interface units in the
Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family.
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index a47496a..ed622fa 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -36,7 +36,7 @@
/* Registers */
#define MVNETA_RXQ_CONFIG_REG(q) (0x1400 + ((q) << 2))
-#define MVNETA_RXQ_HW_BUF_ALLOC BIT(1)
+#define MVNETA_RXQ_HW_BUF_ALLOC BIT(0)
#define MVNETA_RXQ_PKT_OFFSET_ALL_MASK (0xf << 8)
#define MVNETA_RXQ_PKT_OFFSET_MASK(offs) ((offs) << 8)
#define MVNETA_RXQ_THRESHOLD_REG(q) (0x14c0 + ((q) << 2))
@@ -62,6 +62,7 @@
#define MVNETA_WIN_SIZE(w) (0x2204 + ((w) << 3))
#define MVNETA_WIN_REMAP(w) (0x2280 + ((w) << 2))
#define MVNETA_BASE_ADDR_ENABLE 0x2290
+#define MVNETA_ACCESS_PROTECT_ENABLE 0x2294
#define MVNETA_PORT_CONFIG 0x2400
#define MVNETA_UNI_PROMISC_MODE BIT(0)
#define MVNETA_DEF_RXQ(q) ((q) << 1)
@@ -159,7 +160,7 @@
#define MVNETA_INTR_ENABLE 0x25b8
#define MVNETA_TXQ_INTR_ENABLE_ALL_MASK 0x0000ff00
-#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0xff000000 // note: neta says it's 0x000000FF
+#define MVNETA_RXQ_INTR_ENABLE_ALL_MASK 0x000000ff
#define MVNETA_RXQ_CMD 0x2680
#define MVNETA_RXQ_DISABLE_SHIFT 8
@@ -242,6 +243,7 @@
#define MVNETA_VLAN_TAG_LEN 4
#define MVNETA_CPU_D_CACHE_LINE_SIZE 32
+#define MVNETA_TX_CSUM_DEF_SIZE 1600
#define MVNETA_TX_CSUM_MAX_SIZE 9800
#define MVNETA_ACC_MODE_EXT 1
@@ -1493,9 +1495,9 @@ static void mvneta_rxq_drop_pkts(struct mvneta_port *pp,
struct mvneta_rx_desc *rx_desc = rxq->descs + i;
void *data = (void *)rx_desc->buf_cookie;
- mvneta_frag_free(pp, data);
dma_unmap_single(pp->dev->dev.parent, rx_desc->buf_phys_addr,
MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
+ mvneta_frag_free(pp, data);
}
if (rx_done)
@@ -1579,12 +1581,16 @@ static int mvneta_rx(struct mvneta_port *pp, int rx_todo,
}
skb = build_skb(data, pp->frag_size > PAGE_SIZE ? 0 : pp->frag_size);
- if (!skb)
- goto err_drop_frame;
+ /* After refill old buffer has to be unmapped regardless
+ * the skb is successfully built or not.
+ */
dma_unmap_single(dev->dev.parent, phys_addr,
MVNETA_RX_BUF_SIZE(pp->pkt_size), DMA_FROM_DEVICE);
+ if (!skb)
+ goto err_drop_frame;
+
rcvd_pkts++;
rcvd_bytes += rx_bytes;
@@ -3191,6 +3197,7 @@ static void mvneta_conf_mbus_windows(struct mvneta_port *pp,
}
mvreg_write(pp, MVNETA_BASE_ADDR_ENABLE, win_enable);
+ mvreg_write(pp, MVNETA_ACCESS_PROTECT_ENABLE, win_protect);
}
/* Power up the port */
@@ -3250,6 +3257,7 @@ static int mvneta_probe(struct platform_device *pdev)
char hw_mac_addr[ETH_ALEN];
const char *mac_from;
const char *managed;
+ int tx_csum_limit;
int phy_mode;
int err;
int cpu;
@@ -3350,8 +3358,21 @@ static int mvneta_probe(struct platform_device *pdev)
}
}
- if (of_device_is_compatible(dn, "marvell,armada-370-neta"))
- pp->tx_csum_limit = 1600;
+ if (!of_property_read_u32(dn, "tx-csum-limit", &tx_csum_limit)) {
+ if (tx_csum_limit < 0 ||
+ tx_csum_limit > MVNETA_TX_CSUM_MAX_SIZE) {
+ tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE;
+ dev_info(&pdev->dev,
+ "Wrong TX csum limit in DT, set to %dB\n",
+ MVNETA_TX_CSUM_DEF_SIZE);
+ }
+ } else if (of_device_is_compatible(dn, "marvell,armada-370-neta")) {
+ tx_csum_limit = MVNETA_TX_CSUM_DEF_SIZE;
+ } else {
+ tx_csum_limit = MVNETA_TX_CSUM_MAX_SIZE;
+ }
+
+ pp->tx_csum_limit = tx_csum_limit;
pp->tx_ring_size = MVNETA_MAX_TXD;
pp->rx_ring_size = MVNETA_MAX_RXD;
diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index d9884fd..a4beccf 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -3413,16 +3413,23 @@ static void mvpp2_bm_pool_bufsize_set(struct mvpp2 *priv,
}
/* Free all buffers from the pool */
-static void mvpp2_bm_bufs_free(struct mvpp2 *priv, struct mvpp2_bm_pool *bm_pool)
+static void mvpp2_bm_bufs_free(struct device *dev, struct mvpp2 *priv,
+ struct mvpp2_bm_pool *bm_pool)
{
int i;
for (i = 0; i < bm_pool->buf_num; i++) {
+ dma_addr_t buf_phys_addr;
u32 vaddr;
/* Get buffer virtual address (indirect access) */
- mvpp2_read(priv, MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
+ buf_phys_addr = mvpp2_read(priv,
+ MVPP2_BM_PHY_ALLOC_REG(bm_pool->id));
vaddr = mvpp2_read(priv, MVPP2_BM_VIRT_ALLOC_REG);
+
+ dma_unmap_single(dev, buf_phys_addr,
+ bm_pool->buf_size, DMA_FROM_DEVICE);
+
if (!vaddr)
break;
dev_kfree_skb_any((struct sk_buff *)vaddr);
@@ -3439,7 +3446,7 @@ static int mvpp2_bm_pool_destroy(struct platform_device *pdev,
{
u32 val;
- mvpp2_bm_bufs_free(priv, bm_pool);
+ mvpp2_bm_bufs_free(&pdev->dev, priv, bm_pool);
if (bm_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", bm_pool->id);
return 0;
@@ -3692,7 +3699,8 @@ mvpp2_bm_pool_use(struct mvpp2_port *port, int pool, enum mvpp2_bm_type type,
MVPP2_BM_LONG_BUF_NUM :
MVPP2_BM_SHORT_BUF_NUM;
else
- mvpp2_bm_bufs_free(port->priv, new_pool);
+ mvpp2_bm_bufs_free(port->dev->dev.parent,
+ port->priv, new_pool);
new_pool->pkt_size = pkt_size;
@@ -3756,7 +3764,7 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
int pkt_size = MVPP2_RX_PKT_SIZE(mtu);
/* Update BM pool with new buffer size */
- mvpp2_bm_bufs_free(port->priv, port_pool);
+ mvpp2_bm_bufs_free(dev->dev.parent, port->priv, port_pool);
if (port_pool->buf_num) {
WARN(1, "cannot free all buffers in pool %d\n", port_pool->id);
return -EIO;
@@ -4401,11 +4409,10 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port,
mvpp2_txq_inc_get(txq_pcpu);
- if (!skb)
- continue;
-
dma_unmap_single(port->dev->dev.parent, buf_phys_addr,
skb_headlen(skb), DMA_TO_DEVICE);
+ if (!skb)
+ continue;
dev_kfree_skb_any(skb);
}
}
@@ -5092,7 +5099,8 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
struct mvpp2_rx_queue *rxq)
{
struct net_device *dev = port->dev;
- int rx_received, rx_filled, i;
+ int rx_received;
+ int rx_done = 0;
u32 rcvd_pkts = 0;
u32 rcvd_bytes = 0;
@@ -5101,17 +5109,18 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
if (rx_todo > rx_received)
rx_todo = rx_received;
- rx_filled = 0;
- for (i = 0; i < rx_todo; i++) {
+ while (rx_done < rx_todo) {
struct mvpp2_rx_desc *rx_desc = mvpp2_rxq_next_desc_get(rxq);
struct mvpp2_bm_pool *bm_pool;
struct sk_buff *skb;
+ dma_addr_t phys_addr;
u32 bm, rx_status;
int pool, rx_bytes, err;
- rx_filled++;
+ rx_done++;
rx_status = rx_desc->status;
rx_bytes = rx_desc->data_size - MVPP2_MH_SIZE;
+ phys_addr = rx_desc->buf_phys_addr;
bm = mvpp2_bm_cookie_build(rx_desc);
pool = mvpp2_bm_cookie_pool_get(bm);
@@ -5128,8 +5137,10 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
* comprised by the RX descriptor.
*/
if (rx_status & MVPP2_RXD_ERR_SUMMARY) {
+ err_drop_frame:
dev->stats.rx_errors++;
mvpp2_rx_error(port, rx_desc);
+ /* Return the buffer to the pool */
mvpp2_pool_refill(port, bm, rx_desc->buf_phys_addr,
rx_desc->buf_cookie);
continue;
@@ -5137,6 +5148,15 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
skb = (struct sk_buff *)rx_desc->buf_cookie;
+ err = mvpp2_rx_refill(port, bm_pool, bm, 0);
+ if (err) {
+ netdev_err(port->dev, "failed to refill BM pools\n");
+ goto err_drop_frame;
+ }
+
+ dma_unmap_single(dev->dev.parent, phys_addr,
+ bm_pool->buf_size, DMA_FROM_DEVICE);
+
rcvd_pkts++;
rcvd_bytes += rx_bytes;
atomic_inc(&bm_pool->in_use);
@@ -5147,12 +5167,6 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
mvpp2_rx_csum(port, rx_status, skb);
napi_gro_receive(&port->napi, skb);
-
- err = mvpp2_rx_refill(port, bm_pool, bm, 0);
- if (err) {
- netdev_err(port->dev, "failed to refill BM pools\n");
- rx_filled--;
- }
}
if (rcvd_pkts) {
@@ -5166,7 +5180,7 @@ static int mvpp2_rx(struct mvpp2_port *port, int rx_todo,
/* Update Rx queue management counters */
wmb();
- mvpp2_rxq_status_update(port, rxq->id, rx_todo, rx_filled);
+ mvpp2_rxq_status_update(port, rxq->id, rx_done, rx_done);
return rx_todo;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 2177e56..d48d579 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -1010,7 +1010,7 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
if (!(smp->mgmt_class == IB_MGMT_CLASS_SUBN_LID_ROUTED &&
smp->method == IB_MGMT_METHOD_GET) || network_view) {
mlx4_err(dev, "Unprivileged slave %d is trying to execute a Subnet MGMT MAD, class 0x%x, method 0x%x, view=%s for attr 0x%x. Rejecting\n",
- slave, smp->method, smp->mgmt_class,
+ slave, smp->mgmt_class, smp->method,
network_view ? "Network" : "Host",
be16_to_cpu(smp->attr_id));
return -EPERM;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index 8a083d7..038f9ce 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -242,6 +242,13 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
unsigned long flags;
u64 ns, zero = 0;
+ /* mlx4_en_init_timestamp is called for each netdev.
+ * mdev->ptp_clock is common for all ports, skip initialization if
+ * was done for other port.
+ */
+ if (mdev->ptp_clock)
+ return;
+
rwlock_init(&mdev->clock_lock);
memset(&mdev->cycles, 0, sizeof(mdev->cycles));
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 005f910..e0ec280 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -232,9 +232,6 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
if (mdev->pndev[i])
mlx4_en_destroy_netdev(mdev->pndev[i]);
- if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
- mlx4_en_remove_timestamp(mdev);
-
flush_workqueue(mdev->workqueue);
destroy_workqueue(mdev->workqueue);
(void) mlx4_mr_free(dev, &mdev->mr);
@@ -320,10 +317,6 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH)
mdev->port_cnt++;
- /* Initialize time stamp mechanism */
- if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
- mlx4_en_init_timestamp(mdev);
-
/* Set default number of RX rings*/
mlx4_en_set_num_rx_rings(mdev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 886e1bc..7869f97 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2072,6 +2072,9 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
/* flush any pending task for this netdev */
flush_workqueue(mdev->workqueue);
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+ mlx4_en_remove_timestamp(mdev);
+
/* Detach the netdev so tasks would not attempt to access it */
mutex_lock(&mdev->state_lock);
mdev->pndev[priv->port] = NULL;
@@ -3058,9 +3061,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+ /* Initialize time stamp mechanism */
if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
- queue_delayed_work(mdev->workqueue, &priv->service_task,
- SERVICE_TASK_DELAY);
+ mlx4_en_init_timestamp(mdev);
+
+ queue_delayed_work(mdev->workqueue, &priv->service_task,
+ SERVICE_TASK_DELAY);
mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap,
mdev->profile.prof[priv->port].rx_ppp,
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 85f1b1e..31c491e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -892,9 +892,10 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
dev->caps.qp1_proxy[i - 1] = func_cap.qp1_proxy_qpn;
dev->caps.port_mask[i] = dev->caps.port_type[i];
dev->caps.phys_port_id[i] = func_cap.phys_port_id;
- if (mlx4_get_slave_pkey_gid_tbl_len(dev, i,
- &dev->caps.gid_table_len[i],
- &dev->caps.pkey_table_len[i]))
+ err = mlx4_get_slave_pkey_gid_tbl_len(dev, i,
+ &dev->caps.gid_table_len[i],
+ &dev->caps.pkey_table_len[i]);
+ if (err)
goto err_mem;
}
@@ -906,6 +907,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
dev->caps.uar_page_size * dev->caps.num_uars,
(unsigned long long)
pci_resource_len(dev->persist->pdev, 2));
+ err = -ENOMEM;
goto err_mem;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 9813d34..cad6c44 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -4306,9 +4306,10 @@ int mlx4_QP_FLOW_STEERING_ATTACH_wrapper(struct mlx4_dev *dev, int slave,
return -EOPNOTSUPP;
ctrl = (struct mlx4_net_trans_rule_hw_ctrl *)inbox->buf;
- ctrl->port = mlx4_slave_convert_port(dev, slave, ctrl->port);
- if (ctrl->port <= 0)
+ err = mlx4_slave_convert_port(dev, slave, ctrl->port);
+ if (err <= 0)
return -EINVAL;
+ ctrl->port = err;
qpn = be32_to_cpu(ctrl->qpn) & 0xffffff;
err = get_res(dev, slave, qpn, RES_QP, &rqp);
if (err) {
@@ -4952,26 +4953,41 @@ static void rem_slave_counters(struct mlx4_dev *dev, int slave)
struct res_counter *counter;
struct res_counter *tmp;
int err;
- int index;
+ int *counters_arr = NULL;
+ int i, j;
err = move_all_busy(dev, slave, RES_COUNTER);
if (err)
mlx4_warn(dev, "rem_slave_counters: Could not move all counters - too busy for slave %d\n",
slave);
- spin_lock_irq(mlx4_tlock(dev));
- list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
- if (counter->com.owner == slave) {
- index = counter->com.res_id;
- rb_erase(&counter->com.node,
- &tracker->res_tree[RES_COUNTER]);
- list_del(&counter->com.list);
- kfree(counter);
- __mlx4_counter_free(dev, index);
+ counters_arr = kmalloc_array(dev->caps.max_counters,
+ sizeof(*counters_arr), GFP_KERNEL);
+ if (!counters_arr)
+ return;
+
+ do {
+ i = 0;
+ j = 0;
+ spin_lock_irq(mlx4_tlock(dev));
+ list_for_each_entry_safe(counter, tmp, counter_list, com.list) {
+ if (counter->com.owner == slave) {
+ counters_arr[i++] = counter->com.res_id;
+ rb_erase(&counter->com.node,
+ &tracker->res_tree[RES_COUNTER]);
+ list_del(&counter->com.list);
+ kfree(counter);
+ }
+ }
+ spin_unlock_irq(mlx4_tlock(dev));
+
+ while (j < i) {
+ __mlx4_counter_free(dev, counters_arr[j++]);
mlx4_release_resource(dev, slave, RES_COUNTER, 1, 0);
}
- }
- spin_unlock_irq(mlx4_tlock(dev));
+ } while (i);
+
+ kfree(counters_arr);
}
static void rem_slave_xrcdns(struct mlx4_dev *dev, int slave)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h
index f2ae62d..22e72bf 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en.h
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h
@@ -334,9 +334,15 @@ struct mlx5e_tx_skb_cb {
#define MLX5E_TX_SKB_CB(__skb) ((struct mlx5e_tx_skb_cb *)__skb->cb)
+enum mlx5e_dma_map_type {
+ MLX5E_DMA_MAP_SINGLE,
+ MLX5E_DMA_MAP_PAGE
+};
+
struct mlx5e_sq_dma {
- dma_addr_t addr;
- u32 size;
+ dma_addr_t addr;
+ u32 size;
+ enum mlx5e_dma_map_type type;
};
enum {
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index 5fc4d2d..1e52db3 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -1332,6 +1332,42 @@ static int mlx5e_modify_tir_lro(struct mlx5e_priv *priv, int tt)
return err;
}
+static int mlx5e_refresh_tir_self_loopback_enable(struct mlx5_core_dev *mdev,
+ u32 tirn)
+{
+ void *in;
+ int inlen;
+ int err;
+
+ inlen = MLX5_ST_SZ_BYTES(modify_tir_in);
+ in = mlx5_vzalloc(inlen);
+ if (!in)
+ return -ENOMEM;
+
+ MLX5_SET(modify_tir_in, in, bitmask.self_lb_en, 1);
+
+ err = mlx5_core_modify_tir(mdev, tirn, in, inlen);
+
+ kvfree(in);
+
+ return err;
+}
+
+static int mlx5e_refresh_tirs_self_loopback_enable(struct mlx5e_priv *priv)
+{
+ int err;
+ int i;
+
+ for (i = 0; i < MLX5E_NUM_TT; i++) {
+ err = mlx5e_refresh_tir_self_loopback_enable(priv->mdev,
+ priv->tirn[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int mlx5e_set_dev_port_mtu(struct net_device *netdev)
{
struct mlx5e_priv *priv = netdev_priv(netdev);
@@ -1376,6 +1412,13 @@ int mlx5e_open_locked(struct net_device *netdev)
goto err_clear_state_opened_flag;
}
+ err = mlx5e_refresh_tirs_self_loopback_enable(priv);
+ if (err) {
+ netdev_err(netdev, "%s: mlx5e_refresh_tirs_self_loopback_enable failed, %d\n",
+ __func__, err);
+ goto err_close_channels;
+ }
+
mlx5e_update_carrier(priv);
mlx5e_redirect_rqts(priv);
@@ -1383,6 +1426,8 @@ int mlx5e_open_locked(struct net_device *netdev)
return 0;
+err_close_channels:
+ mlx5e_close_channels(priv);
err_clear_state_opened_flag:
clear_bit(MLX5E_STATE_OPENED, &priv->state);
return err;
@@ -1856,6 +1901,8 @@ static int mlx5e_change_mtu(struct net_device *netdev, int new_mtu)
mlx5_query_port_max_mtu(mdev, &max_mtu, 1);
+ max_mtu = MLX5E_HW2SW_MTU(max_mtu);
+
if (new_mtu > max_mtu) {
netdev_err(netdev,
"%s: Bad MTU (%d) > (%d) Max\n",
@@ -1909,6 +1956,9 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev)
"Not creating net device, some required device capabilities are missing\n");
return -ENOTSUPP;
}
+ if (!MLX5_CAP_ETH(mdev, self_lb_en_modifiable))
+ mlx5_core_warn(mdev, "Self loop back prevention is not supported\n");
+
return 0;
}
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index cd8f85a..1341b1d 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -61,39 +61,47 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw)
}
}
-static void mlx5e_dma_pop_last_pushed(struct mlx5e_sq *sq, dma_addr_t *addr,
- u32 *size)
+static inline void mlx5e_tx_dma_unmap(struct device *pdev,
+ struct mlx5e_sq_dma *dma)
{
- sq->dma_fifo_pc--;
- *addr = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr;
- *size = sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size;
-}
-
-static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb)
-{
- dma_addr_t addr;
- u32 size;
- int i;
-
- for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) {
- mlx5e_dma_pop_last_pushed(sq, &addr, &size);
- dma_unmap_single(sq->pdev, addr, size, DMA_TO_DEVICE);
+ switch (dma->type) {
+ case MLX5E_DMA_MAP_SINGLE:
+ dma_unmap_single(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+ break;
+ case MLX5E_DMA_MAP_PAGE:
+ dma_unmap_page(pdev, dma->addr, dma->size, DMA_TO_DEVICE);
+ break;
+ default:
+ WARN_ONCE(true, "mlx5e_tx_dma_unmap unknown DMA type!\n");
}
}
-static inline void mlx5e_dma_push(struct mlx5e_sq *sq, dma_addr_t addr,
- u32 size)
+static inline void mlx5e_dma_push(struct mlx5e_sq *sq,
+ dma_addr_t addr,
+ u32 size,
+ enum mlx5e_dma_map_type map_type)
{
sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].addr = addr;
sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].size = size;
+ sq->dma_fifo[sq->dma_fifo_pc & sq->dma_fifo_mask].type = map_type;
sq->dma_fifo_pc++;
}
-static inline void mlx5e_dma_get(struct mlx5e_sq *sq, u32 i, dma_addr_t *addr,
- u32 *size)
+static inline struct mlx5e_sq_dma *mlx5e_dma_get(struct mlx5e_sq *sq, u32 i)
{
- *addr = sq->dma_fifo[i & sq->dma_fifo_mask].addr;
- *size = sq->dma_fifo[i & sq->dma_fifo_mask].size;
+ return &sq->dma_fifo[i & sq->dma_fifo_mask];
+}
+
+static void mlx5e_dma_unmap_wqe_err(struct mlx5e_sq *sq, struct sk_buff *skb)
+{
+ int i;
+
+ for (i = 0; i < MLX5E_TX_SKB_CB(skb)->num_dma; i++) {
+ struct mlx5e_sq_dma *last_pushed_dma =
+ mlx5e_dma_get(sq, --sq->dma_fifo_pc);
+
+ mlx5e_tx_dma_unmap(sq->pdev, last_pushed_dma);
+ }
}
u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb,
@@ -118,8 +126,15 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq,
*/
#define MLX5E_MIN_INLINE ETH_HLEN
- if (bf && (skb_headlen(skb) <= sq->max_inline))
- return skb_headlen(skb);
+ if (bf) {
+ u16 ihs = skb_headlen(skb);
+
+ if (skb_vlan_tag_present(skb))
+ ihs += VLAN_HLEN;
+
+ if (ihs <= sq->max_inline)
+ return skb_headlen(skb);
+ }
return MLX5E_MIN_INLINE;
}
@@ -218,7 +233,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
dseg->lkey = sq->mkey_be;
dseg->byte_count = cpu_to_be32(headlen);
- mlx5e_dma_push(sq, dma_addr, headlen);
+ mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE);
MLX5E_TX_SKB_CB(skb)->num_dma++;
dseg++;
@@ -237,7 +252,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb)
dseg->lkey = sq->mkey_be;
dseg->byte_count = cpu_to_be32(fsz);
- mlx5e_dma_push(sq, dma_addr, fsz);
+ mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE);
MLX5E_TX_SKB_CB(skb)->num_dma++;
dseg++;
@@ -353,13 +368,10 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq)
}
for (j = 0; j < MLX5E_TX_SKB_CB(skb)->num_dma; j++) {
- dma_addr_t addr;
- u32 size;
+ struct mlx5e_sq_dma *dma =
+ mlx5e_dma_get(sq, dma_fifo_cc++);
- mlx5e_dma_get(sq, dma_fifo_cc, &addr, &size);
- dma_fifo_cc++;
- dma_unmap_single(sq->pdev, addr, size,
- DMA_TO_DEVICE);
+ mlx5e_tx_dma_unmap(sq->pdev, dma);
}
npkts++;
diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c
index b83f7c0..122c2ee 100644
--- a/drivers/net/ethernet/natsemi/natsemi.c
+++ b/drivers/net/ethernet/natsemi/natsemi.c
@@ -1937,6 +1937,12 @@ static void refill_rx(struct net_device *dev)
break; /* Better luck next round. */
np->rx_dma[entry] = pci_map_single(np->pci_dev,
skb->data, buflen, PCI_DMA_FROMDEVICE);
+ if (pci_dma_mapping_error(np->pci_dev,
+ np->rx_dma[entry])) {
+ dev_kfree_skb_any(skb);
+ np->rx_skbuff[entry] = NULL;
+ break; /* Better luck next round. */
+ }
np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
}
np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -2093,6 +2099,12 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
np->tx_skbuff[entry] = skb;
np->tx_dma[entry] = pci_map_single(np->pci_dev,
skb->data,skb->len, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(np->pci_dev, np->tx_dma[entry])) {
+ np->tx_skbuff[entry] = NULL;
+ dev_kfree_skb_irq(skb);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
np->tx_ring[entry].addr = cpu_to_le32(np->tx_dma[entry]);
diff --git a/drivers/net/ethernet/nxp/lpc_eth.c b/drivers/net/ethernet/nxp/lpc_eth.c
index b159ef8..0576651 100644
--- a/drivers/net/ethernet/nxp/lpc_eth.c
+++ b/drivers/net/ethernet/nxp/lpc_eth.c
@@ -1326,7 +1326,7 @@ static int lpc_eth_drv_probe(struct platform_device *pdev)
/* Get platform resources */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if ((!res) || (irq < 0) || (irq >= NR_IRQS)) {
+ if (!res || irq < 0) {
dev_err(&pdev->dev, "error getting resources.\n");
ret = -ENXIO;
goto err_exit;
diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
index 30a6f24..ddcfcab 100644
--- a/drivers/net/ethernet/qlogic/Kconfig
+++ b/drivers/net/ethernet/qlogic/Kconfig
@@ -94,6 +94,7 @@ config NETXEN_NIC
config QED
tristate "QLogic QED 25/40/100Gb core driver"
depends on PCI
+ select ZLIB_INFLATE
---help---
This enables the support for ...
diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
index ac17d86..1292c36 100644
--- a/drivers/net/ethernet/qlogic/qed/qed.h
+++ b/drivers/net/ethernet/qlogic/qed/qed.h
@@ -299,6 +299,7 @@ struct qed_hwfn {
/* Flag indicating whether interrupts are enabled or not*/
bool b_int_enabled;
+ bool b_int_requested;
struct qed_mcp_info *mcp_info;
@@ -491,6 +492,8 @@ u32 qed_unzip_data(struct qed_hwfn *p_hwfn,
u32 input_len, u8 *input_buf,
u32 max_size, u8 *unzip_buf);
+int qed_slowpath_irq_req(struct qed_hwfn *hwfn);
+
#define QED_ETH_INTERFACE_VERSION 300
#endif /* _QED_H */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
index b9b7b7e..817bbd5 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
@@ -223,6 +223,7 @@ int qed_resc_alloc(struct qed_dev *cdev)
if (!p_hwfn->p_tx_cids) {
DP_NOTICE(p_hwfn,
"Failed to allocate memory for Tx Cids\n");
+ rc = -ENOMEM;
goto alloc_err;
}
@@ -230,6 +231,7 @@ int qed_resc_alloc(struct qed_dev *cdev)
if (!p_hwfn->p_rx_cids) {
DP_NOTICE(p_hwfn,
"Failed to allocate memory for Rx Cids\n");
+ rc = -ENOMEM;
goto alloc_err;
}
}
@@ -281,14 +283,17 @@ int qed_resc_alloc(struct qed_dev *cdev)
/* EQ */
p_eq = qed_eq_alloc(p_hwfn, 256);
-
- if (!p_eq)
+ if (!p_eq) {
+ rc = -ENOMEM;
goto alloc_err;
+ }
p_hwfn->p_eq = p_eq;
p_consq = qed_consq_alloc(p_hwfn);
- if (!p_consq)
+ if (!p_consq) {
+ rc = -ENOMEM;
goto alloc_err;
+ }
p_hwfn->p_consq = p_consq;
/* DMA info initialization */
@@ -303,6 +308,7 @@ int qed_resc_alloc(struct qed_dev *cdev)
cdev->reset_stats = kzalloc(sizeof(*cdev->reset_stats), GFP_KERNEL);
if (!cdev->reset_stats) {
DP_NOTICE(cdev, "Failed to allocate reset statistics\n");
+ rc = -ENOMEM;
goto alloc_err;
}
@@ -562,7 +568,7 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
}
/* Enable classification by MAC if needed */
- if (hw_mode & MODE_MF_SI) {
+ if (hw_mode & (1 << MODE_MF_SI)) {
DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
"Configuring TAGMAC_CLS_TYPE\n");
STORE_RT_REG(p_hwfn,
@@ -1379,52 +1385,63 @@ err0:
return rc;
}
-static u32 qed_hw_bar_size(struct qed_dev *cdev,
- u8 bar_id)
+static u32 qed_hw_bar_size(struct qed_hwfn *p_hwfn,
+ u8 bar_id)
{
- u32 size = pci_resource_len(cdev->pdev, (bar_id > 0) ? 2 : 0);
+ u32 bar_reg = (bar_id == 0 ? PGLUE_B_REG_PF_BAR0_SIZE
+ : PGLUE_B_REG_PF_BAR1_SIZE);
+ u32 val = qed_rd(p_hwfn, p_hwfn->p_main_ptt, bar_reg);
- return size / cdev->num_hwfns;
+ /* Get the BAR size(in KB) from hardware given val */
+ return 1 << (val + 15);
}
int qed_hw_prepare(struct qed_dev *cdev,
int personality)
{
- int rc, i;
+ struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev);
+ int rc;
/* Store the precompiled init data ptrs */
qed_init_iro_array(cdev);
/* Initialize the first hwfn - will learn number of hwfns */
- rc = qed_hw_prepare_single(&cdev->hwfns[0], cdev->regview,
+ rc = qed_hw_prepare_single(p_hwfn,
+ cdev->regview,
cdev->doorbells, personality);
if (rc)
return rc;
- personality = cdev->hwfns[0].hw_info.personality;
+ personality = p_hwfn->hw_info.personality;
/* Initialize the rest of the hwfns */
- for (i = 1; i < cdev->num_hwfns; i++) {
+ if (cdev->num_hwfns > 1) {
void __iomem *p_regview, *p_doorbell;
+ u8 __iomem *addr;
+
+ /* adjust bar offset for second engine */
+ addr = cdev->regview + qed_hw_bar_size(p_hwfn, 0) / 2;
+ p_regview = addr;
+
+ /* adjust doorbell bar offset for second engine */
+ addr = cdev->doorbells + qed_hw_bar_size(p_hwfn, 1) / 2;
+ p_doorbell = addr;
- p_regview = cdev->regview +
- i * qed_hw_bar_size(cdev, 0);
- p_doorbell = cdev->doorbells +
- i * qed_hw_bar_size(cdev, 1);
- rc = qed_hw_prepare_single(&cdev->hwfns[i], p_regview,
+ /* prepare second hw function */
+ rc = qed_hw_prepare_single(&cdev->hwfns[1], p_regview,
p_doorbell, personality);
+
+ /* in case of error, need to free the previously
+ * initiliazed hwfn 0.
+ */
if (rc) {
- /* Cleanup previously initialized hwfns */
- while (--i >= 0) {
- qed_init_free(&cdev->hwfns[i]);
- qed_mcp_free(&cdev->hwfns[i]);
- qed_hw_hwfn_free(&cdev->hwfns[i]);
- }
- return rc;
+ qed_init_free(p_hwfn);
+ qed_mcp_free(p_hwfn);
+ qed_hw_hwfn_free(p_hwfn);
}
}
- return 0;
+ return rc;
}
void qed_hw_remove(struct qed_dev *cdev)
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c
index 2e399b6..9cc9d62 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_int.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_int.c
@@ -251,11 +251,6 @@ void qed_int_sp_dpc(unsigned long hwfn_cookie)
int arr_size;
u16 rc = 0;
- if (!p_hwfn) {
- DP_ERR(p_hwfn->cdev, "DPC called - no hwfn!\n");
- return;
- }
-
if (!p_hwfn->p_sp_sb) {
DP_ERR(p_hwfn->cdev, "DPC called - no p_sp_sb\n");
return;
@@ -788,22 +783,16 @@ void qed_int_igu_enable_int(struct qed_hwfn *p_hwfn,
qed_wr(p_hwfn, p_ptt, IGU_REG_PF_CONFIGURATION, igu_pf_conf);
}
-void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- enum qed_int_mode int_mode)
+int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+ enum qed_int_mode int_mode)
{
- int i;
-
- p_hwfn->b_int_enabled = 1;
+ int rc, i;
/* Mask non-link attentions */
for (i = 0; i < 9; i++)
qed_wr(p_hwfn, p_ptt,
MISC_REG_AEU_ENABLE1_IGU_OUT_0 + (i << 2), 0);
- /* Enable interrupt Generation */
- qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode);
-
/* Configure AEU signal change to produce attentions for link */
qed_wr(p_hwfn, p_ptt, IGU_REG_LEADING_EDGE_LATCH, 0xfff);
qed_wr(p_hwfn, p_ptt, IGU_REG_TRAILING_EDGE_LATCH, 0xfff);
@@ -813,6 +802,19 @@ void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
/* Unmask AEU signals toward IGU */
qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_MASK_ATTN_IGU, 0xff);
+ if ((int_mode != QED_INT_MODE_INTA) || IS_LEAD_HWFN(p_hwfn)) {
+ rc = qed_slowpath_irq_req(p_hwfn);
+ if (rc != 0) {
+ DP_NOTICE(p_hwfn, "Slowpath IRQ request failed\n");
+ return -EINVAL;
+ }
+ p_hwfn->b_int_requested = true;
+ }
+ /* Enable interrupt Generation */
+ qed_int_igu_enable_int(p_hwfn, p_ptt, int_mode);
+ p_hwfn->b_int_enabled = 1;
+
+ return rc;
}
void qed_int_igu_disable_int(struct qed_hwfn *p_hwfn,
@@ -1132,3 +1134,11 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
return info->igu_sb_cnt;
}
+
+void qed_int_disable_post_isr_release(struct qed_dev *cdev)
+{
+ int i;
+
+ for_each_hwfn(cdev, i)
+ cdev->hwfns[i].b_int_requested = false;
+}
diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h
index 16b5751..51e0b09 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_int.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_int.h
@@ -169,10 +169,14 @@ int qed_int_get_num_sbs(struct qed_hwfn *p_hwfn,
int *p_iov_blks);
/**
- * @file
+ * @brief qed_int_disable_post_isr_release - performs the cleanup post ISR
+ * release. The API need to be called after releasing all slowpath IRQs
+ * of the device.
+ *
+ * @param cdev
*
- * @brief Interrupt handler
*/
+void qed_int_disable_post_isr_release(struct qed_dev *cdev);
#define QED_CAU_DEF_RX_TIMER_RES 0
#define QED_CAU_DEF_TX_TIMER_RES 0
@@ -366,10 +370,11 @@ void qed_int_setup(struct qed_hwfn *p_hwfn,
* @param p_hwfn
* @param p_ptt
* @param int_mode
+ *
+ * @return int
*/
-void qed_int_igu_enable(struct qed_hwfn *p_hwfn,
- struct qed_ptt *p_ptt,
- enum qed_int_mode int_mode);
+int qed_int_igu_enable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+ enum qed_int_mode int_mode);
/**
* @brief - Initialize CAU status block entry
diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
index 947c7af..174f734 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_main.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
@@ -476,41 +476,22 @@ static irqreturn_t qed_single_int(int irq, void *dev_instance)
return rc;
}
-static int qed_slowpath_irq_req(struct qed_dev *cdev)
+int qed_slowpath_irq_req(struct qed_hwfn *hwfn)
{
- int i = 0, rc = 0;
+ struct qed_dev *cdev = hwfn->cdev;
+ int rc = 0;
+ u8 id;
if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
- /* Request all the slowpath MSI-X vectors */
- for (i = 0; i < cdev->num_hwfns; i++) {
- snprintf(cdev->hwfns[i].name, NAME_SIZE,
- "sp-%d-%02x:%02x.%02x",
- i, cdev->pdev->bus->number,
- PCI_SLOT(cdev->pdev->devfn),
- cdev->hwfns[i].abs_pf_id);
-
- rc = request_irq(cdev->int_params.msix_table[i].vector,
- qed_msix_sp_int, 0,
- cdev->hwfns[i].name,
- cdev->hwfns[i].sp_dpc);
- if (rc)
- break;
-
- DP_VERBOSE(&cdev->hwfns[i],
- (NETIF_MSG_INTR | QED_MSG_SP),
+ id = hwfn->my_id;
+ snprintf(hwfn->name, NAME_SIZE, "sp-%d-%02x:%02x.%02x",
+ id, cdev->pdev->bus->number,
+ PCI_SLOT(cdev->pdev->devfn), hwfn->abs_pf_id);
+ rc = request_irq(cdev->int_params.msix_table[id].vector,
+ qed_msix_sp_int, 0, hwfn->name, hwfn->sp_dpc);
+ if (!rc)
+ DP_VERBOSE(hwfn, (NETIF_MSG_INTR | QED_MSG_SP),
"Requested slowpath MSI-X\n");
- }
-
- if (i != cdev->num_hwfns) {
- /* Free already request MSI-X vectors */
- for (i--; i >= 0; i--) {
- unsigned int vec =
- cdev->int_params.msix_table[i].vector;
- synchronize_irq(vec);
- free_irq(cdev->int_params.msix_table[i].vector,
- cdev->hwfns[i].sp_dpc);
- }
- }
} else {
unsigned long flags = 0;
@@ -534,13 +515,17 @@ static void qed_slowpath_irq_free(struct qed_dev *cdev)
if (cdev->int_params.out.int_mode == QED_INT_MODE_MSIX) {
for_each_hwfn(cdev, i) {
+ if (!cdev->hwfns[i].b_int_requested)
+ break;
synchronize_irq(cdev->int_params.msix_table[i].vector);
free_irq(cdev->int_params.msix_table[i].vector,
cdev->hwfns[i].sp_dpc);
}
} else {
- free_irq(cdev->pdev->irq, cdev);
+ if (QED_LEADING_HWFN(cdev)->b_int_requested)
+ free_irq(cdev->pdev->irq, cdev);
}
+ qed_int_disable_post_isr_release(cdev);
}
static int qed_nic_stop(struct qed_dev *cdev)
@@ -765,16 +750,11 @@ static int qed_slowpath_start(struct qed_dev *cdev,
if (rc)
goto err1;
- /* Request the slowpath IRQ */
- rc = qed_slowpath_irq_req(cdev);
- if (rc)
- goto err2;
-
/* Allocate stream for unzipping */
rc = qed_alloc_stream_mem(cdev);
if (rc) {
DP_NOTICE(cdev, "Failed to allocate stream memory\n");
- goto err3;
+ goto err2;
}
/* Start the slowpath */
diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
index 7a5ce59..e8df123 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
@@ -363,4 +363,8 @@
0x7 << 0)
#define MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT \
0
+#define PGLUE_B_REG_PF_BAR0_SIZE \
+ 0x2aae60UL
+#define PGLUE_B_REG_PF_BAR1_SIZE \
+ 0x2aae64UL
#endif
diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h
index 31a1f1e..287fadf 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
+++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
@@ -124,8 +124,12 @@ struct qed_spq {
dma_addr_t p_phys;
struct qed_spq_entry *p_virt;
- /* Used as index for completions (returns on EQ by FW) */
- u16 echo_idx;
+#define SPQ_RING_SIZE \
+ (CORE_SPQE_PAGE_SIZE_BYTES / sizeof(struct slow_path_element))
+
+ /* Bitmap for handling out-of-order completions */
+ DECLARE_BITMAP(p_comp_bitmap, SPQ_RING_SIZE);
+ u8 comp_bitmap_idx;
/* Statistics */
u32 unlimited_pending_count;
diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
index 7c0b845..3dd548a 100644
--- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
+++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
@@ -112,8 +112,6 @@ static int
qed_spq_fill_entry(struct qed_hwfn *p_hwfn,
struct qed_spq_entry *p_ent)
{
- p_ent->elem.hdr.echo = 0;
- p_hwfn->p_spq->echo_idx++;
p_ent->flags = 0;
switch (p_ent->comp_mode) {
@@ -195,10 +193,12 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
struct qed_spq *p_spq,
struct qed_spq_entry *p_ent)
{
- struct qed_chain *p_chain = &p_hwfn->p_spq->chain;
+ struct qed_chain *p_chain = &p_hwfn->p_spq->chain;
+ u16 echo = qed_chain_get_prod_idx(p_chain);
struct slow_path_element *elem;
struct core_db_data db;
+ p_ent->elem.hdr.echo = cpu_to_le16(echo);
elem = qed_chain_produce(p_chain);
if (!elem) {
DP_NOTICE(p_hwfn, "Failed to produce from SPQ chain\n");
@@ -437,7 +437,9 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn)
p_spq->comp_count = 0;
p_spq->comp_sent_count = 0;
p_spq->unlimited_pending_count = 0;
- p_spq->echo_idx = 0;
+
+ bitmap_zero(p_spq->p_comp_bitmap, SPQ_RING_SIZE);
+ p_spq->comp_bitmap_idx = 0;
/* SPQ cid, cannot fail */
qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid);
@@ -582,26 +584,32 @@ qed_spq_add_entry(struct qed_hwfn *p_hwfn,
struct qed_spq *p_spq = p_hwfn->p_spq;
if (p_ent->queue == &p_spq->unlimited_pending) {
- struct qed_spq_entry *p_en2;
if (list_empty(&p_spq->free_pool)) {
list_add_tail(&p_ent->list, &p_spq->unlimited_pending);
p_spq->unlimited_pending_count++;
return 0;
- }
+ } else {
+ struct qed_spq_entry *p_en2;
- p_en2 = list_first_entry(&p_spq->free_pool,
- struct qed_spq_entry,
- list);
- list_del(&p_en2->list);
+ p_en2 = list_first_entry(&p_spq->free_pool,
+ struct qed_spq_entry,
+ list);
+ list_del(&p_en2->list);
+
+ /* Copy the ring element physical pointer to the new
+ * entry, since we are about to override the entire ring
+ * entry and don't want to lose the pointer.
+ */
+ p_ent->elem.data_ptr = p_en2->elem.data_ptr;
- /* Strcut assignment */
- *p_en2 = *p_ent;
+ *p_en2 = *p_ent;
- kfree(p_ent);
+ kfree(p_ent);
- p_ent = p_en2;
+ p_ent = p_en2;
+ }
}
/* entry is to be placed in 'pending' queue */
@@ -777,13 +785,38 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending,
list) {
if (p_ent->elem.hdr.echo == echo) {
+ u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
+
list_del(&p_ent->list);
- qed_chain_return_produced(&p_spq->chain);
+ /* Avoid overriding of SPQ entries when getting
+ * out-of-order completions, by marking the completions
+ * in a bitmap and increasing the chain consumer only
+ * for the first successive completed entries.
+ */
+ bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE);
+
+ while (test_bit(p_spq->comp_bitmap_idx,
+ p_spq->p_comp_bitmap)) {
+ bitmap_clear(p_spq->p_comp_bitmap,
+ p_spq->comp_bitmap_idx,
+ SPQ_RING_SIZE);
+ p_spq->comp_bitmap_idx++;
+ qed_chain_return_produced(&p_spq->chain);
+ }
+
p_spq->comp_count++;
found = p_ent;
break;
}
+
+ /* This is relatively uncommon - depends on scenarios
+ * which have mutliple per-PF sent ramrods.
+ */
+ DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
+ "Got completion for echo %04x - doesn't match echo %04x in completion pending list\n",
+ le16_to_cpu(echo),
+ le16_to_cpu(p_ent->elem.hdr.echo));
}
/* Release lock before callback, as callback may post
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
index be7d7a6..3490675 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c
@@ -246,12 +246,13 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *adapter)
u32 state;
state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
- while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit--) {
+ while (state != QLCNIC_DEV_NPAR_OPER && idc->vnic_wait_limit) {
+ idc->vnic_wait_limit--;
msleep(1000);
state = QLCRDX(ahw, QLC_83XX_VNIC_STATE);
}
- if (!idc->vnic_wait_limit) {
+ if (state != QLCNIC_DEV_NPAR_OPER) {
dev_err(&adapter->pdev->dev,
"vNIC mode not operational, state check timed out.\n");
return -EIO;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
index a5f422f..daf0515 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c
@@ -772,8 +772,10 @@ int qlcnic_82xx_config_intrpt(struct qlcnic_adapter *adapter, u8 op_type)
int i, err = 0;
for (i = 0; i < ahw->num_msix; i++) {
- qlcnic_alloc_mbx_args(&cmd, adapter,
- QLCNIC_CMD_MQ_TX_CONFIG_INTR);
+ err = qlcnic_alloc_mbx_args(&cmd, adapter,
+ QLCNIC_CMD_MQ_TX_CONFIG_INTR);
+ if (err)
+ return err;
type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL;
val = type | (ahw->intr_tbl[i].type << 4);
if (ahw->intr_tbl[i].type == QLCNIC_INTRPT_MSIX)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index d448145..1205f6f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -353,7 +353,8 @@ static int qlcnic_set_mac(struct net_device *netdev, void *p)
if (!is_valid_ether_addr(addr->sa_data))
return -EINVAL;
- if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data))
+ if (ether_addr_equal_unaligned(adapter->mac_addr, addr->sa_data) &&
+ ether_addr_equal_unaligned(netdev->dev_addr, addr->sa_data))
return 0;
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 02b7115..9979764 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -4211,8 +4211,9 @@ static int ql_change_rx_buffers(struct ql_adapter *qdev)
/* Wait for an outstanding reset to complete. */
if (!test_bit(QL_ADAPTER_UP, &qdev->flags)) {
- int i = 3;
- while (i-- && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
+ int i = 4;
+
+ while (--i && !test_bit(QL_ADAPTER_UP, &qdev->flags)) {
netif_err(qdev, ifup, qdev->ndev,
"Waiting for adapter UP...\n");
ssleep(1);
diff --git a/drivers/net/ethernet/qualcomm/qca_spi.c b/drivers/net/ethernet/qualcomm/qca_spi.c
index ddb2c6c..689a4a5 100644
--- a/drivers/net/ethernet/qualcomm/qca_spi.c
+++ b/drivers/net/ethernet/qualcomm/qca_spi.c
@@ -736,9 +736,8 @@ qcaspi_netdev_tx_timeout(struct net_device *dev)
netdev_info(qca->net_dev, "Transmit timeout at %ld, latency %ld\n",
jiffies, jiffies - dev->trans_start);
qca->net_dev->stats.tx_errors++;
- /* wake the queue if there is room */
- if (qcaspi_tx_ring_has_space(&qca->txr))
- netif_wake_queue(dev);
+ /* Trigger tx queue flush and QCA7000 reset */
+ qca->sync = QCASPI_SYNC_UNKNOWN;
}
static int
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index b4f2123..79ef799 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -7429,15 +7429,15 @@ process_pkt:
rtl8169_rx_vlan_tag(desc, skb);
+ if (skb->pkt_type == PACKET_MULTICAST)
+ dev->stats.multicast++;
+
napi_gro_receive(&tp->napi, skb);
u64_stats_update_begin(&tp->rx_stats.syncp);
tp->rx_stats.packets++;
tp->rx_stats.bytes += pkt_size;
u64_stats_update_end(&tp->rx_stats.syncp);
-
- if (skb->pkt_type == PACKET_MULTICAST)
- dev->stats.multicast++;
}
release_descriptor:
desc->opts2 = 0;
diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c
index aa7b208..467d416 100644
--- a/drivers/net/ethernet/renesas/ravb_main.c
+++ b/drivers/net/ethernet/renesas/ravb_main.c
@@ -408,8 +408,6 @@ static int ravb_dmac_init(struct net_device *ndev)
/* Interrupt enable: */
/* Frame receive */
ravb_write(ndev, RIC0_FRE0 | RIC0_FRE1, RIC0);
- /* Receive FIFO full warning */
- ravb_write(ndev, RIC1_RFWE, RIC1);
/* Receive FIFO full error, descriptor empty */
ravb_write(ndev, RIC2_QFE0 | RIC2_QFE1 | RIC2_RFFE, RIC2);
/* Frame transmitted, timestamp FIFO updated */
@@ -733,8 +731,10 @@ static irqreturn_t ravb_interrupt(int irq, void *dev_id)
((tis & tic) & BIT(q))) {
if (napi_schedule_prep(&priv->napi[q])) {
/* Mask RX and TX interrupts */
- ravb_write(ndev, ric0 & ~BIT(q), RIC0);
- ravb_write(ndev, tic & ~BIT(q), TIC);
+ ric0 &= ~BIT(q);
+ tic &= ~BIT(q);
+ ravb_write(ndev, ric0, RIC0);
+ ravb_write(ndev, tic, TIC);
__napi_schedule(&priv->napi[q]);
} else {
netdev_warn(ndev,
@@ -905,6 +905,9 @@ static int ravb_phy_init(struct net_device *ndev)
netdev_info(ndev, "limited PHY to 100Mbit/s\n");
}
+ /* 10BASE is not supported */
+ phydev->supported &= ~PHY_10BT_FEATURES;
+
netdev_info(ndev, "attached PHY %d (IRQ %d) to driver %s\n",
phydev->addr, phydev->irq, phydev->drv->name);
@@ -1037,7 +1040,7 @@ static const char ravb_gstrings_stats[][ETH_GSTRING_LEN] = {
"rx_queue_1_mcast_packets",
"rx_queue_1_errors",
"rx_queue_1_crc_errors",
- "rx_queue_1_frame_errors_",
+ "rx_queue_1_frame_errors",
"rx_queue_1_length_errors",
"rx_queue_1_missed_errors",
"rx_queue_1_over_errors",
@@ -1225,7 +1228,7 @@ static int ravb_open(struct net_device *ndev)
/* Device init */
error = ravb_dmac_init(ndev);
if (error)
- goto out_free_irq;
+ goto out_free_irq2;
ravb_emac_init(ndev);
/* Initialise PTP Clock driver */
@@ -1243,9 +1246,11 @@ static int ravb_open(struct net_device *ndev)
out_ptp_stop:
/* Stop PTP Clock driver */
ravb_ptp_stop(ndev);
+out_free_irq2:
+ if (priv->chip_id == RCAR_GEN3)
+ free_irq(priv->emac_irq, ndev);
out_free_irq:
free_irq(ndev->irq, ndev);
- free_irq(priv->emac_irq, ndev);
out_napi_off:
napi_disable(&priv->napi[RAVB_NC]);
napi_disable(&priv->napi[RAVB_BE]);
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 6150a23..6a8fc0f 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -52,6 +52,8 @@
NETIF_MSG_RX_ERR| \
NETIF_MSG_TX_ERR)
+#define SH_ETH_OFFSET_INVALID ((u16)~0)
+
#define SH_ETH_OFFSET_DEFAULTS \
[0 ... SH_ETH_MAX_REGISTER_OFFSET - 1] = SH_ETH_OFFSET_INVALID
@@ -404,6 +406,28 @@ static const u16 sh_eth_offset_fast_sh3_sh2[SH_ETH_MAX_REGISTER_OFFSET] = {
static void sh_eth_rcv_snd_disable(struct net_device *ndev);
static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev);
+static void sh_eth_write(struct net_device *ndev, u32 data, int enum_index)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u16 offset = mdp->reg_offset[enum_index];
+
+ if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+ return;
+
+ iowrite32(data, mdp->addr + offset);
+}
+
+static u32 sh_eth_read(struct net_device *ndev, int enum_index)
+{
+ struct sh_eth_private *mdp = netdev_priv(ndev);
+ u16 offset = mdp->reg_offset[enum_index];
+
+ if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
+ return ~0U;
+
+ return ioread32(mdp->addr + offset);
+}
+
static bool sh_eth_is_gether(struct sh_eth_private *mdp)
{
return mdp->reg_offset == sh_eth_offset_gigabit;
@@ -1098,7 +1122,7 @@ static struct mdiobb_ops bb_ops = {
static void sh_eth_ring_free(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
- int i;
+ int ringsize, i;
/* Free Rx skb ringbuffer */
if (mdp->rx_skbuff) {
@@ -1115,6 +1139,20 @@ static void sh_eth_ring_free(struct net_device *ndev)
}
kfree(mdp->tx_skbuff);
mdp->tx_skbuff = NULL;
+
+ if (mdp->rx_ring) {
+ ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
+ dma_free_coherent(NULL, ringsize, mdp->rx_ring,
+ mdp->rx_desc_dma);
+ mdp->rx_ring = NULL;
+ }
+
+ if (mdp->tx_ring) {
+ ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
+ dma_free_coherent(NULL, ringsize, mdp->tx_ring,
+ mdp->tx_desc_dma);
+ mdp->tx_ring = NULL;
+ }
}
/* format skb and descriptor buffer */
@@ -1129,6 +1167,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring;
int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
dma_addr_t dma_addr;
+ u32 buf_len;
mdp->cur_rx = 0;
mdp->cur_tx = 0;
@@ -1149,16 +1188,16 @@ static void sh_eth_ring_format(struct net_device *ndev)
/* RX descriptor */
rxdesc = &mdp->rx_ring[i];
/* The size of the buffer is a multiple of 32 bytes. */
- rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
- dma_addr = dma_map_single(&ndev->dev, skb->data,
- rxdesc->buffer_length,
+ buf_len = ALIGN(mdp->rx_buf_sz, 32);
+ rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
+ dma_addr = dma_map_single(&ndev->dev, skb->data, buf_len,
DMA_FROM_DEVICE);
if (dma_mapping_error(&ndev->dev, dma_addr)) {
kfree_skb(skb);
break;
}
mdp->rx_skbuff[i] = skb;
- rxdesc->addr = dma_addr;
+ rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP);
/* Rx descriptor address set */
@@ -1182,7 +1221,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
mdp->tx_skbuff[i] = NULL;
txdesc = &mdp->tx_ring[i];
txdesc->status = cpu_to_edmac(mdp, TD_TFP);
- txdesc->buffer_length = 0;
+ txdesc->len = cpu_to_edmac(mdp, 0);
if (i == 0) {
/* Tx descriptor address set */
sh_eth_write(ndev, mdp->tx_desc_dma, TDLAR);
@@ -1199,7 +1238,7 @@ static void sh_eth_ring_format(struct net_device *ndev)
static int sh_eth_ring_init(struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
- int rx_ringsize, tx_ringsize, ret = 0;
+ int rx_ringsize, tx_ringsize;
/* +26 gets the maximum ethernet encapsulation, +7 & ~7 because the
* card needs room to do 8 byte alignment, +2 so we can reserve
@@ -1214,26 +1253,20 @@ static int sh_eth_ring_init(struct net_device *ndev)
/* Allocate RX and TX skb rings */
mdp->rx_skbuff = kcalloc(mdp->num_rx_ring, sizeof(*mdp->rx_skbuff),
GFP_KERNEL);
- if (!mdp->rx_skbuff) {
- ret = -ENOMEM;
- return ret;
- }
+ if (!mdp->rx_skbuff)
+ return -ENOMEM;
mdp->tx_skbuff = kcalloc(mdp->num_tx_ring, sizeof(*mdp->tx_skbuff),
GFP_KERNEL);
- if (!mdp->tx_skbuff) {
- ret = -ENOMEM;
- goto skb_ring_free;
- }
+ if (!mdp->tx_skbuff)
+ goto ring_free;
/* Allocate all Rx descriptors. */
rx_ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
mdp->rx_ring = dma_alloc_coherent(NULL, rx_ringsize, &mdp->rx_desc_dma,
GFP_KERNEL);
- if (!mdp->rx_ring) {
- ret = -ENOMEM;
- goto skb_ring_free;
- }
+ if (!mdp->rx_ring)
+ goto ring_free;
mdp->dirty_rx = 0;
@@ -1241,42 +1274,15 @@ static int sh_eth_ring_init(struct net_device *ndev)
tx_ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
mdp->tx_ring = dma_alloc_coherent(NULL, tx_ringsize, &mdp->tx_desc_dma,
GFP_KERNEL);
- if (!mdp->tx_ring) {
- ret = -ENOMEM;
- goto desc_ring_free;
- }
- return ret;
-
-desc_ring_free:
- /* free DMA buffer */
- dma_free_coherent(NULL, rx_ringsize, mdp->rx_ring, mdp->rx_desc_dma);
+ if (!mdp->tx_ring)
+ goto ring_free;
+ return 0;
-skb_ring_free:
- /* Free Rx and Tx skb ring buffer */
+ring_free:
+ /* Free Rx and Tx skb ring buffer and DMA buffer */
sh_eth_ring_free(ndev);
- mdp->tx_ring = NULL;
- mdp->rx_ring = NULL;
-
- return ret;
-}
-
-static void sh_eth_free_dma_buffer(struct sh_eth_private *mdp)
-{
- int ringsize;
-
- if (mdp->rx_ring) {
- ringsize = sizeof(struct sh_eth_rxdesc) * mdp->num_rx_ring;
- dma_free_coherent(NULL, ringsize, mdp->rx_ring,
- mdp->rx_desc_dma);
- mdp->rx_ring = NULL;
- }
- if (mdp->tx_ring) {
- ringsize = sizeof(struct sh_eth_txdesc) * mdp->num_tx_ring;
- dma_free_coherent(NULL, ringsize, mdp->tx_ring,
- mdp->tx_desc_dma);
- mdp->tx_ring = NULL;
- }
+ return -ENOMEM;
}
static int sh_eth_dev_init(struct net_device *ndev, bool start)
@@ -1422,8 +1428,10 @@ static int sh_eth_txfree(struct net_device *ndev)
entry, edmac_to_cpu(mdp, txdesc->status));
/* Free the original skb. */
if (mdp->tx_skbuff[entry]) {
- dma_unmap_single(&ndev->dev, txdesc->addr,
- txdesc->buffer_length, DMA_TO_DEVICE);
+ dma_unmap_single(&ndev->dev,
+ edmac_to_cpu(mdp, txdesc->addr),
+ edmac_to_cpu(mdp, txdesc->len) >> 16,
+ DMA_TO_DEVICE);
dev_kfree_skb_irq(mdp->tx_skbuff[entry]);
mdp->tx_skbuff[entry] = NULL;
free_num++;
@@ -1433,7 +1441,7 @@ static int sh_eth_txfree(struct net_device *ndev)
txdesc->status |= cpu_to_edmac(mdp, TD_TDLE);
ndev->stats.tx_packets++;
- ndev->stats.tx_bytes += txdesc->buffer_length;
+ ndev->stats.tx_bytes += edmac_to_cpu(mdp, txdesc->len) >> 16;
}
return free_num;
}
@@ -1452,6 +1460,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
u32 desc_status;
int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN + 32 - 1;
dma_addr_t dma_addr;
+ u32 buf_len;
boguscnt = min(boguscnt, *quota);
limit = boguscnt;
@@ -1460,7 +1469,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
/* RACT bit must be checked before all the following reads */
dma_rmb();
desc_status = edmac_to_cpu(mdp, rxdesc->status);
- pkt_len = rxdesc->frame_length;
+ pkt_len = edmac_to_cpu(mdp, rxdesc->len) & RD_RFL;
if (--boguscnt < 0)
break;
@@ -1481,6 +1490,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
if (mdp->cd->shift_rd0)
desc_status >>= 16;
+ skb = mdp->rx_skbuff[entry];
if (desc_status & (RD_RFS1 | RD_RFS2 | RD_RFS3 | RD_RFS4 |
RD_RFS5 | RD_RFS6 | RD_RFS10)) {
ndev->stats.rx_errors++;
@@ -1496,16 +1506,16 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
ndev->stats.rx_missed_errors++;
if (desc_status & RD_RFS10)
ndev->stats.rx_over_errors++;
- } else {
+ } else if (skb) {
+ dma_addr = edmac_to_cpu(mdp, rxdesc->addr);
if (!mdp->cd->hw_swap)
sh_eth_soft_swap(
- phys_to_virt(ALIGN(rxdesc->addr, 4)),
+ phys_to_virt(ALIGN(dma_addr, 4)),
pkt_len + 2);
- skb = mdp->rx_skbuff[entry];
mdp->rx_skbuff[entry] = NULL;
if (mdp->cd->rpadir)
skb_reserve(skb, NET_IP_ALIGN);
- dma_unmap_single(&ndev->dev, rxdesc->addr,
+ dma_unmap_single(&ndev->dev, dma_addr,
ALIGN(mdp->rx_buf_sz, 32),
DMA_FROM_DEVICE);
skb_put(skb, pkt_len);
@@ -1525,7 +1535,8 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
entry = mdp->dirty_rx % mdp->num_rx_ring;
rxdesc = &mdp->rx_ring[entry];
/* The size of the buffer is 32 byte boundary. */
- rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 32);
+ buf_len = ALIGN(mdp->rx_buf_sz, 32);
+ rxdesc->len = cpu_to_edmac(mdp, buf_len << 16);
if (mdp->rx_skbuff[entry] == NULL) {
skb = netdev_alloc_skb(ndev, skbuff_size);
@@ -1533,8 +1544,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
break; /* Better luck next round. */
sh_eth_set_receive_align(skb);
dma_addr = dma_map_single(&ndev->dev, skb->data,
- rxdesc->buffer_length,
- DMA_FROM_DEVICE);
+ buf_len, DMA_FROM_DEVICE);
if (dma_mapping_error(&ndev->dev, dma_addr)) {
kfree_skb(skb);
break;
@@ -1542,7 +1552,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota)
mdp->rx_skbuff[entry] = skb;
skb_checksum_none_assert(skb);
- rxdesc->addr = dma_addr;
+ rxdesc->addr = cpu_to_edmac(mdp, dma_addr);
}
dma_wmb(); /* RACT bit must be set after all the above writes */
if (entry >= mdp->num_rx_ring - 1)
@@ -2239,10 +2249,8 @@ static int sh_eth_set_ringparam(struct net_device *ndev,
sh_eth_dev_exit(ndev);
- /* Free all the skbuffs in the Rx queue. */
+ /* Free all the skbuffs in the Rx queue and the DMA buffers. */
sh_eth_ring_free(ndev);
- /* Free DMA buffer */
- sh_eth_free_dma_buffer(mdp);
}
/* Set new parameters */
@@ -2352,8 +2360,8 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
/* Free all the skbuffs in the Rx queue. */
for (i = 0; i < mdp->num_rx_ring; i++) {
rxdesc = &mdp->rx_ring[i];
- rxdesc->status = 0;
- rxdesc->addr = 0xBADF00D0;
+ rxdesc->status = cpu_to_edmac(mdp, 0);
+ rxdesc->addr = cpu_to_edmac(mdp, 0xBADF00D0);
dev_kfree_skb(mdp->rx_skbuff[i]);
mdp->rx_skbuff[i] = NULL;
}
@@ -2371,6 +2379,7 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
struct sh_eth_txdesc *txdesc;
+ dma_addr_t dma_addr;
u32 entry;
unsigned long flags;
@@ -2393,15 +2402,15 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev)
txdesc = &mdp->tx_ring[entry];
/* soft swap. */
if (!mdp->cd->hw_swap)
- sh_eth_soft_swap(phys_to_virt(ALIGN(txdesc->addr, 4)),
- skb->len + 2);
- txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len,
- DMA_TO_DEVICE);
- if (dma_mapping_error(&ndev->dev, txdesc->addr)) {
+ sh_eth_soft_swap(PTR_ALIGN(skb->data, 4), skb->len + 2);
+ dma_addr = dma_map_single(&ndev->dev, skb->data, skb->len,
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&ndev->dev, dma_addr)) {
kfree_skb(skb);
return NETDEV_TX_OK;
}
- txdesc->buffer_length = skb->len;
+ txdesc->addr = cpu_to_edmac(mdp, dma_addr);
+ txdesc->len = cpu_to_edmac(mdp, skb->len << 16);
dma_wmb(); /* TACT bit must be set after all the above writes */
if (entry >= mdp->num_tx_ring - 1)
@@ -2487,12 +2496,9 @@ static int sh_eth_close(struct net_device *ndev)
free_irq(ndev->irq, ndev);
- /* Free all the skbuffs in the Rx queue. */
+ /* Free all the skbuffs in the Rx queue and the DMA buffer. */
sh_eth_ring_free(ndev);
- /* free DMA buffer */
- sh_eth_free_dma_buffer(mdp);
-
pm_runtime_put_sync(&mdp->pdev->dev);
mdp->is_opened = 0;
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 50382b1..72fcfc9 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -283,7 +283,7 @@ enum DMAC_IM_BIT {
DMAC_M_RINT1 = 0x00000001,
};
-/* Receive descriptor bit */
+/* Receive descriptor 0 bits */
enum RD_STS_BIT {
RD_RACT = 0x80000000, RD_RDLE = 0x40000000,
RD_RFP1 = 0x20000000, RD_RFP0 = 0x10000000,
@@ -298,6 +298,12 @@ enum RD_STS_BIT {
#define RDFEND RD_RFP0
#define RD_RFP (RD_RFP1|RD_RFP0)
+/* Receive descriptor 1 bits */
+enum RD_LEN_BIT {
+ RD_RFL = 0x0000ffff, /* receive frame length */
+ RD_RBL = 0xffff0000, /* receive buffer length */
+};
+
/* FCFTR */
enum FCFTR_BIT {
FCFTR_RFF2 = 0x00040000, FCFTR_RFF1 = 0x00020000,
@@ -307,7 +313,7 @@ enum FCFTR_BIT {
#define DEFAULT_FIFO_F_D_RFF (FCFTR_RFF2 | FCFTR_RFF1 | FCFTR_RFF0)
#define DEFAULT_FIFO_F_D_RFD (FCFTR_RFD2 | FCFTR_RFD1 | FCFTR_RFD0)
-/* Transmit descriptor bit */
+/* Transmit descriptor 0 bits */
enum TD_STS_BIT {
TD_TACT = 0x80000000, TD_TDLE = 0x40000000,
TD_TFP1 = 0x20000000, TD_TFP0 = 0x10000000,
@@ -317,6 +323,11 @@ enum TD_STS_BIT {
#define TDFEND TD_TFP0
#define TD_TFP (TD_TFP1|TD_TFP0)
+/* Transmit descriptor 1 bits */
+enum TD_LEN_BIT {
+ TD_TBL = 0xffff0000, /* transmit buffer length */
+};
+
/* RMCR */
enum RMCR_BIT {
RMCR_RNC = 0x00000001,
@@ -425,15 +436,9 @@ enum TSU_FWSLC_BIT {
*/
struct sh_eth_txdesc {
u32 status; /* TD0 */
-#if defined(__LITTLE_ENDIAN)
- u16 pad0; /* TD1 */
- u16 buffer_length; /* TD1 */
-#else
- u16 buffer_length; /* TD1 */
- u16 pad0; /* TD1 */
-#endif
+ u32 len; /* TD1 */
u32 addr; /* TD2 */
- u32 pad1; /* padding data */
+ u32 pad0; /* padding data */
} __aligned(2) __packed;
/* The sh ether Rx buffer descriptors.
@@ -441,13 +446,7 @@ struct sh_eth_txdesc {
*/
struct sh_eth_rxdesc {
u32 status; /* RD0 */
-#if defined(__LITTLE_ENDIAN)
- u16 frame_length; /* RD1 */
- u16 buffer_length; /* RD1 */
-#else
- u16 buffer_length; /* RD1 */
- u16 frame_length; /* RD1 */
-#endif
+ u32 len; /* RD1 */
u32 addr; /* RD2 */
u32 pad0; /* padding data */
} __aligned(2) __packed;
@@ -546,31 +545,6 @@ static inline void sh_eth_soft_swap(char *src, int len)
#endif
}
-#define SH_ETH_OFFSET_INVALID ((u16) ~0)
-
-static inline void sh_eth_write(struct net_device *ndev, u32 data,
- int enum_index)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
- u16 offset = mdp->reg_offset[enum_index];
-
- if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
- return;
-
- iowrite32(data, mdp->addr + offset);
-}
-
-static inline u32 sh_eth_read(struct net_device *ndev, int enum_index)
-{
- struct sh_eth_private *mdp = netdev_priv(ndev);
- u16 offset = mdp->reg_offset[enum_index];
-
- if (WARN_ON(offset == SH_ETH_OFFSET_INVALID))
- return ~0U;
-
- return ioread32(mdp->addr + offset);
-}
-
static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,
int enum_index)
{
diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c
index bc6d21b..e6a084a 100644
--- a/drivers/net/ethernet/sfc/ef10.c
+++ b/drivers/net/ethernet/sfc/ef10.c
@@ -3299,7 +3299,8 @@ static int efx_ef10_filter_remove_internal(struct efx_nic *efx,
new_spec.priority = EFX_FILTER_PRI_AUTO;
new_spec.flags = (EFX_FILTER_FLAG_RX |
- EFX_FILTER_FLAG_RX_RSS);
+ (efx_rss_enabled(efx) ?
+ EFX_FILTER_FLAG_RX_RSS : 0));
new_spec.dmaq_id = 0;
new_spec.rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
rc = efx_ef10_filter_push(efx, &new_spec,
@@ -3921,6 +3922,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
{
struct efx_ef10_filter_table *table = efx->filter_state;
struct efx_ef10_dev_addr *addr_list;
+ enum efx_filter_flags filter_flags;
struct efx_filter_spec spec;
u8 baddr[ETH_ALEN];
unsigned int i, j;
@@ -3935,11 +3937,11 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
addr_count = table->dev_uc_count;
}
+ filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0;
+
/* Insert/renew filters */
for (i = 0; i < addr_count; i++) {
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
- EFX_FILTER_FLAG_RX_RSS,
- 0);
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
addr_list[i].addr);
rc = efx_ef10_filter_insert(efx, &spec, true);
@@ -3968,9 +3970,7 @@ static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx,
if (multicast && rollback) {
/* Also need an Ethernet broadcast filter */
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
- EFX_FILTER_FLAG_RX_RSS,
- 0);
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
eth_broadcast_addr(baddr);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr);
rc = efx_ef10_filter_insert(efx, &spec, true);
@@ -4000,13 +4000,14 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
{
struct efx_ef10_filter_table *table = efx->filter_state;
struct efx_ef10_nic_data *nic_data = efx->nic_data;
+ enum efx_filter_flags filter_flags;
struct efx_filter_spec spec;
u8 baddr[ETH_ALEN];
int rc;
- efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
- EFX_FILTER_FLAG_RX_RSS,
- 0);
+ filter_flags = efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0;
+
+ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
if (multicast)
efx_filter_set_mc_def(&spec);
@@ -4023,8 +4024,7 @@ static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast,
if (!nic_data->workaround_26807) {
/* Also need an Ethernet broadcast filter */
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO,
- EFX_FILTER_FLAG_RX_RSS,
- 0);
+ filter_flags, 0);
eth_broadcast_addr(baddr);
efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC,
baddr);
diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c
index 6e11ee6..a3c42a3 100644
--- a/drivers/net/ethernet/sfc/efx.c
+++ b/drivers/net/ethernet/sfc/efx.c
@@ -1247,11 +1247,9 @@ static int efx_init_io(struct efx_nic *efx)
* masks event though they reject 46 bit masks.
*/
while (dma_mask > 0x7fffffffUL) {
- if (dma_supported(&pci_dev->dev, dma_mask)) {
- rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask);
- if (rc == 0)
- break;
- }
+ rc = dma_set_mask_and_coherent(&pci_dev->dev, dma_mask);
+ if (rc == 0)
+ break;
dma_mask >>= 1;
}
if (rc) {
@@ -3424,7 +3422,7 @@ out:
* with our request for slot reset the mmio_enabled callback will never be
* called, and the link_reset callback is not used by AER or EEH mechanisms.
*/
-static struct pci_error_handlers efx_err_handlers = {
+static const struct pci_error_handlers efx_err_handlers = {
.error_detected = efx_io_error_detected,
.slot_reset = efx_io_slot_reset,
.resume = efx_io_resume,
diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h
index 1aaf76c..1082747 100644
--- a/drivers/net/ethernet/sfc/efx.h
+++ b/drivers/net/ethernet/sfc/efx.h
@@ -76,6 +76,11 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue);
#define EFX_TXQ_MAX_ENT(efx) (EFX_WORKAROUND_35388(efx) ? \
EFX_MAX_DMAQ_SIZE / 2 : EFX_MAX_DMAQ_SIZE)
+static inline bool efx_rss_enabled(struct efx_nic *efx)
+{
+ return efx->rss_spread > 1;
+}
+
/* Filters */
void efx_mac_reconfigure(struct efx_nic *efx);
diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c
index 5a1c5a8..133e9e3 100644
--- a/drivers/net/ethernet/sfc/farch.c
+++ b/drivers/net/ethernet/sfc/farch.c
@@ -2242,7 +2242,7 @@ efx_farch_filter_init_rx_auto(struct efx_nic *efx,
*/
spec->priority = EFX_FILTER_PRI_AUTO;
spec->flags = (EFX_FILTER_FLAG_RX |
- (efx->n_rx_channels > 1 ? EFX_FILTER_FLAG_RX_RSS : 0) |
+ (efx_rss_enabled(efx) ? EFX_FILTER_FLAG_RX_RSS : 0) |
(efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0));
spec->dmaq_id = 0;
}
diff --git a/drivers/net/ethernet/sfc/txc43128_phy.c b/drivers/net/ethernet/sfc/txc43128_phy.c
index 3d5ee32..194f67d 100644
--- a/drivers/net/ethernet/sfc/txc43128_phy.c
+++ b/drivers/net/ethernet/sfc/txc43128_phy.c
@@ -418,7 +418,7 @@ static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd)
val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
efx_mdio_write(efx, mmd, TXC_GLRGS_GLCMD, val);
- while (tries--) {
+ while (--tries) {
val = efx_mdio_read(efx, mmd, TXC_GLRGS_GLCMD);
if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN)))
break;
diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c
index c860c90..219a99b 100644
--- a/drivers/net/ethernet/smsc/smsc911x.c
+++ b/drivers/net/ethernet/smsc/smsc911x.c
@@ -809,22 +809,17 @@ static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata)
static int smsc911x_phy_reset(struct smsc911x_data *pdata)
{
- struct phy_device *phy_dev = pdata->phy_dev;
unsigned int temp;
unsigned int i = 100000;
- BUG_ON(!phy_dev);
- BUG_ON(!phy_dev->bus);
-
- SMSC_TRACE(pdata, hw, "Performing PHY BCR Reset");
- smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET);
+ temp = smsc911x_reg_read(pdata, PMT_CTRL);
+ smsc911x_reg_write(pdata, PMT_CTRL, temp | PMT_CTRL_PHY_RST_);
do {
msleep(1);
- temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr,
- MII_BMCR);
- } while ((i--) && (temp & BMCR_RESET));
+ temp = smsc911x_reg_read(pdata, PMT_CTRL);
+ } while ((i--) && (temp & PMT_CTRL_PHY_RST_));
- if (temp & BMCR_RESET) {
+ if (unlikely(temp & PMT_CTRL_PHY_RST_)) {
SMSC_WARN(pdata, hw, "PHY reset failed to complete");
return -EIO;
}
@@ -2296,7 +2291,7 @@ static int smsc911x_init(struct net_device *dev)
}
/* Reset the LAN911x */
- if (smsc911x_soft_reset(pdata))
+ if (smsc911x_phy_reset(pdata) || smsc911x_soft_reset(pdata))
return -ENODEV;
dev->flags |= IFF_MULTICAST;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
index 9d89bdb..82de68b 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
@@ -337,11 +337,11 @@ static int ipq806x_gmac_probe(struct platform_device *pdev)
QSGMII_PHY_RX_SIGNAL_DETECT_EN |
QSGMII_PHY_TX_DRIVER_EN |
QSGMII_PHY_QSGMII_EN |
- 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
- 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
- 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
- 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
- 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
+ 0x4ul << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
+ 0x3ul << QSGMII_PHY_RX_DC_BIAS_OFFSET |
+ 0x1ul << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
+ 0x2ul << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
+ 0xCul << QSGMII_PHY_TX_DRV_AMP_OFFSET);
}
plat_dat->has_gmac = true;
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
index 11baa4b..0cd3ecf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -354,7 +354,7 @@ static int gmac_clk_init(struct rk_priv_data *bsp_priv)
static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
{
- int phy_iface = phy_iface = bsp_priv->phy_iface;
+ int phy_iface = bsp_priv->phy_iface;
if (enable) {
if (!bsp_priv->clk_enabled) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
index 7f6f4a4..58c05ac 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -299,16 +299,17 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) {
const char *rs;
+ dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
+
err = of_property_read_string(np, "st,tx-retime-src", &rs);
if (err < 0) {
dev_warn(dev, "Use internal clock source\n");
- dwmac->tx_retime_src = TX_RETIME_SRC_CLKGEN;
- } else if (!strcasecmp(rs, "clk_125")) {
- dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
- } else if (!strcasecmp(rs, "txclk")) {
- dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
+ } else {
+ if (!strcasecmp(rs, "clk_125"))
+ dwmac->tx_retime_src = TX_RETIME_SRC_CLK_125;
+ else if (!strcasecmp(rs, "txclk"))
+ dwmac->tx_retime_src = TX_RETIME_SRC_TXCLK;
}
-
dwmac->speed = SPEED_1000;
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
index 52b8ed9..adff463 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
@@ -153,7 +153,11 @@ static int sun7i_gmac_probe(struct platform_device *pdev)
if (ret)
return ret;
- return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ ret = stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
+ if (ret)
+ sun7i_gmac_exit(pdev, plat_dat->bsp_priv);
+
+ return ret;
}
static const struct of_device_id sun7i_dwmac_match[] = {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 64d8aa4..a5b869e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -185,7 +185,7 @@ static void stmmac_clk_csr_set(struct stmmac_priv *priv)
priv->clk_csr = STMMAC_CSR_100_150M;
else if ((clk_rate >= CSR_F_150M) && (clk_rate < CSR_F_250M))
priv->clk_csr = STMMAC_CSR_150_250M;
- else if ((clk_rate >= CSR_F_250M) && (clk_rate < CSR_F_300M))
+ else if ((clk_rate >= CSR_F_250M) && (clk_rate <= CSR_F_300M))
priv->clk_csr = STMMAC_CSR_250_300M;
}
}
@@ -2232,6 +2232,12 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit)
frame_len = priv->hw->desc->get_rx_frame_len(p, coe);
+ /* check if frame_len fits the preallocated memory */
+ if (frame_len > priv->dma_buf_sz) {
+ priv->dev->stats.rx_length_errors++;
+ break;
+ }
+
/* ACS is set; GMAC core strips PAD/FCS for IEEE 802.3
* Type frames (LLC/LLC-SNAP)
*/
@@ -3040,8 +3046,6 @@ int stmmac_suspend(struct net_device *ndev)
priv->hw->dma->stop_tx(priv->ioaddr);
priv->hw->dma->stop_rx(priv->ioaddr);
- stmmac_clear_descriptors(priv);
-
/* Enable Power down mode by programming the PMT regs */
if (device_may_wakeup(priv->device)) {
priv->hw->mac->pmt(priv->hw, priv->wolopts);
@@ -3099,9 +3103,15 @@ int stmmac_resume(struct net_device *ndev)
netif_device_attach(ndev);
- init_dma_desc_rings(ndev, GFP_ATOMIC);
+ priv->cur_rx = 0;
+ priv->dirty_rx = 0;
+ priv->dirty_tx = 0;
+ priv->cur_tx = 0;
+ stmmac_clear_descriptors(priv);
+
stmmac_hw_setup(ndev, false);
stmmac_init_tx_coalesce(priv);
+ stmmac_set_rx_mode(ndev);
napi_enable(&priv->napi);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
index ebf6abc..bba670c 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
@@ -138,7 +138,6 @@ int stmmac_mdio_reset(struct mii_bus *bus)
#ifdef CONFIG_OF
if (priv->device->of_node) {
- int reset_gpio, active_low;
if (data->reset_gpio < 0) {
struct device_node *np = priv->device->of_node;
@@ -154,24 +153,23 @@ int stmmac_mdio_reset(struct mii_bus *bus)
"snps,reset-active-low");
of_property_read_u32_array(np,
"snps,reset-delays-us", data->delays, 3);
- }
- reset_gpio = data->reset_gpio;
- active_low = data->active_low;
+ if (gpio_request(data->reset_gpio, "mdio-reset"))
+ return 0;
+ }
- if (!gpio_request(reset_gpio, "mdio-reset")) {
- gpio_direction_output(reset_gpio, active_low ? 1 : 0);
- if (data->delays[0])
- msleep(DIV_ROUND_UP(data->delays[0], 1000));
+ gpio_direction_output(data->reset_gpio,
+ data->active_low ? 1 : 0);
+ if (data->delays[0])
+ msleep(DIV_ROUND_UP(data->delays[0], 1000));
- gpio_set_value(reset_gpio, active_low ? 0 : 1);
- if (data->delays[1])
- msleep(DIV_ROUND_UP(data->delays[1], 1000));
+ gpio_set_value(data->reset_gpio, data->active_low ? 0 : 1);
+ if (data->delays[1])
+ msleep(DIV_ROUND_UP(data->delays[1], 1000));
- gpio_set_value(reset_gpio, active_low ? 1 : 0);
- if (data->delays[2])
- msleep(DIV_ROUND_UP(data->delays[2], 1000));
- }
+ gpio_set_value(data->reset_gpio, data->active_low ? 1 : 0);
+ if (data->delays[2])
+ msleep(DIV_ROUND_UP(data->delays[2], 1000));
}
#endif
diff --git a/drivers/net/ethernet/synopsys/dwc_eth_qos.c b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
index 85b3326..9066d7a 100644
--- a/drivers/net/ethernet/synopsys/dwc_eth_qos.c
+++ b/drivers/net/ethernet/synopsys/dwc_eth_qos.c
@@ -2970,8 +2970,7 @@ err_out_unregister_netdev:
err_out_clk_dis_aper:
clk_disable_unprepare(lp->apb_pclk);
err_out_free_netdev:
- if (lp->phy_node)
- of_node_put(lp->phy_node);
+ of_node_put(lp->phy_node);
free_netdev(ndev);
platform_set_drvdata(pdev, NULL);
return ret;
diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c
index c08be62..1562ab4 100644
--- a/drivers/net/ethernet/ti/cpsw-common.c
+++ b/drivers/net/ethernet/ti/cpsw-common.c
@@ -78,6 +78,9 @@ static int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave,
int ti_cm_get_macid(struct device *dev, int slave, u8 *mac_addr)
{
+ if (of_machine_is_compatible("ti,dm8148"))
+ return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr);
+
if (of_machine_is_compatible("ti,am33xx"))
return cpsw_am33xx_cm_get_macid(dev, 0x630, slave, mac_addr);
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 040fbc1..fc95806 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -2026,11 +2026,8 @@ static int cpsw_probe_dt(struct cpsw_priv *priv,
for_each_child_of_node(node, slave_node) {
struct cpsw_slave_data *slave_data = data->slave_data + i;
const void *mac_addr = NULL;
- u32 phyid;
int lenp;
const __be32 *parp;
- struct device_node *mdio_node;
- struct platform_device *mdio;
/* This is no slave child node, continue */
if (strcmp(slave_node->name, "slave"))
@@ -2038,20 +2035,45 @@ static int cpsw_probe_dt(struct cpsw_priv *priv,
priv->phy_node = of_parse_phandle(slave_node, "phy-handle", 0);
parp = of_get_property(slave_node, "phy_id", &lenp);
- if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) {
- dev_err(&pdev->dev, "Missing slave[%d] phy_id property\n", i);
+ if (of_phy_is_fixed_link(slave_node)) {
+ struct device_node *phy_node;
+ struct phy_device *phy_dev;
+
+ /* In the case of a fixed PHY, the DT node associated
+ * to the PHY is the Ethernet MAC DT node.
+ */
+ ret = of_phy_register_fixed_link(slave_node);
+ if (ret)
+ return ret;
+ phy_node = of_node_get(slave_node);
+ phy_dev = of_phy_find_device(phy_node);
+ if (!phy_dev)
+ return -ENODEV;
+ snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+ PHY_ID_FMT, phy_dev->bus->id, phy_dev->addr);
+ } else if (parp) {
+ u32 phyid;
+ struct device_node *mdio_node;
+ struct platform_device *mdio;
+
+ if (lenp != (sizeof(__be32) * 2)) {
+ dev_err(&pdev->dev, "Invalid slave[%d] phy_id property\n", i);
+ goto no_phy_slave;
+ }
+ mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
+ phyid = be32_to_cpup(parp+1);
+ mdio = of_find_device_by_node(mdio_node);
+ of_node_put(mdio_node);
+ if (!mdio) {
+ dev_err(&pdev->dev, "Missing mdio platform device\n");
+ return -EINVAL;
+ }
+ snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
+ PHY_ID_FMT, mdio->name, phyid);
+ } else {
+ dev_err(&pdev->dev, "No slave[%d] phy_id or fixed-link property\n", i);
goto no_phy_slave;
}
- mdio_node = of_find_node_by_phandle(be32_to_cpup(parp));
- phyid = be32_to_cpup(parp+1);
- mdio = of_find_device_by_node(mdio_node);
- of_node_put(mdio_node);
- if (!mdio) {
- dev_err(&pdev->dev, "Missing mdio platform device\n");
- return -EINVAL;
- }
- snprintf(slave_data->phy_id, sizeof(slave_data->phy_id),
- PHY_ID_FMT, mdio->name, phyid);
slave_data->phy_if = of_get_phy_mode(slave_node);
if (slave_data->phy_if < 0) {
dev_err(&pdev->dev, "Missing or malformed slave[%d] phy-mode property\n",
@@ -2405,7 +2427,7 @@ static int cpsw_probe(struct platform_device *pdev)
ndev->irq = platform_get_irq(pdev, 1);
if (ndev->irq < 0) {
dev_err(priv->dev, "error getting irq resource\n");
- ret = -ENOENT;
+ ret = ndev->irq;
goto clean_ale_ret;
}
@@ -2426,8 +2448,10 @@ static int cpsw_probe(struct platform_device *pdev)
/* RX IRQ */
irq = platform_get_irq(pdev, 1);
- if (irq < 0)
+ if (irq < 0) {
+ ret = irq;
goto clean_ale_ret;
+ }
priv->irqs_table[0] = irq;
ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt,
@@ -2439,8 +2463,10 @@ static int cpsw_probe(struct platform_device *pdev)
/* TX IRQ */
irq = platform_get_irq(pdev, 2);
- if (irq < 0)
+ if (irq < 0) {
+ ret = irq;
goto clean_ale_ret;
+ }
priv->irqs_table[1] = irq;
ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt,
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index ae68afd..f38696c 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -345,13 +345,6 @@ VELOCITY_PARAM(flow_control, "Enable flow control ability");
*/
VELOCITY_PARAM(speed_duplex, "Setting the speed and duplex mode");
-#define VAL_PKT_LEN_DEF 0
-/* ValPktLen[] is used for setting the checksum offload ability of NIC.
- 0: Receive frame with invalid layer 2 length (Default)
- 1: Drop frame with invalid layer 2 length
-*/
-VELOCITY_PARAM(ValPktLen, "Receiving or Drop invalid 802.3 frame");
-
#define WOL_OPT_DEF 0
#define WOL_OPT_MIN 0
#define WOL_OPT_MAX 7
@@ -494,7 +487,6 @@ static void velocity_get_options(struct velocity_opt *opts, int index,
velocity_set_int_opt(&opts->flow_cntl, flow_control[index], FLOW_CNTL_MIN, FLOW_CNTL_MAX, FLOW_CNTL_DEF, "flow_control", devname);
velocity_set_bool_opt(&opts->flags, IP_byte_align[index], IP_ALIG_DEF, VELOCITY_FLAGS_IP_ALIGN, "IP_byte_align", devname);
- velocity_set_bool_opt(&opts->flags, ValPktLen[index], VAL_PKT_LEN_DEF, VELOCITY_FLAGS_VAL_PKT_LEN, "ValPktLen", devname);
velocity_set_int_opt((int *) &opts->spd_dpx, speed_duplex[index], MED_LNK_MIN, MED_LNK_MAX, MED_LNK_DEF, "Media link mode", devname);
velocity_set_int_opt(&opts->wol_opts, wol_opts[index], WOL_OPT_MIN, WOL_OPT_MAX, WOL_OPT_DEF, "Wake On Lan options", devname);
opts->numrx = (opts->numrx & ~3);
@@ -2055,8 +2047,9 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
int pkt_len = le16_to_cpu(rd->rdesc0.len) & 0x3fff;
struct sk_buff *skb;
- if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP)) {
- VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name);
+ if (unlikely(rd->rdesc0.RSR & (RSR_STP | RSR_EDP | RSR_RL))) {
+ if (rd->rdesc0.RSR & (RSR_STP | RSR_EDP))
+ VELOCITY_PRT(MSG_LEVEL_VERBOSE, KERN_ERR " %s : the received frame spans multiple RDs.\n", vptr->netdev->name);
stats->rx_length_errors++;
return -EINVAL;
}
@@ -2069,17 +2062,6 @@ static int velocity_receive_frame(struct velocity_info *vptr, int idx)
dma_sync_single_for_cpu(vptr->dev, rd_info->skb_dma,
vptr->rx.buf_sz, DMA_FROM_DEVICE);
- /*
- * Drop frame not meeting IEEE 802.3
- */
-
- if (vptr->flags & VELOCITY_FLAGS_VAL_PKT_LEN) {
- if (rd->rdesc0.RSR & RSR_RL) {
- stats->rx_length_errors++;
- return -EINVAL;
- }
- }
-
velocity_rx_csum(rd, skb);
if (velocity_rx_copy(&skb, pkt_len, vptr) < 0) {
diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c
index 2d3848c..b103adb 100644
--- a/drivers/net/fjes/fjes_hw.c
+++ b/drivers/net/fjes/fjes_hw.c
@@ -143,9 +143,7 @@ static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh)
static void fjes_hw_free_epbuf(struct epbuf_handler *epbh)
{
- if (epbh->buffer)
- vfree(epbh->buffer);
-
+ vfree(epbh->buffer);
epbh->buffer = NULL;
epbh->size = 0;
@@ -601,7 +599,7 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid)
FJES_CMD_REQ_RES_CODE_BUSY) &&
(timeout > 0)) {
msleep(200 + hw->my_epid * 20);
- timeout -= (200 + hw->my_epid * 20);
+ timeout -= (200 + hw->my_epid * 20);
res_buf->unshare_buffer.length = 0;
res_buf->unshare_buffer.code = 0;
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index de5c30c..58efdec 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -967,8 +967,6 @@ static netdev_tx_t geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
err = udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
&fl6.saddr, &fl6.daddr, prio, ttl,
sport, geneve->dst_port, !udp_csum);
-
- iptunnel_xmit_stats(err, &dev->stats, dev->tstats);
return NETDEV_TX_OK;
tx_error:
@@ -1157,7 +1155,7 @@ static int geneve_configure(struct net *net, struct net_device *dev,
struct geneve_net *gn = net_generic(net, geneve_net_id);
struct geneve_dev *t, *geneve = netdev_priv(dev);
bool tun_collect_md, tun_on_same_port;
- int err;
+ int err, encap_len;
if (!remote)
return -EINVAL;
@@ -1189,6 +1187,14 @@ static int geneve_configure(struct net *net, struct net_device *dev,
if (t)
return -EBUSY;
+ /* make enough headroom for basic scenario */
+ encap_len = GENEVE_BASE_HLEN + ETH_HLEN;
+ if (remote->sa.sa_family == AF_INET)
+ encap_len += sizeof(struct iphdr);
+ else
+ encap_len += sizeof(struct ipv6hdr);
+ dev->needed_headroom = encap_len + ETH_HLEN;
+
if (metadata) {
if (tun_on_same_port)
return -EPERM;
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 7c4a415..5a1e985 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -683,14 +683,20 @@ static void sixpack_close(struct tty_struct *tty)
if (!atomic_dec_and_test(&sp->refcnt))
down(&sp->dead_sem);
- unregister_netdev(sp->dev);
+ /* We must stop the queue to avoid potentially scribbling
+ * on the free buffers. The sp->dead_sem is not sufficient
+ * to protect us from sp->xbuff access.
+ */
+ netif_stop_queue(sp->dev);
- del_timer(&sp->tx_t);
- del_timer(&sp->resync_t);
+ del_timer_sync(&sp->tx_t);
+ del_timer_sync(&sp->resync_t);
/* Free all 6pack frame buffers. */
kfree(sp->rbuff);
kfree(sp->xbuff);
+
+ unregister_netdev(sp->dev);
}
/* Perform I/O control on an active 6pack channel. */
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 216bfd3..85828f1 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -797,14 +797,19 @@ static void mkiss_close(struct tty_struct *tty)
*/
if (!atomic_dec_and_test(&ax->refcnt))
down(&ax->dead_sem);
-
- unregister_netdev(ax->dev);
+ /*
+ * Halt the transmit queue so that a new transmit cannot scribble
+ * on our buffers
+ */
+ netif_stop_queue(ax->dev);
/* Free all AX25 frame buffers. */
kfree(ax->rbuff);
kfree(ax->xbuff);
ax->tty = NULL;
+
+ unregister_netdev(ax->dev);
}
/* Perform I/O control on an active ax25 channel. */
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index d50887e..8c48bb2 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -254,7 +254,7 @@ acct:
}
}
-static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
+static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
bool local)
{
struct ipvl_dev *ipvlan = addr->master;
@@ -262,6 +262,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
unsigned int len;
rx_handler_result_t ret = RX_HANDLER_CONSUMED;
bool success = false;
+ struct sk_buff *skb = *pskb;
len = skb->len + ETH_HLEN;
if (unlikely(!(dev->flags & IFF_UP))) {
@@ -273,6 +274,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff *skb,
if (!skb)
goto out;
+ *pskb = skb;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
@@ -486,7 +488,7 @@ static int ipvlan_xmit_mode_l3(struct sk_buff *skb, struct net_device *dev)
addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
if (addr)
- return ipvlan_rcv_frame(addr, skb, true);
+ return ipvlan_rcv_frame(addr, &skb, true);
out:
skb->dev = ipvlan->phy_dev;
@@ -506,7 +508,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev)
if (lyr3h) {
addr = ipvlan_addr_lookup(ipvlan->port, lyr3h, addr_type, true);
if (addr)
- return ipvlan_rcv_frame(addr, skb, true);
+ return ipvlan_rcv_frame(addr, &skb, true);
}
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
@@ -589,7 +591,7 @@ static rx_handler_result_t ipvlan_handle_mode_l3(struct sk_buff **pskb,
addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
if (addr)
- ret = ipvlan_rcv_frame(addr, skb, false);
+ ret = ipvlan_rcv_frame(addr, pskb, false);
out:
return ret;
@@ -626,7 +628,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb,
addr = ipvlan_addr_lookup(port, lyr3h, addr_type, true);
if (addr)
- ret = ipvlan_rcv_frame(addr, skb, false);
+ ret = ipvlan_rcv_frame(addr, pskb, false);
}
return ret;
@@ -651,5 +653,5 @@ rx_handler_result_t ipvlan_handle_frame(struct sk_buff **pskb)
WARN_ONCE(true, "ipvlan_handle_frame() called for mode = [%hx]\n",
port->mode);
kfree_skb(skb);
- return NET_RX_DROP;
+ return RX_HANDLER_CONSUMED;
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 86f6c62..06c8bfe 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -415,6 +415,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
skb = ip_check_defrag(dev_net(skb->dev), skb, IP_DEFRAG_MACVLAN);
if (!skb)
return RX_HANDLER_CONSUMED;
+ *pskb = skb;
eth = eth_hdr(skb);
macvlan_forward_source(skb, port, eth->h_source);
src = macvlan_hash_lookup(port, eth->h_source);
@@ -456,6 +457,7 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)
goto out;
}
+ *pskb = skb;
skb->dev = dev;
skb->pkt_type = PACKET_HOST;
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 197c939..0fc5219 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -498,7 +498,7 @@ static void macvtap_sock_write_space(struct sock *sk)
wait_queue_head_t *wqueue;
if (!sock_writeable(sk) ||
- !test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
+ !test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags))
return;
wqueue = sk_sleep(sk);
@@ -585,7 +585,7 @@ static unsigned int macvtap_poll(struct file *file, poll_table * wait)
mask |= POLLIN | POLLRDNORM;
if (sock_writeable(&q->sk) ||
- (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &q->sock.flags) &&
+ (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &q->sock.flags) &&
sock_writeable(&q->sk)))
mask |= POLLOUT | POLLWRNORM;
@@ -935,6 +935,9 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q,
/* Nothing to read, let's sleep */
schedule();
}
+ if (!noblock)
+ finish_wait(sk_sleep(&q->sk), &wait);
+
if (skb) {
ret = macvtap_put_user(q, skb, to);
if (unlikely(ret < 0))
@@ -942,8 +945,6 @@ static ssize_t macvtap_do_read(struct macvtap_queue *q,
else
consume_skb(skb);
}
- if (!noblock)
- finish_wait(sk_sleep(&q->sk), &wait);
return ret;
}
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 97f3acd..06ee639 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -244,15 +244,6 @@ static void free_param_target(struct netconsole_target *nt)
* <target>/...
*/
-struct netconsole_target_attr {
- struct configfs_attribute attr;
- ssize_t (*show)(struct netconsole_target *nt,
- char *buf);
- ssize_t (*store)(struct netconsole_target *nt,
- const char *buf,
- size_t count);
-};
-
static struct netconsole_target *to_target(struct config_item *item)
{
return item ?
@@ -264,58 +255,62 @@ static struct netconsole_target *to_target(struct config_item *item)
* Attribute operations for netconsole_target.
*/
-static ssize_t show_enabled(struct netconsole_target *nt, char *buf)
+static ssize_t enabled_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", nt->enabled);
+ return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->enabled);
}
-static ssize_t show_extended(struct netconsole_target *nt, char *buf)
+static ssize_t extended_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", nt->extended);
+ return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->extended);
}
-static ssize_t show_dev_name(struct netconsole_target *nt, char *buf)
+static ssize_t dev_name_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%s\n", nt->np.dev_name);
+ return snprintf(buf, PAGE_SIZE, "%s\n", to_target(item)->np.dev_name);
}
-static ssize_t show_local_port(struct netconsole_target *nt, char *buf)
+static ssize_t local_port_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.local_port);
+ return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.local_port);
}
-static ssize_t show_remote_port(struct netconsole_target *nt, char *buf)
+static ssize_t remote_port_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", nt->np.remote_port);
+ return snprintf(buf, PAGE_SIZE, "%d\n", to_target(item)->np.remote_port);
}
-static ssize_t show_local_ip(struct netconsole_target *nt, char *buf)
+static ssize_t local_ip_show(struct config_item *item, char *buf)
{
+ struct netconsole_target *nt = to_target(item);
+
if (nt->np.ipv6)
return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.local_ip.in6);
else
return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.local_ip);
}
-static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf)
+static ssize_t remote_ip_show(struct config_item *item, char *buf)
{
+ struct netconsole_target *nt = to_target(item);
+
if (nt->np.ipv6)
return snprintf(buf, PAGE_SIZE, "%pI6c\n", &nt->np.remote_ip.in6);
else
return snprintf(buf, PAGE_SIZE, "%pI4\n", &nt->np.remote_ip);
}
-static ssize_t show_local_mac(struct netconsole_target *nt, char *buf)
+static ssize_t local_mac_show(struct config_item *item, char *buf)
{
- struct net_device *dev = nt->np.dev;
+ struct net_device *dev = to_target(item)->np.dev;
static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast);
}
-static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
+static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac);
+ return snprintf(buf, PAGE_SIZE, "%pM\n", to_target(item)->np.remote_mac);
}
/*
@@ -325,23 +320,26 @@ static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf)
* would enable him to dynamically add new netpoll targets for new
* network interfaces as and when they come up).
*/
-static ssize_t store_enabled(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t enabled_store(struct config_item *item,
+ const char *buf, size_t count)
{
+ struct netconsole_target *nt = to_target(item);
unsigned long flags;
int enabled;
int err;
+ mutex_lock(&dynamic_netconsole_mutex);
err = kstrtoint(buf, 10, &enabled);
if (err < 0)
- return err;
+ goto out_unlock;
+
+ err = -EINVAL;
if (enabled < 0 || enabled > 1)
- return -EINVAL;
+ goto out_unlock;
if ((bool)enabled == nt->enabled) {
pr_info("network logging has already %s\n",
nt->enabled ? "started" : "stopped");
- return -EINVAL;
+ goto out_unlock;
}
if (enabled) { /* true */
@@ -358,7 +356,7 @@ static ssize_t store_enabled(struct netconsole_target *nt,
err = netpoll_setup(&nt->np);
if (err)
- return err;
+ goto out_unlock;
pr_info("netconsole: network logging started\n");
} else { /* false */
@@ -374,42 +372,56 @@ static ssize_t store_enabled(struct netconsole_target *nt,
nt->enabled = enabled;
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return err;
}
-static ssize_t store_extended(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t extended_store(struct config_item *item, const char *buf,
+ size_t count)
{
+ struct netconsole_target *nt = to_target(item);
int extended;
int err;
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ err = -EINVAL;
+ goto out_unlock;
}
err = kstrtoint(buf, 10, &extended);
if (err < 0)
- return err;
- if (extended < 0 || extended > 1)
- return -EINVAL;
+ goto out_unlock;
+ if (extended < 0 || extended > 1) {
+ err = -EINVAL;
+ goto out_unlock;
+ }
nt->extended = extended;
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return err;
}
-static ssize_t store_dev_name(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t dev_name_store(struct config_item *item, const char *buf,
+ size_t count)
{
+ struct netconsole_target *nt = to_target(item);
size_t len;
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
+ mutex_unlock(&dynamic_netconsole_mutex);
return -EINVAL;
}
@@ -420,53 +432,66 @@ static ssize_t store_dev_name(struct netconsole_target *nt,
if (nt->np.dev_name[len - 1] == '\n')
nt->np.dev_name[len - 1] = '\0';
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
}
-static ssize_t store_local_port(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t local_port_store(struct config_item *item, const char *buf,
+ size_t count)
{
- int rv;
+ struct netconsole_target *nt = to_target(item);
+ int rv = -EINVAL;
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ goto out_unlock;
}
rv = kstrtou16(buf, 10, &nt->np.local_port);
if (rv < 0)
- return rv;
+ goto out_unlock;
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return rv;
}
-static ssize_t store_remote_port(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t remote_port_store(struct config_item *item,
+ const char *buf, size_t count)
{
- int rv;
+ struct netconsole_target *nt = to_target(item);
+ int rv = -EINVAL;
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ goto out_unlock;
}
rv = kstrtou16(buf, 10, &nt->np.remote_port);
if (rv < 0)
- return rv;
+ goto out_unlock;
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return rv;
}
-static ssize_t store_local_ip(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t local_ip_store(struct config_item *item, const char *buf,
+ size_t count)
{
+ struct netconsole_target *nt = to_target(item);
+
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ goto out_unlock;
}
if (strnchr(buf, count, ':')) {
@@ -474,29 +499,35 @@ static ssize_t store_local_ip(struct netconsole_target *nt,
if (in6_pton(buf, count, nt->np.local_ip.in6.s6_addr, -1, &end) > 0) {
if (*end && *end != '\n') {
pr_err("invalid IPv6 address at: <%c>\n", *end);
- return -EINVAL;
+ goto out_unlock;
}
nt->np.ipv6 = true;
} else
- return -EINVAL;
+ goto out_unlock;
} else {
if (!nt->np.ipv6) {
nt->np.local_ip.ip = in_aton(buf);
} else
- return -EINVAL;
+ goto out_unlock;
}
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return -EINVAL;
}
-static ssize_t store_remote_ip(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t remote_ip_store(struct config_item *item, const char *buf,
+ size_t count)
{
+ struct netconsole_target *nt = to_target(item);
+
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ goto out_unlock;
}
if (strnchr(buf, count, ':')) {
@@ -504,74 +535,71 @@ static ssize_t store_remote_ip(struct netconsole_target *nt,
if (in6_pton(buf, count, nt->np.remote_ip.in6.s6_addr, -1, &end) > 0) {
if (*end && *end != '\n') {
pr_err("invalid IPv6 address at: <%c>\n", *end);
- return -EINVAL;
+ goto out_unlock;
}
nt->np.ipv6 = true;
} else
- return -EINVAL;
+ goto out_unlock;
} else {
if (!nt->np.ipv6) {
nt->np.remote_ip.ip = in_aton(buf);
} else
- return -EINVAL;
+ goto out_unlock;
}
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return -EINVAL;
}
-static ssize_t store_remote_mac(struct netconsole_target *nt,
- const char *buf,
- size_t count)
+static ssize_t remote_mac_store(struct config_item *item, const char *buf,
+ size_t count)
{
+ struct netconsole_target *nt = to_target(item);
u8 remote_mac[ETH_ALEN];
+ mutex_lock(&dynamic_netconsole_mutex);
if (nt->enabled) {
pr_err("target (%s) is enabled, disable to update parameters\n",
config_item_name(&nt->item));
- return -EINVAL;
+ goto out_unlock;
}
if (!mac_pton(buf, remote_mac))
- return -EINVAL;
+ goto out_unlock;
if (buf[3 * ETH_ALEN - 1] && buf[3 * ETH_ALEN - 1] != '\n')
- return -EINVAL;
+ goto out_unlock;
memcpy(nt->np.remote_mac, remote_mac, ETH_ALEN);
+ mutex_unlock(&dynamic_netconsole_mutex);
return strnlen(buf, count);
+out_unlock:
+ mutex_unlock(&dynamic_netconsole_mutex);
+ return -EINVAL;
}
-/*
- * Attribute definitions for netconsole_target.
- */
-
-#define NETCONSOLE_TARGET_ATTR_RO(_name) \
-static struct netconsole_target_attr netconsole_target_##_name = \
- __CONFIGFS_ATTR(_name, S_IRUGO, show_##_name, NULL)
-
-#define NETCONSOLE_TARGET_ATTR_RW(_name) \
-static struct netconsole_target_attr netconsole_target_##_name = \
- __CONFIGFS_ATTR(_name, S_IRUGO | S_IWUSR, show_##_name, store_##_name)
-
-NETCONSOLE_TARGET_ATTR_RW(enabled);
-NETCONSOLE_TARGET_ATTR_RW(extended);
-NETCONSOLE_TARGET_ATTR_RW(dev_name);
-NETCONSOLE_TARGET_ATTR_RW(local_port);
-NETCONSOLE_TARGET_ATTR_RW(remote_port);
-NETCONSOLE_TARGET_ATTR_RW(local_ip);
-NETCONSOLE_TARGET_ATTR_RW(remote_ip);
-NETCONSOLE_TARGET_ATTR_RO(local_mac);
-NETCONSOLE_TARGET_ATTR_RW(remote_mac);
+CONFIGFS_ATTR(, enabled);
+CONFIGFS_ATTR(, extended);
+CONFIGFS_ATTR(, dev_name);
+CONFIGFS_ATTR(, local_port);
+CONFIGFS_ATTR(, remote_port);
+CONFIGFS_ATTR(, local_ip);
+CONFIGFS_ATTR(, remote_ip);
+CONFIGFS_ATTR_RO(, local_mac);
+CONFIGFS_ATTR(, remote_mac);
static struct configfs_attribute *netconsole_target_attrs[] = {
- &netconsole_target_enabled.attr,
- &netconsole_target_extended.attr,
- &netconsole_target_dev_name.attr,
- &netconsole_target_local_port.attr,
- &netconsole_target_remote_port.attr,
- &netconsole_target_local_ip.attr,
- &netconsole_target_remote_ip.attr,
- &netconsole_target_local_mac.attr,
- &netconsole_target_remote_mac.attr,
+ &attr_enabled,
+ &attr_extended,
+ &attr_dev_name,
+ &attr_local_port,
+ &attr_remote_port,
+ &attr_local_ip,
+ &attr_remote_ip,
+ &attr_local_mac,
+ &attr_remote_mac,
NULL,
};
@@ -584,43 +612,8 @@ static void netconsole_target_release(struct config_item *item)
kfree(to_target(item));
}
-static ssize_t netconsole_target_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *buf)
-{
- ssize_t ret = -EINVAL;
- struct netconsole_target *nt = to_target(item);
- struct netconsole_target_attr *na =
- container_of(attr, struct netconsole_target_attr, attr);
-
- if (na->show)
- ret = na->show(nt, buf);
-
- return ret;
-}
-
-static ssize_t netconsole_target_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *buf,
- size_t count)
-{
- ssize_t ret = -EINVAL;
- struct netconsole_target *nt = to_target(item);
- struct netconsole_target_attr *na =
- container_of(attr, struct netconsole_target_attr, attr);
-
- mutex_lock(&dynamic_netconsole_mutex);
- if (na->store)
- ret = na->store(nt, buf, count);
- mutex_unlock(&dynamic_netconsole_mutex);
-
- return ret;
-}
-
static struct configfs_item_operations netconsole_target_item_ops = {
.release = netconsole_target_release,
- .show_attribute = netconsole_target_attr_show,
- .store_attribute = netconsole_target_attr_store,
};
static struct config_item_type netconsole_target_type = {
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
index fabf11d..2d020a3 100644
--- a/drivers/net/phy/at803x.c
+++ b/drivers/net/phy/at803x.c
@@ -308,6 +308,8 @@ static struct phy_driver at803x_driver[] = {
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = at803x_ack_interrupt,
+ .config_intr = at803x_config_intr,
.driver = {
.owner = THIS_MODULE,
},
@@ -327,6 +329,8 @@ static struct phy_driver at803x_driver[] = {
.flags = PHY_HAS_INTERRUPT,
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
+ .ack_interrupt = at803x_ack_interrupt,
+ .config_intr = at803x_config_intr,
.driver = {
.owner = THIS_MODULE,
},
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 07a6119..3ce5d95 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -614,7 +614,7 @@ static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM5461, 0xfffffff0 },
{ PHY_ID_BCM54616S, 0xfffffff0 },
{ PHY_ID_BCM5464, 0xfffffff0 },
- { PHY_ID_BCM5482, 0xfffffff0 },
+ { PHY_ID_BCM5481, 0xfffffff0 },
{ PHY_ID_BCM5482, 0xfffffff0 },
{ PHY_ID_BCM50610, 0xfffffff0 },
{ PHY_ID_BCM50610M, 0xfffffff0 },
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 5de8d58..0240552 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -1154,6 +1154,21 @@ static struct phy_driver marvell_drivers[] = {
.driver = { .owner = THIS_MODULE },
},
{
+ .phy_id = MARVELL_PHY_ID_88E1540,
+ .phy_id_mask = MARVELL_PHY_ID_MASK,
+ .name = "Marvell 88E1540",
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_aneg = &m88e1510_config_aneg,
+ .read_status = &marvell_read_status,
+ .ack_interrupt = &marvell_ack_interrupt,
+ .config_intr = &marvell_config_intr,
+ .did_interrupt = &m88e1121_did_interrupt,
+ .resume = &genphy_resume,
+ .suspend = &genphy_suspend,
+ .driver = { .owner = THIS_MODULE },
+ },
+ {
.phy_id = MARVELL_PHY_ID_88E3016,
.phy_id_mask = MARVELL_PHY_ID_MASK,
.name = "Marvell 88E3016",
@@ -1186,6 +1201,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
{ MARVELL_PHY_ID_88E1318S, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1116R, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E1510, MARVELL_PHY_ID_MASK },
+ { MARVELL_PHY_ID_88E1540, MARVELL_PHY_ID_MASK },
{ MARVELL_PHY_ID_88E3016, MARVELL_PHY_ID_MASK },
{ }
};
diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c
index 908e8d4..7f8e766 100644
--- a/drivers/net/phy/mdio-mux.c
+++ b/drivers/net/phy/mdio-mux.c
@@ -149,9 +149,14 @@ int mdio_mux_init(struct device *dev,
}
cb->bus_number = v;
cb->parent = pb;
+
cb->mii_bus = mdiobus_alloc();
+ if (!cb->mii_bus) {
+ ret_val = -ENOMEM;
+ of_node_put(child_bus_node);
+ break;
+ }
cb->mii_bus->priv = cb;
-
cb->mii_bus->irq = cb->phy_irq;
cb->mii_bus->name = "mdio_mux";
snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%x.%x",
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index cf6312f..e13ad6c 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -339,9 +339,18 @@ static int ksz9021_config_init(struct phy_device *phydev)
{
const struct device *dev = &phydev->dev;
const struct device_node *of_node = dev->of_node;
+ const struct device *dev_walker;
- if (!of_node && dev->parent->of_node)
- of_node = dev->parent->of_node;
+ /* The Micrel driver has a deprecated option to place phy OF
+ * properties in the MAC node. Walk up the tree of devices to
+ * find a device with an OF node.
+ */
+ dev_walker = &phydev->dev;
+ do {
+ of_node = dev_walker->of_node;
+ dev_walker = dev_walker->parent;
+
+ } while (!of_node && dev_walker);
if (of_node) {
ksz9021_load_values_from_of(phydev, of_node,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index adb48ab..47cd306d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -448,7 +448,8 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
mdiobus_write(phydev->bus, mii_data->phy_id,
mii_data->reg_num, val);
- if (mii_data->reg_num == MII_BMCR &&
+ if (mii_data->phy_id == phydev->addr &&
+ mii_data->reg_num == MII_BMCR &&
val & BMCR_RESET)
return phy_init_hw(phydev);
@@ -863,6 +864,9 @@ void phy_state_machine(struct work_struct *work)
needs_aneg = true;
break;
case PHY_NOLINK:
+ if (phy_interrupt_is_valid(phydev))
+ break;
+
err = phy_read_status(phydev);
if (err)
break;
diff --git a/drivers/net/phy/vitesse.c b/drivers/net/phy/vitesse.c
index 76cad71..dd295db 100644
--- a/drivers/net/phy/vitesse.c
+++ b/drivers/net/phy/vitesse.c
@@ -66,6 +66,7 @@
#define PHY_ID_VSC8244 0x000fc6c0
#define PHY_ID_VSC8514 0x00070670
#define PHY_ID_VSC8574 0x000704a0
+#define PHY_ID_VSC8601 0x00070420
#define PHY_ID_VSC8662 0x00070660
#define PHY_ID_VSC8221 0x000fc550
#define PHY_ID_VSC8211 0x000fc4b0
@@ -133,7 +134,8 @@ static int vsc82xx_config_intr(struct phy_device *phydev)
(phydev->drv->phy_id == PHY_ID_VSC8234 ||
phydev->drv->phy_id == PHY_ID_VSC8244 ||
phydev->drv->phy_id == PHY_ID_VSC8514 ||
- phydev->drv->phy_id == PHY_ID_VSC8574) ?
+ phydev->drv->phy_id == PHY_ID_VSC8574 ||
+ phydev->drv->phy_id == PHY_ID_VSC8601) ?
MII_VSC8244_IMASK_MASK :
MII_VSC8221_IMASK_MASK);
else {
@@ -272,6 +274,18 @@ static struct phy_driver vsc82xx_driver[] = {
.config_intr = &vsc82xx_config_intr,
.driver = { .owner = THIS_MODULE,},
}, {
+ .phy_id = PHY_ID_VSC8601,
+ .name = "Vitesse VSC8601",
+ .phy_id_mask = 0x000ffff0,
+ .features = PHY_GBIT_FEATURES,
+ .flags = PHY_HAS_INTERRUPT,
+ .config_init = &genphy_config_init,
+ .config_aneg = &genphy_config_aneg,
+ .read_status = &genphy_read_status,
+ .ack_interrupt = &vsc824x_ack_interrupt,
+ .config_intr = &vsc82xx_config_intr,
+ .driver = { .owner = THIS_MODULE,},
+}, {
.phy_id = PHY_ID_VSC8662,
.name = "Vitesse VSC8662",
.phy_id_mask = 0x000ffff0,
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 5e0b432..0a37f84 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -568,6 +568,9 @@ static int pppoe_create(struct net *net, struct socket *sock, int kern)
sk->sk_family = PF_PPPOX;
sk->sk_protocol = PX_PROTO_OE;
+ INIT_WORK(&pppox_sk(sk)->proto.pppoe.padt_work,
+ pppoe_unbind_sock_work);
+
return 0;
}
@@ -632,8 +635,6 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
lock_sock(sk);
- INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
-
error = -EINVAL;
if (sp->sa_protocol != PX_PROTO_OE)
goto end;
@@ -663,8 +664,13 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->pppoe_dev = NULL;
}
- memset(sk_pppox(po) + 1, 0,
- sizeof(struct pppox_sock) - sizeof(struct sock));
+ po->pppoe_ifindex = 0;
+ memset(&po->pppoe_pa, 0, sizeof(po->pppoe_pa));
+ memset(&po->pppoe_relay, 0, sizeof(po->pppoe_relay));
+ memset(&po->chan, 0, sizeof(po->chan));
+ po->next = NULL;
+ po->num = 0;
+
sk->sk_state = PPPOX_NONE;
}
diff --git a/drivers/net/ppp/pptp.c b/drivers/net/ppp/pptp.c
index fc69e41..597c53e 100644
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -419,6 +419,9 @@ static int pptp_bind(struct socket *sock, struct sockaddr *uservaddr,
struct pptp_opt *opt = &po->proto.pptp;
int error = 0;
+ if (sockaddr_len < sizeof(struct sockaddr_pppox))
+ return -EINVAL;
+
lock_sock(sk);
opt->src_addr = sp->sa_addr.pptp;
@@ -440,6 +443,9 @@ static int pptp_connect(struct socket *sock, struct sockaddr *uservaddr,
struct flowi4 fl4;
int error = 0;
+ if (sockaddr_len < sizeof(struct sockaddr_pppox))
+ return -EINVAL;
+
if (sp->sa_protocol != PX_PROTO_PPTP)
return -EINVAL;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index b1878fa..f0db770 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1040,7 +1040,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table *wait)
mask |= POLLIN | POLLRDNORM;
if (sock_writeable(sk) ||
- (!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
+ (!test_and_set_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
sock_writeable(sk)))
mask |= POLLOUT | POLLWRNORM;
@@ -1488,7 +1488,7 @@ static void tun_sock_write_space(struct sock *sk)
if (!sock_writeable(sk))
return;
- if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags))
+ if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sk->sk_socket->flags))
return;
wqueue = sk_sleep(sk);
diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c
index c78d3cb..3da70bf 100644
--- a/drivers/net/usb/cdc_ether.c
+++ b/drivers/net/usb/cdc_ether.c
@@ -696,6 +696,11 @@ static const struct usb_device_id products[] = {
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
.driver_info = (kernel_ulong_t) &wwan_info,
}, {
+ /* Dell DW5580 modules */
+ USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, 0x81ba, USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
+ .driver_info = (kernel_ulong_t)&wwan_info,
+}, {
USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
USB_CDC_PROTO_NONE),
.driver_info = (unsigned long) &cdc_info,
diff --git a/drivers/net/usb/cdc_mbim.c b/drivers/net/usb/cdc_mbim.c
index bbde988..bdd83d9 100644
--- a/drivers/net/usb/cdc_mbim.c
+++ b/drivers/net/usb/cdc_mbim.c
@@ -100,7 +100,7 @@ static const struct net_device_ops cdc_mbim_netdev_ops = {
.ndo_stop = usbnet_stop,
.ndo_start_xmit = usbnet_start_xmit,
.ndo_tx_timeout = usbnet_tx_timeout,
- .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_change_mtu = cdc_ncm_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
.ndo_vlan_rx_add_vid = cdc_mbim_rx_add_vid,
@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *dev, struct usb_interface *intf)
if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
goto err;
- ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
+ ret = cdc_ncm_bind_common(dev, intf, data_altsetting, dev->driver_info->data);
if (ret)
goto err;
@@ -582,6 +582,26 @@ static const struct driver_info cdc_mbim_info_zlp = {
.tx_fixup = cdc_mbim_tx_fixup,
};
+/* The spefication explicitly allows NDPs to be placed anywhere in the
+ * frame, but some devices fail unless the NDP is placed after the IP
+ * packets. Using the CDC_NCM_FLAG_NDP_TO_END flags to force this
+ * behaviour.
+ *
+ * Note: The current implementation of this feature restricts each NTB
+ * to a single NDP, implying that multiplexed sessions cannot share an
+ * NTB. This might affect performace for multiplexed sessions.
+ */
+static const struct driver_info cdc_mbim_info_ndp_to_end = {
+ .description = "CDC MBIM",
+ .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+ .bind = cdc_mbim_bind,
+ .unbind = cdc_mbim_unbind,
+ .manage_power = cdc_mbim_manage_power,
+ .rx_fixup = cdc_mbim_rx_fixup,
+ .tx_fixup = cdc_mbim_tx_fixup,
+ .data = CDC_NCM_FLAG_NDP_TO_END,
+};
+
static const struct usb_device_id mbim_devs[] = {
/* This duplicate NCM entry is intentional. MBIM devices can
* be disguised as NCM by default, and this is necessary to
@@ -597,6 +617,10 @@ static const struct usb_device_id mbim_devs[] = {
{ USB_VENDOR_AND_INTERFACE_INFO(0x0bdb, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info,
},
+ /* Huawei E3372 fails unless NDP comes after the IP packets */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x12d1, 0x157d, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
+ },
/* default entry */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
.driver_info = (unsigned long)&cdc_mbim_info_zlp,
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
index a187f08..e8a1144 100644
--- a/drivers/net/usb/cdc_ncm.c
+++ b/drivers/net/usb/cdc_ncm.c
@@ -41,6 +41,7 @@
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/ctype.h>
+#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/workqueue.h>
#include <linux/mii.h>
@@ -689,9 +690,35 @@ static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
kfree(ctx);
}
+/* we need to override the usbnet change_mtu ndo for two reasons:
+ * - respect the negotiated maximum datagram size
+ * - avoid unwanted changes to rx and tx buffers
+ */
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+ int maxmtu = ctx->max_datagram_size - cdc_ncm_eth_hlen(dev);
+
+ if (new_mtu <= 0 || new_mtu > maxmtu)
+ return -EINVAL;
+ net->mtu = new_mtu;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cdc_ncm_change_mtu);
+
+static const struct net_device_ops cdc_ncm_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = cdc_ncm_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
{
- const struct usb_cdc_union_desc *union_desc = NULL;
struct cdc_ncm_ctx *ctx;
struct usb_driver *driver;
u8 *buf;
@@ -725,15 +752,16 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
/* parse through descriptors associated with control interface */
cdc_parse_cdc_header(&hdr, intf, buf, len);
- ctx->data = usb_ifnum_to_if(dev->udev,
- hdr.usb_cdc_union_desc->bSlaveInterface0);
+ if (hdr.usb_cdc_union_desc)
+ ctx->data = usb_ifnum_to_if(dev->udev,
+ hdr.usb_cdc_union_desc->bSlaveInterface0);
ctx->ether_desc = hdr.usb_cdc_ether_desc;
ctx->func_desc = hdr.usb_cdc_ncm_desc;
ctx->mbim_desc = hdr.usb_cdc_mbim_desc;
ctx->mbim_extended_desc = hdr.usb_cdc_mbim_extended_desc;
/* some buggy devices have an IAD but no CDC Union */
- if (!union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
+ if (!hdr.usb_cdc_union_desc && intf->intf_assoc && intf->intf_assoc->bInterfaceCount == 2) {
ctx->data = usb_ifnum_to_if(dev->udev, intf->cur_altsetting->desc.bInterfaceNumber + 1);
dev_dbg(&intf->dev, "CDC Union missing - got slave from IAD\n");
}
@@ -823,6 +851,9 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
/* add our sysfs attrs */
dev->net->sysfs_groups[0] = &cdc_ncm_sysfs_attr_group;
+ /* must handle MTU changes */
+ dev->net->netdev_ops = &cdc_ncm_netdev_ops;
+
return 0;
error2:
@@ -955,10 +986,18 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm_ndp(struct cdc_ncm_ctx *ctx, struct sk_
* NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
* the wNdpIndex field in the header is actually not consistent with reality. It will be later.
*/
- if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
+ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
if (ctx->delayed_ndp16->dwSignature == sign)
return ctx->delayed_ndp16;
+ /* We can only push a single NDP to the end. Return
+ * NULL to send what we've already got and queue this
+ * skb for later.
+ */
+ else if (ctx->delayed_ndp16->dwSignature)
+ return NULL;
+ }
+
/* follow the chain of NDPs, looking for a match */
while (ndpoffset) {
ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
@@ -1550,6 +1589,24 @@ static const struct usb_device_id cdc_devs[] = {
.driver_info = (unsigned long) &wwan_info,
},
+ /* DW5812 LTE Verizon Mobile Broadband Card
+ * Unlike DW5550 this device requires FLAG_NOARP
+ */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bb,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&wwan_noarp_info,
+ },
+
+ /* DW5813 LTE AT&T Mobile Broadband Card
+ * Unlike DW5550 this device requires FLAG_NOARP
+ */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x413c, 0x81bc,
+ USB_CLASS_COMM,
+ USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+ .driver_info = (unsigned long)&wwan_noarp_info,
+ },
+
/* Dell branded MBM devices like DW5550 */
{ .match_flags = USB_DEVICE_ID_MATCH_INT_INFO
| USB_DEVICE_ID_MATCH_VENDOR,
diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c
index 1e9cdca..f64b25c 100644
--- a/drivers/net/usb/kaweth.c
+++ b/drivers/net/usb/kaweth.c
@@ -1177,12 +1177,6 @@ err_fw:
INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl);
usb_set_intfdata(intf, kaweth);
-#if 0
-// dma_supported() is deeply broken on almost all architectures
- if (dma_supported (dev, 0xffffffffffffffffULL))
- kaweth->net->features |= NETIF_F_HIGHDMA;
-#endif
-
SET_NETDEV_DEV(netdev, dev);
if (register_netdev(netdev) != 0) {
dev_err(dev, "Error registering netdev.\n");
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index c547199..5fccc5a 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -725,6 +725,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */
{QMI_FIXED_INTF(0x1bc7, 0x1200, 5)}, /* Telit LE920 */
{QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */
+ {QMI_FIXED_INTF(0x1c9e, 0x9b01, 3)}, /* XS Stick W100-2 from 4G Systems */
{QMI_FIXED_INTF(0x0b3c, 0xc000, 4)}, /* Olivetti Olicard 100 */
{QMI_FIXED_INTF(0x0b3c, 0xc001, 4)}, /* Olivetti Olicard 120 */
{QMI_FIXED_INTF(0x0b3c, 0xc002, 4)}, /* Olivetti Olicard 140 */
@@ -741,6 +742,7 @@ static const struct usb_device_id products[] = {
{QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
{QMI_FIXED_INTF(0x03f0, 0x4e1d, 8)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
+ {QMI_FIXED_INTF(0x22de, 0x9061, 3)}, /* WeTelecom WPD-600N */
/* 4. Gobi 1000 devices */
{QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
@@ -771,6 +773,7 @@ static const struct usb_device_id products[] = {
{QMI_GOBI_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */
{QMI_GOBI_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */
{QMI_GOBI_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */
+ {QMI_FIXED_INTF(0x05c6, 0x9215, 4)}, /* Quectel EC20 Mini PCIe */
{QMI_GOBI_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */
{QMI_GOBI_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */
{QMI_GOBI_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */
@@ -802,10 +805,24 @@ static const struct usb_device_id products[] = {
};
MODULE_DEVICE_TABLE(usb, products);
+static bool quectel_ec20_detected(struct usb_interface *intf)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+
+ if (dev->actconfig &&
+ le16_to_cpu(dev->descriptor.idVendor) == 0x05c6 &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x9215 &&
+ dev->actconfig->desc.bNumInterfaces == 5)
+ return true;
+
+ return false;
+}
+
static int qmi_wwan_probe(struct usb_interface *intf,
const struct usb_device_id *prod)
{
struct usb_device_id *id = (struct usb_device_id *)prod;
+ struct usb_interface_descriptor *desc = &intf->cur_altsetting->desc;
/* Workaround to enable dynamic IDs. This disables usbnet
* blacklisting functionality. Which, if required, can be
@@ -817,6 +834,12 @@ static int qmi_wwan_probe(struct usb_interface *intf,
id->driver_info = (unsigned long)&qmi_wwan_info;
}
+ /* Quectel EC20 quirk where we've QMI on interface 4 instead of 0 */
+ if (quectel_ec20_detected(intf) && desc->bInterfaceNumber == 0) {
+ dev_dbg(&intf->dev, "Quectel EC20 quirk, skipping interface 0\n");
+ return -ENODEV;
+ }
+
return usbnet_probe(intf, id);
}
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index d9427ca..2fb637a 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -3067,17 +3067,6 @@ static int rtl8152_open(struct net_device *netdev)
mutex_lock(&tp->control);
- /* The WORK_ENABLE may be set when autoresume occurs */
- if (test_bit(WORK_ENABLE, &tp->flags)) {
- clear_bit(WORK_ENABLE, &tp->flags);
- usb_kill_urb(tp->intr_urb);
- cancel_delayed_work_sync(&tp->schedule);
-
- /* disable the tx/rx, if the workqueue has enabled them. */
- if (netif_carrier_ok(netdev))
- tp->rtl_ops.disable(tp);
- }
-
tp->rtl_ops.up(tp);
rtl8152_set_speed(tp, AUTONEG_ENABLE,
@@ -3124,12 +3113,6 @@ static int rtl8152_close(struct net_device *netdev)
} else {
mutex_lock(&tp->control);
- /* The autosuspend may have been enabled and wouldn't
- * be disable when autoresume occurs, because the
- * netif_running() would be false.
- */
- rtl_runtime_suspend_enable(tp, false);
-
tp->rtl_ops.down(tp);
mutex_unlock(&tp->control);
@@ -3512,7 +3495,7 @@ static int rtl8152_resume(struct usb_interface *intf)
netif_device_attach(tp->netdev);
}
- if (netif_running(tp->netdev)) {
+ if (netif_running(tp->netdev) && tp->netdev->flags & IFF_UP) {
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
rtl_runtime_suspend_enable(tp, false);
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
@@ -3532,6 +3515,8 @@ static int rtl8152_resume(struct usb_interface *intf)
}
usb_submit_urb(tp->intr_urb, GFP_KERNEL);
} else if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
+ if (tp->netdev->flags & IFF_UP)
+ rtl_runtime_suspend_enable(tp, false);
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
}
@@ -3540,6 +3525,14 @@ static int rtl8152_resume(struct usb_interface *intf)
return 0;
}
+static int rtl8152_reset_resume(struct usb_interface *intf)
+{
+ struct r8152 *tp = usb_get_intfdata(intf);
+
+ clear_bit(SELECTIVE_SUSPEND, &tp->flags);
+ return rtl8152_resume(intf);
+}
+
static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct r8152 *tp = netdev_priv(dev);
@@ -4291,7 +4284,7 @@ static struct usb_driver rtl8152_driver = {
.disconnect = rtl8152_disconnect,
.suspend = rtl8152_suspend,
.resume = rtl8152_resume,
- .reset_resume = rtl8152_resume,
+ .reset_resume = rtl8152_reset_resume,
.pre_reset = rtl8152_pre_reset,
.post_reset = rtl8152_post_reset,
.supports_autosuspend = 1,
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 060918f..0744bf2 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -1662,12 +1662,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
* bind() should set rx_urb_size in that case.
*/
dev->hard_mtu = net->mtu + net->hard_header_len;
-#if 0
-// dma_supported() is deeply broken on almost all architectures
- // possible with some EHCI controllers
- if (dma_supported (&udev->dev, DMA_BIT_MASK(64)))
- net->features |= NETIF_F_HIGHDMA;
-#endif
net->netdev_ops = &usbnet_netdev_ops;
net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 0ef4a5a..ba21d07 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -117,12 +117,6 @@ static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev)
kfree_skb(skb);
goto drop;
}
- /* don't change ip_summed == CHECKSUM_PARTIAL, as that
- * will cause bad checksum on forwarded packets
- */
- if (skb->ip_summed == CHECKSUM_NONE &&
- rcv->features & NETIF_F_RXCSUM)
- skb->ip_summed = CHECKSUM_UNNECESSARY;
if (likely(dev_forward_skb(rcv, skb) == NET_RX_SUCCESS)) {
struct pcpu_vstats *stats = this_cpu_ptr(dev->vstats);
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index d8838ded..f94ab78 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -140,6 +140,12 @@ struct virtnet_info {
/* CPU hot plug notifier */
struct notifier_block nb;
+
+ /* Control VQ buffers: protected by the rtnl lock */
+ struct virtio_net_ctrl_hdr ctrl_hdr;
+ virtio_net_ctrl_ack ctrl_status;
+ u8 ctrl_promisc;
+ u8 ctrl_allmulti;
};
struct padded_vnet_hdr {
@@ -976,31 +982,30 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
struct scatterlist *out)
{
struct scatterlist *sgs[4], hdr, stat;
- struct virtio_net_ctrl_hdr ctrl;
- virtio_net_ctrl_ack status = ~0;
unsigned out_num = 0, tmp;
/* Caller should know better */
BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ));
- ctrl.class = class;
- ctrl.cmd = cmd;
+ vi->ctrl_status = ~0;
+ vi->ctrl_hdr.class = class;
+ vi->ctrl_hdr.cmd = cmd;
/* Add header */
- sg_init_one(&hdr, &ctrl, sizeof(ctrl));
+ sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr));
sgs[out_num++] = &hdr;
if (out)
sgs[out_num++] = out;
/* Add return status. */
- sg_init_one(&stat, &status, sizeof(status));
+ sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status));
sgs[out_num] = &stat;
BUG_ON(out_num + 1 > ARRAY_SIZE(sgs));
virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC);
if (unlikely(!virtqueue_kick(vi->cvq)))
- return status == VIRTIO_NET_OK;
+ return vi->ctrl_status == VIRTIO_NET_OK;
/* Spin for a response, the kick causes an ioport write, trapping
* into the hypervisor, so the request should be handled immediately.
@@ -1009,7 +1014,7 @@ static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd,
!virtqueue_is_broken(vi->cvq))
cpu_relax();
- return status == VIRTIO_NET_OK;
+ return vi->ctrl_status == VIRTIO_NET_OK;
}
static int virtnet_set_mac_address(struct net_device *dev, void *p)
@@ -1151,7 +1156,6 @@ static void virtnet_set_rx_mode(struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
struct scatterlist sg[2];
- u8 promisc, allmulti;
struct virtio_net_ctrl_mac *mac_data;
struct netdev_hw_addr *ha;
int uc_count;
@@ -1163,22 +1167,22 @@ static void virtnet_set_rx_mode(struct net_device *dev)
if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX))
return;
- promisc = ((dev->flags & IFF_PROMISC) != 0);
- allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
+ vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0);
+ vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0);
- sg_init_one(sg, &promisc, sizeof(promisc));
+ sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
VIRTIO_NET_CTRL_RX_PROMISC, sg))
dev_warn(&dev->dev, "Failed to %sable promisc mode.\n",
- promisc ? "en" : "dis");
+ vi->ctrl_promisc ? "en" : "dis");
- sg_init_one(sg, &allmulti, sizeof(allmulti));
+ sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX,
VIRTIO_NET_CTRL_RX_ALLMULTI, sg))
dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n",
- allmulti ? "en" : "dis");
+ vi->ctrl_allmulti ? "en" : "dis");
uc_count = netdev_uc_count(dev);
mc_count = netdev_mc_count(dev);
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index 46f4cad..0cbf520 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -587,6 +587,12 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
&adapter->pdev->dev,
rbi->skb->data, rbi->len,
PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ rbi->dma_addr)) {
+ dev_kfree_skb_any(rbi->skb);
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
} else {
/* rx buffer skipped by the device */
}
@@ -605,13 +611,18 @@ vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
&adapter->pdev->dev,
rbi->page, 0, PAGE_SIZE,
PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ rbi->dma_addr)) {
+ put_page(rbi->page);
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
} else {
/* rx buffers skipped by the device */
}
val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT;
}
- BUG_ON(rbi->dma_addr == 0);
gd->rxd.addr = cpu_to_le64(rbi->dma_addr);
gd->dword[2] = cpu_to_le32((!ring->gen << VMXNET3_RXD_GEN_SHIFT)
| val | rbi->len);
@@ -655,7 +666,7 @@ vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd,
}
-static void
+static int
vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
struct vmxnet3_tx_queue *tq, struct pci_dev *pdev,
struct vmxnet3_adapter *adapter)
@@ -715,6 +726,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi->dma_addr = dma_map_single(&adapter->pdev->dev,
skb->data + buf_offset, buf_size,
PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+ return -EFAULT;
tbi->len = buf_size;
@@ -755,6 +768,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
tbi->dma_addr = skb_frag_dma_map(&adapter->pdev->dev, frag,
buf_offset, buf_size,
DMA_TO_DEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, tbi->dma_addr))
+ return -EFAULT;
tbi->len = buf_size;
@@ -782,6 +797,8 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
/* set the last buf_info for the pkt */
tbi->skb = skb;
tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base;
+
+ return 0;
}
@@ -1020,7 +1037,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
}
/* fill tx descs related to addr & len */
- vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter);
+ if (vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter))
+ goto unlock_drop_pkt;
/* setup the EOP desc */
ctx.eop_txd->dword[3] = cpu_to_le32(VMXNET3_TXD_CQ | VMXNET3_TXD_EOP);
@@ -1231,6 +1249,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_rx_buf_info *rbi;
struct sk_buff *skb, *new_skb = NULL;
struct page *new_page = NULL;
+ dma_addr_t new_dma_addr;
int num_to_alloc;
struct Vmxnet3_RxDesc *rxd;
u32 idx, ring_idx;
@@ -1287,6 +1306,21 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skip_page_frags = true;
goto rcd_done;
}
+ new_dma_addr = dma_map_single(&adapter->pdev->dev,
+ new_skb->data, rbi->len,
+ PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ new_dma_addr)) {
+ dev_kfree_skb(new_skb);
+ /* Skb allocation failed, do not handover this
+ * skb to stack. Reuse it. Drop the existing pkt
+ */
+ rq->stats.rx_buf_alloc_failure++;
+ ctx->skb = NULL;
+ rq->stats.drop_total++;
+ skip_page_frags = true;
+ goto rcd_done;
+ }
dma_unmap_single(&adapter->pdev->dev, rbi->dma_addr,
rbi->len,
@@ -1303,9 +1337,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
/* Immediate refill */
rbi->skb = new_skb;
- rbi->dma_addr = dma_map_single(&adapter->pdev->dev,
- rbi->skb->data, rbi->len,
- PCI_DMA_FROMDEVICE);
+ rbi->dma_addr = new_dma_addr;
rxd->addr = cpu_to_le64(rbi->dma_addr);
rxd->len = rbi->len;
if (adapter->version == 2 &&
@@ -1348,6 +1380,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skip_page_frags = true;
goto rcd_done;
}
+ new_dma_addr = dma_map_page(&adapter->pdev->dev,
+ new_page,
+ 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev,
+ new_dma_addr)) {
+ put_page(new_page);
+ rq->stats.rx_buf_alloc_failure++;
+ dev_kfree_skb(ctx->skb);
+ ctx->skb = NULL;
+ skip_page_frags = true;
+ goto rcd_done;
+ }
dma_unmap_page(&adapter->pdev->dev,
rbi->dma_addr, rbi->len,
@@ -1357,10 +1402,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
/* Immediate refill */
rbi->page = new_page;
- rbi->dma_addr = dma_map_page(&adapter->pdev->dev
- , rbi->page,
- 0, PAGE_SIZE,
- PCI_DMA_FROMDEVICE);
+ rbi->dma_addr = new_dma_addr;
rxd->addr = cpu_to_le64(rbi->dma_addr);
rxd->len = rbi->len;
}
@@ -2157,16 +2199,18 @@ vmxnet3_set_mc(struct net_device *netdev)
if (!netdev_mc_empty(netdev)) {
new_table = vmxnet3_copy_mc(netdev);
if (new_table) {
- rxConf->mfTableLen = cpu_to_le16(
- netdev_mc_count(netdev) * ETH_ALEN);
+ size_t sz = netdev_mc_count(netdev) * ETH_ALEN;
+
+ rxConf->mfTableLen = cpu_to_le16(sz);
new_table_pa = dma_map_single(
&adapter->pdev->dev,
new_table,
- rxConf->mfTableLen,
+ sz,
PCI_DMA_TODEVICE);
}
- if (new_table_pa) {
+ if (!dma_mapping_error(&adapter->pdev->dev,
+ new_table_pa)) {
new_mode |= VMXNET3_RXM_MCAST;
rxConf->mfTablePA = cpu_to_le64(new_table_pa);
} else {
@@ -3074,6 +3118,11 @@ vmxnet3_probe_device(struct pci_dev *pdev,
adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter,
sizeof(struct vmxnet3_adapter),
PCI_DMA_TODEVICE);
+ if (dma_mapping_error(&adapter->pdev->dev, adapter->adapter_pa)) {
+ dev_err(&pdev->dev, "Failed to map dma\n");
+ err = -EFAULT;
+ goto err_dma_map;
+ }
adapter->shared = dma_alloc_coherent(
&adapter->pdev->dev,
sizeof(struct Vmxnet3_DriverShared),
@@ -3232,6 +3281,7 @@ err_alloc_queue_desc:
err_alloc_shared:
dma_unmap_single(&adapter->pdev->dev, adapter->adapter_pa,
sizeof(struct vmxnet3_adapter), PCI_DMA_TODEVICE);
+err_dma_map:
free_netdev(netdev);
return err;
}
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 3f859a5..bdb8a6c 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,10 +69,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.4.3.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.4.5.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01040300
+#define VMXNET3_DRIVER_VERSION_NUM 0x01040500
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c
index 92fa3e1..0a242b2 100644
--- a/drivers/net/vrf.c
+++ b/drivers/net/vrf.c
@@ -800,7 +800,7 @@ static struct rtable *vrf_get_rtable(const struct net_device *dev,
}
/* called under rcu_read_lock */
-static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
+static int vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
{
struct fib_result res = { .tclassid = 0 };
struct net *net = dev_net(dev);
@@ -808,9 +808,10 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
u8 flags = fl4->flowi4_flags;
u8 scope = fl4->flowi4_scope;
u8 tos = RT_FL_TOS(fl4);
+ int rc;
if (unlikely(!fl4->daddr))
- return;
+ return 0;
fl4->flowi4_flags |= FLOWI_FLAG_SKIP_NH_OIF;
fl4->flowi4_iif = LOOPBACK_IFINDEX;
@@ -818,7 +819,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
fl4->flowi4_scope = ((tos & RTO_ONLINK) ?
RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
- if (!fib_lookup(net, fl4, &res, 0)) {
+ rc = fib_lookup(net, fl4, &res, 0);
+ if (!rc) {
if (res.type == RTN_LOCAL)
fl4->saddr = res.fi->fib_prefsrc ? : fl4->daddr;
else
@@ -828,6 +830,8 @@ static void vrf_get_saddr(struct net_device *dev, struct flowi4 *fl4)
fl4->flowi4_flags = flags;
fl4->flowi4_tos = orig_tos;
fl4->flowi4_scope = scope;
+
+ return rc;
}
#if IS_ENABLED(CONFIG_IPV6)
@@ -907,7 +911,6 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
struct net_vrf *vrf = netdev_priv(dev);
- int err;
if (!data || !data[IFLA_VRF_TABLE])
return -EINVAL;
@@ -916,15 +919,7 @@ static int vrf_newlink(struct net *src_net, struct net_device *dev,
dev->priv_flags |= IFF_L3MDEV_MASTER;
- err = register_netdevice(dev);
- if (err < 0)
- goto out_fail;
-
- return 0;
-
-out_fail:
- free_netdev(dev);
- return err;
+ return register_netdevice(dev);
}
static size_t vrf_nl_getsize(const struct net_device *dev)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 6369a57..ba363ce 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1158,7 +1158,6 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
struct pcpu_sw_netstats *stats;
union vxlan_addr saddr;
int err = 0;
- union vxlan_addr *remote_ip;
/* For flow based devices, map all packets to VNI 0 */
if (vs->flags & VXLAN_F_COLLECT_METADATA)
@@ -1169,7 +1168,6 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
if (!vxlan)
goto drop;
- remote_ip = &vxlan->default_dst.remote_ip;
skb_reset_mac_header(skb);
skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev)));
skb->protocol = eth_type_trans(skb, vxlan->dev);
@@ -1179,8 +1177,8 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr))
goto drop;
- /* Re-examine inner Ethernet packet */
- if (remote_ip->sa.sa_family == AF_INET) {
+ /* Get data from the outer IP header */
+ if (vxlan_get_sk_family(vs) == AF_INET) {
oip = ip_hdr(skb);
saddr.sin.sin_addr.s_addr = oip->saddr;
saddr.sa.sa_family = AF_INET;
@@ -1848,6 +1846,34 @@ static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *sk
!(vxflags & VXLAN_F_UDP_CSUM));
}
+#if IS_ENABLED(CONFIG_IPV6)
+static struct dst_entry *vxlan6_get_route(struct vxlan_dev *vxlan,
+ struct sk_buff *skb, int oif,
+ const struct in6_addr *daddr,
+ struct in6_addr *saddr)
+{
+ struct dst_entry *ndst;
+ struct flowi6 fl6;
+ int err;
+
+ memset(&fl6, 0, sizeof(fl6));
+ fl6.flowi6_oif = oif;
+ fl6.daddr = *daddr;
+ fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr;
+ fl6.flowi6_mark = skb->mark;
+ fl6.flowi6_proto = IPPROTO_UDP;
+
+ err = ipv6_stub->ipv6_dst_lookup(vxlan->net,
+ vxlan->vn6_sock->sock->sk,
+ &ndst, &fl6);
+ if (err < 0)
+ return ERR_PTR(err);
+
+ *saddr = fl6.saddr;
+ return ndst;
+}
+#endif
+
/* Bypass encapsulation if the destination is local */
static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan,
struct vxlan_dev *dst_vxlan)
@@ -2035,21 +2061,17 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
#if IS_ENABLED(CONFIG_IPV6)
} else {
struct dst_entry *ndst;
- struct flowi6 fl6;
+ struct in6_addr saddr;
u32 rt6i_flags;
if (!vxlan->vn6_sock)
goto drop;
sk = vxlan->vn6_sock->sock->sk;
- memset(&fl6, 0, sizeof(fl6));
- fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0;
- fl6.daddr = dst->sin6.sin6_addr;
- fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr;
- fl6.flowi6_mark = skb->mark;
- fl6.flowi6_proto = IPPROTO_UDP;
-
- if (ipv6_stub->ipv6_dst_lookup(vxlan->net, sk, &ndst, &fl6)) {
+ ndst = vxlan6_get_route(vxlan, skb,
+ rdst ? rdst->remote_ifindex : 0,
+ &dst->sin6.sin6_addr, &saddr);
+ if (IS_ERR(ndst)) {
netdev_dbg(dev, "no route to %pI6\n",
&dst->sin6.sin6_addr);
dev->stats.tx_carrier_errors++;
@@ -2081,7 +2103,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
}
ttl = ttl ? : ip6_dst_hoplimit(ndst);
- err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr,
+ err = vxlan6_xmit_skb(ndst, sk, skb, dev, &saddr, &dst->sin6.sin6_addr,
0, ttl, src_port, dst_port, htonl(vni << 8), md,
!net_eq(vxlan->net, dev_net(vxlan->dev)),
flags);
@@ -2395,9 +2417,30 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
vxlan->cfg.port_max, true);
dport = info->key.tp_dst ? : vxlan->cfg.dst_port;
- if (ip_tunnel_info_af(info) == AF_INET)
+ if (ip_tunnel_info_af(info) == AF_INET) {
+ if (!vxlan->vn4_sock)
+ return -EINVAL;
return egress_ipv4_tun_info(dev, skb, info, sport, dport);
- return -EINVAL;
+ } else {
+#if IS_ENABLED(CONFIG_IPV6)
+ struct dst_entry *ndst;
+
+ if (!vxlan->vn6_sock)
+ return -EINVAL;
+ ndst = vxlan6_get_route(vxlan, skb, 0,
+ &info->key.u.ipv6.dst,
+ &info->key.u.ipv6.src);
+ if (IS_ERR(ndst))
+ return PTR_ERR(ndst);
+ dst_release(ndst);
+
+ info->key.tp_src = sport;
+ info->key.tp_dst = dport;
+#else /* !CONFIG_IPV6 */
+ return -EPFNOSUPPORT;
+#endif
+ }
+ return 0;
}
static const struct net_device_ops vxlan_netdev_ops = {
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index e92aaf6..89541cc 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -1075,11 +1075,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
used = pvc_is_used(pvc);
- if (type == ARPHRD_ETHER) {
+ if (type == ARPHRD_ETHER)
dev = alloc_netdev(0, "pvceth%d", NET_NAME_UNKNOWN,
ether_setup);
- dev->priv_flags &= ~IFF_TX_SKB_SHARING;
- } else
+ else
dev = alloc_netdev(0, "pvc%d", NET_NAME_UNKNOWN, pvc_setup);
if (!dev) {
@@ -1088,9 +1087,10 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
return -ENOBUFS;
}
- if (type == ARPHRD_ETHER)
+ if (type == ARPHRD_ETHER) {
+ dev->priv_flags &= ~IFF_TX_SKB_SHARING;
eth_hw_addr_random(dev);
- else {
+ } else {
*(__be16*)dev->dev_addr = htons(dlci);
dlci_to_q922(dev->broadcast, dlci);
}
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 5c47b01..cd39025 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -549,16 +549,12 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
static int x25_asy_open_tty(struct tty_struct *tty)
{
- struct x25_asy *sl = tty->disc_data;
+ struct x25_asy *sl;
int err;
if (tty->ops->write == NULL)
return -EOPNOTSUPP;
- /* First make sure we're not already connected. */
- if (sl && sl->magic == X25_ASY_MAGIC)
- return -EEXIST;
-
/* OK. Find a free X.25 channel to use. */
sl = x25_asy_alloc();
if (sl == NULL)
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index aa9bd92..0947cc2 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -51,6 +51,7 @@ MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
{
.id = QCA988X_HW_2_0_VERSION,
+ .dev_id = QCA988X_2_0_DEVICE_ID,
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -69,6 +70,25 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
},
{
.id = QCA6174_HW_2_1_VERSION,
+ .dev_id = QCA6164_2_1_DEVICE_ID,
+ .name = "qca6164 hw2.1",
+ .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .fw = {
+ .dir = QCA6174_HW_2_1_FW_DIR,
+ .fw = QCA6174_HW_2_1_FW_FILE,
+ .otp = QCA6174_HW_2_1_OTP_FILE,
+ .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+ },
+ },
+ {
+ .id = QCA6174_HW_2_1_VERSION,
+ .dev_id = QCA6174_2_1_DEVICE_ID,
.name = "qca6174 hw2.1",
.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -86,6 +106,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
},
{
.id = QCA6174_HW_3_0_VERSION,
+ .dev_id = QCA6174_2_1_DEVICE_ID,
.name = "qca6174 hw3.0",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -103,6 +124,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
},
{
.id = QCA6174_HW_3_2_VERSION,
+ .dev_id = QCA6174_2_1_DEVICE_ID,
.name = "qca6174 hw3.2",
.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
.uart_pin = 6,
@@ -121,6 +143,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
},
{
.id = QCA99X0_HW_2_0_DEV_VERSION,
+ .dev_id = QCA99X0_2_0_DEVICE_ID,
.name = "qca99x0 hw2.0",
.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,
.uart_pin = 7,
@@ -139,10 +162,31 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
},
{
.id = QCA9377_HW_1_0_DEV_VERSION,
+ .dev_id = QCA9377_1_0_DEVICE_ID,
.name = "qca9377 hw1.0",
.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
- .uart_pin = 7,
+ .uart_pin = 6,
.otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
+ .fw = {
+ .dir = QCA9377_HW_1_0_FW_DIR,
+ .fw = QCA9377_HW_1_0_FW_FILE,
+ .otp = QCA9377_HW_1_0_OTP_FILE,
+ .board = QCA9377_HW_1_0_BOARD_DATA_FILE,
+ .board_size = QCA9377_BOARD_DATA_SZ,
+ .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
+ },
+ },
+ {
+ .id = QCA9377_HW_1_1_DEV_VERSION,
+ .dev_id = QCA9377_1_0_DEVICE_ID,
+ .name = "qca9377 hw1.1",
+ .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .otp_exe_param = 0,
+ .channel_counters_freq_hz = 88000,
+ .max_probe_resp_desc_thres = 0,
.fw = {
.dir = QCA9377_HW_1_0_FW_DIR,
.fw = QCA9377_HW_1_0_FW_FILE,
@@ -1263,7 +1307,8 @@ static int ath10k_init_hw_params(struct ath10k *ar)
for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {
hw_params = &ath10k_hw_params_list[i];
- if (hw_params->id == ar->target_version)
+ if (hw_params->id == ar->target_version &&
+ hw_params->dev_id == ar->dev_id)
break;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 018c64f..858d75f 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -636,6 +636,7 @@ struct ath10k {
struct ath10k_hw_params {
u32 id;
+ u16 dev_id;
const char *name;
u32 patch_load_addr;
int uart_pin;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 39966a0..713c2bc 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -22,6 +22,12 @@
#define ATH10K_FW_DIR "ath10k"
+#define QCA988X_2_0_DEVICE_ID (0x003c)
+#define QCA6164_2_1_DEVICE_ID (0x0041)
+#define QCA6174_2_1_DEVICE_ID (0x003e)
+#define QCA99X0_2_0_DEVICE_ID (0x0040)
+#define QCA9377_1_0_DEVICE_ID (0x0042)
+
/* QCA988X 1.0 definitions (unsupported) */
#define QCA988X_HW_1_0_CHIP_ID_REV 0x0
@@ -42,6 +48,10 @@
#define QCA6174_HW_3_0_VERSION 0x05020000
#define QCA6174_HW_3_2_VERSION 0x05030000
+/* QCA9377 target BMI version signatures */
+#define QCA9377_HW_1_0_DEV_VERSION 0x05020000
+#define QCA9377_HW_1_1_DEV_VERSION 0x05020001
+
enum qca6174_pci_rev {
QCA6174_PCI_REV_1_1 = 0x11,
QCA6174_PCI_REV_1_3 = 0x13,
@@ -60,6 +70,11 @@ enum qca6174_chip_id_rev {
QCA6174_HW_3_2_CHIP_ID_REV = 10,
};
+enum qca9377_chip_id_rev {
+ QCA9377_HW_1_0_CHIP_ID_REV = 0x0,
+ QCA9377_HW_1_1_CHIP_ID_REV = 0x1,
+};
+
#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1"
#define QCA6174_HW_2_1_FW_FILE "firmware.bin"
#define QCA6174_HW_2_1_OTP_FILE "otp.bin"
@@ -85,8 +100,6 @@ enum qca6174_chip_id_rev {
#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
/* QCA9377 1.0 definitions */
-#define QCA9377_HW_1_0_DEV_VERSION 0x05020001
-#define QCA9377_HW_1_0_CHIP_ID_REV 0x1
#define QCA9377_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA9377/hw1.0"
#define QCA9377_HW_1_0_FW_FILE "firmware.bin"
#define QCA9377_HW_1_0_OTP_FILE "otp.bin"
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index a7411fe..95a55405 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4225,7 +4225,7 @@ static int ath10k_config(struct ieee80211_hw *hw, u32 changed)
static u32 get_nss_from_chainmask(u16 chain_mask)
{
- if ((chain_mask & 0x15) == 0x15)
+ if ((chain_mask & 0xf) == 0xf)
return 4;
else if ((chain_mask & 0x7) == 0x7)
return 3;
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 3fca200..930785a 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -57,12 +57,6 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
#define ATH10K_PCI_TARGET_WAIT 3000
#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
-#define QCA988X_2_0_DEVICE_ID (0x003c)
-#define QCA6164_2_1_DEVICE_ID (0x0041)
-#define QCA6174_2_1_DEVICE_ID (0x003e)
-#define QCA99X0_2_0_DEVICE_ID (0x0040)
-#define QCA9377_1_0_DEVICE_ID (0x0042)
-
static const struct pci_device_id ath10k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
{ PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */
@@ -92,7 +86,9 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
{ QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
{ QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV },
+
{ QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV },
+ { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV },
};
static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
@@ -111,8 +107,9 @@ static void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state);
static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state);
+static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);
-static const struct ce_attr host_ce_config_wlan[] = {
+static struct ce_attr host_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
@@ -128,7 +125,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
- .recv_cb = ath10k_pci_htc_rx_cb,
+ .recv_cb = ath10k_pci_htt_htc_rx_cb,
},
/* CE2: target->host WMI */
@@ -217,7 +214,7 @@ static const struct ce_attr host_ce_config_wlan[] = {
};
/* Target firmware's Copy Engine configuration. */
-static const struct ce_pipe_config target_ce_config_wlan[] = {
+static struct ce_pipe_config target_ce_config_wlan[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
@@ -330,7 +327,7 @@ static const struct ce_pipe_config target_ce_config_wlan[] = {
* This table is derived from the CE_PCI TABLE, above.
* It is passed to the Target at startup for use by firmware.
*/
-static const struct service_to_pipe target_service_to_ce_map_wlan[] = {
+static struct service_to_pipe target_service_to_ce_map_wlan[] = {
{
__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */
@@ -1208,6 +1205,16 @@ static void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
}
+static void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)
+{
+ /* CE4 polling needs to be done whenever CE pipe which transports
+ * HTT Rx (target->host) is processed.
+ */
+ ath10k_ce_per_engine_service(ce_state->ar, 4);
+
+ ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);
+}
+
/* Called by lower (CE) layer when a send to HTT Target completes. */
static void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state)
{
@@ -2027,6 +2034,29 @@ static int ath10k_pci_init_config(struct ath10k *ar)
return 0;
}
+static void ath10k_pci_override_ce_config(struct ath10k *ar)
+{
+ struct ce_attr *attr;
+ struct ce_pipe_config *config;
+
+ /* For QCA6174 we're overriding the Copy Engine 5 configuration,
+ * since it is currently used for other feature.
+ */
+
+ /* Override Host's Copy Engine 5 configuration */
+ attr = &host_ce_config_wlan[5];
+ attr->src_sz_max = 0;
+ attr->dest_nentries = 0;
+
+ /* Override Target firmware's Copy Engine configuration */
+ config = &target_ce_config_wlan[5];
+ config->pipedir = __cpu_to_le32(PIPEDIR_OUT);
+ config->nbytes_max = __cpu_to_le32(2048);
+
+ /* Map from service/endpoint to Copy Engine */
+ target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
+}
+
static int ath10k_pci_alloc_pipes(struct ath10k *ar)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -3020,6 +3050,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_core_destroy;
}
+ if (QCA_REV_6174(ar))
+ ath10k_pci_override_ce_config(ar);
+
ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 97bc186..a1d10b8 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -580,16 +580,10 @@ static ssize_t wil_write_file_rxon(struct file *file, const char __user *buf,
long channel;
bool on;
- char *kbuf = kmalloc(len + 1, GFP_KERNEL);
-
- if (!kbuf)
- return -ENOMEM;
- if (copy_from_user(kbuf, buf, len)) {
- kfree(kbuf);
- return -EIO;
- }
+ char *kbuf = memdup_user_nul(buf, len);
- kbuf[len] = '\0';
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
rc = kstrtol(kbuf, 0, &channel);
kfree(kbuf);
if (rc)
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index 1a73c7a..d9a4aee 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -70,12 +70,18 @@
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 17
+#define IWL7265_UCODE_API_MAX 19
+#define IWL7265D_UCODE_API_MAX 19
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13
+#define IWL7265_UCODE_API_OK 13
+#define IWL7265D_UCODE_API_OK 13
/* Lowest firmware API version supported */
#define IWL7260_UCODE_API_MIN 13
+#define IWL7265_UCODE_API_MIN 13
+#define IWL7265D_UCODE_API_MIN 13
/* NVM versions */
#define IWL7260_NVM_VERSION 0x0a1d
@@ -149,10 +155,7 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.ht40_bands = BIT(IEEE80211_BAND_2GHZ) | BIT(IEEE80211_BAND_5GHZ),
};
-#define IWL_DEVICE_7000 \
- .ucode_api_max = IWL7260_UCODE_API_MAX, \
- .ucode_api_ok = IWL7260_UCODE_API_OK, \
- .ucode_api_min = IWL7260_UCODE_API_MIN, \
+#define IWL_DEVICE_7000_COMMON \
.device_family = IWL_DEVICE_FAMILY_7000, \
.max_inst_size = IWL60_RTC_INST_SIZE, \
.max_data_size = IWL60_RTC_DATA_SIZE, \
@@ -163,6 +166,24 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \
.dccm_offset = IWL7000_DCCM_OFFSET
+#define IWL_DEVICE_7000 \
+ IWL_DEVICE_7000_COMMON, \
+ .ucode_api_max = IWL7260_UCODE_API_MAX, \
+ .ucode_api_ok = IWL7260_UCODE_API_OK, \
+ .ucode_api_min = IWL7260_UCODE_API_MIN
+
+#define IWL_DEVICE_7005 \
+ IWL_DEVICE_7000_COMMON, \
+ .ucode_api_max = IWL7265_UCODE_API_MAX, \
+ .ucode_api_ok = IWL7265_UCODE_API_OK, \
+ .ucode_api_min = IWL7265_UCODE_API_MIN
+
+#define IWL_DEVICE_7005D \
+ IWL_DEVICE_7000_COMMON, \
+ .ucode_api_max = IWL7265D_UCODE_API_MAX, \
+ .ucode_api_ok = IWL7265D_UCODE_API_OK, \
+ .ucode_api_min = IWL7265D_UCODE_API_MIN
+
const struct iwl_cfg iwl7260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7260",
.fw_name_pre = IWL7260_FW_PRE,
@@ -266,7 +287,7 @@ static const struct iwl_ht_params iwl7265_ht_params = {
const struct iwl_cfg iwl3165_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 3165",
.fw_name_pre = IWL7265D_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005D,
.ht_params = &iwl7000_ht_params,
.nvm_ver = IWL3165_NVM_VERSION,
.nvm_calib_ver = IWL3165_TX_POWER_VERSION,
@@ -277,7 +298,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
const struct iwl_cfg iwl7265_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -288,7 +309,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
const struct iwl_cfg iwl7265_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -299,7 +320,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
const struct iwl_cfg iwl7265_n_cfg = {
.name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -310,7 +331,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
const struct iwl_cfg iwl7265d_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7265",
.fw_name_pre = IWL7265D_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005D,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -321,7 +342,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
const struct iwl_cfg iwl7265d_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 7265",
.fw_name_pre = IWL7265D_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005D,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -332,7 +353,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
const struct iwl_cfg iwl7265d_n_cfg = {
.name = "Intel(R) Wireless N 7265",
.fw_name_pre = IWL7265D_FW_PRE,
- IWL_DEVICE_7000,
+ IWL_DEVICE_7005D,
.ht_params = &iwl7265_ht_params,
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
@@ -342,5 +363,5 @@ const struct iwl_cfg iwl7265d_n_cfg = {
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
MODULE_FIRMWARE(IWL3160_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
-MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265_MODULE_FIRMWARE(IWL7265_UCODE_API_OK));
+MODULE_FIRMWARE(IWL7265D_MODULE_FIRMWARE(IWL7265D_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 0116e5a..9bcc0bf 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -69,7 +69,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
-#define IWL8000_UCODE_API_MAX 17
+#define IWL8000_UCODE_API_MAX 19
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 85ae902..29ae58e 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -309,9 +309,9 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* to transmit packets to the AP, i.e. the PTK.
*/
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) {
- key->hw_key_idx = 0;
mvm->ptk_ivlen = key->iv_len;
mvm->ptk_icvlen = key->icv_len;
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 0);
} else {
/*
* firmware only supports TSC/RSC for a single key,
@@ -319,12 +319,11 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
* with new ones -- this relies on mac80211 doing
* list_add_tail().
*/
- key->hw_key_idx = 1;
mvm->gtk_ivlen = key->iv_len;
mvm->gtk_icvlen = key->icv_len;
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, 1);
}
- ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, true);
data->error = ret != 0;
out_unlock:
mutex_unlock(&mvm->mutex);
@@ -772,9 +771,6 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
*/
set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
- /* We reprogram keys and shouldn't allocate new key indices */
- memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
-
mvm->ptk_ivlen = 0;
mvm->ptk_icvlen = 0;
mvm->ptk_ivlen = 0;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 1fb6846..e88afac 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -2941,6 +2941,7 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
+ u8 key_offset;
if (iwlwifi_mod_params.sw_crypto) {
IWL_DEBUG_MAC80211(mvm, "leave - hwcrypto disabled\n");
@@ -3006,10 +3007,14 @@ static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
break;
}
+ /* in HW restart reuse the index, otherwise request a new one */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
+ key_offset = key->hw_key_idx;
+ else
+ key_offset = STA_KEY_IDX_INVALID;
+
IWL_DEBUG_MAC80211(mvm, "set hwcrypto key\n");
- ret = iwl_mvm_set_sta_key(mvm, vif, sta, key,
- test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
- &mvm->status));
+ ret = iwl_mvm_set_sta_key(mvm, vif, sta, key, key_offset);
if (ret) {
IWL_WARN(mvm, "set key failed\n");
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 300a249..2b976b1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -1201,7 +1201,8 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
return max_offs;
}
-static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
+static u8 iwl_mvm_get_key_sta_id(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -1218,8 +1219,21 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
* station ID, then use AP's station ID.
*/
if (vif->type == NL80211_IFTYPE_STATION &&
- mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT)
- return mvmvif->ap_sta_id;
+ mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
+ u8 sta_id = mvmvif->ap_sta_id;
+
+ sta = rcu_dereference_check(mvm->fw_id_to_mac_id[sta_id],
+ lockdep_is_held(&mvm->mutex));
+ /*
+ * It is possible that the 'sta' parameter is NULL,
+ * for example when a GTK is removed - the sta_id will then
+ * be the AP ID, and no station was passed by mac80211.
+ */
+ if (IS_ERR_OR_NULL(sta))
+ return IWL_MVM_STATION_COUNT;
+
+ return sta_id;
+ }
return IWL_MVM_STATION_COUNT;
}
@@ -1227,7 +1241,8 @@ static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta,
struct ieee80211_key_conf *keyconf, bool mcast,
- u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags)
+ u32 tkip_iv32, u16 *tkip_p1k, u32 cmd_flags,
+ u8 key_offset)
{
struct iwl_mvm_add_sta_key_cmd cmd = {};
__le16 key_flags;
@@ -1269,7 +1284,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
if (mcast)
key_flags |= cpu_to_le16(STA_KEY_MULTICAST);
- cmd.key_offset = keyconf->hw_key_idx;
+ cmd.key_offset = key_offset;
cmd.key_flags = key_flags;
cmd.sta_id = sta_id;
@@ -1360,6 +1375,7 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf,
+ u8 key_offset,
bool mcast)
{
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
@@ -1375,17 +1391,17 @@ static int __iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
ieee80211_get_key_rx_seq(keyconf, 0, &seq);
ieee80211_get_tkip_rx_p1k(keyconf, addr, seq.tkip.iv32, p1k);
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
- seq.tkip.iv32, p1k, 0);
+ seq.tkip.iv32, p1k, 0, key_offset);
break;
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
- 0, NULL, 0);
+ 0, NULL, 0, key_offset);
break;
default:
ret = iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
- 0, NULL, 0);
+ 0, NULL, 0, key_offset);
}
return ret;
@@ -1433,7 +1449,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf,
- bool have_key_offset)
+ u8 key_offset)
{
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
u8 sta_id;
@@ -1443,7 +1459,7 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
/* Get the station id from the mvm local station table */
- sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+ sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
if (sta_id == IWL_MVM_STATION_COUNT) {
IWL_ERR(mvm, "Failed to find station id\n");
return -EINVAL;
@@ -1470,18 +1486,25 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
return -EINVAL;
- if (!have_key_offset) {
- /*
- * The D3 firmware hardcodes the PTK offset to 0, so we have to
- * configure it there. As a result, this workaround exists to
- * let the caller set the key offset (hw_key_idx), see d3.c.
- */
- keyconf->hw_key_idx = iwl_mvm_set_fw_key_idx(mvm);
- if (keyconf->hw_key_idx == STA_KEY_IDX_INVALID)
+ /* If the key_offset is not pre-assigned, we need to find a
+ * new offset to use. In normal cases, the offset is not
+ * pre-assigned, but during HW_RESTART we want to reuse the
+ * same indices, so we pass them when this function is called.
+ *
+ * In D3 entry, we need to hardcoded the indices (because the
+ * firmware hardcodes the PTK offset to 0). In this case, we
+ * need to make sure we don't overwrite the hw_key_idx in the
+ * keyconf structure, because otherwise we cannot configure
+ * the original ones back when resuming.
+ */
+ if (key_offset == STA_KEY_IDX_INVALID) {
+ key_offset = iwl_mvm_set_fw_key_idx(mvm);
+ if (key_offset == STA_KEY_IDX_INVALID)
return -ENOSPC;
+ keyconf->hw_key_idx = key_offset;
}
- ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, mcast);
+ ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, key_offset, mcast);
if (ret) {
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
goto end;
@@ -1495,7 +1518,8 @@ int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
*/
if (keyconf->cipher == WLAN_CIPHER_SUITE_WEP40 ||
keyconf->cipher == WLAN_CIPHER_SUITE_WEP104) {
- ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf, !mcast);
+ ret = __iwl_mvm_set_sta_key(mvm, vif, sta, keyconf,
+ key_offset, !mcast);
if (ret) {
__clear_bit(keyconf->hw_key_idx, mvm->fw_key_table);
__iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
@@ -1521,7 +1545,7 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
/* Get the station id from the mvm local station table */
- sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+ sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
IWL_DEBUG_WEP(mvm, "mvm remove dynamic key: idx=%d sta=%d\n",
keyconf->keyidx, sta_id);
@@ -1547,24 +1571,6 @@ int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
return 0;
}
- /*
- * It is possible that the 'sta' parameter is NULL, and thus
- * there is a need to retrieve the sta from the local station table,
- * for example when a GTK is removed (where the sta_id will then be
- * the AP ID, and no station was passed by mac80211.)
- */
- if (!sta) {
- sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[sta_id],
- lockdep_is_held(&mvm->mutex));
- if (!sta) {
- IWL_ERR(mvm, "Invalid station id\n");
- return -EINVAL;
- }
- }
-
- if (WARN_ON_ONCE(iwl_mvm_sta_from_mac80211(sta)->vif != vif))
- return -EINVAL;
-
ret = __iwl_mvm_remove_sta_key(mvm, sta_id, keyconf, mcast);
if (ret)
return ret;
@@ -1584,14 +1590,15 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
u16 *phase1key)
{
struct iwl_mvm_sta *mvm_sta;
- u8 sta_id = iwl_mvm_get_key_sta_id(vif, sta);
+ u8 sta_id;
bool mcast = !(keyconf->flags & IEEE80211_KEY_FLAG_PAIRWISE);
- if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
- return;
-
rcu_read_lock();
+ sta_id = iwl_mvm_get_key_sta_id(mvm, vif, sta);
+ if (WARN_ON_ONCE(sta_id == IWL_MVM_STATION_COUNT))
+ goto unlock;
+
if (!sta) {
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
if (WARN_ON(IS_ERR_OR_NULL(sta))) {
@@ -1602,7 +1609,9 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm,
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
iwl_mvm_send_sta_key(mvm, mvm_sta, keyconf, mcast,
- iv32, phase1key, CMD_ASYNC);
+ iv32, phase1key, CMD_ASYNC, keyconf->hw_key_idx);
+
+ unlock:
rcu_read_unlock();
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index eedb215..0631cc0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -365,8 +365,8 @@ int iwl_mvm_rm_sta_id(struct iwl_mvm *mvm,
int iwl_mvm_set_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- bool have_key_offset);
+ struct ieee80211_key_conf *keyconf,
+ u8 key_offset);
int iwl_mvm_remove_sta_key(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index 644b58b..639761f 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -423,14 +423,21 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
/* 8000 Series */
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x1010, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0130, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x1130, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0132, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x1132, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0110, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x01F0, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0012, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x1012, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x1110, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0050, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0250, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x1050, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0150, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x1150, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
- {IWL_PCI_DEVICE(0x24F4, 0x1130, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x1030, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0xC010, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0xC110, iwl8260_2ac_cfg)},
@@ -438,18 +445,28 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24F3, 0xC050, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0xD050, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x8010, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x8110, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x9010, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x9110, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x8030, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x9030, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x8130, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x9130, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x8132, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x9132, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x8050, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x8150, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x9050, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x9150, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0044, iwl8260_2n_cfg)},
{IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0810, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0910, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0850, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0950, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F3, 0x0930, iwl8260_2ac_cfg)},
#endif /* CONFIG_IWLMVM */
{0}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 26cbf1d..faed182 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -56,19 +56,15 @@ static ssize_t lbs_sleepparams_write(struct file *file,
loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- ssize_t buf_size, ret;
+ ssize_t ret;
struct sleep_params sp;
int p1, p2, p3, p4, p5, p6;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(user_buf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, user_buf, buf_size)) {
- ret = -EFAULT;
- goto out_unlock;
- }
ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
if (ret != 6) {
ret = -EINVAL;
@@ -88,7 +84,7 @@ static ssize_t lbs_sleepparams_write(struct file *file,
ret = -EINVAL;
out_unlock:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -125,18 +121,14 @@ static ssize_t lbs_host_sleep_write(struct file *file,
loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- ssize_t buf_size, ret;
+ ssize_t ret;
int host_sleep;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(user_buf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, user_buf, buf_size)) {
- ret = -EFAULT;
- goto out_unlock;
- }
ret = sscanf(buf, "%d", &host_sleep);
if (ret != 1) {
ret = -EINVAL;
@@ -162,7 +154,7 @@ static ssize_t lbs_host_sleep_write(struct file *file,
ret = count;
out_unlock:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -281,21 +273,15 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
struct cmd_ds_802_11_subscribe_event *events;
struct mrvl_ie_thresholds *tlv;
struct lbs_private *priv = file->private_data;
- ssize_t buf_size;
int value, freq, new_mask;
uint16_t curr_mask;
char *buf;
int ret;
- buf = (char *)get_zeroed_page(GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- ret = -EFAULT;
- goto out_page;
- }
ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
if (ret != 3) {
ret = -EINVAL;
@@ -343,7 +329,7 @@ static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
out_events:
kfree(events);
out_page:
- free_page((unsigned long)buf);
+ kfree(buf);
return ret;
}
@@ -472,22 +458,15 @@ static ssize_t lbs_rdmac_write(struct file *file,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
priv->mac_offset = simple_strtoul(buf, NULL, 16);
- res = count;
-out_unlock:
- free_page(addr);
- return res;
+ kfree(buf);
+ return count;
}
static ssize_t lbs_wrmac_write(struct file *file,
@@ -496,18 +475,14 @@ static ssize_t lbs_wrmac_write(struct file *file,
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
+ ssize_t res;
u32 offset, value;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
res = sscanf(buf, "%x %x", &offset, &value);
if (res != 2) {
res = -EFAULT;
@@ -520,7 +495,7 @@ static ssize_t lbs_wrmac_write(struct file *file,
if (!res)
res = count;
out_unlock:
- free_page(addr);
+ kfree(buf);
return res;
}
@@ -554,22 +529,16 @@ static ssize_t lbs_rdbbp_write(struct file *file,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
priv->bbp_offset = simple_strtoul(buf, NULL, 16);
- res = count;
-out_unlock:
- free_page(addr);
- return res;
+ kfree(buf);
+
+ return count;
}
static ssize_t lbs_wrbbp_write(struct file *file,
@@ -578,18 +547,14 @@ static ssize_t lbs_wrbbp_write(struct file *file,
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
+ ssize_t res;
u32 offset, value;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
res = sscanf(buf, "%x %x", &offset, &value);
if (res != 2) {
res = -EFAULT;
@@ -602,7 +567,7 @@ static ssize_t lbs_wrbbp_write(struct file *file,
if (!res)
res = count;
out_unlock:
- free_page(addr);
+ kfree(buf);
return res;
}
@@ -636,22 +601,15 @@ static ssize_t lbs_rdrf_write(struct file *file,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
priv->rf_offset = simple_strtoul(buf, NULL, 16);
- res = count;
-out_unlock:
- free_page(addr);
- return res;
+ kfree(buf);
+ return count;
}
static ssize_t lbs_wrrf_write(struct file *file,
@@ -660,18 +618,14 @@ static ssize_t lbs_wrrf_write(struct file *file,
{
struct lbs_private *priv = file->private_data;
- ssize_t res, buf_size;
+ ssize_t res;
u32 offset, value;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- if (!buf)
- return -ENOMEM;
+ char *buf;
+
+ buf = memdup_user_nul(userbuf, min(count, len - 1));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- buf_size = min(count, len - 1);
- if (copy_from_user(buf, userbuf, buf_size)) {
- res = -EFAULT;
- goto out_unlock;
- }
res = sscanf(buf, "%x %x", &offset, &value);
if (res != 2) {
res = -EFAULT;
@@ -684,7 +638,7 @@ static ssize_t lbs_wrrf_write(struct file *file,
if (!res)
res = count;
out_unlock:
- free_page(addr);
+ kfree(buf);
return res;
}
@@ -915,16 +869,9 @@ static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
if (cnt == 0)
return 0;
- pdata = kmalloc(cnt + 1, GFP_KERNEL);
- if (pdata == NULL)
- return 0;
-
- if (copy_from_user(pdata, buf, cnt)) {
- lbs_deb_debugfs("Copy from user failed\n");
- kfree(pdata);
- return 0;
- }
- pdata[cnt] = '\0';
+ pdata = memdup_user_nul(buf, cnt);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
p0 = pdata;
for (i = 0; i < num_of_items; i++) {
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 9824d8d..241e1c3 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -447,20 +447,13 @@ static ssize_t
mwifiex_regrdwr_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *) addr;
- size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ char *buf;
int ret;
u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
- if (!buf)
- return -ENOMEM;
-
-
- if (copy_from_user(buf, ubuf, buf_size)) {
- ret = -EFAULT;
- goto done;
- }
+ buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
@@ -474,7 +467,7 @@ mwifiex_regrdwr_write(struct file *file,
ret = count;
}
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -572,17 +565,11 @@ mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
int ret;
unsigned long debug_mask;
struct mwifiex_private *priv = (void *)file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (void *)addr;
- size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
+ char *buf;
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, ubuf, buf_size)) {
- ret = -EFAULT;
- goto done;
- }
+ buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
if (kstrtoul(buf, 0, &debug_mask)) {
ret = -EINVAL;
@@ -592,7 +579,7 @@ mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
priv->adapter->debug_mask = debug_mask;
ret = count;
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -609,17 +596,11 @@ mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
struct mwifiex_ds_mem_rw mem_rw;
u16 cmd_action;
struct mwifiex_private *priv = (void *)file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (void *)addr;
- size_t buf_size = min(count, (size_t)(PAGE_SIZE - 1));
-
- if (!buf)
- return -ENOMEM;
+ char *buf;
- if (copy_from_user(buf, ubuf, buf_size)) {
- ret = -EFAULT;
- goto done;
- }
+ buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
if (ret != 3) {
@@ -645,7 +626,7 @@ mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
ret = count;
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -686,20 +667,13 @@ static ssize_t
mwifiex_rdeeprom_write(struct file *file,
const char __user *ubuf, size_t count, loff_t *ppos)
{
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *) addr;
- size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ char *buf;
int ret = 0;
int offset = -1, bytes = -1;
- if (!buf)
- return -ENOMEM;
-
-
- if (copy_from_user(buf, ubuf, buf_size)) {
- ret = -EFAULT;
- goto done;
- }
+ buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
sscanf(buf, "%d %d", &offset, &bytes);
@@ -712,7 +686,7 @@ mwifiex_rdeeprom_write(struct file *file,
ret = count;
}
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
@@ -771,21 +745,15 @@ mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
size_t count, loff_t *ppos)
{
struct mwifiex_private *priv = (void *)file->private_data;
- unsigned long addr = get_zeroed_page(GFP_KERNEL);
- char *buf = (char *)addr;
- size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1);
+ char *buf;
int ret, arg_num;
struct mwifiex_ds_hs_cfg hscfg;
int conditions = HS_CFG_COND_DEF;
u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, ubuf, buf_size)) {
- ret = -EFAULT;
- goto done;
- }
+ buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
@@ -823,7 +791,7 @@ mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
priv->adapter->hs_enabling = false;
ret = count;
done:
- free_page(addr);
+ kfree(buf);
return ret;
}
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
index 6e9418e..bbb789f 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
@@ -2272,7 +2272,7 @@ void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- if (!rtlpci->int_clear)
+ if (rtlpci->int_clear)
rtl8821ae_clear_interrupt(hw);/*clear it here first*/
rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF);
diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
index 8ee141a..142bdff 100644
--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
+++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c
@@ -448,7 +448,7 @@ MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n");
MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
-MODULE_PARM_DESC(int_clear, "Set to 1 to disable interrupt clear before set (default 0)\n");
+MODULE_PARM_DESC(int_clear, "Set to 0 to disable interrupt clear before set (default 1)\n");
static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index eb43f94..be72306 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -1205,26 +1205,11 @@ err_out:
static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
{
- loff_t ret;
-
/* only requests of dword-aligned size and offset are supported */
if (offset % 4)
return -EINVAL;
- switch (orig) {
- case SEEK_SET:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case SEEK_CUR:
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
+ return no_seek_end_llseek(file, offset, orig);
}
static const struct file_operations dev_mem_ops = {
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index e481f37..1049c34 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -258,18 +258,18 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
struct netrx_pending_operations *npo)
{
struct xenvif_rx_meta *meta;
- struct xen_netif_rx_request *req;
+ struct xen_netif_rx_request req;
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
meta = npo->meta + npo->meta_prod++;
meta->gso_type = XEN_NETIF_GSO_TYPE_NONE;
meta->gso_size = 0;
meta->size = 0;
- meta->id = req->id;
+ meta->id = req.id;
npo->copy_off = 0;
- npo->copy_gref = req->gref;
+ npo->copy_gref = req.gref;
return meta;
}
@@ -424,7 +424,7 @@ static int xenvif_gop_skb(struct sk_buff *skb,
struct xenvif *vif = netdev_priv(skb->dev);
int nr_frags = skb_shinfo(skb)->nr_frags;
int i;
- struct xen_netif_rx_request *req;
+ struct xen_netif_rx_request req;
struct xenvif_rx_meta *meta;
unsigned char *data;
int head = 1;
@@ -443,15 +443,15 @@ static int xenvif_gop_skb(struct sk_buff *skb,
/* Set up a GSO prefix descriptor, if necessary */
if ((1 << gso_type) & vif->gso_prefix_mask) {
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
meta = npo->meta + npo->meta_prod++;
meta->gso_type = gso_type;
meta->gso_size = skb_shinfo(skb)->gso_size;
meta->size = 0;
- meta->id = req->id;
+ meta->id = req.id;
}
- req = RING_GET_REQUEST(&queue->rx, queue->rx.req_cons++);
+ RING_COPY_REQUEST(&queue->rx, queue->rx.req_cons++, &req);
meta = npo->meta + npo->meta_prod++;
if ((1 << gso_type) & vif->gso_mask) {
@@ -463,9 +463,9 @@ static int xenvif_gop_skb(struct sk_buff *skb,
}
meta->size = 0;
- meta->id = req->id;
+ meta->id = req.id;
npo->copy_off = 0;
- npo->copy_gref = req->gref;
+ npo->copy_gref = req.gref;
data = skb->data;
while (data < skb_tail_pointer(skb)) {
@@ -679,9 +679,7 @@ static void tx_add_credit(struct xenvif_queue *queue)
* Allow a burst big enough to transmit a jumbo packet of up to 128kB.
* Otherwise the interface can seize up due to insufficient credit.
*/
- max_burst = RING_GET_REQUEST(&queue->tx, queue->tx.req_cons)->size;
- max_burst = min(max_burst, 131072UL);
- max_burst = max(max_burst, queue->credit_bytes);
+ max_burst = max(131072UL, queue->credit_bytes);
/* Take care that adding a new chunk of credit doesn't wrap to zero. */
max_credit = queue->remaining_credit + queue->credit_bytes;
@@ -711,7 +709,7 @@ static void xenvif_tx_err(struct xenvif_queue *queue,
spin_unlock_irqrestore(&queue->response_lock, flags);
if (cons == end)
break;
- txp = RING_GET_REQUEST(&queue->tx, cons++);
+ RING_COPY_REQUEST(&queue->tx, cons++, txp);
} while (1);
queue->tx.req_cons = cons;
}
@@ -778,8 +776,7 @@ static int xenvif_count_requests(struct xenvif_queue *queue,
if (drop_err)
txp = &dropped_tx;
- memcpy(txp, RING_GET_REQUEST(&queue->tx, cons + slots),
- sizeof(*txp));
+ RING_COPY_REQUEST(&queue->tx, cons + slots, txp);
/* If the guest submitted a frame >= 64 KiB then
* first->size overflowed and following slots will
@@ -1112,8 +1109,7 @@ static int xenvif_get_extras(struct xenvif_queue *queue,
return -EBADR;
}
- memcpy(&extra, RING_GET_REQUEST(&queue->tx, cons),
- sizeof(extra));
+ RING_COPY_REQUEST(&queue->tx, cons, &extra);
if (unlikely(!extra.type ||
extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
queue->tx.req_cons = ++cons;
@@ -1322,7 +1318,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue,
idx = queue->tx.req_cons;
rmb(); /* Ensure that we see the request before we copy it. */
- memcpy(&txreq, RING_GET_REQUEST(&queue->tx, idx), sizeof(txreq));
+ RING_COPY_REQUEST(&queue->tx, idx, &txreq);
/* Credit-based scheduling. */
if (txreq.size > queue->remaining_credit &&
diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig
index 444ca94..670af76 100644
--- a/drivers/nfc/nfcmrvl/Kconfig
+++ b/drivers/nfc/nfcmrvl/Kconfig
@@ -44,7 +44,7 @@ config NFC_MRVL_I2C
config NFC_MRVL_SPI
tristate "Marvell NFC-over-SPI driver"
- depends on NFC_MRVL && SPI
+ depends on NFC_MRVL && NFC_NCI_SPI
help
Marvell NFC-over-SPI driver.
diff --git a/drivers/nfc/nfcmrvl/fw_dnld.c b/drivers/nfc/nfcmrvl/fw_dnld.c
index bfa7713..f8dcdf4 100644
--- a/drivers/nfc/nfcmrvl/fw_dnld.c
+++ b/drivers/nfc/nfcmrvl/fw_dnld.c
@@ -113,9 +113,12 @@ static void fw_dnld_over(struct nfcmrvl_private *priv, u32 error)
}
atomic_set(&priv->ndev->cmd_cnt, 0);
- del_timer_sync(&priv->ndev->cmd_timer);
- del_timer_sync(&priv->fw_dnld.timer);
+ if (timer_pending(&priv->ndev->cmd_timer))
+ del_timer_sync(&priv->ndev->cmd_timer);
+
+ if (timer_pending(&priv->fw_dnld.timer))
+ del_timer_sync(&priv->fw_dnld.timer);
nfc_info(priv->dev, "FW loading over (%d)]\n", error);
@@ -472,9 +475,12 @@ void nfcmrvl_fw_dnld_deinit(struct nfcmrvl_private *priv)
void nfcmrvl_fw_dnld_recv_frame(struct nfcmrvl_private *priv,
struct sk_buff *skb)
{
+ /* Discard command timer */
+ if (timer_pending(&priv->ndev->cmd_timer))
+ del_timer_sync(&priv->ndev->cmd_timer);
+
/* Allow next command */
atomic_set(&priv->ndev->cmd_cnt, 1);
- del_timer_sync(&priv->ndev->cmd_timer);
/* Queue and trigger rx work */
skb_queue_tail(&priv->fw_dnld.rx_q, skb);
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
index 8079ae0..51c8240 100644
--- a/drivers/nfc/nfcmrvl/main.c
+++ b/drivers/nfc/nfcmrvl/main.c
@@ -194,6 +194,9 @@ void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
nfcmrvl_fw_dnld_deinit(priv);
+ if (priv->config.reset_n_io)
+ devm_gpio_free(priv->dev, priv->config.reset_n_io);
+
nci_unregister_device(ndev);
nci_free_device(ndev);
kfree(priv);
@@ -251,8 +254,6 @@ void nfcmrvl_chip_halt(struct nfcmrvl_private *priv)
gpio_set_value(priv->config.reset_n_io, 0);
}
-#ifdef CONFIG_OF
-
int nfcmrvl_parse_dt(struct device_node *node,
struct nfcmrvl_platform_data *pdata)
{
@@ -275,16 +276,6 @@ int nfcmrvl_parse_dt(struct device_node *node,
return 0;
}
-
-#else
-
-int nfcmrvl_parse_dt(struct device_node *node,
- struct nfcmrvl_platform_data *pdata)
-{
- return -ENODEV;
-}
-
-#endif
EXPORT_SYMBOL_GPL(nfcmrvl_parse_dt);
MODULE_AUTHOR("Marvell International Ltd.");
diff --git a/drivers/nfc/nfcmrvl/uart.c b/drivers/nfc/nfcmrvl/uart.c
index f3d041c..83a99e3 100644
--- a/drivers/nfc/nfcmrvl/uart.c
+++ b/drivers/nfc/nfcmrvl/uart.c
@@ -67,8 +67,6 @@ static struct nfcmrvl_if_ops uart_ops = {
.nci_update_config = nfcmrvl_uart_nci_update_config
};
-#ifdef CONFIG_OF
-
static int nfcmrvl_uart_parse_dt(struct device_node *node,
struct nfcmrvl_platform_data *pdata)
{
@@ -102,16 +100,6 @@ static int nfcmrvl_uart_parse_dt(struct device_node *node,
return 0;
}
-#else
-
-static int nfcmrvl_uart_parse_dt(struct device_node *node,
- struct nfcmrvl_platform_data *pdata)
-{
- return -ENODEV;
-}
-
-#endif
-
/*
** NCI UART OPS
*/
@@ -152,10 +140,6 @@ static int nfcmrvl_nci_uart_open(struct nci_uart *nu)
nu->drv_data = priv;
nu->ndev = priv->ndev;
- /* Set BREAK */
- if (priv->config.break_control && nu->tty->ops->break_ctl)
- nu->tty->ops->break_ctl(nu->tty, -1);
-
return 0;
}
@@ -174,6 +158,9 @@ static void nfcmrvl_nci_uart_tx_start(struct nci_uart *nu)
{
struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+ if (priv->ndev->nfc_dev->fw_download_in_progress)
+ return;
+
/* Remove BREAK to wake up the NFCC */
if (priv->config.break_control && nu->tty->ops->break_ctl) {
nu->tty->ops->break_ctl(nu->tty, 0);
@@ -185,13 +172,18 @@ static void nfcmrvl_nci_uart_tx_done(struct nci_uart *nu)
{
struct nfcmrvl_private *priv = (struct nfcmrvl_private *)nu->drv_data;
+ if (priv->ndev->nfc_dev->fw_download_in_progress)
+ return;
+
/*
** To ensure that if the NFCC goes in DEEP SLEEP sate we can wake him
** up. we set BREAK. Once we will be ready to send again we will remove
** it.
*/
- if (priv->config.break_control && nu->tty->ops->break_ctl)
+ if (priv->config.break_control && nu->tty->ops->break_ctl) {
nu->tty->ops->break_ctl(nu->tty, -1);
+ usleep_range(1000, 3000);
+ }
}
static struct nci_uart nfcmrvl_nci_uart = {
diff --git a/drivers/nvdimm/blk.c b/drivers/nvdimm/blk.c
index 0df77cb..91a336e 100644
--- a/drivers/nvdimm/blk.c
+++ b/drivers/nvdimm/blk.c
@@ -161,7 +161,7 @@ static int nd_blk_do_bvec(struct nd_blk_device *blk_dev,
return err;
}
-static void nd_blk_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t nd_blk_make_request(struct request_queue *q, struct bio *bio)
{
struct block_device *bdev = bio->bi_bdev;
struct gendisk *disk = bdev->bd_disk;
@@ -208,6 +208,7 @@ static void nd_blk_make_request(struct request_queue *q, struct bio *bio)
out:
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
static int nd_blk_rw_bytes(struct nd_namespace_common *ndns,
diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c
index eae93ab..efb2c1c 100644
--- a/drivers/nvdimm/btt.c
+++ b/drivers/nvdimm/btt.c
@@ -1150,7 +1150,7 @@ static int btt_do_bvec(struct btt *btt, struct bio_integrity_payload *bip,
return ret;
}
-static void btt_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t btt_make_request(struct request_queue *q, struct bio *bio)
{
struct bio_integrity_payload *bip = bio_integrity(bio);
struct btt *btt = q->queuedata;
@@ -1198,6 +1198,7 @@ static void btt_make_request(struct request_queue *q, struct bio *bio)
out:
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
static int btt_rw_page(struct block_device *bdev, sector_t sector,
diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c
index 8282db2..b0045a5 100644
--- a/drivers/nvdimm/e820.c
+++ b/drivers/nvdimm/e820.c
@@ -3,6 +3,7 @@
* Copyright (c) 2015, Intel Corporation.
*/
#include <linux/platform_device.h>
+#include <linux/memory_hotplug.h>
#include <linux/libnvdimm.h>
#include <linux/module.h>
@@ -25,6 +26,18 @@ static int e820_pmem_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+static int e820_range_to_nid(resource_size_t addr)
+{
+ return memory_add_physaddr_to_nid(addr);
+}
+#else
+static int e820_range_to_nid(resource_size_t addr)
+{
+ return NUMA_NO_NODE;
+}
+#endif
+
static int e820_pmem_probe(struct platform_device *pdev)
{
static struct nvdimm_bus_descriptor nd_desc;
@@ -48,7 +61,7 @@ static int e820_pmem_probe(struct platform_device *pdev)
memset(&ndr_desc, 0, sizeof(ndr_desc));
ndr_desc.res = p;
ndr_desc.attr_groups = e820_pmem_region_attribute_groups;
- ndr_desc.numa_node = NUMA_NO_NODE;
+ ndr_desc.numa_node = e820_range_to_nid(p->start);
set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags);
if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc))
goto err;
diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
index 0ba6a97..8ee7989 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
@@ -64,7 +64,7 @@ static void pmem_do_bvec(struct pmem_device *pmem, struct page *page,
kunmap_atomic(mem);
}
-static void pmem_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t pmem_make_request(struct request_queue *q, struct bio *bio)
{
bool do_acct;
unsigned long start;
@@ -84,6 +84,7 @@ static void pmem_make_request(struct request_queue *q, struct bio *bio)
wmb_pmem();
bio_endio(bio);
+ return BLK_QC_T_NONE;
}
static int pmem_rw_page(struct block_device *bdev, sector_t sector,
@@ -104,22 +105,11 @@ static long pmem_direct_access(struct block_device *bdev, sector_t sector,
{
struct pmem_device *pmem = bdev->bd_disk->private_data;
resource_size_t offset = sector * 512 + pmem->data_offset;
- resource_size_t size;
-
- if (pmem->data_offset) {
- /*
- * Limit the direct_access() size to what is covered by
- * the memmap
- */
- size = (pmem->size - offset) & ~ND_PFN_MASK;
- } else
- size = pmem->size - offset;
-
- /* FIXME convert DAX to comprehend that this mapping has a lifetime */
+
*kaddr = pmem->virt_addr + offset;
*pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT;
- return size;
+ return pmem->size - offset;
}
static const struct block_device_operations pmem_fops = {
@@ -150,18 +140,15 @@ static struct pmem_device *pmem_alloc(struct device *dev,
return ERR_PTR(-EBUSY);
}
- if (pmem_should_map_pages(dev)) {
- void *addr = devm_memremap_pages(dev, res);
+ if (pmem_should_map_pages(dev))
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res);
+ else
+ pmem->virt_addr = (void __pmem *) devm_memremap(dev,
+ pmem->phys_addr, pmem->size,
+ ARCH_MEMREMAP_PMEM);
- if (IS_ERR(addr))
- return addr;
- pmem->virt_addr = (void __pmem *) addr;
- } else {
- pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr,
- pmem->size);
- if (!pmem->virt_addr)
- return ERR_PTR(-ENXIO);
- }
+ if (IS_ERR(pmem->virt_addr))
+ return (void __force *) pmem->virt_addr;
return pmem;
}
@@ -179,9 +166,10 @@ static void pmem_detach_disk(struct pmem_device *pmem)
static int pmem_attach_disk(struct device *dev,
struct nd_namespace_common *ndns, struct pmem_device *pmem)
{
+ int nid = dev_to_node(dev);
struct gendisk *disk;
- pmem->pmem_queue = blk_alloc_queue(GFP_KERNEL);
+ pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid);
if (!pmem->pmem_queue)
return -ENOMEM;
@@ -191,7 +179,7 @@ static int pmem_attach_disk(struct device *dev,
blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY);
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue);
- disk = alloc_disk(0);
+ disk = alloc_disk_node(0, nid);
if (!disk) {
blk_cleanup_queue(pmem->pmem_queue);
return -ENOMEM;
@@ -363,8 +351,8 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
/* establish pfn range for lookup, and switch to direct map */
pmem = dev_get_drvdata(dev);
- memunmap_pmem(dev, pmem->virt_addr);
- pmem->virt_addr = (void __pmem *)devm_memremap_pages(dev, &nsio->res);
+ devm_memunmap(dev, (void __force *) pmem->virt_addr);
+ pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res);
if (IS_ERR(pmem->virt_addr)) {
rc = PTR_ERR(pmem->virt_addr);
goto err;
diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile
index 219dc206..a5fe239 100644
--- a/drivers/nvme/host/Makefile
+++ b/drivers/nvme/host/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_BLK_DEV_NVME) += nvme.o
-nvme-y += pci.o scsi.o lightnvm.o
+lightnvm-$(CONFIG_NVM) := lightnvm.o
+nvme-y += pci.o scsi.o $(lightnvm-y)
diff --git a/drivers/nvme/host/lightnvm.c b/drivers/nvme/host/lightnvm.c
index e0b7b95..15f2acb 100644
--- a/drivers/nvme/host/lightnvm.c
+++ b/drivers/nvme/host/lightnvm.c
@@ -22,8 +22,6 @@
#include "nvme.h"
-#ifdef CONFIG_NVM
-
#include <linux/nvme.h>
#include <linux/bitops.h>
#include <linux/lightnvm.h>
@@ -93,7 +91,7 @@ struct nvme_nvm_l2ptbl {
__le16 cdw14[6];
};
-struct nvme_nvm_bbtbl {
+struct nvme_nvm_getbbtbl {
__u8 opcode;
__u8 flags;
__u16 command_id;
@@ -101,10 +99,23 @@ struct nvme_nvm_bbtbl {
__u64 rsvd[2];
__le64 prp1;
__le64 prp2;
- __le32 prp1_len;
- __le32 prp2_len;
- __le32 lbb;
- __u32 rsvd11[3];
+ __le64 spba;
+ __u32 rsvd4[4];
+};
+
+struct nvme_nvm_setbbtbl {
+ __u8 opcode;
+ __u8 flags;
+ __u16 command_id;
+ __le32 nsid;
+ __le64 rsvd[2];
+ __le64 prp1;
+ __le64 prp2;
+ __le64 spba;
+ __le16 nlb;
+ __u8 value;
+ __u8 rsvd3;
+ __u32 rsvd4[3];
};
struct nvme_nvm_erase_blk {
@@ -129,8 +140,8 @@ struct nvme_nvm_command {
struct nvme_nvm_hb_rw hb_rw;
struct nvme_nvm_ph_rw ph_rw;
struct nvme_nvm_l2ptbl l2p;
- struct nvme_nvm_bbtbl get_bb;
- struct nvme_nvm_bbtbl set_bb;
+ struct nvme_nvm_getbbtbl get_bb;
+ struct nvme_nvm_setbbtbl set_bb;
struct nvme_nvm_erase_blk erase;
};
};
@@ -142,11 +153,13 @@ struct nvme_nvm_id_group {
__u8 num_ch;
__u8 num_lun;
__u8 num_pln;
+ __u8 rsvd1;
__le16 num_blk;
__le16 num_pg;
__le16 fpg_sz;
__le16 csecs;
__le16 sos;
+ __le16 rsvd2;
__le32 trdt;
__le32 trdm;
__le32 tprt;
@@ -154,8 +167,9 @@ struct nvme_nvm_id_group {
__le32 tbet;
__le32 tbem;
__le32 mpos;
+ __le32 mccap;
__le16 cpar;
- __u8 reserved[913];
+ __u8 reserved[906];
} __packed;
struct nvme_nvm_addr_format {
@@ -178,15 +192,28 @@ struct nvme_nvm_id {
__u8 ver_id;
__u8 vmnt;
__u8 cgrps;
- __u8 res[5];
+ __u8 res;
__le32 cap;
__le32 dom;
struct nvme_nvm_addr_format ppaf;
- __u8 ppat;
- __u8 resv[223];
+ __u8 resv[228];
struct nvme_nvm_id_group groups[4];
} __packed;
+struct nvme_nvm_bb_tbl {
+ __u8 tblid[4];
+ __le16 verid;
+ __le16 revid;
+ __le32 rvsd1;
+ __le32 tblks;
+ __le32 tfact;
+ __le32 tgrown;
+ __le32 tdresv;
+ __le32 thresv;
+ __le32 rsvd2[8];
+ __u8 blk[0];
+};
+
/*
* Check we didn't inadvertently grow the command struct
*/
@@ -195,12 +222,14 @@ static inline void _nvme_nvm_check_size(void)
BUILD_BUG_ON(sizeof(struct nvme_nvm_identity) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_hb_rw) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_ph_rw) != 64);
- BUILD_BUG_ON(sizeof(struct nvme_nvm_bbtbl) != 64);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_getbbtbl) != 64);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_setbbtbl) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_l2ptbl) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id_group) != 960);
BUILD_BUG_ON(sizeof(struct nvme_nvm_addr_format) != 128);
BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != 4096);
+ BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 512);
}
static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
@@ -234,6 +263,7 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
dst->tbet = le32_to_cpu(src->tbet);
dst->tbem = le32_to_cpu(src->tbem);
dst->mpos = le32_to_cpu(src->mpos);
+ dst->mccap = le32_to_cpu(src->mccap);
dst->cpar = le16_to_cpu(src->cpar);
}
@@ -241,9 +271,10 @@ static int init_grps(struct nvm_id *nvm_id, struct nvme_nvm_id *nvme_nvm_id)
return 0;
}
-static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
+static int nvme_nvm_identity(struct nvm_dev *nvmdev, struct nvm_id *nvm_id)
{
- struct nvme_ns *ns = q->queuedata;
+ struct nvme_ns *ns = nvmdev->q->queuedata;
+ struct nvme_dev *dev = ns->dev;
struct nvme_nvm_id *nvme_nvm_id;
struct nvme_nvm_command c = {};
int ret;
@@ -256,8 +287,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
if (!nvme_nvm_id)
return -ENOMEM;
- ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, nvme_nvm_id,
- sizeof(struct nvme_nvm_id));
+ ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+ nvme_nvm_id, sizeof(struct nvme_nvm_id));
if (ret) {
ret = -EIO;
goto out;
@@ -268,6 +299,8 @@ static int nvme_nvm_identity(struct request_queue *q, struct nvm_id *nvm_id)
nvm_id->cgrps = nvme_nvm_id->cgrps;
nvm_id->cap = le32_to_cpu(nvme_nvm_id->cap);
nvm_id->dom = le32_to_cpu(nvme_nvm_id->dom);
+ memcpy(&nvm_id->ppaf, &nvme_nvm_id->ppaf,
+ sizeof(struct nvme_nvm_addr_format));
ret = init_grps(nvm_id, nvme_nvm_id);
out:
@@ -275,13 +308,13 @@ out:
return ret;
}
-static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb,
+static int nvme_nvm_get_l2p_tbl(struct nvm_dev *nvmdev, u64 slba, u32 nlb,
nvm_l2p_update_fn *update_l2p, void *priv)
{
- struct nvme_ns *ns = q->queuedata;
+ struct nvme_ns *ns = nvmdev->q->queuedata;
struct nvme_dev *dev = ns->dev;
struct nvme_nvm_command c = {};
- u32 len = queue_max_hw_sectors(q) << 9;
+ u32 len = queue_max_hw_sectors(dev->admin_q) << 9;
u32 nlb_pr_rq = len / sizeof(u64);
u64 cmd_slba = slba;
void *entries;
@@ -299,8 +332,8 @@ static int nvme_nvm_get_l2p_tbl(struct request_queue *q, u64 slba, u32 nlb,
c.l2p.slba = cpu_to_le64(cmd_slba);
c.l2p.nlb = cpu_to_le32(cmd_nlb);
- ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c,
- entries, len);
+ ret = nvme_submit_sync_cmd(dev->admin_q,
+ (struct nvme_command *)&c, entries, len);
if (ret) {
dev_err(dev->dev, "L2P table transfer failed (%d)\n",
ret);
@@ -322,43 +355,84 @@ out:
return ret;
}
-static int nvme_nvm_get_bb_tbl(struct request_queue *q, int lunid,
- unsigned int nr_blocks,
- nvm_bb_update_fn *update_bbtbl, void *priv)
+static int nvme_nvm_get_bb_tbl(struct nvm_dev *nvmdev, struct ppa_addr ppa,
+ int nr_blocks, nvm_bb_update_fn *update_bbtbl,
+ void *priv)
{
+ struct request_queue *q = nvmdev->q;
struct nvme_ns *ns = q->queuedata;
struct nvme_dev *dev = ns->dev;
struct nvme_nvm_command c = {};
- void *bb_bitmap;
- u16 bb_bitmap_size;
+ struct nvme_nvm_bb_tbl *bb_tbl;
+ int tblsz = sizeof(struct nvme_nvm_bb_tbl) + nr_blocks;
int ret = 0;
c.get_bb.opcode = nvme_nvm_admin_get_bb_tbl;
c.get_bb.nsid = cpu_to_le32(ns->ns_id);
- c.get_bb.lbb = cpu_to_le32(lunid);
- bb_bitmap_size = ((nr_blocks >> 15) + 1) * PAGE_SIZE;
- bb_bitmap = kmalloc(bb_bitmap_size, GFP_KERNEL);
- if (!bb_bitmap)
- return -ENOMEM;
+ c.get_bb.spba = cpu_to_le64(ppa.ppa);
- bitmap_zero(bb_bitmap, nr_blocks);
+ bb_tbl = kzalloc(tblsz, GFP_KERNEL);
+ if (!bb_tbl)
+ return -ENOMEM;
- ret = nvme_submit_sync_cmd(q, (struct nvme_command *)&c, bb_bitmap,
- bb_bitmap_size);
+ ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+ bb_tbl, tblsz);
if (ret) {
dev_err(dev->dev, "get bad block table failed (%d)\n", ret);
ret = -EIO;
goto out;
}
- ret = update_bbtbl(lunid, bb_bitmap, nr_blocks, priv);
+ if (bb_tbl->tblid[0] != 'B' || bb_tbl->tblid[1] != 'B' ||
+ bb_tbl->tblid[2] != 'L' || bb_tbl->tblid[3] != 'T') {
+ dev_err(dev->dev, "bbt format mismatch\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (le16_to_cpu(bb_tbl->verid) != 1) {
+ ret = -EINVAL;
+ dev_err(dev->dev, "bbt version not supported\n");
+ goto out;
+ }
+
+ if (le32_to_cpu(bb_tbl->tblks) != nr_blocks) {
+ ret = -EINVAL;
+ dev_err(dev->dev, "bbt unsuspected blocks returned (%u!=%u)",
+ le32_to_cpu(bb_tbl->tblks), nr_blocks);
+ goto out;
+ }
+
+ ppa = dev_to_generic_addr(nvmdev, ppa);
+ ret = update_bbtbl(ppa, nr_blocks, bb_tbl->blk, priv);
if (ret) {
ret = -EINTR;
goto out;
}
out:
- kfree(bb_bitmap);
+ kfree(bb_tbl);
+ return ret;
+}
+
+static int nvme_nvm_set_bb_tbl(struct nvm_dev *nvmdev, struct nvm_rq *rqd,
+ int type)
+{
+ struct nvme_ns *ns = nvmdev->q->queuedata;
+ struct nvme_dev *dev = ns->dev;
+ struct nvme_nvm_command c = {};
+ int ret = 0;
+
+ c.set_bb.opcode = nvme_nvm_admin_set_bb_tbl;
+ c.set_bb.nsid = cpu_to_le32(ns->ns_id);
+ c.set_bb.spba = cpu_to_le64(rqd->ppa_addr.ppa);
+ c.set_bb.nlb = cpu_to_le16(rqd->nr_pages - 1);
+ c.set_bb.value = type;
+
+ ret = nvme_submit_sync_cmd(dev->admin_q, (struct nvme_command *)&c,
+ NULL, 0);
+ if (ret)
+ dev_err(dev->dev, "set bad block table failed (%d)\n", ret);
return ret;
}
@@ -381,7 +455,7 @@ static void nvme_nvm_end_io(struct request *rq, int error)
struct nvm_rq *rqd = rq->end_io_data;
struct nvm_dev *dev = rqd->dev;
- if (dev->mt->end_io(rqd, error))
+ if (dev->mt && dev->mt->end_io(rqd, error))
pr_err("nvme: err status: %x result: %lx\n",
rq->errors, (unsigned long)rq->special);
@@ -389,8 +463,9 @@ static void nvme_nvm_end_io(struct request *rq, int error)
blk_mq_free_request(rq);
}
-static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd)
+static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
{
+ struct request_queue *q = dev->q;
struct nvme_ns *ns = q->queuedata;
struct request *rq;
struct bio *bio = rqd->bio;
@@ -428,8 +503,9 @@ static int nvme_nvm_submit_io(struct request_queue *q, struct nvm_rq *rqd)
return 0;
}
-static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd)
+static int nvme_nvm_erase_block(struct nvm_dev *dev, struct nvm_rq *rqd)
{
+ struct request_queue *q = dev->q;
struct nvme_ns *ns = q->queuedata;
struct nvme_nvm_command c = {};
@@ -441,9 +517,9 @@ static int nvme_nvm_erase_block(struct request_queue *q, struct nvm_rq *rqd)
return nvme_submit_sync_cmd(q, (struct nvme_command *)&c, NULL, 0);
}
-static void *nvme_nvm_create_dma_pool(struct request_queue *q, char *name)
+static void *nvme_nvm_create_dma_pool(struct nvm_dev *nvmdev, char *name)
{
- struct nvme_ns *ns = q->queuedata;
+ struct nvme_ns *ns = nvmdev->q->queuedata;
struct nvme_dev *dev = ns->dev;
return dma_pool_create(name, dev->dev, PAGE_SIZE, PAGE_SIZE, 0);
@@ -456,7 +532,7 @@ static void nvme_nvm_destroy_dma_pool(void *pool)
dma_pool_destroy(dma_pool);
}
-static void *nvme_nvm_dev_dma_alloc(struct request_queue *q, void *pool,
+static void *nvme_nvm_dev_dma_alloc(struct nvm_dev *dev, void *pool,
gfp_t mem_flags, dma_addr_t *dma_handler)
{
return dma_pool_alloc(pool, mem_flags, dma_handler);
@@ -474,6 +550,7 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
.get_l2p_tbl = nvme_nvm_get_l2p_tbl,
.get_bb_tbl = nvme_nvm_get_bb_tbl,
+ .set_bb_tbl = nvme_nvm_set_bb_tbl,
.submit_io = nvme_nvm_submit_io,
.erase_block = nvme_nvm_erase_block,
@@ -496,31 +573,27 @@ void nvme_nvm_unregister(struct request_queue *q, char *disk_name)
nvm_unregister(disk_name);
}
+/* move to shared place when used in multiple places. */
+#define PCI_VENDOR_ID_CNEX 0x1d1d
+#define PCI_DEVICE_ID_CNEX_WL 0x2807
+#define PCI_DEVICE_ID_CNEX_QEMU 0x1f1f
+
int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
{
struct nvme_dev *dev = ns->dev;
struct pci_dev *pdev = to_pci_dev(dev->dev);
/* QEMU NVMe simulator - PCI ID + Vendor specific bit */
- if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x5845 &&
+ if (pdev->vendor == PCI_VENDOR_ID_CNEX &&
+ pdev->device == PCI_DEVICE_ID_CNEX_QEMU &&
id->vs[0] == 0x1)
return 1;
/* CNEX Labs - PCI ID + Vendor specific bit */
- if (pdev->vendor == 0x1d1d && pdev->device == 0x2807 &&
+ if (pdev->vendor == PCI_VENDOR_ID_CNEX &&
+ pdev->device == PCI_DEVICE_ID_CNEX_WL &&
id->vs[0] == 0x1)
return 1;
return 0;
}
-#else
-int nvme_nvm_register(struct request_queue *q, char *disk_name)
-{
- return 0;
-}
-void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {};
-int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
-{
- return 0;
-}
-#endif /* CONFIG_NVM */
diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
index fdb4e5b..044253d 100644
--- a/drivers/nvme/host/nvme.h
+++ b/drivers/nvme/host/nvme.h
@@ -136,8 +136,22 @@ int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg);
int nvme_sg_get_version_num(int __user *ip);
+#ifdef CONFIG_NVM
int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
int nvme_nvm_register(struct request_queue *q, char *disk_name);
void nvme_nvm_unregister(struct request_queue *q, char *disk_name);
+#else
+static inline int nvme_nvm_register(struct request_queue *q, char *disk_name)
+{
+ return 0;
+}
+
+static inline void nvme_nvm_unregister(struct request_queue *q, char *disk_name) {};
+
+static inline int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id)
+{
+ return 0;
+}
+#endif /* CONFIG_NVM */
#endif /* _NVME_H */
diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
index 97b6640..0c67b57 100644
--- a/drivers/nvme/host/pci.c
+++ b/drivers/nvme/host/pci.c
@@ -90,7 +90,7 @@ static struct class *nvme_class;
static int __nvme_reset(struct nvme_dev *dev);
static int nvme_reset(struct nvme_dev *dev);
-static int nvme_process_cq(struct nvme_queue *nvmeq);
+static void nvme_process_cq(struct nvme_queue *nvmeq);
static void nvme_dead_ctrl(struct nvme_dev *dev);
struct async_cmd_info {
@@ -896,19 +896,28 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
goto retry_cmd;
}
if (blk_integrity_rq(req)) {
- if (blk_rq_count_integrity_sg(req->q, req->bio) != 1)
+ if (blk_rq_count_integrity_sg(req->q, req->bio) != 1) {
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+ dma_dir);
goto error_cmd;
+ }
sg_init_table(iod->meta_sg, 1);
if (blk_rq_map_integrity_sg(
- req->q, req->bio, iod->meta_sg) != 1)
+ req->q, req->bio, iod->meta_sg) != 1) {
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+ dma_dir);
goto error_cmd;
+ }
if (rq_data_dir(req))
nvme_dif_remap(req, nvme_dif_prep);
- if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir))
+ if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir)) {
+ dma_unmap_sg(dev->dev, iod->sg, iod->nents,
+ dma_dir);
goto error_cmd;
+ }
}
}
@@ -935,7 +944,7 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
return BLK_MQ_RQ_QUEUE_BUSY;
}
-static int nvme_process_cq(struct nvme_queue *nvmeq)
+static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag)
{
u16 head, phase;
@@ -953,6 +962,8 @@ static int nvme_process_cq(struct nvme_queue *nvmeq)
head = 0;
phase = !phase;
}
+ if (tag && *tag == cqe.command_id)
+ *tag = -1;
ctx = nvme_finish_cmd(nvmeq, cqe.command_id, &fn);
fn(nvmeq, ctx, &cqe);
}
@@ -964,14 +975,19 @@ static int nvme_process_cq(struct nvme_queue *nvmeq)
* a big problem.
*/
if (head == nvmeq->cq_head && phase == nvmeq->cq_phase)
- return 0;
+ return;
- writel(head, nvmeq->q_db + nvmeq->dev->db_stride);
+ if (likely(nvmeq->cq_vector >= 0))
+ writel(head, nvmeq->q_db + nvmeq->dev->db_stride);
nvmeq->cq_head = head;
nvmeq->cq_phase = phase;
nvmeq->cqe_seen = 1;
- return 1;
+}
+
+static void nvme_process_cq(struct nvme_queue *nvmeq)
+{
+ __nvme_process_cq(nvmeq, NULL);
}
static irqreturn_t nvme_irq(int irq, void *data)
@@ -995,6 +1011,23 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
return IRQ_WAKE_THREAD;
}
+static int nvme_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
+{
+ struct nvme_queue *nvmeq = hctx->driver_data;
+
+ if ((le16_to_cpu(nvmeq->cqes[nvmeq->cq_head].status) & 1) ==
+ nvmeq->cq_phase) {
+ spin_lock_irq(&nvmeq->q_lock);
+ __nvme_process_cq(nvmeq, &tag);
+ spin_unlock_irq(&nvmeq->q_lock);
+
+ if (tag == -1)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* Returns 0 on success. If the result is negative, it's a Linux error code;
* if the result is positive, it's an NVM Express status code
@@ -1656,6 +1689,7 @@ static struct blk_mq_ops nvme_mq_ops = {
.init_hctx = nvme_init_hctx,
.init_request = nvme_init_request,
.timeout = nvme_timeout,
+ .poll = nvme_poll,
};
static void nvme_dev_remove_admin(struct nvme_dev *dev)
@@ -1701,11 +1735,15 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
{
int result;
u32 aqa;
- u64 cap = readq(&dev->bar->cap);
+ u64 cap = lo_hi_readq(&dev->bar->cap);
struct nvme_queue *nvmeq;
- unsigned page_shift = PAGE_SHIFT;
+ /*
+ * default to a 4K page size, with the intention to update this
+ * path in the future to accomodate architectures with differing
+ * kernel and IO page sizes.
+ */
+ unsigned page_shift = 12;
unsigned dev_page_min = NVME_CAP_MPSMIN(cap) + 12;
- unsigned dev_page_max = NVME_CAP_MPSMAX(cap) + 12;
if (page_shift < dev_page_min) {
dev_err(dev->dev,
@@ -1714,13 +1752,6 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
1 << page_shift);
return -ENODEV;
}
- if (page_shift > dev_page_max) {
- dev_info(dev->dev,
- "Device maximum page size (%u) smaller than "
- "host (%u); enabling work-around\n",
- 1 << dev_page_max, 1 << page_shift);
- page_shift = dev_page_max;
- }
dev->subsystem = readl(&dev->bar->vs) >= NVME_VS(1, 1) ?
NVME_CAP_NSSRC(cap) : 0;
@@ -1750,8 +1781,8 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
dev->ctrl_config |= NVME_CC_IOSQES | NVME_CC_IOCQES;
writel(aqa, &dev->bar->aqa);
- writeq(nvmeq->sq_dma_addr, &dev->bar->asq);
- writeq(nvmeq->cq_dma_addr, &dev->bar->acq);
+ lo_hi_writeq(nvmeq->sq_dma_addr, &dev->bar->asq);
+ lo_hi_writeq(nvmeq->cq_dma_addr, &dev->bar->acq);
result = nvme_enable_ctrl(dev, cap);
if (result)
@@ -2244,7 +2275,7 @@ static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
if (dev->max_hw_sectors) {
blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
blk_queue_max_segments(ns->queue,
- ((dev->max_hw_sectors << 9) / dev->page_size) + 1);
+ (dev->max_hw_sectors / (dev->page_size >> 9)) + 1);
}
if (dev->stripe_size)
blk_queue_chunk_sectors(ns->queue, dev->stripe_size >> 9);
@@ -2509,8 +2540,17 @@ static void nvme_ns_remove(struct nvme_ns *ns)
{
bool kill = nvme_io_incapable(ns->dev) && !blk_queue_dying(ns->queue);
- if (kill)
+ if (kill) {
blk_set_queue_dying(ns->queue);
+
+ /*
+ * The controller was shutdown first if we got here through
+ * device removal. The shutdown may requeue outstanding
+ * requests. These need to be aborted immediately so
+ * del_gendisk doesn't block indefinitely for their completion.
+ */
+ blk_mq_abort_requeue_list(ns->queue);
+ }
if (ns->disk->flags & GENHD_FL_UP)
del_gendisk(ns->disk);
if (kill || !blk_queue_dying(ns->queue)) {
@@ -2582,7 +2622,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
struct pci_dev *pdev = to_pci_dev(dev->dev);
int res;
struct nvme_id_ctrl *ctrl;
- int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
+ int shift = NVME_CAP_MPSMIN(lo_hi_readq(&dev->bar->cap)) + 12;
res = nvme_identify_ctrl(dev, &ctrl);
if (res) {
@@ -2598,6 +2638,8 @@ static int nvme_dev_add(struct nvme_dev *dev)
memcpy(dev->firmware_rev, ctrl->fr, sizeof(ctrl->fr));
if (ctrl->mdts)
dev->max_hw_sectors = 1 << (ctrl->mdts + shift - 9);
+ else
+ dev->max_hw_sectors = UINT_MAX;
if ((pdev->vendor == PCI_VENDOR_ID_INTEL) &&
(pdev->device == 0x0953) && ctrl->vs[3]) {
unsigned int max_hw_sectors;
@@ -2671,10 +2713,22 @@ static int nvme_dev_map(struct nvme_dev *dev)
goto unmap;
}
- cap = readq(&dev->bar->cap);
+ cap = lo_hi_readq(&dev->bar->cap);
dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH);
dev->db_stride = 1 << NVME_CAP_STRIDE(cap);
dev->dbs = ((void __iomem *)dev->bar) + 4096;
+
+ /*
+ * Temporary fix for the Apple controller found in the MacBook8,1 and
+ * some MacBook7,1 to avoid controller resets and data loss.
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_APPLE && pdev->device == 0x2001) {
+ dev->q_depth = 2;
+ dev_warn(dev->dev, "detected Apple NVMe controller, set "
+ "queue depth=%u to work around controller resets\n",
+ dev->q_depth);
+ }
+
if (readl(&dev->bar->vs) >= NVME_VS(1, 2))
dev->cmb = nvme_map_cmb(dev);
@@ -2734,7 +2788,7 @@ static void nvme_wait_dq(struct nvme_delq_ctx *dq, struct nvme_dev *dev)
* queues than admin tags.
*/
set_current_state(TASK_RUNNING);
- nvme_disable_ctrl(dev, readq(&dev->bar->cap));
+ nvme_disable_ctrl(dev, lo_hi_readq(&dev->bar->cap));
nvme_clear_queue(dev->queues[0]);
flush_kthread_worker(dq->worker);
nvme_disable_queue(dev, 0);
@@ -2761,6 +2815,10 @@ static void nvme_del_queue_end(struct nvme_queue *nvmeq)
{
struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx;
nvme_put_dq(dq);
+
+ spin_lock_irq(&nvmeq->q_lock);
+ nvme_process_cq(nvmeq);
+ spin_unlock_irq(&nvmeq->q_lock);
}
static int adapter_async_del_queue(struct nvme_queue *nvmeq, u8 opcode,
@@ -2928,6 +2986,15 @@ static void nvme_dev_remove(struct nvme_dev *dev)
{
struct nvme_ns *ns, *next;
+ if (nvme_io_incapable(dev)) {
+ /*
+ * If the device is not capable of IO (surprise hot-removal,
+ * for example), we need to quiesce prior to deleting the
+ * namespaces. This will end outstanding requests and prevent
+ * attempts to sync dirty data.
+ */
+ nvme_dev_shutdown(dev);
+ }
list_for_each_entry_safe(ns, next, &dev->namespaces, list)
nvme_ns_remove(ns);
}
@@ -3377,6 +3444,7 @@ static const struct pci_error_handlers nvme_err_handler = {
static const struct pci_device_id nvme_id_table[] = {
{ PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) },
+ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, nvme_id_table);
diff --git a/drivers/of/address.c b/drivers/of/address.c
index cd53fe4..9582c57 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -485,9 +485,10 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
int rone;
u64 offset = OF_BAD_ADDR;
- /* Normally, an absence of a "ranges" property means we are
+ /*
+ * Normally, an absence of a "ranges" property means we are
* crossing a non-translatable boundary, and thus the addresses
- * below the current not cannot be converted to CPU physical ones.
+ * below the current cannot be converted to CPU physical ones.
* Unfortunately, while this is very clear in the spec, it's not
* what Apple understood, and they do have things like /uni-n or
* /ht nodes with no "ranges" property and a lot of perfectly
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index d243029..655f79d 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
+#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
@@ -436,6 +437,8 @@ static void *kernel_tree_alloc(u64 size, u64 align)
return kzalloc(size, GFP_KERNEL);
}
+static DEFINE_MUTEX(of_fdt_unflatten_mutex);
+
/**
* of_fdt_unflatten_tree - create tree of device_nodes from flat blob
*
@@ -447,7 +450,9 @@ static void *kernel_tree_alloc(u64 size, u64 align)
void of_fdt_unflatten_tree(const unsigned long *blob,
struct device_node **mynodes)
{
+ mutex_lock(&of_fdt_unflatten_mutex);
__unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
+ mutex_unlock(&of_fdt_unflatten_mutex);
}
EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
@@ -1041,7 +1046,7 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
- pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n",
+ pr_err("Reserved memory not supported, ignoring range %pa - %pa%s\n",
&base, &size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 902b89b..4fa916d 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -53,7 +53,7 @@ EXPORT_SYMBOL_GPL(irq_of_parse_and_map);
* Returns a pointer to the interrupt parent node, or NULL if the interrupt
* parent could not be determined.
*/
-static struct device_node *of_irq_find_parent(struct device_node *child)
+struct device_node *of_irq_find_parent(struct device_node *child)
{
struct device_node *p;
const __be32 *parp;
@@ -77,6 +77,7 @@ static struct device_node *of_irq_find_parent(struct device_node *child)
return p;
}
+EXPORT_SYMBOL_GPL(of_irq_find_parent);
/**
* of_irq_parse_raw - Low level interrupt tree parsing
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index ff27177..b1449f7 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -143,26 +143,6 @@ void of_pci_check_probe_only(void)
}
EXPORT_SYMBOL_GPL(of_pci_check_probe_only);
-/**
- * of_pci_dma_configure - Setup DMA configuration
- * @dev: ptr to pci_dev struct of the PCI device
- *
- * Function to update PCI devices's DMA configuration using the same
- * info from the OF node of host bridge's parent (if any).
- */
-void of_pci_dma_configure(struct pci_dev *pci_dev)
-{
- struct device *dev = &pci_dev->dev;
- struct device *bridge = pci_get_host_bridge_device(pci_dev);
-
- if (!bridge->parent)
- return;
-
- of_dma_configure(dev, bridge->parent->of_node);
- pci_put_host_bridge_device(bridge);
-}
-EXPORT_SYMBOL_GPL(of_pci_dma_configure);
-
#if defined(CONFIG_OF_ADDRESS)
/**
* of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index 62f467b..1a3556a 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -124,6 +124,10 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
align = dt_mem_next_cell(dt_root_addr_cells, &prop);
}
+ /* Need adjust the alignment to satisfy the CMA requirement */
+ if (IS_ENABLED(CONFIG_CMA) && of_flat_dt_is_compatible(node, "shared-dma-pool"))
+ align = max(align, (phys_addr_t)PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order));
+
prop = of_get_flat_dt_prop(node, "alloc-ranges", &len);
if (prop) {
@@ -202,7 +206,13 @@ static int __init __rmem_cmp(const void *a, const void *b)
{
const struct reserved_mem *ra = a, *rb = b;
- return ra->base - rb->base;
+ if (ra->base < rb->base)
+ return -1;
+
+ if (ra->base > rb->base)
+ return 1;
+
+ return 0;
}
static void __init __rmem_check_for_overlap(void)
@@ -226,10 +236,9 @@ static void __init __rmem_check_for_overlap(void)
this_end = this->base + this->size;
next_end = next->base + next->size;
- WARN(1,
- "Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",
- this->name, &this->base, &this_end,
- next->name, &next->base, &next_end);
+ pr_err("Reserved memory: OVERLAP DETECTED!\n%s (%pa--%pa) overlaps with %s (%pa--%pa)\n",
+ this->name, &this->base, &this_end,
+ next->name, &next->base, &next_end);
}
}
}
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 957b421..8e11fb2 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -704,8 +704,6 @@ ccio_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt)
* ccio_dma_supported - Verify the IOMMU supports the DMA address range.
* @dev: The PCI device.
* @mask: A bit mask describing the DMA address range of the device.
- *
- * This function implements the pci_dma_supported function.
*/
static int
ccio_dma_supported(struct device *dev, u64 mask)
diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h
index 761e77b..e56f156 100644
--- a/drivers/parisc/iommu-helpers.h
+++ b/drivers/parisc/iommu-helpers.h
@@ -104,7 +104,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
struct scatterlist *contig_sg; /* contig chunk head */
unsigned long dma_offset, dma_len; /* start/len of DMA stream */
unsigned int n_mappings = 0;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
+ unsigned int max_seg_size = min(dma_get_max_seg_size(dev),
+ (unsigned)DMA_CHUNK_SIZE);
+ unsigned int max_seg_boundary = dma_get_seg_boundary(dev) + 1;
+ if (max_seg_boundary) /* check if the addition above didn't overflow */
+ max_seg_size = min(max_seg_size, max_seg_boundary);
while (nents > 0) {
@@ -138,14 +142,11 @@ iommu_coalesce_chunks(struct ioc *ioc, struct device *dev,
/*
** First make sure current dma stream won't
- ** exceed DMA_CHUNK_SIZE if we coalesce the
+ ** exceed max_seg_size if we coalesce the
** next entry.
*/
- if(unlikely(ALIGN(dma_len + dma_offset + startsg->length,
- IOVP_SIZE) > DMA_CHUNK_SIZE))
- break;
-
- if (startsg->length + dma_len > max_seg_size)
+ if (unlikely(ALIGN(dma_len + dma_offset + startsg->length, IOVP_SIZE) >
+ max_seg_size))
break;
/*
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index f131ba9..c0ad9aa 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -5,6 +5,7 @@ config PCI_DRA7XX
bool "TI DRA7xx PCIe controller"
select PCIE_DW
depends on OF && HAS_IOMEM && TI_PIPE3
+ depends on BROKEN
help
Enables support for the PCIe controller in the DRA7xx SoC. There
are two instances of PCIe controller in DRA7xx. This controller can
diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c
index e5dda38..99da549 100644
--- a/drivers/pci/host/pcie-altera.c
+++ b/drivers/pci/host/pcie-altera.c
@@ -55,8 +55,10 @@
#define TLP_CFG_DW2(bus, devfn, offset) \
(((bus) << 24) | ((devfn) << 16) | (offset))
#define TLP_REQ_ID(bus, devfn) (((bus) << 8) | (devfn))
+#define TLP_COMP_STATUS(s) (((s) >> 12) & 7)
#define TLP_HDR_SIZE 3
#define TLP_LOOP 500
+#define RP_DEVFN 0
#define INTX_NUM 4
@@ -166,34 +168,41 @@ static bool altera_pcie_valid_config(struct altera_pcie *pcie,
static int tlp_read_packet(struct altera_pcie *pcie, u32 *value)
{
- u8 loop;
+ int i;
bool sop = 0;
u32 ctrl;
u32 reg0, reg1;
+ u32 comp_status = 1;
/*
* Minimum 2 loops to read TLP headers and 1 loop to read data
* payload.
*/
- for (loop = 0; loop < TLP_LOOP; loop++) {
+ for (i = 0; i < TLP_LOOP; i++) {
ctrl = cra_readl(pcie, RP_RXCPL_STATUS);
if ((ctrl & RP_RXCPL_SOP) || (ctrl & RP_RXCPL_EOP) || sop) {
reg0 = cra_readl(pcie, RP_RXCPL_REG0);
reg1 = cra_readl(pcie, RP_RXCPL_REG1);
- if (ctrl & RP_RXCPL_SOP)
+ if (ctrl & RP_RXCPL_SOP) {
sop = true;
+ comp_status = TLP_COMP_STATUS(reg1);
+ }
if (ctrl & RP_RXCPL_EOP) {
+ if (comp_status)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
if (value)
*value = reg0;
+
return PCIBIOS_SUCCESSFUL;
}
}
udelay(5);
}
- return -ENOENT;
+ return PCIBIOS_DEVICE_NOT_FOUND;
}
static void tlp_write_packet(struct altera_pcie *pcie, u32 *headers,
@@ -233,7 +242,7 @@ static int tlp_cfg_dword_read(struct altera_pcie *pcie, u8 bus, u32 devfn,
else
headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGRD1);
- headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+ headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
TLP_READ_TAG, byte_en);
headers[2] = TLP_CFG_DW2(bus, devfn, where);
@@ -253,7 +262,7 @@ static int tlp_cfg_dword_write(struct altera_pcie *pcie, u8 bus, u32 devfn,
else
headers[0] = TLP_CFG_DW0(TLP_FMTTYPE_CFGWR1);
- headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, devfn),
+ headers[1] = TLP_CFG_DW1(TLP_REQ_ID(pcie->root_bus_nr, RP_DEVFN),
TLP_WRITE_TAG, byte_en);
headers[2] = TLP_CFG_DW2(bus, devfn, where);
@@ -458,7 +467,7 @@ static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
struct device_node *node = dev->of_node;
/* Setup INTx */
- pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM,
+ pcie->irq_domain = irq_domain_add_linear(node, INTX_NUM + 1,
&intx_domain_ops, pcie);
if (!pcie->irq_domain) {
dev_err(dev, "Failed to get a INTx IRQ domain\n");
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 540f077..02a7452 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -440,7 +440,6 @@ int dw_pcie_host_init(struct pcie_port *pp)
ret, pp->io);
continue;
}
- pp->io_base = pp->io->start;
break;
case IORESOURCE_MEM:
pp->mem = win->res;
diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c
index 35457ec..77f7c66 100644
--- a/drivers/pci/host/pcie-hisi.c
+++ b/drivers/pci/host/pcie-hisi.c
@@ -61,7 +61,9 @@ static int hisi_pcie_cfg_read(struct pcie_port *pp, int where, int size,
*val = *(u8 __force *) walker;
else if (size == 2)
*val = *(u16 __force *) walker;
- else if (size != 4)
+ else if (size == 4)
+ *val = reg_val;
+ else
return PCIBIOS_BAD_REGISTER_NUMBER;
return PCIBIOS_SUCCESSFUL;
@@ -111,7 +113,7 @@ static struct pcie_host_ops hisi_pcie_host_ops = {
.link_up = hisi_pcie_link_up,
};
-static int __init hisi_add_pcie_port(struct pcie_port *pp,
+static int hisi_add_pcie_port(struct pcie_port *pp,
struct platform_device *pdev)
{
int ret;
@@ -139,7 +141,7 @@ static int __init hisi_add_pcie_port(struct pcie_port *pp,
return 0;
}
-static int __init hisi_pcie_probe(struct platform_device *pdev)
+static int hisi_pcie_probe(struct platform_device *pdev)
{
struct hisi_pcie *hisi_pcie;
struct pcie_port *pp;
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 53e4632..7a0df3f 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -54,7 +54,7 @@ static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
struct irq_domain *domain;
domain = pci_msi_get_domain(dev);
- if (domain)
+ if (domain && irq_domain_is_hierarchy(domain))
return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
return arch_setup_msi_irqs(dev, nvec, type);
@@ -65,7 +65,7 @@ static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
struct irq_domain *domain;
domain = pci_msi_get_domain(dev);
- if (domain)
+ if (domain && irq_domain_is_hierarchy(domain))
pci_msi_domain_free_irqs(domain, dev);
else
arch_teardown_msi_irqs(dev);
@@ -257,6 +257,7 @@ void pci_msi_mask_irq(struct irq_data *data)
{
msi_set_mask_bit(data, 1);
}
+EXPORT_SYMBOL_GPL(pci_msi_mask_irq);
/**
* pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts
@@ -266,6 +267,7 @@ void pci_msi_unmask_irq(struct irq_data *data)
{
msi_set_mask_bit(data, 0);
}
+EXPORT_SYMBOL_GPL(pci_msi_unmask_irq);
void default_restore_msi_irqs(struct pci_dev *dev)
{
@@ -1126,6 +1128,7 @@ struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
{
return to_pci_dev(desc->dev);
}
+EXPORT_SYMBOL(msi_desc_to_pci_dev);
void *msi_desc_to_pci_sysdata(struct msi_desc *desc)
{
@@ -1285,6 +1288,7 @@ struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode,
domain->bus_token = DOMAIN_BUS_PCI_MSI;
return domain;
}
+EXPORT_SYMBOL_GPL(pci_msi_create_irq_domain);
/**
* pci_msi_domain_alloc_irqs - Allocate interrupts for @dev in @domain
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index a32ba75..d3f32d6 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -9,7 +9,9 @@
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/irqdomain.h>
#include <linux/pci.h>
+#include <linux/msi.h>
#include <linux/pci_hotplug.h>
#include <linux/module.h>
#include <linux/pci-aspm.h>
@@ -689,6 +691,46 @@ static struct acpi_bus_type acpi_pci_bus = {
.cleanup = pci_acpi_cleanup,
};
+
+static struct fwnode_handle *(*pci_msi_get_fwnode_cb)(struct device *dev);
+
+/**
+ * pci_msi_register_fwnode_provider - Register callback to retrieve fwnode
+ * @fn: Callback matching a device to a fwnode that identifies a PCI
+ * MSI domain.
+ *
+ * This should be called by irqchip driver, which is the parent of
+ * the MSI domain to provide callback interface to query fwnode.
+ */
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *))
+{
+ pci_msi_get_fwnode_cb = fn;
+}
+
+/**
+ * pci_host_bridge_acpi_msi_domain - Retrieve MSI domain of a PCI host bridge
+ * @bus: The PCI host bridge bus.
+ *
+ * This function uses the callback function registered by
+ * pci_msi_register_fwnode_provider() to retrieve the irq_domain with
+ * type DOMAIN_BUS_PCI_MSI of the specified host bridge bus.
+ * This returns NULL on error or when the domain is not found.
+ */
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus)
+{
+ struct fwnode_handle *fwnode;
+
+ if (!pci_msi_get_fwnode_cb)
+ return NULL;
+
+ fwnode = pci_msi_get_fwnode_cb(&bus->dev);
+ if (!fwnode)
+ return NULL;
+
+ return irq_find_matching_fwnode(fwnode, DOMAIN_BUS_PCI_MSI);
+}
+
static int __init acpi_pci_init(void)
{
int ret;
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 4446fcb..d7ffd66 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1146,9 +1146,21 @@ static int pci_pm_runtime_suspend(struct device *dev)
pci_dev->state_saved = false;
pci_dev->no_d3cold = false;
error = pm->runtime_suspend(dev);
- suspend_report_result(pm->runtime_suspend, error);
- if (error)
+ if (error) {
+ /*
+ * -EBUSY and -EAGAIN is used to request the runtime PM core
+ * to schedule a new suspend, so log the event only with debug
+ * log level.
+ */
+ if (error == -EBUSY || error == -EAGAIN)
+ dev_dbg(dev, "can't suspend now (%pf returned %d)\n",
+ pm->runtime_suspend, error);
+ else
+ dev_err(dev, "can't suspend (%pf returned %d)\n",
+ pm->runtime_suspend, error);
+
return error;
+ }
if (!pci_dev->d3cold_allowed)
pci_dev->no_d3cold = true;
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 9261868..eead54c 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -216,7 +216,10 @@ static ssize_t numa_node_store(struct device *dev,
if (ret)
return ret;
- if (node >= MAX_NUMNODES || !node_online(node))
+ if ((node < 0 && node != NUMA_NO_NODE) || node >= MAX_NUMNODES)
+ return -EINVAL;
+
+ if (node != NUMA_NO_NODE && !node_online(node))
return -EINVAL;
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index fd2f03f..d390fc1 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -337,6 +337,4 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe)
}
#endif
-struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
-
#endif /* DRIVERS_PCI_H */
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f53b8e8..553a029 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -6,6 +6,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/of_device.h>
#include <linux/of_pci.h>
#include <linux/pci_hotplug.h>
#include <linux/slab.h>
@@ -13,6 +14,7 @@
#include <linux/cpumask.h>
#include <linux/pci-aspm.h>
#include <linux/aer.h>
+#include <linux/acpi.h>
#include <asm-generic/pci-bridge.h>
#include "pci.h"
@@ -670,6 +672,8 @@ static struct irq_domain *pci_host_bridge_msi_domain(struct pci_bus *bus)
* should be called from here.
*/
d = pci_host_bridge_of_msi_domain(bus);
+ if (!d)
+ d = pci_host_bridge_acpi_msi_domain(bus);
return d;
}
@@ -1672,6 +1676,34 @@ static void pci_set_msi_domain(struct pci_dev *dev)
dev_set_msi_domain(&dev->dev, d);
}
+/**
+ * pci_dma_configure - Setup DMA configuration
+ * @dev: ptr to pci_dev struct of the PCI device
+ *
+ * Function to update PCI devices's DMA configuration using the same
+ * info from the OF node or ACPI node of host bridge's parent (if any).
+ */
+static void pci_dma_configure(struct pci_dev *dev)
+{
+ struct device *bridge = pci_get_host_bridge_device(dev);
+
+ if (IS_ENABLED(CONFIG_OF) &&
+ bridge->parent && bridge->parent->of_node) {
+ of_dma_configure(&dev->dev, bridge->parent->of_node);
+ } else if (has_acpi_companion(bridge)) {
+ struct acpi_device *adev = to_acpi_device_node(bridge->fwnode);
+ enum dev_dma_attr attr = acpi_get_dma_attr(adev);
+
+ if (attr == DEV_DMA_NOT_SUPPORTED)
+ dev_warn(&dev->dev, "DMA not supported.\n");
+ else
+ arch_setup_dma_ops(&dev->dev, 0, 0, NULL,
+ attr == DEV_DMA_COHERENT);
+ }
+
+ pci_put_host_bridge_device(bridge);
+}
+
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
int ret;
@@ -1685,7 +1717,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
- of_pci_dma_configure(dev);
+ pci_dma_configure(dev);
pci_set_dma_max_seg_size(dev, 65536);
pci_set_dma_seg_boundary(dev, 0xffffffff);
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
index be3755c..166637f 100644
--- a/drivers/perf/arm_pmu.c
+++ b/drivers/perf/arm_pmu.c
@@ -551,14 +551,6 @@ static void armpmu_init(struct arm_pmu *armpmu)
};
}
-int armpmu_register(struct arm_pmu *armpmu, int type)
-{
- armpmu_init(armpmu);
- pr_info("enabled with %s PMU driver, %d counters available\n",
- armpmu->name, armpmu->num_events);
- return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
-}
-
/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *__oprofile_cpu_pmu;
@@ -887,6 +879,8 @@ int arm_pmu_device_probe(struct platform_device *pdev,
return -ENOMEM;
}
+ armpmu_init(pmu);
+
if (!__oprofile_cpu_pmu)
__oprofile_cpu_pmu = pmu;
@@ -912,10 +906,13 @@ int arm_pmu_device_probe(struct platform_device *pdev,
if (ret)
goto out_free;
- ret = armpmu_register(pmu, -1);
+ ret = perf_pmu_register(&pmu->pmu, pmu->name, -1);
if (ret)
goto out_destroy;
+ pr_info("enabled with %s PMU driver, %d counters available\n",
+ pmu->name, pmu->num_events);
+
return 0;
out_destroy:
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 7eb5859d..03cb3ea 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -233,6 +233,7 @@ config PHY_SUN9I_USB
tristate "Allwinner sun9i SoC USB PHY driver"
depends on ARCH_SUNXI && HAS_IOMEM && OF
depends on RESET_CONTROLLER
+ depends on USB_COMMON
select GENERIC_PHY
help
Enable this to support the transceiver that is part of Allwinner
diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c
index 7ad72b7..082c03f 100644
--- a/drivers/phy/phy-bcm-cygnus-pcie.c
+++ b/drivers/phy/phy-bcm-cygnus-pcie.c
@@ -128,6 +128,7 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
struct phy_provider *provider;
struct resource *res;
unsigned cnt = 0;
+ int ret;
if (of_get_child_count(node) == 0) {
dev_err(dev, "PHY no child node\n");
@@ -154,24 +155,28 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
if (of_property_read_u32(child, "reg", &id)) {
dev_err(dev, "missing reg property for %s\n",
child->name);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (id >= MAX_NUM_PHYS) {
dev_err(dev, "invalid PHY id: %u\n", id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (core->phys[id].phy) {
dev_err(dev, "duplicated PHY id: %u\n", id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
p = &core->phys[id];
p->phy = devm_phy_create(dev, child, &cygnus_pcie_phy_ops);
if (IS_ERR(p->phy)) {
dev_err(dev, "failed to create PHY\n");
- return PTR_ERR(p->phy);
+ ret = PTR_ERR(p->phy);
+ goto put_child;
}
p->core = core;
@@ -191,6 +196,9 @@ static int cygnus_pcie_phy_probe(struct platform_device *pdev)
dev_dbg(dev, "registered %u PCIe PHY(s)\n", cnt);
return 0;
+put_child:
+ of_node_put(child);
+ return ret;
}
static const struct of_device_id cygnus_pcie_phy_match_table[] = {
diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/phy-berlin-sata.c
index 77a2e05..f84a33a 100644
--- a/drivers/phy/phy-berlin-sata.c
+++ b/drivers/phy/phy-berlin-sata.c
@@ -195,7 +195,7 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
struct phy_provider *phy_provider;
struct phy_berlin_priv *priv;
struct resource *res;
- int i = 0;
+ int ret, i = 0;
u32 phy_id;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -237,22 +237,27 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
if (of_property_read_u32(child, "reg", &phy_id)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (phy_id >= ARRAY_SIZE(phy_berlin_power_down_bits)) {
dev_err(dev, "invalid reg in node %s\n", child->name);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
phy_desc = devm_kzalloc(dev, sizeof(*phy_desc), GFP_KERNEL);
- if (!phy_desc)
- return -ENOMEM;
+ if (!phy_desc) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
phy = devm_phy_create(dev, NULL, &phy_berlin_sata_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY %d\n", phy_id);
- return PTR_ERR(phy);
+ ret = PTR_ERR(phy);
+ goto put_child;
}
phy_desc->phy = phy;
@@ -269,6 +274,9 @@ static int phy_berlin_sata_probe(struct platform_device *pdev)
phy_provider =
devm_of_phy_provider_register(dev, phy_berlin_sata_phy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
+put_child:
+ of_node_put(child);
+ return ret;
}
static const struct of_device_id phy_berlin_sata_of_match[] = {
diff --git a/drivers/phy/phy-brcmstb-sata.c b/drivers/phy/phy-brcmstb-sata.c
index 8a2cb16..cd9dba8 100644
--- a/drivers/phy/phy-brcmstb-sata.c
+++ b/drivers/phy/phy-brcmstb-sata.c
@@ -140,7 +140,7 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
struct brcm_sata_phy *priv;
struct resource *res;
struct phy_provider *provider;
- int count = 0;
+ int ret, count = 0;
if (of_get_child_count(dn) == 0)
return -ENODEV;
@@ -163,16 +163,19 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
if (of_property_read_u32(child, "reg", &id)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (id >= MAX_PORTS) {
dev_err(dev, "invalid reg: %u\n", id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
if (priv->phys[id].phy) {
dev_err(dev, "already registered port %u\n", id);
- return -EINVAL;
+ ret = -EINVAL;
+ goto put_child;
}
port = &priv->phys[id];
@@ -182,7 +185,8 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
port->ssc_en = of_property_read_bool(child, "brcm,enable-ssc");
if (IS_ERR(port->phy)) {
dev_err(dev, "failed to create PHY\n");
- return PTR_ERR(port->phy);
+ ret = PTR_ERR(port->phy);
+ goto put_child;
}
phy_set_drvdata(port->phy, port);
@@ -198,6 +202,9 @@ static int brcm_sata_phy_probe(struct platform_device *pdev)
dev_info(dev, "registered %d port(s)\n", count);
return 0;
+put_child:
+ of_node_put(child);
+ return ret;
}
static struct platform_driver brcm_sata_phy_driver = {
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index fc48fac..8c7f27d 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -636,8 +636,9 @@ EXPORT_SYMBOL_GPL(devm_of_phy_get);
* @np: node containing the phy
* @index: index of the phy
*
- * Gets the phy using _of_phy_get(), and associates a device with it using
- * devres. On driver detach, release function is invoked on the devres data,
+ * Gets the phy using _of_phy_get(), then gets a refcount to it,
+ * and associates a device with it using devres. On driver detach,
+ * release function is invoked on the devres data,
* then, devres data is freed.
*
*/
@@ -651,13 +652,21 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
return ERR_PTR(-ENOMEM);
phy = _of_phy_get(np, index);
- if (!IS_ERR(phy)) {
- *ptr = phy;
- devres_add(dev, ptr);
- } else {
+ if (IS_ERR(phy)) {
devres_free(ptr);
+ return phy;
}
+ if (!try_module_get(phy->ops->owner)) {
+ devres_free(ptr);
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+
+ get_device(&phy->dev);
+
+ *ptr = phy;
+ devres_add(dev, ptr);
+
return phy;
}
EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c
index c47b56b..3acd2a1 100644
--- a/drivers/phy/phy-miphy28lp.c
+++ b/drivers/phy/phy-miphy28lp.c
@@ -1226,15 +1226,18 @@ static int miphy28lp_probe(struct platform_device *pdev)
miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
GFP_KERNEL);
- if (!miphy_phy)
- return -ENOMEM;
+ if (!miphy_phy) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
miphy_dev->phys[port] = miphy_phy;
phy = devm_phy_create(&pdev->dev, child, &miphy28lp_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
- return PTR_ERR(phy);
+ ret = PTR_ERR(phy);
+ goto put_child;
}
miphy_dev->phys[port]->phy = phy;
@@ -1242,11 +1245,11 @@ static int miphy28lp_probe(struct platform_device *pdev)
ret = miphy28lp_of_probe(child, miphy_phy);
if (ret)
- return ret;
+ goto put_child;
ret = miphy28lp_probe_resets(child, miphy_dev->phys[port]);
if (ret)
- return ret;
+ goto put_child;
phy_set_drvdata(phy, miphy_dev->phys[port]);
port++;
@@ -1255,6 +1258,9 @@ static int miphy28lp_probe(struct platform_device *pdev)
provider = devm_of_phy_provider_register(&pdev->dev, miphy28lp_xlate);
return PTR_ERR_OR_ZERO(provider);
+put_child:
+ of_node_put(child);
+ return ret;
}
static const struct of_device_id miphy28lp_of_match[] = {
diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c
index 00a686a..e661f3b 100644
--- a/drivers/phy/phy-miphy365x.c
+++ b/drivers/phy/phy-miphy365x.c
@@ -566,22 +566,25 @@ static int miphy365x_probe(struct platform_device *pdev)
miphy_phy = devm_kzalloc(&pdev->dev, sizeof(*miphy_phy),
GFP_KERNEL);
- if (!miphy_phy)
- return -ENOMEM;
+ if (!miphy_phy) {
+ ret = -ENOMEM;
+ goto put_child;
+ }
miphy_dev->phys[port] = miphy_phy;
phy = devm_phy_create(&pdev->dev, child, &miphy365x_ops);
if (IS_ERR(phy)) {
dev_err(&pdev->dev, "failed to create PHY\n");
- return PTR_ERR(phy);
+ ret = PTR_ERR(phy);
+ goto put_child;
}
miphy_dev->phys[port]->phy = phy;
ret = miphy365x_of_probe(child, miphy_phy);
if (ret)
- return ret;
+ goto put_child;
phy_set_drvdata(phy, miphy_dev->phys[port]);
@@ -591,12 +594,15 @@ static int miphy365x_probe(struct platform_device *pdev)
&miphy_phy->ctrlreg);
if (ret) {
dev_err(&pdev->dev, "No sysconfig offset found\n");
- return ret;
+ goto put_child;
}
}
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
return PTR_ERR_OR_ZERO(provider);
+put_child:
+ of_node_put(child);
+ return ret;
}
static const struct of_device_id miphy365x_of_match[] = {
diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
index f30b28b..e427c3b 100644
--- a/drivers/phy/phy-mt65xx-usb3.c
+++ b/drivers/phy/phy-mt65xx-usb3.c
@@ -415,7 +415,7 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
struct resource *sif_res;
struct mt65xx_u3phy *u3phy;
struct resource res;
- int port;
+ int port, retval;
u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL);
if (!u3phy)
@@ -447,31 +447,34 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
for_each_child_of_node(np, child_np) {
struct mt65xx_phy_instance *instance;
struct phy *phy;
- int retval;
instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL);
- if (!instance)
- return -ENOMEM;
+ if (!instance) {
+ retval = -ENOMEM;
+ goto put_child;
+ }
u3phy->phys[port] = instance;
phy = devm_phy_create(dev, child_np, &mt65xx_u3phy_ops);
if (IS_ERR(phy)) {
dev_err(dev, "failed to create phy\n");
- return PTR_ERR(phy);
+ retval = PTR_ERR(phy);
+ goto put_child;
}
retval = of_address_to_resource(child_np, 0, &res);
if (retval) {
dev_err(dev, "failed to get address resource(id-%d)\n",
port);
- return retval;
+ goto put_child;
}
instance->port_base = devm_ioremap_resource(&phy->dev, &res);
if (IS_ERR(instance->port_base)) {
dev_err(dev, "failed to remap phy regs\n");
- return PTR_ERR(instance->port_base);
+ retval = PTR_ERR(instance->port_base);
+ goto put_child;
}
instance->phy = phy;
@@ -483,6 +486,9 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
return PTR_ERR_OR_ZERO(provider);
+put_child:
+ of_node_put(child_np);
+ return retval;
}
static const struct of_device_id mt65xx_u3phy_id_table[] = {
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
index 91d6f34..62c43c4 100644
--- a/drivers/phy/phy-rockchip-usb.c
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -108,13 +108,16 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
for_each_available_child_of_node(dev->of_node, child) {
rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
- if (!rk_phy)
- return -ENOMEM;
+ if (!rk_phy) {
+ err = -ENOMEM;
+ goto put_child;
+ }
if (of_property_read_u32(child, "reg", &reg_offset)) {
dev_err(dev, "missing reg property in node %s\n",
child->name);
- return -EINVAL;
+ err = -EINVAL;
+ goto put_child;
}
rk_phy->reg_offset = reg_offset;
@@ -127,18 +130,22 @@ static int rockchip_usb_phy_probe(struct platform_device *pdev)
rk_phy->phy = devm_phy_create(dev, child, &ops);
if (IS_ERR(rk_phy->phy)) {
dev_err(dev, "failed to create PHY\n");
- return PTR_ERR(rk_phy->phy);
+ err = PTR_ERR(rk_phy->phy);
+ goto put_child;
}
phy_set_drvdata(rk_phy->phy, rk_phy);
/* only power up usb phy when it use, so disable it when init*/
err = rockchip_usb_phy_power(rk_phy, 1);
if (err)
- return err;
+ goto put_child;
}
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
+put_child:
+ of_node_put(child);
+ return err;
}
static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index b422e4e..99a4c10 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -5,8 +5,6 @@
config PINCTRL
bool
-if PINCTRL
-
menu "Pin controllers"
depends on PINCTRL
@@ -246,7 +244,7 @@ config PINCTRL_ZYNQ
select PINMUX
select GENERIC_PINCONF
help
- This selectes the pinctrl driver for Xilinx Zynq.
+ This selects the pinctrl driver for Xilinx Zynq.
source "drivers/pinctrl/bcm/Kconfig"
source "drivers/pinctrl/berlin/Kconfig"
@@ -254,6 +252,7 @@ source "drivers/pinctrl/freescale/Kconfig"
source "drivers/pinctrl/intel/Kconfig"
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/nomadik/Kconfig"
+source "drivers/pinctrl/pxa/Kconfig"
source "drivers/pinctrl/qcom/Kconfig"
source "drivers/pinctrl/samsung/Kconfig"
source "drivers/pinctrl/sh-pfc/Kconfig"
@@ -274,5 +273,3 @@ config PINCTRL_TB10X
select GPIOLIB
endmenu
-
-endif
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 738cb49..bf1b5ca 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -41,15 +41,16 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
obj-$(CONFIG_ARCH_BCM) += bcm/
-obj-$(CONFIG_ARCH_BERLIN) += berlin/
+obj-$(CONFIG_PINCTRL_BERLIN) += berlin/
obj-y += freescale/
obj-$(CONFIG_X86) += intel/
-obj-$(CONFIG_PLAT_ORION) += mvebu/
+obj-$(CONFIG_PINCTRL_MVEBU) += mvebu/
obj-y += nomadik/
+obj-$(CONFIG_ARCH_PXA) += pxa/
obj-$(CONFIG_ARCH_QCOM) += qcom/
obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/
obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/
-obj-$(CONFIG_PLAT_SPEAR) += spear/
+obj-$(CONFIG_PINCTRL_SPEAR) += spear/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_PINCTRL_UNIPHIER) += uniphier/
obj-$(CONFIG_ARCH_VT8500) += vt8500/
diff --git a/drivers/pinctrl/bcm/Kconfig b/drivers/pinctrl/bcm/Kconfig
index cd11d4d..2cc7438 100644
--- a/drivers/pinctrl/bcm/Kconfig
+++ b/drivers/pinctrl/bcm/Kconfig
@@ -9,6 +9,7 @@ config PINCTRL_BCM281XX
select PINCONF
select GENERIC_PINCONF
select REGMAP_MMIO
+ default ARCH_BCM_MOBILE
help
Say Y here to support Broadcom BCM281xx pinctrl driver, which is used
for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351,
@@ -20,27 +21,41 @@ config PINCTRL_BCM2835
select PINMUX
select PINCONF
-config PINCTRL_CYGNUS_GPIO
- bool "Broadcom Cygnus GPIO (with PINCONF) driver"
- depends on OF_GPIO && ARCH_BCM_CYGNUS
+config PINCTRL_IPROC_GPIO
+ bool "Broadcom iProc GPIO (with PINCONF) driver"
+ depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST)
select GPIOLIB_IRQCHIP
select PINCONF
select GENERIC_PINCONF
- default ARCH_BCM_CYGNUS
+ default ARCH_BCM_IPROC
help
- Say yes here to enable the Broadcom Cygnus GPIO driver.
+ Say yes here to enable the Broadcom iProc GPIO driver.
+
+ The Broadcom iProc based SoCs- Cygnus, NS2, NSP and Stingray, use
+ same GPIO Controller IP hence this driver could be used for all.
The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU
GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and
the always-ON GPIO controller (CRMU/AON). All 3 GPIO controllers are
supported by this driver.
- All 3 Cygnus GPIO controllers support basic PINCONF functions such
+ The Broadcom NSP has two GPIO controllers including the ChipcommonA
+ GPIO, the ChipcommonB GPIO. Later controller is supported by this
+ driver.
+
+ The Broadcom NS2 has two GPIO controller including the CRMU GPIO,
+ the ChipcommonG GPIO. Both controllers are supported by this driver.
+
+ The Broadcom Stingray GPIO controllers are supported by this driver.
+
+ All above SoCs GPIO controllers support basic PINCONF functions such
as bias pull up, pull down, and drive strength configurations, when
these pins are muxed to GPIO.
- Pins from the ASIU GPIO can be individually muxed to GPIO function,
- through interaction with the Cygnus IOMUX controller.
+ It provides the framework where pins from the individual GPIO can be
+ individually muxed to GPIO function, through interaction with the
+ SoCs IOMUX controller. This features could be used only on SoCs which
+ support individual pin muxing.
config PINCTRL_CYGNUS_MUX
bool "Broadcom Cygnus IOMUX driver"
@@ -54,3 +69,20 @@ config PINCTRL_CYGNUS_MUX
The Broadcom Cygnus IOMUX driver supports group based IOMUX
configuration, with the exception that certain individual pins
can be overrided to GPIO function
+
+config PINCTRL_NSP_GPIO
+ bool "Broadcom NSP GPIO (with PINCONF) driver"
+ depends on OF_GPIO && (ARCH_BCM_NSP || COMPILE_TEST)
+ select GPIOLIB_IRQCHIP
+ select PINCONF
+ select GENERIC_PINCONF
+ default ARCH_BCM_NSP
+ help
+ Say yes here to enable the Broadcom NSP GPIO driver.
+
+ The Broadcom Northstar Plus SoC ChipcommonA GPIO controller is
+ supported by this driver.
+
+ The ChipcommonA GPIO controller support basic PINCONF functions such
+ as bias pull up, pull down, and drive strength configurations, when
+ these pins are muxed to GPIO.
diff --git a/drivers/pinctrl/bcm/Makefile b/drivers/pinctrl/bcm/Makefile
index 2b2f70e..6148367d 100644
--- a/drivers/pinctrl/bcm/Makefile
+++ b/drivers/pinctrl/bcm/Makefile
@@ -2,5 +2,6 @@
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
-obj-$(CONFIG_PINCTRL_CYGNUS_GPIO) += pinctrl-cygnus-gpio.o
+obj-$(CONFIG_PINCTRL_IPROC_GPIO) += pinctrl-iproc-gpio.o
obj-$(CONFIG_PINCTRL_CYGNUS_MUX) += pinctrl-cygnus-mux.o
+obj-$(CONFIG_PINCTRL_NSP_GPIO) += pinctrl-nsp-gpio.o
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index a1ea565..75b0d8c 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -342,12 +342,6 @@ static int bcm2835_gpio_get(struct gpio_chip *chip, unsigned offset)
return bcm2835_gpio_get_bit(pc, GPLEV0, offset);
}
-static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- return pinctrl_gpio_direction_output(chip->base + offset);
-}
-
static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
@@ -355,6 +349,13 @@ static void bcm2835_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
bcm2835_gpio_set_bit(pc, value ? GPSET0 : GPCLR0, offset);
}
+static int bcm2835_gpio_direction_output(struct gpio_chip *chip,
+ unsigned offset, int value)
+{
+ bcm2835_gpio_set(chip, offset, value);
+ return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
static int bcm2835_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct bcm2835_pinctrl *pc = dev_get_drvdata(chip->dev);
@@ -794,7 +795,7 @@ static int bcm2835_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
return 0;
out:
- kfree(maps);
+ bcm2835_pctl_dt_free_map(pctldev, maps, num_pins * maps_per_pin);
return err;
}
diff --git a/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 12a48f4..314591a 100644
--- a/drivers/pinctrl/bcm/pinctrl-cygnus-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -10,14 +10,16 @@
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * This file contains the Broadcom Cygnus GPIO driver that supports 3
- * GPIO controllers on Cygnus including the ASIU GPIO controller, the
+ * This file contains the Broadcom Iproc GPIO driver that supports 3
+ * GPIO controllers on Iproc including the ASIU GPIO controller, the
* chipCommonG GPIO controller, and the always-on GPIO controller. Basic
* PINCONF such as bias pull up/down, and drive strength are also supported
* in this driver.
*
- * Pins from the ASIU GPIO can be individually muxed to GPIO function,
- * through the interaction with the Cygnus IOMUX controller
+ * It provides the functionality where pins from the GPIO can be
+ * individually muxed to GPIO function, if individual pad
+ * configuration is supported, through the interaction with respective
+ * SoCs IOMUX controller.
*/
#include <linux/kernel.h>
@@ -34,42 +36,42 @@
#include "../pinctrl-utils.h"
-#define CYGNUS_GPIO_DATA_IN_OFFSET 0x00
-#define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04
-#define CYGNUS_GPIO_OUT_EN_OFFSET 0x08
-#define CYGNUS_GPIO_INT_TYPE_OFFSET 0x0c
-#define CYGNUS_GPIO_INT_DE_OFFSET 0x10
-#define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14
-#define CYGNUS_GPIO_INT_MSK_OFFSET 0x18
-#define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c
-#define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20
-#define CYGNUS_GPIO_INT_CLR_OFFSET 0x24
-#define CYGNUS_GPIO_PAD_RES_OFFSET 0x34
-#define CYGNUS_GPIO_RES_EN_OFFSET 0x38
+#define IPROC_GPIO_DATA_IN_OFFSET 0x00
+#define IPROC_GPIO_DATA_OUT_OFFSET 0x04
+#define IPROC_GPIO_OUT_EN_OFFSET 0x08
+#define IPROC_GPIO_INT_TYPE_OFFSET 0x0c
+#define IPROC_GPIO_INT_DE_OFFSET 0x10
+#define IPROC_GPIO_INT_EDGE_OFFSET 0x14
+#define IPROC_GPIO_INT_MSK_OFFSET 0x18
+#define IPROC_GPIO_INT_STAT_OFFSET 0x1c
+#define IPROC_GPIO_INT_MSTAT_OFFSET 0x20
+#define IPROC_GPIO_INT_CLR_OFFSET 0x24
+#define IPROC_GPIO_PAD_RES_OFFSET 0x34
+#define IPROC_GPIO_RES_EN_OFFSET 0x38
/* drive strength control for ASIU GPIO */
-#define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
+#define IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58
/* drive strength control for CCM/CRMU (AON) GPIO */
-#define CYGNUS_GPIO_DRV0_CTRL_OFFSET 0x00
+#define IPROC_GPIO_DRV0_CTRL_OFFSET 0x00
#define GPIO_BANK_SIZE 0x200
#define NGPIOS_PER_BANK 32
#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
-#define CYGNUS_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
-#define CYGNUS_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
+#define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
+#define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
#define GPIO_DRV_STRENGTH_BIT_SHIFT 20
#define GPIO_DRV_STRENGTH_BITS 3
#define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1)
/*
- * Cygnus GPIO core
+ * Iproc GPIO core
*
* @dev: pointer to device
- * @base: I/O register base for Cygnus GPIO controller
- * @io_ctrl: I/O register base for certain type of Cygnus GPIO controller that
+ * @base: I/O register base for Iproc GPIO controller
+ * @io_ctrl: I/O register base for certain type of Iproc GPIO controller that
* has the PINCONF support implemented outside of the GPIO block
* @lock: lock to protect access to I/O registers
* @gc: GPIO chip
@@ -79,7 +81,7 @@
* @pctl: pointer to pinctrl_dev
* @pctldesc: pinctrl descriptor
*/
-struct cygnus_gpio {
+struct iproc_gpio {
struct device *dev;
void __iomem *base;
@@ -96,33 +98,33 @@ struct cygnus_gpio {
struct pinctrl_desc pctldesc;
};
-static inline struct cygnus_gpio *to_cygnus_gpio(struct gpio_chip *gc)
+static inline struct iproc_gpio *to_iproc_gpio(struct gpio_chip *gc)
{
- return container_of(gc, struct cygnus_gpio, gc);
+ return container_of(gc, struct iproc_gpio, gc);
}
/*
* Mapping from PINCONF pins to GPIO pins is 1-to-1
*/
-static inline unsigned cygnus_pin_to_gpio(unsigned pin)
+static inline unsigned iproc_pin_to_gpio(unsigned pin)
{
return pin;
}
/**
- * cygnus_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
- * Cygnus GPIO register
+ * iproc_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
+ * Iproc GPIO register
*
- * @cygnus_gpio: Cygnus GPIO device
+ * @iproc_gpio: Iproc GPIO device
* @reg: register offset
* @gpio: GPIO pin
* @set: set or clear
*/
-static inline void cygnus_set_bit(struct cygnus_gpio *chip, unsigned int reg,
+static inline void iproc_set_bit(struct iproc_gpio *chip, unsigned int reg,
unsigned gpio, bool set)
{
- unsigned int offset = CYGNUS_GPIO_REG(gpio, reg);
- unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
+ unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
u32 val;
val = readl(chip->base + offset);
@@ -133,19 +135,19 @@ static inline void cygnus_set_bit(struct cygnus_gpio *chip, unsigned int reg,
writel(val, chip->base + offset);
}
-static inline bool cygnus_get_bit(struct cygnus_gpio *chip, unsigned int reg,
+static inline bool iproc_get_bit(struct iproc_gpio *chip, unsigned int reg,
unsigned gpio)
{
- unsigned int offset = CYGNUS_GPIO_REG(gpio, reg);
- unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
+ unsigned int offset = IPROC_GPIO_REG(gpio, reg);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
return !!(readl(chip->base + offset) & BIT(shift));
}
-static void cygnus_gpio_irq_handler(struct irq_desc *desc)
+static void iproc_gpio_irq_handler(struct irq_desc *desc)
{
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
int i, bit;
@@ -154,7 +156,7 @@ static void cygnus_gpio_irq_handler(struct irq_desc *desc)
/* go through the entire GPIO banks and handle all interrupts */
for (i = 0; i < chip->num_banks; i++) {
unsigned long val = readl(chip->base + (i * GPIO_BANK_SIZE) +
- CYGNUS_GPIO_INT_MSTAT_OFFSET);
+ IPROC_GPIO_INT_MSTAT_OFFSET);
for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
unsigned pin = NGPIOS_PER_BANK * i + bit;
@@ -165,7 +167,7 @@ static void cygnus_gpio_irq_handler(struct irq_desc *desc)
* handler, so we do not leave any window
*/
writel(BIT(bit), chip->base + (i * GPIO_BANK_SIZE) +
- CYGNUS_GPIO_INT_CLR_OFFSET);
+ IPROC_GPIO_INT_CLR_OFFSET);
generic_handle_irq(child_irq);
}
@@ -175,60 +177,60 @@ static void cygnus_gpio_irq_handler(struct irq_desc *desc)
}
-static void cygnus_gpio_irq_ack(struct irq_data *d)
+static void iproc_gpio_irq_ack(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned gpio = d->hwirq;
- unsigned int offset = CYGNUS_GPIO_REG(gpio,
- CYGNUS_GPIO_INT_CLR_OFFSET);
- unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
+ unsigned int offset = IPROC_GPIO_REG(gpio,
+ IPROC_GPIO_INT_CLR_OFFSET);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
u32 val = BIT(shift);
writel(val, chip->base + offset);
}
/**
- * cygnus_gpio_irq_set_mask - mask/unmask a GPIO interrupt
+ * iproc_gpio_irq_set_mask - mask/unmask a GPIO interrupt
*
* @d: IRQ chip data
* @unmask: mask/unmask GPIO interrupt
*/
-static void cygnus_gpio_irq_set_mask(struct irq_data *d, bool unmask)
+static void iproc_gpio_irq_set_mask(struct irq_data *d, bool unmask)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned gpio = d->hwirq;
- cygnus_set_bit(chip, CYGNUS_GPIO_INT_MSK_OFFSET, gpio, unmask);
+ iproc_set_bit(chip, IPROC_GPIO_INT_MSK_OFFSET, gpio, unmask);
}
-static void cygnus_gpio_irq_mask(struct irq_data *d)
+static void iproc_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- cygnus_gpio_irq_set_mask(d, false);
+ iproc_gpio_irq_set_mask(d, false);
spin_unlock_irqrestore(&chip->lock, flags);
}
-static void cygnus_gpio_irq_unmask(struct irq_data *d)
+static void iproc_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- cygnus_gpio_irq_set_mask(d, true);
+ iproc_gpio_irq_set_mask(d, true);
spin_unlock_irqrestore(&chip->lock, flags);
}
-static int cygnus_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+static int iproc_gpio_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned gpio = d->hwirq;
bool level_triggered = false;
bool dual_edge = false;
@@ -263,10 +265,10 @@ static int cygnus_gpio_irq_set_type(struct irq_data *d, unsigned int type)
}
spin_lock_irqsave(&chip->lock, flags);
- cygnus_set_bit(chip, CYGNUS_GPIO_INT_TYPE_OFFSET, gpio,
+ iproc_set_bit(chip, IPROC_GPIO_INT_TYPE_OFFSET, gpio,
level_triggered);
- cygnus_set_bit(chip, CYGNUS_GPIO_INT_DE_OFFSET, gpio, dual_edge);
- cygnus_set_bit(chip, CYGNUS_GPIO_INT_EDGE_OFFSET, gpio,
+ iproc_set_bit(chip, IPROC_GPIO_INT_DE_OFFSET, gpio, dual_edge);
+ iproc_set_bit(chip, IPROC_GPIO_INT_EDGE_OFFSET, gpio,
rising_or_high);
spin_unlock_irqrestore(&chip->lock, flags);
@@ -277,32 +279,32 @@ static int cygnus_gpio_irq_set_type(struct irq_data *d, unsigned int type)
return 0;
}
-static struct irq_chip cygnus_gpio_irq_chip = {
- .name = "bcm-cygnus-gpio",
- .irq_ack = cygnus_gpio_irq_ack,
- .irq_mask = cygnus_gpio_irq_mask,
- .irq_unmask = cygnus_gpio_irq_unmask,
- .irq_set_type = cygnus_gpio_irq_set_type,
+static struct irq_chip iproc_gpio_irq_chip = {
+ .name = "bcm-iproc-gpio",
+ .irq_ack = iproc_gpio_irq_ack,
+ .irq_mask = iproc_gpio_irq_mask,
+ .irq_unmask = iproc_gpio_irq_unmask,
+ .irq_set_type = iproc_gpio_irq_set_type,
};
/*
- * Request the Cygnus IOMUX pinmux controller to mux individual pins to GPIO
+ * Request the Iproc IOMUX pinmux controller to mux individual pins to GPIO
*/
-static int cygnus_gpio_request(struct gpio_chip *gc, unsigned offset)
+static int iproc_gpio_request(struct gpio_chip *gc, unsigned offset)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned gpio = gc->base + offset;
- /* not all Cygnus GPIO pins can be muxed individually */
+ /* not all Iproc GPIO pins can be muxed individually */
if (!chip->pinmux_is_supported)
return 0;
return pinctrl_request_gpio(gpio);
}
-static void cygnus_gpio_free(struct gpio_chip *gc, unsigned offset)
+static void iproc_gpio_free(struct gpio_chip *gc, unsigned offset)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned gpio = gc->base + offset;
if (!chip->pinmux_is_supported)
@@ -311,13 +313,13 @@ static void cygnus_gpio_free(struct gpio_chip *gc, unsigned offset)
pinctrl_free_gpio(gpio);
}
-static int cygnus_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
+static int iproc_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, false);
+ iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, false);
spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
@@ -325,15 +327,15 @@ static int cygnus_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
return 0;
}
-static int cygnus_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
+static int iproc_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
int val)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, true);
- cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
+ iproc_set_bit(chip, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
+ iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
@@ -341,29 +343,29 @@ static int cygnus_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
return 0;
}
-static void cygnus_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
+static void iproc_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
+ iproc_set_bit(chip, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
spin_unlock_irqrestore(&chip->lock, flags);
dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
}
-static int cygnus_gpio_get(struct gpio_chip *gc, unsigned gpio)
+static int iproc_gpio_get(struct gpio_chip *gc, unsigned gpio)
{
- struct cygnus_gpio *chip = to_cygnus_gpio(gc);
- unsigned int offset = CYGNUS_GPIO_REG(gpio,
- CYGNUS_GPIO_DATA_IN_OFFSET);
- unsigned int shift = CYGNUS_GPIO_SHIFT(gpio);
+ struct iproc_gpio *chip = to_iproc_gpio(gc);
+ unsigned int offset = IPROC_GPIO_REG(gpio,
+ IPROC_GPIO_DATA_IN_OFFSET);
+ unsigned int shift = IPROC_GPIO_SHIFT(gpio);
return !!(readl(chip->base + offset) & BIT(shift));
}
-static int cygnus_get_groups_count(struct pinctrl_dev *pctldev)
+static int iproc_get_groups_count(struct pinctrl_dev *pctldev)
{
return 1;
}
@@ -372,20 +374,20 @@ static int cygnus_get_groups_count(struct pinctrl_dev *pctldev)
* Only one group: "gpio_grp", since this local pinctrl device only performs
* GPIO specific PINCONF configurations
*/
-static const char *cygnus_get_group_name(struct pinctrl_dev *pctldev,
+static const char *iproc_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return "gpio_grp";
}
-static const struct pinctrl_ops cygnus_pctrl_ops = {
- .get_groups_count = cygnus_get_groups_count,
- .get_group_name = cygnus_get_group_name,
+static const struct pinctrl_ops iproc_pctrl_ops = {
+ .get_groups_count = iproc_get_groups_count,
+ .get_group_name = iproc_get_group_name,
.dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
.dt_free_map = pinctrl_utils_dt_free_map,
};
-static int cygnus_gpio_set_pull(struct cygnus_gpio *chip, unsigned gpio,
+static int iproc_gpio_set_pull(struct iproc_gpio *chip, unsigned gpio,
bool disable, bool pull_up)
{
unsigned long flags;
@@ -393,11 +395,11 @@ static int cygnus_gpio_set_pull(struct cygnus_gpio *chip, unsigned gpio,
spin_lock_irqsave(&chip->lock, flags);
if (disable) {
- cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, false);
+ iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
} else {
- cygnus_set_bit(chip, CYGNUS_GPIO_PAD_RES_OFFSET, gpio,
+ iproc_set_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio,
pull_up);
- cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, true);
+ iproc_set_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
}
spin_unlock_irqrestore(&chip->lock, flags);
@@ -407,18 +409,18 @@ static int cygnus_gpio_set_pull(struct cygnus_gpio *chip, unsigned gpio,
return 0;
}
-static void cygnus_gpio_get_pull(struct cygnus_gpio *chip, unsigned gpio,
+static void iproc_gpio_get_pull(struct iproc_gpio *chip, unsigned gpio,
bool *disable, bool *pull_up)
{
unsigned long flags;
spin_lock_irqsave(&chip->lock, flags);
- *disable = !cygnus_get_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio);
- *pull_up = cygnus_get_bit(chip, CYGNUS_GPIO_PAD_RES_OFFSET, gpio);
+ *disable = !iproc_get_bit(chip, IPROC_GPIO_RES_EN_OFFSET, gpio);
+ *pull_up = iproc_get_bit(chip, IPROC_GPIO_PAD_RES_OFFSET, gpio);
spin_unlock_irqrestore(&chip->lock, flags);
}
-static int cygnus_gpio_set_strength(struct cygnus_gpio *chip, unsigned gpio,
+static int iproc_gpio_set_strength(struct iproc_gpio *chip, unsigned gpio,
unsigned strength)
{
void __iomem *base;
@@ -432,14 +434,14 @@ static int cygnus_gpio_set_strength(struct cygnus_gpio *chip, unsigned gpio,
if (chip->io_ctrl) {
base = chip->io_ctrl;
- offset = CYGNUS_GPIO_DRV0_CTRL_OFFSET;
+ offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
} else {
base = chip->base;
- offset = CYGNUS_GPIO_REG(gpio,
- CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET);
+ offset = IPROC_GPIO_REG(gpio,
+ IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
}
- shift = CYGNUS_GPIO_SHIFT(gpio);
+ shift = IPROC_GPIO_SHIFT(gpio);
dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
strength);
@@ -458,7 +460,7 @@ static int cygnus_gpio_set_strength(struct cygnus_gpio *chip, unsigned gpio,
return 0;
}
-static int cygnus_gpio_get_strength(struct cygnus_gpio *chip, unsigned gpio,
+static int iproc_gpio_get_strength(struct iproc_gpio *chip, unsigned gpio,
u16 *strength)
{
void __iomem *base;
@@ -468,14 +470,14 @@ static int cygnus_gpio_get_strength(struct cygnus_gpio *chip, unsigned gpio,
if (chip->io_ctrl) {
base = chip->io_ctrl;
- offset = CYGNUS_GPIO_DRV0_CTRL_OFFSET;
+ offset = IPROC_GPIO_DRV0_CTRL_OFFSET;
} else {
base = chip->base;
- offset = CYGNUS_GPIO_REG(gpio,
- CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET);
+ offset = IPROC_GPIO_REG(gpio,
+ IPROC_GPIO_ASIU_DRV0_CTRL_OFFSET);
}
- shift = CYGNUS_GPIO_SHIFT(gpio);
+ shift = IPROC_GPIO_SHIFT(gpio);
spin_lock_irqsave(&chip->lock, flags);
*strength = 0;
@@ -493,44 +495,43 @@ static int cygnus_gpio_get_strength(struct cygnus_gpio *chip, unsigned gpio,
return 0;
}
-static int cygnus_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+static int iproc_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *config)
{
- struct cygnus_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+ struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param = pinconf_to_config_param(*config);
- unsigned gpio = cygnus_pin_to_gpio(pin);
+ unsigned gpio = iproc_pin_to_gpio(pin);
u16 arg;
bool disable, pull_up;
int ret;
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
+ iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (disable)
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_UP:
- cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
+ iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (!disable && pull_up)
return 0;
else
return -EINVAL;
case PIN_CONFIG_BIAS_PULL_DOWN:
- cygnus_gpio_get_pull(chip, gpio, &disable, &pull_up);
+ iproc_gpio_get_pull(chip, gpio, &disable, &pull_up);
if (!disable && !pull_up)
return 0;
else
return -EINVAL;
case PIN_CONFIG_DRIVE_STRENGTH:
- ret = cygnus_gpio_get_strength(chip, gpio, &arg);
+ ret = iproc_gpio_get_strength(chip, gpio, &arg);
if (ret)
return ret;
- else
- *config = pinconf_to_config_packed(param, arg);
+ *config = pinconf_to_config_packed(param, arg);
return 0;
@@ -541,13 +542,13 @@ static int cygnus_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
return -ENOTSUPP;
}
-static int cygnus_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+static int iproc_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long *configs, unsigned num_configs)
{
- struct cygnus_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+ struct iproc_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
enum pin_config_param param;
u16 arg;
- unsigned i, gpio = cygnus_pin_to_gpio(pin);
+ unsigned i, gpio = iproc_pin_to_gpio(pin);
int ret = -ENOTSUPP;
for (i = 0; i < num_configs; i++) {
@@ -556,25 +557,25 @@ static int cygnus_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
switch (param) {
case PIN_CONFIG_BIAS_DISABLE:
- ret = cygnus_gpio_set_pull(chip, gpio, true, false);
+ ret = iproc_gpio_set_pull(chip, gpio, true, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_UP:
- ret = cygnus_gpio_set_pull(chip, gpio, false, true);
+ ret = iproc_gpio_set_pull(chip, gpio, false, true);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
- ret = cygnus_gpio_set_pull(chip, gpio, false, false);
+ ret = iproc_gpio_set_pull(chip, gpio, false, false);
if (ret < 0)
goto out;
break;
case PIN_CONFIG_DRIVE_STRENGTH:
- ret = cygnus_gpio_set_strength(chip, gpio, arg);
+ ret = iproc_gpio_set_strength(chip, gpio, arg);
if (ret < 0)
goto out;
break;
@@ -589,20 +590,20 @@ out:
return ret;
}
-static const struct pinconf_ops cygnus_pconf_ops = {
+static const struct pinconf_ops iproc_pconf_ops = {
.is_generic = true,
- .pin_config_get = cygnus_pin_config_get,
- .pin_config_set = cygnus_pin_config_set,
+ .pin_config_get = iproc_pin_config_get,
+ .pin_config_set = iproc_pin_config_set,
};
/*
- * Cygnus GPIO controller supports some PINCONF related configurations such as
+ * Iproc GPIO controller supports some PINCONF related configurations such as
* pull up, pull down, and drive strength, when the pin is configured to GPIO
*
* Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
* local GPIO pins
*/
-static int cygnus_gpio_register_pinconf(struct cygnus_gpio *chip)
+static int iproc_gpio_register_pinconf(struct iproc_gpio *chip)
{
struct pinctrl_desc *pctldesc = &chip->pctldesc;
struct pinctrl_pin_desc *pins;
@@ -622,10 +623,10 @@ static int cygnus_gpio_register_pinconf(struct cygnus_gpio *chip)
}
pctldesc->name = dev_name(chip->dev);
- pctldesc->pctlops = &cygnus_pctrl_ops;
+ pctldesc->pctlops = &iproc_pctrl_ops;
pctldesc->pins = pins;
pctldesc->npins = gc->ngpio;
- pctldesc->confops = &cygnus_pconf_ops;
+ pctldesc->confops = &iproc_pconf_ops;
chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
if (IS_ERR(chip->pctl)) {
@@ -636,59 +637,27 @@ static int cygnus_gpio_register_pinconf(struct cygnus_gpio *chip)
return 0;
}
-static void cygnus_gpio_unregister_pinconf(struct cygnus_gpio *chip)
+static void iproc_gpio_unregister_pinconf(struct iproc_gpio *chip)
{
- if (chip->pctl)
- pinctrl_unregister(chip->pctl);
+ pinctrl_unregister(chip->pctl);
}
-struct cygnus_gpio_data {
- unsigned num_gpios;
-};
-
-static const struct cygnus_gpio_data cygnus_cmm_gpio_data = {
- .num_gpios = 24,
-};
-
-static const struct cygnus_gpio_data cygnus_asiu_gpio_data = {
- .num_gpios = 146,
+static const struct of_device_id iproc_gpio_of_match[] = {
+ { .compatible = "brcm,cygnus-ccm-gpio" },
+ { .compatible = "brcm,cygnus-asiu-gpio" },
+ { .compatible = "brcm,cygnus-crmu-gpio" },
+ { .compatible = "brcm,iproc-gpio" },
+ { }
};
-static const struct cygnus_gpio_data cygnus_crmu_gpio_data = {
- .num_gpios = 6,
-};
-
-static const struct of_device_id cygnus_gpio_of_match[] = {
- {
- .compatible = "brcm,cygnus-ccm-gpio",
- .data = &cygnus_cmm_gpio_data,
- },
- {
- .compatible = "brcm,cygnus-asiu-gpio",
- .data = &cygnus_asiu_gpio_data,
- },
- {
- .compatible = "brcm,cygnus-crmu-gpio",
- .data = &cygnus_crmu_gpio_data,
- }
-};
-
-static int cygnus_gpio_probe(struct platform_device *pdev)
+static int iproc_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
- struct cygnus_gpio *chip;
+ struct iproc_gpio *chip;
struct gpio_chip *gc;
u32 ngpios;
int irq, ret;
- const struct of_device_id *match;
- const struct cygnus_gpio_data *gpio_data;
-
- match = of_match_device(cygnus_gpio_of_match, dev);
- if (!match)
- return -ENODEV;
- gpio_data = match->data;
- ngpios = gpio_data->num_gpios;
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
@@ -713,6 +682,11 @@ static int cygnus_gpio_probe(struct platform_device *pdev)
}
}
+ if (of_property_read_u32(dev->of_node, "ngpios", &ngpios)) {
+ dev_err(&pdev->dev, "missing ngpios DT property\n");
+ return -ENODEV;
+ }
+
spin_lock_init(&chip->lock);
gc = &chip->gc;
@@ -722,12 +696,12 @@ static int cygnus_gpio_probe(struct platform_device *pdev)
gc->label = dev_name(dev);
gc->dev = dev;
gc->of_node = dev->of_node;
- gc->request = cygnus_gpio_request;
- gc->free = cygnus_gpio_free;
- gc->direction_input = cygnus_gpio_direction_input;
- gc->direction_output = cygnus_gpio_direction_output;
- gc->set = cygnus_gpio_set;
- gc->get = cygnus_gpio_get;
+ gc->request = iproc_gpio_request;
+ gc->free = iproc_gpio_free;
+ gc->direction_input = iproc_gpio_direction_input;
+ gc->direction_output = iproc_gpio_direction_output;
+ gc->set = iproc_gpio_set;
+ gc->get = iproc_gpio_get;
chip->pinmux_is_supported = of_property_read_bool(dev->of_node,
"gpio-ranges");
@@ -738,7 +712,7 @@ static int cygnus_gpio_probe(struct platform_device *pdev)
return ret;
}
- ret = cygnus_gpio_register_pinconf(chip);
+ ret = iproc_gpio_register_pinconf(chip);
if (ret) {
dev_err(dev, "unable to register pinconf\n");
goto err_rm_gpiochip;
@@ -747,21 +721,21 @@ static int cygnus_gpio_probe(struct platform_device *pdev)
/* optional GPIO interrupt support */
irq = platform_get_irq(pdev, 0);
if (irq) {
- ret = gpiochip_irqchip_add(gc, &cygnus_gpio_irq_chip, 0,
+ ret = gpiochip_irqchip_add(gc, &iproc_gpio_irq_chip, 0,
handle_simple_irq, IRQ_TYPE_NONE);
if (ret) {
dev_err(dev, "no GPIO irqchip\n");
goto err_unregister_pinconf;
}
- gpiochip_set_chained_irqchip(gc, &cygnus_gpio_irq_chip, irq,
- cygnus_gpio_irq_handler);
+ gpiochip_set_chained_irqchip(gc, &iproc_gpio_irq_chip, irq,
+ iproc_gpio_irq_handler);
}
return 0;
err_unregister_pinconf:
- cygnus_gpio_unregister_pinconf(chip);
+ iproc_gpio_unregister_pinconf(chip);
err_rm_gpiochip:
gpiochip_remove(gc);
@@ -769,16 +743,16 @@ err_rm_gpiochip:
return ret;
}
-static struct platform_driver cygnus_gpio_driver = {
+static struct platform_driver iproc_gpio_driver = {
.driver = {
- .name = "cygnus-gpio",
- .of_match_table = cygnus_gpio_of_match,
+ .name = "iproc-gpio",
+ .of_match_table = iproc_gpio_of_match,
},
- .probe = cygnus_gpio_probe,
+ .probe = iproc_gpio_probe,
};
-static int __init cygnus_gpio_init(void)
+static int __init iproc_gpio_init(void)
{
- return platform_driver_probe(&cygnus_gpio_driver, cygnus_gpio_probe);
+ return platform_driver_probe(&iproc_gpio_driver, iproc_gpio_probe);
}
-arch_initcall_sync(cygnus_gpio_init);
+arch_initcall_sync(iproc_gpio_init);
diff --git a/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
new file mode 100644
index 0000000..725c36f
--- /dev/null
+++ b/drivers/pinctrl/bcm/pinctrl-nsp-gpio.c
@@ -0,0 +1,749 @@
+/*
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * This file contains the Broadcom Northstar Plus (NSP) GPIO driver that
+ * supports the chipCommonA GPIO controller. Basic PINCONF such as bias,
+ * pull up/down, slew and drive strength are also supported in this driver.
+ *
+ * Pins from the chipCommonA GPIO can be individually muxed to GPIO function,
+ * through the interaction with the NSP IOMUX controller.
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/slab.h>
+
+#include "../pinctrl-utils.h"
+
+#define NSP_CHIP_A_INT_STATUS 0x00
+#define NSP_CHIP_A_INT_MASK 0x04
+#define NSP_GPIO_DATA_IN 0x40
+#define NSP_GPIO_DATA_OUT 0x44
+#define NSP_GPIO_OUT_EN 0x48
+#define NSP_GPIO_INT_POLARITY 0x50
+#define NSP_GPIO_INT_MASK 0x54
+#define NSP_GPIO_EVENT 0x58
+#define NSP_GPIO_EVENT_INT_MASK 0x5c
+#define NSP_GPIO_EVENT_INT_POLARITY 0x64
+#define NSP_CHIP_A_GPIO_INT_BIT 0x01
+
+/* I/O parameters offset for chipcommon A GPIO */
+#define NSP_GPIO_DRV_CTRL 0x00
+#define NSP_GPIO_HYSTERESIS_EN 0x10
+#define NSP_GPIO_SLEW_RATE_EN 0x14
+#define NSP_PULL_UP_EN 0x18
+#define NSP_PULL_DOWN_EN 0x1c
+#define GPIO_DRV_STRENGTH_BITS 0x03
+
+/*
+ * nsp GPIO core
+ *
+ * @dev: pointer to device
+ * @base: I/O register base for nsp GPIO controller
+ * @io_ctrl: I/O register base for PINCONF support outside the GPIO block
+ * @gc: GPIO chip
+ * @pctl: pointer to pinctrl_dev
+ * @pctldesc: pinctrl descriptor
+ * @irq_domain: pointer to irq domain
+ * @lock: lock to protect access to I/O registers
+ */
+struct nsp_gpio {
+ struct device *dev;
+ void __iomem *base;
+ void __iomem *io_ctrl;
+ struct gpio_chip gc;
+ struct pinctrl_dev *pctl;
+ struct pinctrl_desc pctldesc;
+ struct irq_domain *irq_domain;
+ spinlock_t lock;
+};
+
+enum base_type {
+ REG,
+ IO_CTRL
+};
+
+static inline struct nsp_gpio *to_nsp_gpio(struct gpio_chip *gc)
+{
+ return container_of(gc, struct nsp_gpio, gc);
+}
+
+/*
+ * Mapping from PINCONF pins to GPIO pins is 1-to-1
+ */
+static inline unsigned nsp_pin_to_gpio(unsigned pin)
+{
+ return pin;
+}
+
+/*
+ * nsp_set_bit - set or clear one bit (corresponding to the GPIO pin) in a
+ * nsp GPIO register
+ *
+ * @nsp_gpio: nsp GPIO device
+ * @base_type: reg base to modify
+ * @reg: register offset
+ * @gpio: GPIO pin
+ * @set: set or clear
+ */
+static inline void nsp_set_bit(struct nsp_gpio *chip, enum base_type address,
+ unsigned int reg, unsigned gpio, bool set)
+{
+ u32 val;
+ void __iomem *base_address;
+
+ if (address == IO_CTRL)
+ base_address = chip->io_ctrl;
+ else
+ base_address = chip->base;
+
+ val = readl(base_address + reg);
+ if (set)
+ val |= BIT(gpio);
+ else
+ val &= ~BIT(gpio);
+
+ writel(val, base_address + reg);
+}
+
+/*
+ * nsp_get_bit - get one bit (corresponding to the GPIO pin) in a
+ * nsp GPIO register
+ */
+static inline bool nsp_get_bit(struct nsp_gpio *chip, enum base_type address,
+ unsigned int reg, unsigned gpio)
+{
+ if (address == IO_CTRL)
+ return !!(readl(chip->io_ctrl + reg) & BIT(gpio));
+ else
+ return !!(readl(chip->base + reg) & BIT(gpio));
+}
+
+static irqreturn_t nsp_gpio_irq_handler(int irq, void *data)
+{
+ struct nsp_gpio *chip = (struct nsp_gpio *)data;
+ struct gpio_chip gc = chip->gc;
+ int bit;
+ unsigned long int_bits = 0;
+ u32 int_status;
+
+ /* go through the entire GPIOs and handle all interrupts */
+ int_status = readl(chip->base + NSP_CHIP_A_INT_STATUS);
+ if (int_status & NSP_CHIP_A_GPIO_INT_BIT) {
+ unsigned int event, level;
+
+ /* Get level and edge interrupts */
+ event = readl(chip->base + NSP_GPIO_EVENT_INT_MASK) &
+ readl(chip->base + NSP_GPIO_EVENT);
+ level = readl(chip->base + NSP_GPIO_DATA_IN) ^
+ readl(chip->base + NSP_GPIO_INT_POLARITY);
+ level &= readl(chip->base + NSP_GPIO_INT_MASK);
+ int_bits = level | event;
+
+ for_each_set_bit(bit, &int_bits, gc.ngpio) {
+ /*
+ * Clear the interrupt before invoking the
+ * handler, so we do not leave any window
+ */
+ writel(BIT(bit), chip->base + NSP_GPIO_EVENT);
+ generic_handle_irq(
+ irq_linear_revmap(chip->irq_domain, bit));
+ }
+ }
+
+ return int_bits ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void nsp_gpio_irq_ack(struct irq_data *d)
+{
+ struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+ unsigned gpio = d->hwirq;
+ u32 val = BIT(gpio);
+ u32 trigger_type;
+
+ trigger_type = irq_get_trigger_type(d->irq);
+ if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+ nsp_set_bit(chip, REG, NSP_GPIO_EVENT, gpio, val);
+}
+
+/*
+ * nsp_gpio_irq_set_mask - mask/unmask a GPIO interrupt
+ *
+ * @d: IRQ chip data
+ * @unmask: mask/unmask GPIO interrupt
+ */
+static void nsp_gpio_irq_set_mask(struct irq_data *d, bool unmask)
+{
+ struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+ unsigned gpio = d->hwirq;
+ u32 trigger_type;
+
+ trigger_type = irq_get_trigger_type(d->irq);
+ if (trigger_type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
+ nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_MASK, gpio, unmask);
+ else
+ nsp_set_bit(chip, REG, NSP_GPIO_INT_MASK, gpio, unmask);
+}
+
+static void nsp_gpio_irq_mask(struct irq_data *d)
+{
+ struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_gpio_irq_set_mask(d, false);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static void nsp_gpio_irq_unmask(struct irq_data *d)
+{
+ struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_gpio_irq_set_mask(d, true);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int nsp_gpio_irq_set_type(struct irq_data *d, unsigned int type)
+{
+ struct nsp_gpio *chip = irq_data_get_irq_chip_data(d);
+ unsigned gpio = d->hwirq;
+ bool level_low;
+ bool falling;
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ falling = nsp_get_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio);
+ level_low = nsp_get_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio);
+
+ switch (type & IRQ_TYPE_SENSE_MASK) {
+ case IRQ_TYPE_EDGE_RISING:
+ falling = false;
+ break;
+
+ case IRQ_TYPE_EDGE_FALLING:
+ falling = true;
+ break;
+
+ case IRQ_TYPE_LEVEL_HIGH:
+ level_low = false;
+ break;
+
+ case IRQ_TYPE_LEVEL_LOW:
+ level_low = true;
+ break;
+
+ default:
+ dev_err(chip->dev, "invalid GPIO IRQ type 0x%x\n",
+ type);
+ spin_unlock_irqrestore(&chip->lock, flags);
+ return -EINVAL;
+ }
+
+ nsp_set_bit(chip, REG, NSP_GPIO_EVENT_INT_POLARITY, gpio, falling);
+ nsp_set_bit(chip, REG, NSP_GPIO_INT_POLARITY, gpio, level_low);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ dev_dbg(chip->dev, "gpio:%u level_low:%s falling:%s\n", gpio,
+ level_low ? "true" : "false", falling ? "true" : "false");
+ return 0;
+}
+
+static struct irq_chip nsp_gpio_irq_chip = {
+ .name = "gpio-a",
+ .irq_enable = nsp_gpio_irq_unmask,
+ .irq_disable = nsp_gpio_irq_mask,
+ .irq_ack = nsp_gpio_irq_ack,
+ .irq_mask = nsp_gpio_irq_mask,
+ .irq_unmask = nsp_gpio_irq_unmask,
+ .irq_set_type = nsp_gpio_irq_set_type,
+};
+
+/*
+ * Request the nsp IOMUX pinmux controller to mux individual pins to GPIO
+ */
+static int nsp_gpio_request(struct gpio_chip *gc, unsigned offset)
+{
+ unsigned gpio = gc->base + offset;
+
+ return pinctrl_request_gpio(gpio);
+}
+
+static void nsp_gpio_free(struct gpio_chip *gc, unsigned offset)
+{
+ unsigned gpio = gc->base + offset;
+
+ pinctrl_free_gpio(gpio);
+}
+
+static int nsp_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
+{
+ struct nsp_gpio *chip = to_nsp_gpio(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, false);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ dev_dbg(chip->dev, "gpio:%u set input\n", gpio);
+ return 0;
+}
+
+static int nsp_gpio_direction_output(struct gpio_chip *gc, unsigned gpio,
+ int val)
+{
+ struct nsp_gpio *chip = to_nsp_gpio(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_set_bit(chip, REG, NSP_GPIO_OUT_EN, gpio, true);
+ nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ dev_dbg(chip->dev, "gpio:%u set output, value:%d\n", gpio, val);
+ return 0;
+}
+
+static void nsp_gpio_set(struct gpio_chip *gc, unsigned gpio, int val)
+{
+ struct nsp_gpio *chip = to_nsp_gpio(gc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_set_bit(chip, REG, NSP_GPIO_DATA_OUT, gpio, !!(val));
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ dev_dbg(chip->dev, "gpio:%u set, value:%d\n", gpio, val);
+}
+
+static int nsp_gpio_get(struct gpio_chip *gc, unsigned gpio)
+{
+ struct nsp_gpio *chip = to_nsp_gpio(gc);
+
+ return !!(readl(chip->base + NSP_GPIO_DATA_IN) & BIT(gpio));
+}
+
+static int nsp_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
+{
+ struct nsp_gpio *chip = to_nsp_gpio(gc);
+
+ return irq_linear_revmap(chip->irq_domain, offset);
+}
+
+static int nsp_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ return 1;
+}
+
+/*
+ * Only one group: "gpio_grp", since this local pinctrl device only performs
+ * GPIO specific PINCONF configurations
+ */
+static const char *nsp_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ return "gpio_grp";
+}
+
+static const struct pinctrl_ops nsp_pctrl_ops = {
+ .get_groups_count = nsp_get_groups_count,
+ .get_group_name = nsp_get_group_name,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int nsp_gpio_set_slew(struct nsp_gpio *chip, unsigned gpio, u16 slew)
+{
+ if (slew)
+ nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, true);
+ else
+ nsp_set_bit(chip, IO_CTRL, NSP_GPIO_SLEW_RATE_EN, gpio, false);
+
+ return 0;
+}
+
+static int nsp_gpio_set_pull(struct nsp_gpio *chip, unsigned gpio,
+ bool pull_up, bool pull_down)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ nsp_set_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio, pull_down);
+ nsp_set_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio, pull_up);
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ dev_dbg(chip->dev, "gpio:%u set pullup:%d pulldown: %d\n",
+ gpio, pull_up, pull_down);
+ return 0;
+}
+
+static void nsp_gpio_get_pull(struct nsp_gpio *chip, unsigned gpio,
+ bool *pull_up, bool *pull_down)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ *pull_up = nsp_get_bit(chip, IO_CTRL, NSP_PULL_UP_EN, gpio);
+ *pull_down = nsp_get_bit(chip, IO_CTRL, NSP_PULL_DOWN_EN, gpio);
+ spin_unlock_irqrestore(&chip->lock, flags);
+}
+
+static int nsp_gpio_set_strength(struct nsp_gpio *chip, unsigned gpio,
+ u16 strength)
+{
+ u32 offset, shift, i;
+ u32 val;
+ unsigned long flags;
+
+ /* make sure drive strength is supported */
+ if (strength < 2 || strength > 16 || (strength % 2))
+ return -ENOTSUPP;
+
+ shift = gpio;
+ offset = NSP_GPIO_DRV_CTRL;
+ dev_dbg(chip->dev, "gpio:%u set drive strength:%d mA\n", gpio,
+ strength);
+ spin_lock_irqsave(&chip->lock, flags);
+ strength = (strength / 2) - 1;
+ for (i = GPIO_DRV_STRENGTH_BITS; i > 0; i--) {
+ val = readl(chip->io_ctrl + offset);
+ val &= ~BIT(shift);
+ val |= ((strength >> (i-1)) & 0x1) << shift;
+ writel(val, chip->io_ctrl + offset);
+ offset += 4;
+ }
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+static int nsp_gpio_get_strength(struct nsp_gpio *chip, unsigned gpio,
+ u16 *strength)
+{
+ unsigned int offset, shift;
+ u32 val;
+ unsigned long flags;
+ int i;
+
+ offset = NSP_GPIO_DRV_CTRL;
+ shift = gpio;
+
+ spin_lock_irqsave(&chip->lock, flags);
+ *strength = 0;
+ for (i = (GPIO_DRV_STRENGTH_BITS - 1); i >= 0; i--) {
+ val = readl(chip->io_ctrl + offset) & BIT(shift);
+ val >>= shift;
+ *strength += (val << i);
+ offset += 4;
+ }
+
+ /* convert to mA */
+ *strength = (*strength + 1) * 2;
+ spin_unlock_irqrestore(&chip->lock, flags);
+
+ return 0;
+}
+
+int nsp_pin_config_group_get(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned long *config)
+{
+ return 0;
+}
+
+int nsp_pin_config_group_set(struct pinctrl_dev *pctldev, unsigned selector,
+ unsigned long *configs, unsigned num_configs)
+{
+ return 0;
+}
+
+static int nsp_pin_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ unsigned int gpio;
+ u16 arg = 0;
+ bool pull_up, pull_down;
+ int ret;
+
+ gpio = nsp_pin_to_gpio(pin);
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+ if ((pull_up == false) && (pull_down == false))
+ return 0;
+ else
+ return -EINVAL;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+ if (pull_up)
+ return 0;
+ else
+ return -EINVAL;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ nsp_gpio_get_pull(chip, gpio, &pull_up, &pull_down);
+ if (pull_down)
+ return 0;
+ else
+ return -EINVAL;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = nsp_gpio_get_strength(chip, gpio, &arg);
+ if (ret)
+ return ret;
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+
+ default:
+ return -ENOTSUPP;
+ }
+}
+
+static int nsp_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct nsp_gpio *chip = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param;
+ u16 arg;
+ unsigned int i, gpio;
+ int ret = -ENOTSUPP;
+
+ gpio = nsp_pin_to_gpio(pin);
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ ret = nsp_gpio_set_pull(chip, gpio, false, false);
+ if (ret < 0)
+ goto out;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ ret = nsp_gpio_set_pull(chip, gpio, true, false);
+ if (ret < 0)
+ goto out;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ ret = nsp_gpio_set_pull(chip, gpio, false, true);
+ if (ret < 0)
+ goto out;
+ break;
+
+ case PIN_CONFIG_DRIVE_STRENGTH:
+ ret = nsp_gpio_set_strength(chip, gpio, arg);
+ if (ret < 0)
+ goto out;
+ break;
+
+ case PIN_CONFIG_SLEW_RATE:
+ ret = nsp_gpio_set_slew(chip, gpio, arg);
+ if (ret < 0)
+ goto out;
+ break;
+
+ default:
+ dev_err(chip->dev, "invalid configuration\n");
+ return -ENOTSUPP;
+ }
+ }
+
+out:
+ return ret;
+}
+
+static const struct pinconf_ops nsp_pconf_ops = {
+ .is_generic = true,
+ .pin_config_get = nsp_pin_config_get,
+ .pin_config_set = nsp_pin_config_set,
+ .pin_config_group_get = nsp_pin_config_group_get,
+ .pin_config_group_set = nsp_pin_config_group_set,
+};
+
+/*
+ * NSP GPIO controller supports some PINCONF related configurations such as
+ * pull up, pull down, slew and drive strength, when the pin is configured
+ * to GPIO.
+ *
+ * Here a local pinctrl device is created with simple 1-to-1 pin mapping to the
+ * local GPIO pins
+ */
+static int nsp_gpio_register_pinconf(struct nsp_gpio *chip)
+{
+ struct pinctrl_desc *pctldesc = &chip->pctldesc;
+ struct pinctrl_pin_desc *pins;
+ struct gpio_chip *gc = &chip->gc;
+ int i;
+
+ pins = devm_kcalloc(chip->dev, gc->ngpio, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+ for (i = 0; i < gc->ngpio; i++) {
+ pins[i].number = i;
+ pins[i].name = devm_kasprintf(chip->dev, GFP_KERNEL,
+ "gpio-%d", i);
+ if (!pins[i].name)
+ return -ENOMEM;
+ }
+ pctldesc->name = dev_name(chip->dev);
+ pctldesc->pctlops = &nsp_pctrl_ops;
+ pctldesc->pins = pins;
+ pctldesc->npins = gc->ngpio;
+ pctldesc->confops = &nsp_pconf_ops;
+
+ chip->pctl = pinctrl_register(pctldesc, chip->dev, chip);
+ if (IS_ERR(chip->pctl)) {
+ dev_err(chip->dev, "unable to register pinctrl device\n");
+ return PTR_ERR(chip->pctl);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id nsp_gpio_of_match[] = {
+ {.compatible = "brcm,nsp-gpio-a",},
+ {}
+};
+
+static int nsp_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nsp_gpio *chip;
+ struct gpio_chip *gc;
+ u32 val, count;
+ int irq, ret;
+
+ if (of_property_read_u32(pdev->dev.of_node, "ngpios", &val)) {
+ dev_err(&pdev->dev, "Missing ngpios OF property\n");
+ return -ENODEV;
+ }
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->dev = dev;
+ platform_set_drvdata(pdev, chip);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ chip->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(chip->base)) {
+ dev_err(dev, "unable to map I/O memory\n");
+ return PTR_ERR(chip->base);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ chip->io_ctrl = devm_ioremap_resource(dev, res);
+ if (IS_ERR(chip->io_ctrl)) {
+ dev_err(dev, "unable to map I/O memory\n");
+ return PTR_ERR(chip->io_ctrl);
+ }
+
+ spin_lock_init(&chip->lock);
+ gc = &chip->gc;
+ gc->base = -1;
+ gc->can_sleep = false;
+ gc->ngpio = val;
+ gc->label = dev_name(dev);
+ gc->dev = dev;
+ gc->of_node = dev->of_node;
+ gc->request = nsp_gpio_request;
+ gc->free = nsp_gpio_free;
+ gc->direction_input = nsp_gpio_direction_input;
+ gc->direction_output = nsp_gpio_direction_output;
+ gc->set = nsp_gpio_set;
+ gc->get = nsp_gpio_get;
+ gc->to_irq = nsp_gpio_to_irq;
+
+ /* optional GPIO interrupt support */
+ irq = platform_get_irq(pdev, 0);
+ if (irq > 0) {
+ /* Create irq domain so that each pin can be assigned an IRQ.*/
+ chip->irq_domain = irq_domain_add_linear(gc->of_node, gc->ngpio,
+ &irq_domain_simple_ops,
+ chip);
+ if (!chip->irq_domain) {
+ dev_err(&pdev->dev, "Couldn't allocate IRQ domain\n");
+ return -ENXIO;
+ }
+
+ /* Map each gpio to an IRQ and set the handler for gpiolib. */
+ for (count = 0; count < gc->ngpio; count++) {
+ int irq = irq_create_mapping(chip->irq_domain, count);
+
+ irq_set_chip_and_handler(irq, &nsp_gpio_irq_chip,
+ handle_simple_irq);
+ irq_set_chip_data(irq, chip);
+ }
+
+ /* Install ISR for this GPIO controller. */
+ ret = devm_request_irq(&pdev->dev, irq, nsp_gpio_irq_handler,
+ IRQF_SHARED, "gpio-a", chip);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request IRQ%d: %d\n",
+ irq, ret);
+ goto err_rm_gpiochip;
+ }
+
+ val = readl(chip->base + NSP_CHIP_A_INT_MASK);
+ val = val | NSP_CHIP_A_GPIO_INT_BIT;
+ writel(val, (chip->base + NSP_CHIP_A_INT_MASK));
+ }
+
+ ret = gpiochip_add(gc);
+ if (ret < 0) {
+ dev_err(dev, "unable to add GPIO chip\n");
+ return ret;
+ }
+
+ ret = nsp_gpio_register_pinconf(chip);
+ if (ret) {
+ dev_err(dev, "unable to register pinconf\n");
+ goto err_rm_gpiochip;
+ }
+
+ return 0;
+
+err_rm_gpiochip:
+ gpiochip_remove(gc);
+
+ return ret;
+}
+
+static struct platform_driver nsp_gpio_driver = {
+ .driver = {
+ .name = "nsp-gpio-a",
+ .of_match_table = nsp_gpio_of_match,
+ },
+ .probe = nsp_gpio_probe,
+};
+
+static int __init nsp_gpio_init(void)
+{
+ return platform_driver_probe(&nsp_gpio_driver, nsp_gpio_probe);
+}
+arch_initcall_sync(nsp_gpio_init);
diff --git a/drivers/pinctrl/berlin/Makefile b/drivers/pinctrl/berlin/Makefile
index 06f9402..6f641ce 100644
--- a/drivers/pinctrl/berlin/Makefile
+++ b/drivers/pinctrl/berlin/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PINCTRL_BERLIN) += berlin.o
+obj-y += berlin.o
obj-$(CONFIG_PINCTRL_BERLIN_BG2) += berlin-bg2.o
obj-$(CONFIG_PINCTRL_BERLIN_BG2CD) += berlin-bg2cd.o
obj-$(CONFIG_PINCTRL_BERLIN_BG2Q) += berlin-bg2q.o
diff --git a/drivers/pinctrl/freescale/pinctrl-imx1-core.c b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
index 88a7fac..acaf84c 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx1-core.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx1-core.c
@@ -538,8 +538,10 @@ static int imx1_pinctrl_parse_functions(struct device_node *np,
func->groups[i] = child->name;
grp = &info->groups[grp_index++];
ret = imx1_pinctrl_parse_groups(child, grp, info, i++);
- if (ret == -ENOMEM)
+ if (ret == -ENOMEM) {
+ of_node_put(child);
return ret;
+ }
}
return 0;
@@ -582,8 +584,10 @@ static int imx1_pinctrl_parse_dt(struct platform_device *pdev,
for_each_child_of_node(np, child) {
ret = imx1_pinctrl_parse_functions(child, info, ifunc++);
- if (ret == -ENOMEM)
+ if (ret == -ENOMEM) {
+ of_node_put(child);
return -ENOMEM;
+ }
}
return 0;
diff --git a/drivers/pinctrl/freescale/pinctrl-vf610.c b/drivers/pinctrl/freescale/pinctrl-vf610.c
index 37a0375..587d1ff 100644
--- a/drivers/pinctrl/freescale/pinctrl-vf610.c
+++ b/drivers/pinctrl/freescale/pinctrl-vf610.c
@@ -299,7 +299,7 @@ static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = {
static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
.pins = vf610_pinctrl_pads,
.npins = ARRAY_SIZE(vf610_pinctrl_pads),
- .flags = SHARE_MUX_CONF_REG,
+ .flags = SHARE_MUX_CONF_REG | ZERO_OFFSET_VALID,
};
static const struct of_device_id vf610_pinctrl_of_match[] = {
diff --git a/drivers/pinctrl/intel/pinctrl-broxton.c b/drivers/pinctrl/intel/pinctrl-broxton.c
index e42d5d4..5979d38 100644
--- a/drivers/pinctrl/intel/pinctrl-broxton.c
+++ b/drivers/pinctrl/intel/pinctrl-broxton.c
@@ -28,6 +28,7 @@
.padcfglock_offset = BXT_PADCFGLOCK, \
.hostown_offset = BXT_HOSTSW_OWN, \
.ie_offset = BXT_GPI_IE, \
+ .gpp_size = 32, \
.pin_base = (s), \
.npins = ((e) - (s) + 1), \
}
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 392e28d..26f6b6f 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -25,9 +25,6 @@
#include "pinctrl-intel.h"
-/* Maximum number of pads in each group */
-#define NPADS_IN_GPP 24
-
/* Offset from regs */
#define PADBAR 0x00c
#define GPI_IS 0x100
@@ -37,6 +34,7 @@
#define PADOWN_BITS 4
#define PADOWN_SHIFT(p) ((p) % 8 * PADOWN_BITS)
#define PADOWN_MASK(p) (0xf << PADOWN_SHIFT(p))
+#define PADOWN_GPP(p) ((p) / 8)
/* Offset from pad_regs */
#define PADCFG0 0x000
@@ -142,7 +140,7 @@ static void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl, unsigned pin,
static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
{
const struct intel_community *community;
- unsigned padno, gpp, gpp_offset, offset;
+ unsigned padno, gpp, offset, group;
void __iomem *padown;
community = intel_get_community(pctrl, pin);
@@ -152,9 +150,9 @@ static bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned pin)
return true;
padno = pin_to_padno(community, pin);
- gpp = padno / NPADS_IN_GPP;
- gpp_offset = padno % NPADS_IN_GPP;
- offset = community->padown_offset + gpp * 16 + (gpp_offset / 8) * 4;
+ group = padno / community->gpp_size;
+ gpp = PADOWN_GPP(padno % community->gpp_size);
+ offset = community->padown_offset + 0x10 * group + gpp * 4;
padown = community->regs + offset;
return !(readl(padown) & PADOWN_MASK(padno));
@@ -173,11 +171,11 @@ static bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned pin)
return false;
padno = pin_to_padno(community, pin);
- gpp = padno / NPADS_IN_GPP;
+ gpp = padno / community->gpp_size;
offset = community->hostown_offset + gpp * 4;
hostown = community->regs + offset;
- return !(readl(hostown) & BIT(padno % NPADS_IN_GPP));
+ return !(readl(hostown) & BIT(padno % community->gpp_size));
}
static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
@@ -193,7 +191,7 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
return false;
padno = pin_to_padno(community, pin);
- gpp = padno / NPADS_IN_GPP;
+ gpp = padno / community->gpp_size;
/*
* If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad,
@@ -202,12 +200,12 @@ static bool intel_pad_locked(struct intel_pinctrl *pctrl, unsigned pin)
*/
offset = community->padcfglock_offset + gpp * 8;
value = readl(community->regs + offset);
- if (value & BIT(pin % NPADS_IN_GPP))
+ if (value & BIT(pin % community->gpp_size))
return true;
offset = community->padcfglock_offset + 4 + gpp * 8;
value = readl(community->regs + offset);
- if (value & BIT(pin % NPADS_IN_GPP))
+ if (value & BIT(pin % community->gpp_size))
return true;
return false;
@@ -663,8 +661,8 @@ static void intel_gpio_irq_ack(struct irq_data *d)
community = intel_get_community(pctrl, pin);
if (community) {
unsigned padno = pin_to_padno(community, pin);
- unsigned gpp_offset = padno % NPADS_IN_GPP;
- unsigned gpp = padno / NPADS_IN_GPP;
+ unsigned gpp_offset = padno % community->gpp_size;
+ unsigned gpp = padno / community->gpp_size;
writel(BIT(gpp_offset), community->regs + GPI_IS + gpp * 4);
}
@@ -685,8 +683,8 @@ static void intel_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
community = intel_get_community(pctrl, pin);
if (community) {
unsigned padno = pin_to_padno(community, pin);
- unsigned gpp_offset = padno % NPADS_IN_GPP;
- unsigned gpp = padno / NPADS_IN_GPP;
+ unsigned gpp_offset = padno % community->gpp_size;
+ unsigned gpp = padno / community->gpp_size;
void __iomem *reg;
u32 value;
@@ -780,8 +778,8 @@ static int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
return -EINVAL;
padno = pin_to_padno(community, pin);
- gpp = padno / NPADS_IN_GPP;
- gpp_offset = padno % NPADS_IN_GPP;
+ gpp = padno / community->gpp_size;
+ gpp_offset = padno % community->gpp_size;
/* Clear the existing wake status */
writel(BIT(gpp_offset), community->regs + GPI_GPE_STS + gpp * 4);
@@ -819,14 +817,14 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
/* Only interrupts that are enabled */
pending &= enabled;
- for_each_set_bit(gpp_offset, &pending, NPADS_IN_GPP) {
+ for_each_set_bit(gpp_offset, &pending, community->gpp_size) {
unsigned padno, irq;
/*
* The last group in community can have less pins
* than NPADS_IN_GPP.
*/
- padno = gpp_offset + gpp * NPADS_IN_GPP;
+ padno = gpp_offset + gpp * community->gpp_size;
if (padno >= community->npins)
break;
@@ -1002,7 +1000,8 @@ int intel_pinctrl_probe(struct platform_device *pdev,
community->regs = regs;
community->pad_regs = regs + padbar;
- community->ngpps = DIV_ROUND_UP(community->npins, NPADS_IN_GPP);
+ community->ngpps = DIV_ROUND_UP(community->npins,
+ community->gpp_size);
}
irq = platform_get_irq(pdev, 0);
diff --git a/drivers/pinctrl/intel/pinctrl-intel.h b/drivers/pinctrl/intel/pinctrl-intel.h
index 4ec8b57..b602157 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.h
+++ b/drivers/pinctrl/intel/pinctrl-intel.h
@@ -55,6 +55,8 @@ struct intel_function {
* ACPI).
* @ie_offset: Register offset of GPI_IE from @regs.
* @pin_base: Starting pin of pins in this community
+ * @gpp_size: Maximum number of pads in each group, such as PADCFGLOCK,
+ * HOSTSW_OWN, GPI_IS, GPI_IE, etc.
* @npins: Number of pins in this community
* @regs: Community specific common registers (reserved for core driver)
* @pad_regs: Community specific pad registers (reserved for core driver)
@@ -68,6 +70,7 @@ struct intel_community {
unsigned hostown_offset;
unsigned ie_offset;
unsigned pin_base;
+ unsigned gpp_size;
size_t npins;
void __iomem *regs;
void __iomem *pad_regs;
diff --git a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
index 1de9ae5..c725a53 100644
--- a/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
+++ b/drivers/pinctrl/intel/pinctrl-sunrisepoint.c
@@ -30,6 +30,7 @@
.padcfglock_offset = SPT_PADCFGLOCK, \
.hostown_offset = SPT_HOSTSW_OWN, \
.ie_offset = SPT_GPI_IE, \
+ .gpp_size = 24, \
.pin_base = (s), \
.npins = ((e) - (s) + 1), \
}
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8127.c b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
index b317b0b..98e0beb 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8127.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8127.c
@@ -351,7 +351,7 @@ static int __init mtk_pinctrl_init(void)
return platform_driver_register(&mtk_pinctrl_driver);
}
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek MT8127 Pinctrl Driver");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8135.c b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
index 404f117..1c153b8 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8135.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8135.c
@@ -366,7 +366,7 @@ static int __init mtk_pinctrl_init(void)
return platform_driver_register(&mtk_pinctrl_driver);
}
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
index ad27184..a62514e 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c
@@ -394,7 +394,7 @@ static int __init mtk_pinctrl_init(void)
return platform_driver_register(&mtk_pinctrl_driver);
}
-module_init(mtk_pinctrl_init);
+arch_initcall(mtk_pinctrl_init);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("MediaTek Pinctrl Driver");
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index f307f1d..e22cbaf 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -509,6 +509,9 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
err = pinconf_generic_parse_dt_config(node, pctldev, &configs,
&num_configs);
+ if (err)
+ return err;
+
if (num_configs)
has_config = 1;
@@ -520,21 +523,23 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (has_config && num_pins >= 1)
maps_per_pin++;
- if (!num_pins || !maps_per_pin)
- return -EINVAL;
+ if (!num_pins || !maps_per_pin) {
+ err = -EINVAL;
+ goto exit;
+ }
reserve = num_pins * maps_per_pin;
err = pinctrl_utils_reserve_map(pctldev, map,
reserved_maps, num_maps, reserve);
if (err < 0)
- goto fail;
+ goto exit;
for (i = 0; i < num_pins; i++) {
err = of_property_read_u32_index(node, "pinmux",
i, &pinfunc);
if (err)
- goto fail;
+ goto exit;
pin = MTK_GET_PIN_NO(pinfunc);
func = MTK_GET_PIN_FUNC(pinfunc);
@@ -543,20 +548,21 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
func >= ARRAY_SIZE(mtk_gpio_functions)) {
dev_err(pctl->dev, "invalid pins value.\n");
err = -EINVAL;
- goto fail;
+ goto exit;
}
grp = mtk_pctrl_find_group_by_pin(pctl, pin);
if (!grp) {
dev_err(pctl->dev, "unable to match pin %d to group\n",
pin);
- return -EINVAL;
+ err = -EINVAL;
+ goto exit;
}
err = mtk_pctrl_dt_node_to_map_func(pctl, pin, func, grp, map,
reserved_maps, num_maps);
if (err < 0)
- goto fail;
+ goto exit;
if (has_config) {
err = pinctrl_utils_add_map_configs(pctldev, map,
@@ -564,13 +570,14 @@ static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (err < 0)
- goto fail;
+ goto exit;
}
}
- return 0;
+ err = 0;
-fail:
+exit:
+ kfree(configs);
return err;
}
@@ -591,6 +598,7 @@ static int mtk_pctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
&reserved_maps, num_maps);
if (ret < 0) {
pinctrl_utils_dt_free_map(pctldev, *map, *num_maps);
+ of_node_put(np);
return ret;
}
}
@@ -747,7 +755,7 @@ static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
reg_addr = mtk_get_port(pctl, offset) + pctl->devdata->dir_offset;
bit = BIT(offset & 0xf);
regmap_read(pctl->regmap1, reg_addr, &read_val);
- return !!(read_val & bit);
+ return !(read_val & bit);
}
static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
@@ -757,12 +765,8 @@ static int mtk_gpio_get(struct gpio_chip *chip, unsigned offset)
unsigned int read_val = 0;
struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
- if (mtk_gpio_get_direction(chip, offset))
- reg_addr = mtk_get_port(pctl, offset) +
- pctl->devdata->dout_offset;
- else
- reg_addr = mtk_get_port(pctl, offset) +
- pctl->devdata->din_offset;
+ reg_addr = mtk_get_port(pctl, offset) +
+ pctl->devdata->din_offset;
bit = BIT(offset & 0xf);
regmap_read(pctl->regmap1, reg_addr, &read_val);
@@ -997,6 +1001,7 @@ static struct gpio_chip mtk_gpio_chip = {
.owner = THIS_MODULE,
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
+ .get_direction = mtk_gpio_get_direction,
.direction_input = mtk_gpio_direction_input,
.direction_output = mtk_gpio_direction_output,
.get = mtk_gpio_get,
diff --git a/drivers/pinctrl/mvebu/Makefile b/drivers/pinctrl/mvebu/Makefile
index 554d8af..18270cd 100644
--- a/drivers/pinctrl/mvebu/Makefile
+++ b/drivers/pinctrl/mvebu/Makefile
@@ -1,4 +1,4 @@
-obj-$(CONFIG_PINCTRL_MVEBU) += pinctrl-mvebu.o
+obj-y += 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
diff --git a/drivers/pinctrl/mvebu/pinctrl-mvebu.c b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
index 77d2221..e4d4738 100644
--- a/drivers/pinctrl/mvebu/pinctrl-mvebu.c
+++ b/drivers/pinctrl/mvebu/pinctrl-mvebu.c
@@ -663,28 +663,20 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
/* assign mpp modes to groups */
for (n = 0; n < soc->nmodes; n++) {
struct mvebu_mpp_mode *mode = &soc->modes[n];
- struct mvebu_pinctrl_group *grp =
- mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
+ struct mvebu_mpp_ctrl_setting *set = &mode->settings[0];
+ struct mvebu_pinctrl_group *grp;
unsigned num_settings;
- if (!grp) {
- dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
- mode->pid);
- continue;
- }
-
- for (num_settings = 0; ;) {
- struct mvebu_mpp_ctrl_setting *set =
- &mode->settings[num_settings];
-
+ for (num_settings = 0; ; set++) {
if (!set->name)
break;
- num_settings++;
/* skip unsupported settings for this variant */
if (pctl->variant && !(pctl->variant & set->variant))
continue;
+ num_settings++;
+
/* find gpio/gpo/gpi settings */
if (strcmp(set->name, "gpio") == 0)
set->flags = MVEBU_SETTING_GPI |
@@ -695,6 +687,17 @@ int mvebu_pinctrl_probe(struct platform_device *pdev)
set->flags = MVEBU_SETTING_GPI;
}
+ /* skip modes with no settings for this variant */
+ if (!num_settings)
+ continue;
+
+ grp = mvebu_pinctrl_find_group_by_pid(pctl, mode->pid);
+ if (!grp) {
+ dev_warn(&pdev->dev, "unknown pinctrl group %d\n",
+ mode->pid);
+ continue;
+ }
+
grp->settings = mode->settings;
grp->num_settings = num_settings;
}
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 099a344..79e6159 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -220,6 +220,7 @@ static void parse_dt_cfg(struct device_node *np,
* parse the config properties into generic pinconfig values.
* @np: node containing the pinconfig properties
* @configs: array with nconfigs entries containing the generic pinconf values
+ * must be freed when no longer necessary.
* @nconfigs: umber of configurations
*/
int pinconf_generic_parse_dt_config(struct device_node *np,
diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c
index fd342df..8e9e8ea 100644
--- a/drivers/pinctrl/pinctrl-adi2.c
+++ b/drivers/pinctrl/pinctrl-adi2.c
@@ -1102,32 +1102,24 @@ static struct platform_driver adi_gpio_driver = {
},
};
+static struct platform_driver * const drivers[] = {
+ &adi_pinctrl_driver,
+ &adi_gpio_pint_driver,
+ &adi_gpio_driver,
+};
+
static int __init adi_pinctrl_setup(void)
{
int ret;
- ret = platform_driver_register(&adi_pinctrl_driver);
+ ret = platform_register_drivers(drivers, ARRAY_SIZE(drivers));
if (ret)
return ret;
- ret = platform_driver_register(&adi_gpio_pint_driver);
- if (ret)
- goto pint_error;
-
- ret = platform_driver_register(&adi_gpio_driver);
- if (ret)
- goto gpio_error;
-
#ifdef CONFIG_PM
register_syscore_ops(&gpio_pm_syscore_ops);
#endif
- return ret;
-gpio_error:
- platform_driver_unregister(&adi_gpio_pint_driver);
-pint_error:
- platform_driver_unregister(&adi_pinctrl_driver);
-
- return ret;
+ return 0;
}
arch_initcall(adi_pinctrl_setup);
diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c
index 33edd07..d5bdceb 100644
--- a/drivers/pinctrl/pinctrl-at91-pio4.c
+++ b/drivers/pinctrl/pinctrl-at91-pio4.c
@@ -500,7 +500,8 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (!num_pins) {
dev_err(pctldev->dev, "no pins found in node %s\n",
of_node_full_name(np));
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit;
}
/*
@@ -514,19 +515,19 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps,
reserve);
if (ret < 0)
- return ret;
+ goto exit;
for (i = 0; i < num_pins; i++) {
const char *group, *func;
ret = of_property_read_u32_index(np, "pinmux", i, &pinfunc);
if (ret)
- return ret;
+ goto exit;
ret = atmel_pctl_xlate_pinfunc(pctldev, np, pinfunc, &group,
&func);
if (ret)
- return ret;
+ goto exit;
pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps,
group, func);
@@ -537,11 +538,13 @@ static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (ret < 0)
- return ret;
+ goto exit;
}
}
- return 0;
+exit:
+ kfree(configs);
+ return ret;
}
static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev,
@@ -1000,7 +1003,7 @@ static int atmel_pinctrl_probe(struct platform_device *pdev)
atmel_pioctrl->irqs[i] = res->start;
irq_set_chained_handler(res->start, atmel_gpio_irq_handler);
irq_set_handler_data(res->start, atmel_pioctrl);
- dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start);
+ dev_dbg(dev, "bank %i: irq=%pr\n", i, res);
}
atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node,
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 0d2fc0c..47b625b 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1828,20 +1828,20 @@ static struct platform_driver at91_pinctrl_driver = {
.remove = at91_pinctrl_remove,
};
+static struct platform_driver * const drivers[] = {
+ &at91_gpio_driver,
+ &at91_pinctrl_driver,
+};
+
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);
+ return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
}
arch_initcall(at91_pinctrl_init);
static void __exit at91_pinctrl_exit(void)
{
- platform_driver_unregister(&at91_pinctrl_driver);
+ platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
}
module_exit(at91_pinctrl_exit);
diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h
index eb89ba0..e137d13 100644
--- a/drivers/pinctrl/pinctrl-lantiq.h
+++ b/drivers/pinctrl/pinctrl-lantiq.h
@@ -162,6 +162,14 @@ enum ltq_pin {
GPIO53,
GPIO54,
GPIO55,
+ GPIO56,
+ GPIO57,
+ GPIO58,
+ GPIO59,
+ GPIO60, /* 60 */
+ GPIO61,
+ GPIO62,
+ GPIO63,
GPIO64,
GPIO65,
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index a065112..9128826 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -614,6 +614,40 @@ static void rk3288_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
}
}
+#define RK3228_PULL_OFFSET 0x100
+
+static void rk3228_calc_pull_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+
+ *regmap = info->regmap_base;
+ *reg = RK3228_PULL_OFFSET;
+ *reg += bank->bank_num * RK3188_PULL_BANK_STRIDE;
+ *reg += ((pin_num / RK3188_PULL_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % RK3188_PULL_PINS_PER_REG);
+ *bit *= RK3188_PULL_BITS_PER_PIN;
+}
+
+#define RK3228_DRV_GRF_OFFSET 0x200
+
+static void rk3228_calc_drv_reg_and_bit(struct rockchip_pin_bank *bank,
+ int pin_num, struct regmap **regmap,
+ int *reg, u8 *bit)
+{
+ struct rockchip_pinctrl *info = bank->drvdata;
+
+ *regmap = info->regmap_base;
+ *reg = RK3228_DRV_GRF_OFFSET;
+ *reg += bank->bank_num * RK3288_DRV_BANK_STRIDE;
+ *reg += ((pin_num / RK3288_DRV_PINS_PER_REG) * 4);
+
+ *bit = (pin_num % RK3288_DRV_PINS_PER_REG);
+ *bit *= RK3288_DRV_BITS_PER_PIN;
+}
+
#define RK3368_PULL_GRF_OFFSET 0x100
#define RK3368_PULL_PMU_OFFSET 0x10
@@ -1258,8 +1292,10 @@ static int rockchip_pinctrl_parse_functions(struct device_node *np,
func->groups[i] = child->name;
grp = &info->groups[grp_index++];
ret = rockchip_pinctrl_parse_groups(child, grp, info, i++);
- if (ret)
+ if (ret) {
+ of_node_put(child);
return ret;
+ }
}
return 0;
@@ -1304,6 +1340,7 @@ static int rockchip_pinctrl_parse_dt(struct platform_device *pdev,
ret = rockchip_pinctrl_parse_functions(child, info, i++);
if (ret) {
dev_err(&pdev->dev, "failed to parse function\n");
+ of_node_put(child);
return ret;
}
}
@@ -2143,6 +2180,23 @@ static struct rockchip_pin_ctrl rk3188_pin_ctrl = {
.pull_calc_reg = rk3188_calc_pull_reg_and_bit,
};
+static struct rockchip_pin_bank rk3228_pin_banks[] = {
+ PIN_BANK(0, 32, "gpio0"),
+ PIN_BANK(1, 32, "gpio1"),
+ PIN_BANK(2, 32, "gpio2"),
+ PIN_BANK(3, 32, "gpio3"),
+};
+
+static struct rockchip_pin_ctrl rk3228_pin_ctrl = {
+ .pin_banks = rk3228_pin_banks,
+ .nr_banks = ARRAY_SIZE(rk3228_pin_banks),
+ .label = "RK3228-GPIO",
+ .type = RK3288,
+ .grf_mux_offset = 0x0,
+ .pull_calc_reg = rk3228_calc_pull_reg_and_bit,
+ .drv_calc_reg = rk3228_calc_drv_reg_and_bit,
+};
+
static struct rockchip_pin_bank rk3288_pin_banks[] = {
PIN_BANK_IOMUX_FLAGS(0, 24, "gpio0", IOMUX_SOURCE_PMU,
IOMUX_SOURCE_PMU,
@@ -2220,6 +2274,8 @@ static const struct of_device_id rockchip_pinctrl_dt_match[] = {
.data = (void *)&rk3066b_pin_ctrl },
{ .compatible = "rockchip,rk3188-pinctrl",
.data = (void *)&rk3188_pin_ctrl },
+ { .compatible = "rockchip,rk3228-pinctrl",
+ .data = (void *)&rk3228_pin_ctrl },
{ .compatible = "rockchip,rk3288-pinctrl",
.data = (void *)&rk3288_pin_ctrl },
{ .compatible = "rockchip,rk3368-pinctrl",
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index ef04b96..d24e5f1 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -1484,10 +1484,7 @@ static void pcs_irq_free(struct pcs_device *pcs)
static void pcs_free_resources(struct pcs_device *pcs)
{
pcs_irq_free(pcs);
-
- if (pcs->pctl)
- pinctrl_unregister(pcs->pctl);
-
+ pinctrl_unregister(pcs->pctl);
pcs_free_funcs(pcs);
pcs_free_pingroups(pcs);
}
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 84a43e6..bd3aa5a 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -253,8 +253,10 @@ static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
err = tegra_xusb_padctl_parse_subnode(padctl, np, maps,
&reserved_maps,
num_maps);
- if (err < 0)
+ if (err < 0) {
+ of_node_put(np);
return err;
+ }
}
return 0;
diff --git a/drivers/pinctrl/pinctrl-tegra.c b/drivers/pinctrl/pinctrl-tegra.c
index 0fd7fd2..9da4da2 100644
--- a/drivers/pinctrl/pinctrl-tegra.c
+++ b/drivers/pinctrl/pinctrl-tegra.c
@@ -217,6 +217,7 @@ static int tegra_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
if (ret < 0) {
pinctrl_utils_dt_free_map(pctldev, *map,
*num_maps);
+ of_node_put(np);
return ret;
}
}
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c
index ae724bd..7db7469 100644
--- a/drivers/pinctrl/pinctrl-xway.c
+++ b/drivers/pinctrl/pinctrl-xway.c
@@ -7,6 +7,7 @@
* publishhed by the Free Software Foundation.
*
* Copyright (C) 2012 John Crispin <blogic@openwrt.org>
+ * Copyright (C) 2015 Martin Schiller <mschiller@tdt.de>
*/
#include <linux/err.h>
@@ -24,7 +25,7 @@
#include <lantiq_soc.h>
-/* we have 3 1/2 banks of 16 bit each */
+/* we have up to 4 banks of 16 bit each */
#define PINS 16
#define PORT3 3
#define PORT(x) (x / PINS)
@@ -35,7 +36,7 @@
#define MUX_ALT1 0x2
/*
- * each bank has this offset apart from the 1/2 bank that is mixed into the
+ * each bank has this offset apart from the 4th bank that is mixed into the
* other 3 ranges
*/
#define REG_OFF 0x30
@@ -51,7 +52,7 @@
#define GPIO_PUDSEL(p) (GPIO_BASE(p) + 0x1c)
#define GPIO_PUDEN(p) (GPIO_BASE(p) + 0x20)
-/* the 1/2 port needs special offsets for some registers */
+/* the 4th port needs special offsets for some registers */
#define GPIO3_OD (GPIO_BASE(0) + 0x24)
#define GPIO3_PUDSEL (GPIO_BASE(0) + 0x28)
#define GPIO3_PUDEN (GPIO_BASE(0) + 0x2C)
@@ -80,17 +81,18 @@
#define FUNC_MUX(f, m) \
{ .func = f, .mux = XWAY_MUX_##m, }
-#define XWAY_MAX_PIN 32
-#define XR9_MAX_PIN 56
-
enum xway_mux {
XWAY_MUX_GPIO = 0,
XWAY_MUX_SPI,
XWAY_MUX_ASC,
+ XWAY_MUX_USIF,
XWAY_MUX_PCI,
+ XWAY_MUX_CBUS,
XWAY_MUX_CGU,
XWAY_MUX_EBU,
+ XWAY_MUX_EBU2,
XWAY_MUX_JTAG,
+ XWAY_MUX_MCD,
XWAY_MUX_EXIN,
XWAY_MUX_TDM,
XWAY_MUX_STP,
@@ -103,9 +105,15 @@ enum xway_mux {
XWAY_MUX_DFE,
XWAY_MUX_SDIO,
XWAY_MUX_GPHY,
+ XWAY_MUX_SSI,
+ XWAY_MUX_WIFI,
XWAY_MUX_NONE = 0xffff,
};
+/* --------- DEPRECATED: xr9 related code --------- */
+/* ---------- use xrx100/xrx200 instead ---------- */
+#define XR9_MAX_PIN 56
+
static const struct ltq_mfp_pin xway_mfp[] = {
/* pin f0 f1 f2 f3 */
MFP_XWAY(GPIO0, GPIO, EXIN, NONE, TDM),
@@ -113,7 +121,7 @@ static const struct ltq_mfp_pin xway_mfp[] = {
MFP_XWAY(GPIO2, GPIO, CGU, EXIN, GPHY),
MFP_XWAY(GPIO3, GPIO, CGU, NONE, PCI),
MFP_XWAY(GPIO4, GPIO, STP, NONE, ASC),
- MFP_XWAY(GPIO5, GPIO, STP, NONE, GPHY),
+ MFP_XWAY(GPIO5, GPIO, STP, GPHY, NONE),
MFP_XWAY(GPIO6, GPIO, STP, GPT, ASC),
MFP_XWAY(GPIO7, GPIO, CGU, PCI, GPHY),
MFP_XWAY(GPIO8, GPIO, CGU, NMI, NONE),
@@ -152,10 +160,10 @@ static const struct ltq_mfp_pin xway_mfp[] = {
MFP_XWAY(GPIO41, GPIO, NONE, NONE, NONE),
MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE),
MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE),
- MFP_XWAY(GPIO44, GPIO, NONE, GPHY, SIN),
+ MFP_XWAY(GPIO44, GPIO, MII, SIN, GPHY),
MFP_XWAY(GPIO45, GPIO, NONE, GPHY, SIN),
MFP_XWAY(GPIO46, GPIO, NONE, NONE, EXIN),
- MFP_XWAY(GPIO47, GPIO, NONE, GPHY, SIN),
+ MFP_XWAY(GPIO47, GPIO, MII, GPHY, SIN),
MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE),
MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE),
MFP_XWAY(GPIO50, GPIO, NONE, NONE, NONE),
@@ -166,42 +174,6 @@ static const struct ltq_mfp_pin xway_mfp[] = {
MFP_XWAY(GPIO55, GPIO, NONE, NONE, NONE),
};
-static const struct ltq_mfp_pin ase_mfp[] = {
- /* pin f0 f1 f2 f3 */
- MFP_XWAY(GPIO0, GPIO, EXIN, MII, TDM),
- MFP_XWAY(GPIO1, GPIO, STP, DFE, EBU),
- MFP_XWAY(GPIO2, GPIO, STP, DFE, EPHY),
- MFP_XWAY(GPIO3, GPIO, STP, EPHY, EBU),
- MFP_XWAY(GPIO4, GPIO, GPT, EPHY, MII),
- MFP_XWAY(GPIO5, GPIO, MII, ASC, GPT),
- MFP_XWAY(GPIO6, GPIO, MII, ASC, EXIN),
- MFP_XWAY(GPIO7, GPIO, SPI, MII, JTAG),
- MFP_XWAY(GPIO8, GPIO, SPI, MII, JTAG),
- MFP_XWAY(GPIO9, GPIO, SPI, MII, JTAG),
- MFP_XWAY(GPIO10, GPIO, SPI, MII, JTAG),
- MFP_XWAY(GPIO11, GPIO, EBU, CGU, JTAG),
- MFP_XWAY(GPIO12, GPIO, EBU, MII, SDIO),
- MFP_XWAY(GPIO13, GPIO, EBU, MII, CGU),
- MFP_XWAY(GPIO14, GPIO, EBU, SPI, CGU),
- MFP_XWAY(GPIO15, GPIO, EBU, SPI, SDIO),
- MFP_XWAY(GPIO16, GPIO, NONE, NONE, NONE),
- MFP_XWAY(GPIO17, GPIO, NONE, NONE, NONE),
- MFP_XWAY(GPIO18, GPIO, NONE, NONE, NONE),
- MFP_XWAY(GPIO19, GPIO, EBU, MII, SDIO),
- MFP_XWAY(GPIO20, GPIO, EBU, MII, SDIO),
- MFP_XWAY(GPIO21, GPIO, EBU, MII, SDIO),
- MFP_XWAY(GPIO22, GPIO, EBU, MII, CGU),
- MFP_XWAY(GPIO23, GPIO, EBU, MII, CGU),
- MFP_XWAY(GPIO24, GPIO, EBU, NONE, MII),
- MFP_XWAY(GPIO25, GPIO, EBU, MII, GPT),
- MFP_XWAY(GPIO26, GPIO, EBU, MII, SDIO),
- MFP_XWAY(GPIO27, GPIO, EBU, NONE, MII),
- MFP_XWAY(GPIO28, GPIO, MII, EBU, SDIO),
- MFP_XWAY(GPIO29, GPIO, EBU, MII, EXIN),
- MFP_XWAY(GPIO30, GPIO, NONE, NONE, NONE),
- MFP_XWAY(GPIO31, GPIO, NONE, NONE, NONE),
-};
-
static const unsigned pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO19, GPIO35};
static const unsigned pins_asc0[] = {GPIO11, GPIO12};
static const unsigned pins_asc0_cts_rts[] = {GPIO9, GPIO10};
@@ -231,6 +203,8 @@ static const unsigned pins_nand_cle[] = {GPIO24};
static const unsigned pins_nand_rdy[] = {GPIO48};
static const unsigned pins_nand_rd[] = {GPIO49};
+static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9};
+
static const unsigned pins_exin0[] = {GPIO0};
static const unsigned pins_exin1[] = {GPIO1};
static const unsigned pins_exin2[] = {GPIO2};
@@ -240,7 +214,7 @@ static const unsigned pins_exin5[] = {GPIO9};
static const unsigned pins_spi[] = {GPIO16, GPIO17, GPIO18};
static const unsigned pins_spi_cs1[] = {GPIO15};
-static const unsigned pins_spi_cs2[] = {GPIO21};
+static const unsigned pins_spi_cs2[] = {GPIO22};
static const unsigned pins_spi_cs3[] = {GPIO13};
static const unsigned pins_spi_cs4[] = {GPIO10};
static const unsigned pins_spi_cs5[] = {GPIO9};
@@ -264,25 +238,6 @@ static const unsigned pins_pci_req2[] = {GPIO31};
static const unsigned pins_pci_req3[] = {GPIO3};
static const unsigned pins_pci_req4[] = {GPIO37};
-static const unsigned ase_pins_jtag[] = {GPIO7, GPIO8, GPIO9, GPIO10, GPIO11};
-static const unsigned ase_pins_asc[] = {GPIO5, GPIO6};
-static const unsigned ase_pins_stp[] = {GPIO1, GPIO2, GPIO3};
-static const unsigned ase_pins_ephy[] = {GPIO2, GPIO3, GPIO4};
-static const unsigned ase_pins_dfe[] = {GPIO1, GPIO2};
-
-static const unsigned ase_pins_spi[] = {GPIO8, GPIO9, GPIO10};
-static const unsigned ase_pins_spi_cs1[] = {GPIO7};
-static const unsigned ase_pins_spi_cs2[] = {GPIO15};
-static const unsigned ase_pins_spi_cs3[] = {GPIO14};
-
-static const unsigned ase_pins_exin0[] = {GPIO6};
-static const unsigned ase_pins_exin1[] = {GPIO29};
-static const unsigned ase_pins_exin2[] = {GPIO0};
-
-static const unsigned ase_pins_gpt1[] = {GPIO5};
-static const unsigned ase_pins_gpt2[] = {GPIO4};
-static const unsigned ase_pins_gpt3[] = {GPIO25};
-
static const struct ltq_pin_group xway_grps[] = {
GRP_MUX("exin0", EXIN, pins_exin0),
GRP_MUX("exin1", EXIN, pins_exin1),
@@ -338,24 +293,6 @@ static const struct ltq_pin_group xway_grps[] = {
GRP_MUX("gphy1 led2", GPHY, pins_gphy1_led2),
};
-static const struct ltq_pin_group ase_grps[] = {
- GRP_MUX("exin0", EXIN, ase_pins_exin0),
- GRP_MUX("exin1", EXIN, ase_pins_exin1),
- GRP_MUX("exin2", EXIN, ase_pins_exin2),
- GRP_MUX("jtag", JTAG, ase_pins_jtag),
- GRP_MUX("stp", STP, ase_pins_stp),
- GRP_MUX("asc", ASC, ase_pins_asc),
- GRP_MUX("gpt1", GPT, ase_pins_gpt1),
- GRP_MUX("gpt2", GPT, ase_pins_gpt2),
- GRP_MUX("gpt3", GPT, ase_pins_gpt3),
- GRP_MUX("ephy", EPHY, ase_pins_ephy),
- GRP_MUX("dfe", DFE, ase_pins_dfe),
- GRP_MUX("spi", SPI, ase_pins_spi),
- GRP_MUX("spi_cs1", SPI, ase_pins_spi_cs1),
- GRP_MUX("spi_cs2", SPI, ase_pins_spi_cs2),
- GRP_MUX("spi_cs3", SPI, ase_pins_spi_cs3),
-};
-
static const char * const xway_pci_grps[] = {"gnt1", "gnt2",
"gnt3", "req1",
"req2", "req3"};
@@ -395,30 +332,6 @@ static const char * const xrx_pci_grps[] = {"gnt1", "gnt2",
"req1", "req2",
"req3", "req4"};
-/* ase */
-static const char * const ase_exin_grps[] = {"exin0", "exin1", "exin2"};
-static const char * const ase_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
-static const char * const ase_dfe_grps[] = {"dfe"};
-static const char * const ase_ephy_grps[] = {"ephy"};
-static const char * const ase_asc_grps[] = {"asc"};
-static const char * const ase_jtag_grps[] = {"jtag"};
-static const char * const ase_stp_grps[] = {"stp"};
-static const char * const ase_spi_grps[] = {"spi", "spi_cs1",
- "spi_cs2", "spi_cs3"};
-
-static const struct ltq_pmx_func danube_funcs[] = {
- {"spi", ARRAY_AND_SIZE(xway_spi_grps)},
- {"asc", ARRAY_AND_SIZE(xway_asc_grps)},
- {"cgu", ARRAY_AND_SIZE(xway_cgu_grps)},
- {"jtag", ARRAY_AND_SIZE(xway_jtag_grps)},
- {"exin", ARRAY_AND_SIZE(xway_exin_grps)},
- {"stp", ARRAY_AND_SIZE(xway_stp_grps)},
- {"gpt", ARRAY_AND_SIZE(xway_gpt_grps)},
- {"nmi", ARRAY_AND_SIZE(xway_nmi_grps)},
- {"pci", ARRAY_AND_SIZE(xway_pci_grps)},
- {"ebu", ARRAY_AND_SIZE(xway_ebu_grps)},
-};
-
static const struct ltq_pmx_func xrx_funcs[] = {
{"spi", ARRAY_AND_SIZE(xway_spi_grps)},
{"asc", ARRAY_AND_SIZE(xway_asc_grps)},
@@ -434,17 +347,991 @@ static const struct ltq_pmx_func xrx_funcs[] = {
{"gphy", ARRAY_AND_SIZE(xrx_gphy_grps)},
};
+/* --------- ase related code --------- */
+#define ASE_MAX_PIN 32
+
+static const struct ltq_mfp_pin ase_mfp[] = {
+ /* pin f0 f1 f2 f3 */
+ MFP_XWAY(GPIO0, GPIO, EXIN, MII, TDM),
+ MFP_XWAY(GPIO1, GPIO, STP, DFE, EBU),
+ MFP_XWAY(GPIO2, GPIO, STP, DFE, EPHY),
+ MFP_XWAY(GPIO3, GPIO, STP, EPHY, EBU),
+ MFP_XWAY(GPIO4, GPIO, GPT, EPHY, MII),
+ MFP_XWAY(GPIO5, GPIO, MII, ASC, GPT),
+ MFP_XWAY(GPIO6, GPIO, MII, ASC, EXIN),
+ MFP_XWAY(GPIO7, GPIO, SPI, MII, JTAG),
+ MFP_XWAY(GPIO8, GPIO, SPI, MII, JTAG),
+ MFP_XWAY(GPIO9, GPIO, SPI, MII, JTAG),
+ MFP_XWAY(GPIO10, GPIO, SPI, MII, JTAG),
+ MFP_XWAY(GPIO11, GPIO, EBU, CGU, JTAG),
+ MFP_XWAY(GPIO12, GPIO, EBU, MII, SDIO),
+ MFP_XWAY(GPIO13, GPIO, EBU, MII, CGU),
+ MFP_XWAY(GPIO14, GPIO, EBU, SPI, CGU),
+ MFP_XWAY(GPIO15, GPIO, EBU, SPI, SDIO),
+ MFP_XWAY(GPIO16, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO17, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO18, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO19, GPIO, EBU, MII, SDIO),
+ MFP_XWAY(GPIO20, GPIO, EBU, MII, SDIO),
+ MFP_XWAY(GPIO21, GPIO, EBU, MII, EBU2),
+ MFP_XWAY(GPIO22, GPIO, EBU, MII, CGU),
+ MFP_XWAY(GPIO23, GPIO, EBU, MII, CGU),
+ MFP_XWAY(GPIO24, GPIO, EBU, EBU2, MDIO),
+ MFP_XWAY(GPIO25, GPIO, EBU, MII, GPT),
+ MFP_XWAY(GPIO26, GPIO, EBU, MII, SDIO),
+ MFP_XWAY(GPIO27, GPIO, EBU, NONE, MDIO),
+ MFP_XWAY(GPIO28, GPIO, MII, EBU, SDIO),
+ MFP_XWAY(GPIO29, GPIO, EBU, MII, EXIN),
+ MFP_XWAY(GPIO30, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO31, GPIO, NONE, NONE, NONE),
+};
+
+static const unsigned ase_exin_pin_map[] = {GPIO6, GPIO29, GPIO0};
+
+static const unsigned ase_pins_exin0[] = {GPIO6};
+static const unsigned ase_pins_exin1[] = {GPIO29};
+static const unsigned ase_pins_exin2[] = {GPIO0};
+
+static const unsigned ase_pins_jtag[] = {GPIO7, GPIO8, GPIO9, GPIO10, GPIO11};
+static const unsigned ase_pins_asc[] = {GPIO5, GPIO6};
+static const unsigned ase_pins_stp[] = {GPIO1, GPIO2, GPIO3};
+static const unsigned ase_pins_mdio[] = {GPIO24, GPIO27};
+static const unsigned ase_pins_ephy_led0[] = {GPIO2};
+static const unsigned ase_pins_ephy_led1[] = {GPIO3};
+static const unsigned ase_pins_ephy_led2[] = {GPIO4};
+static const unsigned ase_pins_dfe_led0[] = {GPIO1};
+static const unsigned ase_pins_dfe_led1[] = {GPIO2};
+
+static const unsigned ase_pins_spi[] = {GPIO8, GPIO9, GPIO10}; /* DEPRECATED */
+static const unsigned ase_pins_spi_di[] = {GPIO8};
+static const unsigned ase_pins_spi_do[] = {GPIO9};
+static const unsigned ase_pins_spi_clk[] = {GPIO10};
+static const unsigned ase_pins_spi_cs1[] = {GPIO7};
+static const unsigned ase_pins_spi_cs2[] = {GPIO15};
+static const unsigned ase_pins_spi_cs3[] = {GPIO14};
+
+static const unsigned ase_pins_gpt1[] = {GPIO5};
+static const unsigned ase_pins_gpt2[] = {GPIO4};
+static const unsigned ase_pins_gpt3[] = {GPIO25};
+
+static const unsigned ase_pins_clkout0[] = {GPIO23};
+static const unsigned ase_pins_clkout1[] = {GPIO22};
+static const unsigned ase_pins_clkout2[] = {GPIO14};
+
+static const struct ltq_pin_group ase_grps[] = {
+ GRP_MUX("exin0", EXIN, ase_pins_exin0),
+ GRP_MUX("exin1", EXIN, ase_pins_exin1),
+ GRP_MUX("exin2", EXIN, ase_pins_exin2),
+ GRP_MUX("jtag", JTAG, ase_pins_jtag),
+ GRP_MUX("spi", SPI, ase_pins_spi), /* DEPRECATED */
+ GRP_MUX("spi_di", SPI, ase_pins_spi_di),
+ GRP_MUX("spi_do", SPI, ase_pins_spi_do),
+ GRP_MUX("spi_clk", SPI, ase_pins_spi_clk),
+ GRP_MUX("spi_cs1", SPI, ase_pins_spi_cs1),
+ GRP_MUX("spi_cs2", SPI, ase_pins_spi_cs2),
+ GRP_MUX("spi_cs3", SPI, ase_pins_spi_cs3),
+ GRP_MUX("asc", ASC, ase_pins_asc),
+ GRP_MUX("stp", STP, ase_pins_stp),
+ GRP_MUX("gpt1", GPT, ase_pins_gpt1),
+ GRP_MUX("gpt2", GPT, ase_pins_gpt2),
+ GRP_MUX("gpt3", GPT, ase_pins_gpt3),
+ GRP_MUX("clkout0", CGU, ase_pins_clkout0),
+ GRP_MUX("clkout1", CGU, ase_pins_clkout1),
+ GRP_MUX("clkout2", CGU, ase_pins_clkout2),
+ GRP_MUX("mdio", MDIO, ase_pins_mdio),
+ GRP_MUX("dfe led0", DFE, ase_pins_dfe_led0),
+ GRP_MUX("dfe led1", DFE, ase_pins_dfe_led1),
+ GRP_MUX("ephy led0", EPHY, ase_pins_ephy_led0),
+ GRP_MUX("ephy led1", EPHY, ase_pins_ephy_led1),
+ GRP_MUX("ephy led2", EPHY, ase_pins_ephy_led2),
+};
+
+static const char * const ase_exin_grps[] = {"exin0", "exin1", "exin2"};
+static const char * const ase_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const ase_cgu_grps[] = {"clkout0", "clkout1",
+ "clkout2"};
+static const char * const ase_mdio_grps[] = {"mdio"};
+static const char * const ase_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const ase_ephy_grps[] = {"ephy led0", "ephy led1",
+ "ephy led2"};
+static const char * const ase_asc_grps[] = {"asc"};
+static const char * const ase_jtag_grps[] = {"jtag"};
+static const char * const ase_stp_grps[] = {"stp"};
+static const char * const ase_spi_grps[] = {"spi", /* DEPRECATED */
+ "spi_di", "spi_do",
+ "spi_clk", "spi_cs1",
+ "spi_cs2", "spi_cs3"};
+
static const struct ltq_pmx_func ase_funcs[] = {
{"spi", ARRAY_AND_SIZE(ase_spi_grps)},
{"asc", ARRAY_AND_SIZE(ase_asc_grps)},
+ {"cgu", ARRAY_AND_SIZE(ase_cgu_grps)},
{"jtag", ARRAY_AND_SIZE(ase_jtag_grps)},
{"exin", ARRAY_AND_SIZE(ase_exin_grps)},
{"stp", ARRAY_AND_SIZE(ase_stp_grps)},
{"gpt", ARRAY_AND_SIZE(ase_gpt_grps)},
+ {"mdio", ARRAY_AND_SIZE(ase_mdio_grps)},
{"ephy", ARRAY_AND_SIZE(ase_ephy_grps)},
{"dfe", ARRAY_AND_SIZE(ase_dfe_grps)},
};
+/* --------- danube related code --------- */
+#define DANUBE_MAX_PIN 32
+
+static const struct ltq_mfp_pin danube_mfp[] = {
+ /* pin f0 f1 f2 f3 */
+ MFP_XWAY(GPIO0, GPIO, EXIN, SDIO, TDM),
+ MFP_XWAY(GPIO1, GPIO, EXIN, CBUS, MII),
+ MFP_XWAY(GPIO2, GPIO, CGU, EXIN, MII),
+ MFP_XWAY(GPIO3, GPIO, CGU, SDIO, PCI),
+ MFP_XWAY(GPIO4, GPIO, STP, DFE, ASC),
+ MFP_XWAY(GPIO5, GPIO, STP, MII, DFE),
+ MFP_XWAY(GPIO6, GPIO, STP, GPT, ASC),
+ MFP_XWAY(GPIO7, GPIO, CGU, CBUS, MII),
+ MFP_XWAY(GPIO8, GPIO, CGU, NMI, MII),
+ MFP_XWAY(GPIO9, GPIO, ASC, SPI, MII),
+ MFP_XWAY(GPIO10, GPIO, ASC, SPI, MII),
+ MFP_XWAY(GPIO11, GPIO, ASC, CBUS, SPI),
+ MFP_XWAY(GPIO12, GPIO, ASC, CBUS, MCD),
+ MFP_XWAY(GPIO13, GPIO, EBU, SPI, MII),
+ MFP_XWAY(GPIO14, GPIO, CGU, CBUS, MII),
+ MFP_XWAY(GPIO15, GPIO, SPI, SDIO, JTAG),
+ MFP_XWAY(GPIO16, GPIO, SPI, SDIO, JTAG),
+ MFP_XWAY(GPIO17, GPIO, SPI, SDIO, JTAG),
+ MFP_XWAY(GPIO18, GPIO, SPI, SDIO, JTAG),
+ MFP_XWAY(GPIO19, GPIO, PCI, SDIO, MII),
+ MFP_XWAY(GPIO20, GPIO, JTAG, SDIO, MII),
+ MFP_XWAY(GPIO21, GPIO, PCI, EBU, GPT),
+ MFP_XWAY(GPIO22, GPIO, SPI, MCD, MII),
+ MFP_XWAY(GPIO23, GPIO, EBU, PCI, STP),
+ MFP_XWAY(GPIO24, GPIO, EBU, TDM, PCI),
+ MFP_XWAY(GPIO25, GPIO, TDM, SDIO, ASC),
+ MFP_XWAY(GPIO26, GPIO, EBU, TDM, SDIO),
+ MFP_XWAY(GPIO27, GPIO, TDM, SDIO, ASC),
+ MFP_XWAY(GPIO28, GPIO, GPT, MII, SDIO),
+ MFP_XWAY(GPIO29, GPIO, PCI, CBUS, MII),
+ MFP_XWAY(GPIO30, GPIO, PCI, CBUS, MII),
+ MFP_XWAY(GPIO31, GPIO, EBU, PCI, MII),
+};
+
+static const unsigned danube_exin_pin_map[] = {GPIO0, GPIO1, GPIO2};
+
+static const unsigned danube_pins_exin0[] = {GPIO0};
+static const unsigned danube_pins_exin1[] = {GPIO1};
+static const unsigned danube_pins_exin2[] = {GPIO2};
+
+static const unsigned danube_pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO18, GPIO20};
+static const unsigned danube_pins_asc0[] = {GPIO11, GPIO12};
+static const unsigned danube_pins_asc0_cts_rts[] = {GPIO9, GPIO10};
+static const unsigned danube_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned danube_pins_nmi[] = {GPIO8};
+
+static const unsigned danube_pins_dfe_led0[] = {GPIO4};
+static const unsigned danube_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned danube_pins_ebu_a24[] = {GPIO13};
+static const unsigned danube_pins_ebu_clk[] = {GPIO21};
+static const unsigned danube_pins_ebu_cs1[] = {GPIO23};
+static const unsigned danube_pins_ebu_a23[] = {GPIO24};
+static const unsigned danube_pins_ebu_wait[] = {GPIO26};
+static const unsigned danube_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned danube_pins_nand_ale[] = {GPIO13};
+static const unsigned danube_pins_nand_cs1[] = {GPIO23};
+static const unsigned danube_pins_nand_cle[] = {GPIO24};
+
+static const unsigned danube_pins_spi[] = {GPIO16, GPIO17, GPIO18}; /* DEPRECATED */
+static const unsigned danube_pins_spi_di[] = {GPIO16};
+static const unsigned danube_pins_spi_do[] = {GPIO17};
+static const unsigned danube_pins_spi_clk[] = {GPIO18};
+static const unsigned danube_pins_spi_cs1[] = {GPIO15};
+static const unsigned danube_pins_spi_cs2[] = {GPIO21};
+static const unsigned danube_pins_spi_cs3[] = {GPIO13};
+static const unsigned danube_pins_spi_cs4[] = {GPIO10};
+static const unsigned danube_pins_spi_cs5[] = {GPIO9};
+static const unsigned danube_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned danube_pins_gpt1[] = {GPIO28};
+static const unsigned danube_pins_gpt2[] = {GPIO21};
+static const unsigned danube_pins_gpt3[] = {GPIO6};
+
+static const unsigned danube_pins_clkout0[] = {GPIO8};
+static const unsigned danube_pins_clkout1[] = {GPIO7};
+static const unsigned danube_pins_clkout2[] = {GPIO3};
+static const unsigned danube_pins_clkout3[] = {GPIO2};
+
+static const unsigned danube_pins_pci_gnt1[] = {GPIO30};
+static const unsigned danube_pins_pci_gnt2[] = {GPIO23};
+static const unsigned danube_pins_pci_gnt3[] = {GPIO19};
+static const unsigned danube_pins_pci_req1[] = {GPIO29};
+static const unsigned danube_pins_pci_req2[] = {GPIO31};
+static const unsigned danube_pins_pci_req3[] = {GPIO3};
+
+static const struct ltq_pin_group danube_grps[] = {
+ GRP_MUX("exin0", EXIN, danube_pins_exin0),
+ GRP_MUX("exin1", EXIN, danube_pins_exin1),
+ GRP_MUX("exin2", EXIN, danube_pins_exin2),
+ GRP_MUX("jtag", JTAG, danube_pins_jtag),
+ GRP_MUX("ebu a23", EBU, danube_pins_ebu_a23),
+ GRP_MUX("ebu a24", EBU, danube_pins_ebu_a24),
+ GRP_MUX("ebu a25", EBU, danube_pins_ebu_a25),
+ GRP_MUX("ebu clk", EBU, danube_pins_ebu_clk),
+ GRP_MUX("ebu cs1", EBU, danube_pins_ebu_cs1),
+ GRP_MUX("ebu wait", EBU, danube_pins_ebu_wait),
+ GRP_MUX("nand ale", EBU, danube_pins_nand_ale),
+ GRP_MUX("nand cs1", EBU, danube_pins_nand_cs1),
+ GRP_MUX("nand cle", EBU, danube_pins_nand_cle),
+ GRP_MUX("spi", SPI, danube_pins_spi), /* DEPRECATED */
+ GRP_MUX("spi_di", SPI, danube_pins_spi_di),
+ GRP_MUX("spi_do", SPI, danube_pins_spi_do),
+ GRP_MUX("spi_clk", SPI, danube_pins_spi_clk),
+ GRP_MUX("spi_cs1", SPI, danube_pins_spi_cs1),
+ GRP_MUX("spi_cs2", SPI, danube_pins_spi_cs2),
+ GRP_MUX("spi_cs3", SPI, danube_pins_spi_cs3),
+ GRP_MUX("spi_cs4", SPI, danube_pins_spi_cs4),
+ GRP_MUX("spi_cs5", SPI, danube_pins_spi_cs5),
+ GRP_MUX("spi_cs6", SPI, danube_pins_spi_cs6),
+ GRP_MUX("asc0", ASC, danube_pins_asc0),
+ GRP_MUX("asc0 cts rts", ASC, danube_pins_asc0_cts_rts),
+ GRP_MUX("stp", STP, danube_pins_stp),
+ GRP_MUX("nmi", NMI, danube_pins_nmi),
+ GRP_MUX("gpt1", GPT, danube_pins_gpt1),
+ GRP_MUX("gpt2", GPT, danube_pins_gpt2),
+ GRP_MUX("gpt3", GPT, danube_pins_gpt3),
+ GRP_MUX("clkout0", CGU, danube_pins_clkout0),
+ GRP_MUX("clkout1", CGU, danube_pins_clkout1),
+ GRP_MUX("clkout2", CGU, danube_pins_clkout2),
+ GRP_MUX("clkout3", CGU, danube_pins_clkout3),
+ GRP_MUX("gnt1", PCI, danube_pins_pci_gnt1),
+ GRP_MUX("gnt2", PCI, danube_pins_pci_gnt2),
+ GRP_MUX("gnt3", PCI, danube_pins_pci_gnt3),
+ GRP_MUX("req1", PCI, danube_pins_pci_req1),
+ GRP_MUX("req2", PCI, danube_pins_pci_req2),
+ GRP_MUX("req3", PCI, danube_pins_pci_req3),
+ GRP_MUX("dfe led0", DFE, danube_pins_dfe_led0),
+ GRP_MUX("dfe led1", DFE, danube_pins_dfe_led1),
+};
+
+static const char * const danube_pci_grps[] = {"gnt1", "gnt2",
+ "gnt3", "req1",
+ "req2", "req3"};
+static const char * const danube_spi_grps[] = {"spi", /* DEPRECATED */
+ "spi_di", "spi_do",
+ "spi_clk", "spi_cs1",
+ "spi_cs2", "spi_cs3",
+ "spi_cs4", "spi_cs5",
+ "spi_cs6"};
+static const char * const danube_cgu_grps[] = {"clkout0", "clkout1",
+ "clkout2", "clkout3"};
+static const char * const danube_ebu_grps[] = {"ebu a23", "ebu a24",
+ "ebu a25", "ebu cs1",
+ "ebu wait", "ebu clk",
+ "nand ale", "nand cs1",
+ "nand cle"};
+static const char * const danube_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const danube_exin_grps[] = {"exin0", "exin1", "exin2"};
+static const char * const danube_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const danube_asc_grps[] = {"asc0", "asc0 cts rts"};
+static const char * const danube_jtag_grps[] = {"jtag"};
+static const char * const danube_stp_grps[] = {"stp"};
+static const char * const danube_nmi_grps[] = {"nmi"};
+
+static const struct ltq_pmx_func danube_funcs[] = {
+ {"spi", ARRAY_AND_SIZE(danube_spi_grps)},
+ {"asc", ARRAY_AND_SIZE(danube_asc_grps)},
+ {"cgu", ARRAY_AND_SIZE(danube_cgu_grps)},
+ {"jtag", ARRAY_AND_SIZE(danube_jtag_grps)},
+ {"exin", ARRAY_AND_SIZE(danube_exin_grps)},
+ {"stp", ARRAY_AND_SIZE(danube_stp_grps)},
+ {"gpt", ARRAY_AND_SIZE(danube_gpt_grps)},
+ {"nmi", ARRAY_AND_SIZE(danube_nmi_grps)},
+ {"pci", ARRAY_AND_SIZE(danube_pci_grps)},
+ {"ebu", ARRAY_AND_SIZE(danube_ebu_grps)},
+ {"dfe", ARRAY_AND_SIZE(danube_dfe_grps)},
+};
+
+/* --------- xrx100 related code --------- */
+#define XRX100_MAX_PIN 56
+
+static const struct ltq_mfp_pin xrx100_mfp[] = {
+ /* pin f0 f1 f2 f3 */
+ MFP_XWAY(GPIO0, GPIO, EXIN, SDIO, TDM),
+ MFP_XWAY(GPIO1, GPIO, EXIN, CBUS, SIN),
+ MFP_XWAY(GPIO2, GPIO, CGU, EXIN, NONE),
+ MFP_XWAY(GPIO3, GPIO, CGU, SDIO, PCI),
+ MFP_XWAY(GPIO4, GPIO, STP, DFE, ASC),
+ MFP_XWAY(GPIO5, GPIO, STP, NONE, DFE),
+ MFP_XWAY(GPIO6, GPIO, STP, GPT, ASC),
+ MFP_XWAY(GPIO7, GPIO, CGU, CBUS, NONE),
+ MFP_XWAY(GPIO8, GPIO, CGU, NMI, NONE),
+ MFP_XWAY(GPIO9, GPIO, ASC, SPI, EXIN),
+ MFP_XWAY(GPIO10, GPIO, ASC, SPI, EXIN),
+ MFP_XWAY(GPIO11, GPIO, ASC, CBUS, SPI),
+ MFP_XWAY(GPIO12, GPIO, ASC, CBUS, MCD),
+ MFP_XWAY(GPIO13, GPIO, EBU, SPI, NONE),
+ MFP_XWAY(GPIO14, GPIO, CGU, NONE, NONE),
+ MFP_XWAY(GPIO15, GPIO, SPI, SDIO, MCD),
+ MFP_XWAY(GPIO16, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO17, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO18, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO19, GPIO, PCI, SDIO, CGU),
+ MFP_XWAY(GPIO20, GPIO, NONE, SDIO, EBU),
+ MFP_XWAY(GPIO21, GPIO, PCI, EBU, GPT),
+ MFP_XWAY(GPIO22, GPIO, SPI, NONE, EBU),
+ MFP_XWAY(GPIO23, GPIO, EBU, PCI, STP),
+ MFP_XWAY(GPIO24, GPIO, EBU, TDM, PCI),
+ MFP_XWAY(GPIO25, GPIO, TDM, SDIO, ASC),
+ MFP_XWAY(GPIO26, GPIO, EBU, TDM, SDIO),
+ MFP_XWAY(GPIO27, GPIO, TDM, SDIO, ASC),
+ MFP_XWAY(GPIO28, GPIO, GPT, NONE, SDIO),
+ MFP_XWAY(GPIO29, GPIO, PCI, CBUS, NONE),
+ MFP_XWAY(GPIO30, GPIO, PCI, CBUS, NONE),
+ MFP_XWAY(GPIO31, GPIO, EBU, PCI, NONE),
+ MFP_XWAY(GPIO32, GPIO, MII, NONE, EBU),
+ MFP_XWAY(GPIO33, GPIO, MII, NONE, EBU),
+ MFP_XWAY(GPIO34, GPIO, SIN, SSI, NONE),
+ MFP_XWAY(GPIO35, GPIO, SIN, SSI, NONE),
+ MFP_XWAY(GPIO36, GPIO, SIN, SSI, NONE),
+ MFP_XWAY(GPIO37, GPIO, PCI, NONE, NONE),
+ MFP_XWAY(GPIO38, GPIO, PCI, NONE, NONE),
+ MFP_XWAY(GPIO39, GPIO, NONE, EXIN, NONE),
+ MFP_XWAY(GPIO40, GPIO, MII, TDM, NONE),
+ MFP_XWAY(GPIO41, GPIO, MII, TDM, NONE),
+ MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO44, GPIO, MII, SIN, NONE),
+ MFP_XWAY(GPIO45, GPIO, MII, NONE, SIN),
+ MFP_XWAY(GPIO46, GPIO, MII, NONE, EXIN),
+ MFP_XWAY(GPIO47, GPIO, MII, NONE, SIN),
+ MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO50, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO51, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO52, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO53, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO54, GPIO, NONE, NONE, NONE),
+ MFP_XWAY(GPIO55, GPIO, NONE, NONE, NONE),
+};
+
+static const unsigned xrx100_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO10, GPIO9};
+
+static const unsigned xrx100_pins_exin0[] = {GPIO0};
+static const unsigned xrx100_pins_exin1[] = {GPIO1};
+static const unsigned xrx100_pins_exin2[] = {GPIO2};
+static const unsigned xrx100_pins_exin3[] = {GPIO39};
+static const unsigned xrx100_pins_exin4[] = {GPIO10};
+static const unsigned xrx100_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx100_pins_asc0[] = {GPIO11, GPIO12};
+static const unsigned xrx100_pins_asc0_cts_rts[] = {GPIO9, GPIO10};
+static const unsigned xrx100_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx100_pins_nmi[] = {GPIO8};
+static const unsigned xrx100_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx100_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx100_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx100_pins_ebu_a24[] = {GPIO13};
+static const unsigned xrx100_pins_ebu_clk[] = {GPIO21};
+static const unsigned xrx100_pins_ebu_cs1[] = {GPIO23};
+static const unsigned xrx100_pins_ebu_a23[] = {GPIO24};
+static const unsigned xrx100_pins_ebu_wait[] = {GPIO26};
+static const unsigned xrx100_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned xrx100_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx100_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx100_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx100_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx100_pins_nand_rd[] = {GPIO49};
+
+static const unsigned xrx100_pins_spi_di[] = {GPIO16};
+static const unsigned xrx100_pins_spi_do[] = {GPIO17};
+static const unsigned xrx100_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx100_pins_spi_cs1[] = {GPIO15};
+static const unsigned xrx100_pins_spi_cs2[] = {GPIO22};
+static const unsigned xrx100_pins_spi_cs3[] = {GPIO13};
+static const unsigned xrx100_pins_spi_cs4[] = {GPIO10};
+static const unsigned xrx100_pins_spi_cs5[] = {GPIO9};
+static const unsigned xrx100_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned xrx100_pins_gpt1[] = {GPIO28};
+static const unsigned xrx100_pins_gpt2[] = {GPIO21};
+static const unsigned xrx100_pins_gpt3[] = {GPIO6};
+
+static const unsigned xrx100_pins_clkout0[] = {GPIO8};
+static const unsigned xrx100_pins_clkout1[] = {GPIO7};
+static const unsigned xrx100_pins_clkout2[] = {GPIO3};
+static const unsigned xrx100_pins_clkout3[] = {GPIO2};
+
+static const unsigned xrx100_pins_pci_gnt1[] = {GPIO30};
+static const unsigned xrx100_pins_pci_gnt2[] = {GPIO23};
+static const unsigned xrx100_pins_pci_gnt3[] = {GPIO19};
+static const unsigned xrx100_pins_pci_gnt4[] = {GPIO38};
+static const unsigned xrx100_pins_pci_req1[] = {GPIO29};
+static const unsigned xrx100_pins_pci_req2[] = {GPIO31};
+static const unsigned xrx100_pins_pci_req3[] = {GPIO3};
+static const unsigned xrx100_pins_pci_req4[] = {GPIO37};
+
+static const struct ltq_pin_group xrx100_grps[] = {
+ GRP_MUX("exin0", EXIN, xrx100_pins_exin0),
+ GRP_MUX("exin1", EXIN, xrx100_pins_exin1),
+ GRP_MUX("exin2", EXIN, xrx100_pins_exin2),
+ GRP_MUX("exin3", EXIN, xrx100_pins_exin3),
+ GRP_MUX("exin4", EXIN, xrx100_pins_exin4),
+ GRP_MUX("exin5", EXIN, xrx100_pins_exin5),
+ GRP_MUX("ebu a23", EBU, xrx100_pins_ebu_a23),
+ GRP_MUX("ebu a24", EBU, xrx100_pins_ebu_a24),
+ GRP_MUX("ebu a25", EBU, xrx100_pins_ebu_a25),
+ GRP_MUX("ebu clk", EBU, xrx100_pins_ebu_clk),
+ GRP_MUX("ebu cs1", EBU, xrx100_pins_ebu_cs1),
+ GRP_MUX("ebu wait", EBU, xrx100_pins_ebu_wait),
+ GRP_MUX("nand ale", EBU, xrx100_pins_nand_ale),
+ GRP_MUX("nand cs1", EBU, xrx100_pins_nand_cs1),
+ GRP_MUX("nand cle", EBU, xrx100_pins_nand_cle),
+ GRP_MUX("nand rdy", EBU, xrx100_pins_nand_rdy),
+ GRP_MUX("nand rd", EBU, xrx100_pins_nand_rd),
+ GRP_MUX("spi_di", SPI, xrx100_pins_spi_di),
+ GRP_MUX("spi_do", SPI, xrx100_pins_spi_do),
+ GRP_MUX("spi_clk", SPI, xrx100_pins_spi_clk),
+ GRP_MUX("spi_cs1", SPI, xrx100_pins_spi_cs1),
+ GRP_MUX("spi_cs2", SPI, xrx100_pins_spi_cs2),
+ GRP_MUX("spi_cs3", SPI, xrx100_pins_spi_cs3),
+ GRP_MUX("spi_cs4", SPI, xrx100_pins_spi_cs4),
+ GRP_MUX("spi_cs5", SPI, xrx100_pins_spi_cs5),
+ GRP_MUX("spi_cs6", SPI, xrx100_pins_spi_cs6),
+ GRP_MUX("asc0", ASC, xrx100_pins_asc0),
+ GRP_MUX("asc0 cts rts", ASC, xrx100_pins_asc0_cts_rts),
+ GRP_MUX("stp", STP, xrx100_pins_stp),
+ GRP_MUX("nmi", NMI, xrx100_pins_nmi),
+ GRP_MUX("gpt1", GPT, xrx100_pins_gpt1),
+ GRP_MUX("gpt2", GPT, xrx100_pins_gpt2),
+ GRP_MUX("gpt3", GPT, xrx100_pins_gpt3),
+ GRP_MUX("clkout0", CGU, xrx100_pins_clkout0),
+ GRP_MUX("clkout1", CGU, xrx100_pins_clkout1),
+ GRP_MUX("clkout2", CGU, xrx100_pins_clkout2),
+ GRP_MUX("clkout3", CGU, xrx100_pins_clkout3),
+ GRP_MUX("gnt1", PCI, xrx100_pins_pci_gnt1),
+ GRP_MUX("gnt2", PCI, xrx100_pins_pci_gnt2),
+ GRP_MUX("gnt3", PCI, xrx100_pins_pci_gnt3),
+ GRP_MUX("gnt4", PCI, xrx100_pins_pci_gnt4),
+ GRP_MUX("req1", PCI, xrx100_pins_pci_req1),
+ GRP_MUX("req2", PCI, xrx100_pins_pci_req2),
+ GRP_MUX("req3", PCI, xrx100_pins_pci_req3),
+ GRP_MUX("req4", PCI, xrx100_pins_pci_req4),
+ GRP_MUX("mdio", MDIO, xrx100_pins_mdio),
+ GRP_MUX("dfe led0", DFE, xrx100_pins_dfe_led0),
+ GRP_MUX("dfe led1", DFE, xrx100_pins_dfe_led1),
+};
+
+static const char * const xrx100_pci_grps[] = {"gnt1", "gnt2",
+ "gnt3", "gnt4",
+ "req1", "req2",
+ "req3", "req4"};
+static const char * const xrx100_spi_grps[] = {"spi_di", "spi_do",
+ "spi_clk", "spi_cs1",
+ "spi_cs2", "spi_cs3",
+ "spi_cs4", "spi_cs5",
+ "spi_cs6"};
+static const char * const xrx100_cgu_grps[] = {"clkout0", "clkout1",
+ "clkout2", "clkout3"};
+static const char * const xrx100_ebu_grps[] = {"ebu a23", "ebu a24",
+ "ebu a25", "ebu cs1",
+ "ebu wait", "ebu clk",
+ "nand ale", "nand cs1",
+ "nand cle", "nand rdy",
+ "nand rd"};
+static const char * const xrx100_exin_grps[] = {"exin0", "exin1", "exin2",
+ "exin3", "exin4", "exin5"};
+static const char * const xrx100_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const xrx100_asc_grps[] = {"asc0", "asc0 cts rts"};
+static const char * const xrx100_stp_grps[] = {"stp"};
+static const char * const xrx100_nmi_grps[] = {"nmi"};
+static const char * const xrx100_mdio_grps[] = {"mdio"};
+static const char * const xrx100_dfe_grps[] = {"dfe led0", "dfe led1"};
+
+static const struct ltq_pmx_func xrx100_funcs[] = {
+ {"spi", ARRAY_AND_SIZE(xrx100_spi_grps)},
+ {"asc", ARRAY_AND_SIZE(xrx100_asc_grps)},
+ {"cgu", ARRAY_AND_SIZE(xrx100_cgu_grps)},
+ {"exin", ARRAY_AND_SIZE(xrx100_exin_grps)},
+ {"stp", ARRAY_AND_SIZE(xrx100_stp_grps)},
+ {"gpt", ARRAY_AND_SIZE(xrx100_gpt_grps)},
+ {"nmi", ARRAY_AND_SIZE(xrx100_nmi_grps)},
+ {"pci", ARRAY_AND_SIZE(xrx100_pci_grps)},
+ {"ebu", ARRAY_AND_SIZE(xrx100_ebu_grps)},
+ {"mdio", ARRAY_AND_SIZE(xrx100_mdio_grps)},
+ {"dfe", ARRAY_AND_SIZE(xrx100_dfe_grps)},
+};
+
+/* --------- xrx200 related code --------- */
+#define XRX200_MAX_PIN 50
+
+static const struct ltq_mfp_pin xrx200_mfp[] = {
+ /* pin f0 f1 f2 f3 */
+ MFP_XWAY(GPIO0, GPIO, EXIN, SDIO, TDM),
+ MFP_XWAY(GPIO1, GPIO, EXIN, CBUS, SIN),
+ MFP_XWAY(GPIO2, GPIO, CGU, EXIN, GPHY),
+ MFP_XWAY(GPIO3, GPIO, CGU, SDIO, PCI),
+ MFP_XWAY(GPIO4, GPIO, STP, DFE, USIF),
+ MFP_XWAY(GPIO5, GPIO, STP, GPHY, DFE),
+ MFP_XWAY(GPIO6, GPIO, STP, GPT, USIF),
+ MFP_XWAY(GPIO7, GPIO, CGU, CBUS, GPHY),
+ MFP_XWAY(GPIO8, GPIO, CGU, NMI, NONE),
+ MFP_XWAY(GPIO9, GPIO, USIF, SPI, EXIN),
+ MFP_XWAY(GPIO10, GPIO, USIF, SPI, EXIN),
+ MFP_XWAY(GPIO11, GPIO, USIF, CBUS, SPI),
+ MFP_XWAY(GPIO12, GPIO, USIF, CBUS, MCD),
+ MFP_XWAY(GPIO13, GPIO, EBU, SPI, NONE),
+ MFP_XWAY(GPIO14, GPIO, CGU, CBUS, USIF),
+ MFP_XWAY(GPIO15, GPIO, SPI, SDIO, MCD),
+ MFP_XWAY(GPIO16, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO17, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO18, GPIO, SPI, SDIO, NONE),
+ MFP_XWAY(GPIO19, GPIO, PCI, SDIO, CGU),
+ MFP_XWAY(GPIO20, GPIO, NONE, SDIO, EBU),
+ MFP_XWAY(GPIO21, GPIO, PCI, EBU, GPT),
+ MFP_XWAY(GPIO22, GPIO, SPI, CGU, EBU),
+ MFP_XWAY(GPIO23, GPIO, EBU, PCI, STP),
+ MFP_XWAY(GPIO24, GPIO, EBU, TDM, PCI),
+ MFP_XWAY(GPIO25, GPIO, TDM, SDIO, USIF),
+ MFP_XWAY(GPIO26, GPIO, EBU, TDM, SDIO),
+ MFP_XWAY(GPIO27, GPIO, TDM, SDIO, USIF),
+ MFP_XWAY(GPIO28, GPIO, GPT, PCI, SDIO),
+ MFP_XWAY(GPIO29, GPIO, PCI, CBUS, EXIN),
+ MFP_XWAY(GPIO30, GPIO, PCI, CBUS, NONE),
+ MFP_XWAY(GPIO31, GPIO, EBU, PCI, NONE),
+ MFP_XWAY(GPIO32, GPIO, MII, NONE, EBU),
+ MFP_XWAY(GPIO33, GPIO, MII, NONE, EBU),
+ MFP_XWAY(GPIO34, GPIO, SIN, SSI, NONE),
+ MFP_XWAY(GPIO35, GPIO, SIN, SSI, NONE),
+ MFP_XWAY(GPIO36, GPIO, SIN, SSI, EXIN),
+ MFP_XWAY(GPIO37, GPIO, USIF, NONE, PCI),
+ MFP_XWAY(GPIO38, GPIO, PCI, USIF, NONE),
+ MFP_XWAY(GPIO39, GPIO, USIF, EXIN, NONE),
+ MFP_XWAY(GPIO40, GPIO, MII, TDM, NONE),
+ MFP_XWAY(GPIO41, GPIO, MII, TDM, NONE),
+ MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO44, GPIO, MII, SIN, GPHY),
+ MFP_XWAY(GPIO45, GPIO, MII, GPHY, SIN),
+ MFP_XWAY(GPIO46, GPIO, MII, NONE, EXIN),
+ MFP_XWAY(GPIO47, GPIO, MII, GPHY, SIN),
+ MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE),
+};
+
+static const unsigned xrx200_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO10, GPIO9};
+
+static const unsigned xrx200_pins_exin0[] = {GPIO0};
+static const unsigned xrx200_pins_exin1[] = {GPIO1};
+static const unsigned xrx200_pins_exin2[] = {GPIO2};
+static const unsigned xrx200_pins_exin3[] = {GPIO39};
+static const unsigned xrx200_pins_exin4[] = {GPIO10};
+static const unsigned xrx200_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx200_pins_usif_uart_rx[] = {GPIO11};
+static const unsigned xrx200_pins_usif_uart_tx[] = {GPIO12};
+static const unsigned xrx200_pins_usif_uart_rts[] = {GPIO9};
+static const unsigned xrx200_pins_usif_uart_cts[] = {GPIO10};
+static const unsigned xrx200_pins_usif_uart_dtr[] = {GPIO4};
+static const unsigned xrx200_pins_usif_uart_dsr[] = {GPIO6};
+static const unsigned xrx200_pins_usif_uart_dcd[] = {GPIO25};
+static const unsigned xrx200_pins_usif_uart_ri[] = {GPIO27};
+
+static const unsigned xrx200_pins_usif_spi_di[] = {GPIO11};
+static const unsigned xrx200_pins_usif_spi_do[] = {GPIO12};
+static const unsigned xrx200_pins_usif_spi_clk[] = {GPIO38};
+static const unsigned xrx200_pins_usif_spi_cs0[] = {GPIO37};
+static const unsigned xrx200_pins_usif_spi_cs1[] = {GPIO39};
+static const unsigned xrx200_pins_usif_spi_cs2[] = {GPIO14};
+
+static const unsigned xrx200_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx200_pins_nmi[] = {GPIO8};
+static const unsigned xrx200_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx200_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx200_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx200_pins_gphy0_led0[] = {GPIO5};
+static const unsigned xrx200_pins_gphy0_led1[] = {GPIO7};
+static const unsigned xrx200_pins_gphy0_led2[] = {GPIO2};
+static const unsigned xrx200_pins_gphy1_led0[] = {GPIO44};
+static const unsigned xrx200_pins_gphy1_led1[] = {GPIO45};
+static const unsigned xrx200_pins_gphy1_led2[] = {GPIO47};
+
+static const unsigned xrx200_pins_ebu_a24[] = {GPIO13};
+static const unsigned xrx200_pins_ebu_clk[] = {GPIO21};
+static const unsigned xrx200_pins_ebu_cs1[] = {GPIO23};
+static const unsigned xrx200_pins_ebu_a23[] = {GPIO24};
+static const unsigned xrx200_pins_ebu_wait[] = {GPIO26};
+static const unsigned xrx200_pins_ebu_a25[] = {GPIO31};
+
+static const unsigned xrx200_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx200_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx200_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx200_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx200_pins_nand_rd[] = {GPIO49};
+
+static const unsigned xrx200_pins_spi_di[] = {GPIO16};
+static const unsigned xrx200_pins_spi_do[] = {GPIO17};
+static const unsigned xrx200_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx200_pins_spi_cs1[] = {GPIO15};
+static const unsigned xrx200_pins_spi_cs2[] = {GPIO22};
+static const unsigned xrx200_pins_spi_cs3[] = {GPIO13};
+static const unsigned xrx200_pins_spi_cs4[] = {GPIO10};
+static const unsigned xrx200_pins_spi_cs5[] = {GPIO9};
+static const unsigned xrx200_pins_spi_cs6[] = {GPIO11};
+
+static const unsigned xrx200_pins_gpt1[] = {GPIO28};
+static const unsigned xrx200_pins_gpt2[] = {GPIO21};
+static const unsigned xrx200_pins_gpt3[] = {GPIO6};
+
+static const unsigned xrx200_pins_clkout0[] = {GPIO8};
+static const unsigned xrx200_pins_clkout1[] = {GPIO7};
+static const unsigned xrx200_pins_clkout2[] = {GPIO3};
+static const unsigned xrx200_pins_clkout3[] = {GPIO2};
+
+static const unsigned xrx200_pins_pci_gnt1[] = {GPIO28};
+static const unsigned xrx200_pins_pci_gnt2[] = {GPIO23};
+static const unsigned xrx200_pins_pci_gnt3[] = {GPIO19};
+static const unsigned xrx200_pins_pci_gnt4[] = {GPIO38};
+static const unsigned xrx200_pins_pci_req1[] = {GPIO29};
+static const unsigned xrx200_pins_pci_req2[] = {GPIO31};
+static const unsigned xrx200_pins_pci_req3[] = {GPIO3};
+static const unsigned xrx200_pins_pci_req4[] = {GPIO37};
+
+static const struct ltq_pin_group xrx200_grps[] = {
+ GRP_MUX("exin0", EXIN, xrx200_pins_exin0),
+ GRP_MUX("exin1", EXIN, xrx200_pins_exin1),
+ GRP_MUX("exin2", EXIN, xrx200_pins_exin2),
+ GRP_MUX("exin3", EXIN, xrx200_pins_exin3),
+ GRP_MUX("exin4", EXIN, xrx200_pins_exin4),
+ GRP_MUX("exin5", EXIN, xrx200_pins_exin5),
+ GRP_MUX("ebu a23", EBU, xrx200_pins_ebu_a23),
+ GRP_MUX("ebu a24", EBU, xrx200_pins_ebu_a24),
+ GRP_MUX("ebu a25", EBU, xrx200_pins_ebu_a25),
+ GRP_MUX("ebu clk", EBU, xrx200_pins_ebu_clk),
+ GRP_MUX("ebu cs1", EBU, xrx200_pins_ebu_cs1),
+ GRP_MUX("ebu wait", EBU, xrx200_pins_ebu_wait),
+ GRP_MUX("nand ale", EBU, xrx200_pins_nand_ale),
+ GRP_MUX("nand cs1", EBU, xrx200_pins_nand_cs1),
+ GRP_MUX("nand cle", EBU, xrx200_pins_nand_cle),
+ GRP_MUX("nand rdy", EBU, xrx200_pins_nand_rdy),
+ GRP_MUX("nand rd", EBU, xrx200_pins_nand_rd),
+ GRP_MUX("spi_di", SPI, xrx200_pins_spi_di),
+ GRP_MUX("spi_do", SPI, xrx200_pins_spi_do),
+ GRP_MUX("spi_clk", SPI, xrx200_pins_spi_clk),
+ GRP_MUX("spi_cs1", SPI, xrx200_pins_spi_cs1),
+ GRP_MUX("spi_cs2", SPI, xrx200_pins_spi_cs2),
+ GRP_MUX("spi_cs3", SPI, xrx200_pins_spi_cs3),
+ GRP_MUX("spi_cs4", SPI, xrx200_pins_spi_cs4),
+ GRP_MUX("spi_cs5", SPI, xrx200_pins_spi_cs5),
+ GRP_MUX("spi_cs6", SPI, xrx200_pins_spi_cs6),
+ GRP_MUX("usif uart_rx", USIF, xrx200_pins_usif_uart_rx),
+ GRP_MUX("usif uart_rx", USIF, xrx200_pins_usif_uart_tx),
+ GRP_MUX("usif uart_rts", USIF, xrx200_pins_usif_uart_rts),
+ GRP_MUX("usif uart_cts", USIF, xrx200_pins_usif_uart_cts),
+ GRP_MUX("usif uart_dtr", USIF, xrx200_pins_usif_uart_dtr),
+ GRP_MUX("usif uart_dsr", USIF, xrx200_pins_usif_uart_dsr),
+ GRP_MUX("usif uart_dcd", USIF, xrx200_pins_usif_uart_dcd),
+ GRP_MUX("usif uart_ri", USIF, xrx200_pins_usif_uart_ri),
+ GRP_MUX("usif spi_di", USIF, xrx200_pins_usif_spi_di),
+ GRP_MUX("usif spi_do", USIF, xrx200_pins_usif_spi_do),
+ GRP_MUX("usif spi_clk", USIF, xrx200_pins_usif_spi_clk),
+ GRP_MUX("usif spi_cs0", USIF, xrx200_pins_usif_spi_cs0),
+ GRP_MUX("usif spi_cs1", USIF, xrx200_pins_usif_spi_cs1),
+ GRP_MUX("usif spi_cs2", USIF, xrx200_pins_usif_spi_cs2),
+ GRP_MUX("stp", STP, xrx200_pins_stp),
+ GRP_MUX("nmi", NMI, xrx200_pins_nmi),
+ GRP_MUX("gpt1", GPT, xrx200_pins_gpt1),
+ GRP_MUX("gpt2", GPT, xrx200_pins_gpt2),
+ GRP_MUX("gpt3", GPT, xrx200_pins_gpt3),
+ GRP_MUX("clkout0", CGU, xrx200_pins_clkout0),
+ GRP_MUX("clkout1", CGU, xrx200_pins_clkout1),
+ GRP_MUX("clkout2", CGU, xrx200_pins_clkout2),
+ GRP_MUX("clkout3", CGU, xrx200_pins_clkout3),
+ GRP_MUX("gnt1", PCI, xrx200_pins_pci_gnt1),
+ GRP_MUX("gnt2", PCI, xrx200_pins_pci_gnt2),
+ GRP_MUX("gnt3", PCI, xrx200_pins_pci_gnt3),
+ GRP_MUX("gnt4", PCI, xrx200_pins_pci_gnt4),
+ GRP_MUX("req1", PCI, xrx200_pins_pci_req1),
+ GRP_MUX("req2", PCI, xrx200_pins_pci_req2),
+ GRP_MUX("req3", PCI, xrx200_pins_pci_req3),
+ GRP_MUX("req4", PCI, xrx200_pins_pci_req4),
+ GRP_MUX("mdio", MDIO, xrx200_pins_mdio),
+ GRP_MUX("dfe led0", DFE, xrx200_pins_dfe_led0),
+ GRP_MUX("dfe led1", DFE, xrx200_pins_dfe_led1),
+ GRP_MUX("gphy0 led0", GPHY, xrx200_pins_gphy0_led0),
+ GRP_MUX("gphy0 led1", GPHY, xrx200_pins_gphy0_led1),
+ GRP_MUX("gphy0 led2", GPHY, xrx200_pins_gphy0_led2),
+ GRP_MUX("gphy1 led0", GPHY, xrx200_pins_gphy1_led0),
+ GRP_MUX("gphy1 led1", GPHY, xrx200_pins_gphy1_led1),
+ GRP_MUX("gphy1 led2", GPHY, xrx200_pins_gphy1_led2),
+};
+
+static const char * const xrx200_pci_grps[] = {"gnt1", "gnt2",
+ "gnt3", "gnt4",
+ "req1", "req2",
+ "req3", "req4"};
+static const char * const xrx200_spi_grps[] = {"spi_di", "spi_do",
+ "spi_clk", "spi_cs1",
+ "spi_cs2", "spi_cs3",
+ "spi_cs4", "spi_cs5",
+ "spi_cs6"};
+static const char * const xrx200_cgu_grps[] = {"clkout0", "clkout1",
+ "clkout2", "clkout3"};
+static const char * const xrx200_ebu_grps[] = {"ebu a23", "ebu a24",
+ "ebu a25", "ebu cs1",
+ "ebu wait", "ebu clk",
+ "nand ale", "nand cs1",
+ "nand cle", "nand rdy",
+ "nand rd"};
+static const char * const xrx200_exin_grps[] = {"exin0", "exin1", "exin2",
+ "exin3", "exin4", "exin5"};
+static const char * const xrx200_gpt_grps[] = {"gpt1", "gpt2", "gpt3"};
+static const char * const xrx200_usif_grps[] = {"usif uart_rx", "usif uart_tx",
+ "usif uart_rts", "usif uart_cts",
+ "usif uart_dtr", "usif uart_dsr",
+ "usif uart_dcd", "usif uart_ri",
+ "usif spi_di", "usif spi_do",
+ "usif spi_clk", "usif spi_cs0",
+ "usif spi_cs1", "usif spi_cs2"};
+static const char * const xrx200_stp_grps[] = {"stp"};
+static const char * const xrx200_nmi_grps[] = {"nmi"};
+static const char * const xrx200_mdio_grps[] = {"mdio"};
+static const char * const xrx200_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const xrx200_gphy_grps[] = {"gphy0 led0", "gphy0 led1",
+ "gphy0 led2", "gphy1 led0",
+ "gphy1 led1", "gphy1 led2"};
+
+static const struct ltq_pmx_func xrx200_funcs[] = {
+ {"spi", ARRAY_AND_SIZE(xrx200_spi_grps)},
+ {"usif", ARRAY_AND_SIZE(xrx200_usif_grps)},
+ {"cgu", ARRAY_AND_SIZE(xrx200_cgu_grps)},
+ {"exin", ARRAY_AND_SIZE(xrx200_exin_grps)},
+ {"stp", ARRAY_AND_SIZE(xrx200_stp_grps)},
+ {"gpt", ARRAY_AND_SIZE(xrx200_gpt_grps)},
+ {"nmi", ARRAY_AND_SIZE(xrx200_nmi_grps)},
+ {"pci", ARRAY_AND_SIZE(xrx200_pci_grps)},
+ {"ebu", ARRAY_AND_SIZE(xrx200_ebu_grps)},
+ {"mdio", ARRAY_AND_SIZE(xrx200_mdio_grps)},
+ {"dfe", ARRAY_AND_SIZE(xrx200_dfe_grps)},
+ {"gphy", ARRAY_AND_SIZE(xrx200_gphy_grps)},
+};
+
+/* --------- xrx300 related code --------- */
+#define XRX300_MAX_PIN 64
+
+static const struct ltq_mfp_pin xrx300_mfp[] = {
+ /* pin f0 f1 f2 f3 */
+ MFP_XWAY(GPIO0, GPIO, EXIN, EPHY, NONE),
+ MFP_XWAY(GPIO1, GPIO, NONE, EXIN, NONE),
+ MFP_XWAY(GPIO2, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO3, GPIO, CGU, NONE, NONE),
+ MFP_XWAY(GPIO4, GPIO, STP, DFE, NONE),
+ MFP_XWAY(GPIO5, GPIO, STP, EPHY, DFE),
+ MFP_XWAY(GPIO6, GPIO, STP, NONE, NONE),
+ MFP_XWAY(GPIO7, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO8, GPIO, CGU, GPHY, EPHY),
+ MFP_XWAY(GPIO9, GPIO, WIFI, NONE, EXIN),
+ MFP_XWAY(GPIO10, GPIO, USIF, SPI, EXIN),
+ MFP_XWAY(GPIO11, GPIO, USIF, WIFI, SPI),
+ MFP_XWAY(GPIO12, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO13, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO14, GPIO, CGU, USIF, EPHY),
+ MFP_XWAY(GPIO15, GPIO, SPI, NONE, MCD),
+ MFP_XWAY(GPIO16, GPIO, SPI, EXIN, NONE),
+ MFP_XWAY(GPIO17, GPIO, SPI, NONE, NONE),
+ MFP_XWAY(GPIO18, GPIO, SPI, NONE, NONE),
+ MFP_XWAY(GPIO19, GPIO, USIF, NONE, EPHY),
+ MFP_XWAY(GPIO20, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO21, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO22, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO23, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO24, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO25, GPIO, TDM, NONE, NONE),
+ MFP_XWAY(GPIO26, GPIO, TDM, NONE, NONE),
+ MFP_XWAY(GPIO27, GPIO, TDM, NONE, NONE),
+ MFP_XWAY(GPIO28, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO29, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO30, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO31, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO32, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO33, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO34, GPIO, NONE, SSI, NONE),
+ MFP_XWAY(GPIO35, GPIO, NONE, SSI, NONE),
+ MFP_XWAY(GPIO36, GPIO, NONE, SSI, NONE),
+ MFP_XWAY(GPIO37, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO38, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO39, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO40, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO41, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE),
+ MFP_XWAY(GPIO44, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO45, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO46, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO47, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO50, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO51, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO52, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO53, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO54, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO55, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO56, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO57, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO58, GPIO, EBU, TDM, NONE),
+ MFP_XWAY(GPIO59, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO60, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO61, GPIO, EBU, NONE, NONE),
+ MFP_XWAY(GPIO62, NONE, NONE, NONE, NONE),
+ MFP_XWAY(GPIO63, NONE, NONE, NONE, NONE),
+};
+
+static const unsigned xrx300_exin_pin_map[] = {GPIO0, GPIO1, GPIO16, GPIO10, GPIO9};
+
+static const unsigned xrx300_pins_exin0[] = {GPIO0};
+static const unsigned xrx300_pins_exin1[] = {GPIO1};
+static const unsigned xrx300_pins_exin2[] = {GPIO16};
+/* EXIN3 is not available on xrX300 */
+static const unsigned xrx300_pins_exin4[] = {GPIO10};
+static const unsigned xrx300_pins_exin5[] = {GPIO9};
+
+static const unsigned xrx300_pins_usif_uart_rx[] = {GPIO11};
+static const unsigned xrx300_pins_usif_uart_tx[] = {GPIO10};
+
+static const unsigned xrx300_pins_usif_spi_di[] = {GPIO11};
+static const unsigned xrx300_pins_usif_spi_do[] = {GPIO10};
+static const unsigned xrx300_pins_usif_spi_clk[] = {GPIO19};
+static const unsigned xrx300_pins_usif_spi_cs0[] = {GPIO14};
+
+static const unsigned xrx300_pins_stp[] = {GPIO4, GPIO5, GPIO6};
+static const unsigned xrx300_pins_mdio[] = {GPIO42, GPIO43};
+
+static const unsigned xrx300_pins_dfe_led0[] = {GPIO4};
+static const unsigned xrx300_pins_dfe_led1[] = {GPIO5};
+
+static const unsigned xrx300_pins_ephy0_led0[] = {GPIO5};
+static const unsigned xrx300_pins_ephy0_led1[] = {GPIO8};
+static const unsigned xrx300_pins_ephy1_led0[] = {GPIO14};
+static const unsigned xrx300_pins_ephy1_led1[] = {GPIO19};
+
+static const unsigned xrx300_pins_nand_ale[] = {GPIO13};
+static const unsigned xrx300_pins_nand_cs1[] = {GPIO23};
+static const unsigned xrx300_pins_nand_cle[] = {GPIO24};
+static const unsigned xrx300_pins_nand_rdy[] = {GPIO48};
+static const unsigned xrx300_pins_nand_rd[] = {GPIO49};
+static const unsigned xrx300_pins_nand_d1[] = {GPIO50};
+static const unsigned xrx300_pins_nand_d0[] = {GPIO51};
+static const unsigned xrx300_pins_nand_d2[] = {GPIO52};
+static const unsigned xrx300_pins_nand_d7[] = {GPIO53};
+static const unsigned xrx300_pins_nand_d6[] = {GPIO54};
+static const unsigned xrx300_pins_nand_d5[] = {GPIO55};
+static const unsigned xrx300_pins_nand_d4[] = {GPIO56};
+static const unsigned xrx300_pins_nand_d3[] = {GPIO57};
+static const unsigned xrx300_pins_nand_cs0[] = {GPIO58};
+static const unsigned xrx300_pins_nand_wr[] = {GPIO59};
+static const unsigned xrx300_pins_nand_wp[] = {GPIO60};
+static const unsigned xrx300_pins_nand_se[] = {GPIO61};
+
+static const unsigned xrx300_pins_spi_di[] = {GPIO16};
+static const unsigned xrx300_pins_spi_do[] = {GPIO17};
+static const unsigned xrx300_pins_spi_clk[] = {GPIO18};
+static const unsigned xrx300_pins_spi_cs1[] = {GPIO15};
+/* SPI_CS2 is not available on xrX300 */
+/* SPI_CS3 is not available on xrX300 */
+static const unsigned xrx300_pins_spi_cs4[] = {GPIO10};
+/* SPI_CS5 is not available on xrX300 */
+static const unsigned xrx300_pins_spi_cs6[] = {GPIO11};
+
+/* CLKOUT0 is not available on xrX300 */
+/* CLKOUT1 is not available on xrX300 */
+static const unsigned xrx300_pins_clkout2[] = {GPIO3};
+
+static const struct ltq_pin_group xrx300_grps[] = {
+ GRP_MUX("exin0", EXIN, xrx300_pins_exin0),
+ GRP_MUX("exin1", EXIN, xrx300_pins_exin1),
+ GRP_MUX("exin2", EXIN, xrx300_pins_exin2),
+ GRP_MUX("exin4", EXIN, xrx300_pins_exin4),
+ GRP_MUX("exin5", EXIN, xrx300_pins_exin5),
+ GRP_MUX("nand ale", EBU, xrx300_pins_nand_ale),
+ GRP_MUX("nand cs1", EBU, xrx300_pins_nand_cs1),
+ GRP_MUX("nand cle", EBU, xrx300_pins_nand_cle),
+ GRP_MUX("nand rdy", EBU, xrx300_pins_nand_rdy),
+ GRP_MUX("nand rd", EBU, xrx300_pins_nand_rd),
+ GRP_MUX("nand d1", EBU, xrx300_pins_nand_d1),
+ GRP_MUX("nand d0", EBU, xrx300_pins_nand_d0),
+ GRP_MUX("nand d2", EBU, xrx300_pins_nand_d2),
+ GRP_MUX("nand d7", EBU, xrx300_pins_nand_d7),
+ GRP_MUX("nand d6", EBU, xrx300_pins_nand_d6),
+ GRP_MUX("nand d5", EBU, xrx300_pins_nand_d5),
+ GRP_MUX("nand d4", EBU, xrx300_pins_nand_d4),
+ GRP_MUX("nand d3", EBU, xrx300_pins_nand_d3),
+ GRP_MUX("nand cs0", EBU, xrx300_pins_nand_cs0),
+ GRP_MUX("nand wr", EBU, xrx300_pins_nand_wr),
+ GRP_MUX("nand wp", EBU, xrx300_pins_nand_wp),
+ GRP_MUX("nand se", EBU, xrx300_pins_nand_se),
+ GRP_MUX("spi_di", SPI, xrx300_pins_spi_di),
+ GRP_MUX("spi_do", SPI, xrx300_pins_spi_do),
+ GRP_MUX("spi_clk", SPI, xrx300_pins_spi_clk),
+ GRP_MUX("spi_cs1", SPI, xrx300_pins_spi_cs1),
+ GRP_MUX("spi_cs4", SPI, xrx300_pins_spi_cs4),
+ GRP_MUX("spi_cs6", SPI, xrx300_pins_spi_cs6),
+ GRP_MUX("usif uart_rx", USIF, xrx300_pins_usif_uart_rx),
+ GRP_MUX("usif uart_tx", USIF, xrx300_pins_usif_uart_tx),
+ GRP_MUX("usif spi_di", USIF, xrx300_pins_usif_spi_di),
+ GRP_MUX("usif spi_do", USIF, xrx300_pins_usif_spi_do),
+ GRP_MUX("usif spi_clk", USIF, xrx300_pins_usif_spi_clk),
+ GRP_MUX("usif spi_cs0", USIF, xrx300_pins_usif_spi_cs0),
+ GRP_MUX("stp", STP, xrx300_pins_stp),
+ GRP_MUX("clkout2", CGU, xrx300_pins_clkout2),
+ GRP_MUX("mdio", MDIO, xrx300_pins_mdio),
+ GRP_MUX("dfe led0", DFE, xrx300_pins_dfe_led0),
+ GRP_MUX("dfe led1", DFE, xrx300_pins_dfe_led1),
+ GRP_MUX("ephy0 led0", GPHY, xrx300_pins_ephy0_led0),
+ GRP_MUX("ephy0 led1", GPHY, xrx300_pins_ephy0_led1),
+ GRP_MUX("ephy1 led0", GPHY, xrx300_pins_ephy1_led0),
+ GRP_MUX("ephy1 led1", GPHY, xrx300_pins_ephy1_led1),
+};
+
+static const char * const xrx300_spi_grps[] = {"spi_di", "spi_do",
+ "spi_clk", "spi_cs1",
+ "spi_cs4", "spi_cs6"};
+static const char * const xrx300_cgu_grps[] = {"clkout2"};
+static const char * const xrx300_ebu_grps[] = {"nand ale", "nand cs1",
+ "nand cle", "nand rdy",
+ "nand rd", "nand d1",
+ "nand d0", "nand d2",
+ "nand d7", "nand d6",
+ "nand d5", "nand d4",
+ "nand d3", "nand cs0",
+ "nand wr", "nand wp",
+ "nand se"};
+static const char * const xrx300_exin_grps[] = {"exin0", "exin1", "exin2",
+ "exin4", "exin5"};
+static const char * const xrx300_usif_grps[] = {"usif uart_rx", "usif uart_tx",
+ "usif spi_di", "usif spi_do",
+ "usif spi_clk", "usif spi_cs0"};
+static const char * const xrx300_stp_grps[] = {"stp"};
+static const char * const xrx300_mdio_grps[] = {"mdio"};
+static const char * const xrx300_dfe_grps[] = {"dfe led0", "dfe led1"};
+static const char * const xrx300_gphy_grps[] = {"ephy0 led0", "ephy0 led1",
+ "ephy1 led0", "ephy1 led1"};
+
+static const struct ltq_pmx_func xrx300_funcs[] = {
+ {"spi", ARRAY_AND_SIZE(xrx300_spi_grps)},
+ {"usif", ARRAY_AND_SIZE(xrx300_usif_grps)},
+ {"cgu", ARRAY_AND_SIZE(xrx300_cgu_grps)},
+ {"exin", ARRAY_AND_SIZE(xrx300_exin_grps)},
+ {"stp", ARRAY_AND_SIZE(xrx300_stp_grps)},
+ {"ebu", ARRAY_AND_SIZE(xrx300_ebu_grps)},
+ {"mdio", ARRAY_AND_SIZE(xrx300_mdio_grps)},
+ {"dfe", ARRAY_AND_SIZE(xrx300_dfe_grps)},
+ {"ephy", ARRAY_AND_SIZE(xrx300_gphy_grps)},
+};
+
/* --------- pinconf related code --------- */
static int xway_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin,
@@ -676,6 +1563,10 @@ static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val)
{
struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev);
+ if (PORT(pin) == PORT3)
+ gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin));
+ else
+ gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin));
gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin));
xway_gpio_set(chip, pin, val);
@@ -695,10 +1586,7 @@ static struct gpio_chip xway_chip = {
/* --------- register the pinctrl layer --------- */
-static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9};
-static const unsigned ase_exin_pins_map[] = {GPIO6, GPIO29, GPIO0};
-
-static struct pinctrl_xway_soc {
+struct pinctrl_xway_soc {
int pin_count;
const struct ltq_mfp_pin *mfp;
const struct ltq_pin_group *grps;
@@ -707,22 +1595,54 @@ static struct pinctrl_xway_soc {
unsigned int num_funcs;
const unsigned *exin;
unsigned int num_exin;
-} soc_cfg[] = {
- /* legacy xway */
- {XWAY_MAX_PIN, xway_mfp,
- xway_grps, ARRAY_SIZE(xway_grps),
- danube_funcs, ARRAY_SIZE(danube_funcs),
- xway_exin_pin_map, 3},
- /* xway xr9 series */
- {XR9_MAX_PIN, xway_mfp,
- xway_grps, ARRAY_SIZE(xway_grps),
- xrx_funcs, ARRAY_SIZE(xrx_funcs),
- xway_exin_pin_map, 6},
- /* xway ase series */
- {XWAY_MAX_PIN, ase_mfp,
- ase_grps, ARRAY_SIZE(ase_grps),
- ase_funcs, ARRAY_SIZE(ase_funcs),
- ase_exin_pins_map, 3},
+};
+
+/* xway xr9 series (DEPRECATED: Use XWAY xRX100/xRX200 Family) */
+static struct pinctrl_xway_soc xr9_pinctrl = {
+ XR9_MAX_PIN, xway_mfp,
+ xway_grps, ARRAY_SIZE(xway_grps),
+ xrx_funcs, ARRAY_SIZE(xrx_funcs),
+ xway_exin_pin_map, 6
+};
+
+/* XWAY AMAZON Family */
+static struct pinctrl_xway_soc ase_pinctrl = {
+ ASE_MAX_PIN, ase_mfp,
+ ase_grps, ARRAY_SIZE(ase_grps),
+ ase_funcs, ARRAY_SIZE(ase_funcs),
+ ase_exin_pin_map, 3
+};
+
+/* XWAY DANUBE Family */
+static struct pinctrl_xway_soc danube_pinctrl = {
+ DANUBE_MAX_PIN, danube_mfp,
+ danube_grps, ARRAY_SIZE(danube_grps),
+ danube_funcs, ARRAY_SIZE(danube_funcs),
+ danube_exin_pin_map, 3
+};
+
+/* XWAY xRX100 Family */
+static struct pinctrl_xway_soc xrx100_pinctrl = {
+ XRX100_MAX_PIN, xrx100_mfp,
+ xrx100_grps, ARRAY_SIZE(xrx100_grps),
+ xrx100_funcs, ARRAY_SIZE(xrx100_funcs),
+ xrx100_exin_pin_map, 6
+};
+
+/* XWAY xRX200 Family */
+static struct pinctrl_xway_soc xrx200_pinctrl = {
+ XRX200_MAX_PIN, xrx200_mfp,
+ xrx200_grps, ARRAY_SIZE(xrx200_grps),
+ xrx200_funcs, ARRAY_SIZE(xrx200_funcs),
+ xrx200_exin_pin_map, 6
+};
+
+/* XWAY xRX300 Family */
+static struct pinctrl_xway_soc xrx300_pinctrl = {
+ XRX300_MAX_PIN, xrx300_mfp,
+ xrx300_grps, ARRAY_SIZE(xrx300_grps),
+ xrx300_funcs, ARRAY_SIZE(xrx300_funcs),
+ xrx300_exin_pin_map, 5
};
static struct pinctrl_gpio_range xway_gpio_range = {
@@ -731,9 +1651,14 @@ static struct pinctrl_gpio_range xway_gpio_range = {
};
static const struct of_device_id xway_match[] = {
- { .compatible = "lantiq,pinctrl-xway", .data = &soc_cfg[0]},
- { .compatible = "lantiq,pinctrl-xr9", .data = &soc_cfg[1]},
- { .compatible = "lantiq,pinctrl-ase", .data = &soc_cfg[2]},
+ { .compatible = "lantiq,pinctrl-xway", .data = &danube_pinctrl}, /*DEPRECATED*/
+ { .compatible = "lantiq,pinctrl-xr9", .data = &xr9_pinctrl}, /*DEPRECATED*/
+ { .compatible = "lantiq,pinctrl-ase", .data = &ase_pinctrl}, /*DEPRECATED*/
+ { .compatible = "lantiq,ase-pinctrl", .data = &ase_pinctrl},
+ { .compatible = "lantiq,danube-pinctrl", .data = &danube_pinctrl},
+ { .compatible = "lantiq,xrx100-pinctrl", .data = &xrx100_pinctrl},
+ { .compatible = "lantiq,xrx200-pinctrl", .data = &xrx200_pinctrl},
+ { .compatible = "lantiq,xrx300-pinctrl", .data = &xrx300_pinctrl},
{},
};
MODULE_DEVICE_TABLE(of, xway_match);
@@ -755,7 +1680,7 @@ static int pinmux_xway_probe(struct platform_device *pdev)
if (match)
xway_soc = (const struct pinctrl_xway_soc *) match->data;
else
- xway_soc = &soc_cfg[0];
+ xway_soc = &danube_pinctrl;
/* find out how many pads we have */
xway_chip.ngpio = xway_soc->pin_count;
diff --git a/drivers/pinctrl/pxa/Kconfig b/drivers/pinctrl/pxa/Kconfig
new file mode 100644
index 0000000..990667f
--- /dev/null
+++ b/drivers/pinctrl/pxa/Kconfig
@@ -0,0 +1,17 @@
+if (ARCH_PXA || COMPILE_TEST)
+
+config PINCTRL_PXA
+ bool
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+
+config PINCTRL_PXA27X
+ tristate "Marvell PXA27x pin controller driver"
+ select PINCTRL_PXA
+ default y if PXA27x
+ help
+ This is the pinctrl, pinmux, pinconf driver for the Marvell
+ PXA2xx block found in the pxa25x and pxa27x platforms.
+
+endif
diff --git a/drivers/pinctrl/pxa/Makefile b/drivers/pinctrl/pxa/Makefile
new file mode 100644
index 0000000..f1d56af
--- /dev/null
+++ b/drivers/pinctrl/pxa/Makefile
@@ -0,0 +1,2 @@
+# Marvell PXA pin control drivers
+obj-$(CONFIG_PINCTRL_PXA27X) += pinctrl-pxa2xx.o pinctrl-pxa27x.o
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa27x.c b/drivers/pinctrl/pxa/pinctrl-pxa27x.c
new file mode 100644
index 0000000..2e2c370
--- /dev/null
+++ b/drivers/pinctrl/pxa/pinctrl-pxa27x.c
@@ -0,0 +1,566 @@
+/*
+ * Marvell PXA27x family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-pxa2xx.h"
+
+static const struct pxa_desc_pin pxa27x_pins[] = {
+ PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(0)),
+ PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(1)),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(9),
+ PXA_FUNCTION(0, 3, "FFCTS"),
+ PXA_FUNCTION(1, 1, "HZ_CLK"),
+ PXA_FUNCTION(1, 3, "CHOUT<0>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(10),
+ PXA_FUNCTION(0, 1, "FFDCD"),
+ PXA_FUNCTION(0, 3, "USB_P3_5"),
+ PXA_FUNCTION(1, 1, "HZ_CLK"),
+ PXA_FUNCTION(1, 3, "CHOUT<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(11),
+ PXA_FUNCTION(0, 1, "EXT_SYNC<0>"),
+ PXA_FUNCTION(0, 2, "SSPRXD2"),
+ PXA_FUNCTION(0, 3, "USB_P3_1"),
+ PXA_FUNCTION(1, 1, "CHOUT<0>"),
+ PXA_FUNCTION(1, 1, "PWM_OUT<2>"),
+ PXA_FUNCTION(1, 3, "48_MHz")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(12),
+ PXA_FUNCTION(0, 1, "EXT_SYNC<1>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<7>"),
+ PXA_FUNCTION(1, 1, "CHOUT<1>"),
+ PXA_FUNCTION(1, 1, "PWM_OUT<3>"),
+ PXA_FUNCTION(1, 3, "48_MHz")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(13),
+ PXA_FUNCTION(0, 1, "CLK_EXT"),
+ PXA_FUNCTION(0, 2, "KP_DKIN<7>"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<7>"),
+ PXA_FUNCTION(1, 1, "SSPTXD2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(14),
+ PXA_FUNCTION(0, 1, "L_VSYNC"),
+ PXA_FUNCTION(0, 2, "SSPSFRM2"),
+ PXA_FUNCTION(1, 1, "SSPSFRM2"),
+ PXA_FUNCTION(1, 3, "UCLK")),
+ PXA_GPIO_ONLY_PIN(PXA_PINCTRL_PIN(15)),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(16),
+ PXA_FUNCTION(0, 1, "KP_MKIN<5>"),
+ PXA_FUNCTION(1, 2, "PWM_OUT<0>"),
+ PXA_FUNCTION(1, 3, "FFTXD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(17),
+ PXA_FUNCTION(0, 1, "KP_MKIN<6>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<6>"),
+ PXA_FUNCTION(1, 2, "PWM_OUT<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(18),
+ PXA_FUNCTION(0, 1, "RDY")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(19),
+ PXA_FUNCTION(0, 1, "SSPSCLK2"),
+ PXA_FUNCTION(0, 3, "FFRXD"),
+ PXA_FUNCTION(1, 1, "SSPSCLK2"),
+ PXA_FUNCTION(1, 2, "L_CS"),
+ PXA_FUNCTION(1, 3, "nURST")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(20),
+ PXA_FUNCTION(0, 1, "DREQ<0>"),
+ PXA_FUNCTION(0, 2, "MBREQ"),
+ PXA_FUNCTION(1, 1, "nSDCS<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(21),
+ PXA_FUNCTION(1, 1, "nSDCS<3>"),
+ PXA_FUNCTION(1, 2, "DVAL<0>"),
+ PXA_FUNCTION(1, 3, "MBGNT")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(22),
+ PXA_FUNCTION(0, 1, "SSPEXTCLK2"),
+ PXA_FUNCTION(0, 2, "SSPSCLKEN2"),
+ PXA_FUNCTION(0, 3, "SSPSCLK2"),
+ PXA_FUNCTION(1, 1, "KP_MKOUT<7>"),
+ PXA_FUNCTION(1, 2, "SSPSYSCLK2"),
+ PXA_FUNCTION(1, 3, "SSPSCLK2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(23),
+ PXA_FUNCTION(0, 2, "SSPSCLK"),
+ PXA_FUNCTION(1, 1, "CIF_MCLK"),
+ PXA_FUNCTION(1, 1, "SSPSCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(24),
+ PXA_FUNCTION(0, 1, "CIF_FV"),
+ PXA_FUNCTION(0, 2, "SSPSFRM"),
+ PXA_FUNCTION(1, 1, "CIF_FV"),
+ PXA_FUNCTION(1, 2, "SSPSFRM")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(25),
+ PXA_FUNCTION(0, 1, "CIF_LV"),
+ PXA_FUNCTION(1, 1, "CIF_LV"),
+ PXA_FUNCTION(1, 2, "SSPTXD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(26),
+ PXA_FUNCTION(0, 1, "SSPRXD"),
+ PXA_FUNCTION(0, 2, "CIF_PCLK"),
+ PXA_FUNCTION(0, 3, "FFCTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(27),
+ PXA_FUNCTION(0, 1, "SSPEXTCLK"),
+ PXA_FUNCTION(0, 2, "SSPSCLKEN"),
+ PXA_FUNCTION(0, 3, "CIF_DD<0>"),
+ PXA_FUNCTION(1, 1, "SSPSYSCLK"),
+ PXA_FUNCTION(1, 3, "FFRTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(28),
+ PXA_FUNCTION(0, 1, "AC97_BITCLK"),
+ PXA_FUNCTION(0, 2, "I2S_BITCLK"),
+ PXA_FUNCTION(0, 3, "SSPSFRM"),
+ PXA_FUNCTION(1, 1, "I2S_BITCLK"),
+ PXA_FUNCTION(1, 3, "SSPSFRM")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(29),
+ PXA_FUNCTION(0, 1, "AC97_SDATA_IN_0"),
+ PXA_FUNCTION(0, 2, "I2S_SDATA_IN"),
+ PXA_FUNCTION(0, 3, "SSPSCLK"),
+ PXA_FUNCTION(1, 1, "SSPRXD2"),
+ PXA_FUNCTION(1, 3, "SSPSCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(30),
+ PXA_FUNCTION(1, 1, "I2S_SDATA_OUT"),
+ PXA_FUNCTION(1, 2, "AC97_SDATA_OUT"),
+ PXA_FUNCTION(1, 3, "USB_P3_2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(31),
+ PXA_FUNCTION(1, 1, "I2S_SYNC"),
+ PXA_FUNCTION(1, 2, "AC97_SYNC"),
+ PXA_FUNCTION(1, 3, "USB_P3_6")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(32),
+ PXA_FUNCTION(1, 1, "MSSCLK"),
+ PXA_FUNCTION(1, 2, "MMCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(33),
+ PXA_FUNCTION(0, 1, "FFRXD"),
+ PXA_FUNCTION(0, 2, "FFDSR"),
+ PXA_FUNCTION(1, 1, "DVAL<1>"),
+ PXA_FUNCTION(1, 2, "nCS<5>"),
+ PXA_FUNCTION(1, 3, "MBGNT")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(34),
+ PXA_FUNCTION(0, 1, "FFRXD"),
+ PXA_FUNCTION(0, 2, "KP_MKIN<3>"),
+ PXA_FUNCTION(0, 3, "SSPSCLK3"),
+ PXA_FUNCTION(1, 1, "USB_P2_2"),
+ PXA_FUNCTION(1, 3, "SSPSCLK3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(35),
+ PXA_FUNCTION(0, 1, "FFCTS"),
+ PXA_FUNCTION(0, 2, "USB_P2_1"),
+ PXA_FUNCTION(0, 3, "SSPSFRM3"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<6>"),
+ PXA_FUNCTION(1, 3, "SSPTXD3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(36),
+ PXA_FUNCTION(0, 1, "FFDCD"),
+ PXA_FUNCTION(0, 2, "SSPSCLK2"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<7>"),
+ PXA_FUNCTION(1, 1, "USB_P2_4"),
+ PXA_FUNCTION(1, 2, "SSPSCLK2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(37),
+ PXA_FUNCTION(0, 1, "FFDSR"),
+ PXA_FUNCTION(0, 2, "SSPSFRM2"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<3>"),
+ PXA_FUNCTION(1, 1, "USB_P2_8"),
+ PXA_FUNCTION(1, 2, "SSPSFRM2"),
+ PXA_FUNCTION(1, 3, "FFTXD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(38),
+ PXA_FUNCTION(0, 1, "FFRI"),
+ PXA_FUNCTION(0, 2, "KP_MKIN<4>"),
+ PXA_FUNCTION(0, 3, "USB_P2_3"),
+ PXA_FUNCTION(1, 1, "SSPTXD3"),
+ PXA_FUNCTION(1, 2, "SSPTXD2"),
+ PXA_FUNCTION(1, 3, "PWM_OUT<0>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(39),
+ PXA_FUNCTION(0, 1, "KP_MKIN<4>"),
+ PXA_FUNCTION(0, 3, "SSPSFRM3"),
+ PXA_FUNCTION(1, 1, "USB_P2_6"),
+ PXA_FUNCTION(1, 2, "FFTXD"),
+ PXA_FUNCTION(1, 3, "SSPSFRM3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(40),
+ PXA_FUNCTION(0, 1, "SSPRXD2"),
+ PXA_FUNCTION(0, 3, "USB_P2_5"),
+ PXA_FUNCTION(1, 1, "KP_MKOUT<6>"),
+ PXA_FUNCTION(1, 2, "FFDTR"),
+ PXA_FUNCTION(1, 3, "SSPSCLK3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(41),
+ PXA_FUNCTION(0, 1, "FFRXD"),
+ PXA_FUNCTION(0, 2, "USB_P2_7"),
+ PXA_FUNCTION(0, 3, "SSPRXD3"),
+ PXA_FUNCTION(1, 1, "KP_MKOUT<7>"),
+ PXA_FUNCTION(1, 2, "FFRTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(42),
+ PXA_FUNCTION(0, 1, "BTRXD"),
+ PXA_FUNCTION(0, 2, "ICP_RXD"),
+ PXA_FUNCTION(1, 3, "CIF_MCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(43),
+ PXA_FUNCTION(0, 3, "CIF_FV"),
+ PXA_FUNCTION(1, 1, "ICP_TXD"),
+ PXA_FUNCTION(1, 2, "BTTXD"),
+ PXA_FUNCTION(1, 3, "CIF_FV")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(44),
+ PXA_FUNCTION(0, 1, "BTCTS"),
+ PXA_FUNCTION(0, 3, "CIF_LV"),
+ PXA_FUNCTION(1, 3, "CIF_LV")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(45),
+ PXA_FUNCTION(0, 3, "CIF_PCLK"),
+ PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+ PXA_FUNCTION(1, 2, "BTRTS"),
+ PXA_FUNCTION(1, 3, "SSPSYSCLK3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(46),
+ PXA_FUNCTION(0, 1, "ICP_RXD"),
+ PXA_FUNCTION(0, 2, "STD_RXD"),
+ PXA_FUNCTION(1, 2, "PWM_OUT<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(47),
+ PXA_FUNCTION(0, 1, "CIF_DD<0>"),
+ PXA_FUNCTION(1, 1, "STD_TXD"),
+ PXA_FUNCTION(1, 2, "ICP_TXD"),
+ PXA_FUNCTION(1, 3, "PWM_OUT<3>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(48),
+ PXA_FUNCTION(0, 1, "CIF_DD<5>"),
+ PXA_FUNCTION(1, 1, "BB_OB_DAT<1>"),
+ PXA_FUNCTION(1, 2, "nPOE")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(49),
+ PXA_FUNCTION(1, 2, "nPWE")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(50),
+ PXA_FUNCTION(0, 1, "CIF_DD<3>"),
+ PXA_FUNCTION(0, 3, "SSPSCLK2"),
+ PXA_FUNCTION(1, 1, "BB_OB_DAT<2>"),
+ PXA_FUNCTION(1, 2, "nPIOR"),
+ PXA_FUNCTION(1, 3, "SSPSCLK2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(51),
+ PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+ PXA_FUNCTION(1, 1, "BB_OB_DAT<3>"),
+ PXA_FUNCTION(1, 2, "nPIOW")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(52),
+ PXA_FUNCTION(0, 1, "CIF_DD<4>"),
+ PXA_FUNCTION(0, 2, "SSPSCLK3"),
+ PXA_FUNCTION(1, 1, "BB_OB_CLK"),
+ PXA_FUNCTION(1, 2, "SSPSCLK3")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(53),
+ PXA_FUNCTION(0, 1, "FFRXD"),
+ PXA_FUNCTION(0, 2, "USB_P2_3"),
+ PXA_FUNCTION(1, 1, "BB_OB_STB"),
+ PXA_FUNCTION(1, 2, "CIF_MCLK"),
+ PXA_FUNCTION(1, 3, "SSPSYSCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(54),
+ PXA_FUNCTION(0, 2, "BB_OB_WAIT"),
+ PXA_FUNCTION(0, 3, "CIF_PCLK"),
+ PXA_FUNCTION(1, 2, "nPCE<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(55),
+ PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+ PXA_FUNCTION(0, 2, "BB_IB_DAT<1>"),
+ PXA_FUNCTION(1, 2, "nPREG")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(56),
+ PXA_FUNCTION(0, 1, "nPWAIT"),
+ PXA_FUNCTION(0, 2, "BB_IB_DAT<2>"),
+ PXA_FUNCTION(1, 1, "USB_P3_4")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(57),
+ PXA_FUNCTION(0, 1, "nIOS16"),
+ PXA_FUNCTION(0, 2, "BB_IB_DAT<3>"),
+ PXA_FUNCTION(1, 3, "SSPTXD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(58),
+ PXA_FUNCTION(0, 2, "LDD<0>"),
+ PXA_FUNCTION(1, 2, "LDD<0>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(59),
+ PXA_FUNCTION(0, 2, "LDD<1>"),
+ PXA_FUNCTION(1, 2, "LDD<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(60),
+ PXA_FUNCTION(0, 2, "LDD<2>"),
+ PXA_FUNCTION(1, 2, "LDD<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(61),
+ PXA_FUNCTION(0, 2, "LDD<3>"),
+ PXA_FUNCTION(1, 2, "LDD<3>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(62),
+ PXA_FUNCTION(0, 2, "LDD<4>"),
+ PXA_FUNCTION(1, 2, "LDD<4>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(63),
+ PXA_FUNCTION(0, 2, "LDD<5>"),
+ PXA_FUNCTION(1, 2, "LDD<5>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(64),
+ PXA_FUNCTION(0, 2, "LDD<6>"),
+ PXA_FUNCTION(1, 2, "LDD<6>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(65),
+ PXA_FUNCTION(0, 2, "LDD<7>"),
+ PXA_FUNCTION(1, 2, "LDD<7>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(66),
+ PXA_FUNCTION(0, 2, "LDD<8>"),
+ PXA_FUNCTION(1, 2, "LDD<8>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(67),
+ PXA_FUNCTION(0, 2, "LDD<9>"),
+ PXA_FUNCTION(1, 2, "LDD<9>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(68),
+ PXA_FUNCTION(0, 2, "LDD<10>"),
+ PXA_FUNCTION(1, 2, "LDD<10>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(69),
+ PXA_FUNCTION(0, 2, "LDD<11>"),
+ PXA_FUNCTION(1, 2, "LDD<11>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(70),
+ PXA_FUNCTION(0, 2, "LDD<12>"),
+ PXA_FUNCTION(1, 2, "LDD<12>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(71),
+ PXA_FUNCTION(0, 2, "LDD<13>"),
+ PXA_FUNCTION(1, 2, "LDD<13>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(72),
+ PXA_FUNCTION(0, 2, "LDD<14>"),
+ PXA_FUNCTION(1, 2, "LDD<14>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(73),
+ PXA_FUNCTION(0, 2, "LDD<15>"),
+ PXA_FUNCTION(1, 2, "LDD<15>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(74),
+ PXA_FUNCTION(1, 2, "L_FCLK_RD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(75),
+ PXA_FUNCTION(1, 2, "L_LCLK_A0")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(76),
+ PXA_FUNCTION(1, 2, "L_PCLK_WR")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(77),
+ PXA_FUNCTION(1, 2, "L_BIAS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(78),
+ PXA_FUNCTION(1, 1, "nPCE<2>"),
+ PXA_FUNCTION(1, 2, "nCS<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(79),
+ PXA_FUNCTION(1, 1, "PSKTSEL"),
+ PXA_FUNCTION(1, 2, "nCS<3>"),
+ PXA_FUNCTION(1, 3, "PWM_OUT<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(80),
+ PXA_FUNCTION(0, 1, "DREQ<1>"),
+ PXA_FUNCTION(0, 2, "MBREQ"),
+ PXA_FUNCTION(1, 2, "nCS<4>"),
+ PXA_FUNCTION(1, 3, "PWM_OUT<3>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(81),
+ PXA_FUNCTION(0, 2, "CIF_DD<0>"),
+ PXA_FUNCTION(1, 1, "SSPTXD3"),
+ PXA_FUNCTION(1, 2, "BB_OB_DAT<0>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(82),
+ PXA_FUNCTION(0, 1, "SSPRXD3"),
+ PXA_FUNCTION(0, 2, "BB_IB_DAT<0>"),
+ PXA_FUNCTION(0, 3, "CIF_DD<5>"),
+ PXA_FUNCTION(1, 3, "FFDTR")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(83),
+ PXA_FUNCTION(0, 1, "SSPSFRM3"),
+ PXA_FUNCTION(0, 2, "BB_IB_CLK"),
+ PXA_FUNCTION(0, 3, "CIF_DD<5>"),
+ PXA_FUNCTION(1, 1, "SSPSFRM3"),
+ PXA_FUNCTION(1, 2, "FFTXD"),
+ PXA_FUNCTION(1, 3, "FFRTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(84),
+ PXA_FUNCTION(0, 1, "SSPCLK3"),
+ PXA_FUNCTION(0, 2, "BB_IB_STB"),
+ PXA_FUNCTION(0, 3, "CIF_FV"),
+ PXA_FUNCTION(1, 1, "SSPCLK3"),
+ PXA_FUNCTION(1, 3, "CIF_FV")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(85),
+ PXA_FUNCTION(0, 1, "FFRXD"),
+ PXA_FUNCTION(0, 2, "DREQ<2>"),
+ PXA_FUNCTION(0, 3, "CIF_LV"),
+ PXA_FUNCTION(1, 1, "nPCE<1>"),
+ PXA_FUNCTION(1, 2, "BB_IB_WAIT"),
+ PXA_FUNCTION(1, 3, "CIF_LV")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(86),
+ PXA_FUNCTION(0, 1, "SSPRXD2"),
+ PXA_FUNCTION(0, 2, "LDD<16>"),
+ PXA_FUNCTION(0, 3, "USB_P3_5"),
+ PXA_FUNCTION(1, 1, "nPCE<1>"),
+ PXA_FUNCTION(1, 2, "LDD<16>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(87),
+ PXA_FUNCTION(0, 1, "nPCE<2>"),
+ PXA_FUNCTION(0, 2, "LDD<17>"),
+ PXA_FUNCTION(0, 3, "USB_P3_1"),
+ PXA_FUNCTION(1, 1, "SSPTXD2"),
+ PXA_FUNCTION(1, 2, "LDD<17>"),
+ PXA_FUNCTION(1, 3, "SSPSFRM2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(88),
+ PXA_FUNCTION(0, 1, "USBHPWR<1>"),
+ PXA_FUNCTION(0, 2, "SSPRXD2"),
+ PXA_FUNCTION(0, 3, "SSPSFRM2"),
+ PXA_FUNCTION(1, 2, "SSPTXD2"),
+ PXA_FUNCTION(1, 3, "SSPSFRM2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(89),
+ PXA_FUNCTION(0, 1, "SSPRXD3"),
+ PXA_FUNCTION(0, 3, "FFRI"),
+ PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+ PXA_FUNCTION(1, 2, "USBHPEN<1>"),
+ PXA_FUNCTION(1, 3, "SSPTXD2")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(90),
+ PXA_FUNCTION(0, 1, "KP_MKIN<5>"),
+ PXA_FUNCTION(0, 3, "USB_P3_5"),
+ PXA_FUNCTION(1, 1, "CIF_DD<4>"),
+ PXA_FUNCTION(1, 2, "nURST")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(91),
+ PXA_FUNCTION(0, 1, "KP_MKIN<6>"),
+ PXA_FUNCTION(0, 3, "USB_P3_1"),
+ PXA_FUNCTION(1, 1, "CIF_DD<5>"),
+ PXA_FUNCTION(1, 2, "UCLK")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(92),
+ PXA_FUNCTION(0, 1, "MMDAT<0>"),
+ PXA_FUNCTION(1, 1, "MMDAT<0>"),
+ PXA_FUNCTION(1, 2, "MSBS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(93),
+ PXA_FUNCTION(0, 1, "KP_DKIN<0>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<6>"),
+ PXA_FUNCTION(1, 1, "AC97_SDATA_OUT")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(94),
+ PXA_FUNCTION(0, 1, "KP_DKIN<1>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<5>"),
+ PXA_FUNCTION(1, 1, "AC97_SYNC")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(95),
+ PXA_FUNCTION(0, 1, "KP_DKIN<2>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<4>"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<6>"),
+ PXA_FUNCTION(1, 1, "AC97_RESET_n")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(96),
+ PXA_FUNCTION(0, 1, "KP_DKIN<3>"),
+ PXA_FUNCTION(0, 2, "MBREQ"),
+ PXA_FUNCTION(0, 3, "FFRXD"),
+ PXA_FUNCTION(1, 2, "DVAL<1>"),
+ PXA_FUNCTION(1, 3, "KP_MKOUT<6>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(97),
+ PXA_FUNCTION(0, 1, "KP_DKIN<4>"),
+ PXA_FUNCTION(0, 2, "DREQ<1>"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<3>"),
+ PXA_FUNCTION(1, 2, "MBGNT")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(98),
+ PXA_FUNCTION(0, 1, "KP_DKIN<5>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<0>"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<4>"),
+ PXA_FUNCTION(1, 1, "AC97_SYSCLK"),
+ PXA_FUNCTION(1, 3, "FFRTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(99),
+ PXA_FUNCTION(0, 1, "KP_DKIN<6>"),
+ PXA_FUNCTION(0, 2, "AC97_SDATA_IN_1"),
+ PXA_FUNCTION(0, 3, "KP_MKIN<5>"),
+ PXA_FUNCTION(1, 3, "FFTXD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(100),
+ PXA_FUNCTION(0, 1, "KP_MKIN<0>"),
+ PXA_FUNCTION(0, 2, "DREQ<2>"),
+ PXA_FUNCTION(0, 3, "FFCTS")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(101),
+ PXA_FUNCTION(0, 1, "KP_MKIN<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(102),
+ PXA_FUNCTION(0, 1, "KP_MKIN<2>"),
+ PXA_FUNCTION(0, 3, "FFRXD"),
+ PXA_FUNCTION(1, 1, "nPCE<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(103),
+ PXA_FUNCTION(0, 1, "CIF_DD<3>"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<0>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(104),
+ PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+ PXA_FUNCTION(1, 1, "PSKTSEL"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(105),
+ PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+ PXA_FUNCTION(1, 1, "nPCE<2>"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(106),
+ PXA_FUNCTION(0, 1, "CIF_DD<9>"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<3>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(107),
+ PXA_FUNCTION(0, 1, "CIF_DD<8>"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<4>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(108),
+ PXA_FUNCTION(0, 1, "CIF_DD<7>"),
+ PXA_FUNCTION(1, 1, "CHOUT<0>"),
+ PXA_FUNCTION(1, 2, "KP_MKOUT<5>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(109),
+ PXA_FUNCTION(0, 1, "MMDAT<1>"),
+ PXA_FUNCTION(0, 2, "MSSDIO"),
+ PXA_FUNCTION(1, 1, "MMDAT<1>"),
+ PXA_FUNCTION(1, 2, "MSSDIO")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(110),
+ PXA_FUNCTION(0, 1, "MMDAT<2>"),
+ PXA_FUNCTION(1, 1, "MMDAT<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(111),
+ PXA_FUNCTION(0, 1, "MMDAT<3>"),
+ PXA_FUNCTION(1, 1, "MMDAT<3>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(112),
+ PXA_FUNCTION(0, 1, "MMCMD"),
+ PXA_FUNCTION(0, 2, "nMSINS"),
+ PXA_FUNCTION(1, 1, "MMCMD")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(113),
+ PXA_FUNCTION(0, 3, "USB_P3_3"),
+ PXA_FUNCTION(1, 1, "I2S_SYSCLK"),
+ PXA_FUNCTION(1, 2, "AC97_RESET_n")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(114),
+ PXA_FUNCTION(0, 1, "CIF_DD<1>"),
+ PXA_FUNCTION(1, 1, "UEN"),
+ PXA_FUNCTION(1, 2, "UVS0")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(115),
+ PXA_FUNCTION(0, 1, "DREQ<0>"),
+ PXA_FUNCTION(0, 2, "CIF_DD<3>"),
+ PXA_FUNCTION(0, 3, "MBREQ"),
+ PXA_FUNCTION(1, 1, "UEN"),
+ PXA_FUNCTION(1, 2, "nUVS1"),
+ PXA_FUNCTION(1, 3, "PWM_OUT<1>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(116),
+ PXA_FUNCTION(0, 1, "CIF_DD<2>"),
+ PXA_FUNCTION(0, 2, "AC97_SDATA_IN_0"),
+ PXA_FUNCTION(0, 3, "UDET"),
+ PXA_FUNCTION(1, 1, "DVAL<0>"),
+ PXA_FUNCTION(1, 2, "nUVS2"),
+ PXA_FUNCTION(1, 3, "MBGNT")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(117),
+ PXA_FUNCTION(0, 1, "SCL"),
+ PXA_FUNCTION(1, 1, "SCL")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(118),
+ PXA_FUNCTION(0, 1, "SDA"),
+ PXA_FUNCTION(1, 1, "SDA")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(119),
+ PXA_FUNCTION(0, 1, "USBHPWR<2>")),
+ PXA_GPIO_PIN(PXA_PINCTRL_PIN(120),
+ PXA_FUNCTION(1, 2, "USBHPEN<2>")),
+};
+
+static int pxa27x_pinctrl_probe(struct platform_device *pdev)
+{
+ int ret, i;
+ void __iomem *base_af[8];
+ void __iomem *base_dir[4];
+ void __iomem *base_sleep[4];
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base_af[0] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base_af[0]))
+ return PTR_ERR(base_af[0]);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ base_dir[0] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base_dir[0]))
+ return PTR_ERR(base_dir[0]);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ base_dir[3] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base_dir[3]))
+ return PTR_ERR(base_dir[3]);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ base_sleep[0] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(base_sleep[0]))
+ return PTR_ERR(base_sleep[0]);
+
+ for (i = 0; i < ARRAY_SIZE(base_af); i++)
+ base_af[i] = base_af[0] + sizeof(base_af[0]) * i;
+ for (i = 0; i < 3; i++)
+ base_dir[i] = base_dir[0] + sizeof(base_dir[0]) * i;
+ for (i = 0; i < ARRAY_SIZE(base_sleep); i++)
+ base_sleep[i] = base_sleep[0] + sizeof(base_af[0]) * i;
+
+ ret = pxa2xx_pinctrl_init(pdev, pxa27x_pins, ARRAY_SIZE(pxa27x_pins),
+ base_af, base_dir, base_sleep);
+ return ret;
+}
+
+static const struct of_device_id pxa27x_pinctrl_match[] = {
+ { .compatible = "marvell,pxa27x-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pxa27x_pinctrl_match);
+
+static struct platform_driver pxa27x_pinctrl_driver = {
+ .probe = pxa27x_pinctrl_probe,
+ .driver = {
+ .name = "pxa27x-pinctrl",
+ .of_match_table = pxa27x_pinctrl_match,
+ },
+};
+module_platform_driver(pxa27x_pinctrl_driver);
+
+MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
+MODULE_DESCRIPTION("Marvell PXA27x pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.c b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
new file mode 100644
index 0000000..d90e205
--- /dev/null
+++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.c
@@ -0,0 +1,436 @@
+/*
+ * Marvell PXA2xx family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/module.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "../pinctrl-utils.h"
+#include "pinctrl-pxa2xx.h"
+
+static int pxa2xx_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->ngroups;
+}
+
+static const char *pxa2xx_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned tgroup)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+
+ return group->name;
+}
+
+static int pxa2xx_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned tgroup,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+
+ *pins = (unsigned *)&group->pin;
+ *num_pins = 1;
+
+ return 0;
+}
+
+static const struct pinctrl_ops pxa2xx_pctl_ops = {
+#ifdef CONFIG_OF
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+#endif
+ .get_groups_count = pxa2xx_pctrl_get_groups_count,
+ .get_group_name = pxa2xx_pctrl_get_group_name,
+ .get_group_pins = pxa2xx_pctrl_get_group_pins,
+};
+
+static struct pxa_desc_function *
+pxa_desc_by_func_group(struct pxa_pinctrl *pctl, const char *pin_name,
+ const char *func_name)
+{
+ int i;
+ struct pxa_desc_function *df;
+
+ for (i = 0; i < pctl->npins; i++) {
+ const struct pxa_desc_pin *pin = pctl->ppins + i;
+
+ if (!strcmp(pin->pin.name, pin_name))
+ for (df = pin->functions; df->name; df++)
+ if (!strcmp(df->name, func_name))
+ return df;
+ }
+
+ return NULL;
+}
+
+static int pxa2xx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned pin,
+ bool input)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+ uint32_t val;
+ void __iomem *gpdr;
+
+ gpdr = pctl->base_gpdr[pin / 32];
+ dev_dbg(pctl->dev, "set_direction(pin=%d): dir=%d\n",
+ pin, !input);
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ val = readl_relaxed(gpdr);
+ val = (val & ~BIT(pin % 32)) | (input ? 0 : BIT(pin % 32));
+ writel_relaxed(val, gpdr);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
+
+ return 0;
+}
+
+static const char *pxa2xx_pmx_get_func_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_function *pf = pctl->functions + function;
+
+ return pf->name;
+}
+
+static int pxa2xx_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctl->nfuncs;
+}
+
+static int pxa2xx_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_function *pf = pctl->functions + function;
+
+ *groups = pf->groups;
+ *num_groups = pf->ngroups;
+
+ return 0;
+}
+
+static int pxa2xx_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned tgroup)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_group *group = pctl->groups + tgroup;
+ struct pxa_desc_function *df;
+ int pin, shift;
+ unsigned long flags;
+ void __iomem *gafr, *gpdr;
+ u32 val;
+
+
+ df = pxa_desc_by_func_group(pctl, group->name,
+ (pctl->functions + function)->name);
+ if (!df)
+ return -EINVAL;
+
+ pin = group->pin;
+ gafr = pctl->base_gafr[pin / 16];
+ gpdr = pctl->base_gpdr[pin / 32];
+ shift = (pin % 16) << 1;
+ dev_dbg(pctl->dev, "set_mux(pin=%d): af=%d dir=%d\n",
+ pin, df->muxval >> 1, df->muxval & 0x1);
+
+ spin_lock_irqsave(&pctl->lock, flags);
+
+ val = readl_relaxed(gafr);
+ val = (val & ~(0x3 << shift)) | ((df->muxval >> 1) << shift);
+ writel_relaxed(val, gafr);
+
+ val = readl_relaxed(gpdr);
+ val = (val & ~BIT(pin % 32)) | ((df->muxval & 1) ? BIT(pin % 32) : 0);
+ writel_relaxed(val, gpdr);
+
+ spin_unlock_irqrestore(&pctl->lock, flags);
+
+ return 0;
+}
+static const struct pinmux_ops pxa2xx_pinmux_ops = {
+ .get_functions_count = pxa2xx_get_functions_count,
+ .get_function_name = pxa2xx_pmx_get_func_name,
+ .get_function_groups = pxa2xx_pmx_get_func_groups,
+ .set_mux = pxa2xx_pmx_set_mux,
+ .gpio_set_direction = pxa2xx_pmx_gpio_set_direction,
+};
+
+static int pxa2xx_pconf_group_get(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long *config)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_group *g = pctl->groups + group;
+ unsigned long flags;
+ unsigned pin = g->pin;
+ void __iomem *pgsr = pctl->base_pgsr[pin / 32];
+ u32 val;
+
+ spin_lock_irqsave(&pctl->lock, flags);
+ val = readl_relaxed(pgsr) & BIT(pin % 32);
+ *config = val ? PIN_CONFIG_LOW_POWER_MODE : 0;
+ spin_unlock_irqrestore(&pctl->lock, flags);
+
+ dev_dbg(pctl->dev, "get sleep gpio state(pin=%d) %d\n",
+ pin, !!val);
+ return 0;
+}
+
+static int pxa2xx_pconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned group,
+ unsigned long *configs,
+ unsigned num_configs)
+{
+ struct pxa_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
+ struct pxa_pinctrl_group *g = pctl->groups + group;
+ unsigned long flags;
+ unsigned pin = g->pin;
+ void __iomem *pgsr = pctl->base_pgsr[pin / 32];
+ int i, is_set = 0;
+ u32 val;
+
+ for (i = 0; i < num_configs; i++) {
+ switch (pinconf_to_config_param(configs[i])) {
+ case PIN_CONFIG_LOW_POWER_MODE:
+ is_set = pinconf_to_config_argument(configs[i]);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ dev_dbg(pctl->dev, "set sleep gpio state(pin=%d) %d\n",
+ pin, is_set);
+
+ spin_lock_irqsave(&pctl->lock, flags);
+ val = readl_relaxed(pgsr);
+ val = (val & ~BIT(pin % 32)) | (is_set ? BIT(pin % 32) : 0);
+ writel_relaxed(val, pgsr);
+ spin_unlock_irqrestore(&pctl->lock, flags);
+
+ return 0;
+}
+
+static const struct pinconf_ops pxa2xx_pconf_ops = {
+ .pin_config_group_get = pxa2xx_pconf_group_get,
+ .pin_config_group_set = pxa2xx_pconf_group_set,
+ .is_generic = true,
+};
+
+static struct pinctrl_desc pxa2xx_pinctrl_desc = {
+ .confops = &pxa2xx_pconf_ops,
+ .pctlops = &pxa2xx_pctl_ops,
+ .pmxops = &pxa2xx_pinmux_ops,
+};
+
+static const struct pxa_pinctrl_function *
+pxa2xx_find_function(struct pxa_pinctrl *pctl, const char *fname,
+ const struct pxa_pinctrl_function *functions)
+{
+ const struct pxa_pinctrl_function *func;
+
+ for (func = functions; func->name; func++)
+ if (!strcmp(fname, func->name))
+ return func;
+
+ return NULL;
+}
+
+static int pxa2xx_build_functions(struct pxa_pinctrl *pctl)
+{
+ int i;
+ struct pxa_pinctrl_function *functions;
+ struct pxa_desc_function *df;
+
+ /*
+ * Each pin can have at most 6 alternate functions, and 2 gpio functions
+ * which are common to each pin. As there are more than 2 pins without
+ * alternate function, 6 * npins is an absolute high limit of the number
+ * of functions.
+ */
+ functions = devm_kcalloc(pctl->dev, pctl->npins * 6,
+ sizeof(*functions), GFP_KERNEL);
+ if (!functions)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->npins; i++)
+ for (df = pctl->ppins[i].functions; df->name; df++)
+ if (!pxa2xx_find_function(pctl, df->name, functions))
+ (functions + pctl->nfuncs++)->name = df->name;
+ pctl->functions = devm_kmemdup(pctl->dev, functions,
+ pctl->nfuncs * sizeof(*functions),
+ GFP_KERNEL);
+ if (!pctl->functions)
+ return -ENOMEM;
+
+ devm_kfree(pctl->dev, functions);
+ return 0;
+}
+
+static int pxa2xx_build_groups(struct pxa_pinctrl *pctl)
+{
+ int i, j, ngroups;
+ struct pxa_pinctrl_function *func;
+ struct pxa_desc_function *df;
+ char **gtmp;
+
+ gtmp = devm_kmalloc_array(pctl->dev, pctl->npins, sizeof(*gtmp),
+ GFP_KERNEL);
+ if (!gtmp)
+ return -ENOMEM;
+
+ for (i = 0; i < pctl->nfuncs; i++) {
+ ngroups = 0;
+ for (j = 0; j < pctl->npins; j++)
+ for (df = pctl->ppins[j].functions; df->name;
+ df++)
+ if (!strcmp(pctl->functions[i].name,
+ df->name))
+ gtmp[ngroups++] = (char *)
+ pctl->ppins[j].pin.name;
+ func = pctl->functions + i;
+ func->ngroups = ngroups;
+ func->groups =
+ devm_kmalloc_array(pctl->dev, ngroups,
+ sizeof(char *), GFP_KERNEL);
+ if (!func->groups)
+ return -ENOMEM;
+
+ memcpy(func->groups, gtmp, ngroups * sizeof(*gtmp));
+ }
+
+ devm_kfree(pctl->dev, gtmp);
+ return 0;
+}
+
+static int pxa2xx_build_state(struct pxa_pinctrl *pctl,
+ const struct pxa_desc_pin *ppins, int npins)
+{
+ struct pxa_pinctrl_group *group;
+ struct pinctrl_pin_desc *pins;
+ int ret, i;
+
+ pctl->npins = npins;
+ pctl->ppins = ppins;
+ pctl->ngroups = npins;
+
+ pctl->desc.npins = npins;
+ pins = devm_kcalloc(pctl->dev, npins, sizeof(*pins), GFP_KERNEL);
+ if (!pins)
+ return -ENOMEM;
+
+ pctl->desc.pins = pins;
+ for (i = 0; i < npins; i++)
+ pins[i] = ppins[i].pin;
+
+ pctl->groups = devm_kmalloc_array(pctl->dev, pctl->ngroups,
+ sizeof(*pctl->groups), GFP_KERNEL);
+ if (!pctl->groups)
+ return -ENOMEM;
+
+ for (i = 0; i < npins; i++) {
+ group = pctl->groups + i;
+ group->name = ppins[i].pin.name;
+ group->pin = ppins[i].pin.number;
+ }
+
+ ret = pxa2xx_build_functions(pctl);
+ if (ret)
+ return ret;
+
+ ret = pxa2xx_build_groups(pctl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int pxa2xx_pinctrl_init(struct platform_device *pdev,
+ const struct pxa_desc_pin *ppins, int npins,
+ void __iomem *base_gafr[], void __iomem *base_gpdr[],
+ void __iomem *base_pgsr[])
+{
+ struct pxa_pinctrl *pctl;
+ int ret, i, maxpin = 0;
+
+ for (i = 0; i < npins; i++)
+ maxpin = max_t(int, ppins[i].pin.number, maxpin);
+
+ pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL);
+ if (!pctl)
+ return -ENOMEM;
+ pctl->base_gafr = devm_kcalloc(&pdev->dev, roundup(maxpin, 16),
+ sizeof(*pctl->base_gafr), GFP_KERNEL);
+ pctl->base_gpdr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
+ sizeof(*pctl->base_gpdr), GFP_KERNEL);
+ pctl->base_pgsr = devm_kcalloc(&pdev->dev, roundup(maxpin, 32),
+ sizeof(*pctl->base_pgsr), GFP_KERNEL);
+ if (!pctl->base_gafr || !pctl->base_gpdr || !pctl->base_pgsr)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pctl);
+ spin_lock_init(&pctl->lock);
+
+ pctl->dev = &pdev->dev;
+ pctl->desc = pxa2xx_pinctrl_desc;
+ pctl->desc.name = dev_name(&pdev->dev);
+ pctl->desc.owner = THIS_MODULE;
+
+ for (i = 0; i < roundup(maxpin, 16); i += 16)
+ pctl->base_gafr[i / 16] = base_gafr[i / 16];
+ for (i = 0; i < roundup(maxpin, 32); i += 32) {
+ pctl->base_gpdr[i / 32] = base_gpdr[i / 32];
+ pctl->base_pgsr[i / 32] = base_pgsr[i / 32];
+ }
+
+ ret = pxa2xx_build_state(pctl, ppins, npins);
+ if (ret)
+ return ret;
+
+ pctl->pctl_dev = pinctrl_register(&pctl->desc, &pdev->dev, pctl);
+ if (IS_ERR(pctl->pctl_dev)) {
+ dev_err(&pdev->dev, "couldn't register pinctrl driver\n");
+ return PTR_ERR(pctl->pctl_dev);
+ }
+
+ dev_info(&pdev->dev, "initialized pxa2xx pinctrl driver\n");
+
+ return 0;
+}
+
+int pxa2xx_pinctrl_exit(struct platform_device *pdev)
+{
+ struct pxa_pinctrl *pctl = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(pctl->pctl_dev);
+ return 0;
+}
diff --git a/drivers/pinctrl/pxa/pinctrl-pxa2xx.h b/drivers/pinctrl/pxa/pinctrl-pxa2xx.h
new file mode 100644
index 0000000..8be1e0b
--- /dev/null
+++ b/drivers/pinctrl/pxa/pinctrl-pxa2xx.h
@@ -0,0 +1,92 @@
+/*
+ * Marvell PXA2xx family pin control
+ *
+ * Copyright (C) 2015 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ */
+
+#ifndef __PINCTRL_PXA_H
+#define __PINCTRL_PXA_H
+
+#define PXA_FUNCTION(_dir, _af, _name) \
+ { \
+ .name = _name, \
+ .muxval = (_dir | (_af << 1)), \
+ }
+
+#define PXA_PIN(_pin, funcs...) \
+ { \
+ .pin = _pin, \
+ .functions = (struct pxa_desc_function[]){ \
+ funcs, { } }, \
+ }
+
+#define PXA_GPIO_PIN(_pin, funcs...) \
+ { \
+ .pin = _pin, \
+ .functions = (struct pxa_desc_function[]){ \
+ PXA_FUNCTION(0, 0, "gpio_in"), \
+ PXA_FUNCTION(1, 0, "gpio_out"), \
+ funcs, { } }, \
+ }
+
+#define PXA_GPIO_ONLY_PIN(_pin) \
+ { \
+ .pin = _pin, \
+ .functions = (struct pxa_desc_function[]){ \
+ PXA_FUNCTION(0, 0, "gpio_in"), \
+ PXA_FUNCTION(1, 0, "gpio_out"), \
+ { } }, \
+ }
+
+#define PXA_PINCTRL_PIN(pin) \
+ PINCTRL_PIN(pin, "P" #pin)
+
+struct pxa_desc_function {
+ const char *name;
+ u8 muxval;
+};
+
+struct pxa_desc_pin {
+ struct pinctrl_pin_desc pin;
+ struct pxa_desc_function *functions;
+};
+
+struct pxa_pinctrl_group {
+ const char *name;
+ unsigned pin;
+};
+
+struct pxa_pinctrl_function {
+ const char *name;
+ const char **groups;
+ unsigned ngroups;
+};
+
+struct pxa_pinctrl {
+ spinlock_t lock;
+ void __iomem **base_gafr;
+ void __iomem **base_gpdr;
+ void __iomem **base_pgsr;
+ struct device *dev;
+ struct pinctrl_desc desc;
+ struct pinctrl_dev *pctl_dev;
+ unsigned npins;
+ const struct pxa_desc_pin *ppins;
+ unsigned ngroups;
+ struct pxa_pinctrl_group *groups;
+ unsigned nfuncs;
+ struct pxa_pinctrl_function *functions;
+ char *name;
+};
+
+int pxa2xx_pinctrl_init(struct platform_device *pdev,
+ const struct pxa_desc_pin *ppins, int npins,
+ void __iomem *base_gafr[], void __iomem *base_gpdr[],
+ void __iomem *base_gpsr[]);
+
+#endif /* __PINCTRL_PXA_H */
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 383263a..eeac8cb 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -63,6 +63,14 @@ config PINCTRL_MSM8916
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found on the Qualcomm 8916 platform.
+config PINCTRL_MSM8996
+ tristate "Qualcomm MSM8996 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm TLMM block found in the Qualcomm MSM8996 platform.
+
config PINCTRL_QDF2XXX
tristate "Qualcomm Technologies QDF2xxx pin controller driver"
depends on GPIOLIB && ACPI
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index 13b190e..dfb50a9 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o
+obj-$(CONFIG_PINCTRL_MSM8996) += pinctrl-msm8996.o
obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8996.c b/drivers/pinctrl/qcom/pinctrl-msm8996.c
new file mode 100644
index 0000000..c257927
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8996.c
@@ -0,0 +1,1942 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+#define FUNCTION(fname) \
+ [msm_mux_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define REG_BASE 0x0
+#define REG_SIZE 0x1000
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = (unsigned)ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ msm_mux_gpio, /* gpio mode */ \
+ msm_mux_##f1, \
+ msm_mux_##f2, \
+ msm_mux_##f3, \
+ msm_mux_##f4, \
+ msm_mux_##f5, \
+ msm_mux_##f6, \
+ msm_mux_##f7, \
+ msm_mux_##f8, \
+ msm_mux_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = REG_BASE + REG_SIZE * id, \
+ .io_reg = REG_BASE + 0x4 + REG_SIZE * id, \
+ .intr_cfg_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .intr_status_reg = REG_BASE + 0xc + REG_SIZE * id, \
+ .intr_target_reg = REG_BASE + 0x8 + REG_SIZE * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 3, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_QDSD_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = (unsigned)ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+static const struct pinctrl_pin_desc msm8996_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "GPIO_122"),
+ PINCTRL_PIN(123, "GPIO_123"),
+ PINCTRL_PIN(124, "GPIO_124"),
+ PINCTRL_PIN(125, "GPIO_125"),
+ PINCTRL_PIN(126, "GPIO_126"),
+ PINCTRL_PIN(127, "GPIO_127"),
+ PINCTRL_PIN(128, "GPIO_128"),
+ PINCTRL_PIN(129, "GPIO_129"),
+ PINCTRL_PIN(130, "GPIO_130"),
+ PINCTRL_PIN(131, "GPIO_131"),
+ PINCTRL_PIN(132, "GPIO_132"),
+ PINCTRL_PIN(133, "GPIO_133"),
+ PINCTRL_PIN(134, "GPIO_134"),
+ PINCTRL_PIN(135, "GPIO_135"),
+ PINCTRL_PIN(136, "GPIO_136"),
+ PINCTRL_PIN(137, "GPIO_137"),
+ PINCTRL_PIN(138, "GPIO_138"),
+ PINCTRL_PIN(139, "GPIO_139"),
+ PINCTRL_PIN(140, "GPIO_140"),
+ PINCTRL_PIN(141, "GPIO_141"),
+ PINCTRL_PIN(142, "GPIO_142"),
+ PINCTRL_PIN(143, "GPIO_143"),
+ PINCTRL_PIN(144, "GPIO_144"),
+ PINCTRL_PIN(145, "GPIO_145"),
+ PINCTRL_PIN(146, "GPIO_146"),
+ PINCTRL_PIN(147, "GPIO_147"),
+ PINCTRL_PIN(148, "GPIO_148"),
+ PINCTRL_PIN(149, "GPIO_149"),
+ PINCTRL_PIN(150, "SDC1_CLK"),
+ PINCTRL_PIN(151, "SDC1_CMD"),
+ PINCTRL_PIN(152, "SDC1_DATA"),
+ PINCTRL_PIN(153, "SDC2_CLK"),
+ PINCTRL_PIN(154, "SDC2_CMD"),
+ PINCTRL_PIN(155, "SDC2_DATA"),
+ PINCTRL_PIN(156, "SDC1_RCLK"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+DECLARE_MSM_GPIO_PINS(122);
+DECLARE_MSM_GPIO_PINS(123);
+DECLARE_MSM_GPIO_PINS(124);
+DECLARE_MSM_GPIO_PINS(125);
+DECLARE_MSM_GPIO_PINS(126);
+DECLARE_MSM_GPIO_PINS(127);
+DECLARE_MSM_GPIO_PINS(128);
+DECLARE_MSM_GPIO_PINS(129);
+DECLARE_MSM_GPIO_PINS(130);
+DECLARE_MSM_GPIO_PINS(131);
+DECLARE_MSM_GPIO_PINS(132);
+DECLARE_MSM_GPIO_PINS(133);
+DECLARE_MSM_GPIO_PINS(134);
+DECLARE_MSM_GPIO_PINS(135);
+DECLARE_MSM_GPIO_PINS(136);
+DECLARE_MSM_GPIO_PINS(137);
+DECLARE_MSM_GPIO_PINS(138);
+DECLARE_MSM_GPIO_PINS(139);
+DECLARE_MSM_GPIO_PINS(140);
+DECLARE_MSM_GPIO_PINS(141);
+DECLARE_MSM_GPIO_PINS(142);
+DECLARE_MSM_GPIO_PINS(143);
+DECLARE_MSM_GPIO_PINS(144);
+DECLARE_MSM_GPIO_PINS(145);
+DECLARE_MSM_GPIO_PINS(146);
+DECLARE_MSM_GPIO_PINS(147);
+DECLARE_MSM_GPIO_PINS(148);
+DECLARE_MSM_GPIO_PINS(149);
+
+static const unsigned int sdc1_clk_pins[] = { 150 };
+static const unsigned int sdc1_cmd_pins[] = { 151 };
+static const unsigned int sdc1_data_pins[] = { 152 };
+static const unsigned int sdc2_clk_pins[] = { 153 };
+static const unsigned int sdc2_cmd_pins[] = { 154 };
+static const unsigned int sdc2_data_pins[] = { 155 };
+static const unsigned int sdc1_rclk_pins[] = { 156 };
+
+enum msm8996_functions {
+ msm_mux_adsp_ext,
+ msm_mux_atest_bbrx0,
+ msm_mux_atest_bbrx1,
+ msm_mux_atest_char,
+ msm_mux_atest_char0,
+ msm_mux_atest_char1,
+ msm_mux_atest_char2,
+ msm_mux_atest_char3,
+ msm_mux_atest_gpsadc0,
+ msm_mux_atest_gpsadc1,
+ msm_mux_atest_tsens,
+ msm_mux_atest_tsens2,
+ msm_mux_atest_usb1,
+ msm_mux_atest_usb10,
+ msm_mux_atest_usb11,
+ msm_mux_atest_usb12,
+ msm_mux_atest_usb13,
+ msm_mux_atest_usb2,
+ msm_mux_atest_usb20,
+ msm_mux_atest_usb21,
+ msm_mux_atest_usb22,
+ msm_mux_atest_usb23,
+ msm_mux_audio_ref,
+ msm_mux_bimc_dte0,
+ msm_mux_bimc_dte1,
+ msm_mux_blsp10_spi,
+ msm_mux_blsp11_i2c_scl_b,
+ msm_mux_blsp11_i2c_sda_b,
+ msm_mux_blsp11_uart_rx_b,
+ msm_mux_blsp11_uart_tx_b,
+ msm_mux_blsp1_spi,
+ msm_mux_blsp2_spi,
+ msm_mux_blsp_i2c1,
+ msm_mux_blsp_i2c10,
+ msm_mux_blsp_i2c11,
+ msm_mux_blsp_i2c12,
+ msm_mux_blsp_i2c2,
+ msm_mux_blsp_i2c3,
+ msm_mux_blsp_i2c4,
+ msm_mux_blsp_i2c5,
+ msm_mux_blsp_i2c6,
+ msm_mux_blsp_i2c7,
+ msm_mux_blsp_i2c8,
+ msm_mux_blsp_i2c9,
+ msm_mux_blsp_spi1,
+ msm_mux_blsp_spi10,
+ msm_mux_blsp_spi11,
+ msm_mux_blsp_spi12,
+ msm_mux_blsp_spi2,
+ msm_mux_blsp_spi3,
+ msm_mux_blsp_spi4,
+ msm_mux_blsp_spi5,
+ msm_mux_blsp_spi6,
+ msm_mux_blsp_spi7,
+ msm_mux_blsp_spi8,
+ msm_mux_blsp_spi9,
+ msm_mux_blsp_uart1,
+ msm_mux_blsp_uart10,
+ msm_mux_blsp_uart11,
+ msm_mux_blsp_uart12,
+ msm_mux_blsp_uart2,
+ msm_mux_blsp_uart3,
+ msm_mux_blsp_uart4,
+ msm_mux_blsp_uart5,
+ msm_mux_blsp_uart6,
+ msm_mux_blsp_uart7,
+ msm_mux_blsp_uart8,
+ msm_mux_blsp_uart9,
+ msm_mux_blsp_uim1,
+ msm_mux_blsp_uim10,
+ msm_mux_blsp_uim11,
+ msm_mux_blsp_uim12,
+ msm_mux_blsp_uim2,
+ msm_mux_blsp_uim3,
+ msm_mux_blsp_uim4,
+ msm_mux_blsp_uim5,
+ msm_mux_blsp_uim6,
+ msm_mux_blsp_uim7,
+ msm_mux_blsp_uim8,
+ msm_mux_blsp_uim9,
+ msm_mux_btfm_slimbus,
+ msm_mux_cam_mclk,
+ msm_mux_cci_async,
+ msm_mux_cci_i2c,
+ msm_mux_cci_timer0,
+ msm_mux_cci_timer1,
+ msm_mux_cci_timer2,
+ msm_mux_cci_timer3,
+ msm_mux_cci_timer4,
+ msm_mux_cri_trng,
+ msm_mux_cri_trng0,
+ msm_mux_cri_trng1,
+ msm_mux_dac_calib0,
+ msm_mux_dac_calib1,
+ msm_mux_dac_calib10,
+ msm_mux_dac_calib11,
+ msm_mux_dac_calib12,
+ msm_mux_dac_calib13,
+ msm_mux_dac_calib14,
+ msm_mux_dac_calib15,
+ msm_mux_dac_calib16,
+ msm_mux_dac_calib17,
+ msm_mux_dac_calib18,
+ msm_mux_dac_calib19,
+ msm_mux_dac_calib2,
+ msm_mux_dac_calib20,
+ msm_mux_dac_calib21,
+ msm_mux_dac_calib22,
+ msm_mux_dac_calib23,
+ msm_mux_dac_calib24,
+ msm_mux_dac_calib25,
+ msm_mux_dac_calib26,
+ msm_mux_dac_calib3,
+ msm_mux_dac_calib4,
+ msm_mux_dac_calib5,
+ msm_mux_dac_calib6,
+ msm_mux_dac_calib7,
+ msm_mux_dac_calib8,
+ msm_mux_dac_calib9,
+ msm_mux_dac_gpio,
+ msm_mux_dbg_out,
+ msm_mux_ddr_bist,
+ msm_mux_edp_hot,
+ msm_mux_edp_lcd,
+ msm_mux_gcc_gp1_clk_a,
+ msm_mux_gcc_gp1_clk_b,
+ msm_mux_gcc_gp2_clk_a,
+ msm_mux_gcc_gp2_clk_b,
+ msm_mux_gcc_gp3_clk_a,
+ msm_mux_gcc_gp3_clk_b,
+ msm_mux_gsm_tx,
+ msm_mux_hdmi_cec,
+ msm_mux_hdmi_ddc,
+ msm_mux_hdmi_hot,
+ msm_mux_hdmi_rcv,
+ msm_mux_isense_dbg,
+ msm_mux_ldo_en,
+ msm_mux_ldo_update,
+ msm_mux_lpass_slimbus,
+ msm_mux_m_voc,
+ msm_mux_mdp_vsync,
+ msm_mux_mdp_vsync_p_b,
+ msm_mux_mdp_vsync_s_b,
+ msm_mux_modem_tsync,
+ msm_mux_mss_lte,
+ msm_mux_nav_dr,
+ msm_mux_nav_pps,
+ msm_mux_pa_indicator,
+ msm_mux_pci_e0,
+ msm_mux_pci_e1,
+ msm_mux_pci_e2,
+ msm_mux_pll_bypassnl,
+ msm_mux_pll_reset,
+ msm_mux_pri_mi2s,
+ msm_mux_prng_rosc,
+ msm_mux_pwr_crypto,
+ msm_mux_pwr_modem,
+ msm_mux_pwr_nav,
+ msm_mux_qdss_cti,
+ msm_mux_qdss_cti_trig_in_a,
+ msm_mux_qdss_cti_trig_in_b,
+ msm_mux_qdss_cti_trig_out_a,
+ msm_mux_qdss_cti_trig_out_b,
+ msm_mux_qdss_stm0,
+ msm_mux_qdss_stm1,
+ msm_mux_qdss_stm10,
+ msm_mux_qdss_stm11,
+ msm_mux_qdss_stm12,
+ msm_mux_qdss_stm13,
+ msm_mux_qdss_stm14,
+ msm_mux_qdss_stm15,
+ msm_mux_qdss_stm16,
+ msm_mux_qdss_stm17,
+ msm_mux_qdss_stm18,
+ msm_mux_qdss_stm19,
+ msm_mux_qdss_stm2,
+ msm_mux_qdss_stm20,
+ msm_mux_qdss_stm21,
+ msm_mux_qdss_stm22,
+ msm_mux_qdss_stm23,
+ msm_mux_qdss_stm24,
+ msm_mux_qdss_stm25,
+ msm_mux_qdss_stm26,
+ msm_mux_qdss_stm27,
+ msm_mux_qdss_stm28,
+ msm_mux_qdss_stm29,
+ msm_mux_qdss_stm3,
+ msm_mux_qdss_stm30,
+ msm_mux_qdss_stm31,
+ msm_mux_qdss_stm4,
+ msm_mux_qdss_stm5,
+ msm_mux_qdss_stm6,
+ msm_mux_qdss_stm7,
+ msm_mux_qdss_stm8,
+ msm_mux_qdss_stm9,
+ msm_mux_qdss_traceclk_a,
+ msm_mux_qdss_traceclk_b,
+ msm_mux_qdss_tracectl_a,
+ msm_mux_qdss_tracectl_b,
+ msm_mux_qdss_tracedata_11,
+ msm_mux_qdss_tracedata_12,
+ msm_mux_qdss_tracedata_a,
+ msm_mux_qdss_tracedata_b,
+ msm_mux_qspi0,
+ msm_mux_qspi1,
+ msm_mux_qspi2,
+ msm_mux_qspi3,
+ msm_mux_qspi_clk,
+ msm_mux_qspi_cs,
+ msm_mux_qua_mi2s,
+ msm_mux_sd_card,
+ msm_mux_sd_write,
+ msm_mux_sdc40,
+ msm_mux_sdc41,
+ msm_mux_sdc42,
+ msm_mux_sdc43,
+ msm_mux_sdc4_clk,
+ msm_mux_sdc4_cmd,
+ msm_mux_sec_mi2s,
+ msm_mux_spkr_i2s,
+ msm_mux_ssbi1,
+ msm_mux_ssbi2,
+ msm_mux_ssc_irq,
+ msm_mux_ter_mi2s,
+ msm_mux_tsense_pwm1,
+ msm_mux_tsense_pwm2,
+ msm_mux_tsif1_clk,
+ msm_mux_tsif1_data,
+ msm_mux_tsif1_en,
+ msm_mux_tsif1_error,
+ msm_mux_tsif1_sync,
+ msm_mux_tsif2_clk,
+ msm_mux_tsif2_data,
+ msm_mux_tsif2_en,
+ msm_mux_tsif2_error,
+ msm_mux_tsif2_sync,
+ msm_mux_uim1,
+ msm_mux_uim2,
+ msm_mux_uim3,
+ msm_mux_uim4,
+ msm_mux_uim_batt,
+ msm_mux_vfr_1,
+ msm_mux_gpio,
+ msm_mux_NA,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7",
+ "gpio8", "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14",
+ "gpio15", "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21",
+ "gpio22", "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28",
+ "gpio29", "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35",
+ "gpio36", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121", "gpio122",
+ "gpio123", "gpio124", "gpio125", "gpio126", "gpio127", "gpio128",
+ "gpio129", "gpio130", "gpio131", "gpio132", "gpio133", "gpio134",
+ "gpio135", "gpio136", "gpio137", "gpio138", "gpio139", "gpio140",
+ "gpio141", "gpio142", "gpio143", "gpio144", "gpio145", "gpio146",
+ "gpio147", "gpio148", "gpio149"
+};
+
+
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3",
+};
+static const char * const blsp_i2c1_groups[] = {
+ "gpio2", "gpio3",
+};
+static const char * const blsp_uim1_groups[] = {
+ "gpio0", "gpio1",
+};
+static const char * const atest_tsens_groups[] = {
+ "gpio3",
+};
+static const char * const bimc_dte1_groups[] = {
+ "gpio3", "gpio5",
+};
+static const char * const blsp_spi8_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uart8_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7",
+};
+static const char * const blsp_uim8_groups[] = {
+ "gpio4", "gpio5",
+};
+static const char * const qdss_cti_trig_out_b_groups[] = {
+ "gpio4",
+};
+static const char * const dac_calib0_groups[] = {
+ "gpio4", "gpio41",
+};
+static const char * const bimc_dte0_groups[] = {
+ "gpio4", "gpio6",
+};
+static const char * const qdss_cti_trig_in_b_groups[] = {
+ "gpio5",
+};
+static const char * const dac_calib1_groups[] = {
+ "gpio5", "gpio42",
+};
+static const char * const dac_calib2_groups[] = {
+ "gpio6", "gpio43",
+};
+static const char * const atest_tsens2_groups[] = {
+ "gpio7",
+};
+static const char * const blsp_spi10_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_uart10_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11",
+};
+static const char * const blsp_uim10_groups[] = {
+ "gpio8", "gpio9",
+};
+static const char * const atest_bbrx1_groups[] = {
+ "gpio8",
+};
+static const char * const atest_usb12_groups[] = {
+ "gpio9",
+};
+static const char * const mdp_vsync_groups[] = {
+ "gpio10", "gpio11", "gpio12",
+};
+static const char * const edp_lcd_groups[] = {
+ "gpio10",
+};
+static const char * const blsp_i2c10_groups[] = {
+ "gpio10", "gpio11",
+};
+static const char * const atest_usb11_groups[] = {
+ "gpio10",
+};
+static const char * const atest_gpsadc0_groups[] = {
+ "gpio11",
+};
+static const char * const edp_hot_groups[] = {
+ "gpio11",
+};
+static const char * const atest_usb10_groups[] = {
+ "gpio11",
+};
+static const char * const m_voc_groups[] = {
+ "gpio12",
+};
+static const char * const dac_gpio_groups[] = {
+ "gpio12",
+};
+static const char * const atest_char_groups[] = {
+ "gpio12",
+};
+static const char * const cam_mclk_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16",
+};
+static const char * const pll_bypassnl_groups[] = {
+ "gpio13",
+};
+static const char * const qdss_stm7_groups[] = {
+ "gpio13",
+};
+static const char * const blsp_i2c8_groups[] = {
+ "gpio6", "gpio7",
+};
+static const char * const atest_usb1_groups[] = {
+ "gpio7",
+};
+static const char * const atest_usb13_groups[] = {
+ "gpio8",
+};
+static const char * const atest_bbrx0_groups[] = {
+ "gpio9",
+};
+static const char * const atest_gpsadc1_groups[] = {
+ "gpio10",
+};
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio13", "gpio14", "gpio15", "gpio16", "gpio17", "gpio18", "gpio19",
+ "gpio21", "gpio22", "gpio23", "gpio26", "gpio29", "gpio57", "gpio58",
+ "gpio92", "gpio93",
+};
+static const char * const pll_reset_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_stm6_groups[] = {
+ "gpio14",
+};
+static const char * const qdss_stm5_groups[] = {
+ "gpio15",
+};
+static const char * const qdss_stm4_groups[] = {
+ "gpio16",
+};
+static const char * const atest_usb2_groups[] = {
+ "gpio16",
+};
+static const char * const dac_calib3_groups[] = {
+ "gpio17", "gpio44",
+};
+static const char * const cci_i2c_groups[] = {
+ "gpio17", "gpio18", "gpio19", "gpio20",
+};
+static const char * const qdss_stm3_groups[] = {
+ "gpio17",
+};
+static const char * const atest_usb23_groups[] = {
+ "gpio17",
+};
+static const char * const atest_char3_groups[] = {
+ "gpio17",
+};
+static const char * const dac_calib4_groups[] = {
+ "gpio18", "gpio45",
+};
+static const char * const qdss_stm2_groups[] = {
+ "gpio18",
+};
+static const char * const atest_usb22_groups[] = {
+ "gpio18",
+};
+static const char * const atest_char2_groups[] = {
+ "gpio18",
+};
+static const char * const dac_calib5_groups[] = {
+ "gpio19", "gpio46",
+};
+static const char * const qdss_stm1_groups[] = {
+ "gpio19",
+};
+static const char * const atest_usb21_groups[] = {
+ "gpio19",
+};
+static const char * const atest_char1_groups[] = {
+ "gpio19",
+};
+static const char * const dac_calib6_groups[] = {
+ "gpio20", "gpio47",
+};
+static const char * const dbg_out_groups[] = {
+ "gpio20",
+};
+static const char * const qdss_stm0_groups[] = {
+ "gpio20",
+};
+static const char * const atest_usb20_groups[] = {
+ "gpio20",
+};
+static const char * const atest_char0_groups[] = {
+ "gpio20",
+};
+static const char * const dac_calib7_groups[] = {
+ "gpio21", "gpio48",
+};
+static const char * const cci_timer0_groups[] = {
+ "gpio21",
+};
+static const char * const qdss_stm13_groups[] = {
+ "gpio21",
+};
+static const char * const dac_calib8_groups[] = {
+ "gpio22", "gpio49",
+};
+static const char * const cci_timer1_groups[] = {
+ "gpio22",
+};
+static const char * const qdss_stm12_groups[] = {
+ "gpio22",
+};
+static const char * const dac_calib9_groups[] = {
+ "gpio23", "gpio50",
+};
+static const char * const cci_timer2_groups[] = {
+ "gpio23",
+};
+static const char * const qdss_stm11_groups[] = {
+ "gpio23",
+};
+static const char * const dac_calib10_groups[] = {
+ "gpio24", "gpio51",
+};
+static const char * const cci_timer3_groups[] = {
+ "gpio24",
+};
+static const char * const cci_async_groups[] = {
+ "gpio24", "gpio25", "gpio26",
+};
+static const char * const blsp1_spi_groups[] = {
+ "gpio24", "gpio27", "gpio28", "gpio90",
+};
+static const char * const qdss_stm10_groups[] = {
+ "gpio24",
+};
+static const char * const qdss_cti_trig_in_a_groups[] = {
+ "gpio24",
+};
+static const char * const dac_calib11_groups[] = {
+ "gpio25", "gpio52",
+};
+static const char * const cci_timer4_groups[] = {
+ "gpio25",
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28",
+};
+static const char * const blsp_uart6_groups[] = {
+ "gpio25", "gpio26", "gpio27", "gpio28",
+};
+static const char * const blsp_uim6_groups[] = {
+ "gpio25", "gpio26",
+};
+static const char * const blsp2_spi_groups[] = {
+ "gpio25", "gpio29", "gpio30",
+};
+static const char * const qdss_stm9_groups[] = {
+ "gpio25",
+};
+static const char * const qdss_cti_trig_out_a_groups[] = {
+ "gpio25",
+};
+static const char * const dac_calib12_groups[] = {
+ "gpio26", "gpio53",
+};
+static const char * const qdss_stm8_groups[] = {
+ "gpio26",
+};
+static const char * const dac_calib13_groups[] = {
+ "gpio27", "gpio54",
+};
+static const char * const blsp_i2c6_groups[] = {
+ "gpio27", "gpio28",
+};
+static const char * const qdss_tracectl_a_groups[] = {
+ "gpio27",
+};
+static const char * const dac_calib14_groups[] = {
+ "gpio28", "gpio55",
+};
+static const char * const qdss_traceclk_a_groups[] = {
+ "gpio28",
+};
+static const char * const dac_calib15_groups[] = {
+ "gpio29", "gpio56",
+};
+static const char * const dac_calib16_groups[] = {
+ "gpio30", "gpio57",
+};
+static const char * const hdmi_rcv_groups[] = {
+ "gpio30",
+};
+static const char * const dac_calib17_groups[] = {
+ "gpio31", "gpio58",
+};
+static const char * const pwr_modem_groups[] = {
+ "gpio31",
+};
+static const char * const hdmi_cec_groups[] = {
+ "gpio31",
+};
+static const char * const pwr_nav_groups[] = {
+ "gpio32",
+};
+static const char * const dac_calib18_groups[] = {
+ "gpio32", "gpio59",
+};
+static const char * const hdmi_ddc_groups[] = {
+ "gpio32", "gpio33",
+};
+static const char * const pwr_crypto_groups[] = {
+ "gpio33",
+};
+static const char * const dac_calib19_groups[] = {
+ "gpio33", "gpio60",
+};
+static const char * const dac_calib20_groups[] = {
+ "gpio34", "gpio61",
+};
+static const char * const hdmi_hot_groups[] = {
+ "gpio34",
+};
+static const char * const dac_calib21_groups[] = {
+ "gpio35", "gpio62",
+};
+static const char * const pci_e0_groups[] = {
+ "gpio35", "gpio36",
+};
+static const char * const dac_calib22_groups[] = {
+ "gpio36", "gpio63",
+};
+static const char * const dac_calib23_groups[] = {
+ "gpio37", "gpio64",
+};
+static const char * const blsp_i2c2_groups[] = {
+ "gpio43", "gpio44",
+};
+static const char * const blsp_spi3_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const blsp_uart3_groups[] = {
+ "gpio45", "gpio46", "gpio47", "gpio48",
+};
+static const char * const blsp_uim3_groups[] = {
+ "gpio45", "gpio46",
+};
+static const char * const blsp_i2c3_groups[] = {
+ "gpio47", "gpio48",
+};
+static const char * const dac_calib24_groups[] = {
+ "gpio38", "gpio65",
+};
+static const char * const dac_calib25_groups[] = {
+ "gpio39", "gpio66",
+};
+static const char * const tsif1_sync_groups[] = {
+ "gpio39",
+};
+static const char * const sd_write_groups[] = {
+ "gpio40",
+};
+static const char * const tsif1_error_groups[] = {
+ "gpio40",
+};
+static const char * const blsp_spi2_groups[] = {
+ "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio41", "gpio42", "gpio43", "gpio44",
+};
+static const char * const blsp_uim2_groups[] = {
+ "gpio41", "gpio42",
+};
+static const char * const qdss_cti_groups[] = {
+ "gpio41", "gpio42", "gpio100", "gpio101",
+};
+static const char * const uim3_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_spi9_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_uart9_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52",
+};
+static const char * const blsp_uim9_groups[] = {
+ "gpio49", "gpio50",
+};
+static const char * const blsp10_spi_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52", "gpio88",
+};
+static const char * const blsp_i2c9_groups[] = {
+ "gpio51", "gpio52",
+};
+static const char * const blsp_spi7_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const blsp_uart7_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56",
+};
+static const char * const blsp_uim7_groups[] = {
+ "gpio53", "gpio54",
+};
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio53", "gpio54", "gpio63", "gpio64", "gpio65", "gpio66", "gpio67",
+ "gpio74", "gpio75", "gpio76", "gpio77", "gpio85", "gpio86", "gpio87",
+ "gpio89", "gpio90",
+};
+static const char * const blsp_i2c7_groups[] = {
+ "gpio55", "gpio56",
+};
+static const char * const qua_mi2s_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+};
+static const char * const gcc_gp1_clk_a_groups[] = {
+ "gpio57",
+};
+static const char * const uim4_groups[] = {
+ "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_spi11_groups[] = {
+ "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_uart11_groups[] = {
+ "gpio58", "gpio59", "gpio60", "gpio61",
+};
+static const char * const blsp_uim11_groups[] = {
+ "gpio58", "gpio59",
+};
+static const char * const gcc_gp2_clk_a_groups[] = {
+ "gpio58",
+};
+static const char * const gcc_gp3_clk_a_groups[] = {
+ "gpio59",
+};
+static const char * const blsp_i2c11_groups[] = {
+ "gpio60", "gpio61",
+};
+static const char * const cri_trng0_groups[] = {
+ "gpio60",
+};
+static const char * const cri_trng1_groups[] = {
+ "gpio61",
+};
+static const char * const cri_trng_groups[] = {
+ "gpio62",
+};
+static const char * const qdss_stm18_groups[] = {
+ "gpio63",
+};
+static const char * const pri_mi2s_groups[] = {
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const qdss_stm17_groups[] = {
+ "gpio64",
+};
+static const char * const blsp_spi4_groups[] = {
+ "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const blsp_uart4_groups[] = {
+ "gpio65", "gpio66", "gpio67", "gpio68",
+};
+static const char * const blsp_uim4_groups[] = {
+ "gpio65", "gpio66",
+};
+static const char * const qdss_stm16_groups[] = {
+ "gpio65",
+};
+static const char * const qdss_stm15_groups[] = {
+ "gpio66",
+};
+static const char * const dac_calib26_groups[] = {
+ "gpio67",
+};
+static const char * const blsp_i2c4_groups[] = {
+ "gpio67", "gpio68",
+};
+static const char * const qdss_stm14_groups[] = {
+ "gpio67",
+};
+static const char * const spkr_i2s_groups[] = {
+ "gpio69", "gpio70", "gpio71", "gpio72",
+};
+static const char * const audio_ref_groups[] = {
+ "gpio69",
+};
+static const char * const lpass_slimbus_groups[] = {
+ "gpio70", "gpio71", "gpio72",
+};
+static const char * const isense_dbg_groups[] = {
+ "gpio70",
+};
+static const char * const tsense_pwm1_groups[] = {
+ "gpio71",
+};
+static const char * const tsense_pwm2_groups[] = {
+ "gpio71",
+};
+static const char * const btfm_slimbus_groups[] = {
+ "gpio73", "gpio74",
+};
+static const char * const ter_mi2s_groups[] = {
+ "gpio74", "gpio75", "gpio76", "gpio77", "gpio78",
+};
+static const char * const qdss_stm22_groups[] = {
+ "gpio74",
+};
+static const char * const qdss_stm21_groups[] = {
+ "gpio75",
+};
+static const char * const qdss_stm20_groups[] = {
+ "gpio76",
+};
+static const char * const qdss_stm19_groups[] = {
+ "gpio77",
+};
+static const char * const ssc_irq_groups[] = {
+ "gpio78", "gpio79", "gpio80", "gpio117", "gpio118", "gpio119",
+ "gpio120", "gpio121", "gpio122", "gpio123", "gpio124", "gpio125",
+};
+static const char * const gcc_gp1_clk_b_groups[] = {
+ "gpio78",
+};
+static const char * const sec_mi2s_groups[] = {
+ "gpio79", "gpio80", "gpio81", "gpio82", "gpio83",
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const blsp_uart5_groups[] = {
+ "gpio81", "gpio82", "gpio83", "gpio84",
+};
+static const char * const blsp_uim5_groups[] = {
+ "gpio81", "gpio82",
+};
+static const char * const gcc_gp2_clk_b_groups[] = {
+ "gpio81",
+};
+static const char * const gcc_gp3_clk_b_groups[] = {
+ "gpio82",
+};
+static const char * const blsp_i2c5_groups[] = {
+ "gpio83", "gpio84",
+};
+static const char * const blsp_spi12_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uart12_groups[] = {
+ "gpio85", "gpio86", "gpio87", "gpio88",
+};
+static const char * const blsp_uim12_groups[] = {
+ "gpio85", "gpio86",
+};
+static const char * const qdss_stm25_groups[] = {
+ "gpio85",
+};
+static const char * const qdss_stm31_groups[] = {
+ "gpio86",
+};
+static const char * const blsp_i2c12_groups[] = {
+ "gpio87", "gpio88",
+};
+static const char * const qdss_stm30_groups[] = {
+ "gpio87",
+};
+static const char * const qdss_stm29_groups[] = {
+ "gpio88",
+};
+static const char * const tsif1_clk_groups[] = {
+ "gpio89",
+};
+static const char * const qdss_stm28_groups[] = {
+ "gpio89",
+};
+static const char * const tsif1_en_groups[] = {
+ "gpio90",
+};
+static const char * const tsif1_data_groups[] = {
+ "gpio91",
+};
+static const char * const sdc4_cmd_groups[] = {
+ "gpio91",
+};
+static const char * const qdss_stm27_groups[] = {
+ "gpio91",
+};
+static const char * const qdss_traceclk_b_groups[] = {
+ "gpio91",
+};
+static const char * const tsif2_error_groups[] = {
+ "gpio92",
+};
+static const char * const sdc43_groups[] = {
+ "gpio92",
+};
+static const char * const vfr_1_groups[] = {
+ "gpio92",
+};
+static const char * const qdss_stm26_groups[] = {
+ "gpio92",
+};
+static const char * const tsif2_clk_groups[] = {
+ "gpio93",
+};
+static const char * const sdc4_clk_groups[] = {
+ "gpio93",
+};
+static const char * const qdss_stm24_groups[] = {
+ "gpio93",
+};
+static const char * const tsif2_en_groups[] = {
+ "gpio94",
+};
+static const char * const sdc42_groups[] = {
+ "gpio94",
+};
+static const char * const qdss_stm23_groups[] = {
+ "gpio94",
+};
+static const char * const qdss_tracectl_b_groups[] = {
+ "gpio94",
+};
+static const char * const sd_card_groups[] = {
+ "gpio95",
+};
+static const char * const tsif2_data_groups[] = {
+ "gpio95",
+};
+static const char * const sdc41_groups[] = {
+ "gpio95",
+};
+static const char * const tsif2_sync_groups[] = {
+ "gpio96",
+};
+static const char * const sdc40_groups[] = {
+ "gpio96",
+};
+static const char * const mdp_vsync_p_b_groups[] = {
+ "gpio97",
+};
+static const char * const ldo_en_groups[] = {
+ "gpio97",
+};
+static const char * const mdp_vsync_s_b_groups[] = {
+ "gpio98",
+};
+static const char * const ldo_update_groups[] = {
+ "gpio98",
+};
+static const char * const blsp11_uart_tx_b_groups[] = {
+ "gpio100",
+};
+static const char * const blsp11_uart_rx_b_groups[] = {
+ "gpio101",
+};
+static const char * const blsp11_i2c_sda_b_groups[] = {
+ "gpio102",
+};
+static const char * const prng_rosc_groups[] = {
+ "gpio102",
+};
+static const char * const blsp11_i2c_scl_b_groups[] = {
+ "gpio103",
+};
+static const char * const uim2_groups[] = {
+ "gpio105", "gpio106", "gpio107", "gpio108",
+};
+static const char * const uim1_groups[] = {
+ "gpio109", "gpio110", "gpio111", "gpio112",
+};
+static const char * const uim_batt_groups[] = {
+ "gpio113",
+};
+static const char * const pci_e2_groups[] = {
+ "gpio114", "gpio115", "gpio116",
+};
+static const char * const pa_indicator_groups[] = {
+ "gpio116",
+};
+static const char * const adsp_ext_groups[] = {
+ "gpio118",
+};
+static const char * const ddr_bist_groups[] = {
+ "gpio121", "gpio122", "gpio123", "gpio124",
+};
+static const char * const qdss_tracedata_11_groups[] = {
+ "gpio123",
+};
+static const char * const qdss_tracedata_12_groups[] = {
+ "gpio124",
+};
+static const char * const modem_tsync_groups[] = {
+ "gpio128",
+};
+static const char * const nav_dr_groups[] = {
+ "gpio128",
+};
+static const char * const nav_pps_groups[] = {
+ "gpio128",
+};
+static const char * const pci_e1_groups[] = {
+ "gpio130", "gpio131", "gpio132",
+};
+static const char * const gsm_tx_groups[] = {
+ "gpio134", "gpio135",
+};
+static const char * const qspi_cs_groups[] = {
+ "gpio138", "gpio141",
+};
+static const char * const ssbi2_groups[] = {
+ "gpio139",
+};
+static const char * const ssbi1_groups[] = {
+ "gpio140",
+};
+static const char * const mss_lte_groups[] = {
+ "gpio144", "gpio145",
+};
+static const char * const qspi_clk_groups[] = {
+ "gpio145",
+};
+static const char * const qspi0_groups[] = {
+ "gpio146",
+};
+static const char * const qspi1_groups[] = {
+ "gpio147",
+};
+static const char * const qspi2_groups[] = {
+ "gpio148",
+};
+static const char * const qspi3_groups[] = {
+ "gpio149",
+};
+
+static const struct msm_function msm8996_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_gpsadc0),
+ FUNCTION(atest_gpsadc1),
+ FUNCTION(atest_tsens),
+ FUNCTION(atest_tsens2),
+ FUNCTION(atest_usb1),
+ FUNCTION(atest_usb10),
+ FUNCTION(atest_usb11),
+ FUNCTION(atest_usb12),
+ FUNCTION(atest_usb13),
+ FUNCTION(atest_usb2),
+ FUNCTION(atest_usb20),
+ FUNCTION(atest_usb21),
+ FUNCTION(atest_usb22),
+ FUNCTION(atest_usb23),
+ FUNCTION(audio_ref),
+ FUNCTION(bimc_dte0),
+ FUNCTION(bimc_dte1),
+ FUNCTION(blsp10_spi),
+ FUNCTION(blsp11_i2c_scl_b),
+ FUNCTION(blsp11_i2c_sda_b),
+ FUNCTION(blsp11_uart_rx_b),
+ FUNCTION(blsp11_uart_tx_b),
+ FUNCTION(blsp1_spi),
+ FUNCTION(blsp2_spi),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_i2c10),
+ FUNCTION(blsp_i2c11),
+ FUNCTION(blsp_i2c12),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(blsp_i2c7),
+ FUNCTION(blsp_i2c8),
+ FUNCTION(blsp_i2c9),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi10),
+ FUNCTION(blsp_spi11),
+ FUNCTION(blsp_spi12),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_spi7),
+ FUNCTION(blsp_spi8),
+ FUNCTION(blsp_spi9),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_uart10),
+ FUNCTION(blsp_uart11),
+ FUNCTION(blsp_uart12),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uart3),
+ FUNCTION(blsp_uart4),
+ FUNCTION(blsp_uart5),
+ FUNCTION(blsp_uart6),
+ FUNCTION(blsp_uart7),
+ FUNCTION(blsp_uart8),
+ FUNCTION(blsp_uart9),
+ FUNCTION(blsp_uim1),
+ FUNCTION(blsp_uim10),
+ FUNCTION(blsp_uim11),
+ FUNCTION(blsp_uim12),
+ FUNCTION(blsp_uim2),
+ FUNCTION(blsp_uim3),
+ FUNCTION(blsp_uim4),
+ FUNCTION(blsp_uim5),
+ FUNCTION(blsp_uim6),
+ FUNCTION(blsp_uim7),
+ FUNCTION(blsp_uim8),
+ FUNCTION(blsp_uim9),
+ FUNCTION(btfm_slimbus),
+ FUNCTION(cam_mclk),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cci_timer3),
+ FUNCTION(cci_timer4),
+ FUNCTION(cri_trng),
+ FUNCTION(cri_trng0),
+ FUNCTION(cri_trng1),
+ FUNCTION(dac_calib0),
+ FUNCTION(dac_calib1),
+ FUNCTION(dac_calib10),
+ FUNCTION(dac_calib11),
+ FUNCTION(dac_calib12),
+ FUNCTION(dac_calib13),
+ FUNCTION(dac_calib14),
+ FUNCTION(dac_calib15),
+ FUNCTION(dac_calib16),
+ FUNCTION(dac_calib17),
+ FUNCTION(dac_calib18),
+ FUNCTION(dac_calib19),
+ FUNCTION(dac_calib2),
+ FUNCTION(dac_calib20),
+ FUNCTION(dac_calib21),
+ FUNCTION(dac_calib22),
+ FUNCTION(dac_calib23),
+ FUNCTION(dac_calib24),
+ FUNCTION(dac_calib25),
+ FUNCTION(dac_calib26),
+ FUNCTION(dac_calib3),
+ FUNCTION(dac_calib4),
+ FUNCTION(dac_calib5),
+ FUNCTION(dac_calib6),
+ FUNCTION(dac_calib7),
+ FUNCTION(dac_calib8),
+ FUNCTION(dac_calib9),
+ FUNCTION(dac_gpio),
+ FUNCTION(dbg_out),
+ FUNCTION(ddr_bist),
+ FUNCTION(edp_hot),
+ FUNCTION(edp_lcd),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(gpio),
+ FUNCTION(gsm_tx),
+ FUNCTION(hdmi_cec),
+ FUNCTION(hdmi_ddc),
+ FUNCTION(hdmi_hot),
+ FUNCTION(hdmi_rcv),
+ FUNCTION(isense_dbg),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(lpass_slimbus),
+ FUNCTION(m_voc),
+ FUNCTION(mdp_vsync),
+ FUNCTION(mdp_vsync_p_b),
+ FUNCTION(mdp_vsync_s_b),
+ FUNCTION(modem_tsync),
+ FUNCTION(mss_lte),
+ FUNCTION(nav_dr),
+ FUNCTION(nav_pps),
+ FUNCTION(pa_indicator),
+ FUNCTION(pci_e0),
+ FUNCTION(pci_e1),
+ FUNCTION(pci_e2),
+ FUNCTION(pll_bypassnl),
+ FUNCTION(pll_reset),
+ FUNCTION(pri_mi2s),
+ FUNCTION(prng_rosc),
+ FUNCTION(pwr_crypto),
+ FUNCTION(pwr_modem),
+ FUNCTION(pwr_nav),
+ FUNCTION(qdss_cti),
+ FUNCTION(qdss_cti_trig_in_a),
+ FUNCTION(qdss_cti_trig_in_b),
+ FUNCTION(qdss_cti_trig_out_a),
+ FUNCTION(qdss_cti_trig_out_b),
+ FUNCTION(qdss_stm0),
+ FUNCTION(qdss_stm1),
+ FUNCTION(qdss_stm10),
+ FUNCTION(qdss_stm11),
+ FUNCTION(qdss_stm12),
+ FUNCTION(qdss_stm13),
+ FUNCTION(qdss_stm14),
+ FUNCTION(qdss_stm15),
+ FUNCTION(qdss_stm16),
+ FUNCTION(qdss_stm17),
+ FUNCTION(qdss_stm18),
+ FUNCTION(qdss_stm19),
+ FUNCTION(qdss_stm2),
+ FUNCTION(qdss_stm20),
+ FUNCTION(qdss_stm21),
+ FUNCTION(qdss_stm22),
+ FUNCTION(qdss_stm23),
+ FUNCTION(qdss_stm24),
+ FUNCTION(qdss_stm25),
+ FUNCTION(qdss_stm26),
+ FUNCTION(qdss_stm27),
+ FUNCTION(qdss_stm28),
+ FUNCTION(qdss_stm29),
+ FUNCTION(qdss_stm3),
+ FUNCTION(qdss_stm30),
+ FUNCTION(qdss_stm31),
+ FUNCTION(qdss_stm4),
+ FUNCTION(qdss_stm5),
+ FUNCTION(qdss_stm6),
+ FUNCTION(qdss_stm7),
+ FUNCTION(qdss_stm8),
+ FUNCTION(qdss_stm9),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(qdss_tracedata_11),
+ FUNCTION(qdss_tracedata_12),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(qspi0),
+ FUNCTION(qspi1),
+ FUNCTION(qspi2),
+ FUNCTION(qspi3),
+ FUNCTION(qspi_clk),
+ FUNCTION(qspi_cs),
+ FUNCTION(qua_mi2s),
+ FUNCTION(sd_card),
+ FUNCTION(sd_write),
+ FUNCTION(sdc40),
+ FUNCTION(sdc41),
+ FUNCTION(sdc42),
+ FUNCTION(sdc43),
+ FUNCTION(sdc4_clk),
+ FUNCTION(sdc4_cmd),
+ FUNCTION(sec_mi2s),
+ FUNCTION(spkr_i2s),
+ FUNCTION(ssbi1),
+ FUNCTION(ssbi2),
+ FUNCTION(ssc_irq),
+ FUNCTION(ter_mi2s),
+ FUNCTION(tsense_pwm1),
+ FUNCTION(tsense_pwm2),
+ FUNCTION(tsif1_clk),
+ FUNCTION(tsif1_data),
+ FUNCTION(tsif1_en),
+ FUNCTION(tsif1_error),
+ FUNCTION(tsif1_sync),
+ FUNCTION(tsif2_clk),
+ FUNCTION(tsif2_data),
+ FUNCTION(tsif2_en),
+ FUNCTION(tsif2_error),
+ FUNCTION(tsif2_sync),
+ FUNCTION(uim1),
+ FUNCTION(uim2),
+ FUNCTION(uim3),
+ FUNCTION(uim4),
+ FUNCTION(uim_batt),
+ FUNCTION(vfr_1),
+};
+
+static const struct msm_pingroup msm8996_groups[] = {
+ PINGROUP(0, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(1, blsp_spi1, blsp_uart1, blsp_uim1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, atest_tsens,
+ bimc_dte1, NA, NA, NA),
+ PINGROUP(4, blsp_spi8, blsp_uart8, blsp_uim8, NA, qdss_cti_trig_out_b,
+ dac_calib0, bimc_dte0, NA, NA),
+ PINGROUP(5, blsp_spi8, blsp_uart8, blsp_uim8, NA, qdss_cti_trig_in_b,
+ dac_calib1, bimc_dte1, NA, NA),
+ PINGROUP(6, blsp_spi8, blsp_uart8, blsp_i2c8, NA, dac_calib2,
+ bimc_dte0, NA, NA, NA),
+ PINGROUP(7, blsp_spi8, blsp_uart8, blsp_i2c8, NA, atest_tsens2,
+ atest_usb1, NA, NA, NA),
+ PINGROUP(8, blsp_spi10, blsp_uart10, blsp_uim10, NA, atest_bbrx1,
+ atest_usb13, NA, NA, NA),
+ PINGROUP(9, blsp_spi10, blsp_uart10, blsp_uim10, atest_bbrx0,
+ atest_usb12, NA, NA, NA, NA),
+ PINGROUP(10, mdp_vsync, blsp_spi10, blsp_uart10, blsp_i2c10,
+ atest_gpsadc1, atest_usb11, NA, NA, NA),
+ PINGROUP(11, mdp_vsync, blsp_spi10, blsp_uart10, blsp_i2c10,
+ atest_gpsadc0, atest_usb10, NA, NA, NA),
+ PINGROUP(12, mdp_vsync, m_voc, dac_gpio, atest_char, NA, NA, NA, NA,
+ NA),
+ PINGROUP(13, cam_mclk, pll_bypassnl, qdss_stm7, qdss_tracedata_b, NA,
+ NA, NA, NA, NA),
+ PINGROUP(14, cam_mclk, pll_reset, qdss_stm6, qdss_tracedata_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(15, cam_mclk, qdss_stm5, qdss_tracedata_b, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(16, cam_mclk, qdss_stm4, qdss_tracedata_b, NA, atest_usb2, NA,
+ NA, NA, NA),
+ PINGROUP(17, cci_i2c, qdss_stm3, qdss_tracedata_b, dac_calib3,
+ atest_usb23, atest_char3, NA, NA, NA),
+ PINGROUP(18, cci_i2c, qdss_stm2, qdss_tracedata_b, dac_calib4,
+ atest_usb22, atest_char2, NA, NA, NA),
+ PINGROUP(19, cci_i2c, qdss_stm1, qdss_tracedata_b, dac_calib5,
+ atest_usb21, atest_char1, NA, NA, NA),
+ PINGROUP(20, cci_i2c, dbg_out, qdss_stm0, dac_calib6, atest_usb20,
+ atest_char0, NA, NA, NA),
+ PINGROUP(21, cci_timer0, qdss_stm13, qdss_tracedata_b, dac_calib7, NA,
+ NA, NA, NA, NA),
+ PINGROUP(22, cci_timer1, qdss_stm12, qdss_tracedata_b, dac_calib8, NA,
+ NA, NA, NA, NA),
+ PINGROUP(23, cci_timer2, blsp1_spi, qdss_stm11, qdss_tracedata_b,
+ dac_calib9, NA, NA, NA, NA),
+ PINGROUP(24, cci_timer3, cci_async, blsp1_spi, qdss_stm10,
+ qdss_cti_trig_in_a, dac_calib10, NA, NA, NA),
+ PINGROUP(25, cci_timer4, cci_async, blsp_spi6, blsp_uart6, blsp_uim6,
+ blsp2_spi, qdss_stm9, qdss_cti_trig_out_a, dac_calib11),
+ PINGROUP(26, cci_async, blsp_spi6, blsp_uart6, blsp_uim6, qdss_stm8,
+ qdss_tracedata_b, dac_calib12, NA, NA),
+ PINGROUP(27, blsp_spi6, blsp_uart6, blsp_i2c6, blsp1_spi,
+ qdss_tracectl_a, dac_calib13, NA, NA, NA),
+ PINGROUP(28, blsp_spi6, blsp_uart6, blsp_i2c6, blsp1_spi,
+ qdss_traceclk_a, dac_calib14, NA, NA, NA),
+ PINGROUP(29, blsp2_spi, NA, qdss_tracedata_b, dac_calib15, NA, NA, NA,
+ NA, NA),
+ PINGROUP(30, hdmi_rcv, blsp2_spi, dac_calib16, NA, NA, NA, NA, NA, NA),
+ PINGROUP(31, hdmi_cec, pwr_modem, dac_calib17, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, hdmi_ddc, pwr_nav, NA, dac_calib18, NA, NA, NA, NA, NA),
+ PINGROUP(33, hdmi_ddc, pwr_crypto, NA, dac_calib19, NA, NA, NA, NA, NA),
+ PINGROUP(34, hdmi_hot, NA, dac_calib20, NA, NA, NA, NA, NA, NA),
+ PINGROUP(35, pci_e0, NA, dac_calib21, NA, NA, NA, NA, NA, NA),
+ PINGROUP(36, pci_e0, NA, dac_calib22, NA, NA, NA, NA, NA, NA),
+ PINGROUP(37, NA, dac_calib23, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(38, NA, dac_calib24, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, tsif1_sync, NA, dac_calib25, NA, NA, NA, NA, NA, NA),
+ PINGROUP(40, sd_write, tsif1_error, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(41, blsp_spi2, blsp_uart2, blsp_uim2, NA, qdss_cti,
+ dac_calib0, NA, NA, NA),
+ PINGROUP(42, blsp_spi2, blsp_uart2, blsp_uim2, NA, qdss_cti,
+ dac_calib1, NA, NA, NA),
+ PINGROUP(43, blsp_spi2, blsp_uart2, blsp_i2c2, NA, dac_calib2, NA, NA,
+ NA, NA),
+ PINGROUP(44, blsp_spi2, blsp_uart2, blsp_i2c2, NA, dac_calib3, NA, NA,
+ NA, NA),
+ PINGROUP(45, blsp_spi3, blsp_uart3, blsp_uim3, NA, dac_calib4, NA, NA,
+ NA, NA),
+ PINGROUP(46, blsp_spi3, blsp_uart3, blsp_uim3, NA, dac_calib5, NA, NA,
+ NA, NA),
+ PINGROUP(47, blsp_spi3, blsp_uart3, blsp_i2c3, dac_calib6, NA, NA, NA,
+ NA, NA),
+ PINGROUP(48, blsp_spi3, blsp_uart3, blsp_i2c3, dac_calib7, NA, NA, NA,
+ NA, NA),
+ PINGROUP(49, uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi,
+ dac_calib8, NA, NA, NA),
+ PINGROUP(50, uim3, blsp_spi9, blsp_uart9, blsp_uim9, blsp10_spi,
+ dac_calib9, NA, NA, NA),
+ PINGROUP(51, uim3, blsp_spi9, blsp_uart9, blsp_i2c9, blsp10_spi,
+ dac_calib10, NA, NA, NA),
+ PINGROUP(52, uim3, blsp_spi9, blsp_uart9, blsp_i2c9,
+ blsp10_spi, dac_calib11, NA, NA, NA),
+ PINGROUP(53, blsp_spi7, blsp_uart7, blsp_uim7, NA, qdss_tracedata_a,
+ dac_calib12, NA, NA, NA),
+ PINGROUP(54, blsp_spi7, blsp_uart7, blsp_uim7, NA, NA,
+ qdss_tracedata_a, dac_calib13, NA, NA),
+ PINGROUP(55, blsp_spi7, blsp_uart7, blsp_i2c7, NA, dac_calib14, NA, NA,
+ NA, NA),
+ PINGROUP(56, blsp_spi7, blsp_uart7, blsp_i2c7, NA, dac_calib15, NA, NA,
+ NA, NA),
+ PINGROUP(57, qua_mi2s, gcc_gp1_clk_a, NA, qdss_tracedata_b,
+ dac_calib16, NA, NA, NA, NA),
+ PINGROUP(58, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_uim11,
+ gcc_gp2_clk_a, NA, qdss_tracedata_b, dac_calib17),
+ PINGROUP(59, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_uim11,
+ gcc_gp3_clk_a, NA, dac_calib18, NA),
+ PINGROUP(60, qua_mi2s, uim4, blsp_spi11, blsp_uart11, blsp_i2c11,
+ cri_trng0, NA, dac_calib19, NA),
+ PINGROUP(61, qua_mi2s, uim4, blsp_spi11, blsp_uart11,
+ blsp_i2c11, cri_trng1, NA, dac_calib20, NA),
+ PINGROUP(62, qua_mi2s, cri_trng, NA, dac_calib21, NA, NA, NA, NA, NA),
+ PINGROUP(63, qua_mi2s, NA, NA, qdss_stm18, qdss_tracedata_a,
+ dac_calib22, NA, NA, NA),
+ PINGROUP(64, pri_mi2s, NA, qdss_stm17, qdss_tracedata_a, dac_calib23,
+ NA, NA, NA, NA),
+ PINGROUP(65, pri_mi2s, blsp_spi4, blsp_uart4, blsp_uim4, NA,
+ qdss_stm16, qdss_tracedata_a, dac_calib24, NA),
+ PINGROUP(66, pri_mi2s, blsp_spi4, blsp_uart4, blsp_uim4, NA,
+ qdss_stm15, qdss_tracedata_a, dac_calib25, NA),
+ PINGROUP(67, pri_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, qdss_stm14,
+ qdss_tracedata_a, dac_calib26, NA, NA),
+ PINGROUP(68, pri_mi2s, blsp_spi4, blsp_uart4, blsp_i2c4, NA, NA, NA,
+ NA, NA),
+ PINGROUP(69, spkr_i2s, audio_ref, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(70, lpass_slimbus, spkr_i2s, isense_dbg, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(71, lpass_slimbus, spkr_i2s, tsense_pwm1, tsense_pwm2, NA, NA,
+ NA, NA, NA),
+ PINGROUP(72, lpass_slimbus, spkr_i2s, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, btfm_slimbus, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, btfm_slimbus, ter_mi2s, qdss_stm22, qdss_tracedata_a, NA,
+ NA, NA, NA, NA),
+ PINGROUP(75, ter_mi2s, qdss_stm21, qdss_tracedata_a, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(76, ter_mi2s, qdss_stm20, qdss_tracedata_a, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(77, ter_mi2s, qdss_stm19, qdss_tracedata_a, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(78, ter_mi2s, gcc_gp1_clk_b, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp2_clk_b,
+ NA, NA, NA, NA),
+ PINGROUP(82, sec_mi2s, blsp_spi5, blsp_uart5, blsp_uim5, gcc_gp3_clk_b,
+ NA, NA, NA, NA),
+ PINGROUP(83, sec_mi2s, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA,
+ NA, NA),
+ PINGROUP(84, blsp_spi5, blsp_uart5, blsp_i2c5, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, blsp_spi12, blsp_uart12, blsp_uim12, NA, qdss_stm25,
+ qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(86, blsp_spi12, blsp_uart12, blsp_uim12, NA, NA, qdss_stm31,
+ qdss_tracedata_a, NA, NA),
+ PINGROUP(87, blsp_spi12, blsp_uart12, blsp_i2c12, NA, qdss_stm30,
+ qdss_tracedata_a, NA, NA, NA),
+ PINGROUP(88, blsp_spi12, blsp_uart12, blsp_i2c12, blsp10_spi, NA,
+ qdss_stm29, NA, NA, NA),
+ PINGROUP(89, tsif1_clk, qdss_stm28, qdss_tracedata_a, NA, NA, NA, NA,
+ NA, NA),
+ PINGROUP(90, tsif1_en, blsp1_spi, qdss_tracedata_a, NA, NA, NA, NA, NA,
+ NA),
+ PINGROUP(91, tsif1_data, sdc4_cmd, qdss_stm27, qdss_traceclk_b, NA, NA,
+ NA, NA, NA),
+ PINGROUP(92, tsif2_error, sdc43, vfr_1, qdss_stm26, qdss_tracedata_b,
+ NA, NA, NA, NA),
+ PINGROUP(93, tsif2_clk, sdc4_clk, NA, qdss_stm24, qdss_tracedata_b, NA,
+ NA, NA, NA),
+ PINGROUP(94, tsif2_en, sdc42, NA, qdss_stm23, qdss_tracectl_b, NA, NA,
+ NA, NA),
+ PINGROUP(95, tsif2_data, sdc41, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(96, tsif2_sync, sdc40, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, NA, NA, mdp_vsync_p_b, ldo_en, NA, NA, NA, NA, NA),
+ PINGROUP(98, NA, NA, mdp_vsync_s_b, ldo_update, NA, NA, NA, NA, NA),
+ PINGROUP(99, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(100, NA, NA, blsp11_uart_tx_b, qdss_cti, NA, NA, NA, NA, NA),
+ PINGROUP(101, NA, blsp11_uart_rx_b, qdss_cti, NA, NA, NA, NA, NA, NA),
+ PINGROUP(102, NA, blsp11_i2c_sda_b, prng_rosc, NA, NA, NA, NA, NA, NA),
+ PINGROUP(103, NA, blsp11_i2c_scl_b, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(104, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(105, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(106, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(107, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(108, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(109, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(110, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(111, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(112, uim1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(113, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(114, NA, pci_e2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(115, NA, pci_e2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(116, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(117, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(118, adsp_ext, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(119, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(120, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(121, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(122, ddr_bist, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(123, ddr_bist, qdss_tracedata_11, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(124, ddr_bist, qdss_tracedata_12, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(125, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(126, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(127, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(128, NA, modem_tsync, nav_dr, nav_pps, NA, NA, NA, NA, NA),
+ PINGROUP(129, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(130, pci_e1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(131, pci_e1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(132, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(133, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(134, gsm_tx, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(135, gsm_tx, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(136, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(137, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(138, NA, qspi_cs, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(139, NA, ssbi2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(140, NA, ssbi1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(141, NA, qspi_cs, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(142, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(143, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(144, mss_lte, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(145, mss_lte, qspi_clk, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(146, NA, qspi0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(147, NA, qspi1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(148, NA, qspi2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(149, NA, qspi3, NA, NA, NA, NA, NA, NA, NA),
+ SDC_QDSD_PINGROUP(sdc1_clk, 0x12c000, 13, 6),
+ SDC_QDSD_PINGROUP(sdc1_cmd, 0x12c000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc1_data, 0x12c000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc2_clk, 0x12d000, 14, 6),
+ SDC_QDSD_PINGROUP(sdc2_cmd, 0x12d000, 11, 3),
+ SDC_QDSD_PINGROUP(sdc2_data, 0x12d000, 9, 0),
+ SDC_QDSD_PINGROUP(sdc1_rclk, 0x12c000, 15, 0),
+};
+
+static const struct msm_pinctrl_soc_data msm8996_pinctrl = {
+ .pins = msm8996_pins,
+ .npins = ARRAY_SIZE(msm8996_pins),
+ .functions = msm8996_functions,
+ .nfunctions = ARRAY_SIZE(msm8996_functions),
+ .groups = msm8996_groups,
+ .ngroups = ARRAY_SIZE(msm8996_groups),
+ .ngpios = 150,
+};
+
+static int msm8996_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8996_pinctrl);
+}
+
+static const struct of_device_id msm8996_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8996-pinctrl", },
+ { }
+};
+
+static struct platform_driver msm8996_pinctrl_driver = {
+ .driver = {
+ .name = "msm8996-pinctrl",
+ .of_match_table = msm8996_pinctrl_of_match,
+ },
+ .probe = msm8996_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8996_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8996_pinctrl_driver);
+}
+arch_initcall(msm8996_pinctrl_init);
+
+static void __exit msm8996_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8996_pinctrl_driver);
+}
+module_exit(msm8996_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm msm8996 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8996_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
index e9ff3bc..f448534 100644
--- a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
+++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c
@@ -32,6 +32,9 @@
static struct msm_pinctrl_soc_data qdf2xxx_pinctrl;
+/* A reasonable limit to the number of GPIOS */
+#define MAX_GPIOS 256
+
static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
{
struct pinctrl_pin_desc *pins;
@@ -42,11 +45,13 @@ static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
/* Query the number of GPIOs from ACPI */
ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios);
- if (ret < 0)
+ if (ret < 0) {
+ dev_warn(&pdev->dev, "missing num-gpios property\n");
return ret;
+ }
- if (!num_gpios) {
- dev_warn(&pdev->dev, "missing num-gpios property\n");
+ if (!num_gpios || num_gpios > MAX_GPIOS) {
+ dev_warn(&pdev->dev, "invalid num-gpios property\n");
return -ENODEV;
}
@@ -55,6 +60,9 @@ static int qdf2xxx_pinctrl_probe(struct platform_device *pdev)
groups = devm_kcalloc(&pdev->dev, num_gpios,
sizeof(struct msm_pingroup), GFP_KERNEL);
+ if (!pins || !groups)
+ return -ENOMEM;
+
for (i = 0; i < num_gpios; i++) {
pins[i].number = i;
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index 6c42ca1..77f6a5c 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -14,6 +14,7 @@
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
@@ -693,18 +694,19 @@ static int pmic_gpio_probe(struct platform_device *pdev)
struct pmic_gpio_pad *pad, *pads;
struct pmic_gpio_state *state;
int ret, npins, i;
- u32 res[2];
+ u32 reg;
- ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+ ret = of_property_read_u32(dev->of_node, "reg", &reg);
if (ret < 0) {
- dev_err(dev, "missing base address and/or range");
+ dev_err(dev, "missing base address");
return ret;
}
- npins = res[1] / PMIC_GPIO_ADDRESS_RANGE;
-
+ npins = platform_irq_count(pdev);
if (!npins)
return -EINVAL;
+ if (npins < 0)
+ return npins;
BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
@@ -752,7 +754,7 @@ static int pmic_gpio_probe(struct platform_device *pdev)
if (pad->irq < 0)
return pad->irq;
- pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE;
+ pad->base = reg + i * PMIC_GPIO_ADDRESS_RANGE;
ret = pmic_gpio_populate(state, pad);
if (ret < 0)
@@ -804,6 +806,7 @@ static int pmic_gpio_remove(struct platform_device *pdev)
static const struct of_device_id pmic_gpio_of_match[] = {
{ .compatible = "qcom,pm8916-gpio" }, /* 4 GPIO's */
{ .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */
+ { .compatible = "qcom,pm8994-gpio" }, /* 22 GPIO's */
{ .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */
{ },
};
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
index 9ce0e30..2df4f29 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -14,6 +14,7 @@
#include <linux/gpio.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinmux.h>
@@ -795,17 +796,19 @@ static int pmic_mpp_probe(struct platform_device *pdev)
struct pmic_mpp_pad *pad, *pads;
struct pmic_mpp_state *state;
int ret, npins, i;
- u32 res[2];
+ u32 reg;
- ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+ ret = of_property_read_u32(dev->of_node, "reg", &reg);
if (ret < 0) {
- dev_err(dev, "missing base address and/or range");
+ dev_err(dev, "missing base address");
return ret;
}
- npins = res[1] / PMIC_MPP_ADDRESS_RANGE;
+ npins = platform_irq_count(pdev);
if (!npins)
return -EINVAL;
+ if (npins < 0)
+ return npins;
BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups));
@@ -854,7 +857,7 @@ static int pmic_mpp_probe(struct platform_device *pdev)
if (pad->irq < 0)
return pad->irq;
- pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE;
+ pad->base = reg + i * PMIC_MPP_ADDRESS_RANGE;
ret = pmic_mpp_populate(state, pad);
if (ret < 0)
@@ -907,6 +910,7 @@ static const struct of_device_id pmic_mpp_of_match[] = {
{ .compatible = "qcom,pm8841-mpp" }, /* 4 MPP's */
{ .compatible = "qcom,pm8916-mpp" }, /* 4 MPP's */
{ .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */
+ { .compatible = "qcom,pm8994-mpp" }, /* 8 MPP's */
{ .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */
{ },
};
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
index d809c9e..e51176e 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
@@ -650,11 +651,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl,
}
static const struct of_device_id pm8xxx_gpio_of_match[] = {
- { .compatible = "qcom,pm8018-gpio", .data = (void *)6 },
- { .compatible = "qcom,pm8038-gpio", .data = (void *)12 },
- { .compatible = "qcom,pm8058-gpio", .data = (void *)40 },
- { .compatible = "qcom,pm8917-gpio", .data = (void *)38 },
- { .compatible = "qcom,pm8921-gpio", .data = (void *)44 },
+ { .compatible = "qcom,pm8018-gpio" },
+ { .compatible = "qcom,pm8038-gpio" },
+ { .compatible = "qcom,pm8058-gpio" },
+ { .compatible = "qcom,pm8917-gpio" },
+ { .compatible = "qcom,pm8921-gpio" },
+ { .compatible = "qcom,ssbi-gpio" },
{ },
};
MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match);
@@ -665,14 +667,19 @@ static int pm8xxx_gpio_probe(struct platform_device *pdev)
struct pinctrl_pin_desc *pins;
struct pm8xxx_gpio *pctrl;
int ret;
- int i;
+ int i, npins;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
pctrl->dev = &pdev->dev;
- pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev);
+ npins = platform_irq_count(pdev);
+ if (!npins)
+ return -EINVAL;
+ if (npins < 0)
+ return npins;
+ pctrl->npins = npins;
pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!pctrl->regmap) {
diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
index 8982027..e9f01de 100644
--- a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
+++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c
@@ -23,6 +23,7 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/of_device.h>
+#include <linux/of_irq.h>
#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
@@ -741,11 +742,12 @@ static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl,
}
static const struct of_device_id pm8xxx_mpp_of_match[] = {
- { .compatible = "qcom,pm8018-mpp", .data = (void *)6 },
- { .compatible = "qcom,pm8038-mpp", .data = (void *)6 },
- { .compatible = "qcom,pm8917-mpp", .data = (void *)10 },
- { .compatible = "qcom,pm8821-mpp", .data = (void *)4 },
- { .compatible = "qcom,pm8921-mpp", .data = (void *)12 },
+ { .compatible = "qcom,pm8018-mpp" },
+ { .compatible = "qcom,pm8038-mpp" },
+ { .compatible = "qcom,pm8917-mpp" },
+ { .compatible = "qcom,pm8821-mpp" },
+ { .compatible = "qcom,pm8921-mpp" },
+ { .compatible = "qcom,ssbi-mpp" },
{ },
};
MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match);
@@ -756,14 +758,19 @@ static int pm8xxx_mpp_probe(struct platform_device *pdev)
struct pinctrl_pin_desc *pins;
struct pm8xxx_mpp *pctrl;
int ret;
- int i;
+ int i, npins;
pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
if (!pctrl)
return -ENOMEM;
pctrl->dev = &pdev->dev;
- pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev);
+ npins = platform_irq_count(pdev);
+ if (!npins)
+ return -EINVAL;
+ if (npins < 0)
+ return npins;
+ pctrl->npins = npins;
pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!pctrl->regmap) {
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index 71ccf6a..16e2293 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -1150,6 +1150,109 @@ const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
},
};
+/* pin banks of exynos5410 pin-controller 0 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks0[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpb0", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpb1", 0x10),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpb2", 0x14),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpb3", 0x18),
+ EXYNOS_PIN_BANK_EINTG(7, 0x0E0, "gpc0", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(4, 0x100, "gpc3", 0x20),
+ EXYNOS_PIN_BANK_EINTG(7, 0x120, "gpc1", 0x24),
+ EXYNOS_PIN_BANK_EINTG(7, 0x140, "gpc2", 0x28),
+ EXYNOS_PIN_BANK_EINTN(2, 0x160, "gpm5"),
+ EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpd1", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpe0", 0x30),
+ EXYNOS_PIN_BANK_EINTG(2, 0x1C0, "gpe1", 0x34),
+ EXYNOS_PIN_BANK_EINTG(6, 0x1E0, "gpf0", 0x38),
+ EXYNOS_PIN_BANK_EINTG(8, 0x200, "gpf1", 0x3c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x220, "gpg0", 0x40),
+ EXYNOS_PIN_BANK_EINTG(8, 0x240, "gpg1", 0x44),
+ EXYNOS_PIN_BANK_EINTG(2, 0x260, "gpg2", 0x48),
+ EXYNOS_PIN_BANK_EINTG(4, 0x280, "gph0", 0x4c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x2A0, "gph1", 0x50),
+ EXYNOS_PIN_BANK_EINTN(8, 0x2C0, "gpm7"),
+ EXYNOS_PIN_BANK_EINTN(6, 0x2E0, "gpy0"),
+ EXYNOS_PIN_BANK_EINTN(4, 0x300, "gpy1"),
+ EXYNOS_PIN_BANK_EINTN(6, 0x320, "gpy2"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x340, "gpy3"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x360, "gpy4"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x380, "gpy5"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x3A0, "gpy6"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x3C0, "gpy7"),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos5410 pin-controller 1 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks1[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpj0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpj1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpj2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpj3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x080, "gpj4", 0x10),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0A0, "gpk0", 0x14),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0C0, "gpk1", 0x18),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0E0, "gpk2", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(7, 0x100, "gpk3", 0x20),
+};
+
+/* pin banks of exynos5410 pin-controller 2 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks2[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpv3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x0C0, "gpv4", 0x10),
+};
+
+/* pin banks of exynos5410 pin-controller 3 */
+static const struct samsung_pin_bank_data exynos5410_pin_banks3[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos5410 SoC. Exynos5410 SoC includes
+ * four gpio/pin-mux/pinconfig controllers.
+ */
+const struct samsung_pin_ctrl exynos5410_pin_ctrl[] __initconst = {
+ {
+ /* pin-controller instance 0 data */
+ .pin_banks = exynos5410_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos5410_pin_banks0),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 1 data */
+ .pin_banks = exynos5410_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos5410_pin_banks1),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 2 data */
+ .pin_banks = exynos5410_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos5410_pin_banks2),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 3 data */
+ .pin_banks = exynos5410_pin_banks3,
+ .nr_banks = ARRAY_SIZE(exynos5410_pin_banks3),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ },
+};
+
/* pin banks of exynos5420 pin-controller 0 */
static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 3f622cc..48294e7 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -1222,6 +1222,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos5250_pin_ctrl },
{ .compatible = "samsung,exynos5260-pinctrl",
.data = (void *)exynos5260_pin_ctrl },
+ { .compatible = "samsung,exynos5410-pinctrl",
+ .data = (void *)exynos5410_pin_ctrl },
{ .compatible = "samsung,exynos5420-pinctrl",
.data = (void *)exynos5420_pin_ctrl },
{ .compatible = "samsung,exynos5433-pinctrl",
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index c1239ff..cd31bfa 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -270,6 +270,7 @@ extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos5410_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos5433_pin_ctrl[];
extern const struct samsung_pin_ctrl exynos7_pin_ctrl[];
diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c
index 02118ab..1cbbe04 100644
--- a/drivers/pinctrl/sh-pfc/pfc-emev2.c
+++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c
@@ -258,18 +258,18 @@ static const u16 pinmux_data[] = {
/* GPSR0 */
/* V9 */
- PINMUX_DATA(JT_SEL_MARK, FN_JT_SEL),
+ PINMUX_SINGLE(JT_SEL),
/* U9 */
- PINMUX_DATA(ERR_RST_REQB_MARK, FN_ERR_RST_REQB),
+ PINMUX_SINGLE(ERR_RST_REQB),
/* V8 */
- PINMUX_DATA(REF_CLKO_MARK, FN_REF_CLKO),
+ PINMUX_SINGLE(REF_CLKO),
/* U8 */
- PINMUX_DATA(EXT_CLKI_MARK, FN_EXT_CLKI),
+ PINMUX_SINGLE(EXT_CLKI),
/* B22*/
PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, LCD3_PXCLK, SEL_LCD3_1_0_00),
PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, YUV3_CLK_O, SEL_LCD3_1_0_01),
/* C21 */
- PINMUX_DATA(LCD3_PXCLKB_MARK, FN_LCD3_PXCLKB),
+ PINMUX_SINGLE(LCD3_PXCLKB),
/* A21 */
PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, LCD3_CLK_I, SEL_LCD3_1_0_00),
PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, YUV3_CLK_I, SEL_LCD3_1_0_01),
@@ -285,17 +285,17 @@ static const u16 pinmux_data[] = {
/* GPSR1 */
/* A20 */
- PINMUX_DATA(LCD3_R0_MARK, FN_LCD3_R0),
+ PINMUX_SINGLE(LCD3_R0),
/* B20 */
- PINMUX_DATA(LCD3_R1_MARK, FN_LCD3_R1),
+ PINMUX_SINGLE(LCD3_R1),
/* A19 */
- PINMUX_DATA(LCD3_R2_MARK, FN_LCD3_R2),
+ PINMUX_SINGLE(LCD3_R2),
/* B19 */
- PINMUX_DATA(LCD3_R3_MARK, FN_LCD3_R3),
+ PINMUX_SINGLE(LCD3_R3),
/* C19 */
- PINMUX_DATA(LCD3_R4_MARK, FN_LCD3_R4),
+ PINMUX_SINGLE(LCD3_R4),
/* B18 */
- PINMUX_DATA(LCD3_R5_MARK, FN_LCD3_R5),
+ PINMUX_SINGLE(LCD3_R5),
/* C18 */
PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, LCD3_R6, SEL_LCD3_9_8_00),
PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, TP33_CLK, SEL_LCD3_9_8_10),
@@ -367,9 +367,9 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D15, SEL_LCD3_11_10_01),
PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA15, SEL_LCD3_11_10_10),
/* AA9 */
- PINMUX_DATA(IIC0_SCL_MARK, FN_IIC0_SCL),
+ PINMUX_SINGLE(IIC0_SCL),
/* AA8 */
- PINMUX_DATA(IIC0_SDA_MARK, FN_IIC0_SDA),
+ PINMUX_SINGLE(IIC0_SDA),
/* Y9 */
PINMUX_IPSR_NOFN(IIC_1_0_PORT46, IIC1_SCL, SEL_IIC_1_0_00),
PINMUX_IPSR_NOFN(IIC_1_0_PORT46, UART3_RX, SEL_IIC_1_0_01),
@@ -377,51 +377,51 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOFN(IIC_1_0_PORT47, IIC1_SDA, SEL_IIC_1_0_00),
PINMUX_IPSR_NOFN(IIC_1_0_PORT47, UART3_TX, SEL_IIC_1_0_01),
/* AC19 */
- PINMUX_DATA(SD_CKI_MARK, FN_SD_CKI),
+ PINMUX_SINGLE(SD_CKI),
/* AB18 */
- PINMUX_DATA(SDI0_CKO_MARK, FN_SDI0_CKO),
+ PINMUX_SINGLE(SDI0_CKO),
/* AC18 */
- PINMUX_DATA(SDI0_CKI_MARK, FN_SDI0_CKI),
+ PINMUX_SINGLE(SDI0_CKI),
/* Y12 */
- PINMUX_DATA(SDI0_CMD_MARK, FN_SDI0_CMD),
+ PINMUX_SINGLE(SDI0_CMD),
/* AA13 */
- PINMUX_DATA(SDI0_DATA0_MARK, FN_SDI0_DATA0),
+ PINMUX_SINGLE(SDI0_DATA0),
/* Y13 */
- PINMUX_DATA(SDI0_DATA1_MARK, FN_SDI0_DATA1),
+ PINMUX_SINGLE(SDI0_DATA1),
/* AA14 */
- PINMUX_DATA(SDI0_DATA2_MARK, FN_SDI0_DATA2),
+ PINMUX_SINGLE(SDI0_DATA2),
/* Y14 */
- PINMUX_DATA(SDI0_DATA3_MARK, FN_SDI0_DATA3),
+ PINMUX_SINGLE(SDI0_DATA3),
/* AA15 */
- PINMUX_DATA(SDI0_DATA4_MARK, FN_SDI0_DATA4),
+ PINMUX_SINGLE(SDI0_DATA4),
/* Y15 */
- PINMUX_DATA(SDI0_DATA5_MARK, FN_SDI0_DATA5),
+ PINMUX_SINGLE(SDI0_DATA5),
/* AA16 */
- PINMUX_DATA(SDI0_DATA6_MARK, FN_SDI0_DATA6),
+ PINMUX_SINGLE(SDI0_DATA6),
/* Y16 */
- PINMUX_DATA(SDI0_DATA7_MARK, FN_SDI0_DATA7),
+ PINMUX_SINGLE(SDI0_DATA7),
/* AB22 */
- PINMUX_DATA(SDI1_CKO_MARK, FN_SDI1_CKO),
+ PINMUX_SINGLE(SDI1_CKO),
/* AA23 */
- PINMUX_DATA(SDI1_CKI_MARK, FN_SDI1_CKI),
+ PINMUX_SINGLE(SDI1_CKI),
/* AC21 */
- PINMUX_DATA(SDI1_CMD_MARK, FN_SDI1_CMD),
+ PINMUX_SINGLE(SDI1_CMD),
/* GPSR2 */
/* AB21 */
- PINMUX_DATA(SDI1_DATA0_MARK, FN_SDI1_DATA0),
+ PINMUX_SINGLE(SDI1_DATA0),
/* AB20 */
- PINMUX_DATA(SDI1_DATA1_MARK, FN_SDI1_DATA1),
+ PINMUX_SINGLE(SDI1_DATA1),
/* AB19 */
- PINMUX_DATA(SDI1_DATA2_MARK, FN_SDI1_DATA2),
+ PINMUX_SINGLE(SDI1_DATA2),
/* AA19 */
- PINMUX_DATA(SDI1_DATA3_MARK, FN_SDI1_DATA3),
+ PINMUX_SINGLE(SDI1_DATA3),
/* J23 */
- PINMUX_DATA(AB_CLK_MARK, FN_AB_CLK),
+ PINMUX_SINGLE(AB_CLK),
/* D21 */
- PINMUX_DATA(AB_CSB0_MARK, FN_AB_CSB0),
+ PINMUX_SINGLE(AB_CSB0),
/* E21 */
- PINMUX_DATA(AB_CSB1_MARK, FN_AB_CSB1),
+ PINMUX_SINGLE(AB_CSB1),
/* F20 */
PINMUX_IPSR_NOFN(AB_1_0_PORT71, AB_CSB2, SEL_AB_1_0_00),
PINMUX_IPSR_NOFN(AB_1_0_PORT71, CF_CSB0, SEL_AB_1_0_10),
@@ -514,7 +514,7 @@ static const u16 pinmux_data[] = {
/* GPSR3 */
/* M21 */
- PINMUX_DATA(AB_A20_MARK, FN_AB_A20),
+ PINMUX_SINGLE(AB_A20),
/* N21 */
PINMUX_IPSR_NOFN(AB_9_8_PORT97, AB_A21, SEL_AB_9_8_00),
PINMUX_IPSR_NOFN(AB_9_8_PORT97, SDI2_CKO, SEL_AB_9_8_01),
@@ -541,13 +541,13 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_A28, SEL_AB_13_12_00),
PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_BEN1, SEL_AB_13_12_10),
/* B8 */
- PINMUX_DATA(USI0_CS1_MARK, FN_USI0_CS1),
+ PINMUX_SINGLE(USI0_CS1),
/* B9 */
- PINMUX_DATA(USI0_CS2_MARK, FN_USI0_CS2),
+ PINMUX_SINGLE(USI0_CS2),
/* C10 */
- PINMUX_DATA(USI1_DI_MARK, FN_USI1_DI),
+ PINMUX_SINGLE(USI1_DI),
/* D10 */
- PINMUX_DATA(USI1_DO_MARK, FN_USI1_DO),
+ PINMUX_SINGLE(USI1_DO),
/* AB5 */
PINMUX_IPSR_NOFN(USI_1_0_PORT109, USI2_CLK, SEL_USI_1_0_00),
PINMUX_IPSR_NOFN(USI_1_0_PORT109, DTV_BCLK_B, SEL_USI_1_0_01),
@@ -587,49 +587,49 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_NOFN(USI_9_8_PORT121, PWM1, SEL_USI_9_8_00),
PINMUX_IPSR_NOFN(USI_9_8_PORT121, USI4_DO, SEL_USI_9_8_01),
/* V20 */
- PINMUX_DATA(NTSC_CLK_MARK, FN_NTSC_CLK),
+ PINMUX_SINGLE(NTSC_CLK),
/* P20 */
- PINMUX_DATA(NTSC_DATA0_MARK, FN_NTSC_DATA0),
+ PINMUX_SINGLE(NTSC_DATA0),
/* P18 */
- PINMUX_DATA(NTSC_DATA1_MARK, FN_NTSC_DATA1),
+ PINMUX_SINGLE(NTSC_DATA1),
/* R20 */
- PINMUX_DATA(NTSC_DATA2_MARK, FN_NTSC_DATA2),
+ PINMUX_SINGLE(NTSC_DATA2),
/* R18 */
- PINMUX_DATA(NTSC_DATA3_MARK, FN_NTSC_DATA3),
+ PINMUX_SINGLE(NTSC_DATA3),
/* T20 */
- PINMUX_DATA(NTSC_DATA4_MARK, FN_NTSC_DATA4),
+ PINMUX_SINGLE(NTSC_DATA4),
/* GPRS3 */
/* T18 */
- PINMUX_DATA(NTSC_DATA5_MARK, FN_NTSC_DATA5),
+ PINMUX_SINGLE(NTSC_DATA5),
/* U20 */
- PINMUX_DATA(NTSC_DATA6_MARK, FN_NTSC_DATA6),
+ PINMUX_SINGLE(NTSC_DATA6),
/* U18 */
- PINMUX_DATA(NTSC_DATA7_MARK, FN_NTSC_DATA7),
+ PINMUX_SINGLE(NTSC_DATA7),
/* W23 */
- PINMUX_DATA(CAM_CLKO_MARK, FN_CAM_CLKO),
+ PINMUX_SINGLE(CAM_CLKO),
/* Y23 */
- PINMUX_DATA(CAM_CLKI_MARK, FN_CAM_CLKI),
+ PINMUX_SINGLE(CAM_CLKI),
/* W22 */
- PINMUX_DATA(CAM_VS_MARK, FN_CAM_VS),
+ PINMUX_SINGLE(CAM_VS),
/* V21 */
- PINMUX_DATA(CAM_HS_MARK, FN_CAM_HS),
+ PINMUX_SINGLE(CAM_HS),
/* T21 */
- PINMUX_DATA(CAM_YUV0_MARK, FN_CAM_YUV0),
+ PINMUX_SINGLE(CAM_YUV0),
/* T22 */
- PINMUX_DATA(CAM_YUV1_MARK, FN_CAM_YUV1),
+ PINMUX_SINGLE(CAM_YUV1),
/* T23 */
- PINMUX_DATA(CAM_YUV2_MARK, FN_CAM_YUV2),
+ PINMUX_SINGLE(CAM_YUV2),
/* U21 */
- PINMUX_DATA(CAM_YUV3_MARK, FN_CAM_YUV3),
+ PINMUX_SINGLE(CAM_YUV3),
/* U22 */
- PINMUX_DATA(CAM_YUV4_MARK, FN_CAM_YUV4),
+ PINMUX_SINGLE(CAM_YUV4),
/* U23 */
- PINMUX_DATA(CAM_YUV5_MARK, FN_CAM_YUV5),
+ PINMUX_SINGLE(CAM_YUV5),
/* V22 */
- PINMUX_DATA(CAM_YUV6_MARK, FN_CAM_YUV6),
+ PINMUX_SINGLE(CAM_YUV6),
/* V23 */
- PINMUX_DATA(CAM_YUV7_MARK, FN_CAM_YUV7),
+ PINMUX_SINGLE(CAM_YUV7),
/* K22 */
PINMUX_IPSR_NOFN(HSI_1_0_PORT143, USI5_CLK_B, SEL_HSI_1_0_01),
/* K23 */
@@ -647,17 +647,17 @@ static const u16 pinmux_data[] = {
/* M22 */
PINMUX_IPSR_NOFN(HSI_1_0_PORT150, USI5_DI_B, SEL_HSI_1_0_01),
/* D13 */
- PINMUX_DATA(JT_TDO_MARK, FN_JT_TDO),
+ PINMUX_SINGLE(JT_TDO),
/* F13 */
- PINMUX_DATA(JT_TDOEN_MARK, FN_JT_TDOEN),
+ PINMUX_SINGLE(JT_TDOEN),
/* AA12 */
- PINMUX_DATA(USB_VBUS_MARK, FN_USB_VBUS),
+ PINMUX_SINGLE(USB_VBUS),
/* A12 */
- PINMUX_DATA(LOWPWR_MARK, FN_LOWPWR),
+ PINMUX_SINGLE(LOWPWR),
/* Y11 */
- PINMUX_DATA(UART1_RX_MARK, FN_UART1_RX),
+ PINMUX_SINGLE(UART1_RX),
/* Y10 */
- PINMUX_DATA(UART1_TX_MARK, FN_UART1_TX),
+ PINMUX_SINGLE(UART1_TX),
/* AA10 */
PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART1_CTSB, SEL_UART_1_0_00),
PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART2_RX, SEL_UART_1_0_01),
@@ -749,7 +749,7 @@ static const unsigned int cf_ctrl_mux[] = {
};
static const unsigned int cf_data8_pins[] = {
- /* CF_D[0:8] */
+ /* CF_D[0:7] */
77, 78, 79, 80,
81, 82, 83, 84,
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
index 279e9dd..7f7c8a6e 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c
@@ -2214,7 +2214,7 @@ static const unsigned int lcd1_data9_mux[] = {
LCD1_D8_MARK,
};
static const unsigned int lcd1_data12_pins[] = {
- /* D[0:12] */
+ /* D[0:11] */
4, 3, 2, 1, 0, 91, 92, 23,
93, 94, 21, 201,
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
index bbd35dc..ad09a67 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7778.c
@@ -548,17 +548,17 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(PENC0_MARK, FN_PENC0),
- PINMUX_DATA(PENC1_MARK, FN_PENC1),
- PINMUX_DATA(A1_MARK, FN_A1),
- PINMUX_DATA(A2_MARK, FN_A2),
- PINMUX_DATA(A3_MARK, FN_A3),
- PINMUX_DATA(WE0_MARK, FN_WE0),
- PINMUX_DATA(AUDIO_CLKA_MARK, FN_AUDIO_CLKA),
- PINMUX_DATA(AUDIO_CLKB_MARK, FN_AUDIO_CLKB),
- PINMUX_DATA(SSI_SCK34_MARK, FN_SSI_SCK34),
- PINMUX_DATA(AVS1_MARK, FN_AVS1),
- PINMUX_DATA(AVS2_MARK, FN_AVS2),
+ PINMUX_SINGLE(PENC0),
+ PINMUX_SINGLE(PENC1),
+ PINMUX_SINGLE(A1),
+ PINMUX_SINGLE(A2),
+ PINMUX_SINGLE(A3),
+ PINMUX_SINGLE(WE0),
+ PINMUX_SINGLE(AUDIO_CLKA),
+ PINMUX_SINGLE(AUDIO_CLKB),
+ PINMUX_SINGLE(SSI_SCK34),
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(AVS2),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_1_0, PRESETOUT),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
index ed4e078..bd17ecc 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7779.c
@@ -23,13 +23,6 @@
#include "sh_pfc.h"
-#define PORT_GP_9(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_32(1, fn, sfx), \
@@ -609,14 +602,14 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(AVS1_MARK, FN_AVS1),
- PINMUX_DATA(AVS1_MARK, FN_AVS1),
- PINMUX_DATA(A17_MARK, FN_A17),
- PINMUX_DATA(A18_MARK, FN_A18),
- PINMUX_DATA(A19_MARK, FN_A19),
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(A17),
+ PINMUX_SINGLE(A18),
+ PINMUX_SINGLE(A19),
- PINMUX_DATA(USB_PENC0_MARK, FN_USB_PENC0),
- PINMUX_DATA(USB_PENC1_MARK, FN_USB_PENC1),
+ PINMUX_SINGLE(USB_PENC0),
+ PINMUX_SINGLE(USB_PENC1),
PINMUX_IPSR_DATA(IP0_2_0, USB_PENC2),
PINMUX_IPSR_MSEL(IP0_2_0, SCK0, SEL_SCIF0_0),
@@ -2289,6 +2282,35 @@ static const unsigned int scif5_clk_d_pins[] = {
static const unsigned int scif5_clk_d_mux[] = {
SCK5_D_MARK,
};
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(4, 28),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(4, 5),
+};
+static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
+static const unsigned int scif_clk_c_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(4, 18),
+};
+static const unsigned int scif_clk_c_mux[] = {
+ SCIF_CLK_C_MARK,
+};
+static const unsigned int scif_clk_d_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(2, 29),
+};
+static const unsigned int scif_clk_d_mux[] = {
+ SCIF_CLK_D_MARK,
+};
/* - SDHI0 ------------------------------------------------------------------ */
static const unsigned int sdhi0_data1_pins[] = {
/* D0 */
@@ -2700,6 +2722,10 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scif5_clk_c),
SH_PFC_PIN_GROUP(scif5_data_d),
SH_PFC_PIN_GROUP(scif5_clk_d),
+ SH_PFC_PIN_GROUP(scif_clk),
+ SH_PFC_PIN_GROUP(scif_clk_b),
+ SH_PFC_PIN_GROUP(scif_clk_c),
+ SH_PFC_PIN_GROUP(scif_clk_d),
SH_PFC_PIN_GROUP(sdhi0_data1),
SH_PFC_PIN_GROUP(sdhi0_data4),
SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -2909,6 +2935,13 @@ static const char * const scif5_groups[] = {
"scif5_clk_d",
};
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+ "scif_clk_b",
+ "scif_clk_c",
+ "scif_clk_d",
+};
+
static const char * const sdhi0_groups[] = {
"sdhi0_data1",
"sdhi0_data4",
@@ -3004,6 +3037,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scif3),
SH_PFC_FUNCTION(scif4),
SH_PFC_FUNCTION(scif5),
+ SH_PFC_FUNCTION(scif_clk),
SH_PFC_FUNCTION(usb0),
SH_PFC_FUNCTION(usb1),
SH_PFC_FUNCTION(usb2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index d9924b0..a8b629b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -26,23 +26,6 @@
#include "core.h"
#include "sh_pfc.h"
-#define PORT_GP_30(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
- PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \
- PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \
- PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \
- PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \
- PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \
- PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \
- PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \
- PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx), \
- PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx), \
- PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_30(1, fn, sfx), \
@@ -806,15 +789,15 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(VI1_DATA7_VI1_B7_MARK, FN_VI1_DATA7_VI1_B7),
- PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
- PINMUX_DATA(USB0_OVC_VBUS_MARK, FN_USB0_OVC_VBUS),
- PINMUX_DATA(USB2_PWEN_MARK, FN_USB2_PWEN),
- PINMUX_DATA(USB2_OVC_MARK, FN_USB2_OVC),
- PINMUX_DATA(AVS1_MARK, FN_AVS1),
- PINMUX_DATA(AVS2_MARK, FN_AVS2),
- PINMUX_DATA(DU_DOTCLKIN0_MARK, FN_DU_DOTCLKIN0),
- PINMUX_DATA(DU_DOTCLKIN2_MARK, FN_DU_DOTCLKIN2),
+ PINMUX_SINGLE(VI1_DATA7_VI1_B7),
+ PINMUX_SINGLE(USB0_PWEN),
+ PINMUX_SINGLE(USB0_OVC_VBUS),
+ PINMUX_SINGLE(USB2_PWEN),
+ PINMUX_SINGLE(USB2_OVC),
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(AVS2),
+ PINMUX_SINGLE(DU_DOTCLKIN0),
+ PINMUX_SINGLE(DU_DOTCLKIN2),
PINMUX_IPSR_DATA(IP0_2_0, D0),
PINMUX_IPSR_MSEL(IP0_2_0, MSIOF3_SCK_B, SEL_SOF3_1),
@@ -3236,6 +3219,21 @@ static const unsigned int scifb2_data_c_pins[] = {
static const unsigned int scifb2_data_c_mux[] = {
SCIFB2_RXD_C_MARK, SCIFB2_TXD_C_MARK,
};
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(4, 26),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
/* - SDHI0 ------------------------------------------------------------------ */
static const unsigned int sdhi0_data1_pins[] = {
/* D0 */
@@ -4139,6 +4137,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scifb2_clk_b),
SH_PFC_PIN_GROUP(scifb2_ctrl_b),
SH_PFC_PIN_GROUP(scifb2_data_c),
+ SH_PFC_PIN_GROUP(scif_clk),
+ SH_PFC_PIN_GROUP(scif_clk_b),
SH_PFC_PIN_GROUP(sdhi0_data1),
SH_PFC_PIN_GROUP(sdhi0_data4),
SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -4555,6 +4555,11 @@ static const char * const scifb2_groups[] = {
"scifb2_data_c",
};
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+ "scif_clk_b",
+};
+
static const char * const sdhi0_groups[] = {
"sdhi0_data1",
"sdhi0_data4",
@@ -4729,6 +4734,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scifb0),
SH_PFC_FUNCTION(scifb1),
SH_PFC_FUNCTION(scifb2),
+ SH_PFC_FUNCTION(scif_clk),
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index 87a4f44..4cfbb94 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -2,6 +2,7 @@
* r8a7791 processor support - PFC hardware block.
*
* Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2014-2015 Cogent Embedded, 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
@@ -13,21 +14,6 @@
#include "core.h"
#include "sh_pfc.h"
-#define PORT_GP_26(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
- PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \
- PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \
- PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \
- PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \
- PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \
- PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \
- PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \
- PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_26(1, fn, sfx), \
@@ -787,23 +773,23 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(EX_CS0_N_MARK, FN_EX_CS0_N),
- PINMUX_DATA(RD_N_MARK, FN_RD_N),
- PINMUX_DATA(AUDIO_CLKA_MARK, FN_AUDIO_CLKA),
- PINMUX_DATA(VI0_CLK_MARK, FN_VI0_CLK),
- PINMUX_DATA(VI0_DATA0_VI0_B0_MARK, FN_VI0_DATA0_VI0_B0),
- PINMUX_DATA(VI0_DATA1_VI0_B1_MARK, FN_VI0_DATA1_VI0_B1),
- PINMUX_DATA(VI0_DATA2_VI0_B2_MARK, FN_VI0_DATA2_VI0_B2),
- PINMUX_DATA(VI0_DATA4_VI0_B4_MARK, FN_VI0_DATA4_VI0_B4),
- PINMUX_DATA(VI0_DATA5_VI0_B5_MARK, FN_VI0_DATA5_VI0_B5),
- PINMUX_DATA(VI0_DATA6_VI0_B6_MARK, FN_VI0_DATA6_VI0_B6),
- PINMUX_DATA(VI0_DATA7_VI0_B7_MARK, FN_VI0_DATA7_VI0_B7),
- PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
- PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC),
- PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
- PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
- PINMUX_DATA(DU0_DOTCLKIN_MARK, FN_DU0_DOTCLKIN),
- PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
+ PINMUX_SINGLE(EX_CS0_N),
+ PINMUX_SINGLE(RD_N),
+ PINMUX_SINGLE(AUDIO_CLKA),
+ PINMUX_SINGLE(VI0_CLK),
+ PINMUX_SINGLE(VI0_DATA0_VI0_B0),
+ PINMUX_SINGLE(VI0_DATA1_VI0_B1),
+ PINMUX_SINGLE(VI0_DATA2_VI0_B2),
+ PINMUX_SINGLE(VI0_DATA4_VI0_B4),
+ PINMUX_SINGLE(VI0_DATA5_VI0_B5),
+ PINMUX_SINGLE(VI0_DATA6_VI0_B6),
+ PINMUX_SINGLE(VI0_DATA7_VI0_B7),
+ PINMUX_SINGLE(USB0_PWEN),
+ PINMUX_SINGLE(USB0_OVC),
+ PINMUX_SINGLE(USB1_PWEN),
+ PINMUX_SINGLE(USB1_OVC),
+ PINMUX_SINGLE(DU0_DOTCLKIN),
+ PINMUX_SINGLE(SD1_CLK),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_0, D0),
@@ -1740,6 +1726,82 @@ static const unsigned int audio_clkout_mux[] = {
AUDIO_CLKOUT_MARK,
};
+/* - AVB -------------------------------------------------------------------- */
+static const unsigned int avb_link_pins[] = {
+ RCAR_GP_PIN(5, 14),
+};
+static const unsigned int avb_link_mux[] = {
+ AVB_LINK_MARK,
+};
+static const unsigned int avb_magic_pins[] = {
+ RCAR_GP_PIN(5, 11),
+};
+static const unsigned int avb_magic_mux[] = {
+ AVB_MAGIC_MARK,
+};
+static const unsigned int avb_phy_int_pins[] = {
+ RCAR_GP_PIN(5, 16),
+};
+static const unsigned int avb_phy_int_mux[] = {
+ AVB_PHY_INT_MARK,
+};
+static const unsigned int avb_mdio_pins[] = {
+ RCAR_GP_PIN(5, 12), RCAR_GP_PIN(5, 9),
+};
+static const unsigned int avb_mdio_mux[] = {
+ AVB_MDC_MARK, AVB_MDIO_MARK,
+};
+static const unsigned int avb_mii_pins[] = {
+ RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 20),
+ RCAR_GP_PIN(5, 21),
+
+ RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+ RCAR_GP_PIN(5, 3),
+
+ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 10),
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 27),
+ RCAR_GP_PIN(5, 28), RCAR_GP_PIN(5, 29),
+};
+static const unsigned int avb_mii_mux[] = {
+ AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+ AVB_TXD3_MARK,
+
+ AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK,
+
+ AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+ AVB_CRS_MARK, AVB_TX_EN_MARK, AVB_TX_ER_MARK,
+ AVB_TX_CLK_MARK, AVB_COL_MARK,
+};
+static const unsigned int avb_gmii_pins[] = {
+ RCAR_GP_PIN(5, 18), RCAR_GP_PIN(5, 19), RCAR_GP_PIN(5, 20),
+ RCAR_GP_PIN(5, 21), RCAR_GP_PIN(5, 22), RCAR_GP_PIN(5, 23),
+ RCAR_GP_PIN(5, 24), RCAR_GP_PIN(5, 25),
+
+ RCAR_GP_PIN(5, 0), RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+ RCAR_GP_PIN(5, 3), RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 5),
+ RCAR_GP_PIN(5, 6), RCAR_GP_PIN(5, 7),
+
+ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 10),
+ RCAR_GP_PIN(5, 15), RCAR_GP_PIN(5, 30), RCAR_GP_PIN(5, 17),
+ RCAR_GP_PIN(5, 26), RCAR_GP_PIN(5, 27), RCAR_GP_PIN(5, 28),
+ RCAR_GP_PIN(5, 29),
+};
+static const unsigned int avb_gmii_mux[] = {
+ AVB_TXD0_MARK, AVB_TXD1_MARK, AVB_TXD2_MARK,
+ AVB_TXD3_MARK, AVB_TXD4_MARK, AVB_TXD5_MARK,
+ AVB_TXD6_MARK, AVB_TXD7_MARK,
+
+ AVB_RXD0_MARK, AVB_RXD1_MARK, AVB_RXD2_MARK,
+ AVB_RXD3_MARK, AVB_RXD4_MARK, AVB_RXD5_MARK,
+ AVB_RXD6_MARK, AVB_RXD7_MARK,
+
+ AVB_RX_ER_MARK, AVB_RX_CLK_MARK, AVB_RX_DV_MARK,
+ AVB_CRS_MARK, AVB_GTX_CLK_MARK, AVB_GTXREFCLK_MARK,
+ AVB_TX_EN_MARK, AVB_TX_ER_MARK, AVB_TX_CLK_MARK,
+ AVB_COL_MARK,
+};
+
/* - CAN -------------------------------------------------------------------- */
static const unsigned int can0_data_pins[] = {
@@ -3602,6 +3664,23 @@ static const unsigned int scifb2_data_d_pins[] = {
static const unsigned int scifb2_data_d_mux[] = {
SCIFB2_RXD_D_MARK, SCIFB2_TXD_D_MARK,
};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(2, 29),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(7, 19),
+};
+static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
+
/* - SDHI0 ------------------------------------------------------------------ */
static const unsigned int sdhi0_data1_pins[] = {
/* D0 */
@@ -4258,6 +4337,12 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(audio_clk_b_b),
SH_PFC_PIN_GROUP(audio_clk_c),
SH_PFC_PIN_GROUP(audio_clkout),
+ SH_PFC_PIN_GROUP(avb_link),
+ SH_PFC_PIN_GROUP(avb_magic),
+ SH_PFC_PIN_GROUP(avb_phy_int),
+ SH_PFC_PIN_GROUP(avb_mdio),
+ SH_PFC_PIN_GROUP(avb_mii),
+ SH_PFC_PIN_GROUP(avb_gmii),
SH_PFC_PIN_GROUP(can0_data),
SH_PFC_PIN_GROUP(can0_data_b),
SH_PFC_PIN_GROUP(can0_data_c),
@@ -4510,6 +4595,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scifb2_data_c),
SH_PFC_PIN_GROUP(scifb2_clk_c),
SH_PFC_PIN_GROUP(scifb2_data_d),
+ SH_PFC_PIN_GROUP(scif_clk),
+ SH_PFC_PIN_GROUP(scif_clk_b),
SH_PFC_PIN_GROUP(sdhi0_data1),
SH_PFC_PIN_GROUP(sdhi0_data4),
SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -4597,6 +4684,15 @@ static const char * const audio_clk_groups[] = {
"audio_clkout",
};
+static const char * const avb_groups[] = {
+ "avb_link",
+ "avb_magic",
+ "avb_phy_int",
+ "avb_mdio",
+ "avb_mii",
+ "avb_gmii",
+};
+
static const char * const can0_groups[] = {
"can0_data",
"can0_data_b",
@@ -4976,6 +5072,11 @@ static const char * const scifb2_groups[] = {
"scifb2_data_d",
};
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+ "scif_clk_b",
+};
+
static const char * const sdhi0_groups[] = {
"sdhi0_data1",
"sdhi0_data4",
@@ -5081,6 +5182,7 @@ static const char * const vin2_groups[] = {
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(audio_clk),
+ SH_PFC_FUNCTION(avb),
SH_PFC_FUNCTION(can0),
SH_PFC_FUNCTION(can1),
SH_PFC_FUNCTION(du),
@@ -5126,6 +5228,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scifb0),
SH_PFC_FUNCTION(scifb1),
SH_PFC_FUNCTION(scifb2),
+ SH_PFC_FUNCTION(scif_clk),
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
index 086f679..3718c78 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c
@@ -15,25 +15,6 @@
#include "core.h"
#include "sh_pfc.h"
-#define PORT_GP_26(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
- PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \
- PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \
- PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \
- PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \
- PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \
- PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \
- PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \
- PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
-#define PORT_GP_28(bank, fn, sfx) \
- PORT_GP_26(bank, fn, sfx), \
- PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_26(1, fn, sfx), \
@@ -618,28 +599,28 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(A2_MARK, FN_A2),
- PINMUX_DATA(WE0_N_MARK, FN_WE0_N),
- PINMUX_DATA(WE1_N_MARK, FN_WE1_N),
- PINMUX_DATA(DACK0_MARK, FN_DACK0),
- PINMUX_DATA(USB0_PWEN_MARK, FN_USB0_PWEN),
- PINMUX_DATA(USB0_OVC_MARK, FN_USB0_OVC),
- PINMUX_DATA(USB1_PWEN_MARK, FN_USB1_PWEN),
- PINMUX_DATA(USB1_OVC_MARK, FN_USB1_OVC),
- PINMUX_DATA(SD0_CLK_MARK, FN_SD0_CLK),
- PINMUX_DATA(SD0_CMD_MARK, FN_SD0_CMD),
- PINMUX_DATA(SD0_DATA0_MARK, FN_SD0_DATA0),
- PINMUX_DATA(SD0_DATA1_MARK, FN_SD0_DATA1),
- PINMUX_DATA(SD0_DATA2_MARK, FN_SD0_DATA2),
- PINMUX_DATA(SD0_DATA3_MARK, FN_SD0_DATA3),
- PINMUX_DATA(SD0_CD_MARK, FN_SD0_CD),
- PINMUX_DATA(SD0_WP_MARK, FN_SD0_WP),
- PINMUX_DATA(SD1_CLK_MARK, FN_SD1_CLK),
- PINMUX_DATA(SD1_CMD_MARK, FN_SD1_CMD),
- PINMUX_DATA(SD1_DATA0_MARK, FN_SD1_DATA0),
- PINMUX_DATA(SD1_DATA1_MARK, FN_SD1_DATA1),
- PINMUX_DATA(SD1_DATA2_MARK, FN_SD1_DATA2),
- PINMUX_DATA(SD1_DATA3_MARK, FN_SD1_DATA3),
+ PINMUX_SINGLE(A2),
+ PINMUX_SINGLE(WE0_N),
+ PINMUX_SINGLE(WE1_N),
+ PINMUX_SINGLE(DACK0),
+ PINMUX_SINGLE(USB0_PWEN),
+ PINMUX_SINGLE(USB0_OVC),
+ PINMUX_SINGLE(USB1_PWEN),
+ PINMUX_SINGLE(USB1_OVC),
+ PINMUX_SINGLE(SD0_CLK),
+ PINMUX_SINGLE(SD0_CMD),
+ PINMUX_SINGLE(SD0_DATA0),
+ PINMUX_SINGLE(SD0_DATA1),
+ PINMUX_SINGLE(SD0_DATA2),
+ PINMUX_SINGLE(SD0_DATA3),
+ PINMUX_SINGLE(SD0_CD),
+ PINMUX_SINGLE(SD0_WP),
+ PINMUX_SINGLE(SD1_CLK),
+ PINMUX_SINGLE(SD1_CMD),
+ PINMUX_SINGLE(SD1_DATA0),
+ PINMUX_SINGLE(SD1_DATA1),
+ PINMUX_SINGLE(SD1_DATA2),
+ PINMUX_SINGLE(SD1_DATA3),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_0, SD1_CD),
@@ -2644,6 +2625,21 @@ static const unsigned int scifb2_ctrl_pins[] = {
static const unsigned int scifb2_ctrl_mux[] = {
SCIFB2_RTS_N_MARK, SCIFB2_CTS_N_MARK,
};
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int scif_clk_mux[] = {
+ SCIF_CLK_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(3, 29),
+};
+static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
/* - SDHI0 ------------------------------------------------------------------ */
static const unsigned int sdhi0_data1_pins[] = {
/* D0 */
@@ -3071,6 +3067,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scifb2_data),
SH_PFC_PIN_GROUP(scifb2_clk),
SH_PFC_PIN_GROUP(scifb2_ctrl),
+ SH_PFC_PIN_GROUP(scif_clk),
+ SH_PFC_PIN_GROUP(scif_clk_b),
SH_PFC_PIN_GROUP(sdhi0_data1),
SH_PFC_PIN_GROUP(sdhi0_data4),
SH_PFC_PIN_GROUP(sdhi0_ctrl),
@@ -3354,6 +3352,11 @@ static const char * const scifb2_groups[] = {
"scifb2_ctrl",
};
+static const char * const scif_clk_groups[] = {
+ "scif_clk",
+ "scif_clk_b",
+};
+
static const char * const sdhi0_groups[] = {
"sdhi0_data1",
"sdhi0_data4",
@@ -3441,6 +3444,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(scifb0),
SH_PFC_FUNCTION(scifb1),
SH_PFC_FUNCTION(scifb2),
+ SH_PFC_FUNCTION(scif_clk),
SH_PFC_FUNCTION(sdhi0),
SH_PFC_FUNCTION(sdhi1),
SH_PFC_FUNCTION(sdhi2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
index 7ddb2ad..ce4f5cd 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7795.c
@@ -13,46 +13,15 @@
#include "core.h"
#include "sh_pfc.h"
-#define PORT_GP_3(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx)
-
-#define PORT_GP_14(bank, fn, sfx) \
- PORT_GP_3(bank, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
- PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \
- PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \
- PORT_GP_1(bank, 14, fn, sfx)
-
-#define PORT_GP_15(bank, fn, sfx) \
- PORT_GP_14(bank, fn, sfx), PORT_GP_1(bank, 15, fn, sfx)
-
-#define PORT_GP_17(bank, fn, sfx) \
- PORT_GP_15(bank, fn, sfx), \
- PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx)
-
-#define PORT_GP_25(bank, fn, sfx) \
- PORT_GP_17(bank, fn, sfx), \
- PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \
- PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \
- PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \
- PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx)
-
-#define PORT_GP_27(bank, fn, sfx) \
- PORT_GP_25(bank, fn, sfx), \
- PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
- PORT_GP_15(0, fn, sfx), \
- PORT_GP_27(1, fn, sfx), \
- PORT_GP_14(2, fn, sfx), \
- PORT_GP_15(3, fn, sfx), \
- PORT_GP_17(4, fn, sfx), \
- PORT_GP_25(5, fn, sfx), \
+ PORT_GP_16(0, fn, sfx), \
+ PORT_GP_28(1, fn, sfx), \
+ PORT_GP_15(2, fn, sfx), \
+ PORT_GP_16(3, fn, sfx), \
+ PORT_GP_18(4, fn, sfx), \
+ PORT_GP_26(5, fn, sfx), \
PORT_GP_32(6, fn, sfx), \
- PORT_GP_3(7, fn, sfx)
+ PORT_GP_4(7, fn, sfx)
/*
* F_() : just information
* FM() : macro for FN_xxx / xxx_MARK
@@ -495,7 +464,7 @@ FM(IP16_31_28) IP16_31_28
#define MOD_SEL1_13 FM(SEL_SCIF3_0) FM(SEL_SCIF3_1)
#define MOD_SEL1_12 FM(SEL_SCIF2_0) FM(SEL_SCIF2_1)
#define MOD_SEL1_11 FM(SEL_SCIF1_0) FM(SEL_SCIF1_1)
-#define MOD_SEL1_10 FM(SEL_SCIF_0) FM(SEL_SCIF_1)
+#define MOD_SEL1_10 FM(SEL_SATA_0) FM(SEL_SATA_1)
#define MOD_SEL1_9 FM(SEL_REMOCON_0) FM(SEL_REMOCON_1)
#define MOD_SEL1_6 FM(SEL_RCAN0_0) FM(SEL_RCAN0_1)
#define MOD_SEL1_5 FM(SEL_PWM6_0) FM(SEL_PWM6_1)
@@ -580,6 +549,25 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(),
+ PINMUX_SINGLE(AVS1),
+ PINMUX_SINGLE(AVS2),
+ PINMUX_SINGLE(HDMI0_CEC),
+ PINMUX_SINGLE(HDMI1_CEC),
+ PINMUX_SINGLE(MSIOF0_RXD),
+ PINMUX_SINGLE(MSIOF0_SCK),
+ PINMUX_SINGLE(MSIOF0_TXD),
+ PINMUX_SINGLE(SD2_CMD),
+ PINMUX_SINGLE(SD3_CLK),
+ PINMUX_SINGLE(SD3_CMD),
+ PINMUX_SINGLE(SD3_DAT0),
+ PINMUX_SINGLE(SD3_DAT1),
+ PINMUX_SINGLE(SD3_DAT2),
+ PINMUX_SINGLE(SD3_DAT3),
+ PINMUX_SINGLE(SD3_DS),
+ PINMUX_SINGLE(SSI_SCK5),
+ PINMUX_SINGLE(SSI_SDATA5),
+ PINMUX_SINGLE(SSI_WS5),
+
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_3_0, AVB_MDC),
PINMUX_IPSR_MSEL(IP0_3_0, MSIOF2_SS2_C, SEL_MSIOF2_2),
@@ -1033,7 +1021,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_DATA(IP9_19_16, SD2_DAT3),
PINMUX_IPSR_DATA(IP9_23_20, SD2_DS),
- PINMUX_IPSR_MSEL(IP9_23_20, SATA_DEVSLP_B, SEL_SCIF_1),
+ PINMUX_IPSR_MSEL(IP9_23_20, SATA_DEVSLP_B, SEL_SATA_1),
PINMUX_IPSR_DATA(IP9_27_24, SD3_DAT4),
PINMUX_IPSR_MSEL(IP9_27_24, SD2_CD_A, SEL_SDHI2_0),
@@ -1293,7 +1281,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_DATA(IP15_11_8, SSI_SDATA6),
PINMUX_IPSR_MSEL(IP15_11_8, SIM0_CLK_D, SEL_SIMCARD_3),
- PINMUX_IPSR_MSEL(IP15_11_8, SATA_DEVSLP_A, SEL_SCIF_0),
+ PINMUX_IPSR_MSEL(IP15_11_8, SATA_DEVSLP_A, SEL_SATA_0),
PINMUX_IPSR_DATA(IP15_15_12, SSI_SCK78),
PINMUX_IPSR_MSEL(IP15_15_12, HRX2_B, SEL_HSCIF2_1),
@@ -1612,6 +1600,191 @@ static const unsigned int avb_avtp_capture_b_mux[] = {
AVB_AVTP_CAPTURE_B_MARK,
};
+/* - HSCIF0 ----------------------------------------------------------------- */
+static const unsigned int hscif0_data_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 13), RCAR_GP_PIN(5, 14),
+};
+static const unsigned int hscif0_data_mux[] = {
+ HRX0_MARK, HTX0_MARK,
+};
+static const unsigned int hscif0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 12),
+};
+static const unsigned int hscif0_clk_mux[] = {
+ HSCK0_MARK,
+};
+static const unsigned int hscif0_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(5, 16), RCAR_GP_PIN(5, 15),
+};
+static const unsigned int hscif0_ctrl_mux[] = {
+ HRTS0_N_MARK, HCTS0_N_MARK,
+};
+/* - HSCIF1 ----------------------------------------------------------------- */
+static const unsigned int hscif1_data_a_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 5), RCAR_GP_PIN(5, 6),
+};
+static const unsigned int hscif1_data_a_mux[] = {
+ HRX1_A_MARK, HTX1_A_MARK,
+};
+static const unsigned int hscif1_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int hscif1_clk_a_mux[] = {
+ HSCK1_A_MARK,
+};
+static const unsigned int hscif1_ctrl_a_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(5, 8), RCAR_GP_PIN(5, 7),
+};
+static const unsigned int hscif1_ctrl_a_mux[] = {
+ HRTS1_N_A_MARK, HCTS1_N_A_MARK,
+};
+
+static const unsigned int hscif1_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(5, 1), RCAR_GP_PIN(5, 2),
+};
+static const unsigned int hscif1_data_b_mux[] = {
+ HRX1_B_MARK, HTX1_B_MARK,
+};
+static const unsigned int hscif1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int hscif1_clk_b_mux[] = {
+ HSCK1_B_MARK,
+};
+static const unsigned int hscif1_ctrl_b_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(5, 4), RCAR_GP_PIN(5, 3),
+};
+static const unsigned int hscif1_ctrl_b_mux[] = {
+ HRTS1_N_B_MARK, HCTS1_N_B_MARK,
+};
+/* - HSCIF2 ----------------------------------------------------------------- */
+static const unsigned int hscif2_data_a_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(6, 8), RCAR_GP_PIN(6, 9),
+};
+static const unsigned int hscif2_data_a_mux[] = {
+ HRX2_A_MARK, HTX2_A_MARK,
+};
+static const unsigned int hscif2_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(6, 10),
+};
+static const unsigned int hscif2_clk_a_mux[] = {
+ HSCK2_A_MARK,
+};
+static const unsigned int hscif2_ctrl_a_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(6, 7), RCAR_GP_PIN(6, 6),
+};
+static const unsigned int hscif2_ctrl_a_mux[] = {
+ HRTS2_N_A_MARK, HCTS2_N_A_MARK,
+};
+
+static const unsigned int hscif2_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(6, 17), RCAR_GP_PIN(6, 18),
+};
+static const unsigned int hscif2_data_b_mux[] = {
+ HRX2_B_MARK, HTX2_B_MARK,
+};
+static const unsigned int hscif2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int hscif2_clk_b_mux[] = {
+ HSCK1_B_MARK,
+};
+static const unsigned int hscif2_ctrl_b_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(6, 20), RCAR_GP_PIN(6, 19),
+};
+static const unsigned int hscif2_ctrl_b_mux[] = {
+ HRTS2_N_B_MARK, HCTS2_N_B_MARK,
+};
+/* - HSCIF3 ----------------------------------------------------------------- */
+static const unsigned int hscif3_data_a_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(1, 23), RCAR_GP_PIN(1, 24),
+};
+static const unsigned int hscif3_data_a_mux[] = {
+ HRX3_A_MARK, HTX3_A_MARK,
+};
+static const unsigned int hscif3_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 22),
+};
+static const unsigned int hscif3_clk_mux[] = {
+ HSCK3_MARK,
+};
+static const unsigned int hscif3_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(1, 26), RCAR_GP_PIN(1, 25),
+};
+static const unsigned int hscif3_ctrl_mux[] = {
+ HRTS3_N_MARK, HCTS3_N_MARK,
+};
+
+static const unsigned int hscif3_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 10), RCAR_GP_PIN(0, 11),
+};
+static const unsigned int hscif3_data_b_mux[] = {
+ HRX3_B_MARK, HTX3_B_MARK,
+};
+static const unsigned int hscif3_data_c_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(0, 14), RCAR_GP_PIN(0, 15),
+};
+static const unsigned int hscif3_data_c_mux[] = {
+ HRX3_C_MARK, HTX3_C_MARK,
+};
+static const unsigned int hscif3_data_d_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(2, 7), RCAR_GP_PIN(2, 8),
+};
+static const unsigned int hscif3_data_d_mux[] = {
+ HRX3_D_MARK, HTX3_D_MARK,
+};
+/* - HSCIF4 ----------------------------------------------------------------- */
+static const unsigned int hscif4_data_a_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(1, 12), RCAR_GP_PIN(1, 13),
+};
+static const unsigned int hscif4_data_a_mux[] = {
+ HRX4_A_MARK, HTX4_A_MARK,
+};
+static const unsigned int hscif4_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 11),
+};
+static const unsigned int hscif4_clk_mux[] = {
+ HSCK4_MARK,
+};
+static const unsigned int hscif4_ctrl_pins[] = {
+ /* RTS, CTS */
+ RCAR_GP_PIN(1, 15), RCAR_GP_PIN(1, 14),
+};
+static const unsigned int hscif4_ctrl_mux[] = {
+ HRTS4_N_MARK, HCTS3_N_MARK,
+};
+
+static const unsigned int hscif4_data_b_pins[] = {
+ /* RX, TX */
+ RCAR_GP_PIN(1, 8), RCAR_GP_PIN(1, 11),
+};
+static const unsigned int hscif4_data_b_mux[] = {
+ HRX4_B_MARK, HTX4_B_MARK,
+};
+
/* - I2C -------------------------------------------------------------------- */
static const unsigned int i2c1_a_pins[] = {
/* SDA, SCL */
@@ -1663,6 +1836,678 @@ static const unsigned int i2c6_c_mux[] = {
SDA6_C_MARK, SCL6_C_MARK,
};
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_clk_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 17),
+};
+static const unsigned int msiof0_clk_mux[] = {
+ MSIOF0_SCK_MARK,
+};
+static const unsigned int msiof0_sync_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 18),
+};
+static const unsigned int msiof0_sync_mux[] = {
+ MSIOF0_SYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 19),
+};
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 21),
+};
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 20),
+};
+static const unsigned int msiof0_txd_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 22),
+};
+static const unsigned int msiof0_rxd_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(6, 8),
+};
+static const unsigned int msiof1_clk_a_mux[] = {
+ MSIOF1_SCK_A_MARK,
+};
+static const unsigned int msiof1_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(6, 9),
+};
+static const unsigned int msiof1_sync_a_mux[] = {
+ MSIOF1_SYNC_A_MARK,
+};
+static const unsigned int msiof1_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(6, 5),
+};
+static const unsigned int msiof1_ss1_a_mux[] = {
+ MSIOF1_SS1_A_MARK,
+};
+static const unsigned int msiof1_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(6, 6),
+};
+static const unsigned int msiof1_ss2_a_mux[] = {
+ MSIOF1_SS2_A_MARK,
+};
+static const unsigned int msiof1_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(6, 7),
+};
+static const unsigned int msiof1_txd_a_mux[] = {
+ MSIOF1_TXD_A_MARK,
+};
+static const unsigned int msiof1_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(6, 10),
+};
+static const unsigned int msiof1_rxd_a_mux[] = {
+ MSIOF1_RXD_A_MARK,
+};
+static const unsigned int msiof1_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 9),
+};
+static const unsigned int msiof1_clk_b_mux[] = {
+ MSIOF1_SCK_B_MARK,
+};
+static const unsigned int msiof1_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 3),
+};
+static const unsigned int msiof1_sync_b_mux[] = {
+ MSIOF1_SYNC_B_MARK,
+};
+static const unsigned int msiof1_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 4),
+};
+static const unsigned int msiof1_ss1_b_mux[] = {
+ MSIOF1_SS1_B_MARK,
+};
+static const unsigned int msiof1_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 0),
+};
+static const unsigned int msiof1_ss2_b_mux[] = {
+ MSIOF1_SS2_B_MARK,
+};
+static const unsigned int msiof1_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 8),
+};
+static const unsigned int msiof1_txd_b_mux[] = {
+ MSIOF1_TXD_B_MARK,
+};
+static const unsigned int msiof1_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 7),
+};
+static const unsigned int msiof1_rxd_b_mux[] = {
+ MSIOF1_RXD_B_MARK,
+};
+static const unsigned int msiof1_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(6, 17),
+};
+static const unsigned int msiof1_clk_c_mux[] = {
+ MSIOF1_SCK_C_MARK,
+};
+static const unsigned int msiof1_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(6, 18),
+};
+static const unsigned int msiof1_sync_c_mux[] = {
+ MSIOF1_SYNC_C_MARK,
+};
+static const unsigned int msiof1_ss1_c_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(6, 21),
+};
+static const unsigned int msiof1_ss1_c_mux[] = {
+ MSIOF1_SS1_C_MARK,
+};
+static const unsigned int msiof1_ss2_c_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(6, 27),
+};
+static const unsigned int msiof1_ss2_c_mux[] = {
+ MSIOF1_SS2_C_MARK,
+};
+static const unsigned int msiof1_txd_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(6, 20),
+};
+static const unsigned int msiof1_txd_c_mux[] = {
+ MSIOF1_TXD_C_MARK,
+};
+static const unsigned int msiof1_rxd_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(6, 19),
+};
+static const unsigned int msiof1_rxd_c_mux[] = {
+ MSIOF1_RXD_C_MARK,
+};
+static const unsigned int msiof1_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 12),
+};
+static const unsigned int msiof1_clk_d_mux[] = {
+ MSIOF1_SCK_D_MARK,
+};
+static const unsigned int msiof1_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 15),
+};
+static const unsigned int msiof1_sync_d_mux[] = {
+ MSIOF1_SYNC_D_MARK,
+};
+static const unsigned int msiof1_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(5, 16),
+};
+static const unsigned int msiof1_ss1_d_mux[] = {
+ MSIOF1_SS1_D_MARK,
+};
+static const unsigned int msiof1_ss2_d_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(5, 21),
+};
+static const unsigned int msiof1_ss2_d_mux[] = {
+ MSIOF1_SS2_D_MARK,
+};
+static const unsigned int msiof1_txd_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(5, 14),
+};
+static const unsigned int msiof1_txd_d_mux[] = {
+ MSIOF1_TXD_D_MARK,
+};
+static const unsigned int msiof1_rxd_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 13),
+};
+static const unsigned int msiof1_rxd_d_mux[] = {
+ MSIOF1_RXD_D_MARK,
+};
+static const unsigned int msiof1_clk_e_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 0),
+};
+static const unsigned int msiof1_clk_e_mux[] = {
+ MSIOF1_SCK_E_MARK,
+};
+static const unsigned int msiof1_sync_e_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(3, 1),
+};
+static const unsigned int msiof1_sync_e_mux[] = {
+ MSIOF1_SYNC_E_MARK,
+};
+static const unsigned int msiof1_ss1_e_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(3, 4),
+};
+static const unsigned int msiof1_ss1_e_mux[] = {
+ MSIOF1_SS1_E_MARK,
+};
+static const unsigned int msiof1_ss2_e_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(3, 5),
+};
+static const unsigned int msiof1_ss2_e_mux[] = {
+ MSIOF1_SS2_E_MARK,
+};
+static const unsigned int msiof1_txd_e_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(3, 3),
+};
+static const unsigned int msiof1_txd_e_mux[] = {
+ MSIOF1_TXD_E_MARK,
+};
+static const unsigned int msiof1_rxd_e_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(3, 2),
+};
+static const unsigned int msiof1_rxd_e_mux[] = {
+ MSIOF1_RXD_E_MARK,
+};
+static const unsigned int msiof1_clk_f_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(5, 23),
+};
+static const unsigned int msiof1_clk_f_mux[] = {
+ MSIOF1_SCK_F_MARK,
+};
+static const unsigned int msiof1_sync_f_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(5, 24),
+};
+static const unsigned int msiof1_sync_f_mux[] = {
+ MSIOF1_SYNC_F_MARK,
+};
+static const unsigned int msiof1_ss1_f_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(6, 1),
+};
+static const unsigned int msiof1_ss1_f_mux[] = {
+ MSIOF1_SS1_F_MARK,
+};
+static const unsigned int msiof1_ss2_f_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(6, 2),
+};
+static const unsigned int msiof1_ss2_f_mux[] = {
+ MSIOF1_SS2_F_MARK,
+};
+static const unsigned int msiof1_txd_f_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(6, 0),
+};
+static const unsigned int msiof1_txd_f_mux[] = {
+ MSIOF1_TXD_F_MARK,
+};
+static const unsigned int msiof1_rxd_f_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(5, 25),
+};
+static const unsigned int msiof1_rxd_f_mux[] = {
+ MSIOF1_RXD_F_MARK,
+};
+static const unsigned int msiof1_clk_g_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(3, 6),
+};
+static const unsigned int msiof1_clk_g_mux[] = {
+ MSIOF1_SCK_G_MARK,
+};
+static const unsigned int msiof1_sync_g_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(3, 7),
+};
+static const unsigned int msiof1_sync_g_mux[] = {
+ MSIOF1_SYNC_G_MARK,
+};
+static const unsigned int msiof1_ss1_g_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(3, 10),
+};
+static const unsigned int msiof1_ss1_g_mux[] = {
+ MSIOF1_SS1_G_MARK,
+};
+static const unsigned int msiof1_ss2_g_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(3, 11),
+};
+static const unsigned int msiof1_ss2_g_mux[] = {
+ MSIOF1_SS2_G_MARK,
+};
+static const unsigned int msiof1_txd_g_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(3, 9),
+};
+static const unsigned int msiof1_txd_g_mux[] = {
+ MSIOF1_TXD_G_MARK,
+};
+static const unsigned int msiof1_rxd_g_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(3, 8),
+};
+static const unsigned int msiof1_rxd_g_mux[] = {
+ MSIOF1_RXD_G_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 9),
+};
+static const unsigned int msiof2_clk_a_mux[] = {
+ MSIOF2_SCK_A_MARK,
+};
+static const unsigned int msiof2_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 8),
+};
+static const unsigned int msiof2_sync_a_mux[] = {
+ MSIOF2_SYNC_A_MARK,
+};
+static const unsigned int msiof2_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 6),
+};
+static const unsigned int msiof2_ss1_a_mux[] = {
+ MSIOF2_SS1_A_MARK,
+};
+static const unsigned int msiof2_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 7),
+};
+static const unsigned int msiof2_ss2_a_mux[] = {
+ MSIOF2_SS2_A_MARK,
+};
+static const unsigned int msiof2_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 11),
+};
+static const unsigned int msiof2_txd_a_mux[] = {
+ MSIOF2_TXD_A_MARK,
+};
+static const unsigned int msiof2_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 10),
+};
+static const unsigned int msiof2_rxd_a_mux[] = {
+ MSIOF2_RXD_A_MARK,
+};
+static const unsigned int msiof2_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 4),
+};
+static const unsigned int msiof2_clk_b_mux[] = {
+ MSIOF2_SCK_B_MARK,
+};
+static const unsigned int msiof2_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 5),
+};
+static const unsigned int msiof2_sync_b_mux[] = {
+ MSIOF2_SYNC_B_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+ MSIOF2_SS1_B_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+ MSIOF2_SS2_B_MARK,
+};
+static const unsigned int msiof2_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 7),
+};
+static const unsigned int msiof2_txd_b_mux[] = {
+ MSIOF2_TXD_B_MARK,
+};
+static const unsigned int msiof2_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 6),
+};
+static const unsigned int msiof2_rxd_b_mux[] = {
+ MSIOF2_RXD_B_MARK,
+};
+static const unsigned int msiof2_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(2, 12),
+};
+static const unsigned int msiof2_clk_c_mux[] = {
+ MSIOF2_SCK_C_MARK,
+};
+static const unsigned int msiof2_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(2, 11),
+};
+static const unsigned int msiof2_sync_c_mux[] = {
+ MSIOF2_SYNC_C_MARK,
+};
+static const unsigned int msiof2_ss1_c_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(2, 10),
+};
+static const unsigned int msiof2_ss1_c_mux[] = {
+ MSIOF2_SS1_C_MARK,
+};
+static const unsigned int msiof2_ss2_c_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(2, 9),
+};
+static const unsigned int msiof2_ss2_c_mux[] = {
+ MSIOF2_SS2_C_MARK,
+};
+static const unsigned int msiof2_txd_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(2, 14),
+};
+static const unsigned int msiof2_txd_c_mux[] = {
+ MSIOF2_TXD_C_MARK,
+};
+static const unsigned int msiof2_rxd_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(2, 13),
+};
+static const unsigned int msiof2_rxd_c_mux[] = {
+ MSIOF2_RXD_C_MARK,
+};
+static const unsigned int msiof2_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 8),
+};
+static const unsigned int msiof2_clk_d_mux[] = {
+ MSIOF2_SCK_D_MARK,
+};
+static const unsigned int msiof2_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 9),
+};
+static const unsigned int msiof2_sync_d_mux[] = {
+ MSIOF2_SYNC_D_MARK,
+};
+static const unsigned int msiof2_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 12),
+};
+static const unsigned int msiof2_ss1_d_mux[] = {
+ MSIOF2_SS1_D_MARK,
+};
+static const unsigned int msiof2_ss2_d_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 13),
+};
+static const unsigned int msiof2_ss2_d_mux[] = {
+ MSIOF2_SS2_D_MARK,
+};
+static const unsigned int msiof2_txd_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 11),
+};
+static const unsigned int msiof2_txd_d_mux[] = {
+ MSIOF2_TXD_D_MARK,
+};
+static const unsigned int msiof2_rxd_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 10),
+};
+static const unsigned int msiof2_rxd_d_mux[] = {
+ MSIOF2_RXD_D_MARK,
+};
+/* - MSIOF3 ----------------------------------------------------------------- */
+static const unsigned int msiof3_clk_a_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(0, 0),
+};
+static const unsigned int msiof3_clk_a_mux[] = {
+ MSIOF3_SCK_A_MARK,
+};
+static const unsigned int msiof3_sync_a_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(0, 1),
+};
+static const unsigned int msiof3_sync_a_mux[] = {
+ MSIOF3_SYNC_A_MARK,
+};
+static const unsigned int msiof3_ss1_a_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(0, 14),
+};
+static const unsigned int msiof3_ss1_a_mux[] = {
+ MSIOF3_SS1_A_MARK,
+};
+static const unsigned int msiof3_ss2_a_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(0, 15),
+};
+static const unsigned int msiof3_ss2_a_mux[] = {
+ MSIOF3_SS2_A_MARK,
+};
+static const unsigned int msiof3_txd_a_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(0, 3),
+};
+static const unsigned int msiof3_txd_a_mux[] = {
+ MSIOF3_TXD_A_MARK,
+};
+static const unsigned int msiof3_rxd_a_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(0, 2),
+};
+static const unsigned int msiof3_rxd_a_mux[] = {
+ MSIOF3_RXD_A_MARK,
+};
+static const unsigned int msiof3_clk_b_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 2),
+};
+static const unsigned int msiof3_clk_b_mux[] = {
+ MSIOF3_SCK_B_MARK,
+};
+static const unsigned int msiof3_sync_b_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 0),
+};
+static const unsigned int msiof3_sync_b_mux[] = {
+ MSIOF3_SYNC_B_MARK,
+};
+static const unsigned int msiof3_ss1_b_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 4),
+};
+static const unsigned int msiof3_ss1_b_mux[] = {
+ MSIOF3_SS1_B_MARK,
+};
+static const unsigned int msiof3_ss2_b_pins[] = {
+ /* SS2 */
+ RCAR_GP_PIN(1, 5),
+};
+static const unsigned int msiof3_ss2_b_mux[] = {
+ MSIOF3_SS2_B_MARK,
+};
+static const unsigned int msiof3_txd_b_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 1),
+};
+static const unsigned int msiof3_txd_b_mux[] = {
+ MSIOF3_TXD_B_MARK,
+};
+static const unsigned int msiof3_rxd_b_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 3),
+};
+static const unsigned int msiof3_rxd_b_mux[] = {
+ MSIOF3_RXD_B_MARK,
+};
+static const unsigned int msiof3_clk_c_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 12),
+};
+static const unsigned int msiof3_clk_c_mux[] = {
+ MSIOF3_SCK_C_MARK,
+};
+static const unsigned int msiof3_sync_c_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 13),
+};
+static const unsigned int msiof3_sync_c_mux[] = {
+ MSIOF3_SYNC_C_MARK,
+};
+static const unsigned int msiof3_txd_c_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 15),
+};
+static const unsigned int msiof3_txd_c_mux[] = {
+ MSIOF3_TXD_C_MARK,
+};
+static const unsigned int msiof3_rxd_c_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 14),
+};
+static const unsigned int msiof3_rxd_c_mux[] = {
+ MSIOF3_RXD_C_MARK,
+};
+static const unsigned int msiof3_clk_d_pins[] = {
+ /* SCK */
+ RCAR_GP_PIN(1, 22),
+};
+static const unsigned int msiof3_clk_d_mux[] = {
+ MSIOF3_SCK_D_MARK,
+};
+static const unsigned int msiof3_sync_d_pins[] = {
+ /* SYNC */
+ RCAR_GP_PIN(1, 23),
+};
+static const unsigned int msiof3_sync_d_mux[] = {
+ MSIOF3_SYNC_D_MARK,
+};
+static const unsigned int msiof3_ss1_d_pins[] = {
+ /* SS1 */
+ RCAR_GP_PIN(1, 26),
+};
+static const unsigned int msiof3_ss1_d_mux[] = {
+ MSIOF3_SS1_D_MARK,
+};
+static const unsigned int msiof3_txd_d_pins[] = {
+ /* TXD */
+ RCAR_GP_PIN(1, 25),
+};
+static const unsigned int msiof3_txd_d_mux[] = {
+ MSIOF3_TXD_D_MARK,
+};
+static const unsigned int msiof3_rxd_d_pins[] = {
+ /* RXD */
+ RCAR_GP_PIN(1, 24),
+};
+static const unsigned int msiof3_rxd_d_mux[] = {
+ MSIOF3_RXD_D_MARK,
+};
+
+/* - SATA --------------------------------------------------------------------*/
+static const unsigned int sata0_devslp_a_pins[] = {
+ /* DEVSLP */
+ RCAR_GP_PIN(6, 16),
+};
+static const unsigned int sata0_devslp_a_mux[] = {
+ SATA_DEVSLP_A_MARK,
+};
+static const unsigned int sata0_devslp_b_pins[] = {
+ /* DEVSLP */
+ RCAR_GP_PIN(4, 6),
+};
+static const unsigned int sata0_devslp_b_mux[] = {
+ SATA_DEVSLP_B_MARK,
+};
+
/* - SCIF0 ------------------------------------------------------------------ */
static const unsigned int scif0_data_pins[] = {
/* RX, TX */
@@ -1845,6 +2690,228 @@ static const unsigned int scif5_clk_pins[] = {
static const unsigned int scif5_clk_mux[] = {
SCK5_MARK,
};
+/* - SDHI0 ------------------------------------------------------------------ */
+static const unsigned int sdhi0_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(3, 2),
+};
+static const unsigned int sdhi0_data1_mux[] = {
+ SD0_DAT0_MARK,
+};
+static const unsigned int sdhi0_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(3, 2), RCAR_GP_PIN(3, 3),
+ RCAR_GP_PIN(3, 4), RCAR_GP_PIN(3, 5),
+};
+static const unsigned int sdhi0_data4_mux[] = {
+ SD0_DAT0_MARK, SD0_DAT1_MARK,
+ SD0_DAT2_MARK, SD0_DAT3_MARK,
+};
+static const unsigned int sdhi0_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(3, 0), RCAR_GP_PIN(3, 1),
+};
+static const unsigned int sdhi0_ctrl_mux[] = {
+ SD0_CLK_MARK, SD0_CMD_MARK,
+};
+static const unsigned int sdhi0_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(3, 12),
+};
+static const unsigned int sdhi0_cd_mux[] = {
+ SD0_CD_MARK,
+};
+static const unsigned int sdhi0_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(3, 13),
+};
+static const unsigned int sdhi0_wp_mux[] = {
+ SD0_WP_MARK,
+};
+/* - SDHI1 ------------------------------------------------------------------ */
+static const unsigned int sdhi1_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(3, 8),
+};
+static const unsigned int sdhi1_data1_mux[] = {
+ SD1_DAT0_MARK,
+};
+static const unsigned int sdhi1_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9),
+ RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11),
+};
+static const unsigned int sdhi1_data4_mux[] = {
+ SD1_DAT0_MARK, SD1_DAT1_MARK,
+ SD1_DAT2_MARK, SD1_DAT3_MARK,
+};
+static const unsigned int sdhi1_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(3, 6), RCAR_GP_PIN(3, 7),
+};
+static const unsigned int sdhi1_ctrl_mux[] = {
+ SD1_CLK_MARK, SD1_CMD_MARK,
+};
+static const unsigned int sdhi1_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(3, 14),
+};
+static const unsigned int sdhi1_cd_mux[] = {
+ SD1_CD_MARK,
+};
+static const unsigned int sdhi1_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(3, 15),
+};
+static const unsigned int sdhi1_wp_mux[] = {
+ SD1_WP_MARK,
+};
+/* - SDHI2 ------------------------------------------------------------------ */
+static const unsigned int sdhi2_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(4, 2),
+};
+static const unsigned int sdhi2_data1_mux[] = {
+ SD2_DAT0_MARK,
+};
+static const unsigned int sdhi2_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+ RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5),
+};
+static const unsigned int sdhi2_data4_mux[] = {
+ SD2_DAT0_MARK, SD2_DAT1_MARK,
+ SD2_DAT2_MARK, SD2_DAT3_MARK,
+};
+static const unsigned int sdhi2_data8_pins[] = {
+ /* D[0:7] */
+ RCAR_GP_PIN(4, 2), RCAR_GP_PIN(4, 3),
+ RCAR_GP_PIN(4, 4), RCAR_GP_PIN(4, 5),
+ RCAR_GP_PIN(3, 8), RCAR_GP_PIN(3, 9),
+ RCAR_GP_PIN(3, 10), RCAR_GP_PIN(3, 11),
+};
+static const unsigned int sdhi2_data8_mux[] = {
+ SD2_DAT0_MARK, SD2_DAT1_MARK,
+ SD2_DAT2_MARK, SD2_DAT3_MARK,
+ SD2_DAT4_MARK, SD2_DAT5_MARK,
+ SD2_DAT6_MARK, SD2_DAT7_MARK,
+};
+static const unsigned int sdhi2_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1),
+};
+static const unsigned int sdhi2_ctrl_mux[] = {
+ SD2_CLK_MARK, SD2_CMD_MARK,
+};
+static const unsigned int sdhi2_cd_a_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(4, 13),
+};
+static const unsigned int sdhi2_cd_a_mux[] = {
+ SD2_CD_A_MARK,
+};
+static const unsigned int sdhi2_cd_b_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(5, 10),
+};
+static const unsigned int sdhi2_cd_b_mux[] = {
+ SD2_CD_B_MARK,
+};
+static const unsigned int sdhi2_wp_a_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(4, 14),
+};
+static const unsigned int sdhi2_wp_a_mux[] = {
+ SD2_WP_A_MARK,
+};
+static const unsigned int sdhi2_wp_b_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(5, 11),
+};
+static const unsigned int sdhi2_wp_b_mux[] = {
+ SD2_WP_B_MARK,
+};
+static const unsigned int sdhi2_ds_pins[] = {
+ /* DS */
+ RCAR_GP_PIN(4, 6),
+};
+static const unsigned int sdhi2_ds_mux[] = {
+ SD2_DS_MARK,
+};
+/* - SDHI3 ------------------------------------------------------------------ */
+static const unsigned int sdhi3_data1_pins[] = {
+ /* D0 */
+ RCAR_GP_PIN(4, 9),
+};
+static const unsigned int sdhi3_data1_mux[] = {
+ SD3_DAT0_MARK,
+};
+static const unsigned int sdhi3_data4_pins[] = {
+ /* D[0:3] */
+ RCAR_GP_PIN(4, 9), RCAR_GP_PIN(4, 10),
+ RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12),
+};
+static const unsigned int sdhi3_data4_mux[] = {
+ SD3_DAT0_MARK, SD3_DAT1_MARK,
+ SD3_DAT2_MARK, SD3_DAT3_MARK,
+};
+static const unsigned int sdhi3_data8_pins[] = {
+ /* D[0:7] */
+ RCAR_GP_PIN(4, 9), RCAR_GP_PIN(4, 10),
+ RCAR_GP_PIN(4, 11), RCAR_GP_PIN(4, 12),
+ RCAR_GP_PIN(4, 13), RCAR_GP_PIN(4, 14),
+ RCAR_GP_PIN(4, 15), RCAR_GP_PIN(4, 16),
+};
+static const unsigned int sdhi3_data8_mux[] = {
+ SD3_DAT0_MARK, SD3_DAT1_MARK,
+ SD3_DAT2_MARK, SD3_DAT3_MARK,
+ SD3_DAT4_MARK, SD3_DAT5_MARK,
+ SD3_DAT6_MARK, SD3_DAT7_MARK,
+};
+static const unsigned int sdhi3_ctrl_pins[] = {
+ /* CLK, CMD */
+ RCAR_GP_PIN(4, 7), RCAR_GP_PIN(4, 8),
+};
+static const unsigned int sdhi3_ctrl_mux[] = {
+ SD3_CLK_MARK, SD3_CMD_MARK,
+};
+static const unsigned int sdhi3_cd_pins[] = {
+ /* CD */
+ RCAR_GP_PIN(4, 15),
+};
+static const unsigned int sdhi3_cd_mux[] = {
+ SD3_CD_MARK,
+};
+static const unsigned int sdhi3_wp_pins[] = {
+ /* WP */
+ RCAR_GP_PIN(4, 16),
+};
+static const unsigned int sdhi3_wp_mux[] = {
+ SD3_WP_MARK,
+};
+static const unsigned int sdhi3_ds_pins[] = {
+ /* DS */
+ RCAR_GP_PIN(4, 17),
+};
+static const unsigned int sdhi3_ds_mux[] = {
+ SD3_DS_MARK,
+};
+
+/* - SCIF Clock ------------------------------------------------------------- */
+static const unsigned int scif_clk_a_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(6, 23),
+};
+static const unsigned int scif_clk_a_mux[] = {
+ SCIF_CLK_A_MARK,
+};
+static const unsigned int scif_clk_b_pins[] = {
+ /* SCIF_CLK */
+ RCAR_GP_PIN(5, 9),
+};
+static const unsigned int scif_clk_b_mux[] = {
+ SCIF_CLK_B_MARK,
+};
/* - SSI -------------------------------------------------------------------- */
static const unsigned int ssi0_data_pins[] = {
@@ -2050,6 +3117,31 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(avb_avtp_capture_a),
SH_PFC_PIN_GROUP(avb_avtp_match_b),
SH_PFC_PIN_GROUP(avb_avtp_capture_b),
+ SH_PFC_PIN_GROUP(hscif0_data),
+ SH_PFC_PIN_GROUP(hscif0_clk),
+ SH_PFC_PIN_GROUP(hscif0_ctrl),
+ SH_PFC_PIN_GROUP(hscif1_data_a),
+ SH_PFC_PIN_GROUP(hscif1_clk_a),
+ SH_PFC_PIN_GROUP(hscif1_ctrl_a),
+ SH_PFC_PIN_GROUP(hscif1_data_b),
+ SH_PFC_PIN_GROUP(hscif1_clk_b),
+ SH_PFC_PIN_GROUP(hscif1_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif2_data_a),
+ SH_PFC_PIN_GROUP(hscif2_clk_a),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_a),
+ SH_PFC_PIN_GROUP(hscif2_data_b),
+ SH_PFC_PIN_GROUP(hscif2_clk_b),
+ SH_PFC_PIN_GROUP(hscif2_ctrl_b),
+ SH_PFC_PIN_GROUP(hscif3_data_a),
+ SH_PFC_PIN_GROUP(hscif3_clk),
+ SH_PFC_PIN_GROUP(hscif3_ctrl),
+ SH_PFC_PIN_GROUP(hscif3_data_b),
+ SH_PFC_PIN_GROUP(hscif3_data_c),
+ SH_PFC_PIN_GROUP(hscif3_data_d),
+ SH_PFC_PIN_GROUP(hscif4_data_a),
+ SH_PFC_PIN_GROUP(hscif4_clk),
+ SH_PFC_PIN_GROUP(hscif4_ctrl),
+ SH_PFC_PIN_GROUP(hscif4_data_b),
SH_PFC_PIN_GROUP(i2c1_a),
SH_PFC_PIN_GROUP(i2c1_b),
SH_PFC_PIN_GROUP(i2c2_a),
@@ -2057,6 +3149,101 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(i2c6_a),
SH_PFC_PIN_GROUP(i2c6_b),
SH_PFC_PIN_GROUP(i2c6_c),
+ SH_PFC_PIN_GROUP(msiof0_clk),
+ SH_PFC_PIN_GROUP(msiof0_sync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+ SH_PFC_PIN_GROUP(msiof1_clk_a),
+ SH_PFC_PIN_GROUP(msiof1_sync_a),
+ SH_PFC_PIN_GROUP(msiof1_ss1_a),
+ SH_PFC_PIN_GROUP(msiof1_ss2_a),
+ SH_PFC_PIN_GROUP(msiof1_txd_a),
+ SH_PFC_PIN_GROUP(msiof1_rxd_a),
+ SH_PFC_PIN_GROUP(msiof1_clk_b),
+ SH_PFC_PIN_GROUP(msiof1_sync_b),
+ SH_PFC_PIN_GROUP(msiof1_ss1_b),
+ SH_PFC_PIN_GROUP(msiof1_ss2_b),
+ SH_PFC_PIN_GROUP(msiof1_txd_b),
+ SH_PFC_PIN_GROUP(msiof1_rxd_b),
+ SH_PFC_PIN_GROUP(msiof1_clk_c),
+ SH_PFC_PIN_GROUP(msiof1_sync_c),
+ SH_PFC_PIN_GROUP(msiof1_ss1_c),
+ SH_PFC_PIN_GROUP(msiof1_ss2_c),
+ SH_PFC_PIN_GROUP(msiof1_txd_c),
+ SH_PFC_PIN_GROUP(msiof1_rxd_c),
+ SH_PFC_PIN_GROUP(msiof1_clk_d),
+ SH_PFC_PIN_GROUP(msiof1_sync_d),
+ SH_PFC_PIN_GROUP(msiof1_ss1_d),
+ SH_PFC_PIN_GROUP(msiof1_ss2_d),
+ SH_PFC_PIN_GROUP(msiof1_txd_d),
+ SH_PFC_PIN_GROUP(msiof1_rxd_d),
+ SH_PFC_PIN_GROUP(msiof1_clk_e),
+ SH_PFC_PIN_GROUP(msiof1_sync_e),
+ SH_PFC_PIN_GROUP(msiof1_ss1_e),
+ SH_PFC_PIN_GROUP(msiof1_ss2_e),
+ SH_PFC_PIN_GROUP(msiof1_txd_e),
+ SH_PFC_PIN_GROUP(msiof1_rxd_e),
+ SH_PFC_PIN_GROUP(msiof1_clk_f),
+ SH_PFC_PIN_GROUP(msiof1_sync_f),
+ SH_PFC_PIN_GROUP(msiof1_ss1_f),
+ SH_PFC_PIN_GROUP(msiof1_ss2_f),
+ SH_PFC_PIN_GROUP(msiof1_txd_f),
+ SH_PFC_PIN_GROUP(msiof1_rxd_f),
+ SH_PFC_PIN_GROUP(msiof1_clk_g),
+ SH_PFC_PIN_GROUP(msiof1_sync_g),
+ SH_PFC_PIN_GROUP(msiof1_ss1_g),
+ SH_PFC_PIN_GROUP(msiof1_ss2_g),
+ SH_PFC_PIN_GROUP(msiof1_txd_g),
+ SH_PFC_PIN_GROUP(msiof1_rxd_g),
+ SH_PFC_PIN_GROUP(msiof2_clk_a),
+ SH_PFC_PIN_GROUP(msiof2_sync_a),
+ SH_PFC_PIN_GROUP(msiof2_ss1_a),
+ SH_PFC_PIN_GROUP(msiof2_ss2_a),
+ SH_PFC_PIN_GROUP(msiof2_txd_a),
+ SH_PFC_PIN_GROUP(msiof2_rxd_a),
+ SH_PFC_PIN_GROUP(msiof2_clk_b),
+ SH_PFC_PIN_GROUP(msiof2_sync_b),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_txd_b),
+ SH_PFC_PIN_GROUP(msiof2_rxd_b),
+ SH_PFC_PIN_GROUP(msiof2_clk_c),
+ SH_PFC_PIN_GROUP(msiof2_sync_c),
+ SH_PFC_PIN_GROUP(msiof2_ss1_c),
+ SH_PFC_PIN_GROUP(msiof2_ss2_c),
+ SH_PFC_PIN_GROUP(msiof2_txd_c),
+ SH_PFC_PIN_GROUP(msiof2_rxd_c),
+ SH_PFC_PIN_GROUP(msiof2_clk_d),
+ SH_PFC_PIN_GROUP(msiof2_sync_d),
+ SH_PFC_PIN_GROUP(msiof2_ss1_d),
+ SH_PFC_PIN_GROUP(msiof2_ss2_d),
+ SH_PFC_PIN_GROUP(msiof2_txd_d),
+ SH_PFC_PIN_GROUP(msiof2_rxd_d),
+ SH_PFC_PIN_GROUP(msiof3_clk_a),
+ SH_PFC_PIN_GROUP(msiof3_sync_a),
+ SH_PFC_PIN_GROUP(msiof3_ss1_a),
+ SH_PFC_PIN_GROUP(msiof3_ss2_a),
+ SH_PFC_PIN_GROUP(msiof3_txd_a),
+ SH_PFC_PIN_GROUP(msiof3_rxd_a),
+ SH_PFC_PIN_GROUP(msiof3_clk_b),
+ SH_PFC_PIN_GROUP(msiof3_sync_b),
+ SH_PFC_PIN_GROUP(msiof3_ss1_b),
+ SH_PFC_PIN_GROUP(msiof3_ss2_b),
+ SH_PFC_PIN_GROUP(msiof3_txd_b),
+ SH_PFC_PIN_GROUP(msiof3_rxd_b),
+ SH_PFC_PIN_GROUP(msiof3_clk_c),
+ SH_PFC_PIN_GROUP(msiof3_sync_c),
+ SH_PFC_PIN_GROUP(msiof3_txd_c),
+ SH_PFC_PIN_GROUP(msiof3_rxd_c),
+ SH_PFC_PIN_GROUP(msiof3_clk_d),
+ SH_PFC_PIN_GROUP(msiof3_sync_d),
+ SH_PFC_PIN_GROUP(msiof3_ss1_d),
+ SH_PFC_PIN_GROUP(msiof3_txd_d),
+ SH_PFC_PIN_GROUP(msiof3_rxd_d),
+ SH_PFC_PIN_GROUP(sata0_devslp_a),
+ SH_PFC_PIN_GROUP(sata0_devslp_b),
SH_PFC_PIN_GROUP(scif0_data),
SH_PFC_PIN_GROUP(scif0_clk),
SH_PFC_PIN_GROUP(scif0_ctrl),
@@ -2082,6 +3269,34 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(scif4_ctrl_c),
SH_PFC_PIN_GROUP(scif5_data),
SH_PFC_PIN_GROUP(scif5_clk),
+ SH_PFC_PIN_GROUP(scif_clk_a),
+ SH_PFC_PIN_GROUP(scif_clk_b),
+ SH_PFC_PIN_GROUP(sdhi0_data1),
+ SH_PFC_PIN_GROUP(sdhi0_data4),
+ SH_PFC_PIN_GROUP(sdhi0_ctrl),
+ SH_PFC_PIN_GROUP(sdhi0_cd),
+ SH_PFC_PIN_GROUP(sdhi0_wp),
+ SH_PFC_PIN_GROUP(sdhi1_data1),
+ SH_PFC_PIN_GROUP(sdhi1_data4),
+ SH_PFC_PIN_GROUP(sdhi1_ctrl),
+ SH_PFC_PIN_GROUP(sdhi1_cd),
+ SH_PFC_PIN_GROUP(sdhi1_wp),
+ SH_PFC_PIN_GROUP(sdhi2_data1),
+ SH_PFC_PIN_GROUP(sdhi2_data4),
+ SH_PFC_PIN_GROUP(sdhi2_data8),
+ SH_PFC_PIN_GROUP(sdhi2_ctrl),
+ SH_PFC_PIN_GROUP(sdhi2_cd_a),
+ SH_PFC_PIN_GROUP(sdhi2_wp_a),
+ SH_PFC_PIN_GROUP(sdhi2_cd_b),
+ SH_PFC_PIN_GROUP(sdhi2_wp_b),
+ SH_PFC_PIN_GROUP(sdhi2_ds),
+ SH_PFC_PIN_GROUP(sdhi3_data1),
+ SH_PFC_PIN_GROUP(sdhi3_data4),
+ SH_PFC_PIN_GROUP(sdhi3_data8),
+ SH_PFC_PIN_GROUP(sdhi3_ctrl),
+ SH_PFC_PIN_GROUP(sdhi3_cd),
+ SH_PFC_PIN_GROUP(sdhi3_wp),
+ SH_PFC_PIN_GROUP(sdhi3_ds),
SH_PFC_PIN_GROUP(ssi0_data),
SH_PFC_PIN_GROUP(ssi01239_ctrl),
SH_PFC_PIN_GROUP(ssi1_data_a),
@@ -2141,6 +3356,46 @@ static const char * const avb_groups[] = {
"avb_avtp_capture_b",
};
+static const char * const hscif0_groups[] = {
+ "hscif0_data",
+ "hscif0_clk",
+ "hscif0_ctrl",
+};
+
+static const char * const hscif1_groups[] = {
+ "hscif1_data_a",
+ "hscif1_clk_a",
+ "hscif1_ctrl_a",
+ "hscif1_data_b",
+ "hscif1_clk_b",
+ "hscif1_ctrl_b",
+};
+
+static const char * const hscif2_groups[] = {
+ "hscif2_data_a",
+ "hscif2_clk_a",
+ "hscif2_ctrl_a",
+ "hscif2_data_b",
+ "hscif2_clk_b",
+ "hscif2_ctrl_b",
+};
+
+static const char * const hscif3_groups[] = {
+ "hscif3_data_a",
+ "hscif3_clk",
+ "hscif3_ctrl",
+ "hscif3_data_b",
+ "hscif3_data_c",
+ "hscif3_data_d",
+};
+
+static const char * const hscif4_groups[] = {
+ "hscif4_data_a",
+ "hscif4_clk",
+ "hscif4_ctrl",
+ "hscif4_data_b",
+};
+
static const char * const i2c1_groups[] = {
"i2c1_a",
"i2c1_b",
@@ -2157,6 +3412,116 @@ static const char * const i2c6_groups[] = {
"i2c6_c",
};
+static const char * const msiof0_groups[] = {
+ "msiof0_clk",
+ "msiof0_sync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_txd",
+ "msiof0_rxd",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_clk_a",
+ "msiof1_sync_a",
+ "msiof1_ss1_a",
+ "msiof1_ss2_a",
+ "msiof1_txd_a",
+ "msiof1_rxd_a",
+ "msiof1_clk_b",
+ "msiof1_sync_b",
+ "msiof1_ss1_b",
+ "msiof1_ss2_b",
+ "msiof1_txd_b",
+ "msiof1_rxd_b",
+ "msiof1_clk_c",
+ "msiof1_sync_c",
+ "msiof1_ss1_c",
+ "msiof1_ss2_c",
+ "msiof1_txd_c",
+ "msiof1_rxd_c",
+ "msiof1_clk_d",
+ "msiof1_sync_d",
+ "msiof1_ss1_d",
+ "msiof1_ss2_d",
+ "msiof1_txd_d",
+ "msiof1_rxd_d",
+ "msiof1_clk_e",
+ "msiof1_sync_e",
+ "msiof1_ss1_e",
+ "msiof1_ss2_e",
+ "msiof1_txd_e",
+ "msiof1_rxd_e",
+ "msiof1_clk_f",
+ "msiof1_sync_f",
+ "msiof1_ss1_f",
+ "msiof1_ss2_f",
+ "msiof1_txd_f",
+ "msiof1_rxd_f",
+ "msiof1_clk_g",
+ "msiof1_sync_g",
+ "msiof1_ss1_g",
+ "msiof1_ss2_g",
+ "msiof1_txd_g",
+ "msiof1_rxd_g",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_clk_a",
+ "msiof2_sync_a",
+ "msiof2_ss1_a",
+ "msiof2_ss2_a",
+ "msiof2_txd_a",
+ "msiof2_rxd_a",
+ "msiof2_clk_b",
+ "msiof2_sync_b",
+ "msiof2_ss1_b",
+ "msiof2_ss2_b",
+ "msiof2_txd_b",
+ "msiof2_rxd_b",
+ "msiof2_clk_c",
+ "msiof2_sync_c",
+ "msiof2_ss1_c",
+ "msiof2_ss2_c",
+ "msiof2_txd_c",
+ "msiof2_rxd_c",
+ "msiof2_clk_d",
+ "msiof2_sync_d",
+ "msiof2_ss1_d",
+ "msiof2_ss2_d",
+ "msiof2_txd_d",
+ "msiof2_rxd_d",
+};
+
+static const char * const msiof3_groups[] = {
+ "msiof3_clk_a",
+ "msiof3_sync_a",
+ "msiof3_ss1_a",
+ "msiof3_ss2_a",
+ "msiof3_txd_a",
+ "msiof3_rxd_a",
+ "msiof3_clk_b",
+ "msiof3_sync_b",
+ "msiof3_ss1_b",
+ "msiof3_ss2_b",
+ "msiof3_txd_b",
+ "msiof3_rxd_b",
+ "msiof3_clk_c",
+ "msiof3_sync_c",
+ "msiof3_txd_c",
+ "msiof3_rxd_c",
+ "msiof3_clk_d",
+ "msiof3_sync_d",
+ "msiof3_ss1_d",
+ "msiof3_txd_d",
+ "msiof3_rxd_d",
+};
+
+static const char * const sata0_groups[] = {
+ "sata0_devslp_a",
+ "sata0_devslp_b",
+};
+
static const char * const scif0_groups[] = {
"scif0_data",
"scif0_clk",
@@ -2200,6 +3565,49 @@ static const char * const scif5_groups[] = {
"scif5_clk",
};
+static const char * const scif_clk_groups[] = {
+ "scif_clk_a",
+ "scif_clk_b",
+};
+
+static const char * const sdhi0_groups[] = {
+ "sdhi0_data1",
+ "sdhi0_data4",
+ "sdhi0_ctrl",
+ "sdhi0_cd",
+ "sdhi0_wp",
+};
+
+static const char * const sdhi1_groups[] = {
+ "sdhi1_data1",
+ "sdhi1_data4",
+ "sdhi1_ctrl",
+ "sdhi1_cd",
+ "sdhi1_wp",
+};
+
+static const char * const sdhi2_groups[] = {
+ "sdhi2_data1",
+ "sdhi2_data4",
+ "sdhi2_data8",
+ "sdhi2_ctrl",
+ "sdhi2_cd_a",
+ "sdhi2_wp_a",
+ "sdhi2_cd_b",
+ "sdhi2_wp_b",
+ "sdhi2_ds",
+};
+
+static const char * const sdhi3_groups[] = {
+ "sdhi3_data1",
+ "sdhi3_data4",
+ "sdhi3_data8",
+ "sdhi3_ctrl",
+ "sdhi3_cd",
+ "sdhi3_wp",
+ "sdhi3_ds",
+};
+
static const char * const ssi_groups[] = {
"ssi0_data",
"ssi01239_ctrl",
@@ -2231,15 +3639,30 @@ static const char * const ssi_groups[] = {
static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(audio_clk),
SH_PFC_FUNCTION(avb),
+ SH_PFC_FUNCTION(hscif0),
+ SH_PFC_FUNCTION(hscif1),
+ SH_PFC_FUNCTION(hscif2),
+ SH_PFC_FUNCTION(hscif3),
+ SH_PFC_FUNCTION(hscif4),
SH_PFC_FUNCTION(i2c1),
SH_PFC_FUNCTION(i2c2),
SH_PFC_FUNCTION(i2c6),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
+ SH_PFC_FUNCTION(sata0),
SH_PFC_FUNCTION(scif0),
SH_PFC_FUNCTION(scif1),
SH_PFC_FUNCTION(scif2),
SH_PFC_FUNCTION(scif3),
SH_PFC_FUNCTION(scif4),
SH_PFC_FUNCTION(scif5),
+ SH_PFC_FUNCTION(scif_clk),
+ SH_PFC_FUNCTION(sdhi0),
+ SH_PFC_FUNCTION(sdhi1),
+ SH_PFC_FUNCTION(sdhi2),
+ SH_PFC_FUNCTION(sdhi3),
SH_PFC_FUNCTION(ssi),
};
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
index 6a69c8c..d25e6f6 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c
@@ -2059,7 +2059,7 @@ static const unsigned int lcd2_data9_mux[] = {
LCD2D8_MARK,
};
static const unsigned int lcd2_data12_pins[] = {
- /* D[0:12] */
+ /* D[0:11] */
128, 129, 142, 143, 144, 145, 138, 139,
140, 141, 130, 131,
};
@@ -2198,6 +2198,420 @@ static const unsigned int mmc0_ctrl_1_pins[] = {
static const unsigned int mmc0_ctrl_1_mux[] = {
MMCCMD1_MARK, MMCCLK1_MARK,
};
+/* - MSIOF0 ----------------------------------------------------------------- */
+static const unsigned int msiof0_rsck_pins[] = {
+ /* RSCK */
+ 66,
+};
+static const unsigned int msiof0_rsck_mux[] = {
+ MSIOF0_RSCK_MARK,
+};
+static const unsigned int msiof0_tsck_pins[] = {
+ /* TSCK */
+ 64,
+};
+static const unsigned int msiof0_tsck_mux[] = {
+ MSIOF0_TSCK_MARK,
+};
+static const unsigned int msiof0_rsync_pins[] = {
+ /* RSYNC */
+ 67,
+};
+static const unsigned int msiof0_rsync_mux[] = {
+ MSIOF0_RSYNC_MARK,
+};
+static const unsigned int msiof0_tsync_pins[] = {
+ /* TSYNC */
+ 63,
+};
+static const unsigned int msiof0_tsync_mux[] = {
+ MSIOF0_TSYNC_MARK,
+};
+static const unsigned int msiof0_ss1_pins[] = {
+ /* SS1 */
+ 62,
+};
+static const unsigned int msiof0_ss1_mux[] = {
+ MSIOF0_SS1_MARK,
+};
+static const unsigned int msiof0_ss2_pins[] = {
+ /* SS2 */
+ 71,
+};
+static const unsigned int msiof0_ss2_mux[] = {
+ MSIOF0_SS2_MARK,
+};
+static const unsigned int msiof0_rxd_pins[] = {
+ /* RXD */
+ 70,
+};
+static const unsigned int msiof0_rxd_mux[] = {
+ MSIOF0_RXD_MARK,
+};
+static const unsigned int msiof0_txd_pins[] = {
+ /* TXD */
+ 65,
+};
+static const unsigned int msiof0_txd_mux[] = {
+ MSIOF0_TXD_MARK,
+};
+static const unsigned int msiof0_mck0_pins[] = {
+ /* MSCK0 */
+ 68,
+};
+static const unsigned int msiof0_mck0_mux[] = {
+ MSIOF0_MCK0_MARK,
+};
+
+static const unsigned int msiof0_mck1_pins[] = {
+ /* MSCK1 */
+ 69,
+};
+static const unsigned int msiof0_mck1_mux[] = {
+ MSIOF0_MCK1_MARK,
+};
+
+static const unsigned int msiof0l_rsck_pins[] = {
+ /* RSCK */
+ 214,
+};
+static const unsigned int msiof0l_rsck_mux[] = {
+ MSIOF0L_RSCK_MARK,
+};
+static const unsigned int msiof0l_tsck_pins[] = {
+ /* TSCK */
+ 219,
+};
+static const unsigned int msiof0l_tsck_mux[] = {
+ MSIOF0L_TSCK_MARK,
+};
+static const unsigned int msiof0l_rsync_pins[] = {
+ /* RSYNC */
+ 215,
+};
+static const unsigned int msiof0l_rsync_mux[] = {
+ MSIOF0L_RSYNC_MARK,
+};
+static const unsigned int msiof0l_tsync_pins[] = {
+ /* TSYNC */
+ 217,
+};
+static const unsigned int msiof0l_tsync_mux[] = {
+ MSIOF0L_TSYNC_MARK,
+};
+static const unsigned int msiof0l_ss1_a_pins[] = {
+ /* SS1 */
+ 207,
+};
+static const unsigned int msiof0l_ss1_a_mux[] = {
+ PORT207_MSIOF0L_SS1_MARK,
+};
+static const unsigned int msiof0l_ss1_b_pins[] = {
+ /* SS1 */
+ 210,
+};
+static const unsigned int msiof0l_ss1_b_mux[] = {
+ PORT210_MSIOF0L_SS1_MARK,
+};
+static const unsigned int msiof0l_ss2_a_pins[] = {
+ /* SS2 */
+ 208,
+};
+static const unsigned int msiof0l_ss2_a_mux[] = {
+ PORT208_MSIOF0L_SS2_MARK,
+};
+static const unsigned int msiof0l_ss2_b_pins[] = {
+ /* SS2 */
+ 211,
+};
+static const unsigned int msiof0l_ss2_b_mux[] = {
+ PORT211_MSIOF0L_SS2_MARK,
+};
+static const unsigned int msiof0l_rxd_pins[] = {
+ /* RXD */
+ 221,
+};
+static const unsigned int msiof0l_rxd_mux[] = {
+ MSIOF0L_RXD_MARK,
+};
+static const unsigned int msiof0l_txd_pins[] = {
+ /* TXD */
+ 222,
+};
+static const unsigned int msiof0l_txd_mux[] = {
+ MSIOF0L_TXD_MARK,
+};
+static const unsigned int msiof0l_mck0_pins[] = {
+ /* MSCK0 */
+ 212,
+};
+static const unsigned int msiof0l_mck0_mux[] = {
+ MSIOF0L_MCK0_MARK,
+};
+static const unsigned int msiof0l_mck1_pins[] = {
+ /* MSCK1 */
+ 213,
+};
+static const unsigned int msiof0l_mck1_mux[] = {
+ MSIOF0L_MCK1_MARK,
+};
+/* - MSIOF1 ----------------------------------------------------------------- */
+static const unsigned int msiof1_rsck_pins[] = {
+ /* RSCK */
+ 234,
+};
+static const unsigned int msiof1_rsck_mux[] = {
+ MSIOF1_RSCK_MARK,
+};
+static const unsigned int msiof1_tsck_pins[] = {
+ /* TSCK */
+ 232,
+};
+static const unsigned int msiof1_tsck_mux[] = {
+ MSIOF1_TSCK_MARK,
+};
+static const unsigned int msiof1_rsync_pins[] = {
+ /* RSYNC */
+ 235,
+};
+static const unsigned int msiof1_rsync_mux[] = {
+ MSIOF1_RSYNC_MARK,
+};
+static const unsigned int msiof1_tsync_pins[] = {
+ /* TSYNC */
+ 231,
+};
+static const unsigned int msiof1_tsync_mux[] = {
+ MSIOF1_TSYNC_MARK,
+};
+static const unsigned int msiof1_ss1_pins[] = {
+ /* SS1 */
+ 238,
+};
+static const unsigned int msiof1_ss1_mux[] = {
+ MSIOF1_SS1_MARK,
+};
+static const unsigned int msiof1_ss2_pins[] = {
+ /* SS2 */
+ 239,
+};
+static const unsigned int msiof1_ss2_mux[] = {
+ MSIOF1_SS2_MARK,
+};
+static const unsigned int msiof1_rxd_pins[] = {
+ /* RXD */
+ 233,
+};
+static const unsigned int msiof1_rxd_mux[] = {
+ MSIOF1_RXD_MARK,
+};
+static const unsigned int msiof1_txd_pins[] = {
+ /* TXD */
+ 230,
+};
+static const unsigned int msiof1_txd_mux[] = {
+ MSIOF1_TXD_MARK,
+};
+static const unsigned int msiof1_mck0_pins[] = {
+ /* MSCK0 */
+ 236,
+};
+static const unsigned int msiof1_mck0_mux[] = {
+ MSIOF1_MCK0_MARK,
+};
+static const unsigned int msiof1_mck1_pins[] = {
+ /* MSCK1 */
+ 237,
+};
+static const unsigned int msiof1_mck1_mux[] = {
+ MSIOF1_MCK1_MARK,
+};
+/* - MSIOF2 ----------------------------------------------------------------- */
+static const unsigned int msiof2_rsck_pins[] = {
+ /* RSCK */
+ 151,
+};
+static const unsigned int msiof2_rsck_mux[] = {
+ MSIOF2_RSCK_MARK,
+};
+static const unsigned int msiof2_tsck_pins[] = {
+ /* TSCK */
+ 135,
+};
+static const unsigned int msiof2_tsck_mux[] = {
+ MSIOF2_TSCK_MARK,
+};
+static const unsigned int msiof2_rsync_pins[] = {
+ /* RSYNC */
+ 152,
+};
+static const unsigned int msiof2_rsync_mux[] = {
+ MSIOF2_RSYNC_MARK,
+};
+static const unsigned int msiof2_tsync_pins[] = {
+ /* TSYNC */
+ 133,
+};
+static const unsigned int msiof2_tsync_mux[] = {
+ MSIOF2_TSYNC_MARK,
+};
+static const unsigned int msiof2_ss1_a_pins[] = {
+ /* SS1 */
+ 131,
+};
+static const unsigned int msiof2_ss1_a_mux[] = {
+ PORT131_MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss1_b_pins[] = {
+ /* SS1 */
+ 153,
+};
+static const unsigned int msiof2_ss1_b_mux[] = {
+ PORT153_MSIOF2_SS1_MARK,
+};
+static const unsigned int msiof2_ss2_a_pins[] = {
+ /* SS2 */
+ 132,
+};
+static const unsigned int msiof2_ss2_a_mux[] = {
+ PORT132_MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_ss2_b_pins[] = {
+ /* SS2 */
+ 156,
+};
+static const unsigned int msiof2_ss2_b_mux[] = {
+ PORT156_MSIOF2_SS2_MARK,
+};
+static const unsigned int msiof2_rxd_a_pins[] = {
+ /* RXD */
+ 130,
+};
+static const unsigned int msiof2_rxd_a_mux[] = {
+ PORT130_MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_rxd_b_pins[] = {
+ /* RXD */
+ 157,
+};
+static const unsigned int msiof2_rxd_b_mux[] = {
+ PORT157_MSIOF2_RXD_MARK,
+};
+static const unsigned int msiof2_txd_pins[] = {
+ /* TXD */
+ 134,
+};
+static const unsigned int msiof2_txd_mux[] = {
+ MSIOF2_TXD_MARK,
+};
+static const unsigned int msiof2_mck0_pins[] = {
+ /* MSCK0 */
+ 154,
+};
+static const unsigned int msiof2_mck0_mux[] = {
+ MSIOF2_MCK0_MARK,
+};
+static const unsigned int msiof2_mck1_pins[] = {
+ /* MSCK1 */
+ 155,
+};
+static const unsigned int msiof2_mck1_mux[] = {
+ MSIOF2_MCK1_MARK,
+};
+
+static const unsigned int msiof2r_tsck_pins[] = {
+ /* TSCK */
+ 248,
+};
+static const unsigned int msiof2r_tsck_mux[] = {
+ MSIOF2R_TSCK_MARK,
+};
+static const unsigned int msiof2r_tsync_pins[] = {
+ /* TSYNC */
+ 249,
+};
+static const unsigned int msiof2r_tsync_mux[] = {
+ MSIOF2R_TSYNC_MARK,
+};
+static const unsigned int msiof2r_rxd_pins[] = {
+ /* RXD */
+ 244,
+};
+static const unsigned int msiof2r_rxd_mux[] = {
+ MSIOF2R_RXD_MARK,
+};
+static const unsigned int msiof2r_txd_pins[] = {
+ /* TXD */
+ 245,
+};
+static const unsigned int msiof2r_txd_mux[] = {
+ MSIOF2R_TXD_MARK,
+};
+/* - MSIOF3 (Pin function name of MSIOF3 is named BBIF1) -------------------- */
+static const unsigned int msiof3_rsck_pins[] = {
+ /* RSCK */
+ 115,
+};
+static const unsigned int msiof3_rsck_mux[] = {
+ BBIF1_RSCK_MARK,
+};
+static const unsigned int msiof3_tsck_pins[] = {
+ /* TSCK */
+ 112,
+};
+static const unsigned int msiof3_tsck_mux[] = {
+ BBIF1_TSCK_MARK,
+};
+static const unsigned int msiof3_rsync_pins[] = {
+ /* RSYNC */
+ 116,
+};
+static const unsigned int msiof3_rsync_mux[] = {
+ BBIF1_RSYNC_MARK,
+};
+static const unsigned int msiof3_tsync_pins[] = {
+ /* TSYNC */
+ 113,
+};
+static const unsigned int msiof3_tsync_mux[] = {
+ BBIF1_TSYNC_MARK,
+};
+static const unsigned int msiof3_ss1_pins[] = {
+ /* SS1 */
+ 117,
+};
+static const unsigned int msiof3_ss1_mux[] = {
+ BBIF1_SS1_MARK,
+};
+static const unsigned int msiof3_ss2_pins[] = {
+ /* SS2 */
+ 109,
+};
+static const unsigned int msiof3_ss2_mux[] = {
+ BBIF1_SS2_MARK,
+};
+static const unsigned int msiof3_rxd_pins[] = {
+ /* RXD */
+ 111,
+};
+static const unsigned int msiof3_rxd_mux[] = {
+ BBIF1_RXD_MARK,
+};
+static const unsigned int msiof3_txd_pins[] = {
+ /* TXD */
+ 114,
+};
+static const unsigned int msiof3_txd_mux[] = {
+ BBIF1_TXD_MARK,
+};
+static const unsigned int msiof3_flow_pins[] = {
+ /* FLOW */
+ 117,
+};
+static const unsigned int msiof3_flow_mux[] = {
+ BBIF1_FLOW_MARK,
+};
+
/* - SCIFA0 ----------------------------------------------------------------- */
static const unsigned int scifa0_data_pins[] = {
/* RXD, TXD */
@@ -2782,6 +3196,64 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(mmc0_data4_1),
SH_PFC_PIN_GROUP(mmc0_data8_1),
SH_PFC_PIN_GROUP(mmc0_ctrl_1),
+ SH_PFC_PIN_GROUP(msiof0_rsck),
+ SH_PFC_PIN_GROUP(msiof0_tsck),
+ SH_PFC_PIN_GROUP(msiof0_rsync),
+ SH_PFC_PIN_GROUP(msiof0_tsync),
+ SH_PFC_PIN_GROUP(msiof0_ss1),
+ SH_PFC_PIN_GROUP(msiof0_ss2),
+ SH_PFC_PIN_GROUP(msiof0_rxd),
+ SH_PFC_PIN_GROUP(msiof0_txd),
+ SH_PFC_PIN_GROUP(msiof0_mck0),
+ SH_PFC_PIN_GROUP(msiof0_mck1),
+ SH_PFC_PIN_GROUP(msiof0l_rsck),
+ SH_PFC_PIN_GROUP(msiof0l_tsck),
+ SH_PFC_PIN_GROUP(msiof0l_rsync),
+ SH_PFC_PIN_GROUP(msiof0l_tsync),
+ SH_PFC_PIN_GROUP(msiof0l_ss1_a),
+ SH_PFC_PIN_GROUP(msiof0l_ss1_b),
+ SH_PFC_PIN_GROUP(msiof0l_ss2_a),
+ SH_PFC_PIN_GROUP(msiof0l_ss2_b),
+ SH_PFC_PIN_GROUP(msiof0l_rxd),
+ SH_PFC_PIN_GROUP(msiof0l_txd),
+ SH_PFC_PIN_GROUP(msiof0l_mck0),
+ SH_PFC_PIN_GROUP(msiof0l_mck1),
+ SH_PFC_PIN_GROUP(msiof1_rsck),
+ SH_PFC_PIN_GROUP(msiof1_tsck),
+ SH_PFC_PIN_GROUP(msiof1_rsync),
+ SH_PFC_PIN_GROUP(msiof1_tsync),
+ SH_PFC_PIN_GROUP(msiof1_ss1),
+ SH_PFC_PIN_GROUP(msiof1_ss2),
+ SH_PFC_PIN_GROUP(msiof1_rxd),
+ SH_PFC_PIN_GROUP(msiof1_txd),
+ SH_PFC_PIN_GROUP(msiof1_mck0),
+ SH_PFC_PIN_GROUP(msiof1_mck1),
+ SH_PFC_PIN_GROUP(msiof2_rsck),
+ SH_PFC_PIN_GROUP(msiof2_tsck),
+ SH_PFC_PIN_GROUP(msiof2_rsync),
+ SH_PFC_PIN_GROUP(msiof2_tsync),
+ SH_PFC_PIN_GROUP(msiof2_ss1_a),
+ SH_PFC_PIN_GROUP(msiof2_ss1_b),
+ SH_PFC_PIN_GROUP(msiof2_ss2_a),
+ SH_PFC_PIN_GROUP(msiof2_ss2_b),
+ SH_PFC_PIN_GROUP(msiof2_rxd_a),
+ SH_PFC_PIN_GROUP(msiof2_rxd_b),
+ SH_PFC_PIN_GROUP(msiof2_txd),
+ SH_PFC_PIN_GROUP(msiof2_mck0),
+ SH_PFC_PIN_GROUP(msiof2_mck1),
+ SH_PFC_PIN_GROUP(msiof2r_tsck),
+ SH_PFC_PIN_GROUP(msiof2r_tsync),
+ SH_PFC_PIN_GROUP(msiof2r_rxd),
+ SH_PFC_PIN_GROUP(msiof2r_txd),
+ SH_PFC_PIN_GROUP(msiof3_rsck),
+ SH_PFC_PIN_GROUP(msiof3_tsck),
+ SH_PFC_PIN_GROUP(msiof3_rsync),
+ SH_PFC_PIN_GROUP(msiof3_tsync),
+ SH_PFC_PIN_GROUP(msiof3_ss1),
+ SH_PFC_PIN_GROUP(msiof3_ss2),
+ SH_PFC_PIN_GROUP(msiof3_rxd),
+ SH_PFC_PIN_GROUP(msiof3_txd),
+ SH_PFC_PIN_GROUP(msiof3_flow),
SH_PFC_PIN_GROUP(scifa0_data),
SH_PFC_PIN_GROUP(scifa0_clk),
SH_PFC_PIN_GROUP(scifa0_ctrl),
@@ -2982,6 +3454,76 @@ static const char * const mmc0_groups[] = {
"mmc0_ctrl_1",
};
+static const char * const msiof0_groups[] = {
+ "msiof0_rsck",
+ "msiof0_tsck",
+ "msiof0_rsync",
+ "msiof0_tsync",
+ "msiof0_ss1",
+ "msiof0_ss2",
+ "msiof0_rxd",
+ "msiof0_txd",
+ "msiof0_mck0",
+ "msiof0_mck1",
+ "msiof0l_rsck",
+ "msiof0l_tsck",
+ "msiof0l_rsync",
+ "msiof0l_tsync",
+ "msiof0l_ss1_a",
+ "msiof0l_ss1_b",
+ "msiof0l_ss2_a",
+ "msiof0l_ss2_b",
+ "msiof0l_rxd",
+ "msiof0l_txd",
+ "msiof0l_mck0",
+ "msiof0l_mck1",
+};
+
+static const char * const msiof1_groups[] = {
+ "msiof1_rsck",
+ "msiof1_tsck",
+ "msiof1_rsync",
+ "msiof1_tsync",
+ "msiof1_ss1",
+ "msiof1_ss2",
+ "msiof1_rxd",
+ "msiof1_txd",
+ "msiof1_mck0",
+ "msiof1_mck1",
+};
+
+static const char * const msiof2_groups[] = {
+ "msiof2_rsck",
+ "msiof2_tsck",
+ "msiof2_rsync",
+ "msiof2_tsync",
+ "msiof2_ss1_a",
+ "msiof2_ss1_b",
+ "msiof2_ss2_a",
+ "msiof2_ss2_b",
+ "msiof2_rxd_a",
+ "msiof2_rxd_b",
+ "msiof2_txd",
+ "msiof2_mck0",
+ "msiof2_mck1",
+ "msiof2r_tsck",
+ "msiof2r_tsync",
+ "msiof2r_rxd",
+ "msiof2r_txd",
+};
+
+static const char * const msiof3_groups[] = {
+ "msiof3_rsck",
+ "msiof3_tsck",
+ "msiof3_rsync",
+ "msiof3_tsync",
+ "msiof3_ss1",
+ "msiof3_ss2",
+ "msiof3_rxd",
+ "msiof3_txd",
+ "msiof3_flow",
+};
+
static const char * const scifa0_groups[] = {
"scifa0_data",
"scifa0_clk",
@@ -3116,6 +3658,10 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(lcd),
SH_PFC_FUNCTION(lcd2),
SH_PFC_FUNCTION(mmc0),
+ SH_PFC_FUNCTION(msiof0),
+ SH_PFC_FUNCTION(msiof1),
+ SH_PFC_FUNCTION(msiof2),
+ SH_PFC_FUNCTION(msiof3),
SH_PFC_FUNCTION(scifa0),
SH_PFC_FUNCTION(scifa1),
SH_PFC_FUNCTION(scifa2),
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7734.c b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
index e7deb51..b0b328b 100644
--- a/drivers/pinctrl/sh-pfc/pfc-sh7734.c
+++ b/drivers/pinctrl/sh-pfc/pfc-sh7734.c
@@ -14,14 +14,6 @@
#include "sh_pfc.h"
-#define PORT_GP_12(bank, fn, sfx) \
- PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \
- PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \
- PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \
- PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \
- PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \
- PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx)
-
#define CPU_ALL_PORT(fn, sfx) \
PORT_GP_32(0, fn, sfx), \
PORT_GP_32(1, fn, sfx), \
@@ -31,11 +23,11 @@
PORT_GP_12(5, fn, sfx)
#undef _GP_DATA
-#define _GP_DATA(bank, pin, name, sfx) \
+#define _GP_DATA(bank, pin, name, sfx, cfg) \
PINMUX_DATA(name##_DATA, name##_FN, name##_IN, name##_OUT)
-#define _GP_INOUTSEL(bank, pin, name, sfx) name##_IN, name##_OUT
-#define _GP_INDT(bank, pin, name, sfx) name##_DATA
+#define _GP_INOUTSEL(bank, pin, name, sfx, cfg) name##_IN, name##_OUT
+#define _GP_INDT(bank, pin, name, sfx, cfg) name##_DATA
#define GP_INOUTSEL(bank) PORT_GP_32_REV(bank, _GP_INOUTSEL, unused)
#define GP_INDT(bank) PORT_GP_32_REV(bank, _GP_INDT, unused)
@@ -585,15 +577,18 @@ enum {
static const u16 pinmux_data[] = {
PINMUX_DATA_GP_ALL(), /* PINMUX_DATA(GP_M_N_DATA, GP_M_N_FN...), */
- PINMUX_DATA(CLKOUT_MARK, FN_CLKOUT),
- PINMUX_DATA(BS_MARK, FN_BS), PINMUX_DATA(CS0_MARK, FN_CS0),
- PINMUX_DATA(EX_CS0_MARK, FN_EX_CS0),
- PINMUX_DATA(RD_MARK, FN_RD), PINMUX_DATA(WE0_MARK, FN_WE0),
- PINMUX_DATA(WE1_MARK, FN_WE1),
- PINMUX_DATA(SCL0_MARK, FN_SCL0), PINMUX_DATA(PENC0_MARK, FN_PENC0),
- PINMUX_DATA(USB_OVC0_MARK, FN_USB_OVC0),
- PINMUX_DATA(IRQ2_B_MARK, FN_IRQ2_B),
- PINMUX_DATA(IRQ3_B_MARK, FN_IRQ3_B),
+ PINMUX_SINGLE(CLKOUT),
+ PINMUX_SINGLE(BS),
+ PINMUX_SINGLE(CS0),
+ PINMUX_SINGLE(EX_CS0),
+ PINMUX_SINGLE(RD),
+ PINMUX_SINGLE(WE0),
+ PINMUX_SINGLE(WE1),
+ PINMUX_SINGLE(SCL0),
+ PINMUX_SINGLE(PENC0),
+ PINMUX_SINGLE(USB_OVC0),
+ PINMUX_SINGLE(IRQ2_B),
+ PINMUX_SINGLE(IRQ3_B),
/* IPSR0 */
PINMUX_IPSR_DATA(IP0_1_0, A0),
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 863c3e3..87b0a59 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -273,8 +273,10 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
for_each_child_of_node(np, child) {
ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps,
&index);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(child);
goto done;
+ }
}
/* If no mapping has been found in child nodes try the config node. */
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 7b373d43..2123ab4 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -199,28 +199,82 @@ struct sh_pfc_soc_info {
PINMUX_DATA(fn##_MARK, FN_##ms, FN_##ipsr, FN_##fn)
/*
+ * Describe a pinmux configuration for a single-function pin with GPIO
+ * capability.
+ * - fn: Function name
+ */
+#define PINMUX_SINGLE(fn) \
+ PINMUX_DATA(fn##_MARK, FN_##fn)
+
+/*
* GP port style (32 ports banks)
*/
#define PORT_GP_CFG_1(bank, pin, fn, sfx, cfg) fn(bank, pin, GP_##bank##_##pin, sfx, cfg)
#define PORT_GP_1(bank, pin, fn, sfx) PORT_GP_CFG_1(bank, pin, fn, sfx, 0)
-#define PORT_GP_CFG_32(bank, fn, sfx, cfg) \
+#define PORT_GP_CFG_4(bank, fn, sfx, cfg) \
PORT_GP_CFG_1(bank, 0, fn, sfx, cfg), PORT_GP_CFG_1(bank, 1, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 2, fn, sfx, cfg), PORT_GP_CFG_1(bank, 3, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 2, fn, sfx, cfg), PORT_GP_CFG_1(bank, 3, fn, sfx, cfg)
+#define PORT_GP_4(bank, fn, sfx) PORT_GP_CFG_4(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_8(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_4(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 4, fn, sfx, cfg), PORT_GP_CFG_1(bank, 5, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 6, fn, sfx, cfg), PORT_GP_CFG_1(bank, 7, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 6, fn, sfx, cfg), PORT_GP_CFG_1(bank, 7, fn, sfx, cfg)
+#define PORT_GP_8(bank, fn, sfx) PORT_GP_CFG_8(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_9(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_8(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 8, fn, sfx, cfg)
+#define PORT_GP_9(bank, fn, sfx) PORT_GP_CFG_9(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_12(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_8(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 8, fn, sfx, cfg), PORT_GP_CFG_1(bank, 9, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 10, fn, sfx, cfg), PORT_GP_CFG_1(bank, 11, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), PORT_GP_CFG_1(bank, 13, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 14, fn, sfx, cfg), PORT_GP_CFG_1(bank, 15, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 16, fn, sfx, cfg), PORT_GP_CFG_1(bank, 17, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 10, fn, sfx, cfg), PORT_GP_CFG_1(bank, 11, fn, sfx, cfg)
+#define PORT_GP_12(bank, fn, sfx) PORT_GP_CFG_12(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_14(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_12(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 12, fn, sfx, cfg), PORT_GP_CFG_1(bank, 13, fn, sfx, cfg)
+#define PORT_GP_14(bank, fn, sfx) PORT_GP_CFG_14(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_15(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_14(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 14, fn, sfx, cfg)
+#define PORT_GP_15(bank, fn, sfx) PORT_GP_CFG_15(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_16(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_14(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 14, fn, sfx, cfg), PORT_GP_CFG_1(bank, 15, fn, sfx, cfg)
+#define PORT_GP_16(bank, fn, sfx) PORT_GP_CFG_16(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_18(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_16(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 16, fn, sfx, cfg), PORT_GP_CFG_1(bank, 17, fn, sfx, cfg)
+#define PORT_GP_18(bank, fn, sfx) PORT_GP_CFG_18(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_26(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_18(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 18, fn, sfx, cfg), PORT_GP_CFG_1(bank, 19, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 20, fn, sfx, cfg), PORT_GP_CFG_1(bank, 21, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 22, fn, sfx, cfg), PORT_GP_CFG_1(bank, 23, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 24, fn, sfx, cfg), PORT_GP_CFG_1(bank, 25, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), PORT_GP_CFG_1(bank, 27, fn, sfx, cfg), \
- PORT_GP_CFG_1(bank, 28, fn, sfx, cfg), PORT_GP_CFG_1(bank, 29, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 24, fn, sfx, cfg), PORT_GP_CFG_1(bank, 25, fn, sfx, cfg)
+#define PORT_GP_26(bank, fn, sfx) PORT_GP_CFG_26(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_28(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_26(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 26, fn, sfx, cfg), PORT_GP_CFG_1(bank, 27, fn, sfx, cfg)
+#define PORT_GP_28(bank, fn, sfx) PORT_GP_CFG_28(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_30(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_28(bank, fn, sfx, cfg), \
+ PORT_GP_CFG_1(bank, 28, fn, sfx, cfg), PORT_GP_CFG_1(bank, 29, fn, sfx, cfg)
+#define PORT_GP_30(bank, fn, sfx) PORT_GP_CFG_30(bank, fn, sfx, 0)
+
+#define PORT_GP_CFG_32(bank, fn, sfx, cfg) \
+ PORT_GP_CFG_30(bank, fn, sfx, cfg), \
PORT_GP_CFG_1(bank, 30, fn, sfx, cfg), PORT_GP_CFG_1(bank, 31, fn, sfx, cfg)
#define PORT_GP_32(bank, fn, sfx) PORT_GP_CFG_32(bank, fn, sfx, 0)
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 829018c..053d98e 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -161,6 +161,9 @@ enum altas7_pad_type {
#define IN_DISABLE_VAL_1_REG_SET 0x0A88
#define IN_DISABLE_VAL_1_REG_CLR 0x0A8C
+/* Offset of the SDIO9SEL*/
+#define SYS2PCI_SDIO9SEL 0x14
+
struct dt_params {
const char *property;
int value;
@@ -370,6 +373,7 @@ struct atlas7_pmx {
struct pinctrl_desc pctl_desc;
struct atlas7_pinctrl_data *pctl_data;
void __iomem *regs[ATLAS7_PINCTRL_REG_BANKS];
+ void __iomem *sys2pci_base;
u32 status_ds[NUM_OF_IN_DISABLE_REG];
u32 status_dsv[NUM_OF_IN_DISABLE_REG];
struct atlas7_pad_status sleep_data[ATLAS7_PINCTRL_TOTAL_PINS];
@@ -885,11 +889,12 @@ static const unsigned int lr_lcdrom_pins[] = { 73, 54, 57, 58, 59, 60, 61,
62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 56, 53, 55, };
static const unsigned int lvds_analog_pins[] = { 149, 150, 151, 152, 153, 154,
155, 156, 157, 158, };
-static const unsigned int nd_df_pins[] = { 44, 43, 42, 41, 40, 39, 38, 37,
- 47, 46, 52, 51, 45, 49, 50, 48, 124, };
-static const unsigned int nd_df_nowp_pins[] = { 44, 43, 42, 41, 40, 39, 38,
- 37, 47, 46, 52, 51, 45, 49, 50, 48, };
+static const unsigned int nd_df_basic_pins[] = { 44, 43, 42, 41, 40, 39, 38,
+ 37, 47, 46, 52, 45, 49, 50, 48, };
+static const unsigned int nd_df_wp_pins[] = { 124, };
+static const unsigned int nd_df_cs_pins[] = { 51, };
static const unsigned int ps_pins[] = { 120, 119, 121, };
+static const unsigned int ps_no_dir_pins[] = { 119, };
static const unsigned int pwc_core_on_pins[] = { 8, };
static const unsigned int pwc_ext_on_pins[] = { 6, };
static const unsigned int pwc_gpio3_clk_pins[] = { 3, };
@@ -944,7 +949,7 @@ static const unsigned int sd2_cdb_pins0[] = { 124, };
static const unsigned int sd2_cdb_pins1[] = { 161, };
static const unsigned int sd2_wpb_pins0[] = { 123, };
static const unsigned int sd2_wpb_pins1[] = { 163, };
-static const unsigned int sd3_pins[] = { 85, 86, 87, 88, 89, 90, };
+static const unsigned int sd3_9_pins[] = { 85, 86, 87, 88, 89, 90, };
static const unsigned int sd5_pins[] = { 91, 92, 93, 94, 95, 96, };
static const unsigned int sd6_pins0[] = { 79, 78, 74, 75, 76, 77, };
static const unsigned int sd6_pins1[] = { 101, 99, 100, 110, 109, 111, };
@@ -998,9 +1003,9 @@ static const unsigned int vi_vip1_ext_pins[] = { 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 108, 103, 104, 105, 106, 107, 102, 97, 98,
99, 100, };
static const unsigned int vi_vip1_low8bit_pins[] = { 74, 75, 76, 77, 78, 79,
- 80, 81, };
-static const unsigned int vi_vip1_high8bit_pins[] = { 82, 83, 84, 108, 103,
- 104, 105, 106, };
+ 80, 81, 82, 83, 84, };
+static const unsigned int vi_vip1_high8bit_pins[] = { 82, 83, 84, 103, 104,
+ 105, 106, 107, 102, 97, 98, };
/* definition of pin group table */
struct atlas7_pin_group altas7_pin_groups[] = {
@@ -1142,9 +1147,11 @@ struct atlas7_pin_group altas7_pin_groups[] = {
GROUP("ld_ldd_lck_grp", ld_ldd_lck_pins),
GROUP("lr_lcdrom_grp", lr_lcdrom_pins),
GROUP("lvds_analog_grp", lvds_analog_pins),
- GROUP("nd_df_grp", nd_df_pins),
- GROUP("nd_df_nowp_grp", nd_df_nowp_pins),
+ GROUP("nd_df_basic_grp", nd_df_basic_pins),
+ GROUP("nd_df_wp_grp", nd_df_wp_pins),
+ GROUP("nd_df_cs_grp", nd_df_cs_pins),
GROUP("ps_grp", ps_pins),
+ GROUP("ps_no_dir_grp", ps_no_dir_pins),
GROUP("pwc_core_on_grp", pwc_core_on_pins),
GROUP("pwc_ext_on_grp", pwc_ext_on_pins),
GROUP("pwc_gpio3_clk_grp", pwc_gpio3_clk_pins),
@@ -1196,7 +1203,7 @@ struct atlas7_pin_group altas7_pin_groups[] = {
GROUP("sd2_cdb_grp1", sd2_cdb_pins1),
GROUP("sd2_wpb_grp0", sd2_wpb_pins0),
GROUP("sd2_wpb_grp1", sd2_wpb_pins1),
- GROUP("sd3_grp", sd3_pins),
+ GROUP("sd3_9_grp", sd3_9_pins),
GROUP("sd5_grp", sd5_pins),
GROUP("sd6_grp0", sd6_pins0),
GROUP("sd6_grp1", sd6_pins1),
@@ -1421,9 +1428,11 @@ static const char * const ld_ldd_fck_grp[] = { "ld_ldd_fck_grp", };
static const char * const ld_ldd_lck_grp[] = { "ld_ldd_lck_grp", };
static const char * const lr_lcdrom_grp[] = { "lr_lcdrom_grp", };
static const char * const lvds_analog_grp[] = { "lvds_analog_grp", };
-static const char * const nd_df_grp[] = { "nd_df_grp", };
-static const char * const nd_df_nowp_grp[] = { "nd_df_nowp_grp", };
+static const char * const nd_df_basic_grp[] = { "nd_df_basic_grp", };
+static const char * const nd_df_wp_grp[] = { "nd_df_wp_grp", };
+static const char * const nd_df_cs_grp[] = { "nd_df_cs_grp", };
static const char * const ps_grp[] = { "ps_grp", };
+static const char * const ps_no_dir_grp[] = { "ps_no_dir_grp", };
static const char * const pwc_core_on_grp[] = { "pwc_core_on_grp", };
static const char * const pwc_ext_on_grp[] = { "pwc_ext_on_grp", };
static const char * const pwc_gpio3_clk_grp[] = { "pwc_gpio3_clk_grp", };
@@ -1478,7 +1487,7 @@ static const char * const sd2_cdb_grp0[] = { "sd2_cdb_grp0", };
static const char * const sd2_cdb_grp1[] = { "sd2_cdb_grp1", };
static const char * const sd2_wpb_grp0[] = { "sd2_wpb_grp0", };
static const char * const sd2_wpb_grp1[] = { "sd2_wpb_grp1", };
-static const char * const sd3_grp[] = { "sd3_grp", };
+static const char * const sd3_9_grp[] = { "sd3_9_grp", };
static const char * const sd5_grp[] = { "sd5_grp", };
static const char * const sd6_grp0[] = { "sd6_grp0", };
static const char * const sd6_grp1[] = { "sd6_grp1", };
@@ -3174,7 +3183,7 @@ static struct atlas7_grp_mux lvds_analog_grp_mux = {
.pad_mux_list = lvds_analog_grp_pad_mux,
};
-static struct atlas7_pad_mux nd_df_grp_pad_mux[] = {
+static struct atlas7_pad_mux nd_df_basic_grp_pad_mux[] = {
MUX(1, 44, 1, N, N, N, N),
MUX(1, 43, 1, N, N, N, N),
MUX(1, 42, 1, N, N, N, N),
@@ -3186,41 +3195,33 @@ static struct atlas7_pad_mux nd_df_grp_pad_mux[] = {
MUX(1, 47, 1, N, N, N, N),
MUX(1, 46, 1, N, N, N, N),
MUX(1, 52, 1, N, N, N, N),
- MUX(1, 51, 1, N, N, N, N),
MUX(1, 45, 1, N, N, N, N),
MUX(1, 49, 1, N, N, N, N),
MUX(1, 50, 1, N, N, N, N),
MUX(1, 48, 1, N, N, N, N),
+};
+
+static struct atlas7_grp_mux nd_df_basic_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(nd_df_basic_grp_pad_mux),
+ .pad_mux_list = nd_df_basic_grp_pad_mux,
+};
+
+static struct atlas7_pad_mux nd_df_wp_grp_pad_mux[] = {
MUX(1, 124, 4, N, N, N, N),
};
-static struct atlas7_grp_mux nd_df_grp_mux = {
- .pad_mux_count = ARRAY_SIZE(nd_df_grp_pad_mux),
- .pad_mux_list = nd_df_grp_pad_mux,
+static struct atlas7_grp_mux nd_df_wp_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(nd_df_wp_grp_pad_mux),
+ .pad_mux_list = nd_df_wp_grp_pad_mux,
};
-static struct atlas7_pad_mux nd_df_nowp_grp_pad_mux[] = {
- MUX(1, 44, 1, N, N, N, N),
- MUX(1, 43, 1, N, N, N, N),
- MUX(1, 42, 1, N, N, N, N),
- MUX(1, 41, 1, N, N, N, N),
- MUX(1, 40, 1, N, N, N, N),
- MUX(1, 39, 1, N, N, N, N),
- MUX(1, 38, 1, N, N, N, N),
- MUX(1, 37, 1, N, N, N, N),
- MUX(1, 47, 1, N, N, N, N),
- MUX(1, 46, 1, N, N, N, N),
- MUX(1, 52, 1, N, N, N, N),
+static struct atlas7_pad_mux nd_df_cs_grp_pad_mux[] = {
MUX(1, 51, 1, N, N, N, N),
- MUX(1, 45, 1, N, N, N, N),
- MUX(1, 49, 1, N, N, N, N),
- MUX(1, 50, 1, N, N, N, N),
- MUX(1, 48, 1, N, N, N, N),
};
-static struct atlas7_grp_mux nd_df_nowp_grp_mux = {
- .pad_mux_count = ARRAY_SIZE(nd_df_nowp_grp_pad_mux),
- .pad_mux_list = nd_df_nowp_grp_pad_mux,
+static struct atlas7_grp_mux nd_df_cs_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(nd_df_cs_grp_pad_mux),
+ .pad_mux_list = nd_df_cs_grp_pad_mux,
};
static struct atlas7_pad_mux ps_grp_pad_mux[] = {
@@ -3234,6 +3235,15 @@ static struct atlas7_grp_mux ps_grp_mux = {
.pad_mux_list = ps_grp_pad_mux,
};
+static struct atlas7_pad_mux ps_no_dir_grp_pad_mux[] = {
+ MUX(1, 119, 2, N, N, N, N),
+};
+
+static struct atlas7_grp_mux ps_no_dir_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(ps_no_dir_grp_pad_mux),
+ .pad_mux_list = ps_no_dir_grp_pad_mux,
+};
+
static struct atlas7_pad_mux pwc_core_on_grp_pad_mux[] = {
MUX(0, 8, 1, N, N, N, N),
};
@@ -3743,7 +3753,7 @@ static struct atlas7_grp_mux sd2_wpb_grp1_mux = {
.pad_mux_list = sd2_wpb_grp1_pad_mux,
};
-static struct atlas7_pad_mux sd3_grp_pad_mux[] = {
+static struct atlas7_pad_mux sd3_9_grp_pad_mux[] = {
MUX(1, 85, 1, N, N, N, N),
MUX(1, 86, 1, N, N, N, N),
MUX(1, 87, 1, N, N, N, N),
@@ -3752,9 +3762,9 @@ static struct atlas7_pad_mux sd3_grp_pad_mux[] = {
MUX(1, 90, 1, N, N, N, N),
};
-static struct atlas7_grp_mux sd3_grp_mux = {
- .pad_mux_count = ARRAY_SIZE(sd3_grp_pad_mux),
- .pad_mux_list = sd3_grp_pad_mux,
+static struct atlas7_grp_mux sd3_9_grp_mux = {
+ .pad_mux_count = ARRAY_SIZE(sd3_9_grp_pad_mux),
+ .pad_mux_list = sd3_9_grp_pad_mux,
};
static struct atlas7_pad_mux sd5_grp_pad_mux[] = {
@@ -4296,6 +4306,9 @@ static struct atlas7_pad_mux vi_vip1_low8bit_grp_pad_mux[] = {
MUX(1, 79, 1, N, N, N, N),
MUX(1, 80, 1, N, N, N, N),
MUX(1, 81, 1, N, N, N, N),
+ MUX(1, 82, 1, N, N, N, N),
+ MUX(1, 83, 1, N, N, N, N),
+ MUX(1, 84, 1, N, N, N, N),
};
static struct atlas7_grp_mux vi_vip1_low8bit_grp_mux = {
@@ -4307,11 +4320,14 @@ static struct atlas7_pad_mux vi_vip1_high8bit_grp_pad_mux[] = {
MUX(1, 82, 1, N, N, N, N),
MUX(1, 83, 1, N, N, N, N),
MUX(1, 84, 1, N, N, N, N),
- MUX(1, 108, 2, N, N, N, N),
MUX(1, 103, 2, N, N, N, N),
MUX(1, 104, 2, N, N, N, N),
MUX(1, 105, 2, N, N, N, N),
MUX(1, 106, 2, N, N, N, N),
+ MUX(1, 107, 2, N, N, N, N),
+ MUX(1, 102, 2, N, N, N, N),
+ MUX(1, 97, 2, N, N, N, N),
+ MUX(1, 98, 2, N, N, N, N),
};
static struct atlas7_grp_mux vi_vip1_high8bit_grp_mux = {
@@ -4598,9 +4614,11 @@ static struct atlas7_pmx_func atlas7_pmx_functions[] = {
FUNCTION("ld_ldd_lck", ld_ldd_lck_grp, &ld_ldd_lck_grp_mux),
FUNCTION("lr_lcdrom", lr_lcdrom_grp, &lr_lcdrom_grp_mux),
FUNCTION("lvds_analog", lvds_analog_grp, &lvds_analog_grp_mux),
- FUNCTION("nd_df", nd_df_grp, &nd_df_grp_mux),
- FUNCTION("nd_df_nowp", nd_df_nowp_grp, &nd_df_nowp_grp_mux),
+ FUNCTION("nd_df_basic", nd_df_basic_grp, &nd_df_basic_grp_mux),
+ FUNCTION("nd_df_wp", nd_df_wp_grp, &nd_df_wp_grp_mux),
+ FUNCTION("nd_df_cs", nd_df_cs_grp, &nd_df_cs_grp_mux),
FUNCTION("ps", ps_grp, &ps_grp_mux),
+ FUNCTION("ps_no_dir", ps_no_dir_grp, &ps_no_dir_grp_mux),
FUNCTION("pwc_core_on", pwc_core_on_grp, &pwc_core_on_grp_mux),
FUNCTION("pwc_ext_on", pwc_ext_on_grp, &pwc_ext_on_grp_mux),
FUNCTION("pwc_gpio3_clk", pwc_gpio3_clk_grp, &pwc_gpio3_clk_grp_mux),
@@ -4686,10 +4704,11 @@ static struct atlas7_pmx_func atlas7_pmx_functions[] = {
FUNCTION("sd2_cdb_m1", sd2_cdb_grp1, &sd2_cdb_grp1_mux),
FUNCTION("sd2_wpb_m0", sd2_wpb_grp0, &sd2_wpb_grp0_mux),
FUNCTION("sd2_wpb_m1", sd2_wpb_grp1, &sd2_wpb_grp1_mux),
- FUNCTION("sd3", sd3_grp, &sd3_grp_mux),
+ FUNCTION("sd3", sd3_9_grp, &sd3_9_grp_mux),
FUNCTION("sd5", sd5_grp, &sd5_grp_mux),
FUNCTION("sd6_m0", sd6_grp0, &sd6_grp0_mux),
FUNCTION("sd6_m1", sd6_grp1, &sd6_grp1_mux),
+ FUNCTION("sd9", sd3_9_grp, &sd3_9_grp_mux),
FUNCTION("sp0_ext_ldo_on",
sp0_ext_ldo_on_grp,
&sp0_ext_ldo_on_grp_mux),
@@ -5097,6 +5116,14 @@ static int atlas7_pmx_set_mux(struct pinctrl_dev *pctldev,
pr_debug("PMX DUMP ### Function:[%s] Group:[%s] #### START >>>\n",
pmx_func->name, pin_grp->name);
+ /* the sd3 and sd9 pin select by SYS2PCI_SDIO9SEL register */
+ if (pin_grp->pins == (unsigned int *)&sd3_9_pins) {
+ if (!strcmp(pmx_func->name, "sd9"))
+ writel(1, pmx->sys2pci_base + SYS2PCI_SDIO9SEL);
+ else
+ writel(0, pmx->sys2pci_base + SYS2PCI_SDIO9SEL);
+ }
+
grp_mux = pmx_func->grpmux;
for (idx = 0; idx < grp_mux->pad_mux_count; idx++) {
@@ -5385,12 +5412,27 @@ static int atlas7_pinmux_probe(struct platform_device *pdev)
struct atlas7_pmx *pmx;
struct device_node *np = pdev->dev.of_node;
u32 banks = ATLAS7_PINCTRL_REG_BANKS;
+ struct device_node *sys2pci_np;
+ struct resource res;
/* Create state holders etc for this driver */
pmx = devm_kzalloc(&pdev->dev, sizeof(*pmx), GFP_KERNEL);
if (!pmx)
return -ENOMEM;
+ /* The sd3 and sd9 shared all pins, and the function select by
+ * SYS2PCI_SDIO9SEL register
+ */
+ sys2pci_np = of_find_node_by_name(NULL, "sys2pci");
+ if (!sys2pci_np)
+ return -EINVAL;
+ ret = of_address_to_resource(sys2pci_np, 0, &res);
+ if (ret)
+ return ret;
+ pmx->sys2pci_base = devm_ioremap_resource(&pdev->dev, &res);
+ if (IS_ERR(pmx->sys2pci_base))
+ return -ENOMEM;
+
pmx->dev = &pdev->dev;
pmx->pctl_data = &atlas7_ioc_data;
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index 2a8d697..edf40df 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -85,12 +85,16 @@ static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
/* calculate number of maps required */
for_each_child_of_node(np_config, np) {
ret = of_property_read_string(np, "sirf,function", &function);
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(np);
return ret;
+ }
ret = of_property_count_strings(np, "sirf,pins");
- if (ret < 0)
+ if (ret < 0) {
+ of_node_put(np);
return ret;
+ }
count += ret;
}
diff --git a/drivers/pinctrl/spear/Makefile b/drivers/pinctrl/spear/Makefile
index 0e400eb..37b8412 100644
--- a/drivers/pinctrl/spear/Makefile
+++ b/drivers/pinctrl/spear/Makefile
@@ -1,7 +1,7 @@
# SPEAr pinmux support
obj-$(CONFIG_PINCTRL_SPEAR_PLGPIO) += pinctrl-plgpio.o
-obj-$(CONFIG_PINCTRL_SPEAR) += pinctrl-spear.o
+obj-y += pinctrl-spear.o
obj-$(CONFIG_PINCTRL_SPEAR3XX) += pinctrl-spear3xx.o
obj-$(CONFIG_PINCTRL_SPEAR300) += pinctrl-spear300.o
obj-$(CONFIG_PINCTRL_SPEAR310) += pinctrl-spear310.o
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index e68fd95..f8dbc8b 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -51,8 +51,17 @@ config PINCTRL_SUN8I_A23_R
depends on RESET_CONTROLLER
select PINCTRL_SUNXI_COMMON
+config PINCTRL_SUN8I_H3
+ def_bool MACH_SUN8I
+ select PINCTRL_SUNXI_COMMON
+
config PINCTRL_SUN9I_A80
def_bool MACH_SUN9I
select PINCTRL_SUNXI_COMMON
+config PINCTRL_SUN9I_A80_R
+ def_bool MACH_SUN9I
+ depends on RESET_CONTROLLER
+ select PINCTRL_SUNXI_COMMON
+
endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index e080290..ef82f22 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -13,4 +13,6 @@ obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o
obj-$(CONFIG_PINCTRL_SUN8I_A33) += pinctrl-sun8i-a33.o
obj-$(CONFIG_PINCTRL_SUN8I_A83T) += pinctrl-sun8i-a83t.o
+obj-$(CONFIG_PINCTRL_SUN8I_H3) += pinctrl-sun8i-h3.o
obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o
+obj-$(CONFIG_PINCTRL_SUN9I_A80_R) += pinctrl-sun9i-a80-r.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
new file mode 100644
index 0000000..77d4cf0
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun8i-h3.c
@@ -0,0 +1,515 @@
+/*
+ * Allwinner H3 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2015 Jens Kuske <jenskuske@gmail.com>
+ *
+ * Based on pinctrl-sun8i-a23.c, which is:
+ * Copyright (C) 2014 Chen-Yu Tsai <wens@csie.org>
+ * Copyright (C) 2014 Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun8i_h3_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION(0x3, "jtag"), /* MS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PA_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION(0x3, "jtag"), /* CK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PA_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PA_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PA_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PA_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x3, "pwm0"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PA_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "sim"), /* PWREN */
+ SUNXI_FUNCTION(0x3, "pwm1"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PA_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "sim"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PA_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "sim"), /* DATA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PA_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "sim"), /* RST */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PA_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "sim"), /* DET */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x3, "di"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x3, "di"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CS */
+ SUNXI_FUNCTION(0x3, "uart3"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x3, "uart3"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spdif"), /* OUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* SYNC */
+ SUNXI_FUNCTION(0x3, "i2c1"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "i2c1"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "sim"), /* VPPEN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DIN */
+ SUNXI_FUNCTION(0x3, "sim"), /* VPPPP */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* WE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* ALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CE1 */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RE */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* RB1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXD3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXD2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXD1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXD0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXCTL/RXDV */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* RXERR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXD3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXD2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXD1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXD0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* CRS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXCTL/TXEN */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* TXERR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* CLKIN/COL */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* MDC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "emac")), /* MDIO */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* PCLK */
+ SUNXI_FUNCTION(0x3, "ts")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "ts")), /* ERR */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "ts")), /* SYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "ts")), /* DVLD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D0 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D1 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D2 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D3 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D4 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D5 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D6 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D7 */
+ SUNXI_FUNCTION(0x3, "ts")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SCK */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SDA */
+ SUNXI_FUNCTION(0x3, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* MS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x3, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CMD */
+ SUNXI_FUNCTION(0x3, "jtag")), /* DO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "jtag")), /* CK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* PG_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* PG_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* PG_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* PG_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* PG_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* PG_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* PG_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* PG_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)), /* PG_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart1"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)), /* PG_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 10)), /* PG_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 11)), /* PG_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 12)), /* PG_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s1"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 13)), /* PG_EINT13 */
+};
+
+static const struct sunxi_pinctrl_desc sun8i_h3_pinctrl_data = {
+ .pins = sun8i_h3_pins,
+ .npins = ARRAY_SIZE(sun8i_h3_pins),
+ .irq_banks = 2,
+};
+
+static int sun8i_h3_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun8i_h3_pinctrl_data);
+}
+
+static const struct of_device_id sun8i_h3_pinctrl_match[] = {
+ { .compatible = "allwinner,sun8i-h3-pinctrl", },
+ {}
+};
+
+static struct platform_driver sun8i_h3_pinctrl_driver = {
+ .probe = sun8i_h3_pinctrl_probe,
+ .driver = {
+ .name = "sun8i-h3-pinctrl",
+ .of_match_table = sun8i_h3_pinctrl_match,
+ },
+};
+builtin_platform_driver(sun8i_h3_pinctrl_driver);
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
new file mode 100644
index 0000000..42547ff
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80-r.c
@@ -0,0 +1,181 @@
+/*
+ * Allwinner A80 SoCs special pins pinctrl driver.
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/reset.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun9i_a80_r_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_uart"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PL_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_uart"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PL_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* TMS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PL_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* TCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PL_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* TDO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PL_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_jtag"), /* TDI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PL_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_cir_rx"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PL_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "1wire"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PL_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_ps2"), /* SCK1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PL_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(L, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_ps2"), /* SDA1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PL_EINT9 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* PM_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* PM_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* PM_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* PM_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_i2s1"), /* LRCKR */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* PM_EINT4 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_i2c1"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 8)), /* PM_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "s_i2c1"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 9)), /* PM_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2s0"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "s_i2s1")), /* MCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2s0"), /* BCLK */
+ SUNXI_FUNCTION(0x3, "s_i2s1")), /* BCLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2s0"), /* LRCK */
+ SUNXI_FUNCTION(0x3, "s_i2s1")), /* LRCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2s0"), /* DIN */
+ SUNXI_FUNCTION(0x3, "s_i2s1")), /* DIN */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2s0"), /* DOUT */
+ SUNXI_FUNCTION(0x3, "s_i2s1")), /* DOUT */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(M, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 15)), /* PM_EINT15 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(N, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2c0"), /* SCK */
+ SUNXI_FUNCTION(0x3, "s_rsb")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(N, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "s_i2c0"), /* SDA */
+ SUNXI_FUNCTION(0x3, "s_rsb")), /* SDA */
+};
+
+static const struct sunxi_pinctrl_desc sun9i_a80_r_pinctrl_data = {
+ .pins = sun9i_a80_r_pins,
+ .npins = ARRAY_SIZE(sun9i_a80_r_pins),
+ .pin_base = PL_BASE,
+ .irq_banks = 2,
+};
+
+static int sun9i_a80_r_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun9i_a80_r_pinctrl_data);
+}
+
+static const struct of_device_id sun9i_a80_r_pinctrl_match[] = {
+ { .compatible = "allwinner,sun9i-a80-r-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun9i_a80_r_pinctrl_match);
+
+static struct platform_driver sun9i_a80_r_pinctrl_driver = {
+ .probe = sun9i_a80_r_pinctrl_probe,
+ .driver = {
+ .name = "sun9i-a80-r-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sun9i_a80_r_pinctrl_match,
+ },
+};
+module_platform_driver(sun9i_a80_r_pinctrl_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com");
+MODULE_DESCRIPTION("Allwinner A80 R_PIO pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig
index ad90707..7abd614 100644
--- a/drivers/pinctrl/uniphier/Kconfig
+++ b/drivers/pinctrl/uniphier/Kconfig
@@ -1,32 +1,35 @@
-if ARCH_UNIPHIER
-
-config PINCTRL_UNIPHIER
- bool
+menuconfig PINCTRL_UNIPHIER
+ bool "UniPhier SoC pinctrl drivers"
+ depends on ARCH_UNIPHIER
+ depends on OF && MFD_SYSCON
+ default y
select PINMUX
select GENERIC_PINCONF
+if PINCTRL_UNIPHIER
+
config PINCTRL_UNIPHIER_PH1_LD4
tristate "UniPhier PH1-LD4 SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
config PINCTRL_UNIPHIER_PH1_PRO4
tristate "UniPhier PH1-Pro4 SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
config PINCTRL_UNIPHIER_PH1_SLD8
tristate "UniPhier PH1-sLD8 SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
config PINCTRL_UNIPHIER_PH1_PRO5
tristate "UniPhier PH1-Pro5 SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
config PINCTRL_UNIPHIER_PROXSTREAM2
tristate "UniPhier ProXstream2 SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
config PINCTRL_UNIPHIER_PH1_LD6B
tristate "UniPhier PH1-LD6b SoC pinctrl driver"
- select PINCTRL_UNIPHIER
+ default y
endif
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 3271cd1..d03df4a 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -4,6 +4,7 @@
menuconfig CHROME_PLATFORMS
bool "Platform support for Chrome hardware"
+ depends on X86 || ARM || ARM64 || COMPILE_TEST
---help---
Say Y here to get to see options for platform support for
various Chromebooks and Chromeboxes. This option alone does
@@ -39,7 +40,7 @@ config CHROMEOS_PSTORE
config CROS_EC_CHARDEV
tristate "Chrome OS Embedded Controller userspace device interface"
- depends on CROS_EC_PROTO
+ depends on MFD_CROS_EC
---help---
This driver adds support to talk with the ChromeOS EC from userspace.
@@ -48,7 +49,7 @@ config CROS_EC_CHARDEV
config CROS_EC_LPC
tristate "ChromeOS Embedded Controller (LPC)"
- depends on MFD_CROS_EC && CROS_EC_PROTO && (X86 || COMPILE_TEST)
+ depends on MFD_CROS_EC && (X86 || COMPILE_TEST)
help
If you say Y here, you get support for talking to the ChromeOS EC
over an LPC bus. This uses a simple byte-level protocol with a
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 4a11b01..bc498bd 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -1,7 +1,8 @@
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
-cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o cros_ec_lightbar.o
+cros_ec_devs-objs := cros_ec_dev.o cros_ec_sysfs.o \
+ cros_ec_lightbar.o cros_ec_vbc.o
obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_devs.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o
diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 0207274..2b441e9 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -47,8 +47,8 @@ static const char *i2c_adapter_names[] = {
"SMBus I801 adapter",
"i915 gmbus vga",
"i915 gmbus panel",
- "i2c-designware-pci",
- "i2c-designware-pci",
+ "Synopsys DesignWare I2C adapter",
+ "Synopsys DesignWare I2C adapter",
};
/* Keep this enum consistent with i2c_adapter_names */
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
index e8fcdc2..d45cd25 100644
--- a/drivers/platform/chrome/cros_ec_dev.c
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -32,6 +32,7 @@ static int ec_major;
static const struct attribute_group *cros_ec_groups[] = {
&cros_ec_attr_group,
&cros_ec_lightbar_attr_group,
+ &cros_ec_vbc_attr_group,
NULL,
};
@@ -287,6 +288,12 @@ static int ec_device_remove(struct platform_device *pdev)
return 0;
}
+static const struct platform_device_id cros_ec_id[] = {
+ { "cros-ec-ctl", 0 },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(platform, cros_ec_id);
+
static struct platform_driver cros_ec_dev_driver = {
.driver = {
.name = "cros-ec-ctl",
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 144e09d..ff76405 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -252,7 +252,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
ret = sscanf(buf, "%i", &val[i++]);
if (ret == 0)
- return -EINVAL;
+ goto exit;
if (i == 4) {
param = (struct ec_params_lightbar *)msg->data;
@@ -268,17 +268,15 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
if ((j++ % 4) == 0) {
ret = lb_throttle();
if (ret)
- return ret;
+ goto exit;
}
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
if (ret < 0)
goto exit;
- if (msg->result != EC_RES_SUCCESS) {
- ret = -EINVAL;
+ if (msg->result != EC_RES_SUCCESS)
goto exit;
- }
i = 0;
ok = 1;
@@ -352,10 +350,6 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
struct cros_ec_dev *ec = container_of(dev,
struct cros_ec_dev, class_dev);
- msg = alloc_lightbar_cmd_msg(ec);
- if (!msg)
- return -ENOMEM;
-
for (len = 0; len < count; len++)
if (!isalnum(buf[len]))
break;
@@ -370,21 +364,30 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
return ret;
}
+ msg = alloc_lightbar_cmd_msg(ec);
+ if (!msg)
+ return -ENOMEM;
+
param = (struct ec_params_lightbar *)msg->data;
param->cmd = LIGHTBAR_CMD_SEQ;
param->seq.num = num;
ret = lb_throttle();
if (ret)
- return ret;
+ goto exit;
ret = cros_ec_cmd_xfer(ec->ec_dev, msg);
if (ret < 0)
- return ret;
+ goto exit;
- if (msg->result != EC_RES_SUCCESS)
- return -EINVAL;
+ if (msg->result != EC_RES_SUCCESS) {
+ ret = -EINVAL;
+ goto exit;
+ }
- return count;
+ ret = count;
+exit:
+ kfree(msg);
+ return ret;
}
/* Module initialization */
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index bdd77ce..f9a2454 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -166,19 +166,9 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec,
/* Check result */
msg->result = inb(EC_LPC_ADDR_HOST_DATA);
-
- switch (msg->result) {
- case EC_RES_SUCCESS:
- break;
- case EC_RES_IN_PROGRESS:
- ret = -EAGAIN;
- dev_dbg(ec->dev, "command 0x%02x in progress\n",
- msg->command);
+ ret = cros_ec_check_result(ec, msg);
+ if (ret)
goto done;
- default:
- dev_dbg(ec->dev, "command 0x%02x returned %d\n",
- msg->command, msg->result);
- }
/* Read back args */
args.flags = inb(EC_LPC_ADDR_HOST_ARGS);
@@ -330,6 +320,13 @@ static struct dmi_system_id cros_ec_lpc_dmi_table[] __initdata = {
},
},
{
+ /* x86-samus, the Chromebook Pixel 2. */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
+ },
+ },
+ {
/* x86-peppy, the Acer C720 Chromebook. */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
diff --git a/drivers/platform/chrome/cros_ec_vbc.c b/drivers/platform/chrome/cros_ec_vbc.c
new file mode 100644
index 0000000..564a0d0
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_vbc.c
@@ -0,0 +1,137 @@
+/*
+ * cros_ec_vbc - Expose the vboot context nvram to userspace
+ *
+ * Copyright (C) 2015 Collabora Ltd.
+ *
+ * based on vendor driver,
+ *
+ * Copyright (C) 2012 The Chromium OS Authors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/cros_ec.h>
+#include <linux/mfd/cros_ec_commands.h>
+#include <linux/slab.h>
+
+static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *att, char *buf,
+ loff_t pos, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
+ class_dev);
+ struct cros_ec_device *ecdev = ec->ec_dev;
+ struct ec_params_vbnvcontext *params;
+ struct cros_ec_command *msg;
+ int err;
+ const size_t para_sz = sizeof(params->op);
+ const size_t resp_sz = sizeof(struct ec_response_vbnvcontext);
+ const size_t payload = max(para_sz, resp_sz);
+
+ msg = kmalloc(sizeof(*msg) + payload, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ /* NB: we only kmalloc()ated enough space for the op field */
+ params = (struct ec_params_vbnvcontext *)msg->data;
+ params->op = EC_VBNV_CONTEXT_OP_READ;
+
+ msg->version = EC_VER_VBNV_CONTEXT;
+ msg->command = EC_CMD_VBNV_CONTEXT;
+ msg->outsize = para_sz;
+ msg->insize = resp_sz;
+
+ err = cros_ec_cmd_xfer(ecdev, msg);
+ if (err < 0) {
+ dev_err(dev, "Error sending read request: %d\n", err);
+ kfree(msg);
+ return err;
+ }
+
+ memcpy(buf, msg->data, resp_sz);
+
+ kfree(msg);
+ return resp_sz;
+}
+
+static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t pos, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
+ class_dev);
+ struct cros_ec_device *ecdev = ec->ec_dev;
+ struct ec_params_vbnvcontext *params;
+ struct cros_ec_command *msg;
+ int err;
+ const size_t para_sz = sizeof(*params);
+ const size_t data_sz = sizeof(params->block);
+
+ /* Only write full values */
+ if (count != data_sz)
+ return -EINVAL;
+
+ msg = kmalloc(sizeof(*msg) + para_sz, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ params = (struct ec_params_vbnvcontext *)msg->data;
+ params->op = EC_VBNV_CONTEXT_OP_WRITE;
+ memcpy(params->block, buf, data_sz);
+
+ msg->version = EC_VER_VBNV_CONTEXT;
+ msg->command = EC_CMD_VBNV_CONTEXT;
+ msg->outsize = para_sz;
+ msg->insize = 0;
+
+ err = cros_ec_cmd_xfer(ecdev, msg);
+ if (err < 0) {
+ dev_err(dev, "Error sending write request: %d\n", err);
+ kfree(msg);
+ return err;
+ }
+
+ kfree(msg);
+ return data_sz;
+}
+
+static umode_t cros_ec_vbc_is_visible(struct kobject *kobj,
+ struct bin_attribute *a, int n)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
+ class_dev);
+ struct device_node *np = ec->ec_dev->dev->of_node;
+
+ if (IS_ENABLED(CONFIG_OF) && np) {
+ if (of_property_read_bool(np, "google,has-vbc-nvram"))
+ return a->attr.mode;
+ }
+
+ return 0;
+}
+
+static BIN_ATTR_RW(vboot_context, 16);
+
+static struct bin_attribute *cros_ec_vbc_bin_attrs[] = {
+ &bin_attr_vboot_context,
+ NULL
+};
+
+struct attribute_group cros_ec_vbc_attr_group = {
+ .name = "vbc",
+ .bin_attrs = cros_ec_vbc_bin_attrs,
+ .is_bin_visible = cros_ec_vbc_is_visible,
+};
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 02bbc70..1089eaa 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -345,6 +345,7 @@ config IDEAPAD_LAPTOP
depends on SERIO_I8042
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
+ depends on ACPI_WMI || ACPI_WMI = n
select INPUT_SPARSEKMAP
help
This is a driver for Lenovo IdeaPad netbooks contains drivers for
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 1f7d80f..f96f7b8 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -1320,7 +1320,7 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
if (err < 0)
return err;
- value = KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000;
+ value = DECI_KELVIN_TO_CELSIUS((value & 0xFFFF)) * 1000;
return sprintf(buf, "%d\n", value);
}
@@ -1682,7 +1682,7 @@ static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
int rv, err, value;
value = asus_wmi_get_devstate_simple(asus, devid);
- if (value == -ENODEV) /* Check device presence */
+ if (value < 0)
return value;
rv = parse_arg(buf, count, &value);
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index fce49f3..a313dfc 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -47,6 +47,10 @@
#define CFG_WIFI_BIT (18)
#define CFG_CAMERA_BIT (19)
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+static const char ideapad_wmi_fnesc_event[] = "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6";
+#endif
+
enum {
VPCCMD_R_VPC1 = 0x10,
VPCCMD_R_BL_MAX,
@@ -567,6 +571,8 @@ static const struct key_entry ideapad_keymap[] = {
{ KE_KEY, 65, { KEY_PROG4 } },
{ KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
{ KE_KEY, 67, { KEY_TOUCHPAD_ON } },
+ { KE_KEY, 128, { KEY_ESC } },
+
{ KE_END, 0 },
};
@@ -825,6 +831,19 @@ static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
}
}
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+static void ideapad_wmi_notify(u32 value, void *context)
+{
+ switch (value) {
+ case 128:
+ ideapad_input_report(context, value);
+ break;
+ default:
+ pr_info("Unknown WMI event %u\n", value);
+ }
+}
+#endif
+
/*
* Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF
* always results in 0 on these models, causing ideapad_laptop to wrongly
@@ -853,24 +872,31 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
- .ident = "Lenovo Yoga 3 14",
+ .ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3 14"),
+ DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
},
},
{
- .ident = "Lenovo Yoga 2 11 / 13 / Pro",
+ .ident = "Lenovo Yoga 3 1170 / 1470",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 3"),
},
},
{
.ident = "Lenovo Yoga 3 Pro 1370",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3 Pro-1370"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3"),
+ },
+ },
+ {
+ .ident = "Lenovo Yoga 900",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
},
},
{}
@@ -935,8 +961,18 @@ static int ideapad_acpi_add(struct platform_device *pdev)
ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv);
if (ret)
goto notification_failed;
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+ ret = wmi_install_notify_handler(ideapad_wmi_fnesc_event, ideapad_wmi_notify, priv);
+ if (ret != AE_OK && ret != AE_NOT_EXIST)
+ goto notification_failed_wmi;
+#endif
return 0;
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+notification_failed_wmi:
+ acpi_remove_notify_handler(priv->adev->handle,
+ ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
+#endif
notification_failed:
ideapad_backlight_exit(priv);
backlight_failed:
@@ -955,6 +991,9 @@ static int ideapad_acpi_remove(struct platform_device *pdev)
struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
int i;
+#if IS_ENABLED(CONFIG_ACPI_WMI)
+ wmi_remove_notify_handler(ideapad_wmi_fnesc_event);
+#endif
acpi_remove_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
ideapad_backlight_exit(priv);
diff --git a/drivers/platform/x86/intel_menlow.c b/drivers/platform/x86/intel_menlow.c
index e8b46d2..0a919d8 100644
--- a/drivers/platform/x86/intel_menlow.c
+++ b/drivers/platform/x86/intel_menlow.c
@@ -315,7 +315,7 @@ static ssize_t aux0_show(struct device *dev,
result = sensor_get_auxtrip(attr->handle, 0, &value);
- return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+ return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value));
}
static ssize_t aux1_show(struct device *dev,
@@ -327,7 +327,7 @@ static ssize_t aux1_show(struct device *dev,
result = sensor_get_auxtrip(attr->handle, 1, &value);
- return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
+ return result ? result : sprintf(buf, "%lu", DECI_KELVIN_TO_CELSIUS(value));
}
static ssize_t aux0_store(struct device *dev,
@@ -345,7 +345,7 @@ static ssize_t aux0_store(struct device *dev,
if (value < 0)
return -EINVAL;
- result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
+ result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_DECI_KELVIN(value));
return result ? result : count;
}
@@ -364,7 +364,7 @@ static ssize_t aux1_store(struct device *dev,
if (value < 0)
return -EINVAL;
- result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
+ result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_DECI_KELVIN(value));
return result ? result : count;
}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 131dd74..0bed473 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -6459,8 +6459,7 @@ static void __init tpacpi_detect_brightness_capabilities(void)
pr_info("detected a 8-level brightness capable ThinkPad\n");
break;
default:
- pr_err("Unsupported brightness interface, "
- "please contact %s\n", TPACPI_MAIL);
+ pr_info("Unsupported brightness interface\n");
tp_features.bright_unkfw = 1;
bright_maxlvl = b - 1;
}
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index cc97f08..48747c2 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -1341,10 +1341,13 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
/* check if the domain is locked by BIOS */
- if (rapl_read_data_raw(rd, FW_LOCK, false, &locked)) {
+ ret = rapl_read_data_raw(rd, FW_LOCK, false, &locked);
+ if (ret)
+ return ret;
+ if (locked) {
pr_info("RAPL package %d domain %s locked by BIOS\n",
rp->id, rd->name);
- rd->state |= DOMAIN_STATE_BIOS_LOCKED;
+ rd->state |= DOMAIN_STATE_BIOS_LOCKED;
}
}
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 062630a..2f4641a 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -92,6 +92,15 @@ config PWM_BCM2835
To compile this driver as a module, choose M here: the module
will be called pwm-bcm2835.
+config PWM_BERLIN
+ tristate "Marvell Berlin PWM support"
+ depends on ARCH_BERLIN
+ help
+ PWM framework driver for Marvell Berlin SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-berlin.
+
config PWM_BFIN
tristate "Blackfin PWM support"
depends on BFIN_GPTIMERS
@@ -101,6 +110,16 @@ config PWM_BFIN
To compile this driver as a module, choose M here: the module
will be called pwm-bfin.
+config PWM_BRCMSTB
+ tristate "Broadcom STB PWM support"
+ depends on ARCH_BRCMSTB || BMIPS_GENERIC
+ help
+ Generic PWM framework driver for the Broadcom Set-top-Box
+ SoCs (BCM7xxx).
+
+ To compile this driver as a module, choose M Here: the module
+ will be called pwm-brcmstb.c.
+
config PWM_CLPS711X
tristate "CLPS711X PWM support"
depends on ARCH_CLPS711X || COMPILE_TEST
@@ -230,6 +249,17 @@ config PWM_LPSS_PLATFORM
To compile this driver as a module, choose M here: the module
will be called pwm-lpss-platform.
+config PWM_MTK_DISP
+ tristate "MediaTek display PWM driver"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ Generic PWM framework driver for MediaTek disp-pwm device.
+ The PWM is used to control the backlight brightness for display.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-mtk-disp.
+
config PWM_MXS
tristate "Freescale MXS PWM support"
depends on ARCH_MXS && OF
@@ -242,7 +272,7 @@ config PWM_MXS
config PWM_PCA9685
tristate "NXP PCA9685 PWM driver"
- depends on OF && I2C
+ depends on I2C
select REGMAP_I2C
help
Generic PWM framework driver for NXP PCA9685 LED controller.
@@ -268,6 +298,17 @@ config PWM_PXA
To compile this driver as a module, choose M here: the module
will be called pwm-pxa.
+config PWM_RCAR
+ tristate "Renesas R-Car PWM support"
+ depends on ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || COMPILE_TEST
+ depends on HAS_IOMEM
+ help
+ This driver exposes the PWM Timer controller found in Renesas
+ R-Car chips through the PWM API.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-rcar.
+
config PWM_RENESAS_TPU
tristate "Renesas TPU PWM support"
depends on ARCH_SHMOBILE || COMPILE_TEST
@@ -338,7 +379,7 @@ config PWM_TEGRA
config PWM_TIECAP
tristate "ECAP PWM support"
- depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX
+ depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
help
PWM driver support for the ECAP APWM controller found on AM33XX
TI SOC
@@ -348,7 +389,7 @@ config PWM_TIECAP
config PWM_TIEHRPWM
tristate "EHRPWM PWM support"
- depends on SOC_AM33XX || ARCH_DAVINCI_DA8XX
+ depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX
help
PWM driver support for the EHRPWM controller found on AM33XX
TI SOC
@@ -358,7 +399,7 @@ config PWM_TIEHRPWM
config PWM_TIPWMSS
bool
- default y if SOC_AM33XX && (PWM_TIECAP || PWM_TIEHRPWM)
+ default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM)
help
PWM Subsystem driver support for AM33xx SOC.
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index a0e00c0..69b8275 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -6,7 +6,9 @@ obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o
obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o
obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o
obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o
+obj-$(CONFIG_PWM_BERLIN) += pwm-berlin.o
obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
+obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o
obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
obj-$(CONFIG_PWM_CRC) += pwm-crc.o
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
@@ -20,10 +22,12 @@ obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o
obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o
obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o
obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o
+obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o
obj-$(CONFIG_PWM_MXS) += pwm-mxs.o
obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o
obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o
obj-$(CONFIG_PWM_PXA) += pwm-pxa.o
+obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o
obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 3f9df3e..d24ca5f 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -269,6 +269,7 @@ int pwmchip_add_with_polarity(struct pwm_chip *chip,
pwm->pwm = chip->base + i;
pwm->hwpwm = i;
pwm->polarity = polarity;
+ mutex_init(&pwm->lock);
radix_tree_insert(&pwm_tree, pwm->pwm, pwm);
}
@@ -473,16 +474,22 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity)
if (!pwm->chip->ops->set_polarity)
return -ENOSYS;
- if (pwm_is_enabled(pwm))
- return -EBUSY;
+ mutex_lock(&pwm->lock);
+
+ if (pwm_is_enabled(pwm)) {
+ err = -EBUSY;
+ goto unlock;
+ }
err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity);
if (err)
- return err;
+ goto unlock;
pwm->polarity = polarity;
- return 0;
+unlock:
+ mutex_unlock(&pwm->lock);
+ return err;
}
EXPORT_SYMBOL_GPL(pwm_set_polarity);
@@ -494,10 +501,22 @@ EXPORT_SYMBOL_GPL(pwm_set_polarity);
*/
int pwm_enable(struct pwm_device *pwm)
{
- if (pwm && !test_and_set_bit(PWMF_ENABLED, &pwm->flags))
- return pwm->chip->ops->enable(pwm->chip, pwm);
+ int err = 0;
- return pwm ? 0 : -EINVAL;
+ if (!pwm)
+ return -EINVAL;
+
+ mutex_lock(&pwm->lock);
+
+ if (!test_and_set_bit(PWMF_ENABLED, &pwm->flags)) {
+ err = pwm->chip->ops->enable(pwm->chip, pwm);
+ if (err)
+ clear_bit(PWMF_ENABLED, &pwm->flags);
+ }
+
+ mutex_unlock(&pwm->lock);
+
+ return err;
}
EXPORT_SYMBOL_GPL(pwm_enable);
@@ -719,8 +738,10 @@ struct pwm_device *pwm_get(struct device *dev, const char *con_id)
}
}
- if (!chosen)
+ if (!chosen) {
+ pwm = ERR_PTR(-ENODEV);
goto out;
+ }
chip = pwmchip_find_by_name(chosen->provider);
if (!chip)
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index 5df1db4..f994c7e 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -227,6 +227,9 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
.data = &atmel_hlcdc_pwm_at91sam9x5_errata,
},
{
+ .compatible = "atmel,sama5d2-hlcdc",
+ },
+ {
.compatible = "atmel,sama5d3-hlcdc",
.data = &atmel_hlcdc_pwm_sama5d3_errata,
},
@@ -236,6 +239,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = {
},
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids);
static int atmel_hlcdc_pwm_probe(struct platform_device *pdev)
{
diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c
index 6da01b3..75db585 100644
--- a/drivers/pwm/pwm-atmel-tcb.c
+++ b/drivers/pwm/pwm-atmel-tcb.c
@@ -305,7 +305,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
*/
if (i == 5) {
i = slowclk;
- rate = 32768;
+ rate = clk_get_rate(tc->slow_clk);
min = div_u64(NSEC_PER_SEC, rate);
max = min << tc->tcb_config->counter_width;
@@ -387,9 +387,9 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL);
if (tcbpwm == NULL) {
- atmel_tc_free(tc);
+ err = -ENOMEM;
dev_err(&pdev->dev, "failed to allocate memory\n");
- return -ENOMEM;
+ goto err_free_tc;
}
tcbpwm->chip.dev = &pdev->dev;
@@ -400,17 +400,27 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev)
tcbpwm->chip.npwm = NPWM;
tcbpwm->tc = tc;
+ err = clk_prepare_enable(tc->slow_clk);
+ if (err)
+ goto err_free_tc;
+
spin_lock_init(&tcbpwm->lock);
err = pwmchip_add(&tcbpwm->chip);
- if (err < 0) {
- atmel_tc_free(tc);
- return err;
- }
+ if (err < 0)
+ goto err_disable_clk;
platform_set_drvdata(pdev, tcbpwm);
return 0;
+
+err_disable_clk:
+ clk_disable_unprepare(tcbpwm->tc->slow_clk);
+
+err_free_tc:
+ atmel_tc_free(tc);
+
+ return err;
}
static int atmel_tcb_pwm_remove(struct platform_device *pdev)
@@ -418,6 +428,8 @@ static int atmel_tcb_pwm_remove(struct platform_device *pdev)
struct atmel_tcb_pwm_chip *tcbpwm = platform_get_drvdata(pdev);
int err;
+ clk_disable_unprepare(tcbpwm->tc->slow_clk);
+
err = pwmchip_remove(&tcbpwm->chip);
if (err < 0)
return err;
diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c
new file mode 100644
index 0000000..6510812
--- /dev/null
+++ b/drivers/pwm/pwm-berlin.c
@@ -0,0 +1,219 @@
+/*
+ * Marvell Berlin PWM driver
+ *
+ * Copyright (C) 2015 Marvell Technology Group Ltd.
+ *
+ * Author: Antoine Tenart <antoine.tenart@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+
+#define BERLIN_PWM_EN 0x0
+#define BERLIN_PWM_ENABLE BIT(0)
+#define BERLIN_PWM_CONTROL 0x4
+#define BERLIN_PWM_PRESCALE_MASK 0x7
+#define BERLIN_PWM_PRESCALE_MAX 4096
+#define BERLIN_PWM_INVERT_POLARITY BIT(3)
+#define BERLIN_PWM_DUTY 0x8
+#define BERLIN_PWM_TCNT 0xc
+#define BERLIN_PWM_MAX_TCNT 65535
+
+struct berlin_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+};
+
+static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct berlin_pwm_chip, chip);
+}
+
+static const u32 prescaler_table[] = {
+ 1, 4, 8, 16, 64, 256, 1024, 4096
+};
+
+static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip,
+ unsigned int channel, unsigned long offset)
+{
+ return readl_relaxed(chip->base + channel * 0x10 + offset);
+}
+
+static inline void berlin_pwm_writel(struct berlin_pwm_chip *chip,
+ unsigned int channel, u32 value,
+ unsigned long offset)
+{
+ writel_relaxed(value, chip->base + channel * 0x10 + offset);
+}
+
+static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev,
+ int duty_ns, int period_ns)
+{
+ struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ unsigned int prescale;
+ u32 value, duty, period;
+ u64 cycles, tmp;
+
+ cycles = clk_get_rate(pwm->clk);
+ cycles *= period_ns;
+ do_div(cycles, NSEC_PER_SEC);
+
+ for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) {
+ tmp = cycles;
+ do_div(tmp, prescaler_table[prescale]);
+
+ if (tmp <= BERLIN_PWM_MAX_TCNT)
+ break;
+ }
+
+ if (tmp > BERLIN_PWM_MAX_TCNT)
+ return -ERANGE;
+
+ period = tmp;
+ cycles = tmp * duty_ns;
+ do_div(cycles, period_ns);
+ duty = cycles;
+
+ value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
+ value &= ~BERLIN_PWM_PRESCALE_MASK;
+ value |= prescale;
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
+
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY);
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, period, BERLIN_PWM_TCNT);
+
+ return 0;
+}
+
+static int berlin_pwm_set_polarity(struct pwm_chip *chip,
+ struct pwm_device *pwm_dev,
+ enum pwm_polarity polarity)
+{
+ struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ u32 value;
+
+ value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL);
+
+ if (polarity == PWM_POLARITY_NORMAL)
+ value &= ~BERLIN_PWM_INVERT_POLARITY;
+ else
+ value |= BERLIN_PWM_INVERT_POLARITY;
+
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL);
+
+ return 0;
+}
+
+static int berlin_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm_dev)
+{
+ struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ u32 value;
+
+ value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
+ value |= BERLIN_PWM_ENABLE;
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
+
+ return 0;
+}
+
+static void berlin_pwm_disable(struct pwm_chip *chip,
+ struct pwm_device *pwm_dev)
+{
+ struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip);
+ u32 value;
+
+ value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_EN);
+ value &= ~BERLIN_PWM_ENABLE;
+ berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_EN);
+}
+
+static const struct pwm_ops berlin_pwm_ops = {
+ .config = berlin_pwm_config,
+ .set_polarity = berlin_pwm_set_polarity,
+ .enable = berlin_pwm_enable,
+ .disable = berlin_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id berlin_pwm_match[] = {
+ { .compatible = "marvell,berlin-pwm" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, berlin_pwm_match);
+
+static int berlin_pwm_probe(struct platform_device *pdev)
+{
+ struct berlin_pwm_chip *pwm;
+ struct resource *res;
+ int ret;
+
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm->base))
+ return PTR_ERR(pwm->base);
+
+ pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm->clk))
+ return PTR_ERR(pwm->clk);
+
+ ret = clk_prepare_enable(pwm->clk);
+ if (ret)
+ return ret;
+
+ pwm->chip.dev = &pdev->dev;
+ pwm->chip.ops = &berlin_pwm_ops;
+ pwm->chip.base = -1;
+ pwm->chip.npwm = 4;
+ pwm->chip.can_sleep = true;
+ pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+ pwm->chip.of_pwm_n_cells = 3;
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+ clk_disable_unprepare(pwm->clk);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, pwm);
+
+ return 0;
+}
+
+static int berlin_pwm_remove(struct platform_device *pdev)
+{
+ struct berlin_pwm_chip *pwm = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pwmchip_remove(&pwm->chip);
+ clk_disable_unprepare(pwm->clk);
+
+ return ret;
+}
+
+static struct platform_driver berlin_pwm_driver = {
+ .probe = berlin_pwm_probe,
+ .remove = berlin_pwm_remove,
+ .driver = {
+ .name = "berlin-pwm",
+ .of_match_table = berlin_pwm_match,
+ },
+};
+module_platform_driver(berlin_pwm_driver);
+
+MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>");
+MODULE_DESCRIPTION("Marvell Berlin PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-brcmstb.c b/drivers/pwm/pwm-brcmstb.c
new file mode 100644
index 0000000..423ce08
--- /dev/null
+++ b/drivers/pwm/pwm-brcmstb.c
@@ -0,0 +1,343 @@
+/*
+ * Broadcom BCM7038 PWM driver
+ * Author: Florian Fainelli
+ *
+ * Copyright (C) 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/export.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/spinlock.h>
+
+#define PWM_CTRL 0x00
+#define CTRL_START BIT(0)
+#define CTRL_OEB BIT(1)
+#define CTRL_FORCE_HIGH BIT(2)
+#define CTRL_OPENDRAIN BIT(3)
+#define CTRL_CHAN_OFFS 4
+
+#define PWM_CTRL2 0x04
+#define CTRL2_OUT_SELECT BIT(0)
+
+#define PWM_CH_SIZE 0x8
+
+#define PWM_CWORD_MSB(ch) (0x08 + ((ch) * PWM_CH_SIZE))
+#define PWM_CWORD_LSB(ch) (0x0c + ((ch) * PWM_CH_SIZE))
+
+/* Number of bits for the CWORD value */
+#define CWORD_BIT_SIZE 16
+
+/*
+ * Maximum control word value allowed when variable-frequency PWM is used as a
+ * clock for the constant-frequency PMW.
+ */
+#define CONST_VAR_F_MAX 32768
+#define CONST_VAR_F_MIN 1
+
+#define PWM_ON(ch) (0x18 + ((ch) * PWM_CH_SIZE))
+#define PWM_ON_MIN 1
+#define PWM_PERIOD(ch) (0x1c + ((ch) * PWM_CH_SIZE))
+#define PWM_PERIOD_MIN 0
+
+#define PWM_ON_PERIOD_MAX 0xff
+
+struct brcmstb_pwm {
+ void __iomem *base;
+ spinlock_t lock;
+ struct clk *clk;
+ struct pwm_chip chip;
+};
+
+static inline u32 brcmstb_pwm_readl(struct brcmstb_pwm *p,
+ unsigned int offset)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return __raw_readl(p->base + offset);
+ else
+ return readl_relaxed(p->base + offset);
+}
+
+static inline void brcmstb_pwm_writel(struct brcmstb_pwm *p, u32 value,
+ unsigned int offset)
+{
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ __raw_writel(value, p->base + offset);
+ else
+ writel_relaxed(value, p->base + offset);
+}
+
+static inline struct brcmstb_pwm *to_brcmstb_pwm(struct pwm_chip *chip)
+{
+ return container_of(chip, struct brcmstb_pwm, chip);
+}
+
+/*
+ * Fv is derived from the variable frequency output. The variable frequency
+ * output is configured using this formula:
+ *
+ * W = cword, if cword < 2 ^ 15 else 16-bit 2's complement of cword
+ *
+ * Fv = W x 2 ^ -16 x 27Mhz (reference clock)
+ *
+ * The period is: (period + 1) / Fv and "on" time is on / (period + 1)
+ *
+ * The PWM core framework specifies that the "duty_ns" parameter is in fact the
+ * "on" time, so this translates directly into our HW programming here.
+ */
+static int brcmstb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
+ unsigned long pc, dc, cword = CONST_VAR_F_MAX;
+ unsigned int channel = pwm->hwpwm;
+ u32 value;
+
+ /*
+ * If asking for a duty_ns equal to period_ns, we need to substract
+ * the period value by 1 to make it shorter than the "on" time and
+ * produce a flat 100% duty cycle signal, and max out the "on" time
+ */
+ if (duty_ns == period_ns) {
+ dc = PWM_ON_PERIOD_MAX;
+ pc = PWM_ON_PERIOD_MAX - 1;
+ goto done;
+ }
+
+ while (1) {
+ u64 rate, tmp;
+
+ /*
+ * Calculate the base rate from base frequency and current
+ * cword
+ */
+ rate = (u64)clk_get_rate(p->clk) * (u64)cword;
+ do_div(rate, 1 << CWORD_BIT_SIZE);
+
+ tmp = period_ns * rate;
+ do_div(tmp, NSEC_PER_SEC);
+ pc = tmp;
+
+ tmp = (duty_ns + 1) * rate;
+ do_div(tmp, NSEC_PER_SEC);
+ dc = tmp;
+
+ /*
+ * We can be called with separate duty and period updates,
+ * so do not reject dc == 0 right away
+ */
+ if (pc == PWM_PERIOD_MIN || (dc < PWM_ON_MIN && duty_ns))
+ return -EINVAL;
+
+ /* We converged on a calculation */
+ if (pc <= PWM_ON_PERIOD_MAX && dc <= PWM_ON_PERIOD_MAX)
+ break;
+
+ /*
+ * The cword needs to be a power of 2 for the variable
+ * frequency generator to output a 50% duty cycle variable
+ * frequency which is used as input clock to the fixed
+ * frequency generator.
+ */
+ cword >>= 1;
+
+ /*
+ * Desired periods are too large, we do not have a divider
+ * for them
+ */
+ if (cword < CONST_VAR_F_MIN)
+ return -EINVAL;
+ }
+
+done:
+ /*
+ * Configure the defined "cword" value to have the variable frequency
+ * generator output a base frequency for the constant frequency
+ * generator to derive from.
+ */
+ spin_lock(&p->lock);
+ brcmstb_pwm_writel(p, cword >> 8, PWM_CWORD_MSB(channel));
+ brcmstb_pwm_writel(p, cword & 0xff, PWM_CWORD_LSB(channel));
+
+ /* Select constant frequency signal output */
+ value = brcmstb_pwm_readl(p, PWM_CTRL2);
+ value |= CTRL2_OUT_SELECT << (channel * CTRL_CHAN_OFFS);
+ brcmstb_pwm_writel(p, value, PWM_CTRL2);
+
+ /* Configure on and period value */
+ brcmstb_pwm_writel(p, pc, PWM_PERIOD(channel));
+ brcmstb_pwm_writel(p, dc, PWM_ON(channel));
+ spin_unlock(&p->lock);
+
+ return 0;
+}
+
+static inline void brcmstb_pwm_enable_set(struct brcmstb_pwm *p,
+ unsigned int channel, bool enable)
+{
+ unsigned int shift = channel * CTRL_CHAN_OFFS;
+ u32 value;
+
+ spin_lock(&p->lock);
+ value = brcmstb_pwm_readl(p, PWM_CTRL);
+
+ if (enable) {
+ value &= ~(CTRL_OEB << shift);
+ value |= (CTRL_START | CTRL_OPENDRAIN) << shift;
+ } else {
+ value &= ~((CTRL_START | CTRL_OPENDRAIN) << shift);
+ value |= CTRL_OEB << shift;
+ }
+
+ brcmstb_pwm_writel(p, value, PWM_CTRL);
+ spin_unlock(&p->lock);
+}
+
+static int brcmstb_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
+
+ brcmstb_pwm_enable_set(p, pwm->hwpwm, true);
+
+ return 0;
+}
+
+static void brcmstb_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct brcmstb_pwm *p = to_brcmstb_pwm(chip);
+
+ brcmstb_pwm_enable_set(p, pwm->hwpwm, false);
+}
+
+static const struct pwm_ops brcmstb_pwm_ops = {
+ .config = brcmstb_pwm_config,
+ .enable = brcmstb_pwm_enable,
+ .disable = brcmstb_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static const struct of_device_id brcmstb_pwm_of_match[] = {
+ { .compatible = "brcm,bcm7038-pwm", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, brcmstb_pwm_of_match);
+
+static int brcmstb_pwm_probe(struct platform_device *pdev)
+{
+ struct brcmstb_pwm *p;
+ struct resource *res;
+ int ret;
+
+ p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ spin_lock_init(&p->lock);
+
+ p->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(p->clk)) {
+ dev_err(&pdev->dev, "failed to obtain clock\n");
+ return PTR_ERR(p->clk);
+ }
+
+ ret = clk_prepare_enable(p->clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to enable clock: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, p);
+
+ p->chip.dev = &pdev->dev;
+ p->chip.ops = &brcmstb_pwm_ops;
+ p->chip.base = -1;
+ p->chip.npwm = 2;
+ p->chip.can_sleep = true;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ p->base = devm_ioremap_resource(&pdev->dev, res);
+ if (!p->base) {
+ ret = -ENOMEM;
+ goto out_clk;
+ }
+
+ ret = pwmchip_add(&p->chip);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+ goto out_clk;
+ }
+
+ return 0;
+
+out_clk:
+ clk_disable_unprepare(p->clk);
+ return ret;
+}
+
+static int brcmstb_pwm_remove(struct platform_device *pdev)
+{
+ struct brcmstb_pwm *p = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pwmchip_remove(&p->chip);
+ clk_disable_unprepare(p->clk);
+
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmstb_pwm_suspend(struct device *dev)
+{
+ struct brcmstb_pwm *p = dev_get_drvdata(dev);
+
+ clk_disable(p->clk);
+
+ return 0;
+}
+
+static int brcmstb_pwm_resume(struct device *dev)
+{
+ struct brcmstb_pwm *p = dev_get_drvdata(dev);
+
+ clk_enable(p->clk);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(brcmstb_pwm_pm_ops, brcmstb_pwm_suspend,
+ brcmstb_pwm_resume);
+
+static struct platform_driver brcmstb_pwm_driver = {
+ .probe = brcmstb_pwm_probe,
+ .remove = brcmstb_pwm_remove,
+ .driver = {
+ .name = "pwm-brcmstb",
+ .of_match_table = brcmstb_pwm_of_match,
+ .pm = &brcmstb_pwm_pm_ops,
+ },
+};
+module_platform_driver(brcmstb_pwm_driver);
+
+MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
+MODULE_DESCRIPTION("Broadcom STB PWM driver");
+MODULE_ALIAS("platform:pwm-brcmstb");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pwm/pwm-lpss-pci.c b/drivers/pwm/pwm-lpss-pci.c
index 45042c1..7160e8a 100644
--- a/drivers/pwm/pwm-lpss-pci.c
+++ b/drivers/pwm/pwm-lpss-pci.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pm_runtime.h>
#include "pwm-lpss.h"
@@ -33,6 +34,10 @@ static int pwm_lpss_probe_pci(struct pci_dev *pdev,
return PTR_ERR(lpwm);
pci_set_drvdata(pdev, lpwm);
+
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+
return 0;
}
@@ -40,16 +45,41 @@ static void pwm_lpss_remove_pci(struct pci_dev *pdev)
{
struct pwm_lpss_chip *lpwm = pci_get_drvdata(pdev);
+ pm_runtime_forbid(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
pwm_lpss_remove(lpwm);
}
+#ifdef CONFIG_PM
+static int pwm_lpss_runtime_suspend_pci(struct device *dev)
+{
+ /*
+ * The PCI core will handle transition to D3 automatically. We only
+ * need to provide runtime PM hooks for that to happen.
+ */
+ return 0;
+}
+
+static int pwm_lpss_runtime_resume_pci(struct device *dev)
+{
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops pwm_lpss_pci_pm = {
+ SET_RUNTIME_PM_OPS(pwm_lpss_runtime_suspend_pci,
+ pwm_lpss_runtime_resume_pci, NULL)
+};
+
static const struct pci_device_id pwm_lpss_pci_ids[] = {
- { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bsw_info},
+ { PCI_VDEVICE(INTEL, 0x0ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x0f08), (unsigned long)&pwm_lpss_byt_info},
{ PCI_VDEVICE(INTEL, 0x0f09), (unsigned long)&pwm_lpss_byt_info},
- { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bsw_info},
+ { PCI_VDEVICE(INTEL, 0x1ac8), (unsigned long)&pwm_lpss_bxt_info},
{ PCI_VDEVICE(INTEL, 0x2288), (unsigned long)&pwm_lpss_bsw_info},
{ PCI_VDEVICE(INTEL, 0x2289), (unsigned long)&pwm_lpss_bsw_info},
+ { PCI_VDEVICE(INTEL, 0x5ac8), (unsigned long)&pwm_lpss_bxt_info},
{ },
};
MODULE_DEVICE_TABLE(pci, pwm_lpss_pci_ids);
@@ -59,6 +89,9 @@ static struct pci_driver pwm_lpss_driver_pci = {
.id_table = pwm_lpss_pci_ids,
.probe = pwm_lpss_probe_pci,
.remove = pwm_lpss_remove_pci,
+ .driver = {
+ .pm = &pwm_lpss_pci_pm,
+ },
};
module_pci_driver(pwm_lpss_driver_pci);
diff --git a/drivers/pwm/pwm-lpss-platform.c b/drivers/pwm/pwm-lpss-platform.c
index 18a9c88..54433fc 100644
--- a/drivers/pwm/pwm-lpss-platform.c
+++ b/drivers/pwm/pwm-lpss-platform.c
@@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include "pwm-lpss.h"
@@ -36,6 +37,10 @@ static int pwm_lpss_probe_platform(struct platform_device *pdev)
return PTR_ERR(lpwm);
platform_set_drvdata(pdev, lpwm);
+
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
return 0;
}
@@ -43,12 +48,14 @@ static int pwm_lpss_remove_platform(struct platform_device *pdev)
{
struct pwm_lpss_chip *lpwm = platform_get_drvdata(pdev);
+ pm_runtime_disable(&pdev->dev);
return pwm_lpss_remove(lpwm);
}
static const struct acpi_device_id pwm_lpss_acpi_match[] = {
{ "80860F09", (unsigned long)&pwm_lpss_byt_info },
{ "80862288", (unsigned long)&pwm_lpss_bsw_info },
+ { "80865AC8", (unsigned long)&pwm_lpss_bxt_info },
{ },
};
MODULE_DEVICE_TABLE(acpi, pwm_lpss_acpi_match);
diff --git a/drivers/pwm/pwm-lpss.c b/drivers/pwm/pwm-lpss.c
index e979825..2504410 100644
--- a/drivers/pwm/pwm-lpss.c
+++ b/drivers/pwm/pwm-lpss.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include "pwm-lpss.h"
@@ -29,6 +30,9 @@
#define PWM_LIMIT (0x8000 + PWM_DIVISION_CORRECTION)
#define NSECS_PER_SEC 1000000000UL
+/* Size of each PWM register space if multiple */
+#define PWM_SIZE 0x400
+
struct pwm_lpss_chip {
struct pwm_chip chip;
void __iomem *regs;
@@ -37,21 +41,44 @@ struct pwm_lpss_chip {
/* BayTrail */
const struct pwm_lpss_boardinfo pwm_lpss_byt_info = {
- .clk_rate = 25000000
+ .clk_rate = 25000000,
+ .npwm = 1,
};
EXPORT_SYMBOL_GPL(pwm_lpss_byt_info);
/* Braswell */
const struct pwm_lpss_boardinfo pwm_lpss_bsw_info = {
- .clk_rate = 19200000
+ .clk_rate = 19200000,
+ .npwm = 1,
};
EXPORT_SYMBOL_GPL(pwm_lpss_bsw_info);
+/* Broxton */
+const struct pwm_lpss_boardinfo pwm_lpss_bxt_info = {
+ .clk_rate = 19200000,
+ .npwm = 4,
+};
+EXPORT_SYMBOL_GPL(pwm_lpss_bxt_info);
+
static inline struct pwm_lpss_chip *to_lpwm(struct pwm_chip *chip)
{
return container_of(chip, struct pwm_lpss_chip, chip);
}
+static inline u32 pwm_lpss_read(const struct pwm_device *pwm)
+{
+ struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
+
+ return readl(lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
+}
+
+static inline void pwm_lpss_write(const struct pwm_device *pwm, u32 value)
+{
+ struct pwm_lpss_chip *lpwm = to_lpwm(pwm->chip);
+
+ writel(value, lpwm->regs + pwm->hwpwm * PWM_SIZE + PWM);
+}
+
static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
@@ -79,38 +106,36 @@ static int pwm_lpss_config(struct pwm_chip *chip, struct pwm_device *pwm,
duty_ns = 1;
on_time_div = 255 - (255 * duty_ns / period_ns);
- ctrl = readl(lpwm->regs + PWM);
+ pm_runtime_get_sync(chip->dev);
+
+ ctrl = pwm_lpss_read(pwm);
ctrl &= ~(PWM_BASE_UNIT_MASK | PWM_ON_TIME_DIV_MASK);
ctrl |= (u16) base_unit << PWM_BASE_UNIT_SHIFT;
ctrl |= on_time_div;
/* request PWM to update on next cycle */
ctrl |= PWM_SW_UPDATE;
- writel(ctrl, lpwm->regs + PWM);
+ pwm_lpss_write(pwm, ctrl);
+
+ pm_runtime_put(chip->dev);
return 0;
}
static int pwm_lpss_enable(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct pwm_lpss_chip *lpwm = to_lpwm(chip);
- u32 ctrl;
-
- ctrl = readl(lpwm->regs + PWM);
- writel(ctrl | PWM_ENABLE, lpwm->regs + PWM);
-
+ pm_runtime_get_sync(chip->dev);
+ pwm_lpss_write(pwm, pwm_lpss_read(pwm) | PWM_ENABLE);
return 0;
}
static void pwm_lpss_disable(struct pwm_chip *chip, struct pwm_device *pwm)
{
- struct pwm_lpss_chip *lpwm = to_lpwm(chip);
- u32 ctrl;
-
- ctrl = readl(lpwm->regs + PWM);
- writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
+ pwm_lpss_write(pwm, pwm_lpss_read(pwm) & ~PWM_ENABLE);
+ pm_runtime_put(chip->dev);
}
static const struct pwm_ops pwm_lpss_ops = {
+ .free = pwm_lpss_disable,
.config = pwm_lpss_config,
.enable = pwm_lpss_enable,
.disable = pwm_lpss_disable,
@@ -135,7 +160,7 @@ struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
lpwm->chip.dev = dev;
lpwm->chip.ops = &pwm_lpss_ops;
lpwm->chip.base = -1;
- lpwm->chip.npwm = 1;
+ lpwm->chip.npwm = info->npwm;
ret = pwmchip_add(&lpwm->chip);
if (ret) {
@@ -149,11 +174,6 @@ EXPORT_SYMBOL_GPL(pwm_lpss_probe);
int pwm_lpss_remove(struct pwm_lpss_chip *lpwm)
{
- u32 ctrl;
-
- ctrl = readl(lpwm->regs + PWM);
- writel(ctrl & ~PWM_ENABLE, lpwm->regs + PWM);
-
return pwmchip_remove(&lpwm->chip);
}
EXPORT_SYMBOL_GPL(pwm_lpss_remove);
diff --git a/drivers/pwm/pwm-lpss.h b/drivers/pwm/pwm-lpss.h
index aa041bb..e8cf337 100644
--- a/drivers/pwm/pwm-lpss.h
+++ b/drivers/pwm/pwm-lpss.h
@@ -20,10 +20,12 @@ struct pwm_lpss_chip;
struct pwm_lpss_boardinfo {
unsigned long clk_rate;
+ unsigned int npwm;
};
extern const struct pwm_lpss_boardinfo pwm_lpss_byt_info;
extern const struct pwm_lpss_boardinfo pwm_lpss_bsw_info;
+extern const struct pwm_lpss_boardinfo pwm_lpss_bxt_info;
struct pwm_lpss_chip *pwm_lpss_probe(struct device *dev, struct resource *r,
const struct pwm_lpss_boardinfo *info);
diff --git a/drivers/pwm/pwm-mtk-disp.c b/drivers/pwm/pwm-mtk-disp.c
new file mode 100644
index 0000000..0ad3385
--- /dev/null
+++ b/drivers/pwm/pwm-mtk-disp.c
@@ -0,0 +1,243 @@
+/*
+ * MediaTek display pulse-width-modulation controller driver.
+ * Copyright (c) 2015 MediaTek Inc.
+ * Author: YH Huang <yh.huang@mediatek.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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define DISP_PWM_EN 0x00
+#define PWM_ENABLE_MASK BIT(0)
+
+#define DISP_PWM_COMMIT 0x08
+#define PWM_COMMIT_MASK BIT(0)
+
+#define DISP_PWM_CON_0 0x10
+#define PWM_CLKDIV_SHIFT 16
+#define PWM_CLKDIV_MAX 0x3ff
+#define PWM_CLKDIV_MASK (PWM_CLKDIV_MAX << PWM_CLKDIV_SHIFT)
+
+#define DISP_PWM_CON_1 0x14
+#define PWM_PERIOD_BIT_WIDTH 12
+#define PWM_PERIOD_MASK ((1 << PWM_PERIOD_BIT_WIDTH) - 1)
+
+#define PWM_HIGH_WIDTH_SHIFT 16
+#define PWM_HIGH_WIDTH_MASK (0x1fff << PWM_HIGH_WIDTH_SHIFT)
+
+struct mtk_disp_pwm {
+ struct pwm_chip chip;
+ struct clk *clk_main;
+ struct clk *clk_mm;
+ void __iomem *base;
+};
+
+static inline struct mtk_disp_pwm *to_mtk_disp_pwm(struct pwm_chip *chip)
+{
+ return container_of(chip, struct mtk_disp_pwm, chip);
+}
+
+static void mtk_disp_pwm_update_bits(struct mtk_disp_pwm *mdp, u32 offset,
+ u32 mask, u32 data)
+{
+ void __iomem *address = mdp->base + offset;
+ u32 value;
+
+ value = readl(address);
+ value &= ~mask;
+ value |= data;
+ writel(value, address);
+}
+
+static int mtk_disp_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
+ u32 clk_div, period, high_width, value;
+ u64 div, rate;
+ int err;
+
+ /*
+ * Find period, high_width and clk_div to suit duty_ns and period_ns.
+ * Calculate proper div value to keep period value in the bound.
+ *
+ * period_ns = 10^9 * (clk_div + 1) * (period + 1) / PWM_CLK_RATE
+ * duty_ns = 10^9 * (clk_div + 1) * high_width / PWM_CLK_RATE
+ *
+ * period = (PWM_CLK_RATE * period_ns) / (10^9 * (clk_div + 1)) - 1
+ * high_width = (PWM_CLK_RATE * duty_ns) / (10^9 * (clk_div + 1))
+ */
+ rate = clk_get_rate(mdp->clk_main);
+ clk_div = div_u64(rate * period_ns, NSEC_PER_SEC) >>
+ PWM_PERIOD_BIT_WIDTH;
+ if (clk_div > PWM_CLKDIV_MAX)
+ return -EINVAL;
+
+ div = NSEC_PER_SEC * (clk_div + 1);
+ period = div64_u64(rate * period_ns, div);
+ if (period > 0)
+ period--;
+
+ high_width = div64_u64(rate * duty_ns, div);
+ value = period | (high_width << PWM_HIGH_WIDTH_SHIFT);
+
+ err = clk_enable(mdp->clk_main);
+ if (err < 0)
+ return err;
+
+ err = clk_enable(mdp->clk_mm);
+ if (err < 0) {
+ clk_disable(mdp->clk_main);
+ return err;
+ }
+
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_0, PWM_CLKDIV_MASK,
+ clk_div << PWM_CLKDIV_SHIFT);
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_CON_1,
+ PWM_PERIOD_MASK | PWM_HIGH_WIDTH_MASK, value);
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 1);
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_COMMIT, PWM_COMMIT_MASK, 0);
+
+ clk_disable(mdp->clk_mm);
+ clk_disable(mdp->clk_main);
+
+ return 0;
+}
+
+static int mtk_disp_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
+ int err;
+
+ err = clk_enable(mdp->clk_main);
+ if (err < 0)
+ return err;
+
+ err = clk_enable(mdp->clk_mm);
+ if (err < 0) {
+ clk_disable(mdp->clk_main);
+ return err;
+ }
+
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 1);
+
+ return 0;
+}
+
+static void mtk_disp_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct mtk_disp_pwm *mdp = to_mtk_disp_pwm(chip);
+
+ mtk_disp_pwm_update_bits(mdp, DISP_PWM_EN, PWM_ENABLE_MASK, 0);
+
+ clk_disable(mdp->clk_mm);
+ clk_disable(mdp->clk_main);
+}
+
+static const struct pwm_ops mtk_disp_pwm_ops = {
+ .config = mtk_disp_pwm_config,
+ .enable = mtk_disp_pwm_enable,
+ .disable = mtk_disp_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int mtk_disp_pwm_probe(struct platform_device *pdev)
+{
+ struct mtk_disp_pwm *mdp;
+ struct resource *r;
+ int ret;
+
+ mdp = devm_kzalloc(&pdev->dev, sizeof(*mdp), GFP_KERNEL);
+ if (!mdp)
+ return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mdp->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(mdp->base))
+ return PTR_ERR(mdp->base);
+
+ mdp->clk_main = devm_clk_get(&pdev->dev, "main");
+ if (IS_ERR(mdp->clk_main))
+ return PTR_ERR(mdp->clk_main);
+
+ mdp->clk_mm = devm_clk_get(&pdev->dev, "mm");
+ if (IS_ERR(mdp->clk_mm))
+ return PTR_ERR(mdp->clk_mm);
+
+ ret = clk_prepare(mdp->clk_main);
+ if (ret < 0)
+ return ret;
+
+ ret = clk_prepare(mdp->clk_mm);
+ if (ret < 0)
+ goto disable_clk_main;
+
+ mdp->chip.dev = &pdev->dev;
+ mdp->chip.ops = &mtk_disp_pwm_ops;
+ mdp->chip.base = -1;
+ mdp->chip.npwm = 1;
+
+ ret = pwmchip_add(&mdp->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pwmchip_add() failed: %d\n", ret);
+ goto disable_clk_mm;
+ }
+
+ platform_set_drvdata(pdev, mdp);
+
+ return 0;
+
+disable_clk_mm:
+ clk_unprepare(mdp->clk_mm);
+disable_clk_main:
+ clk_unprepare(mdp->clk_main);
+ return ret;
+}
+
+static int mtk_disp_pwm_remove(struct platform_device *pdev)
+{
+ struct mtk_disp_pwm *mdp = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = pwmchip_remove(&mdp->chip);
+ clk_unprepare(mdp->clk_mm);
+ clk_unprepare(mdp->clk_main);
+
+ return ret;
+}
+
+static const struct of_device_id mtk_disp_pwm_of_match[] = {
+ { .compatible = "mediatek,mt8173-disp-pwm" },
+ { .compatible = "mediatek,mt6595-disp-pwm" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_pwm_of_match);
+
+static struct platform_driver mtk_disp_pwm_driver = {
+ .driver = {
+ .name = "mediatek-disp-pwm",
+ .of_match_table = mtk_disp_pwm_of_match,
+ },
+ .probe = mtk_disp_pwm_probe,
+ .remove = mtk_disp_pwm_remove,
+};
+module_platform_driver(mtk_disp_pwm_driver);
+
+MODULE_AUTHOR("YH Huang <yh.huang@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek SoC display PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-pca9685.c b/drivers/pwm/pwm-pca9685.c
index 70448a6..117fccf 100644
--- a/drivers/pwm/pwm-pca9685.c
+++ b/drivers/pwm/pwm-pca9685.c
@@ -19,9 +19,11 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -297,7 +299,6 @@ static const struct regmap_config pca9685_regmap_i2c_config = {
static int pca9685_pwm_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct device_node *np = client->dev.of_node;
struct pca9685 *pca;
int ret;
int mode2;
@@ -320,12 +321,12 @@ static int pca9685_pwm_probe(struct i2c_client *client,
regmap_read(pca->regmap, PCA9685_MODE2, &mode2);
- if (of_property_read_bool(np, "invert"))
+ if (device_property_read_bool(&client->dev, "invert"))
mode2 |= MODE2_INVRT;
else
mode2 &= ~MODE2_INVRT;
- if (of_property_read_bool(np, "open-drain"))
+ if (device_property_read_bool(&client->dev, "open-drain"))
mode2 &= ~MODE2_OUTDRV;
else
mode2 |= MODE2_OUTDRV;
@@ -363,16 +364,27 @@ static const struct i2c_device_id pca9685_id[] = {
};
MODULE_DEVICE_TABLE(i2c, pca9685_id);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id pca9685_acpi_ids[] = {
+ { "INT3492", 0 },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(acpi, pca9685_acpi_ids);
+#endif
+
+#ifdef CONFIG_OF
static const struct of_device_id pca9685_dt_ids[] = {
{ .compatible = "nxp,pca9685-pwm", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, pca9685_dt_ids);
+#endif
static struct i2c_driver pca9685_i2c_driver = {
.driver = {
.name = "pca9685-pwm",
- .of_match_table = pca9685_dt_ids,
+ .acpi_match_table = ACPI_PTR(pca9685_acpi_ids),
+ .of_match_table = of_match_ptr(pca9685_dt_ids),
},
.probe = pca9685_pwm_probe,
.remove = pca9685_pwm_remove,
diff --git a/drivers/pwm/pwm-rcar.c b/drivers/pwm/pwm-rcar.c
new file mode 100644
index 0000000..6e99a63
--- /dev/null
+++ b/drivers/pwm/pwm-rcar.c
@@ -0,0 +1,274 @@
+/*
+ * R-Car PWM Timer driver
+ *
+ * Copyright (C) 2015 Renesas Electronics Corporation
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+#define RCAR_PWM_MAX_DIVISION 24
+#define RCAR_PWM_MAX_CYCLE 1023
+
+#define RCAR_PWMCR 0x00
+#define RCAR_PWMCR_CC0_MASK 0x000f0000
+#define RCAR_PWMCR_CC0_SHIFT 16
+#define RCAR_PWMCR_CCMD BIT(15)
+#define RCAR_PWMCR_SYNC BIT(11)
+#define RCAR_PWMCR_SS0 BIT(4)
+#define RCAR_PWMCR_EN0 BIT(0)
+
+#define RCAR_PWMCNT 0x04
+#define RCAR_PWMCNT_CYC0_MASK 0x03ff0000
+#define RCAR_PWMCNT_CYC0_SHIFT 16
+#define RCAR_PWMCNT_PH0_MASK 0x000003ff
+#define RCAR_PWMCNT_PH0_SHIFT 0
+
+struct rcar_pwm_chip {
+ struct pwm_chip chip;
+ void __iomem *base;
+ struct clk *clk;
+};
+
+static inline struct rcar_pwm_chip *to_rcar_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct rcar_pwm_chip, chip);
+}
+
+static void rcar_pwm_write(struct rcar_pwm_chip *rp, u32 data,
+ unsigned int offset)
+{
+ writel(data, rp->base + offset);
+}
+
+static u32 rcar_pwm_read(struct rcar_pwm_chip *rp, unsigned int offset)
+{
+ return readl(rp->base + offset);
+}
+
+static void rcar_pwm_update(struct rcar_pwm_chip *rp, u32 mask, u32 data,
+ unsigned int offset)
+{
+ u32 value;
+
+ value = rcar_pwm_read(rp, offset);
+ value &= ~mask;
+ value |= data & mask;
+ rcar_pwm_write(rp, value, offset);
+}
+
+static int rcar_pwm_get_clock_division(struct rcar_pwm_chip *rp, int period_ns)
+{
+ unsigned long clk_rate = clk_get_rate(rp->clk);
+ unsigned long long max; /* max cycle / nanoseconds */
+ unsigned int div;
+
+ if (clk_rate == 0)
+ return -EINVAL;
+
+ for (div = 0; div <= RCAR_PWM_MAX_DIVISION; div++) {
+ max = (unsigned long long)NSEC_PER_SEC * RCAR_PWM_MAX_CYCLE *
+ (1 << div);
+ do_div(max, clk_rate);
+ if (period_ns < max)
+ break;
+ }
+
+ return (div <= RCAR_PWM_MAX_DIVISION) ? div : -ERANGE;
+}
+
+static void rcar_pwm_set_clock_control(struct rcar_pwm_chip *rp,
+ unsigned int div)
+{
+ u32 value;
+
+ value = rcar_pwm_read(rp, RCAR_PWMCR);
+ value &= ~(RCAR_PWMCR_CCMD | RCAR_PWMCR_CC0_MASK);
+
+ if (div & 1)
+ value |= RCAR_PWMCR_CCMD;
+
+ div >>= 1;
+
+ value |= div << RCAR_PWMCR_CC0_SHIFT;
+ rcar_pwm_write(rp, value, RCAR_PWMCR);
+}
+
+static int rcar_pwm_set_counter(struct rcar_pwm_chip *rp, int div, int duty_ns,
+ int period_ns)
+{
+ unsigned long long one_cycle, tmp; /* 0.01 nanoseconds */
+ unsigned long clk_rate = clk_get_rate(rp->clk);
+ u32 cyc, ph;
+
+ one_cycle = (unsigned long long)NSEC_PER_SEC * 100ULL * (1 << div);
+ do_div(one_cycle, clk_rate);
+
+ tmp = period_ns * 100ULL;
+ do_div(tmp, one_cycle);
+ cyc = (tmp << RCAR_PWMCNT_CYC0_SHIFT) & RCAR_PWMCNT_CYC0_MASK;
+
+ tmp = duty_ns * 100ULL;
+ do_div(tmp, one_cycle);
+ ph = tmp & RCAR_PWMCNT_PH0_MASK;
+
+ /* Avoid prohibited setting */
+ if (cyc == 0 || ph == 0)
+ return -EINVAL;
+
+ rcar_pwm_write(rp, cyc | ph, RCAR_PWMCNT);
+
+ return 0;
+}
+
+static int rcar_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+
+ return clk_prepare_enable(rp->clk);
+}
+
+static void rcar_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+
+ clk_disable_unprepare(rp->clk);
+}
+
+static int rcar_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+ int div, ret;
+
+ div = rcar_pwm_get_clock_division(rp, period_ns);
+ if (div < 0)
+ return div;
+
+ /* Let the core driver set pwm->period if disabled and duty_ns == 0 */
+ if (!test_bit(PWMF_ENABLED, &pwm->flags) && !duty_ns)
+ return 0;
+
+ rcar_pwm_update(rp, RCAR_PWMCR_SYNC, RCAR_PWMCR_SYNC, RCAR_PWMCR);
+
+ ret = rcar_pwm_set_counter(rp, div, duty_ns, period_ns);
+ if (!ret)
+ rcar_pwm_set_clock_control(rp, div);
+
+ /* The SYNC should be set to 0 even if rcar_pwm_set_counter failed */
+ rcar_pwm_update(rp, RCAR_PWMCR_SYNC, 0, RCAR_PWMCR);
+
+ return ret;
+}
+
+static int rcar_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+ u32 value;
+
+ /* Don't enable the PWM device if CYC0 or PH0 is 0 */
+ value = rcar_pwm_read(rp, RCAR_PWMCNT);
+ if ((value & RCAR_PWMCNT_CYC0_MASK) == 0 ||
+ (value & RCAR_PWMCNT_PH0_MASK) == 0)
+ return -EINVAL;
+
+ rcar_pwm_update(rp, RCAR_PWMCR_EN0, RCAR_PWMCR_EN0, RCAR_PWMCR);
+
+ return 0;
+}
+
+static void rcar_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct rcar_pwm_chip *rp = to_rcar_pwm_chip(chip);
+
+ rcar_pwm_update(rp, RCAR_PWMCR_EN0, 0, RCAR_PWMCR);
+}
+
+static const struct pwm_ops rcar_pwm_ops = {
+ .request = rcar_pwm_request,
+ .free = rcar_pwm_free,
+ .config = rcar_pwm_config,
+ .enable = rcar_pwm_enable,
+ .disable = rcar_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int rcar_pwm_probe(struct platform_device *pdev)
+{
+ struct rcar_pwm_chip *rcar_pwm;
+ struct resource *res;
+ int ret;
+
+ rcar_pwm = devm_kzalloc(&pdev->dev, sizeof(*rcar_pwm), GFP_KERNEL);
+ if (rcar_pwm == NULL)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rcar_pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rcar_pwm->base))
+ return PTR_ERR(rcar_pwm->base);
+
+ rcar_pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rcar_pwm->clk)) {
+ dev_err(&pdev->dev, "cannot get clock\n");
+ return PTR_ERR(rcar_pwm->clk);
+ }
+
+ platform_set_drvdata(pdev, rcar_pwm);
+
+ rcar_pwm->chip.dev = &pdev->dev;
+ rcar_pwm->chip.ops = &rcar_pwm_ops;
+ rcar_pwm->chip.base = -1;
+ rcar_pwm->chip.npwm = 1;
+
+ ret = pwmchip_add(&rcar_pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register PWM chip: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+}
+
+static int rcar_pwm_remove(struct platform_device *pdev)
+{
+ struct rcar_pwm_chip *rcar_pwm = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return pwmchip_remove(&rcar_pwm->chip);
+}
+
+static const struct of_device_id rcar_pwm_of_table[] = {
+ { .compatible = "renesas,pwm-rcar", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rcar_pwm_of_table);
+
+static struct platform_driver rcar_pwm_driver = {
+ .probe = rcar_pwm_probe,
+ .remove = rcar_pwm_remove,
+ .driver = {
+ .name = "pwm-rcar",
+ .of_match_table = of_match_ptr(rcar_pwm_of_table),
+ }
+};
+module_platform_driver(rcar_pwm_driver);
+
+MODULE_AUTHOR("Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>");
+MODULE_DESCRIPTION("Renesas PWM Timer Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:pwm-rcar");
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
index cd9dde5..67af9f6 100644
--- a/drivers/pwm/pwm-sun4i.c
+++ b/drivers/pwm/pwm-sun4i.c
@@ -68,6 +68,7 @@ static const u32 prescaler_table[] = {
struct sun4i_pwm_data {
bool has_prescaler_bypass;
bool has_rdy;
+ unsigned int npwm;
};
struct sun4i_pwm_chip {
@@ -114,7 +115,7 @@ static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* is not an integer so round it half up instead of
* truncating to get less surprising values.
*/
- div = clk_rate * period_ns + NSEC_PER_SEC/2;
+ div = clk_rate * period_ns + NSEC_PER_SEC / 2;
do_div(div, NSEC_PER_SEC);
if (div - 1 > PWM_PRD_MASK)
prescaler = 0;
@@ -262,11 +263,25 @@ static const struct pwm_ops sun4i_pwm_ops = {
static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
.has_prescaler_bypass = false,
.has_rdy = false,
+ .npwm = 2,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a10s = {
+ .has_prescaler_bypass = true,
+ .has_rdy = true,
+ .npwm = 2,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a13 = {
+ .has_prescaler_bypass = true,
+ .has_rdy = true,
+ .npwm = 1,
};
static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
.has_prescaler_bypass = true,
.has_rdy = true,
+ .npwm = 2,
};
static const struct of_device_id sun4i_pwm_dt_ids[] = {
@@ -274,6 +289,12 @@ static const struct of_device_id sun4i_pwm_dt_ids[] = {
.compatible = "allwinner,sun4i-a10-pwm",
.data = &sun4i_pwm_data_a10,
}, {
+ .compatible = "allwinner,sun5i-a10s-pwm",
+ .data = &sun4i_pwm_data_a10s,
+ }, {
+ .compatible = "allwinner,sun5i-a13-pwm",
+ .data = &sun4i_pwm_data_a13,
+ }, {
.compatible = "allwinner,sun7i-a20-pwm",
.data = &sun4i_pwm_data_a20,
}, {
@@ -305,14 +326,14 @@ static int sun4i_pwm_probe(struct platform_device *pdev)
if (IS_ERR(pwm->clk))
return PTR_ERR(pwm->clk);
+ pwm->data = match->data;
pwm->chip.dev = &pdev->dev;
pwm->chip.ops = &sun4i_pwm_ops;
pwm->chip.base = -1;
- pwm->chip.npwm = 2;
+ pwm->chip.npwm = pwm->data->npwm;
pwm->chip.can_sleep = true;
pwm->chip.of_xlate = of_pwm_xlate_with_flags;
pwm->chip.of_pwm_n_cells = 3;
- pwm->data = match->data;
spin_lock_init(&pwm->ctrl_lock);
diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c
index c472772..9c90886 100644
--- a/drivers/pwm/sysfs.c
+++ b/drivers/pwm/sysfs.c
@@ -40,18 +40,18 @@ static struct pwm_device *child_to_pwm_device(struct device *child)
return export->pwm;
}
-static ssize_t pwm_period_show(struct device *child,
- struct device_attribute *attr,
- char *buf)
+static ssize_t period_show(struct device *child,
+ struct device_attribute *attr,
+ char *buf)
{
const struct pwm_device *pwm = child_to_pwm_device(child);
return sprintf(buf, "%u\n", pwm_get_period(pwm));
}
-static ssize_t pwm_period_store(struct device *child,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t period_store(struct device *child,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
struct pwm_device *pwm = child_to_pwm_device(child);
unsigned int val;
@@ -66,18 +66,18 @@ static ssize_t pwm_period_store(struct device *child,
return ret ? : size;
}
-static ssize_t pwm_duty_cycle_show(struct device *child,
- struct device_attribute *attr,
- char *buf)
+static ssize_t duty_cycle_show(struct device *child,
+ struct device_attribute *attr,
+ char *buf)
{
const struct pwm_device *pwm = child_to_pwm_device(child);
return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm));
}
-static ssize_t pwm_duty_cycle_store(struct device *child,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t duty_cycle_store(struct device *child,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
struct pwm_device *pwm = child_to_pwm_device(child);
unsigned int val;
@@ -92,19 +92,18 @@ static ssize_t pwm_duty_cycle_store(struct device *child,
return ret ? : size;
}
-static ssize_t pwm_enable_show(struct device *child,
- struct device_attribute *attr,
- char *buf)
+static ssize_t enable_show(struct device *child,
+ struct device_attribute *attr,
+ char *buf)
{
const struct pwm_device *pwm = child_to_pwm_device(child);
- int enabled = pwm_is_enabled(pwm);
- return sprintf(buf, "%d\n", enabled);
+ return sprintf(buf, "%d\n", pwm_is_enabled(pwm));
}
-static ssize_t pwm_enable_store(struct device *child,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t enable_store(struct device *child,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
struct pwm_device *pwm = child_to_pwm_device(child);
int val, ret;
@@ -128,9 +127,9 @@ static ssize_t pwm_enable_store(struct device *child,
return ret ? : size;
}
-static ssize_t pwm_polarity_show(struct device *child,
- struct device_attribute *attr,
- char *buf)
+static ssize_t polarity_show(struct device *child,
+ struct device_attribute *attr,
+ char *buf)
{
const struct pwm_device *pwm = child_to_pwm_device(child);
const char *polarity = "unknown";
@@ -148,9 +147,9 @@ static ssize_t pwm_polarity_show(struct device *child,
return sprintf(buf, "%s\n", polarity);
}
-static ssize_t pwm_polarity_store(struct device *child,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t polarity_store(struct device *child,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
struct pwm_device *pwm = child_to_pwm_device(child);
enum pwm_polarity polarity;
@@ -168,10 +167,10 @@ static ssize_t pwm_polarity_store(struct device *child,
return ret ? : size;
}
-static DEVICE_ATTR(period, 0644, pwm_period_show, pwm_period_store);
-static DEVICE_ATTR(duty_cycle, 0644, pwm_duty_cycle_show, pwm_duty_cycle_store);
-static DEVICE_ATTR(enable, 0644, pwm_enable_show, pwm_enable_store);
-static DEVICE_ATTR(polarity, 0644, pwm_polarity_show, pwm_polarity_store);
+static DEVICE_ATTR_RW(period);
+static DEVICE_ATTR_RW(duty_cycle);
+static DEVICE_ATTR_RW(enable);
+static DEVICE_ATTR_RW(polarity);
static struct attribute *pwm_attrs[] = {
&dev_attr_period.attr,
@@ -245,9 +244,9 @@ static int pwm_unexport_child(struct device *parent, struct pwm_device *pwm)
return 0;
}
-static ssize_t pwm_export_store(struct device *parent,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t export_store(struct device *parent,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct pwm_chip *chip = dev_get_drvdata(parent);
struct pwm_device *pwm;
@@ -271,11 +270,11 @@ static ssize_t pwm_export_store(struct device *parent,
return ret ? : len;
}
-static DEVICE_ATTR(export, 0200, NULL, pwm_export_store);
+static DEVICE_ATTR_WO(export);
-static ssize_t pwm_unexport_store(struct device *parent,
- struct device_attribute *attr,
- const char *buf, size_t len)
+static ssize_t unexport_store(struct device *parent,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct pwm_chip *chip = dev_get_drvdata(parent);
unsigned int hwpwm;
@@ -292,7 +291,7 @@ static ssize_t pwm_unexport_store(struct device *parent,
return ret ? : len;
}
-static DEVICE_ATTR(unexport, 0200, NULL, pwm_unexport_store);
+static DEVICE_ATTR_WO(unexport);
static ssize_t npwm_show(struct device *parent, struct device_attribute *attr,
char *buf)
diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c
index 8b3130f..9e03d15 100644
--- a/drivers/remoteproc/remoteproc_core.c
+++ b/drivers/remoteproc/remoteproc_core.c
@@ -1478,6 +1478,8 @@ module_init(remoteproc_init);
static void __exit remoteproc_exit(void)
{
+ ida_destroy(&rproc_dev_index);
+
rproc_exit_debugfs();
}
module_exit(remoteproc_exit);
diff --git a/drivers/remoteproc/remoteproc_debugfs.c b/drivers/remoteproc/remoteproc_debugfs.c
index 9d30809..916af50 100644
--- a/drivers/remoteproc/remoteproc_debugfs.c
+++ b/drivers/remoteproc/remoteproc_debugfs.c
@@ -156,7 +156,7 @@ rproc_recovery_write(struct file *filp, const char __user *user_buf,
char buf[10];
int ret;
- if (count > sizeof(buf))
+ if (count < 1 || count > sizeof(buf))
return count;
ret = copy_from_user(buf, user_buf, count);
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index 284b587..d6c853b 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -483,24 +483,23 @@ static int da9063_rtc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, rtc);
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
+ &da9063_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ da9063_data_to_tm(data, &rtc->alarm_time, rtc);
+ rtc->rtc_sync = false;
+
irq_alarm = platform_get_irq_byname(pdev, "ALARM");
ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
da9063_alarm_event,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"ALARM", rtc);
- if (ret) {
+ if (ret)
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret);
- return ret;
- }
-
- rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
- &da9063_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtc_dev))
- return PTR_ERR(rtc->rtc_dev);
- da9063_data_to_tm(data, &rtc->alarm_time, rtc);
- rtc->rtc_sync = false;
return ret;
}
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 188006c..aa705bb 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -15,9 +15,6 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/of_device.h>
-#include <linux/of_irq.h>
-#include <linux/pm_wakeirq.h>
#include <linux/rtc/ds1307.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -117,7 +114,6 @@ struct ds1307 {
#define HAS_ALARM 1 /* bit 1 == irq claimed */
struct i2c_client *client;
struct rtc_device *rtc;
- int wakeirq;
s32 (*read_block_data)(const struct i2c_client *client, u8 command,
u8 length, u8 *values);
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
@@ -1138,7 +1134,10 @@ read_rtc:
bin2bcd(tmp));
}
- device_set_wakeup_capable(&client->dev, want_irq);
+ if (want_irq) {
+ device_set_wakeup_capable(&client->dev, true);
+ set_bit(HAS_ALARM, &ds1307->flags);
+ }
ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
rtc_ops, THIS_MODULE);
if (IS_ERR(ds1307->rtc)) {
@@ -1146,43 +1145,19 @@ read_rtc:
}
if (want_irq) {
- struct device_node *node = client->dev.of_node;
-
err = devm_request_threaded_irq(&client->dev,
client->irq, NULL, irq_handler,
IRQF_SHARED | IRQF_ONESHOT,
ds1307->rtc->name, client);
if (err) {
client->irq = 0;
+ device_set_wakeup_capable(&client->dev, false);
+ clear_bit(HAS_ALARM, &ds1307->flags);
dev_err(&client->dev, "unable to request IRQ!\n");
- goto no_irq;
- }
-
- set_bit(HAS_ALARM, &ds1307->flags);
- dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
-
- /* Currently supported by OF code only! */
- if (!node)
- goto no_irq;
-
- err = of_irq_get(node, 1);
- if (err <= 0) {
- if (err == -EPROBE_DEFER)
- goto exit;
- goto no_irq;
- }
- ds1307->wakeirq = err;
-
- err = dev_pm_set_dedicated_wake_irq(&client->dev,
- ds1307->wakeirq);
- if (err) {
- dev_err(&client->dev, "unable to setup wakeIRQ %d!\n",
- err);
- goto exit;
- }
+ } else
+ dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
}
-no_irq:
if (chip->nvram_size) {
ds1307->nvram = devm_kzalloc(&client->dev,
@@ -1226,9 +1201,6 @@ static int ds1307_remove(struct i2c_client *client)
{
struct ds1307 *ds1307 = i2c_get_clientdata(client);
- if (ds1307->wakeirq)
- dev_pm_clear_wake_irq(&client->dev);
-
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
index 91ca0bc..35c9aad 100644
--- a/drivers/rtc/rtc-rk808.c
+++ b/drivers/rtc/rtc-rk808.c
@@ -56,6 +56,42 @@ struct rk808_rtc {
int irq;
};
+/*
+ * The Rockchip calendar used by the RK808 counts November with 31 days. We use
+ * these translation functions to convert its dates to/from the Gregorian
+ * calendar used by the rest of the world. We arbitrarily define Jan 1st, 2016
+ * as the day when both calendars were in sync, and treat all other dates
+ * relative to that.
+ * NOTE: Other system software (e.g. firmware) that reads the same hardware must
+ * implement this exact same conversion algorithm, with the same anchor date.
+ */
+static time64_t nov2dec_transitions(struct rtc_time *tm)
+{
+ return (tm->tm_year + 1900) - 2016 + (tm->tm_mon + 1 > 11 ? 1 : 0);
+}
+
+static void rockchip_to_gregorian(struct rtc_time *tm)
+{
+ /* If it's Nov 31st, rtc_tm_to_time64() will count that like Dec 1st */
+ time64_t time = rtc_tm_to_time64(tm);
+ rtc_time64_to_tm(time + nov2dec_transitions(tm) * 86400, tm);
+}
+
+static void gregorian_to_rockchip(struct rtc_time *tm)
+{
+ time64_t extra_days = nov2dec_transitions(tm);
+ time64_t time = rtc_tm_to_time64(tm);
+ rtc_time64_to_tm(time - extra_days * 86400, tm);
+
+ /* Compensate if we went back over Nov 31st (will work up to 2381) */
+ if (nov2dec_transitions(tm) < extra_days) {
+ if (tm->tm_mon + 1 == 11)
+ tm->tm_mday++; /* This may result in 31! */
+ else
+ rtc_time64_to_tm(time - (extra_days - 1) * 86400, tm);
+ }
+}
+
/* Read current time and date in RTC */
static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
{
@@ -101,9 +137,10 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
tm->tm_mon = (bcd2bin(rtc_data[4] & MONTHS_REG_MSK)) - 1;
tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100;
tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK);
+ rockchip_to_gregorian(tm);
dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
return ret;
}
@@ -116,6 +153,10 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 rtc_data[NUM_TIME_REGS];
int ret;
+ dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+ gregorian_to_rockchip(tm);
rtc_data[0] = bin2bcd(tm->tm_sec);
rtc_data[1] = bin2bcd(tm->tm_min);
rtc_data[2] = bin2bcd(tm->tm_hour);
@@ -123,9 +164,6 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm)
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
rtc_data[5] = bin2bcd(tm->tm_year - 100);
rtc_data[6] = bin2bcd(tm->tm_wday);
- dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
- 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_wday, tm->tm_hour , tm->tm_min, tm->tm_sec);
/* Stop RTC while updating the RTC registers */
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
@@ -170,6 +208,7 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_mday = bcd2bin(alrm_data[3] & DAYS_REG_MSK);
alrm->time.tm_mon = (bcd2bin(alrm_data[4] & MONTHS_REG_MSK)) - 1;
alrm->time.tm_year = (bcd2bin(alrm_data[5] & YEARS_REG_MSK)) + 100;
+ rockchip_to_gregorian(&alrm->time);
ret = regmap_read(rk808->regmap, RK808_RTC_INT_REG, &int_reg);
if (ret) {
@@ -227,6 +266,7 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
alrm->time.tm_min, alrm->time.tm_sec);
+ gregorian_to_rockchip(&alrm->time);
alrm_data[0] = bin2bcd(alrm->time.tm_sec);
alrm_data[1] = bin2bcd(alrm->time.tm_min);
alrm_data[2] = bin2bcd(alrm->time.tm_hour);
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 5ed44fe..94a8f4a 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -27,7 +27,8 @@
static int dcssblk_open(struct block_device *bdev, fmode_t mode);
static void dcssblk_release(struct gendisk *disk, fmode_t mode);
-static void dcssblk_make_request(struct request_queue *q, struct bio *bio);
+static blk_qc_t dcssblk_make_request(struct request_queue *q,
+ struct bio *bio);
static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
void __pmem **kaddr, unsigned long *pfn);
@@ -815,7 +816,7 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
up_write(&dcssblk_devices_sem);
}
-static void
+static blk_qc_t
dcssblk_make_request(struct request_queue *q, struct bio *bio)
{
struct dcssblk_dev_info *dev_info;
@@ -874,9 +875,10 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
bytes_done += bvec.bv_len;
}
bio_endio(bio);
- return;
+ return BLK_QC_T_NONE;
fail:
bio_io_error(bio);
+ return BLK_QC_T_NONE;
}
static long
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 02871f1..288f59a 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -181,7 +181,7 @@ static unsigned long xpram_highest_page_index(void)
/*
* Block device make request function.
*/
-static void xpram_make_request(struct request_queue *q, struct bio *bio)
+static blk_qc_t xpram_make_request(struct request_queue *q, struct bio *bio)
{
xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
struct bio_vec bvec;
@@ -223,9 +223,10 @@ static void xpram_make_request(struct request_queue *q, struct bio *bio)
}
}
bio_endio(bio);
- return;
+ return BLK_QC_T_NONE;
fail:
bio_io_error(bio);
+ return BLK_QC_T_NONE;
}
static int xpram_getgeo(struct block_device *bdev, struct hd_geometry *geo)
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 7bc6df3..6804354 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -40,10 +40,14 @@ struct read_info_sccb {
u8 fac85; /* 85 */
u8 _pad_86[91 - 86]; /* 86-90 */
u8 flags; /* 91 */
- u8 _pad_92[100 - 92]; /* 92-99 */
+ u8 _pad_92[99 - 92]; /* 92-98 */
+ u8 hamaxpow; /* 99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
- u8 _pad_112[120 - 112]; /* 112-119 */
+ u8 _pad_112[116 - 112]; /* 112-115 */
+ u8 fac116; /* 116 */
+ u8 _pad_117[119 - 117]; /* 117-118 */
+ u8 fac119; /* 119 */
u16 hcpua; /* 120-121 */
u8 _pad_122[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE);
@@ -108,6 +112,8 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp.facilities = sccb->facilities;
sclp.has_sprp = !!(sccb->fac84 & 0x02);
sclp.has_core_type = !!(sccb->fac84 & 0x01);
+ sclp.has_esca = !!(sccb->fac116 & 0x08);
+ sclp.has_hvs = !!(sccb->fac119 & 0x80);
if (sccb->fac85 & 0x02)
S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP;
sclp.rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
@@ -115,6 +121,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp.rzm <<= 20;
sclp.ibc = sccb->ibc;
+ if (sccb->hamaxpow && sccb->hamaxpow < 64)
+ sclp.hamax = (1UL << sccb->hamaxpow) - 1;
+ else
+ sclp.hamax = U64_MAX;
+
if (!sccb->hcpua) {
if (MACHINE_IS_VM)
sclp.max_cores = 64;
@@ -131,6 +142,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
continue;
sclp.has_siif = cpue->siif;
sclp.has_sigpif = cpue->sigpif;
+ sclp.has_sief2 = cpue->sief2;
break;
}
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
index 0fdedad..2a67b49 100644
--- a/drivers/s390/char/vmcp.c
+++ b/drivers/s390/char/vmcp.c
@@ -88,14 +88,9 @@ vmcp_write(struct file *file, const char __user *buff, size_t count,
if (count > 240)
return -EINVAL;
- cmd = kmalloc(count + 1, GFP_KERNEL);
- if (!cmd)
- return -ENOMEM;
- if (copy_from_user(cmd, buff, count)) {
- kfree(cmd);
- return -EFAULT;
- }
- cmd[count] = '\0';
+ cmd = memdup_user_nul(buff, count);
+ if (IS_ERR(cmd))
+ return PTR_ERR(cmd);
session = file->private_data;
if (mutex_lock_interruptible(&session->mutex)) {
kfree(cmd);
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c
index 0efb27f..6c30e93a 100644
--- a/drivers/s390/char/vmur.c
+++ b/drivers/s390/char/vmur.c
@@ -782,24 +782,11 @@ static int ur_release(struct inode *inode, struct file *file)
static loff_t ur_llseek(struct file *file, loff_t offset, int whence)
{
- loff_t newpos;
-
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
return -ESPIPE; /* seek allowed only for reader */
if (offset % PAGE_SIZE)
return -ESPIPE; /* only multiples of 4K allowed */
- switch (whence) {
- case 0: /* SEEK_SET */
- newpos = offset;
- break;
- case 1: /* SEEK_CUR */
- newpos = file->f_pos + offset;
- break;
- default:
- return -EINVAL;
- }
- file->f_pos = newpos;
- return newpos;
+ return no_seek_end_llseek(file, offset, whence);
}
static const struct file_operations ur_fops = {
diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c
index 823f41f..3339b86 100644
--- a/drivers/s390/char/zcore.c
+++ b/drivers/s390/char/zcore.c
@@ -385,18 +385,7 @@ static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
loff_t rc;
mutex_lock(&zcore_mutex);
- switch (orig) {
- case 0:
- file->f_pos = offset;
- rc = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- rc = file->f_pos;
- break;
- default:
- rc = -EINVAL;
- }
+ rc = no_seek_end_llseek(file, offset, orig);
mutex_unlock(&zcore_mutex);
return rc;
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 548a189..a831d18 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -1080,28 +1080,10 @@ void __init chsc_init_cleanup(void)
free_page((unsigned long)sei_page);
}
-int chsc_enable_facility(int operation_code)
+int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code)
{
- unsigned long flags;
int ret;
- struct {
- struct chsc_header request;
- u8 reserved1:4;
- u8 format:4;
- u8 reserved2;
- u16 operation_code;
- u32 reserved3;
- u32 reserved4;
- u32 operation_data_area[252];
- struct chsc_header response;
- u32 reserved5:4;
- u32 format2:4;
- u32 reserved6:24;
- } __attribute__ ((packed)) *sda_area;
- spin_lock_irqsave(&chsc_page_lock, flags);
- memset(chsc_page, 0, PAGE_SIZE);
- sda_area = chsc_page;
sda_area->request.length = 0x0400;
sda_area->request.code = 0x0031;
sda_area->operation_code = operation_code;
@@ -1119,10 +1101,25 @@ int chsc_enable_facility(int operation_code)
default:
ret = chsc_error_from_response(sda_area->response.code);
}
+out:
+ return ret;
+}
+
+int chsc_enable_facility(int operation_code)
+{
+ struct chsc_sda_area *sda_area;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&chsc_page_lock, flags);
+ memset(chsc_page, 0, PAGE_SIZE);
+ sda_area = chsc_page;
+
+ ret = __chsc_enable_facility(sda_area, operation_code);
if (ret != 0)
CIO_CRW_EVENT(2, "chsc: sda (oc=%x) failed (rc=%04x)\n",
operation_code, sda_area->response.code);
-out:
+
spin_unlock_irqrestore(&chsc_page_lock, flags);
return ret;
}
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 76c9b50..0de134c 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -115,6 +115,20 @@ struct chsc_scpd {
u8 data[PAGE_SIZE - 20];
} __attribute__ ((packed));
+struct chsc_sda_area {
+ struct chsc_header request;
+ u8 :4;
+ u8 format:4;
+ u8 :8;
+ u16 operation_code;
+ u32 :32;
+ u32 :32;
+ u32 operation_data_area[252];
+ struct chsc_header response;
+ u32 :4;
+ u32 format2:4;
+ u32 :24;
+} __packed __aligned(PAGE_SIZE);
extern int chsc_get_ssd_info(struct subchannel_id schid,
struct chsc_ssd_info *ssd);
@@ -122,6 +136,7 @@ extern int chsc_determine_css_characteristics(void);
extern int chsc_init(void);
extern void chsc_init_cleanup(void);
+int __chsc_enable_facility(struct chsc_sda_area *sda_area, int operation_code);
extern int chsc_enable_facility(int);
struct channel_subsystem;
extern int chsc_secm(struct channel_subsystem *, int);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index b5620e8..690b854 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -925,18 +925,32 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo)
{
+ static struct chsc_sda_area sda_area __initdata;
struct subchannel_id schid;
struct schib schib;
schid = *(struct subchannel_id *)&S390_lowcore.subchannel_id;
if (!schid.one)
return -ENODEV;
+
+ if (schid.ssid) {
+ /*
+ * Firmware should have already enabled MSS but whoever started
+ * the kernel might have initiated a channel subsystem reset.
+ * Ensure that MSS is enabled.
+ */
+ memset(&sda_area, 0, sizeof(sda_area));
+ if (__chsc_enable_facility(&sda_area, CHSC_SDA_OC_MSS))
+ return -ENODEV;
+ }
if (stsch_err(schid, &schib))
return -ENODEV;
if (schib.pmcw.st != SUBCHANNEL_TYPE_IO)
return -ENODEV;
if (!schib.pmcw.dnv)
return -ENODEV;
+
+ iplinfo->ssid = schid.ssid;
iplinfo->devno = schib.pmcw.dev;
iplinfo->is_qdio = schib.pmcw.qf;
return 0;
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 2ee3053..489e703 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -702,17 +702,12 @@ css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
css->global_pgid.pgid_high.ext_cssid.version = 0x80;
css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
} else {
-#ifdef CONFIG_SMP
css->global_pgid.pgid_high.cpu_addr = stap();
-#else
- css->global_pgid.pgid_high.cpu_addr = 0;
-#endif
}
get_cpu_id(&cpu_id);
css->global_pgid.cpu_id = cpu_id.ident;
css->global_pgid.cpu_model = cpu_id.machine;
css->global_pgid.tod_high = tod_high;
-
}
static void
diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile
index 57f710b..b8ab186 100644
--- a/drivers/s390/crypto/Makefile
+++ b/drivers/s390/crypto/Makefile
@@ -3,6 +3,9 @@
#
ap-objs := ap_bus.o
-obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o zcrypt_pcixcc.o
-obj-$(CONFIG_ZCRYPT) += zcrypt_cex2a.o zcrypt_cex4.o
+# zcrypt_api depends on ap
+obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o
+# msgtype* depend on zcrypt_api
obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o
+# adapter drivers depend on ap, zcrypt_api and msgtype*
+obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 9cb3dfb..24ec282 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -74,6 +74,7 @@ static struct device *ap_root_device = NULL;
static struct ap_config_info *ap_configuration;
static DEFINE_SPINLOCK(ap_device_list_lock);
static LIST_HEAD(ap_device_list);
+static bool initialised;
/*
* Workqueue timer for bus rescan.
@@ -598,8 +599,10 @@ static enum ap_wait ap_sm_read(struct ap_device *ap_dev)
status = ap_sm_recv(ap_dev);
switch (status.response_code) {
case AP_RESPONSE_NORMAL:
- if (ap_dev->queue_count > 0)
+ if (ap_dev->queue_count > 0) {
+ ap_dev->state = AP_STATE_WORKING;
return AP_WAIT_AGAIN;
+ }
ap_dev->state = AP_STATE_IDLE;
return AP_WAIT_NONE;
case AP_RESPONSE_NO_PENDING_REPLY:
@@ -1384,6 +1387,9 @@ int ap_driver_register(struct ap_driver *ap_drv, struct module *owner,
{
struct device_driver *drv = &ap_drv->driver;
+ if (!initialised)
+ return -ENODEV;
+
drv->bus = &ap_bus_type;
drv->probe = ap_device_probe;
drv->remove = ap_device_remove;
@@ -1808,6 +1814,7 @@ int __init ap_module_init(void)
goto out_pm;
queue_work(system_long_wq, &ap_scan_work);
+ initialised = true;
return 0;
@@ -1837,6 +1844,7 @@ void ap_module_exit(void)
{
int i;
+ initialised = false;
ap_reset_domain();
ap_poll_thread_stop();
del_timer_sync(&ap_config_timer);
diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c
index a9603eb..9f8fa42 100644
--- a/drivers/s390/crypto/zcrypt_api.c
+++ b/drivers/s390/crypto/zcrypt_api.c
@@ -317,11 +317,9 @@ EXPORT_SYMBOL(zcrypt_device_unregister);
void zcrypt_msgtype_register(struct zcrypt_ops *zops)
{
- if (zops->owner) {
- spin_lock_bh(&zcrypt_ops_list_lock);
- list_add_tail(&zops->list, &zcrypt_ops_list);
- spin_unlock_bh(&zcrypt_ops_list_lock);
- }
+ spin_lock_bh(&zcrypt_ops_list_lock);
+ list_add_tail(&zops->list, &zcrypt_ops_list);
+ spin_unlock_bh(&zcrypt_ops_list_lock);
}
EXPORT_SYMBOL(zcrypt_msgtype_register);
@@ -342,7 +340,7 @@ struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant)
spin_lock_bh(&zcrypt_ops_list_lock);
list_for_each_entry(zops, &zcrypt_ops_list, list) {
if ((zops->variant == variant) &&
- (!strncmp(zops->owner->name, name, MODULE_NAME_LEN))) {
+ (!strncmp(zops->name, name, sizeof(zops->name)))) {
found = 1;
break;
}
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index 7508768..38618f0 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -96,6 +96,7 @@ struct zcrypt_ops {
struct list_head list; /* zcrypt ops list. */
struct module *owner;
int variant;
+ char name[128];
};
struct zcrypt_device {
diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c
index 71ceee9..74edf29 100644
--- a/drivers/s390/crypto/zcrypt_msgtype50.c
+++ b/drivers/s390/crypto/zcrypt_msgtype50.c
@@ -513,6 +513,7 @@ static struct zcrypt_ops zcrypt_msgtype50_ops = {
.rsa_modexpo = zcrypt_cex2a_modexpo,
.rsa_modexpo_crt = zcrypt_cex2a_modexpo_crt,
.owner = THIS_MODULE,
+ .name = MSGTYPE50_NAME,
.variant = MSGTYPE50_VARIANT_DEFAULT,
};
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c
index 7476221..9a2dd47 100644
--- a/drivers/s390/crypto/zcrypt_msgtype6.c
+++ b/drivers/s390/crypto/zcrypt_msgtype6.c
@@ -1119,6 +1119,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev,
*/
static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
.owner = THIS_MODULE,
+ .name = MSGTYPE06_NAME,
.variant = MSGTYPE06_VARIANT_NORNG,
.rsa_modexpo = zcrypt_msgtype6_modexpo,
.rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
@@ -1127,6 +1128,7 @@ static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
static struct zcrypt_ops zcrypt_msgtype6_ops = {
.owner = THIS_MODULE,
+ .name = MSGTYPE06_NAME,
.variant = MSGTYPE06_VARIANT_DEFAULT,
.rsa_modexpo = zcrypt_msgtype6_modexpo,
.rsa_modexpo_crt = zcrypt_msgtype6_modexpo_crt,
@@ -1136,6 +1138,7 @@ static struct zcrypt_ops zcrypt_msgtype6_ops = {
static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = {
.owner = THIS_MODULE,
+ .name = MSGTYPE06_NAME,
.variant = MSGTYPE06_VARIANT_EP11,
.rsa_modexpo = NULL,
.rsa_modexpo_crt = NULL,
diff --git a/drivers/s390/virtio/virtio_ccw.c b/drivers/s390/virtio/virtio_ccw.c
index b2a1a81..1b83159 100644
--- a/drivers/s390/virtio/virtio_ccw.c
+++ b/drivers/s390/virtio/virtio_ccw.c
@@ -984,6 +984,36 @@ static struct virtqueue *virtio_ccw_vq_by_ind(struct virtio_ccw_device *vcdev,
return vq;
}
+static void virtio_ccw_check_activity(struct virtio_ccw_device *vcdev,
+ __u32 activity)
+{
+ if (vcdev->curr_io & activity) {
+ switch (activity) {
+ case VIRTIO_CCW_DOING_READ_FEAT:
+ case VIRTIO_CCW_DOING_WRITE_FEAT:
+ case VIRTIO_CCW_DOING_READ_CONFIG:
+ case VIRTIO_CCW_DOING_WRITE_CONFIG:
+ case VIRTIO_CCW_DOING_WRITE_STATUS:
+ case VIRTIO_CCW_DOING_SET_VQ:
+ case VIRTIO_CCW_DOING_SET_IND:
+ case VIRTIO_CCW_DOING_SET_CONF_IND:
+ case VIRTIO_CCW_DOING_RESET:
+ case VIRTIO_CCW_DOING_READ_VQ_CONF:
+ case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
+ case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
+ vcdev->curr_io &= ~activity;
+ wake_up(&vcdev->wait_q);
+ break;
+ default:
+ /* don't know what to do... */
+ dev_warn(&vcdev->cdev->dev,
+ "Suspicious activity '%08x'\n", activity);
+ WARN_ON(1);
+ break;
+ }
+ }
+}
+
static void virtio_ccw_int_handler(struct ccw_device *cdev,
unsigned long intparm,
struct irb *irb)
@@ -995,6 +1025,12 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
if (!vcdev)
return;
+ if (IS_ERR(irb)) {
+ vcdev->err = PTR_ERR(irb);
+ virtio_ccw_check_activity(vcdev, activity);
+ /* Don't poke around indicators, something's wrong. */
+ return;
+ }
/* Check if it's a notification from the host. */
if ((intparm == 0) &&
(scsw_stctl(&irb->scsw) ==
@@ -1010,31 +1046,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
/* Map everything else to -EIO. */
vcdev->err = -EIO;
}
- if (vcdev->curr_io & activity) {
- switch (activity) {
- case VIRTIO_CCW_DOING_READ_FEAT:
- case VIRTIO_CCW_DOING_WRITE_FEAT:
- case VIRTIO_CCW_DOING_READ_CONFIG:
- case VIRTIO_CCW_DOING_WRITE_CONFIG:
- case VIRTIO_CCW_DOING_WRITE_STATUS:
- case VIRTIO_CCW_DOING_SET_VQ:
- case VIRTIO_CCW_DOING_SET_IND:
- case VIRTIO_CCW_DOING_SET_CONF_IND:
- case VIRTIO_CCW_DOING_RESET:
- case VIRTIO_CCW_DOING_READ_VQ_CONF:
- case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
- case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
- vcdev->curr_io &= ~activity;
- wake_up(&vcdev->wait_q);
- break;
- default:
- /* don't know what to do... */
- dev_warn(&cdev->dev, "Suspicious activity '%08x'\n",
- activity);
- WARN_ON(1);
- break;
- }
- }
+ virtio_ccw_check_activity(vcdev, activity);
for_each_set_bit(i, &vcdev->indicators,
sizeof(vcdev->indicators) * BITS_PER_BYTE) {
/* The bit clear must happen before the vring kick. */
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 5843288..e077ebd 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -390,16 +390,9 @@ static int copyin_string(char __user *user, size_t len, char **ptr)
if ((ssize_t)len < 0 || (ssize_t)(len + 1) < 0)
return -EINVAL;
- tmp = kmalloc(len + 1, GFP_KERNEL);
- if (!tmp)
- return -ENOMEM;
-
- if (copy_from_user(tmp, user, len)) {
- kfree(tmp);
- return -EFAULT;
- }
-
- tmp[len] = '\0';
+ tmp = memdup_user_nul(user, len);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
*ptr = tmp;
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index a209c34..d4c2856 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -325,7 +325,6 @@ NCR_700_detect(struct scsi_host_template *tpnt,
tpnt->slave_destroy = NCR_700_slave_destroy;
tpnt->slave_alloc = NCR_700_slave_alloc;
tpnt->change_queue_depth = NCR_700_change_queue_depth;
- tpnt->use_blk_tags = 1;
if(tpnt->name == NULL)
tpnt->name = "53c700";
@@ -1107,7 +1106,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
BUG();
}
if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
- struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
+ struct scsi_cmnd *SCp;
+
+ SCp = scsi_host_find_tag(SDp->host, hostdata->msgin[2]);
if(unlikely(SCp == NULL)) {
printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n",
host->host_no, reselection_id, lun, hostdata->msgin[2]);
@@ -1119,7 +1120,9 @@ process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
"reselection is tag %d, slot %p(%d)\n",
hostdata->msgin[2], slot, slot->tag);
} else {
- struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
+ struct scsi_cmnd *SCp;
+
+ SCp = scsi_host_find_tag(SDp->host, SCSI_NO_TAG);
if(unlikely(SCp == NULL)) {
sdev_printk(KERN_ERR, SDp,
"no saved request for untagged cmd\n");
@@ -1823,7 +1826,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
slot->tag, slot);
} else {
slot->tag = SCSI_NO_TAG;
- /* must populate current_cmnd for scsi_find_tag to work */
+ /* must populate current_cmnd for scsi_host_find_tag to work */
SCp->device->current_cmnd = SCp;
}
/* sanity check: some of the commands generated by the mid-layer
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index 5c74e4c..867b864 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -2136,7 +2136,7 @@ static unsigned char FPT_SccbMgr_bad_isr(u32 p_port, unsigned char p_card,
*
*---------------------------------------------------------------------*/
-static void FPT_SccbMgrTableInitAll()
+static void FPT_SccbMgrTableInitAll(void)
{
unsigned char thisCard;
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index d2f480b..64eed87 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -364,6 +364,7 @@ config SCSI_HPSA
tristate "HP Smart Array SCSI driver"
depends on PCI && SCSI
select CHECK_SIGNATURE
+ select SCSI_SAS_ATTRS
help
This driver supports HP Smart Array Controllers (circa 2009).
It is a SCSI alternative to the cciss driver, which is a block
@@ -499,6 +500,7 @@ config SCSI_ADVANSYS
tristate "AdvanSys SCSI support"
depends on SCSI
depends on ISA || EISA || PCI
+ depends on ISA_DMA_API || !ISA
help
This is a driver for all SCSI host adapters manufactured by
AdvanSys. It is documented in the kernel source in
@@ -534,7 +536,6 @@ config SCSI_ARCMSR
source "drivers/scsi/esas2r/Kconfig"
source "drivers/scsi/megaraid/Kconfig.megaraid"
-source "drivers/scsi/mpt2sas/Kconfig"
source "drivers/scsi/mpt3sas/Kconfig"
source "drivers/scsi/ufs/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1a8c9b5..c14bca4 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -106,7 +106,6 @@ obj-$(CONFIG_CXLFLASH) += cxlflash/
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
-obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/
obj-$(CONFIG_SCSI_MPT3SAS) += mpt3sas/
obj-$(CONFIG_SCSI_UFSHCD) += ufs/
obj-$(CONFIG_SCSI_ACARD) += atp870u.o
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 9b3dd6e..e4c2437 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -259,7 +259,7 @@ MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the"
" 0=off, 1=on");
module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(msi, "IRQ handling."
- " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)");
+ " 0=PIC(default), 1=MSI, 2=MSI-X)");
module_param(startup_timeout, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for"
" adapter to have it's kernel up and\n"
@@ -570,7 +570,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd)
status = aac_fib_send(ContainerCommand,
cmd_fibcontext,
- sizeof (struct aac_get_name),
+ sizeof(struct aac_get_name_resp),
FsaNormal,
0, 1,
(fib_callback)get_container_name_callback,
@@ -1052,7 +1052,7 @@ static int aac_get_container_serial(struct scsi_cmnd * scsicmd)
status = aac_fib_send(ContainerCommand,
cmd_fibcontext,
- sizeof (struct aac_get_serial),
+ sizeof(struct aac_get_serial_resp),
FsaNormal,
0, 1,
(fib_callback) get_container_serial_callback,
@@ -2977,11 +2977,16 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
return;
BUG_ON(fibptr == NULL);
-
dev = fibptr->dev;
- srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+ scsi_dma_unmap(scsicmd);
+ /* expose physical device if expose_physicald flag is on */
+ if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
+ && expose_physicals > 0)
+ aac_expose_phy_device(scsicmd);
+
+ srbreply = (struct aac_srb_reply *) fib_data(fibptr);
scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */
if (fibptr->flags & FIB_CONTEXT_FLAG_FASTRESP) {
@@ -2994,147 +2999,157 @@ static void aac_srb_callback(void *context, struct fib * fibptr)
*/
scsi_set_resid(scsicmd, scsi_bufflen(scsicmd)
- le32_to_cpu(srbreply->data_xfer_length));
- }
-
- scsi_dma_unmap(scsicmd);
-
- /* expose physical device if expose_physicald flag is on */
- if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01)
- && expose_physicals > 0)
- aac_expose_phy_device(scsicmd);
+ /*
+ * First check the fib status
+ */
- /*
- * First check the fib status
- */
+ if (le32_to_cpu(srbreply->status) != ST_OK) {
+ int len;
- if (le32_to_cpu(srbreply->status) != ST_OK){
- int len;
- printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
- len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
- SCSI_SENSE_BUFFERSIZE);
- scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
- memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
- }
+ printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
+ len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+ SCSI_SENSE_BUFFERSIZE);
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8
+ | SAM_STAT_CHECK_CONDITION;
+ memcpy(scsicmd->sense_buffer,
+ srbreply->sense_data, len);
+ }
- /*
- * Next check the srb status
- */
- switch( (le32_to_cpu(srbreply->srb_status))&0x3f){
- case SRB_STATUS_ERROR_RECOVERY:
- case SRB_STATUS_PENDING:
- case SRB_STATUS_SUCCESS:
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
- break;
- case SRB_STATUS_DATA_OVERRUN:
- switch(scsicmd->cmnd[0]){
- case READ_6:
- case WRITE_6:
- case READ_10:
- case WRITE_10:
- case READ_12:
- case WRITE_12:
- case READ_16:
- case WRITE_16:
- if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) {
- printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
- } else {
- printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+ /*
+ * Next check the srb status
+ */
+ switch ((le32_to_cpu(srbreply->srb_status))&0x3f) {
+ case SRB_STATUS_ERROR_RECOVERY:
+ case SRB_STATUS_PENDING:
+ case SRB_STATUS_SUCCESS:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
+ case SRB_STATUS_DATA_OVERRUN:
+ switch (scsicmd->cmnd[0]) {
+ case READ_6:
+ case WRITE_6:
+ case READ_10:
+ case WRITE_10:
+ case READ_12:
+ case WRITE_12:
+ case READ_16:
+ case WRITE_16:
+ if (le32_to_cpu(srbreply->data_xfer_length)
+ < scsicmd->underflow)
+ printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
+ else
+ printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ case INQUIRY: {
+ scsicmd->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ }
+ default:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ break;
}
- scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
break;
- case INQUIRY: {
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ case SRB_STATUS_ABORTED:
+ scsicmd->result = DID_ABORT << 16 | ABORT << 8;
break;
- }
- default:
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+ case SRB_STATUS_ABORT_FAILED:
+ /*
+ * Not sure about this one - but assuming the
+ * hba was trying to abort for some reason
+ */
+ scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+ break;
+ case SRB_STATUS_PARITY_ERROR:
+ scsicmd->result = DID_PARITY << 16
+ | MSG_PARITY_ERROR << 8;
+ break;
+ case SRB_STATUS_NO_DEVICE:
+ case SRB_STATUS_INVALID_PATH_ID:
+ case SRB_STATUS_INVALID_TARGET_ID:
+ case SRB_STATUS_INVALID_LUN:
+ case SRB_STATUS_SELECTION_TIMEOUT:
+ scsicmd->result = DID_NO_CONNECT << 16
+ | COMMAND_COMPLETE << 8;
break;
- }
- break;
- case SRB_STATUS_ABORTED:
- scsicmd->result = DID_ABORT << 16 | ABORT << 8;
- break;
- case SRB_STATUS_ABORT_FAILED:
- // Not sure about this one - but assuming the hba was trying to abort for some reason
- scsicmd->result = DID_ERROR << 16 | ABORT << 8;
- break;
- case SRB_STATUS_PARITY_ERROR:
- scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8;
- break;
- case SRB_STATUS_NO_DEVICE:
- case SRB_STATUS_INVALID_PATH_ID:
- case SRB_STATUS_INVALID_TARGET_ID:
- case SRB_STATUS_INVALID_LUN:
- case SRB_STATUS_SELECTION_TIMEOUT:
- scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
- break;
- case SRB_STATUS_COMMAND_TIMEOUT:
- case SRB_STATUS_TIMEOUT:
- scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_COMMAND_TIMEOUT:
+ case SRB_STATUS_TIMEOUT:
+ scsicmd->result = DID_TIME_OUT << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_BUSY:
- scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_BUSY:
+ scsicmd->result = DID_BUS_BUSY << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_BUS_RESET:
- scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8;
- break;
+ case SRB_STATUS_BUS_RESET:
+ scsicmd->result = DID_RESET << 16
+ | COMMAND_COMPLETE << 8;
+ break;
- case SRB_STATUS_MESSAGE_REJECTED:
- scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
- break;
- case SRB_STATUS_REQUEST_FLUSHED:
- case SRB_STATUS_ERROR:
- case SRB_STATUS_INVALID_REQUEST:
- case SRB_STATUS_REQUEST_SENSE_FAILED:
- case SRB_STATUS_NO_HBA:
- case SRB_STATUS_UNEXPECTED_BUS_FREE:
- case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
- case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
- case SRB_STATUS_DELAYED_RETRY:
- case SRB_STATUS_BAD_FUNCTION:
- case SRB_STATUS_NOT_STARTED:
- case SRB_STATUS_NOT_IN_USE:
- case SRB_STATUS_FORCE_ABORT:
- case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
- default:
+ case SRB_STATUS_MESSAGE_REJECTED:
+ scsicmd->result = DID_ERROR << 16
+ | MESSAGE_REJECT << 8;
+ break;
+ case SRB_STATUS_REQUEST_FLUSHED:
+ case SRB_STATUS_ERROR:
+ case SRB_STATUS_INVALID_REQUEST:
+ case SRB_STATUS_REQUEST_SENSE_FAILED:
+ case SRB_STATUS_NO_HBA:
+ case SRB_STATUS_UNEXPECTED_BUS_FREE:
+ case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+ case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+ case SRB_STATUS_DELAYED_RETRY:
+ case SRB_STATUS_BAD_FUNCTION:
+ case SRB_STATUS_NOT_STARTED:
+ case SRB_STATUS_NOT_IN_USE:
+ case SRB_STATUS_FORCE_ABORT:
+ case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+ default:
#ifdef AAC_DETAILED_STATUS_INFO
- printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
- le32_to_cpu(srbreply->srb_status) & 0x3F,
- aac_get_status_string(
- le32_to_cpu(srbreply->srb_status) & 0x3F),
- scsicmd->cmnd[0],
- le32_to_cpu(srbreply->scsi_status));
+ printk(KERN_INFO "aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+ le32_to_cpu(srbreply->srb_status) & 0x3F,
+ aac_get_status_string(
+ le32_to_cpu(srbreply->srb_status) & 0x3F),
+ scsicmd->cmnd[0],
+ le32_to_cpu(srbreply->scsi_status));
#endif
- if ((scsicmd->cmnd[0] == ATA_12)
- || (scsicmd->cmnd[0] == ATA_16)) {
- if (scsicmd->cmnd[2] & (0x01 << 5)) {
- scsicmd->result = DID_OK << 16
- | COMMAND_COMPLETE << 8;
+ if ((scsicmd->cmnd[0] == ATA_12)
+ || (scsicmd->cmnd[0] == ATA_16)) {
+ if (scsicmd->cmnd[2] & (0x01 << 5)) {
+ scsicmd->result = DID_OK << 16
+ | COMMAND_COMPLETE << 8;
break;
+ } else {
+ scsicmd->result = DID_ERROR << 16
+ | COMMAND_COMPLETE << 8;
+ break;
+ }
} else {
scsicmd->result = DID_ERROR << 16
- | COMMAND_COMPLETE << 8;
+ | COMMAND_COMPLETE << 8;
break;
}
- } else {
- scsicmd->result = DID_ERROR << 16
- | COMMAND_COMPLETE << 8;
- break;
}
- }
- if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) {
- int len;
- scsicmd->result |= SAM_STAT_CHECK_CONDITION;
- len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
- SCSI_SENSE_BUFFERSIZE);
+ if (le32_to_cpu(srbreply->scsi_status)
+ == SAM_STAT_CHECK_CONDITION) {
+ int len;
+
+ scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+ len = min_t(u32, le32_to_cpu(srbreply->sense_data_size),
+ SCSI_SENSE_BUFFERSIZE);
#ifdef AAC_DETAILED_STATUS_INFO
- printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
- le32_to_cpu(srbreply->status), len);
+ printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n",
+ le32_to_cpu(srbreply->status), len);
#endif
- memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+ memcpy(scsicmd->sense_buffer,
+ srbreply->sense_data, len);
+ }
}
/*
* OR in the scsi status (already shifted up a bit)
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 40fe65c..074878b 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
* D E F I N E S
*----------------------------------------------------------------------------*/
-#define AAC_MAX_MSIX 8 /* vectors */
+#define AAC_MAX_MSIX 32 /* vectors */
#define AAC_PCI_MSI_ENABLE 0x8000
enum {
@@ -62,7 +62,7 @@ enum {
#define PMC_GLOBAL_INT_BIT0 0x00000001
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 40709
+# define AAC_DRIVER_BUILD 41010
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -547,6 +547,7 @@ struct adapter_ops
int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4);
int (*adapter_check_health)(struct aac_dev *dev);
int (*adapter_restart)(struct aac_dev *dev, int bled);
+ void (*adapter_start)(struct aac_dev *dev);
/* Transport operations */
int (*adapter_ioremap)(struct aac_dev * dev, u32 size);
irq_handler_t adapter_intr;
@@ -843,6 +844,10 @@ struct src_registers {
&((AEP)->regs.src.bar0->CSR))
#define src_writel(AEP, CSR, value) writel(value, \
&((AEP)->regs.src.bar0->CSR))
+#if defined(writeq)
+#define src_writeq(AEP, CSR, value) writeq(value, \
+ &((AEP)->regs.src.bar0->CSR))
+#endif
#define SRC_ODR_SHIFT 12
#define SRC_IDR_SHIFT 9
@@ -1162,6 +1167,11 @@ struct aac_dev
struct fsa_dev_info *fsa_dev;
struct task_struct *thread;
int cardtype;
+ /*
+ *This lock will protect the two 32-bit
+ *writes to the Inbound Queue
+ */
+ spinlock_t iq_lock;
/*
* The following is the device specific extension.
@@ -1247,6 +1257,9 @@ struct aac_dev
#define aac_adapter_restart(dev,bled) \
(dev)->a_ops.adapter_restart(dev,bled)
+#define aac_adapter_start(dev) \
+ ((dev)->a_ops.adapter_start(dev))
+
#define aac_adapter_ioremap(dev, size) \
(dev)->a_ops.adapter_ioremap(dev, size)
@@ -2097,6 +2110,8 @@ static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor)
#define AAC_OWNER_ERROR_HANDLER 0x103
#define AAC_OWNER_FIRMWARE 0x106
+int aac_acquire_irq(struct aac_dev *dev);
+void aac_free_irq(struct aac_dev *dev);
const char *aac_driverinfo(struct Scsi_Host *);
struct fib *aac_fib_alloc(struct aac_dev *dev);
int aac_fib_setup(struct aac_dev *dev);
@@ -2127,6 +2142,7 @@ int aac_sa_init(struct aac_dev *dev);
int aac_src_init(struct aac_dev *dev);
int aac_srcv_init(struct aac_dev *dev);
int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
+void aac_define_int_mode(struct aac_dev *dev);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index,
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 45db84a..0e954e3 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -43,8 +43,6 @@
#include "aacraid.h"
-static void aac_define_int_mode(struct aac_dev *dev);
-
struct aac_common aac_config = {
.irq_mod = 1
};
@@ -338,6 +336,74 @@ static int aac_comm_init(struct aac_dev * dev)
return 0;
}
+void aac_define_int_mode(struct aac_dev *dev)
+{
+ int i, msi_count, min_msix;
+
+ msi_count = i = 0;
+ /* max. vectors from GET_COMM_PREFERRED_SETTINGS */
+ if (dev->max_msix == 0 ||
+ dev->pdev->device == PMC_DEVICE_S6 ||
+ dev->sync_mode) {
+ dev->max_msix = 1;
+ dev->vector_cap =
+ dev->scsi_host_ptr->can_queue +
+ AAC_NUM_MGT_FIB;
+ return;
+ }
+
+ /* Don't bother allocating more MSI-X vectors than cpus */
+ msi_count = min(dev->max_msix,
+ (unsigned int)num_online_cpus());
+
+ dev->max_msix = msi_count;
+
+ if (msi_count > AAC_MAX_MSIX)
+ msi_count = AAC_MAX_MSIX;
+
+ for (i = 0; i < msi_count; i++)
+ dev->msixentry[i].entry = i;
+
+ if (msi_count > 1 &&
+ pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
+ min_msix = 2;
+ i = pci_enable_msix_range(dev->pdev,
+ dev->msixentry,
+ min_msix,
+ msi_count);
+ if (i > 0) {
+ dev->msi_enabled = 1;
+ msi_count = i;
+ } else {
+ dev->msi_enabled = 0;
+ printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
+ dev->name, dev->id, i);
+ }
+ }
+
+ if (!dev->msi_enabled) {
+ msi_count = 1;
+ i = pci_enable_msi(dev->pdev);
+
+ if (!i) {
+ dev->msi_enabled = 1;
+ dev->msi = 1;
+ } else {
+ printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
+ dev->name, dev->id, i);
+ }
+ }
+
+ if (!dev->msi_enabled)
+ dev->max_msix = msi_count = 1;
+ else {
+ if (dev->max_msix > msi_count)
+ dev->max_msix = msi_count;
+ }
+ dev->vector_cap =
+ (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
+ msi_count;
+}
struct aac_dev *aac_init_adapter(struct aac_dev *dev)
{
u32 status[5];
@@ -350,6 +416,7 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
dev->management_fib_count = 0;
spin_lock_init(&dev->manage_lock);
spin_lock_init(&dev->sync_lock);
+ spin_lock_init(&dev->iq_lock);
dev->max_fib_size = sizeof(struct hw_fib);
dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size
- sizeof(struct aac_fibhdr)
@@ -508,79 +575,3 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
return dev;
}
-static void aac_define_int_mode(struct aac_dev *dev)
-{
-
- int i, msi_count;
-
- msi_count = i = 0;
- /* max. vectors from GET_COMM_PREFERRED_SETTINGS */
- if (dev->max_msix == 0 ||
- dev->pdev->device == PMC_DEVICE_S6 ||
- dev->sync_mode) {
- dev->max_msix = 1;
- dev->vector_cap =
- dev->scsi_host_ptr->can_queue +
- AAC_NUM_MGT_FIB;
- return;
- }
-
- msi_count = min(dev->max_msix,
- (unsigned int)num_online_cpus());
-
- dev->max_msix = msi_count;
-
- if (msi_count > AAC_MAX_MSIX)
- msi_count = AAC_MAX_MSIX;
-
- for (i = 0; i < msi_count; i++)
- dev->msixentry[i].entry = i;
-
- if (msi_count > 1 &&
- pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX)) {
- i = pci_enable_msix(dev->pdev,
- dev->msixentry,
- msi_count);
- /* Check how many MSIX vectors are allocated */
- if (i >= 0) {
- dev->msi_enabled = 1;
- if (i) {
- msi_count = i;
- if (pci_enable_msix(dev->pdev,
- dev->msixentry,
- msi_count)) {
- dev->msi_enabled = 0;
- printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
- } else {
- dev->msi_enabled = 0;
- printk(KERN_ERR "%s%d: MSIX not supported!! Will try MSI 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
-
- if (!dev->msi_enabled) {
- msi_count = 1;
- i = pci_enable_msi(dev->pdev);
-
- if (!i) {
- dev->msi_enabled = 1;
- dev->msi = 1;
- } else {
- printk(KERN_ERR "%s%d: MSI not supported!! Will try INTx 0x%x.\n",
- dev->name, dev->id, i);
- }
- }
-
- if (!dev->msi_enabled)
- dev->max_msix = msi_count = 1;
- else {
- if (dev->max_msix > msi_count)
- dev->max_msix = msi_count;
- }
- dev->vector_cap =
- (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) /
- msi_count;
-}
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index 4da5749..a1f90fe 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -1270,13 +1270,12 @@ retry_next:
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
{
int index, quirks;
- int retval, i;
+ int retval;
struct Scsi_Host *host;
struct scsi_device *dev;
struct scsi_cmnd *command;
struct scsi_cmnd *command_list;
int jafo = 0;
- int cpu;
/*
* Assumptions:
@@ -1339,35 +1338,7 @@ static int _aac_reset_adapter(struct aac_dev *aac, int forced)
aac->comm_phys = 0;
kfree(aac->queues);
aac->queues = NULL;
- cpu = cpumask_first(cpu_online_mask);
- if (aac->pdev->device == PMC_DEVICE_S6 ||
- aac->pdev->device == PMC_DEVICE_S7 ||
- aac->pdev->device == PMC_DEVICE_S8 ||
- aac->pdev->device == PMC_DEVICE_S9) {
- if (aac->max_msix > 1) {
- for (i = 0; i < aac->max_msix; i++) {
- if (irq_set_affinity_hint(
- aac->msixentry[i].vector,
- NULL)) {
- printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n",
- aac->name,
- aac->id,
- cpu);
- }
- cpu = cpumask_next(cpu,
- cpu_online_mask);
- free_irq(aac->msixentry[i].vector,
- &(aac->aac_msix[i]));
- }
- pci_disable_msix(aac->pdev);
- } else {
- free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
- }
- } else {
- free_irq(aac->pdev->irq, aac);
- }
- if (aac->msi)
- pci_disable_msi(aac->pdev);
+ aac_free_irq(aac);
kfree(aac->fsa_dev);
aac->fsa_dev = NULL;
quirks = aac_get_driver_ident(index)->quirks;
@@ -1978,3 +1949,83 @@ int aac_command_thread(void *data)
dev->aif_thread = 0;
return 0;
}
+
+int aac_acquire_irq(struct aac_dev *dev)
+{
+ int i;
+ int j;
+ int ret = 0;
+ int cpu;
+
+ cpu = cpumask_first(cpu_online_mask);
+ if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ dev->aac_msix[i].vector_no = i;
+ dev->aac_msix[i].dev = dev;
+ if (request_irq(dev->msixentry[i].vector,
+ dev->a_ops.adapter_intr,
+ 0, "aacraid", &(dev->aac_msix[i]))) {
+ printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
+ dev->name, dev->id, i);
+ for (j = 0 ; j < i ; j++)
+ free_irq(dev->msixentry[j].vector,
+ &(dev->aac_msix[j]));
+ pci_disable_msix(dev->pdev);
+ ret = -1;
+ }
+ if (irq_set_affinity_hint(dev->msixentry[i].vector,
+ get_cpu_mask(cpu))) {
+ printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n",
+ dev->name, dev->id, cpu);
+ }
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ }
+ } else {
+ dev->aac_msix[0].vector_no = 0;
+ dev->aac_msix[0].dev = dev;
+
+ if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED, "aacraid",
+ &(dev->aac_msix[0])) < 0) {
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+ dev->name, dev->id);
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+void aac_free_irq(struct aac_dev *dev)
+{
+ int i;
+ int cpu;
+
+ cpu = cpumask_first(cpu_online_mask);
+ if (dev->pdev->device == PMC_DEVICE_S6 ||
+ dev->pdev->device == PMC_DEVICE_S7 ||
+ dev->pdev->device == PMC_DEVICE_S8 ||
+ dev->pdev->device == PMC_DEVICE_S9) {
+ if (dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ if (irq_set_affinity_hint(
+ dev->msixentry[i].vector, NULL)) {
+ printk(KERN_ERR "%s%d: Failed to reset IRQ affinity for cpu %d\n",
+ dev->name, dev->id, cpu);
+ }
+ cpu = cpumask_next(cpu, cpu_online_mask);
+ free_irq(dev->msixentry[i].vector,
+ &(dev->aac_msix[i]));
+ }
+ } else {
+ free_irq(dev->pdev->irq, &(dev->aac_msix[0]));
+ }
+ } else {
+ free_irq(dev->pdev->irq, dev);
+ }
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ else if (dev->max_msix > 1)
+ pci_disable_msix(dev->pdev);
+}
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 9eec027..3b6e5c6 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -1317,6 +1317,154 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
return error;
}
+#if (defined(CONFIG_PM))
+void aac_release_resources(struct aac_dev *aac)
+{
+ int i;
+
+ aac_adapter_disable_int(aac);
+ if (aac->pdev->device == PMC_DEVICE_S6 ||
+ aac->pdev->device == PMC_DEVICE_S7 ||
+ aac->pdev->device == PMC_DEVICE_S8 ||
+ aac->pdev->device == PMC_DEVICE_S9) {
+ if (aac->max_msix > 1) {
+ for (i = 0; i < aac->max_msix; i++)
+ free_irq(aac->msixentry[i].vector,
+ &(aac->aac_msix[i]));
+ } else {
+ free_irq(aac->pdev->irq, &(aac->aac_msix[0]));
+ }
+ } else {
+ free_irq(aac->pdev->irq, aac);
+ }
+ if (aac->msi)
+ pci_disable_msi(aac->pdev);
+ else if (aac->max_msix > 1)
+ pci_disable_msix(aac->pdev);
+
+}
+
+static int aac_acquire_resources(struct aac_dev *dev)
+{
+ int i, j;
+ int instance = dev->id;
+ const char *name = dev->name;
+ unsigned long status;
+ /*
+ * First clear out all interrupts. Then enable the one's that we
+ * can handle.
+ */
+ while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)
+ || status == 0xffffffff)
+ msleep(20);
+
+ aac_adapter_disable_int(dev);
+ aac_adapter_enable_int(dev);
+
+
+ if ((dev->pdev->device == PMC_DEVICE_S7 ||
+ dev->pdev->device == PMC_DEVICE_S8 ||
+ dev->pdev->device == PMC_DEVICE_S9))
+ aac_define_int_mode(dev);
+
+ if (dev->msi_enabled)
+ aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
+
+ if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
+ for (i = 0; i < dev->max_msix; i++) {
+ dev->aac_msix[i].vector_no = i;
+ dev->aac_msix[i].dev = dev;
+
+ if (request_irq(dev->msixentry[i].vector,
+ dev->a_ops.adapter_intr,
+ 0, "aacraid", &(dev->aac_msix[i]))) {
+ printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
+ name, instance, i);
+ for (j = 0 ; j < i ; j++)
+ free_irq(dev->msixentry[j].vector,
+ &(dev->aac_msix[j]));
+ pci_disable_msix(dev->pdev);
+ goto error_iounmap;
+ }
+ }
+ } else {
+ dev->aac_msix[0].vector_no = 0;
+ dev->aac_msix[0].dev = dev;
+
+ if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
+ IRQF_SHARED, "aacraid",
+ &(dev->aac_msix[0])) < 0) {
+ if (dev->msi)
+ pci_disable_msi(dev->pdev);
+ printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
+ name, instance);
+ goto error_iounmap;
+ }
+ }
+
+ aac_adapter_enable_int(dev);
+
+ if (!dev->sync_mode)
+ aac_adapter_start(dev);
+ return 0;
+
+error_iounmap:
+ return -1;
+
+}
+static int aac_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+
+ scsi_block_requests(shost);
+ aac_send_shutdown(aac);
+
+ aac_release_resources(aac);
+
+ pci_set_drvdata(pdev, shost);
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+ return 0;
+}
+
+static int aac_resume(struct pci_dev *pdev)
+{
+ struct Scsi_Host *shost = pci_get_drvdata(pdev);
+ struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+ int r;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_enable_wake(pdev, PCI_D0, 0);
+ pci_restore_state(pdev);
+ r = pci_enable_device(pdev);
+
+ if (r)
+ goto fail_device;
+
+ pci_set_master(pdev);
+ if (aac_acquire_resources(aac))
+ goto fail_device;
+ /*
+ * reset this flag to unblock ioctl() as it was set at
+ * aac_send_shutdown() to block ioctls from upperlayer
+ */
+ aac->adapter_shutdown = 0;
+ scsi_unblock_requests(shost);
+
+ return 0;
+
+fail_device:
+ printk(KERN_INFO "%s%d: resume failed.\n", aac->name, aac->id);
+ scsi_host_put(shost);
+ pci_disable_device(pdev);
+ return -ENODEV;
+}
+#endif
+
static void aac_shutdown(struct pci_dev *dev)
{
struct Scsi_Host *shost = pci_get_drvdata(dev);
@@ -1356,6 +1504,10 @@ static struct pci_driver aac_pci_driver = {
.id_table = aac_pci_tbl,
.probe = aac_probe_one,
.remove = aac_remove_one,
+#if (defined(CONFIG_PM))
+ .suspend = aac_suspend,
+ .resume = aac_resume,
+#endif
.shutdown = aac_shutdown,
};
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index 9570612..ac16380 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -623,6 +623,7 @@ int _aac_rx_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
dev->a_ops.adapter_check_health = aac_rx_check_health;
dev->a_ops.adapter_restart = aac_rx_restart_adapter;
+ dev->a_ops.adapter_start = aac_rx_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index e66477c..869aea2 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -372,6 +372,7 @@ int aac_sa_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
dev->a_ops.adapter_check_health = aac_sa_check_health;
dev->a_ops.adapter_restart = aac_sa_restart_adapter;
+ dev->a_ops.adapter_start = aac_sa_start_adapter;
dev->a_ops.adapter_intr = aac_sa_intr;
dev->a_ops.adapter_deliver = aac_rx_deliver_producer;
dev->a_ops.adapter_ioremap = aac_sa_ioremap;
diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c
index e63cf9f..2aa34ea 100644
--- a/drivers/scsi/aacraid/src.c
+++ b/drivers/scsi/aacraid/src.c
@@ -447,6 +447,10 @@ static int aac_src_deliver_message(struct fib *fib)
u32 fibsize;
dma_addr_t address;
struct aac_fib_xporthdr *pFibX;
+#if !defined(writeq)
+ unsigned long flags;
+#endif
+
u16 hdr_size = le16_to_cpu(fib->hw_fib_va->header.Size);
atomic_inc(&q->numpending);
@@ -511,10 +515,14 @@ static int aac_src_deliver_message(struct fib *fib)
return -EINVAL;
address |= fibsize;
}
-
+#if defined(writeq)
+ src_writeq(dev, MUnit.IQ_L, (u64)address);
+#else
+ spin_lock_irqsave(&fib->dev->iq_lock, flags);
src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff);
src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
-
+ spin_unlock_irqrestore(&fib->dev->iq_lock, flags);
+#endif
return 0;
}
@@ -726,6 +734,7 @@ int aac_src_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
dev->a_ops.adapter_check_health = aac_src_check_health;
dev->a_ops.adapter_restart = aac_src_restart_adapter;
+ dev->a_ops.adapter_start = aac_src_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
@@ -741,7 +750,7 @@ int aac_src_init(struct aac_dev *dev)
if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1)
goto error_iounmap;
- dev->msi = aac_msi && !pci_enable_msi(dev->pdev);
+ dev->msi = !pci_enable_msi(dev->pdev);
dev->aac_msix[0].vector_no = 0;
dev->aac_msix[0].dev = dev;
@@ -789,9 +798,7 @@ int aac_srcv_init(struct aac_dev *dev)
unsigned long status;
int restart = 0;
int instance = dev->id;
- int i, j;
const char *name = dev->name;
- int cpu;
dev->a_ops.adapter_ioremap = aac_srcv_ioremap;
dev->a_ops.adapter_comm = aac_src_select_comm;
@@ -892,6 +899,7 @@ int aac_srcv_init(struct aac_dev *dev)
dev->a_ops.adapter_sync_cmd = src_sync_cmd;
dev->a_ops.adapter_check_health = aac_src_check_health;
dev->a_ops.adapter_restart = aac_src_restart_adapter;
+ dev->a_ops.adapter_start = aac_src_start_adapter;
/*
* First clear out all interrupts. Then enable the one's that we
@@ -908,48 +916,10 @@ int aac_srcv_init(struct aac_dev *dev)
goto error_iounmap;
if (dev->msi_enabled)
aac_src_access_devreg(dev, AAC_ENABLE_MSIX);
- if (!dev->sync_mode && dev->msi_enabled && dev->max_msix > 1) {
- cpu = cpumask_first(cpu_online_mask);
- for (i = 0; i < dev->max_msix; i++) {
- dev->aac_msix[i].vector_no = i;
- dev->aac_msix[i].dev = dev;
-
- if (request_irq(dev->msixentry[i].vector,
- dev->a_ops.adapter_intr,
- 0,
- "aacraid",
- &(dev->aac_msix[i]))) {
- printk(KERN_ERR "%s%d: Failed to register IRQ for vector %d.\n",
- name, instance, i);
- for (j = 0 ; j < i ; j++)
- free_irq(dev->msixentry[j].vector,
- &(dev->aac_msix[j]));
- pci_disable_msix(dev->pdev);
- goto error_iounmap;
- }
- if (irq_set_affinity_hint(
- dev->msixentry[i].vector,
- get_cpu_mask(cpu))) {
- printk(KERN_ERR "%s%d: Failed to set IRQ affinity for cpu %d\n",
- name, instance, cpu);
- }
- cpu = cpumask_next(cpu, cpu_online_mask);
- }
- } else {
- dev->aac_msix[0].vector_no = 0;
- dev->aac_msix[0].dev = dev;
-
- if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr,
- IRQF_SHARED,
- "aacraid",
- &(dev->aac_msix[0])) < 0) {
- if (dev->msi)
- pci_disable_msi(dev->pdev);
- printk(KERN_ERR "%s%d: Interrupt unavailable.\n",
- name, instance);
- goto error_iounmap;
- }
- }
+
+ if (aac_acquire_irq(dev))
+ goto error_iounmap;
+
dev->dbg_base = dev->base_start;
dev->dbg_base_mapped = dev->base;
dev->dbg_size = dev->base_size;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 4305178..febbd83 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7803,7 +7803,7 @@ adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp,
return ASC_BUSY;
}
scsiqp->sense_addr = cpu_to_le32(sense_addr);
- scsiqp->sense_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE);
+ scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE;
/* Build ADV_SCSI_REQ_Q */
@@ -10819,7 +10819,6 @@ static struct scsi_host_template advansys_template = {
* by enabling clustering, I/O throughput increases as well.
*/
.use_clustering = ENABLE_CLUSTERING,
- .use_blk_tags = 1,
};
static int advansys_wide_init_chip(struct Scsi_Host *shost)
@@ -11211,11 +11210,6 @@ static int advansys_board_found(struct Scsi_Host *shost, unsigned int iop,
/* Set maximum number of queues the adapter can handle. */
shost->can_queue = adv_dvc_varp->max_host_qng;
}
- ret = scsi_init_shared_tag_map(shost, shost->can_queue);
- if (ret) {
- shost_printk(KERN_ERR, shost, "init tag map failed\n");
- goto err_free_dma;
- }
/*
* Set the maximum number of scatter-gather elements the
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index ce96a0b..2588b8f 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -925,7 +925,6 @@ struct scsi_host_template aic79xx_driver_template = {
.slave_configure = ahd_linux_slave_configure,
.target_alloc = ahd_linux_target_alloc,
.target_destroy = ahd_linux_target_destroy,
- .use_blk_tags = 1,
};
/******************************** Bus DMA *************************************/
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index a2f2c77..b846a46 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -812,7 +812,6 @@ struct scsi_host_template aic7xxx_driver_template = {
.slave_configure = ahc_linux_slave_configure,
.target_alloc = ahc_linux_target_alloc,
.target_destroy = ahc_linux_target_destroy,
- .use_blk_tags = 1,
};
/**************************** Tasklet Handler *********************************/
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index f6c336b..662b232 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -73,7 +73,6 @@ static struct scsi_host_template aic94xx_sht = {
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -704,10 +703,10 @@ static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha)
{
int err;
+ scsi_remove_host(asd_ha->sas_ha.core.shost);
err = sas_unregister_ha(&asd_ha->sas_ha);
sas_remove_host(asd_ha->sas_ha.core.shost);
- scsi_remove_host(asd_ha->sas_ha.core.shost);
scsi_host_put(asd_ha->sas_ha.core.shost);
kfree(asd_ha->sas_ha.sas_phy);
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 2e6abe7..fe0c514 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -1198,14 +1198,16 @@ free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
* alloc_wrb_handle - To allocate a wrb handle
* @phba: The hba pointer
* @cid: The cid to use for allocation
+ * @pwrb_context: ptr to ptr to wrb context
*
* This happens under session_lock until submission to chip
*/
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid)
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ struct hwi_wrb_context **pcontext)
{
struct hwi_wrb_context *pwrb_context;
struct hwi_controller *phwi_ctrlr;
- struct wrb_handle *pwrb_handle, *pwrb_handle_tmp;
+ struct wrb_handle *pwrb_handle;
uint16_t cri_index = BE_GET_CRI_FROM_CID(cid);
phwi_ctrlr = phba->phwi_ctrlr;
@@ -1219,9 +1221,9 @@ struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid)
pwrb_context->alloc_index = 0;
else
pwrb_context->alloc_index++;
- pwrb_handle_tmp = pwrb_context->pwrb_handle_base[
- pwrb_context->alloc_index];
- pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index;
+
+ /* Return the context address */
+ *pcontext = pwrb_context;
} else
pwrb_handle = NULL;
return pwrb_handle;
@@ -3184,7 +3186,7 @@ be_sgl_create_contiguous(void *virtual_address,
{
WARN_ON(!virtual_address);
WARN_ON(!physical_address);
- WARN_ON(!length > 0);
+ WARN_ON(!length);
WARN_ON(!sgl);
sgl->va = virtual_address;
@@ -4678,6 +4680,7 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
struct beiscsi_offload_params *params)
{
struct wrb_handle *pwrb_handle;
+ struct hwi_wrb_context *pwrb_context = NULL;
struct beiscsi_hba *phba = beiscsi_conn->phba;
struct iscsi_task *task = beiscsi_conn->task;
struct iscsi_session *session = task->conn->session;
@@ -4692,14 +4695,17 @@ beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
beiscsi_cleanup_task(task);
spin_unlock_bh(&session->back_lock);
- pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid);
+ pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid,
+ &pwrb_context);
/* Check for the adapter family */
if (is_chip_be2_be3r(phba))
beiscsi_offload_cxn_v0(params, pwrb_handle,
- phba->init_mem);
+ phba->init_mem,
+ pwrb_context);
else
- beiscsi_offload_cxn_v2(params, pwrb_handle);
+ beiscsi_offload_cxn_v2(params, pwrb_handle,
+ pwrb_context);
be_dws_le_to_cpu(pwrb_handle->pwrb,
sizeof(struct iscsi_target_context_update_wrb));
@@ -4769,7 +4775,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
goto free_hndls;
}
io_task->pwrb_handle = alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4803,7 +4810,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
io_task->psgl_handle;
io_task->pwrb_handle =
alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO |
@@ -4839,7 +4847,8 @@ static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
}
io_task->pwrb_handle =
alloc_wrb_handle(phba,
- beiscsi_conn->beiscsi_conn_cid);
+ beiscsi_conn->beiscsi_conn_cid,
+ &io_task->pwrb_context);
if (!io_task->pwrb_handle) {
beiscsi_log(phba, KERN_ERR,
BEISCSI_LOG_IO | BEISCSI_LOG_CONFIG,
@@ -4925,7 +4934,12 @@ int beiscsi_iotask_v2(struct iscsi_task *task, struct scatterlist *sg,
hwi_write_sgl_v2(pwrb, sg, num_sg, io_task);
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
@@ -4982,7 +4996,13 @@ static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
hwi_write_sgl(pwrb, sg, num_sg, io_task);
AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
@@ -5020,7 +5040,13 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
task->data_count);
AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
pwrb_typeoffset = BE_WRB_TYPE_OFFSET;
} else {
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, cmdsn_itt, pwrb,
@@ -5032,7 +5058,13 @@ static int beiscsi_mtask(struct iscsi_task *task)
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, r2t_exp_dtl, pwrb,
task->data_count);
AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb, pwrb,
- io_task->pwrb_handle->nxt_wrb_index);
+ io_task->pwrb_handle->wrb_index);
+ if (io_task->pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_wrb_v2, ptr2nextwrb,
+ io_task->pwrb_context->plast_wrb,
+ io_task->pwrb_handle->wrb_index);
+ io_task->pwrb_context->plast_wrb = pwrb;
+
pwrb_typeoffset = SKH_WRB_TYPE_OFFSET;
}
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
index 51366de..5c67c07 100644
--- a/drivers/scsi/be2iscsi/be_main.h
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -36,7 +36,7 @@
#include <scsi/scsi_transport_iscsi.h>
#define DRV_NAME "be2iscsi"
-#define BUILD_STR "10.6.0.0"
+#define BUILD_STR "10.6.0.1"
#define BE_NAME "Emulex OneConnect" \
"Open-iSCSI Driver version" BUILD_STR
#define DRV_DESC BE_NAME " " "Driver"
@@ -502,6 +502,7 @@ struct beiscsi_io_task {
struct sgl_handle *psgl_handle;
struct beiscsi_conn *conn;
struct scsi_cmnd *scsi_cmnd;
+ struct hwi_wrb_context *pwrb_context;
unsigned int cmd_sn;
unsigned int flags;
unsigned short cid;
@@ -833,7 +834,8 @@ struct amap_iscsi_wrb_v2 {
} __packed;
-struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid);
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ struct hwi_wrb_context **pcontext);
void
free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
@@ -1044,7 +1046,6 @@ enum hwh_type_enum {
struct wrb_handle {
enum hwh_type_enum type;
unsigned short wrb_index;
- unsigned short nxt_wrb_index;
struct iscsi_task *pio_handle;
struct iscsi_wrb *pwrb;
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
index 1b2bd04..aea3e6b 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.c
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -1573,7 +1573,8 @@ beiscsi_phys_port_disp(struct device *dev, struct device_attribute *attr,
void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle,
- struct be_mem_descriptor *mem_descr)
+ struct be_mem_descriptor *mem_descr,
+ struct hwi_wrb_context *pwrb_context)
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
@@ -1617,7 +1618,14 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
max_burst_length) / 32]);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
- pwrb, pwrb_handle->nxt_wrb_index);
+ pwrb, pwrb_handle->wrb_index);
+ if (pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ ptr2nextwrb,
+ pwrb_context->plast_wrb,
+ pwrb_handle->wrb_index);
+ pwrb_context->plast_wrb = pwrb;
+
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
session_state, pwrb, 0);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
@@ -1637,7 +1645,8 @@ void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
}
void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
- struct wrb_handle *pwrb_handle)
+ struct wrb_handle *pwrb_handle,
+ struct hwi_wrb_context *pwrb_context)
{
struct iscsi_wrb *pwrb = pwrb_handle->pwrb;
@@ -1652,7 +1661,14 @@ void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
BE_TGT_CTX_UPDT_CMD);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
ptr2nextwrb,
- pwrb, pwrb_handle->nxt_wrb_index);
+ pwrb, pwrb_handle->wrb_index);
+ if (pwrb_context->plast_wrb)
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
+ ptr2nextwrb,
+ pwrb_context->plast_wrb,
+ pwrb_handle->wrb_index);
+ pwrb_context->plast_wrb = pwrb;
+
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2, wrb_idx,
pwrb, pwrb_handle->wrb_index);
AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb_v2,
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
index afa326d..c1dbb69 100644
--- a/drivers/scsi/be2iscsi/be_mgmt.h
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -330,10 +330,13 @@ ssize_t beiscsi_phys_port_disp(struct device *dev,
void beiscsi_offload_cxn_v0(struct beiscsi_offload_params *params,
struct wrb_handle *pwrb_handle,
- struct be_mem_descriptor *mem_descr);
+ struct be_mem_descriptor *mem_descr,
+ struct hwi_wrb_context *pwrb_context);
void beiscsi_offload_cxn_v2(struct beiscsi_offload_params *params,
- struct wrb_handle *pwrb_handle);
+ struct wrb_handle *pwrb_handle,
+ struct hwi_wrb_context *pwrb_context);
+
void beiscsi_ue_detect(struct beiscsi_hba *phba);
int be_cmd_modify_eq_delay(struct beiscsi_hba *phba,
struct be_set_eqd *, int num);
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index 8367c11..299c6f8 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -800,7 +800,6 @@ struct scsi_host_template bfad_im_scsi_host_template = {
.shost_attrs = bfad_im_host_attrs,
.max_sectors = BFAD_MAX_SECTORS,
.vendor_id = BFA_PCI_VENDOR_ID_BROCADE,
- .use_blk_tags = 1,
};
struct scsi_host_template bfad_im_vport_template = {
@@ -822,7 +821,6 @@ struct scsi_host_template bfad_im_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = bfad_im_vport_attrs,
.max_sectors = BFAD_MAX_SECTORS,
- .use_blk_tags = 1,
};
bfa_status_t
diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
index fe2106c..ac1c0b6 100644
--- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
+++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h
@@ -1,9 +1,9 @@
-/* 57xx_hsi_bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* 57xx_hsi_bnx2fc.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2fc/Kconfig b/drivers/scsi/bnx2fc/Kconfig
index 0978828..d401a09 100644
--- a/drivers/scsi/bnx2fc/Kconfig
+++ b/drivers/scsi/bnx2fc/Kconfig
@@ -1,5 +1,5 @@
config SCSI_BNX2X_FCOE
- tristate "QLogic NetXtreme II FCoE support"
+ tristate "QLogic FCoE offload support"
depends on PCI
depends on (IPV6 || IPV6=n)
depends on LIBFC
@@ -9,5 +9,4 @@ config SCSI_BNX2X_FCOE
select NET_VENDOR_BROADCOM
select CNIC
---help---
- This driver supports FCoE offload for the QLogic NetXtreme II
- devices.
+ This driver supports FCoE offload for the QLogic devices.
diff --git a/drivers/scsi/bnx2fc/bnx2fc.h b/drivers/scsi/bnx2fc/bnx2fc.h
index 1346e05..499e369 100644
--- a/drivers/scsi/bnx2fc/bnx2fc.h
+++ b/drivers/scsi/bnx2fc/bnx2fc.h
@@ -1,7 +1,7 @@
-/* bnx2fc.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc.h: QLogic Linux FCoE offload driver.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,7 +65,7 @@
#include "bnx2fc_constants.h"
#define BNX2FC_NAME "bnx2fc"
-#define BNX2FC_VERSION "2.4.2"
+#define BNX2FC_VERSION "2.9.6"
#define PFX "bnx2fc: "
@@ -303,7 +303,6 @@ struct bnx2fc_rport {
#define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5
#define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6
#define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7
-#define BNX2FC_FLAG_EXPL_LOGO 0x8
#define BNX2FC_FLAG_DISABLE_FAILED 0x9
#define BNX2FC_FLAG_ENABLED 0xa
diff --git a/drivers/scsi/bnx2fc/bnx2fc_constants.h b/drivers/scsi/bnx2fc/bnx2fc_constants.h
index e147cc7..5b20efb 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_constants.h
+++ b/drivers/scsi/bnx2fc/bnx2fc_constants.h
@@ -1,9 +1,9 @@
-/* bnx2fc_constants.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_constants.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.c b/drivers/scsi/bnx2fc/bnx2fc_debug.c
index d055df0..c9e0bc7 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_debug.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.c
@@ -1,9 +1,9 @@
-/* bnx2fc_debug.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_debug.c: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2fc/bnx2fc_debug.h b/drivers/scsi/bnx2fc/bnx2fc_debug.h
index 2b90067..34fda3e 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_debug.h
+++ b/drivers/scsi/bnx2fc/bnx2fc_debug.h
@@ -1,9 +1,9 @@
-/* bnx2fc_debug.h: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_debug.h: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2fc/bnx2fc_els.c b/drivers/scsi/bnx2fc/bnx2fc_els.c
index ef355c1..5beea77 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_els.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_els.c
@@ -1,10 +1,10 @@
/*
- * bnx2fc_els.c: QLogic NetXtreme II Linux FCoE offload driver.
+ * bnx2fc_els.c: QLogic Linux FCoE offload driver.
* This file contains helper routines that handle ELS requests
* and responses.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -689,8 +689,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
rc = -EINVAL;
goto els_err;
}
- if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) ||
- (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) {
+ if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) {
printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op);
rc = -EINVAL;
goto els_err;
@@ -707,6 +706,7 @@ static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op,
els_req->cb_func = cb_func;
cb_arg->io_req = els_req;
els_req->cb_arg = cb_arg;
+ els_req->data_xfer_len = data_len;
mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req);
rc = bnx2fc_init_mp_req(els_req);
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index b0bc5ff..67405c6 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -1,10 +1,10 @@
-/* bnx2fc_fcoe.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_fcoe.c: QLogic Linux FCoE offload driver.
* This file contains the code that interacts with libfc, libfcoe,
* cnic modules to create FCoE instances, send/receive non-offloaded
* FIP/FCoE packets, listen to link events etc.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,16 +23,16 @@ DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu);
#define DRV_MODULE_NAME "bnx2fc"
#define DRV_MODULE_VERSION BNX2FC_VERSION
-#define DRV_MODULE_RELDATE "Dec 11, 2013"
+#define DRV_MODULE_RELDATE "October 15, 2015"
static char version[] =
- "QLogic NetXtreme II FCoE Driver " DRV_MODULE_NAME \
+ "QLogic FCoE Driver " DRV_MODULE_NAME \
" v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Bhanu Prakash Gollapudi <bprakash@broadcom.com>");
-MODULE_DESCRIPTION("QLogic NetXtreme II BCM57710 FCoE Driver");
+MODULE_DESCRIPTION("QLogic FCoE Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
@@ -2091,7 +2091,7 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
{
struct bnx2fc_interface *interface = fcoe_ctlr_priv(ctlr);
struct bnx2fc_hba *hba;
- struct cnic_fc_npiv_tbl npiv_tbl;
+ struct cnic_fc_npiv_tbl *npiv_tbl;
struct fc_lport *lport;
if (interface->enabled == false) {
@@ -2123,11 +2123,16 @@ static int __bnx2fc_enable(struct fcoe_ctlr *ctlr)
if (!hba->cnic->get_fc_npiv_tbl)
goto done;
- memset(&npiv_tbl, 0, sizeof(npiv_tbl));
- if (hba->cnic->get_fc_npiv_tbl(hba->cnic, &npiv_tbl))
+ npiv_tbl = kzalloc(sizeof(struct cnic_fc_npiv_tbl), GFP_KERNEL);
+ if (!npiv_tbl)
goto done;
- bnx2fc_npiv_create_vports(lport, &npiv_tbl);
+ if (hba->cnic->get_fc_npiv_tbl(hba->cnic, npiv_tbl))
+ goto done_free;
+
+ bnx2fc_npiv_create_vports(lport, npiv_tbl);
+done_free:
+ kfree(npiv_tbl);
done:
return 0;
}
@@ -2862,7 +2867,6 @@ static struct scsi_host_template bnx2fc_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
.max_sectors = 1024,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
index c6688d7..28c671b 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_hwi.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_hwi.c
@@ -1,9 +1,9 @@
-/* bnx2fc_hwi.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_hwi.c: QLogic Linux FCoE offload driver.
* This file contains the code that low level functions that interact
* with 57712 FCoE firmware.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 9ecca85..0002caf 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1,8 +1,8 @@
-/* bnx2fc_io.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_io.c: QLogic Linux FCoE offload driver.
* IO manager and SCSI IO processing.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -40,11 +40,8 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
{
struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd,
timeout_work.work);
- struct fc_lport *lport;
- struct fc_rport_priv *rdata;
u8 cmd_type = io_req->cmd_type;
struct bnx2fc_rport *tgt = io_req->tgt;
- int logo_issued;
int rc;
BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d,"
@@ -80,25 +77,14 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
io_req->refcount.refcount.counter);
if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
&io_req->req_flags))) {
-
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
+ /*
+ * Cleanup and return original command to
+ * mid-layer.
+ */
+ bnx2fc_initiate_cleanup(io_req);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- /* Explicitly logo the target */
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicit "
- "logo - tgt flags = 0x%lx\n",
- tgt->flags);
-
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
}
} else {
@@ -116,28 +102,10 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
rc = bnx2fc_initiate_abts(io_req);
if (rc == SUCCESS)
goto done;
- /*
- * Explicitly logo the target if
- * abts initiation fails
- */
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
+
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicit "
- "logo - tgt flags = 0x%lx\n",
- tgt->flags);
-
-
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
} else {
BNX2FC_IO_DBG(io_req, "IO already in "
@@ -152,22 +120,9 @@ static void bnx2fc_cmd_timeout(struct work_struct *work)
if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE,
&io_req->req_flags)) {
- lport = io_req->port->lport;
- rdata = io_req->tgt->rdata;
- logo_issued = test_and_set_bit(
- BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
kref_put(&io_req->refcount, bnx2fc_cmd_release);
spin_unlock_bh(&tgt->tgt_lock);
- /* Explicitly logo the target */
- if (!logo_issued) {
- BNX2FC_IO_DBG(io_req, "Explicitly logo"
- "(els)\n");
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
return;
}
} else {
@@ -623,8 +578,12 @@ int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req)
mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req);
memset(mp_req, 0, sizeof(struct bnx2fc_mp_req));
- mp_req->req_len = sizeof(struct fcp_cmnd);
- io_req->data_xfer_len = mp_req->req_len;
+ if (io_req->cmd_type != BNX2FC_ELS) {
+ mp_req->req_len = sizeof(struct fcp_cmnd);
+ io_req->data_xfer_len = mp_req->req_len;
+ } else
+ mp_req->req_len = io_req->data_xfer_len;
+
mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, CNIC_PAGE_SIZE,
&mp_req->req_buf_dma,
GFP_ATOMIC);
@@ -1108,18 +1067,11 @@ int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd)
return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET);
}
-int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
+int bnx2fc_abts_cleanup(struct bnx2fc_cmd *io_req)
{
struct bnx2fc_rport *tgt = io_req->tgt;
- struct fc_rport_priv *rdata = tgt->rdata;
- int logo_issued;
int rc = SUCCESS;
- int wait_cnt = 0;
- BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n",
- tgt->flags);
- logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO,
- &tgt->flags);
io_req->wait_for_comp = 1;
bnx2fc_initiate_cleanup(io_req);
@@ -1132,21 +1084,8 @@ int bnx2fc_expl_logo(struct fc_lport *lport, struct bnx2fc_cmd *io_req)
* release the reference taken in eh_abort to allow the
* target to re-login after flushing IOs
*/
- kref_put(&io_req->refcount, bnx2fc_cmd_release);
-
- if (!logo_issued) {
- clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags);
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_logoff(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- do {
- msleep(BNX2FC_RELOGIN_WAIT_TIME);
- if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) {
- rc = FAILED;
- break;
- }
- } while (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags));
- }
+ kref_put(&io_req->refcount, bnx2fc_cmd_release);
+
spin_lock_bh(&tgt->tgt_lock);
return rc;
}
@@ -1248,7 +1187,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
if (cancel_delayed_work(&io_req->timeout_work))
kref_put(&io_req->refcount,
bnx2fc_cmd_release); /* drop timer hold */
- rc = bnx2fc_expl_logo(lport, io_req);
+ rc = bnx2fc_abts_cleanup(io_req);
/* This only occurs when an task abort was requested while ABTS
is in progress. Setting the IO_CLEANUP flag will skip the
RRQ process in the case when the fw generated SCSI_CMD cmpl
@@ -1287,7 +1226,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd)
/* Let the scsi-ml try to recover this command */
printk(KERN_ERR PFX "abort failed, xid = 0x%x\n",
io_req->xid);
- rc = bnx2fc_expl_logo(lport, io_req);
+ rc = bnx2fc_abts_cleanup(io_req);
goto out;
} else {
/*
@@ -1755,7 +1694,10 @@ static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
int fcp_rsp_len = 0;
io_req->fcp_status = FC_GOOD;
- io_req->fcp_resid = fcp_rsp->fcp_resid;
+ io_req->fcp_resid = 0;
+ if (rsp_flags & (FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER |
+ FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER))
+ io_req->fcp_resid = fcp_rsp->fcp_resid;
io_req->scsi_comp_flags = rsp_flags;
CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status =
diff --git a/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
index c66c708..08ec318 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_tgt.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_tgt.c
@@ -1,9 +1,9 @@
-/* bnx2fc_tgt.c: QLogic NetXtreme II Linux FCoE offload driver.
+/* bnx2fc_tgt.c: QLogic Linux FCoE offload driver.
* Handles operations such as session offload/upload etc, and manages
* session resources such as connection id and qp resources.
*
- * Copyright (c) 2008 - 2013 Broadcom Corporation
- * Copyright (c) 2014, QLogic Corporation
+ * Copyright (c) 2008-2013 Broadcom Corporation
+ * Copyright (c) 2014-2015 QLogic Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -560,12 +560,6 @@ void bnx2fc_rport_event_handler(struct fc_lport *lport,
(hba->num_ofld_sess == 0)) {
wake_up_interruptible(&hba->shutdown_wait);
}
- if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) {
- printk(KERN_ERR PFX "Relogin to the tgt\n");
- mutex_lock(&lport->disc.disc_mutex);
- lport->tt.rport_login(rdata);
- mutex_unlock(&lport->disc.disc_mutex);
- }
mutex_unlock(&hba->hba_mutex);
break;
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index 2c4562d..c2a6f9f 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -2283,7 +2283,6 @@ struct scsi_host_template csio_fcoe_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_lport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
- .use_blk_tags = 1,
};
struct scsi_host_template csio_fcoe_shost_vport_template = {
@@ -2303,7 +2302,6 @@ struct scsi_host_template csio_fcoe_shost_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_vport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
- .use_blk_tags = 1,
};
/*
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 31f8966..33581ba 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -256,7 +256,6 @@ static struct scsi_host_template driver_template = {
.proc_name = ESAS2R_DRVR_NAME,
.change_queue_depth = scsi_change_queue_depth,
.max_sectors = 0xFFFF,
- .use_blk_tags = 1,
};
int sgl_page_size = 512;
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 065b25d..71cb05b 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2694,7 +2694,6 @@ struct scsi_host_template scsi_esp_template = {
.use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xffff,
.skip_settle_delay = 1,
- .use_blk_tags = 1,
};
EXPORT_SYMBOL(scsi_esp_template);
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index d3eb80c..f442406 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -287,7 +287,6 @@ static struct scsi_host_template fcoe_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xffff,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -1873,7 +1872,6 @@ static int fcoe_percpu_receive_thread(void *arg)
set_user_nice(current, MIN_NICE);
-retry:
while (!kthread_should_stop()) {
spin_lock_bh(&p->fcoe_rx_list.lock);
@@ -1883,7 +1881,7 @@ retry:
set_current_state(TASK_INTERRUPTIBLE);
spin_unlock_bh(&p->fcoe_rx_list.lock);
schedule();
- goto retry;
+ continue;
}
spin_unlock_bh(&p->fcoe_rx_list.lock);
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 8a0d4d7..58ce902 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -118,7 +118,6 @@ static struct scsi_host_template fnic_host_template = {
.sg_tablesize = FNIC_MAX_SG_DESC_CNT,
.max_sectors = 0xffff,
.shost_attrs = fnic_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -697,13 +696,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
fnic->fnic_max_tag_id = host->can_queue;
- err = scsi_init_shared_tag_map(host, fnic->fnic_max_tag_id);
- if (err) {
- shost_printk(KERN_ERR, fnic->lport->host,
- "Unable to alloc shared tag map\n");
- goto err_out_dev_close;
- }
-
host->max_lun = fnic->config.luns_per_tgt;
host->max_id = FNIC_MAX_FCP_TARGET;
host->max_cmd_len = FCOE_MAX_CMD_LEN;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 8bb173e..82ac1cd 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -217,6 +217,13 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
error = scsi_mq_setup_tags(shost);
if (error)
goto fail;
+ } else {
+ shost->bqt = blk_init_tags(shost->can_queue,
+ shost->hostt->tag_alloc_policy);
+ if (!shost->bqt) {
+ error = -ENOMEM;
+ goto fail;
+ }
}
/*
@@ -326,6 +333,17 @@ static void scsi_host_dev_release(struct device *dev)
kfree(queuedata);
}
+ if (shost->shost_state == SHOST_CREATED) {
+ /*
+ * Free the shost_dev device name here if scsi_host_alloc()
+ * and scsi_host_put() have been called but neither
+ * scsi_host_add() nor scsi_host_remove() has been called.
+ * This avoids that the memory allocated for the shost_dev
+ * name is leaked.
+ */
+ kfree(dev_name(&shost->shost_dev));
+ }
+
scsi_destroy_command_freelist(shost);
if (shost_use_blk_mq(shost)) {
if (shost->tag_set.tags)
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 40669f8..a386036 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -41,6 +41,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_dbg.h>
#include <linux/cciss_ioctl.h>
#include <linux/string.h>
@@ -54,8 +55,11 @@
#include "hpsa_cmd.h"
#include "hpsa.h"
-/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */
-#define HPSA_DRIVER_VERSION "3.4.10-0"
+/*
+ * HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.'
+ * with an optional trailing '-' followed by a byte value (0-255).
+ */
+#define HPSA_DRIVER_VERSION "3.4.14-0"
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
@@ -205,6 +209,16 @@ static struct board_type products[] = {
{0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
+static struct scsi_transport_template *hpsa_sas_transport_template;
+static int hpsa_add_sas_host(struct ctlr_info *h);
+static void hpsa_delete_sas_host(struct ctlr_info *h);
+static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
+ struct hpsa_scsi_dev_t *device);
+static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device);
+static struct hpsa_scsi_dev_t
+ *hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
+ struct sas_rphy *rphy);
+
#define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy)
static const struct scsi_cmnd hpsa_cmd_busy;
#define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle)
@@ -230,6 +244,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
int cmd_type);
static void hpsa_free_cmd_pool(struct ctlr_info *h);
#define VPD_PAGE (1 << 8)
+#define HPSA_SIMPLE_ERROR_BITS 0x03
static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
@@ -243,7 +258,7 @@ static int hpsa_slave_alloc(struct scsi_device *sdev);
static int hpsa_slave_configure(struct scsi_device *sdev);
static void hpsa_slave_destroy(struct scsi_device *sdev);
-static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno);
+static void hpsa_update_scsi_devices(struct ctlr_info *h);
static int check_for_unit_attention(struct ctlr_info *h,
struct CommandList *c);
static void check_ioctl_unit_attention(struct ctlr_info *h,
@@ -274,7 +289,10 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
static void hpsa_command_resubmit_worker(struct work_struct *work);
static u32 lockup_detected(struct ctlr_info *h);
static int detect_controller_lockup(struct ctlr_info *h);
-static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device);
+static void hpsa_disable_rld_caching(struct ctlr_info *h);
+static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
+ struct ReportExtendedLUNdata *buf, int bufsize);
+static int hpsa_luns_changed(struct ctlr_info *h);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -606,7 +624,7 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
}
static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
- "1(+0)ADM", "UNKNOWN"
+ "1(+0)ADM", "UNKNOWN", "PHYS DRV"
};
#define HPSA_RAID_0 0
#define HPSA_RAID_4 1
@@ -615,7 +633,13 @@ static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
#define HPSA_RAID_51 4
#define HPSA_RAID_6 5 /* also used for RAID 60 */
#define HPSA_RAID_ADM 6 /* also used for RAID 1+0 ADM */
-#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1)
+#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 2)
+#define PHYSICAL_DRIVE (ARRAY_SIZE(raid_label) - 1)
+
+static inline bool is_logical_device(struct hpsa_scsi_dev_t *device)
+{
+ return !device->physical_device;
+}
static ssize_t raid_level_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -637,7 +661,7 @@ static ssize_t raid_level_show(struct device *dev,
}
/* Is this even a logical drive? */
- if (!is_logical_dev_addr_mode(hdev->scsi3addr)) {
+ if (!is_logical_device(hdev)) {
spin_unlock_irqrestore(&h->lock, flags);
l = snprintf(buf, PAGE_SIZE, "N/A\n");
return l;
@@ -726,7 +750,6 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev,
}
#define MAX_PATHS 8
-#define PATH_STRING_LEN 50
static ssize_t path_info_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -742,9 +765,7 @@ static ssize_t path_info_show(struct device *dev,
u8 path_map_index = 0;
char *active;
unsigned char phys_connector[2];
- unsigned char path[MAX_PATHS][PATH_STRING_LEN];
- memset(path, 0, MAX_PATHS * PATH_STRING_LEN);
sdev = to_scsi_device(dev);
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->devlock, flags);
@@ -764,18 +785,19 @@ static ssize_t path_info_show(struct device *dev,
else
continue;
- output_len = snprintf(path[i],
- PATH_STRING_LEN, "[%d:%d:%d:%d] %20.20s ",
+ output_len += scnprintf(buf + output_len,
+ PAGE_SIZE - output_len,
+ "[%d:%d:%d:%d] %20.20s ",
h->scsi_host->host_no,
hdev->bus, hdev->target, hdev->lun,
scsi_device_type(hdev->devtype));
- if (is_ext_target(h, hdev) ||
- (hdev->devtype == TYPE_RAID) ||
- is_logical_dev_addr_mode(hdev->scsi3addr)) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "%s\n",
- active);
+ if (hdev->external ||
+ hdev->devtype == TYPE_RAID ||
+ is_logical_device(hdev)) {
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len,
+ "%s\n", active);
continue;
}
@@ -787,36 +809,33 @@ static ssize_t path_info_show(struct device *dev,
if (phys_connector[1] < '0')
phys_connector[1] = '0';
if (hdev->phys_connector[i] > 0)
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"PORT: %.2s ",
phys_connector);
- if (hdev->devtype == TYPE_DISK &&
- hdev->expose_state != HPSA_DO_NOT_EXPOSE) {
+ if (hdev->devtype == TYPE_DISK && hdev->expose_device) {
if (box == 0 || box == 0xFF) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"BAY: %hhu %s\n",
bay, active);
} else {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN,
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len,
"BOX: %hhu BAY: %hhu %s\n",
box, bay, active);
}
} else if (box != 0 && box != 0xFF) {
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "BOX: %hhu %s\n",
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len, "BOX: %hhu %s\n",
box, active);
} else
- output_len += snprintf(path[i] + output_len,
- PATH_STRING_LEN, "%s\n", active);
+ output_len += snprintf(buf + output_len,
+ PAGE_SIZE - output_len, "%s\n", active);
}
spin_unlock_irqrestore(&h->devlock, flags);
- return snprintf(buf, output_len+1, "%s%s%s%s%s%s%s%s",
- path[0], path[1], path[2], path[3],
- path[4], path[5], path[6], path[7]);
+ return output_len;
}
static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL);
@@ -848,7 +867,6 @@ static struct device_attribute *hpsa_sdev_attrs[] = {
&dev_attr_unique_id,
&dev_attr_hp_ssd_smart_path_enabled,
&dev_attr_path_info,
- &dev_attr_lockup_detected,
NULL,
};
@@ -860,6 +878,7 @@ static struct device_attribute *hpsa_shost_attrs[] = {
&dev_attr_resettable,
&dev_attr_hp_ssd_smart_path_status,
&dev_attr_raid_offload_debug,
+ &dev_attr_lockup_detected,
NULL,
};
@@ -1134,25 +1153,62 @@ static int hpsa_find_target_lun(struct ctlr_info *h,
return !found;
}
-static inline void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
+static void hpsa_show_dev_msg(const char *level, struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev, char *description)
{
+#define LABEL_SIZE 25
+ char label[LABEL_SIZE];
+
+ if (h == NULL || h->pdev == NULL || h->scsi_host == NULL)
+ return;
+
+ switch (dev->devtype) {
+ case TYPE_RAID:
+ snprintf(label, LABEL_SIZE, "controller");
+ break;
+ case TYPE_ENCLOSURE:
+ snprintf(label, LABEL_SIZE, "enclosure");
+ break;
+ case TYPE_DISK:
+ if (dev->external)
+ snprintf(label, LABEL_SIZE, "external");
+ else if (!is_logical_dev_addr_mode(dev->scsi3addr))
+ snprintf(label, LABEL_SIZE, "%s",
+ raid_label[PHYSICAL_DRIVE]);
+ else
+ snprintf(label, LABEL_SIZE, "RAID-%s",
+ dev->raid_level > RAID_UNKNOWN ? "?" :
+ raid_label[dev->raid_level]);
+ break;
+ case TYPE_ROM:
+ snprintf(label, LABEL_SIZE, "rom");
+ break;
+ case TYPE_TAPE:
+ snprintf(label, LABEL_SIZE, "tape");
+ break;
+ case TYPE_MEDIUM_CHANGER:
+ snprintf(label, LABEL_SIZE, "changer");
+ break;
+ default:
+ snprintf(label, LABEL_SIZE, "UNKNOWN");
+ break;
+ }
+
dev_printk(level, &h->pdev->dev,
- "scsi %d:%d:%d:%d: %s %s %.8s %.16s RAID-%s SSDSmartPathCap%c En%c Exp=%d\n",
+ "scsi %d:%d:%d:%d: %s %s %.8s %.16s %s SSDSmartPathCap%c En%c Exp=%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun,
description,
scsi_device_type(dev->devtype),
dev->vendor,
dev->model,
- dev->raid_level > RAID_UNKNOWN ?
- "RAID-?" : raid_label[dev->raid_level],
+ label,
dev->offload_config ? '+' : '-',
dev->offload_enabled ? '+' : '-',
- dev->expose_state);
+ dev->expose_device);
}
/* Add an entry into h->dev[] array. */
-static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno,
+static int hpsa_scsi_add_entry(struct ctlr_info *h,
struct hpsa_scsi_dev_t *device,
struct hpsa_scsi_dev_t *added[], int *nadded)
{
@@ -1221,14 +1277,14 @@ lun_assigned:
added[*nadded] = device;
(*nadded)++;
hpsa_show_dev_msg(KERN_INFO, h, device,
- device->expose_state & HPSA_SCSI_ADD ? "added" : "masked");
+ device->expose_device ? "added" : "masked");
device->offload_to_be_enabled = device->offload_enabled;
device->offload_enabled = 0;
return 0;
}
/* Update an entry in h->dev[] array. */
-static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
+static void hpsa_scsi_update_entry(struct ctlr_info *h,
int entry, struct hpsa_scsi_dev_t *new_entry)
{
int offload_enabled;
@@ -1276,7 +1332,7 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
}
/* Replace an entry from h->dev[] array. */
-static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
+static void hpsa_scsi_replace_entry(struct ctlr_info *h,
int entry, struct hpsa_scsi_dev_t *new_entry,
struct hpsa_scsi_dev_t *added[], int *nadded,
struct hpsa_scsi_dev_t *removed[], int *nremoved)
@@ -1304,7 +1360,7 @@ static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno,
}
/* Remove an entry from h->dev[] array. */
-static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry,
+static void hpsa_scsi_remove_entry(struct ctlr_info *h, int entry,
struct hpsa_scsi_dev_t *removed[], int *nremoved)
{
/* assumes h->devlock is held */
@@ -1415,6 +1471,9 @@ static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle,
#define DEVICE_CHANGED 1
#define DEVICE_SAME 2
#define DEVICE_UPDATED 3
+ if (needle == NULL)
+ return DEVICE_NOT_FOUND;
+
for (i = 0; i < haystack_size; i++) {
if (haystack[i] == NULL) /* previously removed. */
continue;
@@ -1577,9 +1636,11 @@ static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h,
if (!logical_drive->offload_config)
continue;
for (j = 0; j < ndevices; j++) {
+ if (dev[j] == NULL)
+ continue;
if (dev[j]->devtype != TYPE_DISK)
continue;
- if (is_logical_dev_addr_mode(dev[j]->scsi3addr))
+ if (is_logical_device(dev[j]))
continue;
if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle)
continue;
@@ -1620,9 +1681,11 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
int i;
for (i = 0; i < ndevices; i++) {
+ if (dev[i] == NULL)
+ continue;
if (dev[i]->devtype != TYPE_DISK)
continue;
- if (!is_logical_dev_addr_mode(dev[i]->scsi3addr))
+ if (!is_logical_device(dev[i]))
continue;
/*
@@ -1638,7 +1701,50 @@ static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
}
}
-static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
+static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
+{
+ int rc = 0;
+
+ if (!h->scsi_host)
+ return 1;
+
+ if (is_logical_device(device)) /* RAID */
+ rc = scsi_add_device(h->scsi_host, device->bus,
+ device->target, device->lun);
+ else /* HBA */
+ rc = hpsa_add_sas_device(h->sas_host, device);
+
+ return rc;
+}
+
+static void hpsa_remove_device(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *device)
+{
+ struct scsi_device *sdev = NULL;
+
+ if (!h->scsi_host)
+ return;
+
+ if (is_logical_device(device)) { /* RAID */
+ sdev = scsi_device_lookup(h->scsi_host, device->bus,
+ device->target, device->lun);
+ if (sdev) {
+ scsi_remove_device(sdev);
+ scsi_device_put(sdev);
+ } else {
+ /*
+ * We don't expect to get here. Future commands
+ * to this device will get a selection timeout as
+ * if the device were gone.
+ */
+ hpsa_show_dev_msg(KERN_WARNING, h, device,
+ "didn't find device for removal.");
+ }
+ } else /* HBA */
+ hpsa_remove_sas_device(device);
+}
+
+static void adjust_hpsa_scsi_table(struct ctlr_info *h,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
/* sd contains scsi3 addresses and devtypes, and inquiry
@@ -1650,7 +1756,15 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
unsigned long flags;
struct hpsa_scsi_dev_t **added, **removed;
int nadded, nremoved;
- struct Scsi_Host *sh = NULL;
+
+ /*
+ * A reset can cause a device status to change
+ * re-schedule the scan to see what happened.
+ */
+ if (h->reset_in_progress) {
+ h->drv_req_rescan = 1;
+ return;
+ }
added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL);
removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -1678,19 +1792,18 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry);
if (device_change == DEVICE_NOT_FOUND) {
changes++;
- hpsa_scsi_remove_entry(h, hostno, i,
- removed, &nremoved);
+ hpsa_scsi_remove_entry(h, i, removed, &nremoved);
continue; /* remove ^^^, hence i not incremented */
} else if (device_change == DEVICE_CHANGED) {
changes++;
- hpsa_scsi_replace_entry(h, hostno, i, sd[entry],
+ hpsa_scsi_replace_entry(h, i, sd[entry],
added, &nadded, removed, &nremoved);
/* Set it to NULL to prevent it from being freed
* at the bottom of hpsa_update_scsi_devices()
*/
sd[entry] = NULL;
} else if (device_change == DEVICE_UPDATED) {
- hpsa_scsi_update_entry(h, hostno, i, sd[entry]);
+ hpsa_scsi_update_entry(h, i, sd[entry]);
}
i++;
}
@@ -1718,8 +1831,7 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
h->ndevices, &entry);
if (device_change == DEVICE_NOT_FOUND) {
changes++;
- if (hpsa_scsi_add_entry(h, hostno, sd[i],
- added, &nadded) != 0)
+ if (hpsa_scsi_add_entry(h, sd[i], added, &nadded) != 0)
break;
sd[i] = NULL; /* prevent from being freed later. */
} else if (device_change == DEVICE_CHANGED) {
@@ -1735,8 +1847,11 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
/* Now that h->dev[]->phys_disk[] is coherent, we can enable
* any logical drives that need it enabled.
*/
- for (i = 0; i < h->ndevices; i++)
+ for (i = 0; i < h->ndevices; i++) {
+ if (h->dev[i] == NULL)
+ continue;
h->dev[i]->offload_enabled = h->dev[i]->offload_to_be_enabled;
+ }
spin_unlock_irqrestore(&h->devlock, flags);
@@ -1755,47 +1870,37 @@ static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
* (or if there are no changes) scsi_scan_host will do it later the
* first time through.
*/
- if (hostno == -1 || !changes)
+ if (!changes)
goto free_and_out;
- sh = h->scsi_host;
/* Notify scsi mid layer of any removed devices */
for (i = 0; i < nremoved; i++) {
- if (removed[i]->expose_state & HPSA_SCSI_ADD) {
- struct scsi_device *sdev =
- scsi_device_lookup(sh, removed[i]->bus,
- removed[i]->target, removed[i]->lun);
- if (sdev != NULL) {
- scsi_remove_device(sdev);
- scsi_device_put(sdev);
- } else {
- /*
- * We don't expect to get here.
- * future cmds to this device will get selection
- * timeout as if the device was gone.
- */
- hpsa_show_dev_msg(KERN_WARNING, h, removed[i],
- "didn't find device for removal.");
- }
- }
+ if (removed[i] == NULL)
+ continue;
+ if (removed[i]->expose_device)
+ hpsa_remove_device(h, removed[i]);
kfree(removed[i]);
removed[i] = NULL;
}
/* Notify scsi mid layer of any added devices */
for (i = 0; i < nadded; i++) {
- if (!(added[i]->expose_state & HPSA_SCSI_ADD))
+ int rc = 0;
+
+ if (added[i] == NULL)
+ continue;
+ if (!(added[i]->expose_device))
continue;
- if (scsi_add_device(sh, added[i]->bus,
- added[i]->target, added[i]->lun) == 0)
+ rc = hpsa_add_device(h, added[i]);
+ if (!rc)
continue;
- hpsa_show_dev_msg(KERN_WARNING, h, added[i],
- "addition failed, device not added.");
+ dev_warn(&h->pdev->dev,
+ "addition failed %d, device not added.", rc);
/* now we have to remove it from h->dev,
* since it didn't get added to scsi mid layer
*/
fixup_botched_add(h, added[i]);
- added[i] = NULL;
+ h->drv_req_rescan = 1;
}
free_and_out:
@@ -1829,11 +1934,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev)
h = sdev_to_hba(sdev);
spin_lock_irqsave(&h->devlock, flags);
- sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
- sdev_id(sdev), sdev->lun);
- if (likely(sd)) {
+ if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) {
+ struct scsi_target *starget;
+ struct sas_rphy *rphy;
+
+ starget = scsi_target(sdev);
+ rphy = target_to_rphy(starget);
+ sd = hpsa_find_device_by_sas_rphy(h, rphy);
+ if (sd) {
+ sd->target = sdev_id(sdev);
+ sd->lun = sdev->lun;
+ }
+ } else
+ sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
+ sdev_id(sdev), sdev->lun);
+
+ if (sd && sd->expose_device) {
atomic_set(&sd->ioaccel_cmds_out, 0);
- sdev->hostdata = (sd->expose_state & HPSA_SCSI_ADD) ? sd : NULL;
+ sdev->hostdata = sd;
} else
sdev->hostdata = NULL;
spin_unlock_irqrestore(&h->devlock, flags);
@@ -1847,7 +1965,7 @@ static int hpsa_slave_configure(struct scsi_device *sdev)
int queue_depth;
sd = sdev->hostdata;
- sdev->no_uld_attach = !sd || !(sd->expose_state & HPSA_ULD_ATTACH);
+ sdev->no_uld_attach = !sd || !sd->expose_device;
if (sd)
queue_depth = sd->queue_depth != 0 ?
@@ -1955,7 +2073,7 @@ static int hpsa_map_ioaccel2_sg_chain_block(struct ctlr_info *h,
u32 chain_size;
chain_block = h->ioaccel2_cmd_sg_list[c->cmdindex];
- chain_size = le32_to_cpu(cp->data_len);
+ chain_size = le32_to_cpu(cp->sg[0].length);
temp64 = pci_map_single(h->pdev, chain_block, chain_size,
PCI_DMA_TODEVICE);
if (dma_mapping_error(&h->pdev->dev, temp64)) {
@@ -1976,7 +2094,7 @@ static void hpsa_unmap_ioaccel2_sg_chain_block(struct ctlr_info *h,
chain_sg = cp->sg;
temp64 = le64_to_cpu(chain_sg->address);
- chain_size = le32_to_cpu(cp->data_len);
+ chain_size = le32_to_cpu(cp->sg[0].length);
pci_unmap_single(h->pdev, temp64, chain_size, PCI_DMA_TODEVICE);
}
@@ -2210,7 +2328,7 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
* the normal I/O path so the controller can handle whatever's
* wrong.
*/
- if (is_logical_dev_addr_mode(dev->scsi3addr) &&
+ if (is_logical_device(dev) &&
c2->error_data.serv_response ==
IOACCEL2_SERV_RESPONSE_FAILURE) {
if (c2->error_data.status ==
@@ -2330,7 +2448,7 @@ static void complete_scsi_command(struct CommandList *cp)
* the normal I/O path so the controller can handle whatever's
* wrong.
*/
- if (is_logical_dev_addr_mode(dev->scsi3addr)) {
+ if (is_logical_device(dev)) {
if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
dev->offload_enabled = 0;
return hpsa_retry_cmd(h, cp);
@@ -2709,9 +2827,8 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
/* fill_cmd can't fail here, no data buffer to map. */
- (void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
+ (void) fill_cmd(c, reset_type, h, NULL, 0, 0,
scsi3addr, TYPE_MSG);
- c->Request.CDB[1] = reset_type; /* fill_cmd defaults to LUN reset */
rc = hpsa_scsi_do_simple_cmd(h, c, reply_queue, NO_TIMEOUT);
if (rc) {
dev_warn(&h->pdev->dev, "Failed to send reset command\n");
@@ -2984,6 +3101,66 @@ out:
return rc;
}
+static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h,
+ unsigned char scsi3addr[], u16 bmic_device_index,
+ struct bmic_sense_subsystem_info *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ c->Request.CDB[2] = bmic_device_index & 0xff;
+ c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if (rc)
+ goto out;
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
+static int hpsa_bmic_id_controller(struct ctlr_info *h,
+ struct bmic_identify_controller *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+
+ rc = fill_cmd(c, BMIC_IDENTIFY_CONTROLLER, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if (rc)
+ goto out;
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
unsigned char scsi3addr[], u16 bmic_device_index,
struct bmic_identify_physical_device *buf, size_t bufsize)
@@ -3010,9 +3187,71 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
}
out:
cmd_free(h, c);
+
return rc;
}
+static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h,
+ unsigned char *scsi3addr)
+{
+ struct ReportExtendedLUNdata *physdev;
+ u32 nphysicals;
+ u64 sa = 0;
+ int i;
+
+ physdev = kzalloc(sizeof(*physdev), GFP_KERNEL);
+ if (!physdev)
+ return 0;
+
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) {
+ dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
+ kfree(physdev);
+ return 0;
+ }
+ nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24;
+
+ for (i = 0; i < nphysicals; i++)
+ if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) {
+ sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]);
+ break;
+ }
+
+ kfree(physdev);
+
+ return sa;
+}
+
+static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr,
+ struct hpsa_scsi_dev_t *dev)
+{
+ int rc;
+ u64 sa = 0;
+
+ if (is_hba_lunid(scsi3addr)) {
+ struct bmic_sense_subsystem_info *ssi;
+
+ ssi = kzalloc(sizeof(*ssi), GFP_KERNEL);
+ if (ssi == NULL) {
+ dev_warn(&h->pdev->dev,
+ "%s: out of memory\n", __func__);
+ return;
+ }
+
+ rc = hpsa_bmic_sense_subsystem_information(h,
+ scsi3addr, 0, ssi, sizeof(*ssi));
+ if (rc == 0) {
+ sa = get_unaligned_be64(ssi->primary_world_wide_id);
+ h->sas_address = sa;
+ }
+
+ kfree(ssi);
+ } else
+ sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr);
+
+ dev->sas_address = sa;
+}
+
+/* Get a device id from inquiry page 0x83 */
static int hpsa_vpd_page_supported(struct ctlr_info *h,
unsigned char scsi3addr[], u8 page)
{
@@ -3097,7 +3336,7 @@ out:
/* Get the device id from inquiry page 0x83 */
static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
- unsigned char *device_id, int buflen)
+ unsigned char *device_id, int index, int buflen)
{
int rc;
unsigned char *buf;
@@ -3109,8 +3348,10 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
return -ENOMEM;
rc = hpsa_scsi_do_inquiry(h, scsi3addr, VPD_PAGE | 0x83, buf, 64);
if (rc == 0)
- memcpy(device_id, &buf[8], buflen);
+ memcpy(device_id, &buf[index], buflen);
+
kfree(buf);
+
return rc != 0;
}
@@ -3339,6 +3580,18 @@ static int hpsa_device_supports_aborts(struct ctlr_info *h,
return rc;
}
+static void sanitize_inquiry_string(unsigned char *s, int len)
+{
+ bool terminated = false;
+
+ for (; len > 0; (--len, ++s)) {
+ if (*s == 0)
+ terminated = true;
+ if (terminated || *s < 0x20 || *s > 0x7e)
+ *s = ' ';
+ }
+}
+
static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device,
unsigned char *is_OBDR_device)
@@ -3351,10 +3604,13 @@ static int hpsa_update_device_info(struct ctlr_info *h,
unsigned char *inq_buff;
unsigned char *obdr_sig;
+ int rc = 0;
inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL);
- if (!inq_buff)
+ if (!inq_buff) {
+ rc = -ENOMEM;
goto bail_out;
+ }
/* Do an inquiry to the device to see what it is. */
if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff,
@@ -3362,9 +3618,13 @@ static int hpsa_update_device_info(struct ctlr_info *h,
/* Inquiry failed (msg printed already) */
dev_err(&h->pdev->dev,
"hpsa_update_device_info: inquiry failed\n");
+ rc = -EIO;
goto bail_out;
}
+ sanitize_inquiry_string(&inq_buff[8], 8);
+ sanitize_inquiry_string(&inq_buff[16], 16);
+
this_device->devtype = (inq_buff[0] & 0x1f);
memcpy(this_device->scsi3addr, scsi3addr, 8);
memcpy(this_device->vendor, &inq_buff[8],
@@ -3373,7 +3633,7 @@ static int hpsa_update_device_info(struct ctlr_info *h,
sizeof(this_device->model));
memset(this_device->device_id, 0,
sizeof(this_device->device_id));
- hpsa_get_device_id(h, scsi3addr, this_device->device_id,
+ hpsa_get_device_id(h, scsi3addr, this_device->device_id, 8,
sizeof(this_device->device_id));
if (this_device->devtype == TYPE_DISK &&
@@ -3411,7 +3671,7 @@ static int hpsa_update_device_info(struct ctlr_info *h,
bail_out:
kfree(inq_buff);
- return 1;
+ return rc;
}
static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
@@ -3439,115 +3699,39 @@ static void hpsa_update_device_supports_aborts(struct ctlr_info *h,
}
}
-static unsigned char *ext_target_model[] = {
- "MSA2012",
- "MSA2024",
- "MSA2312",
- "MSA2324",
- "P2000 G3 SAS",
- "MSA 2040 SAS",
- NULL,
-};
-
-static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device)
-{
- int i;
-
- for (i = 0; ext_target_model[i]; i++)
- if (strncmp(device->model, ext_target_model[i],
- strlen(ext_target_model[i])) == 0)
- return 1;
- return 0;
-}
-
-/* Helper function to assign bus, target, lun mapping of devices.
- * Puts non-external target logical volumes on bus 0, external target logical
- * volumes on bus 1, physical devices on bus 2. and the hba on bus 3.
+/*
+ * Helper function to assign bus, target, lun mapping of devices.
* Logical drive target and lun are assigned at this time, but
* physical device lun and target assignment are deferred (assigned
* in hpsa_find_target_lun, called by hpsa_scsi_add_entry.)
- */
+*/
static void figure_bus_target_lun(struct ctlr_info *h,
u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device)
{
- u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes));
+ u32 lunid = get_unaligned_le32(lunaddrbytes);
if (!is_logical_dev_addr_mode(lunaddrbytes)) {
/* physical device, target and lun filled in later */
if (is_hba_lunid(lunaddrbytes))
- hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff);
+ hpsa_set_bus_target_lun(device,
+ HPSA_HBA_BUS, 0, lunid & 0x3fff);
else
/* defer target, lun assignment for physical devices */
- hpsa_set_bus_target_lun(device, 2, -1, -1);
+ hpsa_set_bus_target_lun(device,
+ HPSA_PHYSICAL_DEVICE_BUS, -1, -1);
return;
}
/* It's a logical device */
- if (is_ext_target(h, device)) {
- /* external target way, put logicals on bus 1
- * and match target/lun numbers box
- * reports, other smart array, bus 0, target 0, match lunid
- */
+ if (device->external) {
hpsa_set_bus_target_lun(device,
- 1, (lunid >> 16) & 0x3fff, lunid & 0x00ff);
+ HPSA_EXTERNAL_RAID_VOLUME_BUS, (lunid >> 16) & 0x3fff,
+ lunid & 0x00ff);
return;
}
- hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff);
+ hpsa_set_bus_target_lun(device, HPSA_RAID_VOLUME_BUS,
+ 0, lunid & 0x3fff);
}
-/*
- * If there is no lun 0 on a target, linux won't find any devices.
- * For the external targets (arrays), we have to manually detect the enclosure
- * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report
- * it for some reason. *tmpdevice is the target we're adding,
- * this_device is a pointer into the current element of currentsd[]
- * that we're building up in update_scsi_devices(), below.
- * lunzerobits is a bitmap that tracks which targets already have a
- * lun 0 assigned.
- * Returns 1 if an enclosure was added, 0 if not.
- */
-static int add_ext_target_dev(struct ctlr_info *h,
- struct hpsa_scsi_dev_t *tmpdevice,
- struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes,
- unsigned long lunzerobits[], int *n_ext_target_devs)
-{
- unsigned char scsi3addr[8];
-
- if (test_bit(tmpdevice->target, lunzerobits))
- return 0; /* There is already a lun 0 on this target. */
-
- if (!is_logical_dev_addr_mode(lunaddrbytes))
- return 0; /* It's the logical targets that may lack lun 0. */
-
- if (!is_ext_target(h, tmpdevice))
- return 0; /* Only external target devices have this problem. */
-
- if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */
- return 0;
-
- memset(scsi3addr, 0, 8);
- scsi3addr[3] = tmpdevice->target;
- if (is_hba_lunid(scsi3addr))
- return 0; /* Don't add the RAID controller here. */
-
- if (is_scsi_rev_5(h))
- return 0; /* p1210m doesn't need to do this. */
-
- if (*n_ext_target_devs >= MAX_EXT_TARGETS) {
- dev_warn(&h->pdev->dev, "Maximum number of external "
- "target devices exceeded. Check your hardware "
- "configuration.");
- return 0;
- }
-
- if (hpsa_update_device_info(h, scsi3addr, this_device, NULL))
- return 0;
- (*n_ext_target_devs)++;
- hpsa_set_bus_target_lun(this_device,
- tmpdevice->bus, tmpdevice->target, 0);
- hpsa_update_device_supports_aborts(h, this_device, scsi3addr);
- set_bit(tmpdevice->target, lunzerobits);
- return 1;
-}
/*
* Get address of physical disk used for an ioaccel2 mode command:
@@ -3577,6 +3761,27 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
return 0;
}
+static int figure_external_status(struct ctlr_info *h, int raid_ctlr_position,
+ int i, int nphysicals, int nlocal_logicals)
+{
+ /* In report logicals, local logicals are listed first,
+ * then any externals.
+ */
+ int logicals_start = nphysicals + (raid_ctlr_position == 0);
+
+ if (i == raid_ctlr_position)
+ return 0;
+
+ if (i < logicals_start)
+ return 0;
+
+ /* i is in logicals range, but still within local logicals */
+ if ((i - nphysicals - (raid_ctlr_position == 0)) < nlocal_logicals)
+ return 0;
+
+ return 1; /* it's an external lun */
+}
+
/*
* Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev,
* logdev. The number of luns in physdev and logdev are returned in
@@ -3650,19 +3855,18 @@ static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position,
/* get physical drive ioaccel handle and queue depth */
static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev,
- u8 *lunaddrbytes,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
struct bmic_identify_physical_device *id_phys)
{
int rc;
- struct ext_report_lun_entry *rle =
- (struct ext_report_lun_entry *) lunaddrbytes;
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
dev->ioaccel_handle = rle->ioaccel_handle;
- if (PHYS_IOACCEL(lunaddrbytes) && dev->ioaccel_handle)
+ if ((rle->device_flags & 0x08) && dev->ioaccel_handle)
dev->hba_ioaccel_enabled = 1;
memset(id_phys, 0, sizeof(*id_phys));
- rc = hpsa_bmic_id_physical_device(h, lunaddrbytes,
- GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys,
+ rc = hpsa_bmic_id_physical_device(h, &rle->lunid[0],
+ GET_BMIC_DRIVE_NUMBER(&rle->lunid[0]), id_phys,
sizeof(*id_phys));
if (!rc)
/* Reserve space for FW operations */
@@ -3673,16 +3877,15 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
DRIVE_CMDS_RESERVED_FOR_FW;
else
dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */
- atomic_set(&dev->ioaccel_cmds_out, 0);
- atomic_set(&dev->reset_cmds_out, 0);
}
static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
- u8 *lunaddrbytes,
+ struct ReportExtendedLUNdata *rlep, int rle_index,
struct bmic_identify_physical_device *id_phys)
{
- if (PHYS_IOACCEL(lunaddrbytes)
- && this_device->ioaccel_handle)
+ struct ext_report_lun_entry *rle = &rlep->LUN[rle_index];
+
+ if ((rle->device_flags & 0x08) && this_device->ioaccel_handle)
this_device->hba_ioaccel_enabled = 1;
memcpy(&this_device->active_path_index,
@@ -3702,7 +3905,33 @@ static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device,
sizeof(this_device->bay));
}
-static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
+/* get number of local logical disks. */
+static int hpsa_set_local_logical_count(struct ctlr_info *h,
+ struct bmic_identify_controller *id_ctlr,
+ u32 *nlocals)
+{
+ int rc;
+
+ if (!id_ctlr) {
+ dev_warn(&h->pdev->dev, "%s: id_ctlr buffer is NULL.\n",
+ __func__);
+ return -ENOMEM;
+ }
+ memset(id_ctlr, 0, sizeof(*id_ctlr));
+ rc = hpsa_bmic_id_controller(h, id_ctlr, sizeof(*id_ctlr));
+ if (!rc)
+ if (id_ctlr->configured_logical_drive_count < 256)
+ *nlocals = id_ctlr->configured_logical_drive_count;
+ else
+ *nlocals = le16_to_cpu(
+ id_ctlr->extended_logical_unit_count);
+ else
+ *nlocals = -1;
+ return rc;
+}
+
+
+static void hpsa_update_scsi_devices(struct ctlr_info *h)
{
/* the idea here is we could get notified
* that some devices have changed, so we do a report
@@ -3717,13 +3946,16 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
struct bmic_identify_physical_device *id_phys = NULL;
+ struct bmic_identify_controller *id_ctlr = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
+ u32 nlocal_logicals = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
+ bool physical_device;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
@@ -3731,17 +3963,29 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
+ id_ctlr = kzalloc(sizeof(*id_ctlr), GFP_KERNEL);
if (!currentsd || !physdev_list || !logdev_list ||
- !tmpdevice || !id_phys) {
+ !tmpdevice || !id_phys || !id_ctlr) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
memset(lunzerobits, 0, sizeof(lunzerobits));
+ h->drv_req_rescan = 0; /* cancel scheduled rescan - we're doing it. */
+
if (hpsa_gather_lun_info(h, physdev_list, &nphysicals,
- logdev_list, &nlogicals))
+ logdev_list, &nlogicals)) {
+ h->drv_req_rescan = 1;
goto out;
+ }
+
+ /* Set number of local logicals (non PTRAID) */
+ if (hpsa_set_local_logical_count(h, id_ctlr, &nlocal_logicals)) {
+ dev_warn(&h->pdev->dev,
+ "%s: Can't determine number of local logical devices.\n",
+ __func__);
+ }
/* We might see up to the maximum number of logical and physical disks
* plus external target devices, and a device for the local RAID
@@ -3762,6 +4006,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (!currentsd[i]) {
dev_warn(&h->pdev->dev, "out of memory at %s:%d\n",
__FILE__, __LINE__);
+ h->drv_req_rescan = 1;
goto out;
}
ndev_allocated++;
@@ -3776,49 +4021,74 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
n_ext_target_devs = 0;
for (i = 0; i < nphysicals + nlogicals + 1; i++) {
u8 *lunaddrbytes, is_OBDR = 0;
+ int rc = 0;
+ int phys_dev_index = i - (raid_ctlr_position == 0);
+
+ physical_device = i < nphysicals + (raid_ctlr_position == 0);
/* Figure out where the LUN ID info is coming from */
lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position,
i, nphysicals, nlogicals, physdev_list, logdev_list);
/* skip masked non-disk devices */
- if (MASKED_DEVICE(lunaddrbytes))
- if (i < nphysicals + (raid_ctlr_position == 0) &&
- NON_DISK_PHYS_DEV(lunaddrbytes))
- continue;
+ if (MASKED_DEVICE(lunaddrbytes) && physical_device &&
+ (physdev_list->LUN[phys_dev_index].device_flags & 0x01))
+ continue;
/* Get device type, vendor, model, device id */
- if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
- &is_OBDR))
- continue; /* skip it if we can't talk to it. */
+ rc = hpsa_update_device_info(h, lunaddrbytes, tmpdevice,
+ &is_OBDR);
+ if (rc == -ENOMEM) {
+ dev_warn(&h->pdev->dev,
+ "Out of memory, rescan deferred.\n");
+ h->drv_req_rescan = 1;
+ goto out;
+ }
+ if (rc) {
+ dev_warn(&h->pdev->dev,
+ "Inquiry failed, skipping device.\n");
+ continue;
+ }
+
+ /* Determine if this is a lun from an external target array */
+ tmpdevice->external =
+ figure_external_status(h, raid_ctlr_position, i,
+ nphysicals, nlocal_logicals);
+
figure_bus_target_lun(h, lunaddrbytes, tmpdevice);
hpsa_update_device_supports_aborts(h, tmpdevice, lunaddrbytes);
this_device = currentsd[ncurrent];
- /*
- * For external target devices, we have to insert a LUN 0 which
- * doesn't show up in CCISS_REPORT_PHYSICAL data, but there
- * is nonetheless an enclosure device there. We have to
- * present that otherwise linux won't find anything if
- * there is no lun 0.
+ /* Turn on discovery_polling if there are ext target devices.
+ * Event-based change notification is unreliable for those.
*/
- if (add_ext_target_dev(h, tmpdevice, this_device,
- lunaddrbytes, lunzerobits,
- &n_ext_target_devs)) {
- ncurrent++;
- this_device = currentsd[ncurrent];
+ if (!h->discovery_polling) {
+ if (tmpdevice->external) {
+ h->discovery_polling = 1;
+ dev_info(&h->pdev->dev,
+ "External target, activate discovery polling.\n");
+ }
}
+
*this_device = *tmpdevice;
+ this_device->physical_device = physical_device;
+
+ /*
+ * Expose all devices except for physical devices that
+ * are masked.
+ */
+ if (MASKED_DEVICE(lunaddrbytes) && this_device->physical_device)
+ this_device->expose_device = 0;
+ else
+ this_device->expose_device = 1;
- /* do not expose masked devices */
- if (MASKED_DEVICE(lunaddrbytes) &&
- i < nphysicals + (raid_ctlr_position == 0)) {
- this_device->expose_state = HPSA_DO_NOT_EXPOSE;
- } else {
- this_device->expose_state =
- HPSA_SG_ATTACH | HPSA_ULD_ATTACH;
- }
+
+ /*
+ * Get the SAS address for physical devices that are exposed.
+ */
+ if (this_device->physical_device && this_device->expose_device)
+ hpsa_get_sas_address(h, lunaddrbytes, this_device);
switch (this_device->devtype) {
case TYPE_ROM:
@@ -3833,14 +4103,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
case TYPE_DISK:
- if (i < nphysicals + (raid_ctlr_position == 0)) {
+ if (this_device->physical_device) {
/* The disk is in HBA mode. */
/* Never use RAID mapper in HBA mode. */
this_device->offload_enabled = 0;
hpsa_get_ioaccel_drive_info(h, this_device,
- lunaddrbytes, id_phys);
- hpsa_get_path_info(this_device, lunaddrbytes,
- id_phys);
+ physdev_list, phys_dev_index, id_phys);
+ hpsa_get_path_info(this_device,
+ physdev_list, phys_dev_index, id_phys);
}
ncurrent++;
break;
@@ -3865,7 +4135,19 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (ncurrent >= HPSA_MAX_DEVICES)
break;
}
- adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent);
+
+ if (h->sas_host == NULL) {
+ int rc = 0;
+
+ rc = hpsa_add_sas_host(h);
+ if (rc) {
+ dev_warn(&h->pdev->dev,
+ "Could not add sas host %d\n", rc);
+ goto out;
+ }
+ }
+
+ adjust_hpsa_scsi_table(h, currentsd, ncurrent);
out:
kfree(tmpdevice);
for (i = 0; i < ndev_allocated; i++)
@@ -3873,6 +4155,7 @@ out:
kfree(currentsd);
kfree(physdev_list);
kfree(logdev_list);
+ kfree(id_ctlr);
kfree(id_phys);
}
@@ -3978,19 +4261,14 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
case READ_6:
case READ_12:
if (*cdb_len == 6) {
- block = (((u32) cdb[2]) << 8) | cdb[3];
+ block = get_unaligned_be16(&cdb[2]);
block_cnt = cdb[4];
+ if (block_cnt == 0)
+ block_cnt = 256;
} else {
BUG_ON(*cdb_len != 12);
- block = (((u32) cdb[2]) << 24) |
- (((u32) cdb[3]) << 16) |
- (((u32) cdb[4]) << 8) |
- cdb[5];
- block_cnt =
- (((u32) cdb[6]) << 24) |
- (((u32) cdb[7]) << 16) |
- (((u32) cdb[8]) << 8) |
- cdb[9];
+ block = get_unaligned_be32(&cdb[2]);
+ block_cnt = get_unaligned_be32(&cdb[6]);
}
if (block_cnt > 0xffff)
return IO_ACCEL_INELIGIBLE;
@@ -4272,6 +4550,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
/* fill in sg elements */
if (use_sg > h->ioaccel_maxsg) {
cp->sg_count = 1;
+ cp->sg[0].length = cpu_to_le32(use_sg * sizeof(cp->sg[0]));
if (hpsa_map_ioaccel2_sg_chain_block(h, cp, c)) {
atomic_dec(&phys_disk->ioaccel_cmds_out);
scsi_dma_unmap(cmd);
@@ -4376,9 +4655,7 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
case WRITE_6:
is_write = 1;
case READ_6:
- first_block =
- (((u64) cmd->cmnd[2]) << 8) |
- cmd->cmnd[3];
+ first_block = get_unaligned_be16(&cmd->cmnd[2]);
block_cnt = cmd->cmnd[4];
if (block_cnt == 0)
block_cnt = 256;
@@ -4947,7 +5224,7 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
if (unlikely(lockup_detected(h)))
return hpsa_scan_complete(h);
- hpsa_update_scsi_devices(h, h->scsi_host->host_no);
+ hpsa_update_scsi_devices(h);
hpsa_scan_complete(h);
}
@@ -4983,7 +5260,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh,
static int hpsa_scsi_host_alloc(struct ctlr_info *h)
{
struct Scsi_Host *sh;
- int error;
sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h));
if (sh == NULL) {
@@ -5001,17 +5277,11 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h)
sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS;
sh->cmd_per_lun = sh->can_queue;
sh->sg_tablesize = h->maxsgentries;
+ sh->transportt = hpsa_sas_transport_template;
sh->hostdata[0] = (unsigned long) h;
sh->irq = h->intr[h->intr_mode];
sh->unique_id = sh->irq;
- error = scsi_init_shared_tag_map(sh, sh->can_queue);
- if (error) {
- dev_err(&h->pdev->dev,
- "%s: scsi_init_shared_tag_map failed for controller %d\n",
- __func__, h->ctlr);
- scsi_host_put(sh);
- return error;
- }
+
h->scsi_host = sh;
return 0;
}
@@ -5167,6 +5437,7 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
int rc;
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
+ u8 reset_type;
char msg[48];
/* find the controller to which the command to be aborted was sent */
@@ -5205,14 +5476,25 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
if (is_hba_lunid(dev->scsi3addr))
return SUCCESS;
- hpsa_show_dev_msg(KERN_WARNING, h, dev, "resetting");
+ if (is_logical_dev_addr_mode(dev->scsi3addr))
+ reset_type = HPSA_DEVICE_RESET_MSG;
+ else
+ reset_type = HPSA_PHYS_TARGET_RESET;
+
+ sprintf(msg, "resetting %s",
+ reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ");
+ hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+
+ h->reset_in_progress = 1;
/* send a reset to the SCSI LUN which the command was sent to */
- rc = hpsa_do_reset(h, dev, dev->scsi3addr, HPSA_RESET_TYPE_LUN,
+ rc = hpsa_do_reset(h, dev, dev->scsi3addr, reset_type,
DEFAULT_REPLY_QUEUE);
- snprintf(msg, sizeof(msg), "reset %s",
- rc == 0 ? "completed successfully" : "failed");
+ sprintf(msg, "reset %s %s",
+ reset_type == HPSA_DEVICE_RESET_MSG ? "logical " : "physical ",
+ rc == 0 ? "completed successfully" : "failed");
hpsa_show_dev_msg(KERN_WARNING, h, dev, msg);
+ h->reset_in_progress = 0;
return rc == 0 ? SUCCESS : FAILED;
}
@@ -6270,6 +6552,24 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[8] = (size >> 8) & 0xFF;
c->Request.CDB[9] = size & 0xFF;
break;
+ case BMIC_SENSE_DIAG_OPTIONS:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ /* Spec says this should be BMIC_WRITE */
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_DIAG_OPTIONS;
+ break;
+ case BMIC_SET_DIAG_OPTIONS:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type,
+ ATTR_SIMPLE, XFER_WRITE);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_WRITE;
+ c->Request.CDB[6] = BMIC_SET_DIAG_OPTIONS;
+ break;
case HPSA_CACHE_FLUSH:
c->Request.CDBLen = 12;
c->Request.type_attr_dir =
@@ -6319,6 +6619,32 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0XFF;
break;
+ case BMIC_SENSE_SUBSYSTEM_INFORMATION:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
+ case BMIC_IDENTIFY_CONTROLLER:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = 0;
+ c->Request.CDB[3] = 0;
+ c->Request.CDB[4] = 0;
+ c->Request.CDB[5] = 0;
+ c->Request.CDB[6] = BMIC_IDENTIFY_CONTROLLER;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ c->Request.CDB[9] = 0;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -6327,6 +6653,20 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
} else if (cmd_type == TYPE_MSG) {
switch (cmd) {
+ case HPSA_PHYS_TARGET_RESET:
+ c->Request.CDBLen = 16;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
+ c->Request.Timeout = 0; /* Don't time out */
+ memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
+ c->Request.CDB[0] = HPSA_RESET;
+ c->Request.CDB[1] = HPSA_TARGET_RESET_TYPE;
+ /* Physical target reset needs no control bytes 4-7*/
+ c->Request.CDB[4] = 0x00;
+ c->Request.CDB[5] = 0x00;
+ c->Request.CDB[6] = 0x00;
+ c->Request.CDB[7] = 0x00;
+ break;
case HPSA_DEVICE_RESET_MSG:
c->Request.CDBLen = 16;
c->Request.type_attr_dir =
@@ -6440,16 +6780,6 @@ static inline void finish_cmd(struct CommandList *c)
complete(c->waiting);
}
-
-static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag)
-{
-#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1)
-#define HPSA_SIMPLE_ERROR_BITS 0x03
- if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant)))
- return tag & ~HPSA_SIMPLE_ERROR_BITS;
- return tag & ~HPSA_PERF_ERROR_BITS;
-}
-
/* process completion of an indexed ("direct lookup") command */
static inline void process_indexed_cmd(struct ctlr_info *h,
u32 raw_tag)
@@ -7860,6 +8190,11 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h)
*/
static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
{
+ if (h->drv_req_rescan) {
+ h->drv_req_rescan = 0;
+ return 1;
+ }
+
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
return 0;
@@ -7893,6 +8228,41 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h)
return 0;
}
+static int hpsa_luns_changed(struct ctlr_info *h)
+{
+ int rc = 1; /* assume there are changes */
+ struct ReportLUNdata *logdev = NULL;
+
+ /* if we can't find out if lun data has changed,
+ * assume that it has.
+ */
+
+ if (!h->lastlogicals)
+ goto out;
+
+ logdev = kzalloc(sizeof(*logdev), GFP_KERNEL);
+ if (!logdev) {
+ dev_warn(&h->pdev->dev,
+ "Out of memory, can't track lun changes.\n");
+ goto out;
+ }
+ if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) {
+ dev_warn(&h->pdev->dev,
+ "report luns failed, can't track lun changes.\n");
+ goto out;
+ }
+ if (memcmp(logdev, h->lastlogicals, sizeof(*logdev))) {
+ dev_info(&h->pdev->dev,
+ "Lun changes detected.\n");
+ memcpy(h->lastlogicals, logdev, sizeof(*logdev));
+ goto out;
+ } else
+ rc = 0; /* no changes detected. */
+out:
+ kfree(logdev);
+ return rc;
+}
+
static void hpsa_rescan_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
@@ -7908,6 +8278,19 @@ static void hpsa_rescan_ctlr_worker(struct work_struct *work)
hpsa_ack_ctlr_events(h);
hpsa_scan_start(h->scsi_host);
scsi_host_put(h->scsi_host);
+ } else if (h->discovery_polling) {
+ hpsa_disable_rld_caching(h);
+ if (hpsa_luns_changed(h)) {
+ struct Scsi_Host *sh = NULL;
+
+ dev_info(&h->pdev->dev,
+ "driver discovery polling rescan.\n");
+ sh = scsi_host_get(h->scsi_host);
+ if (sh != NULL) {
+ hpsa_scan_start(sh);
+ scsi_host_put(sh);
+ }
+ }
}
spin_lock_irqsave(&h->lock, flags);
if (!h->remove_in_progress)
@@ -8148,6 +8531,8 @@ reinit_after_soft_reset:
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
+ /* Disable discovery polling.*/
+ h->discovery_polling = 0;
/* Turn the interrupts on so we can service requests */
@@ -8155,6 +8540,11 @@ reinit_after_soft_reset:
hpsa_hba_inquiry(h);
+ h->lastlogicals = kzalloc(sizeof(*(h->lastlogicals)), GFP_KERNEL);
+ if (!h->lastlogicals)
+ dev_info(&h->pdev->dev,
+ "Can't track change to report lun data\n");
+
/* Monitor the controller for firmware lockups */
h->heartbeat_sample_interval = HEARTBEAT_SAMPLE_INTERVAL;
INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
@@ -8227,6 +8617,71 @@ out:
kfree(flush_buf);
}
+/* Make controller gather fresh report lun data each time we
+ * send down a report luns request
+ */
+static void hpsa_disable_rld_caching(struct ctlr_info *h)
+{
+ u32 *options;
+ struct CommandList *c;
+ int rc;
+
+ /* Don't bother trying to set diag options if locked up */
+ if (unlikely(h->lockup_detected))
+ return;
+
+ options = kzalloc(sizeof(*options), GFP_KERNEL);
+ if (!options) {
+ dev_err(&h->pdev->dev,
+ "Error: failed to disable rld caching, during alloc.\n");
+ return;
+ }
+
+ c = cmd_alloc(h);
+
+ /* first, get the current diag options settings */
+ if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ /* Now, set the bit for disabling the RLD caching */
+ *options |= HPSA_DIAG_OPTS_DISABLE_RLD_CACHING;
+
+ if (fill_cmd(c, BMIC_SET_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_TODEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ /* Now verify that it got set: */
+ if (fill_cmd(c, BMIC_SENSE_DIAG_OPTIONS, h, options, 4, 0,
+ RAID_CTLR_LUNID, TYPE_CMD))
+ goto errout;
+
+ rc = hpsa_scsi_do_simple_cmd_with_retry(h, c,
+ PCI_DMA_FROMDEVICE, NO_TIMEOUT);
+ if ((rc != 0) || (c->err_info->CommandStatus != 0))
+ goto errout;
+
+ if (*options & HPSA_DIAG_OPTS_DISABLE_RLD_CACHING)
+ goto out;
+
+errout:
+ dev_err(&h->pdev->dev,
+ "Error: failed to disable report lun data caching.\n");
+out:
+ cmd_free(h, c);
+ kfree(options);
+}
+
static void hpsa_shutdown(struct pci_dev *pdev)
{
struct ctlr_info *h;
@@ -8292,6 +8747,7 @@ static void hpsa_remove_one(struct pci_dev *pdev)
hpsa_free_performant_mode(h); /* init_one 7 */
hpsa_free_sg_chain_blocks(h); /* init_one 6 */
hpsa_free_cmd_pool(h); /* init_one 5 */
+ kfree(h->lastlogicals);
/* hpsa_free_irqs already called via hpsa_shutdown init_one 4 */
@@ -8304,6 +8760,9 @@ static void hpsa_remove_one(struct pci_dev *pdev)
free_percpu(h->lockup_detected); /* init_one 2 */
h->lockup_detected = NULL; /* init_one 2 */
/* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */
+
+ hpsa_delete_sas_host(h);
+
kfree(h); /* init_one 1 */
}
@@ -8766,18 +9225,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h)
} while (1);
}
+static struct hpsa_sas_phy *hpsa_alloc_sas_phy(
+ struct hpsa_sas_port *hpsa_sas_port)
+{
+ struct hpsa_sas_phy *hpsa_sas_phy;
+ struct sas_phy *phy;
+
+ hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL);
+ if (!hpsa_sas_phy)
+ return NULL;
+
+ phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev,
+ hpsa_sas_port->next_phy_index);
+ if (!phy) {
+ kfree(hpsa_sas_phy);
+ return NULL;
+ }
+
+ hpsa_sas_port->next_phy_index++;
+ hpsa_sas_phy->phy = phy;
+ hpsa_sas_phy->parent_port = hpsa_sas_port;
+
+ return hpsa_sas_phy;
+}
+
+static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy)
+{
+ struct sas_phy *phy = hpsa_sas_phy->phy;
+
+ sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy);
+ sas_phy_free(phy);
+ if (hpsa_sas_phy->added_to_port)
+ list_del(&hpsa_sas_phy->phy_list_entry);
+ kfree(hpsa_sas_phy);
+}
+
+static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_phy *phy;
+ struct sas_identify *identify;
+
+ hpsa_sas_port = hpsa_sas_phy->parent_port;
+ phy = hpsa_sas_phy->phy;
+
+ identify = &phy->identify;
+ memset(identify, 0, sizeof(*identify));
+ identify->sas_address = hpsa_sas_port->sas_address;
+ identify->device_type = SAS_END_DEVICE;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+ phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
+ phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
+ phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
+
+ rc = sas_phy_add(hpsa_sas_phy->phy);
+ if (rc)
+ return rc;
+
+ sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy);
+ list_add_tail(&hpsa_sas_phy->phy_list_entry,
+ &hpsa_sas_port->phy_list_head);
+ hpsa_sas_phy->added_to_port = true;
+
+ return 0;
+}
+
+static int
+ hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port,
+ struct sas_rphy *rphy)
+{
+ struct sas_identify *identify;
+
+ identify = &rphy->identify;
+ identify->sas_address = hpsa_sas_port->sas_address;
+ identify->initiator_port_protocols = SAS_PROTOCOL_STP;
+ identify->target_port_protocols = SAS_PROTOCOL_STP;
+
+ return sas_rphy_add(rphy);
+}
+
+static struct hpsa_sas_port
+ *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node,
+ u64 sas_address)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_port *port;
+
+ hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL);
+ if (!hpsa_sas_port)
+ return NULL;
+
+ INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head);
+ hpsa_sas_port->parent_node = hpsa_sas_node;
+
+ port = sas_port_alloc_num(hpsa_sas_node->parent_dev);
+ if (!port)
+ goto free_hpsa_port;
+
+ rc = sas_port_add(port);
+ if (rc)
+ goto free_sas_port;
+
+ hpsa_sas_port->port = port;
+ hpsa_sas_port->sas_address = sas_address;
+ list_add_tail(&hpsa_sas_port->port_list_entry,
+ &hpsa_sas_node->port_list_head);
+
+ return hpsa_sas_port;
+
+free_sas_port:
+ sas_port_free(port);
+free_hpsa_port:
+ kfree(hpsa_sas_port);
+
+ return NULL;
+}
+
+static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port)
+{
+ struct hpsa_sas_phy *hpsa_sas_phy;
+ struct hpsa_sas_phy *next;
+
+ list_for_each_entry_safe(hpsa_sas_phy, next,
+ &hpsa_sas_port->phy_list_head, phy_list_entry)
+ hpsa_free_sas_phy(hpsa_sas_phy);
+
+ sas_port_delete(hpsa_sas_port->port);
+ list_del(&hpsa_sas_port->port_list_entry);
+ kfree(hpsa_sas_port);
+}
+
+static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev)
+{
+ struct hpsa_sas_node *hpsa_sas_node;
+
+ hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL);
+ if (hpsa_sas_node) {
+ hpsa_sas_node->parent_dev = parent_dev;
+ INIT_LIST_HEAD(&hpsa_sas_node->port_list_head);
+ }
+
+ return hpsa_sas_node;
+}
+
+static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node)
+{
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct hpsa_sas_port *next;
+
+ if (!hpsa_sas_node)
+ return;
+
+ list_for_each_entry_safe(hpsa_sas_port, next,
+ &hpsa_sas_node->port_list_head, port_list_entry)
+ hpsa_free_sas_port(hpsa_sas_port);
+
+ kfree(hpsa_sas_node);
+}
+
+static struct hpsa_scsi_dev_t
+ *hpsa_find_device_by_sas_rphy(struct ctlr_info *h,
+ struct sas_rphy *rphy)
+{
+ int i;
+ struct hpsa_scsi_dev_t *device;
+
+ for (i = 0; i < h->ndevices; i++) {
+ device = h->dev[i];
+ if (!device->sas_port)
+ continue;
+ if (device->sas_port->rphy == rphy)
+ return device;
+ }
+
+ return NULL;
+}
+
+static int hpsa_add_sas_host(struct ctlr_info *h)
+{
+ int rc;
+ struct device *parent_dev;
+ struct hpsa_sas_node *hpsa_sas_node;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct hpsa_sas_phy *hpsa_sas_phy;
+
+ parent_dev = &h->scsi_host->shost_gendev;
+
+ hpsa_sas_node = hpsa_alloc_sas_node(parent_dev);
+ if (!hpsa_sas_node)
+ return -ENOMEM;
+
+ hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address);
+ if (!hpsa_sas_port) {
+ rc = -ENODEV;
+ goto free_sas_node;
+ }
+
+ hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port);
+ if (!hpsa_sas_phy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ rc = hpsa_sas_port_add_phy(hpsa_sas_phy);
+ if (rc)
+ goto free_sas_phy;
+
+ h->sas_host = hpsa_sas_node;
+
+ return 0;
+
+free_sas_phy:
+ hpsa_free_sas_phy(hpsa_sas_phy);
+free_sas_port:
+ hpsa_free_sas_port(hpsa_sas_port);
+free_sas_node:
+ hpsa_free_sas_node(hpsa_sas_node);
+
+ return rc;
+}
+
+static void hpsa_delete_sas_host(struct ctlr_info *h)
+{
+ hpsa_free_sas_node(h->sas_host);
+}
+
+static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node,
+ struct hpsa_scsi_dev_t *device)
+{
+ int rc;
+ struct hpsa_sas_port *hpsa_sas_port;
+ struct sas_rphy *rphy;
+
+ hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address);
+ if (!hpsa_sas_port)
+ return -ENOMEM;
+
+ rphy = sas_end_device_alloc(hpsa_sas_port->port);
+ if (!rphy) {
+ rc = -ENODEV;
+ goto free_sas_port;
+ }
+
+ hpsa_sas_port->rphy = rphy;
+ device->sas_port = hpsa_sas_port;
+
+ rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy);
+ if (rc)
+ goto free_sas_port;
+
+ return 0;
+
+free_sas_port:
+ hpsa_free_sas_port(hpsa_sas_port);
+ device->sas_port = NULL;
+
+ return rc;
+}
+
+static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device)
+{
+ if (device->sas_port) {
+ hpsa_free_sas_port(device->sas_port);
+ device->sas_port = NULL;
+ }
+}
+
+static int
+hpsa_sas_get_linkerrors(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_get_bay_identifier(struct sas_rphy *rphy)
+{
+ return -ENXIO;
+}
+
+static int
+hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_phy_enable(struct sas_phy *phy, int enable)
+{
+ return 0;
+}
+
+static int
+hpsa_sas_phy_setup(struct sas_phy *phy)
+{
+ return 0;
+}
+
+static void
+hpsa_sas_phy_release(struct sas_phy *phy)
+{
+}
+
+static int
+hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
+{
+ return -EINVAL;
+}
+
+/* SMP = Serial Management Protocol */
+static int
+hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
+struct request *req)
+{
+ return -EINVAL;
+}
+
+static struct sas_function_template hpsa_sas_transport_functions = {
+ .get_linkerrors = hpsa_sas_get_linkerrors,
+ .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier,
+ .get_bay_identifier = hpsa_sas_get_bay_identifier,
+ .phy_reset = hpsa_sas_phy_reset,
+ .phy_enable = hpsa_sas_phy_enable,
+ .phy_setup = hpsa_sas_phy_setup,
+ .phy_release = hpsa_sas_phy_release,
+ .set_phy_speed = hpsa_sas_phy_speed,
+ .smp_handler = hpsa_sas_smp_handler,
+};
+
/*
* This is it. Register the PCI driver information for the cards we control
* the OS will call our registered routines when it finds one of our cards.
*/
static int __init hpsa_init(void)
{
- return pci_register_driver(&hpsa_pci_driver);
+ int rc;
+
+ hpsa_sas_transport_template =
+ sas_attach_transport(&hpsa_sas_transport_functions);
+ if (!hpsa_sas_transport_template)
+ return -ENODEV;
+
+ rc = pci_register_driver(&hpsa_pci_driver);
+
+ if (rc)
+ sas_release_transport(hpsa_sas_transport_template);
+
+ return rc;
}
static void __exit hpsa_cleanup(void)
{
pci_unregister_driver(&hpsa_pci_driver);
+ sas_release_transport(hpsa_sas_transport_template);
}
static void __attribute__((unused)) verify_offsets(void)
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 27debb3..ae5beda 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -33,12 +33,38 @@ struct access_method {
unsigned long (*command_completed)(struct ctlr_info *h, u8 q);
};
+/* for SAS hosts and SAS expanders */
+struct hpsa_sas_node {
+ struct device *parent_dev;
+ struct list_head port_list_head;
+};
+
+struct hpsa_sas_port {
+ struct list_head port_list_entry;
+ u64 sas_address;
+ struct sas_port *port;
+ int next_phy_index;
+ struct list_head phy_list_head;
+ struct hpsa_sas_node *parent_node;
+ struct sas_rphy *rphy;
+};
+
+struct hpsa_sas_phy {
+ struct list_head phy_list_entry;
+ struct sas_phy *phy;
+ struct hpsa_sas_port *parent_port;
+ bool added_to_port;
+};
+
struct hpsa_scsi_dev_t {
- int devtype;
+ unsigned int devtype;
int bus, target, lun; /* as presented to the OS */
unsigned char scsi3addr[8]; /* as presented to the HW */
+ u8 physical_device : 1;
+ u8 expose_device;
#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0"
unsigned char device_id[16]; /* from inquiry pg. 0x83 */
+ u64 sas_address;
unsigned char vendor[8]; /* bytes 8-15 of inquiry data */
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
@@ -75,11 +101,8 @@ struct hpsa_scsi_dev_t {
struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES];
int nphysical_disks;
int supports_aborts;
-#define HPSA_DO_NOT_EXPOSE 0x0
-#define HPSA_SG_ATTACH 0x1
-#define HPSA_ULD_ATTACH 0x2
-#define HPSA_SCSI_ADD (HPSA_SG_ATTACH | HPSA_ULD_ATTACH)
- u8 expose_state;
+ struct hpsa_sas_port *sas_port;
+ int external; /* 1-from external array 0-not <0-unknown */
};
struct reply_queue_buffer {
@@ -136,6 +159,7 @@ struct ctlr_info {
char *product_name;
struct pci_dev *pdev;
u32 board_id;
+ u64 sas_address;
void __iomem *vaddr;
unsigned long paddr;
int nr_cmds; /* Number of commands allowed on this controller */
@@ -262,7 +286,10 @@ struct ctlr_info {
spinlock_t offline_device_lock;
struct list_head offline_device_list;
int acciopath_status;
+ int drv_req_rescan;
int raid_offload_debug;
+ int discovery_polling;
+ struct ReportLUNdata *lastlogicals;
int needs_abort_tags_swizzled;
struct workqueue_struct *resubmit_wq;
struct workqueue_struct *rescan_ctlr_wq;
@@ -270,6 +297,8 @@ struct ctlr_info {
wait_queue_head_t abort_cmd_wait_queue;
wait_queue_head_t event_sync_wait_queue;
struct mutex reset_mutex;
+ u8 reset_in_progress;
+ struct hpsa_sas_node *sas_host;
};
struct offline_device_entry {
@@ -283,6 +312,7 @@ struct offline_device_entry {
#define HPSA_RESET_TYPE_BUS 0x01
#define HPSA_RESET_TYPE_TARGET 0x03
#define HPSA_RESET_TYPE_LUN 0x04
+#define HPSA_PHYS_TARGET_RESET 0x99 /* not defined by cciss spec */
#define HPSA_MSG_SEND_RETRY_LIMIT 10
#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000)
@@ -367,6 +397,11 @@ struct offline_device_entry {
#define IOACCEL2_INBOUND_POSTQ_64_LOW 0xd0
#define IOACCEL2_INBOUND_POSTQ_64_HI 0xd4
+#define HPSA_PHYSICAL_DEVICE_BUS 0
+#define HPSA_RAID_VOLUME_BUS 1
+#define HPSA_EXTERNAL_RAID_VOLUME_BUS 2
+#define HPSA_HBA_BUS 3
+
/*
Send the command to the hardware
*/
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index 47c756b..d92ef0d 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -260,8 +260,6 @@ struct ext_report_lun_entry {
u8 wwid[8];
u8 device_type;
u8 device_flags;
-#define NON_DISK_PHYS_DEV(x) ((x)[17] & 0x01)
-#define PHYS_IOACCEL(x) ((x)[17] & 0x08)
u8 lun_count; /* multi-lun device, how many luns */
u8 redundant_paths;
u32 ioaccel_handle; /* ioaccel1 only uses lower 16 bits */
@@ -288,6 +286,11 @@ struct SenseSubsystem_info {
#define BMIC_FLASH_FIRMWARE 0xF7
#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
+#define BMIC_IDENTIFY_CONTROLLER 0x11
+#define BMIC_SET_DIAG_OPTIONS 0xF4
+#define BMIC_SENSE_DIAG_OPTIONS 0xF5
+#define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000
+#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66
/* Command List Structure */
union SCSI3Addr {
@@ -684,6 +687,16 @@ struct hpsa_pci_info {
u32 board_id;
};
+struct bmic_identify_controller {
+ u8 configured_logical_drive_count; /* offset 0 */
+ u8 pad1[153];
+ __le16 extended_logical_unit_count; /* offset 154 */
+ u8 pad2[136];
+ u8 controller_mode; /* offset 292 */
+ u8 pad3[32];
+};
+
+
struct bmic_identify_physical_device {
u8 scsi_bus; /* SCSI Bus number on controller */
u8 scsi_id; /* SCSI ID on this bus */
@@ -816,5 +829,18 @@ struct bmic_identify_physical_device {
u8 padding[112];
};
+struct bmic_sense_subsystem_info {
+ u8 primary_slot_number;
+ u8 reserved[3];
+ u8 chasis_serial_number[32];
+ u8 primary_world_wide_id[8];
+ u8 primary_array_serial_number[32]; /* NULL terminated */
+ u8 primary_cache_serial_number[32]; /* NULL terminated */
+ u8 reserved_2[8];
+ u8 secondary_array_serial_number[32];
+ u8 secondary_cache_serial_number[32];
+ u8 pad[332];
+};
+
#pragma pack()
#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 057d277..6aa317c 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -3095,7 +3095,6 @@ static struct scsi_host_template driver_template = {
.max_sectors = IBMVFC_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = ibmvfc_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 6a41c36..adfef9d 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -106,9 +106,9 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(IBMVSCSI_VERSION);
module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_id, "Largest ID value for each channel");
+MODULE_PARM_DESC(max_id, "Largest ID value for each channel [Default=64]");
module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(max_channel, "Largest channel value");
+MODULE_PARM_DESC(max_channel, "Largest channel value [Default=3]");
module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
module_param_named(max_requests, max_requests, int, S_IRUGO);
@@ -2289,11 +2289,15 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
goto init_pool_failed;
}
- host->max_lun = 8;
+ host->max_lun = IBMVSCSI_MAX_LUN;
host->max_id = max_id;
host->max_channel = max_channel;
host->max_cmd_len = 16;
+ dev_info(dev,
+ "Maximum ID: %d Maximum LUN: %llu Maximum Channel: %d\n",
+ host->max_id, host->max_lun, host->max_channel);
+
if (scsi_add_host(hostdata->host, hostdata->dev))
goto add_host_failed;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
index 7d64867..1067367 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.h
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -48,6 +48,7 @@ struct Scsi_Host;
#define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16
#define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */
#define IBMVSCSI_MAX_CMDS_PER_LUN 64
+#define IBMVSCSI_MAX_LUN 32
/* ------------------------------------------------------------
* Data Structures
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index b62836d..536cd5a 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -6363,15 +6363,19 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
ipr_cmd->scsi_cmd = scsi_cmd;
ipr_cmd->done = ipr_scsi_eh_done;
- if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
+ if (ipr_is_gscsi(res)) {
if (scsi_cmd->underflow == 0)
ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
- ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
- if (ipr_is_gscsi(res) && res->reset_occurred) {
+ if (res->reset_occurred) {
res->reset_occurred = 0;
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
}
+ }
+
+ if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
+
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
if (scsi_cmd->flags & SCMD_TAGGED)
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK;
@@ -6502,7 +6506,6 @@ static struct scsi_host_template driver_template = {
.shost_attrs = ipr_ioa_attrs,
.sdev_attrs = ipr_dev_attrs,
.proc_name = IPR_NAME,
- .use_blk_tags = 1,
};
/**
@@ -7671,6 +7674,63 @@ static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
return IPR_RC_JOB_RETURN;
}
+static int ipr_ioa_service_action_failed(struct ipr_cmnd *ipr_cmd)
+{
+ u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc);
+
+ if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT)
+ return IPR_RC_JOB_CONTINUE;
+
+ return ipr_reset_cmd_failed(ipr_cmd);
+}
+
+static void ipr_build_ioa_service_action(struct ipr_cmnd *ipr_cmd,
+ __be32 res_handle, u8 sa_code)
+{
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+
+ ioarcb->res_handle = res_handle;
+ ioarcb->cmd_pkt.cdb[0] = IPR_IOA_SERVICE_ACTION;
+ ioarcb->cmd_pkt.cdb[1] = sa_code;
+ ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+}
+
+/**
+ * ipr_ioafp_set_caching_parameters - Issue Set Cache parameters service
+ * action
+ *
+ * Return value:
+ * none
+ **/
+static int ipr_ioafp_set_caching_parameters(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data;
+
+ ENTER;
+
+ ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+
+ if (pageC4->cache_cap[0] & IPR_CAP_SYNC_CACHE) {
+ ipr_build_ioa_service_action(ipr_cmd,
+ cpu_to_be32(IPR_IOA_RES_HANDLE),
+ IPR_IOA_SA_CHANGE_CACHE_PARAMS);
+
+ ioarcb->cmd_pkt.cdb[2] = 0x40;
+
+ ipr_cmd->job_step_failed = ipr_ioa_service_action_failed;
+ ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
+ IPR_SET_SUP_DEVICE_TIMEOUT);
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
/**
* ipr_ioafp_inquiry - Send an Inquiry to the adapter.
* @ipr_cmd: ipr command struct
@@ -7722,6 +7782,39 @@ static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page)
}
/**
+ * ipr_ioafp_pageC4_inquiry - Send a Page 0xC4 Inquiry to the adapter.
+ * @ipr_cmd: ipr command struct
+ *
+ * This function sends a Page 0xC4 inquiry to the adapter
+ * to retrieve software VPD information.
+ *
+ * Return value:
+ * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_pageC4_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data;
+ struct ipr_inquiry_pageC4 *pageC4 = &ioa_cfg->vpd_cbs->pageC4_data;
+
+ ENTER;
+ ipr_cmd->job_step = ipr_ioafp_set_caching_parameters;
+ memset(pageC4, 0, sizeof(*pageC4));
+
+ if (ipr_inquiry_page_supported(page0, 0xC4)) {
+ ipr_ioafp_inquiry(ipr_cmd, 1, 0xC4,
+ (ioa_cfg->vpd_cbs_dma
+ + offsetof(struct ipr_misc_cbs,
+ pageC4_data)),
+ sizeof(struct ipr_inquiry_pageC4));
+ return IPR_RC_JOB_RETURN;
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_CONTINUE;
+}
+
+/**
* ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter.
* @ipr_cmd: ipr command struct
*
@@ -7738,7 +7831,7 @@ static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd)
struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap;
ENTER;
- ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+ ipr_cmd->job_step = ipr_ioafp_pageC4_inquiry;
memset(cap, 0, sizeof(*cap));
if (ipr_inquiry_page_supported(page0, 0xD0)) {
@@ -8277,6 +8370,42 @@ static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd)
return IPR_RC_JOB_RETURN;
}
+static int ipr_dump_mailbox_wait(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+ ENTER;
+
+ if (ioa_cfg->sdt_state != GET_DUMP)
+ return IPR_RC_JOB_RETURN;
+
+ if (!ioa_cfg->sis64 || !ipr_cmd->u.time_left ||
+ (readl(ioa_cfg->regs.sense_interrupt_reg) &
+ IPR_PCII_MAILBOX_STABLE)) {
+
+ if (!ipr_cmd->u.time_left)
+ dev_err(&ioa_cfg->pdev->dev,
+ "Timed out waiting for Mailbox register.\n");
+
+ ioa_cfg->sdt_state = READ_DUMP;
+ ioa_cfg->dump_timeout = 0;
+ if (ioa_cfg->sis64)
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT);
+ else
+ ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT);
+ ipr_cmd->job_step = ipr_reset_wait_for_dump;
+ schedule_work(&ioa_cfg->work_q);
+
+ } else {
+ ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
+ ipr_reset_start_timer(ipr_cmd,
+ IPR_CHECK_FOR_RESET_TIMEOUT);
+ }
+
+ LEAVE;
+ return IPR_RC_JOB_RETURN;
+}
+
/**
* ipr_reset_restore_cfg_space - Restore PCI config space.
* @ipr_cmd: ipr command struct
@@ -8326,20 +8455,11 @@ static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
if (ioa_cfg->in_ioa_bringdown) {
ipr_cmd->job_step = ipr_ioa_bringdown_done;
+ } else if (ioa_cfg->sdt_state == GET_DUMP) {
+ ipr_cmd->job_step = ipr_dump_mailbox_wait;
+ ipr_cmd->u.time_left = IPR_WAIT_FOR_MAILBOX;
} else {
ipr_cmd->job_step = ipr_reset_enable_ioa;
-
- if (GET_DUMP == ioa_cfg->sdt_state) {
- ioa_cfg->sdt_state = READ_DUMP;
- ioa_cfg->dump_timeout = 0;
- if (ioa_cfg->sis64)
- ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT);
- else
- ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT);
- ipr_cmd->job_step = ipr_reset_wait_for_dump;
- schedule_work(&ioa_cfg->work_q);
- return IPR_RC_JOB_RETURN;
- }
}
LEAVE;
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index e4fb17a..a34c7a5 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -39,8 +39,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.6.2"
-#define IPR_DRIVER_DATE "(June 11, 2015)"
+#define IPR_DRIVER_VERSION "2.6.3"
+#define IPR_DRIVER_DATE "(October 17, 2015)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -216,6 +216,10 @@
#define IPR_SET_ALL_SUPPORTED_DEVICES 0x80
#define IPR_IOA_SHUTDOWN 0xF7
#define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05
+#define IPR_IOA_SERVICE_ACTION 0xD2
+
+/* IOA Service Actions */
+#define IPR_IOA_SA_CHANGE_CACHE_PARAMS 0x14
/*
* Timeouts
@@ -279,6 +283,9 @@
#define IPR_IPL_INIT_STAGE_TIME_MASK 0x0000ffff
#define IPR_PCII_IPL_STAGE_CHANGE (0x80000000 >> 0)
+#define IPR_PCII_MAILBOX_STABLE (0x80000000 >> 4)
+#define IPR_WAIT_FOR_MAILBOX (2 * HZ)
+
#define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0)
#define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3)
#define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4)
@@ -846,6 +853,16 @@ struct ipr_inquiry_page0 {
u8 page[IPR_INQUIRY_PAGE0_ENTRIES];
}__attribute__((packed));
+struct ipr_inquiry_pageC4 {
+ u8 peri_qual_dev_type;
+ u8 page_code;
+ u8 reserved1;
+ u8 len;
+ u8 cache_cap[4];
+#define IPR_CAP_SYNC_CACHE 0x08
+ u8 reserved2[20];
+} __packed;
+
struct ipr_hostrcb_device_data_entry {
struct ipr_vpd vpd;
struct ipr_res_addr dev_res_addr;
@@ -1319,6 +1336,7 @@ struct ipr_misc_cbs {
struct ipr_inquiry_page0 page0_data;
struct ipr_inquiry_page3 page3_data;
struct ipr_inquiry_cap cap;
+ struct ipr_inquiry_pageC4 pageC4_data;
struct ipr_mode_pages mode_pages;
struct ipr_supported_device supp_dev;
};
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 0dfcabe..77128d68 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -170,7 +170,6 @@ static struct scsi_host_template isci_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = isci_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -272,11 +271,11 @@ static void isci_unregister(struct isci_host *isci_host)
if (!isci_host)
return;
+ shost = to_shost(isci_host);
+ scsi_remove_host(shost);
sas_unregister_ha(&isci_host->sas_ha);
- shost = to_shost(isci_host);
sas_remove_host(shost);
- scsi_remove_host(shost);
scsi_host_put(shost);
}
diff --git a/drivers/scsi/libfc/fc_npiv.c b/drivers/scsi/libfc/fc_npiv.c
index 9fbf78e..c168321 100644
--- a/drivers/scsi/libfc/fc_npiv.c
+++ b/drivers/scsi/libfc/fc_npiv.c
@@ -25,7 +25,7 @@
#include <linux/export.h>
/**
- * fc_vport_create() - Create a new NPIV vport instance
+ * libfc_vport_create() - Create a new NPIV vport instance
* @vport: fc_vport structure from scsi_transport_fc
* @privsize: driver private data size to allocate along with the Scsi_Host
*/
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 3feeb44..b6fa257 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -5173,7 +5173,6 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
rjt_err = LSRJT_CMD_UNSUPPORTED;
goto rjt;
}
- lcb_context = kmalloc(sizeof(struct lpfc_lcb_context), GFP_KERNEL);
if (phba->hba_flag & HBA_FCOE_MODE) {
rjt_err = LSRJT_CMD_UNSUPPORTED;
@@ -5204,6 +5203,12 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
goto rjt;
}
+ lcb_context = kmalloc(sizeof(*lcb_context), GFP_KERNEL);
+ if (!lcb_context) {
+ rjt_err = LSRJT_UNABLE_TPC;
+ goto rjt;
+ }
+
state = (beacon->lcb_sub_command == LPFC_LCB_ON) ? 1 : 0;
lcb_context->sub_command = beacon->lcb_sub_command;
lcb_context->type = beacon->lcb_type;
@@ -5214,6 +5219,7 @@ lpfc_els_rcv_lcb(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb,
if (lpfc_sli4_set_beacon(vport, lcb_context, state)) {
lpfc_printf_vlog(ndlp->vport, KERN_ERR,
LOG_ELS, "0193 failed to send mail box");
+ kfree(lcb_context);
lpfc_nlp_put(ndlp);
rjt_err = LSRJT_UNABLE_TPC;
goto rjt;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 051b3b3..4679ed4 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -5914,7 +5914,6 @@ struct scsi_host_template lpfc_template_s3 = {
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -5940,7 +5939,6 @@ struct scsi_host_template lpfc_template = {
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -5964,6 +5962,5 @@ struct scsi_host_template lpfc_vport_template = {
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
.change_queue_depth = scsi_change_queue_depth,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 20c3754..c0f7c8c 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -35,8 +35,8 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.807.10.00-rc1"
-#define MEGASAS_RELDATE "March 6, 2015"
+#define MEGASAS_VERSION "06.808.16.00-rc1"
+#define MEGASAS_RELDATE "Oct. 8, 2015"
/*
* Device IDs
@@ -52,6 +52,10 @@
#define PCI_DEVICE_ID_LSI_PLASMA 0x002f
#define PCI_DEVICE_ID_LSI_INVADER 0x005d
#define PCI_DEVICE_ID_LSI_FURY 0x005f
+#define PCI_DEVICE_ID_LSI_INTRUDER 0x00ce
+#define PCI_DEVICE_ID_LSI_INTRUDER_24 0x00cf
+#define PCI_DEVICE_ID_LSI_CUTLASS_52 0x0052
+#define PCI_DEVICE_ID_LSI_CUTLASS_53 0x0053
/*
* Intel HBA SSDIDs
@@ -62,6 +66,14 @@
#define MEGARAID_INTEL_RS3MC044_SSDID 0x9381
#define MEGARAID_INTEL_RS3WC080_SSDID 0x9341
#define MEGARAID_INTEL_RS3WC040_SSDID 0x9343
+#define MEGARAID_INTEL_RMS3BC160_SSDID 0x352B
+
+/*
+ * Intruder HBA SSDIDs
+ */
+#define MEGARAID_INTRUDER_SSDID1 0x9371
+#define MEGARAID_INTRUDER_SSDID2 0x9390
+#define MEGARAID_INTRUDER_SSDID3 0x9370
/*
* Intel HBA branding
@@ -78,6 +90,8 @@
"Intel(R) RAID Controller RS3WC080"
#define MEGARAID_INTEL_RS3WC040_BRANDING \
"Intel(R) RAID Controller RS3WC040"
+#define MEGARAID_INTEL_RMS3BC160_BRANDING \
+ "Intel(R) Integrated RAID Module RMS3BC160"
/*
* =====================================
@@ -273,6 +287,16 @@ enum MFI_STAT {
MFI_STAT_INVALID_STATUS = 0xFF
};
+enum mfi_evt_class {
+ MFI_EVT_CLASS_DEBUG = -2,
+ MFI_EVT_CLASS_PROGRESS = -1,
+ MFI_EVT_CLASS_INFO = 0,
+ MFI_EVT_CLASS_WARNING = 1,
+ MFI_EVT_CLASS_CRITICAL = 2,
+ MFI_EVT_CLASS_FATAL = 3,
+ MFI_EVT_CLASS_DEAD = 4
+};
+
/*
* Crash dump related defines
*/
@@ -364,6 +388,8 @@ enum MR_EVT_ARGS {
MR_EVT_ARGS_GENERIC,
};
+
+#define SGE_BUFFER_SIZE 4096
/*
* define constants for device list query options
*/
@@ -394,6 +420,7 @@ enum MR_LD_QUERY_TYPE {
#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db
#define MR_EVT_LD_OFFLINE 0x00fc
#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152
+#define MR_EVT_CTRL_PROP_CHANGED 0x012f
enum MR_PD_STATE {
MR_PD_STATE_UNCONFIGURED_GOOD = 0x00,
@@ -973,7 +1000,12 @@ struct megasas_ctrl_info {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:12;
+ u32 reserved:7;
+ u32 useSeqNumJbodFP:1;
+ u32 supportExtendedSSCSize:1;
+ u32 supportDiskCacheSettingForSysPDs:1;
+ u32 supportCPLDUpdate:1;
+ u32 supportTTYLogCompression:1;
u32 discardCacheDuringLDDelete:1;
u32 supportSecurityonJBOD:1;
u32 supportCacheBypassModes:1;
@@ -1013,7 +1045,12 @@ struct megasas_ctrl_info {
u32 supportCacheBypassModes:1;
u32 supportSecurityonJBOD:1;
u32 discardCacheDuringLDDelete:1;
- u32 reserved:12;
+ u32 supportTTYLogCompression:1;
+ u32 supportCPLDUpdate:1;
+ u32 supportDiskCacheSettingForSysPDs:1;
+ u32 supportExtendedSSCSize:1;
+ u32 useSeqNumJbodFP:1;
+ u32 reserved:7;
#endif
} adapterOperations3;
@@ -1229,7 +1266,9 @@ union megasas_sgl_frame {
typedef union _MFI_CAPABILITIES {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:25;
+ u32 reserved:23;
+ u32 support_ext_io_size:1;
+ u32 support_ext_queue_depth:1;
u32 security_protocol_cmds_fw:1;
u32 support_core_affinity:1;
u32 support_ndrive_r1_lb:1;
@@ -1245,7 +1284,9 @@ typedef union _MFI_CAPABILITIES {
u32 support_ndrive_r1_lb:1;
u32 support_core_affinity:1;
u32 security_protocol_cmds_fw:1;
- u32 reserved:25;
+ u32 support_ext_queue_depth:1;
+ u32 support_ext_io_size:1;
+ u32 reserved:23;
#endif
} mfi_capabilities;
__le32 reg;
@@ -1690,6 +1731,7 @@ struct megasas_instance {
u32 crash_dump_drv_support;
u32 crash_dump_app_support;
u32 secure_jbod_support;
+ bool use_seqnum_jbod_fp; /* Added for PD sequence */
spinlock_t crashdump_lock;
struct megasas_register_set __iomem *reg_set;
@@ -1748,6 +1790,7 @@ struct megasas_instance {
u8 UnevenSpanSupport;
u8 supportmax256vd;
+ u8 allow_fw_scan;
u16 fw_supported_vd_count;
u16 fw_supported_pd_count;
@@ -1769,7 +1812,9 @@ struct megasas_instance {
struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES];
struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES];
u64 map_id;
+ u64 pd_seq_map_id;
struct megasas_cmd *map_update_cmd;
+ struct megasas_cmd *jbod_seq_cmd;
unsigned long bar;
long reset_flags;
struct mutex reset_mutex;
@@ -1780,6 +1825,7 @@ struct megasas_instance {
char mpio;
u16 throttlequeuedepth;
u8 mask_interrupts;
+ u16 max_chain_frame_sz;
u8 is_imr;
bool dev_handle;
};
@@ -1985,6 +2031,9 @@ __le16 get_updated_dev_handle(struct megasas_instance *instance,
void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map,
struct LD_LOAD_BALANCE_INFO *lbInfo);
int megasas_get_ctrl_info(struct megasas_instance *instance);
+/* PD sequence */
+int
+megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend);
int megasas_set_crash_dump_params(struct megasas_instance *instance,
u8 crash_buf_state);
void megasas_free_host_crash_buffer(struct megasas_instance *instance);
@@ -2000,5 +2049,6 @@ void __megasas_return_cmd(struct megasas_instance *instance,
void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion);
int megasas_cmd_type(struct scsi_cmnd *cmd);
+void megasas_setup_jbod_map(struct megasas_instance *instance);
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index eaa81e5..97a1c1c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -135,6 +135,12 @@ static struct pci_device_id megasas_pci_table[] = {
/* Invader */
{PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FURY)},
/* Fury */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER)},
+ /* Intruder */
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INTRUDER_24)},
+ /* Intruder 24 port*/
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_52)},
+ {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_CUTLASS_53)},
{}
};
@@ -260,6 +266,66 @@ megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
+static const char *
+format_timestamp(uint32_t timestamp)
+{
+ static char buffer[32];
+
+ if ((timestamp & 0xff000000) == 0xff000000)
+ snprintf(buffer, sizeof(buffer), "boot + %us", timestamp &
+ 0x00ffffff);
+ else
+ snprintf(buffer, sizeof(buffer), "%us", timestamp);
+ return buffer;
+}
+
+static const char *
+format_class(int8_t class)
+{
+ static char buffer[6];
+
+ switch (class) {
+ case MFI_EVT_CLASS_DEBUG:
+ return "debug";
+ case MFI_EVT_CLASS_PROGRESS:
+ return "progress";
+ case MFI_EVT_CLASS_INFO:
+ return "info";
+ case MFI_EVT_CLASS_WARNING:
+ return "WARN";
+ case MFI_EVT_CLASS_CRITICAL:
+ return "CRIT";
+ case MFI_EVT_CLASS_FATAL:
+ return "FATAL";
+ case MFI_EVT_CLASS_DEAD:
+ return "DEAD";
+ default:
+ snprintf(buffer, sizeof(buffer), "%d", class);
+ return buffer;
+ }
+}
+
+/**
+ * megasas_decode_evt: Decode FW AEN event and print critical event
+ * for information.
+ * @instance: Adapter soft state
+ */
+static void
+megasas_decode_evt(struct megasas_instance *instance)
+{
+ struct megasas_evt_detail *evt_detail = instance->evt_detail;
+ union megasas_evt_class_locale class_locale;
+ class_locale.word = le32_to_cpu(evt_detail->cl.word);
+
+ if (class_locale.members.class >= MFI_EVT_CLASS_CRITICAL)
+ dev_info(&instance->pdev->dev, "%d (%s/0x%04x/%s) - %s\n",
+ le32_to_cpu(evt_detail->seq_num),
+ format_timestamp(le32_to_cpu(evt_detail->time_stamp)),
+ (class_locale.members.locale),
+ format_class(class_locale.members.class),
+ evt_detail->description);
+}
+
/**
* The following functions are defined for xscale
* (deviceid : 1064R, PERC5) controllers
@@ -1659,8 +1725,56 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no)
return NULL;
}
+/*
+* megasas_set_dma_alignment - Set DMA alignment for PI enabled VD
+*
+* @sdev: OS provided scsi device
+*
+* Returns void
+*/
+static void megasas_set_dma_alignment(struct scsi_device *sdev)
+{
+ u32 device_id, ld;
+ struct megasas_instance *instance;
+ struct fusion_context *fusion;
+ struct MR_LD_RAID *raid;
+ struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ fusion = instance->ctrl_context;
+
+ if (!fusion)
+ return;
+
+ if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) {
+ device_id = ((sdev->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL)
+ + sdev->id;
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+ ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
+ raid = MR_LdRaidGet(ld, local_map_ptr);
+
+ if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER)
+ blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
+ }
+}
+
static int megasas_slave_configure(struct scsi_device *sdev)
{
+ u16 pd_index = 0;
+ struct megasas_instance *instance;
+
+ instance = megasas_lookup_instance(sdev->host->host_no);
+ if (instance->allow_fw_scan) {
+ if (sdev->channel < MEGASAS_MAX_PD_CHANNELS &&
+ sdev->type == TYPE_DISK) {
+ pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
+ sdev->id;
+ if (instance->pd_list[pd_index].driveState !=
+ MR_PD_STATE_SYSTEM)
+ return -ENXIO;
+ }
+ }
+ megasas_set_dma_alignment(sdev);
/*
* The RAID firmware may require extended timeouts.
*/
@@ -1683,8 +1797,8 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
pd_index =
(sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) +
sdev->id;
- if (instance->pd_list[pd_index].driveState ==
- MR_PD_STATE_SYSTEM) {
+ if ((instance->allow_fw_scan || instance->pd_list[pd_index].driveState ==
+ MR_PD_STATE_SYSTEM)) {
return 0;
}
return -ENXIO;
@@ -1736,10 +1850,7 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance)
msleep(1000);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context)) {
writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
/* Flush */
readl(&instance->reg_set->doorbell);
@@ -2506,10 +2617,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd)
/*
* First wait for all commands to complete
*/
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (instance->ctrl_context)
ret = megasas_reset_fusion(scmd->device->host, 1);
else
ret = megasas_generic_reset(scmd);
@@ -2837,7 +2945,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
struct megasas_header *hdr = &cmd->frame->hdr;
unsigned long flags;
struct fusion_context *fusion = instance->ctrl_context;
- u32 opcode;
+ u32 opcode, status;
/* flag for the retry reset */
cmd->retry_for_fw_reset = 0;
@@ -2945,6 +3053,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
&& (cmd->frame->dcmd.mbox.b[1] == 1)) {
fusion->fast_path_io = 0;
spin_lock_irqsave(instance->host->host_lock, flags);
+ instance->map_update_cmd = NULL;
if (cmd->frame->hdr.cmd_status != 0) {
if (cmd->frame->hdr.cmd_status !=
MFI_STAT_NOT_FOUND)
@@ -2982,6 +3091,27 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
spin_unlock_irqrestore(&poll_aen_lock, flags);
}
+ /* FW has an updated PD sequence */
+ if ((opcode == MR_DCMD_SYSTEM_PD_MAP_GET_INFO) &&
+ (cmd->frame->dcmd.mbox.b[0] == 1)) {
+
+ spin_lock_irqsave(instance->host->host_lock, flags);
+ status = cmd->frame->hdr.cmd_status;
+ instance->jbod_seq_cmd = NULL;
+ megasas_return_cmd(instance, cmd);
+
+ if (status == MFI_STAT_OK) {
+ instance->pd_seq_map_id++;
+ /* Re-register a pd sync seq num cmd */
+ if (megasas_sync_pd_seq_num(instance, true))
+ instance->use_seqnum_jbod_fp = false;
+ } else
+ instance->use_seqnum_jbod_fp = false;
+
+ spin_unlock_irqrestore(instance->host->host_lock, flags);
+ break;
+ }
+
/*
* See if got an event notification
*/
@@ -3348,22 +3478,14 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context))
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->doorbell);
- } else {
+ else
writel(
MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
- }
max_wait = MEGASAS_RESET_WAIT_TIME;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
@@ -3374,17 +3496,10 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context))
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->doorbell);
- } else
+ else
writel(MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
@@ -3401,24 +3516,11 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr)
PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
(instance->pdev->device ==
PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device
- == PCI_DEVICE_ID_LSI_FURY)) {
+ (instance->ctrl_context)) {
writel(MFI_RESET_FLAGS,
&instance->reg_set->doorbell);
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+
+ if (instance->ctrl_context) {
for (i = 0; i < (10 * 1000); i += 20) {
if (readl(
&instance->
@@ -3639,11 +3741,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
memset(cmd->frame, 0, total_sz);
cmd->frame->io.context = cpu_to_le32(cmd->index);
cmd->frame->io.pad_0 = 0;
- if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_PLASMA) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) &&
- (instance->pdev->device != PCI_DEVICE_ID_LSI_FURY) &&
- (reset_devices))
+ if (!instance->ctrl_context && reset_devices)
cmd->frame->hdr.cmd = MFI_CMD_INVALID;
}
@@ -4136,11 +4234,21 @@ megasas_get_ctrl_info(struct megasas_instance *instance)
le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
megasas_update_ext_vd_details(instance);
+ instance->use_seqnum_jbod_fp =
+ ctrl_info->adapterOperations3.useSeqNumJbodFP;
instance->is_imr = (ctrl_info->memory_size ? 0 : 1);
dev_info(&instance->pdev->dev,
"controller type\t: %s(%dMB)\n",
instance->is_imr ? "iMR" : "MR",
le16_to_cpu(ctrl_info->memory_size));
+ instance->disableOnlineCtrlReset =
+ ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
+ dev_info(&instance->pdev->dev, "Online Controller Reset(OCR)\t: %s\n",
+ instance->disableOnlineCtrlReset ? "Disabled" : "Enabled");
+ instance->secure_jbod_support =
+ ctrl_info->adapterOperations3.supportSecurityonJBOD;
+ dev_info(&instance->pdev->dev, "Secure JBOD support\t: %s\n",
+ instance->secure_jbod_support ? "Yes" : "No");
}
pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
@@ -4481,6 +4589,62 @@ megasas_destroy_irqs(struct megasas_instance *instance) {
}
/**
+ * megasas_setup_jbod_map - setup jbod map for FP seq_number.
+ * @instance: Adapter soft state
+ * @is_probe: Driver probe check
+ *
+ * Return 0 on success.
+ */
+void
+megasas_setup_jbod_map(struct megasas_instance *instance)
+{
+ int i;
+ struct fusion_context *fusion = instance->ctrl_context;
+ u32 pd_seq_map_sz;
+
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) * (MAX_PHYSICAL_DEVICES - 1));
+
+ if (reset_devices || !fusion ||
+ !instance->ctrl_info->adapterOperations3.useSeqNumJbodFP) {
+ dev_info(&instance->pdev->dev,
+ "Jbod map is not supported %s %d\n",
+ __func__, __LINE__);
+ instance->use_seqnum_jbod_fp = false;
+ return;
+ }
+
+ if (fusion->pd_seq_sync[0])
+ goto skip_alloc;
+
+ for (i = 0; i < JBOD_MAPS_COUNT; i++) {
+ fusion->pd_seq_sync[i] = dma_alloc_coherent
+ (&instance->pdev->dev, pd_seq_map_sz,
+ &fusion->pd_seq_phys[i], GFP_KERNEL);
+ if (!fusion->pd_seq_sync[i]) {
+ dev_err(&instance->pdev->dev,
+ "Failed to allocate memory from %s %d\n",
+ __func__, __LINE__);
+ if (i == 1) {
+ dma_free_coherent(&instance->pdev->dev,
+ pd_seq_map_sz, fusion->pd_seq_sync[0],
+ fusion->pd_seq_phys[0]);
+ fusion->pd_seq_sync[0] = NULL;
+ }
+ instance->use_seqnum_jbod_fp = false;
+ return;
+ }
+ }
+
+skip_alloc:
+ if (!megasas_sync_pd_seq_num(instance, false) &&
+ !megasas_sync_pd_seq_num(instance, true))
+ instance->use_seqnum_jbod_fp = true;
+ else
+ instance->use_seqnum_jbod_fp = false;
+}
+
+/**
* megasas_init_fw - Initializes the FW
* @instance: Adapter soft state
*
@@ -4498,6 +4662,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
unsigned long bar_list;
int i, loop, fw_msix_count = 0;
struct IOV_111 *iovPtr;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
/* Find first memory bar */
bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM);
@@ -4523,6 +4690,10 @@ static int megasas_init_fw(struct megasas_instance *instance)
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
+ case PCI_DEVICE_ID_LSI_INTRUDER:
+ case PCI_DEVICE_ID_LSI_INTRUDER_24:
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
instance->instancet = &megasas_instance_template_fusion;
break;
case PCI_DEVICE_ID_LSI_SAS1078R:
@@ -4541,6 +4712,7 @@ static int megasas_init_fw(struct megasas_instance *instance)
case PCI_DEVICE_ID_DELL_PERC5:
default:
instance->instancet = &megasas_instance_template_xscale;
+ instance->allow_fw_scan = 1;
break;
}
@@ -4575,37 +4747,32 @@ static int megasas_init_fw(struct megasas_instance *instance)
scratch_pad_2 = readl
(&instance->reg_set->outbound_scratch_pad_2);
/* Check max MSI-X vectors */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA)) {
- instance->msix_vectors = (scratch_pad_2
- & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
- fw_msix_count = instance->msix_vectors;
- if (msix_vectors)
- instance->msix_vectors =
- min(msix_vectors,
- instance->msix_vectors);
- } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)
- || (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- /* Invader/Fury supports more than 8 MSI-X */
- instance->msix_vectors = ((scratch_pad_2
- & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
- >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
- fw_msix_count = instance->msix_vectors;
- /* Save 1-15 reply post index address to local memory
- * Index 0 is already saved from reg offset
- * MPI2_REPLY_POST_HOST_INDEX_OFFSET
- */
- for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
- instance->reply_post_host_index_addr[loop] =
- (u32 __iomem *)
- ((u8 __iomem *)instance->reg_set +
- MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
- + (loop * 0x10));
+ if (fusion) {
+ if (fusion->adapter_type == THUNDERBOLT_SERIES) { /* Thunderbolt Series*/
+ instance->msix_vectors = (scratch_pad_2
+ & MR_MAX_REPLY_QUEUES_OFFSET) + 1;
+ fw_msix_count = instance->msix_vectors;
+ } else { /* Invader series supports more than 8 MSI-x vectors*/
+ instance->msix_vectors = ((scratch_pad_2
+ & MR_MAX_REPLY_QUEUES_EXT_OFFSET)
+ >> MR_MAX_REPLY_QUEUES_EXT_OFFSET_SHIFT) + 1;
+ fw_msix_count = instance->msix_vectors;
+ /* Save 1-15 reply post index address to local memory
+ * Index 0 is already saved from reg offset
+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET
+ */
+ for (loop = 1; loop < MR_MAX_MSIX_REG_ARRAY; loop++) {
+ instance->reply_post_host_index_addr[loop] =
+ (u32 __iomem *)
+ ((u8 __iomem *)instance->reg_set +
+ MPI2_SUP_REPLY_POST_HOST_INDEX_OFFSET
+ + (loop * 0x10));
+ }
}
if (msix_vectors)
instance->msix_vectors = min(msix_vectors,
instance->msix_vectors);
- } else
+ } else /* MFI adapters */
instance->msix_vectors = 1;
/* Don't bother allocating more MSI-X vectors than cpus */
instance->msix_vectors = min(instance->msix_vectors,
@@ -4626,6 +4793,9 @@ static int megasas_init_fw(struct megasas_instance *instance)
"current msix/online cpus\t: (%d/%d)\n",
instance->msix_vectors, (unsigned int)num_online_cpus());
+ tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
+ (unsigned long)instance);
+
if (instance->msix_vectors ?
megasas_setup_irqs_msix(instance, 1) :
megasas_setup_irqs_ioapic(instance))
@@ -4646,13 +4816,13 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (instance->instancet->init_adapter(instance))
goto fail_init_adapter;
- tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
- (unsigned long)instance);
instance->instancet->enable_intr(instance);
dev_err(&instance->pdev->dev, "INIT adapter done\n");
+ megasas_setup_jbod_map(instance);
+
/** for passthrough
* the following function will get the PD LIST.
*/
@@ -4686,8 +4856,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2);
- instance->disableOnlineCtrlReset =
- ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
instance->mpio = ctrl_info->adapterOperations2.mpio;
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
@@ -4700,18 +4868,22 @@ static int megasas_init_fw(struct megasas_instance *instance)
}
if (ctrl_info->host_interface.SRIOV) {
- if (!ctrl_info->adapterOperations2.activePassive)
- instance->PlasmaFW111 = 1;
-
- if (!instance->PlasmaFW111)
- instance->requestorId =
- ctrl_info->iov.requestorId;
- else {
- iovPtr = (struct IOV_111 *)((unsigned char *)ctrl_info + IOV_111_OFFSET);
- instance->requestorId = iovPtr->requestorId;
+ instance->requestorId = ctrl_info->iov.requestorId;
+ if (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) {
+ if (!ctrl_info->adapterOperations2.activePassive)
+ instance->PlasmaFW111 = 1;
+
+ dev_info(&instance->pdev->dev, "SR-IOV: firmware type: %s\n",
+ instance->PlasmaFW111 ? "1.11" : "new");
+
+ if (instance->PlasmaFW111) {
+ iovPtr = (struct IOV_111 *)
+ ((unsigned char *)ctrl_info + IOV_111_OFFSET);
+ instance->requestorId = iovPtr->requestorId;
+ }
}
- dev_warn(&instance->pdev->dev, "I am VF "
- "requestorId %d\n", instance->requestorId);
+ dev_info(&instance->pdev->dev, "SRIOV: VF requestorId %d\n",
+ instance->requestorId);
}
instance->crash_dump_fw_support =
@@ -4732,8 +4904,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->crash_dump_buf = NULL;
}
- instance->secure_jbod_support =
- ctrl_info->adapterOperations3.supportSecurityonJBOD;
dev_info(&instance->pdev->dev,
"pci id\t\t: (0x%04x)/(0x%04x)/(0x%04x)/(0x%04x)\n",
@@ -4743,16 +4913,14 @@ static int megasas_init_fw(struct megasas_instance *instance)
le16_to_cpu(ctrl_info->pci.sub_device_id));
dev_info(&instance->pdev->dev, "unevenspan support : %s\n",
instance->UnevenSpanSupport ? "yes" : "no");
- dev_info(&instance->pdev->dev, "disable ocr : %s\n",
- instance->disableOnlineCtrlReset ? "yes" : "no");
dev_info(&instance->pdev->dev, "firmware crash dump : %s\n",
instance->crash_dump_drv_support ? "yes" : "no");
- dev_info(&instance->pdev->dev, "secure jbod : %s\n",
- instance->secure_jbod_support ? "yes" : "no");
+ dev_info(&instance->pdev->dev, "jbod sync map : %s\n",
+ instance->use_seqnum_jbod_fp ? "yes" : "no");
instance->max_sectors_per_req = instance->max_num_sge *
- PAGE_SIZE / 512;
+ SGE_BUFFER_SIZE / 512;
if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
instance->max_sectors_per_req = tmp_sectors;
@@ -5049,7 +5217,6 @@ static int megasas_start_aen(struct megasas_instance *instance)
static int megasas_io_attach(struct megasas_instance *instance)
{
struct Scsi_Host *host = instance->host;
- u32 error;
/*
* Export parameters required by SCSI mid-layer
@@ -5092,20 +5259,10 @@ static int megasas_io_attach(struct megasas_instance *instance)
host->max_cmd_len = 16;
/* Fusion only supports host reset */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (instance->ctrl_context) {
host->hostt->eh_device_reset_handler = NULL;
host->hostt->eh_bus_reset_handler = NULL;
}
- error = scsi_init_shared_tag_map(host, host->can_queue);
- if (error) {
- dev_err(&instance->pdev->dev,
- "Failed to shared tag from %s %d\n",
- __func__, __LINE__);
- return -ENODEV;
- }
/*
* Notify the mid-layer about the new controller
@@ -5218,6 +5375,10 @@ static int megasas_probe_one(struct pci_dev *pdev,
case PCI_DEVICE_ID_LSI_PLASMA:
case PCI_DEVICE_ID_LSI_INVADER:
case PCI_DEVICE_ID_LSI_FURY:
+ case PCI_DEVICE_ID_LSI_INTRUDER:
+ case PCI_DEVICE_ID_LSI_INTRUDER_24:
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
{
instance->ctrl_context_pages =
get_order(sizeof(struct fusion_context));
@@ -5231,6 +5392,11 @@ static int megasas_probe_one(struct pci_dev *pdev,
fusion = instance->ctrl_context;
memset(fusion, 0,
((1 << PAGE_SHIFT) << instance->ctrl_context_pages));
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA))
+ fusion->adapter_type = THUNDERBOLT_SERIES;
+ else
+ fusion->adapter_type = INVADER_SERIES;
}
break;
default: /* For all other supported controllers */
@@ -5333,10 +5499,7 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->disableOnlineCtrlReset = 1;
instance->UnevenSpanSupport = 0;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (instance->ctrl_context) {
INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq);
INIT_WORK(&instance->crash_init, megasas_fusion_crash_dump_wq);
} else
@@ -5416,10 +5579,7 @@ fail_io_attach:
instance->instancet->disable_intr(instance);
megasas_destroy_irqs(instance);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (instance->ctrl_context)
megasas_release_fusion(instance);
else
megasas_release_mfi(instance);
@@ -5506,10 +5666,14 @@ static void megasas_shutdown_controller(struct megasas_instance *instance,
if (instance->aen_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->aen_cmd, 30);
+ instance->aen_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
if (instance->map_update_cmd)
megasas_issue_blocked_abort_cmd(instance,
- instance->map_update_cmd, 30);
+ instance->map_update_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+ if (instance->jbod_seq_cmd)
+ megasas_issue_blocked_abort_cmd(instance,
+ instance->jbod_seq_cmd, MEGASAS_BLOCKED_CMD_TIMEOUT);
+
dcmd = &cmd->frame->dcmd;
memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
@@ -5628,12 +5792,7 @@ megasas_resume(struct pci_dev *pdev)
instance->msix_vectors))
goto fail_reenable_msix;
- switch (instance->pdev->device) {
- case PCI_DEVICE_ID_LSI_FUSION:
- case PCI_DEVICE_ID_LSI_PLASMA:
- case PCI_DEVICE_ID_LSI_INVADER:
- case PCI_DEVICE_ID_LSI_FURY:
- {
+ if (instance->ctrl_context) {
megasas_reset_reply_desc(instance);
if (megasas_ioc_init_fusion(instance)) {
megasas_free_cmds(instance);
@@ -5642,14 +5801,11 @@ megasas_resume(struct pci_dev *pdev)
}
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
- }
- break;
- default:
+ } else {
*instance->producer = 0;
*instance->consumer = 0;
if (megasas_issue_init_mfi(instance))
goto fail_init_mfi;
- break;
}
tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet,
@@ -5674,6 +5830,7 @@ megasas_resume(struct pci_dev *pdev)
}
instance->instancet->enable_intr(instance);
+ megasas_setup_jbod_map(instance);
instance->unload = 0;
/*
@@ -5721,6 +5878,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
struct Scsi_Host *host;
struct megasas_instance *instance;
struct fusion_context *fusion;
+ u32 pd_seq_map_sz;
instance = pci_get_drvdata(pdev);
instance->unload = 1;
@@ -5769,12 +5927,11 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (instance->msix_vectors)
pci_disable_msix(instance->pdev);
- switch (instance->pdev->device) {
- case PCI_DEVICE_ID_LSI_FUSION:
- case PCI_DEVICE_ID_LSI_PLASMA:
- case PCI_DEVICE_ID_LSI_INVADER:
- case PCI_DEVICE_ID_LSI_FURY:
+ if (instance->ctrl_context) {
megasas_release_fusion(instance);
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) *
+ (MAX_PHYSICAL_DEVICES - 1));
for (i = 0; i < 2 ; i++) {
if (fusion->ld_map[i])
dma_free_coherent(&instance->pdev->dev,
@@ -5784,11 +5941,15 @@ static void megasas_detach_one(struct pci_dev *pdev)
if (fusion->ld_drv_map[i])
free_pages((ulong)fusion->ld_drv_map[i],
fusion->drv_map_pages);
+ if (fusion->pd_seq_sync)
+ dma_free_coherent(&instance->pdev->dev,
+ pd_seq_map_sz,
+ fusion->pd_seq_sync[i],
+ fusion->pd_seq_phys[i]);
}
free_pages((ulong)instance->ctrl_context,
instance->ctrl_context_pages);
- break;
- default:
+ } else {
megasas_release_mfi(instance);
pci_free_consistent(pdev, sizeof(u32),
instance->producer,
@@ -5796,7 +5957,6 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_free_consistent(pdev, sizeof(u32),
instance->consumer,
instance->consumer_h);
- break;
}
kfree(instance->ctrl_info);
@@ -6316,6 +6476,9 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
compat_uptr_t ptr;
+ unsigned long local_raw_ptr;
+ u32 local_sense_off;
+ u32 local_sense_len;
if (clear_user(ioc, sizeof(*ioc)))
return -EFAULT;
@@ -6333,9 +6496,15 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
* sense_len is not null, so prepare the 64bit value under
* the same condition.
*/
- if (ioc->sense_len) {
+ if (get_user(local_raw_ptr, ioc->frame.raw) ||
+ get_user(local_sense_off, &ioc->sense_off) ||
+ get_user(local_sense_len, &ioc->sense_len))
+ return -EFAULT;
+
+
+ if (local_sense_len) {
void __user **sense_ioc_ptr =
- (void __user **)(ioc->frame.raw + ioc->sense_off);
+ (void __user **)((u8*)local_raw_ptr + local_sense_off);
compat_uptr_t *sense_cioc_ptr =
(compat_uptr_t *)(cioc->frame.raw + cioc->sense_off);
if (get_user(ptr, sense_cioc_ptr) ||
@@ -6504,6 +6673,7 @@ megasas_aen_polling(struct work_struct *work)
instance->ev = NULL;
host = instance->host;
if (instance->evt_detail) {
+ megasas_decode_evt(instance);
switch (le32_to_cpu(instance->evt_detail->code)) {
case MR_EVT_PD_INSERTED:
@@ -6564,8 +6734,7 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_CFG_CLEARED:
case MR_EVT_LD_DELETED:
if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
+ megasas_get_ld_vf_affiliation(instance, 0)) {
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
@@ -6596,8 +6765,7 @@ megasas_aen_polling(struct work_struct *work)
break;
case MR_EVT_LD_CREATED:
if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
+ megasas_get_ld_vf_affiliation(instance, 0)) {
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
@@ -6627,6 +6795,9 @@ megasas_aen_polling(struct work_struct *work)
case MR_EVT_LD_STATE_CHANGE:
doscan = 1;
break;
+ case MR_EVT_CTRL_PROP_CHANGED:
+ megasas_get_ctrl_info(instance);
+ break;
default:
doscan = 0;
break;
@@ -6663,8 +6834,7 @@ megasas_aen_polling(struct work_struct *work)
}
if (!instance->requestorId ||
- (instance->requestorId &&
- megasas_get_ld_vf_affiliation(instance, 0))) {
+ megasas_get_ld_vf_affiliation(instance, 0)) {
if (megasas_ld_list_query(instance,
MR_LD_QUERY_TYPE_EXPOSED_TO_HOST))
megasas_get_ld_list(instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index be57b18..741509b 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -741,14 +741,12 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
u8 physArm, span;
u64 row;
u8 retval = TRUE;
- u8 do_invader = 0;
u64 *pdBlock = &io_info->pdBlock;
__le16 *pDevHandle = &io_info->devHandle;
u32 logArm, rowMod, armQ, arm;
+ struct fusion_context *fusion;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
- instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- do_invader = 1;
+ fusion = instance->ctrl_context;
/*Get row and span from io_info for Uneven Span IO.*/
row = io_info->start_row;
@@ -779,7 +777,8 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld,
else {
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
- (!do_invader || (do_invader &&
+ ((fusion->adapter_type == THUNDERBOLT_SERIES) ||
+ ((fusion->adapter_type == INVADER_SERIES) &&
(raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
else if (raid->level == 1) {
@@ -823,13 +822,12 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
u8 physArm, span;
u64 row;
u8 retval = TRUE;
- u8 do_invader = 0;
u64 *pdBlock = &io_info->pdBlock;
__le16 *pDevHandle = &io_info->devHandle;
+ struct fusion_context *fusion;
+
+ fusion = instance->ctrl_context;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER ||
- instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- do_invader = 1;
row = mega_div64_32(stripRow, raid->rowDataSize);
@@ -875,7 +873,8 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow,
/* set dev handle as invalid. */
*pDevHandle = cpu_to_le16(MR_PD_INVALID);
if ((raid->level >= 5) &&
- (!do_invader || (do_invader &&
+ ((fusion->adapter_type == THUNDERBOLT_SERIES) ||
+ ((fusion->adapter_type == INVADER_SERIES) &&
(raid->regTypeReqOnRead != REGION_TYPE_UNUSED))))
pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE;
else if (raid->level == 1) {
@@ -909,6 +908,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
struct RAID_CONTEXT *pRAID_Context,
struct MR_DRV_RAID_MAP_ALL *map, u8 **raidLUN)
{
+ struct fusion_context *fusion;
struct MR_LD_RAID *raid;
u32 ld, stripSize, stripe_mask;
u64 endLba, endStrip, endRow, start_row, start_strip;
@@ -929,6 +929,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
isRead = io_info->isRead;
io_info->IoforUnevenSpan = 0;
io_info->start_span = SPAN_INVALID;
+ fusion = instance->ctrl_context;
ld = MR_TargetIdToLdGet(ldTgtId, map);
raid = MR_LdRaidGet(ld, map);
@@ -1092,8 +1093,7 @@ MR_BuildRaidContext(struct megasas_instance *instance,
cpu_to_le16(raid->fpIoTimeoutForLd ?
raid->fpIoTimeoutForLd :
map->raidMap.fpPdIoTimeoutSec);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
pRAID_Context->regLockFlags = (isRead) ?
raid->regTypeReqOnRead : raid->regTypeReqOnWrite;
else
@@ -1198,10 +1198,6 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
span_row_width +=
MR_LdSpanPtrGet
(ld, count, map)->spanRowDataSize;
- printk(KERN_INFO "megasas:"
- "span %x rowDataSize %x\n",
- count, MR_LdSpanPtrGet
- (ld, count, map)->spanRowDataSize);
}
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index f0837cc..8d630a5 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -316,26 +316,23 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance)
u32 max_cmd;
struct fusion_context *fusion;
struct megasas_cmd_fusion *cmd;
- u32 total_sz_chain_frame;
fusion = instance->ctrl_context;
max_cmd = instance->max_fw_cmds;
- total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME;
/*
* Use DMA pool facility provided by PCI layer
*/
- fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion",
- instance->pdev,
- total_sz_chain_frame, 4,
- 0);
+ fusion->sg_dma_pool = pci_pool_create("sg_pool_fusion", instance->pdev,
+ instance->max_chain_frame_sz,
+ 4, 0);
if (!fusion->sg_dma_pool) {
dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n");
return -ENOMEM;
}
- fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion",
+ fusion->sense_dma_pool = pci_pool_create("sense pool fusion",
instance->pdev,
SCSI_SENSE_BUFFERSIZE, 64, 0);
@@ -605,6 +602,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
int i;
struct megasas_header *frame_hdr;
const char *sys_info;
+ MFI_CAPABILITIES *drv_ops;
fusion = instance->ctrl_context;
@@ -652,20 +650,21 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
init_frame->cmd = MFI_CMD_INIT;
init_frame->cmd_status = 0xFF;
+ drv_ops = (MFI_CAPABILITIES *) &(init_frame->driver_operations);
+
/* driver support Extended MSIX */
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- init_frame->driver_operations.
- mfi_capabilities.support_additional_msix = 1;
+ if (fusion->adapter_type == INVADER_SERIES)
+ drv_ops->mfi_capabilities.support_additional_msix = 1;
/* driver supports HA / Remote LUN over Fast Path interface */
- init_frame->driver_operations.mfi_capabilities.support_fp_remote_lun
- = 1;
- init_frame->driver_operations.mfi_capabilities.support_max_255lds
- = 1;
- init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb
- = 1;
- init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw
- = 1;
+ drv_ops->mfi_capabilities.support_fp_remote_lun = 1;
+
+ drv_ops->mfi_capabilities.support_max_255lds = 1;
+ drv_ops->mfi_capabilities.support_ndrive_r1_lb = 1;
+ drv_ops->mfi_capabilities.security_protocol_cmds_fw = 1;
+
+ if (instance->max_chain_frame_sz > MEGASAS_CHAIN_FRAME_SZ_MIN)
+ drv_ops->mfi_capabilities.support_ext_io_size = 1;
+
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
@@ -726,6 +725,83 @@ fail_get_cmd:
return ret;
}
+/**
+ * megasas_sync_pd_seq_num - JBOD SEQ MAP
+ * @instance: Adapter soft state
+ * @pend: set to 1, if it is pended jbod map.
+ *
+ * Issue Jbod map to the firmware. If it is pended command,
+ * issue command and return. If it is first instance of jbod map
+ * issue and receive command.
+ */
+int
+megasas_sync_pd_seq_num(struct megasas_instance *instance, bool pend) {
+ int ret = 0;
+ u32 pd_seq_map_sz;
+ struct megasas_cmd *cmd;
+ struct megasas_dcmd_frame *dcmd;
+ struct fusion_context *fusion = instance->ctrl_context;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
+ dma_addr_t pd_seq_h;
+
+ pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id & 1)];
+ pd_seq_h = fusion->pd_seq_phys[(instance->pd_seq_map_id & 1)];
+ pd_seq_map_sz = sizeof(struct MR_PD_CFG_SEQ_NUM_SYNC) +
+ (sizeof(struct MR_PD_CFG_SEQ) *
+ (MAX_PHYSICAL_DEVICES - 1));
+
+ cmd = megasas_get_cmd(instance);
+ if (!cmd) {
+ dev_err(&instance->pdev->dev,
+ "Could not get mfi cmd. Fail from %s %d\n",
+ __func__, __LINE__);
+ return -ENOMEM;
+ }
+
+ dcmd = &cmd->frame->dcmd;
+
+ memset(pd_sync, 0, pd_seq_map_sz);
+ memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE);
+ dcmd->cmd = MFI_CMD_DCMD;
+ dcmd->cmd_status = 0xFF;
+ dcmd->sge_count = 1;
+ dcmd->timeout = 0;
+ dcmd->pad_0 = 0;
+ dcmd->data_xfer_len = cpu_to_le32(pd_seq_map_sz);
+ dcmd->opcode = cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO);
+ dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(pd_seq_h);
+ dcmd->sgl.sge32[0].length = cpu_to_le32(pd_seq_map_sz);
+
+ if (pend) {
+ dcmd->mbox.b[0] = MEGASAS_DCMD_MBOX_PEND_FLAG;
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_WRITE);
+ instance->jbod_seq_cmd = cmd;
+ instance->instancet->issue_dcmd(instance, cmd);
+ return 0;
+ }
+
+ dcmd->flags = cpu_to_le16(MFI_FRAME_DIR_READ);
+
+ /* Below code is only for non pended DCMD */
+ if (instance->ctrl_context && !instance->mask_interrupts)
+ ret = megasas_issue_blocked_cmd(instance, cmd, 60);
+ else
+ ret = megasas_issue_polled(instance, cmd);
+
+ if (le32_to_cpu(pd_sync->count) > MAX_PHYSICAL_DEVICES) {
+ dev_warn(&instance->pdev->dev,
+ "driver supports max %d JBOD, but FW reports %d\n",
+ MAX_PHYSICAL_DEVICES, le32_to_cpu(pd_sync->count));
+ ret = -EINVAL;
+ }
+
+ if (!ret)
+ instance->pd_seq_map_id++;
+
+ megasas_return_cmd(instance, cmd);
+ return ret;
+}
+
/*
* megasas_get_ld_map_info - Returns FW's ld_map structure
* @instance: Adapter soft state
@@ -961,6 +1037,18 @@ megasas_display_intel_branding(struct megasas_instance *instance)
break;
}
break;
+ case PCI_DEVICE_ID_LSI_CUTLASS_52:
+ case PCI_DEVICE_ID_LSI_CUTLASS_53:
+ switch (instance->pdev->subsystem_device) {
+ case MEGARAID_INTEL_RMS3BC160_SSDID:
+ dev_info(&instance->pdev->dev, "scsi host %d: %s\n",
+ instance->host->host_no,
+ MEGARAID_INTEL_RMS3BC160_BRANDING);
+ break;
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -977,7 +1065,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
{
struct megasas_register_set __iomem *reg_set;
struct fusion_context *fusion;
- u32 max_cmd;
+ u32 max_cmd, scratch_pad_2;
int i = 0, count;
fusion = instance->ctrl_context;
@@ -1016,15 +1104,40 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
(MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE *
(max_cmd + 1)); /* Extra 1 for SMID 0 */
+ scratch_pad_2 = readl(&instance->reg_set->outbound_scratch_pad_2);
+ /* If scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK is set,
+ * Firmware support extended IO chain frame which is 4 times more than
+ * legacy Firmware.
+ * Legacy Firmware - Frame size is (8 * 128) = 1K
+ * 1M IO Firmware - Frame size is (8 * 128 * 4) = 4K
+ */
+ if (scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK)
+ instance->max_chain_frame_sz =
+ ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
+ MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_1MB_IO;
+ else
+ instance->max_chain_frame_sz =
+ ((scratch_pad_2 & MEGASAS_MAX_CHAIN_SIZE_MASK) >>
+ MEGASAS_MAX_CHAIN_SHIFT) * MEGASAS_256K_IO;
+
+ if (instance->max_chain_frame_sz < MEGASAS_CHAIN_FRAME_SZ_MIN) {
+ dev_warn(&instance->pdev->dev, "frame size %d invalid, fall back to legacy max frame size %d\n",
+ instance->max_chain_frame_sz,
+ MEGASAS_CHAIN_FRAME_SZ_MIN);
+ instance->max_chain_frame_sz = MEGASAS_CHAIN_FRAME_SZ_MIN;
+ }
+
fusion->max_sge_in_main_msg =
- (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE -
- offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
+ (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE
+ - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16;
fusion->max_sge_in_chain =
- MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION);
+ instance->max_chain_frame_sz
+ / sizeof(union MPI2_SGE_IO_UNION);
- instance->max_num_sge = rounddown_pow_of_two(
- fusion->max_sge_in_main_msg + fusion->max_sge_in_chain - 2);
+ instance->max_num_sge =
+ rounddown_pow_of_two(fusion->max_sge_in_main_msg
+ + fusion->max_sge_in_chain - 2);
/* Used for pass thru MFI frame (DCMD) */
fusion->chain_offset_mfi_pthru =
@@ -1186,8 +1299,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
fusion = instance->ctrl_context;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr;
sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
sgl_ptr_end->Flags = 0;
@@ -1204,11 +1316,9 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sgl_ptr->Length = cpu_to_le32(sg_dma_len(os_sgl));
sgl_ptr->Address = cpu_to_le64(sg_dma_address(os_sgl));
sgl_ptr->Flags = 0;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES)
if (i == sge_count - 1)
sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST;
- }
sgl_ptr++;
sg_processed = i + 1;
@@ -1217,10 +1327,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
(sge_count > fusion->max_sge_in_main_msg)) {
struct MPI25_IEEE_SGE_CHAIN64 *sg_chain;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
if ((le16_to_cpu(cmd->io_request->IoFlags) &
MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) !=
MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH)
@@ -1236,10 +1343,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sg_chain = sgl_ptr;
/* Prepare chain element */
sg_chain->NextChainOffset = 0;
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT;
else
sg_chain->Flags =
@@ -1250,7 +1354,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sgl_ptr =
(struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
- memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
+ memset(sgl_ptr, 0, instance->max_chain_frame_sz);
}
}
@@ -1556,8 +1660,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
cmd->request_desc->SCSIIO.RequestFlags =
(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
if (io_request->RaidContext.regLockFlags ==
REGION_TYPE_UNUSED)
cmd->request_desc->SCSIIO.RequestFlags =
@@ -1582,7 +1685,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG;
if ((raidLUN[0] == 1) &&
- (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 2)) {
+ (local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].validHandles > 1)) {
instance->dev_handle = !(instance->dev_handle);
io_info.devHandle =
local_map_ptr->raidMap.devHndlInfo[io_info.pd_after_lb].devHandle[instance->dev_handle];
@@ -1598,8 +1701,7 @@ megasas_build_ldio_fusion(struct megasas_instance *instance,
cmd->request_desc->SCSIIO.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO
<< MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
if (io_request->RaidContext.regLockFlags ==
REGION_TYPE_UNUSED)
cmd->request_desc->SCSIIO.RequestFlags =
@@ -1722,7 +1824,9 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
u16 timeout_limit;
struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
struct RAID_CONTEXT *pRAID_Context;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_sync;
struct fusion_context *fusion = instance->ctrl_context;
+ pd_sync = (void *)fusion->pd_seq_sync[(instance->pd_seq_map_id - 1) & 1];
device_id = MEGASAS_DEV_INDEX(scmd);
pd_index = MEGASAS_PD_INDEX(scmd);
@@ -1731,16 +1835,38 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
io_request = cmd->io_request;
/* get RAID_Context pointer */
pRAID_Context = &io_request->RaidContext;
+ pRAID_Context->regLockFlags = 0;
+ pRAID_Context->regLockRowLBA = 0;
+ pRAID_Context->regLockLength = 0;
io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
io_request->LUN[1] = scmd->device->lun;
pRAID_Context->RAIDFlags = MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
<< MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
- pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
- pRAID_Context->configSeqNum = 0;
- local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
- io_request->DevHandle =
- local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ /* If FW supports PD sequence number */
+ if (instance->use_seqnum_jbod_fp &&
+ instance->pd_list[pd_index].driveType == TYPE_DISK) {
+ /* TgtId must be incremented by 255 as jbod seq number is index
+ * below raid map
+ */
+ pRAID_Context->VirtualDiskTgtId =
+ cpu_to_le16(device_id + (MAX_PHYSICAL_DEVICES - 1));
+ pRAID_Context->configSeqNum = pd_sync->seq[pd_index].seqNum;
+ io_request->DevHandle = pd_sync->seq[pd_index].devHandle;
+ pRAID_Context->regLockFlags |=
+ (MR_RL_FLAGS_SEQ_NUM_ENABLE|MR_RL_FLAGS_GRANT_DESTINATION_CUDA);
+ } else if (fusion->fast_path_io) {
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+ pRAID_Context->configSeqNum = 0;
+ local_map_ptr = fusion->ld_drv_map[(instance->map_id & 1)];
+ io_request->DevHandle =
+ local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ } else {
+ /* Want to send all IO via FW path */
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
+ pRAID_Context->configSeqNum = 0;
+ io_request->DevHandle = cpu_to_le16(0xFFFF);
+ }
cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
cmd->request_desc->SCSIIO.MSIxIndex =
@@ -1755,22 +1881,16 @@ megasas_build_syspd_fusion(struct megasas_instance *instance,
(MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
pRAID_Context->timeoutValue = cpu_to_le16(os_timeout_value);
+ pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
} else {
/* system pd Fast Path */
io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- pRAID_Context->regLockFlags = 0;
- pRAID_Context->regLockRowLBA = 0;
- pRAID_Context->regLockLength = 0;
timeout_limit = (scmd->device->type == TYPE_DISK) ?
255 : 0xFFFF;
pRAID_Context->timeoutValue =
cpu_to_le16((os_timeout_value > timeout_limit) ?
timeout_limit : os_timeout_value);
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- cmd->request_desc->SCSIIO.RequestFlags |=
- (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ if (fusion->adapter_type == INVADER_SERIES) {
pRAID_Context->Type = MPI2_TYPE_CUDA;
pRAID_Context->nseg = 0x1;
io_request->IoFlags |=
@@ -1796,7 +1916,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
struct scsi_cmnd *scp,
struct megasas_cmd_fusion *cmd)
{
- u32 sge_count;
+ u16 sge_count;
u8 cmd_type;
struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request;
@@ -1854,7 +1974,11 @@ megasas_build_io_fusion(struct megasas_instance *instance,
return 1;
}
+ /* numSGE store lower 8 bit of sge_count.
+ * numSGEExt store higher 8 bit of sge_count
+ */
io_request->RaidContext.numSGE = sge_count;
+ io_request->RaidContext.numSGEExt = (u8)(sge_count >> 8);
io_request->SGLFlags = cpu_to_le16(MPI2_SGE_FLAGS_64_BIT_ADDRESSING);
@@ -2084,10 +2208,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
* pending to be completed
*/
if (threshold_reply_count >= THRESHOLD_REPLY_COUNT) {
- if ((instance->pdev->device ==
- PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device ==
- PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2103,8 +2224,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex)
return IRQ_NONE;
wmb();
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ if (fusion->adapter_type == INVADER_SERIES)
writel(((MSIxIndex & 0x7) << 24) |
fusion->last_reply_idx[MSIxIndex],
instance->reply_post_host_index_addr[MSIxIndex/8]);
@@ -2227,8 +2347,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
io_req = cmd->io_request;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ if (fusion->adapter_type == INVADER_SERIES) {
struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end =
(struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL;
sgl_ptr_end += fusion->max_sge_in_main_msg - 1;
@@ -2248,7 +2367,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT |
MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR;
- mpi25_ieee_chain->Length = cpu_to_le32(MEGASAS_MAX_SZ_CHAIN_FRAME);
+ mpi25_ieee_chain->Length = cpu_to_le32(instance->max_chain_frame_sz);
return 0;
}
@@ -2384,6 +2503,70 @@ static int
megasas_adp_reset_fusion(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
+ u32 host_diag, abs_state, retry;
+
+ /* Now try to reset the chip */
+ writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+ writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
+
+ /* Check that the diag write enable (DRWE) bit is on */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
+ msleep(100);
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 100) {
+ dev_warn(&instance->pdev->dev,
+ "Host diag unlock failed from %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
+ return -1;
+
+ /* Send chip reset command */
+ writel(host_diag | HOST_DIAG_RESET_ADAPTER,
+ &instance->reg_set->fusion_host_diag);
+ msleep(3000);
+
+ /* Make sure reset adapter bit is cleared */
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ retry = 0;
+ while (host_diag & HOST_DIAG_RESET_ADAPTER) {
+ msleep(100);
+ host_diag = readl(&instance->reg_set->fusion_host_diag);
+ if (retry++ == 1000) {
+ dev_warn(&instance->pdev->dev,
+ "Diag reset adapter never cleared %s %d\n",
+ __func__, __LINE__);
+ break;
+ }
+ }
+ if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ return -1;
+
+ abs_state = instance->instancet->read_fw_status_reg(instance->reg_set)
+ & MFI_STATE_MASK;
+ retry = 0;
+
+ while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
+ msleep(100);
+ abs_state = instance->instancet->
+ read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ }
+ if (abs_state <= MFI_STATE_FW_INIT) {
+ dev_warn(&instance->pdev->dev,
+ "fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n",
+ abs_state, __func__, __LINE__);
+ return -1;
+ }
+
return 0;
}
@@ -2512,8 +2695,10 @@ void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
continue;
req_desc = megasas_get_request_descriptor
(instance, smid - 1);
- if (req_desc && (cmd_mfi->frame->dcmd.opcode !=
- cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)))
+ if (req_desc && ((cmd_mfi->frame->dcmd.opcode !=
+ cpu_to_le32(MR_DCMD_LD_MAP_GET_INFO)) &&
+ (cmd_mfi->frame->dcmd.opcode !=
+ cpu_to_le32(MR_DCMD_SYSTEM_PD_MAP_GET_INFO))))
megasas_fire_cmd_fusion(instance, req_desc);
else
megasas_return_cmd(instance, cmd_mfi);
@@ -2547,11 +2732,11 @@ out:
/* Core fusion reset function */
int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
{
- int retval = SUCCESS, i, retry = 0, convert = 0;
+ int retval = SUCCESS, i, convert = 0;
struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion;
- u32 host_diag, abs_state, status_reg, reset_adapter;
+ u32 abs_state, status_reg, reset_adapter;
u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL;
@@ -2705,82 +2890,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
/* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_1ST_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_2ND_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_3RD_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_4TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_5TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
- writel(MPI2_WRSEQ_6TH_KEY_VALUE,
- &instance->reg_set->fusion_seq_offset);
-
- /* Check that the diag write enable (DRWE) bit is on */
- host_diag = readl(&instance->reg_set->fusion_host_diag);
- retry = 0;
- while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
- msleep(100);
- host_diag =
- readl(&instance->reg_set->fusion_host_diag);
- if (retry++ == 100) {
- dev_warn(&instance->pdev->dev,
- "Host diag unlock failed! "
- "for scsi%d\n",
- instance->host->host_no);
- break;
- }
- }
- if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
- continue;
- /* Send chip reset command */
- writel(host_diag | HOST_DIAG_RESET_ADAPTER,
- &instance->reg_set->fusion_host_diag);
- msleep(3000);
-
- /* Make sure reset adapter bit is cleared */
- host_diag = readl(&instance->reg_set->fusion_host_diag);
- retry = 0;
- while (host_diag & HOST_DIAG_RESET_ADAPTER) {
- msleep(100);
- host_diag =
- readl(&instance->reg_set->fusion_host_diag);
- if (retry++ == 1000) {
- dev_warn(&instance->pdev->dev,
- "Diag reset adapter never "
- "cleared for scsi%d!\n",
- instance->host->host_no);
- break;
- }
- }
- if (host_diag & HOST_DIAG_RESET_ADAPTER)
+ if (instance->instancet->adp_reset
+ (instance, instance->reg_set))
continue;
- abs_state =
- instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- retry = 0;
-
- while ((abs_state <= MFI_STATE_FW_INIT) &&
- (retry++ < 1000)) {
- msleep(100);
- abs_state =
- instance->instancet->read_fw_status_reg(
- instance->reg_set) & MFI_STATE_MASK;
- }
- if (abs_state <= MFI_STATE_FW_INIT) {
- dev_warn(&instance->pdev->dev, "firmware "
- "state < MFI_STATE_FW_INIT, state = "
- "0x%x for scsi%d\n", abs_state,
- instance->host->host_no);
- continue;
- }
-
/* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) {
dev_warn(&instance->pdev->dev, "Failed to "
@@ -2816,6 +2930,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
+ megasas_setup_jbod_map(instance);
+
clear_bit(MEGASAS_FUSION_IN_RESET,
&instance->reset_flags);
instance->instancet->enable_intr(instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index ced6dc0..473005c 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -35,8 +35,13 @@
#define _MEGARAID_SAS_FUSION_H_
/* Fusion defines */
-#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024
+#define MEGASAS_CHAIN_FRAME_SZ_MIN 1024
#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009)
+#define MEGASAS_MAX_CHAIN_SHIFT 5
+#define MEGASAS_MAX_CHAIN_SIZE_UNITS_MASK 0x400000
+#define MEGASAS_MAX_CHAIN_SIZE_MASK 0x3E0
+#define MEGASAS_256K_IO 128
+#define MEGASAS_1MB_IO (MEGASAS_256K_IO * 4)
#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256
#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0
#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1
@@ -89,6 +94,12 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {
#define MEGASAS_FP_CMD_LEN 16
#define MEGASAS_FUSION_IN_RESET 0
#define THRESHOLD_REPLY_COUNT 50
+#define JBOD_MAPS_COUNT 2
+
+enum MR_FUSION_ADAPTER_TYPE {
+ THUNDERBOLT_SERIES = 0,
+ INVADER_SERIES = 1,
+};
/*
* Raid Context structure which describes MegaRAID specific IO Parameters
@@ -117,7 +128,9 @@ struct RAID_CONTEXT {
u8 numSGE;
__le16 configSeqNum;
u8 spanArm;
- u8 resvd2[3];
+ u8 priority;
+ u8 numSGEExt;
+ u8 resvd2;
};
#define RAID_CTX_SPANARM_ARM_SHIFT (0)
@@ -486,6 +499,7 @@ struct MPI2_IOC_INIT_REQUEST {
#define MAX_PHYSICAL_DEVICES 256
#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES)
#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101
+#define MR_DCMD_SYSTEM_PD_MAP_GET_INFO 0x0200e102
#define MR_DCMD_CTRL_SHARED_HOST_MEM_ALLOC 0x010e8485 /* SR-IOV HB alloc*/
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS_111 0x03200200
#define MR_DCMD_LD_VF_MAP_GET_ALL_LDS 0x03150200
@@ -789,6 +803,21 @@ struct MR_FW_RAID_MAP_EXT {
struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES_EXT];
};
+/*
+ * * define MR_PD_CFG_SEQ structure for system PDs
+ * */
+struct MR_PD_CFG_SEQ {
+ __le16 seqNum;
+ __le16 devHandle;
+ u8 reserved[4];
+} __packed;
+
+struct MR_PD_CFG_SEQ_NUM_SYNC {
+ __le32 size;
+ __le32 count;
+ struct MR_PD_CFG_SEQ seq[1];
+} __packed;
+
struct fusion_context {
struct megasas_cmd_fusion **cmd_list;
dma_addr_t req_frames_desc_phys;
@@ -828,9 +857,12 @@ struct fusion_context {
u32 current_map_sz;
u32 drv_map_sz;
u32 drv_map_pages;
+ struct MR_PD_CFG_SEQ_NUM_SYNC *pd_seq_sync[JBOD_MAPS_COUNT];
+ dma_addr_t pd_seq_phys[JBOD_MAPS_COUNT];
u8 fast_path_io;
struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES_EXT];
LD_SPAN_INFO log_to_span[MAX_LOGICAL_DRIVES_EXT];
+ u8 adapter_type;
};
union desc_value {
diff --git a/drivers/scsi/mpt2sas/Kconfig b/drivers/scsi/mpt2sas/Kconfig
deleted file mode 100644
index 657b45c..0000000
--- a/drivers/scsi/mpt2sas/Kconfig
+++ /dev/null
@@ -1,67 +0,0 @@
-#
-# Kernel configuration file for the MPT2SAS
-#
-# This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2014 LSI Corporation
-# (mailto:DL-MPTFusionLinux@lsi.com)
-
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-
-# NO WARRANTY
-# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
-# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
-# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
-# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
-# solely responsible for determining the appropriateness of using and
-# distributing the Program and assumes all risks associated with its
-# exercise of rights under this Agreement, including but not limited to
-# the risks and costs of program errors, damage to or loss of data,
-# programs or equipment, and unavailability or interruption of operations.
-
-# DISCLAIMER OF LIABILITY
-# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
-# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
-# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
-# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
-# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-# USA.
-
-config SCSI_MPT2SAS
- tristate "LSI MPT Fusion SAS 2.0 Device Driver"
- depends on PCI && SCSI
- select SCSI_SAS_ATTRS
- select RAID_ATTRS
- ---help---
- This driver supports PCI-Express SAS 6Gb/s Host Adapters.
-
-config SCSI_MPT2SAS_MAX_SGE
- int "LSI MPT Fusion Max number of SG Entries (16 - 128)"
- depends on PCI && SCSI && SCSI_MPT2SAS
- default "128"
- range 16 128
- ---help---
- This option allows you to specify the maximum number of scatter-
- gather entries per I/O. The driver default is 128, which matches
- SAFE_PHYS_SEGMENTS. However, it may decreased down to 16.
- Decreasing this parameter will reduce memory requirements
- on a per controller instance.
-
-config SCSI_MPT2SAS_LOGGING
- bool "LSI MPT Fusion logging facility"
- depends on PCI && SCSI && SCSI_MPT2SAS
- ---help---
- This turns on a logging facility.
diff --git a/drivers/scsi/mpt2sas/Makefile b/drivers/scsi/mpt2sas/Makefile
deleted file mode 100644
index 728f047..0000000
--- a/drivers/scsi/mpt2sas/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# mpt2sas makefile
-obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o
-mpt2sas-y += mpt2sas_base.o \
- mpt2sas_config.o \
- mpt2sas_scsih.o \
- mpt2sas_transport.o \
- mpt2sas_ctl.o
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
deleted file mode 100644
index 7fc6f23..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ /dev/null
@@ -1,1170 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2.h
- * Title: MPI Message independent structures and definitions
- * including System Interface Register Set and
- * scatter/gather formats.
- * Creation Date: June 21, 2006
- *
- * mpi2.h Version: 02.00.35
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT.
- * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT.
- * Moved ReplyPostHostIndex register to offset 0x6C of the
- * MPI2_SYSTEM_INTERFACE_REGS and modified the define for
- * MPI2_REPLY_POST_HOST_INDEX_OFFSET.
- * Added union of request descriptors.
- * Added union of reply descriptors.
- * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added define for MPI2_VERSION_02_00.
- * Fixed the size of the FunctionDependent5 field in the
- * MPI2_DEFAULT_REPLY structure.
- * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT.
- * Removed the MPI-defined Fault Codes and extended the
- * product specific codes up to 0xEFFF.
- * Added a sixth key value for the WriteSequence register
- * and changed the flush value to 0x0.
- * Added message function codes for Diagnostic Buffer Post
- * and Diagnsotic Release.
- * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
- * Moved MPI2_VERSION_UNION from mpi2_ioc.h.
- * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT.
- * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added #defines for marking a reply descriptor as unused.
- * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT.
- * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
- * Moved LUN field defines from mpi2_init.h.
- * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
- * In all request and reply descriptors, replaced VF_ID
- * field with MSIxIndex field.
- * Removed DevHandle field from
- * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
- * bytes reserved.
- * Added RAID Accelerator functionality.
- * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT.
- * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MSI-x index mask and shift for Reply Post Host
- * Index register.
- * Added function code for Host Based Discovery Action.
- * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL.
- * Added defines for product-specific range of message
- * function codes, 0xF0 to 0xFF.
- * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added alternative defines for the SGE Direction bit.
- * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define.
- * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI2_FUNCTION_SEND_HOST_MESSAGE.
- * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT.
- * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-18-11 02.00.23 Bumped MPI2_HEADER_VERSION_UNIT.
- * 02-06-12 02.00.24 Bumped MPI2_HEADER_VERSION_UNIT.
- * 03-29-12 02.00.25 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added Hard Reset delay timings.
- * 07-10-12 02.00.26 Bumped MPI2_HEADER_VERSION_UNIT.
- * 07-26-12 02.00.27 Bumped MPI2_HEADER_VERSION_UNIT.
- * 11-27-12 02.00.28 Bumped MPI2_HEADER_VERSION_UNIT.
- * 12-20-12 02.00.29 Bumped MPI2_HEADER_VERSION_UNIT.
- * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET.
- * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
- * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
- * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
- * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
- * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT.
- * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_H
-#define MPI2_H
-
-
-/*****************************************************************************
-*
-* MPI Version Definitions
-*
-*****************************************************************************/
-
-#define MPI2_VERSION_MAJOR (0x02)
-#define MPI2_VERSION_MINOR (0x00)
-#define MPI2_VERSION_MAJOR_MASK (0xFF00)
-#define MPI2_VERSION_MAJOR_SHIFT (8)
-#define MPI2_VERSION_MINOR_MASK (0x00FF)
-#define MPI2_VERSION_MINOR_SHIFT (0)
-#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \
- MPI2_VERSION_MINOR)
-
-#define MPI2_VERSION_02_00 (0x0200)
-
-/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x23)
-#define MPI2_HEADER_VERSION_DEV (0x00)
-#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
-#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
-#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF)
-#define MPI2_HEADER_VERSION_DEV_SHIFT (0)
-#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV)
-
-
-/*****************************************************************************
-*
-* IOC State Definitions
-*
-*****************************************************************************/
-
-#define MPI2_IOC_STATE_RESET (0x00000000)
-#define MPI2_IOC_STATE_READY (0x10000000)
-#define MPI2_IOC_STATE_OPERATIONAL (0x20000000)
-#define MPI2_IOC_STATE_FAULT (0x40000000)
-
-#define MPI2_IOC_STATE_MASK (0xF0000000)
-#define MPI2_IOC_STATE_SHIFT (28)
-
-/* Fault state range for prodcut specific codes */
-#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000)
-#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF)
-
-
-/*****************************************************************************
-*
-* System Interface Register Definitions
-*
-*****************************************************************************/
-
-typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
-{
- U32 Doorbell; /* 0x00 */
- U32 WriteSequence; /* 0x04 */
- U32 HostDiagnostic; /* 0x08 */
- U32 Reserved1; /* 0x0C */
- U32 DiagRWData; /* 0x10 */
- U32 DiagRWAddressLow; /* 0x14 */
- U32 DiagRWAddressHigh; /* 0x18 */
- U32 Reserved2[5]; /* 0x1C */
- U32 HostInterruptStatus; /* 0x30 */
- U32 HostInterruptMask; /* 0x34 */
- U32 DCRData; /* 0x38 */
- U32 DCRAddress; /* 0x3C */
- U32 Reserved3[2]; /* 0x40 */
- U32 ReplyFreeHostIndex; /* 0x48 */
- U32 Reserved4[8]; /* 0x4C */
- U32 ReplyPostHostIndex; /* 0x6C */
- U32 Reserved5; /* 0x70 */
- U32 HCBSize; /* 0x74 */
- U32 HCBAddressLow; /* 0x78 */
- U32 HCBAddressHigh; /* 0x7C */
- U32 Reserved6[16]; /* 0x80 */
- U32 RequestDescriptorPostLow; /* 0xC0 */
- U32 RequestDescriptorPostHigh; /* 0xC4 */
- U32 Reserved7[14]; /* 0xC8 */
-} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS,
- Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t;
-
-/*
- * Defines for working with the Doorbell register.
- */
-#define MPI2_DOORBELL_OFFSET (0x00000000)
-
-/* IOC --> System values */
-#define MPI2_DOORBELL_USED (0x08000000)
-#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000)
-#define MPI2_DOORBELL_WHO_INIT_SHIFT (24)
-#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF)
-#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF)
-
-/* System --> IOC values */
-#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000)
-#define MPI2_DOORBELL_FUNCTION_SHIFT (24)
-#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000)
-#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16)
-
-
-/*
- * Defines for the WriteSequence register
- */
-#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004)
-#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F)
-#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0)
-#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF)
-#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4)
-#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB)
-#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2)
-#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7)
-#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD)
-
-/*
- * Defines for the HostDiagnostic register
- */
-#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008)
-
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800)
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000)
-#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800)
-
-#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400)
-#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200)
-#define MPI2_DIAG_HCB_MODE (0x00000100)
-#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080)
-#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040)
-#define MPI2_DIAG_RESET_HISTORY (0x00000020)
-#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010)
-#define MPI2_DIAG_RESET_ADAPTER (0x00000004)
-#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002)
-
-/*
- * Offsets for DiagRWData and address
- */
-#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010)
-#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014)
-#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018)
-
-/*
- * Defines for the HostInterruptStatus register
- */
-#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030)
-#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000)
-#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS
-#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000)
-#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008)
-#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001)
-#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS
-
-/*
- * Defines for the HostInterruptMask register
- */
-#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034)
-#define MPI2_HIM_RESET_IRQ_MASK (0x40000000)
-#define MPI2_HIM_REPLY_INT_MASK (0x00000008)
-#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK
-#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001)
-#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK
-
-/*
- * Offsets for DCRData and address
- */
-#define MPI2_DCR_DATA_OFFSET (0x00000038)
-#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C)
-
-/*
- * Offset for the Reply Free Queue
- */
-#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048)
-
-/*
- * Defines for the Reply Descriptor Post Queue
- */
-#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C)
-#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF)
-#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000)
-#define MPI2_RPHI_MSIX_INDEX_SHIFT (24)
-#define MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET (0x0000030C) /* MPI v2.5 only */
-
-/*
- * Defines for the HCBSize and address
- */
-#define MPI2_HCB_SIZE_OFFSET (0x00000074)
-#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000)
-#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001)
-
-#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078)
-#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C)
-
-/*
- * Offsets for the Request Queue
- */
-#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0)
-#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4)
-
-
-/* Hard Reset delay timings */
-#define MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC (50000)
-#define MPI2_HARD_RESET_PCIE_RESET_READ_WINDOW_MICRO_SEC (255000)
-#define MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC (256000)
-
-/*****************************************************************************
-*
-* Message Descriptors
-*
-*****************************************************************************/
-
-/* Request Descriptors */
-
-/* Default Request Descriptor */
-typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 DescriptorTypeDependent; /* 0x06 */
-} MPI2_DEFAULT_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR,
- Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t;
-
-/* defines for the RequestFlags field */
-#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E)
-#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00)
-#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
-#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
-#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08)
-#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
-
-#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
-
-
-/* High Priority Request Descriptor */
-typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 Reserved1; /* 0x06 */
-} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR,
- Mpi2HighPriorityRequestDescriptor_t,
- MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t;
-
-
-/* SCSI IO Request Descriptor */
-typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 DevHandle; /* 0x06 */
-} MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR,
- Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t;
-
-
-/* SCSI Target Request Descriptor */
-typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
-{
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 IoIndex; /* 0x06 */
-} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR,
- Mpi2SCSITargetRequestDescriptor_t,
- MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t;
-
-
-/* RAID Accelerator Request Descriptor */
-typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
- U8 RequestFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 LMID; /* 0x04 */
- U16 Reserved; /* 0x06 */
-} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
- Mpi2RAIDAcceleratorRequestDescriptor_t,
- MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t;
-
-
-/* union of Request Descriptors */
-typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
-{
- MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
- MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
- MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
- MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
- MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
- U64 Words;
-} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
- Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
-
-
-/* Reply Descriptors */
-
-/* Default Reply Descriptor */
-typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 DescriptorTypeDependent1; /* 0x02 */
- U32 DescriptorTypeDependent2; /* 0x04 */
-} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
- Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;
-
-/* defines for the ReplyFlags field */
-#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
-#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
-#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
-#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05)
-#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
-
-/* values for marking a reply descriptor as unused */
-#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF)
-#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF)
-
-/* Address Reply Descriptor */
-typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U32 ReplyFrameAddress; /* 0x04 */
-} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
- Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t;
-
-#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00)
-
-
-/* SCSI IO Success Reply Descriptor */
-typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U16 TaskTag; /* 0x04 */
- U16 Reserved1; /* 0x06 */
-} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
- Mpi2SCSIIOSuccessReplyDescriptor_t,
- MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t;
-
-
-/* TargetAssist Success Reply Descriptor */
-typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U8 SequenceNumber; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 IoIndex; /* 0x06 */
-} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR,
- Mpi2TargetAssistSuccessReplyDescriptor_t,
- MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t;
-
-
-/* Target Command Buffer Reply Descriptor */
-typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
-{
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U8 VP_ID; /* 0x02 */
- U8 Flags; /* 0x03 */
- U16 InitiatorDevHandle; /* 0x04 */
- U16 IoIndex; /* 0x06 */
-} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR,
- Mpi2TargetCommandBufferReplyDescriptor_t,
- MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t;
-
-/* defines for Flags field */
-#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F)
-
-
-/* RAID Accelerator Success Reply Descriptor */
-typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
- U8 ReplyFlags; /* 0x00 */
- U8 MSIxIndex; /* 0x01 */
- U16 SMID; /* 0x02 */
- U32 Reserved; /* 0x04 */
-} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
- MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
- Mpi2RAIDAcceleratorSuccessReplyDescriptor_t,
- MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t;
-
-
-/* union of Reply Descriptors */
-typedef union _MPI2_REPLY_DESCRIPTORS_UNION
-{
- MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
- MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
- MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
- MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
- MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
- MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
- U64 Words;
-} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
-Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
-
-
-
-/*****************************************************************************
-*
-* Message Functions
-*
-*****************************************************************************/
-
-#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */
-#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */
-#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */
-#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */
-#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */
-#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */
-#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */
-#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */
-#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */
-#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */
-#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */
-#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */
-#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */
-#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */
-#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */
-#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */
-#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */
-#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */
-#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */
-#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */
-#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */
-#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */
-#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */
-#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
-#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
-#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/
-/* Host Based Discovery Action */
-#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F)
-/* Power Management Control */
-#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30)
-/* Send Host Message */
-#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31)
-/* beginning of product-specific range */
-#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0)
-/* end of product-specific range */
-#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF)
-
-
-
-
-/* Doorbell functions */
-#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40)
-#define MPI2_FUNCTION_HANDSHAKE (0x42)
-
-
-/*****************************************************************************
-*
-* IOC Status Values
-*
-*****************************************************************************/
-
-/* mask for IOCStatus status value */
-#define MPI2_IOCSTATUS_MASK (0x7FFF)
-
-/****************************************************************************
-* Common IOCStatus values for all replies
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SUCCESS (0x0000)
-#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001)
-#define MPI2_IOCSTATUS_BUSY (0x0002)
-#define MPI2_IOCSTATUS_INVALID_SGL (0x0003)
-#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004)
-#define MPI2_IOCSTATUS_INVALID_VPID (0x0005)
-#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006)
-#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007)
-#define MPI2_IOCSTATUS_INVALID_STATE (0x0008)
-#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009)
-
-/****************************************************************************
-* Config IOCStatus values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022)
-#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023)
-#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024)
-#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025)
-
-/****************************************************************************
-* SCSI IO Reply
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040)
-#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042)
-#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043)
-#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044)
-#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045)
-#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046)
-#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047)
-#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048)
-#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049)
-#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A)
-#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B)
-#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C)
-
-/****************************************************************************
-* For use by SCSI Initiator and SCSI Target end-to-end data protection
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D)
-#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E)
-#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F)
-
-/****************************************************************************
-* SCSI Target values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062)
-#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063)
-#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064)
-#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065)
-#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A)
-#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D)
-#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E)
-#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F)
-#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070)
-#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071)
-
-/****************************************************************************
-* Serial Attached SCSI values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090)
-#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091)
-
-/****************************************************************************
-* Diagnostic Buffer Post / Diagnostic Release values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0)
-
-/****************************************************************************
-* RAID Accelerator values
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0)
-
-/****************************************************************************
-* IOCStatus flag to indicate that log info is available
-****************************************************************************/
-
-#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
-
-/****************************************************************************
-* IOCLogInfo Types
-****************************************************************************/
-
-#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000)
-#define MPI2_IOCLOGINFO_TYPE_SHIFT (28)
-#define MPI2_IOCLOGINFO_TYPE_NONE (0x0)
-#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1)
-#define MPI2_IOCLOGINFO_TYPE_FC (0x2)
-#define MPI2_IOCLOGINFO_TYPE_SAS (0x3)
-#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4)
-#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF)
-
-
-/*****************************************************************************
-*
-* Standard Message Structures
-*
-*****************************************************************************/
-
-/****************************************************************************
-* Request Message Header for all request messages
-****************************************************************************/
-
-typedef struct _MPI2_REQUEST_HEADER
-{
- U16 FunctionDependent1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 FunctionDependent2; /* 0x04 */
- U8 FunctionDependent3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
-} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER,
- MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t;
-
-
-/****************************************************************************
-* Default Reply
-****************************************************************************/
-
-typedef struct _MPI2_DEFAULT_REPLY
-{
- U16 FunctionDependent1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 FunctionDependent2; /* 0x04 */
- U8 FunctionDependent3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 FunctionDependent5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY,
- MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t;
-
-
-/* common version structure/union used in messages and configuration pages */
-
-typedef struct _MPI2_VERSION_STRUCT
-{
- U8 Dev; /* 0x00 */
- U8 Unit; /* 0x01 */
- U8 Minor; /* 0x02 */
- U8 Major; /* 0x03 */
-} MPI2_VERSION_STRUCT;
-
-typedef union _MPI2_VERSION_UNION
-{
- MPI2_VERSION_STRUCT Struct;
- U32 Word;
-} MPI2_VERSION_UNION;
-
-
-/* LUN field defines, common to many structures */
-#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF)
-#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000)
-#define MPI2_LUN_LEVEL_1_WORD (0xFF00)
-#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00)
-
-
-/*****************************************************************************
-*
-* Fusion-MPT MPI Scatter Gather Elements
-*
-*****************************************************************************/
-
-/****************************************************************************
-* MPI Simple Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_SIMPLE32
-{
- U32 FlagsLength;
- U32 Address;
-} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32,
- Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t;
-
-typedef struct _MPI2_SGE_SIMPLE64
-{
- U32 FlagsLength;
- U64 Address;
-} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64,
- Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t;
-
-typedef struct _MPI2_SGE_SIMPLE_UNION
-{
- U32 FlagsLength;
- union
- {
- U32 Address32;
- U64 Address64;
- } u;
-} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION,
- Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t;
-
-
-/****************************************************************************
-* MPI Chain Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_CHAIN32
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- U32 Address;
-} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32,
- Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t;
-
-typedef struct _MPI2_SGE_CHAIN64
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- U64 Address;
-} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64,
- Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t;
-
-typedef struct _MPI2_SGE_CHAIN_UNION
-{
- U16 Length;
- U8 NextChainOffset;
- U8 Flags;
- union
- {
- U32 Address32;
- U64 Address64;
- } u;
-} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION,
- Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t;
-
-
-/****************************************************************************
-* MPI Transaction Context Element structures
-****************************************************************************/
-
-typedef struct _MPI2_SGE_TRANSACTION32
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[1];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32,
- Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t;
-
-typedef struct _MPI2_SGE_TRANSACTION64
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[2];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64,
- Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t;
-
-typedef struct _MPI2_SGE_TRANSACTION96
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[3];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96,
- Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t;
-
-typedef struct _MPI2_SGE_TRANSACTION128
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- U32 TransactionContext[4];
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128,
- Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128;
-
-typedef struct _MPI2_SGE_TRANSACTION_UNION
-{
- U8 Reserved;
- U8 ContextSize;
- U8 DetailsLength;
- U8 Flags;
- union
- {
- U32 TransactionContext32[1];
- U32 TransactionContext64[2];
- U32 TransactionContext96[3];
- U32 TransactionContext128[4];
- } u;
- U32 TransactionDetails[1];
-} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION,
- Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t;
-
-
-/****************************************************************************
-* MPI SGE union for IO SGL's
-****************************************************************************/
-
-typedef struct _MPI2_MPI_SGE_IO_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_CHAIN_UNION Chain;
- } u;
-} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION,
- Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t;
-
-
-/****************************************************************************
-* MPI SGE union for SGL's with Simple and Transaction elements
-****************************************************************************/
-
-typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_TRANSACTION_UNION Transaction;
- } u;
-} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION,
- Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t;
-
-
-/****************************************************************************
-* All MPI SGE types union
-****************************************************************************/
-
-typedef struct _MPI2_MPI_SGE_UNION
-{
- union
- {
- MPI2_SGE_SIMPLE_UNION Simple;
- MPI2_SGE_CHAIN_UNION Chain;
- MPI2_SGE_TRANSACTION_UNION Transaction;
- } u;
-} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION,
- Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t;
-
-
-/****************************************************************************
-* MPI SGE field definition and masks
-****************************************************************************/
-
-/* Flags field bit definitions */
-
-#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80)
-#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40)
-#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30)
-#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08)
-#define MPI2_SGE_FLAGS_DIRECTION (0x04)
-#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02)
-#define MPI2_SGE_FLAGS_END_OF_LIST (0x01)
-
-#define MPI2_SGE_FLAGS_SHIFT (24)
-
-#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF)
-#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF)
-
-/* Element Type */
-
-#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00)
-#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10)
-#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30)
-#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30)
-
-/* Address location */
-
-#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00)
-
-/* Direction */
-
-#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00)
-#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04)
-
-#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST)
-#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC)
-
-/* Address Size */
-
-#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00)
-#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02)
-
-/* Context Size */
-
-#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00)
-#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02)
-#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04)
-#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06)
-
-#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000)
-#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16)
-
-/****************************************************************************
-* MPI SGE operation Macros
-****************************************************************************/
-
-/* SIMPLE FlagsLength manipulations... */
-#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT)
-#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT)
-#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK)
-#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK)
-
-#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l))
-
-#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength)
-#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength)
-#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l)
-
-/* CAUTION - The following are READ-MODIFY-WRITE! */
-#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f)
-#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l)
-
-#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT)
-
-
-/*****************************************************************************
-*
-* Fusion-MPT IEEE Scatter Gather Elements
-*
-*****************************************************************************/
-
-/****************************************************************************
-* IEEE Simple Element structures
-****************************************************************************/
-
-typedef struct _MPI2_IEEE_SGE_SIMPLE32
-{
- U32 Address;
- U32 FlagsLength;
-} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32,
- Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t;
-
-typedef struct _MPI2_IEEE_SGE_SIMPLE64
-{
- U64 Address;
- U32 Length;
- U16 Reserved1;
- U8 Reserved2;
- U8 Flags;
-} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64,
- Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t;
-
-typedef union _MPI2_IEEE_SGE_SIMPLE_UNION
-{
- MPI2_IEEE_SGE_SIMPLE32 Simple32;
- MPI2_IEEE_SGE_SIMPLE64 Simple64;
-} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION,
- Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t;
-
-
-/****************************************************************************
-* IEEE Chain Element structures
-****************************************************************************/
-
-typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32;
-
-typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64;
-
-typedef union _MPI2_IEEE_SGE_CHAIN_UNION
-{
- MPI2_IEEE_SGE_CHAIN32 Chain32;
- MPI2_IEEE_SGE_CHAIN64 Chain64;
-} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION,
- Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t;
-
-
-/****************************************************************************
-* All IEEE SGE types union
-****************************************************************************/
-
-typedef struct _MPI2_IEEE_SGE_UNION
-{
- union
- {
- MPI2_IEEE_SGE_SIMPLE_UNION Simple;
- MPI2_IEEE_SGE_CHAIN_UNION Chain;
- } u;
-} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION,
- Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t;
-
-
-/****************************************************************************
-* IEEE SGE field definitions and masks
-****************************************************************************/
-
-/* Flags field bit definitions */
-
-#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80)
-
-#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24)
-
-#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF)
-
-/* Element Type */
-
-#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00)
-#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80)
-
-/* Data Location Address Space */
-
-#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03)
-#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02)
-#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03)
- /* IEEE Simple Element only */
-#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03)
- /* IEEE Chain Element only */
-#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \
- (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */
-
-/****************************************************************************
-* IEEE SGE operation Macros
-****************************************************************************/
-
-/* SIMPLE FlagsLength manipulations... */
-#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT)
-#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT)
-#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK)
-
-#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l))
-
-#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength)
-#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength)
-#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l)
-
-/* CAUTION - The following are READ-MODIFY-WRITE! */
-#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f)
-#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l)
-
-
-
-
-/*****************************************************************************
-*
-* Fusion-MPT MPI/IEEE Scatter Gather Unions
-*
-*****************************************************************************/
-
-typedef union _MPI2_SIMPLE_SGE_UNION
-{
- MPI2_SGE_SIMPLE_UNION MpiSimple;
- MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
-} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION,
- Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t;
-
-
-typedef union _MPI2_SGE_IO_UNION
-{
- MPI2_SGE_SIMPLE_UNION MpiSimple;
- MPI2_SGE_CHAIN_UNION MpiChain;
- MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple;
- MPI2_IEEE_SGE_CHAIN_UNION IeeeChain;
-} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION,
- Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t;
-
-
-/****************************************************************************
-*
-* Values for SGLFlags field, used in many request messages with an SGL
-*
-****************************************************************************/
-
-/* values for MPI SGL Data Location Address Space subfield */
-#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C)
-#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00)
-#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04)
-#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08)
-#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C)
-/* values for SGL Type subfield */
-#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03)
-#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00)
-#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01)
-#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02)
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
deleted file mode 100644
index ee8d2d6..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ /dev/null
@@ -1,3068 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_cnfg.h
- * Title: MPI Configuration messages and pages
- * Creation Date: November 10, 2006
- *
- * mpi2_cnfg.h Version: 02.00.29
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags.
- * Added Manufacturing Page 11.
- * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
- * define.
- * 06-26-07 02.00.02 Adding generic structure for product-specific
- * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
- * Rework of BIOS Page 2 configuration page.
- * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
- * forms.
- * Added configuration pages IOC Page 8 and Driver
- * Persistent Mapping Page 0.
- * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated
- * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
- * RAID Physical Disk Pages 0 and 1, RAID Configuration
- * Page 0).
- * Added new value for AccessStatus field of SAS Device
- * Page 0 (_SATA_NEEDS_INITIALIZATION).
- * 10-31-07 02.00.04 Added missing SEPDevHandle field to
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for
- * NVDATA.
- * Modified IOC Page 7 to use masks and added field for
- * SASBroadcastPrimitiveMasks.
- * Added MPI2_CONFIG_PAGE_BIOS_4.
- * Added MPI2_CONFIG_PAGE_LOG_0.
- * 02-29-08 02.00.06 Modified various names to make them 32-character unique.
- * Added SAS Device IDs.
- * Updated Integrated RAID configuration pages including
- * Manufacturing Page 4, IOC Page 6, and RAID Configuration
- * Page 0.
- * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
- * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
- * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
- * Added missing MaxNumRoutedSasAddresses field to
- * MPI2_CONFIG_PAGE_EXPANDER_0.
- * Added SAS Port Page 0.
- * Modified structure layout for
- * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
- * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
- * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
- * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
- * to 0x000000FF.
- * Added two new values for the Physical Disk Coercion Size
- * bits in the Flags field of Manufacturing Page 4.
- * Added product-specific Manufacturing pages 16 to 31.
- * Modified Flags bits for controlling write cache on SATA
- * drives in IO Unit Page 1.
- * Added new bit to AdditionalControlFlags of SAS IO Unit
- * Page 1 to control Invalid Topology Correction.
- * Added additional defines for RAID Volume Page 0
- * VolumeStatusFlags field.
- * Modified meaning of RAID Volume Page 0 VolumeSettings
- * define for auto-configure of hot-swap drives.
- * Added SupportedPhysDisks field to RAID Volume Page 1 and
- * added related defines.
- * Added PhysDiskAttributes field (and related defines) to
- * RAID Physical Disk Page 0.
- * Added MPI2_SAS_PHYINFO_PHY_VACANT define.
- * Added three new DiscoveryStatus bits for SAS IO Unit
- * Page 0 and SAS Expander Page 0.
- * Removed multiplexing information from SAS IO Unit pages.
- * Added BootDeviceWaitTime field to SAS IO Unit Page 4.
- * Removed Zone Address Resolved bit from PhyInfo and from
- * Expander Page 0 Flags field.
- * Added two new AccessStatus values to SAS Device Page 0
- * for indicating routing problems. Added 3 reserved words
- * to this page.
- * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3.
- * Inserted missing reserved field into structure for IOC
- * Page 6.
- * Added more pending task bits to RAID Volume Page 0
- * VolumeStatusFlags defines.
- * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
- * Added a new DiscoveryStatus bit for SAS IO Unit Page 0
- * and SAS Expander Page 0 to flag a downstream initiator
- * when in simplified routing mode.
- * Removed SATA Init Failure defines for DiscoveryStatus
- * fields of SAS IO Unit Page 0 and SAS Expander Page 0.
- * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
- * Added PortGroups, DmaGroup, and ControlGroup fields to
- * SAS Device Page 0.
- * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
- * Unit Page 6.
- * Added expander reduced functionality data to SAS
- * Expander Page 0.
- * Added SAS PHY Page 2 and SAS PHY Page 3.
- * 07-30-09 02.00.12 Added IO Unit Page 7.
- * Added new device ids.
- * Added SAS IO Unit Page 5.
- * Added partial and slumber power management capable flags
- * to SAS Device Page 0 Flags field.
- * Added PhyInfo defines for power condition.
- * Added Ethernet configuration pages.
- * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY.
- * Added SAS PHY Page 4 structure and defines.
- * 02-10-10 02.00.14 Modified the comments for the configuration page
- * structures that contain an array of data. The host
- * should use the "count" field in the page data (e.g. the
- * NumPhys field) to determine the number of valid elements
- * in the array.
- * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines.
- * Added PowerManagementCapabilities to IO Unit Page 7.
- * Added PortWidthModGroup field to
- * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines.
- * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines.
- * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT
- * define.
- * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define.
- * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define.
- * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing)
- * defines.
- * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to
- * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for
- * the Pinout field.
- * Added BoardTemperature and BoardTemperatureUnits fields
- * to MPI2_CONFIG_PAGE_IO_UNIT_7.
- * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define
- * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure.
- * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST.
- * Added IO Unit Page 8, IO Unit Page 9,
- * and IO Unit Page 10.
- * Added SASNotifyPrimitiveMasks field to
- * MPI2_CONFIG_PAGE_IOC_7.
- * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec).
- * 05-25-11 02.00.20 Cleaned up a few comments.
- * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities
- * for PCIe link as obsolete.
- * Added SpinupFlags field containing a Disable Spin-up
- * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of
- * SAS IO Unit Page 4.
- * 11-18-11 02.00.22 Added define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT.
- * Added UEFIVersion field to BIOS Page 1 and defined new
- * BiosOptions bits.
- * 11-27-12 02.00.23 Added MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER.
- * Added MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID.
- * 12-20-12 02.00.24 Marked MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION as
- * obsolete for MPI v2.5 and later.
- * Added some defines for 12G SAS speeds.
- * 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK.
- * Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to
- * match the specification.
- * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
- * MPI2_CONFIG_PAGE_MAN_7.
- * Added EnclosureLevel and ConnectorName fields to
- * MPI2_CONFIG_PAGE_SAS_DEV_0.
- * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
- * MPI2_CONFIG_PAGE_SAS_DEV_0.
- * Added EnclosureLevel field to
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
- * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
- * 01-08-14 02.00.28 Added more defines for the BiosOptions field of
- * MPI2_CONFIG_PAGE_BIOS_1.
- * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
- * more defines for the BiosOptions field.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_CNFG_H
-#define MPI2_CNFG_H
-
-/*****************************************************************************
-* Configuration Page Header and defines
-*****************************************************************************/
-
-/* Config Page Header */
-typedef struct _MPI2_CONFIG_PAGE_HEADER
-{
- U8 PageVersion; /* 0x00 */
- U8 PageLength; /* 0x01 */
- U8 PageNumber; /* 0x02 */
- U8 PageType; /* 0x03 */
-} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER,
- Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t;
-
-typedef union _MPI2_CONFIG_PAGE_HEADER_UNION
-{
- MPI2_CONFIG_PAGE_HEADER Struct;
- U8 Bytes[4];
- U16 Word16[2];
- U32 Word32;
-} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION,
- Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion;
-
-/* Extended Config Page Header */
-typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER
-{
- U8 PageVersion; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 PageNumber; /* 0x02 */
- U8 PageType; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 Reserved2; /* 0x07 */
-} MPI2_CONFIG_EXTENDED_PAGE_HEADER,
- MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER,
- Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t;
-
-typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION
-{
- MPI2_CONFIG_PAGE_HEADER Struct;
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext;
- U8 Bytes[8];
- U16 Word16[4];
- U32 Word32[2];
-} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION,
- Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion;
-
-
-/* PageType field values */
-#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00)
-#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10)
-#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20)
-#define MPI2_CONFIG_PAGEATTR_MASK (0xF0)
-
-#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00)
-#define MPI2_CONFIG_PAGETYPE_IOC (0x01)
-#define MPI2_CONFIG_PAGETYPE_BIOS (0x02)
-#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08)
-#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09)
-#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A)
-#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F)
-#define MPI2_CONFIG_PAGETYPE_MASK (0x0F)
-
-#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF)
-
-
-/* ExtPageType field values */
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13)
-#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14)
-#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15)
-#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16)
-#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17)
-#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18)
-#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19)
-#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A)
-
-
-/*****************************************************************************
-* PageAddress defines
-*****************************************************************************/
-
-/* RAID Volume PageAddress format */
-#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000)
-
-#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* RAID Physical Disk PageAddress format */
-#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000)
-#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000)
-#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000)
-
-#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF)
-#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF)
-
-
-/* SAS Expander PageAddress format */
-#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000)
-#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000)
-
-#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF)
-#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000)
-#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16)
-
-
-/* SAS Device PageAddress format */
-#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000)
-
-#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* SAS PHY PageAddress format */
-#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000)
-#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000)
-
-#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF)
-#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF)
-
-
-/* SAS Port PageAddress format */
-#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000)
-#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000)
-
-#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF)
-
-
-/* SAS Enclosure PageAddress format */
-#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000)
-#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000)
-
-#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF)
-
-
-/* RAID Configuration PageAddress format */
-#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000)
-#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000)
-#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000)
-
-#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF)
-
-
-/* Driver Persistent Mapping PageAddress format */
-#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000)
-
-#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000)
-#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16)
-#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF)
-
-
-/* Ethernet PageAddress format */
-#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000)
-#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000)
-
-#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF)
-
-
-
-/****************************************************************************
-* Configuration messages
-****************************************************************************/
-
-/* Configuration Request Message */
-typedef struct _MPI2_CONFIG_REQUEST
-{
- U8 Action; /* 0x00 */
- U8 SGLFlags; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 ProxyVF_ID; /* 0x0D */
- U16 Reserved4; /* 0x0E */
- U32 Reserved3; /* 0x10 */
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */
- U32 PageAddress; /* 0x18 */
- MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */
-} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST,
- Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t;
-
-/* values for the Action field */
-#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00)
-#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01)
-#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02)
-#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03)
-#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04)
-#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05)
-#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06)
-#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* Config Reply Message */
-typedef struct _MPI2_CONFIG_REPLY
-{
- U8 Action; /* 0x00 */
- U8 SGLFlags; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ExtPageLength; /* 0x04 */
- U8 ExtPageType; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 Reserved2; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */
-} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY,
- Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t;
-
-
-
-/*****************************************************************************
-*
-* C o n f i g u r a t i o n P a g e s
-*
-*****************************************************************************/
-
-/****************************************************************************
-* Manufacturing Config pages
-****************************************************************************/
-
-#define MPI2_MFGPAGE_VENDORID_LSI (0x1000)
-
-/* SAS */
-#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070)
-#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072)
-#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074)
-#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076)
-#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077)
-#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064)
-#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065)
-
-#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E)
-
-#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080)
-#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081)
-#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082)
-#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083)
-#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084)
-#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085)
-#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086)
-#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087)
-#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E)
-
-
-
-
-/* Manufacturing Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 ChipName[16]; /* 0x04 */
- U8 ChipRevision[8]; /* 0x14 */
- U8 BoardName[16]; /* 0x1C */
- U8 BoardAssembly[16]; /* 0x2C */
- U8 BoardTracerNumber[16]; /* 0x3C */
-} MPI2_CONFIG_PAGE_MAN_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0,
- Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t;
-
-#define MPI2_MANUFACTURING0_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 VPD[256]; /* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1,
- Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t;
-
-#define MPI2_MANUFACTURING1_PAGEVERSION (0x00)
-
-
-typedef struct _MPI2_CHIP_REVISION_ID
-{
- U16 DeviceID; /* 0x00 */
- U8 PCIRevisionID; /* 0x02 */
- U8 Reserved; /* 0x03 */
-} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID,
- Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t;
-
-
-/* Manufacturing Page 2 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS
-#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_2
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */
- U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_2,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2,
- Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t;
-
-#define MPI2_MANUFACTURING2_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 3 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check Header.PageLength at runtime.
- */
-#ifndef MPI2_MAN_PAGE_3_INFO_WORDS
-#define MPI2_MAN_PAGE_3_INFO_WORDS (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */
- U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_3,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3,
- Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t;
-
-#define MPI2_MANUFACTURING3_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 4 */
-
-typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS
-{
- U8 PowerSaveFlags; /* 0x00 */
- U8 InternalOperationsSleepTime; /* 0x01 */
- U8 InternalOperationsRunTime; /* 0x02 */
- U8 HostIdleTime; /* 0x03 */
-} MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
- MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS,
- Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t;
-
-/* defines for the PowerSaveFlags field */
-#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03)
-#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00)
-#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01)
-#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02)
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_4
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Flags; /* 0x08 */
- U8 InquirySize; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- U8 InquiryData[56]; /* 0x10 */
- U32 RAID0VolumeSettings; /* 0x48 */
- U32 RAID1EVolumeSettings; /* 0x4C */
- U32 RAID1VolumeSettings; /* 0x50 */
- U32 RAID10VolumeSettings; /* 0x54 */
- U32 Reserved4; /* 0x58 */
- U32 Reserved5; /* 0x5C */
- MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */
- U8 MaxOCEDisks; /* 0x64 */
- U8 ResyncRate; /* 0x65 */
- U16 DataScrubDuration; /* 0x66 */
- U8 MaxHotSpares; /* 0x68 */
- U8 MaxPhysDisksPerVol; /* 0x69 */
- U8 MaxPhysDisks; /* 0x6A */
- U8 MaxVolumes; /* 0x6B */
-} MPI2_CONFIG_PAGE_MAN_4,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4,
- Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t;
-
-#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A)
-
-/* Manufacturing Page 4 Flags field */
-#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000)
-#define MPI2_MANPAGE4_METADATA_512MB (0x00000000)
-
-#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000)
-#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000)
-#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000)
-
-#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00)
-#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000)
-#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400)
-#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800)
-#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00)
-
-#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300)
-#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000)
-#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100)
-#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200)
-
-#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080)
-#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040)
-#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020)
-#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010)
-#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008)
-#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004)
-#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002)
-#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001)
-
-
-/* Manufacturing Page 5 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES
-#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_MANUFACTURING5_ENTRY
-{
- U64 WWID; /* 0x00 */
- U64 DeviceName; /* 0x08 */
-} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY,
- Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_5
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */
-} MPI2_CONFIG_PAGE_MAN_5,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5,
- Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t;
-
-#define MPI2_MANUFACTURING5_PAGEVERSION (0x03)
-
-
-/* Manufacturing Page 6 */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_6
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo;/* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_6,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6,
- Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t;
-
-#define MPI2_MANUFACTURING6_PAGEVERSION (0x00)
-
-
-/* Manufacturing Page 7 */
-
-typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO
-{
- U32 Pinout; /* 0x00 */
- U8 Connector[16]; /* 0x04 */
- U8 Location; /* 0x14 */
- U8 ReceptacleID; /* 0x15 */
- U16 Slot; /* 0x16 */
- U32 Reserved2; /* 0x18 */
-} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO,
- Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t;
-
-/* defines for the Pinout field */
-#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00)
-#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8)
-
-#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF)
-#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00)
-#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01)
-#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02)
-#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03)
-#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04)
-#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05)
-#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06)
-#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07)
-#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08)
-#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B)
-#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C)
-#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D)
-
-/* defines for the Location field */
-#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01)
-#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02)
-#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04)
-#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08)
-#define MPI2_MANPAGE7_LOCATION_AUTO (0x10)
-#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20)
-#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX
-#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_7
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Flags; /* 0x0C */
- U8 EnclosureName[16]; /* 0x10 */
- U8 NumPhys; /* 0x20 */
- U8 Reserved3; /* 0x21 */
- U16 Reserved4; /* 0x22 */
- MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */
-} MPI2_CONFIG_PAGE_MAN_7,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7,
- Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t;
-
-#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
-
-/* defines for the Flags field */
-#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008)
-#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
-#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
-
-
-/*
- * Generic structure to use for product-specific manufacturing pages
- * (currently Manufacturing Page 8 through Manufacturing Page 31).
- */
-
-typedef struct _MPI2_CONFIG_PAGE_MAN_PS
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo;/* 0x04 */
-} MPI2_CONFIG_PAGE_MAN_PS,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS,
- Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t;
-
-#define MPI2_MANUFACTURING8_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING9_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING10_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING11_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING12_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING13_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING14_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING15_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING16_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING17_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING18_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING19_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING20_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING21_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING22_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING23_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING24_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING25_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING26_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING27_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING28_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING29_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING30_PAGEVERSION (0x00)
-#define MPI2_MANUFACTURING31_PAGEVERSION (0x00)
-
-
-/****************************************************************************
-* IO Unit Config Pages
-****************************************************************************/
-
-/* IO Unit Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U64 UniqueValue; /* 0x04 */
- MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */
- MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */
-} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0,
- Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t;
-
-#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02)
-
-
-/* IO Unit Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Flags; /* 0x04 */
-} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1,
- Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t;
-
-#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04)
-
-/* IO Unit Page 1 Flags defines */
-#define MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK (0x00004000)
-#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800)
-#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600)
-#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9)
-#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000)
-#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200)
-#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400)
-#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100)
-#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040)
-#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020)
-#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004)
-
-
-/* IO Unit Page 3 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for GPIOCount at runtime.
- */
-#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX
-#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 GPIOCount; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */
-} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3,
- Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t;
-
-#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01)
-
-/* defines for IO Unit Page 3 GPIOVal field */
-#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC)
-#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2)
-#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000)
-#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001)
-
-
-/* IO Unit Page 5 */
-
-/*
- * Upper layer code (drivers, utilities, etc.) should leave this define set to
- * one and check the value returned for NumDmaEngines at runtime.
- */
-#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
-#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */
- U64 RaidAcceleratorBufferSize; /* 0x0C */
- U64 RaidAcceleratorControlBaseAddress; /* 0x14 */
- U8 RAControlSize; /* 0x1C */
- U8 NumDmaEngines; /* 0x1D */
- U8 RAMinControlSize; /* 0x1E */
- U8 RAMaxControlSize; /* 0x1F */
- U32 Reserved1; /* 0x20 */
- U32 Reserved2; /* 0x24 */
- U32 Reserved3; /* 0x28 */
- U32 DmaEngineCapabilities
- [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */
-} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5,
- Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t;
-
-#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00)
-
-/* defines for IO Unit Page 5 DmaEngineCapabilities field */
-#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFFFF0000)
-#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16)
-
-#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008)
-#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004)
-#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002)
-#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001)
-
-
-/* IO Unit Page 6 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 Flags; /* 0x04 */
- U8 RAHostControlSize; /* 0x06 */
- U8 Reserved0; /* 0x07 */
- U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
- U32 Reserved3; /* 0x18 */
-} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6,
- Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t;
-
-#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00)
-
-/* defines for IO Unit Page 6 Flags field */
-#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001)
-
-
-/* IO Unit Page 7 */
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 Reserved1; /* 0x04 */
- U8 PCIeWidth; /* 0x06 */
- U8 PCIeSpeed; /* 0x07 */
- U32 ProcessorState; /* 0x08 */
- U32 PowerManagementCapabilities; /* 0x0C */
- U16 IOCTemperature; /* 0x10 */
- U8 IOCTemperatureUnits; /* 0x12 */
- U8 IOCSpeed; /* 0x13 */
- U16 BoardTemperature; /* 0x14 */
- U8 BoardTemperatureUnits; /* 0x16 */
- U8 Reserved3; /* 0x17 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
- U32 Reserved6; /* 0x20 */
- U32 Reserved7; /* 0x24 */
-} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7,
- Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t;
-
-#define MPI2_IOUNITPAGE7_PAGEVERSION (0x04)
-
-/* defines for IO Unit Page 7 PCIeWidth field */
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04)
-#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08)
-
-/* defines for IO Unit Page 7 PCIeSpeed field */
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00)
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01)
-#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02)
-
-/* defines for IO Unit Page 7 ProcessorState field */
-#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F)
-#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0)
-
-#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01)
-#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02)
-
-/* defines for IO Unit Page 7 PowerManagementCapabilities field */
-#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400)
-#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200)
-#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100)
-#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */
-#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */
-
-/* defines for IO Unit Page 7 IOCTemperatureUnits field */
-#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01)
-#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02)
-
-/* defines for IO Unit Page 7 IOCSpeed field */
-#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04)
-#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08)
-
-/* defines for IO Unit Page 7 BoardTemperatureUnits field */
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00)
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01)
-#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02)
-
-/* IO Unit Page 8 */
-
-#define MPI2_IOUNIT8_NUM_THRESHOLDS (4)
-
-typedef struct _MPI2_IOUNIT8_SENSOR {
- U16 Flags; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U16
- Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
-} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR,
-Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t;
-
-/* defines for IO Unit Page 8 Sensor Flags field */
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002)
-#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumSensors at runtime.
- */
-#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES
-#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U8 NumSensors; /* 0x0C */
- U8 PollingInterval; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_IOUNIT8_SENSOR
- Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8,
-Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t;
-
-#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00)
-
-
-/* IO Unit Page 9 */
-
-typedef struct _MPI2_IOUNIT9_SENSOR {
- U16 CurrentTemperature; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U8 Flags; /* 0x04 */
- U8 Reserved2; /* 0x05 */
- U16 Reserved3; /* 0x06 */
- U32 Reserved4; /* 0x08 */
- U32 Reserved5; /* 0x0C */
-} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR,
-Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t;
-
-/* defines for IO Unit Page 9 Sensor Flags field */
-#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumSensors at runtime.
- */
-#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES
-#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U8 NumSensors; /* 0x0C */
- U8 Reserved4; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_IOUNIT9_SENSOR
- Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9,
-Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t;
-
-#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00)
-
-
-/* IO Unit Page 10 */
-
-typedef struct _MPI2_IOUNIT10_FUNCTION {
- U8 CreditPercent; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION,
-Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumFunctions at runtime.
- */
-#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES
-#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumFunctions; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- MPI2_IOUNIT10_FUNCTION
- Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */
-} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10,
-Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t;
-
-#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01)
-
-
-
-/****************************************************************************
-* IOC Config Pages
-****************************************************************************/
-
-/* IOC Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U16 VendorID; /* 0x0C */
- U16 DeviceID; /* 0x0E */
- U8 RevisionID; /* 0x10 */
- U8 Reserved3; /* 0x11 */
- U16 Reserved4; /* 0x12 */
- U32 ClassCode; /* 0x14 */
- U16 SubsystemVendorID; /* 0x18 */
- U16 SubsystemID; /* 0x1A */
-} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0,
- Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t;
-
-#define MPI2_IOCPAGE0_PAGEVERSION (0x02)
-
-
-/* IOC Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Flags; /* 0x04 */
- U32 CoalescingTimeout; /* 0x08 */
- U8 CoalescingDepth; /* 0x0C */
- U8 PCISlotNum; /* 0x0D */
- U8 PCIBusNum; /* 0x0E */
- U8 PCIDomainSegment; /* 0x0F */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1,
- Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t;
-
-#define MPI2_IOCPAGE1_PAGEVERSION (0x05)
-
-/* defines for IOC Page 1 Flags field */
-#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001)
-
-#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF)
-#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF)
-#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF)
-
-/* IOC Page 6 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_6
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 CapabilitiesFlags; /* 0x04 */
- U8 MaxDrivesRAID0; /* 0x08 */
- U8 MaxDrivesRAID1; /* 0x09 */
- U8 MaxDrivesRAID1E; /* 0x0A */
- U8 MaxDrivesRAID10; /* 0x0B */
- U8 MinDrivesRAID0; /* 0x0C */
- U8 MinDrivesRAID1; /* 0x0D */
- U8 MinDrivesRAID1E; /* 0x0E */
- U8 MinDrivesRAID10; /* 0x0F */
- U32 Reserved1; /* 0x10 */
- U8 MaxGlobalHotSpares; /* 0x14 */
- U8 MaxPhysDisks; /* 0x15 */
- U8 MaxVolumes; /* 0x16 */
- U8 MaxConfigs; /* 0x17 */
- U8 MaxOCEDisks; /* 0x18 */
- U8 Reserved2; /* 0x19 */
- U16 Reserved3; /* 0x1A */
- U32 SupportedStripeSizeMapRAID0; /* 0x1C */
- U32 SupportedStripeSizeMapRAID1E; /* 0x20 */
- U32 SupportedStripeSizeMapRAID10; /* 0x24 */
- U32 Reserved4; /* 0x28 */
- U32 Reserved5; /* 0x2C */
- U16 DefaultMetadataSize; /* 0x30 */
- U16 Reserved6; /* 0x32 */
- U16 MaxBadBlockTableEntries; /* 0x34 */
- U16 Reserved7; /* 0x36 */
- U32 IRNvsramVersion; /* 0x38 */
-} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6,
- Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t;
-
-#define MPI2_IOCPAGE6_PAGEVERSION (0x05)
-
-/* defines for IOC Page 6 CapabilitiesFlags */
-#define MPI2_IOCPAGE6_CAP_FLAGS_4K_SECTORS_SUPPORT (0x00000020)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004)
-#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002)
-#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001)
-
-
-/* IOC Page 7 */
-
-#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4)
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_7
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */
- U16 SASBroadcastPrimitiveMasks; /* 0x18 */
- U16 SASNotifyPrimitiveMasks; /* 0x1A */
- U32 Reserved3; /* 0x1C */
-} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7,
- Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t;
-
-#define MPI2_IOCPAGE7_PAGEVERSION (0x02)
-
-
-/* IOC Page 8 */
-
-typedef struct _MPI2_CONFIG_PAGE_IOC_8
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumDevsPerEnclosure; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U16 MaxPersistentEntries; /* 0x08 */
- U16 MaxNumPhysicalMappedIDs; /* 0x0A */
- U16 Flags; /* 0x0C */
- U16 Reserved3; /* 0x0E */
- U16 IRVolumeMappingFlags; /* 0x10 */
- U16 Reserved4; /* 0x12 */
- U32 Reserved5; /* 0x14 */
-} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8,
- Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t;
-
-#define MPI2_IOCPAGE8_PAGEVERSION (0x00)
-
-/* defines for IOC Page 8 Flags field */
-#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020)
-#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010)
-
-#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E)
-#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000)
-#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002)
-
-#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001)
-#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000)
-
-/* defines for IOC Page 8 IRVolumeMappingFlags */
-#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003)
-#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000)
-#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001)
-
-
-/****************************************************************************
-* BIOS Config Pages
-****************************************************************************/
-
-/* BIOS Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 BiosOptions; /* 0x04 */
- U32 IOCSettings; /* 0x08 */
- U8 SSUTimeout; /* 0x0C */
- U8 Reserved1; /* 0x0D */
- U16 Reserved2; /* 0x0E */
- U32 DeviceSettings; /* 0x10 */
- U16 NumberOfDevices; /* 0x14 */
- U16 UEFIVersion; /* 0x16 */
- U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */
- U16 IOTimeoutSequential; /* 0x1A */
- U16 IOTimeoutOther; /* 0x1C */
- U16 IOTimeoutBlockDevicesRM; /* 0x1E */
-} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
- Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
-
-#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
-
-/* values for BIOS Page 1 BiosOptions field */
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800)
-#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000)
-
-#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300)
-#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100)
-#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200)
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
-#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
-
-#define MPI2_BIOSPAGE1_OPTIONS_MASK_UEFI_HII_REGISTRATION (0x00000006)
-#define MPI2_BIOSPAGE1_OPTIONS_ENABLE_UEFI_HII (0x00000000)
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_UEFI_HII (0x00000002)
-#define MPI2_BIOSPAGE1_OPTIONS_VERSION_CHECK_UEFI_HII (0x00000004)
-
-#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001)
-
-/* values for BIOS Page 1 IOCSettings field */
-#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000)
-#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000)
-
-#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0)
-#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040)
-#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080)
-
-#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030)
-#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000)
-#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010)
-#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020)
-#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030)
-
-#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008)
-
-/* values for BIOS Page 1 DeviceSettings field */
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002)
-#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001)
-
-/* defines for BIOS Page 1 UEFIVersion field */
-#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_MASK (0xFF00)
-#define MPI2_BIOSPAGE1_UEFI_VER_MAJOR_SHIFT (8)
-#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_MASK (0x00FF)
-#define MPI2_BIOSPAGE1_UEFI_VER_MINOR_SHIFT (0)
-
-
-
-/* BIOS Page 2 */
-
-typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER
-{
- U32 Reserved1; /* 0x00 */
- U32 Reserved2; /* 0x04 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
- U32 Reserved5; /* 0x10 */
- U32 Reserved6; /* 0x14 */
-} MPI2_BOOT_DEVICE_ADAPTER_ORDER,
- MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER,
- Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t;
-
-typedef struct _MPI2_BOOT_DEVICE_SAS_WWID
-{
- U64 SASAddress; /* 0x00 */
- U8 LUN[8]; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID,
- Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t;
-
-typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT
-{
- U64 EnclosureLogicalID; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U16 SlotNumber; /* 0x10 */
- U16 Reserved3; /* 0x12 */
- U32 Reserved4; /* 0x14 */
-} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
- MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT,
- Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t;
-
-typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME
-{
- U64 DeviceName; /* 0x00 */
- U8 LUN[8]; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
-} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME,
- Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t;
-
-typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE
-{
- MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder;
- MPI2_BOOT_DEVICE_SAS_WWID SasWwid;
- MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot;
- MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName;
-} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE,
- Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t;
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_2
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- U32 Reserved4; /* 0x10 */
- U32 Reserved5; /* 0x14 */
- U32 Reserved6; /* 0x18 */
- U8 ReqBootDeviceForm; /* 0x1C */
- U8 Reserved7; /* 0x1D */
- U16 Reserved8; /* 0x1E */
- MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */
- U8 ReqAltBootDeviceForm; /* 0x38 */
- U8 Reserved9; /* 0x39 */
- U16 Reserved10; /* 0x3A */
- MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */
- U8 CurrentBootDeviceForm; /* 0x58 */
- U8 Reserved11; /* 0x59 */
- U16 Reserved12; /* 0x5A */
- MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */
-} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2,
- Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t;
-
-#define MPI2_BIOSPAGE2_PAGEVERSION (0x04)
-
-/* values for BIOS Page 2 BootDeviceForm fields */
-#define MPI2_BIOSPAGE2_FORM_MASK (0x0F)
-#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00)
-#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05)
-#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06)
-#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07)
-
-
-/* BIOS Page 3 */
-
-typedef struct _MPI2_ADAPTER_INFO
-{
- U8 PciBusNumber; /* 0x00 */
- U8 PciDeviceAndFunctionNumber; /* 0x01 */
- U16 AdapterFlags; /* 0x02 */
-} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO,
- Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t;
-
-#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001)
-#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002)
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_3
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U32 GlobalFlags; /* 0x04 */
- U32 BiosVersion; /* 0x08 */
- MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */
- U32 Reserved1; /* 0x1C */
-} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3,
- Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t;
-
-#define MPI2_BIOSPAGE3_PAGEVERSION (0x00)
-
-/* values for BIOS Page 3 GlobalFlags */
-#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002)
-#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004)
-#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010)
-
-#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0)
-#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000)
-#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020)
-#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040)
-
-
-/* BIOS Page 4 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES
-#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1)
-#endif
-
-typedef struct _MPI2_BIOS4_ENTRY
-{
- U64 ReassignmentWWID; /* 0x00 */
- U64 ReassignmentDeviceName; /* 0x08 */
-} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY,
- Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_BIOS_4
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */
-} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4,
- Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t;
-
-#define MPI2_BIOSPAGE4_PAGEVERSION (0x01)
-
-
-/****************************************************************************
-* RAID Volume Config Pages
-****************************************************************************/
-
-/* RAID Volume Page 0 */
-
-typedef struct _MPI2_RAIDVOL0_PHYS_DISK
-{
- U8 RAIDSetNum; /* 0x00 */
- U8 PhysDiskMap; /* 0x01 */
- U8 PhysDiskNum; /* 0x02 */
- U8 Reserved; /* 0x03 */
-} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK,
- Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t;
-
-/* defines for the PhysDiskMap field */
-#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01)
-#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02)
-
-typedef struct _MPI2_RAIDVOL0_SETTINGS
-{
- U16 Settings; /* 0x00 */
- U8 HotSparePool; /* 0x01 */
- U8 Reserved; /* 0x02 */
-} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS,
- Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t;
-
-/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */
-#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01)
-#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02)
-#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04)
-#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08)
-#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10)
-#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20)
-#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40)
-#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80)
-
-/* RAID Volume Page 0 VolumeSettings defines */
-#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008)
-#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004)
-
-#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003)
-#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000)
-#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001)
-#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhysDisks at runtime.
- */
-#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX
-#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U8 VolumeState; /* 0x06 */
- U8 VolumeType; /* 0x07 */
- U32 VolumeStatusFlags; /* 0x08 */
- MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */
- U64 MaxLBA; /* 0x10 */
- U32 StripeSize; /* 0x18 */
- U16 BlockSize; /* 0x1C */
- U16 Reserved1; /* 0x1E */
- U8 SupportedPhysDisks; /* 0x20 */
- U8 ResyncRate; /* 0x21 */
- U16 DataScrubDuration; /* 0x22 */
- U8 NumPhysDisks; /* 0x24 */
- U8 Reserved2; /* 0x25 */
- U8 Reserved3; /* 0x26 */
- U8 InactiveStatus; /* 0x27 */
- MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */
-} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0,
- Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t;
-
-#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A)
-
-/* values for RAID VolumeState */
-#define MPI2_RAID_VOL_STATE_MISSING (0x00)
-#define MPI2_RAID_VOL_STATE_FAILED (0x01)
-#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02)
-#define MPI2_RAID_VOL_STATE_ONLINE (0x03)
-#define MPI2_RAID_VOL_STATE_DEGRADED (0x04)
-#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05)
-
-/* values for RAID VolumeType */
-#define MPI2_RAID_VOL_TYPE_RAID0 (0x00)
-#define MPI2_RAID_VOL_TYPE_RAID1E (0x01)
-#define MPI2_RAID_VOL_TYPE_RAID1 (0x02)
-#define MPI2_RAID_VOL_TYPE_RAID10 (0x05)
-#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF)
-
-/* values for RAID Volume Page 0 VolumeStatusFlags field */
-#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080)
-#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020)
-#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000)
-#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010)
-#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008)
-#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004)
-#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002)
-#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001)
-
-/* values for RAID Volume Page 0 SupportedPhysDisks field */
-#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08)
-#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04)
-#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02)
-#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01)
-
-/* values for RAID Volume Page 0 InactiveStatus field */
-#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00)
-#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01)
-#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02)
-#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03)
-#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04)
-#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05)
-#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06)
-
-
-/* RAID Volume Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U16 Reserved0; /* 0x06 */
- U8 GUID[24]; /* 0x08 */
- U8 Name[16]; /* 0x20 */
- U64 WWID; /* 0x30 */
- U32 Reserved1; /* 0x38 */
- U32 Reserved2; /* 0x3C */
-} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1,
- Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t;
-
-#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03)
-
-
-/****************************************************************************
-* RAID Physical Disk Config Pages
-****************************************************************************/
-
-/* RAID Physical Disk Page 0 */
-
-typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS
-{
- U16 Reserved1; /* 0x00 */
- U8 HotSparePool; /* 0x02 */
- U8 Reserved2; /* 0x03 */
-} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS,
- Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t;
-
-/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */
-
-typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA
-{
- U8 VendorID[8]; /* 0x00 */
- U8 ProductID[16]; /* 0x08 */
- U8 ProductRevLevel[4]; /* 0x18 */
- U8 SerialNum[32]; /* 0x1C */
-} MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
- MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA,
- Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t;
-
-typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U16 DevHandle; /* 0x04 */
- U8 Reserved1; /* 0x06 */
- U8 PhysDiskNum; /* 0x07 */
- MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */
- U32 Reserved3; /* 0x4C */
- U8 PhysDiskState; /* 0x50 */
- U8 OfflineReason; /* 0x51 */
- U8 IncompatibleReason; /* 0x52 */
- U8 PhysDiskAttributes; /* 0x53 */
- U32 PhysDiskStatusFlags; /* 0x54 */
- U64 DeviceMaxLBA; /* 0x58 */
- U64 HostMaxLBA; /* 0x60 */
- U64 CoercedMaxLBA; /* 0x68 */
- U16 BlockSize; /* 0x70 */
- U16 Reserved5; /* 0x72 */
- U32 Reserved6; /* 0x74 */
-} MPI2_CONFIG_PAGE_RD_PDISK_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0,
- Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t;
-
-#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05)
-
-/* PhysDiskState defines */
-#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00)
-#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01)
-#define MPI2_RAID_PD_STATE_OFFLINE (0x02)
-#define MPI2_RAID_PD_STATE_ONLINE (0x03)
-#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04)
-#define MPI2_RAID_PD_STATE_DEGRADED (0x05)
-#define MPI2_RAID_PD_STATE_REBUILDING (0x06)
-#define MPI2_RAID_PD_STATE_OPTIMAL (0x07)
-
-/* OfflineReason defines */
-#define MPI2_PHYSDISK0_ONLINE (0x00)
-#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01)
-#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03)
-#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04)
-#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05)
-#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06)
-#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF)
-
-/* IncompatibleReason defines */
-#define MPI2_PHYSDISK0_COMPATIBLE (0x00)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06)
-#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF)
-
-/* PhysDiskAttributes defines */
-#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C)
-#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08)
-#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04)
-
-#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03)
-#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02)
-#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01)
-
-/* PhysDiskStatusFlags defines */
-#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020)
-#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000)
-#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008)
-#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004)
-#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002)
-#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001)
-
-
-/* RAID Physical Disk Page 1 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhysDiskPaths at runtime.
- */
-#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX
-#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1)
-#endif
-
-typedef struct _MPI2_RAIDPHYSDISK1_PATH
-{
- U16 DevHandle; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U64 WWID; /* 0x04 */
- U64 OwnerWWID; /* 0x0C */
- U8 OwnerIdentifier; /* 0x14 */
- U8 Reserved2; /* 0x15 */
- U16 Flags; /* 0x16 */
-} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH,
- Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t;
-
-/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */
-#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004)
-#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002)
-#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001)
-
-typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1
-{
- MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhysDiskPaths; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 Reserved1; /* 0x06 */
- U32 Reserved2; /* 0x08 */
- MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */
-} MPI2_CONFIG_PAGE_RD_PDISK_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1,
- Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t;
-
-#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02)
-
-
-/****************************************************************************
-* values for fields used by several types of SAS Config Pages
-****************************************************************************/
-
-/* values for NegotiatedLinkRates fields */
-#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0)
-#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4)
-#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F)
-/* link rates used for Negotiated Physical and Logical Link Rate */
-#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00)
-#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01)
-#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02)
-#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03)
-#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04)
-#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05)
-#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06)
-#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08)
-#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09)
-#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A)
-
-
-/* values for AttachedPhyInfo fields */
-#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040)
-#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020)
-#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010)
-
-#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F)
-#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000)
-#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001)
-#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002)
-#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003)
-#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004)
-#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005)
-#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006)
-#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007)
-#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008)
-
-
-/* values for PhyInfo fields */
-#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000)
-
-#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000)
-#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27)
-#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000)
-#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000)
-#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000)
-
-#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000)
-#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000)
-#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000)
-#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000)
-#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000)
-#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000)
-
-#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000)
-#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000)
-#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000)
-#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000)
-#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000)
-#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000)
-#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000)
-#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000)
-#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000)
-#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000)
-
-#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000)
-#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000)
-#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000)
-#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000)
-
-#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00)
-#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8)
-
-#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0)
-#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000)
-#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010)
-#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020)
-
-
-/* values for SAS ProgrammedLinkRate fields */
-#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0)
-#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00)
-#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80)
-#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90)
-#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0)
-#define MPI25_SAS_PRATE_MAX_RATE_12_0 (0xB0)
-#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F)
-#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00)
-#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08)
-#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09)
-#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A)
-
-
-/* values for SAS HwLinkRate fields */
-#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0)
-#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80)
-#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90)
-#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0)
-#define MPI25_SAS_HWRATE_MAX_RATE_12_0 (0xB0)
-#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F)
-#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08)
-#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09)
-#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A)
-
-
-
-/****************************************************************************
-* SAS IO Unit Config Pages
-****************************************************************************/
-
-/* SAS IO Unit Page 0 */
-
-typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA
-{
- U8 Port; /* 0x00 */
- U8 PortFlags; /* 0x01 */
- U8 PhyFlags; /* 0x02 */
- U8 NegotiatedLinkRate; /* 0x03 */
- U32 ControllerPhyDeviceInfo;/* 0x04 */
- U16 AttachedDevHandle; /* 0x08 */
- U16 ControllerDevHandle; /* 0x0A */
- U32 DiscoveryStatus; /* 0x0C */
- U32 Reserved; /* 0x10 */
-} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA,
- Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT0_PHY_MAX
-#define MPI2_SAS_IOUNIT0_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U8 NumPhys; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0,
- Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t;
-
-#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05)
-
-/* values for SAS IO Unit Page 0 PortFlags */
-#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08)
-#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01)
-
-/* values for SAS IO Unit Page 0 PhyFlags */
-#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10)
-#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08)
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */
-
-/* values for SAS IO Unit Page 0 DiscoveryStatus */
-#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400)
-#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001)
-
-
-/* SAS IO Unit Page 1 */
-
-typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA
-{
- U8 Port; /* 0x00 */
- U8 PortFlags; /* 0x01 */
- U8 PhyFlags; /* 0x02 */
- U8 MaxMinLinkRate; /* 0x03 */
- U32 ControllerPhyDeviceInfo; /* 0x04 */
- U16 MaxTargetPortConnectTime; /* 0x08 */
- U16 Reserved1; /* 0x0A */
-} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA,
- Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t;
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT1_PHY_MAX
-#define MPI2_SAS_IOUNIT1_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 ControlFlags; /* 0x08 */
- U16 SASNarrowMaxQueueDepth; /* 0x0A */
- U16 AdditionalControlFlags; /* 0x0C */
- U16 SASWideMaxQueueDepth; /* 0x0E */
- U8 NumPhys; /* 0x10 */
- U8 SATAMaxQDepth; /* 0x11 */
- U8 ReportDeviceMissingDelay; /* 0x12 */
- U8 IODeviceMissingDelay; /* 0x13 */
- MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_1,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1,
- Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t;
-
-#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09)
-
-/* values for SAS IO Unit Page 1 ControlFlags */
-#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000)
-
-#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600)
-#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1)
-#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2)
-
-#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020)
-#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010)
-#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008)
-#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004)
-#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002)
-#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001)
-
-/* values for SAS IO Unit Page 1 AdditionalControlFlags */
-#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080)
-#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040)
-#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020)
-#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010)
-#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008)
-#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004)
-#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002)
-#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001)
-
-/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */
-#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F)
-#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80)
-
-/* values for SAS IO Unit Page 1 PortFlags */
-#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01)
-
-/* values for SAS IO Unit Page 1 PhyFlags */
-#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10)
-#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08)
-
-/* values for SAS IO Unit Page 1 MaxMinLinkRate */
-#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0)
-#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80)
-#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90)
-#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0)
-#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F)
-#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08)
-#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09)
-#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A)
-
-/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */
-
-
-/* SAS IO Unit Page 4 */
-
-typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP
-{
- U8 MaxTargetSpinup; /* 0x00 */
- U8 SpinupDelay; /* 0x01 */
- U8 SpinupFlags; /* 0x02 */
- U8 Reserved1; /* 0x03 */
-} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP,
- Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t;
-
-/* defines for SAS IO Unit Page 4 SpinupFlags */
-#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT4_PHY_MAX
-#define MPI2_SAS_IOUNIT4_PHY_MAX (4)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */
- U32 Reserved1; /* 0x18 */
- U32 Reserved2; /* 0x1C */
- U32 Reserved3; /* 0x20 */
- U8 BootDeviceWaitTime; /* 0x24 */
- U8 Reserved4; /* 0x25 */
- U16 Reserved5; /* 0x26 */
- U8 NumPhys; /* 0x28 */
- U8 PEInitialSpinupDelay; /* 0x29 */
- U8 PEReplyDelay; /* 0x2A */
- U8 Flags; /* 0x2B */
- U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */
-} MPI2_CONFIG_PAGE_SASIOUNIT_4,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4,
- Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t;
-
-#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02)
-
-/* defines for Flags field */
-#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01)
-
-/* defines for PHY field */
-#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03)
-
-
-/* SAS IO Unit Page 5 */
-
-typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS {
- U8 ControlFlags; /* 0x00 */
- U8 PortWidthModGroup; /* 0x01 */
- U16 InactivityTimerExponent; /* 0x02 */
- U8 SATAPartialTimeout; /* 0x04 */
- U8 Reserved2; /* 0x05 */
- U8 SATASlumberTimeout; /* 0x06 */
- U8 Reserved3; /* 0x07 */
- U8 SASPartialTimeout; /* 0x08 */
- U8 Reserved4; /* 0x09 */
- U8 SASSlumberTimeout; /* 0x0A */
- U8 Reserved5; /* 0x0B */
-} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS,
- Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t;
-
-/* defines for ControlFlags field */
-#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08)
-#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04)
-#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02)
-#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01)
-
-/* defines for PortWidthModeGroup field */
-#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF)
-
-/* defines for InactivityTimerExponent field */
-#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12)
-#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8)
-#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4)
-#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007)
-#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0)
-
-#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7)
-#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6)
-#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5)
-#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4)
-#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3)
-#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2)
-#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1)
-#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhys at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT5_PHY_MAX
-#define MPI2_SAS_IOUNIT5_PHY_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumPhys; /* 0x08 */
- U8 Reserved1; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
- MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings
- [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_5,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5,
- Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t;
-
-#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01)
-
-
-/* SAS IO Unit Page 6 */
-
-typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS {
- U8 CurrentStatus; /* 0x00 */
- U8 CurrentModulation; /* 0x01 */
- U8 CurrentUtilization; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 Reserved2; /* 0x04 */
-} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS,
- Mpi2SasIOUnit6PortWidthModGroupStatus_t,
- MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t;
-
-/* defines for CurrentStatus field */
-#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00)
-#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01)
-#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02)
-#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03)
-#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04)
-#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05)
-#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06)
-#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07)
-
-/* defines for CurrentModulation field */
-#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00)
-#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01)
-#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02)
-#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumGroups at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX
-#define MPI2_SAS_IOUNIT6_GROUP_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U8 NumGroups; /* 0x10 */
- U8 Reserved3; /* 0x11 */
- U16 Reserved4; /* 0x12 */
- MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS
- PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_6,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6,
- Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t;
-
-#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00)
-
-
-/* SAS IO Unit Page 7 */
-
-typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS {
- U8 Flags; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U8 Threshold75Pct; /* 0x04 */
- U8 Threshold50Pct; /* 0x05 */
- U8 Threshold25Pct; /* 0x06 */
- U8 Reserved3; /* 0x07 */
-} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
- MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS,
- Mpi2SasIOUnit7PortWidthModGroupSettings_t,
- MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t;
-
-/* defines for Flags field */
-#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01)
-
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumGroups at runtime.
- */
-#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX
-#define MPI2_SAS_IOUNIT7_GROUP_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 SamplingInterval; /* 0x08 */
- U8 WindowLength; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U8 NumGroups; /* 0x14 */
- U8 Reserved4; /* 0x15 */
- U16 Reserved5; /* 0x16 */
- MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS
- PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_7,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7,
- Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t;
-
-#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00)
-
-
-/* SAS IO Unit Page 8 */
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 PowerManagementCapabilities;/* 0x0C */
- U32 Reserved2; /* 0x10 */
-} MPI2_CONFIG_PAGE_SASIOUNIT_8,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8,
- Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t;
-
-#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00)
-
-/* defines for PowerManagementCapabilities field */
-#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000)
-#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800)
-#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400)
-#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200)
-#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002)
-#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001)
-
-
-
-/* SAS IO Unit Page 16 */
-
-typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT16 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U64 TimeStamp; /* 0x08 */
- U32 Reserved1; /* 0x10 */
- U32 Reserved2; /* 0x14 */
- U32 FastPathPendedRequests; /* 0x18 */
- U32 FastPathUnPendedRequests; /* 0x1C */
- U32 FastPathHostRequestStarts; /* 0x20 */
- U32 FastPathFirmwareRequestStarts; /* 0x24 */
- U32 FastPathHostCompletions; /* 0x28 */
- U32 FastPathFirmwareCompletions; /* 0x2C */
- U32 NonFastPathRequestStarts; /* 0x30 */
- U32 NonFastPathHostCompletions; /* 0x30 */
-} MPI2_CONFIG_PAGE_SASIOUNIT16,
-MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT16,
-Mpi2SasIOUnitPage16_t, MPI2_POINTER pMpi2SasIOUnitPage16_t;
-
-#define MPI2_SASIOUNITPAGE16_PAGEVERSION (0x00)
-
-
-/****************************************************************************
-* SAS Expander Config Pages
-****************************************************************************/
-
-/* SAS Expander Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PhysicalPort; /* 0x08 */
- U8 ReportGenLength; /* 0x09 */
- U16 EnclosureHandle; /* 0x0A */
- U64 SASAddress; /* 0x0C */
- U32 DiscoveryStatus; /* 0x14 */
- U16 DevHandle; /* 0x18 */
- U16 ParentDevHandle; /* 0x1A */
- U16 ExpanderChangeCount; /* 0x1C */
- U16 ExpanderRouteIndexes; /* 0x1E */
- U8 NumPhys; /* 0x20 */
- U8 SASLevel; /* 0x21 */
- U16 Flags; /* 0x22 */
- U16 STPBusInactivityTimeLimit; /* 0x24 */
- U16 STPMaxConnectTimeLimit; /* 0x26 */
- U16 STP_SMP_NexusLossTime; /* 0x28 */
- U16 MaxNumRoutedSasAddresses; /* 0x2A */
- U64 ActiveZoneManagerSASAddress;/* 0x2C */
- U16 ZoneLockInactivityLimit; /* 0x34 */
- U16 Reserved1; /* 0x36 */
- U8 TimeToReducedFunc; /* 0x38 */
- U8 InitialTimeToReducedFunc; /* 0x39 */
- U8 MaxReducedFuncTime; /* 0x3A */
- U8 Reserved2; /* 0x3B */
-} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
- Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
-
-#define MPI2_SASEXPANDER0_PAGEVERSION (0x06)
-
-/* values for SAS Expander Page 0 DiscoveryStatus field */
-#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400)
-#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001)
-
-/* values for SAS Expander Page 0 Flags field */
-#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000)
-#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000)
-#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800)
-#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400)
-#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200)
-#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100)
-#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080)
-#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010)
-#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004)
-#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002)
-#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001)
-
-
-/* SAS Expander Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PhysicalPort; /* 0x08 */
- U8 Reserved1; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U8 NumPhys; /* 0x0C */
- U8 Phy; /* 0x0D */
- U16 NumTableEntriesProgrammed; /* 0x0E */
- U8 ProgrammedLinkRate; /* 0x10 */
- U8 HwLinkRate; /* 0x11 */
- U16 AttachedDevHandle; /* 0x12 */
- U32 PhyInfo; /* 0x14 */
- U32 AttachedDeviceInfo; /* 0x18 */
- U16 ExpanderDevHandle; /* 0x1C */
- U8 ChangeCount; /* 0x1E */
- U8 NegotiatedLinkRate; /* 0x1F */
- U8 PhyIdentifier; /* 0x20 */
- U8 AttachedPhyIdentifier; /* 0x21 */
- U8 Reserved3; /* 0x22 */
- U8 DiscoveryInfo; /* 0x23 */
- U32 AttachedPhyInfo; /* 0x24 */
- U8 ZoneGroup; /* 0x28 */
- U8 SelfConfigStatus; /* 0x29 */
- U16 Reserved4; /* 0x2A */
-} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1,
- Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t;
-
-#define MPI2_SASEXPANDER1_PAGEVERSION (0x02)
-
-/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
-
-/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
-
-/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
-
-/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-/* values for SAS Expander Page 1 DiscoveryInfo field */
-#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04)
-#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02)
-#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01)
-
-/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
-
-/****************************************************************************
-* SAS Device Config Pages
-****************************************************************************/
-
-/* SAS Device Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 Slot; /* 0x08 */
- U16 EnclosureHandle; /* 0x0A */
- U64 SASAddress; /* 0x0C */
- U16 ParentDevHandle; /* 0x14 */
- U8 PhyNum; /* 0x16 */
- U8 AccessStatus; /* 0x17 */
- U16 DevHandle; /* 0x18 */
- U8 AttachedPhyIdentifier; /* 0x1A */
- U8 ZoneGroup; /* 0x1B */
- U32 DeviceInfo; /* 0x1C */
- U16 Flags; /* 0x20 */
- U8 PhysicalPort; /* 0x22 */
- U8 MaxPortConnections; /* 0x23 */
- U64 DeviceName; /* 0x24 */
- U8 PortGroups; /* 0x2C */
- U8 DmaGroup; /* 0x2D */
- U8 ControlGroup; /* 0x2E */
- U8 EnclosureLevel; /* 0x2F */
- U8 ConnectorName[4]; /* 0x30 */
- U32 Reserved3; /* 0x34 */
-} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0,
- Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t;
-
-#define MPI2_SASDEVICE0_PAGEVERSION (0x09)
-
-/* values for SAS Device Page 0 AccessStatus field */
-#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03)
-#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04)
-#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05)
-#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06)
-#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07)
-/* specific values for SATA Init failures */
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19)
-#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F)
-
-/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */
-
-/* values for SAS Device Page 0 Flags field */
-#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000)
-#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000)
-#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200)
-#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
-#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
-#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
-#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
-#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
-
-
-/* SAS Device Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U64 SASAddress; /* 0x0C */
- U32 Reserved2; /* 0x14 */
- U16 DevHandle; /* 0x18 */
- U16 Reserved3; /* 0x1A */
- U8 InitialRegDeviceFIS[20];/* 0x1C */
-} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1,
- Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t;
-
-#define MPI2_SASDEVICE1_PAGEVERSION (0x01)
-
-
-/****************************************************************************
-* SAS PHY Config Pages
-****************************************************************************/
-
-/* SAS PHY Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 OwnerDevHandle; /* 0x08 */
- U16 Reserved1; /* 0x0A */
- U16 AttachedDevHandle; /* 0x0C */
- U8 AttachedPhyIdentifier; /* 0x0E */
- U8 Reserved2; /* 0x0F */
- U32 AttachedPhyInfo; /* 0x10 */
- U8 ProgrammedLinkRate; /* 0x14 */
- U8 HwLinkRate; /* 0x15 */
- U8 ChangeCount; /* 0x16 */
- U8 Flags; /* 0x17 */
- U32 PhyInfo; /* 0x18 */
- U8 NegotiatedLinkRate; /* 0x1C */
- U8 Reserved3; /* 0x1D */
- U16 Reserved4; /* 0x1E */
-} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0,
- Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t;
-
-#define MPI2_SASPHY0_PAGEVERSION (0x03)
-
-/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */
-
-/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */
-
-/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */
-
-/* values for SAS PHY Page 0 Flags field */
-#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01)
-
-/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */
-
-
-/* SAS PHY Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 InvalidDwordCount; /* 0x0C */
- U32 RunningDisparityErrorCount; /* 0x10 */
- U32 LossDwordSynchCount; /* 0x14 */
- U32 PhyResetProblemCount; /* 0x18 */
-} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1,
- Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t;
-
-#define MPI2_SASPHY1_PAGEVERSION (0x01)
-
-
-/* SAS PHY Page 2 */
-
-typedef struct _MPI2_SASPHY2_PHY_EVENT {
- U8 PhyEventCode; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 PhyEventInfo; /* 0x04 */
-} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT,
- Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t;
-
-/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */
-
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhyEvents at runtime.
- */
-#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
-#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U8 NumPhyEvents; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX];
- /* 0x10 */
-} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2,
- Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t;
-
-#define MPI2_SASPHY2_PAGEVERSION (0x00)
-
-
-/* SAS PHY Page 3 */
-
-typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
- U8 PhyEventCode; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U8 CounterType; /* 0x04 */
- U8 ThresholdWindow; /* 0x05 */
- U8 TimeUnits; /* 0x06 */
- U8 Reserved3; /* 0x07 */
- U32 EventThreshold; /* 0x08 */
- U16 ThresholdFlags; /* 0x0C */
- U16 Reserved4; /* 0x0E */
-} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG,
- Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t;
-
-/* values for PhyEventCode field */
-#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00)
-#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01)
-#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02)
-#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03)
-#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04)
-#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05)
-#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06)
-#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20)
-#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21)
-#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22)
-#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23)
-#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24)
-#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25)
-#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26)
-#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27)
-#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28)
-#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29)
-#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A)
-#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B)
-#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C)
-#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D)
-#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E)
-#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40)
-#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41)
-#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42)
-#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43)
-#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44)
-#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45)
-#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50)
-#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51)
-#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52)
-#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60)
-#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61)
-#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63)
-#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0)
-#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
-#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
-
-/* values for the CounterType field */
-#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
-#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
-#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02)
-
-/* values for the TimeUnits field */
-#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00)
-#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01)
-#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02)
-#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03)
-
-/* values for the ThresholdFlags field */
-#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002)
-#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001)
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumPhyEvents at runtime.
- */
-#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
-#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
-#endif
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U8 NumPhyEvents; /* 0x0C */
- U8 Reserved2; /* 0x0D */
- U16 Reserved3; /* 0x0E */
- MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig
- [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */
-} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3,
- Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t;
-
-#define MPI2_SASPHY3_PAGEVERSION (0x00)
-
-
-/* SAS PHY Page 4 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U16 Reserved1; /* 0x08 */
- U8 Reserved2; /* 0x0A */
- U8 Flags; /* 0x0B */
- U8 InitialFrame[28]; /* 0x0C */
-} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4,
- Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t;
-
-#define MPI2_SASPHY4_PAGEVERSION (0x00)
-
-/* values for the Flags field */
-#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02)
-#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01)
-
-
-
-
-/****************************************************************************
-* SAS Port Config Pages
-****************************************************************************/
-
-/* SAS Port Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 PortNumber; /* 0x08 */
- U8 PhysicalPort; /* 0x09 */
- U8 PortWidth; /* 0x0A */
- U8 PhysicalPortWidth; /* 0x0B */
- U8 ZoneGroup; /* 0x0C */
- U8 Reserved1; /* 0x0D */
- U16 Reserved2; /* 0x0E */
- U64 SASAddress; /* 0x10 */
- U32 DeviceInfo; /* 0x18 */
- U32 Reserved3; /* 0x1C */
- U32 Reserved4; /* 0x20 */
-} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0,
- Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t;
-
-#define MPI2_SASPORT0_PAGEVERSION (0x00)
-
-/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */
-
-
-/****************************************************************************
-* SAS Enclosure Config Pages
-****************************************************************************/
-
-/* SAS Enclosure Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U64 EnclosureLogicalID; /* 0x0C */
- U16 Flags; /* 0x14 */
- U16 EnclosureHandle; /* 0x16 */
- U16 NumSlots; /* 0x18 */
- U16 StartSlot; /* 0x1A */
- U8 Reserved2; /* 0x1C */
- U8 EnclosureLevel; /* 0x1D */
- U16 SEPDevHandle; /* 0x1E */
- U32 Reserved3; /* 0x20 */
- U32 Reserved4; /* 0x24 */
-} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
- Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
-
-#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
-
-/* values for SAS Enclosure Page 0 Flags field */
-#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004)
-#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005)
-
-
-/****************************************************************************
-* Log Config Page
-****************************************************************************/
-
-/* Log Page 0 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumLogEntries at runtime.
- */
-#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES
-#define MPI2_LOG_0_NUM_LOG_ENTRIES (1)
-#endif
-
-#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C)
-
-typedef struct _MPI2_LOG_0_ENTRY
-{
- U64 TimeStamp; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U16 LogSequence; /* 0x0C */
- U16 LogEntryQualifier; /* 0x0E */
- U8 VP_ID; /* 0x10 */
- U8 VF_ID; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */
-} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY,
- Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t;
-
-/* values for Log Page 0 LogEntry LogEntryQualifier field */
-#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000)
-#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001)
-#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002)
-#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000)
-#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF)
-
-typedef struct _MPI2_CONFIG_PAGE_LOG_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
- U16 NumLogEntries; /* 0x10 */
- U16 Reserved3; /* 0x12 */
- MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */
-} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0,
- Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t;
-
-#define MPI2_LOG_0_PAGEVERSION (0x02)
-
-
-/****************************************************************************
-* RAID Config Page
-****************************************************************************/
-
-/* RAID Page 0 */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check the value returned for NumElements at runtime.
- */
-#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS
-#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1)
-#endif
-
-typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT
-{
- U16 ElementFlags; /* 0x00 */
- U16 VolDevHandle; /* 0x02 */
- U8 HotSparePool; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 PhysDiskDevHandle; /* 0x06 */
-} MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
- MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT,
- Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t;
-
-/* values for the ElementFlags field */
-#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F)
-#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000)
-#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001)
-#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002)
-#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003)
-
-
-typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumHotSpares; /* 0x08 */
- U8 NumPhysDisks; /* 0x09 */
- U8 NumVolumes; /* 0x0A */
- U8 ConfigNum; /* 0x0B */
- U32 Flags; /* 0x0C */
- U8 ConfigGUID[24]; /* 0x10 */
- U32 Reserved1; /* 0x28 */
- U8 NumElements; /* 0x2C */
- U8 Reserved2; /* 0x2D */
- U16 Reserved3; /* 0x2E */
- MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */
-} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0,
- Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t;
-
-#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00)
-
-/* values for RAID Configuration Page 0 Flags field */
-#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001)
-
-
-/****************************************************************************
-* Driver Persistent Mapping Config Pages
-****************************************************************************/
-
-/* Driver Persistent Mapping Page 0 */
-
-typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY
-{
- U64 PhysicalIdentifier; /* 0x00 */
- U16 MappingInformation; /* 0x08 */
- U16 DeviceIndex; /* 0x0A */
- U32 PhysicalBitsMapping; /* 0x0C */
- U32 Reserved1; /* 0x10 */
-} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY,
- Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t;
-
-typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0
-{
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */
-} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0,
- Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t;
-
-#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00)
-
-/* values for Driver Persistent Mapping Page 0 MappingInformation field */
-#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0)
-#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4)
-#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F)
-
-
-/****************************************************************************
-* Ethernet Config Pages
-****************************************************************************/
-
-/* Ethernet Page 0 */
-
-/* IP address (union of IPv4 and IPv6) */
-typedef union _MPI2_ETHERNET_IP_ADDR {
- U32 IPv4Addr;
- U32 IPv6Addr[4];
-} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR,
- Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t;
-
-#define MPI2_ETHERNET_HOST_NAME_LENGTH (32)
-
-typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U8 NumInterfaces; /* 0x08 */
- U8 Reserved0; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Status; /* 0x0C */
- U8 MediaState; /* 0x10 */
- U8 Reserved2; /* 0x11 */
- U16 Reserved3; /* 0x12 */
- U8 MacAddress[6]; /* 0x14 */
- U8 Reserved4; /* 0x1A */
- U8 Reserved5; /* 0x1B */
- MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */
- MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */
- MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */
- MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */
- MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */
- MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */
- U8 HostName
- [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
-} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0,
- Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t;
-
-#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00)
-
-/* values for Ethernet Page 0 Status field */
-#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000)
-#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000)
-#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000)
-#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100)
-#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080)
-#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040)
-#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020)
-#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010)
-#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008)
-#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004)
-#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002)
-#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001)
-
-/* values for Ethernet Page 0 MediaState field */
-#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80)
-#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00)
-#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80)
-
-#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07)
-#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00)
-#define MPI2_ETHPG0_MS_10MBIT (0x01)
-#define MPI2_ETHPG0_MS_100MBIT (0x02)
-#define MPI2_ETHPG0_MS_1GBIT (0x03)
-
-
-/* Ethernet Page 1 */
-
-typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 Reserved0; /* 0x08 */
- U32 Flags; /* 0x0C */
- U8 MediaState; /* 0x10 */
- U8 Reserved1; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 MacAddress[6]; /* 0x14 */
- U8 Reserved3; /* 0x1A */
- U8 Reserved4; /* 0x1B */
- MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */
- MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */
- MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */
- MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */
- MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */
- U32 Reserved5; /* 0x6C */
- U32 Reserved6; /* 0x70 */
- U32 Reserved7; /* 0x74 */
- U32 Reserved8; /* 0x78 */
- U8 HostName
- [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */
-} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1,
- Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t;
-
-#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00)
-
-/* values for Ethernet Page 1 Flags field */
-#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100)
-#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080)
-#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040)
-#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020)
-#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010)
-#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008)
-#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004)
-#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002)
-#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001)
-
-/* values for Ethernet Page 1 MediaState field */
-#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80)
-#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00)
-#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80)
-
-#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07)
-#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00)
-#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01)
-#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02)
-#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03)
-
-
-/****************************************************************************
-* Extended Manufacturing Config Pages
-****************************************************************************/
-
-/*
- * Generic structure to use for product-specific extended manufacturing pages
- * (currently Extended Manufacturing Page 40 through Extended Manufacturing
- * Page 60).
- */
-
-typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS {
- MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
- U32 ProductSpecificInfo; /* 0x08 */
-} MPI2_CONFIG_PAGE_EXT_MAN_PS,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS,
- Mpi2ExtManufacturingPagePS_t,
- MPI2_POINTER pMpi2ExtManufacturingPagePS_t;
-
-/* PageVersion should be provided by product-specific code */
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
deleted file mode 100644
index eea1a16..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_init.h
- * Title: MPI SCSI initiator mode messages and structures
- * Creation Date: June 23, 2006
- *
- * mpi2_init.h Version: 02.00.15
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t.
- * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines.
- * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention.
- * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
- * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
- * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
- * Control field Task Attribute flags.
- * Moved LUN field defines to mpi2.h because they are
- * common to many structures.
- * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
- * Query Asynchronous Event.
- * Defined two new bits in the SlotStatus field of the SCSI
- * Enclosure Processor Request and Reply.
- * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for
- * both SCSI IO Error Reply and SCSI Task Management Reply.
- * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY.
- * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define.
- * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it.
- * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request.
- * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define.
- * 02-06-12 02.00.13 Added alternate defines for Task Priority / Command
- * Priority to match SAM-4.
- * 07-10-12 02.00.14 Added MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION.
- * 04-09-13 02.00.15 Added SCSIStatusQualifier field to MPI2_SCSI_IO_REPLY,
- * replacing the Reserved4 field.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_INIT_H
-#define MPI2_INIT_H
-
-/*****************************************************************************
-*
-* SCSI Initiator Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* SCSI IO messages and associated structures
-****************************************************************************/
-
-typedef struct
-{
- U8 CDB[20]; /* 0x00 */
- U32 PrimaryReferenceTag; /* 0x14 */
- U16 PrimaryApplicationTag; /* 0x18 */
- U16 PrimaryApplicationTagMask; /* 0x1A */
- U32 TransferLength; /* 0x1C */
-} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32,
- Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t;
-
-typedef union
-{
- U8 CDB32[32];
- MPI2_SCSI_IO_CDB_EEDP32 EEDP32;
- MPI2_SGE_SIMPLE_UNION SGE;
-} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION,
- Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t;
-
-/* SCSI IO Request Message */
-typedef struct _MPI2_SCSI_IO_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U32 SenseBufferLowAddress; /* 0x0C */
- U16 SGLFlags; /* 0x10 */
- U8 SenseBufferLength; /* 0x12 */
- U8 Reserved4; /* 0x13 */
- U8 SGLOffset0; /* 0x14 */
- U8 SGLOffset1; /* 0x15 */
- U8 SGLOffset2; /* 0x16 */
- U8 SGLOffset3; /* 0x17 */
- U32 SkipCount; /* 0x18 */
- U32 DataLength; /* 0x1C */
- U32 BidirectionalDataLength; /* 0x20 */
- U16 IoFlags; /* 0x24 */
- U16 EEDPFlags; /* 0x26 */
- U32 EEDPBlockSize; /* 0x28 */
- U32 SecondaryReferenceTag; /* 0x2C */
- U16 SecondaryApplicationTag; /* 0x30 */
- U16 ApplicationTagTranslationMask; /* 0x32 */
- U8 LUN[8]; /* 0x34 */
- U32 Control; /* 0x3C */
- MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */
-
-#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */
- MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion;
-#endif
-
- MPI2_SGE_IO_UNION SGL; /* 0x60 */
-
-} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST,
- Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t;
-
-/* SCSI IO MsgFlags bits */
-
-/* MsgFlags for SenseBufferAddressSpace */
-#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C)
-#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00)
-#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04)
-#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08)
-#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C)
-
-/* SCSI IO SGLFlags bits */
-
-/* base values for Data Location Address Space */
-#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C)
-#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00)
-#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04)
-#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08)
-#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C)
-
-/* base values for Type */
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01)
-#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02)
-
-/* shift values for each sub-field */
-#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12)
-#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8)
-#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4)
-#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0)
-
-/* number of SGLOffset fields */
-#define MPI2_SCSIIO_NUM_SGLOFFSETS (4)
-
-/* SCSI IO IoFlags bits */
-
-/* Large CDB Address Space */
-#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000)
-#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000)
-#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000)
-
-#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000)
-#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800)
-#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400)
-#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200)
-#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF)
-
-/* SCSI IO EEDPFlags bits */
-
-#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000)
-#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000)
-
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100)
-
-#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008)
-
-#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007)
-#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001)
-#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003)
-#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004)
-#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006)
-#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007)
-
-/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */
-
-/* SCSI IO Control bits */
-#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000)
-#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26)
-
-#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000)
-#define MPI2_SCSIIO_CONTROL_SHIFT_DATADIRECTION (24)
-#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000)
-#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000)
-#define MPI2_SCSIIO_CONTROL_READ (0x02000000)
-#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000)
-
-#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800)
-#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11)
-/* alternate name for the previous field; called Command Priority in SAM-4 */
-#define MPI2_SCSIIO_CONTROL_CMDPRI_MASK (0x00007800)
-#define MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT (11)
-
-#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700)
-#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000)
-#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100)
-#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200)
-#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400)
-
-#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0)
-#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000)
-#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040)
-#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080)
-
-
-/* SCSI IO Error Reply Message */
-typedef struct _MPI2_SCSI_IO_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 SCSIStatus; /* 0x0C */
- U8 SCSIState; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 TransferCount; /* 0x14 */
- U32 SenseCount; /* 0x18 */
- U32 ResponseInfo; /* 0x1C */
- U16 TaskTag; /* 0x20 */
- U16 SCSIStatusQualifier; /* 0x22 */
- U32 BidirectionalTransferCount; /* 0x24 */
- U32 Reserved5; /* 0x28 */
- U32 Reserved6; /* 0x2C */
-} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY,
- Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t;
-
-/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */
-
-#define MPI2_SCSI_STATUS_GOOD (0x00)
-#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02)
-#define MPI2_SCSI_STATUS_CONDITION_MET (0x04)
-#define MPI2_SCSI_STATUS_BUSY (0x08)
-#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10)
-#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14)
-#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18)
-#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */
-#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28)
-#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30)
-#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40)
-
-/* SCSI IO Reply SCSIState flags */
-
-#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10)
-#define MPI2_SCSI_STATE_TERMINATED (0x08)
-#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04)
-#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02)
-#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01)
-
-/* masks and shifts for the ResponseInfo field */
-
-#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF)
-#define MPI2_SCSI_RI_SHIFT_REASONCODE (0)
-
-#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF)
-
-
-/****************************************************************************
-* SCSI Task Management messages
-****************************************************************************/
-
-/* SCSI Task Management Request Message */
-typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved1; /* 0x04 */
- U8 TaskType; /* 0x05 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 LUN[8]; /* 0x0C */
- U32 Reserved4[7]; /* 0x14 */
- U16 TaskMID; /* 0x30 */
- U16 Reserved5; /* 0x32 */
-} MPI2_SCSI_TASK_MANAGE_REQUEST,
- MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST,
- Mpi2SCSITaskManagementRequest_t,
- MPI2_POINTER pMpi2SCSITaskManagementRequest_t;
-
-/* TaskType values */
-
-#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01)
-#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02)
-#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03)
-#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05)
-#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06)
-#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
-#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A)
-
-/* obsolete TaskType name */
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \
- (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
-
-/* MsgFlags bits */
-
-#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08)
-#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10)
-
-#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01)
-
-
-
-/* SCSI Task Management Reply Message */
-typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 ResponseCode; /* 0x04 */
- U8 TaskType; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 TerminationCount; /* 0x14 */
- U32 ResponseInfo; /* 0x18 */
-} MPI2_SCSI_TASK_MANAGE_REPLY,
- MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY,
- Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t;
-
-/* ResponseCode values */
-
-#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00)
-#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02)
-#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04)
-#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05)
-#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08)
-#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09)
-#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A)
-#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80)
-
-/* masks and shifts for the ResponseInfo field */
-
-#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16)
-#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000)
-#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24)
-
-
-/****************************************************************************
-* SCSI Enclosure Processor messages
-****************************************************************************/
-
-/* SCSI Enclosure Processor Request Message */
-typedef struct _MPI2_SEP_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Action; /* 0x04 */
- U8 Flags; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 SlotStatus; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
- U32 Reserved5; /* 0x18 */
- U16 Slot; /* 0x1C */
- U16 EnclosureHandle; /* 0x1E */
-} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST,
- Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t;
-
-/* Action defines */
-#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00)
-#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01)
-
-/* Flags defines */
-#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00)
-#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01)
-
-/* SlotStatus defines */
-#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000)
-#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
-#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
-#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100)
-#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080)
-#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
-#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
-#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
-#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004)
-#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002)
-#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001)
-
-
-/* SCSI Enclosure Processor Reply Message */
-typedef struct _MPI2_SEP_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Action; /* 0x04 */
- U8 Flags; /* 0x05 */
- U8 Reserved1; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 SlotStatus; /* 0x14 */
- U32 Reserved4; /* 0x18 */
- U16 Slot; /* 0x1C */
- U16 EnclosureHandle; /* 0x1E */
-} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY,
- Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t;
-
-/* SlotStatus defines */
-#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000)
-#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000)
-#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200)
-#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100)
-#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080)
-#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
-#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
-#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
-#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004)
-#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002)
-#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001)
-
-
-#endif
-
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
deleted file mode 100644
index b02de48..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ /dev/null
@@ -1,1708 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_ioc.h
- * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
- * Creation Date: October 11, 2006
- *
- * mpi2_ioc.h Version: 02.00.24
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to
- * MaxTargets.
- * Added TotalImageSize field to FWDownload Request.
- * Added reserved words to FWUpload Request.
- * 06-26-07 02.00.02 Added IR Configuration Change List Event.
- * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit
- * request and replaced it with
- * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
- * Replaced the MinReplyQueueDepth field of the IOCFacts
- * reply with MaxReplyDescriptorPostQueueDepth.
- * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
- * depth for the Reply Descriptor Post Queue.
- * Added SASAddress field to Initiator Device Table
- * Overflow Event data.
- * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
- * for SAS Initiator Device Status Change Event data.
- * Modified Reason Code defines for SAS Topology Change
- * List Event data, including adding a bit for PHY Vacant
- * status, and adding a mask for the Reason Code.
- * Added define for
- * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
- * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
- * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of
- * the IOCFacts Reply.
- * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
- * Moved MPI2_VERSION_UNION to mpi2.h.
- * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
- * instead of enables, and added SASBroadcastPrimitiveMasks
- * field.
- * Added Log Entry Added Event and related structure.
- * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
- * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
- * Added MaxVolumes and MaxPersistentEntries fields to
- * IOCFacts reply.
- * Added ProtocalFlags and IOCCapabilities fields to
- * MPI2_FW_IMAGE_HEADER.
- * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
- * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
- * a U16 (from a U32).
- * Removed extra 's' from EventMasks name.
- * 06-27-08 02.00.08 Fixed an offset in a comment.
- * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
- * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
- * renamed MinReplyFrameSize to ReplyFrameSize.
- * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
- * Added two new RAIDOperation values for Integrated RAID
- * Operations Status Event data.
- * Added four new IR Configuration Change List Event data
- * ReasonCode values.
- * Added two new ReasonCode defines for SAS Device Status
- * Change Event data.
- * Added three new DiscoveryStatus bits for the SAS
- * Discovery event data.
- * Added Multiplexing Status Change bit to the PhyStatus
- * field of the SAS Topology Change List event data.
- * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
- * BootFlags are now product-specific.
- * Added defines for the indivdual signature bytes
- * for MPI2_INIT_IMAGE_FOOTER.
- * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
- * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
- * define.
- * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
- * define.
- * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
- * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
- * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
- * Added two new reason codes for SAS Device Status Change
- * Event.
- * Added new event: SAS PHY Counter.
- * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure.
- * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
- * Added new product id family for 2208.
- * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST.
- * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY.
- * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY.
- * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY.
- * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define.
- * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define.
- * Added Host Based Discovery Phy Event data.
- * Added defines for ProductID Product field
- * (MPI2_FW_HEADER_PID_).
- * Modified values for SAS ProductID Family
- * (MPI2_FW_HEADER_PID_FAMILY_).
- * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines.
- * Added PowerManagementControl Request structures and
- * defines.
- * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete.
- * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define.
- * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC.
- * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added
- * SASNotifyPrimitiveMasks field to
- * MPI2_EVENT_NOTIFICATION_REQUEST.
- * Added Temperature Threshold Event.
- * Added Host Message Event.
- * Added Send Host Message request and reply.
- * 05-25-11 02.00.18 For Extended Image Header, added
- * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and
- * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines.
- * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define.
- * 08-24-11 02.00.19 Added PhysicalPort field to
- * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure.
- * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete.
- * 03-29-12 02.00.21 Added a product specific range to event values.
- * 07-26-12 02.00.22 Added MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE.
- * Added ElapsedSeconds field to
- * MPI2_EVENT_DATA_IR_OPERATION_STATUS.
- * 08-19-13 02.00.23 For IOCInit, added MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE
- * and MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY.
- * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
- * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
- * Added Encrypted Hash Extended Image.
- * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_IOC_H
-#define MPI2_IOC_H
-
-/*****************************************************************************
-*
-* IOC Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* IOCInit message
-****************************************************************************/
-
-/* IOCInit Request message */
-typedef struct _MPI2_IOC_INIT_REQUEST
-{
- U8 WhoInit; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 MsgVersion; /* 0x0C */
- U16 HeaderVersion; /* 0x0E */
- U32 Reserved5; /* 0x10 */
- U16 Reserved6; /* 0x14 */
- U8 Reserved7; /* 0x16 */
- U8 HostMSIxVectors; /* 0x17 */
- U16 Reserved8; /* 0x18 */
- U16 SystemRequestFrameSize; /* 0x1A */
- U16 ReplyDescriptorPostQueueDepth; /* 0x1C */
- U16 ReplyFreeQueueDepth; /* 0x1E */
- U32 SenseBufferAddressHigh; /* 0x20 */
- U32 SystemReplyAddressHigh; /* 0x24 */
- U64 SystemRequestFrameBaseAddress; /* 0x28 */
- U64 ReplyDescriptorPostQueueAddress;/* 0x30 */
- U64 ReplyFreeQueueAddress; /* 0x38 */
- U64 TimeStamp; /* 0x40 */
-} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST,
- Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t;
-
-/* WhoInit values */
-#define MPI2_WHOINIT_NOT_INITIALIZED (0x00)
-#define MPI2_WHOINIT_SYSTEM_BIOS (0x01)
-#define MPI2_WHOINIT_ROM_BIOS (0x02)
-#define MPI2_WHOINIT_PCI_PEER (0x03)
-#define MPI2_WHOINIT_HOST_DRIVER (0x04)
-#define MPI2_WHOINIT_MANUFACTURER (0x05)
-
-/* MsgFlags */
-#define MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE (0x01)
-
-/* MsgVersion */
-#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00)
-#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8)
-#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF)
-#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0)
-
-/* HeaderVersion */
-#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00)
-#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8)
-#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF)
-#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0)
-
-/* minimum depth for a Reply Descriptor Post Queue */
-#define MPI2_RDPQ_DEPTH_MIN (16)
-
-/* Reply Descriptor Post Queue Array Entry */
-typedef struct _MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY {
- U64 RDPQBaseAddress; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
-} MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
-MPI2_POINTER PTR_MPI2_IOC_INIT_RDPQ_ARRAY_ENTRY,
-Mpi2IOCInitRDPQArrayEntry, MPI2_POINTER pMpi2IOCInitRDPQArrayEntry;
-
-/* IOCInit Reply message */
-typedef struct _MPI2_IOC_INIT_REPLY
-{
- U8 WhoInit; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY,
- Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t;
-
-
-/****************************************************************************
-* IOCFacts message
-****************************************************************************/
-
-/* IOCFacts Request message */
-typedef struct _MPI2_IOC_FACTS_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
-} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST,
- Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t;
-
-
-/* IOCFacts Reply message */
-typedef struct _MPI2_IOC_FACTS_REPLY
-{
- U16 MsgVersion; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 HeaderVersion; /* 0x04 */
- U8 IOCNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U16 IOCExceptions; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 MaxChainDepth; /* 0x14 */
- U8 WhoInit; /* 0x15 */
- U8 NumberOfPorts; /* 0x16 */
- U8 MaxMSIxVectors; /* 0x17 */
- U16 RequestCredit; /* 0x18 */
- U16 ProductID; /* 0x1A */
- U32 IOCCapabilities; /* 0x1C */
- MPI2_VERSION_UNION FWVersion; /* 0x20 */
- U16 IOCRequestFrameSize; /* 0x24 */
- U16 Reserved3; /* 0x26 */
- U16 MaxInitiators; /* 0x28 */
- U16 MaxTargets; /* 0x2A */
- U16 MaxSasExpanders; /* 0x2C */
- U16 MaxEnclosures; /* 0x2E */
- U16 ProtocolFlags; /* 0x30 */
- U16 HighPriorityCredit; /* 0x32 */
- U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */
- U8 ReplyFrameSize; /* 0x36 */
- U8 MaxVolumes; /* 0x37 */
- U16 MaxDevHandle; /* 0x38 */
- U16 MaxPersistentEntries; /* 0x3A */
- U16 MinDevHandle; /* 0x3C */
- U16 Reserved4; /* 0x3E */
-} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY,
- Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t;
-
-/* MsgVersion */
-#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00)
-#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8)
-#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF)
-#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0)
-
-/* HeaderVersion */
-#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00)
-#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8)
-#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF)
-#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0)
-
-/* IOCExceptions */
-#define MPI2_IOCFACTS_EXCEPT_PARTIAL_MEMORY_FAILURE (0x0200)
-#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100)
-
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040)
-#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060)
-
-#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010)
-#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008)
-#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004)
-#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002)
-#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001)
-
-/* defines for WhoInit field are after the IOCInit Request */
-
-/* ProductID field uses MPI2_FW_HEADER_PID_ */
-
-/* IOCCapabilities */
-#define MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE (0x00040000)
-#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000)
-#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000)
-#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000)
-#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000)
-#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000)
-#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800)
-#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100)
-#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080)
-#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040)
-#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020)
-#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010)
-#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008)
-#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004)
-
-/* ProtocolFlags */
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001)
-#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002)
-
-
-/****************************************************************************
-* PortFacts message
-****************************************************************************/
-
-/* PortFacts Request message */
-typedef struct _MPI2_PORT_FACTS_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 PortNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
-} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST,
- Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t;
-
-/* PortFacts Reply message */
-typedef struct _MPI2_PORT_FACTS_REPLY
-{
- U16 Reserved1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 PortNumber; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 Reserved5; /* 0x14 */
- U8 PortType; /* 0x15 */
- U16 Reserved6; /* 0x16 */
- U16 MaxPostedCmdBuffers; /* 0x18 */
- U16 Reserved7; /* 0x1A */
-} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY,
- Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t;
-
-/* PortType values */
-#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00)
-#define MPI2_PORTFACTS_PORTTYPE_FC (0x10)
-#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20)
-#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30)
-#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31)
-
-
-/****************************************************************************
-* PortEnable message
-****************************************************************************/
-
-/* PortEnable Request message */
-typedef struct _MPI2_PORT_ENABLE_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved2; /* 0x04 */
- U8 PortFlags; /* 0x05 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
-} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST,
- Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t;
-
-
-/* PortEnable Reply message */
-typedef struct _MPI2_PORT_ENABLE_REPLY
-{
- U16 Reserved1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U8 Reserved2; /* 0x04 */
- U8 PortFlags; /* 0x05 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY,
- Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t;
-
-
-/****************************************************************************
-* EventNotification message
-****************************************************************************/
-
-/* EventNotification Request message */
-#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4)
-
-typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U32 Reserved5; /* 0x0C */
- U32 Reserved6; /* 0x10 */
- U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */
- U16 SASBroadcastPrimitiveMasks; /* 0x24 */
- U16 SASNotifyPrimitiveMasks; /* 0x26 */
- U32 Reserved8; /* 0x28 */
-} MPI2_EVENT_NOTIFICATION_REQUEST,
- MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST,
- Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t;
-
-
-/* EventNotification Reply message */
-typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
-{
- U16 EventDataLength; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 AckRequired; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U16 Event; /* 0x14 */
- U16 Reserved4; /* 0x16 */
- U32 EventContext; /* 0x18 */
- U32 EventData[1]; /* 0x1C */
-} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY,
- Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t;
-
-/* AckRequired */
-#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00)
-#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01)
-
-/* Event */
-#define MPI2_EVENT_LOG_DATA (0x0001)
-#define MPI2_EVENT_STATE_CHANGE (0x0002)
-#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005)
-#define MPI2_EVENT_EVENT_CHANGE (0x000A)
-#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */
-#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F)
-#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014)
-#define MPI2_EVENT_SAS_DISCOVERY (0x0016)
-#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017)
-#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018)
-#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019)
-#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C)
-#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D)
-#define MPI2_EVENT_IR_VOLUME (0x001E)
-#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F)
-#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020)
-#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021)
-#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022)
-#define MPI2_EVENT_GPIO_INTERRUPT (0x0023)
-#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024)
-#define MPI2_EVENT_SAS_QUIESCE (0x0025)
-#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026)
-#define MPI2_EVENT_TEMP_THRESHOLD (0x0027)
-#define MPI2_EVENT_HOST_MESSAGE (0x0028)
-#define MPI2_EVENT_MIN_PRODUCT_SPECIFIC (0x006E)
-#define MPI2_EVENT_MAX_PRODUCT_SPECIFIC (0x007F)
-
-/* Log Entry Added Event data */
-
-/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */
-#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C)
-
-typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED
-{
- U64 TimeStamp; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U16 LogSequence; /* 0x0C */
- U16 LogEntryQualifier; /* 0x0E */
- U8 VP_ID; /* 0x10 */
- U8 VF_ID; /* 0x11 */
- U16 Reserved2; /* 0x12 */
- U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */
-} MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED,
- Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t;
-
-/* GPIO Interrupt Event data */
-
-typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT {
- U8 GPIONum; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_EVENT_DATA_GPIO_INTERRUPT,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT,
- Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t;
-
-/* Temperature Threshold Event data */
-
-typedef struct _MPI2_EVENT_DATA_TEMPERATURE {
- U16 Status; /* 0x00 */
- U8 SensorNum; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U16 CurrentTemperature; /* 0x04 */
- U16 Reserved2; /* 0x06 */
- U32 Reserved3; /* 0x08 */
- U32 Reserved4; /* 0x0C */
-} MPI2_EVENT_DATA_TEMPERATURE,
-MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE,
-Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t;
-
-/* Temperature Threshold Event data Status bits */
-#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008)
-#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004)
-#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002)
-#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001)
-
-
-/* Host Message Event data */
-
-typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE {
- U8 SourceVF_ID; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
- U32 HostData[1]; /* 0x08 */
-} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE,
-Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t;
-
-
-/* Hard Reset Received Event data */
-
-typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED
-{
- U8 Reserved1; /* 0x00 */
- U8 Port; /* 0x01 */
- U16 Reserved2; /* 0x02 */
-} MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED,
- Mpi2EventDataHardResetReceived_t,
- MPI2_POINTER pMpi2EventDataHardResetReceived_t;
-
-/* Task Set Full Event data */
-/* this event is obsolete */
-
-typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL
-{
- U16 DevHandle; /* 0x00 */
- U16 CurrentDepth; /* 0x02 */
-} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL,
- Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t;
-
-
-/* SAS Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
-{
- U16 TaskTag; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U8 ASC; /* 0x04 */
- U8 ASCQ; /* 0x05 */
- U16 DevHandle; /* 0x06 */
- U32 Reserved2; /* 0x08 */
- U64 SASAddress; /* 0x0C */
- U8 LUN[8]; /* 0x14 */
-} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE,
- Mpi2EventDataSasDeviceStatusChange_t,
- MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;
-
-/* SAS Device Status Change Event data ReasonCode values */
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12)
-
-
-/* Integrated RAID Operation Status Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS
-{
- U16 VolDevHandle; /* 0x00 */
- U16 Reserved1; /* 0x02 */
- U8 RAIDOperation; /* 0x04 */
- U8 PercentComplete; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U32 ElapsedSeconds; /* 0x08 */
-} MPI2_EVENT_DATA_IR_OPERATION_STATUS,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS,
- Mpi2EventDataIrOperationStatus_t,
- MPI2_POINTER pMpi2EventDataIrOperationStatus_t;
-
-/* Integrated RAID Operation Status Event data RAIDOperation values */
-#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00)
-#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02)
-#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03)
-#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04)
-
-
-/* Integrated RAID Volume Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_VOLUME
-{
- U16 VolDevHandle; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 NewValue; /* 0x04 */
- U32 PreviousValue; /* 0x08 */
-} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME,
- Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t;
-
-/* Integrated RAID Volume Event data ReasonCode values */
-#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01)
-#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02)
-#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03)
-
-
-/* Integrated RAID Physical Disk Event data */
-
-typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK
-{
- U16 Reserved1; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysDiskNum; /* 0x03 */
- U16 PhysDiskDevHandle; /* 0x04 */
- U16 Reserved2; /* 0x06 */
- U16 Slot; /* 0x08 */
- U16 EnclosureHandle; /* 0x0A */
- U32 NewValue; /* 0x0C */
- U32 PreviousValue; /* 0x10 */
-} MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK,
- Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t;
-
-/* Integrated RAID Physical Disk Event data ReasonCode values */
-#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01)
-#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02)
-#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03)
-
-
-/* Integrated RAID Configuration Change List Event data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumElements at runtime.
- */
-#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT
-#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1)
-#endif
-
-typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT
-{
- U16 ElementFlags; /* 0x00 */
- U16 VolDevHandle; /* 0x02 */
- U8 ReasonCode; /* 0x04 */
- U8 PhysDiskNum; /* 0x05 */
- U16 PhysDiskDevHandle; /* 0x06 */
-} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT,
- Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t;
-
-/* IR Configuration Change List Event data ElementFlags values */
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001)
-#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002)
-
-/* IR Configuration Change List Event data ReasonCode values */
-#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01)
-#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02)
-#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03)
-#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04)
-#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05)
-#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06)
-#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07)
-#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08)
-#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09)
-
-typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST
-{
- U8 NumElements; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 Reserved2; /* 0x02 */
- U8 ConfigNum; /* 0x03 */
- U32 Flags; /* 0x04 */
- MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */
-} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST,
- Mpi2EventDataIrConfigChangeList_t,
- MPI2_POINTER pMpi2EventDataIrConfigChangeList_t;
-
-/* IR Configuration Change List Event data Flags values */
-#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001)
-
-
-/* SAS Discovery Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY
-{
- U8 Flags; /* 0x00 */
- U8 ReasonCode; /* 0x01 */
- U8 PhysicalPort; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 DiscoveryStatus; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_DISCOVERY,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY,
- Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t;
-
-/* SAS Discovery Event data Flags values */
-#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02)
-#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01)
-
-/* SAS Discovery Event data ReasonCode values */
-#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01)
-#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02)
-
-/* SAS Discovery Event data DiscoveryStatus values */
-#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000)
-#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000)
-#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000)
-#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000)
-#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000)
-#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000)
-#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000)
-#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800)
-#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400)
-#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080)
-#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040)
-#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020)
-#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010)
-#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004)
-#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002)
-#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001)
-
-
-/* SAS Broadcast Primitive Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE
-{
- U8 PhyNum; /* 0x00 */
- U8 Port; /* 0x01 */
- U8 PortWidth; /* 0x02 */
- U8 Primitive; /* 0x03 */
-} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE,
- Mpi2EventDataSasBroadcastPrimitive_t,
- MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t;
-
-/* defines for the Primitive field */
-#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01)
-#define MPI2_EVENT_PRIMITIVE_SES (0x02)
-#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03)
-#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04)
-#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05)
-#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06)
-#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07)
-#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08)
-
-/* SAS Notify Primitive Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE {
- U8 PhyNum; /* 0x00 */
- U8 Port; /* 0x01 */
- U8 Reserved1; /* 0x02 */
- U8 Primitive; /* 0x03 */
-} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
-MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE,
-Mpi2EventDataSasNotifyPrimitive_t,
-MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t;
-
-/* defines for the Primitive field */
-#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01)
-#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02)
-#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03)
-#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04)
-
-
-/* SAS Initiator Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE
-{
- U8 ReasonCode; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U16 DevHandle; /* 0x02 */
- U64 SASAddress; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE,
- Mpi2EventDataSasInitDevStatusChange_t,
- MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t;
-
-/* SAS Initiator Device Status Change event ReasonCode values */
-#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01)
-#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02)
-
-
-/* SAS Initiator Device Table Overflow Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW
-{
- U16 MaxInit; /* 0x00 */
- U16 CurrentInit; /* 0x02 */
- U64 SASAddress; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW,
- Mpi2EventDataSasInitTableOverflow_t,
- MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t;
-
-
-/* SAS Topology Change List Event data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumEntries at runtime.
- */
-#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT
-#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1)
-#endif
-
-typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY
-{
- U16 AttachedDevHandle; /* 0x00 */
- U8 LinkRate; /* 0x02 */
- U8 PhyStatus; /* 0x03 */
-} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY,
- Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t;
-
-typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST
-{
- U16 EnclosureHandle; /* 0x00 */
- U16 ExpanderDevHandle; /* 0x02 */
- U8 NumPhys; /* 0x04 */
- U8 Reserved1; /* 0x05 */
- U16 Reserved2; /* 0x06 */
- U8 NumEntries; /* 0x08 */
- U8 StartPhyNum; /* 0x09 */
- U8 ExpStatus; /* 0x0A */
- U8 PhysicalPort; /* 0x0B */
- MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/
-} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST,
- Mpi2EventDataSasTopologyChangeList_t,
- MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t;
-
-/* values for the ExpStatus field */
-#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00)
-#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01)
-#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02)
-#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03)
-#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04)
-
-/* defines for the LinkRate field */
-#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0)
-#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4)
-#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F)
-#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0)
-
-#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00)
-#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01)
-#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02)
-#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03)
-#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04)
-#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05)
-#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09)
-#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A)
-
-/* values for the PhyStatus field */
-#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80)
-#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10)
-/* values for the PhyStatus ReasonCode sub-field */
-#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F)
-#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01)
-#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02)
-#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03)
-#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04)
-#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05)
-
-
-/* SAS Enclosure Device Status Change Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
-{
- U16 EnclosureHandle; /* 0x00 */
- U8 ReasonCode; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U64 EnclosureLogicalID; /* 0x04 */
- U16 NumSlots; /* 0x0C */
- U16 StartSlot; /* 0x0E */
- U32 PhyBits; /* 0x10 */
-} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE,
- Mpi2EventDataSasEnclDevStatusChange_t,
- MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t;
-
-/* SAS Enclosure Device Status Change event ReasonCode values */
-#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01)
-#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02)
-
-
-/* SAS PHY Counter Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
- U64 TimeStamp; /* 0x00 */
- U32 Reserved1; /* 0x08 */
- U8 PhyEventCode; /* 0x0C */
- U8 PhyNum; /* 0x0D */
- U16 Reserved2; /* 0x0E */
- U32 PhyEventInfo; /* 0x10 */
- U8 CounterType; /* 0x14 */
- U8 ThresholdWindow; /* 0x15 */
- U8 TimeUnits; /* 0x16 */
- U8 Reserved3; /* 0x17 */
- U32 EventThreshold; /* 0x18 */
- U16 ThresholdFlags; /* 0x1C */
- U16 Reserved4; /* 0x1E */
-} MPI2_EVENT_DATA_SAS_PHY_COUNTER,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER,
- Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t;
-
-/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the
- * PhyEventCode field
- * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the
- * CounterType field
- * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the
- * TimeUnits field
- * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the
- * ThresholdFlags field
- * */
-
-
-/* SAS Quiesce Event data */
-
-typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE {
- U8 ReasonCode; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
-} MPI2_EVENT_DATA_SAS_QUIESCE,
- MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE,
- Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t;
-
-/* SAS Quiesce Event data ReasonCode values */
-#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01)
-#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02)
-
-
-/* Host Based Discovery Phy Event data */
-
-typedef struct _MPI2_EVENT_HBD_PHY_SAS {
- U8 Flags; /* 0x00 */
- U8 NegotiatedLinkRate; /* 0x01 */
- U8 PhyNum; /* 0x02 */
- U8 PhysicalPort; /* 0x03 */
- U32 Reserved1; /* 0x04 */
- U8 InitialFrame[28]; /* 0x08 */
-} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS,
- Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t;
-
-/* values for the Flags field */
-#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02)
-#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01)
-
-/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for
- * the NegotiatedLinkRate field */
-
-typedef union _MPI2_EVENT_HBD_DESCRIPTOR {
- MPI2_EVENT_HBD_PHY_SAS Sas;
-} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR,
- Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t;
-
-typedef struct _MPI2_EVENT_DATA_HBD_PHY {
- U8 DescriptorType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Reserved3; /* 0x04 */
- MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */
-} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY,
- Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t;
-
-/* values for the DescriptorType field */
-#define MPI2_EVENT_HBD_DT_SAS (0x01)
-
-
-
-/****************************************************************************
-* EventAck message
-****************************************************************************/
-
-/* EventAck Request message */
-typedef struct _MPI2_EVENT_ACK_REQUEST
-{
- U16 Reserved1; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Event; /* 0x0C */
- U16 Reserved5; /* 0x0E */
- U32 EventContext; /* 0x10 */
-} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST,
- Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t;
-
-
-/* EventAck Reply message */
-typedef struct _MPI2_EVENT_ACK_REPLY
-{
- U16 Reserved1; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY,
- Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t;
-
-
-/****************************************************************************
-* SendHostMessage message
-****************************************************************************/
-
-/* SendHostMessage Request message */
-typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST {
- U16 HostDataLength; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U8 Reserved4; /* 0x0C */
- U8 DestVF_ID; /* 0x0D */
- U16 Reserved5; /* 0x0E */
- U32 Reserved6; /* 0x10 */
- U32 Reserved7; /* 0x14 */
- U32 Reserved8; /* 0x18 */
- U32 Reserved9; /* 0x1C */
- U32 Reserved10; /* 0x20 */
- U32 HostData[1]; /* 0x24 */
-} MPI2_SEND_HOST_MESSAGE_REQUEST,
-MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST,
-Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t;
-
-
-/* SendHostMessage Reply message */
-typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY {
- U16 HostDataLength; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved1; /* 0x04 */
- U8 Reserved2; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY,
-Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t;
-
-
-/****************************************************************************
-* FWDownload message
-****************************************************************************/
-
-/* FWDownload Request message */
-typedef struct _MPI2_FW_DOWNLOAD_REQUEST
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U32 TotalImageSize; /* 0x0C */
- U32 Reserved5; /* 0x10 */
- MPI2_MPI_SGE_UNION SGL; /* 0x14 */
-} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST,
- Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest;
-
-#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01)
-
-#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01)
-#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02)
-#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09)
-#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A)
-#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
-#define MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY (0x0C)
-#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0)
-
-/* FWDownload TransactionContext Element */
-typedef struct _MPI2_FW_DOWNLOAD_TCSGE
-{
- U8 Reserved1; /* 0x00 */
- U8 ContextSize; /* 0x01 */
- U8 DetailsLength; /* 0x02 */
- U8 Flags; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 ImageOffset; /* 0x08 */
- U32 ImageSize; /* 0x0C */
-} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE,
- Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t;
-
-/* FWDownload Reply message */
-typedef struct _MPI2_FW_DOWNLOAD_REPLY
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY,
- Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t;
-
-
-/****************************************************************************
-* FWUpload message
-****************************************************************************/
-
-/* FWUpload Request message */
-typedef struct _MPI2_FW_UPLOAD_REQUEST
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U32 Reserved5; /* 0x0C */
- U32 Reserved6; /* 0x10 */
- MPI2_MPI_SGE_UNION SGL; /* 0x14 */
-} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST,
- Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t;
-
-#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00)
-#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01)
-#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02)
-#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05)
-#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06)
-#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07)
-#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08)
-#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09)
-#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A)
-#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B)
-
-typedef struct _MPI2_FW_UPLOAD_TCSGE
-{
- U8 Reserved1; /* 0x00 */
- U8 ContextSize; /* 0x01 */
- U8 DetailsLength; /* 0x02 */
- U8 Flags; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 ImageOffset; /* 0x08 */
- U32 ImageSize; /* 0x0C */
-} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE,
- Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t;
-
-/* FWUpload Reply message */
-typedef struct _MPI2_FW_UPLOAD_REPLY
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 ActualImageSize; /* 0x14 */
-} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY,
- Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t;
-
-
-/* FW Image Header */
-typedef struct _MPI2_FW_IMAGE_HEADER
-{
- U32 Signature; /* 0x00 */
- U32 Signature0; /* 0x04 */
- U32 Signature1; /* 0x08 */
- U32 Signature2; /* 0x0C */
- MPI2_VERSION_UNION MPIVersion; /* 0x10 */
- MPI2_VERSION_UNION FWVersion; /* 0x14 */
- MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */
- MPI2_VERSION_UNION PackageVersion; /* 0x1C */
- U16 VendorID; /* 0x20 */
- U16 ProductID; /* 0x22 */
- U16 ProtocolFlags; /* 0x24 */
- U16 Reserved26; /* 0x26 */
- U32 IOCCapabilities; /* 0x28 */
- U32 ImageSize; /* 0x2C */
- U32 NextImageHeaderOffset; /* 0x30 */
- U32 Checksum; /* 0x34 */
- U32 Reserved38; /* 0x38 */
- U32 Reserved3C; /* 0x3C */
- U32 Reserved40; /* 0x40 */
- U32 Reserved44; /* 0x44 */
- U32 Reserved48; /* 0x48 */
- U32 Reserved4C; /* 0x4C */
- U32 Reserved50; /* 0x50 */
- U32 Reserved54; /* 0x54 */
- U32 Reserved58; /* 0x58 */
- U32 Reserved5C; /* 0x5C */
- U32 Reserved60; /* 0x60 */
- U32 FirmwareVersionNameWhat; /* 0x64 */
- U8 FirmwareVersionName[32]; /* 0x68 */
- U32 VendorNameWhat; /* 0x88 */
- U8 VendorName[32]; /* 0x8C */
- U32 PackageNameWhat; /* 0x88 */
- U8 PackageName[32]; /* 0x8C */
- U32 ReservedD0; /* 0xD0 */
- U32 ReservedD4; /* 0xD4 */
- U32 ReservedD8; /* 0xD8 */
- U32 ReservedDC; /* 0xDC */
- U32 ReservedE0; /* 0xE0 */
- U32 ReservedE4; /* 0xE4 */
- U32 ReservedE8; /* 0xE8 */
- U32 ReservedEC; /* 0xEC */
- U32 ReservedF0; /* 0xF0 */
- U32 ReservedF4; /* 0xF4 */
- U32 ReservedF8; /* 0xF8 */
- U32 ReservedFC; /* 0xFC */
-} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER,
- Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t;
-
-/* Signature field */
-#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00)
-#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000)
-#define MPI2_FW_HEADER_SIGNATURE (0xEA000000)
-
-/* Signature0 field */
-#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04)
-#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A)
-
-/* Signature1 field */
-#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08)
-#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5)
-
-/* Signature2 field */
-#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C)
-#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA)
-
-
-/* defines for using the ProductID field */
-#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000)
-#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000)
-
-#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00)
-#define MPI2_FW_HEADER_PID_PROD_A (0x0000)
-#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200)
-#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700)
-
-
-#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF)
-/* SAS */
-#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013)
-#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014)
-
-/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */
-
-/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */
-
-
-#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C)
-#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30)
-#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64)
-
-#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840)
-
-#define MPI2_FW_HEADER_SIZE (0x100)
-
-
-/* Extended Image Header */
-typedef struct _MPI2_EXT_IMAGE_HEADER
-
-{
- U8 ImageType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 Checksum; /* 0x04 */
- U32 ImageSize; /* 0x08 */
- U32 NextImageHeaderOffset; /* 0x0C */
- U32 PackageVersion; /* 0x10 */
- U32 Reserved3; /* 0x14 */
- U32 Reserved4; /* 0x18 */
- U32 Reserved5; /* 0x1C */
- U8 IdentifyString[32]; /* 0x20 */
-} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER,
- Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t;
-
-/* useful offsets */
-#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00)
-#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08)
-#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C)
-
-#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40)
-
-/* defines for the ImageType field */
-#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00)
-#define MPI2_EXT_IMAGE_TYPE_FW (0x01)
-#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03)
-#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04)
-#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05)
-#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06)
-#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07)
-#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08)
-#define MPI2_EXT_IMAGE_TYPE_ENCRYPTED_HASH (0x09)
-#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF)
-#define MPI2_EXT_IMAGE_TYPE_MAX \
- (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */
-
-
-
-/* FLASH Layout Extended Image Data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check RegionsPerLayout at runtime.
- */
-#ifndef MPI2_FLASH_NUMBER_OF_REGIONS
-#define MPI2_FLASH_NUMBER_OF_REGIONS (1)
-#endif
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumberOfLayouts at runtime.
- */
-#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS
-#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1)
-#endif
-
-typedef struct _MPI2_FLASH_REGION
-{
- U8 RegionType; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 RegionOffset; /* 0x04 */
- U32 RegionSize; /* 0x08 */
- U32 Reserved3; /* 0x0C */
-} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION,
- Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t;
-
-typedef struct _MPI2_FLASH_LAYOUT
-{
- U32 FlashSize; /* 0x00 */
- U32 Reserved1; /* 0x04 */
- U32 Reserved2; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */
-} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT,
- Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t;
-
-typedef struct _MPI2_FLASH_LAYOUT_DATA
-{
- U8 ImageRevision; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 SizeOfRegion; /* 0x02 */
- U8 Reserved2; /* 0x03 */
- U16 NumberOfLayouts; /* 0x04 */
- U16 RegionsPerLayout; /* 0x06 */
- U16 MinimumSectorAlignment; /* 0x08 */
- U16 Reserved3; /* 0x0A */
- U32 Reserved4; /* 0x0C */
- MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */
-} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA,
- Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t;
-
-/* defines for the RegionType field */
-#define MPI2_FLASH_REGION_UNUSED (0x00)
-#define MPI2_FLASH_REGION_FIRMWARE (0x01)
-#define MPI2_FLASH_REGION_BIOS (0x02)
-#define MPI2_FLASH_REGION_NVDATA (0x03)
-#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05)
-#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06)
-#define MPI2_FLASH_REGION_CONFIG_1 (0x07)
-#define MPI2_FLASH_REGION_CONFIG_2 (0x08)
-#define MPI2_FLASH_REGION_MEGARAID (0x09)
-#define MPI2_FLASH_REGION_INIT (0x0A)
-
-/* ImageRevision */
-#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00)
-
-
-
-/* Supported Devices Extended Image Data */
-
-/*
- * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
- * one and check NumberOfDevices at runtime.
- */
-#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES
-#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1)
-#endif
-
-typedef struct _MPI2_SUPPORTED_DEVICE
-{
- U16 DeviceID; /* 0x00 */
- U16 VendorID; /* 0x02 */
- U16 DeviceIDMask; /* 0x04 */
- U16 Reserved1; /* 0x06 */
- U8 LowPCIRev; /* 0x08 */
- U8 HighPCIRev; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
-} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE,
- Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t;
-
-typedef struct _MPI2_SUPPORTED_DEVICES_DATA
-{
- U8 ImageRevision; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 NumberOfDevices; /* 0x02 */
- U8 Reserved2; /* 0x03 */
- U32 Reserved3; /* 0x04 */
- MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */
-} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA,
- Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t;
-
-/* ImageRevision */
-#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00)
-
-
-/* Init Extended Image Data */
-
-typedef struct _MPI2_INIT_IMAGE_FOOTER
-
-{
- U32 BootFlags; /* 0x00 */
- U32 ImageSize; /* 0x04 */
- U32 Signature0; /* 0x08 */
- U32 Signature1; /* 0x0C */
- U32 Signature2; /* 0x10 */
- U32 ResetVector; /* 0x14 */
-} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER,
- Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t;
-
-/* defines for the BootFlags field */
-#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00)
-
-/* defines for the ImageSize field */
-#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04)
-
-/* defines for the Signature0 field */
-#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08)
-#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA)
-
-/* defines for the Signature1 field */
-#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C)
-#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5)
-
-/* defines for the Signature2 field */
-#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10)
-#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A)
-
-/* Signature fields as individual bytes */
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A)
-
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5)
-
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA)
-#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A)
-
-/* defines for the ResetVector field */
-#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14)
-
-
-/* Encrypted Hash Extended Image Data */
-
-typedef struct _MPI25_ENCRYPTED_HASH_ENTRY {
- U8 HashImageType; /* 0x00 */
- U8 HashAlgorithm; /* 0x01 */
- U8 EncryptionAlgorithm; /* 0x02 */
- U8 Reserved1; /* 0x03 */
- U32 Reserved2; /* 0x04 */
- U32 EncryptedHash[1]; /* 0x08 */
-} MPI25_ENCRYPTED_HASH_ENTRY, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_ENTRY,
-Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t;
-
-/* values for HashImageType */
-#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00)
-#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01)
-#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02)
-
-/* values for HashAlgorithm */
-#define MPI25_HASH_ALGORITHM_UNUSED (0x00)
-#define MPI25_HASH_ALGORITHM_SHA256 (0x01)
-
-/* values for EncryptionAlgorithm */
-#define MPI25_ENCRYPTION_ALG_UNUSED (0x00)
-#define MPI25_ENCRYPTION_ALG_RSA256 (0x01)
-
-typedef struct _MPI25_ENCRYPTED_HASH_DATA {
- U8 ImageVersion; /* 0x00 */
- U8 NumHash; /* 0x01 */
- U16 Reserved1; /* 0x02 */
- U32 Reserved2; /* 0x04 */
- MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /* 0x08 */
-} MPI25_ENCRYPTED_HASH_DATA, MPI2_POINTER PTR_MPI25_ENCRYPTED_HASH_DATA,
-Mpi25EncryptedHashData_t, MPI2_POINTER pMpi25EncryptedHashData_t;
-
-/****************************************************************************
-* PowerManagementControl message
-****************************************************************************/
-
-/* PowerManagementControl Request message */
-typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST {
- U8 Feature; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U8 Parameter1; /* 0x0C */
- U8 Parameter2; /* 0x0D */
- U8 Parameter3; /* 0x0E */
- U8 Parameter4; /* 0x0F */
- U32 Reserved5; /* 0x10 */
- U32 Reserved6; /* 0x14 */
-} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST,
- Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t;
-
-/* defines for the Feature field */
-#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01)
-#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02)
-#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */
-#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04)
-#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF)
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */
-/* Parameter1 contains a PHY number */
-/* Parameter2 indicates power condition action using these defines */
-#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01)
-#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02)
-#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03)
-/* Parameter3 and Parameter4 are reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION
- * Feature */
-/* Parameter1 contains SAS port width modulation group number */
-/* Parameter2 indicates IOC action using these defines */
-#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01)
-#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02)
-#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03)
-/* Parameter3 indicates desired modulation level using these defines */
-#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00)
-#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01)
-#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02)
-#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03)
-/* Parameter4 is reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */
-/* Parameter1 indicates desired PCIe link speed using these defines */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */
-/* Parameter2 indicates desired PCIe link width using these defines */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */
-#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */
-/* Parameter3 and Parameter4 are reserved */
-
-/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */
-/* Parameter1 indicates desired IOC hardware clock speed using these defines */
-#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01)
-#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02)
-#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04)
-#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08)
-/* Parameter2, Parameter3, and Parameter4 are reserved */
-
-
-/* PowerManagementControl Reply message */
-typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY {
- U8 Feature; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY,
- Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
deleted file mode 100644
index 7efa58f..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_raid.h
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_raid.h
- * Title: MPI Integrated RAID messages and structures
- * Creation Date: April 26, 2007
- *
- * mpi2_raid.h Version: 02.00.10
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 08-31-07 02.00.01 Modifications to RAID Action request and reply,
- * including the Actions and ActionData.
- * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
- * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that
- * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT
- * can be sized by the build environment.
- * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of
- * VolumeCreationFlags and marked the old one as obsolete.
- * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define.
- * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with
- * related structures and defines.
- * Added product-specific range to RAID Action values.
- * 02-06-12 02.00.08 Added MPI2_RAID_ACTION_PHYSDISK_HIDDEN.
- * 07-26-12 02.00.09 Added ElapsedSeconds field to MPI2_RAID_VOL_INDICATOR.
- * Added MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID define.
- * 04-17-13 02.00.10 Added MPI25_RAID_ACTION_ADATA_ALLOW_PI.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_RAID_H
-#define MPI2_RAID_H
-
-/*****************************************************************************
-*
-* Integrated RAID Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* RAID Action messages
-****************************************************************************/
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_CREATE_VOLUME action */
-#define MPI25_RAID_ACTION_ADATA_ALLOW_PI (0x80000000)
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */
-#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000)
-#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001)
-
-/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */
-#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001)
-
-/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */
-typedef struct _MPI2_RAID_ACTION_RATE_DATA
-{
- U8 RateToChange; /* 0x00 */
- U8 RateOrMode; /* 0x01 */
- U16 DataScrubDuration; /* 0x02 */
-} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA,
- Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t;
-
-#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00)
-#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01)
-#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02)
-
-/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */
-typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION
-{
- U8 RAIDFunction; /* 0x00 */
- U8 Flags; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_START_RAID_FUNCTION,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION,
- Mpi2RaidActionStartRaidFunction_t,
- MPI2_POINTER pMpi2RaidActionStartRaidFunction_t;
-
-/* defines for the RAIDFunction field */
-#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00)
-#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02)
-
-/* defines for the Flags field */
-#define MPI2_RAID_ACTION_START_NEW (0x00)
-#define MPI2_RAID_ACTION_START_RESUME (0x01)
-
-/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */
-typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION
-{
- U8 RAIDFunction; /* 0x00 */
- U8 Flags; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION,
- Mpi2RaidActionStopRaidFunction_t,
- MPI2_POINTER pMpi2RaidActionStopRaidFunction_t;
-
-/* defines for the RAIDFunction field */
-#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00)
-#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01)
-#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02)
-
-/* defines for the Flags field */
-#define MPI2_RAID_ACTION_STOP_ABORT (0x00)
-#define MPI2_RAID_ACTION_STOP_PAUSE (0x01)
-
-/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */
-typedef struct _MPI2_RAID_ACTION_HOT_SPARE
-{
- U8 HotSparePool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 DevHandle; /* 0x02 */
-} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE,
- Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t;
-
-/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */
-typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE
-{
- U8 Flags; /* 0x00 */
- U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */
- U16 Reserved1; /* 0x02 */
-} MPI2_RAID_ACTION_FW_UPDATE_MODE,
- MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE,
- Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t;
-
-/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */
-#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00)
-#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01)
-
-typedef union _MPI2_RAID_ACTION_DATA
-{
- U32 Word;
- MPI2_RAID_ACTION_RATE_DATA Rates;
- MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction;
- MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction;
- MPI2_RAID_ACTION_HOT_SPARE HotSpare;
- MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode;
-} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA,
- Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t;
-
-
-/* RAID Action Request Message */
-typedef struct _MPI2_RAID_ACTION_REQUEST
-{
- U8 Action; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 VolDevHandle; /* 0x04 */
- U8 PhysDiskNum; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U32 Reserved3; /* 0x0C */
- MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */
- MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */
-} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST,
- Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t;
-
-/* RAID Action request Action values */
-
-#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01)
-#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02)
-#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03)
-#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04)
-#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05)
-#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A)
-#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B)
-#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F)
-#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11)
-#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15)
-#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17)
-#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18)
-#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19)
-#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C)
-#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D)
-#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E)
-#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20)
-#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21)
-#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22)
-#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23)
-#define MPI2_RAID_ACTION_PHYSDISK_HIDDEN (0x24)
-#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80)
-#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF)
-
-/* RAID Volume Creation Structure */
-
-/*
- * The following define can be customized for the targeted product.
- */
-#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS
-#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1)
-#endif
-
-typedef struct _MPI2_RAID_VOLUME_PHYSDISK
-{
- U8 RAIDSetNum; /* 0x00 */
- U8 PhysDiskMap; /* 0x01 */
- U16 PhysDiskDevHandle; /* 0x02 */
-} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK,
- Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t;
-
-/* defines for the PhysDiskMap field */
-#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01)
-#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02)
-
-typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT
-{
- U8 NumPhysDisks; /* 0x00 */
- U8 VolumeType; /* 0x01 */
- U16 Reserved1; /* 0x02 */
- U32 VolumeCreationFlags; /* 0x04 */
- U32 VolumeSettings; /* 0x08 */
- U8 Reserved2; /* 0x0C */
- U8 ResyncRate; /* 0x0D */
- U16 DataScrubDuration; /* 0x0E */
- U64 VolumeMaxLBA; /* 0x10 */
- U32 StripeSize; /* 0x18 */
- U8 Name[16]; /* 0x1C */
- MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */
-} MPI2_RAID_VOLUME_CREATION_STRUCT,
- MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT,
- Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t;
-
-/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */
-
-/* defines for the VolumeCreationFlags field */
-#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000)
-#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004)
-#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002)
-#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001)
-/* The following is an obsolete define.
- * It must be shifted left 24 bits in order to set the proper bit.
- */
-#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80)
-
-
-/* RAID Online Capacity Expansion Structure */
-
-typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION
-{
- U32 Flags; /* 0x00 */
- U16 DevHandle0; /* 0x04 */
- U16 Reserved1; /* 0x06 */
- U16 DevHandle1; /* 0x08 */
- U16 Reserved2; /* 0x0A */
-} MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
- MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION,
- Mpi2RaidOnlineCapacityExpansion_t,
- MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t;
-
-/* RAID Compatibility Input Structure */
-
-typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT {
- U16 SourceDevHandle; /* 0x00 */
- U16 CandidateDevHandle; /* 0x02 */
- U32 Flags; /* 0x04 */
- U32 Reserved1; /* 0x08 */
- U32 Reserved2; /* 0x0C */
-} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
-MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT,
-Mpi2RaidCompatibilityInputStruct_t,
-MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t;
-
-/* defines for RAID Compatibility Structure Flags field */
-#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002)
-#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001)
-
-
-/* RAID Volume Indicator Structure */
-
-typedef struct _MPI2_RAID_VOL_INDICATOR
-{
- U64 TotalBlocks; /* 0x00 */
- U64 BlocksRemaining; /* 0x08 */
- U32 Flags; /* 0x10 */
- U32 ElapsedSeconds; /* 0x14 */
-} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR,
- Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t;
-
-/* defines for RAID Volume Indicator Flags field */
-#define MPI2_RAID_VOL_FLAGS_ELAPSED_SECONDS_VALID (0x80000000)
-
-#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F)
-#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000)
-#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001)
-#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002)
-#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003)
-#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004)
-
-/* RAID Compatibility Result Structure */
-
-typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT {
- U8 State; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U16 Reserved2; /* 0x02 */
- U32 GenericAttributes; /* 0x04 */
- U32 OEMSpecificAttributes; /* 0x08 */
- U32 Reserved3; /* 0x0C */
- U32 Reserved4; /* 0x10 */
-} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
-MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT,
-Mpi2RaidCompatibilityResultStruct_t,
-MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t;
-
-/* defines for RAID Compatibility Result Structure State field */
-#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00)
-#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01)
-
-/* defines for RAID Compatibility Result Structure GenericAttributes field */
-#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010)
-
-#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C)
-#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008)
-#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004)
-
-#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003)
-#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002)
-#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001)
-
-/* RAID Action Reply ActionData union */
-typedef union _MPI2_RAID_ACTION_REPLY_DATA
-{
- U32 Word[6];
- MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator;
- U16 VolDevHandle;
- U8 VolumeState;
- U8 PhysDiskNum;
- MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult;
-} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA,
- Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t;
-
-/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */
-
-
-/* RAID Action Reply Message */
-typedef struct _MPI2_RAID_ACTION_REPLY
-{
- U8 Action; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 VolDevHandle; /* 0x04 */
- U8 PhysDiskNum; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved2; /* 0x0A */
- U16 Reserved3; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */
-} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY,
- Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
deleted file mode 100644
index 45b6fa1..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_sas.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_sas.h
- * Title: MPI Serial Attached SCSI structures and definitions
- * Creation Date: February 9, 2007
- *
- * mpi2_sas.h Version: 02.00.05
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit
- * Control Request.
- * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
- * Request.
- * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST
- * to MPI2_SGE_IO_UNION since it supports chained SGLs.
- * 05-12-10 02.00.04 Modified some comments.
- * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_SAS_H
-#define MPI2_SAS_H
-
-/*
- * Values for SASStatus.
- */
-#define MPI2_SASSTATUS_SUCCESS (0x00)
-#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01)
-#define MPI2_SASSTATUS_INVALID_FRAME (0x02)
-#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03)
-#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04)
-#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05)
-#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06)
-#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07)
-#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08)
-#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09)
-#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A)
-#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B)
-#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C)
-#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D)
-#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E)
-#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F)
-#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10)
-#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11)
-#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12)
-#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13)
-#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14)
-
-
-/*
- * Values for the SAS DeviceInfo field used in SAS Device Status Change Event
- * data and SAS Configuration pages.
- */
-#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000)
-#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000)
-#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000)
-#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800)
-#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400)
-#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200)
-#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100)
-#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080)
-#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040)
-#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020)
-#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010)
-#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008)
-
-#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007)
-#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000)
-#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001)
-#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002)
-#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003)
-
-
-/*****************************************************************************
-*
-* SAS Messages
-*
-*****************************************************************************/
-
-/****************************************************************************
-* SMP Passthrough messages
-****************************************************************************/
-
-/* SMP Passthrough Request Message */
-typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST
-{
- U8 PassthroughFlags; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 RequestDataLength; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U64 SASAddress; /* 0x10 */
- U32 Reserved3; /* 0x18 */
- U32 Reserved4; /* 0x1C */
- MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */
-} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST,
- Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* SMP Passthrough Reply Message */
-typedef struct _MPI2_SMP_PASSTHROUGH_REPLY
-{
- U8 PassthroughFlags; /* 0x00 */
- U8 PhysicalPort; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 ResponseDataLength; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 SASStatus; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 Reserved3; /* 0x14 */
- U8 ResponseData[4]; /* 0x18 */
-} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY,
- Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80)
-
-/* values for SASStatus field are at the top of this file */
-
-
-/****************************************************************************
-* SATA Passthrough messages
-****************************************************************************/
-
-/* SATA Passthrough Request Message */
-typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST
-{
- U16 DevHandle; /* 0x00 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 PassthroughFlags; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U32 Reserved2; /* 0x0C */
- U32 Reserved3; /* 0x10 */
- U32 Reserved4; /* 0x14 */
- U32 DataLength; /* 0x18 */
- U8 CommandFIS[20]; /* 0x1C */
- MPI2_SGE_IO_UNION SGL; /* 0x30 */
-} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST,
- Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t;
-
-/* values for PassthroughFlags field */
-#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002)
-#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* SATA Passthrough Reply Message */
-typedef struct _MPI2_SATA_PASSTHROUGH_REPLY
-{
- U16 DevHandle; /* 0x00 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 PassthroughFlags; /* 0x04 */
- U8 SGLFlags; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved1; /* 0x0A */
- U8 Reserved2; /* 0x0C */
- U8 SASStatus; /* 0x0D */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 StatusFIS[20]; /* 0x14 */
- U32 StatusControlRegisters; /* 0x28 */
- U32 TransferCount; /* 0x2C */
-} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY,
- Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t;
-
-/* values for SASStatus field are at the top of this file */
-
-
-/****************************************************************************
-* SAS IO Unit Control messages
-****************************************************************************/
-
-/* SAS IO Unit Control Request Message */
-typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST
-{
- U8 Operation; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 DevHandle; /* 0x04 */
- U8 IOCParameter; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U8 PhyNum; /* 0x0E */
- U8 PrimFlags; /* 0x0F */
- U32 Primitive; /* 0x10 */
- U8 LookupMethod; /* 0x14 */
- U8 Reserved5; /* 0x15 */
- U16 SlotNumber; /* 0x16 */
- U64 LookupAddress; /* 0x18 */
- U32 IOCParameterValue; /* 0x20 */
- U32 Reserved7; /* 0x24 */
- U32 Reserved8; /* 0x28 */
-} MPI2_SAS_IOUNIT_CONTROL_REQUEST,
- MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST,
- Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t;
-
-/* values for the Operation field */
-#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02)
-#define MPI2_SAS_OP_PHY_LINK_RESET (0x06)
-#define MPI2_SAS_OP_PHY_HARD_RESET (0x07)
-#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08)
-#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A)
-#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B)
-#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C)
-#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D)
-#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E)
-#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F)
-#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14)
-#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15)
-#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80)
-
-/* values for the PrimFlags field */
-#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08)
-#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02)
-#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01)
-
-/* values for the LookupMethod field */
-#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01)
-#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02)
-#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03)
-
-
-/* SAS IO Unit Control Reply Message */
-typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY
-{
- U8 Operation; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 DevHandle; /* 0x04 */
- U8 IOCParameter; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved3; /* 0x0A */
- U16 Reserved4; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_SAS_IOUNIT_CONTROL_REPLY,
- MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY,
- Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t;
-
-
-#endif
-
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
deleted file mode 100644
index 659b8ac..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_tool.h
- * Title: MPI diagnostic tool structures and definitions
- * Creation Date: March 26, 2007
- *
- * mpi2_tool.h Version: 02.00.12
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
- * structures and defines.
- * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
- * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool.
- * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request
- * and reply messages.
- * Added MPI2_DIAG_BUF_TYPE_EXTENDED.
- * Incremented MPI2_DIAG_BUF_TYPE_COUNT.
- * 05-12-10 02.00.05 Added Diagnostic Data Upload tool.
- * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer
- * Post Request.
- * 05-25-11 02.00.07 Added Flags field and related defines to
- * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST.
- * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
- * it uses MPI Chain SGE as well as MPI Simple SGE.
- * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
- * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_TOOL_H
-#define MPI2_TOOL_H
-
-/*****************************************************************************
-*
-* Toolbox Messages
-*
-*****************************************************************************/
-
-/* defines for the Tools */
-#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
-#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
-#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02)
-#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
-#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
-#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
-#define MPI2_TOOLBOX_TEXT_DISPLAY_TOOL (0x07)
-
-
-/****************************************************************************
-* Toolbox reply
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_REPLY
-{
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY,
- Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t;
-
-
-/****************************************************************************
-* Toolbox Clean Tool request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST
-{
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U32 Flags; /* 0x0C */
- } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST,
- Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t;
-
-/* values for the Flags field */
-#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000)
-#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000)
-#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000)
-#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000)
-#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000)
-#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
-#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
-#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
-#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
-#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002)
-#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001)
-
-
-/****************************************************************************
-* Toolbox Memory Move request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */
-} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST,
- Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t;
-
-
-/****************************************************************************
-* Toolbox Diagnostic Data Upload request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U8 SGLFlags; /* 0x0C */
- U8 Reserved5; /* 0x0D */
- U16 Reserved6; /* 0x0E */
- U32 Flags; /* 0x10 */
- U32 DataLength; /* 0x14 */
- MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */
-} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
-MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST,
-Mpi2ToolboxDiagDataUploadRequest_t,
-MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t;
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER {
- U32 DiagDataLength; /* 00h */
- U8 FormatCode; /* 04h */
- U8 Reserved1; /* 05h */
- U16 Reserved2; /* 06h */
-} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER,
-Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t;
-
-
-/****************************************************************************
-* Toolbox ISTWI Read Write Tool
-****************************************************************************/
-
-/* Toolbox ISTWI Read Write Tool request message */
-typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U32 Reserved5; /* 0x0C */
- U32 Reserved6; /* 0x10 */
- U8 DevIndex; /* 0x14 */
- U8 Action; /* 0x15 */
- U8 SGLFlags; /* 0x16 */
- U8 Flags; /* 0x17 */
- U16 TxDataLength; /* 0x18 */
- U16 RxDataLength; /* 0x1A */
- U32 Reserved8; /* 0x1C */
- U32 Reserved9; /* 0x20 */
- U32 Reserved10; /* 0x24 */
- U32 Reserved11; /* 0x28 */
- U32 Reserved12; /* 0x2C */
- MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */
-} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
- MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
- Mpi2ToolboxIstwiReadWriteRequest_t,
- MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t;
-
-/* values for the Action field */
-#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01)
-#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02)
-#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03)
-#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10)
-#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
-#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-/* values for the Flags field */
-#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80)
-#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07)
-
-/* Toolbox ISTWI Read Write Tool reply message */
-typedef struct _MPI2_TOOLBOX_ISTWI_REPLY {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U8 DevIndex; /* 0x14 */
- U8 Action; /* 0x15 */
- U8 IstwiStatus; /* 0x16 */
- U8 Reserved6; /* 0x17 */
- U16 TxDataCount; /* 0x18 */
- U16 RxDataCount; /* 0x1A */
-} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY,
- Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t;
-
-
-/****************************************************************************
-* Toolbox Beacon Tool request
-****************************************************************************/
-
-typedef struct _MPI2_TOOLBOX_BEACON_REQUEST
-{
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U8 Reserved5; /* 0x0C */
- U8 PhysicalPort; /* 0x0D */
- U8 Reserved6; /* 0x0E */
- U8 Flags; /* 0x0F */
-} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST,
- Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t;
-
-/* values for the Flags field */
-#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00)
-#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
-
-
-/****************************************************************************
-* Toolbox Diagnostic CLI Tool
-****************************************************************************/
-
-#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C)
-
-/* MPI v2.0 Toolbox Diagnostic CLI Tool request message */
-typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U8 SGLFlags; /* 0x0C */
- U8 Reserved5; /* 0x0D */
- U16 Reserved6; /* 0x0E */
- U32 DataLength; /* 0x10 */
- U8 DiagnosticCliCommand
- [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */
- MPI2_MPI_SGE_IO_UNION SGL; /* 0x70 */
-} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
- MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
- Mpi2ToolboxDiagnosticCliRequest_t,
- MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
-
-/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */
-
-
-/* Toolbox Diagnostic CLI Tool reply message */
-typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 ReturnedDataLength; /* 0x14 */
-} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY,
- MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY,
- Mpi2ToolboxDiagnosticCliReply_t,
- MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t;
-
-
-/****************************************************************************
-* Toolbox Console Text Display Tool
-****************************************************************************/
-
-/* Toolbox Console Text Display Tool request message */
-typedef struct _MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST {
- U8 Tool; /* 0x00 */
- U8 Reserved1; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U8 Console; /* 0x0C */
- U8 Flags; /* 0x0D */
- U16 Reserved6; /* 0x0E */
- U8 TextToDisplay[4]; /* 0x10 */
-} MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
-MPI2_POINTER PTR_MPI2_TOOLBOX_TEXT_DISPLAY_REQUEST,
-Mpi2ToolboxTextDisplayRequest_t,
-MPI2_POINTER pMpi2ToolboxTextDisplayRequest_t;
-
-/* defines for the Console field */
-#define MPI2_TOOLBOX_CONSOLE_TYPE_MASK (0xF0)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_DEFAULT (0x00)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_UART (0x10)
-#define MPI2_TOOLBOX_CONSOLE_TYPE_ETHERNET (0x20)
-
-#define MPI2_TOOLBOX_CONSOLE_NUMBER_MASK (0x0F)
-
-/* defines for the Flags field */
-#define MPI2_TOOLBOX_CONSOLE_FLAG_TIMESTAMP (0x01)
-
-
-
-/*****************************************************************************
-*
-* Diagnostic Buffer Messages
-*
-*****************************************************************************/
-
-
-/****************************************************************************
-* Diagnostic Buffer Post request
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
-{
- U8 ExtendedType; /* 0x00 */
- U8 BufferType; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U64 BufferAddress; /* 0x0C */
- U32 BufferLength; /* 0x14 */
- U32 Reserved5; /* 0x18 */
- U32 Reserved6; /* 0x1C */
- U32 Flags; /* 0x20 */
- U32 ProductSpecific[23]; /* 0x24 */
-} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST,
- Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t;
-
-/* values for the ExtendedType field */
-#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02)
-
-/* values for the BufferType field */
-#define MPI2_DIAG_BUF_TYPE_TRACE (0x00)
-#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01)
-#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02)
-/* count of the number of buffer types */
-#define MPI2_DIAG_BUF_TYPE_COUNT (0x03)
-
-/* values for the Flags field */
-#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002)
-#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001)
-
-
-/****************************************************************************
-* Diagnostic Buffer Post reply
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_BUFFER_POST_REPLY
-{
- U8 ExtendedType; /* 0x00 */
- U8 BufferType; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
- U32 TransferLength; /* 0x14 */
-} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY,
- Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t;
-
-
-/****************************************************************************
-* Diagnostic Release request
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_RELEASE_REQUEST
-{
- U8 Reserved1; /* 0x00 */
- U8 BufferType; /* 0x01 */
- U8 ChainOffset; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
-} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST,
- Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t;
-
-
-/****************************************************************************
-* Diagnostic Buffer Post reply
-****************************************************************************/
-
-typedef struct _MPI2_DIAG_RELEASE_REPLY
-{
- U8 Reserved1; /* 0x00 */
- U8 BufferType; /* 0x01 */
- U8 MsgLength; /* 0x02 */
- U8 Function; /* 0x03 */
- U16 Reserved2; /* 0x04 */
- U8 Reserved3; /* 0x06 */
- U8 MsgFlags; /* 0x07 */
- U8 VP_ID; /* 0x08 */
- U8 VF_ID; /* 0x09 */
- U16 Reserved4; /* 0x0A */
- U16 Reserved5; /* 0x0C */
- U16 IOCStatus; /* 0x0E */
- U32 IOCLogInfo; /* 0x10 */
-} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY,
- Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t;
-
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/drivers/scsi/mpt2sas/mpi/mpi2_type.h
deleted file mode 100644
index 6b0dcdd..0000000
--- a/drivers/scsi/mpt2sas/mpi/mpi2_type.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2000-2014 LSI Corporation.
- *
- *
- * Name: mpi2_type.h
- * Title: MPI basic type definitions
- * Creation Date: August 16, 2006
- *
- * mpi2_type.h Version: 02.00.00
- *
- * Version History
- * ---------------
- *
- * Date Version Description
- * -------- -------- ------------------------------------------------------
- * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
- * --------------------------------------------------------------------------
- */
-
-#ifndef MPI2_TYPE_H
-#define MPI2_TYPE_H
-
-
-/*******************************************************************************
- * Define MPI2_POINTER if it hasn't already been defined. By default
- * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as
- * a far pointer by defining MPI2_POINTER as "far *" before this header file is
- * included.
- */
-#ifndef MPI2_POINTER
-#define MPI2_POINTER *
-#endif
-
-/* the basic types may have already been included by mpi_type.h */
-#ifndef MPI_TYPE_H
-/*****************************************************************************
-*
-* Basic Types
-*
-*****************************************************************************/
-
-typedef u8 U8;
-typedef __le16 U16;
-typedef __le32 U32;
-typedef __le64 U64 __attribute__((aligned(4)));
-
-/*****************************************************************************
-*
-* Pointer Types
-*
-*****************************************************************************/
-
-typedef U8 *PU8;
-typedef U16 *PU16;
-typedef U32 *PU32;
-typedef U64 *PU64;
-
-#endif
-
-#endif
-
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
deleted file mode 100644
index c167911..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ /dev/null
@@ -1,4899 +0,0 @@
-/*
- * This is the Fusion MPT base driver providing common API layer interface
- * for access to MPT (Message Passing Technology) firmware.
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kdev_t.h>
-#include <linux/blkdev.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/dma-mapping.h>
-#include <linux/sort.h>
-#include <linux/io.h>
-#include <linux/time.h>
-#include <linux/kthread.h>
-#include <linux/aer.h>
-
-#include "mpt2sas_base.h"
-
-static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
-
-#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-
-#define MAX_HBA_QUEUE_DEPTH 30000
-#define MAX_CHAIN_DEPTH 100000
-static int max_queue_depth = -1;
-module_param(max_queue_depth, int, 0);
-MODULE_PARM_DESC(max_queue_depth, " max controller queue depth ");
-
-static int max_sgl_entries = -1;
-module_param(max_sgl_entries, int, 0);
-MODULE_PARM_DESC(max_sgl_entries, " max sg entries ");
-
-static int msix_disable = -1;
-module_param(msix_disable, int, 0);
-MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)");
-
-static int max_msix_vectors = -1;
-module_param(max_msix_vectors, int, 0);
-MODULE_PARM_DESC(max_msix_vectors, " max msix vectors ");
-
-static int mpt2sas_fwfault_debug;
-MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault "
- "and halt firmware - (default=0)");
-
-static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
-MODULE_PARM_DESC(disable_discovery, " disable discovery ");
-
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
-
-static int
-_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag);
-
-/**
- * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug.
- *
- */
-static int
-_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
-{
- int ret = param_set_int(val, kp);
- struct MPT2SAS_ADAPTER *ioc;
-
- if (ret)
- return ret;
-
- /* global ioc spinlock to protect controller list on list operations */
- printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug);
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
- ioc->fwfault_debug = mpt2sas_fwfault_debug;
- spin_unlock(&gioc_lock);
- return 0;
-}
-
-module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug,
- param_get_int, &mpt2sas_fwfault_debug, 0644);
-
-/**
- * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc
- * @arg: input argument, used to derive ioc
- *
- * Return 0 if controller is removed from pci subsystem.
- * Return -1 for other case.
- */
-static int mpt2sas_remove_dead_ioc_func(void *arg)
-{
- struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg;
- struct pci_dev *pdev;
-
- if ((ioc == NULL))
- return -1;
-
- pdev = ioc->pdev;
- if ((pdev == NULL))
- return -1;
- pci_stop_and_remove_bus_device_locked(pdev);
- return 0;
-}
-
-
-/**
- * _base_fault_reset_work - workq handling ioc fault conditions
- * @work: input argument, used to derive ioc
- * Context: sleep.
- *
- * Return nothing.
- */
-static void
-_base_fault_reset_work(struct work_struct *work)
-{
- struct MPT2SAS_ADAPTER *ioc =
- container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work);
- unsigned long flags;
- u32 doorbell;
- int rc;
- struct task_struct *p;
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- goto rearm_timer;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) {
- printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n",
- ioc->name, __func__);
-
- /* It may be possible that EEH recovery can resolve some of
- * pci bus failure issues rather removing the dead ioc function
- * by considering controller is in a non-operational state. So
- * here priority is given to the EEH recovery. If it doesn't
- * not resolve this issue, mpt2sas driver will consider this
- * controller to non-operational state and remove the dead ioc
- * function.
- */
- if (ioc->non_operational_loop++ < 5) {
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock,
- flags);
- goto rearm_timer;
- }
-
- /*
- * Call _scsih_flush_pending_cmds callback so that we flush all
- * pending commands back to OS. This call is required to aovid
- * deadlock at block layer. Dead IOC will fail to do diag reset,
- * and this call is safe since dead ioc will never return any
- * command back from HW.
- */
- ioc->schedule_dead_ioc_flush_running_cmds(ioc);
- /*
- * Set remove_host flag early since kernel thread will
- * take some time to execute.
- */
- ioc->remove_host = 1;
- /*Remove the Dead Host */
- p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc,
- "mpt2sas_dead_ioc_%d", ioc->id);
- if (IS_ERR(p)) {
- printk(MPT2SAS_ERR_FMT
- "%s: Running mpt2sas_dead_ioc thread failed !!!!\n",
- ioc->name, __func__);
- } else {
- printk(MPT2SAS_ERR_FMT
- "%s: Running mpt2sas_dead_ioc thread success !!!!\n",
- ioc->name, __func__);
- }
-
- return; /* don't rearm timer */
- }
-
- ioc->non_operational_loop = 0;
-
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name,
- __func__, (rc == 0) ? "success" : "failed");
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
- mpt2sas_base_fault_info(ioc, doorbell &
- MPI2_DOORBELL_DATA_MASK);
- }
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- rearm_timer:
- if (ioc->fault_reset_work_q)
- queue_delayed_work(ioc->fault_reset_work_q,
- &ioc->fault_reset_work,
- msecs_to_jiffies(FAULT_POLLING_INTERVAL));
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-}
-
-/**
- * mpt2sas_base_start_watchdog - start the fault_reset_work_q
- * @ioc: per adapter object
- * Context: sleep.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
-
- if (ioc->fault_reset_work_q)
- return;
-
- /* initialize fault polling */
- INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
- snprintf(ioc->fault_reset_work_q_name,
- sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
- ioc->fault_reset_work_q =
- create_singlethread_workqueue(ioc->fault_reset_work_q_name);
- if (!ioc->fault_reset_work_q) {
- printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n",
- ioc->name, __func__, __LINE__);
- return;
- }
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->fault_reset_work_q)
- queue_delayed_work(ioc->fault_reset_work_q,
- &ioc->fault_reset_work,
- msecs_to_jiffies(FAULT_POLLING_INTERVAL));
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-}
-
-/**
- * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q
- * @ioc: per adapter object
- * Context: sleep.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
- struct workqueue_struct *wq;
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- wq = ioc->fault_reset_work_q;
- ioc->fault_reset_work_q = NULL;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- if (wq) {
- if (!cancel_delayed_work_sync(&ioc->fault_reset_work))
- flush_workqueue(wq);
- destroy_workqueue(wq);
- }
-}
-
-/**
- * mpt2sas_base_fault_info - verbose translation of firmware FAULT code
- * @ioc: per adapter object
- * @fault_code: fault code
- *
- * Return nothing.
- */
-void
-mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code)
-{
- printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n",
- ioc->name, fault_code);
-}
-
-/**
- * mpt2sas_halt_firmware - halt's mpt controller firmware
- * @ioc: per adapter object
- *
- * For debugging timeout related issues. Writing 0xCOFFEE00
- * to the doorbell register will halt controller firmware. With
- * the purpose to stop both driver and firmware, the enduser can
- * obtain a ring buffer from controller UART.
- */
-void
-mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 doorbell;
-
- if (!ioc->fwfault_debug)
- return;
-
- dump_stack();
-
- doorbell = readl(&ioc->chip->Doorbell);
- if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT)
- mpt2sas_base_fault_info(ioc , doorbell);
- else {
- writel(0xC0FFEE00, &ioc->chip->Doorbell);
- printk(MPT2SAS_ERR_FMT "Firmware is halted due to command "
- "timeout\n", ioc->name);
- }
-
- panic("panic in %s\n", __func__);
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _base_sas_ioc_info - verbose translation of the ioc status
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @request_hdr: request mf
- *
- * Return nothing.
- */
-static void
-_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply,
- MPI2RequestHeader_t *request_hdr)
-{
- u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- char *desc = NULL;
- u16 frame_sz;
- char *func_str = NULL;
-
- /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */
- if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
- request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
-
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- return;
-
- switch (ioc_status) {
-
-/****************************************************************************
-* Common IOCStatus values for all replies
-****************************************************************************/
-
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- desc = "invalid function";
- break;
- case MPI2_IOCSTATUS_BUSY:
- desc = "busy";
- break;
- case MPI2_IOCSTATUS_INVALID_SGL:
- desc = "invalid sgl";
- break;
- case MPI2_IOCSTATUS_INTERNAL_ERROR:
- desc = "internal error";
- break;
- case MPI2_IOCSTATUS_INVALID_VPID:
- desc = "invalid vpid";
- break;
- case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
- desc = "insufficient resources";
- break;
- case MPI2_IOCSTATUS_INVALID_FIELD:
- desc = "invalid field";
- break;
- case MPI2_IOCSTATUS_INVALID_STATE:
- desc = "invalid state";
- break;
- case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED:
- desc = "op state not supported";
- break;
-
-/****************************************************************************
-* Config IOCStatus values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION:
- desc = "config invalid action";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE:
- desc = "config invalid type";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE:
- desc = "config invalid page";
- break;
- case MPI2_IOCSTATUS_CONFIG_INVALID_DATA:
- desc = "config invalid data";
- break;
- case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS:
- desc = "config no defaults";
- break;
- case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT:
- desc = "config cant commit";
- break;
-
-/****************************************************************************
-* SCSI IO Reply
-****************************************************************************/
-
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- break;
-
-/****************************************************************************
-* For use by SCSI Initiator and SCSI Target end-to-end data protection
-****************************************************************************/
-
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- desc = "eedp guard error";
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- desc = "eedp ref tag error";
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- desc = "eedp app tag error";
- break;
-
-/****************************************************************************
-* SCSI Target values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX:
- desc = "target invalid io index";
- break;
- case MPI2_IOCSTATUS_TARGET_ABORTED:
- desc = "target aborted";
- break;
- case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE:
- desc = "target no conn retryable";
- break;
- case MPI2_IOCSTATUS_TARGET_NO_CONNECTION:
- desc = "target no connection";
- break;
- case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH:
- desc = "target xfer count mismatch";
- break;
- case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR:
- desc = "target data offset error";
- break;
- case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA:
- desc = "target too much write data";
- break;
- case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT:
- desc = "target iu too short";
- break;
- case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT:
- desc = "target ack nak timeout";
- break;
- case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED:
- desc = "target nak received";
- break;
-
-/****************************************************************************
-* Serial Attached SCSI values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED:
- desc = "smp request failed";
- break;
- case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN:
- desc = "smp data overrun";
- break;
-
-/****************************************************************************
-* Diagnostic Buffer Post / Diagnostic Release values
-****************************************************************************/
-
- case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED:
- desc = "diagnostic released";
- break;
- default:
- break;
- }
-
- if (!desc)
- return;
-
- switch (request_hdr->Function) {
- case MPI2_FUNCTION_CONFIG:
- frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size;
- func_str = "config_page";
- break;
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t);
- func_str = "task_mgmt";
- break;
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t);
- func_str = "sas_iounit_ctl";
- break;
- case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR:
- frame_sz = sizeof(Mpi2SepRequest_t);
- func_str = "enclosure";
- break;
- case MPI2_FUNCTION_IOC_INIT:
- frame_sz = sizeof(Mpi2IOCInitRequest_t);
- func_str = "ioc_init";
- break;
- case MPI2_FUNCTION_PORT_ENABLE:
- frame_sz = sizeof(Mpi2PortEnableRequest_t);
- func_str = "port_enable";
- break;
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size;
- func_str = "smp_passthru";
- break;
- default:
- frame_sz = 32;
- func_str = "unknown";
- break;
- }
-
- printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p),"
- " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str);
-
- _debug_dump_mf(request_hdr, frame_sz/4);
-}
-
-/**
- * _base_display_event_data - verbose translation of firmware asyn events
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- *
- * Return nothing.
- */
-static void
-_base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply)
-{
- char *desc = NULL;
- u16 event;
-
- if (!(ioc->logging_level & MPT_DEBUG_EVENTS))
- return;
-
- event = le16_to_cpu(mpi_reply->Event);
-
- switch (event) {
- case MPI2_EVENT_LOG_DATA:
- desc = "Log Data";
- break;
- case MPI2_EVENT_STATE_CHANGE:
- desc = "Status Change";
- break;
- case MPI2_EVENT_HARD_RESET_RECEIVED:
- desc = "Hard Reset Received";
- break;
- case MPI2_EVENT_EVENT_CHANGE:
- desc = "Event Change";
- break;
- case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- desc = "Device Status Change";
- break;
- case MPI2_EVENT_IR_OPERATION_STATUS:
- if (!ioc->hide_ir_msg)
- desc = "IR Operation Status";
- break;
- case MPI2_EVENT_SAS_DISCOVERY:
- {
- Mpi2EventDataSasDiscovery_t *event_data =
- (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData;
- printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
- if (event_data->DiscoveryStatus)
- printk("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- printk("\n");
- return;
- }
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- desc = "SAS Broadcast Primitive";
- break;
- case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE:
- desc = "SAS Init Device Status Change";
- break;
- case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW:
- desc = "SAS Init Table Overflow";
- break;
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- desc = "SAS Topology Change List";
- break;
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- desc = "SAS Enclosure Device Status Change";
- break;
- case MPI2_EVENT_IR_VOLUME:
- if (!ioc->hide_ir_msg)
- desc = "IR Volume";
- break;
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- if (!ioc->hide_ir_msg)
- desc = "IR Physical Disk";
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- if (!ioc->hide_ir_msg)
- desc = "IR Configuration Change List";
- break;
- case MPI2_EVENT_LOG_ENTRY_ADDED:
- if (!ioc->hide_ir_msg)
- desc = "Log Entry Added";
- break;
- case MPI2_EVENT_TEMP_THRESHOLD:
- desc = "Temperature Threshold";
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc);
-}
-#endif
-
-/**
- * _base_sas_log_info - verbose translation of firmware log info
- * @ioc: per adapter object
- * @log_info: log info
- *
- * Return nothing.
- */
-static void
-_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info)
-{
- union loginfo_type {
- u32 loginfo;
- struct {
- u32 subcode:16;
- u32 code:8;
- u32 originator:4;
- u32 bus_type:4;
- } dw;
- };
- union loginfo_type sas_loginfo;
- char *originator_str = NULL;
-
- sas_loginfo.loginfo = log_info;
- if (sas_loginfo.dw.bus_type != 3 /*SAS*/)
- return;
-
- /* each nexus loss loginfo */
- if (log_info == 0x31170000)
- return;
-
- /* eat the loginfos associated with task aborts */
- if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info ==
- 0x31140000 || log_info == 0x31130000))
- return;
-
- switch (sas_loginfo.dw.originator) {
- case 0:
- originator_str = "IOP";
- break;
- case 1:
- originator_str = "PL";
- break;
- case 2:
- if (!ioc->hide_ir_msg)
- originator_str = "IR";
- else
- originator_str = "WarpDrive";
- break;
- }
-
- printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), "
- "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info,
- originator_str, sas_loginfo.dw.code,
- sas_loginfo.dw.subcode);
-}
-
-/**
- * _base_display_reply_info -
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Return nothing.
- */
-static void
-_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- u16 ioc_status;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
- (ioc->logging_level & MPT_DEBUG_REPLY)) {
- _base_sas_ioc_info(ioc , mpi_reply,
- mpt2sas_base_get_msg_frame(ioc, smid));
- }
-#endif
- if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
- _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo));
-}
-
-/**
- * mpt2sas_base_done - base internal command completion routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return 1;
-
- if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
-
- ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- }
- ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
-
- complete(&ioc->base_cmds.done);
- return 1;
-}
-
-/**
- * _base_async_event - main callback handler for firmware asyn events
- * @ioc: per adapter object
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Returns void.
- */
-static void
-_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
-{
- Mpi2EventNotificationReply_t *mpi_reply;
- Mpi2EventAckRequest_t *ack_request;
- u16 smid;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (!mpi_reply)
- return;
- if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _base_display_event_data(ioc, mpi_reply);
-#endif
- if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
- goto out;
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- goto out;
- }
-
- ack_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t));
- ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
- ack_request->Event = mpi_reply->Event;
- ack_request->EventContext = mpi_reply->EventContext;
- ack_request->VF_ID = 0; /* TODO */
- ack_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid);
-
- out:
-
- /* scsih callback handler */
- mpt2sas_scsih_event_callback(ioc, msix_index, reply);
-
- /* ctl callback handler */
- mpt2sas_ctl_event_callback(ioc, msix_index, reply);
-
- return;
-}
-
-/**
- * _base_get_cb_idx - obtain the callback index
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return callback index.
- */
-static u8
-_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- int i;
- u8 cb_idx;
-
- if (smid < ioc->hi_priority_smid) {
- i = smid - 1;
- cb_idx = ioc->scsi_lookup[i].cb_idx;
- } else if (smid < ioc->internal_smid) {
- i = smid - ioc->hi_priority_smid;
- cb_idx = ioc->hpr_lookup[i].cb_idx;
- } else if (smid <= ioc->hba_queue_depth) {
- i = smid - ioc->internal_smid;
- cb_idx = ioc->internal_lookup[i].cb_idx;
- } else
- cb_idx = 0xFF;
- return cb_idx;
-}
-
-/**
- * _base_mask_interrupts - disable interrupts
- * @ioc: per adapter object
- *
- * Disabling ResetIRQ, Reply and Doorbell Interrupts
- *
- * Return nothing.
- */
-static void
-_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 him_register;
-
- ioc->mask_interrupts = 1;
- him_register = readl(&ioc->chip->HostInterruptMask);
- him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK;
- writel(him_register, &ioc->chip->HostInterruptMask);
- readl(&ioc->chip->HostInterruptMask);
-}
-
-/**
- * _base_unmask_interrupts - enable interrupts
- * @ioc: per adapter object
- *
- * Enabling only Reply Interrupts
- *
- * Return nothing.
- */
-static void
-_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
-{
- u32 him_register;
-
- him_register = readl(&ioc->chip->HostInterruptMask);
- him_register &= ~MPI2_HIM_RIM;
- writel(him_register, &ioc->chip->HostInterruptMask);
- ioc->mask_interrupts = 0;
-}
-
-union reply_descriptor {
- u64 word;
- struct {
- u32 low;
- u32 high;
- } u;
-};
-
-/**
- * _base_interrupt - MPT adapter (IOC) specific interrupt handler.
- * @irq: irq number (not used)
- * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
- * @r: pt_regs pointer (not used)
- *
- * Return IRQ_HANDLE if processed, else IRQ_NONE.
- */
-static irqreturn_t
-_base_interrupt(int irq, void *bus_id)
-{
- struct adapter_reply_queue *reply_q = bus_id;
- union reply_descriptor rd;
- u32 completed_cmds;
- u8 request_desript_type;
- u16 smid;
- u8 cb_idx;
- u32 reply;
- u8 msix_index = reply_q->msix_index;
- struct MPT2SAS_ADAPTER *ioc = reply_q->ioc;
- Mpi2ReplyDescriptorsUnion_t *rpf;
- u8 rc;
-
- if (ioc->mask_interrupts)
- return IRQ_NONE;
-
- if (!atomic_add_unless(&reply_q->busy, 1, 1))
- return IRQ_NONE;
-
- rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index];
- request_desript_type = rpf->Default.ReplyFlags
- & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) {
- atomic_dec(&reply_q->busy);
- return IRQ_NONE;
- }
-
- completed_cmds = 0;
- cb_idx = 0xFF;
- do {
- rd.word = le64_to_cpu(rpf->Words);
- if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX)
- goto out;
- reply = 0;
- smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
- if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
- reply = le32_to_cpu
- (rpf->AddressReply.ReplyFrameAddress);
- if (reply > ioc->reply_dma_max_address ||
- reply < ioc->reply_dma_min_address)
- reply = 0;
- } else if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER)
- goto next;
- else if (request_desript_type ==
- MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
- goto next;
- if (smid) {
- cb_idx = _base_get_cb_idx(ioc, smid);
- if ((likely(cb_idx < MPT_MAX_CALLBACKS))
- && (likely(mpt_callbacks[cb_idx] != NULL))) {
- rc = mpt_callbacks[cb_idx](ioc, smid,
- msix_index, reply);
- if (reply)
- _base_display_reply_info(ioc, smid,
- msix_index, reply);
- if (rc)
- mpt2sas_base_free_smid(ioc, smid);
- }
- }
- if (!smid)
- _base_async_event(ioc, msix_index, reply);
-
- /* reply free queue handling */
- if (reply) {
- ioc->reply_free_host_index =
- (ioc->reply_free_host_index ==
- (ioc->reply_free_queue_depth - 1)) ?
- 0 : ioc->reply_free_host_index + 1;
- ioc->reply_free[ioc->reply_free_host_index] =
- cpu_to_le32(reply);
- wmb();
- writel(ioc->reply_free_host_index,
- &ioc->chip->ReplyFreeHostIndex);
- }
-
- next:
-
- rpf->Words = cpu_to_le64(ULLONG_MAX);
- reply_q->reply_post_host_index =
- (reply_q->reply_post_host_index ==
- (ioc->reply_post_queue_depth - 1)) ? 0 :
- reply_q->reply_post_host_index + 1;
- request_desript_type =
- reply_q->reply_post_free[reply_q->reply_post_host_index].
- Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK;
- completed_cmds++;
- if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED)
- goto out;
- if (!reply_q->reply_post_host_index)
- rpf = reply_q->reply_post_free;
- else
- rpf++;
- } while (1);
-
- out:
-
- if (!completed_cmds) {
- atomic_dec(&reply_q->busy);
- return IRQ_NONE;
- }
- wmb();
- if (ioc->is_warpdrive) {
- writel(reply_q->reply_post_host_index,
- ioc->reply_post_host_index[msix_index]);
- atomic_dec(&reply_q->busy);
- return IRQ_HANDLED;
- }
- writel(reply_q->reply_post_host_index | (msix_index <<
- MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex);
- atomic_dec(&reply_q->busy);
- return IRQ_HANDLED;
-}
-
-/**
- * _base_is_controller_msix_enabled - is controller support muli-reply queues
- * @ioc: per adapter object
- *
- */
-static inline int
-_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc)
-{
- return (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable;
-}
-
-/**
- * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues
- * @ioc: per adapter object
- * Context: ISR conext
- *
- * Called when a Task Management request has completed. We want
- * to flush the other reply queues so all the outstanding IO has been
- * completed back to OS before we process the TM completetion.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc)
-{
- struct adapter_reply_queue *reply_q;
-
- /* If MSIX capability is turned off
- * then multi-queues are not enabled
- */
- if (!_base_is_controller_msix_enabled(ioc))
- return;
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- if (ioc->shost_recovery)
- return;
- /* TMs are on msix_index == 0 */
- if (reply_q->msix_index == 0)
- continue;
- _base_interrupt(reply_q->vector, (void *)reply_q);
- }
-}
-
-/**
- * mpt2sas_base_release_callback_handler - clear interrupt callback handler
- * @cb_idx: callback index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_release_callback_handler(u8 cb_idx)
-{
- mpt_callbacks[cb_idx] = NULL;
-}
-
-/**
- * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler
- * @cb_func: callback function
- *
- * Returns cb_func.
- */
-u8
-mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func)
-{
- u8 cb_idx;
-
- for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--)
- if (mpt_callbacks[cb_idx] == NULL)
- break;
-
- mpt_callbacks[cb_idx] = cb_func;
- return cb_idx;
-}
-
-/**
- * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler
- *
- * Return nothing.
- */
-void
-mpt2sas_base_initialize_callback_handler(void)
-{
- u8 cb_idx;
-
- for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++)
- mpt2sas_base_release_callback_handler(cb_idx);
-}
-
-/**
- * mpt2sas_base_build_zero_len_sge - build zero length sg entry
- * @ioc: per adapter object
- * @paddr: virtual address for SGE
- *
- * Create a zero length scatter gather entry to insure the IOCs hardware has
- * something to use if the target device goes brain dead and tries
- * to send data even when none is asked for.
- *
- * Return nothing.
- */
-void
-mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr)
-{
- u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST |
- MPI2_SGE_FLAGS_SIMPLE_ELEMENT) <<
- MPI2_SGE_FLAGS_SHIFT);
- ioc->base_add_sg_single(paddr, flags_length, -1);
-}
-
-/**
- * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr.
- * @paddr: virtual address for SGE
- * @flags_length: SGE flags and data transfer length
- * @dma_addr: Physical address
- *
- * Return nothing.
- */
-static void
-_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr)
-{
- Mpi2SGESimple32_t *sgel = paddr;
-
- flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING |
- MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
- sgel->FlagsLength = cpu_to_le32(flags_length);
- sgel->Address = cpu_to_le32(dma_addr);
-}
-
-
-/**
- * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr.
- * @paddr: virtual address for SGE
- * @flags_length: SGE flags and data transfer length
- * @dma_addr: Physical address
- *
- * Return nothing.
- */
-static void
-_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr)
-{
- Mpi2SGESimple64_t *sgel = paddr;
-
- flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING |
- MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT;
- sgel->FlagsLength = cpu_to_le32(flags_length);
- sgel->Address = cpu_to_le64(dma_addr);
-}
-
-#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10))
-
-/**
- * _base_config_dma_addressing - set dma addressing
- * @ioc: per adapter object
- * @pdev: PCI device struct
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev)
-{
- struct sysinfo s;
- u64 consistent_dma_mask;
-
- if (ioc->dma_mask)
- consistent_dma_mask = DMA_BIT_MASK(64);
- else
- consistent_dma_mask = DMA_BIT_MASK(32);
-
- if (sizeof(dma_addr_t) > 4) {
- const uint64_t required_mask =
- dma_get_required_mask(&pdev->dev);
- if ((required_mask > DMA_BIT_MASK(32)) &&
- !pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) &&
- !pci_set_consistent_dma_mask(pdev, consistent_dma_mask)) {
- ioc->base_add_sg_single = &_base_add_sg_single_64;
- ioc->sge_size = sizeof(Mpi2SGESimple64_t);
- ioc->dma_mask = 64;
- goto out;
- }
- }
-
- if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))
- && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- ioc->base_add_sg_single = &_base_add_sg_single_32;
- ioc->sge_size = sizeof(Mpi2SGESimple32_t);
- ioc->dma_mask = 32;
- } else
- return -ENODEV;
-
- out:
- si_meminfo(&s);
- printk(MPT2SAS_INFO_FMT
- "%d BIT PCI BUS DMA ADDRESSING SUPPORTED, total mem (%ld kB)\n",
- ioc->name, ioc->dma_mask, convert_to_kb(s.totalram));
-
- return 0;
-}
-
-static int
-_base_change_consistent_dma_mask(struct MPT2SAS_ADAPTER *ioc,
- struct pci_dev *pdev)
-{
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) {
- if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)))
- return -ENODEV;
- }
- return 0;
-}
-/**
- * _base_check_enable_msix - checks MSIX capabable.
- * @ioc: per adapter object
- *
- * Check to see if card is capable of MSIX, and set number
- * of available msix vectors
- */
-static int
-_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- int base;
- u16 message_control;
-
-
- /* Check whether controller SAS2008 B0 controller,
- if it is SAS2008 B0 controller use IO-APIC instead of MSIX */
- if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
- ioc->pdev->revision == 0x01) {
- return -EINVAL;
- }
-
- base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
- if (!base) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not "
- "supported\n", ioc->name));
- return -EINVAL;
- }
-
- /* get msix vector count */
- /* NUMA_IO not supported for older controllers */
- if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
- ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
- ioc->msix_vector_count = 1;
- else {
- pci_read_config_word(ioc->pdev, base + 2, &message_control);
- ioc->msix_vector_count = (message_control & 0x3FF) + 1;
- }
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, "
- "vector_count(%d)\n", ioc->name, ioc->msix_vector_count));
-
- return 0;
-}
-
-/**
- * _base_free_irq - free irq
- * @ioc: per adapter object
- *
- * Freeing respective reply_queue from the list.
- */
-static void
-_base_free_irq(struct MPT2SAS_ADAPTER *ioc)
-{
- struct adapter_reply_queue *reply_q, *next;
-
- if (list_empty(&ioc->reply_queue_list))
- return;
-
- list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
- list_del(&reply_q->list);
- irq_set_affinity_hint(reply_q->vector, NULL);
- free_cpumask_var(reply_q->affinity_hint);
- synchronize_irq(reply_q->vector);
- free_irq(reply_q->vector, reply_q);
- kfree(reply_q);
- }
-}
-
-/**
- * _base_request_irq - request irq
- * @ioc: per adapter object
- * @index: msix index into vector table
- * @vector: irq vector
- *
- * Inserting respective reply_queue into the list.
- */
-static int
-_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)
-{
- struct adapter_reply_queue *reply_q;
- int r;
-
- reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL);
- if (!reply_q) {
- printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n",
- ioc->name, (int)sizeof(struct adapter_reply_queue));
- return -ENOMEM;
- }
- reply_q->ioc = ioc;
- reply_q->msix_index = index;
- reply_q->vector = vector;
-
- if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
- return -ENOMEM;
- cpumask_clear(reply_q->affinity_hint);
-
- atomic_set(&reply_q->busy, 0);
- if (ioc->msix_enable)
- snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
- MPT2SAS_DRIVER_NAME, ioc->id, index);
- else
- snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
- MPT2SAS_DRIVER_NAME, ioc->id);
- r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
- reply_q);
- if (r) {
- printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n",
- reply_q->name, vector);
- kfree(reply_q);
- return -EBUSY;
- }
-
- INIT_LIST_HEAD(&reply_q->list);
- list_add_tail(&reply_q->list, &ioc->reply_queue_list);
- return 0;
-}
-
-/**
- * _base_assign_reply_queues - assigning msix index for each cpu
- * @ioc: per adapter object
- *
- * The enduser would need to set the affinity via /proc/irq/#/smp_affinity
- *
- * It would nice if we could call irq_set_affinity, however it is not
- * an exported symbol
- */
-static void
-_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned int cpu, nr_cpus, nr_msix, index = 0;
- struct adapter_reply_queue *reply_q;
-
- if (!_base_is_controller_msix_enabled(ioc))
- return;
-
- memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz);
-
- nr_cpus = num_online_cpus();
- nr_msix = ioc->reply_queue_count = min(ioc->reply_queue_count,
- ioc->facts.MaxMSIxVectors);
- if (!nr_msix)
- return;
-
- cpu = cpumask_first(cpu_online_mask);
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
-
- unsigned int i, group = nr_cpus / nr_msix;
-
- if (cpu >= nr_cpus)
- break;
-
- if (index < nr_cpus % nr_msix)
- group++;
-
- for (i = 0 ; i < group ; i++) {
- ioc->cpu_msix_table[cpu] = index;
- cpumask_or(reply_q->affinity_hint,
- reply_q->affinity_hint, get_cpu_mask(cpu));
- cpu = cpumask_next(cpu, cpu_online_mask);
- }
-
- if (irq_set_affinity_hint(reply_q->vector,
- reply_q->affinity_hint))
- dinitprintk(ioc, pr_info(MPT2SAS_FMT
- "error setting affinity hint for irq vector %d\n",
- ioc->name, reply_q->vector));
- index++;
- }
-}
-
-/**
- * _base_disable_msix - disables msix
- * @ioc: per adapter object
- *
- */
-static void
-_base_disable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->msix_enable) {
- pci_disable_msix(ioc->pdev);
- ioc->msix_enable = 0;
- }
-}
-
-/**
- * _base_enable_msix - enables msix, failback to io_apic
- * @ioc: per adapter object
- *
- */
-static int
-_base_enable_msix(struct MPT2SAS_ADAPTER *ioc)
-{
- struct msix_entry *entries, *a;
- int r;
- int i;
- u8 try_msix = 0;
-
- if (msix_disable == -1 || msix_disable == 0)
- try_msix = 1;
-
- if (!try_msix)
- goto try_ioapic;
-
- if (_base_check_enable_msix(ioc) != 0)
- goto try_ioapic;
-
- ioc->reply_queue_count = min_t(int, ioc->cpu_count,
- ioc->msix_vector_count);
-
- if (!ioc->rdpq_array_enable && max_msix_vectors == -1)
- max_msix_vectors = 8;
-
- if (max_msix_vectors > 0) {
- ioc->reply_queue_count = min_t(int, max_msix_vectors,
- ioc->reply_queue_count);
- ioc->msix_vector_count = ioc->reply_queue_count;
- } else if (max_msix_vectors == 0)
- goto try_ioapic;
-
- printk(MPT2SAS_INFO_FMT
- "MSI-X vectors supported: %d, no of cores: %d, max_msix_vectors: %d\n",
- ioc->name, ioc->msix_vector_count, ioc->cpu_count, max_msix_vectors);
-
- entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry),
- GFP_KERNEL);
- if (!entries) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc "
- "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- goto try_ioapic;
- }
-
- for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++)
- a->entry = i;
-
- r = pci_enable_msix_exact(ioc->pdev, entries, ioc->reply_queue_count);
- if (r) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT
- "pci_enable_msix_exact failed (r=%d) !!!\n", ioc->name, r));
- kfree(entries);
- goto try_ioapic;
- }
-
- ioc->msix_enable = 1;
- for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) {
- r = _base_request_irq(ioc, i, a->vector);
- if (r) {
- _base_free_irq(ioc);
- _base_disable_msix(ioc);
- kfree(entries);
- goto try_ioapic;
- }
- }
-
- kfree(entries);
- return 0;
-
-/* failback to io_apic interrupt routing */
- try_ioapic:
-
- ioc->reply_queue_count = 1;
- r = _base_request_irq(ioc, 0, ioc->pdev->irq);
-
- return r;
-}
-
-/**
- * mpt2sas_base_map_resources - map in controller resources (io/irq/memap)
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
-{
- struct pci_dev *pdev = ioc->pdev;
- u32 memap_sz;
- u32 pio_sz;
- int i, r = 0;
- u64 pio_chip = 0;
- u64 chip_phys = 0;
- struct adapter_reply_queue *reply_q;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n",
- ioc->name, __func__));
-
- ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM);
- if (pci_enable_device_mem(pdev)) {
- printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: "
- "failed\n", ioc->name);
- ioc->bars = 0;
- return -ENODEV;
- }
-
-
- if (pci_request_selected_regions(pdev, ioc->bars,
- MPT2SAS_DRIVER_NAME)) {
- printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: "
- "failed\n", ioc->name);
- ioc->bars = 0;
- r = -ENODEV;
- goto out_fail;
- }
-
- /* AER (Advanced Error Reporting) hooks */
- pci_enable_pcie_error_reporting(pdev);
-
- pci_set_master(pdev);
-
- if (_base_config_dma_addressing(ioc, pdev) != 0) {
- printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n",
- ioc->name, pci_name(pdev));
- r = -ENODEV;
- goto out_fail;
- }
-
- for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) &&
- (!memap_sz || !pio_sz); i++) {
- if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
- if (pio_sz)
- continue;
- pio_chip = (u64)pci_resource_start(pdev, i);
- pio_sz = pci_resource_len(pdev, i);
- } else {
- if (memap_sz)
- continue;
- /* verify memory resource is valid before using */
- if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
- ioc->chip_phys = pci_resource_start(pdev, i);
- chip_phys = (u64)ioc->chip_phys;
- memap_sz = pci_resource_len(pdev, i);
- ioc->chip = ioremap(ioc->chip_phys, memap_sz);
- }
- }
- }
-
- if (ioc->chip == NULL) {
- printk(MPT2SAS_ERR_FMT "unable to map adapter memory! "
- "or resource not found\n", ioc->name);
- r = -EINVAL;
- goto out_fail;
- }
-
- _base_mask_interrupts(ioc);
-
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out_fail;
-
- if (!ioc->rdpq_array_enable_assigned) {
- ioc->rdpq_array_enable = ioc->rdpq_array_capable;
- ioc->rdpq_array_enable_assigned = 1;
- }
-
- r = _base_enable_msix(ioc);
- if (r)
- goto out_fail;
-
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list)
- printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n",
- reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" :
- "IO-APIC enabled"), reply_q->vector);
-
- printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n",
- ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz);
- printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n",
- ioc->name, (unsigned long long)pio_chip, pio_sz);
-
- /* Save PCI configuration state for recovery from PCI AER/EEH errors */
- pci_save_state(pdev);
-
- return 0;
-
- out_fail:
- if (ioc->chip_phys)
- iounmap(ioc->chip);
- ioc->chip_phys = 0;
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
- return r;
-}
-
-/**
- * mpt2sas_base_get_msg_frame - obtain request mf pointer
- * @ioc: per adapter object
- * @smid: system request message index(smid zero is invalid)
- *
- * Returns virt pointer to message frame.
- */
-void *
-mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->request + (smid * ioc->request_sz));
-}
-
-/**
- * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns virt pointer to sense buffer.
- */
-void *
-mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
-}
-
-/**
- * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns phys pointer to the low 32bit address of the sense buffer.
- */
-__le32
-mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return cpu_to_le32(ioc->sense_dma +
- ((smid - 1) * SCSI_SENSE_BUFFERSIZE));
-}
-
-/**
- * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address
- * @ioc: per adapter object
- * @phys_addr: lower 32 physical addr of the reply
- *
- * Converts 32bit lower physical addr into a virt address.
- */
-void *
-mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
-{
- if (!phys_addr)
- return NULL;
- return ioc->reply + (phys_addr - (u32)ioc->reply_dma);
-}
-
-/**
- * mpt2sas_base_get_smid - obtain a free smid from internal queue
- * @ioc: per adapter object
- * @cb_idx: callback index
- *
- * Returns smid (zero is invalid)
- */
-u16
-mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
-{
- unsigned long flags;
- struct request_tracker *request;
- u16 smid;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (list_empty(&ioc->internal_free_list)) {
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
- ioc->name, __func__);
- return 0;
- }
-
- request = list_entry(ioc->internal_free_list.next,
- struct request_tracker, tracker_list);
- request->cb_idx = cb_idx;
- smid = request->smid;
- list_del(&request->tracker_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-/**
- * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue
- * @ioc: per adapter object
- * @cb_idx: callback index
- * @scmd: pointer to scsi command object
- *
- * Returns smid (zero is invalid)
- */
-u16
-mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
- struct scsi_cmnd *scmd)
-{
- unsigned long flags;
- struct scsiio_tracker *request;
- u16 smid;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (list_empty(&ioc->free_list)) {
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
- ioc->name, __func__);
- return 0;
- }
-
- request = list_entry(ioc->free_list.next,
- struct scsiio_tracker, tracker_list);
- request->scmd = scmd;
- request->cb_idx = cb_idx;
- smid = request->smid;
- list_del(&request->tracker_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-/**
- * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue
- * @ioc: per adapter object
- * @cb_idx: callback index
- *
- * Returns smid (zero is invalid)
- */
-u16
-mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
-{
- unsigned long flags;
- struct request_tracker *request;
- u16 smid;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (list_empty(&ioc->hpr_free_list)) {
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return 0;
- }
-
- request = list_entry(ioc->hpr_free_list.next,
- struct request_tracker, tracker_list);
- request->cb_idx = cb_idx;
- smid = request->smid;
- list_del(&request->tracker_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-
-/**
- * mpt2sas_base_free_smid - put smid back on free_list
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- unsigned long flags;
- int i;
- struct chain_tracker *chain_req, *next;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (smid < ioc->hi_priority_smid) {
- /* scsiio queue */
- i = smid - 1;
- if (!list_empty(&ioc->scsi_lookup[i].chain_list)) {
- list_for_each_entry_safe(chain_req, next,
- &ioc->scsi_lookup[i].chain_list, tracker_list) {
- list_del_init(&chain_req->tracker_list);
- list_add(&chain_req->tracker_list,
- &ioc->free_chain_list);
- }
- }
- ioc->scsi_lookup[i].cb_idx = 0xFF;
- ioc->scsi_lookup[i].scmd = NULL;
- ioc->scsi_lookup[i].direct_io = 0;
- list_add(&ioc->scsi_lookup[i].tracker_list,
- &ioc->free_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- /*
- * See _wait_for_commands_to_complete() call with regards
- * to this code.
- */
- if (ioc->shost_recovery && ioc->pending_io_count) {
- if (ioc->pending_io_count == 1)
- wake_up(&ioc->reset_wq);
- ioc->pending_io_count--;
- }
- return;
- } else if (smid < ioc->internal_smid) {
- /* hi-priority */
- i = smid - ioc->hi_priority_smid;
- ioc->hpr_lookup[i].cb_idx = 0xFF;
- list_add(&ioc->hpr_lookup[i].tracker_list,
- &ioc->hpr_free_list);
- } else if (smid <= ioc->hba_queue_depth) {
- /* internal queue */
- i = smid - ioc->internal_smid;
- ioc->internal_lookup[i].cb_idx = 0xFF;
- list_add(&ioc->internal_lookup[i].tracker_list,
- &ioc->internal_free_list);
- }
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-}
-
-/**
- * _base_writeq - 64 bit write to MMIO
- * @ioc: per adapter object
- * @b: data payload
- * @addr: address in MMIO space
- * @writeq_lock: spin lock
- *
- * Glue for handling an atomic 64 bit word to MMIO. This special handling takes
- * care of 32 bit environment where its not quarenteed to send the entire word
- * in one transfer.
- */
-#ifndef writeq
-static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
- spinlock_t *writeq_lock)
-{
- unsigned long flags;
- __u64 data_out = cpu_to_le64(b);
-
- spin_lock_irqsave(writeq_lock, flags);
- writel((u32)(data_out), addr);
- writel((u32)(data_out >> 32), (addr + 4));
- spin_unlock_irqrestore(writeq_lock, flags);
-}
-#else
-static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
- spinlock_t *writeq_lock)
-{
- writeq(cpu_to_le64(b), addr);
-}
-#endif
-
-static inline u8
-_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc)
-{
- return ioc->cpu_msix_table[raw_smp_processor_id()];
-}
-
-/**
- * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- * @handle: device handle
- *
- * Return nothing.
- */
-void
-mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)
-{
- Mpi2RequestDescriptorUnion_t descriptor;
- u64 *request = (u64 *)&descriptor;
-
-
- descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.SCSIIO.SMID = cpu_to_le16(smid);
- descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
- descriptor.SCSIIO.LMID = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-
-/**
- * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- Mpi2RequestDescriptorUnion_t descriptor;
- u64 *request = (u64 *)&descriptor;
-
- descriptor.HighPriority.RequestFlags =
- MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
- descriptor.HighPriority.MSIxIndex = 0;
- descriptor.HighPriority.SMID = cpu_to_le16(smid);
- descriptor.HighPriority.LMID = 0;
- descriptor.HighPriority.Reserved1 = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * mpt2sas_base_put_smid_default - Default, primarily used for config pages
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Return nothing.
- */
-void
-mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- Mpi2RequestDescriptorUnion_t descriptor;
- u64 *request = (u64 *)&descriptor;
-
- descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- descriptor.Default.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.Default.SMID = cpu_to_le16(smid);
- descriptor.Default.LMID = 0;
- descriptor.Default.DescriptorTypeDependent = 0;
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware
- * @ioc: per adapter object
- * @smid: system request message index
- * @io_index: value used to track the IO
- *
- * Return nothing.
- */
-void
-mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u16 io_index)
-{
- Mpi2RequestDescriptorUnion_t descriptor;
- u64 *request = (u64 *)&descriptor;
-
- descriptor.SCSITarget.RequestFlags =
- MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
- descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc);
- descriptor.SCSITarget.SMID = cpu_to_le16(smid);
- descriptor.SCSITarget.LMID = 0;
- descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
- _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow,
- &ioc->scsi_lookup_lock);
-}
-
-/**
- * _base_display_dell_branding - Disply branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- char dell_branding[MPT2SAS_DELL_BRANDING_SIZE];
-
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL)
- return;
-
- memset(dell_branding, 0, MPT2SAS_DELL_BRANDING_SIZE);
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
- strncpy(dell_branding,
- MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_PERC_H200_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- case MPT2SAS_DELL_6GBPS_SAS_SSDID:
- strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_BRANDING,
- MPT2SAS_DELL_BRANDING_SIZE - 1);
- break;
- default:
- sprintf(dell_branding, "0x%4X", ioc->pdev->subsystem_device);
- break;
- }
-
- printk(MPT2SAS_INFO_FMT "%s: Vendor(0x%04X), Device(0x%04X),"
- " SSVID(0x%04X), SSDID(0x%04X)\n", ioc->name, dell_branding,
- ioc->pdev->vendor, ioc->pdev->device, ioc->pdev->subsystem_vendor,
- ioc->pdev->subsystem_device);
-}
-
-/**
- * _base_display_intel_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
- return;
-
- switch (ioc->pdev->device) {
- case MPI2_MFGPAGE_DEVID_SAS2008:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_INTEL_RMS2LL080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS2LL040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS2LL040_BRANDING);
- break;
- case MPT2SAS_INTEL_SSD910_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_SSD910_BRANDING);
- break;
- default:
- break;
- }
- case MPI2_MFGPAGE_DEVID_SAS2308_2:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_INTEL_RS25GB008_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RS25GB008_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25JB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25JB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25JB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25KB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB080_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25KB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25KB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25LB040_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB040_BRANDING);
- break;
- case MPT2SAS_INTEL_RMS25LB080_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_INTEL_RMS25LB080_BRANDING);
- break;
- default:
- break;
- }
- default:
- break;
- }
-}
-
-/**
- * _base_display_hp_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID)
- return;
-
- switch (ioc->pdev->device) {
- case MPI2_MFGPAGE_DEVID_SAS2004:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
- break;
- default:
- break;
- }
- case MPI2_MFGPAGE_DEVID_SAS2308_2:
- switch (ioc->pdev->subsystem_device) {
- case MPT2SAS_HP_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_INTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
- break;
- case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
- printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
- break;
- default:
- break;
- }
- default:
- break;
- }
-}
-
-/**
- * _base_display_ioc_capabilities - Disply IOC's capabilities.
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc)
-{
- int i = 0;
- char desc[16];
- u32 iounit_pg1_flags;
- u32 bios_version;
-
- bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
- strncpy(desc, ioc->manu_pg0.ChipName, 16);
- printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), "
- "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n",
- ioc->name, desc,
- (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
- (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
- (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
- ioc->facts.FWVersion.Word & 0x000000FF,
- ioc->pdev->revision,
- (bios_version & 0xFF000000) >> 24,
- (bios_version & 0x00FF0000) >> 16,
- (bios_version & 0x0000FF00) >> 8,
- bios_version & 0x000000FF);
-
- _base_display_dell_branding(ioc);
- _base_display_intel_branding(ioc);
- _base_display_hp_branding(ioc);
-
- printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name);
-
- if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) {
- printk("Initiator");
- i++;
- }
-
- if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) {
- printk("%sTarget", i ? "," : "");
- i++;
- }
-
- i = 0;
- printk("), ");
- printk("Capabilities=(");
-
- if (!ioc->hide_ir_msg) {
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
- printk("Raid");
- i++;
- }
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
- printk("%sTLR", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) {
- printk("%sMulticast", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) {
- printk("%sBIDI Target", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) {
- printk("%sEEDP", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) {
- printk("%sSnapshot Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) {
- printk("%sDiag Trace Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) {
- printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : "");
- i++;
- }
-
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) {
- printk("%sTask Set Full", i ? "," : "");
- i++;
- }
-
- iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
- if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) {
- printk("%sNCQ", i ? "," : "");
- i++;
- }
-
- printk(")\n");
-}
-
-/**
- * mpt2sas_base_update_missing_delay - change the missing delay timers
- * @ioc: per adapter object
- * @device_missing_delay: amount of time till device is reported missing
- * @io_missing_delay: interval IO is returned when there is a missing device
- *
- * Return nothing.
- *
- * Passed on the command line, this function will modify the device missing
- * delay, as well as the io missing delay. This should be called at driver
- * load time.
- */
-void
-mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
- u16 device_missing_delay, u8 io_missing_delay)
-{
- u16 dmd, dmd_new, dmd_orignal;
- u8 io_missing_delay_original;
- u16 sz;
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u8 num_phys = 0;
- u16 ioc_status;
-
- mpt2sas_config_get_number_hba_phys(ioc, &num_phys);
- if (!num_phys)
- return;
-
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- /* device missing delay */
- dmd = sas_iounit_pg1->ReportDeviceMissingDelay;
- if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
- dmd_orignal = dmd;
- if (device_missing_delay > 0x7F) {
- dmd = (device_missing_delay > 0x7F0) ? 0x7F0 :
- device_missing_delay;
- dmd = dmd / 16;
- dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16;
- } else
- dmd = device_missing_delay;
- sas_iounit_pg1->ReportDeviceMissingDelay = dmd;
-
- /* io missing delay */
- io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay;
- sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay;
-
- if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
- sz)) {
- if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- dmd_new = (dmd &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- dmd_new =
- dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
- printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), "
- "new(%d)\n", ioc->name, dmd_orignal, dmd_new);
- printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), "
- "new(%d)\n", ioc->name, io_missing_delay_original,
- io_missing_delay);
- ioc->device_missing_delay = dmd_new;
- ioc->io_missing_delay = io_missing_delay;
- }
-
-out:
- kfree(sas_iounit_pg1);
-}
-
-/**
- * _base_static_config_pages - static start of day config pages
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ConfigReply_t mpi_reply;
- u32 iounit_pg1_flags;
-
- mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0);
- if (ioc->ir_firmware)
- mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply,
- &ioc->manu_pg10);
- mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2);
- mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3);
- mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
- mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
- mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
- mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
- _base_display_ioc_capabilities(ioc);
-
- /*
- * Enable task_set_full handling in iounit_pg1 when the
- * facts capabilities indicate that its supported.
- */
- iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags);
- if ((ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING))
- iounit_pg1_flags &=
- ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
- else
- iounit_pg1_flags |=
- MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
- ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
- mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
-
- if (ioc->iounit_pg8.NumSensors)
- ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
-}
-
-/**
- * _base_release_memory_pools - release memory
- * @ioc: per adapter object
- *
- * Free memory allocated from _base_allocate_memory_pools.
- *
- * Return nothing.
- */
-static void
-_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
-{
- int i = 0;
- struct reply_post_struct *rps;
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->request) {
- pci_free_consistent(ioc->pdev, ioc->request_dma_sz,
- ioc->request, ioc->request_dma);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)"
- ": free\n", ioc->name, ioc->request));
- ioc->request = NULL;
- }
-
- if (ioc->sense) {
- pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma);
- if (ioc->sense_dma_pool)
- pci_pool_destroy(ioc->sense_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)"
- ": free\n", ioc->name, ioc->sense));
- ioc->sense = NULL;
- }
-
- if (ioc->reply) {
- pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma);
- if (ioc->reply_dma_pool)
- pci_pool_destroy(ioc->reply_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)"
- ": free\n", ioc->name, ioc->reply));
- ioc->reply = NULL;
- }
-
- if (ioc->reply_free) {
- pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free,
- ioc->reply_free_dma);
- if (ioc->reply_free_dma_pool)
- pci_pool_destroy(ioc->reply_free_dma_pool);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool"
- "(0x%p): free\n", ioc->name, ioc->reply_free));
- ioc->reply_free = NULL;
- }
-
- if (ioc->reply_post) {
- do {
- rps = &ioc->reply_post[i];
- if (rps->reply_post_free) {
- pci_pool_free(
- ioc->reply_post_free_dma_pool,
- rps->reply_post_free,
- rps->reply_post_free_dma);
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply_post_free_pool(0x%p): free\n",
- ioc->name, rps->reply_post_free));
- rps->reply_post_free = NULL;
- }
- } while (ioc->rdpq_array_enable &&
- (++i < ioc->reply_queue_count));
-
- if (ioc->reply_post_free_dma_pool)
- pci_pool_destroy(ioc->reply_post_free_dma_pool);
- kfree(ioc->reply_post);
- }
-
- if (ioc->config_page) {
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "config_page(0x%p): free\n", ioc->name,
- ioc->config_page));
- pci_free_consistent(ioc->pdev, ioc->config_page_sz,
- ioc->config_page, ioc->config_page_dma);
- }
-
- if (ioc->scsi_lookup) {
- free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages);
- ioc->scsi_lookup = NULL;
- }
- kfree(ioc->hpr_lookup);
- kfree(ioc->internal_lookup);
- if (ioc->chain_lookup) {
- for (i = 0; i < ioc->chain_depth; i++) {
- if (ioc->chain_lookup[i].chain_buffer)
- pci_pool_free(ioc->chain_dma_pool,
- ioc->chain_lookup[i].chain_buffer,
- ioc->chain_lookup[i].chain_buffer_dma);
- }
- if (ioc->chain_dma_pool)
- pci_pool_destroy(ioc->chain_dma_pool);
- free_pages((ulong)ioc->chain_lookup, ioc->chain_pages);
- ioc->chain_lookup = NULL;
- }
-}
-
-
-/**
- * _base_allocate_memory_pools - allocate start of day memory pools
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 success, anything else error
- */
-static int
-_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- struct mpt2sas_facts *facts;
- u16 max_sge_elements;
- u16 chains_needed_per_io;
- u32 sz, total_sz, reply_post_free_sz;
- u32 retry_sz;
- u16 max_request_credit;
- int i;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- retry_sz = 0;
- facts = &ioc->facts;
-
- /* command line tunables for max sgl entries */
- if (max_sgl_entries != -1) {
- ioc->shost->sg_tablesize = min_t(unsigned short,
- max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS);
- if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH)
- printk(MPT2SAS_WARN_FMT
- "sg_tablesize(%u) is bigger than kernel defined"
- " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
- ioc->shost->sg_tablesize, MPT2SAS_SG_DEPTH);
- } else {
- ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
- }
-
- /* command line tunables for max controller queue depth */
- if (max_queue_depth != -1 && max_queue_depth != 0) {
- max_request_credit = min_t(u16, max_queue_depth +
- ioc->hi_priority_depth + ioc->internal_depth,
- facts->RequestCredit);
- if (max_request_credit > MAX_HBA_QUEUE_DEPTH)
- max_request_credit = MAX_HBA_QUEUE_DEPTH;
- } else
- max_request_credit = min_t(u16, facts->RequestCredit,
- MAX_HBA_QUEUE_DEPTH);
-
- ioc->hba_queue_depth = max_request_credit;
- ioc->hi_priority_depth = facts->HighPriorityCredit;
- ioc->internal_depth = ioc->hi_priority_depth + 5;
-
- /* request frame size */
- ioc->request_sz = facts->IOCRequestFrameSize * 4;
-
- /* reply frame size */
- ioc->reply_sz = facts->ReplyFrameSize * 4;
-
- retry_allocation:
- total_sz = 0;
- /* calculate number of sg elements left over in the 1st frame */
- max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) -
- sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size);
- ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size;
-
- /* now do the same for a chain buffer */
- max_sge_elements = ioc->request_sz - ioc->sge_size;
- ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size;
-
- ioc->chain_offset_value_for_main_message =
- ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) +
- (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4;
-
- /*
- * MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE
- */
- chains_needed_per_io = ((ioc->shost->sg_tablesize -
- ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message)
- + 1;
- if (chains_needed_per_io > facts->MaxChainDepth) {
- chains_needed_per_io = facts->MaxChainDepth;
- ioc->shost->sg_tablesize = min_t(u16,
- ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message
- * chains_needed_per_io), ioc->shost->sg_tablesize);
- }
- ioc->chains_needed_per_io = chains_needed_per_io;
-
- /* reply free queue sizing - taking into account for 64 FW events */
- ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
-
- /* calculate reply descriptor post queue depth */
- ioc->reply_post_queue_depth = ioc->hba_queue_depth +
- ioc->reply_free_queue_depth + 1;
- /* align the reply post queue on the next 16 count boundary */
- if (ioc->reply_post_queue_depth % 16)
- ioc->reply_post_queue_depth += 16 -
- (ioc->reply_post_queue_depth % 16);
-
-
- if (ioc->reply_post_queue_depth >
- facts->MaxReplyDescriptorPostQueueDepth) {
- ioc->reply_post_queue_depth =
- facts->MaxReplyDescriptorPostQueueDepth -
- (facts->MaxReplyDescriptorPostQueueDepth % 16);
- ioc->hba_queue_depth =
- ((ioc->reply_post_queue_depth - 64) / 2) - 1;
- ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64;
- }
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
- "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
- "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
- ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
- ioc->chains_needed_per_io));
-
- /* reply post queue, 16 byte align */
- reply_post_free_sz = ioc->reply_post_queue_depth *
- sizeof(Mpi2DefaultReplyDescriptor_t);
-
- sz = reply_post_free_sz;
- if (_base_is_controller_msix_enabled(ioc) && !ioc->rdpq_array_enable)
- sz *= ioc->reply_queue_count;
-
- ioc->reply_post = kcalloc((ioc->rdpq_array_enable) ?
- (ioc->reply_queue_count):1,
- sizeof(struct reply_post_struct), GFP_KERNEL);
-
- if (!ioc->reply_post) {
- printk(MPT2SAS_ERR_FMT "reply_post_free pool: kcalloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool",
- ioc->pdev, sz, 16, 0);
- if (!ioc->reply_post_free_dma_pool) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- i = 0;
- do {
- ioc->reply_post[i].reply_post_free =
- pci_pool_alloc(ioc->reply_post_free_dma_pool,
- GFP_KERNEL,
- &ioc->reply_post[i].reply_post_free_dma);
- if (!ioc->reply_post[i].reply_post_free) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- memset(ioc->reply_post[i].reply_post_free, 0, sz);
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply post free pool (0x%p): depth(%d),"
- "element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_post[i].reply_post_free,
- ioc->reply_post_queue_depth, 8, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "reply_post_free_dma = (0x%llx)\n", ioc->name,
- (unsigned long long)
- ioc->reply_post[i].reply_post_free_dma));
- total_sz += sz;
- } while (ioc->rdpq_array_enable && (++i < ioc->reply_queue_count));
-
- if (ioc->dma_mask == 64) {
- if (_base_change_consistent_dma_mask(ioc, ioc->pdev) != 0) {
- printk(MPT2SAS_WARN_FMT
- "no suitable consistent DMA mask for %s\n",
- ioc->name, pci_name(ioc->pdev));
- goto out;
- }
- }
-
- ioc->scsiio_depth = ioc->hba_queue_depth -
- ioc->hi_priority_depth - ioc->internal_depth;
-
- /* set the scsi host can_queue depth
- * with some internal commands that could be outstanding
- */
- ioc->shost->can_queue = ioc->scsiio_depth;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "
- "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue));
-
- /* contiguous pool for request and chains, 16 byte align, one extra "
- * "frame for smid=0
- */
- ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
- sz = ((ioc->scsiio_depth + 1) * ioc->request_sz);
-
- /* hi-priority queue */
- sz += (ioc->hi_priority_depth * ioc->request_sz);
-
- /* internal queue */
- sz += (ioc->internal_depth * ioc->request_sz);
-
- ioc->request_dma_sz = sz;
- ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
- if (!ioc->request) {
- printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kB)\n", ioc->name, ioc->hba_queue_depth,
- ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
- if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH)
- goto out;
- retry_sz += 64;
- ioc->hba_queue_depth = max_request_credit - retry_sz;
- goto retry_allocation;
- }
-
- if (retry_sz)
- printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kb)\n", ioc->name, ioc->hba_queue_depth,
- ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
-
-
- /* hi-priority queue */
- ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) *
- ioc->request_sz);
- ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) *
- ioc->request_sz);
-
- /* internal queue */
- ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth *
- ioc->request_sz);
- ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
- ioc->request_sz);
-
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
- "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->request, ioc->hba_queue_depth, ioc->request_sz,
- (ioc->hba_queue_depth * ioc->request_sz)/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n",
- ioc->name, (unsigned long long) ioc->request_dma));
- total_sz += sz;
-
- sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker);
- ioc->scsi_lookup_pages = get_order(sz);
- ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages(
- GFP_KERNEL, ioc->scsi_lookup_pages);
- if (!ioc->scsi_lookup) {
- printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, "
- "sz(%d)\n", ioc->name, (int)sz);
- goto out;
- }
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): "
- "depth(%d)\n", ioc->name, ioc->request,
- ioc->scsiio_depth));
-
- ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH);
- sz = ioc->chain_depth * sizeof(struct chain_tracker);
- ioc->chain_pages = get_order(sz);
-
- ioc->chain_lookup = (struct chain_tracker *)__get_free_pages(
- GFP_KERNEL, ioc->chain_pages);
- if (!ioc->chain_lookup) {
- printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, "
- "sz(%d)\n", ioc->name, (int)sz);
- goto out;
- }
- ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev,
- ioc->request_sz, 16, 0);
- if (!ioc->chain_dma_pool) {
- printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create "
- "failed\n", ioc->name);
- goto out;
- }
- for (i = 0; i < ioc->chain_depth; i++) {
- ioc->chain_lookup[i].chain_buffer = pci_pool_alloc(
- ioc->chain_dma_pool , GFP_KERNEL,
- &ioc->chain_lookup[i].chain_buffer_dma);
- if (!ioc->chain_lookup[i].chain_buffer) {
- ioc->chain_depth = i;
- goto chain_done;
- }
- total_sz += ioc->request_sz;
- }
-chain_done:
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
- ioc->request_sz))/1024));
-
- /* initialize hi-priority queue smid's */
- ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
- sizeof(struct request_tracker), GFP_KERNEL);
- if (!ioc->hpr_lookup) {
- printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->hi_priority_smid = ioc->scsiio_depth + 1;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): "
- "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority,
- ioc->hi_priority_depth, ioc->hi_priority_smid));
-
- /* initialize internal queue smid's */
- ioc->internal_lookup = kcalloc(ioc->internal_depth,
- sizeof(struct request_tracker), GFP_KERNEL);
- if (!ioc->internal_lookup) {
- printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): "
- "depth(%d), start smid(%d)\n", ioc->name, ioc->internal,
- ioc->internal_depth, ioc->internal_smid));
-
- /* sense buffers, 4 byte align */
- sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
- ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
- 0);
- if (!ioc->sense_dma_pool) {
- printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL,
- &ioc->sense_dma);
- if (!ioc->sense) {
- printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "sense pool(0x%p): depth(%d), element_size(%d), pool_size"
- "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth,
- SCSI_SENSE_BUFFERSIZE, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->sense_dma));
- total_sz += sz;
-
- /* reply pool, 4 byte align */
- sz = ioc->reply_free_queue_depth * ioc->reply_sz;
- ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4,
- 0);
- if (!ioc->reply_dma_pool) {
- printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL,
- &ioc->reply_dma);
- if (!ioc->reply) {
- printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n",
- ioc->name);
- goto out;
- }
- ioc->reply_dma_min_address = (u32)(ioc->reply_dma);
- ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth"
- "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply,
- ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n",
- ioc->name, (unsigned long long)ioc->reply_dma));
- total_sz += sz;
-
- /* reply free queue, 16 byte align */
- sz = ioc->reply_free_queue_depth * 4;
- ioc->reply_free_dma_pool = pci_pool_create("reply_free pool",
- ioc->pdev, sz, 16, 0);
- if (!ioc->reply_free_dma_pool) {
- printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create "
- "failed\n", ioc->name);
- goto out;
- }
- ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL,
- &ioc->reply_free_dma);
- if (!ioc->reply_free) {
- printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc "
- "failed\n", ioc->name);
- goto out;
- }
- memset(ioc->reply_free, 0, sz);
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): "
- "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma"
- "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma));
- total_sz += sz;
-
- ioc->config_page_sz = 512;
- ioc->config_page = pci_alloc_consistent(ioc->pdev,
- ioc->config_page_sz, &ioc->config_page_dma);
- if (!ioc->config_page) {
- printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc "
- "failed\n", ioc->name);
- goto out;
- }
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size"
- "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma"
- "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma));
- total_sz += ioc->config_page_sz;
-
- printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n",
- ioc->name, total_sz/1024);
- printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), "
- "Max Controller Queue Depth(%d)\n",
- ioc->name, ioc->shost->can_queue, facts->RequestCredit);
- printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n",
- ioc->name, ioc->shost->sg_tablesize);
- return 0;
-
- out:
- return -ENOMEM;
-}
-
-
-/**
- * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter.
- * @ioc: Pointer to MPT_ADAPTER structure
- * @cooked: Request raw or cooked IOC state
- *
- * Returns all IOC Doorbell register bits if cooked==0, else just the
- * Doorbell bits in MPI_IOC_STATE_MASK.
- */
-u32
-mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked)
-{
- u32 s, sc;
-
- s = readl(&ioc->chip->Doorbell);
- sc = s & MPI2_IOC_STATE_MASK;
- return cooked ? sc : s;
-}
-
-/**
- * _base_wait_on_iocstate - waiting on a particular ioc state
- * @ioc_state: controller state { READY, OPERATIONAL, or RESET }
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout,
- int sleep_flag)
-{
- u32 count, cntdn;
- u32 current_state;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- current_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (current_state == ioc_state)
- return 0;
- if (count && current_state == MPI2_IOC_STATE_FAULT)
- break;
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- return current_state;
-}
-
-/**
- * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by
- * a write to the doorbell)
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell.
- */
-static int
-_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 int_status;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- int_status = readl(&ioc->chip->HostInterruptStatus);
- if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- }
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "int_status(%x)!\n", ioc->name, __func__, count, int_status);
- return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell.
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to
- * doorbell.
- */
-static int
-_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 int_status;
- u32 doorbell;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- int_status = readl(&ioc->chip->HostInterruptStatus);
- if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) {
- doorbell = readl(&ioc->chip->Doorbell);
- if ((doorbell & MPI2_IOC_STATE_MASK) ==
- MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc , doorbell);
- return -EFAULT;
- }
- } else if (int_status == 0xFFFFFFFF)
- goto out;
-
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- out:
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "int_status(%x)!\n", ioc->name, __func__, count, int_status);
- return -EFAULT;
-}
-
-/**
- * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use
- * @ioc: per adapter object
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 cntdn, count;
- u32 doorbell_reg;
-
- count = 0;
- cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout;
- do {
- doorbell_reg = readl(&ioc->chip->Doorbell);
- if (!(doorbell_reg & MPI2_DOORBELL_USED)) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "successful count(%d), timeout(%d)\n", ioc->name,
- __func__, count, timeout));
- return 0;
- }
- if (sleep_flag == CAN_SLEEP)
- msleep(1);
- else
- udelay(500);
- count++;
- } while (--cntdn);
-
- printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), "
- "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg);
- return -EFAULT;
-}
-
-/**
- * _base_send_ioc_reset - send doorbell reset
- * @ioc: per adapter object
- * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout,
- int sleep_flag)
-{
- u32 ioc_state;
- int r = 0;
-
- if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) {
- printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n",
- ioc->name, __func__);
- return -EFAULT;
- }
-
- if (!(ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY))
- return -EFAULT;
-
- printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name);
-
- writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT,
- &ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) {
- r = -EFAULT;
- goto out;
- }
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
- " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
- r = -EFAULT;
- goto out;
- }
- out:
- printk(MPT2SAS_INFO_FMT "message unit reset: %s\n",
- ioc->name, ((r == 0) ? "SUCCESS" : "FAILED"));
- return r;
-}
-
-/**
- * _base_handshake_req_reply_wait - send request thru doorbell interface
- * @ioc: per adapter object
- * @request_bytes: request length
- * @request: pointer having request payload
- * @reply_bytes: reply length
- * @reply: pointer to reply payload
- * @timeout: timeout in second
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
- u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag)
-{
- MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply;
- int i;
- u8 failed;
- u16 dummy;
- __le32 *mfp;
-
- /* make sure doorbell is not in use */
- if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) {
- printk(MPT2SAS_ERR_FMT "doorbell is in use "
- " (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* clear pending doorbell interrupts from previous state changes */
- if (readl(&ioc->chip->HostInterruptStatus) &
- MPI2_HIS_IOC2SYS_DB_STATUS)
- writel(0, &ioc->chip->HostInterruptStatus);
-
- /* send message to ioc */
- writel(((MPI2_FUNCTION_HANDSHAKE<<MPI2_DOORBELL_FUNCTION_SHIFT) |
- ((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
- &ioc->chip->Doorbell);
-
- if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "int failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
- writel(0, &ioc->chip->HostInterruptStatus);
-
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "ack failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* send message 32-bits at a time */
- for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) {
- writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag)))
- failed = 1;
- }
-
- if (failed) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "sending request failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* now wait for the reply */
- if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "int failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
-
- /* read the first two 16-bits, it gives the total length of the reply */
- reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell handshake "
- "int failed (line=%d)\n", ioc->name, __LINE__);
- return -EFAULT;
- }
- reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
-
- for (i = 2; i < default_reply->MsgLength * 2; i++) {
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
- printk(MPT2SAS_ERR_FMT "doorbell "
- "handshake int failed (line=%d)\n", ioc->name,
- __LINE__);
- return -EFAULT;
- }
- if (i >= reply_bytes/2) /* overflow case */
- dummy = readl(&ioc->chip->Doorbell);
- else
- reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell)
- & MPI2_DOORBELL_DATA_MASK);
- writel(0, &ioc->chip->HostInterruptStatus);
- }
-
- _base_wait_for_doorbell_int(ioc, 5, sleep_flag);
- if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use "
- " (line=%d)\n", ioc->name, __LINE__));
- }
- writel(0, &ioc->chip->HostInterruptStatus);
-
- if (ioc->logging_level & MPT_DEBUG_INIT) {
- mfp = (__le32 *)reply;
- printk(KERN_INFO "\toffset:data\n");
- for (i = 0; i < reply_bytes/4; i++)
- printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
- le32_to_cpu(mfp[i]));
- }
- return 0;
-}
-
-/**
- * mpt2sas_base_sas_iounit_control - send sas iounit control to FW
- * @ioc: per adapter object
- * @mpi_reply: the reply payload from FW
- * @mpi_request: the request payload sent to FW
- *
- * The SAS IO Unit Control Request message allows the host to perform low-level
- * operations, such as resets on the PHYs of the IO Unit, also allows the host
- * to obtain the IOC assigned device handles for a device if it has other
- * identifying information about the device, in addition allows the host to
- * remove IOC resources associated with the device.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SasIoUnitControlReply_t *mpi_reply,
- Mpi2SasIoUnitControlRequest_t *mpi_request)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- bool issue_reset = false;
- int rc;
- void *request;
- u16 wait_state_count;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mutex_lock(&ioc->base_cmds.mutex);
-
- if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t));
- if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
- mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
- ioc->ioc_link_reset_in_progress = 1;
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
- msecs_to_jiffies(10000));
- if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
- mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) &&
- ioc->ioc_link_reset_in_progress)
- ioc->ioc_link_reset_in_progress = 0;
- if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SasIoUnitControlRequest_t)/4);
- if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = true;
- goto issue_host_reset;
- }
- if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->base_cmds.reply,
- sizeof(Mpi2SasIoUnitControlReply_t));
- else
- memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- rc = -EFAULT;
- out:
- mutex_unlock(&ioc->base_cmds.mutex);
- return rc;
-}
-
-
-/**
- * mpt2sas_base_scsi_enclosure_processor - sending request to sep device
- * @ioc: per adapter object
- * @mpi_reply: the reply payload from FW
- * @mpi_request: the request payload sent to FW
- *
- * The SCSI Enclosure Processor request message causes the IOC to
- * communicate with SES devices to control LED status signals.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- bool issue_reset = false;
- int rc;
- void *request;
- u16 wait_state_count;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mutex_lock(&ioc->base_cmds.mutex);
-
- if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
- msecs_to_jiffies(10000));
- if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SepRequest_t)/4);
- if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = true;
- goto issue_host_reset;
- }
- if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->base_cmds.reply,
- sizeof(Mpi2SepReply_t));
- else
- memset(mpi_reply, 0, sizeof(Mpi2SepReply_t));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- rc = -EFAULT;
- out:
- mutex_unlock(&ioc->base_cmds.mutex);
- return rc;
-}
-
-/**
- * _base_get_port_facts - obtain port facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag)
-{
- Mpi2PortFactsRequest_t mpi_request;
- Mpi2PortFactsReply_t mpi_reply;
- struct mpt2sas_port_facts *pfacts;
- int mpi_reply_sz, mpi_request_sz, r;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mpi_reply_sz = sizeof(Mpi2PortFactsReply_t);
- mpi_request_sz = sizeof(Mpi2PortFactsRequest_t);
- memset(&mpi_request, 0, mpi_request_sz);
- mpi_request.Function = MPI2_FUNCTION_PORT_FACTS;
- mpi_request.PortNumber = port;
- r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- return r;
- }
-
- pfacts = &ioc->pfacts[port];
- memset(pfacts, 0, sizeof(struct mpt2sas_port_facts));
- pfacts->PortNumber = mpi_reply.PortNumber;
- pfacts->VP_ID = mpi_reply.VP_ID;
- pfacts->VF_ID = mpi_reply.VF_ID;
- pfacts->MaxPostedCmdBuffers =
- le16_to_cpu(mpi_reply.MaxPostedCmdBuffers);
-
- return 0;
-}
-
-/**
- * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL
- * @ioc: per adapter object
- * @timeout:
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_wait_for_iocstate(struct MPT2SAS_ADAPTER *ioc, int timeout,
- int sleep_flag)
-{
- u32 ioc_state, doorbell;
- int rc;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery)
- return 0;
-
- doorbell = mpt2sas_base_get_iocstate(ioc, 0);
- ioc_state = doorbell & MPI2_IOC_STATE_MASK;
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
-
- switch (ioc_state) {
- case MPI2_IOC_STATE_READY:
- case MPI2_IOC_STATE_OPERATIONAL:
- return 0;
- }
-
- if (doorbell & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT
- "unexpected doorbell activ!e\n", ioc->name));
- goto issue_diag_reset;
- }
-
- if (ioc_state == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, doorbell &
- MPI2_DOORBELL_DATA_MASK);
- goto issue_diag_reset;
- }
-
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY,
- timeout, sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed going to ready state (ioc_state=0x%x)\n",
- ioc->name, __func__, ioc_state);
- return -EFAULT;
- }
-
- issue_diag_reset:
- rc = _base_diag_reset(ioc, sleep_flag);
- return rc;
-}
-
-/**
- * _base_get_ioc_facts - obtain ioc facts reply and save in ioc
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2IOCFactsRequest_t mpi_request;
- Mpi2IOCFactsReply_t mpi_reply;
- struct mpt2sas_facts *facts;
- int mpi_reply_sz, mpi_request_sz, r;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- r = _base_wait_for_iocstate(ioc, 10, sleep_flag);
- if (r) {
- printk(MPT2SAS_ERR_FMT "%s: failed getting to correct state\n",
- ioc->name, __func__);
- return r;
- }
-
- mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t);
- mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t);
- memset(&mpi_request, 0, mpi_request_sz);
- mpi_request.Function = MPI2_FUNCTION_IOC_FACTS;
- r = _base_handshake_req_reply_wait(ioc, mpi_request_sz,
- (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- return r;
- }
-
- facts = &ioc->facts;
- memset(facts, 0, sizeof(struct mpt2sas_facts));
- facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion);
- facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion);
- facts->VP_ID = mpi_reply.VP_ID;
- facts->VF_ID = mpi_reply.VF_ID;
- facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions);
- facts->MaxChainDepth = mpi_reply.MaxChainDepth;
- facts->WhoInit = mpi_reply.WhoInit;
- facts->NumberOfPorts = mpi_reply.NumberOfPorts;
- facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors;
- facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit);
- facts->MaxReplyDescriptorPostQueueDepth =
- le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth);
- facts->ProductID = le16_to_cpu(mpi_reply.ProductID);
- facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities);
- if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID))
- ioc->ir_firmware = 1;
- if ((facts->IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE))
- ioc->rdpq_array_capable = 1;
- facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word);
- facts->IOCRequestFrameSize =
- le16_to_cpu(mpi_reply.IOCRequestFrameSize);
- facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators);
- facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets);
- ioc->shost->max_id = -1;
- facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders);
- facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures);
- facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags);
- facts->HighPriorityCredit =
- le16_to_cpu(mpi_reply.HighPriorityCredit);
- facts->ReplyFrameSize = mpi_reply.ReplyFrameSize;
- facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle);
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), "
- "max chains per io(%d)\n", ioc->name, facts->RequestCredit,
- facts->MaxChainDepth));
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), "
- "reply frame size(%d)\n", ioc->name,
- facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4));
- return 0;
-}
-
-/**
- * _base_send_ioc_init - send ioc_init to firmware
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2IOCInitRequest_t mpi_request;
- Mpi2IOCInitReply_t mpi_reply;
- int i, r = 0;
- struct timeval current_time;
- u16 ioc_status;
- u32 reply_post_free_array_sz = 0;
- Mpi2IOCInitRDPQArrayEntry *reply_post_free_array = NULL;
- dma_addr_t reply_post_free_array_dma;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
- mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
- mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
- mpi_request.VF_ID = 0; /* TODO */
- mpi_request.VP_ID = 0;
- mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
- mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
-
- if (_base_is_controller_msix_enabled(ioc))
- mpi_request.HostMSIxVectors = ioc->reply_queue_count;
- mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4);
- mpi_request.ReplyDescriptorPostQueueDepth =
- cpu_to_le16(ioc->reply_post_queue_depth);
- mpi_request.ReplyFreeQueueDepth =
- cpu_to_le16(ioc->reply_free_queue_depth);
-
- mpi_request.SenseBufferAddressHigh =
- cpu_to_le32((u64)ioc->sense_dma >> 32);
- mpi_request.SystemReplyAddressHigh =
- cpu_to_le32((u64)ioc->reply_dma >> 32);
- mpi_request.SystemRequestFrameBaseAddress =
- cpu_to_le64((u64)ioc->request_dma);
- mpi_request.ReplyFreeQueueAddress =
- cpu_to_le64((u64)ioc->reply_free_dma);
-
- if (ioc->rdpq_array_enable) {
- reply_post_free_array_sz = ioc->reply_queue_count *
- sizeof(Mpi2IOCInitRDPQArrayEntry);
- reply_post_free_array = pci_alloc_consistent(ioc->pdev,
- reply_post_free_array_sz, &reply_post_free_array_dma);
- if (!reply_post_free_array) {
- printk(MPT2SAS_ERR_FMT
- "reply_post_free_array: pci_alloc_consistent failed\n",
- ioc->name);
- r = -ENOMEM;
- goto out;
- }
- memset(reply_post_free_array, 0, reply_post_free_array_sz);
- for (i = 0; i < ioc->reply_queue_count; i++)
- reply_post_free_array[i].RDPQBaseAddress =
- cpu_to_le64(
- (u64)ioc->reply_post[i].reply_post_free_dma);
- mpi_request.MsgFlags = MPI2_IOCINIT_MSGFLAG_RDPQ_ARRAY_MODE;
- mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le64((u64)reply_post_free_array_dma);
- } else {
- mpi_request.ReplyDescriptorPostQueueAddress =
- cpu_to_le64((u64)ioc->reply_post[0].reply_post_free_dma);
- }
-
- /* This time stamp specifies number of milliseconds
- * since epoch ~ midnight January 1, 1970.
- */
- do_gettimeofday(&current_time);
- mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 +
- (current_time.tv_usec / 1000));
-
- if (ioc->logging_level & MPT_DEBUG_INIT) {
- __le32 *mfp;
- int i;
-
- mfp = (__le32 *)&mpi_request;
- printk(KERN_INFO "\toffset:data\n");
- for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++)
- printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4,
- le32_to_cpu(mfp[i]));
- }
-
- r = _base_handshake_req_reply_wait(ioc,
- sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request,
- sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10,
- sleep_flag);
-
- if (r != 0) {
- printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n",
- ioc->name, __func__, r);
- goto out;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS ||
- mpi_reply.IOCLogInfo) {
- printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__);
- r = -EIO;
- }
-
-out:
- if (reply_post_free_array)
- pci_free_consistent(ioc->pdev, reply_post_free_array_sz,
- reply_post_free_array,
- reply_post_free_array_dma);
- return r;
-}
-
-/**
- * mpt2sas_port_enable_done - command completion routine for port enable
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- u16 ioc_status;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return 1;
-
- if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
-
- ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->port_enable_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- }
- ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING;
-
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- ioc->port_enable_failed = 1;
-
- if (ioc->is_driver_loading) {
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- mpt2sas_port_enable_complete(ioc);
- return 1;
- } else {
- ioc->start_scan_failed = ioc_status;
- ioc->start_scan = 0;
- return 1;
- }
- }
- complete(&ioc->port_enable_cmds.done);
- return 1;
-}
-
-
-/**
- * _base_send_port_enable - send port_enable(discovery stuff) to firmware
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2PortEnableRequest_t *mpi_request;
- Mpi2PortEnableReply_t *mpi_reply;
- unsigned long timeleft;
- int r = 0;
- u16 smid;
- u16 ioc_status;
-
- printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
-
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- ioc->port_enable_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->port_enable_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
- mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
-
- init_completion(&ioc->port_enable_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done,
- 300*HZ);
- if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2PortEnableRequest_t)/4);
- if (ioc->port_enable_cmds.status & MPT2_CMD_RESET)
- r = -EFAULT;
- else
- r = -ETIME;
- goto out;
- }
- mpi_reply = ioc->port_enable_cmds.reply;
-
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n",
- ioc->name, __func__, ioc_status);
- r = -EFAULT;
- goto out;
- }
- out:
- ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED;
- printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ?
- "SUCCESS" : "FAILED"));
- return r;
-}
-
-/**
- * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply)
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2PortEnableRequest_t *mpi_request;
- u16 smid;
-
- printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name);
-
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- ioc->port_enable_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->port_enable_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
- mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
-
- mpt2sas_base_put_smid_default(ioc, smid);
- return 0;
-}
-
-/**
- * _base_determine_wait_on_discovery - desposition
- * @ioc: per adapter object
- *
- * Decide whether to wait on discovery to complete. Used to either
- * locate boot device, or report volumes ahead of physical devices.
- *
- * Returns 1 for wait, 0 for don't wait
- */
-static int
-_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc)
-{
- /* We wait for discovery to complete if IR firmware is loaded.
- * The sas topology events arrive before PD events, so we need time to
- * turn on the bit in ioc->pd_handles to indicate PD
- * Also, it maybe required to report Volumes ahead of physical
- * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set.
- */
- if (ioc->ir_firmware)
- return 1;
-
- /* if no Bios, then we don't need to wait */
- if (!ioc->bios_pg3.BiosVersion)
- return 0;
-
- /* Bios is present, then we drop down here.
- *
- * If there any entries in the Bios Page 2, then we wait
- * for discovery to complete.
- */
-
- /* Current Boot Device */
- if ((ioc->bios_pg2.CurrentBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
- /* Request Boot Device */
- (ioc->bios_pg2.ReqBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED &&
- /* Alternate Request Boot Device */
- (ioc->bios_pg2.ReqAltBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK) ==
- MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED)
- return 0;
-
- return 1;
-}
-
-
-/**
- * _base_unmask_events - turn on notification for this event
- * @ioc: per adapter object
- * @event: firmware event
- *
- * The mask is stored in ioc->event_masks.
- */
-static void
-_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
-{
- u32 desired_event;
-
- if (event >= 128)
- return;
-
- desired_event = (1 << (event % 32));
-
- if (event < 32)
- ioc->event_masks[0] &= ~desired_event;
- else if (event < 64)
- ioc->event_masks[1] &= ~desired_event;
- else if (event < 96)
- ioc->event_masks[2] &= ~desired_event;
- else if (event < 128)
- ioc->event_masks[3] &= ~desired_event;
-}
-
-/**
- * _base_event_notification - send event notification
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- Mpi2EventNotificationRequest_t *mpi_request;
- unsigned long timeleft;
- u16 smid;
- int r = 0;
- int i;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
- printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return -EAGAIN;
- }
- ioc->base_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->base_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
- mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
- mpi_request->EventMasks[i] =
- cpu_to_le32(ioc->event_masks[i]);
- init_completion(&ioc->base_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
- if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2EventNotificationRequest_t)/4);
- if (ioc->base_cmds.status & MPT2_CMD_RESET)
- r = -EFAULT;
- else
- r = -ETIME;
- } else
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n",
- ioc->name, __func__));
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- return r;
-}
-
-/**
- * mpt2sas_base_validate_event_type - validating event types
- * @ioc: per adapter object
- * @event: firmware event
- *
- * This will turn on firmware event notification when application
- * ask for that event. We don't mask events that are already enabled.
- */
-void
-mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
-{
- int i, j;
- u32 event_mask, desired_event;
- u8 send_update_to_fw;
-
- for (i = 0, send_update_to_fw = 0; i <
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) {
- event_mask = ~event_type[i];
- desired_event = 1;
- for (j = 0; j < 32; j++) {
- if (!(event_mask & desired_event) &&
- (ioc->event_masks[i] & desired_event)) {
- ioc->event_masks[i] &= ~desired_event;
- send_update_to_fw = 1;
- }
- desired_event = (desired_event << 1);
- }
- }
-
- if (!send_update_to_fw)
- return;
-
- mutex_lock(&ioc->base_cmds.mutex);
- _base_event_notification(ioc, CAN_SLEEP);
- mutex_unlock(&ioc->base_cmds.mutex);
-}
-
-/**
- * _base_diag_reset - the "big hammer" start of day reset
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- u32 host_diagnostic;
- u32 ioc_state;
- u32 count;
- u32 hcb_size;
-
- printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name);
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n",
- ioc->name));
-
- count = 0;
- do {
- /* Write magic sequence to WriteSequence register
- * Loop until in diagnostic mode
- */
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic "
- "sequence\n", ioc->name));
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence);
- writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence);
-
- /* wait 100 msec */
- if (sleep_flag == CAN_SLEEP)
- msleep(100);
- else
- mdelay(100);
-
- if (count++ > 20)
- goto out;
-
- host_diagnostic = readl(&ioc->chip->HostDiagnostic);
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic "
- "sequence: count(%d), host_diagnostic(0x%08x)\n",
- ioc->name, count, host_diagnostic));
-
- } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0);
-
- hcb_size = readl(&ioc->chip->HCBSize);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n",
- ioc->name));
- writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER,
- &ioc->chip->HostDiagnostic);
-
- /* This delay allows the chip PCIe hardware time to finish reset tasks*/
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_FIRST_READ_DELAY_MICRO_SEC/1000);
-
- /* Approximately 300 second max wait */
- for (count = 0; count < (300000000 /
- MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC); count++) {
-
- host_diagnostic = readl(&ioc->chip->HostDiagnostic);
-
- if (host_diagnostic == 0xFFFFFFFF)
- goto out;
- if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER))
- break;
-
- /* Wait to pass the second read delay window */
- if (sleep_flag == CAN_SLEEP)
- msleep(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- /1000);
- else
- mdelay(MPI2_HARD_RESET_PCIE_SECOND_READ_DELAY_MICRO_SEC
- /1000);
- }
-
- if (host_diagnostic & MPI2_DIAG_HCB_MODE) {
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter "
- "assuming the HCB Address points to good F/W\n",
- ioc->name));
- host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK;
- host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW;
- writel(host_diagnostic, &ioc->chip->HostDiagnostic);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT
- "re-enable the HCDW\n", ioc->name));
- writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE,
- &ioc->chip->HCBSize);
- }
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n",
- ioc->name));
- writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET,
- &ioc->chip->HostDiagnostic);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the "
- "diagnostic register\n", ioc->name));
- writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence);
-
- drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the "
- "READY state\n", ioc->name));
- ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20,
- sleep_flag);
- if (ioc_state) {
- printk(MPT2SAS_ERR_FMT "%s: failed going to ready state "
- " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state);
- goto out;
- }
-
- printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name);
- return 0;
-
- out:
- printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name);
- return -EFAULT;
-}
-
-/**
- * _base_make_ioc_ready - put controller in READY state
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- * @type: FORCE_BIG_HAMMER or SOFT_RESET
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type)
-{
- u32 ioc_state;
- int rc;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery)
- return 0;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n",
- ioc->name, __func__, ioc_state));
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY)
- return 0;
-
- if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
- "active!\n", ioc->name));
- goto issue_diag_reset;
- }
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, ioc_state &
- MPI2_DOORBELL_DATA_MASK);
- goto issue_diag_reset;
- }
-
- if (type == FORCE_BIG_HAMMER)
- goto issue_diag_reset;
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL)
- if (!(_base_send_ioc_reset(ioc,
- MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) {
- ioc->ioc_reset_count++;
- return 0;
- }
-
- issue_diag_reset:
- rc = _base_diag_reset(ioc, CAN_SLEEP);
- ioc->ioc_reset_count++;
- return rc;
-}
-
-/**
- * _base_make_ioc_operational - put controller in OPERATIONAL state
- * @ioc: per adapter object
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- int r, i;
- unsigned long flags;
- u32 reply_address;
- u16 smid;
- struct _tr_list *delayed_tr, *delayed_tr_next;
- u8 hide_flag;
- struct adapter_reply_queue *reply_q;
- long reply_post_free;
- u32 reply_post_free_sz, index = 0;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- /* clean the delayed target reset list */
- list_for_each_entry_safe(delayed_tr, delayed_tr_next,
- &ioc->delayed_tr_list, list) {
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- }
-
- list_for_each_entry_safe(delayed_tr, delayed_tr_next,
- &ioc->delayed_tr_volume_list, list) {
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- }
-
- /* initialize the scsi lookup free list */
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- INIT_LIST_HEAD(&ioc->free_list);
- smid = 1;
- for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
- INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list);
- ioc->scsi_lookup[i].cb_idx = 0xFF;
- ioc->scsi_lookup[i].smid = smid;
- ioc->scsi_lookup[i].scmd = NULL;
- ioc->scsi_lookup[i].direct_io = 0;
- list_add_tail(&ioc->scsi_lookup[i].tracker_list,
- &ioc->free_list);
- }
-
- /* hi-priority queue */
- INIT_LIST_HEAD(&ioc->hpr_free_list);
- smid = ioc->hi_priority_smid;
- for (i = 0; i < ioc->hi_priority_depth; i++, smid++) {
- ioc->hpr_lookup[i].cb_idx = 0xFF;
- ioc->hpr_lookup[i].smid = smid;
- list_add_tail(&ioc->hpr_lookup[i].tracker_list,
- &ioc->hpr_free_list);
- }
-
- /* internal queue */
- INIT_LIST_HEAD(&ioc->internal_free_list);
- smid = ioc->internal_smid;
- for (i = 0; i < ioc->internal_depth; i++, smid++) {
- ioc->internal_lookup[i].cb_idx = 0xFF;
- ioc->internal_lookup[i].smid = smid;
- list_add_tail(&ioc->internal_lookup[i].tracker_list,
- &ioc->internal_free_list);
- }
-
- /* chain pool */
- INIT_LIST_HEAD(&ioc->free_chain_list);
- for (i = 0; i < ioc->chain_depth; i++)
- list_add_tail(&ioc->chain_lookup[i].tracker_list,
- &ioc->free_chain_list);
-
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- /* initialize Reply Free Queue */
- for (i = 0, reply_address = (u32)ioc->reply_dma ;
- i < ioc->reply_free_queue_depth ; i++, reply_address +=
- ioc->reply_sz)
- ioc->reply_free[i] = cpu_to_le32(reply_address);
-
- /* initialize reply queues */
- if (ioc->is_driver_loading)
- _base_assign_reply_queues(ioc);
-
- /* initialize Reply Post Free Queue */
- reply_post_free_sz = ioc->reply_post_queue_depth *
- sizeof(Mpi2DefaultReplyDescriptor_t);
- reply_post_free = (long)ioc->reply_post[index].reply_post_free;
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- reply_q->reply_post_host_index = 0;
- reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *)
- reply_post_free;
- for (i = 0; i < ioc->reply_post_queue_depth; i++)
- reply_q->reply_post_free[i].Words =
- cpu_to_le64(ULLONG_MAX);
- if (!_base_is_controller_msix_enabled(ioc))
- goto skip_init_reply_post_free_queue;
- /*
- * If RDPQ is enabled, switch to the next allocation.
- * Otherwise advance within the contiguous region.
- */
- if (ioc->rdpq_array_enable)
- reply_post_free = (long)
- ioc->reply_post[++index].reply_post_free;
- else
- reply_post_free += reply_post_free_sz;
- }
- skip_init_reply_post_free_queue:
-
- r = _base_send_ioc_init(ioc, sleep_flag);
- if (r)
- return r;
-
- /* initialize reply free host index */
- ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1;
- writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex);
-
- /* initialize reply post host index */
- list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
- writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT,
- &ioc->chip->ReplyPostHostIndex);
- if (!_base_is_controller_msix_enabled(ioc))
- goto skip_init_reply_post_host_index;
- }
-
- skip_init_reply_post_host_index:
-
- _base_unmask_interrupts(ioc);
-
- r = _base_event_notification(ioc, sleep_flag);
- if (r)
- return r;
-
- if (sleep_flag == CAN_SLEEP)
- _base_static_config_pages(ioc);
-
-
- if (ioc->is_driver_loading) {
- if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
- == 0x80) {
- hide_flag = (u8) (
- le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
- MFG_PAGE10_HIDE_SSDS_MASK);
- if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
- ioc->mfg_pg10_hide_flag = hide_flag;
- }
- ioc->wait_for_discovery_to_complete =
- _base_determine_wait_on_discovery(ioc);
- return r; /* scan_start and scan_finished support */
- }
- r = _base_send_port_enable(ioc, sleep_flag);
- if (r)
- return r;
-
- return r;
-}
-
-/**
- * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap)
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc)
-{
- struct pci_dev *pdev = ioc->pdev;
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- /* synchronizing freeing resource with pci_access_mutex lock */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->chip_phys && ioc->chip) {
- _base_mask_interrupts(ioc);
- ioc->shost_recovery = 1;
- _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- ioc->shost_recovery = 0;
- }
-
- _base_free_irq(ioc);
- _base_disable_msix(ioc);
-
- if (ioc->chip_phys && ioc->chip)
- iounmap(ioc->chip);
- ioc->chip_phys = 0;
-
- if (pci_is_enabled(pdev)) {
- pci_release_selected_regions(ioc->pdev, ioc->bars);
- pci_disable_pcie_error_reporting(pdev);
- pci_disable_device(pdev);
- }
- mutex_unlock(&ioc->pci_access_mutex);
- return;
-}
-
-/**
- * mpt2sas_base_attach - attach controller instance
- * @ioc: per adapter object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
-{
- int r, i;
- int cpu_id, last_cpu_id = 0;
-
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- /* setup cpu_msix_table */
- ioc->cpu_count = num_online_cpus();
- for_each_online_cpu(cpu_id)
- last_cpu_id = cpu_id;
- ioc->cpu_msix_table_sz = last_cpu_id + 1;
- ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL);
- ioc->reply_queue_count = 1;
- if (!ioc->cpu_msix_table) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for "
- "cpu_msix_table failed!!!\n", ioc->name));
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- if (ioc->is_warpdrive) {
- ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
- sizeof(resource_size_t *), GFP_KERNEL);
- if (!ioc->reply_post_host_index) {
- dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation "
- "for cpu_msix_table failed!!!\n", ioc->name));
- r = -ENOMEM;
- goto out_free_resources;
- }
- }
-
- ioc->rdpq_array_enable_assigned = 0;
- ioc->dma_mask = 0;
- r = mpt2sas_base_map_resources(ioc);
- if (r)
- goto out_free_resources;
-
- if (ioc->is_warpdrive) {
- ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
- &ioc->chip->ReplyPostHostIndex;
-
- for (i = 1; i < ioc->cpu_msix_table_sz; i++)
- ioc->reply_post_host_index[i] =
- (resource_size_t __iomem *)
- ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
- * 4)));
- }
-
- pci_set_drvdata(ioc->pdev, ioc->shost);
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out_free_resources;
-
- r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET);
- if (r)
- goto out_free_resources;
-
- ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(struct mpt2sas_port_facts), GFP_KERNEL);
- if (!ioc->pfacts) {
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
- r = _base_get_port_facts(ioc, i, CAN_SLEEP);
- if (r)
- goto out_free_resources;
- }
-
- r = _base_allocate_memory_pools(ioc, CAN_SLEEP);
- if (r)
- goto out_free_resources;
-
- init_waitqueue_head(&ioc->reset_wq);
- /* allocate memory pd handle bitmask list */
- ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8);
- if (ioc->facts.MaxDevHandle % 8)
- ioc->pd_handles_sz++;
- ioc->pd_handles = kzalloc(ioc->pd_handles_sz,
- GFP_KERNEL);
- if (!ioc->pd_handles) {
- r = -ENOMEM;
- goto out_free_resources;
- }
- ioc->blocking_handles = kzalloc(ioc->pd_handles_sz,
- GFP_KERNEL);
- if (!ioc->blocking_handles) {
- r = -ENOMEM;
- goto out_free_resources;
- }
- ioc->fwfault_debug = mpt2sas_fwfault_debug;
-
- /* base internal command bits */
- mutex_init(&ioc->base_cmds.mutex);
- ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
-
- /* port_enable command bits */
- ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED;
-
- /* transport internal command bits */
- ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->transport_cmds.mutex);
-
- /* scsih internal command bits */
- ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->scsih_cmds.mutex);
-
- /* task management internal command bits */
- ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->tm_cmds.mutex);
-
- /* config page internal command bits */
- ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->config_cmds.mutex);
-
- /* ctl module internal command bits */
- ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
- ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL);
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- mutex_init(&ioc->ctl_cmds.mutex);
-
- if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
- !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
- !ioc->config_cmds.reply || !ioc->ctl_cmds.reply ||
- !ioc->ctl_cmds.sense) {
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply ||
- !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply ||
- !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) {
- r = -ENOMEM;
- goto out_free_resources;
- }
-
- for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
- ioc->event_masks[i] = -1;
-
- /* here we enable the events we care about */
- _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
- _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE);
- _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST);
- _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME);
- _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
- _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
- _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
- _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD);
- r = _base_make_ioc_operational(ioc, CAN_SLEEP);
- if (r)
- goto out_free_resources;
-
- ioc->non_operational_loop = 0;
-
- return 0;
-
- out_free_resources:
-
- ioc->remove_host = 1;
- mpt2sas_base_free_resources(ioc);
- _base_release_memory_pools(ioc);
- pci_set_drvdata(ioc->pdev, NULL);
- kfree(ioc->cpu_msix_table);
- if (ioc->is_warpdrive)
- kfree(ioc->reply_post_host_index);
- kfree(ioc->pd_handles);
- kfree(ioc->blocking_handles);
- kfree(ioc->tm_cmds.reply);
- kfree(ioc->transport_cmds.reply);
- kfree(ioc->scsih_cmds.reply);
- kfree(ioc->config_cmds.reply);
- kfree(ioc->base_cmds.reply);
- kfree(ioc->port_enable_cmds.reply);
- kfree(ioc->ctl_cmds.reply);
- kfree(ioc->ctl_cmds.sense);
- kfree(ioc->pfacts);
- ioc->ctl_cmds.reply = NULL;
- ioc->base_cmds.reply = NULL;
- ioc->tm_cmds.reply = NULL;
- ioc->scsih_cmds.reply = NULL;
- ioc->transport_cmds.reply = NULL;
- ioc->config_cmds.reply = NULL;
- ioc->pfacts = NULL;
- return r;
-}
-
-
-/**
- * mpt2sas_base_detach - remove controller instance
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc)
-{
-
- dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- mpt2sas_base_stop_watchdog(ioc);
- mpt2sas_base_free_resources(ioc);
- _base_release_memory_pools(ioc);
- pci_set_drvdata(ioc->pdev, NULL);
- kfree(ioc->cpu_msix_table);
- if (ioc->is_warpdrive)
- kfree(ioc->reply_post_host_index);
- kfree(ioc->pd_handles);
- kfree(ioc->blocking_handles);
- kfree(ioc->pfacts);
- kfree(ioc->ctl_cmds.reply);
- kfree(ioc->ctl_cmds.sense);
- kfree(ioc->base_cmds.reply);
- kfree(ioc->port_enable_cmds.reply);
- kfree(ioc->tm_cmds.reply);
- kfree(ioc->transport_cmds.reply);
- kfree(ioc->scsih_cmds.reply);
- kfree(ioc->config_cmds.reply);
-}
-
-/**
- * _base_reset_handler - reset callback handler (for base)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- *
- * Return nothing.
- */
-static void
-_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- mpt2sas_scsih_reset_handler(ioc, reset_phase);
- mpt2sas_ctl_reset_handler(ioc, reset_phase);
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->transport_cmds.status & MPT2_CMD_PENDING) {
- ioc->transport_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid);
- complete(&ioc->transport_cmds.done);
- }
- if (ioc->base_cmds.status & MPT2_CMD_PENDING) {
- ioc->base_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid);
- complete(&ioc->base_cmds.done);
- }
- if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) {
- ioc->port_enable_failed = 1;
- ioc->port_enable_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid);
- if (ioc->is_driver_loading) {
- ioc->start_scan_failed =
- MPI2_IOCSTATUS_INTERNAL_ERROR;
- ioc->start_scan = 0;
- ioc->port_enable_cmds.status =
- MPT2_CMD_NOT_USED;
- } else
- complete(&ioc->port_enable_cmds.done);
-
- }
- if (ioc->config_cmds.status & MPT2_CMD_PENDING) {
- ioc->config_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid);
- ioc->config_cmds.smid = USHRT_MAX;
- complete(&ioc->config_cmds.done);
- }
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- break;
- }
-}
-
-/**
- * _wait_for_commands_to_complete - reset controller
- * @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- *
- * This function waiting(3s) for all pending commands to complete
- * prior to putting controller in reset.
- */
-static void
-_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
-{
- u32 ioc_state;
- unsigned long flags;
- u16 i;
-
- ioc->pending_io_count = 0;
- if (sleep_flag != CAN_SLEEP)
- return;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL)
- return;
-
- /* pending command count */
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = 0; i < ioc->scsiio_depth; i++)
- if (ioc->scsi_lookup[i].cb_idx != 0xFF)
- ioc->pending_io_count++;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- if (!ioc->pending_io_count)
- return;
-
- /* wait for pending commands to complete */
- wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ);
-}
-
-/**
- * mpt2sas_base_hard_reset_handler - reset controller
- * @ioc: Pointer to MPT_ADAPTER structure
- * @sleep_flag: CAN_SLEEP or NO_SLEEP
- * @type: FORCE_BIG_HAMMER or SOFT_RESET
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type)
-{
- int r;
- unsigned long flags;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- if (ioc->pci_error_recovery) {
- printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n",
- ioc->name, __func__);
- r = 0;
- goto out_unlocked;
- }
-
- if (mpt2sas_fwfault_debug)
- mpt2sas_halt_firmware(ioc);
-
- /* TODO - What we really should be doing is pulling
- * out all the code associated with NO_SLEEP; its never used.
- * That is legacy code from mpt fusion driver, ported over.
- * I will leave this BUG_ON here for now till its been resolved.
- */
- BUG_ON(sleep_flag == NO_SLEEP);
-
- /* wait for an active reset in progress to complete */
- if (!mutex_trylock(&ioc->reset_in_progress_mutex)) {
- do {
- ssleep(1);
- } while (ioc->shost_recovery == 1);
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
- __func__));
- return ioc->ioc_reset_in_progress_status;
- }
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- ioc->shost_recovery = 1;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
-
- _base_reset_handler(ioc, MPT2_IOC_PRE_RESET);
- _wait_for_commands_to_complete(ioc, sleep_flag);
- _base_mask_interrupts(ioc);
- r = _base_make_ioc_ready(ioc, sleep_flag, type);
- if (r)
- goto out;
- _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
-
- /* If this hard reset is called while port enable is active, then
- * there is no reason to call make_ioc_operational
- */
- if (ioc->is_driver_loading && ioc->port_enable_failed) {
- ioc->remove_host = 1;
- r = -EFAULT;
- goto out;
- }
-
- r = _base_get_ioc_facts(ioc, CAN_SLEEP);
- if (r)
- goto out;
-
- if (ioc->rdpq_array_enable && !ioc->rdpq_array_capable)
- panic("%s: Issue occurred with flashing controller firmware."
- "Please reboot the system and ensure that the correct"
- " firmware version is running\n", ioc->name);
-
- r = _base_make_ioc_operational(ioc, sleep_flag);
- if (!r)
- _base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
- out:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n",
- ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED")));
-
- spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- ioc->ioc_reset_in_progress_status = r;
- ioc->shost_recovery = 0;
- spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
- mutex_unlock(&ioc->reset_in_progress_mutex);
-
- out_unlocked:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name,
- __func__));
- return r;
-}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
deleted file mode 100644
index 97ea360..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ /dev/null
@@ -1,1235 +0,0 @@
-/*
- * This is the Fusion MPT base driver providing common API layer interface
- * for access to MPT (Message Passing Technology) firmware.
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_BASE_H_INCLUDED
-#define MPT2SAS_BASE_H_INCLUDED
-
-#include "mpi/mpi2_type.h"
-#include "mpi/mpi2.h"
-#include "mpi/mpi2_ioc.h"
-#include "mpi/mpi2_cnfg.h"
-#include "mpi/mpi2_init.h"
-#include "mpi/mpi2_raid.h"
-#include "mpi/mpi2_tool.h"
-#include "mpi/mpi2_sas.h"
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_tcq.h>
-#include <scsi/scsi_transport_sas.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_eh.h>
-
-#include "mpt2sas_debug.h"
-
-/* driver versioning info */
-#define MPT2SAS_DRIVER_NAME "mpt2sas"
-#define MPT2SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
-#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "20.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 20
-#define MPT2SAS_MINOR_VERSION 100
-#define MPT2SAS_BUILD_VERSION 00
-#define MPT2SAS_RELEASE_VERSION 00
-
-/*
- * Set MPT2SAS_SG_DEPTH value based on user input.
- */
-#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
-#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16
-#define MPT2SAS_SG_DEPTH 16
-#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128
-#define MPT2SAS_SG_DEPTH 128
-#else
-#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
-#endif
-#else
-#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */
-#endif
-
-
-/*
- * Generic Defines
- */
-#define MPT2SAS_SATA_QUEUE_DEPTH 32
-#define MPT2SAS_SAS_QUEUE_DEPTH 254
-#define MPT2SAS_RAID_QUEUE_DEPTH 128
-
-#define MPT_NAME_LENGTH 32 /* generic length of strings */
-#define MPT_STRING_LENGTH 64
-
-#define MPT_MAX_CALLBACKS 16
-
-
-#define CAN_SLEEP 1
-#define NO_SLEEP 0
-
-#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */
-
-#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/
-
-#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF
-
-
-/*
- * reset phases
- */
-#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */
-#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */
-#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */
-
-/*
- * logging format
- */
-#define MPT2SAS_FMT "%s: "
-#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT
-#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT
-#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT
-#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT
-
-/*
- * Dell HBA branding
- */
-#define MPT2SAS_DELL_BRANDING_SIZE 32
-
-#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA"
-#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter"
-#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated"
-#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular"
-#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded"
-#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200"
-#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS"
-
-/*
- * Dell HBA SSDIDs
- */
-#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C
-#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D
-#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E
-#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F
-#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20
-#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21
-#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22
-
-/*
- * Intel HBA branding
- */
-#define MPT2SAS_INTEL_RMS25JB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25JB080"
-#define MPT2SAS_INTEL_RMS25JB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25JB040"
-#define MPT2SAS_INTEL_RMS25KB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25KB080"
-#define MPT2SAS_INTEL_RMS25KB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25KB040"
-#define MPT2SAS_INTEL_RMS25LB040_BRANDING \
- "Intel(R) Integrated RAID Module RMS25LB040"
-#define MPT2SAS_INTEL_RMS25LB080_BRANDING \
- "Intel(R) Integrated RAID Module RMS25LB080"
-#define MPT2SAS_INTEL_RMS2LL080_BRANDING \
- "Intel Integrated RAID Module RMS2LL080"
-#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
- "Intel Integrated RAID Module RMS2LL040"
-#define MPT2SAS_INTEL_RS25GB008_BRANDING \
- "Intel(R) RAID Controller RS25GB008"
-#define MPT2SAS_INTEL_SSD910_BRANDING \
- "Intel(R) SSD 910 Series"
-/*
- * Intel HBA SSDIDs
- */
-#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516
-#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517
-#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518
-#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519
-#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A
-#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B
-#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
-#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
-#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000
-#define MPT2SAS_INTEL_SSD910_SSDID 0x3700
-
-/*
- * HP HBA branding
- */
-#define MPT2SAS_HP_3PAR_SSVID 0x1590
-#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter"
-#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter"
-#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter"
-#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter"
-#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter"
-
-/*
- * HO HBA SSDIDs
- */
-#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041
-#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042
-#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043
-#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044
-#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046
-
-/*
- * WarpDrive Specific Log codes
- */
-
-#define MPT2_WARPDRIVE_LOGENTRY (0x8002)
-#define MPT2_WARPDRIVE_LC_SSDT (0x41)
-#define MPT2_WARPDRIVE_LC_SSDLW (0x43)
-#define MPT2_WARPDRIVE_LC_SSDLF (0x44)
-#define MPT2_WARPDRIVE_LC_BRMF (0x4D)
-
-/*
- * per target private data
- */
-#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
-#define MPT_TARGET_FLAGS_VOLUME 0x02
-#define MPT_TARGET_FLAGS_DELETED 0x04
-
-/**
- * struct MPT2SAS_TARGET - starget private hostdata
- * @starget: starget object
- * @sas_address: target sas address
- * @raid_device: raid_device pointer to access volume data
- * @handle: device handle
- * @num_luns: number luns
- * @flags: MPT_TARGET_FLAGS_XXX flags
- * @deleted: target flaged for deletion
- * @tm_busy: target is busy with TM request.
- * @sdev: The sas_device associated with this target
- */
-struct MPT2SAS_TARGET {
- struct scsi_target *starget;
- u64 sas_address;
- struct _raid_device *raid_device;
- u16 handle;
- int num_luns;
- u32 flags;
- u8 deleted;
- u8 tm_busy;
- struct _sas_device *sdev;
-};
-
-
-/*
- * per device private data
- */
-#define MPT_DEVICE_FLAGS_INIT 0x01
-#define MPT_DEVICE_TLR_ON 0x02
-
-/**
- * struct MPT2SAS_DEVICE - sdev private hostdata
- * @sas_target: starget private hostdata
- * @lun: lun number
- * @flags: MPT_DEVICE_XXX flags
- * @configured_lun: lun is configured
- * @block: device is in SDEV_BLOCK state
- * @tlr_snoop_check: flag used in determining whether to disable TLR
- */
-
-/* OEM Identifiers */
-#define MFG10_OEM_ID_INVALID (0x00000000)
-#define MFG10_OEM_ID_DELL (0x00000001)
-#define MFG10_OEM_ID_FSC (0x00000002)
-#define MFG10_OEM_ID_SUN (0x00000003)
-#define MFG10_OEM_ID_IBM (0x00000004)
-
-/* GENERIC Flags 0*/
-#define MFG10_GF0_OCE_DISABLED (0x00000001)
-#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002)
-#define MFG10_GF0_R10_DISPLAY (0x00000004)
-#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008)
-#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010)
-
-/* OEM Specific Flags will come from OEM specific header files */
-typedef struct _MPI2_CONFIG_PAGE_MAN_10 {
- MPI2_CONFIG_PAGE_HEADER Header; /* 00h */
- U8 OEMIdentifier; /* 04h */
- U8 Reserved1; /* 05h */
- U16 Reserved2; /* 08h */
- U32 Reserved3; /* 0Ch */
- U32 GenericFlags0; /* 10h */
- U32 GenericFlags1; /* 14h */
- U32 Reserved4; /* 18h */
- U32 OEMSpecificFlags0; /* 1Ch */
- U32 OEMSpecificFlags1; /* 20h */
- U32 Reserved5[18]; /* 24h-60h*/
-} MPI2_CONFIG_PAGE_MAN_10,
- MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10,
- Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t;
-
-#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003)
-#define MFG_PAGE10_HIDE_ALL_DISKS (0x00)
-#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01)
-#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02)
-
-
-struct MPT2SAS_DEVICE {
- struct MPT2SAS_TARGET *sas_target;
- unsigned int lun;
- u32 flags;
- u8 configured_lun;
- u8 block;
- u8 tlr_snoop_check;
-};
-
-#define MPT2_CMD_NOT_USED 0x8000 /* free */
-#define MPT2_CMD_COMPLETE 0x0001 /* completed */
-#define MPT2_CMD_PENDING 0x0002 /* pending */
-#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */
-#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */
-
-/**
- * struct _internal_cmd - internal commands struct
- * @mutex: mutex
- * @done: completion
- * @reply: reply message pointer
- * @sense: sense data
- * @status: MPT2_CMD_XXX status
- * @smid: system message id
- */
-struct _internal_cmd {
- struct mutex mutex;
- struct completion done;
- void *reply;
- void *sense;
- u16 status;
- u16 smid;
-};
-
-
-/**
- * struct _sas_device - attached device information
- * @list: sas device list
- * @starget: starget object
- * @sas_address: device sas address
- * @device_name: retrieved from the SAS IDENTIFY frame.
- * @handle: device handle
- * @sas_address_parent: sas address of parent expander or sas host
- * @enclosure_handle: enclosure handle
- * @enclosure_logical_id: enclosure logical identifier
- * @volume_handle: volume handle (valid when hidden raid member)
- * @volume_wwid: volume unique identifier
- * @device_info: bitfield provides detailed info about the device
- * @id: target id
- * @channel: target channel
- * @slot: number number
- * @phy: phy identifier provided in sas device page 0
- * @responding: used in _scsih_sas_device_mark_responding
- * @pfa_led_on: flag for PFA LED status
- */
-struct _sas_device {
- struct list_head list;
- struct scsi_target *starget;
- u64 sas_address;
- u64 device_name;
- u16 handle;
- u64 sas_address_parent;
- u16 enclosure_handle;
- u64 enclosure_logical_id;
- u16 volume_handle;
- u64 volume_wwid;
- u32 device_info;
- int id;
- int channel;
- u16 slot;
- u8 phy;
- u8 responding;
- u8 pfa_led_on;
- struct kref refcount;
-};
-
-static inline void sas_device_get(struct _sas_device *s)
-{
- kref_get(&s->refcount);
-}
-
-static inline void sas_device_free(struct kref *r)
-{
- kfree(container_of(r, struct _sas_device, refcount));
-}
-
-static inline void sas_device_put(struct _sas_device *s)
-{
- kref_put(&s->refcount, sas_device_free);
-}
-
-/**
- * struct _raid_device - raid volume link list
- * @list: sas device list
- * @starget: starget object
- * @sdev: scsi device struct (volumes are single lun)
- * @wwid: unique identifier for the volume
- * @handle: device handle
- * @block_size: Block size of the volume
- * @id: target id
- * @channel: target channel
- * @volume_type: the raid level
- * @device_info: bitfield provides detailed info about the hidden components
- * @num_pds: number of hidden raid components
- * @responding: used in _scsih_raid_device_mark_responding
- * @percent_complete: resync percent complete
- * @direct_io_enabled: Whether direct io to PDs are allowed or not
- * @stripe_exponent: X where 2powX is the stripe sz in blocks
- * @block_exponent: X where 2powX is the block sz in bytes
- * @max_lba: Maximum number of LBA in the volume
- * @stripe_sz: Stripe Size of the volume
- * @device_info: Device info of the volume member disk
- * @pd_handle: Array of handles of the physical drives for direct I/O in le16
- */
-#define MPT_MAX_WARPDRIVE_PDS 8
-struct _raid_device {
- struct list_head list;
- struct scsi_target *starget;
- struct scsi_device *sdev;
- u64 wwid;
- u16 handle;
- u16 block_sz;
- int id;
- int channel;
- u8 volume_type;
- u8 num_pds;
- u8 responding;
- u8 percent_complete;
- u8 direct_io_enabled;
- u8 stripe_exponent;
- u8 block_exponent;
- u64 max_lba;
- u32 stripe_sz;
- u32 device_info;
- u16 pd_handle[MPT_MAX_WARPDRIVE_PDS];
-};
-
-/**
- * struct _boot_device - boot device info
- * @is_raid: flag to indicate whether this is volume
- * @device: holds pointer for either struct _sas_device or
- * struct _raid_device
- */
-struct _boot_device {
- u8 is_raid;
- void *device;
-};
-
-/**
- * struct _sas_port - wide/narrow sas port information
- * @port_list: list of ports belonging to expander
- * @num_phys: number of phys belonging to this port
- * @remote_identify: attached device identification
- * @rphy: sas transport rphy object
- * @port: sas transport wide/narrow port object
- * @phy_list: _sas_phy list objects belonging to this port
- */
-struct _sas_port {
- struct list_head port_list;
- u8 num_phys;
- struct sas_identify remote_identify;
- struct sas_rphy *rphy;
- struct sas_port *port;
- struct list_head phy_list;
-};
-
-/**
- * struct _sas_phy - phy information
- * @port_siblings: list of phys belonging to a port
- * @identify: phy identification
- * @remote_identify: attached device identification
- * @phy: sas transport phy object
- * @phy_id: unique phy id
- * @handle: device handle for this phy
- * @attached_handle: device handle for attached device
- * @phy_belongs_to_port: port has been created for this phy
- */
-struct _sas_phy {
- struct list_head port_siblings;
- struct sas_identify identify;
- struct sas_identify remote_identify;
- struct sas_phy *phy;
- u8 phy_id;
- u16 handle;
- u16 attached_handle;
- u8 phy_belongs_to_port;
-};
-
-/**
- * struct _sas_node - sas_host/expander information
- * @list: list of expanders
- * @parent_dev: parent device class
- * @num_phys: number phys belonging to this sas_host/expander
- * @sas_address: sas address of this sas_host/expander
- * @handle: handle for this sas_host/expander
- * @sas_address_parent: sas address of parent expander or sas host
- * @enclosure_handle: handle for this a member of an enclosure
- * @device_info: bitwise defining capabilities of this sas_host/expander
- * @responding: used in _scsih_expander_device_mark_responding
- * @phy: a list of phys that make up this sas_host/expander
- * @sas_port_list: list of ports attached to this sas_host/expander
- */
-struct _sas_node {
- struct list_head list;
- struct device *parent_dev;
- u8 num_phys;
- u64 sas_address;
- u16 handle;
- u64 sas_address_parent;
- u16 enclosure_handle;
- u64 enclosure_logical_id;
- u8 responding;
- struct _sas_phy *phy;
- struct list_head sas_port_list;
-};
-
-/**
- * enum reset_type - reset state
- * @FORCE_BIG_HAMMER: issue diagnostic reset
- * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer
- */
-enum reset_type {
- FORCE_BIG_HAMMER,
- SOFT_RESET,
-};
-
-/**
- * struct chain_tracker - firmware chain tracker
- * @chain_buffer: chain buffer
- * @chain_buffer_dma: physical address
- * @tracker_list: list of free request (ioc->free_chain_list)
- */
-struct chain_tracker {
- void *chain_buffer;
- dma_addr_t chain_buffer_dma;
- struct list_head tracker_list;
-};
-
-/**
- * struct scsiio_tracker - scsi mf request tracker
- * @smid: system message id
- * @scmd: scsi request pointer
- * @cb_idx: callback index
- * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
- * @chain_list: list of chains associated to this IO
- * @tracker_list: list of free request (ioc->free_list)
- */
-struct scsiio_tracker {
- u16 smid;
- struct scsi_cmnd *scmd;
- u8 cb_idx;
- u8 direct_io;
- struct list_head chain_list;
- struct list_head tracker_list;
-};
-
-/**
- * struct request_tracker - firmware request tracker
- * @smid: system message id
- * @cb_idx: callback index
- * @tracker_list: list of free request (ioc->free_list)
- */
-struct request_tracker {
- u16 smid;
- u8 cb_idx;
- struct list_head tracker_list;
-};
-
-/**
- * struct _tr_list - target reset list
- * @handle: device handle
- * @state: state machine
- */
-struct _tr_list {
- struct list_head list;
- u16 handle;
- u16 state;
-};
-
-typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
-
-/**
- * struct adapter_reply_queue - the reply queue struct
- * @ioc: per adapter object
- * @msix_index: msix index into vector table
- * @vector: irq vector
- * @reply_post_host_index: head index in the pool where FW completes IO
- * @reply_post_free: reply post base virt address
- * @name: the name registered to request_irq()
- * @busy: isr is actively processing replies on another cpu
- * @list: this list
-*/
-struct adapter_reply_queue {
- struct MPT2SAS_ADAPTER *ioc;
- u8 msix_index;
- unsigned int vector;
- u32 reply_post_host_index;
- Mpi2ReplyDescriptorsUnion_t *reply_post_free;
- char name[MPT_NAME_LENGTH];
- atomic_t busy;
- cpumask_var_t affinity_hint;
- struct list_head list;
-};
-
-/* IOC Facts and Port Facts converted from little endian to cpu */
-union mpi2_version_union {
- MPI2_VERSION_STRUCT Struct;
- u32 Word;
-};
-
-struct mpt2sas_facts {
- u16 MsgVersion;
- u16 HeaderVersion;
- u8 IOCNumber;
- u8 VP_ID;
- u8 VF_ID;
- u16 IOCExceptions;
- u16 IOCStatus;
- u32 IOCLogInfo;
- u8 MaxChainDepth;
- u8 WhoInit;
- u8 NumberOfPorts;
- u8 MaxMSIxVectors;
- u16 RequestCredit;
- u16 ProductID;
- u32 IOCCapabilities;
- union mpi2_version_union FWVersion;
- u16 IOCRequestFrameSize;
- u16 Reserved3;
- u16 MaxInitiators;
- u16 MaxTargets;
- u16 MaxSasExpanders;
- u16 MaxEnclosures;
- u16 ProtocolFlags;
- u16 HighPriorityCredit;
- u16 MaxReplyDescriptorPostQueueDepth;
- u8 ReplyFrameSize;
- u8 MaxVolumes;
- u16 MaxDevHandle;
- u16 MaxPersistentEntries;
- u16 MinDevHandle;
-};
-
-struct mpt2sas_port_facts {
- u8 PortNumber;
- u8 VP_ID;
- u8 VF_ID;
- u8 PortType;
- u16 MaxPostedCmdBuffers;
-};
-
-struct reply_post_struct {
- Mpi2ReplyDescriptorsUnion_t *reply_post_free;
- dma_addr_t reply_post_free_dma;
-};
-
-/**
- * enum mutex_type - task management mutex type
- * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it
- * @TM_MUTEX_ON: mutex is required
- */
-enum mutex_type {
- TM_MUTEX_OFF = 0,
- TM_MUTEX_ON = 1,
-};
-
-typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
-/**
- * struct MPT2SAS_ADAPTER - per adapter struct
- * @list: ioc_list
- * @shost: shost object
- * @id: unique adapter id
- * @cpu_count: number online cpus
- * @name: generic ioc string
- * @tmp_string: tmp string used for logging
- * @pdev: pci pdev object
- * @chip: memory mapped register space
- * @chip_phys: physical addrss prior to mapping
- * @logging_level: see mpt2sas_debug.h
- * @fwfault_debug: debuging FW timeouts
- * @ir_firmware: IR firmware present
- * @bars: bitmask of BAR's that must be configured
- * @mask_interrupts: ignore interrupt
- * @dma_mask: used to set the consistent dma mask
- * @fault_reset_work_q_name: fw fault work queue
- * @fault_reset_work_q: ""
- * @fault_reset_work: ""
- * @firmware_event_name: fw event work queue
- * @firmware_event_thread: ""
- * @fw_events_off: flag to turn off fw event handling
- * @fw_event_lock:
- * @fw_event_list: list of fw events
- * @aen_event_read_flag: event log was read
- * @broadcast_aen_busy: broadcast aen waiting to be serviced
- * @shost_recovery: host reset in progress
- * @ioc_reset_in_progress_lock:
- * @ioc_link_reset_in_progress: phy/hard reset in progress
- * @ignore_loginfos: ignore loginfos during task management
- * @remove_host: flag for when driver unloads, to avoid sending dev resets
- * @pci_error_recovery: flag to prevent ioc access until slot reset completes
- * @wait_for_discovery_to_complete: flag set at driver load time when
- * waiting on reporting devices
- * @is_driver_loading: flag set at driver load time
- * @port_enable_failed: flag set when port enable has failed
- * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work
- * @start_scan_failed: means port enable failed, return's the ioc_status
- * @msix_enable: flag indicating msix is enabled
- * @msix_vector_count: number msix vectors
- * @cpu_msix_table: table for mapping cpus to msix index
- * @cpu_msix_table_sz: table size
- * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands
- * @scsi_io_cb_idx: shost generated commands
- * @tm_cb_idx: task management commands
- * @scsih_cb_idx: scsih internal commands
- * @transport_cb_idx: transport internal commands
- * @ctl_cb_idx: clt internal commands
- * @base_cb_idx: base internal commands
- * @config_cb_idx: base internal commands
- * @tm_tr_cb_idx : device removal target reset handshake
- * @tm_tr_volume_cb_idx : volume removal target reset
- * @base_cmds:
- * @transport_cmds:
- * @scsih_cmds:
- * @tm_cmds:
- * @ctl_cmds:
- * @config_cmds:
- * @base_add_sg_single: handler for either 32/64 bit sgl's
- * @event_type: bits indicating which events to log
- * @event_context: unique id for each logged event
- * @event_log: event log pointer
- * @event_masks: events that are masked
- * @facts: static facts data
- * @pfacts: static port facts data
- * @manu_pg0: static manufacturing page 0
- * @manu_pg10: static manufacturing page 10
- * @bios_pg2: static bios page 2
- * @bios_pg3: static bios page 3
- * @ioc_pg8: static ioc page 8
- * @iounit_pg0: static iounit page 0
- * @iounit_pg1: static iounit page 1
- * @iounit_pg8: static iounit page 8
- * @sas_hba: sas host object
- * @sas_expander_list: expander object list
- * @sas_node_lock:
- * @sas_device_list: sas device object list
- * @sas_device_init_list: sas device object list (used only at init time)
- * @sas_device_lock:
- * @io_missing_delay: time for IO completed by fw when PDR enabled
- * @device_missing_delay: time for device missing by fw when PDR enabled
- * @sas_id : used for setting volume target IDs
- * @blocking_handles: bitmask used to identify which devices need blocking
- * @pd_handles : bitmask for PD handles
- * @pd_handles_sz : size of pd_handle bitmask
- * @config_page_sz: config page size
- * @config_page: reserve memory for config page payload
- * @config_page_dma:
- * @hba_queue_depth: hba request queue depth
- * @sge_size: sg element size for either 32/64 bit
- * @scsiio_depth: SCSI_IO queue depth
- * @request_sz: per request frame size
- * @request: pool of request frames
- * @request_dma:
- * @request_dma_sz:
- * @scsi_lookup: firmware request tracker list
- * @scsi_lookup_lock:
- * @free_list: free list of request
- * @chain: pool of chains
- * @pending_io_count:
- * @reset_wq:
- * @chain_dma:
- * @max_sges_in_main_message: number sg elements in main message
- * @max_sges_in_chain_message: number sg elements per chain
- * @chains_needed_per_io: max chains per io
- * @chain_offset_value_for_main_message: location 1st sg in main
- * @chain_depth: total chains allocated
- * @hi_priority_smid:
- * @hi_priority:
- * @hi_priority_dma:
- * @hi_priority_depth:
- * @hpr_lookup:
- * @hpr_free_list:
- * @internal_smid:
- * @internal:
- * @internal_dma:
- * @internal_depth:
- * @internal_lookup:
- * @internal_free_list:
- * @sense: pool of sense
- * @sense_dma:
- * @sense_dma_pool:
- * @reply_depth: hba reply queue depth:
- * @reply_sz: per reply frame size:
- * @reply: pool of replys:
- * @reply_dma:
- * @reply_dma_pool:
- * @reply_free_queue_depth: reply free depth
- * @reply_free: pool for reply free queue (32 bit addr)
- * @reply_free_dma:
- * @reply_free_dma_pool:
- * @reply_free_host_index: tail index in pool to insert free replys
- * @reply_post_queue_depth: reply post queue depth
- * @reply_post_struct: struct for reply_post_free physical & virt address
- * @rdpq_array_capable: FW supports multiple reply queue addresses in ioc_init
- * @rdpq_array_enable: rdpq_array support is enabled in the driver
- * @rdpq_array_enable_assigned: this ensures that rdpq_array_enable flag
- * is assigned only ones
- * @reply_queue_count: number of reply queue's
- * @reply_queue_list: link list contaning the reply queue info
- * @reply_post_host_index: head index in the pool where FW completes IO
- * @delayed_tr_list: target reset link list
- * @delayed_tr_volume_list: volume target reset link list
- * @@temp_sensors_count: flag to carry the number of temperature sensors
- * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
- * pci resource handling. PCI resource freeing will lead to free
- * vital hardware/memory resource, which might be in use by cli/sysfs
- * path functions resulting in Null pointer reference followed by kernel
- * crash. To avoid the above race condition we use mutex syncrhonization
- * which ensures the syncrhonization between cli/sysfs_show path
- */
-struct MPT2SAS_ADAPTER {
- struct list_head list;
- struct Scsi_Host *shost;
- u8 id;
- int cpu_count;
- char name[MPT_NAME_LENGTH];
- char tmp_string[MPT_STRING_LENGTH];
- struct pci_dev *pdev;
- Mpi2SystemInterfaceRegs_t __iomem *chip;
- resource_size_t chip_phys;
- int logging_level;
- int fwfault_debug;
- u8 ir_firmware;
- int bars;
- u8 mask_interrupts;
- int dma_mask;
-
- /* fw fault handler */
- char fault_reset_work_q_name[20];
- struct workqueue_struct *fault_reset_work_q;
- struct delayed_work fault_reset_work;
-
- /* fw event handler */
- char firmware_event_name[20];
- struct workqueue_struct *firmware_event_thread;
- spinlock_t fw_event_lock;
- struct list_head fw_event_list;
-
- /* misc flags */
- int aen_event_read_flag;
- u8 broadcast_aen_busy;
- u16 broadcast_aen_pending;
- u8 shost_recovery;
-
- struct mutex reset_in_progress_mutex;
- spinlock_t ioc_reset_in_progress_lock;
- u8 ioc_link_reset_in_progress;
- u8 ioc_reset_in_progress_status;
-
- u8 ignore_loginfos;
- u8 remove_host;
- u8 pci_error_recovery;
- u8 wait_for_discovery_to_complete;
- struct completion port_enable_done;
- u8 is_driver_loading;
- u8 port_enable_failed;
-
- u8 start_scan;
- u16 start_scan_failed;
-
- u8 msix_enable;
- u16 msix_vector_count;
- u8 *cpu_msix_table;
- resource_size_t __iomem **reply_post_host_index;
- u16 cpu_msix_table_sz;
- u32 ioc_reset_count;
- MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
- u32 non_operational_loop;
-
- /* internal commands, callback index */
- u8 scsi_io_cb_idx;
- u8 tm_cb_idx;
- u8 transport_cb_idx;
- u8 scsih_cb_idx;
- u8 ctl_cb_idx;
- u8 base_cb_idx;
- u8 port_enable_cb_idx;
- u8 config_cb_idx;
- u8 tm_tr_cb_idx;
- u8 tm_tr_volume_cb_idx;
- u8 tm_sas_control_cb_idx;
- struct _internal_cmd base_cmds;
- struct _internal_cmd port_enable_cmds;
- struct _internal_cmd transport_cmds;
- struct _internal_cmd scsih_cmds;
- struct _internal_cmd tm_cmds;
- struct _internal_cmd ctl_cmds;
- struct _internal_cmd config_cmds;
-
- MPT_ADD_SGE base_add_sg_single;
-
- /* event log */
- u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
- u32 event_context;
- void *event_log;
- u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
-
- /* static config pages */
- struct mpt2sas_facts facts;
- struct mpt2sas_port_facts *pfacts;
- Mpi2ManufacturingPage0_t manu_pg0;
- Mpi2BiosPage2_t bios_pg2;
- Mpi2BiosPage3_t bios_pg3;
- Mpi2IOCPage8_t ioc_pg8;
- Mpi2IOUnitPage0_t iounit_pg0;
- Mpi2IOUnitPage1_t iounit_pg1;
- Mpi2IOUnitPage8_t iounit_pg8;
-
- struct _boot_device req_boot_device;
- struct _boot_device req_alt_boot_device;
- struct _boot_device current_boot_device;
-
- /* sas hba, expander, and device list */
- struct _sas_node sas_hba;
- struct list_head sas_expander_list;
- spinlock_t sas_node_lock;
- struct list_head sas_device_list;
- struct list_head sas_device_init_list;
- spinlock_t sas_device_lock;
- struct list_head raid_device_list;
- spinlock_t raid_device_lock;
- u8 io_missing_delay;
- u16 device_missing_delay;
- int sas_id;
- void *blocking_handles;
- void *pd_handles;
- u16 pd_handles_sz;
-
- /* config page */
- u16 config_page_sz;
- void *config_page;
- dma_addr_t config_page_dma;
-
- /* scsiio request */
- u16 hba_queue_depth;
- u16 sge_size;
- u16 scsiio_depth;
- u16 request_sz;
- u8 *request;
- dma_addr_t request_dma;
- u32 request_dma_sz;
- struct scsiio_tracker *scsi_lookup;
- ulong scsi_lookup_pages;
- spinlock_t scsi_lookup_lock;
- struct list_head free_list;
- int pending_io_count;
- wait_queue_head_t reset_wq;
-
- /* chain */
- struct chain_tracker *chain_lookup;
- struct list_head free_chain_list;
- struct dma_pool *chain_dma_pool;
- ulong chain_pages;
- u16 max_sges_in_main_message;
- u16 max_sges_in_chain_message;
- u16 chains_needed_per_io;
- u16 chain_offset_value_for_main_message;
- u32 chain_depth;
-
- /* hi-priority queue */
- u16 hi_priority_smid;
- u8 *hi_priority;
- dma_addr_t hi_priority_dma;
- u16 hi_priority_depth;
- struct request_tracker *hpr_lookup;
- struct list_head hpr_free_list;
-
- /* internal queue */
- u16 internal_smid;
- u8 *internal;
- dma_addr_t internal_dma;
- u16 internal_depth;
- struct request_tracker *internal_lookup;
- struct list_head internal_free_list;
-
- /* sense */
- u8 *sense;
- dma_addr_t sense_dma;
- struct dma_pool *sense_dma_pool;
-
- /* reply */
- u16 reply_sz;
- u8 *reply;
- dma_addr_t reply_dma;
- u32 reply_dma_max_address;
- u32 reply_dma_min_address;
- struct dma_pool *reply_dma_pool;
-
- /* reply free queue */
- u16 reply_free_queue_depth;
- __le32 *reply_free;
- dma_addr_t reply_free_dma;
- struct dma_pool *reply_free_dma_pool;
- u32 reply_free_host_index;
-
- /* reply post queue */
- u16 reply_post_queue_depth;
- struct reply_post_struct *reply_post;
- u8 rdpq_array_capable;
- u8 rdpq_array_enable;
- u8 rdpq_array_enable_assigned;
- struct dma_pool *reply_post_free_dma_pool;
- u8 reply_queue_count;
- struct list_head reply_queue_list;
-
- struct list_head delayed_tr_list;
- struct list_head delayed_tr_volume_list;
- u8 temp_sensors_count;
-
- /* diag buffer support */
- u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
- dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT];
- u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT];
- Mpi2ManufacturingPage10_t manu_pg10;
- u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23];
- u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
- u32 ring_buffer_offset;
- u32 ring_buffer_sz;
- u8 is_warpdrive;
- u8 hide_ir_msg;
- u8 mfg_pg10_hide_flag;
- u8 hide_drives;
-
- struct mutex pci_access_mutex;
-};
-
-typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-
-
-/* base shared API */
-extern struct list_head mpt2sas_ioc_list;
-/* spinlock on list operations over IOCs
- * Case: when multiple warpdrive cards(IOCs) are in use
- * Each IOC will added to the ioc list stucture on initialization.
- * Watchdog threads run at regular intervals to check IOC for any
- * fault conditions which will trigger the dead_ioc thread to
- * deallocate pci resource, resulting deleting the IOC netry from list,
- * this deletion need to protected by spinlock to enusre that
- * ioc removal is syncrhonized, if not synchronized it might lead to
- * list_del corruption as the ioc list is traversed in cli path
- */
-extern spinlock_t gioc_lock;
-void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc);
-
-int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc);
-int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc);
-int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
- enum reset_type type);
-
-void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr);
-__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
- u16 smid);
-void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc);
-
-/* hi-priority queue */
-u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
-u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
- struct scsi_cmnd *scmd);
-
-u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
-void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u16 handle);
-void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u16 io_index);
-void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_initialize_callback_handler(void);
-u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
-void mpt2sas_base_release_callback_handler(u8 cb_idx);
-
-u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-u8 mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 msix_index, u32 reply);
-void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
-
-u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
-
-void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code);
-int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t
- *mpi_request);
-int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
- Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request);
-void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type);
-
-void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc);
-
-void mpt2sas_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc,
- u16 device_missing_delay, u8 io_missing_delay);
-
-int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc);
-
-/* scsih shared API */
-void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply);
-int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- uint channel, uint id, uint lun, u8 type, u16 smid_task,
- ulong timeout, enum mutex_type m_type);
-void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
-void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
-void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address);
-struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc,
- u16 handle);
-struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER
- *ioc, u64 sas_address);
-struct _sas_device *mpt2sas_get_sdev_by_addr(
- struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-struct _sas_device *__mpt2sas_get_sdev_by_addr(
- struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-
-void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc);
-void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-
-/* config shared API */
-u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
-int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
-int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page);
-int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage2_t *config_page);
-int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage3_t *config_page);
-int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage0_t *config_page);
-int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz);
-int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage1_t *config_page);
-int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOUnitPage1_t *config_page);
-int mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page);
-int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
-int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
-int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz);
-int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2IOCPage8_t *config_page);
-int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle);
-int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number);
-int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number);
-int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle);
-int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds);
-int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz);
-int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
- u32 form_specific);
-int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
- u16 *volume_handle);
-int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
- u64 *wwid);
-/* ctl shared API */
-extern struct device_attribute *mpt2sas_host_attrs[];
-extern struct device_attribute *mpt2sas_dev_attrs[];
-void mpt2sas_ctl_init(void);
-void mpt2sas_ctl_exit(void);
-u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply);
-void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply);
-
-void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc,
- u8 bits_to_regsiter);
-
-/* transport shared API */
-u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply);
-struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, u64 sas_address);
-void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u64 sas_address_parent);
-int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev);
-int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev);
-void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, u16 handle, u8 phy_number, u8 link_rate);
-extern struct sas_function_template mpt2sas_transport_functions;
-extern struct scsi_transport_template *mpt2sas_transport_template;
-extern int scsi_internal_device_block(struct scsi_device *sdev);
-extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc,
- u8 msix_index, u32 reply);
-extern int scsi_internal_device_unblock(struct scsi_device *sdev,
- enum scsi_device_state new_state);
-
-#endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
deleted file mode 100644
index c43815b..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ /dev/null
@@ -1,1527 +0,0 @@
-/*
- * This module provides common API for accessing firmware configuration pages
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/blkdev.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include "mpt2sas_base.h"
-
-/* local definitions */
-
-/* Timeout for config page request (in seconds) */
-#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15
-
-/* Common sgl flags for READING a config page. */
-#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
- | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT)
-
-/* Common sgl flags for WRITING a config page. */
-#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \
- | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \
- << MPI2_SGE_FLAGS_SHIFT)
-
-/**
- * struct config_request - obtain dma memory via routine
- * @sz: size
- * @page: virt pointer
- * @page_dma: phys pointer
- *
- */
-struct config_request{
- u16 sz;
- void *page;
- dma_addr_t page_dma;
-};
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _config_display_some_debug - debug routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @calling_function_name: string pass from calling function
- * @mpi_reply: reply message frame
- * Context: none.
- *
- * Function for displaying debug info helpful when debugging issues
- * in this module.
- */
-static void
-_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
-{
- Mpi2ConfigRequest_t *mpi_request;
- char *desc = NULL;
-
- if (!(ioc->logging_level & MPT_DEBUG_CONFIG))
- return;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) {
- case MPI2_CONFIG_PAGETYPE_IO_UNIT:
- desc = "io_unit";
- break;
- case MPI2_CONFIG_PAGETYPE_IOC:
- desc = "ioc";
- break;
- case MPI2_CONFIG_PAGETYPE_BIOS:
- desc = "bios";
- break;
- case MPI2_CONFIG_PAGETYPE_RAID_VOLUME:
- desc = "raid_volume";
- break;
- case MPI2_CONFIG_PAGETYPE_MANUFACTURING:
- desc = "manufaucturing";
- break;
- case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK:
- desc = "physdisk";
- break;
- case MPI2_CONFIG_PAGETYPE_EXTENDED:
- switch (mpi_request->ExtPageType) {
- case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT:
- desc = "sas_io_unit";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER:
- desc = "sas_expander";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE:
- desc = "sas_device";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY:
- desc = "sas_phy";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_LOG:
- desc = "log";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE:
- desc = "enclosure";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG:
- desc = "raid_config";
- break;
- case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING:
- desc = "driver_mapping";
- break;
- }
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), "
- "smid(%d)\n", ioc->name, calling_function_name, desc,
- mpi_request->Header.PageNumber, mpi_request->Action,
- le32_to_cpu(mpi_request->PageAddress), smid);
-
- if (!mpi_reply)
- return;
-
- if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_INFO_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
-}
-#endif
-
-/**
- * _config_alloc_config_dma_memory - obtain physical memory
- * @ioc: per adapter object
- * @mem: struct config_request
- *
- * A wrapper for obtaining dma-able memory for config page request.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
- struct config_request *mem)
-{
- int r = 0;
-
- if (mem->sz > ioc->config_page_sz) {
- mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz,
- &mem->page_dma, GFP_KERNEL);
- if (!mem->page) {
- printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent"
- " failed asking for (%d) bytes!!\n",
- ioc->name, __func__, mem->sz);
- r = -ENOMEM;
- }
- } else { /* use tmp buffer if less than 512 bytes */
- mem->page = ioc->config_page;
- mem->page_dma = ioc->config_page_dma;
- }
- return r;
-}
-
-/**
- * _config_free_config_dma_memory - wrapper to free the memory
- * @ioc: per adapter object
- * @mem: struct config_request
- *
- * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static void
-_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
- struct config_request *mem)
-{
- if (mem->sz > ioc->config_page_sz)
- dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page,
- mem->page_dma);
-}
-
-/**
- * mpt2sas_config_done - config page completion routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: none.
- *
- * The callback handler when using _config_request.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
-
- if (ioc->config_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->config_cmds.smid != smid)
- return 1;
- ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID;
- memcpy(ioc->config_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- }
- ioc->config_cmds.status &= ~MPT2_CMD_PENDING;
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _config_display_some_debug(ioc, smid, "config_done", mpi_reply);
-#endif
- ioc->config_cmds.smid = USHRT_MAX;
- complete(&ioc->config_cmds.done);
- return 1;
-}
-
-/**
- * _config_request - main routine for sending config page requests
- * @ioc: per adapter object
- * @mpi_request: request message frame
- * @mpi_reply: reply mf payload returned from firmware
- * @timeout: timeout in seconds
- * @config_page: contents of the config page
- * @config_page_sz: size of config page
- * Context: sleep
- *
- * A generic API for config page requests to firmware.
- *
- * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling
- * this API.
- *
- * The callback index is set inside `ioc->config_cb_idx.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
- *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout,
- void *config_page, u16 config_page_sz)
-{
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- Mpi2ConfigRequest_t *config_request;
- int r;
- u8 retry_count, issue_host_reset = 0;
- u16 wait_state_count;
- struct config_request mem;
-
- mutex_lock(&ioc->config_cmds.mutex);
- if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n",
- ioc->name, __func__);
- mutex_unlock(&ioc->config_cmds.mutex);
- return -EAGAIN;
- }
-
- retry_count = 0;
- memset(&mem, 0, sizeof(struct config_request));
-
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
-
- if (config_page) {
- mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion;
- mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber;
- mpi_request->Header.PageType = mpi_reply->Header.PageType;
- mpi_request->Header.PageLength = mpi_reply->Header.PageLength;
- mpi_request->ExtPageLength = mpi_reply->ExtPageLength;
- mpi_request->ExtPageType = mpi_reply->ExtPageType;
- if (mpi_request->Header.PageLength)
- mem.sz = mpi_request->Header.PageLength * 4;
- else
- mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4;
- r = _config_alloc_config_dma_memory(ioc, &mem);
- if (r != 0)
- goto out;
- if (mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT ||
- mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) {
- ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
- MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz,
- mem.page_dma);
- memcpy(mem.page, config_page, min_t(u16, mem.sz,
- config_page_sz));
- } else {
- memset(config_page, 0, config_page_sz);
- ioc->base_add_sg_single(&mpi_request->PageBufferSGE,
- MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma);
- }
- }
-
- retry_config:
- if (retry_count) {
- if (retry_count > 2) { /* attempt only 2 retries */
- r = -EFAULT;
- goto free_mem;
- }
- printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n",
- ioc->name, __func__, retry_count);
- }
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- r = -EFAULT;
- goto free_mem;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- r = -EAGAIN;
- goto free_mem;
- }
-
- r = 0;
- memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t));
- ioc->config_cmds.status = MPT2_CMD_PENDING;
- config_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->config_cmds.smid = smid;
- memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _config_display_some_debug(ioc, smid, "config_request", NULL);
-#endif
- init_completion(&ioc->config_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
- timeout*HZ);
- if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2ConfigRequest_t)/4);
- retry_count++;
- if (ioc->config_cmds.smid == smid)
- mpt2sas_base_free_smid(ioc, smid);
- if ((ioc->shost_recovery) || (ioc->config_cmds.status &
- MPT2_CMD_RESET) || ioc->pci_error_recovery)
- goto retry_config;
- issue_host_reset = 1;
- r = -EFAULT;
- goto free_mem;
- }
-
- if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID)
- memcpy(mpi_reply, ioc->config_cmds.reply,
- sizeof(Mpi2ConfigReply_t));
- if (retry_count)
- printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n",
- ioc->name, __func__, retry_count);
- if (config_page && mpi_request->Action ==
- MPI2_CONFIG_ACTION_PAGE_READ_CURRENT)
- memcpy(config_page, mem.page, min_t(u16, mem.sz,
- config_page_sz));
- free_mem:
- if (config_page)
- _config_free_config_dma_memory(ioc, &mem);
- out:
- ioc->config_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->config_cmds.mutex);
-
- if (issue_host_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- return r;
-}
-
-/**
- * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING;
- mpi_request.Header.PageNumber = 10;
- mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_bios_pg2 - obtain bios page 2
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
- mpi_request.Header.PageNumber = 2;
- mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_bios_pg3 - obtain bios page 3
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2BiosPage3_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS;
- mpi_request.Header.PageNumber = 3;
- mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_set_iounit_pg1 - set iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg3 - obtain iounit page 3
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 3;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
- mpi_request.Header.PageNumber = 8;
- mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC;
- mpi_request.Header.PageNumber = 8;
- mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: device handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
- mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION;
- mpi_request.Header.PageNumber = 0;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: device handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE;
- mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION;
- mpi_request.Header.PageNumber = 1;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host
- * @ioc: per adapter object
- * @num_phys: pointer returned with the number of phys
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
- u16 ioc_status;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t config_page;
-
- *num_phys = 0;
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
- sizeof(Mpi2SasIOUnitPage0_t));
- if (!r) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
- *num_phys = config_page.NumPhys;
- }
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Calling function should call config_get_number_hba_phys prior to
- * this function, so enough memory is allocated for config_page.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT;
- _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_expander_pg0 - obtain expander page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_expander_pg1 - obtain expander page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number,
- u16 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM |
- (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: expander handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phy_pg0 - obtain phy page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phy_pg1 - obtain phy page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @phy_number: phy number
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: volume handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form,
- u32 handle)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 1;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume
- * @ioc: per adapter object
- * @handle: volume handle
- * @num_pds: returns pds count
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u8 *num_pds)
-{
- Mpi2ConfigRequest_t mpi_request;
- Mpi2RaidVolPage0_t config_page;
- Mpi2ConfigReply_t mpi_reply;
- int r;
- u16 ioc_status;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- *num_pds = 0;
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress =
- cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page,
- sizeof(Mpi2RaidVolPage0_t));
- if (!r) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS)
- *num_pds = config_page.NumPhysDisks;
- }
-
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_HANDLE or HANDLE
- * @handle: volume handle
- * @sz: size of buffer passed in config_page
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc,
- Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form,
- u32 handle, u16 sz)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | handle);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0
- * @ioc: per adapter object
- * @mpi_reply: reply mf payload returned from firmware
- * @config_page: contents of the config page
- * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE
- * @form_specific: specific to the form
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
- *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form,
- u32 form_specific)
-{
- Mpi2ConfigRequest_t mpi_request;
- int r;
-
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK;
- mpi_request.Header.PageNumber = 0;
- mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.PageAddress = cpu_to_le32(form | form_specific);
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- r = _config_request(ioc, &mpi_request, mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- sizeof(*config_page));
- out:
- return r;
-}
-
-/**
- * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components
- * @ioc: per adapter object
- * @pd_handle: phys disk handle
- * @volume_handle: volume handle
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle,
- u16 *volume_handle)
-{
- Mpi2RaidConfigurationPage0_t *config_page = NULL;
- Mpi2ConfigRequest_t mpi_request;
- Mpi2ConfigReply_t mpi_reply;
- int r, i, config_page_sz;
- u16 ioc_status;
- int config_num;
- u16 element_type;
- u16 phys_disk_dev_handle;
-
- *volume_handle = 0;
- memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
- mpi_request.Function = MPI2_FUNCTION_CONFIG;
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
- mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED;
- mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG;
- mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION;
- mpi_request.Header.PageNumber = 0;
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
- if (r)
- goto out;
-
- mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
- config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4);
- config_page = kmalloc(config_page_sz, GFP_KERNEL);
- if (!config_page) {
- r = -1;
- goto out;
- }
- config_num = 0xff;
- while (1) {
- mpi_request.PageAddress = cpu_to_le32(config_num +
- MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM);
- r = _config_request(ioc, &mpi_request, &mpi_reply,
- MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
- config_page_sz);
- if (r)
- goto out;
- r = -1;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < config_page->NumElements; i++) {
- element_type = le16_to_cpu(config_page->
- ConfigElement[i].ElementFlags) &
- MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
- if (element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT ||
- element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) {
- phys_disk_dev_handle =
- le16_to_cpu(config_page->ConfigElement[i].
- PhysDiskDevHandle);
- if (phys_disk_dev_handle == pd_handle) {
- *volume_handle =
- le16_to_cpu(config_page->
- ConfigElement[i].VolDevHandle);
- r = 0;
- goto out;
- }
- } else if (element_type ==
- MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) {
- *volume_handle = 0;
- r = 0;
- goto out;
- }
- }
- config_num = config_page->ConfigNum;
- }
- out:
- kfree(config_page);
- return r;
-}
-
-/**
- * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle
- * @ioc: per adapter object
- * @volume_handle: volume handle
- * @wwid: volume wwid
- * Context: sleep.
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle,
- u64 *wwid)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2RaidVolPage1_t raid_vol_pg1;
-
- *wwid = 0;
- if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE,
- volume_handle))) {
- *wwid = le64_to_cpu(raid_vol_pg1.WWID);
- return 0;
- } else
- return -1;
-}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
deleted file mode 100644
index 3694b63..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ /dev/null
@@ -1,3101 +0,0 @@
-/*
- * Management Module Support for MPT (Message Passing Technology) based
- * controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/compat.h>
-#include <linux/poll.h>
-
-#include <linux/io.h>
-#include <linux/uaccess.h>
-
-#include "mpt2sas_base.h"
-#include "mpt2sas_ctl.h"
-
-static DEFINE_MUTEX(_ctl_mutex);
-static struct fasync_struct *async_queue;
-static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait);
-
-static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type,
- u8 *issue_reset);
-
-/**
- * enum block_state - blocking state
- * @NON_BLOCKING: non blocking
- * @BLOCKING: blocking
- *
- * These states are for ioctls that need to wait for a response
- * from firmware, so they probably require sleep.
- */
-enum block_state {
- NON_BLOCKING,
- BLOCKING,
-};
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _ctl_sas_device_find_by_handle - sas device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-static struct _sas_device *
-_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device, *r;
-
- r = NULL;
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (sas_device->handle != handle)
- continue;
- r = sas_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _ctl_display_some_debug - debug routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @calling_function_name: string pass from calling function
- * @mpi_reply: reply message frame
- * Context: none.
- *
- * Function for displaying debug info helpful when debugging issues
- * in this module.
- */
-static void
-_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- char *calling_function_name, MPI2DefaultReply_t *mpi_reply)
-{
- Mpi2ConfigRequest_t *mpi_request;
- char *desc = NULL;
-
- if (!(ioc->logging_level & MPT_DEBUG_IOCTL))
- return;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- switch (mpi_request->Function) {
- case MPI2_FUNCTION_SCSI_IO_REQUEST:
- {
- Mpi2SCSIIORequest_t *scsi_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "scsi_io, cmd(0x%02x), cdb_len(%d)",
- scsi_request->CDB.CDB32[0],
- le16_to_cpu(scsi_request->IoFlags) & 0xF);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- desc = "task_mgmt";
- break;
- case MPI2_FUNCTION_IOC_INIT:
- desc = "ioc_init";
- break;
- case MPI2_FUNCTION_IOC_FACTS:
- desc = "ioc_facts";
- break;
- case MPI2_FUNCTION_CONFIG:
- {
- Mpi2ConfigRequest_t *config_request =
- (Mpi2ConfigRequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "config, type(0x%02x), ext_type(0x%02x), number(%d)",
- (config_request->Header.PageType &
- MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType,
- config_request->Header.PageNumber);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_PORT_FACTS:
- desc = "port_facts";
- break;
- case MPI2_FUNCTION_PORT_ENABLE:
- desc = "port_enable";
- break;
- case MPI2_FUNCTION_EVENT_NOTIFICATION:
- desc = "event_notification";
- break;
- case MPI2_FUNCTION_FW_DOWNLOAD:
- desc = "fw_download";
- break;
- case MPI2_FUNCTION_FW_UPLOAD:
- desc = "fw_upload";
- break;
- case MPI2_FUNCTION_RAID_ACTION:
- desc = "raid_action";
- break;
- case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
- {
- Mpi2SCSIIORequest_t *scsi_request =
- (Mpi2SCSIIORequest_t *)mpi_request;
-
- snprintf(ioc->tmp_string, MPT_STRING_LENGTH,
- "raid_pass, cmd(0x%02x), cdb_len(%d)",
- scsi_request->CDB.CDB32[0],
- le16_to_cpu(scsi_request->IoFlags) & 0xF);
- desc = ioc->tmp_string;
- break;
- }
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- desc = "sas_iounit_cntl";
- break;
- case MPI2_FUNCTION_SATA_PASSTHROUGH:
- desc = "sata_pass";
- break;
- case MPI2_FUNCTION_DIAG_BUFFER_POST:
- desc = "diag_buffer_post";
- break;
- case MPI2_FUNCTION_DIAG_RELEASE:
- desc = "diag_release";
- break;
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- desc = "smp_passthrough";
- break;
- }
-
- if (!desc)
- return;
-
- printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n",
- ioc->name, calling_function_name, desc, smid);
-
- if (!mpi_reply)
- return;
-
- if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo)
- printk(MPT2SAS_INFO_FMT
- "\tiocstatus(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- Mpi2SCSIIOReply_t *scsi_reply =
- (Mpi2SCSIIOReply_t *)mpi_reply;
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _ctl_sas_device_find_by_handle(ioc,
- le16_to_cpu(scsi_reply->DevHandle));
- if (sas_device) {
- printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
- "phy(%d)\n", ioc->name, (unsigned long long)
- sas_device->sas_address, sas_device->phy);
- printk(MPT2SAS_WARN_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, sas_device->enclosure_logical_id,
- sas_device->slot);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (scsi_reply->SCSIState || scsi_reply->SCSIStatus)
- printk(MPT2SAS_INFO_FMT
- "\tscsi_state(0x%02x), scsi_status"
- "(0x%02x)\n", ioc->name,
- scsi_reply->SCSIState,
- scsi_reply->SCSIStatus);
- }
-}
-#endif
-
-/**
- * mpt2sas_ctl_done - ctl module completion routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: none.
- *
- * The callback handler when using ioc->ctl_cb_idx.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
- Mpi2SCSIIOReply_t *scsiio_reply;
- const void *sense_data;
- u32 sz;
-
- if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->ctl_cmds.smid != smid)
- return 1;
- ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID;
- /* get sense data */
- if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_reply->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply;
- if (scsiio_reply->SCSIState &
- MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
- le32_to_cpu(scsiio_reply->SenseCount));
- sense_data = mpt2sas_base_get_sense_buffer(ioc,
- smid);
- memcpy(ioc->ctl_cmds.sense, sense_data, sz);
- }
- }
- }
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
-#endif
- ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->ctl_cmds.done);
- return 1;
-}
-
-/**
- * _ctl_check_event_type - determines when an event needs logging
- * @ioc: per adapter object
- * @event: firmware event
- *
- * The bitmask in ioc->event_type[] indicates which events should be
- * be saved in the driver event_log. This bitmask is set by application.
- *
- * Returns 1 when event should be captured, or zero means no match.
- */
-static int
-_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event)
-{
- u16 i;
- u32 desired_event;
-
- if (event >= 128 || !event || !ioc->event_log)
- return 0;
-
- desired_event = (1 << (event % 32));
- if (!desired_event)
- desired_event = 1;
- i = event / 32;
- return desired_event & ioc->event_type[i];
-}
-
-/**
- * mpt2sas_ctl_add_to_event_log - add event
- * @ioc: per adapter object
- * @mpi_reply: reply message frame
- *
- * Return nothing.
- */
-void
-mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventNotificationReply_t *mpi_reply)
-{
- struct MPT2_IOCTL_EVENTS *event_log;
- u16 event;
- int i;
- u32 sz, event_data_sz;
- u8 send_aen = 0;
-
- if (!ioc->event_log)
- return;
-
- event = le16_to_cpu(mpi_reply->Event);
-
- if (_ctl_check_event_type(ioc, event)) {
-
- /* insert entry into circular event_log */
- i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE;
- event_log = ioc->event_log;
- event_log[i].event = event;
- event_log[i].context = ioc->event_context++;
-
- event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4;
- sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE);
- memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE);
- memcpy(event_log[i].data, mpi_reply->EventData, sz);
- send_aen = 1;
- }
-
- /* This aen_event_read_flag flag is set until the
- * application has read the event log.
- * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify.
- */
- if (event == MPI2_EVENT_LOG_ENTRY_ADDED ||
- (send_aen && !ioc->aen_event_read_flag)) {
- ioc->aen_event_read_flag = 1;
- wake_up_interruptible(&ctl_poll_wait);
- if (async_queue)
- kill_fasync(&async_queue, SIGIO, POLL_IN);
- }
-}
-
-/**
- * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
- * @ioc: per adapter object
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: interrupt.
- *
- * This function merely adds a new work task into ioc->firmware_event_thread.
- * The tasks are worked from _firmware_event_work in user context.
- *
- * Returns void.
- */
-void
-mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply)
-{
- Mpi2EventNotificationReply_t *mpi_reply;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
- return;
-}
-
-/**
- * _ctl_verify_adapter - validates ioc_number passed from application
- * @ioc: per adapter object
- * @iocpp: The ioc pointer is returned in this.
- *
- * Return (-1) means error, else ioc_number.
- */
-static int
-_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp)
-{
- struct MPT2SAS_ADAPTER *ioc;
- /* global ioc lock to protect controller on list operations */
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
- if (ioc->id != ioc_number)
- continue;
- spin_unlock(&gioc_lock);
- *iocpp = ioc;
- return ioc_number;
- }
- spin_unlock(&gioc_lock);
- *iocpp = NULL;
- return -1;
-}
-
-/**
- * mpt2sas_ctl_reset_handler - reset callback handler (for ctl)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- */
-void
-mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- int i;
- u8 issue_reset;
-
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!(ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_REGISTERED))
- continue;
- if ((ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- continue;
- _ctl_send_release(ioc, i, &issue_reset);
- }
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) {
- ioc->ctl_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid);
- complete(&ioc->ctl_cmds.done);
- }
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
-
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!(ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_REGISTERED))
- continue;
- if ((ioc->diag_buffer_status[i] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- continue;
- ioc->diag_buffer_status[i] |=
- MPT2_DIAG_BUFFER_IS_DIAG_RESET;
- }
- break;
- }
-}
-
-/**
- * _ctl_fasync -
- * @fd -
- * @filep -
- * @mode -
- *
- * Called when application request fasyn callback handler.
- */
-static int
-_ctl_fasync(int fd, struct file *filep, int mode)
-{
- return fasync_helper(fd, filep, mode, &async_queue);
-}
-
-/**
- * _ctl_poll -
- * @file -
- * @wait -
- *
- */
-static unsigned int
-_ctl_poll(struct file *filep, poll_table *wait)
-{
- struct MPT2SAS_ADAPTER *ioc;
-
- poll_wait(filep, &ctl_poll_wait, wait);
-
- /* global ioc lock to protect controller on list operations */
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
- if (ioc->aen_event_read_flag) {
- spin_unlock(&gioc_lock);
- return POLLIN | POLLRDNORM;
- }
- }
- spin_unlock(&gioc_lock);
- return 0;
-}
-
-/**
- * _ctl_set_task_mid - assign an active smid to tm request
- * @ioc: per adapter object
- * @karg - (struct mpt2_ioctl_command)
- * @tm_request - pointer to mf from user space
- *
- * Returns 0 when an smid if found, else fail.
- * during failure, the reply frame is filled.
- */
-static int
-_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
- Mpi2SCSITaskManagementRequest_t *tm_request)
-{
- u8 found = 0;
- u16 i;
- u16 handle;
- struct scsi_cmnd *scmd;
- struct MPT2SAS_DEVICE *priv_data;
- unsigned long flags;
- Mpi2SCSITaskManagementReply_t *tm_reply;
- u32 sz;
- u32 lun;
- char *desc = NULL;
-
- if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
- desc = "abort_task";
- else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK)
- desc = "query_task";
- else
- return 0;
-
- lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN);
-
- handle = le16_to_cpu(tm_request->DevHandle);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = ioc->scsiio_depth; i && !found; i--) {
- scmd = ioc->scsi_lookup[i - 1].scmd;
- if (scmd == NULL || scmd->device == NULL ||
- scmd->device->hostdata == NULL)
- continue;
- if (lun != scmd->device->lun)
- continue;
- priv_data = scmd->device->hostdata;
- if (priv_data->sas_target == NULL)
- continue;
- if (priv_data->sas_target->handle != handle)
- continue;
- tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid);
- found = 1;
- }
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- if (!found) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun));
- tm_reply = ioc->ctl_cmds.reply;
- tm_reply->DevHandle = tm_request->DevHandle;
- tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- tm_reply->TaskType = tm_request->TaskType;
- tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4;
- tm_reply->VP_ID = tm_request->VP_ID;
- tm_reply->VF_ID = tm_request->VF_ID;
- sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz);
- if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply,
- sz))
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- return 1;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name,
- desc, le16_to_cpu(tm_request->DevHandle), lun,
- le16_to_cpu(tm_request->TaskMID)));
- return 0;
-}
-
-/**
- * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode
- * @ioc: per adapter object
- * @karg - (struct mpt2_ioctl_command)
- * @mf - pointer to mf in user space
- */
-static long
-_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command karg,
- void __user *mf)
-{
- MPI2RequestHeader_t *mpi_request = NULL, *request;
- MPI2DefaultReply_t *mpi_reply;
- u32 ioc_state;
- u16 ioc_status;
- u16 smid;
- unsigned long timeout, timeleft;
- u8 issue_reset;
- u32 sz;
- void *psge;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- size_t data_out_sz = 0;
- void *data_in = NULL;
- dma_addr_t data_in_dma;
- size_t data_in_sz = 0;
- u32 sgl_flags;
- long ret;
- u16 wait_state_count;
-
- issue_reset = 0;
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- ret = -EAGAIN;
- goto out;
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- ret = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL);
- if (!mpi_request) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for "
- "mpi_request\n", ioc->name, __func__);
- ret = -ENOMEM;
- goto out;
- }
-
- /* Check for overflow and wraparound */
- if (karg.data_sge_offset * 4 > ioc->request_sz ||
- karg.data_sge_offset > (UINT_MAX / 4)) {
- ret = -EINVAL;
- goto out;
- }
-
- /* copy in request message frame from user */
- if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__,
- __func__);
- ret = -EFAULT;
- goto out;
- }
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ret = -EAGAIN;
- goto out;
- }
- } else {
-
- smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ret = -EAGAIN;
- goto out;
- }
- }
-
- ret = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- request = mpt2sas_base_get_msg_frame(ioc, smid);
- memcpy(request, mpi_request, karg.data_sge_offset*4);
- ioc->ctl_cmds.smid = smid;
- data_out_sz = karg.data_out_size;
- data_in_sz = karg.data_in_size;
-
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) {
- if (!le16_to_cpu(mpi_request->FunctionDependent1) ||
- le16_to_cpu(mpi_request->FunctionDependent1) >
- ioc->facts.MaxDevHandle) {
- ret = -EINVAL;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- /* obtain dma-able memory for data transfer */
- if (data_out_sz) /* WRITE */ {
- data_out = pci_alloc_consistent(ioc->pdev, data_out_sz,
- &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- if (copy_from_user(data_out, karg.data_out_buf_ptr,
- data_out_sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -EFAULT;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- if (data_in_sz) /* READ */ {
- data_in = pci_alloc_consistent(ioc->pdev, data_in_sz,
- &data_in_dma);
- if (!data_in) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- /* add scatter gather elements */
- psge = (void *)request + (karg.data_sge_offset*4);
-
- if (!data_out_sz && !data_in_sz) {
- mpt2sas_base_build_zero_len_sge(ioc, psge);
- } else if (data_out_sz && data_in_sz) {
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_out_sz, data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_in_sz, data_in_dma);
- } else if (data_out_sz) /* WRITE */ {
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_out_sz, data_out_dma);
- } else if (data_in_sz) /* READ */ {
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- data_in_sz, data_in_dma);
- }
-
- /* send command to firmware */
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- _ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
-#endif
-
- init_completion(&ioc->ctl_cmds.done);
- switch (mpi_request->Function) {
- case MPI2_FUNCTION_SCSI_IO_REQUEST:
- case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH:
- {
- Mpi2SCSIIORequest_t *scsiio_request =
- (Mpi2SCSIIORequest_t *)request;
- scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
- scsiio_request->SenseBufferLowAddress =
- mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE);
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- le16_to_cpu(mpi_request->FunctionDependent1));
- else
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SCSI_TASK_MGMT:
- {
- Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)request;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
- "handle(0x%04x), task_type(0x%02x)\n", ioc->name,
- le16_to_cpu(tm_request->DevHandle), tm_request->TaskType));
-
- if (tm_request->TaskType ==
- MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK ||
- tm_request->TaskType ==
- MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) {
- if (_ctl_set_task_mid(ioc, &karg, tm_request)) {
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
- tm_request->DevHandle));
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SMP_PASSTHROUGH:
- {
- Mpi2SmpPassthroughRequest_t *smp_request =
- (Mpi2SmpPassthroughRequest_t *)mpi_request;
- u8 *data;
-
- /* ioc determines which port to use */
- smp_request->PhysicalPort = 0xFF;
- if (smp_request->PassthroughFlags &
- MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE)
- data = (u8 *)&smp_request->SGL;
- else {
- if (unlikely(data_out == NULL)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- mpt2sas_base_free_smid(ioc, smid);
- ret = -EINVAL;
- goto out;
- }
- data = data_out;
- }
-
- if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) {
- ioc->ioc_link_reset_in_progress = 1;
- ioc->ignore_loginfos = 1;
- }
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
- {
- Mpi2SasIoUnitControlRequest_t *sasiounit_request =
- (Mpi2SasIoUnitControlRequest_t *)mpi_request;
-
- if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET
- || sasiounit_request->Operation ==
- MPI2_SAS_OP_PHY_LINK_RESET) {
- ioc->ioc_link_reset_in_progress = 1;
- ioc->ignore_loginfos = 1;
- }
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
- default:
- mpt2sas_base_put_smid_default(ioc, smid);
- break;
- }
-
- if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT)
- timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;
- else
- timeout = karg.timeout;
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- timeout*HZ);
- if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
- Mpi2SCSITaskManagementRequest_t *tm_request =
- (Mpi2SCSITaskManagementRequest_t *)mpi_request;
- mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu(
- tm_request->DevHandle));
- } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH ||
- mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) &&
- ioc->ioc_link_reset_in_progress) {
- ioc->ioc_link_reset_in_progress = 0;
- ioc->ignore_loginfos = 0;
- }
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request, karg.data_sge_offset);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
- (ioc->logging_level & MPT_DEBUG_TM)) {
- Mpi2SCSITaskManagementReply_t *tm_reply =
- (Mpi2SCSITaskManagementReply_t *)mpi_reply;
-
- printk(MPT2SAS_INFO_FMT "TASK_MGMT: "
- "IOCStatus(0x%04x), IOCLogInfo(0x%08x), "
- "TerminationCount(0x%08x)\n", ioc->name,
- le16_to_cpu(tm_reply->IOCStatus),
- le32_to_cpu(tm_reply->IOCLogInfo),
- le32_to_cpu(tm_reply->TerminationCount));
- }
-#endif
- /* copy out xdata to user */
- if (data_in_sz) {
- if (copy_to_user(karg.data_in_buf_ptr, data_in,
- data_in_sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- /* copy out reply message frame to user */
- if (karg.max_reply_bytes) {
- sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz);
- if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply,
- sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- /* copy out sense to user */
- if (karg.max_sense_bytes && (mpi_request->Function ==
- MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) {
- sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
- if (copy_to_user(karg.sense_data_ptr,
- ioc->ctl_cmds.sense, sz)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- ret = -ENODATA;
- goto out;
- }
- }
-
- issue_host_reset:
- if (issue_reset) {
- ret = -ENODATA;
- if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST ||
- mpi_request->Function ==
- MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH ||
- mpi_request->Function == MPI2_FUNCTION_SATA_PASSTHROUGH)) {
- printk(MPT2SAS_INFO_FMT "issue target reset: handle "
- "= (0x%04x)\n", ioc->name,
- le16_to_cpu(mpi_request->FunctionDependent1));
- mpt2sas_halt_firmware(ioc);
- mpt2sas_scsih_issue_tm(ioc,
- le16_to_cpu(mpi_request->FunctionDependent1), 0, 0,
- 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10,
- TM_MUTEX_ON);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- } else
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- }
-
- out:
-
- /* free memory associated with sg buffers */
- if (data_in)
- pci_free_consistent(ioc->pdev, data_in_sz, data_in,
- data_in_dma);
-
- if (data_out)
- pci_free_consistent(ioc->pdev, data_out_sz, data_out,
- data_out_dma);
-
- kfree(mpi_request);
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return ret;
-}
-
-/**
- * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_getiocinfo(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_iocinfo karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- memset(&karg, 0 , sizeof(karg));
- if (ioc->is_warpdrive)
- karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200;
- else
- karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
- if (ioc->pfacts)
- karg.port_number = ioc->pfacts[0].PortNumber;
- karg.hw_rev = ioc->pdev->revision;
- karg.pci_id = ioc->pdev->device;
- karg.subsystem_device = ioc->pdev->subsystem_device;
- karg.subsystem_vendor = ioc->pdev->subsystem_vendor;
- karg.pci_information.u.bits.bus = ioc->pdev->bus->number;
- karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn);
- karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
- karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
- karg.firmware_version = ioc->facts.FWVersion.Word;
- strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME);
- strcat(karg.driver_version, "-");
- strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
- karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventquery(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventquery karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE;
- memcpy(karg.event_types, ioc->event_type,
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventenable(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventenable karg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- if (ioc->event_log)
- return 0;
- memcpy(ioc->event_type, karg.event_types,
- MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32));
- mpt2sas_base_validate_event_type(ioc, ioc->event_type);
-
- /* initialize event_log */
- ioc->event_context = 0;
- ioc->aen_event_read_flag = 0;
- ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE,
- sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL);
- if (!ioc->event_log) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -ENOMEM;
- }
- return 0;
-}
-
-/**
- * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_eventreport(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_eventreport karg;
- u32 number_bytes, max_events, max;
- struct mpt2_ioctl_eventreport __user *uarg = arg;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- number_bytes = karg.hdr.max_data_size -
- sizeof(struct mpt2_ioctl_header);
- max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS);
- max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events);
-
- /* If fewer than 1 event is requested, there must have
- * been some type of error.
- */
- if (!max || !ioc->event_log)
- return -ENODATA;
-
- number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS);
- if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- /* reset flag so SIGIO can restart */
- ioc->aen_event_read_flag = 0;
- return 0;
-}
-
-/**
- * _ctl_do_reset - main handler for MPT2HARDRESET opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_do_reset(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_diag_reset karg;
- int retval;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name,
- __func__));
-
- retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- printk(MPT2SAS_INFO_FMT "host reset: %s\n",
- ioc->name, ((!retval) ? "SUCCESS" : "FAILED"));
- return 0;
-}
-
-/**
- * _ctl_btdh_search_sas_device - searching for sas device
- * @ioc: per adapter object
- * @btdh: btdh ioctl payload
- */
-static int
-_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_btdh_mapping *btdh)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc = 0;
-
- if (list_empty(&ioc->sas_device_list))
- return rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
- btdh->handle == sas_device->handle) {
- btdh->bus = sas_device->channel;
- btdh->id = sas_device->id;
- rc = 1;
- goto out;
- } else if (btdh->bus == sas_device->channel && btdh->id ==
- sas_device->id && btdh->handle == 0xFFFF) {
- btdh->handle = sas_device->handle;
- rc = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/**
- * _ctl_btdh_search_raid_device - searching for raid device
- * @ioc: per adapter object
- * @btdh: btdh ioctl payload
- */
-static int
-_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_ioctl_btdh_mapping *btdh)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- int rc = 0;
-
- if (list_empty(&ioc->raid_device_list))
- return rc;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF &&
- btdh->handle == raid_device->handle) {
- btdh->bus = raid_device->channel;
- btdh->id = raid_device->id;
- rc = 1;
- goto out;
- } else if (btdh->bus == raid_device->channel && btdh->id ==
- raid_device->id && btdh->handle == 0xFFFF) {
- btdh->handle = raid_device->handle;
- rc = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return rc;
-}
-
-/**
- * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_btdh_mapping(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_ioctl_btdh_mapping karg;
- int rc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- rc = _ctl_btdh_search_sas_device(ioc, &karg);
- if (!rc)
- _ctl_btdh_search_raid_device(ioc, &karg);
-
- if (copy_to_user(arg, &karg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_diag_capability - return diag buffer capability
- * @ioc: per adapter object
- * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED
- *
- * returns 1 when diag buffer support is enabled in firmware
- */
-static u8
-_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type)
-{
- u8 rc = 0;
-
- switch (buffer_type) {
- case MPI2_DIAG_BUF_TYPE_TRACE:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER)
- rc = 1;
- break;
- case MPI2_DIAG_BUF_TYPE_SNAPSHOT:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER)
- rc = 1;
- break;
- case MPI2_DIAG_BUF_TYPE_EXTENDED:
- if (ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER)
- rc = 1;
- }
-
- return rc;
-}
-
-/**
- * _ctl_diag_register_2 - wrapper for registering diag buffer support
- * @ioc: per adapter object
- * @diag_register: the diag_register struct passed in from user space
- *
- */
-static long
-_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc,
- struct mpt2_diag_register *diag_register)
-{
- int rc, i;
- void *request_data = NULL;
- dma_addr_t request_data_dma;
- u32 request_data_sz = 0;
- Mpi2DiagBufferPostRequest_t *mpi_request;
- Mpi2DiagBufferPostReply_t *mpi_reply;
- u8 buffer_type;
- unsigned long timeleft;
- u16 smid;
- u16 ioc_status;
- u8 issue_reset = 0;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- buffer_type = diag_register->buffer_type;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if (ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) {
- printk(MPT2SAS_ERR_FMT "%s: already has a registered "
- "buffer for buffer_type(0x%02x)\n", ioc->name, __func__,
- buffer_type);
- return -EINVAL;
- }
-
- if (diag_register->requested_buffer_size % 4) {
- printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size "
- "is not 4 byte aligned\n", ioc->name, __func__);
- return -EINVAL;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- request_data = ioc->diag_buffer[buffer_type];
- request_data_sz = diag_register->requested_buffer_size;
- ioc->unique_id[buffer_type] = diag_register->unique_id;
- ioc->diag_buffer_status[buffer_type] = 0;
- memcpy(ioc->product_specific[buffer_type],
- diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS);
- ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags;
-
- if (request_data) {
- request_data_dma = ioc->diag_buffer_dma[buffer_type];
- if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) {
- pci_free_consistent(ioc->pdev,
- ioc->diag_buffer_sz[buffer_type],
- request_data, request_data_dma);
- request_data = NULL;
- }
- }
-
- if (request_data == NULL) {
- ioc->diag_buffer_sz[buffer_type] = 0;
- ioc->diag_buffer_dma[buffer_type] = 0;
- request_data = pci_alloc_consistent(
- ioc->pdev, request_data_sz, &request_data_dma);
- if (request_data == NULL) {
- printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"
- " for diag buffers, requested size(%d)\n",
- ioc->name, __func__, request_data_sz);
- mpt2sas_base_free_smid(ioc, smid);
- return -ENOMEM;
- }
- ioc->diag_buffer[buffer_type] = request_data;
- ioc->diag_buffer_sz[buffer_type] = request_data_sz;
- ioc->diag_buffer_dma[buffer_type] = request_data_dma;
- }
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = diag_register->buffer_type;
- mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags);
- mpi_request->BufferAddress = cpu_to_le64(request_data_dma);
- mpi_request->BufferLength = cpu_to_le32(request_data_sz);
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), "
- "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
- (unsigned long long)request_data_dma,
- le32_to_cpu(mpi_request->BufferLength)));
-
- for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
- mpi_request->ProductSpecific[i] =
- cpu_to_le32(ioc->product_specific[buffer_type][i]);
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagBufferPostRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- out:
-
- if (rc && request_data)
- pci_free_consistent(ioc->pdev, request_data_sz,
- request_data, request_data_dma);
-
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-/**
- * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time
- * @ioc: per adapter object
- * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1
- *
- * This is called when command line option diag_buffer_enable is enabled
- * at driver load time.
- */
-void
-mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register)
-{
- struct mpt2_diag_register diag_register;
-
- memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
-
- if (bits_to_register & 1) {
- printk(MPT2SAS_INFO_FMT "registering trace buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
- /* register for 1MB buffers */
- diag_register.requested_buffer_size = (1024 * 1024);
- diag_register.unique_id = 0x7075900;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-
- if (bits_to_register & 2) {
- printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT;
- /* register for 2MB buffers */
- diag_register.requested_buffer_size = 2 * (1024 * 1024);
- diag_register.unique_id = 0x7075901;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-
- if (bits_to_register & 4) {
- printk(MPT2SAS_INFO_FMT "registering extended buffer support\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED;
- /* register for 2MB buffers */
- diag_register.requested_buffer_size = 2 * (1024 * 1024);
- diag_register.unique_id = 0x7075901;
- _ctl_diag_register_2(ioc, &diag_register);
- }
-}
-
-/**
- * _ctl_diag_register - application register with driver
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
- */
-static long
-_ctl_diag_register(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_register karg;
- long rc;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- rc = _ctl_diag_register_2(ioc, &karg);
- return rc;
-}
-
-/**
- * _ctl_diag_unregister - application unregister with driver
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * This will allow the driver to cleanup any memory allocated for diag
- * messages and to free up any resources.
- */
-static long
-_ctl_diag_unregister(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_unregister karg;
- void *request_data;
- dma_addr_t request_data_dma;
- u32 request_data_sz;
- u8 buffer_type;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been "
- "released\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- request_data_sz = ioc->diag_buffer_sz[buffer_type];
- request_data_dma = ioc->diag_buffer_dma[buffer_type];
- pci_free_consistent(ioc->pdev, request_data_sz,
- request_data, request_data_dma);
- ioc->diag_buffer[buffer_type] = NULL;
- ioc->diag_buffer_status[buffer_type] = 0;
- return 0;
-}
-
-/**
- * _ctl_diag_query - query relevant info associated with diag buffers
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- *
- * The application will send only buffer_type and unique_id. Driver will
- * inspect unique_id first, if valid, fill in all the info. If unique_id is
- * 0x00, the driver will return info specified by Buffer Type.
- */
-static long
-_ctl_diag_query(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_query karg;
- void *request_data;
- int i;
- u8 buffer_type;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- karg.application_flags = 0;
- buffer_type = karg.buffer_type;
-
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id & 0xffffff00) {
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__,
- karg.unique_id);
- return -EINVAL;
- }
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED)
- karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
- MPT2_APP_FLAGS_BUFFER_VALID);
- else
- karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED |
- MPT2_APP_FLAGS_BUFFER_VALID |
- MPT2_APP_FLAGS_FW_BUFFER_ACCESS);
-
- for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
- karg.product_specific[i] =
- ioc->product_specific[buffer_type][i];
-
- karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type];
- karg.driver_added_buffer_size = 0;
- karg.unique_id = ioc->unique_id[buffer_type];
- karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type];
-
- if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) {
- printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query "
- "data @ %p\n", ioc->name, __func__, arg);
- return -EFAULT;
- }
- return 0;
-}
-
-/**
- * _ctl_send_release - Diag Release Message
- * @ioc: per adapter object
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @issue_reset - specifies whether host reset is required.
- *
- */
-static int
-_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
-{
- Mpi2DiagReleaseRequest_t *mpi_request;
- Mpi2DiagReleaseReply_t *mpi_reply;
- u16 smid;
- u16 ioc_status;
- u32 ioc_state;
- int rc;
- unsigned long timeleft;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- rc = 0;
- *issue_reset = 0;
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "skipping due to FAULT state\n", ioc->name,
- __func__));
- rc = -EAGAIN;
- goto out;
- }
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
- mpi_request->BufferType = buffer_type;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagReleaseRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- *issue_reset = 1;
- rc = -EFAULT;
- goto out;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_RELEASED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- out:
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-/**
- * _ctl_diag_release - request to send Diag Release Message to firmware
- * @arg - user space buffer containing ioctl content
- *
- * This allows ownership of the specified buffer to returned to the driver,
- * allowing an application to read the buffer without fear that firmware is
- * overwritting information in the buffer.
- */
-static long
-_ctl_diag_release(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_release karg;
- void *request_data;
- int rc;
- u8 buffer_type;
- u8 issue_reset = 0;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not "
- "registered\n", ioc->name, __func__, buffer_type);
- return -EINVAL;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- if (ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) {
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) "
- "is already released\n", ioc->name, __func__,
- buffer_type);
- return 0;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
-
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- /* buffers were released by due to host reset */
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_DIAG_RESET)) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_RELEASED;
- ioc->diag_buffer_status[buffer_type] &=
- ~MPT2_DIAG_BUFFER_IS_DIAG_RESET;
- printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) "
- "was released due to host reset\n", ioc->name, __func__,
- buffer_type);
- return 0;
- }
-
- rc = _ctl_send_release(ioc, buffer_type, &issue_reset);
-
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- return rc;
-}
-
-/**
- * _ctl_diag_read_buffer - request for copy of the diag buffer
- * @ioc: per adapter object
- * @arg - user space buffer containing ioctl content
- */
-static long
-_ctl_diag_read_buffer(struct MPT2SAS_ADAPTER *ioc, void __user *arg)
-{
- struct mpt2_diag_read_buffer karg;
- struct mpt2_diag_read_buffer __user *uarg = arg;
- void *request_data, *diag_data;
- Mpi2DiagBufferPostRequest_t *mpi_request;
- Mpi2DiagBufferPostReply_t *mpi_reply;
- int rc, i;
- u8 buffer_type;
- unsigned long timeleft, request_size, copy_size;
- u16 smid;
- u16 ioc_status;
- u8 issue_reset = 0;
-
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name,
- __func__));
-
- buffer_type = karg.unique_id & 0x000000ff;
- if (!_ctl_diag_capability(ioc, buffer_type)) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -EPERM;
- }
-
- if (karg.unique_id != ioc->unique_id[buffer_type]) {
- printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not "
- "registered\n", ioc->name, __func__, karg.unique_id);
- return -EINVAL;
- }
-
- request_data = ioc->diag_buffer[buffer_type];
- if (!request_data) {
- printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type);
- return -ENOMEM;
- }
-
- request_size = ioc->diag_buffer_sz[buffer_type];
-
- if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) {
- printk(MPT2SAS_ERR_FMT "%s: either the starting_offset "
- "or bytes_to_read are not 4 byte aligned\n", ioc->name,
- __func__);
- return -EINVAL;
- }
-
- if (karg.starting_offset > request_size)
- return -EINVAL;
-
- diag_data = (void *)(request_data + karg.starting_offset);
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), "
- "offset(%d), sz(%d)\n", ioc->name, __func__,
- diag_data, karg.starting_offset, karg.bytes_to_read));
-
- /* Truncate data on requests that are too large */
- if ((diag_data + karg.bytes_to_read < diag_data) ||
- (diag_data + karg.bytes_to_read > request_data + request_size))
- copy_size = request_size - karg.starting_offset;
- else
- copy_size = karg.bytes_to_read;
-
- if (copy_to_user((void __user *)uarg->diagnostic_data,
- diag_data, copy_size)) {
- printk(MPT2SAS_ERR_FMT "%s: Unable to write "
- "mpt_diag_read_buffer_t data @ %p\n", ioc->name,
- __func__, diag_data);
- return -EFAULT;
- }
-
- if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0)
- return 0;
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister "
- "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type));
- if ((ioc->diag_buffer_status[buffer_type] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0) {
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "buffer_type(0x%02x) is still registered\n", ioc->name,
- __func__, buffer_type));
- return 0;
- }
- /* Get a free request frame and save the message context.
- */
-
- if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- ioc->ctl_cmds.status = MPT2_CMD_PENDING;
- memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz);
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->ctl_cmds.smid = smid;
-
- mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST;
- mpi_request->BufferType = buffer_type;
- mpi_request->BufferLength =
- cpu_to_le32(ioc->diag_buffer_sz[buffer_type]);
- mpi_request->BufferAddress =
- cpu_to_le64(ioc->diag_buffer_dma[buffer_type]);
- for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
- mpi_request->ProductSpecific[i] =
- cpu_to_le32(ioc->product_specific[buffer_type][i]);
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
-
- init_completion(&ioc->ctl_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
- MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
-
- if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name,
- __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2DiagBufferPostRequest_t)/4);
- if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- /* process the completed Reply Message Frame */
- if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: no reply message\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
-
- mpi_reply = ioc->ctl_cmds.reply;
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- ioc->diag_buffer_status[buffer_type] |=
- MPT2_DIAG_BUFFER_IS_REGISTERED;
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n",
- ioc->name, __func__));
- } else {
- printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) "
- "log_info(0x%08x)\n", ioc->name, __func__,
- ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo));
- rc = -EFAULT;
- }
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- out:
-
- ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
- return rc;
-}
-
-
-#ifdef CONFIG_COMPAT
-/**
- * _ctl_compat_mpt_command - convert 32bit pointers to 64bit.
- * @ioc: per adapter object
- * @cmd - ioctl opcode
- * @arg - (struct mpt2_ioctl_command32)
- *
- * MPT2COMMAND32 - Handle 32bit applications running on 64bit os.
- */
-static long
-_ctl_compat_mpt_command(struct MPT2SAS_ADAPTER *ioc, unsigned cmd,
- void __user *arg)
-{
- struct mpt2_ioctl_command32 karg32;
- struct mpt2_ioctl_command32 __user *uarg;
- struct mpt2_ioctl_command karg;
-
- if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32))
- return -EINVAL;
-
- uarg = (struct mpt2_ioctl_command32 __user *) arg;
-
- if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- memset(&karg, 0, sizeof(struct mpt2_ioctl_command));
- karg.hdr.ioc_number = karg32.hdr.ioc_number;
- karg.hdr.port_number = karg32.hdr.port_number;
- karg.hdr.max_data_size = karg32.hdr.max_data_size;
- karg.timeout = karg32.timeout;
- karg.max_reply_bytes = karg32.max_reply_bytes;
- karg.data_in_size = karg32.data_in_size;
- karg.data_out_size = karg32.data_out_size;
- karg.max_sense_bytes = karg32.max_sense_bytes;
- karg.data_sge_offset = karg32.data_sge_offset;
- karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr);
- karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr);
- karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr);
- karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr);
- return _ctl_do_mpt_command(ioc, karg, &uarg->mf);
-}
-#endif
-
-/**
- * _ctl_ioctl_main - main ioctl entry point
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg -
- * compat - handles 32 bit applications in 64bit os
- */
-static long
-_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
- u8 compat)
-{
- struct MPT2SAS_ADAPTER *ioc;
- struct mpt2_ioctl_header ioctl_header;
- enum block_state state;
- long ret = -EINVAL;
-
- /* get IOCTL header */
- if (copy_from_user(&ioctl_header, (char __user *)arg,
- sizeof(struct mpt2_ioctl_header))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- return -EFAULT;
- }
-
- if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
- return -ENODEV;
- /* pci_access_mutex lock acquired by ioctl path */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading || ioc->remove_host) {
- ret = -EAGAIN;
- goto out_unlock_pciaccess;
- }
-
- state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
- if (state == NON_BLOCKING) {
- if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
- ret = -EAGAIN;
- goto out_unlock_pciaccess;
- }
- } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
- ret = -ERESTARTSYS;
- goto out_unlock_pciaccess;
- }
-
- switch (cmd) {
- case MPT2IOCINFO:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo))
- ret = _ctl_getiocinfo(ioc, arg);
- break;
-#ifdef CONFIG_COMPAT
- case MPT2COMMAND32:
-#endif
- case MPT2COMMAND:
- {
- struct mpt2_ioctl_command __user *uarg;
- struct mpt2_ioctl_command karg;
-#ifdef CONFIG_COMPAT
- if (compat) {
- ret = _ctl_compat_mpt_command(ioc, cmd, arg);
- break;
- }
-#endif
- if (copy_from_user(&karg, arg, sizeof(karg))) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n",
- __FILE__, __LINE__, __func__);
- ret = -EFAULT;
- break;
- }
-
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) {
- uarg = arg;
- ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf);
- }
- break;
- }
- case MPT2EVENTQUERY:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery))
- ret = _ctl_eventquery(ioc, arg);
- break;
- case MPT2EVENTENABLE:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable))
- ret = _ctl_eventenable(ioc, arg);
- break;
- case MPT2EVENTREPORT:
- ret = _ctl_eventreport(ioc, arg);
- break;
- case MPT2HARDRESET:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset))
- ret = _ctl_do_reset(ioc, arg);
- break;
- case MPT2BTDHMAPPING:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping))
- ret = _ctl_btdh_mapping(ioc, arg);
- break;
- case MPT2DIAGREGISTER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register))
- ret = _ctl_diag_register(ioc, arg);
- break;
- case MPT2DIAGUNREGISTER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister))
- ret = _ctl_diag_unregister(ioc, arg);
- break;
- case MPT2DIAGQUERY:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query))
- ret = _ctl_diag_query(ioc, arg);
- break;
- case MPT2DIAGRELEASE:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release))
- ret = _ctl_diag_release(ioc, arg);
- break;
- case MPT2DIAGREADBUFFER:
- if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer))
- ret = _ctl_diag_read_buffer(ioc, arg);
- break;
- default:
-
- dctlprintk(ioc, printk(MPT2SAS_INFO_FMT
- "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd));
- break;
- }
-
- mutex_unlock(&ioc->ctl_cmds.mutex);
-out_unlock_pciaccess:
- mutex_unlock(&ioc->pci_access_mutex);
- return ret;
-}
-
-/**
- * _ctl_ioctl - main ioctl entry point (unlocked)
- * @file - (struct file)
- * @cmd - ioctl opcode
- * @arg -
- */
-static long
-_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- long ret;
-
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
- return ret;
-}
-#ifdef CONFIG_COMPAT
-/**
- * _ctl_ioctl_compat - main ioctl entry point (compat)
- * @file -
- * @cmd -
- * @arg -
- *
- * This routine handles 32 bit applications in 64bit os.
- */
-static long
-_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
-{
- long ret;
-
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
- return ret;
-}
-#endif
-
-/* scsi host attributes */
-
-/**
- * _ctl_version_fw_show - firmware version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
- (ioc->facts.FWVersion.Word & 0xFF000000) >> 24,
- (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16,
- (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8,
- ioc->facts.FWVersion.Word & 0x000000FF);
-}
-static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL);
-
-/**
- * _ctl_version_bios_show - bios version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
-
- return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n",
- (version & 0xFF000000) >> 24,
- (version & 0x00FF0000) >> 16,
- (version & 0x0000FF00) >> 8,
- version & 0x000000FF);
-}
-static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL);
-
-/**
- * _ctl_version_mpi_show - MPI (message passing interface) version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%03x.%02x\n",
- ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8);
-}
-static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL);
-
-/**
- * _ctl_version_product_show - product name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_product_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName);
-}
-static DEVICE_ATTR(version_product, S_IRUGO,
- _ctl_version_product_show, NULL);
-
-/**
- * _ctl_version_nvdata_persistent_show - ndvata persistent version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_nvdata_persistent_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n",
- le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word));
-}
-static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO,
- _ctl_version_nvdata_persistent_show, NULL);
-
-/**
- * _ctl_version_nvdata_default_show - nvdata default version
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_version_nvdata_default_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n",
- le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word));
-}
-static DEVICE_ATTR(version_nvdata_default, S_IRUGO,
- _ctl_version_nvdata_default_show, NULL);
-
-/**
- * _ctl_board_name_show - board name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_name_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName);
-}
-static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL);
-
-/**
- * _ctl_board_assembly_show - board assembly name
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly);
-}
-static DEVICE_ATTR(board_assembly, S_IRUGO,
- _ctl_board_assembly_show, NULL);
-
-/**
- * _ctl_board_tracer_show - board tracer number
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber);
-}
-static DEVICE_ATTR(board_tracer, S_IRUGO,
- _ctl_board_tracer_show, NULL);
-
-/**
- * _ctl_io_delay_show - io missing delay
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is for firmware implemention for deboucing device
- * removal events.
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay);
-}
-static DEVICE_ATTR(io_delay, S_IRUGO,
- _ctl_io_delay_show, NULL);
-
-/**
- * _ctl_device_delay_show - device missing delay
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is for firmware implemention for deboucing device
- * removal events.
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay);
-}
-static DEVICE_ATTR(device_delay, S_IRUGO,
- _ctl_device_delay_show, NULL);
-
-/**
- * _ctl_fw_queue_depth_show - global credits
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is firmware queue depth limit
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit);
-}
-static DEVICE_ATTR(fw_queue_depth, S_IRUGO,
- _ctl_fw_queue_depth_show, NULL);
-
-/**
- * _ctl_sas_address_show - sas address
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the controller sas address
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
- (unsigned long long)ioc->sas_hba.sas_address);
-}
-static DEVICE_ATTR(host_sas_address, S_IRUGO,
- _ctl_host_sas_address_show, NULL);
-
-/**
- * _ctl_logging_level_show - logging level
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- */
-static ssize_t
-_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level);
-}
-static ssize_t
-_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%x", &val) != 1)
- return -EINVAL;
-
- ioc->logging_level = val;
- printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name,
- ioc->logging_level);
- return strlen(buf);
-}
-static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
- _ctl_logging_level_show, _ctl_logging_level_store);
-
-/* device attributes */
-/*
- * _ctl_fwfault_debug_show - show/store fwfault_debug
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * mpt2sas_fwfault_debug is command line option
- * A sysfs 'read/write' shost attribute.
- */
-static ssize_t
-_ctl_fwfault_debug_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug);
-}
-static ssize_t
-_ctl_fwfault_debug_store(struct device *cdev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- ioc->fwfault_debug = val;
- printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name,
- ioc->fwfault_debug);
- return strlen(buf);
-}
-static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR,
- _ctl_fwfault_debug_show, _ctl_fwfault_debug_store);
-
-
-/**
- * _ctl_ioc_reset_count_show - ioc reset count
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is firmware queue depth limit
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count);
-}
-static DEVICE_ATTR(ioc_reset_count, S_IRUGO,
- _ctl_ioc_reset_count_show, NULL);
-
-/**
- * _ctl_ioc_reply_queue_count_show - number of reply queues
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is number of reply queues
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_ioc_reply_queue_count_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- u8 reply_queue_count;
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if ((ioc->facts.IOCCapabilities &
- MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable)
- reply_queue_count = ioc->reply_queue_count;
- else
- reply_queue_count = 1;
- return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count);
-}
-static DEVICE_ATTR(reply_queue_count, S_IRUGO,
- _ctl_ioc_reply_queue_count_show, NULL);
-
-/**
- * _ctl_BRM_status_show - Backup Rail Monitor Status
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is number of reply queues
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u16 backup_rail_monitor_status = 0;
- u16 ioc_status;
- int sz;
- ssize_t rc = 0;
-
- if (!ioc->is_warpdrive) {
- printk(MPT2SAS_ERR_FMT "%s: BRM attribute is only for"\
- "warpdrive\n", ioc->name, __func__);
- goto out;
- }
- /* pci_access_mutex lock acquired by sysfs show path */
- mutex_lock(&ioc->pci_access_mutex);
- if (ioc->pci_error_recovery || ioc->remove_host) {
- mutex_unlock(&ioc->pci_access_mutex);
- return 0;
- }
-
- /* allocate upto GPIOVal 36 entries */
- sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
- io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
- if (!io_unit_pg3) {
- printk(MPT2SAS_ERR_FMT "%s: failed allocating memory"\
- "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
- goto out;
- }
-
- if (mpt2sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
- 0) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed reading iounit_pg3\n", ioc->name,
- __func__);
- goto out;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "%s: iounit_pg3 failed with"\
- "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
- goto out;
- }
-
- if (io_unit_pg3->GPIOCount < 25) {
- printk(MPT2SAS_ERR_FMT "%s: iounit_pg3->GPIOCount less than"\
- "25 entries, detected (%d) entries\n", ioc->name, __func__,
- io_unit_pg3->GPIOCount);
- goto out;
- }
-
- /* BRM status is in bit zero of GPIOVal[24] */
- backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
- rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
-
- out:
- kfree(io_unit_pg3);
- mutex_unlock(&ioc->pci_access_mutex);
- return rc;
-}
-static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
-
-struct DIAG_BUFFER_START {
- __le32 Size;
- __le32 DiagVersion;
- u8 BufferType;
- u8 Reserved[3];
- __le32 Reserved1;
- __le32 Reserved2;
- __le32 Reserved3;
-};
-/**
- * _ctl_host_trace_buffer_size_show - host buffer size (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_host_trace_buffer_size_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- u32 size = 0;
- struct DIAG_BUFFER_START *request_data;
-
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- request_data = (struct DIAG_BUFFER_START *)
- ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE];
- if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 ||
- le32_to_cpu(request_data->DiagVersion) == 0x01000000) &&
- le32_to_cpu(request_data->Reserved3) == 0x4742444c)
- size = le32_to_cpu(request_data->Size);
-
- ioc->ring_buffer_sz = size;
- return snprintf(buf, PAGE_SIZE, "%d\n", size);
-}
-static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO,
- _ctl_host_trace_buffer_size_show, NULL);
-
-/**
- * _ctl_host_trace_buffer_show - firmware ring buffer (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- *
- * You will only be able to read 4k bytes of ring buffer at a time.
- * In order to read beyond 4k bytes, you will have to write out the
- * offset to the same attribute, it will move the pointer.
- */
-static ssize_t
-_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr,
- char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- void *request_data;
- u32 size;
-
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) {
- printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not "
- "registered\n", ioc->name, __func__);
- return 0;
- }
-
- if (ioc->ring_buffer_offset > ioc->ring_buffer_sz)
- return 0;
-
- size = ioc->ring_buffer_sz - ioc->ring_buffer_offset;
- size = (size > PAGE_SIZE) ? PAGE_SIZE : size;
- request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset;
- memcpy(buf, request_data, size);
- return size;
-}
-
-static ssize_t
-_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int val = 0;
-
- if (sscanf(buf, "%d", &val) != 1)
- return -EINVAL;
-
- ioc->ring_buffer_offset = val;
- return strlen(buf);
-}
-static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store);
-
-/*****************************************/
-
-/**
- * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only)
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * A sysfs 'read/write' shost attribute.
- *
- * This is a mechnism to post/release host_trace_buffers
- */
-static ssize_t
-_ctl_host_trace_buffer_enable_show(struct device *cdev,
- struct device_attribute *attr, char *buf)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) ||
- ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0))
- return snprintf(buf, PAGE_SIZE, "off\n");
- else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- return snprintf(buf, PAGE_SIZE, "release\n");
- else
- return snprintf(buf, PAGE_SIZE, "post\n");
-}
-
-static ssize_t
-_ctl_host_trace_buffer_enable_store(struct device *cdev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct Scsi_Host *shost = class_to_shost(cdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- char str[10] = "";
- struct mpt2_diag_register diag_register;
- u8 issue_reset = 0;
-
- if (sscanf(buf, "%9s", str) != 1)
- return -EINVAL;
-
- if (!strcmp(str, "post")) {
- /* exit out if host buffers are already posted */
- if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) &&
- (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) &&
- ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED) == 0))
- goto out;
- memset(&diag_register, 0, sizeof(struct mpt2_diag_register));
- printk(MPT2SAS_INFO_FMT "posting host trace buffers\n",
- ioc->name);
- diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE;
- diag_register.requested_buffer_size = (1024 * 1024);
- diag_register.unique_id = 0x7075900;
- ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0;
- _ctl_diag_register_2(ioc, &diag_register);
- } else if (!strcmp(str, "release")) {
- /* exit out if host buffers are already released */
- if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE])
- goto out;
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)
- goto out;
- if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] &
- MPT2_DIAG_BUFFER_IS_RELEASED))
- goto out;
- printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n",
- ioc->name);
- _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset);
- }
-
- out:
- return strlen(buf);
-}
-static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR,
- _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store);
-
-struct device_attribute *mpt2sas_host_attrs[] = {
- &dev_attr_version_fw,
- &dev_attr_version_bios,
- &dev_attr_version_mpi,
- &dev_attr_version_product,
- &dev_attr_version_nvdata_persistent,
- &dev_attr_version_nvdata_default,
- &dev_attr_board_name,
- &dev_attr_board_assembly,
- &dev_attr_board_tracer,
- &dev_attr_io_delay,
- &dev_attr_device_delay,
- &dev_attr_logging_level,
- &dev_attr_fwfault_debug,
- &dev_attr_fw_queue_depth,
- &dev_attr_host_sas_address,
- &dev_attr_ioc_reset_count,
- &dev_attr_host_trace_buffer_size,
- &dev_attr_host_trace_buffer,
- &dev_attr_host_trace_buffer_enable,
- &dev_attr_reply_queue_count,
- &dev_attr_BRM_status,
- NULL,
-};
-
-/**
- * _ctl_device_sas_address_show - sas address
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the sas address for the target
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
-
- return snprintf(buf, PAGE_SIZE, "0x%016llx\n",
- (unsigned long long)sas_device_priv_data->sas_target->sas_address);
-}
-static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL);
-
-/**
- * _ctl_device_handle_show - device handle
- * @cdev - pointer to embedded class device
- * @buf - the buffer returned
- *
- * This is the firmware assigned device handle
- *
- * A sysfs 'read-only' shost attribute.
- */
-static ssize_t
-_ctl_device_handle_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata;
-
- return snprintf(buf, PAGE_SIZE, "0x%04x\n",
- sas_device_priv_data->sas_target->handle);
-}
-static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL);
-
-struct device_attribute *mpt2sas_dev_attrs[] = {
- &dev_attr_sas_address,
- &dev_attr_sas_device_handle,
- NULL,
-};
-
-static const struct file_operations ctl_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = _ctl_ioctl,
- .poll = _ctl_poll,
- .fasync = _ctl_fasync,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = _ctl_ioctl_compat,
-#endif
- .llseek = noop_llseek,
-};
-
-static struct miscdevice ctl_dev = {
- .minor = MPT2SAS_MINOR,
- .name = MPT2SAS_DEV_NAME,
- .fops = &ctl_fops,
-};
-
-/**
- * mpt2sas_ctl_init - main entry point for ctl.
- *
- */
-void
-mpt2sas_ctl_init(void)
-{
- async_queue = NULL;
- if (misc_register(&ctl_dev) < 0)
- printk(KERN_ERR "%s can't register misc device [minor=%d]\n",
- MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
-
- init_waitqueue_head(&ctl_poll_wait);
-}
-
-/**
- * mpt2sas_ctl_exit - exit point for ctl
- *
- */
-void
-mpt2sas_ctl_exit(void)
-{
- struct MPT2SAS_ADAPTER *ioc;
- int i;
-
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list) {
-
- /* free memory associated to diag buffers */
- for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) {
- if (!ioc->diag_buffer[i])
- continue;
- pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i],
- ioc->diag_buffer[i], ioc->diag_buffer_dma[i]);
- ioc->diag_buffer[i] = NULL;
- ioc->diag_buffer_status[i] = 0;
- }
-
- kfree(ioc->event_log);
- }
- misc_deregister(&ctl_dev);
-}
-
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
deleted file mode 100644
index 46b2fc5..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * Management Module Support for MPT (Message Passing Technology) based
- * controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_CTL_H_INCLUDED
-#define MPT2SAS_CTL_H_INCLUDED
-
-#ifdef __KERNEL__
-#include <linux/miscdevice.h>
-#endif
-
-#define MPT2SAS_DEV_NAME "mpt2ctl"
-#define MPT2_MAGIC_NUMBER 'L'
-#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
-
-/**
- * IOCTL opcodes
- */
-#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \
- struct mpt2_ioctl_iocinfo)
-#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \
- struct mpt2_ioctl_command)
-#ifdef CONFIG_COMPAT
-#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \
- struct mpt2_ioctl_command32)
-#endif
-#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \
- struct mpt2_ioctl_eventquery)
-#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \
- struct mpt2_ioctl_eventenable)
-#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \
- struct mpt2_ioctl_eventreport)
-#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \
- struct mpt2_ioctl_diag_reset)
-#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \
- struct mpt2_ioctl_btdh_mapping)
-
-/* diag buffer support */
-#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \
- struct mpt2_diag_register)
-#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \
- struct mpt2_diag_release)
-#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \
- struct mpt2_diag_unregister)
-#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \
- struct mpt2_diag_query)
-#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \
- struct mpt2_diag_read_buffer)
-
-/**
- * struct mpt2_ioctl_header - main header structure
- * @ioc_number - IOC unit number
- * @port_number - IOC port number
- * @max_data_size - maximum number bytes to transfer on read
- */
-struct mpt2_ioctl_header {
- uint32_t ioc_number;
- uint32_t port_number;
- uint32_t max_data_size;
-};
-
-/**
- * struct mpt2_ioctl_diag_reset - diagnostic reset
- * @hdr - generic header
- */
-struct mpt2_ioctl_diag_reset {
- struct mpt2_ioctl_header hdr;
-};
-
-
-/**
- * struct mpt2_ioctl_pci_info - pci device info
- * @device - pci device id
- * @function - pci function id
- * @bus - pci bus id
- * @segment_id - pci segment id
- */
-struct mpt2_ioctl_pci_info {
- union {
- struct {
- uint32_t device:5;
- uint32_t function:3;
- uint32_t bus:24;
- } bits;
- uint32_t word;
- } u;
- uint32_t segment_id;
-};
-
-
-#define MPT2_IOCTL_INTERFACE_SCSI (0x00)
-#define MPT2_IOCTL_INTERFACE_FC (0x01)
-#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
-#define MPT2_IOCTL_INTERFACE_SAS (0x03)
-#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
-#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05)
-#define MPT2_IOCTL_VERSION_LENGTH (32)
-
-/**
- * struct mpt2_ioctl_iocinfo - generic controller info
- * @hdr - generic header
- * @adapter_type - type of adapter (spi, fc, sas)
- * @port_number - port number
- * @pci_id - PCI Id
- * @hw_rev - hardware revision
- * @sub_system_device - PCI subsystem Device ID
- * @sub_system_vendor - PCI subsystem Vendor ID
- * @rsvd0 - reserved
- * @firmware_version - firmware version
- * @bios_version - BIOS version
- * @driver_version - driver version - 32 ASCII characters
- * @rsvd1 - reserved
- * @scsi_id - scsi id of adapter 0
- * @rsvd2 - reserved
- * @pci_information - pci info (2nd revision)
- */
-struct mpt2_ioctl_iocinfo {
- struct mpt2_ioctl_header hdr;
- uint32_t adapter_type;
- uint32_t port_number;
- uint32_t pci_id;
- uint32_t hw_rev;
- uint32_t subsystem_device;
- uint32_t subsystem_vendor;
- uint32_t rsvd0;
- uint32_t firmware_version;
- uint32_t bios_version;
- uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH];
- uint8_t rsvd1;
- uint8_t scsi_id;
- uint16_t rsvd2;
- struct mpt2_ioctl_pci_info pci_information;
-};
-
-
-/* number of event log entries */
-#define MPT2SAS_CTL_EVENT_LOG_SIZE (50)
-
-/**
- * struct mpt2_ioctl_eventquery - query event count and type
- * @hdr - generic header
- * @event_entries - number of events returned by get_event_report
- * @rsvd - reserved
- * @event_types - type of events currently being captured
- */
-struct mpt2_ioctl_eventquery {
- struct mpt2_ioctl_header hdr;
- uint16_t event_entries;
- uint16_t rsvd;
- uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];
-};
-
-/**
- * struct mpt2_ioctl_eventenable - enable/disable event capturing
- * @hdr - generic header
- * @event_types - toggle off/on type of events to be captured
- */
-struct mpt2_ioctl_eventenable {
- struct mpt2_ioctl_header hdr;
- uint32_t event_types[4];
-};
-
-#define MPT2_EVENT_DATA_SIZE (192)
-/**
- * struct MPT2_IOCTL_EVENTS -
- * @event - the event that was reported
- * @context - unique value for each event assigned by driver
- * @data - event data returned in fw reply message
- */
-struct MPT2_IOCTL_EVENTS {
- uint32_t event;
- uint32_t context;
- uint8_t data[MPT2_EVENT_DATA_SIZE];
-};
-
-/**
- * struct mpt2_ioctl_eventreport - returing event log
- * @hdr - generic header
- * @event_data - (see struct MPT2_IOCTL_EVENTS)
- */
-struct mpt2_ioctl_eventreport {
- struct mpt2_ioctl_header hdr;
- struct MPT2_IOCTL_EVENTS event_data[1];
-};
-
-/**
- * struct mpt2_ioctl_command - generic mpt firmware passthru ioctl
- * @hdr - generic header
- * @timeout - command timeout in seconds. (if zero then use driver default
- * value).
- * @reply_frame_buf_ptr - reply location
- * @data_in_buf_ptr - destination for read
- * @data_out_buf_ptr - data source for write
- * @sense_data_ptr - sense data location
- * @max_reply_bytes - maximum number of reply bytes to be sent to app.
- * @data_in_size - number bytes for data transfer in (read)
- * @data_out_size - number bytes for data transfer out (write)
- * @max_sense_bytes - maximum number of bytes for auto sense buffers
- * @data_sge_offset - offset in words from the start of the request message to
- * the first SGL
- * @mf[1];
- */
-struct mpt2_ioctl_command {
- struct mpt2_ioctl_header hdr;
- uint32_t timeout;
- void __user *reply_frame_buf_ptr;
- void __user *data_in_buf_ptr;
- void __user *data_out_buf_ptr;
- void __user *sense_data_ptr;
- uint32_t max_reply_bytes;
- uint32_t data_in_size;
- uint32_t data_out_size;
- uint32_t max_sense_bytes;
- uint32_t data_sge_offset;
- uint8_t mf[1];
-};
-
-#ifdef CONFIG_COMPAT
-struct mpt2_ioctl_command32 {
- struct mpt2_ioctl_header hdr;
- uint32_t timeout;
- uint32_t reply_frame_buf_ptr;
- uint32_t data_in_buf_ptr;
- uint32_t data_out_buf_ptr;
- uint32_t sense_data_ptr;
- uint32_t max_reply_bytes;
- uint32_t data_in_size;
- uint32_t data_out_size;
- uint32_t max_sense_bytes;
- uint32_t data_sge_offset;
- uint8_t mf[1];
-};
-#endif
-
-/**
- * struct mpt2_ioctl_btdh_mapping - mapping info
- * @hdr - generic header
- * @id - target device identification number
- * @bus - SCSI bus number that the target device exists on
- * @handle - device handle for the target device
- * @rsvd - reserved
- *
- * To obtain a bus/id the application sets
- * handle to valid handle, and bus/id to 0xFFFF.
- *
- * To obtain the device handle the application sets
- * bus/id valid value, and the handle to 0xFFFF.
- */
-struct mpt2_ioctl_btdh_mapping {
- struct mpt2_ioctl_header hdr;
- uint32_t id;
- uint32_t bus;
- uint16_t handle;
- uint16_t rsvd;
-};
-
-
-/* status bits for ioc->diag_buffer_status */
-#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01)
-#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02)
-#define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04)
-
-/* application flags for mpt2_diag_register, mpt2_diag_query */
-#define MPT2_APP_FLAGS_APP_OWNED (0x0001)
-#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002)
-#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004)
-
-/* flags for mpt2_diag_read_buffer */
-#define MPT2_FLAGS_REREGISTER (0x0001)
-
-#define MPT2_PRODUCT_SPECIFIC_DWORDS 23
-
-/**
- * struct mpt2_diag_register - application register with driver
- * @hdr - generic header
- * @reserved -
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @application_flags - misc flags
- * @diagnostic_flags - specifies flags affecting command processing
- * @product_specific - product specific information
- * @requested_buffer_size - buffers size in bytes
- * @unique_id - tag specified by application that is used to signal ownership
- * of the buffer.
- *
- * This will allow the driver to setup any required buffers that will be
- * needed by firmware to communicate with the driver.
- */
-struct mpt2_diag_register {
- struct mpt2_ioctl_header hdr;
- uint8_t reserved;
- uint8_t buffer_type;
- uint16_t application_flags;
- uint32_t diagnostic_flags;
- uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
- uint32_t requested_buffer_size;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_unregister - application unregister with driver
- * @hdr - generic header
- * @unique_id - tag uniquely identifies the buffer to be unregistered
- *
- * This will allow the driver to cleanup any memory allocated for diag
- * messages and to free up any resources.
- */
-struct mpt2_diag_unregister {
- struct mpt2_ioctl_header hdr;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_query - query relevant info associated with diag buffers
- * @hdr - generic header
- * @reserved -
- * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED
- * @application_flags - misc flags
- * @diagnostic_flags - specifies flags affecting command processing
- * @product_specific - product specific information
- * @total_buffer_size - diag buffer size in bytes
- * @driver_added_buffer_size - size of extra space appended to end of buffer
- * @unique_id - unique id associated with this buffer.
- *
- * The application will send only buffer_type and unique_id. Driver will
- * inspect unique_id first, if valid, fill in all the info. If unique_id is
- * 0x00, the driver will return info specified by Buffer Type.
- */
-struct mpt2_diag_query {
- struct mpt2_ioctl_header hdr;
- uint8_t reserved;
- uint8_t buffer_type;
- uint16_t application_flags;
- uint32_t diagnostic_flags;
- uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS];
- uint32_t total_buffer_size;
- uint32_t driver_added_buffer_size;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_release - request to send Diag Release Message to firmware
- * @hdr - generic header
- * @unique_id - tag uniquely identifies the buffer to be released
- *
- * This allows ownership of the specified buffer to returned to the driver,
- * allowing an application to read the buffer without fear that firmware is
- * overwritting information in the buffer.
- */
-struct mpt2_diag_release {
- struct mpt2_ioctl_header hdr;
- uint32_t unique_id;
-};
-
-/**
- * struct mpt2_diag_read_buffer - request for copy of the diag buffer
- * @hdr - generic header
- * @status -
- * @reserved -
- * @flags - misc flags
- * @starting_offset - starting offset within drivers buffer where to start
- * reading data at into the specified application buffer
- * @bytes_to_read - number of bytes to copy from the drivers buffer into the
- * application buffer starting at starting_offset.
- * @unique_id - unique id associated with this buffer.
- * @diagnostic_data - data payload
- */
-struct mpt2_diag_read_buffer {
- struct mpt2_ioctl_header hdr;
- uint8_t status;
- uint8_t reserved;
- uint16_t flags;
- uint32_t starting_offset;
- uint32_t bytes_to_read;
- uint32_t unique_id;
- uint32_t diagnostic_data[1];
-};
-
-#endif /* MPT2SAS_CTL_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
deleted file mode 100644
index 277120d..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Logging Support for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#ifndef MPT2SAS_DEBUG_H_INCLUDED
-#define MPT2SAS_DEBUG_H_INCLUDED
-
-#define MPT_DEBUG 0x00000001
-#define MPT_DEBUG_MSG_FRAME 0x00000002
-#define MPT_DEBUG_SG 0x00000004
-#define MPT_DEBUG_EVENTS 0x00000008
-#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010
-#define MPT_DEBUG_INIT 0x00000020
-#define MPT_DEBUG_EXIT 0x00000040
-#define MPT_DEBUG_FAIL 0x00000080
-#define MPT_DEBUG_TM 0x00000100
-#define MPT_DEBUG_REPLY 0x00000200
-#define MPT_DEBUG_HANDSHAKE 0x00000400
-#define MPT_DEBUG_CONFIG 0x00000800
-#define MPT_DEBUG_DL 0x00001000
-#define MPT_DEBUG_RESET 0x00002000
-#define MPT_DEBUG_SCSI 0x00004000
-#define MPT_DEBUG_IOCTL 0x00008000
-#define MPT_DEBUG_CSMISAS 0x00010000
-#define MPT_DEBUG_SAS 0x00020000
-#define MPT_DEBUG_TRANSPORT 0x00040000
-#define MPT_DEBUG_TASK_SET_FULL 0x00080000
-
-#define MPT_DEBUG_TARGET_MODE 0x00100000
-
-
-/*
- * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig
- */
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
-{ \
- if (IOC->logging_level & BITS) \
- CMD; \
-}
-#else
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
-#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
-
-
-/*
- * debug macros
- */
-
-#define dprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG)
-
-#define dsgprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG)
-
-#define devtprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS)
-
-#define dewtprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK)
-
-#define dinitprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT)
-
-#define dexitprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT)
-
-#define dfailprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL)
-
-#define dtmprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM)
-
-#define dreplyprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY)
-
-#define dhsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE)
-
-#define dcprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG)
-
-#define ddlprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL)
-
-#define drsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET)
-
-#define dsprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI)
-
-#define dctlprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL)
-
-#define dcsmisasprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS)
-
-#define dsasprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS)
-
-#define dsastransport(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE)
-
-#define dmfprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME)
-
-#define dtsfprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL)
-
-#define dtransportprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT)
-
-#define dTMprintk(IOC, CMD) \
- MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE)
-
-/* inline functions for dumping debug data*/
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _debug_dump_mf - print message frame contents
- * @mpi_request: pointer to message frame
- * @sz: number of dwords
- */
-static inline void
-_debug_dump_mf(void *mpi_request, int sz)
-{
- int i;
- __le32 *mfp = (__le32 *)mpi_request;
-
- printk(KERN_INFO "mf:\n\t");
- for (i = 0; i < sz; i++) {
- if (i && ((i % 8) == 0))
- printk("\n\t");
- printk("%08x ", le32_to_cpu(mfp[i]));
- }
- printk("\n");
-}
-#else
-#define _debug_dump_mf(mpi_request, sz)
-#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */
-
-#endif /* MPT2SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
deleted file mode 100644
index 0ad09b2..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ /dev/null
@@ -1,8855 +0,0 @@
-/*
- * Scsi Host Layer for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/blkdev.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/aer.h>
-#include <linux/raid_class.h>
-#include <linux/slab.h>
-
-#include <asm/unaligned.h>
-
-#include "mpt2sas_base.h"
-
-MODULE_AUTHOR(MPT2SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT2SAS_DRIVER_VERSION);
-
-#define RAID_CHANNEL 1
-
-/* forward proto's */
-static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander);
-static void _firmware_event_work(struct work_struct *work);
-
-static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-
-static void _scsih_scan_start(struct Scsi_Host *shost);
-static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
-
-/* global parameters */
-LIST_HEAD(mpt2sas_ioc_list);
-/* global ioc lock for list operations */
-DEFINE_SPINLOCK(gioc_lock);
-/* local parameters */
-static u8 scsi_io_cb_idx = -1;
-static u8 tm_cb_idx = -1;
-static u8 ctl_cb_idx = -1;
-static u8 base_cb_idx = -1;
-static u8 port_enable_cb_idx = -1;
-static u8 transport_cb_idx = -1;
-static u8 scsih_cb_idx = -1;
-static u8 config_cb_idx = -1;
-static int mpt_ids;
-
-static u8 tm_tr_cb_idx = -1 ;
-static u8 tm_tr_volume_cb_idx = -1 ;
-static u8 tm_sas_control_cb_idx = -1;
-
-/* command line options */
-static u32 logging_level;
-MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
- "(default=0)");
-
-static ushort max_sectors = 0xFFFF;
-module_param(max_sectors, ushort, 0);
-MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767");
-
-static int missing_delay[2] = {-1, -1};
-module_param_array(missing_delay, int, NULL, 0);
-MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay");
-
-/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
-#define MPT2SAS_MAX_LUN (16895)
-static int max_lun = MPT2SAS_MAX_LUN;
-module_param(max_lun, int, 0);
-MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-
-/* diag_buffer_enable is bitwise
- * bit 0 set = TRACE
- * bit 1 set = SNAPSHOT
- * bit 2 set = EXTENDED
- *
- * Either bit can be set, or both
- */
-static int diag_buffer_enable = -1;
-module_param(diag_buffer_enable, int, 0);
-MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers "
- "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)");
-
-static int disable_discovery = -1;
-module_param(disable_discovery, int, 0);
-MODULE_PARM_DESC(disable_discovery, " disable discovery ");
-
-/* permit overriding the host protection capabilities mask (EEDP/T10 PI) */
-static int prot_mask = 0;
-module_param(prot_mask, int, 0);
-MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
-
-/**
- * struct sense_info - common structure for obtaining sense keys
- * @skey: sense key
- * @asc: additional sense code
- * @ascq: additional sense code qualifier
- */
-struct sense_info {
- u8 skey;
- u8 asc;
- u8 ascq;
-};
-
-
-#define MPT2SAS_TURN_ON_PFA_LED (0xFFFC)
-#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD)
-#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF)
-/**
- * struct fw_event_work - firmware event struct
- * @list: link list framework
- * @work: work object (ioc->fault_reset_work_q)
- * @cancel_pending_work: flag set during reset handling
- * @ioc: per adapter object
- * @device_handle: device handle
- * @VF_ID: virtual function id
- * @VP_ID: virtual port id
- * @ignore: flag meaning this event has been marked to ignore
- * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
- * @event_data: reply event data payload follows
- *
- * This object stored on ioc->fw_event_list.
- */
-struct fw_event_work {
- struct list_head list;
- u8 cancel_pending_work;
- struct delayed_work delayed_work;
- struct MPT2SAS_ADAPTER *ioc;
- u16 device_handle;
- u8 VF_ID;
- u8 VP_ID;
- u8 ignore;
- u16 event;
- struct kref refcount;
- char event_data[0] __aligned(4);
-};
-
-static void fw_event_work_free(struct kref *r)
-{
- kfree(container_of(r, struct fw_event_work, refcount));
-}
-
-static void fw_event_work_get(struct fw_event_work *fw_work)
-{
- kref_get(&fw_work->refcount);
-}
-
-static void fw_event_work_put(struct fw_event_work *fw_work)
-{
- kref_put(&fw_work->refcount, fw_event_work_free);
-}
-
-static struct fw_event_work *alloc_fw_event_work(int len)
-{
- struct fw_event_work *fw_event;
-
- fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC);
- if (!fw_event)
- return NULL;
-
- kref_init(&fw_event->refcount);
- return fw_event;
-}
-
-/* raid transport support */
-static struct raid_template *mpt2sas_raid_template;
-
-/**
- * struct _scsi_io_transfer - scsi io transfer
- * @handle: sas device handle (assigned by firmware)
- * @is_raid: flag set for hidden raid components
- * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE,
- * @data_length: data transfer length
- * @data_dma: dma pointer to data
- * @sense: sense data
- * @lun: lun number
- * @cdb_length: cdb length
- * @cdb: cdb contents
- * @timeout: timeout for this command
- * @VF_ID: virtual function id
- * @VP_ID: virtual port id
- * @valid_reply: flag set for reply message
- * @sense_length: sense length
- * @ioc_status: ioc status
- * @scsi_state: scsi state
- * @scsi_status: scsi staus
- * @log_info: log information
- * @transfer_length: data length transfer when there is a reply message
- *
- * Used for sending internal scsi commands to devices within this module.
- * Refer to _scsi_send_scsi_io().
- */
-struct _scsi_io_transfer {
- u16 handle;
- u8 is_raid;
- enum dma_data_direction dir;
- u32 data_length;
- dma_addr_t data_dma;
- u8 sense[SCSI_SENSE_BUFFERSIZE];
- u32 lun;
- u8 cdb_length;
- u8 cdb[32];
- u8 timeout;
- u8 VF_ID;
- u8 VP_ID;
- u8 valid_reply;
- /* the following bits are only valid when 'valid_reply = 1' */
- u32 sense_length;
- u16 ioc_status;
- u8 scsi_state;
- u8 scsi_status;
- u32 log_info;
- u32 transfer_length;
-};
-
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static struct pci_device_id scsih_pci_table[] = {
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Falcon ~ 2008*/
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Liberator ~ 2108 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Meteor ~ 2116 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Thunderbolt ~ 2208 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Mustang ~ 2308 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
- PCI_ANY_ID, PCI_ANY_ID },
- /* SSS6200 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
- PCI_ANY_ID, PCI_ANY_ID },
- {0} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, scsih_pci_table);
-
-/**
- * _scsih_set_debug_level - global setting of ioc->logging_level.
- *
- * Note: The logging levels are defined in mpt2sas_debug.h.
- */
-static int
-_scsih_set_debug_level(const char *val, struct kernel_param *kp)
-{
- int ret = param_set_int(val, kp);
- struct MPT2SAS_ADAPTER *ioc;
-
- if (ret)
- return ret;
-
- printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level);
- spin_lock(&gioc_lock);
- list_for_each_entry(ioc, &mpt2sas_ioc_list, list)
- ioc->logging_level = logging_level;
- spin_unlock(&gioc_lock);
- return 0;
-}
-module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
- &logging_level, 0644);
-
-/**
- * _scsih_srch_boot_sas_address - search based on sas_address
- * @sas_address: sas address
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_sas_address(u64 sas_address,
- Mpi2BootDeviceSasWwid_t *boot_device)
-{
- return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
-}
-
-/**
- * _scsih_srch_boot_device_name - search based on device name
- * @device_name: device name specified in INDENTIFY fram
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_device_name(u64 device_name,
- Mpi2BootDeviceDeviceName_t *boot_device)
-{
- return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
-}
-
-/**
- * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot
- * @enclosure_logical_id: enclosure logical id
- * @slot_number: slot number
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static inline int
-_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
- Mpi2BootDeviceEnclosureSlot_t *boot_device)
-{
- return (enclosure_logical_id == le64_to_cpu(boot_device->
- EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
- SlotNumber)) ? 1 : 0;
-}
-
-/**
- * _scsih_is_boot_device - search for matching boot device.
- * @sas_address: sas address
- * @device_name: device name specified in INDENTIFY fram
- * @enclosure_logical_id: enclosure logical id
- * @slot_number: slot number
- * @form: specifies boot device form
- * @boot_device: boot device object from bios page 2
- *
- * Returns 1 when there's a match, 0 means no match.
- */
-static int
-_scsih_is_boot_device(u64 sas_address, u64 device_name,
- u64 enclosure_logical_id, u16 slot, u8 form,
- Mpi2BiosPage2BootDevice_t *boot_device)
-{
- int rc = 0;
-
- switch (form) {
- case MPI2_BIOSPAGE2_FORM_SAS_WWID:
- if (!sas_address)
- break;
- rc = _scsih_srch_boot_sas_address(
- sas_address, &boot_device->SasWwid);
- break;
- case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT:
- if (!enclosure_logical_id)
- break;
- rc = _scsih_srch_boot_encl_slot(
- enclosure_logical_id,
- slot, &boot_device->EnclosureSlot);
- break;
- case MPI2_BIOSPAGE2_FORM_DEVICE_NAME:
- if (!device_name)
- break;
- rc = _scsih_srch_boot_device_name(
- device_name, &boot_device->DeviceName);
- break;
- case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED:
- break;
- }
-
- return rc;
-}
-
-/**
- * _scsih_get_sas_address - set the sas_address for given device handle
- * @handle: device handle
- * @sas_address: sas address
- *
- * Returns 0 success, non-zero when failure
- */
-static int
-_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u64 *sas_address)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 ioc_status;
- *sas_address = 0;
-
- if (handle <= ioc->sas_hba.num_phys) {
- *sas_address = ioc->sas_hba.sas_address;
- return 0;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_SUCCESS) {
- *sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- return 0;
- }
-
- /* we hit this becuase the given parent handle doesn't exist */
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- return -ENXIO;
- /* else error case */
- printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), "
- "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
- return -EIO;
-}
-
-/**
- * _scsih_determine_boot_device - determine boot device.
- * @ioc: per adapter object
- * @device: either sas_device or raid_device object
- * @is_raid: [flag] 1 = raid object, 0 = sas object
- *
- * Determines whether this device should be first reported device to
- * to scsi-ml or sas transport, this purpose is for persistent boot device.
- * There are primary, alternate, and current entries in bios page 2. The order
- * priority is primary, alternate, then current. This routine saves
- * the corresponding device object and is_raid flag in the ioc object.
- * The saved data to be used later in _scsih_probe_boot_devices().
- */
-static void
-_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc,
- void *device, u8 is_raid)
-{
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- u64 sas_address;
- u64 device_name;
- u64 enclosure_logical_id;
- u16 slot;
-
- /* only process this function when driver loads */
- if (!ioc->is_driver_loading)
- return;
-
- /* no Bios, return immediately */
- if (!ioc->bios_pg3.BiosVersion)
- return;
-
- if (!is_raid) {
- sas_device = device;
- sas_address = sas_device->sas_address;
- device_name = sas_device->device_name;
- enclosure_logical_id = sas_device->enclosure_logical_id;
- slot = sas_device->slot;
- } else {
- raid_device = device;
- sas_address = raid_device->wwid;
- device_name = 0;
- enclosure_logical_id = 0;
- slot = 0;
- }
-
- if (!ioc->req_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.ReqBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.RequestedBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: req_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->req_boot_device.device = device;
- ioc->req_boot_device.is_raid = is_raid;
- }
- }
-
- if (!ioc->req_alt_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.ReqAltBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.RequestedAltBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: req_alt_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->req_alt_boot_device.device = device;
- ioc->req_alt_boot_device.is_raid = is_raid;
- }
- }
-
- if (!ioc->current_boot_device.device) {
- if (_scsih_is_boot_device(sas_address, device_name,
- enclosure_logical_id, slot,
- (ioc->bios_pg2.CurrentBootDeviceForm &
- MPI2_BIOSPAGE2_FORM_MASK),
- &ioc->bios_pg2.CurrentBootDevice)) {
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: current_boot_device(0x%016llx)\n",
- ioc->name, __func__,
- (unsigned long long)sas_address));
- ioc->current_boot_device.device = device;
- ioc->current_boot_device.is_raid = is_raid;
- }
- }
-}
-
-static struct _sas_device *
-__mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc,
- struct MPT2SAS_TARGET *tgt_priv)
-{
- struct _sas_device *ret;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- ret = tgt_priv->sdev;
- if (ret)
- sas_device_get(ret);
-
- return ret;
-}
-
-static struct _sas_device *
-mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc,
- struct MPT2SAS_TARGET *tgt_priv)
-{
- struct _sas_device *ret;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return ret;
-}
-
-
-struct _sas_device *
-__mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->sas_address == sas_address)
- goto found_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->sas_address == sas_address)
- goto found_device;
-
- return NULL;
-
-found_device:
- sas_device_get(sas_device);
- return sas_device;
-}
-
-/**
- * mpt2sas_get_sdev_by_addr - sas device search
- * @ioc: per adapter object
- * @sas_address: sas address
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-struct _sas_device *
-mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-static struct _sas_device *
-__mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
-
- assert_spin_locked(&ioc->sas_device_lock);
-
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->handle == handle)
- goto found_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->handle == handle)
- goto found_device;
-
- return NULL;
-
-found_device:
- sas_device_get(sas_device);
- return sas_device;
-}
-
-/**
- * mpt2sas_get_sdev_by_handle - sas device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for sas_device based on sas_address, then return sas_device
- * object.
- */
-static struct _sas_device *
-mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-/**
- * _scsih_sas_device_remove - remove sas_device from list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * If sas_device is on the list, remove it and decrement its reference count.
- */
-static void
-_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- if (!sas_device)
- return;
-
- /*
- * The lock serializes access to the list, but we still need to verify
- * that nobody removed the entry while we were waiting on the lock.
- */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (!list_empty(&sas_device->list)) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-
-/**
- * _scsih_sas_device_add - insert sas_device to the list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * Adding new object to the ioc->sas_device_list.
- */
-static void
-_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)sas_device->sas_address));
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- } else if (!sas_device->starget) {
- /* When asyn scanning is enabled, its not possible to remove
- * devices while scanning is turned on due to an oops in
- * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
- */
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- }
- }
-}
-
-/**
- * _scsih_sas_device_init_add - insert sas_device to the list.
- * @ioc: per adapter object
- * @sas_device: the sas_device object
- * Context: This function will acquire ioc->sas_device_lock.
- *
- * Adding new object at driver load time to the ioc->sas_device_init_list.
- */
-static void
-_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)sas_device->sas_address));
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
- _scsih_determine_boot_device(ioc, sas_device, 0);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_raid_device_find_by_id - raid device search
- * @ioc: per adapter object
- * @id: sas device target id
- * @channel: sas device channel
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on target id, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->id == id && raid_device->channel == channel) {
- r = raid_device;
- goto out;
- }
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_find_by_handle - raid device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on handle, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->handle != handle)
- continue;
- r = raid_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_find_by_wwid - raid device search
- * @ioc: per adapter object
- * @handle: sas device handle (assigned by firmware)
- * Context: Calling function should acquire ioc->raid_device_lock
- *
- * This searches for raid_device based on wwid, then return raid_device
- * object.
- */
-static struct _raid_device *
-_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid)
-{
- struct _raid_device *raid_device, *r;
-
- r = NULL;
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->wwid != wwid)
- continue;
- r = raid_device;
- goto out;
- }
-
- out:
- return r;
-}
-
-/**
- * _scsih_raid_device_add - add raid_device object
- * @ioc: per adapter object
- * @raid_device: raid_device object
- *
- * This is added to the raid_device_list link list.
- */
-static void
-_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- unsigned long flags;
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle"
- "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__,
- raid_device->handle, (unsigned long long)raid_device->wwid));
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_add_tail(&raid_device->list, &ioc->raid_device_list);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_raid_device_remove - delete raid_device object
- * @ioc: per adapter object
- * @raid_device: raid_device object
- *
- */
-static void
-_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_del(&raid_device->list);
- kfree(raid_device);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * mpt2sas_scsih_expander_find_by_handle - expander device search
- * @ioc: per adapter object
- * @handle: expander handle (assigned by firmware)
- * Context: Calling function should acquire ioc->sas_device_lock
- *
- * This searches for expander device based on handle, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->handle != handle)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
- * mpt2sas_scsih_expander_find_by_sas_address - expander device search
- * @ioc: per adapter object
- * @sas_address: sas address
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * This searches for expander device based on sas_address, then returns the
- * sas_node object.
- */
-struct _sas_node *
-mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_node *sas_expander, *r;
-
- r = NULL;
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address != sas_address)
- continue;
- r = sas_expander;
- goto out;
- }
- out:
- return r;
-}
-
-/**
- * _scsih_expander_node_add - insert expander device to the list.
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Adding new object to the ioc->sas_expander_list.
- *
- * Return nothing.
- */
-static void
-_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_add_tail(&sas_expander->list, &ioc->sas_expander_list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-}
-
-/**
- * _scsih_is_end_device - determines if device is an end device
- * @device_info: bitfield providing information about the device.
- * Context: none
- *
- * Returns 1 if end device.
- */
-static int
-_scsih_is_end_device(u32 device_info)
-{
- if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
- ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
- (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
- (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)))
- return 1;
- else
- return 0;
-}
-
-/**
- * _scsih_scsi_lookup_get - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- */
-static struct scsi_cmnd *
-_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->scsi_lookup[smid - 1].scmd;
-}
-
-/**
- * _scsih_scsi_lookup_get_clear - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- * Then will derefrence the stored scmd pointer.
- */
-static inline struct scsi_cmnd *
-_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- unsigned long flags;
- struct scsi_cmnd *scmd;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- scmd = ioc->scsi_lookup[smid - 1].scmd;
- ioc->scsi_lookup[smid - 1].scmd = NULL;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
-
- return scmd;
-}
-
-/**
- * _scsih_scsi_lookup_find_by_scmd - scmd lookup
- * @ioc: per adapter object
- * @smid: system request message index
- * @scmd: pointer to scsi command object
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will search for a scmd pointer in the scsi_lookup array,
- * returning the revelent smid. A returned value of zero means invalid.
- */
-static u16
-_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
- *scmd)
-{
- u16 smid;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- smid = 0;
- for (i = 0; i < ioc->scsiio_depth; i++) {
- if (ioc->scsi_lookup[i].scmd == scmd) {
- smid = ioc->scsi_lookup[i].smid;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return smid;
-}
-
-/**
- * _scsih_scsi_lookup_find_by_target - search for matching channel:id
- * @ioc: per adapter object
- * @id: target id
- * @channel: channel
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will search for a matching channel:id in the scsi_lookup array,
- * returning 1 if found.
- */
-static u8
-_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
- int channel)
-{
- u8 found;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- found = 0;
- for (i = 0 ; i < ioc->scsiio_depth; i++) {
- if (ioc->scsi_lookup[i].scmd &&
- (ioc->scsi_lookup[i].scmd->device->id == id &&
- ioc->scsi_lookup[i].scmd->device->channel == channel)) {
- found = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return found;
-}
-
-/**
- * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun
- * @ioc: per adapter object
- * @id: target id
- * @lun: lun number
- * @channel: channel
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will search for a matching channel:id:lun in the scsi_lookup array,
- * returning 1 if found.
- */
-static u8
-_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
- unsigned int lun, int channel)
-{
- u8 found;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- found = 0;
- for (i = 0 ; i < ioc->scsiio_depth; i++) {
- if (ioc->scsi_lookup[i].scmd &&
- (ioc->scsi_lookup[i].scmd->device->id == id &&
- ioc->scsi_lookup[i].scmd->device->channel == channel &&
- ioc->scsi_lookup[i].scmd->device->lun == lun)) {
- found = 1;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return found;
-}
-
-/**
- * _scsih_get_chain_buffer_tracker - obtain chain tracker
- * @ioc: per adapter object
- * @smid: smid associated to an IO request
- *
- * Returns chain tracker(from ioc->free_chain_list)
- */
-static struct chain_tracker *
-_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- struct chain_tracker *chain_req;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- if (list_empty(&ioc->free_chain_list)) {
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not "
- "available\n", ioc->name));
- return NULL;
- }
- chain_req = list_entry(ioc->free_chain_list.next,
- struct chain_tracker, tracker_list);
- list_del_init(&chain_req->tracker_list);
- list_add_tail(&chain_req->tracker_list,
- &ioc->scsi_lookup[smid - 1].chain_list);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return chain_req;
-}
-
-/**
- * _scsih_build_scatter_gather - main sg creation routine
- * @ioc: per adapter object
- * @scmd: scsi command
- * @smid: system request message index
- * Context: none.
- *
- * The main routine that builds scatter gather table from a given
- * scsi request sent via the .queuecommand main handler.
- *
- * Returns 0 success, anything else error
- */
-static int
-_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
- struct scsi_cmnd *scmd, u16 smid)
-{
- Mpi2SCSIIORequest_t *mpi_request;
- dma_addr_t chain_dma;
- struct scatterlist *sg_scmd;
- void *sg_local, *chain;
- u32 chain_offset;
- u32 chain_length;
- u32 chain_flags;
- int sges_left;
- u32 sges_in_segment;
- u32 sgl_flags;
- u32 sgl_flags_last_element;
- u32 sgl_flags_end_buffer;
- struct chain_tracker *chain_req;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
-
- /* init scatter gather flags */
- sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
- if (scmd->sc_data_direction == DMA_TO_DEVICE)
- sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
- sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
- << MPI2_SGE_FLAGS_SHIFT;
- sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
- << MPI2_SGE_FLAGS_SHIFT;
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-
- sg_scmd = scsi_sglist(scmd);
- sges_left = scsi_dma_map(scmd);
- if (sges_left < 0) {
- sdev_printk(KERN_ERR, scmd->device, "pci_map_sg"
- " failed: request for %d bytes!\n", scsi_bufflen(scmd));
- return -ENOMEM;
- }
-
- sg_local = &mpi_request->SGL;
- sges_in_segment = ioc->max_sges_in_main_message;
- if (sges_left <= sges_in_segment)
- goto fill_in_last_segment;
-
- mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
- (sges_in_segment * ioc->sge_size))/4;
-
- /* fill in main message segment when there is a chain following */
- while (sges_in_segment) {
- if (sges_in_segment == 1)
- ioc->base_add_sg_single(sg_local,
- sgl_flags_last_element | sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- sges_in_segment--;
- }
-
- /* initializing the chain flags and pointers */
- chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
- chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
- if (!chain_req)
- return -1;
- chain = chain_req->chain_buffer;
- chain_dma = chain_req->chain_buffer_dma;
- do {
- sges_in_segment = (sges_left <=
- ioc->max_sges_in_chain_message) ? sges_left :
- ioc->max_sges_in_chain_message;
- chain_offset = (sges_left == sges_in_segment) ?
- 0 : (sges_in_segment * ioc->sge_size)/4;
- chain_length = sges_in_segment * ioc->sge_size;
- if (chain_offset) {
- chain_offset = chain_offset <<
- MPI2_SGE_CHAIN_OFFSET_SHIFT;
- chain_length += ioc->sge_size;
- }
- ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
- chain_length, chain_dma);
- sg_local = chain;
- if (!chain_offset)
- goto fill_in_last_segment;
-
- /* fill in chain segments */
- while (sges_in_segment) {
- if (sges_in_segment == 1)
- ioc->base_add_sg_single(sg_local,
- sgl_flags_last_element |
- sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd),
- sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- sges_in_segment--;
- }
-
- chain_req = _scsih_get_chain_buffer_tracker(ioc, smid);
- if (!chain_req)
- return -1;
- chain = chain_req->chain_buffer;
- chain_dma = chain_req->chain_buffer_dma;
- } while (1);
-
-
- fill_in_last_segment:
-
- /* fill the last segment */
- while (sges_left) {
- if (sges_left == 1)
- ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- else
- ioc->base_add_sg_single(sg_local, sgl_flags |
- sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
- sg_scmd = sg_next(sg_scmd);
- sg_local += ioc->sge_size;
- sges_left--;
- }
-
- return 0;
-}
-
-/**
- * _scsih_change_queue_depth - setting device queue depth
- * @sdev: scsi device struct
- * @qdepth: requested queue depth
- *
- * Returns queue depth.
- */
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
-{
- struct Scsi_Host *shost = sdev->host;
- int max_depth;
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- max_depth = shost->can_queue;
-
- /* limit max device queue for SATA to 32 */
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- goto not_sata;
- sas_target_priv_data = sas_device_priv_data->sas_target;
- if (!sas_target_priv_data)
- goto not_sata;
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
- goto not_sata;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data);
- if (sas_device) {
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- max_depth = MPT2SAS_SATA_QUEUE_DEPTH;
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- not_sata:
- if (!sdev->tagged_supported)
- max_depth = 1;
- if (qdepth > max_depth)
- qdepth = max_depth;
- return scsi_change_queue_depth(sdev, qdepth);
-}
-
-/**
- * _scsih_target_alloc - target add routine
- * @starget: scsi target struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_target_alloc(struct scsi_target *starget)
-{
- struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- struct sas_rphy *rphy;
-
- sas_target_priv_data = kzalloc(sizeof(*sas_target_priv_data),
- GFP_KERNEL);
- if (!sas_target_priv_data)
- return -ENOMEM;
-
- starget->hostdata = sas_target_priv_data;
- sas_target_priv_data->starget = starget;
- sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
-
- /* RAID volumes */
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
- starget->channel);
- if (raid_device) {
- sas_target_priv_data->handle = raid_device->handle;
- sas_target_priv_data->sas_address = raid_device->wwid;
- sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- if (ioc->is_warpdrive)
- sas_target_priv_data->raid_device = raid_device;
- raid_device->starget = starget;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return 0;
- }
-
- /* sas/sata devices */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- rphy = dev_to_rphy(starget->dev.parent);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
-
- if (sas_device) {
- sas_target_priv_data->handle = sas_device->handle;
- sas_target_priv_data->sas_address = sas_device->sas_address;
- sas_target_priv_data->sdev = sas_device;
- sas_device->starget = starget;
- sas_device->id = starget->id;
- sas_device->channel = starget->channel;
- if (test_bit(sas_device->handle, ioc->pd_handles))
- sas_target_priv_data->flags |=
- MPT_TARGET_FLAGS_RAID_COMPONENT;
-
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return 0;
-}
-
-/**
- * _scsih_target_destroy - target destroy routine
- * @starget: scsi target struct
- *
- * Returns nothing.
- */
-static void
-_scsih_target_destroy(struct scsi_target *starget)
-{
- struct Scsi_Host *shost = dev_to_shost(&starget->dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- struct sas_rphy *rphy;
-
- sas_target_priv_data = starget->hostdata;
- if (!sas_target_priv_data)
- return;
-
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, starget->id,
- starget->channel);
- if (raid_device) {
- raid_device->starget = NULL;
- raid_device->sdev = NULL;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- goto out;
- }
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- rphy = dev_to_rphy(starget->dev.parent);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data);
- if (sas_device && (sas_device->starget == starget) &&
- (sas_device->id == starget->id) &&
- (sas_device->channel == starget->channel))
- sas_device->starget = NULL;
-
- if (sas_device) {
- /*
- * Corresponding get() is in _scsih_target_alloc()
- */
- sas_target_priv_data->sdev = NULL;
- sas_device_put(sas_device);
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- out:
- kfree(sas_target_priv_data);
- starget->hostdata = NULL;
-}
-
-/**
- * _scsih_slave_alloc - device add routine
- * @sdev: scsi device struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_slave_alloc(struct scsi_device *sdev)
-{
- struct Scsi_Host *shost;
- struct MPT2SAS_ADAPTER *ioc;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_target *starget;
- struct _raid_device *raid_device;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- sas_device_priv_data = kzalloc(sizeof(*sas_device_priv_data),
- GFP_KERNEL);
- if (!sas_device_priv_data)
- return -ENOMEM;
-
- sas_device_priv_data->lun = sdev->lun;
- sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT;
-
- starget = scsi_target(sdev);
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->num_luns++;
- sas_device_priv_data->sas_target = sas_target_priv_data;
- sdev->hostdata = sas_device_priv_data;
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT))
- sdev->no_uld_attach = 1;
-
- shost = dev_to_shost(&starget->dev);
- ioc = shost_priv(shost);
- if (starget->channel == RAID_CHANNEL) {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc,
- starget->id, starget->channel);
- if (raid_device)
- raid_device->sdev = sdev; /* raid is single lun */
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-
- if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_target_priv_data->sas_address);
- if (sas_device && (sas_device->starget == NULL)) {
- sdev_printk(KERN_INFO, sdev,
- "%s : sas_device->starget set to starget @ %d\n",
- __func__, __LINE__);
- sas_device->starget = starget;
- }
-
- if (sas_device)
- sas_device_put(sas_device);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-
- return 0;
-}
-
-/**
- * _scsih_slave_destroy - device destroy routine
- * @sdev: scsi device struct
- *
- * Returns nothing.
- */
-static void
-_scsih_slave_destroy(struct scsi_device *sdev)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget;
- struct Scsi_Host *shost;
- struct MPT2SAS_ADAPTER *ioc;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (!sdev->hostdata)
- return;
-
- starget = scsi_target(sdev);
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->num_luns--;
-
- shost = dev_to_shost(&starget->dev);
- ioc = shost_priv(shost);
-
- if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc,
- sas_target_priv_data);
- if (sas_device && !sas_target_priv_data->num_luns)
- sas_device->starget = NULL;
-
- if (sas_device)
- sas_device_put(sas_device);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-
- kfree(sdev->hostdata);
- sdev->hostdata = NULL;
-}
-
-/**
- * _scsih_display_sata_capabilities - sata capabilities
- * @ioc: per adapter object
- * @handle: device handle
- * @sdev: scsi device struct
- */
-static void
-_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc,
- u16 handle, struct scsi_device *sdev)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- u16 flags;
- u32 device_info;
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- flags = le16_to_cpu(sas_device_pg0.Flags);
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
-
- sdev_printk(KERN_INFO, sdev,
- "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), "
- "sw_preserve(%s)\n",
- (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" :
- "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n",
- (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n");
-}
-
-/**
- * _scsih_is_raid - return boolean indicating device is raid volume
- * @dev the device struct object
- */
-static int
-_scsih_is_raid(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
-
- if (ioc->is_warpdrive)
- return 0;
- return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
-}
-
-/**
- * _scsih_get_resync - get raid volume resync percent complete
- * @dev the device struct object
- */
-static void
-_scsih_get_resync(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
- static struct _raid_device *raid_device;
- unsigned long flags;
- Mpi2RaidVolPage0_t vol_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 volume_status_flags;
- u8 percent_complete;
- u16 handle;
-
- percent_complete = 0;
- handle = 0;
- if (ioc->is_warpdrive)
- goto out;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
- sdev->channel);
- if (raid_device) {
- handle = raid_device->handle;
- percent_complete = raid_device->percent_complete;
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!handle)
- goto out;
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- percent_complete = 0;
- goto out;
- }
-
- volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (!(volume_status_flags &
- MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS))
- percent_complete = 0;
-
- out:
- raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
-}
-
-/**
- * _scsih_get_state - get raid volume level
- * @dev the device struct object
- */
-static void
-_scsih_get_state(struct device *dev)
-{
- struct scsi_device *sdev = to_scsi_device(dev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host);
- static struct _raid_device *raid_device;
- unsigned long flags;
- Mpi2RaidVolPage0_t vol_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 volstate;
- enum raid_state state = RAID_STATE_UNKNOWN;
- u16 handle = 0;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
- sdev->channel);
- if (raid_device)
- handle = raid_device->handle;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (!raid_device)
- goto out;
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags);
- if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
- state = RAID_STATE_RESYNCING;
- goto out;
- }
-
- switch (vol_pg0.VolumeState) {
- case MPI2_RAID_VOL_STATE_OPTIMAL:
- case MPI2_RAID_VOL_STATE_ONLINE:
- state = RAID_STATE_ACTIVE;
- break;
- case MPI2_RAID_VOL_STATE_DEGRADED:
- state = RAID_STATE_DEGRADED;
- break;
- case MPI2_RAID_VOL_STATE_FAILED:
- case MPI2_RAID_VOL_STATE_MISSING:
- state = RAID_STATE_OFFLINE;
- break;
- }
- out:
- raid_set_state(mpt2sas_raid_template, dev, state);
-}
-
-/**
- * _scsih_set_level - set raid level
- * @sdev: scsi device struct
- * @volume_type: volume type
- */
-static void
-_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
-{
- enum raid_level level = RAID_LEVEL_UNKNOWN;
-
- switch (volume_type) {
- case MPI2_RAID_VOL_TYPE_RAID0:
- level = RAID_LEVEL_0;
- break;
- case MPI2_RAID_VOL_TYPE_RAID10:
- level = RAID_LEVEL_10;
- break;
- case MPI2_RAID_VOL_TYPE_RAID1E:
- level = RAID_LEVEL_1E;
- break;
- case MPI2_RAID_VOL_TYPE_RAID1:
- level = RAID_LEVEL_1;
- break;
- }
-
- raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level);
-}
-
-/**
- * _scsih_get_volume_capabilities - volume capabilities
- * @ioc: per adapter object
- * @sas_device: the raid_device object
- *
- * Returns 0 for success, else 1
- */
-static int
-_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- Mpi2RaidVolPage0_t *vol_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 sz;
- u8 num_pds;
-
- if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
- &num_pds)) || !num_pds) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- return 1;
- }
-
- raid_device->num_pds = num_pds;
- sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
- sizeof(Mpi2RaidVol0PhysDisk_t));
- vol_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!vol_pg0) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- return 1;
- }
-
- if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__,
- __func__));
- kfree(vol_pg0);
- return 1;
- }
-
- raid_device->volume_type = vol_pg0->VolumeType;
-
- /* figure out what the underlying devices are by
- * obtaining the device_info bits for the 1st device
- */
- if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
- vol_pg0->PhysDisk[0].PhysDiskNum))) {
- if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- le16_to_cpu(pd_pg0.DevHandle)))) {
- raid_device->device_info =
- le32_to_cpu(sas_device_pg0.DeviceInfo);
- }
- }
-
- kfree(vol_pg0);
- return 0;
-}
-/**
- * _scsih_disable_ddio - Disable direct I/O for all the volumes
- * @ioc: per adapter object
- */
-static void
-_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t vol_pg1;
- Mpi2ConfigReply_t mpi_reply;
- struct _raid_device *raid_device;
- u16 handle;
- u16 ioc_status;
- unsigned long flags;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
- handle = le16_to_cpu(vol_pg1.DevHandle);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device)
- raid_device->direct_io_enabled = 0;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
- return;
-}
-
-
-/**
- * _scsih_get_num_volumes - Get number of volumes in the ioc
- * @ioc: per adapter object
- */
-static u8
-_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t vol_pg1;
- Mpi2ConfigReply_t mpi_reply;
- u16 handle;
- u8 vol_cnt = 0;
- u16 ioc_status;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
- break;
- vol_cnt++;
- handle = le16_to_cpu(vol_pg1.DevHandle);
- }
- return vol_cnt;
-}
-
-
-/**
- * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O.
- * @ioc: per adapter object
- * @raid_device: the raid_device object
- */
-static void
-_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc,
- struct _raid_device *raid_device)
-{
- Mpi2RaidVolPage0_t *vol_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 sz;
- u8 num_pds, count;
- unsigned long stripe_sz, block_sz;
- u8 stripe_exp, block_exp;
- u64 dev_max_lba;
-
- if (!ioc->is_warpdrive)
- return;
-
- if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "globally as drives are exposed\n", ioc->name);
- return;
- }
- if (_scsih_get_num_volumes(ioc) > 1) {
- _scsih_disable_ddio(ioc);
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "globally as number of drives > 1\n", ioc->name);
- return;
- }
- if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle,
- &num_pds)) || !num_pds) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Failure in computing number of drives\n", ioc->name);
- return;
- }
-
- sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
- sizeof(Mpi2RaidVol0PhysDisk_t));
- vol_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!vol_pg0) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Memory allocation failure for RVPG0\n", ioc->name);
- return;
- }
-
- if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
- MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "Failure in retrieving RVPG0\n", ioc->name);
- kfree(vol_pg0);
- return;
- }
-
- /*
- * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
- * assumed for WARPDRIVE, disable direct I/O
- */
- if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
- printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): num_mem=%d, "
- "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
- num_pds, MPT_MAX_WARPDRIVE_PDS);
- kfree(vol_pg0);
- return;
- }
- for (count = 0; count < num_pds; count++) {
- if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
- vol_pg0->PhysDisk[count].PhysDiskNum) ||
- le16_to_cpu(pd_pg0.DevHandle) ==
- MPT2SAS_INVALID_DEVICE_HANDLE) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- "handle retrieval failed for member number=%d\n",
- ioc->name, raid_device->handle,
- vol_pg0->PhysDisk[count].PhysDiskNum);
- goto out_error;
- }
- /* Disable direct I/O if member drive lba exceeds 4 bytes */
- dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
- if (dev_max_lba >> 32) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is "
- "disabled for the drive with handle(0x%04x) member"
- "handle (0x%04x) unsupported max lba 0x%016llx\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(pd_pg0.DevHandle),
- (unsigned long long)dev_max_lba);
- goto out_error;
- }
-
- raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
- }
-
- /*
- * Assumption for WD: Direct I/O is not supported if the volume is
- * not RAID0
- */
- if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x): type=%d, "
- "s_sz=%uK, blk_size=%u\n", ioc->name,
- raid_device->handle, raid_device->volume_type,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024,
- le16_to_cpu(vol_pg0->BlockSize));
- goto out_error;
- }
-
- stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
- stripe_exp = find_first_bit(&stripe_sz, 32);
- if (stripe_exp == 32) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
- ioc->name, raid_device->handle,
- (le32_to_cpu(vol_pg0->StripeSize) *
- le16_to_cpu(vol_pg0->BlockSize)) / 1024);
- goto out_error;
- }
- raid_device->stripe_exponent = stripe_exp;
- block_sz = le16_to_cpu(vol_pg0->BlockSize);
- block_exp = find_first_bit(&block_sz, 16);
- if (block_exp == 16) {
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled "
- "for the drive with handle(0x%04x) invalid block sz %u\n",
- ioc->name, raid_device->handle,
- le16_to_cpu(vol_pg0->BlockSize));
- goto out_error;
- }
- raid_device->block_exponent = block_exp;
- raid_device->direct_io_enabled = 1;
-
- printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive"
- " with handle(0x%04x)\n", ioc->name, raid_device->handle);
- /*
- * WARPDRIVE: Though the following fields are not used for direct IO,
- * stored for future purpose:
- */
- raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
- raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
- raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
-
-
- kfree(vol_pg0);
- return;
-
-out_error:
- raid_device->direct_io_enabled = 0;
- for (count = 0; count < num_pds; count++)
- raid_device->pd_handle[count] = 0;
- kfree(vol_pg0);
- return;
-}
-
-/**
- * _scsih_enable_tlr - setting TLR flags
- * @ioc: per adapter object
- * @sdev: scsi device struct
- *
- * Enabling Transaction Layer Retries for tape devices when
- * vpd page 0x90 is present
- *
- */
-static void
-_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev)
-{
- /* only for TAPE */
- if (sdev->type != TYPE_TAPE)
- return;
-
- if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR))
- return;
-
- sas_enable_tlr(sdev);
- sdev_printk(KERN_INFO, sdev, "TLR %s\n",
- sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled");
- return;
-
-}
-
-/**
- * _scsih_slave_configure - device configure routine.
- * @sdev: scsi device struct
- *
- * Returns 0 if ok. Any other return is assumed to be an error and
- * the device is ignored.
- */
-static int
-_scsih_slave_configure(struct scsi_device *sdev)
-{
- struct Scsi_Host *shost = sdev->host;
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- unsigned long flags;
- int qdepth;
- u8 ssp_target = 0;
- char *ds = "";
- char *r_level = "";
- u16 handle, volume_handle = 0;
- u64 volume_wwid = 0;
-
- qdepth = 1;
- sas_device_priv_data = sdev->hostdata;
- sas_device_priv_data->configured_lun = 1;
- sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT;
- sas_target_priv_data = sas_device_priv_data->sas_target;
- handle = sas_target_priv_data->handle;
-
- /* raid volume handling */
- if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (!raid_device) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
-
- if (_scsih_get_volume_capabilities(ioc, raid_device)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
- /*
- * WARPDRIVE: Initialize the required data for Direct IO
- */
- _scsih_init_warpdrive_properties(ioc, raid_device);
-
- /* RAID Queue Depth Support
- * IS volume = underlying qdepth of drive type, either
- * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH
- * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH)
- */
- if (raid_device->device_info &
- MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (raid_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
- else
- ds = "STP";
- }
-
- switch (raid_device->volume_type) {
- case MPI2_RAID_VOL_TYPE_RAID0:
- r_level = "RAID0";
- break;
- case MPI2_RAID_VOL_TYPE_RAID1E:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- if (ioc->manu_pg10.OEMIdentifier &&
- (le32_to_cpu(ioc->manu_pg10.GenericFlags0) &
- MFG10_GF0_R10_DISPLAY) &&
- !(raid_device->num_pds % 2))
- r_level = "RAID10";
- else
- r_level = "RAID1E";
- break;
- case MPI2_RAID_VOL_TYPE_RAID1:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAID1";
- break;
- case MPI2_RAID_VOL_TYPE_RAID10:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAID10";
- break;
- case MPI2_RAID_VOL_TYPE_UNKNOWN:
- default:
- qdepth = MPT2SAS_RAID_QUEUE_DEPTH;
- r_level = "RAIDX";
- break;
- }
-
- if (!ioc->hide_ir_msg)
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "wwid(0x%016llx), pd_count(%d), type(%s)\n",
- r_level, raid_device->handle,
- (unsigned long long)raid_device->wwid,
- raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth);
- /* raid transport support */
- if (!ioc->is_warpdrive)
- _scsih_set_level(sdev, raid_device->volume_type);
- return 0;
- }
-
- /* non-raid handling */
- if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) {
- if (mpt2sas_config_get_volume_handle(ioc, handle,
- &volume_handle)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- if (volume_handle && mpt2sas_config_get_volume_wwid(ioc,
- volume_handle, &volume_wwid)) {
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__));
- return 1;
- }
- }
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_device_priv_data->sas_target->sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- dfailprintk(ioc, printk(MPT2SAS_WARN_FMT
- "failure at %s:%d/%s()!\n", ioc->name, __FILE__,
- __LINE__, __func__));
- return 1;
- }
- sas_device->volume_handle = volume_handle;
- sas_device->volume_wwid = volume_wwid;
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) {
- qdepth = MPT2SAS_SAS_QUEUE_DEPTH;
- ssp_target = 1;
- ds = "SSP";
- } else {
- qdepth = MPT2SAS_SATA_QUEUE_DEPTH;
- if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
- ds = "STP";
- else if (sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- ds = "SATA";
- }
- sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), "
- "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n",
- ds, sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy,
- (unsigned long long)sas_device->device_name);
- sdev_printk(KERN_INFO, sdev, "%s: "
- "enclosure_logical_id(0x%016llx), slot(%d)\n", ds,
- (unsigned long long) sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!ssp_target)
- _scsih_display_sata_capabilities(ioc, handle, sdev);
-
- _scsih_change_queue_depth(sdev, qdepth);
-
- if (ssp_target) {
- sas_read_port_mode_page(sdev);
- _scsih_enable_tlr(ioc, sdev);
- }
-
- return 0;
-}
-
-/**
- * _scsih_bios_param - fetch head, sector, cylinder info for a disk
- * @sdev: scsi device struct
- * @bdev: pointer to block device context
- * @capacity: device size (in 512 byte sectors)
- * @params: three element array to place output:
- * params[0] number of heads (max 255)
- * params[1] number of sectors (max 63)
- * params[2] number of cylinders
- *
- * Return nothing.
- */
-static int
-_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int params[])
-{
- int heads;
- int sectors;
- sector_t cylinders;
- ulong dummy;
-
- heads = 64;
- sectors = 32;
-
- dummy = heads * sectors;
- cylinders = capacity;
- sector_div(cylinders, dummy);
-
- /*
- * Handle extended translation size for logical drives
- * > 1Gb
- */
- if ((ulong)capacity >= 0x200000) {
- heads = 255;
- sectors = 63;
- dummy = heads * sectors;
- cylinders = capacity;
- sector_div(cylinders, dummy);
- }
-
- /* return result */
- params[0] = heads;
- params[1] = sectors;
- params[2] = cylinders;
-
- return 0;
-}
-
-/**
- * _scsih_response_code - translation of device response code
- * @ioc: per adapter object
- * @response_code: response code returned by the device
- *
- * Return nothing.
- */
-static void
-_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
-{
- char *desc;
-
- switch (response_code) {
- case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE:
- desc = "task management request completed";
- break;
- case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME:
- desc = "invalid frame";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED:
- desc = "task management request not supported";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_FAILED:
- desc = "task management request failed";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED:
- desc = "task management request succeeded";
- break;
- case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN:
- desc = "invalid lun";
- break;
- case 0xA:
- desc = "overlapped tag attempted";
- break;
- case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC:
- desc = "task queued, however not sent to target";
- break;
- default:
- desc = "unknown";
- break;
- }
- printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n",
- ioc->name, response_code, desc);
-}
-
-/**
- * _scsih_tm_done - tm completion routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: none.
- *
- * The callback handler when using scsih_issue_tm.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
-
- if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->tm_cmds.smid != smid)
- return 1;
- mpt2sas_base_flush_reply_queues(ioc);
- ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (mpi_reply) {
- memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4);
- ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->tm_cmds.done);
- return 1;
-}
-
-/**
- * mpt2sas_scsih_set_tm_flag - set per target tm_busy
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During taskmangement request, we need to freeze the device queue.
- */
-void
-mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
- u8 skip = 0;
-
- shost_for_each_device(sdev, ioc->shost) {
- if (skip)
- continue;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- sas_device_priv_data->sas_target->tm_busy = 1;
- skip = 1;
- ioc->ignore_loginfos = 1;
- }
- }
-}
-
-/**
- * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During taskmangement request, we need to freeze the device queue.
- */
-void
-mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
- u8 skip = 0;
-
- shost_for_each_device(sdev, ioc->shost) {
- if (skip)
- continue;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- sas_device_priv_data->sas_target->tm_busy = 0;
- skip = 1;
- ioc->ignore_loginfos = 0;
- }
- }
-}
-
-
-/**
- * mpt2sas_scsih_issue_tm - main routine for sending tm requests
- * @ioc: per adapter struct
- * @device_handle: device handle
- * @channel: the channel assigned by the OS
- * @id: the id assigned by the OS
- * @lun: lun number
- * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h)
- * @smid_task: smid assigned to the task
- * @timeout: timeout in seconds
- * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF
- * Context: user
- *
- * A generic API for sending task management requests to firmware.
- *
- * The callback index is set inside `ioc->tm_cb_idx`.
- *
- * Return SUCCESS or FAILED.
- */
-int
-mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel,
- uint id, uint lun, u8 type, u16 smid_task, ulong timeout,
- enum mutex_type m_type)
-{
- Mpi2SCSITaskManagementRequest_t *mpi_request;
- Mpi2SCSITaskManagementReply_t *mpi_reply;
- u16 smid = 0;
- u32 ioc_state;
- unsigned long timeleft;
- struct scsiio_tracker *scsi_lookup = NULL;
- int rc;
-
- if (m_type == TM_MUTEX_ON)
- mutex_lock(&ioc->tm_cmds.mutex);
- if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
- __func__, ioc->name);
- rc = FAILED;
- goto err_out;
- }
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- rc = FAILED;
- goto err_out;
- }
-
- ioc_state = mpt2sas_base_get_iocstate(ioc, 0);
- if (ioc_state & MPI2_DOORBELL_USED) {
- dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell "
- "active!\n", ioc->name));
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
- }
-
- if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) {
- mpt2sas_base_fault_info(ioc, ioc_state &
- MPI2_DOORBELL_DATA_MASK);
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- goto err_out;
- }
-
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = FAILED;
- goto err_out;
- }
-
- if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK)
- scsi_lookup = &ioc->scsi_lookup[smid_task - 1];
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
- " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
- smid_task));
- ioc->tm_cmds.status = MPT2_CMD_PENDING;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->tm_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
- memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t));
- mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- mpi_request->DevHandle = cpu_to_le16(handle);
- mpi_request->TaskType = type;
- mpi_request->TaskMID = cpu_to_le16(smid_task);
- int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
- mpt2sas_scsih_set_tm_flag(ioc, handle);
- init_completion(&ioc->tm_cmds.done);
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
- if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SCSITaskManagementRequest_t)/4);
- if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) {
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = (!rc) ? SUCCESS : FAILED;
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- mpt2sas_scsih_clear_tm_flag(ioc, handle);
- goto err_out;
- }
- }
-
- if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) {
- mpi_reply = ioc->tm_cmds.reply;
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: "
- "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
- if (ioc->logging_level & MPT_DEBUG_TM) {
- _scsih_response_code(ioc, mpi_reply->ResponseCode);
- if (mpi_reply->IOCStatus)
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SCSITaskManagementRequest_t)/4);
- }
- }
-
- switch (type) {
- case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK:
- rc = SUCCESS;
- if (scsi_lookup->scmd == NULL)
- break;
- rc = FAILED;
- break;
-
- case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET:
- if (_scsih_scsi_lookup_find_by_target(ioc, id, channel))
- rc = FAILED;
- else
- rc = SUCCESS;
- break;
-
- case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET:
- case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET:
- if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel))
- rc = FAILED;
- else
- rc = SUCCESS;
- break;
- case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK:
- rc = SUCCESS;
- break;
- default:
- rc = FAILED;
- break;
- }
-
- mpt2sas_scsih_clear_tm_flag(ioc, handle);
- ioc->tm_cmds.status = MPT2_CMD_NOT_USED;
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
-
- return rc;
-
- err_out:
- if (m_type == TM_MUTEX_ON)
- mutex_unlock(&ioc->tm_cmds.mutex);
- return rc;
-}
-
-/**
- * _scsih_tm_display_info - displays info about the device
- * @ioc: per adapter struct
- * @scmd: pointer to scsi command object
- *
- * Called by task management callback handlers.
- */
-static void
-_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
-{
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *priv_target = starget->hostdata;
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
- char *device_str = NULL;
-
- if (!priv_target)
- return;
- if (ioc->hide_ir_msg)
- device_str = "WarpDrive";
- else
- device_str = "volume";
-
- scsi_print_command(scmd);
- if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- starget_printk(KERN_INFO, starget, "%s handle(0x%04x), "
- "%s wwid(0x%016llx)\n", device_str, priv_target->handle,
- device_str, (unsigned long long)priv_target->sas_address);
- } else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target);
- if (sas_device) {
- if (priv_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- starget_printk(KERN_INFO, starget,
- "volume handle(0x%04x), "
- "volume wwid(0x%016llx)\n",
- sas_device->volume_handle,
- (unsigned long long)sas_device->volume_wwid);
- }
- starget_printk(KERN_INFO, starget,
- "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n",
- sas_device->handle,
- (unsigned long long)sas_device->sas_address,
- sas_device->phy);
- starget_printk(KERN_INFO, starget,
- "enclosure_logical_id(0x%016llx), slot(%d)\n",
- (unsigned long long)sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
-}
-
-/**
- * _scsih_abort - eh threads main abort routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_abort(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u16 smid;
- u16 handle;
- int r;
-
- sdev_printk(KERN_INFO, scmd->device, "attempting task abort! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- sdev_printk(KERN_INFO, scmd->device, "device been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* search for the command */
- smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd);
- if (!smid) {
- scmd->result = DID_RESET << 16;
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components and volumes this is not supported */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT ||
- sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- mpt2sas_halt_firmware(ioc);
-
- handle = sas_device_priv_data->sas_target->handle;
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, TM_MUTEX_ON);
-
- out:
- sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
- return r;
-}
-
-/**
- * _scsih_dev_reset - eh threads main device reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_dev_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device = NULL;
- u16 handle;
- int r;
-
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *target_priv_data = starget->hostdata;
-
- starget_printk(KERN_INFO, starget, "attempting device reset! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "device been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components obtain the volume_handle */
- handle = 0;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- sas_device = mpt2sas_get_sdev_from_target(ioc,
- target_priv_data);
- if (sas_device)
- handle = sas_device->volume_handle;
- } else
- handle = sas_device_priv_data->sas_target->handle;
-
- if (!handle) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, scmd->device->lun,
- MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, TM_MUTEX_ON);
-
- out:
- sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- if (sas_device)
- sas_device_put(sas_device);
-
- return r;
-}
-
-/**
- * _scsih_target_reset - eh threads main target reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_target_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device = NULL;
- u16 handle;
- int r;
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *target_priv_data = starget->hostdata;
-
- starget_printk(KERN_INFO, starget, "attempting target reset! "
- "scmd(%p)\n", scmd);
- _scsih_tm_display_info(ioc, scmd);
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- starget_printk(KERN_INFO, starget, "target been deleted! "
- "scmd(%p)\n", scmd);
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- r = SUCCESS;
- goto out;
- }
-
- /* for hidden raid components obtain the volume_handle */
- handle = 0;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT) {
- sas_device = mpt2sas_get_sdev_from_target(ioc,
- target_priv_data);
- if (sas_device)
- handle = sas_device->volume_handle;
- } else
- handle = sas_device_priv_data->sas_target->handle;
-
- if (!handle) {
- scmd->result = DID_RESET << 16;
- r = FAILED;
- goto out;
- }
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel,
- scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0,
- 30, TM_MUTEX_ON);
-
- out:
- starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
- ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- if (sas_device)
- sas_device_put(sas_device);
-
- return r;
-}
-
-/**
- * _scsih_host_reset - eh threads main host reset routine
- * @scmd: pointer to scsi command object
- *
- * Returns SUCCESS if command aborted else FAILED
- */
-static int
-_scsih_host_reset(struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
- int r, retval;
-
- printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n",
- ioc->name, scmd);
- scsi_print_command(scmd);
-
- if (ioc->is_driver_loading) {
- printk(MPT2SAS_INFO_FMT "Blocking the host reset\n",
- ioc->name);
- r = FAILED;
- goto out;
- }
-
- retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- r = (retval < 0) ? FAILED : SUCCESS;
-
- out:
- printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
- ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
-
- return r;
-}
-
-/**
- * _scsih_fw_event_add - insert and queue up fw_event
- * @ioc: per adapter object
- * @fw_event: object describing the event
- * Context: This function will acquire ioc->fw_event_lock.
- *
- * This adds the firmware event object into link list, then queues it up to
- * be processed from user context.
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
-{
- unsigned long flags;
-
- if (ioc->firmware_event_thread == NULL)
- return;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- fw_event_work_get(fw_event);
- list_add_tail(&fw_event->list, &ioc->fw_event_list);
- INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work);
- fw_event_work_get(fw_event);
- queue_delayed_work(ioc->firmware_event_thread,
- &fw_event->delayed_work, 0);
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_fw_event_del_from_list - delete fw_event from the list
- * @ioc: per adapter object
- * @fw_event: object describing the event
- * Context: This function will acquire ioc->fw_event_lock.
- *
- * If the fw_event is on the fw_event_list, remove it and do a put.
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_del_from_list(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
- *fw_event)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- if (!list_empty(&fw_event->list)) {
- list_del_init(&fw_event->list);
- fw_event_work_put(fw_event);
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_error_recovery_delete_devices - remove devices not responding
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- if (ioc->is_driver_loading)
- return;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
-
- fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-/**
- * mpt2sas_port_enable_complete - port enable completed (fake event)
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-void
-mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
- fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-static struct fw_event_work *dequeue_next_fw_event(struct MPT2SAS_ADAPTER *ioc)
-{
- unsigned long flags;
- struct fw_event_work *fw_event = NULL;
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- if (!list_empty(&ioc->fw_event_list)) {
- fw_event = list_first_entry(&ioc->fw_event_list,
- struct fw_event_work, list);
- list_del_init(&fw_event->list);
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-
- return fw_event;
-}
-
-/**
- * _scsih_fw_event_cleanup_queue - cleanup event queue
- * @ioc: per adapter object
- *
- * Walk the firmware event queue, either killing timers, or waiting
- * for outstanding events to complete
- *
- * Return nothing.
- */
-static void
-_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc)
-{
- struct fw_event_work *fw_event;
-
- if (list_empty(&ioc->fw_event_list) ||
- !ioc->firmware_event_thread || in_interrupt())
- return;
-
- while ((fw_event = dequeue_next_fw_event(ioc))) {
- /*
- * Wait on the fw_event to complete. If this returns 1, then
- * the event was never executed, and we need a put for the
- * reference the delayed_work had on the fw_event.
- *
- * If it did execute, we wait for it to finish, and the put will
- * happen from _firmware_event_work()
- */
- if (cancel_delayed_work_sync(&fw_event->delayed_work))
- fw_event_work_put(fw_event);
-
- fw_event_work_put(fw_event);
- }
-}
-
-/**
- * _scsih_ublock_io_all_device - unblock every device
- * @ioc: per adapter object
- *
- * change the device state from block to running
- */
-static void
-_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (!sas_device_priv_data->block)
- continue;
- sas_device_priv_data->block = 0;
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, "
- "handle(0x%04x)\n",
- sas_device_priv_data->sas_target->handle));
- scsi_internal_device_unblock(sdev, SDEV_RUNNING);
- }
-}
-/**
- * _scsih_ublock_io_device - set the device state to SDEV_RUNNING
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (!sas_device_priv_data->block)
- continue;
- if (sas_device_priv_data->sas_target->sas_address ==
- sas_address) {
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
- MPT2SAS_INFO_FMT "SDEV_RUNNING: "
- "sas address(0x%016llx)\n", ioc->name,
- (unsigned long long)sas_address));
- sas_device_priv_data->block = 0;
- scsi_internal_device_unblock(sdev, SDEV_RUNNING);
- }
- }
-}
-
-/**
- * _scsih_block_io_all_device - set the device state to SDEV_BLOCK
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->block)
- continue;
- sas_device_priv_data->block = 1;
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, "
- "handle(0x%04x)\n",
- sas_device_priv_data->sas_target->handle));
- scsi_internal_device_block(sdev);
- }
-}
-
-
-/**
- * _scsih_block_io_device - set the device state to SDEV_BLOCK
- * @ioc: per adapter object
- * @handle: device handle
- *
- * During device pull we need to appropiately set the sdev state.
- */
-static void
-_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data)
- continue;
- if (sas_device_priv_data->block)
- continue;
- if (sas_device_priv_data->sas_target->handle == handle) {
- dewtprintk(ioc, sdev_printk(KERN_INFO, sdev,
- MPT2SAS_INFO_FMT "SDEV_BLOCK: "
- "handle(0x%04x)\n", ioc->name, handle));
- sas_device_priv_data->block = 1;
- scsi_internal_device_block(sdev);
- }
- }
-}
-
-/**
- * _scsih_block_io_to_children_attached_to_ex
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- *
- * This routine set sdev state to SDEV_BLOCK for all devices
- * attached to this expander. This function called when expander is
- * pulled.
- */
-static void
-_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- struct _sas_port *mpt2sas_port;
- struct _sas_device *sas_device;
- struct _sas_node *expander_sibling;
- unsigned long flags;
-
- if (!sas_expander)
- return;
-
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- mpt2sas_port->remote_identify.sas_address);
- if (sas_device) {
- set_bit(sas_device->handle,
- ioc->blocking_handles);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- }
- }
-
- list_for_each_entry(mpt2sas_port,
- &sas_expander->sas_port_list, port_list) {
-
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE) {
- expander_sibling =
- mpt2sas_scsih_expander_find_by_sas_address(
- ioc, mpt2sas_port->remote_identify.sas_address);
- _scsih_block_io_to_children_attached_to_ex(ioc,
- expander_sibling);
- }
- }
-}
-
-/**
- * _scsih_block_io_to_children_attached_directly
- * @ioc: per adapter object
- * @event_data: topology change event data
- *
- * This routine set sdev state to SDEV_BLOCK for all devices
- * direct attached during device pull.
- */
-static void
-_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- int i;
- u16 handle;
- u16 reason_code;
- u8 phy_number;
-
- for (i = 0; i < event_data->NumEntries; i++) {
- handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
- if (!handle)
- continue;
- phy_number = event_data->StartPhyNum + i;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING)
- _scsih_block_io_device(ioc, handle);
- }
-}
-
-/**
- * _scsih_tm_tr_send - send task management request
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt time.
- *
- * This code is to initiate the device removal handshake protocol
- * with controller firmware. This function will issue target reset
- * using high priority request queue. It will send a sas iounit
- * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
- *
- * This is designed to send muliple task management request at the same
- * time to the fifo. If the fifo is full, we will append the request,
- * and process it in a future completion.
- */
-static void
-_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2SCSITaskManagementRequest_t *mpi_request;
- u16 smid;
- struct _sas_device *sas_device = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
- u64 sas_address = 0;
- unsigned long flags;
- struct _tr_list *delayed_tr;
- u32 ioc_state;
-
- if (ioc->remove_host) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
- "removed: handle(0x%04x)\n", __func__, ioc->name, handle));
- return;
- } else if (ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
- "error recovery: handle(0x%04x)\n", __func__, ioc->name,
- handle));
- return;
- }
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
- "operational: handle(0x%04x)\n", __func__, ioc->name,
- handle));
- return;
- }
-
- /* if PD, then return */
- if (test_bit(handle, ioc->pd_handles))
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device && sas_device->starget &&
- sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- sas_address = sas_device->sas_address;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_target_priv_data) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle,
- (unsigned long long)sas_address));
- _scsih_ublock_io_device(ioc, sas_address);
- sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE;
- }
-
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
- if (!smid) {
- delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
- if (!delayed_tr)
- goto out;
- INIT_LIST_HEAD(&delayed_tr->list);
- delayed_tr->handle = handle;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
- goto out;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
- ioc->tm_tr_cb_idx));
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- mpi_request->DevHandle = cpu_to_le16(handle);
- mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
-out:
- if (sas_device)
- sas_device_put(sas_device);
-}
-
-
-
-/**
- * _scsih_sas_control_complete - completion routine
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: interrupt time.
- *
- * This is the sas iounit control completion routine.
- * This code is part of the code to initiate the device removal
- * handshake protocol with controller firmware.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 msix_index, u32 reply)
-{
- Mpi2SasIoUnitControlReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (likely(mpi_reply)) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "sc_complete:handle(0x%04x), (open) "
- "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid,
- le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo)));
- } else {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- }
- return 1;
-}
-
-/**
- * _scsih_tm_tr_volume_send - send target reset request for volumes
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt time.
- *
- * This is designed to send muliple task management request at the same
- * time to the fifo. If the fifo is full, we will append the request,
- * and process it in a future completion.
- */
-static void
-_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2SCSITaskManagementRequest_t *mpi_request;
- u16 smid;
- struct _tr_list *delayed_tr;
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
- "progress!\n", __func__, ioc->name));
- return;
- }
-
- smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx);
- if (!smid) {
- delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
- if (!delayed_tr)
- return;
- INIT_LIST_HEAD(&delayed_tr->list);
- delayed_tr->handle = handle;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n",
- ioc->name, handle));
- return;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid,
- ioc->tm_tr_volume_cb_idx));
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
- mpi_request->DevHandle = cpu_to_le16(handle);
- mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
- mpt2sas_base_put_smid_hi_priority(ioc, smid);
-}
-
-/**
- * _scsih_tm_volume_tr_complete - target reset completion
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: interrupt time.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 msix_index, u32 reply)
-{
- u16 handle;
- Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
- Mpi2SCSITaskManagementReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in "
- "progress!\n", __func__, ioc->name));
- return 1;
- }
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return 1;
- }
- mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
- handle = le16_to_cpu(mpi_request_tm->DevHandle);
- if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, printk("spurious interrupt: "
- "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
- return 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
-
- return _scsih_check_for_pending_tm(ioc, smid);
-}
-
-/**
- * _scsih_tm_tr_complete -
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: interrupt time.
- *
- * This is the target reset completion routine.
- * This code is part of the code to initiate the device removal
- * handshake protocol with controller firmware.
- * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE)
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- u16 handle;
- Mpi2SCSITaskManagementRequest_t *mpi_request_tm;
- Mpi2SCSITaskManagementReply_t *mpi_reply =
- mpt2sas_base_get_reply_virt_addr(ioc, reply);
- Mpi2SasIoUnitControlRequest_t *mpi_request;
- u16 smid_sas_ctrl;
- u32 ioc_state;
-
- if (ioc->remove_host) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been "
- "removed\n", __func__, ioc->name));
- return 1;
- } else if (ioc->pci_error_recovery) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci "
- "error recovery\n", __func__, ioc->name));
- return 1;
- }
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not "
- "operational\n", __func__, ioc->name));
- return 1;
- }
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return 1;
- }
- mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid);
- handle = le16_to_cpu(mpi_request_tm->DevHandle);
- if (handle != le16_to_cpu(mpi_reply->DevHandle)) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: "
- "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle,
- le16_to_cpu(mpi_reply->DevHandle), smid));
- return 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), "
- "loginfo(0x%08x), completed(%d)\n", ioc->name,
- handle, smid, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo),
- le32_to_cpu(mpi_reply->TerminationCount)));
-
- smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
- if (!smid_sas_ctrl) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- return 1;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), "
- "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl,
- ioc->tm_sas_control_cb_idx));
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl);
- memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
- mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE;
- mpi_request->DevHandle = mpi_request_tm->DevHandle;
- mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
-
- return _scsih_check_for_pending_tm(ioc, smid);
-}
-
-/**
- * _scsih_check_for_pending_tm - check for pending task management
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * This will check delayed target reset list, and feed the
- * next reqeust.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- struct _tr_list *delayed_tr;
-
- if (!list_empty(&ioc->delayed_tr_volume_list)) {
- delayed_tr = list_entry(ioc->delayed_tr_volume_list.next,
- struct _tr_list, list);
- mpt2sas_base_free_smid(ioc, smid);
- _scsih_tm_tr_volume_send(ioc, delayed_tr->handle);
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- return 0;
- }
-
- if (!list_empty(&ioc->delayed_tr_list)) {
- delayed_tr = list_entry(ioc->delayed_tr_list.next,
- struct _tr_list, list);
- mpt2sas_base_free_smid(ioc, smid);
- _scsih_tm_tr_send(ioc, delayed_tr->handle);
- list_del(&delayed_tr->list);
- kfree(delayed_tr);
- return 0;
- }
-
- return 1;
-}
-
-/**
- * _scsih_check_topo_delete_events - sanity check on topo events
- * @ioc: per adapter object
- * @event_data: the event data payload
- *
- * This routine added to better handle cable breaker.
- *
- * This handles the case where driver receives multiple expander
- * add and delete events in a single shot. When there is a delete event
- * the routine will void any pending add events waiting in the event queue.
- *
- * Return nothing.
- */
-static void
-_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- struct fw_event_work *fw_event;
- Mpi2EventDataSasTopologyChangeList_t *local_event_data;
- u16 expander_handle;
- struct _sas_node *sas_expander;
- unsigned long flags;
- int i, reason_code;
- u16 handle;
-
- for (i = 0 ; i < event_data->NumEntries; i++) {
- handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
- if (!handle)
- continue;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
- if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
- _scsih_tm_tr_send(ioc, handle);
- }
-
- expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
- if (expander_handle < ioc->sas_hba.num_phys) {
- _scsih_block_io_to_children_attached_directly(ioc, event_data);
- return;
- }
- if (event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING) {
- /* put expander attached devices into blocking state */
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- expander_handle);
- _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- do {
- handle = find_first_bit(ioc->blocking_handles,
- ioc->facts.MaxDevHandle);
- if (handle < ioc->facts.MaxDevHandle)
- _scsih_block_io_device(ioc, handle);
- } while (test_and_clear_bit(handle, ioc->blocking_handles));
- } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING)
- _scsih_block_io_to_children_attached_directly(ioc, event_data);
-
- if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING)
- return;
-
- /* mark ignore flag for pending events */
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- list_for_each_entry(fw_event, &ioc->fw_event_list, list) {
- if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST ||
- fw_event->ignore)
- continue;
- local_event_data = (Mpi2EventDataSasTopologyChangeList_t *)
- fw_event->event_data;
- if (local_event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_ADDED ||
- local_event_data->ExpStatus ==
- MPI2_EVENT_SAS_TOPO_ES_RESPONDING) {
- if (le16_to_cpu(local_event_data->ExpanderDevHandle) ==
- expander_handle) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "setting ignoring flag\n", ioc->name));
- fw_event->ignore = 1;
- }
- }
- }
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
-}
-
-/**
- * _scsih_set_volume_delete_flag - setting volume delete flag
- * @ioc: per adapter object
- * @handle: device handle
- *
- * This
- * Return nothing.
- */
-static void
-_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device && raid_device->starget &&
- raid_device->starget->hostdata) {
- sas_target_priv_data =
- raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "setting delete flag: handle(0x%04x), "
- "wwid(0x%016llx)\n", ioc->name, handle,
- (unsigned long long) raid_device->wwid));
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_set_volume_handle_for_tr - set handle for target reset to volume
- * @handle: input handle
- * @a: handle for volume a
- * @b: handle for volume b
- *
- * IR firmware only supports two raid volumes. The purpose of this
- * routine is to set the volume handle in either a or b. When the given
- * input handle is non-zero, or when a and b have not been set before.
- */
-static void
-_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b)
-{
- if (!handle || handle == *a || handle == *b)
- return;
- if (!*a)
- *a = handle;
- else if (!*b)
- *b = handle;
-}
-
-/**
- * _scsih_check_ir_config_unhide_events - check for UNHIDE events
- * @ioc: per adapter object
- * @event_data: the event data payload
- * Context: interrupt time.
- *
- * This routine will send target reset to volume, followed by target
- * resets to the PDs. This is called when a PD has been removed, or
- * volume has been deleted or removed. When the target reset is sent
- * to volume, the PD target resets need to be queued to start upon
- * completion of the volume target reset.
- *
- * Return nothing.
- */
-static void
-_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrConfigChangeList_t *event_data)
-{
- Mpi2EventIrConfigElement_t *element;
- int i;
- u16 handle, volume_handle, a, b;
- struct _tr_list *delayed_tr;
-
- a = 0;
- b = 0;
-
- if (ioc->is_warpdrive)
- return;
-
- /* Volume Resets for Deleted or Removed */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (element->ReasonCode ==
- MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED ||
- element->ReasonCode ==
- MPI2_EVENT_IR_CHANGE_RC_REMOVED) {
- volume_handle = le16_to_cpu(element->VolDevHandle);
- _scsih_set_volume_delete_flag(ioc, volume_handle);
- _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
- }
- }
-
- /* Volume Resets for UNHIDE events */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG)
- continue;
- if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) {
- volume_handle = le16_to_cpu(element->VolDevHandle);
- _scsih_set_volume_handle_for_tr(volume_handle, &a, &b);
- }
- }
-
- if (a)
- _scsih_tm_tr_volume_send(ioc, a);
- if (b)
- _scsih_tm_tr_volume_send(ioc, b);
-
- /* PD target resets */
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
- if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE)
- continue;
- handle = le16_to_cpu(element->PhysDiskDevHandle);
- volume_handle = le16_to_cpu(element->VolDevHandle);
- clear_bit(handle, ioc->pd_handles);
- if (!volume_handle)
- _scsih_tm_tr_send(ioc, handle);
- else if (volume_handle == a || volume_handle == b) {
- delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
- BUG_ON(!delayed_tr);
- INIT_LIST_HEAD(&delayed_tr->list);
- delayed_tr->handle = handle;
- list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name,
- handle));
- } else
- _scsih_tm_tr_send(ioc, handle);
- }
-}
-
-
-/**
- * _scsih_check_volume_delete_events - set delete flag for volumes
- * @ioc: per adapter object
- * @event_data: the event data payload
- * Context: interrupt time.
- *
- * This will handle the case when the cable connected to entire volume is
- * pulled. We will take care of setting the deleted flag so normal IO will
- * not be sent.
- *
- * Return nothing.
- */
-static void
-_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrVolume_t *event_data)
-{
- u32 state;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
- return;
- state = le32_to_cpu(event_data->NewValue);
- if (state == MPI2_RAID_VOL_STATE_MISSING || state ==
- MPI2_RAID_VOL_STATE_FAILED)
- _scsih_set_volume_delete_flag(ioc,
- le16_to_cpu(event_data->VolDevHandle));
-}
-
-/**
- * _scsih_temp_threshold_events - display temperature threshold exceeded events
- * @ioc: per adapter object
- * @event_data: the temp threshold event data
- * Context: interrupt time.
- *
- * Return nothing.
- */
-static void
-_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataTemperature_t *event_data)
-{
- if (ioc->temp_sensors_count >= event_data->SensorNum) {
- printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s"
- " exceeded for Sensor: %d !!!\n", ioc->name,
- ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ",
- ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ",
- event_data->SensorNum);
- printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n",
- ioc->name, event_data->CurrentTemperature);
- }
-}
-
-/**
- * _scsih_flush_running_cmds - completing outstanding commands.
- * @ioc: per adapter object
- *
- * The flushing out of all pending scmd commands following host reset,
- * where all IO is dropped to the floor.
- *
- * Return nothing.
- */
-static void
-_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
-{
- struct scsi_cmnd *scmd;
- u16 smid;
- u16 count = 0;
-
- for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
- scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
- if (!scmd)
- continue;
- count++;
- mpt2sas_base_free_smid(ioc, smid);
- scsi_dma_unmap(scmd);
- if (ioc->pci_error_recovery)
- scmd->result = DID_NO_CONNECT << 16;
- else
- scmd->result = DID_RESET << 16;
- scmd->scsi_done(scmd);
- }
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n",
- ioc->name, count));
-}
-
-/**
- * _scsih_setup_eedp - setup MPI request for EEDP transfer
- * @scmd: pointer to scsi command object
- * @mpi_request: pointer to the SCSI_IO reqest message frame
- *
- * Supporting protection 1 and 3.
- *
- * Returns nothing
- */
-static void
-_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request)
-{
- u16 eedp_flags;
- unsigned char prot_op = scsi_get_prot_op(scmd);
- unsigned char prot_type = scsi_get_prot_type(scmd);
-
- if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL)
- return;
-
- if (prot_op == SCSI_PROT_READ_STRIP)
- eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP;
- else if (prot_op == SCSI_PROT_WRITE_INSERT)
- eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP;
- else
- return;
-
- switch (prot_type) {
- case SCSI_PROT_DIF_TYPE1:
- case SCSI_PROT_DIF_TYPE2:
-
- /*
- * enable ref/guard checking
- * auto increment ref tag
- */
- eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG |
- MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
- mpi_request->CDB.EEDP32.PrimaryReferenceTag =
- cpu_to_be32(scsi_get_lba(scmd));
- break;
-
- case SCSI_PROT_DIF_TYPE3:
-
- /*
- * enable guard checking
- */
- eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD;
- break;
- }
- mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size);
- mpi_request->EEDPFlags = cpu_to_le16(eedp_flags);
-}
-
-/**
- * _scsih_eedp_error_handling - return sense code for EEDP errors
- * @scmd: pointer to scsi command object
- * @ioc_status: ioc status
- *
- * Returns nothing
- */
-static void
-_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
-{
- u8 ascq;
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- ascq = 0x01;
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- ascq = 0x02;
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- ascq = 0x03;
- break;
- default:
- ascq = 0x00;
- break;
- }
-
- scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq);
- scmd->result = DRIVER_SENSE << 24 | (DID_ABORT << 16) |
- SAM_STAT_CHECK_CONDITION;
-}
-
-/**
- * _scsih_scsi_direct_io_get - returns direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- *
- * Returns the smid stored scmd pointer.
- */
-static inline u8
-_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->scsi_lookup[smid - 1].direct_io;
-}
-
-/**
- * _scsih_scsi_direct_io_set - sets direct io flag
- * @ioc: per adapter object
- * @smid: system request message index
- * @direct_io: Zero or non-zero value to set in the direct_io flag
- *
- * Returns Nothing.
- */
-static inline void
-_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
-{
- ioc->scsi_lookup[smid - 1].direct_io = direct_io;
-}
-
-
-/**
- * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
- * @ioc: per adapter object
- * @scmd: pointer to scsi command object
- * @raid_device: pointer to raid device data structure
- * @mpi_request: pointer to the SCSI_IO reqest message frame
- * @smid: system request message index
- *
- * Returns nothing
- */
-static void
-_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
- struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
- u16 smid)
-{
- sector_t v_lba, p_lba, stripe_off, column, io_size;
- u32 stripe_sz, stripe_exp;
- u8 num_pds, cmd = scmd->cmnd[0];
-
- if (cmd != READ_10 && cmd != WRITE_10 &&
- cmd != READ_16 && cmd != WRITE_16)
- return;
-
- if (cmd == READ_10 || cmd == WRITE_10)
- v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
- else
- v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
-
- io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
-
- if (v_lba + io_size - 1 > raid_device->max_lba)
- return;
-
- stripe_sz = raid_device->stripe_sz;
- stripe_exp = raid_device->stripe_exponent;
- stripe_off = v_lba & (stripe_sz - 1);
-
- /* Return unless IO falls within a stripe */
- if (stripe_off + io_size > stripe_sz)
- return;
-
- num_pds = raid_device->num_pds;
- p_lba = v_lba >> stripe_exp;
- column = sector_div(p_lba, num_pds);
- p_lba = (p_lba << stripe_exp) + stripe_off;
-
- mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
-
- if (cmd == READ_10 || cmd == WRITE_10)
- put_unaligned_be32(lower_32_bits(p_lba),
- &mpi_request->CDB.CDB32[2]);
- else
- put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
-
- _scsih_scsi_direct_io_set(ioc, smid, 1);
-}
-
-/**
- * _scsih_qcmd - main scsi request entry point
- * @scmd: pointer to scsi command object
- * @done: function pointer to be invoked on completion
- *
- * The callback index is set inside `ioc->scsi_io_cb_idx`.
- *
- * Returns 0 on success. If there's a failure, return either:
- * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
- * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
- */
-static int
-_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct _raid_device *raid_device;
- Mpi2SCSIIORequest_t *mpi_request;
- u32 mpi_control;
- u16 smid;
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- if (ioc->pci_error_recovery || ioc->remove_host) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- sas_target_priv_data = sas_device_priv_data->sas_target;
- /* invalid device handle */
- if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- /* host recovery or link resets sent via IOCTLs */
- if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress)
- return SCSI_MLQUEUE_HOST_BUSY;
- /* device busy with task management */
- else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy)
- return SCSI_MLQUEUE_DEVICE_BUSY;
- /* device has been deleted */
- else if (sas_target_priv_data->deleted) {
- scmd->result = DID_NO_CONNECT << 16;
- scmd->scsi_done(scmd);
- return 0;
- }
-
- if (scmd->sc_data_direction == DMA_FROM_DEVICE)
- mpi_control = MPI2_SCSIIO_CONTROL_READ;
- else if (scmd->sc_data_direction == DMA_TO_DEVICE)
- mpi_control = MPI2_SCSIIO_CONTROL_WRITE;
- else
- mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
-
- /* set tags */
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
-
- /* Make sure Device is not raid volume.
- * We do not expose raid functionality to upper layer for warpdrive.
- */
- if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
- mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
-
- smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- goto out;
- }
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t));
- _scsih_setup_eedp(scmd, mpi_request);
- if (scmd->cmd_len == 32)
- mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT;
- mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT)
- mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH;
- else
- mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
- mpi_request->DevHandle =
- cpu_to_le16(sas_device_priv_data->sas_target->handle);
- mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
- mpi_request->Control = cpu_to_le32(mpi_control);
- mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len);
- mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR;
- mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE;
- mpi_request->SenseBufferLowAddress =
- mpt2sas_base_get_sense_buffer_dma(ioc, smid);
- mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4;
- mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI +
- MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR);
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
- mpi_request->LUN);
- memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
-
- if (!mpi_request->DataLength) {
- mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL);
- } else {
- if (_scsih_build_scatter_gather(ioc, scmd, smid)) {
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
- }
-
- raid_device = sas_target_priv_data->raid_device;
- if (raid_device && raid_device->direct_io_enabled)
- _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request,
- smid);
-
- if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST))
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- le16_to_cpu(mpi_request->DevHandle));
- else
- mpt2sas_base_put_smid_default(ioc, smid);
- return 0;
-
- out:
- return SCSI_MLQUEUE_HOST_BUSY;
-}
-
-/**
- * _scsih_normalize_sense - normalize descriptor and fixed format sense data
- * @sense_buffer: sense data returned by target
- * @data: normalized skey/asc/ascq
- *
- * Return nothing.
- */
-static void
-_scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
-{
- if ((sense_buffer[0] & 0x7F) >= 0x72) {
- /* descriptor format */
- data->skey = sense_buffer[1] & 0x0F;
- data->asc = sense_buffer[2];
- data->ascq = sense_buffer[3];
- } else {
- /* fixed format */
- data->skey = sense_buffer[2] & 0x0F;
- data->asc = sense_buffer[12];
- data->ascq = sense_buffer[13];
- }
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request
- * @ioc: per adapter object
- * @scmd: pointer to scsi command object
- * @mpi_reply: reply mf payload returned from firmware
- *
- * scsi_status - SCSI Status code returned from target device
- * scsi_state - state info associated with SCSI_IO determined by ioc
- * ioc_status - ioc supplied status info
- *
- * Return nothing.
- */
-static void
-_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
- Mpi2SCSIIOReply_t *mpi_reply, u16 smid)
-{
- u32 response_info;
- u8 *response_bytes;
- u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- u8 scsi_state = mpi_reply->SCSIState;
- u8 scsi_status = mpi_reply->SCSIStatus;
- char *desc_ioc_state = NULL;
- char *desc_scsi_status = NULL;
- char *desc_scsi_state = ioc->tmp_string;
- u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
- struct _sas_device *sas_device = NULL;
- struct scsi_target *starget = scmd->device->sdev_target;
- struct MPT2SAS_TARGET *priv_target = starget->hostdata;
- char *device_str = NULL;
-
- if (!priv_target)
- return;
-
- if (ioc->hide_ir_msg)
- device_str = "WarpDrive";
- else
- device_str = "volume";
-
- if (log_info == 0x31170000)
- return;
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_SUCCESS:
- desc_ioc_state = "success";
- break;
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- desc_ioc_state = "invalid function";
- break;
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- desc_ioc_state = "scsi recovered error";
- break;
- case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE:
- desc_ioc_state = "scsi invalid dev handle";
- break;
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- desc_ioc_state = "scsi device not there";
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- desc_ioc_state = "scsi data overrun";
- break;
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- desc_ioc_state = "scsi data underrun";
- break;
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- desc_ioc_state = "scsi io data error";
- break;
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- desc_ioc_state = "scsi protocol error";
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- desc_ioc_state = "scsi task terminated";
- break;
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- desc_ioc_state = "scsi residual mismatch";
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- desc_ioc_state = "scsi task mgmt failed";
- break;
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- desc_ioc_state = "scsi ioc terminated";
- break;
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- desc_ioc_state = "scsi ext terminated";
- break;
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- desc_ioc_state = "eedp guard error";
- break;
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- desc_ioc_state = "eedp ref tag error";
- break;
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- desc_ioc_state = "eedp app tag error";
- break;
- default:
- desc_ioc_state = "unknown";
- break;
- }
-
- switch (scsi_status) {
- case MPI2_SCSI_STATUS_GOOD:
- desc_scsi_status = "good";
- break;
- case MPI2_SCSI_STATUS_CHECK_CONDITION:
- desc_scsi_status = "check condition";
- break;
- case MPI2_SCSI_STATUS_CONDITION_MET:
- desc_scsi_status = "condition met";
- break;
- case MPI2_SCSI_STATUS_BUSY:
- desc_scsi_status = "busy";
- break;
- case MPI2_SCSI_STATUS_INTERMEDIATE:
- desc_scsi_status = "intermediate";
- break;
- case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET:
- desc_scsi_status = "intermediate condmet";
- break;
- case MPI2_SCSI_STATUS_RESERVATION_CONFLICT:
- desc_scsi_status = "reservation conflict";
- break;
- case MPI2_SCSI_STATUS_COMMAND_TERMINATED:
- desc_scsi_status = "command terminated";
- break;
- case MPI2_SCSI_STATUS_TASK_SET_FULL:
- desc_scsi_status = "task set full";
- break;
- case MPI2_SCSI_STATUS_ACA_ACTIVE:
- desc_scsi_status = "aca active";
- break;
- case MPI2_SCSI_STATUS_TASK_ABORTED:
- desc_scsi_status = "task aborted";
- break;
- default:
- desc_scsi_status = "unknown";
- break;
- }
-
- desc_scsi_state[0] = '\0';
- if (!scsi_state)
- desc_scsi_state = " ";
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
- strcat(desc_scsi_state, "response info ");
- if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- strcat(desc_scsi_state, "state terminated ");
- if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS)
- strcat(desc_scsi_state, "no status ");
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED)
- strcat(desc_scsi_state, "autosense failed ");
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)
- strcat(desc_scsi_state, "autosense valid ");
-
- scsi_print_command(scmd);
-
- if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
- printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
- device_str, (unsigned long long)priv_target->sas_address);
- } else {
- sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target);
- if (sas_device) {
- printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), "
- "phy(%d)\n", ioc->name, sas_device->sas_address,
- sas_device->phy);
- printk(MPT2SAS_WARN_FMT
- "\tenclosure_logical_id(0x%016llx), slot(%d)\n",
- ioc->name, sas_device->enclosure_logical_id,
- sas_device->slot);
-
- sas_device_put(sas_device);
- }
- }
-
- printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), "
- "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle),
- desc_ioc_state, ioc_status, smid);
- printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), "
- "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow,
- scsi_get_resid(scmd));
- printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), "
- "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag),
- le32_to_cpu(mpi_reply->TransferCount), scmd->result);
- printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), "
- "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status,
- scsi_status, desc_scsi_state, scsi_state);
-
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- struct sense_info data;
- _scsih_normalize_sense(scmd->sense_buffer, &data);
- printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: "
- "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey,
- data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount));
- }
-
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) {
- response_info = le32_to_cpu(mpi_reply->ResponseInfo);
- response_bytes = (u8 *)&response_info;
- _scsih_response_code(ioc, response_bytes[0]);
- }
-}
-#endif
-
-/**
- * _scsih_turn_on_pfa_led - illuminate PFA LED
- * @ioc: per adapter object
- * @handle: device handle
- * Context: process
- *
- * Return nothing.
- */
-static void
-_scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2SepReply_t mpi_reply;
- Mpi2SepRequest_t mpi_request;
- struct _sas_device *sas_device;
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (!sas_device)
- return;
-
- memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
- mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
- mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
- mpi_request.SlotStatus =
- cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT);
- mpi_request.DevHandle = cpu_to_le16(handle);
- mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS;
- if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
- &mpi_request)) != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- goto out;
- }
- sas_device->pfa_led_on = 1;
-
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
- goto out;
- }
-out:
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_turn_off_pfa_led - turn off PFA LED
- * @ioc: per adapter object
- * @sas_device: sas device whose PFA LED has to turned off
- * Context: process
- *
- * Return nothing.
- */
-static void
-_scsih_turn_off_pfa_led(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- Mpi2SepReply_t mpi_reply;
- Mpi2SepRequest_t mpi_request;
-
- memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t));
- mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR;
- mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS;
- mpi_request.SlotStatus = 0;
- mpi_request.Slot = cpu_to_le16(sas_device->slot);
- mpi_request.DevHandle = 0;
- mpi_request.EnclosureHandle = cpu_to_le16(sas_device->enclosure_handle);
- mpi_request.Flags = MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS;
- if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply,
- &mpi_request)) != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: "
- "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name,
- le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo)));
- return;
- }
-}
-
-/**
- * _scsih_send_event_to_turn_on_pfa_led - fire delayed event
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt.
- *
- * Return nothing.
- */
-static void
-_scsih_send_event_to_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct fw_event_work *fw_event;
-
- fw_event = alloc_fw_event_work(0);
- if (!fw_event)
- return;
- fw_event->event = MPT2SAS_TURN_ON_PFA_LED;
- fw_event->device_handle = handle;
- fw_event->ioc = ioc;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
-}
-
-/**
- * _scsih_smart_predicted_fault - process smart errors
- * @ioc: per adapter object
- * @handle: device handle
- * Context: interrupt.
- *
- * Return nothing.
- */
-static void
-_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct scsi_target *starget;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- Mpi2EventNotificationReply_t *event_reply;
- Mpi2EventDataSasDeviceStatusChange_t *event_data;
- struct _sas_device *sas_device;
- ssize_t sz;
- unsigned long flags;
-
- /* only handle non-raid devices */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (!sas_device) {
- goto out_unlock;
- }
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
-
- if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
- ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
- goto out_unlock;
-
- starget_printk(KERN_WARNING, starget, "predicted fault\n");
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
- _scsih_send_event_to_turn_on_pfa_led(ioc, handle);
-
- /* insert into event log */
- sz = offsetof(Mpi2EventNotificationReply_t, EventData) +
- sizeof(Mpi2EventDataSasDeviceStatusChange_t);
- event_reply = kzalloc(sz, GFP_ATOMIC);
- if (!event_reply) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- event_reply->Event =
- cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE);
- event_reply->MsgLength = sz/4;
- event_reply->EventDataLength =
- cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4);
- event_data = (Mpi2EventDataSasDeviceStatusChange_t *)
- event_reply->EventData;
- event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA;
- event_data->ASC = 0x5D;
- event_data->DevHandle = cpu_to_le16(handle);
- event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
- mpt2sas_ctl_add_to_event_log(ioc, event_reply);
- kfree(event_reply);
-out:
- if (sas_device)
- sas_device_put(sas_device);
- return;
-
-out_unlock:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- goto out;
-}
-
-/**
- * _scsih_io_done - scsi request callback
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Callback handler when using _scsih_qcmd.
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
-{
- Mpi2SCSIIORequest_t *mpi_request;
- Mpi2SCSIIOReply_t *mpi_reply;
- struct scsi_cmnd *scmd;
- u16 ioc_status;
- u32 xfer_cnt;
- u8 scsi_state;
- u8 scsi_status;
- u32 log_info;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 response_code = 0;
- unsigned long flags;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
- if (scmd == NULL)
- return 1;
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
-
- if (mpi_reply == NULL) {
- scmd->result = DID_OK << 16;
- goto out;
- }
-
- sas_device_priv_data = scmd->device->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target ||
- sas_device_priv_data->sas_target->deleted) {
- scmd->result = DID_NO_CONNECT << 16;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
- /*
- * WARPDRIVE: If direct_io is set then it is directIO,
- * the failed direct I/O should be redirected to volume
- */
- if (_scsih_scsi_direct_io_get(ioc, smid) &&
- ((ioc_status & MPI2_IOCSTATUS_MASK)
- != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].scmd = scmd;
- _scsih_scsi_direct_io_set(ioc, smid, 0);
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
- mpi_request->DevHandle =
- cpu_to_le16(sas_device_priv_data->sas_target->handle);
- mpt2sas_base_put_smid_scsi_io(ioc, smid,
- sas_device_priv_data->sas_target->handle);
- return 0;
- }
-
-
- /* turning off TLR */
- scsi_state = mpi_reply->SCSIState;
- if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
- response_code =
- le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
- if (!sas_device_priv_data->tlr_snoop_check) {
- sas_device_priv_data->tlr_snoop_check++;
- /* Make sure Device is not raid volume.
- * We do not expose raid functionality to upper layer for warpdrive.
- */
- if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) &&
- sas_is_tlr_enabled(scmd->device) &&
- response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
- sas_disable_tlr(scmd->device);
- sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
- }
- }
-
- xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
- scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt);
- if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)
- log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
- else
- log_info = 0;
- ioc_status &= MPI2_IOCSTATUS_MASK;
- scsi_status = mpi_reply->SCSIStatus;
-
- if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 &&
- (scsi_status == MPI2_SCSI_STATUS_BUSY ||
- scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT ||
- scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) {
- ioc_status = MPI2_IOCSTATUS_SUCCESS;
- }
-
- if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) {
- struct sense_info data;
- const void *sense_data = mpt2sas_base_get_sense_buffer(ioc,
- smid);
- u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE,
- le32_to_cpu(mpi_reply->SenseCount));
- memcpy(scmd->sense_buffer, sense_data, sz);
- _scsih_normalize_sense(scmd->sense_buffer, &data);
- /* failure prediction threshold exceeded */
- if (data.asc == 0x5D)
- _scsih_smart_predicted_fault(ioc,
- le16_to_cpu(mpi_reply->DevHandle));
- }
-
- switch (ioc_status) {
- case MPI2_IOCSTATUS_BUSY:
- case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES:
- scmd->result = SAM_STAT_BUSY;
- break;
-
- case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE:
- scmd->result = DID_NO_CONNECT << 16;
- break;
-
- case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED:
- if (sas_device_priv_data->block) {
- scmd->result = DID_TRANSPORT_DISRUPTED << 16;
- goto out;
- }
- if (log_info == 0x32010081) {
- scmd->result = DID_RESET << 16;
- break;
- }
- scmd->result = DID_SOFT_ERROR << 16;
- break;
- case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
- case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED:
- scmd->result = DID_RESET << 16;
- break;
-
- case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH:
- if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt))
- scmd->result = DID_SOFT_ERROR << 16;
- else
- scmd->result = (DID_OK << 16) | scsi_status;
- break;
-
- case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN:
- scmd->result = (DID_OK << 16) | scsi_status;
-
- if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID))
- break;
-
- if (xfer_cnt < scmd->underflow) {
- if (scsi_status == SAM_STAT_BUSY)
- scmd->result = SAM_STAT_BUSY;
- else
- scmd->result = DID_SOFT_ERROR << 16;
- } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS))
- scmd->result = DID_SOFT_ERROR << 16;
- else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- scmd->result = DID_RESET << 16;
- else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) {
- mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID;
- mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION;
- scmd->result = (DRIVER_SENSE << 24) |
- SAM_STAT_CHECK_CONDITION;
- scmd->sense_buffer[0] = 0x70;
- scmd->sense_buffer[2] = ILLEGAL_REQUEST;
- scmd->sense_buffer[12] = 0x20;
- scmd->sense_buffer[13] = 0;
- }
- break;
-
- case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN:
- scsi_set_resid(scmd, 0);
- case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR:
- case MPI2_IOCSTATUS_SUCCESS:
- scmd->result = (DID_OK << 16) | scsi_status;
- if (response_code ==
- MPI2_SCSITASKMGMT_RSP_INVALID_FRAME ||
- (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED |
- MPI2_SCSI_STATE_NO_SCSI_STATUS)))
- scmd->result = DID_SOFT_ERROR << 16;
- else if (scsi_state & MPI2_SCSI_STATE_TERMINATED)
- scmd->result = DID_RESET << 16;
- break;
-
- case MPI2_IOCSTATUS_EEDP_GUARD_ERROR:
- case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR:
- case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR:
- _scsih_eedp_error_handling(scmd, ioc_status);
- break;
- case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR:
- case MPI2_IOCSTATUS_INVALID_FUNCTION:
- case MPI2_IOCSTATUS_INVALID_SGL:
- case MPI2_IOCSTATUS_INTERNAL_ERROR:
- case MPI2_IOCSTATUS_INVALID_FIELD:
- case MPI2_IOCSTATUS_INVALID_STATE:
- case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR:
- case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED:
- default:
- scmd->result = DID_SOFT_ERROR << 16;
- break;
-
- }
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
- _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
-#endif
-
- out:
- scsi_dma_unmap(scmd);
- scmd->scsi_done(scmd);
- return 1;
-}
-
-/**
- * _scsih_sas_host_refresh - refreshing sas host object contents
- * @ioc: per adapter object
- * Context: user
- *
- * During port enable, fw will send topology events for every device. Its
- * possible that the handles may change from the previous setting, so this
- * code keeping handles updating if changed.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc)
-{
- u16 sz;
- u16 ioc_status;
- int i;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- u16 attached_handle;
- u8 link_rate;
-
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT
- "updating handles for sas_host(0x%016llx)\n",
- ioc->name, (unsigned long long)ioc->sas_hba.sas_address));
-
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys
- * sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz)) != 0)
- goto out;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- goto out;
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4;
- if (i == 0)
- ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
- PhyData[0].ControllerDevHandle);
- ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
- attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i].
- AttachedDevHandle);
- if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
- link_rate = MPI2_SAS_NEG_LINK_RATE_1_5;
- mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address,
- attached_handle, i, link_rate);
- }
- out:
- kfree(sas_iounit_pg0);
-}
-
-/**
- * _scsih_sas_host_add - create sas host object
- * @ioc: per adapter object
- *
- * Creating host side data object, stored in ioc->sas_hba
- *
- * Return nothing.
- */
-static void
-_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc)
-{
- int i;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasPhyPage0_t phy_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- u16 ioc_status;
- u16 sz;
- u16 device_missing_delay;
-
- mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys);
- if (!ioc->sas_hba.num_phys) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- /* sas_iounit page 0 */
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- /* sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- ioc->io_missing_delay =
- le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay);
- device_missing_delay =
- le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay);
- if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16)
- ioc->device_missing_delay = (device_missing_delay &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16;
- else
- ioc->device_missing_delay = device_missing_delay &
- MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
-
- ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev;
- ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys,
- sizeof(struct _sas_phy), GFP_KERNEL);
- if (!ioc->sas_hba.phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- i))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
-
- if (i == 0)
- ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0->
- PhyData[0].ControllerDevHandle);
- ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle;
- ioc->sas_hba.phy[i].phy_id = i;
- mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i],
- phy_pg0, ioc->sas_hba.parent_dev);
- }
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out;
- }
- ioc->sas_hba.enclosure_handle =
- le16_to_cpu(sas_device_pg0.EnclosureHandle);
- ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), "
- "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle,
- (unsigned long long) ioc->sas_hba.sas_address,
- ioc->sas_hba.num_phys) ;
-
- if (ioc->sas_hba.enclosure_handle) {
- if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
- &enclosure_pg0,
- MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- ioc->sas_hba.enclosure_handle))) {
- ioc->sas_hba.enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
- }
- }
-
- out:
- kfree(sas_iounit_pg1);
- kfree(sas_iounit_pg0);
-}
-
-/**
- * _scsih_expander_add - creating expander object
- * @ioc: per adapter object
- * @handle: expander handle
- *
- * Creating expander object, stored in ioc->sas_expander_list.
- *
- * Return 0 for success, else error.
- */
-static int
-_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_node *sas_expander;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2ExpanderPage1_t expander_pg1;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- u32 ioc_status;
- u16 parent_handle;
- u64 sas_address, sas_address_parent = 0;
- int i;
- unsigned long flags;
- struct _sas_port *mpt2sas_port = NULL;
- int rc = 0;
-
- if (!handle)
- return -1;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- return -1;
-
- if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- /* handle out of order topology events */
- parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle);
- if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent)
- != 0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if (sas_address_parent != ioc->sas_hba.sas_address) {
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address_parent);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (!sas_expander) {
- rc = _scsih_expander_add(ioc, parent_handle);
- if (rc != 0)
- return rc;
- }
- }
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_address = le64_to_cpu(expander_pg0.SASAddress);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (sas_expander)
- return 0;
-
- sas_expander = kzalloc(sizeof(struct _sas_node),
- GFP_KERNEL);
- if (!sas_expander) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_expander->handle = handle;
- sas_expander->num_phys = expander_pg0.NumPhys;
- sas_expander->sas_address_parent = sas_address_parent;
- sas_expander->sas_address = sas_address;
-
- printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x),"
- " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name,
- handle, parent_handle, (unsigned long long)
- sas_expander->sas_address, sas_expander->num_phys);
-
- if (!sas_expander->num_phys)
- goto out_fail;
- sas_expander->phy = kcalloc(sas_expander->num_phys,
- sizeof(struct _sas_phy), GFP_KERNEL);
- if (!sas_expander->phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
-
- INIT_LIST_HEAD(&sas_expander->sas_port_list);
- mpt2sas_port = mpt2sas_transport_port_add(ioc, handle,
- sas_address_parent);
- if (!mpt2sas_port) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- sas_expander->parent_dev = &mpt2sas_port->rphy->dev;
-
- for (i = 0 ; i < sas_expander->num_phys ; i++) {
- if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
- &expander_pg1, i, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- sas_expander->phy[i].handle = handle;
- sas_expander->phy[i].phy_id = i;
-
- if ((mpt2sas_transport_add_expander_phy(ioc,
- &sas_expander->phy[i], expander_pg1,
- sas_expander->parent_dev))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -1;
- goto out_fail;
- }
- }
-
- if (sas_expander->enclosure_handle) {
- if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply,
- &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- sas_expander->enclosure_handle))) {
- sas_expander->enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
- }
- }
-
- _scsih_expander_node_add(ioc, sas_expander);
- return 0;
-
- out_fail:
-
- if (mpt2sas_port)
- mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_address_parent);
- kfree(sas_expander);
- return rc;
-}
-
-/**
- * _scsih_done - scsih callback handler.
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Callback handler when sending internal generated message frames.
- * The callback index passed is `ioc->scsih_cb_idx`
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-static u8
-_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->scsih_cmds.smid != smid)
- return 1;
- ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- memcpy(ioc->scsih_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->scsih_cmds.done);
- return 1;
-}
-
-/**
- * mpt2sas_expander_remove - removing expander object
- * @ioc: per adapter object
- * @sas_address: expander sas_address
- *
- * Return nothing.
- */
-void
-mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address)
-{
- struct _sas_node *sas_expander;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address);
- if (sas_expander)
- list_del(&sas_expander->list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (sas_expander)
- _scsih_expander_node_remove(ioc, sas_expander);
-}
-
-/**
- * _scsih_check_access_status - check access flags
- * @ioc: per adapter object
- * @sas_address: sas address
- * @handle: sas device handle
- * @access_flags: errors returned during discovery of the device
- *
- * Return 0 for success, else failure
- */
-static u8
-_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 handle, u8 access_status)
-{
- u8 rc = 1;
- char *desc = NULL;
-
- switch (access_status) {
- case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS:
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION:
- rc = 0;
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED:
- desc = "sata capability failed";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT:
- desc = "sata affiliation conflict";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE:
- desc = "route not addressable";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE:
- desc = "smp error not addressable";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED:
- desc = "device blocked";
- break;
- case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE:
- case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX:
- desc = "sata initialization failed";
- break;
- default:
- desc = "unknown";
- break;
- }
-
- if (!rc)
- return 0;
-
- printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), "
- "handle(0x%04x)\n", ioc->name, desc,
- (unsigned long long)sas_address, handle);
- return rc;
-}
-
-static void
-_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- struct _sas_device *sas_device;
- u32 ioc_status;
- unsigned long flags;
- u64 sas_address;
- struct scsi_target *starget;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- u32 device_info;
-
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle)))
- return;
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- return;
-
- /* check if this is end device */
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info)))
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (!sas_device) {
- printk(MPT2SAS_ERR_FMT "device is not present "
- "handle(0x%04x), no sas_device!!!\n", ioc->name, handle);
- goto out_unlock;
- }
-
- if (unlikely(sas_device->handle != handle)) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)"
- " to (0x%04x)!!!\n", sas_device->handle, handle);
- sas_target_priv_data->handle = handle;
- sas_device->handle = handle;
- }
-
- /* check if device is present */
- if (!(le16_to_cpu(sas_device_pg0.Flags) &
- MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- printk(MPT2SAS_ERR_FMT "device is not present "
- "handle(0x%04x), flags!!!\n", ioc->name, handle);
- goto out_unlock;
- }
-
- /* check if there were any issues with discovery */
- if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
- goto out_unlock;
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- _scsih_ublock_io_device(ioc, sas_address);
- if (sas_device)
- sas_device_put(sas_device);
- return;
-
-out_unlock:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_add_device - creating sas device object
- * @ioc: per adapter object
- * @handle: sas device handle
- * @phy_num: phy number end device attached to
- * @is_pd: is this hidden raid component
- *
- * Creating end device object, stored in ioc->sas_device_list.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd)
-{
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2SasEnclosurePage0_t enclosure_pg0;
- struct _sas_device *sas_device;
- u32 ioc_status;
- __le64 sas_address;
- u32 device_info;
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
-
- /* check if device is present */
- if (!(le16_to_cpu(sas_device_pg0.Flags) &
- MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n",
- ioc->name, le16_to_cpu(sas_device_pg0.Flags));
- return -1;
- }
-
- /* check if there were any issues with discovery */
- if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus))
- return -1;
-
- /* check if this is end device */
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- sas_device = mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (sas_device) {
- sas_device_put(sas_device);
- return 0;
- }
-
- sas_device = kzalloc(sizeof(struct _sas_device),
- GFP_KERNEL);
- if (!sas_device) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
-
- kref_init(&sas_device->refcount);
- sas_device->handle = handle;
- if (_scsih_get_sas_address(ioc, le16_to_cpu
- (sas_device_pg0.ParentDevHandle),
- &sas_device->sas_address_parent) != 0)
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_device->enclosure_handle =
- le16_to_cpu(sas_device_pg0.EnclosureHandle);
- sas_device->slot =
- le16_to_cpu(sas_device_pg0.Slot);
- sas_device->device_info = device_info;
- sas_device->sas_address = sas_address;
- sas_device->phy = sas_device_pg0.PhyNum;
-
- /* get enclosure_logical_id */
- if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0(
- ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE,
- sas_device->enclosure_handle)))
- sas_device->enclosure_logical_id =
- le64_to_cpu(enclosure_pg0.EnclosureLogicalID);
-
- /* get device name */
- sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName);
-
- if (ioc->wait_for_discovery_to_complete)
- _scsih_sas_device_init_add(ioc, sas_device);
- else
- _scsih_sas_device_add(ioc, sas_device);
-
- sas_device_put(sas_device);
- return 0;
-}
-
-/**
- * _scsih_remove_device - removing sas device object
- * @ioc: per adapter object
- * @sas_device_delete: the sas_device object
- *
- * Return nothing.
- */
-static void
-_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
-
- if ((ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) &&
- (sas_device->pfa_led_on)) {
- _scsih_turn_off_pfa_led(ioc, sas_device);
- sas_device->pfa_led_on = 0;
- }
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
-
- if (sas_device->starget && sas_device->starget->hostdata) {
- sas_target_priv_data = sas_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- _scsih_ublock_io_device(ioc, sas_device->sas_address);
- sas_target_priv_data->handle =
- MPT2SAS_INVALID_DEVICE_HANDLE;
- }
-
- if (!ioc->hide_drives)
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
-
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr"
- "(0x%016llx)\n", ioc->name, sas_device->handle,
- (unsigned long long) sas_device->sas_address);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: "
- "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__,
- sas_device->handle, (unsigned long long)
- sas_device->sas_address));
-}
-/**
- * _scsih_device_remove_by_handle - removing device object by handle
- * @ioc: per adapter object
- * @handle: device handle
- *
- * Return nothing.
- */
-static void
-_scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-
-/**
- * mpt2sas_device_remove_by_sas_address - removing device object by sas address
- * @ioc: per adapter object
- * @sas_address: device sas_address
- *
- * Return nothing.
- */
-void
-mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- struct _sas_device *sas_device;
- unsigned long flags;
-
- if (ioc->shost_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address);
- if (sas_device) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device) {
- _scsih_remove_device(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_topology_change_event_debug - debug for topology event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- */
-static void
-_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasTopologyChangeList_t *event_data)
-{
- int i;
- u16 handle;
- u16 reason_code;
- u8 phy_number;
- char *status_str = NULL;
- u8 link_rate, prev_link_rate;
-
- switch (event_data->ExpStatus) {
- case MPI2_EVENT_SAS_TOPO_ES_ADDED:
- status_str = "add";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING:
- status_str = "remove";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_RESPONDING:
- case 0:
- status_str = "responding";
- break;
- case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING:
- status_str = "remove delay";
- break;
- default:
- status_str = "unknown status";
- break;
- }
- printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n",
- ioc->name, status_str);
- printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) "
- "start_phy(%02d), count(%d)\n",
- le16_to_cpu(event_data->ExpanderDevHandle),
- le16_to_cpu(event_data->EnclosureHandle),
- event_data->StartPhyNum, event_data->NumEntries);
- for (i = 0; i < event_data->NumEntries; i++) {
- handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
- if (!handle)
- continue;
- phy_number = event_data->StartPhyNum + i;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
- switch (reason_code) {
- case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
- status_str = "target add";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
- status_str = "target remove";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING:
- status_str = "delay target remove";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
- status_str = "link rate change";
- break;
- case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE:
- status_str = "target responding";
- break;
- default:
- status_str = "unknown";
- break;
- }
- link_rate = event_data->PHY[i].LinkRate >> 4;
- prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:"
- " link rate: new(0x%02x), old(0x%02x)\n", phy_number,
- handle, status_str, link_rate, prev_link_rate);
-
- }
-}
-#endif
-
-/**
- * _scsih_sas_topology_change_event - handle topology changes
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- */
-static void
-_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- int i;
- u16 parent_handle, handle;
- u16 reason_code;
- u8 phy_number, max_phys;
- struct _sas_node *sas_expander;
- u64 sas_address;
- unsigned long flags;
- u8 link_rate, prev_link_rate;
- Mpi2EventDataSasTopologyChangeList_t *event_data =
- (Mpi2EventDataSasTopologyChangeList_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_topology_change_event_debug(ioc, event_data);
-#endif
-
- if (ioc->remove_host || ioc->pci_error_recovery)
- return;
-
- if (!ioc->sas_hba.num_phys)
- _scsih_sas_host_add(ioc);
- else
- _scsih_sas_host_refresh(ioc);
-
- if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander "
- "event\n", ioc->name));
- return;
- }
-
- parent_handle = le16_to_cpu(event_data->ExpanderDevHandle);
-
- /* handle expander add */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED)
- if (_scsih_expander_add(ioc, parent_handle) != 0)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc,
- parent_handle);
- if (sas_expander) {
- sas_address = sas_expander->sas_address;
- max_phys = sas_expander->num_phys;
- } else if (parent_handle < ioc->sas_hba.num_phys) {
- sas_address = ioc->sas_hba.sas_address;
- max_phys = ioc->sas_hba.num_phys;
- } else {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle siblings events */
- for (i = 0; i < event_data->NumEntries; i++) {
- if (fw_event->ignore) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring "
- "expander event\n", ioc->name));
- return;
- }
- if (ioc->shost_recovery || ioc->remove_host ||
- ioc->pci_error_recovery)
- return;
- phy_number = event_data->StartPhyNum + i;
- if (phy_number >= max_phys)
- continue;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
- if ((event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
- MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
- continue;
- handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
- if (!handle)
- continue;
- link_rate = event_data->PHY[i].LinkRate >> 4;
- prev_link_rate = event_data->PHY[i].LinkRate & 0xF;
- switch (reason_code) {
- case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED:
-
- if (ioc->shost_recovery)
- break;
-
- if (link_rate == prev_link_rate)
- break;
-
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, phy_number, link_rate);
-
- if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5)
- break;
-
- _scsih_check_device(ioc, handle);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED:
-
- if (ioc->shost_recovery)
- break;
-
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, phy_number, link_rate);
-
- _scsih_add_device(ioc, handle, phy_number, 0);
- break;
- case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING:
-
- _scsih_device_remove_by_handle(ioc, handle);
- break;
- }
- }
-
- /* handle expander removal */
- if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING &&
- sas_expander)
- mpt2sas_expander_remove(ioc, sas_address);
-
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_device_status_change_event_debug - debug for device event
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasDeviceStatusChange_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->ReasonCode) {
- case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
- reason_str = "smart data";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED:
- reason_str = "unsupported device discovered";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
- reason_str = "internal device reset";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL:
- reason_str = "internal task abort";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL:
- reason_str = "internal task abort set";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL:
- reason_str = "internal clear task set";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL:
- reason_str = "internal query task";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE:
- reason_str = "sata init failure";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET:
- reason_str = "internal device reset complete";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL:
- reason_str = "internal task abort complete";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION:
- reason_str = "internal async notification";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY:
- reason_str = "expander reduced functionality";
- break;
- case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY:
- reason_str = "expander reduced functionality complete";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
- printk(MPT2SAS_INFO_FMT "device status change: (%s)\n"
- "\thandle(0x%04x), sas address(0x%016llx), tag(%d)",
- ioc->name, reason_str, le16_to_cpu(event_data->DevHandle),
- (unsigned long long)le64_to_cpu(event_data->SASAddress),
- le16_to_cpu(event_data->TaskTag));
- if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA)
- printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name,
- event_data->ASC, event_data->ASCQ);
- printk(KERN_INFO "\n");
-}
-#endif
-
-/**
- * _scsih_sas_device_status_change_event - handle device status change
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- struct MPT2SAS_TARGET *target_priv_data;
- struct _sas_device *sas_device;
- u64 sas_address;
- unsigned long flags;
- Mpi2EventDataSasDeviceStatusChange_t *event_data =
- (Mpi2EventDataSasDeviceStatusChange_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_device_status_change_event_debug(ioc,
- event_data);
-#endif
-
- /* In MPI Revision K (0xC), the internal device reset complete was
- * implemented, so avoid setting tm_busy flag for older firmware.
- */
- if ((ioc->facts.HeaderVersion >> 8) < 0xC)
- return;
-
- if (event_data->ReasonCode !=
- MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
- event_data->ReasonCode !=
- MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET)
- return;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_address = le64_to_cpu(event_data->SASAddress);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- sas_address);
-
- if (!sas_device || !sas_device->starget)
- goto out;
-
- target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data)
- goto out;
-
- if (event_data->ReasonCode ==
- MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
- target_priv_data->tm_busy = 1;
- else
- target_priv_data->tm_busy = 0;
-
-out:
- if (sas_device)
- sas_device_put(sas_device);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataSasEnclDevStatusChange_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->ReasonCode) {
- case MPI2_EVENT_SAS_ENCL_RC_ADDED:
- reason_str = "enclosure add";
- break;
- case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING:
- reason_str = "enclosure remove";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
-
- printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n"
- "\thandle(0x%04x), enclosure logical id(0x%016llx)"
- " number slots(%d)\n", ioc->name, reason_str,
- le16_to_cpu(event_data->EnclosureHandle),
- (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
- le16_to_cpu(event_data->StartSlot));
-}
-#endif
-
-/**
- * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_enclosure_dev_status_change_event_debug(ioc,
- (Mpi2EventDataSasEnclDevStatusChange_t *)
- fw_event->event_data);
-#endif
-}
-
-/**
- * _scsih_sas_broadcast_primitive_event - handle broadcast events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- struct scsi_cmnd *scmd;
- struct scsi_device *sdev;
- u16 smid, handle;
- u32 lun;
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- u32 termination_count;
- u32 query_count;
- Mpi2SCSITaskManagementReply_t *mpi_reply;
- Mpi2EventDataSasBroadcastPrimitive_t *event_data =
- (Mpi2EventDataSasBroadcastPrimitive_t *)
- fw_event->event_data;
- u16 ioc_status;
- unsigned long flags;
- int r;
- u8 max_retries = 0;
- u8 task_abort_retries;
-
- mutex_lock(&ioc->tm_cmds.mutex);
- pr_info(MPT2SAS_FMT
- "%s: enter: phy number(%d), width(%d)\n",
- ioc->name, __func__, event_data->PhyNum,
- event_data->PortWidth);
-
- _scsih_block_io_all_device(ioc);
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- mpi_reply = ioc->tm_cmds.reply;
-broadcast_aen_retry:
-
- /* sanity checks for retrying this loop */
- if (max_retries++ == 5) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n",
- ioc->name, __func__));
- goto out;
- } else if (max_retries > 1)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n",
- ioc->name, __func__, max_retries - 1));
-
- termination_count = 0;
- query_count = 0;
- for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
- if (ioc->shost_recovery)
- goto out;
- scmd = _scsih_scsi_lookup_get(ioc, smid);
- if (!scmd)
- continue;
- sdev = scmd->device;
- sas_device_priv_data = sdev->hostdata;
- if (!sas_device_priv_data || !sas_device_priv_data->sas_target)
- continue;
- /* skip hidden raid components */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_RAID_COMPONENT)
- continue;
- /* skip volumes */
- if (sas_device_priv_data->sas_target->flags &
- MPT_TARGET_FLAGS_VOLUME)
- continue;
-
- handle = sas_device_priv_data->sas_target->handle;
- lun = sas_device_priv_data->lun;
- query_count++;
-
- if (ioc->shost_recovery)
- goto out;
-
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun,
- MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30,
- TM_MUTEX_OFF);
- if (r == FAILED) {
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: FAILED when sending "
- "QUERY_TASK: scmd(%p)\n", scmd);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
- ioc_status = le16_to_cpu(mpi_reply->IOCStatus)
- & MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- sdev_printk(KERN_WARNING, sdev, "query task: FAILED "
- "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status,
- scmd);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
-
- /* see if IO is still owned by IOC and target */
- if (mpi_reply->ResponseCode ==
- MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
- mpi_reply->ResponseCode ==
- MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) {
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- continue;
- }
- task_abort_retries = 0;
- tm_retry:
- if (task_abort_retries++ == 60) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s: ABORT_TASK: giving up\n", ioc->name,
- __func__));
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- goto broadcast_aen_retry;
- }
-
- if (ioc->shost_recovery)
- goto out_no_lock;
-
- r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id,
- sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30,
- TM_MUTEX_OFF);
- if (r == FAILED) {
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : "
- "scmd(%p)\n", scmd);
- goto tm_retry;
- }
-
- if (task_abort_retries > 1)
- sdev_printk(KERN_WARNING, sdev,
- "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):"
- " scmd(%p)\n",
- task_abort_retries - 1, scmd);
-
- termination_count += le32_to_cpu(mpi_reply->TerminationCount);
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- }
-
- if (ioc->broadcast_aen_pending) {
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to"
- " pending AEN\n", ioc->name, __func__));
- ioc->broadcast_aen_pending = 0;
- goto broadcast_aen_retry;
- }
-
- out:
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- out_no_lock:
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - exit, query_count = %d termination_count = %d\n",
- ioc->name, __func__, query_count, termination_count));
-
- ioc->broadcast_aen_busy = 0;
- if (!ioc->shost_recovery)
- _scsih_ublock_io_all_device(ioc);
- mutex_unlock(&ioc->tm_cmds.mutex);
-}
-
-/**
- * _scsih_sas_discovery_event - handle discovery events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- Mpi2EventDataSasDiscovery_t *event_data =
- (Mpi2EventDataSasDiscovery_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
- printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name,
- (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
- "start" : "stop");
- if (event_data->DiscoveryStatus)
- printk("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- printk("\n");
- }
-#endif
-
- if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
- !ioc->sas_hba.num_phys) {
- if (disable_discovery > 0 && ioc->shost_recovery) {
- /* Wait for the reset to complete */
- while (ioc->shost_recovery)
- ssleep(1);
- }
- _scsih_sas_host_add(ioc);
- }
-}
-
-/**
- * _scsih_reprobe_lun - reprobing lun
- * @sdev: scsi device struct
- * @no_uld_attach: sdev->no_uld_attach flag setting
- *
- **/
-static void
-_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach)
-{
- int rc;
-
- sdev->no_uld_attach = no_uld_attach ? 1 : 0;
- sdev_printk(KERN_INFO, sdev, "%s raid component\n",
- sdev->no_uld_attach ? "hidding" : "exposing");
- rc = scsi_device_reprobe(sdev);
-}
-
-/**
- * _scsih_sas_volume_add - add new volume
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- u64 wwid;
- u16 handle = le16_to_cpu(element->VolDevHandle);
- int rc;
-
- mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
- if (!wwid) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (raid_device)
- return;
-
- raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
- if (!raid_device) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- return;
- }
-
- raid_device->id = ioc->sas_id++;
- raid_device->channel = RAID_CHANNEL;
- raid_device->handle = handle;
- raid_device->wwid = wwid;
- _scsih_raid_device_add(ioc, raid_device);
- if (!ioc->wait_for_discovery_to_complete) {
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- } else {
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- _scsih_determine_boot_device(ioc, raid_device, 1);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-}
-
-/**
- * _scsih_sas_volume_delete - delete volume
- * @ioc: per adapter object
- * @handle: volume device handle
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle)
-{
- struct _raid_device *raid_device;
- unsigned long flags;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget = NULL;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device) {
- if (raid_device->starget) {
- starget = raid_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->deleted = 1;
- }
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- list_del(&raid_device->list);
- kfree(raid_device);
- }
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (starget)
- scsi_remove_target(&starget->dev);
-}
-
-/**
- * _scsih_sas_pd_expose - expose pd component to /dev/sdX
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- struct scsi_target *starget = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device->volume_handle = 0;
- sas_device->volume_wwid = 0;
- clear_bit(handle, ioc->pd_handles);
- if (sas_device->starget && sas_device->starget->hostdata) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->flags &=
- ~MPT_TARGET_FLAGS_RAID_COMPONENT;
- }
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
-
- /* exposing raid component */
- if (starget)
- starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
-
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_sas_pd_hide - hide pd component from /dev/sdX
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- struct scsi_target *starget = NULL;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- unsigned long flags;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- u16 volume_handle = 0;
- u64 volume_wwid = 0;
-
- mpt2sas_config_get_volume_handle(ioc, handle, &volume_handle);
- if (volume_handle)
- mpt2sas_config_get_volume_wwid(ioc, volume_handle,
- &volume_wwid);
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- set_bit(handle, ioc->pd_handles);
- if (sas_device->starget && sas_device->starget->hostdata) {
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->flags |=
- MPT_TARGET_FLAGS_RAID_COMPONENT;
- sas_device->volume_handle = volume_handle;
- sas_device->volume_wwid = volume_wwid;
- }
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (!sas_device)
- return;
-
- /* hiding raid component */
- if (starget)
- starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
-
- sas_device_put(sas_device);
-}
-
-/**
- * _scsih_sas_pd_delete - delete pd component
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
-
- _scsih_device_remove_by_handle(ioc, handle);
-}
-
-/**
- * _scsih_sas_pd_add - remove pd component
- * @ioc: per adapter object
- * @element: IR config element data
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventIrConfigElement_t *element)
-{
- struct _sas_device *sas_device;
- u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- u64 sas_address;
- u16 parent_handle;
-
- set_bit(handle, ioc->pd_handles);
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- return;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
-
- _scsih_add_device(ioc, handle, 0, 1);
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrConfigChangeList_t *event_data)
-{
- Mpi2EventIrConfigElement_t *element;
- u8 element_type;
- int i;
- char *reason_str = NULL, *element_str = NULL;
-
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
-
- printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n",
- ioc->name, (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ?
- "foreign" : "native", event_data->NumElements);
- for (i = 0; i < event_data->NumElements; i++, element++) {
- switch (element->ReasonCode) {
- case MPI2_EVENT_IR_CHANGE_RC_ADDED:
- reason_str = "add";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
- reason_str = "remove";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE:
- reason_str = "no change";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- reason_str = "hide";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- reason_str = "unhide";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
- reason_str = "volume_created";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
- reason_str = "volume_deleted";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- reason_str = "pd_created";
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- reason_str = "pd_deleted";
- break;
- default:
- reason_str = "unknown reason";
- break;
- }
- element_type = le16_to_cpu(element->ElementFlags) &
- MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK;
- switch (element_type) {
- case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT:
- element_str = "volume";
- break;
- case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT:
- element_str = "phys disk";
- break;
- case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT:
- element_str = "hot spare";
- break;
- default:
- element_str = "unknown element";
- break;
- }
- printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), "
- "pd handle(0x%04x), pd num(0x%02x)\n", element_str,
- reason_str, le16_to_cpu(element->VolDevHandle),
- le16_to_cpu(element->PhysDiskDevHandle),
- element->PhysDiskNum);
- }
-}
-#endif
-
-/**
- * _scsih_sas_ir_config_change_event - handle ir configuration change events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- Mpi2EventIrConfigElement_t *element;
- int i;
- u8 foreign_config;
- Mpi2EventDataIrConfigChangeList_t *event_data =
- (Mpi2EventDataIrConfigChangeList_t *)
- fw_event->event_data;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- && !ioc->hide_ir_msg)
- _scsih_sas_ir_config_change_event_debug(ioc, event_data);
-
-#endif
-
- if (ioc->shost_recovery)
- return;
-
- foreign_config = (le32_to_cpu(event_data->Flags) &
- MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
-
- element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- for (i = 0; i < event_data->NumElements; i++, element++) {
-
- switch (element->ReasonCode) {
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED:
- case MPI2_EVENT_IR_CHANGE_RC_ADDED:
- if (!foreign_config)
- _scsih_sas_volume_add(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED:
- case MPI2_EVENT_IR_CHANGE_RC_REMOVED:
- if (!foreign_config)
- _scsih_sas_volume_delete(ioc,
- le16_to_cpu(element->VolDevHandle));
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_hide(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_expose(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_add(ioc, element);
- break;
- case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- if (!ioc->is_warpdrive)
- _scsih_sas_pd_delete(ioc, element);
- break;
- }
- }
-}
-
-/**
- * _scsih_sas_ir_volume_event - IR volume event
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- u64 wwid;
- unsigned long flags;
- struct _raid_device *raid_device;
- u16 handle;
- u32 state;
- int rc;
- Mpi2EventDataIrVolume_t *event_data =
- (Mpi2EventDataIrVolume_t *)
- fw_event->event_data;
-
- if (ioc->shost_recovery)
- return;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
- return;
-
- handle = le16_to_cpu(event_data->VolDevHandle);
- state = le32_to_cpu(event_data->NewValue);
- if (!ioc->hide_ir_msg)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
-
- switch (state) {
- case MPI2_RAID_VOL_STATE_MISSING:
- case MPI2_RAID_VOL_STATE_FAILED:
- _scsih_sas_volume_delete(ioc, handle);
- break;
-
- case MPI2_RAID_VOL_STATE_ONLINE:
- case MPI2_RAID_VOL_STATE_DEGRADED:
- case MPI2_RAID_VOL_STATE_OPTIMAL:
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-
- if (raid_device)
- break;
-
- mpt2sas_config_get_volume_wwid(ioc, handle, &wwid);
- if (!wwid) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- break;
- }
-
- raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL);
- if (!raid_device) {
- printk(MPT2SAS_ERR_FMT
- "failure at %s:%d/%s()!\n", ioc->name,
- __FILE__, __LINE__, __func__);
- break;
- }
-
- raid_device->id = ioc->sas_id++;
- raid_device->channel = RAID_CHANNEL;
- raid_device->handle = handle;
- raid_device->wwid = wwid;
- _scsih_raid_device_add(ioc, raid_device);
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- break;
-
- case MPI2_RAID_VOL_STATE_INITIALIZING:
- default:
- break;
- }
-}
-
-/**
- * _scsih_sas_ir_physical_disk_event - PD event
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- u16 handle, parent_handle;
- u32 state;
- struct _sas_device *sas_device;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasDevicePage0_t sas_device_pg0;
- u32 ioc_status;
- Mpi2EventDataIrPhysicalDisk_t *event_data =
- (Mpi2EventDataIrPhysicalDisk_t *)
- fw_event->event_data;
- u64 sas_address;
-
- if (ioc->shost_recovery)
- return;
-
- if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED)
- return;
-
- handle = le16_to_cpu(event_data->PhysDiskDevHandle);
- state = le32_to_cpu(event_data->NewValue);
-
- if (!ioc->hide_ir_msg)
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), "
- "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
-
- switch (state) {
- case MPI2_RAID_PD_STATE_ONLINE:
- case MPI2_RAID_PD_STATE_DEGRADED:
- case MPI2_RAID_PD_STATE_REBUILDING:
- case MPI2_RAID_PD_STATE_OPTIMAL:
- case MPI2_RAID_PD_STATE_HOT_SPARE:
-
- if (!ioc->is_warpdrive)
- set_bit(handle, ioc->pd_handles);
-
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- return;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address))
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
-
- _scsih_add_device(ioc, handle, 0, 1);
-
- break;
-
- case MPI2_RAID_PD_STATE_OFFLINE:
- case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
- case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
- default:
- break;
- }
-}
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
-/**
- * _scsih_sas_ir_operation_status_event_debug - debug for IR op event
- * @ioc: per adapter object
- * @event_data: event data payload
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
- Mpi2EventDataIrOperationStatus_t *event_data)
-{
- char *reason_str = NULL;
-
- switch (event_data->RAIDOperation) {
- case MPI2_EVENT_IR_RAIDOP_RESYNC:
- reason_str = "resync";
- break;
- case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION:
- reason_str = "online capacity expansion";
- break;
- case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK:
- reason_str = "consistency check";
- break;
- case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT:
- reason_str = "background init";
- break;
- case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT:
- reason_str = "make data consistent";
- break;
- }
-
- if (!reason_str)
- return;
-
- printk(MPT2SAS_INFO_FMT "raid operational status: (%s)"
- "\thandle(0x%04x), percent complete(%d)\n",
- ioc->name, reason_str,
- le16_to_cpu(event_data->VolDevHandle),
- event_data->PercentComplete);
-}
-#endif
-
-/**
- * _scsih_sas_ir_operation_status_event - handle RAID operation events
- * @ioc: per adapter object
- * @fw_event: The fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
- struct fw_event_work *fw_event)
-{
- Mpi2EventDataIrOperationStatus_t *event_data =
- (Mpi2EventDataIrOperationStatus_t *)
- fw_event->event_data;
- static struct _raid_device *raid_device;
- unsigned long flags;
- u16 handle;
-
-#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
- if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- && !ioc->hide_ir_msg)
- _scsih_sas_ir_operation_status_event_debug(ioc,
- event_data);
-#endif
-
- /* code added for raid transport support */
- if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- handle = le16_to_cpu(event_data->VolDevHandle);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
- if (raid_device)
- raid_device->percent_complete =
- event_data->PercentComplete;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- }
-}
-
-/**
- * _scsih_prep_device_scan - initialize parameters prior to device scan
- * @ioc: per adapter object
- *
- * Set the deleted flag prior to device scan. If the device is found during
- * the scan, then we clear the deleted flag.
- */
-static void
-_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc)
-{
- struct MPT2SAS_DEVICE *sas_device_priv_data;
- struct scsi_device *sdev;
-
- shost_for_each_device(sdev, ioc->shost) {
- sas_device_priv_data = sdev->hostdata;
- if (sas_device_priv_data && sas_device_priv_data->sas_target)
- sas_device_priv_data->sas_target->deleted = 1;
- }
-}
-
-/**
- * _scsih_mark_responding_sas_device - mark a sas_devices as responding
- * @ioc: per adapter object
- * @sas_address: sas address
- * @slot: enclosure slot id
- * @handle: device handle
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_sas_devices.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 slot, u16 handle)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data = NULL;
- struct scsi_target *starget;
- struct _sas_device *sas_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry(sas_device, &ioc->sas_device_list, list) {
- if (sas_device->sas_address == sas_address &&
- sas_device->slot == slot) {
- sas_device->responding = 1;
- starget = sas_device->starget;
- if (starget && starget->hostdata) {
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->tm_busy = 0;
- sas_target_priv_data->deleted = 0;
- } else
- sas_target_priv_data = NULL;
- if (starget)
- starget_printk(KERN_INFO, starget,
- "handle(0x%04x), sas_addr(0x%016llx), "
- "enclosure logical id(0x%016llx), "
- "slot(%d)\n", handle,
- (unsigned long long)sas_device->sas_address,
- (unsigned long long)
- sas_device->enclosure_logical_id,
- sas_device->slot);
- if (sas_device->handle == handle)
- goto out;
- printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
- sas_device->handle);
- sas_device->handle = handle;
- if (sas_target_priv_data)
- sas_target_priv_data->handle = handle;
- goto out;
- }
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_search_responding_sas_devices -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- __le64 sas_address;
- u16 handle;
- u32 device_info;
- u16 slot;
-
- printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name);
-
- if (list_empty(&ioc->sas_device_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
- handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- handle = le16_to_cpu(sas_device_pg0.DevHandle);
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
- if (!(_scsih_is_end_device(device_info)))
- continue;
- sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- slot = le16_to_cpu(sas_device_pg0.Slot);
- _scsih_mark_responding_sas_device(ioc, sas_address, slot,
- handle);
- }
-out:
- printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n",
- ioc->name);
-}
-
-/**
- * _scsih_mark_responding_raid_device - mark a raid_device as responding
- * @ioc: per adapter object
- * @wwid: world wide identifier for raid volume
- * @handle: device handle
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_raid_devices.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid,
- u16 handle)
-{
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct scsi_target *starget;
- struct _raid_device *raid_device;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- list_for_each_entry(raid_device, &ioc->raid_device_list, list) {
- if (raid_device->wwid == wwid && raid_device->starget) {
- starget = raid_device->starget;
- if (starget && starget->hostdata) {
- sas_target_priv_data = starget->hostdata;
- sas_target_priv_data->deleted = 0;
- } else
- sas_target_priv_data = NULL;
- raid_device->responding = 1;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- starget_printk(KERN_INFO, raid_device->starget,
- "handle(0x%04x), wwid(0x%016llx)\n", handle,
- (unsigned long long)raid_device->wwid);
- /*
- * WARPDRIVE: The handles of the PDs might have changed
- * across the host reset so re-initialize the
- * required data for Direct IO
- */
- _scsih_init_warpdrive_properties(ioc, raid_device);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- if (raid_device->handle == handle) {
- spin_unlock_irqrestore(&ioc->raid_device_lock,
- flags);
- return;
- }
- printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
- raid_device->handle);
- raid_device->handle = handle;
- if (sas_target_priv_data)
- sas_target_priv_data->handle = handle;
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- return;
- }
- }
-
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
-}
-
-/**
- * _scsih_search_responding_raid_devices -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidVolPage1_t volume_pg1;
- Mpi2RaidVolPage0_t volume_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 handle;
- u8 phys_disk_num;
-
- if (!ioc->ir_firmware)
- return;
-
- printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n",
- ioc->name);
-
- if (list_empty(&ioc->raid_device_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- handle = le16_to_cpu(volume_pg1.DevHandle);
-
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
- &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t)))
- continue;
-
- if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED)
- _scsih_mark_responding_raid_device(ioc,
- le64_to_cpu(volume_pg1.WWID), handle);
- }
-
- /* refresh the pd_handles */
- if (!ioc->is_warpdrive) {
- phys_disk_num = 0xFF;
- memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
- while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
- phys_disk_num))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
- phys_disk_num = pd_pg0.PhysDiskNum;
- handle = le16_to_cpu(pd_pg0.DevHandle);
- set_bit(handle, ioc->pd_handles);
- }
- }
-out:
- printk(MPT2SAS_INFO_FMT "search for responding raid volumes: "
- "complete\n", ioc->name);
-}
-
-/**
- * _scsih_mark_responding_expander - mark a expander as responding
- * @ioc: per adapter object
- * @sas_address: sas address
- * @handle:
- *
- * After host reset, find out whether devices are still responding.
- * Used in _scsi_remove_unresponsive_expanders.
- *
- * Return nothing.
- */
-static void
-_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u16 handle)
-{
- struct _sas_node *sas_expander;
- unsigned long flags;
- int i;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) {
- if (sas_expander->sas_address != sas_address)
- continue;
- sas_expander->responding = 1;
- if (sas_expander->handle == handle)
- goto out;
- printk(KERN_INFO "\texpander(0x%016llx): handle changed"
- " from(0x%04x) to (0x%04x)!!!\n",
- (unsigned long long)sas_expander->sas_address,
- sas_expander->handle, handle);
- sas_expander->handle = handle;
- for (i = 0 ; i < sas_expander->num_phys ; i++)
- sas_expander->phy[i].handle = handle;
- goto out;
- }
- out:
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-}
-
-/**
- * _scsih_search_responding_expanders -
- * @ioc: per adapter object
- *
- * After host reset, find out whether devices are still responding.
- * If not remove.
- *
- * Return nothing.
- */
-static void
-_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u64 sas_address;
- u16 handle;
-
- printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name);
-
- if (list_empty(&ioc->sas_expander_list))
- goto out;
-
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS)
- break;
-
- handle = le16_to_cpu(expander_pg0.DevHandle);
- sas_address = le64_to_cpu(expander_pg0.SASAddress);
- printk(KERN_INFO "\texpander present: handle(0x%04x), "
- "sas_addr(0x%016llx)\n", handle,
- (unsigned long long)sas_address);
- _scsih_mark_responding_expander(ioc, sas_address, handle);
- }
-
- out:
- printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name);
-}
-
-/**
- * _scsih_remove_unresponding_sas_devices - removing unresponding devices
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device, *sas_device_next;
- struct _sas_node *sas_expander, *sas_expander_next;
- struct _raid_device *raid_device, *raid_device_next;
- struct list_head tmp_list;
- unsigned long flags;
- LIST_HEAD(head);
-
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n",
- ioc->name);
-
- /* removing unresponding end devices */
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n",
- ioc->name);
-
- /*
- * Iterate, pulling off devices marked as non-responding. We become the
- * owner for the reference the list had on any object we prune.
- */
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_for_each_entry_safe(sas_device, sas_device_next,
- &ioc->sas_device_list, list) {
- if (!sas_device->responding)
- list_move_tail(&sas_device->list, &head);
- else
- sas_device->responding = 0;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- /*
- * Now, uninitialize and remove the unresponding devices we pruned.
- */
- list_for_each_entry_safe(sas_device, sas_device_next, &head, list) {
- _scsih_remove_device(ioc, sas_device);
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
-
- /* removing unresponding volumes */
- if (ioc->ir_firmware) {
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: "
- "volumes\n", ioc->name);
- list_for_each_entry_safe(raid_device, raid_device_next,
- &ioc->raid_device_list, list) {
- if (!raid_device->responding)
- _scsih_sas_volume_delete(ioc,
- raid_device->handle);
- else
- raid_device->responding = 0;
- }
- }
- /* removing unresponding expanders */
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: expanders\n",
- ioc->name);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- INIT_LIST_HEAD(&tmp_list);
- list_for_each_entry_safe(sas_expander, sas_expander_next,
- &ioc->sas_expander_list, list) {
- if (!sas_expander->responding)
- list_move_tail(&sas_expander->list, &tmp_list);
- else
- sas_expander->responding = 0;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- list_for_each_entry_safe(sas_expander, sas_expander_next, &tmp_list,
- list) {
- list_del(&sas_expander->list);
- _scsih_expander_node_remove(ioc, sas_expander);
- }
- printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n",
- ioc->name);
- /* unblock devices */
- _scsih_ublock_io_all_device(ioc);
-}
-
-static void
-_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander, u16 handle)
-{
- Mpi2ExpanderPage1_t expander_pg1;
- Mpi2ConfigReply_t mpi_reply;
- int i;
-
- for (i = 0 ; i < sas_expander->num_phys ; i++) {
- if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply,
- &expander_pg1, i, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- mpt2sas_transport_update_links(ioc, sas_expander->sas_address,
- le16_to_cpu(expander_pg1.AttachedDevHandle), i,
- expander_pg1.NegotiatedLinkRate >> 4);
- }
-}
-
-/**
- * _scsih_scan_for_devices_after_reset - scan for devices after host reset
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2ExpanderPage0_t expander_pg0;
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2RaidVolPage1_t volume_pg1;
- Mpi2RaidVolPage0_t volume_pg0;
- Mpi2RaidPhysDiskPage0_t pd_pg0;
- Mpi2EventIrConfigElement_t element;
- Mpi2ConfigReply_t mpi_reply;
- u8 phys_disk_num;
- u16 ioc_status;
- u16 handle, parent_handle;
- u64 sas_address;
- struct _sas_device *sas_device;
- struct _sas_node *expander_device;
- static struct _raid_device *raid_device;
- u8 retry_count;
- unsigned long flags;
-
- printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name);
-
- _scsih_sas_host_refresh(ioc);
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: expanders start\n",
- ioc->name);
- /* expanders */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0,
- MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from expander scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(expander_pg0.DevHandle);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- expander_device = mpt2sas_scsih_expander_find_by_sas_address(
- ioc, le64_to_cpu(expander_pg0.SASAddress));
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (expander_device)
- _scsih_refresh_expander_links(ioc, expander_device,
- handle);
- else {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding expander: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
- _scsih_expander_add(ioc, handle);
- printk(MPT2SAS_INFO_FMT "\tAFTER adding expander: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(expander_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: expanders complete\n",
- ioc->name);
-
- if (!ioc->ir_firmware)
- goto skip_to_sas;
-
- printk(MPT2SAS_INFO_FMT "\tscan devices phys disk start\n", ioc->name);
- /* phys disk */
- phys_disk_num = 0xFF;
- while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
- &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM,
- phys_disk_num))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan:"
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- phys_disk_num = pd_pg0.PhysDiskNum;
- handle = le16_to_cpu(pd_pg0.DevHandle);
- sas_device = mpt2sas_get_sdev_by_handle(ioc, handle);
- if (sas_device) {
- sas_device_put(sas_device);
- continue;
- }
- if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
- handle) != 0)
- continue;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from phys disk scan "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle,
- &sas_address)) {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding phys disk: "
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- mpt2sas_transport_update_links(ioc, sas_address,
- handle, sas_device_pg0.PhyNum,
- MPI2_SAS_NEG_LINK_RATE_1_5);
- set_bit(handle, ioc->pd_handles);
- retry_count = 0;
- /* This will retry adding the end device.
- * _scsih_add_device() will decide on retries and
- * return "1" when it should be retried
- */
- while (_scsih_add_device(ioc, handle, retry_count++,
- 1)) {
- ssleep(1);
- }
- printk(MPT2SAS_INFO_FMT "\tAFTER adding phys disk: "
- " handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: phys disk complete\n",
- ioc->name);
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: volumes start\n", ioc->name);
- /* volumes */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
- &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(volume_pg1.DevHandle);
- spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_wwid(ioc,
- le64_to_cpu(volume_pg1.WWID));
- spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
- if (raid_device)
- continue;
- if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply,
- &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle,
- sizeof(Mpi2RaidVolPage0_t)))
- continue;
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from volume scan: "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE ||
- volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) {
- memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t));
- element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED;
- element.VolDevHandle = volume_pg1.DevHandle;
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding volume: "
- " handle (0x%04x)\n", ioc->name,
- volume_pg1.DevHandle);
- _scsih_sas_volume_add(ioc, &element);
- printk(MPT2SAS_INFO_FMT "\tAFTER adding volume: "
- " handle (0x%04x)\n", ioc->name,
- volume_pg1.DevHandle);
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: volumes complete\n",
- ioc->name);
-
- skip_to_sas:
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: end devices start\n",
- ioc->name);
- /* sas devices */
- handle = 0xFFFF;
- while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply,
- &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE,
- handle))) {
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_INFO_FMT "\tbreak from end device scan:"
- " ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, ioc_status,
- le32_to_cpu(mpi_reply.IOCLogInfo));
- break;
- }
- handle = le16_to_cpu(sas_device_pg0.DevHandle);
- if (!(_scsih_is_end_device(
- le32_to_cpu(sas_device_pg0.DeviceInfo))))
- continue;
- sas_device = mpt2sas_get_sdev_by_addr(ioc,
- le64_to_cpu(sas_device_pg0.SASAddress));
- if (sas_device) {
- sas_device_put(sas_device);
- continue;
- }
- parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
- if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
- printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- mpt2sas_transport_update_links(ioc, sas_address, handle,
- sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5);
- retry_count = 0;
- /* This will retry adding the end device.
- * _scsih_add_device() will decide on retries and
- * return "1" when it should be retried
- */
- while (_scsih_add_device(ioc, handle, retry_count++,
- 0)) {
- ssleep(1);
- }
- printk(MPT2SAS_INFO_FMT "\tAFTER adding end device: "
- "handle (0x%04x), sas_addr(0x%016llx)\n",
- ioc->name, handle, (unsigned long long)
- le64_to_cpu(sas_device_pg0.SASAddress));
- }
- }
-
- printk(MPT2SAS_INFO_FMT "\tscan devices: end devices complete\n",
- ioc->name);
-
- printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name);
-}
-
-
-/**
- * mpt2sas_scsih_reset_handler - reset callback handler (for scsih)
- * @ioc: per adapter object
- * @reset_phase: phase
- *
- * The handler for doing any required cleanup or initialization.
- *
- * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET,
- * MPT2_IOC_DONE_RESET
- *
- * Return nothing.
- */
-void
-mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase)
-{
- switch (reset_phase) {
- case MPT2_IOC_PRE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_PRE_RESET\n", ioc->name, __func__));
- break;
- case MPT2_IOC_AFTER_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__));
- if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) {
- ioc->scsih_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid);
- complete(&ioc->scsih_cmds.done);
- }
- if (ioc->tm_cmds.status & MPT2_CMD_PENDING) {
- ioc->tm_cmds.status |= MPT2_CMD_RESET;
- mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid);
- complete(&ioc->tm_cmds.done);
- }
- _scsih_fw_event_cleanup_queue(ioc);
- _scsih_flush_running_cmds(ioc);
- break;
- case MPT2_IOC_DONE_RESET:
- dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: "
- "MPT2_IOC_DONE_RESET\n", ioc->name, __func__));
- _scsih_sas_host_refresh(ioc);
- _scsih_prep_device_scan(ioc);
- _scsih_search_responding_sas_devices(ioc);
- _scsih_search_responding_raid_devices(ioc);
- _scsih_search_responding_expanders(ioc);
- if ((!ioc->is_driver_loading) && !(disable_discovery > 0 &&
- !ioc->sas_hba.num_phys)) {
- _scsih_prep_device_scan(ioc);
- _scsih_search_responding_sas_devices(ioc);
- _scsih_search_responding_raid_devices(ioc);
- _scsih_search_responding_expanders(ioc);
- _scsih_error_recovery_delete_devices(ioc);
- }
- break;
- }
-}
-
-/**
- * _firmware_event_work - delayed task for processing firmware events
- * @ioc: per adapter object
- * @work: equal to the fw_event_work object
- * Context: user.
- *
- * Return nothing.
- */
-static void
-_firmware_event_work(struct work_struct *work)
-{
- struct fw_event_work *fw_event = container_of(work,
- struct fw_event_work, delayed_work.work);
- struct MPT2SAS_ADAPTER *ioc = fw_event->ioc;
-
- _scsih_fw_event_del_from_list(ioc, fw_event);
-
- /* the queue is being flushed so ignore this event */
- if (ioc->remove_host || ioc->pci_error_recovery) {
- fw_event_work_put(fw_event);
- return;
- }
-
- switch (fw_event->event) {
- case MPT2SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost) ||
- ioc->shost_recovery) {
- /*
- * If we're unloading, bail. Otherwise, this can become
- * an infinite loop.
- */
- if (ioc->remove_host)
- goto out;
-
- ssleep(1);
- }
- _scsih_remove_unresponding_sas_devices(ioc);
- _scsih_scan_for_devices_after_reset(ioc);
- break;
- case MPT2SAS_PORT_ENABLE_COMPLETE:
- ioc->start_scan = 0;
-
- if (missing_delay[0] != -1 && missing_delay[1] != -1)
- mpt2sas_base_update_missing_delay(ioc, missing_delay[0],
- missing_delay[1]);
-
- dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete "
- "from worker thread\n", ioc->name));
- break;
- case MPT2SAS_TURN_ON_PFA_LED:
- _scsih_turn_on_pfa_led(ioc, fw_event->device_handle);
- break;
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _scsih_sas_topology_change_event(ioc, fw_event);
- break;
- case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- _scsih_sas_device_status_change_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_SAS_DISCOVERY:
- _scsih_sas_discovery_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- _scsih_sas_broadcast_primitive_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- _scsih_sas_enclosure_dev_status_change_event(ioc,
- fw_event);
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_sas_ir_config_change_event(ioc, fw_event);
- break;
- case MPI2_EVENT_IR_VOLUME:
- _scsih_sas_ir_volume_event(ioc, fw_event);
- break;
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- _scsih_sas_ir_physical_disk_event(ioc, fw_event);
- break;
- case MPI2_EVENT_IR_OPERATION_STATUS:
- _scsih_sas_ir_operation_status_event(ioc, fw_event);
- break;
- }
-out:
- fw_event_work_put(fw_event);
-}
-
-/**
- * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
- * @ioc: per adapter object
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- * Context: interrupt.
- *
- * This function merely adds a new work task into ioc->firmware_event_thread.
- * The tasks are worked from _firmware_event_work in user context.
- *
- * Returns void.
- */
-void
-mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
- u32 reply)
-{
- struct fw_event_work *fw_event;
- Mpi2EventNotificationReply_t *mpi_reply;
- u16 event;
- u16 sz;
-
- /* events turned off due to host reset or driver unloading */
- if (ioc->remove_host || ioc->pci_error_recovery)
- return;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
-
- if (unlikely(!mpi_reply)) {
- printk(MPT2SAS_ERR_FMT "mpi_reply not valid at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- event = le16_to_cpu(mpi_reply->Event);
-
- switch (event) {
- /* handle these */
- case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- {
- Mpi2EventDataSasBroadcastPrimitive_t *baen_data =
- (Mpi2EventDataSasBroadcastPrimitive_t *)
- mpi_reply->EventData;
-
- if (baen_data->Primitive !=
- MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
- return;
-
- if (ioc->broadcast_aen_busy) {
- ioc->broadcast_aen_pending++;
- return;
- } else
- ioc->broadcast_aen_busy = 1;
- break;
- }
-
- case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _scsih_check_topo_delete_events(ioc,
- (Mpi2EventDataSasTopologyChangeList_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_check_ir_config_unhide_events(ioc,
- (Mpi2EventDataIrConfigChangeList_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_IR_VOLUME:
- _scsih_check_volume_delete_events(ioc,
- (Mpi2EventDataIrVolume_t *)
- mpi_reply->EventData);
- break;
- case MPI2_EVENT_LOG_ENTRY_ADDED:
- {
- Mpi2EventDataLogEntryAdded_t *log_entry;
- __le32 *log_code;
-
- if (!ioc->is_warpdrive)
- break;
-
- log_entry = (Mpi2EventDataLogEntryAdded_t *)
- mpi_reply->EventData;
- log_code = (__le32 *)log_entry->LogData;
-
- if (le16_to_cpu(log_entry->LogEntryQualifier)
- != MPT2_WARPDRIVE_LOGENTRY)
- break;
-
- switch (le32_to_cpu(*log_code)) {
- case MPT2_WARPDRIVE_LC_SSDT:
- printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
- "IO Throttling has occurred in the WarpDrive "
- "subsystem. Check WarpDrive documentation for "
- "additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_SSDLW:
- printk(MPT2SAS_WARN_FMT "WarpDrive Warning: "
- "Program/Erase Cycles for the WarpDrive subsystem "
- "in degraded range. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_SSDLF:
- printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
- "There are no Program/Erase Cycles for the "
- "WarpDrive subsystem. The storage device will be "
- "in read-only mode. Check WarpDrive documentation "
- "for additional details.\n", ioc->name);
- break;
- case MPT2_WARPDRIVE_LC_BRMF:
- printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: "
- "The Backup Rail Monitor has failed on the "
- "WarpDrive subsystem. Check WarpDrive "
- "documentation for additional details.\n",
- ioc->name);
- break;
- }
-
- break;
- }
- case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- case MPI2_EVENT_IR_OPERATION_STATUS:
- case MPI2_EVENT_SAS_DISCOVERY:
- case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
- case MPI2_EVENT_IR_PHYSICAL_DISK:
- break;
-
- case MPI2_EVENT_TEMP_THRESHOLD:
- _scsih_temp_threshold_events(ioc,
- (Mpi2EventDataTemperature_t *)
- mpi_reply->EventData);
- break;
-
- default: /* ignore the rest */
- return;
- }
-
- sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
- fw_event = alloc_fw_event_work(sz);
- if (!fw_event) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return;
- }
-
- memcpy(fw_event->event_data, mpi_reply->EventData, sz);
- fw_event->ioc = ioc;
- fw_event->VF_ID = mpi_reply->VF_ID;
- fw_event->VP_ID = mpi_reply->VP_ID;
- fw_event->event = event;
- _scsih_fw_event_add(ioc, fw_event);
- fw_event_work_put(fw_event);
- return;
-}
-
-/* shost template */
-static struct scsi_host_template scsih_driver_template = {
- .module = THIS_MODULE,
- .name = "Fusion MPT SAS Host",
- .proc_name = MPT2SAS_DRIVER_NAME,
- .queuecommand = _scsih_qcmd,
- .target_alloc = _scsih_target_alloc,
- .slave_alloc = _scsih_slave_alloc,
- .slave_configure = _scsih_slave_configure,
- .target_destroy = _scsih_target_destroy,
- .slave_destroy = _scsih_slave_destroy,
- .scan_finished = _scsih_scan_finished,
- .scan_start = _scsih_scan_start,
- .change_queue_depth = _scsih_change_queue_depth,
- .eh_abort_handler = _scsih_abort,
- .eh_device_reset_handler = _scsih_dev_reset,
- .eh_target_reset_handler = _scsih_target_reset,
- .eh_host_reset_handler = _scsih_host_reset,
- .bios_param = _scsih_bios_param,
- .can_queue = 1,
- .this_id = -1,
- .sg_tablesize = MPT2SAS_SG_DEPTH,
- .max_sectors = 32767,
- .cmd_per_lun = 7,
- .use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = mpt2sas_host_attrs,
- .sdev_attrs = mpt2sas_dev_attrs,
- .track_queue_depth = 1,
-};
-
-/**
- * _scsih_expander_node_remove - removing expander device from list.
- * @ioc: per adapter object
- * @sas_expander: the sas_device object
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * Removing object and freeing associated memory from the
- * ioc->sas_expander_list.
- *
- * Return nothing.
- */
-static void
-_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_expander)
-{
- struct _sas_port *mpt2sas_port, *next;
-
- /* remove sibling ports attached to this expander */
- list_for_each_entry_safe(mpt2sas_port, next,
- &sas_expander->sas_port_list, port_list) {
- if (ioc->shost_recovery)
- return;
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- else if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc,
- mpt2sas_port->remote_identify.sas_address);
- }
-
- mpt2sas_transport_port_remove(ioc, sas_expander->sas_address,
- sas_expander->sas_address_parent);
-
- printk(MPT2SAS_INFO_FMT "expander_remove: handle"
- "(0x%04x), sas_addr(0x%016llx)\n", ioc->name,
- sas_expander->handle, (unsigned long long)
- sas_expander->sas_address);
-
- kfree(sas_expander->phy);
- kfree(sas_expander);
-}
-
-/**
- * _scsih_ir_shutdown - IR shutdown notification
- * @ioc: per adapter object
- *
- * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that
- * the host system is shutting down.
- *
- * Return nothing.
- */
-static void
-_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc)
-{
- Mpi2RaidActionRequest_t *mpi_request;
- Mpi2RaidActionReply_t *mpi_reply;
- u16 smid;
-
- /* is IR firmware build loaded ? */
- if (!ioc->ir_firmware)
- return;
-
- mutex_lock(&ioc->scsih_cmds.mutex);
-
- if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n",
- ioc->name, __func__);
- goto out;
- }
- ioc->scsih_cmds.status = MPT2_CMD_PENDING;
-
- smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->scsih_cmds.smid = smid;
- memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t));
-
- mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
- mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
-
- if (!ioc->hide_ir_msg)
- printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name);
- init_completion(&ioc->scsih_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
-
- if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- goto out;
- }
-
- if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) {
- mpi_reply = ioc->scsih_cmds.reply;
-
- if (!ioc->hide_ir_msg)
- printk(MPT2SAS_INFO_FMT "IR shutdown (complete): "
- "ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
- }
-
- out:
- ioc->scsih_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->scsih_cmds.mutex);
-}
-
-/**
- * _scsih_shutdown - routine call during system shutdown
- * @pdev: PCI device struct
- *
- * Return nothing.
- */
-static void
-_scsih_shutdown(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct workqueue_struct *wq;
- unsigned long flags;
-
- ioc->remove_host = 1;
- _scsih_fw_event_cleanup_queue(ioc);
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- wq = ioc->firmware_event_thread;
- ioc->firmware_event_thread = NULL;
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- if (wq)
- destroy_workqueue(wq);
-
- _scsih_ir_shutdown(ioc);
- mpt2sas_base_detach(ioc);
-}
-
-/**
- * _scsih_remove - detach and remove add host
- * @pdev: PCI device struct
- *
- * Routine called when unloading the driver.
- * Return nothing.
- */
-static void
-_scsih_remove(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- struct _sas_port *mpt2sas_port, *next_port;
- struct _raid_device *raid_device, *next;
- struct MPT2SAS_TARGET *sas_target_priv_data;
- struct workqueue_struct *wq;
- unsigned long flags;
-
- ioc->remove_host = 1;
- _scsih_fw_event_cleanup_queue(ioc);
-
- spin_lock_irqsave(&ioc->fw_event_lock, flags);
- wq = ioc->firmware_event_thread;
- ioc->firmware_event_thread = NULL;
- spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- if (wq)
- destroy_workqueue(wq);
-
- /* release all the volumes */
- _scsih_ir_shutdown(ioc);
- list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
- list) {
- if (raid_device->starget) {
- sas_target_priv_data =
- raid_device->starget->hostdata;
- sas_target_priv_data->deleted = 1;
- scsi_remove_target(&raid_device->starget->dev);
- }
- printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid"
- "(0x%016llx)\n", ioc->name, raid_device->handle,
- (unsigned long long) raid_device->wwid);
- _scsih_raid_device_remove(ioc, raid_device);
- }
-
- /* free ports attached to the sas_host */
- list_for_each_entry_safe(mpt2sas_port, next_port,
- &ioc->sas_hba.sas_port_list, port_list) {
- if (mpt2sas_port->remote_identify.device_type ==
- SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc,
- mpt2sas_port->remote_identify.sas_address);
- else if (mpt2sas_port->remote_identify.device_type ==
- SAS_EDGE_EXPANDER_DEVICE ||
- mpt2sas_port->remote_identify.device_type ==
- SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc,
- mpt2sas_port->remote_identify.sas_address);
- }
-
- /* free phys attached to the sas_host */
- if (ioc->sas_hba.num_phys) {
- kfree(ioc->sas_hba.phy);
- ioc->sas_hba.phy = NULL;
- ioc->sas_hba.num_phys = 0;
- }
-
- sas_remove_host(shost);
- scsi_remove_host(shost);
- mpt2sas_base_detach(ioc);
- spin_lock(&gioc_lock);
- list_del(&ioc->list);
- spin_unlock(&gioc_lock);
- scsi_host_put(shost);
-}
-
-/**
- * _scsih_probe_boot_devices - reports 1st device
- * @ioc: per adapter object
- *
- * If specified in bios page 2, this routine reports the 1st
- * device scsi-ml or sas transport for persistent boot device
- * purposes. Please refer to function _scsih_determine_boot_device()
- */
-static void
-_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- u8 is_raid;
- void *device;
- struct _sas_device *sas_device;
- struct _raid_device *raid_device;
- u16 handle;
- u64 sas_address_parent;
- u64 sas_address;
- unsigned long flags;
- int rc;
-
- /* no Bios, return immediately */
- if (!ioc->bios_pg3.BiosVersion)
- return;
-
- device = NULL;
- is_raid = 0;
- if (ioc->req_boot_device.device) {
- device = ioc->req_boot_device.device;
- is_raid = ioc->req_boot_device.is_raid;
- } else if (ioc->req_alt_boot_device.device) {
- device = ioc->req_alt_boot_device.device;
- is_raid = ioc->req_alt_boot_device.is_raid;
- } else if (ioc->current_boot_device.device) {
- device = ioc->current_boot_device.device;
- is_raid = ioc->current_boot_device.is_raid;
- }
-
- if (!device)
- return;
-
- if (is_raid) {
- raid_device = device;
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- } else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = device;
- handle = sas_device->handle;
- sas_address_parent = sas_device->sas_address_parent;
- sas_address = sas_device->sas_address;
- list_move_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (ioc->hide_drives)
- return;
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- } else if (!sas_device->starget) {
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_address,
- sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- }
- }
- }
-}
-
-/**
- * _scsih_probe_raid - reporting raid volumes to scsi-ml
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _raid_device *raid_device, *raid_next;
- int rc;
-
- list_for_each_entry_safe(raid_device, raid_next,
- &ioc->raid_device_list, list) {
- if (raid_device->starget)
- continue;
- rc = scsi_add_device(ioc->shost, RAID_CHANNEL,
- raid_device->id, 0);
- if (rc)
- _scsih_raid_device_remove(ioc, raid_device);
- }
-}
-
-static struct _sas_device *get_next_sas_device(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- if (!list_empty(&ioc->sas_device_init_list)) {
- sas_device = list_first_entry(&ioc->sas_device_init_list,
- struct _sas_device, list);
- sas_device_get(sas_device);
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- return sas_device;
-}
-
-static void sas_device_make_active(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_device *sas_device)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
-
- /*
- * Since we dropped the lock during the call to port_add(), we need to
- * be careful here that somebody else didn't move or delete this item
- * while we were busy with other things.
- *
- * If it was on the list, we need a put() for the reference the list
- * had. Either way, we need a get() for the destination list.
- */
- if (!list_empty(&sas_device->list)) {
- list_del_init(&sas_device->list);
- sas_device_put(sas_device);
- }
-
- sas_device_get(sas_device);
- list_add_tail(&sas_device->list, &ioc->sas_device_list);
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-}
-
-/**
- * _scsih_probe_sas - reporting sas devices to sas transport
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc)
-{
- struct _sas_device *sas_device;
-
- if (ioc->hide_drives)
- return;
-
- while ((sas_device = get_next_sas_device(ioc))) {
- if (!mpt2sas_transport_port_add(ioc, sas_device->handle,
- sas_device->sas_address_parent)) {
- _scsih_sas_device_remove(ioc, sas_device);
- sas_device_put(sas_device);
- continue;
- } else if (!sas_device->starget) {
- if (!ioc->is_driver_loading) {
- mpt2sas_transport_port_remove(ioc,
- sas_device->sas_address,
- sas_device->sas_address_parent);
- _scsih_sas_device_remove(ioc, sas_device);
- sas_device_put(sas_device);
- continue;
- }
- }
-
- sas_device_make_active(ioc, sas_device);
- sas_device_put(sas_device);
- }
-}
-
-/**
- * _scsih_probe_devices - probing for devices
- * @ioc: per adapter object
- *
- * Called during initial loading of the driver.
- */
-static void
-_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc)
-{
- u16 volume_mapping_flags;
-
- if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR))
- return; /* return when IOC doesn't support initiator mode */
-
- _scsih_probe_boot_devices(ioc);
-
- if (ioc->ir_firmware) {
- volume_mapping_flags =
- le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) &
- MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE;
- if (volume_mapping_flags ==
- MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) {
- _scsih_probe_raid(ioc);
- _scsih_probe_sas(ioc);
- } else {
- _scsih_probe_sas(ioc);
- _scsih_probe_raid(ioc);
- }
- } else
- _scsih_probe_sas(ioc);
-}
-
-
-/**
- * _scsih_scan_start - scsi lld callback for .scan_start
- * @shost: SCSI host pointer
- *
- * The shost has the ability to discover targets on its own instead
- * of scanning the entire bus. In our implemention, we will kick off
- * firmware discovery.
- */
-static void
-_scsih_scan_start(struct Scsi_Host *shost)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int rc;
-
- if (diag_buffer_enable != -1 && diag_buffer_enable != 0)
- mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable);
-
- if (disable_discovery > 0)
- return;
-
- ioc->start_scan = 1;
- rc = mpt2sas_port_enable(ioc);
-
- if (rc != 0)
- printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name);
-}
-
-/**
- * _scsih_scan_finished - scsi lld callback for .scan_finished
- * @shost: SCSI host pointer
- * @time: elapsed time of the scan in jiffies
- *
- * This function will be called periodically until it returns 1 with the
- * scsi_host and the elapsed time of the scan in jiffies. In our implemention,
- * we wait for firmware discovery to complete, then return 1.
- */
-static int
-_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- if (disable_discovery > 0) {
- ioc->is_driver_loading = 0;
- ioc->wait_for_discovery_to_complete = 0;
- return 1;
- }
-
- if (time >= (300 * HZ)) {
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
- printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout "
- "(timeout=300s)\n", ioc->name);
- ioc->is_driver_loading = 0;
- return 1;
- }
-
- if (ioc->start_scan)
- return 0;
-
- if (ioc->start_scan_failed) {
- printk(MPT2SAS_INFO_FMT "port enable: FAILED with "
- "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed);
- ioc->is_driver_loading = 0;
- ioc->wait_for_discovery_to_complete = 0;
- ioc->remove_host = 1;
- return 1;
- }
-
- printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name);
- ioc->base_cmds.status = MPT2_CMD_NOT_USED;
-
- if (ioc->wait_for_discovery_to_complete) {
- ioc->wait_for_discovery_to_complete = 0;
- _scsih_probe_devices(ioc);
- }
- mpt2sas_base_start_watchdog(ioc);
- ioc->is_driver_loading = 0;
- return 1;
-}
-
-
-/**
- * _scsih_probe - attach and add scsi host
- * @pdev: PCI device struct
- * @id: pci device id
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct MPT2SAS_ADAPTER *ioc;
- struct Scsi_Host *shost;
- int rv;
-
- shost = scsi_host_alloc(&scsih_driver_template,
- sizeof(struct MPT2SAS_ADAPTER));
- if (!shost)
- return -ENODEV;
-
- /* init local params */
- ioc = shost_priv(shost);
- memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER));
- INIT_LIST_HEAD(&ioc->list);
- spin_lock(&gioc_lock);
- list_add_tail(&ioc->list, &mpt2sas_ioc_list);
- spin_unlock(&gioc_lock);
- ioc->shost = shost;
- ioc->id = mpt_ids++;
- sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id);
- ioc->pdev = pdev;
- if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) {
- ioc->is_warpdrive = 1;
- ioc->hide_ir_msg = 1;
- } else
- ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
- ioc->scsi_io_cb_idx = scsi_io_cb_idx;
- ioc->tm_cb_idx = tm_cb_idx;
- ioc->ctl_cb_idx = ctl_cb_idx;
- ioc->base_cb_idx = base_cb_idx;
- ioc->port_enable_cb_idx = port_enable_cb_idx;
- ioc->transport_cb_idx = transport_cb_idx;
- ioc->scsih_cb_idx = scsih_cb_idx;
- ioc->config_cb_idx = config_cb_idx;
- ioc->tm_tr_cb_idx = tm_tr_cb_idx;
- ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx;
- ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx;
- ioc->logging_level = logging_level;
- ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
- /* misc semaphores and spin locks */
- mutex_init(&ioc->reset_in_progress_mutex);
- /* initializing pci_access_mutex lock */
- mutex_init(&ioc->pci_access_mutex);
- spin_lock_init(&ioc->ioc_reset_in_progress_lock);
- spin_lock_init(&ioc->scsi_lookup_lock);
- spin_lock_init(&ioc->sas_device_lock);
- spin_lock_init(&ioc->sas_node_lock);
- spin_lock_init(&ioc->fw_event_lock);
- spin_lock_init(&ioc->raid_device_lock);
-
- INIT_LIST_HEAD(&ioc->sas_device_list);
- INIT_LIST_HEAD(&ioc->sas_device_init_list);
- INIT_LIST_HEAD(&ioc->sas_expander_list);
- INIT_LIST_HEAD(&ioc->fw_event_list);
- INIT_LIST_HEAD(&ioc->raid_device_list);
- INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
- INIT_LIST_HEAD(&ioc->delayed_tr_list);
- INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
- INIT_LIST_HEAD(&ioc->reply_queue_list);
-
- /* init shost parameters */
- shost->max_cmd_len = 32;
- shost->max_lun = max_lun;
- shost->transportt = mpt2sas_transport_template;
- shost->unique_id = ioc->id;
-
- if (max_sectors != 0xFFFF) {
- if (max_sectors < 64) {
- shost->max_sectors = 64;
- printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
- "for max_sectors, range is 64 to 32767. Assigning "
- "value of 64.\n", ioc->name, max_sectors);
- } else if (max_sectors > 32767) {
- shost->max_sectors = 32767;
- printk(MPT2SAS_WARN_FMT "Invalid value %d passed "
- "for max_sectors, range is 64 to 8192. Assigning "
- "default value of 32767.\n", ioc->name,
- max_sectors);
- } else {
- shost->max_sectors = max_sectors & 0xFFFE;
- printk(MPT2SAS_INFO_FMT "The max_sectors value is "
- "set to %d\n", ioc->name, shost->max_sectors);
- }
- }
-
- /* register EEDP capabilities with SCSI layer */
- if (prot_mask)
- scsi_host_set_prot(shost, prot_mask);
- else
- scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
- | SHOST_DIF_TYPE2_PROTECTION
- | SHOST_DIF_TYPE3_PROTECTION);
-
- scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
-
- /* event thread */
- snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
- "fw_event%d", ioc->id);
- ioc->firmware_event_thread = create_singlethread_workqueue(
- ioc->firmware_event_name);
- if (!ioc->firmware_event_thread) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rv = -ENODEV;
- goto out_thread_fail;
- }
-
- ioc->is_driver_loading = 1;
- if ((mpt2sas_base_attach(ioc))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rv = -ENODEV;
- goto out_attach_fail;
- }
-
- if (ioc->is_warpdrive) {
- if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
- ioc->hide_drives = 0;
- else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
- ioc->hide_drives = 1;
- else {
- if (_scsih_get_num_volumes(ioc))
- ioc->hide_drives = 1;
- else
- ioc->hide_drives = 0;
- }
- } else
- ioc->hide_drives = 0;
-
- rv = scsi_add_host(shost, &pdev->dev);
- if (rv) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_add_shost_fail;
- }
-
- scsi_scan_host(shost);
-
- return 0;
-
- out_add_shost_fail:
- mpt2sas_base_detach(ioc);
- out_attach_fail:
- destroy_workqueue(ioc->firmware_event_thread);
- out_thread_fail:
- spin_lock(&gioc_lock);
- list_del(&ioc->list);
- spin_unlock(&gioc_lock);
- scsi_host_put(shost);
- return rv;
-}
-
-#ifdef CONFIG_PM
-/**
- * _scsih_suspend - power management suspend main entry point
- * @pdev: PCI device struct
- * @state: PM state change to (usually PCI_D3)
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- pci_power_t device_state;
-
- mpt2sas_base_stop_watchdog(ioc);
- scsi_block_requests(shost);
- _scsih_ir_shutdown(ioc);
- device_state = pci_choose_state(pdev, state);
- printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering "
- "operating state [D%d]\n", ioc->name, pdev,
- pci_name(pdev), device_state);
-
- mpt2sas_base_free_resources(ioc);
- pci_save_state(pdev);
- pci_set_power_state(pdev, device_state);
- return 0;
-}
-
-/**
- * _scsih_resume - power management resume main entry point
- * @pdev: PCI device struct
- *
- * Returns 0 success, anything else error.
- */
-static int
-_scsih_resume(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- pci_power_t device_state = pdev->current_state;
- int r;
-
- printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous "
- "operating state [D%d]\n", ioc->name, pdev,
- pci_name(pdev), device_state);
-
- pci_set_power_state(pdev, PCI_D0);
- pci_enable_wake(pdev, PCI_D0, 0);
- pci_restore_state(pdev);
- ioc->pdev = pdev;
- r = mpt2sas_base_map_resources(ioc);
- if (r)
- return r;
-
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET);
- scsi_unblock_requests(shost);
- mpt2sas_base_start_watchdog(ioc);
- return 0;
-}
-#endif /* CONFIG_PM */
-
-/**
- * _scsih_pci_error_detected - Called when a PCI error is detected.
- * @pdev: PCI device struct
- * @state: PCI channel state
- *
- * Description: Called when a PCI error is detected.
- *
- * Return value:
- * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
- */
-static pci_ers_result_t
-_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n",
- ioc->name, state);
-
- switch (state) {
- case pci_channel_io_normal:
- return PCI_ERS_RESULT_CAN_RECOVER;
- case pci_channel_io_frozen:
- /* Fatal error, prepare for slot reset */
- ioc->pci_error_recovery = 1;
- scsi_block_requests(ioc->shost);
- mpt2sas_base_stop_watchdog(ioc);
- mpt2sas_base_free_resources(ioc);
- return PCI_ERS_RESULT_NEED_RESET;
- case pci_channel_io_perm_failure:
- /* Permanent error, prepare for device removal */
- ioc->pci_error_recovery = 1;
- mpt2sas_base_stop_watchdog(ioc);
- _scsih_flush_running_cmds(ioc);
- return PCI_ERS_RESULT_DISCONNECT;
- }
- return PCI_ERS_RESULT_NEED_RESET;
-}
-
-/**
- * _scsih_pci_slot_reset - Called when PCI slot has been reset.
- * @pdev: PCI device struct
- *
- * Description: This routine is called by the pci error recovery
- * code after the PCI slot has been reset, just before we
- * should resume normal operations.
- */
-static pci_ers_result_t
-_scsih_pci_slot_reset(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- int rc;
-
- printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n",
- ioc->name);
-
- ioc->pci_error_recovery = 0;
- ioc->pdev = pdev;
- pci_restore_state(pdev);
- rc = mpt2sas_base_map_resources(ioc);
- if (rc)
- return PCI_ERS_RESULT_DISCONNECT;
-
-
- rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
-
- printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name,
- (rc == 0) ? "success" : "failed");
-
- if (!rc)
- return PCI_ERS_RESULT_RECOVERED;
- else
- return PCI_ERS_RESULT_DISCONNECT;
-}
-
-/**
- * _scsih_pci_resume() - resume normal ops after PCI reset
- * @pdev: pointer to PCI device
- *
- * Called when the error recovery driver tells us that its
- * OK to resume normal operation. Use completion to allow
- * halted scsi ops to resume.
- */
-static void
-_scsih_pci_resume(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name);
-
- pci_cleanup_aer_uncorrect_error_status(pdev);
- mpt2sas_base_start_watchdog(ioc);
- scsi_unblock_requests(ioc->shost);
-}
-
-/**
- * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
- * @pdev: pointer to PCI device
- */
-static pci_ers_result_t
-_scsih_pci_mmio_enabled(struct pci_dev *pdev)
-{
- struct Scsi_Host *shost = pci_get_drvdata(pdev);
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
-
- printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n",
- ioc->name);
-
- /* TODO - dump whatever for debugging purposes */
-
- /* Request a slot reset. */
- return PCI_ERS_RESULT_NEED_RESET;
-}
-
-static const struct pci_error_handlers _scsih_err_handler = {
- .error_detected = _scsih_pci_error_detected,
- .mmio_enabled = _scsih_pci_mmio_enabled,
- .slot_reset = _scsih_pci_slot_reset,
- .resume = _scsih_pci_resume,
-};
-
-static struct pci_driver scsih_driver = {
- .name = MPT2SAS_DRIVER_NAME,
- .id_table = scsih_pci_table,
- .probe = _scsih_probe,
- .remove = _scsih_remove,
- .shutdown = _scsih_shutdown,
- .err_handler = &_scsih_err_handler,
-#ifdef CONFIG_PM
- .suspend = _scsih_suspend,
- .resume = _scsih_resume,
-#endif
-};
-
-/* raid transport support */
-static struct raid_function_template mpt2sas_raid_functions = {
- .cookie = &scsih_driver_template,
- .is_raid = _scsih_is_raid,
- .get_resync = _scsih_get_resync,
- .get_state = _scsih_get_state,
-};
-
-/**
- * _scsih_init - main entry point for this driver.
- *
- * Returns 0 success, anything else error.
- */
-static int __init
-_scsih_init(void)
-{
- int error;
-
- mpt_ids = 0;
- printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME,
- MPT2SAS_DRIVER_VERSION);
-
- mpt2sas_transport_template =
- sas_attach_transport(&mpt2sas_transport_functions);
- if (!mpt2sas_transport_template)
- return -ENODEV;
- /* raid transport support */
- mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions);
- if (!mpt2sas_raid_template) {
- sas_release_transport(mpt2sas_transport_template);
- return -ENODEV;
- }
-
- mpt2sas_base_initialize_callback_handler();
-
- /* queuecommand callback hander */
- scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done);
-
- /* task management callback handler */
- tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done);
-
- /* base internal commands callback handler */
- base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done);
- port_enable_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_port_enable_done);
-
- /* transport internal commands callback handler */
- transport_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_transport_done);
-
- /* scsih internal commands callback handler */
- scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done);
-
- /* configuration page API internal commands callback handler */
- config_cb_idx = mpt2sas_base_register_callback_handler(
- mpt2sas_config_done);
-
- /* ctl module callback handler */
- ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
-
- tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
- _scsih_tm_tr_complete);
-
- tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler(
- _scsih_tm_volume_tr_complete);
-
- tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
- _scsih_sas_control_complete);
-
- mpt2sas_ctl_init();
-
- error = pci_register_driver(&scsih_driver);
- if (error) {
- /* raid transport support */
- raid_class_release(mpt2sas_raid_template);
- sas_release_transport(mpt2sas_transport_template);
- }
-
- return error;
-}
-
-/**
- * _scsih_exit - exit point for this driver (when it is a module).
- *
- * Returns 0 success, anything else error.
- */
-static void __exit
-_scsih_exit(void)
-{
- printk(KERN_INFO "mpt2sas version %s unloading\n",
- MPT2SAS_DRIVER_VERSION);
-
- pci_unregister_driver(&scsih_driver);
-
- mpt2sas_ctl_exit();
-
- mpt2sas_base_release_callback_handler(scsi_io_cb_idx);
- mpt2sas_base_release_callback_handler(tm_cb_idx);
- mpt2sas_base_release_callback_handler(base_cb_idx);
- mpt2sas_base_release_callback_handler(port_enable_cb_idx);
- mpt2sas_base_release_callback_handler(transport_cb_idx);
- mpt2sas_base_release_callback_handler(scsih_cb_idx);
- mpt2sas_base_release_callback_handler(config_cb_idx);
- mpt2sas_base_release_callback_handler(ctl_cb_idx);
-
- mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
- mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx);
- mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
-
- /* raid transport support */
- raid_class_release(mpt2sas_raid_template);
- sas_release_transport(mpt2sas_transport_template);
-
-}
-
-module_init(_scsih_init);
-module_exit(_scsih_exit);
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
deleted file mode 100644
index af86800..0000000
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ /dev/null
@@ -1,2173 +0,0 @@
-/*
- * SAS Transport Layer for MPT (Message Passing Technology) based controllers
- *
- * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2014 LSI Corporation
- * Copyright (C) 20013-2014 Avago Technologies
- * (mailto: MPT-FusionLinux.pdl@avagotech.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * NO WARRANTY
- * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
- * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
- * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
- * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
- * solely responsible for determining the appropriateness of using and
- * distributing the Program and assumes all risks associated with its
- * exercise of rights under this Agreement, including but not limited to
- * the risks and costs of program errors, damage to or loss of data,
- * programs or equipment, and unavailability or interruption of operations.
-
- * DISCLAIMER OF LIABILITY
- * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
- * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/workqueue.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_transport_sas.h>
-#include <scsi/scsi_dbg.h>
-
-#include "mpt2sas_base.h"
-/**
- * _transport_sas_node_find_by_sas_address - sas node search
- * @ioc: per adapter object
- * @sas_address: sas address of expander or sas host
- * Context: Calling function should acquire ioc->sas_node_lock.
- *
- * Search for either hba phys or expander device based on handle, then returns
- * the sas_node object.
- */
-static struct _sas_node *
-_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address)
-{
- if (ioc->sas_hba.sas_address == sas_address)
- return &ioc->sas_hba;
- else
- return mpt2sas_scsih_expander_find_by_sas_address(ioc,
- sas_address);
-}
-
-/**
- * _transport_convert_phy_link_rate -
- * @link_rate: link rate returned from mpt firmware
- *
- * Convert link_rate from mpi fusion into sas_transport form.
- */
-static enum sas_linkrate
-_transport_convert_phy_link_rate(u8 link_rate)
-{
- enum sas_linkrate rc;
-
- switch (link_rate) {
- case MPI2_SAS_NEG_LINK_RATE_1_5:
- rc = SAS_LINK_RATE_1_5_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_3_0:
- rc = SAS_LINK_RATE_3_0_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_6_0:
- rc = SAS_LINK_RATE_6_0_GBPS;
- break;
- case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED:
- rc = SAS_PHY_DISABLED;
- break;
- case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
- rc = SAS_LINK_RATE_FAILED;
- break;
- case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR:
- rc = SAS_SATA_PORT_SELECTOR;
- break;
- case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
- rc = SAS_PHY_RESET_IN_PROGRESS;
- break;
- default:
- case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE:
- case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE:
- rc = SAS_LINK_RATE_UNKNOWN;
- break;
- }
- return rc;
-}
-
-/**
- * _transport_set_identify - set identify for phys and end devices
- * @ioc: per adapter object
- * @handle: device handle
- * @identify: sas identify info
- *
- * Populates sas identify info.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- struct sas_identify *identify)
-{
- Mpi2SasDevicePage0_t sas_device_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u32 device_info;
- u32 ioc_status;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
- MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
-
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)"
- "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status,
- __FILE__, __LINE__, __func__);
- return -EIO;
- }
-
- memset(identify, 0, sizeof(struct sas_identify));
- device_info = le32_to_cpu(sas_device_pg0.DeviceInfo);
-
- /* sas_address */
- identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
-
- /* phy number of the parent device this device is linked to */
- identify->phy_identifier = sas_device_pg0.PhyNum;
-
- /* device_type */
- switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
- case MPI2_SAS_DEVICE_INFO_NO_DEVICE:
- identify->device_type = SAS_PHY_UNUSED;
- break;
- case MPI2_SAS_DEVICE_INFO_END_DEVICE:
- identify->device_type = SAS_END_DEVICE;
- break;
- case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER:
- identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
- break;
- case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER:
- identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
- break;
- }
-
- /* initiator_port_protocols */
- if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
- if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST)
- identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
-
- /* target_port_protocols */
- if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_SSP;
- if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_STP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET)
- identify->target_port_protocols |= SAS_PROTOCOL_SMP;
- if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- identify->target_port_protocols |= SAS_PROTOCOL_SATA;
-
- return 0;
-}
-
-/**
- * mpt2sas_transport_done - internal transport layer callback handler.
- * @ioc: per adapter object
- * @smid: system request message index
- * @msix_index: MSIX table index supplied by the OS
- * @reply: reply message frame(lower 32bit addr)
- *
- * Callback handler when sending internal generated transport cmds.
- * The callback index passed is `ioc->transport_cb_idx`
- *
- * Return 1 meaning mf should be freed from _base_interrupt
- * 0 means the mf is freed from this function.
- */
-u8
-mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
- u32 reply)
-{
- MPI2DefaultReply_t *mpi_reply;
-
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
- if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED)
- return 1;
- if (ioc->transport_cmds.smid != smid)
- return 1;
- ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
- if (mpi_reply) {
- memcpy(ioc->transport_cmds.reply, mpi_reply,
- mpi_reply->MsgLength*4);
- ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID;
- }
- ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
- complete(&ioc->transport_cmds.done);
- return 1;
-}
-
-/* report manufacture request structure */
-struct rep_manu_request{
- u8 smp_frame_type;
- u8 function;
- u8 reserved;
- u8 request_length;
-};
-
-/* report manufacture reply structure */
-struct rep_manu_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x01 */
- u8 function_result;
- u8 response_length;
- u16 expander_change_count;
- u8 reserved0[2];
- u8 sas_format;
- u8 reserved2[3];
- u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
- u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
- u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
- u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
- u16 component_id;
- u8 component_revision_id;
- u8 reserved3;
- u8 vendor_specific[8];
-};
-
-/**
- * _transport_expander_report_manufacture - obtain SMP report_manufacture
- * @ioc: per adapter object
- * @sas_address: expander sas address
- * @edev: the sas_expander_device object
- *
- * Fills in the sas_expander_device object when SMP port is created.
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, struct sas_expander_device *edev)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct rep_manu_reply *manufacture_reply;
- struct rep_manu_request *manufacture_request;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- rc = 0;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
-
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- manufacture_request = data_out;
- manufacture_request->smp_frame_type = 0x40;
- manufacture_request->function = 1;
- manufacture_request->reserved = 0;
- manufacture_request->request_length = 0;
-
- memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
- mpi_request->PhysicalPort = 0xFF;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- mpi_request->SASAddress = cpu_to_le64(sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct rep_manu_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct rep_manu_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct rep_manu_reply), data_out_dma +
- sizeof(struct rep_manu_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
- "send to sas_addr(0x%016llx)\n", ioc->name,
- (unsigned long long)sas_address));
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
- u8 *tmp;
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "report_manufacture - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct rep_manu_reply))
- goto out;
-
- manufacture_reply = data_out + sizeof(struct rep_manu_request);
- strncpy(edev->vendor_id, manufacture_reply->vendor_id,
- SAS_EXPANDER_VENDOR_ID_LEN);
- strncpy(edev->product_id, manufacture_reply->product_id,
- SAS_EXPANDER_PRODUCT_ID_LEN);
- strncpy(edev->product_rev, manufacture_reply->product_rev,
- SAS_EXPANDER_PRODUCT_REV_LEN);
- edev->level = manufacture_reply->sas_format & 1;
- if (edev->level) {
- strncpy(edev->component_vendor_id,
- manufacture_reply->component_vendor_id,
- SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
- tmp = (u8 *)&manufacture_reply->component_id;
- edev->component_id = tmp[0] << 8 | tmp[1];
- edev->component_revision_id =
- manufacture_reply->component_revision_id;
- }
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "report_manufacture - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_delete_port - helper function to removing a port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- *
- * Returns nothing.
- */
-static void
-_transport_delete_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_port *mpt2sas_port)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
- enum sas_device_type device_type =
- mpt2sas_port->remote_identify.device_type;
-
- dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: sas_addr(0x%016llx)\n",
- (unsigned long long) sas_address);
-
- ioc->logging_level |= MPT_DEBUG_TRANSPORT;
- if (device_type == SAS_END_DEVICE)
- mpt2sas_device_remove_by_sas_address(ioc, sas_address);
- else if (device_type == SAS_EDGE_EXPANDER_DEVICE ||
- device_type == SAS_FANOUT_EXPANDER_DEVICE)
- mpt2sas_expander_remove(ioc, sas_address);
- ioc->logging_level &= ~MPT_DEBUG_TRANSPORT;
-}
-
-/**
- * _transport_delete_phy - helper function to removing single phy from port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
-
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "remove: sas_addr(0x%016llx), phy(%d)\n",
- (unsigned long long) sas_address, mpt2sas_phy->phy_id);
-
- list_del(&mpt2sas_phy->port_siblings);
- mpt2sas_port->num_phys--;
- sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 0;
-}
-
-/**
- * _transport_add_phy - helper function to adding single phy to port
- * @ioc: per adapter object
- * @mpt2sas_port: mpt2sas per port object
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port,
- struct _sas_phy *mpt2sas_phy)
-{
- u64 sas_address = mpt2sas_port->remote_identify.sas_address;
-
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long)
- sas_address, mpt2sas_phy->phy_id);
-
- list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list);
- mpt2sas_port->num_phys++;
- sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 1;
-}
-
-/**
- * _transport_add_phy_to_an_existing_port - adding new phy to existing port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @mpt2sas_phy: mpt2sas per phy object
- * @sas_address: sas address of device/expander were phy needs to be added to
- *
- * Returns nothing.
- */
-static void
-_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
-struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address)
-{
- struct _sas_port *mpt2sas_port;
- struct _sas_phy *phy_srch;
-
- if (mpt2sas_phy->phy_belongs_to_port == 1)
- return;
-
- list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list,
- port_list) {
- if (mpt2sas_port->remote_identify.sas_address !=
- sas_address)
- continue;
- list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
- port_siblings) {
- if (phy_srch == mpt2sas_phy)
- return;
- }
- _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy);
- return;
- }
-
-}
-
-/**
- * _transport_del_phy_from_an_existing_port - delete phy from existing port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @mpt2sas_phy: mpt2sas per phy object
- *
- * Returns nothing.
- */
-static void
-_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc,
- struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy)
-{
- struct _sas_port *mpt2sas_port, *next;
- struct _sas_phy *phy_srch;
-
- if (mpt2sas_phy->phy_belongs_to_port == 0)
- return;
-
- list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
- port_list) {
- list_for_each_entry(phy_srch, &mpt2sas_port->phy_list,
- port_siblings) {
- if (phy_srch != mpt2sas_phy)
- continue;
- if (mpt2sas_port->num_phys == 1)
- _transport_delete_port(ioc, mpt2sas_port);
- else
- _transport_delete_phy(ioc, mpt2sas_port,
- mpt2sas_phy);
- return;
- }
- }
-}
-
-/**
- * _transport_sanity_check - sanity check when adding a new port
- * @ioc: per adapter object
- * @sas_node: sas node object (either expander or sas host)
- * @sas_address: sas address of device being added
- *
- * See the explanation above from _transport_delete_duplicate_port
- */
-static void
-_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node,
- u64 sas_address)
-{
- int i;
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address != sas_address)
- continue;
- if (sas_node->phy[i].phy_belongs_to_port == 1)
- _transport_del_phy_from_an_existing_port(ioc, sas_node,
- &sas_node->phy[i]);
- }
-}
-
-/**
- * mpt2sas_transport_port_add - insert port to the list
- * @ioc: per adapter object
- * @handle: handle of attached device
- * @sas_address: sas address of parent expander or sas host
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Adding new port object to the sas_node->sas_port_list.
- *
- * Returns mpt2sas_port.
- */
-struct _sas_port *
-mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle,
- u64 sas_address)
-{
- struct _sas_phy *mpt2sas_phy, *next;
- struct _sas_port *mpt2sas_port;
- unsigned long flags;
- struct _sas_node *sas_node;
- struct sas_rphy *rphy;
- int i;
- struct sas_port *port;
-
- mpt2sas_port = kzalloc(sizeof(struct _sas_port),
- GFP_KERNEL);
- if (!mpt2sas_port) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return NULL;
- }
-
- INIT_LIST_HEAD(&mpt2sas_port->port_list);
- INIT_LIST_HEAD(&mpt2sas_port->phy_list);
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (!sas_node) {
- printk(MPT2SAS_ERR_FMT "%s: Could not find "
- "parent sas_address(0x%016llx)!\n", ioc->name,
- __func__, (unsigned long long)sas_address);
- goto out_fail;
- }
-
- if ((_transport_set_identify(ioc, handle,
- &mpt2sas_port->remote_identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- _transport_sanity_check(ioc, sas_node,
- mpt2sas_port->remote_identify.sas_address);
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address !=
- mpt2sas_port->remote_identify.sas_address)
- continue;
- list_add_tail(&sas_node->phy[i].port_siblings,
- &mpt2sas_port->phy_list);
- mpt2sas_port->num_phys++;
- }
-
- if (!mpt2sas_port->num_phys) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- port = sas_port_alloc_num(sas_node->parent_dev);
- if ((sas_port_add(port))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- goto out_fail;
- }
-
- list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list,
- port_siblings) {
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)"
- ", sas_addr(0x%016llx), phy(%d)\n", handle,
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_phy->phy_id);
- sas_port_add_phy(port, mpt2sas_phy->phy);
- mpt2sas_phy->phy_belongs_to_port = 1;
- }
-
- mpt2sas_port->port = port;
- if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE)
- rphy = sas_end_device_alloc(port);
- else
- rphy = sas_expander_alloc(port,
- mpt2sas_port->remote_identify.device_type);
-
- rphy->identify = mpt2sas_port->remote_identify;
- if ((sas_rphy_add(rphy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), "
- "sas_addr(0x%016llx)\n", handle,
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address);
- mpt2sas_port->rphy = rphy;
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list);
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* fill in report manufacture */
- if (mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER ||
- mpt2sas_port->remote_identify.device_type ==
- MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER)
- _transport_expander_report_manufacture(ioc,
- mpt2sas_port->remote_identify.sas_address,
- rphy_to_expander_device(rphy));
-
- return mpt2sas_port;
-
- out_fail:
- list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list,
- port_siblings)
- list_del(&mpt2sas_phy->port_siblings);
- kfree(mpt2sas_port);
- return NULL;
-}
-
-/**
- * mpt2sas_transport_port_remove - remove port from the list
- * @ioc: per adapter object
- * @sas_address: sas address of attached device
- * @sas_address_parent: sas address of parent expander or sas host
- * Context: This function will acquire ioc->sas_node_lock.
- *
- * Removing object and freeing associated memory from the
- * ioc->sas_port_list.
- *
- * Return nothing.
- */
-void
-mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
- u64 sas_address_parent)
-{
- int i;
- unsigned long flags;
- struct _sas_port *mpt2sas_port, *next;
- struct _sas_node *sas_node;
- u8 found = 0;
- struct _sas_phy *mpt2sas_phy, *next_phy;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc,
- sas_address_parent);
- if (!sas_node) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
- list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list,
- port_list) {
- if (mpt2sas_port->remote_identify.sas_address != sas_address)
- continue;
- found = 1;
- list_del(&mpt2sas_port->port_list);
- goto out;
- }
- out:
- if (!found) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
-
- for (i = 0; i < sas_node->num_phys; i++) {
- if (sas_node->phy[i].remote_identify.sas_address == sas_address)
- memset(&sas_node->phy[i].remote_identify, 0 ,
- sizeof(struct sas_identify));
- }
-
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- list_for_each_entry_safe(mpt2sas_phy, next_phy,
- &mpt2sas_port->phy_list, port_siblings) {
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &mpt2sas_port->port->dev,
- "remove: sas_addr(0x%016llx), phy(%d)\n",
- (unsigned long long)
- mpt2sas_port->remote_identify.sas_address,
- mpt2sas_phy->phy_id);
- mpt2sas_phy->phy_belongs_to_port = 0;
- sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy);
- list_del(&mpt2sas_phy->port_siblings);
- }
- sas_port_delete(mpt2sas_port->port);
- kfree(mpt2sas_port);
-}
-
-/**
- * mpt2sas_transport_add_host_phy - report sas_host phy to transport
- * @ioc: per adapter object
- * @mpt2sas_phy: mpt2sas per phy object
- * @phy_pg0: sas phy page 0
- * @parent_dev: parent device class object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev)
-{
- struct sas_phy *phy;
- int phy_index = mpt2sas_phy->phy_id;
-
-
- INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
- phy = sas_phy_alloc(parent_dev, phy_index);
- if (!phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
- &mpt2sas_phy->identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- phy->identify = mpt2sas_phy->identify;
- mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle);
- if (mpt2sas_phy->attached_handle)
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
- &mpt2sas_phy->remote_identify);
- phy->identify.phy_identifier = mpt2sas_phy->phy_id;
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
- phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
- phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
- phy_pg0.HwLinkRate >> 4);
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate >> 4);
-
- if ((sas_phy_add(phy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_phy_free(phy);
- return -1;
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &phy->dev,
- "add: handle(0x%04x), sas_addr(0x%016llx)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- mpt2sas_phy->handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address,
- mpt2sas_phy->attached_handle,
- (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
- mpt2sas_phy->phy = phy;
- return 0;
-}
-
-
-/**
- * mpt2sas_transport_add_expander_phy - report expander phy to transport
- * @ioc: per adapter object
- * @mpt2sas_phy: mpt2sas per phy object
- * @expander_pg1: expander page 1
- * @parent_dev: parent device class object
- *
- * Returns 0 for success, non-zero for failure.
- */
-int
-mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy
- *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev)
-{
- struct sas_phy *phy;
- int phy_index = mpt2sas_phy->phy_id;
-
- INIT_LIST_HEAD(&mpt2sas_phy->port_siblings);
- phy = sas_phy_alloc(parent_dev, phy_index);
- if (!phy) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- if ((_transport_set_identify(ioc, mpt2sas_phy->handle,
- &mpt2sas_phy->identify))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -1;
- }
- phy->identify = mpt2sas_phy->identify;
- mpt2sas_phy->attached_handle =
- le16_to_cpu(expander_pg1.AttachedDevHandle);
- if (mpt2sas_phy->attached_handle)
- _transport_set_identify(ioc, mpt2sas_phy->attached_handle,
- &mpt2sas_phy->remote_identify);
- phy->identify.phy_identifier = mpt2sas_phy->phy_id;
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.NegotiatedLinkRate &
- MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- phy->minimum_linkrate_hw = _transport_convert_phy_link_rate(
- expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK);
- phy->maximum_linkrate_hw = _transport_convert_phy_link_rate(
- expander_pg1.HwLinkRate >> 4);
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- expander_pg1.ProgrammedLinkRate >> 4);
-
- if ((sas_phy_add(phy))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- sas_phy_free(phy);
- return -1;
- }
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &phy->dev,
- "add: handle(0x%04x), sas_addr(0x%016llx)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- mpt2sas_phy->handle, (unsigned long long)
- mpt2sas_phy->identify.sas_address,
- mpt2sas_phy->attached_handle,
- (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
- mpt2sas_phy->phy = phy;
- return 0;
-}
-
-/**
- * mpt2sas_transport_update_links - refreshing phy link changes
- * @ioc: per adapter object
- * @sas_address: sas address of parent expander or sas host
- * @handle: attached device handle
- * @phy_numberv: phy number
- * @link_rate: new link rate
- *
- * Returns nothing.
- */
-void
-mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc,
- u64 sas_address, u16 handle, u8 phy_number, u8 link_rate)
-{
- unsigned long flags;
- struct _sas_node *sas_node;
- struct _sas_phy *mpt2sas_phy;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery)
- return;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address);
- if (!sas_node) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return;
- }
-
- mpt2sas_phy = &sas_node->phy[phy_number];
- mpt2sas_phy->attached_handle = handle;
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) {
- _transport_set_identify(ioc, handle,
- &mpt2sas_phy->remote_identify);
- _transport_add_phy_to_an_existing_port(ioc, sas_node,
- mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address);
- } else
- memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct
- sas_identify));
-
- if (mpt2sas_phy->phy)
- mpt2sas_phy->phy->negotiated_linkrate =
- _transport_convert_phy_link_rate(link_rate);
-
- if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
- dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev,
- "refresh: parent sas_addr(0x%016llx),\n"
- "\tlink_rate(0x%02x), phy(%d)\n"
- "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n",
- (unsigned long long)sas_address,
- link_rate, phy_number, handle, (unsigned long long)
- mpt2sas_phy->remote_identify.sas_address);
-}
-
-static inline void *
-phy_to_ioc(struct sas_phy *phy)
-{
- struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
- return shost_priv(shost);
-}
-
-static inline void *
-rphy_to_ioc(struct sas_rphy *rphy)
-{
- struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
- return shost_priv(shost);
-}
-
-
-/* report phy error log structure */
-struct phy_error_log_request{
- u8 smp_frame_type; /* 0x40 */
- u8 function; /* 0x11 */
- u8 allocated_response_length;
- u8 request_length; /* 02 */
- u8 reserved_1[5];
- u8 phy_identifier;
- u8 reserved_2[2];
-};
-
-/* report phy error log reply structure */
-struct phy_error_log_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x11 */
- u8 function_result;
- u8 response_length;
- __be16 expander_change_count;
- u8 reserved_1[3];
- u8 phy_identifier;
- u8 reserved_2[2];
- __be32 invalid_dword;
- __be32 running_disparity_error;
- __be32 loss_of_dword_sync;
- __be32 phy_reset_problem;
-};
-
-/**
- * _transport_get_expander_phy_error_log - return expander counters
- * @ioc: per adapter object
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc,
- struct sas_phy *phy)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct phy_error_log_request *phy_error_log_request;
- struct phy_error_log_reply *phy_error_log_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct phy_error_log_request) +
- sizeof(struct phy_error_log_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- rc = -EINVAL;
- memset(data_out, 0, sz);
- phy_error_log_request = data_out;
- phy_error_log_request->smp_frame_type = 0x40;
- phy_error_log_request->function = 0x11;
- phy_error_log_request->request_length = 2;
- phy_error_log_request->allocated_response_length = 0;
- phy_error_log_request->phy_identifier = phy->number;
-
- memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
- mpi_request->PhysicalPort = 0xFF;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct phy_error_log_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_error_log_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_error_log_reply), data_out_dma +
- sizeof(struct phy_error_log_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
- "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name,
- (unsigned long long)phy->identify.sas_address, phy->number));
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct phy_error_log_reply))
- goto out;
-
- phy_error_log_reply = data_out +
- sizeof(struct phy_error_log_request);
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - function_result(%d)\n",
- ioc->name, phy_error_log_reply->function_result));
-
- phy->invalid_dword_count =
- be32_to_cpu(phy_error_log_reply->invalid_dword);
- phy->running_disparity_error_count =
- be32_to_cpu(phy_error_log_reply->running_disparity_error);
- phy->loss_of_dword_sync_count =
- be32_to_cpu(phy_error_log_reply->loss_of_dword_sync);
- phy->phy_reset_problem_count =
- be32_to_cpu(phy_error_log_reply->phy_reset_problem);
- rc = 0;
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_error_log - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_get_linkerrors - return phy counters for both hba and expanders
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_get_linkerrors(struct sas_phy *phy)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- unsigned long flags;
- Mpi2ConfigReply_t mpi_reply;
- Mpi2SasPhyPage1_t phy_pg1;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_get_expander_phy_error_log(ioc, phy);
-
- /* get hba phy error logs */
- if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1,
- phy->number))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- phy->number, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
-
- phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount);
- phy->running_disparity_error_count =
- le32_to_cpu(phy_pg1.RunningDisparityErrorCount);
- phy->loss_of_dword_sync_count =
- le32_to_cpu(phy_pg1.LossDwordSynchCount);
- phy->phy_reset_problem_count =
- le32_to_cpu(phy_pg1.PhyResetProblemCount);
- return 0;
-}
-
-/**
- * _transport_get_enclosure_identifier -
- * @phy: The sas phy object
- *
- * Obtain the enclosure logical id for an expander.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
-{
- struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
- if (sas_device) {
- *identifier = sas_device->enclosure_logical_id;
- rc = 0;
- sas_device_put(sas_device);
- } else {
- *identifier = 0;
- rc = -ENXIO;
- }
-
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/**
- * _transport_get_bay_identifier -
- * @phy: The sas phy object
- *
- * Returns the slot id for a device that resides inside an enclosure.
- */
-static int
-_transport_get_bay_identifier(struct sas_rphy *rphy)
-{
- struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy);
- struct _sas_device *sas_device;
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = __mpt2sas_get_sdev_by_addr(ioc,
- rphy->identify.sas_address);
- if (sas_device) {
- rc = sas_device->slot;
- sas_device_put(sas_device);
- } else {
- rc = -ENXIO;
- }
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return rc;
-}
-
-/* phy control request structure */
-struct phy_control_request{
- u8 smp_frame_type; /* 0x40 */
- u8 function; /* 0x91 */
- u8 allocated_response_length;
- u8 request_length; /* 0x09 */
- u16 expander_change_count;
- u8 reserved_1[3];
- u8 phy_identifier;
- u8 phy_operation;
- u8 reserved_2[13];
- u64 attached_device_name;
- u8 programmed_min_physical_link_rate;
- u8 programmed_max_physical_link_rate;
- u8 reserved_3[6];
-};
-
-/* phy control reply structure */
-struct phy_control_reply{
- u8 smp_frame_type; /* 0x41 */
- u8 function; /* 0x11 */
- u8 function_result;
- u8 response_length;
-};
-
-#define SMP_PHY_CONTROL_LINK_RESET (0x01)
-#define SMP_PHY_CONTROL_HARD_RESET (0x02)
-#define SMP_PHY_CONTROL_DISABLE (0x03)
-
-/**
- * _transport_expander_phy_control - expander phy control
- * @ioc: per adapter object
- * @phy: The sas phy object
- *
- * Returns 0 for success, non-zero for failure.
- *
- */
-static int
-_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc,
- struct sas_phy *phy, u8 phy_operation)
-{
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- struct phy_control_request *phy_control_request;
- struct phy_control_reply *phy_control_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- void *data_out = NULL;
- dma_addr_t data_out_dma;
- u32 sz;
- u16 wait_state_count;
-
- if (ioc->shost_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- mutex_lock(&ioc->transport_cmds.mutex);
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto out;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto out;
- }
-
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- sz = sizeof(struct phy_control_request) +
- sizeof(struct phy_control_reply);
- data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma);
- if (!data_out) {
- printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__,
- __LINE__, __func__);
- rc = -ENOMEM;
- mpt2sas_base_free_smid(ioc, smid);
- goto out;
- }
-
- rc = -EINVAL;
- memset(data_out, 0, sz);
- phy_control_request = data_out;
- phy_control_request->smp_frame_type = 0x40;
- phy_control_request->function = 0x91;
- phy_control_request->request_length = 9;
- phy_control_request->allocated_response_length = 0;
- phy_control_request->phy_identifier = phy->number;
- phy_control_request->phy_operation = phy_operation;
- phy_control_request->programmed_min_physical_link_rate =
- phy->minimum_linkrate << 4;
- phy_control_request->programmed_max_physical_link_rate =
- phy->maximum_linkrate << 4;
-
- memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
- mpi_request->PhysicalPort = 0xFF;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address);
- mpi_request->RequestDataLength =
- cpu_to_le16(sizeof(struct phy_error_log_request));
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_request), data_out_dma);
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- ioc->base_add_sg_single(psge, sgl_flags |
- sizeof(struct phy_control_reply), data_out_dma +
- sizeof(struct phy_control_request));
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
- "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name,
- (unsigned long long)phy->identify.sas_address, phy->number,
- phy_operation));
-
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s: timeout\n",
- ioc->name, __func__);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - "
- "complete\n", ioc->name));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - reply data transfer size(%d)\n",
- ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- if (le16_to_cpu(mpi_reply->ResponseDataLength) !=
- sizeof(struct phy_control_reply))
- goto out;
-
- phy_control_reply = data_out +
- sizeof(struct phy_control_request);
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - function_result(%d)\n",
- ioc->name, phy_control_reply->function_result));
-
- rc = 0;
- } else
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "phy_control - no reply\n", ioc->name));
-
- issue_host_reset:
- if (issue_reset)
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- if (data_out)
- pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma);
-
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-/**
- * _transport_phy_reset -
- * @phy: The sas phy object
- * @hard_reset:
- *
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_reset(struct sas_phy *phy, int hard_reset)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIoUnitControlReply_t mpi_reply;
- Mpi2SasIoUnitControlRequest_t mpi_request;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_expander_phy_control(ioc, phy,
- (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET :
- SMP_PHY_CONTROL_LINK_RESET);
-
- /* handle hba phys */
- memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t));
- mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
- mpi_request.Operation = hard_reset ?
- MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET;
- mpi_request.PhyNum = phy->number;
-
- if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- return -ENXIO;
- }
-
- if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo)
- printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status"
- "(0x%04x), loginfo(0x%08x)\n", ioc->name,
- phy->number, le16_to_cpu(mpi_reply.IOCStatus),
- le32_to_cpu(mpi_reply.IOCLogInfo));
-
- return 0;
-}
-
-/**
- * _transport_phy_enable - enable/disable phys
- * @phy: The sas phy object
- * @enable: enable phy when true
- *
- * Only support sas_host direct attached phys.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_enable(struct sas_phy *phy, int enable)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 sz;
- int rc = 0;
- unsigned long flags;
- int i, discovery_active;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address)
- return _transport_expander_phy_control(ioc, phy,
- (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET :
- SMP_PHY_CONTROL_DISABLE);
-
- /* handle hba phys */
-
- /* read sas_iounit page 0 */
- sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit0PhyData_t));
- sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg0) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply,
- sas_iounit_pg0, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
-
- /* unable to enable/disable phys when when discovery is active */
- for (i = 0, discovery_active = 0; i < ioc->sas_hba.num_phys ; i++) {
- if (sas_iounit_pg0->PhyData[i].PortFlags &
- MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS) {
- printk(MPT2SAS_ERR_FMT "discovery is active on "
- "port = %d, phy = %d: unable to enable/disable "
- "phys, try again later!\n", ioc->name,
- sas_iounit_pg0->PhyData[i].Port, i);
- discovery_active = 1;
- }
- }
-
- if (discovery_active) {
- rc = -EAGAIN;
- goto out;
- }
-
- /* read sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
- /* copy Port/PortFlags/PhyFlags from page 0 */
- for (i = 0; i < ioc->sas_hba.num_phys ; i++) {
- sas_iounit_pg1->PhyData[i].Port =
- sas_iounit_pg0->PhyData[i].Port;
- sas_iounit_pg1->PhyData[i].PortFlags =
- (sas_iounit_pg0->PhyData[i].PortFlags &
- MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG);
- sas_iounit_pg1->PhyData[i].PhyFlags =
- (sas_iounit_pg0->PhyData[i].PhyFlags &
- (MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED +
- MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED));
- }
- if (enable)
- sas_iounit_pg1->PhyData[phy->number].PhyFlags
- &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
- else
- sas_iounit_pg1->PhyData[phy->number].PhyFlags
- |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE;
-
- mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz);
-
- /* link reset */
- if (enable)
- _transport_phy_reset(phy, 0);
-
- out:
- kfree(sas_iounit_pg1);
- kfree(sas_iounit_pg0);
- return rc;
-}
-
-/**
- * _transport_phy_speed - set phy min/max link rates
- * @phy: The sas phy object
- * @rates: rates defined in sas_phy_linkrates
- *
- * Only support sas_host direct attached phys.
- * Returns 0 for success, non-zero for failure.
- */
-static int
-_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates)
-{
- struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy);
- Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL;
- Mpi2SasPhyPage0_t phy_pg0;
- Mpi2ConfigReply_t mpi_reply;
- u16 ioc_status;
- u16 sz;
- int i;
- int rc = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->sas_node_lock, flags);
- if (_transport_sas_node_find_by_sas_address(ioc,
- phy->identify.sas_address) == NULL) {
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
- return -EINVAL;
- }
- spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
-
- if (!rates->minimum_linkrate)
- rates->minimum_linkrate = phy->minimum_linkrate;
- else if (rates->minimum_linkrate < phy->minimum_linkrate_hw)
- rates->minimum_linkrate = phy->minimum_linkrate_hw;
-
- if (!rates->maximum_linkrate)
- rates->maximum_linkrate = phy->maximum_linkrate;
- else if (rates->maximum_linkrate > phy->maximum_linkrate_hw)
- rates->maximum_linkrate = phy->maximum_linkrate_hw;
-
- /* handle expander phys */
- if (phy->identify.sas_address != ioc->sas_hba.sas_address) {
- phy->minimum_linkrate = rates->minimum_linkrate;
- phy->maximum_linkrate = rates->maximum_linkrate;
- return _transport_expander_phy_control(ioc, phy,
- SMP_PHY_CONTROL_LINK_RESET);
- }
-
- /* handle hba phys */
-
- /* sas_iounit page 1 */
- sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys *
- sizeof(Mpi2SasIOUnit1PhyData_t));
- sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL);
- if (!sas_iounit_pg1) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENOMEM;
- goto out;
- }
- if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply,
- sas_iounit_pg1, sz))) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
- ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
- MPI2_IOCSTATUS_MASK;
- if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -EIO;
- goto out;
- }
-
- for (i = 0; i < ioc->sas_hba.num_phys; i++) {
- if (phy->number != i) {
- sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
- (ioc->sas_hba.phy[i].phy->minimum_linkrate +
- (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4));
- } else {
- sas_iounit_pg1->PhyData[i].MaxMinLinkRate =
- (rates->minimum_linkrate +
- (rates->maximum_linkrate << 4));
- }
- }
-
- if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1,
- sz)) {
- printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
- ioc->name, __FILE__, __LINE__, __func__);
- rc = -ENXIO;
- goto out;
- }
-
- /* link reset */
- _transport_phy_reset(phy, 0);
-
- /* read phy page 0, then update the rates in the sas transport phy */
- if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0,
- phy->number)) {
- phy->minimum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK);
- phy->maximum_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.ProgrammedLinkRate >> 4);
- phy->negotiated_linkrate = _transport_convert_phy_link_rate(
- phy_pg0.NegotiatedLinkRate &
- MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL);
- }
-
- out:
- kfree(sas_iounit_pg1);
- return rc;
-}
-
-
-/**
- * _transport_smp_handler - transport portal for smp passthru
- * @shost: shost object
- * @rphy: sas transport rphy object
- * @req:
- *
- * This used primarily for smp_utils.
- * Example:
- * smp_rep_general /sys/class/bsg/expander-5:0
- */
-static int
-_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
- struct request *req)
-{
- struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
- Mpi2SmpPassthroughRequest_t *mpi_request;
- Mpi2SmpPassthroughReply_t *mpi_reply;
- int rc;
- u16 smid;
- u32 ioc_state;
- unsigned long timeleft;
- void *psge;
- u32 sgl_flags;
- u8 issue_reset = 0;
- dma_addr_t dma_addr_in = 0;
- dma_addr_t dma_addr_out = 0;
- dma_addr_t pci_dma_in = 0;
- dma_addr_t pci_dma_out = 0;
- void *pci_addr_in = NULL;
- void *pci_addr_out = NULL;
- u16 wait_state_count;
- struct request *rsp = req->next_rq;
- struct bio_vec bvec;
- struct bvec_iter iter;
-
- if (!rsp) {
- printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
- "missing\n", ioc->name, __func__);
- return -EINVAL;
- }
- if (ioc->shost_recovery || ioc->pci_error_recovery) {
- printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
- __func__, ioc->name);
- return -EFAULT;
- }
-
- rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex);
- if (rc)
- return rc;
-
- if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) {
- printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name,
- __func__);
- rc = -EAGAIN;
- goto out;
- }
- ioc->transport_cmds.status = MPT2_CMD_PENDING;
-
- /* Check if the request is split across multiple segments */
- if (bio_multiple_segments(req->bio)) {
- u32 offset = 0;
-
- /* Allocate memory and copy the request */
- pci_addr_out = pci_alloc_consistent(ioc->pdev,
- blk_rq_bytes(req), &pci_dma_out);
- if (!pci_addr_out) {
- printk(MPT2SAS_INFO_FMT "%s(): PCI Addr out = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto out;
- }
-
- bio_for_each_segment(bvec, req->bio, iter) {
- memcpy(pci_addr_out + offset,
- page_address(bvec.bv_page) + bvec.bv_offset,
- bvec.bv_len);
- offset += bvec.bv_len;
- }
- } else {
- dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
- blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_out) {
- printk(MPT2SAS_INFO_FMT "%s(): DMA Addr out = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto free_pci;
- }
- }
-
- /* Check if the response needs to be populated across
- * multiple segments */
- if (bio_multiple_segments(rsp->bio)) {
- pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
- &pci_dma_in);
- if (!pci_addr_in) {
- printk(MPT2SAS_INFO_FMT "%s(): PCI Addr in = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto unmap;
- }
- } else {
- dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio),
- blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
- if (!dma_addr_in) {
- printk(MPT2SAS_INFO_FMT "%s(): DMA Addr in = NULL\n",
- ioc->name, __func__);
- rc = -ENOMEM;
- goto unmap;
- }
- }
-
- wait_state_count = 0;
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) {
- if (wait_state_count++ == 10) {
- printk(MPT2SAS_ERR_FMT
- "%s: failed due to ioc not operational\n",
- ioc->name, __func__);
- rc = -EFAULT;
- goto unmap;
- }
- ssleep(1);
- ioc_state = mpt2sas_base_get_iocstate(ioc, 1);
- printk(MPT2SAS_INFO_FMT "%s: waiting for "
- "operational state(count=%d)\n", ioc->name,
- __func__, wait_state_count);
- }
- if (wait_state_count)
- printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
- ioc->name, __func__);
-
- smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx);
- if (!smid) {
- printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
- ioc->name, __func__);
- rc = -EAGAIN;
- goto unmap;
- }
-
- rc = 0;
- mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
- ioc->transport_cmds.smid = smid;
-
- memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
- mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
- mpi_request->PhysicalPort = 0xFF;
- mpi_request->VF_ID = 0; /* TODO */
- mpi_request->VP_ID = 0;
- mpi_request->SASAddress = (rphy) ?
- cpu_to_le64(rphy->identify.sas_address) :
- cpu_to_le64(ioc->sas_hba.sas_address);
- mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
- psge = &mpi_request->SGL;
-
- /* WRITE sgel first */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- if (bio_multiple_segments(req->bio)) {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(req) - 4), pci_dma_out);
- } else {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(req) - 4), dma_addr_out);
- }
-
- /* incr sgel */
- psge += ioc->sge_size;
-
- /* READ sgel last */
- sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
- MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
- MPI2_SGE_FLAGS_END_OF_LIST);
- sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
- if (bio_multiple_segments(rsp->bio)) {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(rsp) + 4), pci_dma_in);
- } else {
- ioc->base_add_sg_single(psge, sgl_flags |
- (blk_rq_bytes(rsp) + 4), dma_addr_in);
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
- "sending smp request\n", ioc->name, __func__));
-
- init_completion(&ioc->transport_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid);
- timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
- 10*HZ);
-
- if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) {
- printk(MPT2SAS_ERR_FMT "%s : timeout\n",
- __func__, ioc->name);
- _debug_dump_mf(mpi_request,
- sizeof(Mpi2SmpPassthroughRequest_t)/4);
- if (!(ioc->transport_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
- goto issue_host_reset;
- }
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - "
- "complete\n", ioc->name, __func__));
-
- if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) {
-
- mpi_reply = ioc->transport_cmds.reply;
-
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - reply data transfer size(%d)\n",
- ioc->name, __func__,
- le16_to_cpu(mpi_reply->ResponseDataLength)));
-
- memcpy(req->sense, mpi_reply, sizeof(*mpi_reply));
- req->sense_len = sizeof(*mpi_reply);
- req->resid_len = 0;
- rsp->resid_len -=
- le16_to_cpu(mpi_reply->ResponseDataLength);
- /* check if the resp needs to be copied from the allocated
- * pci mem */
- if (bio_multiple_segments(rsp->bio)) {
- u32 offset = 0;
- u32 bytes_to_copy =
- le16_to_cpu(mpi_reply->ResponseDataLength);
- bio_for_each_segment(bvec, rsp->bio, iter) {
- if (bytes_to_copy <= bvec.bv_len) {
- memcpy(page_address(bvec.bv_page) +
- bvec.bv_offset, pci_addr_in +
- offset, bytes_to_copy);
- break;
- } else {
- memcpy(page_address(bvec.bv_page) +
- bvec.bv_offset, pci_addr_in +
- offset, bvec.bv_len);
- bytes_to_copy -= bvec.bv_len;
- }
- offset += bvec.bv_len;
- }
- }
- } else {
- dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT
- "%s - no reply\n", ioc->name, __func__));
- rc = -ENXIO;
- }
-
- issue_host_reset:
- if (issue_reset) {
- mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
- FORCE_BIG_HAMMER);
- rc = -ETIMEDOUT;
- }
-
- unmap:
- if (dma_addr_out)
- pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req),
- PCI_DMA_BIDIRECTIONAL);
- if (dma_addr_in)
- pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp),
- PCI_DMA_BIDIRECTIONAL);
-
- free_pci:
- if (pci_addr_out)
- pci_free_consistent(ioc->pdev, blk_rq_bytes(req), pci_addr_out,
- pci_dma_out);
-
- if (pci_addr_in)
- pci_free_consistent(ioc->pdev, blk_rq_bytes(rsp), pci_addr_in,
- pci_dma_in);
-
- out:
- ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
- mutex_unlock(&ioc->transport_cmds.mutex);
- return rc;
-}
-
-struct sas_function_template mpt2sas_transport_functions = {
- .get_linkerrors = _transport_get_linkerrors,
- .get_enclosure_identifier = _transport_get_enclosure_identifier,
- .get_bay_identifier = _transport_get_bay_identifier,
- .phy_reset = _transport_phy_reset,
- .phy_enable = _transport_phy_enable,
- .set_phy_speed = _transport_phy_speed,
- .smp_handler = _transport_smp_handler,
-};
-
-struct scsi_transport_template *mpt2sas_transport_template;
diff --git a/drivers/scsi/mpt3sas/Kconfig b/drivers/scsi/mpt3sas/Kconfig
index 4d235dd..b736dbc 100644
--- a/drivers/scsi/mpt3sas/Kconfig
+++ b/drivers/scsi/mpt3sas/Kconfig
@@ -41,15 +41,15 @@
# USA.
config SCSI_MPT3SAS
- tristate "LSI MPT Fusion SAS 3.0 Device Driver"
+ tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver"
depends on PCI && SCSI
select SCSI_SAS_ATTRS
select RAID_ATTRS
---help---
This driver supports PCI-Express SAS 12Gb/s Host Adapters.
-config SCSI_MPT3SAS_MAX_SGE
- int "LSI MPT Fusion Max number of SG Entries (16 - 256)"
+config SCSI_MPT2SAS_MAX_SGE
+ int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)"
depends on PCI && SCSI && SCSI_MPT3SAS
default "128"
range 16 256
@@ -60,8 +60,23 @@ config SCSI_MPT3SAS_MAX_SGE
can be 256. However, it may decreased down to 16. Decreasing this
parameter will reduce memory requirements on a per controller instance.
-config SCSI_MPT3SAS_LOGGING
- bool "LSI MPT Fusion logging facility"
+config SCSI_MPT3SAS_MAX_SGE
+ int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)"
depends on PCI && SCSI && SCSI_MPT3SAS
+ default "128"
+ range 16 256
+ ---help---
+ This option allows you to specify the maximum number of scatter-
+ gather entries per I/O. The driver default is 128, which matches
+ MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this
+ can be 256. However, it may decreased down to 16. Decreasing this
+ parameter will reduce memory requirements on a per controller instance.
+
+config SCSI_MPT2SAS
+ tristate "Legacy MPT2SAS config option"
+ default n
+ select SCSI_MPT3SAS
+ depends on PCI && SCSI
---help---
- This turns on a logging facility.
+ Dummy config option for backwards compatiblity: configure the MPT3SAS
+ driver instead.
diff --git a/drivers/scsi/mpt3sas/Makefile b/drivers/scsi/mpt3sas/Makefile
index efb0c4c..b7643f5 100644
--- a/drivers/scsi/mpt3sas/Makefile
+++ b/drivers/scsi/mpt3sas/Makefile
@@ -5,4 +5,5 @@ mpt3sas-y += mpt3sas_base.o \
mpt3sas_scsih.o \
mpt3sas_transport.o \
mpt3sas_ctl.o \
- mpt3sas_trigger_diag.o
+ mpt3sas_trigger_diag.o \
+ mpt3sas_warpdrive.o
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index d4f1dcd..11393eb 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -108,9 +108,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp)
if (ret)
return ret;
+ /* global ioc spinlock to protect controller list on list operations */
pr_info("setting fwfault_debug(%d)\n", mpt3sas_fwfault_debug);
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
ioc->fwfault_debug = mpt3sas_fwfault_debug;
+ spin_unlock(&gioc_lock);
return 0;
}
module_param_call(mpt3sas_fwfault_debug, _scsih_set_fwfault_debug,
@@ -157,7 +160,7 @@ _base_fault_reset_work(struct work_struct *work)
spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags);
- if (ioc->shost_recovery)
+ if (ioc->shost_recovery || ioc->pci_error_recovery)
goto rearm_timer;
spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags);
@@ -166,6 +169,20 @@ _base_fault_reset_work(struct work_struct *work)
pr_err(MPT3SAS_FMT "SAS host is non-operational !!!!\n",
ioc->name);
+ /* It may be possible that EEH recovery can resolve some of
+ * pci bus failure issues rather removing the dead ioc function
+ * by considering controller is in a non-operational state. So
+ * here priority is given to the EEH recovery. If it doesn't
+ * not resolve this issue, mpt3sas driver will consider this
+ * controller to non-operational state and remove the dead ioc
+ * function.
+ */
+ if (ioc->non_operational_loop++ < 5) {
+ spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock,
+ flags);
+ goto rearm_timer;
+ }
+
/*
* Call _scsih_flush_pending_cmds callback so that we flush all
* pending commands back to OS. This call is required to aovid
@@ -181,7 +198,7 @@ _base_fault_reset_work(struct work_struct *work)
ioc->remove_host = 1;
/*Remove the Dead Host */
p = kthread_run(mpt3sas_remove_dead_ioc_func, ioc,
- "mpt3sas_dead_ioc_%d", ioc->id);
+ "%s_dead_ioc_%d", ioc->driver_name, ioc->id);
if (IS_ERR(p))
pr_err(MPT3SAS_FMT
"%s: Running mpt3sas_dead_ioc thread failed !!!!\n",
@@ -193,6 +210,8 @@ _base_fault_reset_work(struct work_struct *work)
return; /* don't rearm timer */
}
+ ioc->non_operational_loop = 0;
+
if ((doorbell & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) {
rc = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
@@ -235,7 +254,8 @@ mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc)
INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work);
snprintf(ioc->fault_reset_work_q_name,
- sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id);
+ sizeof(ioc->fault_reset_work_q_name), "poll_%s%d_status",
+ ioc->driver_name, ioc->id);
ioc->fault_reset_work_q =
create_singlethread_workqueue(ioc->fault_reset_work_q_name);
if (!ioc->fault_reset_work_q) {
@@ -324,7 +344,6 @@ mpt3sas_halt_firmware(struct MPT3SAS_ADAPTER *ioc)
panic("panic in %s\n", __func__);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _base_sas_ioc_info - verbose translation of the ioc status
* @ioc: per adapter object
@@ -578,7 +597,8 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
desc = "Device Status Change";
break;
case MPI2_EVENT_IR_OPERATION_STATUS:
- desc = "IR Operation Status";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Operation Status";
break;
case MPI2_EVENT_SAS_DISCOVERY:
{
@@ -609,16 +629,20 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
desc = "SAS Enclosure Device Status Change";
break;
case MPI2_EVENT_IR_VOLUME:
- desc = "IR Volume";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Volume";
break;
case MPI2_EVENT_IR_PHYSICAL_DISK:
- desc = "IR Physical Disk";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Physical Disk";
break;
case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- desc = "IR Configuration Change List";
+ if (!ioc->hide_ir_msg)
+ desc = "IR Configuration Change List";
break;
case MPI2_EVENT_LOG_ENTRY_ADDED:
- desc = "Log Entry Added";
+ if (!ioc->hide_ir_msg)
+ desc = "Log Entry Added";
break;
case MPI2_EVENT_TEMP_THRESHOLD:
desc = "Temperature Threshold";
@@ -630,7 +654,6 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
pr_info(MPT3SAS_FMT "%s\n", ioc->name, desc);
}
-#endif
/**
* _base_sas_log_info - verbose translation of firmware log info
@@ -675,7 +698,10 @@ _base_sas_log_info(struct MPT3SAS_ADAPTER *ioc , u32 log_info)
originator_str = "PL";
break;
case 2:
- originator_str = "IR";
+ if (!ioc->hide_ir_msg)
+ originator_str = "IR";
+ else
+ originator_str = "WarpDrive";
break;
}
@@ -710,13 +736,13 @@ _base_display_reply_info(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
return;
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
if ((ioc_status & MPI2_IOCSTATUS_MASK) &&
(ioc->logging_level & MPT_DEBUG_REPLY)) {
_base_sas_ioc_info(ioc , mpi_reply,
mpt3sas_base_get_msg_frame(ioc, smid));
}
-#endif
+
if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) {
loginfo = le32_to_cpu(mpi_reply->IOCLogInfo);
_base_sas_log_info(ioc, loginfo);
@@ -783,9 +809,9 @@ _base_async_event(struct MPT3SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
return 1;
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
return 1;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
_base_display_event_data(ioc, mpi_reply);
-#endif
+
if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED))
goto out;
smid = mpt3sas_base_get_smid(ioc, ioc->base_cb_idx);
@@ -1009,6 +1035,12 @@ _base_interrupt(int irq, void *bus_id)
}
wmb();
+ if (ioc->is_warpdrive) {
+ writel(reply_q->reply_post_host_index,
+ ioc->reply_post_host_index[msix_index]);
+ atomic_dec(&reply_q->busy);
+ return IRQ_HANDLED;
+ }
/* Update Reply Post Host Index.
* For those HBA's which support combined reply queue feature
@@ -1320,6 +1352,149 @@ _base_build_zero_len_sge_ieee(struct MPT3SAS_ADAPTER *ioc, void *paddr)
}
/**
+ * _base_build_sg_scmd - main sg creation routine
+ * @ioc: per adapter object
+ * @scmd: scsi command
+ * @smid: system request message index
+ * Context: none.
+ *
+ * The main routine that builds scatter gather table from a given
+ * scsi request sent via the .queuecommand main handler.
+ *
+ * Returns 0 success, anything else error
+ */
+static int
+_base_build_sg_scmd(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_cmnd *scmd, u16 smid)
+{
+ Mpi2SCSIIORequest_t *mpi_request;
+ dma_addr_t chain_dma;
+ struct scatterlist *sg_scmd;
+ void *sg_local, *chain;
+ u32 chain_offset;
+ u32 chain_length;
+ u32 chain_flags;
+ int sges_left;
+ u32 sges_in_segment;
+ u32 sgl_flags;
+ u32 sgl_flags_last_element;
+ u32 sgl_flags_end_buffer;
+ struct chain_tracker *chain_req;
+
+ mpi_request = mpt3sas_base_get_msg_frame(ioc, smid);
+
+ /* init scatter gather flags */
+ sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT;
+ if (scmd->sc_data_direction == DMA_TO_DEVICE)
+ sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC;
+ sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT)
+ << MPI2_SGE_FLAGS_SHIFT;
+ sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT |
+ MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST)
+ << MPI2_SGE_FLAGS_SHIFT;
+ sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
+
+ sg_scmd = scsi_sglist(scmd);
+ sges_left = scsi_dma_map(scmd);
+ if (sges_left < 0) {
+ sdev_printk(KERN_ERR, scmd->device,
+ "pci_map_sg failed: request for %d bytes!\n",
+ scsi_bufflen(scmd));
+ return -ENOMEM;
+ }
+
+ sg_local = &mpi_request->SGL;
+ sges_in_segment = ioc->max_sges_in_main_message;
+ if (sges_left <= sges_in_segment)
+ goto fill_in_last_segment;
+
+ mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) +
+ (sges_in_segment * ioc->sge_size))/4;
+
+ /* fill in main message segment when there is a chain following */
+ while (sges_in_segment) {
+ if (sges_in_segment == 1)
+ ioc->base_add_sg_single(sg_local,
+ sgl_flags_last_element | sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ sges_in_segment--;
+ }
+
+ /* initializing the chain flags and pointers */
+ chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT;
+ chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
+ do {
+ sges_in_segment = (sges_left <=
+ ioc->max_sges_in_chain_message) ? sges_left :
+ ioc->max_sges_in_chain_message;
+ chain_offset = (sges_left == sges_in_segment) ?
+ 0 : (sges_in_segment * ioc->sge_size)/4;
+ chain_length = sges_in_segment * ioc->sge_size;
+ if (chain_offset) {
+ chain_offset = chain_offset <<
+ MPI2_SGE_CHAIN_OFFSET_SHIFT;
+ chain_length += ioc->sge_size;
+ }
+ ioc->base_add_sg_single(sg_local, chain_flags | chain_offset |
+ chain_length, chain_dma);
+ sg_local = chain;
+ if (!chain_offset)
+ goto fill_in_last_segment;
+
+ /* fill in chain segments */
+ while (sges_in_segment) {
+ if (sges_in_segment == 1)
+ ioc->base_add_sg_single(sg_local,
+ sgl_flags_last_element |
+ sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd),
+ sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ sges_in_segment--;
+ }
+
+ chain_req = _base_get_chain_buffer_tracker(ioc, smid);
+ if (!chain_req)
+ return -1;
+ chain = chain_req->chain_buffer;
+ chain_dma = chain_req->chain_buffer_dma;
+ } while (1);
+
+
+ fill_in_last_segment:
+
+ /* fill the last segment */
+ while (sges_left) {
+ if (sges_left == 1)
+ ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ else
+ ioc->base_add_sg_single(sg_local, sgl_flags |
+ sg_dma_len(sg_scmd), sg_dma_address(sg_scmd));
+ sg_scmd = sg_next(sg_scmd);
+ sg_local += ioc->sge_size;
+ sges_left--;
+ }
+
+ return 0;
+}
+
+/**
* _base_build_sg_scmd_ieee - main sg creation routine for IEEE format
* @ioc: per adapter object
* @scmd: scsi command
@@ -1571,6 +1746,14 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
int base;
u16 message_control;
+ /* Check whether controller SAS2008 B0 controller,
+ * if it is SAS2008 B0 controller use IO-APIC instead of MSIX
+ */
+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 &&
+ ioc->pdev->revision == SAS2_PCI_DEVICE_B0_REVISION) {
+ return -EINVAL;
+ }
+
base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX);
if (!base) {
dfailprintk(ioc, pr_info(MPT3SAS_FMT "msix not supported\n",
@@ -1579,9 +1762,19 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc)
}
/* get msix vector count */
-
- pci_read_config_word(ioc->pdev, base + 2, &message_control);
- ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+ /* NUMA_IO not supported for older controllers */
+ if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 ||
+ ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2)
+ ioc->msix_vector_count = 1;
+ else {
+ pci_read_config_word(ioc->pdev, base + 2, &message_control);
+ ioc->msix_vector_count = (message_control & 0x3FF) + 1;
+ }
dinitprintk(ioc, pr_info(MPT3SAS_FMT
"msix is supported, vector_count(%d)\n",
ioc->name, ioc->msix_vector_count));
@@ -1643,10 +1836,10 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
atomic_set(&reply_q->busy, 0);
if (ioc->msix_enable)
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
- MPT3SAS_DRIVER_NAME, ioc->id, index);
+ ioc->driver_name, ioc->id, index);
else
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d",
- MPT3SAS_DRIVER_NAME, ioc->id);
+ ioc->driver_name, ioc->id);
r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name,
reply_q);
if (r) {
@@ -1872,7 +2065,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc)
if (pci_request_selected_regions(pdev, ioc->bars,
- MPT3SAS_DRIVER_NAME)) {
+ ioc->driver_name)) {
pr_warn(MPT3SAS_FMT "pci_request_selected_regions: failed\n",
ioc->name);
ioc->bars = 0;
@@ -2158,6 +2351,7 @@ mpt3sas_base_free_smid(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].scmd = NULL;
+ ioc->scsi_lookup[i].direct_io = 0;
list_add(&ioc->scsi_lookup[i].tracker_list, &ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -2318,143 +2512,261 @@ mpt3sas_base_put_smid_default(struct MPT3SAS_ADAPTER *ioc, u16 smid)
}
/**
- * _base_display_intel_branding - Display branding string
+ * _base_display_OEMs_branding - Display branding string
* @ioc: per adapter object
*
* Return nothing.
*/
static void
-_base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc)
+_base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc)
{
if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL)
return;
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_INTEL_RMS3JC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RMS3JC080_BRANDING);
- break;
-
- case MPT3SAS_INTEL_RS3GC008_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3GC008_BRANDING);
- break;
- case MPT3SAS_INTEL_RS3FC044_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3FC044_BRANDING);
- break;
- case MPT3SAS_INTEL_RS3UC080_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_INTEL_RS3UC080_BRANDING);
+ switch (ioc->pdev->subsystem_vendor) {
+ case PCI_VENDOR_ID_INTEL:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RMS2LL080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS2LL040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS2LL040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_SSD910_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_SSD910_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_INTEL_RS25GB008_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RS25GB008_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25JB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25JB080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25JB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25JB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25KB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25KB080_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25KB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25KB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25LB040_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25LB040_BRANDING);
+ break;
+ case MPT2SAS_INTEL_RMS25LB080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_INTEL_RMS25LB080_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_INTEL_RMS3JC080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RMS3JC080_BRANDING);
+ break;
+
+ case MPT3SAS_INTEL_RS3GC008_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3GC008_BRANDING);
+ break;
+ case MPT3SAS_INTEL_RS3FC044_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3FC044_BRANDING);
+ break;
+ case MPT3SAS_INTEL_RS3UC080_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_INTEL_RS3UC080_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "Intel(R) Controller: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
break;
- default:
- pr_info(MPT3SAS_FMT
- "Intel(R) Controller: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
- break;
- }
-}
-
-
-
-/**
- * _base_display_dell_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL)
- return;
-
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_DELL_12G_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_DELL_12G_HBA_BRANDING);
+ case PCI_VENDOR_ID_DELL:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING);
+ break;
+ case MPT2SAS_DELL_PERC_H200_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_PERC_H200_BRANDING);
+ break;
+ case MPT2SAS_DELL_6GBPS_SAS_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_DELL_6GBPS_SAS_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Dell 6Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ break;
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_DELL_12G_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_DELL_12G_HBA_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Dell 12Gbps HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
+ "Dell HBA: Subsystem ID: 0x%X\n", ioc->name,
ioc->pdev->subsystem_device);
break;
}
break;
- default:
- pr_info(MPT3SAS_FMT
- "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name,
- ioc->pdev->subsystem_device);
- break;
- }
-}
-
-/**
- * _base_display_cisco_branding - Display branding string
- * @ioc: per adapter object
- *
- * Return nothing.
- */
-static void
-_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc)
-{
- if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO)
- return;
-
- switch (ioc->pdev->device) {
- case MPI25_MFGPAGE_DEVID_SAS3008:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
- break;
- case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
+ case PCI_VENDOR_ID_CISCO:
+ switch (ioc->pdev->device) {
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_CISCO_12G_8E_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_8E_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_8I_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_8I_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
- case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ case MPI25_MFGPAGE_DEVID_SAS3108_1:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
+ break;
+ case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING
+ );
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
break;
default:
pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "Cisco SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
break;
- case MPI25_MFGPAGE_DEVID_SAS3108_1:
- switch (ioc->pdev->subsystem_device) {
- case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING);
- break;
- case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID:
- pr_info(MPT3SAS_FMT "%s\n", ioc->name,
- MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING);
- break;
+ case MPT2SAS_HP_3PAR_SSVID:
+ switch (ioc->pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SAS2004:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ switch (ioc->pdev->subsystem_device) {
+ case MPT2SAS_HP_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_2_4_INTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_2_4_EXTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_2_4_EXTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING);
+ break;
+ case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID:
+ pr_info(MPT3SAS_FMT "%s\n", ioc->name,
+ MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING);
+ break;
+ default:
+ pr_info(MPT3SAS_FMT
+ "HP 6Gbps SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
+ break;
+ }
default:
pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
+ "HP SAS HBA: Subsystem ID: 0x%X\n",
+ ioc->name, ioc->pdev->subsystem_device);
break;
}
- break;
default:
- pr_info(MPT3SAS_FMT
- "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n",
- ioc->name, ioc->pdev->subsystem_device);
break;
}
}
@@ -2488,9 +2800,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
(bios_version & 0x0000FF00) >> 8,
bios_version & 0x000000FF);
- _base_display_intel_branding(ioc);
- _base_display_dell_branding(ioc);
- _base_display_cisco_branding(ioc);
+ _base_display_OEMs_branding(ioc);
pr_info(MPT3SAS_FMT "Protocol=(", ioc->name);
@@ -2508,10 +2818,12 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc)
pr_info("), ");
pr_info("Capabilities=(");
- if (ioc->facts.IOCCapabilities &
+ if (!ioc->hide_ir_msg) {
+ if (ioc->facts.IOCCapabilities &
MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) {
pr_info("Raid");
i++;
+ }
}
if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) {
@@ -2852,18 +3164,22 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
/* command line tunables for max sgl entries */
if (max_sgl_entries != -1)
sg_tablesize = max_sgl_entries;
- else
- sg_tablesize = MPT3SAS_SG_DEPTH;
+ else {
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ sg_tablesize = MPT2SAS_SG_DEPTH;
+ else
+ sg_tablesize = MPT3SAS_SG_DEPTH;
+ }
- if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS)
- sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS;
- else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) {
+ if (sg_tablesize < MPT_MIN_PHYS_SEGMENTS)
+ sg_tablesize = MPT_MIN_PHYS_SEGMENTS;
+ else if (sg_tablesize > MPT_MAX_PHYS_SEGMENTS) {
sg_tablesize = min_t(unsigned short, sg_tablesize,
SCSI_MAX_SG_CHAIN_SEGMENTS);
pr_warn(MPT3SAS_FMT
"sg_tablesize(%u) is bigger than kernel"
" defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
- sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS);
+ sg_tablesize, MPT_MAX_PHYS_SEGMENTS);
}
ioc->shost->sg_tablesize = sg_tablesize;
@@ -4021,7 +4337,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
mpi_request.VF_ID = 0; /* TODO */
mpi_request.VP_ID = 0;
- mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION);
+ mpi_request.MsgVersion = cpu_to_le16(ioc->hba_mpi_version_belonged);
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
if (_base_is_controller_msix_enabled(ioc))
@@ -4655,6 +4971,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
u32 reply_address;
u16 smid;
struct _tr_list *delayed_tr, *delayed_tr_next;
+ u8 hide_flag;
struct adapter_reply_queue *reply_q;
long reply_post_free;
u32 reply_post_free_sz, index = 0;
@@ -4685,6 +5002,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
ioc->scsi_lookup[i].cb_idx = 0xFF;
ioc->scsi_lookup[i].smid = smid;
ioc->scsi_lookup[i].scmd = NULL;
+ ioc->scsi_lookup[i].direct_io = 0;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
}
@@ -4787,6 +5105,16 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
if (ioc->is_driver_loading) {
+
+ if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier
+ == 0x80) {
+ hide_flag = (u8) (
+ le32_to_cpu(ioc->manu_pg10.OEMSpecificFlags0) &
+ MFG_PAGE10_HIDE_SSDS_MASK);
+ if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK)
+ ioc->mfg_pg10_hide_flag = hide_flag;
+ }
+
ioc->wait_for_discovery_to_complete =
_base_determine_wait_on_discovery(ioc);
@@ -4812,6 +5140,8 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
+ /* synchronizing freeing resource with pci_access_mutex lock */
+ mutex_lock(&ioc->pci_access_mutex);
if (ioc->chip_phys && ioc->chip) {
_base_mask_interrupts(ioc);
ioc->shost_recovery = 1;
@@ -4820,6 +5150,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc)
}
mpt3sas_base_unmap_resources(ioc);
+ mutex_unlock(&ioc->pci_access_mutex);
return;
}
@@ -4834,7 +5165,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
{
int r, i;
int cpu_id, last_cpu_id = 0;
- u8 revision;
dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name,
__func__));
@@ -4854,19 +5184,16 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
goto out_free_resources;
}
- /* Check whether the controller revision is C0 or above.
- * only C0 and above revision controllers support 96 MSI-X vectors.
- */
- revision = ioc->pdev->revision;
-
- if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 ||
- ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) &&
- (revision >= 0x02))
- ioc->msix96_vector = 1;
+ if (ioc->is_warpdrive) {
+ ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz,
+ sizeof(resource_size_t *), GFP_KERNEL);
+ if (!ioc->reply_post_host_index) {
+ dfailprintk(ioc, pr_info(MPT3SAS_FMT "allocation "
+ "for cpu_msix_table failed!!!\n", ioc->name));
+ r = -ENOMEM;
+ goto out_free_resources;
+ }
+ }
ioc->rdpq_array_enable_assigned = 0;
ioc->dma_mask = 0;
@@ -4874,23 +5201,41 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ if (ioc->is_warpdrive) {
+ ioc->reply_post_host_index[0] = (resource_size_t __iomem *)
+ &ioc->chip->ReplyPostHostIndex;
+
+ for (i = 1; i < ioc->cpu_msix_table_sz; i++)
+ ioc->reply_post_host_index[i] =
+ (resource_size_t __iomem *)
+ ((u8 __iomem *)&ioc->chip->Doorbell + (0x4000 + ((i - 1)
+ * 4)));
+ }
pci_set_drvdata(ioc->pdev, ioc->shost);
r = _base_get_ioc_facts(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
- /*
- * In SAS3.0,
- * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
- * Target Status - all require the IEEE formated scatter gather
- * elements.
- */
-
- ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
- ioc->build_sg = &_base_build_sg_ieee;
- ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
- ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ ioc->build_sg_scmd = &_base_build_sg_scmd;
+ ioc->build_sg = &_base_build_sg;
+ ioc->build_zero_len_sge = &_base_build_zero_len_sge;
+ break;
+ case MPI25_VERSION:
+ /*
+ * In SAS3.0,
+ * SCSI_IO, SMP_PASSTHRU, SATA_PASSTHRU, Target Assist, and
+ * Target Status - all require the IEEE formated scatter gather
+ * elements.
+ */
+ ioc->build_sg_scmd = &_base_build_sg_scmd_ieee;
+ ioc->build_sg = &_base_build_sg_ieee;
+ ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee;
+ ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t);
+ break;
+ }
/*
* These function pointers for other requests that don't
@@ -5006,6 +5351,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
if (r)
goto out_free_resources;
+ ioc->non_operational_loop = 0;
return 0;
out_free_resources:
@@ -5016,6 +5362,8 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
kfree(ioc->cpu_msix_table);
+ if (ioc->is_warpdrive)
+ kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
kfree(ioc->blocking_handles);
kfree(ioc->tm_cmds.reply);
@@ -5055,6 +5403,8 @@ mpt3sas_base_detach(struct MPT3SAS_ADAPTER *ioc)
_base_release_memory_pools(ioc);
pci_set_drvdata(ioc->pdev, NULL);
kfree(ioc->cpu_msix_table);
+ if (ioc->is_warpdrive)
+ kfree(ioc->reply_post_host_index);
kfree(ioc->pd_handles);
kfree(ioc->blocking_handles);
kfree(ioc->pfacts);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index f0e462b..5ad271e 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -63,6 +63,8 @@
#include <scsi/scsi_transport_sas.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
#include "mpt3sas_debug.h"
#include "mpt3sas_trigger_diag.h"
@@ -71,23 +73,37 @@
#define MPT3SAS_DRIVER_NAME "mpt3sas"
#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
-#define MPT3SAS_DRIVER_VERSION "09.100.00.00"
+#define MPT3SAS_DRIVER_VERSION "09.102.00.00"
#define MPT3SAS_MAJOR_VERSION 9
-#define MPT3SAS_MINOR_VERSION 100
+#define MPT3SAS_MINOR_VERSION 102
#define MPT3SAS_BUILD_VERSION 0
#define MPT3SAS_RELEASE_VERSION 00
+#define MPT2SAS_DRIVER_NAME "mpt2sas"
+#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
+#define MPT2SAS_DRIVER_VERSION "20.102.00.00"
+#define MPT2SAS_MAJOR_VERSION 20
+#define MPT2SAS_MINOR_VERSION 102
+#define MPT2SAS_BUILD_VERSION 0
+#define MPT2SAS_RELEASE_VERSION 00
+
/*
* Set MPT3SAS_SG_DEPTH value based on user input.
*/
-#define MPT3SAS_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS
-#define MPT3SAS_MIN_PHYS_SEGMENTS 16
+#define MPT_MAX_PHYS_SEGMENTS SCSI_MAX_SG_SEGMENTS
+#define MPT_MIN_PHYS_SEGMENTS 16
+
#ifdef CONFIG_SCSI_MPT3SAS_MAX_SGE
#define MPT3SAS_SG_DEPTH CONFIG_SCSI_MPT3SAS_MAX_SGE
#else
-#define MPT3SAS_SG_DEPTH MPT3SAS_MAX_PHYS_SEGMENTS
+#define MPT3SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS
#endif
+#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE
+#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE
+#else
+#define MPT2SAS_SG_DEPTH MPT_MAX_PHYS_SEGMENTS
+#endif
/*
* Generic Defines
@@ -124,6 +140,16 @@
#define MPT3SAS_FMT "%s: "
/*
+ * WarpDrive Specific Log codes
+ */
+
+#define MPT2_WARPDRIVE_LOGENTRY (0x8002)
+#define MPT2_WARPDRIVE_LC_SSDT (0x41)
+#define MPT2_WARPDRIVE_LC_SSDLW (0x43)
+#define MPT2_WARPDRIVE_LC_SSDLF (0x44)
+#define MPT2_WARPDRIVE_LC_BRMF (0x4D)
+
+/*
* per target private data
*/
#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01
@@ -131,9 +157,33 @@
#define MPT_TARGET_FLAGS_DELETED 0x04
#define MPT_TARGET_FASTPATH_IO 0x08
+#define SAS2_PCI_DEVICE_B0_REVISION (0x01)
+#define SAS3_PCI_DEVICE_C0_REVISION (0x02)
+
/*
* Intel HBA branding
*/
+#define MPT2SAS_INTEL_RMS25JB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25JB080"
+#define MPT2SAS_INTEL_RMS25JB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25JB040"
+#define MPT2SAS_INTEL_RMS25KB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25KB080"
+#define MPT2SAS_INTEL_RMS25KB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25KB040"
+#define MPT2SAS_INTEL_RMS25LB040_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25LB040"
+#define MPT2SAS_INTEL_RMS25LB080_BRANDING \
+ "Intel(R) Integrated RAID Module RMS25LB080"
+#define MPT2SAS_INTEL_RMS2LL080_BRANDING \
+ "Intel Integrated RAID Module RMS2LL080"
+#define MPT2SAS_INTEL_RMS2LL040_BRANDING \
+ "Intel Integrated RAID Module RMS2LL040"
+#define MPT2SAS_INTEL_RS25GB008_BRANDING \
+ "Intel(R) RAID Controller RS25GB008"
+#define MPT2SAS_INTEL_SSD910_BRANDING \
+ "Intel(R) SSD 910 Series"
+
#define MPT3SAS_INTEL_RMS3JC080_BRANDING \
"Intel(R) Integrated RAID Module RMS3JC080"
#define MPT3SAS_INTEL_RS3GC008_BRANDING \
@@ -146,33 +196,62 @@
/*
* Intel HBA SSDIDs
*/
-#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521
-#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522
-#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523
-#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524
+#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516
+#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517
+#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518
+#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519
+#define MPT2SAS_INTEL_RMS25LB040_SSDID 0x351A
+#define MPT2SAS_INTEL_RMS25LB080_SSDID 0x351B
+#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E
+#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F
+#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000
+#define MPT2SAS_INTEL_SSD910_SSDID 0x3700
+
+#define MPT3SAS_INTEL_RMS3JC080_SSDID 0x3521
+#define MPT3SAS_INTEL_RS3GC008_SSDID 0x3522
+#define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523
+#define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524
/*
* Dell HBA branding
*/
+#define MPT2SAS_DELL_BRANDING_SIZE 32
+
+#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA"
+#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter"
+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated"
+#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular"
+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded"
+#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200"
+#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS"
+
#define MPT3SAS_DELL_12G_HBA_BRANDING \
"Dell 12Gbps HBA"
/*
* Dell HBA SSDIDs
*/
-#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46
+#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C
+#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D
+#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E
+#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F
+#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20
+#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21
+#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22
+
+#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46
/*
* Cisco HBA branding
*/
#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \
- "Cisco 9300-8E 12G SAS HBA"
+ "Cisco 9300-8E 12G SAS HBA"
#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \
- "Cisco 9300-8i 12G SAS HBA"
+ "Cisco 9300-8i 12G SAS HBA"
#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \
- "Cisco 12G Modular SAS Pass through Controller"
+ "Cisco 12G Modular SAS Pass through Controller"
#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \
- "UCS C3X60 12G SAS Pass through Controller"
+ "UCS C3X60 12G SAS Pass through Controller"
/*
* Cisco HBA SSSDIDs
*/
@@ -189,6 +268,31 @@
#define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04)
/*
+ * HP HBA branding
+ */
+#define MPT2SAS_HP_3PAR_SSVID 0x1590
+
+#define MPT2SAS_HP_2_4_INTERNAL_BRANDING \
+ "HP H220 Host Bus Adapter"
+#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING \
+ "HP H221 Host Bus Adapter"
+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING \
+ "HP H222 Host Bus Adapter"
+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING \
+ "HP H220i Host Bus Adapter"
+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING \
+ "HP H210i Host Bus Adapter"
+
+/*
+ * HO HBA SSDIDs
+ */
+#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041
+#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042
+#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043
+#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044
+#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046
+
+/*
* Combined Reply Queue constants,
* There are twelve Supplemental Reply Post Host Index Registers
* and each register is at offset 0x10 bytes from the previous one.
@@ -243,20 +347,24 @@ struct Mpi2ManufacturingPage11_t {
* struct MPT3SAS_TARGET - starget private hostdata
* @starget: starget object
* @sas_address: target sas address
+ * @raid_device: raid_device pointer to access volume data
* @handle: device handle
* @num_luns: number luns
* @flags: MPT_TARGET_FLAGS_XXX flags
* @deleted: target flaged for deletion
* @tm_busy: target is busy with TM request.
+ * @sdev: The sas_device associated with this target
*/
struct MPT3SAS_TARGET {
struct scsi_target *starget;
u64 sas_address;
+ struct _raid_device *raid_device;
u16 handle;
int num_luns;
u32 flags;
u8 deleted;
u8 tm_busy;
+ struct _sas_device *sdev;
};
@@ -266,6 +374,11 @@ struct MPT3SAS_TARGET {
#define MPT_DEVICE_FLAGS_INIT 0x01
#define MPT_DEVICE_TLR_ON 0x02
+#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003)
+#define MFG_PAGE10_HIDE_ALL_DISKS (0x00)
+#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01)
+#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02)
+
/**
* struct MPT3SAS_DEVICE - sdev private hostdata
* @sas_target: starget private hostdata
@@ -358,8 +471,24 @@ struct _sas_device {
u8 pend_sas_rphy_add;
u8 enclosure_level;
u8 connector_name[4];
+ struct kref refcount;
};
+static inline void sas_device_get(struct _sas_device *s)
+{
+ kref_get(&s->refcount);
+}
+
+static inline void sas_device_free(struct kref *r)
+{
+ kfree(container_of(r, struct _sas_device, refcount));
+}
+
+static inline void sas_device_put(struct _sas_device *s)
+{
+ kref_put(&s->refcount, sas_device_free);
+}
+
/**
* struct _raid_device - raid volume link list
* @list: sas device list
@@ -367,6 +496,7 @@ struct _sas_device {
* @sdev: scsi device struct (volumes are single lun)
* @wwid: unique identifier for the volume
* @handle: device handle
+ * @block_size: Block size of the volume
* @id: target id
* @channel: target channel
* @volume_type: the raid level
@@ -374,6 +504,13 @@ struct _sas_device {
* @num_pds: number of hidden raid components
* @responding: used in _scsih_raid_device_mark_responding
* @percent_complete: resync percent complete
+ * @direct_io_enabled: Whether direct io to PDs are allowed or not
+ * @stripe_exponent: X where 2powX is the stripe sz in blocks
+ * @block_exponent: X where 2powX is the block sz in bytes
+ * @max_lba: Maximum number of LBA in the volume
+ * @stripe_sz: Stripe Size of the volume
+ * @device_info: Device info of the volume member disk
+ * @pd_handle: Array of handles of the physical drives for direct I/O in le16
*/
#define MPT_MAX_WARPDRIVE_PDS 8
struct _raid_device {
@@ -382,13 +519,20 @@ struct _raid_device {
struct scsi_device *sdev;
u64 wwid;
u16 handle;
+ u16 block_sz;
int id;
int channel;
u8 volume_type;
u8 num_pds;
u8 responding;
u8 percent_complete;
+ u8 direct_io_enabled;
+ u8 stripe_exponent;
+ u8 block_exponent;
+ u64 max_lba;
+ u32 stripe_sz;
u32 device_info;
+ u16 pd_handle[MPT_MAX_WARPDRIVE_PDS];
};
/**
@@ -497,12 +641,14 @@ struct chain_tracker {
* @smid: system message id
* @scmd: scsi request pointer
* @cb_idx: callback index
+ * @direct_io: To indicate whether I/O is direct (WARPDRIVE)
* @tracker_list: list of free request (ioc->free_list)
*/
struct scsiio_tracker {
u16 smid;
struct scsi_cmnd *scmd;
u8 cb_idx;
+ u8 direct_io;
struct list_head chain_list;
struct list_head tracker_list;
};
@@ -775,7 +921,13 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @replyPostRegisterIndex: index of next position in Reply Desc Post Queue
* @delayed_tr_list: target reset link list
* @delayed_tr_volume_list: volume target reset link list
- * @@temp_sensors_count: flag to carry the number of temperature sensors
+ * @temp_sensors_count: flag to carry the number of temperature sensors
+ * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and
+ * pci resource handling. PCI resource freeing will lead to free
+ * vital hardware/memory resource, which might be in use by cli/sysfs
+ * path functions resulting in Null pointer reference followed by kernel
+ * crash. To avoid the above race condition we use mutex syncrhonization
+ * which ensures the syncrhonization between cli/sysfs_show path.
*/
struct MPT3SAS_ADAPTER {
struct list_head list;
@@ -783,6 +935,7 @@ struct MPT3SAS_ADAPTER {
u8 id;
int cpu_count;
char name[MPT_NAME_LENGTH];
+ char driver_name[MPT_NAME_LENGTH];
char tmp_string[MPT_STRING_LENGTH];
struct pci_dev *pdev;
Mpi2SystemInterfaceRegs_t __iomem *chip;
@@ -829,8 +982,10 @@ struct MPT3SAS_ADAPTER {
u16 msix_vector_count;
u8 *cpu_msix_table;
u16 cpu_msix_table_sz;
+ resource_size_t __iomem **reply_post_host_index;
u32 ioc_reset_count;
MPT3SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds;
+ u32 non_operational_loop;
/* internal commands, callback index */
u8 scsi_io_cb_idx;
@@ -859,6 +1014,7 @@ struct MPT3SAS_ADAPTER {
MPT_BUILD_SG build_sg;
MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge;
u16 sge_size_ieee;
+ u16 hba_mpi_version_belonged;
/* function ptr for MPI sg elements only */
MPT_BUILD_SG build_sg_mpi;
@@ -987,6 +1143,7 @@ struct MPT3SAS_ADAPTER {
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
u8 temp_sensors_count;
+ struct mutex pci_access_mutex;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -998,6 +1155,10 @@ struct MPT3SAS_ADAPTER {
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
u32 ring_buffer_offset;
u32 ring_buffer_sz;
+ u8 is_warpdrive;
+ u8 hide_ir_msg;
+ u8 mfg_pg10_hide_flag;
+ u8 hide_drives;
spinlock_t diag_trigger_lock;
u8 diag_trigger_active;
struct SL_WH_MASTER_TRIGGER_T diag_trigger_master;
@@ -1012,6 +1173,19 @@ typedef u8 (*MPT_CALLBACK)(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
/* base shared API */
extern struct list_head mpt3sas_ioc_list;
+extern char driver_name[MPT_NAME_LENGTH];
+/* spinlock on list operations over IOCs
+ * Case: when multiple warpdrive cards(IOCs) are in use
+ * Each IOC will added to the ioc list structure on initialization.
+ * Watchdog threads run at regular intervals to check IOC for any
+ * fault conditions which will trigger the dead_ioc thread to
+ * deallocate pci resource, resulting deleting the IOC netry from list,
+ * this deletion need to protected by spinlock to enusre that
+ * ioc removal is syncrhonized, if not synchronized it might lead to
+ * list_del corruption as the ioc list is traversed in cli path.
+ */
+extern spinlock_t gioc_lock;
+
void mpt3sas_base_start_watchdog(struct MPT3SAS_ADAPTER *ioc);
void mpt3sas_base_stop_watchdog(struct MPT3SAS_ADAPTER *ioc);
@@ -1090,10 +1264,14 @@ struct _sas_node *mpt3sas_scsih_expander_find_by_handle(
struct MPT3SAS_ADAPTER *ioc, u16 handle);
struct _sas_node *mpt3sas_scsih_expander_find_by_sas_address(
struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
-struct _sas_device *mpt3sas_scsih_sas_device_find_by_sas_address(
- struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
+struct _sas_device *mpt3sas_get_sdev_by_addr(
+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
+struct _sas_device *__mpt3sas_get_sdev_by_addr(
+ struct MPT3SAS_ADAPTER *ioc, u64 sas_address);
void mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc);
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle);
/* config shared API */
u8 mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
@@ -1133,6 +1311,8 @@ int mpt3sas_config_get_sas_iounit_pg0(struct MPT3SAS_ADAPTER *ioc,
u16 sz);
int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
@@ -1177,8 +1357,8 @@ int mpt3sas_config_get_volume_wwid(struct MPT3SAS_ADAPTER *ioc,
/* ctl shared API */
extern struct device_attribute *mpt3sas_host_attrs[];
extern struct device_attribute *mpt3sas_dev_attrs[];
-void mpt3sas_ctl_init(void);
-void mpt3sas_ctl_exit(void);
+void mpt3sas_ctl_init(ushort hbas_to_enumerate);
+void mpt3sas_ctl_exit(ushort hbas_to_enumerate);
u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
void mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase);
@@ -1193,6 +1373,7 @@ int mpt3sas_send_diag_release(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type,
u8 *issue_reset);
/* transport shared API */
+extern struct scsi_transport_template *mpt3sas_transport_template;
u8 mpt3sas_transport_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
struct _sas_port *mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc,
@@ -1224,4 +1405,18 @@ void mpt3sas_trigger_scsi(struct MPT3SAS_ADAPTER *ioc, u8 sense_key,
u8 asc, u8 ascq);
void mpt3sas_trigger_mpi(struct MPT3SAS_ADAPTER *ioc, u16 ioc_status,
u32 loginfo);
+
+/* warpdrive APIs */
+u8 mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc);
+void mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+ struct _raid_device *raid_device);
+u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid);
+void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io);
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+ u16 smid);
+
#endif /* MPT3SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index e45c461..a6914ec 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -83,7 +83,6 @@ struct config_request {
dma_addr_t page_dma;
};
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _config_display_some_debug - debug routine
* @ioc: per adapter object
@@ -173,7 +172,6 @@ _config_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
le32_to_cpu(mpi_reply->IOCLogInfo));
}
-#endif
/**
* _config_alloc_config_dma_memory - obtain physical memory
@@ -255,9 +253,7 @@ mpt3sas_config_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
mpi_reply->MsgLength*4);
}
ioc->config_cmds.status &= ~MPT3_CMD_PENDING;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_done", mpi_reply);
-#endif
ioc->config_cmds.smid = USHRT_MAX;
complete(&ioc->config_cmds.done);
return 1;
@@ -387,9 +383,7 @@ _config_request(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
config_request = mpt3sas_base_get_msg_frame(ioc, smid);
ioc->config_cmds.smid = smid;
memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t));
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_config_display_some_debug(ioc, smid, "config_request", NULL);
-#endif
init_completion(&ioc->config_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
@@ -872,6 +866,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
}
/**
+ * mpt3sas_config_get_iounit_pg3 - obtain iounit page 3
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * @sz: size of buffer passed in config_page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ mpi_request.Header.PageNumber = 3;
+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE3_PAGEVERSION;
+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz);
+ out:
+ return r;
+}
+
+/**
* mpt3sas_config_get_iounit_pg8 - obtain iounit page 8
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index 080c8a7..d8366b0 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -78,7 +78,6 @@ enum block_state {
BLOCKING,
};
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _ctl_sas_device_find_by_handle - sas device search
* @ioc: per adapter object
@@ -254,8 +253,6 @@ _ctl_display_some_debug(struct MPT3SAS_ADAPTER *ioc, u16 smid,
}
}
-#endif
-
/**
* mpt3sas_ctl_done - ctl module completion routine
* @ioc: per adapter object
@@ -302,9 +299,7 @@ mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
}
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply);
-#endif
ioc->ctl_cmds.status &= ~MPT3_CMD_PENDING;
complete(&ioc->ctl_cmds.done);
return 1;
@@ -414,20 +409,31 @@ mpt3sas_ctl_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
* _ctl_verify_adapter - validates ioc_number passed from application
* @ioc: per adapter object
* @iocpp: The ioc pointer is returned in this.
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ * MPI25_VERSION for mpt3ctl ioctl device.
*
* Return (-1) means error, else ioc_number.
*/
static int
-_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp)
+_ctl_verify_adapter(int ioc_number, struct MPT3SAS_ADAPTER **iocpp,
+ int mpi_version)
{
struct MPT3SAS_ADAPTER *ioc;
-
+ /* global ioc lock to protect controller on list operations */
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
if (ioc->id != ioc_number)
continue;
+ /* Check whether this ioctl command is from right
+ * ioctl device or not, if not continue the search.
+ */
+ if (ioc->hba_mpi_version_belonged != mpi_version)
+ continue;
+ spin_unlock(&gioc_lock);
*iocpp = ioc;
return ioc_number;
}
+ spin_unlock(&gioc_lock);
*iocpp = NULL;
return -1;
}
@@ -497,7 +503,7 @@ mpt3sas_ctl_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
*
* Called when application request fasyn callback handler.
*/
-static int
+int
_ctl_fasync(int fd, struct file *filep, int mode)
{
return fasync_helper(fd, filep, mode, &async_queue);
@@ -509,17 +515,22 @@ _ctl_fasync(int fd, struct file *filep, int mode)
* @wait -
*
*/
-static unsigned int
+unsigned int
_ctl_poll(struct file *filep, poll_table *wait)
{
struct MPT3SAS_ADAPTER *ioc;
poll_wait(filep, &ctl_poll_wait, wait);
+ /* global ioc lock to protect controller on list operations */
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list) {
- if (ioc->aen_event_read_flag)
+ if (ioc->aen_event_read_flag) {
+ spin_unlock(&gioc_lock);
return POLLIN | POLLRDNORM;
+ }
}
+ spin_unlock(&gioc_lock);
return 0;
}
@@ -759,9 +770,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
psge = (void *)request + (karg.data_sge_offset*4);
/* send command to firmware */
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
_ctl_display_some_debug(ioc, smid, "ctl_request", NULL);
-#endif
init_completion(&ioc->ctl_cmds.done);
switch (mpi_request->Function) {
@@ -916,7 +925,6 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
mpi_reply = ioc->ctl_cmds.reply;
ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT &&
(ioc->logging_level & MPT_DEBUG_TM)) {
Mpi2SCSITaskManagementReply_t *tm_reply =
@@ -929,7 +937,7 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg,
le32_to_cpu(tm_reply->IOCLogInfo),
le32_to_cpu(tm_reply->TerminationCount));
}
-#endif
+
/* copy out xdata to user */
if (data_in_sz) {
if (copy_to_user(karg.data_in_buf_ptr, data_in,
@@ -1023,7 +1031,6 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
__func__));
memset(&karg, 0 , sizeof(karg));
- karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
if (ioc->pfacts)
karg.port_number = ioc->pfacts[0].PortNumber;
karg.hw_rev = ioc->pdev->revision;
@@ -1035,9 +1042,21 @@ _ctl_getiocinfo(struct MPT3SAS_ADAPTER *ioc, void __user *arg)
karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn);
karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus);
karg.firmware_version = ioc->facts.FWVersion.Word;
- strcpy(karg.driver_version, MPT3SAS_DRIVER_NAME);
+ strcpy(karg.driver_version, ioc->driver_name);
strcat(karg.driver_version, "-");
- strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
+ switch (ioc->hba_mpi_version_belonged) {
+ case MPI2_VERSION:
+ if (ioc->is_warpdrive)
+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200;
+ else
+ karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2;
+ strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION);
+ break;
+ case MPI25_VERSION:
+ karg.adapter_type = MPT3_IOCTL_INTERFACE_SAS3;
+ strcat(karg.driver_version, MPT3SAS_DRIVER_VERSION);
+ break;
+ }
karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion);
if (copy_to_user(arg, &karg, sizeof(karg))) {
@@ -2181,12 +2200,14 @@ _ctl_compat_mpt_command(struct MPT3SAS_ADAPTER *ioc, unsigned cmd,
* _ctl_ioctl_main - main ioctl entry point
* @file - (struct file)
* @cmd - ioctl opcode
- * @arg -
- * compat - handles 32 bit applications in 64bit os
+ * @arg - user space data buffer
+ * @compat - handles 32 bit applications in 64bit os
+ * @mpi_version: will be MPI2_VERSION for mpt2ctl ioctl device &
+ * MPI25_VERSION for mpt3ctl ioctl device.
*/
static long
_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
- u8 compat)
+ u8 compat, u16 mpi_version)
{
struct MPT3SAS_ADAPTER *ioc;
struct mpt3_ioctl_header ioctl_header;
@@ -2201,19 +2222,29 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
return -EFAULT;
}
- if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc)
+ if (_ctl_verify_adapter(ioctl_header.ioc_number,
+ &ioc, mpi_version) == -1 || !ioc)
return -ENODEV;
+ /* pci_access_mutex lock acquired by ioctl path */
+ mutex_lock(&ioc->pci_access_mutex);
+
if (ioc->shost_recovery || ioc->pci_error_recovery ||
- ioc->is_driver_loading)
- return -EAGAIN;
+ ioc->is_driver_loading || ioc->remove_host) {
+ ret = -EAGAIN;
+ goto out_unlock_pciaccess;
+ }
state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING;
if (state == NON_BLOCKING) {
- if (!mutex_trylock(&ioc->ctl_cmds.mutex))
- return -EAGAIN;
- } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex))
- return -ERESTARTSYS;
+ if (!mutex_trylock(&ioc->ctl_cmds.mutex)) {
+ ret = -EAGAIN;
+ goto out_unlock_pciaccess;
+ }
+ } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) {
+ ret = -ERESTARTSYS;
+ goto out_unlock_pciaccess;
+ }
switch (cmd) {
@@ -2294,39 +2325,78 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg,
}
mutex_unlock(&ioc->ctl_cmds.mutex);
+out_unlock_pciaccess:
+ mutex_unlock(&ioc->pci_access_mutex);
return ret;
}
/**
- * _ctl_ioctl - main ioctl entry point (unlocked)
+ * _ctl_ioctl - mpt3ctl main ioctl entry point (unlocked)
* @file - (struct file)
* @cmd - ioctl opcode
* @arg -
*/
-static long
+long
_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0);
+ /* pass MPI25_VERSION value, to indicate that this ioctl cmd
+ * came from mpt3ctl ioctl device.
+ */
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI25_VERSION);
return ret;
}
+/**
+ * _ctl_mpt2_ioctl - mpt2ctl main ioctl entry point (unlocked)
+ * @file - (struct file)
+ * @cmd - ioctl opcode
+ * @arg -
+ */
+long
+_ctl_mpt2_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long ret;
+
+ /* pass MPI2_VERSION value, to indicate that this ioctl cmd
+ * came from mpt2ctl ioctl device.
+ */
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 0, MPI2_VERSION);
+ return ret;
+}
#ifdef CONFIG_COMPAT
/**
- * _ctl_ioctl_compat - main ioctl entry point (compat)
+ *_ ctl_ioctl_compat - main ioctl entry point (compat)
* @file -
* @cmd -
* @arg -
*
* This routine handles 32 bit applications in 64bit os.
*/
-static long
+long
_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
- ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1);
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI25_VERSION);
+ return ret;
+}
+
+/**
+ *_ ctl_mpt2_ioctl_compat - main ioctl entry point (compat)
+ * @file -
+ * @cmd -
+ * @arg -
+ *
+ * This routine handles 32 bit applications in 64bit os.
+ */
+long
+_ctl_mpt2_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
+{
+ long ret;
+
+ ret = _ctl_ioctl_main(file, cmd, (void __user *)arg, 1, MPI2_VERSION);
return ret;
}
#endif
@@ -2713,6 +2783,82 @@ _ctl_ioc_reply_queue_count_show(struct device *cdev,
static DEVICE_ATTR(reply_queue_count, S_IRUGO, _ctl_ioc_reply_queue_count_show,
NULL);
+/**
+ * _ctl_BRM_status_show - Backup Rail Monitor Status
+ * @cdev - pointer to embedded class device
+ * @buf - the buffer returned
+ *
+ * This is number of reply queues
+ *
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t
+_ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(cdev);
+ struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
+ Mpi2IOUnitPage3_t *io_unit_pg3 = NULL;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 backup_rail_monitor_status = 0;
+ u16 ioc_status;
+ int sz;
+ ssize_t rc = 0;
+
+ if (!ioc->is_warpdrive) {
+ pr_err(MPT3SAS_FMT "%s: BRM attribute is only for"
+ " warpdrive\n", ioc->name, __func__);
+ goto out;
+ }
+ /* pci_access_mutex lock acquired by sysfs show path */
+ mutex_lock(&ioc->pci_access_mutex);
+ if (ioc->pci_error_recovery || ioc->remove_host) {
+ mutex_unlock(&ioc->pci_access_mutex);
+ return 0;
+ }
+
+ /* allocate upto GPIOVal 36 entries */
+ sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36);
+ io_unit_pg3 = kzalloc(sz, GFP_KERNEL);
+ if (!io_unit_pg3) {
+ pr_err(MPT3SAS_FMT "%s: failed allocating memory "
+ "for iounit_pg3: (%d) bytes\n", ioc->name, __func__, sz);
+ goto out;
+ }
+
+ if (mpt3sas_config_get_iounit_pg3(ioc, &mpi_reply, io_unit_pg3, sz) !=
+ 0) {
+ pr_err(MPT3SAS_FMT
+ "%s: failed reading iounit_pg3\n", ioc->name,
+ __func__);
+ goto out;
+ }
+
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK;
+ if (ioc_status != MPI2_IOCSTATUS_SUCCESS) {
+ pr_err(MPT3SAS_FMT "%s: iounit_pg3 failed with "
+ "ioc_status(0x%04x)\n", ioc->name, __func__, ioc_status);
+ goto out;
+ }
+
+ if (io_unit_pg3->GPIOCount < 25) {
+ pr_err(MPT3SAS_FMT "%s: iounit_pg3->GPIOCount less than "
+ "25 entries, detected (%d) entries\n", ioc->name, __func__,
+ io_unit_pg3->GPIOCount);
+ goto out;
+ }
+
+ /* BRM status is in bit zero of GPIOVal[24] */
+ backup_rail_monitor_status = le16_to_cpu(io_unit_pg3->GPIOVal[24]);
+ rc = snprintf(buf, PAGE_SIZE, "%d\n", (backup_rail_monitor_status & 1));
+
+ out:
+ kfree(io_unit_pg3);
+ mutex_unlock(&ioc->pci_access_mutex);
+ return rc;
+}
+static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL);
+
struct DIAG_BUFFER_START {
__le32 Size;
__le32 DiagVersion;
@@ -3165,6 +3311,7 @@ struct device_attribute *mpt3sas_host_attrs[] = {
&dev_attr_diag_trigger_event,
&dev_attr_diag_trigger_scsi,
&dev_attr_diag_trigger_mpi,
+ &dev_attr_BRM_status,
NULL,
};
@@ -3218,6 +3365,7 @@ struct device_attribute *mpt3sas_dev_attrs[] = {
NULL,
};
+/* file operations table for mpt3ctl device */
static const struct file_operations ctl_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = _ctl_ioctl,
@@ -3228,23 +3376,53 @@ static const struct file_operations ctl_fops = {
#endif
};
+/* file operations table for mpt2ctl device */
+static const struct file_operations ctl_gen2_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = _ctl_mpt2_ioctl,
+ .poll = _ctl_poll,
+ .fasync = _ctl_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = _ctl_mpt2_ioctl_compat,
+#endif
+};
+
static struct miscdevice ctl_dev = {
.minor = MPT3SAS_MINOR,
.name = MPT3SAS_DEV_NAME,
.fops = &ctl_fops,
};
+static struct miscdevice gen2_ctl_dev = {
+ .minor = MPT2SAS_MINOR,
+ .name = MPT2SAS_DEV_NAME,
+ .fops = &ctl_gen2_fops,
+};
+
/**
* mpt3sas_ctl_init - main entry point for ctl.
*
*/
void
-mpt3sas_ctl_init(void)
+mpt3sas_ctl_init(ushort hbas_to_enumerate)
{
async_queue = NULL;
- if (misc_register(&ctl_dev) < 0)
- pr_err("%s can't register misc device [minor=%d]\n",
- MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
+
+ /* Don't register mpt3ctl ioctl device if
+ * hbas_to_enumarate is one.
+ */
+ if (hbas_to_enumerate != 1)
+ if (misc_register(&ctl_dev) < 0)
+ pr_err("%s can't register misc device [minor=%d]\n",
+ MPT3SAS_DRIVER_NAME, MPT3SAS_MINOR);
+
+ /* Don't register mpt3ctl ioctl device if
+ * hbas_to_enumarate is two.
+ */
+ if (hbas_to_enumerate != 2)
+ if (misc_register(&gen2_ctl_dev) < 0)
+ pr_err("%s can't register misc device [minor=%d]\n",
+ MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR);
init_waitqueue_head(&ctl_poll_wait);
}
@@ -3254,7 +3432,7 @@ mpt3sas_ctl_init(void)
*
*/
void
-mpt3sas_ctl_exit(void)
+mpt3sas_ctl_exit(ushort hbas_to_enumerate)
{
struct MPT3SAS_ADAPTER *ioc;
int i;
@@ -3279,5 +3457,8 @@ mpt3sas_ctl_exit(void)
kfree(ioc->event_log);
}
- misc_deregister(&ctl_dev);
+ if (hbas_to_enumerate != 1)
+ misc_deregister(&ctl_dev);
+ if (hbas_to_enumerate != 2)
+ misc_deregister(&gen2_ctl_dev);
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
index aee99ce..8940835 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
@@ -50,10 +50,13 @@
#include <linux/miscdevice.h>
#endif
-
+#ifndef MPT2SAS_MINOR
+#define MPT2SAS_MINOR (MPT_MINOR + 1)
+#endif
#ifndef MPT3SAS_MINOR
#define MPT3SAS_MINOR (MPT_MINOR + 2)
#endif
+#define MPT2SAS_DEV_NAME "mpt2ctl"
#define MPT3SAS_DEV_NAME "mpt3ctl"
#define MPT3_MAGIC_NUMBER 'L'
#define MPT3_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */
@@ -138,6 +141,7 @@ struct mpt3_ioctl_pci_info {
#define MPT2_IOCTL_INTERFACE_FC_IP (0x02)
#define MPT2_IOCTL_INTERFACE_SAS (0x03)
#define MPT2_IOCTL_INTERFACE_SAS2 (0x04)
+#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05)
#define MPT3_IOCTL_INTERFACE_SAS3 (0x06)
#define MPT2_IOCTL_VERSION_LENGTH (32)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h
index 4e8a63f..cceeb2c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_debug.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h
@@ -68,20 +68,11 @@
#define MPT_DEBUG_TRIGGER_DIAG 0x00200000
-/*
- * CONFIG_SCSI_MPT3SAS_LOGGING - enabled in Kconfig
- */
-
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \
{ \
if (IOC->logging_level & BITS) \
CMD; \
}
-#else
-#define MPT_CHECK_LOGGING(IOC, CMD, BITS)
-#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */
-
/*
* debug macros
@@ -153,7 +144,7 @@
/* inline functions for dumping debug data*/
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
+
/**
* _debug_dump_mf - print message frame contents
* @mpi_request: pointer to message frame
@@ -211,10 +202,5 @@ _debug_dump_config(void *mpi_request, int sz)
}
pr_info("\n");
}
-#else
-#define _debug_dump_mf(mpi_request, sz)
-#define _debug_dump_reply(mpi_request, sz)
-#define _debug_dump_config(mpi_request, sz)
-#endif /* CONFIG_SCSI_MPT3SAS_LOGGING */
#endif /* MPT3SAS_DEBUG_H_INCLUDED */
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 8ccef38..9ab77b0 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -54,14 +54,10 @@
#include <linux/interrupt.h>
#include <linux/aer.h>
#include <linux/raid_class.h>
+#include <asm/unaligned.h>
#include "mpt3sas_base.h"
-MODULE_AUTHOR(MPT3SAS_AUTHOR);
-MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
-
#define RAID_CHANNEL 1
/* forward proto's */
static void _scsih_expander_node_remove(struct MPT3SAS_ADAPTER *ioc,
@@ -75,11 +71,16 @@ static int _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle,
static u8 _scsih_check_for_pending_tm(struct MPT3SAS_ADAPTER *ioc, u16 smid);
-static void _scsih_scan_start(struct Scsi_Host *shost);
-static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time);
-
/* global parameters */
LIST_HEAD(mpt3sas_ioc_list);
+/* global ioc lock for list operations */
+DEFINE_SPINLOCK(gioc_lock);
+
+MODULE_AUTHOR(MPT3SAS_AUTHOR);
+MODULE_DESCRIPTION(MPT3SAS_DESCRIPTION);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MPT3SAS_DRIVER_VERSION);
+MODULE_ALIAS("mpt2sas");
/* local parameters */
static u8 scsi_io_cb_idx = -1;
@@ -90,7 +91,8 @@ static u8 port_enable_cb_idx = -1;
static u8 transport_cb_idx = -1;
static u8 scsih_cb_idx = -1;
static u8 config_cb_idx = -1;
-static int mpt_ids;
+static int mpt2_ids;
+static int mpt3_ids;
static u8 tm_tr_cb_idx = -1 ;
static u8 tm_tr_volume_cb_idx = -1 ;
@@ -117,8 +119,12 @@ static u64 max_lun = MPT3SAS_MAX_LUN;
module_param(max_lun, ullong, 0);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
-
-
+static ushort hbas_to_enumerate;
+module_param(hbas_to_enumerate, ushort, 0);
+MODULE_PARM_DESC(hbas_to_enumerate,
+ " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
+ 1 - enumerates only SAS 2.0 generation HBAs\n \
+ 2 - enumerates only SAS 3.0 generation HBAs (default=0)");
/* diag_buffer_enable is bitwise
* bit 0 set = TRACE
@@ -143,8 +149,8 @@ MODULE_PARM_DESC(prot_mask, " host protection capabilities mask, def=7 ");
/* raid transport support */
-
-static struct raid_template *mpt3sas_raid_template;
+struct raid_template *mpt3sas_raid_template;
+struct raid_template *mpt2sas_raid_template;
/**
@@ -191,11 +197,36 @@ struct fw_event_work {
u8 VP_ID;
u8 ignore;
u16 event;
+ struct kref refcount;
char event_data[0] __aligned(4);
};
-/* raid transport support */
-static struct raid_template *mpt3sas_raid_template;
+static void fw_event_work_free(struct kref *r)
+{
+ kfree(container_of(r, struct fw_event_work, refcount));
+}
+
+static void fw_event_work_get(struct fw_event_work *fw_work)
+{
+ kref_get(&fw_work->refcount);
+}
+
+static void fw_event_work_put(struct fw_event_work *fw_work)
+{
+ kref_put(&fw_work->refcount, fw_event_work_free);
+}
+
+static struct fw_event_work *alloc_fw_event_work(int len)
+{
+ struct fw_event_work *fw_event;
+
+ fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC);
+ if (!fw_event)
+ return NULL;
+
+ kref_init(&fw_event->refcount);
+ return fw_event;
+}
/**
* struct _scsi_io_transfer - scsi io transfer
@@ -245,28 +276,6 @@ struct _scsi_io_transfer {
u32 transfer_length;
};
-/*
- * The pci device ids are defined in mpi/mpi2_cnfg.h.
- */
-static const struct pci_device_id scsih_pci_table[] = {
- /* Fury ~ 3004 and 3008 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
- PCI_ANY_ID, PCI_ANY_ID },
- /* Invader ~ 3108 */
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
- PCI_ANY_ID, PCI_ANY_ID },
- { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
- PCI_ANY_ID, PCI_ANY_ID },
- {0} /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(pci, scsih_pci_table);
-
/**
* _scsih_set_debug_level - global setting of ioc->logging_level.
*
@@ -282,8 +291,10 @@ _scsih_set_debug_level(const char *val, struct kernel_param *kp)
return ret;
pr_info("setting logging_level(0x%08x)\n", logging_level);
+ spin_lock(&gioc_lock);
list_for_each_entry(ioc, &mpt3sas_ioc_list, list)
ioc->logging_level = logging_level;
+ spin_unlock(&gioc_lock);
return 0;
}
module_param_call(logging_level, _scsih_set_debug_level, param_get_int,
@@ -518,8 +529,61 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
}
}
+static struct _sas_device *
+__mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
+ struct MPT3SAS_TARGET *tgt_priv)
+{
+ struct _sas_device *ret;
+
+ assert_spin_locked(&ioc->sas_device_lock);
+
+ ret = tgt_priv->sdev;
+ if (ret)
+ sas_device_get(ret);
+
+ return ret;
+}
+
+static struct _sas_device *
+mpt3sas_get_sdev_from_target(struct MPT3SAS_ADAPTER *ioc,
+ struct MPT3SAS_TARGET *tgt_priv)
+{
+ struct _sas_device *ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ ret = __mpt3sas_get_sdev_from_target(ioc, tgt_priv);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return ret;
+}
+
+
+struct _sas_device *
+__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
+ u64 sas_address)
+{
+ struct _sas_device *sas_device;
+
+ assert_spin_locked(&ioc->sas_device_lock);
+
+ list_for_each_entry(sas_device, &ioc->sas_device_list, list)
+ if (sas_device->sas_address == sas_address)
+ goto found_device;
+
+ list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
+ if (sas_device->sas_address == sas_address)
+ goto found_device;
+
+ return NULL;
+
+found_device:
+ sas_device_get(sas_device);
+ return sas_device;
+}
+
/**
- * mpt3sas_scsih_sas_device_find_by_sas_address - sas device search
+ * mpt3sas_get_sdev_by_addr - sas device search
* @ioc: per adapter object
* @sas_address: sas address
* Context: Calling function should acquire ioc->sas_device_lock
@@ -528,24 +592,44 @@ _scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc,
* object.
*/
struct _sas_device *
-mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
+mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address)
{
struct _sas_device *sas_device;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
+ sas_address);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return sas_device;
+}
+
+static struct _sas_device *
+__mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+{
+ struct _sas_device *sas_device;
+
+ assert_spin_locked(&ioc->sas_device_lock);
list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->sas_address == sas_address)
- return sas_device;
+ if (sas_device->handle == handle)
+ goto found_device;
list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->sas_address == sas_address)
- return sas_device;
+ if (sas_device->handle == handle)
+ goto found_device;
return NULL;
+
+found_device:
+ sas_device_get(sas_device);
+ return sas_device;
}
/**
- * _scsih_sas_device_find_by_handle - sas device search
+ * mpt3sas_get_sdev_by_handle - sas device search
* @ioc: per adapter object
* @handle: sas device handle (assigned by firmware)
* Context: Calling function should acquire ioc->sas_device_lock
@@ -554,19 +638,16 @@ mpt3sas_scsih_sas_device_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
* object.
*/
static struct _sas_device *
-_scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+mpt3sas_get_sdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct _sas_device *sas_device;
+ unsigned long flags;
- list_for_each_entry(sas_device, &ioc->sas_device_list, list)
- if (sas_device->handle == handle)
- return sas_device;
-
- list_for_each_entry(sas_device, &ioc->sas_device_init_list, list)
- if (sas_device->handle == handle)
- return sas_device;
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return NULL;
+ return sas_device;
}
/**
@@ -575,7 +656,7 @@ _scsih_sas_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
* @sas_device: the sas_device object
* Context: This function will acquire ioc->sas_device_lock.
*
- * Removing object and freeing associated memory from the ioc->sas_device_list.
+ * If sas_device is on the list, remove it and decrement its reference count.
*/
static void
_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
@@ -602,9 +683,15 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc,
ioc->name, sas_device->enclosure_level,
sas_device->connector_name);
+ /*
+ * The lock serializes access to the list, but we still need to verify
+ * that nobody removed the entry while we were waiting on the lock.
+ */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_del(&sas_device->list);
- kfree(sas_device);
+ if (!list_empty(&sas_device->list)) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -625,12 +712,16 @@ _scsih_device_remove_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (sas_device)
- list_del(&sas_device->list);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
_scsih_remove_device(ioc, sas_device);
+ sas_device_put(sas_device);
+ }
}
/**
@@ -651,13 +742,16 @@ mpt3sas_device_remove_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_address);
- if (sas_device)
- list_del(&sas_device->list);
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc, sas_address);
+ if (sas_device) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
_scsih_remove_device(ioc, sas_device);
+ sas_device_put(sas_device);
+ }
}
/**
@@ -692,6 +786,7 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->enclosure_level, sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -745,6 +840,7 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc,
sas_device->connector_name));
spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device_get(sas_device);
list_add_tail(&sas_device->list, &ioc->sas_device_init_list);
_scsih_determine_boot_device(ioc, sas_device, 0);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -778,7 +874,7 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
}
/**
- * _scsih_raid_device_find_by_handle - raid device search
+ * mpt3sas_raid_device_find_by_handle - raid device search
* @ioc: per adapter object
* @handle: sas device handle (assigned by firmware)
* Context: Calling function should acquire ioc->raid_device_lock
@@ -786,8 +882,8 @@ _scsih_raid_device_find_by_id(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
* This searches for raid_device based on handle, then return raid_device
* object.
*/
-static struct _raid_device *
-_scsih_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
+struct _raid_device *
+mpt3sas_raid_device_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct _raid_device *raid_device, *r;
@@ -1095,14 +1191,14 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id,
}
/**
- * _scsih_change_queue_depth - setting device queue depth
+ * scsih_change_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
*
* Returns queue depth.
*/
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
+int
+scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
@@ -1123,12 +1219,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
goto not_sata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))
goto not_sata;
+
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_device_priv_data->sas_target->sas_address);
- if (sas_device && sas_device->device_info &
- MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
- max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
+ if (sas_device) {
+ if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE)
+ max_depth = MPT3SAS_SATA_QUEUE_DEPTH;
+
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata:
@@ -1141,14 +1240,14 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
}
/**
- * _scsih_target_alloc - target add routine
+ * scsih_target_alloc - target add routine
* @starget: scsi target struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_target_alloc(struct scsi_target *starget)
+int
+scsih_target_alloc(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1176,7 +1275,9 @@ _scsih_target_alloc(struct scsi_target *starget)
sas_target_priv_data->handle = raid_device->handle;
sas_target_priv_data->sas_address = raid_device->wwid;
sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME;
- raid_device->starget = starget;
+ sas_target_priv_data->raid_device = raid_device;
+ if (ioc->is_warpdrive)
+ raid_device->starget = starget;
}
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
return 0;
@@ -1185,12 +1286,13 @@ _scsih_target_alloc(struct scsi_target *starget)
/* sas/sata devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device) {
sas_target_priv_data->handle = sas_device->handle;
sas_target_priv_data->sas_address = sas_device->sas_address;
+ sas_target_priv_data->sdev = sas_device;
sas_device->starget = starget;
sas_device->id = starget->id;
sas_device->channel = starget->channel;
@@ -1206,13 +1308,13 @@ _scsih_target_alloc(struct scsi_target *starget)
}
/**
- * _scsih_target_destroy - target destroy routine
+ * scsih_target_destroy - target destroy routine
* @starget: scsi target struct
*
* Returns nothing.
*/
-static void
-_scsih_target_destroy(struct scsi_target *starget)
+void
+scsih_target_destroy(struct scsi_target *starget)
{
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1240,13 +1342,21 @@ _scsih_target_destroy(struct scsi_target *starget)
spin_lock_irqsave(&ioc->sas_device_lock, flags);
rphy = dev_to_rphy(starget->dev.parent);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- rphy->identify.sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, sas_target_priv_data);
if (sas_device && (sas_device->starget == starget) &&
(sas_device->id == starget->id) &&
(sas_device->channel == starget->channel))
sas_device->starget = NULL;
+ if (sas_device) {
+ /*
+ * Corresponding get() is in _scsih_target_alloc()
+ */
+ sas_target_priv_data->sdev = NULL;
+ sas_device_put(sas_device);
+
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
out:
@@ -1255,14 +1365,14 @@ _scsih_target_destroy(struct scsi_target *starget)
}
/**
- * _scsih_slave_alloc - device add routine
+ * scsih_slave_alloc - device add routine
* @sdev: scsi device struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_slave_alloc(struct scsi_device *sdev)
+int
+scsih_slave_alloc(struct scsi_device *sdev)
{
struct Scsi_Host *shost;
struct MPT3SAS_ADAPTER *ioc;
@@ -1302,14 +1412,18 @@ _scsih_slave_alloc(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_target_priv_data->sas_address);
if (sas_device && (sas_device->starget == NULL)) {
sdev_printk(KERN_INFO, sdev,
"%s : sas_device->starget set to starget @ %d\n",
- __func__, __LINE__);
+ __func__, __LINE__);
sas_device->starget = starget;
}
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -1317,13 +1431,13 @@ _scsih_slave_alloc(struct scsi_device *sdev)
}
/**
- * _scsih_slave_destroy - device destroy routine
+ * scsih_slave_destroy - device destroy routine
* @sdev: scsi device struct
*
* Returns nothing.
*/
-static void
-_scsih_slave_destroy(struct scsi_device *sdev)
+void
+scsih_slave_destroy(struct scsi_device *sdev)
{
struct MPT3SAS_TARGET *sas_target_priv_data;
struct scsi_target *starget;
@@ -1344,10 +1458,13 @@ _scsih_slave_destroy(struct scsi_device *sdev)
if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_target_priv_data->sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc,
+ sas_target_priv_data);
if (sas_device && !sas_target_priv_data->num_luns)
sas_device->starget = NULL;
+
+ if (sas_device)
+ sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
@@ -1409,23 +1526,26 @@ _scsih_display_sata_capabilities(struct MPT3SAS_ADAPTER *ioc,
*/
/**
- * _scsih_is_raid - return boolean indicating device is raid volume
+ * scsih_is_raid - return boolean indicating device is raid volume
* @dev the device struct object
*/
-static int
-_scsih_is_raid(struct device *dev)
+int
+scsih_is_raid(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
+ struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
+ if (ioc->is_warpdrive)
+ return 0;
return (sdev->channel == RAID_CHANNEL) ? 1 : 0;
}
/**
- * _scsih_get_resync - get raid volume resync percent complete
+ * scsih_get_resync - get raid volume resync percent complete
* @dev the device struct object
*/
-static void
-_scsih_get_resync(struct device *dev)
+void
+scsih_get_resync(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
@@ -1439,6 +1559,9 @@ _scsih_get_resync(struct device *dev)
percent_complete = 0;
handle = 0;
+ if (ioc->is_warpdrive)
+ goto out;
+
spin_lock_irqsave(&ioc->raid_device_lock, flags);
raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id,
sdev->channel);
@@ -1466,15 +1589,18 @@ _scsih_get_resync(struct device *dev)
percent_complete = 0;
out:
- raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ raid_set_resync(mpt2sas_raid_template, dev, percent_complete);
+ if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ raid_set_resync(mpt3sas_raid_template, dev, percent_complete);
}
/**
- * _scsih_get_state - get raid volume level
+ * scsih_get_state - get raid volume level
* @dev the device struct object
*/
-static void
-_scsih_get_state(struct device *dev)
+void
+scsih_get_state(struct device *dev)
{
struct scsi_device *sdev = to_scsi_device(dev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(sdev->host);
@@ -1524,7 +1650,10 @@ _scsih_get_state(struct device *dev)
break;
}
out:
- raid_set_state(mpt3sas_raid_template, dev, state);
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ raid_set_state(mpt2sas_raid_template, dev, state);
+ if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ raid_set_state(mpt3sas_raid_template, dev, state);
}
/**
@@ -1533,7 +1662,8 @@ _scsih_get_state(struct device *dev)
* @volume_type: volume type
*/
static void
-_scsih_set_level(struct scsi_device *sdev, u8 volume_type)
+_scsih_set_level(struct MPT3SAS_ADAPTER *ioc,
+ struct scsi_device *sdev, u8 volume_type)
{
enum raid_level level = RAID_LEVEL_UNKNOWN;
@@ -1552,7 +1682,12 @@ _scsih_set_level(struct scsi_device *sdev, u8 volume_type)
break;
}
- raid_set_level(mpt3sas_raid_template, &sdev->sdev_gendev, level);
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ raid_set_level(mpt2sas_raid_template,
+ &sdev->sdev_gendev, level);
+ if (ioc->hba_mpi_version_belonged == MPI25_VERSION)
+ raid_set_level(mpt3sas_raid_template,
+ &sdev->sdev_gendev, level);
}
@@ -1622,8 +1757,6 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc,
return 0;
}
-
-
/**
* _scsih_enable_tlr - setting TLR flags
* @ioc: per adapter object
@@ -1652,14 +1785,14 @@ _scsih_enable_tlr(struct MPT3SAS_ADAPTER *ioc, struct scsi_device *sdev)
}
/**
- * _scsih_slave_configure - device configure routine.
+ * scsih_slave_configure - device configure routine.
* @sdev: scsi device struct
*
* Returns 0 if ok. Any other return is assumed to be an error and
* the device is ignored.
*/
-static int
-_scsih_slave_configure(struct scsi_device *sdev)
+int
+scsih_slave_configure(struct scsi_device *sdev)
{
struct Scsi_Host *shost = sdev->host;
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -1686,7 +1819,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (!raid_device) {
dfailprintk(ioc, pr_warn(MPT3SAS_FMT
@@ -1702,6 +1835,10 @@ _scsih_slave_configure(struct scsi_device *sdev)
return 1;
}
+ /*
+ * WARPDRIVE: Initialize the required data for Direct IO
+ */
+ mpt3sas_init_warpdrive_properties(ioc, raid_device);
/* RAID Queue Depth Support
* IS volume = underlying qdepth of drive type, either
@@ -1750,17 +1887,19 @@ _scsih_slave_configure(struct scsi_device *sdev)
break;
}
- sdev_printk(KERN_INFO, sdev,
- "%s: handle(0x%04x), wwid(0x%016llx), pd_count(%d), type(%s)\n",
- r_level, raid_device->handle,
- (unsigned long long)raid_device->wwid,
- raid_device->num_pds, ds);
-
+ if (!ioc->hide_ir_msg)
+ sdev_printk(KERN_INFO, sdev,
+ "%s: handle(0x%04x), wwid(0x%016llx),"
+ " pd_count(%d), type(%s)\n",
+ r_level, raid_device->handle,
+ (unsigned long long)raid_device->wwid,
+ raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth);
+ scsih_change_queue_depth(sdev, qdepth);
-/* raid transport support */
- _scsih_set_level(sdev, raid_device->volume_type);
+ /* raid transport support */
+ if (!ioc->is_warpdrive)
+ _scsih_set_level(ioc, sdev, raid_device->volume_type);
return 0;
}
@@ -1783,7 +1922,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_device_priv_data->sas_target->sas_address);
if (!sas_device) {
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
@@ -1823,13 +1962,14 @@ _scsih_slave_configure(struct scsi_device *sdev)
ds, sas_device->enclosure_level,
sas_device->connector_name);
+ sas_device_put(sas_device);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
if (!ssp_target)
_scsih_display_sata_capabilities(ioc, handle, sdev);
- _scsih_change_queue_depth(sdev, qdepth);
+ scsih_change_queue_depth(sdev, qdepth);
if (ssp_target) {
sas_read_port_mode_page(sdev);
@@ -1840,7 +1980,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
}
/**
- * _scsih_bios_param - fetch head, sector, cylinder info for a disk
+ * scsih_bios_param - fetch head, sector, cylinder info for a disk
* @sdev: scsi device struct
* @bdev: pointer to block device context
* @capacity: device size (in 512 byte sectors)
@@ -1851,8 +1991,8 @@ _scsih_slave_configure(struct scsi_device *sdev)
*
* Return nothing.
*/
-static int
-_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+int
+scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int params[])
{
int heads;
@@ -2209,7 +2349,10 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
if (!priv_target)
return;
- device_str = "volume";
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
scsi_print_command(scmd);
if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) {
@@ -2219,8 +2362,7 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
device_str, (unsigned long long)priv_target->sas_address);
} else {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- priv_target->sas_address);
+ sas_device = __mpt3sas_get_sdev_from_target(ioc, priv_target);
if (sas_device) {
if (priv_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
@@ -2246,19 +2388,21 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd)
"enclosure level(0x%04x),connector name(%s)\n",
sas_device->enclosure_level,
sas_device->connector_name);
+
+ sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
}
/**
- * _scsih_abort - eh threads main abort routine
+ * scsih_abort - eh threads main abort routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_abort(struct scsi_cmnd *scmd)
+int
+scsih_abort(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
@@ -2311,21 +2455,23 @@ _scsih_abort(struct scsi_cmnd *scmd)
}
/**
- * _scsih_dev_reset - eh threads main device reset routine
+ * scsih_dev_reset - eh threads main device reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_dev_reset(struct scsi_cmnd *scmd)
+int
+scsih_dev_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
+ struct _sas_device *sas_device = NULL;
u16 handle;
int r;
+ struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
+
sdev_printk(KERN_INFO, scmd->device,
"attempting device reset! scmd(%p)\n", scmd);
_scsih_tm_display_info(ioc, scmd);
@@ -2344,12 +2490,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
handle = 0;
if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- sas_device_priv_data->sas_target->handle);
+ sas_device = mpt3sas_get_sdev_from_target(ioc,
+ target_priv_data);
if (sas_device)
handle = sas_device->volume_handle;
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else
handle = sas_device_priv_data->sas_target->handle;
@@ -2366,25 +2510,29 @@ _scsih_dev_reset(struct scsi_cmnd *scmd)
out:
sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
return r;
}
/**
- * _scsih_target_reset - eh threads main target reset routine
+ * scsih_target_reset - eh threads main target reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_target_reset(struct scsi_cmnd *scmd)
+int
+scsih_target_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
struct MPT3SAS_DEVICE *sas_device_priv_data;
- struct _sas_device *sas_device;
- unsigned long flags;
+ struct _sas_device *sas_device = NULL;
u16 handle;
int r;
struct scsi_target *starget = scmd->device->sdev_target;
+ struct MPT3SAS_TARGET *target_priv_data = starget->hostdata;
starget_printk(KERN_INFO, starget, "attempting target reset! scmd(%p)\n",
scmd);
@@ -2404,12 +2552,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
handle = 0;
if (sas_device_priv_data->sas_target->flags &
MPT_TARGET_FLAGS_RAID_COMPONENT) {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc,
- sas_device_priv_data->sas_target->handle);
+ sas_device = mpt3sas_get_sdev_from_target(ioc,
+ target_priv_data);
if (sas_device)
handle = sas_device->volume_handle;
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
} else
handle = sas_device_priv_data->sas_target->handle;
@@ -2426,18 +2572,22 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
out:
starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n",
((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
+
+ if (sas_device)
+ sas_device_put(sas_device);
+
return r;
}
/**
- * _scsih_host_reset - eh threads main host reset routine
+ * scsih_host_reset - eh threads main host reset routine
* @scmd: pointer to scsi command object
*
* Returns SUCCESS if command aborted else FAILED
*/
-static int
-_scsih_host_reset(struct scsi_cmnd *scmd)
+int
+scsih_host_reset(struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(scmd->device->host);
int r, retval;
@@ -2483,32 +2633,36 @@ _scsih_fw_event_add(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
return;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
+ fw_event_work_get(fw_event);
INIT_LIST_HEAD(&fw_event->list);
list_add_tail(&fw_event->list, &ioc->fw_event_list);
INIT_WORK(&fw_event->work, _firmware_event_work);
+ fw_event_work_get(fw_event);
queue_work(ioc->firmware_event_thread, &fw_event->work);
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
/**
- * _scsih_fw_event_free - delete fw_event
+ * _scsih_fw_event_del_from_list - delete fw_event from the list
* @ioc: per adapter object
* @fw_event: object describing the event
* Context: This function will acquire ioc->fw_event_lock.
*
- * This removes firmware event object from link list, frees associated memory.
+ * If the fw_event is on the fw_event_list, remove it and do a put.
*
* Return nothing.
*/
static void
-_scsih_fw_event_free(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work
+_scsih_fw_event_del_from_list(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work
*fw_event)
{
unsigned long flags;
spin_lock_irqsave(&ioc->fw_event_lock, flags);
- list_del(&fw_event->list);
- kfree(fw_event);
+ if (!list_empty(&fw_event->list)) {
+ list_del_init(&fw_event->list);
+ fw_event_work_put(fw_event);
+ }
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
}
@@ -2525,17 +2679,19 @@ mpt3sas_send_trigger_data_event(struct MPT3SAS_ADAPTER *ioc,
struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data)
{
struct fw_event_work *fw_event;
+ u16 sz;
if (ioc->is_driver_loading)
return;
- fw_event = kzalloc(sizeof(*fw_event) + sizeof(*event_data),
- GFP_ATOMIC);
+ sz = sizeof(*event_data);
+ fw_event = alloc_fw_event_work(sz);
if (!fw_event)
return;
fw_event->event = MPT3SAS_PROCESS_TRIGGER_DIAG;
fw_event->ioc = ioc;
memcpy(fw_event->event_data, event_data, sizeof(*event_data));
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -2551,12 +2707,13 @@ _scsih_error_recovery_delete_devices(struct MPT3SAS_ADAPTER *ioc)
if (ioc->is_driver_loading)
return;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_REMOVE_UNRESPONDING_DEVICES;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -2570,12 +2727,29 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc)
{
struct fw_event_work *fw_event;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_PORT_ENABLE_COMPLETE;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
+}
+
+static struct fw_event_work *dequeue_next_fw_event(struct MPT3SAS_ADAPTER *ioc)
+{
+ unsigned long flags;
+ struct fw_event_work *fw_event = NULL;
+
+ spin_lock_irqsave(&ioc->fw_event_lock, flags);
+ if (!list_empty(&ioc->fw_event_list)) {
+ fw_event = list_first_entry(&ioc->fw_event_list,
+ struct fw_event_work, list);
+ list_del_init(&fw_event->list);
+ }
+ spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
+
+ return fw_event;
}
/**
@@ -2590,17 +2764,25 @@ mpt3sas_port_enable_complete(struct MPT3SAS_ADAPTER *ioc)
static void
_scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc)
{
- struct fw_event_work *fw_event, *next;
+ struct fw_event_work *fw_event;
if (list_empty(&ioc->fw_event_list) ||
!ioc->firmware_event_thread || in_interrupt())
return;
- list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
- if (cancel_delayed_work_sync(&fw_event->delayed_work)) {
- _scsih_fw_event_free(ioc, fw_event);
- continue;
- }
+ while ((fw_event = dequeue_next_fw_event(ioc))) {
+ /*
+ * Wait on the fw_event to complete. If this returns 1, then
+ * the event was never executed, and we need a put for the
+ * reference the delayed_work had on the fw_event.
+ *
+ * If it did execute, we wait for it to finish, and the put will
+ * happen from _firmware_event_work()
+ */
+ if (cancel_delayed_work_sync(&fw_event->delayed_work))
+ fw_event_work_put(fw_event);
+
+ fw_event_work_put(fw_event);
}
}
@@ -2763,7 +2945,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct scsi_device *sdev;
struct _sas_device *sas_device;
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (!sas_device)
return;
@@ -2779,6 +2961,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle)
continue;
_scsih_internal_device_block(sdev, sas_device_priv_data);
}
+
+ sas_device_put(sas_device);
}
/**
@@ -2807,12 +2991,13 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT3SAS_ADAPTER *ioc,
if (mpt3sas_port->remote_identify.device_type ==
SAS_END_DEVICE) {
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device =
- mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- mpt3sas_port->remote_identify.sas_address);
- if (sas_device)
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
+ mpt3sas_port->remote_identify.sas_address);
+ if (sas_device) {
set_bit(sas_device->handle,
- ioc->blocking_handles);
+ ioc->blocking_handles);
+ sas_device_put(sas_device);
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
}
@@ -2880,7 +3065,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
Mpi2SCSITaskManagementRequest_t *mpi_request;
u16 smid;
- struct _sas_device *sas_device;
+ struct _sas_device *sas_device = NULL;
struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
u64 sas_address = 0;
unsigned long flags;
@@ -2913,7 +3098,7 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
return;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device && sas_device->starget &&
sas_device->starget->hostdata) {
sas_target_priv_data = sas_device->starget->hostdata;
@@ -2947,14 +3132,14 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!smid) {
delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
if (!delayed_tr)
- return;
+ goto out;
INIT_LIST_HEAD(&delayed_tr->list);
delayed_tr->handle = handle;
list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list);
dewtprintk(ioc, pr_info(MPT3SAS_FMT
"DELAYED:tr:handle(0x%04x), (open)\n",
ioc->name, handle));
- return;
+ goto out;
}
dewtprintk(ioc, pr_info(MPT3SAS_FMT
@@ -2968,6 +3153,10 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle)
mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
mpt3sas_base_put_smid_hi_priority(ioc, smid);
mpt3sas_trigger_master(ioc, MASTER_TRIGGER_DEVICE_REMOVAL);
+
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
}
/**
@@ -3337,7 +3526,7 @@ _scsih_set_volume_delete_flag(struct MPT3SAS_ADAPTER *ioc, u16 handle)
unsigned long flags;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device && raid_device->starget &&
raid_device->starget->hostdata) {
sas_target_priv_data =
@@ -3398,6 +3587,9 @@ _scsih_check_ir_config_unhide_events(struct MPT3SAS_ADAPTER *ioc,
a = 0;
b = 0;
+ if (ioc->is_warpdrive)
+ return;
+
/* Volume Resets for Deleted or Removed */
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
for (i = 0; i < event_data->NumElements; i++, element++) {
@@ -3634,8 +3826,9 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
}
+
/**
- * _scsih_qcmd - main scsi request entry point
+ * scsih_qcmd - main scsi request entry point
* @scmd: pointer to scsi command object
* @done: function pointer to be invoked on completion
*
@@ -3645,21 +3838,20 @@ _scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status)
* SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or
* SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full
*/
-static int
-_scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
+int
+scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
struct MPT3SAS_DEVICE *sas_device_priv_data;
struct MPT3SAS_TARGET *sas_target_priv_data;
+ struct _raid_device *raid_device;
Mpi2SCSIIORequest_t *mpi_request;
u32 mpi_control;
u16 smid;
u16 handle;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_SCSI)
scsi_print_command(scmd);
-#endif
sas_device_priv_data = scmd->device->hostdata;
if (!sas_device_priv_data || !sas_device_priv_data->sas_target) {
@@ -3709,8 +3901,11 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
/* set tags */
mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
- scmd->cmd_len != 32)
+ /* Make sure Device is not raid volume.
+ * We do not expose raid functionality to upper layer for warpdrive.
+ */
+ if (!ioc->is_warpdrive && !scsih_is_raid(&scmd->device->sdev_gendev)
+ && sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32)
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
smid = mpt3sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
@@ -3752,13 +3947,19 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
} else
ioc->build_zero_len_sge(ioc, &mpi_request->SGL);
+ raid_device = sas_target_priv_data->raid_device;
+ if (raid_device && raid_device->direct_io_enabled)
+ mpt3sas_setup_direct_io(ioc, scmd, raid_device, mpi_request,
+ smid);
+
if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) {
if (sas_target_priv_data->flags & MPT_TARGET_FASTPATH_IO) {
mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len |
MPI25_SCSIIO_IOFLAGS_FAST_PATH);
mpt3sas_base_put_smid_fast_path(ioc, smid, handle);
} else
- mpt3sas_base_put_smid_scsi_io(ioc, smid, handle);
+ mpt3sas_base_put_smid_scsi_io(ioc, smid,
+ le16_to_cpu(mpi_request->DevHandle));
} else
mpt3sas_base_put_smid_default(ioc, smid);
return 0;
@@ -3790,7 +3991,6 @@ _scsih_normalize_sense(char *sense_buffer, struct sense_info *data)
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_scsi_ioc_info - translated non-succesfull SCSI_IO request
* @ioc: per adapter object
@@ -3818,14 +4018,16 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
char *desc_scsi_state = ioc->tmp_string;
u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo);
struct _sas_device *sas_device = NULL;
- unsigned long flags;
struct scsi_target *starget = scmd->device->sdev_target;
struct MPT3SAS_TARGET *priv_target = starget->hostdata;
char *device_str = NULL;
if (!priv_target)
return;
- device_str = "volume";
+ if (ioc->hide_ir_msg)
+ device_str = "WarpDrive";
+ else
+ device_str = "volume";
if (log_info == 0x31170000)
return;
@@ -3946,9 +4148,7 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
pr_warn(MPT3SAS_FMT "\t%s wwid(0x%016llx)\n", ioc->name,
device_str, (unsigned long long)priv_target->sas_address);
} else {
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- priv_target->sas_address);
+ sas_device = mpt3sas_get_sdev_from_target(ioc, priv_target);
if (sas_device) {
pr_warn(MPT3SAS_FMT
"\tsas_address(0x%016llx), phy(%d)\n",
@@ -3967,8 +4167,9 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
" connector name( %s)\n", ioc->name,
sas_device->enclosure_level,
sas_device->connector_name);
+
+ sas_device_put(sas_device);
}
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
pr_warn(MPT3SAS_FMT
@@ -4003,7 +4204,6 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
_scsih_response_code(ioc, response_bytes[0]);
}
}
-#endif
/**
* _scsih_turn_on_pfa_led - illuminate PFA LED
@@ -4020,7 +4220,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
Mpi2SepRequest_t mpi_request;
struct _sas_device *sas_device;
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (!sas_device)
return;
@@ -4035,7 +4235,7 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
&mpi_request)) != 0) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name,
__FILE__, __LINE__, __func__);
- return;
+ goto out;
}
sas_device->pfa_led_on = 1;
@@ -4044,9 +4244,12 @@ _scsih_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
"enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n",
ioc->name, le16_to_cpu(mpi_reply.IOCStatus),
le32_to_cpu(mpi_reply.IOCLogInfo)));
- return;
+ goto out;
}
+out:
+ sas_device_put(sas_device);
}
+
/**
* _scsih_turn_off_pfa_led - turn off Fault LED
* @ioc: per adapter object
@@ -4085,6 +4288,7 @@ _scsih_turn_off_pfa_led(struct MPT3SAS_ADAPTER *ioc,
return;
}
}
+
/**
* _scsih_send_event_to_turn_on_pfa_led - fire delayed event
* @ioc: per adapter object
@@ -4098,13 +4302,14 @@ _scsih_send_event_to_turn_on_pfa_led(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{
struct fw_event_work *fw_event;
- fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(0);
if (!fw_event)
return;
fw_event->event = MPT3SAS_TURN_ON_PFA_LED;
fw_event->device_handle = handle;
fw_event->ioc = ioc;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
}
/**
@@ -4128,19 +4333,17 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
/* only handle non-raid devices */
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (!sas_device)
+ goto out_unlock;
+
starget = sas_device->starget;
sas_target_priv_data = starget->hostdata;
if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) ||
- ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)))
+ goto out_unlock;
+
if (sas_device->enclosure_handle != 0)
starget_printk(KERN_INFO, starget, "predicted fault, "
"enclosure logical id(0x%016llx), slot(%d)\n",
@@ -4163,7 +4366,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
if (!event_reply) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return;
+ goto out;
}
event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
@@ -4180,6 +4383,14 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle)
event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address);
mpt3sas_ctl_add_to_event_log(ioc, event_reply);
kfree(event_reply);
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
+ return;
+
+out_unlock:
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ goto out;
}
/**
@@ -4207,6 +4418,7 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
u32 log_info;
struct MPT3SAS_DEVICE *sas_device_priv_data;
u32 response_code = 0;
+ unsigned long flags;
mpi_reply = mpt3sas_base_get_reply_virt_addr(ioc, reply);
scmd = _scsih_scsi_lookup_get_clear(ioc, smid);
@@ -4228,6 +4440,24 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
ioc_status = le16_to_cpu(mpi_reply->IOCStatus);
+ /*
+ * WARPDRIVE: If direct_io is set then it is directIO,
+ * the failed direct I/O should be redirected to volume
+ */
+ if (mpt3sas_scsi_direct_io_get(ioc, smid) &&
+ ((ioc_status & MPI2_IOCSTATUS_MASK)
+ != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) {
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ ioc->scsi_lookup[smid - 1].scmd = scmd;
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ mpt3sas_scsi_direct_io_set(ioc, smid, 0);
+ memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
+ mpi_request->DevHandle =
+ cpu_to_le16(sas_device_priv_data->sas_target->handle);
+ mpt3sas_base_put_smid_scsi_io(ioc, smid,
+ sas_device_priv_data->sas_target->handle);
+ return 0;
+ }
/* turning off TLR */
scsi_state = mpi_reply->SCSIState;
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID)
@@ -4235,10 +4465,13 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF;
if (!sas_device_priv_data->tlr_snoop_check) {
sas_device_priv_data->tlr_snoop_check++;
- if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
- response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME)
- sas_device_priv_data->flags &=
- ~MPT_DEVICE_TLR_ON;
+ if (!ioc->is_warpdrive &&
+ !scsih_is_raid(&scmd->device->sdev_gendev) &&
+ sas_is_tlr_enabled(scmd->device) &&
+ response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) {
+ sas_disable_tlr(scmd->device);
+ sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n");
+ }
}
xfer_cnt = le32_to_cpu(mpi_reply->TransferCount);
@@ -4271,13 +4504,11 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
le16_to_cpu(mpi_reply->DevHandle));
mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq);
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (!(ioc->logging_level & MPT_DEBUG_REPLY) &&
((scmd->sense_buffer[2] == UNIT_ATTENTION) ||
(scmd->sense_buffer[2] == MEDIUM_ERROR) ||
(scmd->sense_buffer[2] == HARDWARE_ERROR)))
_scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid);
-#endif
}
switch (ioc_status) {
case MPI2_IOCSTATUS_BUSY:
@@ -4384,10 +4615,8 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY))
_scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid);
-#endif
out:
@@ -4933,13 +5162,11 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(sas_device_pg0.SASAddress);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_address);
- if (!sas_device) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!sas_device)
+ goto out_unlock;
if (unlikely(sas_device->handle != handle)) {
starget = sas_device->starget;
@@ -4967,20 +5194,25 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc,
pr_err(MPT3SAS_FMT
"device is not present handle(0x%04x), flags!!!\n",
ioc->name, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
+ goto out_unlock;
}
/* check if there were any issues with discovery */
if (_scsih_check_access_status(ioc, sas_address, handle,
- sas_device_pg0.AccessStatus)) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ sas_device_pg0.AccessStatus))
+ goto out_unlock;
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
_scsih_ublock_io_device(ioc, sas_address);
+ if (sas_device)
+ sas_device_put(sas_device);
+ return;
+
+out_unlock:
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (sas_device)
+ sas_device_put(sas_device);
}
/**
@@ -5005,7 +5237,6 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
u32 ioc_status;
u64 sas_address;
u32 device_info;
- unsigned long flags;
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
@@ -5041,13 +5272,12 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
sas_device_pg0.AccessStatus))
return -1;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
- sas_address);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
-
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
+ sas_address);
+ if (sas_device) {
+ sas_device_put(sas_device);
return -1;
+ }
sas_device = kzalloc(sizeof(struct _sas_device),
GFP_KERNEL);
@@ -5057,6 +5287,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
return 0;
}
+ kref_init(&sas_device->refcount);
sas_device->handle = handle;
if (_scsih_get_sas_address(ioc,
le16_to_cpu(sas_device_pg0.ParentDevHandle),
@@ -5098,6 +5329,7 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num,
else
_scsih_sas_device_add(ioc, sas_device);
+ sas_device_put(sas_device);
return 0;
}
@@ -5144,7 +5376,9 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
sas_target_priv_data->handle =
MPT3SAS_INVALID_DEVICE_HANDLE;
}
- mpt3sas_transport_port_remove(ioc,
+
+ if (!ioc->hide_drives)
+ mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
@@ -5180,11 +5414,8 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc,
"%s: exit: enclosure level(0x%04x), connector name(%s)\n",
ioc->name, __func__, sas_device->enclosure_level,
sas_device->connector_name));
-
- kfree(sas_device);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_topology_change_event_debug - debug for topology event
* @ioc: per adapter object
@@ -5262,7 +5493,6 @@ _scsih_sas_topology_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
}
}
-#endif
/**
* _scsih_sas_topology_change_event - handle topology changes
@@ -5287,10 +5517,8 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataSasTopologyChangeList_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_topology_change_event_debug(ioc, event_data);
-#endif
if (ioc->shost_recovery || ioc->remove_host || ioc->pci_error_recovery)
return 0;
@@ -5396,7 +5624,6 @@ _scsih_sas_topology_change_event(struct MPT3SAS_ADAPTER *ioc,
return 0;
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_device_status_change_event_debug - debug for device event
* @event_data: event data payload
@@ -5464,7 +5691,6 @@ _scsih_sas_device_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
event_data->ASC, event_data->ASCQ);
pr_info("\n");
}
-#endif
/**
* _scsih_sas_device_status_change_event - handle device status change
@@ -5486,11 +5712,9 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataSasDeviceStatusChange_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_device_status_change_event_debug(ioc,
event_data);
-#endif
/* In MPI Revision K (0xC), the internal device reset complete was
* implemented, so avoid setting tm_busy flag for older firmware.
@@ -5506,29 +5730,30 @@ _scsih_sas_device_status_change_event(struct MPT3SAS_ADAPTER *ioc,
spin_lock_irqsave(&ioc->sas_device_lock, flags);
sas_address = le64_to_cpu(event_data->SASAddress);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
sas_address);
- if (!sas_device || !sas_device->starget) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!sas_device || !sas_device->starget)
+ goto out;
target_priv_data = sas_device->starget->hostdata;
- if (!target_priv_data) {
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- return;
- }
+ if (!target_priv_data)
+ goto out;
if (event_data->ReasonCode ==
MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET)
target_priv_data->tm_busy = 1;
else
target_priv_data->tm_busy = 0;
+
+out:
+ if (sas_device)
+ sas_device_put(sas_device);
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure
* event
@@ -5563,7 +5788,6 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
(unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID),
le16_to_cpu(event_data->StartSlot));
}
-#endif
/**
* _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
@@ -5577,12 +5801,10 @@ static void
_scsih_sas_enclosure_dev_status_change_event(struct MPT3SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_enclosure_dev_status_change_event_debug(ioc,
(Mpi2EventDataSasEnclDevStatusChange_t *)
fw_event->event_data);
-#endif
}
/**
@@ -5762,17 +5984,15 @@ _scsih_sas_discovery_event(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventDataSasDiscovery_t *event_data =
(Mpi2EventDataSasDiscovery_t *) fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
pr_info(MPT3SAS_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
- if (event_data->DiscoveryStatus)
- pr_info("discovery_status(0x%08x)",
- le32_to_cpu(event_data->DiscoveryStatus));
- pr_info("\n");
+ if (event_data->DiscoveryStatus)
+ pr_info("discovery_status(0x%08x)",
+ le32_to_cpu(event_data->DiscoveryStatus));
+ pr_info("\n");
}
-#endif
if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED &&
!ioc->sas_hba.num_phys) {
@@ -5804,6 +6024,8 @@ _scsih_ir_fastpath(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phys_disk_num)
u16 ioc_status;
u32 log_info;
+ if (ioc->hba_mpi_version_belonged == MPI2_VERSION)
+ return rc;
mutex_lock(&ioc->scsih_cmds.mutex);
@@ -5971,7 +6193,7 @@ _scsih_sas_volume_delete(struct MPT3SAS_ADAPTER *ioc, u16 handle)
struct scsi_target *starget = NULL;
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device) {
if (raid_device->starget) {
starget = raid_device->starget;
@@ -6008,7 +6230,7 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
sas_device->volume_handle = 0;
sas_device->volume_wwid = 0;
@@ -6027,6 +6249,8 @@ _scsih_sas_pd_expose(struct MPT3SAS_ADAPTER *ioc,
/* exposing raid component */
if (starget)
starget_for_each_device(starget, NULL, _scsih_reprobe_lun);
+
+ sas_device_put(sas_device);
}
/**
@@ -6055,7 +6279,7 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
&volume_wwid);
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ sas_device = __mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
set_bit(handle, ioc->pd_handles);
if (sas_device->starget && sas_device->starget->hostdata) {
@@ -6073,8 +6297,11 @@ _scsih_sas_pd_hide(struct MPT3SAS_ADAPTER *ioc,
/* hiding raid component */
_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
+
if (starget)
starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun);
+
+ sas_device_put(sas_device);
}
/**
@@ -6107,7 +6334,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
Mpi2EventIrConfigElement_t *element)
{
struct _sas_device *sas_device;
- unsigned long flags;
u16 handle = le16_to_cpu(element->PhysDiskDevHandle);
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
@@ -6117,11 +6343,10 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
set_bit(handle, ioc->pd_handles);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
if (sas_device) {
_scsih_ir_fastpath(ioc, handle, element->PhysDiskNum);
+ sas_device_put(sas_device);
return;
}
@@ -6149,7 +6374,6 @@ _scsih_sas_pd_add(struct MPT3SAS_ADAPTER *ioc,
_scsih_add_device(ioc, handle, 0, 1);
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events
* @ioc: per adapter object
@@ -6229,7 +6453,6 @@ _scsih_sas_ir_config_change_event_debug(struct MPT3SAS_ADAPTER *ioc,
element->PhysDiskNum);
}
}
-#endif
/**
* _scsih_sas_ir_config_change_event - handle ir configuration change events
@@ -6250,18 +6473,16 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
(Mpi2EventDataIrConfigChangeList_t *)
fw_event->event_data;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) &&
+ (!ioc->hide_ir_msg))
_scsih_sas_ir_config_change_event_debug(ioc, event_data);
-#endif
-
foreign_config = (le32_to_cpu(event_data->Flags) &
MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0;
element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0];
- if (ioc->shost_recovery) {
-
+ if (ioc->shost_recovery &&
+ ioc->hba_mpi_version_belonged != MPI2_VERSION) {
for (i = 0; i < event_data->NumElements; i++, element++) {
if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_HIDE)
_scsih_ir_fastpath(ioc,
@@ -6270,6 +6491,7 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
}
return;
}
+
for (i = 0; i < event_data->NumElements; i++, element++) {
switch (element->ReasonCode) {
@@ -6285,16 +6507,20 @@ _scsih_sas_ir_config_change_event(struct MPT3SAS_ADAPTER *ioc,
le16_to_cpu(element->VolDevHandle));
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED:
- _scsih_sas_pd_hide(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_hide(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED:
- _scsih_sas_pd_expose(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_expose(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_HIDE:
- _scsih_sas_pd_add(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_add(ioc, element);
break;
case MPI2_EVENT_IR_CHANGE_RC_UNHIDE:
- _scsih_sas_pd_delete(ioc, element);
+ if (!ioc->is_warpdrive)
+ _scsih_sas_pd_delete(ioc, element);
break;
}
}
@@ -6329,10 +6555,11 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->VolDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
- le32_to_cpu(event_data->PreviousValue), state));
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ ioc->name, __func__, handle,
+ le32_to_cpu(event_data->PreviousValue), state));
switch (state) {
case MPI2_RAID_VOL_STATE_MISSING:
case MPI2_RAID_VOL_STATE_FAILED:
@@ -6344,7 +6571,7 @@ _scsih_sas_ir_volume_event(struct MPT3SAS_ADAPTER *ioc,
case MPI2_RAID_VOL_STATE_OPTIMAL:
spin_lock_irqsave(&ioc->raid_device_lock, flags);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
if (raid_device)
@@ -6398,7 +6625,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
u16 handle, parent_handle;
u32 state;
struct _sas_device *sas_device;
- unsigned long flags;
Mpi2ConfigReply_t mpi_reply;
Mpi2SasDevicePage0_t sas_device_pg0;
u32 ioc_status;
@@ -6415,10 +6641,12 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
handle = le16_to_cpu(event_data->PhysDiskDevHandle);
state = le32_to_cpu(event_data->NewValue);
- dewtprintk(ioc, pr_info(MPT3SAS_FMT
- "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
- ioc->name, __func__, handle,
+ if (!ioc->hide_ir_msg)
+ dewtprintk(ioc, pr_info(MPT3SAS_FMT
+ "%s: handle(0x%04x), old(0x%08x), new(0x%08x)\n",
+ ioc->name, __func__, handle,
le32_to_cpu(event_data->PreviousValue), state));
+
switch (state) {
case MPI2_RAID_PD_STATE_ONLINE:
case MPI2_RAID_PD_STATE_DEGRADED:
@@ -6426,13 +6654,14 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
case MPI2_RAID_PD_STATE_OPTIMAL:
case MPI2_RAID_PD_STATE_HOT_SPARE:
- set_bit(handle, ioc->pd_handles);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (!ioc->is_warpdrive)
+ set_bit(handle, ioc->pd_handles);
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device_put(sas_device);
return;
+ }
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
@@ -6467,7 +6696,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT3SAS_ADAPTER *ioc,
}
}
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
/**
* _scsih_sas_ir_operation_status_event_debug - debug for IR op event
* @ioc: per adapter object
@@ -6509,7 +6737,6 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT3SAS_ADAPTER *ioc,
le16_to_cpu(event_data->VolDevHandle),
event_data->PercentComplete);
}
-#endif
/**
* _scsih_sas_ir_operation_status_event - handle RAID operation events
@@ -6530,18 +6757,17 @@ _scsih_sas_ir_operation_status_event(struct MPT3SAS_ADAPTER *ioc,
unsigned long flags;
u16 handle;
-#ifdef CONFIG_SCSI_MPT3SAS_LOGGING
- if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
+ if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) &&
+ (!ioc->hide_ir_msg))
_scsih_sas_ir_operation_status_event_debug(ioc,
event_data);
-#endif
/* code added for raid transport support */
if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) {
spin_lock_irqsave(&ioc->raid_device_lock, flags);
handle = le16_to_cpu(event_data->VolDevHandle);
- raid_device = _scsih_raid_device_find_by_handle(ioc, handle);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
if (raid_device)
raid_device->percent_complete =
event_data->PercentComplete;
@@ -6703,7 +6929,7 @@ static void
_scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
u16 handle)
{
- struct MPT3SAS_TARGET *sas_target_priv_data;
+ struct MPT3SAS_TARGET *sas_target_priv_data = NULL;
struct scsi_target *starget;
struct _raid_device *raid_device;
unsigned long flags;
@@ -6722,6 +6948,13 @@ _scsih_mark_responding_raid_device(struct MPT3SAS_ADAPTER *ioc, u64 wwid,
starget_printk(KERN_INFO, raid_device->starget,
"handle(0x%04x), wwid(0x%016llx)\n", handle,
(unsigned long long)raid_device->wwid);
+
+ /*
+ * WARPDRIVE: The handles of the PDs might have changed
+ * across the host reset so re-initialize the
+ * required data for Direct IO
+ */
+ mpt3sas_init_warpdrive_properties(ioc, raid_device);
spin_lock_irqsave(&ioc->raid_device_lock, flags);
if (raid_device->handle == handle) {
spin_unlock_irqrestore(&ioc->raid_device_lock,
@@ -6791,6 +7024,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
}
/* refresh the pd_handles */
+ if (!ioc->is_warpdrive) {
phys_disk_num = 0xFF;
memset(ioc->pd_handles, 0, ioc->pd_handles_sz);
while (!(mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
@@ -6804,6 +7038,7 @@ _scsih_search_responding_raid_devices(struct MPT3SAS_ADAPTER *ioc)
handle = le16_to_cpu(pd_pg0.DevHandle);
set_bit(handle, ioc->pd_handles);
}
+ }
out:
pr_info(MPT3SAS_FMT "search for responding raid volumes: complete\n",
ioc->name);
@@ -6906,6 +7141,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
struct _raid_device *raid_device, *raid_device_next;
struct list_head tmp_list;
unsigned long flags;
+ LIST_HEAD(head);
pr_info(MPT3SAS_FMT "removing unresponding devices: start\n",
ioc->name);
@@ -6913,14 +7149,28 @@ _scsih_remove_unresponding_sas_devices(struct MPT3SAS_ADAPTER *ioc)
/* removing unresponding end devices */
pr_info(MPT3SAS_FMT "removing unresponding devices: end-devices\n",
ioc->name);
+ /*
+ * Iterate, pulling off devices marked as non-responding. We become the
+ * owner for the reference the list had on any object we prune.
+ */
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
list_for_each_entry_safe(sas_device, sas_device_next,
&ioc->sas_device_list, list) {
if (!sas_device->responding)
- mpt3sas_device_remove_by_sas_address(ioc,
- sas_device->sas_address);
+ list_move_tail(&sas_device->list, &head);
else
sas_device->responding = 0;
}
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ /*
+ * Now, uninitialize and remove the unresponding devices we pruned.
+ */
+ list_for_each_entry_safe(sas_device, sas_device_next, &head, list) {
+ _scsih_remove_device(ioc, sas_device);
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
/* removing unresponding volumes */
if (ioc->ir_firmware) {
@@ -7074,11 +7324,11 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
}
phys_disk_num = pd_pg0.PhysDiskNum;
handle = le16_to_cpu(pd_pg0.DevHandle);
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ sas_device = mpt3sas_get_sdev_by_handle(ioc, handle);
+ if (sas_device) {
+ sas_device_put(sas_device);
continue;
+ }
if (mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply,
&sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE,
handle) != 0)
@@ -7199,12 +7449,12 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc)
if (!(_scsih_is_end_device(
le32_to_cpu(sas_device_pg0.DeviceInfo))))
continue;
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
le64_to_cpu(sas_device_pg0.SASAddress));
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
- if (sas_device)
+ if (sas_device) {
+ sas_device_put(sas_device);
continue;
+ }
parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle);
if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) {
pr_info(MPT3SAS_FMT "\tBEFORE adding end device: " \
@@ -7296,10 +7546,11 @@ mpt3sas_scsih_reset_handler(struct MPT3SAS_ADAPTER *ioc, int reset_phase)
static void
_mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
{
+ _scsih_fw_event_del_from_list(ioc, fw_event);
+
/* the queue is being flushed so ignore this event */
- if (ioc->remove_host ||
- ioc->pci_error_recovery) {
- _scsih_fw_event_free(ioc, fw_event);
+ if (ioc->remove_host || ioc->pci_error_recovery) {
+ fw_event_work_put(fw_event);
return;
}
@@ -7310,8 +7561,16 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
fw_event->event_data);
break;
case MPT3SAS_REMOVE_UNRESPONDING_DEVICES:
- while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery)
+ while (scsi_host_in_recovery(ioc->shost) ||
+ ioc->shost_recovery) {
+ /*
+ * If we're unloading, bail. Otherwise, this can become
+ * an infinite loop.
+ */
+ if (ioc->remove_host)
+ goto out;
ssleep(1);
+ }
_scsih_remove_unresponding_sas_devices(ioc);
_scsih_scan_for_devices_after_reset(ioc);
break;
@@ -7356,7 +7615,8 @@ _mpt3sas_fw_work(struct MPT3SAS_ADAPTER *ioc, struct fw_event_work *fw_event)
_scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
}
- _scsih_fw_event_free(ioc, fw_event);
+out:
+ fw_event_work_put(fw_event);
}
/**
@@ -7453,7 +7713,53 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
(Mpi2EventDataIrVolume_t *)
mpi_reply->EventData);
break;
+ case MPI2_EVENT_LOG_ENTRY_ADDED:
+ {
+ Mpi2EventDataLogEntryAdded_t *log_entry;
+ u32 *log_code;
+
+ if (!ioc->is_warpdrive)
+ break;
+
+ log_entry = (Mpi2EventDataLogEntryAdded_t *)
+ mpi_reply->EventData;
+ log_code = (u32 *)log_entry->LogData;
+ if (le16_to_cpu(log_entry->LogEntryQualifier)
+ != MPT2_WARPDRIVE_LOGENTRY)
+ break;
+
+ switch (le32_to_cpu(*log_code)) {
+ case MPT2_WARPDRIVE_LC_SSDT:
+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
+ "IO Throttling has occurred in the WarpDrive "
+ "subsystem. Check WarpDrive documentation for "
+ "additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLW:
+ pr_warn(MPT3SAS_FMT "WarpDrive Warning: "
+ "Program/Erase Cycles for the WarpDrive subsystem "
+ "in degraded range. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_SSDLF:
+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
+ "There are no Program/Erase Cycles for the "
+ "WarpDrive subsystem. The storage device will be "
+ "in read-only mode. Check WarpDrive documentation "
+ "for additional details.\n", ioc->name);
+ break;
+ case MPT2_WARPDRIVE_LC_BRMF:
+ pr_err(MPT3SAS_FMT "WarpDrive Fatal Error: "
+ "The Backup Rail Monitor has failed on the "
+ "WarpDrive subsystem. Check WarpDrive "
+ "documentation for additional details.\n",
+ ioc->name);
+ break;
+ }
+
+ break;
+ }
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
case MPI2_EVENT_IR_OPERATION_STATUS:
case MPI2_EVENT_SAS_DISCOVERY:
@@ -7472,7 +7778,7 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
}
sz = le16_to_cpu(mpi_reply->EventDataLength) * 4;
- fw_event = kzalloc(sizeof(*fw_event) + sz, GFP_ATOMIC);
+ fw_event = alloc_fw_event_work(sz);
if (!fw_event) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
@@ -7485,39 +7791,10 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
fw_event->VP_ID = mpi_reply->VP_ID;
fw_event->event = event;
_scsih_fw_event_add(ioc, fw_event);
+ fw_event_work_put(fw_event);
return 1;
}
-/* shost template */
-static struct scsi_host_template scsih_driver_template = {
- .module = THIS_MODULE,
- .name = "Fusion MPT SAS Host",
- .proc_name = MPT3SAS_DRIVER_NAME,
- .queuecommand = _scsih_qcmd,
- .target_alloc = _scsih_target_alloc,
- .slave_alloc = _scsih_slave_alloc,
- .slave_configure = _scsih_slave_configure,
- .target_destroy = _scsih_target_destroy,
- .slave_destroy = _scsih_slave_destroy,
- .scan_finished = _scsih_scan_finished,
- .scan_start = _scsih_scan_start,
- .change_queue_depth = _scsih_change_queue_depth,
- .eh_abort_handler = _scsih_abort,
- .eh_device_reset_handler = _scsih_dev_reset,
- .eh_target_reset_handler = _scsih_target_reset,
- .eh_host_reset_handler = _scsih_host_reset,
- .bios_param = _scsih_bios_param,
- .can_queue = 1,
- .this_id = -1,
- .sg_tablesize = MPT3SAS_SG_DEPTH,
- .max_sectors = 32767,
- .cmd_per_lun = 7,
- .use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = mpt3sas_host_attrs,
- .sdev_attrs = mpt3sas_dev_attrs,
- .track_queue_depth = 1,
-};
-
/**
* _scsih_expander_node_remove - removing expander device from list.
* @ioc: per adapter object
@@ -7613,7 +7890,8 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
mpi_request->Function = MPI2_FUNCTION_RAID_ACTION;
mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED;
- pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
+ if (!ioc->hide_ir_msg)
+ pr_info(MPT3SAS_FMT "IR shutdown (sending)\n", ioc->name);
init_completion(&ioc->scsih_cmds.done);
mpt3sas_base_put_smid_default(ioc, smid);
wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ);
@@ -7626,10 +7904,11 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
if (ioc->scsih_cmds.status & MPT3_CMD_REPLY_VALID) {
mpi_reply = ioc->scsih_cmds.reply;
- pr_info(MPT3SAS_FMT
- "IR shutdown (complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
- ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
- le32_to_cpu(mpi_reply->IOCLogInfo));
+ if (!ioc->hide_ir_msg)
+ pr_info(MPT3SAS_FMT "IR shutdown "
+ "(complete): ioc_status(0x%04x), loginfo(0x%08x)\n",
+ ioc->name, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo));
}
out:
@@ -7638,13 +7917,13 @@ _scsih_ir_shutdown(struct MPT3SAS_ADAPTER *ioc)
}
/**
- * _scsih_remove - detach and remove add host
+ * scsih_remove - detach and remove add host
* @pdev: PCI device struct
*
* Routine called when unloading the driver.
* Return nothing.
*/
-static void _scsih_remove(struct pci_dev *pdev)
+void scsih_remove(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7705,18 +7984,20 @@ static void _scsih_remove(struct pci_dev *pdev)
sas_remove_host(shost);
scsi_remove_host(shost);
mpt3sas_base_detach(ioc);
+ spin_lock(&gioc_lock);
list_del(&ioc->list);
+ spin_unlock(&gioc_lock);
scsi_host_put(shost);
}
/**
- * _scsih_shutdown - routine call during system shutdown
+ * scsih_shutdown - routine call during system shutdown
* @pdev: PCI device struct
*
* Return nothing.
*/
-static void
-_scsih_shutdown(struct pci_dev *pdev)
+void
+scsih_shutdown(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7794,6 +8075,8 @@ _scsih_probe_boot_devices(struct MPT3SAS_ADAPTER *ioc)
list_move_tail(&sas_device->list, &ioc->sas_device_list);
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ if (ioc->hide_drives)
+ return;
if (!mpt3sas_transport_port_add(ioc, handle,
sas_address_parent)) {
_scsih_sas_device_remove(ioc, sas_device);
@@ -7831,6 +8114,48 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
}
}
+static struct _sas_device *get_next_sas_device(struct MPT3SAS_ADAPTER *ioc)
+{
+ struct _sas_device *sas_device = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ if (!list_empty(&ioc->sas_device_init_list)) {
+ sas_device = list_first_entry(&ioc->sas_device_init_list,
+ struct _sas_device, list);
+ sas_device_get(sas_device);
+ }
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ return sas_device;
+}
+
+static void sas_device_make_active(struct MPT3SAS_ADAPTER *ioc,
+ struct _sas_device *sas_device)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+
+ /*
+ * Since we dropped the lock during the call to port_add(), we need to
+ * be careful here that somebody else didn't move or delete this item
+ * while we were busy with other things.
+ *
+ * If it was on the list, we need a put() for the reference the list
+ * had. Either way, we need a get() for the destination list.
+ */
+ if (!list_empty(&sas_device->list)) {
+ list_del_init(&sas_device->list);
+ sas_device_put(sas_device);
+ }
+
+ sas_device_get(sas_device);
+ list_add_tail(&sas_device->list, &ioc->sas_device_list);
+
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+}
+
/**
* _scsih_probe_sas - reporting sas devices to sas transport
* @ioc: per adapter object
@@ -7840,17 +8165,16 @@ _scsih_probe_raid(struct MPT3SAS_ADAPTER *ioc)
static void
_scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
{
- struct _sas_device *sas_device, *next;
- unsigned long flags;
+ struct _sas_device *sas_device;
- /* SAS Device List */
- list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list,
- list) {
+ if (ioc->hide_drives)
+ return;
+ while ((sas_device = get_next_sas_device(ioc))) {
if (!mpt3sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent)) {
- list_del(&sas_device->list);
- kfree(sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ sas_device_put(sas_device);
continue;
} else if (!sas_device->starget) {
/*
@@ -7863,15 +8187,13 @@ _scsih_probe_sas(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent);
- list_del(&sas_device->list);
- kfree(sas_device);
+ _scsih_sas_device_remove(ioc, sas_device);
+ sas_device_put(sas_device);
continue;
}
}
-
- spin_lock_irqsave(&ioc->sas_device_lock, flags);
- list_move_tail(&sas_device->list, &ioc->sas_device_list);
- spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+ sas_device_make_active(ioc, sas_device);
+ sas_device_put(sas_device);
}
}
@@ -7908,15 +8230,15 @@ _scsih_probe_devices(struct MPT3SAS_ADAPTER *ioc)
}
/**
- * _scsih_scan_start - scsi lld callback for .scan_start
+ * scsih_scan_start - scsi lld callback for .scan_start
* @shost: SCSI host pointer
*
* The shost has the ability to discover targets on its own instead
* of scanning the entire bus. In our implemention, we will kick off
* firmware discovery.
*/
-static void
-_scsih_scan_start(struct Scsi_Host *shost)
+void
+scsih_scan_start(struct Scsi_Host *shost)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
int rc;
@@ -7934,7 +8256,7 @@ _scsih_scan_start(struct Scsi_Host *shost)
}
/**
- * _scsih_scan_finished - scsi lld callback for .scan_finished
+ * scsih_scan_finished - scsi lld callback for .scan_finished
* @shost: SCSI host pointer
* @time: elapsed time of the scan in jiffies
*
@@ -7942,8 +8264,8 @@ _scsih_scan_start(struct Scsi_Host *shost)
* scsi_host and the elapsed time of the scan in jiffies. In our implemention,
* we wait for firmware discovery to complete, then return 1.
*/
-static int
-_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
+int
+scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
{
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -7987,6 +8309,124 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
return 1;
}
+/* shost template for SAS 2.0 HBA devices */
+static struct scsi_host_template mpt2sas_driver_template = {
+ .module = THIS_MODULE,
+ .name = "Fusion MPT SAS Host",
+ .proc_name = MPT2SAS_DRIVER_NAME,
+ .queuecommand = scsih_qcmd,
+ .target_alloc = scsih_target_alloc,
+ .slave_alloc = scsih_slave_alloc,
+ .slave_configure = scsih_slave_configure,
+ .target_destroy = scsih_target_destroy,
+ .slave_destroy = scsih_slave_destroy,
+ .scan_finished = scsih_scan_finished,
+ .scan_start = scsih_scan_start,
+ .change_queue_depth = scsih_change_queue_depth,
+ .eh_abort_handler = scsih_abort,
+ .eh_device_reset_handler = scsih_dev_reset,
+ .eh_target_reset_handler = scsih_target_reset,
+ .eh_host_reset_handler = scsih_host_reset,
+ .bios_param = scsih_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = MPT2SAS_SG_DEPTH,
+ .max_sectors = 32767,
+ .cmd_per_lun = 7,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mpt3sas_host_attrs,
+ .sdev_attrs = mpt3sas_dev_attrs,
+ .track_queue_depth = 1,
+};
+
+/* raid transport support for SAS 2.0 HBA devices */
+static struct raid_function_template mpt2sas_raid_functions = {
+ .cookie = &mpt2sas_driver_template,
+ .is_raid = scsih_is_raid,
+ .get_resync = scsih_get_resync,
+ .get_state = scsih_get_state,
+};
+
+/* shost template for SAS 3.0 HBA devices */
+static struct scsi_host_template mpt3sas_driver_template = {
+ .module = THIS_MODULE,
+ .name = "Fusion MPT SAS Host",
+ .proc_name = MPT3SAS_DRIVER_NAME,
+ .queuecommand = scsih_qcmd,
+ .target_alloc = scsih_target_alloc,
+ .slave_alloc = scsih_slave_alloc,
+ .slave_configure = scsih_slave_configure,
+ .target_destroy = scsih_target_destroy,
+ .slave_destroy = scsih_slave_destroy,
+ .scan_finished = scsih_scan_finished,
+ .scan_start = scsih_scan_start,
+ .change_queue_depth = scsih_change_queue_depth,
+ .eh_abort_handler = scsih_abort,
+ .eh_device_reset_handler = scsih_dev_reset,
+ .eh_target_reset_handler = scsih_target_reset,
+ .eh_host_reset_handler = scsih_host_reset,
+ .bios_param = scsih_bios_param,
+ .can_queue = 1,
+ .this_id = -1,
+ .sg_tablesize = MPT3SAS_SG_DEPTH,
+ .max_sectors = 32767,
+ .cmd_per_lun = 7,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = mpt3sas_host_attrs,
+ .sdev_attrs = mpt3sas_dev_attrs,
+ .track_queue_depth = 1,
+};
+
+/* raid transport support for SAS 3.0 HBA devices */
+static struct raid_function_template mpt3sas_raid_functions = {
+ .cookie = &mpt3sas_driver_template,
+ .is_raid = scsih_is_raid,
+ .get_resync = scsih_get_resync,
+ .get_state = scsih_get_state,
+};
+
+/**
+ * _scsih_determine_hba_mpi_version - determine in which MPI version class
+ * this device belongs to.
+ * @pdev: PCI device struct
+ *
+ * return MPI2_VERSION for SAS 2.0 HBA devices,
+ * MPI25_VERSION for SAS 3.0 HBA devices.
+ */
+u16
+_scsih_determine_hba_mpi_version(struct pci_dev *pdev)
+{
+
+ switch (pdev->device) {
+ case MPI2_MFGPAGE_DEVID_SSS6200:
+ case MPI2_MFGPAGE_DEVID_SAS2004:
+ case MPI2_MFGPAGE_DEVID_SAS2008:
+ case MPI2_MFGPAGE_DEVID_SAS2108_1:
+ case MPI2_MFGPAGE_DEVID_SAS2108_2:
+ case MPI2_MFGPAGE_DEVID_SAS2108_3:
+ case MPI2_MFGPAGE_DEVID_SAS2116_1:
+ case MPI2_MFGPAGE_DEVID_SAS2116_2:
+ case MPI2_MFGPAGE_DEVID_SAS2208_1:
+ case MPI2_MFGPAGE_DEVID_SAS2208_2:
+ case MPI2_MFGPAGE_DEVID_SAS2208_3:
+ case MPI2_MFGPAGE_DEVID_SAS2208_4:
+ case MPI2_MFGPAGE_DEVID_SAS2208_5:
+ case MPI2_MFGPAGE_DEVID_SAS2208_6:
+ case MPI2_MFGPAGE_DEVID_SAS2308_1:
+ case MPI2_MFGPAGE_DEVID_SAS2308_2:
+ case MPI2_MFGPAGE_DEVID_SAS2308_3:
+ return MPI2_VERSION;
+ case MPI25_MFGPAGE_DEVID_SAS3004:
+ case MPI25_MFGPAGE_DEVID_SAS3008:
+ case MPI25_MFGPAGE_DEVID_SAS3108_1:
+ case MPI25_MFGPAGE_DEVID_SAS3108_2:
+ case MPI25_MFGPAGE_DEVID_SAS3108_5:
+ case MPI25_MFGPAGE_DEVID_SAS3108_6:
+ return MPI25_VERSION;
+ }
+ return 0;
+}
+
/**
* _scsih_probe - attach and add scsi host
* @pdev: PCI device struct
@@ -7994,26 +8434,72 @@ _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time)
*
* Returns 0 success, anything else error.
*/
-static int
+int
_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct MPT3SAS_ADAPTER *ioc;
- struct Scsi_Host *shost;
+ struct Scsi_Host *shost = NULL;
int rv;
+ u16 hba_mpi_version;
- shost = scsi_host_alloc(&scsih_driver_template,
- sizeof(struct MPT3SAS_ADAPTER));
- if (!shost)
+ /* Determine in which MPI version class this pci device belongs */
+ hba_mpi_version = _scsih_determine_hba_mpi_version(pdev);
+ if (hba_mpi_version == 0)
return -ENODEV;
- /* init local params */
- ioc = shost_priv(shost);
- memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ /* Enumerate only SAS 2.0 HBA's if hbas_to_enumerate is one,
+ * for other generation HBA's return with -ENODEV
+ */
+ if ((hbas_to_enumerate == 1) && (hba_mpi_version != MPI2_VERSION))
+ return -ENODEV;
+
+ /* Enumerate only SAS 3.0 HBA's if hbas_to_enumerate is two,
+ * for other generation HBA's return with -ENODEV
+ */
+ if ((hbas_to_enumerate == 2) && (hba_mpi_version != MPI25_VERSION))
+ return -ENODEV;
+
+ switch (hba_mpi_version) {
+ case MPI2_VERSION:
+ /* Use mpt2sas driver host template for SAS 2.0 HBA's */
+ shost = scsi_host_alloc(&mpt2sas_driver_template,
+ sizeof(struct MPT3SAS_ADAPTER));
+ if (!shost)
+ return -ENODEV;
+ ioc = shost_priv(shost);
+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ ioc->hba_mpi_version_belonged = hba_mpi_version;
+ ioc->id = mpt2_ids++;
+ sprintf(ioc->driver_name, "%s", MPT2SAS_DRIVER_NAME);
+ if (pdev->device == MPI2_MFGPAGE_DEVID_SSS6200) {
+ ioc->is_warpdrive = 1;
+ ioc->hide_ir_msg = 1;
+ } else
+ ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS;
+ break;
+ case MPI25_VERSION:
+ /* Use mpt3sas driver host template for SAS 3.0 HBA's */
+ shost = scsi_host_alloc(&mpt3sas_driver_template,
+ sizeof(struct MPT3SAS_ADAPTER));
+ if (!shost)
+ return -ENODEV;
+ ioc = shost_priv(shost);
+ memset(ioc, 0, sizeof(struct MPT3SAS_ADAPTER));
+ ioc->hba_mpi_version_belonged = hba_mpi_version;
+ ioc->id = mpt3_ids++;
+ sprintf(ioc->driver_name, "%s", MPT3SAS_DRIVER_NAME);
+ if (pdev->revision >= SAS3_PCI_DEVICE_C0_REVISION)
+ ioc->msix96_vector = 1;
+ break;
+ default:
+ return -ENODEV;
+ }
+
INIT_LIST_HEAD(&ioc->list);
+ spin_lock(&gioc_lock);
list_add_tail(&ioc->list, &mpt3sas_ioc_list);
+ spin_unlock(&gioc_lock);
ioc->shost = shost;
- ioc->id = mpt_ids++;
- sprintf(ioc->name, "%s%d", MPT3SAS_DRIVER_NAME, ioc->id);
ioc->pdev = pdev;
ioc->scsi_io_cb_idx = scsi_io_cb_idx;
ioc->tm_cb_idx = tm_cb_idx;
@@ -8030,6 +8516,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds;
/* misc semaphores and spin locks */
mutex_init(&ioc->reset_in_progress_mutex);
+ /* initializing pci_access_mutex lock */
+ mutex_init(&ioc->pci_access_mutex);
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
spin_lock_init(&ioc->scsi_lookup_lock);
spin_lock_init(&ioc->sas_device_lock);
@@ -8048,6 +8536,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->delayed_tr_volume_list);
INIT_LIST_HEAD(&ioc->reply_queue_list);
+ sprintf(ioc->name, "%s_cm%d", ioc->driver_name, ioc->id);
+
/* init shost parameters */
shost->max_cmd_len = 32;
shost->max_lun = max_lun;
@@ -8086,7 +8576,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
/* event thread */
snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
- "fw_event%d", ioc->id);
+ "fw_event_%s%d", ioc->driver_name, ioc->id);
ioc->firmware_event_thread = alloc_ordered_workqueue(
ioc->firmware_event_name, WQ_MEM_RECLAIM);
if (!ioc->firmware_event_thread) {
@@ -8103,6 +8593,21 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rv = -ENODEV;
goto out_attach_fail;
}
+
+ if (ioc->is_warpdrive) {
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS)
+ ioc->hide_drives = 0;
+ else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS)
+ ioc->hide_drives = 1;
+ else {
+ if (mpt3sas_get_num_volumes(ioc))
+ ioc->hide_drives = 1;
+ else
+ ioc->hide_drives = 0;
+ }
+ } else
+ ioc->hide_drives = 0;
+
rv = scsi_add_host(shost, &pdev->dev);
if (rv) {
pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n",
@@ -8117,21 +8622,23 @@ out_add_shost_fail:
out_attach_fail:
destroy_workqueue(ioc->firmware_event_thread);
out_thread_fail:
+ spin_lock(&gioc_lock);
list_del(&ioc->list);
+ spin_unlock(&gioc_lock);
scsi_host_put(shost);
return rv;
}
#ifdef CONFIG_PM
/**
- * _scsih_suspend - power management suspend main entry point
+ * scsih_suspend - power management suspend main entry point
* @pdev: PCI device struct
* @state: PM state change to (usually PCI_D3)
*
* Returns 0 success, anything else error.
*/
-static int
-_scsih_suspend(struct pci_dev *pdev, pm_message_t state)
+int
+scsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8152,13 +8659,13 @@ _scsih_suspend(struct pci_dev *pdev, pm_message_t state)
}
/**
- * _scsih_resume - power management resume main entry point
+ * scsih_resume - power management resume main entry point
* @pdev: PCI device struct
*
* Returns 0 success, anything else error.
*/
-static int
-_scsih_resume(struct pci_dev *pdev)
+int
+scsih_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8185,7 +8692,7 @@ _scsih_resume(struct pci_dev *pdev)
#endif /* CONFIG_PM */
/**
- * _scsih_pci_error_detected - Called when a PCI error is detected.
+ * scsih_pci_error_detected - Called when a PCI error is detected.
* @pdev: PCI device struct
* @state: PCI channel state
*
@@ -8194,8 +8701,8 @@ _scsih_resume(struct pci_dev *pdev)
* Return value:
* PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT
*/
-static pci_ers_result_t
-_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
+pci_ers_result_t
+scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8224,15 +8731,15 @@ _scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state)
}
/**
- * _scsih_pci_slot_reset - Called when PCI slot has been reset.
+ * scsih_pci_slot_reset - Called when PCI slot has been reset.
* @pdev: PCI device struct
*
* Description: This routine is called by the pci error recovery
* code after the PCI slot has been reset, just before we
* should resume normal operations.
*/
-static pci_ers_result_t
-_scsih_pci_slot_reset(struct pci_dev *pdev)
+pci_ers_result_t
+scsih_pci_slot_reset(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8261,15 +8768,15 @@ _scsih_pci_slot_reset(struct pci_dev *pdev)
}
/**
- * _scsih_pci_resume() - resume normal ops after PCI reset
+ * scsih_pci_resume() - resume normal ops after PCI reset
* @pdev: pointer to PCI device
*
* Called when the error recovery driver tells us that its
* OK to resume normal operation. Use completion to allow
* halted scsi ops to resume.
*/
-static void
-_scsih_pci_resume(struct pci_dev *pdev)
+void
+scsih_pci_resume(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8282,11 +8789,11 @@ _scsih_pci_resume(struct pci_dev *pdev)
}
/**
- * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
+ * scsih_pci_mmio_enabled - Enable MMIO and dump debug registers
* @pdev: pointer to PCI device
*/
-static pci_ers_result_t
-_scsih_pci_mmio_enabled(struct pci_dev *pdev)
+pci_ers_result_t
+scsih_pci_mmio_enabled(struct pci_dev *pdev)
{
struct Scsi_Host *shost = pci_get_drvdata(pdev);
struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
@@ -8300,61 +8807,99 @@ _scsih_pci_mmio_enabled(struct pci_dev *pdev)
return PCI_ERS_RESULT_NEED_RESET;
}
-/* raid transport support */
-static struct raid_function_template mpt3sas_raid_functions = {
- .cookie = &scsih_driver_template,
- .is_raid = _scsih_is_raid,
- .get_resync = _scsih_get_resync,
- .get_state = _scsih_get_state,
+/*
+ * The pci device ids are defined in mpi/mpi2_cnfg.h.
+ */
+static const struct pci_device_id mpt3sas_pci_table[] = {
+ /* Spitfire ~ 2004 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Falcon ~ 2008 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Liberator ~ 2108 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Meteor ~ 2116 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Thunderbolt ~ 2208 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Mustang ~ 2308 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* SSS6200 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Fury ~ 3004 and 3008 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3004,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3008,
+ PCI_ANY_ID, PCI_ANY_ID },
+ /* Invader ~ 3108 */
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_1,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_2,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_5,
+ PCI_ANY_ID, PCI_ANY_ID },
+ { MPI2_MFGPAGE_VENDORID_LSI, MPI25_MFGPAGE_DEVID_SAS3108_6,
+ PCI_ANY_ID, PCI_ANY_ID },
+ {0} /* Terminating entry */
};
+MODULE_DEVICE_TABLE(pci, mpt3sas_pci_table);
-static struct pci_error_handlers _scsih_err_handler = {
- .error_detected = _scsih_pci_error_detected,
- .mmio_enabled = _scsih_pci_mmio_enabled,
- .slot_reset = _scsih_pci_slot_reset,
- .resume = _scsih_pci_resume,
+static struct pci_error_handlers _mpt3sas_err_handler = {
+ .error_detected = scsih_pci_error_detected,
+ .mmio_enabled = scsih_pci_mmio_enabled,
+ .slot_reset = scsih_pci_slot_reset,
+ .resume = scsih_pci_resume,
};
-static struct pci_driver scsih_driver = {
+static struct pci_driver mpt3sas_driver = {
.name = MPT3SAS_DRIVER_NAME,
- .id_table = scsih_pci_table,
+ .id_table = mpt3sas_pci_table,
.probe = _scsih_probe,
- .remove = _scsih_remove,
- .shutdown = _scsih_shutdown,
- .err_handler = &_scsih_err_handler,
+ .remove = scsih_remove,
+ .shutdown = scsih_shutdown,
+ .err_handler = &_mpt3sas_err_handler,
#ifdef CONFIG_PM
- .suspend = _scsih_suspend,
- .resume = _scsih_resume,
+ .suspend = scsih_suspend,
+ .resume = scsih_resume,
#endif
};
-
/**
- * _scsih_init - main entry point for this driver.
+ * scsih_init - main entry point for this driver.
*
* Returns 0 success, anything else error.
*/
-static int __init
-_scsih_init(void)
+int
+scsih_init(void)
{
- int error;
-
- mpt_ids = 0;
-
- pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
- MPT3SAS_DRIVER_VERSION);
-
- mpt3sas_transport_template =
- sas_attach_transport(&mpt3sas_transport_functions);
- if (!mpt3sas_transport_template)
- return -ENODEV;
-
-/* raid transport support */
- mpt3sas_raid_template = raid_class_attach(&mpt3sas_raid_functions);
- if (!mpt3sas_raid_template) {
- sas_release_transport(mpt3sas_transport_template);
- return -ENODEV;
- }
+ mpt2_ids = 0;
+ mpt3_ids = 0;
mpt3sas_base_initialize_callback_handler();
@@ -8392,33 +8937,17 @@ _scsih_init(void)
tm_sas_control_cb_idx = mpt3sas_base_register_callback_handler(
_scsih_sas_control_complete);
- mpt3sas_ctl_init();
-
- error = pci_register_driver(&scsih_driver);
- if (error) {
- /* raid transport support */
- raid_class_release(mpt3sas_raid_template);
- sas_release_transport(mpt3sas_transport_template);
- }
-
- return error;
+ return 0;
}
/**
- * _scsih_exit - exit point for this driver (when it is a module).
+ * scsih_exit - exit point for this driver (when it is a module).
*
* Returns 0 success, anything else error.
*/
-static void __exit
-_scsih_exit(void)
+void
+scsih_exit(void)
{
- pr_info("mpt3sas version %s unloading\n",
- MPT3SAS_DRIVER_VERSION);
-
- mpt3sas_ctl_exit();
-
- pci_unregister_driver(&scsih_driver);
-
mpt3sas_base_release_callback_handler(scsi_io_cb_idx);
mpt3sas_base_release_callback_handler(tm_cb_idx);
@@ -8434,9 +8963,86 @@ _scsih_exit(void)
mpt3sas_base_release_callback_handler(tm_sas_control_cb_idx);
/* raid transport support */
- raid_class_release(mpt3sas_raid_template);
+ if (hbas_to_enumerate != 1)
+ raid_class_release(mpt3sas_raid_template);
+ if (hbas_to_enumerate != 2)
+ raid_class_release(mpt2sas_raid_template);
sas_release_transport(mpt3sas_transport_template);
}
-module_init(_scsih_init);
-module_exit(_scsih_exit);
+/**
+ * _mpt3sas_init - main entry point for this driver.
+ *
+ * Returns 0 success, anything else error.
+ */
+static int __init
+_mpt3sas_init(void)
+{
+ int error;
+
+ pr_info("%s version %s loaded\n", MPT3SAS_DRIVER_NAME,
+ MPT3SAS_DRIVER_VERSION);
+
+ mpt3sas_transport_template =
+ sas_attach_transport(&mpt3sas_transport_functions);
+ if (!mpt3sas_transport_template)
+ return -ENODEV;
+
+ /* No need attach mpt3sas raid functions template
+ * if hbas_to_enumarate value is one.
+ */
+ if (hbas_to_enumerate != 1) {
+ mpt3sas_raid_template =
+ raid_class_attach(&mpt3sas_raid_functions);
+ if (!mpt3sas_raid_template) {
+ sas_release_transport(mpt3sas_transport_template);
+ return -ENODEV;
+ }
+ }
+
+ /* No need to attach mpt2sas raid functions template
+ * if hbas_to_enumarate value is two
+ */
+ if (hbas_to_enumerate != 2) {
+ mpt2sas_raid_template =
+ raid_class_attach(&mpt2sas_raid_functions);
+ if (!mpt2sas_raid_template) {
+ sas_release_transport(mpt3sas_transport_template);
+ return -ENODEV;
+ }
+ }
+
+ error = scsih_init();
+ if (error) {
+ scsih_exit();
+ return error;
+ }
+
+ mpt3sas_ctl_init(hbas_to_enumerate);
+
+ error = pci_register_driver(&mpt3sas_driver);
+ if (error)
+ scsih_exit();
+
+ return error;
+}
+
+/**
+ * _mpt3sas_exit - exit point for this driver (when it is a module).
+ *
+ */
+static void __exit
+_mpt3sas_exit(void)
+{
+ pr_info("mpt3sas version %s unloading\n",
+ MPT3SAS_DRIVER_VERSION);
+
+ pci_unregister_driver(&mpt3sas_driver);
+
+ mpt3sas_ctl_exit(hbas_to_enumerate);
+
+ scsih_exit();
+}
+
+module_init(_mpt3sas_init);
+module_exit(_mpt3sas_exit);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 70fd019..ca36d7e 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -734,7 +734,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
rphy->identify = mpt3sas_port->remote_identify;
if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = mpt3sas_get_sdev_by_addr(ioc,
mpt3sas_port->remote_identify.sas_address);
if (!sas_device) {
dfailprintk(ioc, printk(MPT3SAS_FMT
@@ -750,8 +750,10 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle,
ioc->name, __FILE__, __LINE__, __func__);
}
- if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE)
+ if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) {
sas_device->pend_sas_rphy_add = 0;
+ sas_device_put(sas_device);
+ }
if ((ioc->logging_level & MPT_DEBUG_TRANSPORT))
dev_printk(KERN_INFO, &rphy->dev,
@@ -1324,15 +1326,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
if (sas_device) {
*identifier = sas_device->enclosure_logical_id;
rc = 0;
+ sas_device_put(sas_device);
} else {
*identifier = 0;
rc = -ENXIO;
}
+
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
@@ -1352,12 +1356,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy)
int rc;
spin_lock_irqsave(&ioc->sas_device_lock, flags);
- sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc,
+ sas_device = __mpt3sas_get_sdev_by_addr(ioc,
rphy->identify.sas_address);
- if (sas_device)
+ if (sas_device) {
rc = sas_device->slot;
- else
+ sas_device_put(sas_device);
+ } else {
rc = -ENXIO;
+ }
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
return rc;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
new file mode 100644
index 0000000..540bd50
--- /dev/null
+++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c
@@ -0,0 +1,344 @@
+/*
+ * Scsi Host Layer for MPT (Message Passing Technology) based controllers
+ *
+ * Copyright (C) 2012-2014 LSI Corporation
+ * Copyright (C) 2013-2015 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * NO WARRANTY
+ * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+ * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+ * solely responsible for determining the appropriateness of using and
+ * distributing the Program and assumes all risks associated with its
+ * exercise of rights under this Agreement, including but not limited to
+ * the risks and costs of program errors, damage to or loss of data,
+ * programs or equipment, and unavailability or interruption of operations.
+
+ * DISCLAIMER OF LIABILITY
+ * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+ * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <asm/unaligned.h>
+
+#include "mpt3sas_base.h"
+
+/**
+ * _warpdrive_disable_ddio - Disable direct I/O for all the volumes
+ * @ioc: per adapter object
+ */
+static void
+_warpdrive_disable_ddio(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ struct _raid_device *raid_device;
+ u16 handle;
+ u16 ioc_status;
+ unsigned long flags;
+
+ handle = 0xFFFF;
+ while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ spin_lock_irqsave(&ioc->raid_device_lock, flags);
+ raid_device = mpt3sas_raid_device_find_by_handle(ioc, handle);
+ if (raid_device)
+ raid_device->direct_io_enabled = 0;
+ spin_unlock_irqrestore(&ioc->raid_device_lock, flags);
+ }
+ return;
+}
+
+
+/**
+ * mpt3sas_get_num_volumes - Get number of volumes in the ioc
+ * @ioc: per adapter object
+ */
+u8
+mpt3sas_get_num_volumes(struct MPT3SAS_ADAPTER *ioc)
+{
+ Mpi2RaidVolPage1_t vol_pg1;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 handle;
+ u8 vol_cnt = 0;
+ u16 ioc_status;
+
+ handle = 0xFFFF;
+ while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply,
+ &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
+ ioc_status = le16_to_cpu(mpi_reply.IOCStatus) &
+ MPI2_IOCSTATUS_MASK;
+ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
+ break;
+ vol_cnt++;
+ handle = le16_to_cpu(vol_pg1.DevHandle);
+ }
+ return vol_cnt;
+}
+
+
+/**
+ * mpt3sas_init_warpdrive_properties - Set properties for warpdrive direct I/O.
+ * @ioc: per adapter object
+ * @raid_device: the raid_device object
+ */
+void
+mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc,
+ struct _raid_device *raid_device)
+{
+ Mpi2RaidVolPage0_t *vol_pg0;
+ Mpi2RaidPhysDiskPage0_t pd_pg0;
+ Mpi2ConfigReply_t mpi_reply;
+ u16 sz;
+ u8 num_pds, count;
+ unsigned long stripe_sz, block_sz;
+ u8 stripe_exp, block_exp;
+ u64 dev_max_lba;
+
+ if (!ioc->is_warpdrive)
+ return;
+
+ if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "globally as drives are exposed\n", ioc->name);
+ return;
+ }
+ if (mpt3sas_get_num_volumes(ioc) > 1) {
+ _warpdrive_disable_ddio(ioc);
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "globally as number of drives > 1\n", ioc->name);
+ return;
+ }
+ if ((mpt3sas_config_get_number_pds(ioc, raid_device->handle,
+ &num_pds)) || !num_pds) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in computing number of drives\n", ioc->name);
+ return;
+ }
+
+ sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds *
+ sizeof(Mpi2RaidVol0PhysDisk_t));
+ vol_pg0 = kzalloc(sz, GFP_KERNEL);
+ if (!vol_pg0) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Memory allocation failure for RVPG0\n", ioc->name);
+ return;
+ }
+
+ if ((mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0,
+ MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "Failure in retrieving RVPG0\n", ioc->name);
+ kfree(vol_pg0);
+ return;
+ }
+
+ /*
+ * WARPDRIVE:If number of physical disks in a volume exceeds the max pds
+ * assumed for WARPDRIVE, disable direct I/O
+ */
+ if (num_pds > MPT_MAX_WARPDRIVE_PDS) {
+ pr_warn(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): num_mem=%d, "
+ "max_mem_allowed=%d\n", ioc->name, raid_device->handle,
+ num_pds, MPT_MAX_WARPDRIVE_PDS);
+ kfree(vol_pg0);
+ return;
+ }
+ for (count = 0; count < num_pds; count++) {
+ if (mpt3sas_config_get_phys_disk_pg0(ioc, &mpi_reply,
+ &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM,
+ vol_pg0->PhysDisk[count].PhysDiskNum) ||
+ pd_pg0.DevHandle == MPT3SAS_INVALID_DEVICE_HANDLE) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+ "disabled for the drive with handle(0x%04x) member"
+ "handle retrieval failed for member number=%d\n",
+ ioc->name, raid_device->handle,
+ vol_pg0->PhysDisk[count].PhysDiskNum);
+ goto out_error;
+ }
+ /* Disable direct I/O if member drive lba exceeds 4 bytes */
+ dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA);
+ if (dev_max_lba >> 32) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is "
+ "disabled for the drive with handle(0x%04x) member"
+ " handle (0x%04x) unsupported max lba 0x%016llx\n",
+ ioc->name, raid_device->handle,
+ le16_to_cpu(pd_pg0.DevHandle),
+ (unsigned long long)dev_max_lba);
+ goto out_error;
+ }
+
+ raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle);
+ }
+
+ /*
+ * Assumption for WD: Direct I/O is not supported if the volume is
+ * not RAID0
+ */
+ if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x): type=%d, "
+ "s_sz=%uK, blk_size=%u\n", ioc->name,
+ raid_device->handle, raid_device->volume_type,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024,
+ le16_to_cpu(vol_pg0->BlockSize));
+ goto out_error;
+ }
+
+ stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ stripe_exp = find_first_bit(&stripe_sz, 32);
+ if (stripe_exp == 32) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) invalid stripe sz %uK\n",
+ ioc->name, raid_device->handle,
+ (le32_to_cpu(vol_pg0->StripeSize) *
+ le16_to_cpu(vol_pg0->BlockSize)) / 1024);
+ goto out_error;
+ }
+ raid_device->stripe_exponent = stripe_exp;
+ block_sz = le16_to_cpu(vol_pg0->BlockSize);
+ block_exp = find_first_bit(&block_sz, 16);
+ if (block_exp == 16) {
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is disabled "
+ "for the drive with handle(0x%04x) invalid block sz %u\n",
+ ioc->name, raid_device->handle,
+ le16_to_cpu(vol_pg0->BlockSize));
+ goto out_error;
+ }
+ raid_device->block_exponent = block_exp;
+ raid_device->direct_io_enabled = 1;
+
+ pr_info(MPT3SAS_FMT "WarpDrive : Direct IO is Enabled for the drive"
+ " with handle(0x%04x)\n", ioc->name, raid_device->handle);
+ /*
+ * WARPDRIVE: Though the following fields are not used for direct IO,
+ * stored for future purpose:
+ */
+ raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA);
+ raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize);
+ raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize);
+
+
+ kfree(vol_pg0);
+ return;
+
+out_error:
+ raid_device->direct_io_enabled = 0;
+ for (count = 0; count < num_pds; count++)
+ raid_device->pd_handle[count] = 0;
+ kfree(vol_pg0);
+ return;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_get - returns direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Returns the smid stored scmd pointer.
+ */
+inline u8
+mpt3sas_scsi_direct_io_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
+{
+ return ioc->scsi_lookup[smid - 1].direct_io;
+}
+
+/**
+ * mpt3sas_scsi_direct_io_set - sets direct io flag
+ * @ioc: per adapter object
+ * @smid: system request message index
+ * @direct_io: Zero or non-zero value to set in the direct_io flag
+ *
+ * Returns Nothing.
+ */
+inline void
+mpt3sas_scsi_direct_io_set(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 direct_io)
+{
+ ioc->scsi_lookup[smid - 1].direct_io = direct_io;
+}
+
+/**
+ * mpt3sas_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O
+ * @ioc: per adapter object
+ * @scmd: pointer to scsi command object
+ * @raid_device: pointer to raid device data structure
+ * @mpi_request: pointer to the SCSI_IO reqest message frame
+ * @smid: system request message index
+ *
+ * Returns nothing
+ */
+void
+mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd,
+ struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request,
+ u16 smid)
+{
+ sector_t v_lba, p_lba, stripe_off, column, io_size;
+ u32 stripe_sz, stripe_exp;
+ u8 num_pds, cmd = scmd->cmnd[0];
+
+ if (cmd != READ_10 && cmd != WRITE_10 &&
+ cmd != READ_16 && cmd != WRITE_16)
+ return;
+
+ if (cmd == READ_10 || cmd == WRITE_10)
+ v_lba = get_unaligned_be32(&mpi_request->CDB.CDB32[2]);
+ else
+ v_lba = get_unaligned_be64(&mpi_request->CDB.CDB32[2]);
+
+ io_size = scsi_bufflen(scmd) >> raid_device->block_exponent;
+
+ if (v_lba + io_size - 1 > raid_device->max_lba)
+ return;
+
+ stripe_sz = raid_device->stripe_sz;
+ stripe_exp = raid_device->stripe_exponent;
+ stripe_off = v_lba & (stripe_sz - 1);
+
+ /* Return unless IO falls within a stripe */
+ if (stripe_off + io_size > stripe_sz)
+ return;
+
+ num_pds = raid_device->num_pds;
+ p_lba = v_lba >> stripe_exp;
+ column = sector_div(p_lba, num_pds);
+ p_lba = (p_lba << stripe_exp) + stripe_off;
+ mpi_request->DevHandle = cpu_to_le16(raid_device->pd_handle[column]);
+
+ if (cmd == READ_10 || cmd == WRITE_10)
+ put_unaligned_be32(lower_32_bits(p_lba),
+ &mpi_request->CDB.CDB32[2]);
+ else
+ put_unaligned_be64(p_lba, &mpi_request->CDB.CDB32[2]);
+
+ mpt3sas_scsi_direct_io_set(ioc, smid, 1);
+}
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index e2d555c..675e7fa 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -65,7 +65,6 @@ static struct scsi_host_template mvs_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = mvst_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -641,9 +640,9 @@ static void mvs_pci_remove(struct pci_dev *pdev)
tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet);
#endif
+ scsi_remove_host(mvi->shost);
sas_unregister_ha(sha);
sas_remove_host(mvi->shost);
- scsi_remove_host(mvi->shost);
MVS_CHIP_DISP->interrupt_disable(mvi);
free_irq(mvi->pdev->irq, sha);
@@ -759,7 +758,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
struct device_attribute *attr,
const char *buffer, size_t size)
{
- int val = 0;
+ unsigned int val = 0;
struct mvs_info *mvi = NULL;
struct Scsi_Host *shost = class_to_shost(cdev);
struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
@@ -767,7 +766,7 @@ mvs_store_interrupt_coalescing(struct device *cdev,
if (buffer == NULL)
return size;
- if (sscanf(buffer, "%d", &val) != 1)
+ if (sscanf(buffer, "%u", &val) != 1)
return -EINVAL;
if (val >= 0x10000) {
diff --git a/drivers/scsi/mvumi.c b/drivers/scsi/mvumi.c
index 3e6b866..02360de 100644
--- a/drivers/scsi/mvumi.c
+++ b/drivers/scsi/mvumi.c
@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/ktime.h>
#include <linux/blkdev.h>
#include <linux/io.h>
#include <scsi/scsi.h>
@@ -858,8 +859,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba,
struct mvumi_hs_page2 *hs_page2;
struct mvumi_hs_page4 *hs_page4;
struct mvumi_hs_page3 *hs_page3;
- struct timeval time;
- unsigned int local_time;
+ u64 time;
+ u64 local_time;
switch (hs_header->page_code) {
case HS_PAGE_HOST_INFO:
@@ -877,9 +878,8 @@ static void mvumi_hs_build_page(struct mvumi_hba *mhba,
hs_page2->slot_number = 0;
hs_page2->intr_level = 0;
hs_page2->intr_vector = 0;
- do_gettimeofday(&time);
- local_time = (unsigned int) (time.tv_sec -
- (sys_tz.tz_minuteswest * 60));
+ time = ktime_get_real_seconds();
+ local_time = (time - (sys_tz.tz_minuteswest * 60));
hs_page2->seconds_since1970 = local_time;
hs_header->checksum = mvumi_calculate_checksum(hs_header,
hs_header->frame_length);
diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h
index f14ec6e..199527d 100644
--- a/drivers/scsi/pm8001/pm8001_defs.h
+++ b/drivers/scsi/pm8001/pm8001_defs.h
@@ -51,6 +51,8 @@ enum chip_flavors {
chip_8076,
chip_8077,
chip_8006,
+ chip_8070,
+ chip_8072
};
enum phy_speed {
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 5c0356f..062ab34 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -58,6 +58,8 @@ static const struct pm8001_chip_info pm8001_chips[] = {
[chip_8076] = {0, 16, &pm8001_80xx_dispatch,},
[chip_8077] = {0, 16, &pm8001_80xx_dispatch,},
[chip_8006] = {0, 16, &pm8001_80xx_dispatch,},
+ [chip_8070] = {0, 8, &pm8001_80xx_dispatch,},
+ [chip_8072] = {0, 16, &pm8001_80xx_dispatch,},
};
static int pm8001_id;
@@ -88,7 +90,6 @@ static struct scsi_host_template pm8001_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = pm8001_host_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -480,7 +481,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
#ifdef PM8001_USE_TASKLET
/* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled())
+ || (pm8001_ha->chip_id == chip_8001))
tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
(unsigned long)&(pm8001_ha->irq_vector[0]));
else
@@ -634,6 +636,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
payload.minor_function = 0;
payload.length = 128;
}
+ } else if ((pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) &&
+ pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) {
+ payload.minor_function = 4;
+ payload.length = 4096;
} else {
payload.minor_function = 1;
payload.length = 4096;
@@ -660,6 +667,11 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
else if (deviceid == 0x0042)
pm8001_ha->sas_addr[j] =
payload.func_specific[0x010 + i];
+ } else if ((pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) &&
+ pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) {
+ pm8001_ha->sas_addr[j] =
+ payload.func_specific[0x010 + i];
} else
pm8001_ha->sas_addr[j] =
payload.func_specific[0x804 + i];
@@ -720,6 +732,153 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
return 0;
}
+struct pm8001_mpi3_phy_pg_trx_config {
+ u32 LaneLosCfg;
+ u32 LanePgaCfg1;
+ u32 LanePisoCfg1;
+ u32 LanePisoCfg2;
+ u32 LanePisoCfg3;
+ u32 LanePisoCfg4;
+ u32 LanePisoCfg5;
+ u32 LanePisoCfg6;
+ u32 LaneBctCtrl;
+};
+
+/**
+ * pm8001_get_internal_phy_settings : Retrieves the internal PHY settings
+ * @pm8001_ha : our adapter
+ * @phycfg : PHY config page to populate
+ */
+static
+void pm8001_get_internal_phy_settings(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_mpi3_phy_pg_trx_config *phycfg)
+{
+ phycfg->LaneLosCfg = 0x00000132;
+ phycfg->LanePgaCfg1 = 0x00203949;
+ phycfg->LanePisoCfg1 = 0x000000FF;
+ phycfg->LanePisoCfg2 = 0xFF000001;
+ phycfg->LanePisoCfg3 = 0xE7011300;
+ phycfg->LanePisoCfg4 = 0x631C40C0;
+ phycfg->LanePisoCfg5 = 0xF8102036;
+ phycfg->LanePisoCfg6 = 0xF74A1000;
+ phycfg->LaneBctCtrl = 0x00FB33F8;
+}
+
+/**
+ * pm8001_get_external_phy_settings : Retrieves the external PHY settings
+ * @pm8001_ha : our adapter
+ * @phycfg : PHY config page to populate
+ */
+static
+void pm8001_get_external_phy_settings(struct pm8001_hba_info *pm8001_ha,
+ struct pm8001_mpi3_phy_pg_trx_config *phycfg)
+{
+ phycfg->LaneLosCfg = 0x00000132;
+ phycfg->LanePgaCfg1 = 0x00203949;
+ phycfg->LanePisoCfg1 = 0x000000FF;
+ phycfg->LanePisoCfg2 = 0xFF000001;
+ phycfg->LanePisoCfg3 = 0xE7011300;
+ phycfg->LanePisoCfg4 = 0x63349140;
+ phycfg->LanePisoCfg5 = 0xF8102036;
+ phycfg->LanePisoCfg6 = 0xF80D9300;
+ phycfg->LaneBctCtrl = 0x00FB33F8;
+}
+
+/**
+ * pm8001_get_phy_mask : Retrieves the mask that denotes if a PHY is int/ext
+ * @pm8001_ha : our adapter
+ * @phymask : The PHY mask
+ */
+static
+void pm8001_get_phy_mask(struct pm8001_hba_info *pm8001_ha, int *phymask)
+{
+ switch (pm8001_ha->pdev->subsystem_device) {
+ case 0x0070: /* H1280 - 8 external 0 internal */
+ case 0x0072: /* H12F0 - 16 external 0 internal */
+ *phymask = 0x0000;
+ break;
+
+ case 0x0071: /* H1208 - 0 external 8 internal */
+ case 0x0073: /* H120F - 0 external 16 internal */
+ *phymask = 0xFFFF;
+ break;
+
+ case 0x0080: /* H1244 - 4 external 4 internal */
+ *phymask = 0x00F0;
+ break;
+
+ case 0x0081: /* H1248 - 4 external 8 internal */
+ *phymask = 0x0FF0;
+ break;
+
+ case 0x0082: /* H1288 - 8 external 8 internal */
+ *phymask = 0xFF00;
+ break;
+
+ default:
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("Unknown subsystem device=0x%.04x",
+ pm8001_ha->pdev->subsystem_device));
+ }
+}
+
+/**
+ * pm8001_set_phy_settings_ven_117c_12Gb : Configure ATTO 12Gb PHY settings
+ * @pm8001_ha : our adapter
+ */
+static
+int pm8001_set_phy_settings_ven_117c_12G(struct pm8001_hba_info *pm8001_ha)
+{
+ struct pm8001_mpi3_phy_pg_trx_config phycfg_int;
+ struct pm8001_mpi3_phy_pg_trx_config phycfg_ext;
+ int phymask = 0;
+ int i = 0;
+
+ memset(&phycfg_int, 0, sizeof(phycfg_int));
+ memset(&phycfg_ext, 0, sizeof(phycfg_ext));
+
+ pm8001_get_internal_phy_settings(pm8001_ha, &phycfg_int);
+ pm8001_get_external_phy_settings(pm8001_ha, &phycfg_ext);
+ pm8001_get_phy_mask(pm8001_ha, &phymask);
+
+ for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+ if (phymask & (1 << i)) {/* Internal PHY */
+ pm8001_set_phy_profile_single(pm8001_ha, i,
+ sizeof(phycfg_int) / sizeof(u32),
+ (u32 *)&phycfg_int);
+
+ } else { /* External PHY */
+ pm8001_set_phy_profile_single(pm8001_ha, i,
+ sizeof(phycfg_ext) / sizeof(u32),
+ (u32 *)&phycfg_ext);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * pm8001_configure_phy_settings : Configures PHY settings based on vendor ID.
+ * @pm8001_ha : our hba.
+ */
+static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
+{
+ switch (pm8001_ha->pdev->subsystem_vendor) {
+ case PCI_VENDOR_ID_ATTO:
+ if (pm8001_ha->pdev->device == 0x0042) /* 6Gb */
+ return 0;
+ else
+ return pm8001_set_phy_settings_ven_117c_12G(pm8001_ha);
+
+ case PCI_VENDOR_ID_ADAPTEC2:
+ case 0:
+ return 0;
+
+ default:
+ return pm8001_get_phy_settings_info(pm8001_ha);
+ }
+}
+
#ifdef PM8001_USE_MSIX
/**
* pm8001_setup_msix - enable MSI-X interrupt
@@ -792,7 +951,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
pdev = pm8001_ha->pdev;
#ifdef PM8001_USE_MSIX
- if (pdev->msix_cap)
+ if (pdev->msix_cap && pci_msi_enabled())
return pm8001_setup_msix(pm8001_ha);
else {
PM8001_INIT_DBG(pm8001_ha,
@@ -803,6 +962,8 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
intx:
/* initialize the INT-X interrupt */
+ pm8001_ha->irq_vector[0].irq_id = 0;
+ pm8001_ha->irq_vector[0].drv_inst = pm8001_ha;
rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED,
DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost));
return rc;
@@ -902,12 +1063,9 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
pm8001_init_sas_add(pm8001_ha);
/* phy setting support for motherboard controller */
- if (pdev->subsystem_vendor != PCI_VENDOR_ID_ADAPTEC2 &&
- pdev->subsystem_vendor != 0) {
- rc = pm8001_get_phy_settings_info(pm8001_ha);
- if (rc)
- goto err_out_shost;
- }
+ if (pm8001_configure_phy_settings(pm8001_ha))
+ goto err_out_shost;
+
pm8001_post_sas_ha_init(shost, chip);
rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
if (rc)
@@ -937,10 +1095,10 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
struct pm8001_hba_info *pm8001_ha;
int i, j;
pm8001_ha = sha->lldd_ha;
+ scsi_remove_host(pm8001_ha->shost);
sas_unregister_ha(sha);
sas_remove_host(pm8001_ha->shost);
list_del(&pm8001_ha->list);
- scsi_remove_host(pm8001_ha->shost);
PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF);
PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
@@ -956,7 +1114,8 @@ static void pm8001_pci_remove(struct pci_dev *pdev)
#endif
#ifdef PM8001_USE_TASKLET
/* For non-msix and msix interrupts */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_kill(&pm8001_ha->tasklet[0]);
else
for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
@@ -1005,7 +1164,8 @@ static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state)
#endif
#ifdef PM8001_USE_TASKLET
/* For non-msix and msix interrupts */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_kill(&pm8001_ha->tasklet[0]);
else
for (j = 0; j < PM8001_MAX_MSIX_VEC; j++)
@@ -1074,7 +1234,8 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
goto err_out_disable;
#ifdef PM8001_USE_TASKLET
/* Tasklet for non msi-x interrupt handler */
- if ((!pdev->msix_cap) || (pm8001_ha->chip_id == chip_8001))
+ if ((!pdev->msix_cap || !pci_msi_enabled()) ||
+ (pm8001_ha->chip_id == chip_8001))
tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet,
(unsigned long)&(pm8001_ha->irq_vector[0]));
else
@@ -1087,6 +1248,19 @@ static int pm8001_pci_resume(struct pci_dev *pdev)
for (i = 1; i < pm8001_ha->number_of_intr; i++)
PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, i);
}
+
+ /* Chip documentation for the 8070 and 8072 SPCv */
+ /* states that a 500ms minimum delay is required */
+ /* before issuing commands. Otherwise, the firmare */
+ /* will enter an unrecoverable state. */
+
+ if (pm8001_ha->chip_id == chip_8070 ||
+ pm8001_ha->chip_id == chip_8072) {
+ mdelay(500);
+ }
+
+ /* Spin up the PHYs */
+
pm8001_ha->flags = PM8001F_RUN_TIME;
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
pm8001_ha->phy[i].enable_completion = &completion;
@@ -1165,6 +1339,20 @@ static struct pci_device_id pm8001_pci_table[] = {
PCI_VENDOR_ID_ADAPTEC2, 0x0808, 0, 0, chip_8077 },
{ PCI_VENDOR_ID_ADAPTEC2, 0x8074,
PCI_VENDOR_ID_ADAPTEC2, 0x0404, 0, 0, chip_8074 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0070, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0071, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0072, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0073, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8070,
+ PCI_VENDOR_ID_ATTO, 0x0080, 0, 0, chip_8070 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0081, 0, 0, chip_8072 },
+ { PCI_VENDOR_ID_ATTO, 0x8072,
+ PCI_VENDOR_ID_ATTO, 0x0082, 0, 0, chip_8072 },
{} /* terminate list */
};
@@ -1220,7 +1408,7 @@ MODULE_AUTHOR("Anand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>");
MODULE_AUTHOR("Sangeetha Gnanasekaran <Sangeetha.Gnanasekaran@pmcs.com>");
MODULE_AUTHOR("Nikith Ganigarakoppal <Nikith.Ganigarakoppal@pmcs.com>");
MODULE_DESCRIPTION(
- "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077 "
+ "PMC-Sierra PM8001/8006/8081/8088/8089/8074/8076/8077/8070/8072 "
"SAS/SATA controller driver");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index e2e97db..6628cc3 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -106,7 +106,9 @@ do { \
#define DEV_IS_EXPANDER(type) ((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
#define IS_SPCV_12G(dev) ((dev->device == 0X8074) \
|| (dev->device == 0X8076) \
- || (dev->device == 0X8077))
+ || (dev->device == 0X8077) \
+ || (dev->device == 0X8070) \
+ || (dev->device == 0X8072))
#define PM8001_NAME_LENGTH 32/* generic length of strings */
extern struct list_head hba_list;
@@ -708,6 +710,8 @@ int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
u32 length, u8 *buf);
+void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
+ u32 phy, u32 length, u32 *buf);
int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct device_attribute *attr, char *buf);
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 9a389f1..eb4fee6 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -1267,6 +1267,8 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
/* check iButton feature support for motherboard controller */
if (pm8001_ha->pdev->subsystem_vendor !=
PCI_VENDOR_ID_ADAPTEC2 &&
+ pm8001_ha->pdev->subsystem_vendor !=
+ PCI_VENDOR_ID_ATTO &&
pm8001_ha->pdev->subsystem_vendor != 0) {
ibutton0 = pm8001_cr32(pm8001_ha, 0,
MSGU_HOST_SCRATCH_PAD_6);
@@ -4576,6 +4578,38 @@ void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
}
PM8001_INIT_DBG(pm8001_ha, pm8001_printk("phy settings completed\n"));
}
+
+void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
+ u32 phy, u32 length, u32 *buf)
+{
+ u32 tag, opc;
+ int rc, i;
+ struct set_phy_profile_req payload;
+ struct inbound_queue_table *circularQ;
+
+ memset(&payload, 0, sizeof(payload));
+
+ rc = pm8001_tag_alloc(pm8001_ha, &tag);
+ if (rc)
+ PM8001_INIT_DBG(pm8001_ha, pm8001_printk("Invalid tag"));
+
+ circularQ = &pm8001_ha->inbnd_q_tbl[0];
+ opc = OPC_INB_SET_PHY_PROFILE;
+
+ payload.tag = cpu_to_le32(tag);
+ payload.ppc_phyid = (((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8)
+ | (phy & 0xFF));
+
+ for (i = 0; i < length; i++)
+ payload.reserved[i] = cpu_to_le32(*(buf + i));
+
+ rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0);
+ if (rc)
+ pm8001_tag_free(pm8001_ha, tag);
+
+ PM8001_INIT_DBG(pm8001_ha,
+ pm8001_printk("PHY %d settings applied", phy));
+}
const struct pm8001_dispatch pm8001_80xx_dispatch = {
.name = "pmc80xx",
.chip_init = pm80xx_chip_init,
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index ed31d8c..b2a8820 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -45,6 +45,7 @@
#include <asm/processor.h>
#include <linux/libata.h>
#include <linux/mutex.h>
+#include <linux/ktime.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
@@ -4254,7 +4255,6 @@ static struct scsi_host_template pmcraid_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = pmcraid_host_attrs,
.proc_name = PMCRAID_DRIVER_NAME,
- .use_blk_tags = 1,
};
/*
@@ -5563,11 +5563,9 @@ static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd)
__be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN);
struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl;
- struct timeval tv;
__le64 timestamp;
- do_gettimeofday(&tv);
- timestamp = tv.tv_sec * 1000;
+ timestamp = ktime_get_real_seconds() * 1000;
pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp);
pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8);
diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c
index eb0cc54..b6b4cfd 100644
--- a/drivers/scsi/qla2xxx/qla_nx.c
+++ b/drivers/scsi/qla2xxx/qla_nx.c
@@ -433,7 +433,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
if (off_in < QLA82XX_PCI_CRBSPACE)
return -1;
- *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE);
+ off_in -= QLA82XX_PCI_CRBSPACE;
/* Try direct map */
m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)];
@@ -443,6 +443,7 @@ qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
return 0;
}
/* Not in direct map, use crb window */
+ *off_out = (void __iomem *)off_in;
return 1;
}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index c2dd17b..bfa9a64 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -267,7 +267,6 @@ struct scsi_host_template qla2xxx_driver_template = {
.shost_attrs = qla2x00_host_attrs,
.supported_mode = MODE_INITIATOR,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index ac65cb7..81af294 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -43,8 +43,6 @@
#include <scsi/scsi_cmnd.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include "qla_def.h"
#include "qla_target.h"
@@ -729,23 +727,23 @@ static int tcm_qla2xxx_init_nodeacl(struct se_node_acl *se_nacl,
#define DEF_QLA_TPG_ATTRIB(name) \
\
-static ssize_t tcm_qla2xxx_tpg_attrib_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t tcm_qla2xxx_tpg_attrib_##name##_show( \
+ struct config_item *item, char *page) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \
struct tcm_qla2xxx_tpg, se_tpg); \
\
return sprintf(page, "%u\n", tpg->tpg_attrib.name); \
} \
\
-static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
+static ssize_t tcm_qla2xxx_tpg_attrib_##name##_store( \
+ struct config_item *item, const char *page, size_t count) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \
struct tcm_qla2xxx_tpg, se_tpg); \
+ struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \
unsigned long val; \
int ret; \
\
@@ -755,81 +753,39 @@ static ssize_t tcm_qla2xxx_tpg_attrib_store_##name( \
" ret: %d\n", ret); \
return -EINVAL; \
} \
- ret = tcm_qla2xxx_set_attrib_##name(tpg, val); \
- \
- return (!ret) ? count : -EINVAL; \
-}
-
-#define DEF_QLA_TPG_ATTR_BOOL(_name) \
- \
-static int tcm_qla2xxx_set_attrib_##_name( \
- struct tcm_qla2xxx_tpg *tpg, \
- unsigned long val) \
-{ \
- struct tcm_qla2xxx_tpg_attrib *a = &tpg->tpg_attrib; \
\
if ((val != 0) && (val != 1)) { \
pr_err("Illegal boolean value %lu\n", val); \
return -EINVAL; \
} \
\
- a->_name = val; \
- return 0; \
-}
-
-#define QLA_TPG_ATTR(_name, _mode) \
- TF_TPG_ATTRIB_ATTR(tcm_qla2xxx, _name, _mode);
+ a->name = val; \
+ \
+ return count; \
+} \
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_attrib_, name)
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_generate_node_acls
- */
-DEF_QLA_TPG_ATTR_BOOL(generate_node_acls);
DEF_QLA_TPG_ATTRIB(generate_node_acls);
-QLA_TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR);
-
-/*
- Define tcm_qla2xxx_attrib_s_cache_dynamic_acls
- */
-DEF_QLA_TPG_ATTR_BOOL(cache_dynamic_acls);
DEF_QLA_TPG_ATTRIB(cache_dynamic_acls);
-QLA_TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_write_protect
- */
-DEF_QLA_TPG_ATTR_BOOL(demo_mode_write_protect);
DEF_QLA_TPG_ATTRIB(demo_mode_write_protect);
-QLA_TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_prod_mode_write_protect
- */
-DEF_QLA_TPG_ATTR_BOOL(prod_mode_write_protect);
DEF_QLA_TPG_ATTRIB(prod_mode_write_protect);
-QLA_TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR);
-
-/*
- * Define tcm_qla2xxx_tpg_attrib_s_demo_mode_login_only
- */
-DEF_QLA_TPG_ATTR_BOOL(demo_mode_login_only);
DEF_QLA_TPG_ATTRIB(demo_mode_login_only);
-QLA_TPG_ATTR(demo_mode_login_only, S_IRUGO | S_IWUSR);
static struct configfs_attribute *tcm_qla2xxx_tpg_attrib_attrs[] = {
- &tcm_qla2xxx_tpg_attrib_generate_node_acls.attr,
- &tcm_qla2xxx_tpg_attrib_cache_dynamic_acls.attr,
- &tcm_qla2xxx_tpg_attrib_demo_mode_write_protect.attr,
- &tcm_qla2xxx_tpg_attrib_prod_mode_write_protect.attr,
- &tcm_qla2xxx_tpg_attrib_demo_mode_login_only.attr,
+ &tcm_qla2xxx_tpg_attrib_attr_generate_node_acls,
+ &tcm_qla2xxx_tpg_attrib_attr_cache_dynamic_acls,
+ &tcm_qla2xxx_tpg_attrib_attr_demo_mode_write_protect,
+ &tcm_qla2xxx_tpg_attrib_attr_prod_mode_write_protect,
+ &tcm_qla2xxx_tpg_attrib_attr_demo_mode_login_only,
NULL,
};
/* End items for tcm_qla2xxx_tpg_attrib_cit */
-static ssize_t tcm_qla2xxx_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_enable_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
@@ -865,11 +821,10 @@ static void tcm_qla2xxx_undepend_tpg(struct work_struct *work)
complete(&base_tpg->tpg_base_comp);
}
-static ssize_t tcm_qla2xxx_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long op;
@@ -909,22 +864,16 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx, enable, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_qla2xxx_tpg_show_dynamic_sessions(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_dynamic_sessions_show(struct config_item *item,
+ char *page)
{
- return target_show_dynamic_sessions(se_tpg, page);
+ return target_show_dynamic_sessions(to_tpg(item), page);
}
-TF_TPG_BASE_ATTR_RO(tcm_qla2xxx, dynamic_sessions);
-
-static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
unsigned long val;
@@ -943,21 +892,24 @@ static ssize_t tcm_qla2xxx_tpg_store_fabric_prot_type(
return count;
}
-static ssize_t tcm_qla2xxx_tpg_show_fabric_prot_type(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_tpg_fabric_prot_type_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
struct tcm_qla2xxx_tpg, se_tpg);
return sprintf(page, "%d\n", tpg->tpg_attrib.fabric_prot_type);
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx, fabric_prot_type, S_IRUGO | S_IWUSR);
+
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_, enable);
+CONFIGFS_ATTR_RO(tcm_qla2xxx_tpg_, dynamic_sessions);
+CONFIGFS_ATTR(tcm_qla2xxx_tpg_, fabric_prot_type);
static struct configfs_attribute *tcm_qla2xxx_tpg_attrs[] = {
- &tcm_qla2xxx_tpg_enable.attr,
- &tcm_qla2xxx_tpg_dynamic_sessions.attr,
- &tcm_qla2xxx_tpg_fabric_prot_type.attr,
+ &tcm_qla2xxx_tpg_attr_enable,
+ &tcm_qla2xxx_tpg_attr_dynamic_sessions,
+ &tcm_qla2xxx_tpg_attr_fabric_prot_type,
NULL,
};
@@ -1030,18 +982,16 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
kfree(tpg);
}
-static ssize_t tcm_qla2xxx_npiv_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_qla2xxx_npiv_tpg_enable_show(struct config_item *item,
+ char *page)
{
- return tcm_qla2xxx_tpg_show_enable(se_tpg, page);
+ return tcm_qla2xxx_tpg_enable_show(item, page);
}
-static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_qla2xxx_npiv_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct se_wwn *se_wwn = se_tpg->se_tpg_wwn;
struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
struct tcm_qla2xxx_lport, lport_wwn);
@@ -1077,10 +1027,10 @@ static ssize_t tcm_qla2xxx_npiv_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(tcm_qla2xxx_npiv_tpg_, enable);
static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = {
- &tcm_qla2xxx_npiv_tpg_enable.attr,
+ &tcm_qla2xxx_npiv_tpg_attr_enable,
NULL,
};
@@ -1783,9 +1733,8 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn)
}
-static ssize_t tcm_qla2xxx_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t tcm_qla2xxx_wwn_version_show(struct config_item *item,
+ char *page)
{
return sprintf(page,
"TCM QLOGIC QLA2XXX NPIV capable fabric module %s on %s/%s on "
@@ -1793,10 +1742,10 @@ static ssize_t tcm_qla2xxx_wwn_show_attr_version(
utsname()->machine);
}
-TF_WWN_ATTR_RO(tcm_qla2xxx, version);
+CONFIGFS_ATTR_RO(tcm_qla2xxx_wwn_, version);
static struct configfs_attribute *tcm_qla2xxx_wwn_attrs[] = {
- &tcm_qla2xxx_wwn_version.attr,
+ &tcm_qla2xxx_wwn_attr_version,
NULL,
};
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 6d25879..01c3610 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -212,7 +212,6 @@ static struct scsi_host_template qla4xxx_driver_template = {
.shost_attrs = qla4xxx_host_attrs,
.host_reset = qla4xxx_host_reset,
.vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
- .use_blk_tags = 1,
};
static struct iscsi_transport qla4xxx_iscsi_transport = {
@@ -8697,13 +8696,6 @@ static int qla4xxx_probe_adapter(struct pci_dev *pdev,
host->can_queue = MAX_SRBS ;
host->transportt = qla4xxx_scsi_transport;
- ret = scsi_init_shared_tag_map(host, MAX_SRBS);
- if (ret) {
- ql4_printk(KERN_WARNING, ha,
- "%s: scsi_init_shared_tag_map failed\n", __func__);
- goto probe_failed;
- }
-
pci_set_drvdata(pdev, ha);
ret = scsi_add_host(host, &pdev->dev);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 207d6a7..d07fb65 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -616,32 +616,11 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
*/
int scsi_change_queue_depth(struct scsi_device *sdev, int depth)
{
- unsigned long flags;
-
- if (depth <= 0)
- goto out;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
-
- /*
- * Check to see if the queue is managed by the block layer.
- * If it is, and we fail to adjust the depth, exit.
- *
- * Do not resize the tag map if it is a host wide share bqt,
- * because the size should be the hosts's can_queue. If there
- * is more IO than the LLD's can_queue (so there are not enuogh
- * tags) request_fn's host queue ready check will handle it.
- */
- if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) {
- if (blk_queue_tagged(sdev->request_queue) &&
- blk_queue_resize_tags(sdev->request_queue, depth) != 0)
- goto out_unlock;
+ if (depth > 0) {
+ sdev->queue_depth = depth;
+ wmb();
}
- sdev->queue_depth = depth;
-out_unlock:
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-out:
return sdev->queue_depth;
}
EXPORT_SYMBOL(scsi_change_queue_depth);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index dfcc45b..d09d602 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -465,8 +465,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
0} },
{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
- {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */
+ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
+ 0, 0, 0, 0, 0, 0} },
{1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
@@ -477,8 +478,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
{10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
0} },
/* 20 */
- {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
+ {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
{6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
diff --git a/drivers/scsi/scsi_pm.c b/drivers/scsi/scsi_pm.c
index e4b7998..459abe1 100644
--- a/drivers/scsi/scsi_pm.c
+++ b/drivers/scsi/scsi_pm.c
@@ -219,13 +219,13 @@ static int sdev_runtime_suspend(struct device *dev)
struct scsi_device *sdev = to_scsi_device(dev);
int err = 0;
- if (pm && pm->runtime_suspend) {
- err = blk_pre_runtime_suspend(sdev->request_queue);
- if (err)
- return err;
+ err = blk_pre_runtime_suspend(sdev->request_queue);
+ if (err)
+ return err;
+ if (pm && pm->runtime_suspend)
err = pm->runtime_suspend(dev);
- blk_post_runtime_suspend(sdev->request_queue, err);
- }
+ blk_post_runtime_suspend(sdev->request_queue, err);
+
return err;
}
@@ -248,11 +248,11 @@ static int sdev_runtime_resume(struct device *dev)
const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
int err = 0;
- if (pm && pm->runtime_resume) {
- blk_pre_runtime_resume(sdev->request_queue);
+ blk_pre_runtime_resume(sdev->request_queue);
+ if (pm && pm->runtime_resume)
err = pm->runtime_resume(dev);
- blk_post_runtime_resume(sdev->request_queue, err);
- }
+ blk_post_runtime_resume(sdev->request_queue, err);
+
return err;
}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index f9f3f82..054923e 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -55,6 +55,7 @@
* Default timeout
*/
#define SCSI_TIMEOUT (2*HZ)
+#define SCSI_REPORT_LUNS_TIMEOUT (30*HZ)
/*
* Prefix values for the SCSI id's (stored in sysfs name field)
@@ -274,8 +275,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
sdev->request_queue->queuedata = sdev;
- if (!shost_use_blk_mq(sdev->host) &&
- (shost->bqt || shost->hostt->use_blk_tags)) {
+ if (!shost_use_blk_mq(sdev->host)) {
blk_queue_init_tags(sdev->request_queue,
sdev->host->cmd_per_lun, shost->bqt,
shost->hostt->tag_alloc_policy);
@@ -701,9 +701,12 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result,
* strings.
*/
if (sdev->inquiry_len < 36) {
- sdev_printk(KERN_INFO, sdev,
- "scsi scan: INQUIRY result too short (%d),"
- " using 36\n", sdev->inquiry_len);
+ if (!sdev->host->short_inquiry) {
+ shost_printk(KERN_INFO, sdev->host,
+ "scsi scan: INQUIRY result too short (%d),"
+ " using 36\n", sdev->inquiry_len);
+ sdev->host->short_inquiry = 1;
+ }
sdev->inquiry_len = 36;
}
@@ -1383,7 +1386,7 @@ retry:
result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE,
lun_data, length, &sshdr,
- SCSI_TIMEOUT + 4 * HZ, 3, NULL);
+ SCSI_REPORT_LUNS_TIMEOUT, 3, NULL);
SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
"scsi scan: REPORT LUNS"
@@ -1712,8 +1715,7 @@ static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost)
return NULL;
if (shost->async_scan) {
- shost_printk(KERN_INFO, shost, "%s called twice\n", __func__);
- dump_stack();
+ shost_printk(KERN_DEBUG, shost, "%s called twice\n", __func__);
return NULL;
}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index dff8faf..21930c9 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -775,6 +775,29 @@ static struct bin_attribute dev_attr_vpd_##_page = { \
sdev_vpd_pg_attr(pg83);
sdev_vpd_pg_attr(pg80);
+static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct scsi_device *sdev = to_scsi_device(dev);
+
+ if (!sdev->inquiry)
+ return -EINVAL;
+
+ return memory_read_from_buffer(buf, count, &off, sdev->inquiry,
+ sdev->inquiry_len);
+}
+
+static struct bin_attribute dev_attr_inquiry = {
+ .attr = {
+ .name = "inquiry",
+ .mode = S_IRUGO,
+ },
+ .size = 0,
+ .read = show_inquiry,
+};
+
static ssize_t
show_iostat_counterbits(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -900,7 +923,7 @@ sdev_store_queue_ramp_up_period(struct device *dev,
return -EINVAL;
sdev->queue_ramp_up_period = msecs_to_jiffies(period);
- return period;
+ return count;
}
static DEVICE_ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR,
@@ -959,6 +982,7 @@ static struct attribute *scsi_sdev_attrs[] = {
static struct bin_attribute *scsi_sdev_bin_attrs[] = {
&dev_attr_vpd_pg83,
&dev_attr_vpd_pg80,
+ &dev_attr_inquiry,
NULL
};
static struct attribute_group scsi_sdev_attr_group = {
@@ -1078,6 +1102,14 @@ void __scsi_remove_device(struct scsi_device *sdev)
{
struct device *dev = &sdev->sdev_gendev;
+ /*
+ * This cleanup path is not reentrant and while it is impossible
+ * to get a new reference with scsi_device_get() someone can still
+ * hold a previously acquired one.
+ */
+ if (sdev->sdev_state == SDEV_DEL)
+ return;
+
if (sdev->is_visible) {
if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
return;
@@ -1160,31 +1192,23 @@ static void __scsi_remove_target(struct scsi_target *starget)
void scsi_remove_target(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev->parent);
- struct scsi_target *starget, *last = NULL;
+ struct scsi_target *starget;
unsigned long flags;
- /* remove targets being careful to lookup next entry before
- * deleting the last
- */
+restart:
spin_lock_irqsave(shost->host_lock, flags);
list_for_each_entry(starget, &shost->__targets, siblings) {
if (starget->state == STARGET_DEL)
continue;
if (starget->dev.parent == dev || &starget->dev == dev) {
- /* assuming new targets arrive at the end */
kref_get(&starget->reap_ref);
spin_unlock_irqrestore(shost->host_lock, flags);
- if (last)
- scsi_target_reap(last);
- last = starget;
__scsi_remove_target(starget);
- spin_lock_irqsave(shost->host_lock, flags);
+ scsi_target_reap(starget);
+ goto restart;
}
}
spin_unlock_irqrestore(shost->host_lock, flags);
-
- if (last)
- scsi_target_reap(last);
}
EXPORT_SYMBOL(scsi_remove_target);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5e170a6..4e08d1cd 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -205,6 +205,7 @@ cache_type_store(struct device *dev, struct device_attribute *attr,
buffer_data[2] &= ~0x05;
buffer_data[2] |= wce << 2 | rcd;
sp = buffer_data[0] & 0x80 ? 1 : 0;
+ buffer_data[0] &= ~0x80;
if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
SD_MAX_RETRIES, &data, &sshdr)) {
@@ -637,11 +638,24 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
unsigned int max_blocks = 0;
q->limits.discard_zeroes_data = 0;
- q->limits.discard_alignment = sdkp->unmap_alignment *
- logical_block_size;
- q->limits.discard_granularity =
- max(sdkp->physical_block_size,
- sdkp->unmap_granularity * logical_block_size);
+
+ /*
+ * When LBPRZ is reported, discard alignment and granularity
+ * must be fixed to the logical block size. Otherwise the block
+ * layer will drop misaligned portions of the request which can
+ * lead to data corruption. If LBPRZ is not set, we honor the
+ * device preference.
+ */
+ if (sdkp->lbprz) {
+ q->limits.discard_alignment = 0;
+ q->limits.discard_granularity = 1;
+ } else {
+ q->limits.discard_alignment = sdkp->unmap_alignment *
+ logical_block_size;
+ q->limits.discard_granularity =
+ max(sdkp->physical_block_size,
+ sdkp->unmap_granularity * logical_block_size);
+ }
sdkp->provisioning_mode = mode;
@@ -2320,11 +2334,8 @@ got_data:
}
}
- if (sdkp->capacity > 0xffffffff) {
+ if (sdkp->capacity > 0xffffffff)
sdp->use_16_for_rw = 1;
- sdkp->max_xfer_blocks = SD_MAX_XFER_BLOCKS;
- } else
- sdkp->max_xfer_blocks = SD_DEF_XFER_BLOCKS;
/* Rescale capacity to 512-byte units */
if (sector_size == 4096)
@@ -2641,7 +2652,6 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
{
unsigned int sector_sz = sdkp->device->sector_size;
const int vpd_len = 64;
- u32 max_xfer_length;
unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL);
if (!buffer ||
@@ -2649,14 +2659,11 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len))
goto out;
- max_xfer_length = get_unaligned_be32(&buffer[8]);
- if (max_xfer_length)
- sdkp->max_xfer_blocks = max_xfer_length;
-
blk_queue_io_min(sdkp->disk->queue,
get_unaligned_be16(&buffer[6]) * sector_sz);
- blk_queue_io_opt(sdkp->disk->queue,
- get_unaligned_be32(&buffer[12]) * sector_sz);
+
+ sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]);
+ sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]);
if (buffer[3] == 0x3c) {
unsigned int lba_count, desc_count;
@@ -2805,6 +2812,11 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
return 0;
}
+static inline u32 logical_to_sectors(struct scsi_device *sdev, u32 blocks)
+{
+ return blocks << (ilog2(sdev->sector_size) - 9);
+}
+
/**
* sd_revalidate_disk - called the first time a new disk is seen,
* performs disk spin up, read_capacity, etc.
@@ -2814,8 +2826,9 @@ static int sd_revalidate_disk(struct gendisk *disk)
{
struct scsi_disk *sdkp = scsi_disk(disk);
struct scsi_device *sdp = sdkp->device;
+ struct request_queue *q = sdkp->disk->queue;
unsigned char *buffer;
- unsigned int max_xfer;
+ unsigned int dev_max, rw_max;
SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp,
"sd_revalidate_disk\n"));
@@ -2863,11 +2876,29 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
sd_set_flush_flag(sdkp);
- max_xfer = sdkp->max_xfer_blocks;
- max_xfer <<= ilog2(sdp->sector_size) - 9;
+ /* Initial block count limit based on CDB TRANSFER LENGTH field size. */
+ dev_max = sdp->use_16_for_rw ? SD_MAX_XFER_BLOCKS : SD_DEF_XFER_BLOCKS;
+
+ /* Some devices report a maximum block count for READ/WRITE requests. */
+ dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks);
+ q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max);
+
+ /*
+ * Use the device's preferred I/O size for reads and writes
+ * unless the reported value is unreasonably small, large, or
+ * garbage.
+ */
+ if (sdkp->opt_xfer_blocks &&
+ sdkp->opt_xfer_blocks <= dev_max &&
+ sdkp->opt_xfer_blocks <= SD_DEF_XFER_BLOCKS &&
+ sdkp->opt_xfer_blocks * sdp->sector_size >= PAGE_CACHE_SIZE)
+ rw_max = q->limits.io_opt =
+ logical_to_sectors(sdp, sdkp->opt_xfer_blocks);
+ else
+ rw_max = BLK_DEF_MAX_SECTORS;
- sdkp->disk->queue->limits.max_sectors =
- min_not_zero(queue_max_hw_sectors(sdkp->disk->queue), max_xfer);
+ /* Combine with controller limits */
+ q->limits.max_sectors = min(rw_max, queue_max_hw_sectors(q));
set_capacity(disk, sdkp->capacity);
sd_config_write_same(sdkp);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 63ba5ca..5f2a84a 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -67,6 +67,7 @@ struct scsi_disk {
atomic_t openers;
sector_t capacity; /* size in 512-byte sectors */
u32 max_xfer_blocks;
+ u32 opt_xfer_blocks;
u32 max_ws_blocks;
u32 max_unmap_blocks;
u32 unmap_granularity;
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index dcb0d76..044d064 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -84,6 +84,7 @@ static void init_device_slot_control(unsigned char *dest_desc,
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
void *buf, int bufflen)
{
+ int ret;
unsigned char cmd[] = {
RECEIVE_DIAGNOSTIC,
1, /* Set PCV bit */
@@ -92,9 +93,26 @@ static int ses_recv_diag(struct scsi_device *sdev, int page_code,
bufflen & 0xff,
0
};
+ unsigned char recv_page_code;
- return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
+ ret = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen,
NULL, SES_TIMEOUT, SES_RETRIES, NULL);
+ if (unlikely(!ret))
+ return ret;
+
+ recv_page_code = ((unsigned char *)buf)[0];
+
+ if (likely(recv_page_code == page_code))
+ return ret;
+
+ /* successful diagnostic but wrong page code. This happens to some
+ * USB devices, just print a message and pretend there was an error */
+
+ sdev_printk(KERN_ERR, sdev,
+ "Wrong diagnostic page; asked for %d got %u\n",
+ page_code, recv_page_code);
+
+ return -EINVAL;
}
static int ses_send_diag(struct scsi_device *sdev, int page_code,
@@ -541,7 +559,15 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
if (desc_ptr)
desc_ptr += len;
- if (addl_desc_ptr)
+ if (addl_desc_ptr &&
+ /* only find additional descriptions for specific devices */
+ (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_SAS_EXPANDER ||
+ /* these elements are optional */
+ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_TARGET_PORT ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT ||
+ type_ptr[0] == ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS))
addl_desc_ptr += addl_desc_ptr[1] + 2;
}
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 9d7b7db..503ab8b 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -787,8 +787,14 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return k; /* probably out of space --> ENOMEM */
}
if (atomic_read(&sdp->detaching)) {
- if (srp->bio)
+ if (srp->bio) {
+ if (srp->rq->cmd != srp->rq->__cmd)
+ kfree(srp->rq->cmd);
+
blk_end_request_all(srp->rq, -EIO);
+ srp->rq = NULL;
+ }
+
sg_finish_rem_req(srp);
return -ENODEV;
}
diff --git a/drivers/scsi/snic/snic_main.c b/drivers/scsi/snic/snic_main.c
index b2b87ce..2b3c253 100644
--- a/drivers/scsi/snic/snic_main.c
+++ b/drivers/scsi/snic/snic_main.c
@@ -124,7 +124,6 @@ static struct scsi_host_template snic_host_template = {
.sg_tablesize = SNIC_MAX_SG_DESC_CNT,
.max_sectors = 0x800,
.shost_attrs = snic_attrs,
- .use_blk_tags = 1,
.track_queue_depth = 1,
.cmd_size = sizeof(struct snic_internal_io_state),
.proc_name = "snic_scsi",
@@ -533,15 +532,6 @@ snic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
snic->max_tag_id = shost->can_queue;
- ret = scsi_init_shared_tag_map(shost, snic->max_tag_id);
- if (ret) {
- SNIC_HOST_ERR(shost,
- "Unable to alloc shared tag map. %d\n",
- ret);
-
- goto err_dev_close;
- }
-
shost->max_lun = snic->config.luns_per_tgt;
shost->max_id = SNIC_MAX_TARGET;
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b37b9b0..2e52295 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4083,6 +4083,7 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
}
cdev->owner = THIS_MODULE;
cdev->ops = &st_fops;
+ STm->cdevs[rew] = cdev;
error = cdev_add(cdev, cdev_devno, 1);
if (error) {
@@ -4091,7 +4092,6 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
pr_err("st%d: Device not attached.\n", dev_num);
goto out_free;
}
- STm->cdevs[rew] = cdev;
i = mode << (4 - ST_NBR_MODE_BITS);
snprintf(name, 10, "%s%s%s", rew ? "n" : "",
@@ -4110,8 +4110,9 @@ static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
return 0;
out_free:
cdev_del(STm->cdevs[rew]);
- STm->cdevs[rew] = NULL;
out:
+ STm->cdevs[rew] = NULL;
+ STm->devs[rew] = NULL;
return error;
}
@@ -4452,11 +4453,41 @@ static ssize_t version_show(struct device_driver *ddd, char *buf)
}
static DRIVER_ATTR_RO(version);
+#if DEBUG
+static ssize_t debug_flag_store(struct device_driver *ddp,
+ const char *buf, size_t count)
+{
+/* We only care what the first byte of the data is the rest is unused.
+ * if it's a '1' we turn on debug and if it's a '0' we disable it. All
+ * other values have -EINVAL returned if they are passed in.
+ */
+ if (count > 0) {
+ if (buf[0] == '0') {
+ debugging = NO_DEBUG;
+ return count;
+ } else if (buf[0] == '1') {
+ debugging = 1;
+ return count;
+ }
+ }
+ return -EINVAL;
+}
+
+static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", debugging);
+}
+static DRIVER_ATTR_RW(debug_flag);
+#endif
+
static struct attribute *st_drv_attrs[] = {
&driver_attr_try_direct_io.attr,
&driver_attr_fixed_buffer_size.attr,
&driver_attr_max_sg_segs.attr,
&driver_attr_version.attr,
+#if DEBUG
+ &driver_attr_debug_flag.attr,
+#endif
NULL,
};
ATTRIBUTE_GROUPS(st_drv);
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 98a62bc..2de28d7 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -25,6 +25,7 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/spinlock.h>
+#include <linux/ktime.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
@@ -362,14 +363,6 @@ MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers");
MODULE_LICENSE("GPL");
MODULE_VERSION(ST_DRIVER_VERSION);
-static void stex_gettime(__le64 *time)
-{
- struct timeval tv;
-
- do_gettimeofday(&tv);
- *time = cpu_to_le64(tv.tv_sec);
-}
-
static struct status_msg *stex_get_status(struct st_hba *hba)
{
struct status_msg *status = hba->status_buffer + hba->status_tail;
@@ -1002,7 +995,7 @@ static int stex_common_handshake(struct st_hba *hba)
h->req_cnt = cpu_to_le16(hba->rq_count+1);
h->status_sz = cpu_to_le16(sizeof(struct status_msg));
h->status_cnt = cpu_to_le16(hba->sts_count+1);
- stex_gettime(&h->hosttime);
+ h->hosttime = cpu_to_le64(ktime_get_real_seconds());
h->partner_type = HMU_PARTNER_TYPE;
if (hba->extra_offset) {
h->extra_offset = cpu_to_le32(hba->extra_offset);
@@ -1076,7 +1069,7 @@ static int stex_ss_handshake(struct st_hba *hba)
h->req_cnt = cpu_to_le16(hba->rq_count+1);
h->status_sz = cpu_to_le16(sizeof(struct status_msg));
h->status_cnt = cpu_to_le16(hba->sts_count+1);
- stex_gettime(&h->hosttime);
+ h->hosttime = cpu_to_le64(ktime_get_real_seconds());
h->partner_type = HMU_PARTNER_TYPE;
h->extra_offset = h->extra_size = 0;
scratch_size = (hba->sts_count+1)*sizeof(u32);
@@ -1374,7 +1367,6 @@ static struct scsi_host_template driver_template = {
.eh_abort_handler = stex_abort,
.eh_host_reset_handler = stex_reset,
.this_id = -1,
- .use_blk_tags = 1,
};
static struct pci_device_id stex_pci_tbl[] = {
@@ -1659,13 +1651,6 @@ static int stex_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (err)
goto out_free_irq;
- err = scsi_init_shared_tag_map(host, host->can_queue);
- if (err) {
- printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n",
- pci_name(pdev));
- goto out_free_irq;
- }
-
pci_set_drvdata(pdev, hba);
err = scsi_add_host(host, &pdev->dev);
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 40c43ae..3fba42a 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -349,11 +349,14 @@ enum storvsc_request_type {
*/
#define SRB_STATUS_AUTOSENSE_VALID 0x80
+#define SRB_STATUS_QUEUE_FROZEN 0x40
#define SRB_STATUS_INVALID_LUN 0x20
#define SRB_STATUS_SUCCESS 0x01
#define SRB_STATUS_ABORTED 0x02
#define SRB_STATUS_ERROR 0x04
+#define SRB_STATUS(status) \
+ (status & ~(SRB_STATUS_AUTOSENSE_VALID | SRB_STATUS_QUEUE_FROZEN))
/*
* This is the end of Protocol specific defines.
*/
@@ -393,9 +396,6 @@ static void storvsc_on_channel_callback(void *context);
struct storvsc_cmd_request {
struct scsi_cmnd *cmd;
- unsigned int bounce_sgl_count;
- struct scatterlist *bounce_sgl;
-
struct hv_device *device;
/* Synchronize the request/response if needed */
@@ -586,241 +586,6 @@ get_in_err:
}
-static void destroy_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count)
-{
- int i;
- struct page *page_buf;
-
- for (i = 0; i < sg_count; i++) {
- page_buf = sg_page((&sgl[i]));
- if (page_buf != NULL)
- __free_page(page_buf);
- }
-
- kfree(sgl);
-}
-
-static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count)
-{
- int i;
-
- /* No need to check */
- if (sg_count < 2)
- return -1;
-
- /* We have at least 2 sg entries */
- for (i = 0; i < sg_count; i++) {
- if (i == 0) {
- /* make sure 1st one does not have hole */
- if (sgl[i].offset + sgl[i].length != PAGE_SIZE)
- return i;
- } else if (i == sg_count - 1) {
- /* make sure last one does not have hole */
- if (sgl[i].offset != 0)
- return i;
- } else {
- /* make sure no hole in the middle */
- if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0)
- return i;
- }
- }
- return -1;
-}
-
-static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl,
- unsigned int sg_count,
- unsigned int len,
- int write)
-{
- int i;
- int num_pages;
- struct scatterlist *bounce_sgl;
- struct page *page_buf;
- unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE);
-
- num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT;
-
- bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC);
- if (!bounce_sgl)
- return NULL;
-
- sg_init_table(bounce_sgl, num_pages);
- for (i = 0; i < num_pages; i++) {
- page_buf = alloc_page(GFP_ATOMIC);
- if (!page_buf)
- goto cleanup;
- sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0);
- }
-
- return bounce_sgl;
-
-cleanup:
- destroy_bounce_buffer(bounce_sgl, num_pages);
- return NULL;
-}
-
-/* Assume the original sgl has enough room */
-static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count,
- unsigned int bounce_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long dest_addr = 0;
- unsigned long flags;
- struct scatterlist *cur_dest_sgl;
- struct scatterlist *cur_src_sgl;
-
- local_irq_save(flags);
- cur_dest_sgl = orig_sgl;
- cur_src_sgl = bounce_sgl;
- for (i = 0; i < orig_sgl_count; i++) {
- dest_addr = (unsigned long)
- kmap_atomic(sg_page(cur_dest_sgl)) +
- cur_dest_sgl->offset;
- dest = dest_addr;
- destlen = cur_dest_sgl->length;
-
- if (bounce_addr == 0)
- bounce_addr = (unsigned long)kmap_atomic(
- sg_page(cur_src_sgl));
-
- while (destlen) {
- src = bounce_addr + cur_src_sgl->offset;
- srclen = cur_src_sgl->length - cur_src_sgl->offset;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- cur_src_sgl->offset += copylen;
- destlen -= copylen;
- dest += copylen;
-
- if (cur_src_sgl->offset == cur_src_sgl->length) {
- /* full */
- kunmap_atomic((void *)bounce_addr);
- j++;
-
- /*
- * It is possible that the number of elements
- * in the bounce buffer may not be equal to
- * the number of elements in the original
- * scatter list. Handle this correctly.
- */
-
- if (j == bounce_sgl_count) {
- /*
- * We are done; cleanup and return.
- */
- kunmap_atomic((void *)(dest_addr -
- cur_dest_sgl->offset));
- local_irq_restore(flags);
- return total_copied;
- }
-
- /* if we need to use another bounce buffer */
- if (destlen || i != orig_sgl_count - 1) {
- cur_src_sgl = sg_next(cur_src_sgl);
- bounce_addr = (unsigned long)
- kmap_atomic(
- sg_page(cur_src_sgl));
- }
- } else if (destlen == 0 && i == orig_sgl_count - 1) {
- /* unmap the last bounce that is < PAGE_SIZE */
- kunmap_atomic((void *)bounce_addr);
- }
- }
-
- kunmap_atomic((void *)(dest_addr - cur_dest_sgl->offset));
- cur_dest_sgl = sg_next(cur_dest_sgl);
- }
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
-/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */
-static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl,
- struct scatterlist *bounce_sgl,
- unsigned int orig_sgl_count)
-{
- int i;
- int j = 0;
- unsigned long src, dest;
- unsigned int srclen, destlen, copylen;
- unsigned int total_copied = 0;
- unsigned long bounce_addr = 0;
- unsigned long src_addr = 0;
- unsigned long flags;
- struct scatterlist *cur_src_sgl;
- struct scatterlist *cur_dest_sgl;
-
- local_irq_save(flags);
-
- cur_src_sgl = orig_sgl;
- cur_dest_sgl = bounce_sgl;
-
- for (i = 0; i < orig_sgl_count; i++) {
- src_addr = (unsigned long)
- kmap_atomic(sg_page(cur_src_sgl)) +
- cur_src_sgl->offset;
- src = src_addr;
- srclen = cur_src_sgl->length;
-
- if (bounce_addr == 0)
- bounce_addr = (unsigned long)
- kmap_atomic(sg_page(cur_dest_sgl));
-
- while (srclen) {
- /* assume bounce offset always == 0 */
- dest = bounce_addr + cur_dest_sgl->length;
- destlen = PAGE_SIZE - cur_dest_sgl->length;
-
- copylen = min(srclen, destlen);
- memcpy((void *)dest, (void *)src, copylen);
-
- total_copied += copylen;
- cur_dest_sgl->length += copylen;
- srclen -= copylen;
- src += copylen;
-
- if (cur_dest_sgl->length == PAGE_SIZE) {
- /* full..move to next entry */
- kunmap_atomic((void *)bounce_addr);
- bounce_addr = 0;
- j++;
- }
-
- /* if we need to use another bounce buffer */
- if (srclen && bounce_addr == 0) {
- cur_dest_sgl = sg_next(cur_dest_sgl);
- bounce_addr = (unsigned long)
- kmap_atomic(
- sg_page(cur_dest_sgl));
- }
-
- }
-
- kunmap_atomic((void *)(src_addr - cur_src_sgl->offset));
- cur_src_sgl = sg_next(cur_src_sgl);
- }
-
- if (bounce_addr)
- kunmap_atomic((void *)bounce_addr);
-
- local_irq_restore(flags);
-
- return total_copied;
-}
-
static void handle_sc_creation(struct vmbus_channel *new_sc)
{
struct hv_device *device = new_sc->primary_channel->device_obj;
@@ -1096,7 +861,7 @@ static void storvsc_handle_error(struct vmscsi_request *vm_srb,
void (*process_err_fn)(struct work_struct *work);
bool do_work = false;
- switch (vm_srb->srb_status) {
+ switch (SRB_STATUS(vm_srb->srb_status)) {
case SRB_STATUS_ERROR:
/*
* If there is an error; offline the device since all
@@ -1171,15 +936,6 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
host = stor_dev->host;
vm_srb = &cmd_request->vstor_packet.vm_srb;
- if (cmd_request->bounce_sgl_count) {
- if (vm_srb->data_in == READ_TYPE)
- copy_from_bounce_buffer(scsi_sglist(scmnd),
- cmd_request->bounce_sgl,
- scsi_sg_count(scmnd),
- cmd_request->bounce_sgl_count);
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
- }
scmnd->result = vm_srb->scsi_status;
@@ -1474,6 +1230,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
blk_queue_rq_timeout(sdevice->request_queue, (storvsc_timeout * HZ));
+ /* Ensure there are no gaps in presented sgls */
+ blk_queue_virt_boundary(sdevice->request_queue, PAGE_SIZE - 1);
+
sdevice->no_write_same = 1;
/*
@@ -1647,8 +1406,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
vm_srb->win8_extension.time_out_value = 60;
vm_srb->win8_extension.srb_flags |=
- (SRB_FLAGS_QUEUE_ACTION_ENABLE |
- SRB_FLAGS_DISABLE_SYNCH_TRANSFER);
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
/* Build the SRB */
switch (scmnd->sc_data_direction) {
@@ -1692,40 +1450,13 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
payload_sz = sizeof(cmd_request->mpb);
if (sg_count) {
- /* check if we need to bounce the sgl */
- if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) {
- cmd_request->bounce_sgl =
- create_bounce_buffer(sgl, sg_count,
- length,
- vm_srb->data_in);
- if (!cmd_request->bounce_sgl)
- return SCSI_MLQUEUE_HOST_BUSY;
-
- cmd_request->bounce_sgl_count =
- ALIGN(length, PAGE_SIZE) >> PAGE_SHIFT;
-
- if (vm_srb->data_in == WRITE_TYPE)
- copy_to_bounce_buffer(sgl,
- cmd_request->bounce_sgl, sg_count);
-
- sgl = cmd_request->bounce_sgl;
- sg_count = cmd_request->bounce_sgl_count;
- }
-
-
if (sg_count > MAX_PAGE_BUFFER_COUNT) {
payload_sz = (sg_count * sizeof(void *) +
sizeof(struct vmbus_packet_mpb_array));
payload = kmalloc(payload_sz, GFP_ATOMIC);
- if (!payload) {
- if (cmd_request->bounce_sgl_count)
- destroy_bounce_buffer(
- cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
-
- return SCSI_MLQUEUE_DEVICE_BUSY;
- }
+ if (!payload)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
payload->range.len = length;
@@ -1754,11 +1485,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
if (ret == -EAGAIN) {
/* no more space */
-
- if (cmd_request->bounce_sgl_count)
- destroy_bounce_buffer(cmd_request->bounce_sgl,
- cmd_request->bounce_sgl_count);
-
return SCSI_MLQUEUE_DEVICE_BUSY;
}
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index e945383..5f45307 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -72,7 +72,7 @@ config SCSI_UFSHCD_PLATFORM
If unsure, say N.
config SCSI_UFS_QCOM
- bool "QCOM specific hooks to UFS controller platform driver"
+ tristate "QCOM specific hooks to UFS controller platform driver"
depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM
select PHY_QCOM_UFS
help
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 4cdffa4..4f38d00 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -19,16 +19,44 @@
#include <linux/phy/phy-qcom-ufs.h>
#include "ufshcd.h"
+#include "ufshcd-pltfrm.h"
#include "unipro.h"
#include "ufs-qcom.h"
#include "ufshci.h"
+#define UFS_QCOM_DEFAULT_DBG_PRINT_EN \
+ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+
+enum {
+ TSTBUS_UAWM,
+ TSTBUS_UARM,
+ TSTBUS_TXUC,
+ TSTBUS_RXUC,
+ TSTBUS_DFC,
+ TSTBUS_TRLUT,
+ TSTBUS_TMRLUT,
+ TSTBUS_OCSC,
+ TSTBUS_UTP_HCI,
+ TSTBUS_COMBINED,
+ TSTBUS_WRAPPER,
+ TSTBUS_UNIPRO,
+ TSTBUS_MAX,
+};
static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
-static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result);
-static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
- const char *speed_mode);
static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote);
+static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
+ u32 clk_cycles);
+
+static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
+ char *prefix)
+{
+ print_hex_dump(KERN_ERR, prefix,
+ len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
+ 16, 4, (void __force *)hba->mmio_base + offset,
+ len * 4, false);
+}
static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
{
@@ -149,13 +177,14 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
&host->tx_l1_sync_clk);
+
out:
return err;
}
static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
u32 tx_lanes;
int err = 0;
@@ -181,7 +210,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
do {
err = ufshcd_dme_get(hba,
- UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
if (err || tx_fsm_val == TX_FSM_HIBERN8)
break;
@@ -195,7 +226,9 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
*/
if (time_after(jiffies, timeout))
err = ufshcd_dme_get(hba,
- UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+ UIC_ARG_MIB_SEL(MPHY_TX_FSM_STATE,
+ UIC_ARG_MPHY_TX_GEN_SEL_INDEX(0)),
+ &tx_fsm_val);
if (err) {
dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
@@ -209,9 +242,18 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
return err;
}
+static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host)
+{
+ ufshcd_rmwl(host->hba, QUNIPRO_SEL,
+ ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0,
+ REG_UFS_CFG1);
+ /* make sure above configuration is applied before we return */
+ mb();
+}
+
static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
@@ -223,9 +265,11 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
usleep_range(1000, 1100);
ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
+
if (ret) {
- dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
- __func__, ret);
+ dev_err(hba->dev,
+ "%s: ufs_qcom_phy_calibrate_phy()failed, ret = %d\n",
+ __func__, ret);
goto out;
}
@@ -246,9 +290,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
ret = ufs_qcom_phy_is_pcs_ready(phy);
if (ret)
- dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
+ dev_err(hba->dev,
+ "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
__func__, ret);
+ ufs_qcom_select_unipro_mode(host);
+
out:
return ret;
}
@@ -271,9 +318,10 @@ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
mb();
}
-static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
+static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
int err = 0;
switch (status) {
@@ -301,13 +349,13 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
}
/**
- * Returns non-zero for success (which rate of core_clk) and 0
- * in case of a failure
+ * Returns zero for success and non-zero in case of a failure
*/
-static unsigned long
-ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
+static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear,
+ u32 hs, u32 rate, bool update_link_startup_timer)
{
- struct ufs_qcom_host *host = hba->priv;
+ int ret = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_clk_info *clki;
u32 core_clk_period_in_ns;
u32 tx_clk_cycles_per_us = 0;
@@ -324,11 +372,13 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
static u32 hs_fr_table_rA[][2] = {
{UFS_HS_G1, 0x1F},
{UFS_HS_G2, 0x3e},
+ {UFS_HS_G3, 0x7D},
};
static u32 hs_fr_table_rB[][2] = {
{UFS_HS_G1, 0x24},
{UFS_HS_G2, 0x49},
+ {UFS_HS_G3, 0x92},
};
/*
@@ -356,7 +406,17 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
core_clk_rate = DEFAULT_CLK_RATE_HZ;
core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
- ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
+ if (ufshcd_readl(hba, REG_UFS_SYS1CLK_1US) != core_clk_cycles_per_us) {
+ ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
+ /*
+ * make sure above write gets applied before we return from
+ * this function.
+ */
+ mb();
+ }
+
+ if (ufs_qcom_cap_qunipro(host))
+ goto out;
core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate;
core_clk_period_in_ns <<= OFFSET_CLK_NS_REG;
@@ -406,35 +466,59 @@ ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
goto out_error;
}
- /* this register 2 fields shall be written at once */
- ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,
- REG_UFS_TX_SYMBOL_CLK_NS_US);
+ if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) !=
+ (core_clk_period_in_ns | tx_clk_cycles_per_us)) {
+ /* this register 2 fields shall be written at once */
+ ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,
+ REG_UFS_TX_SYMBOL_CLK_NS_US);
+ /*
+ * make sure above write gets applied before we return from
+ * this function.
+ */
+ mb();
+ }
+
+ if (update_link_startup_timer) {
+ ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100),
+ REG_UFS_PA_LINK_STARTUP_TIMER);
+ /*
+ * make sure that this configuration is applied before
+ * we return
+ */
+ mb();
+ }
goto out;
out_error:
- core_clk_rate = 0;
+ ret = -EINVAL;
out:
- return core_clk_rate;
+ return ret;
}
-static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)
+static int ufs_qcom_link_startup_notify(struct ufs_hba *hba,
+ enum ufs_notify_change_status status)
{
- unsigned long core_clk_rate = 0;
- u32 core_clk_cycles_per_100ms;
+ int err = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
switch (status) {
case PRE_CHANGE:
- core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1,
- SLOWAUTO_MODE, 0);
- if (!core_clk_rate) {
+ if (ufs_qcom_cfg_timers(hba, UFS_PWM_G1, SLOWAUTO_MODE,
+ 0, true)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
- core_clk_cycles_per_100ms =
- (core_clk_rate / MSEC_PER_SEC) * 100;
- ufshcd_writel(hba, core_clk_cycles_per_100ms,
- REG_UFS_PA_LINK_STARTUP_TIMER);
+
+ if (ufs_qcom_cap_qunipro(host))
+ /*
+ * set unipro core clock cycles to 150 & clear clock
+ * divider
+ */
+ err = ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba,
+ 150);
+
break;
case POST_CHANGE:
ufs_qcom_link_startup_post_change(hba);
@@ -443,12 +527,13 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)
break;
}
- return 0;
+out:
+ return err;
}
static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int ret = 0;
@@ -470,8 +555,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* If UniPro link is not active, PHY ref_clk, main PHY analog power
* rail and low noise analog power rail for PLL can be switched off.
*/
- if (!ufs_qcom_is_link_active(hba))
+ if (!ufs_qcom_is_link_active(hba)) {
+ ufs_qcom_disable_lane_clks(host);
phy_power_off(phy);
+ }
out:
return ret;
@@ -479,7 +566,7 @@ out:
static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
int err;
@@ -490,6 +577,10 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
goto out;
}
+ err = ufs_qcom_enable_lane_clks(host);
+ if (err)
+ goto out;
+
hba->is_sys_suspended = false;
out:
@@ -594,6 +685,81 @@ static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,
return 0;
}
+#ifdef CONFIG_MSM_BUS_SCALING
+static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
+ const char *speed_mode)
+{
+ struct device *dev = host->hba->dev;
+ struct device_node *np = dev->of_node;
+ int err;
+ const char *key = "qcom,bus-vector-names";
+
+ if (!speed_mode) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN"))
+ err = of_property_match_string(np, key, "MAX");
+ else
+ err = of_property_match_string(np, key, speed_mode);
+
+out:
+ if (err < 0)
+ dev_err(dev, "%s: Invalid %s mode %d\n",
+ __func__, speed_mode, err);
+ return err;
+}
+
+static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)
+{
+ int gear = max_t(u32, p->gear_rx, p->gear_tx);
+ int lanes = max_t(u32, p->lane_rx, p->lane_tx);
+ int pwr;
+
+ /* default to PWM Gear 1, Lane 1 if power mode is not initialized */
+ if (!gear)
+ gear = 1;
+
+ if (!lanes)
+ lanes = 1;
+
+ if (!p->pwr_rx && !p->pwr_tx) {
+ pwr = SLOWAUTO_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "MIN");
+ } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE ||
+ p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) {
+ pwr = FAST_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS",
+ p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes);
+ } else {
+ pwr = SLOW_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d",
+ "PWM", gear, lanes);
+ }
+}
+
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+{
+ int err = 0;
+
+ if (vote != host->bus_vote.curr_vote) {
+ err = msm_bus_scale_client_update_request(
+ host->bus_vote.client_handle, vote);
+ if (err) {
+ dev_err(host->hba->dev,
+ "%s: msm_bus_scale_client_update_request() failed: bus_client_handle=0x%x, vote=%d, err=%d\n",
+ __func__, host->bus_vote.client_handle,
+ vote, err);
+ goto out;
+ }
+
+ host->bus_vote.curr_vote = vote;
+ }
+out:
+ return err;
+}
+
static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
{
int vote;
@@ -615,13 +781,137 @@ static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
return err;
}
+static ssize_t
+show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ host->bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ uint32_t value;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ host->bus_vote.is_max_bw_needed = !!value;
+ ufs_qcom_update_bus_bw_vote(host);
+ }
+
+ return count;
+}
+
+static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
+{
+ int err;
+ struct msm_bus_scale_pdata *bus_pdata;
+ struct device *dev = host->hba->dev;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct device_node *np = dev->of_node;
+
+ bus_pdata = msm_bus_cl_get_pdata(pdev);
+ if (!bus_pdata) {
+ dev_err(dev, "%s: failed to get bus vectors\n", __func__);
+ err = -ENODATA;
+ goto out;
+ }
+
+ err = of_property_count_strings(np, "qcom,bus-vector-names");
+ if (err < 0 || err != bus_pdata->num_usecases) {
+ dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ host->bus_vote.client_handle = msm_bus_scale_register_client(bus_pdata);
+ if (!host->bus_vote.client_handle) {
+ dev_err(dev, "%s: msm_bus_scale_register_client failed\n",
+ __func__);
+ err = -EFAULT;
+ goto out;
+ }
+
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN");
+ host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX");
+
+ host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw;
+ host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw;
+ sysfs_attr_init(&host->bus_vote.max_bus_bw.attr);
+ host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
+ host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ err = device_create_file(dev, &host->bus_vote.max_bus_bw);
+out:
+ return err;
+}
+#else /* CONFIG_MSM_BUS_SCALING */
+static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
+{
+ return 0;
+}
+
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+{
+ return 0;
+}
+
+static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
+{
+ return 0;
+}
+#endif /* CONFIG_MSM_BUS_SCALING */
+
+static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable)
+{
+ if (host->dev_ref_clk_ctrl_mmio &&
+ (enable ^ host->is_dev_ref_clk_enabled)) {
+ u32 temp = readl_relaxed(host->dev_ref_clk_ctrl_mmio);
+
+ if (enable)
+ temp |= host->dev_ref_clk_en_mask;
+ else
+ temp &= ~host->dev_ref_clk_en_mask;
+
+ /*
+ * If we are here to disable this clock it might be immediately
+ * after entering into hibern8 in which case we need to make
+ * sure that device ref_clk is active at least 1us after the
+ * hibern8 enter.
+ */
+ if (!enable)
+ udelay(1);
+
+ writel_relaxed(temp, host->dev_ref_clk_ctrl_mmio);
+
+ /* ensure that ref_clk is enabled/disabled before we return */
+ wmb();
+
+ /*
+ * If we call hibern8 exit after this, we need to make sure that
+ * device ref_clk is stable for at least 1us before the hibern8
+ * exit command.
+ */
+ if (enable)
+ udelay(1);
+
+ host->is_dev_ref_clk_enabled = enable;
+ }
+}
+
static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
- bool status,
+ enum ufs_notify_change_status status,
struct ufs_pa_layer_attr *dev_max_params,
struct ufs_pa_layer_attr *dev_req_params)
{
u32 val;
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct phy *phy = host->generic_phy;
struct ufs_qcom_dev_params ufs_qcom_cap;
int ret = 0;
@@ -649,6 +939,20 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
ufs_qcom_cap.desired_working_mode =
UFS_QCOM_LIMIT_DESIRED_MODE;
+ if (host->hw_ver.major == 0x1) {
+ /*
+ * HS-G3 operations may not reliably work on legacy QCOM
+ * UFS host controller hardware even though capability
+ * exchange during link startup phase may end up
+ * negotiating maximum supported gear as G3.
+ * Hence downgrade the maximum supported gear to HS-G2.
+ */
+ if (ufs_qcom_cap.hs_tx_gear > UFS_HS_G2)
+ ufs_qcom_cap.hs_tx_gear = UFS_HS_G2;
+ if (ufs_qcom_cap.hs_rx_gear > UFS_HS_G2)
+ ufs_qcom_cap.hs_rx_gear = UFS_HS_G2;
+ }
+
ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap,
dev_max_params,
dev_req_params);
@@ -660,9 +964,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
break;
case POST_CHANGE:
- if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
+ if (ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
dev_req_params->pwr_rx,
- dev_req_params->hs_rate)) {
+ dev_req_params->hs_rate, false)) {
dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
__func__);
/*
@@ -696,7 +1000,7 @@ out:
static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
if (host->hw_ver.major == 0x1)
return UFSHCI_VERSION_11;
@@ -715,7 +1019,7 @@ static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba)
*/
static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
if (host->hw_ver.major == 0x01) {
hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
@@ -724,10 +1028,11 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001)
hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR;
+
+ hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
}
if (host->hw_ver.major >= 0x2) {
- hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC;
hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION;
if (!ufs_qcom_cap_qunipro(host))
@@ -740,79 +1045,29 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
static void ufs_qcom_set_caps(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
- if (host->hw_ver.major >= 0x2)
- host->caps = UFS_QCOM_CAP_QUNIPRO;
-}
-
-static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
- const char *speed_mode)
-{
- struct device *dev = host->hba->dev;
- struct device_node *np = dev->of_node;
- int err;
- const char *key = "qcom,bus-vector-names";
-
- if (!speed_mode) {
- err = -EINVAL;
- goto out;
- }
-
- if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN"))
- err = of_property_match_string(np, key, "MAX");
- else
- err = of_property_match_string(np, key, speed_mode);
-
-out:
- if (err < 0)
- dev_err(dev, "%s: Invalid %s mode %d\n",
- __func__, speed_mode, err);
- return err;
-}
-
-static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
-{
- int err = 0;
-
- if (vote != host->bus_vote.curr_vote)
- host->bus_vote.curr_vote = vote;
-
- return err;
-}
-
-static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)
-{
- int gear = max_t(u32, p->gear_rx, p->gear_tx);
- int lanes = max_t(u32, p->lane_rx, p->lane_tx);
- int pwr;
-
- /* default to PWM Gear 1, Lane 1 if power mode is not initialized */
- if (!gear)
- gear = 1;
-
- if (!lanes)
- lanes = 1;
+ hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING;
+ hba->caps |= UFSHCD_CAP_CLK_SCALING;
+ hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
- if (!p->pwr_rx && !p->pwr_tx) {
- pwr = SLOWAUTO_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "MIN");
- } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE ||
- p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) {
- pwr = FAST_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS",
- p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes);
- } else {
- pwr = SLOW_MODE;
- snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d",
- "PWM", gear, lanes);
+ if (host->hw_ver.major >= 0x2) {
+ host->caps = UFS_QCOM_CAP_QUNIPRO |
+ UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE;
}
}
+/**
+ * ufs_qcom_setup_clocks - enables/disable clocks
+ * @hba: host controller instance
+ * @on: If true, enable clocks else disable them.
+ *
+ * Returns 0 on success, non-zero on failure.
+ */
static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
{
- struct ufs_qcom_host *host = hba->priv;
- int err = 0;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ int err;
int vote = 0;
/*
@@ -835,20 +1090,18 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
goto out;
}
- /* enable the device ref clock */
- ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy);
vote = host->bus_vote.saved_vote;
if (vote == host->bus_vote.min_bw_vote)
ufs_qcom_update_bus_bw_vote(host);
+
} else {
+
/* M-PHY RMMI interface clocks can be turned off */
ufs_qcom_phy_disable_iface_clk(host->generic_phy);
- if (!ufs_qcom_is_link_active(hba)) {
- /* turn off UFS local PHY ref_clk */
- ufs_qcom_phy_disable_ref_clk(host->generic_phy);
+ if (!ufs_qcom_is_link_active(hba))
/* disable device ref_clk */
- ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy);
- }
+ ufs_qcom_dev_ref_clk_ctrl(host, false);
+
vote = host->bus_vote.min_bw_vote;
}
@@ -861,68 +1114,17 @@ out:
return err;
}
-static ssize_t
-show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- struct ufs_qcom_host *host = hba->priv;
-
- return snprintf(buf, PAGE_SIZE, "%u\n",
- host->bus_vote.is_max_bw_needed);
-}
-
-static ssize_t
-store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ufs_hba *hba = dev_get_drvdata(dev);
- struct ufs_qcom_host *host = hba->priv;
- uint32_t value;
-
- if (!kstrtou32(buf, 0, &value)) {
- host->bus_vote.is_max_bw_needed = !!value;
- ufs_qcom_update_bus_bw_vote(host);
- }
-
- return count;
-}
-
-static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
-{
- int err;
- struct device *dev = host->hba->dev;
- struct device_node *np = dev->of_node;
-
- err = of_property_count_strings(np, "qcom,bus-vector-names");
- if (err < 0 ) {
- dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n",
- __func__, err);
- goto out;
- }
-
- /* cache the vote index for minimum and maximum bandwidth */
- host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN");
- host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX");
-
- host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw;
- host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw;
- sysfs_attr_init(&host->bus_vote.max_bus_bw.attr);
- host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
- host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
- err = device_create_file(dev, &host->bus_vote.max_bus_bw);
-out:
- return err;
-}
-
#define ANDROID_BOOT_DEV_MAX 30
static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
-static int get_android_boot_dev(char *str)
+
+#ifndef MODULE
+static int __init get_android_boot_dev(char *str)
{
strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX);
return 1;
}
__setup("androidboot.bootdevice=", get_android_boot_dev);
+#endif
/**
* ufs_qcom_init - bind phy with controller
@@ -938,7 +1140,9 @@ static int ufs_qcom_init(struct ufs_hba *hba)
{
int err;
struct device *dev = hba->dev;
+ struct platform_device *pdev = to_platform_device(dev);
struct ufs_qcom_host *host;
+ struct resource *res;
if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
return -ENODEV;
@@ -950,9 +1154,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
goto out;
}
+ /* Make a two way bind between the qcom host and the hba */
host->hba = hba;
- hba->priv = (void *)host;
+ ufshcd_set_variant(hba, host);
+ /*
+ * voting/devoting device ref_clk source is time consuming hence
+ * skip devoting it during aggressive clock gating. This clock
+ * will still be gated off during runtime suspend.
+ */
host->generic_phy = devm_phy_get(dev, "ufsphy");
if (IS_ERR(host->generic_phy)) {
@@ -968,6 +1178,30 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_get_controller_revision(hba, &host->hw_ver.major,
&host->hw_ver.minor, &host->hw_ver.step);
+ /*
+ * for newer controllers, device reference clock control bit has
+ * moved inside UFS controller register address space itself.
+ */
+ if (host->hw_ver.major >= 0x02) {
+ host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1;
+ host->dev_ref_clk_en_mask = BIT(26);
+ } else {
+ /* "dev_ref_clk_ctrl_mem" is optional resource */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (res) {
+ host->dev_ref_clk_ctrl_mmio =
+ devm_ioremap_resource(dev, res);
+ if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) {
+ dev_warn(dev,
+ "%s: could not map dev_ref_clk_ctrl_mmio, err %ld\n",
+ __func__,
+ PTR_ERR(host->dev_ref_clk_ctrl_mmio));
+ host->dev_ref_clk_ctrl_mmio = NULL;
+ }
+ host->dev_ref_clk_en_mask = BIT(5);
+ }
+ }
+
/* update phy revision information before calling phy_init() */
ufs_qcom_phy_save_controller_version(host->generic_phy,
host->hw_ver.major, host->hw_ver.minor, host->hw_ver.step);
@@ -984,14 +1218,20 @@ static int ufs_qcom_init(struct ufs_hba *hba)
ufs_qcom_set_caps(hba);
ufs_qcom_advertise_quirks(hba);
- hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING;
- hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
-
ufs_qcom_setup_clocks(hba, true);
if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
ufs_qcom_hosts[hba->dev->id] = host;
+ host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
+ ufs_qcom_get_default_testbus_cfg(host);
+ err = ufs_qcom_testbus_config(host);
+ if (err) {
+ dev_warn(dev, "%s: failed to configure the testbus %d\n",
+ __func__, err);
+ err = 0;
+ }
+
goto out;
out_disable_phy:
@@ -1000,40 +1240,266 @@ out_unregister_bus:
phy_exit(host->generic_phy);
out_host_free:
devm_kfree(dev, host);
- hba->priv = NULL;
+ ufshcd_set_variant(hba, NULL);
out:
return err;
}
static void ufs_qcom_exit(struct ufs_hba *hba)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
ufs_qcom_disable_lane_clks(host);
phy_power_off(host->generic_phy);
}
-static
-void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
+static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba,
+ u32 clk_cycles)
+{
+ int err;
+ u32 core_clk_ctrl_reg;
+
+ if (clk_cycles > DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK)
+ return -EINVAL;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ &core_clk_ctrl_reg);
+ if (err)
+ goto out;
+
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK;
+ core_clk_ctrl_reg |= clk_cycles;
+
+ /* Clear CORE_CLK_DIV_EN */
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
+
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ core_clk_ctrl_reg);
+out:
+ return err;
+}
+
+static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba)
+{
+ /* nothing to do as of now */
+ return 0;
+}
+
+static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ /* set unipro core clock cycles to 150 and clear clock divider */
+ return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 150);
+}
+
+static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+ int err;
+ u32 core_clk_ctrl_reg;
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ &core_clk_ctrl_reg);
+
+ /* make sure CORE_CLK_DIV_EN is cleared */
+ if (!err &&
+ (core_clk_ctrl_reg & DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT)) {
+ core_clk_ctrl_reg &= ~DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT;
+ err = ufshcd_dme_set(hba,
+ UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL),
+ core_clk_ctrl_reg);
+ }
+
+ return err;
+}
+
+static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
+
+ if (!ufs_qcom_cap_qunipro(host))
+ return 0;
+
+ /* set unipro core clock cycles to 75 and clear clock divider */
+ return ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(hba, 75);
+}
+
+static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba,
+ bool scale_up, enum ufs_notify_change_status status)
{
- struct ufs_qcom_host *host = hba->priv;
+ struct ufs_qcom_host *host = ufshcd_get_variant(hba);
struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
+ int err = 0;
- if (!dev_req_params)
- return;
+ if (status == PRE_CHANGE) {
+ if (scale_up)
+ err = ufs_qcom_clk_scale_up_pre_change(hba);
+ else
+ err = ufs_qcom_clk_scale_down_pre_change(hba);
+ } else {
+ if (scale_up)
+ err = ufs_qcom_clk_scale_up_post_change(hba);
+ else
+ err = ufs_qcom_clk_scale_down_post_change(hba);
- ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
- dev_req_params->pwr_rx,
- dev_req_params->hs_rate);
+ if (err || !dev_req_params)
+ goto out;
+
+ ufs_qcom_cfg_timers(hba,
+ dev_req_params->gear_rx,
+ dev_req_params->pwr_rx,
+ dev_req_params->hs_rate,
+ false);
+ ufs_qcom_update_bus_bw_vote(host);
+ }
+
+out:
+ return err;
}
+static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
+{
+ /* provide a legal default configuration */
+ host->testbus.select_major = TSTBUS_UAWM;
+ host->testbus.select_minor = 1;
+}
+
+static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
+{
+ if (host->testbus.select_major >= TSTBUS_MAX) {
+ dev_err(host->hba->dev,
+ "%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
+ __func__, host->testbus.select_major);
+ return false;
+ }
+
+ /*
+ * Not performing check for each individual select_major
+ * mappings of select_minor, since there is no harm in
+ * configuring a non-existent select_minor
+ */
+ if (host->testbus.select_minor > 0x1F) {
+ dev_err(host->hba->dev,
+ "%s: 0x%05X is not a legal testbus option\n",
+ __func__, host->testbus.select_minor);
+ return false;
+ }
+
+ return true;
+}
+
+int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
+{
+ int reg;
+ int offset;
+ u32 mask = TEST_BUS_SUB_SEL_MASK;
+
+ if (!host)
+ return -EINVAL;
+
+ if (!ufs_qcom_testbus_cfg_is_ok(host))
+ return -EPERM;
+
+ switch (host->testbus.select_major) {
+ case TSTBUS_UAWM:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 24;
+ break;
+ case TSTBUS_UARM:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 16;
+ break;
+ case TSTBUS_TXUC:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 8;
+ break;
+ case TSTBUS_RXUC:
+ reg = UFS_TEST_BUS_CTRL_0;
+ offset = 0;
+ break;
+ case TSTBUS_DFC:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 24;
+ break;
+ case TSTBUS_TRLUT:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 16;
+ break;
+ case TSTBUS_TMRLUT:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 8;
+ break;
+ case TSTBUS_OCSC:
+ reg = UFS_TEST_BUS_CTRL_1;
+ offset = 0;
+ break;
+ case TSTBUS_WRAPPER:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 16;
+ break;
+ case TSTBUS_COMBINED:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 8;
+ break;
+ case TSTBUS_UTP_HCI:
+ reg = UFS_TEST_BUS_CTRL_2;
+ offset = 0;
+ break;
+ case TSTBUS_UNIPRO:
+ reg = UFS_UNIPRO_CFG;
+ offset = 1;
+ break;
+ /*
+ * No need for a default case, since
+ * ufs_qcom_testbus_cfg_is_ok() checks that the configuration
+ * is legal
+ */
+ }
+ mask <<= offset;
+
+ pm_runtime_get_sync(host->hba->dev);
+ ufshcd_hold(host->hba, false);
+ ufshcd_rmwl(host->hba, TEST_BUS_SEL,
+ (u32)host->testbus.select_major << 19,
+ REG_UFS_CFG1);
+ ufshcd_rmwl(host->hba, mask,
+ (u32)host->testbus.select_minor << offset,
+ reg);
+ ufshcd_release(host->hba);
+ pm_runtime_put_sync(host->hba->dev);
+
+ return 0;
+}
+
+static void ufs_qcom_testbus_read(struct ufs_hba *hba)
+{
+ ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
+}
+
+static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
+{
+ ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
+ "HCI Vendor Specific Registers ");
+
+ ufs_qcom_testbus_read(hba);
+}
/**
* struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
*
* The variant operations configure the necessary controller and PHY
* handshake during initialization.
*/
-static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
+static struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.name = "qcom",
.init = ufs_qcom_init,
.exit = ufs_qcom_exit,
@@ -1045,5 +1511,66 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
.pwr_change_notify = ufs_qcom_pwr_change_notify,
.suspend = ufs_qcom_suspend,
.resume = ufs_qcom_resume,
+ .dbg_register_dump = ufs_qcom_dump_dbg_regs,
+};
+
+/**
+ * ufs_qcom_probe - probe routine of the driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Return zero for success and non-zero for failure
+ */
+static int ufs_qcom_probe(struct platform_device *pdev)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+
+ /* Perform generic probe */
+ err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops);
+ if (err)
+ dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
+
+ return err;
+}
+
+/**
+ * ufs_qcom_remove - set driver_data of the device to NULL
+ * @pdev: pointer to platform device handle
+ *
+ * Always return 0
+ */
+static int ufs_qcom_remove(struct platform_device *pdev)
+{
+ struct ufs_hba *hba = platform_get_drvdata(pdev);
+
+ pm_runtime_get_sync(&(pdev)->dev);
+ ufshcd_remove(hba);
+ return 0;
+}
+
+static const struct of_device_id ufs_qcom_of_match[] = {
+ { .compatible = "qcom,ufshc"},
+ {},
+};
+
+static const struct dev_pm_ops ufs_qcom_pm_ops = {
+ .suspend = ufshcd_pltfrm_suspend,
+ .resume = ufshcd_pltfrm_resume,
+ .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
+ .runtime_resume = ufshcd_pltfrm_runtime_resume,
+ .runtime_idle = ufshcd_pltfrm_runtime_idle,
};
-EXPORT_SYMBOL(ufs_hba_qcom_vops);
+
+static struct platform_driver ufs_qcom_pltform = {
+ .probe = ufs_qcom_probe,
+ .remove = ufs_qcom_remove,
+ .shutdown = ufshcd_pltfrm_shutdown,
+ .driver = {
+ .name = "ufshcd-qcom",
+ .pm = &ufs_qcom_pm_ops,
+ .of_match_table = of_match_ptr(ufs_qcom_of_match),
+ },
+};
+module_platform_driver(ufs_qcom_pltform);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
index db2c0a0..36249b3 100644
--- a/drivers/scsi/ufs/ufs-qcom.h
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -35,8 +35,8 @@
#define UFS_QCOM_LIMIT_NUM_LANES_RX 2
#define UFS_QCOM_LIMIT_NUM_LANES_TX 2
-#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2
-#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2
+#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G3
+#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G3
#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4
#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4
#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE
@@ -58,6 +58,21 @@ enum {
REG_UFS_CFG2 = 0xE0,
REG_UFS_HW_VERSION = 0xE4,
+ UFS_TEST_BUS = 0xE8,
+ UFS_TEST_BUS_CTRL_0 = 0xEC,
+ UFS_TEST_BUS_CTRL_1 = 0xF0,
+ UFS_TEST_BUS_CTRL_2 = 0xF4,
+ UFS_UNIPRO_CFG = 0xF8,
+
+ /*
+ * QCOM UFS host controller vendor specific registers
+ * added in HW Version 3.0.0
+ */
+ UFS_AH8_CFG = 0xFC,
+};
+
+/* QCOM UFS host controller vendor specific debug registers */
+enum {
UFS_DBG_RD_REG_UAWM = 0x100,
UFS_DBG_RD_REG_UARM = 0x200,
UFS_DBG_RD_REG_TXUC = 0x300,
@@ -73,6 +88,14 @@ enum {
UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
};
+#define UFS_CNTLR_2_x_x_VEN_REGS_OFFSET(x) (0x000 + x)
+#define UFS_CNTLR_3_x_x_VEN_REGS_OFFSET(x) (0x400 + x)
+
+/* bit definitions for REG_UFS_CFG1 register */
+#define QUNIPRO_SEL UFS_BIT(0)
+#define TEST_BUS_EN BIT(18)
+#define TEST_BUS_SEL GENMASK(22, 19)
+
/* bit definitions for REG_UFS_CFG2 register */
#define UAWM_HW_CGC_EN (1 << 0)
#define UARM_HW_CGC_EN (1 << 1)
@@ -83,6 +106,9 @@ enum {
#define TMRLUT_HW_CGC_EN (1 << 6)
#define OCSC_HW_CGC_EN (1 << 7)
+/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
+#define TEST_BUS_SUB_SEL_MASK 0x1F /* All XXX_SEL fields are 5 bits wide */
+
#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
@@ -106,6 +132,21 @@ enum ufs_qcom_phy_init_type {
UFS_PHY_INIT_CFG_RESTORE,
};
+/* QCOM UFS debug print bit mask */
+#define UFS_QCOM_DBG_PRINT_REGS_EN BIT(0)
+#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN BIT(1)
+#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN BIT(2)
+
+#define UFS_QCOM_DBG_PRINT_ALL \
+ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
+ UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
+
+/* QUniPro Vendor specific attributes */
+#define DME_VS_CORE_CLK_CTRL 0xD002
+/* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */
+#define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8)
+#define DME_VS_CORE_CLK_CTRL_MAX_CORE_CLK_1US_CYCLES_MASK 0xFF
+
static inline void
ufs_qcom_get_controller_revision(struct ufs_hba *hba,
u8 *major, u16 *minor, u16 *step)
@@ -157,8 +198,13 @@ struct ufs_hw_version {
u16 minor;
u8 major;
};
-struct ufs_qcom_host {
+struct ufs_qcom_testbus {
+ u8 select_major;
+ u8 select_minor;
+};
+
+struct ufs_qcom_host {
/*
* Set this capability if host controller supports the QUniPro mode
* and if driver wants the Host controller to operate in QUniPro mode.
@@ -166,6 +212,12 @@ struct ufs_qcom_host {
* controller supports the QUniPro mode.
*/
#define UFS_QCOM_CAP_QUNIPRO UFS_BIT(0)
+
+ /*
+ * Set this capability if host controller can retain the secure
+ * configuration even after UFS controller core power collapse.
+ */
+ #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE UFS_BIT(1)
u32 caps;
struct phy *generic_phy;
@@ -178,13 +230,23 @@ struct ufs_qcom_host {
struct clk *tx_l1_sync_clk;
bool is_lane_clks_enabled;
+ void __iomem *dev_ref_clk_ctrl_mmio;
+ bool is_dev_ref_clk_enabled;
struct ufs_hw_version hw_ver;
+
+ u32 dev_ref_clk_en_mask;
+
+ /* Bitmask for enabling debug prints */
+ u32 dbg_print_en;
+ struct ufs_qcom_testbus testbus;
};
#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
+int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
+
static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
{
if (host->caps & UFS_QCOM_CAP_QUNIPRO)
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7db9564..9714f2a 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -38,20 +38,7 @@
#include <linux/of.h>
#include "ufshcd.h"
-
-static const struct of_device_id ufs_of_match[];
-static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
-{
- if (dev->of_node) {
- const struct of_device_id *match;
-
- match = of_match_node(ufs_of_match, dev->of_node);
- if (match)
- return (struct ufs_hba_variant_ops *)match->data;
- }
-
- return NULL;
-}
+#include "ufshcd-pltfrm.h"
static int ufshcd_parse_clock_info(struct ufs_hba *hba)
{
@@ -245,10 +232,11 @@ out:
* Returns 0 if successful
* Returns non-zero otherwise
*/
-static int ufshcd_pltfrm_suspend(struct device *dev)
+int ufshcd_pltfrm_suspend(struct device *dev)
{
return ufshcd_system_suspend(dev_get_drvdata(dev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend);
/**
* ufshcd_pltfrm_resume - resume power management function
@@ -257,43 +245,47 @@ static int ufshcd_pltfrm_suspend(struct device *dev)
* Returns 0 if successful
* Returns non-zero otherwise
*/
-static int ufshcd_pltfrm_resume(struct device *dev)
+int ufshcd_pltfrm_resume(struct device *dev)
{
return ufshcd_system_resume(dev_get_drvdata(dev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume);
-static int ufshcd_pltfrm_runtime_suspend(struct device *dev)
+int ufshcd_pltfrm_runtime_suspend(struct device *dev)
{
return ufshcd_runtime_suspend(dev_get_drvdata(dev));
}
-static int ufshcd_pltfrm_runtime_resume(struct device *dev)
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend);
+
+int ufshcd_pltfrm_runtime_resume(struct device *dev)
{
return ufshcd_runtime_resume(dev_get_drvdata(dev));
}
-static int ufshcd_pltfrm_runtime_idle(struct device *dev)
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume);
+
+int ufshcd_pltfrm_runtime_idle(struct device *dev)
{
return ufshcd_runtime_idle(dev_get_drvdata(dev));
}
-#else /* !CONFIG_PM */
-#define ufshcd_pltfrm_suspend NULL
-#define ufshcd_pltfrm_resume NULL
-#define ufshcd_pltfrm_runtime_suspend NULL
-#define ufshcd_pltfrm_runtime_resume NULL
-#define ufshcd_pltfrm_runtime_idle NULL
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle);
+
#endif /* CONFIG_PM */
-static void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
+void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
{
ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev));
}
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown);
/**
- * ufshcd_pltfrm_probe - probe routine of the driver
+ * ufshcd_pltfrm_init - probe routine of the driver
* @pdev: pointer to Platform device handle
+ * @vops: pointer to variant ops
*
* Returns 0 on success, non-zero value on failure
*/
-static int ufshcd_pltfrm_probe(struct platform_device *pdev)
+int ufshcd_pltfrm_init(struct platform_device *pdev,
+ struct ufs_hba_variant_ops *vops)
{
struct ufs_hba *hba;
void __iomem *mmio_base;
@@ -321,19 +313,19 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
goto out;
}
- hba->vops = get_variant_ops(&pdev->dev);
+ hba->vops = vops;
err = ufshcd_parse_clock_info(hba);
if (err) {
dev_err(&pdev->dev, "%s: clock parse failed %d\n",
__func__, err);
- goto out;
+ goto dealloc_host;
}
err = ufshcd_parse_regulator_info(hba);
if (err) {
dev_err(&pdev->dev, "%s: regulator init failed %d\n",
__func__, err);
- goto out;
+ goto dealloc_host;
}
pm_runtime_set_active(&pdev->dev);
@@ -352,50 +344,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
out_disable_rpm:
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
+dealloc_host:
+ ufshcd_dealloc_host(hba);
out:
return err;
}
-
-/**
- * ufshcd_pltfrm_remove - remove platform driver routine
- * @pdev: pointer to platform device handle
- *
- * Returns 0 on success, non-zero value on failure
- */
-static int ufshcd_pltfrm_remove(struct platform_device *pdev)
-{
- struct ufs_hba *hba = platform_get_drvdata(pdev);
-
- pm_runtime_get_sync(&(pdev)->dev);
- ufshcd_remove(hba);
- return 0;
-}
-
-static const struct of_device_id ufs_of_match[] = {
- { .compatible = "jedec,ufs-1.1"},
- {},
-};
-
-static const struct dev_pm_ops ufshcd_dev_pm_ops = {
- .suspend = ufshcd_pltfrm_suspend,
- .resume = ufshcd_pltfrm_resume,
- .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
- .runtime_resume = ufshcd_pltfrm_runtime_resume,
- .runtime_idle = ufshcd_pltfrm_runtime_idle,
-};
-
-static struct platform_driver ufshcd_pltfrm_driver = {
- .probe = ufshcd_pltfrm_probe,
- .remove = ufshcd_pltfrm_remove,
- .shutdown = ufshcd_pltfrm_shutdown,
- .driver = {
- .name = "ufshcd",
- .pm = &ufshcd_dev_pm_ops,
- .of_match_table = ufs_of_match,
- },
-};
-
-module_platform_driver(ufshcd_pltfrm_driver);
+EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h
new file mode 100644
index 0000000..df64c41
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFSHCD_PLTFRM_H_
+#define UFSHCD_PLTFRM_H_
+
+#include "ufshcd.h"
+
+int ufshcd_pltfrm_init(struct platform_device *pdev,
+ struct ufs_hba_variant_ops *vops);
+void ufshcd_pltfrm_shutdown(struct platform_device *pdev);
+
+#ifdef CONFIG_PM
+
+int ufshcd_pltfrm_suspend(struct device *dev);
+int ufshcd_pltfrm_resume(struct device *dev);
+int ufshcd_pltfrm_runtime_suspend(struct device *dev);
+int ufshcd_pltfrm_runtime_resume(struct device *dev);
+int ufshcd_pltfrm_runtime_idle(struct device *dev);
+
+#else /* !CONFIG_PM */
+
+#define ufshcd_pltfrm_suspend NULL
+#define ufshcd_pltfrm_resume NULL
+#define ufshcd_pltfrm_runtime_suspend NULL
+#define ufshcd_pltfrm_runtime_resume NULL
+#define ufshcd_pltfrm_runtime_idle NULL
+
+#endif /* CONFIG_PM */
+
+#endif /* UFSHCD_PLTFRM_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index b0ade73..85cd256 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -271,10 +271,8 @@ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba)
*/
static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba)
{
- if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION) {
- if (hba->vops && hba->vops->get_ufs_hci_version)
- return hba->vops->get_ufs_hci_version(hba);
- }
+ if (hba->quirks & UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION)
+ return ufshcd_vops_get_ufs_hci_version(hba);
return ufshcd_readl(hba, REG_UFS_VERSION);
}
@@ -627,6 +625,7 @@ start:
out:
return rc;
}
+EXPORT_SYMBOL_GPL(ufshcd_hold);
static void ufshcd_gate_work(struct work_struct *work)
{
@@ -714,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba)
__ufshcd_release(hba);
spin_unlock_irqrestore(hba->host->host_lock, flags);
}
+EXPORT_SYMBOL_GPL(ufshcd_release);
static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -2473,9 +2473,8 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba,
dev_err(hba->dev,
"%s: power mode change failed %d\n", __func__, ret);
} else {
- if (hba->vops && hba->vops->pwr_change_notify)
- hba->vops->pwr_change_notify(hba,
- POST_CHANGE, NULL, pwr_mode);
+ ufshcd_vops_pwr_change_notify(hba, POST_CHANGE, NULL,
+ pwr_mode);
memcpy(&hba->pwr_info, pwr_mode,
sizeof(struct ufs_pa_layer_attr));
@@ -2495,10 +2494,10 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr final_params = { 0 };
int ret;
- if (hba->vops && hba->vops->pwr_change_notify)
- hba->vops->pwr_change_notify(hba,
- PRE_CHANGE, desired_pwr_mode, &final_params);
- else
+ ret = ufshcd_vops_pwr_change_notify(hba, PRE_CHANGE,
+ desired_pwr_mode, &final_params);
+
+ if (ret)
memcpy(&final_params, desired_pwr_mode, sizeof(final_params));
ret = ufshcd_change_power_mode(hba, &final_params);
@@ -2647,8 +2646,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
/* UniPro link is disabled at this point */
ufshcd_set_link_off(hba);
- if (hba->vops && hba->vops->hce_enable_notify)
- hba->vops->hce_enable_notify(hba, PRE_CHANGE);
+ ufshcd_vops_hce_enable_notify(hba, PRE_CHANGE);
/* start controller initialization sequence */
ufshcd_hba_start(hba);
@@ -2681,8 +2679,7 @@ static int ufshcd_hba_enable(struct ufs_hba *hba)
/* enable UIC related interrupts */
ufshcd_enable_intr(hba, UFSHCD_UIC_MASK);
- if (hba->vops && hba->vops->hce_enable_notify)
- hba->vops->hce_enable_notify(hba, POST_CHANGE);
+ ufshcd_vops_hce_enable_notify(hba, POST_CHANGE);
return 0;
}
@@ -2735,8 +2732,7 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
int retries = DME_LINKSTARTUP_RETRIES;
do {
- if (hba->vops && hba->vops->link_startup_notify)
- hba->vops->link_startup_notify(hba, PRE_CHANGE);
+ ufshcd_vops_link_startup_notify(hba, PRE_CHANGE);
ret = ufshcd_dme_link_startup(hba);
@@ -2767,11 +2763,9 @@ static int ufshcd_link_startup(struct ufs_hba *hba)
}
/* Include any host controller configuration via UIC commands */
- if (hba->vops && hba->vops->link_startup_notify) {
- ret = hba->vops->link_startup_notify(hba, POST_CHANGE);
- if (ret)
- goto out;
- }
+ ret = ufshcd_vops_link_startup_notify(hba, POST_CHANGE);
+ if (ret)
+ goto out;
ret = ufshcd_make_hba_operational(hba);
out:
@@ -4355,7 +4349,6 @@ static struct scsi_host_template ufshcd_driver_template = {
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
.can_queue = UFSHCD_CAN_QUEUE,
.max_host_blocked = 1,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -4578,8 +4571,7 @@ static int __ufshcd_setup_clocks(struct ufs_hba *hba, bool on,
}
}
- if (hba->vops && hba->vops->setup_clocks)
- ret = hba->vops->setup_clocks(hba, on);
+ ret = ufshcd_vops_setup_clocks(hba, on);
out:
if (ret) {
list_for_each_entry(clki, head, list) {
@@ -4645,27 +4637,22 @@ static int ufshcd_variant_hba_init(struct ufs_hba *hba)
if (!hba->vops)
goto out;
- if (hba->vops->init) {
- err = hba->vops->init(hba);
- if (err)
- goto out;
- }
+ err = ufshcd_vops_init(hba);
+ if (err)
+ goto out;
- if (hba->vops->setup_regulators) {
- err = hba->vops->setup_regulators(hba, true);
- if (err)
- goto out_exit;
- }
+ err = ufshcd_vops_setup_regulators(hba, true);
+ if (err)
+ goto out_exit;
goto out;
out_exit:
- if (hba->vops->exit)
- hba->vops->exit(hba);
+ ufshcd_vops_exit(hba);
out:
if (err)
dev_err(hba->dev, "%s: variant %s init failed err %d\n",
- __func__, hba->vops ? hba->vops->name : "", err);
+ __func__, ufshcd_get_var_name(hba), err);
return err;
}
@@ -4674,14 +4661,11 @@ static void ufshcd_variant_hba_exit(struct ufs_hba *hba)
if (!hba->vops)
return;
- if (hba->vops->setup_clocks)
- hba->vops->setup_clocks(hba, false);
+ ufshcd_vops_setup_clocks(hba, false);
- if (hba->vops->setup_regulators)
- hba->vops->setup_regulators(hba, false);
+ ufshcd_vops_setup_regulators(hba, false);
- if (hba->vops->exit)
- hba->vops->exit(hba);
+ ufshcd_vops_exit(hba);
}
static int ufshcd_hba_init(struct ufs_hba *hba)
@@ -5058,17 +5042,13 @@ disable_clks:
* vendor specific host controller register space call them before the
* host clocks are ON.
*/
- if (hba->vops && hba->vops->suspend) {
- ret = hba->vops->suspend(hba, pm_op);
- if (ret)
- goto set_link_active;
- }
+ ret = ufshcd_vops_suspend(hba, pm_op);
+ if (ret)
+ goto set_link_active;
- if (hba->vops && hba->vops->setup_clocks) {
- ret = hba->vops->setup_clocks(hba, false);
- if (ret)
- goto vops_resume;
- }
+ ret = ufshcd_vops_setup_clocks(hba, false);
+ if (ret)
+ goto vops_resume;
if (!ufshcd_is_link_active(hba))
ufshcd_setup_clocks(hba, false);
@@ -5079,7 +5059,7 @@ disable_clks:
hba->clk_gating.state = CLKS_OFF;
/*
* Disable the host irq as host controller as there won't be any
- * host controller trasanction expected till resume.
+ * host controller transaction expected till resume.
*/
ufshcd_disable_irq(hba);
/* Put the host controller in low power mode if possible */
@@ -5087,8 +5067,7 @@ disable_clks:
goto out;
vops_resume:
- if (hba->vops && hba->vops->resume)
- hba->vops->resume(hba, pm_op);
+ ufshcd_vops_resume(hba, pm_op);
set_link_active:
ufshcd_vreg_set_hpm(hba);
if (ufshcd_is_link_hibern8(hba) && !ufshcd_uic_hibern8_exit(hba))
@@ -5144,11 +5123,9 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
* vendor specific host controller register space call them when the
* host clocks are ON.
*/
- if (hba->vops && hba->vops->resume) {
- ret = hba->vops->resume(hba, pm_op);
- if (ret)
- goto disable_vreg;
- }
+ ret = ufshcd_vops_resume(hba, pm_op);
+ if (ret)
+ goto disable_vreg;
if (ufshcd_is_link_hibern8(hba)) {
ret = ufshcd_uic_hibern8_exit(hba);
@@ -5189,8 +5166,7 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
set_old_link_state:
ufshcd_link_state_transition(hba, old_link_state, 0);
vendor_suspend:
- if (hba->vops && hba->vops->suspend)
- hba->vops->suspend(hba, pm_op);
+ ufshcd_vops_suspend(hba, pm_op);
disable_vreg:
ufshcd_vreg_set_lpm(hba);
disable_irq_and_vops_clks:
@@ -5373,6 +5349,16 @@ void ufshcd_remove(struct ufs_hba *hba)
EXPORT_SYMBOL_GPL(ufshcd_remove);
/**
+ * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA)
+ * @hba: pointer to Host Bus Adapter (HBA)
+ */
+void ufshcd_dealloc_host(struct ufs_hba *hba)
+{
+ scsi_host_put(hba->host);
+}
+EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
+
+/**
* ufshcd_set_dma_mask - Set dma mask based on the controller
* addressing capability
* @hba: per adapter instance
@@ -5433,6 +5419,10 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
if (!head || list_empty(head))
goto out;
+ ret = ufshcd_vops_clk_scale_notify(hba, scale_up, PRE_CHANGE);
+ if (ret)
+ return ret;
+
list_for_each_entry(clki, head, list) {
if (!IS_ERR_OR_NULL(clki->clk)) {
if (scale_up && clki->max_freq) {
@@ -5463,8 +5453,9 @@ static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up)
dev_dbg(hba->dev, "%s: clk: %s, rate: %lu\n", __func__,
clki->name, clk_get_rate(clki->clk));
}
- if (hba->vops->clk_scale_notify)
- hba->vops->clk_scale_notify(hba);
+
+ ret = ufshcd_vops_clk_scale_notify(hba, scale_up, POST_CHANGE);
+
out:
return ret;
}
@@ -5619,13 +5610,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
hba->is_irq_enabled = true;
}
- /* Enable SCSI tag mapping */
- err = scsi_init_shared_tag_map(host, host->can_queue);
- if (err) {
- dev_err(hba->dev, "init shared queue failed\n");
- goto exit_gating;
- }
-
err = scsi_add_host(host, hba->dev);
if (err) {
dev_err(hba->dev, "scsi_add_host failed\n");
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index c40a0e7..2570d94 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -223,8 +223,10 @@ struct ufs_clk_info {
bool enabled;
};
-#define PRE_CHANGE 0
-#define POST_CHANGE 1
+enum ufs_notify_change_status {
+ PRE_CHANGE,
+ POST_CHANGE,
+};
struct ufs_pa_layer_attr {
u32 gear_rx;
@@ -259,22 +261,28 @@ struct ufs_pwr_mode_info {
* to be set.
* @suspend: called during host controller PM callback
* @resume: called during host controller PM callback
+ * @dbg_register_dump: used to dump controller debug information
*/
struct ufs_hba_variant_ops {
const char *name;
int (*init)(struct ufs_hba *);
void (*exit)(struct ufs_hba *);
u32 (*get_ufs_hci_version)(struct ufs_hba *);
- void (*clk_scale_notify)(struct ufs_hba *);
- int (*setup_clocks)(struct ufs_hba *, bool);
+ int (*clk_scale_notify)(struct ufs_hba *, bool,
+ enum ufs_notify_change_status);
+ int (*setup_clocks)(struct ufs_hba *, bool);
int (*setup_regulators)(struct ufs_hba *, bool);
- int (*hce_enable_notify)(struct ufs_hba *, bool);
- int (*link_startup_notify)(struct ufs_hba *, bool);
+ int (*hce_enable_notify)(struct ufs_hba *,
+ enum ufs_notify_change_status);
+ int (*link_startup_notify)(struct ufs_hba *,
+ enum ufs_notify_change_status);
int (*pwr_change_notify)(struct ufs_hba *,
- bool, struct ufs_pa_layer_attr *,
+ enum ufs_notify_change_status status,
+ struct ufs_pa_layer_attr *,
struct ufs_pa_layer_attr *);
int (*suspend)(struct ufs_hba *, enum ufs_pm_op);
int (*resume)(struct ufs_hba *, enum ufs_pm_op);
+ void (*dbg_register_dump)(struct ufs_hba *hba);
};
/* clock gating state */
@@ -576,6 +584,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
}
int ufshcd_alloc_host(struct device *, struct ufs_hba **);
+void ufshcd_dealloc_host(struct ufs_hba *);
int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
void ufshcd_remove(struct ufs_hba *);
@@ -594,6 +603,27 @@ static inline void check_upiu_size(void)
GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE);
}
+/**
+ * ufshcd_set_variant - set variant specific data to the hba
+ * @hba - per adapter instance
+ * @variant - pointer to variant specific data
+ */
+static inline void ufshcd_set_variant(struct ufs_hba *hba, void *variant)
+{
+ BUG_ON(!hba);
+ hba->priv = variant;
+}
+
+/**
+ * ufshcd_get_variant - get variant specific data from the hba
+ * @hba - per adapter instance
+ */
+static inline void *ufshcd_get_variant(struct ufs_hba *hba)
+{
+ BUG_ON(!hba);
+ return hba->priv;
+}
+
extern int ufshcd_runtime_suspend(struct ufs_hba *hba);
extern int ufshcd_runtime_resume(struct ufs_hba *hba);
extern int ufshcd_runtime_idle(struct ufs_hba *hba);
@@ -653,4 +683,109 @@ static inline int ufshcd_dme_peer_get(struct ufs_hba *hba,
int ufshcd_hold(struct ufs_hba *hba, bool async);
void ufshcd_release(struct ufs_hba *hba);
+
+/* Wrapper functions for safely calling variant operations */
+static inline const char *ufshcd_get_var_name(struct ufs_hba *hba)
+{
+ if (hba->vops)
+ return hba->vops->name;
+ return "";
+}
+
+static inline int ufshcd_vops_init(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->init)
+ return hba->vops->init(hba);
+
+ return 0;
+}
+
+static inline void ufshcd_vops_exit(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->exit)
+ return hba->vops->exit(hba);
+}
+
+static inline u32 ufshcd_vops_get_ufs_hci_version(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->get_ufs_hci_version)
+ return hba->vops->get_ufs_hci_version(hba);
+
+ return ufshcd_readl(hba, REG_UFS_VERSION);
+}
+
+static inline int ufshcd_vops_clk_scale_notify(struct ufs_hba *hba,
+ bool up, enum ufs_notify_change_status status)
+{
+ if (hba->vops && hba->vops->clk_scale_notify)
+ return hba->vops->clk_scale_notify(hba, up, status);
+ return 0;
+}
+
+static inline int ufshcd_vops_setup_clocks(struct ufs_hba *hba, bool on)
+{
+ if (hba->vops && hba->vops->setup_clocks)
+ return hba->vops->setup_clocks(hba, on);
+ return 0;
+}
+
+static inline int ufshcd_vops_setup_regulators(struct ufs_hba *hba, bool status)
+{
+ if (hba->vops && hba->vops->setup_regulators)
+ return hba->vops->setup_regulators(hba, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_hce_enable_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->hce_enable_notify)
+ return hba->vops->hce_enable_notify(hba, status);
+
+ return 0;
+}
+static inline int ufshcd_vops_link_startup_notify(struct ufs_hba *hba,
+ bool status)
+{
+ if (hba->vops && hba->vops->link_startup_notify)
+ return hba->vops->link_startup_notify(hba, status);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_pwr_change_notify(struct ufs_hba *hba,
+ bool status,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ if (hba->vops && hba->vops->pwr_change_notify)
+ return hba->vops->pwr_change_notify(hba, status,
+ dev_max_params, dev_req_params);
+
+ return -ENOTSUPP;
+}
+
+static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op)
+{
+ if (hba->vops && hba->vops->suspend)
+ return hba->vops->suspend(hba, op);
+
+ return 0;
+}
+
+static inline int ufshcd_vops_resume(struct ufs_hba *hba, enum ufs_pm_op op)
+{
+ if (hba->vops && hba->vops->resume)
+ return hba->vops->resume(hba, op);
+
+ return 0;
+}
+
+static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
+{
+ if (hba->vops && hba->vops->dbg_register_dump)
+ hba->vops->dbg_register_dump(hba);
+}
+
#endif /* End of Header */
diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c
index 25abd4e..91a00301 100644
--- a/drivers/sh/pm_runtime.c
+++ b/drivers/sh/pm_runtime.c
@@ -34,7 +34,7 @@ static struct pm_clk_notifier_block platform_bus_notifier = {
static int __init sh_pm_runtime_init(void)
{
- if (IS_ENABLED(CONFIG_ARCH_SHMOBILE_MULTI)) {
+ if (IS_ENABLED(CONFIG_ARCH_SHMOBILE)) {
if (!of_find_compatible_node(NULL, NULL,
"renesas,cpg-mstp-clocks"))
return 0;
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index 96ddecb..4e853ed 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -1,7 +1,9 @@
menu "SOC (System On Chip) specific Drivers"
+source "drivers/soc/brcmstb/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
+source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/sunxi/Kconfig"
source "drivers/soc/ti/Kconfig"
source "drivers/soc/versatile/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 0b12d77..f2ba2e9 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -2,9 +2,11 @@
# Makefile for the Linux Kernel SOC specific device drivers.
#
+obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/
obj-$(CONFIG_MACH_DOVE) += dove/
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_ARCH_QCOM) += qcom/
+obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
obj-$(CONFIG_SOC_TI) += ti/
diff --git a/drivers/soc/brcmstb/Kconfig b/drivers/soc/brcmstb/Kconfig
new file mode 100644
index 0000000..39cab3b
--- /dev/null
+++ b/drivers/soc/brcmstb/Kconfig
@@ -0,0 +1,9 @@
+menuconfig SOC_BRCMSTB
+ bool "Broadcom STB SoC drivers"
+ depends on ARM
+ help
+ Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
+ This option alone enables only some support code, while the drivers
+ can be enabled individually within this menu.
+
+ If unsure, say N.
diff --git a/drivers/soc/brcmstb/Makefile b/drivers/soc/brcmstb/Makefile
new file mode 100644
index 0000000..9120b27
--- /dev/null
+++ b/drivers/soc/brcmstb/Makefile
@@ -0,0 +1 @@
+obj-y += common.o biuctrl.o
diff --git a/drivers/soc/brcmstb/biuctrl.c b/drivers/soc/brcmstb/biuctrl.c
new file mode 100644
index 0000000..9049c076f
--- /dev/null
+++ b/drivers/soc/brcmstb/biuctrl.c
@@ -0,0 +1,116 @@
+/*
+ * Broadcom STB SoCs Bus Unit Interface controls
+ *
+ * Copyright (C) 2015, Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) "brcmstb: " KBUILD_MODNAME ": " fmt
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
+
+#define CPU_CREDIT_REG_OFFSET 0x184
+#define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000
+
+static void __iomem *cpubiuctrl_base;
+static bool mcp_wr_pairing_en;
+
+static int __init mcp_write_pairing_set(void)
+{
+ u32 creds = 0;
+
+ if (!cpubiuctrl_base)
+ return -1;
+
+ creds = readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
+ if (mcp_wr_pairing_en) {
+ pr_info("MCP: Enabling write pairing\n");
+ writel_relaxed(creds | CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
+ cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
+ } else if (creds & CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK) {
+ pr_info("MCP: Disabling write pairing\n");
+ writel_relaxed(creds & ~CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK,
+ cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
+ } else {
+ pr_info("MCP: Write pairing already disabled\n");
+ }
+
+ return 0;
+}
+
+static int __init setup_hifcpubiuctrl_regs(void)
+{
+ struct device_node *np;
+ int ret = 0;
+
+ np = of_find_compatible_node(NULL, NULL, "brcm,brcmstb-cpu-biu-ctrl");
+ if (!np) {
+ pr_err("missing BIU control node\n");
+ return -ENODEV;
+ }
+
+ cpubiuctrl_base = of_iomap(np, 0);
+ if (!cpubiuctrl_base) {
+ pr_err("failed to remap BIU control base\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ mcp_wr_pairing_en = of_property_read_bool(np, "brcm,write-pairing");
+out:
+ of_node_put(np);
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static u32 cpu_credit_reg_dump; /* for save/restore */
+
+static int brcmstb_cpu_credit_reg_suspend(void)
+{
+ if (cpubiuctrl_base)
+ cpu_credit_reg_dump =
+ readl_relaxed(cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
+ return 0;
+}
+
+static void brcmstb_cpu_credit_reg_resume(void)
+{
+ if (cpubiuctrl_base)
+ writel_relaxed(cpu_credit_reg_dump,
+ cpubiuctrl_base + CPU_CREDIT_REG_OFFSET);
+}
+
+static struct syscore_ops brcmstb_cpu_credit_syscore_ops = {
+ .suspend = brcmstb_cpu_credit_reg_suspend,
+ .resume = brcmstb_cpu_credit_reg_resume,
+};
+#endif
+
+
+void __init brcmstb_biuctrl_init(void)
+{
+ int ret;
+
+ setup_hifcpubiuctrl_regs();
+
+ ret = mcp_write_pairing_set();
+ if (ret) {
+ pr_err("MCP: Unable to disable write pairing!\n");
+ return;
+ }
+
+#ifdef CONFIG_PM_SLEEP
+ register_syscore_ops(&brcmstb_cpu_credit_syscore_ops);
+#endif
+}
diff --git a/drivers/soc/brcmstb/common.c b/drivers/soc/brcmstb/common.c
new file mode 100644
index 0000000..c262c02
--- /dev/null
+++ b/drivers/soc/brcmstb/common.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ * Copyright © 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of.h>
+
+#include <soc/brcmstb/common.h>
+
+static const struct of_device_id brcmstb_machine_match[] = {
+ { .compatible = "brcm,brcmstb", },
+ { }
+};
+
+bool soc_is_brcmstb(void)
+{
+ struct device_node *root;
+
+ root = of_find_node_by_path("/");
+ if (!root)
+ return false;
+
+ return of_match_node(brcmstb_machine_match, root) != NULL;
+}
diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
index 9d50682..0a4ea80 100644
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -23,6 +23,7 @@ config MTK_PMIC_WRAP
config MTK_SCPSYS
bool "MediaTek SCPSYS Support"
depends on ARCH_MEDIATEK || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
select REGMAP
select MTK_INFRACFG
select PM_GENERIC_DOMAINS if PM
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 8bc7b41..105597a 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -725,10 +725,6 @@ static int pwrap_init(struct pmic_wrapper *wrp)
pwrap_writel(wrp, 0x1, PWRAP_WACS2_EN);
pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD);
pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN);
- pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
- pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN);
- pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
- pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
if (pwrap_is_mt8135(wrp)) {
/* enable pwrap events and pwrap bridge in AP side */
@@ -896,6 +892,12 @@ static int pwrap_probe(struct platform_device *pdev)
return -ENODEV;
}
+ /* Initialize watchdog, may not be done by the bootloader */
+ pwrap_writel(wrp, 0xf, PWRAP_WDT_UNIT);
+ pwrap_writel(wrp, 0xffffffff, PWRAP_WDT_SRC_EN);
+ pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
+ pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN);
+
irq = platform_get_irq(pdev, 0);
ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH,
"mt-pmic-pwrap", wrp);
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index 164a7d8..4d4203c 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -54,12 +54,16 @@
#define PWR_STATUS_USB BIT(25)
enum clk_id {
+ MT8173_CLK_NONE,
MT8173_CLK_MM,
MT8173_CLK_MFG,
- MT8173_CLK_NONE,
- MT8173_CLK_MAX = MT8173_CLK_NONE,
+ MT8173_CLK_VENC,
+ MT8173_CLK_VENC_LT,
+ MT8173_CLK_MAX,
};
+#define MAX_CLKS 2
+
struct scp_domain_data {
const char *name;
u32 sta_mask;
@@ -67,7 +71,8 @@ struct scp_domain_data {
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
- enum clk_id clk_id;
+ enum clk_id clk_id[MAX_CLKS];
+ bool active_wakeup;
};
static const struct scp_domain_data scp_domain_data[] __initconst = {
@@ -77,7 +82,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_VDE_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = MT8173_CLK_MM,
+ .clk_id = {MT8173_CLK_MM},
},
[MT8173_POWER_DOMAIN_VENC] = {
.name = "venc",
@@ -85,7 +90,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_VEN_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = MT8173_CLK_MM,
+ .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
},
[MT8173_POWER_DOMAIN_ISP] = {
.name = "isp",
@@ -93,7 +98,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_ISP_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = MT8173_CLK_MM,
+ .clk_id = {MT8173_CLK_MM},
},
[MT8173_POWER_DOMAIN_MM] = {
.name = "mm",
@@ -101,7 +106,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_DIS_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(12, 12),
- .clk_id = MT8173_CLK_MM,
+ .clk_id = {MT8173_CLK_MM},
.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
MT8173_TOP_AXI_PROT_EN_MM_M1,
},
@@ -111,7 +116,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_VEN2_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = MT8173_CLK_MM,
+ .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
},
[MT8173_POWER_DOMAIN_AUDIO] = {
.name = "audio",
@@ -119,7 +124,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_AUDIO_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = MT8173_CLK_NONE,
+ .clk_id = {MT8173_CLK_NONE},
},
[MT8173_POWER_DOMAIN_USB] = {
.name = "usb",
@@ -127,7 +132,8 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_USB_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(15, 12),
- .clk_id = MT8173_CLK_NONE,
+ .clk_id = {MT8173_CLK_NONE},
+ .active_wakeup = true,
},
[MT8173_POWER_DOMAIN_MFG_ASYNC] = {
.name = "mfg_async",
@@ -135,7 +141,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_MFG_ASYNC_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = 0,
- .clk_id = MT8173_CLK_MFG,
+ .clk_id = {MT8173_CLK_MFG},
},
[MT8173_POWER_DOMAIN_MFG_2D] = {
.name = "mfg_2d",
@@ -143,7 +149,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_MFG_2D_PWR_CON,
.sram_pdn_bits = GENMASK(11, 8),
.sram_pdn_ack_bits = GENMASK(13, 12),
- .clk_id = MT8173_CLK_NONE,
+ .clk_id = {MT8173_CLK_NONE},
},
[MT8173_POWER_DOMAIN_MFG] = {
.name = "mfg",
@@ -151,7 +157,7 @@ static const struct scp_domain_data scp_domain_data[] __initconst = {
.ctl_offs = SPM_MFG_PWR_CON,
.sram_pdn_bits = GENMASK(13, 8),
.sram_pdn_ack_bits = GENMASK(21, 16),
- .clk_id = MT8173_CLK_NONE,
+ .clk_id = {MT8173_CLK_NONE},
.bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
MT8173_TOP_AXI_PROT_EN_MFG_M0 |
MT8173_TOP_AXI_PROT_EN_MFG_M1 |
@@ -166,12 +172,13 @@ struct scp;
struct scp_domain {
struct generic_pm_domain genpd;
struct scp *scp;
- struct clk *clk;
+ struct clk *clk[MAX_CLKS];
u32 sta_mask;
void __iomem *ctl_addr;
u32 sram_pdn_bits;
u32 sram_pdn_ack_bits;
u32 bus_prot_mask;
+ bool active_wakeup;
};
struct scp {
@@ -212,11 +219,16 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
u32 sram_pdn_ack = scpd->sram_pdn_ack_bits;
u32 val;
int ret;
+ int i;
+
+ for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
+ ret = clk_prepare_enable(scpd->clk[i]);
+ if (ret) {
+ for (--i; i >= 0; i--)
+ clk_disable_unprepare(scpd->clk[i]);
- if (scpd->clk) {
- ret = clk_prepare_enable(scpd->clk);
- if (ret)
goto err_clk;
+ }
}
val = readl(ctl_addr);
@@ -282,7 +294,10 @@ static int scpsys_power_on(struct generic_pm_domain *genpd)
return 0;
err_pwr_ack:
- clk_disable_unprepare(scpd->clk);
+ for (i = MAX_CLKS - 1; i >= 0; i--) {
+ if (scpd->clk[i])
+ clk_disable_unprepare(scpd->clk[i]);
+ }
err_clk:
dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
@@ -299,6 +314,7 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
u32 pdn_ack = scpd->sram_pdn_ack_bits;
u32 val;
int ret;
+ int i;
if (scpd->bus_prot_mask) {
ret = mtk_infracfg_set_bus_protection(scp->infracfg,
@@ -360,8 +376,8 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
expired = true;
}
- if (scpd->clk)
- clk_disable_unprepare(scpd->clk);
+ for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
+ clk_disable_unprepare(scpd->clk[i]);
return 0;
@@ -371,11 +387,22 @@ out:
return ret;
}
+static bool scpsys_active_wakeup(struct device *dev)
+{
+ struct generic_pm_domain *genpd;
+ struct scp_domain *scpd;
+
+ genpd = pd_to_genpd(dev->pm_domain);
+ scpd = container_of(genpd, struct scp_domain, genpd);
+
+ return scpd->active_wakeup;
+}
+
static int __init scpsys_probe(struct platform_device *pdev)
{
struct genpd_onecell_data *pd_data;
struct resource *res;
- int i, ret;
+ int i, j, ret;
struct scp *scp;
struct clk *clk[MT8173_CLK_MAX];
@@ -405,6 +432,14 @@ static int __init scpsys_probe(struct platform_device *pdev)
if (IS_ERR(clk[MT8173_CLK_MFG]))
return PTR_ERR(clk[MT8173_CLK_MFG]);
+ clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
+ if (IS_ERR(clk[MT8173_CLK_VENC]))
+ return PTR_ERR(clk[MT8173_CLK_VENC]);
+
+ clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
+ if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
+ return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
+
scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"infracfg");
if (IS_ERR(scp->infracfg)) {
@@ -428,12 +463,14 @@ static int __init scpsys_probe(struct platform_device *pdev)
scpd->sram_pdn_bits = data->sram_pdn_bits;
scpd->sram_pdn_ack_bits = data->sram_pdn_ack_bits;
scpd->bus_prot_mask = data->bus_prot_mask;
- if (data->clk_id != MT8173_CLK_NONE)
- scpd->clk = clk[data->clk_id];
+ scpd->active_wakeup = data->active_wakeup;
+ for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
+ scpd->clk[j] = clk[data->clk_id[j]];
genpd->name = data->name;
genpd->power_off = scpsys_power_off;
genpd->power_on = scpsys_power_on;
+ genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
/*
* Initially turn on all domains to make the domains usable
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index ba47b70..eec7614 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -19,6 +19,15 @@ config QCOM_PM
modes. It interface with various system drivers to put the cores in
low power modes.
+config QCOM_SMEM
+ tristate "Qualcomm Shared Memory Manager (SMEM)"
+ depends on ARCH_QCOM
+ depends on HWSPINLOCK
+ help
+ Say y here to enable support for the Qualcomm Shared Memory Manager.
+ The driver provides an interface to items in a heap shared among all
+ processors in a Qualcomm platform.
+
config QCOM_SMD
tristate "Qualcomm Shared Memory Driver (SMD)"
depends on QCOM_SMEM
@@ -40,11 +49,3 @@ config QCOM_SMD_RPM
Say M here if you want to include support for the Qualcomm RPM as a
module. This will build a module called "qcom-smd-rpm".
-
-config QCOM_SMEM
- tristate "Qualcomm Shared Memory Manager (SMEM)"
- depends on ARCH_QCOM
- help
- Say y here to enable support for the Qualcomm Shared Memory Manager.
- The driver provides an interface to items in a heap shared among all
- processors in a Qualcomm platform.
diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c
index 1392ccf..2969321 100644
--- a/drivers/soc/qcom/smd-rpm.c
+++ b/drivers/soc/qcom/smd-rpm.c
@@ -17,6 +17,7 @@
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include <linux/soc/qcom/smd.h>
#include <linux/soc/qcom/smd-rpm.h>
@@ -44,8 +45,8 @@ struct qcom_smd_rpm {
* @length: length of the payload
*/
struct qcom_rpm_header {
- u32 service_type;
- u32 length;
+ __le32 service_type;
+ __le32 length;
};
/**
@@ -57,11 +58,11 @@ struct qcom_rpm_header {
* @data_len: length of the payload following this header
*/
struct qcom_rpm_request {
- u32 msg_id;
- u32 flags;
- u32 type;
- u32 id;
- u32 data_len;
+ __le32 msg_id;
+ __le32 flags;
+ __le32 type;
+ __le32 id;
+ __le32 data_len;
};
/**
@@ -74,10 +75,10 @@ struct qcom_rpm_request {
* Multiple of these messages can be stacked in an rpm message.
*/
struct qcom_rpm_message {
- u32 msg_type;
- u32 length;
+ __le32 msg_type;
+ __le32 length;
union {
- u32 msg_id;
+ __le32 msg_id;
u8 message[0];
};
};
@@ -104,30 +105,34 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
static unsigned msg_id = 1;
int left;
int ret;
-
struct {
struct qcom_rpm_header hdr;
struct qcom_rpm_request req;
- u8 payload[count];
- } pkt;
+ u8 payload[];
+ } *pkt;
+ size_t size = sizeof(*pkt) + count;
/* SMD packets to the RPM may not exceed 256 bytes */
- if (WARN_ON(sizeof(pkt) >= 256))
+ if (WARN_ON(size >= 256))
return -EINVAL;
+ pkt = kmalloc(size, GFP_KERNEL);
+ if (!pkt)
+ return -ENOMEM;
+
mutex_lock(&rpm->lock);
- pkt.hdr.service_type = RPM_SERVICE_TYPE_REQUEST;
- pkt.hdr.length = sizeof(struct qcom_rpm_request) + count;
+ pkt->hdr.service_type = cpu_to_le32(RPM_SERVICE_TYPE_REQUEST);
+ pkt->hdr.length = cpu_to_le32(sizeof(struct qcom_rpm_request) + count);
- pkt.req.msg_id = msg_id++;
- pkt.req.flags = BIT(state);
- pkt.req.type = type;
- pkt.req.id = id;
- pkt.req.data_len = count;
- memcpy(pkt.payload, buf, count);
+ pkt->req.msg_id = cpu_to_le32(msg_id++);
+ pkt->req.flags = cpu_to_le32(state);
+ pkt->req.type = cpu_to_le32(type);
+ pkt->req.id = cpu_to_le32(id);
+ pkt->req.data_len = cpu_to_le32(count);
+ memcpy(pkt->payload, buf, count);
- ret = qcom_smd_send(rpm->rpm_channel, &pkt, sizeof(pkt));
+ ret = qcom_smd_send(rpm->rpm_channel, pkt, size);
if (ret)
goto out;
@@ -138,6 +143,7 @@ int qcom_rpm_smd_write(struct qcom_smd_rpm *rpm,
ret = rpm->ack_status;
out:
+ kfree(pkt);
mutex_unlock(&rpm->lock);
return ret;
}
@@ -148,27 +154,29 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
size_t count)
{
const struct qcom_rpm_header *hdr = data;
+ size_t hdr_length = le32_to_cpu(hdr->length);
const struct qcom_rpm_message *msg;
struct qcom_smd_rpm *rpm = dev_get_drvdata(&qsdev->dev);
const u8 *buf = data + sizeof(struct qcom_rpm_header);
- const u8 *end = buf + hdr->length;
+ const u8 *end = buf + hdr_length;
char msgbuf[32];
int status = 0;
- u32 len;
+ u32 len, msg_length;
- if (hdr->service_type != RPM_SERVICE_TYPE_REQUEST ||
- hdr->length < sizeof(struct qcom_rpm_message)) {
+ if (le32_to_cpu(hdr->service_type) != RPM_SERVICE_TYPE_REQUEST ||
+ hdr_length < sizeof(struct qcom_rpm_message)) {
dev_err(&qsdev->dev, "invalid request\n");
return 0;
}
while (buf < end) {
msg = (struct qcom_rpm_message *)buf;
- switch (msg->msg_type) {
+ msg_length = le32_to_cpu(msg->length);
+ switch (le32_to_cpu(msg->msg_type)) {
case RPM_MSG_TYPE_MSG_ID:
break;
case RPM_MSG_TYPE_ERR:
- len = min_t(u32, ALIGN(msg->length, 4), sizeof(msgbuf));
+ len = min_t(u32, ALIGN(msg_length, 4), sizeof(msgbuf));
memcpy_fromio(msgbuf, msg->message, len);
msgbuf[len - 1] = 0;
@@ -179,7 +187,7 @@ static int qcom_smd_rpm_callback(struct qcom_smd_device *qsdev,
break;
}
- buf = PTR_ALIGN(buf + 2 * sizeof(u32) + msg->length, 4);
+ buf = PTR_ALIGN(buf + 2 * sizeof(u32) + msg_length, 4);
}
rpm->ack_status = status;
diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c
index a6155c9..86b598c 100644
--- a/drivers/soc/qcom/smd.c
+++ b/drivers/soc/qcom/smd.c
@@ -65,7 +65,9 @@
*/
struct smd_channel_info;
+struct smd_channel_info_pair;
struct smd_channel_info_word;
+struct smd_channel_info_word_pair;
#define SMD_ALLOC_TBL_COUNT 2
#define SMD_ALLOC_TBL_SIZE 64
@@ -85,8 +87,8 @@ static const struct {
.fifo_base_id = 338
},
{
- .alloc_tbl_id = 14,
- .info_base_id = 266,
+ .alloc_tbl_id = 266,
+ .info_base_id = 138,
.fifo_base_id = 202,
},
};
@@ -151,10 +153,8 @@ enum smd_channel_state {
* @name: name of the channel
* @state: local state of the channel
* @remote_state: remote state of the channel
- * @tx_info: byte aligned outgoing channel info
- * @rx_info: byte aligned incoming channel info
- * @tx_info_word: word aligned outgoing channel info
- * @rx_info_word: word aligned incoming channel info
+ * @info: byte aligned outgoing/incoming channel info
+ * @info_word: word aligned outgoing/incoming channel info
* @tx_lock: lock to make writes to the channel mutually exclusive
* @fblockread_event: wakeup event tied to tx fBLOCKREADINTR
* @tx_fifo: pointer to the outgoing ring buffer
@@ -175,11 +175,8 @@ struct qcom_smd_channel {
enum smd_channel_state state;
enum smd_channel_state remote_state;
- struct smd_channel_info *tx_info;
- struct smd_channel_info *rx_info;
-
- struct smd_channel_info_word *tx_info_word;
- struct smd_channel_info_word *rx_info_word;
+ struct smd_channel_info_pair *info;
+ struct smd_channel_info_word_pair *info_word;
struct mutex tx_lock;
wait_queue_head_t fblockread_event;
@@ -215,7 +212,7 @@ struct qcom_smd {
* Format of the smd_info smem items, for byte aligned channels.
*/
struct smd_channel_info {
- u32 state;
+ __le32 state;
u8 fDSR;
u8 fCTS;
u8 fCD;
@@ -224,46 +221,104 @@ struct smd_channel_info {
u8 fTAIL;
u8 fSTATE;
u8 fBLOCKREADINTR;
- u32 tail;
- u32 head;
+ __le32 tail;
+ __le32 head;
+};
+
+struct smd_channel_info_pair {
+ struct smd_channel_info tx;
+ struct smd_channel_info rx;
};
/*
* Format of the smd_info smem items, for word aligned channels.
*/
struct smd_channel_info_word {
- u32 state;
- u32 fDSR;
- u32 fCTS;
- u32 fCD;
- u32 fRI;
- u32 fHEAD;
- u32 fTAIL;
- u32 fSTATE;
- u32 fBLOCKREADINTR;
- u32 tail;
- u32 head;
+ __le32 state;
+ __le32 fDSR;
+ __le32 fCTS;
+ __le32 fCD;
+ __le32 fRI;
+ __le32 fHEAD;
+ __le32 fTAIL;
+ __le32 fSTATE;
+ __le32 fBLOCKREADINTR;
+ __le32 tail;
+ __le32 head;
};
-#define GET_RX_CHANNEL_INFO(channel, param) \
- (channel->rx_info_word ? \
- channel->rx_info_word->param : \
- channel->rx_info->param)
-
-#define SET_RX_CHANNEL_INFO(channel, param, value) \
- (channel->rx_info_word ? \
- (channel->rx_info_word->param = value) : \
- (channel->rx_info->param = value))
-
-#define GET_TX_CHANNEL_INFO(channel, param) \
- (channel->tx_info_word ? \
- channel->tx_info_word->param : \
- channel->tx_info->param)
+struct smd_channel_info_word_pair {
+ struct smd_channel_info_word tx;
+ struct smd_channel_info_word rx;
+};
-#define SET_TX_CHANNEL_INFO(channel, param, value) \
- (channel->tx_info_word ? \
- (channel->tx_info_word->param = value) : \
- (channel->tx_info->param = value))
+#define GET_RX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->rx.param) : \
+ channel->info->rx.param; \
+ })
+
+#define GET_RX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->rx.param : \
+ channel->info->rx.param); \
+ })
+
+#define SET_RX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = value; \
+ })
+
+#define SET_RX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->rx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->rx.param = cpu_to_le32(value); \
+ else \
+ channel->info->rx.param = cpu_to_le32(value); \
+ })
+
+#define GET_TX_CHANNEL_FLAG(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ channel->info_word ? \
+ le32_to_cpu(channel->info_word->tx.param) : \
+ channel->info->tx.param; \
+ })
+
+#define GET_TX_CHANNEL_INFO(channel, param) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ le32_to_cpu(channel->info_word ? \
+ channel->info_word->tx.param : \
+ channel->info->tx.param); \
+ })
+
+#define SET_TX_CHANNEL_FLAG(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u8)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = value; \
+ })
+
+#define SET_TX_CHANNEL_INFO(channel, param, value) \
+ ({ \
+ BUILD_BUG_ON(sizeof(channel->info->tx.param) != sizeof(u32)); \
+ if (channel->info_word) \
+ channel->info_word->tx.param = cpu_to_le32(value); \
+ else \
+ channel->info->tx.param = cpu_to_le32(value); \
+ })
/**
* struct qcom_smd_alloc_entry - channel allocation entry
@@ -274,9 +329,9 @@ struct smd_channel_info_word {
*/
struct qcom_smd_alloc_entry {
u8 name[20];
- u32 cid;
- u32 flags;
- u32 ref_count;
+ __le32 cid;
+ __le32 flags;
+ __le32 ref_count;
} __packed;
#define SMD_CHANNEL_FLAGS_EDGE_MASK 0xff
@@ -305,14 +360,14 @@ static void qcom_smd_signal_channel(struct qcom_smd_channel *channel)
static void qcom_smd_channel_reset(struct qcom_smd_channel *channel)
{
SET_TX_CHANNEL_INFO(channel, state, SMD_CHANNEL_CLOSED);
- SET_TX_CHANNEL_INFO(channel, fDSR, 0);
- SET_TX_CHANNEL_INFO(channel, fCTS, 0);
- SET_TX_CHANNEL_INFO(channel, fCD, 0);
- SET_TX_CHANNEL_INFO(channel, fRI, 0);
- SET_TX_CHANNEL_INFO(channel, fHEAD, 0);
- SET_TX_CHANNEL_INFO(channel, fTAIL, 0);
- SET_TX_CHANNEL_INFO(channel, fSTATE, 1);
- SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1);
+ SET_TX_CHANNEL_FLAG(channel, fDSR, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, 0);
+ SET_TX_CHANNEL_FLAG(channel, fCD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fRI, 0);
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 0);
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
SET_TX_CHANNEL_INFO(channel, head, 0);
SET_TX_CHANNEL_INFO(channel, tail, 0);
@@ -350,12 +405,12 @@ static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
dev_dbg(edge->smd->dev, "set_state(%s, %d)\n", channel->name, state);
- SET_TX_CHANNEL_INFO(channel, fDSR, is_open);
- SET_TX_CHANNEL_INFO(channel, fCTS, is_open);
- SET_TX_CHANNEL_INFO(channel, fCD, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fDSR, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCTS, is_open);
+ SET_TX_CHANNEL_FLAG(channel, fCD, is_open);
SET_TX_CHANNEL_INFO(channel, state, state);
- SET_TX_CHANNEL_INFO(channel, fSTATE, 1);
+ SET_TX_CHANNEL_FLAG(channel, fSTATE, 1);
channel->state = state;
qcom_smd_signal_channel(channel);
@@ -364,20 +419,15 @@ static void qcom_smd_channel_set_state(struct qcom_smd_channel *channel,
/*
* Copy count bytes of data using 32bit accesses, if that's required.
*/
-static void smd_copy_to_fifo(void __iomem *_dst,
- const void *_src,
+static void smd_copy_to_fifo(void __iomem *dst,
+ const void *src,
size_t count,
bool word_aligned)
{
- u32 *dst = (u32 *)_dst;
- u32 *src = (u32 *)_src;
-
if (word_aligned) {
- count /= sizeof(u32);
- while (count--)
- writel_relaxed(*src++, dst++);
+ __iowrite32_copy(dst, src, count / sizeof(u32));
} else {
- memcpy_toio(_dst, _src, count);
+ memcpy_toio(dst, src, count);
}
}
@@ -395,7 +445,7 @@ static void smd_copy_from_fifo(void *_dst,
if (word_aligned) {
count /= sizeof(u32);
while (count--)
- *dst++ = readl_relaxed(src++);
+ *dst++ = __raw_readl(src++);
} else {
memcpy_fromio(_dst, _src, count);
}
@@ -412,7 +462,7 @@ static size_t qcom_smd_channel_peek(struct qcom_smd_channel *channel,
unsigned tail;
size_t len;
- word_aligned = channel->rx_info_word != NULL;
+ word_aligned = channel->info_word;
tail = GET_RX_CHANNEL_INFO(channel, tail);
len = min_t(size_t, count, channel->fifo_size - tail);
@@ -491,7 +541,7 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
{
bool need_state_scan = false;
int remote_state;
- u32 pktlen;
+ __le32 pktlen;
int avail;
int ret;
@@ -502,10 +552,10 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
need_state_scan = true;
}
/* Indicate that we have seen any state change */
- SET_RX_CHANNEL_INFO(channel, fSTATE, 0);
+ SET_RX_CHANNEL_FLAG(channel, fSTATE, 0);
/* Signal waiting qcom_smd_send() about the interrupt */
- if (!GET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR))
+ if (!GET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR))
wake_up_interruptible(&channel->fblockread_event);
/* Don't consume any data until we've opened the channel */
@@ -513,7 +563,7 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
goto out;
/* Indicate that we've seen the new data */
- SET_RX_CHANNEL_INFO(channel, fHEAD, 0);
+ SET_RX_CHANNEL_FLAG(channel, fHEAD, 0);
/* Consume data */
for (;;) {
@@ -522,7 +572,7 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
if (!channel->pkt_size && avail >= SMD_PACKET_HEADER_LEN) {
qcom_smd_channel_peek(channel, &pktlen, sizeof(pktlen));
qcom_smd_channel_advance(channel, SMD_PACKET_HEADER_LEN);
- channel->pkt_size = pktlen;
+ channel->pkt_size = le32_to_cpu(pktlen);
} else if (channel->pkt_size && avail >= channel->pkt_size) {
ret = qcom_smd_channel_recv_single(channel);
if (ret)
@@ -533,10 +583,10 @@ static bool qcom_smd_channel_intr(struct qcom_smd_channel *channel)
}
/* Indicate that we have seen and updated tail */
- SET_RX_CHANNEL_INFO(channel, fTAIL, 1);
+ SET_RX_CHANNEL_FLAG(channel, fTAIL, 1);
/* Signal the remote that we've consumed the data (if requested) */
- if (!GET_RX_CHANNEL_INFO(channel, fBLOCKREADINTR)) {
+ if (!GET_RX_CHANNEL_FLAG(channel, fBLOCKREADINTR)) {
/* Ensure ordering of channel info updates */
wmb();
@@ -627,7 +677,7 @@ static int qcom_smd_write_fifo(struct qcom_smd_channel *channel,
unsigned head;
size_t len;
- word_aligned = channel->tx_info_word != NULL;
+ word_aligned = channel->info_word;
head = GET_TX_CHANNEL_INFO(channel, head);
len = min_t(size_t, count, channel->fifo_size - head);
@@ -665,12 +715,16 @@ static int qcom_smd_write_fifo(struct qcom_smd_channel *channel,
*/
int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
{
- u32 hdr[5] = {len,};
+ __le32 hdr[5] = { cpu_to_le32(len), };
int tlen = sizeof(hdr) + len;
int ret;
/* Word aligned channels only accept word size aligned data */
- if (channel->rx_info_word != NULL && len % 4)
+ if (channel->info_word && len % 4)
+ return -EINVAL;
+
+ /* Reject packets that are too big */
+ if (tlen >= channel->fifo_size)
return -EINVAL;
ret = mutex_lock_interruptible(&channel->tx_lock);
@@ -683,7 +737,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
goto out;
}
- SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0);
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 0);
ret = wait_event_interruptible(channel->fblockread_event,
qcom_smd_get_tx_avail(channel) >= tlen ||
@@ -691,15 +745,15 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len)
if (ret)
goto out;
- SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1);
+ SET_TX_CHANNEL_FLAG(channel, fBLOCKREADINTR, 1);
}
- SET_TX_CHANNEL_INFO(channel, fTAIL, 0);
+ SET_TX_CHANNEL_FLAG(channel, fTAIL, 0);
qcom_smd_write_fifo(channel, hdr, sizeof(hdr));
qcom_smd_write_fifo(channel, data, len);
- SET_TX_CHANNEL_INFO(channel, fHEAD, 1);
+ SET_TX_CHANNEL_FLAG(channel, fHEAD, 1);
/* Ensure ordering of channel info updates */
wmb();
@@ -727,6 +781,19 @@ static struct qcom_smd_driver *to_smd_driver(struct device *dev)
static int qcom_smd_dev_match(struct device *dev, struct device_driver *drv)
{
+ struct qcom_smd_device *qsdev = to_smd_device(dev);
+ struct qcom_smd_driver *qsdrv = container_of(drv, struct qcom_smd_driver, driver);
+ const struct qcom_smd_id *match = qsdrv->smd_match_table;
+ const char *name = qsdev->channel->name;
+
+ if (match) {
+ while (match->name[0]) {
+ if (!strcmp(match->name, name))
+ return 1;
+ match++;
+ }
+ }
+
return of_driver_match_device(dev, drv);
}
@@ -854,10 +921,8 @@ static struct device_node *qcom_smd_match_channel(struct device_node *edge_node,
for_each_available_child_of_node(edge_node, child) {
key = "qcom,smd-channels";
ret = of_property_read_string(child, key, &name);
- if (ret) {
- of_node_put(child);
+ if (ret)
continue;
- }
if (strcmp(name, channel) == 0)
return child;
@@ -880,19 +945,17 @@ static int qcom_smd_create_device(struct qcom_smd_channel *channel)
if (channel->qsdev)
return -EEXIST;
- node = qcom_smd_match_channel(edge->of_node, channel->name);
- if (!node) {
- dev_dbg(smd->dev, "no match for '%s'\n", channel->name);
- return -ENXIO;
- }
-
dev_dbg(smd->dev, "registering '%s'\n", channel->name);
qsdev = kzalloc(sizeof(*qsdev), GFP_KERNEL);
if (!qsdev)
return -ENOMEM;
- dev_set_name(&qsdev->dev, "%s.%s", edge->of_node->name, node->name);
+ node = qcom_smd_match_channel(edge->of_node, channel->name);
+ dev_set_name(&qsdev->dev, "%s.%s",
+ edge->of_node->name,
+ node ? node->name : channel->name);
+
qsdev->dev.parent = smd->dev;
qsdev->dev.bus = &qcom_smd_bus;
qsdev->dev.release = qcom_smd_release_device;
@@ -978,21 +1041,20 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
spin_lock_init(&channel->recv_lock);
init_waitqueue_head(&channel->fblockread_event);
- ret = qcom_smem_get(edge->remote_pid, smem_info_item, (void **)&info,
- &info_size);
- if (ret)
+ info = qcom_smem_get(edge->remote_pid, smem_info_item, &info_size);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
goto free_name_and_channel;
+ }
/*
* Use the size of the item to figure out which channel info struct to
* use.
*/
if (info_size == 2 * sizeof(struct smd_channel_info_word)) {
- channel->tx_info_word = info;
- channel->rx_info_word = info + sizeof(struct smd_channel_info_word);
+ channel->info_word = info;
} else if (info_size == 2 * sizeof(struct smd_channel_info)) {
- channel->tx_info = info;
- channel->rx_info = info + sizeof(struct smd_channel_info);
+ channel->info = info;
} else {
dev_err(smd->dev,
"channel info of size %zu not supported\n", info_size);
@@ -1000,10 +1062,11 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed
goto free_name_and_channel;
}
- ret = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_base,
- &fifo_size);
- if (ret)
+ fifo_base = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_size);
+ if (IS_ERR(fifo_base)) {
+ ret = PTR_ERR(fifo_base);
goto free_name_and_channel;
+ }
/* The channel consist of a rx and tx fifo of equal size */
fifo_size /= 2;
@@ -1040,20 +1103,19 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge)
unsigned long flags;
unsigned fifo_id;
unsigned info_id;
- int ret;
int tbl;
int i;
+ u32 eflags, cid;
for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) {
- ret = qcom_smem_get(edge->remote_pid,
- smem_items[tbl].alloc_tbl_id,
- (void **)&alloc_tbl,
- NULL);
- if (ret < 0)
+ alloc_tbl = qcom_smem_get(edge->remote_pid,
+ smem_items[tbl].alloc_tbl_id, NULL);
+ if (IS_ERR(alloc_tbl))
continue;
for (i = 0; i < SMD_ALLOC_TBL_SIZE; i++) {
entry = &alloc_tbl[i];
+ eflags = le32_to_cpu(entry->flags);
if (test_bit(i, edge->allocated[tbl]))
continue;
@@ -1063,14 +1125,15 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge)
if (!entry->name[0])
continue;
- if (!(entry->flags & SMD_CHANNEL_FLAGS_PACKET))
+ if (!(eflags & SMD_CHANNEL_FLAGS_PACKET))
continue;
- if ((entry->flags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id)
+ if ((eflags & SMD_CHANNEL_FLAGS_EDGE_MASK) != edge->edge_id)
continue;
- info_id = smem_items[tbl].info_base_id + entry->cid;
- fifo_id = smem_items[tbl].fifo_base_id + entry->cid;
+ cid = le32_to_cpu(entry->cid);
+ info_id = smem_items[tbl].info_base_id + cid;
+ fifo_id = smem_items[tbl].fifo_base_id + cid;
channel = qcom_smd_create_channel(edge, info_id, fifo_id, entry->name);
if (IS_ERR(channel))
@@ -1227,11 +1290,12 @@ static int qcom_smd_probe(struct platform_device *pdev)
int num_edges;
int ret;
int i = 0;
+ void *p;
/* Wait for smem */
- ret = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL, NULL);
- if (ret == -EPROBE_DEFER)
- return ret;
+ p = qcom_smem_get(QCOM_SMEM_HOST_ANY, smem_items[0].alloc_tbl_id, NULL);
+ if (PTR_ERR(p) == -EPROBE_DEFER)
+ return PTR_ERR(p);
num_edges = of_get_available_child_count(pdev->dev.of_node);
array_size = sizeof(*smd) + num_edges * sizeof(struct qcom_smd_edge);
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index 5236518..19019aa 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -92,9 +92,9 @@
* @params: parameters to the command
*/
struct smem_proc_comm {
- u32 command;
- u32 status;
- u32 params[2];
+ __le32 command;
+ __le32 status;
+ __le32 params[2];
};
/**
@@ -106,10 +106,10 @@ struct smem_proc_comm {
* the default region. bits 0,1 are reserved
*/
struct smem_global_entry {
- u32 allocated;
- u32 offset;
- u32 size;
- u32 aux_base; /* bits 1:0 reserved */
+ __le32 allocated;
+ __le32 offset;
+ __le32 size;
+ __le32 aux_base; /* bits 1:0 reserved */
};
#define AUX_BASE_MASK 0xfffffffc
@@ -125,11 +125,11 @@ struct smem_global_entry {
*/
struct smem_header {
struct smem_proc_comm proc_comm[4];
- u32 version[32];
- u32 initialized;
- u32 free_offset;
- u32 available;
- u32 reserved;
+ __le32 version[32];
+ __le32 initialized;
+ __le32 free_offset;
+ __le32 available;
+ __le32 reserved;
struct smem_global_entry toc[SMEM_ITEM_COUNT];
};
@@ -143,12 +143,12 @@ struct smem_header {
* @reserved: reserved entries for later use
*/
struct smem_ptable_entry {
- u32 offset;
- u32 size;
- u32 flags;
- u16 host0;
- u16 host1;
- u32 reserved[8];
+ __le32 offset;
+ __le32 size;
+ __le32 flags;
+ __le16 host0;
+ __le16 host1;
+ __le32 reserved[8];
};
/**
@@ -160,13 +160,14 @@ struct smem_ptable_entry {
* @entry: list of @smem_ptable_entry for the @num_entries partitions
*/
struct smem_ptable {
- u32 magic;
- u32 version;
- u32 num_entries;
- u32 reserved[5];
+ u8 magic[4];
+ __le32 version;
+ __le32 num_entries;
+ __le32 reserved[5];
struct smem_ptable_entry entry[];
};
-#define SMEM_PTABLE_MAGIC 0x434f5424 /* "$TOC" */
+
+static const u8 SMEM_PTABLE_MAGIC[] = { 0x24, 0x54, 0x4f, 0x43 }; /* "$TOC" */
/**
* struct smem_partition_header - header of the partitions
@@ -181,15 +182,16 @@ struct smem_ptable {
* @reserved: for now reserved entries
*/
struct smem_partition_header {
- u32 magic;
- u16 host0;
- u16 host1;
- u32 size;
- u32 offset_free_uncached;
- u32 offset_free_cached;
- u32 reserved[3];
+ u8 magic[4];
+ __le16 host0;
+ __le16 host1;
+ __le32 size;
+ __le32 offset_free_uncached;
+ __le32 offset_free_cached;
+ __le32 reserved[3];
};
-#define SMEM_PART_MAGIC 0x54525024 /* "$PRT" */
+
+static const u8 SMEM_PART_MAGIC[] = { 0x24, 0x50, 0x52, 0x54 };
/**
* struct smem_private_entry - header of each item in the private partition
@@ -201,12 +203,12 @@ struct smem_partition_header {
* @reserved: for now reserved entry
*/
struct smem_private_entry {
- u16 canary;
- u16 item;
- u32 size; /* includes padding bytes */
- u16 padding_data;
- u16 padding_hdr;
- u32 reserved;
+ u16 canary; /* bytes are the same so no swapping needed */
+ __le16 item;
+ __le32 size; /* includes padding bytes */
+ __le16 padding_data;
+ __le16 padding_hdr;
+ __le32 reserved;
};
#define SMEM_PRIVATE_CANARY 0xa5a5
@@ -242,6 +244,45 @@ struct qcom_smem {
struct smem_region regions[0];
};
+static struct smem_private_entry *
+phdr_to_last_private_entry(struct smem_partition_header *phdr)
+{
+ void *p = phdr;
+
+ return p + le32_to_cpu(phdr->offset_free_uncached);
+}
+
+static void *phdr_to_first_cached_entry(struct smem_partition_header *phdr)
+{
+ void *p = phdr;
+
+ return p + le32_to_cpu(phdr->offset_free_cached);
+}
+
+static struct smem_private_entry *
+phdr_to_first_private_entry(struct smem_partition_header *phdr)
+{
+ void *p = phdr;
+
+ return p + sizeof(*phdr);
+}
+
+static struct smem_private_entry *
+private_entry_next(struct smem_private_entry *e)
+{
+ void *p = e;
+
+ return p + sizeof(*e) + le16_to_cpu(e->padding_hdr) +
+ le32_to_cpu(e->size);
+}
+
+static void *entry_to_item(struct smem_private_entry *e)
+{
+ void *p = e;
+
+ return p + sizeof(*e) + le16_to_cpu(e->padding_hdr);
+}
+
/* Pointer to the one and only smem handle */
static struct qcom_smem *__smem;
@@ -254,16 +295,16 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
size_t size)
{
struct smem_partition_header *phdr;
- struct smem_private_entry *hdr;
+ struct smem_private_entry *hdr, *end;
size_t alloc_size;
- void *p;
+ void *cached;
phdr = smem->partitions[host];
+ hdr = phdr_to_first_private_entry(phdr);
+ end = phdr_to_last_private_entry(phdr);
+ cached = phdr_to_first_cached_entry(phdr);
- p = (void *)phdr + sizeof(*phdr);
- while (p < (void *)phdr + phdr->offset_free_uncached) {
- hdr = p;
-
+ while (hdr < end) {
if (hdr->canary != SMEM_PRIVATE_CANARY) {
dev_err(smem->dev,
"Found invalid canary in host %d partition\n",
@@ -271,24 +312,23 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
return -EINVAL;
}
- if (hdr->item == item)
+ if (le16_to_cpu(hdr->item) == item)
return -EEXIST;
- p += sizeof(*hdr) + hdr->padding_hdr + hdr->size;
+ hdr = private_entry_next(hdr);
}
/* Check that we don't grow into the cached region */
alloc_size = sizeof(*hdr) + ALIGN(size, 8);
- if (p + alloc_size >= (void *)phdr + phdr->offset_free_cached) {
+ if ((void *)hdr + alloc_size >= cached) {
dev_err(smem->dev, "Out of memory\n");
return -ENOSPC;
}
- hdr = p;
hdr->canary = SMEM_PRIVATE_CANARY;
- hdr->item = item;
- hdr->size = ALIGN(size, 8);
- hdr->padding_data = hdr->size - size;
+ hdr->item = cpu_to_le16(item);
+ hdr->size = cpu_to_le32(ALIGN(size, 8));
+ hdr->padding_data = cpu_to_le16(le32_to_cpu(hdr->size) - size);
hdr->padding_hdr = 0;
/*
@@ -297,7 +337,7 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem,
* gets a consistent view of the linked list.
*/
wmb();
- phdr->offset_free_uncached += alloc_size;
+ le32_add_cpu(&phdr->offset_free_uncached, alloc_size);
return 0;
}
@@ -318,11 +358,11 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem,
return -EEXIST;
size = ALIGN(size, 8);
- if (WARN_ON(size > header->available))
+ if (WARN_ON(size > le32_to_cpu(header->available)))
return -ENOMEM;
entry->offset = header->free_offset;
- entry->size = size;
+ entry->size = cpu_to_le32(size);
/*
* Ensure the header is consistent before we mark the item allocated,
@@ -330,10 +370,10 @@ static int qcom_smem_alloc_global(struct qcom_smem *smem,
* even though they do not take the spinlock on read.
*/
wmb();
- entry->allocated = 1;
+ entry->allocated = cpu_to_le32(1);
- header->free_offset += size;
- header->available -= size;
+ le32_add_cpu(&header->free_offset, size);
+ le32_add_cpu(&header->available, -size);
return 0;
}
@@ -378,10 +418,9 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
}
EXPORT_SYMBOL(qcom_smem_alloc);
-static int qcom_smem_get_global(struct qcom_smem *smem,
- unsigned item,
- void **ptr,
- size_t *size)
+static void *qcom_smem_get_global(struct qcom_smem *smem,
+ unsigned item,
+ size_t *size)
{
struct smem_header *header;
struct smem_region *area;
@@ -390,100 +429,94 @@ static int qcom_smem_get_global(struct qcom_smem *smem,
unsigned i;
if (WARN_ON(item >= SMEM_ITEM_COUNT))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
header = smem->regions[0].virt_base;
entry = &header->toc[item];
if (!entry->allocated)
- return -ENXIO;
+ return ERR_PTR(-ENXIO);
- if (ptr != NULL) {
- aux_base = entry->aux_base & AUX_BASE_MASK;
+ aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
- for (i = 0; i < smem->num_regions; i++) {
- area = &smem->regions[i];
+ for (i = 0; i < smem->num_regions; i++) {
+ area = &smem->regions[i];
- if (area->aux_base == aux_base || !aux_base) {
- *ptr = area->virt_base + entry->offset;
- break;
- }
+ if (area->aux_base == aux_base || !aux_base) {
+ if (size != NULL)
+ *size = le32_to_cpu(entry->size);
+ return area->virt_base + le32_to_cpu(entry->offset);
}
}
- if (size != NULL)
- *size = entry->size;
- return 0;
+ return ERR_PTR(-ENOENT);
}
-static int qcom_smem_get_private(struct qcom_smem *smem,
- unsigned host,
- unsigned item,
- void **ptr,
- size_t *size)
+static void *qcom_smem_get_private(struct qcom_smem *smem,
+ unsigned host,
+ unsigned item,
+ size_t *size)
{
struct smem_partition_header *phdr;
- struct smem_private_entry *hdr;
- void *p;
+ struct smem_private_entry *e, *end;
phdr = smem->partitions[host];
+ e = phdr_to_first_private_entry(phdr);
+ end = phdr_to_last_private_entry(phdr);
- p = (void *)phdr + sizeof(*phdr);
- while (p < (void *)phdr + phdr->offset_free_uncached) {
- hdr = p;
-
- if (hdr->canary != SMEM_PRIVATE_CANARY) {
+ while (e < end) {
+ if (e->canary != SMEM_PRIVATE_CANARY) {
dev_err(smem->dev,
"Found invalid canary in host %d partition\n",
host);
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
}
- if (hdr->item == item) {
- if (ptr != NULL)
- *ptr = p + sizeof(*hdr) + hdr->padding_hdr;
-
+ if (le16_to_cpu(e->item) == item) {
if (size != NULL)
- *size = hdr->size - hdr->padding_data;
+ *size = le32_to_cpu(e->size) -
+ le16_to_cpu(e->padding_data);
- return 0;
+ return entry_to_item(e);
}
- p += sizeof(*hdr) + hdr->padding_hdr + hdr->size;
+ e = private_entry_next(e);
}
- return -ENOENT;
+ return ERR_PTR(-ENOENT);
}
/**
* qcom_smem_get() - resolve ptr of size of a smem item
* @host: the remote processor, or -1
* @item: smem item handle
- * @ptr: pointer to be filled out with address of the item
* @size: pointer to be filled out with size of the item
*
- * Looks up pointer and size of a smem item.
+ * Looks up smem item and returns pointer to it. Size of smem
+ * item is returned in @size.
*/
-int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size)
+void *qcom_smem_get(unsigned host, unsigned item, size_t *size)
{
unsigned long flags;
int ret;
+ void *ptr = ERR_PTR(-EPROBE_DEFER);
if (!__smem)
- return -EPROBE_DEFER;
+ return ptr;
ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
HWSPINLOCK_TIMEOUT,
&flags);
if (ret)
- return ret;
+ return ERR_PTR(ret);
if (host < SMEM_HOST_COUNT && __smem->partitions[host])
- ret = qcom_smem_get_private(__smem, host, item, ptr, size);
+ ptr = qcom_smem_get_private(__smem, host, item, size);
else
- ret = qcom_smem_get_global(__smem, item, ptr, size);
+ ptr = qcom_smem_get_global(__smem, item, size);
hwspin_unlock_irqrestore(__smem->hwlock, &flags);
- return ret;
+
+ return ptr;
}
EXPORT_SYMBOL(qcom_smem_get);
@@ -506,10 +539,11 @@ int qcom_smem_get_free_space(unsigned host)
if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
phdr = __smem->partitions[host];
- ret = phdr->offset_free_cached - phdr->offset_free_uncached;
+ ret = le32_to_cpu(phdr->offset_free_cached) -
+ le32_to_cpu(phdr->offset_free_uncached);
} else {
header = __smem->regions[0].virt_base;
- ret = header->available;
+ ret = le32_to_cpu(header->available);
}
return ret;
@@ -518,13 +552,11 @@ EXPORT_SYMBOL(qcom_smem_get_free_space);
static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
{
- unsigned *versions;
+ __le32 *versions;
size_t size;
- int ret;
- ret = qcom_smem_get_global(smem, SMEM_ITEM_VERSION,
- (void **)&versions, &size);
- if (ret < 0) {
+ versions = qcom_smem_get_global(smem, SMEM_ITEM_VERSION, &size);
+ if (IS_ERR(versions)) {
dev_err(smem->dev, "Unable to read the version item\n");
return -ENOENT;
}
@@ -534,7 +566,7 @@ static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
return -EINVAL;
}
- return versions[SMEM_MASTER_SBL_VERSION_INDEX];
+ return le32_to_cpu(versions[SMEM_MASTER_SBL_VERSION_INDEX]);
}
static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
@@ -544,35 +576,38 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
unsigned remote_host;
+ u32 version, host0, host1;
int i;
ptable = smem->regions[0].virt_base + smem->regions[0].size - SZ_4K;
- if (ptable->magic != SMEM_PTABLE_MAGIC)
+ if (memcmp(ptable->magic, SMEM_PTABLE_MAGIC, sizeof(ptable->magic)))
return 0;
- if (ptable->version != 1) {
+ version = le32_to_cpu(ptable->version);
+ if (version != 1) {
dev_err(smem->dev,
- "Unsupported partition header version %d\n",
- ptable->version);
+ "Unsupported partition header version %d\n", version);
return -EINVAL;
}
- for (i = 0; i < ptable->num_entries; i++) {
+ for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i];
+ host0 = le16_to_cpu(entry->host0);
+ host1 = le16_to_cpu(entry->host1);
- if (entry->host0 != local_host && entry->host1 != local_host)
+ if (host0 != local_host && host1 != local_host)
continue;
- if (!entry->offset)
+ if (!le32_to_cpu(entry->offset))
continue;
- if (!entry->size)
+ if (!le32_to_cpu(entry->size))
continue;
- if (entry->host0 == local_host)
- remote_host = entry->host1;
+ if (host0 == local_host)
+ remote_host = host1;
else
- remote_host = entry->host0;
+ remote_host = host0;
if (remote_host >= SMEM_HOST_COUNT) {
dev_err(smem->dev,
@@ -588,21 +623,24 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
return -EINVAL;
}
- header = smem->regions[0].virt_base + entry->offset;
+ header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
+ host0 = le16_to_cpu(header->host0);
+ host1 = le16_to_cpu(header->host1);
- if (header->magic != SMEM_PART_MAGIC) {
+ if (memcmp(header->magic, SMEM_PART_MAGIC,
+ sizeof(header->magic))) {
dev_err(smem->dev,
"Partition %d has invalid magic\n", i);
return -EINVAL;
}
- if (header->host0 != local_host && header->host1 != local_host) {
+ if (host0 != local_host && host1 != local_host) {
dev_err(smem->dev,
"Partition %d hosts are invalid\n", i);
return -EINVAL;
}
- if (header->host0 != remote_host && header->host1 != remote_host) {
+ if (host0 != remote_host && host1 != remote_host) {
dev_err(smem->dev,
"Partition %d hosts are invalid\n", i);
return -EINVAL;
@@ -614,7 +652,7 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
return -EINVAL;
}
- if (header->offset_free_uncached > header->size) {
+ if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
dev_err(smem->dev,
"Partition %d has invalid free pointer\n", i);
return -EINVAL;
@@ -626,37 +664,47 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
return 0;
}
-static int qcom_smem_count_mem_regions(struct platform_device *pdev)
+static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
+ const char *name, int i)
{
- struct resource *res;
- int num_regions = 0;
- int i;
-
- for (i = 0; i < pdev->num_resources; i++) {
- res = &pdev->resource[i];
+ struct device_node *np;
+ struct resource r;
+ int ret;
- if (resource_type(res) == IORESOURCE_MEM)
- num_regions++;
+ np = of_parse_phandle(dev->of_node, name, 0);
+ if (!np) {
+ dev_err(dev, "No %s specified\n", name);
+ return -EINVAL;
}
- return num_regions;
+ ret = of_address_to_resource(np, 0, &r);
+ of_node_put(np);
+ if (ret)
+ return ret;
+
+ smem->regions[i].aux_base = (u32)r.start;
+ smem->regions[i].size = resource_size(&r);
+ smem->regions[i].virt_base = devm_ioremap_nocache(dev, r.start,
+ resource_size(&r));
+ if (!smem->regions[i].virt_base)
+ return -ENOMEM;
+
+ return 0;
}
static int qcom_smem_probe(struct platform_device *pdev)
{
struct smem_header *header;
- struct device_node *np;
struct qcom_smem *smem;
- struct resource *res;
- struct resource r;
size_t array_size;
- int num_regions = 0;
+ int num_regions;
int hwlock_id;
u32 version;
int ret;
- int i;
- num_regions = qcom_smem_count_mem_regions(pdev) + 1;
+ num_regions = 1;
+ if (of_find_property(pdev->dev.of_node, "qcom,rpm-msg-ram", NULL))
+ num_regions++;
array_size = num_regions * sizeof(struct smem_region);
smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL);
@@ -666,39 +714,17 @@ static int qcom_smem_probe(struct platform_device *pdev)
smem->dev = &pdev->dev;
smem->num_regions = num_regions;
- np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
- if (!np) {
- dev_err(&pdev->dev, "No memory-region specified\n");
- return -EINVAL;
- }
-
- ret = of_address_to_resource(np, 0, &r);
- of_node_put(np);
+ ret = qcom_smem_map_memory(smem, &pdev->dev, "memory-region", 0);
if (ret)
return ret;
- smem->regions[0].aux_base = (u32)r.start;
- smem->regions[0].size = resource_size(&r);
- smem->regions[0].virt_base = devm_ioremap_nocache(&pdev->dev,
- r.start,
- resource_size(&r));
- if (!smem->regions[0].virt_base)
- return -ENOMEM;
-
- for (i = 1; i < num_regions; i++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, i - 1);
-
- smem->regions[i].aux_base = (u32)res->start;
- smem->regions[i].size = resource_size(res);
- smem->regions[i].virt_base = devm_ioremap_nocache(&pdev->dev,
- res->start,
- resource_size(res));
- if (!smem->regions[i].virt_base)
- return -ENOMEM;
- }
+ if (num_regions > 1 && (ret = qcom_smem_map_memory(smem, &pdev->dev,
+ "qcom,rpm-msg-ram", 1)))
+ return ret;
header = smem->regions[0].virt_base;
- if (header->initialized != 1 || header->reserved) {
+ if (le32_to_cpu(header->initialized) != 1 ||
+ le32_to_cpu(header->reserved)) {
dev_err(&pdev->dev, "SMEM is not initialized by SBL\n");
return -EINVAL;
}
@@ -730,8 +756,8 @@ static int qcom_smem_probe(struct platform_device *pdev)
static int qcom_smem_remove(struct platform_device *pdev)
{
- __smem = NULL;
hwspin_lock_free(__smem->hwlock);
+ __smem = NULL;
return 0;
}
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index b04b05a..0ad66fa 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -116,7 +116,7 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);
-typedef int (*idle_fn)(int);
+typedef int (*idle_fn)(void);
static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);
static inline void spm_register_write(struct spm_driver_data *drv,
@@ -179,10 +179,10 @@ static int qcom_pm_collapse(unsigned long int unused)
return -1;
}
-static int qcom_cpu_spc(int cpu)
+static int qcom_cpu_spc(void)
{
int ret;
- struct spm_driver_data *drv = per_cpu(cpu_spm_drv, cpu);
+ struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv);
spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
ret = cpu_suspend(0, qcom_pm_collapse);
@@ -197,9 +197,9 @@ static int qcom_cpu_spc(int cpu)
return ret;
}
-static int qcom_idle_enter(int cpu, unsigned long index)
+static int qcom_idle_enter(unsigned long index)
{
- return per_cpu(qcom_idle_ops, cpu)[index](cpu);
+ return __this_cpu_read(qcom_idle_ops)[index]();
}
static const struct of_device_id qcom_idle_state_match[] __initconst = {
diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
new file mode 100644
index 0000000..7140ff8
--- /dev/null
+++ b/drivers/soc/rockchip/Kconfig
@@ -0,0 +1,18 @@
+if ARCH_ROCKCHIP || COMPILE_TEST
+
+#
+# Rockchip Soc drivers
+#
+config ROCKCHIP_PM_DOMAINS
+ bool "Rockchip generic power domain"
+ depends on PM
+ select PM_GENERIC_DOMAINS
+ help
+ Say y here to enable power domain support.
+ In order to meet high performance and low power requirements, a power
+ management unit is designed or saving power when RK3288 in low power
+ mode. The RK3288 PMU is dedicated for managing the power of the whole chip.
+
+ If unsure, say N.
+
+endif
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
new file mode 100644
index 0000000..3d73d06
--- /dev/null
+++ b/drivers/soc/rockchip/Makefile
@@ -0,0 +1,4 @@
+#
+# Rockchip Soc drivers
+#
+obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c
new file mode 100644
index 0000000..534c589
--- /dev/null
+++ b/drivers/soc/rockchip/pm_domains.c
@@ -0,0 +1,490 @@
+/*
+ * Rockchip Generic power domain support.
+ *
+ * Copyright (c) 2015 ROCKCHIP, Co. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/pm_clock.h>
+#include <linux/pm_domain.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <dt-bindings/power/rk3288-power.h>
+
+struct rockchip_domain_info {
+ int pwr_mask;
+ int status_mask;
+ int req_mask;
+ int idle_mask;
+ int ack_mask;
+};
+
+struct rockchip_pmu_info {
+ u32 pwr_offset;
+ u32 status_offset;
+ u32 req_offset;
+ u32 idle_offset;
+ u32 ack_offset;
+
+ u32 core_pwrcnt_offset;
+ u32 gpu_pwrcnt_offset;
+
+ unsigned int core_power_transition_time;
+ unsigned int gpu_power_transition_time;
+
+ int num_domains;
+ const struct rockchip_domain_info *domain_info;
+};
+
+struct rockchip_pm_domain {
+ struct generic_pm_domain genpd;
+ const struct rockchip_domain_info *info;
+ struct rockchip_pmu *pmu;
+ int num_clks;
+ struct clk *clks[];
+};
+
+struct rockchip_pmu {
+ struct device *dev;
+ struct regmap *regmap;
+ const struct rockchip_pmu_info *info;
+ struct mutex mutex; /* mutex lock for pmu */
+ struct genpd_onecell_data genpd_data;
+ struct generic_pm_domain *domains[];
+};
+
+#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
+
+#define DOMAIN(pwr, status, req, idle, ack) \
+{ \
+ .pwr_mask = BIT(pwr), \
+ .status_mask = BIT(status), \
+ .req_mask = BIT(req), \
+ .idle_mask = BIT(idle), \
+ .ack_mask = BIT(ack), \
+}
+
+#define DOMAIN_RK3288(pwr, status, req) \
+ DOMAIN(pwr, status, req, req, (req) + 16)
+
+static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
+{
+ struct rockchip_pmu *pmu = pd->pmu;
+ const struct rockchip_domain_info *pd_info = pd->info;
+ unsigned int val;
+
+ regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
+ return (val & pd_info->idle_mask) == pd_info->idle_mask;
+}
+
+static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
+ bool idle)
+{
+ const struct rockchip_domain_info *pd_info = pd->info;
+ struct rockchip_pmu *pmu = pd->pmu;
+ unsigned int val;
+
+ regmap_update_bits(pmu->regmap, pmu->info->req_offset,
+ pd_info->req_mask, idle ? -1U : 0);
+
+ dsb(sy);
+
+ do {
+ regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
+ } while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0));
+
+ while (rockchip_pmu_domain_is_idle(pd) != idle)
+ cpu_relax();
+
+ return 0;
+}
+
+static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
+{
+ struct rockchip_pmu *pmu = pd->pmu;
+ unsigned int val;
+
+ regmap_read(pmu->regmap, pmu->info->status_offset, &val);
+
+ /* 1'b0: power on, 1'b1: power off */
+ return !(val & pd->info->status_mask);
+}
+
+static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
+ bool on)
+{
+ struct rockchip_pmu *pmu = pd->pmu;
+
+ regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
+ pd->info->pwr_mask, on ? 0 : -1U);
+
+ dsb(sy);
+
+ while (rockchip_pmu_domain_is_on(pd) != on)
+ cpu_relax();
+}
+
+static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
+{
+ int i;
+
+ mutex_lock(&pd->pmu->mutex);
+
+ if (rockchip_pmu_domain_is_on(pd) != power_on) {
+ for (i = 0; i < pd->num_clks; i++)
+ clk_enable(pd->clks[i]);
+
+ if (!power_on) {
+ /* FIXME: add code to save AXI_QOS */
+
+ /* if powering down, idle request to NIU first */
+ rockchip_pmu_set_idle_request(pd, true);
+ }
+
+ rockchip_do_pmu_set_power_domain(pd, power_on);
+
+ if (power_on) {
+ /* if powering up, leave idle mode */
+ rockchip_pmu_set_idle_request(pd, false);
+
+ /* FIXME: add code to restore AXI_QOS */
+ }
+
+ for (i = pd->num_clks - 1; i >= 0; i--)
+ clk_disable(pd->clks[i]);
+ }
+
+ mutex_unlock(&pd->pmu->mutex);
+ return 0;
+}
+
+static int rockchip_pd_power_on(struct generic_pm_domain *domain)
+{
+ struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
+
+ return rockchip_pd_power(pd, true);
+}
+
+static int rockchip_pd_power_off(struct generic_pm_domain *domain)
+{
+ struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
+
+ return rockchip_pd_power(pd, false);
+}
+
+static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ struct clk *clk;
+ int i;
+ int error;
+
+ dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
+
+ error = pm_clk_create(dev);
+ if (error) {
+ dev_err(dev, "pm_clk_create failed %d\n", error);
+ return error;
+ }
+
+ i = 0;
+ while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
+ dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
+ error = pm_clk_add_clk(dev, clk);
+ if (error) {
+ dev_err(dev, "pm_clk_add_clk failed %d\n", error);
+ clk_put(clk);
+ pm_clk_destroy(dev);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
+ struct device *dev)
+{
+ dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
+
+ pm_clk_destroy(dev);
+}
+
+static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
+ struct device_node *node)
+{
+ const struct rockchip_domain_info *pd_info;
+ struct rockchip_pm_domain *pd;
+ struct clk *clk;
+ int clk_cnt;
+ int i;
+ u32 id;
+ int error;
+
+ error = of_property_read_u32(node, "reg", &id);
+ if (error) {
+ dev_err(pmu->dev,
+ "%s: failed to retrieve domain id (reg): %d\n",
+ node->name, error);
+ return -EINVAL;
+ }
+
+ if (id >= pmu->info->num_domains) {
+ dev_err(pmu->dev, "%s: invalid domain id %d\n",
+ node->name, id);
+ return -EINVAL;
+ }
+
+ pd_info = &pmu->info->domain_info[id];
+ if (!pd_info) {
+ dev_err(pmu->dev, "%s: undefined domain id %d\n",
+ node->name, id);
+ return -EINVAL;
+ }
+
+ clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells");
+ pd = devm_kzalloc(pmu->dev,
+ sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]),
+ GFP_KERNEL);
+ if (!pd)
+ return -ENOMEM;
+
+ pd->info = pd_info;
+ pd->pmu = pmu;
+
+ for (i = 0; i < clk_cnt; i++) {
+ clk = of_clk_get(node, i);
+ if (IS_ERR(clk)) {
+ error = PTR_ERR(clk);
+ dev_err(pmu->dev,
+ "%s: failed to get clk at index %d: %d\n",
+ node->name, i, error);
+ goto err_out;
+ }
+
+ error = clk_prepare(clk);
+ if (error) {
+ dev_err(pmu->dev,
+ "%s: failed to prepare clk %pC (index %d): %d\n",
+ node->name, clk, i, error);
+ clk_put(clk);
+ goto err_out;
+ }
+
+ pd->clks[pd->num_clks++] = clk;
+
+ dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n",
+ clk, node->name);
+ }
+
+ error = rockchip_pd_power(pd, true);
+ if (error) {
+ dev_err(pmu->dev,
+ "failed to power on domain '%s': %d\n",
+ node->name, error);
+ goto err_out;
+ }
+
+ pd->genpd.name = node->name;
+ pd->genpd.power_off = rockchip_pd_power_off;
+ pd->genpd.power_on = rockchip_pd_power_on;
+ pd->genpd.attach_dev = rockchip_pd_attach_dev;
+ pd->genpd.detach_dev = rockchip_pd_detach_dev;
+ pd->genpd.flags = GENPD_FLAG_PM_CLK;
+ pm_genpd_init(&pd->genpd, NULL, false);
+
+ pmu->genpd_data.domains[id] = &pd->genpd;
+ return 0;
+
+err_out:
+ while (--i >= 0) {
+ clk_unprepare(pd->clks[i]);
+ clk_put(pd->clks[i]);
+ }
+ return error;
+}
+
+static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
+{
+ int i;
+
+ for (i = 0; i < pd->num_clks; i++) {
+ clk_unprepare(pd->clks[i]);
+ clk_put(pd->clks[i]);
+ }
+
+ /* protect the zeroing of pm->num_clks */
+ mutex_lock(&pd->pmu->mutex);
+ pd->num_clks = 0;
+ mutex_unlock(&pd->pmu->mutex);
+
+ /* devm will free our memory */
+}
+
+static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
+{
+ struct generic_pm_domain *genpd;
+ struct rockchip_pm_domain *pd;
+ int i;
+
+ for (i = 0; i < pmu->genpd_data.num_domains; i++) {
+ genpd = pmu->genpd_data.domains[i];
+ if (genpd) {
+ pd = to_rockchip_pd(genpd);
+ rockchip_pm_remove_one_domain(pd);
+ }
+ }
+
+ /* devm will free our memory */
+}
+
+static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
+ u32 domain_reg_offset,
+ unsigned int count)
+{
+ /* First configure domain power down transition count ... */
+ regmap_write(pmu->regmap, domain_reg_offset, count);
+ /* ... and then power up count. */
+ regmap_write(pmu->regmap, domain_reg_offset + 4, count);
+}
+
+static int rockchip_pm_domain_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *node;
+ struct device *parent;
+ struct rockchip_pmu *pmu;
+ const struct of_device_id *match;
+ const struct rockchip_pmu_info *pmu_info;
+ int error;
+
+ if (!np) {
+ dev_err(dev, "device tree node not found\n");
+ return -ENODEV;
+ }
+
+ match = of_match_device(dev->driver->of_match_table, dev);
+ if (!match || !match->data) {
+ dev_err(dev, "missing pmu data\n");
+ return -EINVAL;
+ }
+
+ pmu_info = match->data;
+
+ pmu = devm_kzalloc(dev,
+ sizeof(*pmu) +
+ pmu_info->num_domains * sizeof(pmu->domains[0]),
+ GFP_KERNEL);
+ if (!pmu)
+ return -ENOMEM;
+
+ pmu->dev = &pdev->dev;
+ mutex_init(&pmu->mutex);
+
+ pmu->info = pmu_info;
+
+ pmu->genpd_data.domains = pmu->domains;
+ pmu->genpd_data.num_domains = pmu_info->num_domains;
+
+ parent = dev->parent;
+ if (!parent) {
+ dev_err(dev, "no parent for syscon devices\n");
+ return -ENODEV;
+ }
+
+ pmu->regmap = syscon_node_to_regmap(parent->of_node);
+
+ /*
+ * Configure power up and down transition delays for CORE
+ * and GPU domains.
+ */
+ rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
+ pmu_info->core_power_transition_time);
+ rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
+ pmu_info->gpu_power_transition_time);
+
+ error = -ENODEV;
+
+ for_each_available_child_of_node(np, node) {
+ error = rockchip_pm_add_one_domain(pmu, node);
+ if (error) {
+ dev_err(dev, "failed to handle node %s: %d\n",
+ node->name, error);
+ goto err_out;
+ }
+ }
+
+ if (error) {
+ dev_dbg(dev, "no power domains defined\n");
+ goto err_out;
+ }
+
+ of_genpd_add_provider_onecell(np, &pmu->genpd_data);
+
+ return 0;
+
+err_out:
+ rockchip_pm_domain_cleanup(pmu);
+ return error;
+}
+
+static const struct rockchip_domain_info rk3288_pm_domains[] = {
+ [RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4),
+ [RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9),
+ [RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3),
+ [RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2),
+};
+
+static const struct rockchip_pmu_info rk3288_pmu = {
+ .pwr_offset = 0x08,
+ .status_offset = 0x0c,
+ .req_offset = 0x10,
+ .idle_offset = 0x14,
+ .ack_offset = 0x14,
+
+ .core_pwrcnt_offset = 0x34,
+ .gpu_pwrcnt_offset = 0x3c,
+
+ .core_power_transition_time = 24, /* 1us */
+ .gpu_power_transition_time = 24, /* 1us */
+
+ .num_domains = ARRAY_SIZE(rk3288_pm_domains),
+ .domain_info = rk3288_pm_domains,
+};
+
+static const struct of_device_id rockchip_pm_domain_dt_match[] = {
+ {
+ .compatible = "rockchip,rk3288-power-controller",
+ .data = (void *)&rk3288_pmu,
+ },
+ { /* sentinel */ },
+};
+
+static struct platform_driver rockchip_pm_domain_driver = {
+ .probe = rockchip_pm_domain_probe,
+ .driver = {
+ .name = "rockchip-pm-domain",
+ .of_match_table = rockchip_pm_domain_dt_match,
+ /*
+ * We can't forcibly eject devices form power domain,
+ * so we can't really remove power domains once they
+ * were added.
+ */
+ .suppress_bind_attrs = true,
+ },
+};
+
+static int __init rockchip_pm_domain_drv_register(void)
+{
+ return platform_driver_register(&rockchip_pm_domain_driver);
+}
+postcore_initcall(rockchip_pm_domain_drv_register);
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index 51da234..6ff936c 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -135,9 +135,10 @@ struct knav_pdsp_info {
};
void __iomem *intd;
u32 __iomem *iram;
- const char *firmware;
u32 id;
struct list_head list;
+ bool loaded;
+ bool started;
};
struct knav_qmgr_info {
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index ef6f69d..d2d48f2 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -261,6 +261,10 @@ static int knav_range_setup_acc_irq(struct knav_range_info *range,
if (old && !new) {
dev_dbg(kdev->dev, "setup-acc-irq: freeing %s for channel %s\n",
acc->name, acc->name);
+ ret = irq_set_affinity_hint(irq, NULL);
+ if (ret)
+ dev_warn(range->kdev->dev,
+ "Failed to set IRQ affinity\n");
free_irq(irq, range);
}
@@ -482,8 +486,8 @@ struct knav_range_ops knav_acc_range_ops = {
* Return 0 on success or error
*/
int knav_init_acc_range(struct knav_device *kdev,
- struct device_node *node,
- struct knav_range_info *range)
+ struct device_node *node,
+ struct knav_range_info *range)
{
struct knav_acc_channel *acc;
struct knav_pdsp_info *pdsp;
@@ -526,6 +530,12 @@ int knav_init_acc_range(struct knav_device *kdev,
return -EINVAL;
}
+ if (!pdsp->started) {
+ dev_err(kdev->dev, "pdsp id %d not started for range %s\n",
+ info->pdsp_id, range->name);
+ return -ENODEV;
+ }
+
info->pdsp = pdsp;
channels = range->num_queues;
if (of_get_property(node, "multi-queue", NULL)) {
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 6d8646d..8c03a80 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -68,6 +68,12 @@ static DEFINE_MUTEX(knav_dev_lock);
idx < (kdev)->num_queues_in_use; \
idx++, inst = knav_queue_idx_to_inst(kdev, idx))
+/* All firmware file names end up here. List the firmware file names below.
+ * Newest followed by older ones. Search is done from start of the array
+ * until a firmware file is found.
+ */
+const char *knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"};
+
/**
* knav_queue_notify: qmss queue notfier call
*
@@ -1173,7 +1179,7 @@ static int knav_queue_setup_link_ram(struct knav_device *kdev)
block++;
if (!block->size)
- return 0;
+ continue;
dev_dbg(kdev->dev, "linkram1: phys:%x, virt:%p, size:%x\n",
block->phys, block->virt, block->size);
@@ -1439,7 +1445,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
struct device *dev = kdev->dev;
struct knav_pdsp_info *pdsp;
struct device_node *child;
- int ret;
for_each_child_of_node(pdsps, child) {
pdsp = devm_kzalloc(dev, sizeof(*pdsp), GFP_KERNEL);
@@ -1448,17 +1453,6 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
return -ENOMEM;
}
pdsp->name = knav_queue_find_name(child);
- ret = of_property_read_string(child, "firmware",
- &pdsp->firmware);
- if (ret < 0 || !pdsp->firmware) {
- dev_err(dev, "unknown firmware for pdsp %s\n",
- pdsp->name);
- devm_kfree(dev, pdsp);
- continue;
- }
- dev_dbg(dev, "pdsp name %s fw name :%s\n", pdsp->name,
- pdsp->firmware);
-
pdsp->iram =
knav_queue_map_reg(kdev, child,
KNAV_QUEUE_PDSP_IRAM_REG_INDEX);
@@ -1489,9 +1483,9 @@ static int knav_queue_init_pdsps(struct knav_device *kdev,
}
of_property_read_u32(child, "id", &pdsp->id);
list_add_tail(&pdsp->list, &kdev->pdsps);
- dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p, firmware %s\n",
+ dev_dbg(dev, "added pdsp %s: command %p, iram %p, regs %p, intd %p\n",
pdsp->name, pdsp->command, pdsp->iram, pdsp->regs,
- pdsp->intd, pdsp->firmware);
+ pdsp->intd);
}
return 0;
}
@@ -1510,6 +1504,8 @@ static int knav_queue_stop_pdsp(struct knav_device *kdev,
dev_err(kdev->dev, "timed out on pdsp %s stop\n", pdsp->name);
return ret;
}
+ pdsp->loaded = false;
+ pdsp->started = false;
return 0;
}
@@ -1518,14 +1514,29 @@ static int knav_queue_load_pdsp(struct knav_device *kdev,
{
int i, ret, fwlen;
const struct firmware *fw;
+ bool found = false;
u32 *fwdata;
- ret = request_firmware(&fw, pdsp->firmware, kdev->dev);
- if (ret) {
- dev_err(kdev->dev, "failed to get firmware %s for pdsp %s\n",
- pdsp->firmware, pdsp->name);
- return ret;
+ for (i = 0; i < ARRAY_SIZE(knav_acc_firmwares); i++) {
+ if (knav_acc_firmwares[i]) {
+ ret = request_firmware_direct(&fw,
+ knav_acc_firmwares[i],
+ kdev->dev);
+ if (!ret) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ dev_err(kdev->dev, "failed to get firmware for pdsp\n");
+ return -ENODEV;
}
+
+ dev_info(kdev->dev, "firmware file %s downloaded for PDSP\n",
+ knav_acc_firmwares[i]);
+
writel_relaxed(pdsp->id + 1, pdsp->command + 0x18);
/* download the firmware */
fwdata = (u32 *)fw->data;
@@ -1583,16 +1594,24 @@ static int knav_queue_start_pdsps(struct knav_device *kdev)
int ret;
knav_queue_stop_pdsps(kdev);
- /* now load them all */
+ /* now load them all. We return success even if pdsp
+ * is not loaded as acc channels are optional on having
+ * firmware availability in the system. We set the loaded
+ * and stated flag and when initialize the acc range, check
+ * it and init the range only if pdsp is started.
+ */
for_each_pdsp(kdev, pdsp) {
ret = knav_queue_load_pdsp(kdev, pdsp);
- if (ret < 0)
- return ret;
+ if (!ret)
+ pdsp->loaded = true;
}
for_each_pdsp(kdev, pdsp) {
- ret = knav_queue_start_pdsp(kdev, pdsp);
- WARN_ON(ret);
+ if (pdsp->loaded) {
+ ret = knav_queue_start_pdsp(kdev, pdsp);
+ if (!ret)
+ pdsp->started = true;
+ }
}
return 0;
}
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index 06858e0..bf9a610 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.c
@@ -562,8 +562,8 @@ static int bcm63xx_spi_probe(struct platform_device *pdev)
goto out_clk_disable;
}
- dev_info(dev, "at 0x%08x (irq %d, FIFOs size %d)\n",
- r->start, irq, bs->fifo_size);
+ dev_info(dev, "at %pr (irq %d, FIFOs size %d)\n",
+ r, irq, bs->fifo_size);
return 0;
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 59a1143..39412c9 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -167,7 +167,7 @@ static inline int is_double_byte_mode(struct fsl_dspi *dspi)
{
unsigned int val;
- regmap_read(dspi->regmap, SPI_CTAR(dspi->cs), &val);
+ regmap_read(dspi->regmap, SPI_CTAR(0), &val);
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
}
@@ -257,7 +257,7 @@ static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
return SPI_PUSHR_TXDATA(d16) |
SPI_PUSHR_PCS(dspi->cs) |
- SPI_PUSHR_CTAS(dspi->cs) |
+ SPI_PUSHR_CTAS(0) |
SPI_PUSHR_CONT;
}
@@ -290,7 +290,7 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
*/
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ regmap_update_bits(dspi->regmap, SPI_CTAR(0),
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@@ -339,7 +339,7 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
if (tx_word && (dspi->len == 1)) {
dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
+ regmap_update_bits(dspi->regmap, SPI_CTAR(0),
SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
tx_word = 0;
}
@@ -407,7 +407,7 @@ static int dspi_transfer_one_message(struct spi_master *master,
regmap_update_bits(dspi->regmap, SPI_MCR,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
- regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+ regmap_write(dspi->regmap, SPI_CTAR(0),
dspi->cur_chip->ctar_val);
trans_mode = dspi->devtype_data->trans_mode;
@@ -566,7 +566,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
regmap_update_bits(dspi->regmap,
- SPI_CTAR(dspi->cs),
+ SPI_CTAR(0),
SPI_FRAME_BITS_MASK,
SPI_FRAME_BITS(16));
dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c
index 563954a..7840067 100644
--- a/drivers/spi/spi-mt65xx.c
+++ b/drivers/spi/spi-mt65xx.c
@@ -410,7 +410,7 @@ static int mtk_spi_setup(struct spi_device *spi)
if (!spi->controller_data)
spi->controller_data = (void *)&mtk_default_chip_info;
- if (mdata->dev_comp->need_pad_sel)
+ if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio))
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
@@ -632,13 +632,23 @@ static int mtk_spi_probe(struct platform_device *pdev)
goto err_put_master;
}
- for (i = 0; i < master->num_chipselect; i++) {
- ret = devm_gpio_request(&pdev->dev, master->cs_gpios[i],
- dev_name(&pdev->dev));
- if (ret) {
- dev_err(&pdev->dev,
- "can't get CS GPIO %i\n", i);
- goto err_put_master;
+ if (!master->cs_gpios && master->num_chipselect > 1) {
+ dev_err(&pdev->dev,
+ "cs_gpios not specified and num_chipselect > 1\n");
+ ret = -EINVAL;
+ goto err_put_master;
+ }
+
+ if (master->cs_gpios) {
+ for (i = 0; i < master->num_chipselect; i++) {
+ ret = devm_gpio_request(&pdev->dev,
+ master->cs_gpios[i],
+ dev_name(&pdev->dev));
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't get CS GPIO %i\n", i);
+ goto err_put_master;
+ }
}
}
}
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index 94af806..5e5fd77 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -1171,19 +1171,31 @@ err_no_rxchan:
static int pl022_dma_autoprobe(struct pl022 *pl022)
{
struct device *dev = &pl022->adev->dev;
+ struct dma_chan *chan;
+ int err;
/* automatically configure DMA channels from platform, normally using DT */
- pl022->dma_rx_channel = dma_request_slave_channel(dev, "rx");
- if (!pl022->dma_rx_channel)
+ chan = dma_request_slave_channel_reason(dev, "rx");
+ if (IS_ERR(chan)) {
+ err = PTR_ERR(chan);
goto err_no_rxchan;
+ }
+
+ pl022->dma_rx_channel = chan;
- pl022->dma_tx_channel = dma_request_slave_channel(dev, "tx");
- if (!pl022->dma_tx_channel)
+ chan = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR(chan)) {
+ err = PTR_ERR(chan);
goto err_no_txchan;
+ }
+
+ pl022->dma_tx_channel = chan;
pl022->dummypage = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!pl022->dummypage)
+ if (!pl022->dummypage) {
+ err = -ENOMEM;
goto err_no_dummypage;
+ }
return 0;
@@ -1194,7 +1206,7 @@ err_no_txchan:
dma_release_channel(pl022->dma_rx_channel);
pl022->dma_rx_channel = NULL;
err_no_rxchan:
- return -ENODEV;
+ return err;
}
static void terminate_dma(struct pl022 *pl022)
@@ -2236,6 +2248,10 @@ static int pl022_probe(struct amba_device *adev, const struct amba_id *id)
/* Get DMA channels, try autoconfiguration first */
status = pl022_dma_autoprobe(pl022);
+ if (status == -EPROBE_DEFER) {
+ dev_dbg(dev, "deferring probe to get DMA channel\n");
+ goto err_no_irq;
+ }
/* If that failed, use channels from platform_info */
if (status == 0)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e2415be..dee1cb8 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -376,6 +376,7 @@ static void spi_drv_shutdown(struct device *dev)
/**
* __spi_register_driver - register a SPI driver
+ * @owner: owner module of the driver to register
* @sdrv: the driver to register
* Context: can sleep
*
@@ -1704,7 +1705,7 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
master->bus_num = -1;
master->num_chipselect = 1;
master->dev.class = &spi_master_class;
- master->dev.parent = get_device(dev);
+ master->dev.parent = dev;
spi_master_set_devdata(master, &master[1]);
return master;
@@ -2130,6 +2131,7 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
* Set transfer tx_nbits and rx_nbits as single transfer default
* (SPI_NBITS_SINGLE) if it is not set for this transfer.
*/
+ message->frame_length = 0;
list_for_each_entry(xfer, &message->transfers, transfer_list) {
message->frame_length += xfer->len;
if (!xfer->bits_per_word)
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 91a0fcd..d0e7dfc 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -651,11 +651,11 @@ static int spidev_release(struct inode *inode, struct file *filp)
kfree(spidev->rx_buffer);
spidev->rx_buffer = NULL;
+ spin_lock_irq(&spidev->spi_lock);
if (spidev->spi)
spidev->speed_hz = spidev->spi->max_speed_hz;
/* ... after we unbound from the underlying device? */
- spin_lock_irq(&spidev->spi_lock);
dofree = (spidev->spi == NULL);
spin_unlock_irq(&spidev->spi_lock);
diff --git a/drivers/staging/android/ion/ion_chunk_heap.c b/drivers/staging/android/ion/ion_chunk_heap.c
index 195c41d..0813163 100644
--- a/drivers/staging/android/ion/ion_chunk_heap.c
+++ b/drivers/staging/android/ion/ion_chunk_heap.c
@@ -81,7 +81,7 @@ static int ion_chunk_heap_allocate(struct ion_heap *heap,
err:
sg = table->sgl;
for (i -= 1; i >= 0; i--) {
- gen_pool_free(chunk_heap->pool, sg_phys(sg) & PAGE_MASK,
+ gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
sg->length);
sg = sg_next(sg);
}
@@ -109,7 +109,7 @@ static void ion_chunk_heap_free(struct ion_buffer *buffer)
DMA_BIDIRECTIONAL);
for_each_sg(table->sgl, sg, table->nents, i) {
- gen_pool_free(chunk_heap->pool, sg_phys(sg) & PAGE_MASK,
+ gen_pool_free(chunk_heap->pool, page_to_phys(sg_page(sg)),
sg->length);
}
chunk_heap->allocated -= allocated_size;
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 6d5b38d..9d7f000 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -18,7 +18,8 @@ source "drivers/staging/iio/resolver/Kconfig"
source "drivers/staging/iio/trigger/Kconfig"
config IIO_DUMMY_EVGEN
- tristate
+ tristate
+ select IRQ_WORK
config IIO_SIMPLE_DUMMY
tristate "An example driver with no hardware requirements"
diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c
index d11c54b..b51f237 100644
--- a/drivers/staging/iio/adc/lpc32xx_adc.c
+++ b/drivers/staging/iio/adc/lpc32xx_adc.c
@@ -76,7 +76,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
if (mask == IIO_CHAN_INFO_RAW) {
mutex_lock(&indio_dev->mlock);
- clk_enable(info->clk);
+ clk_prepare_enable(info->clk);
/* Measurement setup */
__raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm,
LPC32XX_ADC_SELECT(info->adc_base));
@@ -84,7 +84,7 @@ static int lpc32xx_read_raw(struct iio_dev *indio_dev,
__raw_writel(AD_PDN_CTRL | AD_STROBE,
LPC32XX_ADC_CTRL(info->adc_base));
wait_for_completion(&info->completion); /* set by ISR */
- clk_disable(info->clk);
+ clk_disable_unprepare(info->clk);
*val = info->value;
mutex_unlock(&indio_dev->mlock);
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index bfbf1c5..6eb600f 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -159,7 +159,7 @@ static irqreturn_t iio_simple_dummy_get_timestamp(int irq, void *private)
struct iio_dummy_state *st = iio_priv(indio_dev);
st->event_timestamp = iio_get_time_ns();
- return IRQ_HANDLED;
+ return IRQ_WAKE_THREAD;
}
/**
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
index f5d741f..485ab26 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_ioctl.h
@@ -110,7 +110,6 @@ struct libcfs_ioctl_handler {
#define IOC_LIBCFS_CLEAR_DEBUG _IOWR('e', 31, long)
#define IOC_LIBCFS_MARK_DEBUG _IOWR('e', 32, long)
#define IOC_LIBCFS_MEMHOG _IOWR('e', 36, long)
-#define IOC_LIBCFS_PING_TEST _IOWR('e', 37, long)
/* lnet ioctls */
#define IOC_LIBCFS_GET_NI _IOWR('e', 50, long)
#define IOC_LIBCFS_FAIL_NID _IOWR('e', 51, long)
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index 07a6859..e7c2b26 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -274,23 +274,6 @@ static int libcfs_ioctl_int(struct cfs_psdev_file *pfile, unsigned long cmd,
}
break;
- case IOC_LIBCFS_PING_TEST: {
- extern void (kping_client)(struct libcfs_ioctl_data *);
- void (*ping)(struct libcfs_ioctl_data *);
-
- CDEBUG(D_IOCTL, "doing %d pings to nid %s (%s)\n",
- data->ioc_count, libcfs_nid2str(data->ioc_nid),
- libcfs_nid2str(data->ioc_nid));
- ping = symbol_get(kping_client);
- if (!ping)
- CERROR("symbol_get failed\n");
- else {
- ping(data);
- symbol_put(kping_client);
- }
- return 0;
- }
-
default: {
struct libcfs_ioctl_handler *hand;
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 02f2759..31cd6b3 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -3139,7 +3139,7 @@ struct file_operations ll_file_operations_noflock = {
.lock = ll_file_noflock
};
-struct inode_operations ll_file_inode_operations = {
+const struct inode_operations ll_file_inode_operations = {
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 9096d31..6102b29 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -705,7 +705,7 @@ extern const struct address_space_operations ll_aops;
extern struct file_operations ll_file_operations;
extern struct file_operations ll_file_operations_flock;
extern struct file_operations ll_file_operations_noflock;
-extern struct inode_operations ll_file_inode_operations;
+extern const struct inode_operations ll_file_inode_operations;
int ll_have_md_lock(struct inode *inode, __u64 *bits,
ldlm_mode_t l_req_mode);
ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
@@ -805,7 +805,7 @@ struct inode *search_inode_for_lustre(struct super_block *sb,
const struct lu_fid *fid);
/* llite/symlink.c */
-extern struct inode_operations ll_fast_symlink_inode_operations;
+extern const struct inode_operations ll_fast_symlink_inode_operations;
/* llite/llite_close.c */
struct ll_close_queue {
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index e6974c3..fed50d5 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -333,7 +333,7 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req)
return count;
}
-static void loop_make_request(struct request_queue *q, struct bio *old_bio)
+static blk_qc_t loop_make_request(struct request_queue *q, struct bio *old_bio)
{
struct lloop_device *lo = q->queuedata;
int rw = bio_rw(old_bio);
@@ -364,9 +364,10 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio)
goto err;
}
loop_add_bio(lo, old_bio);
- return;
+ return BLK_QC_T_NONE;
err:
bio_io_error(old_bio);
+ return BLK_QC_T_NONE;
}
static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio)
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 2ca2200..64db5e8 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -126,9 +126,7 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash,
rc = cl_file_inode_init(inode, md);
}
if (rc != 0) {
- make_bad_inode(inode);
- unlock_new_inode(inode);
- iput(inode);
+ iget_failed(inode);
inode = ERR_PTR(rc);
} else
unlock_new_inode(inode);
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index 69b2036..2610348 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -118,12 +118,20 @@ failed:
return rc;
}
-static const char *ll_follow_link(struct dentry *dentry, void **cookie)
+static void ll_put_link(void *p)
+{
+ ptlrpc_req_finished(p);
+}
+
+static const char *ll_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(dentry);
struct ptlrpc_request *request = NULL;
int rc;
char *symname = NULL;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
CDEBUG(D_VFSTRACE, "VFS Op\n");
ll_inode_size_lock(inode);
@@ -135,22 +143,16 @@ static const char *ll_follow_link(struct dentry *dentry, void **cookie)
}
/* symname may contain a pointer to the request message buffer,
- * we delay request releasing until ll_put_link then.
+ * we delay request releasing then.
*/
- *cookie = request;
+ set_delayed_call(done, ll_put_link, request);
return symname;
}
-static void ll_put_link(struct inode *unused, void *cookie)
-{
- ptlrpc_req_finished(cookie);
-}
-
-struct inode_operations ll_fast_symlink_inode_operations = {
+const struct inode_operations ll_fast_symlink_inode_operations = {
.readlink = generic_readlink,
.setattr = ll_setattr,
- .follow_link = ll_follow_link,
- .put_link = ll_put_link,
+ .get_link = ll_get_link,
.getattr = ll_getattr,
.permission = ll_inode_permission,
.setxattr = ll_setxattr,
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 4b7eb33..660b8ac 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -60,10 +60,10 @@
static
int get_xattr_type(const char *name)
{
- if (!strcmp(name, POSIX_ACL_XATTR_ACCESS))
+ if (!strcmp(name, XATTR_NAME_POSIX_ACL_ACCESS))
return XATTR_ACL_ACCESS_T;
- if (!strcmp(name, POSIX_ACL_XATTR_DEFAULT))
+ if (!strcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT))
return XATTR_ACL_DEFAULT_T;
if (!strncmp(name, XATTR_USER_PREFIX,
diff --git a/drivers/staging/lustre/lustre/obdecho/echo_client.c b/drivers/staging/lustre/lustre/obdecho/echo_client.c
index f61ef66..a4a9a76 100644
--- a/drivers/staging/lustre/lustre/obdecho/echo_client.c
+++ b/drivers/staging/lustre/lustre/obdecho/echo_client.c
@@ -1270,6 +1270,7 @@ static int
echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
{
struct lov_stripe_md *ulsm = _ulsm;
+ struct lov_oinfo **p;
int nob, i;
nob = offsetof(struct lov_stripe_md, lsm_oinfo[lsm->lsm_stripe_count]);
@@ -1279,9 +1280,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
if (copy_to_user(ulsm, lsm, sizeof(*ulsm)))
return -EFAULT;
- for (i = 0; i < lsm->lsm_stripe_count; i++) {
- if (copy_to_user(ulsm->lsm_oinfo[i], lsm->lsm_oinfo[i],
- sizeof(lsm->lsm_oinfo[0])))
+ for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) {
+ struct lov_oinfo __user *up;
+ if (get_user(up, ulsm->lsm_oinfo + i) ||
+ copy_to_user(up, *p, sizeof(struct lov_oinfo)))
return -EFAULT;
}
return 0;
@@ -1289,9 +1291,10 @@ echo_copyout_lsm(struct lov_stripe_md *lsm, void *_ulsm, int ulsm_nob)
static int
echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm,
- void *ulsm, int ulsm_nob)
+ struct lov_stripe_md __user *ulsm, int ulsm_nob)
{
struct echo_client_obd *ec = ed->ed_ec;
+ struct lov_oinfo **p;
int i;
if (ulsm_nob < sizeof(*lsm))
@@ -1306,11 +1309,10 @@ echo_copyin_lsm(struct echo_device *ed, struct lov_stripe_md *lsm,
((__u64)lsm->lsm_stripe_size * lsm->lsm_stripe_count > ~0UL))
return -EINVAL;
- for (i = 0; i < lsm->lsm_stripe_count; i++) {
- if (copy_from_user(lsm->lsm_oinfo[i],
- ((struct lov_stripe_md *)ulsm)-> \
- lsm_oinfo[i],
- sizeof(lsm->lsm_oinfo[0])))
+ for (i = 0, p = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++, p++) {
+ struct lov_oinfo __user *up;
+ if (get_user(up, ulsm->lsm_oinfo + i) ||
+ copy_from_user(*p, up, sizeof(struct lov_oinfo)))
return -EFAULT;
}
return 0;
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index b10d601..93bffba 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -1000,8 +1000,8 @@ static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev,
timeout = BCM2048_AUTO_SEARCH_TIMEOUT;
if (!wait_for_completion_timeout(&bdev->compl,
- msecs_to_jiffies(timeout)))
- dev_err(&bdev->client->dev, "IRQ timeout.\n");
+ msecs_to_jiffies(timeout)))
+ dev_err(&bdev->client->dev, "IRQ timeout.\n");
if (value)
if (!bdev->scan_state)
diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig
index 4de2f08..f40a069 100644
--- a/drivers/staging/media/davinci_vpfe/Kconfig
+++ b/drivers/staging/media/davinci_vpfe/Kconfig
@@ -2,6 +2,8 @@ config VIDEO_DM365_VPFE
tristate "DM365 VPFE Media Controller Capture Driver"
depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF
depends on HAS_DMA
+ depends on VIDEO_V4L2_SUBDEV_API
+ depends on VIDEO_DAVINCI_VPBE_DISPLAY
select VIDEOBUF2_DMA_CONTIG
help
Support for DM365 VPFE based Media Controller Capture driver.
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index b1dfa2c..c492914 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -1536,8 +1536,9 @@ ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
* @fse: pointer to v4l2_subdev_frame_size_enum structure.
*/
static int
-ipipe_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg,
- struct v4l2_subdev_frame_size_enum *fse)
+ipipe_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_pad_config *cfg,
+ struct v4l2_subdev_frame_size_enum *fse)
{
struct vpfe_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt format;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
index 2a3a56b..b1d5e23 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
@@ -254,7 +254,7 @@ int config_ipipe_hw(struct vpfe_ipipe_device *ipipe)
void __iomem *ipipe_base = ipipe->base_addr;
struct v4l2_mbus_framefmt *outformat;
u32 color_pat;
- u32 ipipe_mode;
+ int ipipe_mode;
u32 data_path;
/* enable clock to IPIPE */
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index acb293e..d892fee 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -63,16 +63,11 @@ resizer_calculate_line_length(u32 pix, int width, int height,
if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
*line_len = width << 1;
- } else if (pix == MEDIA_BUS_FMT_Y8_1X8 ||
- pix == MEDIA_BUS_FMT_UV8_1X8) {
- *line_len = width;
- *line_len_c = width;
} else {
- /* YUV 420 */
- /* round width to upper 32 byte boundary */
*line_len = width;
*line_len_c = width;
}
+
/* adjust the line len to be a multiple of 32 */
*line_len += 31;
*line_len &= ~0x1f;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index 01df068..69b678c 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -227,7 +227,7 @@ static int vpfe_enable_clock(struct vpfe_device *vpfe_dev)
return 0;
vpfe_dev->clks = kcalloc(vpfe_cfg->num_clocks,
- sizeof(struct clock *), GFP_KERNEL);
+ sizeof(*vpfe_dev->clks), GFP_KERNEL);
if (vpfe_dev->clks == NULL)
return -ENOMEM;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 0fdff91..adb2bc8 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -470,7 +470,7 @@ void vpfe_video_process_buffer_complete(struct vpfe_video_device *video)
{
struct vpfe_pipeline *pipe = &video->pipe;
- v4l2_get_timestamp(&video->cur_frm->vb.timestamp);
+ video->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
vb2_buffer_done(&video->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
if (pipe->state == VPFE_PIPELINE_STREAM_CONTINUOUS)
video->cur_frm = video->next_frm;
@@ -1078,7 +1078,7 @@ vpfe_g_dv_timings(struct file *file, void *fh,
* the buffer nbuffers and buffer size
*/
static int
-vpfe_buffer_queue_setup(struct vb2_queue *vq, const void *parg,
+vpfe_buffer_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 534b810..ff1926c 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -885,12 +885,14 @@ static int imon_probe(struct usb_interface *interface,
vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum);
/* Everything went fine. Just unlock and return retval (with is 0) */
+ mutex_unlock(&context->ctx_lock);
goto driver_unlock;
unregister_lirc:
lirc_unregister_driver(driver->minor);
free_tx_urb:
+ mutex_unlock(&context->ctx_lock);
usb_free_urb(tx_urb);
free_rx_urb:
diff --git a/drivers/staging/media/lirc/lirc_parallel.c b/drivers/staging/media/lirc/lirc_parallel.c
index c140834..d009bcb 100644
--- a/drivers/staging/media/lirc/lirc_parallel.c
+++ b/drivers/staging/media/lirc/lirc_parallel.c
@@ -33,7 +33,7 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
-#include <linux/time.h>
+#include <linux/ktime.h>
#include <linux/mm.h>
#include <linux/delay.h>
@@ -144,25 +144,22 @@ static void lirc_off(void)
static unsigned int init_lirc_timer(void)
{
- struct timeval tv, now;
+ ktime_t kt, now, timeout;
unsigned int level, newlevel, timeelapsed, newtimer;
int count = 0;
- do_gettimeofday(&tv);
- tv.tv_sec++; /* wait max. 1 sec. */
+ kt = ktime_get();
+ /* wait max. 1 sec. */
+ timeout = ktime_add_ns(kt, NSEC_PER_SEC);
level = lirc_get_timer();
do {
newlevel = lirc_get_timer();
if (level == 0 && newlevel != 0)
count++;
level = newlevel;
- do_gettimeofday(&now);
- } while (count < 1000 && (now.tv_sec < tv.tv_sec
- || (now.tv_sec == tv.tv_sec
- && now.tv_usec < tv.tv_usec)));
-
- timeelapsed = (now.tv_sec + 1 - tv.tv_sec)*1000000
- + (now.tv_usec - tv.tv_usec);
+ now = ktime_get();
+ } while (count < 1000 && (ktime_before(now, timeout)));
+ timeelapsed = ktime_us_delta(now, kt);
if (count >= 1000 && timeelapsed > 0) {
if (default_timer == 0) {
/* autodetect timer */
@@ -220,8 +217,8 @@ static void rbuf_write(int signal)
static void lirc_lirc_irq_handler(void *blah)
{
- struct timeval tv;
- static struct timeval lasttv;
+ ktime_t kt, delkt;
+ static ktime_t lastkt;
static int init;
long signal;
int data;
@@ -244,16 +241,14 @@ static void lirc_lirc_irq_handler(void *blah)
#ifdef LIRC_TIMER
if (init) {
- do_gettimeofday(&tv);
+ kt = ktime_get();
- signal = tv.tv_sec - lasttv.tv_sec;
- if (signal > 15)
+ delkt = ktime_sub(kt, lastkt);
+ if (ktime_compare(delkt, ktime_set(15, 0)) > 0)
/* really long time */
data = PULSE_MASK;
else
- data = (int) (signal*1000000 +
- tv.tv_usec - lasttv.tv_usec +
- LIRC_SFH506_DELAY);
+ data = (int)(ktime_to_us(delkt) + LIRC_SFH506_DELAY);
rbuf_write(data); /* space */
} else {
@@ -301,7 +296,7 @@ static void lirc_lirc_irq_handler(void *blah)
data = 1;
rbuf_write(PULSE_BIT|data); /* pulse */
}
- do_gettimeofday(&lasttv);
+ lastkt = ktime_get();
#else
/* add your code here */
#endif
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index f2dca69..2218d00 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -42,6 +42,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
+#include <linux/ktime.h>
#include <media/lirc.h>
#include <media/lirc_dev.h>
@@ -111,7 +112,7 @@ struct sasem_context {
} tx;
/* for dealing with repeat codes (wish there was a toggle bit!) */
- struct timeval presstime;
+ ktime_t presstime;
char lastcode[8];
int codesaved;
};
@@ -566,8 +567,8 @@ static void incoming_packet(struct sasem_context *context,
{
int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer;
- long ms;
- struct timeval tv;
+ u64 ns;
+ ktime_t kt;
if (len != 8) {
dev_warn(&context->dev->dev,
@@ -584,9 +585,8 @@ static void incoming_packet(struct sasem_context *context,
*/
/* get the time since the last button press */
- do_gettimeofday(&tv);
- ms = (tv.tv_sec - context->presstime.tv_sec) * 1000 +
- (tv.tv_usec - context->presstime.tv_usec) / 1000;
+ kt = ktime_get();
+ ns = ktime_to_ns(ktime_sub(kt, context->presstime));
if (memcmp(buf, "\x08\0\0\0\0\0\0\0", 8) == 0) {
/*
@@ -600,10 +600,9 @@ static void incoming_packet(struct sasem_context *context,
* in that time and then get a false repeat of the previous
* press but it is long enough for a genuine repeat
*/
- if ((ms < 250) && (context->codesaved != 0)) {
+ if ((ns < 250 * NSEC_PER_MSEC) && (context->codesaved != 0)) {
memcpy(buf, &context->lastcode, 8);
- context->presstime.tv_sec = tv.tv_sec;
- context->presstime.tv_usec = tv.tv_usec;
+ context->presstime = kt;
}
} else {
/* save the current valid code for repeats */
@@ -613,8 +612,7 @@ static void incoming_packet(struct sasem_context *context,
* just for safety reasons
*/
context->codesaved = 1;
- context->presstime.tv_sec = tv.tv_sec;
- context->presstime.tv_usec = tv.tv_usec;
+ context->presstime = kt;
}
lirc_buffer_write(context->driver->rbuf, buf);
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
index 64a7b2f..b798b31 100644
--- a/drivers/staging/media/lirc/lirc_serial.c
+++ b/drivers/staging/media/lirc/lirc_serial.c
@@ -59,7 +59,7 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/serial_reg.h>
-#include <linux/time.h>
+#include <linux/ktime.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/wait.h>
@@ -204,7 +204,7 @@ static struct lirc_serial hardware[] = {
#define RBUF_LEN 256
-static struct timeval lasttv = {0, 0};
+static ktime_t lastkt;
static struct lirc_buffer rbuf;
@@ -542,10 +542,10 @@ static void frbwrite(int l)
static irqreturn_t lirc_irq_handler(int i, void *blah)
{
- struct timeval tv;
+ ktime_t kt;
int counter, dcd;
u8 status;
- long deltv;
+ ktime_t delkt;
int data;
static int last_dcd = -1;
@@ -565,7 +565,7 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
if ((status & hardware[type].signal_pin_change)
&& sense != -1) {
/* get current time */
- do_gettimeofday(&tv);
+ kt = ktime_get();
/* New mode, written by Trent Piepho
<xyzzy@u.washington.edu>. */
@@ -594,34 +594,20 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
dcd = (status & hardware[type].signal_pin) ? 1 : 0;
if (dcd == last_dcd) {
- pr_warn("ignoring spike: %d %d %lx %lx %lx %lx\n",
- dcd, sense,
- tv.tv_sec, lasttv.tv_sec,
- (unsigned long)tv.tv_usec,
- (unsigned long)lasttv.tv_usec);
+ pr_warn("ignoring spike: %d %d %llx %llx\n",
+ dcd, sense, ktime_to_us(kt),
+ ktime_to_us(lastkt));
continue;
}
- deltv = tv.tv_sec-lasttv.tv_sec;
- if (tv.tv_sec < lasttv.tv_sec ||
- (tv.tv_sec == lasttv.tv_sec &&
- tv.tv_usec < lasttv.tv_usec)) {
- pr_warn("AIEEEE: your clock just jumped backwards\n");
- pr_warn("%d %d %lx %lx %lx %lx\n",
- dcd, sense,
- tv.tv_sec, lasttv.tv_sec,
- (unsigned long)tv.tv_usec,
- (unsigned long)lasttv.tv_usec);
- data = PULSE_MASK;
- } else if (deltv > 15) {
+ delkt = ktime_sub(kt, lastkt);
+ if (ktime_compare(delkt, ktime_set(15, 0)) > 0) {
data = PULSE_MASK; /* really long time */
if (!(dcd^sense)) {
/* sanity check */
- pr_warn("AIEEEE: %d %d %lx %lx %lx %lx\n",
- dcd, sense,
- tv.tv_sec, lasttv.tv_sec,
- (unsigned long)tv.tv_usec,
- (unsigned long)lasttv.tv_usec);
+ pr_warn("AIEEEE: %d %d %llx %llx\n",
+ dcd, sense, ktime_to_us(kt),
+ ktime_to_us(lastkt));
/*
* detecting pulse while this
* MUST be a space!
@@ -629,11 +615,9 @@ static irqreturn_t lirc_irq_handler(int i, void *blah)
sense = sense ? 0 : 1;
}
} else
- data = (int) (deltv*1000000 +
- tv.tv_usec -
- lasttv.tv_usec);
+ data = (int) ktime_to_us(delkt);
frbwrite(dcd^sense ? data : (data|PULSE_BIT));
- lasttv = tv;
+ lastkt = kt;
last_dcd = dcd;
wake_up_interruptible(&rbuf.wait_poll);
}
@@ -790,7 +774,7 @@ static int set_use_inc(void *data)
unsigned long flags;
/* initialize timestamp */
- do_gettimeofday(&lasttv);
+ lastkt = ktime_get();
spin_lock_irqsave(&hardware[type].lock, flags);
@@ -979,7 +963,7 @@ static int lirc_serial_resume(struct platform_device *dev)
spin_lock_irqsave(&hardware[type].lock, flags);
/* Enable Interrupt */
- do_gettimeofday(&lasttv);
+ lastkt = ktime_get();
soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI);
off();
diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig
index 8d4e3bd..4618346 100644
--- a/drivers/staging/media/omap4iss/Kconfig
+++ b/drivers/staging/media/omap4iss/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_OMAP4
tristate "OMAP 4 Camera support"
- depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C && ARCH_OMAP4
depends on HAS_DMA
select MFD_SYSCON
select VIDEOBUF2_DMA_CONTIG
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index aa76ccd..e27a988 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -601,8 +601,8 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe,
subdev = media_entity_to_v4l2_subdev(entity);
ret = v4l2_subdev_call(subdev, video, s_stream, 0);
if (ret < 0) {
- dev_dbg(iss->dev, "%s: module stop timeout.\n",
- subdev->name);
+ dev_warn(iss->dev, "%s: module stop timeout.\n",
+ subdev->name);
/* If the entity failed to stopped, assume it has
* crashed. Mark it as such, the ISS will be reset when
* applications will release it.
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index 35df8b4..5929357 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -20,7 +20,7 @@
#include <linux/platform_device.h>
#include <linux/wait.h>
-#include <media/omap4iss.h>
+#include <linux/platform_data/media/omap4iss.h>
#include "iss_regs.h"
#include "iss_csiphy.h"
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index c6e6d47..b941035 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -674,6 +674,9 @@ static void csi2_isr_ctx(struct iss_csi2_device *csi2,
status = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n));
iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n), status);
+ if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+ return;
+
/* Propagate frame number */
if (status & CSI2_CTX_IRQ_FS) {
struct iss_pipeline *pipe =
@@ -776,9 +779,6 @@ void omap4iss_csi2_isr(struct iss_csi2_device *csi2)
pipe->error = true;
}
- if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
- return;
-
/* Successful cases */
if (csi2_irqstatus & CSI2_IRQ_CONTEXT0)
csi2_isr_ctx(csi2, &csi2->contexts[0]);
diff --git a/drivers/staging/media/omap4iss/iss_csiphy.h b/drivers/staging/media/omap4iss/iss_csiphy.h
index e9ca439..a0f2d97 100644
--- a/drivers/staging/media/omap4iss/iss_csiphy.h
+++ b/drivers/staging/media/omap4iss/iss_csiphy.h
@@ -14,7 +14,7 @@
#ifndef OMAP4_ISS_CSI_PHY_H
#define OMAP4_ISS_CSI_PHY_H
-#include <media/omap4iss.h>
+#include <linux/platform_data/media/omap4iss.h>
struct iss_csi2_device;
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index 9c8180b..108961e 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -158,8 +158,8 @@ static void resizer_set_outaddr(struct iss_resizer_device *resizer, u32 addr)
/* Program UV buffer address... Hardcoded to be contiguous! */
if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) &&
(outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) {
- u32 c_addr = addr + (resizer->video_out.bpl_value *
- (outformat->height - 1));
+ u32 c_addr = addr + resizer->video_out.bpl_value
+ * outformat->height;
/* Ensure Y_BAD_L[6:0] = C_BAD_L[6:0]*/
if ((c_addr ^ addr) & 0x7f) {
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 2a0158b..e9aeca0 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -287,7 +287,6 @@ iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh)
*/
static int iss_video_queue_setup(struct vb2_queue *vq,
- const void *parg,
unsigned int *count, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -434,7 +433,7 @@ struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
list_del(&buf->list);
spin_unlock_irqrestore(&video->qlock, flags);
- v4l2_get_timestamp(&buf->vb.timestamp);
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
/* Do frame number propagation only if this is the output video node.
* Frame number either comes from the CSI receivers or it gets
diff --git a/drivers/staging/wilc1000/coreconfigurator.c b/drivers/staging/wilc1000/coreconfigurator.c
index e10c6ff..9568bdb 100644
--- a/drivers/staging/wilc1000/coreconfigurator.c
+++ b/drivers/staging/wilc1000/coreconfigurator.c
@@ -13,12 +13,8 @@
#include "wilc_wlan.h"
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/etherdevice.h>
#define TAG_PARAM_OFFSET (MAC_HDR_LEN + TIME_STAMP_LEN + \
BEACON_INTERVAL_LEN + CAP_INFO_LEN)
-#define ADDR1 4
-#define ADDR2 10
-#define ADDR3 16
/* Basic Frame Type Codes (2-bit) */
enum basic_frame_type {
@@ -175,32 +171,38 @@ static inline u8 get_from_ds(u8 *header)
return ((header[1] & 0x02) >> 1);
}
+/* This function extracts the MAC Address in 'address1' field of the MAC */
+/* header and updates the MAC Address in the allocated 'addr' variable. */
+static inline void get_address1(u8 *pu8msa, u8 *addr)
+{
+ memcpy(addr, pu8msa + 4, 6);
+}
+
+/* This function extracts the MAC Address in 'address2' field of the MAC */
+/* header and updates the MAC Address in the allocated 'addr' variable. */
+static inline void get_address2(u8 *pu8msa, u8 *addr)
+{
+ memcpy(addr, pu8msa + 10, 6);
+}
+
+/* This function extracts the MAC Address in 'address3' field of the MAC */
+/* header and updates the MAC Address in the allocated 'addr' variable. */
+static inline void get_address3(u8 *pu8msa, u8 *addr)
+{
+ memcpy(addr, pu8msa + 16, 6);
+}
+
/* This function extracts the BSSID from the incoming WLAN packet based on */
-/* the 'from ds' bit, and updates the MAC Address in the allocated 'data' */
+/* the 'from ds' bit, and updates the MAC Address in the allocated 'addr' */
/* variable. */
static inline void get_BSSID(u8 *data, u8 *bssid)
{
if (get_from_ds(data) == 1)
- /*
- * Extract the MAC Address in 'address2' field of the MAC
- * header and update the MAC Address in the allocated 'data'
- * variable.
- */
- ether_addr_copy(data, bssid + ADDR2);
+ get_address2(data, bssid);
else if (get_to_ds(data) == 1)
- /*
- * Extract the MAC Address in 'address1' field of the MAC
- * header and update the MAC Address in the allocated 'data'
- * variable.
- */
- ether_addr_copy(data, bssid + ADDR1);
+ get_address1(data, bssid);
else
- /*
- * Extract the MAC Address in 'address3' field of the MAC
- * header and update the MAC Address in the allocated 'data'
- * variable.
- */
- ether_addr_copy(data, bssid + ADDR3);
+ get_address3(data, bssid);
}
/* This function extracts the SSID from a beacon/probe response frame */
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index 342a07c..72204fb 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4074,6 +4074,17 @@ reject:
return iscsit_add_reject(conn, ISCSI_REASON_BOOKMARK_NO_RESOURCES, buf);
}
+static bool iscsi_target_check_conn_state(struct iscsi_conn *conn)
+{
+ bool ret;
+
+ spin_lock_bh(&conn->state_lock);
+ ret = (conn->conn_state != TARG_CONN_STATE_LOGGED_IN);
+ spin_unlock_bh(&conn->state_lock);
+
+ return ret;
+}
+
int iscsi_target_rx_thread(void *arg)
{
int ret, rc;
@@ -4091,7 +4102,7 @@ int iscsi_target_rx_thread(void *arg)
* incoming iscsi/tcp socket I/O, and/or failing the connection.
*/
rc = wait_for_completion_interruptible(&conn->rx_login_comp);
- if (rc < 0)
+ if (rc < 0 || iscsi_target_check_conn_state(conn))
return 0;
if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) {
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index c7461d7..255204c 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -23,8 +23,6 @@
#include <linux/inet.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include <target/iscsi/iscsi_transport.h>
#include <target/iscsi/iscsi_target_core.h>
@@ -37,20 +35,17 @@
#include "iscsi_target.h"
#include <target/iscsi/iscsi_target_stat.h>
-struct lio_target_configfs_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(void *, char *);
- ssize_t (*store)(void *, const char *, size_t);
-};
/* Start items for lio_target_portal_cit */
-static ssize_t lio_target_np_show_sctp(
- struct se_tpg_np *se_tpg_np,
- char *page)
+static inline struct iscsi_tpg_np *to_iscsi_tpg_np(struct config_item *item)
+{
+ return container_of(to_tpg_np(item), struct iscsi_tpg_np, se_tpg_np);
+}
+
+static ssize_t lio_target_np_sctp_show(struct config_item *item, char *page)
{
- struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
- struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
struct iscsi_tpg_np *tpg_np_sctp;
ssize_t rb;
@@ -63,15 +58,12 @@ static ssize_t lio_target_np_show_sctp(
return rb;
}
-static ssize_t lio_target_np_store_sctp(
- struct se_tpg_np *se_tpg_np,
- const char *page,
- size_t count)
+static ssize_t lio_target_np_sctp_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
struct iscsi_np *np;
struct iscsi_portal_group *tpg;
- struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
- struct iscsi_tpg_np, se_tpg_np);
struct iscsi_tpg_np *tpg_np_sctp = NULL;
u32 op;
int ret;
@@ -119,14 +111,9 @@ out:
return -EINVAL;
}
-TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR);
-
-static ssize_t lio_target_np_show_iser(
- struct se_tpg_np *se_tpg_np,
- char *page)
+static ssize_t lio_target_np_iser_show(struct config_item *item, char *page)
{
- struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
- struct iscsi_tpg_np, se_tpg_np);
+ struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
struct iscsi_tpg_np *tpg_np_iser;
ssize_t rb;
@@ -139,15 +126,12 @@ static ssize_t lio_target_np_show_iser(
return rb;
}
-static ssize_t lio_target_np_store_iser(
- struct se_tpg_np *se_tpg_np,
- const char *page,
- size_t count)
+static ssize_t lio_target_np_iser_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct iscsi_tpg_np *tpg_np = to_iscsi_tpg_np(item);
struct iscsi_np *np;
struct iscsi_portal_group *tpg;
- struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np,
- struct iscsi_tpg_np, se_tpg_np);
struct iscsi_tpg_np *tpg_np_iser = NULL;
char *endptr;
u32 op;
@@ -198,11 +182,12 @@ out:
return rc;
}
-TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(lio_target_np_, sctp);
+CONFIGFS_ATTR(lio_target_np_, iser);
static struct configfs_attribute *lio_target_portal_attrs[] = {
- &lio_target_np_sctp.attr,
- &lio_target_np_iser.attr,
+ &lio_target_np_attr_sctp,
+ &lio_target_np_attr_iser,
NULL,
};
@@ -360,22 +345,21 @@ out:
/* Start items for lio_target_nacl_attrib_cit */
-#define DEF_NACL_ATTRIB(name) \
-static ssize_t iscsi_nacl_attrib_show_##name( \
- struct se_node_acl *se_nacl, \
- char *page) \
+#define ISCSI_NACL_ATTR(name) \
+static ssize_t iscsi_nacl_attrib_##name##_show(struct config_item *item,\
+ char *page) \
{ \
+ struct se_node_acl *se_nacl = attrib_to_nacl(item); \
struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
se_node_acl); \
\
return sprintf(page, "%u\n", nacl->node_attrib.name); \
} \
\
-static ssize_t iscsi_nacl_attrib_store_##name( \
- struct se_node_acl *se_nacl, \
- const char *page, \
- size_t count) \
+static ssize_t iscsi_nacl_attrib_##name##_store(struct config_item *item,\
+ const char *page, size_t count) \
{ \
+ struct se_node_acl *se_nacl = attrib_to_nacl(item); \
struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \
se_node_acl); \
u32 val; \
@@ -389,59 +373,28 @@ static ssize_t iscsi_nacl_attrib_store_##name( \
return ret; \
\
return count; \
-}
+} \
+ \
+CONFIGFS_ATTR(iscsi_nacl_attrib_, name)
-#define NACL_ATTR(_name, _mode) TF_NACL_ATTRIB_ATTR(iscsi, _name, _mode);
-/*
- * Define iscsi_node_attrib_s_dataout_timeout
- */
-DEF_NACL_ATTRIB(dataout_timeout);
-NACL_ATTR(dataout_timeout, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_dataout_timeout_retries
- */
-DEF_NACL_ATTRIB(dataout_timeout_retries);
-NACL_ATTR(dataout_timeout_retries, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_default_erl
- */
-DEF_NACL_ATTRIB(default_erl);
-NACL_ATTR(default_erl, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_nopin_timeout
- */
-DEF_NACL_ATTRIB(nopin_timeout);
-NACL_ATTR(nopin_timeout, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_nopin_response_timeout
- */
-DEF_NACL_ATTRIB(nopin_response_timeout);
-NACL_ATTR(nopin_response_timeout, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_random_datain_pdu_offsets
- */
-DEF_NACL_ATTRIB(random_datain_pdu_offsets);
-NACL_ATTR(random_datain_pdu_offsets, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_random_datain_seq_offsets
- */
-DEF_NACL_ATTRIB(random_datain_seq_offsets);
-NACL_ATTR(random_datain_seq_offsets, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_node_attrib_s_random_r2t_offsets
- */
-DEF_NACL_ATTRIB(random_r2t_offsets);
-NACL_ATTR(random_r2t_offsets, S_IRUGO | S_IWUSR);
+ISCSI_NACL_ATTR(dataout_timeout);
+ISCSI_NACL_ATTR(dataout_timeout_retries);
+ISCSI_NACL_ATTR(default_erl);
+ISCSI_NACL_ATTR(nopin_timeout);
+ISCSI_NACL_ATTR(nopin_response_timeout);
+ISCSI_NACL_ATTR(random_datain_pdu_offsets);
+ISCSI_NACL_ATTR(random_datain_seq_offsets);
+ISCSI_NACL_ATTR(random_r2t_offsets);
static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = {
- &iscsi_nacl_attrib_dataout_timeout.attr,
- &iscsi_nacl_attrib_dataout_timeout_retries.attr,
- &iscsi_nacl_attrib_default_erl.attr,
- &iscsi_nacl_attrib_nopin_timeout.attr,
- &iscsi_nacl_attrib_nopin_response_timeout.attr,
- &iscsi_nacl_attrib_random_datain_pdu_offsets.attr,
- &iscsi_nacl_attrib_random_datain_seq_offsets.attr,
- &iscsi_nacl_attrib_random_r2t_offsets.attr,
+ &iscsi_nacl_attrib_attr_dataout_timeout,
+ &iscsi_nacl_attrib_attr_dataout_timeout_retries,
+ &iscsi_nacl_attrib_attr_default_erl,
+ &iscsi_nacl_attrib_attr_nopin_timeout,
+ &iscsi_nacl_attrib_attr_nopin_response_timeout,
+ &iscsi_nacl_attrib_attr_random_datain_pdu_offsets,
+ &iscsi_nacl_attrib_attr_random_datain_seq_offsets,
+ &iscsi_nacl_attrib_attr_random_r2t_offsets,
NULL,
};
@@ -450,7 +403,7 @@ static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = {
/* Start items for lio_target_nacl_auth_cit */
#define __DEF_NACL_AUTH_STR(prefix, name, flags) \
-static ssize_t __iscsi_##prefix##_show_##name( \
+static ssize_t __iscsi_##prefix##_##name##_show( \
struct iscsi_node_acl *nacl, \
char *page) \
{ \
@@ -461,7 +414,7 @@ static ssize_t __iscsi_##prefix##_show_##name( \
return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \
} \
\
-static ssize_t __iscsi_##prefix##_store_##name( \
+static ssize_t __iscsi_##prefix##_##name##_store( \
struct iscsi_node_acl *nacl, \
const char *page, \
size_t count) \
@@ -487,8 +440,35 @@ static ssize_t __iscsi_##prefix##_store_##name( \
return count; \
}
+#define DEF_NACL_AUTH_STR(name, flags) \
+ __DEF_NACL_AUTH_STR(nacl_auth, name, flags) \
+static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \
+ char *page) \
+{ \
+ struct se_node_acl *nacl = auth_to_nacl(item); \
+ return __iscsi_nacl_auth_##name##_show(container_of(nacl, \
+ struct iscsi_node_acl, se_node_acl), page); \
+} \
+static ssize_t iscsi_nacl_auth_##name##_store(struct config_item *item, \
+ const char *page, size_t count) \
+{ \
+ struct se_node_acl *nacl = auth_to_nacl(item); \
+ return __iscsi_nacl_auth_##name##_store(container_of(nacl, \
+ struct iscsi_node_acl, se_node_acl), page, count); \
+} \
+ \
+CONFIGFS_ATTR(iscsi_nacl_auth_, name)
+
+/*
+ * One-way authentication userid
+ */
+DEF_NACL_AUTH_STR(userid, NAF_USERID_SET);
+DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET);
+DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+
#define __DEF_NACL_AUTH_INT(prefix, name) \
-static ssize_t __iscsi_##prefix##_show_##name( \
+static ssize_t __iscsi_##prefix##_##name##_show( \
struct iscsi_node_acl *nacl, \
char *page) \
{ \
@@ -500,69 +480,26 @@ static ssize_t __iscsi_##prefix##_show_##name( \
return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \
}
-#define DEF_NACL_AUTH_STR(name, flags) \
- __DEF_NACL_AUTH_STR(nacl_auth, name, flags) \
-static ssize_t iscsi_nacl_auth_show_##name( \
- struct se_node_acl *nacl, \
- char *page) \
-{ \
- return __iscsi_nacl_auth_show_##name(container_of(nacl, \
- struct iscsi_node_acl, se_node_acl), page); \
-} \
-static ssize_t iscsi_nacl_auth_store_##name( \
- struct se_node_acl *nacl, \
- const char *page, \
- size_t count) \
-{ \
- return __iscsi_nacl_auth_store_##name(container_of(nacl, \
- struct iscsi_node_acl, se_node_acl), page, count); \
-}
-
#define DEF_NACL_AUTH_INT(name) \
__DEF_NACL_AUTH_INT(nacl_auth, name) \
-static ssize_t iscsi_nacl_auth_show_##name( \
- struct se_node_acl *nacl, \
- char *page) \
+static ssize_t iscsi_nacl_auth_##name##_show(struct config_item *item, \
+ char *page) \
{ \
- return __iscsi_nacl_auth_show_##name(container_of(nacl, \
- struct iscsi_node_acl, se_node_acl), page); \
-}
-
-#define AUTH_ATTR(_name, _mode) TF_NACL_AUTH_ATTR(iscsi, _name, _mode);
-#define AUTH_ATTR_RO(_name) TF_NACL_AUTH_ATTR_RO(iscsi, _name);
+ struct se_node_acl *nacl = auth_to_nacl(item); \
+ return __iscsi_nacl_auth_##name##_show(container_of(nacl, \
+ struct iscsi_node_acl, se_node_acl), page); \
+} \
+ \
+CONFIGFS_ATTR_RO(iscsi_nacl_auth_, name)
-/*
- * One-way authentication userid
- */
-DEF_NACL_AUTH_STR(userid, NAF_USERID_SET);
-AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
-/*
- * One-way authentication password
- */
-DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET);
-AUTH_ATTR(password, S_IRUGO | S_IWUSR);
-/*
- * Enforce mutual authentication
- */
DEF_NACL_AUTH_INT(authenticate_target);
-AUTH_ATTR_RO(authenticate_target);
-/*
- * Mutual authentication userid
- */
-DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
-AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
-/*
- * Mutual authentication password
- */
-DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
-AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
static struct configfs_attribute *lio_target_nacl_auth_attrs[] = {
- &iscsi_nacl_auth_userid.attr,
- &iscsi_nacl_auth_password.attr,
- &iscsi_nacl_auth_authenticate_target.attr,
- &iscsi_nacl_auth_userid_mutual.attr,
- &iscsi_nacl_auth_password_mutual.attr,
+ &iscsi_nacl_auth_attr_userid,
+ &iscsi_nacl_auth_attr_password,
+ &iscsi_nacl_auth_attr_authenticate_target,
+ &iscsi_nacl_auth_attr_userid_mutual,
+ &iscsi_nacl_auth_attr_password_mutual,
NULL,
};
@@ -570,11 +507,11 @@ static struct configfs_attribute *lio_target_nacl_auth_attrs[] = {
/* Start items for lio_target_nacl_param_cit */
-#define DEF_NACL_PARAM(name) \
-static ssize_t iscsi_nacl_param_show_##name( \
- struct se_node_acl *se_nacl, \
- char *page) \
+#define ISCSI_NACL_PARAM(name) \
+static ssize_t iscsi_nacl_param_##name##_show(struct config_item *item, \
+ char *page) \
{ \
+ struct se_node_acl *se_nacl = param_to_nacl(item); \
struct iscsi_session *sess; \
struct se_session *se_sess; \
ssize_t rb; \
@@ -592,55 +529,34 @@ static ssize_t iscsi_nacl_param_show_##name( \
spin_unlock_bh(&se_nacl->nacl_sess_lock); \
\
return rb; \
-}
-
-#define NACL_PARAM_ATTR(_name) TF_NACL_PARAM_ATTR_RO(iscsi, _name);
-
-DEF_NACL_PARAM(MaxConnections);
-NACL_PARAM_ATTR(MaxConnections);
-
-DEF_NACL_PARAM(InitialR2T);
-NACL_PARAM_ATTR(InitialR2T);
-
-DEF_NACL_PARAM(ImmediateData);
-NACL_PARAM_ATTR(ImmediateData);
-
-DEF_NACL_PARAM(MaxBurstLength);
-NACL_PARAM_ATTR(MaxBurstLength);
-
-DEF_NACL_PARAM(FirstBurstLength);
-NACL_PARAM_ATTR(FirstBurstLength);
-
-DEF_NACL_PARAM(DefaultTime2Wait);
-NACL_PARAM_ATTR(DefaultTime2Wait);
-
-DEF_NACL_PARAM(DefaultTime2Retain);
-NACL_PARAM_ATTR(DefaultTime2Retain);
-
-DEF_NACL_PARAM(MaxOutstandingR2T);
-NACL_PARAM_ATTR(MaxOutstandingR2T);
-
-DEF_NACL_PARAM(DataPDUInOrder);
-NACL_PARAM_ATTR(DataPDUInOrder);
-
-DEF_NACL_PARAM(DataSequenceInOrder);
-NACL_PARAM_ATTR(DataSequenceInOrder);
-
-DEF_NACL_PARAM(ErrorRecoveryLevel);
-NACL_PARAM_ATTR(ErrorRecoveryLevel);
+} \
+ \
+CONFIGFS_ATTR_RO(iscsi_nacl_param_, name)
+
+ISCSI_NACL_PARAM(MaxConnections);
+ISCSI_NACL_PARAM(InitialR2T);
+ISCSI_NACL_PARAM(ImmediateData);
+ISCSI_NACL_PARAM(MaxBurstLength);
+ISCSI_NACL_PARAM(FirstBurstLength);
+ISCSI_NACL_PARAM(DefaultTime2Wait);
+ISCSI_NACL_PARAM(DefaultTime2Retain);
+ISCSI_NACL_PARAM(MaxOutstandingR2T);
+ISCSI_NACL_PARAM(DataPDUInOrder);
+ISCSI_NACL_PARAM(DataSequenceInOrder);
+ISCSI_NACL_PARAM(ErrorRecoveryLevel);
static struct configfs_attribute *lio_target_nacl_param_attrs[] = {
- &iscsi_nacl_param_MaxConnections.attr,
- &iscsi_nacl_param_InitialR2T.attr,
- &iscsi_nacl_param_ImmediateData.attr,
- &iscsi_nacl_param_MaxBurstLength.attr,
- &iscsi_nacl_param_FirstBurstLength.attr,
- &iscsi_nacl_param_DefaultTime2Wait.attr,
- &iscsi_nacl_param_DefaultTime2Retain.attr,
- &iscsi_nacl_param_MaxOutstandingR2T.attr,
- &iscsi_nacl_param_DataPDUInOrder.attr,
- &iscsi_nacl_param_DataSequenceInOrder.attr,
- &iscsi_nacl_param_ErrorRecoveryLevel.attr,
+ &iscsi_nacl_param_attr_MaxConnections,
+ &iscsi_nacl_param_attr_InitialR2T,
+ &iscsi_nacl_param_attr_ImmediateData,
+ &iscsi_nacl_param_attr_MaxBurstLength,
+ &iscsi_nacl_param_attr_FirstBurstLength,
+ &iscsi_nacl_param_attr_DefaultTime2Wait,
+ &iscsi_nacl_param_attr_DefaultTime2Retain,
+ &iscsi_nacl_param_attr_MaxOutstandingR2T,
+ &iscsi_nacl_param_attr_DataPDUInOrder,
+ &iscsi_nacl_param_attr_DataSequenceInOrder,
+ &iscsi_nacl_param_attr_ErrorRecoveryLevel,
NULL,
};
@@ -648,10 +564,9 @@ static struct configfs_attribute *lio_target_nacl_param_attrs[] = {
/* Start items for lio_target_acl_cit */
-static ssize_t lio_target_nacl_show_info(
- struct se_node_acl *se_nacl,
- char *page)
+static ssize_t lio_target_nacl_info_show(struct config_item *item, char *page)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct iscsi_session *sess;
struct iscsi_conn *conn;
struct se_session *se_sess;
@@ -766,20 +681,16 @@ static ssize_t lio_target_nacl_show_info(
return rb;
}
-TF_NACL_BASE_ATTR_RO(lio_target, info);
-
-static ssize_t lio_target_nacl_show_cmdsn_depth(
- struct se_node_acl *se_nacl,
- char *page)
+static ssize_t lio_target_nacl_cmdsn_depth_show(struct config_item *item,
+ char *page)
{
- return sprintf(page, "%u\n", se_nacl->queue_depth);
+ return sprintf(page, "%u\n", acl_to_nacl(item)->queue_depth);
}
-static ssize_t lio_target_nacl_store_cmdsn_depth(
- struct se_node_acl *se_nacl,
- const char *page,
- size_t count)
+static ssize_t lio_target_nacl_cmdsn_depth_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct se_portal_group *se_tpg = se_nacl->se_tpg;
struct iscsi_portal_group *tpg = container_of(se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
@@ -829,20 +740,15 @@ static ssize_t lio_target_nacl_store_cmdsn_depth(
return (!ret) ? count : (ssize_t)ret;
}
-TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR);
-
-static ssize_t lio_target_nacl_show_tag(
- struct se_node_acl *se_nacl,
- char *page)
+static ssize_t lio_target_nacl_tag_show(struct config_item *item, char *page)
{
- return snprintf(page, PAGE_SIZE, "%s", se_nacl->acl_tag);
+ return snprintf(page, PAGE_SIZE, "%s", acl_to_nacl(item)->acl_tag);
}
-static ssize_t lio_target_nacl_store_tag(
- struct se_node_acl *se_nacl,
- const char *page,
- size_t count)
+static ssize_t lio_target_nacl_tag_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
int ret;
ret = core_tpg_set_initiator_node_tag(se_nacl->se_tpg, se_nacl, page);
@@ -852,12 +758,14 @@ static ssize_t lio_target_nacl_store_tag(
return count;
}
-TF_NACL_BASE_ATTR(lio_target, tag, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR_RO(lio_target_nacl_, info);
+CONFIGFS_ATTR(lio_target_nacl_, cmdsn_depth);
+CONFIGFS_ATTR(lio_target_nacl_, tag);
static struct configfs_attribute *lio_target_initiator_attrs[] = {
- &lio_target_nacl_info.attr,
- &lio_target_nacl_cmdsn_depth.attr,
- &lio_target_nacl_tag.attr,
+ &lio_target_nacl_attr_info,
+ &lio_target_nacl_attr_cmdsn_depth,
+ &lio_target_nacl_attr_tag,
NULL,
};
@@ -907,10 +815,10 @@ static void lio_target_cleanup_nodeacl( struct se_node_acl *se_nacl)
#define DEF_TPG_ATTRIB(name) \
\
-static ssize_t iscsi_tpg_attrib_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t iscsi_tpg_attrib_##name##_show(struct config_item *item, \
+ char *page) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
ssize_t rb; \
@@ -923,11 +831,10 @@ static ssize_t iscsi_tpg_attrib_show_##name( \
return rb; \
} \
\
-static ssize_t iscsi_tpg_attrib_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
+static ssize_t iscsi_tpg_attrib_##name##_store(struct config_item *item,\
+ const char *page, size_t count) \
{ \
+ struct se_portal_group *se_tpg = attrib_to_tpg(item); \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
u32 val; \
@@ -948,90 +855,37 @@ static ssize_t iscsi_tpg_attrib_store_##name( \
out: \
iscsit_put_tpg(tpg); \
return ret; \
-}
-
-#define TPG_ATTR(_name, _mode) TF_TPG_ATTRIB_ATTR(iscsi, _name, _mode);
+} \
+CONFIGFS_ATTR(iscsi_tpg_attrib_, name)
-/*
- * Define iscsi_tpg_attrib_s_authentication
- */
DEF_TPG_ATTRIB(authentication);
-TPG_ATTR(authentication, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_login_timeout
- */
DEF_TPG_ATTRIB(login_timeout);
-TPG_ATTR(login_timeout, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_netif_timeout
- */
DEF_TPG_ATTRIB(netif_timeout);
-TPG_ATTR(netif_timeout, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_generate_node_acls
- */
DEF_TPG_ATTRIB(generate_node_acls);
-TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_default_cmdsn_depth
- */
DEF_TPG_ATTRIB(default_cmdsn_depth);
-TPG_ATTR(default_cmdsn_depth, S_IRUGO | S_IWUSR);
-/*
- Define iscsi_tpg_attrib_s_cache_dynamic_acls
- */
DEF_TPG_ATTRIB(cache_dynamic_acls);
-TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_demo_mode_write_protect
- */
DEF_TPG_ATTRIB(demo_mode_write_protect);
-TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_prod_mode_write_protect
- */
DEF_TPG_ATTRIB(prod_mode_write_protect);
-TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_demo_mode_discovery,
- */
DEF_TPG_ATTRIB(demo_mode_discovery);
-TPG_ATTR(demo_mode_discovery, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_default_erl
- */
DEF_TPG_ATTRIB(default_erl);
-TPG_ATTR(default_erl, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_t10_pi
- */
DEF_TPG_ATTRIB(t10_pi);
-TPG_ATTR(t10_pi, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_fabric_prot_type
- */
DEF_TPG_ATTRIB(fabric_prot_type);
-TPG_ATTR(fabric_prot_type, S_IRUGO | S_IWUSR);
-/*
- * Define iscsi_tpg_attrib_s_tpg_enabled_sendtargets
- */
DEF_TPG_ATTRIB(tpg_enabled_sendtargets);
-TPG_ATTR(tpg_enabled_sendtargets, S_IRUGO | S_IWUSR);
static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
- &iscsi_tpg_attrib_authentication.attr,
- &iscsi_tpg_attrib_login_timeout.attr,
- &iscsi_tpg_attrib_netif_timeout.attr,
- &iscsi_tpg_attrib_generate_node_acls.attr,
- &iscsi_tpg_attrib_default_cmdsn_depth.attr,
- &iscsi_tpg_attrib_cache_dynamic_acls.attr,
- &iscsi_tpg_attrib_demo_mode_write_protect.attr,
- &iscsi_tpg_attrib_prod_mode_write_protect.attr,
- &iscsi_tpg_attrib_demo_mode_discovery.attr,
- &iscsi_tpg_attrib_default_erl.attr,
- &iscsi_tpg_attrib_t10_pi.attr,
- &iscsi_tpg_attrib_fabric_prot_type.attr,
- &iscsi_tpg_attrib_tpg_enabled_sendtargets.attr,
+ &iscsi_tpg_attrib_attr_authentication,
+ &iscsi_tpg_attrib_attr_login_timeout,
+ &iscsi_tpg_attrib_attr_netif_timeout,
+ &iscsi_tpg_attrib_attr_generate_node_acls,
+ &iscsi_tpg_attrib_attr_default_cmdsn_depth,
+ &iscsi_tpg_attrib_attr_cache_dynamic_acls,
+ &iscsi_tpg_attrib_attr_demo_mode_write_protect,
+ &iscsi_tpg_attrib_attr_prod_mode_write_protect,
+ &iscsi_tpg_attrib_attr_demo_mode_discovery,
+ &iscsi_tpg_attrib_attr_default_erl,
+ &iscsi_tpg_attrib_attr_t10_pi,
+ &iscsi_tpg_attrib_attr_fabric_prot_type,
+ &iscsi_tpg_attrib_attr_tpg_enabled_sendtargets,
NULL,
};
@@ -1040,9 +894,8 @@ static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = {
/* Start items for lio_target_tpg_auth_cit */
#define __DEF_TPG_AUTH_STR(prefix, name, flags) \
-static ssize_t __iscsi_##prefix##_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \
+ char *page) \
{ \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
@@ -1054,10 +907,8 @@ static ssize_t __iscsi_##prefix##_show_##name( \
return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \
} \
\
-static ssize_t __iscsi_##prefix##_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
+static ssize_t __iscsi_##prefix##_##name##_store(struct se_portal_group *se_tpg,\
+ const char *page, size_t count) \
{ \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
@@ -1081,10 +932,31 @@ static ssize_t __iscsi_##prefix##_store_##name( \
return count; \
}
+#define DEF_TPG_AUTH_STR(name, flags) \
+ __DEF_TPG_AUTH_STR(tpg_auth, name, flags) \
+static ssize_t iscsi_tpg_auth_##name##_show(struct config_item *item, \
+ char *page) \
+{ \
+ return __iscsi_tpg_auth_##name##_show(auth_to_tpg(item), page); \
+} \
+ \
+static ssize_t iscsi_tpg_auth_##name##_store(struct config_item *item, \
+ const char *page, size_t count) \
+{ \
+ return __iscsi_tpg_auth_##name##_store(auth_to_tpg(item), page, count); \
+} \
+ \
+CONFIGFS_ATTR(iscsi_tpg_auth_, name);
+
+
+DEF_TPG_AUTH_STR(userid, NAF_USERID_SET);
+DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET);
+DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
+
#define __DEF_TPG_AUTH_INT(prefix, name) \
-static ssize_t __iscsi_##prefix##_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t __iscsi_##prefix##_##name##_show(struct se_portal_group *se_tpg, \
+ char *page) \
{ \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
@@ -1096,67 +968,23 @@ static ssize_t __iscsi_##prefix##_show_##name( \
return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \
}
-#define DEF_TPG_AUTH_STR(name, flags) \
- __DEF_TPG_AUTH_STR(tpg_auth, name, flags) \
-static ssize_t iscsi_tpg_auth_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
-{ \
- return __iscsi_tpg_auth_show_##name(se_tpg, page); \
-} \
- \
-static ssize_t iscsi_tpg_auth_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
-{ \
- return __iscsi_tpg_auth_store_##name(se_tpg, page, count); \
-}
-
#define DEF_TPG_AUTH_INT(name) \
__DEF_TPG_AUTH_INT(tpg_auth, name) \
-static ssize_t iscsi_tpg_auth_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t iscsi_tpg_auth_##name##_show(struct config_item *item, \
+ char *page) \
{ \
- return __iscsi_tpg_auth_show_##name(se_tpg, page); \
-}
-
-#define TPG_AUTH_ATTR(_name, _mode) TF_TPG_AUTH_ATTR(iscsi, _name, _mode);
-#define TPG_AUTH_ATTR_RO(_name) TF_TPG_AUTH_ATTR_RO(iscsi, _name);
+ return __iscsi_tpg_auth_##name##_show(auth_to_tpg(item), page); \
+} \
+CONFIGFS_ATTR_RO(iscsi_tpg_auth_, name);
-/*
- * * One-way authentication userid
- * */
-DEF_TPG_AUTH_STR(userid, NAF_USERID_SET);
-TPG_AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
-/*
- * * One-way authentication password
- * */
-DEF_TPG_AUTH_STR(password, NAF_PASSWORD_SET);
-TPG_AUTH_ATTR(password, S_IRUGO | S_IWUSR);
-/*
- * * Enforce mutual authentication
- * */
DEF_TPG_AUTH_INT(authenticate_target);
-TPG_AUTH_ATTR_RO(authenticate_target);
-/*
- * * Mutual authentication userid
- * */
-DEF_TPG_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
-TPG_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
-/*
- * * Mutual authentication password
- * */
-DEF_TPG_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
-TPG_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
static struct configfs_attribute *lio_target_tpg_auth_attrs[] = {
- &iscsi_tpg_auth_userid.attr,
- &iscsi_tpg_auth_password.attr,
- &iscsi_tpg_auth_authenticate_target.attr,
- &iscsi_tpg_auth_userid_mutual.attr,
- &iscsi_tpg_auth_password_mutual.attr,
+ &iscsi_tpg_auth_attr_userid,
+ &iscsi_tpg_auth_attr_password,
+ &iscsi_tpg_auth_attr_authenticate_target,
+ &iscsi_tpg_auth_attr_userid_mutual,
+ &iscsi_tpg_auth_attr_password_mutual,
NULL,
};
@@ -1165,10 +993,10 @@ static struct configfs_attribute *lio_target_tpg_auth_attrs[] = {
/* Start items for lio_target_tpg_param_cit */
#define DEF_TPG_PARAM(name) \
-static ssize_t iscsi_tpg_param_show_##name( \
- struct se_portal_group *se_tpg, \
- char *page) \
+static ssize_t iscsi_tpg_param_##name##_show(struct config_item *item, \
+ char *page) \
{ \
+ struct se_portal_group *se_tpg = param_to_tpg(item); \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
struct iscsi_param *param; \
@@ -1188,11 +1016,10 @@ static ssize_t iscsi_tpg_param_show_##name( \
iscsit_put_tpg(tpg); \
return rb; \
} \
-static ssize_t iscsi_tpg_param_store_##name( \
- struct se_portal_group *se_tpg, \
- const char *page, \
- size_t count) \
+static ssize_t iscsi_tpg_param_##name##_store(struct config_item *item, \
+ const char *page, size_t count) \
{ \
+ struct se_portal_group *se_tpg = param_to_tpg(item); \
struct iscsi_portal_group *tpg = container_of(se_tpg, \
struct iscsi_portal_group, tpg_se_tpg); \
char *buf; \
@@ -1220,96 +1047,54 @@ static ssize_t iscsi_tpg_param_store_##name( \
out: \
kfree(buf); \
iscsit_put_tpg(tpg); \
- return -EINVAL; \
-}
-
-#define TPG_PARAM_ATTR(_name, _mode) TF_TPG_PARAM_ATTR(iscsi, _name, _mode);
+ return -EINVAL; \
+} \
+CONFIGFS_ATTR(iscsi_tpg_param_, name)
DEF_TPG_PARAM(AuthMethod);
-TPG_PARAM_ATTR(AuthMethod, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(HeaderDigest);
-TPG_PARAM_ATTR(HeaderDigest, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(DataDigest);
-TPG_PARAM_ATTR(DataDigest, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(MaxConnections);
-TPG_PARAM_ATTR(MaxConnections, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(TargetAlias);
-TPG_PARAM_ATTR(TargetAlias, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(InitialR2T);
-TPG_PARAM_ATTR(InitialR2T, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(ImmediateData);
-TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(MaxRecvDataSegmentLength);
-TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(MaxXmitDataSegmentLength);
-TPG_PARAM_ATTR(MaxXmitDataSegmentLength, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(MaxBurstLength);
-TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(FirstBurstLength);
-TPG_PARAM_ATTR(FirstBurstLength, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(DefaultTime2Wait);
-TPG_PARAM_ATTR(DefaultTime2Wait, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(DefaultTime2Retain);
-TPG_PARAM_ATTR(DefaultTime2Retain, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(MaxOutstandingR2T);
-TPG_PARAM_ATTR(MaxOutstandingR2T, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(DataPDUInOrder);
-TPG_PARAM_ATTR(DataPDUInOrder, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(DataSequenceInOrder);
-TPG_PARAM_ATTR(DataSequenceInOrder, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(ErrorRecoveryLevel);
-TPG_PARAM_ATTR(ErrorRecoveryLevel, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(IFMarker);
-TPG_PARAM_ATTR(IFMarker, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(OFMarker);
-TPG_PARAM_ATTR(OFMarker, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(IFMarkInt);
-TPG_PARAM_ATTR(IFMarkInt, S_IRUGO | S_IWUSR);
-
DEF_TPG_PARAM(OFMarkInt);
-TPG_PARAM_ATTR(OFMarkInt, S_IRUGO | S_IWUSR);
static struct configfs_attribute *lio_target_tpg_param_attrs[] = {
- &iscsi_tpg_param_AuthMethod.attr,
- &iscsi_tpg_param_HeaderDigest.attr,
- &iscsi_tpg_param_DataDigest.attr,
- &iscsi_tpg_param_MaxConnections.attr,
- &iscsi_tpg_param_TargetAlias.attr,
- &iscsi_tpg_param_InitialR2T.attr,
- &iscsi_tpg_param_ImmediateData.attr,
- &iscsi_tpg_param_MaxRecvDataSegmentLength.attr,
- &iscsi_tpg_param_MaxXmitDataSegmentLength.attr,
- &iscsi_tpg_param_MaxBurstLength.attr,
- &iscsi_tpg_param_FirstBurstLength.attr,
- &iscsi_tpg_param_DefaultTime2Wait.attr,
- &iscsi_tpg_param_DefaultTime2Retain.attr,
- &iscsi_tpg_param_MaxOutstandingR2T.attr,
- &iscsi_tpg_param_DataPDUInOrder.attr,
- &iscsi_tpg_param_DataSequenceInOrder.attr,
- &iscsi_tpg_param_ErrorRecoveryLevel.attr,
- &iscsi_tpg_param_IFMarker.attr,
- &iscsi_tpg_param_OFMarker.attr,
- &iscsi_tpg_param_IFMarkInt.attr,
- &iscsi_tpg_param_OFMarkInt.attr,
+ &iscsi_tpg_param_attr_AuthMethod,
+ &iscsi_tpg_param_attr_HeaderDigest,
+ &iscsi_tpg_param_attr_DataDigest,
+ &iscsi_tpg_param_attr_MaxConnections,
+ &iscsi_tpg_param_attr_TargetAlias,
+ &iscsi_tpg_param_attr_InitialR2T,
+ &iscsi_tpg_param_attr_ImmediateData,
+ &iscsi_tpg_param_attr_MaxRecvDataSegmentLength,
+ &iscsi_tpg_param_attr_MaxXmitDataSegmentLength,
+ &iscsi_tpg_param_attr_MaxBurstLength,
+ &iscsi_tpg_param_attr_FirstBurstLength,
+ &iscsi_tpg_param_attr_DefaultTime2Wait,
+ &iscsi_tpg_param_attr_DefaultTime2Retain,
+ &iscsi_tpg_param_attr_MaxOutstandingR2T,
+ &iscsi_tpg_param_attr_DataPDUInOrder,
+ &iscsi_tpg_param_attr_DataSequenceInOrder,
+ &iscsi_tpg_param_attr_ErrorRecoveryLevel,
+ &iscsi_tpg_param_attr_IFMarker,
+ &iscsi_tpg_param_attr_OFMarker,
+ &iscsi_tpg_param_attr_IFMarkInt,
+ &iscsi_tpg_param_attr_OFMarkInt,
NULL,
};
@@ -1317,10 +1102,9 @@ static struct configfs_attribute *lio_target_tpg_param_attrs[] = {
/* Start items for lio_target_tpg_cit */
-static ssize_t lio_target_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t lio_target_tpg_enable_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct iscsi_portal_group *tpg = container_of(se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
ssize_t len;
@@ -1333,11 +1117,10 @@ static ssize_t lio_target_tpg_show_enable(
return len;
}
-static ssize_t lio_target_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t lio_target_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct iscsi_portal_group *tpg = container_of(se_tpg,
struct iscsi_portal_group, tpg_se_tpg);
u32 op;
@@ -1375,20 +1158,19 @@ out:
return -EINVAL;
}
-TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR);
-static ssize_t lio_target_tpg_show_dynamic_sessions(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t lio_target_tpg_dynamic_sessions_show(struct config_item *item,
+ char *page)
{
- return target_show_dynamic_sessions(se_tpg, page);
+ return target_show_dynamic_sessions(to_tpg(item), page);
}
-TF_TPG_BASE_ATTR_RO(lio_target, dynamic_sessions);
+CONFIGFS_ATTR(lio_target_tpg_, enable);
+CONFIGFS_ATTR_RO(lio_target_tpg_, dynamic_sessions);
static struct configfs_attribute *lio_target_tpg_attrs[] = {
- &lio_target_tpg_enable.attr,
- &lio_target_tpg_dynamic_sessions.attr,
+ &lio_target_tpg_attr_enable,
+ &lio_target_tpg_attr_dynamic_sessions,
NULL,
};
@@ -1463,17 +1245,16 @@ static void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg)
/* Start LIO-Target TIQN struct contig_item lio_target_cit */
-static ssize_t lio_target_wwn_show_attr_lio_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t lio_target_wwn_lio_version_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "Datera Inc. iSCSI Target "ISCSIT_VERSION"\n");
}
-TF_WWN_ATTR_RO(lio_target, lio_version);
+CONFIGFS_ATTR_RO(lio_target_wwn_, lio_version);
static struct configfs_attribute *lio_target_wwn_attrs[] = {
- &lio_target_wwn_lio_version.attr,
+ &lio_target_wwn_attr_lio_version,
NULL,
};
@@ -1552,77 +1333,47 @@ static void lio_target_call_coredeltiqn(
#define DEF_DISC_AUTH_STR(name, flags) \
__DEF_NACL_AUTH_STR(disc, name, flags) \
-static ssize_t iscsi_disc_show_##name( \
- struct target_fabric_configfs *tf, \
- char *page) \
+static ssize_t iscsi_disc_##name##_show(struct config_item *item, char *page) \
{ \
- return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \
+ return __iscsi_disc_##name##_show(&iscsit_global->discovery_acl,\
page); \
} \
-static ssize_t iscsi_disc_store_##name( \
- struct target_fabric_configfs *tf, \
- const char *page, \
- size_t count) \
+static ssize_t iscsi_disc_##name##_store(struct config_item *item, \
+ const char *page, size_t count) \
{ \
- return __iscsi_disc_store_##name(&iscsit_global->discovery_acl, \
+ return __iscsi_disc_##name##_store(&iscsit_global->discovery_acl, \
page, count); \
-}
+ \
+} \
+CONFIGFS_ATTR(iscsi_disc_, name)
+
+DEF_DISC_AUTH_STR(userid, NAF_USERID_SET);
+DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET);
+DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
+DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
#define DEF_DISC_AUTH_INT(name) \
__DEF_NACL_AUTH_INT(disc, name) \
-static ssize_t iscsi_disc_show_##name( \
- struct target_fabric_configfs *tf, \
- char *page) \
+static ssize_t iscsi_disc_##name##_show(struct config_item *item, char *page) \
{ \
- return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \
+ return __iscsi_disc_##name##_show(&iscsit_global->discovery_acl, \
page); \
-}
-
-#define DISC_AUTH_ATTR(_name, _mode) TF_DISC_ATTR(iscsi, _name, _mode)
-#define DISC_AUTH_ATTR_RO(_name) TF_DISC_ATTR_RO(iscsi, _name)
+} \
+CONFIGFS_ATTR_RO(iscsi_disc_, name)
-/*
- * One-way authentication userid
- */
-DEF_DISC_AUTH_STR(userid, NAF_USERID_SET);
-DISC_AUTH_ATTR(userid, S_IRUGO | S_IWUSR);
-/*
- * One-way authentication password
- */
-DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET);
-DISC_AUTH_ATTR(password, S_IRUGO | S_IWUSR);
-/*
- * Enforce mutual authentication
- */
DEF_DISC_AUTH_INT(authenticate_target);
-DISC_AUTH_ATTR_RO(authenticate_target);
-/*
- * Mutual authentication userid
- */
-DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET);
-DISC_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR);
-/*
- * Mutual authentication password
- */
-DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET);
-DISC_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR);
-/*
- * enforce_discovery_auth
- */
-static ssize_t iscsi_disc_show_enforce_discovery_auth(
- struct target_fabric_configfs *tf,
- char *page)
+
+static ssize_t iscsi_disc_enforce_discovery_auth_show(struct config_item *item,
+ char *page)
{
struct iscsi_node_auth *discovery_auth = &iscsit_global->discovery_acl.node_auth;
return sprintf(page, "%d\n", discovery_auth->enforce_discovery_auth);
}
-static ssize_t iscsi_disc_store_enforce_discovery_auth(
- struct target_fabric_configfs *tf,
- const char *page,
- size_t count)
+static ssize_t iscsi_disc_enforce_discovery_auth_store(struct config_item *item,
+ const char *page, size_t count)
{
struct iscsi_param *param;
struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg;
@@ -1677,15 +1428,15 @@ static ssize_t iscsi_disc_store_enforce_discovery_auth(
return count;
}
-DISC_AUTH_ATTR(enforce_discovery_auth, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(iscsi_disc_, enforce_discovery_auth);
static struct configfs_attribute *lio_target_discovery_auth_attrs[] = {
- &iscsi_disc_userid.attr,
- &iscsi_disc_password.attr,
- &iscsi_disc_authenticate_target.attr,
- &iscsi_disc_userid_mutual.attr,
- &iscsi_disc_password_mutual.attr,
- &iscsi_disc_enforce_discovery_auth.attr,
+ &iscsi_disc_attr_userid,
+ &iscsi_disc_attr_password,
+ &iscsi_disc_attr_authenticate_target,
+ &iscsi_disc_attr_userid_mutual,
+ &iscsi_disc_attr_password_mutual,
+ &iscsi_disc_attr_enforce_discovery_auth,
NULL,
};
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 5c964c0..9fc9117 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -388,6 +388,7 @@ err:
if (login->login_complete) {
if (conn->rx_thread && conn->rx_thread_active) {
send_sig(SIGINT, conn->rx_thread, 1);
+ complete(&conn->rx_login_comp);
kthread_stop(conn->rx_thread);
}
if (conn->tx_thread && conn->tx_thread_active) {
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 51d1734..2cbea2a 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -208,7 +208,7 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr)
if (!pl) {
pr_err("Unable to allocate memory for"
" struct iscsi_param_list.\n");
- return -1 ;
+ return -ENOMEM;
}
INIT_LIST_HEAD(&pl->param_list);
INIT_LIST_HEAD(&pl->extra_response_list);
@@ -578,7 +578,7 @@ int iscsi_copy_param_list(
param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL);
if (!param_list) {
pr_err("Unable to allocate memory for struct iscsi_param_list.\n");
- return -1;
+ return -ENOMEM;
}
INIT_LIST_HEAD(&param_list->param_list);
INIT_LIST_HEAD(&param_list->extra_response_list);
@@ -629,7 +629,7 @@ int iscsi_copy_param_list(
err_out:
iscsi_release_param_list(param_list);
- return -1;
+ return -ENOMEM;
}
static void iscsi_release_extra_responses(struct iscsi_param_list *param_list)
@@ -729,7 +729,7 @@ static int iscsi_add_notunderstood_response(
if (!extra_response) {
pr_err("Unable to allocate memory for"
" struct iscsi_extra_response.\n");
- return -1;
+ return -ENOMEM;
}
INIT_LIST_HEAD(&extra_response->er_list);
@@ -1370,7 +1370,7 @@ int iscsi_decode_text_input(
tmpbuf = kzalloc(length + 1, GFP_KERNEL);
if (!tmpbuf) {
pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length);
- return -1;
+ return -ENOMEM;
}
memcpy(tmpbuf, textbuf, length);
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
index 9dd94ff..411cb26 100644
--- a/drivers/target/iscsi/iscsi_target_stat.c
+++ b/drivers/target/iscsi/iscsi_target_stat.c
@@ -21,7 +21,6 @@
#include <linux/export.h>
#include <scsi/iscsi_proto.h>
#include <target/target_core_base.h>
-#include <target/configfs_macros.h>
#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
@@ -50,76 +49,56 @@
/*
* Instance Attributes Table
*/
-CONFIGFS_EATTR_STRUCT(iscsi_stat_instance, iscsi_wwn_stat_grps);
-#define ISCSI_STAT_INSTANCE_ATTR(_name, _mode) \
-static struct iscsi_stat_instance_attribute \
- iscsi_stat_instance_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_instance_show_attr_##_name, \
- iscsi_stat_instance_store_attr_##_name);
-
-#define ISCSI_STAT_INSTANCE_ATTR_RO(_name) \
-static struct iscsi_stat_instance_attribute \
- iscsi_stat_instance_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_instance_show_attr_##_name);
-
-static ssize_t iscsi_stat_instance_show_attr_inst(
- struct iscsi_wwn_stat_grps *igrps, char *page)
-{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+static struct iscsi_tiqn *iscsi_instance_tiqn(struct config_item *item)
+{
+ struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_wwn_stat_grps, iscsi_instance_group);
+ return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps);
+}
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+static ssize_t iscsi_stat_instance_inst_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_instance_tiqn(item)->tiqn_index);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(inst);
-static ssize_t iscsi_stat_instance_show_attr_min_ver(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_min_ver_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(min_ver);
-static ssize_t iscsi_stat_instance_show_attr_max_ver(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_max_ver_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(max_ver);
-static ssize_t iscsi_stat_instance_show_attr_portals(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_portals_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_num_tpg_nps);
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_instance_tiqn(item)->tiqn_num_tpg_nps);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(portals);
-static ssize_t iscsi_stat_instance_show_attr_nodes(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_nodes_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_INST_NUM_NODES);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(nodes);
-static ssize_t iscsi_stat_instance_show_attr_sessions(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_sessions_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_nsessions);
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_instance_tiqn(item)->tiqn_nsessions);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(sessions);
-static ssize_t iscsi_stat_instance_show_attr_fail_sess(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_fail_sess_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
u32 sess_err_count;
@@ -131,88 +110,84 @@ static ssize_t iscsi_stat_instance_show_attr_fail_sess(
return snprintf(page, PAGE_SIZE, "%u\n", sess_err_count);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(fail_sess);
-static ssize_t iscsi_stat_instance_show_attr_fail_type(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_fail_type_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
return snprintf(page, PAGE_SIZE, "%u\n",
sess_err->last_sess_failure_type);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(fail_type);
-static ssize_t iscsi_stat_instance_show_attr_fail_rem_name(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_fail_rem_name_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_instance_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
return snprintf(page, PAGE_SIZE, "%s\n",
sess_err->last_sess_fail_rem_name[0] ?
sess_err->last_sess_fail_rem_name : NONE);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(fail_rem_name);
-static ssize_t iscsi_stat_instance_show_attr_disc_time(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_disc_time_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DISCONTINUITY_TIME);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(disc_time);
-static ssize_t iscsi_stat_instance_show_attr_description(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_description_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%s\n", ISCSI_INST_DESCR);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(description);
-static ssize_t iscsi_stat_instance_show_attr_vendor(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_vendor_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "Datera, Inc. iSCSI-Target\n");
}
-ISCSI_STAT_INSTANCE_ATTR_RO(vendor);
-static ssize_t iscsi_stat_instance_show_attr_version(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_instance_version_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%s\n", ISCSIT_VERSION);
}
-ISCSI_STAT_INSTANCE_ATTR_RO(version);
-CONFIGFS_EATTR_OPS(iscsi_stat_instance, iscsi_wwn_stat_grps,
- iscsi_instance_group);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, min_ver);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, max_ver);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, portals);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, nodes);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, sessions);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_sess);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_type);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, fail_rem_name);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, disc_time);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, description);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, vendor);
+CONFIGFS_ATTR_RO(iscsi_stat_instance_, version);
static struct configfs_attribute *iscsi_stat_instance_attrs[] = {
- &iscsi_stat_instance_inst.attr,
- &iscsi_stat_instance_min_ver.attr,
- &iscsi_stat_instance_max_ver.attr,
- &iscsi_stat_instance_portals.attr,
- &iscsi_stat_instance_nodes.attr,
- &iscsi_stat_instance_sessions.attr,
- &iscsi_stat_instance_fail_sess.attr,
- &iscsi_stat_instance_fail_type.attr,
- &iscsi_stat_instance_fail_rem_name.attr,
- &iscsi_stat_instance_disc_time.attr,
- &iscsi_stat_instance_description.attr,
- &iscsi_stat_instance_vendor.attr,
- &iscsi_stat_instance_version.attr,
+ &iscsi_stat_instance_attr_inst,
+ &iscsi_stat_instance_attr_min_ver,
+ &iscsi_stat_instance_attr_max_ver,
+ &iscsi_stat_instance_attr_portals,
+ &iscsi_stat_instance_attr_nodes,
+ &iscsi_stat_instance_attr_sessions,
+ &iscsi_stat_instance_attr_fail_sess,
+ &iscsi_stat_instance_attr_fail_type,
+ &iscsi_stat_instance_attr_fail_rem_name,
+ &iscsi_stat_instance_attr_disc_time,
+ &iscsi_stat_instance_attr_description,
+ &iscsi_stat_instance_attr_vendor,
+ &iscsi_stat_instance_attr_version,
NULL,
};
-static struct configfs_item_operations iscsi_stat_instance_item_ops = {
- .show_attribute = iscsi_stat_instance_attr_show,
- .store_attribute = iscsi_stat_instance_attr_store,
-};
-
struct config_item_type iscsi_stat_instance_cit = {
- .ct_item_ops = &iscsi_stat_instance_item_ops,
.ct_attrs = iscsi_stat_instance_attrs,
.ct_owner = THIS_MODULE,
};
@@ -220,81 +195,61 @@ struct config_item_type iscsi_stat_instance_cit = {
/*
* Instance Session Failure Stats Table
*/
-CONFIGFS_EATTR_STRUCT(iscsi_stat_sess_err, iscsi_wwn_stat_grps);
-#define ISCSI_STAT_SESS_ERR_ATTR(_name, _mode) \
-static struct iscsi_stat_sess_err_attribute \
- iscsi_stat_sess_err_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_sess_err_show_attr_##_name, \
- iscsi_stat_sess_err_store_attr_##_name);
-
-#define ISCSI_STAT_SESS_ERR_ATTR_RO(_name) \
-static struct iscsi_stat_sess_err_attribute \
- iscsi_stat_sess_err_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_sess_err_show_attr_##_name);
-
-static ssize_t iscsi_stat_sess_err_show_attr_inst(
- struct iscsi_wwn_stat_grps *igrps, char *page)
-{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+static struct iscsi_tiqn *iscsi_sess_err_tiqn(struct config_item *item)
+{
+ struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_wwn_stat_grps, iscsi_sess_err_group);
+ return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps);
+}
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+static ssize_t iscsi_stat_sess_err_inst_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_sess_err_tiqn(item)->tiqn_index);
}
-ISCSI_STAT_SESS_ERR_ATTR_RO(inst);
-static ssize_t iscsi_stat_sess_err_show_attr_digest_errors(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_err_digest_errors_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
return snprintf(page, PAGE_SIZE, "%u\n", sess_err->digest_errors);
}
-ISCSI_STAT_SESS_ERR_ATTR_RO(digest_errors);
-static ssize_t iscsi_stat_sess_err_show_attr_cxn_errors(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_err_cxn_errors_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
return snprintf(page, PAGE_SIZE, "%u\n", sess_err->cxn_timeout_errors);
}
-ISCSI_STAT_SESS_ERR_ATTR_RO(cxn_errors);
-static ssize_t iscsi_stat_sess_err_show_attr_format_errors(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_err_format_errors_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_sess_err_tiqn(item);
struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats;
return snprintf(page, PAGE_SIZE, "%u\n", sess_err->pdu_format_errors);
}
-ISCSI_STAT_SESS_ERR_ATTR_RO(format_errors);
-CONFIGFS_EATTR_OPS(iscsi_stat_sess_err, iscsi_wwn_stat_grps,
- iscsi_sess_err_group);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, digest_errors);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, cxn_errors);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_err_, format_errors);
static struct configfs_attribute *iscsi_stat_sess_err_attrs[] = {
- &iscsi_stat_sess_err_inst.attr,
- &iscsi_stat_sess_err_digest_errors.attr,
- &iscsi_stat_sess_err_cxn_errors.attr,
- &iscsi_stat_sess_err_format_errors.attr,
+ &iscsi_stat_sess_err_attr_inst,
+ &iscsi_stat_sess_err_attr_digest_errors,
+ &iscsi_stat_sess_err_attr_cxn_errors,
+ &iscsi_stat_sess_err_attr_format_errors,
NULL,
};
-static struct configfs_item_operations iscsi_stat_sess_err_item_ops = {
- .show_attribute = iscsi_stat_sess_err_attr_show,
- .store_attribute = iscsi_stat_sess_err_attr_store,
-};
-
struct config_item_type iscsi_stat_sess_err_cit = {
- .ct_item_ops = &iscsi_stat_sess_err_item_ops,
.ct_attrs = iscsi_stat_sess_err_attrs,
.ct_owner = THIS_MODULE,
};
@@ -302,42 +257,30 @@ struct config_item_type iscsi_stat_sess_err_cit = {
/*
* Target Attributes Table
*/
-CONFIGFS_EATTR_STRUCT(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps);
-#define ISCSI_STAT_TGT_ATTR(_name, _mode) \
-static struct iscsi_stat_tgt_attr_attribute \
- iscsi_stat_tgt_attr_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_tgt-attr_show_attr_##_name, \
- iscsi_stat_tgt_attr_store_attr_##_name);
-
-#define ISCSI_STAT_TGT_ATTR_RO(_name) \
-static struct iscsi_stat_tgt_attr_attribute \
- iscsi_stat_tgt_attr_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_tgt_attr_show_attr_##_name);
-
-static ssize_t iscsi_stat_tgt_attr_show_attr_inst(
- struct iscsi_wwn_stat_grps *igrps, char *page)
-{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+static struct iscsi_tiqn *iscsi_tgt_attr_tiqn(struct config_item *item)
+{
+ struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_wwn_stat_grps, iscsi_tgt_attr_group);
+ return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps);
+}
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+static ssize_t iscsi_stat_tgt_attr_inst_show(struct config_item *item,
+ char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_tgt_attr_tiqn(item)->tiqn_index);
}
-ISCSI_STAT_TGT_ATTR_RO(inst);
-static ssize_t iscsi_stat_tgt_attr_show_attr_indx(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_indx_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
}
-ISCSI_STAT_TGT_ATTR_RO(indx);
-static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_login_fails_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
u32 fail_count;
@@ -349,13 +292,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails(
return snprintf(page, PAGE_SIZE, "%u\n", fail_count);
}
-ISCSI_STAT_TGT_ATTR_RO(login_fails);
-static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_last_fail_time_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
u32 last_fail_time;
@@ -367,13 +308,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time(
return snprintf(page, PAGE_SIZE, "%u\n", last_fail_time);
}
-ISCSI_STAT_TGT_ATTR_RO(last_fail_time);
-static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_last_fail_type_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
u32 last_fail_type;
@@ -383,13 +322,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type(
return snprintf(page, PAGE_SIZE, "%u\n", last_fail_type);
}
-ISCSI_STAT_TGT_ATTR_RO(last_fail_type);
-static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_fail_intr_name_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
unsigned char buf[224];
@@ -400,13 +337,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name(
return snprintf(page, PAGE_SIZE, "%s\n", buf);
}
-ISCSI_STAT_TGT_ATTR_RO(fail_intr_name);
-static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_fail_intr_addr_type_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
int ret;
@@ -419,13 +354,11 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type(
return ret;
}
-ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type);
-static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_tgt_attr_fail_intr_addr_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_tgt_attr_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
int ret;
@@ -435,30 +368,29 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr(
return ret;
}
-ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr);
-CONFIGFS_EATTR_OPS(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps,
- iscsi_tgt_attr_group);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, indx);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, login_fails);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, last_fail_time);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, last_fail_type);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_name);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_addr_type);
+CONFIGFS_ATTR_RO(iscsi_stat_tgt_attr_, fail_intr_addr);
static struct configfs_attribute *iscsi_stat_tgt_attr_attrs[] = {
- &iscsi_stat_tgt_attr_inst.attr,
- &iscsi_stat_tgt_attr_indx.attr,
- &iscsi_stat_tgt_attr_login_fails.attr,
- &iscsi_stat_tgt_attr_last_fail_time.attr,
- &iscsi_stat_tgt_attr_last_fail_type.attr,
- &iscsi_stat_tgt_attr_fail_intr_name.attr,
- &iscsi_stat_tgt_attr_fail_intr_addr_type.attr,
- &iscsi_stat_tgt_attr_fail_intr_addr.attr,
+ &iscsi_stat_tgt_attr_attr_inst,
+ &iscsi_stat_tgt_attr_attr_indx,
+ &iscsi_stat_tgt_attr_attr_login_fails,
+ &iscsi_stat_tgt_attr_attr_last_fail_time,
+ &iscsi_stat_tgt_attr_attr_last_fail_type,
+ &iscsi_stat_tgt_attr_attr_fail_intr_name,
+ &iscsi_stat_tgt_attr_attr_fail_intr_addr_type,
+ &iscsi_stat_tgt_attr_attr_fail_intr_addr,
NULL,
};
-static struct configfs_item_operations iscsi_stat_tgt_attr_item_ops = {
- .show_attribute = iscsi_stat_tgt_attr_attr_show,
- .store_attribute = iscsi_stat_tgt_attr_attr_store,
-};
-
struct config_item_type iscsi_stat_tgt_attr_cit = {
- .ct_item_ops = &iscsi_stat_tgt_attr_item_ops,
.ct_attrs = iscsi_stat_tgt_attr_attrs,
.ct_owner = THIS_MODULE,
};
@@ -466,42 +398,29 @@ struct config_item_type iscsi_stat_tgt_attr_cit = {
/*
* Target Login Stats Table
*/
-CONFIGFS_EATTR_STRUCT(iscsi_stat_login, iscsi_wwn_stat_grps);
-#define ISCSI_STAT_LOGIN(_name, _mode) \
-static struct iscsi_stat_login_attribute \
- iscsi_stat_login_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_login_show_attr_##_name, \
- iscsi_stat_login_store_attr_##_name);
-
-#define ISCSI_STAT_LOGIN_RO(_name) \
-static struct iscsi_stat_login_attribute \
- iscsi_stat_login_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_login_show_attr_##_name);
-
-static ssize_t iscsi_stat_login_show_attr_inst(
- struct iscsi_wwn_stat_grps *igrps, char *page)
-{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+static struct iscsi_tiqn *iscsi_login_stat_tiqn(struct config_item *item)
+{
+ struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_wwn_stat_grps, iscsi_login_stats_group);
+ return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps);
+}
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+static ssize_t iscsi_stat_login_inst_show(struct config_item *item, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_login_stat_tiqn(item)->tiqn_index);
}
-ISCSI_STAT_LOGIN_RO(inst);
-static ssize_t iscsi_stat_login_show_attr_indx(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_indx_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
}
-ISCSI_STAT_LOGIN_RO(indx);
-static ssize_t iscsi_stat_login_show_attr_accepts(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_accepts_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -511,13 +430,11 @@ static ssize_t iscsi_stat_login_show_attr_accepts(
return ret;
}
-ISCSI_STAT_LOGIN_RO(accepts);
-static ssize_t iscsi_stat_login_show_attr_other_fails(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_other_fails_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -527,13 +444,11 @@ static ssize_t iscsi_stat_login_show_attr_other_fails(
return ret;
}
-ISCSI_STAT_LOGIN_RO(other_fails);
-static ssize_t iscsi_stat_login_show_attr_redirects(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_redirects_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -543,13 +458,11 @@ static ssize_t iscsi_stat_login_show_attr_redirects(
return ret;
}
-ISCSI_STAT_LOGIN_RO(redirects);
-static ssize_t iscsi_stat_login_show_attr_authorize_fails(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_authorize_fails_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -559,13 +472,11 @@ static ssize_t iscsi_stat_login_show_attr_authorize_fails(
return ret;
}
-ISCSI_STAT_LOGIN_RO(authorize_fails);
-static ssize_t iscsi_stat_login_show_attr_authenticate_fails(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_authenticate_fails_show(
+ struct config_item *item, char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -575,13 +486,11 @@ static ssize_t iscsi_stat_login_show_attr_authenticate_fails(
return ret;
}
-ISCSI_STAT_LOGIN_RO(authenticate_fails);
-static ssize_t iscsi_stat_login_show_attr_negotiate_fails(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_login_negotiate_fails_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_login_stat_tiqn(item);
struct iscsi_login_stats *lstat = &tiqn->login_stats;
ssize_t ret;
@@ -591,30 +500,29 @@ static ssize_t iscsi_stat_login_show_attr_negotiate_fails(
return ret;
}
-ISCSI_STAT_LOGIN_RO(negotiate_fails);
-CONFIGFS_EATTR_OPS(iscsi_stat_login, iscsi_wwn_stat_grps,
- iscsi_login_stats_group);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, indx);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, accepts);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, other_fails);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, redirects);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, authorize_fails);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, authenticate_fails);
+CONFIGFS_ATTR_RO(iscsi_stat_login_, negotiate_fails);
static struct configfs_attribute *iscsi_stat_login_stats_attrs[] = {
- &iscsi_stat_login_inst.attr,
- &iscsi_stat_login_indx.attr,
- &iscsi_stat_login_accepts.attr,
- &iscsi_stat_login_other_fails.attr,
- &iscsi_stat_login_redirects.attr,
- &iscsi_stat_login_authorize_fails.attr,
- &iscsi_stat_login_authenticate_fails.attr,
- &iscsi_stat_login_negotiate_fails.attr,
+ &iscsi_stat_login_attr_inst,
+ &iscsi_stat_login_attr_indx,
+ &iscsi_stat_login_attr_accepts,
+ &iscsi_stat_login_attr_other_fails,
+ &iscsi_stat_login_attr_redirects,
+ &iscsi_stat_login_attr_authorize_fails,
+ &iscsi_stat_login_attr_authenticate_fails,
+ &iscsi_stat_login_attr_negotiate_fails,
NULL,
};
-static struct configfs_item_operations iscsi_stat_login_stats_item_ops = {
- .show_attribute = iscsi_stat_login_attr_show,
- .store_attribute = iscsi_stat_login_attr_store,
-};
-
struct config_item_type iscsi_stat_login_cit = {
- .ct_item_ops = &iscsi_stat_login_stats_item_ops,
.ct_attrs = iscsi_stat_login_stats_attrs,
.ct_owner = THIS_MODULE,
};
@@ -622,78 +530,56 @@ struct config_item_type iscsi_stat_login_cit = {
/*
* Target Logout Stats Table
*/
-
-CONFIGFS_EATTR_STRUCT(iscsi_stat_logout, iscsi_wwn_stat_grps);
-#define ISCSI_STAT_LOGOUT(_name, _mode) \
-static struct iscsi_stat_logout_attribute \
- iscsi_stat_logout_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_logout_show_attr_##_name, \
- iscsi_stat_logout_store_attr_##_name);
-
-#define ISCSI_STAT_LOGOUT_RO(_name) \
-static struct iscsi_stat_logout_attribute \
- iscsi_stat_logout_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_logout_show_attr_##_name);
-
-static ssize_t iscsi_stat_logout_show_attr_inst(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static struct iscsi_tiqn *iscsi_logout_stat_tiqn(struct config_item *item)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_wwn_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_wwn_stat_grps, iscsi_logout_stats_group);
+ return container_of(igrps, struct iscsi_tiqn, tiqn_stat_grps);
+}
- return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
+static ssize_t iscsi_stat_logout_inst_show(struct config_item *item, char *page)
+{
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ iscsi_logout_stat_tiqn(item)->tiqn_index);
}
-ISCSI_STAT_LOGOUT_RO(inst);
-static ssize_t iscsi_stat_logout_show_attr_indx(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_logout_indx_show(struct config_item *item, char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX);
}
-ISCSI_STAT_LOGOUT_RO(indx);
-static ssize_t iscsi_stat_logout_show_attr_normal_logouts(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_logout_normal_logouts_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_logout_stat_tiqn(item);
struct iscsi_logout_stats *lstats = &tiqn->logout_stats;
return snprintf(page, PAGE_SIZE, "%u\n", lstats->normal_logouts);
}
-ISCSI_STAT_LOGOUT_RO(normal_logouts);
-static ssize_t iscsi_stat_logout_show_attr_abnormal_logouts(
- struct iscsi_wwn_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_logout_abnormal_logouts_show(struct config_item *item,
+ char *page)
{
- struct iscsi_tiqn *tiqn = container_of(igrps,
- struct iscsi_tiqn, tiqn_stat_grps);
+ struct iscsi_tiqn *tiqn = iscsi_logout_stat_tiqn(item);
struct iscsi_logout_stats *lstats = &tiqn->logout_stats;
return snprintf(page, PAGE_SIZE, "%u\n", lstats->abnormal_logouts);
}
-ISCSI_STAT_LOGOUT_RO(abnormal_logouts);
-CONFIGFS_EATTR_OPS(iscsi_stat_logout, iscsi_wwn_stat_grps,
- iscsi_logout_stats_group);
+CONFIGFS_ATTR_RO(iscsi_stat_logout_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_logout_, indx);
+CONFIGFS_ATTR_RO(iscsi_stat_logout_, normal_logouts);
+CONFIGFS_ATTR_RO(iscsi_stat_logout_, abnormal_logouts);
static struct configfs_attribute *iscsi_stat_logout_stats_attrs[] = {
- &iscsi_stat_logout_inst.attr,
- &iscsi_stat_logout_indx.attr,
- &iscsi_stat_logout_normal_logouts.attr,
- &iscsi_stat_logout_abnormal_logouts.attr,
+ &iscsi_stat_logout_attr_inst,
+ &iscsi_stat_logout_attr_indx,
+ &iscsi_stat_logout_attr_normal_logouts,
+ &iscsi_stat_logout_attr_abnormal_logouts,
NULL,
};
-static struct configfs_item_operations iscsi_stat_logout_stats_item_ops = {
- .show_attribute = iscsi_stat_logout_attr_show,
- .store_attribute = iscsi_stat_logout_attr_store,
-};
-
struct config_item_type iscsi_stat_logout_cit = {
- .ct_item_ops = &iscsi_stat_logout_stats_item_ops,
.ct_attrs = iscsi_stat_logout_stats_attrs,
.ct_owner = THIS_MODULE,
};
@@ -701,39 +587,26 @@ struct config_item_type iscsi_stat_logout_cit = {
/*
* Session Stats Table
*/
+static struct iscsi_node_acl *iscsi_stat_nacl(struct config_item *item)
+{
+ struct iscsi_node_stat_grps *igrps = container_of(to_config_group(item),
+ struct iscsi_node_stat_grps, iscsi_sess_stats_group);
+ return container_of(igrps, struct iscsi_node_acl, node_stat_grps);
+}
-CONFIGFS_EATTR_STRUCT(iscsi_stat_sess, iscsi_node_stat_grps);
-#define ISCSI_STAT_SESS(_name, _mode) \
-static struct iscsi_stat_sess_attribute \
- iscsi_stat_sess_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- iscsi_stat_sess_show_attr_##_name, \
- iscsi_stat_sess_store_attr_##_name);
-
-#define ISCSI_STAT_SESS_RO(_name) \
-static struct iscsi_stat_sess_attribute \
- iscsi_stat_sess_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- iscsi_stat_sess_show_attr_##_name);
-
-static ssize_t iscsi_stat_sess_show_attr_inst(
- struct iscsi_node_stat_grps *igrps, char *page)
-{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+static ssize_t iscsi_stat_sess_inst_show(struct config_item *item, char *page)
+{
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_wwn *wwn = acl->se_node_acl.se_tpg->se_tpg_wwn;
struct iscsi_tiqn *tiqn = container_of(wwn,
struct iscsi_tiqn, tiqn_wwn);
return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index);
}
-ISCSI_STAT_SESS_RO(inst);
-static ssize_t iscsi_stat_sess_show_attr_node(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_node_show(struct config_item *item, char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -751,13 +624,10 @@ static ssize_t iscsi_stat_sess_show_attr_node(
return ret;
}
-ISCSI_STAT_SESS_RO(node);
-static ssize_t iscsi_stat_sess_show_attr_indx(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_indx_show(struct config_item *item, char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -775,13 +645,11 @@ static ssize_t iscsi_stat_sess_show_attr_indx(
return ret;
}
-ISCSI_STAT_SESS_RO(indx);
-static ssize_t iscsi_stat_sess_show_attr_cmd_pdus(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_cmd_pdus_show(struct config_item *item,
+ char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -799,13 +667,11 @@ static ssize_t iscsi_stat_sess_show_attr_cmd_pdus(
return ret;
}
-ISCSI_STAT_SESS_RO(cmd_pdus);
-static ssize_t iscsi_stat_sess_show_attr_rsp_pdus(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_rsp_pdus_show(struct config_item *item,
+ char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -823,13 +689,11 @@ static ssize_t iscsi_stat_sess_show_attr_rsp_pdus(
return ret;
}
-ISCSI_STAT_SESS_RO(rsp_pdus);
-static ssize_t iscsi_stat_sess_show_attr_txdata_octs(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_txdata_octs_show(struct config_item *item,
+ char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -847,13 +711,11 @@ static ssize_t iscsi_stat_sess_show_attr_txdata_octs(
return ret;
}
-ISCSI_STAT_SESS_RO(txdata_octs);
-static ssize_t iscsi_stat_sess_show_attr_rxdata_octs(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_rxdata_octs_show(struct config_item *item,
+ char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -871,13 +733,11 @@ static ssize_t iscsi_stat_sess_show_attr_rxdata_octs(
return ret;
}
-ISCSI_STAT_SESS_RO(rxdata_octs);
-static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_conn_digest_errors_show(struct config_item *item,
+ char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -895,13 +755,11 @@ static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors(
return ret;
}
-ISCSI_STAT_SESS_RO(conn_digest_errors);
-static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors(
- struct iscsi_node_stat_grps *igrps, char *page)
+static ssize_t iscsi_stat_sess_conn_timeout_errors_show(
+ struct config_item *item, char *page)
{
- struct iscsi_node_acl *acl = container_of(igrps,
- struct iscsi_node_acl, node_stat_grps);
+ struct iscsi_node_acl *acl = iscsi_stat_nacl(item);
struct se_node_acl *se_nacl = &acl->se_node_acl;
struct iscsi_session *sess;
struct se_session *se_sess;
@@ -919,31 +777,31 @@ static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors(
return ret;
}
-ISCSI_STAT_SESS_RO(conn_timeout_errors);
-CONFIGFS_EATTR_OPS(iscsi_stat_sess, iscsi_node_stat_grps,
- iscsi_sess_stats_group);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, inst);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, node);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, indx);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, cmd_pdus);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, rsp_pdus);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, txdata_octs);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, rxdata_octs);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, conn_digest_errors);
+CONFIGFS_ATTR_RO(iscsi_stat_sess_, conn_timeout_errors);
static struct configfs_attribute *iscsi_stat_sess_stats_attrs[] = {
- &iscsi_stat_sess_inst.attr,
- &iscsi_stat_sess_node.attr,
- &iscsi_stat_sess_indx.attr,
- &iscsi_stat_sess_cmd_pdus.attr,
- &iscsi_stat_sess_rsp_pdus.attr,
- &iscsi_stat_sess_txdata_octs.attr,
- &iscsi_stat_sess_rxdata_octs.attr,
- &iscsi_stat_sess_conn_digest_errors.attr,
- &iscsi_stat_sess_conn_timeout_errors.attr,
+ &iscsi_stat_sess_attr_inst,
+ &iscsi_stat_sess_attr_node,
+ &iscsi_stat_sess_attr_indx,
+ &iscsi_stat_sess_attr_cmd_pdus,
+ &iscsi_stat_sess_attr_rsp_pdus,
+ &iscsi_stat_sess_attr_txdata_octs,
+ &iscsi_stat_sess_attr_rxdata_octs,
+ &iscsi_stat_sess_attr_conn_digest_errors,
+ &iscsi_stat_sess_attr_conn_timeout_errors,
NULL,
};
-static struct configfs_item_operations iscsi_stat_sess_stats_item_ops = {
- .show_attribute = iscsi_stat_sess_attr_show,
- .store_attribute = iscsi_stat_sess_attr_store,
-};
-
struct config_item_type iscsi_stat_sess_cit = {
- .ct_item_ops = &iscsi_stat_sess_stats_item_ops,
.ct_attrs = iscsi_stat_sess_stats_attrs,
.ct_owner = THIS_MODULE,
};
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index 5bc85ff..4fb0eca 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -34,7 +34,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
#include "tcm_loop.h"
@@ -377,7 +376,6 @@ static struct scsi_host_template tcm_loop_driver_template = {
.use_clustering = DISABLE_CLUSTERING,
.slave_alloc = tcm_loop_slave_alloc,
.module = THIS_MODULE,
- .use_blk_tags = 1,
.track_queue_depth = 1,
};
@@ -763,21 +761,20 @@ static void tcm_loop_port_unlink(
/* End items for tcm_loop_port_cit */
-static ssize_t tcm_loop_tpg_attrib_show_fabric_prot_type(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_loop_tpg_attrib_fabric_prot_type_show(
+ struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
return sprintf(page, "%d\n", tl_tpg->tl_fabric_prot_type);
}
-static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_loop_tpg_attrib_fabric_prot_type_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg, struct tcm_loop_tpg,
tl_se_tpg);
unsigned long val;
@@ -796,10 +793,10 @@ static ssize_t tcm_loop_tpg_attrib_store_fabric_prot_type(
return count;
}
-TF_TPG_ATTRIB_ATTR(tcm_loop, fabric_prot_type, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(tcm_loop_tpg_attrib_, fabric_prot_type);
static struct configfs_attribute *tcm_loop_tpg_attrib_attrs[] = {
- &tcm_loop_tpg_attrib_fabric_prot_type.attr,
+ &tcm_loop_tpg_attrib_attr_fabric_prot_type,
NULL,
};
@@ -894,10 +891,9 @@ static int tcm_loop_drop_nexus(
/* End items for tcm_loop_nexus_cit */
-static ssize_t tcm_loop_tpg_show_nexus(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_loop_tpg_nexus_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
struct tcm_loop_tpg, tl_se_tpg);
struct tcm_loop_nexus *tl_nexus;
@@ -913,11 +909,10 @@ static ssize_t tcm_loop_tpg_show_nexus(
return ret;
}
-static ssize_t tcm_loop_tpg_store_nexus(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_loop_tpg_nexus_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
struct tcm_loop_tpg, tl_se_tpg);
struct tcm_loop_hba *tl_hba = tl_tpg->tl_hba;
@@ -992,12 +987,10 @@ check_newline:
return count;
}
-TF_TPG_BASE_ATTR(tcm_loop, nexus, S_IRUGO | S_IWUSR);
-
-static ssize_t tcm_loop_tpg_show_transport_status(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_loop_tpg_transport_status_show(struct config_item *item,
+ char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
struct tcm_loop_tpg, tl_se_tpg);
const char *status = NULL;
@@ -1020,11 +1013,10 @@ static ssize_t tcm_loop_tpg_show_transport_status(
return ret;
}
-static ssize_t tcm_loop_tpg_store_transport_status(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_loop_tpg_transport_status_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct tcm_loop_tpg *tl_tpg = container_of(se_tpg,
struct tcm_loop_tpg, tl_se_tpg);
@@ -1044,11 +1036,12 @@ static ssize_t tcm_loop_tpg_store_transport_status(
return -EINVAL;
}
-TF_TPG_BASE_ATTR(tcm_loop, transport_status, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(tcm_loop_tpg_, nexus);
+CONFIGFS_ATTR(tcm_loop_tpg_, transport_status);
static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
- &tcm_loop_tpg_nexus.attr,
- &tcm_loop_tpg_transport_status.attr,
+ &tcm_loop_tpg_attr_nexus,
+ &tcm_loop_tpg_attr_transport_status,
NULL,
};
@@ -1216,17 +1209,15 @@ static void tcm_loop_drop_scsi_hba(
}
/* Start items for tcm_loop_cit */
-static ssize_t tcm_loop_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t tcm_loop_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "TCM Loopback Fabric module %s\n", TCM_LOOP_VERSION);
}
-TF_WWN_ATTR_RO(tcm_loop, version);
+CONFIGFS_ATTR_RO(tcm_loop_wwn_, version);
static struct configfs_attribute *tcm_loop_wwn_attrs[] = {
- &tcm_loop_wwn_version.attr,
+ &tcm_loop_wwn_attr_version,
NULL,
};
diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c
index 0edf320..35f7d31 100644
--- a/drivers/target/sbp/sbp_target.c
+++ b/drivers/target/sbp/sbp_target.c
@@ -35,8 +35,6 @@
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include <asm/unaligned.h>
#include "sbp_target.h"
@@ -2111,24 +2109,21 @@ static void sbp_drop_tport(struct se_wwn *wwn)
kfree(tport);
}
-static ssize_t sbp_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t sbp_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "FireWire SBP fabric module %s\n", SBP_VERSION);
}
-TF_WWN_ATTR_RO(sbp, version);
+CONFIGFS_ATTR_RO(sbp_wwn_, version);
static struct configfs_attribute *sbp_wwn_attrs[] = {
- &sbp_wwn_version.attr,
+ &sbp_wwn_attr_version,
NULL,
};
-static ssize_t sbp_tpg_show_directory_id(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t sbp_tpg_directory_id_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
@@ -2138,11 +2133,10 @@ static ssize_t sbp_tpg_show_directory_id(
return sprintf(page, "%06x\n", tport->directory_id);
}
-static ssize_t sbp_tpg_store_directory_id(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t sbp_tpg_directory_id_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
unsigned long val;
@@ -2166,20 +2160,18 @@ static ssize_t sbp_tpg_store_directory_id(
return count;
}
-static ssize_t sbp_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t sbp_tpg_enable_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
return sprintf(page, "%d\n", tport->enable);
}
-static ssize_t sbp_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t sbp_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
unsigned long val;
@@ -2219,29 +2211,28 @@ static ssize_t sbp_tpg_store_enable(
return count;
}
-TF_TPG_BASE_ATTR(sbp, directory_id, S_IRUGO | S_IWUSR);
-TF_TPG_BASE_ATTR(sbp, enable, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(sbp_tpg_, directory_id);
+CONFIGFS_ATTR(sbp_tpg_, enable);
static struct configfs_attribute *sbp_tpg_base_attrs[] = {
- &sbp_tpg_directory_id.attr,
- &sbp_tpg_enable.attr,
+ &sbp_tpg_attr_directory_id,
+ &sbp_tpg_attr_enable,
NULL,
};
-static ssize_t sbp_tpg_attrib_show_mgt_orb_timeout(
- struct se_portal_group *se_tpg,
+static ssize_t sbp_tpg_attrib_mgt_orb_timeout_show(struct config_item *item,
char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
return sprintf(page, "%d\n", tport->mgt_orb_timeout);
}
-static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t sbp_tpg_attrib_mgt_orb_timeout_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
unsigned long val;
@@ -2264,20 +2255,19 @@ static ssize_t sbp_tpg_attrib_store_mgt_orb_timeout(
return count;
}
-static ssize_t sbp_tpg_attrib_show_max_reconnect_timeout(
- struct se_portal_group *se_tpg,
+static ssize_t sbp_tpg_attrib_max_reconnect_timeout_show(struct config_item *item,
char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
return sprintf(page, "%d\n", tport->max_reconnect_timeout);
}
-static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t sbp_tpg_attrib_max_reconnect_timeout_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
unsigned long val;
@@ -2300,20 +2290,19 @@ static ssize_t sbp_tpg_attrib_store_max_reconnect_timeout(
return count;
}
-static ssize_t sbp_tpg_attrib_show_max_logins_per_lun(
- struct se_portal_group *se_tpg,
+static ssize_t sbp_tpg_attrib_max_logins_per_lun_show(struct config_item *item,
char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
return sprintf(page, "%d\n", tport->max_logins_per_lun);
}
-static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t sbp_tpg_attrib_max_logins_per_lun_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct sbp_tpg *tpg = container_of(se_tpg, struct sbp_tpg, se_tpg);
struct sbp_tport *tport = tpg->tport;
unsigned long val;
@@ -2330,14 +2319,14 @@ static ssize_t sbp_tpg_attrib_store_max_logins_per_lun(
return count;
}
-TF_TPG_ATTRIB_ATTR(sbp, mgt_orb_timeout, S_IRUGO | S_IWUSR);
-TF_TPG_ATTRIB_ATTR(sbp, max_reconnect_timeout, S_IRUGO | S_IWUSR);
-TF_TPG_ATTRIB_ATTR(sbp, max_logins_per_lun, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(sbp_tpg_attrib_, mgt_orb_timeout);
+CONFIGFS_ATTR(sbp_tpg_attrib_, max_reconnect_timeout);
+CONFIGFS_ATTR(sbp_tpg_attrib_, max_logins_per_lun);
static struct configfs_attribute *sbp_tpg_attrib_attrs[] = {
- &sbp_tpg_attrib_mgt_orb_timeout.attr,
- &sbp_tpg_attrib_max_reconnect_timeout.attr,
- &sbp_tpg_attrib_max_logins_per_lun.attr,
+ &sbp_tpg_attrib_attr_mgt_orb_timeout,
+ &sbp_tpg_attrib_attr_max_reconnect_timeout,
+ &sbp_tpg_attrib_attr_max_logins_per_lun,
NULL,
};
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 860e840..b9b9ffd 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -40,8 +40,6 @@
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include "target_core_internal.h"
#include "target_core_alua.h"
@@ -78,12 +76,6 @@ extern struct t10_alua_lu_gp *default_lu_gp;
static LIST_HEAD(g_tf_list);
static DEFINE_MUTEX(g_tf_lock);
-struct target_core_configfs_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(void *, char *);
- ssize_t (*store)(void *, const char *, size_t);
-};
-
static struct config_group target_core_hbagroup;
static struct config_group alua_group;
static struct config_group alua_lu_gps_group;
@@ -97,24 +89,15 @@ item_to_hba(struct config_item *item)
/*
* Attributes for /sys/kernel/config/target/
*/
-static ssize_t target_core_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
+static ssize_t target_core_item_version_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "Target Engine Core ConfigFS Infrastructure %s"
" on %s/%s on "UTS_RELEASE"\n", TARGET_CORE_VERSION,
utsname()->sysname, utsname()->machine);
}
-static struct configfs_item_operations target_core_fabric_item_ops = {
- .show_attribute = target_core_attr_show,
-};
-
-static struct configfs_attribute target_core_item_attr_version = {
- .ca_owner = THIS_MODULE,
- .ca_name = "version",
- .ca_mode = S_IRUGO,
-};
+CONFIGFS_ATTR_RO(target_core_item_, version);
static struct target_fabric_configfs *target_core_get_fabric(
const char *name)
@@ -273,7 +256,6 @@ static struct configfs_attribute *target_core_fabric_item_attrs[] = {
* Provides Fabrics Groups and Item Attributes for /sys/kernel/config/target/
*/
static struct config_item_type target_core_fabrics_item = {
- .ct_item_ops = &target_core_fabric_item_ops,
.ct_group_ops = &target_core_fabric_group_ops,
.ct_attrs = target_core_fabric_item_attrs,
.ct_owner = THIS_MODULE,
@@ -476,47 +458,54 @@ EXPORT_SYMBOL(target_unregister_template);
// Stop functions called by external Target Fabrics Modules
//############################################################################*/
+static inline struct se_dev_attrib *to_attrib(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_dev_attrib,
+ da_group);
+}
+
/* Start functions for struct config_item_type tb_dev_attrib_cit */
-#define DEF_TB_DEV_ATTRIB_SHOW(_name) \
-static ssize_t show_##_name(struct se_dev_attrib *da, char *page) \
+#define DEF_CONFIGFS_ATTRIB_SHOW(_name) \
+static ssize_t _name##_show(struct config_item *item, char *page) \
{ \
- return snprintf(page, PAGE_SIZE, "%u\n", da->_name); \
-}
-
-DEF_TB_DEV_ATTRIB_SHOW(emulate_model_alias);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_dpo);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_write);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_fua_read);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_write_cache);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_ua_intlck_ctrl);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_tas);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_tpu);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_tpws);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_caw);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_3pc);
-DEF_TB_DEV_ATTRIB_SHOW(pi_prot_type);
-DEF_TB_DEV_ATTRIB_SHOW(hw_pi_prot_type);
-DEF_TB_DEV_ATTRIB_SHOW(pi_prot_format);
-DEF_TB_DEV_ATTRIB_SHOW(enforce_pr_isids);
-DEF_TB_DEV_ATTRIB_SHOW(is_nonrot);
-DEF_TB_DEV_ATTRIB_SHOW(emulate_rest_reord);
-DEF_TB_DEV_ATTRIB_SHOW(force_pr_aptpl);
-DEF_TB_DEV_ATTRIB_SHOW(hw_block_size);
-DEF_TB_DEV_ATTRIB_SHOW(block_size);
-DEF_TB_DEV_ATTRIB_SHOW(hw_max_sectors);
-DEF_TB_DEV_ATTRIB_SHOW(optimal_sectors);
-DEF_TB_DEV_ATTRIB_SHOW(hw_queue_depth);
-DEF_TB_DEV_ATTRIB_SHOW(queue_depth);
-DEF_TB_DEV_ATTRIB_SHOW(max_unmap_lba_count);
-DEF_TB_DEV_ATTRIB_SHOW(max_unmap_block_desc_count);
-DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity);
-DEF_TB_DEV_ATTRIB_SHOW(unmap_granularity_alignment);
-DEF_TB_DEV_ATTRIB_SHOW(max_write_same_len);
-
-#define DEF_TB_DEV_ATTRIB_STORE_U32(_name) \
-static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
+ return snprintf(page, PAGE_SIZE, "%u\n", to_attrib(item)->_name); \
+}
+
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_model_alias);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_dpo);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_fua_write);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_fua_read);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_write_cache);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_ua_intlck_ctrl);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_tas);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpu);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpws);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_caw);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_3pc);
+DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_type);
+DEF_CONFIGFS_ATTRIB_SHOW(hw_pi_prot_type);
+DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_format);
+DEF_CONFIGFS_ATTRIB_SHOW(enforce_pr_isids);
+DEF_CONFIGFS_ATTRIB_SHOW(is_nonrot);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_rest_reord);
+DEF_CONFIGFS_ATTRIB_SHOW(force_pr_aptpl);
+DEF_CONFIGFS_ATTRIB_SHOW(hw_block_size);
+DEF_CONFIGFS_ATTRIB_SHOW(block_size);
+DEF_CONFIGFS_ATTRIB_SHOW(hw_max_sectors);
+DEF_CONFIGFS_ATTRIB_SHOW(optimal_sectors);
+DEF_CONFIGFS_ATTRIB_SHOW(hw_queue_depth);
+DEF_CONFIGFS_ATTRIB_SHOW(queue_depth);
+DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_lba_count);
+DEF_CONFIGFS_ATTRIB_SHOW(max_unmap_block_desc_count);
+DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity);
+DEF_CONFIGFS_ATTRIB_SHOW(unmap_granularity_alignment);
+DEF_CONFIGFS_ATTRIB_SHOW(max_write_same_len);
+
+#define DEF_CONFIGFS_ATTRIB_STORE_U32(_name) \
+static ssize_t _name##_store(struct config_item *item, const char *page,\
size_t count) \
{ \
+ struct se_dev_attrib *da = to_attrib(item); \
u32 val; \
int ret; \
\
@@ -527,16 +516,17 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
return count; \
}
-DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_lba_count);
-DEF_TB_DEV_ATTRIB_STORE_U32(max_unmap_block_desc_count);
-DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity);
-DEF_TB_DEV_ATTRIB_STORE_U32(unmap_granularity_alignment);
-DEF_TB_DEV_ATTRIB_STORE_U32(max_write_same_len);
+DEF_CONFIGFS_ATTRIB_STORE_U32(max_unmap_lba_count);
+DEF_CONFIGFS_ATTRIB_STORE_U32(max_unmap_block_desc_count);
+DEF_CONFIGFS_ATTRIB_STORE_U32(unmap_granularity);
+DEF_CONFIGFS_ATTRIB_STORE_U32(unmap_granularity_alignment);
+DEF_CONFIGFS_ATTRIB_STORE_U32(max_write_same_len);
-#define DEF_TB_DEV_ATTRIB_STORE_BOOL(_name) \
-static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
+#define DEF_CONFIGFS_ATTRIB_STORE_BOOL(_name) \
+static ssize_t _name##_store(struct config_item *item, const char *page, \
size_t count) \
{ \
+ struct se_dev_attrib *da = to_attrib(item); \
bool flag; \
int ret; \
\
@@ -547,14 +537,14 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
return count; \
}
-DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_fua_write);
-DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_caw);
-DEF_TB_DEV_ATTRIB_STORE_BOOL(emulate_3pc);
-DEF_TB_DEV_ATTRIB_STORE_BOOL(enforce_pr_isids);
-DEF_TB_DEV_ATTRIB_STORE_BOOL(is_nonrot);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_fua_write);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_caw);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_3pc);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(enforce_pr_isids);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(is_nonrot);
-#define DEF_TB_DEV_ATTRIB_STORE_STUB(_name) \
-static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
+#define DEF_CONFIGFS_ATTRIB_STORE_STUB(_name) \
+static ssize_t _name##_store(struct config_item *item, const char *page,\
size_t count) \
{ \
printk_once(KERN_WARNING \
@@ -562,8 +552,8 @@ static ssize_t store_##_name(struct se_dev_attrib *da, const char *page,\
return count; \
}
-DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_dpo);
-DEF_TB_DEV_ATTRIB_STORE_STUB(emulate_fua_read);
+DEF_CONFIGFS_ATTRIB_STORE_STUB(emulate_dpo);
+DEF_CONFIGFS_ATTRIB_STORE_STUB(emulate_fua_read);
static void dev_set_t10_wwn_model_alias(struct se_device *dev)
{
@@ -578,9 +568,10 @@ static void dev_set_t10_wwn_model_alias(struct se_device *dev)
snprintf(&dev->t10_wwn.model[0], 16, "%s", configname);
}
-static ssize_t store_emulate_model_alias(struct se_dev_attrib *da,
+static ssize_t emulate_model_alias_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
struct se_device *dev = da->da_dev;
bool flag;
int ret;
@@ -606,9 +597,10 @@ static ssize_t store_emulate_model_alias(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_write_cache(struct se_dev_attrib *da,
+static ssize_t emulate_write_cache_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -627,9 +619,10 @@ static ssize_t store_emulate_write_cache(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da,
+static ssize_t emulate_ua_intlck_ctrl_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
u32 val;
int ret;
@@ -654,9 +647,10 @@ static ssize_t store_emulate_ua_intlck_ctrl(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_tas(struct se_dev_attrib *da,
+static ssize_t emulate_tas_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -677,9 +671,10 @@ static ssize_t store_emulate_tas(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_tpu(struct se_dev_attrib *da,
+static ssize_t emulate_tpu_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -702,9 +697,10 @@ static ssize_t store_emulate_tpu(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_tpws(struct se_dev_attrib *da,
+static ssize_t emulate_tpws_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -727,9 +723,10 @@ static ssize_t store_emulate_tpws(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_pi_prot_type(struct se_dev_attrib *da,
+static ssize_t pi_prot_type_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
int old_prot = da->pi_prot_type, ret;
struct se_device *dev = da->da_dev;
u32 flag;
@@ -787,9 +784,10 @@ static ssize_t store_pi_prot_type(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_pi_prot_format(struct se_dev_attrib *da,
+static ssize_t pi_prot_format_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
struct se_device *dev = da->da_dev;
bool flag;
int ret;
@@ -824,9 +822,10 @@ static ssize_t store_pi_prot_format(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da,
+static ssize_t force_pr_aptpl_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -845,9 +844,10 @@ static ssize_t store_force_pr_aptpl(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da,
+static ssize_t emulate_rest_reord_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
bool flag;
int ret;
@@ -869,9 +869,10 @@ static ssize_t store_emulate_rest_reord(struct se_dev_attrib *da,
/*
* Note, this can only be called on unexported SE Device Object.
*/
-static ssize_t store_queue_depth(struct se_dev_attrib *da,
+static ssize_t queue_depth_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
struct se_device *dev = da->da_dev;
u32 val;
int ret;
@@ -905,9 +906,10 @@ static ssize_t store_queue_depth(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_optimal_sectors(struct se_dev_attrib *da,
+static ssize_t optimal_sectors_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
u32 val;
int ret;
@@ -934,9 +936,10 @@ static ssize_t store_optimal_sectors(struct se_dev_attrib *da,
return count;
}
-static ssize_t store_block_size(struct se_dev_attrib *da,
+static ssize_t block_size_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_dev_attrib *da = to_attrib(item);
u32 val;
int ret;
@@ -967,50 +970,35 @@ static ssize_t store_block_size(struct se_dev_attrib *da,
return count;
}
-CONFIGFS_EATTR_STRUCT(target_backend_dev_attrib, se_dev_attrib);
-#define TB_DEV_ATTR(_backend, _name, _mode) \
-static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- show_##_name, \
- store_##_name);
-
-#define TB_DEV_ATTR_RO(_backend, _name) \
-static struct target_backend_dev_attrib_attribute _backend##_dev_attrib_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- show_##_name);
-
-TB_DEV_ATTR(target_core, emulate_model_alias, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_dpo, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_fua_write, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_fua_read, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_write_cache, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_ua_intlck_ctrl, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_tas, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_tpu, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_tpws, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_caw, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_3pc, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, pi_prot_type, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR_RO(target_core, hw_pi_prot_type);
-TB_DEV_ATTR(target_core, pi_prot_format, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, enforce_pr_isids, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, is_nonrot, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, emulate_rest_reord, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, force_pr_aptpl, S_IRUGO | S_IWUSR)
-TB_DEV_ATTR_RO(target_core, hw_block_size);
-TB_DEV_ATTR(target_core, block_size, S_IRUGO | S_IWUSR)
-TB_DEV_ATTR_RO(target_core, hw_max_sectors);
-TB_DEV_ATTR(target_core, optimal_sectors, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR_RO(target_core, hw_queue_depth);
-TB_DEV_ATTR(target_core, queue_depth, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, max_unmap_lba_count, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, max_unmap_block_desc_count, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, unmap_granularity, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, unmap_granularity_alignment, S_IRUGO | S_IWUSR);
-TB_DEV_ATTR(target_core, max_write_same_len, S_IRUGO | S_IWUSR);
-
-CONFIGFS_EATTR_STRUCT(target_core_dev_attrib, se_dev_attrib);
-CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
+CONFIGFS_ATTR(, emulate_model_alias);
+CONFIGFS_ATTR(, emulate_dpo);
+CONFIGFS_ATTR(, emulate_fua_write);
+CONFIGFS_ATTR(, emulate_fua_read);
+CONFIGFS_ATTR(, emulate_write_cache);
+CONFIGFS_ATTR(, emulate_ua_intlck_ctrl);
+CONFIGFS_ATTR(, emulate_tas);
+CONFIGFS_ATTR(, emulate_tpu);
+CONFIGFS_ATTR(, emulate_tpws);
+CONFIGFS_ATTR(, emulate_caw);
+CONFIGFS_ATTR(, emulate_3pc);
+CONFIGFS_ATTR(, pi_prot_type);
+CONFIGFS_ATTR_RO(, hw_pi_prot_type);
+CONFIGFS_ATTR(, pi_prot_format);
+CONFIGFS_ATTR(, enforce_pr_isids);
+CONFIGFS_ATTR(, is_nonrot);
+CONFIGFS_ATTR(, emulate_rest_reord);
+CONFIGFS_ATTR(, force_pr_aptpl);
+CONFIGFS_ATTR_RO(, hw_block_size);
+CONFIGFS_ATTR(, block_size);
+CONFIGFS_ATTR_RO(, hw_max_sectors);
+CONFIGFS_ATTR(, optimal_sectors);
+CONFIGFS_ATTR_RO(, hw_queue_depth);
+CONFIGFS_ATTR(, queue_depth);
+CONFIGFS_ATTR(, max_unmap_lba_count);
+CONFIGFS_ATTR(, max_unmap_block_desc_count);
+CONFIGFS_ATTR(, unmap_granularity);
+CONFIGFS_ATTR(, unmap_granularity_alignment);
+CONFIGFS_ATTR(, max_write_same_len);
/*
* dev_attrib attributes for devices using the target core SBC/SPC
@@ -1018,100 +1006,78 @@ CONFIGFS_EATTR_OPS(target_core_dev_attrib, se_dev_attrib, da_group);
* these.
*/
struct configfs_attribute *sbc_attrib_attrs[] = {
- &target_core_dev_attrib_emulate_model_alias.attr,
- &target_core_dev_attrib_emulate_dpo.attr,
- &target_core_dev_attrib_emulate_fua_write.attr,
- &target_core_dev_attrib_emulate_fua_read.attr,
- &target_core_dev_attrib_emulate_write_cache.attr,
- &target_core_dev_attrib_emulate_ua_intlck_ctrl.attr,
- &target_core_dev_attrib_emulate_tas.attr,
- &target_core_dev_attrib_emulate_tpu.attr,
- &target_core_dev_attrib_emulate_tpws.attr,
- &target_core_dev_attrib_emulate_caw.attr,
- &target_core_dev_attrib_emulate_3pc.attr,
- &target_core_dev_attrib_pi_prot_type.attr,
- &target_core_dev_attrib_hw_pi_prot_type.attr,
- &target_core_dev_attrib_pi_prot_format.attr,
- &target_core_dev_attrib_enforce_pr_isids.attr,
- &target_core_dev_attrib_is_nonrot.attr,
- &target_core_dev_attrib_emulate_rest_reord.attr,
- &target_core_dev_attrib_force_pr_aptpl.attr,
- &target_core_dev_attrib_hw_block_size.attr,
- &target_core_dev_attrib_block_size.attr,
- &target_core_dev_attrib_hw_max_sectors.attr,
- &target_core_dev_attrib_optimal_sectors.attr,
- &target_core_dev_attrib_hw_queue_depth.attr,
- &target_core_dev_attrib_queue_depth.attr,
- &target_core_dev_attrib_max_unmap_lba_count.attr,
- &target_core_dev_attrib_max_unmap_block_desc_count.attr,
- &target_core_dev_attrib_unmap_granularity.attr,
- &target_core_dev_attrib_unmap_granularity_alignment.attr,
- &target_core_dev_attrib_max_write_same_len.attr,
+ &attr_emulate_model_alias,
+ &attr_emulate_dpo,
+ &attr_emulate_fua_write,
+ &attr_emulate_fua_read,
+ &attr_emulate_write_cache,
+ &attr_emulate_ua_intlck_ctrl,
+ &attr_emulate_tas,
+ &attr_emulate_tpu,
+ &attr_emulate_tpws,
+ &attr_emulate_caw,
+ &attr_emulate_3pc,
+ &attr_pi_prot_type,
+ &attr_hw_pi_prot_type,
+ &attr_pi_prot_format,
+ &attr_enforce_pr_isids,
+ &attr_is_nonrot,
+ &attr_emulate_rest_reord,
+ &attr_force_pr_aptpl,
+ &attr_hw_block_size,
+ &attr_block_size,
+ &attr_hw_max_sectors,
+ &attr_optimal_sectors,
+ &attr_hw_queue_depth,
+ &attr_queue_depth,
+ &attr_max_unmap_lba_count,
+ &attr_max_unmap_block_desc_count,
+ &attr_unmap_granularity,
+ &attr_unmap_granularity_alignment,
+ &attr_max_write_same_len,
NULL,
};
EXPORT_SYMBOL(sbc_attrib_attrs);
-TB_DEV_ATTR_RO(target_pt, hw_pi_prot_type);
-TB_DEV_ATTR_RO(target_pt, hw_block_size);
-TB_DEV_ATTR_RO(target_pt, hw_max_sectors);
-TB_DEV_ATTR_RO(target_pt, hw_queue_depth);
-
/*
* Minimal dev_attrib attributes for devices passing through CDBs.
* In this case we only provide a few read-only attributes for
* backwards compatibility.
*/
struct configfs_attribute *passthrough_attrib_attrs[] = {
- &target_pt_dev_attrib_hw_pi_prot_type.attr,
- &target_pt_dev_attrib_hw_block_size.attr,
- &target_pt_dev_attrib_hw_max_sectors.attr,
- &target_pt_dev_attrib_hw_queue_depth.attr,
+ &attr_hw_pi_prot_type,
+ &attr_hw_block_size,
+ &attr_hw_max_sectors,
+ &attr_hw_queue_depth,
NULL,
};
EXPORT_SYMBOL(passthrough_attrib_attrs);
-static struct configfs_item_operations target_core_dev_attrib_ops = {
- .show_attribute = target_core_dev_attrib_attr_show,
- .store_attribute = target_core_dev_attrib_attr_store,
-};
-
-TB_CIT_SETUP_DRV(dev_attrib, &target_core_dev_attrib_ops, NULL);
+TB_CIT_SETUP_DRV(dev_attrib, NULL, NULL);
/* End functions for struct config_item_type tb_dev_attrib_cit */
/* Start functions for struct config_item_type tb_dev_wwn_cit */
-CONFIGFS_EATTR_STRUCT(target_core_dev_wwn, t10_wwn);
-#define SE_DEV_WWN_ATTR(_name, _mode) \
-static struct target_core_dev_wwn_attribute target_core_dev_wwn_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_core_dev_wwn_show_attr_##_name, \
- target_core_dev_wwn_store_attr_##_name);
-
-#define SE_DEV_WWN_ATTR_RO(_name); \
-do { \
- static struct target_core_dev_wwn_attribute \
- target_core_dev_wwn_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_core_dev_wwn_show_attr_##_name); \
-} while (0);
+static struct t10_wwn *to_t10_wwn(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct t10_wwn, t10_wwn_group);
+}
/*
* VPD page 0x80 Unit serial
*/
-static ssize_t target_core_dev_wwn_show_attr_vpd_unit_serial(
- struct t10_wwn *t10_wwn,
- char *page)
+static ssize_t target_wwn_vpd_unit_serial_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "T10 VPD Unit Serial Number: %s\n",
- &t10_wwn->unit_serial[0]);
+ &to_t10_wwn(item)->unit_serial[0]);
}
-static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(
- struct t10_wwn *t10_wwn,
- const char *page,
- size_t count)
+static ssize_t target_wwn_vpd_unit_serial_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct t10_wwn *t10_wwn = to_t10_wwn(item);
struct se_device *dev = t10_wwn->t10_dev;
unsigned char buf[INQUIRY_VPD_SERIAL_LEN];
@@ -1167,15 +1133,13 @@ static ssize_t target_core_dev_wwn_store_attr_vpd_unit_serial(
return count;
}
-SE_DEV_WWN_ATTR(vpd_unit_serial, S_IRUGO | S_IWUSR);
-
/*
* VPD page 0x83 Protocol Identifier
*/
-static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(
- struct t10_wwn *t10_wwn,
- char *page)
+static ssize_t target_wwn_vpd_protocol_identifier_show(struct config_item *item,
+ char *page)
{
+ struct t10_wwn *t10_wwn = to_t10_wwn(item);
struct t10_vpd *vpd;
unsigned char buf[VPD_TMP_BUF_SIZE];
ssize_t len = 0;
@@ -1199,25 +1163,15 @@ static ssize_t target_core_dev_wwn_show_attr_vpd_protocol_identifier(
return len;
}
-static ssize_t target_core_dev_wwn_store_attr_vpd_protocol_identifier(
- struct t10_wwn *t10_wwn,
- const char *page,
- size_t count)
-{
- return -ENOSYS;
-}
-
-SE_DEV_WWN_ATTR(vpd_protocol_identifier, S_IRUGO | S_IWUSR);
-
/*
* Generic wrapper for dumping VPD identifiers by association.
*/
#define DEF_DEV_WWN_ASSOC_SHOW(_name, _assoc) \
-static ssize_t target_core_dev_wwn_show_attr_##_name( \
- struct t10_wwn *t10_wwn, \
- char *page) \
+static ssize_t target_wwn_##_name##_show(struct config_item *item, \
+ char *page) \
{ \
- struct t10_vpd *vpd; \
+ struct t10_wwn *t10_wwn = to_t10_wwn(item); \
+ struct t10_vpd *vpd; \
unsigned char buf[VPD_TMP_BUF_SIZE]; \
ssize_t len = 0; \
\
@@ -1249,84 +1203,39 @@ static ssize_t target_core_dev_wwn_show_attr_##_name( \
return len; \
}
-/*
- * VPD page 0x83 Association: Logical Unit
- */
+/* VPD page 0x83 Association: Logical Unit */
DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_logical_unit, 0x00);
-
-static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_logical_unit(
- struct t10_wwn *t10_wwn,
- const char *page,
- size_t count)
-{
- return -ENOSYS;
-}
-
-SE_DEV_WWN_ATTR(vpd_assoc_logical_unit, S_IRUGO | S_IWUSR);
-
-/*
- * VPD page 0x83 Association: Target Port
- */
+/* VPD page 0x83 Association: Target Port */
DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_target_port, 0x10);
-
-static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_target_port(
- struct t10_wwn *t10_wwn,
- const char *page,
- size_t count)
-{
- return -ENOSYS;
-}
-
-SE_DEV_WWN_ATTR(vpd_assoc_target_port, S_IRUGO | S_IWUSR);
-
-/*
- * VPD page 0x83 Association: SCSI Target Device
- */
+/* VPD page 0x83 Association: SCSI Target Device */
DEF_DEV_WWN_ASSOC_SHOW(vpd_assoc_scsi_target_device, 0x20);
-static ssize_t target_core_dev_wwn_store_attr_vpd_assoc_scsi_target_device(
- struct t10_wwn *t10_wwn,
- const char *page,
- size_t count)
-{
- return -ENOSYS;
-}
-
-SE_DEV_WWN_ATTR(vpd_assoc_scsi_target_device, S_IRUGO | S_IWUSR);
-
-CONFIGFS_EATTR_OPS(target_core_dev_wwn, t10_wwn, t10_wwn_group);
+CONFIGFS_ATTR(target_wwn_, vpd_unit_serial);
+CONFIGFS_ATTR_RO(target_wwn_, vpd_protocol_identifier);
+CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_logical_unit);
+CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_target_port);
+CONFIGFS_ATTR_RO(target_wwn_, vpd_assoc_scsi_target_device);
static struct configfs_attribute *target_core_dev_wwn_attrs[] = {
- &target_core_dev_wwn_vpd_unit_serial.attr,
- &target_core_dev_wwn_vpd_protocol_identifier.attr,
- &target_core_dev_wwn_vpd_assoc_logical_unit.attr,
- &target_core_dev_wwn_vpd_assoc_target_port.attr,
- &target_core_dev_wwn_vpd_assoc_scsi_target_device.attr,
+ &target_wwn_attr_vpd_unit_serial,
+ &target_wwn_attr_vpd_protocol_identifier,
+ &target_wwn_attr_vpd_assoc_logical_unit,
+ &target_wwn_attr_vpd_assoc_target_port,
+ &target_wwn_attr_vpd_assoc_scsi_target_device,
NULL,
};
-static struct configfs_item_operations target_core_dev_wwn_ops = {
- .show_attribute = target_core_dev_wwn_attr_show,
- .store_attribute = target_core_dev_wwn_attr_store,
-};
-
-TB_CIT_SETUP(dev_wwn, &target_core_dev_wwn_ops, NULL, target_core_dev_wwn_attrs);
+TB_CIT_SETUP(dev_wwn, NULL, NULL, target_core_dev_wwn_attrs);
/* End functions for struct config_item_type tb_dev_wwn_cit */
/* Start functions for struct config_item_type tb_dev_pr_cit */
-CONFIGFS_EATTR_STRUCT(target_core_dev_pr, se_device);
-#define SE_DEV_PR_ATTR(_name, _mode) \
-static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_core_dev_pr_show_attr_##_name, \
- target_core_dev_pr_store_attr_##_name);
-
-#define SE_DEV_PR_ATTR_RO(_name); \
-static struct target_core_dev_pr_attribute target_core_dev_pr_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_core_dev_pr_show_attr_##_name);
+static struct se_device *pr_to_dev(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_device,
+ dev_pr_group);
+}
static ssize_t target_core_dev_pr_show_spc3_res(struct se_device *dev,
char *page)
@@ -1367,9 +1276,9 @@ static ssize_t target_core_dev_pr_show_spc2_res(struct se_device *dev,
return len;
}
-static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev,
- char *page)
+static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
{
+ struct se_device *dev = pr_to_dev(item);
int ret;
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
@@ -1384,11 +1293,10 @@ static ssize_t target_core_dev_pr_show_attr_res_holder(struct se_device *dev,
return ret;
}
-SE_DEV_PR_ATTR_RO(res_holder);
-
-static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_pr_all_tgt_pts_show(struct config_item *item,
+ char *page)
{
+ struct se_device *dev = pr_to_dev(item);
ssize_t len = 0;
spin_lock(&dev->dev_reservation_lock);
@@ -1406,22 +1314,17 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_all_tgt_pts(
return len;
}
-SE_DEV_PR_ATTR_RO(res_pr_all_tgt_pts);
-
-static ssize_t target_core_dev_pr_show_attr_res_pr_generation(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_pr_generation_show(struct config_item *item,
+ char *page)
{
- return sprintf(page, "0x%08x\n", dev->t10_pr.pr_generation);
+ return sprintf(page, "0x%08x\n", pr_to_dev(item)->t10_pr.pr_generation);
}
-SE_DEV_PR_ATTR_RO(res_pr_generation);
-/*
- * res_pr_holder_tg_port
- */
-static ssize_t target_core_dev_pr_show_attr_res_pr_holder_tg_port(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_pr_holder_tg_port_show(struct config_item *item,
+ char *page)
{
+ struct se_device *dev = pr_to_dev(item);
struct se_node_acl *se_nacl;
struct se_portal_group *se_tpg;
struct t10_pr_registration *pr_reg;
@@ -1453,11 +1356,11 @@ out_unlock:
return len;
}
-SE_DEV_PR_ATTR_RO(res_pr_holder_tg_port);
-static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_pr_registered_i_pts_show(struct config_item *item,
+ char *page)
{
+ struct se_device *dev = pr_to_dev(item);
const struct target_core_fabric_ops *tfo;
struct t10_pr_registration *pr_reg;
unsigned char buf[384];
@@ -1495,11 +1398,9 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_registered_i_pts(
return len;
}
-SE_DEV_PR_ATTR_RO(res_pr_registered_i_pts);
-
-static ssize_t target_core_dev_pr_show_attr_res_pr_type(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_pr_type_show(struct config_item *item, char *page)
{
+ struct se_device *dev = pr_to_dev(item);
struct t10_pr_registration *pr_reg;
ssize_t len = 0;
@@ -1516,11 +1417,10 @@ static ssize_t target_core_dev_pr_show_attr_res_pr_type(
return len;
}
-SE_DEV_PR_ATTR_RO(res_pr_type);
-
-static ssize_t target_core_dev_pr_show_attr_res_type(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
{
+ struct se_device *dev = pr_to_dev(item);
+
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
return sprintf(page, "SPC_PASSTHROUGH\n");
else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
@@ -1529,11 +1429,11 @@ static ssize_t target_core_dev_pr_show_attr_res_type(
return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");
}
-SE_DEV_PR_ATTR_RO(res_type);
-
-static ssize_t target_core_dev_pr_show_attr_res_aptpl_active(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_aptpl_active_show(struct config_item *item,
+ char *page)
{
+ struct se_device *dev = pr_to_dev(item);
+
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
return 0;
@@ -1541,14 +1441,11 @@ static ssize_t target_core_dev_pr_show_attr_res_aptpl_active(
(dev->t10_pr.pr_aptpl_active) ? "Activated" : "Disabled");
}
-SE_DEV_PR_ATTR_RO(res_aptpl_active);
-
-/*
- * res_aptpl_metadata
- */
-static ssize_t target_core_dev_pr_show_attr_res_aptpl_metadata(
- struct se_device *dev, char *page)
+static ssize_t target_pr_res_aptpl_metadata_show(struct config_item *item,
+ char *page)
{
+ struct se_device *dev = pr_to_dev(item);
+
if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
return 0;
@@ -1580,11 +1477,10 @@ static match_table_t tokens = {
{Opt_err, NULL}
};
-static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata(
- struct se_device *dev,
- const char *page,
- size_t count)
+static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_device *dev = pr_to_dev(item);
unsigned char *i_fabric = NULL, *i_port = NULL, *isid = NULL;
unsigned char *t_fabric = NULL, *t_port = NULL;
char *orig, *ptr, *opts;
@@ -1765,37 +1661,44 @@ out:
return (ret == 0) ? count : ret;
}
-SE_DEV_PR_ATTR(res_aptpl_metadata, S_IRUGO | S_IWUSR);
-CONFIGFS_EATTR_OPS(target_core_dev_pr, se_device, dev_pr_group);
+CONFIGFS_ATTR_RO(target_pr_, res_holder);
+CONFIGFS_ATTR_RO(target_pr_, res_pr_all_tgt_pts);
+CONFIGFS_ATTR_RO(target_pr_, res_pr_generation);
+CONFIGFS_ATTR_RO(target_pr_, res_pr_holder_tg_port);
+CONFIGFS_ATTR_RO(target_pr_, res_pr_registered_i_pts);
+CONFIGFS_ATTR_RO(target_pr_, res_pr_type);
+CONFIGFS_ATTR_RO(target_pr_, res_type);
+CONFIGFS_ATTR_RO(target_pr_, res_aptpl_active);
+CONFIGFS_ATTR(target_pr_, res_aptpl_metadata);
static struct configfs_attribute *target_core_dev_pr_attrs[] = {
- &target_core_dev_pr_res_holder.attr,
- &target_core_dev_pr_res_pr_all_tgt_pts.attr,
- &target_core_dev_pr_res_pr_generation.attr,
- &target_core_dev_pr_res_pr_holder_tg_port.attr,
- &target_core_dev_pr_res_pr_registered_i_pts.attr,
- &target_core_dev_pr_res_pr_type.attr,
- &target_core_dev_pr_res_type.attr,
- &target_core_dev_pr_res_aptpl_active.attr,
- &target_core_dev_pr_res_aptpl_metadata.attr,
+ &target_pr_attr_res_holder,
+ &target_pr_attr_res_pr_all_tgt_pts,
+ &target_pr_attr_res_pr_generation,
+ &target_pr_attr_res_pr_holder_tg_port,
+ &target_pr_attr_res_pr_registered_i_pts,
+ &target_pr_attr_res_pr_type,
+ &target_pr_attr_res_type,
+ &target_pr_attr_res_aptpl_active,
+ &target_pr_attr_res_aptpl_metadata,
NULL,
};
-static struct configfs_item_operations target_core_dev_pr_ops = {
- .show_attribute = target_core_dev_pr_attr_show,
- .store_attribute = target_core_dev_pr_attr_store,
-};
-
-TB_CIT_SETUP(dev_pr, &target_core_dev_pr_ops, NULL, target_core_dev_pr_attrs);
+TB_CIT_SETUP(dev_pr, NULL, NULL, target_core_dev_pr_attrs);
/* End functions for struct config_item_type tb_dev_pr_cit */
/* Start functions for struct config_item_type tb_dev_cit */
-static ssize_t target_core_show_dev_info(void *p, char *page)
+static inline struct se_device *to_device(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_device, dev_group);
+}
+
+static ssize_t target_dev_info_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
int bl = 0;
ssize_t read_bytes = 0;
@@ -1806,35 +1709,17 @@ static ssize_t target_core_show_dev_info(void *p, char *page)
return read_bytes;
}
-static struct target_core_configfs_attribute target_core_attr_dev_info = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "info",
- .ca_mode = S_IRUGO },
- .show = target_core_show_dev_info,
- .store = NULL,
-};
-
-static ssize_t target_core_store_dev_control(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_control_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
return dev->transport->set_configfs_dev_params(dev, page, count);
}
-static struct target_core_configfs_attribute target_core_attr_dev_control = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "control",
- .ca_mode = S_IWUSR },
- .show = NULL,
- .store = target_core_store_dev_control,
-};
-
-static ssize_t target_core_show_dev_alias(void *p, char *page)
+static ssize_t target_dev_alias_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
if (!(dev->dev_flags & DF_USING_ALIAS))
return 0;
@@ -1842,12 +1727,10 @@ static ssize_t target_core_show_dev_alias(void *p, char *page)
return snprintf(page, PAGE_SIZE, "%s\n", dev->dev_alias);
}
-static ssize_t target_core_store_dev_alias(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_alias_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct se_hba *hba = dev->se_hba;
ssize_t read_bytes;
@@ -1874,17 +1757,9 @@ static ssize_t target_core_store_dev_alias(
return read_bytes;
}
-static struct target_core_configfs_attribute target_core_attr_dev_alias = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "alias",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = target_core_show_dev_alias,
- .store = target_core_store_dev_alias,
-};
-
-static ssize_t target_core_show_dev_udev_path(void *p, char *page)
+static ssize_t target_dev_udev_path_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
if (!(dev->dev_flags & DF_USING_UDEV_PATH))
return 0;
@@ -1892,12 +1767,10 @@ static ssize_t target_core_show_dev_udev_path(void *p, char *page)
return snprintf(page, PAGE_SIZE, "%s\n", dev->udev_path);
}
-static ssize_t target_core_store_dev_udev_path(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_udev_path_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct se_hba *hba = dev->se_hba;
ssize_t read_bytes;
@@ -1925,27 +1798,17 @@ static ssize_t target_core_store_dev_udev_path(
return read_bytes;
}
-static struct target_core_configfs_attribute target_core_attr_dev_udev_path = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "udev_path",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = target_core_show_dev_udev_path,
- .store = target_core_store_dev_udev_path,
-};
-
-static ssize_t target_core_show_dev_enable(void *p, char *page)
+static ssize_t target_dev_enable_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
return snprintf(page, PAGE_SIZE, "%d\n", !!(dev->dev_flags & DF_CONFIGURED));
}
-static ssize_t target_core_store_dev_enable(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
char *ptr;
int ret;
@@ -1962,17 +1825,9 @@ static ssize_t target_core_store_dev_enable(
return count;
}
-static struct target_core_configfs_attribute target_core_attr_dev_enable = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "enable",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = target_core_show_dev_enable,
- .store = target_core_store_dev_enable,
-};
-
-static ssize_t target_core_show_alua_lu_gp(void *p, char *page)
+static ssize_t target_dev_alua_lu_gp_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct config_item *lu_ci;
struct t10_alua_lu_gp *lu_gp;
struct t10_alua_lu_gp_member *lu_gp_mem;
@@ -1994,12 +1849,10 @@ static ssize_t target_core_show_alua_lu_gp(void *p, char *page)
return len;
}
-static ssize_t target_core_store_alua_lu_gp(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_alua_lu_gp_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct se_hba *hba = dev->se_hba;
struct t10_alua_lu_gp *lu_gp = NULL, *lu_gp_new = NULL;
struct t10_alua_lu_gp_member *lu_gp_mem;
@@ -2076,17 +1929,9 @@ static ssize_t target_core_store_alua_lu_gp(
return count;
}
-static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "alua_lu_gp",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = target_core_show_alua_lu_gp,
- .store = target_core_store_alua_lu_gp,
-};
-
-static ssize_t target_core_show_dev_lba_map(void *p, char *page)
+static ssize_t target_dev_lba_map_show(struct config_item *item, char *page)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct t10_alua_lba_map *map;
struct t10_alua_lba_map_member *mem;
char *b = page;
@@ -2129,12 +1974,10 @@ static ssize_t target_core_show_dev_lba_map(void *p, char *page)
return bl;
}
-static ssize_t target_core_store_dev_lba_map(
- void *p,
- const char *page,
- size_t count)
+static ssize_t target_dev_lba_map_store(struct config_item *item,
+ const char *page, size_t count)
{
- struct se_device *dev = p;
+ struct se_device *dev = to_device(item);
struct t10_alua_lba_map *lba_map = NULL;
struct list_head lba_list;
char *map_entries, *ptr;
@@ -2246,22 +2089,22 @@ out:
return count;
}
-static struct target_core_configfs_attribute target_core_attr_dev_lba_map = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "lba_map",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = target_core_show_dev_lba_map,
- .store = target_core_store_dev_lba_map,
-};
+CONFIGFS_ATTR_RO(target_dev_, info);
+CONFIGFS_ATTR_WO(target_dev_, control);
+CONFIGFS_ATTR(target_dev_, alias);
+CONFIGFS_ATTR(target_dev_, udev_path);
+CONFIGFS_ATTR(target_dev_, enable);
+CONFIGFS_ATTR(target_dev_, alua_lu_gp);
+CONFIGFS_ATTR(target_dev_, lba_map);
static struct configfs_attribute *target_core_dev_attrs[] = {
- &target_core_attr_dev_info.attr,
- &target_core_attr_dev_control.attr,
- &target_core_attr_dev_alias.attr,
- &target_core_attr_dev_udev_path.attr,
- &target_core_attr_dev_enable.attr,
- &target_core_attr_dev_alua_lu_gp.attr,
- &target_core_attr_dev_lba_map.attr,
+ &target_dev_attr_info,
+ &target_dev_attr_control,
+ &target_dev_attr_alias,
+ &target_dev_attr_udev_path,
+ &target_dev_attr_enable,
+ &target_dev_attr_alua_lu_gp,
+ &target_dev_attr_lba_map,
NULL,
};
@@ -2275,42 +2118,8 @@ static void target_core_dev_release(struct config_item *item)
target_free_device(dev);
}
-static ssize_t target_core_dev_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct config_group *dev_cg = to_config_group(item);
- struct se_device *dev =
- container_of(dev_cg, struct se_device, dev_group);
- struct target_core_configfs_attribute *tc_attr = container_of(
- attr, struct target_core_configfs_attribute, attr);
-
- if (!tc_attr->show)
- return -EINVAL;
-
- return tc_attr->show(dev, page);
-}
-
-static ssize_t target_core_dev_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct config_group *dev_cg = to_config_group(item);
- struct se_device *dev =
- container_of(dev_cg, struct se_device, dev_group);
- struct target_core_configfs_attribute *tc_attr = container_of(
- attr, struct target_core_configfs_attribute, attr);
-
- if (!tc_attr->store)
- return -EINVAL;
-
- return tc_attr->store(dev, page, count);
-}
-
static struct configfs_item_operations target_core_dev_item_ops = {
.release = target_core_dev_release,
- .show_attribute = target_core_dev_show,
- .store_attribute = target_core_dev_store,
};
TB_CIT_SETUP(dev, &target_core_dev_item_ops, NULL, target_core_dev_attrs);
@@ -2319,38 +2128,25 @@ TB_CIT_SETUP(dev, &target_core_dev_item_ops, NULL, target_core_dev_attrs);
/* Start functions for struct config_item_type target_core_alua_lu_gp_cit */
-CONFIGFS_EATTR_STRUCT(target_core_alua_lu_gp, t10_alua_lu_gp);
-#define SE_DEV_ALUA_LU_ATTR(_name, _mode) \
-static struct target_core_alua_lu_gp_attribute \
- target_core_alua_lu_gp_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_core_alua_lu_gp_show_attr_##_name, \
- target_core_alua_lu_gp_store_attr_##_name);
-
-#define SE_DEV_ALUA_LU_ATTR_RO(_name) \
-static struct target_core_alua_lu_gp_attribute \
- target_core_alua_lu_gp_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_core_alua_lu_gp_show_attr_##_name);
+static inline struct t10_alua_lu_gp *to_lu_gp(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct t10_alua_lu_gp,
+ lu_gp_group);
+}
-/*
- * lu_gp_id
- */
-static ssize_t target_core_alua_lu_gp_show_attr_lu_gp_id(
- struct t10_alua_lu_gp *lu_gp,
- char *page)
+static ssize_t target_lu_gp_lu_gp_id_show(struct config_item *item, char *page)
{
+ struct t10_alua_lu_gp *lu_gp = to_lu_gp(item);
+
if (!lu_gp->lu_gp_valid_id)
return 0;
-
return sprintf(page, "%hu\n", lu_gp->lu_gp_id);
}
-static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id(
- struct t10_alua_lu_gp *lu_gp,
- const char *page,
- size_t count)
+static ssize_t target_lu_gp_lu_gp_id_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct t10_alua_lu_gp *lu_gp = to_lu_gp(item);
struct config_group *alua_lu_gp_cg = &lu_gp->lu_gp_group;
unsigned long lu_gp_id;
int ret;
@@ -2379,15 +2175,9 @@ static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id(
return count;
}
-SE_DEV_ALUA_LU_ATTR(lu_gp_id, S_IRUGO | S_IWUSR);
-
-/*
- * members
- */
-static ssize_t target_core_alua_lu_gp_show_attr_members(
- struct t10_alua_lu_gp *lu_gp,
- char *page)
+static ssize_t target_lu_gp_members_show(struct config_item *item, char *page)
{
+ struct t10_alua_lu_gp *lu_gp = to_lu_gp(item);
struct se_device *dev;
struct se_hba *hba;
struct t10_alua_lu_gp_member *lu_gp_mem;
@@ -2419,13 +2209,12 @@ static ssize_t target_core_alua_lu_gp_show_attr_members(
return len;
}
-SE_DEV_ALUA_LU_ATTR_RO(members);
-
-CONFIGFS_EATTR_OPS(target_core_alua_lu_gp, t10_alua_lu_gp, lu_gp_group);
+CONFIGFS_ATTR(target_lu_gp_, lu_gp_id);
+CONFIGFS_ATTR_RO(target_lu_gp_, members);
static struct configfs_attribute *target_core_alua_lu_gp_attrs[] = {
- &target_core_alua_lu_gp_lu_gp_id.attr,
- &target_core_alua_lu_gp_members.attr,
+ &target_lu_gp_attr_lu_gp_id,
+ &target_lu_gp_attr_members,
NULL,
};
@@ -2439,8 +2228,6 @@ static void target_core_alua_lu_gp_release(struct config_item *item)
static struct configfs_item_operations target_core_alua_lu_gp_ops = {
.release = target_core_alua_lu_gp_release,
- .show_attribute = target_core_alua_lu_gp_attr_show,
- .store_attribute = target_core_alua_lu_gp_attr_store,
};
static struct config_item_type target_core_alua_lu_gp_cit = {
@@ -2511,36 +2298,23 @@ static struct config_item_type target_core_alua_lu_gps_cit = {
/* Start functions for struct config_item_type target_core_alua_tg_pt_gp_cit */
-CONFIGFS_EATTR_STRUCT(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp);
-#define SE_DEV_ALUA_TG_PT_ATTR(_name, _mode) \
-static struct target_core_alua_tg_pt_gp_attribute \
- target_core_alua_tg_pt_gp_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_core_alua_tg_pt_gp_show_attr_##_name, \
- target_core_alua_tg_pt_gp_store_attr_##_name);
-
-#define SE_DEV_ALUA_TG_PT_ATTR_RO(_name) \
-static struct target_core_alua_tg_pt_gp_attribute \
- target_core_alua_tg_pt_gp_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_core_alua_tg_pt_gp_show_attr_##_name);
+static inline struct t10_alua_tg_pt_gp *to_tg_pt_gp(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct t10_alua_tg_pt_gp,
+ tg_pt_gp_group);
+}
-/*
- * alua_access_state
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_state(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_alua_access_state_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "%d\n",
- atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state));
+ atomic_read(&to_tg_pt_gp(item)->tg_pt_gp_alua_access_state));
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_alua_access_state_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
unsigned long tmp;
int new_state, ret;
@@ -2582,24 +2356,18 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
return (!ret) ? count : -EINVAL;
}
-SE_DEV_ALUA_TG_PT_ATTR(alua_access_state, S_IRUGO | S_IWUSR);
-
-/*
- * alua_access_status
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_status(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_alua_access_status_show(struct config_item *item,
+ char *page)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
return sprintf(page, "%s\n",
core_alua_dump_status(tg_pt_gp->tg_pt_gp_alua_access_status));
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_alua_access_status_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
unsigned long tmp;
int new_status, ret;
@@ -2630,43 +2398,31 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status(
return count;
}
-SE_DEV_ALUA_TG_PT_ATTR(alua_access_status, S_IRUGO | S_IWUSR);
-
-/*
- * alua_access_type
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_access_type(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_alua_access_type_show(struct config_item *item,
+ char *page)
{
- return core_alua_show_access_type(tg_pt_gp, page);
+ return core_alua_show_access_type(to_tg_pt_gp(item), page);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_type(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_alua_access_type_store(struct config_item *item,
+ const char *page, size_t count)
{
- return core_alua_store_access_type(tg_pt_gp, page, count);
+ return core_alua_store_access_type(to_tg_pt_gp(item), page, count);
}
-SE_DEV_ALUA_TG_PT_ATTR(alua_access_type, S_IRUGO | S_IWUSR);
-
-/*
- * alua_supported_states
- */
-
-#define SE_DEV_ALUA_SUPPORT_STATE_SHOW(_name, _var, _bit) \
-static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_support_##_name( \
- struct t10_alua_tg_pt_gp *t, char *p) \
+#define ALUA_SUPPORTED_STATE_ATTR(_name, _bit) \
+static ssize_t target_tg_pt_gp_alua_support_##_name##_show( \
+ struct config_item *item, char *p) \
{ \
- return sprintf(p, "%d\n", !!(t->_var & _bit)); \
-}
-
-#define SE_DEV_ALUA_SUPPORT_STATE_STORE(_name, _var, _bit) \
-static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_support_##_name(\
- struct t10_alua_tg_pt_gp *t, const char *p, size_t c) \
+ struct t10_alua_tg_pt_gp *t = to_tg_pt_gp(item); \
+ return sprintf(p, "%d\n", \
+ !!(t->tg_pt_gp_alua_supported_states & _bit)); \
+} \
+ \
+static ssize_t target_tg_pt_gp_alua_support_##_name##_store( \
+ struct config_item *item, const char *p, size_t c) \
{ \
+ struct t10_alua_tg_pt_gp *t = to_tg_pt_gp(item); \
unsigned long tmp; \
int ret; \
\
@@ -2687,70 +2443,32 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_support_##_name(\
return -EINVAL; \
} \
if (tmp) \
- t->_var |= _bit; \
+ t->tg_pt_gp_alua_supported_states |= _bit; \
else \
- t->_var &= ~_bit; \
+ t->tg_pt_gp_alua_supported_states &= ~_bit; \
\
return c; \
}
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(transitioning,
- tg_pt_gp_alua_supported_states, ALUA_T_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(transitioning,
- tg_pt_gp_alua_supported_states, ALUA_T_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_transitioning, S_IRUGO | S_IWUSR);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(offline,
- tg_pt_gp_alua_supported_states, ALUA_O_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(offline,
- tg_pt_gp_alua_supported_states, ALUA_O_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_offline, S_IRUGO | S_IWUSR);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent,
- tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent,
- tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable,
- tg_pt_gp_alua_supported_states, ALUA_U_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(unavailable,
- tg_pt_gp_alua_supported_states, ALUA_U_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_unavailable, S_IRUGO | S_IWUSR);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(standby,
- tg_pt_gp_alua_supported_states, ALUA_S_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(standby,
- tg_pt_gp_alua_supported_states, ALUA_S_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_standby, S_IRUGO | S_IWUSR);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_optimized,
- tg_pt_gp_alua_supported_states, ALUA_AO_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(active_optimized,
- tg_pt_gp_alua_supported_states, ALUA_AO_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_optimized, S_IRUGO | S_IWUSR);
-
-SE_DEV_ALUA_SUPPORT_STATE_SHOW(active_nonoptimized,
- tg_pt_gp_alua_supported_states, ALUA_AN_SUP);
-SE_DEV_ALUA_SUPPORT_STATE_STORE(active_nonoptimized,
- tg_pt_gp_alua_supported_states, ALUA_AN_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_active_nonoptimized, S_IRUGO | S_IWUSR);
+ALUA_SUPPORTED_STATE_ATTR(transitioning, ALUA_T_SUP);
+ALUA_SUPPORTED_STATE_ATTR(offline, ALUA_O_SUP);
+ALUA_SUPPORTED_STATE_ATTR(lba_dependent, ALUA_LBD_SUP);
+ALUA_SUPPORTED_STATE_ATTR(unavailable, ALUA_U_SUP);
+ALUA_SUPPORTED_STATE_ATTR(standby, ALUA_S_SUP);
+ALUA_SUPPORTED_STATE_ATTR(active_optimized, ALUA_AO_SUP);
+ALUA_SUPPORTED_STATE_ATTR(active_nonoptimized, ALUA_AN_SUP);
-/*
- * alua_write_metadata
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_alua_write_metadata(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_alua_write_metadata_show(
+ struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", tg_pt_gp->tg_pt_gp_write_metadata);
+ return sprintf(page, "%d\n",
+ to_tg_pt_gp(item)->tg_pt_gp_write_metadata);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_alua_write_metadata_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
unsigned long tmp;
int ret;
@@ -2770,110 +2488,71 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata(
return count;
}
-SE_DEV_ALUA_TG_PT_ATTR(alua_write_metadata, S_IRUGO | S_IWUSR);
-
-
-
-/*
- * nonop_delay_msecs
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_nonop_delay_msecs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_nonop_delay_msecs_show(struct config_item *item,
+ char *page)
{
- return core_alua_show_nonop_delay_msecs(tg_pt_gp, page);
-
+ return core_alua_show_nonop_delay_msecs(to_tg_pt_gp(item), page);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_nonop_delay_msecs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_nonop_delay_msecs_store(struct config_item *item,
+ const char *page, size_t count)
{
- return core_alua_store_nonop_delay_msecs(tg_pt_gp, page, count);
+ return core_alua_store_nonop_delay_msecs(to_tg_pt_gp(item), page,
+ count);
}
-SE_DEV_ALUA_TG_PT_ATTR(nonop_delay_msecs, S_IRUGO | S_IWUSR);
-
-/*
- * trans_delay_msecs
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_trans_delay_msecs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_trans_delay_msecs_show(struct config_item *item,
+ char *page)
{
- return core_alua_show_trans_delay_msecs(tg_pt_gp, page);
+ return core_alua_show_trans_delay_msecs(to_tg_pt_gp(item), page);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_trans_delay_msecs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_trans_delay_msecs_store(struct config_item *item,
+ const char *page, size_t count)
{
- return core_alua_store_trans_delay_msecs(tg_pt_gp, page, count);
+ return core_alua_store_trans_delay_msecs(to_tg_pt_gp(item), page,
+ count);
}
-SE_DEV_ALUA_TG_PT_ATTR(trans_delay_msecs, S_IRUGO | S_IWUSR);
-
-/*
- * implicit_trans_secs
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_implicit_trans_secs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_implicit_trans_secs_show(
+ struct config_item *item, char *page)
{
- return core_alua_show_implicit_trans_secs(tg_pt_gp, page);
+ return core_alua_show_implicit_trans_secs(to_tg_pt_gp(item), page);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_implicit_trans_secs(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_implicit_trans_secs_store(
+ struct config_item *item, const char *page, size_t count)
{
- return core_alua_store_implicit_trans_secs(tg_pt_gp, page, count);
+ return core_alua_store_implicit_trans_secs(to_tg_pt_gp(item), page,
+ count);
}
-SE_DEV_ALUA_TG_PT_ATTR(implicit_trans_secs, S_IRUGO | S_IWUSR);
-
-/*
- * preferred
- */
-
-static ssize_t target_core_alua_tg_pt_gp_show_attr_preferred(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_preferred_show(struct config_item *item,
+ char *page)
{
- return core_alua_show_preferred_bit(tg_pt_gp, page);
+ return core_alua_show_preferred_bit(to_tg_pt_gp(item), page);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_preferred(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_preferred_store(struct config_item *item,
+ const char *page, size_t count)
{
- return core_alua_store_preferred_bit(tg_pt_gp, page, count);
+ return core_alua_store_preferred_bit(to_tg_pt_gp(item), page, count);
}
-SE_DEV_ALUA_TG_PT_ATTR(preferred, S_IRUGO | S_IWUSR);
-
-/*
- * tg_pt_gp_id
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_tg_pt_gp_id(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_tg_pt_gp_id_show(struct config_item *item,
+ char *page)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
+
if (!tg_pt_gp->tg_pt_gp_valid_id)
return 0;
-
return sprintf(page, "%hu\n", tg_pt_gp->tg_pt_gp_id);
}
-static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- const char *page,
- size_t count)
+static ssize_t target_tg_pt_gp_tg_pt_gp_id_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
struct config_group *alua_tg_pt_gp_cg = &tg_pt_gp->tg_pt_gp_group;
unsigned long tg_pt_gp_id;
int ret;
@@ -2902,15 +2581,10 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id(
return count;
}
-SE_DEV_ALUA_TG_PT_ATTR(tg_pt_gp_id, S_IRUGO | S_IWUSR);
-
-/*
- * members
- */
-static ssize_t target_core_alua_tg_pt_gp_show_attr_members(
- struct t10_alua_tg_pt_gp *tg_pt_gp,
- char *page)
+static ssize_t target_tg_pt_gp_members_show(struct config_item *item,
+ char *page)
{
+ struct t10_alua_tg_pt_gp *tg_pt_gp = to_tg_pt_gp(item);
struct se_lun *lun;
ssize_t len = 0, cur_len;
unsigned char buf[TG_PT_GROUP_NAME_BUF];
@@ -2942,29 +2616,42 @@ static ssize_t target_core_alua_tg_pt_gp_show_attr_members(
return len;
}
-SE_DEV_ALUA_TG_PT_ATTR_RO(members);
-
-CONFIGFS_EATTR_OPS(target_core_alua_tg_pt_gp, t10_alua_tg_pt_gp,
- tg_pt_gp_group);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_state);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_status);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_access_type);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_transitioning);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_offline);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_lba_dependent);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_unavailable);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_standby);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_optimized);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_support_active_nonoptimized);
+CONFIGFS_ATTR(target_tg_pt_gp_, alua_write_metadata);
+CONFIGFS_ATTR(target_tg_pt_gp_, nonop_delay_msecs);
+CONFIGFS_ATTR(target_tg_pt_gp_, trans_delay_msecs);
+CONFIGFS_ATTR(target_tg_pt_gp_, implicit_trans_secs);
+CONFIGFS_ATTR(target_tg_pt_gp_, preferred);
+CONFIGFS_ATTR(target_tg_pt_gp_, tg_pt_gp_id);
+CONFIGFS_ATTR_RO(target_tg_pt_gp_, members);
static struct configfs_attribute *target_core_alua_tg_pt_gp_attrs[] = {
- &target_core_alua_tg_pt_gp_alua_access_state.attr,
- &target_core_alua_tg_pt_gp_alua_access_status.attr,
- &target_core_alua_tg_pt_gp_alua_access_type.attr,
- &target_core_alua_tg_pt_gp_alua_support_transitioning.attr,
- &target_core_alua_tg_pt_gp_alua_support_offline.attr,
- &target_core_alua_tg_pt_gp_alua_support_lba_dependent.attr,
- &target_core_alua_tg_pt_gp_alua_support_unavailable.attr,
- &target_core_alua_tg_pt_gp_alua_support_standby.attr,
- &target_core_alua_tg_pt_gp_alua_support_active_nonoptimized.attr,
- &target_core_alua_tg_pt_gp_alua_support_active_optimized.attr,
- &target_core_alua_tg_pt_gp_alua_write_metadata.attr,
- &target_core_alua_tg_pt_gp_nonop_delay_msecs.attr,
- &target_core_alua_tg_pt_gp_trans_delay_msecs.attr,
- &target_core_alua_tg_pt_gp_implicit_trans_secs.attr,
- &target_core_alua_tg_pt_gp_preferred.attr,
- &target_core_alua_tg_pt_gp_tg_pt_gp_id.attr,
- &target_core_alua_tg_pt_gp_members.attr,
+ &target_tg_pt_gp_attr_alua_access_state,
+ &target_tg_pt_gp_attr_alua_access_status,
+ &target_tg_pt_gp_attr_alua_access_type,
+ &target_tg_pt_gp_attr_alua_support_transitioning,
+ &target_tg_pt_gp_attr_alua_support_offline,
+ &target_tg_pt_gp_attr_alua_support_lba_dependent,
+ &target_tg_pt_gp_attr_alua_support_unavailable,
+ &target_tg_pt_gp_attr_alua_support_standby,
+ &target_tg_pt_gp_attr_alua_support_active_nonoptimized,
+ &target_tg_pt_gp_attr_alua_support_active_optimized,
+ &target_tg_pt_gp_attr_alua_write_metadata,
+ &target_tg_pt_gp_attr_nonop_delay_msecs,
+ &target_tg_pt_gp_attr_trans_delay_msecs,
+ &target_tg_pt_gp_attr_implicit_trans_secs,
+ &target_tg_pt_gp_attr_preferred,
+ &target_tg_pt_gp_attr_tg_pt_gp_id,
+ &target_tg_pt_gp_attr_members,
NULL,
};
@@ -2978,8 +2665,6 @@ static void target_core_alua_tg_pt_gp_release(struct config_item *item)
static struct configfs_item_operations target_core_alua_tg_pt_gp_ops = {
.release = target_core_alua_tg_pt_gp_release,
- .show_attribute = target_core_alua_tg_pt_gp_attr_show,
- .store_attribute = target_core_alua_tg_pt_gp_attr_store,
};
static struct config_item_type target_core_alua_tg_pt_gp_cit = {
@@ -3237,34 +2922,24 @@ static struct configfs_group_operations target_core_hba_group_ops = {
.drop_item = target_core_drop_subdev,
};
-CONFIGFS_EATTR_STRUCT(target_core_hba, se_hba);
-#define SE_HBA_ATTR(_name, _mode) \
-static struct target_core_hba_attribute \
- target_core_hba_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_core_hba_show_attr_##_name, \
- target_core_hba_store_attr_##_name);
-#define SE_HBA_ATTR_RO(_name) \
-static struct target_core_hba_attribute \
- target_core_hba_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_core_hba_show_attr_##_name);
+static inline struct se_hba *to_hba(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_hba, hba_group);
+}
-static ssize_t target_core_hba_show_attr_hba_info(
- struct se_hba *hba,
- char *page)
+static ssize_t target_hba_info_show(struct config_item *item, char *page)
{
+ struct se_hba *hba = to_hba(item);
+
return sprintf(page, "HBA Index: %d plugin: %s version: %s\n",
hba->hba_id, hba->backend->ops->name,
TARGET_CORE_VERSION);
}
-SE_HBA_ATTR_RO(hba_info);
-
-static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba,
- char *page)
+static ssize_t target_hba_mode_show(struct config_item *item, char *page)
{
+ struct se_hba *hba = to_hba(item);
int hba_mode = 0;
if (hba->hba_flags & HBA_FLAGS_PSCSI_MODE)
@@ -3273,9 +2948,10 @@ static ssize_t target_core_hba_show_attr_hba_mode(struct se_hba *hba,
return sprintf(page, "%d\n", hba_mode);
}
-static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,
- const char *page, size_t count)
+static ssize_t target_hba_mode_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_hba *hba = to_hba(item);
unsigned long mode_flag;
int ret;
@@ -3304,9 +2980,8 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba,
return count;
}
-SE_HBA_ATTR(hba_mode, S_IRUGO | S_IWUSR);
-
-CONFIGFS_EATTR_OPS(target_core_hba, se_hba, hba_group);
+CONFIGFS_ATTR_RO(target_, hba_info);
+CONFIGFS_ATTR(target_, hba_mode);
static void target_core_hba_release(struct config_item *item)
{
@@ -3316,15 +2991,13 @@ static void target_core_hba_release(struct config_item *item)
}
static struct configfs_attribute *target_core_hba_attrs[] = {
- &target_core_hba_hba_info.attr,
- &target_core_hba_hba_mode.attr,
+ &target_attr_hba_info,
+ &target_attr_hba_mode,
NULL,
};
static struct configfs_item_operations target_core_hba_item_ops = {
.release = target_core_hba_release,
- .show_attribute = target_core_hba_attr_show,
- .store_attribute = target_core_hba_attr_store,
};
static struct config_item_type target_core_hba_cit = {
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c
index be42429..f916d18 100644
--- a/drivers/target/target_core_fabric_configfs.c
+++ b/drivers/target/target_core_fabric_configfs.c
@@ -35,8 +35,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include "target_core_internal.h"
#include "target_core_alua.h"
@@ -152,17 +150,16 @@ static int target_fabric_mappedlun_unlink(
return core_dev_del_initiator_node_lun_acl(lun, lacl);
}
-CONFIGFS_EATTR_STRUCT(target_fabric_mappedlun, se_lun_acl);
-#define TCM_MAPPEDLUN_ATTR(_name, _mode) \
-static struct target_fabric_mappedlun_attribute target_fabric_mappedlun_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_fabric_mappedlun_show_##_name, \
- target_fabric_mappedlun_store_##_name);
+static struct se_lun_acl *item_to_lun_acl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_lun_acl,
+ se_lun_group);
+}
-static ssize_t target_fabric_mappedlun_show_write_protect(
- struct se_lun_acl *lacl,
- char *page)
+static ssize_t target_fabric_mappedlun_write_protect_show(
+ struct config_item *item, char *page)
{
+ struct se_lun_acl *lacl = item_to_lun_acl(item);
struct se_node_acl *se_nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t len = 0;
@@ -178,11 +175,10 @@ static ssize_t target_fabric_mappedlun_show_write_protect(
return len;
}
-static ssize_t target_fabric_mappedlun_store_write_protect(
- struct se_lun_acl *lacl,
- const char *page,
- size_t count)
+static ssize_t target_fabric_mappedlun_write_protect_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_lun_acl *lacl = item_to_lun_acl(item);
struct se_node_acl *se_nacl = lacl->se_lun_nacl;
struct se_portal_group *se_tpg = se_nacl->se_tpg;
unsigned long op;
@@ -209,9 +205,12 @@ static ssize_t target_fabric_mappedlun_store_write_protect(
}
-TCM_MAPPEDLUN_ATTR(write_protect, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(target_fabric_mappedlun_, write_protect);
-CONFIGFS_EATTR_OPS(target_fabric_mappedlun, se_lun_acl, se_lun_group);
+static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
+ &target_fabric_mappedlun_attr_write_protect,
+ NULL,
+};
static void target_fabric_mappedlun_release(struct config_item *item)
{
@@ -222,15 +221,8 @@ static void target_fabric_mappedlun_release(struct config_item *item)
core_dev_free_initiator_node_lun_acl(se_tpg, lacl);
}
-static struct configfs_attribute *target_fabric_mappedlun_attrs[] = {
- &target_fabric_mappedlun_write_protect.attr,
- NULL,
-};
-
static struct configfs_item_operations target_fabric_mappedlun_item_ops = {
.release = target_fabric_mappedlun_release,
- .show_attribute = target_fabric_mappedlun_attr_show,
- .store_attribute = target_fabric_mappedlun_attr_store,
.allow_link = target_fabric_mappedlun_link,
.drop_link = target_fabric_mappedlun_unlink,
};
@@ -266,49 +258,12 @@ TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops,
/* End of tfc_tpg_mappedlun_port_cit */
-/* Start of tfc_tpg_nacl_attrib_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group);
-
-static struct configfs_item_operations target_fabric_nacl_attrib_item_ops = {
- .show_attribute = target_fabric_nacl_attrib_attr_show,
- .store_attribute = target_fabric_nacl_attrib_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_nacl_attrib, &target_fabric_nacl_attrib_item_ops, NULL);
-
-/* End of tfc_tpg_nacl_attrib_cit */
-
-/* Start of tfc_tpg_nacl_auth_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_nacl_auth, se_node_acl, acl_auth_group);
-
-static struct configfs_item_operations target_fabric_nacl_auth_item_ops = {
- .show_attribute = target_fabric_nacl_auth_attr_show,
- .store_attribute = target_fabric_nacl_auth_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_nacl_auth, &target_fabric_nacl_auth_item_ops, NULL);
-
-/* End of tfc_tpg_nacl_auth_cit */
-
-/* Start of tfc_tpg_nacl_param_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_nacl_param, se_node_acl, acl_param_group);
-
-static struct configfs_item_operations target_fabric_nacl_param_item_ops = {
- .show_attribute = target_fabric_nacl_param_attr_show,
- .store_attribute = target_fabric_nacl_param_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_nacl_param, &target_fabric_nacl_param_item_ops, NULL);
-
-/* End of tfc_tpg_nacl_param_cit */
+TF_CIT_SETUP_DRV(tpg_nacl_attrib, NULL, NULL);
+TF_CIT_SETUP_DRV(tpg_nacl_auth, NULL, NULL);
+TF_CIT_SETUP_DRV(tpg_nacl_param, NULL, NULL);
/* Start of tfc_tpg_nacl_base_cit */
-CONFIGFS_EATTR_OPS(target_fabric_nacl_base, se_node_acl, acl_group);
-
static struct config_group *target_fabric_make_mappedlun(
struct config_group *group,
const char *name)
@@ -438,8 +393,6 @@ static void target_fabric_nacl_base_release(struct config_item *item)
static struct configfs_item_operations target_fabric_nacl_base_item_ops = {
.release = target_fabric_nacl_base_release,
- .show_attribute = target_fabric_nacl_base_attr_show,
- .store_attribute = target_fabric_nacl_base_attr_store,
};
static struct configfs_group_operations target_fabric_nacl_base_group_ops = {
@@ -540,8 +493,6 @@ TF_CIT_SETUP(tpg_nacl, NULL, &target_fabric_nacl_group_ops, NULL);
/* Start of tfc_tpg_np_base_cit */
-CONFIGFS_EATTR_OPS(target_fabric_np_base, se_tpg_np, tpg_np_group);
-
static void target_fabric_np_base_release(struct config_item *item)
{
struct se_tpg_np *se_tpg_np = container_of(to_config_group(item),
@@ -554,8 +505,6 @@ static void target_fabric_np_base_release(struct config_item *item)
static struct configfs_item_operations target_fabric_np_base_item_ops = {
.release = target_fabric_np_base_release,
- .show_attribute = target_fabric_np_base_attr_show,
- .store_attribute = target_fabric_np_base_attr_store,
};
TF_CIT_SETUP_DRV(tpg_np_base, &target_fabric_np_base_item_ops, NULL);
@@ -610,132 +559,113 @@ TF_CIT_SETUP(tpg_np, NULL, &target_fabric_np_group_ops, NULL);
/* Start of tfc_tpg_port_cit */
-CONFIGFS_EATTR_STRUCT(target_fabric_port, se_lun);
-#define TCM_PORT_ATTR(_name, _mode) \
-static struct target_fabric_port_attribute target_fabric_port_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_fabric_port_show_attr_##_name, \
- target_fabric_port_store_attr_##_name);
-
-#define TCM_PORT_ATTOR_RO(_name) \
- __CONFIGFS_EATTR_RO(_name, \
- target_fabric_port_show_attr_##_name);
+static struct se_lun *item_to_lun(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_lun,
+ lun_group);
+}
-/*
- * alua_tg_pt_gp
- */
-static ssize_t target_fabric_port_show_attr_alua_tg_pt_gp(
- struct se_lun *lun,
- char *page)
+static ssize_t target_fabric_port_alua_tg_pt_gp_show(struct config_item *item,
+ char *page)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_show_tg_pt_gp_info(lun, page);
}
-static ssize_t target_fabric_port_store_attr_alua_tg_pt_gp(
- struct se_lun *lun,
- const char *page,
- size_t count)
+static ssize_t target_fabric_port_alua_tg_pt_gp_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_store_tg_pt_gp_info(lun, page, count);
}
-TCM_PORT_ATTR(alua_tg_pt_gp, S_IRUGO | S_IWUSR);
-
-/*
- * alua_tg_pt_offline
- */
-static ssize_t target_fabric_port_show_attr_alua_tg_pt_offline(
- struct se_lun *lun,
- char *page)
+static ssize_t target_fabric_port_alua_tg_pt_offline_show(
+ struct config_item *item, char *page)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_show_offline_bit(lun, page);
}
-static ssize_t target_fabric_port_store_attr_alua_tg_pt_offline(
- struct se_lun *lun,
- const char *page,
- size_t count)
+static ssize_t target_fabric_port_alua_tg_pt_offline_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_store_offline_bit(lun, page, count);
}
-TCM_PORT_ATTR(alua_tg_pt_offline, S_IRUGO | S_IWUSR);
-
-/*
- * alua_tg_pt_status
- */
-static ssize_t target_fabric_port_show_attr_alua_tg_pt_status(
- struct se_lun *lun,
- char *page)
+static ssize_t target_fabric_port_alua_tg_pt_status_show(
+ struct config_item *item, char *page)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_show_secondary_status(lun, page);
}
-static ssize_t target_fabric_port_store_attr_alua_tg_pt_status(
- struct se_lun *lun,
- const char *page,
- size_t count)
+static ssize_t target_fabric_port_alua_tg_pt_status_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_store_secondary_status(lun, page, count);
}
-TCM_PORT_ATTR(alua_tg_pt_status, S_IRUGO | S_IWUSR);
-
-/*
- * alua_tg_pt_write_md
- */
-static ssize_t target_fabric_port_show_attr_alua_tg_pt_write_md(
- struct se_lun *lun,
- char *page)
+static ssize_t target_fabric_port_alua_tg_pt_write_md_show(
+ struct config_item *item, char *page)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_show_secondary_write_metadata(lun, page);
}
-static ssize_t target_fabric_port_store_attr_alua_tg_pt_write_md(
- struct se_lun *lun,
- const char *page,
- size_t count)
+static ssize_t target_fabric_port_alua_tg_pt_write_md_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_lun *lun = item_to_lun(item);
+
if (!lun || !lun->lun_se_dev)
return -ENODEV;
return core_alua_store_secondary_write_metadata(lun, page, count);
}
-TCM_PORT_ATTR(alua_tg_pt_write_md, S_IRUGO | S_IWUSR);
-
+CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_gp);
+CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_offline);
+CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_status);
+CONFIGFS_ATTR(target_fabric_port_, alua_tg_pt_write_md);
static struct configfs_attribute *target_fabric_port_attrs[] = {
- &target_fabric_port_alua_tg_pt_gp.attr,
- &target_fabric_port_alua_tg_pt_offline.attr,
- &target_fabric_port_alua_tg_pt_status.attr,
- &target_fabric_port_alua_tg_pt_write_md.attr,
+ &target_fabric_port_attr_alua_tg_pt_gp,
+ &target_fabric_port_attr_alua_tg_pt_offline,
+ &target_fabric_port_attr_alua_tg_pt_status,
+ &target_fabric_port_attr_alua_tg_pt_write_md,
NULL,
};
-CONFIGFS_EATTR_OPS(target_fabric_port, se_lun, lun_group);
-
static int target_fabric_port_link(
struct config_item *lun_ci,
struct config_item *se_dev_ci)
@@ -821,8 +751,6 @@ static void target_fabric_port_release(struct config_item *item)
}
static struct configfs_item_operations target_fabric_port_item_ops = {
- .show_attribute = target_fabric_port_attr_show,
- .store_attribute = target_fabric_port_attr_store,
.release = target_fabric_port_release,
.allow_link = target_fabric_port_link,
.drop_link = target_fabric_port_unlink,
@@ -952,50 +880,11 @@ TF_CIT_SETUP(tpg_lun, NULL, &target_fabric_lun_group_ops, NULL);
/* End of tfc_tpg_lun_cit */
-/* Start of tfc_tpg_attrib_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_tpg_attrib, se_portal_group, tpg_attrib_group);
-
-static struct configfs_item_operations target_fabric_tpg_attrib_item_ops = {
- .show_attribute = target_fabric_tpg_attrib_attr_show,
- .store_attribute = target_fabric_tpg_attrib_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_attrib, &target_fabric_tpg_attrib_item_ops, NULL);
-
-/* End of tfc_tpg_attrib_cit */
-
-/* Start of tfc_tpg_auth_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_tpg_auth, se_portal_group, tpg_auth_group);
-
-static struct configfs_item_operations target_fabric_tpg_auth_item_ops = {
- .show_attribute = target_fabric_tpg_auth_attr_show,
- .store_attribute = target_fabric_tpg_auth_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_auth, &target_fabric_tpg_auth_item_ops, NULL);
-
-/* End of tfc_tpg_attrib_cit */
-
-/* Start of tfc_tpg_param_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_tpg_param, se_portal_group, tpg_param_group);
-
-static struct configfs_item_operations target_fabric_tpg_param_item_ops = {
- .show_attribute = target_fabric_tpg_param_attr_show,
- .store_attribute = target_fabric_tpg_param_attr_store,
-};
-
-TF_CIT_SETUP_DRV(tpg_param, &target_fabric_tpg_param_item_ops, NULL);
-
-/* End of tfc_tpg_param_cit */
+TF_CIT_SETUP_DRV(tpg_attrib, NULL, NULL);
+TF_CIT_SETUP_DRV(tpg_auth, NULL, NULL);
+TF_CIT_SETUP_DRV(tpg_param, NULL, NULL);
/* Start of tfc_tpg_base_cit */
-/*
- * For use with TF_TPG_ATTR() and TF_TPG_ATTR_RO()
- */
-CONFIGFS_EATTR_OPS(target_fabric_tpg, se_portal_group, tpg_group);
static void target_fabric_tpg_release(struct config_item *item)
{
@@ -1009,8 +898,6 @@ static void target_fabric_tpg_release(struct config_item *item)
static struct configfs_item_operations target_fabric_tpg_base_item_ops = {
.release = target_fabric_tpg_release,
- .show_attribute = target_fabric_tpg_attr_show,
- .store_attribute = target_fabric_tpg_attr_store,
};
TF_CIT_SETUP_DRV(tpg_base, &target_fabric_tpg_base_item_ops, NULL);
@@ -1176,33 +1063,9 @@ static struct configfs_group_operations target_fabric_wwn_group_ops = {
.make_group = target_fabric_make_wwn,
.drop_item = target_fabric_drop_wwn,
};
-/*
- * For use with TF_WWN_ATTR() and TF_WWN_ATTR_RO()
- */
-CONFIGFS_EATTR_OPS(target_fabric_wwn, target_fabric_configfs, tf_group);
-
-static struct configfs_item_operations target_fabric_wwn_item_ops = {
- .show_attribute = target_fabric_wwn_attr_show,
- .store_attribute = target_fabric_wwn_attr_store,
-};
-
-TF_CIT_SETUP_DRV(wwn, &target_fabric_wwn_item_ops, &target_fabric_wwn_group_ops);
-
-/* End of tfc_wwn_cit */
-
-/* Start of tfc_discovery_cit */
-
-CONFIGFS_EATTR_OPS(target_fabric_discovery, target_fabric_configfs,
- tf_disc_group);
-
-static struct configfs_item_operations target_fabric_discovery_item_ops = {
- .show_attribute = target_fabric_discovery_attr_show,
- .store_attribute = target_fabric_discovery_attr_store,
-};
-
-TF_CIT_SETUP_DRV(discovery, &target_fabric_discovery_item_ops, NULL);
-/* End of tfc_discovery_cit */
+TF_CIT_SETUP_DRV(wwn, NULL, &target_fabric_wwn_group_ops);
+TF_CIT_SETUP_DRV(discovery, NULL, NULL);
int target_fabric_setup_cits(struct target_fabric_configfs *tf)
{
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h
index 99c24ac..dae0750c 100644
--- a/drivers/target/target_core_internal.h
+++ b/drivers/target/target_core_internal.h
@@ -87,6 +87,9 @@ void target_free_device(struct se_device *);
/* target_core_configfs.c */
void target_setup_backend_cits(struct target_backend *);
+/* target_core_fabric_configfs.c */
+int target_fabric_setup_cits(struct target_fabric_configfs *);
+
/* target_core_fabric_lib.c */
int target_get_pr_transport_id_len(struct se_node_acl *nacl,
struct t10_pr_registration *pr_reg, int *format_code);
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 0b4b2a6..98698d8 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -371,7 +371,8 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
return 0;
}
-static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success)
+static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd, bool success,
+ int *post_ret)
{
unsigned char *buf, *addr;
struct scatterlist *sg;
@@ -437,7 +438,8 @@ sbc_execute_rw(struct se_cmd *cmd)
cmd->data_direction);
}
-static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
+static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success,
+ int *post_ret)
{
struct se_device *dev = cmd->se_dev;
@@ -447,8 +449,10 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
* sent to the backend driver.
*/
spin_lock_irq(&cmd->t_state_lock);
- if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status)
+ if ((cmd->transport_state & CMD_T_SENT) && !cmd->scsi_status) {
cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST;
+ *post_ret = 1;
+ }
spin_unlock_irq(&cmd->t_state_lock);
/*
@@ -460,7 +464,8 @@ static sense_reason_t compare_and_write_post(struct se_cmd *cmd, bool success)
return TCM_NO_SENSE;
}
-static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success)
+static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool success,
+ int *post_ret)
{
struct se_device *dev = cmd->se_dev;
struct scatterlist *write_sg = NULL, *sg;
@@ -556,11 +561,11 @@ static sense_reason_t compare_and_write_callback(struct se_cmd *cmd, bool succes
if (block_size < PAGE_SIZE) {
sg_set_page(&write_sg[i], m.page, block_size,
- block_size);
+ m.piter.sg->offset + block_size);
} else {
sg_miter_next(&m);
sg_set_page(&write_sg[i], m.page, block_size,
- 0);
+ m.piter.sg->offset);
}
len -= block_size;
i++;
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c
index 20ed5d2..81a6b3e 100644
--- a/drivers/target/target_core_stat.c
+++ b/drivers/target/target_core_stat.c
@@ -37,7 +37,6 @@
#include <target/target_core_base.h>
#include <target/target_core_backend.h>
#include <target/target_core_fabric.h>
-#include <target/configfs_macros.h>
#include "target_core_internal.h"
@@ -55,75 +54,49 @@
* SCSI Device Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps);
-#define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \
-static struct target_stat_scsi_dev_attribute \
- target_stat_scsi_dev_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_dev_show_attr_##_name, \
- target_stat_scsi_dev_store_attr_##_name);
-
-#define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \
-static struct target_stat_scsi_dev_attribute \
- target_stat_scsi_dev_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_dev_show_attr_##_name);
+static struct se_device *to_stat_dev(struct config_item *item)
+{
+ struct se_dev_stat_grps *sgrps = container_of(to_config_group(item),
+ struct se_dev_stat_grps, scsi_dev_group);
+ return container_of(sgrps, struct se_device, dev_stat_grps);
+}
-static ssize_t target_stat_scsi_dev_show_attr_inst(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_inst_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
- struct se_hba *hba = dev->se_hba;
+ struct se_hba *hba = to_stat_dev(item)->se_hba;
return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
}
-DEV_STAT_SCSI_DEV_ATTR_RO(inst);
-static ssize_t target_stat_scsi_dev_show_attr_indx(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_indx_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
+ return snprintf(page, PAGE_SIZE, "%u\n", to_stat_dev(item)->dev_index);
}
-DEV_STAT_SCSI_DEV_ATTR_RO(indx);
-static ssize_t target_stat_scsi_dev_show_attr_role(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_role_show(struct config_item *item, char *page)
{
return snprintf(page, PAGE_SIZE, "Target\n");
}
-DEV_STAT_SCSI_DEV_ATTR_RO(role);
-static ssize_t target_stat_scsi_dev_show_attr_ports(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_ports_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", dev->export_count);
+ return snprintf(page, PAGE_SIZE, "%u\n", to_stat_dev(item)->export_count);
}
-DEV_STAT_SCSI_DEV_ATTR_RO(ports);
-CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group);
+CONFIGFS_ATTR_RO(target_stat_, inst);
+CONFIGFS_ATTR_RO(target_stat_, indx);
+CONFIGFS_ATTR_RO(target_stat_, role);
+CONFIGFS_ATTR_RO(target_stat_, ports);
static struct configfs_attribute *target_stat_scsi_dev_attrs[] = {
- &target_stat_scsi_dev_inst.attr,
- &target_stat_scsi_dev_indx.attr,
- &target_stat_scsi_dev_role.attr,
- &target_stat_scsi_dev_ports.attr,
+ &target_stat_attr_inst,
+ &target_stat_attr_indx,
+ &target_stat_attr_role,
+ &target_stat_attr_ports,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = {
- .show_attribute = target_stat_scsi_dev_attr_show,
- .store_attribute = target_stat_scsi_dev_attr_store,
-};
-
static struct config_item_type target_stat_scsi_dev_cit = {
- .ct_item_ops = &target_stat_scsi_dev_attrib_ops,
.ct_attrs = target_stat_scsi_dev_attrs,
.ct_owner = THIS_MODULE,
};
@@ -131,109 +104,78 @@ static struct config_item_type target_stat_scsi_dev_cit = {
/*
* SCSI Target Device Table
*/
+static struct se_device *to_stat_tgt_dev(struct config_item *item)
+{
+ struct se_dev_stat_grps *sgrps = container_of(to_config_group(item),
+ struct se_dev_stat_grps, scsi_tgt_dev_group);
+ return container_of(sgrps, struct se_device, dev_stat_grps);
+}
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps);
-#define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \
-static struct target_stat_scsi_tgt_dev_attribute \
- target_stat_scsi_tgt_dev_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_tgt_dev_show_attr_##_name, \
- target_stat_scsi_tgt_dev_store_attr_##_name);
-
-#define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \
-static struct target_stat_scsi_tgt_dev_attribute \
- target_stat_scsi_tgt_dev_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_tgt_dev_show_attr_##_name);
-
-static ssize_t target_stat_scsi_tgt_dev_show_attr_inst(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_inst_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
- struct se_hba *hba = dev->se_hba;
+ struct se_hba *hba = to_stat_tgt_dev(item)->se_hba;
return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst);
-static ssize_t target_stat_scsi_tgt_dev_show_attr_indx(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_indx_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
+ return snprintf(page, PAGE_SIZE, "%u\n", to_stat_tgt_dev(item)->dev_index);
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx);
-static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_num_lus_show(struct config_item *item,
+ char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT);
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus);
-static ssize_t target_stat_scsi_tgt_dev_show_attr_status(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_status_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
- if (dev->export_count)
+ if (to_stat_tgt_dev(item)->export_count)
return snprintf(page, PAGE_SIZE, "activated");
else
return snprintf(page, PAGE_SIZE, "deactivated");
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status);
-static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_non_access_lus_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
int non_accessible_lus;
- if (dev->export_count)
+ if (to_stat_tgt_dev(item)->export_count)
non_accessible_lus = 0;
else
non_accessible_lus = 1;
return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus);
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus);
-static ssize_t target_stat_scsi_tgt_dev_show_attr_resets(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_tgt_resets_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
return snprintf(page, PAGE_SIZE, "%lu\n",
- atomic_long_read(&dev->num_resets));
+ atomic_long_read(&to_stat_tgt_dev(item)->num_resets));
}
-DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets);
-
-CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group);
+CONFIGFS_ATTR_RO(target_stat_tgt_, inst);
+CONFIGFS_ATTR_RO(target_stat_tgt_, indx);
+CONFIGFS_ATTR_RO(target_stat_tgt_, num_lus);
+CONFIGFS_ATTR_RO(target_stat_tgt_, status);
+CONFIGFS_ATTR_RO(target_stat_tgt_, non_access_lus);
+CONFIGFS_ATTR_RO(target_stat_tgt_, resets);
static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = {
- &target_stat_scsi_tgt_dev_inst.attr,
- &target_stat_scsi_tgt_dev_indx.attr,
- &target_stat_scsi_tgt_dev_num_lus.attr,
- &target_stat_scsi_tgt_dev_status.attr,
- &target_stat_scsi_tgt_dev_non_access_lus.attr,
- &target_stat_scsi_tgt_dev_resets.attr,
+ &target_stat_tgt_attr_inst,
+ &target_stat_tgt_attr_indx,
+ &target_stat_tgt_attr_num_lus,
+ &target_stat_tgt_attr_status,
+ &target_stat_tgt_attr_non_access_lus,
+ &target_stat_tgt_attr_resets,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = {
- .show_attribute = target_stat_scsi_tgt_dev_attr_show,
- .store_attribute = target_stat_scsi_tgt_dev_attr_store,
-};
-
static struct config_item_type target_stat_scsi_tgt_dev_cit = {
- .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops,
.ct_attrs = target_stat_scsi_tgt_dev_attrs,
.ct_owner = THIS_MODULE,
};
@@ -242,72 +184,50 @@ static struct config_item_type target_stat_scsi_tgt_dev_cit = {
* SCSI Logical Unit Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps);
-#define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \
-static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_lu_show_attr_##_name, \
- target_stat_scsi_lu_store_attr_##_name);
-
-#define DEV_STAT_SCSI_LU_ATTR_RO(_name) \
-static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_lu_show_attr_##_name);
+static struct se_device *to_stat_lu_dev(struct config_item *item)
+{
+ struct se_dev_stat_grps *sgrps = container_of(to_config_group(item),
+ struct se_dev_stat_grps, scsi_lu_group);
+ return container_of(sgrps, struct se_device, dev_stat_grps);
+}
-static ssize_t target_stat_scsi_lu_show_attr_inst(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_inst_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
- struct se_hba *hba = dev->se_hba;
+ struct se_hba *hba = to_stat_lu_dev(item)->se_hba;
return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index);
}
-DEV_STAT_SCSI_LU_ATTR_RO(inst);
-static ssize_t target_stat_scsi_lu_show_attr_dev(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_dev_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
-
- return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index);
+ return snprintf(page, PAGE_SIZE, "%u\n",
+ to_stat_lu_dev(item)->dev_index);
}
-DEV_STAT_SCSI_LU_ATTR_RO(dev);
-static ssize_t target_stat_scsi_lu_show_attr_indx(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_indx_show(struct config_item *item, char *page)
{
return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX);
}
-DEV_STAT_SCSI_LU_ATTR_RO(indx);
-static ssize_t target_stat_scsi_lu_show_attr_lun(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_lun_show(struct config_item *item, char *page)
{
/* FIXME: scsiLuDefaultLun */
return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0);
}
-DEV_STAT_SCSI_LU_ATTR_RO(lun);
-static ssize_t target_stat_scsi_lu_show_attr_lu_name(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_lu_name_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuWwnName */
return snprintf(page, PAGE_SIZE, "%s\n",
(strlen(dev->t10_wwn.unit_serial)) ?
dev->t10_wwn.unit_serial : "None");
}
-DEV_STAT_SCSI_LU_ATTR_RO(lu_name);
-static ssize_t target_stat_scsi_lu_show_attr_vend(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_vend_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
int i;
char str[sizeof(dev->t10_wwn.vendor)+1];
@@ -318,30 +238,24 @@ static ssize_t target_stat_scsi_lu_show_attr_vend(
str[i] = '\0';
return snprintf(page, PAGE_SIZE, "%s\n", str);
}
-DEV_STAT_SCSI_LU_ATTR_RO(vend);
-static ssize_t target_stat_scsi_lu_show_attr_prod(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_prod_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
int i;
char str[sizeof(dev->t10_wwn.model)+1];
/* scsiLuProductId */
- for (i = 0; i < sizeof(dev->t10_wwn.vendor); i++)
+ for (i = 0; i < sizeof(dev->t10_wwn.model); i++)
str[i] = ISPRINT(dev->t10_wwn.model[i]) ?
dev->t10_wwn.model[i] : ' ';
str[i] = '\0';
return snprintf(page, PAGE_SIZE, "%s\n", str);
}
-DEV_STAT_SCSI_LU_ATTR_RO(prod);
-static ssize_t target_stat_scsi_lu_show_attr_rev(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_rev_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
int i;
char str[sizeof(dev->t10_wwn.revision)+1];
@@ -352,146 +266,137 @@ static ssize_t target_stat_scsi_lu_show_attr_rev(
str[i] = '\0';
return snprintf(page, PAGE_SIZE, "%s\n", str);
}
-DEV_STAT_SCSI_LU_ATTR_RO(rev);
-static ssize_t target_stat_scsi_lu_show_attr_dev_type(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_dev_type_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuPeripheralType */
return snprintf(page, PAGE_SIZE, "%u\n",
dev->transport->get_device_type(dev));
}
-DEV_STAT_SCSI_LU_ATTR_RO(dev_type);
-static ssize_t target_stat_scsi_lu_show_attr_status(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_status_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuStatus */
return snprintf(page, PAGE_SIZE, "%s\n",
(dev->export_count) ? "available" : "notavailable");
}
-DEV_STAT_SCSI_LU_ATTR_RO(status);
-static ssize_t target_stat_scsi_lu_show_attr_state_bit(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_state_bit_show(struct config_item *item,
+ char *page)
{
/* scsiLuState */
return snprintf(page, PAGE_SIZE, "exposed\n");
}
-DEV_STAT_SCSI_LU_ATTR_RO(state_bit);
-static ssize_t target_stat_scsi_lu_show_attr_num_cmds(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_num_cmds_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuNumCommands */
return snprintf(page, PAGE_SIZE, "%lu\n",
atomic_long_read(&dev->num_cmds));
}
-DEV_STAT_SCSI_LU_ATTR_RO(num_cmds);
-static ssize_t target_stat_scsi_lu_show_attr_read_mbytes(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_read_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuReadMegaBytes */
return snprintf(page, PAGE_SIZE, "%lu\n",
atomic_long_read(&dev->read_bytes) >> 20);
}
-DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes);
-static ssize_t target_stat_scsi_lu_show_attr_write_mbytes(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_write_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuWrittenMegaBytes */
return snprintf(page, PAGE_SIZE, "%lu\n",
atomic_long_read(&dev->write_bytes) >> 20);
}
-DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes);
-static ssize_t target_stat_scsi_lu_show_attr_resets(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_resets_show(struct config_item *item, char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuInResets */
- return snprintf(page, PAGE_SIZE, "%lu\n", atomic_long_read(&dev->num_resets));
+ return snprintf(page, PAGE_SIZE, "%lu\n",
+ atomic_long_read(&dev->num_resets));
}
-DEV_STAT_SCSI_LU_ATTR_RO(resets);
-static ssize_t target_stat_scsi_lu_show_attr_full_stat(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_full_stat_show(struct config_item *item,
+ char *page)
{
/* FIXME: scsiLuOutTaskSetFullStatus */
return snprintf(page, PAGE_SIZE, "%u\n", 0);
}
-DEV_STAT_SCSI_LU_ATTR_RO(full_stat);
-static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_hs_num_cmds_show(struct config_item *item,
+ char *page)
{
/* FIXME: scsiLuHSInCommands */
return snprintf(page, PAGE_SIZE, "%u\n", 0);
}
-DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds);
-static ssize_t target_stat_scsi_lu_show_attr_creation_time(
- struct se_dev_stat_grps *sgrps, char *page)
+static ssize_t target_stat_lu_creation_time_show(struct config_item *item,
+ char *page)
{
- struct se_device *dev =
- container_of(sgrps, struct se_device, dev_stat_grps);
+ struct se_device *dev = to_stat_lu_dev(item);
/* scsiLuCreationTime */
return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time -
INITIAL_JIFFIES) * 100 / HZ));
}
-DEV_STAT_SCSI_LU_ATTR_RO(creation_time);
-CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group);
+CONFIGFS_ATTR_RO(target_stat_lu_, inst);
+CONFIGFS_ATTR_RO(target_stat_lu_, dev);
+CONFIGFS_ATTR_RO(target_stat_lu_, indx);
+CONFIGFS_ATTR_RO(target_stat_lu_, lun);
+CONFIGFS_ATTR_RO(target_stat_lu_, lu_name);
+CONFIGFS_ATTR_RO(target_stat_lu_, vend);
+CONFIGFS_ATTR_RO(target_stat_lu_, prod);
+CONFIGFS_ATTR_RO(target_stat_lu_, rev);
+CONFIGFS_ATTR_RO(target_stat_lu_, dev_type);
+CONFIGFS_ATTR_RO(target_stat_lu_, status);
+CONFIGFS_ATTR_RO(target_stat_lu_, state_bit);
+CONFIGFS_ATTR_RO(target_stat_lu_, num_cmds);
+CONFIGFS_ATTR_RO(target_stat_lu_, read_mbytes);
+CONFIGFS_ATTR_RO(target_stat_lu_, write_mbytes);
+CONFIGFS_ATTR_RO(target_stat_lu_, resets);
+CONFIGFS_ATTR_RO(target_stat_lu_, full_stat);
+CONFIGFS_ATTR_RO(target_stat_lu_, hs_num_cmds);
+CONFIGFS_ATTR_RO(target_stat_lu_, creation_time);
static struct configfs_attribute *target_stat_scsi_lu_attrs[] = {
- &target_stat_scsi_lu_inst.attr,
- &target_stat_scsi_lu_dev.attr,
- &target_stat_scsi_lu_indx.attr,
- &target_stat_scsi_lu_lun.attr,
- &target_stat_scsi_lu_lu_name.attr,
- &target_stat_scsi_lu_vend.attr,
- &target_stat_scsi_lu_prod.attr,
- &target_stat_scsi_lu_rev.attr,
- &target_stat_scsi_lu_dev_type.attr,
- &target_stat_scsi_lu_status.attr,
- &target_stat_scsi_lu_state_bit.attr,
- &target_stat_scsi_lu_num_cmds.attr,
- &target_stat_scsi_lu_read_mbytes.attr,
- &target_stat_scsi_lu_write_mbytes.attr,
- &target_stat_scsi_lu_resets.attr,
- &target_stat_scsi_lu_full_stat.attr,
- &target_stat_scsi_lu_hs_num_cmds.attr,
- &target_stat_scsi_lu_creation_time.attr,
+ &target_stat_lu_attr_inst,
+ &target_stat_lu_attr_dev,
+ &target_stat_lu_attr_indx,
+ &target_stat_lu_attr_lun,
+ &target_stat_lu_attr_lu_name,
+ &target_stat_lu_attr_vend,
+ &target_stat_lu_attr_prod,
+ &target_stat_lu_attr_rev,
+ &target_stat_lu_attr_dev_type,
+ &target_stat_lu_attr_status,
+ &target_stat_lu_attr_state_bit,
+ &target_stat_lu_attr_num_cmds,
+ &target_stat_lu_attr_read_mbytes,
+ &target_stat_lu_attr_write_mbytes,
+ &target_stat_lu_attr_resets,
+ &target_stat_lu_attr_full_stat,
+ &target_stat_lu_attr_hs_num_cmds,
+ &target_stat_lu_attr_creation_time,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = {
- .show_attribute = target_stat_scsi_lu_attr_show,
- .store_attribute = target_stat_scsi_lu_attr_store,
-};
-
static struct config_item_type target_stat_scsi_lu_cit = {
- .ct_item_ops = &target_stat_scsi_lu_attrib_ops,
.ct_attrs = target_stat_scsi_lu_attrs,
.ct_owner = THIS_MODULE,
};
@@ -521,24 +426,16 @@ void target_stat_setup_dev_default_groups(struct se_device *dev)
* SCSI Port Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps);
-#define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \
-static struct target_stat_scsi_port_attribute \
- target_stat_scsi_port_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_port_show_attr_##_name, \
- target_stat_scsi_port_store_attr_##_name);
-
-#define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \
-static struct target_stat_scsi_port_attribute \
- target_stat_scsi_port_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_port_show_attr_##_name);
+static struct se_lun *to_stat_port(struct config_item *item)
+{
+ struct se_port_stat_grps *pgrps = container_of(to_config_group(item),
+ struct se_port_stat_grps, scsi_port_group);
+ return container_of(pgrps, struct se_lun, port_stat_grps);
+}
-static ssize_t target_stat_scsi_port_show_attr_inst(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_port_inst_show(struct config_item *item, char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -549,12 +446,10 @@ static ssize_t target_stat_scsi_port_show_attr_inst(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_PORT_ATTR_RO(inst);
-static ssize_t target_stat_scsi_port_show_attr_dev(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_port_dev_show(struct config_item *item, char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -565,12 +460,10 @@ static ssize_t target_stat_scsi_port_show_attr_dev(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_PORT_ATTR_RO(dev);
-static ssize_t target_stat_scsi_port_show_attr_indx(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_port_indx_show(struct config_item *item, char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -581,12 +474,10 @@ static ssize_t target_stat_scsi_port_show_attr_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_PORT_ATTR_RO(indx);
-static ssize_t target_stat_scsi_port_show_attr_role(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_port_role_show(struct config_item *item, char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -597,12 +488,11 @@ static ssize_t target_stat_scsi_port_show_attr_role(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_PORT_ATTR_RO(role);
-static ssize_t target_stat_scsi_port_show_attr_busy_count(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_port_busy_count_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -615,26 +505,23 @@ static ssize_t target_stat_scsi_port_show_attr_busy_count(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_PORT_ATTR_RO(busy_count);
-CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group);
+CONFIGFS_ATTR_RO(target_stat_port_, inst);
+CONFIGFS_ATTR_RO(target_stat_port_, dev);
+CONFIGFS_ATTR_RO(target_stat_port_, indx);
+CONFIGFS_ATTR_RO(target_stat_port_, role);
+CONFIGFS_ATTR_RO(target_stat_port_, busy_count);
static struct configfs_attribute *target_stat_scsi_port_attrs[] = {
- &target_stat_scsi_port_inst.attr,
- &target_stat_scsi_port_dev.attr,
- &target_stat_scsi_port_indx.attr,
- &target_stat_scsi_port_role.attr,
- &target_stat_scsi_port_busy_count.attr,
+ &target_stat_port_attr_inst,
+ &target_stat_port_attr_dev,
+ &target_stat_port_attr_indx,
+ &target_stat_port_attr_role,
+ &target_stat_port_attr_busy_count,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_port_attrib_ops = {
- .show_attribute = target_stat_scsi_port_attr_show,
- .store_attribute = target_stat_scsi_port_attr_store,
-};
-
static struct config_item_type target_stat_scsi_port_cit = {
- .ct_item_ops = &target_stat_scsi_port_attrib_ops,
.ct_attrs = target_stat_scsi_port_attrs,
.ct_owner = THIS_MODULE,
};
@@ -642,24 +529,17 @@ static struct config_item_type target_stat_scsi_port_cit = {
/*
* SCSI Target Port Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps);
-#define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \
-static struct target_stat_scsi_tgt_port_attribute \
- target_stat_scsi_tgt_port_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_tgt_port_show_attr_##_name, \
- target_stat_scsi_tgt_port_store_attr_##_name);
-
-#define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \
-static struct target_stat_scsi_tgt_port_attribute \
- target_stat_scsi_tgt_port_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_tgt_port_show_attr_##_name);
-
-static ssize_t target_stat_scsi_tgt_port_show_attr_inst(
- struct se_port_stat_grps *pgrps, char *page)
-{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+static struct se_lun *to_stat_tgt_port(struct config_item *item)
+{
+ struct se_port_stat_grps *pgrps = container_of(to_config_group(item),
+ struct se_port_stat_grps, scsi_tgt_port_group);
+ return container_of(pgrps, struct se_lun, port_stat_grps);
+}
+
+static ssize_t target_stat_tgt_port_inst_show(struct config_item *item,
+ char *page)
+{
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -670,12 +550,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_inst(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst);
-static ssize_t target_stat_scsi_tgt_port_show_attr_dev(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_dev_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -686,12 +565,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_dev(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev);
-static ssize_t target_stat_scsi_tgt_port_show_attr_indx(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -702,12 +580,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx);
-static ssize_t target_stat_scsi_tgt_port_show_attr_name(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_name_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_portal_group *tpg = lun->lun_tpg;
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -721,12 +598,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_name(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name);
-static ssize_t target_stat_scsi_tgt_port_show_attr_port_index(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_port_index_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_portal_group *tpg = lun->lun_tpg;
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -740,12 +616,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_port_index(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index);
-static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_in_cmds_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -757,12 +632,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds);
-static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_write_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -774,12 +648,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes);
-static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_read_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -791,12 +664,11 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes);
-static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_tgt_port_hs_in_cmds_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_stat_tgt_port(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -809,57 +681,49 @@ static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds);
-CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps,
- scsi_tgt_port_group);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, inst);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, dev);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, indx);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, name);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, port_index);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, in_cmds);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, write_mbytes);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, read_mbytes);
+CONFIGFS_ATTR_RO(target_stat_tgt_port_, hs_in_cmds);
static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = {
- &target_stat_scsi_tgt_port_inst.attr,
- &target_stat_scsi_tgt_port_dev.attr,
- &target_stat_scsi_tgt_port_indx.attr,
- &target_stat_scsi_tgt_port_name.attr,
- &target_stat_scsi_tgt_port_port_index.attr,
- &target_stat_scsi_tgt_port_in_cmds.attr,
- &target_stat_scsi_tgt_port_write_mbytes.attr,
- &target_stat_scsi_tgt_port_read_mbytes.attr,
- &target_stat_scsi_tgt_port_hs_in_cmds.attr,
+ &target_stat_tgt_port_attr_inst,
+ &target_stat_tgt_port_attr_dev,
+ &target_stat_tgt_port_attr_indx,
+ &target_stat_tgt_port_attr_name,
+ &target_stat_tgt_port_attr_port_index,
+ &target_stat_tgt_port_attr_in_cmds,
+ &target_stat_tgt_port_attr_write_mbytes,
+ &target_stat_tgt_port_attr_read_mbytes,
+ &target_stat_tgt_port_attr_hs_in_cmds,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = {
- .show_attribute = target_stat_scsi_tgt_port_attr_show,
- .store_attribute = target_stat_scsi_tgt_port_attr_store,
-};
-
static struct config_item_type target_stat_scsi_tgt_port_cit = {
- .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops,
.ct_attrs = target_stat_scsi_tgt_port_attrs,
.ct_owner = THIS_MODULE,
};
/*
* SCSI Transport Table
-o */
-
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps);
-#define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \
-static struct target_stat_scsi_transport_attribute \
- target_stat_scsi_transport_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_transport_show_attr_##_name, \
- target_stat_scsi_transport_store_attr_##_name);
-
-#define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \
-static struct target_stat_scsi_transport_attribute \
- target_stat_scsi_transport_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_transport_show_attr_##_name);
-
-static ssize_t target_stat_scsi_transport_show_attr_inst(
- struct se_port_stat_grps *pgrps, char *page)
-{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ */
+static struct se_lun *to_transport_stat(struct config_item *item)
+{
+ struct se_port_stat_grps *pgrps = container_of(to_config_group(item),
+ struct se_port_stat_grps, scsi_transport_group);
+ return container_of(pgrps, struct se_lun, port_stat_grps);
+}
+
+static ssize_t target_stat_transport_inst_show(struct config_item *item,
+ char *page)
+{
+ struct se_lun *lun = to_transport_stat(item);
struct se_device *dev;
ssize_t ret = -ENODEV;
@@ -870,12 +734,11 @@ static ssize_t target_stat_scsi_transport_show_attr_inst(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst);
-static ssize_t target_stat_scsi_transport_show_attr_device(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_transport_device_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_transport_stat(item);
struct se_device *dev;
struct se_portal_group *tpg = lun->lun_tpg;
ssize_t ret = -ENODEV;
@@ -890,12 +753,11 @@ static ssize_t target_stat_scsi_transport_show_attr_device(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device);
-static ssize_t target_stat_scsi_transport_show_attr_indx(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_transport_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_transport_stat(item);
struct se_device *dev;
struct se_portal_group *tpg = lun->lun_tpg;
ssize_t ret = -ENODEV;
@@ -908,12 +770,11 @@ static ssize_t target_stat_scsi_transport_show_attr_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx);
-static ssize_t target_stat_scsi_transport_show_attr_dev_name(
- struct se_port_stat_grps *pgrps, char *page)
+static ssize_t target_stat_transport_dev_name_show(struct config_item *item,
+ char *page)
{
- struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps);
+ struct se_lun *lun = to_transport_stat(item);
struct se_device *dev;
struct se_portal_group *tpg = lun->lun_tpg;
struct t10_wwn *wwn;
@@ -932,26 +793,21 @@ static ssize_t target_stat_scsi_transport_show_attr_dev_name(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name);
-CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps,
- scsi_transport_group);
+CONFIGFS_ATTR_RO(target_stat_transport_, inst);
+CONFIGFS_ATTR_RO(target_stat_transport_, device);
+CONFIGFS_ATTR_RO(target_stat_transport_, indx);
+CONFIGFS_ATTR_RO(target_stat_transport_, dev_name);
static struct configfs_attribute *target_stat_scsi_transport_attrs[] = {
- &target_stat_scsi_transport_inst.attr,
- &target_stat_scsi_transport_device.attr,
- &target_stat_scsi_transport_indx.attr,
- &target_stat_scsi_transport_dev_name.attr,
+ &target_stat_transport_attr_inst,
+ &target_stat_transport_attr_device,
+ &target_stat_transport_attr_indx,
+ &target_stat_transport_attr_dev_name,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = {
- .show_attribute = target_stat_scsi_transport_attr_show,
- .store_attribute = target_stat_scsi_transport_attr_store,
-};
-
static struct config_item_type target_stat_scsi_transport_cit = {
- .ct_item_ops = &target_stat_scsi_transport_attrib_ops,
.ct_attrs = target_stat_scsi_transport_attrs,
.ct_owner = THIS_MODULE,
};
@@ -981,25 +837,17 @@ void target_stat_setup_port_default_groups(struct se_lun *lun)
* SCSI Authorized Initiator Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps);
-#define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \
-static struct target_stat_scsi_auth_intr_attribute \
- target_stat_scsi_auth_intr_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_auth_intr_show_attr_##_name, \
- target_stat_scsi_auth_intr_store_attr_##_name);
-
-#define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \
-static struct target_stat_scsi_auth_intr_attribute \
- target_stat_scsi_auth_intr_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_auth_intr_show_attr_##_name);
-
-static ssize_t target_stat_scsi_auth_intr_show_attr_inst(
- struct se_ml_stat_grps *lgrps, char *page)
-{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+static struct se_lun_acl *auth_to_lacl(struct config_item *item)
+{
+ struct se_ml_stat_grps *lgrps = container_of(to_config_group(item),
+ struct se_ml_stat_grps, scsi_auth_intr_group);
+ return container_of(lgrps, struct se_lun_acl, ml_stat_grps);
+}
+
+static ssize_t target_stat_auth_inst_show(struct config_item *item,
+ char *page)
+{
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_portal_group *tpg;
@@ -1018,13 +866,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_inst(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst);
-static ssize_t target_stat_scsi_auth_intr_show_attr_dev(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_dev_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_lun *lun;
@@ -1042,13 +888,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev);
-static ssize_t target_stat_scsi_auth_intr_show_attr_port(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_port_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_portal_group *tpg;
@@ -1066,13 +910,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_port(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port);
-static ssize_t target_stat_scsi_auth_intr_show_attr_indx(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1088,13 +930,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx);
-static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_dev_or_port_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1110,13 +950,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port);
-static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_intr_name_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1132,13 +970,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name);
-static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_map_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1154,13 +990,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx);
-static ssize_t target_stat_scsi_auth_intr_show_attr_att_count(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_att_count_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1176,13 +1010,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_att_count(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count);
-static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_num_cmds_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1199,13 +1031,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds);
-static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_read_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1222,13 +1052,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes);
-static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_write_mbytes_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1245,13 +1073,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes);
-static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_hs_num_cmds_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1267,13 +1093,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds);
-static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_creation_time_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1290,13 +1114,11 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time);
-static ssize_t target_stat_scsi_auth_intr_show_attr_row_status(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_auth_row_status_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = auth_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1312,36 +1134,41 @@ static ssize_t target_stat_scsi_auth_intr_show_attr_row_status(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status);
-CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps,
- scsi_auth_intr_group);
+CONFIGFS_ATTR_RO(target_stat_auth_, inst);
+CONFIGFS_ATTR_RO(target_stat_auth_, dev);
+CONFIGFS_ATTR_RO(target_stat_auth_, port);
+CONFIGFS_ATTR_RO(target_stat_auth_, indx);
+CONFIGFS_ATTR_RO(target_stat_auth_, dev_or_port);
+CONFIGFS_ATTR_RO(target_stat_auth_, intr_name);
+CONFIGFS_ATTR_RO(target_stat_auth_, map_indx);
+CONFIGFS_ATTR_RO(target_stat_auth_, att_count);
+CONFIGFS_ATTR_RO(target_stat_auth_, num_cmds);
+CONFIGFS_ATTR_RO(target_stat_auth_, read_mbytes);
+CONFIGFS_ATTR_RO(target_stat_auth_, write_mbytes);
+CONFIGFS_ATTR_RO(target_stat_auth_, hs_num_cmds);
+CONFIGFS_ATTR_RO(target_stat_auth_, creation_time);
+CONFIGFS_ATTR_RO(target_stat_auth_, row_status);
static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = {
- &target_stat_scsi_auth_intr_inst.attr,
- &target_stat_scsi_auth_intr_dev.attr,
- &target_stat_scsi_auth_intr_port.attr,
- &target_stat_scsi_auth_intr_indx.attr,
- &target_stat_scsi_auth_intr_dev_or_port.attr,
- &target_stat_scsi_auth_intr_intr_name.attr,
- &target_stat_scsi_auth_intr_map_indx.attr,
- &target_stat_scsi_auth_intr_att_count.attr,
- &target_stat_scsi_auth_intr_num_cmds.attr,
- &target_stat_scsi_auth_intr_read_mbytes.attr,
- &target_stat_scsi_auth_intr_write_mbytes.attr,
- &target_stat_scsi_auth_intr_hs_num_cmds.attr,
- &target_stat_scsi_auth_intr_creation_time.attr,
- &target_stat_scsi_auth_intr_row_status.attr,
+ &target_stat_auth_attr_inst,
+ &target_stat_auth_attr_dev,
+ &target_stat_auth_attr_port,
+ &target_stat_auth_attr_indx,
+ &target_stat_auth_attr_dev_or_port,
+ &target_stat_auth_attr_intr_name,
+ &target_stat_auth_attr_map_indx,
+ &target_stat_auth_attr_att_count,
+ &target_stat_auth_attr_num_cmds,
+ &target_stat_auth_attr_read_mbytes,
+ &target_stat_auth_attr_write_mbytes,
+ &target_stat_auth_attr_hs_num_cmds,
+ &target_stat_auth_attr_creation_time,
+ &target_stat_auth_attr_row_status,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = {
- .show_attribute = target_stat_scsi_auth_intr_attr_show,
- .store_attribute = target_stat_scsi_auth_intr_attr_store,
-};
-
static struct config_item_type target_stat_scsi_auth_intr_cit = {
- .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops,
.ct_attrs = target_stat_scsi_auth_intr_attrs,
.ct_owner = THIS_MODULE,
};
@@ -1350,25 +1177,17 @@ static struct config_item_type target_stat_scsi_auth_intr_cit = {
* SCSI Attached Initiator Port Table
*/
-CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps);
-#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \
-static struct target_stat_scsi_att_intr_port_attribute \
- target_stat_scsi_att_intr_port_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- target_stat_scsi_att_intr_port_show_attr_##_name, \
- target_stat_scsi_att_intr_port_store_attr_##_name);
-
-#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \
-static struct target_stat_scsi_att_intr_port_attribute \
- target_stat_scsi_att_intr_port_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- target_stat_scsi_att_intr_port_show_attr_##_name);
-
-static ssize_t target_stat_scsi_att_intr_port_show_attr_inst(
- struct se_ml_stat_grps *lgrps, char *page)
-{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+static struct se_lun_acl *iport_to_lacl(struct config_item *item)
+{
+ struct se_ml_stat_grps *lgrps = container_of(to_config_group(item),
+ struct se_ml_stat_grps, scsi_att_intr_port_group);
+ return container_of(lgrps, struct se_lun_acl, ml_stat_grps);
+}
+
+static ssize_t target_stat_iport_inst_show(struct config_item *item,
+ char *page)
+{
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_portal_group *tpg;
@@ -1387,13 +1206,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_inst(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst);
-static ssize_t target_stat_scsi_att_intr_port_show_attr_dev(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_iport_dev_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_lun *lun;
@@ -1411,13 +1228,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_dev(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev);
-static ssize_t target_stat_scsi_att_intr_port_show_attr_port(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_iport_port_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
struct se_portal_group *tpg;
@@ -1435,13 +1250,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port);
-static ssize_t target_stat_scsi_att_intr_port_show_attr_indx(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_iport_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_session *se_sess;
struct se_portal_group *tpg;
@@ -1461,13 +1274,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_indx(
spin_unlock_irq(&nacl->nacl_sess_lock);
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx);
-static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_iport_port_auth_indx_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_dev_entry *deve;
ssize_t ret;
@@ -1483,13 +1294,11 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx(
rcu_read_unlock();
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx);
-static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident(
- struct se_ml_stat_grps *lgrps, char *page)
+static ssize_t target_stat_iport_port_ident_show(struct config_item *item,
+ char *page)
{
- struct se_lun_acl *lacl = container_of(lgrps,
- struct se_lun_acl, ml_stat_grps);
+ struct se_lun_acl *lacl = iport_to_lacl(item);
struct se_node_acl *nacl = lacl->se_lun_nacl;
struct se_session *se_sess;
struct se_portal_group *tpg;
@@ -1513,28 +1322,25 @@ static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident(
spin_unlock_irq(&nacl->nacl_sess_lock);
return ret;
}
-DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident);
-CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps,
- scsi_att_intr_port_group);
+CONFIGFS_ATTR_RO(target_stat_iport_, inst);
+CONFIGFS_ATTR_RO(target_stat_iport_, dev);
+CONFIGFS_ATTR_RO(target_stat_iport_, port);
+CONFIGFS_ATTR_RO(target_stat_iport_, indx);
+CONFIGFS_ATTR_RO(target_stat_iport_, port_auth_indx);
+CONFIGFS_ATTR_RO(target_stat_iport_, port_ident);
static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = {
- &target_stat_scsi_att_intr_port_inst.attr,
- &target_stat_scsi_att_intr_port_dev.attr,
- &target_stat_scsi_att_intr_port_port.attr,
- &target_stat_scsi_att_intr_port_indx.attr,
- &target_stat_scsi_att_intr_port_port_auth_indx.attr,
- &target_stat_scsi_att_intr_port_port_ident.attr,
+ &target_stat_iport_attr_inst,
+ &target_stat_iport_attr_dev,
+ &target_stat_iport_attr_port,
+ &target_stat_iport_attr_indx,
+ &target_stat_iport_attr_port_auth_indx,
+ &target_stat_iport_attr_port_ident,
NULL,
};
-static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = {
- .show_attribute = target_stat_scsi_att_intr_port_attr_show,
- .store_attribute = target_stat_scsi_att_intr_port_attr_store,
-};
-
static struct config_item_type target_stat_scsi_att_intr_port_cit = {
- .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops,
.ct_attrs = target_stat_scsi_ath_intr_port_attrs,
.ct_owner = THIS_MODULE,
};
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c
index 5b28203..28fb301 100644
--- a/drivers/target/target_core_tmr.c
+++ b/drivers/target/target_core_tmr.c
@@ -130,6 +130,9 @@ void core_tmr_abort_task(
if (tmr->ref_task_tag != ref_tag)
continue;
+ if (!kref_get_unless_zero(&se_cmd->cmd_kref))
+ continue;
+
printk("ABORT_TASK: Found referenced %s task_tag: %llu\n",
se_cmd->se_tfo->get_fabric_name(), ref_tag);
@@ -139,13 +142,15 @@ void core_tmr_abort_task(
" skipping\n", ref_tag);
spin_unlock(&se_cmd->t_state_lock);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+ target_put_sess_cmd(se_cmd);
+
goto out;
}
se_cmd->transport_state |= CMD_T_ABORTED;
spin_unlock(&se_cmd->t_state_lock);
list_del_init(&se_cmd->se_cmd_list);
- kref_get(&se_cmd->cmd_kref);
spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
cancel_work_sync(&se_cmd->work);
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 5bacc7b..4fdcee2 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1658,7 +1658,7 @@ bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags)
void transport_generic_request_failure(struct se_cmd *cmd,
sense_reason_t sense_reason)
{
- int ret = 0;
+ int ret = 0, post_ret = 0;
pr_debug("-----[ Storage Engine Exception for cmd: %p ITT: 0x%08llx"
" CDB: 0x%02x\n", cmd, cmd->tag, cmd->t_task_cdb[0]);
@@ -1680,7 +1680,7 @@ void transport_generic_request_failure(struct se_cmd *cmd,
*/
if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
cmd->transport_complete_callback)
- cmd->transport_complete_callback(cmd, false);
+ cmd->transport_complete_callback(cmd, false, &post_ret);
switch (sense_reason) {
case TCM_NON_EXISTENT_LUN:
@@ -2068,11 +2068,13 @@ static void target_complete_ok_work(struct work_struct *work)
*/
if (cmd->transport_complete_callback) {
sense_reason_t rc;
+ bool caw = (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE);
+ bool zero_dl = !(cmd->data_length);
+ int post_ret = 0;
- rc = cmd->transport_complete_callback(cmd, true);
- if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) {
- if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) &&
- !cmd->data_length)
+ rc = cmd->transport_complete_callback(cmd, true, &post_ret);
+ if (!rc && !post_ret) {
+ if (caw && zero_dl)
goto queue_rsp;
return;
@@ -2507,23 +2509,24 @@ out:
EXPORT_SYMBOL(target_get_sess_cmd);
static void target_release_cmd_kref(struct kref *kref)
- __releases(&se_cmd->se_sess->sess_cmd_lock)
{
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
struct se_session *se_sess = se_cmd->se_sess;
+ unsigned long flags;
+ spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
if (list_empty(&se_cmd->se_cmd_list)) {
- spin_unlock(&se_sess->sess_cmd_lock);
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
se_cmd->se_tfo->release_cmd(se_cmd);
return;
}
if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
- spin_unlock(&se_sess->sess_cmd_lock);
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
complete(&se_cmd->cmd_wait_comp);
return;
}
list_del(&se_cmd->se_cmd_list);
- spin_unlock(&se_sess->sess_cmd_lock);
+ spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
se_cmd->se_tfo->release_cmd(se_cmd);
}
@@ -2539,8 +2542,7 @@ int target_put_sess_cmd(struct se_cmd *se_cmd)
se_cmd->se_tfo->release_cmd(se_cmd);
return 1;
}
- return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref,
- &se_sess->sess_cmd_lock);
+ return kref_put(&se_cmd->cmd_kref, target_release_cmd_kref);
}
EXPORT_SYMBOL(target_put_sess_cmd);
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 937cebf..5e6d6cb 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -638,7 +638,7 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data)
if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags))
return 0;
- if (!time_after(cmd->deadline, jiffies))
+ if (!time_after(jiffies, cmd->deadline))
return 0;
set_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags);
@@ -1101,8 +1101,6 @@ tcmu_parse_cdb(struct se_cmd *cmd)
static const struct target_backend_ops tcmu_ops = {
.name = "user",
- .inquiry_prod = "USER",
- .inquiry_rev = TCMU_VERSION,
.owner = THIS_MODULE,
.transport_flags = TRANSPORT_FLAG_PASSTHROUGH,
.attach_hba = tcmu_attach_hba,
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c
index aa3caca..064d6df 100644
--- a/drivers/target/tcm_fc/tfc_cmd.c
+++ b/drivers/target/tcm_fc/tfc_cmd.c
@@ -36,7 +36,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/configfs_macros.h>
#include "tcm_fc.h"
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c
index 1667093..85aeaa0 100644
--- a/drivers/target/tcm_fc/tfc_conf.c
+++ b/drivers/target/tcm_fc/tfc_conf.c
@@ -38,8 +38,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include "tcm_fc.h"
@@ -131,55 +129,51 @@ static ssize_t ft_wwn_store(void *arg, const char *buf, size_t len)
* ACL auth ops.
*/
-static ssize_t ft_nacl_show_port_name(
- struct se_node_acl *se_nacl,
- char *page)
+static ssize_t ft_nacl_port_name_show(struct config_item *item, char *page)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct ft_node_acl *acl = container_of(se_nacl,
struct ft_node_acl, se_node_acl);
return ft_wwn_show(&acl->node_auth.port_name, page);
}
-static ssize_t ft_nacl_store_port_name(
- struct se_node_acl *se_nacl,
- const char *page,
- size_t count)
+static ssize_t ft_nacl_port_name_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct ft_node_acl *acl = container_of(se_nacl,
struct ft_node_acl, se_node_acl);
return ft_wwn_store(&acl->node_auth.port_name, page, count);
}
-TF_NACL_BASE_ATTR(ft, port_name, S_IRUGO | S_IWUSR);
-
-static ssize_t ft_nacl_show_node_name(
- struct se_node_acl *se_nacl,
- char *page)
+static ssize_t ft_nacl_node_name_show(struct config_item *item,
+ char *page)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct ft_node_acl *acl = container_of(se_nacl,
struct ft_node_acl, se_node_acl);
return ft_wwn_show(&acl->node_auth.node_name, page);
}
-static ssize_t ft_nacl_store_node_name(
- struct se_node_acl *se_nacl,
- const char *page,
- size_t count)
+static ssize_t ft_nacl_node_name_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_node_acl *se_nacl = acl_to_nacl(item);
struct ft_node_acl *acl = container_of(se_nacl,
struct ft_node_acl, se_node_acl);
return ft_wwn_store(&acl->node_auth.node_name, page, count);
}
-TF_NACL_BASE_ATTR(ft, node_name, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(ft_nacl_, node_name);
+CONFIGFS_ATTR(ft_nacl_, port_name);
static struct configfs_attribute *ft_nacl_base_attrs[] = {
- &ft_nacl_port_name.attr,
- &ft_nacl_node_name.attr,
+ &ft_nacl_attr_port_name,
+ &ft_nacl_attr_node_name,
NULL,
};
@@ -386,18 +380,16 @@ static void ft_del_wwn(struct se_wwn *wwn)
kfree(ft_wwn);
}
-static ssize_t ft_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t ft_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "TCM FC " FT_VERSION " on %s/%s on "
""UTS_RELEASE"\n", utsname()->sysname, utsname()->machine);
}
-TF_WWN_ATTR_RO(ft, version);
+CONFIGFS_ATTR_RO(ft_wwn_, version);
static struct configfs_attribute *ft_wwn_attrs[] = {
- &ft_wwn_version.attr,
+ &ft_wwn_attr_version,
NULL,
};
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c
index 4b0fedd..847c1aa 100644
--- a/drivers/target/tcm_fc/tfc_io.c
+++ b/drivers/target/tcm_fc/tfc_io.c
@@ -44,7 +44,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/configfs_macros.h>
#include "tcm_fc.h"
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c
index 31a9e3f..7b934ea 100644
--- a/drivers/target/tcm_fc/tfc_sess.c
+++ b/drivers/target/tcm_fc/tfc_sess.c
@@ -36,7 +36,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/configfs_macros.h>
#include "tcm_fc.h"
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 5aabc4b..8cc4ac6 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -147,6 +147,20 @@ config CLOCK_THERMAL
device that is configured to use this cooling mechanism will be
controlled to reduce clock frequency whenever temperature is high.
+config DEVFREQ_THERMAL
+ bool "Generic device cooling support"
+ depends on PM_DEVFREQ
+ depends on PM_OPP
+ help
+ This implements the generic devfreq cooling mechanism through
+ frequency reduction for devices using devfreq.
+
+ This will throttle the device by limiting the maximum allowed DVFS
+ frequency corresponding to the cooling level.
+
+ In order to use the power extensions of the cooling device,
+ devfreq should use the simple_ondemand governor.
+
If you want this support, you should say Y here.
config THERMAL_EMULATION
@@ -275,6 +289,7 @@ config X86_PKG_TEMP_THERMAL
tristate "X86 package temperature thermal driver"
depends on X86_THERMAL_VECTOR
select THERMAL_GOV_USER_SPACE
+ select THERMAL_WRITABLE_TRIPS
default m
help
Enable this to register CPU digital sensor for package temperature as
@@ -296,6 +311,7 @@ config INTEL_SOC_DTS_THERMAL
tristate "Intel SoCs DTS thermal driver"
depends on X86
select INTEL_SOC_DTS_IOSF_CORE
+ select THERMAL_WRITABLE_TRIPS
help
Enable this to register Intel SoCs (e.g. Bay Trail) platform digital
temperature sensor (DTS). These SoCs have two additional DTSs in
@@ -322,6 +338,7 @@ config INT340X_THERMAL
select ACPI_THERMAL_REL
select ACPI_FAN
select INTEL_SOC_DTS_IOSF_CORE
+ select THERMAL_WRITABLE_TRIPS
help
Newer laptops and tablets that use ACPI may have thermal sensors and
other devices with thermal control capabilities outside the core
@@ -365,7 +382,7 @@ endmenu
config QCOM_SPMI_TEMP_ALARM
tristate "Qualcomm SPMI PMIC Temperature Alarm"
- depends on OF && (SPMI || COMPILE_TEST) && IIO
+ depends on OF && SPMI && IIO
select REGMAP_SPMI
help
This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP)
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 26f1608..cfae6a6 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -22,6 +22,9 @@ thermal_sys-$(CONFIG_CPU_THERMAL) += cpu_cooling.o
# clock cooling
thermal_sys-$(CONFIG_CLOCK_THERMAL) += clock_cooling.o
+# devfreq cooling
+thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
+
# platform thermal drivers
obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
index 26b8d32..ae75328 100644
--- a/drivers/thermal/armada_thermal.c
+++ b/drivers/thermal/armada_thermal.c
@@ -224,9 +224,9 @@ static const struct armada_thermal_data armada380_data = {
.is_valid_shift = 10,
.temp_shift = 0,
.temp_mask = 0x3ff,
- .coef_b = 2931108200UL,
- .coef_m = 5000000UL,
- .coef_div = 10502,
+ .coef_b = 1172499100UL,
+ .coef_m = 2000096UL,
+ .coef_div = 4201,
.inverted = true,
};
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 42c6f71..e3fbc5a 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -591,8 +591,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
if (trace_thermal_power_cpu_get_power_enabled()) {
u32 ncpus = cpumask_weight(&cpufreq_device->allowed_cpus);
- load_cpu = devm_kcalloc(&cdev->device, ncpus, sizeof(*load_cpu),
- GFP_KERNEL);
+ load_cpu = kcalloc(ncpus, sizeof(*load_cpu), GFP_KERNEL);
}
for_each_cpu(cpu, &cpufreq_device->allowed_cpus) {
@@ -615,8 +614,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
dynamic_power = get_dynamic_power(cpufreq_device, freq);
ret = get_static_power(cpufreq_device, tz, freq, &static_power);
if (ret) {
- if (load_cpu)
- devm_kfree(&cdev->device, load_cpu);
+ kfree(load_cpu);
return ret;
}
@@ -625,7 +623,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
&cpufreq_device->allowed_cpus,
freq, load_cpu, i, dynamic_power, static_power);
- devm_kfree(&cdev->device, load_cpu);
+ kfree(load_cpu);
}
*power = static_power + dynamic_power;
diff --git a/drivers/thermal/devfreq_cooling.c b/drivers/thermal/devfreq_cooling.c
new file mode 100644
index 0000000..01f0015
--- /dev/null
+++ b/drivers/thermal/devfreq_cooling.c
@@ -0,0 +1,573 @@
+/*
+ * devfreq_cooling: Thermal cooling device implementation for devices using
+ * devfreq
+ *
+ * Copyright (C) 2014-2015 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * TODO:
+ * - If OPPs are added or removed after devfreq cooling has
+ * registered, the devfreq cooling won't react to it.
+ */
+
+#include <linux/devfreq.h>
+#include <linux/devfreq_cooling.h>
+#include <linux/export.h>
+#include <linux/slab.h>
+#include <linux/pm_opp.h>
+#include <linux/thermal.h>
+
+#include <trace/events/thermal.h>
+
+static DEFINE_MUTEX(devfreq_lock);
+static DEFINE_IDR(devfreq_idr);
+
+/**
+ * struct devfreq_cooling_device - Devfreq cooling device
+ * @id: unique integer value corresponding to each
+ * devfreq_cooling_device registered.
+ * @cdev: Pointer to associated thermal cooling device.
+ * @devfreq: Pointer to associated devfreq device.
+ * @cooling_state: Current cooling state.
+ * @power_table: Pointer to table with maximum power draw for each
+ * cooling state. State is the index into the table, and
+ * the power is in mW.
+ * @freq_table: Pointer to a table with the frequencies sorted in descending
+ * order. You can index the table by cooling device state
+ * @freq_table_size: Size of the @freq_table and @power_table
+ * @power_ops: Pointer to devfreq_cooling_power, used to generate the
+ * @power_table.
+ */
+struct devfreq_cooling_device {
+ int id;
+ struct thermal_cooling_device *cdev;
+ struct devfreq *devfreq;
+ unsigned long cooling_state;
+ u32 *power_table;
+ u32 *freq_table;
+ size_t freq_table_size;
+ struct devfreq_cooling_power *power_ops;
+};
+
+/**
+ * get_idr - function to get a unique id.
+ * @idr: struct idr * handle used to create a id.
+ * @id: int * value generated by this function.
+ *
+ * This function will populate @id with an unique
+ * id, using the idr API.
+ *
+ * Return: 0 on success, an error code on failure.
+ */
+static int get_idr(struct idr *idr, int *id)
+{
+ int ret;
+
+ mutex_lock(&devfreq_lock);
+ ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
+ mutex_unlock(&devfreq_lock);
+ if (unlikely(ret < 0))
+ return ret;
+ *id = ret;
+
+ return 0;
+}
+
+/**
+ * release_idr - function to free the unique id.
+ * @idr: struct idr * handle used for creating the id.
+ * @id: int value representing the unique id.
+ */
+static void release_idr(struct idr *idr, int id)
+{
+ mutex_lock(&devfreq_lock);
+ idr_remove(idr, id);
+ mutex_unlock(&devfreq_lock);
+}
+
+/**
+ * partition_enable_opps() - disable all opps above a given state
+ * @dfc: Pointer to devfreq we are operating on
+ * @cdev_state: cooling device state we're setting
+ *
+ * Go through the OPPs of the device, enabling all OPPs until
+ * @cdev_state and disabling those frequencies above it.
+ */
+static int partition_enable_opps(struct devfreq_cooling_device *dfc,
+ unsigned long cdev_state)
+{
+ int i;
+ struct device *dev = dfc->devfreq->dev.parent;
+
+ for (i = 0; i < dfc->freq_table_size; i++) {
+ struct dev_pm_opp *opp;
+ int ret = 0;
+ unsigned int freq = dfc->freq_table[i];
+ bool want_enable = i >= cdev_state ? true : false;
+
+ rcu_read_lock();
+ opp = dev_pm_opp_find_freq_exact(dev, freq, !want_enable);
+ rcu_read_unlock();
+
+ if (PTR_ERR(opp) == -ERANGE)
+ continue;
+ else if (IS_ERR(opp))
+ return PTR_ERR(opp);
+
+ if (want_enable)
+ ret = dev_pm_opp_enable(dev, freq);
+ else
+ ret = dev_pm_opp_disable(dev, freq);
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int devfreq_cooling_get_max_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+
+ *state = dfc->freq_table_size - 1;
+
+ return 0;
+}
+
+static int devfreq_cooling_get_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+
+ *state = dfc->cooling_state;
+
+ return 0;
+}
+
+static int devfreq_cooling_set_cur_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+ struct devfreq *df = dfc->devfreq;
+ struct device *dev = df->dev.parent;
+ int ret;
+
+ if (state == dfc->cooling_state)
+ return 0;
+
+ dev_dbg(dev, "Setting cooling state %lu\n", state);
+
+ if (state >= dfc->freq_table_size)
+ return -EINVAL;
+
+ ret = partition_enable_opps(dfc, state);
+ if (ret)
+ return ret;
+
+ dfc->cooling_state = state;
+
+ return 0;
+}
+
+/**
+ * freq_get_state() - get the cooling state corresponding to a frequency
+ * @dfc: Pointer to devfreq cooling device
+ * @freq: frequency in Hz
+ *
+ * Return: the cooling state associated with the @freq, or
+ * THERMAL_CSTATE_INVALID if it wasn't found.
+ */
+static unsigned long
+freq_get_state(struct devfreq_cooling_device *dfc, unsigned long freq)
+{
+ int i;
+
+ for (i = 0; i < dfc->freq_table_size; i++) {
+ if (dfc->freq_table[i] == freq)
+ return i;
+ }
+
+ return THERMAL_CSTATE_INVALID;
+}
+
+/**
+ * get_static_power() - calculate the static power
+ * @dfc: Pointer to devfreq cooling device
+ * @freq: Frequency in Hz
+ *
+ * Calculate the static power in milliwatts using the supplied
+ * get_static_power(). The current voltage is calculated using the
+ * OPP library. If no get_static_power() was supplied, assume the
+ * static power is negligible.
+ */
+static unsigned long
+get_static_power(struct devfreq_cooling_device *dfc, unsigned long freq)
+{
+ struct devfreq *df = dfc->devfreq;
+ struct device *dev = df->dev.parent;
+ unsigned long voltage;
+ struct dev_pm_opp *opp;
+
+ if (!dfc->power_ops->get_static_power)
+ return 0;
+
+ rcu_read_lock();
+
+ opp = dev_pm_opp_find_freq_exact(dev, freq, true);
+ if (IS_ERR(opp) && (PTR_ERR(opp) == -ERANGE))
+ opp = dev_pm_opp_find_freq_exact(dev, freq, false);
+
+ voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
+
+ rcu_read_unlock();
+
+ if (voltage == 0) {
+ dev_warn_ratelimited(dev,
+ "Failed to get voltage for frequency %lu: %ld\n",
+ freq, IS_ERR(opp) ? PTR_ERR(opp) : 0);
+ return 0;
+ }
+
+ return dfc->power_ops->get_static_power(voltage);
+}
+
+/**
+ * get_dynamic_power - calculate the dynamic power
+ * @dfc: Pointer to devfreq cooling device
+ * @freq: Frequency in Hz
+ * @voltage: Voltage in millivolts
+ *
+ * Calculate the dynamic power in milliwatts consumed by the device at
+ * frequency @freq and voltage @voltage. If the get_dynamic_power()
+ * was supplied as part of the devfreq_cooling_power struct, then that
+ * function is used. Otherwise, a simple power model (Pdyn = Coeff *
+ * Voltage^2 * Frequency) is used.
+ */
+static unsigned long
+get_dynamic_power(struct devfreq_cooling_device *dfc, unsigned long freq,
+ unsigned long voltage)
+{
+ u64 power;
+ u32 freq_mhz;
+ struct devfreq_cooling_power *dfc_power = dfc->power_ops;
+
+ if (dfc_power->get_dynamic_power)
+ return dfc_power->get_dynamic_power(freq, voltage);
+
+ freq_mhz = freq / 1000000;
+ power = (u64)dfc_power->dyn_power_coeff * freq_mhz * voltage * voltage;
+ do_div(power, 1000000000);
+
+ return power;
+}
+
+static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cdev,
+ struct thermal_zone_device *tz,
+ u32 *power)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+ struct devfreq *df = dfc->devfreq;
+ struct devfreq_dev_status *status = &df->last_status;
+ unsigned long state;
+ unsigned long freq = status->current_frequency;
+ u32 dyn_power, static_power;
+
+ /* Get dynamic power for state */
+ state = freq_get_state(dfc, freq);
+ if (state == THERMAL_CSTATE_INVALID)
+ return -EAGAIN;
+
+ dyn_power = dfc->power_table[state];
+
+ /* Scale dynamic power for utilization */
+ dyn_power = (dyn_power * status->busy_time) / status->total_time;
+
+ /* Get static power */
+ static_power = get_static_power(dfc, freq);
+
+ trace_thermal_power_devfreq_get_power(cdev, status, freq, dyn_power,
+ static_power);
+
+ *power = dyn_power + static_power;
+
+ return 0;
+}
+
+static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev,
+ struct thermal_zone_device *tz,
+ unsigned long state,
+ u32 *power)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+ unsigned long freq;
+ u32 static_power;
+
+ if (state < 0 || state >= dfc->freq_table_size)
+ return -EINVAL;
+
+ freq = dfc->freq_table[state];
+ static_power = get_static_power(dfc, freq);
+
+ *power = dfc->power_table[state] + static_power;
+ return 0;
+}
+
+static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
+ struct thermal_zone_device *tz,
+ u32 power, unsigned long *state)
+{
+ struct devfreq_cooling_device *dfc = cdev->devdata;
+ struct devfreq *df = dfc->devfreq;
+ struct devfreq_dev_status *status = &df->last_status;
+ unsigned long freq = status->current_frequency;
+ unsigned long busy_time;
+ s32 dyn_power;
+ u32 static_power;
+ int i;
+
+ static_power = get_static_power(dfc, freq);
+
+ dyn_power = power - static_power;
+ dyn_power = dyn_power > 0 ? dyn_power : 0;
+
+ /* Scale dynamic power for utilization */
+ busy_time = status->busy_time ?: 1;
+ dyn_power = (dyn_power * status->total_time) / busy_time;
+
+ /*
+ * Find the first cooling state that is within the power
+ * budget for dynamic power.
+ */
+ for (i = 0; i < dfc->freq_table_size - 1; i++)
+ if (dyn_power >= dfc->power_table[i])
+ break;
+
+ *state = i;
+ trace_thermal_power_devfreq_limit(cdev, freq, *state, power);
+ return 0;
+}
+
+static struct thermal_cooling_device_ops devfreq_cooling_ops = {
+ .get_max_state = devfreq_cooling_get_max_state,
+ .get_cur_state = devfreq_cooling_get_cur_state,
+ .set_cur_state = devfreq_cooling_set_cur_state,
+};
+
+/**
+ * devfreq_cooling_gen_tables() - Generate power and freq tables.
+ * @dfc: Pointer to devfreq cooling device.
+ *
+ * Generate power and frequency tables: the power table hold the
+ * device's maximum power usage at each cooling state (OPP). The
+ * static and dynamic power using the appropriate voltage and
+ * frequency for the state, is acquired from the struct
+ * devfreq_cooling_power, and summed to make the maximum power draw.
+ *
+ * The frequency table holds the frequencies in descending order.
+ * That way its indexed by cooling device state.
+ *
+ * The tables are malloced, and pointers put in dfc. They must be
+ * freed when unregistering the devfreq cooling device.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int devfreq_cooling_gen_tables(struct devfreq_cooling_device *dfc)
+{
+ struct devfreq *df = dfc->devfreq;
+ struct device *dev = df->dev.parent;
+ int ret, num_opps;
+ unsigned long freq;
+ u32 *power_table = NULL;
+ u32 *freq_table;
+ int i;
+
+ num_opps = dev_pm_opp_get_opp_count(dev);
+
+ if (dfc->power_ops) {
+ power_table = kcalloc(num_opps, sizeof(*power_table),
+ GFP_KERNEL);
+ if (!power_table)
+ return -ENOMEM;
+ }
+
+ freq_table = kcalloc(num_opps, sizeof(*freq_table),
+ GFP_KERNEL);
+ if (!freq_table) {
+ ret = -ENOMEM;
+ goto free_power_table;
+ }
+
+ for (i = 0, freq = ULONG_MAX; i < num_opps; i++, freq--) {
+ unsigned long power_dyn, voltage;
+ struct dev_pm_opp *opp;
+
+ rcu_read_lock();
+
+ opp = dev_pm_opp_find_freq_floor(dev, &freq);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ ret = PTR_ERR(opp);
+ goto free_tables;
+ }
+
+ voltage = dev_pm_opp_get_voltage(opp) / 1000; /* mV */
+
+ rcu_read_unlock();
+
+ if (dfc->power_ops) {
+ power_dyn = get_dynamic_power(dfc, freq, voltage);
+
+ dev_dbg(dev, "Dynamic power table: %lu MHz @ %lu mV: %lu = %lu mW\n",
+ freq / 1000000, voltage, power_dyn, power_dyn);
+
+ power_table[i] = power_dyn;
+ }
+
+ freq_table[i] = freq;
+ }
+
+ if (dfc->power_ops)
+ dfc->power_table = power_table;
+
+ dfc->freq_table = freq_table;
+ dfc->freq_table_size = num_opps;
+
+ return 0;
+
+free_tables:
+ kfree(freq_table);
+free_power_table:
+ kfree(power_table);
+
+ return ret;
+}
+
+/**
+ * of_devfreq_cooling_register_power() - Register devfreq cooling device,
+ * with OF and power information.
+ * @np: Pointer to OF device_node.
+ * @df: Pointer to devfreq device.
+ * @dfc_power: Pointer to devfreq_cooling_power.
+ *
+ * Register a devfreq cooling device. The available OPPs must be
+ * registered on the device.
+ *
+ * If @dfc_power is provided, the cooling device is registered with the
+ * power extensions. For the power extensions to work correctly,
+ * devfreq should use the simple_ondemand governor, other governors
+ * are not currently supported.
+ */
+struct thermal_cooling_device *
+of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
+ struct devfreq_cooling_power *dfc_power)
+{
+ struct thermal_cooling_device *cdev;
+ struct devfreq_cooling_device *dfc;
+ char dev_name[THERMAL_NAME_LENGTH];
+ int err;
+
+ dfc = kzalloc(sizeof(*dfc), GFP_KERNEL);
+ if (!dfc)
+ return ERR_PTR(-ENOMEM);
+
+ dfc->devfreq = df;
+
+ if (dfc_power) {
+ dfc->power_ops = dfc_power;
+
+ devfreq_cooling_ops.get_requested_power =
+ devfreq_cooling_get_requested_power;
+ devfreq_cooling_ops.state2power = devfreq_cooling_state2power;
+ devfreq_cooling_ops.power2state = devfreq_cooling_power2state;
+ }
+
+ err = devfreq_cooling_gen_tables(dfc);
+ if (err)
+ goto free_dfc;
+
+ err = get_idr(&devfreq_idr, &dfc->id);
+ if (err)
+ goto free_tables;
+
+ snprintf(dev_name, sizeof(dev_name), "thermal-devfreq-%d", dfc->id);
+
+ cdev = thermal_of_cooling_device_register(np, dev_name, dfc,
+ &devfreq_cooling_ops);
+ if (IS_ERR(cdev)) {
+ err = PTR_ERR(cdev);
+ dev_err(df->dev.parent,
+ "Failed to register devfreq cooling device (%d)\n",
+ err);
+ goto release_idr;
+ }
+
+ dfc->cdev = cdev;
+
+ return cdev;
+
+release_idr:
+ release_idr(&devfreq_idr, dfc->id);
+free_tables:
+ kfree(dfc->power_table);
+ kfree(dfc->freq_table);
+free_dfc:
+ kfree(dfc);
+
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(of_devfreq_cooling_register_power);
+
+/**
+ * of_devfreq_cooling_register() - Register devfreq cooling device,
+ * with OF information.
+ * @np: Pointer to OF device_node.
+ * @df: Pointer to devfreq device.
+ */
+struct thermal_cooling_device *
+of_devfreq_cooling_register(struct device_node *np, struct devfreq *df)
+{
+ return of_devfreq_cooling_register_power(np, df, NULL);
+}
+EXPORT_SYMBOL_GPL(of_devfreq_cooling_register);
+
+/**
+ * devfreq_cooling_register() - Register devfreq cooling device.
+ * @df: Pointer to devfreq device.
+ */
+struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df)
+{
+ return of_devfreq_cooling_register(NULL, df);
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_register);
+
+/**
+ * devfreq_cooling_unregister() - Unregister devfreq cooling device.
+ * @dfc: Pointer to devfreq cooling device to unregister.
+ */
+void devfreq_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+ struct devfreq_cooling_device *dfc;
+
+ if (!cdev)
+ return;
+
+ dfc = cdev->devdata;
+
+ thermal_cooling_device_unregister(dfc->cdev);
+ release_idr(&devfreq_idr, dfc->id);
+ kfree(dfc->power_table);
+ kfree(dfc->freq_table);
+
+ kfree(dfc);
+}
+EXPORT_SYMBOL_GPL(devfreq_cooling_unregister);
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 4bec1d3..c5547bd 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -55,6 +55,7 @@
#define TEMPSENSE2_PANIC_VALUE_SHIFT 16
#define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
+#define OCOTP_MEM0 0x0480
#define OCOTP_ANA1 0x04e0
/* The driver supports 1 passive trip point and 1 critical trip point */
@@ -64,12 +65,6 @@ enum imx_thermal_trip {
IMX_TRIP_NUM,
};
-/*
- * It defines the temperature in millicelsius for passive trip point
- * that will trigger cooling action when crossed.
- */
-#define IMX_TEMP_PASSIVE 85000
-
#define IMX_POLLING_DELAY 2000 /* millisecond */
#define IMX_PASSIVE_DELAY 1000
@@ -100,12 +95,14 @@ struct imx_thermal_data {
u32 c1, c2; /* See formula in imx_get_sensor_data() */
int temp_passive;
int temp_critical;
+ int temp_max;
int alarm_temp;
int last_temp;
bool irq_enabled;
int irq;
struct clk *thermal_clk;
const struct thermal_soc_data *socdata;
+ const char *temp_grade;
};
static void imx_set_panic_temp(struct imx_thermal_data *data,
@@ -285,10 +282,12 @@ static int imx_set_trip_temp(struct thermal_zone_device *tz, int trip,
{
struct imx_thermal_data *data = tz->devdata;
+ /* do not allow changing critical threshold */
if (trip == IMX_TRIP_CRITICAL)
return -EPERM;
- if (temp > IMX_TEMP_PASSIVE)
+ /* do not allow passive to be set higher than critical */
+ if (temp < 0 || temp > data->temp_critical)
return -EINVAL;
data->temp_passive = temp;
@@ -404,17 +403,39 @@ static int imx_get_sensor_data(struct platform_device *pdev)
data->c1 = temp64;
data->c2 = n1 * data->c1 + 1000 * t1;
- /*
- * Set the default passive cooling trip point,
- * can be changed from userspace.
- */
- data->temp_passive = IMX_TEMP_PASSIVE;
+ /* use OTP for thermal grade */
+ ret = regmap_read(map, OCOTP_MEM0, &val);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
+ return ret;
+ }
+
+ /* The maximum die temp is specified by the Temperature Grade */
+ switch ((val >> 6) & 0x3) {
+ case 0: /* Commercial (0 to 95C) */
+ data->temp_grade = "Commercial";
+ data->temp_max = 95000;
+ break;
+ case 1: /* Extended Commercial (-20 to 105C) */
+ data->temp_grade = "Extended Commercial";
+ data->temp_max = 105000;
+ break;
+ case 2: /* Industrial (-40 to 105C) */
+ data->temp_grade = "Industrial";
+ data->temp_max = 105000;
+ break;
+ case 3: /* Automotive (-40 to 125C) */
+ data->temp_grade = "Automotive";
+ data->temp_max = 125000;
+ break;
+ }
/*
- * The maximum die temperature set to 20 C higher than
- * IMX_TEMP_PASSIVE.
+ * Set the critical trip point at 5C under max
+ * Set the passive trip point at 10C under max (can change via sysfs)
*/
- data->temp_critical = 1000 * 20 + data->temp_passive;
+ data->temp_critical = data->temp_max - (1000 * 5);
+ data->temp_passive = data->temp_max - (1000 * 10);
return 0;
}
@@ -487,14 +508,6 @@ static int imx_thermal_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
- ret = devm_request_threaded_irq(&pdev->dev, data->irq,
- imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
- 0, "imx_thermal", data);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
- return ret;
- }
-
platform_set_drvdata(pdev, data);
ret = imx_get_sensor_data(pdev);
@@ -559,6 +572,11 @@ static int imx_thermal_probe(struct platform_device *pdev)
return ret;
}
+ dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC"
+ " critical:%dC passive:%dC\n", data->temp_grade,
+ data->temp_max / 1000, data->temp_critical / 1000,
+ data->temp_passive / 1000);
+
/* Enable measurements at ~ 10 Hz */
regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
@@ -571,6 +589,17 @@ static int imx_thermal_probe(struct platform_device *pdev)
regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
+ ret = devm_request_threaded_irq(&pdev->dev, data->irq,
+ imx_thermal_alarm_irq, imx_thermal_alarm_irq_thread,
+ 0, "imx_thermal", data);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret);
+ clk_disable_unprepare(data->thermal_clk);
+ thermal_zone_device_unregister(data->tz);
+ cpufreq_cooling_unregister(data->cdev);
+ return ret;
+ }
+
data->irq_enabled = true;
data->mode = THERMAL_DEVICE_ENABLED;
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 42b7d42..be4eedc 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -964,7 +964,7 @@ void of_thermal_destroy_zones(void)
np = of_find_node_by_name(NULL, "thermal-zones");
if (!np) {
- pr_err("unable to find thermal zones\n");
+ pr_debug("unable to find thermal zones\n");
return;
}
diff --git a/drivers/thermal/power_allocator.c b/drivers/thermal/power_allocator.c
index f0fbea3..1246aa6 100644
--- a/drivers/thermal/power_allocator.c
+++ b/drivers/thermal/power_allocator.c
@@ -174,7 +174,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
/**
* pid_controller() - PID controller
* @tz: thermal zone we are operating in
- * @current_temp: the current temperature in millicelsius
* @control_temp: the target temperature in millicelsius
* @max_allocatable_power: maximum allocatable power for this thermal zone
*
@@ -191,7 +190,6 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
* Return: The power budget for the next period.
*/
static u32 pid_controller(struct thermal_zone_device *tz,
- int current_temp,
int control_temp,
u32 max_allocatable_power)
{
@@ -211,7 +209,7 @@ static u32 pid_controller(struct thermal_zone_device *tz,
true);
}
- err = control_temp - current_temp;
+ err = control_temp - tz->temperature;
err = int_to_frac(err);
/* Calculate the proportional term */
@@ -332,7 +330,6 @@ static void divvy_up_power(u32 *req_power, u32 *max_power, int num_actors,
}
static int allocate_power(struct thermal_zone_device *tz,
- int current_temp,
int control_temp)
{
struct thermal_instance *instance;
@@ -418,8 +415,7 @@ static int allocate_power(struct thermal_zone_device *tz,
i++;
}
- power_range = pid_controller(tz, current_temp, control_temp,
- max_allocatable_power);
+ power_range = pid_controller(tz, control_temp, max_allocatable_power);
divvy_up_power(weighted_req_power, max_power, num_actors,
total_weighted_req_power, power_range, granted_power,
@@ -444,8 +440,8 @@ static int allocate_power(struct thermal_zone_device *tz,
trace_thermal_power_allocator(tz, req_power, total_req_power,
granted_power, total_granted_power,
num_actors, power_range,
- max_allocatable_power, current_temp,
- control_temp - current_temp);
+ max_allocatable_power, tz->temperature,
+ control_temp - tz->temperature);
kfree(req_power);
unlock:
@@ -612,7 +608,7 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
{
int ret;
- int switch_on_temp, control_temp, current_temp;
+ int switch_on_temp, control_temp;
struct power_allocator_params *params = tz->governor_data;
/*
@@ -622,15 +618,9 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
if (trip != params->trip_max_desired_temperature)
return 0;
- ret = thermal_zone_get_temp(tz, &current_temp);
- if (ret) {
- dev_warn(&tz->device, "Failed to get temperature: %d\n", ret);
- return ret;
- }
-
ret = tz->ops->get_trip_temp(tz, params->trip_switch_on,
&switch_on_temp);
- if (!ret && (current_temp < switch_on_temp)) {
+ if (!ret && (tz->temperature < switch_on_temp)) {
tz->passive = 0;
reset_pid_controller(params);
allow_maximum_power(tz);
@@ -648,7 +638,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
return ret;
}
- return allocate_power(tz, current_temp, control_temp);
+ return allocate_power(tz, control_temp);
}
static struct thermal_governor thermal_gov_power_allocator = {
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c
index 5d4ae7d..13d01ed 100644
--- a/drivers/thermal/rcar_thermal.c
+++ b/drivers/thermal/rcar_thermal.c
@@ -361,6 +361,24 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data)
/*
* platform functions
*/
+static int rcar_thermal_remove(struct platform_device *pdev)
+{
+ struct rcar_thermal_common *common = platform_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+ struct rcar_thermal_priv *priv;
+
+ rcar_thermal_for_each_priv(priv, common) {
+ if (rcar_has_irq_support(priv))
+ rcar_thermal_irq_disable(priv);
+ thermal_zone_device_unregister(priv->zone);
+ }
+
+ pm_runtime_put(dev);
+ pm_runtime_disable(dev);
+
+ return 0;
+}
+
static int rcar_thermal_probe(struct platform_device *pdev)
{
struct rcar_thermal_common *common;
@@ -377,6 +395,8 @@ static int rcar_thermal_probe(struct platform_device *pdev)
if (!common)
return -ENOMEM;
+ platform_set_drvdata(pdev, common);
+
INIT_LIST_HEAD(&common->head);
spin_lock_init(&common->lock);
common->dev = dev;
@@ -454,43 +474,16 @@ static int rcar_thermal_probe(struct platform_device *pdev)
rcar_thermal_common_write(common, ENR, enr_bits);
}
- platform_set_drvdata(pdev, common);
-
dev_info(dev, "%d sensor probed\n", i);
return 0;
error_unregister:
- rcar_thermal_for_each_priv(priv, common) {
- if (rcar_has_irq_support(priv))
- rcar_thermal_irq_disable(priv);
- thermal_zone_device_unregister(priv->zone);
- }
-
- pm_runtime_put(dev);
- pm_runtime_disable(dev);
+ rcar_thermal_remove(pdev);
return ret;
}
-static int rcar_thermal_remove(struct platform_device *pdev)
-{
- struct rcar_thermal_common *common = platform_get_drvdata(pdev);
- struct device *dev = &pdev->dev;
- struct rcar_thermal_priv *priv;
-
- rcar_thermal_for_each_priv(priv, common) {
- if (rcar_has_irq_support(priv))
- rcar_thermal_irq_disable(priv);
- thermal_zone_device_unregister(priv->zone);
- }
-
- pm_runtime_put(dev);
- pm_runtime_disable(dev);
-
- return 0;
-}
-
static const struct of_device_id rcar_thermal_dt_ids[] = {
{ .compatible = "renesas,rcar-thermal", },
{},
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index c89ffb2..e845841 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -1,6 +1,9 @@
/*
* Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
*
+ * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd
+ * Caesar Wang <wxt@rock-chips.com>
+ *
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
@@ -22,6 +25,7 @@
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/thermal.h>
+#include <linux/pinctrl/consumer.h>
/**
* If the temperature over a period of time High,
@@ -44,17 +48,50 @@ enum tshut_polarity {
};
/**
- * The system has three Temperature Sensors. channel 0 is reserved,
- * channel 1 is for CPU, and channel 2 is for GPU.
+ * The system has two Temperature Sensors.
+ * sensor0 is for CPU, and sensor1 is for GPU.
*/
enum sensor_id {
- SENSOR_CPU = 1,
+ SENSOR_CPU = 0,
SENSOR_GPU,
};
+/**
+* The conversion table has the adc value and temperature.
+* ADC_DECREMENT is the adc value decremnet.(e.g. v2_code_table)
+* ADC_INCREMNET is the adc value incremnet.(e.g. v3_code_table)
+*/
+enum adc_sort_mode {
+ ADC_DECREMENT = 0,
+ ADC_INCREMENT,
+};
+
+/**
+ * The max sensors is two in rockchip SoCs.
+ * Two sensors: CPU and GPU sensor.
+ */
+#define SOC_MAX_SENSORS 2
+
+struct chip_tsadc_table {
+ const struct tsadc_table *id;
+
+ /* the array table size*/
+ unsigned int length;
+
+ /* that analogic mask data */
+ u32 data_mask;
+
+ /* the sort mode is adc value that increment or decrement in table */
+ enum adc_sort_mode mode;
+};
+
struct rockchip_tsadc_chip {
+ /* The sensor id of chip correspond to the ADC channel */
+ int chn_id[SOC_MAX_SENSORS];
+ int chn_num;
+
/* The hardware-controlled tshut property */
- long tshut_temp;
+ int tshut_temp;
enum tshut_mode tshut_mode;
enum tshut_polarity tshut_polarity;
@@ -64,37 +101,40 @@ struct rockchip_tsadc_chip {
void (*control)(void __iomem *reg, bool on);
/* Per-sensor methods */
- int (*get_temp)(int chn, void __iomem *reg, int *temp);
- void (*set_tshut_temp)(int chn, void __iomem *reg, long temp);
+ int (*get_temp)(struct chip_tsadc_table table,
+ int chn, void __iomem *reg, int *temp);
+ void (*set_tshut_temp)(struct chip_tsadc_table table,
+ int chn, void __iomem *reg, int temp);
void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
+
+ /* Per-table methods */
+ struct chip_tsadc_table table;
};
struct rockchip_thermal_sensor {
struct rockchip_thermal_data *thermal;
struct thermal_zone_device *tzd;
- enum sensor_id id;
+ int id;
};
-#define NUM_SENSORS 2 /* Ignore unused sensor 0 */
-
struct rockchip_thermal_data {
const struct rockchip_tsadc_chip *chip;
struct platform_device *pdev;
struct reset_control *reset;
- struct rockchip_thermal_sensor sensors[NUM_SENSORS];
+ struct rockchip_thermal_sensor sensors[SOC_MAX_SENSORS];
struct clk *clk;
struct clk *pclk;
void __iomem *regs;
- long tshut_temp;
+ int tshut_temp;
enum tshut_mode tshut_mode;
enum tshut_polarity tshut_polarity;
};
-/* TSADC V2 Sensor info define: */
+/* TSADC Sensor info define: */
#define TSADCV2_AUTO_CON 0x04
#define TSADCV2_INT_EN 0x08
#define TSADCV2_INT_PD 0x0c
@@ -106,26 +146,26 @@ struct rockchip_thermal_data {
#define TSADCV2_AUTO_PERIOD_HT 0x6c
#define TSADCV2_AUTO_EN BIT(0)
-#define TSADCV2_AUTO_DISABLE ~BIT(0)
#define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn))
#define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8)
-#define TSADCV2_AUTO_TSHUT_POLARITY_LOW ~BIT(8)
#define TSADCV2_INT_SRC_EN(chn) BIT(chn)
#define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn))
#define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn))
-#define TSADCV2_INT_PD_CLEAR ~BIT(8)
+#define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8)
#define TSADCV2_DATA_MASK 0xfff
+#define TSADCV3_DATA_MASK 0x3ff
+
#define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4
#define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4
#define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */
#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */
struct tsadc_table {
- unsigned long code;
- long temp;
+ u32 code;
+ int temp;
};
static const struct tsadc_table v2_code_table[] = {
@@ -164,24 +204,63 @@ static const struct tsadc_table v2_code_table[] = {
{3452, 115000},
{3437, 120000},
{3421, 125000},
- {0, 125000},
};
-static u32 rk_tsadcv2_temp_to_code(long temp)
+static const struct tsadc_table v3_code_table[] = {
+ {0, -40000},
+ {106, -40000},
+ {108, -35000},
+ {110, -30000},
+ {112, -25000},
+ {114, -20000},
+ {116, -15000},
+ {118, -10000},
+ {120, -5000},
+ {122, 0},
+ {124, 5000},
+ {126, 10000},
+ {128, 15000},
+ {130, 20000},
+ {132, 25000},
+ {134, 30000},
+ {136, 35000},
+ {138, 40000},
+ {140, 45000},
+ {142, 50000},
+ {144, 55000},
+ {146, 60000},
+ {148, 65000},
+ {150, 70000},
+ {152, 75000},
+ {154, 80000},
+ {156, 85000},
+ {158, 90000},
+ {160, 95000},
+ {162, 100000},
+ {163, 105000},
+ {165, 110000},
+ {167, 115000},
+ {169, 120000},
+ {171, 125000},
+ {TSADCV3_DATA_MASK, 125000},
+};
+
+static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table,
+ int temp)
{
int high, low, mid;
low = 0;
- high = ARRAY_SIZE(v2_code_table) - 1;
+ high = table.length - 1;
mid = (high + low) / 2;
- if (temp < v2_code_table[low].temp || temp > v2_code_table[high].temp)
+ if (temp < table.id[low].temp || temp > table.id[high].temp)
return 0;
while (low <= high) {
- if (temp == v2_code_table[mid].temp)
- return v2_code_table[mid].code;
- else if (temp < v2_code_table[mid].temp)
+ if (temp == table.id[mid].temp)
+ return table.id[mid].code;
+ else if (temp < table.id[mid].temp)
high = mid - 1;
else
low = mid + 1;
@@ -191,27 +270,54 @@ static u32 rk_tsadcv2_temp_to_code(long temp)
return 0;
}
-static int rk_tsadcv2_code_to_temp(u32 code)
+static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code,
+ int *temp)
{
- unsigned int low = 0;
- unsigned int high = ARRAY_SIZE(v2_code_table) - 1;
+ unsigned int low = 1;
+ unsigned int high = table.length - 1;
unsigned int mid = (low + high) / 2;
unsigned int num;
unsigned long denom;
- /* Invalid code, return -EAGAIN */
- if (code > TSADCV2_DATA_MASK)
- return -EAGAIN;
-
- while (low <= high && mid) {
- if (code >= v2_code_table[mid].code &&
- code < v2_code_table[mid - 1].code)
- break;
- else if (code < v2_code_table[mid].code)
- low = mid + 1;
- else
- high = mid - 1;
- mid = (low + high) / 2;
+ WARN_ON(table.length < 2);
+
+ switch (table.mode) {
+ case ADC_DECREMENT:
+ code &= table.data_mask;
+ if (code < table.id[high].code)
+ return -EAGAIN; /* Incorrect reading */
+
+ while (low <= high) {
+ if (code >= table.id[mid].code &&
+ code < table.id[mid - 1].code)
+ break;
+ else if (code < table.id[mid].code)
+ low = mid + 1;
+ else
+ high = mid - 1;
+
+ mid = (low + high) / 2;
+ }
+ break;
+ case ADC_INCREMENT:
+ code &= table.data_mask;
+ if (code < table.id[low].code)
+ return -EAGAIN; /* Incorrect reading */
+
+ while (low <= high) {
+ if (code >= table.id[mid - 1].code &&
+ code < table.id[mid].code)
+ break;
+ else if (code > table.id[mid].code)
+ low = mid + 1;
+ else
+ high = mid - 1;
+
+ mid = (low + high) / 2;
+ }
+ break;
+ default:
+ pr_err("Invalid the conversion table\n");
}
/*
@@ -220,31 +326,37 @@ static int rk_tsadcv2_code_to_temp(u32 code)
* temperature between 2 table entries is linear and interpolate
* to produce less granular result.
*/
- num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp;
- num *= v2_code_table[mid - 1].code - code;
- denom = v2_code_table[mid - 1].code - v2_code_table[mid].code;
- return v2_code_table[mid - 1].temp + (num / denom);
+ num = table.id[mid].temp - v2_code_table[mid - 1].temp;
+ num *= abs(table.id[mid - 1].code - code);
+ denom = abs(table.id[mid - 1].code - table.id[mid].code);
+ *temp = table.id[mid - 1].temp + (num / denom);
+
+ return 0;
}
/**
- * rk_tsadcv2_initialize - initialize TASDC Controller
- * (1) Set TSADCV2_AUTO_PERIOD, configure the interleave between
- * every two accessing of TSADC in normal operation.
- * (2) Set TSADCV2_AUTO_PERIOD_HT, configure the interleave between
- * every two accessing of TSADC after the temperature is higher
- * than COM_SHUT or COM_INT.
- * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE,
- * if the temperature is higher than COMP_INT or COMP_SHUT for
- * "debounce" times, TSADC controller will generate interrupt or TSHUT.
+ * rk_tsadcv2_initialize - initialize TASDC Controller.
+ *
+ * (1) Set TSADC_V2_AUTO_PERIOD:
+ * Configure the interleave between every two accessing of
+ * TSADC in normal operation.
+ *
+ * (2) Set TSADCV2_AUTO_PERIOD_HT:
+ * Configure the interleave between every two accessing of
+ * TSADC after the temperature is higher than COM_SHUT or COM_INT.
+ *
+ * (3) Set TSADCV2_HIGH_INT_DEBOUNCE and TSADC_HIGHT_TSHUT_DEBOUNCE:
+ * If the temperature is higher than COMP_INT or COMP_SHUT for
+ * "debounce" times, TSADC controller will generate interrupt or TSHUT.
*/
static void rk_tsadcv2_initialize(void __iomem *regs,
enum tshut_polarity tshut_polarity)
{
if (tshut_polarity == TSHUT_HIGH_ACTIVE)
- writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_HIGH),
+ writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
regs + TSADCV2_AUTO_CON);
else
- writel_relaxed(0 | (TSADCV2_AUTO_TSHUT_POLARITY_LOW),
+ writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH,
regs + TSADCV2_AUTO_CON);
writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD);
@@ -261,7 +373,7 @@ static void rk_tsadcv2_irq_ack(void __iomem *regs)
u32 val;
val = readl_relaxed(regs + TSADCV2_INT_PD);
- writel_relaxed(val & TSADCV2_INT_PD_CLEAR, regs + TSADCV2_INT_PD);
+ writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD);
}
static void rk_tsadcv2_control(void __iomem *regs, bool enable)
@@ -277,25 +389,22 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable)
writel_relaxed(val, regs + TSADCV2_AUTO_CON);
}
-static int rk_tsadcv2_get_temp(int chn, void __iomem *regs, int *temp)
+static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
+ int chn, void __iomem *regs, int *temp)
{
u32 val;
- /* the A/D value of the channel last conversion need some time */
val = readl_relaxed(regs + TSADCV2_DATA(chn));
- if (val == 0)
- return -EAGAIN;
- *temp = rk_tsadcv2_code_to_temp(val);
-
- return 0;
+ return rk_tsadcv2_code_to_temp(table, val, temp);
}
-static void rk_tsadcv2_tshut_temp(int chn, void __iomem *regs, long temp)
+static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
+ int chn, void __iomem *regs, int temp)
{
u32 tshut_value, val;
- tshut_value = rk_tsadcv2_temp_to_code(temp);
+ tshut_value = rk_tsadcv2_temp_to_code(table, temp);
writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn));
/* TSHUT will be valid */
@@ -321,6 +430,10 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
}
static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
+ .chn_id[SENSOR_CPU] = 1, /* cpu sensor is channel 1 */
+ .chn_id[SENSOR_GPU] = 2, /* gpu sensor is channel 2 */
+ .chn_num = 2, /* two channels for tsadc */
+
.tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
.tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
.tshut_temp = 95000,
@@ -331,6 +444,37 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
.get_temp = rk_tsadcv2_get_temp,
.set_tshut_temp = rk_tsadcv2_tshut_temp,
.set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+ .table = {
+ .id = v2_code_table,
+ .length = ARRAY_SIZE(v2_code_table),
+ .data_mask = TSADCV2_DATA_MASK,
+ .mode = ADC_DECREMENT,
+ },
+};
+
+static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
+ .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
+ .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
+ .chn_num = 2, /* two channels for tsadc */
+
+ .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */
+ .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */
+ .tshut_temp = 95000,
+
+ .initialize = rk_tsadcv2_initialize,
+ .irq_ack = rk_tsadcv2_irq_ack,
+ .control = rk_tsadcv2_control,
+ .get_temp = rk_tsadcv2_get_temp,
+ .set_tshut_temp = rk_tsadcv2_tshut_temp,
+ .set_tshut_mode = rk_tsadcv2_tshut_mode,
+
+ .table = {
+ .id = v3_code_table,
+ .length = ARRAY_SIZE(v3_code_table),
+ .data_mask = TSADCV3_DATA_MASK,
+ .mode = ADC_INCREMENT,
+ },
};
static const struct of_device_id of_rockchip_thermal_match[] = {
@@ -338,6 +482,10 @@ static const struct of_device_id of_rockchip_thermal_match[] = {
.compatible = "rockchip,rk3288-tsadc",
.data = (void *)&rk3288_tsadc_data,
},
+ {
+ .compatible = "rockchip,rk3368-tsadc",
+ .data = (void *)&rk3368_tsadc_data,
+ },
{ /* end */ },
};
MODULE_DEVICE_TABLE(of, of_rockchip_thermal_match);
@@ -360,7 +508,7 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
thermal->chip->irq_ack(thermal->regs);
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+ for (i = 0; i < thermal->chip->chn_num; i++)
thermal_zone_device_update(thermal->sensors[i].tzd);
return IRQ_HANDLED;
@@ -373,7 +521,8 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
const struct rockchip_tsadc_chip *tsadc = sensor->thermal->chip;
int retval;
- retval = tsadc->get_temp(sensor->id, thermal->regs, out_temp);
+ retval = tsadc->get_temp(tsadc->table,
+ sensor->id, thermal->regs, out_temp);
dev_dbg(&thermal->pdev->dev, "sensor %d - temp: %d, retval: %d\n",
sensor->id, *out_temp, retval);
@@ -392,7 +541,7 @@ static int rockchip_configure_from_dt(struct device *dev,
if (of_property_read_u32(np, "rockchip,hw-tshut-temp", &shut_temp)) {
dev_warn(dev,
- "Missing tshut temp property, using default %ld\n",
+ "Missing tshut temp property, using default %d\n",
thermal->chip->tshut_temp);
thermal->tshut_temp = thermal->chip->tshut_temp;
} else {
@@ -400,7 +549,7 @@ static int rockchip_configure_from_dt(struct device *dev,
}
if (thermal->tshut_temp > INT_MAX) {
- dev_err(dev, "Invalid tshut temperature specified: %ld\n",
+ dev_err(dev, "Invalid tshut temperature specified: %d\n",
thermal->tshut_temp);
return -ERANGE;
}
@@ -445,13 +594,14 @@ static int
rockchip_thermal_register_sensor(struct platform_device *pdev,
struct rockchip_thermal_data *thermal,
struct rockchip_thermal_sensor *sensor,
- enum sensor_id id)
+ int id)
{
const struct rockchip_tsadc_chip *tsadc = thermal->chip;
int error;
tsadc->set_tshut_mode(id, thermal->regs, thermal->tshut_mode);
- tsadc->set_tshut_temp(id, thermal->regs, thermal->tshut_temp);
+ tsadc->set_tshut_temp(tsadc->table, id, thermal->regs,
+ thermal->tshut_temp);
sensor->thermal = thermal;
sensor->id = id;
@@ -484,7 +634,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
const struct of_device_id *match;
struct resource *res;
int irq;
- int i;
+ int i, j;
int error;
match = of_match_node(of_rockchip_thermal_match, np);
@@ -559,22 +709,19 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
- error = rockchip_thermal_register_sensor(pdev, thermal,
- &thermal->sensors[0],
- SENSOR_CPU);
- if (error) {
- dev_err(&pdev->dev,
- "failed to register CPU thermal sensor: %d\n", error);
- goto err_disable_pclk;
- }
-
- error = rockchip_thermal_register_sensor(pdev, thermal,
- &thermal->sensors[1],
- SENSOR_GPU);
- if (error) {
- dev_err(&pdev->dev,
- "failed to register GPU thermal sensor: %d\n", error);
- goto err_unregister_cpu_sensor;
+ for (i = 0; i < thermal->chip->chn_num; i++) {
+ error = rockchip_thermal_register_sensor(pdev, thermal,
+ &thermal->sensors[i],
+ thermal->chip->chn_id[i]);
+ if (error) {
+ dev_err(&pdev->dev,
+ "failed to register sensor[%d] : error = %d\n",
+ i, error);
+ for (j = 0; j < i; j++)
+ thermal_zone_of_sensor_unregister(&pdev->dev,
+ thermal->sensors[j].tzd);
+ goto err_disable_pclk;
+ }
}
error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
@@ -584,22 +731,23 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
if (error) {
dev_err(&pdev->dev,
"failed to request tsadc irq: %d\n", error);
- goto err_unregister_gpu_sensor;
+ goto err_unregister_sensor;
}
thermal->chip->control(thermal->regs, true);
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+ for (i = 0; i < thermal->chip->chn_num; i++)
rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
platform_set_drvdata(pdev, thermal);
return 0;
-err_unregister_gpu_sensor:
- thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[1].tzd);
-err_unregister_cpu_sensor:
- thermal_zone_of_sensor_unregister(&pdev->dev, thermal->sensors[0].tzd);
+err_unregister_sensor:
+ while (i--)
+ thermal_zone_of_sensor_unregister(&pdev->dev,
+ thermal->sensors[i].tzd);
+
err_disable_pclk:
clk_disable_unprepare(thermal->pclk);
err_disable_clk:
@@ -613,7 +761,7 @@ static int rockchip_thermal_remove(struct platform_device *pdev)
struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
+ for (i = 0; i < thermal->chip->chn_num; i++) {
struct rockchip_thermal_sensor *sensor = &thermal->sensors[i];
rockchip_thermal_toggle_sensor(sensor, false);
@@ -634,7 +782,7 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+ for (i = 0; i < thermal->chip->chn_num; i++)
rockchip_thermal_toggle_sensor(&thermal->sensors[i], false);
thermal->chip->control(thermal->regs, false);
@@ -642,6 +790,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
clk_disable(thermal->pclk);
clk_disable(thermal->clk);
+ pinctrl_pm_select_sleep_state(dev);
+
return 0;
}
@@ -664,20 +814,23 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
thermal->chip->initialize(thermal->regs, thermal->tshut_polarity);
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++) {
- enum sensor_id id = thermal->sensors[i].id;
+ for (i = 0; i < thermal->chip->chn_num; i++) {
+ int id = thermal->sensors[i].id;
thermal->chip->set_tshut_mode(id, thermal->regs,
thermal->tshut_mode);
- thermal->chip->set_tshut_temp(id, thermal->regs,
+ thermal->chip->set_tshut_temp(thermal->chip->table,
+ id, thermal->regs,
thermal->tshut_temp);
}
thermal->chip->control(thermal->regs, true);
- for (i = 0; i < ARRAY_SIZE(thermal->sensors); i++)
+ for (i = 0; i < thermal->chip->chn_num; i++)
rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
+ pinctrl_pm_select_default_state(dev);
+
return 0;
}
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index ca920b0..fa61eff 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -548,7 +548,7 @@ static int exynos5433_tmu_initialize(struct platform_device *pdev)
default:
pdata->cal_type = TYPE_ONE_POINT_TRIMMING;
break;
- };
+ }
dev_info(&pdev->dev, "Calibration type is %d-point calibration\n",
cal_type ? 2 : 1);
@@ -608,7 +608,7 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
unsigned int trim_info = 0, con, rising_threshold;
- int ret = 0, threshold_code;
+ int threshold_code;
int crit_temp = 0;
/*
@@ -651,7 +651,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
/* Clear the PMIN in the common TMU register */
if (!data->id)
writel(0, data->base_second + EXYNOS5440_TMU_PMIN);
- return ret;
+
+ return 0;
}
static int exynos7_tmu_initialize(struct platform_device *pdev)
@@ -1168,27 +1169,10 @@ static int exynos_map_dt_data(struct platform_device *pdev)
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
struct exynos_tmu_platform_data *pdata;
struct resource res;
- int ret;
if (!data || !pdev->dev.of_node)
return -ENODEV;
- /*
- * Try enabling the regulator if found
- * TODO: Add regulator as an SOC feature, so that regulator enable
- * is a compulsory call.
- */
- data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
- if (!IS_ERR(data->regulator)) {
- ret = regulator_enable(data->regulator);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable vtmu\n");
- return ret;
- }
- } else {
- dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
- }
-
data->id = of_alias_get_id(pdev->dev.of_node, "tmuctrl");
if (data->id < 0)
data->id = 0;
@@ -1306,12 +1290,22 @@ static int exynos_tmu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
mutex_init(&data->lock);
- data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
- &exynos_sensor_ops);
- if (IS_ERR(data->tzd)) {
- pr_err("thermal: tz: %p ERROR\n", data->tzd);
- return PTR_ERR(data->tzd);
+ /*
+ * Try enabling the regulator if found
+ * TODO: Add regulator as an SOC feature, so that regulator enable
+ * is a compulsory call.
+ */
+ data->regulator = devm_regulator_get(&pdev->dev, "vtmu");
+ if (!IS_ERR(data->regulator)) {
+ ret = regulator_enable(data->regulator);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable vtmu\n");
+ return ret;
+ }
+ } else {
+ dev_info(&pdev->dev, "Regulator node (vtmu) not found\n");
}
+
ret = exynos_map_dt_data(pdev);
if (ret)
goto err_sensor;
@@ -1363,23 +1357,38 @@ static int exynos_tmu_probe(struct platform_device *pdev)
break;
default:
break;
- };
+ }
+
+ /*
+ * data->tzd must be registered before calling exynos_tmu_initialize(),
+ * requesting irq and calling exynos_tmu_control().
+ */
+ data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+ &exynos_sensor_ops);
+ if (IS_ERR(data->tzd)) {
+ ret = PTR_ERR(data->tzd);
+ dev_err(&pdev->dev, "Failed to register sensor: %d\n", ret);
+ goto err_sclk;
+ }
ret = exynos_tmu_initialize(pdev);
if (ret) {
dev_err(&pdev->dev, "Failed to initialize TMU\n");
- goto err_sclk;
+ goto err_thermal;
}
ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
- goto err_sclk;
+ goto err_thermal;
}
exynos_tmu_control(pdev, true);
return 0;
+
+err_thermal:
+ thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
err_sclk:
clk_disable_unprepare(data->sclk);
err_clk:
@@ -1388,9 +1397,8 @@ err_clk_sec:
if (!IS_ERR(data->clk_sec))
clk_unprepare(data->clk_sec);
err_sensor:
- if (!IS_ERR_OR_NULL(data->regulator))
+ if (!IS_ERR(data->regulator))
regulator_disable(data->regulator);
- thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
return ret;
}
diff --git a/drivers/thermal/ti-soc-thermal/Kconfig b/drivers/thermal/ti-soc-thermal/Kconfig
index cb6686f..ea8283f 100644
--- a/drivers/thermal/ti-soc-thermal/Kconfig
+++ b/drivers/thermal/ti-soc-thermal/Kconfig
@@ -19,6 +19,21 @@ config TI_THERMAL
This includes trip points definitions, extrapolation rules and
CPU cooling device bindings.
+config OMAP3_THERMAL
+ bool "Texas Instruments OMAP3 thermal support"
+ depends on TI_SOC_THERMAL
+ depends on ARCH_OMAP3 || COMPILE_TEST
+ help
+ If you say yes here you get thermal support for the Texas Instruments
+ OMAP3 SoC family. The current chips supported are:
+ - OMAP3430
+
+ OMAP3 chips normally don't need thermal management, and sensors in
+ this generation are not accurate, nor they are very close to
+ the important hotspots.
+
+ Say 'N' here.
+
config OMAP4_THERMAL
bool "Texas Instruments OMAP4 thermal support"
depends on TI_SOC_THERMAL
diff --git a/drivers/thermal/ti-soc-thermal/Makefile b/drivers/thermal/ti-soc-thermal/Makefile
index 1226b24..0f89bdf 100644
--- a/drivers/thermal/ti-soc-thermal/Makefile
+++ b/drivers/thermal/ti-soc-thermal/Makefile
@@ -2,5 +2,6 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal.o
ti-soc-thermal-y := ti-bandgap.o
ti-soc-thermal-$(CONFIG_TI_THERMAL) += ti-thermal-common.o
ti-soc-thermal-$(CONFIG_DRA752_THERMAL) += dra752-thermal-data.o
+ti-soc-thermal-$(CONFIG_OMAP3_THERMAL) += omap3-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP4_THERMAL) += omap4-thermal-data.o
ti-soc-thermal-$(CONFIG_OMAP5_THERMAL) += omap5-thermal-data.o
diff --git a/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c
new file mode 100644
index 0000000..3ee3434
--- /dev/null
+++ b/drivers/thermal/ti-soc-thermal/omap3-thermal-data.c
@@ -0,0 +1,176 @@
+/*
+ * OMAP3 thermal driver.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Inc.
+ * Copyright (C) 2014 Pavel Machek <pavel@ucw.cz>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Note
+ * http://www.ti.com/lit/er/sprz278f/sprz278f.pdf "Advisory
+ * 3.1.1.186 MMC OCP Clock Not Gated When Thermal Sensor Is Used"
+ *
+ * Also TI says:
+ * Just be careful when you try to make thermal policy like decisions
+ * based on this sensor. Placement of the sensor w.r.t the actual logic
+ * generating heat has to be a factor as well. If you are just looking
+ * for an approximation temperature (thermometerish kind), you might be
+ * ok with this. I am not sure we'd find any TI data around this.. just a
+ * heads up.
+ */
+
+#include "ti-thermal.h"
+#include "ti-bandgap.h"
+
+/*
+ * OMAP34XX has one instance of thermal sensor for MPU
+ * need to describe the individual bit fields
+ */
+static struct temp_sensor_registers
+omap34xx_mpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = 0,
+ .bgap_soc_mask = BIT(8),
+ .bgap_eocz_mask = BIT(7),
+ .bgap_dtemp_mask = 0x7f,
+
+ .bgap_mode_ctrl = 0,
+ .mode_ctrl_mask = BIT(9),
+};
+
+/* Thresholds and limits for OMAP34XX MPU temperature sensor */
+static struct temp_sensor_data omap34xx_mpu_temp_sensor_data = {
+ .min_freq = 32768,
+ .max_freq = 32768,
+ .max_temp = 125000,
+ .min_temp = -40000,
+ .hyst_val = 5000,
+};
+
+/*
+ * Temperature values in milli degree celsius
+ */
+static const int
+omap34xx_adc_to_temp[128] = {
+ -40000, -40000, -40000, -40000, -40000, -39000, -38000, -36000,
+ -34000, -32000, -31000, -29000, -28000, -26000, -25000, -24000,
+ -22000, -21000, -19000, -18000, -17000, -15000, -14000, -12000,
+ -11000, -9000, -8000, -7000, -5000, -4000, -2000, -1000, 0000,
+ 1000, 3000, 4000, 5000, 7000, 8000, 10000, 11000, 13000, 14000,
+ 15000, 17000, 18000, 20000, 21000, 22000, 24000, 25000, 27000,
+ 28000, 30000, 31000, 32000, 34000, 35000, 37000, 38000, 39000,
+ 41000, 42000, 44000, 45000, 47000, 48000, 49000, 51000, 52000,
+ 53000, 55000, 56000, 58000, 59000, 60000, 62000, 63000, 65000,
+ 66000, 67000, 69000, 70000, 72000, 73000, 74000, 76000, 77000,
+ 79000, 80000, 81000, 83000, 84000, 85000, 87000, 88000, 89000,
+ 91000, 92000, 94000, 95000, 96000, 98000, 99000, 100000,
+ 102000, 103000, 105000, 106000, 107000, 109000, 110000, 111000,
+ 113000, 114000, 116000, 117000, 118000, 120000, 121000, 122000,
+ 124000, 124000, 125000, 125000, 125000, 125000, 125000
+};
+
+/* OMAP34XX data */
+const struct ti_bandgap_data omap34xx_data = {
+ .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE,
+ .fclock_name = "ts_fck",
+ .div_ck_name = "ts_fck",
+ .conv_table = omap34xx_adc_to_temp,
+ .adc_start_val = 0,
+ .adc_end_val = 127,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+
+ .sensors = {
+ {
+ .registers = &omap34xx_mpu_temp_sensor_registers,
+ .ts_data = &omap34xx_mpu_temp_sensor_data,
+ .domain = "cpu",
+ .slope = 0,
+ .constant = 20000,
+ .slope_pcb = 0,
+ .constant_pcb = 20000,
+ .register_cooling = NULL,
+ .unregister_cooling = NULL,
+ },
+ },
+ .sensor_count = 1,
+};
+
+/*
+ * OMAP36XX has one instance of thermal sensor for MPU
+ * need to describe the individual bit fields
+ */
+static struct temp_sensor_registers
+omap36xx_mpu_temp_sensor_registers = {
+ .temp_sensor_ctrl = 0,
+ .bgap_soc_mask = BIT(9),
+ .bgap_eocz_mask = BIT(8),
+ .bgap_dtemp_mask = 0xFF,
+
+ .bgap_mode_ctrl = 0,
+ .mode_ctrl_mask = BIT(10),
+};
+
+/* Thresholds and limits for OMAP36XX MPU temperature sensor */
+static struct temp_sensor_data omap36xx_mpu_temp_sensor_data = {
+ .min_freq = 32768,
+ .max_freq = 32768,
+ .max_temp = 125000,
+ .min_temp = -40000,
+ .hyst_val = 5000,
+};
+
+/*
+ * Temperature values in milli degree celsius
+ */
+static const int
+omap36xx_adc_to_temp[128] = {
+ -40000, -40000, -40000, -40000, -40000, -40000, -40000, -40000,
+ -40000, -40000, -40000, -40000, -40000, -38000, -35000, -34000,
+ -32000, -30000, -28000, -26000, -24000, -22000, -20000, -18500,
+ -17000, -15000, -13500, -12000, -10000, -8000, -6500, -5000, -3500,
+ -1500, 0, 2000, 3500, 5000, 6500, 8500, 10000, 12000, 13500,
+ 15000, 17000, 19000, 21000, 23000, 25000, 27000, 28500, 30000,
+ 32000, 33500, 35000, 37000, 38500, 40000, 42000, 43500, 45000,
+ 47000, 48500, 50000, 52000, 53500, 55000, 57000, 58500, 60000,
+ 62000, 64000, 66000, 68000, 70000, 71500, 73500, 75000, 77000,
+ 78500, 80000, 82000, 83500, 85000, 87000, 88500, 90000, 92000,
+ 93500, 95000, 97000, 98500, 100000, 102000, 103500, 105000, 107000,
+ 109000, 111000, 113000, 115000, 117000, 118500, 120000, 122000,
+ 123500, 125000, 125000, 125000, 125000, 125000, 125000, 125000,
+ 125000, 125000, 125000, 125000, 125000, 125000, 125000, 125000,
+ 125000, 125000, 125000, 125000, 125000, 125000, 125000
+};
+
+/* OMAP36XX data */
+const struct ti_bandgap_data omap36xx_data = {
+ .features = TI_BANDGAP_FEATURE_CLK_CTRL | TI_BANDGAP_FEATURE_UNRELIABLE,
+ .fclock_name = "ts_fck",
+ .div_ck_name = "ts_fck",
+ .conv_table = omap36xx_adc_to_temp,
+ .adc_start_val = 0,
+ .adc_end_val = 127,
+ .expose_sensor = ti_thermal_expose_sensor,
+ .remove_sensor = ti_thermal_remove_sensor,
+
+ .sensors = {
+ {
+ .registers = &omap36xx_mpu_temp_sensor_registers,
+ .ts_data = &omap36xx_mpu_temp_sensor_data,
+ .domain = "cpu",
+ .slope = 0,
+ .constant = 20000,
+ .slope_pcb = 0,
+ .constant_pcb = 20000,
+ .register_cooling = NULL,
+ .unregister_cooling = NULL,
+ },
+ },
+ .sensor_count = 1,
+};
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
index 10c47c0..1e34a1e 100644
--- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c
@@ -1274,6 +1274,10 @@ int ti_bandgap_probe(struct platform_device *pdev)
}
bgp->dev = &pdev->dev;
+ if (TI_BANDGAP_HAS(bgp, UNRELIABLE))
+ dev_warn(&pdev->dev,
+ "This OMAP thermal sensor is unreliable. You've been warned\n");
+
if (TI_BANDGAP_HAS(bgp, TSHUT)) {
ret = ti_bandgap_tshut_init(bgp, pdev);
if (ret) {
@@ -1579,6 +1583,16 @@ static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend,
#endif
static const struct of_device_id of_ti_bandgap_match[] = {
+#ifdef CONFIG_OMAP3_THERMAL
+ {
+ .compatible = "ti,omap34xx-bandgap",
+ .data = (void *)&omap34xx_data,
+ },
+ {
+ .compatible = "ti,omap36xx-bandgap",
+ .data = (void *)&omap36xx_data,
+ },
+#endif
#ifdef CONFIG_OMAP4_THERMAL
{
.compatible = "ti,omap4430-bandgap",
diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.h b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
index 0c52f7a..fe0adb8 100644
--- a/drivers/thermal/ti-soc-thermal/ti-bandgap.h
+++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.h
@@ -322,6 +322,8 @@ struct ti_temp_sensor {
* has Errata 814
* TI_BANDGAP_FEATURE_ERRATA_813 - used to workaorund when the bandgap device
* has Errata 813
+ * TI_BANDGAP_FEATURE_UNRELIABLE - used when the sensor readings are too
+ * inaccurate.
* TI_BANDGAP_HAS(b, f) - macro to check if a bandgap device is capable of a
* specific feature (above) or not. Return non-zero, if yes.
*/
@@ -337,6 +339,7 @@ struct ti_temp_sensor {
#define TI_BANDGAP_FEATURE_HISTORY_BUFFER BIT(9)
#define TI_BANDGAP_FEATURE_ERRATA_814 BIT(10)
#define TI_BANDGAP_FEATURE_ERRATA_813 BIT(11)
+#define TI_BANDGAP_FEATURE_UNRELIABLE BIT(12)
#define TI_BANDGAP_HAS(b, f) \
((b)->conf->features & TI_BANDGAP_FEATURE_ ## f)
@@ -390,6 +393,14 @@ int ti_bandgap_set_sensor_data(struct ti_bandgap *bgp, int id, void *data);
void *ti_bandgap_get_sensor_data(struct ti_bandgap *bgp, int id);
int ti_bandgap_get_trend(struct ti_bandgap *bgp, int id, int *trend);
+#ifdef CONFIG_OMAP3_THERMAL
+extern const struct ti_bandgap_data omap34xx_data;
+extern const struct ti_bandgap_data omap36xx_data;
+#else
+#define omap34xx_data NULL
+#define omap36xx_data NULL
+#endif
+
#ifdef CONFIG_OMAP4_THERMAL
extern const struct ti_bandgap_data omap4430_data;
extern const struct ti_bandgap_data omap4460_data;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 1384426..e49c2bce 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -169,7 +169,7 @@ static inline int tty_copy_to_user(struct tty_struct *tty,
{
struct n_tty_data *ldata = tty->disc_data;
- tty_audit_add_data(tty, to, n, ldata->icanon);
+ tty_audit_add_data(tty, from, n, ldata->icanon);
return copy_to_user(to, from, n);
}
@@ -2054,13 +2054,13 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
size_t eol;
size_t tail;
int ret, found = 0;
- bool eof_push = 0;
/* N.B. avoid overrun if nr == 0 */
- n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
- if (!n)
+ if (!*nr)
return 0;
+ n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
+
tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
size = min_t(size_t, tail + n, N_TTY_BUF_SIZE);
@@ -2081,12 +2081,11 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
n = eol - tail;
if (n > N_TTY_BUF_SIZE)
n += N_TTY_BUF_SIZE;
- n += found;
- c = n;
+ c = n + found;
- if (found && !ldata->push && read_buf(ldata, eol) == __DISABLED_CHAR) {
- n--;
- eof_push = !n && ldata->read_tail != ldata->line_start;
+ if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) {
+ c = min(*nr, c);
+ n = c;
}
n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu size:%zu more:%zu\n",
@@ -2116,7 +2115,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
ldata->push = 0;
tty_audit_push(tty);
}
- return eof_push ? -EAGAIN : 0;
+ return 0;
}
extern ssize_t redirected_tty_write(struct file *, const char __user *,
@@ -2273,10 +2272,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
if (ldata->icanon && !L_EXTPROC(tty)) {
retval = canon_copy_from_read_buf(tty, &b, &nr);
- if (retval == -EAGAIN) {
- retval = 0;
- continue;
- } else if (retval)
+ if (retval)
break;
} else {
int uncopied;
diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c
index c0533a5..910bfee 100644
--- a/drivers/tty/serial/8250/8250_fsl.c
+++ b/drivers/tty/serial/8250/8250_fsl.c
@@ -60,3 +60,4 @@ int fsl8250_handle_irq(struct uart_port *port)
spin_unlock_irqrestore(&up->port.lock, flags);
return 1;
}
+EXPORT_SYMBOL_GPL(fsl8250_handle_irq);
diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c
index d11621e..245edbb 100644
--- a/drivers/tty/serial/8250/8250_uniphier.c
+++ b/drivers/tty/serial/8250/8250_uniphier.c
@@ -115,12 +115,16 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value)
*/
static int uniphier_serial_dl_read(struct uart_8250_port *up)
{
- return readl(up->port.membase + UNIPHIER_UART_DLR);
+ int offset = UNIPHIER_UART_DLR << up->port.regshift;
+
+ return readl(up->port.membase + offset);
}
static void uniphier_serial_dl_write(struct uart_8250_port *up, int value)
{
- writel(value, up->port.membase + UNIPHIER_UART_DLR);
+ int offset = UNIPHIER_UART_DLR << up->port.regshift;
+
+ writel(value, up->port.membase + offset);
}
static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port,
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index e6f5e12..6412f14 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -373,6 +373,7 @@ config SERIAL_8250_MID
depends on SERIAL_8250 && PCI
select HSU_DMA if SERIAL_8250_DMA
select HSU_DMA_PCI if X86_INTEL_MID
+ select RATIONAL
help
Selecting this option will enable handling of the extra features
present on the UART found on Intel Medfield SOC and various other
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 1aec440..f38beb2 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1539,7 +1539,6 @@ config SERIAL_FSL_LPUART
tristate "Freescale lpuart serial port support"
depends on HAS_DMA
select SERIAL_CORE
- select SERIAL_EARLYCON
help
Support for the on-chip lpuart on some Freescale SOCs.
@@ -1547,6 +1546,7 @@ config SERIAL_FSL_LPUART_CONSOLE
bool "Console on Freescale lpuart serial port"
depends on SERIAL_FSL_LPUART=y
select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
help
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
diff --git a/drivers/tty/serial/bcm63xx_uart.c b/drivers/tty/serial/bcm63xx_uart.c
index 681e0f3..a1c0a89 100644
--- a/drivers/tty/serial/bcm63xx_uart.c
+++ b/drivers/tty/serial/bcm63xx_uart.c
@@ -474,7 +474,7 @@ static int bcm_uart_startup(struct uart_port *port)
/* register irq and enable rx interrupts */
ret = request_irq(port->irq, bcm_uart_interrupt, 0,
- bcm_uart_type(port), port);
+ dev_name(port->dev), port);
if (ret)
return ret;
bcm_uart_writel(port, UART_RX_INT_MASK, UART_IR_REG);
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index f096360..b5b2f2b 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -115,6 +115,7 @@ static int __init register_earlycon(char *buf, const struct earlycon_id *match)
if (buf && !parse_options(&early_console_dev, buf))
buf = NULL;
+ spin_lock_init(&port->lock);
port->uartclk = BASE_BAUD * 16;
if (port->mapbase)
port->membase = earlycon_map(port->mapbase, 64);
@@ -202,6 +203,7 @@ int __init of_setup_earlycon(unsigned long addr,
int err;
struct uart_port *port = &early_console_dev.port;
+ spin_lock_init(&port->lock);
port->iotype = UPIO_MEM;
port->mapbase = addr;
port->uartclk = BASE_BAUD * 16;
diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c
index 6813e31..2f80bc7 100644
--- a/drivers/tty/serial/etraxfs-uart.c
+++ b/drivers/tty/serial/etraxfs-uart.c
@@ -894,7 +894,7 @@ static int etraxfs_uart_probe(struct platform_device *pdev)
up->regi_ser = of_iomap(np, 0);
up->port.dev = &pdev->dev;
- up->gpios = mctrl_gpio_init(&pdev->dev, 0);
+ up->gpios = mctrl_gpio_init_noauto(&pdev->dev, 0);
if (IS_ERR(up->gpios))
return PTR_ERR(up->gpios);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index 960e50a..51c7507 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -1437,7 +1437,7 @@ static void sci_request_dma(struct uart_port *port)
sg_init_table(sg, 1);
s->rx_buf[i] = buf;
sg_dma_address(sg) = dma;
- sg->length = s->buf_len_rx;
+ sg_dma_len(sg) = s->buf_len_rx;
buf += s->buf_len_rx;
dma += s->buf_len_rx;
diff --git a/drivers/tty/serial/sunhv.c b/drivers/tty/serial/sunhv.c
index 0640318..ca0d380 100644
--- a/drivers/tty/serial/sunhv.c
+++ b/drivers/tty/serial/sunhv.c
@@ -148,8 +148,10 @@ static int receive_chars_read(struct uart_port *port)
uart_handle_dcd_change(port, 1);
}
- for (i = 0; i < bytes_read; i++)
- uart_handle_sysrq_char(port, con_read_page[i]);
+ if (port->sysrq != 0 && *con_read_page) {
+ for (i = 0; i < bytes_read; i++)
+ uart_handle_sysrq_char(port, con_read_page[i]);
+ }
if (port->state == NULL)
continue;
@@ -168,17 +170,17 @@ struct sunhv_ops {
int (*receive_chars)(struct uart_port *port);
};
-static struct sunhv_ops bychar_ops = {
+static const struct sunhv_ops bychar_ops = {
.transmit_chars = transmit_chars_putchar,
.receive_chars = receive_chars_getchar,
};
-static struct sunhv_ops bywrite_ops = {
+static const struct sunhv_ops bywrite_ops = {
.transmit_chars = transmit_chars_write,
.receive_chars = receive_chars_read,
};
-static struct sunhv_ops *sunhv_ops = &bychar_ops;
+static const struct sunhv_ops *sunhv_ops = &bychar_ops;
static struct tty_port *receive_chars(struct uart_port *port)
{
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 5381a72..e513940 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -133,6 +133,12 @@ static void sysrq_handle_crash(int key)
{
char *killer = NULL;
+ /* we need to release the RCU read lock here,
+ * otherwise we get an annoying
+ * 'BUG: sleeping function called from invalid context'
+ * complaint from the kernel before the panic.
+ */
+ rcu_read_unlock();
panic_on_oops = 1; /* force panic */
wmb();
*killer = 1;
diff --git a/drivers/tty/tty_audit.c b/drivers/tty/tty_audit.c
index 90ca082..3d245cd 100644
--- a/drivers/tty/tty_audit.c
+++ b/drivers/tty/tty_audit.c
@@ -265,7 +265,7 @@ static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty,
*
* Audit @data of @size from @tty, if necessary.
*/
-void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+void tty_audit_add_data(struct tty_struct *tty, const void *data,
size_t size, unsigned icanon)
{
struct tty_audit_buf *buf;
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 9a479e6..3cd31e0 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -450,7 +450,7 @@ receive_buf(struct tty_struct *tty, struct tty_buffer *head, int count)
count = disc->ops->receive_buf2(tty, p, f, count);
else {
count = min_t(int, count, tty->receive_room);
- if (count)
+ if (count && disc->ops->receive_buf)
disc->ops->receive_buf(tty, p, f, count);
}
return count;
diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c
index 0c41dbc..bcc8e1e 100644
--- a/drivers/tty/tty_io.c
+++ b/drivers/tty/tty_io.c
@@ -1282,18 +1282,22 @@ int tty_send_xchar(struct tty_struct *tty, char ch)
int was_stopped = tty->stopped;
if (tty->ops->send_xchar) {
+ down_read(&tty->termios_rwsem);
tty->ops->send_xchar(tty, ch);
+ up_read(&tty->termios_rwsem);
return 0;
}
if (tty_write_lock(tty, 0) < 0)
return -ERESTARTSYS;
+ down_read(&tty->termios_rwsem);
if (was_stopped)
start_tty(tty);
tty->ops->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
+ up_read(&tty->termios_rwsem);
tty_write_unlock(tty);
return 0;
}
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 9c5aebf..1445dd3 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -1147,16 +1147,12 @@ int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
spin_unlock_irq(&tty->flow_lock);
break;
case TCIOFF:
- down_read(&tty->termios_rwsem);
if (STOP_CHAR(tty) != __DISABLED_CHAR)
retval = tty_send_xchar(tty, STOP_CHAR(tty));
- up_read(&tty->termios_rwsem);
break;
case TCION:
- down_read(&tty->termios_rwsem);
if (START_CHAR(tty) != __DISABLED_CHAR)
retval = tty_send_xchar(tty, START_CHAR(tty));
- up_read(&tty->termios_rwsem);
break;
default:
return -EINVAL;
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c
index 5af8f18..629e3c8 100644
--- a/drivers/tty/tty_ldisc.c
+++ b/drivers/tty/tty_ldisc.c
@@ -592,7 +592,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
/* Restart the work queue in case no characters kick it off. Safe if
already running */
- schedule_work(&tty->port->buf.work);
+ tty_buffer_restart_work(tty->port);
tty_unlock(tty);
return retval;
diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c
index 6ccbf60..5a048b7 100644
--- a/drivers/usb/chipidea/ci_hdrc_imx.c
+++ b/drivers/usb/chipidea/ci_hdrc_imx.c
@@ -84,6 +84,12 @@ struct ci_hdrc_imx_data {
struct imx_usbmisc_data *usbmisc_data;
bool supports_runtime_pm;
bool in_lpm;
+ /* SoC before i.mx6 (except imx23/imx28) needs three clks */
+ bool need_three_clks;
+ struct clk *clk_ipg;
+ struct clk *clk_ahb;
+ struct clk *clk_per;
+ /* --------------------------------- */
};
/* Common functions shared by usbmisc drivers */
@@ -135,6 +141,102 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
}
/* End of common functions shared by usbmisc drivers*/
+static int imx_get_clks(struct device *dev)
+{
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ data->clk_ipg = devm_clk_get(dev, "ipg");
+ if (IS_ERR(data->clk_ipg)) {
+ /* If the platform only needs one clocks */
+ data->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(data->clk)) {
+ ret = PTR_ERR(data->clk);
+ dev_err(dev,
+ "Failed to get clks, err=%ld,%ld\n",
+ PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
+ return ret;
+ }
+ return ret;
+ }
+
+ data->clk_ahb = devm_clk_get(dev, "ahb");
+ if (IS_ERR(data->clk_ahb)) {
+ ret = PTR_ERR(data->clk_ahb);
+ dev_err(dev,
+ "Failed to get ahb clock, err=%d\n", ret);
+ return ret;
+ }
+
+ data->clk_per = devm_clk_get(dev, "per");
+ if (IS_ERR(data->clk_per)) {
+ ret = PTR_ERR(data->clk_per);
+ dev_err(dev,
+ "Failed to get per clock, err=%d\n", ret);
+ return ret;
+ }
+
+ data->need_three_clks = true;
+ return ret;
+}
+
+static int imx_prepare_enable_clks(struct device *dev)
+{
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (data->need_three_clks) {
+ ret = clk_prepare_enable(data->clk_ipg);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable ipg clk, err=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk_ahb);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable ahb clk, err=%d\n",
+ ret);
+ clk_disable_unprepare(data->clk_ipg);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(data->clk_per);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable per clk, err=%d\n",
+ ret);
+ clk_disable_unprepare(data->clk_ahb);
+ clk_disable_unprepare(data->clk_ipg);
+ return ret;
+ }
+ } else {
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(dev,
+ "Failed to prepare/enable clk, err=%d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void imx_disable_unprepare_clks(struct device *dev)
+{
+ struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
+
+ if (data->need_three_clks) {
+ clk_disable_unprepare(data->clk_per);
+ clk_disable_unprepare(data->clk_ahb);
+ clk_disable_unprepare(data->clk_ipg);
+ } else {
+ clk_disable_unprepare(data->clk);
+ }
+}
static int ci_hdrc_imx_probe(struct platform_device *pdev)
{
@@ -145,31 +247,31 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
.flags = CI_HDRC_SET_NON_ZERO_TTHA,
};
int ret;
- const struct of_device_id *of_id =
- of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
- const struct ci_hdrc_imx_platform_flag *imx_platform_flag = of_id->data;
+ const struct of_device_id *of_id;
+ const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
+
+ of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
+ if (!of_id)
+ return -ENODEV;
+
+ imx_platform_flag = of_id->data;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
+ platform_set_drvdata(pdev, data);
data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
if (IS_ERR(data->usbmisc_data))
return PTR_ERR(data->usbmisc_data);
- data->clk = devm_clk_get(&pdev->dev, NULL);
- if (IS_ERR(data->clk)) {
- dev_err(&pdev->dev,
- "Failed to get clock, err=%ld\n", PTR_ERR(data->clk));
- return PTR_ERR(data->clk);
- }
+ ret = imx_get_clks(&pdev->dev);
+ if (ret)
+ return ret;
- ret = clk_prepare_enable(data->clk);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to prepare or enable clock, err=%d\n", ret);
+ ret = imx_prepare_enable_clks(&pdev->dev);
+ if (ret)
return ret;
- }
data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
if (IS_ERR(data->phy)) {
@@ -212,8 +314,6 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
goto disable_device;
}
- platform_set_drvdata(pdev, data);
-
if (data->supports_runtime_pm) {
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
@@ -226,7 +326,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
disable_device:
ci_hdrc_remove_device(data->ci_pdev);
err_clk:
- clk_disable_unprepare(data->clk);
+ imx_disable_unprepare_clks(&pdev->dev);
return ret;
}
@@ -240,7 +340,7 @@ static int ci_hdrc_imx_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
}
ci_hdrc_remove_device(data->ci_pdev);
- clk_disable_unprepare(data->clk);
+ imx_disable_unprepare_clks(&pdev->dev);
return 0;
}
@@ -252,7 +352,7 @@ static int imx_controller_suspend(struct device *dev)
dev_dbg(dev, "at %s\n", __func__);
- clk_disable_unprepare(data->clk);
+ imx_disable_unprepare_clks(dev);
data->in_lpm = true;
return 0;
@@ -270,7 +370,7 @@ static int imx_controller_resume(struct device *dev)
return 0;
}
- ret = clk_prepare_enable(data->clk);
+ ret = imx_prepare_enable_clks(dev);
if (ret)
return ret;
@@ -285,7 +385,7 @@ static int imx_controller_resume(struct device *dev)
return 0;
clk_disable:
- clk_disable_unprepare(data->clk);
+ imx_disable_unprepare_clks(dev);
return ret;
}
diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c
index 080b7be..58c8485 100644
--- a/drivers/usb/chipidea/debug.c
+++ b/drivers/usb/chipidea/debug.c
@@ -322,8 +322,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
return -EINVAL;
pm_runtime_get_sync(ci->dev);
+ disable_irq(ci->irq);
ci_role_stop(ci);
ret = ci_role_start(ci, role);
+ enable_irq(ci->irq);
pm_runtime_put_sync(ci->dev);
return ret ? ret : count;
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 8223fe7..391a122 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1751,6 +1751,22 @@ static int ci_udc_start(struct usb_gadget *gadget,
return retval;
}
+static void ci_udc_stop_for_otg_fsm(struct ci_hdrc *ci)
+{
+ if (!ci_otg_is_fsm_mode(ci))
+ return;
+
+ mutex_lock(&ci->fsm.lock);
+ if (ci->fsm.otg->state == OTG_STATE_A_PERIPHERAL) {
+ ci->fsm.a_bidl_adis_tmout = 1;
+ ci_hdrc_otg_fsm_start(ci);
+ } else if (ci->fsm.otg->state == OTG_STATE_B_PERIPHERAL) {
+ ci->fsm.protocol = PROTO_UNDEF;
+ ci->fsm.otg->state = OTG_STATE_UNDEFINED;
+ }
+ mutex_unlock(&ci->fsm.lock);
+}
+
/**
* ci_udc_stop: unregister a gadget driver
*/
@@ -1775,6 +1791,7 @@ static int ci_udc_stop(struct usb_gadget *gadget)
ci->driver = NULL;
spin_unlock_irqrestore(&ci->lock, flags);
+ ci_udc_stop_for_otg_fsm(ci);
return 0;
}
diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c
index fcea4eb..ab8b027 100644
--- a/drivers/usb/chipidea/usbmisc_imx.c
+++ b/drivers/usb/chipidea/usbmisc_imx.c
@@ -500,7 +500,11 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
{
struct resource *res;
struct imx_usbmisc *data;
- struct of_device_id *tmp_dev;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
+ if (!of_id)
+ return -ENODEV;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -513,9 +517,7 @@ static int usbmisc_imx_probe(struct platform_device *pdev)
if (IS_ERR(data->base))
return PTR_ERR(data->base);
- tmp_dev = (struct of_device_id *)
- of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
- data->ops = (const struct usbmisc_ops *)tmp_dev->data;
+ data->ops = (const struct usbmisc_ops *)of_id->data;
platform_set_drvdata(pdev, data);
return 0;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b30e742..26ca4f9 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1838,6 +1838,11 @@ static const struct usb_device_id acm_ids[] = {
},
#endif
+ /* Exclude Infineon Flash Loader utility */
+ { USB_DEVICE(0x058b, 0x0041),
+ .driver_info = IGNORE_DEVICE,
+ },
+
/* control interfaces without any protocol set */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
USB_CDC_PROTO_NONE) },
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 433bbc3..071964c 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -884,11 +884,11 @@ static int usblp_wwait(struct usblp *usblp, int nonblock)
add_wait_queue(&usblp->wwait, &waita);
for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
if (mutex_lock_interruptible(&usblp->mut)) {
rc = -EINTR;
break;
}
+ set_current_state(TASK_INTERRUPTIBLE);
rc = usblp_wtest(usblp, nonblock);
mutex_unlock(&usblp->mut);
if (rc <= 0)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index a99c89e..dd28010 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -77,8 +77,7 @@ config USB_OTG_BLACKLIST_HUB
config USB_OTG_FSM
tristate "USB 2.0 OTG FSM implementation"
- depends on USB
- select USB_OTG
+ depends on USB && USB_OTG
select USB_PHY
help
Implements OTG Finite State Machine as specified in On-The-Go
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 7caff02..5050760 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -115,7 +115,8 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
USB_SS_MULT(desc->bmAttributes) > 3) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
- "setting to 3\n", desc->bmAttributes + 1,
+ "setting to 3\n",
+ USB_SS_MULT(desc->bmAttributes),
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp.bmAttributes = 2;
}
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index 2a3bbdf..cffa0a0 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -661,32 +661,8 @@ static unsigned int usb_device_poll(struct file *file,
return 0;
}
-static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
-{
- loff_t ret;
-
- mutex_lock(&file_inode(file)->i_mutex);
-
- switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- case 2:
- default:
- ret = -EINVAL;
- }
-
- mutex_unlock(&file_inode(file)->i_mutex);
- return ret;
-}
-
const struct file_operations usbfs_devices_fops = {
- .llseek = usb_device_lseek,
+ .llseek = no_seek_end_llseek,
.read = usb_device_read,
.poll = usb_device_poll,
};
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 38ae877c..dbc3e14 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -157,30 +157,6 @@ static int connected(struct usb_dev_state *ps)
ps->dev->state != USB_STATE_NOTATTACHED);
}
-static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
-{
- loff_t ret;
-
- mutex_lock(&file_inode(file)->i_mutex);
-
- switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- break;
- case 2:
- default:
- ret = -EINVAL;
- }
-
- mutex_unlock(&file_inode(file)->i_mutex);
- return ret;
-}
-
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes,
loff_t *ppos)
{
@@ -2366,7 +2342,7 @@ static unsigned int usbdev_poll(struct file *file,
const struct file_operations usbdev_file_operations = {
.owner = THIS_MODULE,
- .llseek = usbdev_lseek,
+ .llseek = no_seek_end_llseek,
.read = usbdev_read,
.poll = usbdev_poll,
.unlocked_ioctl = usbdev_ioctl,
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index bdeadc1..ddbf32d 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -124,6 +124,10 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev)
int usb_device_supports_lpm(struct usb_device *udev)
{
+ /* Some devices have trouble with LPM */
+ if (udev->quirks & USB_QUIRK_NO_LPM)
+ return 0;
+
/* USB 2.1 (and greater) devices indicate LPM support through
* their USB 2.0 Extended Capabilities BOS descriptor.
*/
@@ -1031,10 +1035,20 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
unsigned delay;
/* Continue a partial initialization */
- if (type == HUB_INIT2)
- goto init2;
- if (type == HUB_INIT3)
+ if (type == HUB_INIT2 || type == HUB_INIT3) {
+ device_lock(hub->intfdev);
+
+ /* Was the hub disconnected while we were waiting? */
+ if (hub->disconnected) {
+ device_unlock(hub->intfdev);
+ kref_put(&hub->kref, hub_release);
+ return;
+ }
+ if (type == HUB_INIT2)
+ goto init2;
goto init3;
+ }
+ kref_get(&hub->kref);
/* The superspeed hub except for root hub has to use Hub Depth
* value as an offset into the route string to locate the bits
@@ -1232,6 +1246,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
queue_delayed_work(system_power_efficient_wq,
&hub->init_work,
msecs_to_jiffies(delay));
+ device_unlock(hub->intfdev);
return; /* Continues at init3: below */
} else {
msleep(delay);
@@ -1253,6 +1268,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
/* Allow autosuspend if it was suppressed */
if (type <= HUB_INIT3)
usb_autopm_put_interface_async(to_usb_interface(hub->intfdev));
+
+ if (type == HUB_INIT2 || type == HUB_INIT3)
+ device_unlock(hub->intfdev);
+
+ kref_put(&hub->kref, hub_release);
}
/* Implement the continuations for the delays above */
@@ -4512,6 +4532,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
+ usb_detect_quirks(udev);
+
if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
retval = usb_get_bos_descriptor(udev);
if (!retval) {
@@ -4710,7 +4732,6 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
if (status < 0)
goto loop;
- usb_detect_quirks(udev);
if (udev->quirks & USB_QUIRK_DELAY_INIT)
msleep(1000);
@@ -5326,9 +5347,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
if (udev->usb2_hw_lpm_enabled == 1)
usb_set_usb2_hardware_lpm(udev, 0);
- bos = udev->bos;
- udev->bos = NULL;
-
/* Disable LPM and LTM while we reset the device and reinstall the alt
* settings. Device-initiated LPM settings, and system exit latency
* settings are cleared when the device is reset, so we have to set
@@ -5337,15 +5355,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
ret = usb_unlocked_disable_lpm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__);
- goto re_enumerate;
+ goto re_enumerate_no_bos;
}
ret = usb_disable_ltm(udev);
if (ret) {
dev_err(&udev->dev, "%s Failed to disable LTM\n.",
__func__);
- goto re_enumerate;
+ goto re_enumerate_no_bos;
}
+ bos = udev->bos;
+ udev->bos = NULL;
+
for (i = 0; i < SET_CONFIG_TRIES; ++i) {
/* ep0 maxpacket size may change; let the HCD know about it.
@@ -5442,10 +5463,11 @@ done:
return 0;
re_enumerate:
- /* LPM state doesn't matter when we're about to destroy the device. */
- hub_port_logical_disconnect(parent_hub, port1);
usb_release_bos_descriptor(udev);
udev->bos = bos;
+re_enumerate_no_bos:
+ /* LPM state doesn't matter when we're about to destroy the device. */
+ hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index 2106183..5487fe308 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -206,7 +206,7 @@ static int link_peers(struct usb_port *left, struct usb_port *right)
else
method = "default";
- pr_warn("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
+ pr_debug("usb: failed to peer %s and %s by %s (%s:%s) (%s:%s)\n",
dev_name(&left->dev), dev_name(&right->dev), method,
dev_name(&left->dev),
lpeer ? dev_name(&lpeer->dev) : "none",
@@ -265,7 +265,7 @@ static void link_peers_report(struct usb_port *left, struct usb_port *right)
if (rc == 0) {
dev_dbg(&left->dev, "peered to %s\n", dev_name(&right->dev));
} else {
- dev_warn(&left->dev, "failed to peer to %s (%d)\n",
+ dev_dbg(&left->dev, "failed to peer to %s (%d)\n",
dev_name(&right->dev), rc);
pr_warn_once("usb: port power management may be unreliable\n");
usb_port_block_power_off = 1;
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index f5a3819..6dc810b 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -125,6 +125,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x04f3, 0x016f), .driver_info =
USB_QUIRK_DEVICE_QUALIFIER },
+ { USB_DEVICE(0x04f3, 0x21b8), .driver_info =
+ USB_QUIRK_DEVICE_QUALIFIER },
+
/* Roland SC-8820 */
{ USB_DEVICE(0x0582, 0x0007), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -199,6 +202,12 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+ /* Blackmagic Design Intensity Shuttle */
+ { USB_DEVICE(0x1edb, 0xbd3b), .driver_info = USB_QUIRK_NO_LPM },
+
+ /* Blackmagic Design UltraStudio SDI */
+ { USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },
+
{ } /* terminating entry must be last */
};
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index e79baf7..571c217 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -324,12 +324,13 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
*/
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
{
- if (hsotg->lx_state == DWC2_L2) {
+ if (hsotg->bus_suspended) {
hsotg->flags.b.port_suspend_change = 1;
usb_hcd_resume_root_hub(hsotg->priv);
- } else {
- hsotg->flags.b.port_l1_change = 1;
}
+
+ if (hsotg->lx_state == DWC2_L1)
+ hsotg->flags.b.port_l1_change = 1;
}
/**
@@ -1428,8 +1429,8 @@ static void dwc2_wakeup_detected(unsigned long data)
dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
dwc2_readl(hsotg->regs + HPRT0));
- hsotg->bus_suspended = 0;
dwc2_hcd_rem_wakeup(hsotg);
+ hsotg->bus_suspended = 0;
/* Change to L0 state */
hsotg->lx_state = DWC2_L0;
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 5859b0f..39c1cbf 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -108,7 +108,8 @@ static const struct dwc2_core_params params_rk3066 = {
.host_ls_low_power_phy_clk = -1,
.ts_dline = -1,
.reload_ctl = -1,
- .ahbcfg = 0x7, /* INCR16 */
+ .ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
+ GAHBCFG_HBSTLEN_SHIFT,
.uframe_sched = -1,
.external_id_pin_ctl = -1,
.hibernation = -1,
@@ -124,9 +125,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg)
if (ret)
return ret;
- ret = clk_prepare_enable(hsotg->clk);
- if (ret)
- return ret;
+ if (hsotg->clk) {
+ ret = clk_prepare_enable(hsotg->clk);
+ if (ret)
+ return ret;
+ }
if (hsotg->uphy)
ret = usb_phy_init(hsotg->uphy);
@@ -174,7 +177,8 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg)
if (ret)
return ret;
- clk_disable_unprepare(hsotg->clk);
+ if (hsotg->clk)
+ clk_disable_unprepare(hsotg->clk);
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
@@ -211,14 +215,41 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
*/
hsotg->phy = devm_phy_get(hsotg->dev, "usb2-phy");
if (IS_ERR(hsotg->phy)) {
- hsotg->phy = NULL;
+ ret = PTR_ERR(hsotg->phy);
+ switch (ret) {
+ case -ENODEV:
+ case -ENOSYS:
+ hsotg->phy = NULL;
+ break;
+ case -EPROBE_DEFER:
+ return ret;
+ default:
+ dev_err(hsotg->dev, "error getting phy %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!hsotg->phy) {
hsotg->uphy = devm_usb_get_phy(hsotg->dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(hsotg->uphy))
- hsotg->uphy = NULL;
- else
- hsotg->plat = dev_get_platdata(hsotg->dev);
+ if (IS_ERR(hsotg->uphy)) {
+ ret = PTR_ERR(hsotg->uphy);
+ switch (ret) {
+ case -ENODEV:
+ case -ENXIO:
+ hsotg->uphy = NULL;
+ break;
+ case -EPROBE_DEFER:
+ return ret;
+ default:
+ dev_err(hsotg->dev, "error getting usb phy %d\n",
+ ret);
+ return ret;
+ }
+ }
}
+ hsotg->plat = dev_get_platdata(hsotg->dev);
+
if (hsotg->phy) {
/*
* If using the generic PHY framework, check if the PHY bus
@@ -228,11 +259,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
hsotg->phyif = GUSBCFG_PHYIF8;
}
- if (!hsotg->phy && !hsotg->uphy && !hsotg->plat) {
- dev_err(hsotg->dev, "no platform data or transceiver defined\n");
- return -EPROBE_DEFER;
- }
-
/* Clock */
hsotg->clk = devm_clk_get(hsotg->dev, "otg");
if (IS_ERR(hsotg->clk)) {
@@ -341,20 +367,6 @@ static int dwc2_driver_probe(struct platform_device *dev)
if (retval)
return retval;
- irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- dev_err(&dev->dev, "missing IRQ resource\n");
- return irq;
- }
-
- dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
- irq);
- retval = devm_request_irq(hsotg->dev, irq,
- dwc2_handle_common_intr, IRQF_SHARED,
- dev_name(hsotg->dev), hsotg);
- if (retval)
- return retval;
-
res = platform_get_resource(dev, IORESOURCE_MEM, 0);
hsotg->regs = devm_ioremap_resource(&dev->dev, res);
if (IS_ERR(hsotg->regs))
@@ -389,6 +401,20 @@ static int dwc2_driver_probe(struct platform_device *dev)
dwc2_set_all_params(hsotg->core_params, -1);
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "missing IRQ resource\n");
+ return irq;
+ }
+
+ dev_dbg(hsotg->dev, "registering common handler for irq%d\n",
+ irq);
+ retval = devm_request_irq(hsotg->dev, irq,
+ dwc2_handle_common_intr, IRQF_SHARED,
+ dev_name(hsotg->dev), hsotg);
+ if (retval)
+ return retval;
+
retval = dwc2_lowlevel_hw_enable(hsotg);
if (retval)
return retval;
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 77a622c..009d830 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -34,6 +34,8 @@
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
+#define PCI_DEVICE_ID_INTEL_BXT 0x0aaa
+#define PCI_DEVICE_ID_INTEL_APL 0x5aaa
static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
static const struct acpi_gpio_params cs_gpios = { 1, 0, false };
@@ -210,6 +212,8 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 55ba447..a58376f 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1078,6 +1078,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* little bit faster.
*/
if (!usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+ !usb_endpoint_xfer_int(dep->endpoint.desc) &&
!(dep->flags & DWC3_EP_BUSY)) {
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
goto out;
@@ -2744,12 +2745,34 @@ int dwc3_gadget_init(struct dwc3 *dwc)
}
dwc->gadget.ops = &dwc3_gadget_ops;
- dwc->gadget.max_speed = USB_SPEED_SUPER;
dwc->gadget.speed = USB_SPEED_UNKNOWN;
dwc->gadget.sg_supported = true;
dwc->gadget.name = "dwc3-gadget";
/*
+ * FIXME We might be setting max_speed to <SUPER, however versions
+ * <2.20a of dwc3 have an issue with metastability (documented
+ * elsewhere in this driver) which tells us we can't set max speed to
+ * anything lower than SUPER.
+ *
+ * Because gadget.max_speed is only used by composite.c and function
+ * drivers (i.e. it won't go into dwc3's registers) we are allowing this
+ * to happen so we avoid sending SuperSpeed Capability descriptor
+ * together with our BOS descriptor as that could confuse host into
+ * thinking we can handle super speed.
+ *
+ * Note that, in fact, we won't even support GetBOS requests when speed
+ * is less than super speed because we don't have means, yet, to tell
+ * composite.c that we are USB 2.0 + LPM ECN.
+ */
+ if (dwc->revision < DWC3_REVISION_220A)
+ dwc3_trace(trace_dwc3_gadget,
+ "Changing max_speed on rev %08x\n",
+ dwc->revision);
+
+ dwc->gadget.max_speed = dwc->maximum_speed;
+
+ /*
* Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize
* on ep out.
*/
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 294eb74..163d305 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -64,6 +64,11 @@ struct gadget_info {
char qw_sign[OS_STRING_QW_SIGN_LEN];
};
+static inline struct gadget_info *to_gadget_info(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct gadget_info, group);
+}
+
struct config_usb_cfg {
struct config_group group;
struct config_group strings_group;
@@ -74,6 +79,12 @@ struct config_usb_cfg {
struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
};
+static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct config_usb_cfg,
+ group);
+}
+
struct gadget_strings {
struct usb_gadget_strings stringtab_dev;
struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
@@ -117,32 +128,25 @@ static int usb_string_copy(const char *s, char **s_copy)
return 0;
}
-CONFIGFS_ATTR_STRUCT(gadget_info);
-CONFIGFS_ATTR_STRUCT(config_usb_cfg);
-
-#define GI_DEVICE_DESC_ITEM_ATTR(name) \
- static struct gadget_info_attribute gadget_cdev_desc_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- gadget_dev_desc_##name##_show, \
- gadget_dev_desc_##name##_store)
-
#define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \
- static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \
char *page) \
{ \
- return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \
+ return sprintf(page, "0x%02x\n", \
+ to_gadget_info(item)->cdev.desc.__name); \
}
#define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \
- static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \
+static ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \
char *page) \
{ \
- return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \
+ return sprintf(page, "0x%04x\n", \
+ le16_to_cpup(&to_gadget_info(item)->cdev.desc.__name)); \
}
#define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \
- static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
u8 val; \
@@ -150,12 +154,12 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg);
ret = kstrtou8(page, 0, &val); \
if (ret) \
return ret; \
- gi->cdev.desc._name = val; \
+ to_gadget_info(item)->cdev.desc._name = val; \
return len; \
}
#define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \
- static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \
+static ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
u16 val; \
@@ -163,7 +167,7 @@ CONFIGFS_ATTR_STRUCT(config_usb_cfg);
ret = kstrtou16(page, 0, &val); \
if (ret) \
return ret; \
- gi->cdev.desc._name = cpu_to_le16p(&val); \
+ to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(&val); \
return len; \
}
@@ -193,7 +197,7 @@ static ssize_t is_valid_bcd(u16 bcd_val)
return 0;
}
-static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi,
+static ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item,
const char *page, size_t len)
{
u16 bcdDevice;
@@ -206,11 +210,11 @@ static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi,
if (ret)
return ret;
- gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
+ to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
return len;
}
-static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi,
+static ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item,
const char *page, size_t len)
{
u16 bcdUSB;
@@ -223,13 +227,13 @@ static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi,
if (ret)
return ret;
- gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
+ to_gadget_info(item)->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
return len;
}
-static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page)
+static ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
{
- return sprintf(page, "%s\n", gi->udc_name ?: "");
+ return sprintf(page, "%s\n", to_gadget_info(item)->udc_name ?: "");
}
static int unregister_gadget(struct gadget_info *gi)
@@ -247,9 +251,10 @@ static int unregister_gadget(struct gadget_info *gi)
return 0;
}
-static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi,
+static ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
const char *page, size_t len)
{
+ struct gadget_info *gi = to_gadget_info(item);
char *name;
int ret;
@@ -283,34 +288,29 @@ err:
return ret;
}
-GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass);
-GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass);
-GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol);
-GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0);
-GI_DEVICE_DESC_ITEM_ATTR(idVendor);
-GI_DEVICE_DESC_ITEM_ATTR(idProduct);
-GI_DEVICE_DESC_ITEM_ATTR(bcdDevice);
-GI_DEVICE_DESC_ITEM_ATTR(bcdUSB);
-GI_DEVICE_DESC_ITEM_ATTR(UDC);
+CONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass);
+CONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass);
+CONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol);
+CONFIGFS_ATTR(gadget_dev_desc_, bMaxPacketSize0);
+CONFIGFS_ATTR(gadget_dev_desc_, idVendor);
+CONFIGFS_ATTR(gadget_dev_desc_, idProduct);
+CONFIGFS_ATTR(gadget_dev_desc_, bcdDevice);
+CONFIGFS_ATTR(gadget_dev_desc_, bcdUSB);
+CONFIGFS_ATTR(gadget_dev_desc_, UDC);
static struct configfs_attribute *gadget_root_attrs[] = {
- &gadget_cdev_desc_bDeviceClass.attr,
- &gadget_cdev_desc_bDeviceSubClass.attr,
- &gadget_cdev_desc_bDeviceProtocol.attr,
- &gadget_cdev_desc_bMaxPacketSize0.attr,
- &gadget_cdev_desc_idVendor.attr,
- &gadget_cdev_desc_idProduct.attr,
- &gadget_cdev_desc_bcdDevice.attr,
- &gadget_cdev_desc_bcdUSB.attr,
- &gadget_cdev_desc_UDC.attr,
+ &gadget_dev_desc_attr_bDeviceClass,
+ &gadget_dev_desc_attr_bDeviceSubClass,
+ &gadget_dev_desc_attr_bDeviceProtocol,
+ &gadget_dev_desc_attr_bMaxPacketSize0,
+ &gadget_dev_desc_attr_idVendor,
+ &gadget_dev_desc_attr_idProduct,
+ &gadget_dev_desc_attr_bcdDevice,
+ &gadget_dev_desc_attr_bcdUSB,
+ &gadget_dev_desc_attr_UDC,
NULL,
};
-static inline struct gadget_info *to_gadget_info(struct config_item *item)
-{
- return container_of(to_config_group(item), struct gadget_info, group);
-}
-
static inline struct gadget_strings *to_gadget_strings(struct config_item *item)
{
return container_of(to_config_group(item), struct gadget_strings,
@@ -324,12 +324,6 @@ static inline struct gadget_config_name *to_gadget_config_name(
group);
}
-static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
-{
- return container_of(to_config_group(item), struct config_usb_cfg,
- group);
-}
-
static inline struct usb_function_instance *to_usb_function_instance(
struct config_item *item)
{
@@ -348,12 +342,8 @@ static void gadget_info_attr_release(struct config_item *item)
kfree(gi);
}
-CONFIGFS_ATTR_OPS(gadget_info);
-
static struct configfs_item_operations gadget_root_item_ops = {
.release = gadget_info_attr_release,
- .show_attribute = gadget_info_attr_show,
- .store_attribute = gadget_info_attr_store,
};
static void gadget_config_attr_release(struct config_item *item)
@@ -454,24 +444,20 @@ static int config_usb_cfg_unlink(
return 0;
}
-CONFIGFS_ATTR_OPS(config_usb_cfg);
-
static struct configfs_item_operations gadget_config_item_ops = {
.release = gadget_config_attr_release,
- .show_attribute = config_usb_cfg_attr_show,
- .store_attribute = config_usb_cfg_attr_store,
.allow_link = config_usb_cfg_link,
.drop_link = config_usb_cfg_unlink,
};
-static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg,
+static ssize_t gadget_config_desc_MaxPower_show(struct config_item *item,
char *page)
{
- return sprintf(page, "%u\n", cfg->c.MaxPower);
+ return sprintf(page, "%u\n", to_config_usb_cfg(item)->c.MaxPower);
}
-static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg,
+static ssize_t gadget_config_desc_MaxPower_store(struct config_item *item,
const char *page, size_t len)
{
u16 val;
@@ -481,17 +467,18 @@ static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg,
return ret;
if (DIV_ROUND_UP(val, 8) > 0xff)
return -ERANGE;
- cfg->c.MaxPower = val;
+ to_config_usb_cfg(item)->c.MaxPower = val;
return len;
}
-static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg,
+static ssize_t gadget_config_desc_bmAttributes_show(struct config_item *item,
char *page)
{
- return sprintf(page, "0x%02x\n", cfg->c.bmAttributes);
+ return sprintf(page, "0x%02x\n",
+ to_config_usb_cfg(item)->c.bmAttributes);
}
-static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg,
+static ssize_t gadget_config_desc_bmAttributes_store(struct config_item *item,
const char *page, size_t len)
{
u8 val;
@@ -504,22 +491,16 @@ static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg,
if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER |
USB_CONFIG_ATT_WAKEUP))
return -EINVAL;
- cfg->c.bmAttributes = val;
+ to_config_usb_cfg(item)->c.bmAttributes = val;
return len;
}
-#define CFG_CONFIG_DESC_ITEM_ATTR(name) \
- static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- gadget_config_desc_##name##_show, \
- gadget_config_desc_##name##_store)
-
-CFG_CONFIG_DESC_ITEM_ATTR(MaxPower);
-CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes);
+CONFIGFS_ATTR(gadget_config_desc_, MaxPower);
+CONFIGFS_ATTR(gadget_config_desc_, bmAttributes);
static struct configfs_attribute *gadget_config_attrs[] = {
- &gadget_usb_cfg_MaxPower.attr,
- &gadget_usb_cfg_bmAttributes.attr,
+ &gadget_config_desc_attr_MaxPower,
+ &gadget_config_desc_attr_bmAttributes,
NULL,
};
@@ -616,11 +597,10 @@ static struct config_item_type functions_type = {
.ct_owner = THIS_MODULE,
};
-CONFIGFS_ATTR_STRUCT(gadget_config_name);
GS_STRINGS_RW(gadget_config_name, configuration);
static struct configfs_attribute *gadget_config_name_langid_attrs[] = {
- &gadget_config_name_configuration.attr,
+ &gadget_config_name_attr_configuration,
NULL,
};
@@ -719,15 +699,14 @@ static struct config_item_type config_desc_type = {
.ct_owner = THIS_MODULE,
};
-CONFIGFS_ATTR_STRUCT(gadget_strings);
GS_STRINGS_RW(gadget_strings, manufacturer);
GS_STRINGS_RW(gadget_strings, product);
GS_STRINGS_RW(gadget_strings, serialnumber);
static struct configfs_attribute *gadget_strings_langid_attrs[] = {
- &gadget_strings_manufacturer.attr,
- &gadget_strings_product.attr,
- &gadget_strings_serialnumber.attr,
+ &gadget_strings_attr_manufacturer,
+ &gadget_strings_attr_product,
+ &gadget_strings_attr_serialnumber,
NULL,
};
@@ -751,27 +730,25 @@ static inline struct os_desc *to_os_desc(struct config_item *item)
return container_of(to_config_group(item), struct os_desc, group);
}
-CONFIGFS_ATTR_STRUCT(os_desc);
-CONFIGFS_ATTR_OPS(os_desc);
-
-static ssize_t os_desc_use_show(struct os_desc *os_desc, char *page)
+static inline struct gadget_info *os_desc_item_to_gadget_info(
+ struct config_item *item)
{
- struct gadget_info *gi;
-
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
+ return to_gadget_info(to_os_desc(item)->group.cg_item.ci_parent);
+}
- return sprintf(page, "%d", gi->use_os_desc);
+static ssize_t os_desc_use_show(struct config_item *item, char *page)
+{
+ return sprintf(page, "%d",
+ os_desc_item_to_gadget_info(item)->use_os_desc);
}
-static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page,
+static ssize_t os_desc_use_store(struct config_item *item, const char *page,
size_t len)
{
- struct gadget_info *gi;
+ struct gadget_info *gi = os_desc_item_to_gadget_info(item);
int ret;
bool use;
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
-
mutex_lock(&gi->lock);
ret = strtobool(page, &use);
if (!ret) {
@@ -783,29 +760,19 @@ static ssize_t os_desc_use_store(struct os_desc *os_desc, const char *page,
return ret;
}
-static struct os_desc_attribute os_desc_use =
- __CONFIGFS_ATTR(use, S_IRUGO | S_IWUSR,
- os_desc_use_show,
- os_desc_use_store);
-
-static ssize_t os_desc_b_vendor_code_show(struct os_desc *os_desc, char *page)
+static ssize_t os_desc_b_vendor_code_show(struct config_item *item, char *page)
{
- struct gadget_info *gi;
-
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
-
- return sprintf(page, "%d", gi->b_vendor_code);
+ return sprintf(page, "%d",
+ os_desc_item_to_gadget_info(item)->b_vendor_code);
}
-static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc,
+static ssize_t os_desc_b_vendor_code_store(struct config_item *item,
const char *page, size_t len)
{
- struct gadget_info *gi;
+ struct gadget_info *gi = os_desc_item_to_gadget_info(item);
int ret;
u8 b_vendor_code;
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
-
mutex_lock(&gi->lock);
ret = kstrtou8(page, 0, &b_vendor_code);
if (!ret) {
@@ -817,29 +784,20 @@ static ssize_t os_desc_b_vendor_code_store(struct os_desc *os_desc,
return ret;
}
-static struct os_desc_attribute os_desc_b_vendor_code =
- __CONFIGFS_ATTR(b_vendor_code, S_IRUGO | S_IWUSR,
- os_desc_b_vendor_code_show,
- os_desc_b_vendor_code_store);
-
-static ssize_t os_desc_qw_sign_show(struct os_desc *os_desc, char *page)
+static ssize_t os_desc_qw_sign_show(struct config_item *item, char *page)
{
- struct gadget_info *gi;
-
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
+ struct gadget_info *gi = os_desc_item_to_gadget_info(item);
memcpy(page, gi->qw_sign, OS_STRING_QW_SIGN_LEN);
-
return OS_STRING_QW_SIGN_LEN;
}
-static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page,
+static ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page,
size_t len)
{
- struct gadget_info *gi;
+ struct gadget_info *gi = os_desc_item_to_gadget_info(item);
int res, l;
- gi = to_gadget_info(os_desc->group.cg_item.ci_parent);
l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1);
if (page[l - 1] == '\n')
--l;
@@ -855,15 +813,14 @@ static ssize_t os_desc_qw_sign_store(struct os_desc *os_desc, const char *page,
return res;
}
-static struct os_desc_attribute os_desc_qw_sign =
- __CONFIGFS_ATTR(qw_sign, S_IRUGO | S_IWUSR,
- os_desc_qw_sign_show,
- os_desc_qw_sign_store);
+CONFIGFS_ATTR(os_desc_, use);
+CONFIGFS_ATTR(os_desc_, b_vendor_code);
+CONFIGFS_ATTR(os_desc_, qw_sign);
static struct configfs_attribute *os_desc_attrs[] = {
- &os_desc_use.attr,
- &os_desc_b_vendor_code.attr,
- &os_desc_qw_sign.attr,
+ &os_desc_attr_use,
+ &os_desc_attr_b_vendor_code,
+ &os_desc_attr_qw_sign,
NULL,
};
@@ -926,8 +883,6 @@ static int os_desc_unlink(struct config_item *os_desc_ci,
static struct configfs_item_operations os_desc_ops = {
.release = os_desc_attr_release,
- .show_attribute = os_desc_attr_show,
- .store_attribute = os_desc_attr_store,
.allow_link = os_desc_link,
.drop_link = os_desc_unlink,
};
@@ -938,28 +893,21 @@ static struct config_item_type os_desc_type = {
.ct_owner = THIS_MODULE,
};
-CONFIGFS_ATTR_STRUCT(usb_os_desc);
-CONFIGFS_ATTR_OPS(usb_os_desc);
-
-
static inline struct usb_os_desc_ext_prop
*to_usb_os_desc_ext_prop(struct config_item *item)
{
return container_of(item, struct usb_os_desc_ext_prop, item);
}
-CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop);
-CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop);
-
-static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop,
- char *page)
+static ssize_t ext_prop_type_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d", ext_prop->type);
+ return sprintf(page, "%d", to_usb_os_desc_ext_prop(item)->type);
}
-static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop,
+static ssize_t ext_prop_type_store(struct config_item *item,
const char *page, size_t len)
{
+ struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
u8 type;
int ret;
@@ -997,9 +945,9 @@ end:
return ret;
}
-static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop,
- char *page)
+static ssize_t ext_prop_data_show(struct config_item *item, char *page)
{
+ struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
int len = ext_prop->data_len;
if (ext_prop->type == USB_EXT_PROP_UNICODE ||
@@ -1011,9 +959,10 @@ static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop,
return len;
}
-static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop,
+static ssize_t ext_prop_data_store(struct config_item *item,
const char *page, size_t len)
{
+ struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
char *new_data;
size_t ret_len = len;
@@ -1044,17 +993,12 @@ static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop,
return ret_len;
}
-static struct usb_os_desc_ext_prop_attribute ext_prop_type =
- __CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR,
- ext_prop_type_show, ext_prop_type_store);
-
-static struct usb_os_desc_ext_prop_attribute ext_prop_data =
- __CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR,
- ext_prop_data_show, ext_prop_data_store);
+CONFIGFS_ATTR(ext_prop_, type);
+CONFIGFS_ATTR(ext_prop_, data);
static struct configfs_attribute *ext_prop_attrs[] = {
- &ext_prop_type.attr,
- &ext_prop_data.attr,
+ &ext_prop_attr_type,
+ &ext_prop_attr_data,
NULL,
};
@@ -1067,8 +1011,6 @@ static void usb_os_desc_ext_prop_release(struct config_item *item)
static struct configfs_item_operations ext_prop_ops = {
.release = usb_os_desc_ext_prop_release,
- .show_attribute = usb_os_desc_ext_prop_attr_show,
- .store_attribute = usb_os_desc_ext_prop_attr_store,
};
static struct config_item *ext_prop_make(
@@ -1137,21 +1079,17 @@ static struct configfs_group_operations interf_grp_ops = {
.drop_item = &ext_prop_drop,
};
-static struct configfs_item_operations interf_item_ops = {
- .show_attribute = usb_os_desc_attr_show,
- .store_attribute = usb_os_desc_attr_store,
-};
-
-static ssize_t interf_grp_compatible_id_show(struct usb_os_desc *desc,
+static ssize_t interf_grp_compatible_id_show(struct config_item *item,
char *page)
{
- memcpy(page, desc->ext_compat_id, 8);
+ memcpy(page, to_usb_os_desc(item)->ext_compat_id, 8);
return 8;
}
-static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
+static ssize_t interf_grp_compatible_id_store(struct config_item *item,
const char *page, size_t len)
{
+ struct usb_os_desc *desc = to_usb_os_desc(item);
int l;
l = min_t(int, 8, len);
@@ -1167,21 +1105,17 @@ static ssize_t interf_grp_compatible_id_store(struct usb_os_desc *desc,
return len;
}
-static struct usb_os_desc_attribute interf_grp_attr_compatible_id =
- __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR,
- interf_grp_compatible_id_show,
- interf_grp_compatible_id_store);
-
-static ssize_t interf_grp_sub_compatible_id_show(struct usb_os_desc *desc,
+static ssize_t interf_grp_sub_compatible_id_show(struct config_item *item,
char *page)
{
- memcpy(page, desc->ext_compat_id + 8, 8);
+ memcpy(page, to_usb_os_desc(item)->ext_compat_id + 8, 8);
return 8;
}
-static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
+static ssize_t interf_grp_sub_compatible_id_store(struct config_item *item,
const char *page, size_t len)
{
+ struct usb_os_desc *desc = to_usb_os_desc(item);
int l;
l = min_t(int, 8, len);
@@ -1197,14 +1131,12 @@ static ssize_t interf_grp_sub_compatible_id_store(struct usb_os_desc *desc,
return len;
}
-static struct usb_os_desc_attribute interf_grp_attr_sub_compatible_id =
- __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR,
- interf_grp_sub_compatible_id_show,
- interf_grp_sub_compatible_id_store);
+CONFIGFS_ATTR(interf_grp_, compatible_id);
+CONFIGFS_ATTR(interf_grp_, sub_compatible_id);
static struct configfs_attribute *interf_grp_attrs[] = {
- &interf_grp_attr_compatible_id.attr,
- &interf_grp_attr_sub_compatible_id.attr,
+ &interf_grp_attr_compatible_id,
+ &interf_grp_attr_sub_compatible_id,
NULL
};
@@ -1242,7 +1174,6 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
f_default_groups[0] = os_desc_group;
os_desc_group->default_groups = interface_groups;
- interface_type->ct_item_ops = &interf_item_ops;
interface_type->ct_group_ops = &interf_grp_ops;
interface_type->ct_attrs = interf_grp_attrs;
interface_type->ct_owner = owner;
diff --git a/drivers/usb/gadget/function/f_acm.c b/drivers/usb/gadget/function/f_acm.c
index 22e723d..2fa1e80 100644
--- a/drivers/usb/gadget/function/f_acm.c
+++ b/drivers/usb/gadget/function/f_acm.c
@@ -761,21 +761,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_serial_opts);
-static ssize_t f_acm_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct f_serial_opts *opts = to_f_serial_opts(item);
- struct f_serial_opts_attribute *f_serial_opts_attr =
- container_of(attr, struct f_serial_opts_attribute, attr);
- ssize_t ret = 0;
-
- if (f_serial_opts_attr->show)
- ret = f_serial_opts_attr->show(opts, page);
- return ret;
-}
-
static void acm_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
@@ -785,20 +770,17 @@ static void acm_attr_release(struct config_item *item)
static struct configfs_item_operations acm_item_ops = {
.release = acm_attr_release,
- .show_attribute = f_acm_attr_show,
};
-static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page)
+static ssize_t f_acm_port_num_show(struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", opts->port_num);
+ return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
}
-static struct f_serial_opts_attribute f_acm_port_num =
- __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show);
-
+CONFIGFS_ATTR_RO(f_acm_port_, num);
static struct configfs_attribute *acm_attrs[] = {
- &f_acm_port_num.attr,
+ &f_acm_port_attr_num,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c
index 4abca70..7ad60ee 100644
--- a/drivers/usb/gadget/function/f_ecm.c
+++ b/drivers/usb/gadget/function/f_ecm.c
@@ -838,10 +838,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ecm);
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ecm);
static struct configfs_attribute *ecm_attrs[] = {
- &f_ecm_opts_dev_addr.attr,
- &f_ecm_opts_host_addr.attr,
- &f_ecm_opts_qmult.attr,
- &f_ecm_opts_ifname.attr,
+ &ecm_opts_attr_dev_addr,
+ &ecm_opts_attr_host_addr,
+ &ecm_opts_attr_qmult,
+ &ecm_opts_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c
index 9a55757..cad35a5 100644
--- a/drivers/usb/gadget/function/f_eem.c
+++ b/drivers/usb/gadget/function/f_eem.c
@@ -545,10 +545,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(eem);
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(eem);
static struct configfs_attribute *eem_attrs[] = {
- &f_eem_opts_dev_addr.attr,
- &f_eem_opts_host_addr.attr,
- &f_eem_opts_qmult.attr,
- &f_eem_opts_ifname.attr,
+ &eem_opts_attr_dev_addr,
+ &eem_opts_attr_host_addr,
+ &eem_opts_attr_qmult,
+ &eem_opts_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index adc6d52..cf43e9e 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -423,7 +423,7 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
- return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
+ return unlikely(copy_to_user(buf, events, size)) ? -EFAULT : size;
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@@ -513,7 +513,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
/* unlocks spinlock */
ret = __ffs_ep0_queue_wait(ffs, data, len);
- if (likely(ret > 0) && unlikely(__copy_to_user(buf, data, len)))
+ if (likely(ret > 0) && unlikely(copy_to_user(buf, data, len)))
ret = -EFAULT;
goto done_mutex;
@@ -3493,7 +3493,7 @@ static char *ffs_prepare_buffer(const char __user *buf, size_t len)
if (unlikely(!data))
return ERR_PTR(-ENOMEM);
- if (unlikely(__copy_from_user(data, buf, len))) {
+ if (unlikely(copy_from_user(data, buf, len))) {
kfree(data);
return ERR_PTR(-EFAULT);
}
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 21fcf18..99285b4 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -705,9 +705,6 @@ static inline struct f_hid_opts *to_f_hid_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_hid_opts);
-CONFIGFS_ATTR_OPS(f_hid_opts);
-
static void hid_attr_release(struct config_item *item)
{
struct f_hid_opts *opts = to_f_hid_opts(item);
@@ -717,13 +714,12 @@ static void hid_attr_release(struct config_item *item)
static struct configfs_item_operations hidg_item_ops = {
.release = hid_attr_release,
- .show_attribute = f_hid_opts_attr_show,
- .store_attribute = f_hid_opts_attr_store,
};
#define F_HID_OPT(name, prec, limit) \
-static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\
+static ssize_t f_hid_opts_##name##_show(struct config_item *item, char *page)\
{ \
+ struct f_hid_opts *opts = to_f_hid_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -733,9 +729,10 @@ static ssize_t f_hid_opts_##name##_show(struct f_hid_opts *opts, char *page)\
return result; \
} \
\
-static ssize_t f_hid_opts_##name##_store(struct f_hid_opts *opts, \
+static ssize_t f_hid_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_hid_opts *opts = to_f_hid_opts(item); \
int ret; \
u##prec num; \
\
@@ -761,16 +758,15 @@ end: \
return ret; \
} \
\
-static struct f_hid_opts_attribute f_hid_opts_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_hid_opts_##name##_show,\
- f_hid_opts_##name##_store)
+CONFIGFS_ATTR(f_hid_opts_, name)
F_HID_OPT(subclass, 8, 255);
F_HID_OPT(protocol, 8, 255);
F_HID_OPT(report_length, 16, 65535);
-static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
+static ssize_t f_hid_opts_report_desc_show(struct config_item *item, char *page)
{
+ struct f_hid_opts *opts = to_f_hid_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -781,9 +777,10 @@ static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
return result;
}
-static ssize_t f_hid_opts_report_desc_store(struct f_hid_opts *opts,
+static ssize_t f_hid_opts_report_desc_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_hid_opts *opts = to_f_hid_opts(item);
int ret = -EBUSY;
char *d;
@@ -810,16 +807,13 @@ end:
return ret;
}
-static struct f_hid_opts_attribute f_hid_opts_report_desc =
- __CONFIGFS_ATTR(report_desc, S_IRUGO | S_IWUSR,
- f_hid_opts_report_desc_show,
- f_hid_opts_report_desc_store);
+CONFIGFS_ATTR(f_hid_opts_, report_desc);
static struct configfs_attribute *hid_attrs[] = {
- &f_hid_opts_subclass.attr,
- &f_hid_opts_protocol.attr,
- &f_hid_opts_report_length.attr,
- &f_hid_opts_report_desc.attr,
+ &f_hid_opts_attr_subclass,
+ &f_hid_opts_attr_protocol,
+ &f_hid_opts_attr_report_length,
+ &f_hid_opts_attr_report_desc,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_loopback.c b/drivers/usb/gadget/function/f_loopback.c
index 6b2102b..ddc3aad 100644
--- a/drivers/usb/gadget/function/f_loopback.c
+++ b/drivers/usb/gadget/function/f_loopback.c
@@ -329,7 +329,7 @@ static int alloc_requests(struct usb_composite_dev *cdev,
for (i = 0; i < loop->qlen && result == 0; i++) {
result = -ENOMEM;
- in_req = usb_ep_alloc_request(loop->in_ep, GFP_KERNEL);
+ in_req = usb_ep_alloc_request(loop->in_ep, GFP_ATOMIC);
if (!in_req)
goto fail;
@@ -465,9 +465,6 @@ static inline struct f_lb_opts *to_f_lb_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_lb_opts);
-CONFIGFS_ATTR_OPS(f_lb_opts);
-
static void lb_attr_release(struct config_item *item)
{
struct f_lb_opts *lb_opts = to_f_lb_opts(item);
@@ -477,12 +474,11 @@ static void lb_attr_release(struct config_item *item)
static struct configfs_item_operations lb_item_ops = {
.release = lb_attr_release,
- .show_attribute = f_lb_opts_attr_show,
- .store_attribute = f_lb_opts_attr_store,
};
-static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
+static ssize_t f_lb_opts_qlen_show(struct config_item *item, char *page)
{
+ struct f_lb_opts *opts = to_f_lb_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -492,9 +488,10 @@ static ssize_t f_lb_opts_qlen_show(struct f_lb_opts *opts, char *page)
return result;
}
-static ssize_t f_lb_opts_qlen_store(struct f_lb_opts *opts,
+static ssize_t f_lb_opts_qlen_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_lb_opts *opts = to_f_lb_opts(item);
int ret;
u32 num;
@@ -515,13 +512,11 @@ end:
return ret;
}
-static struct f_lb_opts_attribute f_lb_opts_qlen =
- __CONFIGFS_ATTR(qlen, S_IRUGO | S_IWUSR,
- f_lb_opts_qlen_show,
- f_lb_opts_qlen_store);
+CONFIGFS_ATTR(f_lb_opts_, qlen);
-static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
+static ssize_t f_lb_opts_bulk_buflen_show(struct config_item *item, char *page)
{
+ struct f_lb_opts *opts = to_f_lb_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -531,9 +526,10 @@ static ssize_t f_lb_opts_bulk_buflen_show(struct f_lb_opts *opts, char *page)
return result;
}
-static ssize_t f_lb_opts_bulk_buflen_store(struct f_lb_opts *opts,
+static ssize_t f_lb_opts_bulk_buflen_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_lb_opts *opts = to_f_lb_opts(item);
int ret;
u32 num;
@@ -554,14 +550,11 @@ end:
return ret;
}
-static struct f_lb_opts_attribute f_lb_opts_bulk_buflen =
- __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR,
- f_lb_opts_bulk_buflen_show,
- f_lb_opts_bulk_buflen_store);
+CONFIGFS_ATTR(f_lb_opts_, bulk_buflen);
static struct configfs_attribute *lb_attrs[] = {
- &f_lb_opts_qlen.attr,
- &f_lb_opts_bulk_buflen.attr,
+ &f_lb_opts_attr_qlen,
+ &f_lb_opts_attr_bulk_buflen,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c
index 5ec5338..223ccf8 100644
--- a/drivers/usb/gadget/function/f_mass_storage.c
+++ b/drivers/usb/gadget/function/f_mass_storage.c
@@ -3140,9 +3140,6 @@ static inline struct fsg_opts *to_fsg_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(fsg_lun_opts);
-CONFIGFS_ATTR_OPS(fsg_lun_opts);
-
static void fsg_lun_attr_release(struct config_item *item)
{
struct fsg_lun_opts *lun_opts;
@@ -3153,110 +3150,93 @@ static void fsg_lun_attr_release(struct config_item *item)
static struct configfs_item_operations fsg_lun_item_ops = {
.release = fsg_lun_attr_release,
- .show_attribute = fsg_lun_opts_attr_show,
- .store_attribute = fsg_lun_opts_attr_store,
};
-static ssize_t fsg_lun_opts_file_show(struct fsg_lun_opts *opts, char *page)
+static ssize_t fsg_lun_opts_file_show(struct config_item *item, char *page)
{
- struct fsg_opts *fsg_opts;
-
- fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
+ struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
+ struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
return fsg_show_file(opts->lun, &fsg_opts->common->filesem, page);
}
-static ssize_t fsg_lun_opts_file_store(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_file_store(struct config_item *item,
const char *page, size_t len)
{
- struct fsg_opts *fsg_opts;
-
- fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
+ struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
+ struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
return fsg_store_file(opts->lun, &fsg_opts->common->filesem, page, len);
}
-static struct fsg_lun_opts_attribute fsg_lun_opts_file =
- __CONFIGFS_ATTR(file, S_IRUGO | S_IWUSR, fsg_lun_opts_file_show,
- fsg_lun_opts_file_store);
+CONFIGFS_ATTR(fsg_lun_opts_, file);
-static ssize_t fsg_lun_opts_ro_show(struct fsg_lun_opts *opts, char *page)
+static ssize_t fsg_lun_opts_ro_show(struct config_item *item, char *page)
{
- return fsg_show_ro(opts->lun, page);
+ return fsg_show_ro(to_fsg_lun_opts(item)->lun, page);
}
-static ssize_t fsg_lun_opts_ro_store(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_ro_store(struct config_item *item,
const char *page, size_t len)
{
- struct fsg_opts *fsg_opts;
-
- fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
+ struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
+ struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
return fsg_store_ro(opts->lun, &fsg_opts->common->filesem, page, len);
}
-static struct fsg_lun_opts_attribute fsg_lun_opts_ro =
- __CONFIGFS_ATTR(ro, S_IRUGO | S_IWUSR, fsg_lun_opts_ro_show,
- fsg_lun_opts_ro_store);
+CONFIGFS_ATTR(fsg_lun_opts_, ro);
-static ssize_t fsg_lun_opts_removable_show(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_removable_show(struct config_item *item,
char *page)
{
- return fsg_show_removable(opts->lun, page);
+ return fsg_show_removable(to_fsg_lun_opts(item)->lun, page);
}
-static ssize_t fsg_lun_opts_removable_store(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_removable_store(struct config_item *item,
const char *page, size_t len)
{
- return fsg_store_removable(opts->lun, page, len);
+ return fsg_store_removable(to_fsg_lun_opts(item)->lun, page, len);
}
-static struct fsg_lun_opts_attribute fsg_lun_opts_removable =
- __CONFIGFS_ATTR(removable, S_IRUGO | S_IWUSR,
- fsg_lun_opts_removable_show,
- fsg_lun_opts_removable_store);
+CONFIGFS_ATTR(fsg_lun_opts_, removable);
-static ssize_t fsg_lun_opts_cdrom_show(struct fsg_lun_opts *opts, char *page)
+static ssize_t fsg_lun_opts_cdrom_show(struct config_item *item, char *page)
{
- return fsg_show_cdrom(opts->lun, page);
+ return fsg_show_cdrom(to_fsg_lun_opts(item)->lun, page);
}
-static ssize_t fsg_lun_opts_cdrom_store(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_cdrom_store(struct config_item *item,
const char *page, size_t len)
{
- struct fsg_opts *fsg_opts;
-
- fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
+ struct fsg_lun_opts *opts = to_fsg_lun_opts(item);
+ struct fsg_opts *fsg_opts = to_fsg_opts(opts->group.cg_item.ci_parent);
return fsg_store_cdrom(opts->lun, &fsg_opts->common->filesem, page,
len);
}
-static struct fsg_lun_opts_attribute fsg_lun_opts_cdrom =
- __CONFIGFS_ATTR(cdrom, S_IRUGO | S_IWUSR, fsg_lun_opts_cdrom_show,
- fsg_lun_opts_cdrom_store);
+CONFIGFS_ATTR(fsg_lun_opts_, cdrom);
-static ssize_t fsg_lun_opts_nofua_show(struct fsg_lun_opts *opts, char *page)
+static ssize_t fsg_lun_opts_nofua_show(struct config_item *item, char *page)
{
- return fsg_show_nofua(opts->lun, page);
+ return fsg_show_nofua(to_fsg_lun_opts(item)->lun, page);
}
-static ssize_t fsg_lun_opts_nofua_store(struct fsg_lun_opts *opts,
+static ssize_t fsg_lun_opts_nofua_store(struct config_item *item,
const char *page, size_t len)
{
- return fsg_store_nofua(opts->lun, page, len);
+ return fsg_store_nofua(to_fsg_lun_opts(item)->lun, page, len);
}
-static struct fsg_lun_opts_attribute fsg_lun_opts_nofua =
- __CONFIGFS_ATTR(nofua, S_IRUGO | S_IWUSR, fsg_lun_opts_nofua_show,
- fsg_lun_opts_nofua_store);
+CONFIGFS_ATTR(fsg_lun_opts_, nofua);
static struct configfs_attribute *fsg_lun_attrs[] = {
- &fsg_lun_opts_file.attr,
- &fsg_lun_opts_ro.attr,
- &fsg_lun_opts_removable.attr,
- &fsg_lun_opts_cdrom.attr,
- &fsg_lun_opts_nofua.attr,
+ &fsg_lun_opts_attr_file,
+ &fsg_lun_opts_attr_ro,
+ &fsg_lun_opts_attr_removable,
+ &fsg_lun_opts_attr_cdrom,
+ &fsg_lun_opts_attr_nofua,
NULL,
};
@@ -3348,9 +3328,6 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item)
config_item_put(item);
}
-CONFIGFS_ATTR_STRUCT(fsg_opts);
-CONFIGFS_ATTR_OPS(fsg_opts);
-
static void fsg_attr_release(struct config_item *item)
{
struct fsg_opts *opts = to_fsg_opts(item);
@@ -3360,12 +3337,11 @@ static void fsg_attr_release(struct config_item *item)
static struct configfs_item_operations fsg_item_ops = {
.release = fsg_attr_release,
- .show_attribute = fsg_opts_attr_show,
- .store_attribute = fsg_opts_attr_store,
};
-static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page)
+static ssize_t fsg_opts_stall_show(struct config_item *item, char *page)
{
+ struct fsg_opts *opts = to_fsg_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -3375,9 +3351,10 @@ static ssize_t fsg_opts_stall_show(struct fsg_opts *opts, char *page)
return result;
}
-static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page,
+static ssize_t fsg_opts_stall_store(struct config_item *item, const char *page,
size_t len)
{
+ struct fsg_opts *opts = to_fsg_opts(item);
int ret;
bool stall;
@@ -3399,13 +3376,12 @@ static ssize_t fsg_opts_stall_store(struct fsg_opts *opts, const char *page,
return ret;
}
-static struct fsg_opts_attribute fsg_opts_stall =
- __CONFIGFS_ATTR(stall, S_IRUGO | S_IWUSR, fsg_opts_stall_show,
- fsg_opts_stall_store);
+CONFIGFS_ATTR(fsg_opts_, stall);
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
-static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page)
+static ssize_t fsg_opts_num_buffers_show(struct config_item *item, char *page)
{
+ struct fsg_opts *opts = to_fsg_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -3415,9 +3391,10 @@ static ssize_t fsg_opts_num_buffers_show(struct fsg_opts *opts, char *page)
return result;
}
-static ssize_t fsg_opts_num_buffers_store(struct fsg_opts *opts,
+static ssize_t fsg_opts_num_buffers_store(struct config_item *item,
const char *page, size_t len)
{
+ struct fsg_opts *opts = to_fsg_opts(item);
int ret;
u8 num;
@@ -3442,17 +3419,13 @@ end:
return ret;
}
-static struct fsg_opts_attribute fsg_opts_num_buffers =
- __CONFIGFS_ATTR(num_buffers, S_IRUGO | S_IWUSR,
- fsg_opts_num_buffers_show,
- fsg_opts_num_buffers_store);
-
+CONFIGFS_ATTR(fsg_opts_, num_buffers);
#endif
static struct configfs_attribute *fsg_attrs[] = {
- &fsg_opts_stall.attr,
+ &fsg_opts_attr_stall,
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
- &fsg_opts_num_buffers.attr,
+ &fsg_opts_attr_num_buffers,
#endif
NULL,
};
diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c
index ce3c8a6..898a570 100644
--- a/drivers/usb/gadget/function/f_midi.c
+++ b/drivers/usb/gadget/function/f_midi.c
@@ -370,6 +370,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (err) {
ERROR(midi, "%s queue req: %d\n",
midi->out_ep->name, err);
+ free_ep_req(midi->out_ep, req);
}
}
@@ -545,7 +546,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
}
}
- if (req->length > 0) {
+ if (req->length > 0 && ep->enabled) {
int err;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
@@ -902,9 +903,6 @@ static inline struct f_midi_opts *to_f_midi_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_midi_opts);
-CONFIGFS_ATTR_OPS(f_midi_opts);
-
static void midi_attr_release(struct config_item *item)
{
struct f_midi_opts *opts = to_f_midi_opts(item);
@@ -914,13 +912,12 @@ static void midi_attr_release(struct config_item *item)
static struct configfs_item_operations midi_item_ops = {
.release = midi_attr_release,
- .show_attribute = f_midi_opts_attr_show,
- .store_attribute = f_midi_opts_attr_store,
};
#define F_MIDI_OPT(name, test_limit, limit) \
-static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \
+static ssize_t f_midi_opts_##name##_show(struct config_item *item, char *page) \
{ \
+ struct f_midi_opts *opts = to_f_midi_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -930,9 +927,10 @@ static ssize_t f_midi_opts_##name##_show(struct f_midi_opts *opts, char *page) \
return result; \
} \
\
-static ssize_t f_midi_opts_##name##_store(struct f_midi_opts *opts, \
+static ssize_t f_midi_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_midi_opts *opts = to_f_midi_opts(item); \
int ret; \
u32 num; \
\
@@ -958,9 +956,7 @@ end: \
return ret; \
} \
\
-static struct f_midi_opts_attribute f_midi_opts_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, f_midi_opts_##name##_show, \
- f_midi_opts_##name##_store)
+CONFIGFS_ATTR(f_midi_opts_, name);
F_MIDI_OPT(index, true, SNDRV_CARDS);
F_MIDI_OPT(buflen, false, 0);
@@ -968,8 +964,9 @@ F_MIDI_OPT(qlen, false, 0);
F_MIDI_OPT(in_ports, true, MAX_PORTS);
F_MIDI_OPT(out_ports, true, MAX_PORTS);
-static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page)
+static ssize_t f_midi_opts_id_show(struct config_item *item, char *page)
{
+ struct f_midi_opts *opts = to_f_midi_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -985,9 +982,10 @@ static ssize_t f_midi_opts_id_show(struct f_midi_opts *opts, char *page)
return result;
}
-static ssize_t f_midi_opts_id_store(struct f_midi_opts *opts,
+static ssize_t f_midi_opts_id_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_midi_opts *opts = to_f_midi_opts(item);
int ret;
char *c;
@@ -1012,17 +1010,15 @@ end:
return ret;
}
-static struct f_midi_opts_attribute f_midi_opts_id =
- __CONFIGFS_ATTR(id, S_IRUGO | S_IWUSR, f_midi_opts_id_show,
- f_midi_opts_id_store);
+CONFIGFS_ATTR(f_midi_opts_, id);
static struct configfs_attribute *midi_attrs[] = {
- &f_midi_opts_index.attr,
- &f_midi_opts_buflen.attr,
- &f_midi_opts_qlen.attr,
- &f_midi_opts_in_ports.attr,
- &f_midi_opts_out_ports.attr,
- &f_midi_opts_id.attr,
+ &f_midi_opts_attr_index,
+ &f_midi_opts_attr_buflen,
+ &f_midi_opts_attr_qlen,
+ &f_midi_opts_attr_in_ports,
+ &f_midi_opts_attr_out_ports,
+ &f_midi_opts_attr_id,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c
index b6f7ed7..7ad798a 100644
--- a/drivers/usb/gadget/function/f_ncm.c
+++ b/drivers/usb/gadget/function/f_ncm.c
@@ -1488,10 +1488,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(ncm);
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(ncm);
static struct configfs_attribute *ncm_attrs[] = {
- &f_ncm_opts_dev_addr.attr,
- &f_ncm_opts_host_addr.attr,
- &f_ncm_opts_qmult.attr,
- &f_ncm_opts_ifname.attr,
+ &ncm_opts_attr_dev_addr,
+ &ncm_opts_attr_host_addr,
+ &ncm_opts_attr_qmult,
+ &ncm_opts_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_obex.c b/drivers/usb/gadget/function/f_obex.c
index 1c3d30a..d6396e0 100644
--- a/drivers/usb/gadget/function/f_obex.c
+++ b/drivers/usb/gadget/function/f_obex.c
@@ -387,22 +387,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_serial_opts);
-static ssize_t f_obex_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct f_serial_opts *opts = to_f_serial_opts(item);
- struct f_serial_opts_attribute *f_serial_opts_attr =
- container_of(attr, struct f_serial_opts_attribute, attr);
- ssize_t ret = 0;
-
- if (f_serial_opts_attr->show)
- ret = f_serial_opts_attr->show(opts, page);
-
- return ret;
-}
-
static void obex_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
@@ -412,19 +396,17 @@ static void obex_attr_release(struct config_item *item)
static struct configfs_item_operations obex_item_ops = {
.release = obex_attr_release,
- .show_attribute = f_obex_attr_show,
};
-static ssize_t f_obex_port_num_show(struct f_serial_opts *opts, char *page)
+static ssize_t f_obex_port_num_show(struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", opts->port_num);
+ return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
}
-static struct f_serial_opts_attribute f_obex_port_num =
- __CONFIGFS_ATTR_RO(port_num, f_obex_port_num_show);
+CONFIGFS_ATTR_RO(f_obex_, port_num);
static struct configfs_attribute *acm_attrs[] = {
- &f_obex_port_num.attr,
+ &f_obex_attr_port_num,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_phonet.c b/drivers/usb/gadget/function/f_phonet.c
index 62a1987..157441d 100644
--- a/drivers/usb/gadget/function/f_phonet.c
+++ b/drivers/usb/gadget/function/f_phonet.c
@@ -583,21 +583,6 @@ static inline struct f_phonet_opts *to_f_phonet_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_phonet_opts);
-static ssize_t f_phonet_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct f_phonet_opts *opts = to_f_phonet_opts(item);
- struct f_phonet_opts_attribute *f_phonet_opts_attr =
- container_of(attr, struct f_phonet_opts_attribute, attr);
- ssize_t ret = 0;
-
- if (f_phonet_opts_attr->show)
- ret = f_phonet_opts_attr->show(opts, page);
- return ret;
-}
-
static void phonet_attr_release(struct config_item *item)
{
struct f_phonet_opts *opts = to_f_phonet_opts(item);
@@ -607,19 +592,17 @@ static void phonet_attr_release(struct config_item *item)
static struct configfs_item_operations phonet_item_ops = {
.release = phonet_attr_release,
- .show_attribute = f_phonet_attr_show,
};
-static ssize_t f_phonet_ifname_show(struct f_phonet_opts *opts, char *page)
+static ssize_t f_phonet_ifname_show(struct config_item *item, char *page)
{
- return gether_get_ifname(opts->net, page, PAGE_SIZE);
+ return gether_get_ifname(to_f_phonet_opts(item)->net, page, PAGE_SIZE);
}
-static struct f_phonet_opts_attribute f_phonet_ifname =
- __CONFIGFS_ATTR_RO(ifname, f_phonet_ifname_show);
+CONFIGFS_ATTR_RO(f_phonet_, ifname);
static struct configfs_attribute *phonet_attrs[] = {
- &f_phonet_ifname.attr,
+ &f_phonet_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c
index 7fb3209..0fbfb2b 100644
--- a/drivers/usb/gadget/function/f_printer.c
+++ b/drivers/usb/gadget/function/f_printer.c
@@ -1146,9 +1146,6 @@ static inline struct f_printer_opts
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_printer_opts);
-CONFIGFS_ATTR_OPS(f_printer_opts);
-
static void printer_attr_release(struct config_item *item)
{
struct f_printer_opts *opts = to_f_printer_opts(item);
@@ -1158,13 +1155,12 @@ static void printer_attr_release(struct config_item *item)
static struct configfs_item_operations printer_item_ops = {
.release = printer_attr_release,
- .show_attribute = f_printer_opts_attr_show,
- .store_attribute = f_printer_opts_attr_store,
};
-static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts,
+static ssize_t f_printer_opts_pnp_string_show(struct config_item *item,
char *page)
{
+ struct f_printer_opts *opts = to_f_printer_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1174,9 +1170,10 @@ static ssize_t f_printer_opts_pnp_string_show(struct f_printer_opts *opts,
return result;
}
-static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts,
+static ssize_t f_printer_opts_pnp_string_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_printer_opts *opts = to_f_printer_opts(item);
int result, l;
mutex_lock(&opts->lock);
@@ -1189,14 +1186,12 @@ static ssize_t f_printer_opts_pnp_string_store(struct f_printer_opts *opts,
return result;
}
-static struct f_printer_opts_attribute f_printer_opts_pnp_string =
- __CONFIGFS_ATTR(pnp_string, S_IRUGO | S_IWUSR,
- f_printer_opts_pnp_string_show,
- f_printer_opts_pnp_string_store);
+CONFIGFS_ATTR(f_printer_opts_, pnp_string);
-static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts,
+static ssize_t f_printer_opts_q_len_show(struct config_item *item,
char *page)
{
+ struct f_printer_opts *opts = to_f_printer_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1206,9 +1201,10 @@ static ssize_t f_printer_opts_q_len_show(struct f_printer_opts *opts,
return result;
}
-static ssize_t f_printer_opts_q_len_store(struct f_printer_opts *opts,
+static ssize_t f_printer_opts_q_len_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_printer_opts *opts = to_f_printer_opts(item);
int ret;
u16 num;
@@ -1229,13 +1225,11 @@ end:
return ret;
}
-static struct f_printer_opts_attribute f_printer_opts_q_len =
- __CONFIGFS_ATTR(q_len, S_IRUGO | S_IWUSR, f_printer_opts_q_len_show,
- f_printer_opts_q_len_store);
+CONFIGFS_ATTR(f_printer_opts_, q_len);
static struct configfs_attribute *printer_attrs[] = {
- &f_printer_opts_pnp_string.attr,
- &f_printer_opts_q_len.attr,
+ &f_printer_opts_attr_pnp_string,
+ &f_printer_opts_attr_q_len,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c
index fd301ed..e587767 100644
--- a/drivers/usb/gadget/function/f_rndis.c
+++ b/drivers/usb/gadget/function/f_rndis.c
@@ -864,10 +864,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis);
static struct configfs_attribute *rndis_attrs[] = {
- &f_rndis_opts_dev_addr.attr,
- &f_rndis_opts_host_addr.attr,
- &f_rndis_opts_qmult.attr,
- &f_rndis_opts_ifname.attr,
+ &rndis_opts_attr_dev_addr,
+ &rndis_opts_attr_host_addr,
+ &rndis_opts_attr_qmult,
+ &rndis_opts_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_serial.c b/drivers/usb/gadget/function/f_serial.c
index ba705e0..6bb44d61 100644
--- a/drivers/usb/gadget/function/f_serial.c
+++ b/drivers/usb/gadget/function/f_serial.c
@@ -258,22 +258,6 @@ static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_serial_opts);
-static ssize_t f_serial_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct f_serial_opts *opts = to_f_serial_opts(item);
- struct f_serial_opts_attribute *f_serial_opts_attr =
- container_of(attr, struct f_serial_opts_attribute, attr);
- ssize_t ret = 0;
-
- if (f_serial_opts_attr->show)
- ret = f_serial_opts_attr->show(opts, page);
-
- return ret;
-}
-
static void serial_attr_release(struct config_item *item)
{
struct f_serial_opts *opts = to_f_serial_opts(item);
@@ -283,19 +267,17 @@ static void serial_attr_release(struct config_item *item)
static struct configfs_item_operations serial_item_ops = {
.release = serial_attr_release,
- .show_attribute = f_serial_attr_show,
};
-static ssize_t f_serial_port_num_show(struct f_serial_opts *opts, char *page)
+static ssize_t f_serial_port_num_show(struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", opts->port_num);
+ return sprintf(page, "%u\n", to_f_serial_opts(item)->port_num);
}
-static struct f_serial_opts_attribute f_serial_port_num =
- __CONFIGFS_ATTR_RO(port_num, f_serial_port_num_show);
+CONFIGFS_ATTR_RO(f_serial_, port_num);
static struct configfs_attribute *acm_attrs[] = {
- &f_serial_port_num.attr,
+ &f_serial_attr_port_num,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index d7646d3..9f3ced6 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -889,9 +889,6 @@ static inline struct f_ss_opts *to_f_ss_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_ss_opts);
-CONFIGFS_ATTR_OPS(f_ss_opts);
-
static void ss_attr_release(struct config_item *item)
{
struct f_ss_opts *ss_opts = to_f_ss_opts(item);
@@ -901,12 +898,11 @@ static void ss_attr_release(struct config_item *item)
static struct configfs_item_operations ss_item_ops = {
.release = ss_attr_release,
- .show_attribute = f_ss_opts_attr_show,
- .store_attribute = f_ss_opts_attr_store,
};
-static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_pattern_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -916,9 +912,10 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_pattern_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_pattern_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u8 num;
@@ -944,13 +941,11 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_pattern =
- __CONFIGFS_ATTR(pattern, S_IRUGO | S_IWUSR,
- f_ss_opts_pattern_show,
- f_ss_opts_pattern_store);
+CONFIGFS_ATTR(f_ss_opts_, pattern);
-static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_isoc_interval_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -960,9 +955,10 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_isoc_interval_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_isoc_interval_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u8 num;
@@ -988,13 +984,11 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_isoc_interval =
- __CONFIGFS_ATTR(isoc_interval, S_IRUGO | S_IWUSR,
- f_ss_opts_isoc_interval_show,
- f_ss_opts_isoc_interval_store);
+CONFIGFS_ATTR(f_ss_opts_, isoc_interval);
-static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_isoc_maxpacket_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1004,9 +998,10 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_isoc_maxpacket_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_isoc_maxpacket_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u16 num;
@@ -1032,13 +1027,11 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_isoc_maxpacket =
- __CONFIGFS_ATTR(isoc_maxpacket, S_IRUGO | S_IWUSR,
- f_ss_opts_isoc_maxpacket_show,
- f_ss_opts_isoc_maxpacket_store);
+CONFIGFS_ATTR(f_ss_opts_, isoc_maxpacket);
-static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_isoc_mult_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1048,9 +1041,10 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_isoc_mult_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_isoc_mult_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u8 num;
@@ -1076,13 +1070,11 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_isoc_mult =
- __CONFIGFS_ATTR(isoc_mult, S_IRUGO | S_IWUSR,
- f_ss_opts_isoc_mult_show,
- f_ss_opts_isoc_mult_store);
+CONFIGFS_ATTR(f_ss_opts_, isoc_mult);
-static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_isoc_maxburst_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1092,9 +1084,10 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_isoc_maxburst_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_isoc_maxburst_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u8 num;
@@ -1120,13 +1113,11 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_isoc_maxburst =
- __CONFIGFS_ATTR(isoc_maxburst, S_IRUGO | S_IWUSR,
- f_ss_opts_isoc_maxburst_show,
- f_ss_opts_isoc_maxburst_store);
+CONFIGFS_ATTR(f_ss_opts_, isoc_maxburst);
-static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
+static ssize_t f_ss_opts_bulk_buflen_show(struct config_item *item, char *page)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int result;
mutex_lock(&opts->lock);
@@ -1136,9 +1127,10 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
return result;
}
-static ssize_t f_ss_opts_bulk_buflen_store(struct f_ss_opts *opts,
+static ssize_t f_ss_opts_bulk_buflen_store(struct config_item *item,
const char *page, size_t len)
{
+ struct f_ss_opts *opts = to_f_ss_opts(item);
int ret;
u32 num;
@@ -1159,18 +1151,15 @@ end:
return ret;
}
-static struct f_ss_opts_attribute f_ss_opts_bulk_buflen =
- __CONFIGFS_ATTR(buflen, S_IRUGO | S_IWUSR,
- f_ss_opts_bulk_buflen_show,
- f_ss_opts_bulk_buflen_store);
+CONFIGFS_ATTR(f_ss_opts_, bulk_buflen);
static struct configfs_attribute *ss_attrs[] = {
- &f_ss_opts_pattern.attr,
- &f_ss_opts_isoc_interval.attr,
- &f_ss_opts_isoc_maxpacket.attr,
- &f_ss_opts_isoc_mult.attr,
- &f_ss_opts_isoc_maxburst.attr,
- &f_ss_opts_bulk_buflen.attr,
+ &f_ss_opts_attr_pattern,
+ &f_ss_opts_attr_isoc_interval,
+ &f_ss_opts_attr_isoc_maxpacket,
+ &f_ss_opts_attr_isoc_mult,
+ &f_ss_opts_attr_isoc_maxburst,
+ &f_ss_opts_attr_bulk_buflen,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c
index 2e66e62..829c78d 100644
--- a/drivers/usb/gadget/function/f_subset.c
+++ b/drivers/usb/gadget/function/f_subset.c
@@ -405,10 +405,10 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(gether);
USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(gether);
static struct configfs_attribute *gether_attrs[] = {
- &f_gether_opts_dev_addr.attr,
- &f_gether_opts_host_addr.attr,
- &f_gether_opts_qmult.attr,
- &f_gether_opts_ifname.attr,
+ &gether_opts_attr_dev_addr,
+ &gether_opts_attr_host_addr,
+ &gether_opts_attr_qmult,
+ &gether_opts_attr_ifname,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index 8ee7019..6a2346b 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -769,9 +769,6 @@ static inline struct f_uac1_opts *to_f_uac1_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_uac1_opts);
-CONFIGFS_ATTR_OPS(f_uac1_opts);
-
static void f_uac1_attr_release(struct config_item *item)
{
struct f_uac1_opts *opts = to_f_uac1_opts(item);
@@ -781,14 +778,13 @@ static void f_uac1_attr_release(struct config_item *item)
static struct configfs_item_operations f_uac1_item_ops = {
.release = f_uac1_attr_release,
- .show_attribute = f_uac1_opts_attr_show,
- .store_attribute = f_uac1_opts_attr_store,
};
#define UAC1_INT_ATTRIBUTE(name) \
-static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \
+static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \
char *page) \
{ \
+ struct f_uac1_opts *opts = to_f_uac1_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -798,9 +794,10 @@ static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \
return result; \
} \
\
-static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \
+static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_uac1_opts *opts = to_f_uac1_opts(item); \
int ret; \
u32 num; \
\
@@ -822,19 +819,17 @@ end: \
return ret; \
} \
\
-static struct f_uac1_opts_attribute f_uac1_opts_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- f_uac1_opts_##name##_show, \
- f_uac1_opts_##name##_store)
+CONFIGFS_ATTR(f_uac1_opts_, name)
UAC1_INT_ATTRIBUTE(req_buf_size);
UAC1_INT_ATTRIBUTE(req_count);
UAC1_INT_ATTRIBUTE(audio_buf_size);
#define UAC1_STR_ATTRIBUTE(name) \
-static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \
+static ssize_t f_uac1_opts_##name##_show(struct config_item *item, \
char *page) \
{ \
+ struct f_uac1_opts *opts = to_f_uac1_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -844,9 +839,10 @@ static ssize_t f_uac1_opts_##name##_show(struct f_uac1_opts *opts, \
return result; \
} \
\
-static ssize_t f_uac1_opts_##name##_store(struct f_uac1_opts *opts, \
+static ssize_t f_uac1_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_uac1_opts *opts = to_f_uac1_opts(item); \
int ret = -EBUSY; \
char *tmp; \
\
@@ -870,22 +866,19 @@ end: \
return ret; \
} \
\
-static struct f_uac1_opts_attribute f_uac1_opts_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- f_uac1_opts_##name##_show, \
- f_uac1_opts_##name##_store)
+CONFIGFS_ATTR(f_uac1_opts_, name)
UAC1_STR_ATTRIBUTE(fn_play);
UAC1_STR_ATTRIBUTE(fn_cap);
UAC1_STR_ATTRIBUTE(fn_cntl);
static struct configfs_attribute *f_uac1_attrs[] = {
- &f_uac1_opts_req_buf_size.attr,
- &f_uac1_opts_req_count.attr,
- &f_uac1_opts_audio_buf_size.attr,
- &f_uac1_opts_fn_play.attr,
- &f_uac1_opts_fn_cap.attr,
- &f_uac1_opts_fn_cntl.attr,
+ &f_uac1_opts_attr_req_buf_size,
+ &f_uac1_opts_attr_req_count,
+ &f_uac1_opts_attr_audio_buf_size,
+ &f_uac1_opts_attr_fn_play,
+ &f_uac1_opts_attr_fn_cap,
+ &f_uac1_opts_attr_fn_cntl,
NULL,
};
diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c
index 63336e2..044ca79 100644
--- a/drivers/usb/gadget/function/f_uac2.c
+++ b/drivers/usb/gadget/function/f_uac2.c
@@ -1439,9 +1439,6 @@ static inline struct f_uac2_opts *to_f_uac2_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_uac2_opts);
-CONFIGFS_ATTR_OPS(f_uac2_opts);
-
static void f_uac2_attr_release(struct config_item *item)
{
struct f_uac2_opts *opts = to_f_uac2_opts(item);
@@ -1451,14 +1448,13 @@ static void f_uac2_attr_release(struct config_item *item)
static struct configfs_item_operations f_uac2_item_ops = {
.release = f_uac2_attr_release,
- .show_attribute = f_uac2_opts_attr_show,
- .store_attribute = f_uac2_opts_attr_store,
};
#define UAC2_ATTRIBUTE(name) \
-static ssize_t f_uac2_opts_##name##_show(struct f_uac2_opts *opts, \
+static ssize_t f_uac2_opts_##name##_show(struct config_item *item, \
char *page) \
{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -1468,9 +1464,10 @@ static ssize_t f_uac2_opts_##name##_show(struct f_uac2_opts *opts, \
return result; \
} \
\
-static ssize_t f_uac2_opts_##name##_store(struct f_uac2_opts *opts, \
+static ssize_t f_uac2_opts_##name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_uac2_opts *opts = to_f_uac2_opts(item); \
int ret; \
u32 num; \
\
@@ -1492,10 +1489,7 @@ end: \
return ret; \
} \
\
-static struct f_uac2_opts_attribute f_uac2_opts_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- f_uac2_opts_##name##_show, \
- f_uac2_opts_##name##_store)
+CONFIGFS_ATTR(f_uac2_opts_, name)
UAC2_ATTRIBUTE(p_chmask);
UAC2_ATTRIBUTE(p_srate);
@@ -1505,12 +1499,12 @@ UAC2_ATTRIBUTE(c_srate);
UAC2_ATTRIBUTE(c_ssize);
static struct configfs_attribute *f_uac2_attrs[] = {
- &f_uac2_opts_p_chmask.attr,
- &f_uac2_opts_p_srate.attr,
- &f_uac2_opts_p_ssize.attr,
- &f_uac2_opts_c_chmask.attr,
- &f_uac2_opts_c_srate.attr,
- &f_uac2_opts_c_ssize.attr,
+ &f_uac2_opts_attr_p_chmask,
+ &f_uac2_opts_attr_p_srate,
+ &f_uac2_opts_attr_p_ssize,
+ &f_uac2_opts_attr_c_chmask,
+ &f_uac2_opts_attr_c_srate,
+ &f_uac2_opts_attr_c_ssize,
NULL,
};
diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h
index bcbd301..4f47289 100644
--- a/drivers/usb/gadget/function/u_ether_configfs.h
+++ b/drivers/usb/gadget/function/u_ether_configfs.h
@@ -17,9 +17,6 @@
#define __U_ETHER_CONFIGFS_H
#define USB_ETHERNET_CONFIGFS_ITEM(_f_) \
- CONFIGFS_ATTR_STRUCT(f_##_f_##_opts); \
- CONFIGFS_ATTR_OPS(f_##_f_##_opts); \
- \
static void _f_##_attr_release(struct config_item *item) \
{ \
struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
@@ -29,14 +26,13 @@
\
static struct configfs_item_operations _f_##_item_ops = { \
.release = _f_##_attr_release, \
- .show_attribute = f_##_f_##_opts_attr_show, \
- .store_attribute = f_##_f_##_opts_attr_store, \
}
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_DEV_ADDR(_f_) \
- static ssize_t _f_##_opts_dev_addr_show(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_dev_addr_show(struct config_item *item, \
char *page) \
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -46,9 +42,10 @@
return result; \
} \
\
- static ssize_t _f_##_opts_dev_addr_store(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_dev_addr_store(struct config_item *item, \
const char *page, size_t len)\
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
mutex_lock(&opts->lock); \
@@ -64,15 +61,13 @@
return ret; \
} \
\
- static struct f_##_f_##_opts_attribute f_##_f_##_opts_dev_addr = \
- __CONFIGFS_ATTR(dev_addr, S_IRUGO | S_IWUSR, \
- _f_##_opts_dev_addr_show, \
- _f_##_opts_dev_addr_store)
+ CONFIGFS_ATTR(_f_##_opts_, dev_addr)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_HOST_ADDR(_f_) \
- static ssize_t _f_##_opts_host_addr_show(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_host_addr_show(struct config_item *item, \
char *page) \
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -82,9 +77,10 @@
return result; \
} \
\
- static ssize_t _f_##_opts_host_addr_store(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_host_addr_store(struct config_item *item, \
const char *page, size_t len)\
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
mutex_lock(&opts->lock); \
@@ -100,15 +96,13 @@
return ret; \
} \
\
- static struct f_##_f_##_opts_attribute f_##_f_##_opts_host_addr = \
- __CONFIGFS_ATTR(host_addr, S_IRUGO | S_IWUSR, \
- _f_##_opts_host_addr_show, \
- _f_##_opts_host_addr_store)
+ CONFIGFS_ATTR(_f_##_opts_, host_addr)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(_f_) \
- static ssize_t _f_##_opts_qmult_show(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_qmult_show(struct config_item *item, \
char *page) \
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
unsigned qmult; \
\
mutex_lock(&opts->lock); \
@@ -117,9 +111,10 @@
return sprintf(page, "%d", qmult); \
} \
\
- static ssize_t _f_##_opts_qmult_store(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_qmult_store(struct config_item *item, \
const char *page, size_t len)\
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
u8 val; \
int ret; \
\
@@ -140,15 +135,13 @@ out: \
return ret; \
} \
\
- static struct f_##_f_##_opts_attribute f_##_f_##_opts_qmult = \
- __CONFIGFS_ATTR(qmult, S_IRUGO | S_IWUSR, \
- _f_##_opts_qmult_show, \
- _f_##_opts_qmult_store)
+ CONFIGFS_ATTR(_f_##_opts_, qmult)
#define USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(_f_) \
- static ssize_t _f_##_opts_ifname_show(struct f_##_f_##_opts *opts, \
+ static ssize_t _f_##_opts_ifname_show(struct config_item *item, \
char *page) \
{ \
+ struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item); \
int ret; \
\
mutex_lock(&opts->lock); \
@@ -158,7 +151,6 @@ out: \
return ret; \
} \
\
- static struct f_##_f_##_opts_attribute f_##_f_##_opts_ifname = \
- __CONFIGFS_ATTR_RO(ifname, _f_##_opts_ifname_show)
+ CONFIGFS_ATTR_RO(_f_##_opts_, ifname)
#endif /* __U_ETHER_CONFIGFS_H */
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
index 3c0467b..ad8c9b0 100644
--- a/drivers/usb/gadget/function/uvc_configfs.c
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -17,19 +17,21 @@
#define UVCG_STREAMING_CONTROL_SIZE 1
-#define CONFIGFS_ATTR_OPS_RO(_item) \
-static ssize_t _item##_attr_show(struct config_item *item, \
- struct configfs_attribute *attr, \
- char *page) \
-{ \
- struct _item *_item = to_##_item(item); \
- struct _item##_attribute *_item##_attr = \
- container_of(attr, struct _item##_attribute, attr); \
- ssize_t ret = 0; \
- \
- if (_item##_attr->show) \
- ret = _item##_attr->show(_item, page); \
- return ret; \
+#define UVC_ATTR(prefix, cname, aname) \
+static struct configfs_attribute prefix##attr_##cname = { \
+ .ca_name = __stringify(aname), \
+ .ca_mode = S_IRUGO | S_IWUGO, \
+ .ca_owner = THIS_MODULE, \
+ .show = prefix##cname##_show, \
+ .store = prefix##cname##_store, \
+}
+
+#define UVC_ATTR_RO(prefix, cname, aname) \
+static struct configfs_attribute prefix##attr_##cname = { \
+ .ca_name = __stringify(aname), \
+ .ca_mode = S_IRUGO, \
+ .ca_owner = THIS_MODULE, \
+ .show = prefix##cname##_show, \
}
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
@@ -48,18 +50,11 @@ static struct uvcg_control_header *to_uvcg_control_header(struct config_item *it
return container_of(item, struct uvcg_control_header, item);
}
-CONFIGFS_ATTR_STRUCT(uvcg_control_header);
-CONFIGFS_ATTR_OPS(uvcg_control_header);
-
-static struct configfs_item_operations uvcg_control_header_item_ops = {
- .show_attribute = uvcg_control_header_attr_show,
- .store_attribute = uvcg_control_header_attr_store,
-};
-
#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
static ssize_t uvcg_control_header_##cname##_show( \
- struct uvcg_control_header *ch, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_control_header *ch = to_uvcg_control_header(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
@@ -79,9 +74,10 @@ static ssize_t uvcg_control_header_##cname##_show( \
} \
\
static ssize_t \
-uvcg_control_header_##cname##_store(struct uvcg_control_header *ch, \
+uvcg_control_header_##cname##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct uvcg_control_header *ch = to_uvcg_control_header(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
@@ -115,11 +111,7 @@ end: \
return ret; \
} \
\
-static struct uvcg_control_header_attribute \
- uvcg_control_header_##cname = \
- __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
- uvcg_control_header_##cname##_show, \
- uvcg_control_header_##cname##_store)
+UVC_ATTR(uvcg_control_header_, cname, aname)
UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
0xffff);
@@ -130,13 +122,12 @@ UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
#undef UVCG_CTRL_HDR_ATTR
static struct configfs_attribute *uvcg_control_header_attrs[] = {
- &uvcg_control_header_bcd_uvc.attr,
- &uvcg_control_header_dw_clock_frequency.attr,
+ &uvcg_control_header_attr_bcd_uvc,
+ &uvcg_control_header_attr_dw_clock_frequency,
NULL,
};
static struct config_item_type uvcg_control_header_type = {
- .ct_item_ops = &uvcg_control_header_item_ops,
.ct_attrs = uvcg_control_header_attrs,
.ct_owner = THIS_MODULE,
};
@@ -196,17 +187,11 @@ static inline struct uvcg_default_processing
struct uvcg_default_processing, group);
}
-CONFIGFS_ATTR_STRUCT(uvcg_default_processing);
-CONFIGFS_ATTR_OPS_RO(uvcg_default_processing);
-
-static struct configfs_item_operations uvcg_default_processing_item_ops = {
- .show_attribute = uvcg_default_processing_attr_show,
-};
-
#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \
static ssize_t uvcg_default_processing_##cname##_show( \
- struct uvcg_default_processing *dp, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_default_processing *dp = to_uvcg_default_processing(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \
@@ -227,9 +212,7 @@ static ssize_t uvcg_default_processing_##cname##_show( \
return result; \
} \
\
-static struct uvcg_default_processing_attribute \
- uvcg_default_processing_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_default_processing_##cname##_show)
+UVC_ATTR_RO(uvcg_default_processing_, cname, aname)
#define identity_conv(x) (x)
@@ -243,8 +226,9 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
#undef UVCG_DEFAULT_PROCESSING_ATTR
static ssize_t uvcg_default_processing_bm_controls_show(
- struct uvcg_default_processing *dp, char *page)
+ struct config_item *item, char *page)
{
+ struct uvcg_default_processing *dp = to_uvcg_default_processing(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
@@ -270,22 +254,18 @@ static ssize_t uvcg_default_processing_bm_controls_show(
return result;
}
-static struct uvcg_default_processing_attribute
- uvcg_default_processing_bm_controls =
- __CONFIGFS_ATTR_RO(bmControls,
- uvcg_default_processing_bm_controls_show);
+UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_processing_attrs[] = {
- &uvcg_default_processing_b_unit_id.attr,
- &uvcg_default_processing_b_source_id.attr,
- &uvcg_default_processing_w_max_multiplier.attr,
- &uvcg_default_processing_bm_controls.attr,
- &uvcg_default_processing_i_processing.attr,
+ &uvcg_default_processing_attr_b_unit_id,
+ &uvcg_default_processing_attr_b_source_id,
+ &uvcg_default_processing_attr_w_max_multiplier,
+ &uvcg_default_processing_attr_bm_controls,
+ &uvcg_default_processing_attr_i_processing,
NULL,
};
static struct config_item_type uvcg_default_processing_type = {
- .ct_item_ops = &uvcg_default_processing_item_ops,
.ct_attrs = uvcg_default_processing_attrs,
.ct_owner = THIS_MODULE,
};
@@ -318,17 +298,11 @@ static inline struct uvcg_default_camera
struct uvcg_default_camera, group);
}
-CONFIGFS_ATTR_STRUCT(uvcg_default_camera);
-CONFIGFS_ATTR_OPS_RO(uvcg_default_camera);
-
-static struct configfs_item_operations uvcg_default_camera_item_ops = {
- .show_attribute = uvcg_default_camera_attr_show,
-};
-
#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \
static ssize_t uvcg_default_camera_##cname##_show( \
- struct uvcg_default_camera *dc, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_default_camera *dc = to_uvcg_default_camera(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
@@ -351,9 +325,7 @@ static ssize_t uvcg_default_camera_##cname##_show( \
return result; \
} \
\
-static struct uvcg_default_camera_attribute \
- uvcg_default_camera_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_default_camera_##cname##_show)
+UVC_ATTR_RO(uvcg_default_camera_, cname, aname)
#define identity_conv(x) (x)
@@ -373,8 +345,9 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
#undef UVCG_DEFAULT_CAMERA_ATTR
static ssize_t uvcg_default_camera_bm_controls_show(
- struct uvcg_default_camera *dc, char *page)
+ struct config_item *item, char *page)
{
+ struct uvcg_default_camera *dc = to_uvcg_default_camera(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
@@ -400,24 +373,21 @@ static ssize_t uvcg_default_camera_bm_controls_show(
return result;
}
-static struct uvcg_default_camera_attribute
- uvcg_default_camera_bm_controls =
- __CONFIGFS_ATTR_RO(bmControls, uvcg_default_camera_bm_controls_show);
+UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls);
static struct configfs_attribute *uvcg_default_camera_attrs[] = {
- &uvcg_default_camera_b_terminal_id.attr,
- &uvcg_default_camera_w_terminal_type.attr,
- &uvcg_default_camera_b_assoc_terminal.attr,
- &uvcg_default_camera_i_terminal.attr,
- &uvcg_default_camera_w_objective_focal_length_min.attr,
- &uvcg_default_camera_w_objective_focal_length_max.attr,
- &uvcg_default_camera_w_ocular_focal_length.attr,
- &uvcg_default_camera_bm_controls.attr,
+ &uvcg_default_camera_attr_b_terminal_id,
+ &uvcg_default_camera_attr_w_terminal_type,
+ &uvcg_default_camera_attr_b_assoc_terminal,
+ &uvcg_default_camera_attr_i_terminal,
+ &uvcg_default_camera_attr_w_objective_focal_length_min,
+ &uvcg_default_camera_attr_w_objective_focal_length_max,
+ &uvcg_default_camera_attr_w_ocular_focal_length,
+ &uvcg_default_camera_attr_bm_controls,
NULL,
};
static struct config_item_type uvcg_default_camera_type = {
- .ct_item_ops = &uvcg_default_camera_item_ops,
.ct_attrs = uvcg_default_camera_attrs,
.ct_owner = THIS_MODULE,
};
@@ -450,17 +420,11 @@ static inline struct uvcg_default_output
struct uvcg_default_output, group);
}
-CONFIGFS_ATTR_STRUCT(uvcg_default_output);
-CONFIGFS_ATTR_OPS_RO(uvcg_default_output);
-
-static struct configfs_item_operations uvcg_default_output_item_ops = {
- .show_attribute = uvcg_default_output_attr_show,
-};
-
#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \
static ssize_t uvcg_default_output_##cname##_show( \
- struct uvcg_default_output *dout, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_default_output *dout = to_uvcg_default_output(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \
@@ -483,9 +447,7 @@ static ssize_t uvcg_default_output_##cname##_show( \
return result; \
} \
\
-static struct uvcg_default_output_attribute \
- uvcg_default_output_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_default_output_##cname##_show)
+UVC_ATTR_RO(uvcg_default_output_, cname, aname)
#define identity_conv(x) (x)
@@ -500,16 +462,15 @@ UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
#undef UVCG_DEFAULT_OUTPUT_ATTR
static struct configfs_attribute *uvcg_default_output_attrs[] = {
- &uvcg_default_output_b_terminal_id.attr,
- &uvcg_default_output_w_terminal_type.attr,
- &uvcg_default_output_b_assoc_terminal.attr,
- &uvcg_default_output_b_source_id.attr,
- &uvcg_default_output_i_terminal.attr,
+ &uvcg_default_output_attr_b_terminal_id,
+ &uvcg_default_output_attr_w_terminal_type,
+ &uvcg_default_output_attr_b_assoc_terminal,
+ &uvcg_default_output_attr_b_source_id,
+ &uvcg_default_output_attr_i_terminal,
NULL,
};
static struct config_item_type uvcg_default_output_type = {
- .ct_item_ops = &uvcg_default_output_item_ops,
.ct_attrs = uvcg_default_output_attrs,
.ct_owner = THIS_MODULE,
};
@@ -800,9 +761,6 @@ static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item
return container_of(item, struct uvcg_streaming_header, item);
}
-CONFIGFS_ATTR_STRUCT(uvcg_streaming_header);
-CONFIGFS_ATTR_OPS(uvcg_streaming_header);
-
static int uvcg_streaming_header_allow_link(struct config_item *src,
struct config_item *target)
{
@@ -893,16 +851,15 @@ out:
}
static struct configfs_item_operations uvcg_streaming_header_item_ops = {
- .show_attribute = uvcg_streaming_header_attr_show,
- .store_attribute = uvcg_streaming_header_attr_store,
.allow_link = uvcg_streaming_header_allow_link,
.drop_link = uvcg_streaming_header_drop_link,
};
#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \
static ssize_t uvcg_streaming_header_##cname##_show( \
- struct uvcg_streaming_header *sh, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_streaming_header *sh = to_uvcg_streaming_header(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\
@@ -921,9 +878,7 @@ static ssize_t uvcg_streaming_header_##cname##_show( \
return result; \
} \
\
-static struct uvcg_streaming_header_attribute \
- uvcg_streaming_header_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_streaming_header_##cname##_show)
+UVC_ATTR_RO(uvcg_streaming_header_, cname, aname)
#define identity_conv(x) (x)
@@ -939,11 +894,11 @@ UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
#undef UVCG_STREAMING_HEADER_ATTR
static struct configfs_attribute *uvcg_streaming_header_attrs[] = {
- &uvcg_streaming_header_bm_info.attr,
- &uvcg_streaming_header_b_terminal_link.attr,
- &uvcg_streaming_header_b_still_capture_method.attr,
- &uvcg_streaming_header_b_trigger_support.attr,
- &uvcg_streaming_header_b_trigger_usage.attr,
+ &uvcg_streaming_header_attr_bm_info,
+ &uvcg_streaming_header_attr_b_terminal_link,
+ &uvcg_streaming_header_attr_b_still_capture_method,
+ &uvcg_streaming_header_attr_b_trigger_support,
+ &uvcg_streaming_header_attr_b_trigger_usage,
NULL,
};
@@ -1022,17 +977,10 @@ static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
return container_of(item, struct uvcg_frame, item);
}
-CONFIGFS_ATTR_STRUCT(uvcg_frame);
-CONFIGFS_ATTR_OPS(uvcg_frame);
-
-static struct configfs_item_operations uvcg_frame_item_ops = {
- .show_attribute = uvcg_frame_attr_show,
- .store_attribute = uvcg_frame_attr_store,
-};
-
#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
-static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\
+static ssize_t uvcg_frame_##cname##_show(struct config_item *item, char *page)\
{ \
+ struct uvcg_frame *f = to_uvcg_frame(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
@@ -1051,9 +999,10 @@ static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\
return result; \
} \
\
-static ssize_t uvcg_frame_##cname##_store(struct uvcg_frame *f, \
+static ssize_t uvcg_frame_##cname##_store(struct config_item *item, \
const char *page, size_t len)\
{ \
+ struct uvcg_frame *f = to_uvcg_frame(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct uvcg_format *fmt; \
@@ -1085,11 +1034,7 @@ end: \
return ret; \
} \
\
-static struct uvcg_frame_attribute \
- uvcg_frame_##cname = \
- __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
- uvcg_frame_##cname##_show, \
- uvcg_frame_##cname##_store)
+UVC_ATTR(uvcg_frame_, cname, aname);
#define noop_conversion(x) (x)
@@ -1108,9 +1053,10 @@ UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
#undef UVCG_FRAME_ATTR
-static ssize_t uvcg_frame_dw_frame_interval_show(struct uvcg_frame *frm,
+static ssize_t uvcg_frame_dw_frame_interval_show(struct config_item *item,
char *page)
{
+ struct uvcg_frame *frm = to_uvcg_frame(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
@@ -1185,9 +1131,10 @@ static int __uvcg_iter_frm_intrv(const char *page, size_t len,
return 0;
}
-static ssize_t uvcg_frame_dw_frame_interval_store(struct uvcg_frame *ch,
+static ssize_t uvcg_frame_dw_frame_interval_store(struct config_item *item,
const char *page, size_t len)
{
+ struct uvcg_frame *ch = to_uvcg_frame(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct uvcg_format *fmt;
@@ -1234,26 +1181,21 @@ end:
return ret;
}
-static struct uvcg_frame_attribute
- uvcg_frame_dw_frame_interval =
- __CONFIGFS_ATTR(dwFrameInterval, S_IRUGO | S_IWUSR,
- uvcg_frame_dw_frame_interval_show,
- uvcg_frame_dw_frame_interval_store);
+UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval);
static struct configfs_attribute *uvcg_frame_attrs[] = {
- &uvcg_frame_bm_capabilities.attr,
- &uvcg_frame_w_width.attr,
- &uvcg_frame_w_height.attr,
- &uvcg_frame_dw_min_bit_rate.attr,
- &uvcg_frame_dw_max_bit_rate.attr,
- &uvcg_frame_dw_max_video_frame_buffer_size.attr,
- &uvcg_frame_dw_default_frame_interval.attr,
- &uvcg_frame_dw_frame_interval.attr,
+ &uvcg_frame_attr_bm_capabilities,
+ &uvcg_frame_attr_w_width,
+ &uvcg_frame_attr_w_height,
+ &uvcg_frame_attr_dw_min_bit_rate,
+ &uvcg_frame_attr_dw_max_bit_rate,
+ &uvcg_frame_attr_dw_max_video_frame_buffer_size,
+ &uvcg_frame_attr_dw_default_frame_interval,
+ &uvcg_frame_attr_dw_frame_interval,
NULL,
};
static struct config_item_type uvcg_frame_type = {
- .ct_item_ops = &uvcg_frame_item_ops,
.ct_attrs = uvcg_frame_attrs,
.ct_owner = THIS_MODULE,
};
@@ -1333,22 +1275,15 @@ static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
struct uvcg_uncompressed, fmt);
}
-CONFIGFS_ATTR_STRUCT(uvcg_uncompressed);
-CONFIGFS_ATTR_OPS(uvcg_uncompressed);
-
-static struct configfs_item_operations uvcg_uncompressed_item_ops = {
- .show_attribute = uvcg_uncompressed_attr_show,
- .store_attribute = uvcg_uncompressed_attr_store,
-};
-
static struct configfs_group_operations uvcg_uncompressed_group_ops = {
.make_item = uvcg_frame_make,
.drop_item = uvcg_frame_drop,
};
-static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch,
+static ssize_t uvcg_uncompressed_guid_format_show(struct config_item *item,
char *page)
{
+ struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
@@ -1367,9 +1302,10 @@ static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch,
return sizeof(ch->desc.guidFormat);
}
-static ssize_t uvcg_uncompressed_guid_format_store(struct uvcg_uncompressed *ch,
+static ssize_t uvcg_uncompressed_guid_format_store(struct config_item *item,
const char *page, size_t len)
{
+ struct uvcg_uncompressed *ch = to_uvcg_uncompressed(item);
struct f_uvc_opts *opts;
struct config_item *opts_item;
struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
@@ -1396,16 +1332,13 @@ end:
return ret;
}
-static struct uvcg_uncompressed_attribute uvcg_uncompressed_guid_format =
- __CONFIGFS_ATTR(guidFormat, S_IRUGO | S_IWUSR,
- uvcg_uncompressed_guid_format_show,
- uvcg_uncompressed_guid_format_store);
-
+UVC_ATTR(uvcg_uncompressed_, guid_format, guidFormat);
#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \
static ssize_t uvcg_uncompressed_##cname##_show( \
- struct uvcg_uncompressed *u, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1424,14 +1357,13 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
return result; \
} \
\
-static struct uvcg_uncompressed_attribute \
- uvcg_uncompressed_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_uncompressed_##cname##_show)
+UVC_ATTR_RO(uvcg_uncompressed_, cname, aname);
#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \
static ssize_t uvcg_uncompressed_##cname##_show( \
- struct uvcg_uncompressed *u, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1451,9 +1383,10 @@ static ssize_t uvcg_uncompressed_##cname##_show( \
} \
\
static ssize_t \
-uvcg_uncompressed_##cname##_store(struct uvcg_uncompressed *u, \
+uvcg_uncompressed_##cname##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct uvcg_uncompressed *u = to_uvcg_uncompressed(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1487,11 +1420,7 @@ end: \
return ret; \
} \
\
-static struct uvcg_uncompressed_attribute \
- uvcg_uncompressed_##cname = \
- __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
- uvcg_uncompressed_##cname##_show, \
- uvcg_uncompressed_##cname##_store)
+UVC_ATTR(uvcg_uncompressed_, cname, aname);
#define identity_conv(x) (x)
@@ -1508,36 +1437,34 @@ UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
#undef UVCG_UNCOMPRESSED_ATTR_RO
static inline ssize_t
-uvcg_uncompressed_bma_controls_show(struct uvcg_uncompressed *unc, char *page)
+uvcg_uncompressed_bma_controls_show(struct config_item *item, char *page)
{
+ struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
return uvcg_format_bma_controls_show(&unc->fmt, page);
}
static inline ssize_t
-uvcg_uncompressed_bma_controls_store(struct uvcg_uncompressed *ch,
+uvcg_uncompressed_bma_controls_store(struct config_item *item,
const char *page, size_t len)
{
- return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+ struct uvcg_uncompressed *unc = to_uvcg_uncompressed(item);
+ return uvcg_format_bma_controls_store(&unc->fmt, page, len);
}
-static struct uvcg_uncompressed_attribute uvcg_uncompressed_bma_controls =
- __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
- uvcg_uncompressed_bma_controls_show,
- uvcg_uncompressed_bma_controls_store);
+UVC_ATTR(uvcg_uncompressed_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
- &uvcg_uncompressed_guid_format.attr,
- &uvcg_uncompressed_b_bits_per_pixel.attr,
- &uvcg_uncompressed_b_default_frame_index.attr,
- &uvcg_uncompressed_b_aspect_ratio_x.attr,
- &uvcg_uncompressed_b_aspect_ratio_y.attr,
- &uvcg_uncompressed_bm_interface_flags.attr,
- &uvcg_uncompressed_bma_controls.attr,
+ &uvcg_uncompressed_attr_guid_format,
+ &uvcg_uncompressed_attr_b_bits_per_pixel,
+ &uvcg_uncompressed_attr_b_default_frame_index,
+ &uvcg_uncompressed_attr_b_aspect_ratio_x,
+ &uvcg_uncompressed_attr_b_aspect_ratio_y,
+ &uvcg_uncompressed_attr_bm_interface_flags,
+ &uvcg_uncompressed_attr_bma_controls,
NULL,
};
static struct config_item_type uvcg_uncompressed_type = {
- .ct_item_ops = &uvcg_uncompressed_item_ops,
.ct_group_ops = &uvcg_uncompressed_group_ops,
.ct_attrs = uvcg_uncompressed_attrs,
.ct_owner = THIS_MODULE,
@@ -1605,22 +1532,15 @@ static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
struct uvcg_mjpeg, fmt);
}
-CONFIGFS_ATTR_STRUCT(uvcg_mjpeg);
-CONFIGFS_ATTR_OPS(uvcg_mjpeg);
-
-static struct configfs_item_operations uvcg_mjpeg_item_ops = {
- .show_attribute = uvcg_mjpeg_attr_show,
- .store_attribute = uvcg_mjpeg_attr_store,
-};
-
static struct configfs_group_operations uvcg_mjpeg_group_ops = {
.make_item = uvcg_frame_make,
.drop_item = uvcg_frame_drop,
};
#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \
-static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \
+ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1639,13 +1559,12 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
return result; \
} \
\
-static struct uvcg_mjpeg_attribute \
- uvcg_mjpeg_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_mjpeg_##cname##_show)
+UVC_ATTR_RO(uvcg_mjpeg_, cname, aname)
#define UVCG_MJPEG_ATTR(cname, aname, conv) \
-static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+static ssize_t uvcg_mjpeg_##cname##_show(struct config_item *item, char *page)\
{ \
+ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1665,9 +1584,10 @@ static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
} \
\
static ssize_t \
-uvcg_mjpeg_##cname##_store(struct uvcg_mjpeg *u, \
+uvcg_mjpeg_##cname##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
@@ -1701,11 +1621,7 @@ end: \
return ret; \
} \
\
-static struct uvcg_mjpeg_attribute \
- uvcg_mjpeg_##cname = \
- __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
- uvcg_mjpeg_##cname##_show, \
- uvcg_mjpeg_##cname##_store)
+UVC_ATTR(uvcg_mjpeg_, cname, aname)
#define identity_conv(x) (x)
@@ -1722,35 +1638,33 @@ UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
#undef UVCG_MJPEG_ATTR_RO
static inline ssize_t
-uvcg_mjpeg_bma_controls_show(struct uvcg_mjpeg *unc, char *page)
+uvcg_mjpeg_bma_controls_show(struct config_item *item, char *page)
{
- return uvcg_format_bma_controls_show(&unc->fmt, page);
+ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
+ return uvcg_format_bma_controls_show(&u->fmt, page);
}
static inline ssize_t
-uvcg_mjpeg_bma_controls_store(struct uvcg_mjpeg *ch,
+uvcg_mjpeg_bma_controls_store(struct config_item *item,
const char *page, size_t len)
{
- return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+ struct uvcg_mjpeg *u = to_uvcg_mjpeg(item);
+ return uvcg_format_bma_controls_store(&u->fmt, page, len);
}
-static struct uvcg_mjpeg_attribute uvcg_mjpeg_bma_controls =
- __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
- uvcg_mjpeg_bma_controls_show,
- uvcg_mjpeg_bma_controls_store);
+UVC_ATTR(uvcg_mjpeg_, bma_controls, bmaControls);
static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
- &uvcg_mjpeg_b_default_frame_index.attr,
- &uvcg_mjpeg_bm_flags.attr,
- &uvcg_mjpeg_b_aspect_ratio_x.attr,
- &uvcg_mjpeg_b_aspect_ratio_y.attr,
- &uvcg_mjpeg_bm_interface_flags.attr,
- &uvcg_mjpeg_bma_controls.attr,
+ &uvcg_mjpeg_attr_b_default_frame_index,
+ &uvcg_mjpeg_attr_bm_flags,
+ &uvcg_mjpeg_attr_b_aspect_ratio_x,
+ &uvcg_mjpeg_attr_b_aspect_ratio_y,
+ &uvcg_mjpeg_attr_bm_interface_flags,
+ &uvcg_mjpeg_attr_bma_controls,
NULL,
};
static struct config_item_type uvcg_mjpeg_type = {
- .ct_item_ops = &uvcg_mjpeg_item_ops,
.ct_group_ops = &uvcg_mjpeg_group_ops,
.ct_attrs = uvcg_mjpeg_attrs,
.ct_owner = THIS_MODULE,
@@ -1811,17 +1725,12 @@ static inline struct uvcg_default_color_matching
struct uvcg_default_color_matching, group);
}
-CONFIGFS_ATTR_STRUCT(uvcg_default_color_matching);
-CONFIGFS_ATTR_OPS_RO(uvcg_default_color_matching);
-
-static struct configfs_item_operations uvcg_default_color_matching_item_ops = {
- .show_attribute = uvcg_default_color_matching_attr_show,
-};
-
#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \
static ssize_t uvcg_default_color_matching_##cname##_show( \
- struct uvcg_default_color_matching *dc, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct uvcg_default_color_matching *dc = \
+ to_uvcg_default_color_matching(item); \
struct f_uvc_opts *opts; \
struct config_item *opts_item; \
struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
@@ -1842,9 +1751,7 @@ static ssize_t uvcg_default_color_matching_##cname##_show( \
return result; \
} \
\
-static struct uvcg_default_color_matching_attribute \
- uvcg_default_color_matching_##cname = \
- __CONFIGFS_ATTR_RO(aname, uvcg_default_color_matching_##cname##_show)
+UVC_ATTR_RO(uvcg_default_color_matching_, cname, aname)
#define identity_conv(x) (x)
@@ -1860,14 +1767,13 @@ UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
- &uvcg_default_color_matching_b_color_primaries.attr,
- &uvcg_default_color_matching_b_transfer_characteristics.attr,
- &uvcg_default_color_matching_b_matrix_coefficients.attr,
+ &uvcg_default_color_matching_attr_b_color_primaries,
+ &uvcg_default_color_matching_attr_b_transfer_characteristics,
+ &uvcg_default_color_matching_attr_b_matrix_coefficients,
NULL,
};
static struct config_item_type uvcg_default_color_matching_type = {
- .ct_item_ops = &uvcg_default_color_matching_item_ops,
.ct_attrs = uvcg_default_color_matching_attrs,
.ct_owner = THIS_MODULE,
};
@@ -2285,9 +2191,6 @@ static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
func_inst.group);
}
-CONFIGFS_ATTR_STRUCT(f_uvc_opts);
-CONFIGFS_ATTR_OPS(f_uvc_opts);
-
static void uvc_attr_release(struct config_item *item)
{
struct f_uvc_opts *opts = to_f_uvc_opts(item);
@@ -2297,14 +2200,13 @@ static void uvc_attr_release(struct config_item *item)
static struct configfs_item_operations uvc_item_ops = {
.release = uvc_attr_release,
- .show_attribute = f_uvc_opts_attr_show,
- .store_attribute = f_uvc_opts_attr_store,
};
#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
static ssize_t f_uvc_opts_##cname##_show( \
- struct f_uvc_opts *opts, char *page) \
+ struct config_item *item, char *page) \
{ \
+ struct f_uvc_opts *opts = to_f_uvc_opts(item); \
int result; \
\
mutex_lock(&opts->lock); \
@@ -2315,9 +2217,10 @@ static ssize_t f_uvc_opts_##cname##_show( \
} \
\
static ssize_t \
-f_uvc_opts_##cname##_store(struct f_uvc_opts *opts, \
+f_uvc_opts_##cname##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct f_uvc_opts *opts = to_f_uvc_opts(item); \
int ret; \
uxx num; \
\
@@ -2342,11 +2245,7 @@ end: \
return ret; \
} \
\
-static struct f_uvc_opts_attribute \
- f_uvc_opts_attribute_##cname = \
- __CONFIGFS_ATTR(cname, S_IRUGO | S_IWUSR, \
- f_uvc_opts_##cname##_show, \
- f_uvc_opts_##cname##_store)
+UVC_ATTR(f_uvc_opts_, cname, aname)
#define identity_conv(x) (x)
@@ -2362,9 +2261,9 @@ UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
#undef UVCG_OPTS_ATTR
static struct configfs_attribute *uvc_attrs[] = {
- &f_uvc_opts_attribute_streaming_interval.attr,
- &f_uvc_opts_attribute_streaming_maxpacket.attr,
- &f_uvc_opts_attribute_streaming_maxburst.attr,
+ &f_uvc_opts_attr_streaming_interval,
+ &f_uvc_opts_attr_streaming_maxpacket,
+ &f_uvc_opts_attr_streaming_maxburst,
NULL,
};
diff --git a/drivers/usb/gadget/function/uvc_queue.c b/drivers/usb/gadget/function/uvc_queue.c
index 51d4a17..912694f 100644
--- a/drivers/usb/gadget/function/uvc_queue.c
+++ b/drivers/usb/gadget/function/uvc_queue.c
@@ -41,7 +41,7 @@
* videobuf2 queue operations
*/
-static int uvc_queue_setup(struct vb2_queue *vq, const void *parg,
+static int uvc_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
@@ -329,7 +329,7 @@ struct uvc_buffer *uvcg_queue_next_buffer(struct uvc_video_queue *queue,
buf->buf.field = V4L2_FIELD_NONE;
buf->buf.sequence = queue->sequence++;
- v4l2_get_timestamp(&buf->buf.timestamp);
+ buf->buf.vb2_buf.timestamp = ktime_get_ns();
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
index 778e42a..22e5615 100644
--- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
@@ -19,8 +19,6 @@
#include <scsi/scsi_tcq.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include <asm/unaligned.h>
#include "tcm_usb_gadget.h"
@@ -1467,23 +1465,21 @@ static void usbg_drop_tport(struct se_wwn *wwn)
/*
* If somebody feels like dropping the version property, go ahead.
*/
-static ssize_t usbg_wwn_show_attr_version(
- struct target_fabric_configfs *tf,
- char *page)
+static ssize_t usbg_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "usb-gadget fabric module\n");
}
-TF_WWN_ATTR_RO(usbg, version);
+
+CONFIGFS_ATTR_RO(usbg_wwn_, version);
static struct configfs_attribute *usbg_wwn_attrs[] = {
- &usbg_wwn_version.attr,
+ &usbg_wwn_attr_version,
NULL,
};
-static ssize_t tcm_usbg_tpg_show_enable(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_usbg_tpg_enable_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect);
@@ -1492,11 +1488,10 @@ static ssize_t tcm_usbg_tpg_show_enable(
static int usbg_attach(struct usbg_tpg *);
static void usbg_detach(struct usbg_tpg *);
-static ssize_t tcm_usbg_tpg_store_enable(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_usbg_tpg_enable_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
unsigned long op;
ssize_t ret;
@@ -1523,12 +1518,10 @@ static ssize_t tcm_usbg_tpg_store_enable(
out:
return count;
}
-TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR);
-static ssize_t tcm_usbg_tpg_show_nexus(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t tcm_usbg_tpg_nexus_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
struct tcm_usbg_nexus *tv_nexus;
ssize_t ret;
@@ -1636,11 +1629,10 @@ out:
return ret;
}
-static ssize_t tcm_usbg_tpg_store_nexus(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t tcm_usbg_tpg_nexus_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg);
unsigned char i_port[USBG_NAMELEN], *ptr;
int ret;
@@ -1670,11 +1662,13 @@ static ssize_t tcm_usbg_tpg_store_nexus(
return ret;
return count;
}
-TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR);
+
+CONFIGFS_ATTR(tcm_usbg_tpg_, enable);
+CONFIGFS_ATTR(tcm_usbg_tpg_, nexus);
static struct configfs_attribute *usbg_base_attrs[] = {
- &tcm_usbg_tpg_enable.attr,
- &tcm_usbg_tpg_nexus.attr,
+ &tcm_usbg_tpg_attr_enable,
+ &tcm_usbg_tpg_attr_nexus,
NULL,
};
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index f0f2b06..f92f5af 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1633,7 +1633,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
spin_lock(&udc->lock);
int_enb = usba_int_enb_get(udc);
- status = usba_readl(udc, INT_STA) & int_enb;
+ status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED);
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index 670ac0b..001a3b7 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -2536,6 +2536,9 @@ static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
udc->pullup_resume = udc->pullup_on;
dplus_pullup(udc, 0);
+ if (udc->driver)
+ udc->driver->disconnect(&udc->gadget);
+
return 0;
}
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 342ffd1..8c6e15b 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -473,6 +473,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
if (!pdata)
return -ENOMEM;
+ pdev->dev.platform_data = pdata;
+
if (!of_property_read_u32(np, "num-ports", &ports))
pdata->ports = ports;
@@ -483,6 +485,7 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
*/
if (i >= pdata->ports) {
pdata->vbus_pin[i] = -EINVAL;
+ pdata->overcurrent_pin[i] = -EINVAL;
continue;
}
@@ -513,10 +516,8 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
}
at91_for_each_port(i) {
- if (i >= pdata->ports) {
- pdata->overcurrent_pin[i] = -EINVAL;
- continue;
- }
+ if (i >= pdata->ports)
+ break;
pdata->overcurrent_pin[i] =
of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
@@ -552,8 +553,6 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
}
}
- pdev->dev.platform_data = pdata;
-
device_init_wakeup(&pdev->dev, 1);
return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
}
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 1b28a00..9c6635d 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -584,27 +584,8 @@ static int uhci_debug_open(struct inode *inode, struct file *file)
static loff_t uhci_debug_lseek(struct file *file, loff_t off, int whence)
{
- struct uhci_debug *up;
- loff_t new = -1;
-
- up = file->private_data;
-
- /*
- * XXX: atomic 64bit seek access, but that needs to be fixed in the VFS
- */
- switch (whence) {
- case 0:
- new = off;
- break;
- case 1:
- new = file->f_pos + off;
- break;
- }
-
- if (new < 0 || new > up->size)
- return -EINVAL;
-
- return (file->f_pos = new);
+ struct uhci_debug *up = file->private_data;
+ return no_seek_end_llseek_size(file, off, whence, up->size);
}
static ssize_t uhci_debug_read(struct file *file, char __user *buf,
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index dc31c42..9f1c053 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -377,6 +377,10 @@ static int qset_fill_page_list(struct whc *whc, struct whc_std *std, gfp_t mem_f
if (std->pl_virt == NULL)
return -ENOMEM;
std->dma_addr = dma_map_single(whc->wusbhc.dev, std->pl_virt, pl_len, DMA_TO_DEVICE);
+ if (dma_mapping_error(whc->wusbhc.dev, std->dma_addr)) {
+ kfree(std->pl_virt);
+ return -EFAULT;
+ }
for (p = 0; p < std->num_pointers; p++) {
std->pl_virt[p].buf_ptr = cpu_to_le64(dma_addr);
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 5d2d7e9..f980c23 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -733,8 +733,30 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
if ((raw_port_status & PORT_RESET) ||
!(raw_port_status & PORT_PE))
return 0xffffffff;
- if (time_after_eq(jiffies,
- bus_state->resume_done[wIndex])) {
+ /* did port event handler already start resume timing? */
+ if (!bus_state->resume_done[wIndex]) {
+ /* If not, maybe we are in a host initated resume? */
+ if (test_bit(wIndex, &bus_state->resuming_ports)) {
+ /* Host initated resume doesn't time the resume
+ * signalling using resume_done[].
+ * It manually sets RESUME state, sleeps 20ms
+ * and sets U0 state. This should probably be
+ * changed, but not right now.
+ */
+ } else {
+ /* port resume was discovered now and here,
+ * start resume timing
+ */
+ unsigned long timeout = jiffies +
+ msecs_to_jiffies(USB_RESUME_TIMEOUT);
+
+ set_bit(wIndex, &bus_state->resuming_ports);
+ bus_state->resume_done[wIndex] = timeout;
+ mod_timer(&hcd->rh_timer, timeout);
+ }
+ /* Has resume been signalled for USB_RESUME_TIME yet? */
+ } else if (time_after_eq(jiffies,
+ bus_state->resume_done[wIndex])) {
int time_left;
xhci_dbg(xhci, "Resume USB2 port %d\n",
@@ -775,19 +797,35 @@ static u32 xhci_get_port_status(struct usb_hcd *hcd,
} else {
/*
* The resume has been signaling for less than
- * 20ms. Report the port status as SUSPEND,
- * let the usbcore check port status again
- * and clear resume signaling later.
+ * USB_RESUME_TIME. Report the port status as SUSPEND,
+ * let the usbcore check port status again and clear
+ * resume signaling later.
*/
status |= USB_PORT_STAT_SUSPEND;
}
}
- if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0
- && (raw_port_status & PORT_POWER)
- && (bus_state->suspended_ports & (1 << wIndex))) {
- bus_state->suspended_ports &= ~(1 << wIndex);
- if (hcd->speed < HCD_USB3)
- bus_state->port_c_suspend |= 1 << wIndex;
+ /*
+ * Clear stale usb2 resume signalling variables in case port changed
+ * state during resume signalling. For example on error
+ */
+ if ((bus_state->resume_done[wIndex] ||
+ test_bit(wIndex, &bus_state->resuming_ports)) &&
+ (raw_port_status & PORT_PLS_MASK) != XDEV_U3 &&
+ (raw_port_status & PORT_PLS_MASK) != XDEV_RESUME) {
+ bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
+ }
+
+
+ if ((raw_port_status & PORT_PLS_MASK) == XDEV_U0 &&
+ (raw_port_status & PORT_POWER)) {
+ if (bus_state->suspended_ports & (1 << wIndex)) {
+ bus_state->suspended_ports &= ~(1 << wIndex);
+ if (hcd->speed < HCD_USB3)
+ bus_state->port_c_suspend |= 1 << wIndex;
+ }
+ bus_state->resume_done[wIndex] = 0;
+ clear_bit(wIndex, &bus_state->resuming_ports);
}
if (raw_port_status & PORT_CONNECT) {
status |= USB_PORT_STAT_CONNECTION;
@@ -1112,6 +1150,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
if ((temp & PORT_PE) == 0)
goto error;
+ set_bit(wIndex, &bus_state->resuming_ports);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_RESUME);
spin_unlock_irqrestore(&xhci->lock, flags);
@@ -1119,6 +1158,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
spin_lock_irqsave(&xhci->lock, flags);
xhci_set_link_state(xhci, port_array, wIndex,
XDEV_U0);
+ clear_bit(wIndex, &bus_state->resuming_ports);
}
bus_state->port_c_suspend |= 1 << wIndex;
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index 17f6897..c621090 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -188,10 +188,14 @@ static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev)
0xb7, 0x0c, 0x34, 0xac, 0x01, 0xe9, 0xbf, 0x45,
0xb7, 0xe6, 0x2b, 0x34, 0xec, 0x93, 0x1e, 0x23,
};
- acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1, NULL);
+ union acpi_object *obj;
+
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(&dev->dev), intel_dsm_uuid, 3, 1,
+ NULL);
+ ACPI_FREE(obj);
}
#else
- static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
+static void xhci_pme_acpi_rtd3_enable(struct pci_dev *dev) { }
#endif /* CONFIG_ACPI */
/* called during probe() after chip reset completes */
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index fa83625..eeaa6c6 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -1583,7 +1583,8 @@ static void handle_port_status(struct xhci_hcd *xhci,
*/
bogus_port_status = true;
goto cleanup;
- } else {
+ } else if (!test_bit(faked_port_index,
+ &bus_state->resuming_ports)) {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
msecs_to_jiffies(USB_RESUME_TIMEOUT);
@@ -3896,28 +3897,6 @@ cleanup:
return ret;
}
-static int ep_ring_is_processing(struct xhci_hcd *xhci,
- int slot_id, unsigned int ep_index)
-{
- struct xhci_virt_device *xdev;
- struct xhci_ring *ep_ring;
- struct xhci_ep_ctx *ep_ctx;
- struct xhci_virt_ep *xep;
- dma_addr_t hw_deq;
-
- xdev = xhci->devs[slot_id];
- xep = &xhci->devs[slot_id]->eps[ep_index];
- ep_ring = xep->ring;
- ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
-
- if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) != EP_STATE_RUNNING)
- return 0;
-
- hw_deq = le64_to_cpu(ep_ctx->deq) & ~EP_CTX_CYCLE_MASK;
- return (hw_deq !=
- xhci_trb_virt_to_dma(ep_ring->enq_seg, ep_ring->enqueue));
-}
-
/*
* Check transfer ring to guarantee there is enough room for the urb.
* Update ISO URB start_frame and interval.
@@ -3983,10 +3962,12 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
}
/* Calculate the start frame and put it in urb->start_frame. */
- if (HCC_CFC(xhci->hcc_params) &&
- ep_ring_is_processing(xhci, slot_id, ep_index)) {
- urb->start_frame = xep->next_frame_id;
- goto skip_start_over;
+ if (HCC_CFC(xhci->hcc_params) && !list_empty(&ep_ring->td_list)) {
+ if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
+ EP_STATE_RUNNING) {
+ urb->start_frame = xep->next_frame_id;
+ goto skip_start_over;
+ }
}
start_frame = readl(&xhci->run_regs->microframe_index);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 6e7dc6f..3f91270 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -175,6 +175,16 @@ int xhci_reset(struct xhci_hcd *xhci)
command |= CMD_RESET;
writel(command, &xhci->op_regs->command);
+ /* Existing Intel xHCI controllers require a delay of 1 mS,
+ * after setting the CMD_RESET bit, and before accessing any
+ * HC registers. This allows the HC to complete the
+ * reset operation and be ready for HC register access.
+ * Without this delay, the subsequent HC register access,
+ * may result in a system hang very rarely.
+ */
+ if (xhci->quirks & XHCI_INTEL_HOST)
+ udelay(1000);
+
ret = xhci_handshake(&xhci->op_regs->command,
CMD_RESET, 0, 10 * 1000 * 1000);
if (ret)
@@ -4768,8 +4778,16 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG);
slot_ctx = xhci_get_slot_ctx(xhci, config_cmd->in_ctx);
slot_ctx->dev_info |= cpu_to_le32(DEV_HUB);
+ /*
+ * refer to section 6.2.2: MTT should be 0 for full speed hub,
+ * but it may be already set to 1 when setup an xHCI virtual
+ * device, so clear it anyway.
+ */
if (tt->multi)
slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
+ else if (hdev->speed == USB_SPEED_FULL)
+ slot_ctx->dev_info &= cpu_to_le32(~DEV_MTT);
+
if (xhci->hci_version > 0x95) {
xhci_dbg(xhci, "xHCI version %x needs hub "
"TT think time and number of ports\n",
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 306d685..8efbaba 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -2825,21 +2825,7 @@ sisusb_lseek(struct file *file, loff_t offset, int orig)
return -ENODEV;
}
- switch (orig) {
- case 0:
- file->f_pos = offset;
- ret = file->f_pos;
- /* never negative, no force_successful_syscall needed */
- break;
- case 1:
- file->f_pos += offset;
- ret = file->f_pos;
- /* never negative, no force_successful_syscall needed */
- break;
- default:
- /* seeking relative to "end of file" is not supported */
- ret = -EINVAL;
- }
+ ret = no_seek_end_llseek(file, offset, orig);
mutex_unlock(&sisusb->lock);
return ret;
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 1f2037b..45c83ba 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -159,7 +159,7 @@ config USB_TI_CPPI_DMA
config USB_TI_CPPI41_DMA
bool 'TI CPPI 4.1 (AM335x)'
- depends on ARCH_OMAP
+ depends on ARCH_OMAP && DMADEVICES
select TI_CPPI41
config USB_TUSB_OMAP_DMA
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index ba13529..ee9ff70 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -132,7 +132,7 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_BLACKFIN
-static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
+static int musb_ulpi_read(struct usb_phy *phy, u32 reg)
{
void __iomem *addr = phy->io_priv;
int i = 0;
@@ -151,7 +151,7 @@ static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
* ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM.
*/
- musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
+ musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
musb_writeb(addr, MUSB_ULPI_REG_CONTROL,
MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR);
@@ -176,7 +176,7 @@ out:
return ret;
}
-static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
+static int musb_ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
{
void __iomem *addr = phy->io_priv;
int i = 0;
@@ -191,8 +191,8 @@ static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
power &= ~MUSB_POWER_SUSPENDM;
musb_writeb(addr, MUSB_POWER, power);
- musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset);
- musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)data);
+ musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)reg);
+ musb_writeb(addr, MUSB_ULPI_REG_DATA, (u8)val);
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ);
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
@@ -1668,7 +1668,7 @@ EXPORT_SYMBOL_GPL(musb_interrupt);
static bool use_dma = 1;
/* "modprobe ... use_dma=0" etc */
-module_param(use_dma, bool, 0);
+module_param(use_dma, bool, 0644);
MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
@@ -2017,7 +2017,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
/* We need musb_read/write functions initialized for PM */
pm_runtime_use_autosuspend(musb->controller);
pm_runtime_set_autosuspend_delay(musb->controller, 200);
- pm_runtime_irq_safe(musb->controller);
pm_runtime_enable(musb->controller);
/* The musb_platform_init() call:
@@ -2095,6 +2094,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
#ifndef CONFIG_MUSB_PIO_ONLY
if (!musb->ops->dma_init || !musb->ops->dma_exit) {
dev_err(dev, "DMA controller not set\n");
+ status = -ENODEV;
goto fail2;
}
musb_dma_controller_create = musb->ops->dma_init;
@@ -2218,6 +2218,12 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_put(musb->controller);
+ /*
+ * For why this is currently needed, see commit 3e43a0725637
+ * ("usb: musb: core: add pm_runtime_irq_safe()")
+ */
+ pm_runtime_irq_safe(musb->controller);
+
return 0;
fail5:
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 26c65e6..795a45b 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -112,22 +112,32 @@ static void musb_h_tx_flush_fifo(struct musb_hw_ep *ep)
struct musb *musb = ep->musb;
void __iomem *epio = ep->regs;
u16 csr;
- u16 lastcsr = 0;
int retries = 1000;
csr = musb_readw(epio, MUSB_TXCSR);
while (csr & MUSB_TXCSR_FIFONOTEMPTY) {
- if (csr != lastcsr)
- dev_dbg(musb->controller, "Host TX FIFONOTEMPTY csr: %02x\n", csr);
- lastcsr = csr;
csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_TXPKTRDY;
musb_writew(epio, MUSB_TXCSR, csr);
csr = musb_readw(epio, MUSB_TXCSR);
- if (WARN(retries-- < 1,
+
+ /*
+ * FIXME: sometimes the tx fifo flush failed, it has been
+ * observed during device disconnect on AM335x.
+ *
+ * To reproduce the issue, ensure tx urb(s) are queued when
+ * unplug the usb device which is connected to AM335x usb
+ * host port.
+ *
+ * I found using a usb-ethernet device and running iperf
+ * (client on AM335x) has very high chance to trigger it.
+ *
+ * Better to turn on dev_dbg() in musb_cleanup_urb() with
+ * CPPI enabled to see the issue when aborting the tx channel.
+ */
+ if (dev_WARN_ONCE(musb->controller, retries-- < 1,
"Could not flush host TX%d fifo: csr: %04x\n",
ep->epnum, csr))
return;
- mdelay(1);
}
}
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 1731324..22e8ecb 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -21,7 +21,6 @@ config AB8500_USB
config FSL_USB2_OTG
bool "Freescale USB OTG Transceiver Driver"
depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM
- select USB_OTG
select USB_PHY
help
Enable this to support Freescale USB OTG transceiver.
@@ -168,8 +167,7 @@ config USB_QCOM_8X16_PHY
config USB_MV_OTG
tristate "Marvell USB OTG support"
- depends on USB_EHCI_MV && USB_MV_UDC && PM
- select USB_OTG
+ depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG
select USB_PHY
help
Say Y here if you want to build Marvell USB OTG transciever
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 80eb991..0d19a6d 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1506,7 +1506,6 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
{
struct msm_otg_platform_data *pdata;
struct extcon_dev *ext_id, *ext_vbus;
- const struct of_device_id *id;
struct device_node *node = pdev->dev.of_node;
struct property *prop;
int len, ret, words;
@@ -1518,8 +1517,9 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
motg->pdata = pdata;
- id = of_match_device(msm_otg_dt_match, &pdev->dev);
- pdata->phy_type = (enum msm_usb_phy_type) id->data;
+ pdata->phy_type = (enum msm_usb_phy_type)of_device_get_match_data(&pdev->dev);
+ if (!pdata->phy_type)
+ return 1;
motg->link_rst = devm_reset_control_get(&pdev->dev, "link");
if (IS_ERR(motg->link_rst))
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index 4d863eb..c2936dc 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -143,12 +143,17 @@ static const struct mxs_phy_data imx6sx_phy_data = {
.flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
};
+static const struct mxs_phy_data imx6ul_phy_data = {
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
+};
+
static const struct of_device_id mxs_phy_dt_ids[] = {
{ .compatible = "fsl,imx6sx-usbphy", .data = &imx6sx_phy_data, },
{ .compatible = "fsl,imx6sl-usbphy", .data = &imx6sl_phy_data, },
{ .compatible = "fsl,imx6q-usbphy", .data = &imx6q_phy_data, },
{ .compatible = "fsl,imx23-usbphy", .data = &imx23_phy_data, },
{ .compatible = "fsl,vf610-usbphy", .data = &vf610_phy_data, },
+ { .compatible = "fsl,imx6ul-usbphy", .data = &imx6ul_phy_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mxs_phy_dt_ids);
@@ -452,10 +457,13 @@ static int mxs_phy_probe(struct platform_device *pdev)
struct clk *clk;
struct mxs_phy *mxs_phy;
int ret;
- const struct of_device_id *of_id =
- of_match_device(mxs_phy_dt_ids, &pdev->dev);
+ const struct of_device_id *of_id;
struct device_node *np = pdev->dev.of_node;
+ of_id = of_match_device(mxs_phy_dt_ids, &pdev->dev);
+ if (!of_id)
+ return -ENODEV;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c
index 1270906..c4bf2de 100644
--- a/drivers/usb/phy/phy-omap-otg.c
+++ b/drivers/usb/phy/phy-omap-otg.c
@@ -105,7 +105,6 @@ static int omap_otg_probe(struct platform_device *pdev)
extcon = extcon_get_extcon_dev(config->extcon);
if (!extcon)
return -EPROBE_DEFER;
- otg_dev->extcon = extcon;
otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL);
if (!otg_dev)
@@ -115,6 +114,7 @@ static int omap_otg_probe(struct platform_device *pdev)
if (IS_ERR(otg_dev->base))
return PTR_ERR(otg_dev->base);
+ otg_dev->extcon = extcon;
otg_dev->id_nb.notifier_call = omap_otg_id_notifier;
otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index de4f97d..8f7a78e 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -131,7 +131,8 @@ static void __usbhsg_queue_pop(struct usbhsg_uep *uep,
struct device *dev = usbhsg_gpriv_to_dev(gpriv);
struct usbhs_priv *priv = usbhsg_gpriv_to_priv(gpriv);
- dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));
+ if (pipe)
+ dev_dbg(dev, "pipe %d : queue pop\n", usbhs_pipe_number(pipe));
ureq->req.status = status;
spin_unlock(usbhs_priv_to_lock(priv));
@@ -685,7 +686,13 @@ static int usbhsg_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
- usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
+ if (pipe)
+ usbhs_pkt_pop(pipe, usbhsg_ureq_to_pkt(ureq));
+
+ /*
+ * To dequeue a request, this driver should call the usbhsg_queue_pop()
+ * even if the pipe is NULL.
+ */
usbhsg_queue_pop(uep, ureq, -ECONNRESET);
return 0;
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index eac7cca..7d4f51a 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -132,7 +132,6 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
- { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index f51a5d5..ec1b8f2 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -531,7 +531,8 @@ static int ipaq_open(struct tty_struct *tty,
* through. Since this has a reasonably high failure rate, we retry
* several times.
*/
- while (retries--) {
+ while (retries) {
+ retries--;
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
0x1, 0, NULL, 0, 100);
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 685fef7..f228060 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -161,6 +161,7 @@ static void option_instat_callback(struct urb *urb);
#define NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_HIGHSPEED 0x9001
#define NOVATELWIRELESS_PRODUCT_E362 0x9010
#define NOVATELWIRELESS_PRODUCT_E371 0x9011
+#define NOVATELWIRELESS_PRODUCT_U620L 0x9022
#define NOVATELWIRELESS_PRODUCT_G2 0xA010
#define NOVATELWIRELESS_PRODUCT_MC551 0xB001
@@ -354,6 +355,7 @@ static void option_instat_callback(struct urb *urb);
/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
* It seems to contain a Qualcomm QSC6240/6290 chipset */
#define FOUR_G_SYSTEMS_PRODUCT_W14 0x9603
+#define FOUR_G_SYSTEMS_PRODUCT_W100 0x9b01
/* iBall 3.5G connect wireless modem */
#define IBALL_3_5G_CONNECT 0x9605
@@ -519,6 +521,11 @@ static const struct option_blacklist_info four_g_w14_blacklist = {
.sendsetup = BIT(0) | BIT(1),
};
+static const struct option_blacklist_info four_g_w100_blacklist = {
+ .sendsetup = BIT(1) | BIT(2),
+ .reserved = BIT(3),
+};
+
static const struct option_blacklist_info alcatel_x200_blacklist = {
.sendsetup = BIT(0) | BIT(1),
.reserved = BIT(4),
@@ -1052,6 +1059,7 @@ static const struct usb_device_id option_ids[] = {
{ 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_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_E371, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_U620L, 0xff, 0x00, 0x00) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_H01A) },
@@ -1641,6 +1649,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
.driver_info = (kernel_ulong_t)&four_g_w14_blacklist
},
+ { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W100),
+ .driver_info = (kernel_ulong_t)&four_g_w100_blacklist
+ },
{ USB_DEVICE_INTERFACE_CLASS(LONGCHEER_VENDOR_ID, SPEEDUP_PRODUCT_SU9800, 0xff) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, ZOOM_PRODUCT_4597) },
{ USB_DEVICE(LONGCHEER_VENDOR_ID, IBALL_3_5G_CONNECT) },
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index 5022fcf..9919d2a 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -22,6 +22,8 @@
#define DRIVER_AUTHOR "Qualcomm Inc"
#define DRIVER_DESC "Qualcomm USB Serial driver"
+#define QUECTEL_EC20_PID 0x9215
+
/* standard device layouts supported by this driver */
enum qcserial_layouts {
QCSERIAL_G2K = 0, /* Gobi 2000 */
@@ -171,6 +173,38 @@ static const struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
+static int handle_quectel_ec20(struct device *dev, int ifnum)
+{
+ int altsetting = 0;
+
+ /*
+ * Quectel EC20 Mini PCIe LTE module layout:
+ * 0: DM/DIAG (use libqcdm from ModemManager for communication)
+ * 1: NMEA
+ * 2: AT-capable modem port
+ * 3: Modem interface
+ * 4: NDIS
+ */
+ switch (ifnum) {
+ case 0:
+ dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n");
+ break;
+ case 1:
+ dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n");
+ break;
+ case 2:
+ case 3:
+ dev_dbg(dev, "Quectel EC20 Modem port found\n");
+ break;
+ case 4:
+ /* Don't claim the QMI/net interface */
+ altsetting = -1;
+ break;
+ }
+
+ return altsetting;
+}
+
static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
{
struct usb_host_interface *intf = serial->interface->cur_altsetting;
@@ -181,6 +215,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
int altsetting = -1;
bool sendsetup = false;
+ /* we only support vendor specific functions */
+ if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+ goto done;
+
nintf = serial->dev->actconfig->desc.bNumInterfaces;
dev_dbg(dev, "Num Interfaces = %d\n", nintf);
ifnum = intf->desc.bInterfaceNumber;
@@ -240,6 +278,12 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
altsetting = -1;
break;
case QCSERIAL_G2K:
+ /* handle non-standard layouts */
+ if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) {
+ altsetting = handle_quectel_ec20(dev, ifnum);
+ goto done;
+ }
+
/*
* Gobi 2K+ USB layout:
* 0: QMI/net
@@ -301,29 +345,39 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
break;
case QCSERIAL_HWI:
/*
- * Huawei layout:
- * 0: AT-capable modem port
- * 1: DM/DIAG
- * 2: AT-capable modem port
- * 3: CCID-compatible PCSC interface
- * 4: QMI/net
- * 5: NMEA
+ * Huawei devices map functions by subclass + protocol
+ * instead of interface numbers. The protocol identify
+ * a specific function, while the subclass indicate a
+ * specific firmware source
+ *
+ * This is a blacklist of functions known to be
+ * non-serial. The rest are assumed to be serial and
+ * will be handled by this driver
*/
- switch (ifnum) {
- case 0:
- case 2:
- dev_dbg(dev, "Modem port found\n");
- break;
- case 1:
- dev_dbg(dev, "DM/DIAG interface found\n");
- break;
- case 5:
- dev_dbg(dev, "NMEA GPS interface found\n");
- break;
- default:
- /* don't claim any unsupported interface */
+ switch (intf->desc.bInterfaceProtocol) {
+ /* QMI combined (qmi_wwan) */
+ case 0x07:
+ case 0x37:
+ case 0x67:
+ /* QMI data (qmi_wwan) */
+ case 0x08:
+ case 0x38:
+ case 0x68:
+ /* QMI control (qmi_wwan) */
+ case 0x09:
+ case 0x39:
+ case 0x69:
+ /* NCM like (huawei_cdc_ncm) */
+ case 0x16:
+ case 0x46:
+ case 0x76:
altsetting = -1;
break;
+ default:
+ dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n",
+ intf->desc.bInterfaceClass,
+ intf->desc.bInterfaceSubClass,
+ intf->desc.bInterfaceProtocol);
}
break;
default:
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index e9da41d..2694df2 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -159,6 +159,7 @@ static const struct usb_device_id ti_id_table_3410[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STEREO_PLUG_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+ { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ } /* terminator */
};
@@ -191,6 +192,7 @@ static const struct usb_device_id ti_id_table_combined[] = {
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) },
{ USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_STRIP_PORT_ID) },
{ USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) },
+ { USB_DEVICE(HONEYWELL_VENDOR_ID, HONEYWELL_HGI80_PRODUCT_ID) },
{ } /* terminator */
};
diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h
index 4a2423e..98f35c6 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.h
+++ b/drivers/usb/serial/ti_usb_3410_5052.h
@@ -56,6 +56,10 @@
#define ABBOTT_PRODUCT_ID ABBOTT_STEREO_PLUG_ID
#define ABBOTT_STRIP_PORT_ID 0x3420
+/* Honeywell vendor and product IDs */
+#define HONEYWELL_VENDOR_ID 0x10ac
+#define HONEYWELL_HGI80_PRODUCT_ID 0x0102 /* Honeywell HGI80 */
+
/* Commands */
#define TI_GET_VERSION 0x01
#define TI_GET_PORT_STATUS 0x02
diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c
index 3658662..a204782 100644
--- a/drivers/usb/serial/usb-serial-simple.c
+++ b/drivers/usb/serial/usb-serial-simple.c
@@ -53,6 +53,7 @@ DEVICE(funsoft, FUNSOFT_IDS);
/* Infineon Flashloader driver */
#define FLASHLOADER_IDS() \
+ { USB_DEVICE_INTERFACE_CLASS(0x058b, 0x0041, USB_CLASS_CDC_DATA) }, \
{ USB_DEVICE(0x8087, 0x0716) }
DEVICE(flashloader, FLASHLOADER_IDS);
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 48ca9c2..5c66d3f 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -796,6 +796,10 @@ static int uas_slave_configure(struct scsi_device *sdev)
if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
sdev->no_report_opcodes = 1;
+ /* A few buggy USB-ATA bridges don't understand FUA */
+ if (devinfo->flags & US_FL_BROKEN_FUA)
+ sdev->broken_fua = 1;
+
scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
return 0;
}
@@ -812,7 +816,6 @@ static struct scsi_host_template uas_host_template = {
.this_id = -1,
.sg_tablesize = SG_NONE,
.skip_settle_delay = 1,
- .use_blk_tags = 1,
};
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
@@ -929,10 +932,6 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (result)
goto set_alt0;
- result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
- if (result)
- goto free_streams;
-
usb_set_intfdata(intf, shost);
result = scsi_add_host(shost, &intf->dev);
if (result)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 6b24791..7ffe420 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1987,7 +1987,7 @@ UNUSUAL_DEV( 0x14cd, 0x6600, 0x0201, 0x0201,
US_FL_IGNORE_RESIDUE ),
/* Reported by Michael Büsch <m@bues.ch> */
-UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0114,
+UNUSUAL_DEV( 0x152d, 0x0567, 0x0114, 0x0116,
"JMicron",
"USB to ATA/ATAPI Bridge",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index c85ea53..ccc113e 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -132,7 +132,7 @@ UNUSUAL_DEV(0x152d, 0x0567, 0x0000, 0x9999,
"JMicron",
"JMS567",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
- US_FL_NO_REPORT_OPCODES),
+ US_FL_BROKEN_FUA | US_FL_NO_REPORT_OPCODES),
/* Reported-by: Hans de Goede <hdegoede@redhat.com> */
UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999,
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 964ad57..56bf6db 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -1035,7 +1035,7 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_CAN_RECOVER;
}
-static struct pci_error_handlers vfio_err_handlers = {
+static const struct pci_error_handlers vfio_err_handlers = {
.error_detected = vfio_pci_aer_err_detected,
};
diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c
index ff75ca3..fe2b470 100644
--- a/drivers/vfio/pci/vfio_pci_config.c
+++ b/drivers/vfio/pci/vfio_pci_config.c
@@ -46,7 +46,7 @@
* 0: Removed from the user visible capability list
* FF: Variable length
*/
-static u8 pci_cap_length[] = {
+static const u8 pci_cap_length[PCI_CAP_ID_MAX + 1] = {
[PCI_CAP_ID_BASIC] = PCI_STD_HEADER_SIZEOF, /* pci config header */
[PCI_CAP_ID_PM] = PCI_PM_SIZEOF,
[PCI_CAP_ID_AGP] = PCI_AGP_SIZEOF,
@@ -74,7 +74,7 @@ static u8 pci_cap_length[] = {
* 0: Removed or masked from the user visible capabilty list
* FF: Variable length
*/
-static u16 pci_ext_cap_length[] = {
+static const u16 pci_ext_cap_length[PCI_EXT_CAP_ID_MAX + 1] = {
[PCI_EXT_CAP_ID_ERR] = PCI_ERR_ROOT_COMMAND,
[PCI_EXT_CAP_ID_VC] = 0xFF,
[PCI_EXT_CAP_ID_DSN] = PCI_EXT_CAP_DSN_SIZEOF,
@@ -671,6 +671,73 @@ static int __init init_pci_cap_pm_perm(struct perm_bits *perm)
return 0;
}
+static int vfio_vpd_config_write(struct vfio_pci_device *vdev, int pos,
+ int count, struct perm_bits *perm,
+ int offset, __le32 val)
+{
+ struct pci_dev *pdev = vdev->pdev;
+ __le16 *paddr = (__le16 *)(vdev->vconfig + pos - offset + PCI_VPD_ADDR);
+ __le32 *pdata = (__le32 *)(vdev->vconfig + pos - offset + PCI_VPD_DATA);
+ u16 addr;
+ u32 data;
+
+ /*
+ * Write through to emulation. If the write includes the upper byte
+ * of PCI_VPD_ADDR, then the PCI_VPD_ADDR_F bit is written and we
+ * have work to do.
+ */
+ count = vfio_default_config_write(vdev, pos, count, perm, offset, val);
+ if (count < 0 || offset > PCI_VPD_ADDR + 1 ||
+ offset + count <= PCI_VPD_ADDR + 1)
+ return count;
+
+ addr = le16_to_cpu(*paddr);
+
+ if (addr & PCI_VPD_ADDR_F) {
+ data = le32_to_cpu(*pdata);
+ if (pci_write_vpd(pdev, addr & ~PCI_VPD_ADDR_F, 4, &data) != 4)
+ return count;
+ } else {
+ if (pci_read_vpd(pdev, addr, 4, &data) != 4)
+ return count;
+ *pdata = cpu_to_le32(data);
+ }
+
+ /*
+ * Toggle PCI_VPD_ADDR_F in the emulated PCI_VPD_ADDR register to
+ * signal completion. If an error occurs above, we assume that not
+ * toggling this bit will induce a driver timeout.
+ */
+ addr ^= PCI_VPD_ADDR_F;
+ *paddr = cpu_to_le16(addr);
+
+ return count;
+}
+
+/* Permissions for Vital Product Data capability */
+static int __init init_pci_cap_vpd_perm(struct perm_bits *perm)
+{
+ if (alloc_perm_bits(perm, pci_cap_length[PCI_CAP_ID_VPD]))
+ return -ENOMEM;
+
+ perm->writefn = vfio_vpd_config_write;
+
+ /*
+ * We always virtualize the next field so we can remove
+ * capabilities from the chain if we want to.
+ */
+ p_setb(perm, PCI_CAP_LIST_NEXT, (u8)ALL_VIRT, NO_WRITE);
+
+ /*
+ * Both the address and data registers are virtualized to
+ * enable access through the pci_vpd_read/write functions
+ */
+ p_setw(perm, PCI_VPD_ADDR, (u16)ALL_VIRT, (u16)ALL_WRITE);
+ p_setd(perm, PCI_VPD_DATA, ALL_VIRT, ALL_WRITE);
+
+ return 0;
+}
+
/* Permissions for PCI-X capability */
static int __init init_pci_cap_pcix_perm(struct perm_bits *perm)
{
@@ -790,6 +857,7 @@ void vfio_pci_uninit_perm_bits(void)
free_perm_bits(&cap_perms[PCI_CAP_ID_BASIC]);
free_perm_bits(&cap_perms[PCI_CAP_ID_PM]);
+ free_perm_bits(&cap_perms[PCI_CAP_ID_VPD]);
free_perm_bits(&cap_perms[PCI_CAP_ID_PCIX]);
free_perm_bits(&cap_perms[PCI_CAP_ID_EXP]);
free_perm_bits(&cap_perms[PCI_CAP_ID_AF]);
@@ -807,7 +875,7 @@ int __init vfio_pci_init_perm_bits(void)
/* Capabilities */
ret |= init_pci_cap_pm_perm(&cap_perms[PCI_CAP_ID_PM]);
- cap_perms[PCI_CAP_ID_VPD].writefn = vfio_raw_config_write;
+ ret |= init_pci_cap_vpd_perm(&cap_perms[PCI_CAP_ID_VPD]);
ret |= init_pci_cap_pcix_perm(&cap_perms[PCI_CAP_ID_PCIX]);
cap_perms[PCI_CAP_ID_VNDR].writefn = vfio_raw_config_write;
ret |= init_pci_cap_exp_perm(&cap_perms[PCI_CAP_ID_EXP]);
diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
index 9ce8afe..41a6224 100644
--- a/drivers/vfio/platform/Makefile
+++ b/drivers/vfio/platform/Makefile
@@ -1,10 +1,12 @@
-
-vfio-platform-y := vfio_platform.o vfio_platform_common.o vfio_platform_irq.o
+vfio-platform-base-y := vfio_platform_common.o vfio_platform_irq.o
+vfio-platform-y := vfio_platform.o
obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
+obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform-base.o
obj-$(CONFIG_VFIO_PLATFORM) += reset/
vfio-amba-y := vfio_amba.o
obj-$(CONFIG_VFIO_AMBA) += vfio-amba.o
+obj-$(CONFIG_VFIO_AMBA) += vfio-platform-base.o
obj-$(CONFIG_VFIO_AMBA) += reset/
diff --git a/drivers/vfio/platform/reset/Kconfig b/drivers/vfio/platform/reset/Kconfig
index 746b96b..70cccc5 100644
--- a/drivers/vfio/platform/reset/Kconfig
+++ b/drivers/vfio/platform/reset/Kconfig
@@ -5,3 +5,11 @@ config VFIO_PLATFORM_CALXEDAXGMAC_RESET
Enables the VFIO platform driver to handle reset for Calxeda xgmac
If you don't know what to do here, say N.
+
+config VFIO_PLATFORM_AMDXGBE_RESET
+ tristate "VFIO support for AMD XGBE reset"
+ depends on VFIO_PLATFORM
+ help
+ Enables the VFIO platform driver to handle reset for AMD XGBE
+
+ If you don't know what to do here, say N.
diff --git a/drivers/vfio/platform/reset/Makefile b/drivers/vfio/platform/reset/Makefile
index 2a486af..93f4e23 100644
--- a/drivers/vfio/platform/reset/Makefile
+++ b/drivers/vfio/platform/reset/Makefile
@@ -1,5 +1,7 @@
vfio-platform-calxedaxgmac-y := vfio_platform_calxedaxgmac.o
+vfio-platform-amdxgbe-y := vfio_platform_amdxgbe.o
ccflags-y += -Idrivers/vfio/platform
obj-$(CONFIG_VFIO_PLATFORM_CALXEDAXGMAC_RESET) += vfio-platform-calxedaxgmac.o
+obj-$(CONFIG_VFIO_PLATFORM_AMDXGBE_RESET) += vfio-platform-amdxgbe.o
diff --git a/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
new file mode 100644
index 0000000..da5356f
--- /dev/null
+++ b/drivers/vfio/platform/reset/vfio_platform_amdxgbe.c
@@ -0,0 +1,127 @@
+/*
+ * VFIO platform driver specialized for AMD xgbe reset
+ * reset code is inherited from AMD xgbe native driver
+ *
+ * Copyright (c) 2015 Linaro Ltd.
+ * www.linaro.org
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <uapi/linux/mdio.h>
+#include <linux/delay.h>
+
+#include "vfio_platform_private.h"
+
+#define DMA_MR 0x3000
+#define MAC_VR 0x0110
+#define DMA_ISR 0x3008
+#define MAC_ISR 0x00b0
+#define PCS_MMD_SELECT 0xff
+#define MDIO_AN_INT 0x8002
+#define MDIO_AN_INTMASK 0x8001
+
+static unsigned int xmdio_read(void *ioaddr, unsigned int mmd,
+ unsigned int reg)
+{
+ unsigned int mmd_address, value;
+
+ mmd_address = (mmd << 16) | ((reg) & 0xffff);
+ iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2));
+ value = ioread32(ioaddr + ((mmd_address & 0xff) << 2));
+ return value;
+}
+
+static void xmdio_write(void *ioaddr, unsigned int mmd,
+ unsigned int reg, unsigned int value)
+{
+ unsigned int mmd_address;
+
+ mmd_address = (mmd << 16) | ((reg) & 0xffff);
+ iowrite32(mmd_address >> 8, ioaddr + (PCS_MMD_SELECT << 2));
+ iowrite32(value, ioaddr + ((mmd_address & 0xff) << 2));
+}
+
+int vfio_platform_amdxgbe_reset(struct vfio_platform_device *vdev)
+{
+ struct vfio_platform_region *xgmac_regs = &vdev->regions[0];
+ struct vfio_platform_region *xpcs_regs = &vdev->regions[1];
+ u32 dma_mr_value, pcs_value, value;
+ unsigned int count;
+
+ if (!xgmac_regs->ioaddr) {
+ xgmac_regs->ioaddr =
+ ioremap_nocache(xgmac_regs->addr, xgmac_regs->size);
+ if (!xgmac_regs->ioaddr)
+ return -ENOMEM;
+ }
+ if (!xpcs_regs->ioaddr) {
+ xpcs_regs->ioaddr =
+ ioremap_nocache(xpcs_regs->addr, xpcs_regs->size);
+ if (!xpcs_regs->ioaddr)
+ return -ENOMEM;
+ }
+
+ /* reset the PHY through MDIO*/
+ pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1);
+ pcs_value |= MDIO_CTRL1_RESET;
+ xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_PCS, MDIO_CTRL1, pcs_value);
+
+ count = 50;
+ do {
+ msleep(20);
+ pcs_value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_PCS,
+ MDIO_CTRL1);
+ } while ((pcs_value & MDIO_CTRL1_RESET) && --count);
+
+ if (pcs_value & MDIO_CTRL1_RESET)
+ pr_warn("%s XGBE PHY reset timeout\n", __func__);
+
+ /* disable auto-negotiation */
+ value = xmdio_read(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1);
+ value &= ~MDIO_AN_CTRL1_ENABLE;
+ xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_CTRL1, value);
+
+ /* disable AN IRQ */
+ xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+
+ /* clear AN IRQ */
+ xmdio_write(xpcs_regs->ioaddr, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ /* MAC software reset */
+ dma_mr_value = ioread32(xgmac_regs->ioaddr + DMA_MR);
+ dma_mr_value |= 0x1;
+ iowrite32(dma_mr_value, xgmac_regs->ioaddr + DMA_MR);
+
+ usleep_range(10, 15);
+
+ count = 2000;
+ while (count-- && (ioread32(xgmac_regs->ioaddr + DMA_MR) & 1))
+ usleep_range(500, 600);
+
+ if (!count)
+ pr_warn("%s MAC SW reset failed\n", __func__);
+
+ return 0;
+}
+
+module_vfio_reset_handler("amd,xgbe-seattle-v1a", vfio_platform_amdxgbe_reset);
+
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Eric Auger <eric.auger@linaro.org>");
+MODULE_DESCRIPTION("Reset support for AMD xgbe vfio platform device");
diff --git a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
index 619dc7d..e3d3d94 100644
--- a/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
+++ b/drivers/vfio/platform/reset/vfio_platform_calxedaxgmac.c
@@ -30,8 +30,6 @@
#define DRIVER_AUTHOR "Eric Auger <eric.auger@linaro.org>"
#define DRIVER_DESC "Reset support for Calxeda xgmac vfio platform device"
-#define CALXEDAXGMAC_COMPAT "calxeda,hb-xgmac"
-
/* XGMAC Register definitions */
#define XGMAC_CONTROL 0x00000000 /* MAC Configuration */
@@ -61,24 +59,25 @@ static inline void xgmac_mac_disable(void __iomem *ioaddr)
int vfio_platform_calxedaxgmac_reset(struct vfio_platform_device *vdev)
{
- struct vfio_platform_region reg = vdev->regions[0];
+ struct vfio_platform_region *reg = &vdev->regions[0];
- if (!reg.ioaddr) {
- reg.ioaddr =
- ioremap_nocache(reg.addr, reg.size);
- if (!reg.ioaddr)
+ if (!reg->ioaddr) {
+ reg->ioaddr =
+ ioremap_nocache(reg->addr, reg->size);
+ if (!reg->ioaddr)
return -ENOMEM;
}
/* disable IRQ */
- writel(0, reg.ioaddr + XGMAC_DMA_INTR_ENA);
+ writel(0, reg->ioaddr + XGMAC_DMA_INTR_ENA);
/* Disable the MAC core */
- xgmac_mac_disable(reg.ioaddr);
+ xgmac_mac_disable(reg->ioaddr);
return 0;
}
-EXPORT_SYMBOL_GPL(vfio_platform_calxedaxgmac_reset);
+
+module_vfio_reset_handler("calxeda,hb-xgmac", vfio_platform_calxedaxgmac_reset);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL v2");
diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c
index ff0331f..a66479b 100644
--- a/drivers/vfio/platform/vfio_amba.c
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -67,6 +67,7 @@ static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
vdev->get_resource = get_amba_resource;
vdev->get_irq = get_amba_irq;
+ vdev->parent_module = THIS_MODULE;
ret = vfio_platform_probe_common(vdev, &adev->dev);
if (ret) {
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
index cef645c..b1cc3a7 100644
--- a/drivers/vfio/platform/vfio_platform.c
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -65,6 +65,7 @@ static int vfio_platform_probe(struct platform_device *pdev)
vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM;
vdev->get_resource = get_platform_resource;
vdev->get_irq = get_platform_irq;
+ vdev->parent_module = THIS_MODULE;
ret = vfio_platform_probe_common(vdev, &pdev->dev);
if (ret)
@@ -91,7 +92,6 @@ static struct platform_driver vfio_platform_driver = {
.remove = vfio_platform_remove,
.driver = {
.name = "vfio-platform",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/vfio/platform/vfio_platform_common.c b/drivers/vfio/platform/vfio_platform_common.c
index e43efb5..418cdd9 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -23,44 +23,47 @@
#include "vfio_platform_private.h"
-static DEFINE_MUTEX(driver_lock);
+#define DRIVER_VERSION "0.10"
+#define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>"
+#define DRIVER_DESC "VFIO platform base module"
-static const struct vfio_platform_reset_combo reset_lookup_table[] = {
- {
- .compat = "calxeda,hb-xgmac",
- .reset_function_name = "vfio_platform_calxedaxgmac_reset",
- .module_name = "vfio-platform-calxedaxgmac",
- },
-};
+static LIST_HEAD(reset_list);
+static DEFINE_MUTEX(driver_lock);
-static void vfio_platform_get_reset(struct vfio_platform_device *vdev,
- struct device *dev)
+static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat,
+ struct module **module)
{
- const char *compat;
- int (*reset)(struct vfio_platform_device *);
- int ret, i;
-
- ret = device_property_read_string(dev, "compatible", &compat);
- if (ret)
- return;
-
- for (i = 0 ; i < ARRAY_SIZE(reset_lookup_table); i++) {
- if (!strcmp(reset_lookup_table[i].compat, compat)) {
- request_module(reset_lookup_table[i].module_name);
- reset = __symbol_get(
- reset_lookup_table[i].reset_function_name);
- if (reset) {
- vdev->reset = reset;
- return;
- }
+ struct vfio_platform_reset_node *iter;
+ vfio_platform_reset_fn_t reset_fn = NULL;
+
+ mutex_lock(&driver_lock);
+ list_for_each_entry(iter, &reset_list, link) {
+ if (!strcmp(iter->compat, compat) &&
+ try_module_get(iter->owner)) {
+ *module = iter->owner;
+ reset_fn = iter->reset;
+ break;
}
}
+ mutex_unlock(&driver_lock);
+ return reset_fn;
+}
+
+static void vfio_platform_get_reset(struct vfio_platform_device *vdev)
+{
+ vdev->reset = vfio_platform_lookup_reset(vdev->compat,
+ &vdev->reset_module);
+ if (!vdev->reset) {
+ request_module("vfio-reset:%s", vdev->compat);
+ vdev->reset = vfio_platform_lookup_reset(vdev->compat,
+ &vdev->reset_module);
+ }
}
static void vfio_platform_put_reset(struct vfio_platform_device *vdev)
{
if (vdev->reset)
- symbol_put_addr(vdev->reset);
+ module_put(vdev->reset_module);
}
static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
@@ -138,15 +141,19 @@ static void vfio_platform_release(void *device_data)
mutex_lock(&driver_lock);
if (!(--vdev->refcnt)) {
- if (vdev->reset)
+ if (vdev->reset) {
+ dev_info(vdev->device, "reset\n");
vdev->reset(vdev);
+ } else {
+ dev_warn(vdev->device, "no reset function found!\n");
+ }
vfio_platform_regions_cleanup(vdev);
vfio_platform_irq_cleanup(vdev);
}
mutex_unlock(&driver_lock);
- module_put(THIS_MODULE);
+ module_put(vdev->parent_module);
}
static int vfio_platform_open(void *device_data)
@@ -154,7 +161,7 @@ static int vfio_platform_open(void *device_data)
struct vfio_platform_device *vdev = device_data;
int ret;
- if (!try_module_get(THIS_MODULE))
+ if (!try_module_get(vdev->parent_module))
return -ENODEV;
mutex_lock(&driver_lock);
@@ -168,8 +175,12 @@ static int vfio_platform_open(void *device_data)
if (ret)
goto err_irq;
- if (vdev->reset)
+ if (vdev->reset) {
+ dev_info(vdev->device, "reset\n");
vdev->reset(vdev);
+ } else {
+ dev_warn(vdev->device, "no reset function found!\n");
+ }
}
vdev->refcnt++;
@@ -307,17 +318,17 @@ static long vfio_platform_ioctl(void *device_data,
return -ENOTTY;
}
-static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
+static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg,
char __user *buf, size_t count,
loff_t off)
{
unsigned int done = 0;
- if (!reg.ioaddr) {
- reg.ioaddr =
- ioremap_nocache(reg.addr, reg.size);
+ if (!reg->ioaddr) {
+ reg->ioaddr =
+ ioremap_nocache(reg->addr, reg->size);
- if (!reg.ioaddr)
+ if (!reg->ioaddr)
return -ENOMEM;
}
@@ -327,7 +338,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
if (count >= 4 && !(off % 4)) {
u32 val;
- val = ioread32(reg.ioaddr + off);
+ val = ioread32(reg->ioaddr + off);
if (copy_to_user(buf, &val, 4))
goto err;
@@ -335,7 +346,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
} else if (count >= 2 && !(off % 2)) {
u16 val;
- val = ioread16(reg.ioaddr + off);
+ val = ioread16(reg->ioaddr + off);
if (copy_to_user(buf, &val, 2))
goto err;
@@ -343,7 +354,7 @@ static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
} else {
u8 val;
- val = ioread8(reg.ioaddr + off);
+ val = ioread8(reg->ioaddr + off);
if (copy_to_user(buf, &val, 1))
goto err;
@@ -376,7 +387,7 @@ static ssize_t vfio_platform_read(void *device_data, char __user *buf,
return -EINVAL;
if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
- return vfio_platform_read_mmio(vdev->regions[index],
+ return vfio_platform_read_mmio(&vdev->regions[index],
buf, count, off);
else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
return -EINVAL; /* not implemented */
@@ -384,17 +395,17 @@ static ssize_t vfio_platform_read(void *device_data, char __user *buf,
return -EINVAL;
}
-static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
+static ssize_t vfio_platform_write_mmio(struct vfio_platform_region *reg,
const char __user *buf, size_t count,
loff_t off)
{
unsigned int done = 0;
- if (!reg.ioaddr) {
- reg.ioaddr =
- ioremap_nocache(reg.addr, reg.size);
+ if (!reg->ioaddr) {
+ reg->ioaddr =
+ ioremap_nocache(reg->addr, reg->size);
- if (!reg.ioaddr)
+ if (!reg->ioaddr)
return -ENOMEM;
}
@@ -406,7 +417,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
if (copy_from_user(&val, buf, 4))
goto err;
- iowrite32(val, reg.ioaddr + off);
+ iowrite32(val, reg->ioaddr + off);
filled = 4;
} else if (count >= 2 && !(off % 2)) {
@@ -414,7 +425,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
if (copy_from_user(&val, buf, 2))
goto err;
- iowrite16(val, reg.ioaddr + off);
+ iowrite16(val, reg->ioaddr + off);
filled = 2;
} else {
@@ -422,7 +433,7 @@ static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
if (copy_from_user(&val, buf, 1))
goto err;
- iowrite8(val, reg.ioaddr + off);
+ iowrite8(val, reg->ioaddr + off);
filled = 1;
}
@@ -452,7 +463,7 @@ static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
return -EINVAL;
if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
- return vfio_platform_write_mmio(vdev->regions[index],
+ return vfio_platform_write_mmio(&vdev->regions[index],
buf, count, off);
else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
return -EINVAL; /* not implemented */
@@ -539,6 +550,14 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
if (!vdev)
return -EINVAL;
+ ret = device_property_read_string(dev, "compatible", &vdev->compat);
+ if (ret) {
+ pr_err("VFIO: cannot retrieve compat for %s\n", vdev->name);
+ return -EINVAL;
+ }
+
+ vdev->device = dev;
+
group = iommu_group_get(dev);
if (!group) {
pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
@@ -551,7 +570,7 @@ int vfio_platform_probe_common(struct vfio_platform_device *vdev,
return ret;
}
- vfio_platform_get_reset(vdev, dev);
+ vfio_platform_get_reset(vdev);
mutex_init(&vdev->igate);
@@ -573,3 +592,34 @@ struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
return vdev;
}
EXPORT_SYMBOL_GPL(vfio_platform_remove_common);
+
+void __vfio_platform_register_reset(struct vfio_platform_reset_node *node)
+{
+ mutex_lock(&driver_lock);
+ list_add(&node->link, &reset_list);
+ mutex_unlock(&driver_lock);
+}
+EXPORT_SYMBOL_GPL(__vfio_platform_register_reset);
+
+void vfio_platform_unregister_reset(const char *compat,
+ vfio_platform_reset_fn_t fn)
+{
+ struct vfio_platform_reset_node *iter, *temp;
+
+ mutex_lock(&driver_lock);
+ list_for_each_entry_safe(iter, temp, &reset_list, link) {
+ if (!strcmp(iter->compat, compat) && (iter->reset == fn)) {
+ list_del(&iter->link);
+ break;
+ }
+ }
+
+ mutex_unlock(&driver_lock);
+
+}
+EXPORT_SYMBOL_GPL(vfio_platform_unregister_reset);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/vfio/platform/vfio_platform_irq.c b/drivers/vfio/platform/vfio_platform_irq.c
index 88bba57..46d4750 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -185,6 +185,7 @@ static int vfio_set_trigger(struct vfio_platform_device *vdev, int index,
int ret;
if (irq->trigger) {
+ irq_clear_status_flags(irq->hwirq, IRQ_NOAUTOEN);
free_irq(irq->hwirq, irq);
kfree(irq->name);
eventfd_ctx_put(irq->trigger);
diff --git a/drivers/vfio/platform/vfio_platform_private.h b/drivers/vfio/platform/vfio_platform_private.h
index 1c9b3d5..42816dd 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -56,6 +56,10 @@ struct vfio_platform_device {
u32 num_irqs;
int refcnt;
struct mutex igate;
+ struct module *parent_module;
+ const char *compat;
+ struct module *reset_module;
+ struct device *device;
/*
* These fields should be filled by the bus specific binder
@@ -70,10 +74,13 @@ struct vfio_platform_device {
int (*reset)(struct vfio_platform_device *vdev);
};
-struct vfio_platform_reset_combo {
- const char *compat;
- const char *reset_function_name;
- const char *module_name;
+typedef int (*vfio_platform_reset_fn_t)(struct vfio_platform_device *vdev);
+
+struct vfio_platform_reset_node {
+ struct list_head link;
+ char *compat;
+ struct module *owner;
+ vfio_platform_reset_fn_t reset;
};
extern int vfio_platform_probe_common(struct vfio_platform_device *vdev,
@@ -89,4 +96,29 @@ extern int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
unsigned start, unsigned count,
void *data);
+extern void __vfio_platform_register_reset(struct vfio_platform_reset_node *n);
+extern void vfio_platform_unregister_reset(const char *compat,
+ vfio_platform_reset_fn_t fn);
+#define vfio_platform_register_reset(__compat, __reset) \
+static struct vfio_platform_reset_node __reset ## _node = { \
+ .owner = THIS_MODULE, \
+ .compat = __compat, \
+ .reset = __reset, \
+}; \
+__vfio_platform_register_reset(&__reset ## _node)
+
+#define module_vfio_reset_handler(compat, reset) \
+MODULE_ALIAS("vfio-reset:" compat); \
+static int __init reset ## _module_init(void) \
+{ \
+ vfio_platform_register_reset(compat, reset); \
+ return 0; \
+}; \
+static void __exit reset ## _module_exit(void) \
+{ \
+ vfio_platform_unregister_reset(compat, reset); \
+}; \
+module_init(reset ## _module_init); \
+module_exit(reset ## _module_exit)
+
#endif /* VFIO_PLATFORM_PRIVATE_H */
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index 563c510..6070b79 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -25,6 +25,7 @@
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/pci.h>
#include <linux/rwsem.h>
#include <linux/sched.h>
#include <linux/slab.h>
@@ -438,16 +439,33 @@ static struct vfio_device *vfio_group_get_device(struct vfio_group *group,
}
/*
- * Whitelist some drivers that we know are safe (no dma) or just sit on
- * a device. It's not always practical to leave a device within a group
- * driverless as it could get re-bound to something unsafe.
+ * Some drivers, like pci-stub, are only used to prevent other drivers from
+ * claiming a device and are therefore perfectly legitimate for a user owned
+ * group. The pci-stub driver has no dependencies on DMA or the IOVA mapping
+ * of the device, but it does prevent the user from having direct access to
+ * the device, which is useful in some circumstances.
+ *
+ * We also assume that we can include PCI interconnect devices, ie. bridges.
+ * IOMMU grouping on PCI necessitates that if we lack isolation on a bridge
+ * then all of the downstream devices will be part of the same IOMMU group as
+ * the bridge. Thus, if placing the bridge into the user owned IOVA space
+ * breaks anything, it only does so for user owned devices downstream. Note
+ * that error notification via MSI can be affected for platforms that handle
+ * MSI within the same IOVA space as DMA.
*/
-static const char * const vfio_driver_whitelist[] = { "pci-stub", "pcieport" };
+static const char * const vfio_driver_whitelist[] = { "pci-stub" };
-static bool vfio_whitelisted_driver(struct device_driver *drv)
+static bool vfio_dev_whitelisted(struct device *dev, struct device_driver *drv)
{
int i;
+ if (dev_is_pci(dev)) {
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
+ return true;
+ }
+
for (i = 0; i < ARRAY_SIZE(vfio_driver_whitelist); i++) {
if (!strcmp(drv->name, vfio_driver_whitelist[i]))
return true;
@@ -462,6 +480,7 @@ static bool vfio_whitelisted_driver(struct device_driver *drv)
* - driver-less
* - bound to a vfio driver
* - bound to a whitelisted driver
+ * - a PCI interconnect device
*
* We use two methods to determine whether a device is bound to a vfio
* driver. The first is to test whether the device exists in the vfio
@@ -486,7 +505,7 @@ static int vfio_dev_viable(struct device *dev, void *data)
}
mutex_unlock(&group->unbound_lock);
- if (!ret || !drv || vfio_whitelisted_driver(drv))
+ if (!ret || !drv || vfio_dev_whitelisted(dev, drv))
return 0;
device = vfio_group_get_device(group, dev);
@@ -517,7 +536,7 @@ static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
return 0;
/* TODO Prevent device auto probing */
- WARN("Device %s added to live group %d!\n", dev_name(dev),
+ WARN(1, "Device %s added to live group %d!\n", dev_name(dev),
iommu_group_id(group->iommu_group));
return 0;
@@ -692,11 +711,12 @@ EXPORT_SYMBOL_GPL(vfio_device_get_from_dev);
static struct vfio_device *vfio_device_get_from_name(struct vfio_group *group,
char *buf)
{
- struct vfio_device *device;
+ struct vfio_device *it, *device = NULL;
mutex_lock(&group->device_lock);
- list_for_each_entry(device, &group->device_list, group_next) {
- if (!strcmp(dev_name(device->dev), buf)) {
+ list_for_each_entry(it, &group->device_list, group_next) {
+ if (!strcmp(dev_name(it->dev), buf)) {
+ device = it;
vfio_device_get(device);
break;
}
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 57d8c37..59d47cb 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -403,13 +403,26 @@ static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
static unsigned long vfio_pgsize_bitmap(struct vfio_iommu *iommu)
{
struct vfio_domain *domain;
- unsigned long bitmap = PAGE_MASK;
+ unsigned long bitmap = ULONG_MAX;
mutex_lock(&iommu->lock);
list_for_each_entry(domain, &iommu->domain_list, next)
bitmap &= domain->domain->ops->pgsize_bitmap;
mutex_unlock(&iommu->lock);
+ /*
+ * In case the IOMMU supports page sizes smaller than PAGE_SIZE
+ * we pretend PAGE_SIZE is supported and hide sub-PAGE_SIZE sizes.
+ * That way the user will be able to map/unmap buffers whose size/
+ * start address is aligned with PAGE_SIZE. Pinning code uses that
+ * granularity while iommu driver can use the sub-PAGE_SIZE size
+ * to map the buffer.
+ */
+ if (bitmap & ~PAGE_MASK) {
+ bitmap &= PAGE_MASK;
+ bitmap |= PAGE_SIZE;
+ }
+
return bitmap;
}
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index e25a236..29cfc57 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -42,8 +42,6 @@
#include <scsi/scsi_proto.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
-#include <target/configfs_macros.h>
#include <linux/vhost.h>
#include <linux/virtio_scsi.h>
#include <linux/llist.h>
@@ -1684,11 +1682,10 @@ static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus,
}
}
-static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type(
- struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
unsigned long val;
@@ -1707,19 +1704,20 @@ static ssize_t vhost_scsi_tpg_attrib_store_fabric_prot_type(
return count;
}
-static ssize_t vhost_scsi_tpg_attrib_show_fabric_prot_type(
- struct se_portal_group *se_tpg,
- char *page)
+static ssize_t vhost_scsi_tpg_attrib_fabric_prot_type_show(
+ struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = attrib_to_tpg(item);
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
return sprintf(page, "%d\n", tpg->tv_fabric_prot_type);
}
-TF_TPG_ATTRIB_ATTR(vhost_scsi, fabric_prot_type, S_IRUGO | S_IWUSR);
+
+CONFIGFS_ATTR(vhost_scsi_tpg_attrib_, fabric_prot_type);
static struct configfs_attribute *vhost_scsi_tpg_attrib_attrs[] = {
- &vhost_scsi_tpg_attrib_fabric_prot_type.attr,
+ &vhost_scsi_tpg_attrib_attr_fabric_prot_type,
NULL,
};
@@ -1867,9 +1865,9 @@ static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
return 0;
}
-static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg,
- char *page)
+static ssize_t vhost_scsi_tpg_nexus_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
struct vhost_scsi_nexus *tv_nexus;
@@ -1888,10 +1886,10 @@ static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg,
return ret;
}
-static ssize_t vhost_scsi_tpg_store_nexus(struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t vhost_scsi_tpg_nexus_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct vhost_scsi_tpg *tpg = container_of(se_tpg,
struct vhost_scsi_tpg, se_tpg);
struct vhost_scsi_tport *tport_wwn = tpg->tport;
@@ -1966,10 +1964,10 @@ check_newline:
return count;
}
-TF_TPG_BASE_ATTR(vhost_scsi, nexus, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(vhost_scsi_tpg_, nexus);
static struct configfs_attribute *vhost_scsi_tpg_attrs[] = {
- &vhost_scsi_tpg_nexus.attr,
+ &vhost_scsi_tpg_attr_nexus,
NULL,
};
@@ -2105,18 +2103,17 @@ static void vhost_scsi_drop_tport(struct se_wwn *wwn)
}
static ssize_t
-vhost_scsi_wwn_show_attr_version(struct target_fabric_configfs *tf,
- char *page)
+vhost_scsi_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
"on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
}
-TF_WWN_ATTR_RO(vhost_scsi, version);
+CONFIGFS_ATTR_RO(vhost_scsi_wwn_, version);
static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
- &vhost_scsi_wwn_version.attr,
+ &vhost_scsi_wwn_attr_version,
NULL,
};
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index eec2f11..ad2146a 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -819,7 +819,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp)
BUILD_BUG_ON(__alignof__ *vq->used > VRING_USED_ALIGN_SIZE);
if ((a.avail_user_addr & (VRING_AVAIL_ALIGN_SIZE - 1)) ||
(a.used_user_addr & (VRING_USED_ALIGN_SIZE - 1)) ||
- (a.log_guest_addr & (sizeof(u64) - 1))) {
+ (a.log_guest_addr & (VRING_USED_ALIGN_SIZE - 1))) {
r = -EINVAL;
break;
}
@@ -1369,7 +1369,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
/* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */
if (unlikely(__get_user(ring_head,
- &vq->avail->ring[last_avail_idx % vq->num]))) {
+ &vq->avail->ring[last_avail_idx & (vq->num - 1)]))) {
vq_err(vq, "Failed to read head: idx %d address %p\n",
last_avail_idx,
&vq->avail->ring[last_avail_idx % vq->num]);
@@ -1489,7 +1489,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
u16 old, new;
int start;
- start = vq->last_used_idx % vq->num;
+ start = vq->last_used_idx & (vq->num - 1);
used = vq->used->ring + start;
if (count == 1) {
if (__put_user(heads[0].id, &used->id)) {
@@ -1531,7 +1531,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
{
int start, n, r;
- start = vq->last_used_idx % vq->num;
+ start = vq->last_used_idx & (vq->num - 1);
n = vq->num - start;
if (n < count) {
r = __vhost_add_used_n(vq, heads, n);
diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c
index b335c1a..fe00a07 100644
--- a/drivers/video/fbdev/fsl-diu-fb.c
+++ b/drivers/video/fbdev/fsl-diu-fb.c
@@ -479,7 +479,10 @@ static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
port = FSL_DIU_PORT_DLVDS;
}
- return diu_ops.valid_monitor_port(port);
+ if (diu_ops.valid_monitor_port)
+ port = diu_ops.valid_monitor_port(port);
+
+ return port;
}
/*
@@ -1915,6 +1918,14 @@ static int __init fsl_diu_init(void)
#else
monitor_port = fsl_diu_name_to_port(monitor_string);
#endif
+
+ /*
+ * Must to verify set_pixel_clock. If not implement on platform,
+ * then that means that there is no platform support for the DIU.
+ */
+ if (!diu_ops.set_pixel_clock)
+ return -ENODEV;
+
pr_info("Freescale Display Interface Unit (DIU) framebuffer driver\n");
#ifdef CONFIG_NOT_COHERENT_CACHE
diff --git a/drivers/video/fbdev/omap2/dss/venc.c b/drivers/video/fbdev/omap2/dss/venc.c
index 99ca268..d05a549 100644
--- a/drivers/video/fbdev/omap2/dss/venc.c
+++ b/drivers/video/fbdev/omap2/dss/venc.c
@@ -275,6 +275,12 @@ const struct omap_video_timings omap_dss_pal_timings = {
.vbp = 41,
.interlace = true,
+
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
};
EXPORT_SYMBOL(omap_dss_pal_timings);
@@ -290,6 +296,12 @@ const struct omap_video_timings omap_dss_ntsc_timings = {
.vbp = 31,
.interlace = true,
+
+ .hsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .vsync_level = OMAPDSS_SIG_ACTIVE_LOW,
+ .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
+ .de_level = OMAPDSS_SIG_ACTIVE_HIGH,
+ .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
};
EXPORT_SYMBOL(omap_dss_ntsc_timings);
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b1877d7..7062bb0 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -412,6 +412,7 @@ static int virtio_init(void)
static void __exit virtio_exit(void)
{
bus_unregister(&virtio_bus);
+ ida_destroy(&virtio_index_ida);
}
core_initcall(virtio_init);
module_exit(virtio_exit);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 096b857..ee663c4 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -80,6 +80,12 @@ struct vring_virtqueue {
/* Last used index we've seen. */
u16 last_used_idx;
+ /* Last written value to avail->flags */
+ u16 avail_flags_shadow;
+
+ /* Last written value to avail->idx in guest byte order */
+ u16 avail_idx_shadow;
+
/* How to notify other side. FIXME: commonalize hcalls! */
bool (*notify)(struct virtqueue *vq);
@@ -109,7 +115,7 @@ static struct vring_desc *alloc_indirect(struct virtqueue *_vq,
* otherwise virt_to_phys will give us bogus addresses in the
* virtqueue.
*/
- gfp &= ~(__GFP_HIGHMEM | __GFP_HIGH);
+ gfp &= ~__GFP_HIGHMEM;
desc = kmalloc(total_sg * sizeof(struct vring_desc), gfp);
if (!desc)
@@ -235,13 +241,14 @@ static inline int virtqueue_add(struct virtqueue *_vq,
/* Put entry in available array (but don't update avail->idx until they
* do sync). */
- avail = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) & (vq->vring.num - 1);
+ avail = vq->avail_idx_shadow & (vq->vring.num - 1);
vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head);
/* Descriptors and available array need to be set before we expose the
* new available array entries. */
virtio_wmb(vq->weak_barriers);
- vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) + 1);
+ vq->avail_idx_shadow++;
+ vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow);
vq->num_added++;
pr_debug("Added buffer head %i to %p\n", head, vq);
@@ -354,8 +361,8 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
* event. */
virtio_mb(vq->weak_barriers);
- old = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->num_added;
- new = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx);
+ old = vq->avail_idx_shadow - vq->num_added;
+ new = vq->avail_idx_shadow;
vq->num_added = 0;
#ifdef DEBUG
@@ -510,7 +517,7 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
/* If we expect an interrupt for the next entry, tell host
* by writing event index and flush out the write before
* the read in the next get_buf call. */
- if (!(vq->vring.avail->flags & cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT))) {
+ if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx);
virtio_mb(vq->weak_barriers);
}
@@ -537,7 +544,11 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
- vq->vring.avail->flags |= cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT);
+ if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) {
+ vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+ }
+
}
EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
@@ -565,7 +576,10 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq)
/* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
* either clear the flags bit or point the event index at the next
* entry. Always do both to keep code simple. */
- vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
+ if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
+ vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+ }
vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx);
END_USE(vq);
return last_used_idx;
@@ -633,9 +647,12 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
/* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
* either clear the flags bit or point the event index at the next
* entry. Always do both to keep code simple. */
- vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
+ if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) {
+ vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow);
+ }
/* TODO: tune this threshold */
- bufs = (u16)(virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->last_used_idx) * 3 / 4;
+ bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4;
vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs);
virtio_mb(vq->weak_barriers);
if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) {
@@ -670,7 +687,8 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
/* detach_buf clears data, so grab it now. */
buf = vq->data[i];
detach_buf(vq, i);
- vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - 1);
+ vq->avail_idx_shadow--;
+ vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow);
END_USE(vq);
return buf;
}
@@ -735,6 +753,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
vq->weak_barriers = weak_barriers;
vq->broken = false;
vq->last_used_idx = 0;
+ vq->avail_flags_shadow = 0;
+ vq->avail_idx_shadow = 0;
vq->num_added = 0;
list_add_tail(&vq->vq.list, &vdev->vqs);
#ifdef DEBUG
@@ -746,8 +766,10 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
/* No callback? Tell other side not to bother us. */
- if (!callback)
- vq->vring.avail->flags |= cpu_to_virtio16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
+ if (!callback) {
+ vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow);
+ }
/* Put everything in free lists. */
vq->free_head = 0;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 7a8a6c6..1c427be 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -446,7 +446,7 @@ config MAX63XX_WATCHDOG
config IMX2_WDT
tristate "IMX2+ Watchdog"
- depends on ARCH_MXC
+ depends on ARCH_MXC || ARCH_LAYERSCAPE
select REGMAP_MMIO
select WATCHDOG_CORE
help
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
index 6ad9df9..b751f43 100644
--- a/drivers/watchdog/mtk_wdt.c
+++ b/drivers/watchdog/mtk_wdt.c
@@ -123,6 +123,7 @@ static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
reg = readl(wdt_base + WDT_MODE);
reg &= ~WDT_MODE_EN;
+ reg |= WDT_MODE_KEY;
iowrite32(reg, wdt_base + WDT_MODE);
return 0;
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index d96bee0..6f17c93 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -205,7 +205,7 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog,
static unsigned int omap_wdt_get_timeleft(struct watchdog_device *wdog)
{
- struct omap_wdt_dev *wdev = watchdog_get_drvdata(wdog);
+ struct omap_wdt_dev *wdev = to_omap_wdt_dev(wdog);
void __iomem *base = wdev->base;
u32 value;
diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c
index 4224b3e..313cd1c 100644
--- a/drivers/watchdog/pnx4008_wdt.c
+++ b/drivers/watchdog/pnx4008_wdt.c
@@ -80,7 +80,7 @@ static unsigned int heartbeat = DEFAULT_HEARTBEAT;
static DEFINE_SPINLOCK(io_lock);
static void __iomem *wdt_base;
-struct clk *wdt_clk;
+static struct clk *wdt_clk;
static int pnx4008_wdt_start(struct watchdog_device *wdd)
{
@@ -161,7 +161,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
if (IS_ERR(wdt_clk))
return PTR_ERR(wdt_clk);
- ret = clk_enable(wdt_clk);
+ ret = clk_prepare_enable(wdt_clk);
if (ret)
return ret;
@@ -184,7 +184,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev)
return 0;
disable_clk:
- clk_disable(wdt_clk);
+ clk_disable_unprepare(wdt_clk);
return ret;
}
@@ -192,7 +192,7 @@ static int pnx4008_wdt_remove(struct platform_device *pdev)
{
watchdog_unregister_device(&pnx4008_wdd);
- clk_disable(wdt_clk);
+ clk_disable_unprepare(wdt_clk);
return 0;
}
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index 7f97cdd..9ec5760 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -140,8 +140,10 @@ static int tegra_wdt_set_timeout(struct watchdog_device *wdd,
{
wdd->timeout = timeout;
- if (watchdog_active(wdd))
+ if (watchdog_active(wdd)) {
+ tegra_wdt_stop(wdd);
return tegra_wdt_start(wdd);
+ }
return 0;
}
diff --git a/drivers/watchdog/w83977f_wdt.c b/drivers/watchdog/w83977f_wdt.c
index 91bf55a..20e2bba 100644
--- a/drivers/watchdog/w83977f_wdt.c
+++ b/drivers/watchdog/w83977f_wdt.c
@@ -224,7 +224,7 @@ static int wdt_keepalive(void)
static int wdt_set_timeout(int t)
{
- int tmrval;
+ unsigned int tmrval;
/*
* Convert seconds to watchdog counter time units, rounding up.
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index aa8a7f7..9b7a35c 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -1,6 +1,6 @@
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
obj-$(CONFIG_X86) += fallback.o
-obj-y += grant-table.o features.o balloon.o manage.o preempt.o
+obj-y += grant-table.o features.o balloon.o manage.o preempt.o time.o
obj-y += events/
obj-y += xenbus/
diff --git a/drivers/xen/acpi.c b/drivers/xen/acpi.c
index 90307c0..6893c79 100644
--- a/drivers/xen/acpi.c
+++ b/drivers/xen/acpi.c
@@ -58,7 +58,7 @@ static int xen_acpi_notify_hypervisor_state(u8 sleep_state,
bits, val_a, val_b))
return -1;
- HYPERVISOR_dom0_op(&op);
+ HYPERVISOR_platform_op(&op);
return 1;
}
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
index f745db2..be7e56a 100644
--- a/drivers/xen/efi.c
+++ b/drivers/xen/efi.c
@@ -42,7 +42,7 @@ static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
{
struct xen_platform_op op = INIT_EFI_OP(get_time);
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
if (tm) {
@@ -67,7 +67,7 @@ static efi_status_t xen_efi_set_time(efi_time_t *tm)
BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
return efi_data(op).status;
@@ -79,7 +79,7 @@ static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
{
struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
if (tm) {
@@ -108,7 +108,7 @@ static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
else
efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
return efi_data(op).status;
@@ -129,7 +129,7 @@ static efi_status_t xen_efi_get_variable(efi_char16_t *name,
efi_data(op).u.get_variable.size = *data_size;
set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
*data_size = efi_data(op).u.get_variable.size;
@@ -152,7 +152,7 @@ static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
sizeof(*vendor));
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
*name_size = efi_data(op).u.get_next_variable_name.size;
@@ -178,7 +178,7 @@ static efi_status_t xen_efi_set_variable(efi_char16_t *name,
efi_data(op).u.set_variable.size = data_size;
set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
return efi_data(op).status;
@@ -196,7 +196,7 @@ static efi_status_t xen_efi_query_variable_info(u32 attr,
efi_data(op).u.query_variable_info.attr = attr;
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
*storage_space = efi_data(op).u.query_variable_info.max_store_size;
@@ -210,7 +210,7 @@ static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
{
struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
*count = efi_data(op).misc;
@@ -232,7 +232,7 @@ static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
efi_data(op).u.update_capsule.capsule_count = count;
efi_data(op).u.update_capsule.sg_list = sg_list;
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
return efi_data(op).status;
@@ -252,7 +252,7 @@ static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
capsules);
efi_data(op).u.query_capsule_capabilities.capsule_count = count;
- if (HYPERVISOR_dom0_op(&op) < 0)
+ if (HYPERVISOR_platform_op(&op) < 0)
return EFI_UNSUPPORTED;
*max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
@@ -331,7 +331,7 @@ efi_system_table_t __init *xen_efi_probe(void)
};
union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
- if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0)
+ if (!xen_initial_domain() || HYPERVISOR_platform_op(&op) < 0)
return NULL;
/* Here we know that Xen runs on EFI platform. */
@@ -347,7 +347,7 @@ efi_system_table_t __init *xen_efi_probe(void)
info->vendor.bufsz = sizeof(vendor);
set_xen_guest_handle(info->vendor.name, vendor);
- if (HYPERVISOR_dom0_op(&op) == 0) {
+ if (HYPERVISOR_platform_op(&op) == 0) {
efi_systab_xen.fw_vendor = __pa_symbol(vendor);
efi_systab_xen.fw_revision = info->vendor.revision;
} else
@@ -357,14 +357,14 @@ efi_system_table_t __init *xen_efi_probe(void)
op.u.firmware_info.type = XEN_FW_EFI_INFO;
op.u.firmware_info.index = XEN_FW_EFI_VERSION;
- if (HYPERVISOR_dom0_op(&op) == 0)
+ if (HYPERVISOR_platform_op(&op) == 0)
efi_systab_xen.hdr.revision = info->version;
op.cmd = XENPF_firmware_info;
op.u.firmware_info.type = XEN_FW_EFI_INFO;
op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
- if (HYPERVISOR_dom0_op(&op) == 0)
+ if (HYPERVISOR_platform_op(&op) == 0)
efi.runtime_version = info->version;
return &efi_systab_xen;
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c
index 849500e..524c221 100644
--- a/drivers/xen/events/events_base.c
+++ b/drivers/xen/events/events_base.c
@@ -39,6 +39,7 @@
#include <asm/irq.h>
#include <asm/idle.h>
#include <asm/io_apic.h>
+#include <asm/i8259.h>
#include <asm/xen/pci.h>
#endif
#include <asm/sync_bitops.h>
@@ -420,7 +421,7 @@ static int __must_check xen_allocate_irq_gsi(unsigned gsi)
return xen_allocate_irq_dynamic();
/* Legacy IRQ descriptors are already allocated by the arch. */
- if (gsi < NR_IRQS_LEGACY)
+ if (gsi < nr_legacy_irqs())
irq = gsi;
else
irq = irq_alloc_desc_at(gsi, -1);
@@ -446,7 +447,7 @@ static void xen_free_irq(unsigned irq)
kfree(info);
/* Legacy IRQ descriptors are managed by the arch. */
- if (irq < NR_IRQS_LEGACY)
+ if (irq < nr_legacy_irqs())
return;
irq_free_desc(irq);
diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c
index e3e9e3d..96a1b8d 100644
--- a/drivers/xen/events/events_fifo.c
+++ b/drivers/xen/events/events_fifo.c
@@ -281,7 +281,8 @@ static void handle_irq_for_port(unsigned port)
static void consume_one_event(unsigned cpu,
struct evtchn_fifo_control_block *control_block,
- unsigned priority, unsigned long *ready)
+ unsigned priority, unsigned long *ready,
+ bool drop)
{
struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
uint32_t head;
@@ -313,13 +314,17 @@ static void consume_one_event(unsigned cpu,
if (head == 0)
clear_bit(priority, ready);
- if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port))
- handle_irq_for_port(port);
+ if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
+ if (unlikely(drop))
+ pr_warn("Dropping pending event for port %u\n", port);
+ else
+ handle_irq_for_port(port);
+ }
q->head[priority] = head;
}
-static void evtchn_fifo_handle_events(unsigned cpu)
+static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
{
struct evtchn_fifo_control_block *control_block;
unsigned long ready;
@@ -331,11 +336,16 @@ static void evtchn_fifo_handle_events(unsigned cpu)
while (ready) {
q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES);
- consume_one_event(cpu, control_block, q, &ready);
+ consume_one_event(cpu, control_block, q, &ready, drop);
ready |= xchg(&control_block->ready, 0);
}
}
+static void evtchn_fifo_handle_events(unsigned cpu)
+{
+ __evtchn_fifo_handle_events(cpu, false);
+}
+
static void evtchn_fifo_resume(void)
{
unsigned cpu;
@@ -420,6 +430,9 @@ static int evtchn_fifo_cpu_notification(struct notifier_block *self,
if (!per_cpu(cpu_control_block, cpu))
ret = evtchn_fifo_alloc_control_block(cpu);
break;
+ case CPU_DEAD:
+ __evtchn_fifo_handle_events(cpu, true);
+ break;
default:
break;
}
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
index 00f40f0..38272ad 100644
--- a/drivers/xen/evtchn.c
+++ b/drivers/xen/evtchn.c
@@ -49,6 +49,8 @@
#include <linux/init.h>
#include <linux/mutex.h>
#include <linux/cpu.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <xen/xen.h>
#include <xen/events.h>
@@ -58,10 +60,10 @@
struct per_user_data {
struct mutex bind_mutex; /* serialize bind/unbind operations */
struct rb_root evtchns;
+ unsigned int nr_evtchns;
/* Notification ring, accessed via /dev/xen/evtchn. */
-#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t))
-#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
+ unsigned int ring_size;
evtchn_port_t *ring;
unsigned int ring_cons, ring_prod, ring_overflow;
struct mutex ring_cons_mutex; /* protect against concurrent readers */
@@ -80,10 +82,41 @@ struct user_evtchn {
bool enabled;
};
+static evtchn_port_t *evtchn_alloc_ring(unsigned int size)
+{
+ evtchn_port_t *ring;
+ size_t s = size * sizeof(*ring);
+
+ ring = kmalloc(s, GFP_KERNEL);
+ if (!ring)
+ ring = vmalloc(s);
+
+ return ring;
+}
+
+static void evtchn_free_ring(evtchn_port_t *ring)
+{
+ kvfree(ring);
+}
+
+static unsigned int evtchn_ring_offset(struct per_user_data *u,
+ unsigned int idx)
+{
+ return idx & (u->ring_size - 1);
+}
+
+static evtchn_port_t *evtchn_ring_entry(struct per_user_data *u,
+ unsigned int idx)
+{
+ return u->ring + evtchn_ring_offset(u, idx);
+}
+
static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
{
struct rb_node **new = &(u->evtchns.rb_node), *parent = NULL;
+ u->nr_evtchns++;
+
while (*new) {
struct user_evtchn *this;
@@ -107,6 +140,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
static void del_evtchn(struct per_user_data *u, struct user_evtchn *evtchn)
{
+ u->nr_evtchns--;
rb_erase(&evtchn->node, &u->evtchns);
kfree(evtchn);
}
@@ -144,8 +178,8 @@ static irqreturn_t evtchn_interrupt(int irq, void *data)
spin_lock(&u->ring_prod_lock);
- if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
- u->ring[EVTCHN_RING_MASK(u->ring_prod)] = evtchn->port;
+ if ((u->ring_prod - u->ring_cons) < u->ring_size) {
+ *evtchn_ring_entry(u, u->ring_prod) = evtchn->port;
wmb(); /* Ensure ring contents visible */
if (u->ring_cons == u->ring_prod++) {
wake_up_interruptible(&u->evtchn_wait);
@@ -200,10 +234,10 @@ static ssize_t evtchn_read(struct file *file, char __user *buf,
}
/* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
- if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
- bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
+ if (((c ^ p) & u->ring_size) != 0) {
+ bytes1 = (u->ring_size - evtchn_ring_offset(u, c)) *
sizeof(evtchn_port_t);
- bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
+ bytes2 = evtchn_ring_offset(u, p) * sizeof(evtchn_port_t);
} else {
bytes1 = (p - c) * sizeof(evtchn_port_t);
bytes2 = 0;
@@ -219,7 +253,7 @@ static ssize_t evtchn_read(struct file *file, char __user *buf,
rc = -EFAULT;
rmb(); /* Ensure that we see the port before we copy it. */
- if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
+ if (copy_to_user(buf, evtchn_ring_entry(u, c), bytes1) ||
((bytes2 != 0) &&
copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
goto unlock_out;
@@ -278,6 +312,66 @@ static ssize_t evtchn_write(struct file *file, const char __user *buf,
return rc;
}
+static int evtchn_resize_ring(struct per_user_data *u)
+{
+ unsigned int new_size;
+ evtchn_port_t *new_ring, *old_ring;
+ unsigned int p, c;
+
+ /*
+ * Ensure the ring is large enough to capture all possible
+ * events. i.e., one free slot for each bound event.
+ */
+ if (u->nr_evtchns <= u->ring_size)
+ return 0;
+
+ if (u->ring_size == 0)
+ new_size = 64;
+ else
+ new_size = 2 * u->ring_size;
+
+ new_ring = evtchn_alloc_ring(new_size);
+ if (!new_ring)
+ return -ENOMEM;
+
+ old_ring = u->ring;
+
+ /*
+ * Access to the ring contents is serialized by either the
+ * prod /or/ cons lock so take both when resizing.
+ */
+ mutex_lock(&u->ring_cons_mutex);
+ spin_lock_irq(&u->ring_prod_lock);
+
+ /*
+ * Copy the old ring contents to the new ring.
+ *
+ * If the ring contents crosses the end of the current ring,
+ * it needs to be copied in two chunks.
+ *
+ * +---------+ +------------------+
+ * |34567 12| -> | 1234567 |
+ * +-----p-c-+ +------------------+
+ */
+ p = evtchn_ring_offset(u, u->ring_prod);
+ c = evtchn_ring_offset(u, u->ring_cons);
+ if (p < c) {
+ memcpy(new_ring + c, u->ring + c, (u->ring_size - c) * sizeof(*u->ring));
+ memcpy(new_ring + u->ring_size, u->ring, p * sizeof(*u->ring));
+ } else
+ memcpy(new_ring + c, u->ring + c, (p - c) * sizeof(*u->ring));
+
+ u->ring = new_ring;
+ u->ring_size = new_size;
+
+ spin_unlock_irq(&u->ring_prod_lock);
+ mutex_unlock(&u->ring_cons_mutex);
+
+ evtchn_free_ring(old_ring);
+
+ return 0;
+}
+
static int evtchn_bind_to_user(struct per_user_data *u, int port)
{
struct user_evtchn *evtchn;
@@ -305,6 +399,10 @@ static int evtchn_bind_to_user(struct per_user_data *u, int port)
if (rc < 0)
goto err;
+ rc = evtchn_resize_ring(u);
+ if (rc < 0)
+ goto err;
+
rc = bind_evtchn_to_irqhandler(port, evtchn_interrupt, 0,
u->name, evtchn);
if (rc < 0)
@@ -503,13 +601,6 @@ static int evtchn_open(struct inode *inode, struct file *filp)
init_waitqueue_head(&u->evtchn_wait);
- u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
- if (u->ring == NULL) {
- kfree(u->name);
- kfree(u);
- return -ENOMEM;
- }
-
mutex_init(&u->bind_mutex);
mutex_init(&u->ring_cons_mutex);
spin_lock_init(&u->ring_prod_lock);
@@ -532,7 +623,7 @@ static int evtchn_release(struct inode *inode, struct file *filp)
evtchn_unbind_from_user(u, evtchn);
}
- free_page((unsigned long)u->ring);
+ evtchn_free_ring(u->ring);
kfree(u->name);
kfree(u);
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 2ea0b3b..dc49538 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -518,7 +518,7 @@ static void mn_release(struct mmu_notifier *mn,
mutex_unlock(&priv->lock);
}
-static struct mmu_notifier_ops gntdev_mmu_ops = {
+static const struct mmu_notifier_ops gntdev_mmu_ops = {
.release = mn_release,
.invalidate_page = mn_invl_page,
.invalidate_range_start = mn_invl_range_start,
@@ -748,6 +748,206 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
return rc;
}
+#define GNTDEV_COPY_BATCH 24
+
+struct gntdev_copy_batch {
+ struct gnttab_copy ops[GNTDEV_COPY_BATCH];
+ struct page *pages[GNTDEV_COPY_BATCH];
+ s16 __user *status[GNTDEV_COPY_BATCH];
+ unsigned int nr_ops;
+ unsigned int nr_pages;
+};
+
+static int gntdev_get_page(struct gntdev_copy_batch *batch, void __user *virt,
+ bool writeable, unsigned long *gfn)
+{
+ unsigned long addr = (unsigned long)virt;
+ struct page *page;
+ unsigned long xen_pfn;
+ int ret;
+
+ ret = get_user_pages_fast(addr, 1, writeable, &page);
+ if (ret < 0)
+ return ret;
+
+ batch->pages[batch->nr_pages++] = page;
+
+ xen_pfn = page_to_xen_pfn(page) + XEN_PFN_DOWN(addr & ~PAGE_MASK);
+ *gfn = pfn_to_gfn(xen_pfn);
+
+ return 0;
+}
+
+static void gntdev_put_pages(struct gntdev_copy_batch *batch)
+{
+ unsigned int i;
+
+ for (i = 0; i < batch->nr_pages; i++)
+ put_page(batch->pages[i]);
+ batch->nr_pages = 0;
+}
+
+static int gntdev_copy(struct gntdev_copy_batch *batch)
+{
+ unsigned int i;
+
+ gnttab_batch_copy(batch->ops, batch->nr_ops);
+ gntdev_put_pages(batch);
+
+ /*
+ * For each completed op, update the status if the op failed
+ * and all previous ops for the segment were successful.
+ */
+ for (i = 0; i < batch->nr_ops; i++) {
+ s16 status = batch->ops[i].status;
+ s16 old_status;
+
+ if (status == GNTST_okay)
+ continue;
+
+ if (__get_user(old_status, batch->status[i]))
+ return -EFAULT;
+
+ if (old_status != GNTST_okay)
+ continue;
+
+ if (__put_user(status, batch->status[i]))
+ return -EFAULT;
+ }
+
+ batch->nr_ops = 0;
+ return 0;
+}
+
+static int gntdev_grant_copy_seg(struct gntdev_copy_batch *batch,
+ struct gntdev_grant_copy_segment *seg,
+ s16 __user *status)
+{
+ uint16_t copied = 0;
+
+ /*
+ * Disallow local -> local copies since there is only space in
+ * batch->pages for one page per-op and this would be a very
+ * expensive memcpy().
+ */
+ if (!(seg->flags & (GNTCOPY_source_gref | GNTCOPY_dest_gref)))
+ return -EINVAL;
+
+ /* Can't cross page if source/dest is a grant ref. */
+ if (seg->flags & GNTCOPY_source_gref) {
+ if (seg->source.foreign.offset + seg->len > XEN_PAGE_SIZE)
+ return -EINVAL;
+ }
+ if (seg->flags & GNTCOPY_dest_gref) {
+ if (seg->dest.foreign.offset + seg->len > XEN_PAGE_SIZE)
+ return -EINVAL;
+ }
+
+ if (put_user(GNTST_okay, status))
+ return -EFAULT;
+
+ while (copied < seg->len) {
+ struct gnttab_copy *op;
+ void __user *virt;
+ size_t len, off;
+ unsigned long gfn;
+ int ret;
+
+ if (batch->nr_ops >= GNTDEV_COPY_BATCH) {
+ ret = gntdev_copy(batch);
+ if (ret < 0)
+ return ret;
+ }
+
+ len = seg->len - copied;
+
+ op = &batch->ops[batch->nr_ops];
+ op->flags = 0;
+
+ if (seg->flags & GNTCOPY_source_gref) {
+ op->source.u.ref = seg->source.foreign.ref;
+ op->source.domid = seg->source.foreign.domid;
+ op->source.offset = seg->source.foreign.offset + copied;
+ op->flags |= GNTCOPY_source_gref;
+ } else {
+ virt = seg->source.virt + copied;
+ off = (unsigned long)virt & ~XEN_PAGE_MASK;
+ len = min(len, (size_t)XEN_PAGE_SIZE - off);
+
+ ret = gntdev_get_page(batch, virt, false, &gfn);
+ if (ret < 0)
+ return ret;
+
+ op->source.u.gmfn = gfn;
+ op->source.domid = DOMID_SELF;
+ op->source.offset = off;
+ }
+
+ if (seg->flags & GNTCOPY_dest_gref) {
+ op->dest.u.ref = seg->dest.foreign.ref;
+ op->dest.domid = seg->dest.foreign.domid;
+ op->dest.offset = seg->dest.foreign.offset + copied;
+ op->flags |= GNTCOPY_dest_gref;
+ } else {
+ virt = seg->dest.virt + copied;
+ off = (unsigned long)virt & ~XEN_PAGE_MASK;
+ len = min(len, (size_t)XEN_PAGE_SIZE - off);
+
+ ret = gntdev_get_page(batch, virt, true, &gfn);
+ if (ret < 0)
+ return ret;
+
+ op->dest.u.gmfn = gfn;
+ op->dest.domid = DOMID_SELF;
+ op->dest.offset = off;
+ }
+
+ op->len = len;
+ copied += len;
+
+ batch->status[batch->nr_ops] = status;
+ batch->nr_ops++;
+ }
+
+ return 0;
+}
+
+static long gntdev_ioctl_grant_copy(struct gntdev_priv *priv, void __user *u)
+{
+ struct ioctl_gntdev_grant_copy copy;
+ struct gntdev_copy_batch batch;
+ unsigned int i;
+ int ret = 0;
+
+ if (copy_from_user(&copy, u, sizeof(copy)))
+ return -EFAULT;
+
+ batch.nr_ops = 0;
+ batch.nr_pages = 0;
+
+ for (i = 0; i < copy.count; i++) {
+ struct gntdev_grant_copy_segment seg;
+
+ if (copy_from_user(&seg, &copy.segments[i], sizeof(seg))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret = gntdev_grant_copy_seg(&batch, &seg, &copy.segments[i].status);
+ if (ret < 0)
+ goto out;
+
+ cond_resched();
+ }
+ if (batch.nr_ops)
+ ret = gntdev_copy(&batch);
+ return ret;
+
+ out:
+ gntdev_put_pages(&batch);
+ return ret;
+}
+
static long gntdev_ioctl(struct file *flip,
unsigned int cmd, unsigned long arg)
{
@@ -767,6 +967,9 @@ static long gntdev_ioctl(struct file *flip,
case IOCTL_GNTDEV_SET_UNMAP_NOTIFY:
return gntdev_ioctl_notify(priv, ptr);
+ case IOCTL_GNTDEV_GRANT_COPY:
+ return gntdev_ioctl_grant_copy(priv, ptr);
+
default:
pr_debug("priv %p, unknown cmd %x\n", priv, cmd);
return -ENOIOCTLCMD;
@@ -804,7 +1007,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
vma->vm_ops = &gntdev_vmops;
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
+ vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP | VM_IO;
if (use_ptemod)
vma->vm_flags |= VM_DONTCOPY;
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index c49f79e..effbaf9 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -128,7 +128,7 @@ struct unmap_refs_callback_data {
int result;
};
-static struct gnttab_ops *gnttab_interface;
+static const struct gnttab_ops *gnttab_interface;
static int grant_table_version;
static int grefs_per_grant_frame;
@@ -1013,7 +1013,7 @@ static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
return rc;
}
-static struct gnttab_ops gnttab_v1_ops = {
+static const struct gnttab_ops gnttab_v1_ops = {
.map_frames = gnttab_map_frames_v1,
.unmap_frames = gnttab_unmap_frames_v1,
.update_entry = gnttab_update_entry_v1,
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
index 49e88f2..cdc6daa 100644
--- a/drivers/xen/pcpu.c
+++ b/drivers/xen/pcpu.c
@@ -78,7 +78,7 @@ static int xen_pcpu_down(uint32_t cpu_id)
.u.cpu_ol.cpuid = cpu_id,
};
- return HYPERVISOR_dom0_op(&op);
+ return HYPERVISOR_platform_op(&op);
}
static int xen_pcpu_up(uint32_t cpu_id)
@@ -89,7 +89,7 @@ static int xen_pcpu_up(uint32_t cpu_id)
.u.cpu_ol.cpuid = cpu_id,
};
- return HYPERVISOR_dom0_op(&op);
+ return HYPERVISOR_platform_op(&op);
}
static ssize_t show_online(struct device *dev,
@@ -277,7 +277,7 @@ static int sync_pcpu(uint32_t cpu, uint32_t *max_cpu)
.u.pcpu_info.xen_cpuid = cpu,
};
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
return ret;
@@ -364,7 +364,7 @@ int xen_pcpu_id(uint32_t acpi_id)
op.cmd = XENPF_get_cpuinfo;
while (cpu_id <= max_id) {
op.u.pcpu_info.xen_cpuid = cpu_id;
- if (HYPERVISOR_dom0_op(&op)) {
+ if (HYPERVISOR_platform_op(&op)) {
cpu_id++;
continue;
}
diff --git a/drivers/xen/time.c b/drivers/xen/time.c
new file mode 100644
index 0000000..7107842
--- /dev/null
+++ b/drivers/xen/time.c
@@ -0,0 +1,88 @@
+/*
+ * Xen stolen ticks accounting.
+ */
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/math64.h>
+#include <linux/gfp.h>
+
+#include <asm/xen/hypervisor.h>
+#include <asm/xen/hypercall.h>
+
+#include <xen/events.h>
+#include <xen/features.h>
+#include <xen/interface/xen.h>
+#include <xen/interface/vcpu.h>
+#include <xen/xen-ops.h>
+
+/* runstate info updated by Xen */
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
+
+/* return an consistent snapshot of 64-bit time/counter value */
+static u64 get64(const u64 *p)
+{
+ u64 ret;
+
+ if (BITS_PER_LONG < 64) {
+ u32 *p32 = (u32 *)p;
+ u32 h, l, h2;
+
+ /*
+ * Read high then low, and then make sure high is
+ * still the same; this will only loop if low wraps
+ * and carries into high.
+ * XXX some clean way to make this endian-proof?
+ */
+ do {
+ h = READ_ONCE(p32[1]);
+ l = READ_ONCE(p32[0]);
+ h2 = READ_ONCE(p32[1]);
+ } while(h2 != h);
+
+ ret = (((u64)h) << 32) | l;
+ } else
+ ret = READ_ONCE(*p);
+
+ return ret;
+}
+
+/*
+ * Runstate accounting
+ */
+void xen_get_runstate_snapshot(struct vcpu_runstate_info *res)
+{
+ u64 state_time;
+ struct vcpu_runstate_info *state;
+
+ BUG_ON(preemptible());
+
+ state = this_cpu_ptr(&xen_runstate);
+
+ /*
+ * The runstate info is always updated by the hypervisor on
+ * the current CPU, so there's no need to use anything
+ * stronger than a compiler barrier when fetching it.
+ */
+ do {
+ state_time = get64(&state->state_entry_time);
+ *res = READ_ONCE(*state);
+ } while (get64(&state->state_entry_time) != state_time);
+}
+
+/* return true when a vcpu could run but has no real cpu to run on */
+bool xen_vcpu_stolen(int vcpu)
+{
+ return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
+}
+
+void xen_setup_runstate_info(int cpu)
+{
+ struct vcpu_register_runstate_memory_area area;
+
+ area.addr.v = &per_cpu(xen_runstate, cpu);
+
+ if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
+ cpu, &area))
+ BUG();
+}
+
diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c
index f4a3694..fdc9e67 100644
--- a/drivers/xen/xen-acpi-cpuhotplug.c
+++ b/drivers/xen/xen-acpi-cpuhotplug.c
@@ -206,7 +206,7 @@ static int xen_hotadd_cpu(struct acpi_processor *pr)
op.u.cpu_add.acpi_id = pr->acpi_id;
op.u.cpu_add.pxm = pxm;
- cpu_id = HYPERVISOR_dom0_op(&op);
+ cpu_id = HYPERVISOR_platform_op(&op);
if (cpu_id < 0)
pr_err(PREFIX "Failed to hotadd CPU for acpi_id %d\n",
pr->acpi_id);
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index f83b754..23d1808 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -36,7 +36,7 @@ static int xen_acpi_pad_idle_cpus(unsigned int idle_nums)
op.u.core_parking.type = XEN_CORE_PARKING_SET;
op.u.core_parking.idle_nums = idle_nums;
- return HYPERVISOR_dom0_op(&op);
+ return HYPERVISOR_platform_op(&op);
}
static int xen_acpi_pad_idle_cpus_num(void)
@@ -46,7 +46,7 @@ static int xen_acpi_pad_idle_cpus_num(void)
op.cmd = XENPF_core_parking;
op.u.core_parking.type = XEN_CORE_PARKING_GET;
- return HYPERVISOR_dom0_op(&op)
+ return HYPERVISOR_platform_op(&op)
?: op.u.core_parking.idle_nums;
}
diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c
index 70fa438..076970a 100644
--- a/drivers/xen/xen-acpi-processor.c
+++ b/drivers/xen/xen-acpi-processor.c
@@ -116,7 +116,7 @@ static int push_cxx_to_hypervisor(struct acpi_processor *_pr)
set_xen_guest_handle(op.u.set_pminfo.power.states, dst_cx_states);
if (!no_hypercall)
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (!ret) {
pr_debug("ACPI CPU%u - C-states uploaded.\n", _pr->acpi_id);
@@ -244,7 +244,7 @@ static int push_pxx_to_hypervisor(struct acpi_processor *_pr)
}
if (!no_hypercall)
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (!ret) {
struct acpi_processor_performance *perf;
@@ -302,7 +302,7 @@ static unsigned int __init get_max_acpi_id(void)
info = &op.u.pcpu_info;
info->xen_cpuid = 0;
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
return NR_CPUS;
@@ -310,7 +310,7 @@ static unsigned int __init get_max_acpi_id(void)
last_cpu = op.u.pcpu_info.max_present;
for (i = 0; i <= last_cpu; i++) {
info->xen_cpuid = i;
- ret = HYPERVISOR_dom0_op(&op);
+ ret = HYPERVISOR_platform_op(&op);
if (ret)
continue;
max_acpi_id = max(info->acpi_id, max_acpi_id);
diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h
index 58e38d5..4d529f3 100644
--- a/drivers/xen/xen-pciback/pciback.h
+++ b/drivers/xen/xen-pciback/pciback.h
@@ -37,6 +37,7 @@ struct xen_pcibk_device {
struct xen_pci_sharedinfo *sh_info;
unsigned long flags;
struct work_struct op_work;
+ struct xen_pci_op op;
};
struct xen_pcibk_dev_data {
diff --git a/drivers/xen/xen-pciback/pciback_ops.c b/drivers/xen/xen-pciback/pciback_ops.c
index c4a0666..73dafdc 100644
--- a/drivers/xen/xen-pciback/pciback_ops.c
+++ b/drivers/xen/xen-pciback/pciback_ops.c
@@ -70,6 +70,13 @@ static void xen_pcibk_control_isr(struct pci_dev *dev, int reset)
enable ? "enable" : "disable");
if (enable) {
+ /*
+ * The MSI or MSI-X should not have an IRQ handler. Otherwise
+ * if the guest terminates we BUG_ON in free_msi_irqs.
+ */
+ if (dev->msi_enabled || dev->msix_enabled)
+ goto out;
+
rc = request_irq(dev_data->irq,
xen_pcibk_guest_interrupt, IRQF_SHARED,
dev_data->irq_name, dev);
@@ -144,7 +151,12 @@ int xen_pcibk_enable_msi(struct xen_pcibk_device *pdev,
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: enable MSI\n", pci_name(dev));
- status = pci_enable_msi(dev);
+ if (dev->msi_enabled)
+ status = -EALREADY;
+ else if (dev->msix_enabled)
+ status = -ENXIO;
+ else
+ status = pci_enable_msi(dev);
if (status) {
pr_warn_ratelimited("%s: error enabling MSI for guest %u: err %d\n",
@@ -173,20 +185,23 @@ static
int xen_pcibk_disable_msi(struct xen_pcibk_device *pdev,
struct pci_dev *dev, struct xen_pci_op *op)
{
- struct xen_pcibk_dev_data *dev_data;
-
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: disable MSI\n",
pci_name(dev));
- pci_disable_msi(dev);
+ if (dev->msi_enabled) {
+ struct xen_pcibk_dev_data *dev_data;
+
+ pci_disable_msi(dev);
+
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
+ }
op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: MSI: %d\n", pci_name(dev),
op->value);
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
return 0;
}
@@ -197,13 +212,26 @@ int xen_pcibk_enable_msix(struct xen_pcibk_device *pdev,
struct xen_pcibk_dev_data *dev_data;
int i, result;
struct msix_entry *entries;
+ u16 cmd;
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: enable MSI-X\n",
pci_name(dev));
+
if (op->value > SH_INFO_MAX_VEC)
return -EINVAL;
+ if (dev->msix_enabled)
+ return -EALREADY;
+
+ /*
+ * PCI_COMMAND_MEMORY must be enabled, otherwise we may not be able
+ * to access the BARs where the MSI-X entries reside.
+ */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ if (dev->msi_enabled || !(cmd & PCI_COMMAND_MEMORY))
+ return -ENXIO;
+
entries = kmalloc(op->value * sizeof(*entries), GFP_KERNEL);
if (entries == NULL)
return -ENOMEM;
@@ -245,23 +273,27 @@ static
int xen_pcibk_disable_msix(struct xen_pcibk_device *pdev,
struct pci_dev *dev, struct xen_pci_op *op)
{
- struct xen_pcibk_dev_data *dev_data;
if (unlikely(verbose_request))
printk(KERN_DEBUG DRV_NAME ": %s: disable MSI-X\n",
pci_name(dev));
- pci_disable_msix(dev);
+ if (dev->msix_enabled) {
+ struct xen_pcibk_dev_data *dev_data;
+
+ pci_disable_msix(dev);
+
+ dev_data = pci_get_drvdata(dev);
+ if (dev_data)
+ dev_data->ack_intr = 1;
+ }
/*
* SR-IOV devices (which don't have any legacy IRQ) have
* an undefined IRQ value of zero.
*/
op->value = dev->irq ? xen_pirq_from_irq(dev->irq) : 0;
if (unlikely(verbose_request))
- printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n", pci_name(dev),
- op->value);
- dev_data = pci_get_drvdata(dev);
- if (dev_data)
- dev_data->ack_intr = 1;
+ printk(KERN_DEBUG DRV_NAME ": %s: MSI-X: %d\n",
+ pci_name(dev), op->value);
return 0;
}
#endif
@@ -298,9 +330,11 @@ void xen_pcibk_do_op(struct work_struct *data)
container_of(data, struct xen_pcibk_device, op_work);
struct pci_dev *dev;
struct xen_pcibk_dev_data *dev_data = NULL;
- struct xen_pci_op *op = &pdev->sh_info->op;
+ struct xen_pci_op *op = &pdev->op;
int test_intx = 0;
+ *op = pdev->sh_info->op;
+ barrier();
dev = xen_pcibk_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
if (dev == NULL)
@@ -342,6 +376,17 @@ void xen_pcibk_do_op(struct work_struct *data)
if ((dev_data->enable_intx != test_intx))
xen_pcibk_control_isr(dev, 0 /* no reset */);
}
+ pdev->sh_info->op.err = op->err;
+ pdev->sh_info->op.value = op->value;
+#ifdef CONFIG_PCI_MSI
+ if (op->cmd == XEN_PCI_OP_enable_msix && op->err == 0) {
+ unsigned int i;
+
+ for (i = 0; i < op->value; i++)
+ pdev->sh_info->op.msix_entries[i].vector =
+ op->msix_entries[i].vector;
+ }
+#endif
/* Tell the driver domain that we're done. */
wmb();
clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c
index 98bc345..4843741 100644
--- a/drivers/xen/xen-pciback/xenbus.c
+++ b/drivers/xen/xen-pciback/xenbus.c
@@ -44,7 +44,6 @@ static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
pdev->xdev = xdev;
- dev_set_drvdata(&xdev->dev, pdev);
mutex_init(&pdev->dev_lock);
@@ -58,6 +57,9 @@ static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev)
kfree(pdev);
pdev = NULL;
}
+
+ dev_set_drvdata(&xdev->dev, pdev);
+
out:
return pdev;
}
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index 9eeefd7..ad4eb10 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -53,7 +53,6 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include <target/target_core_fabric_configfs.h>
#include <asm/hypervisor.h>
@@ -727,7 +726,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
if (!pending_req)
return 1;
- ring_req = *RING_GET_REQUEST(ring, rc);
+ RING_COPY_REQUEST(ring, rc, &ring_req);
ring->req_cons = ++rc;
err = prepare_pending_reqs(info, &ring_req, pending_req);
@@ -1438,9 +1437,10 @@ static void scsiback_aborted_task(struct se_cmd *se_cmd)
{
}
-static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg,
+static ssize_t scsiback_tpg_param_alias_show(struct config_item *item,
char *page)
{
+ struct se_portal_group *se_tpg = param_to_tpg(item);
struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg,
se_tpg);
ssize_t rb;
@@ -1452,9 +1452,10 @@ static ssize_t scsiback_tpg_param_show_alias(struct se_portal_group *se_tpg,
return rb;
}
-static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg,
+static ssize_t scsiback_tpg_param_alias_store(struct config_item *item,
const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = param_to_tpg(item);
struct scsiback_tpg *tpg = container_of(se_tpg, struct scsiback_tpg,
se_tpg);
int len;
@@ -1474,10 +1475,10 @@ static ssize_t scsiback_tpg_param_store_alias(struct se_portal_group *se_tpg,
return count;
}
-TF_TPG_PARAM_ATTR(scsiback, alias, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(scsiback_tpg_param_, alias);
static struct configfs_attribute *scsiback_param_attrs[] = {
- &scsiback_tpg_param_alias.attr,
+ &scsiback_tpg_param_attr_alias,
NULL,
};
@@ -1585,9 +1586,9 @@ static int scsiback_drop_nexus(struct scsiback_tpg *tpg)
return 0;
}
-static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg,
- char *page)
+static ssize_t scsiback_tpg_nexus_show(struct config_item *item, char *page)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct scsiback_tpg *tpg = container_of(se_tpg,
struct scsiback_tpg, se_tpg);
struct scsiback_nexus *tv_nexus;
@@ -1606,10 +1607,10 @@ static ssize_t scsiback_tpg_show_nexus(struct se_portal_group *se_tpg,
return ret;
}
-static ssize_t scsiback_tpg_store_nexus(struct se_portal_group *se_tpg,
- const char *page,
- size_t count)
+static ssize_t scsiback_tpg_nexus_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct se_portal_group *se_tpg = to_tpg(item);
struct scsiback_tpg *tpg = container_of(se_tpg,
struct scsiback_tpg, se_tpg);
struct scsiback_tport *tport_wwn = tpg->tport;
@@ -1681,26 +1682,25 @@ check_newline:
return count;
}
-TF_TPG_BASE_ATTR(scsiback, nexus, S_IRUGO | S_IWUSR);
+CONFIGFS_ATTR(scsiback_tpg_, nexus);
static struct configfs_attribute *scsiback_tpg_attrs[] = {
- &scsiback_tpg_nexus.attr,
+ &scsiback_tpg_attr_nexus,
NULL,
};
static ssize_t
-scsiback_wwn_show_attr_version(struct target_fabric_configfs *tf,
- char *page)
+scsiback_wwn_version_show(struct config_item *item, char *page)
{
return sprintf(page, "xen-pvscsi fabric module %s on %s/%s on "
UTS_RELEASE"\n",
VSCSI_VERSION, utsname()->sysname, utsname()->machine);
}
-TF_WWN_ATTR_RO(scsiback, version);
+CONFIGFS_ATTR_RO(scsiback_wwn_, version);
static struct configfs_attribute *scsiback_wwn_attrs[] = {
- &scsiback_wwn_version.attr,
+ &scsiback_wwn_attr_version,
NULL,
};
diff --git a/drivers/xen/xenfs/xensyms.c b/drivers/xen/xenfs/xensyms.c
index f8b1285..a03f261 100644
--- a/drivers/xen/xenfs/xensyms.c
+++ b/drivers/xen/xenfs/xensyms.c
@@ -31,7 +31,7 @@ static int xensyms_next_sym(struct xensyms *xs)
symnum = symdata->symnum;
- ret = HYPERVISOR_dom0_op(&xs->op);
+ ret = HYPERVISOR_platform_op(&xs->op);
if (ret < 0)
return ret;
@@ -50,7 +50,7 @@ static int xensyms_next_sym(struct xensyms *xs)
set_xen_guest_handle(symdata->name, xs->name);
symdata->symnum--; /* Rewind */
- ret = HYPERVISOR_dom0_op(&xs->op);
+ ret = HYPERVISOR_platform_op(&xs->op);
if (ret < 0)
return ret;
}
diff --git a/firmware/WHENCE b/firmware/WHENCE
index 0c4d96d..de6f22e 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -677,7 +677,7 @@ File: av7110/bootcode.bin
Licence: GPLv2 or later
-ARM assembly source code available at http://www.linuxtv.org/downloads/firmware/Boot.S
+ARM assembly source code available at https://linuxtv.org/downloads/firmware/Boot.S
--------------------------------------------------------------------------
diff --git a/fs/9p/Makefile b/fs/9p/Makefile
index ff7be98..9619cca 100644
--- a/fs/9p/Makefile
+++ b/fs/9p/Makefile
@@ -10,10 +10,7 @@ obj-$(CONFIG_9P_FS) := 9p.o
vfs_dentry.o \
v9fs.o \
fid.o \
- xattr.o \
- xattr_user.o \
- xattr_trusted.o
+ xattr.o
9p-$(CONFIG_9P_FSCACHE) += cache.o
9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
-9p-$(CONFIG_9P_FS_SECURITY) += xattr_security.o
diff --git a/fs/9p/acl.c b/fs/9p/acl.c
index 31c0103..9da967f 100644
--- a/fs/9p/acl.c
+++ b/fs/9p/acl.c
@@ -67,8 +67,8 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
return 0;
}
/* get the default/access acl values and cache them */
- dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
- pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
+ dacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_DEFAULT);
+ pacl = __v9fs_get_acl(fid, XATTR_NAME_POSIX_ACL_ACCESS);
if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
@@ -133,10 +133,10 @@ static int v9fs_set_acl(struct p9_fid *fid, int type, struct posix_acl *acl)
goto err_free_out;
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
BUG();
@@ -212,42 +212,22 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
return 0;
}
-static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
-{
- char *full_name;
-
- switch (type) {
- case ACL_TYPE_ACCESS:
- full_name = POSIX_ACL_XATTR_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- full_name = POSIX_ACL_XATTR_DEFAULT;
- break;
- default:
- BUG();
- }
- return v9fs_xattr_get(dentry, full_name, buffer, size);
-}
-
-static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int v9fs_xattr_get_acl(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
struct v9fs_session_info *v9ses;
struct posix_acl *acl;
int error;
- if (strcmp(name, "") != 0)
- return -EINVAL;
-
v9ses = v9fs_dentry2v9ses(dentry);
/*
* We allow set/get/list of acl when access=client is not specified
*/
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
- return v9fs_remote_get_acl(dentry, name, buffer, size, type);
+ return v9fs_xattr_get(dentry, handler->name, buffer, size);
- acl = v9fs_get_cached_acl(d_inode(dentry), type);
+ acl = v9fs_get_cached_acl(d_inode(dentry), handler->flags);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
@@ -258,46 +238,23 @@ static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
return error;
}
-static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
- const void *value, size_t size,
- int flags, int type)
-{
- char *full_name;
-
- switch (type) {
- case ACL_TYPE_ACCESS:
- full_name = POSIX_ACL_XATTR_ACCESS;
- break;
- case ACL_TYPE_DEFAULT:
- full_name = POSIX_ACL_XATTR_DEFAULT;
- break;
- default:
- BUG();
- }
- return v9fs_xattr_set(dentry, full_name, value, size, flags);
-}
-
-
-static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
- const void *value, size_t size,
- int flags, int type)
+static int v9fs_xattr_set_acl(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
int retval;
struct posix_acl *acl;
struct v9fs_session_info *v9ses;
struct inode *inode = d_inode(dentry);
- if (strcmp(name, "") != 0)
- return -EINVAL;
-
v9ses = v9fs_dentry2v9ses(dentry);
/*
* set the attribute on the remote. Without even looking at the
* xattr value. We leave it to the server to validate
*/
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
- return v9fs_remote_set_acl(dentry, name,
- value, size, flags, type);
+ return v9fs_xattr_set(dentry, handler->name, value, size,
+ flags);
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
@@ -316,9 +273,8 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
} else
acl = NULL;
- switch (type) {
+ switch (handler->flags) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
if (acl) {
umode_t mode = inode->i_mode;
retval = posix_acl_equiv_mode(acl, &mode);
@@ -349,7 +305,6 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
}
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
if (!S_ISDIR(inode->i_mode)) {
retval = acl ? -EINVAL : 0;
goto err_out;
@@ -358,23 +313,23 @@ static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
default:
BUG();
}
- retval = v9fs_xattr_set(dentry, name, value, size, flags);
+ retval = v9fs_xattr_set(dentry, handler->name, value, size, flags);
if (!retval)
- set_cached_acl(inode, type, acl);
+ set_cached_acl(inode, handler->flags, acl);
err_out:
posix_acl_release(acl);
return retval;
}
const struct xattr_handler v9fs_xattr_acl_access_handler = {
- .prefix = POSIX_ACL_XATTR_ACCESS,
+ .name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.get = v9fs_xattr_get_acl,
.set = v9fs_xattr_set_acl,
};
const struct xattr_handler v9fs_xattr_acl_default_handler = {
- .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.get = v9fs_xattr_get_acl,
.set = v9fs_xattr_set_acl,
diff --git a/fs/9p/cache.c b/fs/9p/cache.c
index a69260f..103ca5e 100644
--- a/fs/9p/cache.c
+++ b/fs/9p/cache.c
@@ -243,14 +243,14 @@ void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp)
if (!v9inode->fscache)
return;
- spin_lock(&v9inode->fscache_lock);
+ mutex_lock(&v9inode->fscache_lock);
if ((filp->f_flags & O_ACCMODE) != O_RDONLY)
v9fs_cache_inode_flush_cookie(inode);
else
v9fs_cache_inode_get_cookie(inode);
- spin_unlock(&v9inode->fscache_lock);
+ mutex_unlock(&v9inode->fscache_lock);
}
void v9fs_cache_inode_reset_cookie(struct inode *inode)
@@ -264,7 +264,7 @@ void v9fs_cache_inode_reset_cookie(struct inode *inode)
old = v9inode->fscache;
- spin_lock(&v9inode->fscache_lock);
+ mutex_lock(&v9inode->fscache_lock);
fscache_relinquish_cookie(v9inode->fscache, 1);
v9ses = v9fs_inode2v9ses(inode);
@@ -274,7 +274,7 @@ void v9fs_cache_inode_reset_cookie(struct inode *inode)
p9_debug(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p\n",
inode, old, v9inode->fscache);
- spin_unlock(&v9inode->fscache_lock);
+ mutex_unlock(&v9inode->fscache_lock);
}
int __v9fs_fscache_release_page(struct page *page, gfp_t gfp)
diff --git a/fs/9p/cache.h b/fs/9p/cache.h
index 2f96754..247e47e 100644
--- a/fs/9p/cache.h
+++ b/fs/9p/cache.h
@@ -21,6 +21,7 @@
*/
#ifndef _9P_CACHE_H
+#define _9P_CACHE_H
#ifdef CONFIG_9P_FSCACHE
#include <linux/fscache.h>
#include <linux/spinlock.h>
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h
index 0923f2c..6877050 100644
--- a/fs/9p/v9fs.h
+++ b/fs/9p/v9fs.h
@@ -123,7 +123,7 @@ struct v9fs_session_info {
struct v9fs_inode {
#ifdef CONFIG_9P_FSCACHE
- spinlock_t fscache_lock;
+ struct mutex fscache_lock;
struct fscache_cookie *fscache;
#endif
struct p9_qid qid;
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 699941e..3a08b3e 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -244,7 +244,7 @@ struct inode *v9fs_alloc_inode(struct super_block *sb)
return NULL;
#ifdef CONFIG_9P_FSCACHE
v9inode->fscache = NULL;
- spin_lock_init(&v9inode->fscache_lock);
+ mutex_init(&v9inode->fscache_lock);
#endif
v9inode->writeback_fid = NULL;
v9inode->cache_validity = 0;
@@ -451,9 +451,9 @@ void v9fs_evict_inode(struct inode *inode)
{
struct v9fs_inode *v9inode = V9FS_I(inode);
- truncate_inode_pages_final(inode->i_mapping);
+ truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
- filemap_fdatawrite(inode->i_mapping);
+ filemap_fdatawrite(&inode->i_data);
v9fs_cache_inode_put_cookie(inode);
/* clunk the fid stashed in writeback_fid */
@@ -1223,18 +1223,26 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
}
/**
- * v9fs_vfs_follow_link - follow a symlink path
+ * v9fs_vfs_get_link - follow a symlink path
* @dentry: dentry for symlink
- * @cookie: place to pass the data to put_link()
+ * @inode: inode for symlink
+ * @done: delayed call for when we are done with the return value
*/
-static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *v9fs_vfs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
- struct p9_fid *fid = v9fs_fid_lookup(dentry);
+ struct v9fs_session_info *v9ses;
+ struct p9_fid *fid;
struct p9_wstat *st;
char *res;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ v9ses = v9fs_dentry2v9ses(dentry);
+ fid = v9fs_fid_lookup(dentry);
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
if (IS_ERR(fid))
@@ -1259,7 +1267,8 @@ static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
p9stat_free(st);
kfree(st);
- return *cookie = res;
+ set_delayed_call(done, kfree_link, res);
+ return res;
}
/**
@@ -1452,8 +1461,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
static const struct inode_operations v9fs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = v9fs_vfs_follow_link,
- .put_link = kfree_put_link,
+ .get_link = v9fs_vfs_get_link,
.getattr = v9fs_vfs_getattr,
.setattr = v9fs_vfs_setattr,
};
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index cb899af..a34702c 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -899,26 +899,34 @@ error:
}
/**
- * v9fs_vfs_follow_link_dotl - follow a symlink path
+ * v9fs_vfs_get_link_dotl - follow a symlink path
* @dentry: dentry for symlink
- * @cookie: place to pass the data to put_link()
+ * @inode: inode for symlink
+ * @done: destructor for return value
*/
static const char *
-v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie)
+v9fs_vfs_get_link_dotl(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct p9_fid *fid = v9fs_fid_lookup(dentry);
+ struct p9_fid *fid;
char *target;
int retval;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
+ fid = v9fs_fid_lookup(dentry);
if (IS_ERR(fid))
return ERR_CAST(fid);
retval = p9_client_readlink(fid, &target);
if (retval)
return ERR_PTR(retval);
- return *cookie = target;
+ set_delayed_call(done, kfree_link, target);
+ return target;
}
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
@@ -984,8 +992,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
.readlink = generic_readlink,
- .follow_link = v9fs_vfs_follow_link_dotl,
- .put_link = kfree_put_link,
+ .get_link = v9fs_vfs_get_link_dotl,
.getattr = v9fs_vfs_getattr_dotl,
.setattr = v9fs_vfs_setattr_dotl,
.setxattr = generic_setxattr,
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c
index 0cf44b6..9dd9b47 100644
--- a/fs/9p/xattr.c
+++ b/fs/9p/xattr.c
@@ -137,6 +137,44 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
}
+static int v9fs_xattr_handler_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ const char *full_name = xattr_full_name(handler, name);
+
+ return v9fs_xattr_get(dentry, full_name, buffer, size);
+}
+
+static int v9fs_xattr_handler_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ const char *full_name = xattr_full_name(handler, name);
+
+ return v9fs_xattr_set(dentry, full_name, value, size, flags);
+}
+
+static struct xattr_handler v9fs_xattr_user_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .get = v9fs_xattr_handler_get,
+ .set = v9fs_xattr_handler_set,
+};
+
+static struct xattr_handler v9fs_xattr_trusted_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .get = v9fs_xattr_handler_get,
+ .set = v9fs_xattr_handler_set,
+};
+
+#ifdef CONFIG_9P_FS_SECURITY
+static struct xattr_handler v9fs_xattr_security_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .get = v9fs_xattr_handler_get,
+ .set = v9fs_xattr_handler_set,
+};
+#endif
+
const struct xattr_handler *v9fs_xattr_handlers[] = {
&v9fs_xattr_user_handler,
&v9fs_xattr_trusted_handler,
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h
index d3e2ea3..c63c3be 100644
--- a/fs/9p/xattr.h
+++ b/fs/9p/xattr.h
@@ -19,9 +19,6 @@
#include <net/9p/client.h>
extern const struct xattr_handler *v9fs_xattr_handlers[];
-extern struct xattr_handler v9fs_xattr_user_handler;
-extern struct xattr_handler v9fs_xattr_trusted_handler;
-extern struct xattr_handler v9fs_xattr_security_handler;
extern const struct xattr_handler v9fs_xattr_acl_access_handler;
extern const struct xattr_handler v9fs_xattr_acl_default_handler;
diff --git a/fs/9p/xattr_security.c b/fs/9p/xattr_security.c
deleted file mode 100644
index cb247a1..0000000
--- a/fs/9p/xattr_security.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright IBM Corporation, 2010
- * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2.1 of the GNU Lesser General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include "xattr.h"
-
-static int v9fs_xattr_security_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(full_name+prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_get(dentry, full_name, buffer, size);
- kfree(full_name);
- return retval;
-}
-
-static int v9fs_xattr_security_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(full_name + prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
- kfree(full_name);
- return retval;
-}
-
-struct xattr_handler v9fs_xattr_security_handler = {
- .prefix = XATTR_SECURITY_PREFIX,
- .get = v9fs_xattr_security_get,
- .set = v9fs_xattr_security_set,
-};
diff --git a/fs/9p/xattr_trusted.c b/fs/9p/xattr_trusted.c
deleted file mode 100644
index e30d33b..0000000
--- a/fs/9p/xattr_trusted.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright IBM Corporation, 2010
- * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2.1 of the GNU Lesser General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include "xattr.h"
-
-static int v9fs_xattr_trusted_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_TRUSTED_PREFIX, prefix_len);
- memcpy(full_name+prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_get(dentry, full_name, buffer, size);
- kfree(full_name);
- return retval;
-}
-
-static int v9fs_xattr_trusted_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_TRUSTED_PREFIX, prefix_len);
- memcpy(full_name + prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
- kfree(full_name);
- return retval;
-}
-
-struct xattr_handler v9fs_xattr_trusted_handler = {
- .prefix = XATTR_TRUSTED_PREFIX,
- .get = v9fs_xattr_trusted_get,
- .set = v9fs_xattr_trusted_set,
-};
diff --git a/fs/9p/xattr_user.c b/fs/9p/xattr_user.c
deleted file mode 100644
index d0b701b..0000000
--- a/fs/9p/xattr_user.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright IBM Corporation, 2010
- * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2.1 of the GNU Lesser General Public License
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- */
-
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include "xattr.h"
-
-static int v9fs_xattr_user_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_USER_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
- memcpy(full_name+prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_get(dentry, full_name, buffer, size);
- kfree(full_name);
- return retval;
-}
-
-static int v9fs_xattr_user_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
-{
- int retval;
- char *full_name;
- size_t name_len;
- size_t prefix_len = XATTR_USER_PREFIX_LEN;
-
- if (name == NULL)
- return -EINVAL;
-
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- name_len = strlen(name);
- full_name = kmalloc(prefix_len + name_len + 1 , GFP_KERNEL);
- if (!full_name)
- return -ENOMEM;
- memcpy(full_name, XATTR_USER_PREFIX, prefix_len);
- memcpy(full_name + prefix_len, name, name_len);
- full_name[prefix_len + name_len] = '\0';
-
- retval = v9fs_xattr_set(dentry, full_name, value, size, flags);
- kfree(full_name);
- return retval;
-}
-
-struct xattr_handler v9fs_xattr_user_handler = {
- .prefix = XATTR_USER_PREFIX,
- .get = v9fs_xattr_user_get,
- .set = v9fs_xattr_user_set,
-};
diff --git a/fs/Kconfig b/fs/Kconfig
index da3f32f..2bb1ef8 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -46,6 +46,12 @@ config FS_DAX
or if unsure, say N. Saying Y will increase the size of the kernel
by about 5kB.
+config FS_DAX_PMD
+ bool
+ default FS_DAX
+ depends on FS_DAX
+ depends on BROKEN
+
endif # BLOCK
# Posix ACL utility routines
@@ -67,6 +73,16 @@ config FILE_LOCKING
for filesystems like NFS and for the flock() system
call. Disabling this option saves about 11k.
+config MANDATORY_FILE_LOCKING
+ bool "Enable Mandatory file locking"
+ depends on FILE_LOCKING
+ default y
+ help
+ This option enables files appropriately marked files on appropriely
+ mounted filesystems to support mandatory locking.
+
+ To the best of my knowledge this is dead code that no one cares about.
+
source "fs/notify/Kconfig"
source "fs/quota/Kconfig"
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 24575d9..ea4aba5 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -45,7 +45,7 @@ struct adfs_dir_ops;
struct adfs_sb_info {
union { struct {
struct adfs_discmap *s_map; /* bh list containing map */
- struct adfs_dir_ops *s_dir; /* directory operations */
+ const struct adfs_dir_ops *s_dir; /* directory operations */
};
struct rcu_head rcu; /* used only at shutdown time */
};
@@ -168,8 +168,8 @@ void __adfs_error(struct super_block *sb, const char *function,
extern const struct inode_operations adfs_dir_inode_operations;
extern const struct file_operations adfs_dir_operations;
extern const struct dentry_operations adfs_dentry_operations;
-extern struct adfs_dir_ops adfs_f_dir_ops;
-extern struct adfs_dir_ops adfs_fplus_dir_ops;
+extern const struct adfs_dir_ops adfs_f_dir_ops;
+extern const struct adfs_dir_ops adfs_fplus_dir_ops;
extern int adfs_dir_update(struct super_block *sb, struct object_info *obj,
int wait);
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c
index 51c279a..fd4cf2c 100644
--- a/fs/adfs/dir.c
+++ b/fs/adfs/dir.c
@@ -21,7 +21,7 @@ adfs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
struct super_block *sb = inode->i_sb;
- struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
+ const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct object_info obj;
struct adfs_dir dir;
int ret = 0;
@@ -69,7 +69,7 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
{
int ret = -EINVAL;
#ifdef CONFIG_ADFS_FS_RW
- struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
+ const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct adfs_dir dir;
printk(KERN_INFO "adfs_dir_update: object %06X in dir %06X\n",
@@ -129,7 +129,7 @@ static int
adfs_dir_lookup_byname(struct inode *inode, struct qstr *name, struct object_info *obj)
{
struct super_block *sb = inode->i_sb;
- struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
+ const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
struct adfs_dir dir;
int ret;
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index 4bbe853..0fbfd0b 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -476,7 +476,7 @@ adfs_f_free(struct adfs_dir *dir)
dir->sb = NULL;
}
-struct adfs_dir_ops adfs_f_dir_ops = {
+const struct adfs_dir_ops adfs_f_dir_ops = {
.read = adfs_f_read,
.setpos = adfs_f_setpos,
.getnext = adfs_f_getnext,
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c
index 82d14cd..c92cfb6 100644
--- a/fs/adfs/dir_fplus.c
+++ b/fs/adfs/dir_fplus.c
@@ -256,7 +256,7 @@ adfs_fplus_free(struct adfs_dir *dir)
dir->sb = NULL;
}
-struct adfs_dir_ops adfs_fplus_dir_ops = {
+const struct adfs_dir_ops adfs_fplus_dir_ops = {
.read = adfs_fplus_read,
.setpos = adfs_fplus_setpos,
.getnext = adfs_fplus_getnext,
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index c69a87e..cc2b2ef 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -138,7 +138,7 @@ extern int affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh);
extern int affs_remove_header(struct dentry *dentry);
extern u32 affs_checksum_block(struct super_block *sb, struct buffer_head *bh);
extern void affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);
-extern void secs_to_datestamp(time_t secs, struct affs_date *ds);
+extern void secs_to_datestamp(time64_t secs, struct affs_date *ds);
extern umode_t prot_to_mode(u32 prot);
extern void mode_to_prot(struct inode *inode);
__printf(3, 4)
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index 5fa92bc..d6c7a51 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -8,6 +8,7 @@
* Please send bug reports to: hjw@zvw.de
*/
+#include <linux/math64.h>
#include "affs.h"
/*
@@ -366,22 +367,22 @@ affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
}
void
-secs_to_datestamp(time_t secs, struct affs_date *ds)
+secs_to_datestamp(time64_t secs, struct affs_date *ds)
{
u32 days;
u32 minute;
+ s32 rem;
secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
if (secs < 0)
secs = 0;
- days = secs / 86400;
- secs -= days * 86400;
- minute = secs / 60;
- secs -= minute * 60;
+ days = div_s64_rem(secs, 86400, &rem);
+ minute = rem / 60;
+ rem -= minute * 60;
ds->days = cpu_to_be32(days);
ds->mins = cpu_to_be32(minute);
- ds->ticks = cpu_to_be32(secs * 50);
+ ds->ticks = cpu_to_be32(rem * 50);
}
umode_t
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 1734950..0fdb0f5 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -140,6 +140,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
break;
case ST_SOFTLINK:
inode->i_mode |= S_IFLNK;
+ inode_nohighmem(inode);
inode->i_op = &affs_symlink_inode_operations;
inode->i_data.a_ops = &affs_symlink_aops;
break;
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 181e05b..00d3002 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -344,6 +344,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
return -ENOSPC;
inode->i_op = &affs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &affs_symlink_aops;
inode->i_mode = S_IFLNK | 0777;
mode_to_prot(inode);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 5b50c4c..8836df5 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -32,7 +32,7 @@ affs_commit_super(struct super_block *sb, int wait)
struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh);
lock_buffer(bh);
- secs_to_datestamp(get_seconds(), &tail->disk_change);
+ secs_to_datestamp(ktime_get_real_seconds(), &tail->disk_change);
affs_fix_checksum(sb, bh);
unlock_buffer(bh);
diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c
index ea5b69a..69b03db 100644
--- a/fs/affs/symlink.c
+++ b/fs/affs/symlink.c
@@ -14,13 +14,13 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
{
struct buffer_head *bh;
struct inode *inode = page->mapping->host;
- char *link = kmap(page);
+ char *link = page_address(page);
struct slink_front *lf;
int i, j;
char c;
char lc;
- pr_debug("follow_link(ino=%lu)\n", inode->i_ino);
+ pr_debug("get_link(ino=%lu)\n", inode->i_ino);
bh = affs_bread(inode->i_sb, inode->i_ino);
if (!bh)
@@ -57,12 +57,10 @@ static int affs_symlink_readpage(struct file *file, struct page *page)
link[i] = '\0';
affs_brelse(bh);
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
fail:
SetPageError(page);
- kunmap(page);
unlock_page(page);
return -EIO;
}
@@ -73,7 +71,6 @@ const struct address_space_operations affs_symlink_aops = {
const struct inode_operations affs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = affs_notify_change,
};
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index e06f5a2..86cc726 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -56,6 +56,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
case AFS_FTYPE_SYMLINK:
inode->i_mode = S_IFLNK | vnode->status.mode;
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
break;
default:
printk("kAFS: AFS vnode with undefined type\n");
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 24a905b..2853b40 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -230,14 +230,9 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf,
if (size <= 1 || size >= PAGE_SIZE)
return -EINVAL;
- kbuf = kmalloc(size + 1, GFP_KERNEL);
- if (!kbuf)
- return -ENOMEM;
-
- ret = -EFAULT;
- if (copy_from_user(kbuf, buf, size) != 0)
- goto done;
- kbuf[size] = 0;
+ kbuf = memdup_user_nul(buf, size);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
/* trim to first NL */
name = memchr(kbuf, '\n', size);
@@ -315,15 +310,9 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
if (size <= 1 || size >= PAGE_SIZE)
return -EINVAL;
- ret = -ENOMEM;
- kbuf = kmalloc(size + 1, GFP_KERNEL);
- if (!kbuf)
- goto nomem;
-
- ret = -EFAULT;
- if (copy_from_user(kbuf, buf, size) != 0)
- goto infault;
- kbuf[size] = 0;
+ kbuf = memdup_user_nul(buf, size);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
/* trim to first NL */
s = memchr(kbuf, '\n', size);
@@ -337,9 +326,7 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
if (ret >= 0)
ret = size; /* consume everything, always */
-infault:
kfree(kbuf);
-nomem:
_leave(" = %d", ret);
return ret;
}
diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c
index da0c334..84e037d 100644
--- a/fs/autofs4/symlink.c
+++ b/fs/autofs4/symlink.c
@@ -12,10 +12,16 @@
#include "autofs_i.h"
-static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
+static const char *autofs4_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
+ struct autofs_sb_info *sbi;
+ struct autofs_info *ino;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+ sbi = autofs4_sbi(dentry->d_sb);
+ ino = autofs4_dentry_ino(dentry);
if (ino && !autofs4_oz_mode(sbi))
ino->last_used = jiffies;
return d_inode(dentry)->i_private;
@@ -23,5 +29,5 @@ static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
const struct inode_operations autofs4_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = autofs4_follow_link
+ .get_link = autofs4_get_link
};
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 861b1e1..103f5d7 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -192,7 +192,7 @@ EXPORT_SYMBOL(make_bad_inode);
* Returns true if the inode in question has been marked as bad.
*/
-int is_bad_inode(struct inode *inode)
+bool is_bad_inode(struct inode *inode)
{
return (inode->i_op == &bad_inode_ops);
}
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 46aedac..25250fa 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -42,7 +42,7 @@ static struct inode *befs_iget(struct super_block *, unsigned long);
static struct inode *befs_alloc_inode(struct super_block *sb);
static void befs_destroy_inode(struct inode *inode);
static void befs_destroy_inodecache(void);
-static const char *befs_follow_link(struct dentry *, void **);
+static int befs_symlink_readpage(struct file *, struct page *);
static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
char **out, int *out_len);
static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
@@ -79,10 +79,8 @@ static const struct address_space_operations befs_aops = {
.bmap = befs_bmap,
};
-static const struct inode_operations befs_symlink_inode_operations = {
- .readlink = generic_readlink,
- .follow_link = befs_follow_link,
- .put_link = kfree_put_link,
+static const struct address_space_operations befs_symlink_aops = {
+ .readpage = befs_symlink_readpage,
};
/*
@@ -398,7 +396,9 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
inode->i_fop = &befs_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
- inode->i_op = &befs_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
+ inode->i_mapping->a_ops = &befs_symlink_aops;
} else {
inode->i_link = befs_ino->i_data.symlink;
inode->i_op = &simple_symlink_inode_operations;
@@ -463,31 +463,33 @@ befs_destroy_inodecache(void)
* The data stream become link name. Unless the LONG_SYMLINK
* flag is set.
*/
-static const char *
-befs_follow_link(struct dentry *dentry, void **cookie)
+static int befs_symlink_readpage(struct file *unused, struct page *page)
{
- struct super_block *sb = dentry->d_sb;
- struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
+ struct inode *inode = page->mapping->host;
+ struct super_block *sb = inode->i_sb;
+ struct befs_inode_info *befs_ino = BEFS_I(inode);
befs_data_stream *data = &befs_ino->i_data.ds;
befs_off_t len = data->size;
- char *link;
+ char *link = page_address(page);
- if (len == 0) {
+ if (len == 0 || len > PAGE_SIZE) {
befs_error(sb, "Long symlink with illegal length");
- return ERR_PTR(-EIO);
+ goto fail;
}
befs_debug(sb, "Follow long symlink");
- link = kmalloc(len, GFP_NOFS);
- if (!link)
- return ERR_PTR(-ENOMEM);
if (befs_read_lsymlink(sb, data, link, len) != len) {
- kfree(link);
befs_error(sb, "Failed to read entire long symlink");
- return ERR_PTR(-EIO);
+ goto fail;
}
link[len - 1] = '\0';
- return *cookie = link;
+ SetPageUptodate(page);
+ unlock_page(page);
+ return 0;
+fail:
+ SetPageError(page);
+ unlock_page(page);
+ return -EIO;
}
/*
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 6b65996..3a93755 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -35,6 +35,7 @@
#include <linux/utsname.h>
#include <linux/coredump.h>
#include <linux/sched.h>
+#include <linux/dax.h>
#include <asm/uaccess.h>
#include <asm/param.h>
#include <asm/page.h>
@@ -487,7 +488,7 @@ static inline int arch_elf_pt_proc(struct elfhdr *ehdr,
}
/**
- * arch_check_elf() - check a PT_LOPROC..PT_HIPROC ELF program header
+ * arch_check_elf() - check an ELF executable
* @ehdr: The main ELF header
* @has_interp: True if the ELF has an interpreter, else false.
* @state: Architecture-specific state preserved throughout the process
@@ -759,16 +760,16 @@ static int load_elf_binary(struct linux_binprm *bprm)
*/
would_dump(bprm, interpreter);
- retval = kernel_read(interpreter, 0, bprm->buf,
- BINPRM_BUF_SIZE);
- if (retval != BINPRM_BUF_SIZE) {
+ /* Get the exec headers */
+ retval = kernel_read(interpreter, 0,
+ (void *)&loc->interp_elf_ex,
+ sizeof(loc->interp_elf_ex));
+ if (retval != sizeof(loc->interp_elf_ex)) {
if (retval >= 0)
retval = -EIO;
goto out_free_dentry;
}
- /* Get the exec headers */
- loc->interp_elf_ex = *((struct elfhdr *)bprm->buf);
break;
}
elf_ppnt++;
@@ -1236,6 +1237,15 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
if (vma->vm_flags & VM_DONTDUMP)
return 0;
+ /* support for DAX */
+ if (vma_is_dax(vma)) {
+ if ((vma->vm_flags & VM_SHARED) && FILTER(DAX_SHARED))
+ goto whole;
+ if (!(vma->vm_flags & VM_SHARED) && FILTER(DAX_PRIVATE))
+ goto whole;
+ return 0;
+ }
+
/* Hugetlb memory check */
if (vma->vm_flags & VM_HUGETLB) {
if ((vma->vm_flags & VM_SHARED) && FILTER(HUGETLB_SHARED))
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 50d15b7..b1adb92 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -35,6 +35,7 @@
#include <linux/elf-fdpic.h>
#include <linux/elfcore.h>
#include <linux/coredump.h>
+#include <linux/dax.h>
#include <asm/uaccess.h>
#include <asm/param.h>
@@ -1231,6 +1232,20 @@ static int maydump(struct vm_area_struct *vma, unsigned long mm_flags)
return 0;
}
+ /* support for DAX */
+ if (vma_is_dax(vma)) {
+ if (vma->vm_flags & VM_SHARED) {
+ dump_ok = test_bit(MMF_DUMP_DAX_SHARED, &mm_flags);
+ kdcore("%08lx: %08lx: %s (DAX shared)", vma->vm_start,
+ vma->vm_flags, dump_ok ? "yes" : "no");
+ } else {
+ dump_ok = test_bit(MMF_DUMP_DAX_PRIVATE, &mm_flags);
+ kdcore("%08lx: %08lx: %s (DAX private)", vma->vm_start,
+ vma->vm_flags, dump_ok ? "yes" : "no");
+ }
+ return dump_ok;
+ }
+
/* By default, dump shared memory if mapped from an anonymous file. */
if (vma->vm_flags & VM_SHARED) {
if (file_inode(vma->vm_file)->i_nlink == 0) {
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 0a793c7..01b8e0d 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -50,12 +50,21 @@ struct block_device *I_BDEV(struct inode *inode)
}
EXPORT_SYMBOL(I_BDEV);
-static void bdev_write_inode(struct inode *inode)
+static void bdev_write_inode(struct block_device *bdev)
{
+ struct inode *inode = bdev->bd_inode;
+ int ret;
+
spin_lock(&inode->i_lock);
while (inode->i_state & I_DIRTY) {
spin_unlock(&inode->i_lock);
- WARN_ON_ONCE(write_inode_now(inode, true));
+ ret = write_inode_now(inode, true);
+ if (ret) {
+ char name[BDEVNAME_SIZE];
+ pr_warn_ratelimited("VFS: Dirty inode writeback failed "
+ "for block device %s (err=%d).\n",
+ bdevname(bdev, name), ret);
+ }
spin_lock(&inode->i_lock);
}
spin_unlock(&inode->i_lock);
@@ -381,9 +390,17 @@ int bdev_read_page(struct block_device *bdev, sector_t sector,
struct page *page)
{
const struct block_device_operations *ops = bdev->bd_disk->fops;
+ int result = -EOPNOTSUPP;
+
if (!ops->rw_page || bdev_get_integrity(bdev))
- return -EOPNOTSUPP;
- return ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
+ return result;
+
+ result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+ if (result)
+ return result;
+ result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, READ);
+ blk_queue_exit(bdev->bd_queue);
+ return result;
}
EXPORT_SYMBOL_GPL(bdev_read_page);
@@ -412,14 +429,20 @@ int bdev_write_page(struct block_device *bdev, sector_t sector,
int result;
int rw = (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : WRITE;
const struct block_device_operations *ops = bdev->bd_disk->fops;
+
if (!ops->rw_page || bdev_get_integrity(bdev))
return -EOPNOTSUPP;
+ result = blk_queue_enter(bdev->bd_queue, GFP_KERNEL);
+ if (result)
+ return result;
+
set_page_writeback(page);
result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, rw);
if (result)
end_page_writeback(page);
else
unlock_page(page);
+ blk_queue_exit(bdev->bd_queue);
return result;
}
EXPORT_SYMBOL_GPL(bdev_write_page);
@@ -1019,12 +1042,9 @@ EXPORT_SYMBOL_GPL(bd_unlink_disk_holder);
static void flush_disk(struct block_device *bdev, bool kill_dirty)
{
if (__invalidate_device(bdev, kill_dirty)) {
- char name[BDEVNAME_SIZE] = "";
-
- if (bdev->bd_disk)
- disk_name(bdev->bd_disk, 0, name);
printk(KERN_WARNING "VFS: busy inodes on changed media or "
- "resized disk %s\n", name);
+ "resized disk %s\n",
+ bdev->bd_disk ? bdev->bd_disk->disk_name : "");
}
if (!bdev->bd_disk)
@@ -1048,12 +1068,9 @@ void check_disk_size_change(struct gendisk *disk, struct block_device *bdev)
disk_size = (loff_t)get_capacity(disk) << 9;
bdev_size = i_size_read(bdev->bd_inode);
if (disk_size != bdev_size) {
- char name[BDEVNAME_SIZE];
-
- disk_name(disk, 0, name);
printk(KERN_INFO
"%s: detected capacity change from %lld to %lld\n",
- name, bdev_size, disk_size);
+ disk->disk_name, bdev_size, disk_size);
i_size_write(bdev->bd_inode, disk_size);
flush_disk(bdev, false);
}
@@ -1500,11 +1517,14 @@ static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part)
WARN_ON_ONCE(bdev->bd_holders);
sync_blockdev(bdev);
kill_bdev(bdev);
+
+ bdev_write_inode(bdev);
/*
- * ->release can cause the queue to disappear, so flush all
- * dirty data before.
+ * Detaching bdev inode from its wb in __destroy_inode()
+ * is too late: the queue which embeds its bdi (along with
+ * root wb) can be gone as soon as we put_disk() below.
*/
- bdev_write_inode(bdev->bd_inode);
+ inode_detach_wb(bdev->bd_inode);
}
if (bdev->bd_contains == bdev) {
if (disk->fops->release)
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 9a0124a..f89db0c 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -37,10 +37,10 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
BUG();
@@ -81,7 +81,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
ret = posix_acl_equiv_mode(acl, &inode->i_mode);
if (ret < 0)
@@ -94,7 +94,7 @@ static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
case ACL_TYPE_DEFAULT:
if (!S_ISDIR(inode->i_mode))
return acl ? -EINVAL : 0;
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
return -EINVAL;
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 6dcdb2e..d453d62 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -355,7 +355,7 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
index = srcu_read_lock(&fs_info->subvol_srcu);
- root = btrfs_read_fs_root_no_name(fs_info, &root_key);
+ root = btrfs_get_fs_root(fs_info, &root_key, false);
if (IS_ERR(root)) {
srcu_read_unlock(&fs_info->subvol_srcu, index);
ret = PTR_ERR(root);
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 8c58191..b7e4e34 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3416,6 +3416,7 @@ int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans,
struct btrfs_block_group_cache *btrfs_lookup_block_group(
struct btrfs_fs_info *info,
u64 bytenr);
+void btrfs_get_block_group(struct btrfs_block_group_cache *cache);
void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
int get_block_group_index(struct btrfs_block_group_cache *cache);
struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans,
@@ -3479,6 +3480,9 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 bytes_used,
u64 type, u64 chunk_objectid, u64 chunk_offset,
u64 size);
+struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(
+ struct btrfs_fs_info *fs_info,
+ const u64 chunk_offset);
int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
struct btrfs_root *root, u64 group_start,
struct extent_map *em);
@@ -4020,7 +4024,8 @@ void btrfs_get_block_group_info(struct list_head *groups_list,
struct btrfs_ioctl_space_info *space);
void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock,
struct btrfs_ioctl_balance_args *bargs);
-
+ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
+ struct file *dst_file, u64 dst_loff);
/* file.c */
int btrfs_auto_defrag_init(void);
@@ -4051,6 +4056,11 @@ int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode,
loff_t pos, size_t write_bytes,
struct extent_state **cached);
int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end);
+ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out,
+ size_t len, unsigned int flags);
+int btrfs_clone_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out, u64 len);
/* tree-defrag.c */
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 640598c..42a378a 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -923,7 +923,7 @@ static int check_async_write(struct inode *inode, unsigned long bio_flags)
if (bio_flags & EXTENT_BIO_TREE_LOG)
return 0;
#ifdef CONFIG_X86
- if (cpu_has_xmm4_2)
+ if (static_cpu_has_safe(X86_FEATURE_XMM4_2))
return 0;
#endif
return 1;
@@ -3780,6 +3780,9 @@ void close_ctree(struct btrfs_root *root)
fs_info->closing = 1;
smp_mb();
+ /* wait for the qgroup rescan worker to stop */
+ btrfs_qgroup_wait_for_completion(fs_info);
+
/* wait for the uuid_scan task to finish */
down(&fs_info->uuid_tree_rescan_sem);
/* avoid complains from lockdep et al., set sem back to initial state */
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 99a8e57..c4661db 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -124,7 +124,7 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
return (cache->flags & bits) == bits;
}
-static void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
+void btrfs_get_block_group(struct btrfs_block_group_cache *cache)
{
atomic_inc(&cache->count);
}
@@ -5915,19 +5915,6 @@ static int update_block_group(struct btrfs_trans_handle *trans,
set_extent_dirty(info->pinned_extents,
bytenr, bytenr + num_bytes - 1,
GFP_NOFS | __GFP_NOFAIL);
- /*
- * No longer have used bytes in this block group, queue
- * it for deletion.
- */
- if (old_val == 0) {
- spin_lock(&info->unused_bgs_lock);
- if (list_empty(&cache->bg_list)) {
- btrfs_get_block_group(cache);
- list_add_tail(&cache->bg_list,
- &info->unused_bgs);
- }
- spin_unlock(&info->unused_bgs_lock);
- }
}
spin_lock(&trans->transaction->dirty_bgs_lock);
@@ -5939,6 +5926,22 @@ static int update_block_group(struct btrfs_trans_handle *trans,
}
spin_unlock(&trans->transaction->dirty_bgs_lock);
+ /*
+ * No longer have used bytes in this block group, queue it for
+ * deletion. We do this after adding the block group to the
+ * dirty list to avoid races between cleaner kthread and space
+ * cache writeout.
+ */
+ if (!alloc && old_val == 0) {
+ spin_lock(&info->unused_bgs_lock);
+ if (list_empty(&cache->bg_list)) {
+ btrfs_get_block_group(cache);
+ list_add_tail(&cache->bg_list,
+ &info->unused_bgs);
+ }
+ spin_unlock(&info->unused_bgs_lock);
+ }
+
btrfs_put_block_group(cache);
total -= num_bytes;
bytenr += num_bytes;
@@ -8105,21 +8108,47 @@ reada:
}
/*
- * TODO: Modify related function to add related node/leaf to dirty_extent_root,
- * for later qgroup accounting.
- *
- * Current, this function does nothing.
+ * These may not be seen by the usual inc/dec ref code so we have to
+ * add them here.
*/
+static int record_one_subtree_extent(struct btrfs_trans_handle *trans,
+ struct btrfs_root *root, u64 bytenr,
+ u64 num_bytes)
+{
+ struct btrfs_qgroup_extent_record *qrecord;
+ struct btrfs_delayed_ref_root *delayed_refs;
+
+ qrecord = kmalloc(sizeof(*qrecord), GFP_NOFS);
+ if (!qrecord)
+ return -ENOMEM;
+
+ qrecord->bytenr = bytenr;
+ qrecord->num_bytes = num_bytes;
+ qrecord->old_roots = NULL;
+
+ delayed_refs = &trans->transaction->delayed_refs;
+ spin_lock(&delayed_refs->lock);
+ if (btrfs_qgroup_insert_dirty_extent(delayed_refs, qrecord))
+ kfree(qrecord);
+ spin_unlock(&delayed_refs->lock);
+
+ return 0;
+}
+
static int account_leaf_items(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct extent_buffer *eb)
{
int nr = btrfs_header_nritems(eb);
- int i, extent_type;
+ int i, extent_type, ret;
struct btrfs_key key;
struct btrfs_file_extent_item *fi;
u64 bytenr, num_bytes;
+ /* We can be called directly from walk_up_proc() */
+ if (!root->fs_info->quota_enabled)
+ return 0;
+
for (i = 0; i < nr; i++) {
btrfs_item_key_to_cpu(eb, &key, i);
@@ -8138,6 +8167,10 @@ static int account_leaf_items(struct btrfs_trans_handle *trans,
continue;
num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi);
+
+ ret = record_one_subtree_extent(trans, root, bytenr, num_bytes);
+ if (ret)
+ return ret;
}
return 0;
}
@@ -8206,8 +8239,6 @@ static int adjust_slots_upwards(struct btrfs_root *root,
/*
* root_eb is the subtree root and is locked before this function is called.
- * TODO: Modify this function to mark all (including complete shared node)
- * to dirty_extent_root to allow it get accounted in qgroup.
*/
static int account_shared_subtree(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
@@ -8285,6 +8316,11 @@ walk_down:
btrfs_tree_read_lock(eb);
btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
path->locks[level] = BTRFS_READ_LOCK_BLOCKING;
+
+ ret = record_one_subtree_extent(trans, root, child_bytenr,
+ root->nodesize);
+ if (ret)
+ goto out;
}
if (level == 0) {
@@ -10256,6 +10292,47 @@ out:
return ret;
}
+struct btrfs_trans_handle *
+btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info,
+ const u64 chunk_offset)
+{
+ struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
+ struct extent_map *em;
+ struct map_lookup *map;
+ unsigned int num_items;
+
+ read_lock(&em_tree->lock);
+ em = lookup_extent_mapping(em_tree, chunk_offset, 1);
+ read_unlock(&em_tree->lock);
+ ASSERT(em && em->start == chunk_offset);
+
+ /*
+ * We need to reserve 3 + N units from the metadata space info in order
+ * to remove a block group (done at btrfs_remove_chunk() and at
+ * btrfs_remove_block_group()), which are used for:
+ *
+ * 1 unit for adding the free space inode's orphan (located in the tree
+ * of tree roots).
+ * 1 unit for deleting the block group item (located in the extent
+ * tree).
+ * 1 unit for deleting the free space item (located in tree of tree
+ * roots).
+ * N units for deleting N device extent items corresponding to each
+ * stripe (located in the device tree).
+ *
+ * In order to remove a block group we also need to reserve units in the
+ * system space info in order to update the chunk tree (update one or
+ * more device items and remove one chunk item), but this is done at
+ * btrfs_remove_chunk() through a call to check_system_chunk().
+ */
+ map = (struct map_lookup *)em->bdev;
+ num_items = 3 + map->num_stripes;
+ free_extent_map(em);
+
+ return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root,
+ num_items, 1);
+}
+
/*
* Process the unused_bgs list and remove any that don't have any allocated
* space inside of them.
@@ -10279,22 +10356,25 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
block_group = list_first_entry(&fs_info->unused_bgs,
struct btrfs_block_group_cache,
bg_list);
- space_info = block_group->space_info;
list_del_init(&block_group->bg_list);
+
+ space_info = block_group->space_info;
+
if (ret || btrfs_mixed_space_info(space_info)) {
btrfs_put_block_group(block_group);
continue;
}
spin_unlock(&fs_info->unused_bgs_lock);
- mutex_lock(&root->fs_info->delete_unused_bgs_mutex);
+ mutex_lock(&fs_info->delete_unused_bgs_mutex);
/* Don't want to race with allocators so take the groups_sem */
down_write(&space_info->groups_sem);
spin_lock(&block_group->lock);
if (block_group->reserved ||
btrfs_block_group_used(&block_group->item) ||
- block_group->ro) {
+ block_group->ro ||
+ list_is_singular(&block_group->list)) {
/*
* We want to bail if we made new allocations or have
* outstanding allocations in this block group. We do
@@ -10319,8 +10399,8 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
* Want to do this before we do anything else so we can recover
* properly if we fail to join the transaction.
*/
- /* 1 for btrfs_orphan_reserve_metadata() */
- trans = btrfs_start_transaction(root, 1);
+ trans = btrfs_start_trans_remove_block_group(fs_info,
+ block_group->key.objectid);
if (IS_ERR(trans)) {
btrfs_dec_block_group_ro(root, block_group);
ret = PTR_ERR(trans);
@@ -10400,17 +10480,21 @@ void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info)
* until transaction commit to do the actual discard.
*/
if (trimming) {
- WARN_ON(!list_empty(&block_group->bg_list));
- spin_lock(&trans->transaction->deleted_bgs_lock);
+ spin_lock(&fs_info->unused_bgs_lock);
+ /*
+ * A concurrent scrub might have added us to the list
+ * fs_info->unused_bgs, so use a list_move operation
+ * to add the block group to the deleted_bgs list.
+ */
list_move(&block_group->bg_list,
&trans->transaction->deleted_bgs);
- spin_unlock(&trans->transaction->deleted_bgs_lock);
+ spin_unlock(&fs_info->unused_bgs_lock);
btrfs_get_block_group(block_group);
}
end_trans:
btrfs_end_transaction(trans, root);
next:
- mutex_unlock(&root->fs_info->delete_unused_bgs_mutex);
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
btrfs_put_block_group(block_group);
spin_lock(&fs_info->unused_bgs_lock);
}
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 6bd5ce9..e3d9022 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -756,8 +756,16 @@ next_slot:
}
btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
- if (key.objectid > ino ||
- key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
+
+ if (key.objectid > ino)
+ break;
+ if (WARN_ON_ONCE(key.objectid < ino) ||
+ key.type < BTRFS_EXTENT_DATA_KEY) {
+ ASSERT(del_nr == 0);
+ path->slots[0]++;
+ goto next_slot;
+ }
+ if (key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end)
break;
fi = btrfs_item_ptr(leaf, path->slots[0],
@@ -776,8 +784,8 @@ next_slot:
btrfs_file_extent_inline_len(leaf,
path->slots[0], fi);
} else {
- WARN_ON(1);
- extent_end = search_start;
+ /* can't happen */
+ BUG();
}
/*
@@ -1283,7 +1291,8 @@ out:
* on error we return an unlocked page and the error value
* on success we return a locked page and 0
*/
-static int prepare_uptodate_page(struct page *page, u64 pos,
+static int prepare_uptodate_page(struct inode *inode,
+ struct page *page, u64 pos,
bool force_uptodate)
{
int ret = 0;
@@ -1298,6 +1307,10 @@ static int prepare_uptodate_page(struct page *page, u64 pos,
unlock_page(page);
return -EIO;
}
+ if (page->mapping != inode->i_mapping) {
+ unlock_page(page);
+ return -EAGAIN;
+ }
}
return 0;
}
@@ -1316,6 +1329,7 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
int faili;
for (i = 0; i < num_pages; i++) {
+again:
pages[i] = find_or_create_page(inode->i_mapping, index + i,
mask | __GFP_WRITE);
if (!pages[i]) {
@@ -1325,13 +1339,17 @@ static noinline int prepare_pages(struct inode *inode, struct page **pages,
}
if (i == 0)
- err = prepare_uptodate_page(pages[i], pos,
+ err = prepare_uptodate_page(inode, pages[i], pos,
force_uptodate);
- if (i == num_pages - 1)
- err = prepare_uptodate_page(pages[i],
+ if (!err && i == num_pages - 1)
+ err = prepare_uptodate_page(inode, pages[i],
pos + write_bytes, false);
if (err) {
page_cache_release(pages[i]);
+ if (err == -EAGAIN) {
+ err = 0;
+ goto again;
+ }
faili = i - 1;
goto fail;
}
@@ -1874,8 +1892,13 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
struct btrfs_log_ctx ctx;
int ret = 0;
bool full_sync = 0;
- const u64 len = end - start + 1;
+ u64 len;
+ /*
+ * The range length can be represented by u64, we have to do the typecasts
+ * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync()
+ */
+ len = (u64)end - (u64)start + 1;
trace_btrfs_sync_file(file, datasync);
/*
@@ -2063,8 +2086,7 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
}
}
if (!full_sync) {
- ret = btrfs_wait_ordered_range(inode, start,
- end - start + 1);
+ ret = btrfs_wait_ordered_range(inode, start, len);
if (ret) {
btrfs_end_transaction(trans, root);
goto out;
@@ -2912,6 +2934,9 @@ const struct file_operations btrfs_file_operations = {
#ifdef CONFIG_COMPAT
.compat_ioctl = btrfs_ioctl,
#endif
+ .copy_file_range = btrfs_copy_file_range,
+ .clone_file_range = btrfs_clone_file_range,
+ .dedupe_file_range = btrfs_dedupe_file_range,
};
void btrfs_auto_defrag_exit(void)
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 85a1f86..cfe99be 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -891,7 +891,7 @@ out:
spin_unlock(&block_group->lock);
ret = 0;
- btrfs_warn(fs_info, "failed to load free space cache for block group %llu, rebuild it now",
+ btrfs_warn(fs_info, "failed to load free space cache for block group %llu, rebuilding it now",
block_group->key.objectid);
}
@@ -2972,7 +2972,7 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
u64 cont1_bytes, u64 min_bytes)
{
struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl;
- struct btrfs_free_space *entry;
+ struct btrfs_free_space *entry = NULL;
int ret = -ENOSPC;
u64 bitmap_offset = offset_to_bitmap(ctl, offset);
@@ -2983,8 +2983,10 @@ setup_cluster_bitmap(struct btrfs_block_group_cache *block_group,
* The bitmap that covers offset won't be in the list unless offset
* is just its start offset.
*/
- entry = list_first_entry(bitmaps, struct btrfs_free_space, list);
- if (entry->offset != bitmap_offset) {
+ if (!list_empty(bitmaps))
+ entry = list_first_entry(bitmaps, struct btrfs_free_space, list);
+
+ if (!entry || entry->offset != bitmap_offset) {
entry = tree_search_offset(ctl, bitmap_offset, 1, 0);
if (entry && list_empty(&entry->list))
list_add(&entry->list, bitmaps);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0e4f2bf..3b8856e 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1304,8 +1304,14 @@ next_slot:
num_bytes = 0;
btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
- if (found_key.objectid > ino ||
- found_key.type > BTRFS_EXTENT_DATA_KEY ||
+ if (found_key.objectid > ino)
+ break;
+ if (WARN_ON_ONCE(found_key.objectid < ino) ||
+ found_key.type < BTRFS_EXTENT_DATA_KEY) {
+ path->slots[0]++;
+ goto next_slot;
+ }
+ if (found_key.type > BTRFS_EXTENT_DATA_KEY ||
found_key.offset > end)
break;
@@ -3544,10 +3550,10 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
int scanned = 0;
if (!xattr_access) {
- xattr_access = btrfs_name_hash(POSIX_ACL_XATTR_ACCESS,
- strlen(POSIX_ACL_XATTR_ACCESS));
- xattr_default = btrfs_name_hash(POSIX_ACL_XATTR_DEFAULT,
- strlen(POSIX_ACL_XATTR_DEFAULT));
+ xattr_access = btrfs_name_hash(XATTR_NAME_POSIX_ACL_ACCESS,
+ strlen(XATTR_NAME_POSIX_ACL_ACCESS));
+ xattr_default = btrfs_name_hash(XATTR_NAME_POSIX_ACL_DEFAULT,
+ strlen(XATTR_NAME_POSIX_ACL_DEFAULT));
}
slot++;
@@ -3768,6 +3774,7 @@ cache_acl:
break;
case S_IFLNK:
inode->i_op = &btrfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &btrfs_symlink_aops;
break;
default:
@@ -4040,9 +4047,7 @@ int btrfs_unlink_inode(struct btrfs_trans_handle *trans,
*/
static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
{
- struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(dir)->root;
- int ret;
/*
* 1 for the possible orphan item
@@ -4051,27 +4056,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
* 1 for the inode ref
* 1 for the inode
*/
- trans = btrfs_start_transaction(root, 5);
- if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
- return trans;
-
- if (PTR_ERR(trans) == -ENOSPC) {
- u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
-
- trans = btrfs_start_transaction(root, 0);
- if (IS_ERR(trans))
- return trans;
- ret = btrfs_cond_migrate_bytes(root->fs_info,
- &root->fs_info->trans_block_rsv,
- num_bytes, 5);
- if (ret) {
- btrfs_end_transaction(trans, root);
- return ERR_PTR(ret);
- }
- trans->block_rsv = &root->fs_info->trans_block_rsv;
- trans->bytes_reserved = num_bytes;
- }
- return trans;
+ return btrfs_start_transaction_fallback_global_rsv(root, 5, 5);
}
static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
@@ -7503,6 +7488,28 @@ struct btrfs_dio_data {
u64 reserve;
};
+static void adjust_dio_outstanding_extents(struct inode *inode,
+ struct btrfs_dio_data *dio_data,
+ const u64 len)
+{
+ unsigned num_extents;
+
+ num_extents = (unsigned) div64_u64(len + BTRFS_MAX_EXTENT_SIZE - 1,
+ BTRFS_MAX_EXTENT_SIZE);
+ /*
+ * If we have an outstanding_extents count still set then we're
+ * within our reservation, otherwise we need to adjust our inode
+ * counter appropriately.
+ */
+ if (dio_data->outstanding_extents) {
+ dio_data->outstanding_extents -= num_extents;
+ } else {
+ spin_lock(&BTRFS_I(inode)->lock);
+ BTRFS_I(inode)->outstanding_extents += num_extents;
+ spin_unlock(&BTRFS_I(inode)->lock);
+ }
+}
+
static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
struct buffer_head *bh_result, int create)
{
@@ -7538,8 +7545,11 @@ static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock,
* If this errors out it's because we couldn't invalidate pagecache for
* this range and we need to fallback to buffered.
*/
- if (lock_extent_direct(inode, lockstart, lockend, &cached_state, create))
- return -ENOTBLK;
+ if (lock_extent_direct(inode, lockstart, lockend, &cached_state,
+ create)) {
+ ret = -ENOTBLK;
+ goto err;
+ }
em = btrfs_get_extent(inode, NULL, 0, start, len, 0);
if (IS_ERR(em)) {
@@ -7657,19 +7667,7 @@ unlock:
if (start + len > i_size_read(inode))
i_size_write(inode, start + len);
- /*
- * If we have an outstanding_extents count still set then we're
- * within our reservation, otherwise we need to adjust our inode
- * counter appropriately.
- */
- if (dio_data->outstanding_extents) {
- (dio_data->outstanding_extents)--;
- } else {
- spin_lock(&BTRFS_I(inode)->lock);
- BTRFS_I(inode)->outstanding_extents++;
- spin_unlock(&BTRFS_I(inode)->lock);
- }
-
+ adjust_dio_outstanding_extents(inode, dio_data, len);
btrfs_free_reserved_data_space(inode, start, len);
WARN_ON(dio_data->reserve < len);
dio_data->reserve -= len;
@@ -7696,8 +7694,17 @@ unlock:
unlock_err:
clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend,
unlock_bits, 1, 0, &cached_state, GFP_NOFS);
+err:
if (dio_data)
current->journal_info = dio_data;
+ /*
+ * Compensate the delalloc release we do in btrfs_direct_IO() when we
+ * write less data then expected, so that we don't underflow our inode's
+ * outstanding extents counter.
+ */
+ if (create && dio_data)
+ adjust_dio_outstanding_extents(inode, dio_data, len);
+
return ret;
}
@@ -9699,6 +9706,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
btrfs_free_path(path);
inode->i_op = &btrfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &btrfs_symlink_aops;
inode_set_bytes(inode, name_len);
btrfs_i_size_write(inode, name_len);
@@ -9988,7 +9996,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
.setattr = btrfs_setattr,
.mknod = btrfs_mknod,
.setxattr = btrfs_setxattr,
- .getxattr = btrfs_getxattr,
+ .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
.permission = btrfs_permission,
@@ -10065,7 +10073,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.setxattr = btrfs_setxattr,
- .getxattr = btrfs_getxattr,
+ .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
.permission = btrfs_permission,
@@ -10079,7 +10087,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
.setattr = btrfs_setattr,
.permission = btrfs_permission,
.setxattr = btrfs_setxattr,
- .getxattr = btrfs_getxattr,
+ .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
.get_acl = btrfs_get_acl,
@@ -10088,13 +10096,12 @@ static const struct inode_operations btrfs_special_inode_operations = {
};
static const struct inode_operations btrfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.getattr = btrfs_getattr,
.setattr = btrfs_setattr,
.permission = btrfs_permission,
.setxattr = btrfs_setxattr,
- .getxattr = btrfs_getxattr,
+ .getxattr = generic_getxattr,
.listxattr = btrfs_listxattr,
.removexattr = btrfs_removexattr,
.update_time = btrfs_update_time,
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index da94138..e219973 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2962,7 +2962,7 @@ static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst,
flush_dcache_page(dst_page);
if (memcmp(addr, dst_addr, cmp_len))
- ret = BTRFS_SAME_DATA_DIFFERS;
+ ret = -EBADE;
kunmap_atomic(addr);
kunmap_atomic(dst_addr);
@@ -3098,53 +3098,16 @@ out_unlock:
#define BTRFS_MAX_DEDUPE_LEN (16 * 1024 * 1024)
-static long btrfs_ioctl_file_extent_same(struct file *file,
- struct btrfs_ioctl_same_args __user *argp)
+ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen,
+ struct file *dst_file, u64 dst_loff)
{
- struct btrfs_ioctl_same_args *same = NULL;
- struct btrfs_ioctl_same_extent_info *info;
- struct inode *src = file_inode(file);
- u64 off;
- u64 len;
- int i;
- int ret;
- unsigned long size;
+ struct inode *src = file_inode(src_file);
+ struct inode *dst = file_inode(dst_file);
u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
- bool is_admin = capable(CAP_SYS_ADMIN);
- u16 count;
-
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- ret = mnt_want_write_file(file);
- if (ret)
- return ret;
-
- if (get_user(count, &argp->dest_count)) {
- ret = -EFAULT;
- goto out;
- }
-
- size = offsetof(struct btrfs_ioctl_same_args __user, info[count]);
-
- same = memdup_user(argp, size);
-
- if (IS_ERR(same)) {
- ret = PTR_ERR(same);
- same = NULL;
- goto out;
- }
+ ssize_t res;
- off = same->logical_offset;
- len = same->length;
-
- /*
- * Limit the total length we will dedupe for each operation.
- * This is intended to bound the total time spent in this
- * ioctl to something sane.
- */
- if (len > BTRFS_MAX_DEDUPE_LEN)
- len = BTRFS_MAX_DEDUPE_LEN;
+ if (olen > BTRFS_MAX_DEDUPE_LEN)
+ olen = BTRFS_MAX_DEDUPE_LEN;
if (WARN_ON_ONCE(bs < PAGE_CACHE_SIZE)) {
/*
@@ -3152,58 +3115,13 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
* result, btrfs_cmp_data() won't correctly handle
* this situation without an update.
*/
- ret = -EINVAL;
- goto out;
- }
-
- ret = -EISDIR;
- if (S_ISDIR(src->i_mode))
- goto out;
-
- ret = -EACCES;
- if (!S_ISREG(src->i_mode))
- goto out;
-
- /* pre-format output fields to sane values */
- for (i = 0; i < count; i++) {
- same->info[i].bytes_deduped = 0ULL;
- same->info[i].status = 0;
- }
-
- for (i = 0, info = same->info; i < count; i++, info++) {
- struct inode *dst;
- struct fd dst_file = fdget(info->fd);
- if (!dst_file.file) {
- info->status = -EBADF;
- continue;
- }
- dst = file_inode(dst_file.file);
-
- if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
- info->status = -EINVAL;
- } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
- info->status = -EXDEV;
- } else if (S_ISDIR(dst->i_mode)) {
- info->status = -EISDIR;
- } else if (!S_ISREG(dst->i_mode)) {
- info->status = -EACCES;
- } else {
- info->status = btrfs_extent_same(src, off, len, dst,
- info->logical_offset);
- if (info->status == 0)
- info->bytes_deduped += len;
- }
- fdput(dst_file);
+ return -EINVAL;
}
- ret = copy_to_user(argp, same, size);
- if (ret)
- ret = -EFAULT;
-
-out:
- mnt_drop_write_file(file);
- kfree(same);
- return ret;
+ res = btrfs_extent_same(src, loff, olen, dst, dst_loff);
+ if (res)
+ return res;
+ return olen;
}
static int clone_finish_inode_update(struct btrfs_trans_handle *trans,
@@ -3779,17 +3697,16 @@ out:
return ret;
}
-static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
- u64 off, u64 olen, u64 destoff)
+static noinline int btrfs_clone_files(struct file *file, struct file *file_src,
+ u64 off, u64 olen, u64 destoff)
{
struct inode *inode = file_inode(file);
+ struct inode *src = file_inode(file_src);
struct btrfs_root *root = BTRFS_I(inode)->root;
- struct fd src_file;
- struct inode *src;
int ret;
u64 len = olen;
u64 bs = root->fs_info->sb->s_blocksize;
- int same_inode = 0;
+ int same_inode = src == inode;
/*
* TODO:
@@ -3802,49 +3719,20 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
* be either compressed or non-compressed.
*/
- /* the destination must be opened for writing */
- if (!(file->f_mode & FMODE_WRITE) || (file->f_flags & O_APPEND))
- return -EINVAL;
-
if (btrfs_root_readonly(root))
return -EROFS;
- ret = mnt_want_write_file(file);
- if (ret)
- return ret;
-
- src_file = fdget(srcfd);
- if (!src_file.file) {
- ret = -EBADF;
- goto out_drop_write;
- }
-
- ret = -EXDEV;
- if (src_file.file->f_path.mnt != file->f_path.mnt)
- goto out_fput;
-
- src = file_inode(src_file.file);
-
- ret = -EINVAL;
- if (src == inode)
- same_inode = 1;
-
- /* the src must be open for reading */
- if (!(src_file.file->f_mode & FMODE_READ))
- goto out_fput;
+ if (file_src->f_path.mnt != file->f_path.mnt ||
+ src->i_sb != inode->i_sb)
+ return -EXDEV;
/* don't make the dst file partly checksummed */
if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) !=
(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM))
- goto out_fput;
+ return -EINVAL;
- ret = -EISDIR;
if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode))
- goto out_fput;
-
- ret = -EXDEV;
- if (src->i_sb != inode->i_sb)
- goto out_fput;
+ return -EISDIR;
if (!same_inode) {
btrfs_double_inode_lock(src, inode);
@@ -3921,21 +3809,25 @@ out_unlock:
btrfs_double_inode_unlock(src, inode);
else
mutex_unlock(&src->i_mutex);
-out_fput:
- fdput(src_file);
-out_drop_write:
- mnt_drop_write_file(file);
return ret;
}
-static long btrfs_ioctl_clone_range(struct file *file, void __user *argp)
+ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out,
+ size_t len, unsigned int flags)
{
- struct btrfs_ioctl_clone_range_args args;
+ ssize_t ret;
- if (copy_from_user(&args, argp, sizeof(args)))
- return -EFAULT;
- return btrfs_ioctl_clone(file, args.src_fd, args.src_offset,
- args.src_length, args.dest_offset);
+ ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out);
+ if (ret == 0)
+ ret = len;
+ return ret;
+}
+
+int btrfs_clone_file_range(struct file *src_file, loff_t off,
+ struct file *dst_file, loff_t destoff, u64 len)
+{
+ return btrfs_clone_files(dst_file, src_file, off, len, destoff);
}
/*
@@ -5485,10 +5377,6 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_dev_info(root, argp);
case BTRFS_IOC_BALANCE:
return btrfs_ioctl_balance(file, NULL);
- case BTRFS_IOC_CLONE:
- return btrfs_ioctl_clone(file, arg, 0, 0, 0);
- case BTRFS_IOC_CLONE_RANGE:
- return btrfs_ioctl_clone_range(file, argp);
case BTRFS_IOC_TRANS_START:
return btrfs_ioctl_trans_start(file);
case BTRFS_IOC_TRANS_END:
@@ -5566,8 +5454,6 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_get_fslabel(file, argp);
case BTRFS_IOC_SET_FSLABEL:
return btrfs_ioctl_set_fslabel(file, argp);
- case BTRFS_IOC_FILE_EXTENT_SAME:
- return btrfs_ioctl_file_extent_same(file, argp);
case BTRFS_IOC_GET_SUPPORTED_FEATURES:
return btrfs_ioctl_get_supported_features(file, argp);
case BTRFS_IOC_GET_FEATURES:
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 46476c2..5279fda 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -993,9 +993,10 @@ int btrfs_quota_disable(struct btrfs_trans_handle *trans,
mutex_lock(&fs_info->qgroup_ioctl_lock);
if (!fs_info->quota_root)
goto out;
- spin_lock(&fs_info->qgroup_lock);
fs_info->quota_enabled = 0;
fs_info->pending_quota_state = 0;
+ btrfs_qgroup_wait_for_completion(fs_info);
+ spin_lock(&fs_info->qgroup_lock);
quota_root = fs_info->quota_root;
fs_info->quota_root = NULL;
fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON;
@@ -1461,6 +1462,8 @@ struct btrfs_qgroup_extent_record
struct btrfs_qgroup_extent_record *entry;
u64 bytenr = record->bytenr;
+ assert_spin_locked(&delayed_refs->lock);
+
while (*p) {
parent_node = *p;
entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record,
@@ -2198,7 +2201,6 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
int slot;
int ret;
- path->leave_spinning = 1;
mutex_lock(&fs_info->qgroup_rescan_lock);
ret = btrfs_search_slot_for_read(fs_info->extent_root,
&fs_info->qgroup_rescan_progress,
@@ -2286,7 +2288,7 @@ static void btrfs_qgroup_rescan_worker(struct btrfs_work *work)
goto out;
err = 0;
- while (!err) {
+ while (!err && !btrfs_fs_closing(fs_info)) {
trans = btrfs_start_transaction(fs_info->fs_root, 0);
if (IS_ERR(trans)) {
err = PTR_ERR(trans);
@@ -2307,7 +2309,8 @@ out:
btrfs_free_path(path);
mutex_lock(&fs_info->qgroup_rescan_lock);
- fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
+ if (!btrfs_fs_closing(fs_info))
+ fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN;
if (err > 0 &&
fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) {
@@ -2336,7 +2339,9 @@ out:
}
btrfs_end_transaction(trans, fs_info->quota_root);
- if (err >= 0) {
+ if (btrfs_fs_closing(fs_info)) {
+ btrfs_info(fs_info, "qgroup scan paused");
+ } else if (err >= 0) {
btrfs_info(fs_info, "qgroup scan completed%s",
err > 0 ? " (inconsistency flag cleared)" : "");
} else {
@@ -2384,12 +2389,11 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
memset(&fs_info->qgroup_rescan_progress, 0,
sizeof(fs_info->qgroup_rescan_progress));
fs_info->qgroup_rescan_progress.objectid = progress_objectid;
+ init_completion(&fs_info->qgroup_rescan_completion);
spin_unlock(&fs_info->qgroup_lock);
mutex_unlock(&fs_info->qgroup_rescan_lock);
- init_completion(&fs_info->qgroup_rescan_completion);
-
memset(&fs_info->qgroup_rescan_work, 0,
sizeof(fs_info->qgroup_rescan_work));
btrfs_init_work(&fs_info->qgroup_rescan_work,
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 550de89..b091d94 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -248,14 +248,9 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check);
static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
struct scrub_block *sblocks_for_recheck);
static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
- struct scrub_block *sblock, int is_metadata,
- int have_csum, u8 *csum, u64 generation,
- u16 csum_size, int retry_failed_mirror);
-static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
- struct scrub_block *sblock,
- int is_metadata, int have_csum,
- const u8 *csum, u64 generation,
- u16 csum_size);
+ struct scrub_block *sblock,
+ int retry_failed_mirror);
+static void scrub_recheck_block_checksum(struct scrub_block *sblock);
static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
struct scrub_block *sblock_good);
static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
@@ -889,11 +884,9 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
struct btrfs_fs_info *fs_info;
u64 length;
u64 logical;
- u64 generation;
unsigned int failed_mirror_index;
unsigned int is_metadata;
unsigned int have_csum;
- u8 *csum;
struct scrub_block *sblocks_for_recheck; /* holds one for each mirror */
struct scrub_block *sblock_bad;
int ret;
@@ -918,13 +911,11 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
}
length = sblock_to_check->page_count * PAGE_SIZE;
logical = sblock_to_check->pagev[0]->logical;
- generation = sblock_to_check->pagev[0]->generation;
BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1);
failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1;
is_metadata = !(sblock_to_check->pagev[0]->flags &
BTRFS_EXTENT_FLAG_DATA);
have_csum = sblock_to_check->pagev[0]->have_csum;
- csum = sblock_to_check->pagev[0]->csum;
dev = sblock_to_check->pagev[0]->dev;
if (sctx->is_dev_replace && !is_metadata && !have_csum) {
@@ -987,8 +978,7 @@ static int scrub_handle_errored_block(struct scrub_block *sblock_to_check)
sblock_bad = sblocks_for_recheck + failed_mirror_index;
/* build and submit the bios for the failed mirror, check checksums */
- scrub_recheck_block(fs_info, sblock_bad, is_metadata, have_csum,
- csum, generation, sctx->csum_size, 1);
+ scrub_recheck_block(fs_info, sblock_bad, 1);
if (!sblock_bad->header_error && !sblock_bad->checksum_error &&
sblock_bad->no_io_error_seen) {
@@ -1101,9 +1091,7 @@ nodatasum_case:
sblock_other = sblocks_for_recheck + mirror_index;
/* build and submit the bios, check checksums */
- scrub_recheck_block(fs_info, sblock_other, is_metadata,
- have_csum, csum, generation,
- sctx->csum_size, 0);
+ scrub_recheck_block(fs_info, sblock_other, 0);
if (!sblock_other->header_error &&
!sblock_other->checksum_error &&
@@ -1215,9 +1203,7 @@ nodatasum_case:
* is verified, but most likely the data comes out
* of the page cache.
*/
- scrub_recheck_block(fs_info, sblock_bad,
- is_metadata, have_csum, csum,
- generation, sctx->csum_size, 1);
+ scrub_recheck_block(fs_info, sblock_bad, 1);
if (!sblock_bad->header_error &&
!sblock_bad->checksum_error &&
sblock_bad->no_io_error_seen)
@@ -1318,6 +1304,9 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
u64 length = original_sblock->page_count * PAGE_SIZE;
u64 logical = original_sblock->pagev[0]->logical;
+ u64 generation = original_sblock->pagev[0]->generation;
+ u64 flags = original_sblock->pagev[0]->flags;
+ u64 have_csum = original_sblock->pagev[0]->have_csum;
struct scrub_recover *recover;
struct btrfs_bio *bbio;
u64 sublen;
@@ -1372,6 +1361,7 @@ static int scrub_setup_recheck_block(struct scrub_block *original_sblock,
sblock = sblocks_for_recheck + mirror_index;
sblock->sctx = sctx;
+
page = kzalloc(sizeof(*page), GFP_NOFS);
if (!page) {
leave_nomem:
@@ -1383,7 +1373,15 @@ leave_nomem:
}
scrub_page_get(page);
sblock->pagev[page_index] = page;
+ page->sblock = sblock;
+ page->flags = flags;
+ page->generation = generation;
page->logical = logical;
+ page->have_csum = have_csum;
+ if (have_csum)
+ memcpy(page->csum,
+ original_sblock->pagev[0]->csum,
+ sctx->csum_size);
scrub_stripe_index_and_offset(logical,
bbio->map_type,
@@ -1474,15 +1472,12 @@ static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info,
* the pages that are errored in the just handled mirror can be repaired.
*/
static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
- struct scrub_block *sblock, int is_metadata,
- int have_csum, u8 *csum, u64 generation,
- u16 csum_size, int retry_failed_mirror)
+ struct scrub_block *sblock,
+ int retry_failed_mirror)
{
int page_num;
sblock->no_io_error_seen = 1;
- sblock->header_error = 0;
- sblock->checksum_error = 0;
for (page_num = 0; page_num < sblock->page_count; page_num++) {
struct bio *bio;
@@ -1518,9 +1513,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
}
if (sblock->no_io_error_seen)
- scrub_recheck_block_checksum(fs_info, sblock, is_metadata,
- have_csum, csum, generation,
- csum_size);
+ scrub_recheck_block_checksum(sblock);
return;
}
@@ -1535,61 +1528,16 @@ static inline int scrub_check_fsid(u8 fsid[],
return !ret;
}
-static void scrub_recheck_block_checksum(struct btrfs_fs_info *fs_info,
- struct scrub_block *sblock,
- int is_metadata, int have_csum,
- const u8 *csum, u64 generation,
- u16 csum_size)
+static void scrub_recheck_block_checksum(struct scrub_block *sblock)
{
- int page_num;
- u8 calculated_csum[BTRFS_CSUM_SIZE];
- u32 crc = ~(u32)0;
- void *mapped_buffer;
-
- WARN_ON(!sblock->pagev[0]->page);
- if (is_metadata) {
- struct btrfs_header *h;
-
- mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
- h = (struct btrfs_header *)mapped_buffer;
-
- if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h) ||
- !scrub_check_fsid(h->fsid, sblock->pagev[0]) ||
- memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
- BTRFS_UUID_SIZE)) {
- sblock->header_error = 1;
- } else if (generation != btrfs_stack_header_generation(h)) {
- sblock->header_error = 1;
- sblock->generation_error = 1;
- }
- csum = h->csum;
- } else {
- if (!have_csum)
- return;
-
- mapped_buffer = kmap_atomic(sblock->pagev[0]->page);
- }
-
- for (page_num = 0;;) {
- if (page_num == 0 && is_metadata)
- crc = btrfs_csum_data(
- ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE,
- crc, PAGE_SIZE - BTRFS_CSUM_SIZE);
- else
- crc = btrfs_csum_data(mapped_buffer, crc, PAGE_SIZE);
-
- kunmap_atomic(mapped_buffer);
- page_num++;
- if (page_num >= sblock->page_count)
- break;
- WARN_ON(!sblock->pagev[page_num]->page);
-
- mapped_buffer = kmap_atomic(sblock->pagev[page_num]->page);
- }
+ sblock->header_error = 0;
+ sblock->checksum_error = 0;
+ sblock->generation_error = 0;
- btrfs_csum_final(crc, calculated_csum);
- if (memcmp(calculated_csum, csum, csum_size))
- sblock->checksum_error = 1;
+ if (sblock->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA)
+ scrub_checksum_data(sblock);
+ else
+ scrub_checksum_tree_block(sblock);
}
static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad,
@@ -1833,6 +1781,18 @@ static int scrub_checksum(struct scrub_block *sblock)
u64 flags;
int ret;
+ /*
+ * No need to initialize these stats currently,
+ * because this function only use return value
+ * instead of these stats value.
+ *
+ * Todo:
+ * always use stats
+ */
+ sblock->header_error = 0;
+ sblock->generation_error = 0;
+ sblock->checksum_error = 0;
+
WARN_ON(sblock->page_count < 1);
flags = sblock->pagev[0]->flags;
ret = 0;
@@ -1858,7 +1818,6 @@ static int scrub_checksum_data(struct scrub_block *sblock)
struct page *page;
void *buffer;
u32 crc = ~(u32)0;
- int fail = 0;
u64 len;
int index;
@@ -1889,9 +1848,9 @@ static int scrub_checksum_data(struct scrub_block *sblock)
btrfs_csum_final(crc, csum);
if (memcmp(csum, on_disk_csum, sctx->csum_size))
- fail = 1;
+ sblock->checksum_error = 1;
- return fail;
+ return sblock->checksum_error;
}
static int scrub_checksum_tree_block(struct scrub_block *sblock)
@@ -1907,8 +1866,6 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
u64 mapped_size;
void *p;
u32 crc = ~(u32)0;
- int fail = 0;
- int crc_fail = 0;
u64 len;
int index;
@@ -1923,19 +1880,20 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
* a) don't have an extent buffer and
* b) the page is already kmapped
*/
-
if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h))
- ++fail;
+ sblock->header_error = 1;
- if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h))
- ++fail;
+ if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h)) {
+ sblock->header_error = 1;
+ sblock->generation_error = 1;
+ }
if (!scrub_check_fsid(h->fsid, sblock->pagev[0]))
- ++fail;
+ sblock->header_error = 1;
if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid,
BTRFS_UUID_SIZE))
- ++fail;
+ sblock->header_error = 1;
len = sctx->nodesize - BTRFS_CSUM_SIZE;
mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE;
@@ -1960,9 +1918,9 @@ static int scrub_checksum_tree_block(struct scrub_block *sblock)
btrfs_csum_final(crc, calculated_csum);
if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size))
- ++crc_fail;
+ sblock->checksum_error = 1;
- return fail || crc_fail;
+ return sblock->header_error || sblock->checksum_error;
}
static int scrub_checksum_super(struct scrub_block *sblock)
@@ -2176,39 +2134,27 @@ static void scrub_missing_raid56_worker(struct btrfs_work *work)
{
struct scrub_block *sblock = container_of(work, struct scrub_block, work);
struct scrub_ctx *sctx = sblock->sctx;
- struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info;
- unsigned int is_metadata;
- unsigned int have_csum;
- u8 *csum;
- u64 generation;
u64 logical;
struct btrfs_device *dev;
- is_metadata = !(sblock->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA);
- have_csum = sblock->pagev[0]->have_csum;
- csum = sblock->pagev[0]->csum;
- generation = sblock->pagev[0]->generation;
logical = sblock->pagev[0]->logical;
dev = sblock->pagev[0]->dev;
- if (sblock->no_io_error_seen) {
- scrub_recheck_block_checksum(fs_info, sblock, is_metadata,
- have_csum, csum, generation,
- sctx->csum_size);
- }
+ if (sblock->no_io_error_seen)
+ scrub_recheck_block_checksum(sblock);
if (!sblock->no_io_error_seen) {
spin_lock(&sctx->stat_lock);
sctx->stat.read_errors++;
spin_unlock(&sctx->stat_lock);
- btrfs_err_rl_in_rcu(fs_info,
+ btrfs_err_rl_in_rcu(sctx->dev_root->fs_info,
"IO error rebuilding logical %llu for dev %s",
logical, rcu_str_deref(dev->name));
} else if (sblock->header_error || sblock->checksum_error) {
spin_lock(&sctx->stat_lock);
sctx->stat.uncorrectable_errors++;
spin_unlock(&sctx->stat_lock);
- btrfs_err_rl_in_rcu(fs_info,
+ btrfs_err_rl_in_rcu(sctx->dev_root->fs_info,
"failed to rebuild valid logical %llu for dev %s",
logical, rcu_str_deref(dev->name));
} else {
@@ -2500,8 +2446,7 @@ static void scrub_block_complete(struct scrub_block *sblock)
}
}
-static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u64 len,
- u8 *csum)
+static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum)
{
struct btrfs_ordered_sum *sum = NULL;
unsigned long index;
@@ -2565,7 +2510,7 @@ static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len,
if (flags & BTRFS_EXTENT_FLAG_DATA) {
/* push csums to sbio */
- have_csum = scrub_find_csum(sctx, logical, l, csum);
+ have_csum = scrub_find_csum(sctx, logical, csum);
if (have_csum == 0)
++sctx->stat.no_csum;
if (sctx->is_dev_replace && !have_csum) {
@@ -2703,7 +2648,7 @@ static int scrub_extent_for_parity(struct scrub_parity *sparity,
if (flags & BTRFS_EXTENT_FLAG_DATA) {
/* push csums to sbio */
- have_csum = scrub_find_csum(sctx, logical, l, csum);
+ have_csum = scrub_find_csum(sctx, logical, csum);
if (have_csum == 0)
goto skip;
}
@@ -3012,6 +2957,9 @@ static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx,
logic_start + map->stripe_len)) {
btrfs_err(fs_info, "scrub: tree block %llu spanning stripes, ignored. logical=%llu",
key.objectid, logic_start);
+ spin_lock(&sctx->stat_lock);
+ sctx->stat.uncorrectable_errors++;
+ spin_unlock(&sctx->stat_lock);
goto next;
}
again:
@@ -3361,6 +3309,9 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
"scrub: tree block %llu spanning "
"stripes, ignored. logical=%llu",
key.objectid, logical);
+ spin_lock(&sctx->stat_lock);
+ sctx->stat.uncorrectable_errors++;
+ spin_unlock(&sctx->stat_lock);
goto next;
}
@@ -3481,7 +3432,9 @@ out:
static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
struct btrfs_device *scrub_dev,
u64 chunk_offset, u64 length,
- u64 dev_offset, int is_dev_replace)
+ u64 dev_offset,
+ struct btrfs_block_group_cache *cache,
+ int is_dev_replace)
{
struct btrfs_mapping_tree *map_tree =
&sctx->dev_root->fs_info->mapping_tree;
@@ -3494,8 +3447,18 @@ static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx,
em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1);
read_unlock(&map_tree->map_tree.lock);
- if (!em)
- return -EINVAL;
+ if (!em) {
+ /*
+ * Might have been an unused block group deleted by the cleaner
+ * kthread or relocation.
+ */
+ spin_lock(&cache->lock);
+ if (!cache->removed)
+ ret = -EINVAL;
+ spin_unlock(&cache->lock);
+
+ return ret;
+ }
map = (struct map_lookup *)em->bdev;
if (em->start != chunk_offset)
@@ -3532,6 +3495,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
u64 length;
u64 chunk_offset;
int ret = 0;
+ int ro_set;
int slot;
struct extent_buffer *l;
struct btrfs_key key;
@@ -3617,7 +3581,21 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
scrub_pause_on(fs_info);
ret = btrfs_inc_block_group_ro(root, cache);
scrub_pause_off(fs_info);
- if (ret) {
+
+ if (ret == 0) {
+ ro_set = 1;
+ } else if (ret == -ENOSPC) {
+ /*
+ * btrfs_inc_block_group_ro return -ENOSPC when it
+ * failed in creating new chunk for metadata.
+ * It is not a problem for scrub/replace, because
+ * metadata are always cowed, and our scrub paused
+ * commit_transactions.
+ */
+ ro_set = 0;
+ } else {
+ btrfs_warn(fs_info, "failed setting block group ro, ret=%d\n",
+ ret);
btrfs_put_block_group(cache);
break;
}
@@ -3626,7 +3604,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
dev_replace->cursor_left = found_key.offset;
dev_replace->item_needs_writeback = 1;
ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length,
- found_key.offset, is_dev_replace);
+ found_key.offset, cache, is_dev_replace);
/*
* flush, submit all pending read and write bios, afterwards
@@ -3660,7 +3638,30 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
scrub_pause_off(fs_info);
- btrfs_dec_block_group_ro(root, cache);
+ if (ro_set)
+ btrfs_dec_block_group_ro(root, cache);
+
+ /*
+ * We might have prevented the cleaner kthread from deleting
+ * this block group if it was already unused because we raced
+ * and set it to RO mode first. So add it back to the unused
+ * list, otherwise it might not ever be deleted unless a manual
+ * balance is triggered or it becomes used and unused again.
+ */
+ spin_lock(&cache->lock);
+ if (!cache->removed && !cache->ro && cache->reserved == 0 &&
+ btrfs_block_group_used(&cache->item) == 0) {
+ spin_unlock(&cache->lock);
+ spin_lock(&fs_info->unused_bgs_lock);
+ if (list_empty(&cache->bg_list)) {
+ btrfs_get_block_group(cache);
+ list_add_tail(&cache->bg_list,
+ &fs_info->unused_bgs);
+ }
+ spin_unlock(&fs_info->unused_bgs_lock);
+ } else {
+ spin_unlock(&cache->lock);
+ }
btrfs_put_block_group(cache);
if (ret)
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 24154e4..a0434c17 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1514,9 +1514,7 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
if ((flags ^ s->s_flags) & MS_RDONLY)
error = -EBUSY;
} else {
- char b[BDEVNAME_SIZE];
-
- strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
+ snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
btrfs_sb(s)->bdev_holder = fs_type;
error = btrfs_fill_super(s, fs_devices, data,
flags & MS_SILENT ? 1 : 0);
diff --git a/fs/btrfs/tests/free-space-tests.c b/fs/btrfs/tests/free-space-tests.c
index c8c3d70..8b72b00 100644
--- a/fs/btrfs/tests/free-space-tests.c
+++ b/fs/btrfs/tests/free-space-tests.c
@@ -898,8 +898,10 @@ int btrfs_test_free_space_cache(void)
}
root = btrfs_alloc_dummy_root();
- if (!root)
+ if (IS_ERR(root)) {
+ ret = PTR_ERR(root);
goto out;
+ }
root->fs_info = btrfs_alloc_dummy_fs_info();
if (!root->fs_info)
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 418c6a2..be8eae8 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -274,7 +274,6 @@ loop:
cur_trans->num_dirty_bgs = 0;
spin_lock_init(&cur_trans->dirty_bgs_lock);
INIT_LIST_HEAD(&cur_trans->deleted_bgs);
- spin_lock_init(&cur_trans->deleted_bgs_lock);
spin_lock_init(&cur_trans->dropped_roots_lock);
list_add_tail(&cur_trans->list, &fs_info->trans_list);
extent_io_tree_init(&cur_trans->dirty_pages,
@@ -592,6 +591,38 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
return start_transaction(root, num_items, TRANS_START,
BTRFS_RESERVE_FLUSH_ALL);
}
+struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
+ struct btrfs_root *root,
+ unsigned int num_items,
+ int min_factor)
+{
+ struct btrfs_trans_handle *trans;
+ u64 num_bytes;
+ int ret;
+
+ trans = btrfs_start_transaction(root, num_items);
+ if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
+ return trans;
+
+ trans = btrfs_start_transaction(root, 0);
+ if (IS_ERR(trans))
+ return trans;
+
+ num_bytes = btrfs_calc_trans_metadata_size(root, num_items);
+ ret = btrfs_cond_migrate_bytes(root->fs_info,
+ &root->fs_info->trans_block_rsv,
+ num_bytes,
+ min_factor);
+ if (ret) {
+ btrfs_end_transaction(trans, root);
+ return ERR_PTR(ret);
+ }
+
+ trans->block_rsv = &root->fs_info->trans_block_rsv;
+ trans->bytes_reserved = num_bytes;
+
+ return trans;
+}
struct btrfs_trans_handle *btrfs_start_transaction_lflush(
struct btrfs_root *root,
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index b05b2f6..64c8221 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -77,8 +77,8 @@ struct btrfs_transaction {
*/
struct mutex cache_write_mutex;
spinlock_t dirty_bgs_lock;
+ /* Protected by spin lock fs_info->unused_bgs_lock. */
struct list_head deleted_bgs;
- spinlock_t deleted_bgs_lock;
spinlock_t dropped_roots_lock;
struct btrfs_delayed_ref_root delayed_refs;
int aborted;
@@ -185,6 +185,10 @@ int btrfs_end_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root,
unsigned int num_items);
+struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv(
+ struct btrfs_root *root,
+ unsigned int num_items,
+ int min_factor);
struct btrfs_trans_handle *btrfs_start_transaction_lflush(
struct btrfs_root *root,
unsigned int num_items);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 9b2dafa..a23399e 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -1973,8 +1973,7 @@ void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info,
if (srcdev->writeable) {
fs_devices->rw_devices--;
/* zero out the old super if it is writable */
- btrfs_scratch_superblocks(srcdev->bdev,
- rcu_str_deref(srcdev->name));
+ btrfs_scratch_superblocks(srcdev->bdev, srcdev->name->str);
}
if (srcdev->bdev)
@@ -2024,8 +2023,7 @@ void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info,
btrfs_sysfs_rm_device_link(fs_info->fs_devices, tgtdev);
if (tgtdev->bdev) {
- btrfs_scratch_superblocks(tgtdev->bdev,
- rcu_str_deref(tgtdev->name));
+ btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str);
fs_info->fs_devices->open_devices--;
}
fs_info->fs_devices->num_devices--;
@@ -2853,7 +2851,8 @@ static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset)
if (ret)
return ret;
- trans = btrfs_start_transaction(root, 0);
+ trans = btrfs_start_trans_remove_block_group(root->fs_info,
+ chunk_offset);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
btrfs_std_error(root->fs_info, ret, NULL);
@@ -3123,7 +3122,7 @@ static int chunk_profiles_filter(u64 chunk_type,
return 1;
}
-static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
+static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
struct btrfs_balance_args *bargs)
{
struct btrfs_block_group_cache *cache;
@@ -3156,7 +3155,7 @@ static int chunk_usage_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset,
return ret;
}
-static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info,
+static int chunk_usage_filter(struct btrfs_fs_info *fs_info,
u64 chunk_offset, struct btrfs_balance_args *bargs)
{
struct btrfs_block_group_cache *cache;
@@ -3400,6 +3399,7 @@ static int __btrfs_balance(struct btrfs_fs_info *fs_info)
u32 count_data = 0;
u32 count_meta = 0;
u32 count_sys = 0;
+ int chunk_reserved = 0;
/* step one make some room on all the devices */
devices = &fs_info->fs_devices->devices;
@@ -3501,6 +3501,7 @@ again:
ret = should_balance_chunk(chunk_root, leaf, chunk,
found_key.offset);
+
btrfs_release_path(path);
if (!ret) {
mutex_unlock(&fs_info->delete_unused_bgs_mutex);
@@ -3537,6 +3538,24 @@ again:
goto loop;
}
+ if ((chunk_type & BTRFS_BLOCK_GROUP_DATA) && !chunk_reserved) {
+ trans = btrfs_start_transaction(chunk_root, 0);
+ if (IS_ERR(trans)) {
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+ ret = PTR_ERR(trans);
+ goto error;
+ }
+
+ ret = btrfs_force_chunk_alloc(trans, chunk_root,
+ BTRFS_BLOCK_GROUP_DATA);
+ btrfs_end_transaction(trans, chunk_root);
+ if (ret < 0) {
+ mutex_unlock(&fs_info->delete_unused_bgs_mutex);
+ goto error;
+ }
+ chunk_reserved = 1;
+ }
+
ret = btrfs_relocate_chunk(chunk_root,
found_key.offset);
mutex_unlock(&fs_info->delete_unused_bgs_mutex);
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index ec57123..d5c84f6 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -382,7 +382,7 @@ struct map_lookup {
#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5)
#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6)
#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7)
-#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 8)
+#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10)
#define BTRFS_BALANCE_ARGS_MASK \
(BTRFS_BALANCE_ARGS_PROFILES | \
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index 6f518c9..7cbef1a 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -313,8 +313,10 @@ ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
/* check to make sure this item is what we want */
if (found_key.objectid != key.objectid)
break;
- if (found_key.type != BTRFS_XATTR_ITEM_KEY)
+ if (found_key.type > BTRFS_XATTR_ITEM_KEY)
break;
+ if (found_key.type < BTRFS_XATTR_ITEM_KEY)
+ goto next;
di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
if (verify_dir_item(root, leaf, di))
@@ -349,137 +351,89 @@ err:
return ret;
}
-/*
- * List of handlers for synthetic system.* attributes. All real ondisk
- * attributes are handled directly.
- */
-const struct xattr_handler *btrfs_xattr_handlers[] = {
-#ifdef CONFIG_BTRFS_FS_POSIX_ACL
- &posix_acl_access_xattr_handler,
- &posix_acl_default_xattr_handler,
-#endif
- NULL,
-};
-
-/*
- * Check if the attribute is in a supported namespace.
- *
- * This is applied after the check for the synthetic attributes in the system
- * namespace.
- */
-static int btrfs_is_valid_xattr(const char *name)
+static int btrfs_xattr_handler_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- int len = strlen(name);
- int prefixlen = 0;
-
- if (!strncmp(name, XATTR_SECURITY_PREFIX,
- XATTR_SECURITY_PREFIX_LEN))
- prefixlen = XATTR_SECURITY_PREFIX_LEN;
- else if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- prefixlen = XATTR_SYSTEM_PREFIX_LEN;
- else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
- prefixlen = XATTR_TRUSTED_PREFIX_LEN;
- else if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
- prefixlen = XATTR_USER_PREFIX_LEN;
- else if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
- prefixlen = XATTR_BTRFS_PREFIX_LEN;
- else
- return -EOPNOTSUPP;
-
- /*
- * The name cannot consist of just prefix
- */
- if (len <= prefixlen)
- return -EINVAL;
+ struct inode *inode = d_inode(dentry);
- return 0;
+ name = xattr_full_name(handler, name);
+ return __btrfs_getxattr(inode, name, buffer, size);
}
-ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size)
+static int btrfs_xattr_handler_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size,
+ int flags)
{
- int ret;
+ struct inode *inode = d_inode(dentry);
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_getxattr(dentry, name, buffer, size);
+ name = xattr_full_name(handler, name);
+ return __btrfs_setxattr(NULL, inode, name, buffer, size, flags);
+}
- ret = btrfs_is_valid_xattr(name);
- if (ret)
- return ret;
- return __btrfs_getxattr(d_inode(dentry), name, buffer, size);
+static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler,
+ struct dentry *dentry,
+ const char *name, const void *value,
+ size_t size, int flags)
+{
+ name = xattr_full_name(handler, name);
+ return btrfs_set_prop(d_inode(dentry), name, value, size, flags);
}
+static const struct xattr_handler btrfs_security_xattr_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .get = btrfs_xattr_handler_get,
+ .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .get = btrfs_xattr_handler_get,
+ .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_user_xattr_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .get = btrfs_xattr_handler_get,
+ .set = btrfs_xattr_handler_set,
+};
+
+static const struct xattr_handler btrfs_btrfs_xattr_handler = {
+ .prefix = XATTR_BTRFS_PREFIX,
+ .get = btrfs_xattr_handler_get,
+ .set = btrfs_xattr_handler_set_prop,
+};
+
+const struct xattr_handler *btrfs_xattr_handlers[] = {
+ &btrfs_security_xattr_handler,
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
+#endif
+ &btrfs_trusted_xattr_handler,
+ &btrfs_user_xattr_handler,
+ &btrfs_btrfs_xattr_handler,
+ NULL,
+};
+
int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root;
- int ret;
- /*
- * The permission on security.* and system.* is not checked
- * in permission().
- */
if (btrfs_root_readonly(root))
return -EROFS;
-
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_setxattr(dentry, name, value, size, flags);
-
- ret = btrfs_is_valid_xattr(name);
- if (ret)
- return ret;
-
- if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
- return btrfs_set_prop(d_inode(dentry), name,
- value, size, flags);
-
- if (size == 0)
- value = ""; /* empty EA, do not remove */
-
- return __btrfs_setxattr(NULL, d_inode(dentry), name, value, size,
- flags);
+ return generic_setxattr(dentry, name, value, size, flags);
}
int btrfs_removexattr(struct dentry *dentry, const char *name)
{
struct btrfs_root *root = BTRFS_I(d_inode(dentry))->root;
- int ret;
- /*
- * The permission on security.* and system.* is not checked
- * in permission().
- */
if (btrfs_root_readonly(root))
return -EROFS;
-
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_removexattr(dentry, name);
-
- ret = btrfs_is_valid_xattr(name);
- if (ret)
- return ret;
-
- if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
- return btrfs_set_prop(d_inode(dentry), name,
- NULL, 0, XATTR_REPLACE);
-
- return __btrfs_setxattr(NULL, d_inode(dentry), name, NULL, 0,
- XATTR_REPLACE);
+ return generic_removexattr(dentry, name);
}
static int btrfs_initxattrs(struct inode *inode,
diff --git a/fs/btrfs/xattr.h b/fs/btrfs/xattr.h
index 5049608..96807b3 100644
--- a/fs/btrfs/xattr.h
+++ b/fs/btrfs/xattr.h
@@ -28,8 +28,6 @@ extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
extern int __btrfs_setxattr(struct btrfs_trans_handle *trans,
struct inode *inode, const char *name,
const void *value, size_t size, int flags);
-extern ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size);
extern int btrfs_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags);
extern int btrfs_removexattr(struct dentry *dentry, const char *name);
diff --git a/fs/buffer.c b/fs/buffer.c
index 51aff02..e1632ab 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -134,13 +134,10 @@ __clear_page_buffers(struct page *page)
static void buffer_io_error(struct buffer_head *bh, char *msg)
{
- char b[BDEVNAME_SIZE];
-
if (!test_bit(BH_Quiet, &bh->b_state))
printk_ratelimited(KERN_ERR
- "Buffer I/O error on dev %s, logical block %llu%s\n",
- bdevname(bh->b_bdev, b),
- (unsigned long long)bh->b_blocknr, msg);
+ "Buffer I/O error on dev %pg, logical block %llu%s\n",
+ bh->b_bdev, (unsigned long long)bh->b_blocknr, msg);
}
/*
@@ -237,15 +234,13 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
* elsewhere, don't buffer_error if we had some unmapped buffers
*/
if (all_mapped) {
- char b[BDEVNAME_SIZE];
-
printk("__find_get_block_slow() failed. "
"block=%llu, b_blocknr=%llu\n",
(unsigned long long)block,
(unsigned long long)bh->b_blocknr);
printk("b_state=0x%08lx, b_size=%zu\n",
bh->b_state, bh->b_size);
- printk("device %s blocksize: %d\n", bdevname(bdev, b),
+ printk("device %pg blocksize: %d\n", bdev,
1 << bd_inode->i_blkbits);
}
out_unlock:
@@ -531,10 +526,8 @@ repeat:
static void do_thaw_one(struct super_block *sb, void *unused)
{
- char b[BDEVNAME_SIZE];
while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb))
- printk(KERN_WARNING "Emergency Thaw on %s\n",
- bdevname(sb->s_bdev, b));
+ printk(KERN_WARNING "Emergency Thaw on %pg\n", sb->s_bdev);
}
static void do_thaw_all(struct work_struct *work)
@@ -1074,12 +1067,10 @@ grow_buffers(struct block_device *bdev, sector_t block, int size, gfp_t gfp)
* pagecache index. (this comparison is done using sector_t types).
*/
if (unlikely(index != block >> sizebits)) {
- char b[BDEVNAME_SIZE];
-
printk(KERN_ERR "%s: requested out-of-range block %llu for "
- "device %s\n",
+ "device %pg\n",
__func__, (unsigned long long)block,
- bdevname(bdev, b));
+ bdev);
return -EIO;
}
@@ -2420,9 +2411,9 @@ EXPORT_SYMBOL(block_commit_write);
* unlock the page.
*
* Direct callers of this function should protect against filesystem freezing
- * using sb_start_write() - sb_end_write() functions.
+ * using sb_start_pagefault() - sb_end_pagefault() functions.
*/
-int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
+int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
get_block_t get_block)
{
struct page *page = vmf->page;
@@ -2459,26 +2450,6 @@ out_unlock:
unlock_page(page);
return ret;
}
-EXPORT_SYMBOL(__block_page_mkwrite);
-
-int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
- get_block_t get_block)
-{
- int ret;
- struct super_block *sb = file_inode(vma->vm_file)->i_sb;
-
- sb_start_pagefault(sb);
-
- /*
- * Update file times before taking page lock. We may end up failing the
- * fault so this update may be superfluous but who really cares...
- */
- file_update_time(vma->vm_file);
-
- ret = __block_page_mkwrite(vma, vmf, get_block);
- sb_end_pagefault(sb);
- return block_page_mkwrite_return(ret);
-}
EXPORT_SYMBOL(block_page_mkwrite);
/*
diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c
index f601def..452e98d 100644
--- a/fs/cachefiles/daemon.c
+++ b/fs/cachefiles/daemon.c
@@ -226,15 +226,9 @@ static ssize_t cachefiles_daemon_write(struct file *file,
return -EOPNOTSUPP;
/* drag the command string into the kernel so we can parse it */
- data = kmalloc(datalen + 1, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- ret = -EFAULT;
- if (copy_from_user(data, _data, datalen) != 0)
- goto error;
-
- data[datalen] = '\0';
+ data = memdup_user_nul(_data, datalen);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
ret = -EINVAL;
if (memchr(data, '\0', datalen))
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index fc1056f..c4b8934 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -655,6 +655,8 @@ lookup_again:
aops = d_backing_inode(object->dentry)->i_mapping->a_ops;
if (!aops->bmap)
goto check_error;
+ if (object->dentry->d_sb->s_blocksize > PAGE_SIZE)
+ goto check_error;
object->backer = object->dentry;
} else {
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c
index 3cbb0e8..c0f3da3 100644
--- a/fs/cachefiles/rdwr.c
+++ b/fs/cachefiles/rdwr.c
@@ -414,9 +414,6 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
ASSERT(inode->i_mapping->a_ops->readpages);
/* calculate the shift required to use bmap */
- if (inode->i_sb->s_blocksize > PAGE_SIZE)
- goto enobufs;
-
shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
op->op.flags &= FSCACHE_OP_KEEP_FLAGS;
@@ -711,9 +708,6 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
ASSERT(inode->i_mapping->a_ops->readpages);
/* calculate the shift required to use bmap */
- if (inode->i_sb->s_blocksize > PAGE_SIZE)
- goto all_enobufs;
-
shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
pagevec_init(&pagevec, 0);
@@ -885,7 +879,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
loff_t pos, eof;
size_t len;
void *data;
- int ret;
+ int ret = -ENOBUFS;
ASSERT(op != NULL);
ASSERT(page != NULL);
@@ -905,6 +899,15 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
cache = container_of(object->fscache.cache,
struct cachefiles_cache, cache);
+ pos = (loff_t)page->index << PAGE_SHIFT;
+
+ /* We mustn't write more data than we have, so we have to beware of a
+ * partial page at EOF.
+ */
+ eof = object->fscache.store_limit_l;
+ if (pos >= eof)
+ goto error;
+
/* write the page to the backing filesystem and let it store it in its
* own time */
path.mnt = cache->mnt;
@@ -912,40 +915,38 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
file = dentry_open(&path, O_RDWR | O_LARGEFILE, cache->cache_cred);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
- } else {
- pos = (loff_t) page->index << PAGE_SHIFT;
-
- /* we mustn't write more data than we have, so we have
- * to beware of a partial page at EOF */
- eof = object->fscache.store_limit_l;
- len = PAGE_SIZE;
- if (eof & ~PAGE_MASK) {
- ASSERTCMP(pos, <, eof);
- if (eof - pos < PAGE_SIZE) {
- _debug("cut short %llx to %llx",
- pos, eof);
- len = eof - pos;
- ASSERTCMP(pos + len, ==, eof);
- }
- }
-
- data = kmap(page);
- ret = __kernel_write(file, data, len, &pos);
- kunmap(page);
- if (ret != len)
- ret = -EIO;
- fput(file);
+ goto error_2;
}
- if (ret < 0) {
- if (ret == -EIO)
- cachefiles_io_error_obj(
- object, "Write page to backing file failed");
- ret = -ENOBUFS;
+ len = PAGE_SIZE;
+ if (eof & ~PAGE_MASK) {
+ if (eof - pos < PAGE_SIZE) {
+ _debug("cut short %llx to %llx",
+ pos, eof);
+ len = eof - pos;
+ ASSERTCMP(pos + len, ==, eof);
+ }
}
- _leave(" = %d", ret);
- return ret;
+ data = kmap(page);
+ ret = __kernel_write(file, data, len, &pos);
+ kunmap(page);
+ fput(file);
+ if (ret != len)
+ goto error_eio;
+
+ _leave(" = 0");
+ return 0;
+
+error_eio:
+ ret = -EIO;
+error_2:
+ if (ret == -EIO)
+ cachefiles_io_error_obj(object,
+ "Write page to backing file failed");
+error:
+ _leave(" = -ENOBUFS [%d]", ret);
+ return -ENOBUFS;
}
/*
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
index 8f84646..f197084 100644
--- a/fs/ceph/acl.c
+++ b/fs/ceph/acl.c
@@ -49,10 +49,10 @@ struct posix_acl *ceph_get_acl(struct inode *inode, int type)
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
BUG();
@@ -92,7 +92,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
ret = posix_acl_equiv_mode(acl, &new_mode);
if (ret < 0)
@@ -106,7 +106,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
ret = acl ? -EINVAL : 0;
goto out;
}
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
ret = -EINVAL;
@@ -202,11 +202,11 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
ceph_pagelist_encode_32(pagelist, acl && default_acl ? 2 : 1);
if (acl) {
- size_t len = strlen(POSIX_ACL_XATTR_ACCESS);
+ size_t len = strlen(XATTR_NAME_POSIX_ACL_ACCESS);
err = ceph_pagelist_reserve(pagelist, len + val_size1 + 8);
if (err)
goto out_err;
- ceph_pagelist_encode_string(pagelist, POSIX_ACL_XATTR_ACCESS,
+ ceph_pagelist_encode_string(pagelist, XATTR_NAME_POSIX_ACL_ACCESS,
len);
err = posix_acl_to_xattr(&init_user_ns, acl,
tmp_buf, val_size1);
@@ -216,12 +216,12 @@ int ceph_pre_init_acls(struct inode *dir, umode_t *mode,
ceph_pagelist_append(pagelist, tmp_buf, val_size1);
}
if (default_acl) {
- size_t len = strlen(POSIX_ACL_XATTR_DEFAULT);
+ size_t len = strlen(XATTR_NAME_POSIX_ACL_DEFAULT);
err = ceph_pagelist_reserve(pagelist, len + val_size2 + 8);
if (err)
goto out_err;
err = ceph_pagelist_encode_string(pagelist,
- POSIX_ACL_XATTR_DEFAULT, len);
+ XATTR_NAME_POSIX_ACL_DEFAULT, len);
err = posix_acl_to_xattr(&init_user_ns, default_acl,
tmp_buf, val_size2);
if (err < 0)
diff --git a/fs/ceph/cache.c b/fs/ceph/cache.c
index 834f9f3..a4766de 100644
--- a/fs/ceph/cache.c
+++ b/fs/ceph/cache.c
@@ -88,7 +88,7 @@ static uint16_t ceph_fscache_inode_get_key(const void *cookie_netfs_data,
const struct ceph_inode_info* ci = cookie_netfs_data;
uint16_t klen;
- /* use ceph virtual inode (id + snaphot) */
+ /* use ceph virtual inode (id + snapshot) */
klen = sizeof(ci->i_vino);
if (klen > maxbuf)
return 0;
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c
index 27b5668..c69e125 100644
--- a/fs/ceph/caps.c
+++ b/fs/ceph/caps.c
@@ -1655,9 +1655,8 @@ retry_locked:
!S_ISDIR(inode->i_mode) && /* ignore readdir cache */
ci->i_wrbuffer_ref == 0 && /* no dirty pages... */
inode->i_data.nrpages && /* have cached pages */
- (file_wanted == 0 || /* no open files */
- (revoking & (CEPH_CAP_FILE_CACHE|
- CEPH_CAP_FILE_LAZYIO))) && /* or revoking cache */
+ (revoking & (CEPH_CAP_FILE_CACHE|
+ CEPH_CAP_FILE_LAZYIO)) && /* or revoking cache */
!tried_invalidate) {
dout("check_caps trying to invalidate on %p\n", inode);
if (try_nonblocking_invalidate(inode) < 0) {
@@ -1971,49 +1970,46 @@ out:
}
/*
- * wait for any uncommitted directory operations to commit.
+ * wait for any unsafe requests to complete.
*/
-static int unsafe_dirop_wait(struct inode *inode)
+static int unsafe_request_wait(struct inode *inode)
{
struct ceph_inode_info *ci = ceph_inode(inode);
- struct list_head *head = &ci->i_unsafe_dirops;
- struct ceph_mds_request *req;
- u64 last_tid;
- int ret = 0;
-
- if (!S_ISDIR(inode->i_mode))
- return 0;
+ struct ceph_mds_request *req1 = NULL, *req2 = NULL;
+ int ret, err = 0;
spin_lock(&ci->i_unsafe_lock);
- if (list_empty(head))
- goto out;
-
- req = list_last_entry(head, struct ceph_mds_request,
- r_unsafe_dir_item);
- last_tid = req->r_tid;
-
- do {
- ceph_mdsc_get_request(req);
- spin_unlock(&ci->i_unsafe_lock);
+ if (S_ISDIR(inode->i_mode) && !list_empty(&ci->i_unsafe_dirops)) {
+ req1 = list_last_entry(&ci->i_unsafe_dirops,
+ struct ceph_mds_request,
+ r_unsafe_dir_item);
+ ceph_mdsc_get_request(req1);
+ }
+ if (!list_empty(&ci->i_unsafe_iops)) {
+ req2 = list_last_entry(&ci->i_unsafe_iops,
+ struct ceph_mds_request,
+ r_unsafe_target_item);
+ ceph_mdsc_get_request(req2);
+ }
+ spin_unlock(&ci->i_unsafe_lock);
- dout("unsafe_dirop_wait %p wait on tid %llu (until %llu)\n",
- inode, req->r_tid, last_tid);
- ret = !wait_for_completion_timeout(&req->r_safe_completion,
- ceph_timeout_jiffies(req->r_timeout));
+ dout("unsafe_requeset_wait %p wait on tid %llu %llu\n",
+ inode, req1 ? req1->r_tid : 0ULL, req2 ? req2->r_tid : 0ULL);
+ if (req1) {
+ ret = !wait_for_completion_timeout(&req1->r_safe_completion,
+ ceph_timeout_jiffies(req1->r_timeout));
if (ret)
- ret = -EIO; /* timed out */
-
- ceph_mdsc_put_request(req);
-
- spin_lock(&ci->i_unsafe_lock);
- if (ret || list_empty(head))
- break;
- req = list_first_entry(head, struct ceph_mds_request,
- r_unsafe_dir_item);
- } while (req->r_tid < last_tid);
-out:
- spin_unlock(&ci->i_unsafe_lock);
- return ret;
+ err = -EIO;
+ ceph_mdsc_put_request(req1);
+ }
+ if (req2) {
+ ret = !wait_for_completion_timeout(&req2->r_safe_completion,
+ ceph_timeout_jiffies(req2->r_timeout));
+ if (ret)
+ err = -EIO;
+ ceph_mdsc_put_request(req2);
+ }
+ return err;
}
int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
@@ -2039,7 +2035,7 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
dirty = try_flush_caps(inode, &flush_tid);
dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
- ret = unsafe_dirop_wait(inode);
+ ret = unsafe_request_wait(inode);
/*
* only wait on non-file metadata writeback (the mds
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index 0c62868..3c68e6a 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -34,6 +34,74 @@
* need to wait for MDS acknowledgement.
*/
+/*
+ * Calculate the length sum of direct io vectors that can
+ * be combined into one page vector.
+ */
+static size_t dio_get_pagev_size(const struct iov_iter *it)
+{
+ const struct iovec *iov = it->iov;
+ const struct iovec *iovend = iov + it->nr_segs;
+ size_t size;
+
+ size = iov->iov_len - it->iov_offset;
+ /*
+ * An iov can be page vectored when both the current tail
+ * and the next base are page aligned.
+ */
+ while (PAGE_ALIGNED((iov->iov_base + iov->iov_len)) &&
+ (++iov < iovend && PAGE_ALIGNED((iov->iov_base)))) {
+ size += iov->iov_len;
+ }
+ dout("dio_get_pagevlen len = %zu\n", size);
+ return size;
+}
+
+/*
+ * Allocate a page vector based on (@it, @nbytes).
+ * The return value is the tuple describing a page vector,
+ * that is (@pages, @page_align, @num_pages).
+ */
+static struct page **
+dio_get_pages_alloc(const struct iov_iter *it, size_t nbytes,
+ size_t *page_align, int *num_pages)
+{
+ struct iov_iter tmp_it = *it;
+ size_t align;
+ struct page **pages;
+ int ret = 0, idx, npages;
+
+ align = (unsigned long)(it->iov->iov_base + it->iov_offset) &
+ (PAGE_SIZE - 1);
+ npages = calc_pages_for(align, nbytes);
+ pages = kmalloc(sizeof(*pages) * npages, GFP_KERNEL);
+ if (!pages) {
+ pages = vmalloc(sizeof(*pages) * npages);
+ if (!pages)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ for (idx = 0; idx < npages; ) {
+ size_t start;
+ ret = iov_iter_get_pages(&tmp_it, pages + idx, nbytes,
+ npages - idx, &start);
+ if (ret < 0)
+ goto fail;
+
+ iov_iter_advance(&tmp_it, ret);
+ nbytes -= ret;
+ idx += (ret + start + PAGE_SIZE - 1) / PAGE_SIZE;
+ }
+
+ BUG_ON(nbytes != 0);
+ *num_pages = npages;
+ *page_align = align;
+ dout("dio_get_pages_alloc: got %d pages align %zu\n", npages, align);
+ return pages;
+fail:
+ ceph_put_page_vector(pages, idx, false);
+ return ERR_PTR(ret);
+}
/*
* Prepare an open request. Preallocate ceph_cap to avoid an
@@ -458,11 +526,10 @@ static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
size_t start;
ssize_t n;
- n = iov_iter_get_pages_alloc(i, &pages, INT_MAX, &start);
- if (n < 0)
- return n;
-
- num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
+ n = dio_get_pagev_size(i);
+ pages = dio_get_pages_alloc(i, n, &start, &num_pages);
+ if (IS_ERR(pages))
+ return PTR_ERR(pages);
ret = striped_read(inode, off, n,
pages, num_pages, checkeof,
@@ -592,7 +659,7 @@ ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
CEPH_OSD_FLAG_WRITE;
while (iov_iter_count(from) > 0) {
- u64 len = iov_iter_single_seg_count(from);
+ u64 len = dio_get_pagev_size(from);
size_t start;
ssize_t n;
@@ -611,14 +678,14 @@ ceph_sync_direct_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos,
osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC, 0);
- n = iov_iter_get_pages_alloc(from, &pages, len, &start);
- if (unlikely(n < 0)) {
- ret = n;
+ n = len;
+ pages = dio_get_pages_alloc(from, len, &start, &num_pages);
+ if (IS_ERR(pages)) {
ceph_osdc_put_request(req);
+ ret = PTR_ERR(pages);
break;
}
- num_pages = (n + start + PAGE_SIZE - 1) / PAGE_SIZE;
/*
* throw out any page cache pages in this range. this
* may block.
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 96d2bd8..da55eb8 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -452,6 +452,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
INIT_LIST_HEAD(&ci->i_unsafe_writes);
INIT_LIST_HEAD(&ci->i_unsafe_dirops);
+ INIT_LIST_HEAD(&ci->i_unsafe_iops);
spin_lock_init(&ci->i_unsafe_lock);
ci->i_snap_realm = NULL;
@@ -1755,7 +1756,7 @@ retry:
*/
static const struct inode_operations ceph_symlink_iops = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = ceph_setattr,
.getattr = ceph_getattr,
.setxattr = ceph_setxattr,
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index 51cb02d..e7b130a 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -633,13 +633,8 @@ static void __register_request(struct ceph_mds_client *mdsc,
mdsc->oldest_tid = req->r_tid;
if (dir) {
- struct ceph_inode_info *ci = ceph_inode(dir);
-
ihold(dir);
- spin_lock(&ci->i_unsafe_lock);
req->r_unsafe_dir = dir;
- list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
- spin_unlock(&ci->i_unsafe_lock);
}
}
@@ -665,13 +660,20 @@ static void __unregister_request(struct ceph_mds_client *mdsc,
rb_erase(&req->r_node, &mdsc->request_tree);
RB_CLEAR_NODE(&req->r_node);
- if (req->r_unsafe_dir) {
+ if (req->r_unsafe_dir && req->r_got_unsafe) {
struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir);
-
spin_lock(&ci->i_unsafe_lock);
list_del_init(&req->r_unsafe_dir_item);
spin_unlock(&ci->i_unsafe_lock);
+ }
+ if (req->r_target_inode && req->r_got_unsafe) {
+ struct ceph_inode_info *ci = ceph_inode(req->r_target_inode);
+ spin_lock(&ci->i_unsafe_lock);
+ list_del_init(&req->r_unsafe_target_item);
+ spin_unlock(&ci->i_unsafe_lock);
+ }
+ if (req->r_unsafe_dir) {
iput(req->r_unsafe_dir);
req->r_unsafe_dir = NULL;
}
@@ -1430,6 +1432,13 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
if ((used | wanted) & CEPH_CAP_ANY_WR)
goto out;
}
+ /* The inode has cached pages, but it's no longer used.
+ * we can safely drop it */
+ if (wanted == 0 && used == CEPH_CAP_FILE_CACHE &&
+ !(oissued & CEPH_CAP_FILE_CACHE)) {
+ used = 0;
+ oissued = 0;
+ }
if ((used | wanted) & ~oissued & mine)
goto out; /* we need these caps */
@@ -1438,7 +1447,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
/* we aren't the only cap.. just remove us */
__ceph_remove_cap(cap, true);
} else {
- /* try to drop referring dentries */
+ /* try dropping referring dentries */
spin_unlock(&ci->i_ceph_lock);
d_prune_aliases(inode);
dout("trim_caps_cb %p cap %p pruned, count now %d\n",
@@ -1704,6 +1713,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode)
req->r_started = jiffies;
req->r_resend_mds = -1;
INIT_LIST_HEAD(&req->r_unsafe_dir_item);
+ INIT_LIST_HEAD(&req->r_unsafe_target_item);
req->r_fmode = -1;
kref_init(&req->r_kref);
INIT_LIST_HEAD(&req->r_wait);
@@ -1935,7 +1945,7 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
len = sizeof(*head) +
pathlen1 + pathlen2 + 2*(1 + sizeof(u32) + sizeof(u64)) +
- sizeof(struct timespec);
+ sizeof(struct ceph_timespec);
/* calculate (max) length for cap releases */
len += sizeof(struct ceph_mds_request_release) *
@@ -2477,6 +2487,14 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
} else {
req->r_got_unsafe = true;
list_add_tail(&req->r_unsafe_item, &req->r_session->s_unsafe);
+ if (req->r_unsafe_dir) {
+ struct ceph_inode_info *ci =
+ ceph_inode(req->r_unsafe_dir);
+ spin_lock(&ci->i_unsafe_lock);
+ list_add_tail(&req->r_unsafe_dir_item,
+ &ci->i_unsafe_dirops);
+ spin_unlock(&ci->i_unsafe_lock);
+ }
}
dout("handle_reply tid %lld result %d\n", tid, result);
@@ -2518,6 +2536,13 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
up_read(&mdsc->snap_rwsem);
if (realm)
ceph_put_snap_realm(mdsc, realm);
+
+ if (err == 0 && req->r_got_unsafe && req->r_target_inode) {
+ struct ceph_inode_info *ci = ceph_inode(req->r_target_inode);
+ spin_lock(&ci->i_unsafe_lock);
+ list_add_tail(&req->r_unsafe_target_item, &ci->i_unsafe_iops);
+ spin_unlock(&ci->i_unsafe_lock);
+ }
out_err:
mutex_lock(&mdsc->mutex);
if (!req->r_aborted) {
@@ -3917,17 +3942,19 @@ static struct ceph_msg *mds_alloc_msg(struct ceph_connection *con,
return msg;
}
-static int sign_message(struct ceph_connection *con, struct ceph_msg *msg)
+static int mds_sign_message(struct ceph_msg *msg)
{
- struct ceph_mds_session *s = con->private;
+ struct ceph_mds_session *s = msg->con->private;
struct ceph_auth_handshake *auth = &s->s_auth;
+
return ceph_auth_sign_message(auth, msg);
}
-static int check_message_signature(struct ceph_connection *con, struct ceph_msg *msg)
+static int mds_check_message_signature(struct ceph_msg *msg)
{
- struct ceph_mds_session *s = con->private;
+ struct ceph_mds_session *s = msg->con->private;
struct ceph_auth_handshake *auth = &s->s_auth;
+
return ceph_auth_check_message_signature(auth, msg);
}
@@ -3940,8 +3967,8 @@ static const struct ceph_connection_operations mds_con_ops = {
.invalidate_authorizer = invalidate_authorizer,
.peer_reset = peer_reset,
.alloc_msg = mds_alloc_msg,
- .sign_message = sign_message,
- .check_message_signature = check_message_signature,
+ .sign_message = mds_sign_message,
+ .check_message_signature = mds_check_message_signature,
};
/* eof */
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index f575eaf..ccf11ef 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -236,6 +236,9 @@ struct ceph_mds_request {
struct inode *r_unsafe_dir;
struct list_head r_unsafe_dir_item;
+ /* unsafe requests that modify the target inode */
+ struct list_head r_unsafe_target_item;
+
struct ceph_mds_session *r_session;
int r_attempts; /* resend attempts */
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index 2f2460d..75b7d12 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -342,6 +342,7 @@ struct ceph_inode_info {
struct list_head i_unsafe_writes; /* uncommitted sync writes */
struct list_head i_unsafe_dirops; /* uncommitted mds dir ops */
+ struct list_head i_unsafe_iops; /* uncommitted mds inode ops */
spinlock_t i_unsafe_lock;
struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index e739950..b7fcb31 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -454,6 +454,10 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
seq_puts(s, ",nocase");
if (tcon->retry)
seq_puts(s, ",hard");
+ if (tcon->use_persistent)
+ seq_puts(s, ",persistenthandles");
+ else if (tcon->use_resilient)
+ seq_puts(s, ",resilienthandles");
if (tcon->unix_ext)
seq_puts(s, ",unix");
else
@@ -896,8 +900,7 @@ const struct inode_operations cifs_file_inode_ops = {
const struct inode_operations cifs_symlink_inode_ops = {
.readlink = generic_readlink,
- .follow_link = cifs_follow_link,
- .put_link = kfree_put_link,
+ .get_link = cifs_get_link,
.permission = cifs_permission,
/* BB add the following two eventually */
/* revalidate: cifs_revalidate,
@@ -910,6 +913,59 @@ const struct inode_operations cifs_symlink_inode_ops = {
#endif
};
+static int cifs_clone_file_range(struct file *src_file, loff_t off,
+ struct file *dst_file, loff_t destoff, u64 len)
+{
+ struct inode *src_inode = file_inode(src_file);
+ struct inode *target_inode = file_inode(dst_file);
+ struct cifsFileInfo *smb_file_src = src_file->private_data;
+ struct cifsFileInfo *smb_file_target = dst_file->private_data;
+ struct cifs_tcon *target_tcon = tlink_tcon(smb_file_target->tlink);
+ unsigned int xid;
+ int rc;
+
+ cifs_dbg(FYI, "clone range\n");
+
+ xid = get_xid();
+
+ if (!src_file->private_data || !dst_file->private_data) {
+ rc = -EBADF;
+ cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
+ goto out;
+ }
+
+ /*
+ * Note: cifs case is easier than btrfs since server responsible for
+ * checks for proper open modes and file type and if it wants
+ * server could even support copy of range where source = target
+ */
+ lock_two_nondirectories(target_inode, src_inode);
+
+ if (len == 0)
+ len = src_inode->i_size - off;
+
+ cifs_dbg(FYI, "about to flush pages\n");
+ /* should we flush first and last page first */
+ truncate_inode_pages_range(&target_inode->i_data, destoff,
+ PAGE_CACHE_ALIGN(destoff + len)-1);
+
+ if (target_tcon->ses->server->ops->duplicate_extents)
+ rc = target_tcon->ses->server->ops->duplicate_extents(xid,
+ smb_file_src, smb_file_target, off, len, destoff);
+ else
+ rc = -EOPNOTSUPP;
+
+ /* force revalidate of size and timestamps of target file now
+ that target is updated on the server */
+ CIFS_I(target_inode)->time = 0;
+ /* although unlocking in the reverse order from locking is not
+ strictly necessary here it is a little cleaner to be consistent */
+ unlock_two_nondirectories(src_inode, target_inode);
+out:
+ free_xid(xid);
+ return rc;
+}
+
const struct file_operations cifs_file_ops = {
.read_iter = cifs_loose_read_iter,
.write_iter = cifs_file_write_iter,
@@ -921,9 +977,8 @@ const struct file_operations cifs_file_ops = {
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
};
@@ -939,9 +994,9 @@ const struct file_operations cifs_file_strict_ops = {
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
+ .clone_file_range = cifs_clone_file_range,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
};
@@ -957,9 +1012,8 @@ const struct file_operations cifs_file_direct_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
.llseek = cifs_llseek,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
@@ -975,9 +1029,8 @@ const struct file_operations cifs_file_nobrl_ops = {
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
};
@@ -992,9 +1045,8 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
.mmap = cifs_file_strict_mmap,
.splice_read = generic_file_splice_read,
.llseek = cifs_llseek,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
};
@@ -1009,9 +1061,8 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
.flush = cifs_flush,
.mmap = cifs_file_mmap,
.splice_read = generic_file_splice_read,
-#ifdef CONFIG_CIFS_POSIX
.unlocked_ioctl = cifs_ioctl,
-#endif /* CONFIG_CIFS_POSIX */
+ .clone_file_range = cifs_clone_file_range,
.llseek = cifs_llseek,
.setlease = cifs_setlease,
.fallocate = cifs_fallocate,
@@ -1022,6 +1073,7 @@ const struct file_operations cifs_dir_ops = {
.release = cifs_closedir,
.read = generic_read_dir,
.unlocked_ioctl = cifs_ioctl,
+ .clone_file_range = cifs_clone_file_range,
.llseek = generic_file_llseek,
};
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index c3cc160..68c4547 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -120,9 +120,8 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
#endif
/* Functions related to symlinks */
-extern const char *cifs_follow_link(struct dentry *direntry, void **cookie);
-extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
- int buflen);
+extern const char *cifs_get_link(struct dentry *, struct inode *,
+ struct delayed_call *);
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
const char *symname);
extern int cifs_removexattr(struct dentry *, const char *);
@@ -131,7 +130,6 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *,
extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t);
extern ssize_t cifs_listxattr(struct dentry *, char *, size_t);
extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
-
#ifdef CONFIG_CIFS_NFSD_EXPORT
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b406a32..2b510c5 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -493,7 +493,10 @@ struct smb_vol {
bool mfsymlinks:1; /* use Minshall+French Symlinks */
bool multiuser:1;
bool rwpidforward:1; /* pid forward for read/write operations */
- bool nosharesock;
+ bool nosharesock:1;
+ bool persistent:1;
+ bool nopersistent:1;
+ bool resilient:1; /* noresilient not required since not fored for CA */
unsigned int rsize;
unsigned int wsize;
bool sockopt_tcp_nodelay:1;
@@ -895,6 +898,8 @@ struct cifs_tcon {
bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
bool broken_sparse_sup; /* if server or share does not support sparse */
bool need_reconnect:1; /* connection reset, tid now invalid */
+ bool use_resilient:1; /* use resilient instead of durable handles */
+ bool use_persistent:1; /* use persistent instead of durable handles */
#ifdef CONFIG_CIFS_SMB2
bool print:1; /* set if connection to printer share */
bool bad_network_name:1; /* set if ret status STATUS_BAD_NETWORK_NAME */
@@ -1015,6 +1020,7 @@ struct cifs_fid {
__u64 persistent_fid; /* persist file id for smb2 */
__u64 volatile_fid; /* volatile file id for smb2 */
__u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
+ __u8 create_guid[16];
#endif
struct cifs_pending_open *pending_open;
unsigned int epoch;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 3f22285..ecb0803 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -87,6 +87,8 @@ enum {
Opt_sign, Opt_seal, Opt_noac,
Opt_fsc, Opt_mfsymlinks,
Opt_multiuser, Opt_sloppy, Opt_nosharesock,
+ Opt_persistent, Opt_nopersistent,
+ Opt_resilient, Opt_noresilient,
/* Mount options which take numeric value */
Opt_backupuid, Opt_backupgid, Opt_uid,
@@ -169,6 +171,10 @@ static const match_table_t cifs_mount_option_tokens = {
{ Opt_multiuser, "multiuser" },
{ Opt_sloppy, "sloppy" },
{ Opt_nosharesock, "nosharesock" },
+ { Opt_persistent, "persistenthandles"},
+ { Opt_nopersistent, "nopersistenthandles"},
+ { Opt_resilient, "resilienthandles"},
+ { Opt_noresilient, "noresilienthandles"},
{ Opt_backupuid, "backupuid=%s" },
{ Opt_backupgid, "backupgid=%s" },
@@ -1497,6 +1503,33 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
case Opt_nosharesock:
vol->nosharesock = true;
break;
+ case Opt_nopersistent:
+ vol->nopersistent = true;
+ if (vol->persistent) {
+ cifs_dbg(VFS,
+ "persistenthandles mount options conflict\n");
+ goto cifs_parse_mount_err;
+ }
+ break;
+ case Opt_persistent:
+ vol->persistent = true;
+ if ((vol->nopersistent) || (vol->resilient)) {
+ cifs_dbg(VFS,
+ "persistenthandles mount options conflict\n");
+ goto cifs_parse_mount_err;
+ }
+ break;
+ case Opt_resilient:
+ vol->resilient = true;
+ if (vol->persistent) {
+ cifs_dbg(VFS,
+ "persistenthandles mount options conflict\n");
+ goto cifs_parse_mount_err;
+ }
+ break;
+ case Opt_noresilient:
+ vol->resilient = false; /* already the default */
+ break;
/* Numeric Values */
case Opt_backupuid:
@@ -2655,6 +2688,42 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
cifs_dbg(FYI, "DFS disabled (%d)\n", tcon->Flags);
}
tcon->seal = volume_info->seal;
+ tcon->use_persistent = false;
+ /* check if SMB2 or later, CIFS does not support persistent handles */
+ if (volume_info->persistent) {
+ if (ses->server->vals->protocol_id == 0) {
+ cifs_dbg(VFS,
+ "SMB3 or later required for persistent handles\n");
+ rc = -EOPNOTSUPP;
+ goto out_fail;
+#ifdef CONFIG_CIFS_SMB2
+ } else if (ses->server->capabilities &
+ SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
+ tcon->use_persistent = true;
+ else /* persistent handles requested but not supported */ {
+ cifs_dbg(VFS,
+ "Persistent handles not supported on share\n");
+ rc = -EOPNOTSUPP;
+ goto out_fail;
+#endif /* CONFIG_CIFS_SMB2 */
+ }
+#ifdef CONFIG_CIFS_SMB2
+ } else if ((tcon->capabilities & SMB2_SHARE_CAP_CONTINUOUS_AVAILABILITY)
+ && (ses->server->capabilities & SMB2_GLOBAL_CAP_PERSISTENT_HANDLES)
+ && (volume_info->nopersistent == false)) {
+ cifs_dbg(FYI, "enabling persistent handles\n");
+ tcon->use_persistent = true;
+#endif /* CONFIG_CIFS_SMB2 */
+ } else if (volume_info->resilient) {
+ if (ses->server->vals->protocol_id == 0) {
+ cifs_dbg(VFS,
+ "SMB2.1 or later required for resilient handles\n");
+ rc = -EOPNOTSUPP;
+ goto out_fail;
+ }
+ tcon->use_resilient = true;
+ }
+
/*
* We can have only one retry value for a connection to a share so for
* resources mounted more than once to the same server share the last
@@ -3503,6 +3572,15 @@ try_mount_again:
goto mount_fail_check;
}
+#ifdef CONFIG_CIFS_SMB2
+ if ((volume_info->persistent == true) && ((ses->server->capabilities &
+ SMB2_GLOBAL_CAP_PERSISTENT_HANDLES) == 0)) {
+ cifs_dbg(VFS, "persistent handles not supported by server\n");
+ rc = -EOPNOTSUPP;
+ goto mount_fail_check;
+ }
+#endif /* CONFIG_CIFS_SMB2*/
+
/* search for existing tcon to this server share */
tcon = cifs_get_tcon(ses, volume_info);
if (IS_ERR(tcon)) {
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 6b66dd5..a329f5b 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1831,11 +1831,11 @@ cifs_invalidate_mapping(struct inode *inode)
* @word: long word containing the bit lock
*/
static int
-cifs_wait_bit_killable(struct wait_bit_key *key)
+cifs_wait_bit_killable(struct wait_bit_key *key, int mode)
{
- if (fatal_signal_pending(current))
- return -ERESTARTSYS;
freezable_schedule_unsafe();
+ if (signal_pending_state(mode, current))
+ return -ERESTARTSYS;
return 0;
}
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index 28a77bf..7a3b84e 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -34,68 +34,36 @@
#include "cifs_ioctl.h"
#include <linux/btrfs.h>
-static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
- unsigned long srcfd, u64 off, u64 len, u64 destoff,
- bool dup_extents)
+static int cifs_file_clone_range(unsigned int xid, struct file *src_file,
+ struct file *dst_file)
{
- int rc;
- struct cifsFileInfo *smb_file_target = dst_file->private_data;
+ struct inode *src_inode = file_inode(src_file);
struct inode *target_inode = file_inode(dst_file);
- struct cifs_tcon *target_tcon;
- struct fd src_file;
struct cifsFileInfo *smb_file_src;
- struct inode *src_inode;
+ struct cifsFileInfo *smb_file_target;
struct cifs_tcon *src_tcon;
+ struct cifs_tcon *target_tcon;
+ int rc;
cifs_dbg(FYI, "ioctl clone range\n");
- /* the destination must be opened for writing */
- if (!(dst_file->f_mode & FMODE_WRITE)) {
- cifs_dbg(FYI, "file target not open for write\n");
- return -EINVAL;
- }
-
- /* check if target volume is readonly and take reference */
- rc = mnt_want_write_file(dst_file);
- if (rc) {
- cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
- return rc;
- }
- src_file = fdget(srcfd);
- if (!src_file.file) {
- rc = -EBADF;
- goto out_drop_write;
- }
-
- if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
- rc = -EBADF;
- cifs_dbg(VFS, "src file seems to be from a different filesystem type\n");
- goto out_fput;
- }
-
- if ((!src_file.file->private_data) || (!dst_file->private_data)) {
+ if (!src_file->private_data || !dst_file->private_data) {
rc = -EBADF;
cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n");
- goto out_fput;
+ goto out;
}
rc = -EXDEV;
smb_file_target = dst_file->private_data;
- smb_file_src = src_file.file->private_data;
+ smb_file_src = src_file->private_data;
src_tcon = tlink_tcon(smb_file_src->tlink);
target_tcon = tlink_tcon(smb_file_target->tlink);
- /* check if source and target are on same tree connection */
- if (src_tcon != target_tcon) {
- cifs_dbg(VFS, "file copy src and target on different volume\n");
- goto out_fput;
+ if (src_tcon->ses != target_tcon->ses) {
+ cifs_dbg(VFS, "source and target of copy not on same server\n");
+ goto out;
}
- src_inode = file_inode(src_file.file);
- rc = -EINVAL;
- if (S_ISDIR(src_inode->i_mode))
- goto out_fput;
-
/*
* Note: cifs case is easier than btrfs since server responsible for
* checks for proper open modes and file type and if it wants
@@ -103,34 +71,66 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
*/
lock_two_nondirectories(target_inode, src_inode);
- /* determine range to clone */
- rc = -EINVAL;
- if (off + len > src_inode->i_size || off + len < off)
- goto out_unlock;
- if (len == 0)
- len = src_inode->i_size - off;
-
cifs_dbg(FYI, "about to flush pages\n");
/* should we flush first and last page first */
- truncate_inode_pages_range(&target_inode->i_data, destoff,
- PAGE_CACHE_ALIGN(destoff + len)-1);
+ truncate_inode_pages(&target_inode->i_data, 0);
- if (dup_extents && target_tcon->ses->server->ops->duplicate_extents)
- rc = target_tcon->ses->server->ops->duplicate_extents(xid,
- smb_file_src, smb_file_target, off, len, destoff);
- else if (!dup_extents && target_tcon->ses->server->ops->clone_range)
+ if (target_tcon->ses->server->ops->clone_range)
rc = target_tcon->ses->server->ops->clone_range(xid,
- smb_file_src, smb_file_target, off, len, destoff);
+ smb_file_src, smb_file_target, 0, src_inode->i_size, 0);
else
rc = -EOPNOTSUPP;
/* force revalidate of size and timestamps of target file now
that target is updated on the server */
CIFS_I(target_inode)->time = 0;
-out_unlock:
/* although unlocking in the reverse order from locking is not
strictly necessary here it is a little cleaner to be consistent */
unlock_two_nondirectories(src_inode, target_inode);
+out:
+ return rc;
+}
+
+static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file,
+ unsigned long srcfd)
+{
+ int rc;
+ struct fd src_file;
+ struct inode *src_inode;
+
+ cifs_dbg(FYI, "ioctl clone range\n");
+ /* the destination must be opened for writing */
+ if (!(dst_file->f_mode & FMODE_WRITE)) {
+ cifs_dbg(FYI, "file target not open for write\n");
+ return -EINVAL;
+ }
+
+ /* check if target volume is readonly and take reference */
+ rc = mnt_want_write_file(dst_file);
+ if (rc) {
+ cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc);
+ return rc;
+ }
+
+ src_file = fdget(srcfd);
+ if (!src_file.file) {
+ rc = -EBADF;
+ goto out_drop_write;
+ }
+
+ if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) {
+ rc = -EBADF;
+ cifs_dbg(VFS, "src file seems to be from a different filesystem type\n");
+ goto out_fput;
+ }
+
+ src_inode = file_inode(src_file.file);
+ rc = -EINVAL;
+ if (S_ISDIR(src_inode->i_mode))
+ goto out_fput;
+
+ rc = cifs_file_clone_range(xid, src_file.file, dst_file);
+
out_fput:
fdput(src_file);
out_drop_write:
@@ -251,10 +251,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg)
}
break;
case CIFS_IOC_COPYCHUNK_FILE:
- rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0, false);
- break;
- case BTRFS_IOC_CLONE:
- rc = cifs_ioctl_clone(xid, filep, arg, 0, 0, 0, true);
+ rc = cifs_ioctl_clone(xid, filep, arg);
break;
case CIFS_IOC_SET_INTEGRITY:
if (pSMBFile == NULL)
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index e3548f7..062c237 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -627,9 +627,9 @@ cifs_hl_exit:
}
const char *
-cifs_follow_link(struct dentry *direntry, void **cookie)
+cifs_get_link(struct dentry *direntry, struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(direntry);
int rc = -ENOMEM;
unsigned int xid;
char *full_path = NULL;
@@ -639,6 +639,9 @@ cifs_follow_link(struct dentry *direntry, void **cookie)
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
+ if (!direntry)
+ return ERR_PTR(-ECHILD);
+
xid = get_xid();
tlink = cifs_sb_tlink(cifs_sb);
@@ -678,7 +681,8 @@ cifs_follow_link(struct dentry *direntry, void **cookie)
kfree(target_path);
return ERR_PTR(rc);
}
- return *cookie = target_path;
+ set_delayed_call(done, kfree_link, target_path);
+ return target_path;
}
int
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 2ab297d..f9e766f 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -43,6 +43,7 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
struct smb2_file_all_info *smb2_data = NULL;
__u8 smb2_oplock[17];
struct cifs_fid *fid = oparms->fid;
+ struct network_resiliency_req nr_ioctl_req;
smb2_path = cifs_convert_path_to_utf16(oparms->path, oparms->cifs_sb);
if (smb2_path == NULL) {
@@ -67,6 +68,24 @@ smb2_open_file(const unsigned int xid, struct cifs_open_parms *oparms,
if (rc)
goto out;
+
+ if (oparms->tcon->use_resilient) {
+ nr_ioctl_req.Timeout = 0; /* use server default (120 seconds) */
+ nr_ioctl_req.Reserved = 0;
+ rc = SMB2_ioctl(xid, oparms->tcon, fid->persistent_fid,
+ fid->volatile_fid, FSCTL_LMR_REQUEST_RESILIENCY, true,
+ (char *)&nr_ioctl_req, sizeof(nr_ioctl_req),
+ NULL, NULL /* no return info */);
+ if (rc == -EOPNOTSUPP) {
+ cifs_dbg(VFS,
+ "resiliency not supported by server, disabling\n");
+ oparms->tcon->use_resilient = false;
+ } else if (rc)
+ cifs_dbg(FYI, "error %d setting resiliency\n", rc);
+
+ rc = 0;
+ }
+
if (buf) {
/* open response does not have IndexNumber field - get it */
rc = SMB2_get_srv_num(xid, oparms->tcon, fid->persistent_fid,
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 18da19f..53ccdde 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -810,7 +810,6 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
cfile->fid.volatile_fid, cfile->pid, &eof, false);
}
-#ifdef CONFIG_CIFS_SMB311
static int
smb2_duplicate_extents(const unsigned int xid,
struct cifsFileInfo *srcfile,
@@ -854,8 +853,6 @@ smb2_duplicate_extents(const unsigned int xid,
duplicate_extents_out:
return rc;
}
-#endif /* CONFIG_CIFS_SMB311 */
-
static int
smb2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
@@ -1703,6 +1700,7 @@ struct smb_version_operations smb30_operations = {
.create_lease_buf = smb3_create_lease_buf,
.parse_lease_buf = smb3_parse_lease_buf,
.clone_range = smb2_clone_range,
+ .duplicate_extents = smb2_duplicate_extents,
.validate_negotiate = smb3_validate_negotiate,
.wp_retry_size = smb2_wp_retry_size,
.dir_needs_close = smb2_dir_needs_close,
@@ -1840,7 +1838,7 @@ struct smb_version_values smb21_values = {
struct smb_version_values smb30_values = {
.version_string = SMB30_VERSION_STRING,
.protocol_id = SMB30_PROT_ID,
- .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+ .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
.large_lock_type = 0,
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
@@ -1860,7 +1858,7 @@ struct smb_version_values smb30_values = {
struct smb_version_values smb302_values = {
.version_string = SMB302_VERSION_STRING,
.protocol_id = SMB302_PROT_ID,
- .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+ .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
.large_lock_type = 0,
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
@@ -1881,7 +1879,7 @@ struct smb_version_values smb302_values = {
struct smb_version_values smb311_values = {
.version_string = SMB311_VERSION_STRING,
.protocol_id = SMB311_PROT_ID,
- .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU,
+ .req_capabilities = SMB2_GLOBAL_CAP_DFS | SMB2_GLOBAL_CAP_LEASING | SMB2_GLOBAL_CAP_LARGE_MTU | SMB2_GLOBAL_CAP_PERSISTENT_HANDLES,
.large_lock_type = 0,
.exclusive_lock_type = SMB2_LOCKFLAG_EXCLUSIVE_LOCK,
.shared_lock_type = SMB2_LOCKFLAG_SHARED_LOCK,
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6127692..7675555 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1151,13 +1151,130 @@ add_lease_context(struct TCP_Server_Info *server, struct kvec *iov,
return 0;
}
+static struct create_durable_v2 *
+create_durable_v2_buf(struct cifs_fid *pfid)
+{
+ struct create_durable_v2 *buf;
+
+ buf = kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->ccontext.DataOffset = cpu_to_le16(offsetof
+ (struct create_durable_v2, dcontext));
+ buf->ccontext.DataLength = cpu_to_le32(sizeof(struct durable_context_v2));
+ buf->ccontext.NameOffset = cpu_to_le16(offsetof
+ (struct create_durable_v2, Name));
+ buf->ccontext.NameLength = cpu_to_le16(4);
+
+ buf->dcontext.Timeout = 0; /* Should this be configurable by workload */
+ buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+ get_random_bytes(buf->dcontext.CreateGuid, 16);
+ memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16);
+
+ /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */
+ buf->Name[0] = 'D';
+ buf->Name[1] = 'H';
+ buf->Name[2] = '2';
+ buf->Name[3] = 'Q';
+ return buf;
+}
+
+static struct create_durable_handle_reconnect_v2 *
+create_reconnect_durable_v2_buf(struct cifs_fid *fid)
+{
+ struct create_durable_handle_reconnect_v2 *buf;
+
+ buf = kzalloc(sizeof(struct create_durable_handle_reconnect_v2),
+ GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ buf->ccontext.DataOffset =
+ cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+ dcontext));
+ buf->ccontext.DataLength =
+ cpu_to_le32(sizeof(struct durable_reconnect_context_v2));
+ buf->ccontext.NameOffset =
+ cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2,
+ Name));
+ buf->ccontext.NameLength = cpu_to_le16(4);
+
+ buf->dcontext.Fid.PersistentFileId = fid->persistent_fid;
+ buf->dcontext.Fid.VolatileFileId = fid->volatile_fid;
+ buf->dcontext.Flags = cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT);
+ memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16);
+
+ /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */
+ buf->Name[0] = 'D';
+ buf->Name[1] = 'H';
+ buf->Name[2] = '2';
+ buf->Name[3] = 'C';
+ return buf;
+}
+
static int
-add_durable_context(struct kvec *iov, unsigned int *num_iovec,
+add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec,
struct cifs_open_parms *oparms)
{
struct smb2_create_req *req = iov[0].iov_base;
unsigned int num = *num_iovec;
+ iov[num].iov_base = create_durable_v2_buf(oparms->fid);
+ if (iov[num].iov_base == NULL)
+ return -ENOMEM;
+ iov[num].iov_len = sizeof(struct create_durable_v2);
+ if (!req->CreateContextsOffset)
+ req->CreateContextsOffset =
+ cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+ iov[1].iov_len);
+ le32_add_cpu(&req->CreateContextsLength, sizeof(struct create_durable_v2));
+ inc_rfc1001_len(&req->hdr, sizeof(struct create_durable_v2));
+ *num_iovec = num + 1;
+ return 0;
+}
+
+static int
+add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec,
+ struct cifs_open_parms *oparms)
+{
+ struct smb2_create_req *req = iov[0].iov_base;
+ unsigned int num = *num_iovec;
+
+ /* indicate that we don't need to relock the file */
+ oparms->reconnect = false;
+
+ iov[num].iov_base = create_reconnect_durable_v2_buf(oparms->fid);
+ if (iov[num].iov_base == NULL)
+ return -ENOMEM;
+ iov[num].iov_len = sizeof(struct create_durable_handle_reconnect_v2);
+ if (!req->CreateContextsOffset)
+ req->CreateContextsOffset =
+ cpu_to_le32(sizeof(struct smb2_create_req) - 4 +
+ iov[1].iov_len);
+ le32_add_cpu(&req->CreateContextsLength,
+ sizeof(struct create_durable_handle_reconnect_v2));
+ inc_rfc1001_len(&req->hdr,
+ sizeof(struct create_durable_handle_reconnect_v2));
+ *num_iovec = num + 1;
+ return 0;
+}
+
+static int
+add_durable_context(struct kvec *iov, unsigned int *num_iovec,
+ struct cifs_open_parms *oparms, bool use_persistent)
+{
+ struct smb2_create_req *req = iov[0].iov_base;
+ unsigned int num = *num_iovec;
+
+ if (use_persistent) {
+ if (oparms->reconnect)
+ return add_durable_reconnect_v2_context(iov, num_iovec,
+ oparms);
+ else
+ return add_durable_v2_context(iov, num_iovec, oparms);
+ }
+
if (oparms->reconnect) {
iov[num].iov_base = create_reconnect_durable_buf(oparms->fid);
/* indicate that we don't need to relock the file */
@@ -1275,7 +1392,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
ccontext->Next =
cpu_to_le32(server->vals->create_lease_size);
}
- rc = add_durable_context(iov, &num_iovecs, oparms);
+
+ rc = add_durable_context(iov, &num_iovecs, oparms,
+ tcon->use_persistent);
if (rc) {
cifs_small_buf_release(req);
kfree(copy_path);
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 4511082..4af5278 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -590,6 +590,44 @@ struct create_durable {
} Data;
} __packed;
+/* See MS-SMB2 2.2.13.2.11 */
+/* Flags */
+#define SMB2_DHANDLE_FLAG_PERSISTENT 0x00000002
+struct durable_context_v2 {
+ __le32 Timeout;
+ __le32 Flags;
+ __u64 Reserved;
+ __u8 CreateGuid[16];
+} __packed;
+
+struct create_durable_v2 {
+ struct create_context ccontext;
+ __u8 Name[8];
+ struct durable_context_v2 dcontext;
+} __packed;
+
+/* See MS-SMB2 2.2.13.2.12 */
+struct durable_reconnect_context_v2 {
+ struct {
+ __u64 PersistentFileId;
+ __u64 VolatileFileId;
+ } Fid;
+ __u8 CreateGuid[16];
+ __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
+} __packed;
+
+/* See MS-SMB2 2.2.14.2.12 */
+struct durable_reconnect_context_v2_rsp {
+ __le32 Timeout;
+ __le32 Flags; /* see above DHANDLE_FLAG_PERSISTENT */
+} __packed;
+
+struct create_durable_handle_reconnect_v2 {
+ struct create_context ccontext;
+ __u8 Name[8];
+ struct durable_reconnect_context_v2 dcontext;
+} __packed;
+
#define COPY_CHUNK_RES_KEY_SIZE 24
struct resume_key_req {
char ResumeKey[COPY_CHUNK_RES_KEY_SIZE];
@@ -643,6 +681,13 @@ struct fsctl_get_integrity_information_rsp {
/* Integrity flags for above */
#define FSCTL_INTEGRITY_FLAG_CHECKSUM_ENFORCEMENT_OFF 0x00000001
+/* See MS-SMB2 2.2.31.3 */
+struct network_resiliency_req {
+ __le32 Timeout;
+ __le32 Reserved;
+} __packed;
+/* There is no buffer for the response ie no struct network_resiliency_rsp */
+
struct validate_negotiate_info_req {
__le32 Capabilities;
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index a639d0d..f996dae 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -90,7 +90,7 @@
#define FSCTL_SRV_ENUMERATE_SNAPSHOTS 0x00144064
/* Retrieve an opaque file reference for server-side data movement ie copy */
#define FSCTL_SRV_REQUEST_RESUME_KEY 0x00140078
-#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4 /* BB add struct */
+#define FSCTL_LMR_REQUEST_RESILIENCY 0x001401D4
#define FSCTL_LMR_GET_LINK_TRACK_INF 0x001400E8 /* BB add struct */
#define FSCTL_LMR_SET_LINK_TRACK_INF 0x001400EC /* BB add struct */
#define FSCTL_VALIDATE_NEGOTIATE_INFO 0x00140204
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index ff9e1f8..f5dc2f0 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -190,8 +190,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
#endif /* CONFIG_CIFS_ACL */
} else {
int temp;
- temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
- strlen(POSIX_ACL_XATTR_ACCESS));
+ temp = strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
+ strlen(XATTR_NAME_POSIX_ACL_ACCESS));
if (temp == 0) {
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & MS_POSIXACL)
@@ -203,8 +203,8 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name,
#else
cifs_dbg(FYI, "set POSIX ACL not supported\n");
#endif
- } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
- strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+ } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
+ strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
@@ -292,8 +292,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon,
full_path, ea_name, ea_value, buf_size,
cifs_sb->local_nls, cifs_remap(cifs_sb));
- } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
- strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
+ } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS,
+ strlen(XATTR_NAME_POSIX_ACL_ACCESS)) == 0) {
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
@@ -303,8 +303,8 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
#else
cifs_dbg(FYI, "Query POSIX ACL not supported yet\n");
#endif /* CONFIG_CIFS_POSIX */
- } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
- strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
+ } else if (strncmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT,
+ strlen(XATTR_NAME_POSIX_ACL_DEFAULT)) == 0) {
#ifdef CONFIG_CIFS_POSIX
if (sb->s_flags & MS_POSIXACL)
rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c
index 7740b1c..1bfb7ba 100644
--- a/fs/coda/cnode.c
+++ b/fs/coda/cnode.c
@@ -8,6 +8,7 @@
#include <linux/coda.h>
#include <linux/coda_psdev.h>
+#include <linux/pagemap.h>
#include "coda_linux.h"
static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
@@ -17,8 +18,7 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2)
static const struct inode_operations coda_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = coda_setattr,
};
@@ -35,6 +35,7 @@ static void coda_fill_inode(struct inode *inode, struct coda_vattr *attr)
inode->i_fop = &coda_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &coda_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &coda_symlink_aops;
inode->i_mapping = &inode->i_data;
} else
diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c
index ab94ef6..03736e2 100644
--- a/fs/coda/symlink.c
+++ b/fs/coda/symlink.c
@@ -26,7 +26,7 @@ static int coda_symlink_filler(struct file *file, struct page *page)
int error;
struct coda_inode_info *cii;
unsigned int len = PAGE_SIZE;
- char *p = kmap(page);
+ char *p = page_address(page);
cii = ITOC(inode);
@@ -34,13 +34,11 @@ static int coda_symlink_filler(struct file *file, struct page *page)
if (error)
goto fail;
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
fail:
SetPageError(page);
- kunmap(page);
unlock_page(page);
return error;
}
diff --git a/fs/compat.c b/fs/compat.c
index 6fd272d..a71936a 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -792,7 +792,7 @@ COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
const void __user *, data)
{
char *kernel_type;
- unsigned long data_page;
+ void *options;
char *kernel_dev;
int retval;
@@ -806,26 +806,25 @@ COMPAT_SYSCALL_DEFINE5(mount, const char __user *, dev_name,
if (IS_ERR(kernel_dev))
goto out1;
- retval = copy_mount_options(data, &data_page);
- if (retval < 0)
+ options = copy_mount_options(data);
+ retval = PTR_ERR(options);
+ if (IS_ERR(options))
goto out2;
- retval = -EINVAL;
-
- if (kernel_type && data_page) {
+ if (kernel_type && options) {
if (!strcmp(kernel_type, NCPFS_NAME)) {
- do_ncp_super_data_conv((void *)data_page);
+ do_ncp_super_data_conv(options);
} else if (!strcmp(kernel_type, NFS4_NAME)) {
- if (do_nfs4_super_data_conv((void *) data_page))
+ retval = -EINVAL;
+ if (do_nfs4_super_data_conv(options))
goto out3;
}
}
- retval = do_mount(kernel_dev, dir_name, kernel_type,
- flags, (void*)data_page);
+ retval = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
out3:
- free_page(data_page);
+ kfree(options);
out2:
kfree(kernel_dev);
out1:
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 48851f6..a5b8eb6 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -58,6 +58,8 @@
#include <linux/atalk.h>
#include <linux/gfp.h>
+#include "internal.h"
+
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/rfcomm.h>
@@ -115,19 +117,38 @@
#include <asm/fbio.h>
#endif
-static int w_long(unsigned int fd, unsigned int cmd,
- compat_ulong_t __user *argp)
+#define convert_in_user(srcptr, dstptr) \
+({ \
+ typeof(*srcptr) val; \
+ \
+ get_user(val, srcptr) || put_user(val, dstptr); \
+})
+
+static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- mm_segment_t old_fs = get_fs();
int err;
- unsigned long val;
- set_fs (KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long)&val);
- set_fs (old_fs);
- if (!err && put_user(val, argp))
+ err = security_file_ioctl(file, cmd, arg);
+ if (err)
+ return err;
+
+ return vfs_ioctl(file, cmd, arg);
+}
+
+static int w_long(struct file *file,
+ unsigned int cmd, compat_ulong_t __user *argp)
+{
+ int err;
+ unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
+
+ if (valp == NULL)
return -EFAULT;
- return err;
+ err = do_ioctl(file, cmd, (unsigned long)valp);
+ if (err)
+ return err;
+ if (convert_in_user(valp, argp))
+ return -EFAULT;
+ return 0;
}
struct compat_video_event {
@@ -139,23 +160,23 @@ struct compat_video_event {
} u;
};
-static int do_video_get_event(unsigned int fd, unsigned int cmd,
- struct compat_video_event __user *up)
+static int do_video_get_event(struct file *file,
+ unsigned int cmd, struct compat_video_event __user *up)
{
- struct video_event kevent;
- mm_segment_t old_fs = get_fs();
+ struct video_event __user *kevent =
+ compat_alloc_user_space(sizeof(*kevent));
int err;
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
- set_fs(old_fs);
+ if (kevent == NULL)
+ return -EFAULT;
+ err = do_ioctl(file, cmd, (unsigned long)kevent);
if (!err) {
- err = put_user(kevent.type, &up->type);
- err |= put_user(kevent.timestamp, &up->timestamp);
- err |= put_user(kevent.u.size.w, &up->u.size.w);
- err |= put_user(kevent.u.size.h, &up->u.size.h);
- err |= put_user(kevent.u.size.aspect_ratio,
+ err = convert_in_user(&kevent->type, &up->type);
+ err |= convert_in_user(&kevent->timestamp, &up->timestamp);
+ err |= convert_in_user(&kevent->u.size.w, &up->u.size.w);
+ err |= convert_in_user(&kevent->u.size.h, &up->u.size.h);
+ err |= convert_in_user(&kevent->u.size.aspect_ratio,
&up->u.size.aspect_ratio);
if (err)
err = -EFAULT;
@@ -169,8 +190,8 @@ struct compat_video_still_picture {
int32_t size;
};
-static int do_video_stillpicture(unsigned int fd, unsigned int cmd,
- struct compat_video_still_picture __user *up)
+static int do_video_stillpicture(struct file *file,
+ unsigned int cmd, struct compat_video_still_picture __user *up)
{
struct video_still_picture __user *up_native;
compat_uptr_t fp;
@@ -190,7 +211,7 @@ static int do_video_stillpicture(unsigned int fd, unsigned int cmd,
if (err)
return -EFAULT;
- err = sys_ioctl(fd, cmd, (unsigned long) up_native);
+ err = do_ioctl(file, cmd, (unsigned long) up_native);
return err;
}
@@ -200,8 +221,8 @@ struct compat_video_spu_palette {
compat_uptr_t palette;
};
-static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
- struct compat_video_spu_palette __user *up)
+static int do_video_set_spu_palette(struct file *file,
+ unsigned int cmd, struct compat_video_spu_palette __user *up)
{
struct video_spu_palette __user *up_native;
compat_uptr_t palp;
@@ -218,7 +239,7 @@ static int do_video_set_spu_palette(unsigned int fd, unsigned int cmd,
if (err)
return -EFAULT;
- err = sys_ioctl(fd, cmd, (unsigned long) up_native);
+ err = do_ioctl(file, cmd, (unsigned long) up_native);
return err;
}
@@ -276,7 +297,7 @@ static int sg_build_iovec(sg_io_hdr_t __user *sgio, void __user *dxferp, u16 iov
return 0;
}
-static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
+static int sg_ioctl_trans(struct file *file, unsigned int cmd,
sg_io_hdr32_t __user *sgio32)
{
sg_io_hdr_t __user *sgio;
@@ -289,7 +310,7 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
if (get_user(interface_id, &sgio32->interface_id))
return -EFAULT;
if (interface_id != 'S')
- return sys_ioctl(fd, cmd, (unsigned long)sgio32);
+ return do_ioctl(file, cmd, (unsigned long)sgio32);
if (get_user(iovec_count, &sgio32->iovec_count))
return -EFAULT;
@@ -349,7 +370,7 @@ static int sg_ioctl_trans(unsigned int fd, unsigned int cmd,
if (put_user(compat_ptr(data), &sgio->usr_ptr))
return -EFAULT;
- err = sys_ioctl(fd, cmd, (unsigned long) sgio);
+ err = do_ioctl(file, cmd, (unsigned long) sgio);
if (err >= 0) {
void __user *datap;
@@ -380,13 +401,13 @@ struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
int unused;
};
-static int sg_grt_trans(unsigned int fd, unsigned int cmd, struct
- compat_sg_req_info __user *o)
+static int sg_grt_trans(struct file *file,
+ unsigned int cmd, struct compat_sg_req_info __user *o)
{
int err, i;
sg_req_info_t __user *r;
r = compat_alloc_user_space(sizeof(sg_req_info_t)*SG_MAX_QUEUE);
- err = sys_ioctl(fd,cmd,(unsigned long)r);
+ err = do_ioctl(file, cmd, (unsigned long)r);
if (err < 0)
return err;
for (i = 0; i < SG_MAX_QUEUE; i++) {
@@ -412,8 +433,8 @@ struct sock_fprog32 {
#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32)
#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32)
-static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd,
- struct sock_fprog32 __user *u_fprog32)
+static int ppp_sock_fprog_ioctl_trans(struct file *file,
+ unsigned int cmd, struct sock_fprog32 __user *u_fprog32)
{
struct sock_fprog __user *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
void __user *fptr64;
@@ -435,7 +456,7 @@ static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd,
else
cmd = PPPIOCSACTIVE;
- return sys_ioctl(fd, cmd, (unsigned long) u_fprog64);
+ return do_ioctl(file, cmd, (unsigned long) u_fprog64);
}
struct ppp_option_data32 {
@@ -451,7 +472,7 @@ struct ppp_idle32 {
};
#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
-static int ppp_gidle(unsigned int fd, unsigned int cmd,
+static int ppp_gidle(struct file *file, unsigned int cmd,
struct ppp_idle32 __user *idle32)
{
struct ppp_idle __user *idle;
@@ -460,7 +481,7 @@ static int ppp_gidle(unsigned int fd, unsigned int cmd,
idle = compat_alloc_user_space(sizeof(*idle));
- err = sys_ioctl(fd, PPPIOCGIDLE, (unsigned long) idle);
+ err = do_ioctl(file, PPPIOCGIDLE, (unsigned long) idle);
if (!err) {
if (get_user(xmit, &idle->xmit_idle) ||
@@ -472,7 +493,7 @@ static int ppp_gidle(unsigned int fd, unsigned int cmd,
return err;
}
-static int ppp_scompress(unsigned int fd, unsigned int cmd,
+static int ppp_scompress(struct file *file, unsigned int cmd,
struct ppp_option_data32 __user *odata32)
{
struct ppp_option_data __user *odata;
@@ -492,7 +513,7 @@ static int ppp_scompress(unsigned int fd, unsigned int cmd,
sizeof(__u32) + sizeof(int)))
return -EFAULT;
- return sys_ioctl(fd, PPPIOCSCOMPRESS, (unsigned long) odata);
+ return do_ioctl(file, PPPIOCSCOMPRESS, (unsigned long) odata);
}
#ifdef CONFIG_BLOCK
@@ -512,12 +533,13 @@ struct mtpos32 {
};
#define MTIOCPOS32 _IOR('m', 3, struct mtpos32)
-static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
+static int mt_ioctl_trans(struct file *file,
+ unsigned int cmd, void __user *argp)
{
- mm_segment_t old_fs = get_fs();
- struct mtget get;
+ /* NULL initialization to make gcc shut up */
+ struct mtget __user *get = NULL;
struct mtget32 __user *umget32;
- struct mtpos pos;
+ struct mtpos __user *pos = NULL;
struct mtpos32 __user *upos32;
unsigned long kcmd;
void *karg;
@@ -526,32 +548,34 @@ static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, void __user *argp)
switch(cmd) {
case MTIOCPOS32:
kcmd = MTIOCPOS;
- karg = &pos;
+ pos = compat_alloc_user_space(sizeof(*pos));
+ karg = pos;
break;
default: /* MTIOCGET32 */
kcmd = MTIOCGET;
- karg = &get;
+ get = compat_alloc_user_space(sizeof(*get));
+ karg = get;
break;
}
- set_fs (KERNEL_DS);
- err = sys_ioctl (fd, kcmd, (unsigned long)karg);
- set_fs (old_fs);
+ if (karg == NULL)
+ return -EFAULT;
+ err = do_ioctl(file, kcmd, (unsigned long)karg);
if (err)
return err;
switch (cmd) {
case MTIOCPOS32:
upos32 = argp;
- err = __put_user(pos.mt_blkno, &upos32->mt_blkno);
+ err = convert_in_user(&pos->mt_blkno, &upos32->mt_blkno);
break;
case MTIOCGET32:
umget32 = argp;
- err = __put_user(get.mt_type, &umget32->mt_type);
- err |= __put_user(get.mt_resid, &umget32->mt_resid);
- err |= __put_user(get.mt_dsreg, &umget32->mt_dsreg);
- err |= __put_user(get.mt_gstat, &umget32->mt_gstat);
- err |= __put_user(get.mt_erreg, &umget32->mt_erreg);
- err |= __put_user(get.mt_fileno, &umget32->mt_fileno);
- err |= __put_user(get.mt_blkno, &umget32->mt_blkno);
+ err = convert_in_user(&get->mt_type, &umget32->mt_type);
+ err |= convert_in_user(&get->mt_resid, &umget32->mt_resid);
+ err |= convert_in_user(&get->mt_dsreg, &umget32->mt_dsreg);
+ err |= convert_in_user(&get->mt_gstat, &umget32->mt_gstat);
+ err |= convert_in_user(&get->mt_erreg, &umget32->mt_erreg);
+ err |= convert_in_user(&get->mt_fileno, &umget32->mt_fileno);
+ err |= convert_in_user(&get->mt_blkno, &umget32->mt_blkno);
break;
}
return err ? -EFAULT: 0;
@@ -605,42 +629,41 @@ struct serial_struct32 {
compat_int_t reserved[1];
};
-static int serial_struct_ioctl(unsigned fd, unsigned cmd,
- struct serial_struct32 __user *ss32)
+static int serial_struct_ioctl(struct file *file,
+ unsigned cmd, struct serial_struct32 __user *ss32)
{
typedef struct serial_struct32 SS32;
int err;
- struct serial_struct ss;
- mm_segment_t oldseg = get_fs();
+ struct serial_struct __user *ss = compat_alloc_user_space(sizeof(*ss));
__u32 udata;
unsigned int base;
+ unsigned char *iomem_base;
+ if (ss == NULL)
+ return -EFAULT;
if (cmd == TIOCSSERIAL) {
- if (!access_ok(VERIFY_READ, ss32, sizeof(SS32)))
- return -EFAULT;
- if (__copy_from_user(&ss, ss32, offsetof(SS32, iomem_base)))
- return -EFAULT;
- if (__get_user(udata, &ss32->iomem_base))
+ if (copy_in_user(ss, ss32, offsetof(SS32, iomem_base)) ||
+ get_user(udata, &ss32->iomem_base))
return -EFAULT;
- ss.iomem_base = compat_ptr(udata);
- if (__get_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
- __get_user(ss.port_high, &ss32->port_high))
+ iomem_base = compat_ptr(udata);
+ if (put_user(iomem_base, &ss->iomem_base) ||
+ convert_in_user(&ss32->iomem_reg_shift,
+ &ss->iomem_reg_shift) ||
+ convert_in_user(&ss32->port_high, &ss->port_high) ||
+ put_user(0UL, &ss->iomap_base))
return -EFAULT;
- ss.iomap_base = 0UL;
}
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd,cmd,(unsigned long)(&ss));
- set_fs(oldseg);
+ err = do_ioctl(file, cmd, (unsigned long)ss);
if (cmd == TIOCGSERIAL && err >= 0) {
- if (!access_ok(VERIFY_WRITE, ss32, sizeof(SS32)))
- return -EFAULT;
- if (__copy_to_user(ss32,&ss,offsetof(SS32,iomem_base)))
+ if (copy_in_user(ss32, ss, offsetof(SS32, iomem_base)) ||
+ get_user(iomem_base, &ss->iomem_base))
return -EFAULT;
- base = (unsigned long)ss.iomem_base >> 32 ?
- 0xffffffff : (unsigned)(unsigned long)ss.iomem_base;
- if (__put_user(base, &ss32->iomem_base) ||
- __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) ||
- __put_user(ss.port_high, &ss32->port_high))
+ base = (unsigned long)iomem_base >> 32 ?
+ 0xffffffff : (unsigned)(unsigned long)iomem_base;
+ if (put_user(base, &ss32->iomem_base) ||
+ convert_in_user(&ss->iomem_reg_shift,
+ &ss32->iomem_reg_shift) ||
+ convert_in_user(&ss->port_high, &ss32->port_high))
return -EFAULT;
}
return err;
@@ -674,8 +697,8 @@ struct i2c_rdwr_aligned {
struct i2c_msg msgs[0];
};
-static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
- struct i2c_rdwr_ioctl_data32 __user *udata)
+static int do_i2c_rdwr_ioctl(struct file *file,
+ unsigned int cmd, struct i2c_rdwr_ioctl_data32 __user *udata)
{
struct i2c_rdwr_aligned __user *tdata;
struct i2c_msg __user *tmsgs;
@@ -686,7 +709,7 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
if (get_user(nmsgs, &udata->nmsgs))
return -EFAULT;
- if (nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
+ if (nmsgs > I2C_RDWR_IOCTL_MAX_MSGS)
return -EINVAL;
if (get_user(datap, &udata->msgs))
@@ -708,11 +731,11 @@ static int do_i2c_rdwr_ioctl(unsigned int fd, unsigned int cmd,
put_user(compat_ptr(datap), &tmsgs[i].buf))
return -EFAULT;
}
- return sys_ioctl(fd, cmd, (unsigned long)tdata);
+ return do_ioctl(file, cmd, (unsigned long)tdata);
}
-static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
- struct i2c_smbus_ioctl_data32 __user *udata)
+static int do_i2c_smbus_ioctl(struct file *file,
+ unsigned int cmd, struct i2c_smbus_ioctl_data32 __user *udata)
{
struct i2c_smbus_ioctl_data __user *tdata;
compat_caddr_t datap;
@@ -734,7 +757,7 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
__put_user(compat_ptr(datap), &tdata->data))
return -EFAULT;
- return sys_ioctl(fd, cmd, (unsigned long)tdata);
+ return do_ioctl(file, cmd, (unsigned long)tdata);
}
#define RTC_IRQP_READ32 _IOR('p', 0x0b, compat_ulong_t)
@@ -742,29 +765,27 @@ static int do_i2c_smbus_ioctl(unsigned int fd, unsigned int cmd,
#define RTC_EPOCH_READ32 _IOR('p', 0x0d, compat_ulong_t)
#define RTC_EPOCH_SET32 _IOW('p', 0x0e, compat_ulong_t)
-static int rtc_ioctl(unsigned fd, unsigned cmd, void __user *argp)
+static int rtc_ioctl(struct file *file,
+ unsigned cmd, void __user *argp)
{
- mm_segment_t oldfs = get_fs();
- compat_ulong_t val32;
- unsigned long kval;
+ unsigned long __user *valp = compat_alloc_user_space(sizeof(*valp));
int ret;
+ if (valp == NULL)
+ return -EFAULT;
switch (cmd) {
case RTC_IRQP_READ32:
case RTC_EPOCH_READ32:
- set_fs(KERNEL_DS);
- ret = sys_ioctl(fd, (cmd == RTC_IRQP_READ32) ?
+ ret = do_ioctl(file, (cmd == RTC_IRQP_READ32) ?
RTC_IRQP_READ : RTC_EPOCH_READ,
- (unsigned long)&kval);
- set_fs(oldfs);
+ (unsigned long)valp);
if (ret)
return ret;
- val32 = kval;
- return put_user(val32, (unsigned int __user *)argp);
+ return convert_in_user(valp, (unsigned int __user *)argp);
case RTC_IRQP_SET32:
- return sys_ioctl(fd, RTC_IRQP_SET, (unsigned long)argp);
+ return do_ioctl(file, RTC_IRQP_SET, (unsigned long)argp);
case RTC_EPOCH_SET32:
- return sys_ioctl(fd, RTC_EPOCH_SET, (unsigned long)argp);
+ return do_ioctl(file, RTC_EPOCH_SET, (unsigned long)argp);
}
return -ENOIOCTLCMD;
@@ -1284,12 +1305,6 @@ COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* NBD */
-COMPATIBLE_IOCTL(NBD_DO_IT)
-COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
-COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
-COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
-COMPATIBLE_IOCTL(NBD_DISCONNECT)
/* i2c */
COMPATIBLE_IOCTL(I2C_SLAVE)
COMPATIBLE_IOCTL(I2C_SLAVE_FORCE)
@@ -1436,53 +1451,53 @@ IGNORE_IOCTL(FBIOGCURSOR32)
* a compat_ioctl operation in the place that handleѕ the
* ioctl for the native case.
*/
-static long do_ioctl_trans(int fd, unsigned int cmd,
+static long do_ioctl_trans(unsigned int cmd,
unsigned long arg, struct file *file)
{
void __user *argp = compat_ptr(arg);
switch (cmd) {
case PPPIOCGIDLE32:
- return ppp_gidle(fd, cmd, argp);
+ return ppp_gidle(file, cmd, argp);
case PPPIOCSCOMPRESS32:
- return ppp_scompress(fd, cmd, argp);
+ return ppp_scompress(file, cmd, argp);
case PPPIOCSPASS32:
case PPPIOCSACTIVE32:
- return ppp_sock_fprog_ioctl_trans(fd, cmd, argp);
+ return ppp_sock_fprog_ioctl_trans(file, cmd, argp);
#ifdef CONFIG_BLOCK
case SG_IO:
- return sg_ioctl_trans(fd, cmd, argp);
+ return sg_ioctl_trans(file, cmd, argp);
case SG_GET_REQUEST_TABLE:
- return sg_grt_trans(fd, cmd, argp);
+ return sg_grt_trans(file, cmd, argp);
case MTIOCGET32:
case MTIOCPOS32:
- return mt_ioctl_trans(fd, cmd, argp);
+ return mt_ioctl_trans(file, cmd, argp);
#endif
/* Serial */
case TIOCGSERIAL:
case TIOCSSERIAL:
- return serial_struct_ioctl(fd, cmd, argp);
+ return serial_struct_ioctl(file, cmd, argp);
/* i2c */
case I2C_FUNCS:
- return w_long(fd, cmd, argp);
+ return w_long(file, cmd, argp);
case I2C_RDWR:
- return do_i2c_rdwr_ioctl(fd, cmd, argp);
+ return do_i2c_rdwr_ioctl(file, cmd, argp);
case I2C_SMBUS:
- return do_i2c_smbus_ioctl(fd, cmd, argp);
+ return do_i2c_smbus_ioctl(file, cmd, argp);
/* Not implemented in the native kernel */
case RTC_IRQP_READ32:
case RTC_IRQP_SET32:
case RTC_EPOCH_READ32:
case RTC_EPOCH_SET32:
- return rtc_ioctl(fd, cmd, argp);
+ return rtc_ioctl(file, cmd, argp);
/* dvb */
case VIDEO_GET_EVENT:
- return do_video_get_event(fd, cmd, argp);
+ return do_video_get_event(file, cmd, argp);
case VIDEO_STILLPICTURE:
- return do_video_stillpicture(fd, cmd, argp);
+ return do_video_stillpicture(file, cmd, argp);
case VIDEO_SET_SPU_PALETTE:
- return do_video_set_spu_palette(fd, cmd, argp);
+ return do_video_set_spu_palette(file, cmd, argp);
}
/*
@@ -1508,12 +1523,7 @@ static long do_ioctl_trans(int fd, unsigned int cmd,
case KDSKBMETA:
case KDSKBLED:
case KDSETLED:
- /* NBD */
- case NBD_SET_SOCK:
- case NBD_SET_BLKSIZE:
- case NBD_SET_SIZE:
- case NBD_SET_SIZE_BLOCKS:
- return do_vfs_ioctl(file, fd, cmd, arg);
+ return vfs_ioctl(file, cmd, arg);
}
return -ENOIOCTLCMD;
@@ -1580,6 +1590,11 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
goto out_fput;
#endif
+ case FICLONE:
+ case FICLONERANGE:
+ case FIDEDUPERANGE:
+ goto do_ioctl;
+
case FIBMAP:
case FIGETBSZ:
case FIONREAD:
@@ -1602,7 +1617,7 @@ COMPAT_SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd,
if (compat_ioctl_check_table(XFORM(cmd)))
goto found_handler;
- error = do_ioctl_trans(fd, cmd, arg, f.file);
+ error = do_ioctl_trans(cmd, arg, f.file);
if (error == -ENOIOCTLCMD)
error = -ENOTTY;
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index c81ce7f..a7a1b21 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1636,6 +1636,116 @@ const struct file_operations configfs_dir_operations = {
.iterate = configfs_readdir,
};
+/**
+ * configfs_register_group - creates a parent-child relation between two groups
+ * @parent_group: parent group
+ * @group: child group
+ *
+ * link groups, creates dentry for the child and attaches it to the
+ * parent dentry.
+ *
+ * Return: 0 on success, negative errno code on error
+ */
+int configfs_register_group(struct config_group *parent_group,
+ struct config_group *group)
+{
+ struct configfs_subsystem *subsys = parent_group->cg_subsys;
+ struct dentry *parent;
+ int ret;
+
+ mutex_lock(&subsys->su_mutex);
+ link_group(parent_group, group);
+ mutex_unlock(&subsys->su_mutex);
+
+ parent = parent_group->cg_item.ci_dentry;
+
+ mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+ ret = create_default_group(parent_group, group);
+ if (!ret) {
+ spin_lock(&configfs_dirent_lock);
+ configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
+ spin_unlock(&configfs_dirent_lock);
+ }
+ mutex_unlock(&d_inode(parent)->i_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(configfs_register_group);
+
+/**
+ * configfs_unregister_group() - unregisters a child group from its parent
+ * @group: parent group to be unregistered
+ *
+ * Undoes configfs_register_group()
+ */
+void configfs_unregister_group(struct config_group *group)
+{
+ struct configfs_subsystem *subsys = group->cg_subsys;
+ struct dentry *dentry = group->cg_item.ci_dentry;
+ struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
+
+ mutex_lock_nested(&d_inode(parent)->i_mutex, I_MUTEX_PARENT);
+ spin_lock(&configfs_dirent_lock);
+ configfs_detach_prep(dentry, NULL);
+ spin_unlock(&configfs_dirent_lock);
+
+ configfs_detach_group(&group->cg_item);
+ d_inode(dentry)->i_flags |= S_DEAD;
+ dont_mount(dentry);
+ d_delete(dentry);
+ mutex_unlock(&d_inode(parent)->i_mutex);
+
+ dput(dentry);
+
+ mutex_lock(&subsys->su_mutex);
+ unlink_group(group);
+ mutex_unlock(&subsys->su_mutex);
+}
+EXPORT_SYMBOL(configfs_unregister_group);
+
+/**
+ * configfs_register_default_group() - allocates and registers a child group
+ * @parent_group: parent group
+ * @name: child group name
+ * @item_type: child item type description
+ *
+ * boilerplate to allocate and register a child group with its parent. We need
+ * kzalloc'ed memory because child's default_group is initially empty.
+ *
+ * Return: allocated config group or ERR_PTR() on error
+ */
+struct config_group *
+configfs_register_default_group(struct config_group *parent_group,
+ const char *name,
+ struct config_item_type *item_type)
+{
+ int ret;
+ struct config_group *group;
+
+ group = kzalloc(sizeof(*group), GFP_KERNEL);
+ if (!group)
+ return ERR_PTR(-ENOMEM);
+ config_group_init_type_name(group, name, item_type);
+
+ ret = configfs_register_group(parent_group, group);
+ if (ret) {
+ kfree(group);
+ return ERR_PTR(ret);
+ }
+ return group;
+}
+EXPORT_SYMBOL(configfs_register_default_group);
+
+/**
+ * configfs_unregister_default_group() - unregisters and frees a child group
+ * @group: the group to act on
+ */
+void configfs_unregister_default_group(struct config_group *group)
+{
+ configfs_unregister_group(group);
+ kfree(group);
+}
+EXPORT_SYMBOL(configfs_unregister_default_group);
+
int configfs_register_subsystem(struct configfs_subsystem *subsys)
{
int err;
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 403269f..d39099e 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -65,7 +65,6 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
{
struct configfs_attribute * attr = to_attr(dentry);
struct config_item * item = to_item(dentry->d_parent);
- struct configfs_item_operations * ops = buffer->ops;
int ret = 0;
ssize_t count;
@@ -74,7 +73,8 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf
if (!buffer->page)
return -ENOMEM;
- count = ops->show_attribute(item,attr,buffer->page);
+ count = attr->show(item, buffer->page);
+
buffer->needs_read_fill = 0;
BUG_ON(count > (ssize_t)SIMPLE_ATTR_SIZE);
if (count >= 0)
@@ -171,9 +171,8 @@ flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size
{
struct configfs_attribute * attr = to_attr(dentry);
struct config_item * item = to_item(dentry->d_parent);
- struct configfs_item_operations * ops = buffer->ops;
- return ops->store_attribute(item,attr,buffer->page,count);
+ return attr->store(item, buffer->page, count);
}
@@ -237,8 +236,7 @@ static int check_perm(struct inode * inode, struct file * file)
* and we must have a store method.
*/
if (file->f_mode & FMODE_WRITE) {
-
- if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute)
+ if (!(inode->i_mode & S_IWUGO) || !attr->store)
goto Eaccess;
}
@@ -248,7 +246,7 @@ static int check_perm(struct inode * inode, struct file * file)
* must be a show method for it.
*/
if (file->f_mode & FMODE_READ) {
- if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute)
+ if (!(inode->i_mode & S_IRUGO) || !attr->show)
goto Eaccess;
}
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index ec5c832..db6d692 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -279,27 +279,33 @@ static int configfs_getlink(struct dentry *dentry, char * path)
}
-static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *configfs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *body;
int error;
- if (!page)
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!body)
return ERR_PTR(-ENOMEM);
- error = configfs_getlink(dentry, (char *)page);
+ error = configfs_getlink(dentry, body);
if (!error) {
- return *cookie = (void *)page;
+ set_delayed_call(done, kfree_link, body);
+ return body;
}
- free_page(page);
+ kfree(body);
return ERR_PTR(error);
}
const struct inode_operations configfs_symlink_inode_operations = {
- .follow_link = configfs_follow_link,
+ .get_link = configfs_get_link,
.readlink = generic_readlink,
- .put_link = free_page_put_link,
.setattr = configfs_setattr,
};
diff --git a/fs/coredump.c b/fs/coredump.c
index 1777331..b3c153c 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -32,6 +32,7 @@
#include <linux/pipe_fs_i.h>
#include <linux/oom.h>
#include <linux/compat.h>
+#include <linux/timekeeping.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -232,9 +233,10 @@ static int format_corename(struct core_name *cn, struct coredump_params *cprm)
break;
/* UNIX time of coredump */
case 't': {
- struct timeval tv;
- do_gettimeofday(&tv);
- err = cn_printf(cn, "%lu", tv.tv_sec);
+ time64_t time;
+
+ time = ktime_get_real_seconds();
+ err = cn_printf(cn, "%lld", time);
break;
}
/* hostname */
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 355c522..b862bc2 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -100,6 +100,7 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &cramfs_aops;
break;
default:
diff --git a/fs/dax.c b/fs/dax.c
index a86d3cc..43671b6 100644
--- a/fs/dax.c
+++ b/fs/dax.c
@@ -29,6 +29,11 @@
#include <linux/uio.h>
#include <linux/vmstat.h>
+/*
+ * dax_clear_blocks() is called from within transaction context from XFS,
+ * and hence this means the stack from this point must follow GFP_NOFS
+ * semantics for all operations.
+ */
int dax_clear_blocks(struct inode *inode, sector_t block, long size)
{
struct block_device *bdev = inode->i_sb->s_bdev;
@@ -169,8 +174,10 @@ static ssize_t dax_io(struct inode *inode, struct iov_iter *iter,
else
len = iov_iter_zero(max - pos, iter);
- if (!len)
+ if (!len) {
+ retval = -EFAULT;
break;
+ }
pos += len;
addr += len;
@@ -534,6 +541,10 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
unsigned long pfn;
int result = 0;
+ /* dax pmd mappings are broken wrt gup and fork */
+ if (!IS_ENABLED(CONFIG_FS_DAX_PMD))
+ return VM_FAULT_FALLBACK;
+
/* Fall back to PTEs if we're going to COW */
if (write && !(vma->vm_flags & VM_SHARED))
return VM_FAULT_FALLBACK;
@@ -622,6 +633,13 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address,
if ((length < PMD_SIZE) || (pfn & PG_PMD_COLOUR))
goto fallback;
+ /*
+ * TODO: teach vmf_insert_pfn_pmd() to support
+ * 'pte_special' for pmds
+ */
+ if (pfn_valid(pfn))
+ goto fallback;
+
if (buffer_unwritten(&bh) || buffer_new(&bh)) {
int i;
for (i = 0; i < PTRS_PER_PMD; i++)
diff --git a/fs/dcache.c b/fs/dcache.c
index 5c33aeb..8d38cd0 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -1734,7 +1734,7 @@ static unsigned d_flags_for_inode(struct inode *inode)
}
if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
- if (unlikely(inode->i_op->follow_link)) {
+ if (unlikely(inode->i_op->get_link)) {
add_flags = DCACHE_SYMLINK_TYPE;
goto type_determined;
}
@@ -3303,18 +3303,18 @@ out:
* @new_dentry: new dentry
* @old_dentry: old dentry
*
- * Returns 1 if new_dentry is a subdirectory of the parent (at any depth).
- * Returns 0 otherwise.
+ * Returns true if new_dentry is a subdirectory of the parent (at any depth).
+ * Returns false otherwise.
* Caller must ensure that "new_dentry" is pinned before calling is_subdir()
*/
-int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
+bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
{
- int result;
+ bool result;
unsigned seq;
if (new_dentry == old_dentry)
- return 1;
+ return true;
do {
/* for restarting inner loop in case of seq retry */
@@ -3325,9 +3325,9 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
*/
rcu_read_lock();
if (d_ancestor(old_dentry, new_dentry))
- result = 1;
+ result = true;
else
- result = 0;
+ result = false;
rcu_read_unlock();
} while (read_seqretry(&rename_lock, seq));
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 5d8f35f..b7fcc0d 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -271,8 +271,12 @@ static struct dentry *start_creating(const char *name, struct dentry *parent)
dput(dentry);
dentry = ERR_PTR(-EEXIST);
}
- if (IS_ERR(dentry))
+
+ if (IS_ERR(dentry)) {
mutex_unlock(&d_inode(parent)->i_mutex);
+ simple_release_fs(&debugfs_mount, &debugfs_mount_count);
+ }
+
return dentry;
}
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 18e7554..602e844 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -109,6 +109,8 @@ struct dio_submit {
struct dio {
int flags; /* doesn't change */
int rw;
+ blk_qc_t bio_cookie;
+ struct block_device *bio_bdev;
struct inode *inode;
loff_t i_size; /* i_size when submitted */
dio_iodone_t *end_io; /* IO completion function */
@@ -397,11 +399,14 @@ static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio)
if (dio->is_async && dio->rw == READ && dio->should_dirty)
bio_set_pages_dirty(bio);
- if (sdio->submit_io)
+ dio->bio_bdev = bio->bi_bdev;
+
+ if (sdio->submit_io) {
sdio->submit_io(dio->rw, bio, dio->inode,
sdio->logical_offset_in_bio);
- else
- submit_bio(dio->rw, bio);
+ dio->bio_cookie = BLK_QC_T_NONE;
+ } else
+ dio->bio_cookie = submit_bio(dio->rw, bio);
sdio->bio = NULL;
sdio->boundary = 0;
@@ -440,7 +445,8 @@ static struct bio *dio_await_one(struct dio *dio)
__set_current_state(TASK_UNINTERRUPTIBLE);
dio->waiter = current;
spin_unlock_irqrestore(&dio->bio_lock, flags);
- io_schedule();
+ if (!blk_poll(bdev_get_queue(dio->bio_bdev), dio->bio_cookie))
+ io_schedule();
/* wake up sets us TASK_RUNNING */
spin_lock_irqsave(&dio->bio_lock, flags);
dio->waiter = NULL;
@@ -1163,6 +1169,16 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
}
}
+ /* Once we sampled i_size check for reads beyond EOF */
+ dio->i_size = i_size_read(inode);
+ if (iov_iter_rw(iter) == READ && offset >= dio->i_size) {
+ if (dio->flags & DIO_LOCKING)
+ mutex_unlock(&inode->i_mutex);
+ kmem_cache_free(dio_cache, dio);
+ retval = 0;
+ goto out;
+ }
+
/*
* For file extending writes updating i_size before data writeouts
* complete can expose uninitialized blocks in dumb filesystems.
@@ -1216,7 +1232,6 @@ do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode,
sdio.next_block_for_io = -1;
dio->iocb = iocb;
- dio->i_size = i_size_read(inode);
spin_lock_init(&dio->bio_lock);
dio->refcount = 1;
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
index d521bdd..8e294fb 100644
--- a/fs/dlm/config.c
+++ b/fs/dlm/config.c
@@ -61,35 +61,8 @@ static struct config_item *make_node(struct config_group *, const char *);
static void drop_node(struct config_group *, struct config_item *);
static void release_node(struct config_item *);
-static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
- char *buf);
-static ssize_t store_cluster(struct config_item *i,
- struct configfs_attribute *a,
- const char *buf, size_t len);
-static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
- char *buf);
-static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
- const char *buf, size_t len);
-static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
- char *buf);
-static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
- const char *buf, size_t len);
-
-static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf);
-static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf,
- size_t len);
-static ssize_t comm_local_read(struct dlm_comm *cm, char *buf);
-static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,
- size_t len);
-static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf,
- size_t len);
-static ssize_t comm_addr_list_read(struct dlm_comm *cm, char *buf);
-static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf);
-static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,
- size_t len);
-static ssize_t node_weight_read(struct dlm_node *nd, char *buf);
-static ssize_t node_weight_write(struct dlm_node *nd, const char *buf,
- size_t len);
+static struct configfs_attribute *comm_attrs[];
+static struct configfs_attribute *node_attrs[];
struct dlm_cluster {
struct config_group group;
@@ -108,6 +81,12 @@ struct dlm_cluster {
char cl_cluster_name[DLM_LOCKSPACE_LEN];
};
+static struct dlm_cluster *config_item_to_cluster(struct config_item *i)
+{
+ return i ? container_of(to_config_group(i), struct dlm_cluster, group) :
+ NULL;
+}
+
enum {
CLUSTER_ATTR_TCP_PORT = 0,
CLUSTER_ATTR_BUFFER_SIZE,
@@ -124,33 +103,24 @@ enum {
CLUSTER_ATTR_CLUSTER_NAME,
};
-struct cluster_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct dlm_cluster *, char *);
- ssize_t (*store)(struct dlm_cluster *, const char *, size_t);
-};
-
-static ssize_t cluster_cluster_name_read(struct dlm_cluster *cl, char *buf)
+static ssize_t cluster_cluster_name_show(struct config_item *item, char *buf)
{
+ struct dlm_cluster *cl = config_item_to_cluster(item);
return sprintf(buf, "%s\n", cl->cl_cluster_name);
}
-static ssize_t cluster_cluster_name_write(struct dlm_cluster *cl,
+static ssize_t cluster_cluster_name_store(struct config_item *item,
const char *buf, size_t len)
{
+ struct dlm_cluster *cl = config_item_to_cluster(item);
+
strlcpy(dlm_config.ci_cluster_name, buf,
sizeof(dlm_config.ci_cluster_name));
strlcpy(cl->cl_cluster_name, buf, sizeof(cl->cl_cluster_name));
return len;
}
-static struct cluster_attribute cluster_attr_cluster_name = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "cluster_name",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = cluster_cluster_name_read,
- .store = cluster_cluster_name_write,
-};
+CONFIGFS_ATTR(cluster_, cluster_name);
static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
int *info_field, int check_zero,
@@ -175,17 +145,19 @@ static ssize_t cluster_set(struct dlm_cluster *cl, unsigned int *cl_field,
}
#define CLUSTER_ATTR(name, check_zero) \
-static ssize_t name##_write(struct dlm_cluster *cl, const char *buf, size_t len) \
+static ssize_t cluster_##name##_store(struct config_item *item, \
+ const char *buf, size_t len) \
{ \
+ struct dlm_cluster *cl = config_item_to_cluster(item); \
return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name, \
check_zero, buf, len); \
} \
-static ssize_t name##_read(struct dlm_cluster *cl, char *buf) \
+static ssize_t cluster_##name##_show(struct config_item *item, char *buf) \
{ \
+ struct dlm_cluster *cl = config_item_to_cluster(item); \
return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name); \
} \
-static struct cluster_attribute cluster_attr_##name = \
-__CONFIGFS_ATTR(name, 0644, name##_read, name##_write)
+CONFIGFS_ATTR(cluster_, name);
CLUSTER_ATTR(tcp_port, 1);
CLUSTER_ATTR(buffer_size, 1);
@@ -201,19 +173,19 @@ CLUSTER_ATTR(new_rsb_count, 0);
CLUSTER_ATTR(recover_callbacks, 0);
static struct configfs_attribute *cluster_attrs[] = {
- [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
- [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr,
- [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr,
- [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr,
- [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
- [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
- [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
- [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol.attr,
- [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs.attr,
- [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us.attr,
- [CLUSTER_ATTR_NEW_RSB_COUNT] = &cluster_attr_new_rsb_count.attr,
- [CLUSTER_ATTR_RECOVER_CALLBACKS] = &cluster_attr_recover_callbacks.attr,
- [CLUSTER_ATTR_CLUSTER_NAME] = &cluster_attr_cluster_name.attr,
+ [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port,
+ [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size,
+ [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size,
+ [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer,
+ [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs,
+ [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs,
+ [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug,
+ [CLUSTER_ATTR_PROTOCOL] = &cluster_attr_protocol,
+ [CLUSTER_ATTR_TIMEWARN_CS] = &cluster_attr_timewarn_cs,
+ [CLUSTER_ATTR_WAITWARN_US] = &cluster_attr_waitwarn_us,
+ [CLUSTER_ATTR_NEW_RSB_COUNT] = &cluster_attr_new_rsb_count,
+ [CLUSTER_ATTR_RECOVER_CALLBACKS] = &cluster_attr_recover_callbacks,
+ [CLUSTER_ATTR_CLUSTER_NAME] = &cluster_attr_cluster_name,
NULL,
};
@@ -224,83 +196,11 @@ enum {
COMM_ATTR_ADDR_LIST,
};
-struct comm_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct dlm_comm *, char *);
- ssize_t (*store)(struct dlm_comm *, const char *, size_t);
-};
-
-static struct comm_attribute comm_attr_nodeid = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "nodeid",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = comm_nodeid_read,
- .store = comm_nodeid_write,
-};
-
-static struct comm_attribute comm_attr_local = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "local",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = comm_local_read,
- .store = comm_local_write,
-};
-
-static struct comm_attribute comm_attr_addr = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "addr",
- .ca_mode = S_IWUSR },
- .store = comm_addr_write,
-};
-
-static struct comm_attribute comm_attr_addr_list = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "addr_list",
- .ca_mode = S_IRUGO },
- .show = comm_addr_list_read,
-};
-
-static struct configfs_attribute *comm_attrs[] = {
- [COMM_ATTR_NODEID] = &comm_attr_nodeid.attr,
- [COMM_ATTR_LOCAL] = &comm_attr_local.attr,
- [COMM_ATTR_ADDR] = &comm_attr_addr.attr,
- [COMM_ATTR_ADDR_LIST] = &comm_attr_addr_list.attr,
- NULL,
-};
-
enum {
NODE_ATTR_NODEID = 0,
NODE_ATTR_WEIGHT,
};
-struct node_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct dlm_node *, char *);
- ssize_t (*store)(struct dlm_node *, const char *, size_t);
-};
-
-static struct node_attribute node_attr_nodeid = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "nodeid",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = node_nodeid_read,
- .store = node_nodeid_write,
-};
-
-static struct node_attribute node_attr_weight = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "weight",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = node_weight_read,
- .store = node_weight_write,
-};
-
-static struct configfs_attribute *node_attrs[] = {
- [NODE_ATTR_NODEID] = &node_attr_nodeid.attr,
- [NODE_ATTR_WEIGHT] = &node_attr_weight.attr,
- NULL,
-};
-
struct dlm_clusters {
struct configfs_subsystem subsys;
};
@@ -349,8 +249,6 @@ static struct configfs_group_operations clusters_ops = {
static struct configfs_item_operations cluster_ops = {
.release = release_cluster,
- .show_attribute = show_cluster,
- .store_attribute = store_cluster,
};
static struct configfs_group_operations spaces_ops = {
@@ -369,8 +267,6 @@ static struct configfs_group_operations comms_ops = {
static struct configfs_item_operations comm_ops = {
.release = release_comm,
- .show_attribute = show_comm,
- .store_attribute = store_comm,
};
static struct configfs_group_operations nodes_ops = {
@@ -380,8 +276,6 @@ static struct configfs_group_operations nodes_ops = {
static struct configfs_item_operations node_ops = {
.release = release_node,
- .show_attribute = show_node,
- .store_attribute = store_node,
};
static struct config_item_type clusters_type = {
@@ -427,12 +321,6 @@ static struct config_item_type node_type = {
.ct_owner = THIS_MODULE,
};
-static struct dlm_cluster *config_item_to_cluster(struct config_item *i)
-{
- return i ? container_of(to_config_group(i), struct dlm_cluster, group) :
- NULL;
-}
-
static struct dlm_space *config_item_to_space(struct config_item *i)
{
return i ? container_of(to_config_group(i), struct dlm_space, group) :
@@ -687,66 +575,30 @@ void dlm_config_exit(void)
* Functions for user space to read/write attributes
*/
-static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
- char *buf)
-{
- struct dlm_cluster *cl = config_item_to_cluster(i);
- struct cluster_attribute *cla =
- container_of(a, struct cluster_attribute, attr);
- return cla->show ? cla->show(cl, buf) : 0;
-}
-
-static ssize_t store_cluster(struct config_item *i,
- struct configfs_attribute *a,
- const char *buf, size_t len)
+static ssize_t comm_nodeid_show(struct config_item *item, char *buf)
{
- struct dlm_cluster *cl = config_item_to_cluster(i);
- struct cluster_attribute *cla =
- container_of(a, struct cluster_attribute, attr);
- return cla->store ? cla->store(cl, buf, len) : -EINVAL;
-}
-
-static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
- char *buf)
-{
- struct dlm_comm *cm = config_item_to_comm(i);
- struct comm_attribute *cma =
- container_of(a, struct comm_attribute, attr);
- return cma->show ? cma->show(cm, buf) : 0;
-}
-
-static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
- const char *buf, size_t len)
-{
- struct dlm_comm *cm = config_item_to_comm(i);
- struct comm_attribute *cma =
- container_of(a, struct comm_attribute, attr);
- return cma->store ? cma->store(cm, buf, len) : -EINVAL;
+ return sprintf(buf, "%d\n", config_item_to_comm(item)->nodeid);
}
-static ssize_t comm_nodeid_read(struct dlm_comm *cm, char *buf)
-{
- return sprintf(buf, "%d\n", cm->nodeid);
-}
-
-static ssize_t comm_nodeid_write(struct dlm_comm *cm, const char *buf,
+static ssize_t comm_nodeid_store(struct config_item *item, const char *buf,
size_t len)
{
- int rc = kstrtoint(buf, 0, &cm->nodeid);
+ int rc = kstrtoint(buf, 0, &config_item_to_comm(item)->nodeid);
if (rc)
return rc;
return len;
}
-static ssize_t comm_local_read(struct dlm_comm *cm, char *buf)
+static ssize_t comm_local_show(struct config_item *item, char *buf)
{
- return sprintf(buf, "%d\n", cm->local);
+ return sprintf(buf, "%d\n", config_item_to_comm(item)->local);
}
-static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,
+static ssize_t comm_local_store(struct config_item *item, const char *buf,
size_t len)
{
+ struct dlm_comm *cm = config_item_to_comm(item);
int rc = kstrtoint(buf, 0, &cm->local);
if (rc)
@@ -756,8 +608,10 @@ static ssize_t comm_local_write(struct dlm_comm *cm, const char *buf,
return len;
}
-static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
+static ssize_t comm_addr_store(struct config_item *item, const char *buf,
+ size_t len)
{
+ struct dlm_comm *cm = config_item_to_comm(item);
struct sockaddr_storage *addr;
int rv;
@@ -783,8 +637,9 @@ static ssize_t comm_addr_write(struct dlm_comm *cm, const char *buf, size_t len)
return len;
}
-static ssize_t comm_addr_list_read(struct dlm_comm *cm, char *buf)
+static ssize_t comm_addr_list_show(struct config_item *item, char *buf)
{
+ struct dlm_comm *cm = config_item_to_comm(item);
ssize_t s;
ssize_t allowance;
int i;
@@ -827,32 +682,28 @@ static ssize_t comm_addr_list_read(struct dlm_comm *cm, char *buf)
return 4096 - allowance;
}
-static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
- char *buf)
-{
- struct dlm_node *nd = config_item_to_node(i);
- struct node_attribute *nda =
- container_of(a, struct node_attribute, attr);
- return nda->show ? nda->show(nd, buf) : 0;
-}
+CONFIGFS_ATTR(comm_, nodeid);
+CONFIGFS_ATTR(comm_, local);
+CONFIGFS_ATTR_WO(comm_, addr);
+CONFIGFS_ATTR_RO(comm_, addr_list);
-static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
- const char *buf, size_t len)
-{
- struct dlm_node *nd = config_item_to_node(i);
- struct node_attribute *nda =
- container_of(a, struct node_attribute, attr);
- return nda->store ? nda->store(nd, buf, len) : -EINVAL;
-}
+static struct configfs_attribute *comm_attrs[] = {
+ [COMM_ATTR_NODEID] = &comm_attr_nodeid,
+ [COMM_ATTR_LOCAL] = &comm_attr_local,
+ [COMM_ATTR_ADDR] = &comm_attr_addr,
+ [COMM_ATTR_ADDR_LIST] = &comm_attr_addr_list,
+ NULL,
+};
-static ssize_t node_nodeid_read(struct dlm_node *nd, char *buf)
+static ssize_t node_nodeid_show(struct config_item *item, char *buf)
{
- return sprintf(buf, "%d\n", nd->nodeid);
+ return sprintf(buf, "%d\n", config_item_to_node(item)->nodeid);
}
-static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,
+static ssize_t node_nodeid_store(struct config_item *item, const char *buf,
size_t len)
{
+ struct dlm_node *nd = config_item_to_node(item);
uint32_t seq = 0;
int rc = kstrtoint(buf, 0, &nd->nodeid);
@@ -863,21 +714,30 @@ static ssize_t node_nodeid_write(struct dlm_node *nd, const char *buf,
return len;
}
-static ssize_t node_weight_read(struct dlm_node *nd, char *buf)
+static ssize_t node_weight_show(struct config_item *item, char *buf)
{
- return sprintf(buf, "%d\n", nd->weight);
+ return sprintf(buf, "%d\n", config_item_to_node(item)->weight);
}
-static ssize_t node_weight_write(struct dlm_node *nd, const char *buf,
+static ssize_t node_weight_store(struct config_item *item, const char *buf,
size_t len)
{
- int rc = kstrtoint(buf, 0, &nd->weight);
+ int rc = kstrtoint(buf, 0, &config_item_to_node(item)->weight);
if (rc)
return rc;
return len;
}
+CONFIGFS_ATTR(node_, nodeid);
+CONFIGFS_ATTR(node_, weight);
+
+static struct configfs_attribute *node_attrs[] = {
+ [NODE_ATTR_NODEID] = &node_attr_nodeid,
+ [NODE_ATTR_WEIGHT] = &node_attr_weight,
+ NULL,
+};
+
/*
* Functions for the dlm to get the info that's been configured
*/
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 87e9d79..3a37bd3 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -421,7 +421,7 @@ static void lowcomms_write_space(struct sock *sk)
if (test_and_clear_bit(CF_APP_LIMITED, &con->flags)) {
con->sock->sk->sk_write_pending--;
- clear_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags);
}
if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
@@ -1448,7 +1448,7 @@ static void send_to_sock(struct connection *con)
msg_flags);
if (ret == -EAGAIN || ret == 0) {
if (ret == -EAGAIN &&
- test_bit(SOCK_ASYNC_NOSPACE, &con->sock->flags) &&
+ test_bit(SOCKWQ_ASYNC_NOSPACE, &con->sock->flags) &&
!test_and_set_bit(CF_APP_LIMITED, &con->flags)) {
/* Notify TCP that we're limited by the
* application window size.
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 173b387..1925d6d 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -515,14 +515,9 @@ static ssize_t device_write(struct file *file, const char __user *buf,
if (count > sizeof(struct dlm_write_request) + DLM_RESNAME_MAXLEN)
return -EINVAL;
- kbuf = kzalloc(count + 1, GFP_NOFS);
- if (!kbuf)
- return -ENOMEM;
-
- if (copy_from_user(kbuf, buf, count)) {
- error = -EFAULT;
- goto out_free;
- }
+ kbuf = memdup_user_nul(buf, count);
+ if (!IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
if (check_version(kbuf)) {
error = -EBADE;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index e2e47ba..040aa87 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -282,9 +282,7 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
if (rc) {
ecryptfs_do_unlink(directory_inode, ecryptfs_dentry,
ecryptfs_inode);
- make_bad_inode(ecryptfs_inode);
- unlock_new_inode(ecryptfs_inode);
- iput(ecryptfs_inode);
+ iget_failed(ecryptfs_inode);
goto out;
}
unlock_new_inode(ecryptfs_inode);
@@ -674,16 +672,24 @@ out:
return rc ? ERR_PTR(rc) : buf;
}
-static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *ecryptfs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
size_t len;
- char *buf = ecryptfs_readlink_lower(dentry, &len);
+ char *buf;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ buf = ecryptfs_readlink_lower(dentry, &len);
if (IS_ERR(buf))
return buf;
fsstack_copy_attr_atime(d_inode(dentry),
d_inode(ecryptfs_dentry_to_lower(dentry)));
buf[len] = '\0';
- return *cookie = buf;
+ set_delayed_call(done, kfree_link, buf);
+ return buf;
}
/**
@@ -1095,8 +1101,7 @@ out:
const struct inode_operations ecryptfs_symlink_iops = {
.readlink = generic_readlink,
- .follow_link = ecryptfs_follow_link,
- .put_link = kfree_put_link,
+ .get_link = ecryptfs_get_link,
.permission = ecryptfs_permission,
.setattr = ecryptfs_setattr,
.getattr = ecryptfs_getattr_link,
diff --git a/fs/efs/inode.c b/fs/efs/inode.c
index 079d203..cdf0872 100644
--- a/fs/efs/inode.c
+++ b/fs/efs/inode.c
@@ -151,6 +151,7 @@ struct inode *efs_iget(struct super_block *super, unsigned long ino)
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &efs_symlink_aops;
break;
case S_IFCHR:
diff --git a/fs/efs/symlink.c b/fs/efs/symlink.c
index 75117d0..4870cc8 100644
--- a/fs/efs/symlink.c
+++ b/fs/efs/symlink.c
@@ -13,7 +13,7 @@
static int efs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = kmap(page);
+ char *link = page_address(page);
struct buffer_head * bh;
struct inode * inode = page->mapping->host;
efs_block_t size = inode->i_size;
@@ -39,12 +39,10 @@ static int efs_symlink_readpage(struct file *file, struct page *page)
}
link[size] = '\0';
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
fail:
SetPageError(page);
- kunmap(page);
unlock_page(page);
return err;
}
diff --git a/fs/exec.c b/fs/exec.c
index b06623a..828ec5f 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -119,7 +119,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
int error = PTR_ERR(tmp);
static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
- .acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
+ .acc_mode = MAY_READ | MAY_EXEC,
.intent = LOOKUP_OPEN,
.lookup_flags = LOOKUP_FOLLOW,
};
@@ -763,7 +763,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags)
int err;
struct open_flags open_exec_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
- .acc_mode = MAY_EXEC | MAY_OPEN,
+ .acc_mode = MAY_EXEC,
.intent = LOOKUP_OPEN,
.lookup_flags = LOOKUP_FOLLOW,
};
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c
index 73c64da..9eaf595 100644
--- a/fs/exofs/inode.c
+++ b/fs/exofs/inode.c
@@ -592,10 +592,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
}
unlock_page(page);
}
- if (PageDirty(page) || PageWriteback(page))
- *uptodate = true;
- else
- *uptodate = PageUptodate(page);
+ *uptodate = PageUptodate(page);
EXOFS_DBGMSG2("index=0x%lx uptodate=%d\n", index, *uptodate);
return page;
} else {
@@ -1227,6 +1224,7 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
inode->i_link = (char *)oi->i_data;
} else {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &exofs_aops;
}
} else {
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index 994e078..c20d77d 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -111,6 +111,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
if (l > sizeof(oi->i_data)) {
/* slow symlink */
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &exofs_aops;
memset(oi->i_data, 0, sizeof(oi->i_data));
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 0aa9bf6..338eefd 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1420,6 +1420,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
sizeof(ei->i_data) - 1);
} else {
inode->i_op = &ext2_symlink_inode_operations;
+ inode_nohighmem(inode);
if (test_opt(inode->i_sb, NOBH))
inode->i_mapping->a_ops = &ext2_nobh_aops;
else
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3267a80..7a2be8f 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -183,6 +183,7 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
if (l > sizeof (EXT2_I(inode)->i_data)) {
/* slow symlink */
inode->i_op = &ext2_symlink_inode_operations;
+ inode_nohighmem(inode);
if (test_opt(inode->i_sb, NOBH))
inode->i_mapping->a_ops = &ext2_nobh_aops;
else
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 3a71cea..748d35a 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -569,6 +569,8 @@ static int parse_options(char *options, struct super_block *sb)
/* Fall through */
case Opt_dax:
#ifdef CONFIG_FS_DAX
+ ext2_msg(sb, KERN_WARNING,
+ "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
set_opt(sbi->s_mount_opt, DAX);
#else
ext2_msg(sb, KERN_INFO, "dax option not supported");
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index ae17179..3495d8a 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -22,8 +22,7 @@
const struct inode_operations ext2_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
@@ -35,7 +34,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
const struct inode_operations ext2_fast_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = ext2_setattr,
#ifdef CONFIG_EXT2_FS_XATTR
.setxattr = generic_setxattr,
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 0b6bfd3..f57a7ab 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -77,10 +77,8 @@
printk("\n"); \
} while (0)
# define ea_bdebug(bh, f...) do { \
- char b[BDEVNAME_SIZE]; \
- printk(KERN_DEBUG "block %s:%lu: ", \
- bdevname(bh->b_bdev, b), \
- (unsigned long) bh->b_blocknr); \
+ printk(KERN_DEBUG "block %pg:%lu: ", \
+ bh->b_bdev, (unsigned long) bh->b_blocknr); \
printk(f); \
printk("\n"); \
} while (0)
@@ -292,17 +290,21 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
const struct xattr_handler *handler =
ext2_xattr_handler(entry->e_name_index);
- if (handler) {
- size_t size = handler->list(dentry, buffer, rest,
- entry->e_name,
- entry->e_name_len,
- handler->flags);
+ if (handler && (!handler->list || handler->list(dentry))) {
+ const char *prefix = handler->prefix ?: handler->name;
+ size_t prefix_len = strlen(prefix);
+ size_t size = prefix_len + entry->e_name_len + 1;
+
if (buffer) {
if (size > rest) {
error = -ERANGE;
goto cleanup;
}
- buffer += size;
+ memcpy(buffer, prefix, prefix_len);
+ buffer += prefix_len;
+ memcpy(buffer, entry->e_name, entry->e_name_len);
+ buffer += entry->e_name_len;
+ *buffer++ = 0;
}
rest -= size;
}
diff --git a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
index 702fc68..ba97f24 100644
--- a/fs/ext2/xattr_security.c
+++ b/fs/ext2/xattr_security.c
@@ -7,37 +7,20 @@
#include <linux/security.h>
#include "xattr.h"
-static size_t
-ext2_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
-{
- const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
-}
-
static int
-ext2_xattr_security_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+ext2_xattr_security_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name,
buffer, size);
}
static int
-ext2_xattr_security_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext2_xattr_security_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_SECURITY, name,
value, size, flags);
}
@@ -68,7 +51,6 @@ ext2_init_security(struct inode *inode, struct inode *dir,
const struct xattr_handler ext2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = ext2_xattr_security_list,
.get = ext2_xattr_security_get,
.set = ext2_xattr_security_set,
};
diff --git a/fs/ext2/xattr_trusted.c b/fs/ext2/xattr_trusted.c
index 42b6e98..2c94d19 100644
--- a/fs/ext2/xattr_trusted.c
+++ b/fs/ext2/xattr_trusted.c
@@ -8,40 +8,26 @@
#include "ext2.h"
#include "xattr.h"
-static size_t
-ext2_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
+static bool
+ext2_xattr_trusted_list(struct dentry *dentry)
{
- const int prefix_len = XATTR_TRUSTED_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (!capable(CAP_SYS_ADMIN))
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
+ return capable(CAP_SYS_ADMIN);
}
static int
-ext2_xattr_trusted_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+ext2_xattr_trusted_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name,
buffer, size);
}
static int
-ext2_xattr_trusted_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext2_xattr_trusted_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext2_xattr_set(d_inode(dentry), EXT2_XATTR_INDEX_TRUSTED, name,
value, size, flags);
}
diff --git a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c
index ecdc460..72a2a96 100644
--- a/fs/ext2/xattr_user.c
+++ b/fs/ext2/xattr_user.c
@@ -10,30 +10,17 @@
#include "ext2.h"
#include "xattr.h"
-static size_t
-ext2_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
+static bool
+ext2_xattr_user_list(struct dentry *dentry)
{
- const size_t prefix_len = XATTR_USER_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (!test_opt(dentry->d_sb, XATTR_USER))
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_USER_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
+ return test_opt(dentry->d_sb, XATTR_USER);
}
static int
-ext2_xattr_user_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+ext2_xattr_user_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP;
return ext2_xattr_get(d_inode(dentry), EXT2_XATTR_INDEX_USER,
@@ -41,11 +28,10 @@ ext2_xattr_user_get(struct dentry *dentry, const char *name,
}
static int
-ext2_xattr_user_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext2_xattr_user_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP;
diff --git a/fs/ext4/crypto.c b/fs/ext4/crypto.c
index af06830..1a08350 100644
--- a/fs/ext4/crypto.c
+++ b/fs/ext4/crypto.c
@@ -389,7 +389,7 @@ int ext4_encrypted_zeroout(struct inode *inode, struct ext4_extent *ex)
struct ext4_crypto_ctx *ctx;
struct page *ciphertext_page = NULL;
struct bio *bio;
- ext4_lblk_t lblk = ex->ee_block;
+ ext4_lblk_t lblk = le32_to_cpu(ex->ee_block);
ext4_fsblk_t pblk = ext4_ext_pblock(ex);
unsigned int len = ext4_ext_get_actual_len(ex);
int ret, err = 0;
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 750063f..cc7ca4e 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -26,6 +26,7 @@
#include <linux/seqlock.h>
#include <linux/mutex.h>
#include <linux/timer.h>
+#include <linux/version.h>
#include <linux/wait.h>
#include <linux/blockgroup_lock.h>
#include <linux/percpu_counter.h>
@@ -727,19 +728,55 @@ struct move_extent {
<= (EXT4_GOOD_OLD_INODE_SIZE + \
(einode)->i_extra_isize)) \
+/*
+ * We use an encoding that preserves the times for extra epoch "00":
+ *
+ * extra msb of adjust for signed
+ * epoch 32-bit 32-bit tv_sec to
+ * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range
+ * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31
+ * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19
+ * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07
+ * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25
+ * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16
+ * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04
+ * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22
+ * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10
+ *
+ * Note that previous versions of the kernel on 64-bit systems would
+ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
+ * 1970. e2fsck will correct this, assuming that it is run on the
+ * affected filesystem before 2242.
+ */
+
static inline __le32 ext4_encode_extra_time(struct timespec *time)
{
- return cpu_to_le32((sizeof(time->tv_sec) > 4 ?
- (time->tv_sec >> 32) & EXT4_EPOCH_MASK : 0) |
- ((time->tv_nsec << EXT4_EPOCH_BITS) & EXT4_NSEC_MASK));
+ u32 extra = sizeof(time->tv_sec) > 4 ?
+ ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0;
+ return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
}
static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra)
{
- if (sizeof(time->tv_sec) > 4)
- time->tv_sec |= (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK)
- << 32;
- time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+ if (unlikely(sizeof(time->tv_sec) > 4 &&
+ (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
+ /* Handle legacy encoding of pre-1970 dates with epoch
+ * bits 1,1. We assume that by kernel version 4.20,
+ * everyone will have run fsck over the affected
+ * filesystems to correct the problem. (This
+ * backwards compatibility may be removed before this
+ * time, at the discretion of the ext4 developers.)
+ */
+ u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
+ if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0)
+ extra_bits = 0;
+ time->tv_sec += extra_bits << 32;
+#else
+ time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+#endif
+ }
+ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
}
#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 7d1aad1..b3bd912 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4283,6 +4283,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
inode->i_op = &ext4_symlink_inode_operations;
ext4_set_aops(inode);
}
+ inode_nohighmem(inode);
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
inode->i_op = &ext4_special_inode_operations;
@@ -5283,7 +5284,7 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
!ext4_should_journal_data(inode) &&
!ext4_nonda_switch(inode->i_sb)) {
do {
- ret = __block_page_mkwrite(vma, vmf,
+ ret = block_page_mkwrite(vma, vmf,
ext4_da_get_block_prep);
} while (ret == -ENOSPC &&
ext4_should_retry_alloc(inode->i_sb, &retries));
@@ -5330,7 +5331,7 @@ retry_alloc:
ret = VM_FAULT_SIGBUS;
goto out;
}
- ret = __block_page_mkwrite(vma, vmf, get_block);
+ ret = block_page_mkwrite(vma, vmf, get_block);
if (!ret && ext4_should_journal_data(inode)) {
if (ext4_walk_page_buffers(handle, page_buffers(page), 0,
PAGE_CACHE_SIZE, NULL, do_journal_get_write_access)) {
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index a969ab3..f27e0c2 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3132,6 +3132,7 @@ static int ext4_symlink(struct inode *dir,
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
if (!encryption_required)
inode->i_op = &ext4_symlink_inode_operations;
+ inode_nohighmem(inode);
ext4_set_aops(inode);
/*
* We cannot call page_symlink() with transaction started
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 17fbe38..090b349 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -52,9 +52,8 @@ void ext4_exit_pageio(void)
*/
static void buffer_io_error(struct buffer_head *bh)
{
- char b[BDEVNAME_SIZE];
- printk_ratelimited(KERN_ERR "Buffer I/O error on device %s, logical block %llu\n",
- bdevname(bh->b_bdev, b),
+ printk_ratelimited(KERN_ERR "Buffer I/O error on device %pg, logical block %llu\n",
+ bh->b_bdev,
(unsigned long long)bh->b_blocknr);
}
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 753f4e6..c9ab67d 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1664,8 +1664,12 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
}
sbi->s_jquota_fmt = m->mount_opt;
#endif
-#ifndef CONFIG_FS_DAX
} else if (token == Opt_dax) {
+#ifdef CONFIG_FS_DAX
+ ext4_msg(sb, KERN_WARNING,
+ "DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
+ sbi->s_mount_opt |= m->mount_opt;
+#else
ext4_msg(sb, KERN_INFO, "dax option not supported");
return -1;
#endif
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index abe2401..6f7ee30 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -23,17 +23,21 @@
#include "xattr.h"
#ifdef CONFIG_EXT4_FS_ENCRYPTION
-static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cookie)
+static const char *ext4_encrypted_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
struct ext4_str cstr, pstr;
- struct inode *inode = d_inode(dentry);
struct ext4_encrypted_symlink_data *sd;
loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
int res;
u32 plen, max_size = inode->i_sb->s_blocksize;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
res = ext4_get_encryption_info(inode);
if (res)
return ERR_PTR(res);
@@ -45,14 +49,14 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage))
return ERR_CAST(cpage);
- caddr = kmap(cpage);
+ caddr = page_address(cpage);
caddr[size] = 0;
}
/* Symlink is encrypted */
sd = (struct ext4_encrypted_symlink_data *)caddr;
cstr.name = sd->encrypted_path;
- cstr.len = le32_to_cpu(sd->len);
+ cstr.len = le16_to_cpu(sd->len);
if ((cstr.len +
sizeof(struct ext4_encrypted_symlink_data) - 1) >
max_size) {
@@ -75,24 +79,20 @@ static const char *ext4_encrypted_follow_link(struct dentry *dentry, void **cook
/* Null-terminate the name */
if (res <= plen)
paddr[res] = '\0';
- if (cpage) {
- kunmap(cpage);
+ if (cpage)
page_cache_release(cpage);
- }
- return *cookie = paddr;
+ set_delayed_call(done, kfree_link, paddr);
+ return paddr;
errout:
- if (cpage) {
- kunmap(cpage);
+ if (cpage)
page_cache_release(cpage);
- }
kfree(paddr);
return ERR_PTR(res);
}
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = ext4_encrypted_follow_link,
- .put_link = kfree_put_link,
+ .get_link = ext4_encrypted_get_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
@@ -103,8 +103,7 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
const struct inode_operations ext4_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
@@ -114,7 +113,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
const struct inode_operations ext4_fast_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = ext4_setattr,
.setxattr = generic_setxattr,
.getxattr = generic_getxattr,
diff --git a/fs/ext4/sysfs.c b/fs/ext4/sysfs.c
index 1b57c72..1420a3c 100644
--- a/fs/ext4/sysfs.c
+++ b/fs/ext4/sysfs.c
@@ -358,7 +358,7 @@ static int name##_open(struct inode *inode, struct file *file) \
return single_open(file, ext4_seq_##name##_show, PDE_DATA(inode)); \
} \
\
-const struct file_operations ext4_seq_##name##_fops = { \
+static const struct file_operations ext4_seq_##name##_fops = { \
.owner = THIS_MODULE, \
.open = name##_open, \
.read = seq_read, \
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index 984448c..a95151e 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -68,10 +68,8 @@
printk("\n"); \
} while (0)
# define ea_bdebug(bh, f...) do { \
- char b[BDEVNAME_SIZE]; \
- printk(KERN_DEBUG "block %s:%lu: ", \
- bdevname(bh->b_bdev, b), \
- (unsigned long) bh->b_blocknr); \
+ printk(KERN_DEBUG "block %pg:%lu: ", \
+ bh->b_bdev, (unsigned long) bh->b_blocknr); \
printk(f); \
printk("\n"); \
} while (0)
@@ -404,20 +402,24 @@ ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry,
const struct xattr_handler *handler =
ext4_xattr_handler(entry->e_name_index);
- if (handler) {
- size_t size = handler->list(dentry, buffer, rest,
- entry->e_name,
- entry->e_name_len,
- handler->flags);
+ if (handler && (!handler->list || handler->list(dentry))) {
+ const char *prefix = handler->prefix ?: handler->name;
+ size_t prefix_len = strlen(prefix);
+ size_t size = prefix_len + entry->e_name_len + 1;
+
if (buffer) {
if (size > rest)
return -ERANGE;
- buffer += size;
+ memcpy(buffer, prefix, prefix_len);
+ buffer += prefix_len;
+ memcpy(buffer, entry->e_name, entry->e_name_len);
+ buffer += entry->e_name_len;
+ *buffer++ = 0;
}
rest -= size;
}
}
- return buffer_size - rest;
+ return buffer_size - rest; /* total size */
}
static int
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index 95d90e0..3e81bdc 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -11,38 +11,20 @@
#include "ext4.h"
#include "xattr.h"
-static size_t
-ext4_xattr_security_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
-{
- const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
- const size_t total_len = prefix_len + name_len + 1;
-
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
-}
-
static int
-ext4_xattr_security_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+ext4_xattr_security_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY,
name, buffer, size);
}
static int
-ext4_xattr_security_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext4_xattr_security_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_SECURITY,
name, value, size, flags);
}
@@ -76,7 +58,6 @@ ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir,
const struct xattr_handler ext4_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = ext4_xattr_security_list,
.get = ext4_xattr_security_get,
.set = ext4_xattr_security_set,
};
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
index 891ee2d..2a3c6f9 100644
--- a/fs/ext4/xattr_trusted.c
+++ b/fs/ext4/xattr_trusted.c
@@ -12,40 +12,26 @@
#include "ext4.h"
#include "xattr.h"
-static size_t
-ext4_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
+static bool
+ext4_xattr_trusted_list(struct dentry *dentry)
{
- const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (!capable(CAP_SYS_ADMIN))
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
+ return capable(CAP_SYS_ADMIN);
}
static int
-ext4_xattr_trusted_get(struct dentry *dentry, const char *name, void *buffer,
- size_t size, int type)
+ext4_xattr_trusted_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name, void *buffer,
+ size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED,
name, buffer, size);
}
static int
-ext4_xattr_trusted_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext4_xattr_trusted_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_TRUSTED,
name, value, size, flags);
}
diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
index 6ed932b..d152f43 100644
--- a/fs/ext4/xattr_user.c
+++ b/fs/ext4/xattr_user.c
@@ -11,30 +11,17 @@
#include "ext4.h"
#include "xattr.h"
-static size_t
-ext4_xattr_user_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
+static bool
+ext4_xattr_user_list(struct dentry *dentry)
{
- const size_t prefix_len = XATTR_USER_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (!test_opt(dentry->d_sb, XATTR_USER))
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_USER_PREFIX, prefix_len);
- memcpy(list+prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
+ return test_opt(dentry->d_sb, XATTR_USER);
}
static int
-ext4_xattr_user_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+ext4_xattr_user_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP;
return ext4_xattr_get(d_inode(dentry), EXT4_XATTR_INDEX_USER,
@@ -42,11 +29,10 @@ ext4_xattr_user_get(struct dentry *dentry, const char *name,
}
static int
-ext4_xattr_user_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+ext4_xattr_user_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (!test_opt(dentry->d_sb, XATTR_USER))
return -EOPNOTSUPP;
return ext4_xattr_set(d_inode(dentry), EXT4_XATTR_INDEX_USER,
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 478e5d5..ad1b18a 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -211,12 +211,10 @@ static int stat_show(struct seq_file *s, void *v)
mutex_lock(&f2fs_stat_mutex);
list_for_each_entry(si, &f2fs_stat_list, stat_list) {
- char devname[BDEVNAME_SIZE];
-
update_general_status(si->sbi);
- seq_printf(s, "\n=====[ partition info(%s). #%d ]=====\n",
- bdevname(si->sbi->sb->s_bdev, devname), i++);
+ seq_printf(s, "\n=====[ partition info(%pg). #%d ]=====\n",
+ si->sbi->sb->s_bdev, i++);
seq_printf(s, "[SB: 1] [CP: 2] [SIT: %d] [NAT: %d] ",
si->sit_area_segs, si->nat_area_segs);
seq_printf(s, "[SSA: %d] [MAIN: %d",
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9db5500..ec6067c 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -1602,13 +1602,11 @@ static inline bool is_dot_dotdot(const struct qstr *str)
static inline bool f2fs_may_extent_tree(struct inode *inode)
{
- mode_t mode = inode->i_mode;
-
if (!test_opt(F2FS_I_SB(inode), EXTENT_CACHE) ||
is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT))
return false;
- return S_ISREG(mode);
+ return S_ISREG(inode->i_mode);
}
static inline void *f2fs_kvmalloc(size_t size, gfp_t flags)
@@ -2121,7 +2119,7 @@ static inline int f2fs_sb_has_crypto(struct super_block *sb)
static inline bool f2fs_may_encrypt(struct inode *inode)
{
#ifdef CONFIG_F2FS_FS_ENCRYPTION
- mode_t mode = inode->i_mode;
+ umode_t mode = inode->i_mode;
return (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode));
#else
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 97e20de..5528801 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -202,6 +202,7 @@ make_now:
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
else
inode->i_op = &f2fs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &f2fs_dblock_aops;
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 2c32110..e7587fc 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -315,12 +315,15 @@ fail:
return err;
}
-static const char *f2fs_follow_link(struct dentry *dentry, void **cookie)
+static const char *f2fs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- const char *link = page_follow_link_light(dentry, cookie);
+ const char *link = page_get_link(dentry, inode, done);
if (!IS_ERR(link) && !*link) {
/* this is broken symlink case */
- page_put_link(NULL, *cookie);
+ do_delayed_call(done);
+ clear_delayed_call(done);
link = ERR_PTR(-ENOENT);
}
return link;
@@ -351,6 +354,7 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
inode->i_op = &f2fs_encrypted_symlink_inode_operations;
else
inode->i_op = &f2fs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &f2fs_dblock_aops;
f2fs_lock_op(sbi);
@@ -923,18 +927,22 @@ static int f2fs_rename2(struct inode *old_dir, struct dentry *old_dentry,
}
#ifdef CONFIG_F2FS_FS_ENCRYPTION
-static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cookie)
+static const char *f2fs_encrypted_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
struct page *cpage = NULL;
char *caddr, *paddr = NULL;
struct f2fs_str cstr;
struct f2fs_str pstr = FSTR_INIT(NULL, 0);
- struct inode *inode = d_inode(dentry);
struct f2fs_encrypted_symlink_data *sd;
loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
u32 max_size = inode->i_sb->s_blocksize;
int res;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
res = f2fs_get_encryption_info(inode);
if (res)
return ERR_PTR(res);
@@ -942,7 +950,7 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
if (IS_ERR(cpage))
return ERR_CAST(cpage);
- caddr = kmap(cpage);
+ caddr = page_address(cpage);
caddr[size] = 0;
/* Symlink is encrypted */
@@ -982,21 +990,19 @@ static const char *f2fs_encrypted_follow_link(struct dentry *dentry, void **cook
/* Null-terminate the name */
paddr[res] = '\0';
- kunmap(cpage);
page_cache_release(cpage);
- return *cookie = paddr;
+ set_delayed_call(done, kfree_link, paddr);
+ return paddr;
errout:
kfree(cstr.name);
f2fs_fname_crypto_free_buffer(&pstr);
- kunmap(cpage);
page_cache_release(cpage);
return ERR_PTR(res);
}
const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = f2fs_encrypted_follow_link,
- .put_link = kfree_put_link,
+ .get_link = f2fs_encrypted_get_link,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
.setxattr = generic_setxattr,
@@ -1031,8 +1037,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
const struct inode_operations f2fs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = f2fs_follow_link,
- .put_link = page_put_link,
+ .get_link = f2fs_get_link,
.getattr = f2fs_getattr,
.setattr = f2fs_setattr,
#ifdef CONFIG_F2FS_FS_XATTR
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index 4de2286..036952a 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -25,49 +25,37 @@
#include "f2fs.h"
#include "xattr.h"
-static size_t f2fs_xattr_generic_list(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t len, int type)
+static int f2fs_xattr_generic_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name, void *buffer,
+ size_t size)
{
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
- int total_len, prefix_len = 0;
- const char *prefix = NULL;
- switch (type) {
+ switch (handler->flags) {
case F2FS_XATTR_INDEX_USER:
if (!test_opt(sbi, XATTR_USER))
return -EOPNOTSUPP;
- prefix = XATTR_USER_PREFIX;
- prefix_len = XATTR_USER_PREFIX_LEN;
break;
case F2FS_XATTR_INDEX_TRUSTED:
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- prefix = XATTR_TRUSTED_PREFIX;
- prefix_len = XATTR_TRUSTED_PREFIX_LEN;
break;
case F2FS_XATTR_INDEX_SECURITY:
- prefix = XATTR_SECURITY_PREFIX;
- prefix_len = XATTR_SECURITY_PREFIX_LEN;
break;
default:
return -EINVAL;
}
-
- total_len = prefix_len + len + 1;
- if (list && total_len <= list_size) {
- memcpy(list, prefix, prefix_len);
- memcpy(list + prefix_len, name, len);
- list[prefix_len + len] = '\0';
- }
- return total_len;
+ return f2fs_getxattr(d_inode(dentry), handler->flags, name,
+ buffer, size, NULL);
}
-static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int f2fs_xattr_generic_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
{
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
- switch (type) {
+ switch (handler->flags) {
case F2FS_XATTR_INDEX_USER:
if (!test_opt(sbi, XATTR_USER))
return -EOPNOTSUPP;
@@ -81,72 +69,39 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name,
default:
return -EINVAL;
}
- if (strcmp(name, "") == 0)
- return -EINVAL;
- return f2fs_getxattr(d_inode(dentry), type, name, buffer, size, NULL);
+ return f2fs_setxattr(d_inode(dentry), handler->flags, name,
+ value, size, NULL, flags);
}
-static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static bool f2fs_xattr_user_list(struct dentry *dentry)
{
struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
- switch (type) {
- case F2FS_XATTR_INDEX_USER:
- if (!test_opt(sbi, XATTR_USER))
- return -EOPNOTSUPP;
- break;
- case F2FS_XATTR_INDEX_TRUSTED:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- break;
- case F2FS_XATTR_INDEX_SECURITY:
- break;
- default:
- return -EINVAL;
- }
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
- return f2fs_setxattr(d_inode(dentry), type, name,
- value, size, NULL, flags);
+ return test_opt(sbi, XATTR_USER);
}
-static size_t f2fs_xattr_advise_list(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t len, int type)
+static bool f2fs_xattr_trusted_list(struct dentry *dentry)
{
- const char *xname = F2FS_SYSTEM_ADVISE_PREFIX;
- size_t size;
-
- if (type != F2FS_XATTR_INDEX_ADVISE)
- return 0;
-
- size = strlen(xname) + 1;
- if (list && size <= list_size)
- memcpy(list, xname, size);
- return size;
+ return capable(CAP_SYS_ADMIN);
}
-static int f2fs_xattr_advise_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int f2fs_xattr_advise_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name, void *buffer,
+ size_t size)
{
struct inode *inode = d_inode(dentry);
- if (strcmp(name, "") != 0)
- return -EINVAL;
-
if (buffer)
*((char *)buffer) = F2FS_I(inode)->i_advise;
return sizeof(char);
}
-static int f2fs_xattr_advise_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static int f2fs_xattr_advise_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
{
struct inode *inode = d_inode(dentry);
- if (strcmp(name, "") != 0)
- return -EINVAL;
if (!inode_owner_or_capable(inode))
return -EPERM;
if (value == NULL)
@@ -185,7 +140,7 @@ int f2fs_init_security(struct inode *inode, struct inode *dir,
const struct xattr_handler f2fs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
.flags = F2FS_XATTR_INDEX_USER,
- .list = f2fs_xattr_generic_list,
+ .list = f2fs_xattr_user_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
@@ -193,15 +148,14 @@ const struct xattr_handler f2fs_xattr_user_handler = {
const struct xattr_handler f2fs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.flags = F2FS_XATTR_INDEX_TRUSTED,
- .list = f2fs_xattr_generic_list,
+ .list = f2fs_xattr_trusted_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
const struct xattr_handler f2fs_xattr_advise_handler = {
- .prefix = F2FS_SYSTEM_ADVISE_PREFIX,
+ .name = F2FS_SYSTEM_ADVISE_NAME,
.flags = F2FS_XATTR_INDEX_ADVISE,
- .list = f2fs_xattr_advise_list,
.get = f2fs_xattr_advise_get,
.set = f2fs_xattr_advise_set,
};
@@ -209,7 +163,6 @@ const struct xattr_handler f2fs_xattr_advise_handler = {
const struct xattr_handler f2fs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.flags = F2FS_XATTR_INDEX_SECURITY,
- .list = f2fs_xattr_generic_list,
.get = f2fs_xattr_generic_get,
.set = f2fs_xattr_generic_set,
};
@@ -457,20 +410,27 @@ ssize_t f2fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
list_for_each_xattr(entry, base_addr) {
const struct xattr_handler *handler =
f2fs_xattr_handler(entry->e_name_index);
+ const char *prefix;
+ size_t prefix_len;
size_t size;
- if (!handler)
+ if (!handler || (handler->list && !handler->list(dentry)))
continue;
- size = handler->list(dentry, buffer, rest, entry->e_name,
- entry->e_name_len, handler->flags);
- if (buffer && size > rest) {
- error = -ERANGE;
- goto cleanup;
+ prefix = handler->prefix ?: handler->name;
+ prefix_len = strlen(prefix);
+ size = prefix_len + entry->e_name_len + 1;
+ if (buffer) {
+ if (size > rest) {
+ error = -ERANGE;
+ goto cleanup;
+ }
+ memcpy(buffer, prefix, prefix_len);
+ buffer += prefix_len;
+ memcpy(buffer, entry->e_name, entry->e_name_len);
+ buffer += entry->e_name_len;
+ *buffer++ = 0;
}
-
- if (buffer)
- buffer += size;
rest -= size;
}
error = buffer_size - rest;
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
index 71a7100..79dccc8 100644
--- a/fs/f2fs/xattr.h
+++ b/fs/f2fs/xattr.h
@@ -27,7 +27,7 @@
#define F2FS_XATTR_REFCOUNT_MAX 1024
/* Name indexes */
-#define F2FS_SYSTEM_ADVISE_PREFIX "system.advise"
+#define F2FS_SYSTEM_ADVISE_NAME "system.advise"
#define F2FS_XATTR_INDEX_USER 1
#define F2FS_XATTR_INDEX_POSIX_ACL_ACCESS 2
#define F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT 3
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 4afc4d9..8b2127f 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -610,9 +610,9 @@ parse_record:
int status = fat_parse_long(inode, &cpos, &bh, &de,
&unicode, &nr_slots);
if (status < 0) {
- ctx->pos = cpos;
+ bh = NULL;
ret = status;
- goto out;
+ goto end_of_dir;
} else if (status == PARSE_INVALID)
goto record_end;
else if (status == PARSE_NOT_LONGNAME)
@@ -654,8 +654,9 @@ parse_record:
fill_len = short_len;
start_filldir:
- if (!fake_offset)
- ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
+ ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry);
+ if (fake_offset && ctx->pos < 2)
+ ctx->pos = 2;
if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) {
if (!dir_emit_dot(file, ctx))
@@ -681,14 +682,19 @@ record_end:
fake_offset = 0;
ctx->pos = cpos;
goto get_new;
+
end_of_dir:
- ctx->pos = cpos;
+ if (fake_offset && cpos < 2)
+ ctx->pos = 2;
+ else
+ ctx->pos = cpos;
fill_failed:
brelse(bh);
if (unicode)
__putname(unicode);
out:
mutex_unlock(&sbi->s_lock);
+
return ret;
}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index ee85cd4..350a2c8 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -51,7 +51,8 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
if (arg & O_NDELAY)
arg |= O_NONBLOCK;
- if (arg & O_DIRECT) {
+ /* Pipe packetized mode is controlled by O_DIRECT flag */
+ if (!S_ISFIFO(filp->f_inode->i_mode) && (arg & O_DIRECT)) {
if (!filp->f_mapping || !filp->f_mapping->a_ops ||
!filp->f_mapping->a_ops->direct_IO)
return -EINVAL;
diff --git a/fs/file.c b/fs/file.c
index 39f8f15..1aed0ad 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -25,9 +25,9 @@
int sysctl_nr_open __read_mostly = 1024*1024;
int sysctl_nr_open_min = BITS_PER_LONG;
-/* our max() is unusable in constant expressions ;-/ */
-#define __const_max(x, y) ((x) < (y) ? (x) : (y))
-int sysctl_nr_open_max = __const_max(INT_MAX, ~(size_t)0/sizeof(void *)) &
+/* our min() is unusable in constant expressions ;-/ */
+#define __const_min(x, y) ((x) < (y) ? (x) : (y))
+int sysctl_nr_open_max = __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) &
-BITS_PER_LONG;
static void *alloc_fdmem(size_t size)
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index ef73ed6..3e2ccad 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -326,6 +326,7 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
} else if (S_ISLNK(ip->i_mode)) {
if (!VXFS_ISIMMED(vip)) {
ip->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(ip);
ip->i_mapping->a_ops = &vxfs_aops;
} else {
ip->i_op = &simple_symlink_inode_operations;
diff --git a/fs/fscache/netfs.c b/fs/fscache/netfs.c
index 6d941f5..9b28649 100644
--- a/fs/fscache/netfs.c
+++ b/fs/fscache/netfs.c
@@ -22,6 +22,7 @@ static LIST_HEAD(fscache_netfs_list);
int __fscache_register_netfs(struct fscache_netfs *netfs)
{
struct fscache_netfs *ptr;
+ struct fscache_cookie *cookie;
int ret;
_enter("{%s}", netfs->name);
@@ -29,29 +30,25 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
INIT_LIST_HEAD(&netfs->link);
/* allocate a cookie for the primary index */
- netfs->primary_index =
- kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL);
+ cookie = kmem_cache_zalloc(fscache_cookie_jar, GFP_KERNEL);
- if (!netfs->primary_index) {
+ if (!cookie) {
_leave(" = -ENOMEM");
return -ENOMEM;
}
/* initialise the primary index cookie */
- atomic_set(&netfs->primary_index->usage, 1);
- atomic_set(&netfs->primary_index->n_children, 0);
- atomic_set(&netfs->primary_index->n_active, 1);
+ atomic_set(&cookie->usage, 1);
+ atomic_set(&cookie->n_children, 0);
+ atomic_set(&cookie->n_active, 1);
- netfs->primary_index->def = &fscache_fsdef_netfs_def;
- netfs->primary_index->parent = &fscache_fsdef_index;
- netfs->primary_index->netfs_data = netfs;
- netfs->primary_index->flags = 1 << FSCACHE_COOKIE_ENABLED;
+ cookie->def = &fscache_fsdef_netfs_def;
+ cookie->parent = &fscache_fsdef_index;
+ cookie->netfs_data = netfs;
+ cookie->flags = 1 << FSCACHE_COOKIE_ENABLED;
- atomic_inc(&netfs->primary_index->parent->usage);
- atomic_inc(&netfs->primary_index->parent->n_children);
-
- spin_lock_init(&netfs->primary_index->lock);
- INIT_HLIST_HEAD(&netfs->primary_index->backing_objects);
+ spin_lock_init(&cookie->lock);
+ INIT_HLIST_HEAD(&cookie->backing_objects);
/* check the netfs type is not already present */
down_write(&fscache_addremove_sem);
@@ -62,6 +59,10 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
goto already_registered;
}
+ atomic_inc(&cookie->parent->usage);
+ atomic_inc(&cookie->parent->n_children);
+
+ netfs->primary_index = cookie;
list_add(&netfs->link, &fscache_netfs_list);
ret = 0;
@@ -70,11 +71,8 @@ int __fscache_register_netfs(struct fscache_netfs *netfs)
already_registered:
up_write(&fscache_addremove_sem);
- if (ret < 0) {
- netfs->primary_index->parent = NULL;
- __fscache_cookie_put(netfs->primary_index);
- netfs->primary_index = NULL;
- }
+ if (ret < 0)
+ kmem_cache_free(fscache_cookie_jar, cookie);
_leave(" = %d", ret);
return ret;
diff --git a/fs/fscache/page.c b/fs/fscache/page.c
index 79483b3..6b35fc4 100644
--- a/fs/fscache/page.c
+++ b/fs/fscache/page.c
@@ -816,7 +816,7 @@ static void fscache_write_op(struct fscache_operation *_op)
goto superseded;
page = results[0];
_debug("gang %d [%lx]", n, page->index);
- if (page->index > op->store_limit) {
+ if (page->index >= op->store_limit) {
fscache_stat(&fscache_n_store_pages_over_limit);
goto superseded;
}
diff --git a/fs/fuse/cuse.c b/fs/fuse/cuse.c
index eae2c11..8e3ee19 100644
--- a/fs/fuse/cuse.c
+++ b/fs/fuse/cuse.c
@@ -549,6 +549,8 @@ static int cuse_channel_release(struct inode *inode, struct file *file)
unregister_chrdev_region(cc->cdev->dev, 1);
cdev_del(cc->cdev);
}
+ /* Base reference is now owned by "fud" */
+ fuse_conn_put(&cc->fc);
rc = fuse_dev_release(inode, file); /* puts the base reference */
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 5e2e087..712601f 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1365,15 +1365,19 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
return err;
}
-static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
+static const char *fuse_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(dentry);
struct fuse_conn *fc = get_fuse_conn(inode);
FUSE_ARGS(args);
char *link;
ssize_t ret;
- link = (char *) __get_free_page(GFP_KERNEL);
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
+ link = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!link)
return ERR_PTR(-ENOMEM);
@@ -1385,11 +1389,11 @@ static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
args.out.args[0].value = link;
ret = fuse_simple_request(fc, &args);
if (ret < 0) {
- free_page((unsigned long) link);
+ kfree(link);
link = ERR_PTR(ret);
} else {
link[ret] = '\0';
- *cookie = link;
+ set_delayed_call(done, kfree_link, link);
}
fuse_invalidate_atime(inode);
return link;
@@ -1909,8 +1913,7 @@ static const struct inode_operations fuse_common_inode_operations = {
static const struct inode_operations fuse_symlink_inode_operations = {
.setattr = fuse_setattr,
- .follow_link = fuse_follow_link,
- .put_link = free_page_put_link,
+ .get_link = fuse_get_link,
.readlink = generic_readlink,
.getattr = fuse_getattr,
.setxattr = fuse_setxattr,
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index e0faf8f..570ca40 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1049,6 +1049,7 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes);
flush_dcache_page(page);
+ iov_iter_advance(ii, tmp);
if (!tmp) {
unlock_page(page);
page_cache_release(page);
@@ -1061,7 +1062,6 @@ static ssize_t fuse_fill_write_pages(struct fuse_req *req,
req->page_descs[req->num_pages].length = tmp;
req->num_pages++;
- iov_iter_advance(ii, tmp);
count += tmp;
pos += tmp;
offset += tmp;
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
index 1be3b06..7919326 100644
--- a/fs/gfs2/acl.c
+++ b/fs/gfs2/acl.c
@@ -31,9 +31,9 @@ static const char *gfs2_acl_name(int type)
{
switch (type) {
case ACL_TYPE_ACCESS:
- return GFS2_POSIX_ACL_ACCESS;
+ return XATTR_POSIX_ACL_ACCESS;
case ACL_TYPE_DEFAULT:
- return GFS2_POSIX_ACL_DEFAULT;
+ return XATTR_POSIX_ACL_DEFAULT;
}
return NULL;
}
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
index 2d65ec4..3af4f40 100644
--- a/fs/gfs2/acl.h
+++ b/fs/gfs2/acl.h
@@ -12,8 +12,6 @@
#include "incore.h"
-#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
-#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
#define GFS2_ACL_MAX_ENTRIES(sdp) ((300 << (sdp)->sd_sb.sb_bsize_shift) >> 12)
extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type);
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 009b551..3e94400 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -1715,24 +1715,30 @@ static int gfs2_rename2(struct inode *odir, struct dentry *odentry,
}
/**
- * gfs2_follow_link - Follow a symbolic link
+ * gfs2_get_link - Follow a symbolic link
* @dentry: The dentry of the link
- * @nd: Data that we pass to vfs_follow_link()
+ * @inode: The inode of the link
+ * @done: destructor for return value
*
* This can handle symlinks of any size.
*
* Returns: 0 on success or error code
*/
-static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
+static const char *gfs2_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
+ struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder i_gh;
struct buffer_head *dibh;
unsigned int size;
char *buf;
int error;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
error = gfs2_glock_nq(&i_gh);
if (error) {
@@ -1762,7 +1768,7 @@ static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
out:
gfs2_glock_dq_uninit(&i_gh);
if (!IS_ERR(buf))
- *cookie = buf;
+ set_delayed_call(done, kfree_link, buf);
return buf;
}
@@ -2130,8 +2136,7 @@ const struct inode_operations gfs2_dir_iops = {
const struct inode_operations gfs2_symlink_iops = {
.readlink = generic_readlink,
- .follow_link = gfs2_follow_link,
- .put_link = kfree_put_link,
+ .get_link = gfs2_get_link,
.permission = gfs2_permission,
.setattr = gfs2_setattr,
.getattr = gfs2_getattr,
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index 7aacdf2..dbed9e2 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -1317,9 +1317,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
if ((flags ^ s->s_flags) & MS_RDONLY)
goto error_super;
} else {
- char b[BDEVNAME_SIZE];
-
- strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
+ snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, &args, flags & MS_SILENT ? 1 : 0);
if (error)
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c
index f0fe884..e8dfb47 100644
--- a/fs/gfs2/xattr.c
+++ b/fs/gfs2/xattr.c
@@ -583,11 +583,13 @@ out:
*
* Returns: actual size of data on success, -errno on error
*/
-static int gfs2_xattr_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int gfs2_xattr_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
struct gfs2_ea_location el;
+ int type = handler->flags;
int error;
if (!ip->i_eattr)
@@ -1227,61 +1229,12 @@ int __gfs2_xattr_set(struct inode *inode, const char *name,
return error;
}
-static int gfs2_xattr_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static int gfs2_xattr_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
return __gfs2_xattr_set(d_inode(dentry), name, value,
- size, flags, type);
-}
-
-
-static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
- struct gfs2_ea_header *ea, char *data)
-{
- struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
- unsigned int amount = GFS2_EA_DATA_LEN(ea);
- unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
- int ret;
-
- ret = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
- if (ret)
- return ret;
-
- ret = gfs2_iter_unstuffed(ip, ea, data, NULL);
- gfs2_trans_end(sdp);
-
- return ret;
-}
-
-int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data)
-{
- struct inode *inode = &ip->i_inode;
- struct gfs2_sbd *sdp = GFS2_SB(inode);
- struct gfs2_ea_location el;
- int error;
-
- error = gfs2_ea_find(ip, GFS2_EATYPE_SYS, GFS2_POSIX_ACL_ACCESS, &el);
- if (error)
- return error;
-
- if (GFS2_EA_IS_STUFFED(el.el_ea)) {
- error = gfs2_trans_begin(sdp, RES_DINODE + RES_EATTR, 0);
- if (error == 0) {
- gfs2_trans_add_meta(ip->i_gl, el.el_bh);
- memcpy(GFS2_EA2DATA(el.el_ea), data,
- GFS2_EA_DATA_LEN(el.el_ea));
- }
- } else {
- error = ea_acl_chmod_unstuffed(ip, el.el_ea, data);
- }
-
- brelse(el.el_bh);
- if (error)
- return error;
-
- error = gfs2_setattr_simple(inode, attr);
- gfs2_trans_end(sdp);
- return error;
+ size, flags, handler->flags);
}
static int ea_dealloc_indirect(struct gfs2_inode *ip)
diff --git a/fs/gfs2/xattr.h b/fs/gfs2/xattr.h
index d392f83..2d887c8 100644
--- a/fs/gfs2/xattr.h
+++ b/fs/gfs2/xattr.h
@@ -62,6 +62,5 @@ extern int gfs2_ea_dealloc(struct gfs2_inode *ip);
/* Exported to acl.c */
extern int gfs2_xattr_acl_get(struct gfs2_inode *ip, const char *name, char **data);
-extern int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data);
#endif /* __EATTR_DOT_H__ */
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index aa3f0d6..a3ec3ae 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -166,7 +166,7 @@ int hfs_mdb_get(struct super_block *sb)
pr_warn("continuing without an alternate MDB\n");
}
- HFS_SB(sb)->bitmap = (__be32 *)__get_free_pages(GFP_KERNEL, PAGE_SIZE < 8192 ? 1 : 0);
+ HFS_SB(sb)->bitmap = kmalloc(8192, GFP_KERNEL);
if (!HFS_SB(sb)->bitmap)
goto out;
@@ -360,7 +360,7 @@ void hfs_mdb_put(struct super_block *sb)
unload_nls(HFS_SB(sb)->nls_io);
unload_nls(HFS_SB(sb)->nls_disk);
- free_pages((unsigned long)HFS_SB(sb)->bitmap, PAGE_SIZE < 8192 ? 1 : 0);
+ kfree(HFS_SB(sb)->bitmap);
kfree(HFS_SB(sb));
sb->s_fs_info = NULL;
}
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 6dd107d..19b33f8 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -403,6 +403,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
} else if (S_ISLNK(inode->i_mode)) {
sbi->file_count++;
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &hfsplus_aops;
hip->clump_blocks = 1;
} else
@@ -526,6 +527,7 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
inode->i_mapping->a_ops = &hfsplus_aops;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &hfsplus_aops;
} else {
init_special_inode(inode, inode->i_mode,
diff --git a/fs/hfsplus/posix_acl.c b/fs/hfsplus/posix_acl.c
index df0c9af..afb33ed 100644
--- a/fs/hfsplus/posix_acl.c
+++ b/fs/hfsplus/posix_acl.c
@@ -21,10 +21,10 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
switch (type) {
case ACL_TYPE_ACCESS:
- xattr_name = POSIX_ACL_XATTR_ACCESS;
+ xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- xattr_name = POSIX_ACL_XATTR_DEFAULT;
+ xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
return ERR_PTR(-EINVAL);
@@ -66,7 +66,7 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
switch (type) {
case ACL_TYPE_ACCESS:
- xattr_name = POSIX_ACL_XATTR_ACCESS;
+ xattr_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
err = posix_acl_equiv_mode(acl, &inode->i_mode);
if (err < 0)
@@ -76,7 +76,7 @@ int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
break;
case ACL_TYPE_DEFAULT:
- xattr_name = POSIX_ACL_XATTR_DEFAULT;
+ xattr_name = XATTR_NAME_POSIX_ACL_DEFAULT;
if (!S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0;
break;
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c
index 416b1db..ab01530 100644
--- a/fs/hfsplus/xattr.c
+++ b/fs/hfsplus/xattr.c
@@ -431,9 +431,6 @@ int hfsplus_setxattr(struct dentry *dentry, const char *name,
char *xattr_name;
int res;
- if (!strcmp(name, ""))
- return -EINVAL;
-
xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
GFP_KERNEL);
if (!xattr_name)
@@ -589,9 +586,6 @@ ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
int res;
char *xattr_name;
- if (!strcmp(name, ""))
- return -EINVAL;
-
xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
GFP_KERNEL);
if (!xattr_name)
@@ -849,12 +843,10 @@ end_removexattr:
return err;
}
-static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int hfsplus_osx_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (!strcmp(name, ""))
- return -EINVAL;
-
/*
* Don't allow retrieving properly prefixed attributes
* by prepending them with "osx."
@@ -871,12 +863,10 @@ static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name,
return __hfsplus_getxattr(d_inode(dentry), name, buffer, size);
}
-static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int hfsplus_osx_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
- if (!strcmp(name, ""))
- return -EINVAL;
-
/*
* Don't allow setting properly prefixed attributes
* by prepending them with "osx."
@@ -893,19 +883,8 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
return __hfsplus_setxattr(d_inode(dentry), name, buffer, size, flags);
}
-static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- /*
- * This method is not used.
- * It is used hfsplus_listxattr() instead of generic_listxattr().
- */
- return -EOPNOTSUPP;
-}
-
const struct xattr_handler hfsplus_xattr_osx_handler = {
.prefix = XATTR_MAC_OSX_PREFIX,
- .list = hfsplus_osx_listxattr,
.get = hfsplus_osx_getxattr,
.set = hfsplus_osx_setxattr,
};
diff --git a/fs/hfsplus/xattr_security.c b/fs/hfsplus/xattr_security.c
index aacff00..72a68a3 100644
--- a/fs/hfsplus/xattr_security.c
+++ b/fs/hfsplus/xattr_security.c
@@ -13,32 +13,24 @@
#include "xattr.h"
#include "acl.h"
-static int hfsplus_security_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int hfsplus_security_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
return hfsplus_getxattr(dentry, name, buffer, size,
XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN);
}
-static int hfsplus_security_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int hfsplus_security_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
return hfsplus_setxattr(dentry, name, buffer, size, flags,
XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN);
}
-static size_t hfsplus_security_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- /*
- * This method is not used.
- * It is used hfsplus_listxattr() instead of generic_listxattr().
- */
- return -EOPNOTSUPP;
-}
-
static int hfsplus_initxattrs(struct inode *inode,
const struct xattr *xattr_array,
void *fs_info)
@@ -92,7 +84,6 @@ int hfsplus_init_inode_security(struct inode *inode,
const struct xattr_handler hfsplus_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = hfsplus_security_listxattr,
.get = hfsplus_security_getxattr,
.set = hfsplus_security_setxattr,
};
diff --git a/fs/hfsplus/xattr_trusted.c b/fs/hfsplus/xattr_trusted.c
index bcf65089..95a7704 100644
--- a/fs/hfsplus/xattr_trusted.c
+++ b/fs/hfsplus/xattr_trusted.c
@@ -11,34 +11,25 @@
#include "hfsplus_fs.h"
#include "xattr.h"
-static int hfsplus_trusted_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int hfsplus_trusted_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
return hfsplus_getxattr(dentry, name, buffer, size,
XATTR_TRUSTED_PREFIX,
XATTR_TRUSTED_PREFIX_LEN);
}
-static int hfsplus_trusted_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int hfsplus_trusted_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
return hfsplus_setxattr(dentry, name, buffer, size, flags,
XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
}
-static size_t hfsplus_trusted_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- /*
- * This method is not used.
- * It is used hfsplus_listxattr() instead of generic_listxattr().
- */
- return -EOPNOTSUPP;
-}
-
const struct xattr_handler hfsplus_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
- .list = hfsplus_trusted_listxattr,
.get = hfsplus_trusted_getxattr,
.set = hfsplus_trusted_setxattr,
};
diff --git a/fs/hfsplus/xattr_user.c b/fs/hfsplus/xattr_user.c
index 5aa0e6d..6fc269b 100644
--- a/fs/hfsplus/xattr_user.c
+++ b/fs/hfsplus/xattr_user.c
@@ -11,34 +11,25 @@
#include "hfsplus_fs.h"
#include "xattr.h"
-static int hfsplus_user_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int hfsplus_user_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
return hfsplus_getxattr(dentry, name, buffer, size,
XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
}
-static int hfsplus_user_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int hfsplus_user_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
return hfsplus_setxattr(dentry, name, buffer, size, flags,
XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
}
-static size_t hfsplus_user_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- /*
- * This method is not used.
- * It is used hfsplus_listxattr() instead of generic_listxattr().
- */
- return -EOPNOTSUPP;
-}
-
const struct xattr_handler hfsplus_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
- .list = hfsplus_user_listxattr,
.get = hfsplus_user_getxattr,
.set = hfsplus_user_setxattr,
};
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 2ac99db..f49be23 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -730,15 +730,13 @@ static int hostfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
init_special_inode(inode, mode, dev);
err = do_mknod(name, mode, MAJOR(dev), MINOR(dev));
- if (!err)
+ if (err)
goto out_free;
err = read_name(inode, name);
__putname(name);
if (err)
goto out_put;
- if (err)
- goto out_put;
d_instantiate(dentry, inode);
return 0;
@@ -892,9 +890,14 @@ static const struct inode_operations hostfs_dir_iops = {
.setattr = hostfs_setattr,
};
-static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *hostfs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- char *link = __getname();
+ char *link;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+ link = kmalloc(PATH_MAX, GFP_KERNEL);
if (link) {
char *path = dentry_name(dentry);
int err = -ENOMEM;
@@ -905,25 +908,20 @@ static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
__putname(path);
}
if (err < 0) {
- __putname(link);
+ kfree(link);
return ERR_PTR(err);
}
} else {
return ERR_PTR(-ENOMEM);
}
- return *cookie = link;
-}
-
-static void hostfs_put_link(struct inode *unused, void *cookie)
-{
- __putname(cookie);
+ set_delayed_call(done, kfree_link, link);
+ return link;
}
static const struct inode_operations hostfs_link_iops = {
.readlink = generic_readlink,
- .follow_link = hostfs_follow_link,
- .put_link = hostfs_put_link,
+ .get_link = hostfs_get_link,
};
static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent)
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 933c737..1f3c6d7 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -77,6 +77,7 @@ void hpfs_read_inode(struct inode *i)
kfree(ea);
i->i_mode = S_IFLNK | 0777;
i->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(i);
i->i_data.a_ops = &hpfs_symlink_aops;
set_nlink(i, 1);
i->i_size = ea_size;
diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c
index a69bbc1..a136929 100644
--- a/fs/hpfs/map.c
+++ b/fs/hpfs/map.c
@@ -133,7 +133,7 @@ __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp)
void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock)
{
struct quad_buffer_head qbh;
- u32 *directory;
+ __le32 *directory;
u32 n_hotfixes, n_used_hotfixes;
unsigned i;
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index ae4d5a1..506765a 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -332,6 +332,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
result->i_blocks = 1;
set_nlink(result, 1);
result->i_size = strlen(symlink);
+ inode_nohighmem(result);
result->i_op = &page_symlink_inode_operations;
result->i_data.a_ops = &hpfs_symlink_aops;
@@ -500,7 +501,7 @@ out:
static int hpfs_symlink_readpage(struct file *file, struct page *page)
{
- char *link = kmap(page);
+ char *link = page_address(page);
struct inode *i = page->mapping->host;
struct fnode *fnode;
struct buffer_head *bh;
@@ -516,14 +517,12 @@ static int hpfs_symlink_readpage(struct file *file, struct page *page)
goto fail;
hpfs_unlock(i->i_sb);
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
fail:
hpfs_unlock(i->i_sb);
SetPageError(page);
- kunmap(page);
unlock_page(page);
return err;
}
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 316adb9..d8f51ee 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -332,12 +332,17 @@ static void remove_huge_page(struct page *page)
* truncation is indicated by end of range being LLONG_MAX
* In this case, we first scan the range and release found pages.
* After releasing pages, hugetlb_unreserve_pages cleans up region/reserv
- * maps and global counts.
+ * maps and global counts. Page faults can not race with truncation
+ * in this routine. hugetlb_no_page() prevents page faults in the
+ * truncated range. It checks i_size before allocation, and again after
+ * with the page table lock for the page held. The same lock must be
+ * acquired to unmap a page.
* hole punch is indicated if end is not LLONG_MAX
* In the hole punch case we scan the range and release found pages.
* Only when releasing a page is the associated region/reserv map
* deleted. The region/reserv map for ranges without associated
- * pages are not modified.
+ * pages are not modified. Page faults can race with hole punch.
+ * This is indicated if we find a mapped page.
* Note: If the passed end of range value is beyond the end of file, but
* not LLONG_MAX this routine still performs a hole punch operation.
*/
@@ -361,46 +366,37 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
next = start;
while (next < end) {
/*
- * Make sure to never grab more pages that we
- * might possibly need.
+ * Don't grab more pages than the number left in the range.
*/
if (end - next < lookup_nr)
lookup_nr = end - next;
/*
- * This pagevec_lookup() may return pages past 'end',
- * so we must check for page->index > end.
+ * When no more pages are found, we are done.
*/
- if (!pagevec_lookup(&pvec, mapping, next, lookup_nr)) {
- if (next == start)
- break;
- next = start;
- continue;
- }
+ if (!pagevec_lookup(&pvec, mapping, next, lookup_nr))
+ break;
for (i = 0; i < pagevec_count(&pvec); ++i) {
struct page *page = pvec.pages[i];
u32 hash;
+ /*
+ * The page (index) could be beyond end. This is
+ * only possible in the punch hole case as end is
+ * max page offset in the truncate case.
+ */
+ next = page->index;
+ if (next >= end)
+ break;
+
hash = hugetlb_fault_mutex_hash(h, current->mm,
&pseudo_vma,
mapping, next, 0);
mutex_lock(&hugetlb_fault_mutex_table[hash]);
lock_page(page);
- if (page->index >= end) {
- unlock_page(page);
- mutex_unlock(&hugetlb_fault_mutex_table[hash]);
- next = end; /* we are done */
- break;
- }
-
- /*
- * If page is mapped, it was faulted in after being
- * unmapped. Do nothing in this race case. In the
- * normal case page is not mapped.
- */
- if (!page_mapped(page)) {
+ if (likely(!page_mapped(page))) {
bool rsv_on_error = !PagePrivate(page);
/*
* We must free the huge page and remove
@@ -421,17 +417,23 @@ static void remove_inode_hugepages(struct inode *inode, loff_t lstart,
hugetlb_fix_reserve_counts(
inode, rsv_on_error);
}
+ } else {
+ /*
+ * If page is mapped, it was faulted in after
+ * being unmapped. It indicates a race between
+ * hole punch and page fault. Do nothing in
+ * this case. Getting here in a truncate
+ * operation is a bug.
+ */
+ BUG_ON(truncate_op);
}
- if (page->index > next)
- next = page->index;
-
- ++next;
unlock_page(page);
-
mutex_unlock(&hugetlb_fault_mutex_table[hash]);
}
+ ++next;
huge_pagevec_release(&pvec);
+ cond_resched();
}
if (truncate_op)
@@ -647,9 +649,6 @@ static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset,
if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size)
i_size_write(inode, offset + len);
inode->i_ctime = CURRENT_TIME;
- spin_lock(&inode->i_lock);
- inode->i_private = NULL;
- spin_unlock(&inode->i_lock);
out:
mutex_unlock(&inode->i_mutex);
return error;
@@ -761,6 +760,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb,
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
break;
}
lockdep_annotate_inode_mutex_key(inode);
diff --git a/fs/inode.c b/fs/inode.c
index 1be5f90..4230f66 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -225,7 +225,7 @@ void __destroy_inode(struct inode *inode)
inode_detach_wb(inode);
security_inode_free(inode);
fsnotify_inode_delete(inode);
- locks_free_lock_context(inode->i_flctx);
+ locks_free_lock_context(inode);
if (!inode->i_nlink) {
WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0);
atomic_long_dec(&inode->i_sb->s_remove_count);
@@ -2028,3 +2028,9 @@ void inode_set_flags(struct inode *inode, unsigned int flags,
new_flags) != old_flags));
}
EXPORT_SYMBOL(inode_set_flags);
+
+void inode_nohighmem(struct inode *inode)
+{
+ mapping_set_gfp_mask(inode->i_mapping, GFP_USER);
+}
+EXPORT_SYMBOL(inode_nohighmem);
diff --git a/fs/internal.h b/fs/internal.h
index 71859c4d..b71deee 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -55,7 +55,7 @@ extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
/*
* namespace.c
*/
-extern int copy_mount_options(const void __user *, unsigned long *);
+extern void *copy_mount_options(const void __user *);
extern char *copy_mount_string(const void __user *);
extern struct vfsmount *lookup_mnt(struct path *);
@@ -151,3 +151,10 @@ extern void mnt_pin_kill(struct mount *m);
* fs/nsfs.c
*/
extern struct dentry_operations ns_dentry_operations;
+
+/*
+ * fs/ioctl.c
+ */
+extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd,
+ unsigned long arg);
+extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 5d01d26..29466c3 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -15,6 +15,7 @@
#include <linux/writeback.h>
#include <linux/buffer_head.h>
#include <linux/falloc.h>
+#include "internal.h"
#include <asm/ioctls.h>
@@ -32,8 +33,7 @@
*
* Returns 0 on success, -errno on error.
*/
-static long vfs_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int error = -ENOTTY;
@@ -215,6 +215,29 @@ static int ioctl_fiemap(struct file *filp, unsigned long arg)
return error;
}
+static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd,
+ u64 off, u64 olen, u64 destoff)
+{
+ struct fd src_file = fdget(srcfd);
+ int ret;
+
+ if (!src_file.file)
+ return -EBADF;
+ ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen);
+ fdput(src_file);
+ return ret;
+}
+
+static long ioctl_file_clone_range(struct file *file, void __user *argp)
+{
+ struct file_clone_range args;
+
+ if (copy_from_user(&args, argp, sizeof(args)))
+ return -EFAULT;
+ return ioctl_file_clone(file, args.src_fd, args.src_offset,
+ args.src_length, args.dest_offset);
+}
+
#ifdef CONFIG_BLOCK
static inline sector_t logical_to_blk(struct inode *inode, loff_t offset)
@@ -545,6 +568,41 @@ static int ioctl_fsthaw(struct file *filp)
return thaw_super(sb);
}
+static long ioctl_file_dedupe_range(struct file *file, void __user *arg)
+{
+ struct file_dedupe_range __user *argp = arg;
+ struct file_dedupe_range *same = NULL;
+ int ret;
+ unsigned long size;
+ u16 count;
+
+ if (get_user(count, &argp->dest_count)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ size = offsetof(struct file_dedupe_range __user, info[count]);
+
+ same = memdup_user(argp, size);
+ if (IS_ERR(same)) {
+ ret = PTR_ERR(same);
+ same = NULL;
+ goto out;
+ }
+
+ ret = vfs_dedupe_file_range(file, same);
+ if (ret)
+ goto out;
+
+ ret = copy_to_user(argp, same, size);
+ if (ret)
+ ret = -EFAULT;
+
+out:
+ kfree(same);
+ return ret;
+}
+
/*
* When you add any new common ioctls to the switches above and below
* please update compat_sys_ioctl() too.
@@ -600,6 +658,15 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
case FIGETBSZ:
return put_user(inode->i_sb->s_blocksize, argp);
+ case FICLONE:
+ return ioctl_file_clone(filp, arg, 0, 0, 0);
+
+ case FICLONERANGE:
+ return ioctl_file_clone_range(filp, argp);
+
+ case FIDEDUPERANGE:
+ return ioctl_file_dedupe_range(filp, argp);
+
default:
if (S_ISREG(inode->i_mode))
error = file_ioctl(filp, cmd, arg);
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index d67a16f..61abdc4 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -1417,6 +1417,7 @@ static int isofs_read_inode(struct inode *inode, int relocated)
inode->i_fop = &isofs_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &isofs_symlink_aops;
} else
/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 735d752..5384ceb 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -687,7 +687,7 @@ static int rock_ridge_symlink_readpage(struct file *file, struct page *page)
struct inode *inode = page->mapping->host;
struct iso_inode_info *ei = ISOFS_I(inode);
struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
- char *link = kmap(page);
+ char *link = page_address(page);
unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
struct buffer_head *bh;
char *rpnt = link;
@@ -774,7 +774,6 @@ repeat:
brelse(bh);
*rpnt = '\0';
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
@@ -791,7 +790,6 @@ fail:
brelse(bh);
error:
SetPageError(page);
- kunmap(page);
unlock_page(page);
return -EIO;
}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index 89463ee..081dff0 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -764,13 +764,11 @@ void jbd2_journal_unlock_updates (journal_t *journal)
static void warn_dirty_buffer(struct buffer_head *bh)
{
- char b[BDEVNAME_SIZE];
-
printk(KERN_WARNING
- "JBD2: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). "
+ "JBD2: Spotted dirty metadata buffer (dev = %pg, blocknr = %llu). "
"There's a risk of filesystem corruption in case of system "
"crash.\n",
- bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr);
+ bh->b_bdev, (unsigned long long)bh->b_blocknr);
}
/* Call t_frozen trigger and copy buffer data into jh->b_frozen_data. */
@@ -1009,7 +1007,8 @@ out:
}
/* Fast check whether buffer is already attached to the required transaction */
-static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh)
+static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh,
+ bool undo)
{
struct journal_head *jh;
bool ret = false;
@@ -1036,6 +1035,9 @@ static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh)
jh = READ_ONCE(bh->b_private);
if (!jh)
goto out;
+ /* For undo access buffer must have data copied */
+ if (undo && !jh->b_committed_data)
+ goto out;
if (jh->b_transaction != handle->h_transaction &&
jh->b_next_transaction != handle->h_transaction)
goto out;
@@ -1073,7 +1075,7 @@ int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh)
struct journal_head *jh;
int rc;
- if (jbd2_write_access_granted(handle, bh))
+ if (jbd2_write_access_granted(handle, bh, false))
return 0;
jh = jbd2_journal_add_journal_head(bh);
@@ -1210,7 +1212,7 @@ int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
char *committed_data = NULL;
JBUFFER_TRACE(jh, "entry");
- if (jbd2_write_access_granted(handle, bh))
+ if (jbd2_write_access_granted(handle, bh, true))
return 0;
jh = jbd2_journal_add_journal_head(bh);
@@ -2152,6 +2154,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh,
if (!buffer_dirty(bh)) {
/* bdflush has written it. We can drop it now */
+ __jbd2_journal_remove_checkpoint(jh);
goto zap_buffer;
}
@@ -2181,6 +2184,7 @@ static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh,
/* The orphan record's transaction has
* committed. We can cleanse this buffer */
clear_buffer_jbddirty(bh);
+ __jbd2_journal_remove_checkpoint(jh);
goto zap_buffer;
}
}
diff --git a/fs/jffs2/security.c b/fs/jffs2/security.c
index d4b43fb..7a28fac 100644
--- a/fs/jffs2/security.c
+++ b/fs/jffs2/security.c
@@ -48,42 +48,24 @@ int jffs2_init_security(struct inode *inode, struct inode *dir,
}
/* ---- XATTR Handler for "security.*" ----------------- */
-static int jffs2_security_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int jffs2_security_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (!strcmp(name, ""))
- return -EINVAL;
-
return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY,
name, buffer, size);
}
-static int jffs2_security_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int jffs2_security_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
- if (!strcmp(name, ""))
- return -EINVAL;
-
return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_SECURITY,
name, buffer, size, flags);
}
-static size_t jffs2_security_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- size_t retlen = XATTR_SECURITY_PREFIX_LEN + name_len + 1;
-
- if (list && retlen <= list_size) {
- strcpy(list, XATTR_SECURITY_PREFIX);
- strcpy(list + XATTR_SECURITY_PREFIX_LEN, name);
- }
-
- return retlen;
-}
-
const struct xattr_handler jffs2_security_xattr_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = jffs2_security_listxattr,
.set = jffs2_security_setxattr,
.get = jffs2_security_getxattr
};
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 8ce2f24..2cabd64 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -14,7 +14,7 @@
const struct inode_operations jffs2_symlink_inode_operations =
{
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = jffs2_setattr,
.setxattr = jffs2_setxattr,
.getxattr = jffs2_getxattr,
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index f092fee..da3e185 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -967,7 +967,8 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
struct jffs2_xattr_ref *ref, **pref;
struct jffs2_xattr_datum *xd;
const struct xattr_handler *xhandle;
- ssize_t len, rc;
+ const char *prefix;
+ ssize_t prefix_len, len, rc;
int retry = 0;
rc = check_xattr_ref_inode(c, ic);
@@ -998,17 +999,23 @@ ssize_t jffs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
}
}
xhandle = xprefix_to_handler(xd->xprefix);
- if (!xhandle)
+ if (!xhandle || (xhandle->list && !xhandle->list(dentry)))
continue;
+ prefix = xhandle->prefix ?: xhandle->name;
+ prefix_len = strlen(prefix);
+ rc = prefix_len + xd->name_len + 1;
+
if (buffer) {
- rc = xhandle->list(dentry, buffer+len, size-len,
- xd->xname, xd->name_len, xd->flags);
- } else {
- rc = xhandle->list(dentry, NULL, 0, xd->xname,
- xd->name_len, xd->flags);
+ if (rc > size - len) {
+ rc = -ERANGE;
+ goto out;
+ }
+ memcpy(buffer, prefix, prefix_len);
+ buffer += prefix_len;
+ memcpy(buffer, xd->xname, xd->name_len);
+ buffer += xd->name_len;
+ *buffer++ = 0;
}
- if (rc < 0)
- goto out;
len += rc;
}
rc = len;
diff --git a/fs/jffs2/xattr_trusted.c b/fs/jffs2/xattr_trusted.c
index ceaf9c6..b2555ef 100644
--- a/fs/jffs2/xattr_trusted.c
+++ b/fs/jffs2/xattr_trusted.c
@@ -16,35 +16,25 @@
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-static int jffs2_trusted_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int jffs2_trusted_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (!strcmp(name, ""))
- return -EINVAL;
return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED,
name, buffer, size);
}
-static int jffs2_trusted_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int jffs2_trusted_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
- if (!strcmp(name, ""))
- return -EINVAL;
return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_TRUSTED,
name, buffer, size, flags);
}
-static size_t jffs2_trusted_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
+static bool jffs2_trusted_listxattr(struct dentry *dentry)
{
- size_t retlen = XATTR_TRUSTED_PREFIX_LEN + name_len + 1;
-
- if (list && retlen<=list_size) {
- strcpy(list, XATTR_TRUSTED_PREFIX);
- strcpy(list + XATTR_TRUSTED_PREFIX_LEN, name);
- }
-
- return retlen;
+ return capable(CAP_SYS_ADMIN);
}
const struct xattr_handler jffs2_trusted_xattr_handler = {
diff --git a/fs/jffs2/xattr_user.c b/fs/jffs2/xattr_user.c
index a71391e..539bd63 100644
--- a/fs/jffs2/xattr_user.c
+++ b/fs/jffs2/xattr_user.c
@@ -16,40 +16,24 @@
#include <linux/mtd/mtd.h>
#include "nodelist.h"
-static int jffs2_user_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int jffs2_user_getxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (!strcmp(name, ""))
- return -EINVAL;
return do_jffs2_getxattr(d_inode(dentry), JFFS2_XPREFIX_USER,
name, buffer, size);
}
-static int jffs2_user_setxattr(struct dentry *dentry, const char *name,
- const void *buffer, size_t size, int flags, int type)
+static int jffs2_user_setxattr(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *buffer, size_t size, int flags)
{
- if (!strcmp(name, ""))
- return -EINVAL;
return do_jffs2_setxattr(d_inode(dentry), JFFS2_XPREFIX_USER,
name, buffer, size, flags);
}
-static size_t jffs2_user_listxattr(struct dentry *dentry, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- size_t retlen = XATTR_USER_PREFIX_LEN + name_len + 1;
-
- if (list && retlen <= list_size) {
- strcpy(list, XATTR_USER_PREFIX);
- strcpy(list + XATTR_USER_PREFIX_LEN, name);
- }
-
- return retlen;
-}
-
const struct xattr_handler jffs2_user_xattr_handler = {
.prefix = XATTR_USER_PREFIX,
- .list = jffs2_user_listxattr,
.set = jffs2_user_setxattr,
.get = jffs2_user_getxattr
};
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index 0c8ca83..4945685 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -40,10 +40,10 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type)
switch(type) {
case ACL_TYPE_ACCESS:
- ea_name = POSIX_ACL_XATTR_ACCESS;
+ ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- ea_name = POSIX_ACL_XATTR_DEFAULT;
+ ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
return ERR_PTR(-EINVAL);
@@ -82,7 +82,7 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
switch (type) {
case ACL_TYPE_ACCESS:
- ea_name = POSIX_ACL_XATTR_ACCESS;
+ ea_name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
rc = posix_acl_equiv_mode(acl, &inode->i_mode);
if (rc < 0)
@@ -94,7 +94,7 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
}
break;
case ACL_TYPE_DEFAULT:
- ea_name = POSIX_ACL_XATTR_DEFAULT;
+ ea_name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
return -EINVAL;
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index 41aa3ca..9d9bae6 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -60,6 +60,7 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
} else if (S_ISLNK(inode->i_mode)) {
if (inode->i_size >= IDATASIZE) {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &jfs_aops;
} else {
inode->i_op = &jfs_fast_symlink_inode_operations;
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index a69bdf2..a270cb7 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -1835,17 +1835,16 @@ static int lbmLogInit(struct jfs_log * log)
for (i = 0; i < LOGPAGES;) {
char *buffer;
uint offset;
- struct page *page;
+ struct page *page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- buffer = (char *) get_zeroed_page(GFP_KERNEL);
- if (buffer == NULL)
+ if (!page)
goto error;
- page = virt_to_page(buffer);
+ buffer = page_address(page);
for (offset = 0; offset < PAGE_SIZE; offset += LOGPSIZE) {
lbuf = kmalloc(sizeof(struct lbuf), GFP_KERNEL);
if (lbuf == NULL) {
if (offset == 0)
- free_page((unsigned long) buffer);
+ __free_page(page);
goto error;
}
if (offset) /* we already have one reference */
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 9d7551f..701f893 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -983,6 +983,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
jfs_info("jfs_symlink: allocate extent ip:0x%p", ip);
ip->i_op = &jfs_symlink_inode_operations;
+ inode_nohighmem(ip);
ip->i_mapping->a_ops = &jfs_aops;
/*
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index 5929e23..f8db4fd 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -23,7 +23,7 @@
const struct inode_operations jfs_fast_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
@@ -33,8 +33,7 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {
const struct inode_operations jfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = jfs_setattr,
.setxattr = jfs_setxattr,
.getxattr = jfs_getxattr,
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index 756dd56..16405ae 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -205,7 +205,7 @@ int kernfs_iop_removexattr(struct dentry *dentry, const char *name)
if (!attrs)
return -ENOMEM;
- return simple_xattr_remove(&attrs->xattrs, name);
+ return simple_xattr_set(&attrs->xattrs, name, NULL, 0, XATTR_REPLACE);
}
ssize_t kernfs_iop_getxattr(struct dentry *dentry, const char *name, void *buf,
@@ -230,7 +230,7 @@ ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
if (!attrs)
return -ENOMEM;
- return simple_xattr_list(&attrs->xattrs, buf, size);
+ return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size);
}
static inline void set_default_inode_attr(struct inode *inode, umode_t mode)
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index db27252..117b8b3 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -112,18 +112,25 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
return error;
}
-static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie)
+static const char *kernfs_iop_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- int error = -ENOMEM;
- unsigned long page = get_zeroed_page(GFP_KERNEL);
- if (!page)
+ char *body;
+ int error;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+ body = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!body)
return ERR_PTR(-ENOMEM);
- error = kernfs_getlink(dentry, (char *)page);
+ error = kernfs_getlink(dentry, body);
if (unlikely(error < 0)) {
- free_page((unsigned long)page);
+ kfree(body);
return ERR_PTR(error);
}
- return *cookie = (char *)page;
+ set_delayed_call(done, kfree_link, body);
+ return body;
}
const struct inode_operations kernfs_symlink_iops = {
@@ -132,8 +139,7 @@ const struct inode_operations kernfs_symlink_iops = {
.getxattr = kernfs_iop_getxattr,
.listxattr = kernfs_iop_listxattr,
.readlink = generic_readlink,
- .follow_link = kernfs_iop_follow_link,
- .put_link = free_page_put_link,
+ .get_link = kernfs_iop_get_link,
.setattr = kernfs_iop_setattr,
.getattr = kernfs_iop_getattr,
.permission = kernfs_iop_permission,
diff --git a/fs/libfs.c b/fs/libfs.c
index c7cbfb0..0149129 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -1019,17 +1019,12 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
}
EXPORT_SYMBOL(noop_fsync);
-void kfree_put_link(struct inode *unused, void *cookie)
+/* Because kfree isn't assignment-compatible with void(void*) ;-/ */
+void kfree_link(void *p)
{
- kfree(cookie);
+ kfree(p);
}
-EXPORT_SYMBOL(kfree_put_link);
-
-void free_page_put_link(struct inode *unused, void *cookie)
-{
- free_page((unsigned long) cookie);
-}
-EXPORT_SYMBOL(free_page_put_link);
+EXPORT_SYMBOL(kfree_link);
/*
* nop .set_page_dirty method so that people can use .page_mkwrite on
@@ -1092,14 +1087,15 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
}
EXPORT_SYMBOL(simple_nosetlease);
-const char *simple_follow_link(struct dentry *dentry, void **cookie)
+const char *simple_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *done)
{
- return d_inode(dentry)->i_link;
+ return inode->i_link;
}
-EXPORT_SYMBOL(simple_follow_link);
+EXPORT_SYMBOL(simple_get_link);
const struct inode_operations simple_symlink_inode_operations = {
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.readlink = generic_readlink
};
EXPORT_SYMBOL(simple_symlink_inode_operations);
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 969d589..d716c99 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
atomic_inc(&nsm->sm_count);
else {
host = NULL;
- nsm = nsm_get_handle(ni->sap, ni->salen,
+ nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
ni->hostname, ni->hostname_len);
if (unlikely(nsm == NULL)) {
dprintk("lockd: %s failed; no nsm handle\n",
@@ -161,6 +161,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
host->h_nsmhandle = nsm;
host->h_addrbuf = nsm->sm_addrbuf;
host->net = ni->net;
+ strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));
out:
return host;
@@ -534,17 +535,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
/**
* nlm_host_rebooted - Release all resources held by rebooted host
+ * @net: network namespace
* @info: pointer to decoded results of NLM_SM_NOTIFY call
*
* We were notified that the specified host has rebooted. Release
* all resources held by that peer.
*/
-void nlm_host_rebooted(const struct nlm_reboot *info)
+void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
{
struct nsm_handle *nsm;
struct nlm_host *host;
- nsm = nsm_reboot_lookup(info);
+ nsm = nsm_reboot_lookup(net, info);
if (unlikely(nsm == NULL))
return;
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 47a32b6..19166d4 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -42,7 +42,7 @@ struct nsm_args {
u32 proc;
char *mon_name;
- char *nodename;
+ const char *nodename;
};
struct nsm_res {
@@ -51,7 +51,6 @@ struct nsm_res {
};
static const struct rpc_program nsm_program;
-static LIST_HEAD(nsm_handles);
static DEFINE_SPINLOCK(nsm_lock);
/*
@@ -87,69 +86,18 @@ static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
return rpc_create(&args);
}
-static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
- struct rpc_clnt *clnt)
-{
- spin_lock(&ln->nsm_clnt_lock);
- if (ln->nsm_users == 0) {
- if (clnt == NULL)
- goto out;
- ln->nsm_clnt = clnt;
- }
- clnt = ln->nsm_clnt;
- ln->nsm_users++;
-out:
- spin_unlock(&ln->nsm_clnt_lock);
- return clnt;
-}
-
-static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
-{
- struct rpc_clnt *clnt, *new;
- struct lockd_net *ln = net_generic(net, lockd_net_id);
-
- clnt = nsm_client_set(ln, NULL);
- if (clnt != NULL)
- goto out;
-
- clnt = new = nsm_create(net, nodename);
- if (IS_ERR(clnt))
- goto out;
-
- clnt = nsm_client_set(ln, new);
- if (clnt != new)
- rpc_shutdown_client(new);
-out:
- return clnt;
-}
-
-static void nsm_client_put(struct net *net)
-{
- struct lockd_net *ln = net_generic(net, lockd_net_id);
- struct rpc_clnt *clnt = NULL;
-
- spin_lock(&ln->nsm_clnt_lock);
- ln->nsm_users--;
- if (ln->nsm_users == 0) {
- clnt = ln->nsm_clnt;
- ln->nsm_clnt = NULL;
- }
- spin_unlock(&ln->nsm_clnt_lock);
- if (clnt != NULL)
- rpc_shutdown_client(clnt);
-}
-
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
- struct rpc_clnt *clnt)
+ const struct nlm_host *host)
{
int status;
+ struct rpc_clnt *clnt;
struct nsm_args args = {
.priv = &nsm->sm_priv,
.prog = NLM_PROGRAM,
.vers = 3,
.proc = NLMPROC_NSM_NOTIFY,
.mon_name = nsm->sm_mon_name,
- .nodename = clnt->cl_nodename,
+ .nodename = host->nodename,
};
struct rpc_message msg = {
.rpc_argp = &args,
@@ -158,6 +106,13 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
memset(res, 0, sizeof(*res));
+ clnt = nsm_create(host->net, host->nodename);
+ if (IS_ERR(clnt)) {
+ dprintk("lockd: failed to create NSM upcall transport, "
+ "status=%ld, net=%p\n", PTR_ERR(clnt), host->net);
+ return PTR_ERR(clnt);
+ }
+
msg.rpc_proc = &clnt->cl_procinfo[proc];
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
if (status == -ECONNREFUSED) {
@@ -171,6 +126,8 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
status);
else
status = 0;
+
+ rpc_shutdown_client(clnt);
return status;
}
@@ -190,32 +147,19 @@ int nsm_monitor(const struct nlm_host *host)
struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
int status;
- struct rpc_clnt *clnt;
- const char *nodename = NULL;
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
if (nsm->sm_monitored)
return 0;
- if (host->h_rpcclnt)
- nodename = host->h_rpcclnt->cl_nodename;
-
/*
* Choose whether to record the caller_name or IP address of
* this peer in the local rpc.statd's database.
*/
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
- clnt = nsm_client_get(host->net, nodename);
- if (IS_ERR(clnt)) {
- status = PTR_ERR(clnt);
- dprintk("lockd: failed to create NSM upcall transport, "
- "status=%d, net=%p\n", status, host->net);
- return status;
- }
-
- status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
+ status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host);
if (unlikely(res.status != 0))
status = -EIO;
if (unlikely(status < 0)) {
@@ -247,11 +191,9 @@ void nsm_unmonitor(const struct nlm_host *host)
if (atomic_read(&nsm->sm_count) == 1
&& nsm->sm_monitored && !nsm->sm_sticky) {
- struct lockd_net *ln = net_generic(host->net, lockd_net_id);
-
dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
- status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
+ status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host);
if (res.status != 0)
status = -EIO;
if (status < 0)
@@ -259,38 +201,38 @@ void nsm_unmonitor(const struct nlm_host *host)
nsm->sm_name);
else
nsm->sm_monitored = 0;
-
- nsm_client_put(host->net);
}
}
-static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
- const size_t len)
+static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles,
+ const char *hostname, const size_t len)
{
struct nsm_handle *nsm;
- list_for_each_entry(nsm, &nsm_handles, sm_link)
+ list_for_each_entry(nsm, nsm_handles, sm_link)
if (strlen(nsm->sm_name) == len &&
memcmp(nsm->sm_name, hostname, len) == 0)
return nsm;
return NULL;
}
-static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
+static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles,
+ const struct sockaddr *sap)
{
struct nsm_handle *nsm;
- list_for_each_entry(nsm, &nsm_handles, sm_link)
+ list_for_each_entry(nsm, nsm_handles, sm_link)
if (rpc_cmp_addr(nsm_addr(nsm), sap))
return nsm;
return NULL;
}
-static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
+static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles,
+ const struct nsm_private *priv)
{
struct nsm_handle *nsm;
- list_for_each_entry(nsm, &nsm_handles, sm_link)
+ list_for_each_entry(nsm, nsm_handles, sm_link)
if (memcmp(nsm->sm_priv.data, priv->data,
sizeof(priv->data)) == 0)
return nsm;
@@ -353,6 +295,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
/**
* nsm_get_handle - Find or create a cached nsm_handle
+ * @net: network namespace
* @sap: pointer to socket address of handle to find
* @salen: length of socket address
* @hostname: pointer to C string containing hostname to find
@@ -365,11 +308,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
* @hostname cannot be found in the handle cache. Returns NULL if
* an error occurs.
*/
-struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
+struct nsm_handle *nsm_get_handle(const struct net *net,
+ const struct sockaddr *sap,
const size_t salen, const char *hostname,
const size_t hostname_len)
{
struct nsm_handle *cached, *new = NULL;
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
if (printk_ratelimit()) {
@@ -384,9 +329,10 @@ retry:
spin_lock(&nsm_lock);
if (nsm_use_hostnames && hostname != NULL)
- cached = nsm_lookup_hostname(hostname, hostname_len);
+ cached = nsm_lookup_hostname(&ln->nsm_handles,
+ hostname, hostname_len);
else
- cached = nsm_lookup_addr(sap);
+ cached = nsm_lookup_addr(&ln->nsm_handles, sap);
if (cached != NULL) {
atomic_inc(&cached->sm_count);
@@ -400,7 +346,7 @@ retry:
}
if (new != NULL) {
- list_add(&new->sm_link, &nsm_handles);
+ list_add(&new->sm_link, &ln->nsm_handles);
spin_unlock(&nsm_lock);
dprintk("lockd: created nsm_handle for %s (%s)\n",
new->sm_name, new->sm_addrbuf);
@@ -417,19 +363,22 @@ retry:
/**
* nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
+ * @net: network namespace
* @info: pointer to NLMPROC_SM_NOTIFY arguments
*
* Returns a matching nsm_handle if found in the nsm cache. The returned
* nsm_handle's reference count is bumped. Otherwise returns NULL if some
* error occurred.
*/
-struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
+struct nsm_handle *nsm_reboot_lookup(const struct net *net,
+ const struct nlm_reboot *info)
{
struct nsm_handle *cached;
+ struct lockd_net *ln = net_generic(net, lockd_net_id);
spin_lock(&nsm_lock);
- cached = nsm_lookup_priv(&info->priv);
+ cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv);
if (unlikely(cached == NULL)) {
spin_unlock(&nsm_lock);
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
diff --git a/fs/lockd/netns.h b/fs/lockd/netns.h
index 097bfa3..5426189 100644
--- a/fs/lockd/netns.h
+++ b/fs/lockd/netns.h
@@ -12,9 +12,7 @@ struct lockd_net {
struct delayed_work grace_period_end;
struct lock_manager lockd_manager;
- spinlock_t nsm_clnt_lock;
- unsigned int nsm_users;
- struct rpc_clnt *nsm_clnt;
+ struct list_head nsm_handles;
};
extern int lockd_net_id;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index d678bcc..5f31ebd 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -592,7 +592,7 @@ static int lockd_init_net(struct net *net)
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
INIT_LIST_HEAD(&ln->lockd_manager.list);
ln->lockd_manager.block_opens = false;
- spin_lock_init(&ln->nsm_clnt_lock);
+ INIT_LIST_HEAD(&ln->nsm_handles);
return 0;
}
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index b147d1a..09c576f 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
return rpc_system_err;
}
- nlm_host_rebooted(argp);
+ nlm_host_rebooted(SVC_NET(rqstp), argp);
return rpc_success;
}
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index 21171f0..fb26b9f 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
return rpc_system_err;
}
- nlm_host_rebooted(argp);
+ nlm_host_rebooted(SVC_NET(rqstp), argp);
return rpc_success;
}
diff --git a/fs/locks.c b/fs/locks.c
index 0d2b326..af1ed74 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -119,7 +119,6 @@
#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/init.h>
-#include <linux/module.h>
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
@@ -230,16 +229,44 @@ locks_get_lock_context(struct inode *inode, int type)
ctx = smp_load_acquire(&inode->i_flctx);
}
out:
+ trace_locks_get_lock_context(inode, type, ctx);
return ctx;
}
+static void
+locks_dump_ctx_list(struct list_head *list, char *list_type)
+{
+ struct file_lock *fl;
+
+ list_for_each_entry(fl, list, fl_list) {
+ pr_warn("%s: fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n", list_type, fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
+ }
+}
+
+static void
+locks_check_ctx_lists(struct inode *inode)
+{
+ struct file_lock_context *ctx = inode->i_flctx;
+
+ if (unlikely(!list_empty(&ctx->flc_flock) ||
+ !list_empty(&ctx->flc_posix) ||
+ !list_empty(&ctx->flc_lease))) {
+ pr_warn("Leaked locks on dev=0x%x:0x%x ino=0x%lx:\n",
+ MAJOR(inode->i_sb->s_dev), MINOR(inode->i_sb->s_dev),
+ inode->i_ino);
+ locks_dump_ctx_list(&ctx->flc_flock, "FLOCK");
+ locks_dump_ctx_list(&ctx->flc_posix, "POSIX");
+ locks_dump_ctx_list(&ctx->flc_lease, "LEASE");
+ }
+}
+
void
-locks_free_lock_context(struct file_lock_context *ctx)
+locks_free_lock_context(struct inode *inode)
{
- if (ctx) {
- WARN_ON_ONCE(!list_empty(&ctx->flc_flock));
- WARN_ON_ONCE(!list_empty(&ctx->flc_posix));
- WARN_ON_ONCE(!list_empty(&ctx->flc_lease));
+ struct file_lock_context *ctx = inode->i_flctx;
+
+ if (unlikely(ctx)) {
+ locks_check_ctx_lists(inode);
kmem_cache_free(flctx_cache, ctx);
}
}
@@ -934,7 +961,8 @@ out:
return error;
}
-static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock)
+static int posix_lock_inode(struct inode *inode, struct file_lock *request,
+ struct file_lock *conflock)
{
struct file_lock *fl, *tmp;
struct file_lock *new_fl = NULL;
@@ -1142,6 +1170,8 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
if (new_fl2)
locks_free_lock(new_fl2);
locks_dispose_list(&dispose);
+ trace_posix_lock_inode(inode, request, error);
+
return error;
}
@@ -1162,7 +1192,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
int posix_lock_file(struct file *filp, struct file_lock *fl,
struct file_lock *conflock)
{
- return __posix_lock_file(file_inode(filp), fl, conflock);
+ return posix_lock_inode(file_inode(filp), fl, conflock);
}
EXPORT_SYMBOL(posix_lock_file);
@@ -1178,7 +1208,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
int error;
might_sleep ();
for (;;) {
- error = __posix_lock_file(inode, fl, NULL);
+ error = posix_lock_inode(inode, fl, NULL);
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1191,6 +1221,7 @@ static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
return error;
}
+#ifdef CONFIG_MANDATORY_FILE_LOCKING
/**
* locks_mandatory_locked - Check for an active lock
* @file: the file to check
@@ -1227,20 +1258,16 @@ int locks_mandatory_locked(struct file *file)
/**
* locks_mandatory_area - Check for a conflicting lock
- * @read_write: %FLOCK_VERIFY_WRITE for exclusive access, %FLOCK_VERIFY_READ
- * for shared
- * @inode: the file to check
+ * @inode: the file to check
* @filp: how the file was opened (if it was)
- * @offset: start of area to check
- * @count: length of area to check
+ * @start: first byte in the file to check
+ * @end: lastbyte in the file to check
+ * @type: %F_WRLCK for a write lock, else %F_RDLCK
*
* Searches the inode's list of locks to find any POSIX locks which conflict.
- * This function is called from rw_verify_area() and
- * locks_verify_truncate().
*/
-int locks_mandatory_area(int read_write, struct inode *inode,
- struct file *filp, loff_t offset,
- size_t count)
+int locks_mandatory_area(struct inode *inode, struct file *filp, loff_t start,
+ loff_t end, unsigned char type)
{
struct file_lock fl;
int error;
@@ -1252,15 +1279,15 @@ int locks_mandatory_area(int read_write, struct inode *inode,
fl.fl_flags = FL_POSIX | FL_ACCESS;
if (filp && !(filp->f_flags & O_NONBLOCK))
sleep = true;
- fl.fl_type = (read_write == FLOCK_VERIFY_WRITE) ? F_WRLCK : F_RDLCK;
- fl.fl_start = offset;
- fl.fl_end = offset + count - 1;
+ fl.fl_type = type;
+ fl.fl_start = start;
+ fl.fl_end = end;
for (;;) {
if (filp) {
fl.fl_owner = filp;
fl.fl_flags &= ~FL_SLEEP;
- error = __posix_lock_file(inode, &fl, NULL);
+ error = posix_lock_inode(inode, &fl, NULL);
if (!error)
break;
}
@@ -1268,7 +1295,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
if (sleep)
fl.fl_flags |= FL_SLEEP;
fl.fl_owner = current->files;
- error = __posix_lock_file(inode, &fl, NULL);
+ error = posix_lock_inode(inode, &fl, NULL);
if (error != FILE_LOCK_DEFERRED)
break;
error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
@@ -1289,6 +1316,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
}
EXPORT_SYMBOL(locks_mandatory_area);
+#endif /* CONFIG_MANDATORY_FILE_LOCKING */
static void lease_clear_pending(struct file_lock *fl, int arg)
{
@@ -1503,12 +1531,10 @@ void lease_get_mtime(struct inode *inode, struct timespec *time)
ctx = smp_load_acquire(&inode->i_flctx);
if (ctx && !list_empty_careful(&ctx->flc_lease)) {
spin_lock(&ctx->flc_lock);
- if (!list_empty(&ctx->flc_lease)) {
- fl = list_first_entry(&ctx->flc_lease,
- struct file_lock, fl_list);
- if (fl->fl_type == F_WRLCK)
- has_lease = true;
- }
+ fl = list_first_entry_or_null(&ctx->flc_lease,
+ struct file_lock, fl_list);
+ if (fl && (fl->fl_type == F_WRLCK))
+ has_lease = true;
spin_unlock(&ctx->flc_lock);
}
@@ -2165,6 +2191,8 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
if (file_lock == NULL)
return -ENOLCK;
+ inode = file_inode(filp);
+
/*
* This might block, so we do it before checking the inode.
*/
@@ -2172,8 +2200,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
if (copy_from_user(&flock, l, sizeof(flock)))
goto out;
- inode = file_inode(filp);
-
/* Don't allow mandatory locks on files that may be memory mapped
* and shared.
*/
@@ -2182,7 +2208,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
goto out;
}
-again:
error = flock_to_posix_lock(filp, file_lock, &flock);
if (error)
goto out;
@@ -2221,23 +2246,29 @@ again:
error = do_lock_file_wait(filp, cmd, file_lock);
/*
- * Attempt to detect a close/fcntl race and recover by
- * releasing the lock that was just acquired.
- */
- /*
- * we need that spin_lock here - it prevents reordering between
- * update of i_flctx->flc_posix and check for it done in close().
- * rcu_read_lock() wouldn't do.
+ * Attempt to detect a close/fcntl race and recover by releasing the
+ * lock that was just acquired. There is no need to do that when we're
+ * unlocking though, or for OFD locks.
*/
- spin_lock(&current->files->file_lock);
- f = fcheck(fd);
- spin_unlock(&current->files->file_lock);
- if (!error && f != filp && flock.l_type != F_UNLCK) {
- flock.l_type = F_UNLCK;
- goto again;
+ if (!error && file_lock->fl_type != F_UNLCK &&
+ !(file_lock->fl_flags & FL_OFDLCK)) {
+ /*
+ * We need that spin_lock here - it prevents reordering between
+ * update of i_flctx->flc_posix and check for it done in
+ * close(). rcu_read_lock() wouldn't do.
+ */
+ spin_lock(&current->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(&current->files->file_lock);
+ if (f != filp) {
+ file_lock->fl_type = F_UNLCK;
+ error = do_lock_file_wait(filp, cmd, file_lock);
+ WARN_ON_ONCE(error);
+ error = -EBADF;
+ }
}
-
out:
+ trace_fcntl_setlk(inode, file_lock, error);
locks_free_lock(file_lock);
return error;
}
@@ -2322,7 +2353,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
goto out;
}
-again:
error = flock64_to_posix_lock(filp, file_lock, &flock);
if (error)
goto out;
@@ -2361,17 +2391,27 @@ again:
error = do_lock_file_wait(filp, cmd, file_lock);
/*
- * Attempt to detect a close/fcntl race and recover by
- * releasing the lock that was just acquired.
+ * Attempt to detect a close/fcntl race and recover by releasing the
+ * lock that was just acquired. There is no need to do that when we're
+ * unlocking though, or for OFD locks.
*/
- spin_lock(&current->files->file_lock);
- f = fcheck(fd);
- spin_unlock(&current->files->file_lock);
- if (!error && f != filp && flock.l_type != F_UNLCK) {
- flock.l_type = F_UNLCK;
- goto again;
+ if (!error && file_lock->fl_type != F_UNLCK &&
+ !(file_lock->fl_flags & FL_OFDLCK)) {
+ /*
+ * We need that spin_lock here - it prevents reordering between
+ * update of i_flctx->flc_posix and check for it done in
+ * close(). rcu_read_lock() wouldn't do.
+ */
+ spin_lock(&current->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(&current->files->file_lock);
+ if (f != filp) {
+ file_lock->fl_type = F_UNLCK;
+ error = do_lock_file_wait(filp, cmd, file_lock);
+ WARN_ON_ONCE(error);
+ error = -EBADF;
+ }
}
-
out:
locks_free_lock(file_lock);
return error;
@@ -2385,6 +2425,7 @@ out:
*/
void locks_remove_posix(struct file *filp, fl_owner_t owner)
{
+ int error;
struct file_lock lock;
struct file_lock_context *ctx;
@@ -2407,10 +2448,11 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
lock.fl_ops = NULL;
lock.fl_lmops = NULL;
- vfs_lock_file(filp, F_SETLK, &lock, NULL);
+ error = vfs_lock_file(filp, F_SETLK, &lock, NULL);
if (lock.fl_ops && lock.fl_ops->fl_release_private)
lock.fl_ops->fl_release_private(&lock);
+ trace_locks_remove_posix(file_inode(filp), &lock, error);
}
EXPORT_SYMBOL(locks_remove_posix);
@@ -2706,7 +2748,7 @@ static int __init proc_locks_init(void)
proc_create("locks", 0, NULL, &proc_locks_operations);
return 0;
}
-module_init(proc_locks_init);
+fs_initcall(proc_locks_init);
#endif
static int __init filelock_init(void)
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index f9b45d4..542468e 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -528,7 +528,8 @@ static int logfs_symlink(struct inode *dir, struct dentry *dentry,
if (IS_ERR(inode))
return PTR_ERR(inode);
- inode->i_op = &logfs_symlink_iops;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &logfs_reg_aops;
return __logfs_create(dir, dentry, inode, target, destlen);
@@ -776,12 +777,6 @@ fail:
return -EIO;
}
-const struct inode_operations logfs_symlink_iops = {
- .readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
-};
-
const struct inode_operations logfs_dir_iops = {
.create = logfs_create,
.link = logfs_link,
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c
index af49e2d..0fce46d 100644
--- a/fs/logfs/inode.c
+++ b/fs/logfs/inode.c
@@ -64,7 +64,8 @@ static void logfs_inode_setops(struct inode *inode)
inode->i_mapping->a_ops = &logfs_reg_aops;
break;
case S_IFLNK:
- inode->i_op = &logfs_symlink_iops;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &logfs_reg_aops;
break;
case S_IFSOCK: /* fall through */
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h
index 5f09376..39d91f8 100644
--- a/fs/logfs/logfs.h
+++ b/fs/logfs/logfs.h
@@ -302,7 +302,7 @@ struct logfs_block {
struct inode *inode;
struct logfs_transaction *ta;
unsigned long alias_map[LOGFS_BLOCK_FACTOR / BITS_PER_LONG];
- struct logfs_block_ops *ops;
+ const struct logfs_block_ops *ops;
int full;
int partial;
int reserved_bytes;
@@ -495,7 +495,6 @@ static inline int logfs_get_sb_mtd(struct logfs_super *s, int mtdnr)
#endif
/* dir.c */
-extern const struct inode_operations logfs_symlink_iops;
extern const struct inode_operations logfs_dir_iops;
extern const struct file_operations logfs_dir_fops;
int logfs_replay_journal(struct super_block *sb);
@@ -579,7 +578,7 @@ int logfs_exist_block(struct inode *inode, u64 bix);
int get_page_reserve(struct inode *inode, struct page *page);
void logfs_get_wblocks(struct super_block *sb, struct page *page, int lock);
void logfs_put_wblocks(struct super_block *sb, struct page *page, int lock);
-extern struct logfs_block_ops indirect_block_ops;
+extern const struct logfs_block_ops indirect_block_ops;
/* segment.c */
int logfs_erase_segment(struct super_block *sb, u32 ofs, int ensure_erase);
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c
index 380d86e..20973c9 100644
--- a/fs/logfs/readwrite.c
+++ b/fs/logfs/readwrite.c
@@ -569,13 +569,13 @@ static void indirect_free_block(struct super_block *sb,
}
-static struct logfs_block_ops inode_block_ops = {
+static const struct logfs_block_ops inode_block_ops = {
.write_block = inode_write_block,
.free_block = inode_free_block,
.write_alias = inode_write_alias,
};
-struct logfs_block_ops indirect_block_ops = {
+const struct logfs_block_ops indirect_block_ops = {
.write_block = indirect_write_block,
.free_block = indirect_free_block,
.write_alias = indirect_write_alias,
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c
index 6de0fbf..d270e4b 100644
--- a/fs/logfs/segment.c
+++ b/fs/logfs/segment.c
@@ -197,7 +197,7 @@ static int btree_write_alias(struct super_block *sb, struct logfs_block *block,
return 0;
}
-static struct logfs_block_ops btree_block_ops = {
+static const struct logfs_block_ops btree_block_ops = {
.write_block = btree_write_block,
.free_block = __free_block,
.write_alias = btree_write_alias,
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 086cd0a..cb1789c 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -435,8 +435,7 @@ static const struct address_space_operations minix_aops = {
static const struct inode_operations minix_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.getattr = minix_getattr,
};
@@ -452,6 +451,7 @@ void minix_set_inode(struct inode *inode, dev_t rdev)
inode->i_mapping->a_ops = &minix_aops;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &minix_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &minix_aops;
} else
init_special_inode(inode, inode->i_mode, rdev);
diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c
index 282e15a..46ca39d 100644
--- a/fs/minix/itree_v1.c
+++ b/fs/minix/itree_v1.c
@@ -24,16 +24,15 @@ static inline block_t *i_data(struct inode *inode)
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
{
int n = 0;
- char b[BDEVNAME_SIZE];
if (block < 0) {
- printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n",
- block, bdevname(inode->i_sb->s_bdev, b));
+ printk("MINIX-fs: block_to_path: block %ld < 0 on dev %pg\n",
+ block, inode->i_sb->s_bdev);
} else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) {
if (printk_ratelimit())
printk("MINIX-fs: block_to_path: "
- "block %ld too big on dev %s\n",
- block, bdevname(inode->i_sb->s_bdev, b));
+ "block %ld too big on dev %pg\n",
+ block, inode->i_sb->s_bdev);
} else if (block < 7) {
offsets[n++] = block;
} else if ((block -= 7) < 512) {
diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c
index 78e2d93..1ee1013 100644
--- a/fs/minix/itree_v2.c
+++ b/fs/minix/itree_v2.c
@@ -26,18 +26,17 @@ static inline block_t *i_data(struct inode *inode)
static int block_to_path(struct inode * inode, long block, int offsets[DEPTH])
{
int n = 0;
- char b[BDEVNAME_SIZE];
struct super_block *sb = inode->i_sb;
if (block < 0) {
- printk("MINIX-fs: block_to_path: block %ld < 0 on dev %s\n",
- block, bdevname(sb->s_bdev, b));
+ printk("MINIX-fs: block_to_path: block %ld < 0 on dev %pg\n",
+ block, sb->s_bdev);
} else if ((u64)block * (u64)sb->s_blocksize >=
minix_sb(sb)->s_max_size) {
if (printk_ratelimit())
printk("MINIX-fs: block_to_path: "
- "block %ld too big on dev %s\n",
- block, bdevname(sb->s_bdev, b));
+ "block %ld too big on dev %pg\n",
+ block, sb->s_bdev);
} else if (block < DIRCOUNT) {
offsets[n++] = block;
} else if ((block -= DIRCOUNT) < INDIRCOUNT(sb)) {
diff --git a/fs/namei.c b/fs/namei.c
index d84d7c7..bceefd5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -505,13 +505,13 @@ struct nameidata {
int total_link_count;
struct saved {
struct path link;
- void *cookie;
+ struct delayed_call done;
const char *name;
- struct inode *inode;
unsigned seq;
} *stack, internal[EMBEDDED_LEVELS];
struct filename *name;
struct nameidata *saved;
+ struct inode *link_inode;
unsigned root_seq;
int dfd;
};
@@ -534,10 +534,8 @@ static void restore_nameidata(void)
current->nameidata = old;
if (old)
old->total_link_count = now->total_link_count;
- if (now->stack != now->internal) {
+ if (now->stack != now->internal)
kfree(now->stack);
- now->stack = now->internal;
- }
}
static int __nd_alloc_stack(struct nameidata *nd)
@@ -592,11 +590,8 @@ static void drop_links(struct nameidata *nd)
int i = nd->depth;
while (i--) {
struct saved *last = nd->stack + i;
- struct inode *inode = last->inode;
- if (last->cookie && inode->i_op->put_link) {
- inode->i_op->put_link(inode, last->cookie);
- last->cookie = NULL;
- }
+ do_delayed_call(&last->done);
+ clear_delayed_call(&last->done);
}
}
@@ -657,7 +652,7 @@ static bool legitimize_links(struct nameidata *nd)
* Path walking has 2 modes, rcu-walk and ref-walk (see
* Documentation/filesystems/path-lookup.txt). In situations when we can't
* continue in RCU mode, we attempt to drop out of rcu-walk mode and grab
- * normal reference counts on dentries and vfsmounts to transition to rcu-walk
+ * normal reference counts on dentries and vfsmounts to transition to ref-walk
* mode. Refcounts are grabbed at the last known good point before rcu-walk
* got stuck, so ref-walk may continue from there. If this is not successful
* (eg. a seqcount has changed), then failure is returned and it's up to caller
@@ -807,19 +802,19 @@ static int complete_walk(struct nameidata *nd)
static void set_root(struct nameidata *nd)
{
- get_fs_root(current->fs, &nd->root);
-}
-
-static void set_root_rcu(struct nameidata *nd)
-{
struct fs_struct *fs = current->fs;
- unsigned seq;
- do {
- seq = read_seqcount_begin(&fs->seq);
- nd->root = fs->root;
- nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
- } while (read_seqcount_retry(&fs->seq, seq));
+ if (nd->flags & LOOKUP_RCU) {
+ unsigned seq;
+
+ do {
+ seq = read_seqcount_begin(&fs->seq);
+ nd->root = fs->root;
+ nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq);
+ } while (read_seqcount_retry(&fs->seq, seq));
+ } else {
+ get_fs_root(fs, &nd->root);
+ }
}
static void path_put_conditional(struct path *path, struct nameidata *nd)
@@ -841,8 +836,28 @@ static inline void path_to_nameidata(const struct path *path,
nd->path.dentry = path->dentry;
}
+static int nd_jump_root(struct nameidata *nd)
+{
+ if (nd->flags & LOOKUP_RCU) {
+ struct dentry *d;
+ nd->path = nd->root;
+ d = nd->path.dentry;
+ nd->inode = d->d_inode;
+ nd->seq = nd->root_seq;
+ if (unlikely(read_seqcount_retry(&d->d_seq, nd->seq)))
+ return -ECHILD;
+ } else {
+ path_put(&nd->path);
+ nd->path = nd->root;
+ path_get(&nd->path);
+ nd->inode = nd->path.dentry->d_inode;
+ }
+ nd->flags |= LOOKUP_JUMPED;
+ return 0;
+}
+
/*
- * Helper to directly jump to a known parsed path from ->follow_link,
+ * Helper to directly jump to a known parsed path from ->get_link,
* caller must have taken a reference to path beforehand.
*/
void nd_jump_link(struct path *path)
@@ -858,9 +873,7 @@ void nd_jump_link(struct path *path)
static inline void put_link(struct nameidata *nd)
{
struct saved *last = nd->stack + --nd->depth;
- struct inode *inode = last->inode;
- if (last->cookie && inode->i_op->put_link)
- inode->i_op->put_link(inode, last->cookie);
+ do_delayed_call(&last->done);
if (!(nd->flags & LOOKUP_RCU))
path_put(&last->link);
}
@@ -892,7 +905,7 @@ static inline int may_follow_link(struct nameidata *nd)
return 0;
/* Allowed if owner and follower match. */
- inode = nd->stack[0].inode;
+ inode = nd->link_inode;
if (uid_eq(current_cred()->fsuid, inode->i_uid))
return 0;
@@ -983,7 +996,7 @@ const char *get_link(struct nameidata *nd)
{
struct saved *last = nd->stack + nd->depth - 1;
struct dentry *dentry = last->link.dentry;
- struct inode *inode = last->inode;
+ struct inode *inode = nd->link_inode;
int error;
const char *res;
@@ -1004,36 +1017,27 @@ const char *get_link(struct nameidata *nd)
nd->last_type = LAST_BIND;
res = inode->i_link;
if (!res) {
+ const char * (*get)(struct dentry *, struct inode *,
+ struct delayed_call *);
+ get = inode->i_op->get_link;
if (nd->flags & LOOKUP_RCU) {
- if (unlikely(unlazy_walk(nd, NULL, 0)))
- return ERR_PTR(-ECHILD);
+ res = get(NULL, inode, &last->done);
+ if (res == ERR_PTR(-ECHILD)) {
+ if (unlikely(unlazy_walk(nd, NULL, 0)))
+ return ERR_PTR(-ECHILD);
+ res = get(dentry, inode, &last->done);
+ }
+ } else {
+ res = get(dentry, inode, &last->done);
}
- res = inode->i_op->follow_link(dentry, &last->cookie);
- if (IS_ERR_OR_NULL(res)) {
- last->cookie = NULL;
+ if (IS_ERR_OR_NULL(res))
return res;
- }
}
if (*res == '/') {
- if (nd->flags & LOOKUP_RCU) {
- struct dentry *d;
- if (!nd->root.mnt)
- set_root_rcu(nd);
- nd->path = nd->root;
- d = nd->path.dentry;
- nd->inode = d->d_inode;
- nd->seq = nd->root_seq;
- if (unlikely(read_seqcount_retry(&d->d_seq, nd->seq)))
- return ERR_PTR(-ECHILD);
- } else {
- if (!nd->root.mnt)
- set_root(nd);
- path_put(&nd->path);
- nd->path = nd->root;
- path_get(&nd->root);
- nd->inode = nd->path.dentry->d_inode;
- }
- nd->flags |= LOOKUP_JUMPED;
+ if (!nd->root.mnt)
+ set_root(nd);
+ if (unlikely(nd_jump_root(nd)))
+ return ERR_PTR(-ECHILD);
while (unlikely(*++res == '/'))
;
}
@@ -1294,8 +1298,6 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
static int follow_dotdot_rcu(struct nameidata *nd)
{
struct inode *inode = nd->inode;
- if (!nd->root.mnt)
- set_root_rcu(nd);
while (1) {
if (path_equal(&nd->path, &nd->root))
@@ -1415,9 +1417,6 @@ static void follow_mount(struct path *path)
static int follow_dotdot(struct nameidata *nd)
{
- if (!nd->root.mnt)
- set_root(nd);
-
while(1) {
struct dentry *old = nd->path.dentry;
@@ -1655,6 +1654,8 @@ static inline int may_lookup(struct nameidata *nd)
static inline int handle_dots(struct nameidata *nd, int type)
{
if (type == LAST_DOTDOT) {
+ if (!nd->root.mnt)
+ set_root(nd);
if (nd->flags & LOOKUP_RCU) {
return follow_dotdot_rcu(nd);
} else
@@ -1691,8 +1692,8 @@ static int pick_link(struct nameidata *nd, struct path *link,
last = nd->stack + nd->depth++;
last->link = *link;
- last->cookie = NULL;
- last->inode = inode;
+ clear_delayed_call(&last->done);
+ nd->link_inode = inode;
last->seq = seq;
return 1;
}
@@ -1996,7 +1997,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
nd->depth = 0;
- nd->total_link_count = 0;
if (flags & LOOKUP_ROOT) {
struct dentry *root = nd->root.dentry;
struct inode *inode = root->d_inode;
@@ -2021,18 +2021,19 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
}
nd->root.mnt = NULL;
+ nd->path.mnt = NULL;
+ nd->path.dentry = NULL;
nd->m_seq = read_seqbegin(&mount_lock);
if (*s == '/') {
- if (flags & LOOKUP_RCU) {
+ if (flags & LOOKUP_RCU)
rcu_read_lock();
- set_root_rcu(nd);
- nd->seq = nd->root_seq;
- } else {
- set_root(nd);
- path_get(&nd->root);
- }
- nd->path = nd->root;
+ set_root(nd);
+ if (likely(!nd_jump_root(nd)))
+ return s;
+ nd->root.mnt = NULL;
+ rcu_read_unlock();
+ return ERR_PTR(-ECHILD);
} else if (nd->dfd == AT_FDCWD) {
if (flags & LOOKUP_RCU) {
struct fs_struct *fs = current->fs;
@@ -2043,11 +2044,14 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
do {
seq = read_seqcount_begin(&fs->seq);
nd->path = fs->pwd;
+ nd->inode = nd->path.dentry->d_inode;
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
} while (read_seqcount_retry(&fs->seq, seq));
} else {
get_fs_pwd(current->fs, &nd->path);
+ nd->inode = nd->path.dentry->d_inode;
}
+ return s;
} else {
/* Caller must check execute permissions on the starting path component */
struct fd f = fdget_raw(nd->dfd);
@@ -2077,16 +2081,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
fdput(f);
return s;
}
-
- nd->inode = nd->path.dentry->d_inode;
- if (!(flags & LOOKUP_RCU))
- return s;
- if (likely(!read_seqcount_retry(&nd->path.dentry->d_seq, nd->seq)))
- return s;
- if (!(nd->flags & LOOKUP_ROOT))
- nd->root.mnt = NULL;
- rcu_read_unlock();
- return ERR_PTR(-ECHILD);
}
static const char *trailing_symlink(struct nameidata *nd)
@@ -2279,6 +2273,8 @@ EXPORT_SYMBOL(vfs_path_lookup);
*
* Note that this routine is purely a helper for filesystem usage and should
* not be called by generic code.
+ *
+ * The caller must hold base->i_mutex.
*/
struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
{
@@ -2322,6 +2318,75 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
}
EXPORT_SYMBOL(lookup_one_len);
+/**
+ * lookup_one_len_unlocked - filesystem helper to lookup single pathname component
+ * @name: pathname component to lookup
+ * @base: base directory to lookup from
+ * @len: maximum length @len should be interpreted to
+ *
+ * Note that this routine is purely a helper for filesystem usage and should
+ * not be called by generic code.
+ *
+ * Unlike lookup_one_len, it should be called without the parent
+ * i_mutex held, and will take the i_mutex itself if necessary.
+ */
+struct dentry *lookup_one_len_unlocked(const char *name,
+ struct dentry *base, int len)
+{
+ struct qstr this;
+ unsigned int c;
+ int err;
+ struct dentry *ret;
+
+ this.name = name;
+ this.len = len;
+ this.hash = full_name_hash(name, 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')
+ return ERR_PTR(-EACCES);
+ }
+ /*
+ * See if the low-level filesystem might want
+ * to use its own hash..
+ */
+ if (base->d_flags & DCACHE_OP_HASH) {
+ int err = base->d_op->d_hash(base, &this);
+ if (err < 0)
+ return ERR_PTR(err);
+ }
+
+ err = inode_permission(base->d_inode, MAY_EXEC);
+ if (err)
+ return ERR_PTR(err);
+
+ /*
+ * __d_lookup() is used to try to get a quick answer and avoid the
+ * mutex. A false-negative does no harm.
+ */
+ ret = __d_lookup(base, &this);
+ if (ret && unlikely(ret->d_flags & DCACHE_OP_REVALIDATE)) {
+ dput(ret);
+ ret = NULL;
+ }
+ if (ret)
+ return ret;
+
+ mutex_lock(&base->d_inode->i_mutex);
+ ret = __lookup_hash(&this, base, 0);
+ mutex_unlock(&base->d_inode->i_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(lookup_one_len_unlocked);
+
int user_path_at_empty(int dfd, const char __user *name, unsigned flags,
struct path *path, int *empty)
{
@@ -2670,10 +2735,6 @@ static int may_open(struct path *path, int acc_mode, int flag)
struct inode *inode = dentry->d_inode;
int error;
- /* O_PATH? */
- if (!acc_mode)
- return 0;
-
if (!inode)
return -ENOENT;
@@ -2695,7 +2756,7 @@ static int may_open(struct path *path, int acc_mode, int flag)
break;
}
- error = inode_permission(inode, acc_mode);
+ error = inode_permission(inode, MAY_OPEN | acc_mode);
if (error)
return error;
@@ -2887,7 +2948,7 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
if (*opened & FILE_CREATED) {
WARN_ON(!(open_flag & O_CREAT));
fsnotify_create(dir, dentry);
- acc_mode = MAY_OPEN;
+ acc_mode = 0;
}
error = may_open(&file->f_path, acc_mode, open_flag);
if (error)
@@ -3100,7 +3161,7 @@ retry_lookup:
/* Don't check for write permission, don't truncate */
open_flag &= ~O_TRUNC;
will_truncate = false;
- acc_mode = MAY_OPEN;
+ acc_mode = 0;
path_to_nameidata(&path, nd);
goto finish_open_created;
}
@@ -3184,10 +3245,11 @@ finish_open:
got_write = true;
}
finish_open_created:
- error = may_open(&nd->path, acc_mode, open_flag);
- if (error)
- goto out;
-
+ if (likely(!(open_flag & O_PATH))) {
+ error = may_open(&nd->path, acc_mode, open_flag);
+ if (error)
+ goto out;
+ }
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
error = vfs_open(&nd->path, file, current_cred());
if (!error) {
@@ -3274,7 +3336,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
goto out2;
audit_inode(nd->name, child, 0);
/* Don't check for other permissions, the inode was just created */
- error = may_open(&path, MAY_OPEN, op->open_flag);
+ error = may_open(&path, 0, op->open_flag);
if (error)
goto out2;
file->f_path.mnt = path.mnt;
@@ -4496,72 +4558,73 @@ EXPORT_SYMBOL(readlink_copy);
/*
* A helper for ->readlink(). This should be used *ONLY* for symlinks that
- * have ->follow_link() touching nd only in nd_set_link(). Using (or not
- * using) it for any given inode is up to filesystem.
+ * have ->get_link() not calling nd_jump_link(). Using (or not using) it
+ * for any given inode is up to filesystem.
*/
int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
- void *cookie;
+ DEFINE_DELAYED_CALL(done);
struct inode *inode = d_inode(dentry);
const char *link = inode->i_link;
int res;
if (!link) {
- link = inode->i_op->follow_link(dentry, &cookie);
+ link = inode->i_op->get_link(dentry, inode, &done);
if (IS_ERR(link))
return PTR_ERR(link);
}
res = readlink_copy(buffer, buflen, link);
- if (inode->i_op->put_link)
- inode->i_op->put_link(inode, cookie);
+ do_delayed_call(&done);
return res;
}
EXPORT_SYMBOL(generic_readlink);
/* get the link contents into pagecache */
-static char *page_getlink(struct dentry * dentry, struct page **ppage)
+const char *page_get_link(struct dentry *dentry, struct inode *inode,
+ struct delayed_call *callback)
{
char *kaddr;
struct page *page;
- struct address_space *mapping = dentry->d_inode->i_mapping;
- page = read_mapping_page(mapping, 0, NULL);
- if (IS_ERR(page))
- return (char*)page;
- *ppage = page;
- kaddr = kmap(page);
- nd_terminate_link(kaddr, dentry->d_inode->i_size, PAGE_SIZE - 1);
+ struct address_space *mapping = inode->i_mapping;
+
+ if (!dentry) {
+ page = find_get_page(mapping, 0);
+ if (!page)
+ return ERR_PTR(-ECHILD);
+ if (!PageUptodate(page)) {
+ put_page(page);
+ return ERR_PTR(-ECHILD);
+ }
+ } else {
+ page = read_mapping_page(mapping, 0, NULL);
+ if (IS_ERR(page))
+ return (char*)page;
+ }
+ set_delayed_call(callback, page_put_link, page);
+ BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM);
+ kaddr = page_address(page);
+ nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1);
return kaddr;
}
-int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
-{
- struct page *page = NULL;
- int res = readlink_copy(buffer, buflen, page_getlink(dentry, &page));
- if (page) {
- kunmap(page);
- page_cache_release(page);
- }
- return res;
-}
-EXPORT_SYMBOL(page_readlink);
+EXPORT_SYMBOL(page_get_link);
-const char *page_follow_link_light(struct dentry *dentry, void **cookie)
+void page_put_link(void *arg)
{
- struct page *page = NULL;
- char *res = page_getlink(dentry, &page);
- if (!IS_ERR(res))
- *cookie = page;
- return res;
+ put_page(arg);
}
-EXPORT_SYMBOL(page_follow_link_light);
+EXPORT_SYMBOL(page_put_link);
-void page_put_link(struct inode *unused, void *cookie)
+int page_readlink(struct dentry *dentry, char __user *buffer, int buflen)
{
- struct page *page = cookie;
- kunmap(page);
- page_cache_release(page);
+ DEFINE_DELAYED_CALL(done);
+ int res = readlink_copy(buffer, buflen,
+ page_get_link(dentry, d_inode(dentry),
+ &done));
+ do_delayed_call(&done);
+ return res;
}
-EXPORT_SYMBOL(page_put_link);
+EXPORT_SYMBOL(page_readlink);
/*
* The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS
@@ -4572,7 +4635,6 @@ int __page_symlink(struct inode *inode, const char *symname, int len, int nofs)
struct page *page;
void *fsdata;
int err;
- char *kaddr;
unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE;
if (nofs)
flags |= AOP_FLAG_NOFS;
@@ -4583,9 +4645,7 @@ retry:
if (err)
goto fail;
- kaddr = kmap_atomic(page);
- memcpy(kaddr, symname, len-1);
- kunmap_atomic(kaddr);
+ memcpy(page_address(page), symname, len-1);
err = pagecache_write_end(NULL, mapping, 0, len-1, len-1,
page, fsdata);
@@ -4610,7 +4670,6 @@ EXPORT_SYMBOL(page_symlink);
const struct inode_operations page_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
};
EXPORT_SYMBOL(page_symlink_inode_operations);
diff --git a/fs/namespace.c b/fs/namespace.c
index 0570729..a830e14 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1584,6 +1584,14 @@ static inline bool may_mount(void)
return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN);
}
+static inline bool may_mandlock(void)
+{
+#ifndef CONFIG_MANDATORY_FILE_LOCKING
+ return false;
+#endif
+ return capable(CAP_SYS_ADMIN);
+}
+
/*
* Now umount can handle mount points as well as block devices.
* This is important for filesystems which use unnamed block devices.
@@ -2601,18 +2609,18 @@ static long exact_copy_from_user(void *to, const void __user * from,
return n;
}
-int copy_mount_options(const void __user * data, unsigned long *where)
+void *copy_mount_options(const void __user * data)
{
int i;
- unsigned long page;
unsigned long size;
+ char *copy;
- *where = 0;
if (!data)
- return 0;
+ return NULL;
- if (!(page = __get_free_page(GFP_KERNEL)))
- return -ENOMEM;
+ copy = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!copy)
+ return ERR_PTR(-ENOMEM);
/* We only care that *some* data at the address the user
* gave us is valid. Just in case, we'll zero
@@ -2623,15 +2631,14 @@ int copy_mount_options(const void __user * data, unsigned long *where)
if (size > PAGE_SIZE)
size = PAGE_SIZE;
- i = size - exact_copy_from_user((void *)page, data, size);
+ i = size - exact_copy_from_user(copy, data, size);
if (!i) {
- free_page(page);
- return -EFAULT;
+ kfree(copy);
+ return ERR_PTR(-EFAULT);
}
if (i != PAGE_SIZE)
- memset((char *)page + i, 0, PAGE_SIZE - i);
- *where = page;
- return 0;
+ memset(copy + i, 0, PAGE_SIZE - i);
+ return copy;
}
char *copy_mount_string(const void __user *data)
@@ -2677,6 +2684,8 @@ long do_mount(const char *dev_name, const char __user *dir_name,
type_page, flags, data_page);
if (!retval && !may_mount())
retval = -EPERM;
+ if (!retval && (flags & MS_MANDLOCK) && !may_mandlock())
+ retval = -EPERM;
if (retval)
goto dput_out;
@@ -2896,7 +2905,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
int ret;
char *kernel_type;
char *kernel_dev;
- unsigned long data_page;
+ void *options;
kernel_type = copy_mount_string(type);
ret = PTR_ERR(kernel_type);
@@ -2908,14 +2917,14 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,
if (IS_ERR(kernel_dev))
goto out_dev;
- ret = copy_mount_options(data, &data_page);
- if (ret < 0)
+ options = copy_mount_options(data);
+ ret = PTR_ERR(options);
+ if (IS_ERR(options))
goto out_data;
- ret = do_mount(kernel_dev, dir_name, kernel_type, flags,
- (void *) data_page);
+ ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options);
- free_page(data_page);
+ kfree(options);
out_data:
kfree(kernel_dev);
out_dev:
@@ -2939,9 +2948,9 @@ bool is_path_reachable(struct mount *mnt, struct dentry *dentry,
return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry);
}
-int path_is_under(struct path *path1, struct path *path2)
+bool path_is_under(struct path *path1, struct path *path2)
{
- int res;
+ bool res;
read_seqlock_excl(&mount_lock);
res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2);
read_sequnlock_excl(&mount_lock);
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 9605a2f..ce1eb3f 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -244,8 +244,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
static const struct inode_operations ncp_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = ncp_notify_change,
};
#endif
@@ -283,6 +282,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &ncp_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &ncp_symlink_aops;
#endif
} else {
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 79b1130..0a3f9b5 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -525,6 +525,8 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
switch (rqdata.cmd) {
case NCP_LOCK_EX:
case NCP_LOCK_SH:
+ if (rqdata.timeout < 0)
+ return -EINVAL;
if (rqdata.timeout == 0)
rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 326d9e1..bdb4dc7 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -75,11 +75,11 @@ nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
* nfs_wait_bit_killable - helper for functions that are sleeping on bit locks
* @word: long word containing the bit lock
*/
-int nfs_wait_bit_killable(struct wait_bit_key *key)
+int nfs_wait_bit_killable(struct wait_bit_key *key, int mode)
{
- if (fatal_signal_pending(current))
- return -ERESTARTSYS;
freezable_schedule_unsafe();
+ if (signal_pending_state(mode, current))
+ return -ERESTARTSYS;
return 0;
}
EXPORT_SYMBOL_GPL(nfs_wait_bit_killable);
@@ -408,9 +408,10 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
inode->i_fop = NULL;
inode->i_flags |= S_AUTOMOUNT;
}
- } else if (S_ISLNK(inode->i_mode))
+ } else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &nfs_symlink_inode_operations;
- else
+ inode_nohighmem(inode);
+ } else
init_special_inode(inode, inode->i_mode, fattr->rdev);
memset(&inode->i_atime, 0, sizeof(inode->i_atime));
@@ -618,7 +619,10 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr,
nfs_inc_stats(inode, NFSIOS_SETATTRTRUNC);
nfs_vmtruncate(inode, attr->ia_size);
}
- nfs_update_inode(inode, fattr);
+ if (fattr->valid)
+ nfs_update_inode(inode, fattr);
+ else
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
@@ -1083,6 +1087,27 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
|| NFS_STALE(inode);
}
+int nfs_revalidate_mapping_rcu(struct inode *inode)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ unsigned long *bitlock = &nfsi->flags;
+ int ret = 0;
+
+ if (IS_SWAPFILE(inode))
+ goto out;
+ if (nfs_mapping_need_revalidate_inode(inode)) {
+ ret = -ECHILD;
+ goto out;
+ }
+ spin_lock(&inode->i_lock);
+ if (test_bit(NFS_INO_INVALIDATING, bitlock) ||
+ (nfsi->cache_validity & NFS_INO_INVALID_DATA))
+ ret = -ECHILD;
+ spin_unlock(&inode->i_lock);
+out:
+ return ret;
+}
+
/**
* __nfs_revalidate_mapping - Revalidate the pagecache
* @inode - pointer to host inode
@@ -1824,7 +1849,11 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if ((long)fattr->gencount - (long)nfsi->attr_gencount > 0)
nfsi->attr_gencount = fattr->gencount;
}
- invalid &= ~NFS_INO_INVALID_ATTR;
+
+ /* Don't declare attrcache up to date if there were no attrs! */
+ if (fattr->valid != 0)
+ invalid &= ~NFS_INO_INVALID_ATTR;
+
/* Don't invalidate the data if we were to blame */
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
|| S_ISLNK(inode->i_mode)))
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 56cfde2..9dea85f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -379,7 +379,7 @@ extern int nfs_drop_inode(struct inode *);
extern void nfs_clear_inode(struct inode *);
extern void nfs_evict_inode(struct inode *);
void nfs_zap_acl_cache(struct inode *inode);
-extern int nfs_wait_bit_killable(struct wait_bit_key *key);
+extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
/* super.c */
extern const struct super_operations nfs_sops;
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index 1ebe2fc..17c0fa1 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -284,12 +284,12 @@ nfs3_listxattr(struct dentry *dentry, char *data, size_t size)
int error;
error = nfs3_list_one_acl(inode, ACL_TYPE_ACCESS,
- POSIX_ACL_XATTR_ACCESS, data, size, &result);
+ XATTR_NAME_POSIX_ACL_ACCESS, data, size, &result);
if (error)
return error;
error = nfs3_list_one_acl(inode, ACL_TYPE_DEFAULT,
- POSIX_ACL_XATTR_DEFAULT, data, size, &result);
+ XATTR_NAME_POSIX_ACL_DEFAULT, data, size, &result);
if (error)
return error;
return result;
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 3e92a3c..6b1ce98 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -14,7 +14,7 @@
#include "pnfs.h"
#include "internal.h"
-#define NFSDBG_FACILITY NFSDBG_PNFS
+#define NFSDBG_FACILITY NFSDBG_PROC
static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
fmode_t fmode)
@@ -284,6 +284,7 @@ static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
.dst_fh = NFS_FH(dst_inode),
.src_offset = src_offset,
.dst_offset = dst_offset,
+ .count = count,
.dst_bitmask = server->cache_consistency_bitmask,
};
struct nfs42_clone_res res = {
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 223bedd..10410e8 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -33,7 +33,7 @@ static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
return ret;
idr_preload(GFP_KERNEL);
spin_lock(&nn->nfs_client_lock);
- ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT);
+ ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
if (ret >= 0)
clp->cl_cb_ident = ret;
spin_unlock(&nn->nfs_client_lock);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 4aa5719..26f9a23 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -7,6 +7,7 @@
#include <linux/file.h>
#include <linux/falloc.h>
#include <linux/nfs_fs.h>
+#include <uapi/linux/btrfs.h> /* BTRFS_IOC_CLONE/BTRFS_IOC_CLONE_RANGE */
#include "delegation.h"
#include "internal.h"
#include "iostat.h"
@@ -194,63 +195,32 @@ static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t
return nfs42_proc_allocate(filep, offset, len);
}
-static noinline long
-nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
- u64 src_off, u64 dst_off, u64 count)
+static int nfs42_clone_file_range(struct file *src_file, loff_t src_off,
+ struct file *dst_file, loff_t dst_off, u64 count)
{
struct inode *dst_inode = file_inode(dst_file);
struct nfs_server *server = NFS_SERVER(dst_inode);
- struct fd src_file;
- struct inode *src_inode;
+ struct inode *src_inode = file_inode(src_file);
unsigned int bs = server->clone_blksize;
+ bool same_inode = false;
int ret;
- /* dst file must be opened for writing */
- if (!(dst_file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- ret = mnt_want_write_file(dst_file);
- if (ret)
- return ret;
-
- src_file = fdget(srcfd);
- if (!src_file.file) {
- ret = -EBADF;
- goto out_drop_write;
- }
-
- src_inode = file_inode(src_file.file);
-
- /* src and dst must be different files */
- ret = -EINVAL;
- if (src_inode == dst_inode)
- goto out_fput;
-
- /* src file must be opened for reading */
- if (!(src_file.file->f_mode & FMODE_READ))
- goto out_fput;
-
- /* src and dst must be regular files */
- ret = -EISDIR;
- if (!S_ISREG(src_inode->i_mode) || !S_ISREG(dst_inode->i_mode))
- goto out_fput;
-
- ret = -EXDEV;
- if (src_file.file->f_path.mnt != dst_file->f_path.mnt ||
- src_inode->i_sb != dst_inode->i_sb)
- goto out_fput;
-
/* check alignment w.r.t. clone_blksize */
ret = -EINVAL;
if (bs) {
if (!IS_ALIGNED(src_off, bs) || !IS_ALIGNED(dst_off, bs))
- goto out_fput;
+ goto out;
if (!IS_ALIGNED(count, bs) && i_size_read(src_inode) != (src_off + count))
- goto out_fput;
+ goto out;
}
+ if (src_inode == dst_inode)
+ same_inode = true;
+
/* XXX: do we lock at all? what if server needs CB_RECALL_LAYOUT? */
- if (dst_inode < src_inode) {
+ if (same_inode) {
+ mutex_lock(&src_inode->i_mutex);
+ } else if (dst_inode < src_inode) {
mutex_lock_nested(&dst_inode->i_mutex, I_MUTEX_PARENT);
mutex_lock_nested(&src_inode->i_mutex, I_MUTEX_CHILD);
} else {
@@ -267,7 +237,7 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
if (ret)
goto out_unlock;
- ret = nfs42_proc_clone(src_file.file, dst_file, src_off, dst_off, count);
+ ret = nfs42_proc_clone(src_file, dst_file, src_off, dst_off, count);
/* truncate inode page cache of the dst range so that future reads can fetch
* new data from server */
@@ -275,62 +245,21 @@ nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
truncate_inode_pages_range(&dst_inode->i_data, dst_off, dst_off + count - 1);
out_unlock:
- if (dst_inode < src_inode) {
+ if (same_inode) {
+ mutex_unlock(&src_inode->i_mutex);
+ } else if (dst_inode < src_inode) {
mutex_unlock(&src_inode->i_mutex);
mutex_unlock(&dst_inode->i_mutex);
} else {
mutex_unlock(&dst_inode->i_mutex);
mutex_unlock(&src_inode->i_mutex);
}
-out_fput:
- fdput(src_file);
-out_drop_write:
- mnt_drop_write_file(dst_file);
+out:
return ret;
}
-
-static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
-{
- struct nfs_ioctl_clone_range_args args;
-
- if (copy_from_user(&args, argp, sizeof(args)))
- return -EFAULT;
-
- return nfs42_ioctl_clone(dst_file, args.src_fd, args.src_off, args.dst_off, args.count);
-}
-#else
-static long nfs42_ioctl_clone(struct file *dst_file, unsigned long srcfd,
- u64 src_off, u64 dst_off, u64 count)
-{
- return -ENOTTY;
-}
-
-static long nfs42_ioctl_clone_range(struct file *dst_file, void __user *argp)
-{
- return -ENOTTY;
-}
#endif /* CONFIG_NFS_V4_2 */
-long nfs4_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
-
- switch (cmd) {
- case NFS_IOC_CLONE:
- return nfs42_ioctl_clone(file, arg, 0, 0, 0);
- case NFS_IOC_CLONE_RANGE:
- return nfs42_ioctl_clone_range(file, argp);
- }
-
- return -ENOTTY;
-}
-
const struct file_operations nfs4_file_operations = {
-#ifdef CONFIG_NFS_V4_2
- .llseek = nfs4_file_llseek,
-#else
- .llseek = nfs_file_llseek,
-#endif
.read_iter = nfs_file_read,
.write_iter = nfs_file_write,
.mmap = nfs_file_mmap,
@@ -342,14 +271,13 @@ const struct file_operations nfs4_file_operations = {
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
-#ifdef CONFIG_NFS_V4_2
- .fallocate = nfs42_fallocate,
-#endif /* CONFIG_NFS_V4_2 */
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
-#ifdef CONFIG_COMPAT
- .unlocked_ioctl = nfs4_ioctl,
+#ifdef CONFIG_NFS_V4_2
+ .llseek = nfs4_file_llseek,
+ .fallocate = nfs42_fallocate,
+ .clone_file_range = nfs42_clone_file_range,
#else
- .compat_ioctl = nfs4_ioctl,
-#endif /* CONFIG_COMPAT */
+ .llseek = nfs_file_llseek,
+#endif
};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ff5bddc..c57d133 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -6248,48 +6248,32 @@ nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
-static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key,
+static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *key,
const void *buf, size_t buflen,
- int flags, int type)
+ int flags)
{
- if (strcmp(key, "") != 0)
- return -EINVAL;
-
return nfs4_proc_set_acl(d_inode(dentry), buf, buflen);
}
-static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key,
- void *buf, size_t buflen, int type)
+static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *key,
+ void *buf, size_t buflen)
{
- if (strcmp(key, "") != 0)
- return -EINVAL;
-
return nfs4_proc_get_acl(d_inode(dentry), buf, buflen);
}
-static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
- size_t list_len, const char *name,
- size_t name_len, int type)
+static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
{
- size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
-
- if (!nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry))))
- return 0;
-
- if (list && len <= list_len)
- memcpy(list, XATTR_NAME_NFSV4_ACL, len);
- return len;
+ return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
}
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
-static inline int nfs4_server_supports_labels(struct nfs_server *server)
-{
- return server->caps & NFS_CAP_SECURITY_LABEL;
-}
-static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
- const void *buf, size_t buflen,
- int flags, int type)
+static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *key,
+ const void *buf, size_t buflen,
+ int flags)
{
if (security_ismaclabel(key))
return nfs4_set_security_label(dentry, buf, buflen);
@@ -6297,36 +6281,43 @@ static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
return -EOPNOTSUPP;
}
-static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key,
- void *buf, size_t buflen, int type)
+static int nfs4_xattr_get_nfs4_label(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *key,
+ void *buf, size_t buflen)
{
if (security_ismaclabel(key))
return nfs4_get_security_label(d_inode(dentry), buf, buflen);
return -EOPNOTSUPP;
}
-static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list,
- size_t list_len, const char *name,
- size_t name_len, int type)
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
{
- size_t len = 0;
+ int len = 0;
- if (nfs_server_capable(d_inode(dentry), NFS_CAP_SECURITY_LABEL)) {
- len = security_inode_listsecurity(d_inode(dentry), NULL, 0);
- if (list && len <= list_len)
- security_inode_listsecurity(d_inode(dentry), list, len);
+ if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
+ len = security_inode_listsecurity(inode, list, list_len);
+ if (list_len && len > list_len)
+ return -ERANGE;
}
return len;
}
static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = nfs4_xattr_list_nfs4_label,
.get = nfs4_xattr_get_nfs4_label,
.set = nfs4_xattr_set_nfs4_label,
};
-#endif
+#else
+
+static ssize_t
+nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
+{
+ return 0;
+}
+
+#endif
/*
* nfs_fhget will use either the mounted_on_fileid or the fileid
@@ -7860,7 +7851,7 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
spin_unlock(&inode->i_lock);
goto out_restart;
}
- if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN)
+ if (nfs4_async_handle_error(task, server, state, &lgp->timeout) == -EAGAIN)
goto out_restart;
out:
dprintk("<-- %s\n", __func__);
@@ -8743,6 +8734,24 @@ const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
#endif
};
+ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+ ssize_t error, error2;
+
+ error = generic_listxattr(dentry, list, size);
+ if (error < 0)
+ return error;
+ if (list) {
+ list += error;
+ size -= error;
+ }
+
+ error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
+ if (error2 < 0)
+ return error2;
+ return error + error2;
+}
+
static const struct inode_operations nfs4_dir_inode_operations = {
.create = nfs_create,
.lookup = nfs_lookup,
@@ -8759,7 +8768,7 @@ static const struct inode_operations nfs4_dir_inode_operations = {
.setattr = nfs_setattr,
.getxattr = generic_getxattr,
.setxattr = generic_setxattr,
- .listxattr = generic_listxattr,
+ .listxattr = nfs4_listxattr,
.removexattr = generic_removexattr,
};
@@ -8769,7 +8778,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
.setattr = nfs_setattr,
.getxattr = generic_getxattr,
.setxattr = generic_setxattr,
- .listxattr = generic_listxattr,
+ .listxattr = nfs4_listxattr,
.removexattr = generic_removexattr,
};
@@ -8828,7 +8837,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
};
static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
- .prefix = XATTR_NAME_NFSV4_ACL,
+ .name = XATTR_NAME_NFSV4_ACL,
.list = nfs4_xattr_list_nfs4_acl,
.get = nfs4_xattr_get_nfs4_acl,
.set = nfs4_xattr_set_nfs4_acl,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index dfed4f5..4e44412 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -3615,6 +3615,7 @@ static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, st
status = 0;
if (unlikely(!(bitmap[0] & FATTR4_WORD0_FS_LOCATIONS)))
goto out;
+ bitmap[0] &= ~FATTR4_WORD0_FS_LOCATIONS;
status = -EIO;
/* Ignore borken servers that return unrequested attrs */
if (unlikely(res == NULL))
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c
index 5c0c6b5..9aebffb 100644
--- a/fs/nfs/objlayout/objio_osd.c
+++ b/fs/nfs/objlayout/objio_osd.c
@@ -476,10 +476,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
}
unlock_page(page);
}
- if (PageDirty(page) || PageWriteback(page))
- *uptodate = true;
- else
- *uptodate = PageUptodate(page);
+ *uptodate = PageUptodate(page);
dprintk("%s: index=0x%lx uptodate=%d\n", __func__, index, *uptodate);
return page;
}
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index fe3ddd2..452a011 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -129,7 +129,7 @@ __nfs_iocounter_wait(struct nfs_io_counter *c)
set_bit(NFS_IO_INPROGRESS, &c->flags);
if (atomic_read(&c->io_count) == 0)
break;
- ret = nfs_wait_bit_killable(&q.key);
+ ret = nfs_wait_bit_killable(&q.key, TASK_KILLABLE);
} while (atomic_read(&c->io_count) != 0 && !ret);
finish_wait(wq, &q.wait);
return ret;
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 93496c0..bec0384 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -872,33 +872,38 @@ send_layoutget(struct pnfs_layout_hdr *lo,
dprintk("--> %s\n", __func__);
- lgp = kzalloc(sizeof(*lgp), gfp_flags);
- if (lgp == NULL)
- return NULL;
+ /*
+ * Synchronously retrieve layout information from server and
+ * store in lseg. If we race with a concurrent seqid morphing
+ * op, then re-send the LAYOUTGET.
+ */
+ do {
+ lgp = kzalloc(sizeof(*lgp), gfp_flags);
+ if (lgp == NULL)
+ return NULL;
+
+ i_size = i_size_read(ino);
+
+ lgp->args.minlength = PAGE_CACHE_SIZE;
+ if (lgp->args.minlength > range->length)
+ lgp->args.minlength = range->length;
+ if (range->iomode == IOMODE_READ) {
+ if (range->offset >= i_size)
+ lgp->args.minlength = 0;
+ else if (i_size - range->offset < lgp->args.minlength)
+ lgp->args.minlength = i_size - range->offset;
+ }
+ lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
+ lgp->args.range = *range;
+ lgp->args.type = server->pnfs_curr_ld->id;
+ lgp->args.inode = ino;
+ lgp->args.ctx = get_nfs_open_context(ctx);
+ lgp->gfp_flags = gfp_flags;
+ lgp->cred = lo->plh_lc_cred;
- i_size = i_size_read(ino);
+ lseg = nfs4_proc_layoutget(lgp, gfp_flags);
+ } while (lseg == ERR_PTR(-EAGAIN));
- lgp->args.minlength = PAGE_CACHE_SIZE;
- if (lgp->args.minlength > range->length)
- lgp->args.minlength = range->length;
- if (range->iomode == IOMODE_READ) {
- if (range->offset >= i_size)
- lgp->args.minlength = 0;
- else if (i_size - range->offset < lgp->args.minlength)
- lgp->args.minlength = i_size - range->offset;
- }
- lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE;
- lgp->args.range = *range;
- lgp->args.type = server->pnfs_curr_ld->id;
- lgp->args.inode = ino;
- lgp->args.ctx = get_nfs_open_context(ctx);
- lgp->gfp_flags = gfp_flags;
- lgp->cred = lo->plh_lc_cred;
-
- /* Synchronously retrieve layout information from server and
- * store in lseg.
- */
- lseg = nfs4_proc_layoutget(lgp, gfp_flags);
if (IS_ERR(lseg)) {
switch (PTR_ERR(lseg)) {
case -ENOMEM:
@@ -1461,11 +1466,11 @@ static bool pnfs_within_mdsthreshold(struct nfs_open_context *ctx,
}
/* stop waiting if someone clears NFS_LAYOUT_RETRY_LAYOUTGET bit. */
-static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key)
+static int pnfs_layoutget_retry_bit_wait(struct wait_bit_key *key, int mode)
{
if (!test_bit(NFS_LAYOUT_RETRY_LAYOUTGET, key->flags))
return 1;
- return nfs_wait_bit_killable(key);
+ return nfs_wait_bit_killable(key, mode);
}
static bool pnfs_prepare_to_retry_layoutget(struct pnfs_layout_hdr *lo)
@@ -1687,6 +1692,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
/* existing state ID, make sure the sequence number matches. */
if (pnfs_layout_stateid_blocked(lo, &res->stateid)) {
dprintk("%s forget reply due to sequence\n", __func__);
+ status = -EAGAIN;
goto out_forget_reply;
}
pnfs_set_layout_stateid(lo, &res->stateid, false);
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index b6de433..4fe3eea 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -42,21 +42,35 @@ error:
return -EIO;
}
-static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
+static const char *nfs_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(dentry);
struct page *page;
void *err;
- err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
- if (err)
- return err;
- page = read_cache_page(&inode->i_data, 0,
- (filler_t *)nfs_symlink_filler, inode);
- if (IS_ERR(page))
- return ERR_CAST(page);
- *cookie = page;
- return kmap(page);
+ if (!dentry) {
+ err = ERR_PTR(nfs_revalidate_mapping_rcu(inode));
+ if (err)
+ return err;
+ page = find_get_page(inode->i_mapping, 0);
+ if (!page)
+ return ERR_PTR(-ECHILD);
+ if (!PageUptodate(page)) {
+ put_page(page);
+ return ERR_PTR(-ECHILD);
+ }
+ } else {
+ err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
+ if (err)
+ return err;
+ page = read_cache_page(&inode->i_data, 0,
+ (filler_t *)nfs_symlink_filler, inode);
+ if (IS_ERR(page))
+ return ERR_CAST(page);
+ }
+ set_delayed_call(done, page_put_link, page);
+ return page_address(page);
}
/*
@@ -64,8 +78,7 @@ static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
*/
const struct inode_operations nfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = nfs_follow_link,
- .put_link = page_put_link,
+ .get_link = nfs_get_link,
.getattr = nfs_getattr,
.setattr = nfs_setattr,
};
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index f6e7cba..2246454 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -262,11 +262,11 @@ void fill_post_wcc(struct svc_fh *fhp)
err = fh_getattr(fhp, &fhp->fh_post_attr);
fhp->fh_post_change = d_inode(fhp->fh_dentry)->i_version;
if (err) {
- fhp->fh_post_saved = 0;
+ fhp->fh_post_saved = false;
/* Grab the ctime anyway - set_change_info might use it */
fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime;
} else
- fhp->fh_post_saved = 1;
+ fhp->fh_post_saved = true;
}
/*
@@ -823,7 +823,7 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
} else
dchild = dget(dparent);
} else
- dchild = lookup_one_len(name, dparent, namlen);
+ dchild = lookup_one_len_unlocked(name, dparent, namlen);
if (IS_ERR(dchild))
return rv;
if (d_mountpoint(dchild))
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index ebf90e4..c9d6c71 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -201,6 +201,7 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
INIT_LIST_HEAD(&ls->ls_perfile);
spin_lock_init(&ls->ls_lock);
INIT_LIST_HEAD(&ls->ls_layouts);
+ mutex_init(&ls->ls_mutex);
ls->ls_layout_type = layout_type;
nfsd4_init_cb(&ls->ls_recall, clp, &nfsd4_cb_layout_ops,
NFSPROC4_CLNT_CB_LAYOUT);
@@ -262,19 +263,23 @@ nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
status = nfserr_jukebox;
if (!ls)
goto out;
+ mutex_lock(&ls->ls_mutex);
} else {
ls = container_of(stid, struct nfs4_layout_stateid, ls_stid);
status = nfserr_bad_stateid;
+ mutex_lock(&ls->ls_mutex);
if (stateid->si_generation > stid->sc_stateid.si_generation)
- goto out_put_stid;
+ goto out_unlock_stid;
if (layout_type != ls->ls_layout_type)
- goto out_put_stid;
+ goto out_unlock_stid;
}
*lsp = ls;
return 0;
+out_unlock_stid:
+ mutex_unlock(&ls->ls_mutex);
out_put_stid:
nfs4_put_stid(stid);
out:
@@ -296,8 +301,6 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
trace_layout_recall(&ls->ls_stid.sc_stateid);
atomic_inc(&ls->ls_stid.sc_count);
- update_stateid(&ls->ls_stid.sc_stateid);
- memcpy(&ls->ls_recall_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t));
nfsd4_run_cb(&ls->ls_recall);
out_unlock:
@@ -406,8 +409,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls)
list_add_tail(&new->lo_perstate, &ls->ls_layouts);
new = NULL;
done:
- update_stateid(&ls->ls_stid.sc_stateid);
- memcpy(&lgp->lg_sid, &ls->ls_stid.sc_stateid, sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&lgp->lg_sid, &ls->ls_stid);
spin_unlock(&ls->ls_lock);
out:
spin_unlock(&fp->fi_lock);
@@ -481,11 +483,8 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
}
}
if (!list_empty(&ls->ls_layouts)) {
- if (found) {
- update_stateid(&ls->ls_stid.sc_stateid);
- memcpy(&lrp->lr_sid, &ls->ls_stid.sc_stateid,
- sizeof(stateid_t));
- }
+ if (found)
+ nfs4_inc_and_copy_stateid(&lrp->lr_sid, &ls->ls_stid);
lrp->lrs_present = 1;
} else {
trace_layoutstate_unhash(&ls->ls_stid.sc_stateid);
@@ -494,6 +493,7 @@ nfsd4_return_file_layouts(struct svc_rqst *rqstp,
}
spin_unlock(&ls->ls_lock);
+ mutex_unlock(&ls->ls_mutex);
nfs4_put_stid(&ls->ls_stid);
nfsd4_free_layouts(&reaplist);
return nfs_ok;
@@ -608,6 +608,17 @@ nfsd4_cb_layout_fail(struct nfs4_layout_stateid *ls)
}
}
+static void
+nfsd4_cb_layout_prepare(struct nfsd4_callback *cb)
+{
+ struct nfs4_layout_stateid *ls =
+ container_of(cb, struct nfs4_layout_stateid, ls_recall);
+
+ mutex_lock(&ls->ls_mutex);
+ nfs4_inc_and_copy_stateid(&ls->ls_recall_sid, &ls->ls_stid);
+ mutex_unlock(&ls->ls_mutex);
+}
+
static int
nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task)
{
@@ -655,6 +666,7 @@ nfsd4_cb_layout_release(struct nfsd4_callback *cb)
}
static struct nfsd4_callback_ops nfsd4_cb_layout_ops = {
+ .prepare = nfsd4_cb_layout_prepare,
.done = nfsd4_cb_layout_done,
.release = nfsd4_cb_layout_release,
};
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 4ce6b97..819ad81 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -774,8 +774,9 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
/* check stateid */
- status = nfs4_preprocess_stateid_op(rqstp, cstate, &read->rd_stateid,
- RD_STATE, &read->rd_filp, &read->rd_tmp_file);
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &read->rd_stateid, RD_STATE,
+ &read->rd_filp, &read->rd_tmp_file);
if (status) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
@@ -921,7 +922,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
status = nfs4_preprocess_stateid_op(rqstp, cstate,
- &setattr->sa_stateid, WR_STATE, NULL, NULL);
+ &cstate->current_fh, &setattr->sa_stateid,
+ WR_STATE, NULL, NULL);
if (status) {
dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
return status;
@@ -985,8 +987,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (write->wr_offset >= OFFSET_MAX)
return nfserr_inval;
- status = nfs4_preprocess_stateid_op(rqstp, cstate, stateid, WR_STATE,
- &filp, NULL);
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ stateid, WR_STATE, &filp, NULL);
if (status) {
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
return status;
@@ -1010,13 +1012,54 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}
static __be32
+nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
+ struct nfsd4_clone *clone)
+{
+ struct file *src, *dst;
+ __be32 status;
+
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
+ &clone->cl_src_stateid, RD_STATE,
+ &src, NULL);
+ if (status) {
+ dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
+ goto out;
+ }
+
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
+ &clone->cl_dst_stateid, WR_STATE,
+ &dst, NULL);
+ if (status) {
+ dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
+ goto out_put_src;
+ }
+
+ /* fix up for NFS-specific error code */
+ if (!S_ISREG(file_inode(src)->i_mode) ||
+ !S_ISREG(file_inode(dst)->i_mode)) {
+ status = nfserr_wrong_type;
+ goto out_put_dst;
+ }
+
+ status = nfsd4_clone_file_range(src, clone->cl_src_pos,
+ dst, clone->cl_dst_pos, clone->cl_count);
+
+out_put_dst:
+ fput(dst);
+out_put_src:
+ fput(src);
+out:
+ return status;
+}
+
+static __be32
nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
struct nfsd4_fallocate *fallocate, int flags)
{
__be32 status = nfserr_notsupp;
struct file *file;
- status = nfs4_preprocess_stateid_op(rqstp, cstate,
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&fallocate->falloc_stateid,
WR_STATE, &file, NULL);
if (status != nfs_ok) {
@@ -1055,7 +1098,7 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
__be32 status;
struct file *file;
- status = nfs4_preprocess_stateid_op(rqstp, cstate,
+ status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
&seek->seek_stateid,
RD_STATE, &file, NULL);
if (status) {
@@ -1309,6 +1352,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
nfserr = nfsd4_insert_layout(lgp, ls);
out_put_stid:
+ mutex_unlock(&ls->ls_mutex);
nfs4_put_stid(&ls->ls_stid);
out:
return nfserr;
@@ -1362,6 +1406,9 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
goto out;
}
+ /* LAYOUTCOMMIT does not require any serialization */
+ mutex_unlock(&ls->ls_mutex);
+
if (new_size > i_size_read(inode)) {
lcp->lc_size_chg = 1;
lcp->lc_newsize = new_size;
@@ -2275,6 +2322,12 @@ static struct nfsd4_operation nfsd4_ops[] = {
.op_name = "OP_DEALLOCATE",
.op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
},
+ [OP_CLONE] = {
+ .op_func = (nfsd4op_func)nfsd4_clone,
+ .op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
+ .op_name = "OP_CLONE",
+ .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
+ },
[OP_SEEK] = {
.op_func = (nfsd4op_func)nfsd4_seek,
.op_name = "OP_SEEK",
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0f1d569..df5dba6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -575,6 +575,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
stid->sc_stateid.si_opaque.so_clid = cl->cl_clientid;
/* Will be incremented before return to client: */
atomic_set(&stid->sc_count, 1);
+ spin_lock_init(&stid->sc_lock);
/*
* It shouldn't be a problem to reuse an opaque stateid value.
@@ -745,6 +746,18 @@ nfs4_put_stid(struct nfs4_stid *s)
put_nfs4_file(fp);
}
+void
+nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid)
+{
+ stateid_t *src = &stid->sc_stateid;
+
+ spin_lock(&stid->sc_lock);
+ if (unlikely(++src->si_generation == 0))
+ src->si_generation = 1;
+ memcpy(dst, src, sizeof(*dst));
+ spin_unlock(&stid->sc_lock);
+}
+
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
{
struct file *filp = NULL;
@@ -765,16 +778,68 @@ void nfs4_unhash_stid(struct nfs4_stid *s)
s->sc_type = 0;
}
-static void
+/**
+ * nfs4_get_existing_delegation - Discover if this delegation already exists
+ * @clp: a pointer to the nfs4_client we're granting a delegation to
+ * @fp: a pointer to the nfs4_file we're granting a delegation on
+ *
+ * Return:
+ * On success: NULL if an existing delegation was not found.
+ *
+ * On error: -EAGAIN if one was previously granted to this nfs4_client
+ * for this nfs4_file.
+ *
+ */
+
+static int
+nfs4_get_existing_delegation(struct nfs4_client *clp, struct nfs4_file *fp)
+{
+ struct nfs4_delegation *searchdp = NULL;
+ struct nfs4_client *searchclp = NULL;
+
+ lockdep_assert_held(&state_lock);
+ lockdep_assert_held(&fp->fi_lock);
+
+ list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) {
+ searchclp = searchdp->dl_stid.sc_client;
+ if (clp == searchclp) {
+ return -EAGAIN;
+ }
+ }
+ return 0;
+}
+
+/**
+ * hash_delegation_locked - Add a delegation to the appropriate lists
+ * @dp: a pointer to the nfs4_delegation we are adding.
+ * @fp: a pointer to the nfs4_file we're granting a delegation on
+ *
+ * Return:
+ * On success: NULL if the delegation was successfully hashed.
+ *
+ * On error: -EAGAIN if one was previously granted to this
+ * nfs4_client for this nfs4_file. Delegation is not hashed.
+ *
+ */
+
+static int
hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp)
{
+ int status;
+ struct nfs4_client *clp = dp->dl_stid.sc_client;
+
lockdep_assert_held(&state_lock);
lockdep_assert_held(&fp->fi_lock);
+ status = nfs4_get_existing_delegation(clp, fp);
+ if (status)
+ return status;
+ ++fp->fi_delegees;
atomic_inc(&dp->dl_stid.sc_count);
dp->dl_stid.sc_type = NFS4_DELEG_STID;
list_add(&dp->dl_perfile, &fp->fi_delegations);
- list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
+ list_add(&dp->dl_perclnt, &clp->cl_delegations);
+ return 0;
}
static bool
@@ -2256,15 +2321,20 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
clid->flags = new->cl_exchange_flags;
}
+static bool client_has_openowners(struct nfs4_client *clp)
+{
+ struct nfs4_openowner *oo;
+
+ list_for_each_entry(oo, &clp->cl_openowners, oo_perclient) {
+ if (!list_empty(&oo->oo_owner.so_stateids))
+ return true;
+ }
+ return false;
+}
+
static bool client_has_state(struct nfs4_client *clp)
{
- /*
- * Note clp->cl_openowners check isn't quite right: there's no
- * need to count owners without stateid's.
- *
- * Also note we should probably be using this in 4.0 case too.
- */
- return !list_empty(&clp->cl_openowners)
+ return client_has_openowners(clp)
#ifdef CONFIG_NFSD_PNFS
|| !list_empty(&clp->cl_lo_states)
#endif
@@ -3049,7 +3119,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* Cases below refer to rfc 3530 section 14.2.33: */
spin_lock(&nn->client_lock);
conf = find_confirmed_client_by_name(&clname, nn);
- if (conf) {
+ if (conf && client_has_state(conf)) {
/* case 0: */
status = nfserr_clid_inuse;
if (clp_used_exchangeid(conf))
@@ -3136,6 +3206,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
} else { /* case 3: normal case; new or rebooted client */
old = find_confirmed_client_by_name(&unconf->cl_name, nn);
if (old) {
+ status = nfserr_clid_inuse;
+ if (client_has_state(old)
+ && !same_creds(&unconf->cl_cred,
+ &old->cl_cred))
+ goto out;
status = mark_client_expired_locked(old);
if (status) {
old = NULL;
@@ -3317,6 +3392,27 @@ static const struct nfs4_stateowner_operations openowner_ops = {
.so_free = nfs4_free_openowner,
};
+static struct nfs4_ol_stateid *
+nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
+{
+ struct nfs4_ol_stateid *local, *ret = NULL;
+ struct nfs4_openowner *oo = open->op_openowner;
+
+ lockdep_assert_held(&fp->fi_lock);
+
+ list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
+ /* ignore lock owners */
+ if (local->st_stateowner->so_is_open_owner == 0)
+ continue;
+ if (local->st_stateowner == &oo->oo_owner) {
+ ret = local;
+ atomic_inc(&ret->st_stid.sc_count);
+ break;
+ }
+ }
+ return ret;
+}
+
static struct nfs4_openowner *
alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
struct nfsd4_compound_state *cstate)
@@ -3348,9 +3444,20 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
return ret;
}
-static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
+static struct nfs4_ol_stateid *
+init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
+ struct nfsd4_open *open)
+{
+
struct nfs4_openowner *oo = open->op_openowner;
+ struct nfs4_ol_stateid *retstp = NULL;
+ spin_lock(&oo->oo_owner.so_client->cl_lock);
+ spin_lock(&fp->fi_lock);
+
+ retstp = nfsd4_find_existing_open(fp, open);
+ if (retstp)
+ goto out_unlock;
atomic_inc(&stp->st_stid.sc_count);
stp->st_stid.sc_type = NFS4_OPEN_STID;
INIT_LIST_HEAD(&stp->st_locks);
@@ -3360,12 +3467,14 @@ static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
stp->st_access_bmap = 0;
stp->st_deny_bmap = 0;
stp->st_openstp = NULL;
- spin_lock(&oo->oo_owner.so_client->cl_lock);
+ init_rwsem(&stp->st_rwsem);
list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
- spin_lock(&fp->fi_lock);
list_add(&stp->st_perfile, &fp->fi_stateids);
+
+out_unlock:
spin_unlock(&fp->fi_lock);
spin_unlock(&oo->oo_owner.so_client->cl_lock);
+ return retstp;
}
/*
@@ -3776,27 +3885,6 @@ out:
return nfs_ok;
}
-static struct nfs4_ol_stateid *
-nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
-{
- struct nfs4_ol_stateid *local, *ret = NULL;
- struct nfs4_openowner *oo = open->op_openowner;
-
- spin_lock(&fp->fi_lock);
- list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
- /* ignore lock owners */
- if (local->st_stateowner->so_is_open_owner == 0)
- continue;
- if (local->st_stateowner == &oo->oo_owner) {
- ret = local;
- atomic_inc(&ret->st_stid.sc_count);
- break;
- }
- }
- spin_unlock(&fp->fi_lock);
- return ret;
-}
-
static inline int nfs4_access_to_access(u32 nfs4_access)
{
int flags = 0;
@@ -3945,6 +4033,18 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
return fl;
}
+/**
+ * nfs4_setlease - Obtain a delegation by requesting lease from vfs layer
+ * @dp: a pointer to the nfs4_delegation we're adding.
+ *
+ * Return:
+ * On success: Return code will be 0 on success.
+ *
+ * On error: -EAGAIN if there was an existing delegation.
+ * nonzero if there is an error in other cases.
+ *
+ */
+
static int nfs4_setlease(struct nfs4_delegation *dp)
{
struct nfs4_file *fp = dp->dl_stid.sc_file;
@@ -3976,16 +4076,19 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
goto out_unlock;
/* Race breaker */
if (fp->fi_deleg_file) {
- status = 0;
- ++fp->fi_delegees;
- hash_delegation_locked(dp, fp);
+ status = hash_delegation_locked(dp, fp);
goto out_unlock;
}
fp->fi_deleg_file = filp;
- fp->fi_delegees = 1;
- hash_delegation_locked(dp, fp);
+ fp->fi_delegees = 0;
+ status = hash_delegation_locked(dp, fp);
spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock);
+ if (status) {
+ /* Should never happen, this is a new fi_deleg_file */
+ WARN_ON_ONCE(1);
+ goto out_fput;
+ }
return 0;
out_unlock:
spin_unlock(&fp->fi_lock);
@@ -4005,6 +4108,15 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
if (fp->fi_had_conflict)
return ERR_PTR(-EAGAIN);
+ spin_lock(&state_lock);
+ spin_lock(&fp->fi_lock);
+ status = nfs4_get_existing_delegation(clp, fp);
+ spin_unlock(&fp->fi_lock);
+ spin_unlock(&state_lock);
+
+ if (status)
+ return ERR_PTR(status);
+
dp = alloc_init_deleg(clp, fh, odstate);
if (!dp)
return ERR_PTR(-ENOMEM);
@@ -4023,9 +4135,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh,
status = -EAGAIN;
goto out_unlock;
}
- ++fp->fi_delegees;
- hash_delegation_locked(dp, fp);
- status = 0;
+ status = hash_delegation_locked(dp, fp);
out_unlock:
spin_unlock(&fp->fi_lock);
spin_unlock(&state_lock);
@@ -4160,6 +4270,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_client *cl = open->op_openowner->oo_owner.so_client;
struct nfs4_file *fp = NULL;
struct nfs4_ol_stateid *stp = NULL;
+ struct nfs4_ol_stateid *swapstp = NULL;
struct nfs4_delegation *dp = NULL;
__be32 status;
@@ -4173,7 +4284,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_check_deleg(cl, open, &dp);
if (status)
goto out;
+ spin_lock(&fp->fi_lock);
stp = nfsd4_find_existing_open(fp, open);
+ spin_unlock(&fp->fi_lock);
} else {
open->op_file = NULL;
status = nfserr_bad_stateid;
@@ -4187,15 +4300,32 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
*/
if (stp) {
/* Stateid was found, this is an OPEN upgrade */
+ down_read(&stp->st_rwsem);
status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
- if (status)
+ if (status) {
+ up_read(&stp->st_rwsem);
goto out;
+ }
} else {
stp = open->op_stp;
open->op_stp = NULL;
- init_open_stateid(stp, fp, open);
+ swapstp = init_open_stateid(stp, fp, open);
+ if (swapstp) {
+ nfs4_put_stid(&stp->st_stid);
+ stp = swapstp;
+ down_read(&stp->st_rwsem);
+ status = nfs4_upgrade_open(rqstp, fp, current_fh,
+ stp, open);
+ if (status) {
+ up_read(&stp->st_rwsem);
+ goto out;
+ }
+ goto upgrade_out;
+ }
+ down_read(&stp->st_rwsem);
status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
if (status) {
+ up_read(&stp->st_rwsem);
release_open_stateid(stp);
goto out;
}
@@ -4205,8 +4335,9 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (stp->st_clnt_odstate == open->op_odstate)
open->op_odstate = NULL;
}
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
+upgrade_out:
+ nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
+ up_read(&stp->st_rwsem);
if (nfsd4_has_session(&resp->cstate)) {
if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
@@ -4666,10 +4797,9 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s,
*/
__be32
nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate, stateid_t *stateid,
- int flags, struct file **filpp, bool *tmp_file)
+ struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
+ stateid_t *stateid, int flags, struct file **filpp, bool *tmp_file)
{
- struct svc_fh *fhp = &cstate->current_fh;
struct inode *ino = d_inode(fhp->fh_dentry);
struct net *net = SVC_NET(rqstp);
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -4819,10 +4949,13 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
* revoked delegations are kept only for free_stateid.
*/
return nfserr_bad_stateid;
+ down_write(&stp->st_rwsem);
status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
- if (status)
- return status;
- return nfs4_check_fh(current_fh, &stp->st_stid);
+ if (status == nfs_ok)
+ status = nfs4_check_fh(current_fh, &stp->st_stid);
+ if (status != nfs_ok)
+ up_write(&stp->st_rwsem);
+ return status;
}
/*
@@ -4869,6 +5002,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
return status;
oo = openowner(stp->st_stateowner);
if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
+ up_write(&stp->st_rwsem);
nfs4_put_stid(&stp->st_stid);
return nfserr_bad_stateid;
}
@@ -4899,11 +5033,13 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
oo = openowner(stp->st_stateowner);
status = nfserr_bad_stateid;
- if (oo->oo_flags & NFS4_OO_CONFIRMED)
+ if (oo->oo_flags & NFS4_OO_CONFIRMED) {
+ up_write(&stp->st_rwsem);
goto put_stateid;
+ }
oo->oo_flags |= NFS4_OO_CONFIRMED;
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
+ up_write(&stp->st_rwsem);
dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
@@ -4975,13 +5111,11 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
goto put_stateid;
}
nfs4_stateid_downgrade(stp, od->od_share_access);
-
reset_union_bmap_deny(od->od_share_deny, stp);
-
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
status = nfs_ok;
put_stateid:
+ up_write(&stp->st_rwsem);
nfs4_put_stid(&stp->st_stid);
out:
nfsd4_bump_seqid(cstate, status);
@@ -5033,8 +5167,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfsd4_bump_seqid(cstate, status);
if (status)
goto out;
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
+ up_write(&stp->st_rwsem);
nfsd4_close_open_stateid(stp);
@@ -5260,6 +5394,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
stp->st_access_bmap = 0;
stp->st_deny_bmap = open_stp->st_deny_bmap;
stp->st_openstp = open_stp;
+ init_rwsem(&stp->st_rwsem);
list_add(&stp->st_locks, &open_stp->st_locks);
list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
spin_lock(&fp->fi_lock);
@@ -5428,6 +5563,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
&open_stp, nn);
if (status)
goto out;
+ up_write(&open_stp->st_rwsem);
open_sop = openowner(open_stp->st_stateowner);
status = nfserr_bad_stateid;
if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
@@ -5435,6 +5571,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
goto out;
status = lookup_or_create_lock_state(cstate, open_stp, lock,
&lock_stp, &new);
+ if (status == nfs_ok)
+ down_write(&lock_stp->st_rwsem);
} else {
status = nfs4_preprocess_seqid_op(cstate,
lock->lk_old_lock_seqid,
@@ -5512,9 +5650,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);
switch (-err) {
case 0: /* success! */
- update_stateid(&lock_stp->st_stid.sc_stateid);
- memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid,
- sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&lock->lk_resp_stateid, &lock_stp->st_stid);
status = 0;
break;
case (EAGAIN): /* conflock holds conflicting lock */
@@ -5540,6 +5676,8 @@ out:
seqid_mutating_err(ntohl(status)))
lock_sop->lo_owner.so_seqid++;
+ up_write(&lock_stp->st_rwsem);
+
/*
* If this is a new, never-before-used stateid, and we are
* returning an error, then just go ahead and release it.
@@ -5704,11 +5842,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
goto out_nfserr;
}
- update_stateid(&stp->st_stid.sc_stateid);
- memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
+ nfs4_inc_and_copy_stateid(&locku->lu_stateid, &stp->st_stid);
fput:
fput(filp);
put_stateid:
+ up_write(&stp->st_rwsem);
nfs4_put_stid(&stp->st_stid);
out:
nfsd4_bump_seqid(cstate, status);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 51c9e9c..d6ef095 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1675,6 +1675,25 @@ nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp,
}
static __be32
+nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone)
+{
+ DECODE_HEAD;
+
+ status = nfsd4_decode_stateid(argp, &clone->cl_src_stateid);
+ if (status)
+ return status;
+ status = nfsd4_decode_stateid(argp, &clone->cl_dst_stateid);
+ if (status)
+ return status;
+
+ READ_BUF(8 + 8 + 8);
+ p = xdr_decode_hyper(p, &clone->cl_src_pos);
+ p = xdr_decode_hyper(p, &clone->cl_dst_pos);
+ p = xdr_decode_hyper(p, &clone->cl_count);
+ DECODE_TAIL;
+}
+
+static __be32
nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek)
{
DECODE_HEAD;
@@ -1785,6 +1804,7 @@ static nfsd4_dec nfsd4_dec_ops[] = {
[OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp,
[OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
[OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
+ [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
};
static inline bool
@@ -2838,14 +2858,14 @@ nfsd4_encode_dirent_fattr(struct xdr_stream *xdr, struct nfsd4_readdir *cd,
__be32 nfserr;
int ignore_crossmnt = 0;
- dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
+ dentry = lookup_one_len_unlocked(name, cd->rd_fhp->fh_dentry, namlen);
if (IS_ERR(dentry))
return nfserrno(PTR_ERR(dentry));
if (d_really_is_negative(dentry)) {
/*
- * nfsd_buffered_readdir drops the i_mutex between
- * readdir and calling this callback, leaving a window
- * where this directory entry could have gone away.
+ * we're not holding the i_mutex here, so there's
+ * a window where this directory entry could have gone
+ * away.
*/
dput(dentry);
return nfserr_noent;
@@ -4292,6 +4312,7 @@ static nfsd4_enc nfsd4_enc_ops[] = {
[OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop,
[OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
[OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
+ [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
};
/*
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index 46ec934..54cde9a 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -63,7 +63,6 @@ static unsigned int longest_chain;
static unsigned int longest_chain_cachesize;
static int nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *vec);
-static void cache_cleaner_func(struct work_struct *unused);
static unsigned long nfsd_reply_cache_count(struct shrinker *shrink,
struct shrink_control *sc);
static unsigned long nfsd_reply_cache_scan(struct shrinker *shrink,
@@ -76,13 +75,6 @@ static struct shrinker nfsd_reply_cache_shrinker = {
};
/*
- * locking for the reply cache:
- * A cache entry is "single use" if c_state == RC_INPROG
- * Otherwise, it when accessing _prev or _next, the lock must be held.
- */
-static DECLARE_DELAYED_WORK(cache_cleaner, cache_cleaner_func);
-
-/*
* Put a cap on the size of the DRC based on the amount of available
* low memory in the machine.
*
@@ -203,7 +195,6 @@ void nfsd_reply_cache_shutdown(void)
unsigned int i;
unregister_shrinker(&nfsd_reply_cache_shrinker);
- cancel_delayed_work_sync(&cache_cleaner);
for (i = 0; i < drc_hashsize; i++) {
struct list_head *head = &drc_hashtbl[i].lru_head;
@@ -217,10 +208,8 @@ void nfsd_reply_cache_shutdown(void)
drc_hashtbl = NULL;
drc_hashsize = 0;
- if (drc_slab) {
- kmem_cache_destroy(drc_slab);
- drc_slab = NULL;
- }
+ kmem_cache_destroy(drc_slab);
+ drc_slab = NULL;
}
/*
@@ -232,7 +221,6 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp)
{
rp->c_timestamp = jiffies;
list_move_tail(&rp->c_lru, &b->lru_head);
- schedule_delayed_work(&cache_cleaner, RC_EXPIRE);
}
static long
@@ -266,7 +254,6 @@ prune_cache_entries(void)
{
unsigned int i;
long freed = 0;
- bool cancel = true;
for (i = 0; i < drc_hashsize; i++) {
struct nfsd_drc_bucket *b = &drc_hashtbl[i];
@@ -275,26 +262,11 @@ prune_cache_entries(void)
continue;
spin_lock(&b->cache_lock);
freed += prune_bucket(b);
- if (!list_empty(&b->lru_head))
- cancel = false;
spin_unlock(&b->cache_lock);
}
-
- /*
- * Conditionally rearm the job to run in RC_EXPIRE since we just
- * ran the pruner.
- */
- if (!cancel)
- mod_delayed_work(system_wq, &cache_cleaner, RC_EXPIRE);
return freed;
}
-static void
-cache_cleaner_func(struct work_struct *unused)
-{
- prune_cache_entries();
-}
-
static unsigned long
nfsd_reply_cache_count(struct shrinker *shrink, struct shrink_control *sc)
{
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 350041a..c1681ce 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -631,10 +631,7 @@ fh_put(struct svc_fh *fhp)
fh_unlock(fhp);
fhp->fh_dentry = NULL;
dput(dentry);
-#ifdef CONFIG_NFSD_V3
- fhp->fh_pre_saved = 0;
- fhp->fh_post_saved = 0;
-#endif
+ fh_clear_wcc(fhp);
}
fh_drop_write(fhp);
if (exp) {
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 1e90dad..2087bae 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -26,16 +26,16 @@ static inline ino_t u32_to_ino_t(__u32 uino)
*/
typedef struct svc_fh {
struct knfsd_fh fh_handle; /* FH data */
+ int fh_maxsize; /* max size for fh_handle */
struct dentry * fh_dentry; /* validated dentry */
struct svc_export * fh_export; /* export pointer */
- int fh_maxsize; /* max size for fh_handle */
- unsigned char fh_locked; /* inode locked by us */
- unsigned char fh_want_write; /* remount protection taken */
+ bool fh_locked; /* inode locked by us */
+ bool fh_want_write; /* remount protection taken */
#ifdef CONFIG_NFSD_V3
- unsigned char fh_post_saved; /* post-op attrs saved */
- unsigned char fh_pre_saved; /* pre-op attrs saved */
+ bool fh_post_saved; /* post-op attrs saved */
+ bool fh_pre_saved; /* pre-op attrs saved */
/* Pre-op attributes saved during fh_lock */
__u64 fh_pre_size; /* size before operation */
@@ -213,8 +213,8 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
static inline void
fh_clear_wcc(struct svc_fh *fhp)
{
- fhp->fh_post_saved = 0;
- fhp->fh_pre_saved = 0;
+ fhp->fh_post_saved = false;
+ fhp->fh_pre_saved = false;
}
/*
@@ -231,7 +231,7 @@ fill_pre_wcc(struct svc_fh *fhp)
fhp->fh_pre_ctime = inode->i_ctime;
fhp->fh_pre_size = inode->i_size;
fhp->fh_pre_change = inode->i_version;
- fhp->fh_pre_saved = 1;
+ fhp->fh_pre_saved = true;
}
}
@@ -267,7 +267,7 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
inode = d_inode(dentry);
mutex_lock_nested(&inode->i_mutex, subclass);
fill_pre_wcc(fhp);
- fhp->fh_locked = 1;
+ fhp->fh_locked = true;
}
static inline void
@@ -285,7 +285,7 @@ fh_unlock(struct svc_fh *fhp)
if (fhp->fh_locked) {
fill_post_wcc(fhp);
mutex_unlock(&d_inode(fhp->fh_dentry)->i_mutex);
- fhp->fh_locked = 0;
+ fhp->fh_locked = false;
}
}
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 583ffc1..99432b7 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -84,7 +84,7 @@ struct nfsd4_callback_ops {
* fields that are of general use to any stateid.
*/
struct nfs4_stid {
- atomic_t sc_count;
+ atomic_t sc_count;
#define NFS4_OPEN_STID 1
#define NFS4_LOCK_STID 2
#define NFS4_DELEG_STID 4
@@ -94,11 +94,12 @@ struct nfs4_stid {
#define NFS4_REVOKED_DELEG_STID 16
#define NFS4_CLOSED_DELEG_STID 32
#define NFS4_LAYOUT_STID 64
- unsigned char sc_type;
- stateid_t sc_stateid;
- struct nfs4_client *sc_client;
- struct nfs4_file *sc_file;
- void (*sc_free)(struct nfs4_stid *);
+ unsigned char sc_type;
+ stateid_t sc_stateid;
+ spinlock_t sc_lock;
+ struct nfs4_client *sc_client;
+ struct nfs4_file *sc_file;
+ void (*sc_free)(struct nfs4_stid *);
};
/*
@@ -364,15 +365,6 @@ struct nfs4_client_reclaim {
char cr_recdir[HEXDIR_LEN]; /* recover dir */
};
-static inline void
-update_stateid(stateid_t *stateid)
-{
- stateid->si_generation++;
- /* Wraparound recommendation from 3530bis-13 9.1.3.2: */
- if (stateid->si_generation == 0)
- stateid->si_generation = 1;
-}
-
/* A reasonable value for REPLAY_ISIZE was estimated as follows:
* The OPEN response, typically the largest, requires
* 4(status) + 8(stateid) + 20(changeinfo) + 4(rflags) + 8(verifier) +
@@ -534,15 +526,16 @@ struct nfs4_file {
* Better suggestions welcome.
*/
struct nfs4_ol_stateid {
- struct nfs4_stid st_stid; /* must be first field */
- struct list_head st_perfile;
- struct list_head st_perstateowner;
- struct list_head st_locks;
- struct nfs4_stateowner * st_stateowner;
- struct nfs4_clnt_odstate * st_clnt_odstate;
- unsigned char st_access_bmap;
- unsigned char st_deny_bmap;
- struct nfs4_ol_stateid * st_openstp;
+ struct nfs4_stid st_stid;
+ struct list_head st_perfile;
+ struct list_head st_perstateowner;
+ struct list_head st_locks;
+ struct nfs4_stateowner *st_stateowner;
+ struct nfs4_clnt_odstate *st_clnt_odstate;
+ unsigned char st_access_bmap;
+ unsigned char st_deny_bmap;
+ struct nfs4_ol_stateid *st_openstp;
+ struct rw_semaphore st_rwsem;
};
static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
@@ -561,6 +554,7 @@ struct nfs4_layout_stateid {
struct nfsd4_callback ls_recall;
stateid_t ls_recall_sid;
bool ls_recalled;
+ struct mutex ls_mutex;
};
static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s)
@@ -584,8 +578,8 @@ struct nfsd4_compound_state;
struct nfsd_net;
extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
- struct nfsd4_compound_state *cstate, stateid_t *stateid,
- int flags, struct file **filp, bool *tmp_file);
+ struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
+ stateid_t *stateid, int flags, struct file **filp, bool *tmp_file);
__be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
stateid_t *stateid, unsigned char typemask,
struct nfs4_stid **s, struct nfsd_net *nn);
@@ -593,6 +587,7 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl,
struct kmem_cache *slab);
void nfs4_unhash_stid(struct nfs4_stid *s);
void nfs4_put_stid(struct nfs4_stid *s);
+void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *);
extern void nfs4_release_reclaim(struct nfsd_net *);
extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir,
diff --git a/fs/nfsd/trace.c b/fs/nfsd/trace.c
index 82f8907..9096746 100644
--- a/fs/nfsd/trace.c
+++ b/fs/nfsd/trace.c
@@ -1,5 +1,3 @@
-#include "state.h"
-
#define CREATE_TRACE_POINTS
#include "trace.h"
diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h
index c668520..0befe76 100644
--- a/fs/nfsd/trace.h
+++ b/fs/nfsd/trace.h
@@ -9,6 +9,8 @@
#include <linux/tracepoint.h>
+#include "state.h"
+
DECLARE_EVENT_CLASS(nfsd_stateid_class,
TP_PROTO(stateid_t *stp),
TP_ARGS(stp),
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 45c0497..d41c149 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -36,6 +36,7 @@
#endif /* CONFIG_NFSD_V3 */
#ifdef CONFIG_NFSD_V4
+#include "../internal.h"
#include "acl.h"
#include "idmap.h"
#endif /* CONFIG_NFSD_V4 */
@@ -217,10 +218,16 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
host_err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_nfserr;
- /*
- * check if we have crossed a mount point ...
- */
if (nfsd_mountpoint(dentry, exp)) {
+ /*
+ * We don't need the i_mutex after all. It's
+ * still possible we could open this (regular
+ * files can be mountpoints too), but the
+ * i_mutex is just there to prevent renames of
+ * something that we might be about to delegate,
+ * and a mountpoint won't be renamed:
+ */
+ fh_unlock(fhp);
if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
dput(dentry);
goto out_nfserr;
@@ -498,6 +505,13 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp,
}
#endif
+__be32 nfsd4_clone_file_range(struct file *src, u64 src_pos, struct file *dst,
+ u64 dst_pos, u64 count)
+{
+ return nfserrno(vfs_clone_file_range(src, src_pos, dst, dst_pos,
+ count));
+}
+
__be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct file *file, loff_t offset, loff_t len,
int flags)
@@ -1631,7 +1645,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
/* cannot use fh_lock as we need deadlock protective ordering
* so do it by hand */
trap = lock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = 1;
+ ffhp->fh_locked = tfhp->fh_locked = true;
fill_pre_wcc(ffhp);
fill_pre_wcc(tfhp);
@@ -1681,7 +1695,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
fill_post_wcc(ffhp);
fill_post_wcc(tfhp);
unlock_rename(tdentry, fdentry);
- ffhp->fh_locked = tfhp->fh_locked = 0;
+ ffhp->fh_locked = tfhp->fh_locked = false;
fh_drop_write(ffhp);
out:
@@ -1809,7 +1823,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
offset = *offsetp;
while (1) {
- struct inode *dir_inode = file_inode(file);
unsigned int reclen;
cdp->err = nfserr_eof; /* will be cleared on successful read */
@@ -1828,15 +1841,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
if (!size)
break;
- /*
- * Various filldir functions may end up calling back into
- * lookup_one_len() and the file system's ->lookup() method.
- * These expect i_mutex to be held, as it would within readdir.
- */
- host_err = mutex_lock_killable(&dir_inode->i_mutex);
- if (host_err)
- break;
-
de = (struct buffered_dirent *)buf.dirent;
while (size > 0) {
offset = de->offset;
@@ -1853,7 +1857,6 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
size -= reclen;
de = (struct buffered_dirent *)((char *)de + reclen);
}
- mutex_unlock(&dir_inode->i_mutex);
if (size > 0) /* We bailed out early */
break;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index fee2451..c11ba31 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -56,6 +56,8 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
struct xdr_netobj *);
__be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
struct file *, loff_t, loff_t, int);
+__be32 nfsd4_clone_file_range(struct file *, u64, struct file *,
+ u64, u64);
#endif /* CONFIG_NFSD_V4 */
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
@@ -112,14 +114,14 @@ static inline int fh_want_write(struct svc_fh *fh)
int ret = mnt_want_write(fh->fh_export->ex_path.mnt);
if (!ret)
- fh->fh_want_write = 1;
+ fh->fh_want_write = true;
return ret;
}
static inline void fh_drop_write(struct svc_fh *fh)
{
if (fh->fh_want_write) {
- fh->fh_want_write = 0;
+ fh->fh_want_write = false;
mnt_drop_write(fh->fh_export->ex_path.mnt);
}
}
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 9f99100..d955481 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -491,6 +491,15 @@ struct nfsd4_fallocate {
u64 falloc_length;
};
+struct nfsd4_clone {
+ /* request */
+ stateid_t cl_src_stateid;
+ stateid_t cl_dst_stateid;
+ u64 cl_src_pos;
+ u64 cl_dst_pos;
+ u64 cl_count;
+};
+
struct nfsd4_seek {
/* request */
stateid_t seek_stateid;
@@ -555,6 +564,7 @@ struct nfsd4_op {
/* NFSv4.2 */
struct nfsd4_fallocate allocate;
struct nfsd4_fallocate deallocate;
+ struct nfsd4_clone clone;
struct nfsd4_seek seek;
} u;
struct nfs4_replay * replay;
@@ -632,7 +642,7 @@ static inline void
set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
{
BUG_ON(!fhp->fh_pre_saved);
- cinfo->atomic = fhp->fh_post_saved;
+ cinfo->atomic = (u32)fhp->fh_post_saved;
cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry));
cinfo->before_change = fhp->fh_pre_change;
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
index 54575e3..088ba00 100644
--- a/fs/nilfs2/file.c
+++ b/fs/nilfs2/file.c
@@ -109,7 +109,7 @@ static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
goto out;
file_update_time(vma->vm_file);
- ret = __block_page_mkwrite(vma, vmf, nilfs_get_block);
+ ret = block_page_mkwrite(vma, vmf, nilfs_get_block);
if (ret) {
nilfs_transaction_abort(inode->i_sb);
goto out;
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index ac2f649..10b2252 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -510,6 +510,7 @@ static int __nilfs_read_inode(struct super_block *sb,
inode->i_mapping->a_ops = &nilfs_aops;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &nilfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &nilfs_aops;
} else {
inode->i_op = &nilfs_special_inode_operations;
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index c9a1a49..7ccdb96 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -161,6 +161,7 @@ static int nilfs_symlink(struct inode *dir, struct dentry *dentry,
/* slow symlink */
inode->i_op = &nilfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &nilfs_aops;
err = page_symlink(inode, symname, l);
if (err)
@@ -568,8 +569,7 @@ const struct inode_operations nilfs_special_inode_operations = {
const struct inode_operations nilfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.permission = nilfs_permission,
};
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 354013e..c734384 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -1316,13 +1316,11 @@ nilfs_mount(struct file_system_type *fs_type, int flags,
}
if (!s->s_root) {
- char b[BDEVNAME_SIZE];
-
- s_new = true;
+ s_new = true;
/* New superblock instance created */
s->s_mode = mode;
- strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
+ snprintf(s->s_id, sizeof(s->s_id), "%pg", sd.bdev);
sb_set_blocksize(s, block_size(sd.bdev));
err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index ddddef0..709fbbd 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1480,16 +1480,17 @@ static int o2hb_read_block_input(struct o2hb_region *reg,
return 0;
}
-static ssize_t o2hb_region_block_bytes_read(struct o2hb_region *reg,
+static ssize_t o2hb_region_block_bytes_show(struct config_item *item,
char *page)
{
- return sprintf(page, "%u\n", reg->hr_block_bytes);
+ return sprintf(page, "%u\n", to_o2hb_region(item)->hr_block_bytes);
}
-static ssize_t o2hb_region_block_bytes_write(struct o2hb_region *reg,
+static ssize_t o2hb_region_block_bytes_store(struct config_item *item,
const char *page,
size_t count)
{
+ struct o2hb_region *reg = to_o2hb_region(item);
int status;
unsigned long block_bytes;
unsigned int block_bits;
@@ -1508,16 +1509,17 @@ static ssize_t o2hb_region_block_bytes_write(struct o2hb_region *reg,
return count;
}
-static ssize_t o2hb_region_start_block_read(struct o2hb_region *reg,
+static ssize_t o2hb_region_start_block_show(struct config_item *item,
char *page)
{
- return sprintf(page, "%llu\n", reg->hr_start_block);
+ return sprintf(page, "%llu\n", to_o2hb_region(item)->hr_start_block);
}
-static ssize_t o2hb_region_start_block_write(struct o2hb_region *reg,
+static ssize_t o2hb_region_start_block_store(struct config_item *item,
const char *page,
size_t count)
{
+ struct o2hb_region *reg = to_o2hb_region(item);
unsigned long long tmp;
char *p = (char *)page;
@@ -1533,16 +1535,16 @@ static ssize_t o2hb_region_start_block_write(struct o2hb_region *reg,
return count;
}
-static ssize_t o2hb_region_blocks_read(struct o2hb_region *reg,
- char *page)
+static ssize_t o2hb_region_blocks_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", reg->hr_blocks);
+ return sprintf(page, "%d\n", to_o2hb_region(item)->hr_blocks);
}
-static ssize_t o2hb_region_blocks_write(struct o2hb_region *reg,
+static ssize_t o2hb_region_blocks_store(struct config_item *item,
const char *page,
size_t count)
{
+ struct o2hb_region *reg = to_o2hb_region(item);
unsigned long tmp;
char *p = (char *)page;
@@ -1561,13 +1563,12 @@ static ssize_t o2hb_region_blocks_write(struct o2hb_region *reg,
return count;
}
-static ssize_t o2hb_region_dev_read(struct o2hb_region *reg,
- char *page)
+static ssize_t o2hb_region_dev_show(struct config_item *item, char *page)
{
unsigned int ret = 0;
- if (reg->hr_bdev)
- ret = sprintf(page, "%s\n", reg->hr_dev_name);
+ if (to_o2hb_region(item)->hr_bdev)
+ ret = sprintf(page, "%s\n", to_o2hb_region(item)->hr_dev_name);
return ret;
}
@@ -1677,10 +1678,11 @@ out:
}
/* this is acting as commit; we set up all of hr_bdev and hr_task or nothing */
-static ssize_t o2hb_region_dev_write(struct o2hb_region *reg,
+static ssize_t o2hb_region_dev_store(struct config_item *item,
const char *page,
size_t count)
{
+ struct o2hb_region *reg = to_o2hb_region(item);
struct task_struct *hb_task;
long fd;
int sectsize;
@@ -1841,9 +1843,9 @@ out:
return ret;
}
-static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
- char *page)
+static ssize_t o2hb_region_pid_show(struct config_item *item, char *page)
{
+ struct o2hb_region *reg = to_o2hb_region(item);
pid_t pid = 0;
spin_lock(&o2hb_live_lock);
@@ -1857,92 +1859,23 @@ static ssize_t o2hb_region_pid_read(struct o2hb_region *reg,
return sprintf(page, "%u\n", pid);
}
-struct o2hb_region_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct o2hb_region *, char *);
- ssize_t (*store)(struct o2hb_region *, const char *, size_t);
-};
-
-static struct o2hb_region_attribute o2hb_region_attr_block_bytes = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "block_bytes",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_region_block_bytes_read,
- .store = o2hb_region_block_bytes_write,
-};
-
-static struct o2hb_region_attribute o2hb_region_attr_start_block = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "start_block",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_region_start_block_read,
- .store = o2hb_region_start_block_write,
-};
-
-static struct o2hb_region_attribute o2hb_region_attr_blocks = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "blocks",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_region_blocks_read,
- .store = o2hb_region_blocks_write,
-};
-
-static struct o2hb_region_attribute o2hb_region_attr_dev = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "dev",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_region_dev_read,
- .store = o2hb_region_dev_write,
-};
-
-static struct o2hb_region_attribute o2hb_region_attr_pid = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "pid",
- .ca_mode = S_IRUGO | S_IRUSR },
- .show = o2hb_region_pid_read,
-};
+CONFIGFS_ATTR(o2hb_region_, block_bytes);
+CONFIGFS_ATTR(o2hb_region_, start_block);
+CONFIGFS_ATTR(o2hb_region_, blocks);
+CONFIGFS_ATTR(o2hb_region_, dev);
+CONFIGFS_ATTR_RO(o2hb_region_, pid);
static struct configfs_attribute *o2hb_region_attrs[] = {
- &o2hb_region_attr_block_bytes.attr,
- &o2hb_region_attr_start_block.attr,
- &o2hb_region_attr_blocks.attr,
- &o2hb_region_attr_dev.attr,
- &o2hb_region_attr_pid.attr,
+ &o2hb_region_attr_block_bytes,
+ &o2hb_region_attr_start_block,
+ &o2hb_region_attr_blocks,
+ &o2hb_region_attr_dev,
+ &o2hb_region_attr_pid,
NULL,
};
-static ssize_t o2hb_region_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct o2hb_region *reg = to_o2hb_region(item);
- struct o2hb_region_attribute *o2hb_region_attr =
- container_of(attr, struct o2hb_region_attribute, attr);
- ssize_t ret = 0;
-
- if (o2hb_region_attr->show)
- ret = o2hb_region_attr->show(reg, page);
- return ret;
-}
-
-static ssize_t o2hb_region_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct o2hb_region *reg = to_o2hb_region(item);
- struct o2hb_region_attribute *o2hb_region_attr =
- container_of(attr, struct o2hb_region_attribute, attr);
- ssize_t ret = -EINVAL;
-
- if (o2hb_region_attr->store)
- ret = o2hb_region_attr->store(reg, page, count);
- return ret;
-}
-
static struct configfs_item_operations o2hb_region_item_ops = {
.release = o2hb_region_release,
- .show_attribute = o2hb_region_show,
- .store_attribute = o2hb_region_store,
};
static struct config_item_type o2hb_region_type = {
@@ -2137,49 +2070,14 @@ unlock:
spin_unlock(&o2hb_live_lock);
}
-struct o2hb_heartbeat_group_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct o2hb_heartbeat_group *, char *);
- ssize_t (*store)(struct o2hb_heartbeat_group *, const char *, size_t);
-};
-
-static ssize_t o2hb_heartbeat_group_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct o2hb_heartbeat_group *reg = to_o2hb_heartbeat_group(to_config_group(item));
- struct o2hb_heartbeat_group_attribute *o2hb_heartbeat_group_attr =
- container_of(attr, struct o2hb_heartbeat_group_attribute, attr);
- ssize_t ret = 0;
-
- if (o2hb_heartbeat_group_attr->show)
- ret = o2hb_heartbeat_group_attr->show(reg, page);
- return ret;
-}
-
-static ssize_t o2hb_heartbeat_group_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct o2hb_heartbeat_group *reg = to_o2hb_heartbeat_group(to_config_group(item));
- struct o2hb_heartbeat_group_attribute *o2hb_heartbeat_group_attr =
- container_of(attr, struct o2hb_heartbeat_group_attribute, attr);
- ssize_t ret = -EINVAL;
-
- if (o2hb_heartbeat_group_attr->store)
- ret = o2hb_heartbeat_group_attr->store(reg, page, count);
- return ret;
-}
-
-static ssize_t o2hb_heartbeat_group_threshold_show(struct o2hb_heartbeat_group *group,
- char *page)
+static ssize_t o2hb_heartbeat_group_threshold_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "%u\n", o2hb_dead_threshold);
}
-static ssize_t o2hb_heartbeat_group_threshold_store(struct o2hb_heartbeat_group *group,
- const char *page,
- size_t count)
+static ssize_t o2hb_heartbeat_group_threshold_store(struct config_item *item,
+ const char *page, size_t count)
{
unsigned long tmp;
char *p = (char *)page;
@@ -2194,17 +2092,15 @@ static ssize_t o2hb_heartbeat_group_threshold_store(struct o2hb_heartbeat_group
return count;
}
-static
-ssize_t o2hb_heartbeat_group_mode_show(struct o2hb_heartbeat_group *group,
- char *page)
+static ssize_t o2hb_heartbeat_group_mode_show(struct config_item *item,
+ char *page)
{
return sprintf(page, "%s\n",
o2hb_heartbeat_mode_desc[o2hb_heartbeat_mode]);
}
-static
-ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
- const char *page, size_t count)
+static ssize_t o2hb_heartbeat_group_mode_store(struct config_item *item,
+ const char *page, size_t count)
{
unsigned int i;
int ret;
@@ -2229,33 +2125,15 @@ ssize_t o2hb_heartbeat_group_mode_store(struct o2hb_heartbeat_group *group,
}
-static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_threshold = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "dead_threshold",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_heartbeat_group_threshold_show,
- .store = o2hb_heartbeat_group_threshold_store,
-};
-
-static struct o2hb_heartbeat_group_attribute o2hb_heartbeat_group_attr_mode = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "mode",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2hb_heartbeat_group_mode_show,
- .store = o2hb_heartbeat_group_mode_store,
-};
+CONFIGFS_ATTR(o2hb_heartbeat_group_, threshold);
+CONFIGFS_ATTR(o2hb_heartbeat_group_, mode);
static struct configfs_attribute *o2hb_heartbeat_group_attrs[] = {
- &o2hb_heartbeat_group_attr_threshold.attr,
- &o2hb_heartbeat_group_attr_mode.attr,
+ &o2hb_heartbeat_group_attr_threshold,
+ &o2hb_heartbeat_group_attr_mode,
NULL,
};
-static struct configfs_item_operations o2hb_heartbeat_group_item_ops = {
- .show_attribute = o2hb_heartbeat_group_show,
- .store_attribute = o2hb_heartbeat_group_store,
-};
-
static struct configfs_group_operations o2hb_heartbeat_group_group_ops = {
.make_item = o2hb_heartbeat_group_make_item,
.drop_item = o2hb_heartbeat_group_drop_item,
@@ -2263,7 +2141,6 @@ static struct configfs_group_operations o2hb_heartbeat_group_group_ops = {
static struct config_item_type o2hb_heartbeat_group_type = {
.ct_group_ops = &o2hb_heartbeat_group_group_ops,
- .ct_item_ops = &o2hb_heartbeat_group_item_ops,
.ct_attrs = o2hb_heartbeat_group_attrs,
.ct_owner = THIS_MODULE,
};
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index 441c84e..72afdca 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -172,9 +172,9 @@ static void o2nm_node_release(struct config_item *item)
kfree(node);
}
-static ssize_t o2nm_node_num_read(struct o2nm_node *node, char *page)
+static ssize_t o2nm_node_num_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", node->nd_num);
+ return sprintf(page, "%d\n", to_o2nm_node(item)->nd_num);
}
static struct o2nm_cluster *to_o2nm_cluster_from_node(struct o2nm_node *node)
@@ -188,15 +188,16 @@ enum {
O2NM_NODE_ATTR_NUM = 0,
O2NM_NODE_ATTR_PORT,
O2NM_NODE_ATTR_ADDRESS,
- O2NM_NODE_ATTR_LOCAL,
};
-static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
+static ssize_t o2nm_node_num_store(struct config_item *item, const char *page,
size_t count)
{
+ struct o2nm_node *node = to_o2nm_node(item);
struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
unsigned long tmp;
char *p = (char *)page;
+ int ret = 0;
tmp = simple_strtoul(p, &p, 0);
if (!p || (*p && (*p != '\n')))
@@ -215,26 +216,30 @@ static ssize_t o2nm_node_num_write(struct o2nm_node *node, const char *page,
write_lock(&cluster->cl_nodes_lock);
if (cluster->cl_nodes[tmp])
- p = NULL;
+ ret = -EEXIST;
+ else if (test_and_set_bit(O2NM_NODE_ATTR_NUM,
+ &node->nd_set_attributes))
+ ret = -EBUSY;
else {
cluster->cl_nodes[tmp] = node;
node->nd_num = tmp;
set_bit(tmp, cluster->cl_nodes_bitmap);
}
write_unlock(&cluster->cl_nodes_lock);
- if (p == NULL)
- return -EEXIST;
+ if (ret)
+ return ret;
return count;
}
-static ssize_t o2nm_node_ipv4_port_read(struct o2nm_node *node, char *page)
+static ssize_t o2nm_node_ipv4_port_show(struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", ntohs(node->nd_ipv4_port));
+ return sprintf(page, "%u\n", ntohs(to_o2nm_node(item)->nd_ipv4_port));
}
-static ssize_t o2nm_node_ipv4_port_write(struct o2nm_node *node,
+static ssize_t o2nm_node_ipv4_port_store(struct config_item *item,
const char *page, size_t count)
{
+ struct o2nm_node *node = to_o2nm_node(item);
unsigned long tmp;
char *p = (char *)page;
@@ -247,20 +252,23 @@ static ssize_t o2nm_node_ipv4_port_write(struct o2nm_node *node,
if (tmp >= (u16)-1)
return -ERANGE;
+ if (test_and_set_bit(O2NM_NODE_ATTR_PORT, &node->nd_set_attributes))
+ return -EBUSY;
node->nd_ipv4_port = htons(tmp);
return count;
}
-static ssize_t o2nm_node_ipv4_address_read(struct o2nm_node *node, char *page)
+static ssize_t o2nm_node_ipv4_address_show(struct config_item *item, char *page)
{
- return sprintf(page, "%pI4\n", &node->nd_ipv4_address);
+ return sprintf(page, "%pI4\n", &to_o2nm_node(item)->nd_ipv4_address);
}
-static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
+static ssize_t o2nm_node_ipv4_address_store(struct config_item *item,
const char *page,
size_t count)
{
+ struct o2nm_node *node = to_o2nm_node(item);
struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
int ret, i;
struct rb_node **p, *parent;
@@ -282,6 +290,9 @@ static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
write_lock(&cluster->cl_nodes_lock);
if (o2nm_node_ip_tree_lookup(cluster, ipv4_addr, &p, &parent))
ret = -EEXIST;
+ else if (test_and_set_bit(O2NM_NODE_ATTR_ADDRESS,
+ &node->nd_set_attributes))
+ ret = -EBUSY;
else {
rb_link_node(&node->nd_ip_node, parent, p);
rb_insert_color(&node->nd_ip_node, &cluster->cl_node_ip_tree);
@@ -295,14 +306,15 @@ static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node,
return count;
}
-static ssize_t o2nm_node_local_read(struct o2nm_node *node, char *page)
+static ssize_t o2nm_node_local_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", node->nd_local);
+ return sprintf(page, "%d\n", to_o2nm_node(item)->nd_local);
}
-static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
+static ssize_t o2nm_node_local_store(struct config_item *item, const char *page,
size_t count)
{
+ struct o2nm_node *node = to_o2nm_node(item);
struct o2nm_cluster *cluster = to_o2nm_cluster_from_node(node);
unsigned long tmp;
char *p = (char *)page;
@@ -349,108 +361,21 @@ static ssize_t o2nm_node_local_write(struct o2nm_node *node, const char *page,
return count;
}
-struct o2nm_node_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct o2nm_node *, char *);
- ssize_t (*store)(struct o2nm_node *, const char *, size_t);
-};
-
-static struct o2nm_node_attribute o2nm_node_attr_num = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "num",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_node_num_read,
- .store = o2nm_node_num_write,
-};
-
-static struct o2nm_node_attribute o2nm_node_attr_ipv4_port = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "ipv4_port",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_node_ipv4_port_read,
- .store = o2nm_node_ipv4_port_write,
-};
-
-static struct o2nm_node_attribute o2nm_node_attr_ipv4_address = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "ipv4_address",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_node_ipv4_address_read,
- .store = o2nm_node_ipv4_address_write,
-};
-
-static struct o2nm_node_attribute o2nm_node_attr_local = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "local",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_node_local_read,
- .store = o2nm_node_local_write,
-};
+CONFIGFS_ATTR(o2nm_node_, num);
+CONFIGFS_ATTR(o2nm_node_, ipv4_port);
+CONFIGFS_ATTR(o2nm_node_, ipv4_address);
+CONFIGFS_ATTR(o2nm_node_, local);
static struct configfs_attribute *o2nm_node_attrs[] = {
- [O2NM_NODE_ATTR_NUM] = &o2nm_node_attr_num.attr,
- [O2NM_NODE_ATTR_PORT] = &o2nm_node_attr_ipv4_port.attr,
- [O2NM_NODE_ATTR_ADDRESS] = &o2nm_node_attr_ipv4_address.attr,
- [O2NM_NODE_ATTR_LOCAL] = &o2nm_node_attr_local.attr,
+ &o2nm_node_attr_num,
+ &o2nm_node_attr_ipv4_port,
+ &o2nm_node_attr_ipv4_address,
+ &o2nm_node_attr_local,
NULL,
};
-static int o2nm_attr_index(struct configfs_attribute *attr)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(o2nm_node_attrs); i++) {
- if (attr == o2nm_node_attrs[i])
- return i;
- }
- BUG();
- return 0;
-}
-
-static ssize_t o2nm_node_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct o2nm_node *node = to_o2nm_node(item);
- struct o2nm_node_attribute *o2nm_node_attr =
- container_of(attr, struct o2nm_node_attribute, attr);
- ssize_t ret = 0;
-
- if (o2nm_node_attr->show)
- ret = o2nm_node_attr->show(node, page);
- return ret;
-}
-
-static ssize_t o2nm_node_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct o2nm_node *node = to_o2nm_node(item);
- struct o2nm_node_attribute *o2nm_node_attr =
- container_of(attr, struct o2nm_node_attribute, attr);
- ssize_t ret;
- int attr_index = o2nm_attr_index(attr);
-
- if (o2nm_node_attr->store == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- if (test_bit(attr_index, &node->nd_set_attributes))
- return -EBUSY;
-
- ret = o2nm_node_attr->store(node, page, count);
- if (ret < count)
- goto out;
-
- set_bit(attr_index, &node->nd_set_attributes);
-out:
- return ret;
-}
-
static struct configfs_item_operations o2nm_node_item_ops = {
.release = o2nm_node_release,
- .show_attribute = o2nm_node_show,
- .store_attribute = o2nm_node_store,
};
static struct config_item_type o2nm_node_type = {
@@ -475,12 +400,6 @@ static struct o2nm_node_group *to_o2nm_node_group(struct config_group *group)
}
#endif
-struct o2nm_cluster_attribute {
- struct configfs_attribute attr;
- ssize_t (*show)(struct o2nm_cluster *, char *);
- ssize_t (*store)(struct o2nm_cluster *, const char *, size_t);
-};
-
static ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
unsigned int *val)
{
@@ -501,15 +420,16 @@ static ssize_t o2nm_cluster_attr_write(const char *page, ssize_t count,
return count;
}
-static ssize_t o2nm_cluster_attr_idle_timeout_ms_read(
- struct o2nm_cluster *cluster, char *page)
+static ssize_t o2nm_cluster_idle_timeout_ms_show(struct config_item *item,
+ char *page)
{
- return sprintf(page, "%u\n", cluster->cl_idle_timeout_ms);
+ return sprintf(page, "%u\n", to_o2nm_cluster(item)->cl_idle_timeout_ms);
}
-static ssize_t o2nm_cluster_attr_idle_timeout_ms_write(
- struct o2nm_cluster *cluster, const char *page, size_t count)
+static ssize_t o2nm_cluster_idle_timeout_ms_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct o2nm_cluster *cluster = to_o2nm_cluster(item);
ssize_t ret;
unsigned int val;
@@ -536,15 +456,17 @@ static ssize_t o2nm_cluster_attr_idle_timeout_ms_write(
return ret;
}
-static ssize_t o2nm_cluster_attr_keepalive_delay_ms_read(
- struct o2nm_cluster *cluster, char *page)
+static ssize_t o2nm_cluster_keepalive_delay_ms_show(
+ struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", cluster->cl_keepalive_delay_ms);
+ return sprintf(page, "%u\n",
+ to_o2nm_cluster(item)->cl_keepalive_delay_ms);
}
-static ssize_t o2nm_cluster_attr_keepalive_delay_ms_write(
- struct o2nm_cluster *cluster, const char *page, size_t count)
+static ssize_t o2nm_cluster_keepalive_delay_ms_store(
+ struct config_item *item, const char *page, size_t count)
{
+ struct o2nm_cluster *cluster = to_o2nm_cluster(item);
ssize_t ret;
unsigned int val;
@@ -571,22 +493,24 @@ static ssize_t o2nm_cluster_attr_keepalive_delay_ms_write(
return ret;
}
-static ssize_t o2nm_cluster_attr_reconnect_delay_ms_read(
- struct o2nm_cluster *cluster, char *page)
+static ssize_t o2nm_cluster_reconnect_delay_ms_show(
+ struct config_item *item, char *page)
{
- return sprintf(page, "%u\n", cluster->cl_reconnect_delay_ms);
+ return sprintf(page, "%u\n",
+ to_o2nm_cluster(item)->cl_reconnect_delay_ms);
}
-static ssize_t o2nm_cluster_attr_reconnect_delay_ms_write(
- struct o2nm_cluster *cluster, const char *page, size_t count)
+static ssize_t o2nm_cluster_reconnect_delay_ms_store(
+ struct config_item *item, const char *page, size_t count)
{
return o2nm_cluster_attr_write(page, count,
- &cluster->cl_reconnect_delay_ms);
+ &to_o2nm_cluster(item)->cl_reconnect_delay_ms);
}
-static ssize_t o2nm_cluster_attr_fence_method_read(
- struct o2nm_cluster *cluster, char *page)
+static ssize_t o2nm_cluster_fence_method_show(
+ struct config_item *item, char *page)
{
+ struct o2nm_cluster *cluster = to_o2nm_cluster(item);
ssize_t ret = 0;
if (cluster)
@@ -595,8 +519,8 @@ static ssize_t o2nm_cluster_attr_fence_method_read(
return ret;
}
-static ssize_t o2nm_cluster_attr_fence_method_write(
- struct o2nm_cluster *cluster, const char *page, size_t count)
+static ssize_t o2nm_cluster_fence_method_store(
+ struct config_item *item, const char *page, size_t count)
{
unsigned int i;
@@ -608,10 +532,10 @@ static ssize_t o2nm_cluster_attr_fence_method_write(
continue;
if (strncasecmp(page, o2nm_fence_method_desc[i], count - 1))
continue;
- if (cluster->cl_fence_method != i) {
+ if (to_o2nm_cluster(item)->cl_fence_method != i) {
printk(KERN_INFO "ocfs2: Changing fence method to %s\n",
o2nm_fence_method_desc[i]);
- cluster->cl_fence_method = i;
+ to_o2nm_cluster(item)->cl_fence_method = i;
}
return count;
}
@@ -620,79 +544,18 @@ bail:
return -EINVAL;
}
-static struct o2nm_cluster_attribute o2nm_cluster_attr_idle_timeout_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "idle_timeout_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_cluster_attr_idle_timeout_ms_read,
- .store = o2nm_cluster_attr_idle_timeout_ms_write,
-};
-
-static struct o2nm_cluster_attribute o2nm_cluster_attr_keepalive_delay_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "keepalive_delay_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_cluster_attr_keepalive_delay_ms_read,
- .store = o2nm_cluster_attr_keepalive_delay_ms_write,
-};
-
-static struct o2nm_cluster_attribute o2nm_cluster_attr_reconnect_delay_ms = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "reconnect_delay_ms",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_cluster_attr_reconnect_delay_ms_read,
- .store = o2nm_cluster_attr_reconnect_delay_ms_write,
-};
-
-static struct o2nm_cluster_attribute o2nm_cluster_attr_fence_method = {
- .attr = { .ca_owner = THIS_MODULE,
- .ca_name = "fence_method",
- .ca_mode = S_IRUGO | S_IWUSR },
- .show = o2nm_cluster_attr_fence_method_read,
- .store = o2nm_cluster_attr_fence_method_write,
-};
+CONFIGFS_ATTR(o2nm_cluster_, idle_timeout_ms);
+CONFIGFS_ATTR(o2nm_cluster_, keepalive_delay_ms);
+CONFIGFS_ATTR(o2nm_cluster_, reconnect_delay_ms);
+CONFIGFS_ATTR(o2nm_cluster_, fence_method);
static struct configfs_attribute *o2nm_cluster_attrs[] = {
- &o2nm_cluster_attr_idle_timeout_ms.attr,
- &o2nm_cluster_attr_keepalive_delay_ms.attr,
- &o2nm_cluster_attr_reconnect_delay_ms.attr,
- &o2nm_cluster_attr_fence_method.attr,
+ &o2nm_cluster_attr_idle_timeout_ms,
+ &o2nm_cluster_attr_keepalive_delay_ms,
+ &o2nm_cluster_attr_reconnect_delay_ms,
+ &o2nm_cluster_attr_fence_method,
NULL,
};
-static ssize_t o2nm_cluster_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
-{
- struct o2nm_cluster *cluster = to_o2nm_cluster(item);
- struct o2nm_cluster_attribute *o2nm_cluster_attr =
- container_of(attr, struct o2nm_cluster_attribute, attr);
- ssize_t ret = 0;
-
- if (o2nm_cluster_attr->show)
- ret = o2nm_cluster_attr->show(cluster, page);
- return ret;
-}
-
-static ssize_t o2nm_cluster_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
-{
- struct o2nm_cluster *cluster = to_o2nm_cluster(item);
- struct o2nm_cluster_attribute *o2nm_cluster_attr =
- container_of(attr, struct o2nm_cluster_attribute, attr);
- ssize_t ret;
-
- if (o2nm_cluster_attr->store == NULL) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = o2nm_cluster_attr->store(cluster, page, count);
- if (ret < count)
- goto out;
-out:
- return ret;
-}
static struct config_item *o2nm_node_group_make_item(struct config_group *group,
const char *name)
@@ -773,8 +636,6 @@ static void o2nm_cluster_release(struct config_item *item)
static struct configfs_item_operations o2nm_cluster_item_ops = {
.release = o2nm_cluster_release,
- .show_attribute = o2nm_cluster_show,
- .store_attribute = o2nm_cluster_store,
};
static struct config_item_type o2nm_cluster_type = {
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index ce38b4c..84f2f80 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -2843,6 +2843,8 @@ again:
res->state &= ~DLM_LOCK_RES_BLOCK_DIRTY;
if (!ret)
BUG_ON(!(res->state & DLM_LOCK_RES_MIGRATING));
+ else
+ res->migration_pending = 0;
spin_unlock(&res->spinlock);
/*
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 8f87e05..97a563b 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -361,6 +361,7 @@ void ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
break;
case S_IFLNK:
inode->i_op = &ocfs2_symlink_inode_operations;
+ inode_nohighmem(inode);
i_size_write(inode, le64_to_cpu(fe->i_size));
break;
default:
diff --git a/fs/ocfs2/locks.c b/fs/ocfs2/locks.c
index 652ece4..d56f007 100644
--- a/fs/ocfs2/locks.c
+++ b/fs/ocfs2/locks.c
@@ -67,7 +67,10 @@ static int ocfs2_do_flock(struct file *file, struct inode *inode,
*/
locks_lock_file_wait(file,
- &(struct file_lock){.fl_type = F_UNLCK});
+ &(struct file_lock) {
+ .fl_type = F_UNLCK,
+ .fl_flags = FL_FLOCK
+ });
ocfs2_file_unlock(file);
}
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 3b48ac2..afb81ea 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -367,7 +367,7 @@ static int ocfs2_mknod(struct inode *dir,
goto leave;
}
- status = posix_acl_create(dir, &mode, &default_acl, &acl);
+ status = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
if (status) {
mlog_errno(status);
goto leave;
@@ -1958,6 +1958,7 @@ static int ocfs2_symlink(struct inode *dir,
inode->i_rdev = 0;
newsize = l - 1;
inode->i_op = &ocfs2_symlink_inode_operations;
+ inode_nohighmem(inode);
if (l > ocfs2_fast_symlink_chars(sb)) {
u32 offset = 0;
diff --git a/fs/ocfs2/resize.c b/fs/ocfs2/resize.c
index d5da6f6..79b8021 100644
--- a/fs/ocfs2/resize.c
+++ b/fs/ocfs2/resize.c
@@ -54,11 +54,12 @@
static u16 ocfs2_calc_new_backup_super(struct inode *inode,
struct ocfs2_group_desc *gd,
u16 cl_cpg,
+ u16 old_bg_clusters,
int set)
{
int i;
u16 backups = 0;
- u32 cluster;
+ u32 cluster, lgd_cluster;
u64 blkno, gd_blkno, lgd_blkno = le64_to_cpu(gd->bg_blkno);
for (i = 0; i < OCFS2_MAX_BACKUP_SUPERBLOCKS; i++) {
@@ -71,6 +72,12 @@ static u16 ocfs2_calc_new_backup_super(struct inode *inode,
else if (gd_blkno > lgd_blkno)
break;
+ /* check if already done backup super */
+ lgd_cluster = ocfs2_blocks_to_clusters(inode->i_sb, lgd_blkno);
+ lgd_cluster += old_bg_clusters;
+ if (lgd_cluster >= cluster)
+ continue;
+
if (set)
ocfs2_set_bit(cluster % cl_cpg,
(unsigned long *)gd->bg_bitmap);
@@ -99,6 +106,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
u16 chain, num_bits, backups = 0;
u16 cl_bpc = le16_to_cpu(cl->cl_bpc);
u16 cl_cpg = le16_to_cpu(cl->cl_cpg);
+ u16 old_bg_clusters;
trace_ocfs2_update_last_group_and_inode(new_clusters,
first_new_cluster);
@@ -112,6 +120,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
group = (struct ocfs2_group_desc *)group_bh->b_data;
+ old_bg_clusters = le16_to_cpu(group->bg_bits) / cl_bpc;
/* update the group first. */
num_bits = new_clusters * cl_bpc;
le16_add_cpu(&group->bg_bits, num_bits);
@@ -125,7 +134,7 @@ static int ocfs2_update_last_group_and_inode(handle_t *handle,
OCFS2_FEATURE_COMPAT_BACKUP_SB)) {
backups = ocfs2_calc_new_backup_super(bm_inode,
group,
- cl_cpg, 1);
+ cl_cpg, old_bg_clusters, 1);
le16_add_cpu(&group->bg_free_bits_count, -1 * backups);
}
@@ -163,7 +172,7 @@ out_rollback:
if (ret < 0) {
ocfs2_calc_new_backup_super(bm_inode,
group,
- cl_cpg, 0);
+ cl_cpg, old_bg_clusters, 0);
le16_add_cpu(&group->bg_free_bits_count, backups);
le16_add_cpu(&group->bg_bits, -1 * num_bits);
le16_add_cpu(&group->bg_free_bits_count, -1 * num_bits);
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 66edce7..6c2a3e3 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -88,8 +88,7 @@ const struct address_space_operations ocfs2_fast_symlink_aops = {
const struct inode_operations ocfs2_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.getattr = ocfs2_getattr,
.setattr = ocfs2_setattr,
.setxattr = generic_setxattr,
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index ebfdea7..f0e241f 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -544,8 +544,7 @@ static inline const char *ocfs2_xattr_prefix(int name_index)
if (name_index > 0 && name_index < OCFS2_XATTR_MAX)
handler = ocfs2_xattr_handler_map[name_index];
-
- return handler ? handler->prefix : NULL;
+ return handler ? xattr_prefix(handler) : NULL;
}
static u32 ocfs2_xattr_name_hash(struct inode *inode,
@@ -884,14 +883,39 @@ static int ocfs2_xattr_value_truncate(struct inode *inode,
return ret;
}
-static int ocfs2_xattr_list_entry(char *buffer, size_t size,
- size_t *result, const char *prefix,
+static int ocfs2_xattr_list_entry(struct super_block *sb,
+ char *buffer, size_t size,
+ size_t *result, int type,
const char *name, int name_len)
{
char *p = buffer + *result;
- int prefix_len = strlen(prefix);
- int total_len = prefix_len + name_len + 1;
+ const char *prefix;
+ int prefix_len;
+ int total_len;
+ switch(type) {
+ case OCFS2_XATTR_INDEX_USER:
+ if (OCFS2_SB(sb)->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
+ return 0;
+ break;
+
+ case OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS:
+ case OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT:
+ if (!(sb->s_flags & MS_POSIXACL))
+ return 0;
+ break;
+
+ case OCFS2_XATTR_INDEX_TRUSTED:
+ if (!capable(CAP_SYS_ADMIN))
+ return 0;
+ break;
+ }
+
+ prefix = ocfs2_xattr_prefix(type);
+ if (!prefix)
+ return 0;
+ prefix_len = strlen(prefix);
+ total_len = prefix_len + name_len + 1;
*result += total_len;
/* we are just looking for how big our buffer needs to be */
@@ -914,23 +938,20 @@ static int ocfs2_xattr_list_entries(struct inode *inode,
{
size_t result = 0;
int i, type, ret;
- const char *prefix, *name;
+ const char *name;
for (i = 0 ; i < le16_to_cpu(header->xh_count); i++) {
struct ocfs2_xattr_entry *entry = &header->xh_entries[i];
type = ocfs2_xattr_get_type(entry);
- prefix = ocfs2_xattr_prefix(type);
-
- if (prefix) {
- name = (const char *)header +
- le16_to_cpu(entry->xe_name_offset);
+ name = (const char *)header +
+ le16_to_cpu(entry->xe_name_offset);
- ret = ocfs2_xattr_list_entry(buffer, buffer_size,
- &result, prefix, name,
- entry->xe_name_len);
- if (ret)
- return ret;
- }
+ ret = ocfs2_xattr_list_entry(inode->i_sb,
+ buffer, buffer_size,
+ &result, type, name,
+ entry->xe_name_len);
+ if (ret)
+ return ret;
}
return result;
@@ -4033,32 +4054,30 @@ static int ocfs2_list_xattr_bucket(struct inode *inode,
int ret = 0, type;
struct ocfs2_xattr_tree_list *xl = (struct ocfs2_xattr_tree_list *)para;
int i, block_off, new_offset;
- const char *prefix, *name;
+ const char *name;
for (i = 0 ; i < le16_to_cpu(bucket_xh(bucket)->xh_count); i++) {
struct ocfs2_xattr_entry *entry = &bucket_xh(bucket)->xh_entries[i];
type = ocfs2_xattr_get_type(entry);
- prefix = ocfs2_xattr_prefix(type);
- if (prefix) {
- ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
- bucket_xh(bucket),
- i,
- &block_off,
- &new_offset);
- if (ret)
- break;
+ ret = ocfs2_xattr_bucket_get_name_value(inode->i_sb,
+ bucket_xh(bucket),
+ i,
+ &block_off,
+ &new_offset);
+ if (ret)
+ break;
- name = (const char *)bucket_block(bucket, block_off) +
- new_offset;
- ret = ocfs2_xattr_list_entry(xl->buffer,
- xl->buffer_size,
- &xl->result,
- prefix, name,
- entry->xe_name_len);
- if (ret)
- break;
- }
+ name = (const char *)bucket_block(bucket, block_off) +
+ new_offset;
+ ret = ocfs2_xattr_list_entry(inode->i_sb,
+ xl->buffer,
+ xl->buffer_size,
+ &xl->result,
+ type, name,
+ entry->xe_name_len);
+ if (ret)
+ break;
}
return ret;
@@ -7226,39 +7245,22 @@ int ocfs2_init_security_and_acl(struct inode *dir,
leave:
return ret;
}
+
/*
* 'security' attributes support
*/
-static size_t ocfs2_xattr_security_list(struct dentry *dentry, char *list,
- size_t list_size, const char *name,
- size_t name_len, int type)
-{
- const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(list + prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
-}
-
-static int ocfs2_xattr_security_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int ocfs2_xattr_security_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY,
name, buffer, size);
}
-static int ocfs2_xattr_security_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static int ocfs2_xattr_security_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_SECURITY,
name, value, size, flags);
}
@@ -7311,7 +7313,6 @@ int ocfs2_init_security_set(handle_t *handle,
const struct xattr_handler ocfs2_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = ocfs2_xattr_security_list,
.get = ocfs2_xattr_security_get,
.set = ocfs2_xattr_security_set,
};
@@ -7319,46 +7320,24 @@ const struct xattr_handler ocfs2_xattr_security_handler = {
/*
* 'trusted' attributes support
*/
-static size_t ocfs2_xattr_trusted_list(struct dentry *dentry, char *list,
- size_t list_size, const char *name,
- size_t name_len, int type)
-{
- const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (!capable(CAP_SYS_ADMIN))
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
- memcpy(list + prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
-}
-
-static int ocfs2_xattr_trusted_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int ocfs2_xattr_trusted_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED,
name, buffer, size);
}
-static int ocfs2_xattr_trusted_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static int ocfs2_xattr_trusted_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
return ocfs2_xattr_set(d_inode(dentry), OCFS2_XATTR_INDEX_TRUSTED,
name, value, size, flags);
}
const struct xattr_handler ocfs2_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
- .list = ocfs2_xattr_trusted_list,
.get = ocfs2_xattr_trusted_get,
.set = ocfs2_xattr_trusted_set,
};
@@ -7366,45 +7345,24 @@ const struct xattr_handler ocfs2_xattr_trusted_handler = {
/*
* 'user' attributes support
*/
-static size_t ocfs2_xattr_user_list(struct dentry *dentry, char *list,
- size_t list_size, const char *name,
- size_t name_len, int type)
-{
- const size_t prefix_len = XATTR_USER_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
- struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
-
- if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
- return 0;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_USER_PREFIX, prefix_len);
- memcpy(list + prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
- return total_len;
-}
-
-static int ocfs2_xattr_user_get(struct dentry *dentry, const char *name,
- void *buffer, size_t size, int type)
+static int ocfs2_xattr_user_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
return -EOPNOTSUPP;
return ocfs2_xattr_get(d_inode(dentry), OCFS2_XATTR_INDEX_USER, name,
buffer, size);
}
-static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+static int ocfs2_xattr_user_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
- if (strcmp(name, "") == 0)
- return -EINVAL;
if (osb->s_mount_opt & OCFS2_MOUNT_NOUSERXATTR)
return -EOPNOTSUPP;
@@ -7414,7 +7372,6 @@ static int ocfs2_xattr_user_set(struct dentry *dentry, const char *name,
const struct xattr_handler ocfs2_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
- .list = ocfs2_xattr_user_list,
.get = ocfs2_xattr_user_get,
.set = ocfs2_xattr_user_set,
};
diff --git a/fs/open.c b/fs/open.c
index b6f1e96..b25b154 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -887,7 +887,7 @@ EXPORT_SYMBOL(dentry_open);
static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
{
int lookup_flags = 0;
- int acc_mode;
+ int acc_mode = ACC_MODE(flags);
if (flags & (O_CREAT | __O_TMPFILE))
op->mode = (mode & S_IALLUGO) | S_IFREG;
@@ -909,7 +909,6 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
if (flags & __O_TMPFILE) {
if ((flags & O_TMPFILE_MASK) != O_TMPFILE)
return -EINVAL;
- acc_mode = MAY_OPEN | ACC_MODE(flags);
if (!(acc_mode & MAY_WRITE))
return -EINVAL;
} else if (flags & O_PATH) {
@@ -919,8 +918,6 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o
*/
flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
acc_mode = 0;
- } else {
- acc_mode = MAY_OPEN | ACC_MODE(flags);
}
op->open_flag = flags;
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 871fcb6..0a89834 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -195,8 +195,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
struct dentry *dentry, struct path *lowerpath,
- struct kstat *stat, struct iattr *attr,
- const char *link)
+ struct kstat *stat, const char *link)
{
struct inode *wdir = workdir->d_inode;
struct inode *udir = upperdir->d_inode;
@@ -240,8 +239,6 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
mutex_lock(&newdentry->d_inode->i_mutex);
err = ovl_set_attr(newdentry, stat);
- if (!err && attr)
- err = notify_change(newdentry, attr, NULL);
mutex_unlock(&newdentry->d_inode->i_mutex);
if (err)
goto out_cleanup;
@@ -286,8 +283,7 @@ out_cleanup:
* that point the file will have already been copied up anyway.
*/
int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
- struct path *lowerpath, struct kstat *stat,
- struct iattr *attr)
+ struct path *lowerpath, struct kstat *stat)
{
struct dentry *workdir = ovl_workdir(dentry);
int err;
@@ -345,26 +341,19 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
}
upperdentry = ovl_dentry_upper(dentry);
if (upperdentry) {
- unlock_rename(workdir, upperdir);
+ /* Raced with another copy-up? Nothing to do, then... */
err = 0;
- /* Raced with another copy-up? Do the setattr here */
- if (attr) {
- mutex_lock(&upperdentry->d_inode->i_mutex);
- err = notify_change(upperdentry, attr, NULL);
- mutex_unlock(&upperdentry->d_inode->i_mutex);
- }
- goto out_put_cred;
+ goto out_unlock;
}
err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
- stat, attr, link);
+ stat, link);
if (!err) {
/* Restore timestamps on parent (best effort) */
ovl_set_timestamps(upperdir, &pstat);
}
out_unlock:
unlock_rename(workdir, upperdir);
-out_put_cred:
revert_creds(old_cred);
put_cred(override_cred);
@@ -406,7 +395,7 @@ int ovl_copy_up(struct dentry *dentry)
ovl_path_lower(next, &lowerpath);
err = vfs_getattr(&lowerpath, &stat);
if (!err)
- err = ovl_copy_up_one(parent, next, &lowerpath, &stat, NULL);
+ err = ovl_copy_up_one(parent, next, &lowerpath, &stat);
dput(parent);
dput(next);
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index ec0c2a050..964a60f 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -12,8 +12,7 @@
#include <linux/xattr.h>
#include "overlayfs.h"
-static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr,
- bool no_data)
+static int ovl_copy_up_truncate(struct dentry *dentry)
{
int err;
struct dentry *parent;
@@ -30,10 +29,8 @@ static int ovl_copy_up_last(struct dentry *dentry, struct iattr *attr,
if (err)
goto out_dput_parent;
- if (no_data)
- stat.size = 0;
-
- err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat, attr);
+ stat.size = 0;
+ err = ovl_copy_up_one(parent, dentry, &lowerpath, &stat);
out_dput_parent:
dput(parent);
@@ -49,13 +46,13 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
if (err)
goto out;
- upperdentry = ovl_dentry_upper(dentry);
- if (upperdentry) {
+ err = ovl_copy_up(dentry);
+ if (!err) {
+ upperdentry = ovl_dentry_upper(dentry);
+
mutex_lock(&upperdentry->d_inode->i_mutex);
err = notify_change(upperdentry, attr, NULL);
mutex_unlock(&upperdentry->d_inode->i_mutex);
- } else {
- err = ovl_copy_up_last(dentry, attr, false);
}
ovl_drop_write(dentry);
out:
@@ -134,57 +131,23 @@ out_dput:
return err;
}
-
-struct ovl_link_data {
- struct dentry *realdentry;
- void *cookie;
-};
-
-static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
+static const char *ovl_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
struct dentry *realdentry;
struct inode *realinode;
- struct ovl_link_data *data = NULL;
- const char *ret;
+
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
realdentry = ovl_dentry_real(dentry);
realinode = realdentry->d_inode;
- if (WARN_ON(!realinode->i_op->follow_link))
+ if (WARN_ON(!realinode->i_op->get_link))
return ERR_PTR(-EPERM);
- if (realinode->i_op->put_link) {
- data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
- if (!data)
- return ERR_PTR(-ENOMEM);
- data->realdentry = realdentry;
- }
-
- ret = realinode->i_op->follow_link(realdentry, cookie);
- if (IS_ERR_OR_NULL(ret)) {
- kfree(data);
- return ret;
- }
-
- if (data)
- data->cookie = *cookie;
-
- *cookie = data;
-
- return ret;
-}
-
-static void ovl_put_link(struct inode *unused, void *c)
-{
- struct inode *realinode;
- struct ovl_link_data *data = c;
-
- if (!data)
- return;
-
- realinode = data->realdentry->d_inode;
- realinode->i_op->put_link(realinode, data->cookie);
- kfree(data);
+ return realinode->i_op->get_link(realdentry, realinode, done);
}
static int ovl_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
@@ -353,7 +316,7 @@ struct inode *ovl_d_select_inode(struct dentry *dentry, unsigned file_flags)
return ERR_PTR(err);
if (file_flags & O_TRUNC)
- err = ovl_copy_up_last(dentry, NULL, true);
+ err = ovl_copy_up_truncate(dentry);
else
err = ovl_copy_up(dentry);
ovl_drop_write(dentry);
@@ -381,8 +344,7 @@ static const struct inode_operations ovl_file_inode_operations = {
static const struct inode_operations ovl_symlink_inode_operations = {
.setattr = ovl_setattr,
- .follow_link = ovl_follow_link,
- .put_link = ovl_put_link,
+ .get_link = ovl_get_link,
.readlink = ovl_readlink,
.getattr = ovl_getattr,
.setxattr = ovl_setxattr,
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index ea5a40b..e17154a 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -194,7 +194,6 @@ void ovl_cleanup(struct inode *dir, struct dentry *dentry);
/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);
int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
- struct path *lowerpath, struct kstat *stat,
- struct iattr *attr);
+ struct path *lowerpath, struct kstat *stat);
int ovl_copy_xattr(struct dentry *old, struct dentry *new);
int ovl_set_attr(struct dentry *upper, struct kstat *stat);
diff --git a/fs/pipe.c b/fs/pipe.c
index 8865f79..42cf8dd 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -366,18 +366,17 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
int offset = buf->offset + buf->len;
if (ops->can_merge && offset + chars <= PAGE_SIZE) {
- int error = ops->confirm(pipe, buf);
- if (error)
+ ret = ops->confirm(pipe, buf);
+ if (ret)
goto out;
ret = copy_page_from_iter(buf->page, offset, chars, from);
if (unlikely(ret < chars)) {
- error = -EFAULT;
+ ret = -EFAULT;
goto out;
}
do_wakeup = 1;
- buf->len += chars;
- ret = chars;
+ buf->len += ret;
if (!iov_iter_count(from))
goto out;
}
@@ -693,17 +692,20 @@ int create_pipe_files(struct file **res, int flags)
d_instantiate(path.dentry, inode);
- err = -ENFILE;
f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops);
- if (IS_ERR(f))
+ if (IS_ERR(f)) {
+ err = PTR_ERR(f);
goto err_dentry;
+ }
f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT));
f->private_data = inode->i_pipe;
res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops);
- if (IS_ERR(res[0]))
+ if (IS_ERR(res[0])) {
+ err = PTR_ERR(res[0]);
goto err_file;
+ }
path_get(&path);
res[0]->private_data = inode->i_pipe;
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 4fb17de..711dd51 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -762,8 +762,9 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
EXPORT_SYMBOL (posix_acl_to_xattr);
static int
-posix_acl_xattr_get(struct dentry *dentry, const char *name,
- void *value, size_t size, int type)
+posix_acl_xattr_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *value, size_t size)
{
struct posix_acl *acl;
int error;
@@ -773,7 +774,7 @@ posix_acl_xattr_get(struct dentry *dentry, const char *name,
if (d_is_symlink(dentry))
return -EOPNOTSUPP;
- acl = get_acl(d_backing_inode(dentry), type);
+ acl = get_acl(d_backing_inode(dentry), handler->flags);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
@@ -786,8 +787,9 @@ posix_acl_xattr_get(struct dentry *dentry, const char *name,
}
static int
-posix_acl_xattr_set(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags, int type)
+posix_acl_xattr_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
struct inode *inode = d_backing_inode(dentry);
struct posix_acl *acl = NULL;
@@ -798,7 +800,7 @@ posix_acl_xattr_set(struct dentry *dentry, const char *name,
if (!inode->i_op->set_acl)
return -EOPNOTSUPP;
- if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+ if (handler->flags == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
return value ? -EACCES : 0;
if (!inode_owner_or_capable(inode))
return -EPERM;
@@ -815,37 +817,20 @@ posix_acl_xattr_set(struct dentry *dentry, const char *name,
}
}
- ret = inode->i_op->set_acl(inode, acl, type);
+ ret = inode->i_op->set_acl(inode, acl, handler->flags);
out:
posix_acl_release(acl);
return ret;
}
-static size_t
-posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
+static bool
+posix_acl_xattr_list(struct dentry *dentry)
{
- const char *xname;
- size_t size;
-
- if (!IS_POSIXACL(d_backing_inode(dentry)))
- return -EOPNOTSUPP;
- if (d_is_symlink(dentry))
- return -EOPNOTSUPP;
-
- if (type == ACL_TYPE_ACCESS)
- xname = POSIX_ACL_XATTR_ACCESS;
- else
- xname = POSIX_ACL_XATTR_DEFAULT;
-
- size = strlen(xname) + 1;
- if (list && size <= list_size)
- memcpy(list, xname, size);
- return size;
+ return IS_POSIXACL(d_backing_inode(dentry));
}
const struct xattr_handler posix_acl_access_xattr_handler = {
- .prefix = POSIX_ACL_XATTR_ACCESS,
+ .name = XATTR_NAME_POSIX_ACL_ACCESS,
.flags = ACL_TYPE_ACCESS,
.list = posix_acl_xattr_list,
.get = posix_acl_xattr_get,
@@ -854,7 +839,7 @@ const struct xattr_handler posix_acl_access_xattr_handler = {
EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
const struct xattr_handler posix_acl_default_xattr_handler = {
- .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .name = XATTR_NAME_POSIX_ACL_DEFAULT,
.flags = ACL_TYPE_DEFAULT,
.list = posix_acl_xattr_list,
.get = posix_acl_xattr_get,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index bd3e9e6..2cf5d7e 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -1564,12 +1564,16 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
return -ENOENT;
}
-static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_pid_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(dentry);
struct path path;
int error = -EACCES;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
/* Are we allowed to snoop on the tasks file descriptors? */
if (!proc_fd_access_allowed(inode))
goto out;
@@ -1630,7 +1634,7 @@ out:
const struct inode_operations proc_pid_link_inode_operations = {
.readlink = proc_pid_readlink,
- .follow_link = proc_pid_follow_link,
+ .get_link = proc_pid_get_link,
.setattr = proc_setattr,
};
@@ -1895,7 +1899,7 @@ static const struct dentry_operations tid_map_files_dentry_operations = {
.d_delete = pid_delete_dentry,
};
-static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
+static int map_files_get_link(struct dentry *dentry, struct path *path)
{
unsigned long vm_start, vm_end;
struct vm_area_struct *vma;
@@ -1945,20 +1949,22 @@ struct map_files_info {
* path to the file in question.
*/
static const char *
-proc_map_files_follow_link(struct dentry *dentry, void **cookie)
+proc_map_files_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
if (!capable(CAP_SYS_ADMIN))
return ERR_PTR(-EPERM);
- return proc_pid_follow_link(dentry, NULL);
+ return proc_pid_get_link(dentry, inode, done);
}
/*
- * Identical to proc_pid_link_inode_operations except for follow_link()
+ * Identical to proc_pid_link_inode_operations except for get_link()
*/
static const struct inode_operations proc_map_files_link_inode_operations = {
.readlink = proc_pid_readlink,
- .follow_link = proc_map_files_follow_link,
+ .get_link = proc_map_files_get_link,
.setattr = proc_setattr,
};
@@ -1975,7 +1981,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
return -ENOENT;
ei = PROC_I(inode);
- ei->op.proc_get_link = proc_map_files_get_link;
+ ei->op.proc_get_link = map_files_get_link;
inode->i_op = &proc_map_files_link_inode_operations;
inode->i_size = 64;
@@ -2359,7 +2365,7 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
struct inode * inode = file_inode(file);
- char *page;
+ void *page;
ssize_t length;
struct task_struct *task = get_proc_task(inode);
@@ -2374,14 +2380,11 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
if (*ppos != 0)
goto out;
- length = -ENOMEM;
- page = (char*)__get_free_page(GFP_TEMPORARY);
- if (!page)
+ page = memdup_user(buf, count);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
goto out;
-
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out_free;
+ }
/* Guard against adverse ptrace interaction */
length = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
@@ -2390,10 +2393,10 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
length = security_setprocattr(task,
(char*)file->f_path.dentry->d_name.name,
- (void*)page, count);
+ page, count);
mutex_unlock(&task->signal->cred_guard_mutex);
out_free:
- free_page((unsigned long) page);
+ kfree(page);
out:
put_task_struct(task);
out_no_task:
@@ -2494,6 +2497,7 @@ static ssize_t proc_coredump_filter_write(struct file *file,
mm = get_task_mm(task);
if (!mm)
goto out_no_mm;
+ ret = 0;
for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
if (val & mask)
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index 3c2a915..56afa5e 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -258,6 +258,7 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx,
name, len, instantiate, p,
(void *)(unsigned long)fd))
goto out_fd_loop;
+ cond_resched();
rcu_read_lock();
}
rcu_read_unlock();
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index bd95b9f..d0e9b9b 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -393,24 +393,25 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
};
#endif
-static const char *proc_follow_link(struct dentry *dentry, void **cookie)
+static void proc_put_link(void *p)
{
- struct proc_dir_entry *pde = PDE(d_inode(dentry));
- if (unlikely(!use_pde(pde)))
- return ERR_PTR(-EINVAL);
- *cookie = pde;
- return pde->data;
+ unuse_pde(p);
}
-static void proc_put_link(struct inode *unused, void *p)
+static const char *proc_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- unuse_pde(p);
+ struct proc_dir_entry *pde = PDE(inode);
+ if (unlikely(!use_pde(pde)))
+ return ERR_PTR(-EINVAL);
+ set_delayed_call(done, proc_put_link, pde);
+ return pde->data;
}
const struct inode_operations proc_link_inode_operations = {
.readlink = generic_readlink,
- .follow_link = proc_follow_link,
- .put_link = proc_put_link,
+ .get_link = proc_get_link,
};
struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de)
diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index f6e8354..1dece87 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -30,14 +30,18 @@ static const struct proc_ns_operations *ns_entries[] = {
&mntns_operations,
};
-static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_ns_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct inode *inode = d_inode(dentry);
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
struct task_struct *task;
struct path ns_path;
void *error = ERR_PTR(-EACCES);
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
task = get_proc_task(inode);
if (!task)
return error;
@@ -74,7 +78,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl
static const struct inode_operations proc_ns_link_inode_operations = {
.readlink = proc_ns_readlink,
- .follow_link = proc_ns_follow_link,
+ .get_link = proc_ns_get_link,
.setattr = proc_setattr,
};
diff --git a/fs/proc/self.c b/fs/proc/self.c
index 113b8d0..67e8db4 100644
--- a/fs/proc/self.c
+++ b/fs/proc/self.c
@@ -18,26 +18,28 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
return readlink_copy(buffer, buflen, tmp);
}
-static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_self_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+ struct pid_namespace *ns = inode->i_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
char *name;
if (!tgid)
return ERR_PTR(-ENOENT);
/* 11 for max length of signed int in decimal + NULL term */
- name = kmalloc(12, GFP_KERNEL);
- if (!name)
- return ERR_PTR(-ENOMEM);
+ name = kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC);
+ if (unlikely(!name))
+ return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
sprintf(name, "%d", tgid);
- return *cookie = name;
+ set_delayed_call(done, kfree_link, name);
+ return name;
}
static const struct inode_operations proc_self_inode_operations = {
.readlink = proc_self_readlink,
- .follow_link = proc_self_follow_link,
- .put_link = kfree_put_link,
+ .get_link = proc_self_get_link,
};
static unsigned self_inum;
diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c
index 947b0f4..9eacd59 100644
--- a/fs/proc/thread_self.c
+++ b/fs/proc/thread_self.c
@@ -19,26 +19,29 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
return readlink_copy(buffer, buflen, tmp);
}
-static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie)
+static const char *proc_thread_self_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct pid_namespace *ns = dentry->d_sb->s_fs_info;
+ struct pid_namespace *ns = inode->i_sb->s_fs_info;
pid_t tgid = task_tgid_nr_ns(current, ns);
pid_t pid = task_pid_nr_ns(current, ns);
char *name;
if (!pid)
return ERR_PTR(-ENOENT);
- name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
- if (!name)
- return ERR_PTR(-ENOMEM);
+ name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF,
+ dentry ? GFP_KERNEL : GFP_ATOMIC);
+ if (unlikely(!name))
+ return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD);
sprintf(name, "%d/task/%d", tgid, pid);
- return *cookie = name;
+ set_delayed_call(done, kfree_link, name);
+ return name;
}
static const struct inode_operations proc_thread_self_inode_operations = {
.readlink = proc_thread_self_readlink,
- .follow_link = proc_thread_self_follow_link,
- .put_link = kfree_put_link,
+ .get_link = proc_thread_self_get_link,
};
static unsigned thread_self_inum;
diff --git a/fs/proc_namespace.c b/fs/proc_namespace.c
index 8ebd9a3..2256e7e 100644
--- a/fs/proc_namespace.c
+++ b/fs/proc_namespace.c
@@ -95,9 +95,9 @@ static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt)
{
struct proc_mounts *p = m->private;
struct mount *r = real_mount(mnt);
- int err = 0;
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
struct super_block *sb = mnt_path.dentry->d_sb;
+ int err;
if (sb->s_op->show_devname) {
err = sb->s_op->show_devname(m, mnt_path.dentry);
@@ -131,16 +131,17 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
struct mount *r = real_mount(mnt);
struct super_block *sb = mnt->mnt_sb;
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
- int err = 0;
+ int err;
seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id,
MAJOR(sb->s_dev), MINOR(sb->s_dev));
- if (sb->s_op->show_path)
+ if (sb->s_op->show_path) {
err = sb->s_op->show_path(m, mnt->mnt_root);
- else
+ if (err)
+ goto out;
+ } else {
seq_dentry(m, mnt->mnt_root, " \t\n\\");
- if (err)
- goto out;
+ }
seq_putc(m, ' ');
/* mountpoints outside of chroot jail will give SEQ_SKIP on this */
@@ -168,12 +169,13 @@ static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt)
seq_puts(m, " - ");
show_type(m, sb);
seq_putc(m, ' ');
- if (sb->s_op->show_devname)
+ if (sb->s_op->show_devname) {
err = sb->s_op->show_devname(m, mnt->mnt_root);
- else
+ if (err)
+ goto out;
+ } else {
mangle(m, r->mnt_devname ? r->mnt_devname : "none");
- if (err)
- goto out;
+ }
seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
err = show_sb_opts(m, sb);
if (err)
@@ -191,7 +193,7 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
struct mount *r = real_mount(mnt);
struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
struct super_block *sb = mnt_path.dentry->d_sb;
- int err = 0;
+ int err;
/* device */
if (sb->s_op->show_devname) {
@@ -220,8 +222,7 @@ static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt)
/* optional statistics */
if (sb->s_op->show_stats) {
seq_putc(m, ' ');
- if (!err)
- err = sb->s_op->show_stats(m, mnt_path.dentry);
+ err = sb->s_op->show_stats(m, mnt_path.dentry);
}
seq_putc(m, '\n');
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index c4bcb77..f37b3de 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -316,6 +316,7 @@ struct inode *qnx4_iget(struct super_block *sb, unsigned long ino)
inode->i_fop = &qnx4_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &qnx4_aops;
qnx4_i(inode)->mmu_private = inode->i_size;
} else {
diff --git a/fs/qnx6/inode.c b/fs/qnx6/inode.c
index 32d2e1a..9728b54 100644
--- a/fs/qnx6/inode.c
+++ b/fs/qnx6/inode.c
@@ -582,6 +582,7 @@ struct inode *qnx6_iget(struct super_block *sb, unsigned ino)
inode->i_mapping->a_ops = &qnx6_aops;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &qnx6_aops;
} else
init_special_inode(inode, inode->i_mode, 0);
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 889d558..38981b0 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -79,6 +79,7 @@ struct inode *ramfs_get_inode(struct super_block *sb,
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
break;
}
}
diff --git a/fs/read_write.c b/fs/read_write.c
index 819ef3f..06b07d5 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -16,6 +16,7 @@
#include <linux/pagemap.h>
#include <linux/splice.h>
#include <linux/compat.h>
+#include <linux/mount.h>
#include "internal.h"
#include <asm/uaccess.h>
@@ -171,6 +172,45 @@ loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t si
EXPORT_SYMBOL(fixed_size_llseek);
/**
+ * no_seek_end_llseek - llseek implementation for fixed-sized devices
+ * @file: file structure to seek on
+ * @offset: file offset to seek to
+ * @whence: type of seek
+ *
+ */
+loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence)
+{
+ switch (whence) {
+ case SEEK_SET: case SEEK_CUR:
+ return generic_file_llseek_size(file, offset, whence,
+ ~0ULL, 0);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(no_seek_end_llseek);
+
+/**
+ * no_seek_end_llseek_size - llseek implementation for fixed-sized devices
+ * @file: file structure to seek on
+ * @offset: file offset to seek to
+ * @whence: type of seek
+ * @size: maximal offset allowed
+ *
+ */
+loff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size)
+{
+ switch (whence) {
+ case SEEK_SET: case SEEK_CUR:
+ return generic_file_llseek_size(file, offset, whence,
+ size, 0);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(no_seek_end_llseek_size);
+
+/**
* noop_llseek - No Operation Performed llseek implementation
* @file: file structure to seek on
* @offset: file offset to seek to
@@ -395,9 +435,8 @@ int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t
}
if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
- retval = locks_mandatory_area(
- read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
- inode, file, pos, count);
+ retval = locks_mandatory_area(inode, file, pos, pos + count - 1,
+ read_write == READ ? F_RDLCK : F_WRLCK);
if (retval < 0)
return retval;
}
@@ -1327,3 +1366,299 @@ COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd,
return do_sendfile(out_fd, in_fd, NULL, count, 0);
}
#endif
+
+/*
+ * copy_file_range() differs from regular file read and write in that it
+ * specifically allows return partial success. When it does so is up to
+ * the copy_file_range method.
+ */
+ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out,
+ size_t len, unsigned int flags)
+{
+ struct inode *inode_in = file_inode(file_in);
+ struct inode *inode_out = file_inode(file_out);
+ ssize_t ret;
+
+ if (flags != 0)
+ return -EINVAL;
+
+ /* copy_file_range allows full ssize_t len, ignoring MAX_RW_COUNT */
+ ret = rw_verify_area(READ, file_in, &pos_in, len);
+ if (ret >= 0)
+ ret = rw_verify_area(WRITE, file_out, &pos_out, len);
+ if (ret < 0)
+ return ret;
+
+ if (!(file_in->f_mode & FMODE_READ) ||
+ !(file_out->f_mode & FMODE_WRITE) ||
+ (file_out->f_flags & O_APPEND))
+ return -EBADF;
+
+ /* this could be relaxed once a method supports cross-fs copies */
+ if (inode_in->i_sb != inode_out->i_sb)
+ return -EXDEV;
+
+ if (len == 0)
+ return 0;
+
+ ret = mnt_want_write_file(file_out);
+ if (ret)
+ return ret;
+
+ ret = -EOPNOTSUPP;
+ if (file_out->f_op->copy_file_range)
+ ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out,
+ pos_out, len, flags);
+ if (ret == -EOPNOTSUPP)
+ ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out,
+ len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0);
+
+ if (ret > 0) {
+ fsnotify_access(file_in);
+ add_rchar(current, ret);
+ fsnotify_modify(file_out);
+ add_wchar(current, ret);
+ }
+ inc_syscr(current);
+ inc_syscw(current);
+
+ mnt_drop_write_file(file_out);
+
+ return ret;
+}
+EXPORT_SYMBOL(vfs_copy_file_range);
+
+SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in,
+ int, fd_out, loff_t __user *, off_out,
+ size_t, len, unsigned int, flags)
+{
+ loff_t pos_in;
+ loff_t pos_out;
+ struct fd f_in;
+ struct fd f_out;
+ ssize_t ret = -EBADF;
+
+ f_in = fdget(fd_in);
+ if (!f_in.file)
+ goto out2;
+
+ f_out = fdget(fd_out);
+ if (!f_out.file)
+ goto out1;
+
+ ret = -EFAULT;
+ if (off_in) {
+ if (copy_from_user(&pos_in, off_in, sizeof(loff_t)))
+ goto out;
+ } else {
+ pos_in = f_in.file->f_pos;
+ }
+
+ if (off_out) {
+ if (copy_from_user(&pos_out, off_out, sizeof(loff_t)))
+ goto out;
+ } else {
+ pos_out = f_out.file->f_pos;
+ }
+
+ ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len,
+ flags);
+ if (ret > 0) {
+ pos_in += ret;
+ pos_out += ret;
+
+ if (off_in) {
+ if (copy_to_user(off_in, &pos_in, sizeof(loff_t)))
+ ret = -EFAULT;
+ } else {
+ f_in.file->f_pos = pos_in;
+ }
+
+ if (off_out) {
+ if (copy_to_user(off_out, &pos_out, sizeof(loff_t)))
+ ret = -EFAULT;
+ } else {
+ f_out.file->f_pos = pos_out;
+ }
+ }
+
+out:
+ fdput(f_out);
+out1:
+ fdput(f_in);
+out2:
+ return ret;
+}
+
+static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write)
+{
+ struct inode *inode = file_inode(file);
+
+ if (unlikely(pos < 0))
+ return -EINVAL;
+
+ if (unlikely((loff_t) (pos + len) < 0))
+ return -EINVAL;
+
+ if (unlikely(inode->i_flctx && mandatory_lock(inode))) {
+ loff_t end = len ? pos + len - 1 : OFFSET_MAX;
+ int retval;
+
+ retval = locks_mandatory_area(inode, file, pos, end,
+ write ? F_WRLCK : F_RDLCK);
+ if (retval < 0)
+ return retval;
+ }
+
+ return security_file_permission(file, write ? MAY_WRITE : MAY_READ);
+}
+
+int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out, u64 len)
+{
+ struct inode *inode_in = file_inode(file_in);
+ struct inode *inode_out = file_inode(file_out);
+ int ret;
+
+ if (inode_in->i_sb != inode_out->i_sb ||
+ file_in->f_path.mnt != file_out->f_path.mnt)
+ return -EXDEV;
+
+ if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode))
+ return -EISDIR;
+ if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode))
+ return -EINVAL;
+
+ if (!(file_in->f_mode & FMODE_READ) ||
+ !(file_out->f_mode & FMODE_WRITE) ||
+ (file_out->f_flags & O_APPEND) ||
+ !file_in->f_op->clone_file_range)
+ return -EBADF;
+
+ ret = clone_verify_area(file_in, pos_in, len, false);
+ if (ret)
+ return ret;
+
+ ret = clone_verify_area(file_out, pos_out, len, true);
+ if (ret)
+ return ret;
+
+ if (pos_in + len > i_size_read(inode_in))
+ return -EINVAL;
+
+ ret = mnt_want_write_file(file_out);
+ if (ret)
+ return ret;
+
+ ret = file_in->f_op->clone_file_range(file_in, pos_in,
+ file_out, pos_out, len);
+ if (!ret) {
+ fsnotify_access(file_in);
+ fsnotify_modify(file_out);
+ }
+
+ mnt_drop_write_file(file_out);
+ return ret;
+}
+EXPORT_SYMBOL(vfs_clone_file_range);
+
+int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
+{
+ struct file_dedupe_range_info *info;
+ struct inode *src = file_inode(file);
+ u64 off;
+ u64 len;
+ int i;
+ int ret;
+ bool is_admin = capable(CAP_SYS_ADMIN);
+ u16 count = same->dest_count;
+ struct file *dst_file;
+ loff_t dst_off;
+ ssize_t deduped;
+
+ if (!(file->f_mode & FMODE_READ))
+ return -EINVAL;
+
+ if (same->reserved1 || same->reserved2)
+ return -EINVAL;
+
+ off = same->src_offset;
+ len = same->src_length;
+
+ ret = -EISDIR;
+ if (S_ISDIR(src->i_mode))
+ goto out;
+
+ ret = -EINVAL;
+ if (!S_ISREG(src->i_mode))
+ goto out;
+
+ ret = clone_verify_area(file, off, len, false);
+ if (ret < 0)
+ goto out;
+ ret = 0;
+
+ /* pre-format output fields to sane values */
+ for (i = 0; i < count; i++) {
+ same->info[i].bytes_deduped = 0ULL;
+ same->info[i].status = FILE_DEDUPE_RANGE_SAME;
+ }
+
+ for (i = 0, info = same->info; i < count; i++, info++) {
+ struct inode *dst;
+ struct fd dst_fd = fdget(info->dest_fd);
+
+ dst_file = dst_fd.file;
+ if (!dst_file) {
+ info->status = -EBADF;
+ goto next_loop;
+ }
+ dst = file_inode(dst_file);
+
+ ret = mnt_want_write_file(dst_file);
+ if (ret) {
+ info->status = ret;
+ goto next_loop;
+ }
+
+ dst_off = info->dest_offset;
+ ret = clone_verify_area(dst_file, dst_off, len, true);
+ if (ret < 0) {
+ info->status = ret;
+ goto next_file;
+ }
+ ret = 0;
+
+ if (info->reserved) {
+ info->status = -EINVAL;
+ } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
+ info->status = -EINVAL;
+ } else if (file->f_path.mnt != dst_file->f_path.mnt) {
+ info->status = -EXDEV;
+ } else if (S_ISDIR(dst->i_mode)) {
+ info->status = -EISDIR;
+ } else if (dst_file->f_op->dedupe_file_range == NULL) {
+ info->status = -EINVAL;
+ } else {
+ deduped = dst_file->f_op->dedupe_file_range(file, off,
+ len, dst_file,
+ info->dest_offset);
+ if (deduped == -EBADE)
+ info->status = FILE_DEDUPE_RANGE_DIFFERS;
+ else if (deduped < 0)
+ info->status = deduped;
+ else
+ info->bytes_deduped += deduped;
+ }
+
+next_file:
+ mnt_drop_write_file(dst_file);
+next_loop:
+ fdput(dst_fd);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(vfs_dedupe_file_range);
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 3d8e7e6..ae9e5b3 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -1361,6 +1361,7 @@ static void init_inode(struct inode *inode, struct treepath *path)
inode->i_fop = &reiserfs_dir_operations;
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &reiserfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &reiserfs_address_space_operations;
} else {
inode->i_blocks = 0;
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 9d6486d..44c2bdc 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -618,12 +618,10 @@ static void release_buffer_page(struct buffer_head *bh)
static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
{
- char b[BDEVNAME_SIZE];
-
if (buffer_journaled(bh)) {
reiserfs_warning(NULL, "clm-2084",
- "pinned buffer %lu:%s sent to disk",
- bh->b_blocknr, bdevname(bh->b_bdev, b));
+ "pinned buffer %lu:%pg sent to disk",
+ bh->b_blocknr, bh->b_bdev);
}
if (uptodate)
set_buffer_uptodate(bh);
@@ -2387,11 +2385,10 @@ static int journal_read(struct super_block *sb)
int replay_count = 0;
int continue_replay = 1;
int ret;
- char b[BDEVNAME_SIZE];
cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(sb);
- reiserfs_info(sb, "checking transaction log (%s)\n",
- bdevname(journal->j_dev_bd, b));
+ reiserfs_info(sb, "checking transaction log (%pg)\n",
+ journal->j_dev_bd);
start = get_seconds();
/*
@@ -2651,8 +2648,8 @@ static int journal_init_dev(struct super_block *super,
set_blocksize(journal->j_dev_bd, super->s_blocksize);
reiserfs_info(super,
- "journal_init_dev: journal device: %s\n",
- bdevname(journal->j_dev_bd, b));
+ "journal_init_dev: journal device: %pg\n",
+ journal->j_dev_bd);
return 0;
}
@@ -2724,7 +2721,6 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
struct reiserfs_journal_header *jh;
struct reiserfs_journal *journal;
struct reiserfs_journal_list *jl;
- char b[BDEVNAME_SIZE];
int ret;
journal = SB_JOURNAL(sb) = vzalloc(sizeof(struct reiserfs_journal));
@@ -2794,10 +2790,10 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
&& (le32_to_cpu(jh->jh_journal.jp_journal_magic) !=
sb_jp_journal_magic(rs))) {
reiserfs_warning(sb, "sh-460",
- "journal header magic %x (device %s) does "
+ "journal header magic %x (device %pg) does "
"not match to magic found in super block %x",
jh->jh_journal.jp_journal_magic,
- bdevname(journal->j_dev_bd, b),
+ journal->j_dev_bd,
sb_jp_journal_magic(rs));
brelse(bhjh);
goto free_and_return;
@@ -2818,10 +2814,10 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
journal->j_max_trans_age = commit_max_age;
}
- reiserfs_info(sb, "journal params: device %s, size %u, "
+ reiserfs_info(sb, "journal params: device %pg, size %u, "
"journal first block %u, max trans len %u, max batch %u, "
"max commit age %u, max trans age %u\n",
- bdevname(journal->j_dev_bd, b),
+ journal->j_dev_bd,
SB_ONDISK_JOURNAL_SIZE(sb),
SB_ONDISK_JOURNAL_1st_BLOCK(sb),
journal->j_trans_max,
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 47f9698..2a12d46 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1170,6 +1170,7 @@ static int reiserfs_symlink(struct inode *parent_dir,
reiserfs_update_inode_transaction(parent_dir);
inode->i_op = &reiserfs_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &reiserfs_address_space_operations;
retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name,
@@ -1664,8 +1665,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
*/
const struct inode_operations reiserfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.setattr = reiserfs_setattr,
.setxattr = reiserfs_setxattr,
.getxattr = reiserfs_getxattr,
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index ae1dc84..4f3f928 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -139,11 +139,9 @@ static void sprintf_block_head(char *buf, struct buffer_head *bh)
static void sprintf_buffer_head(char *buf, struct buffer_head *bh)
{
- char b[BDEVNAME_SIZE];
-
sprintf(buf,
- "dev %s, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
- bdevname(bh->b_bdev, b), bh->b_size,
+ "dev %pg, size %zd, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+ bh->b_bdev, bh->b_size,
(unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
bh->b_state, bh->b_page,
buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
@@ -530,7 +528,6 @@ static int print_super_block(struct buffer_head *bh)
(struct reiserfs_super_block *)(bh->b_data);
int skipped, data_blocks;
char *version;
- char b[BDEVNAME_SIZE];
if (is_reiserfs_3_5(rs)) {
version = "3.5";
@@ -543,7 +540,7 @@ static int print_super_block(struct buffer_head *bh)
return 1;
}
- printk("%s\'s super block is in block %llu\n", bdevname(bh->b_bdev, b),
+ printk("%pg\'s super block is in block %llu\n", bh->b_bdev,
(unsigned long long)bh->b_blocknr);
printk("Reiserfs version %s\n", version);
printk("Block count %u\n", sb_block_count(rs));
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 621b9f3..fe99915 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -303,11 +303,10 @@ static int show_journal(struct seq_file *m, void *unused)
struct reiserfs_sb_info *r = REISERFS_SB(sb);
struct reiserfs_super_block *rs = r->s_rs;
struct journal_params *jp = &rs->s_v1.s_journal;
- char b[BDEVNAME_SIZE];
seq_printf(m, /* on-disk fields */
"jp_journal_1st_block: \t%i\n"
- "jp_journal_dev: \t%s[%x]\n"
+ "jp_journal_dev: \t%pg[%x]\n"
"jp_journal_size: \t%i\n"
"jp_journal_trans_max: \t%i\n"
"jp_journal_magic: \t%i\n"
@@ -348,7 +347,7 @@ static int show_journal(struct seq_file *m, void *unused)
"prepare: \t%12lu\n"
"prepare_retry: \t%12lu\n",
DJP(jp_journal_1st_block),
- bdevname(SB_JOURNAL(sb)->j_dev_bd, b),
+ SB_JOURNAL(sb)->j_dev_bd,
DJP(jp_journal_dev),
DJP(jp_journal_size),
DJP(jp_journal_trans_max),
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index e87f9b5..e5ddb4e 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -756,7 +756,8 @@ find_xattr_handler_prefix(const struct xattr_handler **handlers,
return NULL;
for_each_xattr_handler(handlers, xah) {
- if (strncmp(xah->prefix, name, strlen(xah->prefix)) == 0)
+ const char *prefix = xattr_prefix(xah);
+ if (strncmp(prefix, name, strlen(prefix)) == 0)
break;
}
@@ -778,7 +779,7 @@ reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->get(dentry, name, buffer, size, handler->flags);
+ return handler->get(handler, dentry, name, buffer, size);
}
/*
@@ -797,7 +798,7 @@ reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->set(dentry, name, value, size, flags, handler->flags);
+ return handler->set(handler, dentry, name, value, size, flags);
}
/*
@@ -814,7 +815,7 @@ int reiserfs_removexattr(struct dentry *dentry, const char *name)
if (!handler || get_inode_sd_version(d_inode(dentry)) == STAT_DATA_V1)
return -EOPNOTSUPP;
- return handler->set(dentry, name, NULL, 0, XATTR_REPLACE, handler->flags);
+ return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
}
struct listxattr_buf {
@@ -839,19 +840,16 @@ static int listxattr_filler(struct dir_context *ctx, const char *name,
handler = find_xattr_handler_prefix(b->dentry->d_sb->s_xattr,
name);
- if (!handler) /* Unsupported xattr name */
+ if (!handler /* Unsupported xattr name */ ||
+ (handler->list && !handler->list(b->dentry)))
return 0;
+ size = namelen + 1;
if (b->buf) {
- size = handler->list(b->dentry, b->buf + b->pos,
- b->size, name, namelen,
- handler->flags);
if (size > b->size)
return -ERANGE;
- } else {
- size = handler->list(b->dentry, NULL, 0, name,
- namelen, handler->flags);
+ memcpy(b->buf + b->pos, name, namelen);
+ b->buf[b->pos + namelen] = 0;
}
-
b->pos += size;
}
return 0;
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index 4b34b9d..558a16b 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -186,10 +186,10 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
break;
default:
BUG();
@@ -244,7 +244,7 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
switch (type) {
case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
+ name = XATTR_NAME_POSIX_ACL_ACCESS;
if (acl) {
error = posix_acl_equiv_mode(acl, &inode->i_mode);
if (error < 0)
@@ -256,7 +256,7 @@ __reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
}
break;
case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
+ name = XATTR_NAME_POSIX_ACL_DEFAULT;
if (!S_ISDIR(inode->i_mode))
return acl ? -EACCES : 0;
break;
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c
index 9a3b061..ab0217d 100644
--- a/fs/reiserfs/xattr_security.c
+++ b/fs/reiserfs/xattr_security.c
@@ -9,8 +9,8 @@
#include <linux/uaccess.h>
static int
-security_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
- int handler_flags)
+security_get(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL;
@@ -22,8 +22,8 @@ security_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
}
static int
-security_set(struct dentry *dentry, const char *name, const void *buffer,
- size_t size, int flags, int handler_flags)
+security_set(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, const void *buffer, size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
return -EINVAL;
@@ -34,20 +34,9 @@ security_set(struct dentry *dentry, const char *name, const void *buffer,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
-static size_t security_list(struct dentry *dentry, char *list, size_t list_len,
- const char *name, size_t namelen, int handler_flags)
+static bool security_list(struct dentry *dentry)
{
- const size_t len = namelen + 1;
-
- if (IS_PRIVATE(d_inode(dentry)))
- return 0;
-
- if (list && len <= list_len) {
- memcpy(list, name, namelen);
- list[namelen] = '\0';
- }
-
- return len;
+ return !IS_PRIVATE(d_inode(dentry));
}
/* Initializes the security context for a new inode and returns the number
diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c
index e4f1343..64b67aa 100644
--- a/fs/reiserfs/xattr_trusted.c
+++ b/fs/reiserfs/xattr_trusted.c
@@ -8,8 +8,8 @@
#include <linux/uaccess.h>
static int
-trusted_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
- int handler_flags)
+trusted_get(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL;
@@ -21,8 +21,8 @@ trusted_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
}
static int
-trusted_set(struct dentry *dentry, const char *name, const void *buffer,
- size_t size, int flags, int handler_flags)
+trusted_set(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, const void *buffer, size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
return -EINVAL;
@@ -33,19 +33,9 @@ trusted_set(struct dentry *dentry, const char *name, const void *buffer,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
-static size_t trusted_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int handler_flags)
+static bool trusted_list(struct dentry *dentry)
{
- const size_t len = name_len + 1;
-
- if (!capable(CAP_SYS_ADMIN) || IS_PRIVATE(d_inode(dentry)))
- return 0;
-
- if (list && len <= list_size) {
- memcpy(list, name, name_len);
- list[name_len] = '\0';
- }
- return len;
+ return capable(CAP_SYS_ADMIN) && !IS_PRIVATE(d_inode(dentry));
}
const struct xattr_handler reiserfs_xattr_trusted_handler = {
diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c
index d0b08d3..12e6306 100644
--- a/fs/reiserfs/xattr_user.c
+++ b/fs/reiserfs/xattr_user.c
@@ -7,8 +7,8 @@
#include <linux/uaccess.h>
static int
-user_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
- int handler_flags)
+user_get(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, void *buffer, size_t size)
{
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
@@ -19,8 +19,8 @@ user_get(struct dentry *dentry, const char *name, void *buffer, size_t size,
}
static int
-user_set(struct dentry *dentry, const char *name, const void *buffer,
- size_t size, int flags, int handler_flags)
+user_set(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, const void *buffer, size_t size, int flags)
{
if (strlen(name) < sizeof(XATTR_USER_PREFIX))
return -EINVAL;
@@ -30,18 +30,9 @@ user_set(struct dentry *dentry, const char *name, const void *buffer,
return reiserfs_xattr_set(d_inode(dentry), name, buffer, size, flags);
}
-static size_t user_list(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int handler_flags)
+static bool user_list(struct dentry *dentry)
{
- const size_t len = name_len + 1;
-
- if (!reiserfs_xattrs_user(dentry->d_sb))
- return 0;
- if (list && len <= list_size) {
- memcpy(list, name, name_len);
- list[name_len] = '\0';
- }
- return len;
+ return reiserfs_xattrs_user(dentry->d_sb);
}
const struct xattr_handler reiserfs_xattr_user_handler = {
diff --git a/fs/romfs/super.c b/fs/romfs/super.c
index 268733c..bb894e7 100644
--- a/fs/romfs/super.c
+++ b/fs/romfs/super.c
@@ -360,6 +360,7 @@ static struct inode *romfs_iget(struct super_block *sb, unsigned long pos)
break;
case ROMFH_SYM:
i->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(i);
i->i_data.a_ops = &romfs_aops;
mode |= S_IRWXUGO;
break;
diff --git a/fs/select.c b/fs/select.c
index 0155473..79d0d49 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -778,8 +778,8 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait,
return mask;
}
-static int do_poll(unsigned int nfds, struct poll_list *list,
- struct poll_wqueues *wait, struct timespec *end_time)
+static int do_poll(struct poll_list *list, struct poll_wqueues *wait,
+ struct timespec *end_time)
{
poll_table* pt = &wait->pt;
ktime_t expire, *to = NULL;
@@ -908,7 +908,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds,
}
poll_initwait(&table);
- fdcount = do_poll(nfds, head, &table, end_time);
+ fdcount = do_poll(head, &table, end_time);
poll_freewait(&table);
for (walk = head; walk; walk = walk->next) {
diff --git a/fs/splice.c b/fs/splice.c
index 801c21c..82bc0d6 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -415,6 +415,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
*/
if (!page->mapping) {
unlock_page(page);
+retry_lookup:
page = find_or_create_page(mapping, index,
mapping_gfp_mask(mapping));
@@ -439,13 +440,10 @@ __generic_file_splice_read(struct file *in, loff_t *ppos,
error = mapping->a_ops->readpage(in, page);
if (unlikely(error)) {
/*
- * We really should re-lookup the page here,
- * but it complicates things a lot. Instead
- * lets just do what we already stored, and
- * we'll get it the next time we are called.
+ * Re-lookup the page
*/
if (error == AOP_TRUNCATED_PAGE)
- error = 0;
+ goto retry_lookup;
break;
}
@@ -809,6 +807,13 @@ static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_des
*/
static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd)
{
+ /*
+ * Check for signal early to make process killable when there are
+ * always buffers available
+ */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
while (!pipe->nrbufs) {
if (!pipe->writers)
return 0;
@@ -884,6 +889,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd,
splice_from_pipe_begin(sd);
do {
+ cond_resched();
ret = splice_from_pipe_next(pipe, sd);
if (ret > 0)
ret = splice_from_pipe_feed(pipe, sd, actor);
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index a1ce5ce..0927b1e 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -41,6 +41,7 @@
#include <linux/fs.h>
#include <linux/vfs.h>
#include <linux/xattr.h>
+#include <linux/pagemap.h>
#include "squashfs_fs.h"
#include "squashfs_fs_sb.h"
@@ -291,6 +292,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
set_nlink(inode, le32_to_cpu(sqsh_ino->nlink));
inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
inode->i_op = &squashfs_symlink_inode_ops;
+ inode_nohighmem(inode);
inode->i_data.a_ops = &squashfs_symlink_aops;
inode->i_mode |= S_IFLNK;
squashfs_i(inode)->start = block;
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c
index 5056bab..dded920 100644
--- a/fs/squashfs/super.c
+++ b/fs/squashfs/super.c
@@ -80,7 +80,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct squashfs_sb_info *msblk;
struct squashfs_super_block *sblk = NULL;
- char b[BDEVNAME_SIZE];
struct inode *root;
long long root_inode;
unsigned short flags;
@@ -124,8 +123,8 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_magic = le32_to_cpu(sblk->s_magic);
if (sb->s_magic != SQUASHFS_MAGIC) {
if (!silent)
- ERROR("Can't find a SQUASHFS superblock on %s\n",
- bdevname(sb->s_bdev, b));
+ ERROR("Can't find a SQUASHFS superblock on %pg\n",
+ sb->s_bdev);
goto failed_mount;
}
@@ -178,7 +177,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
msblk->inodes = le32_to_cpu(sblk->inodes);
flags = le16_to_cpu(sblk->flags);
- TRACE("Found valid superblock on %s\n", bdevname(sb->s_bdev, b));
+ TRACE("Found valid superblock on %pg\n", sb->s_bdev);
TRACE("Inodes are %scompressed\n", SQUASHFS_UNCOMPRESSED_INODES(flags)
? "un" : "");
TRACE("Data is %scompressed\n", SQUASHFS_UNCOMPRESSED_DATA(flags)
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index 12806df..dbcc2f5 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -119,8 +119,7 @@ const struct address_space_operations squashfs_symlink_aops = {
const struct inode_operations squashfs_symlink_inode_ops = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.getxattr = generic_getxattr,
.listxattr = squashfs_listxattr
};
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c
index e5e0ddf..1e9de96 100644
--- a/fs/squashfs/xattr.c
+++ b/fs/squashfs/xattr.c
@@ -58,7 +58,7 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
struct squashfs_xattr_entry entry;
struct squashfs_xattr_val val;
const struct xattr_handler *handler;
- int name_size, prefix_size = 0;
+ int name_size;
err = squashfs_read_metadata(sb, &entry, &start, &offset,
sizeof(entry));
@@ -67,15 +67,16 @@ ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
name_size = le16_to_cpu(entry.size);
handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
- if (handler)
- prefix_size = handler->list(d, buffer, rest, NULL,
- name_size, handler->flags);
- if (prefix_size) {
+ if (handler && (!handler->list || handler->list(d))) {
+ const char *prefix = handler->prefix ?: handler->name;
+ size_t prefix_size = strlen(prefix);
+
if (buffer) {
if (prefix_size + name_size + 1 > rest) {
err = -ERANGE;
goto failed;
}
+ memcpy(buffer, prefix, prefix_size);
buffer += prefix_size;
}
err = squashfs_read_metadata(sb, buffer, &start,
@@ -212,88 +213,45 @@ failed:
}
-/*
- * User namespace support
- */
-static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size,
- const char *name, size_t name_len, int type)
-{
- if (list && XATTR_USER_PREFIX_LEN <= list_size)
- memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
- return XATTR_USER_PREFIX_LEN;
-}
-
-static int squashfs_user_get(struct dentry *d, const char *name, void *buffer,
- size_t size, int type)
+static int squashfs_xattr_handler_get(const struct xattr_handler *handler,
+ struct dentry *d, const char *name,
+ void *buffer, size_t size)
{
- if (name[0] == '\0')
- return -EINVAL;
-
- return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_USER, name,
+ return squashfs_xattr_get(d_inode(d), handler->flags, name,
buffer, size);
}
+/*
+ * User namespace support
+ */
static const struct xattr_handler squashfs_xattr_user_handler = {
.prefix = XATTR_USER_PREFIX,
- .list = squashfs_user_list,
- .get = squashfs_user_get
+ .flags = SQUASHFS_XATTR_USER,
+ .get = squashfs_xattr_handler_get
};
/*
* Trusted namespace support
*/
-static size_t squashfs_trusted_list(struct dentry *d, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
+static bool squashfs_trusted_xattr_handler_list(struct dentry *d)
{
- if (!capable(CAP_SYS_ADMIN))
- return 0;
-
- if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size)
- memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
- return XATTR_TRUSTED_PREFIX_LEN;
-}
-
-static int squashfs_trusted_get(struct dentry *d, const char *name,
- void *buffer, size_t size, int type)
-{
- if (name[0] == '\0')
- return -EINVAL;
-
- return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_TRUSTED, name,
- buffer, size);
+ return capable(CAP_SYS_ADMIN);
}
static const struct xattr_handler squashfs_xattr_trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
- .list = squashfs_trusted_list,
- .get = squashfs_trusted_get
+ .flags = SQUASHFS_XATTR_TRUSTED,
+ .list = squashfs_trusted_xattr_handler_list,
+ .get = squashfs_xattr_handler_get
};
/*
* Security namespace support
*/
-static size_t squashfs_security_list(struct dentry *d, char *list,
- size_t list_size, const char *name, size_t name_len, int type)
-{
- if (list && XATTR_SECURITY_PREFIX_LEN <= list_size)
- memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
- return XATTR_SECURITY_PREFIX_LEN;
-}
-
-static int squashfs_security_get(struct dentry *d, const char *name,
- void *buffer, size_t size, int type)
-{
- if (name[0] == '\0')
- return -EINVAL;
-
- return squashfs_xattr_get(d_inode(d), SQUASHFS_XATTR_SECURITY, name,
- buffer, size);
-}
-
static const struct xattr_handler squashfs_xattr_security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
- .list = squashfs_security_list,
- .get = squashfs_security_get
+ .flags = SQUASHFS_XATTR_SECURITY,
+ .get = squashfs_xattr_handler_get
};
static const struct xattr_handler *squashfs_xattr_handler(int type)
diff --git a/fs/super.c b/fs/super.c
index 954aeb8..cc658a2 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -1012,10 +1012,8 @@ struct dentry *mount_bdev(struct file_system_type *fs_type,
blkdev_put(bdev, mode);
down_write(&s->s_umount);
} else {
- char b[BDEVNAME_SIZE];
-
s->s_mode = mode;
- strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
+ snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev);
sb_set_blocksize(s, block_size(bdev));
error = fill_super(s, data, flags & MS_SILENT ? 1 : 0);
if (error) {
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index e123659..dc1358b 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -73,13 +73,26 @@ static int create_files(struct kernfs_node *parent, struct kobject *kobj,
}
if (grp->bin_attrs) {
- for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) {
+ for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) {
+ umode_t mode = (*bin_attr)->attr.mode;
+
if (update)
kernfs_remove_by_name(parent,
(*bin_attr)->attr.name);
+ if (grp->is_bin_visible) {
+ mode = grp->is_bin_visible(kobj, *bin_attr, i);
+ if (!mode)
+ continue;
+ }
+
+ WARN(mode & ~(SYSFS_PREALLOC | 0664),
+ "Attribute %s: Invalid permissions 0%o\n",
+ (*bin_attr)->attr.name, mode);
+
+ mode &= SYSFS_PREALLOC | 0664;
error = sysfs_add_file_mode_ns(parent,
&(*bin_attr)->attr, true,
- (*bin_attr)->attr.mode, NULL);
+ mode, NULL);
if (error)
break;
}
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 590ad92..07ac18c 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -146,8 +146,7 @@ static inline void write3byte(struct sysv_sb_info *sbi,
static const struct inode_operations sysv_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
+ .get_link = page_get_link,
.getattr = sysv_getattr,
};
@@ -162,15 +161,9 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
inode->i_fop = &sysv_dir_operations;
inode->i_mapping->a_ops = &sysv_aops;
} else if (S_ISLNK(inode->i_mode)) {
- if (inode->i_blocks) {
- inode->i_op = &sysv_symlink_inode_operations;
- inode->i_mapping->a_ops = &sysv_aops;
- } else {
- inode->i_op = &simple_symlink_inode_operations;
- inode->i_link = (char *)SYSV_I(inode)->i_data;
- nd_terminate_link(inode->i_link, inode->i_size,
- sizeof(SYSV_I(inode)->i_data) - 1);
- }
+ inode->i_op = &sysv_symlink_inode_operations;
+ inode_nohighmem(inode);
+ inode->i_mapping->a_ops = &sysv_aops;
} else
init_special_inode(inode, inode->i_mode, rdev);
}
diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig
index ba66d50..7ff7712 100644
--- a/fs/ubifs/Kconfig
+++ b/fs/ubifs/Kconfig
@@ -35,3 +35,18 @@ config UBIFS_FS_ZLIB
default y
help
Zlib compresses better than LZO but it is slower. Say 'Y' if unsure.
+
+config UBIFS_ATIME_SUPPORT
+ bool "Access time support" if UBIFS_FS
+ depends on UBIFS_FS
+ default n
+ help
+ Originally UBIFS did not support atime, because it looked like a bad idea due
+ increased flash wear. This option adds atime support and it is disabled by default
+ to preserve the old behavior. If you enable this option, UBIFS starts updating atime,
+ which means that file-system read operations will cause writes (inode atime
+ updates). This may affect file-system performance and increase flash device wear,
+ so be careful. How often atime is updated depends on the selected strategy:
+ strictatime is the "heavy", relatime is "lighter", etc.
+
+ If unsure, say 'N'
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 4c46a98..595ca0d 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -2573,7 +2573,7 @@ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
{
int err, failing;
- if (c->dbg->pc_happened)
+ if (dbg_is_power_cut(c))
return -EROFS;
failing = power_cut_emulated(c, lnum, 1);
@@ -2595,7 +2595,7 @@ int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
{
int err;
- if (c->dbg->pc_happened)
+ if (dbg_is_power_cut(c))
return -EROFS;
if (power_cut_emulated(c, lnum, 1))
return -EROFS;
@@ -2611,7 +2611,7 @@ int dbg_leb_unmap(struct ubifs_info *c, int lnum)
{
int err;
- if (c->dbg->pc_happened)
+ if (dbg_is_power_cut(c))
return -EROFS;
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
@@ -2627,7 +2627,7 @@ int dbg_leb_map(struct ubifs_info *c, int lnum)
{
int err;
- if (c->dbg->pc_happened)
+ if (dbg_is_power_cut(c))
return -EROFS;
if (power_cut_emulated(c, lnum, 0))
return -EROFS;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 5c27c66..e49bd28 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -449,13 +449,14 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
}
out:
+ kfree(file->private_data);
+ file->private_data = NULL;
+
if (err != -ENOENT) {
ubifs_err(c, "cannot find next direntry, error %d", err);
return err;
}
- kfree(file->private_data);
- file->private_data = NULL;
/* 2 is a special value indicating that there are no more direntries */
ctx->pos = 2;
return 0;
@@ -787,9 +788,6 @@ static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
dbg_gen("dent '%pd' in dir ino %lu", dentry, dir->i_ino);
- if (!new_valid_dev(rdev))
- return -EINVAL;
-
if (S_ISBLK(mode) || S_ISCHR(mode)) {
dev = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS);
if (!dev)
@@ -1188,6 +1186,9 @@ const struct inode_operations ubifs_dir_inode_operations = {
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ .update_time = ubifs_update_time,
+#endif
};
const struct file_operations ubifs_dir_operations = {
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index a3dfe2a..eff6280 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1354,6 +1354,47 @@ static inline int mctime_update_needed(const struct inode *inode,
return 0;
}
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+/**
+ * ubifs_update_time - update time of inode.
+ * @inode: inode to update
+ *
+ * This function updates time of the inode.
+ */
+int ubifs_update_time(struct inode *inode, struct timespec *time,
+ int flags)
+{
+ struct ubifs_inode *ui = ubifs_inode(inode);
+ struct ubifs_info *c = inode->i_sb->s_fs_info;
+ struct ubifs_budget_req req = { .dirtied_ino = 1,
+ .dirtied_ino_d = ALIGN(ui->data_len, 8) };
+ int iflags = I_DIRTY_TIME;
+ int err, release;
+
+ err = ubifs_budget_space(c, &req);
+ if (err)
+ return err;
+
+ mutex_lock(&ui->ui_mutex);
+ if (flags & S_ATIME)
+ inode->i_atime = *time;
+ if (flags & S_CTIME)
+ inode->i_ctime = *time;
+ if (flags & S_MTIME)
+ inode->i_mtime = *time;
+
+ if (!(inode->i_sb->s_flags & MS_LAZYTIME))
+ iflags |= I_DIRTY_SYNC;
+
+ release = ui->dirty;
+ __mark_inode_dirty(inode, iflags);
+ mutex_unlock(&ui->ui_mutex);
+ if (release)
+ ubifs_release_budget(c, &req);
+ return 0;
+}
+#endif
+
/**
* update_ctime - update mtime and ctime of an inode.
* @inode: inode to update
@@ -1537,6 +1578,9 @@ static int ubifs_file_mmap(struct file *file, struct vm_area_struct *vma)
if (err)
return err;
vma->vm_ops = &ubifs_file_vm_ops;
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ file_accessed(file);
+#endif
return 0;
}
@@ -1557,17 +1601,23 @@ const struct inode_operations ubifs_file_inode_operations = {
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ .update_time = ubifs_update_time,
+#endif
};
const struct inode_operations ubifs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
.setattr = ubifs_setattr,
.getattr = ubifs_getattr,
.setxattr = ubifs_setxattr,
.getxattr = ubifs_getxattr,
.listxattr = ubifs_listxattr,
.removexattr = ubifs_removexattr,
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ .update_time = ubifs_update_time,
+#endif
};
const struct file_operations ubifs_file_operations = {
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
index dc9f27e..9a51710 100644
--- a/fs/ubifs/lpt.c
+++ b/fs/ubifs/lpt.c
@@ -1498,11 +1498,10 @@ static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
}
/* nnode is being committed, so copy it */
- n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
+ n = kmemdup(nnode, sizeof(struct ubifs_nnode), GFP_NOFS);
if (unlikely(!n))
return ERR_PTR(-ENOMEM);
- memcpy(n, nnode, sizeof(struct ubifs_nnode));
n->cnext = NULL;
__set_bit(DIRTY_CNODE, &n->flags);
__clear_bit(COW_CNODE, &n->flags);
@@ -1549,11 +1548,10 @@ static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
}
/* pnode is being committed, so copy it */
- p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
+ p = kmemdup(pnode, sizeof(struct ubifs_pnode), GFP_NOFS);
if (unlikely(!p))
return ERR_PTR(-ENOMEM);
- memcpy(p, pnode, sizeof(struct ubifs_pnode));
p->cnext = NULL;
__set_bit(DIRTY_CNODE, &p->flags);
__clear_bit(COW_CNODE, &p->flags);
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index ee7cb5e..8ece6ca 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -155,13 +155,8 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
*/
static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
{
- if (new_valid_dev(rdev)) {
- dev->new = cpu_to_le32(new_encode_dev(rdev));
- return sizeof(dev->new);
- } else {
- dev->huge = cpu_to_le64(huge_encode_dev(rdev));
- return sizeof(dev->huge);
- }
+ dev->new = cpu_to_le32(new_encode_dev(rdev));
+ return sizeof(dev->new);
}
/**
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 695fc71..586d593 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -789,7 +789,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
corrupted_rescan:
/* Re-scan the corrupted data with verbose messages */
ubifs_err(c, "corruption %d", ret);
- ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
corrupted:
ubifs_scanned_corruption(c, lnum, offs, buf);
err = -EUCLEAN;
@@ -1331,8 +1331,7 @@ void ubifs_destroy_size_tree(struct ubifs_info *c)
struct size_entry *e, *n;
rbtree_postorder_for_each_entry_safe(e, n, &c->size_tree, rb) {
- if (e->inode)
- iput(e->inode);
+ iput(e->inode);
kfree(e);
}
@@ -1533,8 +1532,7 @@ int ubifs_recover_size(struct ubifs_info *c)
err = fix_size_in_place(c, e);
if (err)
return err;
- if (e->inode)
- iput(e->inode);
+ iput(e->inode);
}
}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 9547a278..1fd90c0 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -128,7 +128,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err)
goto out_ino;
- inode->i_flags |= (S_NOCMTIME | S_NOATIME);
+ inode->i_flags |= S_NOCMTIME;
+#ifndef CONFIG_UBIFS_ATIME_SUPPORT
+ inode->i_flags |= S_NOATIME;
+#endif
set_nlink(inode, le32_to_cpu(ino->nlink));
i_uid_write(inode, le32_to_cpu(ino->uid));
i_gid_write(inode, le32_to_cpu(ino->gid));
@@ -2037,7 +2040,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations;
- sb->s_xattr = ubifs_xattr_handlers;
mutex_lock(&c->umount_mutex);
err = mount_ubifs(c);
@@ -2139,7 +2141,12 @@ static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
if (err)
goto out_deact;
/* We do not support atime */
- sb->s_flags |= MS_ACTIVE | MS_NOATIME;
+ sb->s_flags |= MS_ACTIVE;
+#ifndef CONFIG_UBIFS_ATIME_SUPPORT
+ sb->s_flags |= MS_NOATIME;
+#else
+ ubifs_msg(c, "full atime support is enabled.");
+#endif
}
/* 'fill_super()' opens ubi again so we must close it here */
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 957f575..fa9a20c 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -198,11 +198,10 @@ static struct ubifs_znode *copy_znode(struct ubifs_info *c,
{
struct ubifs_znode *zn;
- zn = kmalloc(c->max_znode_sz, GFP_NOFS);
+ zn = kmemdup(znode, c->max_znode_sz, GFP_NOFS);
if (unlikely(!zn))
return ERR_PTR(-ENOMEM);
- memcpy(zn, znode, c->max_znode_sz);
zn->cnext = NULL;
__set_bit(DIRTY_ZNODE, &zn->flags);
__clear_bit(COW_ZNODE, &zn->flags);
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index de75902..a5697de 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -858,9 +858,9 @@ struct ubifs_compressor {
* @mod_dent: non-zero if the operation removes or modifies an existing
* directory entry
* @new_ino: non-zero if the operation adds a new inode
- * @new_ino_d: now much data newly created inode contains
+ * @new_ino_d: how much data newly created inode contains
* @dirtied_ino: how many inodes the operation makes dirty
- * @dirtied_ino_d: now much data dirtied inode contains
+ * @dirtied_ino_d: how much data dirtied inode contains
* @idx_growth: how much the index will supposedly grow
* @data_growth: how much new data the operation will supposedly add
* @dd_growth: how much data that makes other data dirty the operation will
@@ -1470,7 +1470,6 @@ extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt;
extern struct kmem_cache *ubifs_inode_slab;
extern const struct super_operations ubifs_super_operations;
-extern const struct xattr_handler *ubifs_xattr_handlers[];
extern const struct address_space_operations ubifs_file_address_operations;
extern const struct file_operations ubifs_file_operations;
extern const struct inode_operations ubifs_file_inode_operations;
@@ -1746,6 +1745,9 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
/* file.c */
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+int ubifs_update_time(struct inode *inode, struct timespec *time, int flags);
+#endif
/* dir.c */
struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c
index fd65b3f..e8b01b7 100644
--- a/fs/ubifs/xattr.c
+++ b/fs/ubifs/xattr.c
@@ -200,6 +200,7 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
int err;
struct ubifs_inode *host_ui = ubifs_inode(host);
struct ubifs_inode *ui = ubifs_inode(inode);
+ void *buf = NULL;
struct ubifs_budget_req req = { .dirtied_ino = 2,
.dirtied_ino_d = ALIGN(size, 8) + ALIGN(host_ui->data_len, 8) };
@@ -208,14 +209,17 @@ static int change_xattr(struct ubifs_info *c, struct inode *host,
if (err)
return err;
- kfree(ui->data);
- ui->data = kmemdup(value, size, GFP_NOFS);
- if (!ui->data) {
+ buf = kmemdup(value, size, GFP_NOFS);
+ if (!buf) {
err = -ENOMEM;
goto out_free;
}
+ mutex_lock(&ui->ui_mutex);
+ kfree(ui->data);
+ ui->data = buf;
inode->i_size = ui->ui_size = size;
ui->data_len = size;
+ mutex_unlock(&ui->ui_mutex);
mutex_lock(&host_ui->ui_mutex);
host->i_ctime = ubifs_current_time(host);
@@ -409,6 +413,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
ubifs_assert(inode->i_size == ui->data_len);
ubifs_assert(ubifs_inode(host)->xattr_size > ui->data_len);
+ mutex_lock(&ui->ui_mutex);
if (buf) {
/* If @buf is %NULL we are supposed to return the length */
if (ui->data_len > size) {
@@ -423,6 +428,7 @@ ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
err = ui->data_len;
out_iput:
+ mutex_unlock(&ui->ui_mutex);
iput(inode);
out_unlock:
kfree(xent);
@@ -582,46 +588,6 @@ out_free:
return err;
}
-static size_t security_listxattr(struct dentry *d, char *list, size_t list_size,
- const char *name, size_t name_len, int flags)
-{
- const int prefix_len = XATTR_SECURITY_PREFIX_LEN;
- const size_t total_len = prefix_len + name_len + 1;
-
- if (list && total_len <= list_size) {
- memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
- memcpy(list + prefix_len, name, name_len);
- list[prefix_len + name_len] = '\0';
- }
-
- return total_len;
-}
-
-static int security_getxattr(struct dentry *d, const char *name, void *buffer,
- size_t size, int flags)
-{
- return ubifs_getxattr(d, name, buffer, size);
-}
-
-static int security_setxattr(struct dentry *d, const char *name,
- const void *value, size_t size, int flags,
- int handler_flags)
-{
- return ubifs_setxattr(d, name, value, size, flags);
-}
-
-static const struct xattr_handler ubifs_xattr_security_handler = {
- .prefix = XATTR_SECURITY_PREFIX,
- .list = security_listxattr,
- .get = security_getxattr,
- .set = security_setxattr,
-};
-
-const struct xattr_handler *ubifs_xattr_handlers[] = {
- &ubifs_xattr_security_handler,
- NULL,
-};
-
static int init_xattrs(struct inode *inode, const struct xattr *xattr_array,
void *fs_info)
{
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 8d0b3ad..0557463 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -1540,7 +1540,8 @@ reread:
break;
case ICBTAG_FILE_TYPE_SYMLINK:
inode->i_data.a_ops = &udf_symlink_aops;
- inode->i_op = &udf_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mode = S_IFLNK | S_IRWXUGO;
break;
case ICBTAG_FILE_TYPE_MAIN:
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index c97b5a8..42eafb9 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -921,7 +921,8 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
}
inode->i_data.a_ops = &udf_symlink_aops;
- inode->i_op = &udf_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
struct kernel_lb_addr eloc;
@@ -1344,8 +1345,3 @@ const struct inode_operations udf_dir_inode_operations = {
.rename = udf_rename,
.tmpfile = udf_tmpfile,
};
-const struct inode_operations udf_symlink_inode_operations = {
- .readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
-};
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c
index 862535b..8d61977 100644
--- a/fs/udf/symlink.c
+++ b/fs/udf/symlink.c
@@ -107,7 +107,7 @@ static int udf_symlink_filler(struct file *file, struct page *page)
struct buffer_head *bh = NULL;
unsigned char *symlink;
int err;
- unsigned char *p = kmap(page);
+ unsigned char *p = page_address(page);
struct udf_inode_info *iinfo;
uint32_t pos;
@@ -141,7 +141,6 @@ static int udf_symlink_filler(struct file *file, struct page *page)
up_read(&iinfo->i_data_sem);
SetPageUptodate(page);
- kunmap(page);
unlock_page(page);
return 0;
@@ -149,7 +148,6 @@ out_unlock_inode:
up_read(&iinfo->i_data_sem);
SetPageError(page);
out_unmap:
- kunmap(page);
unlock_page(page);
return err;
}
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 47bb3f5..ce169b4 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -85,7 +85,6 @@ extern const struct inode_operations udf_dir_inode_operations;
extern const struct file_operations udf_dir_operations;
extern const struct inode_operations udf_file_inode_operations;
extern const struct file_operations udf_file_operations;
-extern const struct inode_operations udf_symlink_inode_operations;
extern const struct address_space_operations udf_aops;
extern const struct address_space_operations udf_adinicb_aops;
extern const struct address_space_operations udf_symlink_aops;
diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile
index 392db25..ec4a6b4 100644
--- a/fs/ufs/Makefile
+++ b/fs/ufs/Makefile
@@ -5,5 +5,5 @@
obj-$(CONFIG_UFS_FS) += ufs.o
ufs-objs := balloc.o cylinder.o dir.o file.o ialloc.o inode.o \
- namei.o super.o symlink.o util.o
+ namei.o super.o util.o
ccflags-$(CONFIG_UFS_DEBUG) += -DDEBUG
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index a064cf44..d897e16 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -528,11 +528,12 @@ static void ufs_set_inode_ops(struct inode *inode)
inode->i_mapping->a_ops = &ufs_aops;
} else if (S_ISLNK(inode->i_mode)) {
if (!inode->i_blocks) {
- inode->i_op = &ufs_fast_symlink_inode_operations;
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
+ inode->i_op = &simple_symlink_inode_operations;
} else {
- inode->i_op = &ufs_symlink_inode_operations;
inode->i_mapping->a_ops = &ufs_aops;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
}
} else
init_special_inode(inode, inode->i_mode,
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index 4796655..acf4a3b 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -123,14 +123,15 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
if (l > UFS_SB(sb)->s_uspi->s_maxsymlinklen) {
/* slow symlink */
- inode->i_op = &ufs_symlink_inode_operations;
+ inode->i_op = &page_symlink_inode_operations;
+ inode_nohighmem(inode);
inode->i_mapping->a_ops = &ufs_aops;
err = page_symlink(inode, symname, l);
if (err)
goto out_fail;
} else {
/* fast symlink */
- inode->i_op = &ufs_fast_symlink_inode_operations;
+ inode->i_op = &simple_symlink_inode_operations;
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
memcpy(inode->i_link, symname, l);
inode->i_size = l-1;
diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c
deleted file mode 100644
index 874480b..0000000
--- a/fs/ufs/symlink.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * linux/fs/ufs/symlink.c
- *
- * Only fast symlinks left here - the rest is done by generic code. AV, 1999
- *
- * Copyright (C) 1998
- * Daniel Pirkl <daniel.pirkl@emai.cz>
- * Charles University, Faculty of Mathematics and Physics
- *
- * from
- *
- * linux/fs/ext2/symlink.c
- *
- * Copyright (C) 1992, 1993, 1994, 1995
- * Remy Card (card@masi.ibp.fr)
- * Laboratoire MASI - Institut Blaise Pascal
- * Universite Pierre et Marie Curie (Paris VI)
- *
- * from
- *
- * linux/fs/minix/symlink.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * ext2 symlink handling code
- */
-
-#include "ufs_fs.h"
-#include "ufs.h"
-
-const struct inode_operations ufs_fast_symlink_inode_operations = {
- .readlink = generic_readlink,
- .follow_link = simple_follow_link,
- .setattr = ufs_setattr,
-};
-
-const struct inode_operations ufs_symlink_inode_operations = {
- .readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
- .setattr = ufs_setattr,
-};
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h
index 7da4aca..c87f4c3 100644
--- a/fs/ufs/ufs.h
+++ b/fs/ufs/ufs.h
@@ -136,10 +136,6 @@ extern __printf(3, 4)
void ufs_panic(struct super_block *, const char *, const char *, ...);
void ufs_mark_sb_dirty(struct super_block *sb);
-/* symlink.c */
-extern const struct inode_operations ufs_fast_symlink_inode_operations;
-extern const struct inode_operations ufs_symlink_inode_operations;
-
static inline struct ufs_sb_info *UFS_SB(struct super_block *sb)
{
return sb->s_fs_info;
diff --git a/fs/xattr.c b/fs/xattr.c
index 072fee1..d5dd6c8 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -208,25 +208,6 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
return error;
}
-/* Compare an extended attribute value with the given value */
-int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
- const char *value, size_t size, gfp_t flags)
-{
- char *xattr_value = NULL;
- int rc;
-
- rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
- if (rc < 0)
- return rc;
-
- if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
- rc = -EINVAL;
- else
- rc = 0;
- kfree(xattr_value);
- return rc;
-}
-
ssize_t
vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
@@ -324,7 +305,6 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
{
int error;
void *kvalue = NULL;
- void *vvalue = NULL; /* If non-NULL, we used vmalloc() */
char kname[XATTR_NAME_MAX + 1];
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
@@ -341,10 +321,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
return -E2BIG;
kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!kvalue) {
- vvalue = vmalloc(size);
- if (!vvalue)
+ kvalue = vmalloc(size);
+ if (!kvalue)
return -ENOMEM;
- kvalue = vvalue;
}
if (copy_from_user(kvalue, value, size)) {
error = -EFAULT;
@@ -357,10 +336,8 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
error = vfs_setxattr(d, kname, kvalue, size, flags);
out:
- if (vvalue)
- vfree(vvalue);
- else
- kfree(kvalue);
+ kvfree(kvalue);
+
return error;
}
@@ -428,7 +405,6 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
{
ssize_t error;
void *kvalue = NULL;
- void *vvalue = NULL;
char kname[XATTR_NAME_MAX + 1];
error = strncpy_from_user(kname, name, sizeof(kname));
@@ -442,10 +418,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
size = XATTR_SIZE_MAX;
kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
if (!kvalue) {
- vvalue = vmalloc(size);
- if (!vvalue)
+ kvalue = vmalloc(size);
+ if (!kvalue)
return -ENOMEM;
- kvalue = vvalue;
}
}
@@ -461,10 +436,9 @@ getxattr(struct dentry *d, const char __user *name, void __user *value,
than XATTR_SIZE_MAX bytes. Not possible. */
error = -E2BIG;
}
- if (vvalue)
- vfree(vvalue);
- else
- kfree(kvalue);
+
+ kvfree(kvalue);
+
return error;
}
@@ -521,17 +495,15 @@ listxattr(struct dentry *d, char __user *list, size_t size)
{
ssize_t error;
char *klist = NULL;
- char *vlist = NULL; /* If non-NULL, we used vmalloc() */
if (size) {
if (size > XATTR_LIST_MAX)
size = XATTR_LIST_MAX;
klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL);
if (!klist) {
- vlist = vmalloc(size);
- if (!vlist)
+ klist = vmalloc(size);
+ if (!klist)
return -ENOMEM;
- klist = vlist;
}
}
@@ -544,10 +516,9 @@ listxattr(struct dentry *d, char __user *list, size_t size)
than XATTR_LIST_MAX bytes. Not possible. */
error = -E2BIG;
}
- if (vlist)
- vfree(vlist);
- else
- kfree(klist);
+
+ kvfree(klist);
+
return error;
}
@@ -700,13 +671,20 @@ xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
return NULL;
for_each_xattr_handler(handlers, handler) {
- const char *n = strcmp_prefix(*name, handler->prefix);
+ const char *n;
+
+ n = strcmp_prefix(*name, xattr_prefix(handler));
if (n) {
+ if (!handler->prefix ^ !*n) {
+ if (*n)
+ continue;
+ return ERR_PTR(-EINVAL);
+ }
*name = n;
- break;
+ return handler;
}
}
- return handler;
+ return ERR_PTR(-EOPNOTSUPP);
}
/*
@@ -718,9 +696,9 @@ generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t s
const struct xattr_handler *handler;
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (!handler)
- return -EOPNOTSUPP;
- return handler->get(dentry, name, buffer, size, handler->flags);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ return handler->get(handler, dentry, name, buffer, size);
}
/*
@@ -735,19 +713,25 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
if (!buffer) {
for_each_xattr_handler(handlers, handler) {
- size += handler->list(dentry, NULL, 0, NULL, 0,
- handler->flags);
+ if (!handler->name ||
+ (handler->list && !handler->list(dentry)))
+ continue;
+ size += strlen(handler->name) + 1;
}
} else {
char *buf = buffer;
+ size_t len;
for_each_xattr_handler(handlers, handler) {
- size = handler->list(dentry, buf, buffer_size,
- NULL, 0, handler->flags);
- if (size > buffer_size)
+ if (!handler->name ||
+ (handler->list && !handler->list(dentry)))
+ continue;
+ len = strlen(handler->name);
+ if (len + 1 > buffer_size)
return -ERANGE;
- buf += size;
- buffer_size -= size;
+ memcpy(buf, handler->name, len + 1);
+ buf += len + 1;
+ buffer_size -= len + 1;
}
size = buf - buffer;
}
@@ -765,9 +749,9 @@ generic_setxattr(struct dentry *dentry, const char *name, const void *value, siz
if (size == 0)
value = ""; /* empty EA, do not remove */
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (!handler)
- return -EOPNOTSUPP;
- return handler->set(dentry, name, value, size, flags, handler->flags);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ return handler->set(handler, dentry, name, value, size, flags);
}
/*
@@ -780,10 +764,9 @@ generic_removexattr(struct dentry *dentry, const char *name)
const struct xattr_handler *handler;
handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
- if (!handler)
- return -EOPNOTSUPP;
- return handler->set(dentry, name, NULL, 0,
- XATTR_REPLACE, handler->flags);
+ if (IS_ERR(handler))
+ return PTR_ERR(handler);
+ return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
}
EXPORT_SYMBOL(generic_getxattr);
@@ -791,6 +774,30 @@ EXPORT_SYMBOL(generic_listxattr);
EXPORT_SYMBOL(generic_setxattr);
EXPORT_SYMBOL(generic_removexattr);
+/**
+ * xattr_full_name - Compute full attribute name from suffix
+ *
+ * @handler: handler of the xattr_handler operation
+ * @name: name passed to the xattr_handler operation
+ *
+ * The get and set xattr handler operations are called with the remainder of
+ * the attribute name after skipping the handler's prefix: for example, "foo"
+ * is passed to the get operation of a handler with prefix "user." to get
+ * attribute "user.foo". The full name is still "there" in the name though.
+ *
+ * Note: the list xattr handler operation when called from the vfs is passed a
+ * NULL name; some file systems use this operation internally, with varying
+ * semantics.
+ */
+const char *xattr_full_name(const struct xattr_handler *handler,
+ const char *name)
+{
+ size_t prefix_len = strlen(xattr_prefix(handler));
+
+ return name - prefix_len;
+}
+EXPORT_SYMBOL(xattr_full_name);
+
/*
* Allocate new xattr and copy in the value; but leave the name to callers.
*/
@@ -840,8 +847,22 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
return ret;
}
-static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
- const void *value, size_t size, int flags)
+/**
+ * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
+ * @xattrs: target simple_xattr list
+ * @name: name of the extended attribute
+ * @value: value of the xattr. If %NULL, will remove the attribute.
+ * @size: size of the new xattr
+ * @flags: %XATTR_{CREATE|REPLACE}
+ *
+ * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
+ * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist;
+ * otherwise, fails with -ENODATA.
+ *
+ * Returns 0 on success, -errno on failure.
+ */
+int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
+ const void *value, size_t size, int flags)
{
struct simple_xattr *xattr;
struct simple_xattr *new_xattr = NULL;
@@ -891,73 +912,64 @@ out:
}
-/**
- * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
- * @xattrs: target simple_xattr list
- * @name: name of the new extended attribute
- * @value: value of the new xattr. If %NULL, will remove the attribute
- * @size: size of the new xattr
- * @flags: %XATTR_{CREATE|REPLACE}
- *
- * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
- * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist;
- * otherwise, fails with -ENODATA.
- *
- * Returns 0 on success, -errno on failure.
- */
-int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
- const void *value, size_t size, int flags)
-{
- if (size == 0)
- value = ""; /* empty EA, do not remove */
- return __simple_xattr_set(xattrs, name, value, size, flags);
-}
-
-/*
- * xattr REMOVE operation for in-memory/pseudo filesystems
- */
-int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
+static bool xattr_is_trusted(const char *name)
{
- return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
+ return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
}
-static bool xattr_is_trusted(const char *name)
+static int xattr_list_one(char **buffer, ssize_t *remaining_size,
+ const char *name)
{
- return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
+ size_t len = strlen(name) + 1;
+ if (*buffer) {
+ if (*remaining_size < len)
+ return -ERANGE;
+ memcpy(*buffer, name, len);
+ *buffer += len;
+ }
+ *remaining_size -= len;
+ return 0;
}
/*
* xattr LIST operation for in-memory/pseudo filesystems
*/
-ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
- size_t size)
+ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs,
+ char *buffer, size_t size)
{
bool trusted = capable(CAP_SYS_ADMIN);
struct simple_xattr *xattr;
- size_t used = 0;
+ ssize_t remaining_size = size;
+ int err;
+
+#ifdef CONFIG_FS_POSIX_ACL
+ if (inode->i_acl) {
+ err = xattr_list_one(&buffer, &remaining_size,
+ XATTR_NAME_POSIX_ACL_ACCESS);
+ if (err)
+ return err;
+ }
+ if (inode->i_default_acl) {
+ err = xattr_list_one(&buffer, &remaining_size,
+ XATTR_NAME_POSIX_ACL_DEFAULT);
+ if (err)
+ return err;
+ }
+#endif
spin_lock(&xattrs->lock);
list_for_each_entry(xattr, &xattrs->head, list) {
- size_t len;
-
/* skip "trusted." attributes for unprivileged callers */
if (!trusted && xattr_is_trusted(xattr->name))
continue;
- len = strlen(xattr->name) + 1;
- used += len;
- if (buffer) {
- if (size < used) {
- used = -ERANGE;
- break;
- }
- memcpy(buffer, xattr->name, len);
- buffer += len;
- }
+ err = xattr_list_one(&buffer, &remaining_size, xattr->name);
+ if (err)
+ return err;
}
spin_unlock(&xattrs->lock);
- return used;
+ return size - remaining_size;
}
/*
diff --git a/fs/xfs/Makefile b/fs/xfs/Makefile
index a096841..f646391 100644
--- a/fs/xfs/Makefile
+++ b/fs/xfs/Makefile
@@ -84,6 +84,7 @@ xfs-y += xfs_aops.o \
xfs_message.o \
xfs_mount.o \
xfs_mru_cache.o \
+ xfs_stats.o \
xfs_super.o \
xfs_symlink.o \
xfs_sysfs.o \
@@ -118,7 +119,6 @@ xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \
xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o
xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o
-xfs-$(CONFIG_PROC_FS) += xfs_stats.o
xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o
xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o
xfs-$(CONFIG_NFSD_PNFS) += xfs_pnfs.o
diff --git a/fs/xfs/kmem.c b/fs/xfs/kmem.c
index a7a3a63..686ba6f 100644
--- a/fs/xfs/kmem.c
+++ b/fs/xfs/kmem.c
@@ -55,8 +55,9 @@ kmem_alloc(size_t size, xfs_km_flags_t flags)
return ptr;
if (!(++retries % 100))
xfs_err(NULL,
- "possible memory allocation deadlock in %s (mode:0x%x)",
- __func__, lflags);
+ "%s(%u) possible memory allocation deadlock size %u in %s (mode:0x%x)",
+ current->comm, current->pid,
+ (unsigned int)size, __func__, lflags);
congestion_wait(BLK_RW_ASYNC, HZ/50);
} while (1);
}
@@ -120,8 +121,9 @@ kmem_zone_alloc(kmem_zone_t *zone, xfs_km_flags_t flags)
return ptr;
if (!(++retries % 100))
xfs_err(NULL,
- "possible memory allocation deadlock in %s (mode:0x%x)",
- __func__, lflags);
+ "%s(%u) possible memory allocation deadlock in %s (mode:0x%x)",
+ current->comm, current->pid,
+ __func__, lflags);
congestion_wait(BLK_RW_ASYNC, HZ/50);
} while (1);
}
diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c
index ffad7f2..3479294 100644
--- a/fs/xfs/libxfs/xfs_alloc.c
+++ b/fs/xfs/libxfs/xfs_alloc.c
@@ -482,7 +482,9 @@ xfs_agfl_verify(
be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks)
return false;
}
- return true;
+
+ return xfs_log_check_lsn(mp,
+ be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn));
}
static void
@@ -651,8 +653,8 @@ xfs_alloc_ag_vextent(
-((long)(args->len)));
}
- XFS_STATS_INC(xs_allocx);
- XFS_STATS_ADD(xs_allocb, args->len);
+ XFS_STATS_INC(args->mp, xs_allocx);
+ XFS_STATS_ADD(args->mp, xs_allocb, args->len);
return error;
}
@@ -1808,8 +1810,8 @@ xfs_free_ag_extent(
if (!isfl)
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (long)len);
- XFS_STATS_INC(xs_freex);
- XFS_STATS_ADD(xs_freeb, len);
+ XFS_STATS_INC(mp, xs_freex);
+ XFS_STATS_ADD(mp, xs_freeb, len);
trace_xfs_free_extent(mp, agno, bno, len, isfl, haveleft, haveright);
@@ -2259,9 +2261,13 @@ xfs_agf_verify(
{
struct xfs_agf *agf = XFS_BUF_TO_AGF(bp);
- if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid))
return false;
+ if (!xfs_log_check_lsn(mp,
+ be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn)))
+ return false;
+ }
if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) &&
XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) &&
@@ -2503,7 +2509,7 @@ xfs_alloc_vextent(
* Try near allocation first, then anywhere-in-ag after
* the first a.g. fails.
*/
- if ((args->userdata == XFS_ALLOC_INITIAL_USER_DATA) &&
+ if ((args->userdata & XFS_ALLOC_INITIAL_USER_DATA) &&
(mp->m_flags & XFS_MOUNT_32BITINODES)) {
args->fsbno = XFS_AGB_TO_FSB(mp,
((mp->m_agfrotor / rotorstep) %
@@ -2634,6 +2640,14 @@ xfs_alloc_vextent(
XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno),
args->len);
#endif
+
+ /* Zero the extent if we were asked to do so */
+ if (args->userdata & XFS_ALLOC_USERDATA_ZERO) {
+ error = xfs_zero_extent(args->ip, args->fsbno, args->len);
+ if (error)
+ goto error0;
+ }
+
}
xfs_perag_put(args->pag);
return 0;
diff --git a/fs/xfs/libxfs/xfs_alloc.h b/fs/xfs/libxfs/xfs_alloc.h
index ca1c816..0ecde4d 100644
--- a/fs/xfs/libxfs/xfs_alloc.h
+++ b/fs/xfs/libxfs/xfs_alloc.h
@@ -101,6 +101,7 @@ typedef struct xfs_alloc_arg {
struct xfs_mount *mp; /* file system mount point */
struct xfs_buf *agbp; /* buffer for a.g. freelist header */
struct xfs_perag *pag; /* per-ag struct for this agno */
+ struct xfs_inode *ip; /* for userdata zeroing method */
xfs_fsblock_t fsbno; /* file system block number */
xfs_agnumber_t agno; /* allocation group number */
xfs_agblock_t agbno; /* allocation group-relative block # */
@@ -120,15 +121,16 @@ typedef struct xfs_alloc_arg {
char wasdel; /* set if allocation was prev delayed */
char wasfromfl; /* set if allocation is from freelist */
char isfl; /* set if is freelist blocks - !acctg */
- char userdata; /* set if this is user data */
+ char userdata; /* mask defining userdata treatment */
xfs_fsblock_t firstblock; /* io first block allocated */
} xfs_alloc_arg_t;
/*
* Defines for userdata
*/
-#define XFS_ALLOC_USERDATA 1 /* allocation is for user data*/
-#define XFS_ALLOC_INITIAL_USER_DATA 2 /* special case start of file */
+#define XFS_ALLOC_USERDATA (1 << 0)/* allocation is for user data*/
+#define XFS_ALLOC_INITIAL_USER_DATA (1 << 1)/* special case start of file */
+#define XFS_ALLOC_USERDATA_ZERO (1 << 2)/* zero extent on allocation */
xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp,
struct xfs_perag *pag, xfs_extlen_t need);
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index ff06557..f949818 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -125,7 +125,7 @@ xfs_attr_get(
uint lock_mode;
int error;
- XFS_STATS_INC(xs_attr_get);
+ XFS_STATS_INC(ip->i_mount, xs_attr_get);
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO;
@@ -209,7 +209,7 @@ xfs_attr_set(
int rsvd = (flags & ATTR_ROOT) != 0;
int error, err2, committed, local;
- XFS_STATS_INC(xs_attr_set);
+ XFS_STATS_INC(mp, xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO;
@@ -412,7 +412,7 @@ xfs_attr_remove(
xfs_fsblock_t firstblock;
int error;
- XFS_STATS_INC(xs_attr_remove);
+ XFS_STATS_INC(mp, xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 33df52d..aa187f7 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -41,6 +41,7 @@
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
#include "xfs_dir2.h"
+#include "xfs_log.h"
/*
@@ -266,6 +267,8 @@ xfs_attr3_leaf_verify(
return false;
if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
+ return false;
} else {
if (ichdr.magic != XFS_ATTR_LEAF_MAGIC)
return false;
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index f38f9bd..5ab95ff 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -107,7 +107,7 @@ xfs_attr3_rmt_verify(
if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt))
return false;
if (be32_to_cpu(rmt->rm_offset) +
- be32_to_cpu(rmt->rm_bytes) > XATTR_SIZE_MAX)
+ be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX)
return false;
if (rmt->rm_owner == 0)
return false;
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 8e2010d..119c242 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -948,14 +948,16 @@ xfs_bmap_local_to_extents(
bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0);
/*
- * Initialise the block and copy the data
+ * Initialize the block, copy the data and log the remote buffer.
*
- * Note: init_fn must set the buffer log item type correctly!
+ * The callout is responsible for logging because the remote format
+ * might differ from the local format and thus we don't know how much to
+ * log here. Note that init_fn must also set the buffer log item type
+ * correctly.
*/
init_fn(tp, bp, ip, ifp);
- /* account for the change in fork size and log everything */
- xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
+ /* account for the change in fork size */
xfs_idata_realloc(ip, -ifp->if_bytes, whichfork);
xfs_bmap_local_to_extents_empty(ip, whichfork);
flags |= XFS_ILOG_CORE;
@@ -1435,7 +1437,7 @@ xfs_bmap_search_extents(
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_rec_host_t *ep; /* extent record pointer */
- XFS_STATS_INC(xs_look_exlist);
+ XFS_STATS_INC(ip->i_mount, xs_look_exlist);
ifp = XFS_IFORK_PTR(ip, fork);
ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
@@ -1732,7 +1734,7 @@ xfs_bmap_add_extent_delay_real(
ASSERT(!bma->cur ||
(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
- XFS_STATS_INC(xs_add_exlist);
+ XFS_STATS_INC(mp, xs_add_exlist);
#define LEFT r[0]
#define RIGHT r[1]
@@ -2286,7 +2288,7 @@ xfs_bmap_add_extent_unwritten_real(
ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
ASSERT(!isnullstartblock(new->br_startblock));
- XFS_STATS_INC(xs_add_exlist);
+ XFS_STATS_INC(mp, xs_add_exlist);
#define LEFT r[0]
#define RIGHT r[1]
@@ -2946,7 +2948,7 @@ xfs_bmap_add_extent_hole_real(
ASSERT(!bma->cur ||
!(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
- XFS_STATS_INC(xs_add_exlist);
+ XFS_STATS_INC(mp, xs_add_exlist);
state = 0;
if (whichfork == XFS_ATTR_FORK)
@@ -3800,8 +3802,13 @@ xfs_bmap_btalloc(
args.wasdel = ap->wasdel;
args.isfl = 0;
args.userdata = ap->userdata;
- if ((error = xfs_alloc_vextent(&args)))
+ if (ap->userdata & XFS_ALLOC_USERDATA_ZERO)
+ args.ip = ap->ip;
+
+ error = xfs_alloc_vextent(&args);
+ if (error)
return error;
+
if (tryagain && args.fsbno == NULLFSBLOCK) {
/*
* Exact allocation failed. Now try with alignment
@@ -4036,7 +4043,7 @@ xfs_bmapi_read(
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
- XFS_STATS_INC(xs_blk_mapr);
+ XFS_STATS_INC(mp, xs_blk_mapr);
ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -4221,7 +4228,7 @@ xfs_bmapi_delay(
if (XFS_FORCED_SHUTDOWN(mp))
return -EIO;
- XFS_STATS_INC(xs_blk_mapw);
+ XFS_STATS_INC(mp, xs_blk_mapw);
if (!(ifp->if_flags & XFS_IFEXTENTS)) {
error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK);
@@ -4300,11 +4307,14 @@ xfs_bmapi_allocate(
/*
* Indicate if this is the first user data in the file, or just any
- * user data.
+ * user data. And if it is userdata, indicate whether it needs to
+ * be initialised to zero during allocation.
*/
if (!(bma->flags & XFS_BMAPI_METADATA)) {
bma->userdata = (bma->offset == 0) ?
XFS_ALLOC_INITIAL_USER_DATA : XFS_ALLOC_USERDATA;
+ if (bma->flags & XFS_BMAPI_ZERO)
+ bma->userdata |= XFS_ALLOC_USERDATA_ZERO;
}
bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1;
@@ -4419,6 +4429,17 @@ xfs_bmapi_convert_unwritten(
mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN)
? XFS_EXT_NORM : XFS_EXT_UNWRITTEN;
+ /*
+ * Before insertion into the bmbt, zero the range being converted
+ * if required.
+ */
+ if (flags & XFS_BMAPI_ZERO) {
+ error = xfs_zero_extent(bma->ip, mval->br_startblock,
+ mval->br_blockcount);
+ if (error)
+ return error;
+ }
+
error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx,
&bma->cur, mval, bma->firstblock, bma->flist,
&tmp_logflags);
@@ -4512,6 +4533,18 @@ xfs_bmapi_write(
ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
+ /* zeroing is for currently only for data extents, not metadata */
+ ASSERT((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)) !=
+ (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO));
+ /*
+ * we can allocate unwritten extents or pre-zero allocated blocks,
+ * but it makes no sense to do both at once. This would result in
+ * zeroing the unwritten extent twice, but it still being an
+ * unwritten extent....
+ */
+ ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) !=
+ (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO));
+
if (unlikely(XFS_TEST_ERROR(
(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE),
@@ -4525,7 +4558,7 @@ xfs_bmapi_write(
ifp = XFS_IFORK_PTR(ip, whichfork);
- XFS_STATS_INC(xs_blk_mapw);
+ XFS_STATS_INC(mp, xs_blk_mapw);
if (*firstblock == NULLFSBLOCK) {
if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE)
@@ -4718,12 +4751,12 @@ xfs_bmap_del_extent(
xfs_filblks_t temp2; /* for indirect length calculations */
int state = 0;
- XFS_STATS_INC(xs_del_exlist);
+ mp = ip->i_mount;
+ XFS_STATS_INC(mp, xs_del_exlist);
if (whichfork == XFS_ATTR_FORK)
state |= BMAP_ATTRFORK;
- mp = ip->i_mount;
ifp = XFS_IFORK_PTR(ip, whichfork);
ASSERT((*idx >= 0) && (*idx < ifp->if_bytes /
(uint)sizeof(xfs_bmbt_rec_t)));
@@ -5070,7 +5103,7 @@ xfs_bunmapi(
*done = 1;
return 0;
}
- XFS_STATS_INC(xs_blk_unmap);
+ XFS_STATS_INC(mp, xs_blk_unmap);
isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
start = bno;
bno = start + len - 1;
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h
index 6aaa0c1..a160f8a 100644
--- a/fs/xfs/libxfs/xfs_bmap.h
+++ b/fs/xfs/libxfs/xfs_bmap.h
@@ -52,9 +52,9 @@ struct xfs_bmalloca {
xfs_extlen_t minleft; /* amount must be left after alloc */
bool eof; /* set if allocating past last extent */
bool wasdel; /* replacing a delayed allocation */
- bool userdata;/* set if is user data */
bool aeof; /* allocated space at eof */
bool conv; /* overwriting unwritten extents */
+ char userdata;/* userdata mask */
int flags;
};
@@ -109,6 +109,14 @@ typedef struct xfs_bmap_free
*/
#define XFS_BMAPI_CONVERT 0x040
+/*
+ * allocate zeroed extents - this requires all newly allocated user data extents
+ * to be initialised to zero. It will be ignored if XFS_BMAPI_METADATA is set.
+ * Use in conjunction with XFS_BMAPI_CONVERT to convert unwritten extents found
+ * during the allocation range to zeroed written extents.
+ */
+#define XFS_BMAPI_ZERO 0x080
+
#define XFS_BMAPI_FLAGS \
{ XFS_BMAPI_ENTIRE, "ENTIRE" }, \
{ XFS_BMAPI_METADATA, "METADATA" }, \
@@ -116,7 +124,8 @@ typedef struct xfs_bmap_free
{ XFS_BMAPI_PREALLOC, "PREALLOC" }, \
{ XFS_BMAPI_IGSTATE, "IGSTATE" }, \
{ XFS_BMAPI_CONTIG, "CONTIG" }, \
- { XFS_BMAPI_CONVERT, "CONVERT" }
+ { XFS_BMAPI_CONVERT, "CONVERT" }, \
+ { XFS_BMAPI_ZERO, "ZERO" }
static inline int xfs_bmapi_aflag(int w)
diff --git a/fs/xfs/libxfs/xfs_btree.c b/fs/xfs/libxfs/xfs_btree.c
index f7d7ee7..af1bbee 100644
--- a/fs/xfs/libxfs/xfs_btree.c
+++ b/fs/xfs/libxfs/xfs_btree.c
@@ -32,6 +32,7 @@
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_alloc.h"
+#include "xfs_log.h"
/*
* Cursor allocation zone.
@@ -222,7 +223,7 @@ xfs_btree_check_ptr(
* long-form btree header.
*
* Prior to calculting the CRC, pull the LSN out of the buffer log item and put
- * it into the buffer so recovery knows what the last modifcation was that made
+ * it into the buffer so recovery knows what the last modification was that made
* it to disk.
*/
void
@@ -243,8 +244,14 @@ bool
xfs_btree_lblock_verify_crc(
struct xfs_buf *bp)
{
- if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn)))
+ return false;
return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF);
+ }
return true;
}
@@ -254,7 +261,7 @@ xfs_btree_lblock_verify_crc(
* short-form btree header.
*
* Prior to calculting the CRC, pull the LSN out of the buffer log item and put
- * it into the buffer so recovery knows what the last modifcation was that made
+ * it into the buffer so recovery knows what the last modification was that made
* it to disk.
*/
void
@@ -275,8 +282,14 @@ bool
xfs_btree_sblock_verify_crc(
struct xfs_buf *bp)
{
- if (xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb))
+ struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp);
+ struct xfs_mount *mp = bp->b_target->bt_mount;
+
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn)))
+ return false;
return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF);
+ }
return true;
}
diff --git a/fs/xfs/libxfs/xfs_btree.h b/fs/xfs/libxfs/xfs_btree.h
index 8f18bab..992dec0 100644
--- a/fs/xfs/libxfs/xfs_btree.h
+++ b/fs/xfs/libxfs/xfs_btree.h
@@ -84,31 +84,38 @@ union xfs_btree_rec {
/*
* Generic stats interface
*/
-#define __XFS_BTREE_STATS_INC(type, stat) \
- XFS_STATS_INC(xs_ ## type ## _2_ ## stat)
-#define XFS_BTREE_STATS_INC(cur, stat) \
+#define __XFS_BTREE_STATS_INC(mp, type, stat) \
+ XFS_STATS_INC(mp, xs_ ## type ## _2_ ## stat)
+#define XFS_BTREE_STATS_INC(cur, stat) \
do { \
+ struct xfs_mount *__mp = cur->bc_mp; \
switch (cur->bc_btnum) { \
- case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(abtb, stat); break; \
- case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(abtc, stat); break; \
- case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(bmbt, stat); break; \
- case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(ibt, stat); break; \
- case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(fibt, stat); break; \
+ case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(__mp, abtb, stat); break; \
+ case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(__mp, abtc, stat); break; \
+ case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(__mp, bmbt, stat); break; \
+ case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(__mp, ibt, stat); break; \
+ case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(__mp, fibt, stat); break; \
case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
-#define __XFS_BTREE_STATS_ADD(type, stat, val) \
- XFS_STATS_ADD(xs_ ## type ## _2_ ## stat, val)
+#define __XFS_BTREE_STATS_ADD(mp, type, stat, val) \
+ XFS_STATS_ADD(mp, xs_ ## type ## _2_ ## stat, val)
#define XFS_BTREE_STATS_ADD(cur, stat, val) \
do { \
+ struct xfs_mount *__mp = cur->bc_mp; \
switch (cur->bc_btnum) { \
- case XFS_BTNUM_BNO: __XFS_BTREE_STATS_ADD(abtb, stat, val); break; \
- case XFS_BTNUM_CNT: __XFS_BTREE_STATS_ADD(abtc, stat, val); break; \
- case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_ADD(bmbt, stat, val); break; \
- case XFS_BTNUM_INO: __XFS_BTREE_STATS_ADD(ibt, stat, val); break; \
- case XFS_BTNUM_FINO: __XFS_BTREE_STATS_ADD(fibt, stat, val); break; \
- case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
+ case XFS_BTNUM_BNO: \
+ __XFS_BTREE_STATS_ADD(__mp, abtb, stat, val); break; \
+ case XFS_BTNUM_CNT: \
+ __XFS_BTREE_STATS_ADD(__mp, abtc, stat, val); break; \
+ case XFS_BTNUM_BMAP: \
+ __XFS_BTREE_STATS_ADD(__mp, bmbt, stat, val); break; \
+ case XFS_BTNUM_INO: \
+ __XFS_BTREE_STATS_ADD(__mp, ibt, stat, val); break; \
+ case XFS_BTNUM_FINO: \
+ __XFS_BTREE_STATS_ADD(__mp, fibt, stat, val); break; \
+ case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \
} \
} while (0)
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index be43248..e89a0f8f 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -39,6 +39,7 @@
#include "xfs_trace.h"
#include "xfs_cksum.h"
#include "xfs_buf_item.h"
+#include "xfs_log.h"
/*
* xfs_da_btree.c
@@ -150,6 +151,8 @@ xfs_da3_node_verify(
return false;
if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn)))
+ return false;
} else {
if (ichdr.magic != XFS_DA_NODE_MAGIC)
return false;
@@ -322,6 +325,7 @@ xfs_da3_node_create(
if (xfs_sb_version_hascrc(&mp->m_sb)) {
struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
+ memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr));
ichdr.magic = XFS_DA3_NODE_MAGIC;
hdr3->info.blkno = cpu_to_be64(bp->b_bn);
hdr3->info.owner = cpu_to_be64(args->dp->i_ino);
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 9de401d..2fb53a5 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -271,7 +271,7 @@ xfs_dir_createname(
rval = xfs_dir_ino_validate(tp->t_mountp, inum);
if (rval)
return rval;
- XFS_STATS_INC(xs_dir_create);
+ XFS_STATS_INC(dp->i_mount, xs_dir_create);
}
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
@@ -365,7 +365,7 @@ xfs_dir_lookup(
int lock_mode;
ASSERT(S_ISDIR(dp->i_d.di_mode));
- XFS_STATS_INC(xs_dir_lookup);
+ XFS_STATS_INC(dp->i_mount, xs_dir_lookup);
/*
* We need to use KM_NOFS here so that lockdep will not throw false
@@ -444,7 +444,7 @@ xfs_dir_removename(
int v; /* type-checking value */
ASSERT(S_ISDIR(dp->i_d.di_mode));
- XFS_STATS_INC(xs_dir_remove);
+ XFS_STATS_INC(dp->i_mount, xs_dir_remove);
args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS);
if (!args)
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 4778d1d..9c10e2b 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -34,6 +34,7 @@
#include "xfs_error.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
+#include "xfs_log.h"
/*
* Local function prototypes.
@@ -71,6 +72,8 @@ xfs_dir3_block_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC))
return false;
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index 824131e..af71a84 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -31,6 +31,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
+#include "xfs_log.h"
/*
* Check the consistency of the data block.
@@ -224,6 +225,8 @@ xfs_dir3_data_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC))
return false;
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index f300240..3923e1f 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -33,6 +33,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
+#include "xfs_log.h"
/*
* Local function declarations.
@@ -164,6 +165,8 @@ xfs_dir3_leaf_verify(
return false;
if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(leaf3->info.lsn)))
+ return false;
} else {
if (leaf->hdr.info.magic != cpu_to_be16(magic))
return false;
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index cc28e92..70b0cb2 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -33,6 +33,7 @@
#include "xfs_trans.h"
#include "xfs_buf_item.h"
#include "xfs_cksum.h"
+#include "xfs_log.h"
/*
* Function declarations.
@@ -97,6 +98,8 @@ xfs_dir3_free_verify(
return false;
if (be64_to_cpu(hdr3->blkno) != bp->b_bn)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn)))
+ return false;
} else {
if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC))
return false;
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 9590a06..8774498 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -60,6 +60,14 @@ struct xfs_ifork;
#define XFS_SB_VERSION_MOREBITSBIT 0x8000
/*
+ * The size of a single extended attribute on disk is limited by
+ * the size of index values within the attribute entries themselves.
+ * These are be16 fields, so we can only support attribute data
+ * sizes up to 2^16 bytes in length.
+ */
+#define XFS_XATTR_SIZE_MAX (1 << 16)
+
+/*
* Supported feature bit list is just all bits in the versionnum field because
* we've used them all up and understand them all. Except, of course, for the
* shared superblock bit, which nobody knows what it does and so is unsupported.
@@ -1483,13 +1491,17 @@ struct xfs_acl {
*/
#define XFS_ACL_MAX_ENTRIES(mp) \
(xfs_sb_version_hascrc(&mp->m_sb) \
- ? (XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \
+ ? (XFS_XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \
sizeof(struct xfs_acl_entry) \
: 25)
-#define XFS_ACL_MAX_SIZE(mp) \
+#define XFS_ACL_SIZE(cnt) \
(sizeof(struct xfs_acl) + \
- sizeof(struct xfs_acl_entry) * XFS_ACL_MAX_ENTRIES((mp)))
+ sizeof(struct xfs_acl_entry) * cnt)
+
+#define XFS_ACL_MAX_SIZE(mp) \
+ XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp)))
+
/* On-disk XFS extended attribute names */
#define SGI_ACL_FILE "SGI_ACL_FILE"
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 89689c6..b2b73a9 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -490,6 +490,16 @@ typedef struct xfs_swapext
#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
/*
+ * ioctl limits
+ */
+#ifdef XATTR_LIST_MAX
+# define XFS_XATTR_LIST_MAX XATTR_LIST_MAX
+#else
+# define XFS_XATTR_LIST_MAX 65536
+#endif
+
+
+/*
* ioctl commands that are used by Linux filesystems
*/
#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 54deb2d..70c1db9 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -38,6 +38,7 @@
#include "xfs_icreate_item.h"
#include "xfs_icache.h"
#include "xfs_trace.h"
+#include "xfs_log.h"
/*
@@ -2500,9 +2501,14 @@ xfs_agi_verify(
struct xfs_mount *mp = bp->b_target->bt_mount;
struct xfs_agi *agi = XFS_BUF_TO_AGI(bp);
- if (xfs_sb_version_hascrc(&mp->m_sb) &&
- !uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
+ if (xfs_sb_version_hascrc(&mp->m_sb)) {
+ if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid))
+ return false;
+ if (!xfs_log_check_lsn(mp,
+ be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn)))
return false;
+ }
+
/*
* Validate the magic number of the agi block.
*/
diff --git a/fs/xfs/libxfs/xfs_sb.c b/fs/xfs/libxfs/xfs_sb.c
index 4742514..a0b071d 100644
--- a/fs/xfs/libxfs/xfs_sb.c
+++ b/fs/xfs/libxfs/xfs_sb.c
@@ -35,6 +35,7 @@
#include "xfs_bmap_btree.h"
#include "xfs_alloc_btree.h"
#include "xfs_ialloc_btree.h"
+#include "xfs_log.h"
/*
* Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -163,6 +164,15 @@ xfs_mount_validate_sb(
"Filesystem can not be safely mounted by this kernel.");
return -EINVAL;
}
+ } else if (xfs_sb_version_hascrc(sbp)) {
+ /*
+ * We can't read verify the sb LSN because the read verifier is
+ * called before the log is allocated and processed. We know the
+ * log is set up before write verifier (!check_version) calls,
+ * so just check it here.
+ */
+ if (!xfs_log_check_lsn(mp, sbp->sb_lsn))
+ return -EFSCORRUPTED;
}
if (xfs_sb_version_has_pquotino(sbp)) {
diff --git a/fs/xfs/libxfs/xfs_symlink_remote.c b/fs/xfs/libxfs/xfs_symlink_remote.c
index 8f8af05..cb6fd20 100644
--- a/fs/xfs/libxfs/xfs_symlink_remote.c
+++ b/fs/xfs/libxfs/xfs_symlink_remote.c
@@ -31,6 +31,7 @@
#include "xfs_cksum.h"
#include "xfs_trans.h"
#include "xfs_buf_item.h"
+#include "xfs_log.h"
/*
@@ -60,6 +61,7 @@ xfs_symlink_hdr_set(
if (!xfs_sb_version_hascrc(&mp->m_sb))
return 0;
+ memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr));
dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC);
dsl->sl_offset = cpu_to_be32(offset);
dsl->sl_bytes = cpu_to_be32(size);
@@ -116,6 +118,8 @@ xfs_symlink_verify(
return false;
if (dsl->sl_owner == 0)
return false;
+ if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn)))
+ return false;
return true;
}
@@ -183,6 +187,7 @@ xfs_symlink_local_to_remote(
if (!xfs_sb_version_hascrc(&mp->m_sb)) {
bp->b_ops = NULL;
memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes);
+ xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1);
return;
}
@@ -198,4 +203,6 @@ xfs_symlink_local_to_remote(
buf = bp->b_addr;
buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp);
memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes);
+ xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) +
+ ifp->if_bytes - 1);
}
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 4b64167..2d5df1f 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -37,16 +37,19 @@
STATIC struct posix_acl *
xfs_acl_from_disk(
- struct xfs_acl *aclp,
- int max_entries)
+ const struct xfs_acl *aclp,
+ int len,
+ int max_entries)
{
struct posix_acl_entry *acl_e;
struct posix_acl *acl;
- struct xfs_acl_entry *ace;
+ const struct xfs_acl_entry *ace;
unsigned int count, i;
+ if (len < sizeof(*aclp))
+ return ERR_PTR(-EFSCORRUPTED);
count = be32_to_cpu(aclp->acl_cnt);
- if (count > max_entries)
+ if (count > max_entries || XFS_ACL_SIZE(count) != len)
return ERR_PTR(-EFSCORRUPTED);
acl = posix_acl_alloc(count, GFP_KERNEL);
@@ -160,10 +163,11 @@ xfs_get_acl(struct inode *inode, int type)
*/
if (error == -ENOATTR)
goto out_update_cache;
+ acl = ERR_PTR(error);
goto out;
}
- acl = xfs_acl_from_disk(xfs_acl, XFS_ACL_MAX_ENTRIES(ip->i_mount));
+ acl = xfs_acl_from_disk(xfs_acl, len, XFS_ACL_MAX_ENTRIES(ip->i_mount));
if (IS_ERR(acl))
goto out;
@@ -248,29 +252,6 @@ xfs_set_mode(struct inode *inode, umode_t mode)
return error;
}
-static int
-xfs_acl_exists(struct inode *inode, unsigned char *name)
-{
- int len = XFS_ACL_MAX_SIZE(XFS_M(inode->i_sb));
-
- return (xfs_attr_get(XFS_I(inode), name, NULL, &len,
- ATTR_ROOT|ATTR_KERNOVAL) == 0);
-}
-
-int
-posix_acl_access_exists(struct inode *inode)
-{
- return xfs_acl_exists(inode, SGI_ACL_FILE);
-}
-
-int
-posix_acl_default_exists(struct inode *inode)
-{
- if (!S_ISDIR(inode->i_mode))
- return 0;
- return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
-}
-
int
xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
{
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 3841b07..286fa89 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -20,20 +20,18 @@
struct inode;
struct posix_acl;
-struct xfs_inode;
#ifdef CONFIG_XFS_POSIX_ACL
extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int posix_acl_access_exists(struct inode *inode);
-extern int posix_acl_default_exists(struct inode *inode);
#else
static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
{
return NULL;
}
# define xfs_set_acl NULL
-# define posix_acl_access_exists(inode) 0
-# define posix_acl_default_exists(inode) 0
#endif /* CONFIG_XFS_POSIX_ACL */
+
+extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags);
+
#endif /* __XFS_ACL_H__ */
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 50ab287..29e7e5d 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -172,6 +172,12 @@ xfs_setfilesize_ioend(
current_set_flags_nested(&tp->t_pflags, PF_FSTRANS);
__sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS);
+ /* we abort the update if there was an IO error */
+ if (ioend->io_error) {
+ xfs_trans_cancel(tp);
+ return ioend->io_error;
+ }
+
return xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size);
}
@@ -212,14 +218,17 @@ xfs_end_io(
ioend->io_error = -EIO;
goto done;
}
- if (ioend->io_error)
- goto done;
/*
* For unwritten extents we need to issue transactions to convert a
* range to normal written extens after the data I/O has finished.
+ * Detecting and handling completion IO errors is done individually
+ * for each case as different cleanup operations need to be performed
+ * on error.
*/
if (ioend->io_type == XFS_IO_UNWRITTEN) {
+ if (ioend->io_error)
+ goto done;
error = xfs_iomap_write_unwritten(ip, ioend->io_offset,
ioend->io_size);
} else if (ioend->io_append_trans) {
@@ -1250,13 +1259,28 @@ xfs_vm_releasepage(
* the DIO. There is only going to be one reference to the ioend and its life
* cycle is constrained by the DIO completion code. hence we don't need
* reference counting here.
+ *
+ * Note that for DIO, an IO to the highest supported file block offset (i.e.
+ * 2^63 - 1FSB bytes) will result in the offset + count overflowing a signed 64
+ * bit variable. Hence if we see this overflow, we have to assume that the IO is
+ * extending the file size. We won't know for sure until IO completion is run
+ * and the actual max write offset is communicated to the IO completion
+ * routine.
+ *
+ * For DAX page faults, we are preparing to never see unwritten extents here,
+ * nor should we ever extend the inode size. Hence we will soon have nothing to
+ * do here for this case, ensuring we don't have to provide an IO completion
+ * callback to free an ioend that we don't actually need for a fault into the
+ * page at offset (2^63 - 1FSB) bytes.
*/
+
static void
xfs_map_direct(
struct inode *inode,
struct buffer_head *bh_result,
struct xfs_bmbt_irec *imap,
- xfs_off_t offset)
+ xfs_off_t offset,
+ bool dax_fault)
{
struct xfs_ioend *ioend;
xfs_off_t size = bh_result->b_size;
@@ -1269,6 +1293,13 @@ xfs_map_direct(
trace_xfs_gbmap_direct(XFS_I(inode), offset, size, type, imap);
+ if (dax_fault) {
+ ASSERT(type == XFS_IO_OVERWRITE);
+ trace_xfs_gbmap_direct_none(XFS_I(inode), offset, size, type,
+ imap);
+ return;
+ }
+
if (bh_result->b_private) {
ioend = bh_result->b_private;
ASSERT(ioend->io_size > 0);
@@ -1283,7 +1314,8 @@ xfs_map_direct(
ioend->io_size, ioend->io_type,
imap);
} else if (type == XFS_IO_UNWRITTEN ||
- offset + size > i_size_read(inode)) {
+ offset + size > i_size_read(inode) ||
+ offset + size < 0) {
ioend = xfs_alloc_ioend(inode, type);
ioend->io_offset = offset;
ioend->io_size = size;
@@ -1345,7 +1377,8 @@ __xfs_get_blocks(
sector_t iblock,
struct buffer_head *bh_result,
int create,
- bool direct)
+ bool direct,
+ bool dax_fault)
{
struct xfs_inode *ip = XFS_I(inode);
struct xfs_mount *mp = ip->i_mount;
@@ -1393,18 +1426,20 @@ __xfs_get_blocks(
if (error)
goto out_unlock;
+ /* for DAX, we convert unwritten extents directly */
if (create &&
(!nimaps ||
(imap.br_startblock == HOLESTARTBLOCK ||
- imap.br_startblock == DELAYSTARTBLOCK))) {
+ imap.br_startblock == DELAYSTARTBLOCK) ||
+ (IS_DAX(inode) && ISUNWRITTEN(&imap)))) {
if (direct || xfs_get_extsz_hint(ip)) {
/*
- * Drop the ilock in preparation for starting the block
- * allocation transaction. It will be retaken
- * exclusively inside xfs_iomap_write_direct for the
- * actual allocation.
+ * xfs_iomap_write_direct() expects the shared lock. It
+ * is unlocked on return.
*/
- xfs_iunlock(ip, lockmode);
+ if (lockmode == XFS_ILOCK_EXCL)
+ xfs_ilock_demote(ip, lockmode);
+
error = xfs_iomap_write_direct(ip, offset, size,
&imap, nimaps);
if (error)
@@ -1441,6 +1476,12 @@ __xfs_get_blocks(
goto out_unlock;
}
+ if (IS_DAX(inode) && create) {
+ ASSERT(!ISUNWRITTEN(&imap));
+ /* zeroing is not needed at a higher layer */
+ new = 0;
+ }
+
/* trim mapping down to size requested */
if (direct || size > (1 << inode->i_blkbits))
xfs_map_trim_size(inode, iblock, bh_result,
@@ -1458,7 +1499,8 @@ __xfs_get_blocks(
set_buffer_unwritten(bh_result);
/* direct IO needs special help */
if (create && direct)
- xfs_map_direct(inode, bh_result, &imap, offset);
+ xfs_map_direct(inode, bh_result, &imap, offset,
+ dax_fault);
}
/*
@@ -1505,7 +1547,7 @@ xfs_get_blocks(
struct buffer_head *bh_result,
int create)
{
- return __xfs_get_blocks(inode, iblock, bh_result, create, false);
+ return __xfs_get_blocks(inode, iblock, bh_result, create, false, false);
}
int
@@ -1515,7 +1557,17 @@ xfs_get_blocks_direct(
struct buffer_head *bh_result,
int create)
{
- return __xfs_get_blocks(inode, iblock, bh_result, create, true);
+ return __xfs_get_blocks(inode, iblock, bh_result, create, true, false);
+}
+
+int
+xfs_get_blocks_dax_fault(
+ struct inode *inode,
+ sector_t iblock,
+ struct buffer_head *bh_result,
+ int create)
+{
+ return __xfs_get_blocks(inode, iblock, bh_result, create, true, true);
}
static void
@@ -1614,45 +1666,6 @@ xfs_end_io_direct_write(
__xfs_end_io_direct_write(inode, ioend, offset, size);
}
-/*
- * For DAX we need a mapping buffer callback for unwritten extent conversion
- * when page faults allocate blocks and then zero them. Note that in this
- * case the mapping indicated by the ioend may extend beyond EOF. We most
- * definitely do not want to extend EOF here, so we trim back the ioend size to
- * EOF.
- */
-#ifdef CONFIG_FS_DAX
-void
-xfs_end_io_dax_write(
- struct buffer_head *bh,
- int uptodate)
-{
- struct xfs_ioend *ioend = bh->b_private;
- struct inode *inode = ioend->io_inode;
- ssize_t size = ioend->io_size;
-
- ASSERT(IS_DAX(ioend->io_inode));
-
- /* if there was an error zeroing, then don't convert it */
- if (!uptodate)
- ioend->io_error = -EIO;
-
- /*
- * Trim update to EOF, so we don't extend EOF during unwritten extent
- * conversion of partial EOF blocks.
- */
- spin_lock(&XFS_I(inode)->i_flags_lock);
- if (ioend->io_offset + size > i_size_read(inode))
- size = i_size_read(inode) - ioend->io_offset;
- spin_unlock(&XFS_I(inode)->i_flags_lock);
-
- __xfs_end_io_direct_write(inode, ioend, ioend->io_offset, size);
-
-}
-#else
-void xfs_end_io_dax_write(struct buffer_head *bh, int uptodate) { }
-#endif
-
static inline ssize_t
xfs_vm_do_dio(
struct inode *inode,
diff --git a/fs/xfs/xfs_aops.h b/fs/xfs/xfs_aops.h
index 86afd1a..f6ffc9a 100644
--- a/fs/xfs/xfs_aops.h
+++ b/fs/xfs/xfs_aops.h
@@ -58,7 +58,8 @@ int xfs_get_blocks(struct inode *inode, sector_t offset,
struct buffer_head *map_bh, int create);
int xfs_get_blocks_direct(struct inode *inode, sector_t offset,
struct buffer_head *map_bh, int create);
-void xfs_end_io_dax_write(struct buffer_head *bh, int uptodate);
+int xfs_get_blocks_dax_fault(struct inode *inode, sector_t offset,
+ struct buffer_head *map_bh, int create);
extern void xfs_count_page_state(struct page *, int *, int *);
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index 65fb37a..0ef7c2e 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -511,7 +511,7 @@ xfs_attr_list_int(
xfs_inode_t *dp = context->dp;
uint lock_mode;
- XFS_STATS_INC(xs_attr_list);
+ XFS_STATS_INC(dp->i_mount, xs_attr_list);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return -EIO;
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index 3bf4ad0..dbae649 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -57,6 +57,35 @@ xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb)
}
/*
+ * Routine to zero an extent on disk allocated to the specific inode.
+ *
+ * The VFS functions take a linearised filesystem block offset, so we have to
+ * convert the sparse xfs fsb to the right format first.
+ * VFS types are real funky, too.
+ */
+int
+xfs_zero_extent(
+ struct xfs_inode *ip,
+ xfs_fsblock_t start_fsb,
+ xfs_off_t count_fsb)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_daddr_t sector = xfs_fsb_to_db(ip, start_fsb);
+ sector_t block = XFS_BB_TO_FSBT(mp, sector);
+ ssize_t size = XFS_FSB_TO_B(mp, count_fsb);
+
+ if (IS_DAX(VFS_I(ip)))
+ return dax_clear_blocks(VFS_I(ip), block, size);
+
+ /*
+ * let the block layer decide on the fastest method of
+ * implementing the zeroing.
+ */
+ return sb_issue_zeroout(mp->m_super, block, count_fsb, GFP_NOFS);
+
+}
+
+/*
* Routine to be called at transaction's end by xfs_bmapi, xfs_bunmapi
* caller. Frees all the extents that need freeing, which must be done
* last due to locking considerations. We never free any extents in
@@ -229,6 +258,13 @@ xfs_bmap_rtalloc(
xfs_trans_mod_dquot_byino(ap->tp, ap->ip,
ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT :
XFS_TRANS_DQ_RTBCOUNT, (long) ralen);
+
+ /* Zero the extent if we were asked to do so */
+ if (ap->userdata & XFS_ALLOC_USERDATA_ZERO) {
+ error = xfs_zero_extent(ap->ip, ap->blkno, ap->length);
+ if (error)
+ return error;
+ }
} else {
ap->length = 0;
}
@@ -1027,7 +1063,7 @@ xfs_alloc_file_space(
xfs_bmap_init(&free_list, &firstfsb);
error = xfs_bmapi_write(tp, ip, startoffset_fsb,
allocatesize_fsb, alloc_type, &firstfsb,
- 0, imapp, &nimaps, &free_list);
+ resblks, imapp, &nimaps, &free_list);
if (error) {
goto error0;
}
diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c
index 8ecffb3..ace91e7 100644
--- a/fs/xfs/xfs_buf.c
+++ b/fs/xfs/xfs_buf.c
@@ -201,7 +201,7 @@ _xfs_buf_alloc(
atomic_set(&bp->b_pin_count, 0);
init_waitqueue_head(&bp->b_waiters);
- XFS_STATS_INC(xb_create);
+ XFS_STATS_INC(target->bt_mount, xb_create);
trace_xfs_buf_init(bp, _RET_IP_);
return bp;
@@ -354,15 +354,16 @@ retry:
*/
if (!(++retries % 100))
xfs_err(NULL,
- "possible memory allocation deadlock in %s (mode:0x%x)",
+ "%s(%u) possible memory allocation deadlock in %s (mode:0x%x)",
+ current->comm, current->pid,
__func__, gfp_mask);
- XFS_STATS_INC(xb_page_retries);
+ XFS_STATS_INC(bp->b_target->bt_mount, xb_page_retries);
congestion_wait(BLK_RW_ASYNC, HZ/50);
goto retry;
}
- XFS_STATS_INC(xb_page_found);
+ XFS_STATS_INC(bp->b_target->bt_mount, xb_page_found);
nbytes = min_t(size_t, size, PAGE_SIZE - offset);
size -= nbytes;
@@ -516,7 +517,7 @@ _xfs_buf_find(
new_bp->b_pag = pag;
spin_unlock(&pag->pag_buf_lock);
} else {
- XFS_STATS_INC(xb_miss_locked);
+ XFS_STATS_INC(btp->bt_mount, xb_miss_locked);
spin_unlock(&pag->pag_buf_lock);
xfs_perag_put(pag);
}
@@ -529,11 +530,11 @@ found:
if (!xfs_buf_trylock(bp)) {
if (flags & XBF_TRYLOCK) {
xfs_buf_rele(bp);
- XFS_STATS_INC(xb_busy_locked);
+ XFS_STATS_INC(btp->bt_mount, xb_busy_locked);
return NULL;
}
xfs_buf_lock(bp);
- XFS_STATS_INC(xb_get_locked_waited);
+ XFS_STATS_INC(btp->bt_mount, xb_get_locked_waited);
}
/*
@@ -549,7 +550,7 @@ found:
}
trace_xfs_buf_find(bp, flags, _RET_IP_);
- XFS_STATS_INC(xb_get_locked);
+ XFS_STATS_INC(btp->bt_mount, xb_get_locked);
return bp;
}
@@ -603,7 +604,7 @@ found:
}
}
- XFS_STATS_INC(xb_get);
+ XFS_STATS_INC(target->bt_mount, xb_get);
trace_xfs_buf_get(bp, flags, _RET_IP_);
return bp;
}
@@ -643,7 +644,7 @@ xfs_buf_read_map(
trace_xfs_buf_read(bp, flags, _RET_IP_);
if (!XFS_BUF_ISDONE(bp)) {
- XFS_STATS_INC(xb_get_read);
+ XFS_STATS_INC(target->bt_mount, xb_get_read);
bp->b_ops = ops;
_xfs_buf_read(bp, flags);
} else if (flags & XBF_ASYNC) {
@@ -1631,13 +1632,9 @@ xfs_setsize_buftarg(
btp->bt_meta_sectormask = sectorsize - 1;
if (set_blocksize(btp->bt_bdev, sectorsize)) {
- char name[BDEVNAME_SIZE];
-
- bdevname(btp->bt_bdev, name);
-
xfs_warn(btp->bt_mount,
- "Cannot set_blocksize to %u on device %s",
- sectorsize, name);
+ "Cannot set_blocksize to %u on device %pg",
+ sectorsize, btp->bt_bdev);
return -EINVAL;
}
diff --git a/fs/xfs/xfs_dir2_readdir.c b/fs/xfs/xfs_dir2_readdir.c
index a989a9c..642d55d 100644
--- a/fs/xfs/xfs_dir2_readdir.c
+++ b/fs/xfs/xfs_dir2_readdir.c
@@ -666,7 +666,7 @@ xfs_readdir(
return -EIO;
ASSERT(S_ISDIR(dp->i_d.di_mode));
- XFS_STATS_INC(xs_dir_getdents);
+ XFS_STATS_INC(dp->i_mount, xs_dir_getdents);
args.dp = dp;
args.geo = dp->i_mount->m_dir_geo;
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index 30cb3af..7ac6c5c 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -75,9 +75,9 @@ xfs_qm_dqdestroy(
ASSERT(list_empty(&dqp->q_lru));
mutex_destroy(&dqp->q_qlock);
- kmem_zone_free(xfs_qm_dqzone, dqp);
- XFS_STATS_DEC(xs_qm_dquot);
+ XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot);
+ kmem_zone_free(xfs_qm_dqzone, dqp);
}
/*
@@ -605,7 +605,7 @@ xfs_qm_dqread(
break;
}
- XFS_STATS_INC(xs_qm_dquot);
+ XFS_STATS_INC(mp, xs_qm_dquot);
trace_xfs_dqread(dqp);
@@ -747,12 +747,12 @@ restart:
mutex_unlock(&qi->qi_tree_lock);
trace_xfs_dqget_hit(dqp);
- XFS_STATS_INC(xs_qm_dqcachehits);
+ XFS_STATS_INC(mp, xs_qm_dqcachehits);
*O_dqpp = dqp;
return 0;
}
mutex_unlock(&qi->qi_tree_lock);
- XFS_STATS_INC(xs_qm_dqcachemisses);
+ XFS_STATS_INC(mp, xs_qm_dqcachemisses);
/*
* Dquot cache miss. We don't want to keep the inode lock across
@@ -806,7 +806,7 @@ restart:
mutex_unlock(&qi->qi_tree_lock);
trace_xfs_dqget_dup(dqp);
xfs_qm_dqdestroy(dqp);
- XFS_STATS_INC(xs_qm_dquot_dups);
+ XFS_STATS_INC(mp, xs_qm_dquot_dups);
goto restart;
}
@@ -846,7 +846,7 @@ xfs_qm_dqput(
trace_xfs_dqput_free(dqp);
if (list_lru_add(&qi->qi_lru, &dqp->q_lru))
- XFS_STATS_INC(xs_qm_dquot_unused);
+ XFS_STATS_INC(dqp->q_mount, xs_qm_dquot_unused);
}
xfs_dqunlock(dqp);
}
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e78feb4..f5392ab 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -242,19 +242,30 @@ xfs_file_fsync(
}
/*
- * All metadata updates are logged, which means that we just have
- * to flush the log up to the latest LSN that touched the inode.
+ * All metadata updates are logged, which means that we just have to
+ * flush the log up to the latest LSN that touched the inode. If we have
+ * concurrent fsync/fdatasync() calls, we need them to all block on the
+ * log force before we clear the ili_fsync_fields field. This ensures
+ * that we don't get a racing sync operation that does not wait for the
+ * metadata to hit the journal before returning. If we race with
+ * clearing the ili_fsync_fields, then all that will happen is the log
+ * force will do nothing as the lsn will already be on disk. We can't
+ * race with setting ili_fsync_fields because that is done under
+ * XFS_ILOCK_EXCL, and that can't happen because we hold the lock shared
+ * until after the ili_fsync_fields is cleared.
*/
xfs_ilock(ip, XFS_ILOCK_SHARED);
if (xfs_ipincount(ip)) {
if (!datasync ||
- (ip->i_itemp->ili_fields & ~XFS_ILOG_TIMESTAMP))
+ (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP))
lsn = ip->i_itemp->ili_last_lsn;
}
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- if (lsn)
+ if (lsn) {
error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed);
+ ip->i_itemp->ili_fsync_fields = 0;
+ }
+ xfs_iunlock(ip, XFS_ILOCK_SHARED);
/*
* If we only have a single device, and the log force about was
@@ -287,7 +298,7 @@ xfs_file_read_iter(
xfs_fsize_t n;
loff_t pos = iocb->ki_pos;
- XFS_STATS_INC(xs_read_calls);
+ XFS_STATS_INC(mp, xs_read_calls);
if (unlikely(iocb->ki_flags & IOCB_DIRECT))
ioflags |= XFS_IO_ISDIRECT;
@@ -365,7 +376,7 @@ xfs_file_read_iter(
ret = generic_file_read_iter(iocb, to);
if (ret > 0)
- XFS_STATS_ADD(xs_read_bytes, ret);
+ XFS_STATS_ADD(mp, xs_read_bytes, ret);
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
return ret;
@@ -383,7 +394,7 @@ xfs_file_splice_read(
int ioflags = 0;
ssize_t ret;
- XFS_STATS_INC(xs_read_calls);
+ XFS_STATS_INC(ip->i_mount, xs_read_calls);
if (infilp->f_mode & FMODE_NOCMTIME)
ioflags |= XFS_IO_INVIS;
@@ -401,7 +412,7 @@ xfs_file_splice_read(
else
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
if (ret > 0)
- XFS_STATS_ADD(xs_read_bytes, ret);
+ XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
return ret;
@@ -482,6 +493,8 @@ xfs_zero_eof(
ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT(offset > isize);
+ trace_xfs_zero_eof(ip, isize, offset - isize);
+
/*
* First handle zeroing the block on which isize resides.
*
@@ -574,6 +587,7 @@ xfs_file_aio_write_checks(
struct xfs_inode *ip = XFS_I(inode);
ssize_t error = 0;
size_t count = iov_iter_count(from);
+ bool drained_dio = false;
restart:
error = generic_write_checks(iocb, from);
@@ -611,12 +625,13 @@ restart:
bool zero = false;
spin_unlock(&ip->i_flags_lock);
- if (*iolock == XFS_IOLOCK_SHARED) {
- xfs_rw_iunlock(ip, *iolock);
- *iolock = XFS_IOLOCK_EXCL;
- xfs_rw_ilock(ip, *iolock);
- iov_iter_reexpand(from, count);
-
+ if (!drained_dio) {
+ if (*iolock == XFS_IOLOCK_SHARED) {
+ xfs_rw_iunlock(ip, *iolock);
+ *iolock = XFS_IOLOCK_EXCL;
+ xfs_rw_ilock(ip, *iolock);
+ iov_iter_reexpand(from, count);
+ }
/*
* We now have an IO submission barrier in place, but
* AIO can do EOF updates during IO completion and hence
@@ -626,6 +641,7 @@ restart:
* no-op.
*/
inode_dio_wait(inode);
+ drained_dio = true;
goto restart;
}
error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), &zero);
@@ -867,7 +883,7 @@ xfs_file_write_iter(
ssize_t ret;
size_t ocount = iov_iter_count(from);
- XFS_STATS_INC(xs_write_calls);
+ XFS_STATS_INC(ip->i_mount, xs_write_calls);
if (ocount == 0)
return 0;
@@ -883,7 +899,7 @@ xfs_file_write_iter(
if (ret > 0) {
ssize_t err;
- XFS_STATS_ADD(xs_write_bytes, ret);
+ XFS_STATS_ADD(ip->i_mount, xs_write_bytes, ret);
/* Handle various SYNC-type writes */
err = generic_write_sync(file, iocb->ki_pos - ret, ret);
@@ -1477,7 +1493,7 @@ xfs_file_llseek(
*
* mmap_sem (MM)
* sb_start_pagefault(vfs, freeze)
- * i_mmap_lock (XFS - truncate serialisation)
+ * i_mmaplock (XFS - truncate serialisation)
* page_lock (MM)
* i_lock (XFS - extent map serialisation)
*/
@@ -1503,10 +1519,9 @@ xfs_filemap_page_mkwrite(
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
if (IS_DAX(inode)) {
- ret = __dax_mkwrite(vma, vmf, xfs_get_blocks_direct,
- xfs_end_io_dax_write);
+ ret = __dax_mkwrite(vma, vmf, xfs_get_blocks_dax_fault, NULL);
} else {
- ret = __block_page_mkwrite(vma, vmf, xfs_get_blocks);
+ ret = block_page_mkwrite(vma, vmf, xfs_get_blocks);
ret = block_page_mkwrite_return(ret);
}
@@ -1538,7 +1553,7 @@ xfs_filemap_fault(
* changes to xfs_get_blocks_direct() to map unwritten extent
* ioend for conversion on read-only mappings.
*/
- ret = __dax_fault(vma, vmf, xfs_get_blocks_direct, NULL);
+ ret = __dax_fault(vma, vmf, xfs_get_blocks_dax_fault, NULL);
} else
ret = filemap_fault(vma, vmf);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
@@ -1546,6 +1561,13 @@ xfs_filemap_fault(
return ret;
}
+/*
+ * Similar to xfs_filemap_fault(), the DAX fault path can call into here on
+ * both read and write faults. Hence we need to handle both cases. There is no
+ * ->pmd_mkwrite callout for huge pages, so we have a single function here to
+ * handle both cases here. @flags carries the information on the type of fault
+ * occuring.
+ */
STATIC int
xfs_filemap_pmd_fault(
struct vm_area_struct *vma,
@@ -1562,15 +1584,54 @@ xfs_filemap_pmd_fault(
trace_xfs_filemap_pmd_fault(ip);
- sb_start_pagefault(inode->i_sb);
- file_update_time(vma->vm_file);
+ if (flags & FAULT_FLAG_WRITE) {
+ sb_start_pagefault(inode->i_sb);
+ file_update_time(vma->vm_file);
+ }
+
xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
- ret = __dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_direct,
- xfs_end_io_dax_write);
+ ret = __dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_dax_fault,
+ NULL);
xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED);
- sb_end_pagefault(inode->i_sb);
+ if (flags & FAULT_FLAG_WRITE)
+ sb_end_pagefault(inode->i_sb);
+
+ return ret;
+}
+
+/*
+ * pfn_mkwrite was originally inteneded to ensure we capture time stamp
+ * updates on write faults. In reality, it's need to serialise against
+ * truncate similar to page_mkwrite. Hence we open-code dax_pfn_mkwrite()
+ * here and cycle the XFS_MMAPLOCK_SHARED to ensure we serialise the fault
+ * barrier in place.
+ */
+static int
+xfs_filemap_pfn_mkwrite(
+ struct vm_area_struct *vma,
+ struct vm_fault *vmf)
+{
+
+ struct inode *inode = file_inode(vma->vm_file);
+ struct xfs_inode *ip = XFS_I(inode);
+ int ret = VM_FAULT_NOPAGE;
+ loff_t size;
+
+ trace_xfs_filemap_pfn_mkwrite(ip);
+
+ sb_start_pagefault(inode->i_sb);
+ file_update_time(vma->vm_file);
+
+ /* check if the faulting page hasn't raced with truncate */
+ xfs_ilock(ip, XFS_MMAPLOCK_SHARED);
+ size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ if (vmf->pgoff >= size)
+ ret = VM_FAULT_SIGBUS;
+ xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);
+ sb_end_pagefault(inode->i_sb);
return ret;
+
}
static const struct vm_operations_struct xfs_file_vm_ops = {
@@ -1578,6 +1639,7 @@ static const struct vm_operations_struct xfs_file_vm_ops = {
.pmd_fault = xfs_filemap_pmd_fault,
.map_pages = filemap_map_pages,
.page_mkwrite = xfs_filemap_page_mkwrite,
+ .pfn_mkwrite = xfs_filemap_pfn_mkwrite,
};
STATIC int
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 0a326bd..d7a490f 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -63,7 +63,7 @@ xfs_inode_alloc(
return NULL;
}
- XFS_STATS_INC(vn_active);
+ XFS_STATS_INC(mp, vn_active);
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!spin_is_locked(&ip->i_flags_lock));
ASSERT(!xfs_isiflocked(ip));
@@ -129,7 +129,7 @@ xfs_inode_free(
/* asserts to verify all state is correct here */
ASSERT(atomic_read(&ip->i_pincount) == 0);
ASSERT(!xfs_isiflocked(ip));
- XFS_STATS_DEC(vn_active);
+ XFS_STATS_DEC(ip->i_mount, vn_active);
call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback);
}
@@ -159,7 +159,7 @@ xfs_iget_cache_hit(
spin_lock(&ip->i_flags_lock);
if (ip->i_ino != ino) {
trace_xfs_iget_skip(ip);
- XFS_STATS_INC(xs_ig_frecycle);
+ XFS_STATS_INC(mp, xs_ig_frecycle);
error = -EAGAIN;
goto out_error;
}
@@ -177,7 +177,7 @@ xfs_iget_cache_hit(
*/
if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) {
trace_xfs_iget_skip(ip);
- XFS_STATS_INC(xs_ig_frecycle);
+ XFS_STATS_INC(mp, xs_ig_frecycle);
error = -EAGAIN;
goto out_error;
}
@@ -259,7 +259,7 @@ xfs_iget_cache_hit(
xfs_ilock(ip, lock_flags);
xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE);
- XFS_STATS_INC(xs_ig_found);
+ XFS_STATS_INC(mp, xs_ig_found);
return 0;
@@ -342,7 +342,7 @@ xfs_iget_cache_miss(
error = radix_tree_insert(&pag->pag_ici_root, agino, ip);
if (unlikely(error)) {
WARN_ON(error != -EEXIST);
- XFS_STATS_INC(xs_ig_dup);
+ XFS_STATS_INC(mp, xs_ig_dup);
error = -EAGAIN;
goto out_preload_end;
}
@@ -412,7 +412,7 @@ xfs_iget(
if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
return -EINVAL;
- XFS_STATS_INC(xs_ig_attempts);
+ XFS_STATS_INC(mp, xs_ig_attempts);
/* get the perag structure and ensure that it's inode capable */
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino));
@@ -429,7 +429,7 @@ again:
goto out_error_or_again;
} else {
rcu_read_unlock();
- XFS_STATS_INC(xs_ig_missed);
+ XFS_STATS_INC(mp, xs_ig_missed);
error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip,
flags, lock_flags);
@@ -965,7 +965,7 @@ reclaim:
xfs_ifunlock(ip);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
- XFS_STATS_INC(xs_ig_reclaims);
+ XFS_STATS_INC(ip->i_mount, xs_ig_reclaims);
/*
* Remove the inode from the per-AG radix tree.
*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index dc40a6d..8ee3939 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2365,6 +2365,7 @@ retry:
iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0;
+ iip->ili_fsync_fields = 0;
iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
&iip->ili_item.li_lsn);
@@ -3271,8 +3272,8 @@ xfs_iflush_cluster(
}
if (clcount) {
- XFS_STATS_INC(xs_icluster_flushcnt);
- XFS_STATS_ADD(xs_icluster_flushinode, clcount);
+ XFS_STATS_INC(mp, xs_icluster_flushcnt);
+ XFS_STATS_ADD(mp, xs_icluster_flushinode, clcount);
}
out_free:
@@ -3345,7 +3346,7 @@ xfs_iflush(
struct xfs_dinode *dip;
int error;
- XFS_STATS_INC(xs_iflush_count);
+ XFS_STATS_INC(mp, xs_iflush_count);
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
ASSERT(xfs_isiflocked(ip));
@@ -3560,6 +3561,7 @@ xfs_iflush_int(
*/
iip->ili_last_fields = iip->ili_fields;
iip->ili_fields = 0;
+ iip->ili_fsync_fields = 0;
iip->ili_logged = 1;
xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn,
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 62bd80f..d14b12b 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -719,6 +719,7 @@ xfs_iflush_abort(
* attempted.
*/
iip->ili_fields = 0;
+ iip->ili_fsync_fields = 0;
}
/*
* Release the inode's flush lock since we're done with it.
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index 488d812..4c7722e 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -34,6 +34,7 @@ typedef struct xfs_inode_log_item {
unsigned short ili_logged; /* flushed logged data */
unsigned int ili_last_fields; /* fields when flushed */
unsigned int ili_fields; /* fields to be logged */
+ unsigned int ili_fsync_fields; /* logged since last fsync */
} xfs_inode_log_item_t;
static inline int xfs_inode_clean(xfs_inode_t *ip)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index ea7d85a..d42738d 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -40,6 +40,7 @@
#include "xfs_symlink.h"
#include "xfs_trans.h"
#include "xfs_pnfs.h"
+#include "xfs_acl.h"
#include <linux/capability.h>
#include <linux/dcache.h>
@@ -411,7 +412,7 @@ xfs_attrlist_by_handle(
if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
return -EFAULT;
if (al_hreq.buflen < sizeof(struct attrlist) ||
- al_hreq.buflen > XATTR_LIST_MAX)
+ al_hreq.buflen > XFS_XATTR_LIST_MAX)
return -EINVAL;
/*
@@ -455,7 +456,7 @@ xfs_attrmulti_attr_get(
unsigned char *kbuf;
int error = -EFAULT;
- if (*len > XATTR_SIZE_MAX)
+ if (*len > XFS_XATTR_SIZE_MAX)
return -EINVAL;
kbuf = kmem_zalloc_large(*len, KM_SLEEP);
if (!kbuf)
@@ -482,17 +483,22 @@ xfs_attrmulti_attr_set(
__uint32_t flags)
{
unsigned char *kbuf;
+ int error;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
- if (len > XATTR_SIZE_MAX)
+ if (len > XFS_XATTR_SIZE_MAX)
return -EINVAL;
kbuf = memdup_user(ubuf, len);
if (IS_ERR(kbuf))
return PTR_ERR(kbuf);
- return xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+ error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+ if (!error)
+ xfs_forget_acl(inode, name, flags);
+ kfree(kbuf);
+ return error;
}
int
@@ -501,9 +507,14 @@ xfs_attrmulti_attr_remove(
unsigned char *name,
__uint32_t flags)
{
+ int error;
+
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
return -EPERM;
- return xfs_attr_remove(XFS_I(inode), name, flags);
+ error = xfs_attr_remove(XFS_I(inode), name, flags);
+ if (!error)
+ xfs_forget_acl(inode, name, flags);
+ return error;
}
STATIC int
@@ -1028,7 +1039,7 @@ xfs_ioctl_setattr_xflags(
xfs_diflags_to_linux(ip);
xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- XFS_STATS_INC(xs_ig_attrchg);
+ XFS_STATS_INC(mp, xs_ig_attrchg);
return 0;
}
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index b88bdc8..1a05d8a 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -356,7 +356,7 @@ xfs_compat_attrlist_by_handle(
sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
return -EFAULT;
if (al_hreq.buflen < sizeof(struct attrlist) ||
- al_hreq.buflen > XATTR_LIST_MAX)
+ al_hreq.buflen > XFS_XATTR_LIST_MAX)
return -EINVAL;
/*
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 1f86033..f4f5b43 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -131,20 +131,30 @@ xfs_iomap_write_direct(
uint qblocks, resblks, resrtextents;
int committed;
int error;
-
- error = xfs_qm_dqattach(ip, 0);
- if (error)
- return error;
+ int lockmode;
+ int bmapi_flags = XFS_BMAPI_PREALLOC;
rt = XFS_IS_REALTIME_INODE(ip);
extsz = xfs_get_extsz_hint(ip);
+ lockmode = XFS_ILOCK_SHARED; /* locked by caller */
+
+ ASSERT(xfs_isilocked(ip, lockmode));
offset_fsb = XFS_B_TO_FSBT(mp, offset);
last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
if ((offset + count) > XFS_ISIZE(ip)) {
+ /*
+ * Assert that the in-core extent list is present since this can
+ * call xfs_iread_extents() and we only have the ilock shared.
+ * This should be safe because the lock was held around a bmapi
+ * call in the caller and we only need it to access the in-core
+ * list.
+ */
+ ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags &
+ XFS_IFEXTENTS);
error = xfs_iomap_eof_align_last_fsb(mp, ip, extsz, &last_fsb);
if (error)
- return error;
+ goto out_unlock;
} else {
if (nmaps && (imap->br_startblock == HOLESTARTBLOCK))
last_fsb = MIN(last_fsb, (xfs_fileoff_t)
@@ -174,9 +184,35 @@ xfs_iomap_write_direct(
}
/*
+ * Drop the shared lock acquired by the caller, attach the dquot if
+ * necessary and move on to transaction setup.
+ */
+ xfs_iunlock(ip, lockmode);
+ error = xfs_qm_dqattach(ip, 0);
+ if (error)
+ return error;
+
+ /*
* Allocate and setup the transaction
*/
tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+
+ /*
+ * For DAX, we do not allocate unwritten extents, but instead we zero
+ * the block before we commit the transaction. Ideally we'd like to do
+ * this outside the transaction context, but if we commit and then crash
+ * we may not have zeroed the blocks and this will be exposed on
+ * recovery of the allocation. Hence we must zero before commit.
+ * Further, if we are mapping unwritten extents here, we need to zero
+ * and convert them to written so that we don't need an unwritten extent
+ * callback for DAX. This also means that we need to be able to dip into
+ * the reserve block pool if there is no space left but we need to do
+ * unwritten extent conversion.
+ */
+ if (IS_DAX(VFS_I(ip))) {
+ bmapi_flags = XFS_BMAPI_CONVERT | XFS_BMAPI_ZERO;
+ tp->t_flags |= XFS_TRANS_RESERVE;
+ }
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_write,
resblks, resrtextents);
/*
@@ -187,7 +223,8 @@ xfs_iomap_write_direct(
return error;
}
- xfs_ilock(ip, XFS_ILOCK_EXCL);
+ lockmode = XFS_ILOCK_EXCL;
+ xfs_ilock(ip, lockmode);
error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag);
if (error)
@@ -202,8 +239,8 @@ xfs_iomap_write_direct(
xfs_bmap_init(&free_list, &firstfsb);
nimaps = 1;
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
- XFS_BMAPI_PREALLOC, &firstfsb, 0,
- imap, &nimaps, &free_list);
+ bmapi_flags, &firstfsb, resblks, imap,
+ &nimaps, &free_list);
if (error)
goto out_bmap_cancel;
@@ -213,6 +250,7 @@ xfs_iomap_write_direct(
error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error)
goto out_bmap_cancel;
+
error = xfs_trans_commit(tp);
if (error)
goto out_unlock;
@@ -229,7 +267,7 @@ xfs_iomap_write_direct(
error = xfs_alert_fsblock_zero(ip, imap);
out_unlock:
- xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ xfs_iunlock(ip, lockmode);
return error;
out_bmap_cancel:
@@ -670,7 +708,7 @@ xfs_iomap_write_allocate(
count_fsb = imap->br_blockcount;
map_start_fsb = imap->br_startoff;
- XFS_STATS_ADD(xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
+ XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb));
while (count_fsb != 0) {
/*
@@ -750,9 +788,9 @@ xfs_iomap_write_allocate(
* pointer that the caller gave to us.
*/
error = xfs_bmapi_write(tp, ip, map_start_fsb,
- count_fsb, 0,
- &first_block, 1,
- imap, &nimaps, &free_list);
+ count_fsb, 0, &first_block,
+ nres, imap, &nimaps,
+ &free_list);
if (error)
goto trans_cancel;
@@ -777,7 +815,7 @@ xfs_iomap_write_allocate(
if ((offset_fsb >= imap->br_startoff) &&
(offset_fsb < (imap->br_startoff +
imap->br_blockcount))) {
- XFS_STATS_INC(xs_xstrat_quick);
+ XFS_STATS_INC(mp, xs_xstrat_quick);
return 0;
}
@@ -866,8 +904,8 @@ xfs_iomap_write_unwritten(
xfs_bmap_init(&free_list, &firstfsb);
nimaps = 1;
error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
- XFS_BMAPI_CONVERT, &firstfsb,
- 1, &imap, &nimaps, &free_list);
+ XFS_BMAPI_CONVERT, &firstfsb, resblks,
+ &imap, &nimaps, &free_list);
if (error)
goto error_on_bmapi_transaction;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 8294132..06eafaf 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -414,13 +414,17 @@ xfs_vn_rename(
* uio is kmalloced for this reason...
*/
STATIC const char *
-xfs_vn_follow_link(
+xfs_vn_get_link(
struct dentry *dentry,
- void **cookie)
+ struct inode *inode,
+ struct delayed_call *done)
{
char *link;
int error = -ENOMEM;
+ if (!dentry)
+ return ERR_PTR(-ECHILD);
+
link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
if (!link)
goto out_err;
@@ -429,7 +433,8 @@ xfs_vn_follow_link(
if (unlikely(error))
goto out_kfree;
- return *cookie = link;
+ set_delayed_call(done, kfree_link, link);
+ return link;
out_kfree:
kfree(link);
@@ -695,7 +700,7 @@ xfs_setattr_nonsize(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- XFS_STATS_INC(xs_ig_attrchg);
+ XFS_STATS_INC(mp, xs_ig_attrchg);
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(tp);
@@ -922,7 +927,7 @@ xfs_setattr_size(
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- XFS_STATS_INC(xs_ig_attrchg);
+ XFS_STATS_INC(mp, xs_ig_attrchg);
if (mp->m_flags & XFS_MOUNT_WSYNC)
xfs_trans_set_sync(tp);
@@ -1172,8 +1177,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
static const struct inode_operations xfs_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = xfs_vn_follow_link,
- .put_link = kfree_put_link,
+ .get_link = xfs_vn_get_link,
.getattr = xfs_vn_getattr,
.setattr = xfs_vn_setattr,
.setxattr = generic_setxattr,
diff --git a/fs/xfs/xfs_linux.h b/fs/xfs/xfs_linux.h
index 85f883d..ec0e239 100644
--- a/fs/xfs/xfs_linux.h
+++ b/fs/xfs/xfs_linux.h
@@ -171,6 +171,13 @@ struct xfs_kobj {
struct completion complete;
};
+struct xstats {
+ struct xfsstats __percpu *xs_stats;
+ struct xfs_kobj xs_kobj;
+};
+
+extern struct xstats xfsstats;
+
/* Kernel uid/gid conversion. These are used to convert to/from the on disk
* uid_t/gid_t types to the kuid_t/kgid_t types that the kernel uses internally.
* The conversion here is type only, the value will remain the same since we
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index aaadee0..f52c72a 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -268,7 +268,7 @@ xlog_grant_head_wait(
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock(&head->lock);
- XFS_STATS_INC(xs_sleep_logspace);
+ XFS_STATS_INC(log->l_mp, xs_sleep_logspace);
trace_xfs_log_grant_sleep(log, tic);
schedule();
@@ -379,7 +379,7 @@ xfs_log_regrant(
if (XLOG_FORCED_SHUTDOWN(log))
return -EIO;
- XFS_STATS_INC(xs_try_logspace);
+ XFS_STATS_INC(mp, xs_try_logspace);
/*
* This is a new transaction on the ticket, so we need to change the
@@ -448,7 +448,7 @@ xfs_log_reserve(
if (XLOG_FORCED_SHUTDOWN(log))
return -EIO;
- XFS_STATS_INC(xs_try_logspace);
+ XFS_STATS_INC(mp, xs_try_logspace);
ASSERT(*ticp == NULL);
tic = xlog_ticket_alloc(log, unit_bytes, cnt, client, permanent,
@@ -1768,7 +1768,7 @@ xlog_sync(
int v2 = xfs_sb_version_haslogv2(&log->l_mp->m_sb);
int size;
- XFS_STATS_INC(xs_log_writes);
+ XFS_STATS_INC(log->l_mp, xs_log_writes);
ASSERT(atomic_read(&iclog->ic_refcnt) == 0);
/* Add for LR header */
@@ -1805,7 +1805,7 @@ xlog_sync(
bp = iclog->ic_bp;
XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn)));
- XFS_STATS_ADD(xs_log_blocks, BTOBB(count));
+ XFS_STATS_ADD(log->l_mp, xs_log_blocks, BTOBB(count));
/* Do we need to split this write into 2 parts? */
if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) {
@@ -2422,11 +2422,20 @@ xlog_write(
&partial_copy_len);
xlog_verify_dest_ptr(log, ptr);
- /* copy region */
+ /*
+ * Copy region.
+ *
+ * Unmount records just log an opheader, so can have
+ * empty payloads with no data region to copy. Hence we
+ * only copy the payload if the vector says it has data
+ * to copy.
+ */
ASSERT(copy_len >= 0);
- memcpy(ptr, reg->i_addr + copy_off, copy_len);
- xlog_write_adv_cnt(&ptr, &len, &log_offset, copy_len);
-
+ if (copy_len > 0) {
+ memcpy(ptr, reg->i_addr + copy_off, copy_len);
+ xlog_write_adv_cnt(&ptr, &len, &log_offset,
+ copy_len);
+ }
copy_len += start_rec_copy + sizeof(xlog_op_header_t);
record_cnt++;
data_cnt += contwr ? copy_len : 0;
@@ -2913,7 +2922,7 @@ restart:
iclog = log->l_iclog;
if (iclog->ic_state != XLOG_STATE_ACTIVE) {
- XFS_STATS_INC(xs_log_noiclogs);
+ XFS_STATS_INC(log->l_mp, xs_log_noiclogs);
/* Wait for log writes to have flushed */
xlog_wait(&log->l_flush_wait, &log->l_icloglock);
@@ -3165,11 +3174,19 @@ xlog_state_switch_iclogs(
}
if (log->l_curr_block >= log->l_logBBsize) {
+ /*
+ * Rewind the current block before the cycle is bumped to make
+ * sure that the combined LSN never transiently moves forward
+ * when the log wraps to the next cycle. This is to support the
+ * unlocked sample of these fields from xlog_valid_lsn(). Most
+ * other cases should acquire l_icloglock.
+ */
+ log->l_curr_block -= log->l_logBBsize;
+ ASSERT(log->l_curr_block >= 0);
+ smp_wmb();
log->l_curr_cycle++;
if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM)
log->l_curr_cycle++;
- log->l_curr_block -= log->l_logBBsize;
- ASSERT(log->l_curr_block >= 0);
}
ASSERT(iclog == log->l_iclog);
log->l_iclog = iclog->ic_next;
@@ -3212,7 +3229,7 @@ _xfs_log_force(
struct xlog_in_core *iclog;
xfs_lsn_t lsn;
- XFS_STATS_INC(xs_log_force);
+ XFS_STATS_INC(mp, xs_log_force);
xlog_cil_force(log);
@@ -3297,7 +3314,7 @@ maybe_sleep:
spin_unlock(&log->l_icloglock);
return -EIO;
}
- XFS_STATS_INC(xs_log_force_sleep);
+ XFS_STATS_INC(mp, xs_log_force_sleep);
xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
/*
* No need to grab the log lock here since we're
@@ -3362,7 +3379,7 @@ _xfs_log_force_lsn(
ASSERT(lsn != 0);
- XFS_STATS_INC(xs_log_force);
+ XFS_STATS_INC(mp, xs_log_force);
lsn = xlog_cil_force_lsn(log, lsn);
if (lsn == NULLCOMMITLSN)
@@ -3411,7 +3428,7 @@ try_again:
(XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) {
ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR));
- XFS_STATS_INC(xs_log_force_sleep);
+ XFS_STATS_INC(mp, xs_log_force_sleep);
xlog_wait(&iclog->ic_prev->ic_write_wait,
&log->l_icloglock);
@@ -3441,7 +3458,7 @@ try_again:
spin_unlock(&log->l_icloglock);
return -EIO;
}
- XFS_STATS_INC(xs_log_force_sleep);
+ XFS_STATS_INC(mp, xs_log_force_sleep);
xlog_wait(&iclog->ic_force_wait, &log->l_icloglock);
/*
* No need to grab the log lock here since we're
@@ -4023,3 +4040,45 @@ xlog_iclogs_empty(
return 1;
}
+/*
+ * Verify that an LSN stamped into a piece of metadata is valid. This is
+ * intended for use in read verifiers on v5 superblocks.
+ */
+bool
+xfs_log_check_lsn(
+ struct xfs_mount *mp,
+ xfs_lsn_t lsn)
+{
+ struct xlog *log = mp->m_log;
+ bool valid;
+
+ /*
+ * norecovery mode skips mount-time log processing and unconditionally
+ * resets the in-core LSN. We can't validate in this mode, but
+ * modifications are not allowed anyways so just return true.
+ */
+ if (mp->m_flags & XFS_MOUNT_NORECOVERY)
+ return true;
+
+ /*
+ * Some metadata LSNs are initialized to NULL (e.g., the agfl). This is
+ * handled by recovery and thus safe to ignore here.
+ */
+ if (lsn == NULLCOMMITLSN)
+ return true;
+
+ valid = xlog_valid_lsn(mp->m_log, lsn);
+
+ /* warn the user about what's gone wrong before verifier failure */
+ if (!valid) {
+ spin_lock(&log->l_icloglock);
+ xfs_warn(mp,
+"Corruption warning: Metadata has LSN (%d:%d) ahead of current LSN (%d:%d). "
+"Please unmount and run xfs_repair (>= v4.3) to resolve.",
+ CYCLE_LSN(lsn), BLOCK_LSN(lsn),
+ log->l_curr_cycle, log->l_curr_block);
+ spin_unlock(&log->l_icloglock);
+ }
+
+ return valid;
+}
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index 09d91d3..aa533a7 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -181,5 +181,6 @@ bool xfs_log_item_in_current_chkpt(struct xfs_log_item *lip);
void xfs_log_work_queue(struct xfs_mount *mp);
void xfs_log_worker(struct work_struct *work);
void xfs_log_quiesce(struct xfs_mount *mp);
+bool xfs_log_check_lsn(struct xfs_mount *, xfs_lsn_t);
#endif /* __XFS_LOG_H__ */
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 950f3f9..8daba74 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -560,4 +560,55 @@ static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock)
remove_wait_queue(wq, &wait);
}
+/*
+ * The LSN is valid so long as it is behind the current LSN. If it isn't, this
+ * means that the next log record that includes this metadata could have a
+ * smaller LSN. In turn, this means that the modification in the log would not
+ * replay.
+ */
+static inline bool
+xlog_valid_lsn(
+ struct xlog *log,
+ xfs_lsn_t lsn)
+{
+ int cur_cycle;
+ int cur_block;
+ bool valid = true;
+
+ /*
+ * First, sample the current lsn without locking to avoid added
+ * contention from metadata I/O. The current cycle and block are updated
+ * (in xlog_state_switch_iclogs()) and read here in a particular order
+ * to avoid false negatives (e.g., thinking the metadata LSN is valid
+ * when it is not).
+ *
+ * The current block is always rewound before the cycle is bumped in
+ * xlog_state_switch_iclogs() to ensure the current LSN is never seen in
+ * a transiently forward state. Instead, we can see the LSN in a
+ * transiently behind state if we happen to race with a cycle wrap.
+ */
+ cur_cycle = ACCESS_ONCE(log->l_curr_cycle);
+ smp_rmb();
+ cur_block = ACCESS_ONCE(log->l_curr_block);
+
+ if ((CYCLE_LSN(lsn) > cur_cycle) ||
+ (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) {
+ /*
+ * If the metadata LSN appears invalid, it's possible the check
+ * above raced with a wrap to the next log cycle. Grab the lock
+ * to check for sure.
+ */
+ spin_lock(&log->l_icloglock);
+ cur_cycle = log->l_curr_cycle;
+ cur_block = log->l_curr_block;
+ spin_unlock(&log->l_icloglock);
+
+ if ((CYCLE_LSN(lsn) > cur_cycle) ||
+ (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block))
+ valid = false;
+ }
+
+ return valid;
+}
+
#endif /* __XFS_LOG_PRIV_H__ */
diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
index 512a094..c5ecaac 100644
--- a/fs/xfs/xfs_log_recover.c
+++ b/fs/xfs/xfs_log_recover.c
@@ -3431,7 +3431,7 @@ xlog_recover_add_to_cont_trans(
* previous record. Copy the rest of the header.
*/
if (list_empty(&trans->r_itemq)) {
- ASSERT(len < sizeof(struct xfs_trans_header));
+ ASSERT(len <= sizeof(struct xfs_trans_header));
if (len > sizeof(struct xfs_trans_header)) {
xfs_warn(log->l_mp, "%s: bad header length", __func__);
return -EIO;
@@ -4609,9 +4609,19 @@ xlog_recover(
int error;
/* find the tail of the log */
- if ((error = xlog_find_tail(log, &head_blk, &tail_blk)))
+ error = xlog_find_tail(log, &head_blk, &tail_blk);
+ if (error)
return error;
+ /*
+ * The superblock was read before the log was available and thus the LSN
+ * could not be verified. Check the superblock LSN against the current
+ * LSN now that it's known.
+ */
+ if (xfs_sb_version_hascrc(&log->l_mp->m_sb) &&
+ !xfs_log_check_lsn(log->l_mp, log->l_mp->m_sb.sb_lsn))
+ return -EINVAL;
+
if (tail_blk != head_blk) {
/* There used to be a comment here:
*
diff --git a/fs/xfs/xfs_message.c b/fs/xfs/xfs_message.c
index d8b6754..11792d8 100644
--- a/fs/xfs/xfs_message.c
+++ b/fs/xfs/xfs_message.c
@@ -17,6 +17,7 @@
#include "xfs.h"
#include "xfs_fs.h"
+#include "xfs_error.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
@@ -43,6 +44,7 @@ void func(const struct xfs_mount *mp, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
+ int level; \
\
va_start(args, fmt); \
\
@@ -51,6 +53,11 @@ void func(const struct xfs_mount *mp, const char *fmt, ...) \
\
__xfs_printk(kern_level, mp, &vaf); \
va_end(args); \
+ \
+ if (!kstrtoint(kern_level, 0, &level) && \
+ level <= LOGLEVEL_ERR && \
+ xfs_error_level >= XFS_ERRLEVEL_HIGH) \
+ xfs_stack_trace(); \
} \
define_xfs_printk_level(xfs_emerg, KERN_EMERG);
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index bf92e0c..bb753b3 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -47,6 +47,16 @@ static DEFINE_MUTEX(xfs_uuid_table_mutex);
static int xfs_uuid_table_size;
static uuid_t *xfs_uuid_table;
+void
+xfs_uuid_table_free(void)
+{
+ if (xfs_uuid_table_size == 0)
+ return;
+ kmem_free(xfs_uuid_table);
+ xfs_uuid_table = NULL;
+ xfs_uuid_table_size = 0;
+}
+
/*
* See if the UUID is unique among mounted XFS filesystems.
* Mount fails if UUID is nil or a FS with the same UUID is already mounted.
@@ -693,10 +703,15 @@ xfs_mountfs(
if (error)
goto out;
- error = xfs_uuid_mount(mp);
+ error = xfs_sysfs_init(&mp->m_stats.xs_kobj, &xfs_stats_ktype,
+ &mp->m_kobj, "stats");
if (error)
goto out_remove_sysfs;
+ error = xfs_uuid_mount(mp);
+ if (error)
+ goto out_del_stats;
+
/*
* Set the minimum read and write sizes
*/
@@ -971,6 +986,8 @@ xfs_mountfs(
xfs_da_unmount(mp);
out_remove_uuid:
xfs_uuid_unmount(mp);
+ out_del_stats:
+ xfs_sysfs_del(&mp->m_stats.xs_kobj);
out_remove_sysfs:
xfs_sysfs_del(&mp->m_kobj);
out:
@@ -1047,6 +1064,7 @@ xfs_unmountfs(
xfs_warn(mp, "Unable to update superblock counters. "
"Freespace may not be correct on next mount.");
+
xfs_log_unmount(mp);
xfs_da_unmount(mp);
xfs_uuid_unmount(mp);
@@ -1056,6 +1074,7 @@ xfs_unmountfs(
#endif
xfs_free_perag(mp);
+ xfs_sysfs_del(&mp->m_stats.xs_kobj);
xfs_sysfs_del(&mp->m_kobj);
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 7999e91..b570984 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -127,6 +127,7 @@ typedef struct xfs_mount {
int64_t m_low_space[XFS_LOWSP_MAX];
/* low free space thresholds */
struct xfs_kobj m_kobj;
+ struct xstats m_stats; /* per-fs stats */
struct workqueue_struct *m_buf_workqueue;
struct workqueue_struct *m_data_workqueue;
@@ -312,6 +313,7 @@ typedef struct xfs_perag {
int pagb_count; /* pagb slots in use */
} xfs_perag_t;
+extern void xfs_uuid_table_free(void);
extern int xfs_log_sbcount(xfs_mount_t *);
extern __uint64_t xfs_default_resblks(xfs_mount_t *mp);
extern int xfs_mountfs(xfs_mount_t *mp);
@@ -336,4 +338,7 @@ extern int xfs_dev_is_read_only(struct xfs_mount *, char *);
extern void xfs_set_low_space_thresholds(struct xfs_mount *);
+int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb,
+ xfs_off_t count_fsb);
+
#endif /* __XFS_MOUNT_H__ */
diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c
index ab4a606..dc62219 100644
--- a/fs/xfs/xfs_pnfs.c
+++ b/fs/xfs/xfs_pnfs.c
@@ -181,6 +181,11 @@ xfs_fs_map_blocks(
ASSERT(imap.br_startblock != DELAYSTARTBLOCK);
if (!nimaps || imap.br_startblock == HOLESTARTBLOCK) {
+ /*
+ * xfs_iomap_write_direct() expects to take ownership of
+ * the shared ilock.
+ */
+ xfs_ilock(ip, XFS_ILOCK_SHARED);
error = xfs_iomap_write_direct(ip, offset, length,
&imap, nimaps);
if (error)
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index 587174f..532ab79 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -184,7 +184,7 @@ xfs_qm_dqpurge(
*/
ASSERT(!list_empty(&dqp->q_lru));
list_lru_del(&qi->qi_lru, &dqp->q_lru);
- XFS_STATS_DEC(xs_qm_dquot_unused);
+ XFS_STATS_DEC(mp, xs_qm_dquot_unused);
xfs_qm_dqdestroy(dqp);
return 0;
@@ -448,11 +448,11 @@ xfs_qm_dquot_isolate(
*/
if (dqp->q_nrefs) {
xfs_dqunlock(dqp);
- XFS_STATS_INC(xs_qm_dqwants);
+ XFS_STATS_INC(dqp->q_mount, xs_qm_dqwants);
trace_xfs_dqreclaim_want(dqp);
list_lru_isolate(lru, &dqp->q_lru);
- XFS_STATS_DEC(xs_qm_dquot_unused);
+ XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot_unused);
return LRU_REMOVED;
}
@@ -496,19 +496,19 @@ xfs_qm_dquot_isolate(
ASSERT(dqp->q_nrefs == 0);
list_lru_isolate_move(lru, &dqp->q_lru, &isol->dispose);
- XFS_STATS_DEC(xs_qm_dquot_unused);
+ XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot_unused);
trace_xfs_dqreclaim_done(dqp);
- XFS_STATS_INC(xs_qm_dqreclaims);
+ XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaims);
return LRU_REMOVED;
out_miss_busy:
trace_xfs_dqreclaim_busy(dqp);
- XFS_STATS_INC(xs_qm_dqreclaim_misses);
+ XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaim_misses);
return LRU_SKIP;
out_unlock_dirty:
trace_xfs_dqreclaim_busy(dqp);
- XFS_STATS_INC(xs_qm_dqreclaim_misses);
+ XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaim_misses);
xfs_dqunlock(dqp);
spin_lock(lru_lock);
return LRU_RETRY;
diff --git a/fs/xfs/xfs_stats.c b/fs/xfs/xfs_stats.c
index f224038..8686df6 100644
--- a/fs/xfs/xfs_stats.c
+++ b/fs/xfs/xfs_stats.c
@@ -18,20 +18,21 @@
#include "xfs.h"
#include <linux/proc_fs.h>
-DEFINE_PER_CPU(struct xfsstats, xfsstats);
+struct xstats xfsstats;
-static int counter_val(int idx)
+static int counter_val(struct xfsstats __percpu *stats, int idx)
{
int val = 0, cpu;
for_each_possible_cpu(cpu)
- val += *(((__u32 *)&per_cpu(xfsstats, cpu) + idx));
+ val += *(((__u32 *)per_cpu_ptr(stats, cpu) + idx));
return val;
}
-static int xfs_stat_proc_show(struct seq_file *m, void *v)
+int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
{
int i, j;
+ int len = 0;
__uint64_t xs_xstrat_bytes = 0;
__uint64_t xs_write_bytes = 0;
__uint64_t xs_read_bytes = 0;
@@ -65,54 +66,59 @@ static int xfs_stat_proc_show(struct seq_file *m, void *v)
};
/* Loop over all stats groups */
+
for (i = j = 0; i < ARRAY_SIZE(xstats); i++) {
- seq_printf(m, "%s", xstats[i].desc);
+ len += snprintf(buf + len, PATH_MAX - len, "%s",
+ xstats[i].desc);
/* inner loop does each group */
for (; j < xstats[i].endpoint; j++)
- seq_printf(m, " %u", counter_val(j));
- seq_putc(m, '\n');
+ len += snprintf(buf + len, PATH_MAX - len, " %u",
+ counter_val(stats, j));
+ len += snprintf(buf + len, PATH_MAX - len, "\n");
}
/* extra precision counters */
for_each_possible_cpu(i) {
- xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes;
- xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes;
- xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes;
+ xs_xstrat_bytes += per_cpu_ptr(stats, i)->xs_xstrat_bytes;
+ xs_write_bytes += per_cpu_ptr(stats, i)->xs_write_bytes;
+ xs_read_bytes += per_cpu_ptr(stats, i)->xs_read_bytes;
}
- seq_printf(m, "xpc %Lu %Lu %Lu\n",
+ len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n",
xs_xstrat_bytes, xs_write_bytes, xs_read_bytes);
- seq_printf(m, "debug %u\n",
+ len += snprintf(buf + len, PATH_MAX-len, "debug %u\n",
#if defined(DEBUG)
1);
#else
0);
#endif
- return 0;
+
+ return len;
}
-static int xfs_stat_proc_open(struct inode *inode, struct file *file)
+void xfs_stats_clearall(struct xfsstats __percpu *stats)
{
- return single_open(file, xfs_stat_proc_show, NULL);
+ int c;
+ __uint32_t vn_active;
+
+ xfs_notice(NULL, "Clearing xfsstats");
+ for_each_possible_cpu(c) {
+ preempt_disable();
+ /* save vn_active, it's a universal truth! */
+ vn_active = per_cpu_ptr(stats, c)->vn_active;
+ memset(per_cpu_ptr(stats, c), 0, sizeof(*stats));
+ per_cpu_ptr(stats, c)->vn_active = vn_active;
+ preempt_enable();
+ }
}
-static const struct file_operations xfs_stat_proc_fops = {
- .owner = THIS_MODULE,
- .open = xfs_stat_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
/* legacy quota interfaces */
#ifdef CONFIG_XFS_QUOTA
static int xqm_proc_show(struct seq_file *m, void *v)
{
/* maximum; incore; ratio free to inuse; freelist */
seq_printf(m, "%d\t%d\t%d\t%u\n",
- 0,
- counter_val(XFSSTAT_END_XQMSTAT),
- 0,
- counter_val(XFSSTAT_END_XQMSTAT + 1));
+ 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT),
+ 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT + 1));
return 0;
}
@@ -136,7 +142,7 @@ static int xqmstat_proc_show(struct seq_file *m, void *v)
seq_printf(m, "qm");
for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++)
- seq_printf(m, " %u", counter_val(j));
+ seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j));
seq_putc(m, '\n');
return 0;
}
@@ -155,44 +161,35 @@ static const struct file_operations xqmstat_proc_fops = {
};
#endif /* CONFIG_XFS_QUOTA */
+#ifdef CONFIG_PROC_FS
int
xfs_init_procfs(void)
{
if (!proc_mkdir("fs/xfs", NULL))
+ return -ENOMEM;
+
+ if (!proc_symlink("fs/xfs/stat", NULL,
+ "/sys/fs/xfs/stats/stats"))
goto out;
- if (!proc_create("fs/xfs/stat", 0, NULL,
- &xfs_stat_proc_fops))
- goto out_remove_xfs_dir;
#ifdef CONFIG_XFS_QUOTA
if (!proc_create("fs/xfs/xqmstat", 0, NULL,
&xqmstat_proc_fops))
- goto out_remove_stat_file;
+ goto out;
if (!proc_create("fs/xfs/xqm", 0, NULL,
&xqm_proc_fops))
- goto out_remove_xqmstat_file;
+ goto out;
#endif
return 0;
-#ifdef CONFIG_XFS_QUOTA
- out_remove_xqmstat_file:
- remove_proc_entry("fs/xfs/xqmstat", NULL);
- out_remove_stat_file:
- remove_proc_entry("fs/xfs/stat", NULL);
-#endif
- out_remove_xfs_dir:
- remove_proc_entry("fs/xfs", NULL);
- out:
+out:
+ remove_proc_subtree("fs/xfs", NULL);
return -ENOMEM;
}
void
xfs_cleanup_procfs(void)
{
-#ifdef CONFIG_XFS_QUOTA
- remove_proc_entry("fs/xfs/xqm", NULL);
- remove_proc_entry("fs/xfs/xqmstat", NULL);
-#endif
- remove_proc_entry("fs/xfs/stat", NULL);
- remove_proc_entry("fs/xfs", NULL);
+ remove_proc_subtree("fs/xfs", NULL);
}
+#endif /* CONFIG_PROC_FS */
diff --git a/fs/xfs/xfs_stats.h b/fs/xfs/xfs_stats.h
index c8f238b..483b0ef 100644
--- a/fs/xfs/xfs_stats.h
+++ b/fs/xfs/xfs_stats.h
@@ -19,8 +19,6 @@
#define __XFS_STATS_H__
-#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
-
#include <linux/percpu.h>
/*
@@ -215,15 +213,29 @@ struct xfsstats {
__uint64_t xs_read_bytes;
};
-DECLARE_PER_CPU(struct xfsstats, xfsstats);
+int xfs_stats_format(struct xfsstats __percpu *stats, char *buf);
+void xfs_stats_clearall(struct xfsstats __percpu *stats);
+extern struct xstats xfsstats;
-/*
- * We don't disable preempt, not too worried about poking the
- * wrong CPU's stat for now (also aggregated before reporting).
- */
-#define XFS_STATS_INC(v) (per_cpu(xfsstats, current_cpu()).v++)
-#define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--)
-#define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc))
+#define XFS_STATS_INC(mp, v) \
+do { \
+ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v++; \
+ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v++; \
+} while (0)
+
+#define XFS_STATS_DEC(mp, v) \
+do { \
+ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v--; \
+ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v--; \
+} while (0)
+
+#define XFS_STATS_ADD(mp, v, inc) \
+do { \
+ per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v += (inc); \
+ per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v += (inc); \
+} while (0)
+
+#if defined(CONFIG_PROC_FS)
extern int xfs_init_procfs(void);
extern void xfs_cleanup_procfs(void);
@@ -231,10 +243,6 @@ extern void xfs_cleanup_procfs(void);
#else /* !CONFIG_PROC_FS */
-# define XFS_STATS_INC(count)
-# define XFS_STATS_DEC(count)
-# define XFS_STATS_ADD(count, inc)
-
static inline int xfs_init_procfs(void)
{
return 0;
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 904f637c..36bd882 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -838,17 +838,18 @@ xfs_init_mount_workqueues(
goto out_destroy_unwritten;
mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s",
- WQ_FREEZABLE, 0, mp->m_fsname);
+ WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_reclaim_workqueue)
goto out_destroy_cil;
mp->m_log_workqueue = alloc_workqueue("xfs-log/%s",
- WQ_FREEZABLE|WQ_HIGHPRI, 0, mp->m_fsname);
+ WQ_MEM_RECLAIM|WQ_FREEZABLE|WQ_HIGHPRI, 0,
+ mp->m_fsname);
if (!mp->m_log_workqueue)
goto out_destroy_reclaim;
mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s",
- WQ_FREEZABLE, 0, mp->m_fsname);
+ WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname);
if (!mp->m_eofblocks_workqueue)
goto out_destroy_log;
@@ -922,7 +923,7 @@ xfs_fs_destroy_inode(
trace_xfs_destroy_inode(ip);
- XFS_STATS_INC(vn_reclaim);
+ XFS_STATS_INC(ip->i_mount, vn_reclaim);
ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
@@ -983,8 +984,8 @@ xfs_fs_evict_inode(
truncate_inode_pages_final(&inode->i_data);
clear_inode(inode);
- XFS_STATS_INC(vn_rele);
- XFS_STATS_INC(vn_remove);
+ XFS_STATS_INC(ip->i_mount, vn_rele);
+ XFS_STATS_INC(ip->i_mount, vn_remove);
xfs_inactive(ip);
}
@@ -1474,9 +1475,16 @@ xfs_fs_fill_super(
if (error)
goto out_destroy_workqueues;
+ /* Allocate stats memory before we do operations that might use it */
+ mp->m_stats.xs_stats = alloc_percpu(struct xfsstats);
+ if (!mp->m_stats.xs_stats) {
+ error = -ENOMEM;
+ goto out_destroy_counters;
+ }
+
error = xfs_readsb(mp, flags);
if (error)
- goto out_destroy_counters;
+ goto out_free_stats;
error = xfs_finish_flags(mp);
if (error)
@@ -1545,9 +1553,11 @@ xfs_fs_fill_super(
xfs_filestream_unmount(mp);
out_free_sb:
xfs_freesb(mp);
+ out_free_stats:
+ free_percpu(mp->m_stats.xs_stats);
out_destroy_counters:
xfs_destroy_percpu_counters(mp);
-out_destroy_workqueues:
+ out_destroy_workqueues:
xfs_destroy_mount_workqueues(mp);
out_close_devices:
xfs_close_devices(mp);
@@ -1574,6 +1584,7 @@ xfs_fs_put_super(
xfs_unmountfs(mp);
xfs_freesb(mp);
+ free_percpu(mp->m_stats.xs_stats);
xfs_destroy_percpu_counters(mp);
xfs_destroy_mount_workqueues(mp);
xfs_close_devices(mp);
@@ -1838,19 +1849,32 @@ init_xfs_fs(void)
xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj);
if (!xfs_kset) {
error = -ENOMEM;
- goto out_sysctl_unregister;;
+ goto out_sysctl_unregister;
}
+ xfsstats.xs_kobj.kobject.kset = xfs_kset;
+
+ xfsstats.xs_stats = alloc_percpu(struct xfsstats);
+ if (!xfsstats.xs_stats) {
+ error = -ENOMEM;
+ goto out_kset_unregister;
+ }
+
+ error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL,
+ "stats");
+ if (error)
+ goto out_free_stats;
+
#ifdef DEBUG
xfs_dbg_kobj.kobject.kset = xfs_kset;
error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
if (error)
- goto out_kset_unregister;
+ goto out_remove_stats_kobj;
#endif
error = xfs_qm_init();
if (error)
- goto out_remove_kobj;
+ goto out_remove_dbg_kobj;
error = register_filesystem(&xfs_fs_type);
if (error)
@@ -1859,11 +1883,15 @@ init_xfs_fs(void)
out_qm_exit:
xfs_qm_exit();
- out_remove_kobj:
+ out_remove_dbg_kobj:
#ifdef DEBUG
xfs_sysfs_del(&xfs_dbg_kobj);
- out_kset_unregister:
+ out_remove_stats_kobj:
#endif
+ xfs_sysfs_del(&xfsstats.xs_kobj);
+ out_free_stats:
+ free_percpu(xfsstats.xs_stats);
+ out_kset_unregister:
kset_unregister(xfs_kset);
out_sysctl_unregister:
xfs_sysctl_unregister();
@@ -1889,6 +1917,8 @@ exit_xfs_fs(void)
#ifdef DEBUG
xfs_sysfs_del(&xfs_dbg_kobj);
#endif
+ xfs_sysfs_del(&xfsstats.xs_kobj);
+ free_percpu(xfsstats.xs_stats);
kset_unregister(xfs_kset);
xfs_sysctl_unregister();
xfs_cleanup_procfs();
@@ -1896,6 +1926,7 @@ exit_xfs_fs(void)
xfs_mru_cache_uninit();
xfs_destroy_workqueues();
xfs_destroy_zones();
+ xfs_uuid_table_free();
}
module_init(init_xfs_fs);
diff --git a/fs/xfs/xfs_sysctl.c b/fs/xfs/xfs_sysctl.c
index a0c8067..aed74d3 100644
--- a/fs/xfs/xfs_sysctl.c
+++ b/fs/xfs/xfs_sysctl.c
@@ -19,6 +19,7 @@
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include "xfs_error.h"
+#include "xfs_stats.h"
static struct ctl_table_header *xfs_table_header;
@@ -31,22 +32,12 @@ xfs_stats_clear_proc_handler(
size_t *lenp,
loff_t *ppos)
{
- int c, ret, *valp = ctl->data;
- __uint32_t vn_active;
+ int ret, *valp = ctl->data;
ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
if (!ret && write && *valp) {
- xfs_notice(NULL, "Clearing xfsstats");
- for_each_possible_cpu(c) {
- preempt_disable();
- /* save vn_active, it's a universal truth! */
- vn_active = per_cpu(xfsstats, c).vn_active;
- memset(&per_cpu(xfsstats, c), 0,
- sizeof(struct xfsstats));
- per_cpu(xfsstats, c).vn_active = vn_active;
- preempt_enable();
- }
+ xfs_stats_clearall(xfsstats.xs_stats);
xfs_stats_clear = 0;
}
diff --git a/fs/xfs/xfs_sysfs.c b/fs/xfs/xfs_sysfs.c
index aa03670..ee70f5d 100644
--- a/fs/xfs/xfs_sysfs.c
+++ b/fs/xfs/xfs_sysfs.c
@@ -21,11 +21,13 @@
#include "xfs_log_format.h"
#include "xfs_log.h"
#include "xfs_log_priv.h"
+#include "xfs_stats.h"
struct xfs_sysfs_attr {
struct attribute attr;
- ssize_t (*show)(char *buf, void *data);
- ssize_t (*store)(const char *buf, size_t count, void *data);
+ ssize_t (*show)(struct kobject *kobject, char *buf);
+ ssize_t (*store)(struct kobject *kobject, const char *buf,
+ size_t count);
};
static inline struct xfs_sysfs_attr *
@@ -38,6 +40,8 @@ to_attr(struct attribute *attr)
static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name)
#define XFS_SYSFS_ATTR_RO(name) \
static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name)
+#define XFS_SYSFS_ATTR_WO(name) \
+ static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name)
#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr
@@ -51,14 +55,42 @@ struct kobj_type xfs_mp_ktype = {
.release = xfs_sysfs_release,
};
+STATIC ssize_t
+xfs_sysfs_object_show(
+ struct kobject *kobject,
+ struct attribute *attr,
+ char *buf)
+{
+ struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+ return xfs_attr->show ? xfs_attr->show(kobject, buf) : 0;
+}
+
+STATIC ssize_t
+xfs_sysfs_object_store(
+ struct kobject *kobject,
+ struct attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+
+ return xfs_attr->store ? xfs_attr->store(kobject, buf, count) : 0;
+}
+
+static const struct sysfs_ops xfs_sysfs_ops = {
+ .show = xfs_sysfs_object_show,
+ .store = xfs_sysfs_object_store,
+};
+
#ifdef DEBUG
/* debug */
STATIC ssize_t
log_recovery_delay_store(
+ struct kobject *kobject,
const char *buf,
- size_t count,
- void *data)
+ size_t count)
{
int ret;
int val;
@@ -77,8 +109,8 @@ log_recovery_delay_store(
STATIC ssize_t
log_recovery_delay_show(
- char *buf,
- void *data)
+ struct kobject *kobject,
+ char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay);
}
@@ -89,52 +121,87 @@ static struct attribute *xfs_dbg_attrs[] = {
NULL,
};
+struct kobj_type xfs_dbg_ktype = {
+ .release = xfs_sysfs_release,
+ .sysfs_ops = &xfs_sysfs_ops,
+ .default_attrs = xfs_dbg_attrs,
+};
+
+#endif /* DEBUG */
+
+/* stats */
+
+static inline struct xstats *
+to_xstats(struct kobject *kobject)
+{
+ struct xfs_kobj *kobj = to_kobj(kobject);
+
+ return container_of(kobj, struct xstats, xs_kobj);
+}
+
STATIC ssize_t
-xfs_dbg_show(
- struct kobject *kobject,
- struct attribute *attr,
- char *buf)
+stats_show(
+ struct kobject *kobject,
+ char *buf)
{
- struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+ struct xstats *stats = to_xstats(kobject);
- return xfs_attr->show ? xfs_attr->show(buf, NULL) : 0;
+ return xfs_stats_format(stats->xs_stats, buf);
}
+XFS_SYSFS_ATTR_RO(stats);
STATIC ssize_t
-xfs_dbg_store(
- struct kobject *kobject,
- struct attribute *attr,
- const char *buf,
- size_t count)
+stats_clear_store(
+ struct kobject *kobject,
+ const char *buf,
+ size_t count)
{
- struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
+ int ret;
+ int val;
+ struct xstats *stats = to_xstats(kobject);
+
+ ret = kstrtoint(buf, 0, &val);
+ if (ret)
+ return ret;
- return xfs_attr->store ? xfs_attr->store(buf, count, NULL) : 0;
+ if (val != 1)
+ return -EINVAL;
+
+ xfs_stats_clearall(stats->xs_stats);
+ return count;
}
+XFS_SYSFS_ATTR_WO(stats_clear);
-static struct sysfs_ops xfs_dbg_ops = {
- .show = xfs_dbg_show,
- .store = xfs_dbg_store,
+static struct attribute *xfs_stats_attrs[] = {
+ ATTR_LIST(stats),
+ ATTR_LIST(stats_clear),
+ NULL,
};
-struct kobj_type xfs_dbg_ktype = {
+struct kobj_type xfs_stats_ktype = {
.release = xfs_sysfs_release,
- .sysfs_ops = &xfs_dbg_ops,
- .default_attrs = xfs_dbg_attrs,
+ .sysfs_ops = &xfs_sysfs_ops,
+ .default_attrs = xfs_stats_attrs,
};
-#endif /* DEBUG */
-
/* xlog */
+static inline struct xlog *
+to_xlog(struct kobject *kobject)
+{
+ struct xfs_kobj *kobj = to_kobj(kobject);
+
+ return container_of(kobj, struct xlog, l_kobj);
+}
+
STATIC ssize_t
log_head_lsn_show(
- char *buf,
- void *data)
+ struct kobject *kobject,
+ char *buf)
{
- struct xlog *log = data;
int cycle;
int block;
+ struct xlog *log = to_xlog(kobject);
spin_lock(&log->l_icloglock);
cycle = log->l_curr_cycle;
@@ -147,12 +214,12 @@ XFS_SYSFS_ATTR_RO(log_head_lsn);
STATIC ssize_t
log_tail_lsn_show(
- char *buf,
- void *data)
+ struct kobject *kobject,
+ char *buf)
{
- struct xlog *log = data;
int cycle;
int block;
+ struct xlog *log = to_xlog(kobject);
xlog_crack_atomic_lsn(&log->l_tail_lsn, &cycle, &block);
return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, block);
@@ -161,12 +228,13 @@ XFS_SYSFS_ATTR_RO(log_tail_lsn);
STATIC ssize_t
reserve_grant_head_show(
- char *buf,
- void *data)
+ struct kobject *kobject,
+ char *buf)
+
{
- struct xlog *log = data;
int cycle;
int bytes;
+ struct xlog *log = to_xlog(kobject);
xlog_crack_grant_head(&log->l_reserve_head.grant, &cycle, &bytes);
return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes);
@@ -175,12 +243,12 @@ XFS_SYSFS_ATTR_RO(reserve_grant_head);
STATIC ssize_t
write_grant_head_show(
- char *buf,
- void *data)
+ struct kobject *kobject,
+ char *buf)
{
- struct xlog *log = data;
int cycle;
int bytes;
+ struct xlog *log = to_xlog(kobject);
xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &bytes);
return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes);
@@ -195,45 +263,8 @@ static struct attribute *xfs_log_attrs[] = {
NULL,
};
-static inline struct xlog *
-to_xlog(struct kobject *kobject)
-{
- struct xfs_kobj *kobj = to_kobj(kobject);
- return container_of(kobj, struct xlog, l_kobj);
-}
-
-STATIC ssize_t
-xfs_log_show(
- struct kobject *kobject,
- struct attribute *attr,
- char *buf)
-{
- struct xlog *log = to_xlog(kobject);
- struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
-
- return xfs_attr->show ? xfs_attr->show(buf, log) : 0;
-}
-
-STATIC ssize_t
-xfs_log_store(
- struct kobject *kobject,
- struct attribute *attr,
- const char *buf,
- size_t count)
-{
- struct xlog *log = to_xlog(kobject);
- struct xfs_sysfs_attr *xfs_attr = to_attr(attr);
-
- return xfs_attr->store ? xfs_attr->store(buf, count, log) : 0;
-}
-
-static struct sysfs_ops xfs_log_ops = {
- .show = xfs_log_show,
- .store = xfs_log_store,
-};
-
struct kobj_type xfs_log_ktype = {
.release = xfs_sysfs_release,
- .sysfs_ops = &xfs_log_ops,
+ .sysfs_ops = &xfs_sysfs_ops,
.default_attrs = xfs_log_attrs,
};
diff --git a/fs/xfs/xfs_sysfs.h b/fs/xfs/xfs_sysfs.h
index 240eee3..be692e5 100644
--- a/fs/xfs/xfs_sysfs.h
+++ b/fs/xfs/xfs_sysfs.h
@@ -22,6 +22,7 @@
extern struct kobj_type xfs_mp_ktype; /* xfs_mount */
extern struct kobj_type xfs_dbg_ktype; /* debug */
extern struct kobj_type xfs_log_ktype; /* xlog */
+extern struct kobj_type xfs_stats_ktype; /* stats */
static inline struct xfs_kobj *
to_kobj(struct kobject *kobject)
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 5ed36b1..877079eb 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -689,6 +689,7 @@ DEFINE_INODE_EVENT(xfs_inode_free_eofblocks_invalid);
DEFINE_INODE_EVENT(xfs_filemap_fault);
DEFINE_INODE_EVENT(xfs_filemap_pmd_fault);
DEFINE_INODE_EVENT(xfs_filemap_page_mkwrite);
+DEFINE_INODE_EVENT(xfs_filemap_pfn_mkwrite);
DECLARE_EVENT_CLASS(xfs_iref_class,
TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip),
@@ -1312,6 +1313,7 @@ DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc);
DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert);
DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound);
DEFINE_SIMPLE_IO_EVENT(xfs_setfilesize);
+DEFINE_SIMPLE_IO_EVENT(xfs_zero_eof);
DECLARE_EVENT_CLASS(xfs_itrunc_class,
TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size),
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c
index a0ab1da..748b16a 100644
--- a/fs/xfs/xfs_trans.c
+++ b/fs/xfs/xfs_trans.c
@@ -930,9 +930,9 @@ __xfs_trans_commit(
*/
if (sync) {
error = _xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL);
- XFS_STATS_INC(xs_trans_sync);
+ XFS_STATS_INC(mp, xs_trans_sync);
} else {
- XFS_STATS_INC(xs_trans_async);
+ XFS_STATS_INC(mp, xs_trans_async);
}
return error;
@@ -955,7 +955,7 @@ out_unreserve:
xfs_trans_free_items(tp, NULLCOMMITLSN, !!error);
xfs_trans_free(tp);
- XFS_STATS_INC(xs_trans_empty);
+ XFS_STATS_INC(mp, xs_trans_empty);
return error;
}
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 1098cf4..aa67339 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -349,7 +349,7 @@ xfsaild_push(
xfs_ail_min_lsn(ailp))) {
ailp->xa_log_flush = 0;
- XFS_STATS_INC(xs_push_ail_flush);
+ XFS_STATS_INC(mp, xs_push_ail_flush);
xfs_log_force(mp, XFS_LOG_SYNC);
}
@@ -371,7 +371,7 @@ xfsaild_push(
goto out_done;
}
- XFS_STATS_INC(xs_push_ail);
+ XFS_STATS_INC(mp, xs_push_ail);
lsn = lip->li_lsn;
while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) {
@@ -385,7 +385,7 @@ xfsaild_push(
lock_result = lip->li_ops->iop_push(lip, &ailp->xa_buf_list);
switch (lock_result) {
case XFS_ITEM_SUCCESS:
- XFS_STATS_INC(xs_push_ail_success);
+ XFS_STATS_INC(mp, xs_push_ail_success);
trace_xfs_ail_push(lip);
ailp->xa_last_pushed_lsn = lsn;
@@ -403,7 +403,7 @@ xfsaild_push(
* re-try the flushing relatively soon if most of the
* AIL is beeing flushed.
*/
- XFS_STATS_INC(xs_push_ail_flushing);
+ XFS_STATS_INC(mp, xs_push_ail_flushing);
trace_xfs_ail_flushing(lip);
flushing++;
@@ -411,14 +411,14 @@ xfsaild_push(
break;
case XFS_ITEM_PINNED:
- XFS_STATS_INC(xs_push_ail_pinned);
+ XFS_STATS_INC(mp, xs_push_ail_pinned);
trace_xfs_ail_pinned(lip);
stuck++;
ailp->xa_log_flush++;
break;
case XFS_ITEM_LOCKED:
- XFS_STATS_INC(xs_push_ail_locked);
+ XFS_STATS_INC(mp, xs_push_ail_locked);
trace_xfs_ail_locked(lip);
stuck++;
@@ -497,6 +497,7 @@ xfsaild(
long tout = 0; /* milliseconds */
current->flags |= PF_MEMALLOC;
+ set_freezable();
while (!kthread_should_stop()) {
if (tout && tout <= 20)
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index 17280cd..b97f1df 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -108,6 +108,15 @@ xfs_trans_log_inode(
ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
+ * Record the specific change for fdatasync optimisation. This
+ * allows fdatasync to skip log forces for inodes that are only
+ * timestamp dirty. We do this before the change count so that
+ * the core being logged in this case does not impact on fdatasync
+ * behaviour.
+ */
+ ip->i_itemp->ili_fsync_fields |= flags;
+
+ /*
* First time we log the inode in a transaction, bump the inode change
* counter if it is configured for this to occur. We don't use
* inode_inc_version() because there is no need for extra locking around
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index c0368151..110f1d7 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -32,15 +32,13 @@
static int
-xfs_xattr_get(struct dentry *dentry, const char *name,
- void *value, size_t size, int xflags)
+xfs_xattr_get(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, void *value, size_t size)
{
+ int xflags = handler->flags;
struct xfs_inode *ip = XFS_I(d_inode(dentry));
int error, asize = size;
- if (strcmp(name, "") == 0)
- return -EINVAL;
-
/* Convert Linux syscall to XFS internal ATTR flags */
if (!size) {
xflags |= ATTR_KERNOVAL;
@@ -53,14 +51,35 @@ xfs_xattr_get(struct dentry *dentry, const char *name,
return asize;
}
-static int
-xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
- size_t size, int flags, int xflags)
+void
+xfs_forget_acl(
+ struct inode *inode,
+ const char *name,
+ int xflags)
{
- struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ /*
+ * Invalidate any cached ACLs if the user has bypassed the ACL
+ * interface. We don't validate the content whatsoever so it is caller
+ * responsibility to provide data in valid format and ensure i_mode is
+ * consistent.
+ */
+ if (xflags & ATTR_ROOT) {
+#ifdef CONFIG_XFS_POSIX_ACL
+ if (!strcmp(name, SGI_ACL_FILE))
+ forget_cached_acl(inode, ACL_TYPE_ACCESS);
+ else if (!strcmp(name, SGI_ACL_DEFAULT))
+ forget_cached_acl(inode, ACL_TYPE_DEFAULT);
+#endif
+ }
+}
- if (strcmp(name, "") == 0)
- return -EINVAL;
+static int
+xfs_xattr_set(const struct xattr_handler *handler, struct dentry *dentry,
+ const char *name, const void *value, size_t size, int flags)
+{
+ int xflags = handler->flags;
+ struct xfs_inode *ip = XFS_I(d_inode(dentry));
+ int error;
/* Convert Linux syscall to XFS internal ATTR flags */
if (flags & XATTR_CREATE)
@@ -70,8 +89,12 @@ xfs_xattr_set(struct dentry *dentry, const char *name, const void *value,
if (!value)
return xfs_attr_remove(ip, (unsigned char *)name, xflags);
- return xfs_attr_set(ip, (unsigned char *)name,
+ error = xfs_attr_set(ip, (unsigned char *)name,
(void *)value, size, xflags);
+ if (!error)
+ xfs_forget_acl(d_inode(dentry), name, xflags);
+
+ return error;
}
static const struct xattr_handler xfs_xattr_user_handler = {
@@ -106,47 +129,19 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
NULL
};
-static unsigned int xfs_xattr_prefix_len(int flags)
-{
- if (flags & XFS_ATTR_SECURE)
- return sizeof("security");
- else if (flags & XFS_ATTR_ROOT)
- return sizeof("trusted");
- else
- return sizeof("user");
-}
-
-static const char *xfs_xattr_prefix(int flags)
-{
- if (flags & XFS_ATTR_SECURE)
- return xfs_xattr_security_handler.prefix;
- else if (flags & XFS_ATTR_ROOT)
- return xfs_xattr_trusted_handler.prefix;
- else
- return xfs_xattr_user_handler.prefix;
-}
-
static int
-xfs_xattr_put_listent(
+__xfs_xattr_put_listent(
struct xfs_attr_list_context *context,
- int flags,
- unsigned char *name,
- int namelen,
- int valuelen,
- unsigned char *value)
+ char *prefix,
+ int prefix_len,
+ unsigned char *name,
+ int namelen)
{
- unsigned int prefix_len = xfs_xattr_prefix_len(flags);
char *offset;
int arraytop;
- ASSERT(context->count >= 0);
-
- /*
- * Only show root namespace entries if we are actually allowed to
- * see them.
- */
- if ((flags & XFS_ATTR_ROOT) && !capable(CAP_SYS_ADMIN))
- return 0;
+ if (!context->alist)
+ goto compute_size;
arraytop = context->count + prefix_len + namelen + 1;
if (arraytop > context->firstu) {
@@ -154,17 +149,19 @@ xfs_xattr_put_listent(
return 1;
}
offset = (char *)context->alist + context->count;
- strncpy(offset, xfs_xattr_prefix(flags), prefix_len);
+ strncpy(offset, prefix, prefix_len);
offset += prefix_len;
strncpy(offset, (char *)name, namelen); /* real name */
offset += namelen;
*offset = '\0';
+
+compute_size:
context->count += prefix_len + namelen + 1;
return 0;
}
static int
-xfs_xattr_put_listent_sizes(
+xfs_xattr_put_listent(
struct xfs_attr_list_context *context,
int flags,
unsigned char *name,
@@ -172,24 +169,55 @@ xfs_xattr_put_listent_sizes(
int valuelen,
unsigned char *value)
{
- context->count += xfs_xattr_prefix_len(flags) + namelen + 1;
- return 0;
-}
+ char *prefix;
+ int prefix_len;
-static int
-list_one_attr(const char *name, const size_t len, void *data,
- size_t size, ssize_t *result)
-{
- char *p = data + *result;
+ ASSERT(context->count >= 0);
- *result += len;
- if (!size)
- return 0;
- if (*result > size)
- return -ERANGE;
+ if (flags & XFS_ATTR_ROOT) {
+#ifdef CONFIG_XFS_POSIX_ACL
+ if (namelen == SGI_ACL_FILE_SIZE &&
+ strncmp(name, SGI_ACL_FILE,
+ SGI_ACL_FILE_SIZE) == 0) {
+ int ret = __xfs_xattr_put_listent(
+ context, XATTR_SYSTEM_PREFIX,
+ XATTR_SYSTEM_PREFIX_LEN,
+ XATTR_POSIX_ACL_ACCESS,
+ strlen(XATTR_POSIX_ACL_ACCESS));
+ if (ret)
+ return ret;
+ } else if (namelen == SGI_ACL_DEFAULT_SIZE &&
+ strncmp(name, SGI_ACL_DEFAULT,
+ SGI_ACL_DEFAULT_SIZE) == 0) {
+ int ret = __xfs_xattr_put_listent(
+ context, XATTR_SYSTEM_PREFIX,
+ XATTR_SYSTEM_PREFIX_LEN,
+ XATTR_POSIX_ACL_DEFAULT,
+ strlen(XATTR_POSIX_ACL_DEFAULT));
+ if (ret)
+ return ret;
+ }
+#endif
- strcpy(p, name);
- return 0;
+ /*
+ * Only show root namespace entries if we are actually allowed to
+ * see them.
+ */
+ if (!capable(CAP_SYS_ADMIN))
+ return 0;
+
+ prefix = XATTR_TRUSTED_PREFIX;
+ prefix_len = XATTR_TRUSTED_PREFIX_LEN;
+ } else if (flags & XFS_ATTR_SECURE) {
+ prefix = XATTR_SECURITY_PREFIX;
+ prefix_len = XATTR_SECURITY_PREFIX_LEN;
+ } else {
+ prefix = XATTR_USER_PREFIX;
+ prefix_len = XATTR_USER_PREFIX_LEN;
+ }
+
+ return __xfs_xattr_put_listent(context, prefix, prefix_len, name,
+ namelen);
}
ssize_t
@@ -198,7 +226,6 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
struct xfs_attr_list_context context;
struct attrlist_cursor_kern cursor = { 0 };
struct inode *inode = d_inode(dentry);
- int error;
/*
* First read the regular on-disk attributes.
@@ -207,37 +234,14 @@ xfs_vn_listxattr(struct dentry *dentry, char *data, size_t size)
context.dp = XFS_I(inode);
context.cursor = &cursor;
context.resynch = 1;
- context.alist = data;
+ context.alist = size ? data : NULL;
context.bufsize = size;
context.firstu = context.bufsize;
-
- if (size)
- context.put_listent = xfs_xattr_put_listent;
- else
- context.put_listent = xfs_xattr_put_listent_sizes;
+ context.put_listent = xfs_xattr_put_listent;
xfs_attr_list_int(&context);
if (context.count < 0)
return -ERANGE;
- /*
- * Then add the two synthetic ACL attributes.
- */
- if (posix_acl_access_exists(inode)) {
- error = list_one_attr(POSIX_ACL_XATTR_ACCESS,
- strlen(POSIX_ACL_XATTR_ACCESS) + 1,
- data, size, &context.count);
- if (error)
- return error;
- }
-
- if (posix_acl_default_exists(inode)) {
- error = list_one_attr(POSIX_ACL_XATTR_DEFAULT,
- strlen(POSIX_ACL_XATTR_DEFAULT) + 1,
- data, size, &context.count);
- if (error)
- return error;
- }
-
return context.count;
}
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index d11eff8..ad0a5ff 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -390,39 +390,6 @@ struct acpi_data_node {
struct completion kobj_done;
};
-static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
-{
- bool ret = false;
-
- if (!adev)
- return ret;
-
- /**
- * Currently, we only support _CCA=1 (i.e. coherent_dma=1)
- * This should be equivalent to specifyig dma-coherent for
- * a device in OF.
- *
- * For the case when _CCA=0 (i.e. coherent_dma=0 && cca_seen=1),
- * There are two cases:
- * case 1. Do not support and disable DMA.
- * case 2. Support but rely on arch-specific cache maintenance for
- * non-coherence DMA operations.
- * Currently, we implement case 1 above.
- *
- * For the case when _CCA is missing (i.e. cca_seen=0) and
- * platform specifies ACPI_CCA_REQUIRED, we do not support DMA,
- * and fallback to arch-specific default handling.
- *
- * See acpi_init_coherency() for more info.
- */
- if (adev->flags.coherent_dma) {
- ret = true;
- if (coherent)
- *coherent = adev->flags.coherent_dma;
- }
- return ret;
-}
-
static inline bool is_acpi_node(struct fwnode_handle *fwnode)
{
return fwnode && (fwnode->type == FWNODE_ACPI
@@ -595,6 +562,9 @@ struct acpi_pci_root {
/* helper */
+bool acpi_dma_supported(struct acpi_device *adev);
+enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev);
+
struct acpi_device *acpi_find_child_device(struct acpi_device *parent,
u64 address, bool check_children);
int acpi_is_root_bridge(acpi_handle);
diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
index b42afad..0f45f93 100644
--- a/include/asm-generic/barrier.h
+++ b/include/asm-generic/barrier.h
@@ -93,7 +93,7 @@
#endif /* CONFIG_SMP */
#ifndef smp_store_mb
-#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); mb(); } while (0)
+#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); smp_mb(); } while (0)
#endif
#ifndef smp_mb__before_atomic
diff --git a/include/asm-generic/pci-dma-compat.h b/include/asm-generic/pci-dma-compat.h
index c110843..eafce7b 100644
--- a/include/asm-generic/pci-dma-compat.h
+++ b/include/asm-generic/pci-dma-compat.h
@@ -6,12 +6,6 @@
#include <linux/dma-mapping.h>
-static inline int
-pci_dma_supported(struct pci_dev *hwdev, u64 mask)
-{
- return dma_supported(hwdev == NULL ? NULL : &hwdev->dev, mask);
-}
-
static inline void *
pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
dma_addr_t *dma_handle)
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 14b0ff32..3a6803c 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -569,7 +569,7 @@ static inline int track_pfn_copy(struct vm_area_struct *vma)
}
/*
- * untrack_pfn_vma is called while unmapping a pfnmap for a region.
+ * untrack_pfn is called while unmapping a pfnmap for a region.
* untrack can be called for a specific region indicated by pfn and size or
* can be for the entire vma (in which case pfn, size are zero).
*/
@@ -577,6 +577,13 @@ static inline void untrack_pfn(struct vm_area_struct *vma,
unsigned long pfn, unsigned long size)
{
}
+
+/*
+ * untrack_pfn_moved is called while mremapping a pfnmap for a new region.
+ */
+static inline void untrack_pfn_moved(struct vm_area_struct *vma)
+{
+}
#else
extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
unsigned long pfn, unsigned long addr,
@@ -586,6 +593,7 @@ extern int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
extern int track_pfn_copy(struct vm_area_struct *vma);
extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
unsigned long size);
+extern void untrack_pfn_moved(struct vm_area_struct *vma);
#endif
#ifdef __HAVE_COLOR_ZERO_PAGE
diff --git a/include/asm-generic/qspinlock.h b/include/asm-generic/qspinlock.h
index e2aadbc..39e1cb2 100644
--- a/include/asm-generic/qspinlock.h
+++ b/include/asm-generic/qspinlock.h
@@ -12,8 +12,9 @@
* GNU General Public License for more details.
*
* (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
+ * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP
*
- * Authors: Waiman Long <waiman.long@hp.com>
+ * Authors: Waiman Long <waiman.long@hpe.com>
*/
#ifndef __ASM_GENERIC_QSPINLOCK_H
#define __ASM_GENERIC_QSPINLOCK_H
@@ -62,7 +63,7 @@ static __always_inline int queued_spin_is_contended(struct qspinlock *lock)
static __always_inline int queued_spin_trylock(struct qspinlock *lock)
{
if (!atomic_read(&lock->val) &&
- (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) == 0))
+ (atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL) == 0))
return 1;
return 0;
}
@@ -77,7 +78,7 @@ static __always_inline void queued_spin_lock(struct qspinlock *lock)
{
u32 val;
- val = atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL);
+ val = atomic_cmpxchg_acquire(&lock->val, 0, _Q_LOCKED_VAL);
if (likely(val == 0))
return;
queued_spin_lock_slowpath(lock, val);
@@ -93,7 +94,7 @@ static __always_inline void queued_spin_unlock(struct qspinlock *lock)
/*
* smp_mb__before_atomic() in order to guarantee release semantics
*/
- smp_mb__before_atomic_dec();
+ smp_mb__before_atomic();
atomic_sub(_Q_LOCKED_VAL, &lock->val);
}
#endif
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index db284bf..9dbb739 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -5,7 +5,7 @@
* Copyright 2001 Red Hat, Inc.
* Based on code from mm/memory.c Copyright Linus Torvalds and others.
*
- * Copyright 2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright 2011 Red Hat, Inc., Peter Zijlstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index 72d8803..1bfa602 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -163,9 +163,10 @@ static inline __must_check long __copy_to_user(void __user *to,
#define put_user(x, ptr) \
({ \
+ void *__p = (ptr); \
might_fault(); \
- access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)) ? \
- __put_user(x, ptr) : \
+ access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \
+ __put_user((x), ((__typeof__(*(ptr)) *)__p)) : \
-EFAULT; \
})
@@ -225,9 +226,10 @@ extern int __put_user_bad(void) __attribute__((noreturn));
#define get_user(x, ptr) \
({ \
+ const void *__p = (ptr); \
might_fault(); \
- access_ok(VERIFY_READ, ptr, sizeof(*ptr)) ? \
- __get_user(x, ptr) : \
+ access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \
+ __get_user((x), (__typeof__(*(ptr)) *)__p) : \
-EFAULT; \
})
diff --git a/include/clocksource/arm_arch_timer.h b/include/clocksource/arm_arch_timer.h
index 9916d0e..25d0914 100644
--- a/include/clocksource/arm_arch_timer.h
+++ b/include/clocksource/arm_arch_timer.h
@@ -23,6 +23,12 @@
#define ARCH_TIMER_CTRL_IT_MASK (1 << 1)
#define ARCH_TIMER_CTRL_IT_STAT (1 << 2)
+#define CNTHCTL_EL1PCTEN (1 << 0)
+#define CNTHCTL_EL1PCEN (1 << 1)
+#define CNTHCTL_EVNTEN (1 << 2)
+#define CNTHCTL_EVNTDIR (1 << 3)
+#define CNTHCTL_EVNTI (0xF << 4)
+
enum arch_timer_reg {
ARCH_TIMER_REG_CTRL,
ARCH_TIMER_REG_TVAL,
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 0b921ae..0a271ca 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -309,6 +309,11 @@ struct drm_file {
unsigned universal_planes:1;
/* true if client understands atomic properties */
unsigned atomic:1;
+ /*
+ * This client is allowed to gain master privileges for @master.
+ * Protected by struct drm_device::master_mutex.
+ */
+ unsigned allowed_master:1;
struct pid *pid;
kuid_t uid;
@@ -910,6 +915,7 @@ extern int drm_open(struct inode *inode, struct file *filp);
extern ssize_t drm_read(struct file *filp, char __user *buffer,
size_t count, loff_t *offset);
extern int drm_release(struct inode *inode, struct file *filp);
+extern int drm_new_set_master(struct drm_device *dev, struct drm_file *fpriv);
/* Mapping support (drm_vm.h) */
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
@@ -947,6 +953,10 @@ extern void drm_send_vblank_event(struct drm_device *dev, unsigned int pipe,
struct drm_pending_vblank_event *e);
extern void drm_crtc_send_vblank_event(struct drm_crtc *crtc,
struct drm_pending_vblank_event *e);
+extern void drm_arm_vblank_event(struct drm_device *dev, unsigned int pipe,
+ struct drm_pending_vblank_event *e);
+extern void drm_crtc_arm_vblank_event(struct drm_crtc *crtc,
+ struct drm_pending_vblank_event *e);
extern bool drm_handle_vblank(struct drm_device *dev, unsigned int pipe);
extern bool drm_crtc_handle_vblank(struct drm_crtc *crtc);
extern int drm_vblank_get(struct drm_device *dev, unsigned int pipe);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index e67aeac..4b74c97 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -136,6 +136,9 @@ drm_atomic_connectors_for_crtc(struct drm_atomic_state *state,
void drm_atomic_legacy_backoff(struct drm_atomic_state *state);
+void
+drm_atomic_clean_old_fb(struct drm_device *dev, unsigned plane_mask, int ret);
+
int __must_check drm_atomic_check_only(struct drm_atomic_state *state);
int __must_check drm_atomic_commit(struct drm_atomic_state *state);
int __must_check drm_atomic_async_commit(struct drm_atomic_state *state);
diff --git a/include/dt-bindings/clock/berlin2q.h b/include/dt-bindings/clock/berlin2q.h
index 287fc3b..72eaf91 100644
--- a/include/dt-bindings/clock/berlin2q.h
+++ b/include/dt-bindings/clock/berlin2q.h
@@ -29,3 +29,4 @@
#define CLKID_SMEMC 24
#define CLKID_PCIE 25
#define CLKID_TWD 26
+#define CLKID_CPU 27
diff --git a/include/dt-bindings/clock/exynos5250.h b/include/dt-bindings/clock/exynos5250.h
index 8183d1c..15508ad 100644
--- a/include/dt-bindings/clock/exynos5250.h
+++ b/include/dt-bindings/clock/exynos5250.h
@@ -173,8 +173,10 @@
/* mux clocks */
#define CLK_MOUT_HDMI 1024
#define CLK_MOUT_GPLL 1025
+#define CLK_MOUT_ACLK200_DISP1_SUB 1026
+#define CLK_MOUT_ACLK300_DISP1_SUB 1027
/* must be greater than maximal clock id */
-#define CLK_NR_CLKS 1026
+#define CLK_NR_CLKS 1028
#endif /* _DT_BINDINGS_CLOCK_EXYNOS_5250_H */
diff --git a/include/dt-bindings/power/rk3288-power.h b/include/dt-bindings/power/rk3288-power.h
new file mode 100644
index 0000000..b8b1045
--- /dev/null
+++ b/include/dt-bindings/power/rk3288-power.h
@@ -0,0 +1,31 @@
+#ifndef __DT_BINDINGS_POWER_RK3288_POWER_H__
+#define __DT_BINDINGS_POWER_RK3288_POWER_H__
+
+/**
+ * RK3288 Power Domain and Voltage Domain Summary.
+ */
+
+/* VD_CORE */
+#define RK3288_PD_A17_0 0
+#define RK3288_PD_A17_1 1
+#define RK3288_PD_A17_2 2
+#define RK3288_PD_A17_3 3
+#define RK3288_PD_SCU 4
+#define RK3288_PD_DEBUG 5
+#define RK3288_PD_MEM 6
+
+/* VD_LOGIC */
+#define RK3288_PD_BUS 7
+#define RK3288_PD_PERI 8
+#define RK3288_PD_VIO 9
+#define RK3288_PD_ALIVE 10
+#define RK3288_PD_HEVC 11
+#define RK3288_PD_VIDEO 12
+
+/* VD_GPU */
+#define RK3288_PD_GPU 13
+
+/* VD_PMU */
+#define RK3288_PD_PMU 14
+
+#endif
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 9c747cb..13a3d53 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -279,6 +279,12 @@ struct vgic_v2_cpu_if {
u32 vgic_lr[VGIC_V2_MAX_LRS];
};
+/*
+ * LRs are stored in reverse order in memory. make sure we index them
+ * correctly.
+ */
+#define VGIC_V3_LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr)
+
struct vgic_v3_cpu_if {
#ifdef CONFIG_KVM_ARM_VGIC_V3
u32 vgic_hcr;
@@ -342,10 +348,10 @@ int kvm_vgic_inject_mapped_irq(struct kvm *kvm, int cpuid,
struct irq_phys_map *map, bool level);
void vgic_v3_dispatch_sgi(struct kvm_vcpu *vcpu, u64 reg);
int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu);
-int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu);
struct irq_phys_map *kvm_vgic_map_phys_irq(struct kvm_vcpu *vcpu,
int virt_irq, int irq);
int kvm_vgic_unmap_phys_irq(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map);
#define irqchip_in_kernel(k) (!!((k)->arch.vgic.in_kernel))
#define vgic_initialized(k) (!!((k)->arch.vgic.nr_cpus))
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index d6f95bb..1991aea 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -514,6 +514,11 @@ static inline bool has_acpi_companion(struct device *dev)
return false;
}
+static inline void acpi_preset_companion(struct device *dev,
+ struct acpi_device *parent, u64 addr)
+{
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
@@ -596,11 +601,16 @@ static inline int acpi_device_modalias(struct device *dev,
return -ENODEV;
}
-static inline bool acpi_check_dma(struct acpi_device *adev, bool *coherent)
+static inline bool acpi_dma_supported(struct acpi_device *adev)
{
return false;
}
+static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
+{
+ return DEV_DMA_NOT_SUPPORTED;
+}
+
#define ACPI_PTR(_ptr) (NULL)
#endif /* !CONFIG_ACPI */
@@ -860,8 +870,8 @@ static inline int acpi_dev_get_property(struct acpi_device *adev,
}
static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode,
- const char *name, const char *cells_name,
- size_t index, struct acpi_reference_args *args)
+ const char *name, size_t index,
+ struct acpi_reference_args *args)
{
return -ENXIO;
}
diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
new file mode 100644
index 0000000..b5abfda
--- /dev/null
+++ b/include/linux/arm-smccc.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, Linaro Limited
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef __LINUX_ARM_SMCCC_H
+#define __LINUX_ARM_SMCCC_H
+
+#include <linux/linkage.h>
+#include <linux/types.h>
+
+/*
+ * This file provides common defines for ARM SMC Calling Convention as
+ * specified in
+ * http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html
+ */
+
+#define ARM_SMCCC_STD_CALL 0
+#define ARM_SMCCC_FAST_CALL 1
+#define ARM_SMCCC_TYPE_SHIFT 31
+
+#define ARM_SMCCC_SMC_32 0
+#define ARM_SMCCC_SMC_64 1
+#define ARM_SMCCC_CALL_CONV_SHIFT 30
+
+#define ARM_SMCCC_OWNER_MASK 0x3F
+#define ARM_SMCCC_OWNER_SHIFT 24
+
+#define ARM_SMCCC_FUNC_MASK 0xFFFF
+
+#define ARM_SMCCC_IS_FAST_CALL(smc_val) \
+ ((smc_val) & (ARM_SMCCC_FAST_CALL << ARM_SMCCC_TYPE_SHIFT))
+#define ARM_SMCCC_IS_64(smc_val) \
+ ((smc_val) & (ARM_SMCCC_SMC_64 << ARM_SMCCC_CALL_CONV_SHIFT))
+#define ARM_SMCCC_FUNC_NUM(smc_val) ((smc_val) & ARM_SMCCC_FUNC_MASK)
+#define ARM_SMCCC_OWNER_NUM(smc_val) \
+ (((smc_val) >> ARM_SMCCC_OWNER_SHIFT) & ARM_SMCCC_OWNER_MASK)
+
+#define ARM_SMCCC_CALL_VAL(type, calling_convention, owner, func_num) \
+ (((type) << ARM_SMCCC_TYPE_SHIFT) | \
+ ((calling_convention) << ARM_SMCCC_CALL_CONV_SHIFT) | \
+ (((owner) & ARM_SMCCC_OWNER_MASK) << ARM_SMCCC_OWNER_SHIFT) | \
+ ((func_num) & ARM_SMCCC_FUNC_MASK))
+
+#define ARM_SMCCC_OWNER_ARCH 0
+#define ARM_SMCCC_OWNER_CPU 1
+#define ARM_SMCCC_OWNER_SIP 2
+#define ARM_SMCCC_OWNER_OEM 3
+#define ARM_SMCCC_OWNER_STANDARD 4
+#define ARM_SMCCC_OWNER_TRUSTED_APP 48
+#define ARM_SMCCC_OWNER_TRUSTED_APP_END 49
+#define ARM_SMCCC_OWNER_TRUSTED_OS 50
+#define ARM_SMCCC_OWNER_TRUSTED_OS_END 63
+
+/**
+ * struct arm_smccc_res - Result from SMC/HVC call
+ * @a0-a3 result values from registers 0 to 3
+ */
+struct arm_smccc_res {
+ unsigned long a0;
+ unsigned long a1;
+ unsigned long a2;
+ unsigned long a3;
+};
+
+/**
+ * arm_smccc_smc() - make SMC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make SMC calls following SMC Calling Convention.
+ * The content of the supplied param are copied to registers 0 to 7 prior
+ * to the SMC instruction. The return values are updated with the content
+ * from register 0 to 3 on return from the SMC instruction.
+ */
+asmlinkage void arm_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res);
+
+/**
+ * arm_smccc_hvc() - make HVC calls
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from registers 0 to 3
+ *
+ * This function is used to make HVC calls following SMC Calling
+ * Convention. The content of the supplied param are copied to registers 0
+ * to 7 prior to the HVC instruction. The return values are updated with
+ * the content from register 0 to 3 on return from the HVC instruction.
+ */
+asmlinkage void arm_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3, unsigned long a4,
+ unsigned long a5, unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res);
+
+#endif /*__LINUX_ARM_SMCCC_H*/
diff --git a/include/linux/atmel_tc.h b/include/linux/atmel_tc.h
index b87c1c7..468fdfa 100644
--- a/include/linux/atmel_tc.h
+++ b/include/linux/atmel_tc.h
@@ -67,6 +67,7 @@ struct atmel_tc {
const struct atmel_tcb_config *tcb_config;
int irq[3];
struct clk *clk[3];
+ struct clk *slow_clk;
struct list_head node;
bool allocated;
};
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 2b8ed12..defeaac 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -107,7 +107,7 @@ static inline __u64 ror64(__u64 word, unsigned int shift)
*/
static inline __u32 rol32(__u32 word, unsigned int shift)
{
- return (word << shift) | (word >> (32 - shift));
+ return (word << shift) | (word >> ((-shift) & 31));
}
/**
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index 83cc9d4..daf17d7 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -59,6 +59,9 @@ struct blk_mq_hw_ctx {
struct blk_mq_cpu_notifier cpu_notifier;
struct kobject kobj;
+
+ unsigned long poll_invoked;
+ unsigned long poll_success;
};
struct blk_mq_tag_set {
@@ -97,6 +100,8 @@ typedef void (exit_request_fn)(void *, struct request *, unsigned int,
typedef void (busy_iter_fn)(struct blk_mq_hw_ctx *, struct request *, void *,
bool);
typedef void (busy_tag_iter_fn)(struct request *, void *, bool);
+typedef int (poll_fn)(struct blk_mq_hw_ctx *, unsigned int);
+
struct blk_mq_ops {
/*
@@ -114,6 +119,11 @@ struct blk_mq_ops {
*/
timeout_fn *timeout;
+ /*
+ * Called to poll for completion of a specific tag.
+ */
+ poll_fn *poll;
+
softirq_done_fn *complete;
/*
diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h
index e813013..0fb6584 100644
--- a/include/linux/blk_types.h
+++ b/include/linux/blk_types.h
@@ -244,4 +244,28 @@ enum rq_flag_bits {
#define REQ_MQ_INFLIGHT (1ULL << __REQ_MQ_INFLIGHT)
#define REQ_NO_TIMEOUT (1ULL << __REQ_NO_TIMEOUT)
+typedef unsigned int blk_qc_t;
+#define BLK_QC_T_NONE -1U
+#define BLK_QC_T_SHIFT 16
+
+static inline bool blk_qc_t_valid(blk_qc_t cookie)
+{
+ return cookie != BLK_QC_T_NONE;
+}
+
+static inline blk_qc_t blk_tag_to_qc_t(unsigned int tag, unsigned int queue_num)
+{
+ return tag | (queue_num << BLK_QC_T_SHIFT);
+}
+
+static inline unsigned int blk_qc_t_to_queue_num(blk_qc_t cookie)
+{
+ return cookie >> BLK_QC_T_SHIFT;
+}
+
+static inline unsigned int blk_qc_t_to_tag(blk_qc_t cookie)
+{
+ return cookie & ((1u << BLK_QC_T_SHIFT) - 1);
+}
+
#endif /* __LINUX_BLK_TYPES_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index d045ca8..c70e358 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -209,7 +209,7 @@ static inline unsigned short req_get_ioprio(struct request *req)
struct blk_queue_ctx;
typedef void (request_fn_proc) (struct request_queue *q);
-typedef void (make_request_fn) (struct request_queue *q, struct bio *bio);
+typedef blk_qc_t (make_request_fn) (struct request_queue *q, struct bio *bio);
typedef int (prep_rq_fn) (struct request_queue *, struct request *);
typedef void (unprep_rq_fn) (struct request_queue *, struct request *);
@@ -254,6 +254,7 @@ struct queue_limits {
unsigned long virt_boundary_mask;
unsigned int max_hw_sectors;
+ unsigned int max_dev_sectors;
unsigned int chunk_sectors;
unsigned int max_sectors;
unsigned int max_segment_size;
@@ -487,6 +488,7 @@ struct request_queue {
#define QUEUE_FLAG_DEAD 19 /* queue tear-down finished */
#define QUEUE_FLAG_INIT_DONE 20 /* queue is initialized */
#define QUEUE_FLAG_NO_SG_MERGE 21 /* don't attempt to merge SG segments*/
+#define QUEUE_FLAG_POLL 22 /* IO polling enabled if set */
#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \
(1 << QUEUE_FLAG_STACKABLE) | \
@@ -761,7 +763,7 @@ static inline void rq_flush_dcache_pages(struct request *rq)
extern int blk_register_queue(struct gendisk *disk);
extern void blk_unregister_queue(struct gendisk *disk);
-extern void generic_make_request(struct bio *bio);
+extern blk_qc_t generic_make_request(struct bio *bio);
extern void blk_rq_init(struct request_queue *q, struct request *rq);
extern void blk_put_request(struct request *);
extern void __blk_put_request(struct request_queue *, struct request *);
@@ -772,7 +774,6 @@ extern void blk_rq_set_block_pc(struct request *);
extern void blk_requeue_request(struct request_queue *, struct request *);
extern void blk_add_request_payload(struct request *rq, struct page *page,
unsigned int len);
-extern int blk_rq_check_limits(struct request_queue *q, struct request *rq);
extern int blk_lld_busy(struct request_queue *q);
extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src,
struct bio_set *bs, gfp_t gfp_mask,
@@ -793,7 +794,10 @@ extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t,
extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t,
struct scsi_ioctl_command __user *);
+extern int blk_queue_enter(struct request_queue *q, gfp_t gfp);
+extern void blk_queue_exit(struct request_queue *q);
extern void blk_start_queue(struct request_queue *q);
+extern void blk_start_queue_async(struct request_queue *q);
extern void blk_stop_queue(struct request_queue *q);
extern void blk_sync_queue(struct request_queue *q);
extern void __blk_stop_queue(struct request_queue *q);
@@ -814,6 +818,8 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *,
extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *,
struct request *, int, rq_end_io_fn *);
+bool blk_poll(struct request_queue *q, blk_qc_t cookie);
+
static inline struct request_queue *bdev_get_queue(struct block_device *bdev)
{
return bdev->bd_disk->queue; /* this is never NULL */
@@ -955,7 +961,6 @@ extern struct request_queue *blk_init_allocated_queue(struct request_queue *,
extern void blk_cleanup_queue(struct request_queue *);
extern void blk_queue_make_request(struct request_queue *, make_request_fn *);
extern void blk_queue_bounce_limit(struct request_queue *, u64);
-extern void blk_limits_max_hw_sectors(struct queue_limits *, unsigned int);
extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int);
extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int);
extern void blk_queue_max_segments(struct request_queue *, unsigned short);
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index f589222..35b22f9 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -19,6 +19,10 @@ extern unsigned long min_low_pfn;
* highest page
*/
extern unsigned long max_pfn;
+/*
+ * highest possible page
+ */
+extern unsigned long long max_possible_pfn;
#ifndef CONFIG_NO_BOOTMEM
/*
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index de464e6..83d1926 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -40,6 +40,7 @@ struct bpf_map {
struct user_struct *user;
const struct bpf_map_ops *ops;
struct work_struct work;
+ atomic_t usercnt;
};
struct bpf_map_type_list {
@@ -167,8 +168,10 @@ struct bpf_prog *bpf_prog_get(u32 ufd);
void bpf_prog_put(struct bpf_prog *prog);
void bpf_prog_put_rcu(struct bpf_prog *prog);
-struct bpf_map *bpf_map_get(u32 ufd);
+struct bpf_map *bpf_map_get_with_uref(u32 ufd);
struct bpf_map *__bpf_map_get(struct fd f);
+void bpf_map_inc(struct bpf_map *map, bool uref);
+void bpf_map_put_with_uref(struct bpf_map *map);
void bpf_map_put(struct bpf_map *map);
extern int sysctl_unprivileged_bpf_disabled;
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index e6797de..89d9aa9e 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -227,8 +227,6 @@ int cont_write_begin(struct file *, struct address_space *, loff_t,
get_block_t *, loff_t *);
int generic_cont_expand_simple(struct inode *inode, loff_t size);
int block_commit_write(struct page *page, unsigned from, unsigned to);
-int __block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
- get_block_t get_block);
int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf,
get_block_t get_block);
/* Convert errno to return value from ->page_mkwrite() call */
diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h
index 397c5cd..3e3799c 100644
--- a/include/linux/ceph/libceph.h
+++ b/include/linux/ceph/libceph.h
@@ -29,8 +29,9 @@
#define CEPH_OPT_NOSHARE (1<<1) /* don't share client with other sbs */
#define CEPH_OPT_MYIP (1<<2) /* specified my ip */
#define CEPH_OPT_NOCRC (1<<3) /* no data crc on writes */
-#define CEPH_OPT_NOMSGAUTH (1<<4) /* not require cephx message signature */
+#define CEPH_OPT_NOMSGAUTH (1<<4) /* don't require msg signing feat */
#define CEPH_OPT_TCP_NODELAY (1<<5) /* TCP_NODELAY on TCP sockets */
+#define CEPH_OPT_NOMSGSIGN (1<<6) /* don't sign msgs */
#define CEPH_OPT_DEFAULT (CEPH_OPT_TCP_NODELAY)
@@ -137,6 +138,7 @@ struct ceph_client {
#endif
};
+#define from_msgr(ms) container_of(ms, struct ceph_client, msgr)
/*
diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
index b2371d9..71b1d6c 100644
--- a/include/linux/ceph/messenger.h
+++ b/include/linux/ceph/messenger.h
@@ -43,10 +43,9 @@ struct ceph_connection_operations {
struct ceph_msg * (*alloc_msg) (struct ceph_connection *con,
struct ceph_msg_header *hdr,
int *skip);
- int (*sign_message) (struct ceph_connection *con, struct ceph_msg *msg);
- int (*check_message_signature) (struct ceph_connection *con,
- struct ceph_msg *msg);
+ int (*sign_message) (struct ceph_msg *msg);
+ int (*check_message_signature) (struct ceph_msg *msg);
};
/* use format string %s%d */
@@ -58,8 +57,6 @@ struct ceph_messenger {
atomic_t stopping;
possible_net_t net;
- bool nocrc;
- bool tcp_nodelay;
/*
* the global_seq counts connections i (attempt to) initiate
@@ -67,9 +64,6 @@ struct ceph_messenger {
*/
u32 global_seq;
spinlock_t global_seq_lock;
-
- u64 supported_features;
- u64 required_features;
};
enum ceph_msg_data_type {
@@ -268,11 +262,7 @@ extern void ceph_msgr_exit(void);
extern void ceph_msgr_flush(void);
extern void ceph_messenger_init(struct ceph_messenger *msgr,
- struct ceph_entity_addr *myaddr,
- u64 supported_features,
- u64 required_features,
- bool nocrc,
- bool tcp_nodelay);
+ struct ceph_entity_addr *myaddr);
extern void ceph_messenger_fini(struct ceph_messenger *msgr);
extern void ceph_con_init(struct ceph_connection *con, void *private,
diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h
index 60d44b2..06b77f9d 100644
--- a/include/linux/cgroup-defs.h
+++ b/include/linux/cgroup-defs.h
@@ -90,7 +90,6 @@ enum {
*/
struct cgroup_file {
/* do not access any fields from outside cgroup core */
- struct list_head node; /* anchored at css->files */
struct kernfs_node *kn;
};
@@ -134,9 +133,6 @@ struct cgroup_subsys_state {
*/
u64 serial_nr;
- /* all cgroup_files associated with this css */
- struct list_head files;
-
/* percpu_ref killing and RCU release */
struct rcu_head rcu_head;
struct work_struct destroy_work;
@@ -426,12 +422,9 @@ struct cgroup_subsys {
void (*css_reset)(struct cgroup_subsys_state *css);
void (*css_e_css_changed)(struct cgroup_subsys_state *css);
- int (*can_attach)(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset);
- void (*cancel_attach)(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset);
- void (*attach)(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset);
+ int (*can_attach)(struct cgroup_taskset *tset);
+ void (*cancel_attach)(struct cgroup_taskset *tset);
+ void (*attach)(struct cgroup_taskset *tset);
int (*can_fork)(struct task_struct *task, void **priv_p);
void (*cancel_fork)(struct task_struct *task, void *priv);
void (*fork)(struct task_struct *task, void *priv);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 22e3754..cb91b44 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -88,6 +88,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts);
int cgroup_rm_cftypes(struct cftype *cfts);
+void cgroup_file_notify(struct cgroup_file *cfile);
char *task_cgroup_path(struct task_struct *task, char *buf, size_t buflen);
int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry);
@@ -119,8 +120,10 @@ struct cgroup_subsys_state *css_rightmost_descendant(struct cgroup_subsys_state
struct cgroup_subsys_state *css_next_descendant_post(struct cgroup_subsys_state *pos,
struct cgroup_subsys_state *css);
-struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset);
-struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset);
+struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,
+ struct cgroup_subsys_state **dst_cssp);
+struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset,
+ struct cgroup_subsys_state **dst_cssp);
void css_task_iter_start(struct cgroup_subsys_state *css,
struct css_task_iter *it);
@@ -235,30 +238,39 @@ void css_task_iter_end(struct css_task_iter *it);
/**
* cgroup_taskset_for_each - iterate cgroup_taskset
* @task: the loop cursor
+ * @dst_css: the destination css
* @tset: taskset to iterate
*
* @tset may contain multiple tasks and they may belong to multiple
- * processes. When there are multiple tasks in @tset, if a task of a
- * process is in @tset, all tasks of the process are in @tset. Also, all
- * are guaranteed to share the same source and destination csses.
+ * processes.
+ *
+ * On the v2 hierarchy, there may be tasks from multiple processes and they
+ * may not share the source or destination csses.
+ *
+ * On traditional hierarchies, when there are multiple tasks in @tset, if a
+ * task of a process is in @tset, all tasks of the process are in @tset.
+ * Also, all are guaranteed to share the same source and destination csses.
*
* Iteration is not in any specific order.
*/
-#define cgroup_taskset_for_each(task, tset) \
- for ((task) = cgroup_taskset_first((tset)); (task); \
- (task) = cgroup_taskset_next((tset)))
+#define cgroup_taskset_for_each(task, dst_css, tset) \
+ for ((task) = cgroup_taskset_first((tset), &(dst_css)); \
+ (task); \
+ (task) = cgroup_taskset_next((tset), &(dst_css)))
/**
* cgroup_taskset_for_each_leader - iterate group leaders in a cgroup_taskset
* @leader: the loop cursor
+ * @dst_css: the destination css
* @tset: takset to iterate
*
* Iterate threadgroup leaders of @tset. For single-task migrations, @tset
* may not contain any.
*/
-#define cgroup_taskset_for_each_leader(leader, tset) \
- for ((leader) = cgroup_taskset_first((tset)); (leader); \
- (leader) = cgroup_taskset_next((tset))) \
+#define cgroup_taskset_for_each_leader(leader, dst_css, tset) \
+ for ((leader) = cgroup_taskset_first((tset), &(dst_css)); \
+ (leader); \
+ (leader) = cgroup_taskset_next((tset), &(dst_css))) \
if ((leader) != (leader)->group_leader) \
; \
else
@@ -516,19 +528,6 @@ static inline void pr_cont_cgroup_path(struct cgroup *cgrp)
pr_cont_kernfs_path(cgrp->kn);
}
-/**
- * cgroup_file_notify - generate a file modified event for a cgroup_file
- * @cfile: target cgroup_file
- *
- * @cfile must have been obtained by setting cftype->file_offset.
- */
-static inline void cgroup_file_notify(struct cgroup_file *cfile)
-{
- /* might not have been created due to one of the CFTYPE selector flags */
- if (cfile->kn)
- kernfs_notify(cfile->kn);
-}
-
#else /* !CONFIG_CGROUPS */
struct cgroup_subsys_state;
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 7784b59..6013021 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -62,12 +62,18 @@ struct module;
* @suspend: suspend function for the clocksource, if necessary
* @resume: resume function for the clocksource, if necessary
* @owner: module reference, must be set by clocksource in modules
+ *
+ * Note: This struct is not used in hotpathes of the timekeeping code
+ * because the timekeeper caches the hot path fields in its own data
+ * structure, so no line cache alignment is required,
+ *
+ * The pointer to the clocksource itself is handed to the read
+ * callback. If you need extra information there you can wrap struct
+ * clocksource into your own struct. Depending on the amount of
+ * information you need you should consider to cache line align that
+ * structure.
*/
struct clocksource {
- /*
- * Hotpath data, fits in a single cache line when the
- * clocksource itself is cacheline aligned.
- */
cycle_t (*read)(struct clocksource *cs);
cycle_t mask;
u32 mult;
@@ -95,7 +101,7 @@ struct clocksource {
cycle_t wd_last;
#endif
struct module *owner;
-} ____cacheline_aligned;
+};
/*
* Clock source flags bits::
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 4dac103..00b042c 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -299,6 +299,23 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
__u.__val; \
})
+/**
+ * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering
+ * @cond: boolean expression to wait for
+ *
+ * Equivalent to using smp_load_acquire() on the condition variable but employs
+ * the control dependency of the wait to reduce the barrier on many platforms.
+ *
+ * The control dependency provides a LOAD->STORE order, the additional RMB
+ * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
+ * aka. ACQUIRE.
+ */
+#define smp_cond_acquire(cond) do { \
+ while (!(cond)) \
+ cpu_relax(); \
+ smp_rmb(); /* ctrl + rmb := acquire */ \
+} while (0)
+
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
diff --git a/include/linux/component.h b/include/linux/component.h
index c00dcc3..a559eeb 100644
--- a/include/linux/component.h
+++ b/include/linux/component.h
@@ -1,39 +1,48 @@
#ifndef COMPONENT_H
#define COMPONENT_H
+#include <linux/stddef.h>
+
struct device;
struct component_ops {
- int (*bind)(struct device *, struct device *, void *);
- void (*unbind)(struct device *, struct device *, void *);
+ int (*bind)(struct device *comp, struct device *master,
+ void *master_data);
+ void (*unbind)(struct device *comp, struct device *master,
+ void *master_data);
};
int component_add(struct device *, const struct component_ops *);
void component_del(struct device *, const struct component_ops *);
-int component_bind_all(struct device *, void *);
-void component_unbind_all(struct device *, void *);
+int component_bind_all(struct device *master, void *master_data);
+void component_unbind_all(struct device *master, void *master_data);
struct master;
struct component_master_ops {
- int (*add_components)(struct device *, struct master *);
- int (*bind)(struct device *);
- void (*unbind)(struct device *);
+ int (*bind)(struct device *master);
+ void (*unbind)(struct device *master);
};
-int component_master_add(struct device *, const struct component_master_ops *);
void component_master_del(struct device *,
const struct component_master_ops *);
-int component_master_add_child(struct master *master,
- int (*compare)(struct device *, void *), void *compare_data);
-
struct component_match;
int component_master_add_with_match(struct device *,
const struct component_master_ops *, struct component_match *);
-void component_match_add(struct device *, struct component_match **,
+void component_match_add_release(struct device *master,
+ struct component_match **matchptr,
+ void (*release)(struct device *, void *),
int (*compare)(struct device *, void *), void *compare_data);
+static inline void component_match_add(struct device *master,
+ struct component_match **matchptr,
+ int (*compare)(struct device *, void *), void *compare_data)
+{
+ component_match_add_release(master, matchptr, NULL, compare,
+ compare_data);
+}
+
#endif
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 63a36e8..758a029 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -125,86 +125,33 @@ struct configfs_attribute {
const char *ca_name;
struct module *ca_owner;
umode_t ca_mode;
+ ssize_t (*show)(struct config_item *, char *);
+ ssize_t (*store)(struct config_item *, const char *, size_t);
};
-/*
- * Users often need to create attribute structures for their configurable
- * attributes, containing a configfs_attribute member and function pointers
- * for the show() and store() operations on that attribute. If they don't
- * need anything else on the extended attribute structure, they can use
- * this macro to define it The argument _item is the name of the
- * config_item structure.
- */
-#define CONFIGFS_ATTR_STRUCT(_item) \
-struct _item##_attribute { \
- struct configfs_attribute attr; \
- ssize_t (*show)(struct _item *, char *); \
- ssize_t (*store)(struct _item *, const char *, size_t); \
+#define CONFIGFS_ATTR(_pfx, _name) \
+static struct configfs_attribute _pfx##attr_##_name = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IRUGO | S_IWUSR, \
+ .ca_owner = THIS_MODULE, \
+ .show = _pfx##_name##_show, \
+ .store = _pfx##_name##_store, \
}
-/*
- * With the extended attribute structure, users can use this macro
- * (similar to sysfs' __ATTR) to make defining attributes easier.
- * An example:
- * #define MYITEM_ATTR(_name, _mode, _show, _store) \
- * struct myitem_attribute childless_attr_##_name = \
- * __CONFIGFS_ATTR(_name, _mode, _show, _store)
- */
-#define __CONFIGFS_ATTR(_name, _mode, _show, _store) \
-{ \
- .attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = _mode, \
- .ca_owner = THIS_MODULE, \
- }, \
- .show = _show, \
- .store = _store, \
-}
-/* Here is a readonly version, only requiring a show() operation */
-#define __CONFIGFS_ATTR_RO(_name, _show) \
-{ \
- .attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = 0444, \
- .ca_owner = THIS_MODULE, \
- }, \
- .show = _show, \
+#define CONFIGFS_ATTR_RO(_pfx, _name) \
+static struct configfs_attribute _pfx##attr_##_name = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IRUGO, \
+ .ca_owner = THIS_MODULE, \
+ .show = _pfx##_name##_show, \
}
-/*
- * With these extended attributes, the simple show_attribute() and
- * store_attribute() operations need to call the show() and store() of the
- * attributes. This is a common pattern, so we provide a macro to define
- * them. The argument _item is the name of the config_item structure.
- * This macro expects the attributes to be named "struct <name>_attribute"
- * and the function to_<name>() to exist;
- */
-#define CONFIGFS_ATTR_OPS(_item) \
-static ssize_t _item##_attr_show(struct config_item *item, \
- struct configfs_attribute *attr, \
- char *page) \
-{ \
- struct _item *_item = to_##_item(item); \
- struct _item##_attribute *_item##_attr = \
- container_of(attr, struct _item##_attribute, attr); \
- ssize_t ret = 0; \
- \
- if (_item##_attr->show) \
- ret = _item##_attr->show(_item, page); \
- return ret; \
-} \
-static ssize_t _item##_attr_store(struct config_item *item, \
- struct configfs_attribute *attr, \
- const char *page, size_t count) \
-{ \
- struct _item *_item = to_##_item(item); \
- struct _item##_attribute *_item##_attr = \
- container_of(attr, struct _item##_attribute, attr); \
- ssize_t ret = -EINVAL; \
- \
- if (_item##_attr->store) \
- ret = _item##_attr->store(_item, page, count); \
- return ret; \
+#define CONFIGFS_ATTR_WO(_pfx, _name) \
+static struct configfs_attribute _pfx##attr_##_name = { \
+ .ca_name = __stringify(_name), \
+ .ca_mode = S_IWUSR, \
+ .ca_owner = THIS_MODULE, \
+ .store = _pfx##_name##_store, \
}
/*
@@ -223,8 +170,6 @@ static ssize_t _item##_attr_store(struct config_item *item, \
*/
struct configfs_item_operations {
void (*release)(struct config_item *);
- ssize_t (*show_attribute)(struct config_item *, struct configfs_attribute *,char *);
- ssize_t (*store_attribute)(struct config_item *,struct configfs_attribute *,const char *, size_t);
int (*allow_link)(struct config_item *src, struct config_item *target);
int (*drop_link)(struct config_item *src, struct config_item *target);
};
@@ -252,6 +197,16 @@ static inline struct configfs_subsystem *to_configfs_subsystem(struct config_gro
int configfs_register_subsystem(struct configfs_subsystem *subsys);
void configfs_unregister_subsystem(struct configfs_subsystem *subsys);
+int configfs_register_group(struct config_group *parent_group,
+ struct config_group *group);
+void configfs_unregister_group(struct config_group *group);
+
+struct config_group *
+configfs_register_default_group(struct config_group *parent_group,
+ const char *name,
+ struct config_item_type *item_type);
+void configfs_unregister_default_group(struct config_group *group);
+
/* These functions can sleep and can alloc with GFP_KERNEL */
/* WARNING: These cannot be called underneath configfs callbacks!! */
int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target);
diff --git a/include/linux/context_tracking.h b/include/linux/context_tracking.h
index 008fc67..d259274 100644
--- a/include/linux/context_tracking.h
+++ b/include/linux/context_tracking.h
@@ -10,6 +10,10 @@
#ifdef CONFIG_CONTEXT_TRACKING
extern void context_tracking_cpu_set(int cpu);
+/* Called with interrupts disabled. */
+extern void __context_tracking_enter(enum ctx_state state);
+extern void __context_tracking_exit(enum ctx_state state);
+
extern void context_tracking_enter(enum ctx_state state);
extern void context_tracking_exit(enum ctx_state state);
extern void context_tracking_user_enter(void);
@@ -18,13 +22,13 @@ extern void context_tracking_user_exit(void);
static inline void user_enter(void)
{
if (context_tracking_is_enabled())
- context_tracking_user_enter();
+ context_tracking_enter(CONTEXT_USER);
}
static inline void user_exit(void)
{
if (context_tracking_is_enabled())
- context_tracking_user_exit();
+ context_tracking_exit(CONTEXT_USER);
}
static inline enum ctx_state exception_enter(void)
@@ -82,21 +86,21 @@ static inline void context_tracking_init(void) { }
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
static inline void guest_enter(void)
{
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
vtime_guest_enter(current);
else
current->flags |= PF_VCPU;
if (context_tracking_is_enabled())
- context_tracking_enter(CONTEXT_GUEST);
+ __context_tracking_enter(CONTEXT_GUEST);
}
static inline void guest_exit(void)
{
if (context_tracking_is_enabled())
- context_tracking_exit(CONTEXT_GUEST);
+ __context_tracking_exit(CONTEXT_GUEST);
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
vtime_guest_exit(current);
else
current->flags &= ~PF_VCPU;
diff --git a/include/linux/context_tracking_state.h b/include/linux/context_tracking_state.h
index ee956c5..1d34fe6 100644
--- a/include/linux/context_tracking_state.h
+++ b/include/linux/context_tracking_state.h
@@ -22,12 +22,12 @@ struct context_tracking {
};
#ifdef CONFIG_CONTEXT_TRACKING
-extern struct static_key context_tracking_enabled;
+extern struct static_key_false context_tracking_enabled;
DECLARE_PER_CPU(struct context_tracking, context_tracking);
static inline bool context_tracking_is_enabled(void)
{
- return static_key_false(&context_tracking_enabled);
+ return static_branch_unlikely(&context_tracking_enabled);
}
static inline bool context_tracking_cpu_is_enabled(void)
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ef4c5b1..177c768 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -77,6 +77,7 @@ struct cpufreq_policy {
unsigned int suspend_freq; /* freq to set during suspend */
unsigned int policy; /* see above */
+ unsigned int last_policy; /* policy before unplug */
struct cpufreq_governor *governor; /* see below */
void *governor_data;
bool governor_enabled; /* governor start/stop flag */
diff --git a/include/linux/delayed_call.h b/include/linux/delayed_call.h
new file mode 100644
index 0000000..f7fa76a
--- /dev/null
+++ b/include/linux/delayed_call.h
@@ -0,0 +1,34 @@
+#ifndef _DELAYED_CALL_H
+#define _DELAYED_CALL_H
+
+/*
+ * Poor man's closures; I wish we could've done them sanely polymorphic,
+ * but...
+ */
+
+struct delayed_call {
+ void (*fn)(void *);
+ void *arg;
+};
+
+#define DEFINE_DELAYED_CALL(name) struct delayed_call name = {NULL, NULL}
+
+/* I really wish we had closures with sane typechecking... */
+static inline void set_delayed_call(struct delayed_call *call,
+ void (*fn)(void *), void *arg)
+{
+ call->fn = fn;
+ call->arg = arg;
+}
+
+static inline void do_delayed_call(struct delayed_call *call)
+{
+ if (call->fn)
+ call->fn(call->arg);
+}
+
+static inline void clear_delayed_call(struct delayed_call *call)
+{
+ call->fn = NULL;
+}
+#endif
diff --git a/include/linux/devfreq_cooling.h b/include/linux/devfreq_cooling.h
new file mode 100644
index 0000000..7adf6cc
--- /dev/null
+++ b/include/linux/devfreq_cooling.h
@@ -0,0 +1,81 @@
+/*
+ * devfreq_cooling: Thermal cooling device implementation for devices using
+ * devfreq
+ *
+ * Copyright (C) 2014-2015 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DEVFREQ_COOLING_H__
+#define __DEVFREQ_COOLING_H__
+
+#include <linux/devfreq.h>
+#include <linux/thermal.h>
+
+#ifdef CONFIG_DEVFREQ_THERMAL
+
+/**
+ * struct devfreq_cooling_power - Devfreq cooling power ops
+ * @get_static_power: Take voltage, in mV, and return the static power
+ * in mW. If NULL, the static power is assumed
+ * to be 0.
+ * @get_dynamic_power: Take voltage, in mV, and frequency, in HZ, and
+ * return the dynamic power draw in mW. If NULL,
+ * a simple power model is used.
+ * @dyn_power_coeff: Coefficient for the simple dynamic power model in
+ * mW/(MHz mV mV).
+ * If get_dynamic_power() is NULL, then the
+ * dynamic power is calculated as
+ * @dyn_power_coeff * frequency * voltage^2
+ */
+struct devfreq_cooling_power {
+ unsigned long (*get_static_power)(unsigned long voltage);
+ unsigned long (*get_dynamic_power)(unsigned long freq,
+ unsigned long voltage);
+ unsigned long dyn_power_coeff;
+};
+
+struct thermal_cooling_device *
+of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
+ struct devfreq_cooling_power *dfc_power);
+struct thermal_cooling_device *
+of_devfreq_cooling_register(struct device_node *np, struct devfreq *df);
+struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df);
+void devfreq_cooling_unregister(struct thermal_cooling_device *dfc);
+
+#else /* !CONFIG_DEVFREQ_THERMAL */
+
+struct thermal_cooling_device *
+of_devfreq_cooling_register_power(struct device_node *np, struct devfreq *df,
+ struct devfreq_cooling_power *dfc_power)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline struct thermal_cooling_device *
+of_devfreq_cooling_register(struct device_node *np, struct devfreq *df)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline struct thermal_cooling_device *
+devfreq_cooling_register(struct devfreq *df)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+static inline void
+devfreq_cooling_unregister(struct thermal_cooling_device *dfc)
+{
+}
+
+#endif /* CONFIG_DEVFREQ_THERMAL */
+#endif /* __DEVFREQ_COOLING_H__ */
diff --git a/include/linux/device.h b/include/linux/device.h
index 5d7bc63..b8f411b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -604,13 +604,21 @@ typedef void (*dr_release_t)(struct device *dev, void *res);
typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data);
#ifdef CONFIG_DEBUG_DEVRES
-extern void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp,
- const char *name);
+extern void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp,
+ int nid, const char *name);
#define devres_alloc(release, size, gfp) \
- __devres_alloc(release, size, gfp, #release)
+ __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release)
+#define devres_alloc_node(release, size, gfp, nid) \
+ __devres_alloc_node(release, size, gfp, nid, #release)
#else
-extern void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp);
+extern void *devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp,
+ int nid);
+static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp)
+{
+ return devres_alloc_node(release, size, gfp, NUMA_NO_NODE);
+}
#endif
+
extern void devres_for_each_res(struct device *dev, dr_release_t release,
dr_match_t match, void *match_data,
void (*fn)(struct device *, void *, void *),
diff --git a/include/linux/dns_resolver.h b/include/linux/dns_resolver.h
index cc92268..6ac3cad 100644
--- a/include/linux/dns_resolver.h
+++ b/include/linux/dns_resolver.h
@@ -27,7 +27,7 @@
#ifdef __KERNEL__
extern int dns_query(const char *type, const char *name, size_t namelen,
- const char *options, char **_result, time_t *_expiry);
+ const char *options, char **_result, time64_t *_expiry);
#endif /* KERNEL */
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 4fe67b8..9e0d789 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -28,12 +28,10 @@ struct device;
extern int edac_op_state;
extern int edac_err_assert;
extern atomic_t edac_handlers;
-extern struct bus_type edac_subsys;
extern int edac_handler_set(void);
extern void edac_atomic_assert_error(void);
extern struct bus_type *edac_get_sysfs_subsys(void);
-extern void edac_put_sysfs_subsys(void);
enum {
EDAC_REPORTING_ENABLED,
@@ -237,8 +235,10 @@ enum mem_type {
#define MEM_FLAG_FB_DDR2 BIT(MEM_FB_DDR2)
#define MEM_FLAG_RDDR2 BIT(MEM_RDDR2)
#define MEM_FLAG_XDR BIT(MEM_XDR)
-#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
-#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR3 BIT(MEM_DDR3)
+#define MEM_FLAG_RDDR3 BIT(MEM_RDDR3)
+#define MEM_FLAG_DDR4 BIT(MEM_DDR4)
+#define MEM_FLAG_RDDR4 BIT(MEM_RDDR4)
/**
* enum edac-type - Error Detection and Correction capabilities and mode
diff --git a/include/linux/enclosure.h b/include/linux/enclosure.h
index 7be22da..a4cf57c 100644
--- a/include/linux/enclosure.h
+++ b/include/linux/enclosure.h
@@ -29,7 +29,11 @@
/* A few generic types ... taken from ses-2 */
enum enclosure_component_type {
ENCLOSURE_COMPONENT_DEVICE = 0x01,
+ ENCLOSURE_COMPONENT_CONTROLLER_ELECTRONICS = 0x07,
+ ENCLOSURE_COMPONENT_SCSI_TARGET_PORT = 0x14,
+ ENCLOSURE_COMPONENT_SCSI_INITIATOR_PORT = 0x15,
ENCLOSURE_COMPONENT_ARRAY_DEVICE = 0x17,
+ ENCLOSURE_COMPONENT_SAS_EXPANDER = 0x18,
};
/* ses-2 common element status */
diff --git a/include/linux/filter.h b/include/linux/filter.h
index 4165e9a..5972ffe 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -493,6 +493,25 @@ static inline void bpf_jit_free(struct bpf_prog *fp)
#define BPF_ANC BIT(15)
+static inline bool bpf_needs_clear_a(const struct sock_filter *first)
+{
+ switch (first->code) {
+ case BPF_RET | BPF_K:
+ case BPF_LD | BPF_W | BPF_LEN:
+ return false;
+
+ case BPF_LD | BPF_W | BPF_ABS:
+ case BPF_LD | BPF_H | BPF_ABS:
+ case BPF_LD | BPF_B | BPF_ABS:
+ if (first->k == SKF_AD_OFF + SKF_AD_ALU_XOR_X)
+ return true;
+ return false;
+
+ default:
+ return true;
+ }
+}
+
static inline u16 bpf_anc_helper(const struct sock_filter *ftest)
{
BUG_ON(ftest->code & BPF_ANC);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9a1cb8c..731262c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -31,6 +31,7 @@
#include <linux/blk_types.h>
#include <linux/workqueue.h>
#include <linux/percpu-rwsem.h>
+#include <linux/delayed_call.h>
#include <asm/byteorder.h>
#include <uapi/linux/fs.h>
@@ -1042,7 +1043,7 @@ extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg);
extern int fcntl_getlease(struct file *filp);
/* fs/locks.c */
-void locks_free_lock_context(struct file_lock_context *ctx);
+void locks_free_lock_context(struct inode *inode);
void locks_free_lock(struct file_lock *fl);
extern void locks_init_lock(struct file_lock *);
extern struct file_lock * locks_alloc_lock(void);
@@ -1103,7 +1104,7 @@ static inline int fcntl_getlease(struct file *filp)
}
static inline void
-locks_free_lock_context(struct file_lock_context *ctx)
+locks_free_lock_context(struct inode *inode)
{
}
@@ -1629,16 +1630,21 @@ struct file_operations {
#ifndef CONFIG_MMU
unsigned (*mmap_capabilities)(struct file *);
#endif
+ ssize_t (*copy_file_range)(struct file *, loff_t, struct file *,
+ loff_t, size_t, unsigned int);
+ int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t,
+ u64);
+ ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
+ u64);
};
struct inode_operations {
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
- const char * (*follow_link) (struct dentry *, void **);
+ const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *);
int (*permission) (struct inode *, int);
struct posix_acl * (*get_acl)(struct inode *, int);
int (*readlink) (struct dentry *, char __user *,int);
- void (*put_link) (struct inode *, void *);
int (*create) (struct inode *,struct dentry *, umode_t, bool);
int (*link) (struct dentry *,struct inode *,struct dentry *);
@@ -1665,8 +1671,6 @@ struct inode_operations {
umode_t create_mode, int *opened);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
int (*set_acl)(struct inode *, struct posix_acl *, int);
-
- /* WARNING: probably going away soon, do not use! */
} ____cacheline_aligned;
ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
@@ -1682,6 +1686,12 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
unsigned long, loff_t *);
extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
unsigned long, loff_t *);
+extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *,
+ loff_t, size_t, unsigned int);
+extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in,
+ struct file *file_out, loff_t pos_out, u64 len);
+extern int vfs_dedupe_file_range(struct file *file,
+ struct file_dedupe_range *same);
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
@@ -2029,12 +2039,9 @@ extern struct kobject *fs_kobj;
#define MAX_RW_COUNT (INT_MAX & PAGE_CACHE_MASK)
-#define FLOCK_VERIFY_READ 1
-#define FLOCK_VERIFY_WRITE 2
-
-#ifdef CONFIG_FILE_LOCKING
+#ifdef CONFIG_MANDATORY_FILE_LOCKING
extern int locks_mandatory_locked(struct file *);
-extern int locks_mandatory_area(int, struct inode *, struct file *, loff_t, size_t);
+extern int locks_mandatory_area(struct inode *, struct file *, loff_t, loff_t, unsigned char);
/*
* Candidates for mandatory locking have the setgid bit set
@@ -2064,19 +2071,59 @@ static inline int locks_verify_locked(struct file *file)
}
static inline int locks_verify_truncate(struct inode *inode,
- struct file *filp,
+ struct file *f,
loff_t size)
{
- if (inode->i_flctx && mandatory_lock(inode))
- return locks_mandatory_area(
- FLOCK_VERIFY_WRITE, inode, filp,
- size < inode->i_size ? size : inode->i_size,
- (size < inode->i_size ? inode->i_size - size
- : size - inode->i_size)
- );
+ if (!inode->i_flctx || !mandatory_lock(inode))
+ return 0;
+
+ if (size < inode->i_size) {
+ return locks_mandatory_area(inode, f, size, inode->i_size - 1,
+ F_WRLCK);
+ } else {
+ return locks_mandatory_area(inode, f, inode->i_size, size - 1,
+ F_WRLCK);
+ }
+}
+
+#else /* !CONFIG_MANDATORY_FILE_LOCKING */
+
+static inline int locks_mandatory_locked(struct file *file)
+{
+ return 0;
+}
+
+static inline int locks_mandatory_area(struct inode *inode, struct file *filp,
+ loff_t start, loff_t end, unsigned char type)
+{
+ return 0;
+}
+
+static inline int __mandatory_lock(struct inode *inode)
+{
+ return 0;
+}
+
+static inline int mandatory_lock(struct inode *inode)
+{
+ return 0;
+}
+
+static inline int locks_verify_locked(struct file *file)
+{
+ return 0;
+}
+
+static inline int locks_verify_truncate(struct inode *inode, struct file *filp,
+ size_t size)
+{
return 0;
}
+#endif /* CONFIG_MANDATORY_FILE_LOCKING */
+
+
+#ifdef CONFIG_FILE_LOCKING
static inline int break_lease(struct inode *inode, unsigned int mode)
{
/*
@@ -2138,39 +2185,6 @@ static inline int break_layout(struct inode *inode, bool wait)
}
#else /* !CONFIG_FILE_LOCKING */
-static inline int locks_mandatory_locked(struct file *file)
-{
- return 0;
-}
-
-static inline int locks_mandatory_area(int rw, struct inode *inode,
- struct file *filp, loff_t offset,
- size_t count)
-{
- return 0;
-}
-
-static inline int __mandatory_lock(struct inode *inode)
-{
- return 0;
-}
-
-static inline int mandatory_lock(struct inode *inode)
-{
- return 0;
-}
-
-static inline int locks_verify_locked(struct file *file)
-{
- return 0;
-}
-
-static inline int locks_verify_truncate(struct inode *inode, struct file *filp,
- size_t size)
-{
- return 0;
-}
-
static inline int break_lease(struct inode *inode, unsigned int mode)
{
return 0;
@@ -2293,9 +2307,9 @@ static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void
{
}
-static inline int sb_is_blkdev_sb(struct super_block *sb)
+static inline bool sb_is_blkdev_sb(struct super_block *sb)
{
- return 0;
+ return false;
}
#endif
extern int sync_filesystem(struct super_block *);
@@ -2373,7 +2387,7 @@ extern void init_special_inode(struct inode *, umode_t, dev_t);
/* Invalid inode operations -- fs/bad_inode.c */
extern void make_bad_inode(struct inode *);
-extern int is_bad_inode(struct inode *);
+extern bool is_bad_inode(struct inode *);
#ifdef CONFIG_BLOCK
/*
@@ -2534,8 +2548,8 @@ extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *);
extern struct file * open_exec(const char *);
/* fs/dcache.c -- generic fs support functions */
-extern int is_subdir(struct dentry *, struct dentry *);
-extern int path_is_under(struct path *, struct path *);
+extern bool is_subdir(struct dentry *, struct dentry *);
+extern bool path_is_under(struct path *, struct path *);
extern char *file_path(struct file *, char *, int);
@@ -2613,7 +2627,7 @@ static inline void remove_inode_hash(struct inode *inode)
extern void inode_sb_list_add(struct inode *inode);
#ifdef CONFIG_BLOCK
-extern void submit_bio(int, struct bio *);
+extern blk_qc_t submit_bio(int, struct bio *);
extern int bdev_read_only(struct block_device *);
#endif
extern int set_blocksize(struct block_device *, int);
@@ -2662,6 +2676,8 @@ extern loff_t generic_file_llseek_size(struct file *file, loff_t offset,
int whence, loff_t maxsize, loff_t eof);
extern loff_t fixed_size_llseek(struct file *file, loff_t offset,
int whence, loff_t size);
+extern loff_t no_seek_end_llseek_size(struct file *, loff_t, int, loff_t);
+extern loff_t no_seek_end_llseek(struct file *, loff_t, int);
extern int generic_file_open(struct inode * inode, struct file * filp);
extern int nonseekable_open(struct inode * inode, struct file * filp);
@@ -2738,14 +2754,14 @@ extern const struct file_operations generic_ro_fops;
extern int readlink_copy(char __user *, int, const char *);
extern int page_readlink(struct dentry *, char __user *, int);
-extern const char *page_follow_link_light(struct dentry *, void **);
-extern void page_put_link(struct inode *, void *);
+extern const char *page_get_link(struct dentry *, struct inode *,
+ struct delayed_call *);
+extern void page_put_link(void *);
extern int __page_symlink(struct inode *inode, const char *symname, int len,
int nofs);
extern int page_symlink(struct inode *inode, const char *symname, int len);
extern const struct inode_operations page_symlink_inode_operations;
-extern void kfree_put_link(struct inode *, void *);
-extern void free_page_put_link(struct inode *, void *);
+extern void kfree_link(void *);
extern int generic_readlink(struct dentry *, char __user *, int);
extern void generic_fillattr(struct inode *, struct kstat *);
int vfs_getattr_nosec(struct path *path, struct kstat *stat);
@@ -2756,7 +2772,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
void inode_sub_bytes(struct inode *inode, loff_t bytes);
loff_t inode_get_bytes(struct inode *inode);
void inode_set_bytes(struct inode *inode, loff_t bytes);
-const char *simple_follow_link(struct dentry *, void **);
+const char *simple_get_link(struct dentry *, struct inode *,
+ struct delayed_call *);
extern const struct inode_operations simple_symlink_inode_operations;
extern int iterate_dir(struct file *, struct dir_context *);
@@ -2766,8 +2783,6 @@ extern int vfs_lstat(const char __user *, struct kstat *);
extern int vfs_fstat(unsigned int, struct kstat *);
extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
-extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
- unsigned long arg);
extern int __generic_block_fiemap(struct inode *inode,
struct fiemap_extent_info *fieinfo,
loff_t start, loff_t len,
@@ -2965,7 +2980,7 @@ int __init get_filesystem_list(char *buf);
#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \
(flag & __FMODE_NONOTIFY)))
-static inline int is_sxid(umode_t mode)
+static inline bool is_sxid(umode_t mode)
{
return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP));
}
@@ -3027,5 +3042,6 @@ static inline bool dir_relax(struct inode *inode)
}
extern bool path_noexec(const struct path *path);
+extern void inode_nohighmem(struct inode *inode);
#endif /* _LINUX_FS_H */
diff --git a/include/linux/fsl/edac.h b/include/linux/fsl/edac.h
new file mode 100644
index 0000000..90d64d4
--- /dev/null
+++ b/include/linux/fsl/edac.h
@@ -0,0 +1,8 @@
+#ifndef FSL_EDAC_H
+#define FSL_EDAC_H
+
+struct mpc85xx_edac_pci_plat_data {
+ struct device_node *of_node;
+};
+
+#endif
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index eae6548..60048c5 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -586,6 +586,7 @@ extern int ftrace_arch_read_dyn_info(char *buf, int size);
extern int skip_trace(unsigned long ip);
extern void ftrace_module_init(struct module *mod);
+extern void ftrace_release_mod(struct module *mod);
extern void ftrace_disable_daemon(void);
extern void ftrace_enable_daemon(void);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 6523109..8942af0 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -271,7 +271,7 @@ static inline int gfpflags_to_migratetype(const gfp_t gfp_flags)
static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
{
- return gfp_flags & __GFP_DIRECT_RECLAIM;
+ return (bool __force)(gfp_flags & __GFP_DIRECT_RECLAIM);
}
#ifdef CONFIG_HIGHMEM
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 685c262..b0eb064 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -96,9 +96,7 @@ u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
struct address_space *mapping,
pgoff_t idx, unsigned long address);
-#ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE
pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud);
-#endif
extern int hugepages_treat_as_movable;
extern int sysctl_hugetlb_shm_group;
diff --git a/include/linux/i2c-ocores.h b/include/linux/i2c-ocores.h
index 1c06b5c..01edd96 100644
--- a/include/linux/i2c-ocores.h
+++ b/include/linux/i2c-ocores.h
@@ -15,6 +15,7 @@ struct ocores_i2c_platform_data {
u32 reg_shift; /* register offset shift value */
u32 reg_io_width; /* register io read/write width */
u32 clock_khz; /* input clock in kHz */
+ bool big_endian; /* registers are big endian */
u8 num_devices; /* number of devices in the devices list */
struct i2c_board_info const *devices; /* devices connected to the bus */
};
diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h
deleted file mode 100644
index 496f5c2..0000000
--- a/include/linux/i2c/i2c-rcar.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __I2C_R_CAR_H__
-#define __I2C_R_CAR_H__
-
-#include <linux/platform_device.h>
-
-struct i2c_rcar_platform_data {
- u32 bus_speed;
-};
-
-#endif /* __I2C_R_CAR_H__ */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 1c1ff7e..f2cb8d4 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -150,7 +150,7 @@ extern struct task_group root_task_group;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
# define INIT_VTIME(tsk) \
- .vtime_seqlock = __SEQLOCK_UNLOCKED(tsk.vtime_seqlock), \
+ .vtime_seqcount = SEQCNT_ZERO(tsk.vtime_seqcount), \
.vtime_snap = 0, \
.vtime_snap_whence = VTIME_SYS,
#else
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index ad16809..cb30edb 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -195,6 +195,7 @@ extern void disable_irq(unsigned int irq);
extern void disable_percpu_irq(unsigned int irq);
extern void enable_irq(unsigned int irq);
extern void enable_percpu_irq(unsigned int irq, unsigned int type);
+extern bool irq_percpu_is_enabled(unsigned int irq);
extern void irq_wake_thread(unsigned int irq, void *dev_id);
/* The following three functions are for the core kernel use only. */
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 0ef2a97..402753b 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -227,7 +227,7 @@ struct ipv6_pinfo {
struct ipv6_ac_socklist *ipv6_ac_list;
struct ipv6_fl_socklist __rcu *ipv6_fl_list;
- struct ipv6_txoptions *opt;
+ struct ipv6_txoptions __rcu *opt;
struct sk_buff *pktoptions;
struct sk_buff *rxpmtu;
struct inet6_cork cork;
diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
index c9ae0c6..d5d798b 100644
--- a/include/linux/irqchip/arm-gic-v3.h
+++ b/include/linux/irqchip/arm-gic-v3.h
@@ -330,6 +330,7 @@ struct rdists {
};
struct irq_domain;
+struct device_node;
int its_cpu_init(void);
int its_init(struct device_node *node, struct rdists *rdists,
struct irq_domain *domain);
diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h
index bae69e5..9c94026 100644
--- a/include/linux/irqchip/arm-gic.h
+++ b/include/linux/irqchip/arm-gic.h
@@ -103,10 +103,21 @@ struct device_node;
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
int gic_cpu_if_down(unsigned int gic_nr);
+/*
+ * Subdrivers that need some preparatory work can initialize their
+ * chips and call this to register their GICs.
+ */
+int gic_of_init(struct device_node *node, struct device_node *parent);
+
+/*
+ * Legacy platforms not converted to DT yet must use this to init
+ * their GIC
+ */
void gic_init(unsigned int nr, int start,
void __iomem *dist , void __iomem *cpu);
-int gicv2m_of_init(struct device_node *node, struct irq_domain *parent);
+int gicv2m_init(struct fwnode_handle *parent_handle,
+ struct irq_domain *parent);
void gic_send_sgi(unsigned int cpu_id, unsigned int irq);
int gic_get_cpu_id(unsigned int cpu);
diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h
index 4e68616..ce824db 100644
--- a/include/linux/irqchip/mips-gic.h
+++ b/include/linux/irqchip/mips-gic.h
@@ -9,6 +9,7 @@
#define __LINUX_IRQCHIP_MIPS_GIC_H
#include <linux/clocksource.h>
+#include <linux/ioport.h>
#define GIC_MAX_INTRS 256
@@ -245,6 +246,8 @@
#define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x))
#define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE)
+#ifdef CONFIG_MIPS_GIC
+
extern unsigned int gic_present;
extern void gic_init(unsigned long gic_base_addr,
@@ -264,4 +267,18 @@ extern unsigned int plat_ipi_resched_int_xlate(unsigned int);
extern int gic_get_c0_compare_int(void);
extern int gic_get_c0_perfcount_int(void);
extern int gic_get_c0_fdc_int(void);
+extern int gic_get_usm_range(struct resource *gic_usm_res);
+
+#else /* CONFIG_MIPS_GIC */
+
+#define gic_present 0
+
+static inline int gic_get_usm_range(struct resource *gic_usm_res)
+{
+ /* Shouldn't be called. */
+ return -1;
+}
+
+#endif /* CONFIG_MIPS_GIC */
+
#endif /* __LINUX_IRQCHIP_MIPS_GIC_H */
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index a587a33..dcca77c 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_IRQDESC_H
#define _LINUX_IRQDESC_H
+#include <linux/rcupdate.h>
+
/*
* Core internal functions to deal with irq descriptors
*/
@@ -40,6 +42,7 @@ struct pt_regs;
* IRQF_NO_SUSPEND set
* @force_resume_depth: number of irqactions on a irq descriptor with
* IRQF_FORCE_RESUME set
+ * @rcu: rcu head for delayed free
* @dir: /proc/irq/ procfs entry
* @name: flow handler name for /proc/interrupts output
*/
@@ -82,6 +85,9 @@ struct irq_desc {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *dir;
#endif
+#ifdef CONFIG_SPARSE_IRQ
+ struct rcu_head rcu;
+#endif
int parent_irq;
struct module *owner;
const char *name;
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index d5e5c5b..f64622a 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -211,6 +211,11 @@ static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node)
return node ? &node->fwnode : NULL;
}
+static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_IRQCHIP;
+}
+
static inline struct irq_domain *irq_find_matching_host(struct device_node *node,
enum irq_domain_bus_token bus_token)
{
@@ -367,6 +372,9 @@ static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
}
+extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs, void *arg);
extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
unsigned int virq,
irq_hw_number_t hwirq,
@@ -410,6 +418,11 @@ static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
static inline void irq_dispose_mapping(unsigned int virq) { }
static inline void irq_domain_activate_irq(struct irq_data *data) { }
static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
+static inline struct irq_domain *irq_find_matching_fwnode(
+ struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token)
+{
+ return NULL;
+}
#endif /* !CONFIG_IRQ_DOMAIN */
#endif /* _LINUX_IRQDOMAIN_H */
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h
index 8dde559..0536524 100644
--- a/include/linux/jump_label.h
+++ b/include/linux/jump_label.h
@@ -5,7 +5,7 @@
* Jump label support
*
* Copyright (C) 2009-2012 Jason Baron <jbaron@redhat.com>
- * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
*
* DEPRECATED API:
*
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 350dfb0..7311c32 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -255,6 +255,7 @@ extern long (*panic_blink)(int state);
__printf(1, 2)
void panic(const char *fmt, ...)
__noreturn __cold;
+void nmi_panic_self_stop(struct pt_regs *);
extern void oops_enter(void);
extern void oops_exit(void);
void print_oops_end_marker(void);
@@ -446,6 +447,33 @@ extern int sysctl_panic_on_stackoverflow;
extern bool crash_kexec_post_notifiers;
/*
+ * panic_cpu is used for synchronizing panic() and crash_kexec() execution. It
+ * holds a CPU number which is executing panic() currently. A value of
+ * PANIC_CPU_INVALID means no CPU has entered panic() or crash_kexec().
+ */
+extern atomic_t panic_cpu;
+#define PANIC_CPU_INVALID -1
+
+/*
+ * A variant of panic() called from NMI context. We return if we've already
+ * panicked on this CPU. If another CPU already panicked, loop in
+ * nmi_panic_self_stop() which can provide architecture dependent code such
+ * as saving register state for crash dump.
+ */
+#define nmi_panic(regs, fmt, ...) \
+do { \
+ int old_cpu, cpu; \
+ \
+ cpu = raw_smp_processor_id(); \
+ old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, cpu); \
+ \
+ if (old_cpu == PANIC_CPU_INVALID) \
+ panic(fmt, ##__VA_ARGS__); \
+ else if (old_cpu != cpu) \
+ nmi_panic_self_stop(regs); \
+} while (0)
+
+/*
* Only to be used by arch init code. If the user over-wrote the default
* CONFIG_PANIC_TIMEOUT, honor it.
*/
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index d140b1e..7b68d27 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -237,6 +237,7 @@ extern int kexec_purgatory_get_set_symbol(struct kimage *image,
unsigned int size, bool get_value);
extern void *kexec_purgatory_get_symbol_addr(struct kimage *image,
const char *name);
+extern void __crash_kexec(struct pt_regs *);
extern void crash_kexec(struct pt_regs *);
int kexec_should_crash(struct task_struct *);
void crash_save_cpu(struct pt_regs *regs, int cpu);
@@ -332,6 +333,7 @@ int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs,
#else /* !CONFIG_KEXEC_CORE */
struct pt_regs;
struct task_struct;
+static inline void __crash_kexec(struct pt_regs *regs) { }
static inline void crash_kexec(struct pt_regs *regs) { }
static inline int kexec_should_crash(struct task_struct *p) { return 0; }
#define kexec_in_progress false
diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h
index d0a1f99..4894c68 100644
--- a/include/linux/kmemleak.h
+++ b/include/linux/kmemleak.h
@@ -25,7 +25,7 @@
#ifdef CONFIG_DEBUG_KMEMLEAK
-extern void kmemleak_init(void) __ref;
+extern void kmemleak_init(void) __init;
extern void kmemleak_alloc(const void *ptr, size_t size, int min_count,
gfp_t gfp) __ref;
extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size,
diff --git a/include/linux/kref.h b/include/linux/kref.h
index 484604d..e15828f 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -19,7 +19,6 @@
#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
-#include <linux/spinlock.h>
struct kref {
atomic_t refcount;
@@ -99,38 +98,6 @@ static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)
return kref_sub(kref, 1, release);
}
-/**
- * kref_put_spinlock_irqsave - decrement refcount for object.
- * @kref: object.
- * @release: pointer to the function that will clean up the object when the
- * last reference to the object is released.
- * This pointer is required, and it is not acceptable to pass kfree
- * in as this function.
- * @lock: lock to take in release case
- *
- * Behaves identical to kref_put with one exception. If the reference count
- * drops to zero, the lock will be taken atomically wrt dropping the reference
- * count. The release function has to call spin_unlock() without _irqrestore.
- */
-static inline int kref_put_spinlock_irqsave(struct kref *kref,
- void (*release)(struct kref *kref),
- spinlock_t *lock)
-{
- unsigned long flags;
-
- WARN_ON(release == NULL);
- if (atomic_add_unless(&kref->refcount, -1, 1))
- return 0;
- spin_lock_irqsave(lock, flags);
- if (atomic_dec_and_test(&kref->refcount)) {
- release(kref);
- local_irq_restore(flags);
- return 1;
- }
- spin_unlock_irqrestore(lock, flags);
- return 0;
-}
-
static inline int kref_put_mutex(struct kref *kref,
void (*release)(struct kref *kref),
struct mutex *lock)
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 242a6d2..f707f74 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -111,38 +111,13 @@ static inline bool is_error_page(struct page *page)
}
/*
- * vcpu->requests bit members
+ * Architecture-independent vcpu->requests bit members
+ * Bits 4-7 are reserved for more arch-independent bits.
*/
#define KVM_REQ_TLB_FLUSH 0
-#define KVM_REQ_MIGRATE_TIMER 1
-#define KVM_REQ_REPORT_TPR_ACCESS 2
-#define KVM_REQ_MMU_RELOAD 3
-#define KVM_REQ_TRIPLE_FAULT 4
-#define KVM_REQ_PENDING_TIMER 5
-#define KVM_REQ_UNHALT 6
-#define KVM_REQ_MMU_SYNC 7
-#define KVM_REQ_CLOCK_UPDATE 8
-#define KVM_REQ_KICK 9
-#define KVM_REQ_DEACTIVATE_FPU 10
-#define KVM_REQ_EVENT 11
-#define KVM_REQ_APF_HALT 12
-#define KVM_REQ_STEAL_UPDATE 13
-#define KVM_REQ_NMI 14
-#define KVM_REQ_PMU 15
-#define KVM_REQ_PMI 16
-#define KVM_REQ_WATCHDOG 17
-#define KVM_REQ_MASTERCLOCK_UPDATE 18
-#define KVM_REQ_MCLOCK_INPROGRESS 19
-#define KVM_REQ_EPR_EXIT 20
-#define KVM_REQ_SCAN_IOAPIC 21
-#define KVM_REQ_GLOBAL_CLOCK_UPDATE 22
-#define KVM_REQ_ENABLE_IBS 23
-#define KVM_REQ_DISABLE_IBS 24
-#define KVM_REQ_APIC_PAGE_RELOAD 25
-#define KVM_REQ_SMI 26
-#define KVM_REQ_HV_CRASH 27
-#define KVM_REQ_IOAPIC_EOI_EXIT 28
-#define KVM_REQ_HV_RESET 29
+#define KVM_REQ_MMU_RELOAD 1
+#define KVM_REQ_PENDING_TIMER 2
+#define KVM_REQ_UNHALT 3
#define KVM_USERSPACE_IRQ_SOURCE_ID 0
#define KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID 1
@@ -318,6 +293,11 @@ struct kvm_s390_adapter_int {
u32 adapter_id;
};
+struct kvm_hv_sint {
+ u32 vcpu;
+ u32 sint;
+};
+
struct kvm_kernel_irq_routing_entry {
u32 gsi;
u32 type;
@@ -331,6 +311,7 @@ struct kvm_kernel_irq_routing_entry {
} irqchip;
struct msi_msg msi;
struct kvm_s390_adapter_int adapter;
+ struct kvm_hv_sint hv_sint;
};
struct hlist_node link;
};
@@ -439,10 +420,13 @@ struct kvm {
/* The guest did something we don't support. */
#define vcpu_unimpl(vcpu, fmt, ...) \
- kvm_pr_unimpl("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
+ kvm_pr_unimpl("vcpu%i, guest rIP: 0x%lx " fmt, \
+ (vcpu)->vcpu_id, kvm_rip_read(vcpu), ## __VA_ARGS__)
#define vcpu_debug(vcpu, fmt, ...) \
kvm_debug("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
+#define vcpu_err(vcpu, fmt, ...) \
+ kvm_err("vcpu%i " fmt, (vcpu)->vcpu_id, ## __VA_ARGS__)
static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
{
@@ -460,6 +444,22 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i)
(vcpup = kvm_get_vcpu(kvm, idx)) != NULL; \
idx++)
+static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id)
+{
+ struct kvm_vcpu *vcpu;
+ int i;
+
+ if (id < 0 || id >= KVM_MAX_VCPUS)
+ return NULL;
+ vcpu = kvm_get_vcpu(kvm, id);
+ if (vcpu && vcpu->vcpu_id == id)
+ return vcpu;
+ kvm_for_each_vcpu(i, vcpu, kvm)
+ if (vcpu->vcpu_id == id)
+ return vcpu;
+ return NULL;
+}
+
#define kvm_for_each_memslot(memslot, slots) \
for (memslot = &slots->memslots[0]; \
memslot < slots->memslots + KVM_MEM_SLOTS_NUM && memslot->npages;\
@@ -473,12 +473,12 @@ void vcpu_put(struct kvm_vcpu *vcpu);
#ifdef __KVM_HAVE_IOAPIC
void kvm_vcpu_request_scan_ioapic(struct kvm *kvm);
-void kvm_arch_irq_routing_update(struct kvm *kvm);
+void kvm_arch_post_irq_routing_update(struct kvm *kvm);
#else
static inline void kvm_vcpu_request_scan_ioapic(struct kvm *kvm)
{
}
-static inline void kvm_arch_irq_routing_update(struct kvm *kvm)
+static inline void kvm_arch_post_irq_routing_update(struct kvm *kvm)
{
}
#endif
@@ -623,7 +623,7 @@ int kvm_gfn_to_hva_cache_init(struct kvm *kvm, struct gfn_to_hva_cache *ghc,
int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);
int kvm_clear_guest(struct kvm *kvm, gpa_t gpa, unsigned long len);
struct kvm_memory_slot *gfn_to_memslot(struct kvm *kvm, gfn_t gfn);
-int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
+bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn);
unsigned long kvm_host_page_size(struct kvm *kvm, gfn_t gfn);
void mark_page_dirty(struct kvm *kvm, gfn_t gfn);
@@ -657,8 +657,6 @@ void kvm_put_guest_fpu(struct kvm_vcpu *vcpu);
void kvm_flush_remote_tlbs(struct kvm *kvm);
void kvm_reload_remote_mmus(struct kvm *kvm);
-void kvm_make_mclock_inprogress_request(struct kvm *kvm);
-void kvm_make_scan_ioapic_request(struct kvm *kvm);
bool kvm_make_all_cpus_request(struct kvm *kvm, unsigned int req);
long kvm_arch_dev_ioctl(struct file *filp,
@@ -979,11 +977,6 @@ static inline bool kvm_is_error_gpa(struct kvm *kvm, gpa_t gpa)
return kvm_is_error_hva(hva);
}
-static inline void kvm_migrate_timers(struct kvm_vcpu *vcpu)
-{
- set_bit(KVM_REQ_MIGRATE_TIMER, &vcpu->requests);
-}
-
enum kvm_stat_kind {
KVM_STAT_VM,
KVM_STAT_VCPU,
@@ -993,7 +986,6 @@ struct kvm_stats_debugfs_item {
const char *name;
int offset;
enum kvm_stat_kind kind;
- struct dentry *dentry;
};
extern struct kvm_stats_debugfs_item debugfs_entries[];
extern struct dentry *kvm_debugfs_dir;
@@ -1080,6 +1072,7 @@ static inline void kvm_irq_routing_update(struct kvm *kvm)
{
}
#endif
+void kvm_arch_irq_routing_update(struct kvm *kvm);
static inline int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
{
@@ -1183,4 +1176,5 @@ void kvm_arch_irq_bypass_start(struct irq_bypass_consumer *);
int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
uint32_t guest_irq, bool set);
#endif /* CONFIG_HAVE_KVM_IRQ_BYPASS */
+
#endif
diff --git a/include/linux/kvm_para.h b/include/linux/kvm_para.h
index 00a97bb..35e568f 100644
--- a/include/linux/kvm_para.h
+++ b/include/linux/kvm_para.h
@@ -4,10 +4,8 @@
#include <uapi/linux/kvm_para.h>
-static inline int kvm_para_has_feature(unsigned int feature)
+static inline bool kvm_para_has_feature(unsigned int feature)
{
- if (kvm_arch_para_features() & (1UL << feature))
- return 1;
- return 0;
+ return !!(kvm_arch_para_features() & (1UL << feature));
}
#endif /* __LINUX_KVM_PARA_H */
diff --git a/include/linux/leds.h b/include/linux/leds.h
index fa359c7..bc1476f 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -44,9 +44,9 @@ struct led_classdev {
#define LED_BLINK_ONESHOT (1 << 17)
#define LED_BLINK_ONESHOT_STOP (1 << 18)
#define LED_BLINK_INVERT (1 << 19)
-#define LED_SYSFS_DISABLE (1 << 20)
-#define SET_BRIGHTNESS_ASYNC (1 << 21)
-#define SET_BRIGHTNESS_SYNC (1 << 22)
+#define LED_BLINK_BRIGHTNESS_CHANGE (1 << 20)
+#define LED_BLINK_DISABLE (1 << 21)
+#define LED_SYSFS_DISABLE (1 << 22)
#define LED_DEV_CAP_FLASH (1 << 23)
/* Set LED brightness level */
@@ -57,8 +57,8 @@ struct led_classdev {
* Set LED brightness level immediately - it can block the caller for
* the time required for accessing a LED device register.
*/
- int (*brightness_set_sync)(struct led_classdev *led_cdev,
- enum led_brightness brightness);
+ int (*brightness_set_blocking)(struct led_classdev *led_cdev,
+ enum led_brightness brightness);
/* Get LED brightness level */
enum led_brightness (*brightness_get)(struct led_classdev *led_cdev);
@@ -156,10 +156,25 @@ extern void led_blink_set_oneshot(struct led_classdev *led_cdev,
*
* Set an LED's brightness, and, if necessary, cancel the
* software blink timer that implements blinking when the
- * hardware doesn't.
+ * hardware doesn't. This function is guaranteed not to sleep.
*/
extern void led_set_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness);
+
+/**
+ * led_set_brightness_sync - set LED brightness synchronously
+ * @led_cdev: the LED to set
+ * @brightness: the brightness to set it to
+ *
+ * Set an LED's brightness immediately. This function will block
+ * the caller for the time required for accessing device registers,
+ * and it can sleep.
+ *
+ * Returns: 0 on success or negative error value on failure
+ */
+extern int led_set_brightness_sync(struct led_classdev *led_cdev,
+ enum led_brightness value);
+
/**
* led_update_brightness - update LED brightness
* @led_cdev: the LED to query
@@ -231,6 +246,8 @@ ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr,
/* Registration functions for complex triggers */
extern int led_trigger_register(struct led_trigger *trigger);
extern void led_trigger_unregister(struct led_trigger *trigger);
+extern int devm_led_trigger_register(struct device *dev,
+ struct led_trigger *trigger);
extern void led_trigger_register_simple(const char *name,
struct led_trigger **trigger);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 83577f8..851821b 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -205,11 +205,13 @@ enum {
ATA_LFLAG_NO_LPM = (1 << 8), /* disable LPM on this link */
ATA_LFLAG_RST_ONCE = (1 << 9), /* limit recovery to one reset */
ATA_LFLAG_CHANGED = (1 << 10), /* LPM state changed on this link */
+ ATA_LFLAG_NO_DB_DELAY = (1 << 11), /* no debounce delay on link resume */
/* struct ata_port flags */
ATA_FLAG_SLAVE_POSS = (1 << 0), /* host supports slave dev */
/* (doesn't imply presence) */
ATA_FLAG_SATA = (1 << 1),
+ ATA_FLAG_NO_LOG_PAGE = (1 << 5), /* do not issue log page read */
ATA_FLAG_NO_ATAPI = (1 << 6), /* No ATAPI support */
ATA_FLAG_PIO_DMA = (1 << 7), /* PIO cmds via DMA */
ATA_FLAG_PIO_LBA48 = (1 << 8), /* Host DMA engine is LBA28 only */
diff --git a/include/linux/lightnvm.h b/include/linux/lightnvm.h
index 5ebd70d..034117b 100644
--- a/include/linux/lightnvm.h
+++ b/include/linux/lightnvm.h
@@ -50,15 +50,21 @@ enum {
NVM_IO_DUAL_ACCESS = 0x1,
NVM_IO_QUAD_ACCESS = 0x2,
+ /* NAND Access Modes */
NVM_IO_SUSPEND = 0x80,
NVM_IO_SLC_MODE = 0x100,
NVM_IO_SCRAMBLE_DISABLE = 0x200,
+
+ /* Block Types */
+ NVM_BLK_T_FREE = 0x0,
+ NVM_BLK_T_BAD = 0x1,
+ NVM_BLK_T_DEV = 0x2,
+ NVM_BLK_T_HOST = 0x4,
};
struct nvm_id_group {
u8 mtype;
u8 fmtype;
- u16 res16;
u8 num_ch;
u8 num_lun;
u8 num_pln;
@@ -74,9 +80,9 @@ struct nvm_id_group {
u32 tbet;
u32 tbem;
u32 mpos;
+ u32 mccap;
u16 cpar;
- u8 res[913];
-} __packed;
+};
struct nvm_addr_format {
u8 ch_offset;
@@ -91,19 +97,15 @@ struct nvm_addr_format {
u8 pg_len;
u8 sect_offset;
u8 sect_len;
- u8 res[4];
};
struct nvm_id {
u8 ver_id;
u8 vmnt;
u8 cgrps;
- u8 res[5];
u32 cap;
u32 dom;
struct nvm_addr_format ppaf;
- u8 ppat;
- u8 resv[224];
struct nvm_id_group groups[4];
} __packed;
@@ -123,39 +125,28 @@ struct nvm_tgt_instance {
#define NVM_VERSION_MINOR 0
#define NVM_VERSION_PATCH 0
-#define NVM_SEC_BITS (8)
-#define NVM_PL_BITS (6)
-#define NVM_PG_BITS (16)
#define NVM_BLK_BITS (16)
-#define NVM_LUN_BITS (10)
+#define NVM_PG_BITS (16)
+#define NVM_SEC_BITS (8)
+#define NVM_PL_BITS (8)
+#define NVM_LUN_BITS (8)
#define NVM_CH_BITS (8)
struct ppa_addr {
+ /* Generic structure for all addresses */
union {
- /* Channel-based PPA format in nand 4x2x2x2x8x10 */
- struct {
- u64 ch : 4;
- u64 sec : 2; /* 4 sectors per page */
- u64 pl : 2; /* 4 planes per LUN */
- u64 lun : 2; /* 4 LUNs per channel */
- u64 pg : 8; /* 256 pages per block */
- u64 blk : 10;/* 1024 blocks per plane */
- u64 resved : 36;
- } chnl;
-
- /* Generic structure for all addresses */
struct {
+ u64 blk : NVM_BLK_BITS;
+ u64 pg : NVM_PG_BITS;
u64 sec : NVM_SEC_BITS;
u64 pl : NVM_PL_BITS;
- u64 pg : NVM_PG_BITS;
- u64 blk : NVM_BLK_BITS;
u64 lun : NVM_LUN_BITS;
u64 ch : NVM_CH_BITS;
} g;
u64 ppa;
};
-} __packed;
+};
struct nvm_rq {
struct nvm_tgt_instance *ins;
@@ -191,18 +182,18 @@ static inline void *nvm_rq_to_pdu(struct nvm_rq *rqdata)
struct nvm_block;
typedef int (nvm_l2p_update_fn)(u64, u32, __le64 *, void *);
-typedef int (nvm_bb_update_fn)(u32, void *, unsigned int, void *);
-typedef int (nvm_id_fn)(struct request_queue *, struct nvm_id *);
-typedef int (nvm_get_l2p_tbl_fn)(struct request_queue *, u64, u32,
+typedef int (nvm_bb_update_fn)(struct ppa_addr, int, u8 *, void *);
+typedef int (nvm_id_fn)(struct nvm_dev *, struct nvm_id *);
+typedef int (nvm_get_l2p_tbl_fn)(struct nvm_dev *, u64, u32,
nvm_l2p_update_fn *, void *);
-typedef int (nvm_op_bb_tbl_fn)(struct request_queue *, int, unsigned int,
+typedef int (nvm_op_bb_tbl_fn)(struct nvm_dev *, struct ppa_addr, int,
nvm_bb_update_fn *, void *);
-typedef int (nvm_op_set_bb_fn)(struct request_queue *, struct nvm_rq *, int);
-typedef int (nvm_submit_io_fn)(struct request_queue *, struct nvm_rq *);
-typedef int (nvm_erase_blk_fn)(struct request_queue *, struct nvm_rq *);
-typedef void *(nvm_create_dma_pool_fn)(struct request_queue *, char *);
+typedef int (nvm_op_set_bb_fn)(struct nvm_dev *, struct nvm_rq *, int);
+typedef int (nvm_submit_io_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef int (nvm_erase_blk_fn)(struct nvm_dev *, struct nvm_rq *);
+typedef void *(nvm_create_dma_pool_fn)(struct nvm_dev *, char *);
typedef void (nvm_destroy_dma_pool_fn)(void *);
-typedef void *(nvm_dev_dma_alloc_fn)(struct request_queue *, void *, gfp_t,
+typedef void *(nvm_dev_dma_alloc_fn)(struct nvm_dev *, void *, gfp_t,
dma_addr_t *);
typedef void (nvm_dev_dma_free_fn)(void *, void*, dma_addr_t);
@@ -210,7 +201,7 @@ struct nvm_dev_ops {
nvm_id_fn *identity;
nvm_get_l2p_tbl_fn *get_l2p_tbl;
nvm_op_bb_tbl_fn *get_bb_tbl;
- nvm_op_set_bb_fn *set_bb;
+ nvm_op_set_bb_fn *set_bb_tbl;
nvm_submit_io_fn *submit_io;
nvm_erase_blk_fn *erase_block;
@@ -220,7 +211,7 @@ struct nvm_dev_ops {
nvm_dev_dma_alloc_fn *dev_dma_alloc;
nvm_dev_dma_free_fn *dev_dma_free;
- uint8_t max_phys_sect;
+ unsigned int max_phys_sect;
};
struct nvm_lun {
@@ -229,7 +220,9 @@ struct nvm_lun {
int lun_id;
int chnl_id;
+ unsigned int nr_inuse_blocks; /* Number of used blocks */
unsigned int nr_free_blocks; /* Number of unused blocks */
+ unsigned int nr_bad_blocks; /* Number of bad blocks */
struct nvm_block *blocks;
spinlock_t lock;
@@ -263,8 +256,7 @@ struct nvm_dev {
int blks_per_lun;
int sec_size;
int oob_size;
- int addr_mode;
- struct nvm_addr_format addr_format;
+ struct nvm_addr_format ppaf;
/* Calculated/Cached values. These do not reflect the actual usable
* blocks at run-time.
@@ -290,118 +282,45 @@ struct nvm_dev {
char name[DISK_NAME_LEN];
};
-/* fallback conversion */
-static struct ppa_addr __generic_to_linear_addr(struct nvm_dev *dev,
- struct ppa_addr r)
+static inline struct ppa_addr generic_to_dev_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
{
struct ppa_addr l;
- l.ppa = r.g.sec +
- r.g.pg * dev->sec_per_pg +
- r.g.blk * (dev->pgs_per_blk *
- dev->sec_per_pg) +
- r.g.lun * (dev->blks_per_lun *
- dev->pgs_per_blk *
- dev->sec_per_pg) +
- r.g.ch * (dev->blks_per_lun *
- dev->pgs_per_blk *
- dev->luns_per_chnl *
- dev->sec_per_pg);
+ l.ppa = ((u64)r.g.blk) << dev->ppaf.blk_offset;
+ l.ppa |= ((u64)r.g.pg) << dev->ppaf.pg_offset;
+ l.ppa |= ((u64)r.g.sec) << dev->ppaf.sect_offset;
+ l.ppa |= ((u64)r.g.pl) << dev->ppaf.pln_offset;
+ l.ppa |= ((u64)r.g.lun) << dev->ppaf.lun_offset;
+ l.ppa |= ((u64)r.g.ch) << dev->ppaf.ch_offset;
return l;
}
-/* fallback conversion */
-static struct ppa_addr __linear_to_generic_addr(struct nvm_dev *dev,
- struct ppa_addr r)
+static inline struct ppa_addr dev_to_generic_addr(struct nvm_dev *dev,
+ struct ppa_addr r)
{
struct ppa_addr l;
- int secs, pgs, blks, luns;
- sector_t ppa = r.ppa;
-
- l.ppa = 0;
-
- div_u64_rem(ppa, dev->sec_per_pg, &secs);
- l.g.sec = secs;
- sector_div(ppa, dev->sec_per_pg);
- div_u64_rem(ppa, dev->sec_per_blk, &pgs);
- l.g.pg = pgs;
-
- sector_div(ppa, dev->pgs_per_blk);
- div_u64_rem(ppa, dev->blks_per_lun, &blks);
- l.g.blk = blks;
-
- sector_div(ppa, dev->blks_per_lun);
- div_u64_rem(ppa, dev->luns_per_chnl, &luns);
- l.g.lun = luns;
-
- sector_div(ppa, dev->luns_per_chnl);
- l.g.ch = ppa;
-
- return l;
-}
-
-static struct ppa_addr __generic_to_chnl_addr(struct ppa_addr r)
-{
- struct ppa_addr l;
-
- l.ppa = 0;
-
- l.chnl.sec = r.g.sec;
- l.chnl.pl = r.g.pl;
- l.chnl.pg = r.g.pg;
- l.chnl.blk = r.g.blk;
- l.chnl.lun = r.g.lun;
- l.chnl.ch = r.g.ch;
-
- return l;
-}
-
-static struct ppa_addr __chnl_to_generic_addr(struct ppa_addr r)
-{
- struct ppa_addr l;
-
- l.ppa = 0;
-
- l.g.sec = r.chnl.sec;
- l.g.pl = r.chnl.pl;
- l.g.pg = r.chnl.pg;
- l.g.blk = r.chnl.blk;
- l.g.lun = r.chnl.lun;
- l.g.ch = r.chnl.ch;
+ /*
+ * (r.ppa << X offset) & X len bitmask. X eq. blk, pg, etc.
+ */
+ l.g.blk = (r.ppa >> dev->ppaf.blk_offset) &
+ (((1 << dev->ppaf.blk_len) - 1));
+ l.g.pg |= (r.ppa >> dev->ppaf.pg_offset) &
+ (((1 << dev->ppaf.pg_len) - 1));
+ l.g.sec |= (r.ppa >> dev->ppaf.sect_offset) &
+ (((1 << dev->ppaf.sect_len) - 1));
+ l.g.pl |= (r.ppa >> dev->ppaf.pln_offset) &
+ (((1 << dev->ppaf.pln_len) - 1));
+ l.g.lun |= (r.ppa >> dev->ppaf.lun_offset) &
+ (((1 << dev->ppaf.lun_len) - 1));
+ l.g.ch |= (r.ppa >> dev->ppaf.ch_offset) &
+ (((1 << dev->ppaf.ch_len) - 1));
return l;
}
-static inline struct ppa_addr addr_to_generic_mode(struct nvm_dev *dev,
- struct ppa_addr gppa)
-{
- switch (dev->addr_mode) {
- case NVM_ADDRMODE_LINEAR:
- return __linear_to_generic_addr(dev, gppa);
- case NVM_ADDRMODE_CHANNEL:
- return __chnl_to_generic_addr(gppa);
- default:
- BUG();
- }
- return gppa;
-}
-
-static inline struct ppa_addr generic_to_addr_mode(struct nvm_dev *dev,
- struct ppa_addr gppa)
-{
- switch (dev->addr_mode) {
- case NVM_ADDRMODE_LINEAR:
- return __generic_to_linear_addr(dev, gppa);
- case NVM_ADDRMODE_CHANNEL:
- return __generic_to_chnl_addr(gppa);
- default:
- BUG();
- }
- return gppa;
-}
-
static inline int ppa_empty(struct ppa_addr ppa_addr)
{
return (ppa_addr.ppa == ADDR_EMPTY);
@@ -426,7 +345,7 @@ static inline struct ppa_addr block_to_ppa(struct nvm_dev *dev,
return ppa;
}
-typedef void (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
+typedef blk_qc_t (nvm_tgt_make_rq_fn)(struct request_queue *, struct bio *);
typedef sector_t (nvm_tgt_capacity_fn)(void *);
typedef int (nvm_tgt_end_io_fn)(struct nvm_rq *, int);
typedef void *(nvm_tgt_init_fn)(struct nvm_dev *, struct gendisk *, int, int);
@@ -468,7 +387,7 @@ typedef int (nvmm_end_io_fn)(struct nvm_rq *, int);
typedef int (nvmm_erase_blk_fn)(struct nvm_dev *, struct nvm_block *,
unsigned long);
typedef struct nvm_lun *(nvmm_get_lun_fn)(struct nvm_dev *, int);
-typedef void (nvmm_free_blocks_print_fn)(struct nvm_dev *);
+typedef void (nvmm_lun_info_print_fn)(struct nvm_dev *);
struct nvmm_type {
const char *name;
@@ -492,7 +411,7 @@ struct nvmm_type {
nvmm_get_lun_fn *get_lun;
/* Statistics */
- nvmm_free_blocks_print_fn *free_blocks_print;
+ nvmm_lun_info_print_fn *lun_info_print;
struct list_head list;
};
diff --git a/include/linux/list.h b/include/linux/list.h
index 993395a..5356f4d 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -24,7 +24,7 @@
static inline void INIT_LIST_HEAD(struct list_head *list)
{
- list->next = list;
+ WRITE_ONCE(list->next, list);
list->prev = list;
}
@@ -42,7 +42,7 @@ static inline void __list_add(struct list_head *new,
next->prev = new;
new->next = next;
new->prev = prev;
- prev->next = new;
+ WRITE_ONCE(prev->next, new);
}
#else
extern void __list_add(struct list_head *new,
@@ -186,7 +186,7 @@ static inline int list_is_last(const struct list_head *list,
*/
static inline int list_empty(const struct list_head *head)
{
- return head->next == head;
+ return READ_ONCE(head->next) == head;
}
/**
@@ -608,7 +608,7 @@ static inline int hlist_unhashed(const struct hlist_node *h)
static inline int hlist_empty(const struct hlist_head *h)
{
- return !h->first;
+ return !READ_ONCE(h->first);
}
static inline void __hlist_del(struct hlist_node *n)
@@ -642,7 +642,7 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
n->next = first;
if (first)
first->pprev = &n->next;
- h->first = n;
+ WRITE_ONCE(h->first, n);
n->pprev = &h->first;
}
@@ -653,14 +653,14 @@ static inline void hlist_add_before(struct hlist_node *n,
n->pprev = next->pprev;
n->next = next;
next->pprev = &n->next;
- *(n->pprev) = n;
+ WRITE_ONCE(*(n->pprev), n);
}
static inline void hlist_add_behind(struct hlist_node *n,
struct hlist_node *prev)
{
n->next = prev->next;
- prev->next = n;
+ WRITE_ONCE(prev->next, n);
n->pprev = &prev->next;
if (n->next)
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index 8132214..ee7229a 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h
@@ -70,7 +70,7 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
static inline int hlist_bl_empty(const struct hlist_bl_head *h)
{
- return !((unsigned long)h->first & ~LIST_BL_LOCKMASK);
+ return !((unsigned long)READ_ONCE(h->first) & ~LIST_BL_LOCKMASK);
}
static inline void hlist_bl_add_head(struct hlist_bl_node *n,
diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h
index 444d2b1..b01fe10 100644
--- a/include/linux/list_nulls.h
+++ b/include/linux/list_nulls.h
@@ -57,7 +57,7 @@ static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h)
static inline int hlist_nulls_empty(const struct hlist_nulls_head *h)
{
- return is_a_nulls(h->first);
+ return is_a_nulls(READ_ONCE(h->first));
}
static inline void hlist_nulls_add_head(struct hlist_nulls_node *n,
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index ff82a32..c153738 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -68,6 +68,7 @@ struct nlm_host {
struct nsm_handle *h_nsmhandle; /* NSM status handle */
char *h_addrbuf; /* address eyecatcher */
struct net *net; /* host net */
+ char nodename[UNX_MAXNODENAME + 1];
};
/*
@@ -235,7 +236,8 @@ void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_shutdown_hosts(void);
void nlm_shutdown_hosts_net(struct net *net);
-void nlm_host_rebooted(const struct nlm_reboot *);
+void nlm_host_rebooted(const struct net *net,
+ const struct nlm_reboot *);
/*
* Host monitoring
@@ -243,11 +245,13 @@ void nlm_host_rebooted(const struct nlm_reboot *);
int nsm_monitor(const struct nlm_host *host);
void nsm_unmonitor(const struct nlm_host *host);
-struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
+struct nsm_handle *nsm_get_handle(const struct net *net,
+ const struct sockaddr *sap,
const size_t salen,
const char *hostname,
const size_t hostname_len);
-struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info);
+struct nsm_handle *nsm_reboot_lookup(const struct net *net,
+ const struct nlm_reboot *info);
void nsm_release(struct nsm_handle *nsm);
/*
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 70400dc..c57e424 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -2,7 +2,7 @@
* Runtime locking correctness validator
*
* Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* see Documentation/locking/lockdep-design.txt for more details.
*/
diff --git a/include/linux/marvell_phy.h b/include/linux/marvell_phy.h
index e6982ac..a57f0df 100644
--- a/include/linux/marvell_phy.h
+++ b/include/linux/marvell_phy.h
@@ -16,6 +16,7 @@
#define MARVELL_PHY_ID_88E1318S 0x01410e90
#define MARVELL_PHY_ID_88E1116R 0x01410e40
#define MARVELL_PHY_ID_88E1510 0x01410dd0
+#define MARVELL_PHY_ID_88E1540 0x01410eb0
#define MARVELL_PHY_ID_88E3016 0x01410e60
/* struct phy_device dev_flags definitions */
diff --git a/include/linux/math64.h b/include/linux/math64.h
index c45c089..6e8b5b2 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -142,6 +142,13 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift)
}
#endif /* mul_u64_u32_shr */
+#ifndef mul_u64_u64_shr
+static inline u64 mul_u64_u64_shr(u64 a, u64 mul, unsigned int shift)
+{
+ return (u64)(((unsigned __int128)a * mul) >> shift);
+}
+#endif /* mul_u64_u64_shr */
+
#else
#ifndef mul_u64_u32_shr
@@ -161,6 +168,79 @@ static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift)
}
#endif /* mul_u64_u32_shr */
+#ifndef mul_u64_u64_shr
+static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift)
+{
+ union {
+ u64 ll;
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 high, low;
+#else
+ u32 low, high;
+#endif
+ } l;
+ } rl, rm, rn, rh, a0, b0;
+ u64 c;
+
+ a0.ll = a;
+ b0.ll = b;
+
+ rl.ll = (u64)a0.l.low * b0.l.low;
+ rm.ll = (u64)a0.l.low * b0.l.high;
+ rn.ll = (u64)a0.l.high * b0.l.low;
+ rh.ll = (u64)a0.l.high * b0.l.high;
+
+ /*
+ * Each of these lines computes a 64-bit intermediate result into "c",
+ * starting at bits 32-95. The low 32-bits go into the result of the
+ * multiplication, the high 32-bits are carried into the next step.
+ */
+ rl.l.high = c = (u64)rl.l.high + rm.l.low + rn.l.low;
+ rh.l.low = c = (c >> 32) + rm.l.high + rn.l.high + rh.l.low;
+ rh.l.high = (c >> 32) + rh.l.high;
+
+ /*
+ * The 128-bit result of the multiplication is in rl.ll and rh.ll,
+ * shift it right and throw away the high part of the result.
+ */
+ if (shift == 0)
+ return rl.ll;
+ if (shift < 64)
+ return (rl.ll >> shift) | (rh.ll << (64 - shift));
+ return rh.ll >> (shift & 63);
+}
+#endif /* mul_u64_u64_shr */
+
#endif
+#ifndef mul_u64_u32_div
+static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor)
+{
+ union {
+ u64 ll;
+ struct {
+#ifdef __BIG_ENDIAN
+ u32 high, low;
+#else
+ u32 low, high;
+#endif
+ } l;
+ } u, rl, rh;
+
+ u.ll = a;
+ rl.ll = (u64)u.l.low * mul;
+ rh.ll = (u64)u.l.high * mul + rl.l.high;
+
+ /* Bits 32-63 of the result will be in rh.l.low. */
+ rl.l.high = do_div(rh.ll, divisor);
+
+ /* Bits 0-31 of the result will be in rl.l.low. */
+ do_div(rl.ll, divisor);
+
+ rl.l.high = rh.l.low;
+ return rl.ll;
+}
+#endif /* mul_u64_u32_div */
+
#endif /* _LINUX_MATH64_H */
diff --git a/include/linux/memblock.h b/include/linux/memblock.h
index 24daf8f..fec66f8 100644
--- a/include/linux/memblock.h
+++ b/include/linux/memblock.h
@@ -25,6 +25,7 @@ enum {
MEMBLOCK_NONE = 0x0, /* No special request */
MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */
MEMBLOCK_MIRROR = 0x2, /* mirrored region */
+ MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */
};
struct memblock_region {
@@ -82,6 +83,7 @@ bool memblock_overlaps_region(struct memblock_type *type,
int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size);
int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size);
int memblock_mark_mirror(phys_addr_t base, phys_addr_t size);
+int memblock_mark_nomap(phys_addr_t base, phys_addr_t size);
ulong choose_memblock_flags(void);
/* Low level functions */
@@ -184,6 +186,11 @@ static inline bool memblock_is_mirror(struct memblock_region *m)
return m->flags & MEMBLOCK_MIRROR;
}
+static inline bool memblock_is_nomap(struct memblock_region *m)
+{
+ return m->flags & MEMBLOCK_NOMAP;
+}
+
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn,
unsigned long *end_pfn);
@@ -319,6 +326,7 @@ phys_addr_t memblock_start_of_DRAM(void);
phys_addr_t memblock_end_of_DRAM(void);
void memblock_enforce_memory_limit(phys_addr_t memory_limit);
int memblock_is_memory(phys_addr_t addr);
+int memblock_is_map_memory(phys_addr_t addr);
int memblock_is_region_memory(phys_addr_t base, phys_addr_t size);
int memblock_is_reserved(phys_addr_t addr);
bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size);
diff --git a/include/linux/mfd/cros_ec.h b/include/linux/mfd/cros_ec.h
index da72671..494682c 100644
--- a/include/linux/mfd/cros_ec.h
+++ b/include/linux/mfd/cros_ec.h
@@ -255,5 +255,6 @@ int cros_ec_query_all(struct cros_ec_device *ec_dev);
/* sysfs stuff */
extern struct attribute_group cros_ec_attr_group;
extern struct attribute_group cros_ec_lightbar_attr_group;
+extern struct attribute_group cros_ec_vbc_attr_group;
#endif /* __LINUX_MFD_CROS_EC_H */
diff --git a/include/linux/mfd/syscon/imx7-iomuxc-gpr.h b/include/linux/mfd/syscon/imx7-iomuxc-gpr.h
new file mode 100644
index 0000000..4585d61
--- /dev/null
+++ b/include/linux/mfd/syscon/imx7-iomuxc-gpr.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_IMX7_IOMUXC_GPR_H
+#define __LINUX_IMX7_IOMUXC_GPR_H
+
+#define IOMUXC_GPR0 0x00
+#define IOMUXC_GPR1 0x04
+#define IOMUXC_GPR2 0x08
+#define IOMUXC_GPR3 0x0c
+#define IOMUXC_GPR4 0x10
+#define IOMUXC_GPR5 0x14
+#define IOMUXC_GPR6 0x18
+#define IOMUXC_GPR7 0x1c
+#define IOMUXC_GPR8 0x20
+#define IOMUXC_GPR9 0x24
+#define IOMUXC_GPR10 0x28
+#define IOMUXC_GPR11 0x2c
+#define IOMUXC_GPR12 0x30
+#define IOMUXC_GPR13 0x34
+#define IOMUXC_GPR14 0x38
+#define IOMUXC_GPR15 0x3c
+#define IOMUXC_GPR16 0x40
+#define IOMUXC_GPR17 0x44
+#define IOMUXC_GPR18 0x48
+#define IOMUXC_GPR19 0x4c
+#define IOMUXC_GPR20 0x50
+#define IOMUXC_GPR21 0x54
+#define IOMUXC_GPR22 0x58
+
+/* For imx7d iomux gpr register field define */
+#define IMX7D_GPR1_IRQ_MASK (0x1 << 12)
+#define IMX7D_GPR1_ENET1_TX_CLK_SEL_MASK (0x1 << 13)
+#define IMX7D_GPR1_ENET2_TX_CLK_SEL_MASK (0x1 << 14)
+#define IMX7D_GPR1_ENET_TX_CLK_SEL_MASK (0x3 << 13)
+#define IMX7D_GPR1_ENET1_CLK_DIR_MASK (0x1 << 17)
+#define IMX7D_GPR1_ENET2_CLK_DIR_MASK (0x1 << 18)
+#define IMX7D_GPR1_ENET_CLK_DIR_MASK (0x3 << 17)
+
+#define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI (0x1 << 4)
+
+#endif /* __LINUX_IMX7_IOMUXC_GPR_H */
diff --git a/include/linux/mfd/wm8350/pmic.h b/include/linux/mfd/wm8350/pmic.h
index 579b50c..7a09e7f 100644
--- a/include/linux/mfd/wm8350/pmic.h
+++ b/include/linux/mfd/wm8350/pmic.h
@@ -715,7 +715,6 @@ struct wm8350_led_platform_data {
struct wm8350_led {
struct platform_device *pdev;
- struct mutex mutex;
struct work_struct work;
spinlock_t value_lock;
enum led_brightness value;
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 7501626..d3133be 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -427,6 +427,17 @@ enum {
};
enum {
+ /*
+ * Max wqe size for rdma read is 512 bytes, so this
+ * limits our max_sge_rd as the wqe needs to fit:
+ * - ctrl segment (16 bytes)
+ * - rdma segment (16 bytes)
+ * - scatter elements (16 bytes each)
+ */
+ MLX4_MAX_SGE_RD = (512 - 16 - 16) / 16
+};
+
+enum {
MLX4_DEV_PMC_SUBTYPE_GUID_INFO = 0x14,
MLX4_DEV_PMC_SUBTYPE_PORT_INFO = 0x15,
MLX4_DEV_PMC_SUBTYPE_PKEY_TABLE = 0x16,
diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h
index dd20974..1565324 100644
--- a/include/linux/mlx5/mlx5_ifc.h
+++ b/include/linux/mlx5/mlx5_ifc.h
@@ -453,26 +453,28 @@ struct mlx5_ifc_per_protocol_networking_offload_caps_bits {
u8 lro_cap[0x1];
u8 lro_psh_flag[0x1];
u8 lro_time_stamp[0x1];
- u8 reserved_0[0x6];
+ u8 reserved_0[0x3];
+ u8 self_lb_en_modifiable[0x1];
+ u8 reserved_1[0x2];
u8 max_lso_cap[0x5];
- u8 reserved_1[0x4];
+ u8 reserved_2[0x4];
u8 rss_ind_tbl_cap[0x4];
- u8 reserved_2[0x3];
+ u8 reserved_3[0x3];
u8 tunnel_lso_const_out_ip_id[0x1];
- u8 reserved_3[0x2];
+ u8 reserved_4[0x2];
u8 tunnel_statless_gre[0x1];
u8 tunnel_stateless_vxlan[0x1];
- u8 reserved_4[0x20];
+ u8 reserved_5[0x20];
- u8 reserved_5[0x10];
+ u8 reserved_6[0x10];
u8 lro_min_mss_size[0x10];
- u8 reserved_6[0x120];
+ u8 reserved_7[0x120];
u8 lro_timer_supported_periods[4][0x20];
- u8 reserved_7[0x600];
+ u8 reserved_8[0x600];
};
struct mlx5_ifc_roce_cap_bits {
@@ -4051,9 +4053,11 @@ struct mlx5_ifc_modify_tis_in_bits {
};
struct mlx5_ifc_modify_tir_bitmask_bits {
- u8 reserved[0x20];
+ u8 reserved_0[0x20];
- u8 reserved1[0x1f];
+ u8 reserved_1[0x1b];
+ u8 self_lb_en[0x1];
+ u8 reserved_2[0x3];
u8 lro[0x1];
};
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index f67b2ec..89df7ab 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -172,7 +172,7 @@ struct dw_mci {
/* For edmac */
struct dw_mci_dma_slave *dms;
/* Registers's physical base address */
- void *phy_regs;
+ resource_size_t phy_regs;
u32 cmd_status;
u32 data_status;
@@ -235,16 +235,10 @@ struct dw_mci_dma_ops {
};
/* IP Quirks/flags. */
-/* DTO fix for command transmission with IDMAC configured */
-#define DW_MCI_QUIRK_IDMAC_DTO BIT(0)
-/* delay needed between retries on some 2.11a implementations */
-#define DW_MCI_QUIRK_RETRY_DELAY BIT(1)
-/* High Speed Capable - Supports HS cards (up to 50MHz) */
-#define DW_MCI_QUIRK_HIGHSPEED BIT(2)
/* Unreliable card detection */
-#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(3)
+#define DW_MCI_QUIRK_BROKEN_CARD_DETECTION BIT(0)
/* Timer for broken data transfer over scheme */
-#define DW_MCI_QUIRK_BROKEN_DTO BIT(4)
+#define DW_MCI_QUIRK_BROKEN_DTO BIT(1)
struct dma_pdata;
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 8673ffe..8dd4d29 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -212,7 +212,9 @@ struct mmc_host {
u32 ocr_avail_sdio; /* SDIO-specific OCR */
u32 ocr_avail_sd; /* SD-specific OCR */
u32 ocr_avail_mmc; /* MMC-specific OCR */
+#ifdef CONFIG_PM_SLEEP
struct notifier_block pm_notify;
+#endif
u32 max_current_330;
u32 max_current_300;
u32 max_current_180;
@@ -259,7 +261,6 @@ struct mmc_host {
#define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
#define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
#define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
-#define MMC_CAP_RUNTIME_RESUME (1 << 20) /* Resume at runtime_resume. */
#define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
#define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
#define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
@@ -289,6 +290,7 @@ struct mmc_host {
#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
#define MMC_CAP2_NO_WRITE_PROTECT (1 << 18) /* No physical write protect pin, assume that card is always read-write */
+#define MMC_CAP2_NO_SDIO (1 << 19) /* Do not send SDIO commands during initialization */
mmc_pm_flag_t pm_caps; /* supported pm features */
@@ -434,8 +436,6 @@ static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
int mmc_regulator_get_supply(struct mmc_host *mmc);
-int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
-
static inline int mmc_card_is_removable(struct mmc_host *host)
{
return !(host->caps & MMC_CAP_NONREMOVABLE);
diff --git a/include/linux/mmdebug.h b/include/linux/mmdebug.h
index 877ef22..772362a 100644
--- a/include/linux/mmdebug.h
+++ b/include/linux/mmdebug.h
@@ -1,6 +1,7 @@
#ifndef LINUX_MM_DEBUG_H
#define LINUX_MM_DEBUG_H 1
+#include <linux/bug.h>
#include <linux/stringify.h>
struct page;
diff --git a/include/linux/msi.h b/include/linux/msi.h
index f71a25e..1c6342a 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -174,6 +174,7 @@ struct msi_controller {
#include <asm/msi.h>
struct irq_domain;
+struct irq_domain_ops;
struct irq_chip;
struct device_node;
struct fwnode_handle;
@@ -279,6 +280,23 @@ struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode,
int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
irq_write_msi_msg_t write_msi_msg);
void platform_msi_domain_free_irqs(struct device *dev);
+
+/* When an MSI domain is used as an intermediate domain */
+int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *args);
+int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
+ int virq, int nvec, msi_alloc_info_t *args);
+struct irq_domain *
+platform_msi_create_device_domain(struct device *dev,
+ unsigned int nvec,
+ irq_write_msi_msg_t write_msi_msg,
+ const struct irq_domain_ops *ops,
+ void *host_data);
+int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs);
+void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nvec);
+void *platform_msi_get_host_data(struct irq_domain *domain);
#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h
index c8723b6..bc742da 100644
--- a/include/linux/mtd/spi-nor.h
+++ b/include/linux/mtd/spi-nor.h
@@ -25,7 +25,7 @@
#define SNOR_MFR_MACRONIX CFI_MFR_MACRONIX
#define SNOR_MFR_SPANSION CFI_MFR_AMD
#define SNOR_MFR_SST CFI_MFR_SST
-#define SNOR_MFR_WINBOND 0xef
+#define SNOR_MFR_WINBOND 0xef /* Also used by some Spansion */
/*
* Note on opcode nomenclature: some opcodes have a format like
diff --git a/include/linux/namei.h b/include/linux/namei.h
index d8c6334..d0f25d8 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -77,6 +77,7 @@ extern struct dentry *kern_path_locked(const char *, struct path *);
extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
+extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int);
extern int follow_down_one(struct path *);
extern int follow_down(struct path *);
diff --git a/include/linux/net.h b/include/linux/net.h
index 70ac5e2..0b4ac7d 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -34,8 +34,12 @@ struct inode;
struct file;
struct net;
-#define SOCK_ASYNC_NOSPACE 0
-#define SOCK_ASYNC_WAITDATA 1
+/* Historically, SOCKWQ_ASYNC_NOSPACE & SOCKWQ_ASYNC_WAITDATA were located
+ * in sock->flags, but moved into sk->sk_wq->flags to be RCU protected.
+ * Eventually all flags will be in sk->sk_wq_flags.
+ */
+#define SOCKWQ_ASYNC_NOSPACE 0
+#define SOCKWQ_ASYNC_WAITDATA 1
#define SOCK_NOSPACE 2
#define SOCK_PASSCRED 3
#define SOCK_PASSSEC 4
@@ -89,6 +93,7 @@ struct socket_wq {
/* Note: wait MUST be first field of socket_wq */
wait_queue_head_t wait;
struct fasync_struct *fasync_list;
+ unsigned long flags; /* %SOCKWQ_ASYNC_NOSPACE, etc */
struct rcu_head rcu;
} ____cacheline_aligned_in_smp;
@@ -96,7 +101,7 @@ struct socket_wq {
* struct socket - general BSD socket
* @state: socket state (%SS_CONNECTED, etc)
* @type: socket type (%SOCK_STREAM, etc)
- * @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
+ * @flags: socket flags (%SOCK_NOSPACE, etc)
* @ops: protocol specific socket operations
* @file: File back pointer for gc
* @sk: internal networking protocol agnostic socket representation
@@ -202,7 +207,7 @@ enum {
SOCK_WAKE_URG,
};
-int sock_wake_async(struct socket *sk, int how, int band);
+int sock_wake_async(struct socket_wq *sk_wq, int how, int band);
int sock_register(const struct net_proto_family *fam);
void sock_unregister(int family);
int __sock_create(struct net *net, int family, int type, int proto,
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index a9e3bf4..3143c84 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1322,6 +1322,7 @@ enum netdev_priv_flags {
#define IFF_L3MDEV_MASTER IFF_L3MDEV_MASTER
#define IFF_NO_QUEUE IFF_NO_QUEUE
#define IFF_OPENVSWITCH IFF_OPENVSWITCH
+#define IFF_L3MDEV_SLAVE IFF_L3MDEV_SLAVE
/**
* struct net_device - The DEVICE structure.
@@ -1397,7 +1398,8 @@ enum netdev_priv_flags {
* @dma: DMA channel
* @mtu: Interface MTU value
* @type: Interface hardware type
- * @hard_header_len: Hardware header length
+ * @hard_header_len: Hardware header length, which means that this is the
+ * minimum size of a packet.
*
* @needed_headroom: Extra headroom the hardware may need, but not in all
* cases can this be guaranteed
@@ -2067,20 +2069,23 @@ struct pcpu_sw_netstats {
struct u64_stats_sync syncp;
};
-#define netdev_alloc_pcpu_stats(type) \
-({ \
- typeof(type) __percpu *pcpu_stats = alloc_percpu(type); \
- if (pcpu_stats) { \
- int __cpu; \
- for_each_possible_cpu(__cpu) { \
- typeof(type) *stat; \
- stat = per_cpu_ptr(pcpu_stats, __cpu); \
- u64_stats_init(&stat->syncp); \
- } \
- } \
- pcpu_stats; \
+#define __netdev_alloc_pcpu_stats(type, gfp) \
+({ \
+ typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\
+ if (pcpu_stats) { \
+ int __cpu; \
+ for_each_possible_cpu(__cpu) { \
+ typeof(type) *stat; \
+ stat = per_cpu_ptr(pcpu_stats, __cpu); \
+ u64_stats_init(&stat->syncp); \
+ } \
+ } \
+ pcpu_stats; \
})
+#define netdev_alloc_pcpu_stats(type) \
+ __netdev_alloc_pcpu_stats(type, GFP_KERNEL)
+
#include <linux/notifier.h>
/* netdevice notifier chain. Please remember to update the rtnetlink
@@ -3853,6 +3858,11 @@ static inline bool netif_is_bridge_master(const struct net_device *dev)
return dev->priv_flags & IFF_EBRIDGE;
}
+static inline bool netif_is_bridge_port(const struct net_device *dev)
+{
+ return dev->priv_flags & IFF_BRIDGE_PORT;
+}
+
static inline bool netif_is_ovs_master(const struct net_device *dev)
{
return dev->priv_flags & IFF_OPENVSWITCH;
diff --git a/include/linux/netfilter/ipset/ip_set.h b/include/linux/netfilter/ipset/ip_set.h
index 48bb01e..0e1f433 100644
--- a/include/linux/netfilter/ipset/ip_set.h
+++ b/include/linux/netfilter/ipset/ip_set.h
@@ -421,7 +421,7 @@ extern void ip_set_free(void *members);
extern int ip_set_get_ipaddr4(struct nlattr *nla, __be32 *ipaddr);
extern int ip_set_get_ipaddr6(struct nlattr *nla, union nf_inet_addr *ipaddr);
extern size_t ip_set_elem_len(struct ip_set *set, struct nlattr *tb[],
- size_t len);
+ size_t len, size_t align);
extern int ip_set_get_extensions(struct ip_set *set, struct nlattr *tb[],
struct ip_set_ext *ext);
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 249d1bb..5646b24 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -14,7 +14,7 @@ struct nfnl_callback {
int (*call_rcu)(struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[]);
- int (*call_batch)(struct sock *nl, struct sk_buff *skb,
+ int (*call_batch)(struct net *net, struct sock *nl, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const cda[]);
const struct nla_policy *policy; /* netlink attribute policy */
diff --git a/include/linux/netfilter_ingress.h b/include/linux/netfilter_ingress.h
index 187feab..5fcd375 100644
--- a/include/linux/netfilter_ingress.h
+++ b/include/linux/netfilter_ingress.h
@@ -5,10 +5,13 @@
#include <linux/netdevice.h>
#ifdef CONFIG_NETFILTER_INGRESS
-static inline int nf_hook_ingress_active(struct sk_buff *skb)
+static inline bool nf_hook_ingress_active(const struct sk_buff *skb)
{
- return nf_hook_list_active(&skb->dev->nf_hooks_ingress,
- NFPROTO_NETDEV, NF_NETDEV_INGRESS);
+#ifdef HAVE_JUMP_LABEL
+ if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS]))
+ return false;
+#endif
+ return !list_empty(&skb->dev->nf_hooks_ingress);
}
static inline int nf_hook_ingress(struct sk_buff *skb)
@@ -16,8 +19,8 @@ static inline int nf_hook_ingress(struct sk_buff *skb)
struct nf_hook_state state;
nf_hook_state_init(&state, &skb->dev->nf_hooks_ingress,
- NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV, NULL,
- skb->dev, NULL, dev_net(skb->dev), NULL);
+ NF_NETDEV_INGRESS, INT_MIN, NFPROTO_NETDEV,
+ skb->dev, NULL, NULL, dev_net(skb->dev), NULL);
return nf_hook_slow(skb, &state);
}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index e7e7853..43aeabd 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -139,10 +139,10 @@ enum nfs_opnum4 {
Needs to be updated if more operations are defined in future.*/
#define FIRST_NFS4_OP OP_ACCESS
-#define LAST_NFS4_OP OP_WRITE_SAME
#define LAST_NFS40_OP OP_RELEASE_LOCKOWNER
#define LAST_NFS41_OP OP_RECLAIM_COMPLETE
-#define LAST_NFS42_OP OP_WRITE_SAME
+#define LAST_NFS42_OP OP_CLONE
+#define LAST_NFS4_OP LAST_NFS42_OP
enum nfsstat4 {
NFS4_OK = 0,
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index c0e9614..37a3d29 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -359,6 +359,7 @@ extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode);
extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping);
+extern int nfs_revalidate_mapping_rcu(struct inode *inode);
extern int nfs_revalidate_mapping_protected(struct inode *inode, struct address_space *mapping);
extern int nfs_setattr(struct dentry *, struct iattr *);
extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *);
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 570d630..11bbae4 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -251,6 +251,7 @@ struct nfs4_layoutget {
struct nfs4_layoutget_res res;
struct rpc_cred *cred;
gfp_t gfp_flags;
+ long timeout;
};
struct nfs4_getdeviceinfo_args {
diff --git a/include/linux/of.h b/include/linux/of.h
index 2194b8c..dd10626 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -126,6 +126,8 @@ extern raw_spinlock_t devtree_lock;
#define OF_POPULATED 3 /* device already created for the node */
#define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */
+#define OF_BAD_ADDR ((u64)-1)
+
#ifdef CONFIG_OF
void of_core_init(void);
@@ -229,8 +231,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size)
#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags)
#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags)
-#define OF_BAD_ADDR ((u64)-1)
-
static inline const char *of_node_full_name(const struct device_node *np)
{
return np ? np->full_name : "<no-node>";
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index d88e81b..507daad 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -57,6 +57,13 @@ extern int of_dma_get_range(struct device_node *np, u64 *dma_addr,
u64 *paddr, u64 *size);
extern bool of_dma_is_coherent(struct device_node *np);
#else /* CONFIG_OF_ADDRESS */
+
+static inline u64 of_translate_address(struct device_node *np,
+ const __be32 *addr)
+{
+ return OF_BAD_ADDR;
+}
+
static inline struct device_node *of_find_matching_node_by_address(
struct device_node *from,
const struct of_device_id *matches,
diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index 36112cd..b90d8ec 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -80,7 +80,7 @@ static inline int of_dma_router_register(struct device_node *np,
static inline struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
const char *name)
{
- return NULL;
+ return ERR_PTR(-ENODEV);
}
static inline struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec,
diff --git a/include/linux/of_irq.h b/include/linux/of_irq.h
index 039f2ee..1e0deb8 100644
--- a/include/linux/of_irq.h
+++ b/include/linux/of_irq.h
@@ -46,12 +46,14 @@ extern int of_irq_get(struct device_node *dev, int index);
extern int of_irq_get_byname(struct device_node *dev, const char *name);
extern int of_irq_to_resource_table(struct device_node *dev,
struct resource *res, int nr_irqs);
+extern struct device_node *of_irq_find_parent(struct device_node *child);
extern struct irq_domain *of_msi_get_domain(struct device *dev,
struct device_node *np,
enum irq_domain_bus_token token);
extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev,
u32 rid);
extern void of_msi_configure(struct device *dev, struct device_node *np);
+u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
#else
static inline int of_irq_count(struct device_node *dev)
{
@@ -70,6 +72,11 @@ static inline int of_irq_to_resource_table(struct device_node *dev,
{
return 0;
}
+static inline void *of_irq_find_parent(struct device_node *child)
+{
+ return NULL;
+}
+
static inline struct irq_domain *of_msi_get_domain(struct device *dev,
struct device_node *np,
enum irq_domain_bus_token token)
@@ -84,6 +91,11 @@ static inline struct irq_domain *of_msi_map_get_device_domain(struct device *dev
static inline void of_msi_configure(struct device *dev, struct device_node *np)
{
}
+static inline u32 of_msi_map_rid(struct device *dev,
+ struct device_node *msi_np, u32 rid_in)
+{
+ return rid_in;
+}
#endif
#if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC)
@@ -93,7 +105,6 @@ static inline void of_msi_configure(struct device *dev, struct device_node *np)
* so declare it here regardless of the CONFIG_OF_IRQ setting.
*/
extern unsigned int irq_of_parse_and_map(struct device_node *node, int index);
-u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in);
#else /* !CONFIG_OF && !CONFIG_SPARC */
static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
@@ -101,12 +112,6 @@ static inline unsigned int irq_of_parse_and_map(struct device_node *dev,
{
return 0;
}
-
-static inline u32 of_msi_map_rid(struct device *dev,
- struct device_node *msi_np, u32 rid_in)
-{
- return rid_in;
-}
#endif /* !CONFIG_OF */
#endif /* __OF_IRQ_H */
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 38c0533..2c51ee7 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -16,7 +16,6 @@ int of_pci_get_devfn(struct device_node *np);
int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin);
int of_pci_parse_bus_range(struct device_node *node, struct resource *res);
int of_get_pci_domain_nr(struct device_node *node);
-void of_pci_dma_configure(struct pci_dev *pci_dev);
void of_pci_check_probe_only(void);
#else
static inline int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq)
@@ -53,8 +52,6 @@ of_get_pci_domain_nr(struct device_node *node)
return -1;
}
-static inline void of_pci_dma_configure(struct pci_dev *pci_dev) { }
-
static inline void of_pci_check_probe_only(void) { }
#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index e828e7b..d86378c 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -412,9 +412,18 @@ struct pci_host_bridge {
void (*release_fn)(struct pci_host_bridge *);
void *release_data;
unsigned int ignore_reset_delay:1; /* for entire hierarchy */
+ /* Resource alignment requirements */
+ resource_size_t (*align_resource)(struct pci_dev *dev,
+ const struct resource *res,
+ resource_size_t start,
+ resource_size_t size,
+ resource_size_t align);
};
#define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev)
+
+struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus);
+
void pci_set_host_bridge_release(struct pci_host_bridge *bridge,
void (*release_fn)(struct pci_host_bridge *),
void *release_data);
@@ -1937,6 +1946,16 @@ static inline struct irq_domain *
pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; }
#endif /* CONFIG_OF */
+#ifdef CONFIG_ACPI
+struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus);
+
+void
+pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *));
+#else
+static inline struct irq_domain *
+pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; }
+#endif
+
#ifdef CONFIG_EEH
static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev)
{
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index 12c9b48..84f542d 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -116,7 +116,7 @@ void percpu_ref_reinit(struct percpu_ref *ref);
*/
static inline void percpu_ref_kill(struct percpu_ref *ref)
{
- return percpu_ref_kill_and_confirm(ref, NULL);
+ percpu_ref_kill_and_confirm(ref, NULL);
}
/*
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index caebf2a..4bc6daf 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -18,12 +18,6 @@
#define PERCPU_MODULE_RESERVE 0
#endif
-#ifndef PERCPU_ENOUGH_ROOM
-#define PERCPU_ENOUGH_ROOM \
- (ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES) + \
- PERCPU_MODULE_RESERVE)
-#endif
-
/* minimum unit size, also is the maximum supported allocation size */
#define PCPU_MIN_UNIT_SIZE PFN_ALIGN(32 << 10)
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
index bfa673b..83b5e34 100644
--- a/include/linux/perf/arm_pmu.h
+++ b/include/linux/perf/arm_pmu.h
@@ -111,8 +111,6 @@ struct arm_pmu {
#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
-int armpmu_register(struct arm_pmu *armpmu, int type);
-
u64 armpmu_event_update(struct perf_event *event);
int armpmu_event_set_period(struct perf_event *event);
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index d841d33..f9828a4 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -697,9 +697,11 @@ struct perf_cgroup {
* if there is no cgroup event for the current CPU context.
*/
static inline struct perf_cgroup *
-perf_cgroup_from_task(struct task_struct *task)
+perf_cgroup_from_task(struct task_struct *task, struct perf_event_context *ctx)
{
- return container_of(task_css(task, perf_event_cgrp_id),
+ return container_of(task_css_check(task, perf_event_cgrp_id,
+ ctx ? lockdep_is_held(&ctx->lock)
+ : true),
struct perf_cgroup, css);
}
#endif /* CONFIG_CGROUP_PERF */
diff --git a/include/linux/platform_data/atmel.h b/include/linux/platform_data/atmel.h
index 91b16ad..3c8825b 100644
--- a/include/linux/platform_data/atmel.h
+++ b/include/linux/platform_data/atmel.h
@@ -9,15 +9,7 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
-#include <linux/device.h>
-#include <linux/i2c.h>
-#include <linux/leds.h>
-#include <linux/spi/spi.h>
-#include <linux/usb/atmel_usba_udc.h>
-#include <linux/atmel-mci.h>
-#include <sound/atmel-ac97c.h>
#include <linux/serial.h>
-#include <linux/platform_data/macb.h>
/* Compact Flash */
struct at91_cf_data {
diff --git a/include/linux/platform_data/camera-rcar.h b/include/linux/platform_data/camera-rcar.h
deleted file mode 100644
index dfc83c5..0000000
--- a/include/linux/platform_data/camera-rcar.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Platform data for Renesas R-Car VIN soc-camera driver
- *
- * Copyright (C) 2011-2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Cogent Embedded, Inc., <source@cogentembedded.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef __CAMERA_RCAR_H_
-#define __CAMERA_RCAR_H_
-
-#define RCAR_VIN_HSYNC_ACTIVE_LOW (1 << 0)
-#define RCAR_VIN_VSYNC_ACTIVE_LOW (1 << 1)
-#define RCAR_VIN_BT601 (1 << 2)
-#define RCAR_VIN_BT656 (1 << 3)
-
-struct rcar_vin_platform_data {
- unsigned int flags;
-};
-
-#endif /* __CAMERA_RCAR_H_ */
diff --git a/include/linux/platform_data/edma.h b/include/linux/platform_data/edma.h
index e2878ba..4299f4b 100644
--- a/include/linux/platform_data/edma.h
+++ b/include/linux/platform_data/edma.h
@@ -72,7 +72,7 @@ struct edma_soc_info {
struct edma_rsv_info *rsv;
/* List of channels allocated for memcpy, terminated with -1 */
- s16 *memcpy_channels;
+ s32 *memcpy_channels;
s8 (*queue_priority_mapping)[2];
const s16 (*xbar_chans)[2];
diff --git a/include/linux/platform_data/irq-renesas-intc-irqpin.h b/include/linux/platform_data/irq-renesas-intc-irqpin.h
deleted file mode 100644
index e4cb911..0000000
--- a/include/linux/platform_data/irq-renesas-intc-irqpin.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Renesas INTC External IRQ Pin Driver
- *
- * Copyright (C) 2013 Magnus Damm
- *
- * 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
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __IRQ_RENESAS_INTC_IRQPIN_H__
-#define __IRQ_RENESAS_INTC_IRQPIN_H__
-
-struct renesas_intc_irqpin_config {
- unsigned int sense_bitfield_width;
- unsigned int irq_base;
- bool control_parent;
-};
-
-#endif /* __IRQ_RENESAS_INTC_IRQPIN_H__ */
diff --git a/include/linux/platform_data/camera-mx2.h b/include/linux/platform_data/media/camera-mx2.h
index 7ded6f1..7ded6f1 100644
--- a/include/linux/platform_data/camera-mx2.h
+++ b/include/linux/platform_data/media/camera-mx2.h
diff --git a/include/linux/platform_data/camera-mx3.h b/include/linux/platform_data/media/camera-mx3.h
index a910dad..a910dad 100644
--- a/include/linux/platform_data/camera-mx3.h
+++ b/include/linux/platform_data/media/camera-mx3.h
diff --git a/include/linux/platform_data/camera-pxa.h b/include/linux/platform_data/media/camera-pxa.h
index 6709b1c..6709b1c 100644
--- a/include/linux/platform_data/camera-pxa.h
+++ b/include/linux/platform_data/media/camera-pxa.h
diff --git a/include/linux/platform_data/coda.h b/include/linux/platform_data/media/coda.h
index 6ad4410..6ad4410 100644
--- a/include/linux/platform_data/coda.h
+++ b/include/linux/platform_data/media/coda.h
diff --git a/include/media/gpio-ir-recv.h b/include/linux/platform_data/media/gpio-ir-recv.h
index 0142736..0c298f5 100644
--- a/include/media/gpio-ir-recv.h
+++ b/include/linux/platform_data/media/gpio-ir-recv.h
@@ -21,4 +21,3 @@ struct gpio_ir_recv_platform_data {
};
#endif /* __GPIO_IR_RECV_H__ */
-
diff --git a/include/media/ir-rx51.h b/include/linux/platform_data/media/ir-rx51.h
index 104aa89..104aa89 100644
--- a/include/media/ir-rx51.h
+++ b/include/linux/platform_data/media/ir-rx51.h
diff --git a/include/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h
index 7611963..7611963 100644
--- a/include/media/mmp-camera.h
+++ b/include/linux/platform_data/media/mmp-camera.h
diff --git a/include/media/omap1_camera.h b/include/linux/platform_data/media/omap1_camera.h
index 819767c..819767c 100644
--- a/include/media/omap1_camera.h
+++ b/include/linux/platform_data/media/omap1_camera.h
diff --git a/include/media/omap4iss.h b/include/linux/platform_data/media/omap4iss.h
index 0d7620d..0d7620d 100644
--- a/include/media/omap4iss.h
+++ b/include/linux/platform_data/media/omap4iss.h
diff --git a/include/media/s5p_hdmi.h b/include/linux/platform_data/media/s5p_hdmi.h
index 181642b..bb9cacb 100644
--- a/include/media/s5p_hdmi.h
+++ b/include/linux/platform_data/media/s5p_hdmi.h
@@ -34,4 +34,3 @@ struct s5p_hdmi_platform_data {
};
#endif /* S5P_HDMI_H */
-
diff --git a/include/media/si4713.h b/include/linux/platform_data/media/si4713.h
index be4f58e..932668a 100644
--- a/include/media/si4713.h
+++ b/include/linux/platform_data/media/si4713.h
@@ -1,5 +1,5 @@
/*
- * include/media/si4713.h
+ * include/linux/platform_data/media/si4713.h
*
* Board related data definitions for Si4713 i2c device driver.
*
diff --git a/include/media/sii9234.h b/include/linux/platform_data/media/sii9234.h
index 6a4a809..6a4a809 100644
--- a/include/media/sii9234.h
+++ b/include/linux/platform_data/media/sii9234.h
diff --git a/include/media/soc_camera_platform.h b/include/linux/platform_data/media/soc_camera_platform.h
index 1e5065da..1e5065da 100644
--- a/include/media/soc_camera_platform.h
+++ b/include/linux/platform_data/media/soc_camera_platform.h
diff --git a/include/media/timb_radio.h b/include/linux/platform_data/media/timb_radio.h
index a40a6a3..a40a6a3 100644
--- a/include/media/timb_radio.h
+++ b/include/linux/platform_data/media/timb_radio.h
diff --git a/include/media/timb_video.h b/include/linux/platform_data/media/timb_video.h
index 70ae439..70ae439 100644
--- a/include/media/timb_video.h
+++ b/include/linux/platform_data/media/timb_video.h
diff --git a/include/linux/platform_data/mmc-mvsdio.h b/include/linux/platform_data/mmc-mvsdio.h
deleted file mode 100644
index d02704cd..0000000
--- a/include/linux/platform_data/mmc-mvsdio.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __MMC_MVSDIO_H
-#define __MMC_MVSDIO_H
-
-#include <linux/mbus.h>
-
-struct mvsdio_platform_data {
- unsigned int clock;
- int gpio_card_detect;
- int gpio_write_protect;
-};
-
-#endif
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index dc777be..6abd019 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -51,6 +51,7 @@ extern void arch_setup_pdev_archdata(struct platform_device *);
extern struct resource *platform_get_resource(struct platform_device *,
unsigned int, unsigned int);
extern int platform_get_irq(struct platform_device *, unsigned int);
+extern int platform_irq_count(struct platform_device *);
extern struct resource *platform_get_resource_byname(struct platform_device *,
unsigned int,
const char *);
diff --git a/include/linux/pmem.h b/include/linux/pmem.h
index 85f810b3..acfea8c 100644
--- a/include/linux/pmem.h
+++ b/include/linux/pmem.h
@@ -65,11 +65,6 @@ static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t si
memcpy(dst, (void __force const *) src, size);
}
-static inline void memunmap_pmem(struct device *dev, void __pmem *addr)
-{
- devm_memunmap(dev, (void __force *) addr);
-}
-
static inline bool arch_has_pmem_api(void)
{
return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API);
@@ -93,7 +88,7 @@ static inline bool arch_has_wmb_pmem(void)
* These defaults seek to offer decent performance and minimize the
* window between i/o completion and writes being durable on media.
* However, it is undefined / architecture specific whether
- * default_memremap_pmem + default_memcpy_to_pmem is sufficient for
+ * ARCH_MEMREMAP_PMEM + default_memcpy_to_pmem is sufficient for
* making data durable relative to i/o completion.
*/
static inline void default_memcpy_to_pmem(void __pmem *dst, const void *src,
@@ -117,25 +112,6 @@ static inline void default_clear_pmem(void __pmem *addr, size_t size)
}
/**
- * memremap_pmem - map physical persistent memory for pmem api
- * @offset: physical address of persistent memory
- * @size: size of the mapping
- *
- * Establish a mapping of the architecture specific memory type expected
- * by memcpy_to_pmem() and wmb_pmem(). For example, it may be
- * the case that an uncacheable or writethrough mapping is sufficient,
- * or a writeback mapping provided memcpy_to_pmem() and
- * wmb_pmem() arrange for the data to be written through the
- * cache to persistent media.
- */
-static inline void __pmem *memremap_pmem(struct device *dev,
- resource_size_t offset, unsigned long size)
-{
- return (void __pmem *) devm_memremap(dev, offset, size,
- ARCH_MEMREMAP_PMEM);
-}
-
-/**
* memcpy_to_pmem - copy data to persistent memory
* @dst: destination buffer for the copy
* @src: source buffer for the copy
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h
index 6f14ee2..e5e8ec4 100644
--- a/include/linux/posix_acl_xattr.h
+++ b/include/linux/posix_acl_xattr.h
@@ -9,16 +9,12 @@
#ifndef _POSIX_ACL_XATTR_H
#define _POSIX_ACL_XATTR_H
+#include <uapi/linux/xattr.h>
#include <linux/posix_acl.h>
-/* Extended attribute names */
-#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
-#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
-
/* Supported ACL a_version fields */
#define POSIX_ACL_XATTR_VERSION 0x0002
-
/* An undefined entry e_id value */
#define ACL_UNDEFINED_ID (-1)
diff --git a/include/linux/property.h b/include/linux/property.h
index 463de52..0a3705a 100644
--- a/include/linux/property.h
+++ b/include/linux/property.h
@@ -27,6 +27,12 @@ enum dev_prop_type {
DEV_PROP_MAX,
};
+enum dev_dma_attr {
+ DEV_DMA_NOT_SUPPORTED,
+ DEV_DMA_NON_COHERENT,
+ DEV_DMA_COHERENT,
+};
+
bool device_property_present(struct device *dev, const char *propname);
int device_property_read_u8_array(struct device *dev, const char *propname,
u8 *val, size_t nval);
@@ -168,7 +174,9 @@ struct property_set {
void device_add_property_set(struct device *dev, struct property_set *pset);
-bool device_dma_is_coherent(struct device *dev);
+bool device_dma_supported(struct device *dev);
+
+enum dev_dma_attr device_get_dma_attr(struct device *dev);
int device_get_phy_mode(struct device *dev);
diff --git a/include/linux/proportions.h b/include/linux/proportions.h
index 5440f64..2122133 100644
--- a/include/linux/proportions.h
+++ b/include/linux/proportions.h
@@ -1,7 +1,7 @@
/*
* FLoating proportions
*
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* This file contains the public data structure and API definitions.
*/
diff --git a/include/linux/psci.h b/include/linux/psci.h
index a682fcc..12c4865 100644
--- a/include/linux/psci.h
+++ b/include/linux/psci.h
@@ -21,6 +21,8 @@
#define PSCI_POWER_STATE_TYPE_POWER_DOWN 1
bool psci_tos_resident_on(int cpu);
+bool psci_power_state_loses_context(u32 state);
+bool psci_power_state_is_valid(u32 state);
struct psci_operations {
int (*cpu_suspend)(u32 state, unsigned long entry_point);
diff --git a/include/linux/pwm.h b/include/linux/pwm.h
index d681f68..cfc3ed4 100644
--- a/include/linux/pwm.h
+++ b/include/linux/pwm.h
@@ -2,6 +2,7 @@
#define __LINUX_PWM_H
#include <linux/err.h>
+#include <linux/mutex.h>
#include <linux/of.h>
struct pwm_device;
@@ -87,6 +88,7 @@ enum {
* @pwm: global index of the PWM device
* @chip: PWM chip providing this PWM device
* @chip_data: chip-private data associated with the PWM device
+ * @lock: used to serialize accesses to the PWM device where necessary
* @period: period of the PWM signal (in nanoseconds)
* @duty_cycle: duty cycle of the PWM signal (in nanoseconds)
* @polarity: polarity of the PWM signal
@@ -98,6 +100,7 @@ struct pwm_device {
unsigned int pwm;
struct pwm_chip *chip;
void *chip_data;
+ struct mutex lock;
unsigned int period;
unsigned int duty_cycle;
diff --git a/include/linux/qcom_scm.h b/include/linux/qcom_scm.h
index 6e7d5ec..9e12000 100644
--- a/include/linux/qcom_scm.h
+++ b/include/linux/qcom_scm.h
@@ -23,6 +23,8 @@ struct qcom_scm_hdcp_req {
u32 val;
};
+extern bool qcom_scm_is_available(void);
+
extern bool qcom_scm_hdcp_available(void);
extern int qcom_scm_hdcp_req(struct qcom_scm_hdcp_req *req, u32 req_cnt,
u32 *resp);
diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h
index 6a43476..1d1ba2c 100644
--- a/include/linux/qed/common_hsi.h
+++ b/include/linux/qed/common_hsi.h
@@ -9,6 +9,8 @@
#ifndef __COMMON_HSI__
#define __COMMON_HSI__
+#define CORE_SPQE_PAGE_SIZE_BYTES 4096
+
#define FW_MAJOR_VERSION 8
#define FW_MINOR_VERSION 4
#define FW_REVISION_VERSION 2
diff --git a/include/linux/qed/qed_chain.h b/include/linux/qed/qed_chain.h
index b920c36..41b9049 100644
--- a/include/linux/qed/qed_chain.h
+++ b/include/linux/qed/qed_chain.h
@@ -111,7 +111,8 @@ static inline u16 qed_chain_get_elem_left(struct qed_chain *p_chain)
used = ((u32)0x10000u + (u32)(p_chain->prod_idx)) -
(u32)p_chain->cons_idx;
if (p_chain->mode == QED_CHAIN_MODE_NEXT_PTR)
- used -= (used / p_chain->elem_per_page);
+ used -= p_chain->prod_idx / p_chain->elem_per_page -
+ p_chain->cons_idx / p_chain->elem_per_page;
return p_chain->capacity - used;
}
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 5ed5409..14ec165 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -179,32 +179,31 @@ static inline void list_replace_rcu(struct list_head *old,
}
/**
- * list_splice_init_rcu - splice an RCU-protected list into an existing list.
+ * __list_splice_init_rcu - join an RCU-protected list into an existing list.
* @list: the RCU-protected list to splice
- * @head: the place in the list to splice the first list into
+ * @prev: points to the last element of the existing list
+ * @next: points to the first element of the existing list
* @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
*
- * @head can be RCU-read traversed concurrently with this function.
+ * The list pointed to by @prev and @next can be RCU-read traversed
+ * concurrently with this function.
*
* Note that this function blocks.
*
- * Important note: the caller must take whatever action is necessary to
- * prevent any other updates to @head. In principle, it is possible
- * to modify the list as soon as sync() begins execution.
- * If this sort of thing becomes necessary, an alternative version
- * based on call_rcu() could be created. But only if -really-
- * needed -- there is no shortage of RCU API members.
+ * Important note: the caller must take whatever action is necessary to prevent
+ * any other updates to the existing list. In principle, it is possible to
+ * modify the list as soon as sync() begins execution. If this sort of thing
+ * becomes necessary, an alternative version based on call_rcu() could be
+ * created. But only if -really- needed -- there is no shortage of RCU API
+ * members.
*/
-static inline void list_splice_init_rcu(struct list_head *list,
- struct list_head *head,
- void (*sync)(void))
+static inline void __list_splice_init_rcu(struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next,
+ void (*sync)(void))
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- if (list_empty(list))
- return;
/*
* "first" and "last" tracking list, so initialize it. RCU readers
@@ -231,10 +230,40 @@ static inline void list_splice_init_rcu(struct list_head *list,
* this function.
*/
- last->next = at;
- rcu_assign_pointer(list_next_rcu(head), first);
- first->prev = head;
- at->prev = last;
+ last->next = next;
+ rcu_assign_pointer(list_next_rcu(prev), first);
+ first->prev = prev;
+ next->prev = last;
+}
+
+/**
+ * list_splice_init_rcu - splice an RCU-protected list into an existing list,
+ * designed for stacks.
+ * @list: the RCU-protected list to splice
+ * @head: the place in the existing list to splice the first list into
+ * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_init_rcu(struct list_head *list,
+ struct list_head *head,
+ void (*sync)(void))
+{
+ if (!list_empty(list))
+ __list_splice_init_rcu(list, head, head->next, sync);
+}
+
+/**
+ * list_splice_tail_init_rcu - splice an RCU-protected list into an existing
+ * list, designed for queues.
+ * @list: the RCU-protected list to splice
+ * @head: the place in the existing list to splice the first list into
+ * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
+ */
+static inline void list_splice_tail_init_rcu(struct list_head *list,
+ struct list_head *head,
+ void (*sync)(void))
+{
+ if (!list_empty(list))
+ __list_splice_init_rcu(list, head->prev, head, sync);
}
/**
@@ -305,6 +334,42 @@ static inline void list_splice_init_rcu(struct list_head *list,
pos = list_entry_rcu(pos->member.next, typeof(*pos), member))
/**
+ * list_entry_lockless - 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_head within the struct.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu(), but requires some implicit RCU
+ * read-side guarding. One example is running within a special
+ * exception-time environment where preemption is disabled and where
+ * lockdep cannot be invoked (in which case updaters must use RCU-sched,
+ * as in synchronize_sched(), call_rcu_sched(), and friends). Another
+ * example is when items are added to the list, but never deleted.
+ */
+#define list_entry_lockless(ptr, type, member) \
+ container_of((typeof(ptr))lockless_dereference(ptr), type, member)
+
+/**
+ * list_for_each_entry_lockless - iterate over rcu 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.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu(), but requires some implicit RCU
+ * read-side guarding. One example is running within a special
+ * exception-time environment where preemption is disabled and where
+ * lockdep cannot be invoked (in which case updaters must use RCU-sched,
+ * as in synchronize_sched(), call_rcu_sched(), and friends). Another
+ * example is when items are added to the list, but never deleted.
+ */
+#define list_for_each_entry_lockless(pos, head, member) \
+ for (pos = list_entry_lockless((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = list_entry_lockless(pos->member.next, typeof(*pos), member))
+
+/**
* list_for_each_entry_continue_rcu - continue iteration over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index a0189ba..14e6f47 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -48,10 +48,17 @@
#include <asm/barrier.h>
+#ifndef CONFIG_TINY_RCU
extern int rcu_expedited; /* for sysctl */
+extern int rcu_normal; /* also for sysctl */
+#endif /* #ifndef CONFIG_TINY_RCU */
#ifdef CONFIG_TINY_RCU
/* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */
+static inline bool rcu_gp_is_normal(void) /* Internal RCU use. */
+{
+ return true;
+}
static inline bool rcu_gp_is_expedited(void) /* Internal RCU use. */
{
return false;
@@ -65,6 +72,7 @@ static inline void rcu_unexpedite_gp(void)
{
}
#else /* #ifdef CONFIG_TINY_RCU */
+bool rcu_gp_is_normal(void); /* Internal RCU use. */
bool rcu_gp_is_expedited(void); /* Internal RCU use. */
void rcu_expedite_gp(void);
void rcu_unexpedite_gp(void);
@@ -321,7 +329,6 @@ static inline int rcu_preempt_depth(void)
/* Internal to kernel */
void rcu_init(void);
-void rcu_end_inkernel_boot(void);
void rcu_sched_qs(void);
void rcu_bh_qs(void);
void rcu_check_callbacks(int user);
@@ -329,6 +336,12 @@ struct notifier_block;
int rcu_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu);
+#ifndef CONFIG_TINY_RCU
+void rcu_end_inkernel_boot(void);
+#else /* #ifndef CONFIG_TINY_RCU */
+static inline void rcu_end_inkernel_boot(void) { }
+#endif /* #ifndef CONFIG_TINY_RCU */
+
#ifdef CONFIG_RCU_STALL_COMMON
void rcu_sysrq_start(void);
void rcu_sysrq_end(void);
@@ -379,9 +392,9 @@ static inline void rcu_init_nohz(void)
*/
#define RCU_NONIDLE(a) \
do { \
- rcu_irq_enter(); \
+ rcu_irq_enter_irqson(); \
do { a; } while (0); \
- rcu_irq_exit(); \
+ rcu_irq_exit_irqson(); \
} while (0)
/*
@@ -741,7 +754,7 @@ static inline void rcu_preempt_sleep_check(void)
* The tracing infrastructure traces RCU (we want that), but unfortunately
* some of the RCU checks causes tracing to lock up the system.
*
- * The tracing version of rcu_dereference_raw() must not call
+ * The no-tracing version of rcu_dereference_raw() must not call
* rcu_read_lock_held().
*/
#define rcu_dereference_raw_notrace(p) __rcu_dereference_check((p), 1, __rcu)
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 4c1aaf9..64809ae 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -181,6 +181,14 @@ static inline void rcu_irq_enter(void)
{
}
+static inline void rcu_irq_exit_irqson(void)
+{
+}
+
+static inline void rcu_irq_enter_irqson(void)
+{
+}
+
static inline void rcu_irq_exit(void)
{
}
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 60d15a0..ad1eda9 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -37,7 +37,7 @@ void rcu_cpu_stall_reset(void);
/*
* Note a virtualization-based context switch. This is simply a
* wrapper around rcu_note_context_switch(), which allows TINY_RCU
- * to save a few bytes.
+ * to save a few bytes. The caller must have disabled interrupts.
*/
static inline void rcu_virt_note_context_switch(int cpu)
{
@@ -97,6 +97,8 @@ void rcu_idle_enter(void);
void rcu_idle_exit(void);
void rcu_irq_enter(void);
void rcu_irq_exit(void);
+void rcu_irq_enter_irqson(void);
+void rcu_irq_exit_irqson(void);
void exit_rcu(void);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index d68bb40..1839434 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -788,10 +788,16 @@ int regmap_fields_update_bits(struct regmap_field *field, unsigned int id,
*
* @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register.
+ * @type_reg_offset: Offset register for the irq type setting.
+ * @type_rising_mask: Mask bit to configure RISING type irq.
+ * @type_falling_mask: Mask bit to configure FALLING type irq.
*/
struct regmap_irq {
unsigned int reg_offset;
unsigned int mask;
+ unsigned int type_reg_offset;
+ unsigned int type_rising_mask;
+ unsigned int type_falling_mask;
};
#define REGMAP_IRQ_REG(_irq, _off, _mask) \
@@ -811,18 +817,23 @@ struct regmap_irq {
* @ack_base: Base ack address. If zero then the chip is clear on read.
* Using zero value is possible with @use_ack bit.
* @wake_base: Base address for wake enables. If zero unsupported.
+ * @type_base: Base address for irq type. If zero unsupported.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
* @init_ack_masked: Ack all masked interrupts once during initalization.
* @mask_invert: Inverted mask register: cleared bits are masked out.
* @use_ack: Use @ack register even if it is zero.
* @ack_invert: Inverted ack register: cleared bits for ack.
* @wake_invert: Inverted wake register: cleared bits are wake enabled.
+ * @type_invert: Invert the type flags.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
* assigned based on the index in the array of the interrupt.
* @num_irqs: Number of descriptors.
+ * @num_type_reg: Number of type registers.
+ * @type_reg_stride: Stride to use for chips where type registers are not
+ * contiguous.
*/
struct regmap_irq_chip {
const char *name;
@@ -832,6 +843,7 @@ struct regmap_irq_chip {
unsigned int unmask_base;
unsigned int ack_base;
unsigned int wake_base;
+ unsigned int type_base;
unsigned int irq_reg_stride;
bool init_ack_masked:1;
bool mask_invert:1;
@@ -839,11 +851,15 @@ struct regmap_irq_chip {
bool ack_invert:1;
bool wake_invert:1;
bool runtime_pm:1;
+ bool type_invert:1;
int num_regs;
const struct regmap_irq *irqs;
int num_irqs;
+
+ int num_type_reg;
+ unsigned int type_reg_stride;
};
struct regmap_irq_chip_data;
@@ -1021,7 +1037,7 @@ static inline void regmap_async_complete(struct regmap *map)
}
static inline int regmap_register_patch(struct regmap *map,
- const struct reg_default *regs,
+ const struct reg_sequence *regs,
int num_regs)
{
WARN_ONCE(1, "regmap API is disabled");
diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h
index 843ceca..e50b31d 100644
--- a/include/linux/rhashtable.h
+++ b/include/linux/rhashtable.h
@@ -19,6 +19,7 @@
#include <linux/atomic.h>
#include <linux/compiler.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/jhash.h>
#include <linux/list_nulls.h>
@@ -339,10 +340,11 @@ static inline int lockdep_rht_bucket_is_held(const struct bucket_table *tbl,
int rhashtable_init(struct rhashtable *ht,
const struct rhashtable_params *params);
-int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
- struct rhash_head *obj,
- struct bucket_table *old_tbl);
-int rhashtable_insert_rehash(struct rhashtable *ht);
+struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
+ const void *key,
+ struct rhash_head *obj,
+ struct bucket_table *old_tbl);
+int rhashtable_insert_rehash(struct rhashtable *ht, struct bucket_table *tbl);
int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter);
void rhashtable_walk_exit(struct rhashtable_iter *iter);
@@ -598,9 +600,11 @@ restart:
new_tbl = rht_dereference_rcu(tbl->future_tbl, ht);
if (unlikely(new_tbl)) {
- err = rhashtable_insert_slow(ht, key, obj, new_tbl);
- if (err == -EAGAIN)
+ tbl = rhashtable_insert_slow(ht, key, obj, new_tbl);
+ if (!IS_ERR_OR_NULL(tbl))
goto slow_path;
+
+ err = PTR_ERR(tbl);
goto out;
}
@@ -611,7 +615,7 @@ restart:
if (unlikely(rht_grow_above_100(ht, tbl))) {
slow_path:
spin_unlock_bh(lock);
- err = rhashtable_insert_rehash(ht);
+ err = rhashtable_insert_rehash(ht, tbl);
rcu_read_unlock();
if (err)
return err;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 4069feb..4bae8ab 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -177,9 +177,9 @@ extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load);
extern void calc_global_load(unsigned long ticks);
#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON)
-extern void update_cpu_load_nohz(void);
+extern void update_cpu_load_nohz(int active);
#else
-static inline void update_cpu_load_nohz(void) { }
+static inline void update_cpu_load_nohz(int active) { }
#endif
extern unsigned long get_parent_ip(unsigned long addr);
@@ -377,6 +377,7 @@ extern void scheduler_tick(void);
extern void sched_show_task(struct task_struct *p);
#ifdef CONFIG_LOCKUP_DETECTOR
+extern void touch_softlockup_watchdog_sched(void);
extern void touch_softlockup_watchdog(void);
extern void touch_softlockup_watchdog_sync(void);
extern void touch_all_softlockup_watchdogs(void);
@@ -387,6 +388,9 @@ extern unsigned int softlockup_panic;
extern unsigned int hardlockup_panic;
void lockup_detector_init(void);
#else
+static inline void touch_softlockup_watchdog_sched(void)
+{
+}
static inline void touch_softlockup_watchdog(void)
{
}
@@ -484,9 +488,11 @@ static inline int get_dumpable(struct mm_struct *mm)
#define MMF_DUMP_ELF_HEADERS 6
#define MMF_DUMP_HUGETLB_PRIVATE 7
#define MMF_DUMP_HUGETLB_SHARED 8
+#define MMF_DUMP_DAX_PRIVATE 9
+#define MMF_DUMP_DAX_SHARED 10
#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS
-#define MMF_DUMP_FILTER_BITS 7
+#define MMF_DUMP_FILTER_BITS 9
#define MMF_DUMP_FILTER_MASK \
(((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
#define MMF_DUMP_FILTER_DEFAULT \
@@ -1266,8 +1272,13 @@ struct sched_entity {
#endif
#ifdef CONFIG_SMP
- /* Per entity load average tracking */
- struct sched_avg avg;
+ /*
+ * Per entity load average tracking.
+ *
+ * Put into separate cache line so it does not
+ * collide with read-mostly values above.
+ */
+ struct sched_avg avg ____cacheline_aligned_in_smp;
#endif
};
@@ -1453,14 +1464,15 @@ struct task_struct {
/* Used for emulating ABI behavior of previous Linux versions */
unsigned int personality;
- unsigned in_execve:1; /* Tell the LSMs that the process is doing an
- * execve */
- unsigned in_iowait:1;
-
- /* Revert to default priority/policy when forking */
+ /* scheduler bits, serialized by scheduler locks */
unsigned sched_reset_on_fork:1;
unsigned sched_contributes_to_load:1;
unsigned sched_migrated:1;
+ unsigned :0; /* force alignment to the next boundary */
+
+ /* unserialized, strictly 'current' */
+ unsigned in_execve:1; /* bit to tell LSMs we're in execve */
+ unsigned in_iowait:1;
#ifdef CONFIG_MEMCG
unsigned memcg_may_oom:1;
#endif
@@ -1517,11 +1529,14 @@ struct task_struct {
cputime_t gtime;
struct prev_cputime prev_cputime;
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
- seqlock_t vtime_seqlock;
+ seqcount_t vtime_seqcount;
unsigned long long vtime_snap;
enum {
- VTIME_SLEEPING = 0,
+ /* Task is sleeping or running in a CPU with VTIME inactive */
+ VTIME_INACTIVE = 0,
+ /* Task runs in userspace in a CPU with VTIME active */
VTIME_USER,
+ /* Task runs in kernelspace in a CPU with VTIME active */
VTIME_SYS,
} vtime_snap_whence;
#endif
@@ -2000,7 +2015,8 @@ static inline int pid_alive(const struct task_struct *p)
}
/**
- * is_global_init - check if a task structure is init
+ * is_global_init - check if a task structure is init. Since init
+ * is free to have sub-threads we need to check tgid.
* @tsk: Task structure to be checked.
*
* Check if a task structure is the first user space task the kernel created.
@@ -2009,7 +2025,7 @@ static inline int pid_alive(const struct task_struct *p)
*/
static inline int is_global_init(struct task_struct *tsk)
{
- return tsk->pid == 1;
+ return task_tgid_nr(tsk) == 1;
}
extern struct pid *cad_pid;
diff --git a/include/linux/sched_clock.h b/include/linux/sched_clock.h
index efa931c..411b52e 100644
--- a/include/linux/sched_clock.h
+++ b/include/linux/sched_clock.h
@@ -10,11 +10,17 @@
#ifdef CONFIG_GENERIC_SCHED_CLOCK
extern void sched_clock_postinit(void);
-#else
-static inline void sched_clock_postinit(void) { }
-#endif
extern void sched_clock_register(u64 (*read)(void), int bits,
unsigned long rate);
+#else
+static inline void sched_clock_postinit(void) { }
+
+static inline void sched_clock_register(u64 (*read)(void), int bits,
+ unsigned long rate)
+{
+ ;
+}
+#endif
#endif
diff --git a/include/linux/scpi_protocol.h b/include/linux/scpi_protocol.h
new file mode 100644
index 0000000..72ce932
--- /dev/null
+++ b/include/linux/scpi_protocol.h
@@ -0,0 +1,78 @@
+/*
+ * SCPI Message Protocol driver header
+ *
+ * Copyright (C) 2014 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/types.h>
+
+struct scpi_opp {
+ u32 freq;
+ u32 m_volt;
+} __packed;
+
+struct scpi_dvfs_info {
+ unsigned int count;
+ unsigned int latency; /* in nanoseconds */
+ struct scpi_opp *opps;
+};
+
+enum scpi_sensor_class {
+ TEMPERATURE,
+ VOLTAGE,
+ CURRENT,
+ POWER,
+};
+
+struct scpi_sensor_info {
+ u16 sensor_id;
+ u8 class;
+ u8 trigger_type;
+ char name[20];
+} __packed;
+
+/**
+ * struct scpi_ops - represents the various operations provided
+ * by SCP through SCPI message protocol
+ * @get_version: returns the major and minor revision on the SCPI
+ * message protocol
+ * @clk_get_range: gets clock range limit(min - max in Hz)
+ * @clk_get_val: gets clock value(in Hz)
+ * @clk_set_val: sets the clock value, setting to 0 will disable the
+ * clock (if supported)
+ * @dvfs_get_idx: gets the Operating Point of the given power domain.
+ * OPP is an index to the list return by @dvfs_get_info
+ * @dvfs_set_idx: sets the Operating Point of the given power domain.
+ * OPP is an index to the list return by @dvfs_get_info
+ * @dvfs_get_info: returns the DVFS capabilities of the given power
+ * domain. It includes the OPP list and the latency information
+ */
+struct scpi_ops {
+ u32 (*get_version)(void);
+ int (*clk_get_range)(u16, unsigned long *, unsigned long *);
+ unsigned long (*clk_get_val)(u16);
+ int (*clk_set_val)(u16, unsigned long);
+ int (*dvfs_get_idx)(u8);
+ int (*dvfs_set_idx)(u8, u8);
+ struct scpi_dvfs_info *(*dvfs_get_info)(u8);
+ int (*sensor_get_capability)(u16 *sensors);
+ int (*sensor_get_info)(u16 sensor_id, struct scpi_sensor_info *);
+ int (*sensor_get_value)(u16, u32 *);
+};
+
+#if IS_REACHABLE(CONFIG_ARM_SCPI_PROTOCOL)
+struct scpi_ops *get_scpi_ops(void);
+#else
+static inline struct scpi_ops *get_scpi_ops(void) { return NULL; }
+#endif
diff --git a/include/linux/signal.h b/include/linux/signal.h
index ab1e039..92557bb 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -239,7 +239,6 @@ extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *);
extern int show_unhandled_signals;
-extern int sigsuspend(sigset_t *);
struct sigaction {
#ifndef __ARCH_HAS_IRIX_SIGACTION
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 7c82e3b..2037a86 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -158,6 +158,24 @@ size_t ksize(const void *);
#endif
/*
+ * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
+ * Intended for arches that get misalignment faults even for 64 bit integer
+ * aligned buffers.
+ */
+#ifndef ARCH_SLAB_MINALIGN
+#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
+#endif
+
+/*
+ * kmalloc and friends return ARCH_KMALLOC_MINALIGN aligned
+ * pointers. kmem_cache_alloc and friends return ARCH_SLAB_MINALIGN
+ * aligned pointers.
+ */
+#define __assume_kmalloc_alignment __assume_aligned(ARCH_KMALLOC_MINALIGN)
+#define __assume_slab_alignment __assume_aligned(ARCH_SLAB_MINALIGN)
+#define __assume_page_alignment __assume_aligned(PAGE_SIZE)
+
+/*
* Kmalloc array related definitions
*/
@@ -286,8 +304,8 @@ static __always_inline int kmalloc_index(size_t size)
}
#endif /* !CONFIG_SLOB */
-void *__kmalloc(size_t size, gfp_t flags);
-void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags);
+void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment;
+void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment;
void kmem_cache_free(struct kmem_cache *, void *);
/*
@@ -298,11 +316,11 @@ void kmem_cache_free(struct kmem_cache *, void *);
* Note that interrupts must be enabled when calling these functions.
*/
void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
-bool kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
+int kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
#ifdef CONFIG_NUMA
-void *__kmalloc_node(size_t size, gfp_t flags, int node);
-void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node);
+void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment;
+void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node) __assume_slab_alignment;
#else
static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node)
{
@@ -316,12 +334,12 @@ static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t f
#endif
#ifdef CONFIG_TRACING
-extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t);
+extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t) __assume_slab_alignment;
#ifdef CONFIG_NUMA
extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s,
gfp_t gfpflags,
- int node, size_t size);
+ int node, size_t size) __assume_slab_alignment;
#else
static __always_inline void *
kmem_cache_alloc_node_trace(struct kmem_cache *s,
@@ -354,10 +372,10 @@ kmem_cache_alloc_node_trace(struct kmem_cache *s,
}
#endif /* CONFIG_TRACING */
-extern void *kmalloc_order(size_t size, gfp_t flags, unsigned int order);
+extern void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment;
#ifdef CONFIG_TRACING
-extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order);
+extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment;
#else
static __always_inline void *
kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order)
@@ -482,15 +500,6 @@ static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node)
return __kmalloc_node(size, flags, node);
}
-/*
- * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment.
- * Intended for arches that get misalignment faults even for 64 bit integer
- * aligned buffers.
- */
-#ifndef ARCH_SLAB_MINALIGN
-#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long)
-#endif
-
struct memcg_cache_array {
struct rcu_head rcu;
struct kmem_cache *entries[0];
diff --git a/include/linux/soc/brcmstb/brcmstb.h b/include/linux/soc/brcmstb/brcmstb.h
new file mode 100644
index 0000000..337ce41
--- /dev/null
+++ b/include/linux/soc/brcmstb/brcmstb.h
@@ -0,0 +1,10 @@
+#ifndef __BRCMSTB_SOC_H
+#define __BRCMSTB_SOC_H
+
+/*
+ * Bus Interface Unit control register setup, must happen early during boot,
+ * before SMP is brought up, called by machine entry point.
+ */
+void brcmstb_biuctrl_init(void);
+
+#endif /* __BRCMSTB_SOC_H */
diff --git a/include/linux/soc/qcom/smd.h b/include/linux/soc/qcom/smd.h
index d7e50aa..d0cb6d1 100644
--- a/include/linux/soc/qcom/smd.h
+++ b/include/linux/soc/qcom/smd.h
@@ -9,6 +9,14 @@ struct qcom_smd_channel;
struct qcom_smd_lookup;
/**
+ * struct qcom_smd_id - struct used for matching a smd device
+ * @name: name of the channel
+ */
+struct qcom_smd_id {
+ char name[20];
+};
+
+/**
* struct qcom_smd_device - smd device struct
* @dev: the device struct
* @channel: handle to the smd channel for this device
@@ -21,6 +29,7 @@ struct qcom_smd_device {
/**
* struct qcom_smd_driver - smd driver struct
* @driver: underlying device driver
+ * @smd_match_table: static channel match table
* @probe: invoked when the smd channel is found
* @remove: invoked when the smd channel is closed
* @callback: invoked when an inbound message is received on the channel,
@@ -29,6 +38,8 @@ struct qcom_smd_device {
*/
struct qcom_smd_driver {
struct device_driver driver;
+ const struct qcom_smd_id *smd_match_table;
+
int (*probe)(struct qcom_smd_device *dev);
void (*remove)(struct qcom_smd_device *dev);
int (*callback)(struct qcom_smd_device *, const void *, size_t);
diff --git a/include/linux/soc/qcom/smem.h b/include/linux/soc/qcom/smem.h
index bc9630d..785e196 100644
--- a/include/linux/soc/qcom/smem.h
+++ b/include/linux/soc/qcom/smem.h
@@ -4,7 +4,7 @@
#define QCOM_SMEM_HOST_ANY -1
int qcom_smem_alloc(unsigned host, unsigned item, size_t size);
-int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size);
+void *qcom_smem_get(unsigned host, unsigned item, size_t *size);
int qcom_smem_get_free_space(unsigned host);
diff --git a/include/linux/spi/pxa2xx_spi.h b/include/linux/spi/pxa2xx_spi.h
index 6d36dac..9ec4c14 100644
--- a/include/linux/spi/pxa2xx_spi.h
+++ b/include/linux/spi/pxa2xx_spi.h
@@ -23,7 +23,6 @@ struct dma_chan;
/* device.platform_data for SSP controller devices */
struct pxa2xx_spi_master {
- u32 clock_enable;
u16 num_chipselect;
u8 enable_dma;
diff --git a/include/linux/stop_machine.h b/include/linux/stop_machine.h
index 0adedca..3cc9632 100644
--- a/include/linux/stop_machine.h
+++ b/include/linux/stop_machine.h
@@ -29,7 +29,7 @@ struct cpu_stop_work {
int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg);
int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg);
-void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
+bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf);
int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg);
@@ -65,7 +65,7 @@ static void stop_one_cpu_nowait_workfn(struct work_struct *work)
preempt_enable();
}
-static inline void stop_one_cpu_nowait(unsigned int cpu,
+static inline bool stop_one_cpu_nowait(unsigned int cpu,
cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf)
{
@@ -74,7 +74,10 @@ static inline void stop_one_cpu_nowait(unsigned int cpu,
work_buf->fn = fn;
work_buf->arg = arg;
schedule_work(&work_buf->work);
+ return true;
}
+
+ return false;
}
static inline int stop_cpus(const struct cpumask *cpumask,
@@ -99,7 +102,7 @@ static inline int try_stop_cpus(const struct cpumask *cpumask,
* grabbing every spinlock (and more). So the "read" side to such a
* lock is anything which disables preemption.
*/
-#if defined(CONFIG_STOP_MACHINE) && defined(CONFIG_SMP)
+#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
/**
* stop_machine: freeze the machine on all CPUs and run this function
@@ -118,7 +121,7 @@ int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus);
int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus);
-#else /* CONFIG_STOP_MACHINE && CONFIG_SMP */
+#else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
static inline int stop_machine(cpu_stop_fn_t fn, void *data,
const struct cpumask *cpus)
@@ -137,5 +140,5 @@ static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
return stop_machine(fn, data, cpus);
}
-#endif /* CONFIG_STOP_MACHINE && CONFIG_SMP */
+#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
#endif /* _LINUX_STOP_MACHINE */
diff --git a/include/linux/string.h b/include/linux/string.h
index 9ef7795..9eebc66 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -10,6 +10,7 @@
extern char *strndup_user(const char __user *, long);
extern void *memdup_user(const void __user *, size_t);
+extern void *memdup_user_nul(const void __user *, size_t);
/*
* Include machine specific inline routines
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index 03d3b4c..ed03c9f 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -48,8 +48,10 @@
struct cache_head {
struct hlist_node cache_list;
time_t expiry_time; /* After time time, don't use the data */
- time_t last_refresh; /* If CACHE_PENDING, this is when upcall
- * was sent, else this is when update was received
+ time_t last_refresh; /* If CACHE_PENDING, this is when upcall was
+ * sent, else this is when update was
+ * received, though it is alway set to
+ * be *after* ->flush_time.
*/
struct kref ref;
unsigned long flags;
@@ -105,8 +107,12 @@ struct cache_detail {
/* fields below this comment are for internal use
* and should not be touched by cache owners
*/
- time_t flush_time; /* flush all cache items with last_refresh
- * earlier than this */
+ time_t flush_time; /* flush all cache items with
+ * last_refresh at or earlier
+ * than this. last_refresh
+ * is never set at or earlier
+ * than this.
+ */
struct list_head others;
time_t nextcheck;
int entries;
@@ -203,7 +209,7 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
static inline int cache_is_expired(struct cache_detail *detail, struct cache_head *h)
{
return (h->expiry_time < seconds_since_boot()) ||
- (detail->flush_time > h->last_refresh);
+ (detail->flush_time >= h->last_refresh);
}
extern int cache_check(struct cache_detail *detail,
diff --git a/include/linux/sunxi-rsb.h b/include/linux/sunxi-rsb.h
new file mode 100644
index 0000000..7e75bb0
--- /dev/null
+++ b/include/linux/sunxi-rsb.h
@@ -0,0 +1,105 @@
+/*
+ * Allwinner Reduced Serial Bus Driver
+ *
+ * Copyright (c) 2015 Chen-Yu Tsai
+ *
+ * Author: Chen-Yu Tsai <wens@csie.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.
+ */
+#ifndef _SUNXI_RSB_H
+#define _SUNXI_RSB_H
+
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+struct sunxi_rsb;
+
+/**
+ * struct sunxi_rsb_device - Basic representation of an RSB device
+ * @dev: Driver model representation of the device.
+ * @ctrl: RSB controller managing the bus hosting this device.
+ * @rtaddr: This device's runtime address
+ * @hwaddr: This device's hardware address
+ */
+struct sunxi_rsb_device {
+ struct device dev;
+ struct sunxi_rsb *rsb;
+ int irq;
+ u8 rtaddr;
+ u16 hwaddr;
+};
+
+static inline struct sunxi_rsb_device *to_sunxi_rsb_device(struct device *d)
+{
+ return container_of(d, struct sunxi_rsb_device, dev);
+}
+
+static inline void *sunxi_rsb_device_get_drvdata(const struct sunxi_rsb_device *rdev)
+{
+ return dev_get_drvdata(&rdev->dev);
+}
+
+static inline void sunxi_rsb_device_set_drvdata(struct sunxi_rsb_device *rdev,
+ void *data)
+{
+ dev_set_drvdata(&rdev->dev, data);
+}
+
+/**
+ * struct sunxi_rsb_driver - RSB slave device driver
+ * @driver: RSB device drivers should initialize name and owner field of
+ * this structure.
+ * @probe: binds this driver to a RSB device.
+ * @remove: unbinds this driver from the RSB device.
+ */
+struct sunxi_rsb_driver {
+ struct device_driver driver;
+ int (*probe)(struct sunxi_rsb_device *rdev);
+ int (*remove)(struct sunxi_rsb_device *rdev);
+};
+
+static inline struct sunxi_rsb_driver *to_sunxi_rsb_driver(struct device_driver *d)
+{
+ return container_of(d, struct sunxi_rsb_driver, driver);
+}
+
+int sunxi_rsb_driver_register(struct sunxi_rsb_driver *rdrv);
+
+/**
+ * sunxi_rsb_driver_unregister() - unregister an RSB client driver
+ * @rdrv: the driver to unregister
+ */
+static inline void sunxi_rsb_driver_unregister(struct sunxi_rsb_driver *rdrv)
+{
+ if (rdrv)
+ driver_unregister(&rdrv->driver);
+}
+
+#define module_sunxi_rsb_driver(__sunxi_rsb_driver) \
+ module_driver(__sunxi_rsb_driver, sunxi_rsb_driver_register, \
+ sunxi_rsb_driver_unregister)
+
+struct regmap *__devm_regmap_init_sunxi_rsb(struct sunxi_rsb_device *rdev,
+ const struct regmap_config *config,
+ struct lock_class_key *lock_key,
+ const char *lock_name);
+
+/**
+ * devm_regmap_init_sunxi_rsb(): Initialise managed register map
+ *
+ * @rdev: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+#define devm_regmap_init_sunxi_rsb(rdev, config) \
+ __regmap_lockdep_wrapper(__devm_regmap_init_sunxi_rsb, #config, \
+ rdev, config)
+
+#endif /* _SUNXI_RSB_H */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index a156b82..185815c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -524,7 +524,7 @@ asmlinkage long sys_chown(const char __user *filename,
asmlinkage long sys_lchown(const char __user *filename,
uid_t user, gid_t group);
asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group);
-#ifdef CONFIG_UID16
+#ifdef CONFIG_HAVE_UID16
asmlinkage long sys_chown16(const char __user *filename,
old_uid_t user, old_gid_t group);
asmlinkage long sys_lchown16(const char __user *filename,
@@ -886,6 +886,9 @@ asmlinkage long sys_execveat(int dfd, const char __user *filename,
const char __user *const __user *envp, int flags);
asmlinkage long sys_membarrier(int cmd, int flags);
+asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in,
+ int fd_out, loff_t __user *off_out,
+ size_t len, unsigned int flags);
asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags);
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index ea090ea..c6f0f0d 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -64,10 +64,18 @@ do { \
* a new subdirectory with this name.
* @is_visible: Optional: Function to return permissions associated with an
* attribute of the group. Will be called repeatedly for each
- * attribute in the group. Only read/write permissions as well as
- * SYSFS_PREALLOC are accepted. Must return 0 if an attribute is
- * not visible. The returned value will replace static permissions
- * defined in struct attribute or struct bin_attribute.
+ * non-binary attribute in the group. Only read/write
+ * permissions as well as SYSFS_PREALLOC are accepted. Must
+ * return 0 if an attribute is not visible. The returned value
+ * will replace static permissions defined in struct attribute.
+ * @is_bin_visible:
+ * Optional: Function to return permissions associated with a
+ * binary attribute of the group. Will be called repeatedly
+ * for each binary attribute in the group. Only read/write
+ * permissions as well as SYSFS_PREALLOC are accepted. Must
+ * return 0 if a binary attribute is not visible. The returned
+ * value will replace static permissions defined in
+ * struct bin_attribute.
* @attrs: Pointer to NULL terminated list of attributes.
* @bin_attrs: Pointer to NULL terminated list of binary attributes.
* Either attrs or bin_attrs or both must be provided.
@@ -76,6 +84,8 @@ struct attribute_group {
const char *name;
umode_t (*is_visible)(struct kobject *,
struct attribute *, int);
+ umode_t (*is_bin_visible)(struct kobject *,
+ struct bin_attribute *, int);
struct attribute **attrs;
struct bin_attribute **bin_attrs;
};
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index c906f45..b386361 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -397,6 +397,13 @@ static inline void fastopen_queue_tune(struct sock *sk, int backlog)
queue->fastopenq.max_qlen = min_t(unsigned int, backlog, somaxconn);
}
+static inline void tcp_move_syn(struct tcp_sock *tp,
+ struct request_sock *req)
+{
+ tp->saved_syn = req->saved_syn;
+ req->saved_syn = NULL;
+}
+
static inline void tcp_saved_syn_free(struct tcp_sock *tp)
{
kfree(tp->saved_syn);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 157d366..613c29b 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -44,9 +44,11 @@
#define THERMAL_WEIGHT_DEFAULT 0
/* Unit conversion macros */
-#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
- ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
-#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
+#define DECI_KELVIN_TO_CELSIUS(t) ({ \
+ long _t = (t); \
+ ((_t-2732 >= 0) ? (_t-2732+5)/10 : (_t-2732-5)/10); \
+})
+#define CELSIUS_TO_DECI_KELVIN(t) ((t)*10+2732)
#define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100)
#define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732)
#define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off))
@@ -436,7 +438,8 @@ static inline void thermal_zone_device_unregister(
static inline int thermal_zone_bind_cooling_device(
struct thermal_zone_device *tz, int trip,
struct thermal_cooling_device *cdev,
- unsigned long upper, unsigned long lower)
+ unsigned long upper, unsigned long lower,
+ unsigned int weight)
{ return -ENODEV; }
static inline int thermal_zone_unbind_cooling_device(
struct thermal_zone_device *tz, int trip,
diff --git a/include/linux/time.h b/include/linux/time.h
index beebe3a..297f09f 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)
extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
+/*
+ * Validates if a timespec/timeval used to inject a time offset is valid.
+ * Offsets can be postive or negative. The value of the timeval/timespec
+ * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
+ * always be non-negative.
+ */
+static inline bool timeval_inject_offset_valid(const struct timeval *tv)
+{
+ /* We don't check the tv_sec as it can be positive or negative */
+
+ /* Can't have more microseconds then a second */
+ if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
+ return false;
+ return true;
+}
+
+static inline bool timespec_inject_offset_valid(const struct timespec *ts)
+{
+ /* We don't check the tv_sec as it can be positive or negative */
+
+ /* Can't have more nanoseconds then a second */
+ if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
+ return false;
+ return true;
+}
+
#define CURRENT_TIME (current_kernel_time())
#define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 })
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
new file mode 100644
index 0000000..e1ee97c
--- /dev/null
+++ b/include/linux/tracepoint-defs.h
@@ -0,0 +1,27 @@
+#ifndef TRACEPOINT_DEFS_H
+#define TRACEPOINT_DEFS_H 1
+
+/*
+ * File can be included directly by headers who only want to access
+ * tracepoint->key to guard out of line trace calls. Otherwise
+ * linux/tracepoint.h should be used.
+ */
+
+#include <linux/atomic.h>
+#include <linux/static_key.h>
+
+struct tracepoint_func {
+ void *func;
+ void *data;
+ int prio;
+};
+
+struct tracepoint {
+ const char *name; /* Tracepoint name */
+ struct static_key key;
+ void (*regfunc)(void);
+ void (*unregfunc)(void);
+ struct tracepoint_func __rcu *funcs;
+};
+
+#endif
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 696a339c..78e8397 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -17,26 +17,12 @@
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/rcupdate.h>
-#include <linux/static_key.h>
+#include <linux/tracepoint-defs.h>
struct module;
struct tracepoint;
struct notifier_block;
-struct tracepoint_func {
- void *func;
- void *data;
- int prio;
-};
-
-struct tracepoint {
- const char *name; /* Tracepoint name */
- struct static_key key;
- void (*regfunc)(void);
- void (*unregfunc)(void);
- struct tracepoint_func __rcu *funcs;
-};
-
struct trace_enum_map {
const char *system;
const char *enum_string;
@@ -171,8 +157,8 @@ extern void syscall_unregfunc(void);
TP_PROTO(data_proto), \
TP_ARGS(data_args), \
TP_CONDITION(cond), \
- rcu_irq_enter(), \
- rcu_irq_exit()); \
+ rcu_irq_enter_irqson(), \
+ rcu_irq_exit_irqson()); \
}
#else
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5b04b0a..5e31f1b 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -607,7 +607,7 @@ extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops);
/* tty_audit.c */
#ifdef CONFIG_AUDIT
-extern void tty_audit_add_data(struct tty_struct *tty, unsigned char *data,
+extern void tty_audit_add_data(struct tty_struct *tty, const void *data,
size_t size, unsigned icanon);
extern void tty_audit_exit(void);
extern void tty_audit_fork(struct signal_struct *sig);
@@ -615,8 +615,8 @@ extern void tty_audit_tiocsti(struct tty_struct *tty, char ch);
extern void tty_audit_push(struct tty_struct *tty);
extern int tty_audit_push_current(void);
#else
-static inline void tty_audit_add_data(struct tty_struct *tty,
- unsigned char *data, size_t size, unsigned icanon)
+static inline void tty_audit_add_data(struct tty_struct *tty, const void *data,
+ size_t size, unsigned icanon)
{
}
static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch)
diff --git a/include/linux/types.h b/include/linux/types.h
index 70d8500..70dd3df 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -35,7 +35,7 @@ typedef __kernel_gid16_t gid16_t;
typedef unsigned long uintptr_t;
-#ifdef CONFIG_UID16
+#ifdef CONFIG_HAVE_UID16
/* This is defined by include/asm-{arch}/posix_types.h */
typedef __kernel_old_uid_t old_uid_t;
typedef __kernel_old_gid_t old_gid_t;
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 8b01e1c..fd9bcfe 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -82,7 +82,7 @@ size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i);
size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes,
struct iov_iter *i);
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i);
+size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i);
size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i);
size_t iov_iter_zero(size_t bytes, struct iov_iter *);
@@ -145,7 +145,7 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
{
i->count = count;
}
-size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
+size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
int import_iovec(int type, const struct iovec __user * uvector,
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 0bdc72f..4a29c75 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -21,7 +21,7 @@
* Authors:
* Srikar Dronamraju
* Jim Keniston
- * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
*/
#include <linux/errno.h>
diff --git a/include/linux/usb/cdc_ncm.h b/include/linux/usb/cdc_ncm.h
index 1f6526c..3a375d0 100644
--- a/include/linux/usb/cdc_ncm.h
+++ b/include/linux/usb/cdc_ncm.h
@@ -138,6 +138,7 @@ struct cdc_ncm_ctx {
};
u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
+int cdc_ncm_change_mtu(struct net_device *net, int new_mtu);
int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
diff --git a/include/linux/usb/gadget_configfs.h b/include/linux/usb/gadget_configfs.h
index d74c0ae..c36e957 100644
--- a/include/linux/usb/gadget_configfs.h
+++ b/include/linux/usb/gadget_configfs.h
@@ -7,9 +7,10 @@ int check_user_usb_string(const char *name,
struct usb_gadget_strings *stringtab_dev);
#define GS_STRINGS_W(__struct, __name) \
- static ssize_t __struct##_##__name##_store(struct __struct *gs, \
+static ssize_t __struct##_##__name##_store(struct config_item *item, \
const char *page, size_t len) \
{ \
+ struct __struct *gs = to_##__struct(item); \
int ret; \
\
ret = usb_string_copy(page, &gs->__name); \
@@ -19,30 +20,20 @@ int check_user_usb_string(const char *name,
}
#define GS_STRINGS_R(__struct, __name) \
- static ssize_t __struct##_##__name##_show(struct __struct *gs, \
- char *page) \
+static ssize_t __struct##_##__name##_show(struct config_item *item, char *page) \
{ \
+ struct __struct *gs = to_##__struct(item); \
return sprintf(page, "%s\n", gs->__name ?: ""); \
}
-#define GS_STRING_ITEM_ATTR(struct_name, name) \
- static struct struct_name##_attribute struct_name##_##name = \
- __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \
- struct_name##_##name##_show, \
- struct_name##_##name##_store)
-
#define GS_STRINGS_RW(struct_name, _name) \
GS_STRINGS_R(struct_name, _name) \
GS_STRINGS_W(struct_name, _name) \
- GS_STRING_ITEM_ATTR(struct_name, _name)
+ CONFIGFS_ATTR(struct_name##_, _name)
#define USB_CONFIG_STRING_RW_OPS(struct_in) \
- CONFIGFS_ATTR_OPS(struct_in); \
- \
static struct configfs_item_operations struct_in##_langid_item_ops = { \
.release = struct_in##_attr_release, \
- .show_attribute = struct_in##_attr_show, \
- .store_attribute = struct_in##_attr_store, \
}; \
\
static struct config_item_type struct_in##_langid_type = { \
diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h
index 9948c87..1d0043d 100644
--- a/include/linux/usb/quirks.h
+++ b/include/linux/usb/quirks.h
@@ -47,4 +47,7 @@
/* device generates spurious wakeup, ignore remote wakeup capability */
#define USB_QUIRK_IGNORE_REMOTE_WAKEUP BIT(9)
+/* device can't handle Link Power Management */
+#define USB_QUIRK_NO_LPM BIT(10)
+
#endif /* __LINUX_USB_QUIRKS_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 73ea2fb..16c0ed6 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -46,7 +46,7 @@
* All kernel-specific stuff were moved to media/v4l2-dev.h, so
* no #if __KERNEL tests are allowed here
*
- * See http://linuxtv.org for more info
+ * See https://linuxtv.org for more info
*
* Author: Bill Dirks <bill@thedirks.org>
* Justin Schoeman
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 5dbc8b0..3e5d907 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -176,11 +176,11 @@ extern void zone_statistics(struct zone *, struct zone *, gfp_t gfp);
#define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d))
#ifdef CONFIG_SMP
-void __mod_zone_page_state(struct zone *, enum zone_stat_item item, int);
+void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long);
void __inc_zone_page_state(struct page *, enum zone_stat_item);
void __dec_zone_page_state(struct page *, enum zone_stat_item);
-void mod_zone_page_state(struct zone *, enum zone_stat_item, int);
+void mod_zone_page_state(struct zone *, enum zone_stat_item, long);
void inc_zone_page_state(struct page *, enum zone_stat_item);
void dec_zone_page_state(struct page *, enum zone_stat_item);
@@ -205,7 +205,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
* The functions directly modify the zone and global counters.
*/
static inline void __mod_zone_page_state(struct zone *zone,
- enum zone_stat_item item, int delta)
+ enum zone_stat_item item, long delta)
{
zone_page_state_add(delta, zone, item);
}
diff --git a/include/linux/vtime.h b/include/linux/vtime.h
index c5165fd..fa21969 100644
--- a/include/linux/vtime.h
+++ b/include/linux/vtime.h
@@ -10,16 +10,27 @@
struct task_struct;
/*
- * vtime_accounting_enabled() definitions/declarations
+ * vtime_accounting_cpu_enabled() definitions/declarations
*/
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
-static inline bool vtime_accounting_enabled(void) { return true; }
+static inline bool vtime_accounting_cpu_enabled(void) { return true; }
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
+/*
+ * Checks if vtime is enabled on some CPU. Cputime readers want to be careful
+ * in that case and compute the tickless cputime.
+ * For now vtime state is tied to context tracking. We might want to decouple
+ * those later if necessary.
+ */
static inline bool vtime_accounting_enabled(void)
{
- if (context_tracking_is_enabled()) {
+ return context_tracking_is_enabled();
+}
+
+static inline bool vtime_accounting_cpu_enabled(void)
+{
+ if (vtime_accounting_enabled()) {
if (context_tracking_cpu_is_enabled())
return true;
}
@@ -29,7 +40,7 @@ static inline bool vtime_accounting_enabled(void)
#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
-static inline bool vtime_accounting_enabled(void) { return false; }
+static inline bool vtime_accounting_cpu_enabled(void) { return false; }
#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */
@@ -44,7 +55,7 @@ extern void vtime_task_switch(struct task_struct *prev);
extern void vtime_common_task_switch(struct task_struct *prev);
static inline void vtime_task_switch(struct task_struct *prev)
{
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
vtime_common_task_switch(prev);
}
#endif /* __ARCH_HAS_VTIME_TASK_SWITCH */
@@ -59,7 +70,7 @@ extern void vtime_account_irq_enter(struct task_struct *tsk);
extern void vtime_common_account_irq_enter(struct task_struct *tsk);
static inline void vtime_account_irq_enter(struct task_struct *tsk)
{
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
vtime_common_account_irq_enter(tsk);
}
#endif /* __ARCH_HAS_VTIME_ACCOUNT */
@@ -78,7 +89,7 @@ extern void vtime_gen_account_irq_exit(struct task_struct *tsk);
static inline void vtime_account_irq_exit(struct task_struct *tsk)
{
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
vtime_gen_account_irq_exit(tsk);
}
diff --git a/include/linux/wait.h b/include/linux/wait.h
index 1e1bf9f..d2f4ec7 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -102,6 +102,36 @@ init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func)
q->func = func;
}
+/**
+ * waitqueue_active -- locklessly test for waiters on the queue
+ * @q: the waitqueue to test for waiters
+ *
+ * returns true if the wait list is not empty
+ *
+ * NOTE: this function is lockless and requires care, incorrect usage _will_
+ * lead to sporadic and non-obvious failure.
+ *
+ * Use either while holding wait_queue_head_t::lock or when used for wakeups
+ * with an extra smp_mb() like:
+ *
+ * CPU0 - waker CPU1 - waiter
+ *
+ * for (;;) {
+ * @cond = true; prepare_to_wait(&wq, &wait, state);
+ * smp_mb(); // smp_mb() from set_current_state()
+ * if (waitqueue_active(wq)) if (@cond)
+ * wake_up(wq); break;
+ * schedule();
+ * }
+ * finish_wait(&wq, &wait);
+ *
+ * Because without the explicit smp_mb() it's possible for the
+ * waitqueue_active() load to get hoisted over the @cond store such that we'll
+ * observe an empty wait list while the waiter might not observe @cond.
+ *
+ * Also note that this 'optimization' trades a spin_lock() for an smp_mb(),
+ * which (when the lock is uncontended) are of roughly equal cost.
+ */
static inline int waitqueue_active(wait_queue_head_t *q)
{
return !list_empty(&q->task_list);
@@ -145,7 +175,7 @@ __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old)
list_del(&old->task_list);
}
-typedef int wait_bit_action_f(struct wait_bit_key *);
+typedef int wait_bit_action_f(struct wait_bit_key *, int mode);
void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key);
void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key);
@@ -960,10 +990,10 @@ int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
} while (0)
-extern int bit_wait(struct wait_bit_key *);
-extern int bit_wait_io(struct wait_bit_key *);
-extern int bit_wait_timeout(struct wait_bit_key *);
-extern int bit_wait_io_timeout(struct wait_bit_key *);
+extern int bit_wait(struct wait_bit_key *, int);
+extern int bit_wait_io(struct wait_bit_key *, int);
+extern int bit_wait_timeout(struct wait_bit_key *, int);
+extern int bit_wait_io_timeout(struct wait_bit_key *, int);
/**
* wait_on_bit - wait for a bit to be cleared
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 0197358..0e32bc7 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -618,4 +618,10 @@ static inline int workqueue_sysfs_register(struct workqueue_struct *wq)
{ return 0; }
#endif /* CONFIG_SYSFS */
+#ifdef CONFIG_WQ_WATCHDOG
+void wq_watchdog_touch(int cpu);
+#else /* CONFIG_WQ_WATCHDOG */
+static inline void wq_watchdog_touch(int cpu) { }
+#endif /* CONFIG_WQ_WATCHDOG */
+
#endif
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 91b0a68..4457541 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -19,17 +19,25 @@
struct inode;
struct dentry;
+/*
+ * struct xattr_handler: When @name is set, match attributes with exactly that
+ * name. When @prefix is set instead, match attributes with that prefix and
+ * with a non-empty suffix.
+ */
struct xattr_handler {
+ const char *name;
const char *prefix;
- int flags; /* fs private flags passed back to the handlers */
- size_t (*list)(struct dentry *dentry, char *list, size_t list_size,
- const char *name, size_t name_len, int handler_flags);
- int (*get)(struct dentry *dentry, const char *name, void *buffer,
- size_t size, int handler_flags);
- int (*set)(struct dentry *dentry, const char *name, const void *buffer,
- size_t size, int flags, int handler_flags);
+ int flags; /* fs private flags */
+ bool (*list)(struct dentry *dentry);
+ int (*get)(const struct xattr_handler *, struct dentry *dentry,
+ const char *name, void *buffer, size_t size);
+ int (*set)(const struct xattr_handler *, struct dentry *dentry,
+ const char *name, const void *buffer, size_t size,
+ int flags);
};
+const char *xattr_full_name(const struct xattr_handler *, const char *);
+
struct xattr {
const char *name;
void *value;
@@ -49,8 +57,11 @@ int generic_setxattr(struct dentry *dentry, const char *name, const void *value,
int generic_removexattr(struct dentry *dentry, const char *name);
ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
char **xattr_value, size_t size, gfp_t flags);
-int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
- const char *value, size_t size, gfp_t flags);
+
+static inline const char *xattr_prefix(const struct xattr_handler *handler)
+{
+ return handler->prefix ?: handler->name;
+}
struct simple_xattrs {
struct list_head head;
@@ -91,8 +102,7 @@ int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
void *buffer, size_t size);
int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
const void *value, size_t size, int flags);
-int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name);
-ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
+ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, char *buffer,
size_t size);
void simple_xattr_list_add(struct simple_xattrs *xattrs,
struct simple_xattr *new_xattr);
diff --git a/include/media/cx2341x.h b/include/media/drv-intf/cx2341x.h
index 9635eeb..9635eeb 100644
--- a/include/media/cx2341x.h
+++ b/include/media/drv-intf/cx2341x.h
diff --git a/include/media/cx25840.h b/include/media/drv-intf/cx25840.h
index 783c5bd..783c5bd 100644
--- a/include/media/cx25840.h
+++ b/include/media/drv-intf/cx25840.h
diff --git a/include/media/exynos-fimc.h b/include/media/drv-intf/exynos-fimc.h
index 69bcd2a..69bcd2a 100644
--- a/include/media/exynos-fimc.h
+++ b/include/media/drv-intf/exynos-fimc.h
diff --git a/include/media/msp3400.h b/include/media/drv-intf/msp3400.h
index 90cf22a..1e6e802 100644
--- a/include/media/msp3400.h
+++ b/include/media/drv-intf/msp3400.h
@@ -223,4 +223,3 @@
*/
#endif /* MSP3400_H */
-
diff --git a/include/media/s3c_camif.h b/include/media/drv-intf/s3c_camif.h
index df96c2c..df96c2c 100644
--- a/include/media/s3c_camif.h
+++ b/include/media/drv-intf/s3c_camif.h
diff --git a/include/media/saa7146.h b/include/media/drv-intf/saa7146.h
index 96058a5..96058a5 100644
--- a/include/media/saa7146.h
+++ b/include/media/drv-intf/saa7146.h
diff --git a/include/media/saa7146_vv.h b/include/media/drv-intf/saa7146_vv.h
index 92766f7..0da6ccc 100644
--- a/include/media/saa7146_vv.h
+++ b/include/media/drv-intf/saa7146_vv.h
@@ -4,7 +4,7 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-fh.h>
-#include <media/saa7146.h>
+#include <media/drv-intf/saa7146.h>
#include <media/videobuf-dma-sg.h>
#define MAX_SAA7146_CAPTURE_BUFFERS 32 /* arbitrary */
diff --git a/include/media/sh_mobile_ceu.h b/include/media/drv-intf/sh_mobile_ceu.h
index 7f57056..7f57056 100644
--- a/include/media/sh_mobile_ceu.h
+++ b/include/media/drv-intf/sh_mobile_ceu.h
diff --git a/include/media/sh_mobile_csi2.h b/include/media/drv-intf/sh_mobile_csi2.h
index 14030db..14030db 100644
--- a/include/media/sh_mobile_csi2.h
+++ b/include/media/drv-intf/sh_mobile_csi2.h
diff --git a/include/media/sh_vou.h b/include/media/drv-intf/sh_vou.h
index ec3ba9a..ec3ba9a 100644
--- a/include/media/sh_vou.h
+++ b/include/media/drv-intf/sh_vou.h
diff --git a/include/media/si476x.h b/include/media/drv-intf/si476x.h
index e02e241..ad87fa8 100644
--- a/include/media/si476x.h
+++ b/include/media/drv-intf/si476x.h
@@ -1,5 +1,5 @@
/*
- * include/media/si476x.h -- Common definitions for si476x driver
+ * include/media/drv-intf/si476x.h -- Common definitions for si476x driver
*
* Copyright (C) 2012 Innovative Converged Devices(ICD)
* Copyright (C) 2013 Andrey Smirnov
diff --git a/include/media/soc_mediabus.h b/include/media/drv-intf/soc_mediabus.h
index 2ff7737..2ff7737 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/drv-intf/soc_mediabus.h
diff --git a/include/media/tea575x.h b/include/media/drv-intf/tea575x.h
index 5d09657..fb272d4 100644
--- a/include/media/tea575x.h
+++ b/include/media/drv-intf/tea575x.h
@@ -63,7 +63,7 @@ struct snd_tea575x {
u32 band; /* 0: FM, 1: FM-Japan, 2: AM */
u32 freq; /* frequency */
struct mutex mutex;
- struct snd_tea575x_ops *ops;
+ const struct snd_tea575x_ops *ops;
void *private_data;
u8 card[32];
u8 bus_info[32];
diff --git a/include/media/ad9389b.h b/include/media/i2c/ad9389b.h
index 5ba9af8..5ba9af8 100644
--- a/include/media/ad9389b.h
+++ b/include/media/i2c/ad9389b.h
diff --git a/include/media/adp1653.h b/include/media/i2c/adp1653.h
index 9779c85..0b67093 100644
--- a/include/media/adp1653.h
+++ b/include/media/i2c/adp1653.h
@@ -1,5 +1,5 @@
/*
- * include/media/adp1653.h
+ * include/media/i2c/adp1653.h
*
* Copyright (C) 2008--2011 Nokia Corporation
*
diff --git a/include/media/adv7183.h b/include/media/i2c/adv7183.h
index c5c2d37..c5c2d37 100644
--- a/include/media/adv7183.h
+++ b/include/media/i2c/adv7183.h
diff --git a/include/media/adv7343.h b/include/media/i2c/adv7343.h
index e4142b1..e4142b1 100644
--- a/include/media/adv7343.h
+++ b/include/media/i2c/adv7343.h
diff --git a/include/media/adv7393.h b/include/media/i2c/adv7393.h
index b28edf3..b28edf3 100644
--- a/include/media/adv7393.h
+++ b/include/media/i2c/adv7393.h
diff --git a/include/media/adv7511.h b/include/media/i2c/adv7511.h
index d83b91d..d83b91d 100644
--- a/include/media/adv7511.h
+++ b/include/media/i2c/adv7511.h
diff --git a/include/media/adv7604.h b/include/media/i2c/adv7604.h
index a913859..a913859 100644
--- a/include/media/adv7604.h
+++ b/include/media/i2c/adv7604.h
diff --git a/include/media/adv7842.h b/include/media/i2c/adv7842.h
index bc24970..bc24970 100644
--- a/include/media/adv7842.h
+++ b/include/media/i2c/adv7842.h
diff --git a/include/media/ak881x.h b/include/media/i2c/ak881x.h
index b7f2add..b7f2add 100644
--- a/include/media/ak881x.h
+++ b/include/media/i2c/ak881x.h
diff --git a/include/media/as3645a.h b/include/media/i2c/as3645a.h
index 5075496..0e07484 100644
--- a/include/media/as3645a.h
+++ b/include/media/i2c/as3645a.h
@@ -1,5 +1,5 @@
/*
- * include/media/as3645a.h
+ * include/media/i2c/as3645a.h
*
* Copyright (C) 2008-2011 Nokia Corporation
*
diff --git a/include/media/bt819.h b/include/media/i2c/bt819.h
index 8025f4b..8025f4b 100644
--- a/include/media/bt819.h
+++ b/include/media/i2c/bt819.h
diff --git a/include/media/cs5345.h b/include/media/i2c/cs5345.h
index 6ccae24..6ccae24 100644
--- a/include/media/cs5345.h
+++ b/include/media/i2c/cs5345.h
diff --git a/include/media/cs53l32a.h b/include/media/i2c/cs53l32a.h
index bf76197..bf76197 100644
--- a/include/media/cs53l32a.h
+++ b/include/media/i2c/cs53l32a.h
diff --git a/include/media/ir-kbd-i2c.h b/include/media/i2c/ir-kbd-i2c.h
index d856435..d856435 100644
--- a/include/media/ir-kbd-i2c.h
+++ b/include/media/i2c/ir-kbd-i2c.h
diff --git a/include/media/lm3560.h b/include/media/i2c/lm3560.h
index 4667070..5ed942a 100644
--- a/include/media/lm3560.h
+++ b/include/media/i2c/lm3560.h
@@ -1,5 +1,5 @@
/*
- * include/media/lm3560.h
+ * include/media/i2c/lm3560.h
*
* Copyright (C) 2013 Texas Instruments
*
diff --git a/include/media/lm3646.h b/include/media/i2c/lm3646.h
index c6acf5a..724c100 100644
--- a/include/media/lm3646.h
+++ b/include/media/i2c/lm3646.h
@@ -1,5 +1,5 @@
/*
- * include/media/lm3646.h
+ * include/media/i2c/lm3646.h
*
* Copyright (C) 2014 Texas Instruments
*
diff --git a/include/media/m52790.h b/include/media/i2c/m52790.h
index 7ddffae..7ddffae 100644
--- a/include/media/m52790.h
+++ b/include/media/i2c/m52790.h
diff --git a/include/media/m5mols.h b/include/media/i2c/m5mols.h
index 4a825ae..4a825ae 100644
--- a/include/media/m5mols.h
+++ b/include/media/i2c/m5mols.h
diff --git a/include/media/mt9m032.h b/include/media/i2c/mt9m032.h
index c3a7811..c3a7811 100644
--- a/include/media/mt9m032.h
+++ b/include/media/i2c/mt9m032.h
diff --git a/include/media/mt9p031.h b/include/media/i2c/mt9p031.h
index 1ba3612..1ba3612 100644
--- a/include/media/mt9p031.h
+++ b/include/media/i2c/mt9p031.h
diff --git a/include/media/mt9t001.h b/include/media/i2c/mt9t001.h
index 03fd63e..03fd63e 100644
--- a/include/media/mt9t001.h
+++ b/include/media/i2c/mt9t001.h
diff --git a/include/media/mt9t112.h b/include/media/i2c/mt9t112.h
index a43c74a..a43c74a 100644
--- a/include/media/mt9t112.h
+++ b/include/media/i2c/mt9t112.h
diff --git a/include/media/mt9v011.h b/include/media/i2c/mt9v011.h
index ea29fc7..ea29fc7 100644
--- a/include/media/mt9v011.h
+++ b/include/media/i2c/mt9v011.h
diff --git a/include/media/mt9v022.h b/include/media/i2c/mt9v022.h
index 4056180..4056180 100644
--- a/include/media/mt9v022.h
+++ b/include/media/i2c/mt9v022.h
diff --git a/include/media/mt9v032.h b/include/media/i2c/mt9v032.h
index 12175a6..12175a6 100644
--- a/include/media/mt9v032.h
+++ b/include/media/i2c/mt9v032.h
diff --git a/include/media/noon010pc30.h b/include/media/i2c/noon010pc30.h
index 58eafee..58eafee 100644
--- a/include/media/noon010pc30.h
+++ b/include/media/i2c/noon010pc30.h
diff --git a/include/media/ov2659.h b/include/media/i2c/ov2659.h
index 4216adc..4216adc 100644
--- a/include/media/ov2659.h
+++ b/include/media/i2c/ov2659.h
diff --git a/include/media/ov7670.h b/include/media/i2c/ov7670.h
index 1913d51..1913d51 100644
--- a/include/media/ov7670.h
+++ b/include/media/i2c/ov7670.h
diff --git a/include/media/ov772x.h b/include/media/i2c/ov772x.h
index 00dbb7c..00dbb7c 100644
--- a/include/media/ov772x.h
+++ b/include/media/i2c/ov772x.h
diff --git a/include/media/ov9650.h b/include/media/i2c/ov9650.h
index d630cf9..d630cf9 100644
--- a/include/media/ov9650.h
+++ b/include/media/i2c/ov9650.h
diff --git a/include/media/rj54n1cb0c.h b/include/media/i2c/rj54n1cb0c.h
index 8ae3288..8ae3288 100644
--- a/include/media/rj54n1cb0c.h
+++ b/include/media/i2c/rj54n1cb0c.h
diff --git a/include/media/s5c73m3.h b/include/media/i2c/s5c73m3.h
index ccb9e54..ccb9e54 100644
--- a/include/media/s5c73m3.h
+++ b/include/media/i2c/s5c73m3.h
diff --git a/include/media/s5k4ecgx.h b/include/media/i2c/s5k4ecgx.h
index 90c1be7..90c1be7 100644
--- a/include/media/s5k4ecgx.h
+++ b/include/media/i2c/s5k4ecgx.h
diff --git a/include/media/s5k6aa.h b/include/media/i2c/s5k6aa.h
index ba34f70..ba34f70 100644
--- a/include/media/s5k6aa.h
+++ b/include/media/i2c/s5k6aa.h
diff --git a/include/media/saa6588.h b/include/media/i2c/saa6588.h
index b5ec1aa..b5ec1aa 100644
--- a/include/media/saa6588.h
+++ b/include/media/i2c/saa6588.h
diff --git a/include/media/saa7115.h b/include/media/i2c/saa7115.h
index 76911e7..53954c9 100644
--- a/include/media/saa7115.h
+++ b/include/media/i2c/saa7115.h
@@ -138,4 +138,3 @@ struct saa7115_platform_data {
};
#endif
-
diff --git a/include/media/saa7127.h b/include/media/i2c/saa7127.h
index bbcf862..7005ba7 100644
--- a/include/media/saa7127.h
+++ b/include/media/i2c/saa7127.h
@@ -38,4 +38,3 @@ enum saa7127_output_type {
};
#endif
-
diff --git a/include/media/smiapp.h b/include/media/i2c/smiapp.h
index 268a3cd..029142d 100644
--- a/include/media/smiapp.h
+++ b/include/media/i2c/smiapp.h
@@ -1,5 +1,5 @@
/*
- * include/media/smiapp.h
+ * include/media/i2c/smiapp.h
*
* Generic driver for SMIA/SMIA++ compliant camera modules
*
diff --git a/include/media/sr030pc30.h b/include/media/i2c/sr030pc30.h
index 6f901a6..6f901a6 100644
--- a/include/media/sr030pc30.h
+++ b/include/media/i2c/sr030pc30.h
diff --git a/include/media/tc358743.h b/include/media/i2c/tc358743.h
index 4513f2f..4513f2f 100644
--- a/include/media/tc358743.h
+++ b/include/media/i2c/tc358743.h
diff --git a/include/media/ths7303.h b/include/media/i2c/ths7303.h
index a7b4929..a7b4929 100644
--- a/include/media/ths7303.h
+++ b/include/media/i2c/ths7303.h
diff --git a/include/media/tvaudio.h b/include/media/i2c/tvaudio.h
index 1ac8184..1ac8184 100644
--- a/include/media/tvaudio.h
+++ b/include/media/i2c/tvaudio.h
diff --git a/include/media/tvp514x.h b/include/media/i2c/tvp514x.h
index 86ed7e8..86ed7e8 100644
--- a/include/media/tvp514x.h
+++ b/include/media/i2c/tvp514x.h
diff --git a/include/media/tvp5150.h b/include/media/i2c/tvp5150.h
index 72bd2a2..649908a 100644
--- a/include/media/tvp5150.h
+++ b/include/media/i2c/tvp5150.h
@@ -31,4 +31,3 @@
#define TVP5150_BLACK_SCREEN 1
#endif
-
diff --git a/include/media/tvp7002.h b/include/media/i2c/tvp7002.h
index fadb6af..fadb6af 100644
--- a/include/media/tvp7002.h
+++ b/include/media/i2c/tvp7002.h
diff --git a/include/media/tw9910.h b/include/media/i2c/tw9910.h
index 90bcf1f..90bcf1f 100644
--- a/include/media/tw9910.h
+++ b/include/media/i2c/tw9910.h
diff --git a/include/media/uda1342.h b/include/media/i2c/uda1342.h
index cd15640..cd15640 100644
--- a/include/media/uda1342.h
+++ b/include/media/i2c/uda1342.h
diff --git a/include/media/upd64031a.h b/include/media/i2c/upd64031a.h
index 3ad6a32..3ad6a32 100644
--- a/include/media/upd64031a.h
+++ b/include/media/i2c/upd64031a.h
diff --git a/include/media/upd64083.h b/include/media/i2c/upd64083.h
index 59b6f32..59b6f32 100644
--- a/include/media/upd64083.h
+++ b/include/media/i2c/upd64083.h
diff --git a/include/media/wm8775.h b/include/media/i2c/wm8775.h
index d0e801a..d0e801a 100644
--- a/include/media/wm8775.h
+++ b/include/media/i2c/wm8775.h
diff --git a/include/media/lirc.h b/include/media/lirc.h
index 4b3ab29..554988c 100644
--- a/include/media/lirc.h
+++ b/include/media/lirc.h
@@ -1,168 +1 @@
-/*
- * lirc.h - linux infrared remote control header file
- * last modified 2010/07/13 by Jarod Wilson
- */
-
-#ifndef _LINUX_LIRC_H
-#define _LINUX_LIRC_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-#define PULSE_BIT 0x01000000
-#define PULSE_MASK 0x00FFFFFF
-
-#define LIRC_MODE2_SPACE 0x00000000
-#define LIRC_MODE2_PULSE 0x01000000
-#define LIRC_MODE2_FREQUENCY 0x02000000
-#define LIRC_MODE2_TIMEOUT 0x03000000
-
-#define LIRC_VALUE_MASK 0x00FFFFFF
-#define LIRC_MODE2_MASK 0xFF000000
-
-#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
-#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
-#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
-#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
-
-#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
-#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
-
-#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
-#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
-#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
-#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
-
-/* used heavily by lirc userspace */
-#define lirc_t int
-
-/*** lirc compatible hardware features ***/
-
-#define LIRC_MODE2SEND(x) (x)
-#define LIRC_SEND2MODE(x) (x)
-#define LIRC_MODE2REC(x) ((x) << 16)
-#define LIRC_REC2MODE(x) ((x) >> 16)
-
-#define LIRC_MODE_RAW 0x00000001
-#define LIRC_MODE_PULSE 0x00000002
-#define LIRC_MODE_MODE2 0x00000004
-#define LIRC_MODE_LIRCCODE 0x00000010
-
-
-#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW)
-#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE)
-#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2)
-#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_SEND_MASK 0x0000003f
-
-#define LIRC_CAN_SET_SEND_CARRIER 0x00000100
-#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200
-#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400
-
-#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW)
-#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE)
-#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2)
-#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
-
-#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
-
-#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16)
-#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
-
-#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
-#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000
-#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000
-#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000
-#define LIRC_CAN_SET_REC_FILTER 0x08000000
-
-#define LIRC_CAN_MEASURE_CARRIER 0x02000000
-#define LIRC_CAN_USE_WIDEBAND_RECEIVER 0x04000000
-
-#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
-#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
-
-#define LIRC_CAN_NOTIFY_DECODE 0x01000000
-
-/*** IOCTL commands for lirc driver ***/
-
-#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32)
-
-#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32)
-#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32)
-#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32)
-#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32)
-#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32)
-#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32)
-#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32)
-
-#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32)
-#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32)
-
-#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32)
-#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32)
-#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32)
-#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32)
-
-/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
-#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32)
-
-#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32)
-#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32)
-/* Note: these can reset the according pulse_width */
-#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32)
-#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32)
-#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32)
-#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32)
-#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32)
-
-/*
- * when a timeout != 0 is set the driver will send a
- * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
- * never sent, timeout is disabled by default
- */
-#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32)
-
-/* 1 enables, 0 disables timeout reports in MODE2 */
-#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32)
-
-/*
- * pulses shorter than this are filtered out by hardware (software
- * emulation in lirc_dev?)
- */
-#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32)
-/*
- * spaces shorter than this are filtered out by hardware (software
- * emulation in lirc_dev?)
- */
-#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32)
-/*
- * if filter cannot be set independently for pulse/space, this should
- * be used
- */
-#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32)
-
-/*
- * if enabled from the next key press on the driver will send
- * LIRC_MODE2_FREQUENCY packets
- */
-#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32)
-
-/*
- * to set a range use
- * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
- * lower bound first and later
- * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
- */
-
-#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32)
-#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32)
-
-#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020)
-
-#define LIRC_SETUP_START _IO('i', 0x00000021)
-#define LIRC_SETUP_END _IO('i', 0x00000022)
-
-#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32)
-
-#endif
+#include <uapi/linux/lirc.h>
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index ec921f6..f649470 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -239,6 +239,7 @@ static inline void init_ir_raw_event(struct ir_raw_event *ev)
memset(ev, 0, sizeof(*ev));
}
+#define IR_DEFAULT_TIMEOUT MS_TO_NS(125)
#define IR_MAX_DURATION 500000000 /* 500 ms */
#define US_TO_NS(usec) ((usec) * 1000)
#define MS_TO_US(msec) ((msec) * 1000)
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 7c4bbc4..7844e98 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -33,26 +33,26 @@ enum rc_type {
RC_TYPE_XMP = 18, /* XMP protocol */
};
-#define RC_BIT_NONE 0
-#define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN)
-#define RC_BIT_OTHER (1 << RC_TYPE_OTHER)
-#define RC_BIT_RC5 (1 << RC_TYPE_RC5)
-#define RC_BIT_RC5X (1 << RC_TYPE_RC5X)
-#define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ)
-#define RC_BIT_JVC (1 << RC_TYPE_JVC)
-#define RC_BIT_SONY12 (1 << RC_TYPE_SONY12)
-#define RC_BIT_SONY15 (1 << RC_TYPE_SONY15)
-#define RC_BIT_SONY20 (1 << RC_TYPE_SONY20)
-#define RC_BIT_NEC (1 << RC_TYPE_NEC)
-#define RC_BIT_SANYO (1 << RC_TYPE_SANYO)
-#define RC_BIT_MCE_KBD (1 << RC_TYPE_MCE_KBD)
-#define RC_BIT_RC6_0 (1 << RC_TYPE_RC6_0)
-#define RC_BIT_RC6_6A_20 (1 << RC_TYPE_RC6_6A_20)
-#define RC_BIT_RC6_6A_24 (1 << RC_TYPE_RC6_6A_24)
-#define RC_BIT_RC6_6A_32 (1 << RC_TYPE_RC6_6A_32)
-#define RC_BIT_RC6_MCE (1 << RC_TYPE_RC6_MCE)
-#define RC_BIT_SHARP (1 << RC_TYPE_SHARP)
-#define RC_BIT_XMP (1 << RC_TYPE_XMP)
+#define RC_BIT_NONE 0ULL
+#define RC_BIT_UNKNOWN (1ULL << RC_TYPE_UNKNOWN)
+#define RC_BIT_OTHER (1ULL << RC_TYPE_OTHER)
+#define RC_BIT_RC5 (1ULL << RC_TYPE_RC5)
+#define RC_BIT_RC5X (1ULL << RC_TYPE_RC5X)
+#define RC_BIT_RC5_SZ (1ULL << RC_TYPE_RC5_SZ)
+#define RC_BIT_JVC (1ULL << RC_TYPE_JVC)
+#define RC_BIT_SONY12 (1ULL << RC_TYPE_SONY12)
+#define RC_BIT_SONY15 (1ULL << RC_TYPE_SONY15)
+#define RC_BIT_SONY20 (1ULL << RC_TYPE_SONY20)
+#define RC_BIT_NEC (1ULL << RC_TYPE_NEC)
+#define RC_BIT_SANYO (1ULL << RC_TYPE_SANYO)
+#define RC_BIT_MCE_KBD (1ULL << RC_TYPE_MCE_KBD)
+#define RC_BIT_RC6_0 (1ULL << RC_TYPE_RC6_0)
+#define RC_BIT_RC6_6A_20 (1ULL << RC_TYPE_RC6_6A_20)
+#define RC_BIT_RC6_6A_24 (1ULL << RC_TYPE_RC6_6A_24)
+#define RC_BIT_RC6_6A_32 (1ULL << RC_TYPE_RC6_6A_32)
+#define RC_BIT_RC6_MCE (1ULL << RC_TYPE_RC6_MCE)
+#define RC_BIT_SHARP (1ULL << RC_TYPE_SHARP)
+#define RC_BIT_XMP (1ULL << RC_TYPE_XMP)
#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \
RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h
index 3ef6e3d..2b94662 100644
--- a/include/media/v4l2-clk.h
+++ b/include/media/v4l2-clk.h
@@ -65,7 +65,12 @@ static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id,
return __v4l2_clk_register_fixed(dev_id, rate, THIS_MODULE);
}
+#define V4L2_CLK_NAME_SIZE 64
+
#define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \
"%d-%04x", adap, client)
+#define v4l2_clk_name_of(name, size, of_full_name) snprintf(name, size, \
+ "of-%s", of_full_name)
+
#endif
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h
index a209526..1113c88 100644
--- a/include/media/v4l2-dv-timings.h
+++ b/include/media/v4l2-dv-timings.h
@@ -107,12 +107,14 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t,
* @standard: the timings according to the standard.
* @pclock_delta: maximum delta in Hz between standard->pixelclock and
* the measured timings.
+ * @match_reduced_fps: if true, then fail if V4L2_DV_FL_REDUCED_FPS does not
+ * match.
*
* Returns true if the two timings match, returns false otherwise.
*/
bool v4l2_match_dv_timings(const struct v4l2_dv_timings *measured,
const struct v4l2_dv_timings *standard,
- unsigned pclock_delta);
+ unsigned pclock_delta, bool match_reduced_fps);
/**
* v4l2_print_dv_timings() - log the contents of a dv_timings struct
@@ -183,4 +185,25 @@ bool v4l2_detect_gtf(unsigned frame_height, unsigned hfreq, unsigned vsync,
*/
struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait);
+/*
+ * reduce_fps - check if conditions for reduced fps are true.
+ * bt - v4l2 timing structure
+ * For different timings reduced fps is allowed if following conditions
+ * are met -
+ * For CVT timings: if reduced blanking v2 (vsync == 8) is true.
+ * For CEA861 timings: if V4L2_DV_FL_CAN_REDUCE_FPS flag is true.
+ */
+static inline bool can_reduce_fps(struct v4l2_bt_timings *bt)
+{
+ if ((bt->standards & V4L2_DV_BT_STD_CVT) && (bt->vsync == 8))
+ return true;
+
+ if ((bt->standards & V4L2_DV_BT_STD_CEA861) &&
+ (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS))
+ return true;
+
+ return false;
+}
+
+
#endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 647ebfe..ef03ae5 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -129,6 +129,8 @@ struct vb2_mem_ops {
* @dbuf_mapped: flag to show whether dbuf is mapped or not
* @bytesused: number of bytes occupied by data in the plane (payload)
* @length: size of this plane (NOT the payload) in bytes
+ * @min_length: minimum required size of this plane (NOT the payload) in bytes.
+ * @length is always greater or equal to @min_length.
* @offset: when memory in the associated struct vb2_buffer is
* VB2_MEMORY_MMAP, equals the offset from the start of
* the device memory for this plane (or is a "cookie" that
@@ -150,6 +152,7 @@ struct vb2_plane {
unsigned int dbuf_mapped;
unsigned int bytesused;
unsigned int length;
+ unsigned int min_length;
union {
unsigned int offset;
unsigned long userptr;
@@ -211,6 +214,7 @@ struct vb2_queue;
* @num_planes: number of planes in the buffer
* on an internal driver queue
* @planes: private per-plane information; do not change
+ * @timestamp: frame timestamp in ns
*/
struct vb2_buffer {
struct vb2_queue *vb2_queue;
@@ -219,6 +223,7 @@ struct vb2_buffer {
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VB2_MAX_PLANES];
+ u64 timestamp;
/* private: internal use only
*
@@ -268,21 +273,26 @@ struct vb2_buffer {
* struct vb2_ops - driver-specific callbacks
*
* @queue_setup: called from VIDIOC_REQBUFS and VIDIOC_CREATE_BUFS
- * handlers before memory allocation, or, if
- * *num_planes != 0, after the allocation to verify a
- * smaller number of buffers. Driver should return
- * the required number of buffers in *num_buffers, the
- * required number of planes per buffer in *num_planes; the
- * size of each plane should be set in the sizes[] array
- * and optional per-plane allocator specific context in the
- * alloc_ctxs[] array. When called from VIDIOC_REQBUFS,
- * fmt == NULL, the driver has to use the currently
- * configured format and *num_buffers is the total number
- * of buffers, that are being allocated. When called from
- * VIDIOC_CREATE_BUFS, fmt != NULL and it describes the
- * target frame format (if the format isn't valid the
- * callback must return -EINVAL). In this case *num_buffers
- * are being allocated additionally to q->num_buffers.
+ * handlers before memory allocation. It can be called
+ * twice: if the original number of requested buffers
+ * could not be allocated, then it will be called a
+ * second time with the actually allocated number of
+ * buffers to verify if that is OK.
+ * The driver should return the required number of buffers
+ * in *num_buffers, the required number of planes per
+ * buffer in *num_planes, the size of each plane should be
+ * set in the sizes[] array and optional per-plane
+ * allocator specific context in the alloc_ctxs[] array.
+ * When called from VIDIOC_REQBUFS, *num_planes == 0, the
+ * driver has to use the currently configured format to
+ * determine the plane sizes and *num_buffers is the total
+ * number of buffers that are being allocated. When called
+ * from VIDIOC_CREATE_BUFS, *num_planes != 0 and it
+ * describes the requested number of planes and sizes[]
+ * contains the requested plane sizes. If either
+ * *num_planes or the requested sizes are invalid callback
+ * must return -EINVAL. In this case *num_buffers are
+ * being allocated additionally to q->num_buffers.
* @wait_prepare: release any locks taken while calling vb2 functions;
* it is called before an ioctl needs to wait for a new
* buffer to arrive; required to avoid a deadlock in
@@ -344,7 +354,7 @@ struct vb2_buffer {
* pre-queued buffers before calling STREAMON.
*/
struct vb2_ops {
- int (*queue_setup)(struct vb2_queue *q, const void *parg,
+ int (*queue_setup)(struct vb2_queue *q,
unsigned int *num_buffers, unsigned int *num_planes,
unsigned int sizes[], void *alloc_ctxs[]);
@@ -362,11 +372,22 @@ struct vb2_ops {
void (*buf_queue)(struct vb2_buffer *vb);
};
+/**
+ * struct vb2_ops - driver-specific callbacks
+ *
+ * @fill_user_buffer: given a vb2_buffer fill in the userspace structure.
+ * For V4L2 this is a struct v4l2_buffer.
+ * @fill_vb2_buffer: given a userspace structure, fill in the vb2_buffer.
+ * If the userspace structure is invalid, then this op
+ * will return an error.
+ * @copy_timestamp: copy the timestamp from a userspace structure to
+ * the vb2_buffer struct.
+ */
struct vb2_buf_ops {
- int (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
+ void (*fill_user_buffer)(struct vb2_buffer *vb, void *pb);
int (*fill_vb2_buffer)(struct vb2_buffer *vb, const void *pb,
struct vb2_plane *planes);
- int (*set_timestamp)(struct vb2_buffer *vb, const void *pb);
+ void (*copy_timestamp)(struct vb2_buffer *vb, const void *pb);
};
/**
@@ -429,6 +450,7 @@ struct vb2_buf_ops {
* called since poll() needs to return POLLERR in that situation.
* @is_multiplanar: set if buffer type is multiplanar
* @is_output: set if buffer type is output
+ * @copy_timestamp: set if vb2-core should set timestamps
* @last_buffer_dequeued: used in poll() and DQBUF to immediately return if the
* last decoded buffer was already dequeued. Set for capture queues
* when a buffer with the V4L2_BUF_FLAG_LAST is dequeued.
@@ -470,7 +492,6 @@ struct vb2_queue {
wait_queue_head_t done_wq;
void *alloc_ctx[VB2_MAX_PLANES];
- unsigned int plane_sizes[VB2_MAX_PLANES];
unsigned int streaming:1;
unsigned int start_streaming_called:1;
@@ -478,6 +499,7 @@ struct vb2_queue {
unsigned int waiting_for_buffers:1;
unsigned int is_multiplanar:1;
unsigned int is_output:1;
+ unsigned int copy_timestamp:1;
unsigned int last_buffer_dequeued:1;
struct vb2_fileio_data *fileio;
@@ -503,11 +525,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state);
void vb2_discard_done(struct vb2_queue *q);
int vb2_wait_for_all_buffers(struct vb2_queue *q);
-int vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
+void vb2_core_querybuf(struct vb2_queue *q, unsigned int index, void *pb);
int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
unsigned int *count);
int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
- unsigned int *count, const void *parg);
+ unsigned int *count, unsigned requested_planes,
+ const unsigned int requested_sizes[]);
int vb2_core_prepare_buf(struct vb2_queue *q, unsigned int index, void *pb);
int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb);
int vb2_core_dqbuf(struct vb2_queue *q, void *pb, bool nonblocking);
@@ -531,6 +554,42 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
unsigned long pgoff,
unsigned long flags);
#endif
+unsigned int vb2_core_poll(struct vb2_queue *q, struct file *file,
+ poll_table *wait);
+size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
+ loff_t *ppos, int nonblock);
+size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
+ loff_t *ppos, int nonblock);
+
+/*
+ * vb2_thread_fnc - callback function for use with vb2_thread
+ *
+ * This is called whenever a buffer is dequeued in the thread.
+ */
+typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
+
+/**
+ * vb2_thread_start() - start a thread for the given queue.
+ * @q: videobuf queue
+ * @fnc: callback function
+ * @priv: priv pointer passed to the callback function
+ * @thread_name:the name of the thread. This will be prefixed with "vb2-".
+ *
+ * This starts a thread that will queue and dequeue until an error occurs
+ * or @vb2_thread_stop is called.
+ *
+ * This function should not be used for anything else but the videobuf2-dvb
+ * support. If you think you have another good use-case for this, then please
+ * contact the linux-media mailinglist first.
+ */
+int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
+ const char *thread_name);
+
+/**
+ * vb2_thread_stop() - stop the thread for the given queue.
+ * @q: videobuf queue
+ */
+int vb2_thread_stop(struct vb2_queue *q);
/**
* vb2_is_streaming() - return streaming status of the queue
@@ -635,4 +694,11 @@ static inline void vb2_clear_last_buffer_dequeued(struct vb2_queue *q)
q->last_buffer_dequeued = false;
}
+/*
+ * The following functions are not part of the vb2 core API, but are useful
+ * functions for videobuf2-*.
+ */
+bool vb2_buffer_in_use(struct vb2_queue *q, struct vb2_buffer *vb);
+int vb2_verify_memory_type(struct vb2_queue *q,
+ enum vb2_memory memory, unsigned int type);
#endif /* _MEDIA_VIDEOBUF2_CORE_H */
diff --git a/include/media/videobuf2-v4l2.h b/include/media/videobuf2-v4l2.h
index 5abab1e..3cc836f 100644
--- a/include/media/videobuf2-v4l2.h
+++ b/include/media/videobuf2-v4l2.h
@@ -28,7 +28,6 @@
* @vb2_buf: video buffer 2
* @flags: buffer informational flags
* @field: enum v4l2_field; field order of the image in the buffer
- * @timestamp: frame timestamp
* @timecode: frame timecode
* @sequence: sequence count of this frame
* Should contain enough information to be able to cover all the fields
@@ -39,7 +38,6 @@ struct vb2_v4l2_buffer {
__u32 flags;
__u32 field;
- struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
@@ -65,42 +63,8 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type);
int __must_check vb2_queue_init(struct vb2_queue *q);
void vb2_queue_release(struct vb2_queue *q);
-
-unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait);
-size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
- loff_t *ppos, int nonblock);
-size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
- loff_t *ppos, int nonblock);
-
-/*
- * vb2_thread_fnc - callback function for use with vb2_thread
- *
- * This is called whenever a buffer is dequeued in the thread.
- */
-typedef int (*vb2_thread_fnc)(struct vb2_buffer *vb, void *priv);
-
-/**
- * vb2_thread_start() - start a thread for the given queue.
- * @q: videobuf queue
- * @fnc: callback function
- * @priv: priv pointer passed to the callback function
- * @thread_name:the name of the thread. This will be prefixed with "vb2-".
- *
- * This starts a thread that will queue and dequeue until an error occurs
- * or @vb2_thread_stop is called.
- *
- * This function should not be used for anything else but the videobuf2-dvb
- * support. If you think you have another good use-case for this, then please
- * contact the linux-media mailinglist first.
- */
-int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
- const char *thread_name);
-
-/**
- * vb2_thread_stop() - stop the thread for the given queue.
- * @q: videobuf queue
- */
-int vb2_thread_stop(struct vb2_queue *q);
+unsigned int vb2_poll(struct vb2_queue *q, struct file *file,
+ poll_table *wait);
/*
* The following functions are not part of the vb2 core API, but are simple
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index b36d837..2a91a05 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -62,6 +62,7 @@ struct unix_sock {
#define UNIX_GC_CANDIDATE 0
#define UNIX_GC_MAYBE_CYCLE 1
struct socket_wq peer_wq;
+ wait_queue_t peer_wake;
};
static inline struct unix_sock *unix_sk(const struct sock *sk)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c98afc0..5289929 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -275,6 +275,8 @@ struct l2cap_conn_rsp {
#define L2CAP_CR_AUTHORIZATION 0x0006
#define L2CAP_CR_BAD_KEY_SIZE 0x0007
#define L2CAP_CR_ENCRYPTION 0x0008
+#define L2CAP_CR_INVALID_SCID 0x0009
+#define L2CAP_CR_SCID_IN_USE 0x0010
/* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000
diff --git a/include/net/dst.h b/include/net/dst.h
index 1279f9b..c7329dc 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -322,6 +322,39 @@ static inline void skb_dst_force(struct sk_buff *skb)
}
}
+/**
+ * dst_hold_safe - Take a reference on a dst if possible
+ * @dst: pointer to dst entry
+ *
+ * This helper returns false if it could not safely
+ * take a reference on a dst.
+ */
+static inline bool dst_hold_safe(struct dst_entry *dst)
+{
+ if (dst->flags & DST_NOCACHE)
+ return atomic_inc_not_zero(&dst->__refcnt);
+ dst_hold(dst);
+ return true;
+}
+
+/**
+ * skb_dst_force_safe - makes sure skb dst is refcounted
+ * @skb: buffer
+ *
+ * If dst is not yet refcounted and not destroyed, grab a ref on it.
+ */
+static inline void skb_dst_force_safe(struct sk_buff *skb)
+{
+ if (skb_dst_is_noref(skb)) {
+ struct dst_entry *dst = skb_dst(skb);
+
+ if (!dst_hold_safe(dst))
+ dst = NULL;
+
+ skb->_skb_refdst = (unsigned long)dst;
+ }
+}
+
/**
* __skb_tunnel_rx - prepare skb for rx reinsert
diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h
index ce00971..6816f0f 100644
--- a/include/net/dst_metadata.h
+++ b/include/net/dst_metadata.h
@@ -63,12 +63,13 @@ static inline struct metadata_dst *tun_rx_dst(int md_size)
static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb)
{
struct metadata_dst *md_dst = skb_metadata_dst(skb);
- int md_size = md_dst->u.tun_info.options_len;
+ int md_size;
struct metadata_dst *new_md;
if (!md_dst)
return ERR_PTR(-EINVAL);
+ md_size = md_dst->u.tun_info.options_len;
new_md = metadata_dst_alloc(md_size, GFP_ATOMIC);
if (!new_md)
return ERR_PTR(-ENOMEM);
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index f5bf731..625bdf9 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -210,6 +210,37 @@ struct inet_sock {
#define IP_CMSG_ORIGDSTADDR BIT(6)
#define IP_CMSG_CHECKSUM BIT(7)
+/**
+ * sk_to_full_sk - Access to a full socket
+ * @sk: pointer to a socket
+ *
+ * SYNACK messages might be attached to request sockets.
+ * Some places want to reach the listener in this case.
+ */
+static inline struct sock *sk_to_full_sk(struct sock *sk)
+{
+#ifdef CONFIG_INET
+ if (sk && sk->sk_state == TCP_NEW_SYN_RECV)
+ sk = inet_reqsk(sk)->rsk_listener;
+#endif
+ return sk;
+}
+
+/* sk_to_full_sk() variant with a const argument */
+static inline const struct sock *sk_const_to_full_sk(const struct sock *sk)
+{
+#ifdef CONFIG_INET
+ if (sk && sk->sk_state == TCP_NEW_SYN_RECV)
+ sk = ((const struct request_sock *)sk)->rsk_listener;
+#endif
+ return sk;
+}
+
+static inline struct sock *skb_to_full_sk(const struct sk_buff *skb)
+{
+ return sk_to_full_sk(skb->sk);
+}
+
static inline struct inet_sock *inet_sk(const struct sock *sk)
{
return (struct inet_sock *)sk;
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 4a6009d..235c781 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -78,6 +78,7 @@ void inet_initpeers(void) __init;
static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip)
{
iaddr->a4.addr = ip;
+ iaddr->a4.vif = 0;
iaddr->family = AF_INET;
}
diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h
index aaf9700..fb961a5 100644
--- a/include/net/ip6_fib.h
+++ b/include/net/ip6_fib.h
@@ -167,7 +167,8 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout)
static inline u32 rt6_get_cookie(const struct rt6_info *rt)
{
- if (rt->rt6i_flags & RTF_PCPU || unlikely(rt->dst.flags & DST_NOCACHE))
+ if (rt->rt6i_flags & RTF_PCPU ||
+ (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from))
rt = (struct rt6_info *)(rt->dst.from);
return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0;
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 2bfb2ad..877f682 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -133,27 +133,18 @@ void rt6_clean_tohost(struct net *net, struct in6_addr *gateway);
/*
* Store a destination cache entry in a socket
*/
-static inline void __ip6_dst_store(struct sock *sk, struct dst_entry *dst,
- const struct in6_addr *daddr,
- const struct in6_addr *saddr)
+static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
+ const struct in6_addr *daddr,
+ const struct in6_addr *saddr)
{
struct ipv6_pinfo *np = inet6_sk(sk);
- struct rt6_info *rt = (struct rt6_info *) dst;
+ np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst);
sk_setup_caps(sk, dst);
np->daddr_cache = daddr;
#ifdef CONFIG_IPV6_SUBTREES
np->saddr_cache = saddr;
#endif
- np->dst_cookie = rt6_get_cookie(rt);
-}
-
-static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst,
- struct in6_addr *daddr, struct in6_addr *saddr)
-{
- spin_lock(&sk->sk_dst_lock);
- __ip6_dst_store(sk, dst, daddr, saddr);
- spin_unlock(&sk->sk_dst_lock);
}
static inline bool ipv6_unicast_destination(const struct sk_buff *skb)
diff --git a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h
index aaee6fa..ff788b6 100644
--- a/include/net/ip6_tunnel.h
+++ b/include/net/ip6_tunnel.h
@@ -90,11 +90,12 @@ static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb,
err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb);
if (net_xmit_eval(err) == 0) {
- struct pcpu_sw_netstats *tstats = this_cpu_ptr(dev->tstats);
+ struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats);
u64_stats_update_begin(&tstats->syncp);
tstats->tx_bytes += pkt_len;
tstats->tx_packets++;
u64_stats_update_end(&tstats->syncp);
+ put_cpu_ptr(tstats);
} else {
stats->tx_errors++;
stats->tx_aborted_errors++;
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index f6dafec..62a750a 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -287,12 +287,13 @@ static inline void iptunnel_xmit_stats(int err,
struct pcpu_sw_netstats __percpu *stats)
{
if (err > 0) {
- struct pcpu_sw_netstats *tstats = this_cpu_ptr(stats);
+ struct pcpu_sw_netstats *tstats = get_cpu_ptr(stats);
u64_stats_update_begin(&tstats->syncp);
tstats->tx_bytes += err;
tstats->tx_packets++;
u64_stats_update_end(&tstats->syncp);
+ put_cpu_ptr(tstats);
} else if (err < 0) {
err_stats->tx_errors++;
err_stats->tx_aborted_errors++;
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index e1a10b0..9a5c9f0 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -205,6 +205,7 @@ extern rwlock_t ip6_ra_lock;
*/
struct ipv6_txoptions {
+ atomic_t refcnt;
/* Length of this structure */
int tot_len;
@@ -217,7 +218,7 @@ struct ipv6_txoptions {
struct ipv6_opt_hdr *dst0opt;
struct ipv6_rt_hdr *srcrt; /* Routing Header */
struct ipv6_opt_hdr *dst1opt;
-
+ struct rcu_head rcu;
/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
};
@@ -252,6 +253,24 @@ struct ipv6_fl_socklist {
struct rcu_head rcu;
};
+static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np)
+{
+ struct ipv6_txoptions *opt;
+
+ rcu_read_lock();
+ opt = rcu_dereference(np->opt);
+ if (opt && !atomic_inc_not_zero(&opt->refcnt))
+ opt = NULL;
+ rcu_read_unlock();
+ return opt;
+}
+
+static inline void txopt_put(struct ipv6_txoptions *opt)
+{
+ if (opt && atomic_dec_and_test(&opt->refcnt))
+ kfree_rcu(opt, rcu);
+}
+
struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label);
struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space,
struct ip6_flowlabel *fl,
@@ -490,6 +509,7 @@ struct ip6_create_arg {
u32 user;
const struct in6_addr *src;
const struct in6_addr *dst;
+ int iif;
u8 ecn;
};
diff --git a/include/net/l3mdev.h b/include/net/l3mdev.h
index 774d85b..5689a0c 100644
--- a/include/net/l3mdev.h
+++ b/include/net/l3mdev.h
@@ -29,7 +29,7 @@ struct l3mdev_ops {
/* IPv4 ops */
struct rtable * (*l3mdev_get_rtable)(const struct net_device *dev,
const struct flowi4 *fl4);
- void (*l3mdev_get_saddr)(struct net_device *dev,
+ int (*l3mdev_get_saddr)(struct net_device *dev,
struct flowi4 *fl4);
/* IPv6 ops */
@@ -112,10 +112,11 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
return rc;
}
-static inline void l3mdev_get_saddr(struct net *net, int ifindex,
- struct flowi4 *fl4)
+static inline int l3mdev_get_saddr(struct net *net, int ifindex,
+ struct flowi4 *fl4)
{
struct net_device *dev;
+ int rc = 0;
if (ifindex) {
@@ -124,11 +125,13 @@ static inline void l3mdev_get_saddr(struct net *net, int ifindex,
dev = dev_get_by_index_rcu(net, ifindex);
if (dev && netif_is_l3_master(dev) &&
dev->l3mdev_ops->l3mdev_get_saddr) {
- dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
+ rc = dev->l3mdev_ops->l3mdev_get_saddr(dev, fl4);
}
rcu_read_unlock();
}
+
+ return rc;
}
static inline struct dst_entry *l3mdev_get_rt6_dst(const struct net_device *dev,
@@ -200,9 +203,10 @@ static inline bool netif_index_is_l3_master(struct net *net, int ifindex)
return false;
}
-static inline void l3mdev_get_saddr(struct net *net, int ifindex,
- struct flowi4 *fl4)
+static inline int l3mdev_get_saddr(struct net *net, int ifindex,
+ struct flowi4 *fl4)
{
+ return 0;
}
static inline
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 82045fc..760bc4d 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -2003,8 +2003,10 @@ enum ieee80211_hw_flags {
* it shouldn't be set.
*
* @max_tx_aggregation_subframes: maximum number of subframes in an
- * aggregate an HT driver will transmit, used by the peer as a
- * hint to size its reorder buffer.
+ * aggregate an HT driver will transmit. Though ADDBA will advertise
+ * a constant value of 64 as some older APs can crash if the window
+ * size is smaller (an example is LinkSys WRT120N with FW v1.0.07
+ * build 002 Jun 18 2012).
*
* @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX
* (if %IEEE80211_HW_QUEUE_CONTROL is set)
diff --git a/include/net/ndisc.h b/include/net/ndisc.h
index bf39374..2d8edaa 100644
--- a/include/net/ndisc.h
+++ b/include/net/ndisc.h
@@ -181,8 +181,7 @@ void ndisc_cleanup(void);
int ndisc_rcv(struct sk_buff *skb);
void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
- const struct in6_addr *daddr, const struct in6_addr *saddr,
- struct sk_buff *oskb);
+ const struct in6_addr *daddr, const struct in6_addr *saddr);
void ndisc_send_rs(struct net_device *dev,
const struct in6_addr *saddr, const struct in6_addr *daddr);
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index c9149cc..4bd7508 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -618,6 +618,8 @@ struct nft_expr_ops {
void (*eval)(const struct nft_expr *expr,
struct nft_regs *regs,
const struct nft_pktinfo *pkt);
+ int (*clone)(struct nft_expr *dst,
+ const struct nft_expr *src);
unsigned int size;
int (*init)(const struct nft_ctx *ctx,
@@ -660,10 +662,20 @@ void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr);
int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
const struct nft_expr *expr);
-static inline void nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
+static inline int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src)
{
+ int err;
+
__module_get(src->ops->type->owner);
- memcpy(dst, src, src->ops->size);
+ if (src->ops->clone) {
+ dst->ops = src->ops;
+ err = src->ops->clone(dst, src);
+ if (err < 0)
+ return err;
+ } else {
+ memcpy(dst, src, src->ops->size);
+ }
+ return 0;
}
/**
diff --git a/include/net/route.h b/include/net/route.h
index ee81307..a3b9ef7 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -283,7 +283,12 @@ static inline struct rtable *ip_route_connect(struct flowi4 *fl4,
sport, dport, sk);
if (!src && oif) {
- l3mdev_get_saddr(net, oif, fl4);
+ int rc;
+
+ rc = l3mdev_get_saddr(net, oif, fl4);
+ if (rc < 0)
+ return ERR_PTR(rc);
+
src = fl4->saddr;
}
if (!dst || !src) {
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 4c79ce8..b2a8e63 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -61,6 +61,9 @@ struct Qdisc {
*/
#define TCQ_F_WARN_NONWC (1 << 16)
#define TCQ_F_CPUSTATS 0x20 /* run using percpu statistics */
+#define TCQ_F_NOPARENT 0x40 /* root of its hierarchy :
+ * qdisc_tree_decrease_qlen() should stop.
+ */
u32 limit;
const struct Qdisc_ops *ops;
struct qdisc_size_table __rcu *stab;
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 495c87e..eea9bde 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -775,10 +775,10 @@ struct sctp_transport {
hb_sent:1,
/* Is the Path MTU update pending on this tranport */
- pmtu_pending:1;
+ pmtu_pending:1,
- /* Has this transport moved the ctsn since we last sacked */
- __u32 sack_generation;
+ /* Has this transport moved the ctsn since we last sacked */
+ sack_generation:1;
u32 dst_cookie;
struct flowi fl;
@@ -1482,19 +1482,20 @@ struct sctp_association {
prsctp_capable:1, /* Can peer do PR-SCTP? */
auth_capable:1; /* Is peer doing SCTP-AUTH? */
- /* Ack State : This flag indicates if the next received
+ /* sack_needed : This flag indicates if the next received
* : packet is to be responded to with a
- * : SACK. This is initializedto 0. When a packet
- * : is received it is incremented. If this value
+ * : SACK. This is initialized to 0. When a packet
+ * : is received sack_cnt is incremented. If this value
* : reaches 2 or more, a SACK is sent and the
* : value is reset to 0. Note: This is used only
* : when no DATA chunks are received out of
* : order. When DATA chunks are out of order,
* : SACK's are not delayed (see Section 6).
*/
- __u8 sack_needed; /* Do we need to sack the peer? */
+ __u8 sack_needed:1, /* Do we need to sack the peer? */
+ sack_generation:1,
+ zero_window_announced:1;
__u32 sack_cnt;
- __u32 sack_generation;
__u32 adaptation_ind; /* Adaptation Code point. */
diff --git a/include/net/sock.h b/include/net/sock.h
index bbf7c2c..14d3c07 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -254,7 +254,6 @@ struct cg_proto;
* @sk_wq: sock wait queue and async head
* @sk_rx_dst: receive input route used by early demux
* @sk_dst_cache: destination cache
- * @sk_dst_lock: destination cache lock
* @sk_policy: flow policy
* @sk_receive_queue: incoming packets
* @sk_wmem_alloc: transmit queue bytes committed
@@ -384,14 +383,16 @@ struct sock {
int sk_rcvbuf;
struct sk_filter __rcu *sk_filter;
- struct socket_wq __rcu *sk_wq;
-
+ union {
+ struct socket_wq __rcu *sk_wq;
+ struct socket_wq *sk_wq_raw;
+ };
#ifdef CONFIG_XFRM
- struct xfrm_policy *sk_policy[2];
+ struct xfrm_policy __rcu *sk_policy[2];
#endif
struct dst_entry *sk_rx_dst;
struct dst_entry __rcu *sk_dst_cache;
- spinlock_t sk_dst_lock;
+ /* Note: 32bit hole on 64bit arches */
atomic_t sk_wmem_alloc;
atomic_t sk_omem_alloc;
int sk_sndbuf;
@@ -403,6 +404,7 @@ struct sock {
sk_userlocks : 4,
sk_protocol : 8,
sk_type : 16;
+#define SK_PROTOCOL_MAX U8_MAX
kmemcheck_bitfield_end(flags);
int sk_wmem_queued;
gfp_t sk_allocation;
@@ -739,6 +741,8 @@ enum sock_flags {
SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */
};
+#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
+
static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
{
nsk->sk_flags = osk->sk_flags;
@@ -813,7 +817,7 @@ void sk_stream_write_space(struct sock *sk);
static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb)
{
/* dont let skb dst not refcounted, we are going to leave rcu lock */
- skb_dst_force(skb);
+ skb_dst_force_safe(skb);
if (!sk->sk_backlog.tail)
sk->sk_backlog.head = skb;
@@ -2005,10 +2009,27 @@ static inline unsigned long sock_wspace(struct sock *sk)
return amt;
}
-static inline void sk_wake_async(struct sock *sk, int how, int band)
+/* Note:
+ * We use sk->sk_wq_raw, from contexts knowing this
+ * pointer is not NULL and cannot disappear/change.
+ */
+static inline void sk_set_bit(int nr, struct sock *sk)
+{
+ set_bit(nr, &sk->sk_wq_raw->flags);
+}
+
+static inline void sk_clear_bit(int nr, struct sock *sk)
+{
+ clear_bit(nr, &sk->sk_wq_raw->flags);
+}
+
+static inline void sk_wake_async(const struct sock *sk, int how, int band)
{
- if (sock_flag(sk, SOCK_FASYNC))
- sock_wake_async(sk->sk_socket, how, band);
+ if (sock_flag(sk, SOCK_FASYNC)) {
+ rcu_read_lock();
+ sock_wake_async(rcu_dereference(sk->sk_wq), how, band);
+ rcu_read_unlock();
+ }
}
/* Since sk_{r,w}mem_alloc sums skb->truesize, even a small frame might
@@ -2226,6 +2247,31 @@ static inline bool sk_listener(const struct sock *sk)
return (1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV);
}
+/**
+ * sk_state_load - read sk->sk_state for lockless contexts
+ * @sk: socket pointer
+ *
+ * Paired with sk_state_store(). Used in places we do not hold socket lock :
+ * tcp_diag_get_info(), tcp_get_info(), tcp_poll(), get_tcp4_sock() ...
+ */
+static inline int sk_state_load(const struct sock *sk)
+{
+ return smp_load_acquire(&sk->sk_state);
+}
+
+/**
+ * sk_state_store - update sk->sk_state
+ * @sk: socket pointer
+ * @newstate: new state
+ *
+ * Paired with sk_state_load(). Should be used in contexts where
+ * state change might impact lockless readers.
+ */
+static inline void sk_state_store(struct sock *sk, int newstate)
+{
+ smp_store_release(&sk->sk_state, newstate);
+}
+
void sock_enable_timestamp(struct sock *sk, int flag);
int sock_get_timestamp(struct sock *, struct timeval __user *);
int sock_get_timestampns(struct sock *, struct timespec __user *);
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index bc865e2..1d22ce9 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -323,7 +323,7 @@ static inline int switchdev_port_fdb_dump(struct sk_buff *skb,
struct net_device *filter_dev,
int idx)
{
- return -EOPNOTSUPP;
+ return idx;
}
static inline void switchdev_port_fwd_mark_set(struct net_device *dev,
diff --git a/include/net/vxlan.h b/include/net/vxlan.h
index c1c899c..e289ada 100644
--- a/include/net/vxlan.h
+++ b/include/net/vxlan.h
@@ -79,7 +79,7 @@ struct vxlanhdr {
};
/* VXLAN header flags. */
-#define VXLAN_HF_RCO BIT(24)
+#define VXLAN_HF_RCO BIT(21)
#define VXLAN_HF_VNI BIT(27)
#define VXLAN_HF_GBP BIT(31)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 4a9c21f..d6f6e50 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -548,6 +548,7 @@ struct xfrm_policy {
u16 family;
struct xfrm_sec_ctx *security;
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
+ struct rcu_head rcu;
};
static inline struct net *xp_net(const struct xfrm_policy *xp)
@@ -1141,12 +1142,14 @@ static inline int xfrm6_route_forward(struct sk_buff *skb)
return xfrm_route_forward(skb, AF_INET6);
}
-int __xfrm_sk_clone_policy(struct sock *sk);
+int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk);
-static inline int xfrm_sk_clone_policy(struct sock *sk)
+static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
{
- if (unlikely(sk->sk_policy[0] || sk->sk_policy[1]))
- return __xfrm_sk_clone_policy(sk);
+ sk->sk_policy[0] = NULL;
+ sk->sk_policy[1] = NULL;
+ if (unlikely(osk->sk_policy[0] || osk->sk_policy[1]))
+ return __xfrm_sk_clone_policy(sk, osk);
return 0;
}
@@ -1154,12 +1157,16 @@ int xfrm_policy_delete(struct xfrm_policy *pol, int dir);
static inline void xfrm_sk_free_policy(struct sock *sk)
{
- if (unlikely(sk->sk_policy[0] != NULL)) {
- xfrm_policy_delete(sk->sk_policy[0], XFRM_POLICY_MAX);
+ struct xfrm_policy *pol;
+
+ pol = rcu_dereference_protected(sk->sk_policy[0], 1);
+ if (unlikely(pol != NULL)) {
+ xfrm_policy_delete(pol, XFRM_POLICY_MAX);
sk->sk_policy[0] = NULL;
}
- if (unlikely(sk->sk_policy[1] != NULL)) {
- xfrm_policy_delete(sk->sk_policy[1], XFRM_POLICY_MAX+1);
+ pol = rcu_dereference_protected(sk->sk_policy[1], 1);
+ if (unlikely(pol != NULL)) {
+ xfrm_policy_delete(pol, XFRM_POLICY_MAX+1);
sk->sk_policy[1] = NULL;
}
}
@@ -1169,7 +1176,7 @@ void xfrm_garbage_collect(struct net *net);
#else
static inline void xfrm_sk_free_policy(struct sock *sk) {}
-static inline int xfrm_sk_clone_policy(struct sock *sk) { return 0; }
+static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) { return 0; }
static inline int xfrm6_route_forward(struct sk_buff *skb) { return 1; }
static inline int xfrm4_route_forward(struct sk_buff *skb) { return 1; }
static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h
index 188df91..ec9b44d 100644
--- a/include/rdma/ib_mad.h
+++ b/include/rdma/ib_mad.h
@@ -237,6 +237,8 @@ struct ib_vendor_mad {
u8 data[IB_MGMT_VENDOR_DATA];
};
+#define IB_MGMT_CLASSPORTINFO_ATTR_ID cpu_to_be16(0x0001)
+
struct ib_class_port_info {
u8 base_version;
u8 class_version;
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 9a68a19..120da1d 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1271,6 +1271,7 @@ struct ib_uobject {
int id; /* index into kernel idr */
struct kref ref;
struct rw_semaphore mutex; /* protects .live */
+ struct rcu_head rcu; /* kfree_rcu() overhead */
int live;
};
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index e113c75..fcfa3d7 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -406,11 +406,6 @@ struct scsi_host_template {
int tag_alloc_policy;
/*
- * Let the block layer assigns tags to all commands.
- */
- unsigned use_blk_tags:1;
-
- /*
* Track QUEUE_FULL events and reduce queue depth on demand.
*/
unsigned track_queue_depth:1;
@@ -673,6 +668,9 @@ struct Scsi_Host {
unsigned use_blk_mq:1;
unsigned use_cmd_list:1;
+ /* Host responded with short (<36 bytes) INQUIRY result */
+ unsigned short_inquiry:1;
+
/*
* Optional work queue to be utilized by the transport
*/
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
index b27977e..4416b10 100644
--- a/include/scsi/scsi_tcq.h
+++ b/include/scsi/scsi_tcq.h
@@ -10,91 +10,36 @@
#ifdef CONFIG_BLOCK
-static inline struct scsi_cmnd *scsi_mq_find_tag(struct Scsi_Host *shost,
- int unique_tag)
-{
- u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
- struct request *req = NULL;
-
- if (hwq < shost->tag_set.nr_hw_queues)
- req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq],
- blk_mq_unique_tag_to_tag(unique_tag));
- return req ? (struct scsi_cmnd *)req->special : NULL;
-}
-
-/**
- * scsi_find_tag - find a tagged command by device
- * @SDpnt: pointer to the ScSI device
- * @tag: tag generated by blk_mq_unique_tag()
- *
- * Notes:
- * Only works with tags allocated by the generic blk layer.
- **/
-static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
-{
- struct request *req;
-
- if (tag != SCSI_NO_TAG) {
- if (shost_use_blk_mq(sdev->host))
- return scsi_mq_find_tag(sdev->host, tag);
-
- req = blk_queue_find_tag(sdev->request_queue, tag);
- return req ? (struct scsi_cmnd *)req->special : NULL;
- }
-
- /* single command, look in space */
- return sdev->current_cmnd;
-}
-
-
-/**
- * scsi_init_shared_tag_map - create a shared tag map
- * @shost: the host to share the tag map among all devices
- * @depth: the total depth of the map
- */
-static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
-{
- /*
- * We always have a shared tag map around when using blk-mq.
- */
- if (shost_use_blk_mq(shost))
- return 0;
-
- /*
- * If the shared tag map isn't already initialized, do it now.
- * This saves callers from having to check ->bqt when setting up
- * devices on the shared host (for libata)
- */
- if (!shost->bqt) {
- shost->bqt = blk_init_tags(depth,
- shost->hostt->tag_alloc_policy);
- if (!shost->bqt)
- return -ENOMEM;
- }
-
- return 0;
-}
-
/**
* scsi_host_find_tag - find the tagged command by host
* @shost: pointer to scsi_host
- * @tag: tag generated by blk_mq_unique_tag()
+ * @tag: tag
*
- * Notes:
- * Only works with tags allocated by the generic blk layer.
+ * Note: for devices using multiple hardware queues tag must have been
+ * generated by blk_mq_unique_tag().
**/
static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
- int tag)
+ int tag)
{
- struct request *req;
+ struct request *req = NULL;
- if (tag != SCSI_NO_TAG) {
- if (shost_use_blk_mq(shost))
- return scsi_mq_find_tag(shost, tag);
+ if (tag == SCSI_NO_TAG)
+ return NULL;
+
+ if (shost_use_blk_mq(shost)) {
+ u16 hwq = blk_mq_unique_tag_to_hwq(tag);
+
+ if (hwq < shost->tag_set.nr_hw_queues) {
+ req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq],
+ blk_mq_unique_tag_to_tag(tag));
+ }
+ } else {
req = blk_map_queue_find_tag(shost->bqt, tag);
- return req ? (struct scsi_cmnd *)req->special : NULL;
}
- return NULL;
+
+ if (!req)
+ return NULL;
+ return req->special;
}
#endif /* CONFIG_BLOCK */
diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h
new file mode 100644
index 0000000..c07d74a
--- /dev/null
+++ b/include/soc/bcm2835/raspberrypi-firmware.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright © 2015 Broadcom
+ *
+ * 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 __SOC_RASPBERRY_FIRMWARE_H__
+#define __SOC_RASPBERRY_FIRMWARE_H__
+
+#include <linux/types.h>
+#include <linux/of_device.h>
+
+struct rpi_firmware;
+
+enum rpi_firmware_property_status {
+ RPI_FIRMWARE_STATUS_REQUEST = 0,
+ RPI_FIRMWARE_STATUS_SUCCESS = 0x80000000,
+ RPI_FIRMWARE_STATUS_ERROR = 0x80000001,
+};
+
+/**
+ * struct rpi_firmware_property_tag_header - Firmware property tag header
+ * @tag: One of enum_mbox_property_tag.
+ * @buf_size: The number of bytes in the value buffer following this
+ * struct.
+ * @req_resp_size: On submit, the length of the request (though it doesn't
+ * appear to be currently used by the firmware). On return,
+ * the length of the response (always 4 byte aligned), with
+ * the low bit set.
+ */
+struct rpi_firmware_property_tag_header {
+ u32 tag;
+ u32 buf_size;
+ u32 req_resp_size;
+};
+
+enum rpi_firmware_property_tag {
+ RPI_FIRMWARE_PROPERTY_END = 0,
+ RPI_FIRMWARE_GET_FIRMWARE_REVISION = 0x00000001,
+
+ RPI_FIRMWARE_SET_CURSOR_INFO = 0x00008010,
+ RPI_FIRMWARE_SET_CURSOR_STATE = 0x00008011,
+
+ RPI_FIRMWARE_GET_BOARD_MODEL = 0x00010001,
+ RPI_FIRMWARE_GET_BOARD_REVISION = 0x00010002,
+ RPI_FIRMWARE_GET_BOARD_MAC_ADDRESS = 0x00010003,
+ RPI_FIRMWARE_GET_BOARD_SERIAL = 0x00010004,
+ RPI_FIRMWARE_GET_ARM_MEMORY = 0x00010005,
+ RPI_FIRMWARE_GET_VC_MEMORY = 0x00010006,
+ RPI_FIRMWARE_GET_CLOCKS = 0x00010007,
+ RPI_FIRMWARE_GET_POWER_STATE = 0x00020001,
+ RPI_FIRMWARE_GET_TIMING = 0x00020002,
+ RPI_FIRMWARE_SET_POWER_STATE = 0x00028001,
+ RPI_FIRMWARE_GET_CLOCK_STATE = 0x00030001,
+ RPI_FIRMWARE_GET_CLOCK_RATE = 0x00030002,
+ RPI_FIRMWARE_GET_VOLTAGE = 0x00030003,
+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE = 0x00030004,
+ RPI_FIRMWARE_GET_MAX_VOLTAGE = 0x00030005,
+ RPI_FIRMWARE_GET_TEMPERATURE = 0x00030006,
+ RPI_FIRMWARE_GET_MIN_CLOCK_RATE = 0x00030007,
+ RPI_FIRMWARE_GET_MIN_VOLTAGE = 0x00030008,
+ RPI_FIRMWARE_GET_TURBO = 0x00030009,
+ RPI_FIRMWARE_GET_MAX_TEMPERATURE = 0x0003000a,
+ RPI_FIRMWARE_ALLOCATE_MEMORY = 0x0003000c,
+ RPI_FIRMWARE_LOCK_MEMORY = 0x0003000d,
+ RPI_FIRMWARE_UNLOCK_MEMORY = 0x0003000e,
+ RPI_FIRMWARE_RELEASE_MEMORY = 0x0003000f,
+ RPI_FIRMWARE_EXECUTE_CODE = 0x00030010,
+ RPI_FIRMWARE_EXECUTE_QPU = 0x00030011,
+ RPI_FIRMWARE_SET_ENABLE_QPU = 0x00030012,
+ RPI_FIRMWARE_GET_DISPMANX_RESOURCE_MEM_HANDLE = 0x00030014,
+ RPI_FIRMWARE_GET_EDID_BLOCK = 0x00030020,
+ RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001,
+ RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002,
+ RPI_FIRMWARE_SET_VOLTAGE = 0x00038003,
+ RPI_FIRMWARE_SET_TURBO = 0x00038009,
+
+ /* Dispmanx TAGS */
+ RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001,
+ RPI_FIRMWARE_FRAMEBUFFER_BLANK = 0x00040002,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT = 0x00040003,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT = 0x00040004,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_DEPTH = 0x00040005,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PIXEL_ORDER = 0x00040006,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_ALPHA_MODE = 0x00040007,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PITCH = 0x00040008,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_VIRTUAL_OFFSET = 0x00040009,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_OVERSCAN = 0x0004000a,
+ RPI_FIRMWARE_FRAMEBUFFER_GET_PALETTE = 0x0004000b,
+ RPI_FIRMWARE_FRAMEBUFFER_RELEASE = 0x00048001,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT = 0x00044003,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT = 0x00044004,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_DEPTH = 0x00044005,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PIXEL_ORDER = 0x00044006,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_ALPHA_MODE = 0x00044007,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_VIRTUAL_OFFSET = 0x00044009,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_OVERSCAN = 0x0004400a,
+ RPI_FIRMWARE_FRAMEBUFFER_TEST_PALETTE = 0x0004400b,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT = 0x00048003,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT = 0x00048004,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_DEPTH = 0x00048005,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PIXEL_ORDER = 0x00048006,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_ALPHA_MODE = 0x00048007,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_VIRTUAL_OFFSET = 0x00048009,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_OVERSCAN = 0x0004800a,
+ RPI_FIRMWARE_FRAMEBUFFER_SET_PALETTE = 0x0004800b,
+
+ RPI_FIRMWARE_GET_COMMAND_LINE = 0x00050001,
+ RPI_FIRMWARE_GET_DMA_CHANNELS = 0x00060001,
+};
+
+int rpi_firmware_property(struct rpi_firmware *fw,
+ u32 tag, void *data, size_t len);
+int rpi_firmware_property_list(struct rpi_firmware *fw,
+ void *data, size_t tag_size);
+struct rpi_firmware *rpi_firmware_get(struct device_node *firmware_node);
+
+#endif /* __SOC_RASPBERRY_FIRMWARE_H__ */
diff --git a/include/soc/brcmstb/common.h b/include/soc/brcmstb/common.h
new file mode 100644
index 0000000..cfb5335
--- /dev/null
+++ b/include/soc/brcmstb/common.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright © 2014 NVIDIA Corporation
+ * Copyright © 2015 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __SOC_BRCMSTB_COMMON_H__
+#define __SOC_BRCMSTB_COMMON_H__
+
+bool soc_is_brcmstb(void);
+
+#endif /* __SOC_BRCMSTB_COMMON_H__ */
diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h
index 2ae8812..94dc6a9 100644
--- a/include/sound/hda_register.h
+++ b/include/sound/hda_register.h
@@ -93,6 +93,9 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_REG_HSW_EM4 0x100c
#define AZX_REG_HSW_EM5 0x1010
+/* Skylake/Broxton display HD-A controller Extended Mode registers */
+#define AZX_REG_SKL_EM4L 0x1040
+
/* PCI space */
#define AZX_PCIREG_TCSEL 0x44
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 7855cfe..95a937e 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -398,6 +398,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w);
+void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm);
/* dapm events */
void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream,
diff --git a/include/sound/soc.h b/include/sound/soc.h
index a8b4b9c..fb955e6 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1655,7 +1655,7 @@ extern const struct dev_pm_ops snd_soc_pm_ops;
/* Helper functions */
static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm)
{
- mutex_lock(&dapm->card->dapm_mutex);
+ mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
}
static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm)
diff --git a/include/target/configfs_macros.h b/include/target/configfs_macros.h
deleted file mode 100644
index a0fc85b..0000000
--- a/include/target/configfs_macros.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; -*-
- * vim: noexpandtab sw=8 ts=8 sts=0:
- *
- * configfs_macros.h - extends macros for configfs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 021110-1307, USA.
- *
- * Based on sysfs:
- * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
- *
- * Based on kobject.h:
- * Copyright (c) 2002-2003 Patrick Mochel
- * Copyright (c) 2002-2003 Open Source Development Labs
- *
- * configfs Copyright (C) 2005 Oracle. All rights reserved.
- *
- * Added CONFIGFS_EATTR() macros from original configfs.h macros
- * Copright (C) 2008-2009 Nicholas A. Bellinger <nab@linux-iscsi.org>
- *
- * Please read Documentation/filesystems/configfs/configfs.txt before using
- * the configfs interface, ESPECIALLY the parts about reference counts and
- * item destructors.
- */
-
-#ifndef _CONFIGFS_MACROS_H_
-#define _CONFIGFS_MACROS_H_
-
-#include <linux/configfs.h>
-
-/*
- * Users often need to create attribute structures for their configurable
- * attributes, containing a configfs_attribute member and function pointers
- * for the show() and store() operations on that attribute. If they don't
- * need anything else on the extended attribute structure, they can use
- * this macro to define it. The argument _name isends up as
- * 'struct _name_attribute, as well as names of to CONFIGFS_ATTR_OPS() below.
- * The argument _item is the name of the structure containing the
- * struct config_item or struct config_group structure members
- */
-#define CONFIGFS_EATTR_STRUCT(_name, _item) \
-struct _name##_attribute { \
- struct configfs_attribute attr; \
- ssize_t (*show)(struct _item *, char *); \
- ssize_t (*store)(struct _item *, const char *, size_t); \
-}
-
-/*
- * With the extended attribute structure, users can use this macro
- * (similar to sysfs' __ATTR) to make defining attributes easier.
- * An example:
- * #define MYITEM_EATTR(_name, _mode, _show, _store) \
- * struct myitem_attribute childless_attr_##_name = \
- * __CONFIGFS_EATTR(_name, _mode, _show, _store)
- */
-#define __CONFIGFS_EATTR(_name, _mode, _show, _store) \
-{ \
- .attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = _mode, \
- .ca_owner = THIS_MODULE, \
- }, \
- .show = _show, \
- .store = _store, \
-}
-/* Here is a readonly version, only requiring a show() operation */
-#define __CONFIGFS_EATTR_RO(_name, _show) \
-{ \
- .attr = { \
- .ca_name = __stringify(_name), \
- .ca_mode = 0444, \
- .ca_owner = THIS_MODULE, \
- }, \
- .show = _show, \
-}
-
-/*
- * With these extended attributes, the simple show_attribute() and
- * store_attribute() operations need to call the show() and store() of the
- * attributes. This is a common pattern, so we provide a macro to define
- * them. The argument _name is the name of the attribute defined by
- * CONFIGFS_ATTR_STRUCT(). The argument _item is the name of the structure
- * containing the struct config_item or struct config_group structure member.
- * The argument _item_member is the actual name of the struct config_* struct
- * in your _item structure. Meaning my_structure->some_config_group.
- * ^^_item^^^^^ ^^_item_member^^^
- * This macro expects the attributes to be named "struct <name>_attribute".
- */
-#define CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member) \
-static struct _item *to_##_name(struct config_item *ci) \
-{ \
- return (ci) ? container_of(to_config_group(ci), struct _item, \
- _item_member) : NULL; \
-}
-
-#define CONFIGFS_EATTR_OPS_SHOW(_name, _item) \
-static ssize_t _name##_attr_show(struct config_item *item, \
- struct configfs_attribute *attr, \
- char *page) \
-{ \
- struct _item *_item = to_##_name(item); \
- struct _name##_attribute * _name##_attr = \
- container_of(attr, struct _name##_attribute, attr); \
- ssize_t ret = 0; \
- \
- if (_name##_attr->show) \
- ret = _name##_attr->show(_item, page); \
- return ret; \
-}
-
-#define CONFIGFS_EATTR_OPS_STORE(_name, _item) \
-static ssize_t _name##_attr_store(struct config_item *item, \
- struct configfs_attribute *attr, \
- const char *page, size_t count) \
-{ \
- struct _item *_item = to_##_name(item); \
- struct _name##_attribute * _name##_attr = \
- container_of(attr, struct _name##_attribute, attr); \
- ssize_t ret = -EINVAL; \
- \
- if (_name##_attr->store) \
- ret = _name##_attr->store(_item, page, count); \
- return ret; \
-}
-
-#define CONFIGFS_EATTR_OPS(_name, _item, _item_member) \
- CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \
- CONFIGFS_EATTR_OPS_SHOW(_name, _item); \
- CONFIGFS_EATTR_OPS_STORE(_name, _item);
-
-#define CONFIGFS_EATTR_OPS_RO(_name, _item, _item_member) \
- CONFIGFS_EATTR_OPS_TO_FUNC(_name, _item, _item_member); \
- CONFIGFS_EATTR_OPS_SHOW(_name, _item);
-
-#endif /* _CONFIGFS_MACROS_H_ */
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 5f48754..aabf0ac 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -474,7 +474,7 @@ struct se_cmd {
struct completion cmd_wait_comp;
const struct target_core_fabric_ops *se_tfo;
sense_reason_t (*execute_cmd)(struct se_cmd *);
- sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool);
+ sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool, int *);
void *protocol_data;
unsigned char *t_task_cdb;
@@ -563,6 +563,36 @@ struct se_node_acl {
struct kref acl_kref;
};
+static inline struct se_node_acl *acl_to_nacl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_node_acl,
+ acl_group);
+}
+
+static inline struct se_node_acl *attrib_to_nacl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_node_acl,
+ acl_attrib_group);
+}
+
+static inline struct se_node_acl *auth_to_nacl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_node_acl,
+ acl_auth_group);
+}
+
+static inline struct se_node_acl *param_to_nacl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_node_acl,
+ acl_param_group);
+}
+
+static inline struct se_node_acl *fabric_stat_to_nacl(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_node_acl,
+ acl_fabric_stat_group);
+}
+
struct se_session {
unsigned sess_tearing_down:1;
u64 sess_bin_isid;
@@ -821,6 +851,12 @@ struct se_tpg_np {
struct config_group tpg_np_group;
};
+static inline struct se_tpg_np *to_tpg_np(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_tpg_np,
+ tpg_np_group);
+}
+
struct se_portal_group {
/*
* PROTOCOL IDENTIFIER value per SPC4, 7.5.1.
@@ -857,6 +893,30 @@ struct se_portal_group {
struct config_group tpg_param_group;
};
+static inline struct se_portal_group *to_tpg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_portal_group,
+ tpg_group);
+}
+
+static inline struct se_portal_group *attrib_to_tpg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_portal_group,
+ tpg_attrib_group);
+}
+
+static inline struct se_portal_group *auth_to_tpg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_portal_group,
+ tpg_auth_group);
+}
+
+static inline struct se_portal_group *param_to_tpg(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct se_portal_group,
+ tpg_param_group);
+}
+
struct se_wwn {
struct target_fabric_configfs *wwn_tf;
struct config_group wwn_group;
diff --git a/include/target/target_core_fabric_configfs.h b/include/target/target_core_fabric_configfs.h
deleted file mode 100644
index 7a0649c..0000000
--- a/include/target/target_core_fabric_configfs.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Used for tfc_wwn_cit attributes
- */
-
-#include <target/configfs_macros.h>
-
-CONFIGFS_EATTR_STRUCT(target_fabric_nacl_attrib, se_node_acl);
-#define TF_NACL_ATTRIB_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_nacl_attrib_attribute _fabric##_nacl_attrib_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_nacl_attrib_show_##_name, \
- _fabric##_nacl_attrib_store_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_nacl_auth, se_node_acl);
-#define TF_NACL_AUTH_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_nacl_auth_show_##_name, \
- _fabric##_nacl_auth_store_##_name);
-
-#define TF_NACL_AUTH_ATTR_RO(_fabric, _name) \
-static struct target_fabric_nacl_auth_attribute _fabric##_nacl_auth_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_nacl_auth_show_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_nacl_param, se_node_acl);
-#define TF_NACL_PARAM_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_nacl_param_show_##_name, \
- _fabric##_nacl_param_store_##_name);
-
-#define TF_NACL_PARAM_ATTR_RO(_fabric, _name) \
-static struct target_fabric_nacl_param_attribute _fabric##_nacl_param_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_nacl_param_show_##_name);
-
-
-CONFIGFS_EATTR_STRUCT(target_fabric_nacl_base, se_node_acl);
-#define TF_NACL_BASE_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_nacl_show_##_name, \
- _fabric##_nacl_store_##_name);
-
-#define TF_NACL_BASE_ATTR_RO(_fabric, _name) \
-static struct target_fabric_nacl_base_attribute _fabric##_nacl_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_nacl_show_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_np_base, se_tpg_np);
-#define TF_NP_BASE_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_np_base_attribute _fabric##_np_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_np_show_##_name, \
- _fabric##_np_store_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_tpg_attrib, se_portal_group);
-#define TF_TPG_ATTRIB_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_tpg_attrib_attribute _fabric##_tpg_attrib_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_tpg_attrib_show_##_name, \
- _fabric##_tpg_attrib_store_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_tpg_auth, se_portal_group);
-#define TF_TPG_AUTH_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_tpg_auth_attribute _fabric##_tpg_auth_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_tpg_auth_show_##_name, \
- _fabric##_tpg_auth_store_##_name);
-
-#define TF_TPG_AUTH_ATTR_RO(_fabric, _name) \
-static struct target_fabric_tpg_auth_attribute _fabric##_tpg_auth_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_tpg_auth_show_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_tpg_param, se_portal_group);
-#define TF_TPG_PARAM_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_tpg_param_attribute _fabric##_tpg_param_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_tpg_param_show_##_name, \
- _fabric##_tpg_param_store_##_name);
-
-
-CONFIGFS_EATTR_STRUCT(target_fabric_tpg, se_portal_group);
-#define TF_TPG_BASE_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_tpg_show_##_name, \
- _fabric##_tpg_store_##_name);
-
-
-#define TF_TPG_BASE_ATTR_RO(_fabric, _name) \
-static struct target_fabric_tpg_attribute _fabric##_tpg_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_tpg_show_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_wwn, target_fabric_configfs);
-#define TF_WWN_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_wwn_show_attr_##_name, \
- _fabric##_wwn_store_attr_##_name);
-
-#define TF_WWN_ATTR_RO(_fabric, _name) \
-static struct target_fabric_wwn_attribute _fabric##_wwn_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_wwn_show_attr_##_name);
-
-CONFIGFS_EATTR_STRUCT(target_fabric_discovery, target_fabric_configfs);
-#define TF_DISC_ATTR(_fabric, _name, _mode) \
-static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \
- __CONFIGFS_EATTR(_name, _mode, \
- _fabric##_disc_show_##_name, \
- _fabric##_disc_store_##_name);
-
-#define TF_DISC_ATTR_RO(_fabric, _name) \
-static struct target_fabric_discovery_attribute _fabric##_disc_##_name = \
- __CONFIGFS_EATTR_RO(_name, \
- _fabric##_disc_show_##_name);
-
-extern int target_fabric_setup_cits(struct target_fabric_configfs *);
diff --git a/include/trace/events/filelock.h b/include/trace/events/filelock.h
index c72f2dc..63a7680 100644
--- a/include/trace/events/filelock.h
+++ b/include/trace/events/filelock.h
@@ -34,6 +34,83 @@
{ F_WRLCK, "F_WRLCK" }, \
{ F_UNLCK, "F_UNLCK" })
+TRACE_EVENT(locks_get_lock_context,
+ TP_PROTO(struct inode *inode, int type, struct file_lock_context *ctx),
+
+ TP_ARGS(inode, type, ctx),
+
+ TP_STRUCT__entry(
+ __field(unsigned long, i_ino)
+ __field(dev_t, s_dev)
+ __field(unsigned char, type)
+ __field(struct file_lock_context *, ctx)
+ ),
+
+ TP_fast_assign(
+ __entry->s_dev = inode->i_sb->s_dev;
+ __entry->i_ino = inode->i_ino;
+ __entry->type = type;
+ __entry->ctx = ctx;
+ ),
+
+ TP_printk("dev=0x%x:0x%x ino=0x%lx type=%s ctx=%p",
+ MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
+ __entry->i_ino, show_fl_type(__entry->type), __entry->ctx)
+);
+
+DECLARE_EVENT_CLASS(filelock_lock,
+ TP_PROTO(struct inode *inode, struct file_lock *fl, int ret),
+
+ TP_ARGS(inode, fl, ret),
+
+ TP_STRUCT__entry(
+ __field(struct file_lock *, fl)
+ __field(unsigned long, i_ino)
+ __field(dev_t, s_dev)
+ __field(struct file_lock *, fl_next)
+ __field(fl_owner_t, fl_owner)
+ __field(unsigned int, fl_pid)
+ __field(unsigned int, fl_flags)
+ __field(unsigned char, fl_type)
+ __field(loff_t, fl_start)
+ __field(loff_t, fl_end)
+ __field(int, ret)
+ ),
+
+ TP_fast_assign(
+ __entry->fl = fl ? fl : NULL;
+ __entry->s_dev = inode->i_sb->s_dev;
+ __entry->i_ino = inode->i_ino;
+ __entry->fl_next = fl ? fl->fl_next : NULL;
+ __entry->fl_owner = fl ? fl->fl_owner : NULL;
+ __entry->fl_pid = fl ? fl->fl_pid : 0;
+ __entry->fl_flags = fl ? fl->fl_flags : 0;
+ __entry->fl_type = fl ? fl->fl_type : 0;
+ __entry->fl_start = fl ? fl->fl_start : 0;
+ __entry->fl_end = fl ? fl->fl_end : 0;
+ __entry->ret = ret;
+ ),
+
+ TP_printk("fl=0x%p dev=0x%x:0x%x ino=0x%lx fl_next=0x%p fl_owner=0x%p fl_pid=%u fl_flags=%s fl_type=%s fl_start=%lld fl_end=%lld ret=%d",
+ __entry->fl, MAJOR(__entry->s_dev), MINOR(__entry->s_dev),
+ __entry->i_ino, __entry->fl_next, __entry->fl_owner,
+ __entry->fl_pid, show_fl_flags(__entry->fl_flags),
+ show_fl_type(__entry->fl_type),
+ __entry->fl_start, __entry->fl_end, __entry->ret)
+);
+
+DEFINE_EVENT(filelock_lock, posix_lock_inode,
+ TP_PROTO(struct inode *inode, struct file_lock *fl, int ret),
+ TP_ARGS(inode, fl, ret));
+
+DEFINE_EVENT(filelock_lock, fcntl_setlk,
+ TP_PROTO(struct inode *inode, struct file_lock *fl, int ret),
+ TP_ARGS(inode, fl, ret));
+
+DEFINE_EVENT(filelock_lock, locks_remove_posix,
+ TP_PROTO(struct inode *inode, struct file_lock *fl, int ret),
+ TP_ARGS(inode, fl, ret));
+
DECLARE_EVENT_CLASS(filelock_lease,
TP_PROTO(struct inode *inode, struct file_lock *fl),
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
index 8b1f806..5738bb3 100644
--- a/include/trace/events/thermal.h
+++ b/include/trace/events/thermal.h
@@ -4,6 +4,7 @@
#if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_THERMAL_H
+#include <linux/devfreq.h>
#include <linux/thermal.h>
#include <linux/tracepoint.h>
@@ -135,6 +136,58 @@ TRACE_EVENT(thermal_power_cpu_limit,
__entry->power)
);
+TRACE_EVENT(thermal_power_devfreq_get_power,
+ TP_PROTO(struct thermal_cooling_device *cdev,
+ struct devfreq_dev_status *status, unsigned long freq,
+ u32 dynamic_power, u32 static_power),
+
+ TP_ARGS(cdev, status, freq, dynamic_power, static_power),
+
+ TP_STRUCT__entry(
+ __string(type, cdev->type )
+ __field(unsigned long, freq )
+ __field(u32, load )
+ __field(u32, dynamic_power )
+ __field(u32, static_power )
+ ),
+
+ TP_fast_assign(
+ __assign_str(type, cdev->type);
+ __entry->freq = freq;
+ __entry->load = (100 * status->busy_time) / status->total_time;
+ __entry->dynamic_power = dynamic_power;
+ __entry->static_power = static_power;
+ ),
+
+ TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u",
+ __get_str(type), __entry->freq,
+ __entry->load, __entry->dynamic_power, __entry->static_power)
+);
+
+TRACE_EVENT(thermal_power_devfreq_limit,
+ TP_PROTO(struct thermal_cooling_device *cdev, unsigned long freq,
+ unsigned long cdev_state, u32 power),
+
+ TP_ARGS(cdev, freq, cdev_state, power),
+
+ TP_STRUCT__entry(
+ __string(type, cdev->type)
+ __field(unsigned int, freq )
+ __field(unsigned long, cdev_state)
+ __field(u32, power )
+ ),
+
+ TP_fast_assign(
+ __assign_str(type, cdev->type);
+ __entry->freq = freq;
+ __entry->cdev_state = cdev_state;
+ __entry->power = power;
+ ),
+
+ TP_printk("type=%s freq=%u cdev_state=%lu power=%u",
+ __get_str(type), __entry->freq, __entry->cdev_state,
+ __entry->power)
+);
#endif /* _TRACE_THERMAL_H */
/* This part must be outside protection */
diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h
index 22afa26..ee7754c 100644
--- a/include/trace/events/v4l2.h
+++ b/include/trace/events/v4l2.h
@@ -184,7 +184,7 @@ DECLARE_EVENT_CLASS(vb2_v4l2_event_class,
__field(int, minor)
__field(u32, flags)
__field(u32, field)
- __field(s64, timestamp)
+ __field(u64, timestamp)
__field(u32, timecode_type)
__field(u32, timecode_flags)
__field(u8, timecode_frames)
@@ -205,7 +205,7 @@ DECLARE_EVENT_CLASS(vb2_v4l2_event_class,
__entry->minor = owner ? owner->vdev->minor : -1;
__entry->flags = vbuf->flags;
__entry->field = vbuf->field;
- __entry->timestamp = timeval_to_ns(&vbuf->timestamp);
+ __entry->timestamp = vb->timestamp;
__entry->timecode_type = vbuf->timecode.type;
__entry->timecode_flags = vbuf->timecode.flags;
__entry->timecode_frames = vbuf->timecode.frames;
diff --git a/include/trace/events/vb2.h b/include/trace/events/vb2.h
index bfeceeb..c1a2241 100644
--- a/include/trace/events/vb2.h
+++ b/include/trace/events/vb2.h
@@ -18,6 +18,7 @@ DECLARE_EVENT_CLASS(vb2_event_class,
__field(u32, index)
__field(u32, type)
__field(u32, bytesused)
+ __field(u64, timestamp)
),
TP_fast_assign(
@@ -28,14 +29,16 @@ DECLARE_EVENT_CLASS(vb2_event_class,
__entry->index = vb->index;
__entry->type = vb->type;
__entry->bytesused = vb->planes[0].bytesused;
+ __entry->timestamp = vb->timestamp;
),
TP_printk("owner = %p, queued = %u, owned_by_drv = %d, index = %u, "
- "type = %u, bytesused = %u", __entry->owner,
+ "type = %u, bytesused = %u, timestamp = %llu", __entry->owner,
__entry->queued_count,
__entry->owned_by_drv_count,
__entry->index, __entry->type,
- __entry->bytesused
+ __entry->bytesused,
+ __entry->timestamp
)
)
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 1324b02..2622b33 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -715,9 +715,11 @@ __SYSCALL(__NR_userfaultfd, sys_userfaultfd)
__SYSCALL(__NR_membarrier, sys_membarrier)
#define __NR_mlock2 284
__SYSCALL(__NR_mlock2, sys_mlock2)
+#define __NR_copy_file_range 285
+__SYSCALL(__NR_copy_file_range, sys_copy_file_range)
#undef __NR_syscalls
-#define __NR_syscalls 285
+#define __NR_syscalls 286
/*
* All syscalls below here should go away really,
diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h
index 8c5e8b9..ee2d542 100644
--- a/include/uapi/drm/drm_fourcc.h
+++ b/include/uapi/drm/drm_fourcc.h
@@ -158,7 +158,7 @@
/* add more to the end as needed */
#define fourcc_mod_code(vendor, val) \
- ((((u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
+ ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL))
/*
* Format Modifier tokens:
@@ -225,7 +225,7 @@
* - multiple of 128 pixels for the width
* - multiple of 32 pixels for the height
*
- * For more information: see http://linuxtv.org/downloads/v4l-dvb-apis/re32.html
+ * For more information: see https://linuxtv.org/downloads/v4l-dvb-apis/re32.html
*/
#define DRM_FORMAT_MOD_SAMSUNG_64_32_TILE fourcc_mod_code(SAMSUNG, 1)
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 628e6e6..c2e5d6c 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -186,6 +186,7 @@ header-y += if_tunnel.h
header-y += if_vlan.h
header-y += if_x25.h
header-y += igmp.h
+header-y += ila.h
header-y += in6.h
header-y += inet_diag.h
header-y += in.h
diff --git a/include/uapi/linux/dvb/video.h b/include/uapi/linux/dvb/video.h
index d3d14a59..4939256 100644
--- a/include/uapi/linux/dvb/video.h
+++ b/include/uapi/linux/dvb/video.h
@@ -26,7 +26,6 @@
#include <linux/types.h>
#ifndef __KERNEL__
-#include <stdint.h>
#include <time.h>
#endif
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index f15d980..b38e647 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -39,12 +39,48 @@
#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
+struct file_clone_range {
+ __s64 src_fd;
+ __u64 src_offset;
+ __u64 src_length;
+ __u64 dest_offset;
+};
+
struct fstrim_range {
__u64 start;
__u64 len;
__u64 minlen;
};
+/* extent-same (dedupe) ioctls; these MUST match the btrfs ioctl definitions */
+#define FILE_DEDUPE_RANGE_SAME 0
+#define FILE_DEDUPE_RANGE_DIFFERS 1
+
+/* from struct btrfs_ioctl_file_extent_same_info */
+struct file_dedupe_range_info {
+ __s64 dest_fd; /* in - destination file */
+ __u64 dest_offset; /* in - start of extent in destination */
+ __u64 bytes_deduped; /* out - total # of bytes we were able
+ * to dedupe from this file. */
+ /* status of this dedupe operation:
+ * < 0 for error
+ * == FILE_DEDUPE_RANGE_SAME if dedupe succeeds
+ * == FILE_DEDUPE_RANGE_DIFFERS if data differs
+ */
+ __s32 status; /* out - see above description */
+ __u32 reserved; /* must be zero */
+};
+
+/* from struct btrfs_ioctl_file_extent_same_args */
+struct file_dedupe_range {
+ __u64 src_offset; /* in - start of extent in source */
+ __u64 src_length; /* in - length of extent */
+ __u16 dest_count; /* in - total elements in info array */
+ __u16 reserved1; /* must be zero */
+ __u32 reserved2; /* must be zero */
+ struct file_dedupe_range_info info[0];
+};
+
/* And dynamically-tunable limits and defaults: */
struct files_stat_struct {
unsigned long nr_files; /* read only */
@@ -159,6 +195,9 @@ struct inodes_stat_t {
#define FIFREEZE _IOWR('X', 119, int) /* Freeze */
#define FITHAW _IOWR('X', 120, int) /* Thaw */
#define FITRIM _IOWR('X', 121, struct fstrim_range) /* Trim */
+#define FICLONE _IOW(0x94, 9, int)
+#define FICLONERANGE _IOW(0x94, 13, struct file_clone_range)
+#define FIDEDUPERANGE _IOWR(0x94, 54, struct file_dedupe_range)
#define FS_IOC_GETFLAGS _IOR('f', 1, long)
#define FS_IOC_SETFLAGS _IOW('f', 2, long)
diff --git a/include/uapi/linux/i2c-dev.h b/include/uapi/linux/i2c-dev.h
index 3f31155..2f05e66 100644
--- a/include/uapi/linux/i2c-dev.h
+++ b/include/uapi/linux/i2c-dev.h
@@ -66,7 +66,9 @@ struct i2c_rdwr_ioctl_data {
__u32 nmsgs; /* number of i2c_msgs */
};
-#define I2C_RDRW_IOCTL_MAX_MSGS 42
+#define I2C_RDWR_IOCTL_MAX_MSGS 42
+/* Originally defined with a typo, keep it for compatibility */
+#define I2C_RDRW_IOCTL_MAX_MSGS I2C_RDWR_IOCTL_MAX_MSGS
#endif /* _UAPI_LINUX_I2C_DEV_H */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 03f3618..9da9051 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -154,6 +154,20 @@ struct kvm_s390_skeys {
__u32 flags;
__u32 reserved[9];
};
+
+struct kvm_hyperv_exit {
+#define KVM_EXIT_HYPERV_SYNIC 1
+ __u32 type;
+ union {
+ struct {
+ __u32 msr;
+ __u64 control;
+ __u64 evt_page;
+ __u64 msg_page;
+ } synic;
+ } u;
+};
+
#define KVM_S390_GET_SKEYS_NONE 1
#define KVM_S390_SKEYS_MAX 1048576
@@ -184,6 +198,7 @@ struct kvm_s390_skeys {
#define KVM_EXIT_SYSTEM_EVENT 24
#define KVM_EXIT_S390_STSI 25
#define KVM_EXIT_IOAPIC_EOI 26
+#define KVM_EXIT_HYPERV 27
/* For KVM_EXIT_INTERNAL_ERROR */
/* Emulate instruction failed. */
@@ -338,6 +353,8 @@ struct kvm_run {
struct {
__u8 vector;
} eoi;
+ /* KVM_EXIT_HYPERV */
+ struct kvm_hyperv_exit hyperv;
/* Fix the size of the union. */
char padding[256];
};
@@ -831,6 +848,8 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_GUEST_DEBUG_HW_WPS 120
#define KVM_CAP_SPLIT_IRQCHIP 121
#define KVM_CAP_IOEVENTFD_ANY_LENGTH 122
+#define KVM_CAP_HYPERV_SYNIC 123
+#define KVM_CAP_S390_RI 124
#ifdef KVM_CAP_IRQ_ROUTING
@@ -854,10 +873,16 @@ struct kvm_irq_routing_s390_adapter {
__u32 adapter_id;
};
+struct kvm_irq_routing_hv_sint {
+ __u32 vcpu;
+ __u32 sint;
+};
+
/* gsi routing entry types */
#define KVM_IRQ_ROUTING_IRQCHIP 1
#define KVM_IRQ_ROUTING_MSI 2
#define KVM_IRQ_ROUTING_S390_ADAPTER 3
+#define KVM_IRQ_ROUTING_HV_SINT 4
struct kvm_irq_routing_entry {
__u32 gsi;
@@ -868,6 +893,7 @@ struct kvm_irq_routing_entry {
struct kvm_irq_routing_irqchip irqchip;
struct kvm_irq_routing_msi msi;
struct kvm_irq_routing_s390_adapter adapter;
+ struct kvm_irq_routing_hv_sint hv_sint;
__u32 pad[8];
} u;
};
diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h
new file mode 100644
index 0000000..4b3ab29
--- /dev/null
+++ b/include/uapi/linux/lirc.h
@@ -0,0 +1,168 @@
+/*
+ * lirc.h - linux infrared remote control header file
+ * last modified 2010/07/13 by Jarod Wilson
+ */
+
+#ifndef _LINUX_LIRC_H
+#define _LINUX_LIRC_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+#define PULSE_BIT 0x01000000
+#define PULSE_MASK 0x00FFFFFF
+
+#define LIRC_MODE2_SPACE 0x00000000
+#define LIRC_MODE2_PULSE 0x01000000
+#define LIRC_MODE2_FREQUENCY 0x02000000
+#define LIRC_MODE2_TIMEOUT 0x03000000
+
+#define LIRC_VALUE_MASK 0x00FFFFFF
+#define LIRC_MODE2_MASK 0xFF000000
+
+#define LIRC_SPACE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_SPACE)
+#define LIRC_PULSE(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_PULSE)
+#define LIRC_FREQUENCY(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_FREQUENCY)
+#define LIRC_TIMEOUT(val) (((val)&LIRC_VALUE_MASK) | LIRC_MODE2_TIMEOUT)
+
+#define LIRC_VALUE(val) ((val)&LIRC_VALUE_MASK)
+#define LIRC_MODE2(val) ((val)&LIRC_MODE2_MASK)
+
+#define LIRC_IS_SPACE(val) (LIRC_MODE2(val) == LIRC_MODE2_SPACE)
+#define LIRC_IS_PULSE(val) (LIRC_MODE2(val) == LIRC_MODE2_PULSE)
+#define LIRC_IS_FREQUENCY(val) (LIRC_MODE2(val) == LIRC_MODE2_FREQUENCY)
+#define LIRC_IS_TIMEOUT(val) (LIRC_MODE2(val) == LIRC_MODE2_TIMEOUT)
+
+/* used heavily by lirc userspace */
+#define lirc_t int
+
+/*** lirc compatible hardware features ***/
+
+#define LIRC_MODE2SEND(x) (x)
+#define LIRC_SEND2MODE(x) (x)
+#define LIRC_MODE2REC(x) ((x) << 16)
+#define LIRC_REC2MODE(x) ((x) >> 16)
+
+#define LIRC_MODE_RAW 0x00000001
+#define LIRC_MODE_PULSE 0x00000002
+#define LIRC_MODE_MODE2 0x00000004
+#define LIRC_MODE_LIRCCODE 0x00000010
+
+
+#define LIRC_CAN_SEND_RAW LIRC_MODE2SEND(LIRC_MODE_RAW)
+#define LIRC_CAN_SEND_PULSE LIRC_MODE2SEND(LIRC_MODE_PULSE)
+#define LIRC_CAN_SEND_MODE2 LIRC_MODE2SEND(LIRC_MODE_MODE2)
+#define LIRC_CAN_SEND_LIRCCODE LIRC_MODE2SEND(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_SEND_MASK 0x0000003f
+
+#define LIRC_CAN_SET_SEND_CARRIER 0x00000100
+#define LIRC_CAN_SET_SEND_DUTY_CYCLE 0x00000200
+#define LIRC_CAN_SET_TRANSMITTER_MASK 0x00000400
+
+#define LIRC_CAN_REC_RAW LIRC_MODE2REC(LIRC_MODE_RAW)
+#define LIRC_CAN_REC_PULSE LIRC_MODE2REC(LIRC_MODE_PULSE)
+#define LIRC_CAN_REC_MODE2 LIRC_MODE2REC(LIRC_MODE_MODE2)
+#define LIRC_CAN_REC_LIRCCODE LIRC_MODE2REC(LIRC_MODE_LIRCCODE)
+
+#define LIRC_CAN_REC_MASK LIRC_MODE2REC(LIRC_CAN_SEND_MASK)
+
+#define LIRC_CAN_SET_REC_CARRIER (LIRC_CAN_SET_SEND_CARRIER << 16)
+#define LIRC_CAN_SET_REC_DUTY_CYCLE (LIRC_CAN_SET_SEND_DUTY_CYCLE << 16)
+
+#define LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE 0x40000000
+#define LIRC_CAN_SET_REC_CARRIER_RANGE 0x80000000
+#define LIRC_CAN_GET_REC_RESOLUTION 0x20000000
+#define LIRC_CAN_SET_REC_TIMEOUT 0x10000000
+#define LIRC_CAN_SET_REC_FILTER 0x08000000
+
+#define LIRC_CAN_MEASURE_CARRIER 0x02000000
+#define LIRC_CAN_USE_WIDEBAND_RECEIVER 0x04000000
+
+#define LIRC_CAN_SEND(x) ((x)&LIRC_CAN_SEND_MASK)
+#define LIRC_CAN_REC(x) ((x)&LIRC_CAN_REC_MASK)
+
+#define LIRC_CAN_NOTIFY_DECODE 0x01000000
+
+/*** IOCTL commands for lirc driver ***/
+
+#define LIRC_GET_FEATURES _IOR('i', 0x00000000, __u32)
+
+#define LIRC_GET_SEND_MODE _IOR('i', 0x00000001, __u32)
+#define LIRC_GET_REC_MODE _IOR('i', 0x00000002, __u32)
+#define LIRC_GET_SEND_CARRIER _IOR('i', 0x00000003, __u32)
+#define LIRC_GET_REC_CARRIER _IOR('i', 0x00000004, __u32)
+#define LIRC_GET_SEND_DUTY_CYCLE _IOR('i', 0x00000005, __u32)
+#define LIRC_GET_REC_DUTY_CYCLE _IOR('i', 0x00000006, __u32)
+#define LIRC_GET_REC_RESOLUTION _IOR('i', 0x00000007, __u32)
+
+#define LIRC_GET_MIN_TIMEOUT _IOR('i', 0x00000008, __u32)
+#define LIRC_GET_MAX_TIMEOUT _IOR('i', 0x00000009, __u32)
+
+#define LIRC_GET_MIN_FILTER_PULSE _IOR('i', 0x0000000a, __u32)
+#define LIRC_GET_MAX_FILTER_PULSE _IOR('i', 0x0000000b, __u32)
+#define LIRC_GET_MIN_FILTER_SPACE _IOR('i', 0x0000000c, __u32)
+#define LIRC_GET_MAX_FILTER_SPACE _IOR('i', 0x0000000d, __u32)
+
+/* code length in bits, currently only for LIRC_MODE_LIRCCODE */
+#define LIRC_GET_LENGTH _IOR('i', 0x0000000f, __u32)
+
+#define LIRC_SET_SEND_MODE _IOW('i', 0x00000011, __u32)
+#define LIRC_SET_REC_MODE _IOW('i', 0x00000012, __u32)
+/* Note: these can reset the according pulse_width */
+#define LIRC_SET_SEND_CARRIER _IOW('i', 0x00000013, __u32)
+#define LIRC_SET_REC_CARRIER _IOW('i', 0x00000014, __u32)
+#define LIRC_SET_SEND_DUTY_CYCLE _IOW('i', 0x00000015, __u32)
+#define LIRC_SET_REC_DUTY_CYCLE _IOW('i', 0x00000016, __u32)
+#define LIRC_SET_TRANSMITTER_MASK _IOW('i', 0x00000017, __u32)
+
+/*
+ * when a timeout != 0 is set the driver will send a
+ * LIRC_MODE2_TIMEOUT data packet, otherwise LIRC_MODE2_TIMEOUT is
+ * never sent, timeout is disabled by default
+ */
+#define LIRC_SET_REC_TIMEOUT _IOW('i', 0x00000018, __u32)
+
+/* 1 enables, 0 disables timeout reports in MODE2 */
+#define LIRC_SET_REC_TIMEOUT_REPORTS _IOW('i', 0x00000019, __u32)
+
+/*
+ * pulses shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_PULSE _IOW('i', 0x0000001a, __u32)
+/*
+ * spaces shorter than this are filtered out by hardware (software
+ * emulation in lirc_dev?)
+ */
+#define LIRC_SET_REC_FILTER_SPACE _IOW('i', 0x0000001b, __u32)
+/*
+ * if filter cannot be set independently for pulse/space, this should
+ * be used
+ */
+#define LIRC_SET_REC_FILTER _IOW('i', 0x0000001c, __u32)
+
+/*
+ * if enabled from the next key press on the driver will send
+ * LIRC_MODE2_FREQUENCY packets
+ */
+#define LIRC_SET_MEASURE_CARRIER_MODE _IOW('i', 0x0000001d, __u32)
+
+/*
+ * to set a range use
+ * LIRC_SET_REC_DUTY_CYCLE_RANGE/LIRC_SET_REC_CARRIER_RANGE with the
+ * lower bound first and later
+ * LIRC_SET_REC_DUTY_CYCLE/LIRC_SET_REC_CARRIER with the upper bound
+ */
+
+#define LIRC_SET_REC_DUTY_CYCLE_RANGE _IOW('i', 0x0000001e, __u32)
+#define LIRC_SET_REC_CARRIER_RANGE _IOW('i', 0x0000001f, __u32)
+
+#define LIRC_NOTIFY_DECODE _IO('i', 0x00000020)
+
+#define LIRC_SETUP_START _IO('i', 0x00000021)
+#define LIRC_SETUP_END _IO('i', 0x00000022)
+
+#define LIRC_SET_WIDEBAND_RECEIVER _IOW('i', 0x00000023, __u32)
+
+#endif
diff --git a/include/uapi/linux/nfs.h b/include/uapi/linux/nfs.h
index 654bae3..5e62961 100644
--- a/include/uapi/linux/nfs.h
+++ b/include/uapi/linux/nfs.h
@@ -33,17 +33,6 @@
#define NFS_PIPE_DIRNAME "nfs"
-/* NFS ioctls */
-/* Let's follow btrfs lead on CLONE to avoid messing userspace */
-#define NFS_IOC_CLONE _IOW(0x94, 9, int)
-#define NFS_IOC_CLONE_RANGE _IOW(0x94, 13, int)
-
-struct nfs_ioctl_clone_range_args {
- __s64 src_fd;
- __u64 src_off, count;
- __u64 dst_off;
-};
-
/*
* NFS stats. The good thing with these values is that NFSv3 errors are
* a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h
index 28ccedd..a27222d 100644
--- a/include/uapi/linux/openvswitch.h
+++ b/include/uapi/linux/openvswitch.h
@@ -628,7 +628,7 @@ struct ovs_action_hash {
* @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the
* mask, the corresponding bit in the value is copied to the connection
* tracking mark field in the connection.
- * @OVS_CT_ATTR_LABEL: %OVS_CT_LABELS_LEN value followed by %OVS_CT_LABELS_LEN
+ * @OVS_CT_ATTR_LABELS: %OVS_CT_LABELS_LEN value followed by %OVS_CT_LABELS_LEN
* mask. For each bit set in the mask, the corresponding bit in the value is
* copied to the connection tracking label field in the connection.
* @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG.
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index d801bb0..1afe962 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -171,6 +171,9 @@ enum perf_branch_sample_type_shift {
PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, /* indirect jumps */
PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, /* direct call */
+ PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, /* no flags */
+ PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, /* no cycles */
+
PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */
};
@@ -192,6 +195,9 @@ enum perf_branch_sample_type {
PERF_SAMPLE_BRANCH_IND_JUMP = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT,
PERF_SAMPLE_BRANCH_CALL = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT,
+ PERF_SAMPLE_BRANCH_NO_FLAGS = 1U << PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT,
+ PERF_SAMPLE_BRANCH_NO_CYCLES = 1U << PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT,
+
PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT,
};
diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h
index 310d83e..3d7a0fc 100644
--- a/include/uapi/linux/psci.h
+++ b/include/uapi/linux/psci.h
@@ -46,6 +46,11 @@
#define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5)
#define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7)
+#define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10)
+#define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14)
+
+#define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14)
+
/* PSCI v0.2 power state encoding for CPU_SUSPEND function */
#define PSCI_0_2_POWER_STATE_ID_MASK 0xffff
#define PSCI_0_2_POWER_STATE_ID_SHIFT 0
@@ -56,6 +61,13 @@
#define PSCI_0_2_POWER_STATE_AFFL_MASK \
(0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT)
+/* PSCI extended power state encoding for CPU_SUSPEND function */
+#define PSCI_1_0_EXT_POWER_STATE_ID_MASK 0xfffffff
+#define PSCI_1_0_EXT_POWER_STATE_ID_SHIFT 0
+#define PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT 30
+#define PSCI_1_0_EXT_POWER_STATE_TYPE_MASK \
+ (0x1 << PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT)
+
/* PSCI v0.2 affinity level state returned by AFFINITY_INFO */
#define PSCI_0_2_AFFINITY_LEVEL_ON 0
#define PSCI_0_2_AFFINITY_LEVEL_OFF 1
@@ -76,6 +88,11 @@
#define PSCI_VERSION_MINOR(ver) \
((ver) & PSCI_VERSION_MINOR_MASK)
+/* PSCI features decoding (>=1.0) */
+#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1
+#define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK \
+ (0x1 << PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT)
+
/* PSCI return values (inclusive of all PSCI versions) */
#define PSCI_RET_SUCCESS 0
#define PSCI_RET_NOT_SUPPORTED -1
@@ -86,5 +103,6 @@
#define PSCI_RET_INTERNAL_FAILURE -6
#define PSCI_RET_NOT_PRESENT -7
#define PSCI_RET_DISABLED -8
+#define PSCI_RET_INVALID_ADDRESS -9
#endif /* _UAPI_LINUX_PSCI_H */
diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h
index 3b3b95e..69ab695 100644
--- a/include/uapi/linux/usb/video.h
+++ b/include/uapi/linux/usb/video.h
@@ -28,6 +28,7 @@
/* A.3. Video Interface Protocol Codes */
#define UVC_PC_PROTOCOL_UNDEFINED 0x00
+#define UVC_PC_PROTOCOL_15 0x01
/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
#define UVC_VC_DESCRIPTOR_UNDEFINED 0x00
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 1bdce50..2d225bc 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -158,8 +158,10 @@ enum v4l2_colorfx {
* We reserve 16 controls for this driver. */
#define V4L2_CID_USER_S2255_BASE (V4L2_CID_USER_BASE + 0x1030)
-/* The base for the si476x driver controls. See include/media/si476x.h for the list
- * of controls. Total of 16 controls is reserved for this driver */
+/*
+ * The base for the si476x driver controls. See include/media/drv-intf/si476x.h
+ * for the list of controls. Total of 16 controls is reserved for this driver
+ */
#define V4L2_CID_USER_SI476X_BASE (V4L2_CID_USER_BASE + 0x1040)
/* The base for the TI VPE driver controls. Total of 16 controls is reserved for
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index a0e87d1..14cd5eb 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -46,7 +46,7 @@
* All kernel-specific stuff were moved to media/v4l2-dev.h, so
* no #if __KERNEL tests are allowed here
*
- * See http://linuxtv.org for more info
+ * See https://linuxtv.org for more info
*
* Author: Bill Dirks <bill@thedirks.org>
* Justin Schoeman
@@ -1476,7 +1476,12 @@ struct v4l2_ext_control {
} __attribute__ ((packed));
struct v4l2_ext_controls {
- __u32 ctrl_class;
+ union {
+#ifndef __KERNEL__
+ __u32 ctrl_class;
+#endif
+ __u32 which;
+ };
__u32 count;
__u32 error_idx;
__u32 reserved[2];
@@ -1484,9 +1489,14 @@ struct v4l2_ext_controls {
};
#define V4L2_CTRL_ID_MASK (0x0fffffff)
+#ifndef __KERNEL__
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
+#endif
+#define V4L2_CTRL_ID2WHICH(id) ((id) & 0x0fff0000UL)
#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
#define V4L2_CTRL_MAX_DIMS (4)
+#define V4L2_CTRL_WHICH_CUR_VAL 0
+#define V4L2_CTRL_WHICH_DEF_VAL 0x0f000000
enum v4l2_ctrl_type {
V4L2_CTRL_TYPE_INTEGER = 1,
diff --git a/include/uapi/xen/gntdev.h b/include/uapi/xen/gntdev.h
index aa7610a..d066197 100644
--- a/include/uapi/xen/gntdev.h
+++ b/include/uapi/xen/gntdev.h
@@ -144,6 +144,56 @@ struct ioctl_gntdev_unmap_notify {
__u32 event_channel_port;
};
+struct gntdev_grant_copy_segment {
+ union {
+ void __user *virt;
+ struct {
+ grant_ref_t ref;
+ __u16 offset;
+ domid_t domid;
+ } foreign;
+ } source, dest;
+ __u16 len;
+
+ __u16 flags; /* GNTCOPY_* */
+ __s16 status; /* GNTST_* */
+};
+
+/*
+ * Copy between grant references and local buffers.
+ *
+ * The copy is split into @count @segments, each of which can copy
+ * to/from one grant reference.
+ *
+ * Each segment is similar to struct gnttab_copy in the hypervisor ABI
+ * except the local buffer is specified using a virtual address
+ * (instead of a GFN and offset).
+ *
+ * The local buffer may cross a Xen page boundary -- the driver will
+ * split segments into multiple ops if required.
+ *
+ * Returns 0 if all segments have been processed and @status in each
+ * segment is valid. Note that one or more segments may have failed
+ * (status != GNTST_okay).
+ *
+ * If the driver had to split a segment into two or more ops, @status
+ * includes the status of the first failed op for that segment (or
+ * GNTST_okay if all ops were successful).
+ *
+ * If -1 is returned, the status of all segments is undefined.
+ *
+ * EINVAL: A segment has local buffers for both source and
+ * destination.
+ * EINVAL: A segment crosses the boundary of a foreign page.
+ * EFAULT: A segment's local buffer is not accessible.
+ */
+#define IOCTL_GNTDEV_GRANT_COPY \
+ _IOC(_IOC_NONE, 'G', 8, sizeof(struct ioctl_gntdev_grant_copy))
+struct ioctl_gntdev_grant_copy {
+ unsigned int count;
+ struct gntdev_grant_copy_segment __user *segments;
+};
+
/* Clear (set to zero) the byte specified by index */
#define UNMAP_NOTIFY_CLEAR_BYTE 0x1
/* Send an interrupt on the indicated event channel */
diff --git a/include/video/imx-ipu-v3.h b/include/video/imx-ipu-v3.h
index 85dedca..eeba753 100644
--- a/include/video/imx-ipu-v3.h
+++ b/include/video/imx-ipu-v3.h
@@ -343,7 +343,6 @@ struct ipu_client_platformdata {
int di;
int dc;
int dp;
- int dmfc;
int dma[2];
};
diff --git a/include/xen/interface/io/ring.h b/include/xen/interface/io/ring.h
index 7d28aff..7dc685b 100644
--- a/include/xen/interface/io/ring.h
+++ b/include/xen/interface/io/ring.h
@@ -181,6 +181,20 @@ struct __name##_back_ring { \
#define RING_GET_REQUEST(_r, _idx) \
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].req))
+/*
+ * Get a local copy of a request.
+ *
+ * Use this in preference to RING_GET_REQUEST() so all processing is
+ * done on a local copy that cannot be modified by the other end.
+ *
+ * Note that https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58145 may cause this
+ * to be ineffective where _req is a struct which consists of only bitfields.
+ */
+#define RING_COPY_REQUEST(_r, _idx, _req) do { \
+ /* Use volatile to force the copy into _req. */ \
+ *(_req) = *(volatile typeof(_req))RING_GET_REQUEST(_r, _idx); \
+} while (0)
+
#define RING_GET_RESPONSE(_r, _idx) \
(&((_r)->sring->ring[((_idx) & (RING_SIZE(_r) - 1))].rsp))
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index 8e03587..732efb0 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -35,14 +35,23 @@
* Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
* 1 January, 1970 if the current system time was <system_time>.
*/
-#define XENPF_settime 17
-struct xenpf_settime {
+#define XENPF_settime32 17
+struct xenpf_settime32 {
/* IN variables. */
uint32_t secs;
uint32_t nsecs;
uint64_t system_time;
};
-DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime_t);
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime32_t);
+#define XENPF_settime64 62
+struct xenpf_settime64 {
+ /* IN variables. */
+ uint64_t secs;
+ uint32_t nsecs;
+ uint32_t mbz;
+ uint64_t system_time;
+};
+DEFINE_GUEST_HANDLE_STRUCT(xenpf_settime64_t);
/*
* Request memory range (@mfn, @mfn+@nr_mfns-1) to have type @type.
@@ -495,7 +504,8 @@ struct xen_platform_op {
uint32_t cmd;
uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
union {
- struct xenpf_settime settime;
+ struct xenpf_settime32 settime32;
+ struct xenpf_settime64 settime64;
struct xenpf_add_memtype add_memtype;
struct xenpf_del_memtype del_memtype;
struct xenpf_read_memtype read_memtype;
diff --git a/include/xen/interface/xen.h b/include/xen/interface/xen.h
index 167071c..d133112 100644
--- a/include/xen/interface/xen.h
+++ b/include/xen/interface/xen.h
@@ -48,7 +48,7 @@
#define __HYPERVISOR_set_callbacks 4
#define __HYPERVISOR_fpu_taskswitch 5
#define __HYPERVISOR_sched_op_compat 6
-#define __HYPERVISOR_dom0_op 7
+#define __HYPERVISOR_platform_op 7
#define __HYPERVISOR_set_debugreg 8
#define __HYPERVISOR_get_debugreg 9
#define __HYPERVISOR_update_descriptor 10
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index e4e214a..86abe07 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -5,6 +5,7 @@
#include <linux/notifier.h>
#include <linux/efi.h>
#include <asm/xen/interface.h>
+#include <xen/interface/vcpu.h>
DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
@@ -18,6 +19,10 @@ void xen_arch_suspend(void);
void xen_resume_notifier_register(struct notifier_block *nb);
void xen_resume_notifier_unregister(struct notifier_block *nb);
+bool xen_vcpu_stolen(int vcpu);
+void xen_setup_runstate_info(int cpu);
+void xen_get_runstate_snapshot(struct vcpu_runstate_info *res);
+
int xen_setup_shutdown_event(void);
extern unsigned long *xen_contiguous_bitmap;
diff --git a/init/Kconfig b/init/Kconfig
index c24b6f7..235c7a2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2030,13 +2030,6 @@ config INIT_ALL_POSSIBLE
it was better to provide this option than to break all the archs
and have several arch maintainers pursuing me down dark alleys.
-config STOP_MACHINE
- bool
- default y
- depends on (SMP && MODULE_UNLOAD) || HOTPLUG_CPU
- help
- Need stop_machine() primitive.
-
source "block/Kconfig"
config PREEMPT_NOTIFIERS
diff --git a/init/main.c b/init/main.c
index 9e64d70..c6ebefa 100644
--- a/init/main.c
+++ b/init/main.c
@@ -943,6 +943,8 @@ static int __ref kernel_init(void *unused)
flush_delayed_fput();
+ rcu_end_inkernel_boot();
+
if (ramdisk_execute_command) {
ret = run_init_process(ramdisk_execute_command);
if (!ret)
diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c
index 3f4c99e..b0799bc 100644
--- a/kernel/bpf/arraymap.c
+++ b/kernel/bpf/arraymap.c
@@ -28,11 +28,17 @@ static struct bpf_map *array_map_alloc(union bpf_attr *attr)
attr->value_size == 0)
return ERR_PTR(-EINVAL);
+ if (attr->value_size >= 1 << (KMALLOC_SHIFT_MAX - 1))
+ /* if value_size is bigger, the user space won't be able to
+ * access the elements.
+ */
+ return ERR_PTR(-E2BIG);
+
elem_size = round_up(attr->value_size, 8);
/* check round_up into zero and u32 overflow */
if (elem_size == 0 ||
- attr->max_entries > (U32_MAX - sizeof(*array)) / elem_size)
+ attr->max_entries > (U32_MAX - PAGE_SIZE - sizeof(*array)) / elem_size)
return ERR_PTR(-ENOMEM);
array_size = sizeof(*array) + attr->max_entries * elem_size;
@@ -105,7 +111,7 @@ static int array_map_update_elem(struct bpf_map *map, void *key, void *value,
/* all elements already exist */
return -EEXIST;
- memcpy(array->value + array->elem_size * index, value, array->elem_size);
+ memcpy(array->value + array->elem_size * index, value, map->value_size);
return 0;
}
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index 19909b2..34777b3 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -64,12 +64,35 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
*/
goto free_htab;
- err = -ENOMEM;
+ if (htab->map.value_size >= (1 << (KMALLOC_SHIFT_MAX - 1)) -
+ MAX_BPF_STACK - sizeof(struct htab_elem))
+ /* if value_size is bigger, the user space won't be able to
+ * access the elements via bpf syscall. This check also makes
+ * sure that the elem_size doesn't overflow and it's
+ * kmalloc-able later in htab_map_update_elem()
+ */
+ goto free_htab;
+
+ htab->elem_size = sizeof(struct htab_elem) +
+ round_up(htab->map.key_size, 8) +
+ htab->map.value_size;
+
/* prevent zero size kmalloc and check for u32 overflow */
if (htab->n_buckets == 0 ||
htab->n_buckets > U32_MAX / sizeof(struct hlist_head))
goto free_htab;
+ if ((u64) htab->n_buckets * sizeof(struct hlist_head) +
+ (u64) htab->elem_size * htab->map.max_entries >=
+ U32_MAX - PAGE_SIZE)
+ /* make sure page count doesn't overflow */
+ goto free_htab;
+
+ htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) +
+ htab->elem_size * htab->map.max_entries,
+ PAGE_SIZE) >> PAGE_SHIFT;
+
+ err = -ENOMEM;
htab->buckets = kmalloc_array(htab->n_buckets, sizeof(struct hlist_head),
GFP_USER | __GFP_NOWARN);
@@ -85,13 +108,6 @@ static struct bpf_map *htab_map_alloc(union bpf_attr *attr)
raw_spin_lock_init(&htab->lock);
htab->count = 0;
- htab->elem_size = sizeof(struct htab_elem) +
- round_up(htab->map.key_size, 8) +
- htab->map.value_size;
-
- htab->map.pages = round_up(htab->n_buckets * sizeof(struct hlist_head) +
- htab->elem_size * htab->map.max_entries,
- PAGE_SIZE) >> PAGE_SHIFT;
return &htab->map;
free_htab:
@@ -222,7 +238,7 @@ static int htab_map_update_elem(struct bpf_map *map, void *key, void *value,
WARN_ON_ONCE(!rcu_read_lock_held());
/* allocate new element outside of lock */
- l_new = kmalloc(htab->elem_size, GFP_ATOMIC);
+ l_new = kmalloc(htab->elem_size, GFP_ATOMIC | __GFP_NOWARN);
if (!l_new)
return -ENOMEM;
diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c
index be6d726..5a8a797 100644
--- a/kernel/bpf/inode.c
+++ b/kernel/bpf/inode.c
@@ -34,7 +34,7 @@ static void *bpf_any_get(void *raw, enum bpf_type type)
atomic_inc(&((struct bpf_prog *)raw)->aux->refcnt);
break;
case BPF_TYPE_MAP:
- atomic_inc(&((struct bpf_map *)raw)->refcnt);
+ bpf_map_inc(raw, true);
break;
default:
WARN_ON_ONCE(1);
@@ -51,7 +51,7 @@ static void bpf_any_put(void *raw, enum bpf_type type)
bpf_prog_put(raw);
break;
case BPF_TYPE_MAP:
- bpf_map_put(raw);
+ bpf_map_put_with_uref(raw);
break;
default:
WARN_ON_ONCE(1);
@@ -64,7 +64,7 @@ static void *bpf_fd_probe_obj(u32 ufd, enum bpf_type *type)
void *raw;
*type = BPF_TYPE_MAP;
- raw = bpf_map_get(ufd);
+ raw = bpf_map_get_with_uref(ufd);
if (IS_ERR(raw)) {
*type = BPF_TYPE_PROG;
raw = bpf_prog_get(ufd);
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 0d3313d..3b39550 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -82,6 +82,14 @@ static void bpf_map_free_deferred(struct work_struct *work)
map->ops->map_free(map);
}
+static void bpf_map_put_uref(struct bpf_map *map)
+{
+ if (atomic_dec_and_test(&map->usercnt)) {
+ if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
+ bpf_fd_array_map_clear(map);
+ }
+}
+
/* decrement map refcnt and schedule it for freeing via workqueue
* (unrelying map implementation ops->map_free() might sleep)
*/
@@ -93,17 +101,15 @@ void bpf_map_put(struct bpf_map *map)
}
}
-static int bpf_map_release(struct inode *inode, struct file *filp)
+void bpf_map_put_with_uref(struct bpf_map *map)
{
- struct bpf_map *map = filp->private_data;
-
- if (map->map_type == BPF_MAP_TYPE_PROG_ARRAY)
- /* prog_array stores refcnt-ed bpf_prog pointers
- * release them all when user space closes prog_array_fd
- */
- bpf_fd_array_map_clear(map);
-
+ bpf_map_put_uref(map);
bpf_map_put(map);
+}
+
+static int bpf_map_release(struct inode *inode, struct file *filp)
+{
+ bpf_map_put_with_uref(filp->private_data);
return 0;
}
@@ -142,6 +148,7 @@ static int map_create(union bpf_attr *attr)
return PTR_ERR(map);
atomic_set(&map->refcnt, 1);
+ atomic_set(&map->usercnt, 1);
err = bpf_map_charge_memlock(map);
if (err)
@@ -174,7 +181,14 @@ struct bpf_map *__bpf_map_get(struct fd f)
return f.file->private_data;
}
-struct bpf_map *bpf_map_get(u32 ufd)
+void bpf_map_inc(struct bpf_map *map, bool uref)
+{
+ atomic_inc(&map->refcnt);
+ if (uref)
+ atomic_inc(&map->usercnt);
+}
+
+struct bpf_map *bpf_map_get_with_uref(u32 ufd)
{
struct fd f = fdget(ufd);
struct bpf_map *map;
@@ -183,7 +197,7 @@ struct bpf_map *bpf_map_get(u32 ufd)
if (IS_ERR(map))
return map;
- atomic_inc(&map->refcnt);
+ bpf_map_inc(map, true);
fdput(f);
return map;
@@ -226,7 +240,7 @@ static int map_lookup_elem(union bpf_attr *attr)
goto free_key;
err = -ENOMEM;
- value = kmalloc(map->value_size, GFP_USER);
+ value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);
if (!value)
goto free_key;
@@ -285,7 +299,7 @@ static int map_update_elem(union bpf_attr *attr)
goto free_key;
err = -ENOMEM;
- value = kmalloc(map->value_size, GFP_USER);
+ value = kmalloc(map->value_size, GFP_USER | __GFP_NOWARN);
if (!value)
goto free_key;
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index c607305..a7945d1 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2021,8 +2021,7 @@ static int replace_map_fd_with_map_ptr(struct verifier_env *env)
* will be used by the valid program until it's unloaded
* and all maps are released in free_bpf_prog_info()
*/
- atomic_inc(&map->refcnt);
-
+ bpf_map_inc(map, false);
fdput(f);
next_insn:
insn++;
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index f1603c1..470f653 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -98,6 +98,12 @@ static DEFINE_SPINLOCK(css_set_lock);
static DEFINE_SPINLOCK(cgroup_idr_lock);
/*
+ * Protects cgroup_file->kn for !self csses. It synchronizes notifications
+ * against file removal/re-creation across css hiding.
+ */
+static DEFINE_SPINLOCK(cgroup_file_kn_lock);
+
+/*
* Protects cgroup_subsys->release_agent_path. Modifying it also requires
* cgroup_mutex. Reading requires either cgroup_mutex or this spinlock.
*/
@@ -754,9 +760,11 @@ static void put_css_set_locked(struct css_set *cset)
if (!atomic_dec_and_test(&cset->refcount))
return;
- /* This css_set is dead. unlink it and release cgroup refcounts */
- for_each_subsys(ss, ssid)
+ /* This css_set is dead. unlink it and release cgroup and css refs */
+ for_each_subsys(ss, ssid) {
list_del(&cset->e_cset_node[ssid]);
+ css_put(cset->subsys[ssid]);
+ }
hash_del(&cset->hlist);
css_set_count--;
@@ -1056,9 +1064,13 @@ static struct css_set *find_css_set(struct css_set *old_cset,
key = css_set_hash(cset->subsys);
hash_add(css_set_table, &cset->hlist, key);
- for_each_subsys(ss, ssid)
+ for_each_subsys(ss, ssid) {
+ struct cgroup_subsys_state *css = cset->subsys[ssid];
+
list_add_tail(&cset->e_cset_node[ssid],
- &cset->subsys[ssid]->cgroup->e_csets[ssid]);
+ &css->cgroup->e_csets[ssid]);
+ css_get(css);
+ }
spin_unlock_bh(&css_set_lock);
@@ -1393,6 +1405,16 @@ static void cgroup_rm_file(struct cgroup *cgrp, const struct cftype *cft)
char name[CGROUP_FILE_NAME_MAX];
lockdep_assert_held(&cgroup_mutex);
+
+ if (cft->file_offset) {
+ struct cgroup_subsys_state *css = cgroup_css(cgrp, cft->ss);
+ struct cgroup_file *cfile = (void *)css + cft->file_offset;
+
+ spin_lock_irq(&cgroup_file_kn_lock);
+ cfile->kn = NULL;
+ spin_unlock_irq(&cgroup_file_kn_lock);
+ }
+
kernfs_remove_by_name(cgrp->kn, cgroup_file_name(cgrp, cft, name));
}
@@ -1856,7 +1878,6 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp)
INIT_LIST_HEAD(&cgrp->self.sibling);
INIT_LIST_HEAD(&cgrp->self.children);
- INIT_LIST_HEAD(&cgrp->self.files);
INIT_LIST_HEAD(&cgrp->cset_links);
INIT_LIST_HEAD(&cgrp->pidlists);
mutex_init(&cgrp->pidlist_mutex);
@@ -2216,6 +2237,9 @@ struct cgroup_taskset {
struct list_head src_csets;
struct list_head dst_csets;
+ /* the subsys currently being processed */
+ int ssid;
+
/*
* Fields for cgroup_taskset_*() iteration.
*
@@ -2278,25 +2302,29 @@ static void cgroup_taskset_add(struct task_struct *task,
/**
* cgroup_taskset_first - reset taskset and return the first task
* @tset: taskset of interest
+ * @dst_cssp: output variable for the destination css
*
* @tset iteration is initialized and the first task is returned.
*/
-struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset)
+struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,
+ struct cgroup_subsys_state **dst_cssp)
{
tset->cur_cset = list_first_entry(tset->csets, struct css_set, mg_node);
tset->cur_task = NULL;
- return cgroup_taskset_next(tset);
+ return cgroup_taskset_next(tset, dst_cssp);
}
/**
* cgroup_taskset_next - iterate to the next task in taskset
* @tset: taskset of interest
+ * @dst_cssp: output variable for the destination css
*
* Return the next task in @tset. Iteration must have been initialized
* with cgroup_taskset_first().
*/
-struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
+struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset,
+ struct cgroup_subsys_state **dst_cssp)
{
struct css_set *cset = tset->cur_cset;
struct task_struct *task = tset->cur_task;
@@ -2311,6 +2339,18 @@ struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset)
if (&task->cg_list != &cset->mg_tasks) {
tset->cur_cset = cset;
tset->cur_task = task;
+
+ /*
+ * This function may be called both before and
+ * after cgroup_taskset_migrate(). The two cases
+ * can be distinguished by looking at whether @cset
+ * has its ->mg_dst_cset set.
+ */
+ if (cset->mg_dst_cset)
+ *dst_cssp = cset->mg_dst_cset->subsys[tset->ssid];
+ else
+ *dst_cssp = cset->subsys[tset->ssid];
+
return task;
}
@@ -2346,7 +2386,8 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset,
/* check that we can legitimately attach to the cgroup */
for_each_e_css(css, i, dst_cgrp) {
if (css->ss->can_attach) {
- ret = css->ss->can_attach(css, tset);
+ tset->ssid = i;
+ ret = css->ss->can_attach(tset);
if (ret) {
failed_css = css;
goto out_cancel_attach;
@@ -2379,9 +2420,12 @@ static int cgroup_taskset_migrate(struct cgroup_taskset *tset,
*/
tset->csets = &tset->dst_csets;
- for_each_e_css(css, i, dst_cgrp)
- if (css->ss->attach)
- css->ss->attach(css, tset);
+ for_each_e_css(css, i, dst_cgrp) {
+ if (css->ss->attach) {
+ tset->ssid = i;
+ css->ss->attach(tset);
+ }
+ }
ret = 0;
goto out_release_tset;
@@ -2390,8 +2434,10 @@ out_cancel_attach:
for_each_e_css(css, i, dst_cgrp) {
if (css == failed_css)
break;
- if (css->ss->cancel_attach)
- css->ss->cancel_attach(css, tset);
+ if (css->ss->cancel_attach) {
+ tset->ssid = i;
+ css->ss->cancel_attach(tset);
+ }
}
out_release_tset:
spin_lock_bh(&css_set_lock);
@@ -3313,9 +3359,9 @@ static int cgroup_add_file(struct cgroup_subsys_state *css, struct cgroup *cgrp,
if (cft->file_offset) {
struct cgroup_file *cfile = (void *)css + cft->file_offset;
- kernfs_get(kn);
+ spin_lock_irq(&cgroup_file_kn_lock);
cfile->kn = kn;
- list_add(&cfile->node, &css->files);
+ spin_unlock_irq(&cgroup_file_kn_lock);
}
return 0;
@@ -3553,6 +3599,22 @@ int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts)
}
/**
+ * cgroup_file_notify - generate a file modified event for a cgroup_file
+ * @cfile: target cgroup_file
+ *
+ * @cfile must have been obtained by setting cftype->file_offset.
+ */
+void cgroup_file_notify(struct cgroup_file *cfile)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cgroup_file_kn_lock, flags);
+ if (cfile->kn)
+ kernfs_notify(cfile->kn);
+ spin_unlock_irqrestore(&cgroup_file_kn_lock, flags);
+}
+
+/**
* cgroup_task_count - count the number of tasks in a cgroup.
* @cgrp: the cgroup in question
*
@@ -4613,13 +4675,9 @@ static void css_free_work_fn(struct work_struct *work)
container_of(work, struct cgroup_subsys_state, destroy_work);
struct cgroup_subsys *ss = css->ss;
struct cgroup *cgrp = css->cgroup;
- struct cgroup_file *cfile;
percpu_ref_exit(&css->refcnt);
- list_for_each_entry(cfile, &css->files, node)
- kernfs_put(cfile->kn);
-
if (ss) {
/* css free path */
int id = css->id;
@@ -4724,7 +4782,6 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
css->ss = ss;
INIT_LIST_HEAD(&css->sibling);
INIT_LIST_HEAD(&css->children);
- INIT_LIST_HEAD(&css->files);
css->serial_nr = css_serial_nr_next++;
if (cgroup_parent(cgrp)) {
diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c
index f1b30ad..2d3df82 100644
--- a/kernel/cgroup_freezer.c
+++ b/kernel/cgroup_freezer.c
@@ -155,12 +155,10 @@ static void freezer_css_free(struct cgroup_subsys_state *css)
* @freezer->lock. freezer_attach() makes the new tasks conform to the
* current state and all following state changes can see the new tasks.
*/
-static void freezer_attach(struct cgroup_subsys_state *new_css,
- struct cgroup_taskset *tset)
+static void freezer_attach(struct cgroup_taskset *tset)
{
- struct freezer *freezer = css_freezer(new_css);
struct task_struct *task;
- bool clear_frozen = false;
+ struct cgroup_subsys_state *new_css;
mutex_lock(&freezer_mutex);
@@ -174,22 +172,21 @@ static void freezer_attach(struct cgroup_subsys_state *new_css,
* current state before executing the following - !frozen tasks may
* be visible in a FROZEN cgroup and frozen tasks in a THAWED one.
*/
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, new_css, tset) {
+ struct freezer *freezer = css_freezer(new_css);
+
if (!(freezer->state & CGROUP_FREEZING)) {
__thaw_task(task);
} else {
freeze_task(task);
- freezer->state &= ~CGROUP_FROZEN;
- clear_frozen = true;
+ /* clear FROZEN and propagate upwards */
+ while (freezer && (freezer->state & CGROUP_FROZEN)) {
+ freezer->state &= ~CGROUP_FROZEN;
+ freezer = parent_freezer(freezer);
+ }
}
}
- /* propagate FROZEN clearing upwards */
- while (clear_frozen && (freezer = parent_freezer(freezer))) {
- freezer->state &= ~CGROUP_FROZEN;
- clear_frozen = freezer->state & CGROUP_FREEZING;
- }
-
mutex_unlock(&freezer_mutex);
}
diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c
index cdd8df4..b50d5a1 100644
--- a/kernel/cgroup_pids.c
+++ b/kernel/cgroup_pids.c
@@ -106,7 +106,7 @@ static void pids_uncharge(struct pids_cgroup *pids, int num)
{
struct pids_cgroup *p;
- for (p = pids; p; p = parent_pids(p))
+ for (p = pids; parent_pids(p); p = parent_pids(p))
pids_cancel(p, num);
}
@@ -123,7 +123,7 @@ static void pids_charge(struct pids_cgroup *pids, int num)
{
struct pids_cgroup *p;
- for (p = pids; p; p = parent_pids(p))
+ for (p = pids; parent_pids(p); p = parent_pids(p))
atomic64_add(num, &p->counter);
}
@@ -140,7 +140,7 @@ static int pids_try_charge(struct pids_cgroup *pids, int num)
{
struct pids_cgroup *p, *q;
- for (p = pids; p; p = parent_pids(p)) {
+ for (p = pids; parent_pids(p); p = parent_pids(p)) {
int64_t new = atomic64_add_return(num, &p->counter);
/*
@@ -162,13 +162,13 @@ revert:
return -EAGAIN;
}
-static int pids_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int pids_can_attach(struct cgroup_taskset *tset)
{
- struct pids_cgroup *pids = css_pids(css);
struct task_struct *task;
+ struct cgroup_subsys_state *dst_css;
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, dst_css, tset) {
+ struct pids_cgroup *pids = css_pids(dst_css);
struct cgroup_subsys_state *old_css;
struct pids_cgroup *old_pids;
@@ -187,13 +187,13 @@ static int pids_can_attach(struct cgroup_subsys_state *css,
return 0;
}
-static void pids_cancel_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void pids_cancel_attach(struct cgroup_taskset *tset)
{
- struct pids_cgroup *pids = css_pids(css);
struct task_struct *task;
+ struct cgroup_subsys_state *dst_css;
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, dst_css, tset) {
+ struct pids_cgroup *pids = css_pids(dst_css);
struct cgroup_subsys_state *old_css;
struct pids_cgroup *old_pids;
@@ -205,65 +205,28 @@ static void pids_cancel_attach(struct cgroup_subsys_state *css,
}
}
+/*
+ * task_css_check(true) in pids_can_fork() and pids_cancel_fork() relies
+ * on threadgroup_change_begin() held by the copy_process().
+ */
static int pids_can_fork(struct task_struct *task, void **priv_p)
{
struct cgroup_subsys_state *css;
struct pids_cgroup *pids;
- int err;
- /*
- * Use the "current" task_css for the pids subsystem as the tentative
- * css. It is possible we will charge the wrong hierarchy, in which
- * case we will forcefully revert/reapply the charge on the right
- * hierarchy after it is committed to the task proper.
- */
- css = task_get_css(current, pids_cgrp_id);
+ css = task_css_check(current, pids_cgrp_id, true);
pids = css_pids(css);
-
- err = pids_try_charge(pids, 1);
- if (err)
- goto err_css_put;
-
- *priv_p = css;
- return 0;
-
-err_css_put:
- css_put(css);
- return err;
+ return pids_try_charge(pids, 1);
}
static void pids_cancel_fork(struct task_struct *task, void *priv)
{
- struct cgroup_subsys_state *css = priv;
- struct pids_cgroup *pids = css_pids(css);
-
- pids_uncharge(pids, 1);
- css_put(css);
-}
-
-static void pids_fork(struct task_struct *task, void *priv)
-{
struct cgroup_subsys_state *css;
- struct cgroup_subsys_state *old_css = priv;
struct pids_cgroup *pids;
- struct pids_cgroup *old_pids = css_pids(old_css);
- css = task_get_css(task, pids_cgrp_id);
+ css = task_css_check(current, pids_cgrp_id, true);
pids = css_pids(css);
-
- /*
- * If the association has changed, we have to revert and reapply the
- * charge/uncharge on the wrong hierarchy to the current one. Since
- * the association can only change due to an organisation event, its
- * okay for us to ignore the limit in this case.
- */
- if (pids != old_pids) {
- pids_uncharge(old_pids, 1);
- pids_charge(pids, 1);
- }
-
- css_put(css);
- css_put(old_css);
+ pids_uncharge(pids, 1);
}
static void pids_free(struct task_struct *task)
@@ -335,6 +298,7 @@ static struct cftype pids_files[] = {
{
.name = "current",
.read_s64 = pids_current_read,
+ .flags = CFTYPE_NOT_ON_ROOT,
},
{ } /* terminate */
};
@@ -346,7 +310,6 @@ struct cgroup_subsys pids_cgrp_subsys = {
.cancel_attach = pids_cancel_attach,
.can_fork = pids_can_fork,
.cancel_fork = pids_cancel_fork,
- .fork = pids_fork,
.free = pids_free,
.legacy_cftypes = pids_files,
.dfl_cftypes = pids_files,
diff --git a/kernel/context_tracking.c b/kernel/context_tracking.c
index 0a495ab..9ad37b9 100644
--- a/kernel/context_tracking.c
+++ b/kernel/context_tracking.c
@@ -24,7 +24,7 @@
#define CREATE_TRACE_POINTS
#include <trace/events/context_tracking.h>
-struct static_key context_tracking_enabled = STATIC_KEY_INIT_FALSE;
+DEFINE_STATIC_KEY_FALSE(context_tracking_enabled);
EXPORT_SYMBOL_GPL(context_tracking_enabled);
DEFINE_PER_CPU(struct context_tracking, context_tracking);
@@ -58,36 +58,13 @@ static void context_tracking_recursion_exit(void)
* instructions to execute won't use any RCU read side critical section
* because this function sets RCU in extended quiescent state.
*/
-void context_tracking_enter(enum ctx_state state)
+void __context_tracking_enter(enum ctx_state state)
{
- unsigned long flags;
-
- /*
- * Repeat the user_enter() check here because some archs may be calling
- * this from asm and if no CPU needs context tracking, they shouldn't
- * go further. Repeat the check here until they support the inline static
- * key check.
- */
- if (!context_tracking_is_enabled())
- return;
-
- /*
- * Some contexts may involve an exception occuring in an irq,
- * leading to that nesting:
- * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
- * This would mess up the dyntick_nesting count though. And rcu_irq_*()
- * helpers are enough to protect RCU uses inside the exception. So
- * just return immediately if we detect we are in an IRQ.
- */
- if (in_interrupt())
- return;
-
/* Kernel threads aren't supposed to go to userspace */
WARN_ON_ONCE(!current->mm);
- local_irq_save(flags);
if (!context_tracking_recursion_enter())
- goto out_irq_restore;
+ return;
if ( __this_cpu_read(context_tracking.state) != state) {
if (__this_cpu_read(context_tracking.active)) {
@@ -120,7 +97,27 @@ void context_tracking_enter(enum ctx_state state)
__this_cpu_write(context_tracking.state, state);
}
context_tracking_recursion_exit();
-out_irq_restore:
+}
+NOKPROBE_SYMBOL(__context_tracking_enter);
+EXPORT_SYMBOL_GPL(__context_tracking_enter);
+
+void context_tracking_enter(enum ctx_state state)
+{
+ unsigned long flags;
+
+ /*
+ * Some contexts may involve an exception occuring in an irq,
+ * leading to that nesting:
+ * rcu_irq_enter() rcu_user_exit() rcu_user_exit() rcu_irq_exit()
+ * This would mess up the dyntick_nesting count though. And rcu_irq_*()
+ * helpers are enough to protect RCU uses inside the exception. So
+ * just return immediately if we detect we are in an IRQ.
+ */
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+ __context_tracking_enter(state);
local_irq_restore(flags);
}
NOKPROBE_SYMBOL(context_tracking_enter);
@@ -128,7 +125,7 @@ EXPORT_SYMBOL_GPL(context_tracking_enter);
void context_tracking_user_enter(void)
{
- context_tracking_enter(CONTEXT_USER);
+ user_enter();
}
NOKPROBE_SYMBOL(context_tracking_user_enter);
@@ -144,19 +141,10 @@ NOKPROBE_SYMBOL(context_tracking_user_enter);
* This call supports re-entrancy. This way it can be called from any exception
* handler without needing to know if we came from userspace or not.
*/
-void context_tracking_exit(enum ctx_state state)
+void __context_tracking_exit(enum ctx_state state)
{
- unsigned long flags;
-
- if (!context_tracking_is_enabled())
- return;
-
- if (in_interrupt())
- return;
-
- local_irq_save(flags);
if (!context_tracking_recursion_enter())
- goto out_irq_restore;
+ return;
if (__this_cpu_read(context_tracking.state) == state) {
if (__this_cpu_read(context_tracking.active)) {
@@ -173,7 +161,19 @@ void context_tracking_exit(enum ctx_state state)
__this_cpu_write(context_tracking.state, CONTEXT_KERNEL);
}
context_tracking_recursion_exit();
-out_irq_restore:
+}
+NOKPROBE_SYMBOL(__context_tracking_exit);
+EXPORT_SYMBOL_GPL(__context_tracking_exit);
+
+void context_tracking_exit(enum ctx_state state)
+{
+ unsigned long flags;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+ __context_tracking_exit(state);
local_irq_restore(flags);
}
NOKPROBE_SYMBOL(context_tracking_exit);
@@ -181,7 +181,7 @@ EXPORT_SYMBOL_GPL(context_tracking_exit);
void context_tracking_user_exit(void)
{
- context_tracking_exit(CONTEXT_USER);
+ user_exit();
}
NOKPROBE_SYMBOL(context_tracking_user_exit);
@@ -191,7 +191,7 @@ void __init context_tracking_cpu_set(int cpu)
if (!per_cpu(context_tracking.active, cpu)) {
per_cpu(context_tracking.active, cpu) = true;
- static_key_slow_inc(&context_tracking_enabled);
+ static_branch_inc(&context_tracking_enabled);
}
if (initialized)
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 10ae736..02a8ea5 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1429,15 +1429,16 @@ static int fmeter_getrate(struct fmeter *fmp)
static struct cpuset *cpuset_attach_old_cs;
/* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
-static int cpuset_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int cpuset_can_attach(struct cgroup_taskset *tset)
{
- struct cpuset *cs = css_cs(css);
+ struct cgroup_subsys_state *css;
+ struct cpuset *cs;
struct task_struct *task;
int ret;
/* used later by cpuset_attach() */
- cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset));
+ cpuset_attach_old_cs = task_cs(cgroup_taskset_first(tset, &css));
+ cs = css_cs(css);
mutex_lock(&cpuset_mutex);
@@ -1447,7 +1448,7 @@ static int cpuset_can_attach(struct cgroup_subsys_state *css,
(cpumask_empty(cs->cpus_allowed) || nodes_empty(cs->mems_allowed)))
goto out_unlock;
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, css, tset) {
ret = task_can_attach(task, cs->cpus_allowed);
if (ret)
goto out_unlock;
@@ -1467,9 +1468,14 @@ out_unlock:
return ret;
}
-static void cpuset_cancel_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void cpuset_cancel_attach(struct cgroup_taskset *tset)
{
+ struct cgroup_subsys_state *css;
+ struct cpuset *cs;
+
+ cgroup_taskset_first(tset, &css);
+ cs = css_cs(css);
+
mutex_lock(&cpuset_mutex);
css_cs(css)->attach_in_progress--;
mutex_unlock(&cpuset_mutex);
@@ -1482,16 +1488,19 @@ static void cpuset_cancel_attach(struct cgroup_subsys_state *css,
*/
static cpumask_var_t cpus_attach;
-static void cpuset_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void cpuset_attach(struct cgroup_taskset *tset)
{
/* static buf protected by cpuset_mutex */
static nodemask_t cpuset_attach_nodemask_to;
struct task_struct *task;
struct task_struct *leader;
- struct cpuset *cs = css_cs(css);
+ struct cgroup_subsys_state *css;
+ struct cpuset *cs;
struct cpuset *oldcs = cpuset_attach_old_cs;
+ cgroup_taskset_first(tset, &css);
+ cs = css_cs(css);
+
mutex_lock(&cpuset_mutex);
/* prepare for attach */
@@ -1502,7 +1511,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css,
guarantee_online_mems(cs, &cpuset_attach_nodemask_to);
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, css, tset) {
/*
* can_attach beforehand should guarantee that this doesn't
* fail. TODO: have a better way to handle failure here
@@ -1518,7 +1527,7 @@ static void cpuset_attach(struct cgroup_subsys_state *css,
* sleep and should be moved outside migration path proper.
*/
cpuset_attach_nodemask_to = cs->effective_mems;
- cgroup_taskset_for_each_leader(leader, tset) {
+ cgroup_taskset_for_each_leader(leader, css, tset) {
struct mm_struct *mm = get_task_mm(leader);
if (mm) {
diff --git a/kernel/events/callchain.c b/kernel/events/callchain.c
index d659487..9c41800 100644
--- a/kernel/events/callchain.c
+++ b/kernel/events/callchain.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
* Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* For licensing details see kernel-base/COPYING
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1a734e0..bf82441 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
* Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* For licensing details see kernel-base/COPYING
@@ -126,6 +126,37 @@ static int cpu_function_call(int cpu, remote_function_f func, void *info)
return data.ret;
}
+static void event_function_call(struct perf_event *event,
+ int (*active)(void *),
+ void (*inactive)(void *),
+ void *data)
+{
+ struct perf_event_context *ctx = event->ctx;
+ struct task_struct *task = ctx->task;
+
+ if (!task) {
+ cpu_function_call(event->cpu, active, data);
+ return;
+ }
+
+again:
+ if (!task_function_call(task, active, data))
+ return;
+
+ raw_spin_lock_irq(&ctx->lock);
+ if (ctx->is_active) {
+ /*
+ * Reload the task pointer, it might have been changed by
+ * a concurrent perf_event_context_sched_out().
+ */
+ task = ctx->task;
+ raw_spin_unlock_irq(&ctx->lock);
+ goto again;
+ }
+ inactive(data);
+ raw_spin_unlock_irq(&ctx->lock);
+}
+
#define EVENT_OWNER_KERNEL ((void *) -1)
static bool is_kernel_event(struct perf_event *event)
@@ -435,7 +466,7 @@ static inline void update_cgrp_time_from_event(struct perf_event *event)
if (!is_cgroup_event(event))
return;
- cgrp = perf_cgroup_from_task(current);
+ cgrp = perf_cgroup_from_task(current, event->ctx);
/*
* Do not update time when cgroup is not active
*/
@@ -458,7 +489,7 @@ perf_cgroup_set_timestamp(struct task_struct *task,
if (!task || !ctx->nr_cgroups)
return;
- cgrp = perf_cgroup_from_task(task);
+ cgrp = perf_cgroup_from_task(task, ctx);
info = this_cpu_ptr(cgrp->info);
info->timestamp = ctx->timestamp;
}
@@ -489,7 +520,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
* we reschedule only in the presence of cgroup
* constrained events.
*/
- rcu_read_lock();
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = this_cpu_ptr(pmu->pmu_cpu_context);
@@ -522,8 +552,10 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
* set cgrp before ctxsw in to allow
* event_filter_match() to not have to pass
* task around
+ * we pass the cpuctx->ctx to perf_cgroup_from_task()
+ * because cgorup events are only per-cpu
*/
- cpuctx->cgrp = perf_cgroup_from_task(task);
+ cpuctx->cgrp = perf_cgroup_from_task(task, &cpuctx->ctx);
cpu_ctx_sched_in(cpuctx, EVENT_ALL, task);
}
perf_pmu_enable(cpuctx->ctx.pmu);
@@ -531,8 +563,6 @@ static void perf_cgroup_switch(struct task_struct *task, int mode)
}
}
- rcu_read_unlock();
-
local_irq_restore(flags);
}
@@ -542,17 +572,20 @@ static inline void perf_cgroup_sched_out(struct task_struct *task,
struct perf_cgroup *cgrp1;
struct perf_cgroup *cgrp2 = NULL;
+ rcu_read_lock();
/*
* we come here when we know perf_cgroup_events > 0
+ * we do not need to pass the ctx here because we know
+ * we are holding the rcu lock
*/
- cgrp1 = perf_cgroup_from_task(task);
+ cgrp1 = perf_cgroup_from_task(task, NULL);
/*
* next is NULL when called from perf_event_enable_on_exec()
* that will systematically cause a cgroup_switch()
*/
if (next)
- cgrp2 = perf_cgroup_from_task(next);
+ cgrp2 = perf_cgroup_from_task(next, NULL);
/*
* only schedule out current cgroup events if we know
@@ -561,6 +594,8 @@ static inline void perf_cgroup_sched_out(struct task_struct *task,
*/
if (cgrp1 != cgrp2)
perf_cgroup_switch(task, PERF_CGROUP_SWOUT);
+
+ rcu_read_unlock();
}
static inline void perf_cgroup_sched_in(struct task_struct *prev,
@@ -569,13 +604,16 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev,
struct perf_cgroup *cgrp1;
struct perf_cgroup *cgrp2 = NULL;
+ rcu_read_lock();
/*
* we come here when we know perf_cgroup_events > 0
+ * we do not need to pass the ctx here because we know
+ * we are holding the rcu lock
*/
- cgrp1 = perf_cgroup_from_task(task);
+ cgrp1 = perf_cgroup_from_task(task, NULL);
/* prev can never be NULL */
- cgrp2 = perf_cgroup_from_task(prev);
+ cgrp2 = perf_cgroup_from_task(prev, NULL);
/*
* only need to schedule in cgroup events if we are changing
@@ -584,6 +622,8 @@ static inline void perf_cgroup_sched_in(struct task_struct *prev,
*/
if (cgrp1 != cgrp2)
perf_cgroup_switch(task, PERF_CGROUP_SWIN);
+
+ rcu_read_unlock();
}
static inline int perf_cgroup_connect(int fd, struct perf_event *event,
@@ -1050,13 +1090,13 @@ retry:
/*
* One of the few rules of preemptible RCU is that one cannot do
* rcu_read_unlock() while holding a scheduler (or nested) lock when
- * part of the read side critical section was preemptible -- see
+ * part of the read side critical section was irqs-enabled -- see
* rcu_read_unlock_special().
*
* Since ctx->lock nests under rq->lock we must ensure the entire read
- * side critical section is non-preemptible.
+ * side critical section has interrupts disabled.
*/
- preempt_disable();
+ local_irq_save(*flags);
rcu_read_lock();
ctx = rcu_dereference(task->perf_event_ctxp[ctxn]);
if (ctx) {
@@ -1070,21 +1110,22 @@ retry:
* if so. If we locked the right context, then it
* can't get swapped on us any more.
*/
- raw_spin_lock_irqsave(&ctx->lock, *flags);
+ raw_spin_lock(&ctx->lock);
if (ctx != rcu_dereference(task->perf_event_ctxp[ctxn])) {
- raw_spin_unlock_irqrestore(&ctx->lock, *flags);
+ raw_spin_unlock(&ctx->lock);
rcu_read_unlock();
- preempt_enable();
+ local_irq_restore(*flags);
goto retry;
}
if (!atomic_inc_not_zero(&ctx->refcount)) {
- raw_spin_unlock_irqrestore(&ctx->lock, *flags);
+ raw_spin_unlock(&ctx->lock);
ctx = NULL;
}
}
rcu_read_unlock();
- preempt_enable();
+ if (!ctx)
+ local_irq_restore(*flags);
return ctx;
}
@@ -1619,6 +1660,17 @@ struct remove_event {
bool detach_group;
};
+static void ___perf_remove_from_context(void *info)
+{
+ struct remove_event *re = info;
+ struct perf_event *event = re->event;
+ struct perf_event_context *ctx = event->ctx;
+
+ if (re->detach_group)
+ perf_group_detach(event);
+ list_del_event(event, ctx);
+}
+
/*
* Cross CPU call to remove a performance event
*
@@ -1646,7 +1698,6 @@ static int __perf_remove_from_context(void *info)
return 0;
}
-
/*
* Remove the event from a task's (or a CPU's) list of events.
*
@@ -1663,7 +1714,6 @@ static int __perf_remove_from_context(void *info)
static void perf_remove_from_context(struct perf_event *event, bool detach_group)
{
struct perf_event_context *ctx = event->ctx;
- struct task_struct *task = ctx->task;
struct remove_event re = {
.event = event,
.detach_group = detach_group,
@@ -1671,44 +1721,8 @@ static void perf_remove_from_context(struct perf_event *event, bool detach_group
lockdep_assert_held(&ctx->mutex);
- if (!task) {
- /*
- * Per cpu events are removed via an smp call. The removal can
- * fail if the CPU is currently offline, but in that case we
- * already called __perf_remove_from_context from
- * perf_event_exit_cpu.
- */
- cpu_function_call(event->cpu, __perf_remove_from_context, &re);
- return;
- }
-
-retry:
- if (!task_function_call(task, __perf_remove_from_context, &re))
- return;
-
- raw_spin_lock_irq(&ctx->lock);
- /*
- * If we failed to find a running task, but find the context active now
- * that we've acquired the ctx->lock, retry.
- */
- if (ctx->is_active) {
- raw_spin_unlock_irq(&ctx->lock);
- /*
- * Reload the task pointer, it might have been changed by
- * a concurrent perf_event_context_sched_out().
- */
- task = ctx->task;
- goto retry;
- }
-
- /*
- * Since the task isn't running, its safe to remove the event, us
- * holding the ctx->lock ensures the task won't get scheduled in.
- */
- if (detach_group)
- perf_group_detach(event);
- list_del_event(event, ctx);
- raw_spin_unlock_irq(&ctx->lock);
+ event_function_call(event, __perf_remove_from_context,
+ ___perf_remove_from_context, &re);
}
/*
@@ -1752,6 +1766,20 @@ int __perf_event_disable(void *info)
return 0;
}
+void ___perf_event_disable(void *info)
+{
+ struct perf_event *event = info;
+
+ /*
+ * Since we have the lock this context can't be scheduled
+ * in, so we can change the state safely.
+ */
+ if (event->state == PERF_EVENT_STATE_INACTIVE) {
+ update_group_times(event);
+ event->state = PERF_EVENT_STATE_OFF;
+ }
+}
+
/*
* Disable a event.
*
@@ -1768,43 +1796,16 @@ int __perf_event_disable(void *info)
static void _perf_event_disable(struct perf_event *event)
{
struct perf_event_context *ctx = event->ctx;
- struct task_struct *task = ctx->task;
-
- if (!task) {
- /*
- * Disable the event on the cpu that it's on
- */
- cpu_function_call(event->cpu, __perf_event_disable, event);
- return;
- }
-
-retry:
- if (!task_function_call(task, __perf_event_disable, event))
- return;
raw_spin_lock_irq(&ctx->lock);
- /*
- * If the event is still active, we need to retry the cross-call.
- */
- if (event->state == PERF_EVENT_STATE_ACTIVE) {
+ if (event->state <= PERF_EVENT_STATE_OFF) {
raw_spin_unlock_irq(&ctx->lock);
- /*
- * Reload the task pointer, it might have been changed by
- * a concurrent perf_event_context_sched_out().
- */
- task = ctx->task;
- goto retry;
- }
-
- /*
- * Since we have the lock this context can't be scheduled
- * in, so we can change the state safely.
- */
- if (event->state == PERF_EVENT_STATE_INACTIVE) {
- update_group_times(event);
- event->state = PERF_EVENT_STATE_OFF;
+ return;
}
raw_spin_unlock_irq(&ctx->lock);
+
+ event_function_call(event, __perf_event_disable,
+ ___perf_event_disable, event);
}
/*
@@ -2057,6 +2058,18 @@ static void perf_event_sched_in(struct perf_cpu_context *cpuctx,
ctx_sched_in(ctx, cpuctx, EVENT_FLEXIBLE, task);
}
+static void ___perf_install_in_context(void *info)
+{
+ struct perf_event *event = info;
+ struct perf_event_context *ctx = event->ctx;
+
+ /*
+ * Since the task isn't running, its safe to add the event, us holding
+ * the ctx->lock ensures the task won't get scheduled in.
+ */
+ add_event_to_ctx(event, ctx);
+}
+
/*
* Cross CPU call to install and enable a performance event
*
@@ -2133,48 +2146,14 @@ perf_install_in_context(struct perf_event_context *ctx,
struct perf_event *event,
int cpu)
{
- struct task_struct *task = ctx->task;
-
lockdep_assert_held(&ctx->mutex);
event->ctx = ctx;
if (event->cpu != -1)
event->cpu = cpu;
- if (!task) {
- /*
- * Per cpu events are installed via an smp call and
- * the install is always successful.
- */
- cpu_function_call(cpu, __perf_install_in_context, event);
- return;
- }
-
-retry:
- if (!task_function_call(task, __perf_install_in_context, event))
- return;
-
- raw_spin_lock_irq(&ctx->lock);
- /*
- * If we failed to find a running task, but find the context active now
- * that we've acquired the ctx->lock, retry.
- */
- if (ctx->is_active) {
- raw_spin_unlock_irq(&ctx->lock);
- /*
- * Reload the task pointer, it might have been changed by
- * a concurrent perf_event_context_sched_out().
- */
- task = ctx->task;
- goto retry;
- }
-
- /*
- * Since the task isn't running, its safe to add the event, us holding
- * the ctx->lock ensures the task won't get scheduled in.
- */
- add_event_to_ctx(event, ctx);
- raw_spin_unlock_irq(&ctx->lock);
+ event_function_call(event, __perf_install_in_context,
+ ___perf_install_in_context, event);
}
/*
@@ -2277,6 +2256,11 @@ unlock:
return 0;
}
+void ___perf_event_enable(void *info)
+{
+ __perf_event_mark_enabled((struct perf_event *)info);
+}
+
/*
* Enable a event.
*
@@ -2289,58 +2273,26 @@ unlock:
static void _perf_event_enable(struct perf_event *event)
{
struct perf_event_context *ctx = event->ctx;
- struct task_struct *task = ctx->task;
- if (!task) {
- /*
- * Enable the event on the cpu that it's on
- */
- cpu_function_call(event->cpu, __perf_event_enable, event);
+ raw_spin_lock_irq(&ctx->lock);
+ if (event->state >= PERF_EVENT_STATE_INACTIVE) {
+ raw_spin_unlock_irq(&ctx->lock);
return;
}
- raw_spin_lock_irq(&ctx->lock);
- if (event->state >= PERF_EVENT_STATE_INACTIVE)
- goto out;
-
/*
* If the event is in error state, clear that first.
- * That way, if we see the event in error state below, we
- * know that it has gone back into error state, as distinct
- * from the task having been scheduled away before the
- * cross-call arrived.
+ *
+ * That way, if we see the event in error state below, we know that it
+ * has gone back into error state, as distinct from the task having
+ * been scheduled away before the cross-call arrived.
*/
if (event->state == PERF_EVENT_STATE_ERROR)
event->state = PERF_EVENT_STATE_OFF;
-
-retry:
- if (!ctx->is_active) {
- __perf_event_mark_enabled(event);
- goto out;
- }
-
raw_spin_unlock_irq(&ctx->lock);
- if (!task_function_call(task, __perf_event_enable, event))
- return;
-
- raw_spin_lock_irq(&ctx->lock);
-
- /*
- * If the context is active and the event is still off,
- * we need to retry the cross-call.
- */
- if (ctx->is_active && event->state == PERF_EVENT_STATE_OFF) {
- /*
- * task could have been flipped by a concurrent
- * perf_event_context_sched_out()
- */
- task = ctx->task;
- goto retry;
- }
-
-out:
- raw_spin_unlock_irq(&ctx->lock);
+ event_function_call(event, __perf_event_enable,
+ ___perf_event_enable, event);
}
/*
@@ -3144,15 +3096,16 @@ static int event_enable_on_exec(struct perf_event *event,
* Enable all of a task's events that have been marked enable-on-exec.
* This expects task == current.
*/
-static void perf_event_enable_on_exec(struct perf_event_context *ctx)
+static void perf_event_enable_on_exec(int ctxn)
{
- struct perf_event_context *clone_ctx = NULL;
+ struct perf_event_context *ctx, *clone_ctx = NULL;
struct perf_event *event;
unsigned long flags;
int enabled = 0;
int ret;
local_irq_save(flags);
+ ctx = current->perf_event_ctxp[ctxn];
if (!ctx || !ctx->nr_events)
goto out;
@@ -3195,17 +3148,11 @@ out:
void perf_event_exec(void)
{
- struct perf_event_context *ctx;
int ctxn;
rcu_read_lock();
- for_each_task_context_nr(ctxn) {
- ctx = current->perf_event_ctxp[ctxn];
- if (!ctx)
- continue;
-
- perf_event_enable_on_exec(ctx);
- }
+ for_each_task_context_nr(ctxn)
+ perf_event_enable_on_exec(ctxn);
rcu_read_unlock();
}
@@ -4144,6 +4091,22 @@ struct period_event {
u64 value;
};
+static void ___perf_event_period(void *info)
+{
+ struct period_event *pe = info;
+ struct perf_event *event = pe->event;
+ u64 value = pe->value;
+
+ if (event->attr.freq) {
+ event->attr.sample_freq = value;
+ } else {
+ event->attr.sample_period = value;
+ event->hw.sample_period = value;
+ }
+
+ local64_set(&event->hw.period_left, 0);
+}
+
static int __perf_event_period(void *info)
{
struct period_event *pe = info;
@@ -4180,8 +4143,6 @@ static int __perf_event_period(void *info)
static int perf_event_period(struct perf_event *event, u64 __user *arg)
{
struct period_event pe = { .event = event, };
- struct perf_event_context *ctx = event->ctx;
- struct task_struct *task;
u64 value;
if (!is_sampling_event(event))
@@ -4196,27 +4157,10 @@ static int perf_event_period(struct perf_event *event, u64 __user *arg)
if (event->attr.freq && value > sysctl_perf_event_sample_rate)
return -EINVAL;
- task = ctx->task;
pe.value = value;
- if (!task) {
- cpu_function_call(event->cpu, __perf_event_period, &pe);
- return 0;
- }
-
-retry:
- if (!task_function_call(task, __perf_event_period, &pe))
- return 0;
-
- raw_spin_lock_irq(&ctx->lock);
- if (ctx->is_active) {
- raw_spin_unlock_irq(&ctx->lock);
- task = ctx->task;
- goto retry;
- }
-
- __perf_event_period(&pe);
- raw_spin_unlock_irq(&ctx->lock);
+ event_function_call(event, __perf_event_period,
+ ___perf_event_period, &pe);
return 0;
}
@@ -5666,6 +5610,17 @@ perf_event_aux_ctx(struct perf_event_context *ctx,
}
static void
+perf_event_aux_task_ctx(perf_event_aux_output_cb output, void *data,
+ struct perf_event_context *task_ctx)
+{
+ rcu_read_lock();
+ preempt_disable();
+ perf_event_aux_ctx(task_ctx, output, data);
+ preempt_enable();
+ rcu_read_unlock();
+}
+
+static void
perf_event_aux(perf_event_aux_output_cb output, void *data,
struct perf_event_context *task_ctx)
{
@@ -5674,14 +5629,23 @@ perf_event_aux(perf_event_aux_output_cb output, void *data,
struct pmu *pmu;
int ctxn;
+ /*
+ * If we have task_ctx != NULL we only notify
+ * the task context itself. The task_ctx is set
+ * only for EXIT events before releasing task
+ * context.
+ */
+ if (task_ctx) {
+ perf_event_aux_task_ctx(output, data, task_ctx);
+ return;
+ }
+
rcu_read_lock();
list_for_each_entry_rcu(pmu, &pmus, entry) {
cpuctx = get_cpu_ptr(pmu->pmu_cpu_context);
if (cpuctx->unique_pmu != pmu)
goto next;
perf_event_aux_ctx(&cpuctx->ctx, output, data);
- if (task_ctx)
- goto next;
ctxn = pmu->task_ctx_nr;
if (ctxn < 0)
goto next;
@@ -5691,12 +5655,6 @@ perf_event_aux(perf_event_aux_output_cb output, void *data,
next:
put_cpu_ptr(pmu->pmu_cpu_context);
}
-
- if (task_ctx) {
- preempt_disable();
- perf_event_aux_ctx(task_ctx, output, data);
- preempt_enable();
- }
rcu_read_unlock();
}
@@ -6462,9 +6420,6 @@ struct swevent_htable {
/* Recursion avoidance in each contexts */
int recursion[PERF_NR_CONTEXTS];
-
- /* Keeps track of cpu being initialized/exited */
- bool online;
};
static DEFINE_PER_CPU(struct swevent_htable, swevent_htable);
@@ -6722,14 +6677,8 @@ static int perf_swevent_add(struct perf_event *event, int flags)
hwc->state = !(flags & PERF_EF_START);
head = find_swevent_head(swhash, event);
- if (!head) {
- /*
- * We can race with cpu hotplug code. Do not
- * WARN if the cpu just got unplugged.
- */
- WARN_ON_ONCE(swhash->online);
+ if (WARN_ON_ONCE(!head))
return -EINVAL;
- }
hlist_add_head_rcu(&event->hlist_entry, head);
perf_event_update_userpage(event);
@@ -6797,7 +6746,6 @@ static int swevent_hlist_get_cpu(struct perf_event *event, int cpu)
int err = 0;
mutex_lock(&swhash->hlist_mutex);
-
if (!swevent_hlist_deref(swhash) && cpu_online(cpu)) {
struct swevent_hlist *hlist;
@@ -6913,6 +6861,10 @@ static int perf_tp_filter_match(struct perf_event *event,
{
void *record = data->raw->data;
+ /* only top level events have filters set */
+ if (event->parent)
+ event = event->parent;
+
if (likely(!event->filter) || filter_match_preds(event->filter, record))
return 1;
return 0;
@@ -8782,10 +8734,8 @@ static void perf_event_exit_task_context(struct task_struct *child, int ctxn)
struct perf_event_context *child_ctx, *clone_ctx = NULL;
unsigned long flags;
- if (likely(!child->perf_event_ctxp[ctxn])) {
- perf_event_task(child, NULL, 0);
+ if (likely(!child->perf_event_ctxp[ctxn]))
return;
- }
local_irq_save(flags);
/*
@@ -8869,6 +8819,14 @@ void perf_event_exit_task(struct task_struct *child)
for_each_task_context_nr(ctxn)
perf_event_exit_task_context(child, ctxn);
+
+ /*
+ * The perf_event_exit_task_context calls perf_event_task
+ * with child's task_ctx, which generates EXIT events for
+ * child contexts and sets child->perf_event_ctxp[] to NULL.
+ * At this point we need to send EXIT events to cpu contexts.
+ */
+ perf_event_task(child, NULL, 0);
}
static void perf_free_event(struct perf_event *event,
@@ -9250,7 +9208,6 @@ static void perf_event_init_cpu(int cpu)
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
mutex_lock(&swhash->hlist_mutex);
- swhash->online = true;
if (swhash->hlist_refcount > 0) {
struct swevent_hlist *hlist;
@@ -9292,14 +9249,7 @@ static void perf_event_exit_cpu_context(int cpu)
static void perf_event_exit_cpu(int cpu)
{
- struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
-
perf_event_exit_cpu_context(cpu);
-
- mutex_lock(&swhash->hlist_mutex);
- swhash->online = false;
- swevent_hlist_release(swhash);
- mutex_unlock(&swhash->hlist_mutex);
}
#else
static inline void perf_event_exit_cpu(int cpu) { }
@@ -9447,16 +9397,18 @@ static void perf_cgroup_css_free(struct cgroup_subsys_state *css)
static int __perf_cgroup_move(void *info)
{
struct task_struct *task = info;
+ rcu_read_lock();
perf_cgroup_switch(task, PERF_CGROUP_SWOUT | PERF_CGROUP_SWIN);
+ rcu_read_unlock();
return 0;
}
-static void perf_cgroup_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void perf_cgroup_attach(struct cgroup_taskset *tset)
{
struct task_struct *task;
+ struct cgroup_subsys_state *css;
- cgroup_taskset_for_each(task, tset)
+ cgroup_taskset_for_each(task, css, tset)
task_function_call(task, __perf_cgroup_move, task);
}
diff --git a/kernel/events/ring_buffer.c b/kernel/events/ring_buffer.c
index b5d1ea7..adfdc05 100644
--- a/kernel/events/ring_buffer.c
+++ b/kernel/events/ring_buffer.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2008 Thomas Gleixner <tglx@linutronix.de>
* Copyright (C) 2008-2011 Red Hat, Inc., Ingo Molnar
- * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008-2011 Red Hat, Inc., Peter Zijlstra
* Copyright © 2009 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
*
* For licensing details see kernel-base/COPYING
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 4e5e979..7dad849 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -19,7 +19,7 @@
* Authors:
* Srikar Dronamraju
* Jim Keniston
- * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra
*/
#include <linux/kernel.h>
diff --git a/kernel/fork.c b/kernel/fork.c
index f97f2c4..291b08c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -380,6 +380,7 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
#endif
tsk->splice_pipe = NULL;
tsk->task_frag.page = NULL;
+ tsk->wake_q.next = NULL;
account_kernel_stack(ti, 1);
@@ -1348,9 +1349,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
prev_cputime_init(&p->prev_cputime);
#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN
- seqlock_init(&p->vtime_seqlock);
+ seqcount_init(&p->vtime_seqcount);
p->vtime_snap = 0;
- p->vtime_snap_whence = VTIME_SLEEPING;
+ p->vtime_snap_whence = VTIME_INACTIVE;
#endif
#if defined(SPLIT_RSS_COUNTING)
@@ -1368,8 +1369,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->real_start_time = ktime_get_boot_ns();
p->io_context = NULL;
p->audit_context = NULL;
- if (clone_flags & CLONE_THREAD)
- threadgroup_change_begin(current);
+ threadgroup_change_begin(current);
cgroup_fork(p);
#ifdef CONFIG_NUMA
p->mempolicy = mpol_dup(p->mempolicy);
@@ -1610,8 +1610,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
proc_fork_connector(p);
cgroup_post_fork(p, cgrp_ss_priv);
- if (clone_flags & CLONE_THREAD)
- threadgroup_change_end(current);
+ threadgroup_change_end(current);
perf_event_fork(p);
trace_task_newtask(p, clone_flags);
@@ -1652,8 +1651,7 @@ bad_fork_cleanup_policy:
mpol_put(p->mempolicy);
bad_fork_cleanup_threadgroup_lock:
#endif
- if (clone_flags & CLONE_THREAD)
- threadgroup_change_end(current);
+ threadgroup_change_end(current);
delayacct_tsk_free(p);
bad_fork_cleanup_count:
atomic_dec(&p->cred->user->processes);
diff --git a/kernel/futex.c b/kernel/futex.c
index 684d754..8a310e2 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -725,9 +725,12 @@ static struct futex_pi_state * alloc_pi_state(void)
}
/*
+ * Drops a reference to the pi_state object and frees or caches it
+ * when the last reference is gone.
+ *
* Must be called with the hb lock held.
*/
-static void free_pi_state(struct futex_pi_state *pi_state)
+static void put_pi_state(struct futex_pi_state *pi_state)
{
if (!pi_state)
return;
@@ -1706,31 +1709,35 @@ retry_private:
* exist yet, look it up one more time to ensure we have a
* reference to it. If the lock was taken, ret contains the
* vpid of the top waiter task.
+ * If the lock was not taken, we have pi_state and an initial
+ * refcount on it. In case of an error we have nothing.
*/
if (ret > 0) {
WARN_ON(pi_state);
drop_count++;
task_count++;
/*
- * If we acquired the lock, then the user
- * space value of uaddr2 should be vpid. It
- * cannot be changed by the top waiter as it
- * is blocked on hb2 lock if it tries to do
- * so. If something fiddled with it behind our
- * back the pi state lookup might unearth
- * it. So we rather use the known value than
- * rereading and handing potential crap to
- * lookup_pi_state.
+ * If we acquired the lock, then the user space value
+ * of uaddr2 should be vpid. It cannot be changed by
+ * the top waiter as it is blocked on hb2 lock if it
+ * tries to do so. If something fiddled with it behind
+ * our back the pi state lookup might unearth it. So
+ * we rather use the known value than rereading and
+ * handing potential crap to lookup_pi_state.
+ *
+ * If that call succeeds then we have pi_state and an
+ * initial refcount on it.
*/
ret = lookup_pi_state(ret, hb2, &key2, &pi_state);
}
switch (ret) {
case 0:
+ /* We hold a reference on the pi state. */
break;
+
+ /* If the above failed, then pi_state is NULL */
case -EFAULT:
- free_pi_state(pi_state);
- pi_state = NULL;
double_unlock_hb(hb1, hb2);
hb_waiters_dec(hb2);
put_futex_key(&key2);
@@ -1746,8 +1753,6 @@ retry_private:
* exit to complete.
* - The user space value changed.
*/
- free_pi_state(pi_state);
- pi_state = NULL;
double_unlock_hb(hb1, hb2);
hb_waiters_dec(hb2);
put_futex_key(&key2);
@@ -1801,30 +1806,58 @@ retry_private:
* of requeue_pi if we couldn't acquire the lock atomically.
*/
if (requeue_pi) {
- /* Prepare the waiter to take the rt_mutex. */
+ /*
+ * Prepare the waiter to take the rt_mutex. Take a
+ * refcount on the pi_state and store the pointer in
+ * the futex_q object of the waiter.
+ */
atomic_inc(&pi_state->refcount);
this->pi_state = pi_state;
ret = rt_mutex_start_proxy_lock(&pi_state->pi_mutex,
this->rt_waiter,
this->task);
if (ret == 1) {
- /* We got the lock. */
+ /*
+ * We got the lock. We do neither drop the
+ * refcount on pi_state nor clear
+ * this->pi_state because the waiter needs the
+ * pi_state for cleaning up the user space
+ * value. It will drop the refcount after
+ * doing so.
+ */
requeue_pi_wake_futex(this, &key2, hb2);
drop_count++;
continue;
} else if (ret) {
- /* -EDEADLK */
+ /*
+ * rt_mutex_start_proxy_lock() detected a
+ * potential deadlock when we tried to queue
+ * that waiter. Drop the pi_state reference
+ * which we took above and remove the pointer
+ * to the state from the waiters futex_q
+ * object.
+ */
this->pi_state = NULL;
- free_pi_state(pi_state);
- goto out_unlock;
+ put_pi_state(pi_state);
+ /*
+ * We stop queueing more waiters and let user
+ * space deal with the mess.
+ */
+ break;
}
}
requeue_futex(this, hb1, hb2, &key2);
drop_count++;
}
+ /*
+ * We took an extra initial reference to the pi_state either
+ * in futex_proxy_trylock_atomic() or in lookup_pi_state(). We
+ * need to drop it here again.
+ */
+ put_pi_state(pi_state);
+
out_unlock:
- free_pi_state(pi_state);
double_unlock_hb(hb1, hb2);
wake_up_q(&wake_q);
hb_waiters_dec(hb2);
@@ -1973,7 +2006,7 @@ static void unqueue_me_pi(struct futex_q *q)
__unqueue_futex(q);
BUG_ON(!q->pi_state);
- free_pi_state(q->pi_state);
+ put_pi_state(q->pi_state);
q->pi_state = NULL;
spin_unlock(q->lock_ptr);
@@ -2755,6 +2788,11 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
if (q.pi_state && (q.pi_state->owner != current)) {
spin_lock(q.lock_ptr);
ret = fixup_pi_state_owner(uaddr2, &q, current);
+ /*
+ * Drop the reference to the pi state which
+ * the requeue_pi() code acquired for us.
+ */
+ put_pi_state(q.pi_state);
spin_unlock(q.lock_ptr);
}
} else {
@@ -3046,7 +3084,8 @@ long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
if (op & FUTEX_CLOCK_REALTIME) {
flags |= FLAGS_CLOCKRT;
- if (cmd != FUTEX_WAIT_BITSET && cmd != FUTEX_WAIT_REQUEUE_PI)
+ if (cmd != FUTEX_WAIT && cmd != FUTEX_WAIT_BITSET && \
+ cmd != FUTEX_WAIT_REQUEUE_PI)
return -ENOSYS;
}
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index 1520645..5797909 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -338,7 +338,6 @@ void handle_nested_irq(unsigned int irq)
raw_spin_lock_irq(&desc->lock);
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
- kstat_incr_irqs_this_cpu(desc);
action = desc->action;
if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) {
@@ -346,6 +345,7 @@ void handle_nested_irq(unsigned int irq)
goto out_unlock;
}
+ kstat_incr_irqs_this_cpu(desc);
irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
raw_spin_unlock_irq(&desc->lock);
@@ -412,13 +412,13 @@ void handle_simple_irq(struct irq_desc *desc)
goto out_unlock;
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
- kstat_incr_irqs_this_cpu(desc);
if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
goto out_unlock;
}
+ kstat_incr_irqs_this_cpu(desc);
handle_irq_event(desc);
out_unlock:
@@ -462,7 +462,6 @@ void handle_level_irq(struct irq_desc *desc)
goto out_unlock;
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
- kstat_incr_irqs_this_cpu(desc);
/*
* If its disabled or no action available
@@ -473,6 +472,7 @@ void handle_level_irq(struct irq_desc *desc)
goto out_unlock;
}
+ kstat_incr_irqs_this_cpu(desc);
handle_irq_event(desc);
cond_unmask_irq(desc);
@@ -532,7 +532,6 @@ void handle_fasteoi_irq(struct irq_desc *desc)
goto out;
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
- kstat_incr_irqs_this_cpu(desc);
/*
* If its disabled or no action available
@@ -544,6 +543,7 @@ void handle_fasteoi_irq(struct irq_desc *desc)
goto out;
}
+ kstat_incr_irqs_this_cpu(desc);
if (desc->istate & IRQS_ONESHOT)
mask_irq(desc);
@@ -950,6 +950,7 @@ void irq_chip_ack_parent(struct irq_data *data)
data = data->parent_data;
data->chip->irq_ack(data);
}
+EXPORT_SYMBOL_GPL(irq_chip_ack_parent);
/**
* irq_chip_mask_parent - Mask the parent interrupt
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h
index 05c2188..fcab63c 100644
--- a/kernel/irq/internals.h
+++ b/kernel/irq/internals.h
@@ -199,6 +199,11 @@ static inline int irq_desc_get_node(struct irq_desc *desc)
return irq_common_data_get_node(&desc->irq_common_data);
}
+static inline int irq_desc_is_chained(struct irq_desc *desc)
+{
+ return (desc->action && desc->action == &chained_action);
+}
+
#ifdef CONFIG_PM_SLEEP
bool irq_pm_check_wakeup(struct irq_desc *desc);
void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action);
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 239e2ae..0409da0 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -159,6 +159,7 @@ static struct irq_desc *alloc_desc(int irq, int node, struct module *owner)
raw_spin_lock_init(&desc->lock);
lockdep_set_class(&desc->lock, &irq_desc_lock_class);
+ init_rcu_head(&desc->rcu);
desc_set_defaults(irq, desc, node, owner);
@@ -171,6 +172,15 @@ err_desc:
return NULL;
}
+static void delayed_free_desc(struct rcu_head *rhp)
+{
+ struct irq_desc *desc = container_of(rhp, struct irq_desc, rcu);
+
+ free_masks(desc);
+ free_percpu(desc->kstat_irqs);
+ kfree(desc);
+}
+
static void free_desc(unsigned int irq)
{
struct irq_desc *desc = irq_to_desc(irq);
@@ -187,9 +197,12 @@ static void free_desc(unsigned int irq)
delete_irq_desc(irq);
mutex_unlock(&sparse_irq_lock);
- free_masks(desc);
- free_percpu(desc->kstat_irqs);
- kfree(desc);
+ /*
+ * We free the descriptor, masks and stat fields via RCU. That
+ * allows demultiplex interrupts to do rcu based management of
+ * the child interrupts.
+ */
+ call_rcu(&desc->rcu, delayed_free_desc);
}
static int alloc_descs(unsigned int start, unsigned int cnt, int node,
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 22aa961..8cf95de 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -60,6 +60,7 @@ struct fwnode_handle *irq_domain_alloc_fwnode(void *data)
fwid->fwnode.type = FWNODE_IRQCHIP;
return &fwid->fwnode;
}
+EXPORT_SYMBOL_GPL(irq_domain_alloc_fwnode);
/**
* irq_domain_free_fwnode - Free a non-OF-backed fwnode_handle
@@ -70,13 +71,14 @@ void irq_domain_free_fwnode(struct fwnode_handle *fwnode)
{
struct irqchip_fwid *fwid;
- if (WARN_ON(fwnode->type != FWNODE_IRQCHIP))
+ if (WARN_ON(!is_fwnode_irqchip(fwnode)))
return;
fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
kfree(fwid->name);
kfree(fwid);
}
+EXPORT_SYMBOL_GPL(irq_domain_free_fwnode);
/**
* __irq_domain_add() - Allocate a new irq_domain data structure
@@ -1013,6 +1015,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
return NULL;
}
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
/**
* irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
@@ -1125,9 +1128,9 @@ static void irq_domain_free_irqs_recursive(struct irq_domain *domain,
}
}
-static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
- unsigned int irq_base,
- unsigned int nr_irqs, void *arg)
+int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs, void *arg)
{
int ret = 0;
struct irq_domain *parent = domain->parent;
@@ -1343,6 +1346,7 @@ struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
}
+EXPORT_SYMBOL_GPL(irq_domain_get_irq_data);
/**
* irq_domain_set_info - Set the complete data for a @virq in @domain
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0eebaee..8411872 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -1434,6 +1434,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
if (!desc)
return NULL;
+ chip_bus_lock(desc);
raw_spin_lock_irqsave(&desc->lock, flags);
/*
@@ -1447,7 +1448,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
if (!action) {
WARN(1, "Trying to free already-free IRQ %d\n", irq);
raw_spin_unlock_irqrestore(&desc->lock, flags);
-
+ chip_bus_sync_unlock(desc);
return NULL;
}
@@ -1475,6 +1476,7 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id)
#endif
raw_spin_unlock_irqrestore(&desc->lock, flags);
+ chip_bus_sync_unlock(desc);
unregister_handler_proc(irq, action);
@@ -1553,9 +1555,7 @@ void free_irq(unsigned int irq, void *dev_id)
desc->affinity_notify = NULL;
#endif
- chip_bus_lock(desc);
kfree(__free_irq(irq, dev_id));
- chip_bus_sync_unlock(desc);
}
EXPORT_SYMBOL(free_irq);
@@ -1743,6 +1743,31 @@ out:
}
EXPORT_SYMBOL_GPL(enable_percpu_irq);
+/**
+ * irq_percpu_is_enabled - Check whether the per cpu irq is enabled
+ * @irq: Linux irq number to check for
+ *
+ * Must be called from a non migratable context. Returns the enable
+ * state of a per cpu interrupt on the current cpu.
+ */
+bool irq_percpu_is_enabled(unsigned int irq)
+{
+ unsigned int cpu = smp_processor_id();
+ struct irq_desc *desc;
+ unsigned long flags;
+ bool is_enabled;
+
+ desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU);
+ if (!desc)
+ return false;
+
+ is_enabled = cpumask_test_cpu(cpu, desc->percpu_enabled);
+ irq_put_desc_unlock(desc, flags);
+
+ return is_enabled;
+}
+EXPORT_SYMBOL_GPL(irq_percpu_is_enabled);
+
void disable_percpu_irq(unsigned int irq)
{
unsigned int cpu = smp_processor_id();
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 6b0c0b7..15b249e 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -252,6 +252,60 @@ struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode,
&msi_domain_ops, info);
}
+int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *arg)
+{
+ struct msi_domain_info *info = domain->host_data;
+ struct msi_domain_ops *ops = info->ops;
+ int ret;
+
+ ret = ops->msi_check(domain, info, dev);
+ if (ret == 0)
+ ret = ops->msi_prepare(domain, dev, nvec, arg);
+
+ return ret;
+}
+
+int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
+ int virq, int nvec, msi_alloc_info_t *arg)
+{
+ struct msi_domain_info *info = domain->host_data;
+ struct msi_domain_ops *ops = info->ops;
+ struct msi_desc *desc;
+ int ret = 0;
+
+ for_each_msi_entry(desc, dev) {
+ /* Don't even try the multi-MSI brain damage. */
+ if (WARN_ON(!desc->irq || desc->nvec_used != 1)) {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+ continue;
+
+ ops->set_desc(arg, desc);
+ /* Assumes the domain mutex is held! */
+ ret = irq_domain_alloc_irqs_recursive(domain, virq, 1, arg);
+ if (ret)
+ break;
+
+ irq_set_msi_desc_off(virq, 0, desc);
+ }
+
+ if (ret) {
+ /* Mop up the damage */
+ for_each_msi_entry(desc, dev) {
+ if (!(desc->irq >= virq && desc->irq < (virq + nvec)))
+ continue;
+
+ irq_domain_free_irqs_common(domain, desc->irq, 1);
+ }
+ }
+
+ return ret;
+}
+
/**
* msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
* @domain: The domain to allocate from
@@ -270,9 +324,7 @@ int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
struct msi_desc *desc;
int i, ret, virq = -1;
- ret = ops->msi_check(domain, info, dev);
- if (ret == 0)
- ret = ops->msi_prepare(domain, dev, nvec, &arg);
+ ret = msi_domain_prepare_irqs(domain, dev, nvec, &arg);
if (ret)
return ret;
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index e80c440..cea1de0 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -70,7 +70,8 @@ void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action)
static bool suspend_device_irq(struct irq_desc *desc)
{
- if (!desc->action || desc->no_suspend_depth)
+ if (!desc->action || irq_desc_is_chained(desc) ||
+ desc->no_suspend_depth)
return false;
if (irqd_is_wakeup_set(&desc->irq_data)) {
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index a916cf1..a2c02fd 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -475,7 +475,7 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
any_count |= kstat_irqs_cpu(i, j);
action = desc->action;
- if ((!action || action == &chained_action) && !any_count)
+ if ((!action || irq_desc_is_chained(desc)) && !any_count)
goto out;
seq_printf(p, "%*d: ", prec, i);
diff --git a/kernel/irq_work.c b/kernel/irq_work.c
index cbf9fb8..bcf107c 100644
--- a/kernel/irq_work.c
+++ b/kernel/irq_work.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra
*
* Provides a framework for enqueueing and running callbacks from hardirq
* context. The enqueueing is NMI-safe.
diff --git a/kernel/jump_label.c b/kernel/jump_label.c
index f7dd15d..05254ee 100644
--- a/kernel/jump_label.c
+++ b/kernel/jump_label.c
@@ -2,7 +2,7 @@
* jump label support
*
* Copyright (C) 2009 Jason Baron <jbaron@redhat.com>
- * Copyright (C) 2011 Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2011 Peter Zijlstra
*
*/
#include <linux/memory.h>
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 11b64a6..c823f30 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -853,7 +853,12 @@ struct kimage *kexec_image;
struct kimage *kexec_crash_image;
int kexec_load_disabled;
-void crash_kexec(struct pt_regs *regs)
+/*
+ * No panic_cpu check version of crash_kexec(). This function is called
+ * only when panic_cpu holds the current CPU number; this is the only CPU
+ * which processes crash_kexec routines.
+ */
+void __crash_kexec(struct pt_regs *regs)
{
/* Take the kexec_mutex here to prevent sys_kexec_load
* running on one cpu from replacing the crash kernel
@@ -876,6 +881,29 @@ void crash_kexec(struct pt_regs *regs)
}
}
+void crash_kexec(struct pt_regs *regs)
+{
+ int old_cpu, this_cpu;
+
+ /*
+ * Only one CPU is allowed to execute the crash_kexec() code as with
+ * panic(). Otherwise parallel calls of panic() and crash_kexec()
+ * may stop each other. To exclude them, we use panic_cpu here too.
+ */
+ this_cpu = raw_smp_processor_id();
+ old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
+ if (old_cpu == PANIC_CPU_INVALID) {
+ /* This is the 1st CPU which comes here, so go ahead. */
+ __crash_kexec(regs);
+
+ /*
+ * Reset panic_cpu to allow another panic()/crash_kexec()
+ * call.
+ */
+ atomic_set(&panic_cpu, PANIC_CPU_INVALID);
+ }
+}
+
size_t crash_get_memory_size(void)
{
size_t size = 0;
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index e83b264..152da4a 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -20,7 +20,7 @@
#include <linux/capability.h>
#include <linux/compiler.h>
-#include <linux/rcupdate.h> /* rcu_expedited */
+#include <linux/rcupdate.h> /* rcu_expedited and rcu_normal */
#define KERNEL_ATTR_RO(_name) \
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
@@ -144,11 +144,12 @@ static ssize_t fscaps_show(struct kobject *kobj,
}
KERNEL_ATTR_RO(fscaps);
+#ifndef CONFIG_TINY_RCU
int rcu_expedited;
static ssize_t rcu_expedited_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
- return sprintf(buf, "%d\n", rcu_expedited);
+ return sprintf(buf, "%d\n", READ_ONCE(rcu_expedited));
}
static ssize_t rcu_expedited_store(struct kobject *kobj,
struct kobj_attribute *attr,
@@ -161,6 +162,24 @@ static ssize_t rcu_expedited_store(struct kobject *kobj,
}
KERNEL_ATTR_RW(rcu_expedited);
+int rcu_normal;
+static ssize_t rcu_normal_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", READ_ONCE(rcu_normal));
+}
+static ssize_t rcu_normal_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ if (kstrtoint(buf, 0, &rcu_normal))
+ return -EINVAL;
+
+ return count;
+}
+KERNEL_ATTR_RW(rcu_normal);
+#endif /* #ifndef CONFIG_TINY_RCU */
+
/*
* Make /sys/kernel/notes give the raw contents of our kernel .notes section.
*/
@@ -202,7 +221,10 @@ static struct attribute * kernel_attrs[] = {
&kexec_crash_size_attr.attr,
&vmcoreinfo_attr.attr,
#endif
+#ifndef CONFIG_TINY_RCU
&rcu_expedited_attr.attr,
+ &rcu_normal_attr.attr,
+#endif
NULL
};
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 6e53441..db545cb 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -294,6 +294,12 @@ static int klp_write_object_relocations(struct module *pmod,
for (reloc = obj->relocs; reloc->name; reloc++) {
if (!klp_is_module(obj)) {
+
+#if defined(CONFIG_RANDOMIZE_BASE)
+ /* If KASLR has been enabled, adjust old value accordingly */
+ if (kaslr_enabled())
+ reloc->val += kaslr_offset();
+#endif
ret = klp_verify_vmlinux_symbol(reloc->name,
reloc->val);
if (ret)
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index deae390..60ace56 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -6,7 +6,7 @@
* Started by Ingo Molnar:
*
* Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* this code maps all the lock dependencies as they occur in a live kernel
* and will warn about the following classes of locking bugs:
diff --git a/kernel/locking/lockdep_proc.c b/kernel/locking/lockdep_proc.c
index d83d798..dbb61a3 100644
--- a/kernel/locking/lockdep_proc.c
+++ b/kernel/locking/lockdep_proc.c
@@ -6,7 +6,7 @@
* Started by Ingo Molnar:
*
* Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com>
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* Code for /proc/lockdep and /proc/lockdep_stats:
*
diff --git a/kernel/locking/osq_lock.c b/kernel/locking/osq_lock.c
index d092a0c..05a3785 100644
--- a/kernel/locking/osq_lock.c
+++ b/kernel/locking/osq_lock.c
@@ -93,10 +93,12 @@ bool osq_lock(struct optimistic_spin_queue *lock)
node->cpu = curr;
/*
- * ACQUIRE semantics, pairs with corresponding RELEASE
- * in unlock() uncontended, or fastpath.
+ * We need both ACQUIRE (pairs with corresponding RELEASE in
+ * unlock() uncontended, or fastpath) and RELEASE (to publish
+ * the node fields we just initialised) semantics when updating
+ * the lock tail.
*/
- old = atomic_xchg_acquire(&lock->tail, curr);
+ old = atomic_xchg(&lock->tail, curr);
if (old == OSQ_UNLOCKED_VAL)
return true;
diff --git a/kernel/locking/qspinlock.c b/kernel/locking/qspinlock.c
index 87e9ce6a..393d187 100644
--- a/kernel/locking/qspinlock.c
+++ b/kernel/locking/qspinlock.c
@@ -14,8 +14,9 @@
* (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
* (C) Copyright 2013-2014 Red Hat, Inc.
* (C) Copyright 2015 Intel Corp.
+ * (C) Copyright 2015 Hewlett-Packard Enterprise Development LP
*
- * Authors: Waiman Long <waiman.long@hp.com>
+ * Authors: Waiman Long <waiman.long@hpe.com>
* Peter Zijlstra <peterz@infradead.org>
*/
@@ -176,7 +177,12 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
{
struct __qspinlock *l = (void *)lock;
- return (u32)xchg(&l->tail, tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET;
+ /*
+ * Use release semantics to make sure that the MCS node is properly
+ * initialized before changing the tail code.
+ */
+ return (u32)xchg_release(&l->tail,
+ tail >> _Q_TAIL_OFFSET) << _Q_TAIL_OFFSET;
}
#else /* _Q_PENDING_BITS == 8 */
@@ -208,7 +214,11 @@ static __always_inline u32 xchg_tail(struct qspinlock *lock, u32 tail)
for (;;) {
new = (val & _Q_LOCKED_PENDING_MASK) | tail;
- old = atomic_cmpxchg(&lock->val, val, new);
+ /*
+ * Use release semantics to make sure that the MCS node is
+ * properly initialized before changing the tail code.
+ */
+ old = atomic_cmpxchg_release(&lock->val, val, new);
if (old == val)
break;
@@ -238,18 +248,20 @@ static __always_inline void set_locked(struct qspinlock *lock)
*/
static __always_inline void __pv_init_node(struct mcs_spinlock *node) { }
-static __always_inline void __pv_wait_node(struct mcs_spinlock *node) { }
+static __always_inline void __pv_wait_node(struct mcs_spinlock *node,
+ struct mcs_spinlock *prev) { }
static __always_inline void __pv_kick_node(struct qspinlock *lock,
struct mcs_spinlock *node) { }
-static __always_inline void __pv_wait_head(struct qspinlock *lock,
- struct mcs_spinlock *node) { }
+static __always_inline u32 __pv_wait_head_or_lock(struct qspinlock *lock,
+ struct mcs_spinlock *node)
+ { return 0; }
#define pv_enabled() false
#define pv_init_node __pv_init_node
#define pv_wait_node __pv_wait_node
#define pv_kick_node __pv_kick_node
-#define pv_wait_head __pv_wait_head
+#define pv_wait_head_or_lock __pv_wait_head_or_lock
#ifdef CONFIG_PARAVIRT_SPINLOCKS
#define queued_spin_lock_slowpath native_queued_spin_lock_slowpath
@@ -319,7 +331,11 @@ void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
if (val == new)
new |= _Q_PENDING_VAL;
- old = atomic_cmpxchg(&lock->val, val, new);
+ /*
+ * Acquire semantic is required here as the function may
+ * return immediately if the lock was free.
+ */
+ old = atomic_cmpxchg_acquire(&lock->val, val, new);
if (old == val)
break;
@@ -382,6 +398,7 @@ queue:
* p,*,* -> n,*,*
*/
old = xchg_tail(lock, tail);
+ next = NULL;
/*
* if there was a previous node; link it and wait until reaching the
@@ -391,8 +408,18 @@ queue:
prev = decode_tail(old);
WRITE_ONCE(prev->next, node);
- pv_wait_node(node);
+ pv_wait_node(node, prev);
arch_mcs_spin_lock_contended(&node->locked);
+
+ /*
+ * While waiting for the MCS lock, the next pointer may have
+ * been set by another lock waiter. We optimistically load
+ * the next pointer & prefetch the cacheline for writing
+ * to reduce latency in the upcoming MCS unlock operation.
+ */
+ next = READ_ONCE(node->next);
+ if (next)
+ prefetchw(next);
}
/*
@@ -406,11 +433,22 @@ queue:
* sequentiality; this is because the set_locked() function below
* does not imply a full barrier.
*
+ * The PV pv_wait_head_or_lock function, if active, will acquire
+ * the lock and return a non-zero value. So we have to skip the
+ * smp_load_acquire() call. As the next PV queue head hasn't been
+ * designated yet, there is no way for the locked value to become
+ * _Q_SLOW_VAL. So both the set_locked() and the
+ * atomic_cmpxchg_relaxed() calls will be safe.
+ *
+ * If PV isn't active, 0 will be returned instead.
+ *
*/
- pv_wait_head(lock, node);
- while ((val = smp_load_acquire(&lock->val.counter)) & _Q_LOCKED_PENDING_MASK)
- cpu_relax();
+ if ((val = pv_wait_head_or_lock(lock, node)))
+ goto locked;
+ smp_cond_acquire(!((val = atomic_read(&lock->val)) & _Q_LOCKED_PENDING_MASK));
+
+locked:
/*
* claim the lock:
*
@@ -422,11 +460,17 @@ queue:
* to grab the lock.
*/
for (;;) {
- if (val != tail) {
+ /* In the PV case we might already have _Q_LOCKED_VAL set */
+ if ((val & _Q_TAIL_MASK) != tail) {
set_locked(lock);
break;
}
- old = atomic_cmpxchg(&lock->val, val, _Q_LOCKED_VAL);
+ /*
+ * The smp_load_acquire() call above has provided the necessary
+ * acquire semantics required for locking. At most two
+ * iterations of this loop may be ran.
+ */
+ old = atomic_cmpxchg_relaxed(&lock->val, val, _Q_LOCKED_VAL);
if (old == val)
goto release; /* No contention */
@@ -434,10 +478,12 @@ queue:
}
/*
- * contended path; wait for next, release.
+ * contended path; wait for next if not observed yet, release.
*/
- while (!(next = READ_ONCE(node->next)))
- cpu_relax();
+ if (!next) {
+ while (!(next = READ_ONCE(node->next)))
+ cpu_relax();
+ }
arch_mcs_spin_unlock_contended(&next->locked);
pv_kick_node(lock, next);
@@ -462,7 +508,7 @@ EXPORT_SYMBOL(queued_spin_lock_slowpath);
#undef pv_init_node
#undef pv_wait_node
#undef pv_kick_node
-#undef pv_wait_head
+#undef pv_wait_head_or_lock
#undef queued_spin_lock_slowpath
#define queued_spin_lock_slowpath __pv_queued_spin_lock_slowpath
diff --git a/kernel/locking/qspinlock_paravirt.h b/kernel/locking/qspinlock_paravirt.h
index f0450ff..87bb235 100644
--- a/kernel/locking/qspinlock_paravirt.h
+++ b/kernel/locking/qspinlock_paravirt.h
@@ -23,6 +23,20 @@
#define _Q_SLOW_VAL (3U << _Q_LOCKED_OFFSET)
/*
+ * Queue Node Adaptive Spinning
+ *
+ * A queue node vCPU will stop spinning if the vCPU in the previous node is
+ * not running. The one lock stealing attempt allowed at slowpath entry
+ * mitigates the slight slowdown for non-overcommitted guest with this
+ * aggressive wait-early mechanism.
+ *
+ * The status of the previous node will be checked at fixed interval
+ * controlled by PV_PREV_CHECK_MASK. This is to ensure that we won't
+ * pound on the cacheline of the previous node too heavily.
+ */
+#define PV_PREV_CHECK_MASK 0xff
+
+/*
* Queue node uses: vcpu_running & vcpu_halted.
* Queue head uses: vcpu_running & vcpu_hashed.
*/
@@ -41,6 +55,94 @@ struct pv_node {
};
/*
+ * By replacing the regular queued_spin_trylock() with the function below,
+ * it will be called once when a lock waiter enter the PV slowpath before
+ * being queued. By allowing one lock stealing attempt here when the pending
+ * bit is off, it helps to reduce the performance impact of lock waiter
+ * preemption without the drawback of lock starvation.
+ */
+#define queued_spin_trylock(l) pv_queued_spin_steal_lock(l)
+static inline bool pv_queued_spin_steal_lock(struct qspinlock *lock)
+{
+ struct __qspinlock *l = (void *)lock;
+
+ return !(atomic_read(&lock->val) & _Q_LOCKED_PENDING_MASK) &&
+ (cmpxchg(&l->locked, 0, _Q_LOCKED_VAL) == 0);
+}
+
+/*
+ * The pending bit is used by the queue head vCPU to indicate that it
+ * is actively spinning on the lock and no lock stealing is allowed.
+ */
+#if _Q_PENDING_BITS == 8
+static __always_inline void set_pending(struct qspinlock *lock)
+{
+ struct __qspinlock *l = (void *)lock;
+
+ WRITE_ONCE(l->pending, 1);
+}
+
+static __always_inline void clear_pending(struct qspinlock *lock)
+{
+ struct __qspinlock *l = (void *)lock;
+
+ WRITE_ONCE(l->pending, 0);
+}
+
+/*
+ * The pending bit check in pv_queued_spin_steal_lock() isn't a memory
+ * barrier. Therefore, an atomic cmpxchg() is used to acquire the lock
+ * just to be sure that it will get it.
+ */
+static __always_inline int trylock_clear_pending(struct qspinlock *lock)
+{
+ struct __qspinlock *l = (void *)lock;
+
+ return !READ_ONCE(l->locked) &&
+ (cmpxchg(&l->locked_pending, _Q_PENDING_VAL, _Q_LOCKED_VAL)
+ == _Q_PENDING_VAL);
+}
+#else /* _Q_PENDING_BITS == 8 */
+static __always_inline void set_pending(struct qspinlock *lock)
+{
+ atomic_set_mask(_Q_PENDING_VAL, &lock->val);
+}
+
+static __always_inline void clear_pending(struct qspinlock *lock)
+{
+ atomic_clear_mask(_Q_PENDING_VAL, &lock->val);
+}
+
+static __always_inline int trylock_clear_pending(struct qspinlock *lock)
+{
+ int val = atomic_read(&lock->val);
+
+ for (;;) {
+ int old, new;
+
+ if (val & _Q_LOCKED_MASK)
+ break;
+
+ /*
+ * Try to clear pending bit & set locked bit
+ */
+ old = val;
+ new = (val & ~_Q_PENDING_MASK) | _Q_LOCKED_VAL;
+ val = atomic_cmpxchg(&lock->val, old, new);
+
+ if (val == old)
+ return 1;
+ }
+ return 0;
+}
+#endif /* _Q_PENDING_BITS == 8 */
+
+/*
+ * Include queued spinlock statistics code
+ */
+#include "qspinlock_stat.h"
+
+/*
* Lock and MCS node addresses hash table for fast lookup
*
* Hashing is done on a per-cacheline basis to minimize the need to access
@@ -100,10 +202,13 @@ static struct qspinlock **pv_hash(struct qspinlock *lock, struct pv_node *node)
{
unsigned long offset, hash = hash_ptr(lock, pv_lock_hash_bits);
struct pv_hash_entry *he;
+ int hopcnt = 0;
for_each_hash_entry(he, offset, hash) {
+ hopcnt++;
if (!cmpxchg(&he->lock, NULL, lock)) {
WRITE_ONCE(he->node, node);
+ qstat_hop(hopcnt);
return &he->lock;
}
}
@@ -144,6 +249,20 @@ static struct pv_node *pv_unhash(struct qspinlock *lock)
}
/*
+ * Return true if when it is time to check the previous node which is not
+ * in a running state.
+ */
+static inline bool
+pv_wait_early(struct pv_node *prev, int loop)
+{
+
+ if ((loop & PV_PREV_CHECK_MASK) != 0)
+ return false;
+
+ return READ_ONCE(prev->state) != vcpu_running;
+}
+
+/*
* Initialize the PV part of the mcs_spinlock node.
*/
static void pv_init_node(struct mcs_spinlock *node)
@@ -161,15 +280,23 @@ static void pv_init_node(struct mcs_spinlock *node)
* pv_kick_node() is used to set _Q_SLOW_VAL and fill in hash table on its
* behalf.
*/
-static void pv_wait_node(struct mcs_spinlock *node)
+static void pv_wait_node(struct mcs_spinlock *node, struct mcs_spinlock *prev)
{
struct pv_node *pn = (struct pv_node *)node;
+ struct pv_node *pp = (struct pv_node *)prev;
+ int waitcnt = 0;
int loop;
+ bool wait_early;
- for (;;) {
- for (loop = SPIN_THRESHOLD; loop; loop--) {
+ /* waitcnt processing will be compiled out if !QUEUED_LOCK_STAT */
+ for (;; waitcnt++) {
+ for (wait_early = false, loop = SPIN_THRESHOLD; loop; loop--) {
if (READ_ONCE(node->locked))
return;
+ if (pv_wait_early(pp, loop)) {
+ wait_early = true;
+ break;
+ }
cpu_relax();
}
@@ -184,12 +311,17 @@ static void pv_wait_node(struct mcs_spinlock *node)
*/
smp_store_mb(pn->state, vcpu_halted);
- if (!READ_ONCE(node->locked))
+ if (!READ_ONCE(node->locked)) {
+ qstat_inc(qstat_pv_wait_node, true);
+ qstat_inc(qstat_pv_wait_again, waitcnt);
+ qstat_inc(qstat_pv_wait_early, wait_early);
pv_wait(&pn->state, vcpu_halted);
+ }
/*
- * If pv_kick_node() changed us to vcpu_hashed, retain that value
- * so that pv_wait_head() knows to not also try to hash this lock.
+ * If pv_kick_node() changed us to vcpu_hashed, retain that
+ * value so that pv_wait_head_or_lock() knows to not also try
+ * to hash this lock.
*/
cmpxchg(&pn->state, vcpu_halted, vcpu_running);
@@ -200,6 +332,7 @@ static void pv_wait_node(struct mcs_spinlock *node)
* So it is better to spin for a while in the hope that the
* MCS lock will be released soon.
*/
+ qstat_inc(qstat_pv_spurious_wakeup, !READ_ONCE(node->locked));
}
/*
@@ -212,8 +345,9 @@ static void pv_wait_node(struct mcs_spinlock *node)
/*
* Called after setting next->locked = 1 when we're the lock owner.
*
- * Instead of waking the waiters stuck in pv_wait_node() advance their state such
- * that they're waiting in pv_wait_head(), this avoids a wake/sleep cycle.
+ * Instead of waking the waiters stuck in pv_wait_node() advance their state
+ * such that they're waiting in pv_wait_head_or_lock(), this avoids a
+ * wake/sleep cycle.
*/
static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
{
@@ -242,14 +376,19 @@ static void pv_kick_node(struct qspinlock *lock, struct mcs_spinlock *node)
}
/*
- * Wait for l->locked to become clear; halt the vcpu after a short spin.
+ * Wait for l->locked to become clear and acquire the lock;
+ * halt the vcpu after a short spin.
* __pv_queued_spin_unlock() will wake us.
+ *
+ * The current value of the lock will be returned for additional processing.
*/
-static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
+static u32
+pv_wait_head_or_lock(struct qspinlock *lock, struct mcs_spinlock *node)
{
struct pv_node *pn = (struct pv_node *)node;
struct __qspinlock *l = (void *)lock;
struct qspinlock **lp = NULL;
+ int waitcnt = 0;
int loop;
/*
@@ -259,12 +398,25 @@ static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
if (READ_ONCE(pn->state) == vcpu_hashed)
lp = (struct qspinlock **)1;
- for (;;) {
+ for (;; waitcnt++) {
+ /*
+ * Set correct vCPU state to be used by queue node wait-early
+ * mechanism.
+ */
+ WRITE_ONCE(pn->state, vcpu_running);
+
+ /*
+ * Set the pending bit in the active lock spinning loop to
+ * disable lock stealing before attempting to acquire the lock.
+ */
+ set_pending(lock);
for (loop = SPIN_THRESHOLD; loop; loop--) {
- if (!READ_ONCE(l->locked))
- return;
+ if (trylock_clear_pending(lock))
+ goto gotlock;
cpu_relax();
}
+ clear_pending(lock);
+
if (!lp) { /* ONCE */
lp = pv_hash(lock, pn);
@@ -280,51 +432,50 @@ static void pv_wait_head(struct qspinlock *lock, struct mcs_spinlock *node)
*
* Matches the smp_rmb() in __pv_queued_spin_unlock().
*/
- if (!cmpxchg(&l->locked, _Q_LOCKED_VAL, _Q_SLOW_VAL)) {
+ if (xchg(&l->locked, _Q_SLOW_VAL) == 0) {
/*
- * The lock is free and _Q_SLOW_VAL has never
- * been set. Therefore we need to unhash before
- * getting the lock.
+ * The lock was free and now we own the lock.
+ * Change the lock value back to _Q_LOCKED_VAL
+ * and unhash the table.
*/
+ WRITE_ONCE(l->locked, _Q_LOCKED_VAL);
WRITE_ONCE(*lp, NULL);
- return;
+ goto gotlock;
}
}
+ WRITE_ONCE(pn->state, vcpu_halted);
+ qstat_inc(qstat_pv_wait_head, true);
+ qstat_inc(qstat_pv_wait_again, waitcnt);
pv_wait(&l->locked, _Q_SLOW_VAL);
/*
* The unlocker should have freed the lock before kicking the
* CPU. So if the lock is still not free, it is a spurious
- * wakeup and so the vCPU should wait again after spinning for
- * a while.
+ * wakeup or another vCPU has stolen the lock. The current
+ * vCPU should spin again.
*/
+ qstat_inc(qstat_pv_spurious_wakeup, READ_ONCE(l->locked));
}
/*
- * Lock is unlocked now; the caller will acquire it without waiting.
- * As with pv_wait_node() we rely on the caller to do a load-acquire
- * for us.
+ * The cmpxchg() or xchg() call before coming here provides the
+ * acquire semantics for locking. The dummy ORing of _Q_LOCKED_VAL
+ * here is to indicate to the compiler that the value will always
+ * be nozero to enable better code optimization.
*/
+gotlock:
+ return (u32)(atomic_read(&lock->val) | _Q_LOCKED_VAL);
}
/*
- * PV version of the unlock function to be used in stead of
- * queued_spin_unlock().
+ * PV versions of the unlock fastpath and slowpath functions to be used
+ * instead of queued_spin_unlock().
*/
-__visible void __pv_queued_spin_unlock(struct qspinlock *lock)
+__visible void
+__pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked)
{
struct __qspinlock *l = (void *)lock;
struct pv_node *node;
- u8 locked;
-
- /*
- * We must not unlock if SLOW, because in that case we must first
- * unhash. Otherwise it would be possible to have multiple @lock
- * entries, which would be BAD.
- */
- locked = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
- if (likely(locked == _Q_LOCKED_VAL))
- return;
if (unlikely(locked != _Q_SLOW_VAL)) {
WARN(!debug_locks_silent,
@@ -338,7 +489,7 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
* so we need a barrier to order the read of the node data in
* pv_unhash *after* we've read the lock being _Q_SLOW_VAL.
*
- * Matches the cmpxchg() in pv_wait_head() setting _Q_SLOW_VAL.
+ * Matches the cmpxchg() in pv_wait_head_or_lock() setting _Q_SLOW_VAL.
*/
smp_rmb();
@@ -361,14 +512,35 @@ __visible void __pv_queued_spin_unlock(struct qspinlock *lock)
* vCPU is harmless other than the additional latency in completing
* the unlock.
*/
+ qstat_inc(qstat_pv_kick_unlock, true);
pv_kick(node->cpu);
}
+
/*
* Include the architecture specific callee-save thunk of the
* __pv_queued_spin_unlock(). This thunk is put together with
- * __pv_queued_spin_unlock() near the top of the file to make sure
- * that the callee-save thunk and the real unlock function are close
- * to each other sharing consecutive instruction cachelines.
+ * __pv_queued_spin_unlock() to make the callee-save thunk and the real unlock
+ * function close to each other sharing consecutive instruction cachelines.
+ * Alternatively, architecture specific version of __pv_queued_spin_unlock()
+ * can be defined.
*/
#include <asm/qspinlock_paravirt.h>
+#ifndef __pv_queued_spin_unlock
+__visible void __pv_queued_spin_unlock(struct qspinlock *lock)
+{
+ struct __qspinlock *l = (void *)lock;
+ u8 locked;
+
+ /*
+ * We must not unlock if SLOW, because in that case we must first
+ * unhash. Otherwise it would be possible to have multiple @lock
+ * entries, which would be BAD.
+ */
+ locked = cmpxchg(&l->locked, _Q_LOCKED_VAL, 0);
+ if (likely(locked == _Q_LOCKED_VAL))
+ return;
+
+ __pv_queued_spin_unlock_slowpath(lock, locked);
+}
+#endif /* __pv_queued_spin_unlock */
diff --git a/kernel/locking/qspinlock_stat.h b/kernel/locking/qspinlock_stat.h
new file mode 100644
index 0000000..640dcec
--- /dev/null
+++ b/kernel/locking/qspinlock_stat.h
@@ -0,0 +1,300 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Authors: Waiman Long <waiman.long@hpe.com>
+ */
+
+/*
+ * When queued spinlock statistical counters are enabled, the following
+ * debugfs files will be created for reporting the counter values:
+ *
+ * <debugfs>/qlockstat/
+ * pv_hash_hops - average # of hops per hashing operation
+ * pv_kick_unlock - # of vCPU kicks issued at unlock time
+ * pv_kick_wake - # of vCPU kicks used for computing pv_latency_wake
+ * pv_latency_kick - average latency (ns) of vCPU kick operation
+ * pv_latency_wake - average latency (ns) from vCPU kick to wakeup
+ * pv_lock_stealing - # of lock stealing operations
+ * pv_spurious_wakeup - # of spurious wakeups
+ * pv_wait_again - # of vCPU wait's that happened after a vCPU kick
+ * pv_wait_early - # of early vCPU wait's
+ * pv_wait_head - # of vCPU wait's at the queue head
+ * pv_wait_node - # of vCPU wait's at a non-head queue node
+ *
+ * Writing to the "reset_counters" file will reset all the above counter
+ * values.
+ *
+ * These statistical counters are implemented as per-cpu variables which are
+ * summed and computed whenever the corresponding debugfs files are read. This
+ * minimizes added overhead making the counters usable even in a production
+ * environment.
+ *
+ * There may be slight difference between pv_kick_wake and pv_kick_unlock.
+ */
+enum qlock_stats {
+ qstat_pv_hash_hops,
+ qstat_pv_kick_unlock,
+ qstat_pv_kick_wake,
+ qstat_pv_latency_kick,
+ qstat_pv_latency_wake,
+ qstat_pv_lock_stealing,
+ qstat_pv_spurious_wakeup,
+ qstat_pv_wait_again,
+ qstat_pv_wait_early,
+ qstat_pv_wait_head,
+ qstat_pv_wait_node,
+ qstat_num, /* Total number of statistical counters */
+ qstat_reset_cnts = qstat_num,
+};
+
+#ifdef CONFIG_QUEUED_LOCK_STAT
+/*
+ * Collect pvqspinlock statistics
+ */
+#include <linux/debugfs.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+
+static const char * const qstat_names[qstat_num + 1] = {
+ [qstat_pv_hash_hops] = "pv_hash_hops",
+ [qstat_pv_kick_unlock] = "pv_kick_unlock",
+ [qstat_pv_kick_wake] = "pv_kick_wake",
+ [qstat_pv_spurious_wakeup] = "pv_spurious_wakeup",
+ [qstat_pv_latency_kick] = "pv_latency_kick",
+ [qstat_pv_latency_wake] = "pv_latency_wake",
+ [qstat_pv_lock_stealing] = "pv_lock_stealing",
+ [qstat_pv_wait_again] = "pv_wait_again",
+ [qstat_pv_wait_early] = "pv_wait_early",
+ [qstat_pv_wait_head] = "pv_wait_head",
+ [qstat_pv_wait_node] = "pv_wait_node",
+ [qstat_reset_cnts] = "reset_counters",
+};
+
+/*
+ * Per-cpu counters
+ */
+static DEFINE_PER_CPU(unsigned long, qstats[qstat_num]);
+static DEFINE_PER_CPU(u64, pv_kick_time);
+
+/*
+ * Function to read and return the qlock statistical counter values
+ *
+ * The following counters are handled specially:
+ * 1. qstat_pv_latency_kick
+ * Average kick latency (ns) = pv_latency_kick/pv_kick_unlock
+ * 2. qstat_pv_latency_wake
+ * Average wake latency (ns) = pv_latency_wake/pv_kick_wake
+ * 3. qstat_pv_hash_hops
+ * Average hops/hash = pv_hash_hops/pv_kick_unlock
+ */
+static ssize_t qstat_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ char buf[64];
+ int cpu, counter, len;
+ u64 stat = 0, kicks = 0;
+
+ /*
+ * Get the counter ID stored in file->f_inode->i_private
+ */
+ if (!file->f_inode) {
+ WARN_ON_ONCE(1);
+ return -EBADF;
+ }
+ counter = (long)(file->f_inode->i_private);
+
+ if (counter >= qstat_num)
+ return -EBADF;
+
+ for_each_possible_cpu(cpu) {
+ stat += per_cpu(qstats[counter], cpu);
+ /*
+ * Need to sum additional counter for some of them
+ */
+ switch (counter) {
+
+ case qstat_pv_latency_kick:
+ case qstat_pv_hash_hops:
+ kicks += per_cpu(qstats[qstat_pv_kick_unlock], cpu);
+ break;
+
+ case qstat_pv_latency_wake:
+ kicks += per_cpu(qstats[qstat_pv_kick_wake], cpu);
+ break;
+ }
+ }
+
+ if (counter == qstat_pv_hash_hops) {
+ u64 frac;
+
+ frac = 100ULL * do_div(stat, kicks);
+ frac = DIV_ROUND_CLOSEST_ULL(frac, kicks);
+
+ /*
+ * Return a X.XX decimal number
+ */
+ len = snprintf(buf, sizeof(buf) - 1, "%llu.%02llu\n", stat, frac);
+ } else {
+ /*
+ * Round to the nearest ns
+ */
+ if ((counter == qstat_pv_latency_kick) ||
+ (counter == qstat_pv_latency_wake)) {
+ stat = 0;
+ if (kicks)
+ stat = DIV_ROUND_CLOSEST_ULL(stat, kicks);
+ }
+ len = snprintf(buf, sizeof(buf) - 1, "%llu\n", stat);
+ }
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+/*
+ * Function to handle write request
+ *
+ * When counter = reset_cnts, reset all the counter values.
+ * Since the counter updates aren't atomic, the resetting is done twice
+ * to make sure that the counters are very likely to be all cleared.
+ */
+static ssize_t qstat_write(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ int cpu;
+
+ /*
+ * Get the counter ID stored in file->f_inode->i_private
+ */
+ if (!file->f_inode) {
+ WARN_ON_ONCE(1);
+ return -EBADF;
+ }
+ if ((long)(file->f_inode->i_private) != qstat_reset_cnts)
+ return count;
+
+ for_each_possible_cpu(cpu) {
+ int i;
+ unsigned long *ptr = per_cpu_ptr(qstats, cpu);
+
+ for (i = 0 ; i < qstat_num; i++)
+ WRITE_ONCE(ptr[i], 0);
+ for (i = 0 ; i < qstat_num; i++)
+ WRITE_ONCE(ptr[i], 0);
+ }
+ return count;
+}
+
+/*
+ * Debugfs data structures
+ */
+static const struct file_operations fops_qstat = {
+ .read = qstat_read,
+ .write = qstat_write,
+ .llseek = default_llseek,
+};
+
+/*
+ * Initialize debugfs for the qspinlock statistical counters
+ */
+static int __init init_qspinlock_stat(void)
+{
+ struct dentry *d_qstat = debugfs_create_dir("qlockstat", NULL);
+ int i;
+
+ if (!d_qstat) {
+ pr_warn("Could not create 'qlockstat' debugfs directory\n");
+ return 0;
+ }
+
+ /*
+ * Create the debugfs files
+ *
+ * As reading from and writing to the stat files can be slow, only
+ * root is allowed to do the read/write to limit impact to system
+ * performance.
+ */
+ for (i = 0; i < qstat_num; i++)
+ debugfs_create_file(qstat_names[i], 0400, d_qstat,
+ (void *)(long)i, &fops_qstat);
+
+ debugfs_create_file(qstat_names[qstat_reset_cnts], 0200, d_qstat,
+ (void *)(long)qstat_reset_cnts, &fops_qstat);
+ return 0;
+}
+fs_initcall(init_qspinlock_stat);
+
+/*
+ * Increment the PV qspinlock statistical counters
+ */
+static inline void qstat_inc(enum qlock_stats stat, bool cond)
+{
+ if (cond)
+ this_cpu_inc(qstats[stat]);
+}
+
+/*
+ * PV hash hop count
+ */
+static inline void qstat_hop(int hopcnt)
+{
+ this_cpu_add(qstats[qstat_pv_hash_hops], hopcnt);
+}
+
+/*
+ * Replacement function for pv_kick()
+ */
+static inline void __pv_kick(int cpu)
+{
+ u64 start = sched_clock();
+
+ per_cpu(pv_kick_time, cpu) = start;
+ pv_kick(cpu);
+ this_cpu_add(qstats[qstat_pv_latency_kick], sched_clock() - start);
+}
+
+/*
+ * Replacement function for pv_wait()
+ */
+static inline void __pv_wait(u8 *ptr, u8 val)
+{
+ u64 *pkick_time = this_cpu_ptr(&pv_kick_time);
+
+ *pkick_time = 0;
+ pv_wait(ptr, val);
+ if (*pkick_time) {
+ this_cpu_add(qstats[qstat_pv_latency_wake],
+ sched_clock() - *pkick_time);
+ qstat_inc(qstat_pv_kick_wake, true);
+ }
+}
+
+#define pv_kick(c) __pv_kick(c)
+#define pv_wait(p, v) __pv_wait(p, v)
+
+/*
+ * PV unfair trylock count tracking function
+ */
+static inline int qstat_spin_steal_lock(struct qspinlock *lock)
+{
+ int ret = pv_queued_spin_steal_lock(lock);
+
+ qstat_inc(qstat_pv_lock_stealing, ret);
+ return ret;
+}
+#undef queued_spin_trylock
+#define queued_spin_trylock(l) qstat_spin_steal_lock(l)
+
+#else /* CONFIG_QUEUED_LOCK_STAT */
+
+static inline void qstat_inc(enum qlock_stats stat, bool cond) { }
+static inline void qstat_hop(int hopcnt) { }
+
+#endif /* CONFIG_QUEUED_LOCK_STAT */
diff --git a/kernel/memremap.c b/kernel/memremap.c
index 9d6b555..7658d32 100644
--- a/kernel/memremap.c
+++ b/kernel/memremap.c
@@ -124,9 +124,10 @@ void *devm_memremap(struct device *dev, resource_size_t offset,
{
void **ptr, *addr;
- ptr = devres_alloc(devm_memremap_release, sizeof(*ptr), GFP_KERNEL);
+ ptr = devres_alloc_node(devm_memremap_release, sizeof(*ptr), GFP_KERNEL,
+ dev_to_node(dev));
if (!ptr)
- return NULL;
+ return ERR_PTR(-ENOMEM);
addr = memremap(offset, size, flags);
if (addr) {
@@ -141,9 +142,8 @@ EXPORT_SYMBOL(devm_memremap);
void devm_memunmap(struct device *dev, void *addr)
{
- WARN_ON(devres_destroy(dev, devm_memremap_release, devm_memremap_match,
- addr));
- memunmap(addr);
+ WARN_ON(devres_release(dev, devm_memremap_release,
+ devm_memremap_match, addr));
}
EXPORT_SYMBOL(devm_memunmap);
@@ -176,8 +176,8 @@ void *devm_memremap_pages(struct device *dev, struct resource *res)
if (is_ram == REGION_INTERSECTS)
return __va(res->start);
- page_map = devres_alloc(devm_memremap_pages_release,
- sizeof(*page_map), GFP_KERNEL);
+ page_map = devres_alloc_node(devm_memremap_pages_release,
+ sizeof(*page_map), GFP_KERNEL, dev_to_node(dev));
if (!page_map)
return ERR_PTR(-ENOMEM);
@@ -185,7 +185,7 @@ void *devm_memremap_pages(struct device *dev, struct resource *res)
nid = dev_to_node(dev);
if (nid < 0)
- nid = 0;
+ nid = numa_mem_id();
error = arch_add_memory(nid, res->start, resource_size(res), true);
if (error) {
diff --git a/kernel/module.c b/kernel/module.c
index 8f051a1..38c7bd5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3571,6 +3571,12 @@ static int load_module(struct load_info *info, const char __user *uargs,
synchronize_sched();
mutex_unlock(&module_mutex);
free_module:
+ /*
+ * Ftrace needs to clean up what it initialized.
+ * This does nothing if ftrace_module_init() wasn't called,
+ * but it must be called outside of module_mutex.
+ */
+ ftrace_release_mod(mod);
/* Free lock-classes; relies on the preceding sync_rcu() */
lockdep_free_key_range(mod->module_core, mod->core_size);
diff --git a/kernel/panic.c b/kernel/panic.c
index 4579dbb..b333380 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -61,6 +61,17 @@ void __weak panic_smp_self_stop(void)
cpu_relax();
}
+/*
+ * Stop ourselves in NMI context if another CPU has already panicked. Arch code
+ * may override this to prepare for crash dumping, e.g. save regs info.
+ */
+void __weak nmi_panic_self_stop(struct pt_regs *regs)
+{
+ panic_smp_self_stop();
+}
+
+atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID);
+
/**
* panic - halt the system
* @fmt: The text string to print
@@ -71,17 +82,17 @@ void __weak panic_smp_self_stop(void)
*/
void panic(const char *fmt, ...)
{
- static DEFINE_SPINLOCK(panic_lock);
static char buf[1024];
va_list args;
long i, i_next = 0;
int state = 0;
+ int old_cpu, this_cpu;
/*
* Disable local interrupts. This will prevent panic_smp_self_stop
* from deadlocking the first cpu that invokes the panic, since
* there is nothing to prevent an interrupt handler (that runs
- * after the panic_lock is acquired) from invoking panic again.
+ * after setting panic_cpu) from invoking panic() again.
*/
local_irq_disable();
@@ -94,8 +105,16 @@ void panic(const char *fmt, ...)
* multiple parallel invocations of panic, all other CPUs either
* stop themself or will wait until they are stopped by the 1st CPU
* with smp_send_stop().
+ *
+ * `old_cpu == PANIC_CPU_INVALID' means this is the 1st CPU which
+ * comes here, so go ahead.
+ * `old_cpu == this_cpu' means we came from nmi_panic() which sets
+ * panic_cpu to this CPU. In this case, this is also the 1st CPU.
*/
- if (!spin_trylock(&panic_lock))
+ this_cpu = raw_smp_processor_id();
+ old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
+
+ if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu)
panic_smp_self_stop();
console_verbose();
@@ -117,9 +136,11 @@ void panic(const char *fmt, ...)
* everything else.
* If we want to run this after calling panic_notifiers, pass
* the "crash_kexec_post_notifiers" option to the kernel.
+ *
+ * Bypass the panic_cpu check and call __crash_kexec directly.
*/
if (!crash_kexec_post_notifiers)
- crash_kexec(NULL);
+ __crash_kexec(NULL);
/*
* Note smp_send_stop is the usual smp shutdown function, which
@@ -142,9 +163,11 @@ void panic(const char *fmt, ...)
* panic_notifiers and dumping kmsg before kdump.
* Note: since some panic_notifiers can make crashed kernel
* more unstable, it can increase risks of the kdump failure too.
+ *
+ * Bypass the panic_cpu check and call __crash_kexec directly.
*/
if (crash_kexec_post_notifiers)
- crash_kexec(NULL);
+ __crash_kexec(NULL);
bust_spinlocks(0);
@@ -152,8 +175,11 @@ void panic(const char *fmt, ...)
* We may have ended up stopping the CPU holding the lock (in
* smp_send_stop()) while still having some valuable data in the console
* buffer. Try to acquire the lock then release it regardless of the
- * result. The release will also print the buffers out.
+ * result. The release will also print the buffers out. Locks debug
+ * should be disabled to avoid reporting bad unlock balance when
+ * panic() is not being callled from OOPS.
*/
+ debug_locks_off();
console_trylock();
console_unlock();
diff --git a/kernel/pid.c b/kernel/pid.c
index ca36879..78b3d9f 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -467,7 +467,7 @@ struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
rcu_read_lock();
if (type != PIDTYPE_PID)
task = task->group_leader;
- pid = get_pid(task->pids[type].pid);
+ pid = get_pid(rcu_dereference(task->pids[type].pid));
rcu_read_unlock();
return pid;
}
@@ -528,7 +528,7 @@ pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type,
if (likely(pid_alive(task))) {
if (type != PIDTYPE_PID)
task = task->group_leader;
- nr = pid_nr_ns(task->pids[type].pid, ns);
+ nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns);
}
rcu_read_unlock();
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index d89328e..d2988d0 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -162,6 +162,27 @@ static int rcu_torture_writer_state;
#define RTWS_SYNC 7
#define RTWS_STUTTER 8
#define RTWS_STOPPING 9
+static const char * const rcu_torture_writer_state_names[] = {
+ "RTWS_FIXED_DELAY",
+ "RTWS_DELAY",
+ "RTWS_REPLACE",
+ "RTWS_DEF_FREE",
+ "RTWS_EXP_SYNC",
+ "RTWS_COND_GET",
+ "RTWS_COND_SYNC",
+ "RTWS_SYNC",
+ "RTWS_STUTTER",
+ "RTWS_STOPPING",
+};
+
+static const char *rcu_torture_writer_state_getname(void)
+{
+ unsigned int i = READ_ONCE(rcu_torture_writer_state);
+
+ if (i >= ARRAY_SIZE(rcu_torture_writer_state_names))
+ return "???";
+ return rcu_torture_writer_state_names[i];
+}
#if defined(MODULE) || defined(CONFIG_RCU_TORTURE_TEST_RUNNABLE)
#define RCUTORTURE_RUNNABLE_INIT 1
@@ -1307,7 +1328,8 @@ rcu_torture_stats_print(void)
rcutorture_get_gp_data(cur_ops->ttype,
&flags, &gpnum, &completed);
- pr_alert("??? Writer stall state %d g%lu c%lu f%#x\n",
+ pr_alert("??? Writer stall state %s(%d) g%lu c%lu f%#x\n",
+ rcu_torture_writer_state_getname(),
rcu_torture_writer_state,
gpnum, completed, flags);
show_rcu_gp_kthreads();
diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c
index a63a1ea..9b9cdd5 100644
--- a/kernel/rcu/srcu.c
+++ b/kernel/rcu/srcu.c
@@ -489,7 +489,7 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount)
*/
void synchronize_srcu(struct srcu_struct *sp)
{
- __synchronize_srcu(sp, rcu_gp_is_expedited()
+ __synchronize_srcu(sp, (rcu_gp_is_expedited() && !rcu_gp_is_normal())
? SYNCHRONIZE_SRCU_EXP_TRYCOUNT
: SYNCHRONIZE_SRCU_TRYCOUNT);
}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index f07343b..e41dd41 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -68,10 +68,6 @@ MODULE_ALIAS("rcutree");
/* Data structures. */
-static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
-static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
-static struct lock_class_key rcu_exp_class[RCU_NUM_LVLS];
-
/*
* In order to export the rcu_state name to the tracing tools, it
* needs to be added in the __tracepoint_string section.
@@ -246,24 +242,17 @@ static int rcu_gp_in_progress(struct rcu_state *rsp)
*/
void rcu_sched_qs(void)
{
- unsigned long flags;
-
- if (__this_cpu_read(rcu_sched_data.cpu_no_qs.s)) {
- trace_rcu_grace_period(TPS("rcu_sched"),
- __this_cpu_read(rcu_sched_data.gpnum),
- TPS("cpuqs"));
- __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false);
- if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))
- return;
- local_irq_save(flags);
- if (__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp)) {
- __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false);
- rcu_report_exp_rdp(&rcu_sched_state,
- this_cpu_ptr(&rcu_sched_data),
- true);
- }
- local_irq_restore(flags);
- }
+ if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.s))
+ return;
+ trace_rcu_grace_period(TPS("rcu_sched"),
+ __this_cpu_read(rcu_sched_data.gpnum),
+ TPS("cpuqs"));
+ __this_cpu_write(rcu_sched_data.cpu_no_qs.b.norm, false);
+ if (!__this_cpu_read(rcu_sched_data.cpu_no_qs.b.exp))
+ return;
+ __this_cpu_write(rcu_sched_data.cpu_no_qs.b.exp, false);
+ rcu_report_exp_rdp(&rcu_sched_state,
+ this_cpu_ptr(&rcu_sched_data), true);
}
void rcu_bh_qs(void)
@@ -300,17 +289,16 @@ EXPORT_PER_CPU_SYMBOL_GPL(rcu_qs_ctr);
* We inform the RCU core by emulating a zero-duration dyntick-idle
* period, which we in turn do by incrementing the ->dynticks counter
* by two.
+ *
+ * The caller must have disabled interrupts.
*/
static void rcu_momentary_dyntick_idle(void)
{
- unsigned long flags;
struct rcu_data *rdp;
struct rcu_dynticks *rdtp;
int resched_mask;
struct rcu_state *rsp;
- local_irq_save(flags);
-
/*
* Yes, we can lose flag-setting operations. This is OK, because
* the flag will be set again after some delay.
@@ -340,13 +328,12 @@ static void rcu_momentary_dyntick_idle(void)
smp_mb__after_atomic(); /* Later stuff after QS. */
break;
}
- local_irq_restore(flags);
}
/*
* Note a context switch. This is a quiescent state for RCU-sched,
* and requires special handling for preemptible RCU.
- * The caller must have disabled preemption.
+ * The caller must have disabled interrupts.
*/
void rcu_note_context_switch(void)
{
@@ -376,9 +363,14 @@ EXPORT_SYMBOL_GPL(rcu_note_context_switch);
*/
void rcu_all_qs(void)
{
+ unsigned long flags;
+
barrier(); /* Avoid RCU read-side critical sections leaking down. */
- if (unlikely(raw_cpu_read(rcu_sched_qs_mask)))
+ if (unlikely(raw_cpu_read(rcu_sched_qs_mask))) {
+ local_irq_save(flags);
rcu_momentary_dyntick_idle();
+ local_irq_restore(flags);
+ }
this_cpu_inc(rcu_qs_ctr);
barrier(); /* Avoid RCU read-side critical sections leaking up. */
}
@@ -605,25 +597,25 @@ static int rcu_future_needs_gp(struct rcu_state *rsp)
* The caller must have disabled interrupts to prevent races with
* normal callback registry.
*/
-static int
+static bool
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
{
int i;
if (rcu_gp_in_progress(rsp))
- return 0; /* No, a grace period is already in progress. */
+ return false; /* No, a grace period is already in progress. */
if (rcu_future_needs_gp(rsp))
- return 1; /* Yes, a no-CBs CPU needs one. */
+ return true; /* Yes, a no-CBs CPU needs one. */
if (!rdp->nxttail[RCU_NEXT_TAIL])
- return 0; /* No, this is a no-CBs (or offline) CPU. */
+ return false; /* No, this is a no-CBs (or offline) CPU. */
if (*rdp->nxttail[RCU_NEXT_READY_TAIL])
- return 1; /* Yes, this CPU has newly registered callbacks. */
+ return true; /* Yes, CPU has newly registered callbacks. */
for (i = RCU_WAIT_TAIL; i < RCU_NEXT_TAIL; i++)
if (rdp->nxttail[i - 1] != rdp->nxttail[i] &&
ULONG_CMP_LT(READ_ONCE(rsp->completed),
rdp->nxtcompleted[i]))
- return 1; /* Yes, CBs for future grace period. */
- return 0; /* No grace period needed. */
+ return true; /* Yes, CBs for future grace period. */
+ return false; /* No grace period needed. */
}
/*
@@ -740,7 +732,7 @@ void rcu_user_enter(void)
*
* Exit from an interrupt handler, which might possibly result in entering
* idle mode, in other words, leaving the mode in which read-side critical
- * sections can occur.
+ * sections can occur. The caller must have disabled interrupts.
*
* This code assumes that the idle loop never does anything that might
* result in unbalanced calls to irq_enter() and irq_exit(). If your
@@ -753,11 +745,10 @@ void rcu_user_enter(void)
*/
void rcu_irq_exit(void)
{
- unsigned long flags;
long long oldval;
struct rcu_dynticks *rdtp;
- local_irq_save(flags);
+ RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_exit() invoked with irqs enabled!!!");
rdtp = this_cpu_ptr(&rcu_dynticks);
oldval = rdtp->dynticks_nesting;
rdtp->dynticks_nesting--;
@@ -768,6 +759,17 @@ void rcu_irq_exit(void)
else
rcu_eqs_enter_common(oldval, true);
rcu_sysidle_enter(1);
+}
+
+/*
+ * Wrapper for rcu_irq_exit() where interrupts are enabled.
+ */
+void rcu_irq_exit_irqson(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ rcu_irq_exit();
local_irq_restore(flags);
}
@@ -865,7 +867,7 @@ void rcu_user_exit(void)
*
* Enter an interrupt handler, which might possibly result in exiting
* idle mode, in other words, entering the mode in which read-side critical
- * sections can occur.
+ * sections can occur. The caller must have disabled interrupts.
*
* Note that the Linux kernel is fully capable of entering an interrupt
* handler that it never exits, for example when doing upcalls to
@@ -881,11 +883,10 @@ void rcu_user_exit(void)
*/
void rcu_irq_enter(void)
{
- unsigned long flags;
struct rcu_dynticks *rdtp;
long long oldval;
- local_irq_save(flags);
+ RCU_LOCKDEP_WARN(!irqs_disabled(), "rcu_irq_enter() invoked with irqs enabled!!!");
rdtp = this_cpu_ptr(&rcu_dynticks);
oldval = rdtp->dynticks_nesting;
rdtp->dynticks_nesting++;
@@ -896,6 +897,17 @@ void rcu_irq_enter(void)
else
rcu_eqs_exit_common(oldval, true);
rcu_sysidle_exit(1);
+}
+
+/*
+ * Wrapper for rcu_irq_enter() where interrupts are enabled.
+ */
+void rcu_irq_enter_irqson(void)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ rcu_irq_enter();
local_irq_restore(flags);
}
@@ -1187,6 +1199,16 @@ static void record_gp_stall_check_time(struct rcu_state *rsp)
}
/*
+ * Convert a ->gp_state value to a character string.
+ */
+static const char *gp_state_getname(short gs)
+{
+ if (gs < 0 || gs >= ARRAY_SIZE(gp_state_names))
+ return "???";
+ return gp_state_names[gs];
+}
+
+/*
* Complain about starvation of grace-period kthread.
*/
static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp)
@@ -1196,12 +1218,16 @@ static void rcu_check_gp_kthread_starvation(struct rcu_state *rsp)
j = jiffies;
gpa = READ_ONCE(rsp->gp_activity);
- if (j - gpa > 2 * HZ)
- pr_err("%s kthread starved for %ld jiffies! g%lu c%lu f%#x s%d ->state=%#lx\n",
+ if (j - gpa > 2 * HZ) {
+ pr_err("%s kthread starved for %ld jiffies! g%lu c%lu f%#x %s(%d) ->state=%#lx\n",
rsp->name, j - gpa,
rsp->gpnum, rsp->completed,
- rsp->gp_flags, rsp->gp_state,
- rsp->gp_kthread ? rsp->gp_kthread->state : 0);
+ rsp->gp_flags,
+ gp_state_getname(rsp->gp_state), rsp->gp_state,
+ rsp->gp_kthread ? rsp->gp_kthread->state : ~0);
+ if (rsp->gp_kthread)
+ sched_show_task(rsp->gp_kthread);
+ }
}
/*
@@ -1214,7 +1240,7 @@ static void rcu_dump_cpu_stacks(struct rcu_state *rsp)
struct rcu_node *rnp;
rcu_for_each_leaf_node(rsp, rnp) {
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (rnp->qsmask != 0) {
for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
if (rnp->qsmask & (1UL << cpu))
@@ -1237,7 +1263,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
/* Only let one CPU complain about others per time interval. */
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
delta = jiffies - READ_ONCE(rsp->jiffies_stall);
if (delta < RCU_STALL_RAT_DELAY || !rcu_gp_in_progress(rsp)) {
raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -1256,7 +1282,7 @@ static void print_other_cpu_stall(struct rcu_state *rsp, unsigned long gpnum)
rsp->name);
print_cpu_stall_info_begin();
rcu_for_each_leaf_node(rsp, rnp) {
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
ndetected += rcu_print_task_stall(rnp);
if (rnp->qsmask != 0) {
for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
@@ -1327,7 +1353,7 @@ static void print_cpu_stall(struct rcu_state *rsp)
rcu_dump_cpu_stacks(rsp);
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (ULONG_CMP_GE(jiffies, READ_ONCE(rsp->jiffies_stall)))
WRITE_ONCE(rsp->jiffies_stall,
jiffies + 3 * rcu_jiffies_till_stall_check() + 3);
@@ -1534,10 +1560,8 @@ rcu_start_future_gp(struct rcu_node *rnp, struct rcu_data *rdp,
* hold it, acquire the root rcu_node structure's lock in order to
* start one (if needed).
*/
- if (rnp != rnp_root) {
- raw_spin_lock(&rnp_root->lock);
- smp_mb__after_unlock_lock();
- }
+ if (rnp != rnp_root)
+ raw_spin_lock_rcu_node(rnp_root);
/*
* Get a new grace-period number. If there really is no grace
@@ -1786,11 +1810,10 @@ static void note_gp_changes(struct rcu_state *rsp, struct rcu_data *rdp)
if ((rdp->gpnum == READ_ONCE(rnp->gpnum) &&
rdp->completed == READ_ONCE(rnp->completed) &&
!unlikely(READ_ONCE(rdp->gpwrap))) || /* w/out lock. */
- !raw_spin_trylock(&rnp->lock)) { /* irqs already off, so later. */
+ !raw_spin_trylock_rcu_node(rnp)) { /* irqs already off, so later. */
local_irq_restore(flags);
return;
}
- smp_mb__after_unlock_lock();
needwake = __note_gp_changes(rsp, rnp, rdp);
raw_spin_unlock_irqrestore(&rnp->lock, flags);
if (needwake)
@@ -1805,21 +1828,20 @@ static void rcu_gp_slow(struct rcu_state *rsp, int delay)
}
/*
- * Initialize a new grace period. Return 0 if no grace period required.
+ * Initialize a new grace period. Return false if no grace period required.
*/
-static int rcu_gp_init(struct rcu_state *rsp)
+static bool rcu_gp_init(struct rcu_state *rsp)
{
unsigned long oldmask;
struct rcu_data *rdp;
struct rcu_node *rnp = rcu_get_root(rsp);
WRITE_ONCE(rsp->gp_activity, jiffies);
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
if (!READ_ONCE(rsp->gp_flags)) {
/* Spurious wakeup, tell caller to go back to sleep. */
raw_spin_unlock_irq(&rnp->lock);
- return 0;
+ return false;
}
WRITE_ONCE(rsp->gp_flags, 0); /* Clear all flags: New grace period. */
@@ -1829,7 +1851,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
* Not supposed to be able to happen.
*/
raw_spin_unlock_irq(&rnp->lock);
- return 0;
+ return false;
}
/* Advance to a new grace period and initialize state. */
@@ -1847,8 +1869,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
*/
rcu_for_each_leaf_node(rsp, rnp) {
rcu_gp_slow(rsp, gp_preinit_delay);
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
if (rnp->qsmaskinit == rnp->qsmaskinitnext &&
!rnp->wait_blkd_tasks) {
/* Nothing to do on this leaf rcu_node structure. */
@@ -1904,8 +1925,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
*/
rcu_for_each_node_breadth_first(rsp, rnp) {
rcu_gp_slow(rsp, gp_init_delay);
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
rdp = this_cpu_ptr(rsp->rda);
rcu_preempt_check_blocked_tasks(rnp);
rnp->qsmask = rnp->qsmaskinit;
@@ -1923,7 +1943,7 @@ static int rcu_gp_init(struct rcu_state *rsp)
WRITE_ONCE(rsp->gp_activity, jiffies);
}
- return 1;
+ return true;
}
/*
@@ -1973,8 +1993,7 @@ static void rcu_gp_fqs(struct rcu_state *rsp, bool first_time)
}
/* Clear flag to prevent immediate re-entry. */
if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
WRITE_ONCE(rsp->gp_flags,
READ_ONCE(rsp->gp_flags) & ~RCU_GP_FLAG_FQS);
raw_spin_unlock_irq(&rnp->lock);
@@ -1993,8 +2012,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
struct rcu_node *rnp = rcu_get_root(rsp);
WRITE_ONCE(rsp->gp_activity, jiffies);
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
gp_duration = jiffies - rsp->gp_start;
if (gp_duration > rsp->gp_max)
rsp->gp_max = gp_duration;
@@ -2019,8 +2037,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
* grace period is recorded in any of the rcu_node structures.
*/
rcu_for_each_node_breadth_first(rsp, rnp) {
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irq_rcu_node(rnp);
WARN_ON_ONCE(rcu_preempt_blocked_readers_cgp(rnp));
WARN_ON_ONCE(rnp->qsmask);
WRITE_ONCE(rnp->completed, rsp->gpnum);
@@ -2035,8 +2052,7 @@ static void rcu_gp_cleanup(struct rcu_state *rsp)
rcu_gp_slow(rsp, gp_cleanup_delay);
}
rnp = rcu_get_root(rsp);
- raw_spin_lock_irq(&rnp->lock);
- smp_mb__after_unlock_lock(); /* Order GP before ->completed update. */
+ raw_spin_lock_irq_rcu_node(rnp); /* Order GP before ->completed update. */
rcu_nocb_gp_set(rnp, nocb);
/* Declare grace period done. */
@@ -2284,8 +2300,7 @@ rcu_report_qs_rnp(unsigned long mask, struct rcu_state *rsp,
raw_spin_unlock_irqrestore(&rnp->lock, flags);
rnp_c = rnp;
rnp = rnp->parent;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
oldmask = rnp_c->qsmask;
}
@@ -2332,8 +2347,7 @@ static void rcu_report_unblock_qs_rnp(struct rcu_state *rsp,
gps = rnp->gpnum;
mask = rnp->grpmask;
raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
- raw_spin_lock(&rnp_p->lock); /* irqs already disabled. */
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp_p); /* irqs already disabled. */
rcu_report_qs_rnp(mask, rsp, rnp_p, gps, flags);
}
@@ -2355,8 +2369,7 @@ rcu_report_qs_rdp(int cpu, struct rcu_state *rsp, struct rcu_data *rdp)
struct rcu_node *rnp;
rnp = rdp->mynode;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if ((rdp->cpu_no_qs.b.norm &&
rdp->rcu_qs_ctr_snap == __this_cpu_read(rcu_qs_ctr)) ||
rdp->gpnum != rnp->gpnum || rnp->completed == rnp->gpnum ||
@@ -2582,8 +2595,7 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf)
rnp = rnp->parent;
if (!rnp)
break;
- raw_spin_lock(&rnp->lock); /* irqs already disabled. */
- smp_mb__after_unlock_lock(); /* GP memory ordering. */
+ raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
rnp->qsmaskinit &= ~mask;
rnp->qsmask &= ~mask;
if (rnp->qsmaskinit) {
@@ -2611,8 +2623,7 @@ static void rcu_cleanup_dying_idle_cpu(int cpu, struct rcu_state *rsp)
/* Remove outgoing CPU from mask in the leaf rcu_node structure. */
mask = rdp->grpmask;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock(); /* Enforce GP memory-order guarantee. */
+ raw_spin_lock_irqsave_rcu_node(rnp, flags); /* Enforce GP memory-order guarantee. */
rnp->qsmaskinitnext &= ~mask;
raw_spin_unlock_irqrestore(&rnp->lock, flags);
}
@@ -2809,8 +2820,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
rcu_for_each_leaf_node(rsp, rnp) {
cond_resched_rcu_qs();
mask = 0;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (rnp->qsmask == 0) {
if (rcu_state_p == &rcu_sched_state ||
rsp != rcu_state_p ||
@@ -2881,8 +2891,7 @@ static void force_quiescent_state(struct rcu_state *rsp)
/* rnp_old == rcu_get_root(rsp), rnp == NULL. */
/* Reached the root of the rcu_node tree, acquire lock. */
- raw_spin_lock_irqsave(&rnp_old->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp_old, flags);
raw_spin_unlock(&rnp_old->fqslock);
if (READ_ONCE(rsp->gp_flags) & RCU_GP_FLAG_FQS) {
rsp->n_force_qs_lh++;
@@ -2914,7 +2923,7 @@ __rcu_process_callbacks(struct rcu_state *rsp)
/* Does this CPU require a not-yet-started grace period? */
local_irq_save(flags);
if (cpu_needs_another_gp(rsp, rdp)) {
- raw_spin_lock(&rcu_get_root(rsp)->lock); /* irqs disabled. */
+ raw_spin_lock_rcu_node(rcu_get_root(rsp)); /* irqs disabled. */
needwake = rcu_start_gp(rsp);
raw_spin_unlock_irqrestore(&rcu_get_root(rsp)->lock, flags);
if (needwake)
@@ -3005,8 +3014,7 @@ static void __call_rcu_core(struct rcu_state *rsp, struct rcu_data *rdp,
if (!rcu_gp_in_progress(rsp)) {
struct rcu_node *rnp_root = rcu_get_root(rsp);
- raw_spin_lock(&rnp_root->lock);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp_root);
needwake = rcu_start_gp(rsp);
raw_spin_unlock(&rnp_root->lock);
if (needwake)
@@ -3365,7 +3373,6 @@ static unsigned long rcu_seq_snap(unsigned long *sp)
{
unsigned long s;
- smp_mb(); /* Caller's modifications seen first by other CPUs. */
s = (READ_ONCE(*sp) + 3) & ~0x1;
smp_mb(); /* Above access must not bleed into critical section. */
return s;
@@ -3392,6 +3399,7 @@ static void rcu_exp_gp_seq_end(struct rcu_state *rsp)
}
static unsigned long rcu_exp_gp_seq_snap(struct rcu_state *rsp)
{
+ smp_mb(); /* Caller's modifications seen first by other CPUs. */
return rcu_seq_snap(&rsp->expedited_sequence);
}
static bool rcu_exp_gp_seq_done(struct rcu_state *rsp, unsigned long s)
@@ -3426,8 +3434,7 @@ static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp)
* CPUs for the current rcu_node structure up the rcu_node tree.
*/
rcu_for_each_leaf_node(rsp, rnp) {
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (rnp->expmaskinit == rnp->expmaskinitnext) {
raw_spin_unlock_irqrestore(&rnp->lock, flags);
continue; /* No new CPUs, nothing to do. */
@@ -3447,8 +3454,7 @@ static void sync_exp_reset_tree_hotplug(struct rcu_state *rsp)
rnp_up = rnp->parent;
done = false;
while (rnp_up) {
- raw_spin_lock_irqsave(&rnp_up->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp_up, flags);
if (rnp_up->expmaskinit)
done = true;
rnp_up->expmaskinit |= mask;
@@ -3472,8 +3478,7 @@ static void __maybe_unused sync_exp_reset_tree(struct rcu_state *rsp)
sync_exp_reset_tree_hotplug(rsp);
rcu_for_each_node_breadth_first(rsp, rnp) {
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
WARN_ON_ONCE(rnp->expmask);
rnp->expmask = rnp->expmaskinit;
raw_spin_unlock_irqrestore(&rnp->lock, flags);
@@ -3531,8 +3536,7 @@ static void __rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
mask = rnp->grpmask;
raw_spin_unlock(&rnp->lock); /* irqs remain disabled */
rnp = rnp->parent;
- raw_spin_lock(&rnp->lock); /* irqs already disabled */
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp); /* irqs already disabled */
WARN_ON_ONCE(!(rnp->expmask & mask));
rnp->expmask &= ~mask;
}
@@ -3549,8 +3553,7 @@ static void __maybe_unused rcu_report_exp_rnp(struct rcu_state *rsp,
{
unsigned long flags;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
__rcu_report_exp_rnp(rsp, rnp, wake, flags);
}
@@ -3564,8 +3567,7 @@ static void rcu_report_exp_cpu_mult(struct rcu_state *rsp, struct rcu_node *rnp,
{
unsigned long flags;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (!(rnp->expmask & mask)) {
raw_spin_unlock_irqrestore(&rnp->lock, flags);
return;
@@ -3609,7 +3611,7 @@ static bool sync_exp_work_done(struct rcu_state *rsp, struct rcu_node *rnp,
*/
static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
{
- struct rcu_data *rdp;
+ struct rcu_data *rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id());
struct rcu_node *rnp0;
struct rcu_node *rnp1 = NULL;
@@ -3623,7 +3625,7 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
if (!mutex_is_locked(&rnp0->exp_funnel_mutex)) {
if (mutex_trylock(&rnp0->exp_funnel_mutex)) {
if (sync_exp_work_done(rsp, rnp0, NULL,
- &rsp->expedited_workdone0, s))
+ &rdp->expedited_workdone0, s))
return NULL;
return rnp0;
}
@@ -3637,14 +3639,13 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
* can be inexact, as it is just promoting locality and is not
* strictly needed for correctness.
*/
- rdp = per_cpu_ptr(rsp->rda, raw_smp_processor_id());
- if (sync_exp_work_done(rsp, NULL, NULL, &rsp->expedited_workdone1, s))
+ if (sync_exp_work_done(rsp, NULL, NULL, &rdp->expedited_workdone1, s))
return NULL;
mutex_lock(&rdp->exp_funnel_mutex);
rnp0 = rdp->mynode;
for (; rnp0 != NULL; rnp0 = rnp0->parent) {
if (sync_exp_work_done(rsp, rnp1, rdp,
- &rsp->expedited_workdone2, s))
+ &rdp->expedited_workdone2, s))
return NULL;
mutex_lock(&rnp0->exp_funnel_mutex);
if (rnp1)
@@ -3654,7 +3655,7 @@ static struct rcu_node *exp_funnel_lock(struct rcu_state *rsp, unsigned long s)
rnp1 = rnp0;
}
if (sync_exp_work_done(rsp, rnp1, rdp,
- &rsp->expedited_workdone3, s))
+ &rdp->expedited_workdone3, s))
return NULL;
return rnp1;
}
@@ -3708,8 +3709,7 @@ static void sync_rcu_exp_select_cpus(struct rcu_state *rsp,
sync_exp_reset_tree(rsp);
rcu_for_each_leaf_node(rsp, rnp) {
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
/* Each pass checks a CPU for identity, offline, and idle. */
mask_ofl_test = 0;
@@ -3741,24 +3741,22 @@ retry_ipi:
ret = smp_call_function_single(cpu, func, rsp, 0);
if (!ret) {
mask_ofl_ipi &= ~mask;
- } else {
- /* Failed, raced with offline. */
- raw_spin_lock_irqsave(&rnp->lock, flags);
- if (cpu_online(cpu) &&
- (rnp->expmask & mask)) {
- raw_spin_unlock_irqrestore(&rnp->lock,
- flags);
- schedule_timeout_uninterruptible(1);
- if (cpu_online(cpu) &&
- (rnp->expmask & mask))
- goto retry_ipi;
- raw_spin_lock_irqsave(&rnp->lock,
- flags);
- }
- if (!(rnp->expmask & mask))
- mask_ofl_ipi &= ~mask;
+ continue;
+ }
+ /* Failed, raced with offline. */
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
+ if (cpu_online(cpu) &&
+ (rnp->expmask & mask)) {
raw_spin_unlock_irqrestore(&rnp->lock, flags);
+ schedule_timeout_uninterruptible(1);
+ if (cpu_online(cpu) &&
+ (rnp->expmask & mask))
+ goto retry_ipi;
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
}
+ if (!(rnp->expmask & mask))
+ mask_ofl_ipi &= ~mask;
+ raw_spin_unlock_irqrestore(&rnp->lock, flags);
}
/* Report quiescent states for those that went offline. */
mask_ofl_test |= mask_ofl_ipi;
@@ -3773,6 +3771,7 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
unsigned long jiffies_stall;
unsigned long jiffies_start;
unsigned long mask;
+ int ndetected;
struct rcu_node *rnp;
struct rcu_node *rnp_root = rcu_get_root(rsp);
int ret;
@@ -3785,7 +3784,7 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
rsp->expedited_wq,
sync_rcu_preempt_exp_done(rnp_root),
jiffies_stall);
- if (ret > 0)
+ if (ret > 0 || sync_rcu_preempt_exp_done(rnp_root))
return;
if (ret < 0) {
/* Hit a signal, disable CPU stall warnings. */
@@ -3795,14 +3794,16 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
}
pr_err("INFO: %s detected expedited stalls on CPUs/tasks: {",
rsp->name);
+ ndetected = 0;
rcu_for_each_leaf_node(rsp, rnp) {
- (void)rcu_print_task_exp_stall(rnp);
+ ndetected = rcu_print_task_exp_stall(rnp);
mask = 1;
for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) {
struct rcu_data *rdp;
if (!(rnp->expmask & mask))
continue;
+ ndetected++;
rdp = per_cpu_ptr(rsp->rda, cpu);
pr_cont(" %d-%c%c%c", cpu,
"O."[cpu_online(cpu)],
@@ -3811,8 +3812,23 @@ static void synchronize_sched_expedited_wait(struct rcu_state *rsp)
}
mask <<= 1;
}
- pr_cont(" } %lu jiffies s: %lu\n",
- jiffies - jiffies_start, rsp->expedited_sequence);
+ pr_cont(" } %lu jiffies s: %lu root: %#lx/%c\n",
+ jiffies - jiffies_start, rsp->expedited_sequence,
+ rnp_root->expmask, ".T"[!!rnp_root->exp_tasks]);
+ if (!ndetected) {
+ pr_err("blocking rcu_node structures:");
+ rcu_for_each_node_breadth_first(rsp, rnp) {
+ if (rnp == rnp_root)
+ continue; /* printed unconditionally */
+ if (sync_rcu_preempt_exp_done(rnp))
+ continue;
+ pr_cont(" l=%u:%d-%d:%#lx/%c",
+ rnp->level, rnp->grplo, rnp->grphi,
+ rnp->expmask,
+ ".T"[!!rnp->exp_tasks]);
+ }
+ pr_cont("\n");
+ }
rcu_for_each_leaf_node(rsp, rnp) {
mask = 1;
for (cpu = rnp->grplo; cpu <= rnp->grphi; cpu++, mask <<= 1) {
@@ -3847,6 +3863,16 @@ void synchronize_sched_expedited(void)
struct rcu_node *rnp;
struct rcu_state *rsp = &rcu_sched_state;
+ /* If only one CPU, this is automatically a grace period. */
+ if (rcu_blocking_is_gp())
+ return;
+
+ /* If expedited grace periods are prohibited, fall back to normal. */
+ if (rcu_gp_is_normal()) {
+ wait_rcu_gp(call_rcu_sched);
+ return;
+ }
+
/* Take a snapshot of the sequence number. */
s = rcu_exp_gp_seq_snap(rsp);
@@ -4135,7 +4161,7 @@ static void rcu_init_new_rnp(struct rcu_node *rnp_leaf)
rnp = rnp->parent;
if (rnp == NULL)
return;
- raw_spin_lock(&rnp->lock); /* Interrupts already disabled. */
+ raw_spin_lock_rcu_node(rnp); /* Interrupts already disabled. */
rnp->qsmaskinit |= mask;
raw_spin_unlock(&rnp->lock); /* Interrupts remain disabled. */
}
@@ -4152,7 +4178,7 @@ rcu_boot_init_percpu_data(int cpu, struct rcu_state *rsp)
struct rcu_node *rnp = rcu_get_root(rsp);
/* Set up local state, ensuring consistent view of global state. */
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
rdp->grpmask = 1UL << (cpu - rdp->mynode->grplo);
rdp->dynticks = &per_cpu(rcu_dynticks, cpu);
WARN_ON_ONCE(rdp->dynticks->dynticks_nesting != DYNTICK_TASK_EXIT_IDLE);
@@ -4179,7 +4205,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
struct rcu_node *rnp = rcu_get_root(rsp);
/* Set up local state, ensuring consistent view of global state. */
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
rdp->qlen_last_fqs_check = 0;
rdp->n_force_qs_snap = rsp->n_force_qs;
rdp->blimit = blimit;
@@ -4198,8 +4224,7 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
*/
rnp = rdp->mynode;
mask = rdp->grpmask;
- raw_spin_lock(&rnp->lock); /* irqs already disabled. */
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
rnp->qsmaskinitnext |= mask;
rnp->expmaskinitnext |= mask;
if (!rdp->beenonline)
@@ -4327,14 +4352,14 @@ static int __init rcu_spawn_gp_kthread(void)
t = kthread_create(rcu_gp_kthread, rsp, "%s", rsp->name);
BUG_ON(IS_ERR(t));
rnp = rcu_get_root(rsp);
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
rsp->gp_kthread = t;
if (kthread_prio) {
sp.sched_priority = kthread_prio;
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
}
- wake_up_process(t);
raw_spin_unlock_irqrestore(&rnp->lock, flags);
+ wake_up_process(t);
}
rcu_spawn_nocb_kthreads();
rcu_spawn_boost_kthreads();
@@ -4385,12 +4410,14 @@ static void __init rcu_init_levelspread(int *levelspread, const int *levelcnt)
/*
* Helper function for rcu_init() that initializes one rcu_state structure.
*/
-static void __init rcu_init_one(struct rcu_state *rsp,
- struct rcu_data __percpu *rda)
+static void __init rcu_init_one(struct rcu_state *rsp)
{
static const char * const buf[] = RCU_NODE_NAME_INIT;
static const char * const fqs[] = RCU_FQS_NAME_INIT;
static const char * const exp[] = RCU_EXP_NAME_INIT;
+ static struct lock_class_key rcu_node_class[RCU_NUM_LVLS];
+ static struct lock_class_key rcu_fqs_class[RCU_NUM_LVLS];
+ static struct lock_class_key rcu_exp_class[RCU_NUM_LVLS];
static u8 fl_mask = 0x1;
int levelcnt[RCU_NUM_LVLS]; /* # nodes in each level. */
@@ -4576,8 +4603,8 @@ void __init rcu_init(void)
rcu_bootup_announce();
rcu_init_geometry();
- rcu_init_one(&rcu_bh_state, &rcu_bh_data);
- rcu_init_one(&rcu_sched_state, &rcu_sched_data);
+ rcu_init_one(&rcu_bh_state);
+ rcu_init_one(&rcu_sched_state);
if (dump_tree)
rcu_dump_rcu_node_tree(&rcu_sched_state);
__rcu_init_preempt();
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index 9fb4e23..83360b4 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -178,6 +178,8 @@ struct rcu_node {
/* beginning of each expedited GP. */
unsigned long expmaskinitnext;
/* Online CPUs for next expedited GP. */
+ /* Any CPU that has ever been online will */
+ /* have its bit set. */
unsigned long grpmask; /* Mask to apply to parent qsmask. */
/* Only one bit will be set in this mask. */
int grplo; /* lowest-numbered CPU or group here. */
@@ -384,6 +386,10 @@ struct rcu_data {
struct rcu_head oom_head;
#endif /* #ifdef CONFIG_RCU_FAST_NO_HZ */
struct mutex exp_funnel_mutex;
+ atomic_long_t expedited_workdone0; /* # done by others #0. */
+ atomic_long_t expedited_workdone1; /* # done by others #1. */
+ atomic_long_t expedited_workdone2; /* # done by others #2. */
+ atomic_long_t expedited_workdone3; /* # done by others #3. */
/* 7) Callback offloading. */
#ifdef CONFIG_RCU_NOCB_CPU
@@ -498,10 +504,6 @@ struct rcu_state {
/* End of fields guarded by barrier_mutex. */
unsigned long expedited_sequence; /* Take a ticket. */
- atomic_long_t expedited_workdone0; /* # done by others #0. */
- atomic_long_t expedited_workdone1; /* # done by others #1. */
- atomic_long_t expedited_workdone2; /* # done by others #2. */
- atomic_long_t expedited_workdone3; /* # done by others #3. */
atomic_long_t expedited_normal; /* # fallbacks to normal. */
atomic_t expedited_need_qs; /* # CPUs left to check in. */
wait_queue_head_t expedited_wq; /* Wait for check-ins. */
@@ -545,6 +547,18 @@ struct rcu_state {
#define RCU_GP_CLEANUP 5 /* Grace-period cleanup started. */
#define RCU_GP_CLEANED 6 /* Grace-period cleanup complete. */
+#ifndef RCU_TREE_NONCORE
+static const char * const gp_state_names[] = {
+ "RCU_GP_IDLE",
+ "RCU_GP_WAIT_GPS",
+ "RCU_GP_DONE_GPS",
+ "RCU_GP_WAIT_FQS",
+ "RCU_GP_DOING_FQS",
+ "RCU_GP_CLEANUP",
+ "RCU_GP_CLEANED",
+};
+#endif /* #ifndef RCU_TREE_NONCORE */
+
extern struct list_head rcu_struct_flavors;
/* Sequence through rcu_state structures for each RCU flavor. */
@@ -664,3 +678,42 @@ static inline void rcu_nocb_q_lengths(struct rcu_data *rdp, long *ql, long *qll)
#else /* #ifdef CONFIG_PPC */
#define smp_mb__after_unlock_lock() do { } while (0)
#endif /* #else #ifdef CONFIG_PPC */
+
+/*
+ * Wrappers for the rcu_node::lock acquire.
+ *
+ * Because the rcu_nodes form a tree, the tree traversal locking will observe
+ * different lock values, this in turn means that an UNLOCK of one level
+ * followed by a LOCK of another level does not imply a full memory barrier;
+ * and most importantly transitivity is lost.
+ *
+ * In order to restore full ordering between tree levels, augment the regular
+ * lock acquire functions with smp_mb__after_unlock_lock().
+ */
+static inline void raw_spin_lock_rcu_node(struct rcu_node *rnp)
+{
+ raw_spin_lock(&rnp->lock);
+ smp_mb__after_unlock_lock();
+}
+
+static inline void raw_spin_lock_irq_rcu_node(struct rcu_node *rnp)
+{
+ raw_spin_lock_irq(&rnp->lock);
+ smp_mb__after_unlock_lock();
+}
+
+#define raw_spin_lock_irqsave_rcu_node(rnp, flags) \
+do { \
+ typecheck(unsigned long, flags); \
+ raw_spin_lock_irqsave(&(rnp)->lock, flags); \
+ smp_mb__after_unlock_lock(); \
+} while (0)
+
+static inline bool raw_spin_trylock_rcu_node(struct rcu_node *rnp)
+{
+ bool locked = raw_spin_trylock(&rnp->lock);
+
+ if (locked)
+ smp_mb__after_unlock_lock();
+ return locked;
+}
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index 630c197..9467a8b 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -63,8 +63,7 @@ static bool __read_mostly rcu_nocb_poll; /* Offload kthread are to poll. */
/*
* Check the RCU kernel configuration parameters and print informative
- * messages about anything out of the ordinary. If you like #ifdef, you
- * will love this function.
+ * messages about anything out of the ordinary.
*/
static void __init rcu_bootup_announce_oddness(void)
{
@@ -147,8 +146,8 @@ static void __init rcu_bootup_announce(void)
* the corresponding expedited grace period will also be the end of the
* normal grace period.
*/
-static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
- unsigned long flags) __releases(rnp->lock)
+static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp)
+ __releases(rnp->lock) /* But leaves rrupts disabled. */
{
int blkd_state = (rnp->gp_tasks ? RCU_GP_TASKS : 0) +
(rnp->exp_tasks ? RCU_EXP_TASKS : 0) +
@@ -236,7 +235,7 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
rnp->gp_tasks = &t->rcu_node_entry;
if (!rnp->exp_tasks && (blkd_state & RCU_EXP_BLKD))
rnp->exp_tasks = &t->rcu_node_entry;
- raw_spin_unlock(&rnp->lock);
+ raw_spin_unlock(&rnp->lock); /* rrupts remain disabled. */
/*
* Report the quiescent state for the expedited GP. This expedited
@@ -251,7 +250,6 @@ static void rcu_preempt_ctxt_queue(struct rcu_node *rnp, struct rcu_data *rdp,
} else {
WARN_ON_ONCE(t->rcu_read_unlock_special.b.exp_need_qs);
}
- local_irq_restore(flags);
}
/*
@@ -286,12 +284,11 @@ static void rcu_preempt_qs(void)
* predating the current grace period drain, in other words, until
* rnp->gp_tasks becomes NULL.
*
- * Caller must disable preemption.
+ * Caller must disable interrupts.
*/
static void rcu_preempt_note_context_switch(void)
{
struct task_struct *t = current;
- unsigned long flags;
struct rcu_data *rdp;
struct rcu_node *rnp;
@@ -301,8 +298,7 @@ static void rcu_preempt_note_context_switch(void)
/* Possibly blocking in an RCU read-side critical section. */
rdp = this_cpu_ptr(rcu_state_p->rda);
rnp = rdp->mynode;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp);
t->rcu_read_unlock_special.b.blocked = true;
t->rcu_blocked_node = rnp;
@@ -318,7 +314,7 @@ static void rcu_preempt_note_context_switch(void)
(rnp->qsmask & rdp->grpmask)
? rnp->gpnum
: rnp->gpnum + 1);
- rcu_preempt_ctxt_queue(rnp, rdp, flags);
+ rcu_preempt_ctxt_queue(rnp, rdp);
} else if (t->rcu_read_lock_nesting < 0 &&
t->rcu_read_unlock_special.s) {
@@ -450,20 +446,13 @@ void rcu_read_unlock_special(struct task_struct *t)
/*
* Remove this task from the list it blocked on. The task
- * now remains queued on the rcu_node corresponding to
- * the CPU it first blocked on, so the first attempt to
- * acquire the task's rcu_node's ->lock will succeed.
- * Keep the loop and add a WARN_ON() out of sheer paranoia.
+ * now remains queued on the rcu_node corresponding to the
+ * CPU it first blocked on, so there is no longer any need
+ * to loop. Retain a WARN_ON_ONCE() out of sheer paranoia.
*/
- for (;;) {
- rnp = t->rcu_blocked_node;
- raw_spin_lock(&rnp->lock); /* irqs already disabled. */
- smp_mb__after_unlock_lock();
- if (rnp == t->rcu_blocked_node)
- break;
- WARN_ON_ONCE(1);
- raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
- }
+ rnp = t->rcu_blocked_node;
+ raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
+ WARN_ON_ONCE(rnp != t->rcu_blocked_node);
empty_norm = !rcu_preempt_blocked_readers_cgp(rnp);
empty_exp = sync_rcu_preempt_exp_done(rnp);
smp_mb(); /* ensure expedited fastpath sees end of RCU c-s. */
@@ -527,7 +516,7 @@ static void rcu_print_detail_task_stall_rnp(struct rcu_node *rnp)
unsigned long flags;
struct task_struct *t;
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
if (!rcu_preempt_blocked_readers_cgp(rnp)) {
raw_spin_unlock_irqrestore(&rnp->lock, flags);
return;
@@ -748,6 +737,12 @@ void synchronize_rcu_expedited(void)
struct rcu_state *rsp = rcu_state_p;
unsigned long s;
+ /* If expedited grace periods are prohibited, fall back to normal. */
+ if (rcu_gp_is_normal()) {
+ wait_rcu_gp(call_rcu);
+ return;
+ }
+
s = rcu_exp_gp_seq_snap(rsp);
rnp_unlock = exp_funnel_lock(rsp, s);
@@ -788,7 +783,7 @@ EXPORT_SYMBOL_GPL(rcu_barrier);
*/
static void __init __rcu_init_preempt(void)
{
- rcu_init_one(rcu_state_p, rcu_data_p);
+ rcu_init_one(rcu_state_p);
}
/*
@@ -989,8 +984,7 @@ static int rcu_boost(struct rcu_node *rnp)
READ_ONCE(rnp->boost_tasks) == NULL)
return 0; /* Nothing left to boost. */
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
/*
* Recheck under the lock: all tasks in need of boosting
@@ -1176,8 +1170,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
"rcub/%d", rnp_index);
if (IS_ERR(t))
return PTR_ERR(t);
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
rnp->boost_kthread_task = t;
raw_spin_unlock_irqrestore(&rnp->lock, flags);
sp.sched_priority = kthread_prio;
@@ -1524,7 +1517,8 @@ static void rcu_prepare_for_idle(void)
struct rcu_state *rsp;
int tne;
- if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL))
+ if (IS_ENABLED(CONFIG_RCU_NOCB_CPU_ALL) ||
+ rcu_is_nocb_cpu(smp_processor_id()))
return;
/* Handle nohz enablement switches conservatively. */
@@ -1538,10 +1532,6 @@ static void rcu_prepare_for_idle(void)
if (!tne)
return;
- /* If this is a no-CBs CPU, no callbacks, just return. */
- if (rcu_is_nocb_cpu(smp_processor_id()))
- return;
-
/*
* If a non-lazy callback arrived at a CPU having only lazy
* callbacks, invoke RCU core for the side-effect of recalculating
@@ -1567,8 +1557,7 @@ static void rcu_prepare_for_idle(void)
if (!*rdp->nxttail[RCU_DONE_TAIL])
continue;
rnp = rdp->mynode;
- raw_spin_lock(&rnp->lock); /* irqs already disabled. */
- smp_mb__after_unlock_lock();
+ raw_spin_lock_rcu_node(rnp); /* irqs already disabled. */
needwake = rcu_accelerate_cbs(rsp, rnp, rdp);
raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
if (needwake)
@@ -2068,8 +2057,7 @@ static void rcu_nocb_wait_gp(struct rcu_data *rdp)
bool needwake;
struct rcu_node *rnp = rdp->mynode;
- raw_spin_lock_irqsave(&rnp->lock, flags);
- smp_mb__after_unlock_lock();
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
needwake = rcu_start_future_gp(rnp, rdp, &c);
raw_spin_unlock_irqrestore(&rnp->lock, flags);
if (needwake)
diff --git a/kernel/rcu/tree_trace.c b/kernel/rcu/tree_trace.c
index ef7093c..1088e64 100644
--- a/kernel/rcu/tree_trace.c
+++ b/kernel/rcu/tree_trace.c
@@ -1,5 +1,5 @@
/*
- * Read-Copy Update tracing for classic implementation
+ * Read-Copy Update tracing for hierarchical implementation.
*
* 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
@@ -16,6 +16,7 @@
* http://www.gnu.org/licenses/gpl-2.0.html.
*
* Copyright IBM Corporation, 2008
+ * Author: Paul E. McKenney
*
* Papers: http://www.rdrop.com/users/paulmck/RCU
*
@@ -33,9 +34,7 @@
#include <linux/sched.h>
#include <linux/atomic.h>
#include <linux/bitops.h>
-#include <linux/module.h>
#include <linux/completion.h>
-#include <linux/moduleparam.h>
#include <linux/percpu.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
@@ -183,14 +182,20 @@ static const struct file_operations rcudata_fops = {
static int show_rcuexp(struct seq_file *m, void *v)
{
+ int cpu;
struct rcu_state *rsp = (struct rcu_state *)m->private;
-
+ struct rcu_data *rdp;
+ unsigned long s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+
+ for_each_possible_cpu(cpu) {
+ rdp = per_cpu_ptr(rsp->rda, cpu);
+ s0 += atomic_long_read(&rdp->expedited_workdone0);
+ s1 += atomic_long_read(&rdp->expedited_workdone1);
+ s2 += atomic_long_read(&rdp->expedited_workdone2);
+ s3 += atomic_long_read(&rdp->expedited_workdone3);
+ }
seq_printf(m, "s=%lu wd0=%lu wd1=%lu wd2=%lu wd3=%lu n=%lu enq=%d sc=%lu\n",
- rsp->expedited_sequence,
- atomic_long_read(&rsp->expedited_workdone0),
- atomic_long_read(&rsp->expedited_workdone1),
- atomic_long_read(&rsp->expedited_workdone2),
- atomic_long_read(&rsp->expedited_workdone3),
+ rsp->expedited_sequence, s0, s1, s2, s3,
atomic_long_read(&rsp->expedited_normal),
atomic_read(&rsp->expedited_need_qs),
rsp->expedited_sequence / 2);
@@ -319,7 +324,7 @@ static void show_one_rcugp(struct seq_file *m, struct rcu_state *rsp)
unsigned long gpmax;
struct rcu_node *rnp = &rsp->node[0];
- raw_spin_lock_irqsave(&rnp->lock, flags);
+ raw_spin_lock_irqsave_rcu_node(rnp, flags);
completed = READ_ONCE(rsp->completed);
gpnum = READ_ONCE(rsp->gpnum);
if (completed == gpnum)
@@ -487,16 +492,4 @@ free_out:
debugfs_remove_recursive(rcudir);
return 1;
}
-
-static void __exit rcutree_trace_cleanup(void)
-{
- debugfs_remove_recursive(rcudir);
-}
-
-
-module_init(rcutree_trace_init);
-module_exit(rcutree_trace_cleanup);
-
-MODULE_AUTHOR("Paul E. McKenney");
-MODULE_DESCRIPTION("Read-Copy Update tracing for hierarchical implementation");
-MODULE_LICENSE("GPL");
+device_initcall(rcutree_trace_init);
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 5f748c5..76b94e1 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -60,7 +60,12 @@ MODULE_ALIAS("rcupdate");
#endif
#define MODULE_PARAM_PREFIX "rcupdate."
+#ifndef CONFIG_TINY_RCU
module_param(rcu_expedited, int, 0);
+module_param(rcu_normal, int, 0);
+static int rcu_normal_after_boot;
+module_param(rcu_normal_after_boot, int, 0);
+#endif /* #ifndef CONFIG_TINY_RCU */
#if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT)
/**
@@ -113,6 +118,17 @@ EXPORT_SYMBOL(rcu_read_lock_sched_held);
#ifndef CONFIG_TINY_RCU
+/*
+ * Should expedited grace-period primitives always fall back to their
+ * non-expedited counterparts? Intended for use within RCU. Note
+ * that if the user specifies both rcu_expedited and rcu_normal, then
+ * rcu_normal wins.
+ */
+bool rcu_gp_is_normal(void)
+{
+ return READ_ONCE(rcu_normal);
+}
+
static atomic_t rcu_expedited_nesting =
ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0);
@@ -157,8 +173,6 @@ void rcu_unexpedite_gp(void)
}
EXPORT_SYMBOL_GPL(rcu_unexpedite_gp);
-#endif /* #ifndef CONFIG_TINY_RCU */
-
/*
* Inform RCU of the end of the in-kernel boot sequence.
*/
@@ -166,8 +180,12 @@ void rcu_end_inkernel_boot(void)
{
if (IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT))
rcu_unexpedite_gp();
+ if (rcu_normal_after_boot)
+ WRITE_ONCE(rcu_normal, 1);
}
+#endif /* #ifndef CONFIG_TINY_RCU */
+
#ifdef CONFIG_PREEMPT_RCU
/*
diff --git a/kernel/sched/auto_group.c b/kernel/sched/auto_group.c
index 750ed60..a5d966c 100644
--- a/kernel/sched/auto_group.c
+++ b/kernel/sched/auto_group.c
@@ -212,7 +212,7 @@ int proc_sched_autogroup_set_nice(struct task_struct *p, int nice)
ag = autogroup_task_get(p);
down_write(&ag->lock);
- err = sched_group_set_shares(ag->tg, prio_to_weight[nice + 20]);
+ err = sched_group_set_shares(ag->tg, sched_prio_to_weight[nice + 20]);
if (!err)
ag->nice = nice;
up_write(&ag->lock);
diff --git a/kernel/sched/clock.c b/kernel/sched/clock.c
index c0a2051..bc54e84 100644
--- a/kernel/sched/clock.c
+++ b/kernel/sched/clock.c
@@ -1,7 +1,7 @@
/*
* sched_clock for unstable cpu clocks
*
- * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra
*
* Updates and enhancements:
* Copyright (C) 2008 Red Hat, Inc. Steven Rostedt <srostedt@redhat.com>
@@ -354,7 +354,7 @@ void sched_clock_idle_wakeup_event(u64 delta_ns)
return;
sched_clock_tick();
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sched();
}
EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 4d568ac..77d97a6 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -731,7 +731,7 @@ bool sched_can_stop_tick(void)
if (current->policy == SCHED_RR) {
struct sched_rt_entity *rt_se = &current->rt;
- return rt_se->run_list.prev == rt_se->run_list.next;
+ return list_is_singular(&rt_se->run_list);
}
/*
@@ -823,8 +823,8 @@ static void set_load_weight(struct task_struct *p)
return;
}
- load->weight = scale_load(prio_to_weight[prio]);
- load->inv_weight = prio_to_wmult[prio];
+ load->weight = scale_load(sched_prio_to_weight[prio]);
+ load->inv_weight = sched_prio_to_wmult[prio];
}
static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
@@ -1071,8 +1071,8 @@ static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new
{
lockdep_assert_held(&rq->lock);
- dequeue_task(rq, p, 0);
p->on_rq = TASK_ON_RQ_MIGRATING;
+ dequeue_task(rq, p, 0);
set_task_cpu(p, new_cpu);
raw_spin_unlock(&rq->lock);
@@ -1080,8 +1080,8 @@ static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new
raw_spin_lock(&rq->lock);
BUG_ON(task_cpu(p) != new_cpu);
- p->on_rq = TASK_ON_RQ_QUEUED;
enqueue_task(rq, p, 0);
+ p->on_rq = TASK_ON_RQ_QUEUED;
check_preempt_curr(rq, p, 0);
return rq;
@@ -1274,6 +1274,15 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
!p->on_rq);
+ /*
+ * Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING,
+ * because schedstat_wait_{start,end} rebase migrating task's wait_start
+ * time relying on p->on_rq.
+ */
+ WARN_ON_ONCE(p->state == TASK_RUNNING &&
+ p->sched_class == &fair_sched_class &&
+ (p->on_rq && !task_on_rq_migrating(p)));
+
#ifdef CONFIG_LOCKDEP
/*
* The caller should hold either p->pi_lock or rq->lock, when changing
@@ -1310,9 +1319,11 @@ static void __migrate_swap_task(struct task_struct *p, int cpu)
src_rq = task_rq(p);
dst_rq = cpu_rq(cpu);
+ p->on_rq = TASK_ON_RQ_MIGRATING;
deactivate_task(src_rq, p, 0);
set_task_cpu(p, cpu);
activate_task(dst_rq, p, 0);
+ p->on_rq = TASK_ON_RQ_QUEUED;
check_preempt_curr(dst_rq, p, 0);
} else {
/*
@@ -1905,6 +1916,97 @@ static void ttwu_queue(struct task_struct *p, int cpu)
raw_spin_unlock(&rq->lock);
}
+/*
+ * Notes on Program-Order guarantees on SMP systems.
+ *
+ * MIGRATION
+ *
+ * The basic program-order guarantee on SMP systems is that when a task [t]
+ * migrates, all its activity on its old cpu [c0] happens-before any subsequent
+ * execution on its new cpu [c1].
+ *
+ * For migration (of runnable tasks) this is provided by the following means:
+ *
+ * A) UNLOCK of the rq(c0)->lock scheduling out task t
+ * B) migration for t is required to synchronize *both* rq(c0)->lock and
+ * rq(c1)->lock (if not at the same time, then in that order).
+ * C) LOCK of the rq(c1)->lock scheduling in task
+ *
+ * Transitivity guarantees that B happens after A and C after B.
+ * Note: we only require RCpc transitivity.
+ * Note: the cpu doing B need not be c0 or c1
+ *
+ * Example:
+ *
+ * CPU0 CPU1 CPU2
+ *
+ * LOCK rq(0)->lock
+ * sched-out X
+ * sched-in Y
+ * UNLOCK rq(0)->lock
+ *
+ * LOCK rq(0)->lock // orders against CPU0
+ * dequeue X
+ * UNLOCK rq(0)->lock
+ *
+ * LOCK rq(1)->lock
+ * enqueue X
+ * UNLOCK rq(1)->lock
+ *
+ * LOCK rq(1)->lock // orders against CPU2
+ * sched-out Z
+ * sched-in X
+ * UNLOCK rq(1)->lock
+ *
+ *
+ * BLOCKING -- aka. SLEEP + WAKEUP
+ *
+ * For blocking we (obviously) need to provide the same guarantee as for
+ * migration. However the means are completely different as there is no lock
+ * chain to provide order. Instead we do:
+ *
+ * 1) smp_store_release(X->on_cpu, 0)
+ * 2) smp_cond_acquire(!X->on_cpu)
+ *
+ * Example:
+ *
+ * CPU0 (schedule) CPU1 (try_to_wake_up) CPU2 (schedule)
+ *
+ * LOCK rq(0)->lock LOCK X->pi_lock
+ * dequeue X
+ * sched-out X
+ * smp_store_release(X->on_cpu, 0);
+ *
+ * smp_cond_acquire(!X->on_cpu);
+ * X->state = WAKING
+ * set_task_cpu(X,2)
+ *
+ * LOCK rq(2)->lock
+ * enqueue X
+ * X->state = RUNNING
+ * UNLOCK rq(2)->lock
+ *
+ * LOCK rq(2)->lock // orders against CPU1
+ * sched-out Z
+ * sched-in X
+ * UNLOCK rq(2)->lock
+ *
+ * UNLOCK X->pi_lock
+ * UNLOCK rq(0)->lock
+ *
+ *
+ * However; for wakeups there is a second guarantee we must provide, namely we
+ * must observe the state that lead to our wakeup. That is, not only must our
+ * task observe its own prior state, it must also observe the stores prior to
+ * its wakeup.
+ *
+ * This means that any means of doing remote wakeups must order the CPU doing
+ * the wakeup against the CPU the task is going to end up running on. This,
+ * however, is already required for the regular Program-Order guarantee above,
+ * since the waking CPU is the one issueing the ACQUIRE (smp_cond_acquire).
+ *
+ */
+
/**
* try_to_wake_up - wake up a thread
* @p: the thread to be awakened
@@ -1947,15 +2049,34 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
#ifdef CONFIG_SMP
/*
- * If the owning (remote) cpu is still in the middle of schedule() with
- * this task as prev, wait until its done referencing the task.
+ * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be
+ * possible to, falsely, observe p->on_cpu == 0.
+ *
+ * One must be running (->on_cpu == 1) in order to remove oneself
+ * from the runqueue.
+ *
+ * [S] ->on_cpu = 1; [L] ->on_rq
+ * UNLOCK rq->lock
+ * RMB
+ * LOCK rq->lock
+ * [S] ->on_rq = 0; [L] ->on_cpu
+ *
+ * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock
+ * from the consecutive calls to schedule(); the first switching to our
+ * task, the second putting it to sleep.
*/
- while (p->on_cpu)
- cpu_relax();
+ smp_rmb();
+
/*
- * Pairs with the smp_wmb() in finish_lock_switch().
+ * If the owning (remote) cpu is still in the middle of schedule() with
+ * this task as prev, wait until its done referencing the task.
+ *
+ * Pairs with the smp_store_release() in finish_lock_switch().
+ *
+ * This ensures that tasks getting woken will be fully ordered against
+ * their previous state and preserve Program Order.
*/
- smp_rmb();
+ smp_cond_acquire(!p->on_cpu);
p->sched_contributes_to_load = !!task_contributes_to_load(p);
p->state = TASK_WAKING;
@@ -2039,7 +2160,6 @@ out:
*/
int wake_up_process(struct task_struct *p)
{
- WARN_ON(task_is_stopped_or_traced(p));
return try_to_wake_up(p, TASK_NORMAL, 0);
}
EXPORT_SYMBOL(wake_up_process);
@@ -2085,6 +2205,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
p->se.vruntime = 0;
INIT_LIST_HEAD(&p->se.group_node);
+#ifdef CONFIG_FAIR_GROUP_SCHED
+ p->se.cfs_rq = NULL;
+#endif
+
#ifdef CONFIG_SCHEDSTATS
memset(&p->se.statistics, 0, sizeof(p->se.statistics));
#endif
@@ -3085,7 +3209,6 @@ static void __sched notrace __schedule(bool preempt)
cpu = smp_processor_id();
rq = cpu_rq(cpu);
- rcu_note_context_switch();
prev = rq->curr;
/*
@@ -3104,13 +3227,16 @@ static void __sched notrace __schedule(bool preempt)
if (sched_feat(HRTICK))
hrtick_clear(rq);
+ local_irq_disable();
+ rcu_note_context_switch();
+
/*
* Make sure that signal_pending_state()->signal_pending() below
* can't be reordered with __set_current_state(TASK_INTERRUPTIBLE)
* done by the caller to avoid the race with signal_wake_up().
*/
smp_mb__before_spinlock();
- raw_spin_lock_irq(&rq->lock);
+ raw_spin_lock(&rq->lock);
lockdep_pin_lock(&rq->lock);
rq->clock_skip_update <<= 1; /* promote REQ to ACT */
@@ -5847,13 +5973,13 @@ static int init_rootdomain(struct root_domain *rd)
{
memset(rd, 0, sizeof(*rd));
- if (!alloc_cpumask_var(&rd->span, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL))
goto out;
- if (!alloc_cpumask_var(&rd->online, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&rd->online, GFP_KERNEL))
goto free_span;
- if (!alloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL))
goto free_online;
- if (!alloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
+ if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL))
goto free_dlo_mask;
init_dl_bw(&rd->dl_bw);
@@ -7331,6 +7457,9 @@ int in_sched_functions(unsigned long addr)
*/
struct task_group root_task_group;
LIST_HEAD(task_groups);
+
+/* Cacheline aligned slab cache for task_group */
+static struct kmem_cache *task_group_cache __read_mostly;
#endif
DECLARE_PER_CPU(cpumask_var_t, load_balance_mask);
@@ -7388,11 +7517,12 @@ void __init sched_init(void)
#endif /* CONFIG_RT_GROUP_SCHED */
#ifdef CONFIG_CGROUP_SCHED
+ task_group_cache = KMEM_CACHE(task_group, 0);
+
list_add(&root_task_group.list, &task_groups);
INIT_LIST_HEAD(&root_task_group.children);
INIT_LIST_HEAD(&root_task_group.siblings);
autogroup_init(&init_task);
-
#endif /* CONFIG_CGROUP_SCHED */
for_each_possible_cpu(i) {
@@ -7673,7 +7803,7 @@ static void free_sched_group(struct task_group *tg)
free_fair_sched_group(tg);
free_rt_sched_group(tg);
autogroup_free(tg);
- kfree(tg);
+ kmem_cache_free(task_group_cache, tg);
}
/* allocate runqueue etc for a new task group */
@@ -7681,7 +7811,7 @@ struct task_group *sched_create_group(struct task_group *parent)
{
struct task_group *tg;
- tg = kzalloc(sizeof(*tg), GFP_KERNEL);
+ tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO);
if (!tg)
return ERR_PTR(-ENOMEM);
@@ -8217,12 +8347,12 @@ static void cpu_cgroup_fork(struct task_struct *task, void *private)
sched_move_task(task);
}
-static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int cpu_cgroup_can_attach(struct cgroup_taskset *tset)
{
struct task_struct *task;
+ struct cgroup_subsys_state *css;
- cgroup_taskset_for_each(task, tset) {
+ cgroup_taskset_for_each(task, css, tset) {
#ifdef CONFIG_RT_GROUP_SCHED
if (!sched_rt_can_attach(css_tg(css), task))
return -EINVAL;
@@ -8235,12 +8365,12 @@ static int cpu_cgroup_can_attach(struct cgroup_subsys_state *css,
return 0;
}
-static void cpu_cgroup_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void cpu_cgroup_attach(struct cgroup_taskset *tset)
{
struct task_struct *task;
+ struct cgroup_subsys_state *css;
- cgroup_taskset_for_each(task, tset)
+ cgroup_taskset_for_each(task, css, tset)
sched_move_task(task);
}
@@ -8586,3 +8716,44 @@ void dump_cpu_task(int cpu)
pr_info("Task dump for CPU %d:\n", cpu);
sched_show_task(cpu_curr(cpu));
}
+
+/*
+ * Nice levels are multiplicative, with a gentle 10% change for every
+ * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
+ * nice 1, it will get ~10% less CPU time than another CPU-bound task
+ * that remained on nice 0.
+ *
+ * The "10% effect" is relative and cumulative: from _any_ nice level,
+ * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
+ * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
+ * If a task goes up by ~10% and another task goes down by ~10% then
+ * the relative distance between them is ~25%.)
+ */
+const int sched_prio_to_weight[40] = {
+ /* -20 */ 88761, 71755, 56483, 46273, 36291,
+ /* -15 */ 29154, 23254, 18705, 14949, 11916,
+ /* -10 */ 9548, 7620, 6100, 4904, 3906,
+ /* -5 */ 3121, 2501, 1991, 1586, 1277,
+ /* 0 */ 1024, 820, 655, 526, 423,
+ /* 5 */ 335, 272, 215, 172, 137,
+ /* 10 */ 110, 87, 70, 56, 45,
+ /* 15 */ 36, 29, 23, 18, 15,
+};
+
+/*
+ * Inverse (2^32/x) values of the sched_prio_to_weight[] array, precalculated.
+ *
+ * In cases where the weight does not change often, we can use the
+ * precalculated inverse to speed up arithmetics by turning divisions
+ * into multiplications:
+ */
+const u32 sched_prio_to_wmult[40] = {
+ /* -20 */ 48388, 59856, 76040, 92818, 118348,
+ /* -15 */ 147320, 184698, 229616, 287308, 360437,
+ /* -10 */ 449829, 563644, 704093, 875809, 1099582,
+ /* -5 */ 1376151, 1717300, 2157191, 2708050, 3363326,
+ /* 0 */ 4194304, 5237765, 6557202, 8165337, 10153587,
+ /* 5 */ 12820798, 15790321, 19976592, 24970740, 31350126,
+ /* 10 */ 39045157, 49367440, 61356676, 76695844, 95443717,
+ /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
+};
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 26a5446..b2ab2ff 100644
--- a/kernel/sched/cputime.c
+++ b/kernel/sched/cputime.c
@@ -5,6 +5,9 @@
#include <linux/static_key.h>
#include <linux/context_tracking.h>
#include "sched.h"
+#ifdef CONFIG_PARAVIRT
+#include <asm/paravirt.h>
+#endif
#ifdef CONFIG_IRQ_TIME_ACCOUNTING
@@ -466,7 +469,7 @@ void account_process_tick(struct task_struct *p, int user_tick)
cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy);
struct rq *rq = this_rq();
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
return;
if (sched_clock_irqtime) {
@@ -680,7 +683,7 @@ static cputime_t get_vtime_delta(struct task_struct *tsk)
{
unsigned long long delta = vtime_delta(tsk);
- WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_SLEEPING);
+ WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE);
tsk->vtime_snap += delta;
/* CHECKME: always safe to convert nsecs to cputime? */
@@ -696,37 +699,37 @@ static void __vtime_account_system(struct task_struct *tsk)
void vtime_account_system(struct task_struct *tsk)
{
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
__vtime_account_system(tsk);
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
void vtime_gen_account_irq_exit(struct task_struct *tsk)
{
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
__vtime_account_system(tsk);
if (context_tracking_in_user())
tsk->vtime_snap_whence = VTIME_USER;
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
void vtime_account_user(struct task_struct *tsk)
{
cputime_t delta_cpu;
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
delta_cpu = get_vtime_delta(tsk);
tsk->vtime_snap_whence = VTIME_SYS;
account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu));
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
void vtime_user_enter(struct task_struct *tsk)
{
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
__vtime_account_system(tsk);
tsk->vtime_snap_whence = VTIME_USER;
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
void vtime_guest_enter(struct task_struct *tsk)
@@ -738,19 +741,19 @@ void vtime_guest_enter(struct task_struct *tsk)
* synchronization against the reader (task_gtime())
* that can thus safely catch up with a tickless delta.
*/
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
__vtime_account_system(tsk);
current->flags |= PF_VCPU;
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
EXPORT_SYMBOL_GPL(vtime_guest_enter);
void vtime_guest_exit(struct task_struct *tsk)
{
- write_seqlock(&tsk->vtime_seqlock);
+ write_seqcount_begin(&tsk->vtime_seqcount);
__vtime_account_system(tsk);
current->flags &= ~PF_VCPU;
- write_sequnlock(&tsk->vtime_seqlock);
+ write_seqcount_end(&tsk->vtime_seqcount);
}
EXPORT_SYMBOL_GPL(vtime_guest_exit);
@@ -763,24 +766,26 @@ void vtime_account_idle(struct task_struct *tsk)
void arch_vtime_task_switch(struct task_struct *prev)
{
- write_seqlock(&prev->vtime_seqlock);
- prev->vtime_snap_whence = VTIME_SLEEPING;
- write_sequnlock(&prev->vtime_seqlock);
+ write_seqcount_begin(&prev->vtime_seqcount);
+ prev->vtime_snap_whence = VTIME_INACTIVE;
+ write_seqcount_end(&prev->vtime_seqcount);
- write_seqlock(&current->vtime_seqlock);
+ write_seqcount_begin(&current->vtime_seqcount);
current->vtime_snap_whence = VTIME_SYS;
current->vtime_snap = sched_clock_cpu(smp_processor_id());
- write_sequnlock(&current->vtime_seqlock);
+ write_seqcount_end(&current->vtime_seqcount);
}
void vtime_init_idle(struct task_struct *t, int cpu)
{
unsigned long flags;
- write_seqlock_irqsave(&t->vtime_seqlock, flags);
+ local_irq_save(flags);
+ write_seqcount_begin(&t->vtime_seqcount);
t->vtime_snap_whence = VTIME_SYS;
t->vtime_snap = sched_clock_cpu(cpu);
- write_sequnlock_irqrestore(&t->vtime_seqlock, flags);
+ write_seqcount_end(&t->vtime_seqcount);
+ local_irq_restore(flags);
}
cputime_t task_gtime(struct task_struct *t)
@@ -788,14 +793,17 @@ cputime_t task_gtime(struct task_struct *t)
unsigned int seq;
cputime_t gtime;
+ if (!vtime_accounting_enabled())
+ return t->gtime;
+
do {
- seq = read_seqbegin(&t->vtime_seqlock);
+ seq = read_seqcount_begin(&t->vtime_seqcount);
gtime = t->gtime;
- if (t->flags & PF_VCPU)
+ if (t->vtime_snap_whence == VTIME_SYS && t->flags & PF_VCPU)
gtime += vtime_delta(t);
- } while (read_seqretry(&t->vtime_seqlock, seq));
+ } while (read_seqcount_retry(&t->vtime_seqcount, seq));
return gtime;
}
@@ -818,7 +826,7 @@ fetch_task_cputime(struct task_struct *t,
*udelta = 0;
*sdelta = 0;
- seq = read_seqbegin(&t->vtime_seqlock);
+ seq = read_seqcount_begin(&t->vtime_seqcount);
if (u_dst)
*u_dst = *u_src;
@@ -826,7 +834,7 @@ fetch_task_cputime(struct task_struct *t,
*s_dst = *s_src;
/* Task is sleeping, nothing to add */
- if (t->vtime_snap_whence == VTIME_SLEEPING ||
+ if (t->vtime_snap_whence == VTIME_INACTIVE ||
is_idle_task(t))
continue;
@@ -842,7 +850,7 @@ fetch_task_cputime(struct task_struct *t,
if (t->vtime_snap_whence == VTIME_SYS)
*sdelta = delta;
}
- } while (read_seqretry(&t->vtime_seqlock, seq));
+ } while (read_seqcount_retry(&t->vtime_seqcount, seq));
}
@@ -850,6 +858,14 @@ void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime)
{
cputime_t udelta, sdelta;
+ if (!vtime_accounting_enabled()) {
+ if (utime)
+ *utime = t->utime;
+ if (stime)
+ *stime = t->stime;
+ return;
+ }
+
fetch_task_cputime(t, utime, stime, &t->utime,
&t->stime, &udelta, &sdelta);
if (utime)
@@ -863,6 +879,14 @@ void task_cputime_scaled(struct task_struct *t,
{
cputime_t udelta, sdelta;
+ if (!vtime_accounting_enabled()) {
+ if (utimescaled)
+ *utimescaled = t->utimescaled;
+ if (stimescaled)
+ *stimescaled = t->stimescaled;
+ return;
+ }
+
fetch_task_cputime(t, utimescaled, stimescaled,
&t->utimescaled, &t->stimescaled, &udelta, &sdelta);
if (utimescaled)
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 8b0a15e..cd64c97 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -176,8 +176,10 @@ static void enqueue_pushable_dl_task(struct rq *rq, struct task_struct *p)
}
}
- if (leftmost)
+ if (leftmost) {
dl_rq->pushable_dl_tasks_leftmost = &p->pushable_dl_tasks;
+ dl_rq->earliest_dl.next = p->dl.deadline;
+ }
rb_link_node(&p->pushable_dl_tasks, parent, link);
rb_insert_color(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root);
@@ -195,6 +197,10 @@ static void dequeue_pushable_dl_task(struct rq *rq, struct task_struct *p)
next_node = rb_next(&p->pushable_dl_tasks);
dl_rq->pushable_dl_tasks_leftmost = next_node;
+ if (next_node) {
+ dl_rq->earliest_dl.next = rb_entry(next_node,
+ struct task_struct, pushable_dl_tasks)->dl.deadline;
+ }
}
rb_erase(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root);
@@ -782,42 +788,14 @@ static void update_curr_dl(struct rq *rq)
#ifdef CONFIG_SMP
-static struct task_struct *pick_next_earliest_dl_task(struct rq *rq, int cpu);
-
-static inline u64 next_deadline(struct rq *rq)
-{
- struct task_struct *next = pick_next_earliest_dl_task(rq, rq->cpu);
-
- if (next && dl_prio(next->prio))
- return next->dl.deadline;
- else
- return 0;
-}
-
static void inc_dl_deadline(struct dl_rq *dl_rq, u64 deadline)
{
struct rq *rq = rq_of_dl_rq(dl_rq);
if (dl_rq->earliest_dl.curr == 0 ||
dl_time_before(deadline, dl_rq->earliest_dl.curr)) {
- /*
- * If the dl_rq had no -deadline tasks, or if the new task
- * has shorter deadline than the current one on dl_rq, we
- * know that the previous earliest becomes our next earliest,
- * as the new task becomes the earliest itself.
- */
- dl_rq->earliest_dl.next = dl_rq->earliest_dl.curr;
dl_rq->earliest_dl.curr = deadline;
cpudl_set(&rq->rd->cpudl, rq->cpu, deadline, 1);
- } else if (dl_rq->earliest_dl.next == 0 ||
- dl_time_before(deadline, dl_rq->earliest_dl.next)) {
- /*
- * On the other hand, if the new -deadline task has a
- * a later deadline than the earliest one on dl_rq, but
- * it is earlier than the next (if any), we must
- * recompute the next-earliest.
- */
- dl_rq->earliest_dl.next = next_deadline(rq);
}
}
@@ -839,7 +817,6 @@ static void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline)
entry = rb_entry(leftmost, struct sched_dl_entity, rb_node);
dl_rq->earliest_dl.curr = entry->deadline;
- dl_rq->earliest_dl.next = next_deadline(rq);
cpudl_set(&rq->rd->cpudl, rq->cpu, entry->deadline, 1);
}
}
@@ -1274,28 +1251,6 @@ static int pick_dl_task(struct rq *rq, struct task_struct *p, int cpu)
return 0;
}
-/* Returns the second earliest -deadline task, NULL otherwise */
-static struct task_struct *pick_next_earliest_dl_task(struct rq *rq, int cpu)
-{
- struct rb_node *next_node = rq->dl.rb_leftmost;
- struct sched_dl_entity *dl_se;
- struct task_struct *p = NULL;
-
-next_node:
- next_node = rb_next(next_node);
- if (next_node) {
- dl_se = rb_entry(next_node, struct sched_dl_entity, rb_node);
- p = dl_task_of(dl_se);
-
- if (pick_dl_task(rq, p, cpu))
- return p;
-
- goto next_node;
- }
-
- return NULL;
-}
-
/*
* Return the earliest pushable rq's task, which is suitable to be executed
* on the CPU, NULL otherwise:
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 824aa9f..1926606 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -17,7 +17,7 @@
* Copyright (C) 2007, Thomas Gleixner <tglx@linutronix.de>
*
* Adaptive scheduling granularity, math enhancements by Peter Zijlstra
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*/
#include <linux/latencytop.h>
@@ -738,12 +738,56 @@ static void update_curr_fair(struct rq *rq)
update_curr(cfs_rq_of(&rq->curr->se));
}
+#ifdef CONFIG_SCHEDSTATS
+static inline void
+update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+ u64 wait_start = rq_clock(rq_of(cfs_rq));
+
+ if (entity_is_task(se) && task_on_rq_migrating(task_of(se)) &&
+ likely(wait_start > se->statistics.wait_start))
+ wait_start -= se->statistics.wait_start;
+
+ se->statistics.wait_start = wait_start;
+}
+
+static void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+ struct task_struct *p;
+ u64 delta = rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start;
+
+ if (entity_is_task(se)) {
+ p = task_of(se);
+ if (task_on_rq_migrating(p)) {
+ /*
+ * Preserve migrating task's wait time so wait_start
+ * time stamp can be adjusted to accumulate wait time
+ * prior to migration.
+ */
+ se->statistics.wait_start = delta;
+ return;
+ }
+ trace_sched_stat_wait(p, delta);
+ }
+
+ se->statistics.wait_max = max(se->statistics.wait_max, delta);
+ se->statistics.wait_count++;
+ se->statistics.wait_sum += delta;
+ se->statistics.wait_start = 0;
+}
+#else
static inline void
update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
- schedstat_set(se->statistics.wait_start, rq_clock(rq_of(cfs_rq)));
}
+static inline void
+update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
+{
+}
+#endif
+
/*
* Task is being enqueued - update stats:
*/
@@ -757,23 +801,6 @@ static void update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se)
update_stats_wait_start(cfs_rq, se);
}
-static void
-update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se)
-{
- schedstat_set(se->statistics.wait_max, max(se->statistics.wait_max,
- rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start));
- schedstat_set(se->statistics.wait_count, se->statistics.wait_count + 1);
- schedstat_set(se->statistics.wait_sum, se->statistics.wait_sum +
- rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start);
-#ifdef CONFIG_SCHEDSTATS
- if (entity_is_task(se)) {
- trace_sched_stat_wait(task_of(se),
- rq_clock(rq_of(cfs_rq)) - se->statistics.wait_start);
- }
-#endif
- schedstat_set(se->statistics.wait_start, 0);
-}
-
static inline void
update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se)
{
@@ -2155,6 +2182,7 @@ void task_numa_work(struct callback_head *work)
unsigned long migrate, next_scan, now = jiffies;
struct task_struct *p = current;
struct mm_struct *mm = p->mm;
+ u64 runtime = p->se.sum_exec_runtime;
struct vm_area_struct *vma;
unsigned long start, end;
unsigned long nr_pte_updates = 0;
@@ -2277,6 +2305,17 @@ out:
else
reset_ptenuma_scan(p);
up_read(&mm->mmap_sem);
+
+ /*
+ * Make sure tasks use at least 32x as much time to run other code
+ * than they used here, to limit NUMA PTE scanning overhead to 3% max.
+ * Usually update_task_scan_period slows down scanning enough; on an
+ * overloaded system we need to limit overhead on a per task basis.
+ */
+ if (unlikely(p->se.sum_exec_runtime != runtime)) {
+ u64 diff = p->se.sum_exec_runtime - runtime;
+ p->node_stamp += 32 * diff;
+ }
}
/*
@@ -2302,7 +2341,7 @@ void task_tick_numa(struct rq *rq, struct task_struct *curr)
now = curr->se.sum_exec_runtime;
period = (u64)curr->numa_scan_period * NSEC_PER_MSEC;
- if (now - curr->node_stamp > period) {
+ if (now > curr->node_stamp + period) {
if (!curr->node_stamp)
curr->numa_scan_period = task_scan_min(curr);
curr->node_stamp += period;
@@ -2670,12 +2709,64 @@ static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force)
{
long delta = cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib;
+ /*
+ * No need to update load_avg for root_task_group as it is not used.
+ */
+ if (cfs_rq->tg == &root_task_group)
+ return;
+
if (force || abs(delta) > cfs_rq->tg_load_avg_contrib / 64) {
atomic_long_add(delta, &cfs_rq->tg->load_avg);
cfs_rq->tg_load_avg_contrib = cfs_rq->avg.load_avg;
}
}
+/*
+ * Called within set_task_rq() right before setting a task's cpu. The
+ * caller only guarantees p->pi_lock is held; no other assumptions,
+ * including the state of rq->lock, should be made.
+ */
+void set_task_rq_fair(struct sched_entity *se,
+ struct cfs_rq *prev, struct cfs_rq *next)
+{
+ if (!sched_feat(ATTACH_AGE_LOAD))
+ return;
+
+ /*
+ * We are supposed to update the task to "current" time, then its up to
+ * date and ready to go to new CPU/cfs_rq. But we have difficulty in
+ * getting what current time is, so simply throw away the out-of-date
+ * time. This will result in the wakee task is less decayed, but giving
+ * the wakee more load sounds not bad.
+ */
+ if (se->avg.last_update_time && prev) {
+ u64 p_last_update_time;
+ u64 n_last_update_time;
+
+#ifndef CONFIG_64BIT
+ u64 p_last_update_time_copy;
+ u64 n_last_update_time_copy;
+
+ do {
+ p_last_update_time_copy = prev->load_last_update_time_copy;
+ n_last_update_time_copy = next->load_last_update_time_copy;
+
+ smp_rmb();
+
+ p_last_update_time = prev->avg.last_update_time;
+ n_last_update_time = next->avg.last_update_time;
+
+ } while (p_last_update_time != p_last_update_time_copy ||
+ n_last_update_time != n_last_update_time_copy);
+#else
+ p_last_update_time = prev->avg.last_update_time;
+ n_last_update_time = next->avg.last_update_time;
+#endif
+ __update_load_avg(p_last_update_time, cpu_of(rq_of(prev)),
+ &se->avg, 0, 0, NULL);
+ se->avg.last_update_time = n_last_update_time;
+ }
+}
#else /* CONFIG_FAIR_GROUP_SCHED */
static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {}
#endif /* CONFIG_FAIR_GROUP_SCHED */
@@ -2689,7 +2780,7 @@ static inline int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq)
int decayed, removed = 0;
if (atomic_long_read(&cfs_rq->removed_load_avg)) {
- long r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
+ s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0);
sa->load_avg = max_t(long, sa->load_avg - r, 0);
sa->load_sum = max_t(s64, sa->load_sum - r * LOAD_AVG_MAX, 0);
removed = 1;
@@ -2809,48 +2900,48 @@ dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se)
max_t(s64, cfs_rq->runnable_load_sum - se->avg.load_sum, 0);
}
-/*
- * Task first catches up with cfs_rq, and then subtract
- * itself from the cfs_rq (task must be off the queue now).
- */
-void remove_entity_load_avg(struct sched_entity *se)
-{
- struct cfs_rq *cfs_rq = cfs_rq_of(se);
- u64 last_update_time;
-
#ifndef CONFIG_64BIT
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
+{
u64 last_update_time_copy;
+ u64 last_update_time;
do {
last_update_time_copy = cfs_rq->load_last_update_time_copy;
smp_rmb();
last_update_time = cfs_rq->avg.last_update_time;
} while (last_update_time != last_update_time_copy);
-#else
- last_update_time = cfs_rq->avg.last_update_time;
-#endif
- __update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
- atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
- atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
+ return last_update_time;
}
-
-/*
- * Update the rq's load with the elapsed running time before entering
- * idle. if the last scheduled task is not a CFS task, idle_enter will
- * be the only way to update the runnable statistic.
- */
-void idle_enter_fair(struct rq *this_rq)
+#else
+static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq)
{
+ return cfs_rq->avg.last_update_time;
}
+#endif
/*
- * Update the rq's load with the elapsed idle time before a task is
- * scheduled. if the newly scheduled task is not a CFS task, idle_exit will
- * be the only way to update the runnable statistic.
+ * Task first catches up with cfs_rq, and then subtract
+ * itself from the cfs_rq (task must be off the queue now).
*/
-void idle_exit_fair(struct rq *this_rq)
+void remove_entity_load_avg(struct sched_entity *se)
{
+ struct cfs_rq *cfs_rq = cfs_rq_of(se);
+ u64 last_update_time;
+
+ /*
+ * Newly created task or never used group entity should not be removed
+ * from its (source) cfs_rq
+ */
+ if (se->avg.last_update_time == 0)
+ return;
+
+ last_update_time = cfs_rq_last_update_time(cfs_rq);
+
+ __update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL);
+ atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg);
+ atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg);
}
static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq)
@@ -4240,42 +4331,37 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags)
*/
/*
- * The exact cpuload at various idx values, calculated at every tick would be
- * load = (2^idx - 1) / 2^idx * load + 1 / 2^idx * cur_load
+ * The exact cpuload calculated at every tick would be:
+ *
+ * load' = (1 - 1/2^i) * load + (1/2^i) * cur_load
*
- * If a cpu misses updates for n-1 ticks (as it was idle) and update gets called
- * on nth tick when cpu may be busy, then we have:
- * load = ((2^idx - 1) / 2^idx)^(n-1) * load
- * load = (2^idx - 1) / 2^idx) * load + 1 / 2^idx * cur_load
+ * If a cpu misses updates for n ticks (as it was idle) and update gets
+ * called on the n+1-th tick when cpu may be busy, then we have:
+ *
+ * load_n = (1 - 1/2^i)^n * load_0
+ * load_n+1 = (1 - 1/2^i) * load_n + (1/2^i) * cur_load
*
* decay_load_missed() below does efficient calculation of
- * load = ((2^idx - 1) / 2^idx)^(n-1) * load
- * avoiding 0..n-1 loop doing load = ((2^idx - 1) / 2^idx) * load
+ *
+ * load' = (1 - 1/2^i)^n * load
+ *
+ * Because x^(n+m) := x^n * x^m we can decompose any x^n in power-of-2 factors.
+ * This allows us to precompute the above in said factors, thereby allowing the
+ * reduction of an arbitrary n in O(log_2 n) steps. (See also
+ * fixed_power_int())
*
* The calculation is approximated on a 128 point scale.
- * degrade_zero_ticks is the number of ticks after which load at any
- * particular idx is approximated to be zero.
- * degrade_factor is a precomputed table, a row for each load idx.
- * Each column corresponds to degradation factor for a power of two ticks,
- * based on 128 point scale.
- * Example:
- * row 2, col 3 (=12) says that the degradation at load idx 2 after
- * 8 ticks is 12/128 (which is an approximation of exact factor 3^8/4^8).
- *
- * With this power of 2 load factors, we can degrade the load n times
- * by looking at 1 bits in n and doing as many mult/shift instead of
- * n mult/shifts needed by the exact degradation.
*/
#define DEGRADE_SHIFT 7
-static const unsigned char
- degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
-static const unsigned char
- degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
- {0, 0, 0, 0, 0, 0, 0, 0},
- {64, 32, 8, 0, 0, 0, 0, 0},
- {96, 72, 40, 12, 1, 0, 0},
- {112, 98, 75, 43, 15, 1, 0},
- {120, 112, 98, 76, 45, 16, 2} };
+
+static const u8 degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128};
+static const u8 degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 64, 32, 8, 0, 0, 0, 0, 0 },
+ { 96, 72, 40, 12, 1, 0, 0, 0 },
+ { 112, 98, 75, 43, 15, 1, 0, 0 },
+ { 120, 112, 98, 76, 45, 16, 2, 0 }
+};
/*
* Update cpu_load for any missed ticks, due to tickless idle. The backlog
@@ -4306,14 +4392,46 @@ decay_load_missed(unsigned long load, unsigned long missed_updates, int idx)
return load;
}
-/*
+/**
+ * __update_cpu_load - update the rq->cpu_load[] statistics
+ * @this_rq: The rq to update statistics for
+ * @this_load: The current load
+ * @pending_updates: The number of missed updates
+ * @active: !0 for NOHZ_FULL
+ *
* Update rq->cpu_load[] statistics. This function is usually called every
- * scheduler tick (TICK_NSEC). With tickless idle this will not be called
- * every tick. We fix it up based on jiffies.
+ * scheduler tick (TICK_NSEC).
+ *
+ * This function computes a decaying average:
+ *
+ * load[i]' = (1 - 1/2^i) * load[i] + (1/2^i) * load
+ *
+ * Because of NOHZ it might not get called on every tick which gives need for
+ * the @pending_updates argument.
+ *
+ * load[i]_n = (1 - 1/2^i) * load[i]_n-1 + (1/2^i) * load_n-1
+ * = A * load[i]_n-1 + B ; A := (1 - 1/2^i), B := (1/2^i) * load
+ * = A * (A * load[i]_n-2 + B) + B
+ * = A * (A * (A * load[i]_n-3 + B) + B) + B
+ * = A^3 * load[i]_n-3 + (A^2 + A + 1) * B
+ * = A^n * load[i]_0 + (A^(n-1) + A^(n-2) + ... + 1) * B
+ * = A^n * load[i]_0 + ((1 - A^n) / (1 - A)) * B
+ * = (1 - 1/2^i)^n * (load[i]_0 - load) + load
+ *
+ * In the above we've assumed load_n := load, which is true for NOHZ_FULL as
+ * any change in load would have resulted in the tick being turned back on.
+ *
+ * For regular NOHZ, this reduces to:
+ *
+ * load[i]_n = (1 - 1/2^i)^n * load[i]_0
+ *
+ * see decay_load_misses(). For NOHZ_FULL we get to subtract and add the extra
+ * term. See the @active paramter.
*/
static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
- unsigned long pending_updates)
+ unsigned long pending_updates, int active)
{
+ unsigned long tickless_load = active ? this_rq->cpu_load[0] : 0;
int i, scale;
this_rq->nr_load_updates++;
@@ -4325,8 +4443,9 @@ static void __update_cpu_load(struct rq *this_rq, unsigned long this_load,
/* scale is effectively 1 << i now, and >> i divides by scale */
- old_load = this_rq->cpu_load[i];
+ old_load = this_rq->cpu_load[i] - tickless_load;
old_load = decay_load_missed(old_load, pending_updates - 1, i);
+ old_load += tickless_load;
new_load = this_load;
/*
* Round up the averaging division if load is increasing. This
@@ -4381,16 +4500,17 @@ static void update_idle_cpu_load(struct rq *this_rq)
pending_updates = curr_jiffies - this_rq->last_load_update_tick;
this_rq->last_load_update_tick = curr_jiffies;
- __update_cpu_load(this_rq, load, pending_updates);
+ __update_cpu_load(this_rq, load, pending_updates, 0);
}
/*
* Called from tick_nohz_idle_exit() -- try and fix up the ticks we missed.
*/
-void update_cpu_load_nohz(void)
+void update_cpu_load_nohz(int active)
{
struct rq *this_rq = this_rq();
unsigned long curr_jiffies = READ_ONCE(jiffies);
+ unsigned long load = active ? weighted_cpuload(cpu_of(this_rq)) : 0;
unsigned long pending_updates;
if (curr_jiffies == this_rq->last_load_update_tick)
@@ -4401,10 +4521,11 @@ void update_cpu_load_nohz(void)
if (pending_updates) {
this_rq->last_load_update_tick = curr_jiffies;
/*
- * We were idle, this means load 0, the current load might be
- * !0 due to remote wakeups and the sort.
+ * In the regular NOHZ case, we were idle, this means load 0.
+ * In the NOHZ_FULL case, we were non-idle, we should consider
+ * its weighted load.
*/
- __update_cpu_load(this_rq, 0, pending_updates);
+ __update_cpu_load(this_rq, load, pending_updates, active);
}
raw_spin_unlock(&this_rq->lock);
}
@@ -4420,7 +4541,7 @@ void update_cpu_load_active(struct rq *this_rq)
* See the mess around update_idle_cpu_load() / update_cpu_load_nohz().
*/
this_rq->last_load_update_tick = jiffies;
- __update_cpu_load(this_rq, load, 1);
+ __update_cpu_load(this_rq, load, 1, 1);
}
/*
@@ -5007,8 +5128,7 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
/*
* Called immediately before a task is migrated to a new cpu; task_cpu(p) and
* cfs_rq_of(p) references at time of call are still valid and identify the
- * previous cpu. However, the caller only guarantees p->pi_lock is held; no
- * other assumptions, including the state of rq->lock, should be made.
+ * previous cpu. The caller guarantees p->pi_lock or task_rq(p)->lock is held.
*/
static void migrate_task_rq_fair(struct task_struct *p)
{
@@ -5721,8 +5841,8 @@ static void detach_task(struct task_struct *p, struct lb_env *env)
{
lockdep_assert_held(&env->src_rq->lock);
- deactivate_task(env->src_rq, p, 0);
p->on_rq = TASK_ON_RQ_MIGRATING;
+ deactivate_task(env->src_rq, p, 0);
set_task_cpu(p, env->dst_cpu);
}
@@ -5855,8 +5975,8 @@ static void attach_task(struct rq *rq, struct task_struct *p)
lockdep_assert_held(&rq->lock);
BUG_ON(task_rq(p) != rq);
- p->on_rq = TASK_ON_RQ_QUEUED;
activate_task(rq, p, 0);
+ p->on_rq = TASK_ON_RQ_QUEUED;
check_preempt_curr(rq, p, 0);
}
@@ -6302,7 +6422,7 @@ static inline void update_sg_lb_stats(struct lb_env *env,
bool *overload)
{
unsigned long load;
- int i;
+ int i, nr_running;
memset(sgs, 0, sizeof(*sgs));
@@ -6319,7 +6439,8 @@ static inline void update_sg_lb_stats(struct lb_env *env,
sgs->group_util += cpu_util(i);
sgs->sum_nr_running += rq->cfs.h_nr_running;
- if (rq->nr_running > 1)
+ nr_running = rq->nr_running;
+ if (nr_running > 1)
*overload = true;
#ifdef CONFIG_NUMA_BALANCING
@@ -6327,7 +6448,10 @@ static inline void update_sg_lb_stats(struct lb_env *env,
sgs->nr_preferred_running += rq->nr_preferred_running;
#endif
sgs->sum_weighted_load += weighted_cpuload(i);
- if (idle_cpu(i))
+ /*
+ * No need to call idle_cpu() if nr_running is not 0
+ */
+ if (!nr_running && idle_cpu(i))
sgs->idle_cpus++;
}
@@ -7248,8 +7372,6 @@ static int idle_balance(struct rq *this_rq)
int pulled_task = 0;
u64 curr_cost = 0;
- idle_enter_fair(this_rq);
-
/*
* We must set idle_stamp _before_ calling idle_balance(), such that we
* measure the duration of idle_balance() as idle time.
@@ -7330,10 +7452,8 @@ out:
if (this_rq->nr_running != this_rq->cfs.h_nr_running)
pulled_task = -1;
- if (pulled_task) {
- idle_exit_fair(this_rq);
+ if (pulled_task)
this_rq->idle_stamp = 0;
- }
return pulled_task;
}
diff --git a/kernel/sched/idle_task.c b/kernel/sched/idle_task.c
index c4ae0f1..47ce949 100644
--- a/kernel/sched/idle_task.c
+++ b/kernel/sched/idle_task.c
@@ -47,7 +47,6 @@ dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
{
- idle_exit_fair(rq);
rq_last_tick_reset(rq);
}
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index e3cc163..8ec86ab 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -64,7 +64,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
raw_spin_unlock(&rt_b->rt_runtime_lock);
}
-#ifdef CONFIG_SMP
+#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI)
static void push_irq_work_func(struct irq_work *work);
#endif
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index efd3bfc..10f1637 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -248,7 +248,12 @@ struct task_group {
unsigned long shares;
#ifdef CONFIG_SMP
- atomic_long_t load_avg;
+ /*
+ * load_avg can be heavily contended at clock tick time, so put
+ * it in its own cacheline separated from the fields above which
+ * will also be accessed at each tick.
+ */
+ atomic_long_t load_avg ____cacheline_aligned;
#endif
#endif
@@ -335,7 +340,15 @@ extern void sched_move_task(struct task_struct *tsk);
#ifdef CONFIG_FAIR_GROUP_SCHED
extern int sched_group_set_shares(struct task_group *tg, unsigned long shares);
-#endif
+
+#ifdef CONFIG_SMP
+extern void set_task_rq_fair(struct sched_entity *se,
+ struct cfs_rq *prev, struct cfs_rq *next);
+#else /* !CONFIG_SMP */
+static inline void set_task_rq_fair(struct sched_entity *se,
+ struct cfs_rq *prev, struct cfs_rq *next) { }
+#endif /* CONFIG_SMP */
+#endif /* CONFIG_FAIR_GROUP_SCHED */
#else /* CONFIG_CGROUP_SCHED */
@@ -933,6 +946,7 @@ static inline void set_task_rq(struct task_struct *p, unsigned int cpu)
#endif
#ifdef CONFIG_FAIR_GROUP_SCHED
+ set_task_rq_fair(&p->se, p->se.cfs_rq, tg->cfs_rq[cpu]);
p->se.cfs_rq = tg->cfs_rq[cpu];
p->se.parent = tg->se[cpu];
#endif
@@ -1073,7 +1087,10 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
* We must ensure this doesn't happen until the switch is completely
* finished.
*
- * Pairs with the control dependency and rmb in try_to_wake_up().
+ * In particular, the load of prev->state in finish_task_switch() must
+ * happen before this.
+ *
+ * Pairs with the smp_cond_acquire() in try_to_wake_up().
*/
smp_store_release(&prev->on_cpu, 0);
#endif
@@ -1110,46 +1127,8 @@ static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev)
#define WEIGHT_IDLEPRIO 3
#define WMULT_IDLEPRIO 1431655765
-/*
- * Nice levels are multiplicative, with a gentle 10% change for every
- * nice level changed. I.e. when a CPU-bound task goes from nice 0 to
- * nice 1, it will get ~10% less CPU time than another CPU-bound task
- * that remained on nice 0.
- *
- * The "10% effect" is relative and cumulative: from _any_ nice level,
- * if you go up 1 level, it's -10% CPU usage, if you go down 1 level
- * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25.
- * If a task goes up by ~10% and another task goes down by ~10% then
- * the relative distance between them is ~25%.)
- */
-static const int prio_to_weight[40] = {
- /* -20 */ 88761, 71755, 56483, 46273, 36291,
- /* -15 */ 29154, 23254, 18705, 14949, 11916,
- /* -10 */ 9548, 7620, 6100, 4904, 3906,
- /* -5 */ 3121, 2501, 1991, 1586, 1277,
- /* 0 */ 1024, 820, 655, 526, 423,
- /* 5 */ 335, 272, 215, 172, 137,
- /* 10 */ 110, 87, 70, 56, 45,
- /* 15 */ 36, 29, 23, 18, 15,
-};
-
-/*
- * Inverse (2^32/x) values of the prio_to_weight[] array, precalculated.
- *
- * In cases where the weight does not change often, we can use the
- * precalculated inverse to speed up arithmetics by turning divisions
- * into multiplications:
- */
-static const u32 prio_to_wmult[40] = {
- /* -20 */ 48388, 59856, 76040, 92818, 118348,
- /* -15 */ 147320, 184698, 229616, 287308, 360437,
- /* -10 */ 449829, 563644, 704093, 875809, 1099582,
- /* -5 */ 1376151, 1717300, 2157191, 2708050, 3363326,
- /* 0 */ 4194304, 5237765, 6557202, 8165337, 10153587,
- /* 5 */ 12820798, 15790321, 19976592, 24970740, 31350126,
- /* 10 */ 39045157, 49367440, 61356676, 76695844, 95443717,
- /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153,
-};
+extern const int sched_prio_to_weight[40];
+extern const u32 sched_prio_to_wmult[40];
#define ENQUEUE_WAKEUP 0x01
#define ENQUEUE_HEAD 0x02
@@ -1249,16 +1228,8 @@ extern void update_group_capacity(struct sched_domain *sd, int cpu);
extern void trigger_load_balance(struct rq *rq);
-extern void idle_enter_fair(struct rq *this_rq);
-extern void idle_exit_fair(struct rq *this_rq);
-
extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask);
-#else
-
-static inline void idle_enter_fair(struct rq *rq) { }
-static inline void idle_exit_fair(struct rq *rq) { }
-
#endif
#ifdef CONFIG_CPU_IDLE
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 052e026..f15d6b6 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -392,7 +392,7 @@ __wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q,
do {
prepare_to_wait(wq, &q->wait, mode);
if (test_bit(q->key.bit_nr, q->key.flags))
- ret = (*action)(&q->key);
+ ret = (*action)(&q->key, mode);
} while (test_bit(q->key.bit_nr, q->key.flags) && !ret);
finish_wait(wq, &q->wait);
return ret;
@@ -431,7 +431,7 @@ __wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q,
prepare_to_wait_exclusive(wq, &q->wait, mode);
if (!test_bit(q->key.bit_nr, q->key.flags))
continue;
- ret = action(&q->key);
+ ret = action(&q->key, mode);
if (!ret)
continue;
abort_exclusive_wait(wq, &q->wait, mode, &q->key);
@@ -581,44 +581,44 @@ void wake_up_atomic_t(atomic_t *p)
}
EXPORT_SYMBOL(wake_up_atomic_t);
-__sched int bit_wait(struct wait_bit_key *word)
+__sched int bit_wait(struct wait_bit_key *word, int mode)
{
- if (signal_pending_state(current->state, current))
- return 1;
schedule();
+ if (signal_pending_state(mode, current))
+ return -EINTR;
return 0;
}
EXPORT_SYMBOL(bit_wait);
-__sched int bit_wait_io(struct wait_bit_key *word)
+__sched int bit_wait_io(struct wait_bit_key *word, int mode)
{
- if (signal_pending_state(current->state, current))
- return 1;
io_schedule();
+ if (signal_pending_state(mode, current))
+ return -EINTR;
return 0;
}
EXPORT_SYMBOL(bit_wait_io);
-__sched int bit_wait_timeout(struct wait_bit_key *word)
+__sched int bit_wait_timeout(struct wait_bit_key *word, int mode)
{
unsigned long now = READ_ONCE(jiffies);
- if (signal_pending_state(current->state, current))
- return 1;
if (time_after_eq(now, word->timeout))
return -EAGAIN;
schedule_timeout(word->timeout - now);
+ if (signal_pending_state(mode, current))
+ return -EINTR;
return 0;
}
EXPORT_SYMBOL_GPL(bit_wait_timeout);
-__sched int bit_wait_io_timeout(struct wait_bit_key *word)
+__sched int bit_wait_io_timeout(struct wait_bit_key *word, int mode)
{
unsigned long now = READ_ONCE(jiffies);
- if (signal_pending_state(current->state, current))
- return 1;
if (time_after_eq(now, word->timeout))
return -EAGAIN;
io_schedule_timeout(word->timeout - now);
+ if (signal_pending_state(mode, current))
+ return -EINTR;
return 0;
}
EXPORT_SYMBOL_GPL(bit_wait_io_timeout);
diff --git a/kernel/signal.c b/kernel/signal.c
index c0b01fe..f3f1f7a 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3503,7 +3503,7 @@ SYSCALL_DEFINE0(pause)
#endif
-int sigsuspend(sigset_t *set)
+static int sigsuspend(sigset_t *set)
{
current->saved_sigmask = current->blocked;
set_current_blocked(set);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 867bc20..edb6de4 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -28,7 +28,6 @@
*/
struct cpu_stop_done {
atomic_t nr_todo; /* nr left to execute */
- bool executed; /* actually executed? */
int ret; /* collected return value */
struct completion completion; /* fired if nr_todo reaches 0 */
};
@@ -63,14 +62,10 @@ static void cpu_stop_init_done(struct cpu_stop_done *done, unsigned int nr_todo)
}
/* signal completion unless @done is NULL */
-static void cpu_stop_signal_done(struct cpu_stop_done *done, bool executed)
+static void cpu_stop_signal_done(struct cpu_stop_done *done)
{
- if (done) {
- if (executed)
- done->executed = true;
- if (atomic_dec_and_test(&done->nr_todo))
- complete(&done->completion);
- }
+ if (atomic_dec_and_test(&done->nr_todo))
+ complete(&done->completion);
}
static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
@@ -81,17 +76,21 @@ static void __cpu_stop_queue_work(struct cpu_stopper *stopper,
}
/* queue @work to @stopper. if offline, @work is completed immediately */
-static void cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
+static bool cpu_stop_queue_work(unsigned int cpu, struct cpu_stop_work *work)
{
struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
unsigned long flags;
+ bool enabled;
spin_lock_irqsave(&stopper->lock, flags);
- if (stopper->enabled)
+ enabled = stopper->enabled;
+ if (enabled)
__cpu_stop_queue_work(stopper, work);
- else
- cpu_stop_signal_done(work->done, false);
+ else if (work->done)
+ cpu_stop_signal_done(work->done);
spin_unlock_irqrestore(&stopper->lock, flags);
+
+ return enabled;
}
/**
@@ -124,9 +123,10 @@ int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg)
struct cpu_stop_work work = { .fn = fn, .arg = arg, .done = &done };
cpu_stop_init_done(&done, 1);
- cpu_stop_queue_work(cpu, &work);
+ if (!cpu_stop_queue_work(cpu, &work))
+ return -ENOENT;
wait_for_completion(&done.completion);
- return done.executed ? done.ret : -ENOENT;
+ return done.ret;
}
/* This controls the threads on each CPU. */
@@ -258,7 +258,6 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
struct cpu_stop_work work1, work2;
struct multi_stop_data msdata;
- preempt_disable();
msdata = (struct multi_stop_data){
.fn = fn,
.data = arg,
@@ -277,16 +276,11 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
if (cpu1 > cpu2)
swap(cpu1, cpu2);
- if (cpu_stop_queue_two_works(cpu1, &work1, cpu2, &work2)) {
- preempt_enable();
+ if (cpu_stop_queue_two_works(cpu1, &work1, cpu2, &work2))
return -ENOENT;
- }
-
- preempt_enable();
wait_for_completion(&done.completion);
-
- return done.executed ? done.ret : -ENOENT;
+ return done.ret;
}
/**
@@ -302,23 +296,28 @@ int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *
*
* CONTEXT:
* Don't care.
+ *
+ * RETURNS:
+ * true if cpu_stop_work was queued successfully and @fn will be called,
+ * false otherwise.
*/
-void stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
+bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg,
struct cpu_stop_work *work_buf)
{
*work_buf = (struct cpu_stop_work){ .fn = fn, .arg = arg, };
- cpu_stop_queue_work(cpu, work_buf);
+ return cpu_stop_queue_work(cpu, work_buf);
}
/* static data for stop_cpus */
static DEFINE_MUTEX(stop_cpus_mutex);
-static void queue_stop_cpus_work(const struct cpumask *cpumask,
+static bool queue_stop_cpus_work(const struct cpumask *cpumask,
cpu_stop_fn_t fn, void *arg,
struct cpu_stop_done *done)
{
struct cpu_stop_work *work;
unsigned int cpu;
+ bool queued = false;
/*
* Disable preemption while queueing to avoid getting
@@ -331,9 +330,12 @@ static void queue_stop_cpus_work(const struct cpumask *cpumask,
work->fn = fn;
work->arg = arg;
work->done = done;
- cpu_stop_queue_work(cpu, work);
+ if (cpu_stop_queue_work(cpu, work))
+ queued = true;
}
lg_global_unlock(&stop_cpus_lock);
+
+ return queued;
}
static int __stop_cpus(const struct cpumask *cpumask,
@@ -342,9 +344,10 @@ static int __stop_cpus(const struct cpumask *cpumask,
struct cpu_stop_done done;
cpu_stop_init_done(&done, cpumask_weight(cpumask));
- queue_stop_cpus_work(cpumask, fn, arg, &done);
+ if (!queue_stop_cpus_work(cpumask, fn, arg, &done))
+ return -ENOENT;
wait_for_completion(&done.completion);
- return done.executed ? done.ret : -ENOENT;
+ return done.ret;
}
/**
@@ -432,7 +435,6 @@ static void cpu_stopper_thread(unsigned int cpu)
{
struct cpu_stopper *stopper = &per_cpu(cpu_stopper, cpu);
struct cpu_stop_work *work;
- int ret;
repeat:
work = NULL;
@@ -448,23 +450,19 @@ repeat:
cpu_stop_fn_t fn = work->fn;
void *arg = work->arg;
struct cpu_stop_done *done = work->done;
- char ksym_buf[KSYM_NAME_LEN] __maybe_unused;
-
- /* cpu stop callbacks are not allowed to sleep */
- preempt_disable();
+ int ret;
+ /* cpu stop callbacks must not sleep, make in_atomic() == T */
+ preempt_count_inc();
ret = fn(arg);
- if (ret)
- done->ret = ret;
-
- /* restore preemption and check it's still balanced */
- preempt_enable();
+ if (done) {
+ if (ret)
+ done->ret = ret;
+ cpu_stop_signal_done(done);
+ }
+ preempt_count_dec();
WARN_ONCE(preempt_count(),
- "cpu_stop: %s(%p) leaked preempt count\n",
- kallsyms_lookup((unsigned long)fn, NULL, NULL, NULL,
- ksym_buf), arg);
-
- cpu_stop_signal_done(done, true);
+ "cpu_stop: %pf(%p) leaked preempt count\n", fn, arg);
goto repeat;
}
}
@@ -531,7 +529,7 @@ static int __init cpu_stop_init(void)
}
early_initcall(cpu_stop_init);
-#ifdef CONFIG_STOP_MACHINE
+#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU)
static int __stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus)
{
@@ -631,4 +629,4 @@ int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data,
return ret ?: done.ret;
}
-#endif /* CONFIG_STOP_MACHINE */
+#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 0623787..2c5e3a8 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -174,6 +174,7 @@ cond_syscall(sys_setfsuid);
cond_syscall(sys_setfsgid);
cond_syscall(sys_capget);
cond_syscall(sys_capset);
+cond_syscall(sys_copy_file_range);
/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index dc6858d..5faf89a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -2047,9 +2047,8 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
void *data)
{
int *i, vleft, first = 1, err = 0;
- unsigned long page = 0;
size_t left;
- char *kbuf;
+ char *kbuf = NULL, *p;
if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) {
*lenp = 0;
@@ -2078,15 +2077,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
if (left > PAGE_SIZE - 1)
left = PAGE_SIZE - 1;
- page = __get_free_page(GFP_TEMPORARY);
- kbuf = (char *) page;
- if (!kbuf)
- return -ENOMEM;
- if (copy_from_user(kbuf, buffer, left)) {
- err = -EFAULT;
- goto free;
- }
- kbuf[left] = 0;
+ p = kbuf = memdup_user_nul(buffer, left);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
}
for (; left && vleft--; i++, first=0) {
@@ -2094,11 +2087,11 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
bool neg;
if (write) {
- left -= proc_skip_spaces(&kbuf);
+ left -= proc_skip_spaces(&p);
if (!left)
break;
- err = proc_get_long(&kbuf, &left, &lval, &neg,
+ err = proc_get_long(&p, &left, &lval, &neg,
proc_wspace_sep,
sizeof(proc_wspace_sep), NULL);
if (err)
@@ -2125,10 +2118,9 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
if (!write && !first && left && !err)
err = proc_put_char(&buffer, &left, '\n');
if (write && !err && left)
- left -= proc_skip_spaces(&kbuf);
-free:
+ left -= proc_skip_spaces(&p);
if (write) {
- free_page(page);
+ kfree(kbuf);
if (first)
return err ? : -EINVAL;
}
@@ -2310,9 +2302,8 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
{
unsigned long *i, *min, *max;
int vleft, first = 1, err = 0;
- unsigned long page = 0;
size_t left;
- char *kbuf;
+ char *kbuf = NULL, *p;
if (!data || !table->maxlen || !*lenp || (*ppos && !write)) {
*lenp = 0;
@@ -2340,15 +2331,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
if (left > PAGE_SIZE - 1)
left = PAGE_SIZE - 1;
- page = __get_free_page(GFP_TEMPORARY);
- kbuf = (char *) page;
- if (!kbuf)
- return -ENOMEM;
- if (copy_from_user(kbuf, buffer, left)) {
- err = -EFAULT;
- goto free;
- }
- kbuf[left] = 0;
+ p = kbuf = memdup_user_nul(buffer, left);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
}
for (; left && vleft--; i++, first = 0) {
@@ -2357,9 +2342,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
if (write) {
bool neg;
- left -= proc_skip_spaces(&kbuf);
+ left -= proc_skip_spaces(&p);
- err = proc_get_long(&kbuf, &left, &val, &neg,
+ err = proc_get_long(&p, &left, &val, &neg,
proc_wspace_sep,
sizeof(proc_wspace_sep), NULL);
if (err)
@@ -2385,10 +2370,9 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
if (!write && !first && left && !err)
err = proc_put_char(&buffer, &left, '\n');
if (write && !err)
- left -= proc_skip_spaces(&kbuf);
-free:
+ left -= proc_skip_spaces(&p);
if (write) {
- free_page(page);
+ kfree(kbuf);
if (first)
return err ? : -EINVAL;
}
@@ -2650,34 +2634,27 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
}
if (write) {
- unsigned long page = 0;
- char *kbuf;
+ char *kbuf, *p;
if (left > PAGE_SIZE - 1)
left = PAGE_SIZE - 1;
- page = __get_free_page(GFP_TEMPORARY);
- kbuf = (char *) page;
- if (!kbuf)
- return -ENOMEM;
- if (copy_from_user(kbuf, buffer, left)) {
- free_page(page);
- return -EFAULT;
- }
- kbuf[left] = 0;
+ p = kbuf = memdup_user_nul(buffer, left);
+ if (IS_ERR(kbuf))
+ return PTR_ERR(kbuf);
tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long),
GFP_KERNEL);
if (!tmp_bitmap) {
- free_page(page);
+ kfree(kbuf);
return -ENOMEM;
}
- proc_skip_char(&kbuf, &left, '\n');
+ proc_skip_char(&p, &left, '\n');
while (!err && left) {
unsigned long val_a, val_b;
bool neg;
- err = proc_get_long(&kbuf, &left, &val_a, &neg, tr_a,
+ err = proc_get_long(&p, &left, &val_a, &neg, tr_a,
sizeof(tr_a), &c);
if (err)
break;
@@ -2688,12 +2665,12 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
val_b = val_a;
if (left) {
- kbuf++;
+ p++;
left--;
}
if (c == '-') {
- err = proc_get_long(&kbuf, &left, &val_b,
+ err = proc_get_long(&p, &left, &val_b,
&neg, tr_b, sizeof(tr_b),
&c);
if (err)
@@ -2704,16 +2681,16 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
break;
}
if (left) {
- kbuf++;
+ p++;
left--;
}
}
bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1);
first = 0;
- proc_skip_char(&kbuf, &left, '\n');
+ proc_skip_char(&p, &left, '\n');
}
- free_page(page);
+ kfree(kbuf);
} else {
unsigned long bit_a, bit_b = 0;
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 7fbba63..e840ed8 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -271,11 +271,27 @@ static int alarmtimer_suspend(struct device *dev)
__pm_wakeup_event(ws, MSEC_PER_SEC);
return ret;
}
+
+static int alarmtimer_resume(struct device *dev)
+{
+ struct rtc_device *rtc;
+
+ rtc = alarmtimer_get_rtcdev();
+ if (rtc)
+ rtc_timer_cancel(rtc, &rtctimer);
+ return 0;
+}
+
#else
static int alarmtimer_suspend(struct device *dev)
{
return 0;
}
+
+static int alarmtimer_resume(struct device *dev)
+{
+ return 0;
+}
#endif
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
@@ -800,6 +816,7 @@ out:
/* Suspend hook structures */
static const struct dev_pm_ops alarmtimer_pm_ops = {
.suspend = alarmtimer_suspend,
+ .resume = alarmtimer_resume,
};
static struct platform_driver alarmtimer_driver = {
diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c
index 1347882..664de53 100644
--- a/kernel/time/clocksource.c
+++ b/kernel/time/clocksource.c
@@ -218,8 +218,8 @@ static void clocksource_watchdog(unsigned long data)
/* Check the deviation from the watchdog clocksource. */
if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
- pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable because the skew is too large:\n",
- cs->name);
+ pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",
+ smp_processor_id(), cs->name);
pr_warn(" '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
watchdog->name, wdnow, wdlast, watchdog->mask);
pr_warn(" '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 149cc80..36f2ca0 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -16,8 +16,11 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/rtc.h>
+#include <linux/math64.h>
#include "ntp_internal.h"
+#include "timekeeping_internal.h"
+
/*
* NTP timekeeping variables:
@@ -70,7 +73,7 @@ static long time_esterror = NTP_PHASE_LIMIT;
static s64 time_freq;
/* time at last adjustment (secs): */
-static long time_reftime;
+static time64_t time_reftime;
static long time_adjust;
@@ -297,25 +300,27 @@ static void ntp_update_offset(long offset)
if (!(time_status & STA_PLL))
return;
- if (!(time_status & STA_NANO))
+ if (!(time_status & STA_NANO)) {
+ /* Make sure the multiplication below won't overflow */
+ offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
offset *= NSEC_PER_USEC;
+ }
/*
* Scale the phase adjustment and
* clamp to the operating range.
*/
- offset = min(offset, MAXPHASE);
- offset = max(offset, -MAXPHASE);
+ offset = clamp(offset, -MAXPHASE, MAXPHASE);
/*
* Select how the frequency is to be controlled
* and in which mode (PLL or FLL).
*/
- secs = get_seconds() - time_reftime;
+ secs = (long)(__ktime_get_real_seconds() - time_reftime);
if (unlikely(time_status & STA_FREQHOLD))
secs = 0;
- time_reftime = get_seconds();
+ time_reftime = __ktime_get_real_seconds();
offset64 = offset;
freq_adj = ntp_update_offset_fll(offset64, secs);
@@ -390,10 +395,11 @@ ktime_t ntp_get_next_leap(void)
*
* Also handles leap second processing, and returns leap offset
*/
-int second_overflow(unsigned long secs)
+int second_overflow(time64_t secs)
{
s64 delta;
int leap = 0;
+ s32 rem;
/*
* Leap second processing. If in leap-insert state at the end of the
@@ -404,19 +410,19 @@ int second_overflow(unsigned long secs)
case TIME_OK:
if (time_status & STA_INS) {
time_state = TIME_INS;
- ntp_next_leap_sec = secs + SECS_PER_DAY -
- (secs % SECS_PER_DAY);
+ div_s64_rem(secs, SECS_PER_DAY, &rem);
+ ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
} else if (time_status & STA_DEL) {
time_state = TIME_DEL;
- ntp_next_leap_sec = secs + SECS_PER_DAY -
- ((secs+1) % SECS_PER_DAY);
+ div_s64_rem(secs + 1, SECS_PER_DAY, &rem);
+ ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
}
break;
case TIME_INS:
if (!(time_status & STA_INS)) {
ntp_next_leap_sec = TIME64_MAX;
time_state = TIME_OK;
- } else if (secs % SECS_PER_DAY == 0) {
+ } else if (secs == ntp_next_leap_sec) {
leap = -1;
time_state = TIME_OOP;
printk(KERN_NOTICE
@@ -427,7 +433,7 @@ int second_overflow(unsigned long secs)
if (!(time_status & STA_DEL)) {
ntp_next_leap_sec = TIME64_MAX;
time_state = TIME_OK;
- } else if ((secs + 1) % SECS_PER_DAY == 0) {
+ } else if (secs == ntp_next_leap_sec) {
leap = 1;
ntp_next_leap_sec = TIME64_MAX;
time_state = TIME_WAIT;
@@ -590,7 +596,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
* reference time to current time.
*/
if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
- time_reftime = get_seconds();
+ time_reftime = __ktime_get_real_seconds();
/* only set allowed bits */
time_status &= STA_RONLY;
@@ -674,8 +680,14 @@ int ntp_validate_timex(struct timex *txc)
return -EINVAL;
}
- if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
- return -EPERM;
+ if (txc->modes & ADJ_SETOFFSET) {
+ /* In order to inject time, you gotta be super-user! */
+ if (!capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ if (!timeval_inject_offset_valid(&txc->time))
+ return -EINVAL;
+ }
/*
* Check for potential multiplication overflows that can
diff --git a/kernel/time/ntp_internal.h b/kernel/time/ntp_internal.h
index af92447..d8a7c11 100644
--- a/kernel/time/ntp_internal.h
+++ b/kernel/time/ntp_internal.h
@@ -6,7 +6,7 @@ extern void ntp_clear(void);
/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
extern u64 ntp_tick_length(void);
extern ktime_t ntp_get_next_leap(void);
-extern int second_overflow(unsigned long secs);
+extern int second_overflow(time64_t secs);
extern int ntp_validate_timex(struct timex *);
extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c
index ce033c7..9cff0ab 100644
--- a/kernel/time/posix-clock.c
+++ b/kernel/time/posix-clock.c
@@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
{
struct posix_clock *clk = get_posix_clock(fp);
- int result = 0;
+ unsigned int result = 0;
if (!clk)
- return -ENODEV;
+ return POLLERR;
if (clk->ops.poll)
result = clk->ops.poll(clk, fp, wait);
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7c7ec45..9cc20af 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -143,7 +143,7 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
* when we go busy again does not account too much ticks.
*/
if (ts->tick_stopped) {
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sched();
if (is_idle_task(current))
ts->idle_jiffies++;
}
@@ -430,7 +430,7 @@ static void tick_nohz_update_jiffies(ktime_t now)
tick_do_update_jiffies64(now);
local_irq_restore(flags);
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sched();
}
/*
@@ -603,15 +603,31 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
/*
* If the tick is due in the next period, keep it ticking or
- * restart it proper.
+ * force prod the timer.
*/
delta = next_tick - basemono;
if (delta <= (u64)TICK_NSEC) {
tick.tv64 = 0;
+ /*
+ * We've not stopped the tick yet, and there's a timer in the
+ * next period, so no point in stopping it either, bail.
+ */
if (!ts->tick_stopped)
goto out;
+
+ /*
+ * If, OTOH, we did stop it, but there's a pending (expired)
+ * timer reprogram the timer hardware to fire now.
+ *
+ * We will not restart the tick proper, just prod the timer
+ * hardware into firing an interrupt to process the pending
+ * timers. Just like tick_irq_exit() will not restart the tick
+ * for 'normal' interrupts.
+ *
+ * Only once we exit the idle loop will we re-enable the tick,
+ * see tick_nohz_idle_exit().
+ */
if (delta == 0) {
- /* Tick is stopped, but required now. Enforce it */
tick_nohz_restart(ts, now);
goto out;
}
@@ -694,14 +710,14 @@ out:
return tick;
}
-static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now)
+static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now, int active)
{
/* Update jiffies first */
tick_do_update_jiffies64(now);
- update_cpu_load_nohz();
+ update_cpu_load_nohz(active);
calc_load_exit_idle();
- touch_softlockup_watchdog();
+ touch_softlockup_watchdog_sched();
/*
* Cancel the scheduled timer and restore the tick
*/
@@ -725,7 +741,7 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
if (can_stop_full_tick())
tick_nohz_stop_sched_tick(ts, ktime_get(), cpu);
else if (ts->tick_stopped)
- tick_nohz_restart_sched_tick(ts, ktime_get());
+ tick_nohz_restart_sched_tick(ts, ktime_get(), 1);
#endif
}
@@ -875,7 +891,7 @@ static void tick_nohz_account_idle_ticks(struct tick_sched *ts)
#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE
unsigned long ticks;
- if (vtime_accounting_enabled())
+ if (vtime_accounting_cpu_enabled())
return;
/*
* We stopped the tick in idle. Update process times would miss the
@@ -916,7 +932,7 @@ void tick_nohz_idle_exit(void)
tick_nohz_stop_idle(ts, now);
if (ts->tick_stopped) {
- tick_nohz_restart_sched_tick(ts, now);
+ tick_nohz_restart_sched_tick(ts, now, 0);
tick_nohz_account_idle_ticks(ts);
}
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d563c19..34b4ced 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -305,8 +305,7 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
delta = timekeeping_get_delta(tkr);
- nsec = delta * tkr->mult + tkr->xtime_nsec;
- nsec >>= tkr->shift;
+ nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
/* If arch requires, add in get_arch_timeoffset() */
return nsec + arch_gettimeoffset();
@@ -846,6 +845,19 @@ time64_t ktime_get_real_seconds(void)
}
EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
+/**
+ * __ktime_get_real_seconds - The same as ktime_get_real_seconds
+ * but without the sequence counter protect. This internal function
+ * is called just when timekeeping lock is already held.
+ */
+time64_t __ktime_get_real_seconds(void)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+
+ return tk->xtime_sec;
+}
+
+
#ifdef CONFIG_NTP_PPS
/**
@@ -959,7 +971,7 @@ int timekeeping_inject_offset(struct timespec *ts)
struct timespec64 ts64, tmp;
int ret = 0;
- if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
+ if (!timespec_inject_offset_valid(ts))
return -EINVAL;
ts64 = timespec_to_timespec64(*ts);
@@ -1592,9 +1604,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
{
s64 interval = tk->cycle_interval;
s64 xinterval = tk->xtime_interval;
+ u32 base = tk->tkr_mono.clock->mult;
+ u32 max = tk->tkr_mono.clock->maxadj;
+ u32 cur_adj = tk->tkr_mono.mult;
s64 tick_error;
bool negative;
- u32 adj;
+ u32 adj_scale;
/* Remove any current error adj from freq calculation */
if (tk->ntp_err_mult)
@@ -1613,13 +1628,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
/* preserve the direction of correction */
negative = (tick_error < 0);
- /* Sort out the magnitude of the correction */
+ /* If any adjustment would pass the max, just return */
+ if (negative && (cur_adj - 1) <= (base - max))
+ return;
+ if (!negative && (cur_adj + 1) >= (base + max))
+ return;
+ /*
+ * Sort out the magnitude of the correction, but
+ * avoid making so large a correction that we go
+ * over the max adjustment.
+ */
+ adj_scale = 0;
tick_error = abs(tick_error);
- for (adj = 0; tick_error > interval; adj++)
+ while (tick_error > interval) {
+ u32 adj = 1 << (adj_scale + 1);
+
+ /* Check if adjustment gets us within 1 unit from the max */
+ if (negative && (cur_adj - adj) <= (base - max))
+ break;
+ if (!negative && (cur_adj + adj) >= (base + max))
+ break;
+
+ adj_scale++;
tick_error >>= 1;
+ }
/* scale the corrections */
- timekeeping_apply_adjustment(tk, offset, negative, adj);
+ timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
}
/*
diff --git a/kernel/time/timekeeping_internal.h b/kernel/time/timekeeping_internal.h
index 4ea005a..5be7627 100644
--- a/kernel/time/timekeeping_internal.h
+++ b/kernel/time/timekeeping_internal.h
@@ -17,7 +17,11 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
{
cycle_t ret = (now - last) & mask;
- return (s64) ret > 0 ? ret : 0;
+ /*
+ * Prevent time going backwards by checking the MSB of mask in
+ * the result. If set, return 0.
+ */
+ return ret & ~(mask >> 1) ? 0 : ret;
}
#else
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
@@ -26,4 +30,6 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
}
#endif
+extern time64_t __ktime_get_real_seconds(void);
+
#endif /* _TIMEKEEPING_INTERNAL_H */
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 74591ba..bbc5d11 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -977,13 +977,29 @@ EXPORT_SYMBOL(add_timer);
*/
void add_timer_on(struct timer_list *timer, int cpu)
{
- struct tvec_base *base = per_cpu_ptr(&tvec_bases, cpu);
+ struct tvec_base *new_base = per_cpu_ptr(&tvec_bases, cpu);
+ struct tvec_base *base;
unsigned long flags;
timer_stats_timer_set_start_info(timer);
BUG_ON(timer_pending(timer) || !timer->function);
- spin_lock_irqsave(&base->lock, flags);
- timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu;
+
+ /*
+ * If @timer was on a different CPU, it should be migrated with the
+ * old base locked to prevent other operations proceeding with the
+ * wrong base locked. See lock_timer_base().
+ */
+ base = lock_timer_base(timer, &flags);
+ if (base != new_base) {
+ timer->flags |= TIMER_MIGRATING;
+
+ spin_unlock(&base->lock);
+ base = new_base;
+ spin_lock(&base->lock);
+ WRITE_ONCE(timer->flags,
+ (timer->flags & ~TIMER_BASEMASK) | cpu);
+ }
+
debug_activate(timer, timer->expires);
internal_add_timer(base, timer);
spin_unlock_irqrestore(&base->lock, flags);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 8d6363f..e45db6b 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -434,7 +434,7 @@ config UPROBE_EVENT
config BPF_EVENTS
depends on BPF_SYSCALL
- depends on KPROBE_EVENT || UPROBE_EVENT
+ depends on (KPROBE_EVENT || UPROBE_EVENT) && PERF_EVENTS
bool
default y
help
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index a990824..2aeb6ff 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -349,16 +349,10 @@ static ssize_t blk_msg_write(struct file *filp, const char __user *buffer,
if (count >= BLK_TN_MAX_MSG)
return -EINVAL;
- msg = kmalloc(count + 1, GFP_KERNEL);
- if (msg == NULL)
- return -ENOMEM;
-
- if (copy_from_user(msg, buffer, count)) {
- kfree(msg);
- return -EFAULT;
- }
+ msg = memdup_user_nul(buffer, count);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
- msg[count] = '\0';
bt = filp->private_data;
__trace_note_message(bt, "%s", msg);
kfree(msg);
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 75f1d05..9c6045a 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -1887,12 +1887,6 @@ rb_event_index(struct ring_buffer_event *event)
return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE;
}
-static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
-{
- cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp;
- cpu_buffer->reader_page->read = 0;
-}
-
static void rb_inc_iter(struct ring_buffer_iter *iter)
{
struct ring_buffer_per_cpu *cpu_buffer = iter->cpu_buffer;
@@ -2803,8 +2797,11 @@ rb_reserve_next_event(struct ring_buffer *buffer,
event = __rb_reserve_next(cpu_buffer, &info);
- if (unlikely(PTR_ERR(event) == -EAGAIN))
+ if (unlikely(PTR_ERR(event) == -EAGAIN)) {
+ if (info.add_timestamp)
+ info.length -= RB_LEN_TIME_EXTEND;
goto again;
+ }
if (!event)
goto out_fail;
@@ -3626,7 +3623,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
/* Finally update the reader page to the new head */
cpu_buffer->reader_page = reader;
- rb_reset_reader_page(cpu_buffer);
+ cpu_buffer->reader_page->read = 0;
if (overwrite != cpu_buffer->last_overrun) {
cpu_buffer->lost_events = overwrite - cpu_buffer->last_overrun;
@@ -3636,6 +3633,10 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer)
goto again;
out:
+ /* Update the read_stamp on the first event */
+ if (reader && reader->read == 0)
+ cpu_buffer->read_stamp = reader->page->time_stamp;
+
arch_spin_unlock(&cpu_buffer->lock);
local_irq_restore(flags);
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 2198a63..87fb980 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -100,8 +100,6 @@ static DEFINE_PER_CPU(bool, trace_cmdline_save);
*/
static int tracing_disabled = 1;
-DEFINE_PER_CPU(int, ftrace_cpu_disabled);
-
cpumask_var_t __read_mostly tracing_buffer_mask;
/*
@@ -1775,10 +1773,6 @@ trace_function(struct trace_array *tr,
struct ring_buffer_event *event;
struct ftrace_entry *entry;
- /* If we are reading the ring buffer, don't trace */
- if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
- return;
-
event = trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry),
flags, pc);
if (!event)
@@ -4554,6 +4548,8 @@ out:
return ret;
}
+#ifdef CONFIG_TRACER_MAX_TRACE
+
static ssize_t
tracing_max_lat_read(struct file *filp, char __user *ubuf,
size_t cnt, loff_t *ppos)
@@ -4568,6 +4564,8 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
return tracing_nsecs_write(filp->private_data, ubuf, cnt, ppos);
}
+#endif
+
static int tracing_open_pipe(struct inode *inode, struct file *filp)
{
struct trace_array *tr = inode->i_private;
@@ -5469,12 +5467,14 @@ static const struct file_operations tracing_thresh_fops = {
.llseek = generic_file_llseek,
};
+#ifdef CONFIG_TRACER_MAX_TRACE
static const struct file_operations tracing_max_lat_fops = {
.open = tracing_open_generic,
.read = tracing_max_lat_read,
.write = tracing_max_lat_write,
.llseek = generic_file_llseek,
};
+#endif
static const struct file_operations set_tracer_fops = {
.open = tracing_open_generic,
@@ -6847,7 +6847,9 @@ struct dentry *tracing_init_dentry(void)
if (tr->dir)
return NULL;
- if (WARN_ON(!debugfs_initialized()))
+ if (WARN_ON(!tracefs_initialized()) ||
+ (IS_ENABLED(CONFIG_DEBUG_FS) &&
+ WARN_ON(!debugfs_initialized())))
return ERR_PTR(-ENODEV);
/*
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index dd76208..919d9d0 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -667,7 +667,6 @@ extern int DYN_FTRACE_TEST_NAME2(void);
extern bool ring_buffer_expanded;
extern bool tracing_selftest_disabled;
-DECLARE_PER_CPU(int, ftrace_cpu_disabled);
#ifdef CONFIG_FTRACE_STARTUP_TEST
extern int trace_selftest_startup_function(struct tracer *trace,
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c
index abfc903..cc9f7a9 100644
--- a/kernel/trace/trace_event_perf.c
+++ b/kernel/trace/trace_event_perf.c
@@ -1,7 +1,7 @@
/*
* trace event based perf event profiling/tracing
*
- * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2009 Red Hat Inc, Peter Zijlstra
* Copyright (C) 2009-2010 Frederic Weisbecker <fweisbec@gmail.com>
*/
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 6bbc5f6..f333e57 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -582,6 +582,12 @@ static void __ftrace_clear_event_pids(struct trace_array *tr)
unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_pre, tr);
unregister_trace_sched_wakeup(event_filter_pid_sched_wakeup_probe_post, tr);
+ unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre, tr);
+ unregister_trace_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post, tr);
+
+ unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_pre, tr);
+ unregister_trace_sched_waking(event_filter_pid_sched_wakeup_probe_post, tr);
+
list_for_each_entry(file, &tr->events, list) {
clear_bit(EVENT_FILE_FL_PID_FILTER_BIT, &file->flags);
}
@@ -1334,15 +1340,9 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (cnt >= PAGE_SIZE)
return -EINVAL;
- buf = (char *)__get_free_page(GFP_TEMPORARY);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, ubuf, cnt)) {
- free_page((unsigned long) buf);
- return -EFAULT;
- }
- buf[cnt] = '\0';
+ buf = memdup_user_nul(ubuf, cnt);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
mutex_lock(&event_mutex);
file = event_file_data(filp);
@@ -1350,7 +1350,7 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
err = apply_event_filter(file, buf);
mutex_unlock(&event_mutex);
- free_page((unsigned long) buf);
+ kfree(buf);
if (err < 0)
return err;
@@ -1501,18 +1501,12 @@ subsystem_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
if (cnt >= PAGE_SIZE)
return -EINVAL;
- buf = (char *)__get_free_page(GFP_TEMPORARY);
- if (!buf)
- return -ENOMEM;
-
- if (copy_from_user(buf, ubuf, cnt)) {
- free_page((unsigned long) buf);
- return -EFAULT;
- }
- buf[cnt] = '\0';
+ buf = memdup_user_nul(ubuf, cnt);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
err = apply_subsystem_event_filter(dir, buf);
- free_page((unsigned long) buf);
+ kfree(buf);
if (err < 0)
return err;
@@ -1729,6 +1723,16 @@ ftrace_event_pid_write(struct file *filp, const char __user *ubuf,
tr, INT_MAX);
register_trace_prio_sched_wakeup(event_filter_pid_sched_wakeup_probe_post,
tr, 0);
+
+ register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_pre,
+ tr, INT_MAX);
+ register_trace_prio_sched_wakeup_new(event_filter_pid_sched_wakeup_probe_post,
+ tr, 0);
+
+ register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_pre,
+ tr, INT_MAX);
+ register_trace_prio_sched_waking(event_filter_pid_sched_wakeup_probe_post,
+ tr, 0);
}
/*
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 42a4009..4b5e8ed6 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -237,28 +237,23 @@ static ssize_t event_trigger_regex_write(struct file *file,
if (cnt >= PAGE_SIZE)
return -EINVAL;
- buf = (char *)__get_free_page(GFP_TEMPORARY);
- if (!buf)
- return -ENOMEM;
+ buf = memdup_user_nul(ubuf, cnt);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
- if (copy_from_user(buf, ubuf, cnt)) {
- free_page((unsigned long)buf);
- return -EFAULT;
- }
- buf[cnt] = '\0';
strim(buf);
mutex_lock(&event_mutex);
event_file = event_file_data(file);
if (unlikely(!event_file)) {
mutex_unlock(&event_mutex);
- free_page((unsigned long)buf);
+ kfree(buf);
return -ENODEV;
}
ret = trigger_process_regex(event_file, buf);
mutex_unlock(&event_mutex);
- free_page((unsigned long)buf);
+ kfree(buf);
if (ret < 0)
goto out;
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 92382af..a663cbb 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -288,9 +288,6 @@ int __trace_graph_entry(struct trace_array *tr,
struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ftrace_graph_ent_entry *entry;
- if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
- return 0;
-
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
sizeof(*entry), flags, pc);
if (!event)
@@ -403,9 +400,6 @@ void __trace_graph_return(struct trace_array *tr,
struct ring_buffer *buffer = tr->trace_buffer.buffer;
struct ftrace_graph_ret_entry *entry;
- if (unlikely(__this_cpu_read(ftrace_cpu_disabled)))
- return;
-
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET,
sizeof(*entry), flags, pc);
if (!event)
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 1c2b285..060df67 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -273,6 +273,7 @@ static const char **find_next(void *v, loff_t *pos)
if (*pos < last_index + start_index)
return __start___tracepoint_str + (*pos - last_index);
+ start_index += last_index;
return find_next_mod_format(start_index, v, fmt, pos);
}
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 88fefa6..9bafc21 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -602,8 +602,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
struct uid_gid_map new_map;
unsigned idx;
struct uid_gid_extent *extent = NULL;
- unsigned long page = 0;
- char *kbuf, *pos, *next_line;
+ char *kbuf = NULL, *pos, *next_line;
ssize_t ret = -EINVAL;
/*
@@ -638,23 +637,18 @@ static ssize_t map_write(struct file *file, const char __user *buf,
if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN))
goto out;
- /* Get a buffer */
- ret = -ENOMEM;
- page = __get_free_page(GFP_TEMPORARY);
- kbuf = (char *) page;
- if (!page)
- goto out;
-
/* Only allow < page size writes at the beginning of the file */
ret = -EINVAL;
if ((*ppos != 0) || (count >= PAGE_SIZE))
goto out;
/* Slurp in the user data */
- ret = -EFAULT;
- if (copy_from_user(kbuf, buf, count))
+ kbuf = memdup_user_nul(buf, count);
+ if (IS_ERR(kbuf)) {
+ ret = PTR_ERR(kbuf);
+ kbuf = NULL;
goto out;
- kbuf[count] = '\0';
+ }
/* Parse the user data */
ret = -EINVAL;
@@ -756,8 +750,7 @@ static ssize_t map_write(struct file *file, const char __user *buf,
ret = count;
out:
mutex_unlock(&userns_state_mutex);
- if (page)
- free_page(page);
+ kfree(kbuf);
return ret;
}
diff --git a/kernel/watchdog.c b/kernel/watchdog.c
index 18f34cf..b3ace6e 100644
--- a/kernel/watchdog.c
+++ b/kernel/watchdog.c
@@ -20,6 +20,7 @@
#include <linux/smpboot.h>
#include <linux/sched/rt.h>
#include <linux/tick.h>
+#include <linux/workqueue.h>
#include <asm/irq_regs.h>
#include <linux/kvm_para.h>
@@ -225,7 +226,15 @@ static void __touch_watchdog(void)
__this_cpu_write(watchdog_touch_ts, get_timestamp());
}
-void touch_softlockup_watchdog(void)
+/**
+ * touch_softlockup_watchdog_sched - touch watchdog on scheduler stalls
+ *
+ * Call when the scheduler may have stalled for legitimate reasons
+ * preventing the watchdog task from executing - e.g. the scheduler
+ * entering idle state. This should only be used for scheduler events.
+ * Use touch_softlockup_watchdog() for everything else.
+ */
+void touch_softlockup_watchdog_sched(void)
{
/*
* Preemption can be enabled. It doesn't matter which CPU's timestamp
@@ -233,6 +242,12 @@ void touch_softlockup_watchdog(void)
*/
raw_cpu_write(watchdog_touch_ts, 0);
}
+
+void touch_softlockup_watchdog(void)
+{
+ touch_softlockup_watchdog_sched();
+ wq_watchdog_touch(raw_smp_processor_id());
+}
EXPORT_SYMBOL(touch_softlockup_watchdog);
void touch_all_softlockup_watchdogs(void)
@@ -246,6 +261,7 @@ void touch_all_softlockup_watchdogs(void)
*/
for_each_watchdog_cpu(cpu)
per_cpu(watchdog_touch_ts, cpu) = 0;
+ wq_watchdog_touch(-1);
}
#ifdef CONFIG_HARDLOCKUP_DETECTOR
@@ -351,7 +367,7 @@ static void watchdog_overflow_callback(struct perf_event *event,
trigger_allbutself_cpu_backtrace();
if (hardlockup_panic)
- panic("Hard LOCKUP");
+ nmi_panic(regs, "Hard LOCKUP");
__this_cpu_write(hard_watchdog_warn, true);
return;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index c579dba..61a0264 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -148,6 +148,8 @@ struct worker_pool {
int id; /* I: pool ID */
unsigned int flags; /* X: flags */
+ unsigned long watchdog_ts; /* L: watchdog timestamp */
+
struct list_head worklist; /* L: list of pending works */
int nr_workers; /* L: total number of workers */
@@ -1083,6 +1085,8 @@ static void pwq_activate_delayed_work(struct work_struct *work)
struct pool_workqueue *pwq = get_work_pwq(work);
trace_workqueue_activate_work(work);
+ if (list_empty(&pwq->pool->worklist))
+ pwq->pool->watchdog_ts = jiffies;
move_linked_works(work, &pwq->pool->worklist, NULL);
__clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work));
pwq->nr_active++;
@@ -1385,6 +1389,8 @@ retry:
trace_workqueue_activate_work(work);
pwq->nr_active++;
worklist = &pwq->pool->worklist;
+ if (list_empty(worklist))
+ pwq->pool->watchdog_ts = jiffies;
} else {
work_flags |= WORK_STRUCT_DELAYED;
worklist = &pwq->delayed_works;
@@ -2157,6 +2163,8 @@ recheck:
list_first_entry(&pool->worklist,
struct work_struct, entry);
+ pool->watchdog_ts = jiffies;
+
if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) {
/* optimization path, not strictly necessary */
process_one_work(worker, work);
@@ -2240,6 +2248,7 @@ repeat:
struct pool_workqueue, mayday_node);
struct worker_pool *pool = pwq->pool;
struct work_struct *work, *n;
+ bool first = true;
__set_current_state(TASK_RUNNING);
list_del_init(&pwq->mayday_node);
@@ -2256,9 +2265,14 @@ repeat:
* process'em.
*/
WARN_ON_ONCE(!list_empty(scheduled));
- list_for_each_entry_safe(work, n, &pool->worklist, entry)
- if (get_work_pwq(work) == pwq)
+ list_for_each_entry_safe(work, n, &pool->worklist, entry) {
+ if (get_work_pwq(work) == pwq) {
+ if (first)
+ pool->watchdog_ts = jiffies;
move_linked_works(work, scheduled, &n);
+ }
+ first = false;
+ }
if (!list_empty(scheduled)) {
process_scheduled_works(rescuer);
@@ -2316,6 +2330,37 @@ repeat:
goto repeat;
}
+/**
+ * check_flush_dependency - check for flush dependency sanity
+ * @target_wq: workqueue being flushed
+ * @target_work: work item being flushed (NULL for workqueue flushes)
+ *
+ * %current is trying to flush the whole @target_wq or @target_work on it.
+ * If @target_wq doesn't have %WQ_MEM_RECLAIM, verify that %current is not
+ * reclaiming memory or running on a workqueue which doesn't have
+ * %WQ_MEM_RECLAIM as that can break forward-progress guarantee leading to
+ * a deadlock.
+ */
+static void check_flush_dependency(struct workqueue_struct *target_wq,
+ struct work_struct *target_work)
+{
+ work_func_t target_func = target_work ? target_work->func : NULL;
+ struct worker *worker;
+
+ if (target_wq->flags & WQ_MEM_RECLAIM)
+ return;
+
+ worker = current_wq_worker();
+
+ WARN_ONCE(current->flags & PF_MEMALLOC,
+ "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%pf",
+ current->pid, current->comm, target_wq->name, target_func);
+ WARN_ONCE(worker && (worker->current_pwq->wq->flags & WQ_MEM_RECLAIM),
+ "workqueue: WQ_MEM_RECLAIM %s:%pf is flushing !WQ_MEM_RECLAIM %s:%pf",
+ worker->current_pwq->wq->name, worker->current_func,
+ target_wq->name, target_func);
+}
+
struct wq_barrier {
struct work_struct work;
struct completion done;
@@ -2525,6 +2570,8 @@ void flush_workqueue(struct workqueue_struct *wq)
list_add_tail(&this_flusher.list, &wq->flusher_overflow);
}
+ check_flush_dependency(wq, NULL);
+
mutex_unlock(&wq->mutex);
wait_for_completion(&this_flusher.done);
@@ -2697,6 +2744,8 @@ static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr)
pwq = worker->current_pwq;
}
+ check_flush_dependency(pwq->wq, work);
+
insert_wq_barrier(pwq, barr, work, worker);
spin_unlock_irq(&pool->lock);
@@ -3069,6 +3118,7 @@ static int init_worker_pool(struct worker_pool *pool)
pool->cpu = -1;
pool->node = NUMA_NO_NODE;
pool->flags |= POOL_DISASSOCIATED;
+ pool->watchdog_ts = jiffies;
INIT_LIST_HEAD(&pool->worklist);
INIT_LIST_HEAD(&pool->idle_list);
hash_init(pool->busy_hash);
@@ -3601,7 +3651,6 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
const struct workqueue_attrs *attrs)
{
struct apply_wqattrs_ctx *ctx;
- int ret = -ENOMEM;
/* only unbound workqueues can change attributes */
if (WARN_ON(!(wq->flags & WQ_UNBOUND)))
@@ -3612,16 +3661,14 @@ static int apply_workqueue_attrs_locked(struct workqueue_struct *wq,
return -EINVAL;
ctx = apply_wqattrs_prepare(wq, attrs);
+ if (!ctx)
+ return -ENOMEM;
/* the ctx has been prepared successfully, let's commit it */
- if (ctx) {
- apply_wqattrs_commit(ctx);
- ret = 0;
- }
-
+ apply_wqattrs_commit(ctx);
apply_wqattrs_cleanup(ctx);
- return ret;
+ return 0;
}
/**
@@ -4308,7 +4355,9 @@ void show_workqueue_state(void)
pr_info("pool %d:", pool->id);
pr_cont_pool_info(pool);
- pr_cont(" workers=%d", pool->nr_workers);
+ pr_cont(" hung=%us workers=%d",
+ jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000,
+ pool->nr_workers);
if (pool->manager)
pr_cont(" manager: %d",
task_pid_nr(pool->manager->task));
@@ -5167,6 +5216,154 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq)
static void workqueue_sysfs_unregister(struct workqueue_struct *wq) { }
#endif /* CONFIG_SYSFS */
+/*
+ * Workqueue watchdog.
+ *
+ * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal
+ * flush dependency, a concurrency managed work item which stays RUNNING
+ * indefinitely. Workqueue stalls can be very difficult to debug as the
+ * usual warning mechanisms don't trigger and internal workqueue state is
+ * largely opaque.
+ *
+ * Workqueue watchdog monitors all worker pools periodically and dumps
+ * state if some pools failed to make forward progress for a while where
+ * forward progress is defined as the first item on ->worklist changing.
+ *
+ * This mechanism is controlled through the kernel parameter
+ * "workqueue.watchdog_thresh" which can be updated at runtime through the
+ * corresponding sysfs parameter file.
+ */
+#ifdef CONFIG_WQ_WATCHDOG
+
+static void wq_watchdog_timer_fn(unsigned long data);
+
+static unsigned long wq_watchdog_thresh = 30;
+static struct timer_list wq_watchdog_timer =
+ TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0);
+
+static unsigned long wq_watchdog_touched = INITIAL_JIFFIES;
+static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES;
+
+static void wq_watchdog_reset_touched(void)
+{
+ int cpu;
+
+ wq_watchdog_touched = jiffies;
+ for_each_possible_cpu(cpu)
+ per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
+}
+
+static void wq_watchdog_timer_fn(unsigned long data)
+{
+ unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ;
+ bool lockup_detected = false;
+ struct worker_pool *pool;
+ int pi;
+
+ if (!thresh)
+ return;
+
+ rcu_read_lock();
+
+ for_each_pool(pool, pi) {
+ unsigned long pool_ts, touched, ts;
+
+ if (list_empty(&pool->worklist))
+ continue;
+
+ /* get the latest of pool and touched timestamps */
+ pool_ts = READ_ONCE(pool->watchdog_ts);
+ touched = READ_ONCE(wq_watchdog_touched);
+
+ if (time_after(pool_ts, touched))
+ ts = pool_ts;
+ else
+ ts = touched;
+
+ if (pool->cpu >= 0) {
+ unsigned long cpu_touched =
+ READ_ONCE(per_cpu(wq_watchdog_touched_cpu,
+ pool->cpu));
+ if (time_after(cpu_touched, ts))
+ ts = cpu_touched;
+ }
+
+ /* did we stall? */
+ if (time_after(jiffies, ts + thresh)) {
+ lockup_detected = true;
+ pr_emerg("BUG: workqueue lockup - pool");
+ pr_cont_pool_info(pool);
+ pr_cont(" stuck for %us!\n",
+ jiffies_to_msecs(jiffies - pool_ts) / 1000);
+ }
+ }
+
+ rcu_read_unlock();
+
+ if (lockup_detected)
+ show_workqueue_state();
+
+ wq_watchdog_reset_touched();
+ mod_timer(&wq_watchdog_timer, jiffies + thresh);
+}
+
+void wq_watchdog_touch(int cpu)
+{
+ if (cpu >= 0)
+ per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies;
+ else
+ wq_watchdog_touched = jiffies;
+}
+
+static void wq_watchdog_set_thresh(unsigned long thresh)
+{
+ wq_watchdog_thresh = 0;
+ del_timer_sync(&wq_watchdog_timer);
+
+ if (thresh) {
+ wq_watchdog_thresh = thresh;
+ wq_watchdog_reset_touched();
+ mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ);
+ }
+}
+
+static int wq_watchdog_param_set_thresh(const char *val,
+ const struct kernel_param *kp)
+{
+ unsigned long thresh;
+ int ret;
+
+ ret = kstrtoul(val, 0, &thresh);
+ if (ret)
+ return ret;
+
+ if (system_wq)
+ wq_watchdog_set_thresh(thresh);
+ else
+ wq_watchdog_thresh = thresh;
+
+ return 0;
+}
+
+static const struct kernel_param_ops wq_watchdog_thresh_ops = {
+ .set = wq_watchdog_param_set_thresh,
+ .get = param_get_ulong,
+};
+
+module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh,
+ 0644);
+
+static void wq_watchdog_init(void)
+{
+ wq_watchdog_set_thresh(wq_watchdog_thresh);
+}
+
+#else /* CONFIG_WQ_WATCHDOG */
+
+static inline void wq_watchdog_init(void) { }
+
+#endif /* CONFIG_WQ_WATCHDOG */
+
static void __init wq_numa_init(void)
{
cpumask_var_t *tbl;
@@ -5290,6 +5487,9 @@ static int __init init_workqueues(void)
!system_unbound_wq || !system_freezable_wq ||
!system_power_efficient_wq ||
!system_freezable_power_efficient_wq);
+
+ wq_watchdog_init();
+
return 0;
}
early_initcall(init_workqueues);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 8c15b29..c98e93c 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -812,6 +812,17 @@ config BOOTPARAM_HUNG_TASK_PANIC_VALUE
default 0 if !BOOTPARAM_HUNG_TASK_PANIC
default 1 if BOOTPARAM_HUNG_TASK_PANIC
+config WQ_WATCHDOG
+ bool "Detect Workqueue Stalls"
+ depends on DEBUG_KERNEL
+ help
+ Say Y here to enable stall detection on workqueues. If a
+ worker pool doesn't make forward progress on a pending work
+ item for over a given amount of time, 30s by default, a
+ warning message is printed along with dump of workqueue
+ state. This can be configured through kernel parameter
+ "workqueue.watchdog_thresh" and its sysfs counterpart.
+
endmenu # "Debug lockups and hangs"
config PANIC_ON_OOPS
@@ -1523,8 +1534,7 @@ config FAIL_IO_TIMEOUT
config FAIL_MMC_REQUEST
bool "Fault-injection capability for MMC IO"
- select DEBUG_FS
- depends on FAULT_INJECTION && MMC
+ depends on FAULT_INJECTION_DEBUG_FS && MMC
help
Provide fault-injection capability for MMC IO.
This will make the mmc core return data errors. This is
diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c
index 83c33a5b..d62de8b 100644
--- a/lib/atomic64_test.c
+++ b/lib/atomic64_test.c
@@ -16,6 +16,10 @@
#include <linux/kernel.h>
#include <linux/atomic.h>
+#ifdef CONFIG_X86
+#include <asm/processor.h> /* for boot_cpu_has below */
+#endif
+
#define TEST(bit, op, c_op, val) \
do { \
atomic##bit##_set(&v, v0); \
@@ -27,6 +31,65 @@ do { \
(unsigned long long)r); \
} while (0)
+/*
+ * Test for a atomic operation family,
+ * @test should be a macro accepting parameters (bit, op, ...)
+ */
+
+#define FAMILY_TEST(test, bit, op, args...) \
+do { \
+ test(bit, op, ##args); \
+ test(bit, op##_acquire, ##args); \
+ test(bit, op##_release, ##args); \
+ test(bit, op##_relaxed, ##args); \
+} while (0)
+
+#define TEST_RETURN(bit, op, c_op, val) \
+do { \
+ atomic##bit##_set(&v, v0); \
+ r = v0; \
+ r c_op val; \
+ BUG_ON(atomic##bit##_##op(val, &v) != r); \
+ BUG_ON(atomic##bit##_read(&v) != r); \
+} while (0)
+
+#define RETURN_FAMILY_TEST(bit, op, c_op, val) \
+do { \
+ FAMILY_TEST(TEST_RETURN, bit, op, c_op, val); \
+} while (0)
+
+#define TEST_ARGS(bit, op, init, ret, expect, args...) \
+do { \
+ atomic##bit##_set(&v, init); \
+ BUG_ON(atomic##bit##_##op(&v, ##args) != ret); \
+ BUG_ON(atomic##bit##_read(&v) != expect); \
+} while (0)
+
+#define XCHG_FAMILY_TEST(bit, init, new) \
+do { \
+ FAMILY_TEST(TEST_ARGS, bit, xchg, init, init, new, new); \
+} while (0)
+
+#define CMPXCHG_FAMILY_TEST(bit, init, new, wrong) \
+do { \
+ FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \
+ init, init, new, init, new); \
+ FAMILY_TEST(TEST_ARGS, bit, cmpxchg, \
+ init, init, init, wrong, new); \
+} while (0)
+
+#define INC_RETURN_FAMILY_TEST(bit, i) \
+do { \
+ FAMILY_TEST(TEST_ARGS, bit, inc_return, \
+ i, (i) + one, (i) + one); \
+} while (0)
+
+#define DEC_RETURN_FAMILY_TEST(bit, i) \
+do { \
+ FAMILY_TEST(TEST_ARGS, bit, dec_return, \
+ i, (i) - one, (i) - one); \
+} while (0)
+
static __init void test_atomic(void)
{
int v0 = 0xaaa31337;
@@ -45,6 +108,18 @@ static __init void test_atomic(void)
TEST(, and, &=, v1);
TEST(, xor, ^=, v1);
TEST(, andnot, &= ~, v1);
+
+ RETURN_FAMILY_TEST(, add_return, +=, onestwos);
+ RETURN_FAMILY_TEST(, add_return, +=, -one);
+ RETURN_FAMILY_TEST(, sub_return, -=, onestwos);
+ RETURN_FAMILY_TEST(, sub_return, -=, -one);
+
+ INC_RETURN_FAMILY_TEST(, v0);
+ DEC_RETURN_FAMILY_TEST(, v0);
+
+ XCHG_FAMILY_TEST(, v0, v1);
+ CMPXCHG_FAMILY_TEST(, v0, v1, onestwos);
+
}
#define INIT(c) do { atomic64_set(&v, c); r = c; } while (0)
@@ -74,25 +149,10 @@ static __init void test_atomic64(void)
TEST(64, xor, ^=, v1);
TEST(64, andnot, &= ~, v1);
- INIT(v0);
- r += onestwos;
- BUG_ON(atomic64_add_return(onestwos, &v) != r);
- BUG_ON(v.counter != r);
-
- INIT(v0);
- r += -one;
- BUG_ON(atomic64_add_return(-one, &v) != r);
- BUG_ON(v.counter != r);
-
- INIT(v0);
- r -= onestwos;
- BUG_ON(atomic64_sub_return(onestwos, &v) != r);
- BUG_ON(v.counter != r);
-
- INIT(v0);
- r -= -one;
- BUG_ON(atomic64_sub_return(-one, &v) != r);
- BUG_ON(v.counter != r);
+ RETURN_FAMILY_TEST(64, add_return, +=, onestwos);
+ RETURN_FAMILY_TEST(64, add_return, +=, -one);
+ RETURN_FAMILY_TEST(64, sub_return, -=, onestwos);
+ RETURN_FAMILY_TEST(64, sub_return, -=, -one);
INIT(v0);
atomic64_inc(&v);
@@ -100,33 +160,15 @@ static __init void test_atomic64(void)
BUG_ON(v.counter != r);
INIT(v0);
- r += one;
- BUG_ON(atomic64_inc_return(&v) != r);
- BUG_ON(v.counter != r);
-
- INIT(v0);
atomic64_dec(&v);
r -= one;
BUG_ON(v.counter != r);
- INIT(v0);
- r -= one;
- BUG_ON(atomic64_dec_return(&v) != r);
- BUG_ON(v.counter != r);
+ INC_RETURN_FAMILY_TEST(64, v0);
+ DEC_RETURN_FAMILY_TEST(64, v0);
- INIT(v0);
- BUG_ON(atomic64_xchg(&v, v1) != v0);
- r = v1;
- BUG_ON(v.counter != r);
-
- INIT(v0);
- BUG_ON(atomic64_cmpxchg(&v, v0, v1) != v0);
- r = v1;
- BUG_ON(v.counter != r);
-
- INIT(v0);
- BUG_ON(atomic64_cmpxchg(&v, v2, v1) != v0);
- BUG_ON(v.counter != r);
+ XCHG_FAMILY_TEST(64, v0, v1);
+ CMPXCHG_FAMILY_TEST(64, v0, v1, v2);
INIT(v0);
BUG_ON(atomic64_add_unless(&v, one, v0));
diff --git a/lib/btree.c b/lib/btree.c
index 4264871..f93a945 100644
--- a/lib/btree.c
+++ b/lib/btree.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 2007-2008 Joern Engel <joern@logfs.org>
* Bits and pieces stolen from Peter Zijlstra's code, which is
- * Copyright 2007, Red Hat Inc. Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright 2007, Red Hat Inc. Peter Zijlstra
* GPLv2
*
* see http://programming.kicks-ass.net/kernel-patches/vma_lookup/btree.patch
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index 8855f01..d34bd24 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -1464,7 +1464,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
entry->type = dma_debug_coherent;
entry->dev = dev;
entry->pfn = page_to_pfn(virt_to_page(virt));
- entry->offset = (size_t) virt & PAGE_MASK;
+ entry->offset = (size_t) virt & ~PAGE_MASK;
entry->size = size;
entry->dev_addr = dma_addr;
entry->direction = DMA_BIDIRECTIONAL;
@@ -1480,7 +1480,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
.type = dma_debug_coherent,
.dev = dev,
.pfn = page_to_pfn(virt_to_page(virt)),
- .offset = (size_t) virt & PAGE_MASK,
+ .offset = (size_t) virt & ~PAGE_MASK,
.dev_addr = addr,
.size = size,
.direction = DMA_BIDIRECTIONAL,
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index e3952e9..fe42b6e 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -657,14 +657,9 @@ static ssize_t ddebug_proc_write(struct file *file, const char __user *ubuf,
pr_warn("expected <%d bytes into control\n", USER_BUF_PAGE);
return -E2BIG;
}
- tmpbuf = kmalloc(len + 1, GFP_KERNEL);
- if (!tmpbuf)
- return -ENOMEM;
- if (copy_from_user(tmpbuf, ubuf, len)) {
- kfree(tmpbuf);
- return -EFAULT;
- }
- tmpbuf[len] = '\0';
+ tmpbuf = memdup_user_nul(ubuf, len);
+ if (IS_ERR(tmpbuf))
+ return PTR_ERR(tmpbuf);
vpr_info("read %d bytes from userspace\n", (int)len);
ret = ddebug_exec_queries(tmpbuf, NULL);
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 75232ad..5fecddc 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -369,7 +369,7 @@ static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t
kunmap_atomic(from);
}
-static void memcpy_to_page(struct page *page, size_t offset, char *from, size_t len)
+static void memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len)
{
char *to = kmap_atomic(page);
memcpy(to + offset, from, len);
@@ -383,9 +383,9 @@ static void memzero_page(struct page *page, size_t offset, size_t len)
kunmap_atomic(addr);
}
-size_t copy_to_iter(void *addr, size_t bytes, struct iov_iter *i)
+size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i)
{
- char *from = addr;
+ const char *from = addr;
if (unlikely(bytes > i->count))
bytes = i->count;
@@ -704,10 +704,10 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
}
EXPORT_SYMBOL(csum_and_copy_from_iter);
-size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
+size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum,
struct iov_iter *i)
{
- char *from = addr;
+ const char *from = addr;
__wsum sum, next;
size_t off = 0;
if (unlikely(bytes > i->count))
@@ -849,3 +849,4 @@ int import_single_range(int rw, void __user *buf, size_t len,
iov_iter_init(i, rw, iov, 1, len);
return 0;
}
+EXPORT_SYMBOL(import_single_range);
diff --git a/lib/list_debug.c b/lib/list_debug.c
index c24c2f7..3859bf6 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -37,7 +37,7 @@ void __list_add(struct list_head *new,
next->prev = new;
new->next = next;
new->prev = prev;
- prev->next = new;
+ WRITE_ONCE(prev->next, new);
}
EXPORT_SYMBOL(__list_add);
diff --git a/lib/proportions.c b/lib/proportions.c
index 6f72429..efa54f25 100644
--- a/lib/proportions.c
+++ b/lib/proportions.c
@@ -1,7 +1,7 @@
/*
* Floating proportions
*
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* Description:
*
diff --git a/lib/rhashtable.c b/lib/rhashtable.c
index a54ff89..51282f5 100644
--- a/lib/rhashtable.c
+++ b/lib/rhashtable.c
@@ -389,33 +389,31 @@ static bool rhashtable_check_elasticity(struct rhashtable *ht,
return false;
}
-int rhashtable_insert_rehash(struct rhashtable *ht)
+int rhashtable_insert_rehash(struct rhashtable *ht,
+ struct bucket_table *tbl)
{
struct bucket_table *old_tbl;
struct bucket_table *new_tbl;
- struct bucket_table *tbl;
unsigned int size;
int err;
old_tbl = rht_dereference_rcu(ht->tbl, ht);
- tbl = rhashtable_last_table(ht, old_tbl);
size = tbl->size;
+ err = -EBUSY;
+
if (rht_grow_above_75(ht, tbl))
size *= 2;
/* Do not schedule more than one rehash */
else if (old_tbl != tbl)
- return -EBUSY;
+ goto fail;
+
+ err = -ENOMEM;
new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC);
- if (new_tbl == NULL) {
- /* Schedule async resize/rehash to try allocation
- * non-atomic context.
- */
- schedule_work(&ht->run_work);
- return -ENOMEM;
- }
+ if (new_tbl == NULL)
+ goto fail;
err = rhashtable_rehash_attach(ht, tbl, new_tbl);
if (err) {
@@ -426,12 +424,24 @@ int rhashtable_insert_rehash(struct rhashtable *ht)
schedule_work(&ht->run_work);
return err;
+
+fail:
+ /* Do not fail the insert if someone else did a rehash. */
+ if (likely(rcu_dereference_raw(tbl->future_tbl)))
+ return 0;
+
+ /* Schedule async rehash to retry allocation in process context. */
+ if (err == -ENOMEM)
+ schedule_work(&ht->run_work);
+
+ return err;
}
EXPORT_SYMBOL_GPL(rhashtable_insert_rehash);
-int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
- struct rhash_head *obj,
- struct bucket_table *tbl)
+struct bucket_table *rhashtable_insert_slow(struct rhashtable *ht,
+ const void *key,
+ struct rhash_head *obj,
+ struct bucket_table *tbl)
{
struct rhash_head *head;
unsigned int hash;
@@ -467,7 +477,12 @@ int rhashtable_insert_slow(struct rhashtable *ht, const void *key,
exit:
spin_unlock(rht_bucket_lock(tbl, hash));
- return err;
+ if (err == 0)
+ return NULL;
+ else if (err == -EAGAIN)
+ return tbl;
+ else
+ return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rhashtable_insert_slow);
@@ -503,10 +518,11 @@ int rhashtable_walk_init(struct rhashtable *ht, struct rhashtable_iter *iter)
if (!iter->walker)
return -ENOMEM;
- mutex_lock(&ht->mutex);
- iter->walker->tbl = rht_dereference(ht->tbl, ht);
+ spin_lock(&ht->lock);
+ iter->walker->tbl =
+ rcu_dereference_protected(ht->tbl, lockdep_is_held(&ht->lock));
list_add(&iter->walker->list, &iter->walker->tbl->walkers);
- mutex_unlock(&ht->mutex);
+ spin_unlock(&ht->lock);
return 0;
}
@@ -520,10 +536,10 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_init);
*/
void rhashtable_walk_exit(struct rhashtable_iter *iter)
{
- mutex_lock(&iter->ht->mutex);
+ spin_lock(&iter->ht->lock);
if (iter->walker->tbl)
list_del(&iter->walker->list);
- mutex_unlock(&iter->ht->mutex);
+ spin_unlock(&iter->ht->lock);
kfree(iter->walker);
}
EXPORT_SYMBOL_GPL(rhashtable_walk_exit);
@@ -547,14 +563,12 @@ int rhashtable_walk_start(struct rhashtable_iter *iter)
{
struct rhashtable *ht = iter->ht;
- mutex_lock(&ht->mutex);
+ rcu_read_lock();
+ spin_lock(&ht->lock);
if (iter->walker->tbl)
list_del(&iter->walker->list);
-
- rcu_read_lock();
-
- mutex_unlock(&ht->mutex);
+ spin_unlock(&ht->lock);
if (!iter->walker->tbl) {
iter->walker->tbl = rht_dereference_rcu(ht->tbl, ht);
@@ -723,9 +737,6 @@ int rhashtable_init(struct rhashtable *ht,
if (params->nulls_base && params->nulls_base < (1U << RHT_BASE_SHIFT))
return -EINVAL;
- if (params->nelem_hint)
- size = rounded_hashtable_size(params);
-
memset(ht, 0, sizeof(*ht));
mutex_init(&ht->mutex);
spin_lock_init(&ht->lock);
@@ -745,6 +756,9 @@ int rhashtable_init(struct rhashtable *ht,
ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE);
+ if (params->nelem_hint)
+ size = rounded_hashtable_size(&ht->p);
+
/* The maximum (not average) chain length grows with the
* size of the hash table, at a rate of (log N)/(log log N).
* The value of 16 is selected so that even if the hash
diff --git a/lib/string.c b/lib/string.c
index 84775ba..0323c0d 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -904,7 +904,7 @@ void *memchr_inv(const void *start, int c, size_t bytes)
value64 = value;
#if defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64
- value64 *= 0x0101010101010101;
+ value64 *= 0x0101010101010101ULL;
#elif defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER)
value64 *= 0x01010101;
value64 |= value64 << 32;
diff --git a/lib/test_bpf.c b/lib/test_bpf.c
index d137739..10cd186 100644
--- a/lib/test_bpf.c
+++ b/lib/test_bpf.c
@@ -5056,6 +5056,36 @@ static struct bpf_test tests[] = {
{ {0x1, 0x0 } },
},
{
+ "MOD default X",
+ .u.insns = {
+ /*
+ * A = 0x42
+ * A = A mod X ; this halt the filter execution if X is 0
+ * ret 0x42
+ */
+ BPF_STMT(BPF_LD | BPF_IMM, 0x42),
+ BPF_STMT(BPF_ALU | BPF_MOD | BPF_X, 0),
+ BPF_STMT(BPF_RET | BPF_K, 0x42),
+ },
+ CLASSIC | FLAG_NO_DATA,
+ {},
+ { {0x1, 0x0 } },
+ },
+ {
+ "MOD default A",
+ .u.insns = {
+ /*
+ * A = A mod 1
+ * ret A
+ */
+ BPF_STMT(BPF_ALU | BPF_MOD | BPF_K, 0x1),
+ BPF_STMT(BPF_RET | BPF_A, 0x0),
+ },
+ CLASSIC | FLAG_NO_DATA,
+ {},
+ { {0x1, 0x0 } },
+ },
+ {
"JMP EQ default A",
.u.insns = {
/*
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index f9cee8e..ac3f947 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -31,6 +31,9 @@
#include <linux/dcache.h>
#include <linux/cred.h>
#include <net/addrconf.h>
+#ifdef CONFIG_BLOCK
+#include <linux/blkdev.h>
+#endif
#include <asm/page.h> /* for PAGE_SIZE */
#include <asm/sections.h> /* for dereference_function_descriptor() */
@@ -613,6 +616,26 @@ char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_sp
return buf;
}
+#ifdef CONFIG_BLOCK
+static noinline_for_stack
+char *bdev_name(char *buf, char *end, struct block_device *bdev,
+ struct printf_spec spec, const char *fmt)
+{
+ struct gendisk *hd = bdev->bd_disk;
+
+ buf = string(buf, end, hd->disk_name, spec);
+ if (bdev->bd_part->partno) {
+ if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) {
+ if (buf < end)
+ *buf = 'p';
+ buf++;
+ }
+ buf = number(buf, end, bdev->bd_part->partno, spec);
+ }
+ return buf;
+}
+#endif
+
static noinline_for_stack
char *symbol_string(char *buf, char *end, void *ptr,
struct printf_spec spec, const char *fmt)
@@ -1443,6 +1466,7 @@ int kptr_restrict __read_mostly;
* (default assumed to be phys_addr_t, passed by reference)
* - 'd[234]' For a dentry name (optionally 2-4 last components)
* - 'D[234]' Same as 'd' but for a struct file
+ * - 'g' For block_device name (gendisk + partition number)
* - 'C' For a clock, it prints the name (Common Clock Framework) or address
* (legacy clock framework) of the clock
* - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
@@ -1600,6 +1624,11 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,
return dentry_name(buf, end,
((const struct file *)ptr)->f_path.dentry,
spec, fmt);
+#ifdef CONFIG_BLOCK
+ case 'g':
+ return bdev_name(buf, end, ptr, spec, fmt);
+#endif
+
}
spec.flags |= SMALL;
if (spec.field_width == -1) {
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 8ed2ffd..7340353 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -957,8 +957,9 @@ EXPORT_SYMBOL(congestion_wait);
* jiffies for either a BDI to exit congestion of the given @sync queue
* or a write to complete.
*
- * In the absence of zone congestion, cond_resched() is called to yield
- * the processor if necessary but otherwise does not sleep.
+ * In the absence of zone congestion, a short sleep or a cond_resched is
+ * performed to yield the processor and to allow other subsystems to make
+ * a forward progress.
*
* The return value is 0 if the sleep is for the full timeout. Otherwise,
* it is the number of jiffies that were still remaining when the function
@@ -978,7 +979,19 @@ long wait_iff_congested(struct zone *zone, int sync, long timeout)
*/
if (atomic_read(&nr_wb_congested[sync]) == 0 ||
!test_bit(ZONE_CONGESTED, &zone->flags)) {
- cond_resched();
+
+ /*
+ * Memory allocation/reclaim might be called from a WQ
+ * context and the current implementation of the WQ
+ * concurrency control doesn't recognize that a particular
+ * WQ is congested if the worker thread is looping without
+ * ever sleeping. Therefore we have to do a short sleep
+ * here rather than calling cond_resched().
+ */
+ if (current->flags & PF_WQ_WORKER)
+ schedule_timeout(1);
+ else
+ cond_resched();
/* In case we scheduled, work out time remaining */
ret = timeout - (jiffies - start);
diff --git a/mm/bootmem.c b/mm/bootmem.c
index 3b63807..91e32bc 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -33,6 +33,7 @@ EXPORT_SYMBOL(contig_page_data);
unsigned long max_low_pfn;
unsigned long min_low_pfn;
unsigned long max_pfn;
+unsigned long long max_possible_pfn;
bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata;
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index c29ddeb..62fe06b 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2009,7 +2009,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
/*
* Be somewhat over-protective like KSM for now!
*/
- if (*vm_flags & (VM_HUGEPAGE | VM_NO_THP))
+ if (*vm_flags & VM_NO_THP)
return -EINVAL;
*vm_flags &= ~VM_NOHUGEPAGE;
*vm_flags |= VM_HUGEPAGE;
@@ -2025,7 +2025,7 @@ int hugepage_madvise(struct vm_area_struct *vma,
/*
* Be somewhat over-protective like KSM for now!
*/
- if (*vm_flags & (VM_NOHUGEPAGE | VM_NO_THP))
+ if (*vm_flags & VM_NO_THP)
return -EINVAL;
*vm_flags &= ~VM_HUGEPAGE;
*vm_flags |= VM_NOHUGEPAGE;
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7ce07d6..ef6963b 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -372,8 +372,10 @@ retry_locked:
spin_unlock(&resv->lock);
trg = kmalloc(sizeof(*trg), GFP_KERNEL);
- if (!trg)
+ if (!trg) {
+ kfree(nrg);
return -ENOMEM;
+ }
spin_lock(&resv->lock);
list_add(&trg->link, &resv->region_cache);
@@ -483,8 +485,16 @@ static long region_del(struct resv_map *resv, long f, long t)
retry:
spin_lock(&resv->lock);
list_for_each_entry_safe(rg, trg, head, link) {
- if (rg->to <= f)
+ /*
+ * Skip regions before the range to be deleted. file_region
+ * ranges are normally of the form [from, to). However, there
+ * may be a "placeholder" entry in the map which is of the form
+ * (from, to) with from == to. Check for placeholder entries
+ * at the beginning of the range to be deleted.
+ */
+ if (rg->to <= f && (rg->to != rg->from || rg->to != f))
continue;
+
if (rg->from >= t)
break;
@@ -1886,7 +1896,10 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,
page = __alloc_buddy_huge_page_with_mpol(h, vma, addr);
if (!page)
goto out_uncharge_cgroup;
-
+ if (!avoid_reserve && vma_has_reserves(vma, gbl_chg)) {
+ SetPagePrivate(page);
+ h->resv_huge_pages--;
+ }
spin_lock(&hugetlb_lock);
list_move(&page->lru, &h->hugepage_activelist);
/* Fall through */
@@ -2138,7 +2151,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
* First take pages out of surplus state. Then make up the
* remaining difference by allocating fresh huge pages.
*
- * We might race with alloc_buddy_huge_page() here and be unable
+ * We might race with __alloc_buddy_huge_page() here and be unable
* to convert a surplus huge page to a normal huge page. That is
* not critical, though, it just means the overall size of the
* pool might be one hugepage larger than it needs to be, but
@@ -2180,7 +2193,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
* By placing pages into the surplus state independent of the
* overcommit value, we are allowing the surplus pool size to
* exceed overcommit. There are few sane options here. Since
- * alloc_buddy_huge_page() is checking the global counter,
+ * __alloc_buddy_huge_page() is checking the global counter,
* though, we'll note that we're not allowed to exceed surplus
* and won't grow the pool anywhere else. Not until one of the
* sysctls are changed, or the surplus pages go out of use.
@@ -3693,12 +3706,12 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
} else if (unlikely(is_hugetlb_entry_hwpoisoned(entry)))
return VM_FAULT_HWPOISON_LARGE |
VM_FAULT_SET_HINDEX(hstate_index(h));
+ } else {
+ ptep = huge_pte_alloc(mm, address, huge_page_size(h));
+ if (!ptep)
+ return VM_FAULT_OOM;
}
- ptep = huge_pte_alloc(mm, address, huge_page_size(h));
- if (!ptep)
- return VM_FAULT_OOM;
-
mapping = vma->vm_file->f_mapping;
idx = vma_hugecache_offset(h, vma, address);
diff --git a/mm/kasan/kasan.c b/mm/kasan/kasan.c
index d41b21b..bc0a8d8 100644
--- a/mm/kasan/kasan.c
+++ b/mm/kasan/kasan.c
@@ -19,6 +19,7 @@
#include <linux/export.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/kmemleak.h>
#include <linux/memblock.h>
#include <linux/memory.h>
#include <linux/mm.h>
@@ -444,6 +445,7 @@ int kasan_module_alloc(void *addr, size_t size)
if (ret) {
find_vm_area(addr)->flags |= VM_KASAN;
+ kmemleak_ignore(ret);
return 0;
}
diff --git a/mm/memblock.c b/mm/memblock.c
index d300f13..07ff069 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -822,6 +822,17 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size)
return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR);
}
+/**
+ * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP.
+ * @base: the base phys addr of the region
+ * @size: the size of the region
+ *
+ * Return 0 on success, -errno on failure.
+ */
+int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size)
+{
+ return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP);
+}
/**
* __next_reserved_mem_region - next function for for_each_reserved_region()
@@ -913,6 +924,10 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags,
if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
continue;
+ /* skip nomap memory unless we were asked for it explicitly */
+ if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+ continue;
+
if (!type_b) {
if (out_start)
*out_start = m_start;
@@ -1022,6 +1037,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags,
if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m))
continue;
+ /* skip nomap memory unless we were asked for it explicitly */
+ if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m))
+ continue;
+
if (!type_b) {
if (out_start)
*out_start = m_start;
@@ -1519,6 +1538,15 @@ int __init_memblock memblock_is_memory(phys_addr_t addr)
return memblock_search(&memblock.memory, addr) != -1;
}
+int __init_memblock memblock_is_map_memory(phys_addr_t addr)
+{
+ int i = memblock_search(&memblock.memory, addr);
+
+ if (i == -1)
+ return false;
+ return !memblock_is_nomap(&memblock.memory.regions[i]);
+}
+
#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
unsigned long *start_pfn, unsigned long *end_pfn)
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 9acfb16..fc10620 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -903,14 +903,20 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
if (prev && reclaim->generation != iter->generation)
goto out_unlock;
- do {
+ while (1) {
pos = READ_ONCE(iter->position);
+ if (!pos || css_tryget(&pos->css))
+ break;
/*
- * A racing update may change the position and
- * put the last reference, hence css_tryget(),
- * or retry to see the updated position.
+ * css reference reached zero, so iter->position will
+ * be cleared by ->css_released. However, we should not
+ * rely on this happening soon, because ->css_released
+ * is called from a work queue, and by busy-waiting we
+ * might block it. So we clear iter->position right
+ * away.
*/
- } while (pos && !css_tryget(&pos->css));
+ (void)cmpxchg(&iter->position, pos, NULL);
+ }
}
if (pos)
@@ -956,17 +962,13 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
}
if (reclaim) {
- if (cmpxchg(&iter->position, pos, memcg) == pos) {
- if (memcg)
- css_get(&memcg->css);
- if (pos)
- css_put(&pos->css);
- }
-
/*
- * pairs with css_tryget when dereferencing iter->position
- * above.
+ * The position could have already been updated by a competing
+ * thread, so check that the value hasn't changed since we read
+ * it to avoid reclaiming from the same cgroup twice.
*/
+ (void)cmpxchg(&iter->position, pos, memcg);
+
if (pos)
css_put(&pos->css);
@@ -999,6 +1001,28 @@ void mem_cgroup_iter_break(struct mem_cgroup *root,
css_put(&prev->css);
}
+static void invalidate_reclaim_iterators(struct mem_cgroup *dead_memcg)
+{
+ struct mem_cgroup *memcg = dead_memcg;
+ struct mem_cgroup_reclaim_iter *iter;
+ struct mem_cgroup_per_zone *mz;
+ int nid, zid;
+ int i;
+
+ while ((memcg = parent_mem_cgroup(memcg))) {
+ for_each_node(nid) {
+ for (zid = 0; zid < MAX_NR_ZONES; zid++) {
+ mz = &memcg->nodeinfo[nid]->zoneinfo[zid];
+ for (i = 0; i <= DEF_PRIORITY; i++) {
+ iter = &mz->iter[i];
+ cmpxchg(&iter->position,
+ dead_memcg, NULL);
+ }
+ }
+ }
+ }
+}
+
/*
* Iteration constructs for visiting all cgroups (under a tree). If
* loops are exited prematurely (break), mem_cgroup_iter_break() must
@@ -2128,7 +2152,7 @@ done_restock:
*/
do {
if (page_counter_read(&memcg->memory) > memcg->high) {
- current->memcg_nr_pages_over_high += nr_pages;
+ current->memcg_nr_pages_over_high += batch;
set_notify_resume(current);
break;
}
@@ -4324,6 +4348,13 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
wb_memcg_offline(memcg);
}
+static void mem_cgroup_css_released(struct cgroup_subsys_state *css)
+{
+ struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+
+ invalidate_reclaim_iterators(memcg);
+}
+
static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
@@ -4779,23 +4810,18 @@ static void mem_cgroup_clear_mc(void)
spin_unlock(&mc.lock);
}
-static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
{
- struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+ struct cgroup_subsys_state *css;
+ struct mem_cgroup *memcg;
struct mem_cgroup *from;
struct task_struct *leader, *p;
struct mm_struct *mm;
unsigned long move_flags;
int ret = 0;
- /*
- * We are now commited to this value whatever it is. Changes in this
- * tunable will only affect upcoming migrations, not the current one.
- * So we need to save it, and keep it going.
- */
- move_flags = READ_ONCE(memcg->move_charge_at_immigrate);
- if (!move_flags)
+ /* charge immigration isn't supported on the default hierarchy */
+ if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
return 0;
/*
@@ -4805,13 +4831,23 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
* multiple.
*/
p = NULL;
- cgroup_taskset_for_each_leader(leader, tset) {
+ cgroup_taskset_for_each_leader(leader, css, tset) {
WARN_ON_ONCE(p);
p = leader;
+ memcg = mem_cgroup_from_css(css);
}
if (!p)
return 0;
+ /*
+ * We are now commited to this value whatever it is. Changes in this
+ * tunable will only affect upcoming migrations, not the current one.
+ * So we need to save it, and keep it going.
+ */
+ move_flags = READ_ONCE(memcg->move_charge_at_immigrate);
+ if (!move_flags)
+ return 0;
+
from = mem_cgroup_from_task(p);
VM_BUG_ON(from == memcg);
@@ -4842,8 +4878,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
return ret;
}
-static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
{
if (mc.to)
mem_cgroup_clear_mc();
@@ -4985,10 +5020,10 @@ retry:
atomic_dec(&mc.from->moving_account);
}
-static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup_taskset *tset)
{
- struct task_struct *p = cgroup_taskset_first(tset);
+ struct cgroup_subsys_state *css;
+ struct task_struct *p = cgroup_taskset_first(tset, &css);
struct mm_struct *mm = get_task_mm(p);
if (mm) {
@@ -5000,17 +5035,14 @@ static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
mem_cgroup_clear_mc();
}
#else /* !CONFIG_MMU */
-static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static int mem_cgroup_can_attach(struct cgroup_taskset *tset)
{
return 0;
}
-static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void mem_cgroup_cancel_attach(struct cgroup_taskset *tset)
{
}
-static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void mem_cgroup_move_task(struct cgroup_taskset *tset)
{
}
#endif
@@ -5184,6 +5216,7 @@ struct cgroup_subsys memory_cgrp_subsys = {
.css_alloc = mem_cgroup_css_alloc,
.css_online = mem_cgroup_css_online,
.css_offline = mem_cgroup_css_offline,
+ .css_released = mem_cgroup_css_released,
.css_free = mem_cgroup_css_free,
.css_reset = mem_cgroup_css_reset,
.can_attach = mem_cgroup_can_attach,
@@ -5511,11 +5544,11 @@ void mem_cgroup_uncharge_list(struct list_head *page_list)
* mem_cgroup_replace_page - migrate a charge to another page
* @oldpage: currently charged page
* @newpage: page to transfer the charge to
- * @lrucare: either or both pages might be on the LRU already
*
* Migrate the charge from @oldpage to @newpage.
*
* Both pages must be locked, @newpage->mapping must be set up.
+ * Either or both pages might be on the LRU already.
*/
void mem_cgroup_replace_page(struct page *oldpage, struct page *newpage)
{
diff --git a/mm/memory.c b/mm/memory.c
index deb679c..c387430 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -3015,9 +3015,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
} else {
/*
* The fault handler has no page to lock, so it holds
- * i_mmap_lock for write to protect against truncate.
+ * i_mmap_lock for read to protect against truncate.
*/
- i_mmap_unlock_write(vma->vm_file->f_mapping);
+ i_mmap_unlock_read(vma->vm_file->f_mapping);
}
goto uncharge_out;
}
@@ -3031,9 +3031,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
} else {
/*
* The fault handler has no page to lock, so it holds
- * i_mmap_lock for write to protect against truncate.
+ * i_mmap_lock for read to protect against truncate.
*/
- i_mmap_unlock_write(vma->vm_file->f_mapping);
+ i_mmap_unlock_read(vma->vm_file->f_mapping);
}
return ret;
uncharge_out:
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 67d488a..a042a9d 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1375,23 +1375,30 @@ int is_mem_section_removable(unsigned long start_pfn, unsigned long nr_pages)
*/
int test_pages_in_a_zone(unsigned long start_pfn, unsigned long end_pfn)
{
- unsigned long pfn;
+ unsigned long pfn, sec_end_pfn;
struct zone *zone = NULL;
struct page *page;
int i;
- for (pfn = start_pfn;
+ for (pfn = start_pfn, sec_end_pfn = SECTION_ALIGN_UP(start_pfn);
pfn < end_pfn;
- pfn += MAX_ORDER_NR_PAGES) {
- i = 0;
- /* This is just a CONFIG_HOLES_IN_ZONE check.*/
- while ((i < MAX_ORDER_NR_PAGES) && !pfn_valid_within(pfn + i))
- i++;
- if (i == MAX_ORDER_NR_PAGES)
+ pfn = sec_end_pfn + 1, sec_end_pfn += PAGES_PER_SECTION) {
+ /* Make sure the memory section is present first */
+ if (!present_section_nr(pfn_to_section_nr(pfn)))
continue;
- page = pfn_to_page(pfn + i);
- if (zone && page_zone(page) != zone)
- return 0;
- zone = page_zone(page);
+ for (; pfn < sec_end_pfn && pfn < end_pfn;
+ pfn += MAX_ORDER_NR_PAGES) {
+ i = 0;
+ /* This is just a CONFIG_HOLES_IN_ZONE check.*/
+ while ((i < MAX_ORDER_NR_PAGES) &&
+ !pfn_valid_within(pfn + i))
+ i++;
+ if (i == MAX_ORDER_NR_PAGES)
+ continue;
+ page = pfn_to_page(pfn + i);
+ if (zone && page_zone(page) != zone)
+ return 0;
+ zone = page_zone(page);
+ }
}
return 1;
}
diff --git a/mm/mremap.c b/mm/mremap.c
index c25bc62..de824e7 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -319,6 +319,10 @@ static unsigned long move_vma(struct vm_area_struct *vma,
hiwater_vm = mm->hiwater_vm;
vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT);
+ /* Tell pfnmap has moved from this vma */
+ if (unlikely(vma->vm_flags & VM_PFNMAP))
+ untrack_pfn_moved(vma);
+
if (do_munmap(mm, old_addr, old_len) < 0) {
/* OOM: unable to split vma, just get accounts right */
vm_unacct_memory(excess >> PAGE_SHIFT);
diff --git a/mm/nobootmem.c b/mm/nobootmem.c
index e57cf24..99feb2b 100644
--- a/mm/nobootmem.c
+++ b/mm/nobootmem.c
@@ -31,6 +31,7 @@ EXPORT_SYMBOL(contig_page_data);
unsigned long max_low_pfn;
unsigned long min_low_pfn;
unsigned long max_pfn;
+unsigned long long max_possible_pfn;
static void * __init __alloc_memory_core_early(int nid, u64 size, u64 align,
u64 goal, u64 limit)
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index d13a339..c126809 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -608,6 +608,8 @@ void oom_kill_process(struct oom_control *oc, struct task_struct *p,
continue;
if (unlikely(p->flags & PF_KTHREAD))
continue;
+ if (is_global_init(p))
+ continue;
if (p->signal->oom_score_adj == OOM_SCORE_ADJ_MIN)
continue;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 2c90357..d15d88c 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2,7 +2,7 @@
* mm/page-writeback.c
*
* Copyright (C) 2002, Linus Torvalds.
- * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra <pzijlstr@redhat.com>
+ * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra
*
* Contains functions related to writing back dirty pages at the
* address_space level.
@@ -1542,7 +1542,9 @@ static void balance_dirty_pages(struct address_space *mapping,
for (;;) {
unsigned long now = jiffies;
unsigned long dirty, thresh, bg_thresh;
- unsigned long m_dirty, m_thresh, m_bg_thresh;
+ unsigned long m_dirty = 0; /* stop bogus uninit warnings */
+ unsigned long m_thresh = 0;
+ unsigned long m_bg_thresh = 0;
/*
* Unstable writes are a feature of certain networked
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 208e4c7..9d666df 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3647,8 +3647,9 @@ static void show_migration_types(unsigned char type)
{
static const char types[MIGRATE_TYPES] = {
[MIGRATE_UNMOVABLE] = 'U',
- [MIGRATE_RECLAIMABLE] = 'E',
[MIGRATE_MOVABLE] = 'M',
+ [MIGRATE_RECLAIMABLE] = 'E',
+ [MIGRATE_HIGHATOMIC] = 'H',
#ifdef CONFIG_CMA
[MIGRATE_CMA] = 'C',
#endif
@@ -5266,6 +5267,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat)
static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
{
+ unsigned long __maybe_unused start = 0;
unsigned long __maybe_unused offset = 0;
/* Skip empty nodes */
@@ -5273,9 +5275,11 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
return;
#ifdef CONFIG_FLAT_NODE_MEM_MAP
+ start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
+ offset = pgdat->node_start_pfn - start;
/* ia64 gets its own node_mem_map, before this, without bootmem */
if (!pgdat->node_mem_map) {
- unsigned long size, start, end;
+ unsigned long size, end;
struct page *map;
/*
@@ -5283,8 +5287,6 @@ static void __init_refok alloc_node_mem_map(struct pglist_data *pgdat)
* aligned but the node_mem_map endpoints must be in order
* for the buddy allocator to function correctly.
*/
- start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1);
- offset = pgdat->node_start_pfn - start;
end = pgdat_end_pfn(pgdat);
end = ALIGN(end, MAX_ORDER_NR_PAGES);
size = (end - start) * sizeof(struct page);
diff --git a/mm/shmem.c b/mm/shmem.c
index 9187eee..5813b7f 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -843,14 +843,14 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
list_add_tail(&info->swaplist, &shmem_swaplist);
if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) {
- swap_shmem_alloc(swap);
- shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
-
spin_lock(&info->lock);
- info->swapped++;
shmem_recalc_inode(inode);
+ info->swapped++;
spin_unlock(&info->lock);
+ swap_shmem_alloc(swap);
+ shmem_delete_from_page_cache(page, swp_to_radix_entry(swap));
+
mutex_unlock(&shmem_swaplist_mutex);
BUG_ON(page_mapped(page));
swap_writepage(page, wbc);
@@ -1078,7 +1078,7 @@ repeat:
if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
error = -EINVAL;
- goto failed;
+ goto unlock;
}
if (page && sgp == SGP_WRITE)
@@ -1246,11 +1246,15 @@ clear:
/* Perhaps the file has been truncated since we checked */
if (sgp != SGP_WRITE && sgp != SGP_FALLOC &&
((loff_t)index << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
+ if (alloced) {
+ ClearPageDirty(page);
+ delete_from_page_cache(page);
+ spin_lock(&info->lock);
+ shmem_recalc_inode(inode);
+ spin_unlock(&info->lock);
+ }
error = -EINVAL;
- if (alloced)
- goto trunc;
- else
- goto failed;
+ goto unlock;
}
*pagep = page;
return 0;
@@ -1258,23 +1262,13 @@ clear:
/*
* Error recovery.
*/
-trunc:
- info = SHMEM_I(inode);
- ClearPageDirty(page);
- delete_from_page_cache(page);
- spin_lock(&info->lock);
- info->alloced--;
- inode->i_blocks -= BLOCKS_PER_PAGE;
- spin_unlock(&info->lock);
decused:
- sbinfo = SHMEM_SB(inode->i_sb);
if (sbinfo->max_blocks)
percpu_counter_add(&sbinfo->used_blocks, -1);
unacct:
shmem_unacct_blocks(info->flags, 1);
failed:
- if (swap.val && error != -EINVAL &&
- !shmem_confirm_swap(mapping, index, swap))
+ if (swap.val && !shmem_confirm_swap(mapping, index, swap))
error = -EEXIST;
unlock:
if (page) {
@@ -2444,7 +2438,6 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
int len;
struct inode *inode;
struct page *page;
- char *kaddr;
struct shmem_inode_info *info;
len = strlen(symname) + 1;
@@ -2483,9 +2476,8 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
}
inode->i_mapping->a_ops = &shmem_aops;
inode->i_op = &shmem_symlink_inode_operations;
- kaddr = kmap_atomic(page);
- memcpy(kaddr, symname, len);
- kunmap_atomic(kaddr);
+ inode_nohighmem(inode);
+ memcpy(page_address(page), symname, len);
SetPageUptodate(page);
set_page_dirty(page);
unlock_page(page);
@@ -2498,23 +2490,34 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
return 0;
}
-static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
+static void shmem_put_link(void *arg)
{
- struct page *page = NULL;
- int error = shmem_getpage(d_inode(dentry), 0, &page, SGP_READ, NULL);
- if (error)
- return ERR_PTR(error);
- unlock_page(page);
- *cookie = page;
- return kmap(page);
+ mark_page_accessed(arg);
+ put_page(arg);
}
-static void shmem_put_link(struct inode *unused, void *cookie)
+static const char *shmem_get_link(struct dentry *dentry,
+ struct inode *inode,
+ struct delayed_call *done)
{
- struct page *page = cookie;
- kunmap(page);
- mark_page_accessed(page);
- page_cache_release(page);
+ struct page *page = NULL;
+ int error;
+ if (!dentry) {
+ page = find_get_page(inode->i_mapping, 0);
+ if (!page)
+ return ERR_PTR(-ECHILD);
+ if (!PageUptodate(page)) {
+ put_page(page);
+ return ERR_PTR(-ECHILD);
+ }
+ } else {
+ error = shmem_getpage(inode, 0, &page, SGP_READ, NULL);
+ if (error)
+ return ERR_PTR(error);
+ unlock_page(page);
+ }
+ set_delayed_call(done, shmem_put_link, page);
+ return page_address(page);
}
#ifdef CONFIG_TMPFS_XATTR
@@ -2561,122 +2564,74 @@ static int shmem_initxattrs(struct inode *inode,
return 0;
}
-static const struct xattr_handler *shmem_xattr_handlers[] = {
-#ifdef CONFIG_TMPFS_POSIX_ACL
- &posix_acl_access_xattr_handler,
- &posix_acl_default_xattr_handler,
-#endif
- NULL
-};
-
-static int shmem_xattr_validate(const char *name)
-{
- struct { const char *prefix; size_t len; } arr[] = {
- { XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN },
- { XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN }
- };
- int i;
-
- for (i = 0; i < ARRAY_SIZE(arr); i++) {
- size_t preflen = arr[i].len;
- if (strncmp(name, arr[i].prefix, preflen) == 0) {
- if (!name[preflen])
- return -EINVAL;
- return 0;
- }
- }
- return -EOPNOTSUPP;
-}
-
-static ssize_t shmem_getxattr(struct dentry *dentry, const char *name,
- void *buffer, size_t size)
+static int shmem_xattr_handler_get(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
{
struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- int err;
-
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_getxattr(dentry, name, buffer, size);
-
- err = shmem_xattr_validate(name);
- if (err)
- return err;
+ name = xattr_full_name(handler, name);
return simple_xattr_get(&info->xattrs, name, buffer, size);
}
-static int shmem_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags)
+static int shmem_xattr_handler_set(const struct xattr_handler *handler,
+ struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- int err;
-
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_setxattr(dentry, name, value, size, flags);
-
- err = shmem_xattr_validate(name);
- if (err)
- return err;
+ name = xattr_full_name(handler, name);
return simple_xattr_set(&info->xattrs, name, value, size, flags);
}
-static int shmem_removexattr(struct dentry *dentry, const char *name)
-{
- struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- int err;
-
- /*
- * If this is a request for a synthetic attribute in the system.*
- * namespace use the generic infrastructure to resolve a handler
- * for it via sb->s_xattr.
- */
- if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return generic_removexattr(dentry, name);
+static const struct xattr_handler shmem_security_xattr_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .get = shmem_xattr_handler_get,
+ .set = shmem_xattr_handler_set,
+};
- err = shmem_xattr_validate(name);
- if (err)
- return err;
+static const struct xattr_handler shmem_trusted_xattr_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .get = shmem_xattr_handler_get,
+ .set = shmem_xattr_handler_set,
+};
- return simple_xattr_remove(&info->xattrs, name);
-}
+static const struct xattr_handler *shmem_xattr_handlers[] = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ &posix_acl_access_xattr_handler,
+ &posix_acl_default_xattr_handler,
+#endif
+ &shmem_security_xattr_handler,
+ &shmem_trusted_xattr_handler,
+ NULL
+};
static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- return simple_xattr_list(&info->xattrs, buffer, size);
+ return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size);
}
#endif /* CONFIG_TMPFS_XATTR */
static const struct inode_operations shmem_short_symlink_operations = {
.readlink = generic_readlink,
- .follow_link = simple_follow_link,
+ .get_link = simple_get_link,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = shmem_setxattr,
- .getxattr = shmem_getxattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = shmem_removexattr,
+ .removexattr = generic_removexattr,
#endif
};
static const struct inode_operations shmem_symlink_inode_operations = {
.readlink = generic_readlink,
- .follow_link = shmem_follow_link,
- .put_link = shmem_put_link,
+ .get_link = shmem_get_link,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = shmem_setxattr,
- .getxattr = shmem_getxattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = shmem_removexattr,
+ .removexattr = generic_removexattr,
#endif
};
@@ -3148,10 +3103,10 @@ static const struct inode_operations shmem_inode_operations = {
.getattr = shmem_getattr,
.setattr = shmem_setattr,
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = shmem_setxattr,
- .getxattr = shmem_getxattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = shmem_removexattr,
+ .removexattr = generic_removexattr,
.set_acl = simple_set_acl,
#endif
};
@@ -3170,10 +3125,10 @@ static const struct inode_operations shmem_dir_inode_operations = {
.tmpfile = shmem_tmpfile,
#endif
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = shmem_setxattr,
- .getxattr = shmem_getxattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = shmem_removexattr,
+ .removexattr = generic_removexattr,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_setattr,
@@ -3183,10 +3138,10 @@ static const struct inode_operations shmem_dir_inode_operations = {
static const struct inode_operations shmem_special_inode_operations = {
#ifdef CONFIG_TMPFS_XATTR
- .setxattr = shmem_setxattr,
- .getxattr = shmem_getxattr,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
.listxattr = shmem_listxattr,
- .removexattr = shmem_removexattr,
+ .removexattr = generic_removexattr,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_setattr,
diff --git a/mm/slab.c b/mm/slab.c
index e0819fa..4765c97 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3419,7 +3419,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
}
EXPORT_SYMBOL(kmem_cache_free_bulk);
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
void **p)
{
return __kmem_cache_alloc_bulk(s, flags, size, p);
diff --git a/mm/slab.h b/mm/slab.h
index 27492eb..7b60871 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -170,7 +170,7 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
* may be allocated or freed using these operations.
*/
void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **);
-bool __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
+int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **);
#ifdef CONFIG_MEMCG_KMEM
/*
diff --git a/mm/slab_common.c b/mm/slab_common.c
index d88e97c..3c6a86b 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -112,7 +112,7 @@ void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p)
kmem_cache_free(s, p[i]);
}
-bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
+int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
void **p)
{
size_t i;
@@ -121,10 +121,10 @@ bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr,
void *x = p[i] = kmem_cache_alloc(s, flags);
if (!x) {
__kmem_cache_free_bulk(s, i, p);
- return false;
+ return 0;
}
}
- return true;
+ return i;
}
#ifdef CONFIG_MEMCG_KMEM
diff --git a/mm/slob.c b/mm/slob.c
index 0d7e5df..17e8f8c 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -617,7 +617,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
}
EXPORT_SYMBOL(kmem_cache_free_bulk);
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
void **p)
{
return __kmem_cache_alloc_bulk(s, flags, size, p);
diff --git a/mm/slub.c b/mm/slub.c
index 7cb4bf9..4699751 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -1065,11 +1065,15 @@ bad:
return 0;
}
+/* Supports checking bulk free of a constructed freelist */
static noinline struct kmem_cache_node *free_debug_processing(
- struct kmem_cache *s, struct page *page, void *object,
+ struct kmem_cache *s, struct page *page,
+ void *head, void *tail, int bulk_cnt,
unsigned long addr, unsigned long *flags)
{
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
+ void *object = head;
+ int cnt = 0;
spin_lock_irqsave(&n->list_lock, *flags);
slab_lock(page);
@@ -1077,6 +1081,9 @@ static noinline struct kmem_cache_node *free_debug_processing(
if (!check_slab(s, page))
goto fail;
+next_object:
+ cnt++;
+
if (!check_valid_pointer(s, page, object)) {
slab_err(s, page, "Invalid object pointer 0x%p", object);
goto fail;
@@ -1107,8 +1114,19 @@ static noinline struct kmem_cache_node *free_debug_processing(
if (s->flags & SLAB_STORE_USER)
set_track(s, object, TRACK_FREE, addr);
trace(s, page, object, 0);
+ /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */
init_object(s, object, SLUB_RED_INACTIVE);
+
+ /* Reached end of constructed freelist yet? */
+ if (object != tail) {
+ object = get_freepointer(s, object);
+ goto next_object;
+ }
out:
+ if (cnt != bulk_cnt)
+ slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n",
+ bulk_cnt, cnt);
+
slab_unlock(page);
/*
* Keep node_lock to preserve integrity
@@ -1204,7 +1222,7 @@ unsigned long kmem_cache_flags(unsigned long object_size,
return flags;
}
-#else
+#else /* !CONFIG_SLUB_DEBUG */
static inline void setup_object_debug(struct kmem_cache *s,
struct page *page, void *object) {}
@@ -1212,7 +1230,8 @@ static inline int alloc_debug_processing(struct kmem_cache *s,
struct page *page, void *object, unsigned long addr) { return 0; }
static inline struct kmem_cache_node *free_debug_processing(
- struct kmem_cache *s, struct page *page, void *object,
+ struct kmem_cache *s, struct page *page,
+ void *head, void *tail, int bulk_cnt,
unsigned long addr, unsigned long *flags) { return NULL; }
static inline int slab_pad_check(struct kmem_cache *s, struct page *page)
@@ -1273,14 +1292,21 @@ static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s,
return memcg_kmem_get_cache(s, flags);
}
-static inline void slab_post_alloc_hook(struct kmem_cache *s,
- gfp_t flags, void *object)
+static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags,
+ size_t size, void **p)
{
+ size_t i;
+
flags &= gfp_allowed_mask;
- kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
- kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags);
+ for (i = 0; i < size; i++) {
+ void *object = p[i];
+
+ kmemcheck_slab_alloc(s, flags, object, slab_ksize(s));
+ kmemleak_alloc_recursive(object, s->object_size, 1,
+ s->flags, flags);
+ kasan_slab_alloc(s, object);
+ }
memcg_kmem_put_cache(s);
- kasan_slab_alloc(s, object);
}
static inline void slab_free_hook(struct kmem_cache *s, void *x)
@@ -1308,6 +1334,29 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x)
kasan_slab_free(s, x);
}
+static inline void slab_free_freelist_hook(struct kmem_cache *s,
+ void *head, void *tail)
+{
+/*
+ * Compiler cannot detect this function can be removed if slab_free_hook()
+ * evaluates to nothing. Thus, catch all relevant config debug options here.
+ */
+#if defined(CONFIG_KMEMCHECK) || \
+ defined(CONFIG_LOCKDEP) || \
+ defined(CONFIG_DEBUG_KMEMLEAK) || \
+ defined(CONFIG_DEBUG_OBJECTS_FREE) || \
+ defined(CONFIG_KASAN)
+
+ void *object = head;
+ void *tail_obj = tail ? : head;
+
+ do {
+ slab_free_hook(s, object);
+ } while ((object != tail_obj) &&
+ (object = get_freepointer(s, object)));
+#endif
+}
+
static void setup_object(struct kmem_cache *s, struct page *page,
void *object)
{
@@ -2295,23 +2344,15 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
* And if we were unable to get a new slab from the partial slab lists then
* we need to allocate a new slab. This is the slowest path since it involves
* a call to the page allocator and the setup of a new slab.
+ *
+ * Version of __slab_alloc to use when we know that interrupts are
+ * already disabled (which is the case for bulk allocation).
*/
-static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
unsigned long addr, struct kmem_cache_cpu *c)
{
void *freelist;
struct page *page;
- unsigned long flags;
-
- local_irq_save(flags);
-#ifdef CONFIG_PREEMPT
- /*
- * We may have been preempted and rescheduled on a different
- * cpu before disabling interrupts. Need to reload cpu area
- * pointer.
- */
- c = this_cpu_ptr(s->cpu_slab);
-#endif
page = c->page;
if (!page)
@@ -2369,7 +2410,6 @@ load_freelist:
VM_BUG_ON(!c->page->frozen);
c->freelist = get_freepointer(s, freelist);
c->tid = next_tid(c->tid);
- local_irq_restore(flags);
return freelist;
new_slab:
@@ -2386,7 +2426,6 @@ new_slab:
if (unlikely(!freelist)) {
slab_out_of_memory(s, gfpflags, node);
- local_irq_restore(flags);
return NULL;
}
@@ -2402,11 +2441,35 @@ new_slab:
deactivate_slab(s, page, get_freepointer(s, freelist));
c->page = NULL;
c->freelist = NULL;
- local_irq_restore(flags);
return freelist;
}
/*
+ * Another one that disabled interrupt and compensates for possible
+ * cpu changes by refetching the per cpu area pointer.
+ */
+static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
+ unsigned long addr, struct kmem_cache_cpu *c)
+{
+ void *p;
+ unsigned long flags;
+
+ local_irq_save(flags);
+#ifdef CONFIG_PREEMPT
+ /*
+ * We may have been preempted and rescheduled on a different
+ * cpu before disabling interrupts. Need to reload cpu area
+ * pointer.
+ */
+ c = this_cpu_ptr(s->cpu_slab);
+#endif
+
+ p = ___slab_alloc(s, gfpflags, node, addr, c);
+ local_irq_restore(flags);
+ return p;
+}
+
+/*
* Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc)
* have the fastpath folded into their functions. So no function call
* overhead for requests that can be satisfied on the fastpath.
@@ -2419,7 +2482,7 @@ new_slab:
static __always_inline void *slab_alloc_node(struct kmem_cache *s,
gfp_t gfpflags, int node, unsigned long addr)
{
- void **object;
+ void *object;
struct kmem_cache_cpu *c;
struct page *page;
unsigned long tid;
@@ -2498,7 +2561,7 @@ redo:
if (unlikely(gfpflags & __GFP_ZERO) && object)
memset(object, 0, s->object_size);
- slab_post_alloc_hook(s, gfpflags, object);
+ slab_post_alloc_hook(s, gfpflags, 1, &object);
return object;
}
@@ -2569,10 +2632,11 @@ EXPORT_SYMBOL(kmem_cache_alloc_node_trace);
* handling required then we can return immediately.
*/
static void __slab_free(struct kmem_cache *s, struct page *page,
- void *x, unsigned long addr)
+ void *head, void *tail, int cnt,
+ unsigned long addr)
+
{
void *prior;
- void **object = (void *)x;
int was_frozen;
struct page new;
unsigned long counters;
@@ -2582,7 +2646,8 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
stat(s, FREE_SLOWPATH);
if (kmem_cache_debug(s) &&
- !(n = free_debug_processing(s, page, x, addr, &flags)))
+ !(n = free_debug_processing(s, page, head, tail, cnt,
+ addr, &flags)))
return;
do {
@@ -2592,10 +2657,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
}
prior = page->freelist;
counters = page->counters;
- set_freepointer(s, object, prior);
+ set_freepointer(s, tail, prior);
new.counters = counters;
was_frozen = new.frozen;
- new.inuse--;
+ new.inuse -= cnt;
if ((!new.inuse || !prior) && !was_frozen) {
if (kmem_cache_has_cpu_partial(s) && !prior) {
@@ -2626,7 +2691,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
} while (!cmpxchg_double_slab(s, page,
prior, counters,
- object, new.counters,
+ head, new.counters,
"__slab_free"));
if (likely(!n)) {
@@ -2691,15 +2756,20 @@ slab_empty:
*
* If fastpath is not possible then fall back to __slab_free where we deal
* with all sorts of special processing.
+ *
+ * Bulk free of a freelist with several objects (all pointing to the
+ * same page) possible by specifying head and tail ptr, plus objects
+ * count (cnt). Bulk free indicated by tail pointer being set.
*/
-static __always_inline void slab_free(struct kmem_cache *s,
- struct page *page, void *x, unsigned long addr)
+static __always_inline void slab_free(struct kmem_cache *s, struct page *page,
+ void *head, void *tail, int cnt,
+ unsigned long addr)
{
- void **object = (void *)x;
+ void *tail_obj = tail ? : head;
struct kmem_cache_cpu *c;
unsigned long tid;
- slab_free_hook(s, x);
+ slab_free_freelist_hook(s, head, tail);
redo:
/*
@@ -2718,19 +2788,19 @@ redo:
barrier();
if (likely(page == c->page)) {
- set_freepointer(s, object, c->freelist);
+ set_freepointer(s, tail_obj, c->freelist);
if (unlikely(!this_cpu_cmpxchg_double(
s->cpu_slab->freelist, s->cpu_slab->tid,
c->freelist, tid,
- object, next_tid(tid)))) {
+ head, next_tid(tid)))) {
note_cmpxchg_failure("slab_free", s, tid);
goto redo;
}
stat(s, FREE_FASTPATH);
} else
- __slab_free(s, page, x, addr);
+ __slab_free(s, page, head, tail_obj, cnt, addr);
}
@@ -2739,59 +2809,116 @@ void kmem_cache_free(struct kmem_cache *s, void *x)
s = cache_from_obj(s, x);
if (!s)
return;
- slab_free(s, virt_to_head_page(x), x, _RET_IP_);
+ slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_);
trace_kmem_cache_free(_RET_IP_, x);
}
EXPORT_SYMBOL(kmem_cache_free);
-/* Note that interrupts must be enabled when calling this function. */
-void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p)
-{
- struct kmem_cache_cpu *c;
+struct detached_freelist {
struct page *page;
- int i;
+ void *tail;
+ void *freelist;
+ int cnt;
+};
- local_irq_disable();
- c = this_cpu_ptr(s->cpu_slab);
+/*
+ * This function progressively scans the array with free objects (with
+ * a limited look ahead) and extract objects belonging to the same
+ * page. It builds a detached freelist directly within the given
+ * page/objects. This can happen without any need for
+ * synchronization, because the objects are owned by running process.
+ * The freelist is build up as a single linked list in the objects.
+ * The idea is, that this detached freelist can then be bulk
+ * transferred to the real freelist(s), but only requiring a single
+ * synchronization primitive. Look ahead in the array is limited due
+ * to performance reasons.
+ */
+static int build_detached_freelist(struct kmem_cache *s, size_t size,
+ void **p, struct detached_freelist *df)
+{
+ size_t first_skipped_index = 0;
+ int lookahead = 3;
+ void *object;
- for (i = 0; i < size; i++) {
- void *object = p[i];
+ /* Always re-init detached_freelist */
+ df->page = NULL;
- BUG_ON(!object);
- /* kmem cache debug support */
- s = cache_from_obj(s, object);
- if (unlikely(!s))
- goto exit;
- slab_free_hook(s, object);
+ do {
+ object = p[--size];
+ } while (!object && size);
- page = virt_to_head_page(object);
+ if (!object)
+ return 0;
- if (c->page == page) {
- /* Fastpath: local CPU free */
- set_freepointer(s, object, c->freelist);
- c->freelist = object;
- } else {
- c->tid = next_tid(c->tid);
- local_irq_enable();
- /* Slowpath: overhead locked cmpxchg_double_slab */
- __slab_free(s, page, object, _RET_IP_);
- local_irq_disable();
- c = this_cpu_ptr(s->cpu_slab);
+ /* Start new detached freelist */
+ set_freepointer(s, object, NULL);
+ df->page = virt_to_head_page(object);
+ df->tail = object;
+ df->freelist = object;
+ p[size] = NULL; /* mark object processed */
+ df->cnt = 1;
+
+ while (size) {
+ object = p[--size];
+ if (!object)
+ continue; /* Skip processed objects */
+
+ /* df->page is always set at this point */
+ if (df->page == virt_to_head_page(object)) {
+ /* Opportunity build freelist */
+ set_freepointer(s, object, df->freelist);
+ df->freelist = object;
+ df->cnt++;
+ p[size] = NULL; /* mark object processed */
+
+ continue;
}
+
+ /* Limit look ahead search */
+ if (!--lookahead)
+ break;
+
+ if (!first_skipped_index)
+ first_skipped_index = size + 1;
}
-exit:
- c->tid = next_tid(c->tid);
- local_irq_enable();
+
+ return first_skipped_index;
+}
+
+
+/* Note that interrupts must be enabled when calling this function. */
+void kmem_cache_free_bulk(struct kmem_cache *orig_s, size_t size, void **p)
+{
+ if (WARN_ON(!size))
+ return;
+
+ do {
+ struct detached_freelist df;
+ struct kmem_cache *s;
+
+ /* Support for memcg */
+ s = cache_from_obj(orig_s, p[size - 1]);
+
+ size = build_detached_freelist(s, size, p, &df);
+ if (unlikely(!df.page))
+ continue;
+
+ slab_free(s, df.page, df.freelist, df.tail, df.cnt, _RET_IP_);
+ } while (likely(size));
}
EXPORT_SYMBOL(kmem_cache_free_bulk);
/* Note that interrupts must be enabled when calling this function. */
-bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
- void **p)
+int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
+ void **p)
{
struct kmem_cache_cpu *c;
int i;
+ /* memcg and kmem_cache debug support */
+ s = slab_pre_alloc_hook(s, flags);
+ if (unlikely(!s))
+ return false;
/*
* Drain objects in the per cpu slab, while disabling local
* IRQs, which protects against PREEMPT and interrupts
@@ -2804,36 +2931,20 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
void *object = c->freelist;
if (unlikely(!object)) {
- local_irq_enable();
/*
* Invoking slow path likely have side-effect
* of re-populating per CPU c->freelist
*/
- p[i] = __slab_alloc(s, flags, NUMA_NO_NODE,
+ p[i] = ___slab_alloc(s, flags, NUMA_NO_NODE,
_RET_IP_, c);
- if (unlikely(!p[i])) {
- __kmem_cache_free_bulk(s, i, p);
- return false;
- }
- local_irq_disable();
+ if (unlikely(!p[i]))
+ goto error;
+
c = this_cpu_ptr(s->cpu_slab);
continue; /* goto for-loop */
}
-
- /* kmem_cache debug support */
- s = slab_pre_alloc_hook(s, flags);
- if (unlikely(!s)) {
- __kmem_cache_free_bulk(s, i, p);
- c->tid = next_tid(c->tid);
- local_irq_enable();
- return false;
- }
-
c->freelist = get_freepointer(s, object);
p[i] = object;
-
- /* kmem_cache debug support */
- slab_post_alloc_hook(s, flags, object);
}
c->tid = next_tid(c->tid);
local_irq_enable();
@@ -2846,7 +2957,14 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size,
memset(p[j], 0, s->object_size);
}
- return true;
+ /* memcg and kmem_cache debug support */
+ slab_post_alloc_hook(s, flags, size, p);
+ return i;
+error:
+ local_irq_enable();
+ slab_post_alloc_hook(s, flags, i, p);
+ __kmem_cache_free_bulk(s, i, p);
+ return 0;
}
EXPORT_SYMBOL(kmem_cache_alloc_bulk);
@@ -3511,7 +3629,7 @@ void kfree(const void *x)
__free_kmem_pages(page, compound_order(page));
return;
}
- slab_free(page->slab_cache, page, object, _RET_IP_);
+ slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_);
}
EXPORT_SYMBOL(kfree);
diff --git a/mm/util.c b/mm/util.c
index 9af1c12..2d28f79 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -176,6 +176,37 @@ char *strndup_user(const char __user *s, long n)
}
EXPORT_SYMBOL(strndup_user);
+/**
+ * memdup_user_nul - duplicate memory region from user space and NUL-terminate
+ *
+ * @src: source address in user space
+ * @len: number of bytes to copy
+ *
+ * Returns an ERR_PTR() on failure.
+ */
+void *memdup_user_nul(const void __user *src, size_t len)
+{
+ char *p;
+
+ /*
+ * Always use GFP_KERNEL, since copy_from_user() can sleep and
+ * cause pagefault, which makes it pointless to use GFP_NOFS
+ * or GFP_ATOMIC.
+ */
+ p = kmalloc_track_caller(len + 1, GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(p, src, len)) {
+ kfree(p);
+ return ERR_PTR(-EFAULT);
+ }
+ p[len] = '\0';
+
+ return p;
+}
+EXPORT_SYMBOL(memdup_user_nul);
+
void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma,
struct vm_area_struct *prev, struct rb_node *rb_parent)
{
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index d045634..8e3c9c5 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1443,7 +1443,6 @@ struct vm_struct *remove_vm_area(const void *addr)
vmap_debug_free_range(va->va_start, va->va_end);
kasan_free_shadow(vm);
free_unmap_vmap_area(va);
- vm->size -= PAGE_SIZE;
return vm;
}
@@ -1468,8 +1467,8 @@ static void __vunmap(const void *addr, int deallocate_pages)
return;
}
- debug_check_no_locks_freed(addr, area->size);
- debug_check_no_obj_freed(addr, area->size);
+ debug_check_no_locks_freed(addr, get_vm_area_size(area));
+ debug_check_no_obj_freed(addr, get_vm_area_size(area));
if (deallocate_pages) {
int i;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 879a2be..c54fd29 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -219,7 +219,7 @@ void set_pgdat_percpu_threshold(pg_data_t *pgdat,
* particular counter cannot be updated from interrupt context.
*/
void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
- int delta)
+ long delta)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -318,8 +318,8 @@ EXPORT_SYMBOL(__dec_zone_page_state);
* 1 Overstepping half of threshold
* -1 Overstepping minus half of threshold
*/
-static inline void mod_state(struct zone *zone,
- enum zone_stat_item item, int delta, int overstep_mode)
+static inline void mod_state(struct zone *zone, enum zone_stat_item item,
+ long delta, int overstep_mode)
{
struct per_cpu_pageset __percpu *pcp = zone->pageset;
s8 __percpu *p = pcp->vm_stat_diff + item;
@@ -357,7 +357,7 @@ static inline void mod_state(struct zone *zone,
}
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
- int delta)
+ long delta)
{
mod_state(zone, item, delta, 0);
}
@@ -384,7 +384,7 @@ EXPORT_SYMBOL(dec_zone_page_state);
* Use interrupt disable to serialize counter updates
*/
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
- int delta)
+ long delta)
{
unsigned long flags;
@@ -921,8 +921,8 @@ static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat,
#ifdef CONFIG_PROC_FS
static char * const migratetype_names[MIGRATE_TYPES] = {
"Unmovable",
- "Reclaimable",
"Movable",
+ "Reclaimable",
"HighAtomic",
#ifdef CONFIG_CMA
"CMA",
@@ -1379,6 +1379,7 @@ static const struct file_operations proc_vmstat_file_operations = {
#endif /* CONFIG_PROC_FS */
#ifdef CONFIG_SMP
+static struct workqueue_struct *vmstat_wq;
static DEFINE_PER_CPU(struct delayed_work, vmstat_work);
int sysctl_stat_interval __read_mostly = HZ;
static cpumask_var_t cpu_stat_off;
@@ -1391,7 +1392,7 @@ static void vmstat_update(struct work_struct *w)
* to occur in the future. Keep on running the
* update worker thread.
*/
- schedule_delayed_work_on(smp_processor_id(),
+ queue_delayed_work_on(smp_processor_id(), vmstat_wq,
this_cpu_ptr(&vmstat_work),
round_jiffies_relative(sysctl_stat_interval));
} else {
@@ -1460,7 +1461,7 @@ static void vmstat_shepherd(struct work_struct *w)
if (need_update(cpu) &&
cpumask_test_and_clear_cpu(cpu, cpu_stat_off))
- schedule_delayed_work_on(cpu,
+ queue_delayed_work_on(cpu, vmstat_wq,
&per_cpu(vmstat_work, cpu), 0);
put_online_cpus();
@@ -1482,6 +1483,7 @@ static void __init start_shepherd_timer(void)
BUG();
cpumask_copy(cpu_stat_off, cpu_online_mask);
+ vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
schedule_delayed_work(&shepherd,
round_jiffies_relative(sysctl_stat_interval));
}
diff --git a/mm/zswap.c b/mm/zswap.c
index 025f8dc..bf14508 100644
--- a/mm/zswap.c
+++ b/mm/zswap.c
@@ -541,6 +541,7 @@ static struct zswap_pool *zswap_pool_last_get(void)
return last;
}
+/* type and compressor must be null-terminated */
static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
{
struct zswap_pool *pool;
@@ -548,10 +549,9 @@ static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor)
assert_spin_locked(&zswap_pools_lock);
list_for_each_entry_rcu(pool, &zswap_pools, list) {
- if (strncmp(pool->tfm_name, compressor, sizeof(pool->tfm_name)))
+ if (strcmp(pool->tfm_name, compressor))
continue;
- if (strncmp(zpool_get_type(pool->zpool), type,
- sizeof(zswap_zpool_type)))
+ if (strcmp(zpool_get_type(pool->zpool), type))
continue;
/* if we can't get it, it's about to be destroyed */
if (!zswap_pool_get(pool))
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 496b275..e2ed698 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -30,7 +30,9 @@ bool vlan_do_receive(struct sk_buff **skbp)
skb->pkt_type = PACKET_HOST;
}
- if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR)) {
+ if (!(vlan_dev_priv(vlan_dev)->flags & VLAN_FLAG_REORDER_HDR) &&
+ !netif_is_macvlan_port(vlan_dev) &&
+ !netif_is_bridge_port(vlan_dev)) {
unsigned int offset = skb->data - skb_mac_header(skb);
/*
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 6e70ddb..199bc76 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -105,7 +105,7 @@ static struct list_head virtio_chan_list;
/* How many bytes left in this page. */
static unsigned int rest_of_page(void *data)
{
- return PAGE_SIZE - ((unsigned long)data % PAGE_SIZE);
+ return PAGE_SIZE - offset_in_page(data);
}
/**
@@ -143,7 +143,6 @@ static void p9_virtio_close(struct p9_client *client)
static void req_done(struct virtqueue *vq)
{
struct virtio_chan *chan = vq->vdev->priv;
- struct p9_fcall *rc;
unsigned int len;
struct p9_req_t *req;
unsigned long flags;
@@ -152,8 +151,8 @@ static void req_done(struct virtqueue *vq)
while (1) {
spin_lock_irqsave(&chan->lock, flags);
- rc = virtqueue_get_buf(chan->vq, &len);
- if (rc == NULL) {
+ req = virtqueue_get_buf(chan->vq, &len);
+ if (req == NULL) {
spin_unlock_irqrestore(&chan->lock, flags);
break;
}
@@ -161,9 +160,6 @@ static void req_done(struct virtqueue *vq)
spin_unlock_irqrestore(&chan->lock, flags);
/* Wakeup if anyone waiting for VirtIO ring space. */
wake_up(chan->vc_wq);
- p9_debug(P9_DEBUG_TRANS, ": rc %p\n", rc);
- p9_debug(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
- req = p9_tag_lookup(chan->client, rc->tag);
p9_client_cb(chan->client, req, REQ_STATUS_RCVD);
}
}
@@ -284,7 +280,7 @@ req_retry:
if (in)
sgs[out_sgs + in_sgs++] = chan->sg + out;
- err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req->tc,
+ err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req,
GFP_ATOMIC);
if (err < 0) {
if (err == -ENOSPC) {
@@ -369,7 +365,7 @@ static int p9_get_mapped_pages(struct virtio_chan *chan,
return -ENOMEM;
*need_drop = 0;
- p -= (*offs = (unsigned long)p % PAGE_SIZE);
+ p -= (*offs = offset_in_page(p));
for (index = 0; index < nr_pages; index++) {
if (is_vmalloc_addr(p))
(*pages)[index] = vmalloc_to_page(p);
@@ -469,7 +465,7 @@ req_retry_pinned:
}
BUG_ON(out_sgs + in_sgs > ARRAY_SIZE(sgs));
- err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req->tc,
+ err = virtqueue_add_sgs(chan->vq, sgs, out_sgs, in_sgs, req,
GFP_ATOMIC);
if (err < 0) {
if (err == -ENOSPC) {
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index ae3a47f..fbd0acf 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -805,6 +805,9 @@ static int ax25_create(struct net *net, struct socket *sock, int protocol,
struct sock *sk;
ax25_cb *ax25;
+ if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+ return -EINVAL;
+
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c
index 83bc1aa..a49c705 100644
--- a/net/batman-adv/distributed-arp-table.c
+++ b/net/batman-adv/distributed-arp-table.c
@@ -566,6 +566,7 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
int select;
batadv_dat_addr_t last_max = BATADV_DAT_ADDR_MAX, ip_key;
struct batadv_dat_candidate *res;
+ struct batadv_dat_entry dat;
if (!bat_priv->orig_hash)
return NULL;
@@ -575,7 +576,9 @@ batadv_dat_select_candidates(struct batadv_priv *bat_priv, __be32 ip_dst)
if (!res)
return NULL;
- ip_key = (batadv_dat_addr_t)batadv_hash_dat(&ip_dst,
+ dat.ip = ip_dst;
+ dat.vid = 0;
+ ip_key = (batadv_dat_addr_t)batadv_hash_dat(&dat,
BATADV_DAT_ADDR_MAX);
batadv_dbg(BATADV_DBG_DAT, bat_priv,
diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c
index 8d990b0..3207667 100644
--- a/net/batman-adv/routing.c
+++ b/net/batman-adv/routing.c
@@ -836,6 +836,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
u8 *orig_addr;
struct batadv_orig_node *orig_node = NULL;
int check, hdr_size = sizeof(*unicast_packet);
+ enum batadv_subtype subtype;
bool is4addr;
unicast_packet = (struct batadv_unicast_packet *)skb->data;
@@ -863,10 +864,20 @@ int batadv_recv_unicast_packet(struct sk_buff *skb,
/* packet for me */
if (batadv_is_my_mac(bat_priv, unicast_packet->dest)) {
if (is4addr) {
- batadv_dat_inc_counter(bat_priv,
- unicast_4addr_packet->subtype);
- orig_addr = unicast_4addr_packet->src;
- orig_node = batadv_orig_hash_find(bat_priv, orig_addr);
+ subtype = unicast_4addr_packet->subtype;
+ batadv_dat_inc_counter(bat_priv, subtype);
+
+ /* Only payload data should be considered for speedy
+ * join. For example, DAT also uses unicast 4addr
+ * types, but those packets should not be considered
+ * for speedy join, since the clients do not actually
+ * reside at the sending originator.
+ */
+ if (subtype == BATADV_P_DATA) {
+ orig_addr = unicast_4addr_packet->src;
+ orig_node = batadv_orig_hash_find(bat_priv,
+ orig_addr);
+ }
}
if (batadv_dat_snoop_incoming_arp_request(bat_priv, skb,
diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c
index 4228b10..76f19ba 100644
--- a/net/batman-adv/translation-table.c
+++ b/net/batman-adv/translation-table.c
@@ -68,13 +68,15 @@ static void batadv_tt_global_del(struct batadv_priv *bat_priv,
unsigned short vid, const char *message,
bool roaming);
-/* returns 1 if they are the same mac addr */
+/* returns 1 if they are the same mac addr and vid */
static int batadv_compare_tt(const struct hlist_node *node, const void *data2)
{
const void *data1 = container_of(node, struct batadv_tt_common_entry,
hash_entry);
+ const struct batadv_tt_common_entry *tt1 = data1;
+ const struct batadv_tt_common_entry *tt2 = data2;
- return batadv_compare_eth(data1, data2);
+ return (tt1->vid == tt2->vid) && batadv_compare_eth(data1, data2);
}
/**
@@ -1427,9 +1429,15 @@ static bool batadv_tt_global_add(struct batadv_priv *bat_priv,
}
/* if the client was temporary added before receiving the first
- * OGM announcing it, we have to clear the TEMP flag
+ * OGM announcing it, we have to clear the TEMP flag. Also,
+ * remove the previous temporary orig node and re-add it
+ * if required. If the orig entry changed, the new one which
+ * is a non-temporary entry is preferred.
*/
- common->flags &= ~BATADV_TT_CLIENT_TEMP;
+ if (common->flags & BATADV_TT_CLIENT_TEMP) {
+ batadv_tt_global_del_orig_list(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
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index a3bffd1..70306cc 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -271,11 +271,11 @@ static long bt_sock_data_wait(struct sock *sk, long timeo)
if (signal_pending(current) || !timeo)
break;
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
}
__set_current_state(TASK_RUNNING);
@@ -441,7 +441,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock,
if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
return mask;
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 83a6aac..62edbf1 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -508,12 +508,6 @@ static void le_setup(struct hci_request *req)
/* Read LE Supported States */
hci_req_add(req, HCI_OP_LE_READ_SUPPORTED_STATES, 0, NULL);
- /* Read LE White List Size */
- hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE, 0, NULL);
-
- /* Clear LE White List */
- hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
-
/* LE-only controllers have LE implicitly enabled */
if (!lmp_bredr_capable(hdev))
hci_dev_set_flag(hdev, HCI_LE_ENABLED);
@@ -832,6 +826,17 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
hci_req_add(req, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
}
+ if (hdev->commands[26] & 0x40) {
+ /* Read LE White List Size */
+ hci_req_add(req, HCI_OP_LE_READ_WHITE_LIST_SIZE,
+ 0, NULL);
+ }
+
+ if (hdev->commands[26] & 0x80) {
+ /* Clear LE White List */
+ hci_req_add(req, HCI_OP_LE_CLEAR_WHITE_LIST, 0, NULL);
+ }
+
if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
/* Read LE Maximum Data Length */
hci_req_add(req, HCI_OP_LE_READ_MAX_DATA_LEN, 0, NULL);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7c65ee2..66e8b6e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -239,7 +239,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
else
dyn_end = L2CAP_CID_DYN_END;
- for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) {
+ for (cid = L2CAP_CID_DYN_START; cid <= dyn_end; cid++) {
if (!__l2cap_get_chan_by_scid(conn, cid))
return cid;
}
@@ -5250,7 +5250,9 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
credits = __le16_to_cpu(rsp->credits);
result = __le16_to_cpu(rsp->result);
- if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23))
+ if (result == L2CAP_CR_SUCCESS && (mtu < 23 || mps < 23 ||
+ dcid < L2CAP_CID_DYN_START ||
+ dcid > L2CAP_CID_LE_DYN_END))
return -EPROTO;
BT_DBG("dcid 0x%4.4x mtu %u mps %u credits %u result 0x%2.2x",
@@ -5270,6 +5272,11 @@ static int l2cap_le_connect_rsp(struct l2cap_conn *conn,
switch (result) {
case L2CAP_CR_SUCCESS:
+ if (__l2cap_get_chan_by_dcid(conn, dcid)) {
+ err = -EBADSLT;
+ break;
+ }
+
chan->ident = 0;
chan->dcid = dcid;
chan->omtu = mtu;
@@ -5437,9 +5444,16 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
goto response_unlock;
}
+ /* Check for valid dynamic CID range */
+ if (scid < L2CAP_CID_DYN_START || scid > L2CAP_CID_LE_DYN_END) {
+ result = L2CAP_CR_INVALID_SCID;
+ chan = NULL;
+ goto response_unlock;
+ }
+
/* Check if we already have channel with that dcid */
if (__l2cap_get_chan_by_dcid(conn, scid)) {
- result = L2CAP_CR_NO_MEM;
+ result = L2CAP_CR_SCID_IN_USE;
chan = NULL;
goto response_unlock;
}
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index fe12966..f52bcbf 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -526,6 +526,9 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
+ if (addr_len < sizeof(struct sockaddr_sco))
+ return -EINVAL;
+
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index c913538..ffed8a1 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -3027,8 +3027,13 @@ static void smp_ready_cb(struct l2cap_chan *chan)
BT_DBG("chan %p", chan);
+ /* No need to call l2cap_chan_hold() here since we already own
+ * the reference taken in smp_new_conn_cb(). This is just the
+ * first time that we tie it to a specific pointer. The code in
+ * l2cap_core.c ensures that there's no risk this function wont
+ * get called if smp_new_conn_cb was previously called.
+ */
conn->smp = chan;
- l2cap_chan_hold(chan);
if (hcon->type == ACL_LINK && test_bit(HCI_CONN_ENCRYPT, &hcon->flags))
bredr_pairing(chan);
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 80c34d7..5f3f645 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -48,7 +48,7 @@ void br_set_state(struct net_bridge_port *p, unsigned int state)
p->state = state;
err = switchdev_port_attr_set(p->dev, &attr);
- if (err)
+ if (err && err != -EOPNOTSUPP)
br_warn(p->br, "error setting offload STP state on port %u(%s)\n",
(unsigned int) p->port_no, p->dev->name);
}
@@ -600,12 +600,17 @@ void __br_set_forward_delay(struct net_bridge *br, unsigned long t)
int br_set_forward_delay(struct net_bridge *br, unsigned long val)
{
unsigned long t = clock_t_to_jiffies(val);
-
- if (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY)
- return -ERANGE;
+ int err = -ERANGE;
spin_lock_bh(&br->lock);
+ if (br->stp_enabled != BR_NO_STP &&
+ (t < BR_MIN_FORWARD_DELAY || t > BR_MAX_FORWARD_DELAY))
+ goto unlock;
+
__br_set_forward_delay(br, t);
+ err = 0;
+
+unlock:
spin_unlock_bh(&br->lock);
- return 0;
+ return err;
}
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index fa53d7a..8a7ada8 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -39,7 +39,7 @@ void br_init_port(struct net_bridge_port *p)
struct switchdev_attr attr = {
.id = SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME,
.flags = SWITCHDEV_F_SKIP_EOPNOTSUPP | SWITCHDEV_F_DEFER,
- .u.ageing_time = p->br->ageing_time,
+ .u.ageing_time = jiffies_to_clock_t(p->br->ageing_time),
};
int err;
@@ -50,7 +50,7 @@ void br_init_port(struct net_bridge_port *p)
p->config_pending = 0;
err = switchdev_port_attr_set(p->dev, &attr);
- if (err)
+ if (err && err != -EOPNOTSUPP)
netdev_err(p->dev, "failed to set HW ageing time\n");
}
@@ -142,7 +142,10 @@ static void br_stp_start(struct net_bridge *br)
char *envp[] = { NULL };
struct net_bridge_port *p;
- r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
+ if (net_eq(dev_net(br->dev), &init_net))
+ r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC);
+ else
+ r = -ENOENT;
spin_lock_bh(&br->lock);
diff --git a/net/caif/caif_socket.c b/net/caif/caif_socket.c
index cc85891..aa209b1 100644
--- a/net/caif/caif_socket.c
+++ b/net/caif/caif_socket.c
@@ -323,7 +323,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
!timeo)
break;
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
release_sock(sk);
timeo = schedule_timeout(timeo);
lock_sock(sk);
@@ -331,7 +331,7 @@ static long caif_stream_data_wait(struct sock *sk, long timeo)
if (sock_flag(sk, SOCK_DEAD))
break;
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
}
finish_wait(sk_sleep(sk), &wait);
diff --git a/net/ceph/auth_x.c b/net/ceph/auth_x.c
index ba6eb17..10d87753 100644
--- a/net/ceph/auth_x.c
+++ b/net/ceph/auth_x.c
@@ -8,6 +8,7 @@
#include <linux/ceph/decode.h>
#include <linux/ceph/auth.h>
+#include <linux/ceph/libceph.h>
#include <linux/ceph/messenger.h>
#include "crypto.h"
@@ -279,6 +280,15 @@ bad:
return -EINVAL;
}
+static void ceph_x_authorizer_cleanup(struct ceph_x_authorizer *au)
+{
+ ceph_crypto_key_destroy(&au->session_key);
+ if (au->buf) {
+ ceph_buffer_put(au->buf);
+ au->buf = NULL;
+ }
+}
+
static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
struct ceph_x_ticket_handler *th,
struct ceph_x_authorizer *au)
@@ -297,7 +307,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
ceph_crypto_key_destroy(&au->session_key);
ret = ceph_crypto_key_clone(&au->session_key, &th->session_key);
if (ret)
- return ret;
+ goto out_au;
maxlen = sizeof(*msg_a) + sizeof(msg_b) +
ceph_x_encrypt_buflen(ticket_blob_len);
@@ -309,8 +319,8 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
if (!au->buf) {
au->buf = ceph_buffer_new(maxlen, GFP_NOFS);
if (!au->buf) {
- ceph_crypto_key_destroy(&au->session_key);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_au;
}
}
au->service = th->service;
@@ -340,7 +350,7 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
ret = ceph_x_encrypt(&au->session_key, &msg_b, sizeof(msg_b),
p, end - p);
if (ret < 0)
- goto out_buf;
+ goto out_au;
p += ret;
au->buf->vec.iov_len = p - au->buf->vec.iov_base;
dout(" built authorizer nonce %llx len %d\n", au->nonce,
@@ -348,9 +358,8 @@ static int ceph_x_build_authorizer(struct ceph_auth_client *ac,
BUG_ON(au->buf->vec.iov_len > maxlen);
return 0;
-out_buf:
- ceph_buffer_put(au->buf);
- au->buf = NULL;
+out_au:
+ ceph_x_authorizer_cleanup(au);
return ret;
}
@@ -624,8 +633,7 @@ static void ceph_x_destroy_authorizer(struct ceph_auth_client *ac,
{
struct ceph_x_authorizer *au = (void *)a;
- ceph_crypto_key_destroy(&au->session_key);
- ceph_buffer_put(au->buf);
+ ceph_x_authorizer_cleanup(au);
kfree(au);
}
@@ -653,8 +661,7 @@ static void ceph_x_destroy(struct ceph_auth_client *ac)
remove_ticket_handler(ac, th);
}
- if (xi->auth_authorizer.buf)
- ceph_buffer_put(xi->auth_authorizer.buf);
+ ceph_x_authorizer_cleanup(&xi->auth_authorizer);
kfree(ac->private);
ac->private = NULL;
@@ -691,8 +698,10 @@ static int ceph_x_sign_message(struct ceph_auth_handshake *auth,
struct ceph_msg *msg)
{
int ret;
- if (!auth->authorizer)
+
+ if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
return 0;
+
ret = calcu_signature((struct ceph_x_authorizer *)auth->authorizer,
msg, &msg->footer.sig);
if (ret < 0)
@@ -707,8 +716,9 @@ static int ceph_x_check_message_signature(struct ceph_auth_handshake *auth,
__le64 sig_check;
int ret;
- if (!auth->authorizer)
+ if (ceph_test_opt(from_msgr(msg->con->msgr), NOMSGSIGN))
return 0;
+
ret = calcu_signature((struct ceph_x_authorizer *)auth->authorizer,
msg, &sig_check);
if (ret < 0)
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 78f098a..bcbec33 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -245,6 +245,8 @@ enum {
Opt_nocrc,
Opt_cephx_require_signatures,
Opt_nocephx_require_signatures,
+ Opt_cephx_sign_messages,
+ Opt_nocephx_sign_messages,
Opt_tcp_nodelay,
Opt_notcp_nodelay,
};
@@ -267,6 +269,8 @@ static match_table_t opt_tokens = {
{Opt_nocrc, "nocrc"},
{Opt_cephx_require_signatures, "cephx_require_signatures"},
{Opt_nocephx_require_signatures, "nocephx_require_signatures"},
+ {Opt_cephx_sign_messages, "cephx_sign_messages"},
+ {Opt_nocephx_sign_messages, "nocephx_sign_messages"},
{Opt_tcp_nodelay, "tcp_nodelay"},
{Opt_notcp_nodelay, "notcp_nodelay"},
{-1, NULL}
@@ -491,6 +495,12 @@ ceph_parse_options(char *options, const char *dev_name,
case Opt_nocephx_require_signatures:
opt->flags |= CEPH_OPT_NOMSGAUTH;
break;
+ case Opt_cephx_sign_messages:
+ opt->flags &= ~CEPH_OPT_NOMSGSIGN;
+ break;
+ case Opt_nocephx_sign_messages:
+ opt->flags |= CEPH_OPT_NOMSGSIGN;
+ break;
case Opt_tcp_nodelay:
opt->flags |= CEPH_OPT_TCP_NODELAY;
@@ -534,6 +544,8 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client)
seq_puts(m, "nocrc,");
if (opt->flags & CEPH_OPT_NOMSGAUTH)
seq_puts(m, "nocephx_require_signatures,");
+ if (opt->flags & CEPH_OPT_NOMSGSIGN)
+ seq_puts(m, "nocephx_sign_messages,");
if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0)
seq_puts(m, "notcp_nodelay,");
@@ -596,11 +608,7 @@ struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
if (ceph_test_opt(client, MYIP))
myaddr = &client->options->my_addr;
- ceph_messenger_init(&client->msgr, myaddr,
- client->supported_features,
- client->required_features,
- ceph_test_opt(client, NOCRC),
- ceph_test_opt(client, TCP_NODELAY));
+ ceph_messenger_init(&client->msgr, myaddr);
/* subsystems */
err = ceph_monc_init(&client->monc, client);
diff --git a/net/ceph/crypto.h b/net/ceph/crypto.h
index d149822..2e9cab0 100644
--- a/net/ceph/crypto.h
+++ b/net/ceph/crypto.h
@@ -16,8 +16,10 @@ struct ceph_crypto_key {
static inline void ceph_crypto_key_destroy(struct ceph_crypto_key *key)
{
- if (key)
+ if (key) {
kfree(key->key);
+ key->key = NULL;
+ }
}
int ceph_crypto_key_clone(struct ceph_crypto_key *dst,
diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
index b9b0e3b..9981039 100644
--- a/net/ceph/messenger.c
+++ b/net/ceph/messenger.c
@@ -509,7 +509,7 @@ static int ceph_tcp_connect(struct ceph_connection *con)
return ret;
}
- if (con->msgr->tcp_nodelay) {
+ if (ceph_test_opt(from_msgr(con->msgr), TCP_NODELAY)) {
int optval = 1;
ret = kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY,
@@ -637,9 +637,6 @@ static int con_close_socket(struct ceph_connection *con)
static void ceph_msg_remove(struct ceph_msg *msg)
{
list_del_init(&msg->list_head);
- BUG_ON(msg->con == NULL);
- msg->con->ops->put(msg->con);
- msg->con = NULL;
ceph_msg_put(msg);
}
@@ -662,15 +659,14 @@ static void reset_connection(struct ceph_connection *con)
if (con->in_msg) {
BUG_ON(con->in_msg->con != con);
- con->in_msg->con = NULL;
ceph_msg_put(con->in_msg);
con->in_msg = NULL;
- con->ops->put(con);
}
con->connect_seq = 0;
con->out_seq = 0;
if (con->out_msg) {
+ BUG_ON(con->out_msg->con != con);
ceph_msg_put(con->out_msg);
con->out_msg = NULL;
}
@@ -1205,7 +1201,7 @@ static void prepare_write_message_footer(struct ceph_connection *con)
con->out_kvec[v].iov_base = &m->footer;
if (con->peer_features & CEPH_FEATURE_MSG_AUTH) {
if (con->ops->sign_message)
- con->ops->sign_message(con, m);
+ con->ops->sign_message(m);
else
m->footer.sig = 0;
con->out_kvec[v].iov_len = sizeof(m->footer);
@@ -1432,7 +1428,8 @@ static int prepare_write_connect(struct ceph_connection *con)
dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con,
con->connect_seq, global_seq, proto);
- con->out_connect.features = cpu_to_le64(con->msgr->supported_features);
+ con->out_connect.features =
+ cpu_to_le64(from_msgr(con->msgr)->supported_features);
con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT);
con->out_connect.connect_seq = cpu_to_le32(con->connect_seq);
con->out_connect.global_seq = cpu_to_le32(global_seq);
@@ -1527,7 +1524,7 @@ static int write_partial_message_data(struct ceph_connection *con)
{
struct ceph_msg *msg = con->out_msg;
struct ceph_msg_data_cursor *cursor = &msg->cursor;
- bool do_datacrc = !con->msgr->nocrc;
+ bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
u32 crc;
dout("%s %p msg %p\n", __func__, con, msg);
@@ -1552,8 +1549,8 @@ static int write_partial_message_data(struct ceph_connection *con)
bool need_crc;
int ret;
- page = ceph_msg_data_next(&msg->cursor, &page_offset, &length,
- &last_piece);
+ page = ceph_msg_data_next(cursor, &page_offset, &length,
+ &last_piece);
ret = ceph_tcp_sendpage(con->sock, page, page_offset,
length, !last_piece);
if (ret <= 0) {
@@ -1564,7 +1561,7 @@ static int write_partial_message_data(struct ceph_connection *con)
}
if (do_datacrc && cursor->need_crc)
crc = ceph_crc32c_page(crc, page, page_offset, length);
- need_crc = ceph_msg_data_advance(&msg->cursor, (size_t)ret);
+ need_crc = ceph_msg_data_advance(cursor, (size_t)ret);
}
dout("%s %p msg %p done\n", __func__, con, msg);
@@ -2005,8 +2002,8 @@ static int process_banner(struct ceph_connection *con)
static int process_connect(struct ceph_connection *con)
{
- u64 sup_feat = con->msgr->supported_features;
- u64 req_feat = con->msgr->required_features;
+ u64 sup_feat = from_msgr(con->msgr)->supported_features;
+ u64 req_feat = from_msgr(con->msgr)->required_features;
u64 server_feat = ceph_sanitize_features(
le64_to_cpu(con->in_reply.features));
int ret;
@@ -2232,7 +2229,7 @@ static int read_partial_msg_data(struct ceph_connection *con)
{
struct ceph_msg *msg = con->in_msg;
struct ceph_msg_data_cursor *cursor = &msg->cursor;
- const bool do_datacrc = !con->msgr->nocrc;
+ bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
struct page *page;
size_t page_offset;
size_t length;
@@ -2246,8 +2243,7 @@ static int read_partial_msg_data(struct ceph_connection *con)
if (do_datacrc)
crc = con->in_data_crc;
while (cursor->resid) {
- page = ceph_msg_data_next(&msg->cursor, &page_offset, &length,
- NULL);
+ page = ceph_msg_data_next(cursor, &page_offset, &length, NULL);
ret = ceph_tcp_recvpage(con->sock, page, page_offset, length);
if (ret <= 0) {
if (do_datacrc)
@@ -2258,7 +2254,7 @@ static int read_partial_msg_data(struct ceph_connection *con)
if (do_datacrc)
crc = ceph_crc32c_page(crc, page, page_offset, ret);
- (void) ceph_msg_data_advance(&msg->cursor, (size_t)ret);
+ (void) ceph_msg_data_advance(cursor, (size_t)ret);
}
if (do_datacrc)
con->in_data_crc = crc;
@@ -2278,7 +2274,7 @@ static int read_partial_message(struct ceph_connection *con)
int end;
int ret;
unsigned int front_len, middle_len, data_len;
- bool do_datacrc = !con->msgr->nocrc;
+ bool do_datacrc = !ceph_test_opt(from_msgr(con->msgr), NOCRC);
bool need_sign = (con->peer_features & CEPH_FEATURE_MSG_AUTH);
u64 seq;
u32 crc;
@@ -2423,7 +2419,7 @@ static int read_partial_message(struct ceph_connection *con)
}
if (need_sign && con->ops->check_message_signature &&
- con->ops->check_message_signature(con, m)) {
+ con->ops->check_message_signature(m)) {
pr_err("read_partial_message %p signature check failed\n", m);
return -EBADMSG;
}
@@ -2438,13 +2434,10 @@ static int read_partial_message(struct ceph_connection *con)
*/
static void process_message(struct ceph_connection *con)
{
- struct ceph_msg *msg;
+ struct ceph_msg *msg = con->in_msg;
BUG_ON(con->in_msg->con != con);
- con->in_msg->con = NULL;
- msg = con->in_msg;
con->in_msg = NULL;
- con->ops->put(con);
/* if first message, set peer_name */
if (con->peer_name.type == 0)
@@ -2677,7 +2670,7 @@ more:
if (ret <= 0) {
switch (ret) {
case -EBADMSG:
- con->error_msg = "bad crc";
+ con->error_msg = "bad crc/signature";
/* fall through */
case -EBADE:
ret = -EIO;
@@ -2918,10 +2911,8 @@ static void con_fault(struct ceph_connection *con)
if (con->in_msg) {
BUG_ON(con->in_msg->con != con);
- con->in_msg->con = NULL;
ceph_msg_put(con->in_msg);
con->in_msg = NULL;
- con->ops->put(con);
}
/* Requeue anything that hasn't been acked */
@@ -2952,15 +2943,8 @@ static void con_fault(struct ceph_connection *con)
* initialize a new messenger instance
*/
void ceph_messenger_init(struct ceph_messenger *msgr,
- struct ceph_entity_addr *myaddr,
- u64 supported_features,
- u64 required_features,
- bool nocrc,
- bool tcp_nodelay)
+ struct ceph_entity_addr *myaddr)
{
- msgr->supported_features = supported_features;
- msgr->required_features = required_features;
-
spin_lock_init(&msgr->global_seq_lock);
if (myaddr)
@@ -2970,8 +2954,6 @@ void ceph_messenger_init(struct ceph_messenger *msgr,
msgr->inst.addr.type = 0;
get_random_bytes(&msgr->inst.addr.nonce, sizeof(msgr->inst.addr.nonce));
encode_my_addr(msgr);
- msgr->nocrc = nocrc;
- msgr->tcp_nodelay = tcp_nodelay;
atomic_set(&msgr->stopping, 0);
write_pnet(&msgr->net, get_net(current->nsproxy->net_ns));
@@ -2986,6 +2968,15 @@ void ceph_messenger_fini(struct ceph_messenger *msgr)
}
EXPORT_SYMBOL(ceph_messenger_fini);
+static void msg_con_set(struct ceph_msg *msg, struct ceph_connection *con)
+{
+ if (msg->con)
+ msg->con->ops->put(msg->con);
+
+ msg->con = con ? con->ops->get(con) : NULL;
+ BUG_ON(msg->con != con);
+}
+
static void clear_standby(struct ceph_connection *con)
{
/* come back from STANDBY? */
@@ -3017,9 +3008,7 @@ void ceph_con_send(struct ceph_connection *con, struct ceph_msg *msg)
return;
}
- BUG_ON(msg->con != NULL);
- msg->con = con->ops->get(con);
- BUG_ON(msg->con == NULL);
+ msg_con_set(msg, con);
BUG_ON(!list_empty(&msg->list_head));
list_add_tail(&msg->list_head, &con->out_queue);
@@ -3047,16 +3036,15 @@ void ceph_msg_revoke(struct ceph_msg *msg)
{
struct ceph_connection *con = msg->con;
- if (!con)
+ if (!con) {
+ dout("%s msg %p null con\n", __func__, msg);
return; /* Message not in our possession */
+ }
mutex_lock(&con->mutex);
if (!list_empty(&msg->list_head)) {
dout("%s %p msg %p - was on queue\n", __func__, con, msg);
list_del_init(&msg->list_head);
- BUG_ON(msg->con == NULL);
- msg->con->ops->put(msg->con);
- msg->con = NULL;
msg->hdr.seq = 0;
ceph_msg_put(msg);
@@ -3080,16 +3068,13 @@ void ceph_msg_revoke(struct ceph_msg *msg)
*/
void ceph_msg_revoke_incoming(struct ceph_msg *msg)
{
- struct ceph_connection *con;
+ struct ceph_connection *con = msg->con;
- BUG_ON(msg == NULL);
- if (!msg->con) {
+ if (!con) {
dout("%s msg %p null con\n", __func__, msg);
-
return; /* Message not in our possession */
}
- con = msg->con;
mutex_lock(&con->mutex);
if (con->in_msg == msg) {
unsigned int front_len = le32_to_cpu(con->in_hdr.front_len);
@@ -3335,9 +3320,8 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
}
if (msg) {
BUG_ON(*skip);
+ msg_con_set(msg, con);
con->in_msg = msg;
- con->in_msg->con = con->ops->get(con);
- BUG_ON(con->in_msg->con == NULL);
} else {
/*
* Null message pointer means either we should skip
@@ -3384,6 +3368,8 @@ static void ceph_msg_release(struct kref *kref)
dout("%s %p\n", __func__, m);
WARN_ON(!list_empty(&m->list_head));
+ msg_con_set(m, NULL);
+
/* drop middle, data, if any */
if (m->middle) {
ceph_buffer_put(m->middle);
diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c
index f79ccac..f8f2359 100644
--- a/net/ceph/osd_client.c
+++ b/net/ceph/osd_client.c
@@ -120,11 +120,13 @@ static void ceph_osd_data_bio_init(struct ceph_osd_data *osd_data,
}
#endif /* CONFIG_BLOCK */
-#define osd_req_op_data(oreq, whch, typ, fld) \
- ({ \
- BUG_ON(whch >= (oreq)->r_num_ops); \
- &(oreq)->r_ops[whch].typ.fld; \
- })
+#define osd_req_op_data(oreq, whch, typ, fld) \
+({ \
+ struct ceph_osd_request *__oreq = (oreq); \
+ unsigned int __whch = (whch); \
+ BUG_ON(__whch >= __oreq->r_num_ops); \
+ &__oreq->r_ops[__whch].typ.fld; \
+})
static struct ceph_osd_data *
osd_req_op_raw_data_in(struct ceph_osd_request *osd_req, unsigned int which)
@@ -1750,8 +1752,7 @@ static void complete_request(struct ceph_osd_request *req)
* handle osd op reply. either call the callback if it is specified,
* or do the completion to wake up the waiting thread.
*/
-static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
- struct ceph_connection *con)
+static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg)
{
void *p, *end;
struct ceph_osd_request *req;
@@ -2807,7 +2808,7 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg)
ceph_osdc_handle_map(osdc, msg);
break;
case CEPH_MSG_OSD_OPREPLY:
- handle_reply(osdc, msg, con);
+ handle_reply(osdc, msg);
break;
case CEPH_MSG_WATCH_NOTIFY:
handle_watch_notify(osdc, msg);
@@ -2849,9 +2850,6 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
goto out;
}
- if (req->r_reply->con)
- dout("%s revoking msg %p from old con %p\n", __func__,
- req->r_reply, req->r_reply->con);
ceph_msg_revoke_incoming(req->r_reply);
if (front_len > req->r_reply->front_alloc_len) {
@@ -2978,17 +2976,19 @@ static int invalidate_authorizer(struct ceph_connection *con)
return ceph_monc_validate_auth(&osdc->client->monc);
}
-static int sign_message(struct ceph_connection *con, struct ceph_msg *msg)
+static int osd_sign_message(struct ceph_msg *msg)
{
- struct ceph_osd *o = con->private;
+ struct ceph_osd *o = msg->con->private;
struct ceph_auth_handshake *auth = &o->o_auth;
+
return ceph_auth_sign_message(auth, msg);
}
-static int check_message_signature(struct ceph_connection *con, struct ceph_msg *msg)
+static int osd_check_message_signature(struct ceph_msg *msg)
{
- struct ceph_osd *o = con->private;
+ struct ceph_osd *o = msg->con->private;
struct ceph_auth_handshake *auth = &o->o_auth;
+
return ceph_auth_check_message_signature(auth, msg);
}
@@ -3000,7 +3000,7 @@ static const struct ceph_connection_operations osd_con_ops = {
.verify_authorizer_reply = verify_authorizer_reply,
.invalidate_authorizer = invalidate_authorizer,
.alloc_msg = alloc_msg,
- .sign_message = sign_message,
- .check_message_signature = check_message_signature,
+ .sign_message = osd_sign_message,
+ .check_message_signature = osd_check_message_signature,
.fault = osd_reset,
};
diff --git a/net/core/datagram.c b/net/core/datagram.c
index 617088a..d62af69 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -785,7 +785,7 @@ unsigned int datagram_poll(struct file *file, struct socket *sock,
if (sock_writeable(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
return mask;
}
diff --git a/net/core/dev.c b/net/core/dev.c
index 8ce3f74..ae00b89 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2403,17 +2403,20 @@ static void skb_warn_bad_offload(const struct sk_buff *skb)
{
static const netdev_features_t null_features = 0;
struct net_device *dev = skb->dev;
- const char *driver = "";
+ const char *name = "";
if (!net_ratelimit())
return;
- if (dev && dev->dev.parent)
- driver = dev_driver_string(dev->dev.parent);
-
+ if (dev) {
+ if (dev->dev.parent)
+ name = dev_driver_string(dev->dev.parent);
+ else
+ name = netdev_name(dev);
+ }
WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d "
"gso_type=%d ip_summed=%d\n",
- driver, dev ? &dev->features : &null_features,
+ name, dev ? &dev->features : &null_features,
skb->sk ? &skb->sk->sk_route_caps : &null_features,
skb->len, skb->data_len, skb_shinfo(skb)->gso_size,
skb_shinfo(skb)->gso_type, skb->ip_summed);
@@ -6402,7 +6405,7 @@ int __netdev_update_features(struct net_device *dev)
struct net_device *upper, *lower;
netdev_features_t features;
struct list_head *iter;
- int err = 0;
+ int err = -1;
ASSERT_RTNL();
@@ -6419,21 +6422,27 @@ int __netdev_update_features(struct net_device *dev)
features = netdev_sync_upper_features(dev, upper, features);
if (dev->features == features)
- return 0;
+ goto sync_lower;
netdev_dbg(dev, "Features changed: %pNF -> %pNF\n",
&dev->features, &features);
if (dev->netdev_ops->ndo_set_features)
err = dev->netdev_ops->ndo_set_features(dev, features);
+ else
+ err = 0;
if (unlikely(err < 0)) {
netdev_err(dev,
"set_features() failed (%d); wanted %pNF, left %pNF\n",
err, &features, &dev->features);
+ /* return non-0 since some features might have changed and
+ * it's better to fire a spurious notification than miss it
+ */
return -1;
}
+sync_lower:
/* some features must be disabled on lower devices when disabled
* on an upper device (think: bonding master or bridge)
*/
@@ -6443,7 +6452,7 @@ int __netdev_update_features(struct net_device *dev)
if (!err)
dev->features = features;
- return 1;
+ return err < 0 ? 0 : 1;
}
/**
diff --git a/net/core/dst.c b/net/core/dst.c
index 2a18180..a1656e3 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -301,12 +301,13 @@ void dst_release(struct dst_entry *dst)
{
if (dst) {
int newrefcnt;
+ unsigned short nocache = dst->flags & DST_NOCACHE;
newrefcnt = atomic_dec_return(&dst->__refcnt);
if (unlikely(newrefcnt < 0))
net_warn_ratelimited("%s: dst:%p refcnt:%d\n",
__func__, dst, newrefcnt);
- if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt)
+ if (!newrefcnt && unlikely(nocache))
call_rcu(&dst->rcu_head, dst_destroy_rcu);
}
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 1aa8437..f18ae91 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -857,7 +857,7 @@ static void neigh_probe(struct neighbour *neigh)
struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue);
/* keep skb alive even if arp_queue overflows */
if (skb)
- skb = skb_copy(skb, GFP_ATOMIC);
+ skb = skb_clone(skb, GFP_ATOMIC);
write_unlock(&neigh->lock);
neigh->ops->solicit(neigh, skb);
atomic_inc(&neigh->probes);
@@ -2215,7 +2215,7 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
ndm->ndm_pad2 = 0;
ndm->ndm_flags = pn->flags | NTF_PROXY;
ndm->ndm_type = RTN_UNICAST;
- ndm->ndm_ifindex = pn->dev->ifindex;
+ ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0;
ndm->ndm_state = NUD_NONE;
if (nla_put(skb, NDA_DST, tbl->key_len, pn->key))
@@ -2333,7 +2333,7 @@ static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
if (h > s_h)
s_idx = 0;
for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) {
- if (dev_net(n->dev) != net)
+ if (pneigh_net(n) != net)
continue;
if (idx < s_idx)
goto next;
diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c
index 6441f47..d9ee8d0 100644
--- a/net/core/netclassid_cgroup.c
+++ b/net/core/netclassid_cgroup.c
@@ -56,7 +56,7 @@ static void cgrp_css_free(struct cgroup_subsys_state *css)
kfree(css_cls_state(css));
}
-static int update_classid(const void *v, struct file *file, unsigned n)
+static int update_classid_sock(const void *v, struct file *file, unsigned n)
{
int err;
struct socket *sock = sock_from_file(file, &err);
@@ -67,18 +67,27 @@ static int update_classid(const void *v, struct file *file, unsigned n)
return 0;
}
-static void cgrp_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void update_classid(struct cgroup_subsys_state *css, void *v)
{
- struct cgroup_cls_state *cs = css_cls_state(css);
- void *v = (void *)(unsigned long)cs->classid;
+ struct css_task_iter it;
struct task_struct *p;
- cgroup_taskset_for_each(p, tset) {
+ css_task_iter_start(css, &it);
+ while ((p = css_task_iter_next(&it))) {
task_lock(p);
- iterate_fd(p->files, 0, update_classid, v);
+ iterate_fd(p->files, 0, update_classid_sock, v);
task_unlock(p);
}
+ css_task_iter_end(&it);
+}
+
+static void cgrp_attach(struct cgroup_taskset *tset)
+{
+ struct cgroup_subsys_state *css;
+
+ cgroup_taskset_first(tset, &css);
+ update_classid(css,
+ (void *)(unsigned long)css_cls_state(css)->classid);
}
static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
@@ -89,8 +98,11 @@ static u64 read_classid(struct cgroup_subsys_state *css, struct cftype *cft)
static int write_classid(struct cgroup_subsys_state *css, struct cftype *cft,
u64 value)
{
- css_cls_state(css)->classid = (u32) value;
+ struct cgroup_cls_state *cs = css_cls_state(css);
+
+ cs->classid = (u32)value;
+ update_classid(css, (void *)(unsigned long)cs->classid);
return 0;
}
diff --git a/net/core/netprio_cgroup.c b/net/core/netprio_cgroup.c
index cbd0a19..40fd09f 100644
--- a/net/core/netprio_cgroup.c
+++ b/net/core/netprio_cgroup.c
@@ -218,13 +218,14 @@ static int update_netprio(const void *v, struct file *file, unsigned n)
return 0;
}
-static void net_prio_attach(struct cgroup_subsys_state *css,
- struct cgroup_taskset *tset)
+static void net_prio_attach(struct cgroup_taskset *tset)
{
struct task_struct *p;
- void *v = (void *)(unsigned long)css->cgroup->id;
+ struct cgroup_subsys_state *css;
+
+ cgroup_taskset_for_each(p, css, tset) {
+ void *v = (void *)(unsigned long)css->cgroup->id;
- cgroup_taskset_for_each(p, tset) {
task_lock(p);
iterate_fd(p->files, 0, update_netprio, v);
task_unlock(p);
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 504bd17..34ba7a0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1045,15 +1045,156 @@ static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev)
return 0;
}
+static noinline_for_stack int rtnl_fill_stats(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ const struct rtnl_link_stats64 *stats;
+ struct rtnl_link_stats64 temp;
+ struct nlattr *attr;
+
+ stats = dev_get_stats(dev, &temp);
+
+ attr = nla_reserve(skb, IFLA_STATS,
+ sizeof(struct rtnl_link_stats));
+ if (!attr)
+ return -EMSGSIZE;
+
+ copy_rtnl_link_stats(nla_data(attr), stats);
+
+ attr = nla_reserve(skb, IFLA_STATS64,
+ sizeof(struct rtnl_link_stats64));
+ if (!attr)
+ return -EMSGSIZE;
+
+ copy_rtnl_link_stats64(nla_data(attr), stats);
+
+ return 0;
+}
+
+static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb,
+ struct net_device *dev,
+ int vfs_num,
+ struct nlattr *vfinfo)
+{
+ struct ifla_vf_rss_query_en vf_rss_query_en;
+ struct ifla_vf_link_state vf_linkstate;
+ struct ifla_vf_spoofchk vf_spoofchk;
+ struct ifla_vf_tx_rate vf_tx_rate;
+ struct ifla_vf_stats vf_stats;
+ struct ifla_vf_trust vf_trust;
+ struct ifla_vf_vlan vf_vlan;
+ struct ifla_vf_rate vf_rate;
+ struct nlattr *vf, *vfstats;
+ struct ifla_vf_mac vf_mac;
+ struct ifla_vf_info ivi;
+
+ /* Not all SR-IOV capable drivers support the
+ * spoofcheck and "RSS query enable" query. Preset to
+ * -1 so the user space tool can detect that the driver
+ * didn't report anything.
+ */
+ ivi.spoofchk = -1;
+ ivi.rss_query_en = -1;
+ ivi.trusted = -1;
+ memset(ivi.mac, 0, sizeof(ivi.mac));
+ /* The default value for VF link state is "auto"
+ * IFLA_VF_LINK_STATE_AUTO which equals zero
+ */
+ ivi.linkstate = 0;
+ if (dev->netdev_ops->ndo_get_vf_config(dev, vfs_num, &ivi))
+ return 0;
+
+ vf_mac.vf =
+ vf_vlan.vf =
+ vf_rate.vf =
+ vf_tx_rate.vf =
+ vf_spoofchk.vf =
+ vf_linkstate.vf =
+ vf_rss_query_en.vf =
+ vf_trust.vf = ivi.vf;
+
+ memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
+ vf_vlan.vlan = ivi.vlan;
+ vf_vlan.qos = ivi.qos;
+ vf_tx_rate.rate = ivi.max_tx_rate;
+ vf_rate.min_tx_rate = ivi.min_tx_rate;
+ vf_rate.max_tx_rate = ivi.max_tx_rate;
+ vf_spoofchk.setting = ivi.spoofchk;
+ vf_linkstate.link_state = ivi.linkstate;
+ vf_rss_query_en.setting = ivi.rss_query_en;
+ vf_trust.setting = ivi.trusted;
+ vf = nla_nest_start(skb, IFLA_VF_INFO);
+ if (!vf) {
+ nla_nest_cancel(skb, vfinfo);
+ return -EMSGSIZE;
+ }
+ if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
+ nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
+ nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
+ &vf_rate) ||
+ nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
+ &vf_tx_rate) ||
+ nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
+ &vf_spoofchk) ||
+ nla_put(skb, IFLA_VF_LINK_STATE, sizeof(vf_linkstate),
+ &vf_linkstate) ||
+ nla_put(skb, IFLA_VF_RSS_QUERY_EN,
+ sizeof(vf_rss_query_en),
+ &vf_rss_query_en) ||
+ nla_put(skb, IFLA_VF_TRUST,
+ sizeof(vf_trust), &vf_trust))
+ return -EMSGSIZE;
+ memset(&vf_stats, 0, sizeof(vf_stats));
+ if (dev->netdev_ops->ndo_get_vf_stats)
+ dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num,
+ &vf_stats);
+ vfstats = nla_nest_start(skb, IFLA_VF_STATS);
+ if (!vfstats) {
+ nla_nest_cancel(skb, vf);
+ nla_nest_cancel(skb, vfinfo);
+ return -EMSGSIZE;
+ }
+ if (nla_put_u64(skb, IFLA_VF_STATS_RX_PACKETS,
+ vf_stats.rx_packets) ||
+ nla_put_u64(skb, IFLA_VF_STATS_TX_PACKETS,
+ vf_stats.tx_packets) ||
+ nla_put_u64(skb, IFLA_VF_STATS_RX_BYTES,
+ vf_stats.rx_bytes) ||
+ nla_put_u64(skb, IFLA_VF_STATS_TX_BYTES,
+ vf_stats.tx_bytes) ||
+ nla_put_u64(skb, IFLA_VF_STATS_BROADCAST,
+ vf_stats.broadcast) ||
+ nla_put_u64(skb, IFLA_VF_STATS_MULTICAST,
+ vf_stats.multicast))
+ return -EMSGSIZE;
+ nla_nest_end(skb, vfstats);
+ nla_nest_end(skb, vf);
+ return 0;
+}
+
+static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev)
+{
+ struct rtnl_link_ifmap map = {
+ .mem_start = dev->mem_start,
+ .mem_end = dev->mem_end,
+ .base_addr = dev->base_addr,
+ .irq = dev->irq,
+ .dma = dev->dma,
+ .port = dev->if_port,
+ };
+ if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
+ return -EMSGSIZE;
+
+ return 0;
+}
+
static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
int type, u32 pid, u32 seq, u32 change,
unsigned int flags, u32 ext_filter_mask)
{
struct ifinfomsg *ifm;
struct nlmsghdr *nlh;
- struct rtnl_link_stats64 temp;
- const struct rtnl_link_stats64 *stats;
- struct nlattr *attr, *af_spec;
+ struct nlattr *af_spec;
struct rtnl_af_ops *af_ops;
struct net_device *upper_dev = netdev_master_upper_dev_get(dev);
@@ -1096,18 +1237,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down))
goto nla_put_failure;
- if (1) {
- struct rtnl_link_ifmap map = {
- .mem_start = dev->mem_start,
- .mem_end = dev->mem_end,
- .base_addr = dev->base_addr,
- .irq = dev->irq,
- .dma = dev->dma,
- .port = dev->if_port,
- };
- if (nla_put(skb, IFLA_MAP, sizeof(map), &map))
- goto nla_put_failure;
- }
+ if (rtnl_fill_link_ifmap(skb, dev))
+ goto nla_put_failure;
if (dev->addr_len) {
if (nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr) ||
@@ -1124,128 +1255,27 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (rtnl_phys_switch_id_fill(skb, dev))
goto nla_put_failure;
- attr = nla_reserve(skb, IFLA_STATS,
- sizeof(struct rtnl_link_stats));
- if (attr == NULL)
- goto nla_put_failure;
-
- stats = dev_get_stats(dev, &temp);
- copy_rtnl_link_stats(nla_data(attr), stats);
-
- attr = nla_reserve(skb, IFLA_STATS64,
- sizeof(struct rtnl_link_stats64));
- if (attr == NULL)
+ if (rtnl_fill_stats(skb, dev))
goto nla_put_failure;
- copy_rtnl_link_stats64(nla_data(attr), stats);
if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF) &&
nla_put_u32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent)))
goto nla_put_failure;
- if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent
- && (ext_filter_mask & RTEXT_FILTER_VF)) {
+ if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent &&
+ ext_filter_mask & RTEXT_FILTER_VF) {
int i;
-
- struct nlattr *vfinfo, *vf, *vfstats;
+ struct nlattr *vfinfo;
int num_vfs = dev_num_vf(dev->dev.parent);
vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST);
if (!vfinfo)
goto nla_put_failure;
for (i = 0; i < num_vfs; i++) {
- struct ifla_vf_info ivi;
- struct ifla_vf_mac vf_mac;
- struct ifla_vf_vlan vf_vlan;
- struct ifla_vf_rate vf_rate;
- struct ifla_vf_tx_rate vf_tx_rate;
- struct ifla_vf_spoofchk vf_spoofchk;
- struct ifla_vf_link_state vf_linkstate;
- struct ifla_vf_rss_query_en vf_rss_query_en;
- struct ifla_vf_stats vf_stats;
- struct ifla_vf_trust vf_trust;
-
- /*
- * Not all SR-IOV capable drivers support the
- * spoofcheck and "RSS query enable" query. Preset to
- * -1 so the user space tool can detect that the driver
- * didn't report anything.
- */
- ivi.spoofchk = -1;
- ivi.rss_query_en = -1;
- ivi.trusted = -1;
- memset(ivi.mac, 0, sizeof(ivi.mac));
- /* The default value for VF link state is "auto"
- * IFLA_VF_LINK_STATE_AUTO which equals zero
- */
- ivi.linkstate = 0;
- if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
- break;
- vf_mac.vf =
- vf_vlan.vf =
- vf_rate.vf =
- vf_tx_rate.vf =
- vf_spoofchk.vf =
- vf_linkstate.vf =
- vf_rss_query_en.vf =
- vf_trust.vf = ivi.vf;
-
- memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac));
- vf_vlan.vlan = ivi.vlan;
- vf_vlan.qos = ivi.qos;
- vf_tx_rate.rate = ivi.max_tx_rate;
- vf_rate.min_tx_rate = ivi.min_tx_rate;
- vf_rate.max_tx_rate = ivi.max_tx_rate;
- vf_spoofchk.setting = ivi.spoofchk;
- vf_linkstate.link_state = ivi.linkstate;
- vf_rss_query_en.setting = ivi.rss_query_en;
- vf_trust.setting = ivi.trusted;
- vf = nla_nest_start(skb, IFLA_VF_INFO);
- if (!vf) {
- nla_nest_cancel(skb, vfinfo);
- goto nla_put_failure;
- }
- if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) ||
- nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) ||
- nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate),
- &vf_rate) ||
- nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate),
- &vf_tx_rate) ||
- nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk),
- &vf_spoofchk) ||
- nla_put(skb, IFLA_VF_LINK_STATE, sizeof(vf_linkstate),
- &vf_linkstate) ||
- nla_put(skb, IFLA_VF_RSS_QUERY_EN,
- sizeof(vf_rss_query_en),
- &vf_rss_query_en) ||
- nla_put(skb, IFLA_VF_TRUST,
- sizeof(vf_trust), &vf_trust))
+ if (rtnl_fill_vfinfo(skb, dev, i, vfinfo))
goto nla_put_failure;
- memset(&vf_stats, 0, sizeof(vf_stats));
- if (dev->netdev_ops->ndo_get_vf_stats)
- dev->netdev_ops->ndo_get_vf_stats(dev, i,
- &vf_stats);
- vfstats = nla_nest_start(skb, IFLA_VF_STATS);
- if (!vfstats) {
- nla_nest_cancel(skb, vf);
- nla_nest_cancel(skb, vfinfo);
- goto nla_put_failure;
- }
- if (nla_put_u64(skb, IFLA_VF_STATS_RX_PACKETS,
- vf_stats.rx_packets) ||
- nla_put_u64(skb, IFLA_VF_STATS_TX_PACKETS,
- vf_stats.tx_packets) ||
- nla_put_u64(skb, IFLA_VF_STATS_RX_BYTES,
- vf_stats.rx_bytes) ||
- nla_put_u64(skb, IFLA_VF_STATS_TX_BYTES,
- vf_stats.tx_bytes) ||
- nla_put_u64(skb, IFLA_VF_STATS_BROADCAST,
- vf_stats.broadcast) ||
- nla_put_u64(skb, IFLA_VF_STATS_MULTICAST,
- vf_stats.multicast))
- goto nla_put_failure;
- nla_nest_end(skb, vfstats);
- nla_nest_end(skb, vf);
}
+
nla_nest_end(skb, vfinfo);
}
diff --git a/net/core/scm.c b/net/core/scm.c
index 3b6899b..8a1741b 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -305,6 +305,8 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
err = put_user(cmlen, &cm->cmsg_len);
if (!err) {
cmlen = CMSG_SPACE(i*sizeof(int));
+ if (msg->msg_controllen < cmlen)
+ cmlen = msg->msg_controllen;
msg->msg_control += cmlen;
msg->msg_controllen -= cmlen;
}
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index aa41e6d..b2df375 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3643,7 +3643,8 @@ static void __skb_complete_tx_timestamp(struct sk_buff *skb,
serr->ee.ee_info = tstype;
if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) {
serr->ee.ee_data = skb_shinfo(skb)->tskey;
- if (sk->sk_protocol == IPPROTO_TCP)
+ if (sk->sk_protocol == IPPROTO_TCP &&
+ sk->sk_type == SOCK_STREAM)
serr->ee.ee_data -= sk->sk_tskey;
}
@@ -4268,7 +4269,8 @@ static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb)
return NULL;
}
- memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
+ memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN,
+ 2 * ETH_ALEN);
skb->mac_header += VLAN_HLEN;
return skb;
}
diff --git a/net/core/sock.c b/net/core/sock.c
index 1e4dd54..0d91f7d 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -433,8 +433,6 @@ static bool sock_needs_netstamp(const struct sock *sk)
}
}
-#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE))
-
static void sock_disable_timestamp(struct sock *sk, unsigned long flags)
{
if (sk->sk_flags & flags) {
@@ -874,7 +872,8 @@ set_rcvbuf:
if (val & SOF_TIMESTAMPING_OPT_ID &&
!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) {
- if (sk->sk_protocol == IPPROTO_TCP) {
+ if (sk->sk_protocol == IPPROTO_TCP &&
+ sk->sk_type == SOCK_STREAM) {
if (sk->sk_state != TCP_ESTABLISHED) {
ret = -EINVAL;
break;
@@ -1530,7 +1529,6 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
skb_queue_head_init(&newsk->sk_receive_queue);
skb_queue_head_init(&newsk->sk_write_queue);
- spin_lock_init(&newsk->sk_dst_lock);
rwlock_init(&newsk->sk_callback_lock);
lockdep_set_class_and_name(&newsk->sk_callback_lock,
af_callback_keys + newsk->sk_family,
@@ -1553,7 +1551,7 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
*/
is_charged = sk_filter_charge(newsk, filter);
- if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk))) {
+ if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) {
/* It is still raw copy of parent, so invalidate
* destructor and make plain sk_free() */
newsk->sk_destruct = NULL;
@@ -1607,7 +1605,7 @@ void sk_setup_caps(struct sock *sk, struct dst_entry *dst)
{
u32 max_segs = 1;
- __sk_dst_set(sk, dst);
+ sk_dst_set(sk, dst);
sk->sk_route_caps = dst->dev->features;
if (sk->sk_route_caps & NETIF_F_GSO)
sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE;
@@ -1815,7 +1813,7 @@ static long sock_wait_for_wmem(struct sock *sk, long timeo)
{
DEFINE_WAIT(wait);
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
for (;;) {
if (!timeo)
break;
@@ -1861,7 +1859,7 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
if (sk_wmem_alloc_get(sk) < sk->sk_sndbuf)
break;
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
err = -EAGAIN;
if (!timeo)
@@ -2048,9 +2046,9 @@ int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb)
DEFINE_WAIT(wait);
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb);
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
finish_wait(sk_sleep(sk), &wait);
return rc;
}
@@ -2388,7 +2386,6 @@ void sock_init_data(struct socket *sock, struct sock *sk)
} else
sk->sk_wq = NULL;
- spin_lock_init(&sk->sk_dst_lock);
rwlock_init(&sk->sk_callback_lock);
lockdep_set_class_and_name(&sk->sk_callback_lock,
af_callback_keys + sk->sk_family,
diff --git a/net/core/stream.c b/net/core/stream.c
index d70f77a..b96f7a7 100644
--- a/net/core/stream.c
+++ b/net/core/stream.c
@@ -39,7 +39,7 @@ void sk_stream_write_space(struct sock *sk)
wake_up_interruptible_poll(&wq->wait, POLLOUT |
POLLWRNORM | POLLWRBAND);
if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN))
- sock_wake_async(sock, SOCK_WAKE_SPACE, POLL_OUT);
+ sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
rcu_read_unlock();
}
}
@@ -126,7 +126,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2;
while (1) {
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
@@ -139,7 +139,7 @@ int sk_stream_wait_memory(struct sock *sk, long *timeo_p)
}
if (signal_pending(current))
goto do_interrupted;
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
if (sk_stream_memory_free(sk) && !vm_wait)
break;
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index db5fc24..9c6d050 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -202,7 +202,9 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
security_req_classify_flow(req, flowi6_to_flowi(&fl6));
- final_p = fl6_update_dst(&fl6, np->opt, &final);
+ rcu_read_lock();
+ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
+ rcu_read_unlock();
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
@@ -219,7 +221,10 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
&ireq->ir_v6_loc_addr,
&ireq->ir_v6_rmt_addr);
fl6.daddr = ireq->ir_v6_rmt_addr;
- err = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+ rcu_read_lock();
+ err = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+ np->tclass);
+ rcu_read_unlock();
err = net_xmit_eval(err);
}
@@ -387,6 +392,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
struct inet_request_sock *ireq = inet_rsk(req);
struct ipv6_pinfo *newnp;
const struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6_txoptions *opt;
struct inet_sock *newinet;
struct dccp6_sock *newdp6;
struct sock *newsk;
@@ -453,7 +459,7 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
* comment in that function for the gory details. -acme
*/
- __ip6_dst_store(newsk, dst, NULL, NULL);
+ ip6_dst_store(newsk, dst, NULL, NULL);
newsk->sk_route_caps = dst->dev->features & ~(NETIF_F_IP_CSUM |
NETIF_F_TSO);
newdp6 = (struct dccp6_sock *)newsk;
@@ -488,13 +494,15 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
* Yes, keeping reference count would be much more clever, but we make
* one more one thing there: reattach optmem to newsk.
*/
- if (np->opt != NULL)
- newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+ opt = rcu_dereference(np->opt);
+ if (opt) {
+ opt = ipv6_dup_options(newsk, opt);
+ RCU_INIT_POINTER(newnp->opt, opt);
+ }
inet_csk(newsk)->icsk_ext_hdr_len = 0;
- if (newnp->opt != NULL)
- inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
- newnp->opt->opt_flen);
+ if (opt)
+ inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+ opt->opt_flen;
dccp_sync_mss(newsk, dst_mtu(dst));
@@ -757,6 +765,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct ipv6_pinfo *np = inet6_sk(sk);
struct dccp_sock *dp = dccp_sk(sk);
struct in6_addr *saddr = NULL, *final_p, final;
+ struct ipv6_txoptions *opt;
struct flowi6 fl6;
struct dst_entry *dst;
int addr_type;
@@ -856,7 +865,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl6.fl6_sport = inet->inet_sport;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
- final_p = fl6_update_dst(&fl6, np->opt, &final);
+ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+ final_p = fl6_update_dst(&fl6, opt, &final);
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
@@ -873,12 +883,11 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
np->saddr = *saddr;
inet->inet_rcv_saddr = LOOPBACK4_IPV6;
- __ip6_dst_store(sk, dst, NULL, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
icsk->icsk_ext_hdr_len = 0;
- if (np->opt != NULL)
- icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
- np->opt->opt_nflen);
+ if (opt)
+ icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
inet->inet_dport = usin->sin6_port;
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index b5cf13a..41e6580 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -339,8 +339,7 @@ unsigned int dccp_poll(struct file *file, struct socket *sock,
if (sk_stream_is_writeable(sk)) {
mask |= POLLOUT | POLLWRNORM;
} else { /* send SIGIO later */
- set_bit(SOCK_ASYNC_NOSPACE,
- &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
/* Race breaker. If space is freed after
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 675cf94..13d6b1a 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -678,6 +678,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol,
{
struct sock *sk;
+ if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+ return -EINVAL;
+
if (!net_eq(net, &init_net))
return -EAFNOSUPPORT;
@@ -1747,9 +1750,9 @@ static int dn_recvmsg(struct socket *sock, struct msghdr *msg, size_t size,
}
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
sk_wait_event(sk, &timeo, dn_data_ready(sk, queue, flags, target));
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
finish_wait(sk_sleep(sk), &wait);
}
@@ -2004,10 +2007,10 @@ static int dn_sendmsg(struct socket *sock, struct msghdr *msg, size_t size)
}
prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
sk_wait_event(sk, &timeo,
!dn_queue_too_long(scp, queue, flags));
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
finish_wait(sk_sleep(sk), &wait);
continue;
}
diff --git a/net/dns_resolver/dns_query.c b/net/dns_resolver/dns_query.c
index 4677b6f..ecc28cf 100644
--- a/net/dns_resolver/dns_query.c
+++ b/net/dns_resolver/dns_query.c
@@ -67,7 +67,7 @@
* Returns the size of the result on success, -ve error code otherwise.
*/
int dns_query(const char *type, const char *name, size_t namelen,
- const char *options, char **_result, time_t *_expiry)
+ const char *options, char **_result, time64_t *_expiry)
{
struct key *rkey;
const struct user_key_payload *upayload;
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index 35a9788..c7d1adc 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -312,7 +312,7 @@ static void send_hsr_supervision_frame(struct hsr_port *master, u8 type)
return;
out:
- WARN_ON_ONCE("HSR: Could not send supervision frame\n");
+ WARN_ONCE(1, "HSR: Could not send supervision frame\n");
kfree_skb(skb);
}
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 11c4ca1..5c5db66 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -257,6 +257,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol,
int try_loading_module = 0;
int err;
+ if (protocol < 0 || protocol >= IPPROTO_MAX)
+ return -EINVAL;
+
sock->state = SS_UNCONNECTED;
/* Look for the requested type/protocol pair. */
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index cc8f3e5..4734475 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -1155,6 +1155,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct netdev_notifier_changeupper_info *info;
struct in_device *in_dev;
struct net *net = dev_net(dev);
unsigned int flags;
@@ -1193,6 +1194,14 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo
case NETDEV_CHANGEMTU:
rt_cache_flush(net);
break;
+ case NETDEV_CHANGEUPPER:
+ info = ptr;
+ /* flush all routes if dev is linked to or unlinked from
+ * an L3 master device (e.g., VRF)
+ */
+ if (info->upper_dev && netif_is_l3_master(info->upper_dev))
+ fib_disable_ip(dev, NETDEV_DOWN, true);
+ break;
}
return NOTIFY_DONE;
}
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 3e87447..d97268e 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -923,14 +923,21 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc)
if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst ||
fib_prefsrc != cfg->fc_dst) {
u32 tb_id = cfg->fc_table;
+ int rc;
if (tb_id == RT_TABLE_MAIN)
tb_id = RT_TABLE_LOCAL;
- if (inet_addr_type_table(cfg->fc_nlinfo.nl_net,
- fib_prefsrc, tb_id) != RTN_LOCAL) {
- return false;
+ rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net,
+ fib_prefsrc, tb_id);
+
+ if (rc != RTN_LOCAL && tb_id != RT_TABLE_LOCAL) {
+ rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net,
+ fib_prefsrc, RT_TABLE_LOCAL);
}
+
+ if (rc != RTN_LOCAL)
+ return false;
}
return true;
}
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index e0fcbbb..bd903fe 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -24,6 +24,7 @@ struct fou {
u16 type;
struct udp_offload udp_offloads;
struct list_head list;
+ struct rcu_head rcu;
};
#define FOU_F_REMCSUM_NOPARTIAL BIT(0)
@@ -417,7 +418,7 @@ static void fou_release(struct fou *fou)
list_del(&fou->list);
udp_tunnel_sock_release(sock);
- kfree(fou);
+ kfree_rcu(fou, rcu);
}
static int fou_encap_init(struct sock *sk, struct fou *fou, struct fou_cfg *cfg)
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 64aaf35..05e4cba 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -2126,7 +2126,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
ASSERT_RTNL();
in_dev = ip_mc_find_dev(net, imr);
- if (!in_dev) {
+ if (!imr->imr_ifindex && !imr->imr_address.s_addr && !in_dev) {
ret = -ENODEV;
goto out;
}
@@ -2147,7 +2147,8 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
*imlp = iml->next_rcu;
- ip_mc_dec_group(in_dev, group);
+ if (in_dev)
+ ip_mc_dec_group(in_dev, group);
/* decrease mem now to avoid the memleak warning */
atomic_sub(sizeof(*iml), &sk->sk_omem_alloc);
@@ -2392,11 +2393,11 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_sf_socklist *psl;
struct net *net = sock_net(sk);
+ ASSERT_RTNL();
+
if (!ipv4_is_multicast(addr))
return -EINVAL;
- rtnl_lock();
-
imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;
imr.imr_address.s_addr = msf->imsf_interface;
imr.imr_ifindex = 0;
@@ -2417,7 +2418,6 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
goto done;
msf->imsf_fmode = pmc->sfmode;
psl = rtnl_dereference(pmc->sflist);
- rtnl_unlock();
if (!psl) {
len = 0;
count = 0;
@@ -2436,7 +2436,6 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
return -EFAULT;
return 0;
done:
- rtnl_unlock();
return err;
}
@@ -2450,6 +2449,8 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
+ ASSERT_RTNL();
+
psin = (struct sockaddr_in *)&gsf->gf_group;
if (psin->sin_family != AF_INET)
return -EINVAL;
@@ -2457,8 +2458,6 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
if (!ipv4_is_multicast(addr))
return -EINVAL;
- rtnl_lock();
-
err = -EADDRNOTAVAIL;
for_each_pmc_rtnl(inet, pmc) {
@@ -2470,7 +2469,6 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
goto done;
gsf->gf_fmode = pmc->sfmode;
psl = rtnl_dereference(pmc->sflist);
- rtnl_unlock();
count = psl ? psl->sl_count : 0;
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
gsf->gf_numsrc = count;
@@ -2490,7 +2488,6 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
}
return 0;
done:
- rtnl_unlock();
return err;
}
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 1feb15f..46b9c88 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -563,7 +563,7 @@ static void reqsk_timer_handler(unsigned long data)
int max_retries, thresh;
u8 defer_accept;
- if (sk_listener->sk_state != TCP_LISTEN)
+ if (sk_state_load(sk_listener) != TCP_LISTEN)
goto drop;
max_retries = icsk->icsk_syn_retries ? : sysctl_tcp_synack_retries;
@@ -749,7 +749,7 @@ int inet_csk_listen_start(struct sock *sk, int backlog)
* It is OK, because this socket enters to hash table only
* after validation is complete.
*/
- sk->sk_state = TCP_LISTEN;
+ sk_state_store(sk, TCP_LISTEN);
if (!sk->sk_prot->get_port(sk, inet->inet_num)) {
inet->inet_sport = htons(inet->inet_num);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index c3c359a..5f73a7c 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1251,11 +1251,22 @@ EXPORT_SYMBOL(compat_ip_setsockopt);
* the _received_ ones. The set sets the _sent_ ones.
*/
+static bool getsockopt_needs_rtnl(int optname)
+{
+ switch (optname) {
+ case IP_MSFILTER:
+ case MCAST_MSFILTER:
+ return true;
+ }
+ return false;
+}
+
static int do_ip_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen, unsigned int flags)
{
struct inet_sock *inet = inet_sk(sk);
- int val;
+ bool needs_rtnl = getsockopt_needs_rtnl(optname);
+ int val, err = 0;
int len;
if (level != SOL_IP)
@@ -1269,6 +1280,8 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
if (len < 0)
return -EINVAL;
+ if (needs_rtnl)
+ rtnl_lock();
lock_sock(sk);
switch (optname) {
@@ -1386,39 +1399,35 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
case IP_MSFILTER:
{
struct ip_msfilter msf;
- int err;
if (len < IP_MSFILTER_SIZE(0)) {
- release_sock(sk);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) {
- release_sock(sk);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
err = ip_mc_msfget(sk, &msf,
(struct ip_msfilter __user *)optval, optlen);
- release_sock(sk);
- return err;
+ goto out;
}
case MCAST_MSFILTER:
{
struct group_filter gsf;
- int err;
if (len < GROUP_FILTER_SIZE(0)) {
- release_sock(sk);
- return -EINVAL;
+ err = -EINVAL;
+ goto out;
}
if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) {
- release_sock(sk);
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}
err = ip_mc_gsfget(sk, &gsf,
(struct group_filter __user *)optval,
optlen);
- release_sock(sk);
- return err;
+ goto out;
}
case IP_MULTICAST_ALL:
val = inet->mc_all;
@@ -1485,6 +1494,12 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
return -EFAULT;
}
return 0;
+
+out:
+ release_sock(sk);
+ if (needs_rtnl)
+ rtnl_unlock();
+ return err;
}
int ip_getsockopt(struct sock *sk, int level,
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index f34c31d..a09fb0d 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -253,9 +253,6 @@ ipip_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
p.i_key = p.o_key = 0;
p.i_flags = p.o_flags = 0;
- if (p.iph.ttl)
- p.iph.frag_off |= htons(IP_DF);
-
err = ip_tunnel_ioctl(dev, &p, cmd);
if (err)
return err;
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index 92dd4b7..c3a3835 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -134,7 +134,7 @@ static int __ipmr_fill_mroute(struct mr_table *mrt, struct sk_buff *skb,
struct mfc_cache *c, struct rtmsg *rtm);
static void mroute_netlink_event(struct mr_table *mrt, struct mfc_cache *mfc,
int cmd);
-static void mroute_clean_tables(struct mr_table *mrt);
+static void mroute_clean_tables(struct mr_table *mrt, bool all);
static void ipmr_expire_process(unsigned long arg);
#ifdef CONFIG_IP_MROUTE_MULTIPLE_TABLES
@@ -350,7 +350,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
static void ipmr_free_table(struct mr_table *mrt)
{
del_timer_sync(&mrt->ipmr_expire_timer);
- mroute_clean_tables(mrt);
+ mroute_clean_tables(mrt, true);
kfree(mrt);
}
@@ -441,10 +441,6 @@ struct net_device *ipmr_new_tunnel(struct net *net, struct vifctl *v)
return dev;
failure:
- /* allow the register to be completed before unregistering. */
- rtnl_unlock();
- rtnl_lock();
-
unregister_netdevice(dev);
return NULL;
}
@@ -540,10 +536,6 @@ static struct net_device *ipmr_reg_vif(struct net *net, struct mr_table *mrt)
return dev;
failure:
- /* allow the register to be completed before unregistering. */
- rtnl_unlock();
- rtnl_lock();
-
unregister_netdevice(dev);
return NULL;
}
@@ -1208,7 +1200,7 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
* Close the multicast socket, and clear the vif tables etc
*/
-static void mroute_clean_tables(struct mr_table *mrt)
+static void mroute_clean_tables(struct mr_table *mrt, bool all)
{
int i;
LIST_HEAD(list);
@@ -1217,8 +1209,9 @@ static void mroute_clean_tables(struct mr_table *mrt)
/* Shut down all active vif entries */
for (i = 0; i < mrt->maxvif; i++) {
- if (!(mrt->vif_table[i].flags & VIFF_STATIC))
- vif_delete(mrt, i, 0, &list);
+ if (!all && (mrt->vif_table[i].flags & VIFF_STATIC))
+ continue;
+ vif_delete(mrt, i, 0, &list);
}
unregister_netdevice_many(&list);
@@ -1226,7 +1219,7 @@ static void mroute_clean_tables(struct mr_table *mrt)
for (i = 0; i < MFC_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc_cache_array[i], list) {
- if (c->mfc_flags & MFC_STATIC)
+ if (!all && (c->mfc_flags & MFC_STATIC))
continue;
list_del_rcu(&c->list);
mroute_netlink_event(mrt, c, RTM_DELROUTE);
@@ -1261,7 +1254,7 @@ static void mrtsock_destruct(struct sock *sk)
NETCONFA_IFINDEX_ALL,
net->ipv4.devconf_all);
RCU_INIT_POINTER(mrt->mroute_sk, NULL);
- mroute_clean_tables(mrt);
+ mroute_clean_tables(mrt, false);
}
}
rtnl_unlock();
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index a355841..c187c60 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -60,6 +60,7 @@ config NFT_REJECT_IPV4
config NFT_DUP_IPV4
tristate "IPv4 nf_tables packet duplication support"
+ depends on !NF_CONNTRACK || NF_CONNTRACK
select NF_DUP_IPV4
help
This module enables IPv4 packet duplication support for nf_tables.
diff --git a/net/ipv4/netfilter/nf_defrag_ipv4.c b/net/ipv4/netfilter/nf_defrag_ipv4.c
index 0e5591c..6fb869f6 100644
--- a/net/ipv4/netfilter/nf_defrag_ipv4.c
+++ b/net/ipv4/netfilter/nf_defrag_ipv4.c
@@ -67,10 +67,9 @@ static unsigned int ipv4_conntrack_defrag(void *priv,
const struct nf_hook_state *state)
{
struct sock *sk = skb->sk;
- struct inet_sock *inet = inet_sk(skb->sk);
- if (sk && (sk->sk_family == PF_INET) &&
- inet->nodefrag)
+ if (sk && sk_fullsock(sk) && (sk->sk_family == PF_INET) &&
+ inet_sk(sk)->nodefrag)
return NF_ACCEPT;
#if IS_ENABLED(CONFIG_NF_CONNTRACK)
diff --git a/net/ipv4/netfilter/nf_nat_pptp.c b/net/ipv4/netfilter/nf_nat_pptp.c
index 657d230..b3ca21b 100644
--- a/net/ipv4/netfilter/nf_nat_pptp.c
+++ b/net/ipv4/netfilter/nf_nat_pptp.c
@@ -45,7 +45,7 @@ static void pptp_nat_expected(struct nf_conn *ct,
struct net *net = nf_ct_net(ct);
const struct nf_conn *master = ct->master;
struct nf_conntrack_expect *other_exp;
- struct nf_conntrack_tuple t;
+ struct nf_conntrack_tuple t = {};
const struct nf_ct_pptp_master *ct_pptp_info;
const struct nf_nat_pptp *nat_pptp_info;
struct nf_nat_range range;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 8c0d0bd..bc35f18 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -406,10 +406,12 @@ static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4,
ip_select_ident(net, skb, NULL);
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ skb->transport_header += iphlen;
+ if (iph->protocol == IPPROTO_ICMP &&
+ length >= iphlen + sizeof(struct icmphdr))
+ icmp_out_count(net, ((struct icmphdr *)
+ skb_transport_header(skb))->type);
}
- if (iph->protocol == IPPROTO_ICMP)
- icmp_out_count(net, ((struct icmphdr *)
- skb_transport_header(skb))->type);
err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT,
net, sk, skb, NULL, rt->dst.dev,
@@ -599,8 +601,11 @@ static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
(inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0),
daddr, saddr, 0, 0);
- if (!saddr && ipc.oif)
- l3mdev_get_saddr(net, ipc.oif, &fl4);
+ if (!saddr && ipc.oif) {
+ err = l3mdev_get_saddr(net, ipc.oif, &fl4);
+ if (err < 0)
+ goto done;
+ }
if (!inet->hdrincl) {
rfv.msg = msg;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 25300c5..a0bd7a5 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -48,14 +48,14 @@ static void set_local_port_range(struct net *net, int range[2])
{
bool same_parity = !((range[0] ^ range[1]) & 1);
- write_seqlock(&net->ipv4.ip_local_ports.lock);
+ write_seqlock_bh(&net->ipv4.ip_local_ports.lock);
if (same_parity && !net->ipv4.ip_local_ports.warned) {
net->ipv4.ip_local_ports.warned = true;
pr_err_ratelimited("ip_local_port_range: prefer different parity for start/end values.\n");
}
net->ipv4.ip_local_ports.range[0] = range[0];
net->ipv4.ip_local_ports.range[1] = range[1];
- write_sequnlock(&net->ipv4.ip_local_ports.lock);
+ write_sequnlock_bh(&net->ipv4.ip_local_ports.lock);
}
/* Validate changes from /proc interface. */
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 0cfa7c0..c82cca1 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -451,11 +451,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
unsigned int mask;
struct sock *sk = sock->sk;
const struct tcp_sock *tp = tcp_sk(sk);
+ int state;
sock_rps_record_flow(sk);
sock_poll_wait(file, sk_sleep(sk), wait);
- if (sk->sk_state == TCP_LISTEN)
+
+ state = sk_state_load(sk);
+ if (state == TCP_LISTEN)
return inet_csk_listen_poll(sk);
/* Socket is not locked. We are protected from async events
@@ -492,14 +495,14 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
* NOTE. Check for TCP_CLOSE is added. The goal is to prevent
* blocking on fresh not-connected or disconnected socket. --ANK
*/
- if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE)
+ if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE)
mask |= POLLHUP;
if (sk->sk_shutdown & RCV_SHUTDOWN)
mask |= POLLIN | POLLRDNORM | POLLRDHUP;
/* Connected or passive Fast Open socket? */
- if (sk->sk_state != TCP_SYN_SENT &&
- (sk->sk_state != TCP_SYN_RECV || tp->fastopen_rsk)) {
+ if (state != TCP_SYN_SENT &&
+ (state != TCP_SYN_RECV || tp->fastopen_rsk)) {
int target = sock_rcvlowat(sk, 0, INT_MAX);
if (tp->urg_seq == tp->copied_seq &&
@@ -507,9 +510,6 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
tp->urg_data)
target++;
- /* Potential race condition. If read of tp below will
- * escape above sk->sk_state, we can be illegally awaken
- * in SYN_* states. */
if (tp->rcv_nxt - tp->copied_seq >= target)
mask |= POLLIN | POLLRDNORM;
@@ -517,8 +517,7 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sk_stream_is_writeable(sk)) {
mask |= POLLOUT | POLLWRNORM;
} else { /* send SIGIO later */
- set_bit(SOCK_ASYNC_NOSPACE,
- &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
/* Race breaker. If space is freed after
@@ -906,7 +905,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
goto out_err;
}
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
mss_now = tcp_send_mss(sk, &size_goal, flags);
copied = 0;
@@ -1134,7 +1133,7 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
}
/* This should be in poll */
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
mss_now = tcp_send_mss(sk, &size_goal, flags);
@@ -1934,7 +1933,7 @@ void tcp_set_state(struct sock *sk, int state)
/* Change state AFTER socket is unhashed to avoid closed
* socket sitting in hash tables.
*/
- sk->sk_state = state;
+ sk_state_store(sk, state);
#ifdef STATE_TRACE
SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]);
@@ -2644,7 +2643,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
if (sk->sk_type != SOCK_STREAM)
return;
- info->tcpi_state = sk->sk_state;
+ info->tcpi_state = sk_state_load(sk);
+
info->tcpi_ca_state = icsk->icsk_ca_state;
info->tcpi_retransmits = icsk->icsk_retransmits;
info->tcpi_probes = icsk->icsk_probes_out;
@@ -2672,7 +2672,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_snd_mss = tp->mss_cache;
info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss;
- if (sk->sk_state == TCP_LISTEN) {
+ if (info->tcpi_state == TCP_LISTEN) {
info->tcpi_unacked = sk->sk_ack_backlog;
info->tcpi_sacked = sk->sk_max_ack_backlog;
} else {
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 479f349..b316040 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -21,7 +21,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r,
{
struct tcp_info *info = _info;
- if (sk->sk_state == TCP_LISTEN) {
+ if (sk_state_load(sk) == TCP_LISTEN) {
r->idiag_rqueue = sk->sk_ack_backlog;
r->idiag_wqueue = sk->sk_max_ack_backlog;
} else if (sk->sk_type == SOCK_STREAM) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index fdd88c3..d4c5115 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2478,6 +2478,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
int newly_acked_sacked = prior_unsacked -
(tp->packets_out - tp->sacked_out);
+ if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
+ return;
+
tp->prr_delivered += newly_acked_sacked;
if (delta < 0) {
u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
@@ -4481,19 +4484,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int
int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
{
struct sk_buff *skb;
+ int err = -ENOMEM;
+ int data_len = 0;
bool fragstolen;
if (size == 0)
return 0;
- skb = alloc_skb(size, sk->sk_allocation);
+ if (size > PAGE_SIZE) {
+ int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS);
+
+ data_len = npages << PAGE_SHIFT;
+ size = data_len + (size & ~PAGE_MASK);
+ }
+ skb = alloc_skb_with_frags(size - data_len, data_len,
+ PAGE_ALLOC_COSTLY_ORDER,
+ &err, sk->sk_allocation);
if (!skb)
goto err;
+ skb_put(skb, size - data_len);
+ skb->data_len = data_len;
+ skb->len = size;
+
if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
goto err_free;
- if (memcpy_from_msg(skb_put(skb, size), msg, size))
+ err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
+ if (err)
goto err_free;
TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
@@ -4509,7 +4527,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
err_free:
kfree_skb(skb);
err:
- return -ENOMEM;
+ return err;
+
}
static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
@@ -5667,6 +5686,7 @@ discard:
}
tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ tp->copied_seq = tp->rcv_nxt;
tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
/* RFC1323: The window in SYN & SYN/ACK segments is
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1c2648b..d8841a2 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -921,7 +921,8 @@ int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr,
}
md5sig = rcu_dereference_protected(tp->md5sig_info,
- sock_owned_by_user(sk));
+ sock_owned_by_user(sk) ||
+ lockdep_is_held(&sk->sk_lock.slock));
if (!md5sig) {
md5sig = kmalloc(sizeof(*md5sig), gfp);
if (!md5sig)
@@ -1326,6 +1327,8 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
if (__inet_inherit_port(sk, newsk) < 0)
goto put_and_exit;
*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
+ if (*own_req)
+ tcp_move_syn(newtp, req);
return newsk;
@@ -1490,7 +1493,7 @@ bool tcp_prequeue(struct sock *sk, struct sk_buff *skb)
if (likely(sk->sk_rx_dst))
skb_dst_drop(skb);
else
- skb_dst_force(skb);
+ skb_dst_force_safe(skb);
__skb_queue_tail(&tp->ucopy.prequeue, skb);
tp->ucopy.memory += skb->truesize;
@@ -1718,8 +1721,7 @@ void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
- if (dst) {
- dst_hold(dst);
+ if (dst && dst_hold_safe(dst)) {
sk->sk_rx_dst = dst;
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
}
@@ -2156,6 +2158,7 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
__u16 destp = ntohs(inet->inet_dport);
__u16 srcp = ntohs(inet->inet_sport);
int rx_queue;
+ int state;
if (icsk->icsk_pending == ICSK_TIME_RETRANS ||
icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS ||
@@ -2173,17 +2176,18 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
timer_expires = jiffies;
}
- if (sk->sk_state == TCP_LISTEN)
+ state = sk_state_load(sk);
+ if (state == TCP_LISTEN)
rx_queue = sk->sk_ack_backlog;
else
- /*
- * because we dont lock socket, we might find a transient negative value
+ /* Because we don't lock the socket,
+ * we might find a transient negative value.
*/
rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX "
"%08X %5u %8d %lu %d %pK %lu %lu %u %u %d",
- i, src, srcp, dest, destp, sk->sk_state,
+ i, src, srcp, dest, destp, state,
tp->write_seq - tp->snd_una,
rx_queue,
timer_active,
@@ -2197,8 +2201,8 @@ static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i)
jiffies_to_clock_t(icsk->icsk_ack.ato),
(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
tp->snd_cwnd,
- sk->sk_state == TCP_LISTEN ?
- (fastopenq ? fastopenq->max_qlen : 0) :
+ state == TCP_LISTEN ?
+ fastopenq->max_qlen :
(tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh));
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 3575dd1..ac6b196 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -551,9 +551,6 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
newtp->rack.mstamp.v64 = 0;
newtp->rack.advanced = 0;
- newtp->saved_syn = req->saved_syn;
- req->saved_syn = NULL;
-
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_PASSIVEOPENS);
}
return newsk;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index cb7ca56..9bfc39f 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -3150,7 +3150,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
{
struct tcp_sock *tp = tcp_sk(sk);
struct tcp_fastopen_request *fo = tp->fastopen_req;
- int syn_loss = 0, space, err = 0, copied;
+ int syn_loss = 0, space, err = 0;
unsigned long last_syn_loss = 0;
struct sk_buff *syn_data;
@@ -3188,17 +3188,18 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn)
goto fallback;
syn_data->ip_summed = CHECKSUM_PARTIAL;
memcpy(syn_data->cb, syn->cb, sizeof(syn->cb));
- copied = copy_from_iter(skb_put(syn_data, space), space,
- &fo->data->msg_iter);
- if (unlikely(!copied)) {
- kfree_skb(syn_data);
- goto fallback;
- }
- if (copied != space) {
- skb_trim(syn_data, copied);
- space = copied;
+ if (space) {
+ int copied = copy_from_iter(skb_put(syn_data, space), space,
+ &fo->data->msg_iter);
+ if (unlikely(!copied)) {
+ kfree_skb(syn_data);
+ goto fallback;
+ }
+ if (copied != space) {
+ skb_trim(syn_data, copied);
+ space = copied;
+ }
}
-
/* No more data pending in inet_wait_for_connect() */
if (space == fo->size)
fo->data = NULL;
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index c9c716a..193ba1f 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -168,7 +168,7 @@ static int tcp_write_timeout(struct sock *sk)
dst_negative_advice(sk);
if (tp->syn_fastopen || tp->syn_data)
tcp_fastopen_cache_set(sk, 0, NULL, true, 0);
- if (tp->syn_data)
+ if (tp->syn_data && icsk->icsk_retransmits == 1)
NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPFASTOPENACTIVEFAIL);
}
@@ -176,6 +176,18 @@ static int tcp_write_timeout(struct sock *sk)
syn_set = true;
} else {
if (retransmits_timed_out(sk, sysctl_tcp_retries1, 0, 0)) {
+ /* Some middle-boxes may black-hole Fast Open _after_
+ * the handshake. Therefore we conservatively disable
+ * Fast Open on this path on recurring timeouts with
+ * few or zero bytes acked after Fast Open.
+ */
+ if (tp->syn_data_acked &&
+ tp->bytes_acked <= tp->rx_opt.mss_clamp) {
+ tcp_fastopen_cache_set(sk, 0, NULL, true, 0);
+ if (icsk->icsk_retransmits == sysctl_tcp_retries1)
+ NET_INC_STATS_BH(sock_net(sk),
+ LINUX_MIB_TCPFASTOPENACTIVEFAIL);
+ }
/* Black hole detection */
tcp_mtu_probing(icsk, sk);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 24ec14f9..c438908 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -100,7 +100,6 @@
#include <linux/slab.h>
#include <net/tcp_states.h>
#include <linux/skbuff.h>
-#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/net_namespace.h>
@@ -1026,8 +1025,11 @@ int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
flow_flags,
faddr, saddr, dport, inet->inet_sport);
- if (!saddr && ipc.oif)
- l3mdev_get_saddr(net, ipc.oif, fl4);
+ if (!saddr && ipc.oif) {
+ err = l3mdev_get_saddr(net, ipc.oif, fl4);
+ if (err < 0)
+ goto out;
+ }
security_sk_classify_flow(sk, flowi4_to_flowi(fl4));
rt = ip_route_output_flow(net, fl4, sk);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 1e0c3c8..7b0edb3 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -259,7 +259,7 @@ static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
xfrm_dst_ifdown(dst, dev);
}
-static struct dst_ops xfrm4_dst_ops = {
+static struct dst_ops xfrm4_dst_ops_template = {
.family = AF_INET,
.gc = xfrm4_garbage_collect,
.update_pmtu = xfrm4_update_pmtu,
@@ -273,7 +273,7 @@ static struct dst_ops xfrm4_dst_ops = {
static struct xfrm_policy_afinfo xfrm4_policy_afinfo = {
.family = AF_INET,
- .dst_ops = &xfrm4_dst_ops,
+ .dst_ops = &xfrm4_dst_ops_template,
.dst_lookup = xfrm4_dst_lookup,
.get_saddr = xfrm4_get_saddr,
.decode_session = _decode_session4,
@@ -295,7 +295,7 @@ static struct ctl_table xfrm4_policy_table[] = {
{ }
};
-static int __net_init xfrm4_net_init(struct net *net)
+static int __net_init xfrm4_net_sysctl_init(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
@@ -323,7 +323,7 @@ err_alloc:
return -ENOMEM;
}
-static void __net_exit xfrm4_net_exit(struct net *net)
+static void __net_exit xfrm4_net_sysctl_exit(struct net *net)
{
struct ctl_table *table;
@@ -335,12 +335,44 @@ static void __net_exit xfrm4_net_exit(struct net *net)
if (!net_eq(net, &init_net))
kfree(table);
}
+#else /* CONFIG_SYSCTL */
+static int inline xfrm4_net_sysctl_init(struct net *net)
+{
+ return 0;
+}
+
+static void inline xfrm4_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm4_net_init(struct net *net)
+{
+ int ret;
+
+ memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template,
+ sizeof(xfrm4_dst_ops_template));
+ ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops);
+ if (ret)
+ return ret;
+
+ ret = xfrm4_net_sysctl_init(net);
+ if (ret)
+ dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+
+ return ret;
+}
+
+static void __net_exit xfrm4_net_exit(struct net *net)
+{
+ xfrm4_net_sysctl_exit(net);
+ dst_entries_destroy(&net->xfrm.xfrm4_dst_ops);
+}
static struct pernet_operations __net_initdata xfrm4_net_ops = {
.init = xfrm4_net_init,
.exit = xfrm4_net_exit,
};
-#endif
static void __init xfrm4_policy_init(void)
{
@@ -349,13 +381,9 @@ static void __init xfrm4_policy_init(void)
void __init xfrm4_init(void)
{
- dst_entries_init(&xfrm4_dst_ops);
-
xfrm4_state_init();
xfrm4_policy_init();
xfrm4_protocol_init();
-#ifdef CONFIG_SYSCTL
register_pernet_subsys(&xfrm4_net_ops);
-#endif
}
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d72fa90..1f21087 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -350,6 +350,12 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
setup_timer(&ndev->rs_timer, addrconf_rs_timer,
(unsigned long)ndev);
memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));
+
+ if (ndev->cnf.stable_secret.initialized)
+ ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
+ else
+ ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64;
+
ndev->cnf.mtu6 = dev->mtu;
ndev->cnf.sysctl = NULL;
ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
@@ -418,6 +424,7 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
if (err) {
ipv6_mc_destroy_dev(ndev);
del_timer(&ndev->regen_timer);
+ snmp6_unregister_dev(ndev);
goto err_release;
}
/* protected by rtnl_lock */
@@ -2454,7 +2461,7 @@ ok:
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD
if (in6_dev->cnf.optimistic_dad &&
!net->ipv6.devconf_all->forwarding && sllao)
- addr_flags = IFA_F_OPTIMISTIC;
+ addr_flags |= IFA_F_OPTIMISTIC;
#endif
/* Do not allow to create too much of autoconfigured
@@ -3641,7 +3648,7 @@ static void addrconf_dad_work(struct work_struct *w)
/* send a neighbour solicitation for our addr */
addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
- ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any, NULL);
+ ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any);
out:
in6_ifa_put(ifp);
rtnl_unlock();
@@ -5362,13 +5369,10 @@ static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write,
goto out;
}
- if (!write) {
- err = snprintf(str, sizeof(str), "%pI6",
- &secret->secret);
- if (err >= sizeof(str)) {
- err = -EIO;
- goto out;
- }
+ err = snprintf(str, sizeof(str), "%pI6", &secret->secret);
+ if (err >= sizeof(str)) {
+ err = -EIO;
+ goto out;
}
err = proc_dostring(&lctl, write, buffer, lenp, ppos);
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index 882124e..a8f6986 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -552,7 +552,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh)
rcu_read_lock();
p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
- if (p && ip6addrlbl_hold(p))
+ if (p && !ip6addrlbl_hold(p))
p = NULL;
lseq = ip6addrlbl_table.seq;
rcu_read_unlock();
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 44bb66b..9f5137c 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -109,6 +109,9 @@ static int inet6_create(struct net *net, struct socket *sock, int protocol,
int try_loading_module = 0;
int err;
+ if (protocol < 0 || protocol >= IPPROTO_MAX)
+ return -EINVAL;
+
/* Look for the requested type/protocol pair. */
lookup_protocol:
err = -ESOCKTNOSUPPORT;
@@ -428,9 +431,11 @@ void inet6_destroy_sock(struct sock *sk)
/* Free tx options */
- opt = xchg(&np->opt, NULL);
- if (opt)
- sock_kfree_s(sk, opt, opt->tot_len);
+ opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL);
+ if (opt) {
+ atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+ txopt_put(opt);
+ }
}
EXPORT_SYMBOL_GPL(inet6_destroy_sock);
@@ -659,7 +664,10 @@ int inet6_sk_rebuild_header(struct sock *sk)
fl6.fl6_sport = inet->inet_sport;
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
- final_p = fl6_update_dst(&fl6, np->opt, &final);
+ rcu_read_lock();
+ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt),
+ &final);
+ rcu_read_unlock();
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
if (IS_ERR(dst)) {
@@ -668,7 +676,7 @@ int inet6_sk_rebuild_header(struct sock *sk)
return PTR_ERR(dst);
}
- __ip6_dst_store(sk, dst, NULL, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
}
return 0;
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index d70b023..517c55b 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -167,8 +167,10 @@ ipv4_connected:
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
- opt = flowlabel ? flowlabel->opt : np->opt;
+ rcu_read_lock();
+ opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt);
final_p = fl6_update_dst(&fl6, opt, &final);
+ rcu_read_unlock();
dst = ip6_dst_lookup_flow(sk, &fl6, final_p);
err = 0;
diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
index ce203b0..ea7c4d6 100644
--- a/net/ipv6/exthdrs.c
+++ b/net/ipv6/exthdrs.c
@@ -727,6 +727,7 @@ ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt)
*((char **)&opt2->dst1opt) += dif;
if (opt2->srcrt)
*((char **)&opt2->srcrt) += dif;
+ atomic_set(&opt2->refcnt, 1);
}
return opt2;
}
@@ -790,7 +791,7 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
return ERR_PTR(-ENOBUFS);
memset(opt2, 0, tot_len);
-
+ atomic_set(&opt2->refcnt, 1);
opt2->tot_len = tot_len;
p = (char *)(opt2 + 1);
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index 36c5a98..0a37ddc 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -834,11 +834,6 @@ void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6,
security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
}
-/*
- * Special lock-class for __icmpv6_sk:
- */
-static struct lock_class_key icmpv6_socket_sk_dst_lock_key;
-
static int __net_init icmpv6_sk_init(struct net *net)
{
struct sock *sk;
@@ -860,15 +855,6 @@ static int __net_init icmpv6_sk_init(struct net *net)
net->ipv6.icmp_sk[i] = sk;
- /*
- * Split off their lock-class, because sk->sk_dst_lock
- * gets used from softirqs, which is safe for
- * __icmpv6_sk (because those never get directly used
- * via userspace syscalls), but unsafe for normal sockets.
- */
- lockdep_set_class(&sk->sk_dst_lock,
- &icmpv6_socket_sk_dst_lock_key);
-
/* Enough space for 2 64K ICMP packets, including
* sk_buff struct overhead.
*/
diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c
index 5d1c7ce..a7ca2cd 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -78,7 +78,9 @@ struct dst_entry *inet6_csk_route_req(const struct sock *sk,
memset(fl6, 0, sizeof(*fl6));
fl6->flowi6_proto = proto;
fl6->daddr = ireq->ir_v6_rmt_addr;
- final_p = fl6_update_dst(fl6, np->opt, &final);
+ rcu_read_lock();
+ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+ rcu_read_unlock();
fl6->saddr = ireq->ir_v6_loc_addr;
fl6->flowi6_oif = ireq->ir_iif;
fl6->flowi6_mark = ireq->ir_mark;
@@ -109,14 +111,6 @@ void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr)
EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr);
static inline
-void __inet6_csk_dst_store(struct sock *sk, struct dst_entry *dst,
- const struct in6_addr *daddr,
- const struct in6_addr *saddr)
-{
- __ip6_dst_store(sk, dst, daddr, saddr);
-}
-
-static inline
struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie)
{
return __sk_dst_check(sk, cookie);
@@ -142,14 +136,16 @@ static struct dst_entry *inet6_csk_route_socket(struct sock *sk,
fl6->fl6_dport = inet->inet_dport;
security_sk_classify_flow(sk, flowi6_to_flowi(fl6));
- final_p = fl6_update_dst(fl6, np->opt, &final);
+ rcu_read_lock();
+ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+ rcu_read_unlock();
dst = __inet6_csk_dst_check(sk, np->dst_cookie);
if (!dst) {
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (!IS_ERR(dst))
- __inet6_csk_dst_store(sk, dst, NULL, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
}
return dst;
}
@@ -175,7 +171,8 @@ int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused
/* Restore final destination back after routing done */
fl6.daddr = sk->sk_v6_daddr;
- res = ip6_xmit(sk, skb, &fl6, np->opt, np->tclass);
+ res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt),
+ np->tclass);
rcu_read_unlock();
return res;
}
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 3c7b931..e5ea177 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -1571,13 +1571,11 @@ static int ip6gre_changelink(struct net_device *dev, struct nlattr *tb[],
return -EEXIST;
} else {
t = nt;
-
- ip6gre_tunnel_unlink(ign, t);
- ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
- ip6gre_tunnel_link(ign, t);
- netdev_state_change(dev);
}
+ ip6gre_tunnel_unlink(ign, t);
+ ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]);
+ ip6gre_tunnel_link(ign, t);
return 0;
}
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index eabffbb..137fca4 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -177,7 +177,7 @@ void ip6_tnl_dst_reset(struct ip6_tnl *t)
int i;
for_each_possible_cpu(i)
- ip6_tnl_per_cpu_dst_set(raw_cpu_ptr(t->dst_cache), NULL);
+ ip6_tnl_per_cpu_dst_set(per_cpu_ptr(t->dst_cache, i), NULL);
}
EXPORT_SYMBOL_GPL(ip6_tnl_dst_reset);
diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index ad19136..a10e771 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -118,7 +118,7 @@ static void mr6_netlink_event(struct mr6_table *mrt, struct mfc6_cache *mfc,
int cmd);
static int ip6mr_rtm_dumproute(struct sk_buff *skb,
struct netlink_callback *cb);
-static void mroute_clean_tables(struct mr6_table *mrt);
+static void mroute_clean_tables(struct mr6_table *mrt, bool all);
static void ipmr_expire_process(unsigned long arg);
#ifdef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES
@@ -334,7 +334,7 @@ static struct mr6_table *ip6mr_new_table(struct net *net, u32 id)
static void ip6mr_free_table(struct mr6_table *mrt)
{
del_timer_sync(&mrt->ipmr_expire_timer);
- mroute_clean_tables(mrt);
+ mroute_clean_tables(mrt, true);
kfree(mrt);
}
@@ -765,10 +765,6 @@ static struct net_device *ip6mr_reg_vif(struct net *net, struct mr6_table *mrt)
return dev;
failure:
- /* allow the register to be completed before unregistering. */
- rtnl_unlock();
- rtnl_lock();
-
unregister_netdevice(dev);
return NULL;
}
@@ -1542,7 +1538,7 @@ static int ip6mr_mfc_add(struct net *net, struct mr6_table *mrt,
* Close the multicast socket, and clear the vif tables etc
*/
-static void mroute_clean_tables(struct mr6_table *mrt)
+static void mroute_clean_tables(struct mr6_table *mrt, bool all)
{
int i;
LIST_HEAD(list);
@@ -1552,8 +1548,9 @@ static void mroute_clean_tables(struct mr6_table *mrt)
* Shut down all active vif entries
*/
for (i = 0; i < mrt->maxvif; i++) {
- if (!(mrt->vif6_table[i].flags & VIFF_STATIC))
- mif6_delete(mrt, i, &list);
+ if (!all && (mrt->vif6_table[i].flags & VIFF_STATIC))
+ continue;
+ mif6_delete(mrt, i, &list);
}
unregister_netdevice_many(&list);
@@ -1562,7 +1559,7 @@ static void mroute_clean_tables(struct mr6_table *mrt)
*/
for (i = 0; i < MFC6_LINES; i++) {
list_for_each_entry_safe(c, next, &mrt->mfc6_cache_array[i], list) {
- if (c->mfc_flags & MFC_STATIC)
+ if (!all && (c->mfc_flags & MFC_STATIC))
continue;
write_lock_bh(&mrt_lock);
list_del(&c->list);
@@ -1625,7 +1622,7 @@ int ip6mr_sk_done(struct sock *sk)
net->ipv6.devconf_all);
write_unlock_bh(&mrt_lock);
- mroute_clean_tables(mrt);
+ mroute_clean_tables(mrt, false);
err = 0;
break;
}
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 63e6956..4449ad1 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -111,7 +111,8 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
}
}
- opt = xchg(&inet6_sk(sk)->opt, opt);
+ opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt,
+ opt);
sk_dst_reset(sk);
return opt;
@@ -231,9 +232,12 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
sk->sk_socket->ops = &inet_dgram_ops;
sk->sk_family = PF_INET;
}
- opt = xchg(&np->opt, NULL);
- if (opt)
- sock_kfree_s(sk, opt, opt->tot_len);
+ opt = xchg((__force struct ipv6_txoptions **)&np->opt,
+ NULL);
+ if (opt) {
+ atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+ txopt_put(opt);
+ }
pktopt = xchg(&np->pktoptions, NULL);
kfree_skb(pktopt);
@@ -403,7 +407,8 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW))
break;
- opt = ipv6_renew_options(sk, np->opt, optname,
+ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+ opt = ipv6_renew_options(sk, opt, optname,
(struct ipv6_opt_hdr __user *)optval,
optlen);
if (IS_ERR(opt)) {
@@ -432,8 +437,10 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
retv = 0;
opt = ipv6_update_options(sk, opt);
sticky_done:
- if (opt)
- sock_kfree_s(sk, opt, opt->tot_len);
+ if (opt) {
+ atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+ txopt_put(opt);
+ }
break;
}
@@ -486,6 +493,7 @@ sticky_done:
break;
memset(opt, 0, sizeof(*opt));
+ atomic_set(&opt->refcnt, 1);
opt->tot_len = sizeof(*opt) + optlen;
retv = -EFAULT;
if (copy_from_user(opt+1, optval, optlen))
@@ -502,8 +510,10 @@ update:
retv = 0;
opt = ipv6_update_options(sk, opt);
done:
- if (opt)
- sock_kfree_s(sk, opt, opt->tot_len);
+ if (opt) {
+ atomic_sub(opt->tot_len, &sk->sk_omem_alloc);
+ txopt_put(opt);
+ }
break;
}
case IPV6_UNICAST_HOPS:
@@ -1110,10 +1120,11 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
case IPV6_RTHDR:
case IPV6_DSTOPTS:
{
+ struct ipv6_txoptions *opt;
lock_sock(sk);
- len = ipv6_getsockopt_sticky(sk, np->opt,
- optname, optval, len);
+ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+ len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len);
release_sock(sk);
/* check if ipv6_getsockopt_sticky() returns err code */
if (len < 0)
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 124338a..5ee56d0 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -1651,7 +1651,6 @@ out:
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT);
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
- IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, payload_len);
} else {
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
}
@@ -2015,7 +2014,6 @@ out:
if (!err) {
ICMP6MSGOUT_INC_STATS(net, idev, type);
ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS);
- IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, full_len);
} else
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 3e0f855..84afb9a 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -556,8 +556,7 @@ static void ndisc_send_unsol_na(struct net_device *dev)
}
void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
- const struct in6_addr *daddr, const struct in6_addr *saddr,
- struct sk_buff *oskb)
+ const struct in6_addr *daddr, const struct in6_addr *saddr)
{
struct sk_buff *skb;
struct in6_addr addr_buf;
@@ -593,9 +592,6 @@ void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,
ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR,
dev->dev_addr);
- if (!(dev->priv_flags & IFF_XMIT_DST_RELEASE) && oskb)
- skb_dst_copy(skb, oskb);
-
ndisc_send_skb(skb, daddr, saddr);
}
@@ -682,12 +678,12 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
"%s: trying to ucast probe in NUD_INVALID: %pI6\n",
__func__, target);
}
- ndisc_send_ns(dev, target, target, saddr, skb);
+ ndisc_send_ns(dev, target, target, saddr);
} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {
neigh_app_ns(neigh);
} else {
addrconf_addr_solict_mult(target, &mcaddr);
- ndisc_send_ns(dev, target, &mcaddr, saddr, skb);
+ ndisc_send_ns(dev, target, &mcaddr, saddr);
}
}
@@ -1187,7 +1183,7 @@ static void ndisc_router_discovery(struct sk_buff *skb)
*/
if (!in6_dev->cnf.accept_ra_from_local &&
ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
- NULL, 0)) {
+ in6_dev->dev, 0)) {
ND_PRINTK(2, info,
"RA from local address detected on dev: %s: default router ignored\n",
skb->dev->name);
@@ -1341,7 +1337,7 @@ skip_linkparms:
#ifdef CONFIG_IPV6_ROUTE_INFO
if (!in6_dev->cnf.accept_ra_from_local &&
ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr,
- NULL, 0)) {
+ in6_dev->dev, 0)) {
ND_PRINTK(2, info,
"RA from local address detected on dev: %s: router info ignored.\n",
skb->dev->name);
diff --git a/net/ipv6/netfilter/Kconfig b/net/ipv6/netfilter/Kconfig
index f6a024e..e10a04c 100644
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -49,6 +49,7 @@ config NFT_REJECT_IPV6
config NFT_DUP_IPV6
tristate "IPv6 nf_tables packet duplication support"
+ depends on !NF_CONNTRACK || NF_CONNTRACK
select NF_DUP_IPV6
help
This module enables IPv6 packet duplication support for nf_tables.
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index d5efeb8..bab4441 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -190,7 +190,7 @@ static void nf_ct_frag6_expire(unsigned long data)
/* Creation primitives. */
static inline struct frag_queue *fq_find(struct net *net, __be32 id,
u32 user, struct in6_addr *src,
- struct in6_addr *dst, u8 ecn)
+ struct in6_addr *dst, int iif, u8 ecn)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -200,6 +200,7 @@ static inline struct frag_queue *fq_find(struct net *net, __be32 id,
arg.user = user;
arg.src = src;
arg.dst = dst;
+ arg.iif = iif;
arg.ecn = ecn;
local_bh_disable();
@@ -601,7 +602,7 @@ struct sk_buff *nf_ct_frag6_gather(struct net *net, struct sk_buff *skb, u32 use
fhdr = (struct frag_hdr *)skb_transport_header(clone);
fq = fq_find(net, fhdr->identification, user, &hdr->saddr, &hdr->daddr,
- ip6_frag_ecn(hdr));
+ skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
if (fq == NULL) {
pr_debug("Can't find and can't create new queue\n");
goto ret_orig;
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index dc65ec1..9914098 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -733,6 +733,7 @@ static int raw6_getfrag(void *from, char *to, int offset, int len, int odd,
static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
+ struct ipv6_txoptions *opt_to_free = NULL;
struct ipv6_txoptions opt_space;
DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
struct in6_addr *daddr, *final_p, final;
@@ -839,8 +840,10 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
if (!(opt->opt_nflen|opt->opt_flen))
opt = NULL;
}
- if (!opt)
- opt = np->opt;
+ if (!opt) {
+ opt = txopt_get(np);
+ opt_to_free = opt;
+ }
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
opt = ipv6_fixup_options(&opt_space, opt);
@@ -906,6 +909,7 @@ done:
dst_release(dst);
out:
fl6_sock_release(flowlabel);
+ txopt_put(opt_to_free);
return err < 0 ? err : len;
do_confirm:
dst_confirm(dst);
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 44e21a0..45f5ae5 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -108,7 +108,10 @@ bool ip6_frag_match(const struct inet_frag_queue *q, const void *a)
return fq->id == arg->id &&
fq->user == arg->user &&
ipv6_addr_equal(&fq->saddr, arg->src) &&
- ipv6_addr_equal(&fq->daddr, arg->dst);
+ ipv6_addr_equal(&fq->daddr, arg->dst) &&
+ (arg->iif == fq->iif ||
+ !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST |
+ IPV6_ADDR_LINKLOCAL)));
}
EXPORT_SYMBOL(ip6_frag_match);
@@ -180,7 +183,7 @@ static void ip6_frag_expire(unsigned long data)
static struct frag_queue *
fq_find(struct net *net, __be32 id, const struct in6_addr *src,
- const struct in6_addr *dst, u8 ecn)
+ const struct in6_addr *dst, int iif, u8 ecn)
{
struct inet_frag_queue *q;
struct ip6_create_arg arg;
@@ -190,6 +193,7 @@ fq_find(struct net *net, __be32 id, const struct in6_addr *src,
arg.user = IP6_DEFRAG_LOCAL_DELIVER;
arg.src = src;
arg.dst = dst;
+ arg.iif = iif;
arg.ecn = ecn;
hash = inet6_hash_frag(id, src, dst);
@@ -551,7 +555,7 @@ static int ipv6_frag_rcv(struct sk_buff *skb)
}
fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr,
- ip6_frag_ecn(hdr));
+ skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr));
if (fq) {
int ret;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c8bc9b4..826e6aa 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -404,6 +404,14 @@ static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
}
}
+static bool __rt6_check_expired(const struct rt6_info *rt)
+{
+ if (rt->rt6i_flags & RTF_EXPIRES)
+ return time_after(jiffies, rt->dst.expires);
+ else
+ return false;
+}
+
static bool rt6_check_expired(const struct rt6_info *rt)
{
if (rt->rt6i_flags & RTF_EXPIRES) {
@@ -515,7 +523,7 @@ static void rt6_probe_deferred(struct work_struct *w)
container_of(w, struct __rt6_probe_work, work);
addrconf_addr_solict_mult(&work->target, &mcaddr);
- ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL, NULL);
+ ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL);
dev_put(work->dev);
kfree(work);
}
@@ -1252,7 +1260,8 @@ static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie)
static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie)
{
- if (rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
+ if (!__rt6_check_expired(rt) &&
+ rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK &&
rt6_check((struct rt6_info *)(rt->dst.from), cookie))
return &rt->dst;
else
@@ -1272,7 +1281,8 @@ static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie)
rt6_dst_from_metrics_check(rt);
- if ((rt->rt6i_flags & RTF_PCPU) || unlikely(dst->flags & DST_NOCACHE))
+ if (rt->rt6i_flags & RTF_PCPU ||
+ (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from))
return rt6_dst_from_check(rt, cookie);
else
return rt6_check(rt, cookie);
@@ -1322,6 +1332,12 @@ static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu)
rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires);
}
+static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
+{
+ return !(rt->rt6i_flags & RTF_CACHE) &&
+ (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node);
+}
+
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
const struct ipv6hdr *iph, u32 mtu)
{
@@ -1335,7 +1351,7 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
if (mtu >= dst_mtu(dst))
return;
- if (rt6->rt6i_flags & RTF_CACHE) {
+ if (!rt6_cache_allowed_for_pmtu(rt6)) {
rt6_do_update_pmtu(rt6, mtu);
} else {
const struct in6_addr *daddr, *saddr;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index bb8f2fa..eaf7ac4 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -222,7 +222,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
memset(&fl6, 0, sizeof(fl6));
fl6.flowi6_proto = IPPROTO_TCP;
fl6.daddr = ireq->ir_v6_rmt_addr;
- final_p = fl6_update_dst(&fl6, np->opt, &final);
+ final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), &final);
fl6.saddr = ireq->ir_v6_loc_addr;
fl6.flowi6_oif = sk->sk_bound_dev_if;
fl6.flowi6_mark = ireq->ir_mark;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ea2f4d5..6b8a8a9 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -93,10 +93,9 @@ static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
- if (dst) {
+ if (dst && dst_hold_safe(dst)) {
const struct rt6_info *rt = (const struct rt6_info *)dst;
- dst_hold(dst);
sk->sk_rx_dst = dst;
inet_sk(sk)->rx_dst_ifindex = skb->skb_iif;
inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
@@ -120,6 +119,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct ipv6_pinfo *np = inet6_sk(sk);
struct tcp_sock *tp = tcp_sk(sk);
struct in6_addr *saddr = NULL, *final_p, final;
+ struct ipv6_txoptions *opt;
struct flowi6 fl6;
struct dst_entry *dst;
int addr_type;
@@ -235,7 +235,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
fl6.fl6_dport = usin->sin6_port;
fl6.fl6_sport = inet->inet_sport;
- final_p = fl6_update_dst(&fl6, np->opt, &final);
+ opt = rcu_dereference_protected(np->opt, sock_owned_by_user(sk));
+ final_p = fl6_update_dst(&fl6, opt, &final);
security_sk_classify_flow(sk, flowi6_to_flowi(&fl6));
@@ -255,7 +256,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
inet->inet_rcv_saddr = LOOPBACK4_IPV6;
sk->sk_gso_type = SKB_GSO_TCPV6;
- __ip6_dst_store(sk, dst, NULL, NULL);
+ ip6_dst_store(sk, dst, NULL, NULL);
if (tcp_death_row.sysctl_tw_recycle &&
!tp->rx_opt.ts_recent_stamp &&
@@ -263,9 +264,9 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
tcp_fetch_timewait_stamp(sk, dst);
icsk->icsk_ext_hdr_len = 0;
- if (np->opt)
- icsk->icsk_ext_hdr_len = (np->opt->opt_flen +
- np->opt->opt_nflen);
+ if (opt)
+ icsk->icsk_ext_hdr_len = opt->opt_flen +
+ opt->opt_nflen;
tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
@@ -461,7 +462,8 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
if (np->repflow && ireq->pktopts)
fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts));
- err = ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+ err = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt),
+ np->tclass);
err = net_xmit_eval(err);
}
@@ -972,6 +974,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
struct inet_request_sock *ireq;
struct ipv6_pinfo *newnp;
const struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6_txoptions *opt;
struct tcp6_sock *newtcp6sk;
struct inet_sock *newinet;
struct tcp_sock *newtp;
@@ -1056,7 +1059,7 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
*/
newsk->sk_gso_type = SKB_GSO_TCPV6;
- __ip6_dst_store(newsk, dst, NULL, NULL);
+ ip6_dst_store(newsk, dst, NULL, NULL);
inet6_sk_rx_dst_set(newsk, skb);
newtcp6sk = (struct tcp6_sock *)newsk;
@@ -1098,13 +1101,15 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
but we make one more one thing there: reattach optmem
to newsk.
*/
- if (np->opt)
- newnp->opt = ipv6_dup_options(newsk, np->opt);
-
+ opt = rcu_dereference(np->opt);
+ if (opt) {
+ opt = ipv6_dup_options(newsk, opt);
+ RCU_INIT_POINTER(newnp->opt, opt);
+ }
inet_csk(newsk)->icsk_ext_hdr_len = 0;
- if (newnp->opt)
- inet_csk(newsk)->icsk_ext_hdr_len = (newnp->opt->opt_nflen +
- newnp->opt->opt_flen);
+ if (opt)
+ inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen +
+ opt->opt_flen;
tcp_ca_openreq_child(newsk, dst);
@@ -1140,14 +1145,18 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
goto out;
}
*own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash));
- /* Clone pktoptions received with SYN, if we own the req */
- if (*own_req && ireq->pktopts) {
- newnp->pktoptions = skb_clone(ireq->pktopts,
- sk_gfp_atomic(sk, GFP_ATOMIC));
- consume_skb(ireq->pktopts);
- ireq->pktopts = NULL;
- if (newnp->pktoptions)
- skb_set_owner_r(newnp->pktoptions, newsk);
+ if (*own_req) {
+ tcp_move_syn(newtp, req);
+
+ /* Clone pktoptions received with SYN, if we own the req */
+ if (ireq->pktopts) {
+ newnp->pktoptions = skb_clone(ireq->pktopts,
+ sk_gfp_atomic(sk, GFP_ATOMIC));
+ consume_skb(ireq->pktopts);
+ ireq->pktopts = NULL;
+ if (newnp->pktoptions)
+ skb_set_owner_r(newnp->pktoptions, newsk);
+ }
}
return newsk;
@@ -1686,6 +1695,8 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
const struct tcp_sock *tp = tcp_sk(sp);
const struct inet_connection_sock *icsk = inet_csk(sp);
const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq;
+ int rx_queue;
+ int state;
dest = &sp->sk_v6_daddr;
src = &sp->sk_v6_rcv_saddr;
@@ -1706,6 +1717,15 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
timer_expires = jiffies;
}
+ state = sk_state_load(sp);
+ if (state == TCP_LISTEN)
+ rx_queue = sp->sk_ack_backlog;
+ else
+ /* Because we don't lock the socket,
+ * we might find a transient negative value.
+ */
+ rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0);
+
seq_printf(seq,
"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
"%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n",
@@ -1714,9 +1734,9 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
src->s6_addr32[2], src->s6_addr32[3], srcp,
dest->s6_addr32[0], dest->s6_addr32[1],
dest->s6_addr32[2], dest->s6_addr32[3], destp,
- sp->sk_state,
- tp->write_seq-tp->snd_una,
- (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq),
+ state,
+ tp->write_seq - tp->snd_una,
+ rx_queue,
timer_active,
jiffies_delta_to_clock_t(timer_expires - jiffies),
icsk->icsk_retransmits,
@@ -1728,7 +1748,7 @@ static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i)
jiffies_to_clock_t(icsk->icsk_ack.ato),
(icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong,
tp->snd_cwnd,
- sp->sk_state == TCP_LISTEN ?
+ state == TCP_LISTEN ?
fastopenq->max_qlen :
(tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh)
);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 01bcb49..9da3287 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -1110,6 +1110,7 @@ int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name);
struct in6_addr *daddr, *final_p, final;
struct ipv6_txoptions *opt = NULL;
+ struct ipv6_txoptions *opt_to_free = NULL;
struct ip6_flowlabel *flowlabel = NULL;
struct flowi6 fl6;
struct dst_entry *dst;
@@ -1263,8 +1264,10 @@ do_udp_sendmsg:
opt = NULL;
connected = 0;
}
- if (!opt)
- opt = np->opt;
+ if (!opt) {
+ opt = txopt_get(np);
+ opt_to_free = opt;
+ }
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
opt = ipv6_fixup_options(&opt_space, opt);
@@ -1373,6 +1376,7 @@ release_dst:
out:
dst_release(dst);
fl6_sock_release(flowlabel);
+ txopt_put(opt_to_free);
if (!err)
return len;
/*
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 5643423..c074771 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -279,7 +279,7 @@ static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev,
xfrm_dst_ifdown(dst, dev);
}
-static struct dst_ops xfrm6_dst_ops = {
+static struct dst_ops xfrm6_dst_ops_template = {
.family = AF_INET6,
.gc = xfrm6_garbage_collect,
.update_pmtu = xfrm6_update_pmtu,
@@ -293,7 +293,7 @@ static struct dst_ops xfrm6_dst_ops = {
static struct xfrm_policy_afinfo xfrm6_policy_afinfo = {
.family = AF_INET6,
- .dst_ops = &xfrm6_dst_ops,
+ .dst_ops = &xfrm6_dst_ops_template,
.dst_lookup = xfrm6_dst_lookup,
.get_saddr = xfrm6_get_saddr,
.decode_session = _decode_session6,
@@ -325,7 +325,7 @@ static struct ctl_table xfrm6_policy_table[] = {
{ }
};
-static int __net_init xfrm6_net_init(struct net *net)
+static int __net_init xfrm6_net_sysctl_init(struct net *net)
{
struct ctl_table *table;
struct ctl_table_header *hdr;
@@ -353,7 +353,7 @@ err_alloc:
return -ENOMEM;
}
-static void __net_exit xfrm6_net_exit(struct net *net)
+static void __net_exit xfrm6_net_sysctl_exit(struct net *net)
{
struct ctl_table *table;
@@ -365,24 +365,52 @@ static void __net_exit xfrm6_net_exit(struct net *net)
if (!net_eq(net, &init_net))
kfree(table);
}
+#else /* CONFIG_SYSCTL */
+static int inline xfrm6_net_sysctl_init(struct net *net)
+{
+ return 0;
+}
+
+static void inline xfrm6_net_sysctl_exit(struct net *net)
+{
+}
+#endif
+
+static int __net_init xfrm6_net_init(struct net *net)
+{
+ int ret;
+
+ memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template,
+ sizeof(xfrm6_dst_ops_template));
+ ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops);
+ if (ret)
+ return ret;
+
+ ret = xfrm6_net_sysctl_init(net);
+ if (ret)
+ dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+
+ return ret;
+}
+
+static void __net_exit xfrm6_net_exit(struct net *net)
+{
+ xfrm6_net_sysctl_exit(net);
+ dst_entries_destroy(&net->xfrm.xfrm6_dst_ops);
+}
static struct pernet_operations xfrm6_net_ops = {
.init = xfrm6_net_init,
.exit = xfrm6_net_exit,
};
-#endif
int __init xfrm6_init(void)
{
int ret;
- dst_entries_init(&xfrm6_dst_ops);
-
ret = xfrm6_policy_init();
- if (ret) {
- dst_entries_destroy(&xfrm6_dst_ops);
+ if (ret)
goto out;
- }
ret = xfrm6_state_init();
if (ret)
goto out_policy;
@@ -391,9 +419,7 @@ int __init xfrm6_init(void)
if (ret)
goto out_state;
-#ifdef CONFIG_SYSCTL
register_pernet_subsys(&xfrm6_net_ops);
-#endif
out:
return ret;
out_state:
@@ -405,11 +431,8 @@ out_policy:
void xfrm6_fini(void)
{
-#ifdef CONFIG_SYSCTL
unregister_pernet_subsys(&xfrm6_net_ops);
-#endif
xfrm6_protocol_fini();
xfrm6_policy_fini();
xfrm6_state_fini();
- dst_entries_destroy(&xfrm6_dst_ops);
}
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index e6aa48b..923abd6 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -1086,6 +1086,9 @@ static int irda_create(struct net *net, struct socket *sock, int protocol,
struct sock *sk;
struct irda_sock *self;
+ if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+ return -EINVAL;
+
if (net != &init_net)
return -EAFNOSUPPORT;
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index fcb2752..435608c 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1483,7 +1483,7 @@ unsigned int iucv_sock_poll(struct file *file, struct socket *sock,
if (sock_writeable(sk) && iucv_below_msglim(sk))
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
return mask;
}
diff --git a/net/l2tp/l2tp_ip6.c b/net/l2tp/l2tp_ip6.c
index aca38d8..a2c8747 100644
--- a/net/l2tp/l2tp_ip6.c
+++ b/net/l2tp/l2tp_ip6.c
@@ -486,6 +486,7 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
DECLARE_SOCKADDR(struct sockaddr_l2tpip6 *, lsa, msg->msg_name);
struct in6_addr *daddr, *final_p, final;
struct ipv6_pinfo *np = inet6_sk(sk);
+ struct ipv6_txoptions *opt_to_free = NULL;
struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL;
struct dst_entry *dst = NULL;
@@ -575,8 +576,10 @@ static int l2tp_ip6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
opt = NULL;
}
- if (opt == NULL)
- opt = np->opt;
+ if (!opt) {
+ opt = txopt_get(np);
+ opt_to_free = opt;
+ }
if (flowlabel)
opt = fl6_merge_options(&opt_space, flowlabel, opt);
opt = ipv6_fixup_options(&opt_space, opt);
@@ -631,6 +634,7 @@ done:
dst_release(dst);
out:
fl6_sock_release(flowlabel);
+ txopt_put(opt_to_free);
return err < 0 ? err : len;
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index a758eb84..ff75718 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -500,7 +500,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
/* send AddBA request */
ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
tid_tx->dialog_token, start_seq_num,
- local->hw.max_tx_aggregation_subframes,
+ IEEE80211_MAX_AMPDU_BUF,
tid_tx->timeout);
}
@@ -926,6 +926,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
amsdu = capab & IEEE80211_ADDBA_PARAM_AMSDU_MASK;
tid = (capab & IEEE80211_ADDBA_PARAM_TID_MASK) >> 2;
buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6;
+ buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes);
mutex_lock(&sta->ampdu_mlme.mtx);
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index c2bd1b6..c12f348 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1169,8 +1169,7 @@ static int sta_apply_parameters(struct ieee80211_local *local,
* rc isn't initialized here yet, so ignore it
*/
__ieee80211_vht_handle_opmode(sdata, sta,
- params->opmode_notif,
- band, false);
+ params->opmode_notif, band);
}
if (ieee80211_vif_is_mesh(&sdata->vif))
@@ -3454,8 +3453,12 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
goto out_unlock;
}
} else {
- /* for cookie below */
- ack_skb = skb;
+ /* Assign a dummy non-zero cookie, it's not sent to
+ * userspace in this case but we rely on its value
+ * internally in the need_offchan case to distinguish
+ * mgmt-tx from remain-on-channel.
+ */
+ *cookie = 0xffffffff;
}
if (!need_offchan) {
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d832bd5..5322b4c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1709,10 +1709,10 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta);
void ieee80211_sta_set_rx_nss(struct sta_info *sta);
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode,
- enum ieee80211_band band, bool nss_only);
+ enum ieee80211_band band);
void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode,
- enum ieee80211_band band, bool nss_only);
+ enum ieee80211_band band);
void ieee80211_apply_vhtcap_overrides(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_vht_cap *vht_cap);
void ieee80211_get_vht_mask_from_cap(__le16 vht_cap,
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index d0dc1bf..c9e325d 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -76,7 +76,8 @@ bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
bool update_bss)
{
- if (__ieee80211_recalc_txpower(sdata) || update_bss)
+ if (__ieee80211_recalc_txpower(sdata) ||
+ (update_bss && ieee80211_sdata_running(sdata)))
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
}
@@ -1861,6 +1862,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
unregister_netdevice(sdata->dev);
} else {
cfg80211_unregister_wdev(&sdata->wdev);
+ ieee80211_teardown_sdata(sdata);
kfree(sdata);
}
}
@@ -1870,7 +1872,6 @@ void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata)
if (WARN_ON_ONCE(!test_bit(SDATA_STATE_RUNNING, &sdata->state)))
return;
ieee80211_do_stop(sdata, true);
- ieee80211_teardown_sdata(sdata);
}
void ieee80211_remove_interfaces(struct ieee80211_local *local)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 858f6b1..175ffcf 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -541,8 +541,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
NL80211_FEATURE_HT_IBSS |
NL80211_FEATURE_VIF_TXPOWER |
NL80211_FEATURE_MAC_ON_CREATE |
- NL80211_FEATURE_USERSPACE_MPM |
- NL80211_FEATURE_FULL_AP_CLIENT_STATE;
+ NL80211_FEATURE_USERSPACE_MPM;
if (!ops->hw_scan)
wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index b890e22..b3b44a5 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -779,10 +779,8 @@ void mesh_plink_broken(struct sta_info *sta)
static void mesh_path_node_reclaim(struct rcu_head *rp)
{
struct mpath_node *node = container_of(rp, struct mpath_node, rcu);
- struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
del_timer_sync(&node->mpath->timer);
- atomic_dec(&sdata->u.mesh.mpaths);
kfree(node->mpath);
kfree(node);
}
@@ -790,8 +788,9 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
/* needs to be called with the corresponding hashwlock taken */
static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
{
- struct mesh_path *mpath;
- mpath = node->mpath;
+ struct mesh_path *mpath = node->mpath;
+ struct ieee80211_sub_if_data *sdata = node->mpath->sdata;
+
spin_lock(&mpath->state_lock);
mpath->flags |= MESH_PATH_RESOLVING;
if (mpath->is_gate)
@@ -799,6 +798,7 @@ static void __mesh_path_del(struct mesh_table *tbl, struct mpath_node *node)
hlist_del_rcu(&node->list);
call_rcu(&node->rcu, mesh_path_node_reclaim);
spin_unlock(&mpath->state_lock);
+ atomic_dec(&sdata->u.mesh.mpaths);
atomic_dec(&tbl->entries);
}
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index b140cc6..3aa0434 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1379,21 +1379,26 @@ static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
*/
if (has_80211h_pwr &&
(!has_cisco_pwr || pwr_level_80211h <= pwr_level_cisco)) {
+ new_ap_level = pwr_level_80211h;
+
+ if (sdata->ap_power_level == new_ap_level)
+ return 0;
+
sdata_dbg(sdata,
"Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
pwr_level_80211h, chan_pwr, pwr_reduction_80211h,
sdata->u.mgd.bssid);
- new_ap_level = pwr_level_80211h;
} else { /* has_cisco_pwr is always true here. */
+ new_ap_level = pwr_level_cisco;
+
+ if (sdata->ap_power_level == new_ap_level)
+ return 0;
+
sdata_dbg(sdata,
"Limiting TX power to %d dBm as advertised by %pM\n",
pwr_level_cisco, sdata->u.mgd.bssid);
- new_ap_level = pwr_level_cisco;
}
- if (sdata->ap_power_level == new_ap_level)
- return 0;
-
sdata->ap_power_level = new_ap_level;
if (__ieee80211_recalc_txpower(sdata))
return BSS_CHANGED_TXPOWER;
@@ -3575,7 +3580,7 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
if (sta && elems.opmode_notif)
ieee80211_vht_handle_opmode(sdata, sta, *elems.opmode_notif,
- rx_status->band, true);
+ rx_status->band);
mutex_unlock(&local->sta_mtx);
changed |= ieee80211_handle_pwr_constr(sdata, chan, mgmt,
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 8bae5de..82af407 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2736,8 +2736,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
opmode = mgmt->u.action.u.vht_opmode_notif.operating_mode;
ieee80211_vht_handle_opmode(rx->sdata, rx->sta,
- opmode, status->band,
- false);
+ opmode, status->band);
goto handled;
}
default:
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 4aeca4b..a413e52 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -597,8 +597,8 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata,
/* We need to ensure power level is at max for scanning. */
ieee80211_hw_config(local, 0);
- if ((req->channels[0]->flags &
- IEEE80211_CHAN_NO_IR) ||
+ if ((req->channels[0]->flags & (IEEE80211_CHAN_NO_IR |
+ IEEE80211_CHAN_RADAR)) ||
!req->n_ssids) {
next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
} else {
@@ -645,7 +645,7 @@ ieee80211_scan_get_channel_time(struct ieee80211_channel *chan)
* TODO: channel switching also consumes quite some time,
* add that delay as well to get a better estimation
*/
- if (chan->flags & IEEE80211_CHAN_NO_IR)
+ if (chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR))
return IEEE80211_PASSIVE_CHANNEL_TIME;
return IEEE80211_PROBE_DELAY + IEEE80211_CHANNEL_TIME;
}
@@ -777,7 +777,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
*
* In any case, it is not necessary for a passive scan.
*/
- if (chan->flags & IEEE80211_CHAN_NO_IR || !scan_req->n_ssids) {
+ if ((chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) ||
+ !scan_req->n_ssids) {
*next_delay = IEEE80211_PASSIVE_CHANNEL_TIME;
local->next_scan_state = SCAN_DECISION;
return;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7405802..33344f5 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1641,6 +1641,29 @@ void ieee80211_stop_device(struct ieee80211_local *local)
drv_stop(local);
}
+static void ieee80211_flush_completed_scan(struct ieee80211_local *local,
+ bool aborted)
+{
+ /* It's possible that we don't handle the scan completion in
+ * time during suspend, so if it's still marked as completed
+ * here, queue the work and flush it to clean things up.
+ * Instead of calling the worker function directly here, we
+ * really queue it to avoid potential races with other flows
+ * scheduling the same work.
+ */
+ if (test_bit(SCAN_COMPLETED, &local->scanning)) {
+ /* If coming from reconfiguration failure, abort the scan so
+ * we don't attempt to continue a partial HW scan - which is
+ * possible otherwise if (e.g.) the 2.4 GHz portion was the
+ * completed scan, and a 5 GHz portion is still pending.
+ */
+ if (aborted)
+ set_bit(SCAN_ABORTED, &local->scanning);
+ ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
+ flush_delayed_work(&local->scan_work);
+ }
+}
+
static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
@@ -1660,6 +1683,8 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
local->suspended = false;
local->in_reconfig = false;
+ ieee80211_flush_completed_scan(local, true);
+
/* scheduled scan clearly can't be running any more, but tell
* cfg80211 and clear local state
*/
@@ -1698,6 +1723,27 @@ static void ieee80211_assign_chanctx(struct ieee80211_local *local,
mutex_unlock(&local->chanctx_mtx);
}
+static void ieee80211_reconfig_stations(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ struct sta_info *sta;
+
+ /* add STAs back */
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ enum ieee80211_sta_state state;
+
+ if (!sta->uploaded || sta->sdata != sdata)
+ continue;
+
+ for (state = IEEE80211_STA_NOTEXIST;
+ state < sta->sta_state; state++)
+ WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
+ state + 1));
+ }
+ mutex_unlock(&local->sta_mtx);
+}
+
int ieee80211_reconfig(struct ieee80211_local *local)
{
struct ieee80211_hw *hw = &local->hw;
@@ -1833,50 +1879,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(drv_add_chanctx(local, ctx));
mutex_unlock(&local->chanctx_mtx);
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (!ieee80211_sdata_running(sdata))
- continue;
- ieee80211_assign_chanctx(local, sdata);
- }
-
sdata = rtnl_dereference(local->monitor_sdata);
if (sdata && ieee80211_sdata_running(sdata))
ieee80211_assign_chanctx(local, sdata);
}
- /* add STAs back */
- mutex_lock(&local->sta_mtx);
- list_for_each_entry(sta, &local->sta_list, list) {
- enum ieee80211_sta_state state;
-
- if (!sta->uploaded)
- continue;
-
- /* AP-mode stations will be added later */
- if (sta->sdata->vif.type == NL80211_IFTYPE_AP)
- continue;
-
- for (state = IEEE80211_STA_NOTEXIST;
- state < sta->sta_state; state++)
- WARN_ON(drv_sta_state(local, sta->sdata, sta, state,
- state + 1));
- }
- mutex_unlock(&local->sta_mtx);
-
- /* reconfigure tx conf */
- if (hw->queues >= IEEE80211_NUM_ACS) {
- list_for_each_entry(sdata, &local->interfaces, list) {
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
- sdata->vif.type == NL80211_IFTYPE_MONITOR ||
- !ieee80211_sdata_running(sdata))
- continue;
-
- for (i = 0; i < IEEE80211_NUM_ACS; i++)
- drv_conf_tx(local, sdata, i,
- &sdata->tx_conf[i]);
- }
- }
-
/* reconfigure hardware */
ieee80211_hw_config(local, ~0);
@@ -1889,6 +1896,22 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (!ieee80211_sdata_running(sdata))
continue;
+ ieee80211_assign_chanctx(local, sdata);
+
+ switch (sdata->vif.type) {
+ case NL80211_IFTYPE_AP_VLAN:
+ case NL80211_IFTYPE_MONITOR:
+ break;
+ default:
+ ieee80211_reconfig_stations(sdata);
+ /* fall through */
+ case NL80211_IFTYPE_AP: /* AP stations are handled later */
+ for (i = 0; i < IEEE80211_NUM_ACS; i++)
+ drv_conf_tx(local, sdata, i,
+ &sdata->tx_conf[i]);
+ break;
+ }
+
/* common change flags for all interface types */
changed = BSS_CHANGED_ERP_CTS_PROT |
BSS_CHANGED_ERP_PREAMBLE |
@@ -2074,17 +2097,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
mb();
local->resuming = false;
- /* It's possible that we don't handle the scan completion in
- * time during suspend, so if it's still marked as completed
- * here, queue the work and flush it to clean things up.
- * Instead of calling the worker function directly here, we
- * really queue it to avoid potential races with other flows
- * scheduling the same work.
- */
- if (test_bit(SCAN_COMPLETED, &local->scanning)) {
- ieee80211_queue_delayed_work(&local->hw, &local->scan_work, 0);
- flush_delayed_work(&local->scan_work);
- }
+ ieee80211_flush_completed_scan(local, false);
if (local->open_count && !reconfig_due_to_wowlan)
drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_SUSPEND);
diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c
index ff1c798..c38b2f0 100644
--- a/net/mac80211/vht.c
+++ b/net/mac80211/vht.c
@@ -378,7 +378,7 @@ void ieee80211_sta_set_rx_nss(struct sta_info *sta)
u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode,
- enum ieee80211_band band, bool nss_only)
+ enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband;
@@ -401,9 +401,6 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
changed |= IEEE80211_RC_NSS_CHANGED;
}
- if (nss_only)
- return changed;
-
switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) {
case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ:
sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20;
@@ -430,13 +427,12 @@ u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
void ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, u8 opmode,
- enum ieee80211_band band, bool nss_only)
+ enum ieee80211_band band)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band];
- u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode,
- band, nss_only);
+ u32 changed = __ieee80211_vht_handle_opmode(sdata, sta, opmode, band);
if (changed > 0)
rate_control_rate_update(local, sband, sta, changed);
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index c70d750..c32fc41 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -27,6 +27,8 @@
*/
#define MAX_MP_SELECT_LABELS 4
+#define MPLS_NEIGH_TABLE_UNSPEC (NEIGH_LINK_TABLE + 1)
+
static int zero = 0;
static int label_limit = (1 << 20) - 1;
@@ -317,7 +319,13 @@ static int mpls_forward(struct sk_buff *skb, struct net_device *dev,
}
}
- err = neigh_xmit(nh->nh_via_table, out_dev, mpls_nh_via(rt, nh), skb);
+ /* If via wasn't specified then send out using device address */
+ if (nh->nh_via_table == MPLS_NEIGH_TABLE_UNSPEC)
+ err = neigh_xmit(NEIGH_LINK_TABLE, out_dev,
+ out_dev->dev_addr, skb);
+ else
+ err = neigh_xmit(nh->nh_via_table, out_dev,
+ mpls_nh_via(rt, nh), skb);
if (err)
net_dbg_ratelimited("%s: packet transmission failed: %d\n",
__func__, err);
@@ -534,6 +542,10 @@ static int mpls_nh_assign_dev(struct net *net, struct mpls_route *rt,
if (!mpls_dev_get(dev))
goto errout;
+ if ((nh->nh_via_table == NEIGH_LINK_TABLE) &&
+ (dev->addr_len != nh->nh_via_alen))
+ goto errout;
+
RCU_INIT_POINTER(nh->nh_dev, dev);
return 0;
@@ -592,10 +604,14 @@ static int mpls_nh_build(struct net *net, struct mpls_route *rt,
goto errout;
}
- err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
- __mpls_nh_via(rt, nh));
- if (err)
- goto errout;
+ if (via) {
+ err = nla_get_via(via, &nh->nh_via_alen, &nh->nh_via_table,
+ __mpls_nh_via(rt, nh));
+ if (err)
+ goto errout;
+ } else {
+ nh->nh_via_table = MPLS_NEIGH_TABLE_UNSPEC;
+ }
err = mpls_nh_assign_dev(net, rt, nh, oif);
if (err)
@@ -677,9 +693,6 @@ static int mpls_nh_build_multi(struct mpls_route_config *cfg,
nla_newdst = nla_find(attrs, attrlen, RTA_NEWDST);
}
- if (!nla_via)
- goto errout;
-
err = mpls_nh_build(cfg->rc_nlinfo.nl_net, rt, nh,
rtnh->rtnh_ifindex, nla_via,
nla_newdst);
@@ -1118,6 +1131,7 @@ static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
cfg->rc_label = LABEL_NOT_SPECIFIED;
cfg->rc_protocol = rtm->rtm_protocol;
+ cfg->rc_via_table = MPLS_NEIGH_TABLE_UNSPEC;
cfg->rc_nlflags = nlh->nlmsg_flags;
cfg->rc_nlinfo.portid = NETLINK_CB(skb).portid;
cfg->rc_nlinfo.nlh = nlh;
@@ -1231,7 +1245,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
nla_put_labels(skb, RTA_NEWDST, nh->nh_labels,
nh->nh_label))
goto nla_put_failure;
- if (nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
+ if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
+ nla_put_via(skb, nh->nh_via_table, mpls_nh_via(rt, nh),
nh->nh_via_alen))
goto nla_put_failure;
dev = rtnl_dereference(nh->nh_dev);
@@ -1257,7 +1272,8 @@ static int mpls_dump_route(struct sk_buff *skb, u32 portid, u32 seq, int event,
nh->nh_labels,
nh->nh_label))
goto nla_put_failure;
- if (nla_put_via(skb, nh->nh_via_table,
+ if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC &&
+ nla_put_via(skb, nh->nh_via_table,
mpls_nh_via(rt, nh),
nh->nh_via_alen))
goto nla_put_failure;
@@ -1319,7 +1335,8 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
if (nh->nh_dev)
payload += nla_total_size(4); /* RTA_OIF */
- payload += nla_total_size(2 + nh->nh_via_alen); /* RTA_VIA */
+ if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC) /* RTA_VIA */
+ payload += nla_total_size(2 + nh->nh_via_alen);
if (nh->nh_labels) /* RTA_NEWDST */
payload += nla_total_size(nh->nh_labels * 4);
} else {
@@ -1328,7 +1345,9 @@ static inline size_t lfib_nlmsg_size(struct mpls_route *rt)
for_nexthops(rt) {
nhsize += nla_total_size(sizeof(struct rtnexthop));
- nhsize += nla_total_size(2 + nh->nh_via_alen);
+ /* RTA_VIA */
+ if (nh->nh_via_table != MPLS_NEIGH_TABLE_UNSPEC)
+ nhsize += nla_total_size(2 + nh->nh_via_alen);
if (nh->nh_labels)
nhsize += nla_total_size(nh->nh_labels * 4);
} endfor_nexthops(rt);
diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c
index 67591ae..64afd3d 100644
--- a/net/mpls/mpls_iptunnel.c
+++ b/net/mpls/mpls_iptunnel.c
@@ -54,10 +54,10 @@ int mpls_output(struct net *net, struct sock *sk, struct sk_buff *skb)
unsigned int ttl;
/* Obtain the ttl */
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (dst->ops->family == AF_INET) {
ttl = ip_hdr(skb)->ttl;
rt = (struct rtable *)dst;
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ } else if (dst->ops->family == AF_INET6) {
ttl = ipv6_hdr(skb)->hop_limit;
rt6 = (struct rt6_info *)dst;
} else {
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index e22349e..4692782 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -869,7 +869,7 @@ config NETFILTER_XT_TARGET_TEE
depends on IPV6 || IPV6=n
depends on !NF_CONNTRACK || NF_CONNTRACK
select NF_DUP_IPV4
- select NF_DUP_IPV6 if IP6_NF_IPTABLES
+ select NF_DUP_IPV6 if IP6_NF_IPTABLES != n
---help---
This option adds a "TEE" target with which a packet can be cloned and
this clone be rerouted to another nexthop.
@@ -882,7 +882,7 @@ config NETFILTER_XT_TARGET_TPROXY
depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n
depends on IP_NF_MANGLE
select NF_DEFRAG_IPV4
- select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
+ select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n
help
This option adds a `TPROXY' target, which is somewhat similar to
REDIRECT. It can only be used in the mangle table and is useful
@@ -1375,7 +1375,7 @@ config NETFILTER_XT_MATCH_SOCKET
depends on IPV6 || IPV6=n
depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n
select NF_DEFRAG_IPV4
- select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES
+ select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n
help
This option adds a `socket' match, which can be used to match
packets for which a TCP or UDP socket lookup finds a valid socket.
diff --git a/net/netfilter/ipset/ip_set_bitmap_gen.h b/net/netfilter/ipset/ip_set_bitmap_gen.h
index d05e759..b0bc475 100644
--- a/net/netfilter/ipset/ip_set_bitmap_gen.h
+++ b/net/netfilter/ipset/ip_set_bitmap_gen.h
@@ -33,7 +33,7 @@
#define mtype_gc IPSET_TOKEN(MTYPE, _gc)
#define mtype MTYPE
-#define get_ext(set, map, id) ((map)->extensions + (set)->dsize * (id))
+#define get_ext(set, map, id) ((map)->extensions + ((set)->dsize * (id)))
static void
mtype_gc_init(struct ip_set *set, void (*gc)(unsigned long ul_set))
@@ -67,12 +67,9 @@ mtype_destroy(struct ip_set *set)
del_timer_sync(&map->gc);
ip_set_free(map->members);
- if (set->dsize) {
- if (set->extensions & IPSET_EXT_DESTROY)
- mtype_ext_cleanup(set);
- ip_set_free(map->extensions);
- }
- kfree(map);
+ if (set->dsize && set->extensions & IPSET_EXT_DESTROY)
+ mtype_ext_cleanup(set);
+ ip_set_free(map);
set->data = NULL;
}
@@ -92,16 +89,14 @@ mtype_head(struct ip_set *set, struct sk_buff *skb)
{
const struct mtype *map = set->data;
struct nlattr *nested;
+ size_t memsize = sizeof(*map) + map->memsize;
nested = ipset_nest_start(skb, IPSET_ATTR_DATA);
if (!nested)
goto nla_put_failure;
if (mtype_do_head(skb, map) ||
nla_put_net32(skb, IPSET_ATTR_REFERENCES, htonl(set->ref - 1)) ||
- nla_put_net32(skb, IPSET_ATTR_MEMSIZE,
- htonl(sizeof(*map) +
- map->memsize +
- set->dsize * map->elements)))
+ nla_put_net32(skb, IPSET_ATTR_MEMSIZE, htonl(memsize)))
goto nla_put_failure;
if (unlikely(ip_set_put_flags(skb, set)))
goto nla_put_failure;
diff --git a/net/netfilter/ipset/ip_set_bitmap_ip.c b/net/netfilter/ipset/ip_set_bitmap_ip.c
index 64a5643..4783eff 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ip.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ip.c
@@ -41,7 +41,6 @@ MODULE_ALIAS("ip_set_bitmap:ip");
/* Type structure */
struct bitmap_ip {
void *members; /* the set members */
- void *extensions; /* data extensions */
u32 first_ip; /* host byte order, included in range */
u32 last_ip; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
@@ -49,6 +48,8 @@ struct bitmap_ip {
size_t memsize; /* members size */
u8 netmask; /* subnet netmask */
struct timer_list gc; /* garbage collection */
+ unsigned char extensions[0] /* data extensions */
+ __aligned(__alignof__(u64));
};
/* ADT structure for generic function args */
@@ -224,13 +225,6 @@ init_map_ip(struct ip_set *set, struct bitmap_ip *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * elements);
- if (!map->extensions) {
- kfree(map->members);
- return false;
- }
- }
map->first_ip = first_ip;
map->last_ip = last_ip;
map->elements = elements;
@@ -316,13 +310,13 @@ bitmap_ip_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
pr_debug("hosts %u, elements %llu\n",
hosts, (unsigned long long)elements);
- map = kzalloc(sizeof(*map), GFP_KERNEL);
+ set->dsize = ip_set_elem_len(set, tb, 0, 0);
+ map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map)
return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ip;
- set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_ip(set, map, first_ip, last_ip,
elements, hosts, netmask)) {
kfree(map);
diff --git a/net/netfilter/ipset/ip_set_bitmap_ipmac.c b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
index 1430535..29dde20 100644
--- a/net/netfilter/ipset/ip_set_bitmap_ipmac.c
+++ b/net/netfilter/ipset/ip_set_bitmap_ipmac.c
@@ -47,24 +47,26 @@ enum {
/* Type structure */
struct bitmap_ipmac {
void *members; /* the set members */
- void *extensions; /* MAC + data extensions */
u32 first_ip; /* host byte order, included in range */
u32 last_ip; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */
struct timer_list gc; /* garbage collector */
+ unsigned char extensions[0] /* MAC + data extensions */
+ __aligned(__alignof__(u64));
};
/* ADT structure for generic function args */
struct bitmap_ipmac_adt_elem {
+ unsigned char ether[ETH_ALEN] __aligned(2);
u16 id;
- unsigned char *ether;
+ u16 add_mac;
};
struct bitmap_ipmac_elem {
unsigned char ether[ETH_ALEN];
unsigned char filled;
-} __attribute__ ((aligned));
+} __aligned(__alignof__(u64));
static inline u32
ip_to_id(const struct bitmap_ipmac *m, u32 ip)
@@ -72,11 +74,11 @@ ip_to_id(const struct bitmap_ipmac *m, u32 ip)
return ip - m->first_ip;
}
-static inline struct bitmap_ipmac_elem *
-get_elem(void *extensions, u16 id, size_t dsize)
-{
- return (struct bitmap_ipmac_elem *)(extensions + id * dsize);
-}
+#define get_elem(extensions, id, dsize) \
+ (struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
+
+#define get_const_elem(extensions, id, dsize) \
+ (const struct bitmap_ipmac_elem *)(extensions + (id) * (dsize))
/* Common functions */
@@ -88,10 +90,9 @@ bitmap_ipmac_do_test(const struct bitmap_ipmac_adt_elem *e,
if (!test_bit(e->id, map->members))
return 0;
- elem = get_elem(map->extensions, e->id, dsize);
- if (elem->filled == MAC_FILLED)
- return !e->ether ||
- ether_addr_equal(e->ether, elem->ether);
+ elem = get_const_elem(map->extensions, e->id, dsize);
+ if (e->add_mac && elem->filled == MAC_FILLED)
+ return ether_addr_equal(e->ether, elem->ether);
/* Trigger kernel to fill out the ethernet address */
return -EAGAIN;
}
@@ -103,7 +104,7 @@ bitmap_ipmac_gc_test(u16 id, const struct bitmap_ipmac *map, size_t dsize)
if (!test_bit(id, map->members))
return 0;
- elem = get_elem(map->extensions, id, dsize);
+ elem = get_const_elem(map->extensions, id, dsize);
/* Timer not started for the incomplete elements */
return elem->filled == MAC_FILLED;
}
@@ -133,7 +134,7 @@ bitmap_ipmac_add_timeout(unsigned long *timeout,
* and we can reuse it later when MAC is filled out,
* possibly by the kernel
*/
- if (e->ether)
+ if (e->add_mac)
ip_set_timeout_set(timeout, t);
else
*timeout = t;
@@ -150,7 +151,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
elem = get_elem(map->extensions, e->id, dsize);
if (test_bit(e->id, map->members)) {
if (elem->filled == MAC_FILLED) {
- if (e->ether &&
+ if (e->add_mac &&
(flags & IPSET_FLAG_EXIST) &&
!ether_addr_equal(e->ether, elem->ether)) {
/* memcpy isn't atomic */
@@ -159,7 +160,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether);
}
return IPSET_ADD_FAILED;
- } else if (!e->ether)
+ } else if (!e->add_mac)
/* Already added without ethernet address */
return IPSET_ADD_FAILED;
/* Fill the MAC address and trigger the timer activation */
@@ -168,7 +169,7 @@ bitmap_ipmac_do_add(const struct bitmap_ipmac_adt_elem *e,
ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED;
return IPSET_ADD_START_STORED_TIMEOUT;
- } else if (e->ether) {
+ } else if (e->add_mac) {
/* We can store MAC too */
ether_addr_copy(elem->ether, e->ether);
elem->filled = MAC_FILLED;
@@ -191,7 +192,7 @@ bitmap_ipmac_do_list(struct sk_buff *skb, const struct bitmap_ipmac *map,
u32 id, size_t dsize)
{
const struct bitmap_ipmac_elem *elem =
- get_elem(map->extensions, id, dsize);
+ get_const_elem(map->extensions, id, dsize);
return nla_put_ipaddr4(skb, IPSET_ATTR_IP,
htonl(map->first_ip + id)) ||
@@ -213,7 +214,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
{
struct bitmap_ipmac *map = set->data;
ipset_adtfn adtfn = set->variant->adt[adt];
- struct bitmap_ipmac_adt_elem e = { .id = 0 };
+ struct bitmap_ipmac_adt_elem e = { .id = 0, .add_mac = 1 };
struct ip_set_ext ext = IP_SET_INIT_KEXT(skb, opt, set);
u32 ip;
@@ -231,7 +232,7 @@ bitmap_ipmac_kadt(struct ip_set *set, const struct sk_buff *skb,
return -EINVAL;
e.id = ip_to_id(map, ip);
- e.ether = eth_hdr(skb)->h_source;
+ memcpy(e.ether, eth_hdr(skb)->h_source, ETH_ALEN);
return adtfn(set, &e, &ext, &opt->ext, opt->cmdflags);
}
@@ -265,11 +266,10 @@ bitmap_ipmac_uadt(struct ip_set *set, struct nlattr *tb[],
return -IPSET_ERR_BITMAP_RANGE;
e.id = ip_to_id(map, ip);
- if (tb[IPSET_ATTR_ETHER])
- e.ether = nla_data(tb[IPSET_ATTR_ETHER]);
- else
- e.ether = NULL;
-
+ if (tb[IPSET_ATTR_ETHER]) {
+ memcpy(e.ether, nla_data(tb[IPSET_ATTR_ETHER]), ETH_ALEN);
+ e.add_mac = 1;
+ }
ret = adtfn(set, &e, &ext, &ext, flags);
return ip_set_eexist(ret, flags) ? 0 : ret;
@@ -300,13 +300,6 @@ init_map_ipmac(struct ip_set *set, struct bitmap_ipmac *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * elements);
- if (!map->extensions) {
- kfree(map->members);
- return false;
- }
- }
map->first_ip = first_ip;
map->last_ip = last_ip;
map->elements = elements;
@@ -361,14 +354,15 @@ bitmap_ipmac_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
if (elements > IPSET_BITMAP_MAX_RANGE + 1)
return -IPSET_ERR_BITMAP_RANGE_SIZE;
- map = kzalloc(sizeof(*map), GFP_KERNEL);
+ set->dsize = ip_set_elem_len(set, tb,
+ sizeof(struct bitmap_ipmac_elem),
+ __alignof__(struct bitmap_ipmac_elem));
+ map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map)
return -ENOMEM;
map->memsize = bitmap_bytes(0, elements - 1);
set->variant = &bitmap_ipmac;
- set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct bitmap_ipmac_elem));
if (!init_map_ipmac(set, map, first_ip, last_ip, elements)) {
kfree(map);
return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_bitmap_port.c b/net/netfilter/ipset/ip_set_bitmap_port.c
index 5338ccd..7f0c733 100644
--- a/net/netfilter/ipset/ip_set_bitmap_port.c
+++ b/net/netfilter/ipset/ip_set_bitmap_port.c
@@ -35,12 +35,13 @@ MODULE_ALIAS("ip_set_bitmap:port");
/* Type structure */
struct bitmap_port {
void *members; /* the set members */
- void *extensions; /* data extensions */
u16 first_port; /* host byte order, included in range */
u16 last_port; /* host byte order, included in range */
u32 elements; /* number of max elements in the set */
size_t memsize; /* members size */
struct timer_list gc; /* garbage collection */
+ unsigned char extensions[0] /* data extensions */
+ __aligned(__alignof__(u64));
};
/* ADT structure for generic function args */
@@ -209,13 +210,6 @@ init_map_port(struct ip_set *set, struct bitmap_port *map,
map->members = ip_set_alloc(map->memsize);
if (!map->members)
return false;
- if (set->dsize) {
- map->extensions = ip_set_alloc(set->dsize * map->elements);
- if (!map->extensions) {
- kfree(map->members);
- return false;
- }
- }
map->first_port = first_port;
map->last_port = last_port;
set->timeout = IPSET_NO_TIMEOUT;
@@ -232,6 +226,7 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
{
struct bitmap_port *map;
u16 first_port, last_port;
+ u32 elements;
if (unlikely(!ip_set_attr_netorder(tb, IPSET_ATTR_PORT) ||
!ip_set_attr_netorder(tb, IPSET_ATTR_PORT_TO) ||
@@ -248,14 +243,15 @@ bitmap_port_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
last_port = tmp;
}
- map = kzalloc(sizeof(*map), GFP_KERNEL);
+ elements = last_port - first_port + 1;
+ set->dsize = ip_set_elem_len(set, tb, 0, 0);
+ map = ip_set_alloc(sizeof(*map) + elements * set->dsize);
if (!map)
return -ENOMEM;
- map->elements = last_port - first_port + 1;
+ map->elements = elements;
map->memsize = bitmap_bytes(0, map->elements);
set->variant = &bitmap_port;
- set->dsize = ip_set_elem_len(set, tb, 0);
if (!init_map_port(set, map, first_port, last_port)) {
kfree(map);
return -ENOMEM;
diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c
index 69ab9c26..54f3d7c 100644
--- a/net/netfilter/ipset/ip_set_core.c
+++ b/net/netfilter/ipset/ip_set_core.c
@@ -364,25 +364,27 @@ add_extension(enum ip_set_ext_id id, u32 flags, struct nlattr *tb[])
}
size_t
-ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len)
+ip_set_elem_len(struct ip_set *set, struct nlattr *tb[], size_t len,
+ size_t align)
{
enum ip_set_ext_id id;
- size_t offset = len;
u32 cadt_flags = 0;
if (tb[IPSET_ATTR_CADT_FLAGS])
cadt_flags = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]);
if (cadt_flags & IPSET_FLAG_WITH_FORCEADD)
set->flags |= IPSET_CREATE_FLAG_FORCEADD;
+ if (!align)
+ align = 1;
for (id = 0; id < IPSET_EXT_ID_MAX; id++) {
if (!add_extension(id, cadt_flags, tb))
continue;
- offset = ALIGN(offset, ip_set_extensions[id].align);
- set->offset[id] = offset;
+ len = ALIGN(len, ip_set_extensions[id].align);
+ set->offset[id] = len;
set->extensions |= ip_set_extensions[id].type;
- offset += ip_set_extensions[id].len;
+ len += ip_set_extensions[id].len;
}
- return offset;
+ return ALIGN(len, align);
}
EXPORT_SYMBOL_GPL(ip_set_elem_len);
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 691b54f..e5336ab 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -72,8 +72,9 @@ struct hbucket {
DECLARE_BITMAP(used, AHASH_MAX_TUNED);
u8 size; /* size of the array */
u8 pos; /* position of the first free entry */
- unsigned char value[0]; /* the array of the values */
-} __attribute__ ((aligned));
+ unsigned char value[0] /* the array of the values */
+ __aligned(__alignof__(u64));
+};
/* The hash table: the table size stored here in order to make resizing easy */
struct htable {
@@ -475,7 +476,7 @@ static void
mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
{
struct htable *t;
- struct hbucket *n;
+ struct hbucket *n, *tmp;
struct mtype_elem *data;
u32 i, j, d;
#ifdef IP_SET_HASH_WITH_NETS
@@ -510,9 +511,14 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
}
}
if (d >= AHASH_INIT_SIZE) {
- struct hbucket *tmp = kzalloc(sizeof(*tmp) +
- (n->size - AHASH_INIT_SIZE) * dsize,
- GFP_ATOMIC);
+ if (d >= n->size) {
+ rcu_assign_pointer(hbucket(t, i), NULL);
+ kfree_rcu(n, rcu);
+ continue;
+ }
+ tmp = kzalloc(sizeof(*tmp) +
+ (n->size - AHASH_INIT_SIZE) * dsize,
+ GFP_ATOMIC);
if (!tmp)
/* Still try to delete expired elements */
continue;
@@ -522,7 +528,7 @@ mtype_expire(struct ip_set *set, struct htype *h, u8 nets_length, size_t dsize)
continue;
data = ahash_data(n, j, dsize);
memcpy(tmp->value + d * dsize, data, dsize);
- set_bit(j, tmp->used);
+ set_bit(d, tmp->used);
d++;
}
tmp->pos = d;
@@ -1323,12 +1329,14 @@ IPSET_TOKEN(HTYPE, _create)(struct net *net, struct ip_set *set,
#endif
set->variant = &IPSET_TOKEN(HTYPE, 4_variant);
set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)));
+ sizeof(struct IPSET_TOKEN(HTYPE, 4_elem)),
+ __alignof__(struct IPSET_TOKEN(HTYPE, 4_elem)));
#ifndef IP_SET_PROTO_UNDEF
} else {
set->variant = &IPSET_TOKEN(HTYPE, 6_variant);
set->dsize = ip_set_elem_len(set, tb,
- sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)));
+ sizeof(struct IPSET_TOKEN(HTYPE, 6_elem)),
+ __alignof__(struct IPSET_TOKEN(HTYPE, 6_elem)));
}
#endif
if (tb[IPSET_ATTR_TIMEOUT]) {
diff --git a/net/netfilter/ipset/ip_set_list_set.c b/net/netfilter/ipset/ip_set_list_set.c
index 5a30ce6..bbede95 100644
--- a/net/netfilter/ipset/ip_set_list_set.c
+++ b/net/netfilter/ipset/ip_set_list_set.c
@@ -31,7 +31,7 @@ struct set_elem {
struct rcu_head rcu;
struct list_head list;
ip_set_id_t id;
-};
+} __aligned(__alignof__(u64));
struct set_adt_elem {
ip_set_id_t id;
@@ -618,7 +618,8 @@ list_set_create(struct net *net, struct ip_set *set, struct nlattr *tb[],
size = IP_SET_LIST_MIN_SIZE;
set->variant = &set_variant;
- set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem));
+ set->dsize = ip_set_elem_len(set, tb, sizeof(struct set_elem),
+ __alignof__(struct set_elem));
if (!init_list_set(net, set, size))
return -ENOMEM;
if (tb[IPSET_ATTR_TIMEOUT]) {
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 1e24fff..f57b4dc 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -1176,6 +1176,7 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
struct ip_vs_protocol *pp;
struct ip_vs_proto_data *pd;
struct ip_vs_conn *cp;
+ struct sock *sk;
EnterFunction(11);
@@ -1183,13 +1184,12 @@ ip_vs_out(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, in
if (skb->ipvs_property)
return NF_ACCEPT;
+ sk = skb_to_full_sk(skb);
/* Bad... Do not break raw sockets */
- if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+ if (unlikely(sk && hooknum == NF_INET_LOCAL_OUT &&
af == AF_INET)) {
- struct sock *sk = skb->sk;
- struct inet_sock *inet = inet_sk(skb->sk);
- if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+ if (sk->sk_family == PF_INET && inet_sk(sk)->nodefrag)
return NF_ACCEPT;
}
@@ -1681,6 +1681,7 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
struct ip_vs_conn *cp;
int ret, pkts;
int conn_reuse_mode;
+ struct sock *sk;
/* Already marked as IPVS request or reply? */
if (skb->ipvs_property)
@@ -1708,12 +1709,11 @@ ip_vs_in(struct netns_ipvs *ipvs, unsigned int hooknum, struct sk_buff *skb, int
ip_vs_fill_iph_skb(af, skb, false, &iph);
/* Bad... Do not break raw sockets */
- if (unlikely(skb->sk != NULL && hooknum == NF_INET_LOCAL_OUT &&
+ sk = skb_to_full_sk(skb);
+ if (unlikely(sk && hooknum == NF_INET_LOCAL_OUT &&
af == AF_INET)) {
- struct sock *sk = skb->sk;
- struct inet_sock *inet = inet_sk(skb->sk);
- if (inet && sk->sk_family == PF_INET && inet->nodefrag)
+ if (sk->sk_family == PF_INET && inet_sk(sk)->nodefrag)
return NF_ACCEPT;
}
diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c
index 97b75f9..d438698 100644
--- a/net/netfilter/nf_nat_redirect.c
+++ b/net/netfilter/nf_nat_redirect.c
@@ -55,7 +55,7 @@ nf_nat_redirect_ipv4(struct sk_buff *skb,
rcu_read_lock();
indev = __in_dev_get_rcu(skb->dev);
- if (indev != NULL) {
+ if (indev && indev->ifa_list) {
ifa = indev->ifa_list;
newdst = ifa->ifa_local;
}
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 93cc473..2cb429d 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -89,6 +89,7 @@ nf_tables_afinfo_lookup(struct net *net, int family, bool autoload)
}
static void nft_ctx_init(struct nft_ctx *ctx,
+ struct net *net,
const struct sk_buff *skb,
const struct nlmsghdr *nlh,
struct nft_af_info *afi,
@@ -96,7 +97,7 @@ static void nft_ctx_init(struct nft_ctx *ctx,
struct nft_chain *chain,
const struct nlattr * const *nla)
{
- ctx->net = sock_net(skb->sk);
+ ctx->net = net;
ctx->afi = afi;
ctx->table = table;
ctx->chain = chain;
@@ -672,15 +673,14 @@ err:
return ret;
}
-static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_newtable(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
const struct nlattr *name;
struct nft_af_info *afi;
struct nft_table *table;
- struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
u32 flags = 0;
struct nft_ctx ctx;
@@ -706,7 +706,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
if (nlh->nlmsg_flags & NLM_F_REPLACE)
return -EOPNOTSUPP;
- nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
return nf_tables_updtable(&ctx);
}
@@ -730,7 +730,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
INIT_LIST_HEAD(&table->sets);
table->flags = flags;
- nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
err = nft_trans_table_add(&ctx, NFT_MSG_NEWTABLE);
if (err < 0)
goto err3;
@@ -810,18 +810,17 @@ out:
return err;
}
-static int nf_tables_deltable(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_deltable(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
struct nft_table *table;
- struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
struct nft_ctx ctx;
- nft_ctx_init(&ctx, skb, nlh, NULL, NULL, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, NULL, NULL, NULL, nla);
if (family == AF_UNSPEC || nla[NFTA_TABLE_NAME] == NULL)
return nft_flush(&ctx, family);
@@ -1221,8 +1220,8 @@ static void nf_tables_chain_destroy(struct nft_chain *chain)
}
}
-static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_newchain(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
@@ -1232,7 +1231,6 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
struct nft_chain *chain;
struct nft_base_chain *basechain = NULL;
struct nlattr *ha[NFTA_HOOK_MAX + 1];
- struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
struct net_device *dev = NULL;
u8 policy = NF_ACCEPT;
@@ -1313,7 +1311,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
return PTR_ERR(stats);
}
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
trans = nft_trans_alloc(&ctx, NFT_MSG_NEWCHAIN,
sizeof(struct nft_trans_chain));
if (trans == NULL) {
@@ -1461,7 +1459,7 @@ static int nf_tables_newchain(struct sock *nlsk, struct sk_buff *skb,
if (err < 0)
goto err1;
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
err = nft_trans_chain_add(&ctx, NFT_MSG_NEWCHAIN);
if (err < 0)
goto err2;
@@ -1476,15 +1474,14 @@ err1:
return err;
}
-static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_delchain(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
struct nft_table *table;
struct nft_chain *chain;
- struct net *net = sock_net(skb->sk);
int family = nfmsg->nfgen_family;
struct nft_ctx ctx;
@@ -1506,7 +1503,7 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
if (chain->use > 0)
return -EBUSY;
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
return nft_delchain(&ctx);
}
@@ -2010,13 +2007,12 @@ static void nf_tables_rule_destroy(const struct nft_ctx *ctx,
static struct nft_expr_info *info;
-static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_newrule(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
struct nft_table *table;
struct nft_chain *chain;
struct nft_rule *rule, *old_rule = NULL;
@@ -2075,7 +2071,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
return PTR_ERR(old_rule);
}
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
n = 0;
size = 0;
@@ -2176,13 +2172,12 @@ err1:
return err;
}
-static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_delrule(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
struct nft_table *table;
struct nft_chain *chain = NULL;
struct nft_rule *rule;
@@ -2205,7 +2200,7 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
return PTR_ERR(chain);
}
- nft_ctx_init(&ctx, skb, nlh, afi, table, chain, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, chain, nla);
if (chain) {
if (nla[NFTA_RULE_HANDLE]) {
@@ -2344,12 +2339,11 @@ static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
[NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
};
-static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
+static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
const struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
- struct net *net = sock_net(skb->sk);
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi = NULL;
struct nft_table *table = NULL;
@@ -2371,7 +2365,7 @@ static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
return -ENOENT;
}
- nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
+ nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
return 0;
}
@@ -2623,6 +2617,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ struct net *net = sock_net(skb->sk);
const struct nft_set *set;
struct nft_ctx ctx;
struct sk_buff *skb2;
@@ -2630,7 +2625,7 @@ static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
int err;
/* Verify existence before starting dump */
- err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
if (err < 0)
return err;
@@ -2693,14 +2688,13 @@ static int nf_tables_set_desc_parse(const struct nft_ctx *ctx,
return 0;
}
-static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_newset(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
const struct nft_set_ops *ops;
struct nft_af_info *afi;
- struct net *net = sock_net(skb->sk);
struct nft_table *table;
struct nft_set *set;
struct nft_ctx ctx;
@@ -2798,7 +2792,7 @@ static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
if (IS_ERR(table))
return PTR_ERR(table);
- nft_ctx_init(&ctx, skb, nlh, afi, table, NULL, nla);
+ nft_ctx_init(&ctx, net, skb, nlh, afi, table, NULL, nla);
set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
if (IS_ERR(set)) {
@@ -2882,8 +2876,8 @@ static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set
nft_set_destroy(set);
}
-static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_delset(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
@@ -2896,7 +2890,7 @@ static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
if (nla[NFTA_SET_TABLE] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
+ err = nft_ctx_init_from_setattr(&ctx, net, skb, nlh, nla);
if (err < 0)
return err;
@@ -3024,7 +3018,7 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
[NFTA_SET_ELEM_LIST_SET_ID] = { .type = NLA_U32 },
};
-static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
+static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx, struct net *net,
const struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nla[],
@@ -3033,7 +3027,6 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
struct nft_af_info *afi;
struct nft_table *table;
- struct net *net = sock_net(skb->sk);
afi = nf_tables_afinfo_lookup(net, nfmsg->nfgen_family, false);
if (IS_ERR(afi))
@@ -3045,7 +3038,7 @@ static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
if (!trans && (table->flags & NFT_TABLE_INACTIVE))
return -ENOENT;
- nft_ctx_init(ctx, skb, nlh, afi, table, NULL, nla);
+ nft_ctx_init(ctx, net, skb, nlh, afi, table, NULL, nla);
return 0;
}
@@ -3135,6 +3128,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct net *net = sock_net(skb->sk);
const struct nft_set *set;
struct nft_set_dump_args args;
struct nft_ctx ctx;
@@ -3150,8 +3144,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
if (err < 0)
return err;
- err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla,
- false);
+ err = nft_ctx_init_from_elemattr(&ctx, net, cb->skb, cb->nlh,
+ (void *)nla, false);
if (err < 0)
return err;
@@ -3212,11 +3206,12 @@ static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
+ struct net *net = sock_net(skb->sk);
const struct nft_set *set;
struct nft_ctx ctx;
int err;
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
if (err < 0)
return err;
@@ -3528,11 +3523,10 @@ err1:
return err;
}
-static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
- struct net *net = sock_net(skb->sk);
const struct nlattr *attr;
struct nft_set *set;
struct nft_ctx ctx;
@@ -3541,7 +3535,7 @@ static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, true);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, true);
if (err < 0)
return err;
@@ -3623,8 +3617,8 @@ err1:
return err;
}
-static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
- const struct nlmsghdr *nlh,
+static int nf_tables_delsetelem(struct net *net, struct sock *nlsk,
+ struct sk_buff *skb, const struct nlmsghdr *nlh,
const struct nlattr * const nla[])
{
const struct nlattr *attr;
@@ -3635,7 +3629,7 @@ static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
if (nla[NFTA_SET_ELEM_LIST_ELEMENTS] == NULL)
return -EINVAL;
- err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla, false);
+ err = nft_ctx_init_from_elemattr(&ctx, net, skb, nlh, nla, false);
if (err < 0)
return err;
@@ -4030,7 +4024,8 @@ static int nf_tables_abort(struct sk_buff *skb)
struct nft_trans *trans, *next;
struct nft_trans_elem *te;
- list_for_each_entry_safe(trans, next, &net->nft.commit_list, list) {
+ list_for_each_entry_safe_reverse(trans, next, &net->nft.commit_list,
+ list) {
switch (trans->msg_type) {
case NFT_MSG_NEWTABLE:
if (nft_trans_table_update(trans)) {
diff --git a/net/netfilter/nf_tables_netdev.c b/net/netfilter/nf_tables_netdev.c
index 7b9c053..edb3502f 100644
--- a/net/netfilter/nf_tables_netdev.c
+++ b/net/netfilter/nf_tables_netdev.c
@@ -94,7 +94,7 @@ nft_do_chain_netdev(void *priv, struct sk_buff *skb,
{
struct nft_pktinfo pkt;
- switch (eth_hdr(skb)->h_proto) {
+ switch (skb->protocol) {
case htons(ETH_P_IP):
nft_netdev_set_pktinfo_ipv4(&pkt, skb, state);
break;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index f1d9e88..77afe91 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -295,8 +295,6 @@ replay:
if (!skb)
return netlink_ack(oskb, nlh, -ENOMEM);
- skb->sk = oskb->sk;
-
nfnl_lock(subsys_id);
ss = rcu_dereference_protected(table[subsys_id].subsys,
lockdep_is_held(&table[subsys_id].mutex));
@@ -381,7 +379,7 @@ replay:
goto ack;
if (nc->call_batch) {
- err = nc->call_batch(net->nfnl, skb, nlh,
+ err = nc->call_batch(net, net->nfnl, skb, nlh,
(const struct nlattr **)cda);
}
@@ -492,7 +490,7 @@ static int nfnetlink_bind(struct net *net, int group)
type = nfnl_group2type[group];
rcu_read_lock();
- ss = nfnetlink_get_subsys(type);
+ ss = nfnetlink_get_subsys(type << 8);
rcu_read_unlock();
if (!ss)
request_module("nfnetlink-subsys-%d", type);
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index 06eb48f..740cce4 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -825,7 +825,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct net *net = sock_net(ctnl);
struct nfnl_log_net *log = nfnl_log_pernet(net);
int ret = 0;
- u16 flags;
+ u16 flags = 0;
if (nfula[NFULA_CFG_CMD]) {
u_int8_t pf = nfmsg->nfgen_family;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 7d81d28..861c661 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -365,8 +365,9 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
break;
}
+ nfnl_ct = rcu_dereference(nfnl_ct_hook);
+
if (queue->flags & NFQA_CFG_F_CONNTRACK) {
- nfnl_ct = rcu_dereference(nfnl_ct_hook);
if (nfnl_ct != NULL) {
ct = nfnl_ct->get_ct(entskb, &ctinfo);
if (ct != NULL)
@@ -1064,9 +1065,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
if (entry == NULL)
return -ENOENT;
+ /* rcu lock already held from nfnl->call_rcu. */
+ nfnl_ct = rcu_dereference(nfnl_ct_hook);
+
if (nfqa[NFQA_CT]) {
- /* rcu lock already held from nfnl->call_rcu. */
- nfnl_ct = rcu_dereference(nfnl_ct_hook);
if (nfnl_ct != NULL)
ct = nfqnl_ct_parse(nfnl_ct, nlh, nfqa, entry, &ctinfo);
}
@@ -1417,6 +1419,7 @@ static int __init nfnetlink_queue_init(void)
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfqnl_rtnl_notifier);
+ unregister_pernet_subsys(&nfnl_queue_net_ops);
out:
return status;
}
diff --git a/net/netfilter/nft_counter.c b/net/netfilter/nft_counter.c
index 1067fb4..c7808fc 100644
--- a/net/netfilter/nft_counter.c
+++ b/net/netfilter/nft_counter.c
@@ -47,27 +47,34 @@ static void nft_counter_eval(const struct nft_expr *expr,
local_bh_enable();
}
-static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
+static void nft_counter_fetch(const struct nft_counter_percpu __percpu *counter,
+ struct nft_counter *total)
{
- struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
- struct nft_counter_percpu *cpu_stats;
- struct nft_counter total;
+ const struct nft_counter_percpu *cpu_stats;
u64 bytes, packets;
unsigned int seq;
int cpu;
- memset(&total, 0, sizeof(total));
+ memset(total, 0, sizeof(*total));
for_each_possible_cpu(cpu) {
- cpu_stats = per_cpu_ptr(priv->counter, cpu);
+ cpu_stats = per_cpu_ptr(counter, cpu);
do {
seq = u64_stats_fetch_begin_irq(&cpu_stats->syncp);
bytes = cpu_stats->counter.bytes;
packets = cpu_stats->counter.packets;
} while (u64_stats_fetch_retry_irq(&cpu_stats->syncp, seq));
- total.packets += packets;
- total.bytes += bytes;
+ total->packets += packets;
+ total->bytes += bytes;
}
+}
+
+static int nft_counter_dump(struct sk_buff *skb, const struct nft_expr *expr)
+{
+ struct nft_counter_percpu_priv *priv = nft_expr_priv(expr);
+ struct nft_counter total;
+
+ nft_counter_fetch(priv->counter, &total);
if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes)) ||
nla_put_be64(skb, NFTA_COUNTER_PACKETS, cpu_to_be64(total.packets)))
@@ -118,6 +125,31 @@ static void nft_counter_destroy(const struct nft_ctx *ctx,
free_percpu(priv->counter);
}
+static int nft_counter_clone(struct nft_expr *dst, const struct nft_expr *src)
+{
+ struct nft_counter_percpu_priv *priv = nft_expr_priv(src);
+ struct nft_counter_percpu_priv *priv_clone = nft_expr_priv(dst);
+ struct nft_counter_percpu __percpu *cpu_stats;
+ struct nft_counter_percpu *this_cpu;
+ struct nft_counter total;
+
+ nft_counter_fetch(priv->counter, &total);
+
+ cpu_stats = __netdev_alloc_pcpu_stats(struct nft_counter_percpu,
+ GFP_ATOMIC);
+ if (cpu_stats == NULL)
+ return ENOMEM;
+
+ preempt_disable();
+ this_cpu = this_cpu_ptr(cpu_stats);
+ this_cpu->counter.packets = total.packets;
+ this_cpu->counter.bytes = total.bytes;
+ preempt_enable();
+
+ priv_clone->counter = cpu_stats;
+ return 0;
+}
+
static struct nft_expr_type nft_counter_type;
static const struct nft_expr_ops nft_counter_ops = {
.type = &nft_counter_type,
@@ -126,6 +158,7 @@ static const struct nft_expr_ops nft_counter_ops = {
.init = nft_counter_init,
.destroy = nft_counter_destroy,
.dump = nft_counter_dump,
+ .clone = nft_counter_clone,
};
static struct nft_expr_type nft_counter_type __read_mostly = {
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index 8cbca34..9399215 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -366,6 +366,7 @@ static int nft_ct_get_dump(struct sk_buff *skb, const struct nft_expr *expr)
goto nla_put_failure;
switch (priv->key) {
+ case NFT_CT_L3PROTOCOL:
case NFT_CT_PROTOCOL:
case NFT_CT_SRC:
case NFT_CT_DST:
diff --git a/net/netfilter/nft_dynset.c b/net/netfilter/nft_dynset.c
index 513a8ef..9dec3bd 100644
--- a/net/netfilter/nft_dynset.c
+++ b/net/netfilter/nft_dynset.c
@@ -50,8 +50,9 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
}
ext = nft_set_elem_ext(set, elem);
- if (priv->expr != NULL)
- nft_expr_clone(nft_set_ext_expr(ext), priv->expr);
+ if (priv->expr != NULL &&
+ nft_expr_clone(nft_set_ext_expr(ext), priv->expr) < 0)
+ return NULL;
return elem;
}
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index e4ad2c2..9dfaf4d 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -31,6 +31,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
const struct nft_meta *priv = nft_expr_priv(expr);
const struct sk_buff *skb = pkt->skb;
const struct net_device *in = pkt->in, *out = pkt->out;
+ struct sock *sk;
u32 *dest = &regs->data[priv->dreg];
switch (priv->key) {
@@ -86,33 +87,35 @@ void nft_meta_get_eval(const struct nft_expr *expr,
*(u16 *)dest = out->type;
break;
case NFT_META_SKUID:
- if (skb->sk == NULL || !sk_fullsock(skb->sk))
+ sk = skb_to_full_sk(skb);
+ if (!sk || !sk_fullsock(sk))
goto err;
- read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket == NULL ||
- skb->sk->sk_socket->file == NULL) {
- read_unlock_bh(&skb->sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
+ if (sk->sk_socket == NULL ||
+ sk->sk_socket->file == NULL) {
+ read_unlock_bh(&sk->sk_callback_lock);
goto err;
}
*dest = from_kuid_munged(&init_user_ns,
- skb->sk->sk_socket->file->f_cred->fsuid);
- read_unlock_bh(&skb->sk->sk_callback_lock);
+ sk->sk_socket->file->f_cred->fsuid);
+ read_unlock_bh(&sk->sk_callback_lock);
break;
case NFT_META_SKGID:
- if (skb->sk == NULL || !sk_fullsock(skb->sk))
+ sk = skb_to_full_sk(skb);
+ if (!sk || !sk_fullsock(sk))
goto err;
- read_lock_bh(&skb->sk->sk_callback_lock);
- if (skb->sk->sk_socket == NULL ||
- skb->sk->sk_socket->file == NULL) {
- read_unlock_bh(&skb->sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
+ if (sk->sk_socket == NULL ||
+ sk->sk_socket->file == NULL) {
+ read_unlock_bh(&sk->sk_callback_lock);
goto err;
}
*dest = from_kgid_munged(&init_user_ns,
- skb->sk->sk_socket->file->f_cred->fsgid);
- read_unlock_bh(&skb->sk->sk_callback_lock);
+ sk->sk_socket->file->f_cred->fsgid);
+ read_unlock_bh(&sk->sk_callback_lock);
break;
#ifdef CONFIG_IP_ROUTE_CLASSID
case NFT_META_RTCLASSID: {
@@ -168,9 +171,10 @@ void nft_meta_get_eval(const struct nft_expr *expr,
break;
#ifdef CONFIG_CGROUP_NET_CLASSID
case NFT_META_CGROUP:
- if (skb->sk == NULL || !sk_fullsock(skb->sk))
+ sk = skb_to_full_sk(skb);
+ if (!sk || !sk_fullsock(sk))
goto err;
- *dest = skb->sk->sk_classid;
+ *dest = sk->sk_classid;
break;
#endif
default:
diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c
index 899b061..3eff7b6 100644
--- a/net/netfilter/xt_TEE.c
+++ b/net/netfilter/xt_TEE.c
@@ -31,8 +31,9 @@ static unsigned int
tee_tg4(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
+ int oif = info->priv ? info->priv->oif : 0;
- nf_dup_ipv4(par->net, skb, par->hooknum, &info->gw.in, info->priv->oif);
+ nf_dup_ipv4(par->net, skb, par->hooknum, &info->gw.in, oif);
return XT_CONTINUE;
}
@@ -42,8 +43,9 @@ static unsigned int
tee_tg6(struct sk_buff *skb, const struct xt_action_param *par)
{
const struct xt_tee_tginfo *info = par->targinfo;
+ int oif = info->priv ? info->priv->oif : 0;
- nf_dup_ipv6(par->net, skb, par->hooknum, &info->gw.in6, info->priv->oif);
+ nf_dup_ipv6(par->net, skb, par->hooknum, &info->gw.in6, oif);
return XT_CONTINUE;
}
diff --git a/net/netfilter/xt_owner.c b/net/netfilter/xt_owner.c
index ca2e577..1302b47 100644
--- a/net/netfilter/xt_owner.c
+++ b/net/netfilter/xt_owner.c
@@ -14,6 +14,7 @@
#include <linux/skbuff.h>
#include <linux/file.h>
#include <net/sock.h>
+#include <net/inet_sock.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_owner.h>
@@ -33,8 +34,9 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
const struct xt_owner_match_info *info = par->matchinfo;
const struct file *filp;
+ struct sock *sk = skb_to_full_sk(skb);
- if (skb->sk == NULL || skb->sk->sk_socket == NULL)
+ if (sk == NULL || sk->sk_socket == NULL)
return (info->match ^ info->invert) == 0;
else if (info->match & info->invert & XT_OWNER_SOCKET)
/*
@@ -43,7 +45,7 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
*/
return false;
- filp = skb->sk->sk_socket->file;
+ filp = sk->sk_socket->file;
if (filp == NULL)
return ((info->match ^ info->invert) &
(XT_OWNER_UID | XT_OWNER_GID)) == 0;
diff --git a/net/nfc/llcp_sock.c b/net/nfc/llcp_sock.c
index b7de0da..ecf0a01 100644
--- a/net/nfc/llcp_sock.c
+++ b/net/nfc/llcp_sock.c
@@ -572,7 +572,7 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock,
if (sock_writeable(sk) && sk->sk_state == LLCP_CONNECTED)
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
pr_debug("mask 0x%x\n", mask);
diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c
index c2cc111..e004067 100644
--- a/net/openvswitch/conntrack.c
+++ b/net/openvswitch/conntrack.c
@@ -53,6 +53,8 @@ struct ovs_conntrack_info {
struct md_labels labels;
};
+static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info);
+
static u16 key_to_nfproto(const struct sw_flow_key *key)
{
switch (ntohs(key->eth.type)) {
@@ -141,6 +143,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state,
* previously sent the packet to conntrack via the ct action.
*/
static void ovs_ct_update_key(const struct sk_buff *skb,
+ const struct ovs_conntrack_info *info,
struct sw_flow_key *key, bool post_ct)
{
const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt;
@@ -158,13 +161,15 @@ static void ovs_ct_update_key(const struct sk_buff *skb,
zone = nf_ct_zone(ct);
} else if (post_ct) {
state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID;
+ if (info)
+ zone = &info->zone;
}
__ovs_ct_update_key(key, state, zone, ct);
}
void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key)
{
- ovs_ct_update_key(skb, key, false);
+ ovs_ct_update_key(skb, NULL, key, false);
}
int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb)
@@ -418,7 +423,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
}
}
- ovs_ct_update_key(skb, key, true);
+ ovs_ct_update_key(skb, info, key, true);
return 0;
}
@@ -693,6 +698,10 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
OVS_NLERR(log, "Failed to allocate conntrack template");
return -ENOMEM;
}
+
+ __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
+ nf_conntrack_get(&ct_info.ct->ct_general);
+
if (helper) {
err = ovs_ct_add_helper(&ct_info, helper, key, log);
if (err)
@@ -704,11 +713,9 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr,
if (err)
goto err_free_ct;
- __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status);
- nf_conntrack_get(&ct_info.ct->ct_general);
return 0;
err_free_ct:
- nf_conntrack_free(ct_info.ct);
+ __ovs_ct_free_action(&ct_info);
return err;
}
@@ -750,6 +757,11 @@ void ovs_ct_free_action(const struct nlattr *a)
{
struct ovs_conntrack_info *ct_info = nla_data(a);
+ __ovs_ct_free_action(ct_info);
+}
+
+static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)
+{
if (ct_info->helper)
module_put(ct_info->helper->me);
if (ct_info->ct)
diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c
index a7a80a6..653d073 100644
--- a/net/openvswitch/dp_notify.c
+++ b/net/openvswitch/dp_notify.c
@@ -58,7 +58,7 @@ void ovs_dp_notify_wq(struct work_struct *work)
struct hlist_node *n;
hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) {
- if (vport->ops->type != OVS_VPORT_TYPE_NETDEV)
+ if (vport->ops->type == OVS_VPORT_TYPE_INTERNAL)
continue;
if (!(vport->dev->priv_flags & IFF_OVS_DATAPATH))
diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c
index 907d6fd..d1bd4a4 100644
--- a/net/openvswitch/flow_netlink.c
+++ b/net/openvswitch/flow_netlink.c
@@ -2434,7 +2434,10 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb)
if (!start)
return -EMSGSIZE;
- err = ovs_nla_put_tunnel_info(skb, tun_info);
+ err = ip_tun_to_nlattr(skb, &tun_info->key,
+ ip_tunnel_info_opts(tun_info),
+ tun_info->options_len,
+ ip_tunnel_info_af(tun_info));
if (err)
return err;
nla_nest_end(skb, start);
diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c
index efb736b..e41cd12 100644
--- a/net/openvswitch/vport-geneve.c
+++ b/net/openvswitch/vport-geneve.c
@@ -117,7 +117,6 @@ static struct vport_ops ovs_geneve_vport_ops = {
.destroy = ovs_netdev_tunnel_destroy,
.get_options = geneve_get_options,
.send = dev_queue_xmit,
- .owner = THIS_MODULE,
};
static int __init ovs_geneve_tnl_init(void)
diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c
index c3257d7..7f8897f 100644
--- a/net/openvswitch/vport-gre.c
+++ b/net/openvswitch/vport-gre.c
@@ -89,7 +89,6 @@ static struct vport_ops ovs_gre_vport_ops = {
.create = gre_create,
.send = dev_queue_xmit,
.destroy = ovs_netdev_tunnel_destroy,
- .owner = THIS_MODULE,
};
static int __init ovs_gre_tnl_init(void)
diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c
index b327368..6b0190b 100644
--- a/net/openvswitch/vport-netdev.c
+++ b/net/openvswitch/vport-netdev.c
@@ -180,9 +180,13 @@ void ovs_netdev_tunnel_destroy(struct vport *vport)
if (vport->dev->priv_flags & IFF_OVS_DATAPATH)
ovs_netdev_detach_dev(vport);
- /* Early release so we can unregister the device */
+ /* We can be invoked by both explicit vport deletion and
+ * underlying netdev deregistration; delete the link only
+ * if it's not already shutting down.
+ */
+ if (vport->dev->reg_state == NETREG_REGISTERED)
+ rtnl_delete_link(vport->dev);
dev_put(vport->dev);
- rtnl_delete_link(vport->dev);
vport->dev = NULL;
rtnl_unlock();
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 0ac0fd0..31cbc8c 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -71,7 +71,7 @@ static struct hlist_head *hash_bucket(const struct net *net, const char *name)
return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
}
-int ovs_vport_ops_register(struct vport_ops *ops)
+int __ovs_vport_ops_register(struct vport_ops *ops)
{
int err = -EEXIST;
struct vport_ops *o;
@@ -87,7 +87,7 @@ errout:
ovs_unlock();
return err;
}
-EXPORT_SYMBOL_GPL(ovs_vport_ops_register);
+EXPORT_SYMBOL_GPL(__ovs_vport_ops_register);
void ovs_vport_ops_unregister(struct vport_ops *ops)
{
@@ -256,8 +256,8 @@ int ovs_vport_set_options(struct vport *vport, struct nlattr *options)
*
* @vport: vport to delete.
*
- * Detaches @vport from its datapath and destroys it. It is possible to fail
- * for reasons such as lack of memory. ovs_mutex must be held.
+ * Detaches @vport from its datapath and destroys it. ovs_mutex must
+ * be held.
*/
void ovs_vport_del(struct vport *vport)
{
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index bdfd82a..8ea3a96 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -196,7 +196,13 @@ static inline const char *ovs_vport_name(struct vport *vport)
return vport->dev->name;
}
-int ovs_vport_ops_register(struct vport_ops *ops);
+int __ovs_vport_ops_register(struct vport_ops *ops);
+#define ovs_vport_ops_register(ops) \
+ ({ \
+ (ops)->owner = THIS_MODULE; \
+ __ovs_vport_ops_register(ops); \
+ })
+
void ovs_vport_ops_unregister(struct vport_ops *ops);
static inline struct rtable *ovs_tunnel_route_lookup(struct net *net,
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 691660b..992396a 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -1741,6 +1741,20 @@ static void fanout_release(struct sock *sk)
kfree_rcu(po->rollover, rcu);
}
+static bool packet_extra_vlan_len_allowed(const struct net_device *dev,
+ struct sk_buff *skb)
+{
+ /* Earlier code assumed this would be a VLAN pkt, double-check
+ * this now that we have the actual packet in hand. We can only
+ * do this check on Ethernet devices.
+ */
+ if (unlikely(dev->type != ARPHRD_ETHER))
+ return false;
+
+ skb_reset_mac_header(skb);
+ return likely(eth_hdr(skb)->h_proto == htons(ETH_P_8021Q));
+}
+
static const struct proto_ops packet_ops;
static const struct proto_ops packet_ops_spkt;
@@ -1902,18 +1916,10 @@ retry:
goto retry;
}
- if (len > (dev->mtu + dev->hard_header_len + extra_len)) {
- /* Earlier code assumed this would be a VLAN pkt,
- * double-check this now that we have the actual
- * packet in hand.
- */
- struct ethhdr *ehdr;
- skb_reset_mac_header(skb);
- ehdr = eth_hdr(skb);
- if (ehdr->h_proto != htons(ETH_P_8021Q)) {
- err = -EMSGSIZE;
- goto out_unlock;
- }
+ if (len > (dev->mtu + dev->hard_header_len + extra_len) &&
+ !packet_extra_vlan_len_allowed(dev, skb)) {
+ err = -EMSGSIZE;
+ goto out_unlock;
}
skb->protocol = proto;
@@ -2323,8 +2329,8 @@ static void tpacket_destruct_skb(struct sk_buff *skb)
static bool ll_header_truncated(const struct net_device *dev, int len)
{
/* net device doesn't like empty head */
- if (unlikely(len <= dev->hard_header_len)) {
- net_warn_ratelimited("%s: packet size is too short (%d <= %d)\n",
+ if (unlikely(len < dev->hard_header_len)) {
+ net_warn_ratelimited("%s: packet size is too short (%d < %d)\n",
current->comm, len, dev->hard_header_len);
return true;
}
@@ -2332,6 +2338,15 @@ static bool ll_header_truncated(const struct net_device *dev, int len)
return false;
}
+static void tpacket_set_protocol(const struct net_device *dev,
+ struct sk_buff *skb)
+{
+ if (dev->type == ARPHRD_ETHER) {
+ skb_reset_mac_header(skb);
+ skb->protocol = eth_hdr(skb)->h_proto;
+ }
+}
+
static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
void *frame, struct net_device *dev, int size_max,
__be16 proto, unsigned char *addr, int hlen)
@@ -2368,8 +2383,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
skb_reserve(skb, hlen);
skb_reset_network_header(skb);
- if (!packet_use_direct_xmit(po))
- skb_probe_transport_header(skb, 0);
if (unlikely(po->tp_tx_has_off)) {
int off_min, off_max, off;
off_min = po->tp_hdrlen - sizeof(struct sockaddr_ll);
@@ -2415,6 +2428,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
dev->hard_header_len);
if (unlikely(err))
return err;
+ if (!skb->protocol)
+ tpacket_set_protocol(dev, skb);
data += dev->hard_header_len;
to_write -= dev->hard_header_len;
@@ -2449,6 +2464,8 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
len = ((to_write > len_max) ? len_max : to_write);
}
+ skb_probe_transport_header(skb, 0);
+
return tp_len;
}
@@ -2493,12 +2510,13 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
if (unlikely(!(dev->flags & IFF_UP)))
goto out_put;
- reserve = dev->hard_header_len + VLAN_HLEN;
+ if (po->sk.sk_socket->type == SOCK_RAW)
+ reserve = dev->hard_header_len;
size_max = po->tx_ring.frame_size
- (po->tp_hdrlen - sizeof(struct sockaddr_ll));
- if (size_max > dev->mtu + reserve)
- size_max = dev->mtu + reserve;
+ if (size_max > dev->mtu + reserve + VLAN_HLEN)
+ size_max = dev->mtu + reserve + VLAN_HLEN;
do {
ph = packet_current_frame(po, &po->tx_ring,
@@ -2525,18 +2543,10 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
tp_len = tpacket_fill_skb(po, skb, ph, dev, size_max, proto,
addr, hlen);
if (likely(tp_len >= 0) &&
- tp_len > dev->mtu + dev->hard_header_len) {
- struct ethhdr *ehdr;
- /* Earlier code assumed this would be a VLAN pkt,
- * double-check this now that we have the actual
- * packet in hand.
- */
+ tp_len > dev->mtu + reserve &&
+ !packet_extra_vlan_len_allowed(dev, skb))
+ tp_len = -EMSGSIZE;
- skb_reset_mac_header(skb);
- ehdr = eth_hdr(skb);
- if (ehdr->h_proto != htons(ETH_P_8021Q))
- tp_len = -EMSGSIZE;
- }
if (unlikely(tp_len < 0)) {
if (po->tp_loss) {
__packet_set_status(po, ph,
@@ -2765,18 +2775,10 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
- if (!gso_type && (len > dev->mtu + reserve + extra_len)) {
- /* Earlier code assumed this would be a VLAN pkt,
- * double-check this now that we have the actual
- * packet in hand.
- */
- struct ethhdr *ehdr;
- skb_reset_mac_header(skb);
- ehdr = eth_hdr(skb);
- if (ehdr->h_proto != htons(ETH_P_8021Q)) {
- err = -EMSGSIZE;
- goto out_free;
- }
+ if (!gso_type && (len > dev->mtu + reserve + extra_len) &&
+ !packet_extra_vlan_len_allowed(dev, skb)) {
+ err = -EMSGSIZE;
+ goto out_free;
}
skb->protocol = proto;
@@ -2807,8 +2809,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
len += vnet_hdr_len;
}
- if (!packet_use_direct_xmit(po))
- skb_probe_transport_header(skb, reserve);
+ skb_probe_transport_header(skb, reserve);
+
if (unlikely(extra_len == 4))
skb->no_fcs = 1;
@@ -2911,22 +2913,40 @@ static int packet_release(struct socket *sock)
* Attach a packet hook.
*/
-static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
+static int packet_do_bind(struct sock *sk, const char *name, int ifindex,
+ __be16 proto)
{
struct packet_sock *po = pkt_sk(sk);
struct net_device *dev_curr;
__be16 proto_curr;
bool need_rehook;
+ struct net_device *dev = NULL;
+ int ret = 0;
+ bool unlisted = false;
- if (po->fanout) {
- if (dev)
- dev_put(dev);
-
+ if (po->fanout)
return -EINVAL;
- }
lock_sock(sk);
spin_lock(&po->bind_lock);
+ rcu_read_lock();
+
+ if (name) {
+ dev = dev_get_by_name_rcu(sock_net(sk), name);
+ if (!dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+ } else if (ifindex) {
+ dev = dev_get_by_index_rcu(sock_net(sk), ifindex);
+ if (!dev) {
+ ret = -ENODEV;
+ goto out_unlock;
+ }
+ }
+
+ if (dev)
+ dev_hold(dev);
proto_curr = po->prot_hook.type;
dev_curr = po->prot_hook.dev;
@@ -2934,14 +2954,29 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
need_rehook = proto_curr != proto || dev_curr != dev;
if (need_rehook) {
- unregister_prot_hook(sk, true);
+ if (po->running) {
+ rcu_read_unlock();
+ __unregister_prot_hook(sk, true);
+ rcu_read_lock();
+ dev_curr = po->prot_hook.dev;
+ if (dev)
+ unlisted = !dev_get_by_index_rcu(sock_net(sk),
+ dev->ifindex);
+ }
po->num = proto;
po->prot_hook.type = proto;
- po->prot_hook.dev = dev;
- po->ifindex = dev ? dev->ifindex : 0;
- packet_cached_dev_assign(po, dev);
+ if (unlikely(unlisted)) {
+ dev_put(dev);
+ po->prot_hook.dev = NULL;
+ po->ifindex = -1;
+ packet_cached_dev_reset(po);
+ } else {
+ po->prot_hook.dev = dev;
+ po->ifindex = dev ? dev->ifindex : 0;
+ packet_cached_dev_assign(po, dev);
+ }
}
if (dev_curr)
dev_put(dev_curr);
@@ -2949,7 +2984,7 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
if (proto == 0 || !need_rehook)
goto out_unlock;
- if (!dev || (dev->flags & IFF_UP)) {
+ if (!unlisted && (!dev || (dev->flags & IFF_UP))) {
register_prot_hook(sk);
} else {
sk->sk_err = ENETDOWN;
@@ -2958,9 +2993,10 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 proto)
}
out_unlock:
+ rcu_read_unlock();
spin_unlock(&po->bind_lock);
release_sock(sk);
- return 0;
+ return ret;
}
/*
@@ -2972,8 +3008,6 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
{
struct sock *sk = sock->sk;
char name[15];
- struct net_device *dev;
- int err = -ENODEV;
/*
* Check legality
@@ -2983,19 +3017,13 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
return -EINVAL;
strlcpy(name, uaddr->sa_data, sizeof(name));
- dev = dev_get_by_name(sock_net(sk), name);
- if (dev)
- err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
- return err;
+ return packet_do_bind(sk, name, 0, pkt_sk(sk)->num);
}
static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_ll *sll = (struct sockaddr_ll *)uaddr;
struct sock *sk = sock->sk;
- struct net_device *dev = NULL;
- int err;
-
/*
* Check legality
@@ -3006,16 +3034,8 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
if (sll->sll_family != AF_PACKET)
return -EINVAL;
- if (sll->sll_ifindex) {
- err = -ENODEV;
- dev = dev_get_by_index(sock_net(sk), sll->sll_ifindex);
- if (dev == NULL)
- goto out;
- }
- err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
-
-out:
- return err;
+ return packet_do_bind(sk, NULL, sll->sll_ifindex,
+ sll->sll_protocol ? : pkt_sk(sk)->num);
}
static struct proto packet_proto = {
@@ -4089,7 +4109,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
err = -EINVAL;
if (unlikely((int)req->tp_block_size <= 0))
goto out;
- if (unlikely(req->tp_block_size & (PAGE_SIZE - 1)))
+ if (unlikely(!PAGE_ALIGNED(req->tp_block_size)))
goto out;
if (po->tp_version >= TPACKET_V3 &&
(int)(req->tp_block_size -
@@ -4101,8 +4121,8 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u,
if (unlikely(req->tp_frame_size & (TPACKET_ALIGNMENT - 1)))
goto out;
- rb->frames_per_block = req->tp_block_size/req->tp_frame_size;
- if (unlikely(rb->frames_per_block <= 0))
+ rb->frames_per_block = req->tp_block_size / req->tp_frame_size;
+ if (unlikely(rb->frames_per_block == 0))
goto out;
if (unlikely((rb->frames_per_block * req->tp_block_nr) !=
req->tp_frame_nr))
diff --git a/net/rds/connection.c b/net/rds/connection.c
index d456403..e3b118c 100644
--- a/net/rds/connection.c
+++ b/net/rds/connection.c
@@ -186,12 +186,6 @@ static struct rds_connection *__rds_conn_create(struct net *net,
}
}
- if (trans == NULL) {
- kmem_cache_free(rds_conn_slab, conn);
- conn = ERR_PTR(-ENODEV);
- goto out;
- }
-
conn->c_trans = trans;
ret = trans->conn_alloc(conn, gfp);
diff --git a/net/rds/send.c b/net/rds/send.c
index 827155c..c9cdb35 100644
--- a/net/rds/send.c
+++ b/net/rds/send.c
@@ -1013,11 +1013,13 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
release_sock(sk);
}
- /* racing with another thread binding seems ok here */
+ lock_sock(sk);
if (daddr == 0 || rs->rs_bound_addr == 0) {
+ release_sock(sk);
ret = -ENOTCONN; /* XXX not a great errno */
goto out;
}
+ release_sock(sk);
if (payload_len > rds_sk_sndbuf(rs)) {
ret = -EMSGSIZE;
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index b41e9ea..f53bf3b6 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -49,7 +49,6 @@
struct rfkill {
spinlock_t lock;
- const char *name;
enum rfkill_type type;
unsigned long state;
@@ -73,6 +72,7 @@ struct rfkill {
struct delayed_work poll_work;
struct work_struct uevent_work;
struct work_struct sync_work;
+ char name[];
};
#define to_rfkill(d) container_of(d, struct rfkill, dev)
@@ -876,14 +876,14 @@ struct rfkill * __must_check rfkill_alloc(const char *name,
if (WARN_ON(type == RFKILL_TYPE_ALL || type >= NUM_RFKILL_TYPES))
return NULL;
- rfkill = kzalloc(sizeof(*rfkill), GFP_KERNEL);
+ rfkill = kzalloc(sizeof(*rfkill) + strlen(name) + 1, GFP_KERNEL);
if (!rfkill)
return NULL;
spin_lock_init(&rfkill->lock);
INIT_LIST_HEAD(&rfkill->node);
rfkill->type = type;
- rfkill->name = name;
+ strcpy(rfkill->name, name);
rfkill->ops = ops;
rfkill->data = ops_data;
diff --git a/net/rxrpc/ar-ack.c b/net/rxrpc/ar-ack.c
index e0547f5..adc555e 100644
--- a/net/rxrpc/ar-ack.c
+++ b/net/rxrpc/ar-ack.c
@@ -723,8 +723,10 @@ process_further:
if ((call->state == RXRPC_CALL_CLIENT_AWAIT_REPLY ||
call->state == RXRPC_CALL_SERVER_AWAIT_ACK) &&
- hard > tx)
+ hard > tx) {
+ call->acks_hard = tx;
goto all_acked;
+ }
smp_rmb();
rxrpc_rotate_tx_window(call, hard - 1);
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index da3cc09..3f65716 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -896,15 +896,9 @@ int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;
- description = kmalloc(optlen + 1, GFP_KERNEL);
- if (!description)
- return -ENOMEM;
-
- if (copy_from_user(description, optval, optlen)) {
- kfree(description);
- return -EFAULT;
- }
- description[optlen] = 0;
+ description = memdup_user_nul(optval, optlen);
+ if (IS_ERR(description))
+ return PTR_ERR(description);
key = request_key(&key_type_rxrpc, description, NULL);
if (IS_ERR(key)) {
@@ -933,15 +927,9 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
if (optlen <= 0 || optlen > PAGE_SIZE - 1)
return -EINVAL;
- description = kmalloc(optlen + 1, GFP_KERNEL);
- if (!description)
- return -ENOMEM;
-
- if (copy_from_user(description, optval, optlen)) {
- kfree(description);
- return -EFAULT;
- }
- description[optlen] = 0;
+ description = memdup_user_nul(optval, optlen);
+ if (IS_ERR(description))
+ return PTR_ERR(description);
key = request_key(&key_type_keyring, description, NULL);
if (IS_ERR(key)) {
diff --git a/net/rxrpc/ar-output.c b/net/rxrpc/ar-output.c
index a40d3af..14c4e12 100644
--- a/net/rxrpc/ar-output.c
+++ b/net/rxrpc/ar-output.c
@@ -531,7 +531,7 @@ static int rxrpc_send_data(struct rxrpc_sock *rx,
timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT);
/* this should be in poll */
- clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk);
if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
return -EPIPE;
diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c
index 536838b..fbfec6a 100644
--- a/net/sched/cls_flow.c
+++ b/net/sched/cls_flow.c
@@ -22,6 +22,7 @@
#include <linux/if_vlan.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <net/inet_sock.h>
#include <net/pkt_cls.h>
#include <net/ip.h>
@@ -197,8 +198,11 @@ static u32 flow_get_rtclassid(const struct sk_buff *skb)
static u32 flow_get_skuid(const struct sk_buff *skb)
{
- if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
- kuid_t skuid = skb->sk->sk_socket->file->f_cred->fsuid;
+ struct sock *sk = skb_to_full_sk(skb);
+
+ if (sk && sk->sk_socket && sk->sk_socket->file) {
+ kuid_t skuid = sk->sk_socket->file->f_cred->fsuid;
+
return from_kuid(&init_user_ns, skuid);
}
return 0;
@@ -206,8 +210,11 @@ static u32 flow_get_skuid(const struct sk_buff *skb)
static u32 flow_get_skgid(const struct sk_buff *skb)
{
- if (skb->sk && skb->sk->sk_socket && skb->sk->sk_socket->file) {
- kgid_t skgid = skb->sk->sk_socket->file->f_cred->fsgid;
+ struct sock *sk = skb_to_full_sk(skb);
+
+ if (sk && sk->sk_socket && sk->sk_socket->file) {
+ kgid_t skgid = sk->sk_socket->file->f_cred->fsgid;
+
return from_kgid(&init_user_ns, skgid);
}
return 0;
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index b5294ce..f2aabc0 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -343,119 +343,145 @@ META_COLLECTOR(int_sk_refcnt)
META_COLLECTOR(int_sk_rcvbuf)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_rcvbuf;
+ dst->value = sk->sk_rcvbuf;
}
META_COLLECTOR(int_sk_shutdown)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_shutdown;
+ dst->value = sk->sk_shutdown;
}
META_COLLECTOR(int_sk_proto)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_protocol;
+ dst->value = sk->sk_protocol;
}
META_COLLECTOR(int_sk_type)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_type;
+ dst->value = sk->sk_type;
}
META_COLLECTOR(int_sk_rmem_alloc)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = sk_rmem_alloc_get(skb->sk);
+ dst->value = sk_rmem_alloc_get(sk);
}
META_COLLECTOR(int_sk_wmem_alloc)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = sk_wmem_alloc_get(skb->sk);
+ dst->value = sk_wmem_alloc_get(sk);
}
META_COLLECTOR(int_sk_omem_alloc)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = atomic_read(&skb->sk->sk_omem_alloc);
+ dst->value = atomic_read(&sk->sk_omem_alloc);
}
META_COLLECTOR(int_sk_rcv_qlen)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_receive_queue.qlen;
+ dst->value = sk->sk_receive_queue.qlen;
}
META_COLLECTOR(int_sk_snd_qlen)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_write_queue.qlen;
+ dst->value = sk->sk_write_queue.qlen;
}
META_COLLECTOR(int_sk_wmem_queued)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_wmem_queued;
+ dst->value = sk->sk_wmem_queued;
}
META_COLLECTOR(int_sk_fwd_alloc)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_forward_alloc;
+ dst->value = sk->sk_forward_alloc;
}
META_COLLECTOR(int_sk_sndbuf)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_sndbuf;
+ dst->value = sk->sk_sndbuf;
}
META_COLLECTOR(int_sk_alloc)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = (__force int) skb->sk->sk_allocation;
+ dst->value = (__force int) sk->sk_allocation;
}
META_COLLECTOR(int_sk_hash)
@@ -469,92 +495,112 @@ META_COLLECTOR(int_sk_hash)
META_COLLECTOR(int_sk_lingertime)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_lingertime / HZ;
+ dst->value = sk->sk_lingertime / HZ;
}
META_COLLECTOR(int_sk_err_qlen)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_error_queue.qlen;
+ dst->value = sk->sk_error_queue.qlen;
}
META_COLLECTOR(int_sk_ack_bl)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_ack_backlog;
+ dst->value = sk->sk_ack_backlog;
}
META_COLLECTOR(int_sk_max_ack_bl)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_max_ack_backlog;
+ dst->value = sk->sk_max_ack_backlog;
}
META_COLLECTOR(int_sk_prio)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_priority;
+ dst->value = sk->sk_priority;
}
META_COLLECTOR(int_sk_rcvlowat)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_rcvlowat;
+ dst->value = sk->sk_rcvlowat;
}
META_COLLECTOR(int_sk_rcvtimeo)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_rcvtimeo / HZ;
+ dst->value = sk->sk_rcvtimeo / HZ;
}
META_COLLECTOR(int_sk_sndtimeo)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_sndtimeo / HZ;
+ dst->value = sk->sk_sndtimeo / HZ;
}
META_COLLECTOR(int_sk_sendmsg_off)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_frag.offset;
+ dst->value = sk->sk_frag.offset;
}
META_COLLECTOR(int_sk_write_pend)
{
- if (skip_nonlocal(skb)) {
+ const struct sock *sk = skb_to_full_sk(skb);
+
+ if (!sk) {
*err = -1;
return;
}
- dst->value = skb->sk->sk_write_pending;
+ dst->value = sk->sk_write_pending;
}
/**************************************************************************
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index f43c8f3..b5c2cf2 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -253,7 +253,8 @@ int qdisc_set_default(const char *name)
}
/* We know handle. Find qdisc among all qdisc's attached to device
- (root qdisc, all its children, children of children etc.)
+ * (root qdisc, all its children, children of children etc.)
+ * Note: caller either uses rtnl or rcu_read_lock()
*/
static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
@@ -264,7 +265,7 @@ static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle)
root->handle == handle)
return root;
- list_for_each_entry(q, &root->list, list) {
+ list_for_each_entry_rcu(q, &root->list, list) {
if (q->handle == handle)
return q;
}
@@ -277,15 +278,18 @@ void qdisc_list_add(struct Qdisc *q)
struct Qdisc *root = qdisc_dev(q)->qdisc;
WARN_ON_ONCE(root == &noop_qdisc);
- list_add_tail(&q->list, &root->list);
+ ASSERT_RTNL();
+ list_add_tail_rcu(&q->list, &root->list);
}
}
EXPORT_SYMBOL(qdisc_list_add);
void qdisc_list_del(struct Qdisc *q)
{
- if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS))
- list_del(&q->list);
+ if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) {
+ ASSERT_RTNL();
+ list_del_rcu(&q->list);
+ }
}
EXPORT_SYMBOL(qdisc_list_del);
@@ -750,14 +754,18 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
if (n == 0)
return;
drops = max_t(int, n, 0);
+ rcu_read_lock();
while ((parentid = sch->parent)) {
if (TC_H_MAJ(parentid) == TC_H_MAJ(TC_H_INGRESS))
- return;
+ break;
+ if (sch->flags & TCQ_F_NOPARENT)
+ break;
+ /* TODO: perform the search on a per txq basis */
sch = qdisc_lookup(qdisc_dev(sch), TC_H_MAJ(parentid));
if (sch == NULL) {
- WARN_ON(parentid != TC_H_ROOT);
- return;
+ WARN_ON_ONCE(parentid != TC_H_ROOT);
+ break;
}
cops = sch->ops->cl_ops;
if (cops->qlen_notify) {
@@ -768,6 +776,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n)
sch->q.qlen -= n;
__qdisc_qstats_drop(sch, drops);
}
+ rcu_read_unlock();
}
EXPORT_SYMBOL(qdisc_tree_decrease_qlen);
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index cb5d4ad..16bc83b 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -658,8 +658,10 @@ static void qdisc_rcu_free(struct rcu_head *head)
{
struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head);
- if (qdisc_is_percpu_stats(qdisc))
+ if (qdisc_is_percpu_stats(qdisc)) {
free_percpu(qdisc->cpu_bstats);
+ free_percpu(qdisc->cpu_qstats);
+ }
kfree((char *) qdisc - qdisc->padded);
}
@@ -737,7 +739,7 @@ static void attach_one_default_qdisc(struct net_device *dev,
return;
}
if (!netif_is_multiqueue(dev))
- qdisc->flags |= TCQ_F_ONETXQUEUE;
+ qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
dev_queue->qdisc_sleeping = qdisc;
}
diff --git a/net/sched/sch_mq.c b/net/sched/sch_mq.c
index f3cbaec..3e82f04 100644
--- a/net/sched/sch_mq.c
+++ b/net/sched/sch_mq.c
@@ -63,7 +63,7 @@ static int mq_init(struct Qdisc *sch, struct nlattr *opt)
if (qdisc == NULL)
goto err;
priv->qdiscs[ntx] = qdisc;
- qdisc->flags |= TCQ_F_ONETXQUEUE;
+ qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
}
sch->flags |= TCQ_F_MQROOT;
@@ -156,7 +156,7 @@ static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
*old = dev_graft_qdisc(dev_queue, new);
if (new)
- new->flags |= TCQ_F_ONETXQUEUE;
+ new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
if (dev->flags & IFF_UP)
dev_activate(dev);
return 0;
diff --git a/net/sched/sch_mqprio.c b/net/sched/sch_mqprio.c
index 3811a74..ad70ecf 100644
--- a/net/sched/sch_mqprio.c
+++ b/net/sched/sch_mqprio.c
@@ -132,7 +132,7 @@ static int mqprio_init(struct Qdisc *sch, struct nlattr *opt)
goto err;
}
priv->qdiscs[i] = qdisc;
- qdisc->flags |= TCQ_F_ONETXQUEUE;
+ qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
}
/* If the mqprio options indicate that hardware should own
@@ -209,7 +209,7 @@ static int mqprio_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new,
*old = dev_graft_qdisc(dev_queue, new);
if (new)
- new->flags |= TCQ_F_ONETXQUEUE;
+ new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT;
if (dev->flags & IFF_UP)
dev_activate(dev);
diff --git a/net/sctp/auth.c b/net/sctp/auth.c
index 4f15b7d..1543e39 100644
--- a/net/sctp/auth.c
+++ b/net/sctp/auth.c
@@ -809,8 +809,8 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep,
if (!has_sha1)
return -EINVAL;
- memcpy(ep->auth_hmacs_list->hmac_ids, &hmacs->shmac_idents[0],
- hmacs->shmac_num_idents * sizeof(__u16));
+ for (i = 0; i < hmacs->shmac_num_idents; i++)
+ ep->auth_hmacs_list->hmac_ids[i] = htons(hmacs->shmac_idents[i]);
ep->auth_hmacs_list->param_hdr.length = htons(sizeof(sctp_paramhdr_t) +
hmacs->shmac_num_idents * sizeof(__u16));
return 0;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index e917d27..ec52912 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -209,6 +209,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi6 *fl6 = &transport->fl.u.ip6;
+ int res;
pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
skb->len, &fl6->saddr, &fl6->daddr);
@@ -220,7 +221,10 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
- return ip6_xmit(sk, skb, fl6, np->opt, np->tclass);
+ rcu_read_lock();
+ res = ip6_xmit(sk, skb, fl6, rcu_dereference(np->opt), np->tclass);
+ rcu_read_unlock();
+ return res;
}
/* Returns the dst cache entry for the given source and destination ip
@@ -262,7 +266,10 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
pr_debug("src=%pI6 - ", &fl6->saddr);
}
- final_p = fl6_update_dst(fl6, np->opt, &final);
+ rcu_read_lock();
+ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
+ rcu_read_unlock();
+
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (!asoc || saddr)
goto out;
@@ -316,14 +323,13 @@ static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
}
}
}
- rcu_read_unlock();
-
if (baddr) {
fl6->saddr = baddr->v6.sin6_addr;
fl6->fl6_sport = baddr->v6.sin6_port;
- final_p = fl6_update_dst(fl6, np->opt, &final);
+ final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
}
+ rcu_read_unlock();
out:
if (!IS_ERR_OR_NULL(dst)) {
@@ -635,6 +641,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct sock *newsk;
struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
struct sctp6_sock *newsctp6sk;
+ struct ipv6_txoptions *opt;
newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, 0);
if (!newsk)
@@ -654,6 +661,13 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
memcpy(newnp, np, sizeof(struct ipv6_pinfo));
+ rcu_read_lock();
+ opt = rcu_dereference(np->opt);
+ if (opt)
+ opt = ipv6_dup_options(newsk, opt);
+ RCU_INIT_POINTER(newnp->opt, opt);
+ rcu_read_unlock();
+
/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
* and getpeername().
*/
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 7e8f0a1..c0380cf 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -324,6 +324,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) :
"illegal chunk");
+ sctp_chunk_hold(chunk);
sctp_outq_tail_data(q, chunk);
if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED)
SCTP_INC_STATS(net, SCTP_MIB_OUTUNORDERCHUNKS);
@@ -1251,6 +1252,7 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_chunk *chunk)
*/
sack_a_rwnd = ntohl(sack->a_rwnd);
+ asoc->peer.zero_window_announced = !sack_a_rwnd;
outstanding = q->outstanding_bytes;
if (outstanding < sack_a_rwnd)
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 763e06a..5d6a03f 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1652,7 +1652,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
/* Set an expiration time for the cookie. */
cookie->c.expiration = ktime_add(asoc->cookie_life,
- ktime_get());
+ ktime_get_real());
/* Copy the peer's init packet. */
memcpy(&cookie->c.peer_init[0], init_chunk->chunk_hdr,
@@ -1780,7 +1780,7 @@ no_hmac:
if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
kt = skb_get_ktime(skb);
else
- kt = ktime_get();
+ kt = ktime_get_real();
if (!asoc && ktime_before(bear_cookie->expiration, kt)) {
/*
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 6f46aa1..22c2bf3 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -4829,7 +4829,8 @@ sctp_disposition_t sctp_sf_do_9_1_prm_abort(
retval = SCTP_DISPOSITION_CONSUME;
- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+ if (abort)
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
/* Even if we can't send the ABORT due to low memory delete the
* TCB. This is a departure from our typical NOMEM handling.
@@ -4966,7 +4967,8 @@ sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
retval = SCTP_DISPOSITION_CONSUME;
- sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
+ if (abort)
+ sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
@@ -5412,7 +5414,8 @@ sctp_disposition_t sctp_sf_do_6_3_3_rtx(struct net *net,
SCTP_INC_STATS(net, SCTP_MIB_T3_RTX_EXPIREDS);
if (asoc->overall_error_count >= asoc->max_retrans) {
- if (asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
+ if (asoc->peer.zero_window_announced &&
+ asoc->state == SCTP_STATE_SHUTDOWN_PENDING) {
/*
* We are here likely because the receiver had its rwnd
* closed for a while and we have not been able to
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 897c01c..ef1d90f 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -972,7 +972,7 @@ static int sctp_setsockopt_bindx(struct sock *sk,
return -EFAULT;
/* Alloc space for the address array in kernel memory. */
- kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+ kaddrs = kmalloc(addrs_size, GFP_USER | __GFP_NOWARN);
if (unlikely(!kaddrs))
return -ENOMEM;
@@ -1301,8 +1301,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
int addrs_size,
sctp_assoc_t *assoc_id)
{
- int err = 0;
struct sockaddr *kaddrs;
+ gfp_t gfp = GFP_KERNEL;
+ int err = 0;
pr_debug("%s: sk:%p addrs:%p addrs_size:%d\n",
__func__, sk, addrs, addrs_size);
@@ -1315,7 +1316,9 @@ static int __sctp_setsockopt_connectx(struct sock *sk,
return -EFAULT;
/* Alloc space for the address array in kernel memory. */
- kaddrs = kmalloc(addrs_size, GFP_KERNEL);
+ if (sk->sk_socket->file)
+ gfp = GFP_USER | __GFP_NOWARN;
+ kaddrs = kmalloc(addrs_size, gfp);
if (unlikely(!kaddrs))
return -ENOMEM;
@@ -1513,8 +1516,7 @@ static void sctp_close(struct sock *sk, long timeout)
struct sctp_chunk *chunk;
chunk = sctp_make_abort_user(asoc, NULL, 0);
- if (chunk)
- sctp_primitive_ABORT(net, asoc, chunk);
+ sctp_primitive_ABORT(net, asoc, chunk);
} else
sctp_primitive_SHUTDOWN(net, asoc, NULL);
}
@@ -1952,8 +1954,6 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
/* Now send the (possibly) fragmented message. */
list_for_each_entry(chunk, &datamsg->chunks, frag_list) {
- sctp_chunk_hold(chunk);
-
/* Do accounting for the write space. */
sctp_set_owner_w(chunk);
@@ -1966,15 +1966,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
* breaks.
*/
err = sctp_primitive_SEND(net, asoc, datamsg);
+ sctp_datamsg_put(datamsg);
/* Did the lower layer accept the chunk? */
- if (err) {
- sctp_datamsg_free(datamsg);
+ if (err)
goto out_free;
- }
pr_debug("%s: we sent primitively\n", __func__);
- sctp_datamsg_put(datamsg);
err = msg_len;
if (unlikely(wait_connect)) {
@@ -4928,7 +4926,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
to = optval + offsetof(struct sctp_getaddrs, addrs);
space_left = len - offsetof(struct sctp_getaddrs, addrs);
- addrs = kmalloc(space_left, GFP_KERNEL);
+ addrs = kmalloc(space_left, GFP_USER | __GFP_NOWARN);
if (!addrs)
return -ENOMEM;
@@ -5777,7 +5775,7 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num;
- ids = kmalloc(len, GFP_KERNEL);
+ ids = kmalloc(len, GFP_USER | __GFP_NOWARN);
if (unlikely(!ids))
return -ENOMEM;
@@ -6458,7 +6456,7 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
if (sctp_writeable(sk)) {
mask |= POLLOUT | POLLWRNORM;
} else {
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
/*
* Since the socket is not locked, the buffer
* might be made available after the writeable check and
@@ -6801,26 +6799,30 @@ no_packet:
static void __sctp_write_space(struct sctp_association *asoc)
{
struct sock *sk = asoc->base.sk;
- struct socket *sock = sk->sk_socket;
- if ((sctp_wspace(asoc) > 0) && sock) {
- if (waitqueue_active(&asoc->wait))
- wake_up_interruptible(&asoc->wait);
+ if (sctp_wspace(asoc) <= 0)
+ return;
- if (sctp_writeable(sk)) {
- wait_queue_head_t *wq = sk_sleep(sk);
+ if (waitqueue_active(&asoc->wait))
+ wake_up_interruptible(&asoc->wait);
- if (wq && waitqueue_active(wq))
- wake_up_interruptible(wq);
+ if (sctp_writeable(sk)) {
+ struct socket_wq *wq;
+
+ rcu_read_lock();
+ wq = rcu_dereference(sk->sk_wq);
+ if (wq) {
+ if (waitqueue_active(&wq->wait))
+ wake_up_interruptible(&wq->wait);
/* Note that we try to include the Async I/O support
* here by modeling from the current TCP/UDP code.
* We have not tested with it yet.
*/
if (!(sk->sk_shutdown & SEND_SHUTDOWN))
- sock_wake_async(sock,
- SOCK_WAKE_SPACE, POLL_OUT);
+ sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT);
}
+ rcu_read_unlock();
}
}
@@ -7163,6 +7165,7 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
newsk->sk_type = sk->sk_type;
newsk->sk_bound_dev_if = sk->sk_bound_dev_if;
newsk->sk_flags = sk->sk_flags;
+ newsk->sk_tsflags = sk->sk_tsflags;
newsk->sk_no_check_tx = sk->sk_no_check_tx;
newsk->sk_no_check_rx = sk->sk_no_check_rx;
newsk->sk_reuse = sk->sk_reuse;
@@ -7195,6 +7198,11 @@ void sctp_copy_sock(struct sock *newsk, struct sock *sk,
newinet->mc_ttl = 1;
newinet->mc_index = 0;
newinet->mc_list = NULL;
+
+ if (newsk->sk_flags & SK_FLAGS_TIMESTAMP)
+ net_enable_timestamp();
+
+ security_sk_clone(sk, newsk);
}
static inline void sctp_copy_descendant(struct sock *sk_to,
@@ -7375,6 +7383,13 @@ struct proto sctp_prot = {
#if IS_ENABLED(CONFIG_IPV6)
+#include <net/transp_v6.h>
+static void sctp_v6_destroy_sock(struct sock *sk)
+{
+ sctp_destroy_sock(sk);
+ inet6_destroy_sock(sk);
+}
+
struct proto sctpv6_prot = {
.name = "SCTPv6",
.owner = THIS_MODULE,
@@ -7384,7 +7399,7 @@ struct proto sctpv6_prot = {
.accept = sctp_accept,
.ioctl = sctp_ioctl,
.init = sctp_init_sock,
- .destroy = sctp_destroy_sock,
+ .destroy = sctp_v6_destroy_sock,
.shutdown = sctp_shutdown,
.setsockopt = sctp_setsockopt,
.getsockopt = sctp_getsockopt,
diff --git a/net/socket.c b/net/socket.c
index dd2c247..d730ef9 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -257,6 +257,7 @@ static struct inode *sock_alloc_inode(struct super_block *sb)
}
init_waitqueue_head(&wq->wait);
wq->fasync_list = NULL;
+ wq->flags = 0;
RCU_INIT_POINTER(ei->socket.wq, wq);
ei->socket.state = SS_UNCONNECTED;
@@ -1056,27 +1057,20 @@ static int sock_fasync(int fd, struct file *filp, int on)
return 0;
}
-/* This function may be called only under socket lock or callback_lock or rcu_lock */
+/* This function may be called only under rcu_lock */
-int sock_wake_async(struct socket *sock, int how, int band)
+int sock_wake_async(struct socket_wq *wq, int how, int band)
{
- struct socket_wq *wq;
-
- if (!sock)
- return -1;
- rcu_read_lock();
- wq = rcu_dereference(sock->wq);
- if (!wq || !wq->fasync_list) {
- rcu_read_unlock();
+ if (!wq || !wq->fasync_list)
return -1;
- }
+
switch (how) {
case SOCK_WAKE_WAITD:
- if (test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))
+ if (test_bit(SOCKWQ_ASYNC_WAITDATA, &wq->flags))
break;
goto call_kill;
case SOCK_WAKE_SPACE:
- if (!test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags))
+ if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags))
break;
/* fall through */
case SOCK_WAKE_IO:
@@ -1086,7 +1080,7 @@ call_kill:
case SOCK_WAKE_URG:
kill_fasync(&wq->fasync_list, SIGURG, band);
}
- rcu_read_unlock();
+
return 0;
}
EXPORT_SYMBOL(sock_wake_async);
@@ -1702,6 +1696,7 @@ SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size,
msg.msg_name = addr ? (struct sockaddr *)&address : NULL;
/* We assume all kernel code knows the size of sockaddr_storage */
msg.msg_namelen = 0;
+ msg.msg_iocb = NULL;
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
err = sock_recvmsg(sock, &msg, iov_iter_count(&msg.msg_iter), flags);
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index dace13d..799e65b 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1411,17 +1411,16 @@ gss_key_timeout(struct rpc_cred *rc)
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
struct gss_cl_ctx *ctx;
- unsigned long now = jiffies;
- unsigned long expire;
+ unsigned long timeout = jiffies + (gss_key_expire_timeo * HZ);
+ int ret = 0;
rcu_read_lock();
ctx = rcu_dereference(gss_cred->gc_ctx);
- if (ctx)
- expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ);
+ if (!ctx || time_after(timeout, ctx->gc_expiry))
+ ret = -EACCES;
rcu_read_unlock();
- if (!ctx || time_after(now, expire))
- return -EACCES;
- return 0;
+
+ return ret;
}
static int
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index 4a2340a..5e4f815 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -41,13 +41,16 @@
static bool cache_defer_req(struct cache_req *req, struct cache_head *item);
static void cache_revisit_request(struct cache_head *item);
-static void cache_init(struct cache_head *h)
+static void cache_init(struct cache_head *h, struct cache_detail *detail)
{
time_t now = seconds_since_boot();
INIT_HLIST_NODE(&h->cache_list);
h->flags = 0;
kref_init(&h->ref);
h->expiry_time = now + CACHE_NEW_EXPIRY;
+ if (now <= detail->flush_time)
+ /* ensure it isn't already expired */
+ now = detail->flush_time + 1;
h->last_refresh = now;
}
@@ -81,7 +84,7 @@ struct cache_head *sunrpc_cache_lookup(struct cache_detail *detail,
* we might get lose if we need to
* cache_put it soon.
*/
- cache_init(new);
+ cache_init(new, detail);
detail->init(new, key);
write_lock(&detail->hash_lock);
@@ -116,10 +119,15 @@ EXPORT_SYMBOL_GPL(sunrpc_cache_lookup);
static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch);
-static void cache_fresh_locked(struct cache_head *head, time_t expiry)
+static void cache_fresh_locked(struct cache_head *head, time_t expiry,
+ struct cache_detail *detail)
{
+ time_t now = seconds_since_boot();
+ if (now <= detail->flush_time)
+ /* ensure it isn't immediately treated as expired */
+ now = detail->flush_time + 1;
head->expiry_time = expiry;
- head->last_refresh = seconds_since_boot();
+ head->last_refresh = now;
smp_wmb(); /* paired with smp_rmb() in cache_is_valid() */
set_bit(CACHE_VALID, &head->flags);
}
@@ -149,7 +157,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
set_bit(CACHE_NEGATIVE, &old->flags);
else
detail->update(old, new);
- cache_fresh_locked(old, new->expiry_time);
+ cache_fresh_locked(old, new->expiry_time, detail);
write_unlock(&detail->hash_lock);
cache_fresh_unlocked(old, detail);
return old;
@@ -162,7 +170,7 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
cache_put(old, detail);
return NULL;
}
- cache_init(tmp);
+ cache_init(tmp, detail);
detail->init(tmp, old);
write_lock(&detail->hash_lock);
@@ -173,8 +181,8 @@ struct cache_head *sunrpc_cache_update(struct cache_detail *detail,
hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]);
detail->entries++;
cache_get(tmp);
- cache_fresh_locked(tmp, new->expiry_time);
- cache_fresh_locked(old, 0);
+ cache_fresh_locked(tmp, new->expiry_time, detail);
+ cache_fresh_locked(old, 0, detail);
write_unlock(&detail->hash_lock);
cache_fresh_unlocked(tmp, detail);
cache_fresh_unlocked(old, detail);
@@ -219,7 +227,8 @@ static int try_to_negate_entry(struct cache_detail *detail, struct cache_head *h
rv = cache_is_valid(h);
if (rv == -EAGAIN) {
set_bit(CACHE_NEGATIVE, &h->flags);
- cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY);
+ cache_fresh_locked(h, seconds_since_boot()+CACHE_NEW_EXPIRY,
+ detail);
rv = -ENOENT;
}
write_unlock(&detail->hash_lock);
@@ -487,10 +496,13 @@ EXPORT_SYMBOL_GPL(cache_flush);
void cache_purge(struct cache_detail *detail)
{
- detail->flush_time = LONG_MAX;
+ time_t now = seconds_since_boot();
+ if (detail->flush_time >= now)
+ now = detail->flush_time + 1;
+ /* 'now' is the maximum value any 'last_refresh' can have */
+ detail->flush_time = now;
detail->nextcheck = seconds_since_boot();
cache_flush();
- detail->flush_time = 1;
}
EXPORT_SYMBOL_GPL(cache_purge);
@@ -1436,6 +1448,7 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
{
char tbuf[20];
char *bp, *ep;
+ time_t then, now;
if (*ppos || count > sizeof(tbuf)-1)
return -EINVAL;
@@ -1447,8 +1460,22 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
return -EINVAL;
bp = tbuf;
- cd->flush_time = get_expiry(&bp);
- cd->nextcheck = seconds_since_boot();
+ then = get_expiry(&bp);
+ now = seconds_since_boot();
+ cd->nextcheck = now;
+ /* Can only set flush_time to 1 second beyond "now", or
+ * possibly 1 second beyond flushtime. This is because
+ * flush_time never goes backwards so it mustn't get too far
+ * ahead of time.
+ */
+ if (then >= now) {
+ /* Want to flush everything, so behave like cache_purge() */
+ if (cd->flush_time >= now)
+ now = cd->flush_time + 1;
+ then = now;
+ }
+
+ cd->flush_time = then;
cache_flush();
*ppos += count;
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index f14f24e..73ad57a 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -250,11 +250,11 @@ void rpc_destroy_wait_queue(struct rpc_wait_queue *queue)
}
EXPORT_SYMBOL_GPL(rpc_destroy_wait_queue);
-static int rpc_wait_bit_killable(struct wait_bit_key *key)
+static int rpc_wait_bit_killable(struct wait_bit_key *key, int mode)
{
- if (fatal_signal_pending(current))
- return -ERESTARTSYS;
freezable_schedule_unsafe();
+ if (signal_pending_state(mode, current))
+ return -ERESTARTSYS;
return 0;
}
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index bc5b7b5..cc98528 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1364,6 +1364,19 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
+ /* Adjust the argument buffer length */
+ rqstp->rq_arg.len = req->rq_private_buf.len;
+ if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
+ rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
+ rqstp->rq_arg.page_len = 0;
+ } else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len +
+ rqstp->rq_arg.page_len)
+ rqstp->rq_arg.page_len = rqstp->rq_arg.len -
+ rqstp->rq_arg.head[0].iov_len;
+ else
+ rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len +
+ rqstp->rq_arg.page_len;
+
/* reset result send buffer "put" position */
resv->iov_len = 0;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 0c81202..1413cdc 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -181,7 +181,7 @@ int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
struct page **ppage = xdr->pages;
size_t base = xdr->page_base;
unsigned int pglen = xdr->page_len;
- unsigned int flags = MSG_MORE;
+ unsigned int flags = MSG_MORE | MSG_SENDPAGE_NOTLAST;
int slen;
int len = 0;
@@ -399,6 +399,31 @@ static int svc_sock_secure_port(struct svc_rqst *rqstp)
return svc_port_is_privileged(svc_addr(rqstp));
}
+static bool sunrpc_waitqueue_active(wait_queue_head_t *wq)
+{
+ if (!wq)
+ return false;
+ /*
+ * There should normally be a memory * barrier here--see
+ * wq_has_sleeper().
+ *
+ * It appears that isn't currently necessary, though, basically
+ * because callers all appear to have sufficient memory barriers
+ * between the time the relevant change is made and the
+ * time they call these callbacks.
+ *
+ * The nfsd code itself doesn't actually explicitly wait on
+ * these waitqueues, but it may wait on them for example in
+ * sendpage() or sendmsg() calls. (And those may be the only
+ * places, since it it uses nonblocking reads.)
+ *
+ * Maybe we should add the memory barriers anyway, but these are
+ * hot paths so we'd need to be convinced there's no sigificant
+ * penalty.
+ */
+ return waitqueue_active(wq);
+}
+
/*
* INET callback when data has been received on the socket.
*/
@@ -414,7 +439,7 @@ static void svc_udp_data_ready(struct sock *sk)
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
svc_xprt_enqueue(&svsk->sk_xprt);
}
- if (wq && waitqueue_active(wq))
+ if (sunrpc_waitqueue_active(wq))
wake_up_interruptible(wq);
}
@@ -432,7 +457,7 @@ static void svc_write_space(struct sock *sk)
svc_xprt_enqueue(&svsk->sk_xprt);
}
- if (wq && waitqueue_active(wq)) {
+ if (sunrpc_waitqueue_active(wq)) {
dprintk("RPC svc_write_space: someone sleeping on %p\n",
svsk);
wake_up_interruptible(wq);
@@ -787,7 +812,7 @@ static void svc_tcp_listen_data_ready(struct sock *sk)
}
wq = sk_sleep(sk);
- if (wq && waitqueue_active(wq))
+ if (sunrpc_waitqueue_active(wq))
wake_up_interruptible_all(wq);
}
@@ -808,7 +833,7 @@ static void svc_tcp_state_change(struct sock *sk)
set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
svc_xprt_enqueue(&svsk->sk_xprt);
}
- if (wq && waitqueue_active(wq))
+ if (sunrpc_waitqueue_active(wq))
wake_up_interruptible_all(wq);
}
@@ -823,7 +848,7 @@ static void svc_tcp_data_ready(struct sock *sk)
set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
svc_xprt_enqueue(&svsk->sk_xprt);
}
- if (wq && waitqueue_active(wq))
+ if (sunrpc_waitqueue_active(wq))
wake_up_interruptible(wq);
}
@@ -1367,7 +1392,6 @@ EXPORT_SYMBOL_GPL(svc_sock_update_bufs);
/*
* Initialize socket for RPC use and create svc_sock struct
- * XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
*/
static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
struct socket *sock,
@@ -1594,7 +1618,7 @@ static void svc_sock_detach(struct svc_xprt *xprt)
sk->sk_write_space = svsk->sk_owspace;
wq = sk_sleep(sk);
- if (wq && waitqueue_active(wq))
+ if (sunrpc_waitqueue_active(wq))
wake_up_interruptible(wq);
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 1d1a704..2ffaf6a 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -398,7 +398,7 @@ static int xs_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
if (unlikely(!sock))
return -ENOTSOCK;
- clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags);
if (base != 0) {
addr = NULL;
addrlen = 0;
@@ -442,7 +442,7 @@ static void xs_nospace_callback(struct rpc_task *task)
struct sock_xprt *transport = container_of(task->tk_rqstp->rq_xprt, struct sock_xprt, xprt);
transport->inet->sk_write_pending--;
- clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
}
/**
@@ -467,7 +467,7 @@ static int xs_nospace(struct rpc_task *task)
/* Don't race with disconnect */
if (xprt_connected(xprt)) {
- if (test_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags)) {
+ if (test_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags)) {
/*
* Notify TCP that we're limited by the application
* window size
@@ -478,7 +478,7 @@ static int xs_nospace(struct rpc_task *task)
xprt_wait_for_buffer_space(task, xs_nospace_callback);
}
} else {
- clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
ret = -ENOTCONN;
}
@@ -626,7 +626,7 @@ process_status:
case -EPERM:
/* When the server has died, an ICMP port unreachable message
* prompts ECONNREFUSED. */
- clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
}
return status;
@@ -715,7 +715,7 @@ static int xs_tcp_send_request(struct rpc_task *task)
case -EADDRINUSE:
case -ENOBUFS:
case -EPIPE:
- clear_bit(SOCK_ASYNC_NOSPACE, &transport->sock->flags);
+ clear_bit(SOCKWQ_ASYNC_NOSPACE, &transport->sock->flags);
}
return status;
@@ -1618,7 +1618,7 @@ static void xs_write_space(struct sock *sk)
if (unlikely(!(xprt = xprt_from_sock(sk))))
return;
- if (test_and_clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags) == 0)
+ if (test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &sock->flags) == 0)
return;
xprt_write_space(xprt);
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 9efbdbd..91aea07 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -191,6 +191,7 @@ void tipc_link_add_bc_peer(struct tipc_link *snd_l,
snd_l->ackers++;
rcv_l->acked = snd_l->snd_nxt - 1;
+ snd_l->state = LINK_ESTABLISHED;
tipc_link_build_bc_init_msg(uc_l, xmitq);
}
@@ -206,6 +207,7 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l,
rcv_l->state = LINK_RESET;
if (!snd_l->ackers) {
tipc_link_reset(snd_l);
+ snd_l->state = LINK_RESET;
__skb_queue_purge(xmitq);
}
}
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 552dbab..b53246f 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -105,6 +105,7 @@ struct tipc_sock {
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
static void tipc_data_ready(struct sock *sk);
static void tipc_write_space(struct sock *sk);
+static void tipc_sock_destruct(struct sock *sk);
static int tipc_release(struct socket *sock);
static int tipc_accept(struct socket *sock, struct socket *new_sock, int flags);
static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p);
@@ -381,6 +382,7 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
sk->sk_rcvbuf = sysctl_tipc_rmem[1];
sk->sk_data_ready = tipc_data_ready;
sk->sk_write_space = tipc_write_space;
+ sk->sk_destruct = tipc_sock_destruct;
tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
tsk->sent_unacked = 0;
atomic_set(&tsk->dupl_rcvcnt, 0);
@@ -470,9 +472,6 @@ static int tipc_release(struct socket *sock)
tipc_node_remove_conn(net, dnode, tsk->portid);
}
- /* Discard any remaining (connection-based) messages in receive queue */
- __skb_queue_purge(&sk->sk_receive_queue);
-
/* Reject any messages that accumulated in backlog queue */
sock->state = SS_DISCONNECTING;
release_sock(sk);
@@ -1515,6 +1514,11 @@ static void tipc_data_ready(struct sock *sk)
rcu_read_unlock();
}
+static void tipc_sock_destruct(struct sock *sk)
+{
+ __skb_queue_purge(&sk->sk_receive_queue);
+}
+
/**
* filter_connect - Handle all incoming messages for a connection-based socket
* @tsk: TIPC socket
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index ad2719a..70c0327 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -158,8 +158,11 @@ static int tipc_udp_send_msg(struct net *net, struct sk_buff *skb,
struct udp_media_addr *src = (struct udp_media_addr *)&b->addr.value;
struct rtable *rt;
- if (skb_headroom(skb) < UDP_MIN_HEADROOM)
- pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
+ if (skb_headroom(skb) < UDP_MIN_HEADROOM) {
+ err = pskb_expand_head(skb, UDP_MIN_HEADROOM, 0, GFP_ATOMIC);
+ if (err)
+ goto tx_error;
+ }
skb_set_inner_protocol(skb, htons(ETH_P_TIPC));
ub = rcu_dereference_rtnl(b->media_ptr);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index aaa0b58..ef05cd9 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -326,6 +326,118 @@ found:
return s;
}
+/* Support code for asymmetrically connected dgram sockets
+ *
+ * If a datagram socket is connected to a socket not itself connected
+ * to the first socket (eg, /dev/log), clients may only enqueue more
+ * messages if the present receive queue of the server socket is not
+ * "too large". This means there's a second writeability condition
+ * poll and sendmsg need to test. The dgram recv code will do a wake
+ * up on the peer_wait wait queue of a socket upon reception of a
+ * datagram which needs to be propagated to sleeping would-be writers
+ * since these might not have sent anything so far. This can't be
+ * accomplished via poll_wait because the lifetime of the server
+ * socket might be less than that of its clients if these break their
+ * association with it or if the server socket is closed while clients
+ * are still connected to it and there's no way to inform "a polling
+ * implementation" that it should let go of a certain wait queue
+ *
+ * In order to propagate a wake up, a wait_queue_t of the client
+ * socket is enqueued on the peer_wait queue of the server socket
+ * whose wake function does a wake_up on the ordinary client socket
+ * wait queue. This connection is established whenever a write (or
+ * poll for write) hit the flow control condition and broken when the
+ * association to the server socket is dissolved or after a wake up
+ * was relayed.
+ */
+
+static int unix_dgram_peer_wake_relay(wait_queue_t *q, unsigned mode, int flags,
+ void *key)
+{
+ struct unix_sock *u;
+ wait_queue_head_t *u_sleep;
+
+ u = container_of(q, struct unix_sock, peer_wake);
+
+ __remove_wait_queue(&unix_sk(u->peer_wake.private)->peer_wait,
+ q);
+ u->peer_wake.private = NULL;
+
+ /* relaying can only happen while the wq still exists */
+ u_sleep = sk_sleep(&u->sk);
+ if (u_sleep)
+ wake_up_interruptible_poll(u_sleep, key);
+
+ return 0;
+}
+
+static int unix_dgram_peer_wake_connect(struct sock *sk, struct sock *other)
+{
+ struct unix_sock *u, *u_other;
+ int rc;
+
+ u = unix_sk(sk);
+ u_other = unix_sk(other);
+ rc = 0;
+ spin_lock(&u_other->peer_wait.lock);
+
+ if (!u->peer_wake.private) {
+ u->peer_wake.private = other;
+ __add_wait_queue(&u_other->peer_wait, &u->peer_wake);
+
+ rc = 1;
+ }
+
+ spin_unlock(&u_other->peer_wait.lock);
+ return rc;
+}
+
+static void unix_dgram_peer_wake_disconnect(struct sock *sk,
+ struct sock *other)
+{
+ struct unix_sock *u, *u_other;
+
+ u = unix_sk(sk);
+ u_other = unix_sk(other);
+ spin_lock(&u_other->peer_wait.lock);
+
+ if (u->peer_wake.private == other) {
+ __remove_wait_queue(&u_other->peer_wait, &u->peer_wake);
+ u->peer_wake.private = NULL;
+ }
+
+ spin_unlock(&u_other->peer_wait.lock);
+}
+
+static void unix_dgram_peer_wake_disconnect_wakeup(struct sock *sk,
+ struct sock *other)
+{
+ unix_dgram_peer_wake_disconnect(sk, other);
+ wake_up_interruptible_poll(sk_sleep(sk),
+ POLLOUT |
+ POLLWRNORM |
+ POLLWRBAND);
+}
+
+/* preconditions:
+ * - unix_peer(sk) == other
+ * - association is stable
+ */
+static int unix_dgram_peer_wake_me(struct sock *sk, struct sock *other)
+{
+ int connected;
+
+ connected = unix_dgram_peer_wake_connect(sk, other);
+
+ if (unix_recvq_full(other))
+ return 1;
+
+ if (connected)
+ unix_dgram_peer_wake_disconnect(sk, other);
+
+ return 0;
+}
+
static int unix_writable(const struct sock *sk)
{
return sk->sk_state != TCP_LISTEN &&
@@ -431,6 +543,8 @@ static void unix_release_sock(struct sock *sk, int embrion)
skpair->sk_state_change(skpair);
sk_wake_async(skpair, SOCK_WAKE_WAITD, POLL_HUP);
}
+
+ unix_dgram_peer_wake_disconnect(sk, skpair);
sock_put(skpair); /* It may now die */
unix_peer(sk) = NULL;
}
@@ -441,6 +555,7 @@ static void unix_release_sock(struct sock *sk, int embrion)
if (state == TCP_LISTEN)
unix_release_sock(skb->sk, 1);
/* passed fds are erased in the kfree_skb hook */
+ UNIXCB(skb).consumed = skb->len;
kfree_skb(skb);
}
@@ -665,6 +780,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock, int kern)
INIT_LIST_HEAD(&u->link);
mutex_init(&u->readlock); /* single task reading lock */
init_waitqueue_head(&u->peer_wait);
+ init_waitqueue_func_entry(&u->peer_wake, unix_dgram_peer_wake_relay);
unix_insert_socket(unix_sockets_unbound(sk), sk);
out:
if (sk == NULL)
@@ -837,32 +953,20 @@ fail:
return NULL;
}
-static int unix_mknod(const char *sun_path, umode_t mode, struct path *res)
+static int unix_mknod(struct dentry *dentry, struct path *path, umode_t mode,
+ struct path *res)
{
- struct dentry *dentry;
- struct path path;
- int err = 0;
- /*
- * Get the parent directory, calculate the hash for last
- * component.
- */
- dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
- err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- return err;
+ int err;
- /*
- * All right, let's create it.
- */
- err = security_path_mknod(&path, dentry, mode, 0);
+ err = security_path_mknod(path, dentry, mode, 0);
if (!err) {
- err = vfs_mknod(d_inode(path.dentry), dentry, mode, 0);
+ err = vfs_mknod(d_inode(path->dentry), dentry, mode, 0);
if (!err) {
- res->mnt = mntget(path.mnt);
+ res->mnt = mntget(path->mnt);
res->dentry = dget(dentry);
}
}
- done_path_create(&path, dentry);
+
return err;
}
@@ -873,10 +977,12 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct unix_sock *u = unix_sk(sk);
struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
char *sun_path = sunaddr->sun_path;
- int err;
+ int err, name_err;
unsigned int hash;
struct unix_address *addr;
struct hlist_head *list;
+ struct path path;
+ struct dentry *dentry;
err = -EINVAL;
if (sunaddr->sun_family != AF_UNIX)
@@ -892,14 +998,34 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out;
addr_len = err;
+ name_err = 0;
+ dentry = NULL;
+ if (sun_path[0]) {
+ /* Get the parent directory, calculate the hash for last
+ * component.
+ */
+ dentry = kern_path_create(AT_FDCWD, sun_path, &path, 0);
+
+ if (IS_ERR(dentry)) {
+ /* delay report until after 'already bound' check */
+ name_err = PTR_ERR(dentry);
+ dentry = NULL;
+ }
+ }
+
err = mutex_lock_interruptible(&u->readlock);
if (err)
- goto out;
+ goto out_path;
err = -EINVAL;
if (u->addr)
goto out_up;
+ if (name_err) {
+ err = name_err == -EEXIST ? -EADDRINUSE : name_err;
+ goto out_up;
+ }
+
err = -ENOMEM;
addr = kmalloc(sizeof(*addr)+addr_len, GFP_KERNEL);
if (!addr)
@@ -910,11 +1036,11 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
addr->hash = hash ^ sk->sk_type;
atomic_set(&addr->refcnt, 1);
- if (sun_path[0]) {
- struct path path;
+ if (dentry) {
+ struct path u_path;
umode_t mode = S_IFSOCK |
(SOCK_INODE(sock)->i_mode & ~current_umask());
- err = unix_mknod(sun_path, mode, &path);
+ err = unix_mknod(dentry, &path, mode, &u_path);
if (err) {
if (err == -EEXIST)
err = -EADDRINUSE;
@@ -922,9 +1048,9 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
goto out_up;
}
addr->hash = UNIX_HASH_SIZE;
- hash = d_backing_inode(path.dentry)->i_ino & (UNIX_HASH_SIZE-1);
+ hash = d_backing_inode(dentry)->i_ino & (UNIX_HASH_SIZE - 1);
spin_lock(&unix_table_lock);
- u->path = path;
+ u->path = u_path;
list = &unix_socket_table[hash];
} else {
spin_lock(&unix_table_lock);
@@ -947,6 +1073,10 @@ out_unlock:
spin_unlock(&unix_table_lock);
out_up:
mutex_unlock(&u->readlock);
+out_path:
+ if (dentry)
+ done_path_create(&path, dentry);
+
out:
return err;
}
@@ -1032,6 +1162,8 @@ restart:
if (unix_peer(sk)) {
struct sock *old_peer = unix_peer(sk);
unix_peer(sk) = other;
+ unix_dgram_peer_wake_disconnect_wakeup(sk, old_peer);
+
unix_state_double_unlock(sk, other);
if (other != old_peer)
@@ -1433,6 +1565,14 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return err;
}
+static bool unix_passcred_enabled(const struct socket *sock,
+ const struct sock *other)
+{
+ return test_bit(SOCK_PASSCRED, &sock->flags) ||
+ !other->sk_socket ||
+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags);
+}
+
/*
* Some apps rely on write() giving SCM_CREDENTIALS
* We include credentials if source or destination socket
@@ -1443,14 +1583,41 @@ static void maybe_add_creds(struct sk_buff *skb, const struct socket *sock,
{
if (UNIXCB(skb).pid)
return;
- if (test_bit(SOCK_PASSCRED, &sock->flags) ||
- !other->sk_socket ||
- test_bit(SOCK_PASSCRED, &other->sk_socket->flags)) {
+ if (unix_passcred_enabled(sock, other)) {
UNIXCB(skb).pid = get_pid(task_tgid(current));
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
}
}
+static int maybe_init_creds(struct scm_cookie *scm,
+ struct socket *socket,
+ const struct sock *other)
+{
+ int err;
+ struct msghdr msg = { .msg_controllen = 0 };
+
+ err = scm_send(socket, &msg, scm, false);
+ if (err)
+ return err;
+
+ if (unix_passcred_enabled(socket, other)) {
+ scm->pid = get_pid(task_tgid(current));
+ current_uid_gid(&scm->creds.uid, &scm->creds.gid);
+ }
+ return err;
+}
+
+static bool unix_skb_scm_eq(struct sk_buff *skb,
+ struct scm_cookie *scm)
+{
+ const struct unix_skb_parms *u = &UNIXCB(skb);
+
+ return u->pid == scm->pid &&
+ uid_eq(u->uid, scm->creds.uid) &&
+ gid_eq(u->gid, scm->creds.gid) &&
+ unix_secdata_eq(scm, skb);
+}
+
/*
* Send AF_UNIX data.
*/
@@ -1471,6 +1638,7 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,
struct scm_cookie scm;
int max_level;
int data_len = 0;
+ int sk_locked;
wait_for_unix_gc();
err = scm_send(sock, msg, &scm, false);
@@ -1549,12 +1717,14 @@ restart:
goto out_free;
}
+ sk_locked = 0;
unix_state_lock(other);
+restart_locked:
err = -EPERM;
if (!unix_may_send(sk, other))
goto out_unlock;
- if (sock_flag(other, SOCK_DEAD)) {
+ if (unlikely(sock_flag(other, SOCK_DEAD))) {
/*
* Check with 1003.1g - what should
* datagram error
@@ -1562,10 +1732,14 @@ restart:
unix_state_unlock(other);
sock_put(other);
+ if (!sk_locked)
+ unix_state_lock(sk);
+
err = 0;
- unix_state_lock(sk);
if (unix_peer(sk) == other) {
unix_peer(sk) = NULL;
+ unix_dgram_peer_wake_disconnect_wakeup(sk, other);
+
unix_state_unlock(sk);
unix_dgram_disconnected(sk, other);
@@ -1591,21 +1765,38 @@ restart:
goto out_unlock;
}
- if (unix_peer(other) != sk && unix_recvq_full(other)) {
- if (!timeo) {
- err = -EAGAIN;
- goto out_unlock;
+ if (unlikely(unix_peer(other) != sk && unix_recvq_full(other))) {
+ if (timeo) {
+ timeo = unix_wait_for_peer(other, timeo);
+
+ err = sock_intr_errno(timeo);
+ if (signal_pending(current))
+ goto out_free;
+
+ goto restart;
}
- timeo = unix_wait_for_peer(other, timeo);
+ if (!sk_locked) {
+ unix_state_unlock(other);
+ unix_state_double_lock(sk, other);
+ }
- err = sock_intr_errno(timeo);
- if (signal_pending(current))
- goto out_free;
+ if (unix_peer(sk) != other ||
+ unix_dgram_peer_wake_me(sk, other)) {
+ err = -EAGAIN;
+ sk_locked = 1;
+ goto out_unlock;
+ }
- goto restart;
+ if (!sk_locked) {
+ sk_locked = 1;
+ goto restart_locked;
+ }
}
+ if (unlikely(sk_locked))
+ unix_state_unlock(sk);
+
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
maybe_add_creds(skb, sock, other);
@@ -1619,6 +1810,8 @@ restart:
return len;
out_unlock:
+ if (sk_locked)
+ unix_state_unlock(sk);
unix_state_unlock(other);
out_free:
kfree_skb(skb);
@@ -1740,8 +1933,10 @@ out_err:
static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,
int offset, size_t size, int flags)
{
- int err = 0;
- bool send_sigpipe = true;
+ int err;
+ bool send_sigpipe = false;
+ bool init_scm = true;
+ struct scm_cookie scm;
struct sock *other, *sk = socket->sk;
struct sk_buff *skb, *newskb = NULL, *tail = NULL;
@@ -1759,7 +1954,7 @@ alloc_skb:
newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT,
&err, 0);
if (!newskb)
- return err;
+ goto err;
}
/* we must acquire readlock as we modify already present
@@ -1768,12 +1963,12 @@ alloc_skb:
err = mutex_lock_interruptible(&unix_sk(other)->readlock);
if (err) {
err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS;
- send_sigpipe = false;
goto err;
}
if (sk->sk_shutdown & SEND_SHUTDOWN) {
err = -EPIPE;
+ send_sigpipe = true;
goto err_unlock;
}
@@ -1782,23 +1977,34 @@ alloc_skb:
if (sock_flag(other, SOCK_DEAD) ||
other->sk_shutdown & RCV_SHUTDOWN) {
err = -EPIPE;
+ send_sigpipe = true;
goto err_state_unlock;
}
+ if (init_scm) {
+ err = maybe_init_creds(&scm, socket, other);
+ if (err)
+ goto err_state_unlock;
+ init_scm = false;
+ }
+
skb = skb_peek_tail(&other->sk_receive_queue);
if (tail && tail == skb) {
skb = newskb;
- } else if (!skb) {
- if (newskb)
+ } else if (!skb || !unix_skb_scm_eq(skb, &scm)) {
+ if (newskb) {
skb = newskb;
- else
+ } else {
+ tail = skb;
goto alloc_skb;
+ }
} else if (newskb) {
/* this is fast path, we don't necessarily need to
* call to kfree_skb even though with newskb == NULL
* this - does no harm
*/
consume_skb(newskb);
+ newskb = NULL;
}
if (skb_append_pagefrags(skb, page, offset, size)) {
@@ -1811,14 +2017,20 @@ alloc_skb:
skb->truesize += size;
atomic_add(size, &sk->sk_wmem_alloc);
- if (newskb)
+ if (newskb) {
+ err = unix_scm_to_skb(&scm, skb, false);
+ if (err)
+ goto err_state_unlock;
+ spin_lock(&other->sk_receive_queue.lock);
__skb_queue_tail(&other->sk_receive_queue, newskb);
+ spin_unlock(&other->sk_receive_queue.lock);
+ }
unix_state_unlock(other);
mutex_unlock(&unix_sk(other)->readlock);
other->sk_data_ready(other);
-
+ scm_destroy(&scm);
return size;
err_state_unlock:
@@ -1829,6 +2041,8 @@ err:
kfree_skb(newskb);
if (send_sigpipe && !(flags & MSG_NOSIGNAL))
send_sig(SIGPIPE, current, 0);
+ if (!init_scm)
+ scm_destroy(&scm);
return err;
}
@@ -1991,7 +2205,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
!timeo)
break;
- set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk);
unix_state_unlock(sk);
timeo = freezable_schedule_timeout(timeo);
unix_state_lock(sk);
@@ -1999,7 +2213,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo,
if (sock_flag(sk, SOCK_DEAD))
break;
- clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+ sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk);
}
finish_wait(sk_sleep(sk), &wait);
@@ -2056,14 +2270,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
/* Lock the socket to prevent queue disordering
* while sleeps in memcpy_tomsg
*/
- err = mutex_lock_interruptible(&u->readlock);
- if (unlikely(err)) {
- /* recvmsg() in non blocking mode is supposed to return -EAGAIN
- * sk_rcvtimeo is not honored by mutex_lock_interruptible()
- */
- err = noblock ? -EAGAIN : -ERESTARTSYS;
- goto out;
- }
+ mutex_lock(&u->readlock);
if (flags & MSG_PEEK)
skip = sk_peek_offset(sk, flags);
@@ -2072,6 +2279,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state)
do {
int chunk;
+ bool drop_skb;
struct sk_buff *skb, *last;
unix_state_lock(sk);
@@ -2106,12 +2314,12 @@ again:
timeo = unix_stream_data_wait(sk, timeo, last,
last_len);
- if (signal_pending(current) ||
- mutex_lock_interruptible(&u->readlock)) {
+ if (signal_pending(current)) {
err = sock_intr_errno(timeo);
goto out;
}
+ mutex_lock(&u->readlock);
continue;
unlock:
unix_state_unlock(sk);
@@ -2131,10 +2339,7 @@ unlock:
if (check_creds) {
/* Never glue messages from different writers */
- if ((UNIXCB(skb).pid != scm.pid) ||
- !uid_eq(UNIXCB(skb).uid, scm.creds.uid) ||
- !gid_eq(UNIXCB(skb).gid, scm.creds.gid) ||
- !unix_secdata_eq(&scm, skb))
+ if (!unix_skb_scm_eq(skb, &scm))
break;
} else if (test_bit(SOCK_PASSCRED, &sock->flags)) {
/* Copy credentials */
@@ -2152,7 +2357,11 @@ unlock:
}
chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size);
+ skb_get(skb);
chunk = state->recv_actor(skb, skip, chunk, state);
+ drop_skb = !unix_skb_len(skb);
+ /* skb is only safe to use if !drop_skb */
+ consume_skb(skb);
if (chunk < 0) {
if (copied == 0)
copied = -EFAULT;
@@ -2161,6 +2370,18 @@ unlock:
copied += chunk;
size -= chunk;
+ if (drop_skb) {
+ /* the skb was touched by a concurrent reader;
+ * we should not expect anything from this skb
+ * anymore and assume it invalid - we can be
+ * sure it was dropped from the socket queue
+ *
+ * let's report a short read
+ */
+ err = 0;
+ break;
+ }
+
/* Mark read part of skb as used */
if (!(flags & MSG_PEEK)) {
UNIXCB(skb).consumed += chunk;
@@ -2454,20 +2675,22 @@ static unsigned int unix_dgram_poll(struct file *file, struct socket *sock,
return mask;
writable = unix_writable(sk);
- other = unix_peer_get(sk);
- if (other) {
- if (unix_peer(other) != sk) {
- sock_poll_wait(file, &unix_sk(other)->peer_wait, wait);
- if (unix_recvq_full(other))
- writable = 0;
- }
- sock_put(other);
+ if (writable) {
+ unix_state_lock(sk);
+
+ other = unix_peer(sk);
+ if (other && unix_peer(other) != sk &&
+ unix_recvq_full(other) &&
+ unix_dgram_peer_wake_me(sk, other))
+ writable = 0;
+
+ unix_state_unlock(sk);
}
if (writable)
mask |= POLLOUT | POLLWRNORM | POLLWRBAND;
else
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
+ sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);
return mask;
}
diff --git a/net/vmw_vsock/vmci_transport.c b/net/vmw_vsock/vmci_transport.c
index 400d872..0a369bb 100644
--- a/net/vmw_vsock/vmci_transport.c
+++ b/net/vmw_vsock/vmci_transport.c
@@ -1234,7 +1234,7 @@ vmci_transport_recv_connecting_server(struct sock *listener,
/* Callers of accept() will be be waiting on the listening socket, not
* the pending socket.
*/
- listener->sk_state_change(listener);
+ listener->sk_data_ready(listener);
return 0;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c71e274..75b0d23 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -7941,8 +7941,10 @@ static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
if (nla_get_flag(info->attrs[NL80211_ATTR_USE_RRM])) {
if (!(rdev->wiphy.features &
NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES) ||
- !(rdev->wiphy.features & NL80211_FEATURE_QUIET))
+ !(rdev->wiphy.features & NL80211_FEATURE_QUIET)) {
+ kzfree(connkeys);
return -EINVAL;
+ }
connect.flags |= ASSOC_REQ_USE_RRM;
}
@@ -9503,6 +9505,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
if (new_triggers.tcp && new_triggers.tcp->sock)
sock_release(new_triggers.tcp->sock);
kfree(new_triggers.tcp);
+ kfree(new_triggers.nd_config);
return err;
}
#endif
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 2e8d6f3..06d050d 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -3029,6 +3029,7 @@ int set_regdom(const struct ieee80211_regdomain *rd,
break;
default:
WARN(1, "invalid initiator %d\n", lr->initiator);
+ kfree(rd);
return -EINVAL;
}
@@ -3221,8 +3222,10 @@ int __init regulatory_init(void)
/* We always try to get an update for the static regdomain */
err = regulatory_hint_core(cfg80211_world_regdom->alpha2);
if (err) {
- if (err == -ENOMEM)
+ if (err == -ENOMEM) {
+ platform_device_unregister(reg_pdev);
return err;
+ }
/*
* N.B. kobject_uevent_env() can fail mainly for when we're out
* memory which is handled and propagated appropriately above
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 09bfcba..b5e665b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -303,6 +303,14 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp)
}
EXPORT_SYMBOL(xfrm_policy_alloc);
+static void xfrm_policy_destroy_rcu(struct rcu_head *head)
+{
+ struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu);
+
+ security_xfrm_policy_free(policy->security);
+ kfree(policy);
+}
+
/* Destroy xfrm_policy: descendant resources must be released to this moment. */
void xfrm_policy_destroy(struct xfrm_policy *policy)
@@ -312,8 +320,7 @@ void xfrm_policy_destroy(struct xfrm_policy *policy)
if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
BUG();
- security_xfrm_policy_free(policy->security);
- kfree(policy);
+ call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
}
EXPORT_SYMBOL(xfrm_policy_destroy);
@@ -1214,8 +1221,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
struct xfrm_policy *pol;
struct net *net = sock_net(sk);
+ rcu_read_lock();
read_lock_bh(&net->xfrm.xfrm_policy_lock);
- if ((pol = sk->sk_policy[dir]) != NULL) {
+ pol = rcu_dereference(sk->sk_policy[dir]);
+ if (pol != NULL) {
bool match = xfrm_selector_match(&pol->selector, fl,
sk->sk_family);
int err = 0;
@@ -1239,6 +1248,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir,
}
out:
read_unlock_bh(&net->xfrm.xfrm_policy_lock);
+ rcu_read_unlock();
return pol;
}
@@ -1307,13 +1317,14 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
#endif
write_lock_bh(&net->xfrm.xfrm_policy_lock);
- old_pol = sk->sk_policy[dir];
- sk->sk_policy[dir] = pol;
+ old_pol = rcu_dereference_protected(sk->sk_policy[dir],
+ lockdep_is_held(&net->xfrm.xfrm_policy_lock));
if (pol) {
pol->curlft.add_time = get_seconds();
pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
xfrm_sk_policy_link(pol, dir);
}
+ rcu_assign_pointer(sk->sk_policy[dir], pol);
if (old_pol) {
if (pol)
xfrm_policy_requeue(old_pol, pol);
@@ -1361,17 +1372,26 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
return newp;
}
-int __xfrm_sk_clone_policy(struct sock *sk)
+int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk)
{
- struct xfrm_policy *p0 = sk->sk_policy[0],
- *p1 = sk->sk_policy[1];
+ const struct xfrm_policy *p;
+ struct xfrm_policy *np;
+ int i, ret = 0;
- sk->sk_policy[0] = sk->sk_policy[1] = NULL;
- if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL)
- return -ENOMEM;
- if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL)
- return -ENOMEM;
- return 0;
+ rcu_read_lock();
+ for (i = 0; i < 2; i++) {
+ p = rcu_dereference(osk->sk_policy[i]);
+ if (p) {
+ np = clone_policy(p, i);
+ if (unlikely(!np)) {
+ ret = -ENOMEM;
+ break;
+ }
+ rcu_assign_pointer(sk->sk_policy[i], np);
+ }
+ }
+ rcu_read_unlock();
+ return ret;
}
static int
@@ -2198,6 +2218,7 @@ struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig,
xdst = NULL;
route = NULL;
+ sk = sk_const_to_full_sk(sk);
if (sk && sk->sk_policy[XFRM_POLICY_OUT]) {
num_pols = 1;
pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
@@ -2477,6 +2498,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
pol = NULL;
+ sk = sk_to_full_sk(sk);
if (sk && sk->sk_policy[dir]) {
pol = xfrm_sk_policy_lookup(sk, dir, &fl);
if (IS_ERR(pol)) {
@@ -2804,7 +2826,6 @@ static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst,
int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
{
- struct net *net;
int err = 0;
if (unlikely(afinfo == NULL))
return -EINVAL;
@@ -2835,26 +2856,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
}
spin_unlock(&xfrm_policy_afinfo_lock);
- rtnl_lock();
- for_each_net(net) {
- struct dst_ops *xfrm_dst_ops;
-
- switch (afinfo->family) {
- case AF_INET:
- xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops;
- break;
-#if IS_ENABLED(CONFIG_IPV6)
- case AF_INET6:
- xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops;
- break;
-#endif
- default:
- BUG();
- }
- *xfrm_dst_ops = *afinfo->dst_ops;
- }
- rtnl_unlock();
-
return err;
}
EXPORT_SYMBOL(xfrm_policy_register_afinfo);
@@ -2890,22 +2891,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
}
EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
-static void __net_init xfrm_dst_ops_init(struct net *net)
-{
- struct xfrm_policy_afinfo *afinfo;
-
- rcu_read_lock();
- afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET]);
- if (afinfo)
- net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops;
-#if IS_ENABLED(CONFIG_IPV6)
- afinfo = rcu_dereference(xfrm_policy_afinfo[AF_INET6]);
- if (afinfo)
- net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops;
-#endif
- rcu_read_unlock();
-}
-
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = netdev_notifier_info_to_dev(ptr);
@@ -3054,7 +3039,6 @@ static int __net_init xfrm_net_init(struct net *net)
rv = xfrm_policy_init(net);
if (rv < 0)
goto out_policy;
- xfrm_dst_ops_init(net);
rv = xfrm_sysctl_init(net);
if (rv < 0)
goto out_sysctl;
diff --git a/samples/Kconfig b/samples/Kconfig
index 224ebb4..d54f28c 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -70,4 +70,10 @@ config SAMPLE_LIVEPATCH
Builds a sample live patch that replaces the procfs handler
for /proc/cmdline to print "this has been live patched".
+config SAMPLE_CONFIGFS
+ tristate "Build configfs patching sample -- loadable modules only"
+ depends on CONFIGFS_FS && m
+ help
+ Builds a sample configfs interface.
+
endif # SAMPLES
diff --git a/samples/Makefile b/samples/Makefile
index f00257b..48001d7 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -1,4 +1,5 @@
# Makefile for Linux samples code
obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \
- hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/
+ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \
+ configfs/
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 79b4596..edd638b 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -67,10 +67,13 @@ HOSTLOADLIBES_lathist += -lelf
# point this to your LLVM backend with bpf support
LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
+# asm/sysreg.h inline assmbly used by it is incompatible with llvm.
+# But, ehere is not easy way to fix it, so just exclude it since it is
+# useless for BPF samples.
$(obj)/%.o: $(src)/%.c
clang $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \
- -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \
+ -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
-O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
clang $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \
- -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \
+ -D__KERNEL__ -D__ASM_SYSREG_H -Wno-unused-value -Wno-pointer-sign \
-O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=asm -o $@.s
diff --git a/samples/configfs/Makefile b/samples/configfs/Makefile
new file mode 100644
index 0000000..a9afd99
--- /dev/null
+++ b/samples/configfs/Makefile
@@ -0,0 +1,2 @@
+
+obj-$(CONFIG_SAMPLE_CONFIGFS) += configfs_sample.o
diff --git a/Documentation/filesystems/configfs/configfs_example_macros.c b/samples/configfs/configfs_sample.c
index 327dfbc..1ea3311 100644
--- a/Documentation/filesystems/configfs/configfs_example_macros.c
+++ b/samples/configfs/configfs_sample.c
@@ -54,18 +54,13 @@ struct childless {
static inline struct childless *to_childless(struct config_item *item)
{
- return item ? container_of(to_configfs_subsystem(to_config_group(item)), struct childless, subsys) : NULL;
+ return item ? container_of(to_configfs_subsystem(to_config_group(item)),
+ struct childless, subsys) : NULL;
}
-CONFIGFS_ATTR_STRUCT(childless);
-#define CHILDLESS_ATTR(_name, _mode, _show, _store) \
-struct childless_attribute childless_attr_##_name = __CONFIGFS_ATTR(_name, _mode, _show, _store)
-#define CHILDLESS_ATTR_RO(_name, _show) \
-struct childless_attribute childless_attr_##_name = __CONFIGFS_ATTR_RO(_name, _show);
-
-static ssize_t childless_showme_read(struct childless *childless,
- char *page)
+static ssize_t childless_showme_show(struct config_item *item, char *page)
{
+ struct childless *childless = to_childless(item);
ssize_t pos;
pos = sprintf(page, "%d\n", childless->showme);
@@ -74,16 +69,15 @@ static ssize_t childless_showme_read(struct childless *childless,
return pos;
}
-static ssize_t childless_storeme_read(struct childless *childless,
- char *page)
+static ssize_t childless_storeme_show(struct config_item *item, char *page)
{
- return sprintf(page, "%d\n", childless->storeme);
+ return sprintf(page, "%d\n", to_childless(item)->storeme);
}
-static ssize_t childless_storeme_write(struct childless *childless,
- const char *page,
- size_t count)
+static ssize_t childless_storeme_store(struct config_item *item,
+ const char *page, size_t count)
{
+ struct childless *childless = to_childless(item);
unsigned long tmp;
char *p = (char *) page;
@@ -99,8 +93,7 @@ static ssize_t childless_storeme_write(struct childless *childless,
return count;
}
-static ssize_t childless_description_read(struct childless *childless,
- char *page)
+static ssize_t childless_description_show(struct config_item *item, char *page)
{
return sprintf(page,
"[01-childless]\n"
@@ -111,26 +104,18 @@ static ssize_t childless_description_read(struct childless *childless,
"than a directory in /proc.\n");
}
-CHILDLESS_ATTR_RO(showme, childless_showme_read);
-CHILDLESS_ATTR(storeme, S_IRUGO | S_IWUSR, childless_storeme_read,
- childless_storeme_write);
-CHILDLESS_ATTR_RO(description, childless_description_read);
+CONFIGFS_ATTR_RO(childless_, showme);
+CONFIGFS_ATTR(childless_, storeme);
+CONFIGFS_ATTR_RO(childless_, description);
static struct configfs_attribute *childless_attrs[] = {
- &childless_attr_showme.attr,
- &childless_attr_storeme.attr,
- &childless_attr_description.attr,
+ &childless_attr_showme,
+ &childless_attr_storeme,
+ &childless_attr_description,
NULL,
};
-CONFIGFS_ATTR_OPS(childless);
-static struct configfs_item_operations childless_item_ops = {
- .show_attribute = childless_attr_show,
- .store_attribute = childless_attr_store,
-};
-
static struct config_item_type childless_type = {
- .ct_item_ops = &childless_item_ops,
.ct_attrs = childless_attrs,
.ct_owner = THIS_MODULE,
};
@@ -168,32 +153,13 @@ static inline struct simple_child *to_simple_child(struct config_item *item)
return item ? container_of(item, struct simple_child, item) : NULL;
}
-static struct configfs_attribute simple_child_attr_storeme = {
- .ca_owner = THIS_MODULE,
- .ca_name = "storeme",
- .ca_mode = S_IRUGO | S_IWUSR,
-};
-
-static struct configfs_attribute *simple_child_attrs[] = {
- &simple_child_attr_storeme,
- NULL,
-};
-
-static ssize_t simple_child_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
+static ssize_t simple_child_storeme_show(struct config_item *item, char *page)
{
- ssize_t count;
- struct simple_child *simple_child = to_simple_child(item);
-
- count = sprintf(page, "%d\n", simple_child->storeme);
-
- return count;
+ return sprintf(page, "%d\n", to_simple_child(item)->storeme);
}
-static ssize_t simple_child_attr_store(struct config_item *item,
- struct configfs_attribute *attr,
- const char *page, size_t count)
+static ssize_t simple_child_storeme_store(struct config_item *item,
+ const char *page, size_t count)
{
struct simple_child *simple_child = to_simple_child(item);
unsigned long tmp;
@@ -211,6 +177,13 @@ static ssize_t simple_child_attr_store(struct config_item *item,
return count;
}
+CONFIGFS_ATTR(simple_child_, storeme);
+
+static struct configfs_attribute *simple_child_attrs[] = {
+ &simple_child_attr_storeme,
+ NULL,
+};
+
static void simple_child_release(struct config_item *item)
{
kfree(to_simple_child(item));
@@ -218,8 +191,6 @@ static void simple_child_release(struct config_item *item)
static struct configfs_item_operations simple_child_item_ops = {
.release = simple_child_release,
- .show_attribute = simple_child_attr_show,
- .store_attribute = simple_child_attr_store,
};
static struct config_item_type simple_child_type = {
@@ -235,10 +206,12 @@ struct simple_children {
static inline struct simple_children *to_simple_children(struct config_item *item)
{
- return item ? container_of(to_config_group(item), struct simple_children, group) : NULL;
+ return item ? container_of(to_config_group(item),
+ struct simple_children, group) : NULL;
}
-static struct config_item *simple_children_make_item(struct config_group *group, const char *name)
+static struct config_item *simple_children_make_item(struct config_group *group,
+ const char *name)
{
struct simple_child *simple_child;
@@ -254,20 +227,8 @@ static struct config_item *simple_children_make_item(struct config_group *group,
return &simple_child->item;
}
-static struct configfs_attribute simple_children_attr_description = {
- .ca_owner = THIS_MODULE,
- .ca_name = "description",
- .ca_mode = S_IRUGO,
-};
-
-static struct configfs_attribute *simple_children_attrs[] = {
- &simple_children_attr_description,
- NULL,
-};
-
-static ssize_t simple_children_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
+static ssize_t simple_children_description_show(struct config_item *item,
+ char *page)
{
return sprintf(page,
"[02-simple-children]\n"
@@ -276,6 +237,13 @@ static ssize_t simple_children_attr_show(struct config_item *item,
"items have only one attribute that is readable and writeable.\n");
}
+CONFIGFS_ATTR_RO(simple_children_, description);
+
+static struct configfs_attribute *simple_children_attrs[] = {
+ &simple_children_attr_description,
+ NULL,
+};
+
static void simple_children_release(struct config_item *item)
{
kfree(to_simple_children(item));
@@ -283,7 +251,6 @@ static void simple_children_release(struct config_item *item)
static struct configfs_item_operations simple_children_item_ops = {
.release = simple_children_release,
- .show_attribute = simple_children_attr_show,
};
/*
@@ -323,7 +290,8 @@ static struct configfs_subsystem simple_children_subsys = {
* children of its own.
*/
-static struct config_group *group_children_make_group(struct config_group *group, const char *name)
+static struct config_group *group_children_make_group(
+ struct config_group *group, const char *name)
{
struct simple_children *simple_children;
@@ -338,20 +306,8 @@ static struct config_group *group_children_make_group(struct config_group *group
return &simple_children->group;
}
-static struct configfs_attribute group_children_attr_description = {
- .ca_owner = THIS_MODULE,
- .ca_name = "description",
- .ca_mode = S_IRUGO,
-};
-
-static struct configfs_attribute *group_children_attrs[] = {
- &group_children_attr_description,
- NULL,
-};
-
-static ssize_t group_children_attr_show(struct config_item *item,
- struct configfs_attribute *attr,
- char *page)
+static ssize_t group_children_description_show(struct config_item *item,
+ char *page)
{
return sprintf(page,
"[03-group-children]\n"
@@ -360,8 +316,11 @@ static ssize_t group_children_attr_show(struct config_item *item,
"groups are like the subsystem simple-children.\n");
}
-static struct configfs_item_operations group_children_item_ops = {
- .show_attribute = group_children_attr_show,
+CONFIGFS_ATTR_RO(group_children_, description);
+
+static struct configfs_attribute *group_children_attrs[] = {
+ &group_children_attr_description,
+ NULL,
};
/*
@@ -373,7 +332,6 @@ static struct configfs_group_operations group_children_group_ops = {
};
static struct config_item_type group_children_type = {
- .ct_item_ops = &group_children_item_ops,
.ct_group_ops = &group_children_group_ops,
.ct_attrs = group_children_attrs,
.ct_owner = THIS_MODULE,
diff --git a/scripts/coccicheck b/scripts/coccicheck
index bbf901a..b2d7581 100755
--- a/scripts/coccicheck
+++ b/scripts/coccicheck
@@ -30,7 +30,7 @@ FLAGS="$SPFLAGS --very-quiet"
# spatch only allows include directories with the syntax "-I include"
# while gcc also allows "-Iinclude" and "-include include"
COCCIINCLUDE=${LINUXINCLUDE//-I/-I }
-COCCIINCLUDE=${COCCIINCLUDE//-include/-I}
+COCCIINCLUDE=${COCCIINCLUDE// -include/ --include}
if [ "$C" = "1" -o "$C" = "2" ]; then
ONLINE=1
diff --git a/scripts/coccinelle/free/ifnullfree.cocci b/scripts/coccinelle/free/ifnullfree.cocci
index a42d70b..52bd235 100644
--- a/scripts/coccinelle/free/ifnullfree.cocci
+++ b/scripts/coccinelle/free/ifnullfree.cocci
@@ -16,19 +16,21 @@ virtual context
@r2 depends on patch@
expression E;
@@
-- if (E)
+- if (E != NULL)
(
-- kfree(E);
-+ kfree(E);
+ kfree(E);
|
-- debugfs_remove(E);
-+ debugfs_remove(E);
+ debugfs_remove(E);
|
-- debugfs_remove_recursive(E);
-+ debugfs_remove_recursive(E);
+ debugfs_remove_recursive(E);
|
-- usb_free_urb(E);
-+ usb_free_urb(E);
+ usb_free_urb(E);
+|
+ kmem_cache_destroy(E);
+|
+ mempool_destroy(E);
+|
+ dma_pool_destroy(E);
)
@r depends on context || report || org @
@@ -36,8 +38,10 @@ expression E;
position p;
@@
-* if (E)
-* \(kfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|usb_free_urb\)(E);
+* if (E != NULL)
+* \(kfree@p\|debugfs_remove@p\|debugfs_remove_recursive@p\|
+* usb_free_urb@p\|kmem_cache_destroy@p\|mempool_destroy@p\|
+* dma_pool_destroy@p\)(E);
@script:python depends on org@
p << r.p;
diff --git a/scripts/coccinelle/iterators/device_node_continue.cocci b/scripts/coccinelle/iterators/device_node_continue.cocci
new file mode 100644
index 0000000..38ab744
--- /dev/null
+++ b/scripts/coccinelle/iterators/device_node_continue.cocci
@@ -0,0 +1,100 @@
+/// Device node iterators put the previous value of the index variable, so an
+/// explicit put causes a double put.
+///
+// Confidence: High
+// Copyright: (C) 2015 Julia Lawall, Inria. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: --no-includes --include-headers
+// Keywords: for_each_child_of_node, etc.
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r exists@
+expression e1,e2;
+local idexpression n;
+iterator name for_each_node_by_name, for_each_node_by_type,
+for_each_compatible_node, for_each_matching_node,
+for_each_matching_node_and_match, for_each_child_of_node,
+for_each_available_child_of_node, for_each_node_with_property;
+iterator i;
+position p1,p2;
+statement S;
+@@
+
+(
+(
+for_each_node_by_name(n,e1) S
+|
+for_each_node_by_type(n,e1) S
+|
+for_each_compatible_node(n,e1,e2) S
+|
+for_each_matching_node(n,e1) S
+|
+for_each_matching_node_and_match(n,e1,e2) S
+|
+for_each_child_of_node(e1,n) S
+|
+for_each_available_child_of_node(e1,n) S
+|
+for_each_node_with_property(n,e1) S
+)
+&
+i@p1(...) {
+ ... when != of_node_get(n)
+ when any
+ of_node_put@p2(n);
+ ... when any
+}
+)
+
+@s exists@
+local idexpression r.n;
+statement S;
+position r.p1,r.p2;
+iterator i;
+@@
+
+ of_node_put@p2(n);
+ ... when any
+ i@p1(..., n, ...)
+ S
+
+@t depends on s && patch && !context && !org && !report@
+local idexpression n;
+position r.p2;
+@@
+
+- of_node_put@p2(n);
+
+// ----------------------------------------------------------------------------
+
+@t_context depends on s && !patch && (context || org || report)@
+local idexpression n;
+position r.p2;
+position j0;
+@@
+
+* of_node_put@j0@p2(n);
+
+// ----------------------------------------------------------------------------
+
+@script:python t_org depends on org@
+j0 << t_context.j0;
+@@
+
+msg = "ERROR: probable double put."
+coccilib.org.print_todo(j0[0], msg)
+
+// ----------------------------------------------------------------------------
+
+@script:python t_report depends on report@
+j0 << t_context.j0;
+@@
+
+msg = "ERROR: probable double put."
+coccilib.report.print_report(j0[0], msg)
+
diff --git a/scripts/coccinelle/misc/compare_const_fl.cocci b/scripts/coccinelle/misc/compare_const_fl.cocci
new file mode 100644
index 0000000..b5d4bab
--- /dev/null
+++ b/scripts/coccinelle/misc/compare_const_fl.cocci
@@ -0,0 +1,171 @@
+/// Move constants to the right of binary operators.
+//# Depends on personal taste in some cases.
+///
+// Confidence: Moderate
+// Copyright: (C) 2015 Copyright: (C) 2015 Julia Lawall, Inria. GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Options: --no-includes --include-headers
+
+virtual patch
+virtual context
+virtual org
+virtual report
+
+@r1 depends on patch && !context && !org && !report
+ disable bitor_comm, neg_if_exp@
+constant c,c1;
+local idexpression i;
+expression e,e1,e2;
+binary operator b = {==,!=,&,|};
+type t;
+@@
+
+(
+c b (c1)
+|
+sizeof(t) b e1
+|
+sizeof e b e1
+|
+i b e1
+|
+c | e1 | e2 | ...
+|
+c | (e ? e1 : e2)
+|
+- c
++ e
+b
+- e
++ c
+)
+
+@r2 depends on patch && !context && !org && !report
+ disable gtr_lss, gtr_lss_eq, not_int2@
+constant c,c1;
+expression e,e1,e2;
+binary operator b;
+binary operator b1 = {<,<=},b2 = {<,<=};
+binary operator b3 = {>,>=},b4 = {>,>=};
+local idexpression i;
+type t;
+@@
+
+(
+c b c1
+|
+sizeof(t) b e1
+|
+sizeof e b e1
+|
+ (e1 b1 e) && (e b2 e2)
+|
+ (e1 b3 e) && (e b4 e2)
+|
+i b e
+|
+- c < e
++ e > c
+|
+- c <= e
++ e >= c
+|
+- c > e
++ e < c
+|
+- c >= e
++ e <= c
+)
+
+// ----------------------------------------------------------------------------
+
+@r1_context depends on !patch && (context || org || report)
+ disable bitor_comm, neg_if_exp exists@
+type t;
+binary operator b = {==,!=,&,|};
+constant c, c1;
+expression e, e1, e2;
+local idexpression i;
+position j0;
+@@
+
+(
+c b (c1)
+|
+sizeof(t) b e1
+|
+sizeof e b e1
+|
+i b e1
+|
+c | e1 | e2 | ...
+|
+c | (e ? e1 : e2)
+|
+* c@j0 b e
+)
+
+@r2_context depends on !patch && (context || org || report)
+ disable gtr_lss, gtr_lss_eq, not_int2 exists@
+type t;
+binary operator b, b1 = {<,<=}, b2 = {<,<=}, b3 = {>,>=}, b4 = {>,>=};
+constant c, c1;
+expression e, e1, e2;
+local idexpression i;
+position j0;
+@@
+
+(
+c b c1
+|
+sizeof(t) b e1
+|
+sizeof e b e1
+|
+ (e1 b1 e) && (e b2 e2)
+|
+ (e1 b3 e) && (e b4 e2)
+|
+i b e
+|
+* c@j0 < e
+|
+* c@j0 <= e
+|
+* c@j0 > e
+|
+* c@j0 >= e
+)
+
+// ----------------------------------------------------------------------------
+
+@script:python r1_org depends on org@
+j0 << r1_context.j0;
+@@
+
+msg = "Move constant to right."
+coccilib.org.print_todo(j0[0], msg)
+
+@script:python r2_org depends on org@
+j0 << r2_context.j0;
+@@
+
+msg = "Move constant to right."
+coccilib.org.print_todo(j0[0], msg)
+
+// ----------------------------------------------------------------------------
+
+@script:python r1_report depends on report@
+j0 << r1_context.j0;
+@@
+
+msg = "Move constant to right."
+coccilib.report.print_report(j0[0], msg)
+
+@script:python r2_report depends on report@
+j0 << r2_context.j0;
+@@
+
+msg = "Move constant to right."
+coccilib.report.print_report(j0[0], msg)
+
diff --git a/scripts/coccinelle/misc/of_table.cocci b/scripts/coccinelle/misc/of_table.cocci
index 3c93404..2294915 100644
--- a/scripts/coccinelle/misc/of_table.cocci
+++ b/scripts/coccinelle/misc/of_table.cocci
@@ -1,6 +1,6 @@
-/// Make sure of_device_id tables are NULL terminated
+/// Make sure (of/i2c/platform)_device_id tables are NULL terminated
//
-// Keywords: of_table
+// Keywords: of_table i2c_table platform_table
// Confidence: Medium
// Options: --include-headers
@@ -13,18 +13,26 @@ virtual report
identifier var, arr;
expression E;
@@
-struct of_device_id arr[] = {
+(
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
...,
{
.var = E,
* }
};
+|
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
+ ...,
+* { ..., E, ... },
+};
+)
@depends on patch@
identifier var, arr;
expression E;
@@
-struct of_device_id arr[] = {
+(
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
...,
{
.var = E,
@@ -32,19 +40,34 @@ struct of_device_id arr[] = {
+ },
+ { }
};
+|
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
+ ...,
+ { ..., E, ... },
++ { },
+};
+)
@r depends on org || report@
position p1;
identifier var, arr;
expression E;
@@
-struct of_device_id arr[] = {
+(
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
...,
{
.var = E,
}
@p1
};
+|
+struct \(of_device_id \| i2c_device_id \| platform_device_id\) arr[] = {
+ ...,
+ { ..., E, ... }
+ @p1
+};
+)
@script:python depends on org@
p1 << r.p1;
diff --git a/scripts/coccinelle/misc/simple_return.cocci b/scripts/coccinelle/misc/simple_return.cocci
deleted file mode 100644
index e8b6313..0000000
--- a/scripts/coccinelle/misc/simple_return.cocci
+++ /dev/null
@@ -1,180 +0,0 @@
-/// Simplify a trivial if-return sequence. Possibly combine with a
-/// preceding function call.
-///
-// Confidence: High
-// Copyright: (C) 2014 Julia Lawall, INRIA/LIP6. GPLv2.
-// Copyright: (C) 2014 Gilles Muller, INRIA/LiP6. GPLv2.
-// URL: http://coccinelle.lip6.fr/
-// Comments:
-// Options: --no-includes --include-headers
-
-virtual patch
-virtual context
-virtual org
-virtual report
-
-@r depends on patch@
-local idexpression e;
-identifier i,f,fn;
-@@
-
-fn(...) { <...
-- e@i =
-+ return
- f(...);
--if (i != 0) return i;
--return 0;
-...> }
-
-@depends on patch@
-identifier r.i;
-type t;
-@@
-
--t i;
- ... when != i
-
-@depends on patch@
-expression e;
-@@
-
--if (e != 0)
- return e;
--return 0;
-
-// -----------------------------------------------------------------------
-
-@s1 depends on context || org || report@
-local idexpression e;
-identifier i,f,fn;
-position p,p1,p2;
-@@
-
-fn(...) { <...
-* e@i@p = f(...);
- if (\(i@p1 != 0\|i@p2 < 0\))
- return i;
- return 0;
-...> }
-
-@s2 depends on context || org || report forall@
-identifier s1.i;
-type t;
-position q,s1.p;
-expression e,f;
-@@
-
-* t i@q;
- ... when != i
- e@p = f(...);
-
-@s3 depends on context || org || report@
-expression e;
-position p1!=s1.p1;
-position p2!=s1.p2;
-@@
-
-*if (\(e@p1 != 0\|e@p2 < 0\))
- return e;
- return 0;
-
-// -----------------------------------------------------------------------
-
-@script:python depends on org@
-p << s1.p;
-p1 << s1.p1;
-q << s2.q;
-@@
-
-cocci.print_main("decl",q)
-cocci.print_secs("use",p)
-cocci.include_match(False)
-
-@script:python depends on org@
-p << s1.p;
-p2 << s1.p2;
-q << s2.q;
-@@
-
-cocci.print_main("decl",q)
-cocci.print_secs("use with questionable test",p)
-cocci.include_match(False)
-
-@script:python depends on org@
-p << s1.p;
-p1 << s1.p1;
-@@
-
-cocci.print_main("use",p)
-
-@script:python depends on org@
-p << s1.p;
-p2 << s1.p2;
-@@
-
-cocci.print_main("use with questionable test",p)
-
-@script:python depends on org@
-p << s3.p1;
-@@
-
-cocci.print_main("test",p)
-
-@script:python depends on org@
-p << s3.p2;
-@@
-
-cocci.print_main("questionable test",p)
-
-// -----------------------------------------------------------------------
-
-@script:python depends on report@
-p << s1.p;
-p1 << s1.p1;
-q << s2.q;
-@@
-
-msg = "WARNING: end returns can be simpified and declaration on line %s can be dropped" % (q[0].line)
-coccilib.report.print_report(p[0],msg)
-cocci.include_match(False)
-
-@script:python depends on report@
-p << s1.p;
-p1 << s1.p1;
-q << s2.q
-;
-@@
-
-msg = "WARNING: end returns may be simpified if negative or 0 value and declaration on line %s can be dropped" % (q[0].line)
-coccilib.report.print_report(p[0],msg)
-cocci.include_match(False)
-
-@script:python depends on report@
-p << s1.p;
-p1 << s1.p1;
-@@
-
-msg = "WARNING: end returns can be simpified"
-coccilib.report.print_report(p[0],msg)
-
-@script:python depends on report@
-p << s1.p;
-p2 << s1.p2;
-@@
-
-msg = "WARNING: end returns can be simpified if negative or 0 value"
-coccilib.report.print_report(p[0],msg)
-
-@script:python depends on report@
-p << s3.p1;
-@@
-
-msg = "WARNING: end returns can be simpified"
-coccilib.report.print_report(p[0],msg)
-
-@script:python depends on report@
-p << s3.p2;
-@@
-
-msg = "WARNING: end returns can be simpified if tested value is negative or 0"
-coccilib.report.print_report(p[0],msg)
diff --git a/scripts/coccinelle/null/deref_null.cocci b/scripts/coccinelle/null/deref_null.cocci
index cdac6cf..f192d60 100644
--- a/scripts/coccinelle/null/deref_null.cocci
+++ b/scripts/coccinelle/null/deref_null.cocci
@@ -1,6 +1,6 @@
///
-/// A variable is dereference under a NULL test.
-/// Even though it is know to be NULL.
+/// A variable is dereferenced under a NULL test.
+/// Even though it is known to be NULL.
///
// Confidence: Moderate
// Copyright: (C) 2010 Nicolas Palix, DIKU. GPLv2.
diff --git a/scripts/coccinelle/tests/odd_ptr_err.cocci b/scripts/coccinelle/tests/odd_ptr_err.cocci
index cfe0a35..dfc6b40 100644
--- a/scripts/coccinelle/tests/odd_ptr_err.cocci
+++ b/scripts/coccinelle/tests/odd_ptr_err.cocci
@@ -1,12 +1,11 @@
/// PTR_ERR should access the value just tested by IS_ERR
-//# There can be false positives in the patch case, where it is the call
+//# There can be false positives in the patch case, where it is the call to
//# IS_ERR that is wrong.
///
// Confidence: High
-// Copyright: (C) 2012 Julia Lawall, INRIA. GPLv2.
-// Copyright: (C) 2012 Gilles Muller, INRIA. GPLv2.
+// Copyright: (C) 2012, 2015 Julia Lawall, INRIA. GPLv2.
+// Copyright: (C) 2012, 2015 Gilles Muller, INRIA. GPLv2.
// URL: http://coccinelle.lip6.fr/
-// Comments:
// Options: --no-includes --include-headers
virtual patch
@@ -14,52 +13,105 @@ virtual context
virtual org
virtual report
-@depends on patch@
-expression e,e1;
+@ok1 exists@
+expression x,e;
+position p;
@@
+if (IS_ERR(x=e) || ...) {
+ <...
+ PTR_ERR@p(x)
+ ...>
+}
+
+@ok2 exists@
+expression x,e1,e2;
+position p;
+@@
+
+if (IS_ERR(x) || ...) {
+ <...
(
-if (IS_ERR(e)) { ... PTR_ERR(e) ... }
+ PTR_ERR@p(\(e1 ? e2 : x\|e1 ? x : e2\))
|
-if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... }
+ PTR_ERR@p(x)
+)
+ ...>
+}
+
+@r1 depends on patch && !context && !org && !report exists@
+expression x,y;
+position p != {ok1.p,ok2.p};
+@@
+
+if (IS_ERR(x) || ...) {
+ ... when any
+ when != IS_ERR(...)
+(
+ PTR_ERR(x)
|
-if (IS_ERR(e))
- { ...
- PTR_ERR(
-- e1
-+ e
+ PTR_ERR@p(
+- y
++ x
)
- ... }
)
+ ... when any
+}
+
+// ----------------------------------------------------------------------------
-@r depends on !patch@
-expression e,e1;
-position p1,p2;
+@r1_context depends on !patch && (context || org || report) exists@
+position p != {ok1.p,ok2.p};
+expression x, y;
+position j0, j1;
@@
+if (IS_ERR@j0(x) || ...) {
+ ... when any
+ when != IS_ERR(...)
(
-if (IS_ERR(e)) { ... PTR_ERR(e) ... }
+ PTR_ERR(x)
|
-if (IS_ERR(e=e1)) { ... PTR_ERR(e) ... }
-|
-*if (IS_ERR@p1(e))
- { ...
-* PTR_ERR@p2(e1)
- ... }
+ PTR_ERR@j1@p(
+ y
+ )
)
+ ... when any
+}
-@script:python depends on org@
-p1 << r.p1;
-p2 << r.p2;
+@r1_disj depends on !patch && (context || org || report) exists@
+position p != {ok1.p,ok2.p};
+expression x, y;
+position r1_context.j0, r1_context.j1;
@@
-cocci.print_main("inconsistent IS_ERR and PTR_ERR",p1)
-cocci.print_secs("PTR_ERR",p2)
+* if (IS_ERR@j0(x) || ...) {
+ ... when any
+ when != IS_ERR(...)
+* PTR_ERR@j1@p(
+ y
+ )
+ ... when any
+}
-@script:python depends on report@
-p1 << r.p1;
-p2 << r.p2;
+// ----------------------------------------------------------------------------
+
+@script:python r1_org depends on org@
+j0 << r1_context.j0;
+j1 << r1_context.j1;
@@
-msg = "inconsistent IS_ERR and PTR_ERR, PTR_ERR on line %s" % (p2[0].line)
-coccilib.report.print_report(p1[0],msg)
+msg = "inconsistent IS_ERR and PTR_ERR"
+coccilib.org.print_todo(j0[0], msg)
+coccilib.org.print_link(j1[0], "")
+
+// ----------------------------------------------------------------------------
+
+@script:python r1_report depends on report@
+j0 << r1_context.j0;
+j1 << r1_context.j1;
+@@
+
+msg = "inconsistent IS_ERR and PTR_ERR on line %s." % (j1[0].line)
+coccilib.report.print_report(j0[0], msg)
+
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 3043d6b..d79cba4 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -229,49 +229,21 @@ $(obj)/.tmp_qtcheck: $(src)/Makefile
# Qt needs some extra effort...
$(obj)/.tmp_qtcheck:
- @set -e; $(kecho) " CHECK qt"; dir=""; pkg=""; \
- if ! pkg-config --exists QtCore 2> /dev/null; then \
- echo "* Unable to find the Qt4 tool qmake. Trying to use Qt3"; \
- pkg-config --exists qt 2> /dev/null && pkg=qt; \
- pkg-config --exists qt-mt 2> /dev/null && pkg=qt-mt; \
- if [ -n "$$pkg" ]; then \
- cflags="\$$(shell pkg-config $$pkg --cflags)"; \
- libs="\$$(shell pkg-config $$pkg --libs)"; \
- moc="\$$(shell pkg-config $$pkg --variable=prefix)/bin/moc"; \
- dir="$$(pkg-config $$pkg --variable=prefix)"; \
- else \
- for d in $$QTDIR /usr/share/qt* /usr/lib/qt*; do \
- if [ -f $$d/include/qconfig.h ]; then dir=$$d; break; fi; \
- done; \
- if [ -z "$$dir" ]; then \
- echo >&2 "*"; \
- echo >&2 "* Unable to find any Qt installation. Please make sure that"; \
- echo >&2 "* the Qt4 or Qt3 development package is correctly installed and"; \
- echo >&2 "* either qmake can be found or install pkg-config or set"; \
- echo >&2 "* the QTDIR environment variable to the correct location."; \
- echo >&2 "*"; \
- false; \
- fi; \
- libpath=$$dir/lib; lib=qt; osdir=""; \
- $(HOSTCXX) -print-multi-os-directory > /dev/null 2>&1 && \
- osdir=x$$($(HOSTCXX) -print-multi-os-directory); \
- test -d $$libpath/$$osdir && libpath=$$libpath/$$osdir; \
- test -f $$libpath/libqt-mt.so && lib=qt-mt; \
- cflags="-I$$dir/include"; \
- libs="-L$$libpath -Wl,-rpath,$$libpath -l$$lib"; \
- moc="$$dir/bin/moc"; \
- fi; \
- if [ ! -x $$dir/bin/moc -a -x /usr/bin/moc ]; then \
- echo "*"; \
- echo "* Unable to find $$dir/bin/moc, using /usr/bin/moc instead."; \
- echo "*"; \
- moc="/usr/bin/moc"; \
- fi; \
+ @set -e; $(kecho) " CHECK qt"; \
+ if pkg-config --exists Qt5Core; then \
+ cflags="-std=c++11 -fPIC `pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets`"; \
+ libs=`pkg-config --libs Qt5Core Qt5Gui Qt5Widgets`; \
+ moc=`pkg-config --variable=host_bins Qt5Core`/moc; \
+ elif pkg-config --exists QtCore; then \
+ cflags=`pkg-config --cflags QtCore QtGui`; \
+ libs=`pkg-config --libs QtCore QtGui`; \
+ moc=`pkg-config --variable=moc_location QtCore`; \
else \
- cflags="\$$(shell pkg-config QtCore QtGui Qt3Support --cflags)"; \
- libs="\$$(shell pkg-config QtCore QtGui Qt3Support --libs)"; \
- moc="\$$(shell pkg-config QtCore --variable=moc_location)"; \
- [ -n "$$moc" ] || moc="\$$(shell pkg-config QtCore --variable=prefix)/bin/moc"; \
+ echo >&2 "*"; \
+ echo >&2 "* Could not find Qt via pkg-config."; \
+ echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"; \
+ echo >&2 "*"; \
+ exit 1; \
fi; \
echo "KC_QT_CFLAGS=$$cflags" > $@; \
echo "KC_QT_LIBS=$$libs" >> $@; \
diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c
index 667d1aa..cbf4996 100644
--- a/scripts/kconfig/expr.c
+++ b/scripts/kconfig/expr.c
@@ -1113,7 +1113,7 @@ void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *
fn(data, e->left.sym, e->left.sym->name);
else
fn(data, NULL, "<choice>");
- fn(data, NULL, e->type == E_LEQ ? ">=" : ">");
+ fn(data, NULL, e->type == E_GEQ ? ">=" : ">");
fn(data, e->right.sym, e->right.sym->name);
break;
case E_UNEQUAL:
diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh
index 0d883b3..67d1314 100755
--- a/scripts/kconfig/merge_config.sh
+++ b/scripts/kconfig/merge_config.sh
@@ -32,7 +32,7 @@ usage() {
echo " -m only merge the fragments, do not execute the make command"
echo " -n use allnoconfig instead of alldefconfig"
echo " -r list redundant entries when merging fragments"
- echo " -O dir to put generated output files"
+ echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead."
}
RUNMAKE=true
@@ -77,11 +77,19 @@ while true; do
esac
done
-if [ "$#" -lt 2 ] ; then
+if [ "$#" -lt 1 ] ; then
usage
exit
fi
+if [ -z "$KCONFIG_CONFIG" ]; then
+ if [ "$OUTPUT" != . ]; then
+ KCONFIG_CONFIG=$(readlink -m -- "$OUTPUT/.config")
+ else
+ KCONFIG_CONFIG=.config
+ fi
+fi
+
INITFILE=$1
shift;
@@ -124,9 +132,9 @@ for MERGE_FILE in $MERGE_LIST ; do
done
if [ "$RUNMAKE" = "false" ]; then
- cp $TMP_FILE $OUTPUT/.config
+ cp -T -- "$TMP_FILE" "$KCONFIG_CONFIG"
echo "#"
- echo "# merged configuration written to $OUTPUT/.config (needs make)"
+ echo "# merged configuration written to $KCONFIG_CONFIG (needs make)"
echo "#"
clean_up
exit
@@ -150,7 +158,7 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET
for CFG in $(sed -n "$SED_CONFIG_EXP" $TMP_FILE); do
REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE)
- ACTUAL_VAL=$(grep -w -e "$CFG" $OUTPUT/.config)
+ ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG")
if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then
echo "Value requested for $CFG not in final .config"
echo "Requested value: $REQUESTED_VAL"
diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
index c3bb7fe..91b7e6f 100644
--- a/scripts/kconfig/qconf.cc
+++ b/scripts/kconfig/qconf.cc
@@ -1,32 +1,17 @@
/*
* Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
+ * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>
* Released under the terms of the GNU GPL v2.0.
*/
#include <qglobal.h>
-#if QT_VERSION < 0x040000
-#include <stddef.h>
-#include <qmainwindow.h>
-#include <qvbox.h>
-#include <qvaluelist.h>
+#include <QMainWindow>
+#include <QList>
#include <qtextbrowser.h>
-#include <qaction.h>
-#include <qheader.h>
-#include <qfiledialog.h>
-#include <qdragobject.h>
-#include <qpopupmenu.h>
-#else
-#include <q3mainwindow.h>
-#include <q3vbox.h>
-#include <q3valuelist.h>
-#include <q3textbrowser.h>
-#include <q3action.h>
-#include <q3header.h>
-#include <q3filedialog.h>
-#include <q3dragobject.h>
-#include <q3popupmenu.h>
-#endif
+#include <QAction>
+#include <QFileDialog>
+#include <QMenu>
#include <qapplication.h>
#include <qdesktopwidget.h>
@@ -57,7 +42,7 @@
static QApplication *configApp;
static ConfigSettings *configSettings;
-Q3Action *ConfigMainWindow::saveAction;
+QAction *ConfigMainWindow::saveAction;
static inline QString qgettext(const char* str)
{
@@ -66,7 +51,7 @@ static inline QString qgettext(const char* str)
static inline QString qgettext(const QString& str)
{
- return QString::fromLocal8Bit(gettext(str.latin1()));
+ return QString::fromLocal8Bit(gettext(str.toLatin1()));
}
ConfigSettings::ConfigSettings()
@@ -77,10 +62,10 @@ ConfigSettings::ConfigSettings()
/**
* Reads a list of integer values from the application settings.
*/
-Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
+QList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
{
- Q3ValueList<int> result;
- QStringList entryList = readListEntry(key, ok);
+ QList<int> result;
+ QStringList entryList = value(key).toStringList();
QStringList::Iterator it;
for (it = entryList.begin(); it != entryList.end(); ++it)
@@ -92,14 +77,16 @@ Q3ValueList<int> ConfigSettings::readSizes(const QString& key, bool *ok)
/**
* Writes a list of integer values to the application settings.
*/
-bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& value)
+bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value)
{
QStringList stringList;
- Q3ValueList<int>::ConstIterator it;
+ QList<int>::ConstIterator it;
for (it = value.begin(); it != value.end(); ++it)
stringList.push_back(QString::number(*it));
- return writeEntry(key, stringList);
+ setValue(key, stringList);
+
+ return true;
}
@@ -109,9 +96,6 @@ bool ConfigSettings::writeSizes(const QString& key, const Q3ValueList<int>& valu
*/
void ConfigItem::okRename(int col)
{
- Parent::okRename(col);
- sym_set_string_value(menu->sym, text(dataColIdx).latin1());
- listView()->updateList(this);
}
/*
@@ -149,11 +133,11 @@ void ConfigItem::updateMenu(void)
} else {
if (sym)
break;
- setPixmap(promptColIdx, 0);
+ setPixmap(promptColIdx, QIcon());
}
goto set_prompt;
case P_COMMENT:
- setPixmap(promptColIdx, 0);
+ setPixmap(promptColIdx, QIcon());
goto set_prompt;
default:
;
@@ -170,7 +154,7 @@ void ConfigItem::updateMenu(void)
char ch;
if (!sym_is_changable(sym) && list->optMode == normalOpt) {
- setPixmap(promptColIdx, 0);
+ setPixmap(promptColIdx, QIcon());
setText(noColIdx, QString::null);
setText(modColIdx, QString::null);
setText(yesColIdx, QString::null);
@@ -216,9 +200,6 @@ void ConfigItem::updateMenu(void)
data = sym_get_string_value(sym);
- int i = list->mapIdx(dataColIdx);
- if (i >= 0)
- setRenameEnabled(i, TRUE);
setText(dataColIdx, data);
if (type == S_STRING)
prompt = QString("%1: %2").arg(prompt).arg(data);
@@ -250,18 +231,6 @@ void ConfigItem::testUpdateMenu(bool v)
updateMenu();
}
-void ConfigItem::paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align)
-{
- ConfigList* list = listView();
-
- if (visible) {
- if (isSelected() && !list->hasFocus() && list->mode == menuMode)
- Parent::paintCell(p, list->inactivedColorGroup, column, width, align);
- else
- Parent::paintCell(p, cg, column, width, align);
- } else
- Parent::paintCell(p, list->disabledColorGroup, column, width, align);
-}
/*
* construct a menu entry
@@ -274,7 +243,7 @@ void ConfigItem::init(void)
menu->data = this;
if (list->mode != fullMode)
- setOpen(TRUE);
+ setExpanded(true);
sym_calc_value(menu->sym);
}
updateMenu();
@@ -299,7 +268,7 @@ ConfigItem::~ConfigItem(void)
ConfigLineEdit::ConfigLineEdit(ConfigView* parent)
: Parent(parent)
{
- connect(this, SIGNAL(lostFocus()), SLOT(hide()));
+ connect(this, SIGNAL(editingFinished()), SLOT(hide()));
}
void ConfigLineEdit::show(ConfigItem* i)
@@ -320,7 +289,7 @@ void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
break;
case Qt::Key_Return:
case Qt::Key_Enter:
- sym_set_string_value(item->menu->sym, text().latin1());
+ sym_set_string_value(item->menu->sym, text().toLatin1());
parent()->updateList(item);
break;
default:
@@ -333,39 +302,39 @@ void ConfigLineEdit::keyPressEvent(QKeyEvent* e)
}
ConfigList::ConfigList(ConfigView* p, const char *name)
- : Parent(p, name),
+ : Parent(p),
updateAll(false),
symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no),
choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no),
menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void),
- showName(false), showRange(false), showData(false), optMode(normalOpt),
+ showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt),
rootEntry(0), headerPopup(0)
{
int i;
- setSorting(-1);
- setRootIsDecorated(TRUE);
- disabledColorGroup = palette().active();
- disabledColorGroup.setColor(QColorGroup::Text, palette().disabled().text());
- inactivedColorGroup = palette().active();
- inactivedColorGroup.setColor(QColorGroup::Highlight, palette().disabled().highlight());
+ setObjectName(name);
+ setSortingEnabled(false);
+ setRootIsDecorated(true);
+
+ setVerticalScrollMode(ScrollPerPixel);
+ setHorizontalScrollMode(ScrollPerPixel);
+
+ setHeaderLabels(QStringList() << _("Option") << _("Name") << "N" << "M" << "Y" << _("Value"));
- connect(this, SIGNAL(selectionChanged(void)),
+ connect(this, SIGNAL(itemSelectionChanged(void)),
SLOT(updateSelection(void)));
if (name) {
configSettings->beginGroup(name);
- showName = configSettings->readBoolEntry("/showName", false);
- showRange = configSettings->readBoolEntry("/showRange", false);
- showData = configSettings->readBoolEntry("/showData", false);
- optMode = (enum optionMode)configSettings->readNumEntry("/optionMode", false);
+ showName = configSettings->value("/showName", false).toBool();
+ showRange = configSettings->value("/showRange", false).toBool();
+ showData = configSettings->value("/showData", false).toBool();
+ optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt();
configSettings->endGroup();
connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
}
- for (i = 0; i < colNr; i++)
- colMap[i] = colRevMap[i] = -1;
- addColumn(promptColIdx, _("Option"));
+ addColumn(promptColIdx);
reinit();
}
@@ -390,26 +359,26 @@ void ConfigList::reinit(void)
removeColumn(nameColIdx);
if (showName)
- addColumn(nameColIdx, _("Name"));
+ addColumn(nameColIdx);
if (showRange) {
- addColumn(noColIdx, "N");
- addColumn(modColIdx, "M");
- addColumn(yesColIdx, "Y");
+ addColumn(noColIdx);
+ addColumn(modColIdx);
+ addColumn(yesColIdx);
}
if (showData)
- addColumn(dataColIdx, _("Value"));
+ addColumn(dataColIdx);
updateListAll();
}
void ConfigList::saveSettings(void)
{
- if (name()) {
- configSettings->beginGroup(name());
- configSettings->writeEntry("/showName", showName);
- configSettings->writeEntry("/showRange", showRange);
- configSettings->writeEntry("/showData", showData);
- configSettings->writeEntry("/optionMode", (int)optMode);
+ if (!objectName().isEmpty()) {
+ configSettings->beginGroup(objectName());
+ configSettings->setValue("/showName", showName);
+ configSettings->setValue("/showRange", showRange);
+ configSettings->setValue("/showData", showData);
+ configSettings->setValue("/optionMode", (int)optMode);
configSettings->endGroup();
}
}
@@ -431,7 +400,10 @@ void ConfigList::updateSelection(void)
struct menu *menu;
enum prop_type type;
- ConfigItem* item = (ConfigItem*)selectedItem();
+ if (selectedItems().count() == 0)
+ return;
+
+ ConfigItem* item = (ConfigItem*)selectedItems().first();
if (!item)
return;
@@ -451,21 +423,23 @@ void ConfigList::updateList(ConfigItem* item)
if (!rootEntry) {
if (mode != listMode)
goto update;
- Q3ListViewItemIterator it(this);
+ QTreeWidgetItemIterator it(this);
ConfigItem* item;
- for (; it.current(); ++it) {
- item = (ConfigItem*)it.current();
+ while (*it) {
+ item = (ConfigItem*)(*it);
if (!item->menu)
continue;
item->testUpdateMenu(menu_is_visible(item->menu));
+
+ ++it;
}
return;
}
if (rootEntry != &rootmenu && (mode == singleMode ||
(mode == symbolMode && rootEntry->parent != &rootmenu))) {
- item = firstChild();
+ item = (ConfigItem *)topLevelItem(0);
if (!item)
item = new ConfigItem(this, 0, true);
last = item;
@@ -479,12 +453,14 @@ void ConfigList::updateList(ConfigItem* item)
item->testUpdateMenu(true);
updateMenuList(item, rootEntry);
- triggerUpdate();
+ update();
+ resizeColumnToContents(0);
return;
}
update:
updateMenuList(this, rootEntry);
- triggerUpdate();
+ update();
+ resizeColumnToContents(0);
}
void ConfigList::setValue(ConfigItem* item, tristate val)
@@ -506,7 +482,7 @@ void ConfigList::setValue(ConfigItem* item, tristate val)
if (!sym_set_tristate_value(sym, val))
return;
if (oldval == no && item->menu->list)
- item->setOpen(TRUE);
+ item->setExpanded(true);
parent()->updateList(item);
break;
}
@@ -524,7 +500,7 @@ void ConfigList::changeValue(ConfigItem* item)
sym = menu->sym;
if (!sym) {
if (item->menu->list)
- item->setOpen(!item->isOpen());
+ item->setExpanded(!item->isExpanded());
return;
}
@@ -536,9 +512,9 @@ void ConfigList::changeValue(ConfigItem* item)
newexpr = sym_toggle_tristate_value(sym);
if (item->menu->list) {
if (oldexpr == newexpr)
- item->setOpen(!item->isOpen());
+ item->setExpanded(!item->isExpanded());
else if (oldexpr == no)
- item->setOpen(TRUE);
+ item->setExpanded(true);
}
if (oldexpr != newexpr)
parent()->updateList(item);
@@ -546,10 +522,7 @@ void ConfigList::changeValue(ConfigItem* item)
case S_INT:
case S_HEX:
case S_STRING:
- if (colMap[dataColIdx] >= 0)
- item->startRename(colMap[dataColIdx]);
- else
- parent()->lineEdit->show(item);
+ parent()->lineEdit->show(item);
break;
}
}
@@ -566,8 +539,10 @@ void ConfigList::setRootMenu(struct menu *menu)
updateMenuList(this, 0);
rootEntry = menu;
updateListAll();
- setSelected(currentItem(), hasFocus());
- ensureItemVisible(currentItem());
+ if (currentItem()) {
+ currentItem()->setSelected(hasFocus());
+ scrollToItem(currentItem());
+ }
}
void ConfigList::setParentMenu(void)
@@ -580,13 +555,16 @@ void ConfigList::setParentMenu(void)
return;
setRootMenu(menu_get_parent_menu(rootEntry->parent));
- Q3ListViewItemIterator it(this);
- for (; (item = (ConfigItem*)it.current()); it++) {
+ QTreeWidgetItemIterator it(this);
+ while (*it) {
+ item = (ConfigItem *)(*it);
if (item->menu == oldroot) {
setCurrentItem(item);
- ensureItemVisible(item);
+ scrollToItem(item);
break;
}
+
+ ++it;
}
}
@@ -597,8 +575,7 @@ void ConfigList::setParentMenu(void)
* parent: either the menu list widget or a menu entry widget
* menu: entry to be updated
*/
-template <class P>
-void ConfigList::updateMenuList(P* parent, struct menu* menu)
+void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu)
{
struct menu* child;
ConfigItem* item;
@@ -607,8 +584,11 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
enum prop_type type;
if (!menu) {
- while ((item = parent->firstChild()))
- delete item;
+ while (parent->childCount() > 0)
+ {
+ delete parent->takeChild(0);
+ }
+
return;
}
@@ -660,9 +640,74 @@ void ConfigList::updateMenuList(P* parent, struct menu* menu)
}
}
+void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu)
+{
+ struct menu* child;
+ ConfigItem* item;
+ ConfigItem* last;
+ bool visible;
+ enum prop_type type;
+
+ if (!menu) {
+ while (parent->topLevelItemCount() > 0)
+ {
+ delete parent->takeTopLevelItem(0);
+ }
+
+ return;
+ }
+
+ last = (ConfigItem*)parent->topLevelItem(0);
+ if (last && !last->goParent)
+ last = 0;
+ for (child = menu->list; child; child = child->next) {
+ item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0);
+ type = child->prompt ? child->prompt->type : P_UNKNOWN;
+
+ switch (mode) {
+ case menuMode:
+ if (!(child->flags & MENU_ROOT))
+ goto hide;
+ break;
+ case symbolMode:
+ if (child->flags & MENU_ROOT)
+ goto hide;
+ break;
+ default:
+ break;
+ }
+
+ visible = menu_is_visible(child);
+ if (!menuSkip(child)) {
+ if (!child->sym && !child->list && !child->prompt)
+ continue;
+ if (!item || item->menu != child)
+ item = new ConfigItem(parent, last, child, visible);
+ else
+ item->testUpdateMenu(visible);
+
+ if (mode == fullMode || mode == menuMode || type != P_MENU)
+ updateMenuList(item, child);
+ else
+ updateMenuList(item, 0);
+ last = item;
+ continue;
+ }
+ hide:
+ if (item && item->menu == child) {
+ last = (ConfigItem*)parent->topLevelItem(0);
+ if (last == item)
+ last = 0;
+ else while (last->nextSibling() != item)
+ last = last->nextSibling();
+ delete item;
+ }
+ }
+}
+
void ConfigList::keyPressEvent(QKeyEvent* ev)
{
- Q3ListViewItem* i = currentItem();
+ QTreeWidgetItem* i = currentItem();
ConfigItem* item;
struct menu *menu;
enum prop_type type;
@@ -714,20 +759,20 @@ void ConfigList::keyPressEvent(QKeyEvent* ev)
ev->accept();
}
-void ConfigList::contentsMousePressEvent(QMouseEvent* e)
+void ConfigList::mousePressEvent(QMouseEvent* e)
{
//QPoint p(contentsToViewport(e->pos()));
//printf("contentsMousePressEvent: %d,%d\n", p.x(), p.y());
- Parent::contentsMousePressEvent(e);
+ Parent::mousePressEvent(e);
}
-void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
+void ConfigList::mouseReleaseEvent(QMouseEvent* e)
{
- QPoint p(contentsToViewport(e->pos()));
+ QPoint p = e->pos();
ConfigItem* item = (ConfigItem*)itemAt(p);
struct menu *menu;
enum prop_type ptype;
- const QPixmap* pm;
+ QIcon icon;
int idx, x;
if (!item)
@@ -735,14 +780,13 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
menu = item->menu;
x = header()->offset() + p.x();
- idx = colRevMap[header()->sectionAt(x)];
+ idx = header()->logicalIndexAt(x);
switch (idx) {
case promptColIdx:
- pm = item->pixmap(promptColIdx);
- if (pm) {
- int off = header()->sectionPos(0) + itemMargin() +
- treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0));
- if (x >= off && x < off + pm->width()) {
+ icon = item->pixmap(promptColIdx);
+ if (!icon.isNull()) {
+ int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly.
+ if (x >= off && x < off + icon.availableSizes().first().width()) {
if (item->goParent) {
emit parentSelected();
break;
@@ -773,19 +817,19 @@ void ConfigList::contentsMouseReleaseEvent(QMouseEvent* e)
skip:
//printf("contentsMouseReleaseEvent: %d,%d\n", p.x(), p.y());
- Parent::contentsMouseReleaseEvent(e);
+ Parent::mouseReleaseEvent(e);
}
-void ConfigList::contentsMouseMoveEvent(QMouseEvent* e)
+void ConfigList::mouseMoveEvent(QMouseEvent* e)
{
//QPoint p(contentsToViewport(e->pos()));
//printf("contentsMouseMoveEvent: %d,%d\n", p.x(), p.y());
- Parent::contentsMouseMoveEvent(e);
+ Parent::mouseMoveEvent(e);
}
-void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
+void ConfigList::mouseDoubleClickEvent(QMouseEvent* e)
{
- QPoint p(contentsToViewport(e->pos()));
+ QPoint p = e->pos(); // TODO: Check if this works(was contentsToViewport).
ConfigItem* item = (ConfigItem*)itemAt(p);
struct menu *menu;
enum prop_type ptype;
@@ -807,7 +851,7 @@ void ConfigList::contentsMouseDoubleClickEvent(QMouseEvent* e)
skip:
//printf("contentsMouseDoubleClickEvent: %d,%d\n", p.x(), p.y());
- Parent::contentsMouseDoubleClickEvent(e);
+ Parent::mouseDoubleClickEvent(e);
}
void ConfigList::focusInEvent(QFocusEvent *e)
@@ -818,7 +862,7 @@ void ConfigList::focusInEvent(QFocusEvent *e)
ConfigItem* item = (ConfigItem *)currentItem();
if (item) {
- setSelected(item, TRUE);
+ item->setSelected(true);
menu = item->menu;
}
emit gotFocus(menu);
@@ -828,33 +872,33 @@ void ConfigList::contextMenuEvent(QContextMenuEvent *e)
{
if (e->y() <= header()->geometry().bottom()) {
if (!headerPopup) {
- Q3Action *action;
+ QAction *action;
- headerPopup = new Q3PopupMenu(this);
- action = new Q3Action(NULL, _("Show Name"), 0, this);
- action->setToggleAction(TRUE);
+ headerPopup = new QMenu(this);
+ action = new QAction(_("Show Name"), this);
+ action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)),
parent(), SLOT(setShowName(bool)));
connect(parent(), SIGNAL(showNameChanged(bool)),
action, SLOT(setOn(bool)));
- action->setOn(showName);
- action->addTo(headerPopup);
- action = new Q3Action(NULL, _("Show Range"), 0, this);
- action->setToggleAction(TRUE);
+ action->setChecked(showName);
+ headerPopup->addAction(action);
+ action = new QAction(_("Show Range"), this);
+ action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)),
parent(), SLOT(setShowRange(bool)));
connect(parent(), SIGNAL(showRangeChanged(bool)),
action, SLOT(setOn(bool)));
- action->setOn(showRange);
- action->addTo(headerPopup);
- action = new Q3Action(NULL, _("Show Data"), 0, this);
- action->setToggleAction(TRUE);
+ action->setChecked(showRange);
+ headerPopup->addAction(action);
+ action = new QAction(_("Show Data"), this);
+ action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)),
parent(), SLOT(setShowData(bool)));
connect(parent(), SIGNAL(showDataChanged(bool)),
action, SLOT(setOn(bool)));
- action->setOn(showData);
- action->addTo(headerPopup);
+ action->setChecked(showData);
+ headerPopup->addAction(action);
}
headerPopup->exec(e->globalPos());
e->accept();
@@ -868,11 +912,17 @@ QAction *ConfigView::showAllAction;
QAction *ConfigView::showPromptAction;
ConfigView::ConfigView(QWidget* parent, const char *name)
- : Parent(parent, name)
+ : Parent(parent)
{
- list = new ConfigList(this, name);
+ setObjectName(name);
+ QVBoxLayout *verticalLayout = new QVBoxLayout(this);
+ verticalLayout->setContentsMargins(0, 0, 0, 0);
+
+ list = new ConfigList(this);
+ verticalLayout->addWidget(list);
lineEdit = new ConfigLineEdit(this);
lineEdit->hide();
+ verticalLayout->addWidget(lineEdit);
this->nextView = viewList;
viewList = this;
@@ -931,10 +981,13 @@ void ConfigView::setShowData(bool b)
void ConfigList::setAllOpen(bool open)
{
- Q3ListViewItemIterator it(this);
+ QTreeWidgetItemIterator it(this);
+
+ while (*it) {
+ (*it)->setExpanded(open);
- for (; it.current(); it++)
- it.current()->setOpen(open);
+ ++it;
+ }
}
void ConfigView::updateList(ConfigItem* item)
@@ -954,11 +1007,14 @@ void ConfigView::updateListAll(void)
}
ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
- : Parent(parent, name), sym(0), _menu(0)
+ : Parent(parent), sym(0), _menu(0)
{
- if (name) {
- configSettings->beginGroup(name);
- _showDebug = configSettings->readBoolEntry("/showDebug", false);
+ setObjectName(name);
+
+
+ if (!objectName().isEmpty()) {
+ configSettings->beginGroup(objectName());
+ _showDebug = configSettings->value("/showDebug", false).toBool();
configSettings->endGroup();
connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings()));
}
@@ -966,9 +1022,9 @@ ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name)
void ConfigInfoView::saveSettings(void)
{
- if (name()) {
- configSettings->beginGroup(name());
- configSettings->writeEntry("/showDebug", showDebug());
+ if (!objectName().isEmpty()) {
+ configSettings->beginGroup(objectName());
+ configSettings->setValue("/showDebug", showDebug());
configSettings->endGroup();
}
}
@@ -1127,8 +1183,8 @@ QString ConfigInfoView::print_filter(const QString &str)
{
QRegExp re("[<>&\"\\n]");
QString res = str;
- for (int i = 0; (i = res.find(re, i)) >= 0;) {
- switch (res[i].latin1()) {
+ for (int i = 0; (i = res.indexOf(re, i)) >= 0;) {
+ switch (res[i].toLatin1()) {
case '<':
res.replace(i, 1, "&lt;");
i += 4;
@@ -1167,37 +1223,42 @@ void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char
*text += str2;
}
-Q3PopupMenu* ConfigInfoView::createPopupMenu(const QPoint& pos)
+QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos)
{
- Q3PopupMenu* popup = Parent::createPopupMenu(pos);
- Q3Action* action = new Q3Action(NULL, _("Show Debug Info"), 0, popup);
- action->setToggleAction(TRUE);
+ QMenu* popup = Parent::createStandardContextMenu(pos);
+ QAction* action = new QAction(_("Show Debug Info"), popup);
+ action->setCheckable(true);
connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool)));
connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool)));
- action->setOn(showDebug());
- popup->insertSeparator();
- action->addTo(popup);
+ action->setChecked(showDebug());
+ popup->addSeparator();
+ popup->addAction(action);
return popup;
}
-void ConfigInfoView::contentsContextMenuEvent(QContextMenuEvent *e)
+void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e)
{
- Parent::contentsContextMenuEvent(e);
+ Parent::contextMenuEvent(e);
}
ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name)
- : Parent(parent, name), result(NULL)
+ : Parent(parent), result(NULL)
{
- setCaption("Search Config");
+ setObjectName(name);
+ setWindowTitle("Search Config");
- QVBoxLayout* layout1 = new QVBoxLayout(this, 11, 6);
- QHBoxLayout* layout2 = new QHBoxLayout(0, 0, 6);
+ QVBoxLayout* layout1 = new QVBoxLayout(this);
+ layout1->setContentsMargins(11, 11, 11, 11);
+ layout1->setSpacing(6);
+ QHBoxLayout* layout2 = new QHBoxLayout(0);
+ layout2->setContentsMargins(0, 0, 0, 0);
+ layout2->setSpacing(6);
layout2->addWidget(new QLabel(_("Find:"), this));
editField = new QLineEdit(this);
connect(editField, SIGNAL(returnPressed()), SLOT(search()));
layout2->addWidget(editField);
searchButton = new QPushButton(_("Search"), this);
- searchButton->setAutoDefault(FALSE);
+ searchButton->setAutoDefault(false);
connect(searchButton, SIGNAL(clicked()), SLOT(search()));
layout2->addWidget(searchButton);
layout1->addLayout(layout2);
@@ -1215,19 +1276,19 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam
layout1->addWidget(split);
if (name) {
- int x, y, width, height;
+ QVariant x, y;
+ int width, height;
bool ok;
configSettings->beginGroup(name);
- width = configSettings->readNumEntry("/window width", parent->width() / 2);
- height = configSettings->readNumEntry("/window height", parent->height() / 2);
+ width = configSettings->value("/window width", parent->width() / 2).toInt();
+ height = configSettings->value("/window height", parent->height() / 2).toInt();
resize(width, height);
- x = configSettings->readNumEntry("/window x", 0, &ok);
- if (ok)
- y = configSettings->readNumEntry("/window y", 0, &ok);
- if (ok)
- move(x, y);
- Q3ValueList<int> sizes = configSettings->readSizes("/split", &ok);
+ x = configSettings->value("/window x");
+ y = configSettings->value("/window y");
+ if ((x.isValid())&&(y.isValid()))
+ move(x.toInt(), y.toInt());
+ QList<int> sizes = configSettings->readSizes("/split", &ok);
if (ok)
split->setSizes(sizes);
configSettings->endGroup();
@@ -1237,12 +1298,12 @@ ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *nam
void ConfigSearchWindow::saveSettings(void)
{
- if (name()) {
- configSettings->beginGroup(name());
- configSettings->writeEntry("/window x", pos().x());
- configSettings->writeEntry("/window y", pos().y());
- configSettings->writeEntry("/window width", size().width());
- configSettings->writeEntry("/window height", size().height());
+ if (!objectName().isEmpty()) {
+ configSettings->beginGroup(objectName());
+ configSettings->setValue("/window x", pos().x());
+ configSettings->setValue("/window y", pos().y());
+ configSettings->setValue("/window width", size().width());
+ configSettings->setValue("/window height", size().height());
configSettings->writeSizes("/split", split->sizes());
configSettings->endGroup();
}
@@ -1258,7 +1319,7 @@ void ConfigSearchWindow::search(void)
list->list->clear();
info->clear();
- result = sym_re_search(editField->text().latin1());
+ result = sym_re_search(editField->text().toLatin1());
if (!result)
return;
for (p = result; *p; p++) {
@@ -1275,29 +1336,25 @@ ConfigMainWindow::ConfigMainWindow(void)
: searchWindow(0)
{
QMenuBar* menu;
- bool ok;
- int x, y, width, height;
+ bool ok = true;
+ QVariant x, y;
+ int width, height;
char title[256];
QDesktopWidget *d = configApp->desktop();
snprintf(title, sizeof(title), "%s%s",
rootmenu.prompt->text,
-#if QT_VERSION < 0x040000
- " (Qt3)"
-#else
""
-#endif
);
- setCaption(title);
+ setWindowTitle(title);
- width = configSettings->readNumEntry("/window width", d->width() - 64);
- height = configSettings->readNumEntry("/window height", d->height() - 64);
+ width = configSettings->value("/window width", d->width() - 64).toInt();
+ height = configSettings->value("/window height", d->height() - 64).toInt();
resize(width, height);
- x = configSettings->readNumEntry("/window x", 0, &ok);
- if (ok)
- y = configSettings->readNumEntry("/window y", 0, &ok);
- if (ok)
- move(x, y);
+ x = configSettings->value("/window x");
+ y = configSettings->value("/window y");
+ if ((x.isValid())&&(y.isValid()))
+ move(x.toInt(), y.toInt());
split1 = new QSplitter(this);
split1->setOrientation(Qt::Horizontal);
@@ -1314,127 +1371,115 @@ ConfigMainWindow::ConfigMainWindow(void)
configList = configView->list;
helpText = new ConfigInfoView(split2, "help");
- helpText->setTextFormat(Qt::RichText);
setTabOrder(configList, helpText);
configList->setFocus();
menu = menuBar();
- toolBar = new Q3ToolBar("Tools", this);
-
- backAction = new Q3Action("Back", QPixmap(xpm_back), _("Back"), 0, this);
- connect(backAction, SIGNAL(activated()), SLOT(goBack()));
- backAction->setEnabled(FALSE);
- Q3Action *quitAction = new Q3Action("Quit", _("&Quit"), Qt::CTRL + Qt::Key_Q, this);
- connect(quitAction, SIGNAL(activated()), SLOT(close()));
- Q3Action *loadAction = new Q3Action("Load", QPixmap(xpm_load), _("&Load"), Qt::CTRL + Qt::Key_L, this);
- connect(loadAction, SIGNAL(activated()), SLOT(loadConfig()));
- saveAction = new Q3Action("Save", QPixmap(xpm_save), _("&Save"), Qt::CTRL + Qt::Key_S, this);
- connect(saveAction, SIGNAL(activated()), SLOT(saveConfig()));
+ toolBar = new QToolBar("Tools", this);
+ addToolBar(toolBar);
+
+ backAction = new QAction(QPixmap(xpm_back), _("Back"), this);
+ connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack()));
+ backAction->setEnabled(false);
+ QAction *quitAction = new QAction(_("&Quit"), this);
+ quitAction->setShortcut(Qt::CTRL + Qt::Key_Q);
+ connect(quitAction, SIGNAL(triggered(bool)), SLOT(close()));
+ QAction *loadAction = new QAction(QPixmap(xpm_load), _("&Load"), this);
+ loadAction->setShortcut(Qt::CTRL + Qt::Key_L);
+ connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig()));
+ saveAction = new QAction(QPixmap(xpm_save), _("&Save"), this);
+ saveAction->setShortcut(Qt::CTRL + Qt::Key_S);
+ connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig()));
conf_set_changed_callback(conf_changed);
// Set saveAction's initial state
conf_changed();
- Q3Action *saveAsAction = new Q3Action("Save As...", _("Save &As..."), 0, this);
- connect(saveAsAction, SIGNAL(activated()), SLOT(saveConfigAs()));
- Q3Action *searchAction = new Q3Action("Find", _("&Find"), Qt::CTRL + Qt::Key_F, this);
- connect(searchAction, SIGNAL(activated()), SLOT(searchConfig()));
- Q3Action *singleViewAction = new Q3Action("Single View", QPixmap(xpm_single_view), _("Single View"), 0, this);
- connect(singleViewAction, SIGNAL(activated()), SLOT(showSingleView()));
- Q3Action *splitViewAction = new Q3Action("Split View", QPixmap(xpm_split_view), _("Split View"), 0, this);
- connect(splitViewAction, SIGNAL(activated()), SLOT(showSplitView()));
- Q3Action *fullViewAction = new Q3Action("Full View", QPixmap(xpm_tree_view), _("Full View"), 0, this);
- connect(fullViewAction, SIGNAL(activated()), SLOT(showFullView()));
-
- Q3Action *showNameAction = new Q3Action(NULL, _("Show Name"), 0, this);
- showNameAction->setToggleAction(TRUE);
+ QAction *saveAsAction = new QAction(_("Save &As..."), this);
+ connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs()));
+ QAction *searchAction = new QAction(_("&Find"), this);
+ searchAction->setShortcut(Qt::CTRL + Qt::Key_F);
+ connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig()));
+ singleViewAction = new QAction(QPixmap(xpm_single_view), _("Single View"), this);
+ singleViewAction->setCheckable(true);
+ connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView()));
+ splitViewAction = new QAction(QPixmap(xpm_split_view), _("Split View"), this);
+ splitViewAction->setCheckable(true);
+ connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView()));
+ fullViewAction = new QAction(QPixmap(xpm_tree_view), _("Full View"), this);
+ fullViewAction->setCheckable(true);
+ connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView()));
+
+ QAction *showNameAction = new QAction(_("Show Name"), this);
+ showNameAction->setCheckable(true);
connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool)));
- connect(configView, SIGNAL(showNameChanged(bool)), showNameAction, SLOT(setOn(bool)));
- showNameAction->setOn(configView->showName());
- Q3Action *showRangeAction = new Q3Action(NULL, _("Show Range"), 0, this);
- showRangeAction->setToggleAction(TRUE);
+ showNameAction->setChecked(configView->showName());
+ QAction *showRangeAction = new QAction(_("Show Range"), this);
+ showRangeAction->setCheckable(true);
connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool)));
- connect(configView, SIGNAL(showRangeChanged(bool)), showRangeAction, SLOT(setOn(bool)));
- showRangeAction->setOn(configList->showRange);
- Q3Action *showDataAction = new Q3Action(NULL, _("Show Data"), 0, this);
- showDataAction->setToggleAction(TRUE);
+ QAction *showDataAction = new QAction(_("Show Data"), this);
+ showDataAction->setCheckable(true);
connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool)));
- connect(configView, SIGNAL(showDataChanged(bool)), showDataAction, SLOT(setOn(bool)));
- showDataAction->setOn(configList->showData);
QActionGroup *optGroup = new QActionGroup(this);
- optGroup->setExclusive(TRUE);
- connect(optGroup, SIGNAL(selected(QAction *)), configView,
+ optGroup->setExclusive(true);
+ connect(optGroup, SIGNAL(triggered(QAction*)), configView,
SLOT(setOptionMode(QAction *)));
- connect(optGroup, SIGNAL(selected(QAction *)), menuView,
+ connect(optGroup, SIGNAL(triggered(QAction *)), menuView,
SLOT(setOptionMode(QAction *)));
-#if QT_VERSION >= 0x040000
configView->showNormalAction = new QAction(_("Show Normal Options"), optGroup);
configView->showAllAction = new QAction(_("Show All Options"), optGroup);
configView->showPromptAction = new QAction(_("Show Prompt Options"), optGroup);
-#else
- configView->showNormalAction = new QAction(_("Show Normal Options"), 0, optGroup);
- configView->showAllAction = new QAction(_("Show All Options"), 0, optGroup);
- configView->showPromptAction = new QAction(_("Show Prompt Options"), 0, optGroup);
-#endif
- configView->showNormalAction->setToggleAction(TRUE);
- configView->showNormalAction->setOn(configList->optMode == normalOpt);
- configView->showAllAction->setToggleAction(TRUE);
- configView->showAllAction->setOn(configList->optMode == allOpt);
- configView->showPromptAction->setToggleAction(TRUE);
- configView->showPromptAction->setOn(configList->optMode == promptOpt);
-
- Q3Action *showDebugAction = new Q3Action(NULL, _("Show Debug Info"), 0, this);
- showDebugAction->setToggleAction(TRUE);
+ configView->showNormalAction->setCheckable(true);
+ configView->showAllAction->setCheckable(true);
+ configView->showPromptAction->setCheckable(true);
+
+ QAction *showDebugAction = new QAction( _("Show Debug Info"), this);
+ showDebugAction->setCheckable(true);
connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool)));
- connect(helpText, SIGNAL(showDebugChanged(bool)), showDebugAction, SLOT(setOn(bool)));
- showDebugAction->setOn(helpText->showDebug());
+ showDebugAction->setChecked(helpText->showDebug());
- Q3Action *showIntroAction = new Q3Action(NULL, _("Introduction"), 0, this);
- connect(showIntroAction, SIGNAL(activated()), SLOT(showIntro()));
- Q3Action *showAboutAction = new Q3Action(NULL, _("About"), 0, this);
- connect(showAboutAction, SIGNAL(activated()), SLOT(showAbout()));
+ QAction *showIntroAction = new QAction( _("Introduction"), this);
+ connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro()));
+ QAction *showAboutAction = new QAction( _("About"), this);
+ connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout()));
// init tool bar
- backAction->addTo(toolBar);
+ toolBar->addAction(backAction);
toolBar->addSeparator();
- loadAction->addTo(toolBar);
- saveAction->addTo(toolBar);
+ toolBar->addAction(loadAction);
+ toolBar->addAction(saveAction);
toolBar->addSeparator();
- singleViewAction->addTo(toolBar);
- splitViewAction->addTo(toolBar);
- fullViewAction->addTo(toolBar);
+ toolBar->addAction(singleViewAction);
+ toolBar->addAction(splitViewAction);
+ toolBar->addAction(fullViewAction);
// create config menu
- Q3PopupMenu* config = new Q3PopupMenu(this);
- menu->insertItem(_("&File"), config);
- loadAction->addTo(config);
- saveAction->addTo(config);
- saveAsAction->addTo(config);
- config->insertSeparator();
- quitAction->addTo(config);
+ QMenu* config = menu->addMenu(_("&File"));
+ config->addAction(loadAction);
+ config->addAction(saveAction);
+ config->addAction(saveAsAction);
+ config->addSeparator();
+ config->addAction(quitAction);
// create edit menu
- Q3PopupMenu* editMenu = new Q3PopupMenu(this);
- menu->insertItem(_("&Edit"), editMenu);
- searchAction->addTo(editMenu);
+ QMenu* editMenu = menu->addMenu(_("&Edit"));
+ editMenu->addAction(searchAction);
// create options menu
- Q3PopupMenu* optionMenu = new Q3PopupMenu(this);
- menu->insertItem(_("&Option"), optionMenu);
- showNameAction->addTo(optionMenu);
- showRangeAction->addTo(optionMenu);
- showDataAction->addTo(optionMenu);
- optionMenu->insertSeparator();
- optGroup->addTo(optionMenu);
- optionMenu->insertSeparator();
+ QMenu* optionMenu = menu->addMenu(_("&Option"));
+ optionMenu->addAction(showNameAction);
+ optionMenu->addAction(showRangeAction);
+ optionMenu->addAction(showDataAction);
+ optionMenu->addSeparator();
+ optionMenu->addActions(optGroup->actions());
+ optionMenu->addSeparator();
// create help menu
- Q3PopupMenu* helpMenu = new Q3PopupMenu(this);
- menu->insertSeparator();
- menu->insertItem(_("&Help"), helpMenu);
- showIntroAction->addTo(helpMenu);
- showAboutAction->addTo(helpMenu);
+ menu->addSeparator();
+ QMenu* helpMenu = menu->addMenu(_("&Help"));
+ helpMenu->addAction(showIntroAction);
+ helpMenu->addAction(showAboutAction);
connect(configList, SIGNAL(menuChanged(struct menu *)),
helpText, SLOT(setInfo(struct menu *)));
@@ -1456,7 +1501,7 @@ ConfigMainWindow::ConfigMainWindow(void)
connect(helpText, SIGNAL(menuSelected(struct menu *)),
SLOT(setMenuLink(struct menu *)));
- QString listMode = configSettings->readEntry("/listMode", "symbol");
+ QString listMode = configSettings->value("/listMode", "symbol").toString();
if (listMode == "single")
showSingleView();
else if (listMode == "full")
@@ -1465,7 +1510,7 @@ ConfigMainWindow::ConfigMainWindow(void)
showSplitView();
// UI setup done, restore splitter positions
- Q3ValueList<int> sizes = configSettings->readSizes("/split1", &ok);
+ QList<int> sizes = configSettings->readSizes("/split1", &ok);
if (ok)
split1->setSizes(sizes);
@@ -1476,7 +1521,7 @@ ConfigMainWindow::ConfigMainWindow(void)
void ConfigMainWindow::loadConfig(void)
{
- QString s = Q3FileDialog::getOpenFileName(conf_get_configname(), NULL, this);
+ QString s = QFileDialog::getOpenFileName(this, "", conf_get_configname());
if (s.isNull())
return;
if (conf_read(QFile::encodeName(s)))
@@ -1495,7 +1540,7 @@ bool ConfigMainWindow::saveConfig(void)
void ConfigMainWindow::saveConfigAs(void)
{
- QString s = Q3FileDialog::getSaveFileName(conf_get_configname(), NULL, this);
+ QString s = QFileDialog::getSaveFileName(this, "", conf_get_configname());
if (s.isNull())
return;
saveConfig();
@@ -1512,9 +1557,9 @@ void ConfigMainWindow::changeMenu(struct menu *menu)
{
configList->setRootMenu(menu);
if (configList->rootEntry->parent == &rootmenu)
- backAction->setEnabled(FALSE);
+ backAction->setEnabled(false);
else
- backAction->setEnabled(TRUE);
+ backAction->setEnabled(true);
}
void ConfigMainWindow::setMenuLink(struct menu *menu)
@@ -1546,8 +1591,8 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
return;
item = menuList->findConfigItem(parent);
if (item) {
- menuList->setSelected(item, TRUE);
- menuList->ensureItemVisible(item);
+ item->setSelected(true);
+ menuList->scrollToItem(item);
}
list->setRootMenu(parent);
}
@@ -1562,8 +1607,8 @@ void ConfigMainWindow::setMenuLink(struct menu *menu)
if (list) {
item = list->findConfigItem(menu);
if (item) {
- list->setSelected(item, TRUE);
- list->ensureItemVisible(item);
+ item->setSelected(true);
+ list->scrollToItem(item);
list->setFocus();
}
}
@@ -1577,15 +1622,21 @@ void ConfigMainWindow::listFocusChanged(void)
void ConfigMainWindow::goBack(void)
{
- ConfigItem* item;
+ ConfigItem* item, *oldSelection;
configList->setParentMenu();
if (configList->rootEntry == &rootmenu)
- backAction->setEnabled(FALSE);
- item = (ConfigItem*)menuList->selectedItem();
+ backAction->setEnabled(false);
+
+ if (menuList->selectedItems().count() == 0)
+ return;
+
+ item = (ConfigItem*)menuList->selectedItems().first();
+ oldSelection = item;
while (item) {
if (item->menu == configList->rootEntry) {
- menuList->setSelected(item, TRUE);
+ oldSelection->setSelected(false);
+ item->setSelected(true);
break;
}
item = (ConfigItem*)item->parent();
@@ -1594,6 +1645,13 @@ void ConfigMainWindow::goBack(void)
void ConfigMainWindow::showSingleView(void)
{
+ singleViewAction->setEnabled(false);
+ singleViewAction->setChecked(true);
+ splitViewAction->setEnabled(true);
+ splitViewAction->setChecked(false);
+ fullViewAction->setEnabled(true);
+ fullViewAction->setChecked(false);
+
menuView->hide();
menuList->setRootMenu(0);
configList->mode = singleMode;
@@ -1601,28 +1659,41 @@ void ConfigMainWindow::showSingleView(void)
configList->updateListAll();
else
configList->setRootMenu(&rootmenu);
- configList->setAllOpen(TRUE);
configList->setFocus();
}
void ConfigMainWindow::showSplitView(void)
{
+ singleViewAction->setEnabled(true);
+ singleViewAction->setChecked(false);
+ splitViewAction->setEnabled(false);
+ splitViewAction->setChecked(true);
+ fullViewAction->setEnabled(true);
+ fullViewAction->setChecked(false);
+
configList->mode = symbolMode;
if (configList->rootEntry == &rootmenu)
configList->updateListAll();
else
configList->setRootMenu(&rootmenu);
- configList->setAllOpen(TRUE);
+ configList->setAllOpen(true);
configApp->processEvents();
menuList->mode = menuMode;
menuList->setRootMenu(&rootmenu);
- menuList->setAllOpen(TRUE);
+ menuList->setAllOpen(true);
menuView->show();
menuList->setFocus();
}
void ConfigMainWindow::showFullView(void)
{
+ singleViewAction->setEnabled(true);
+ singleViewAction->setChecked(false);
+ splitViewAction->setEnabled(true);
+ splitViewAction->setChecked(false);
+ fullViewAction->setEnabled(false);
+ fullViewAction->setChecked(true);
+
menuView->hide();
menuList->setRootMenu(0);
configList->mode = fullMode;
@@ -1630,7 +1701,6 @@ void ConfigMainWindow::showFullView(void)
configList->updateListAll();
else
configList->setRootMenu(&rootmenu);
- configList->setAllOpen(FALSE);
configList->setFocus();
}
@@ -1684,7 +1754,8 @@ void ConfigMainWindow::showIntro(void)
void ConfigMainWindow::showAbout(void)
{
- static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n\n"
+ static const QString str = _("qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n"
+ "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n"
"Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n");
QMessageBox::information(this, "qconf", str);
@@ -1692,10 +1763,10 @@ void ConfigMainWindow::showAbout(void)
void ConfigMainWindow::saveSettings(void)
{
- configSettings->writeEntry("/window x", pos().x());
- configSettings->writeEntry("/window y", pos().y());
- configSettings->writeEntry("/window width", size().width());
- configSettings->writeEntry("/window height", size().height());
+ configSettings->setValue("/window x", pos().x());
+ configSettings->setValue("/window y", pos().y());
+ configSettings->setValue("/window width", size().width());
+ configSettings->setValue("/window height", size().height());
QString entry;
switch(configList->mode) {
@@ -1714,7 +1785,7 @@ void ConfigMainWindow::saveSettings(void)
default:
break;
}
- configSettings->writeEntry("/listMode", entry);
+ configSettings->setValue("/listMode", entry);
configSettings->writeSizes("/split1", split1->sizes());
configSettings->writeSizes("/split2", split2->sizes());
@@ -1746,7 +1817,7 @@ static const char *progname;
static void usage(void)
{
- printf(_("%s [-s] <config>\n"), progname);
+ printf(_("%s [-s] <config>\n").toLatin1().constData(), progname);
exit(0);
}
@@ -1785,7 +1856,6 @@ int main(int ac, char** av)
v = new ConfigMainWindow();
//zconfdump(stdout);
- configApp->setMainWidget(v);
configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
configApp->connect(configApp, SIGNAL(aboutToQuit()), v, SLOT(saveSettings()));
v->show();
diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h
index bde0c6b..a40036d 100644
--- a/scripts/kconfig/qconf.h
+++ b/scripts/kconfig/qconf.h
@@ -3,26 +3,18 @@
* Released under the terms of the GNU GPL v2.0.
*/
-#if QT_VERSION < 0x040000
-#include <qlistview.h>
-#else
-#include <q3listview.h>
-#endif
+#include <QTextBrowser>
+#include <QTreeWidget>
+#include <QMainWindow>
+#include <QHeaderView>
#include <qsettings.h>
-
-#if QT_VERSION < 0x040000
-#define Q3ValueList QValueList
-#define Q3PopupMenu QPopupMenu
-#define Q3ListView QListView
-#define Q3ListViewItem QListViewItem
-#define Q3VBox QVBox
-#define Q3TextBrowser QTextBrowser
-#define Q3MainWindow QMainWindow
-#define Q3Action QAction
-#define Q3ToolBar QToolBar
-#define Q3ListViewItemIterator QListViewItemIterator
-#define Q3FileDialog QFileDialog
-#endif
+#include <QPushButton>
+#include <QSettings>
+#include <QLineEdit>
+#include <QSplitter>
+#include <QCheckBox>
+#include <QDialog>
+#include "expr.h"
class ConfigView;
class ConfigList;
@@ -33,8 +25,8 @@ class ConfigMainWindow;
class ConfigSettings : public QSettings {
public:
ConfigSettings();
- Q3ValueList<int> readSizes(const QString& key, bool *ok);
- bool writeSizes(const QString& key, const Q3ValueList<int>& value);
+ QList<int> readSizes(const QString& key, bool *ok);
+ bool writeSizes(const QString& key, const QList<int>& value);
};
enum colIdx {
@@ -47,9 +39,9 @@ enum optionMode {
normalOpt = 0, allOpt, promptOpt
};
-class ConfigList : public Q3ListView {
+class ConfigList : public QTreeWidget {
Q_OBJECT
- typedef class Q3ListView Parent;
+ typedef class QTreeWidget Parent;
public:
ConfigList(ConfigView* p, const char *name = 0);
void reinit(void);
@@ -61,10 +53,10 @@ public:
protected:
void keyPressEvent(QKeyEvent *e);
- void contentsMousePressEvent(QMouseEvent *e);
- void contentsMouseReleaseEvent(QMouseEvent *e);
- void contentsMouseMoveEvent(QMouseEvent *e);
- void contentsMouseDoubleClickEvent(QMouseEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void mouseDoubleClickEvent(QMouseEvent *e);
void focusInEvent(QFocusEvent *e);
void contextMenuEvent(QContextMenuEvent *e);
@@ -95,32 +87,23 @@ public:
}
ConfigItem* firstChild() const
{
- return (ConfigItem *)Parent::firstChild();
- }
- int mapIdx(colIdx idx)
- {
- return colMap[idx];
+ return (ConfigItem *)children().first();
}
- void addColumn(colIdx idx, const QString& label)
+ void addColumn(colIdx idx)
{
- colMap[idx] = Parent::addColumn(label);
- colRevMap[colMap[idx]] = idx;
+ showColumn(idx);
}
void removeColumn(colIdx idx)
{
- int col = colMap[idx];
- if (col >= 0) {
- Parent::removeColumn(col);
- colRevMap[col] = colMap[idx] = -1;
- }
+ hideColumn(idx);
}
void setAllOpen(bool open);
void setParentMenu(void);
bool menuSkip(struct menu *);
- template <class P>
- void updateMenuList(P*, struct menu*);
+ void updateMenuList(ConfigItem *parent, struct menu*);
+ void updateMenuList(ConfigList *parent, struct menu*);
bool updateAll;
@@ -132,30 +115,26 @@ public:
enum listMode mode;
enum optionMode optMode;
struct menu *rootEntry;
- QColorGroup disabledColorGroup;
- QColorGroup inactivedColorGroup;
- Q3PopupMenu* headerPopup;
-
-private:
- int colMap[colNr];
- int colRevMap[colNr];
+ QPalette disabledColorGroup;
+ QPalette inactivedColorGroup;
+ QMenu* headerPopup;
};
-class ConfigItem : public Q3ListViewItem {
- typedef class Q3ListViewItem Parent;
+class ConfigItem : public QTreeWidgetItem {
+ typedef class QTreeWidgetItem Parent;
public:
- ConfigItem(Q3ListView *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), menu(m), visible(v), goParent(false)
+ ConfigItem(ConfigList *parent, ConfigItem *after, struct menu *m, bool v)
+ : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
{
init();
}
ConfigItem(ConfigItem *parent, ConfigItem *after, struct menu *m, bool v)
- : Parent(parent, after), menu(m), visible(v), goParent(false)
+ : Parent(parent, after), nextItem(0), menu(m), visible(v), goParent(false)
{
init();
}
- ConfigItem(Q3ListView *parent, ConfigItem *after, bool v)
- : Parent(parent, after), menu(0), visible(v), goParent(true)
+ ConfigItem(ConfigList *parent, ConfigItem *after, bool v)
+ : Parent(parent, after), nextItem(0), menu(0), visible(v), goParent(true)
{
init();
}
@@ -166,33 +145,43 @@ public:
void testUpdateMenu(bool v);
ConfigList* listView() const
{
- return (ConfigList*)Parent::listView();
+ return (ConfigList*)Parent::treeWidget();
}
ConfigItem* firstChild() const
{
- return (ConfigItem *)Parent::firstChild();
+ return (ConfigItem *)Parent::child(0);
}
- ConfigItem* nextSibling() const
+ ConfigItem* nextSibling()
{
- return (ConfigItem *)Parent::nextSibling();
+ ConfigItem *ret = NULL;
+ ConfigItem *_parent = (ConfigItem *)parent();
+
+ if(_parent) {
+ ret = (ConfigItem *)_parent->child(_parent->indexOfChild(this)+1);
+ } else {
+ QTreeWidget *_treeWidget = treeWidget();
+ ret = (ConfigItem *)_treeWidget->topLevelItem(_treeWidget->indexOfTopLevelItem(this)+1);
+ }
+
+ return ret;
}
void setText(colIdx idx, const QString& text)
{
- Parent::setText(listView()->mapIdx(idx), text);
+ Parent::setText(idx, text);
}
QString text(colIdx idx) const
{
- return Parent::text(listView()->mapIdx(idx));
+ return Parent::text(idx);
}
- void setPixmap(colIdx idx, const QPixmap& pm)
+ void setPixmap(colIdx idx, const QIcon &icon)
{
- Parent::setPixmap(listView()->mapIdx(idx), pm);
+ Parent::setIcon(idx, icon);
}
- const QPixmap* pixmap(colIdx idx) const
+ const QIcon pixmap(colIdx idx) const
{
- return Parent::pixmap(listView()->mapIdx(idx));
+ return icon(idx);
}
- void paintCell(QPainter* p, const QColorGroup& cg, int column, int width, int align);
+ // TODO: Implement paintCell
ConfigItem* nextItem;
struct menu *menu;
@@ -216,9 +205,9 @@ public:
ConfigItem *item;
};
-class ConfigView : public Q3VBox {
+class ConfigView : public QWidget {
Q_OBJECT
- typedef class Q3VBox Parent;
+ typedef class QWidget Parent;
public:
ConfigView(QWidget* parent, const char *name = 0);
~ConfigView(void);
@@ -249,9 +238,9 @@ public:
static QAction *showPromptAction;
};
-class ConfigInfoView : public Q3TextBrowser {
+class ConfigInfoView : public QTextBrowser {
Q_OBJECT
- typedef class Q3TextBrowser Parent;
+ typedef class QTextBrowser Parent;
public:
ConfigInfoView(QWidget* parent, const char *name = 0);
bool showDebug(void) const { return _showDebug; }
@@ -271,8 +260,8 @@ protected:
QString debug_info(struct symbol *sym);
static QString print_filter(const QString &str);
static void expr_print_help(void *data, struct symbol *sym, const char *str);
- Q3PopupMenu* createPopupMenu(const QPoint& pos);
- void contentsContextMenuEvent(QContextMenuEvent *e);
+ QMenu *createStandardContextMenu(const QPoint & pos);
+ void contextMenuEvent(QContextMenuEvent *e);
struct symbol *sym;
struct menu *_menu;
@@ -299,10 +288,10 @@ protected:
struct symbol **result;
};
-class ConfigMainWindow : public Q3MainWindow {
+class ConfigMainWindow : public QMainWindow {
Q_OBJECT
- static Q3Action *saveAction;
+ static QAction *saveAction;
static void conf_changed(void);
public:
ConfigMainWindow(void);
@@ -331,8 +320,11 @@ protected:
ConfigView *configView;
ConfigList *configList;
ConfigInfoView *helpText;
- Q3ToolBar *toolBar;
- Q3Action *backAction;
- QSplitter* split1;
- QSplitter* split2;
+ QToolBar *toolBar;
+ QAction *backAction;
+ QAction *singleViewAction;
+ QAction *splitViewAction;
+ QAction *fullViewAction;
+ QSplitter *split1;
+ QSplitter *split2;
};
diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c
index 50878dc..25cf0c2 100644
--- a/scripts/kconfig/symbol.c
+++ b/scripts/kconfig/symbol.c
@@ -1116,6 +1116,8 @@ static void sym_check_print_recursive(struct symbol *last_sym)
if (stack->sym == last_sym)
fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
prop->file->name, prop->lineno);
+ fprintf(stderr, "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n");
+ fprintf(stderr, "subsection \"Kconfig recursive dependency limitations\"\n");
if (stack->expr) {
fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
prop->file->name, prop->lineno,
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 125b906..638a38e 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -2711,7 +2711,7 @@ $kernelversion = get_kernel_version();
# generate a sequence of code that will splice in highlighting information
# using the s// operator.
-foreach my $k (keys @highlights) {
+for (my $k = 0; $k < @highlights; $k++) {
my $pattern = $highlights[$k][0];
my $result = $highlights[$k][1];
# print STDERR "scanning pattern:$pattern, highlight:($result)\n";
diff --git a/scripts/ld-version.sh b/scripts/ld-version.sh
index 198580d..d154f08 100755
--- a/scripts/ld-version.sh
+++ b/scripts/ld-version.sh
@@ -2,7 +2,9 @@
# extract linker version number from stdin and turn into single number
{
gsub(".*)", "");
+ gsub(".*version ", "");
+ gsub("-.*", "");
split($1,a, ".");
- print a[1]*10000000 + a[2]*100000 + a[3]*10000 + a[4]*100 + a[5];
+ print a[1]*100000000 + a[2]*1000000 + a[3]*10000 + a[4]*100 + a[5];
exit
}
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 1a10d8a..ba6c34e 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -62,7 +62,7 @@ vmlinux_link()
-Wl,--start-group \
${KBUILD_VMLINUX_MAIN} \
-Wl,--end-group \
- -lutil ${1}
+ -lutil -lrt -lpthread ${1}
rm -f linux
fi
}
diff --git a/scripts/package/builddeb b/scripts/package/builddeb
index b967e4f..6c3b038 100755
--- a/scripts/package/builddeb
+++ b/scripts/package/builddeb
@@ -52,7 +52,16 @@ set_debarch() {
arm64)
debarch=arm64 ;;
arm*)
- debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;;
+ if grep -q CONFIG_AEABI=y $KCONFIG_CONFIG; then
+ if grep -q CONFIG_VFP=y $KCONFIG_CONFIG; then
+ debarch=armhf
+ else
+ debarch=armel
+ fi
+ else
+ debarch=arm
+ fi
+ ;;
*)
debarch=$(dpkg --print-architecture)
echo "" >&2
diff --git a/scripts/recordmcount.c b/scripts/recordmcount.c
index 698768b..e1675927 100644
--- a/scripts/recordmcount.c
+++ b/scripts/recordmcount.c
@@ -48,12 +48,17 @@
static int fd_map; /* File descriptor for file being modified. */
static int mmap_failed; /* Boolean flag. */
-static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */
static char gpfx; /* prefix for global symbol name (sometimes '_') */
static struct stat sb; /* Remember .st_size, etc. */
static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
static const char *altmcount; /* alternate mcount symbol name */
static int warn_on_notrace_sect; /* warn when section has mcount not being recorded */
+static void *file_map; /* pointer of the mapped file */
+static void *file_end; /* pointer to the end of the mapped file */
+static int file_updated; /* flag to state file was changed */
+static void *file_ptr; /* current file pointer location */
+static void *file_append; /* added to the end of the file */
+static size_t file_append_size; /* how much is added to end of file */
/* setjmp() return values */
enum {
@@ -67,10 +72,14 @@ static void
cleanup(void)
{
if (!mmap_failed)
- munmap(ehdr_curr, sb.st_size);
+ munmap(file_map, sb.st_size);
else
- free(ehdr_curr);
- close(fd_map);
+ free(file_map);
+ file_map = NULL;
+ free(file_append);
+ file_append = NULL;
+ file_append_size = 0;
+ file_updated = 0;
}
static void __attribute__((noreturn))
@@ -92,12 +101,22 @@ succeed_file(void)
static off_t
ulseek(int const fd, off_t const offset, int const whence)
{
- off_t const w = lseek(fd, offset, whence);
- if (w == (off_t)-1) {
- perror("lseek");
+ switch (whence) {
+ case SEEK_SET:
+ file_ptr = file_map + offset;
+ break;
+ case SEEK_CUR:
+ file_ptr += offset;
+ break;
+ case SEEK_END:
+ file_ptr = file_map + (sb.st_size - offset);
+ break;
+ }
+ if (file_ptr < file_map) {
+ fprintf(stderr, "lseek: seek before file\n");
fail_file();
}
- return w;
+ return file_ptr - file_map;
}
static size_t
@@ -114,12 +133,38 @@ uread(int const fd, void *const buf, size_t const count)
static size_t
uwrite(int const fd, void const *const buf, size_t const count)
{
- size_t const n = write(fd, buf, count);
- if (n != count) {
- perror("write");
- fail_file();
+ size_t cnt = count;
+ off_t idx = 0;
+
+ file_updated = 1;
+
+ if (file_ptr + count >= file_end) {
+ off_t aoffset = (file_ptr + count) - file_end;
+
+ if (aoffset > file_append_size) {
+ file_append = realloc(file_append, aoffset);
+ file_append_size = aoffset;
+ }
+ if (!file_append) {
+ perror("write");
+ fail_file();
+ }
+ if (file_ptr < file_end) {
+ cnt = file_end - file_ptr;
+ } else {
+ cnt = 0;
+ idx = aoffset - count;
+ }
}
- return n;
+
+ if (cnt)
+ memcpy(file_ptr, buf, cnt);
+
+ if (cnt < count)
+ memcpy(file_append + idx, buf + cnt, count - cnt);
+
+ file_ptr += count;
+ return count;
}
static void *
@@ -192,9 +237,7 @@ static int make_nop_arm64(void *map, size_t const offset)
*/
static void *mmap_file(char const *fname)
{
- void *addr;
-
- fd_map = open(fname, O_RDWR);
+ fd_map = open(fname, O_RDONLY);
if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
perror(fname);
fail_file();
@@ -203,15 +246,58 @@ static void *mmap_file(char const *fname)
fprintf(stderr, "not a regular file: %s\n", fname);
fail_file();
}
- addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
- fd_map, 0);
+ file_map = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
+ fd_map, 0);
mmap_failed = 0;
- if (addr == MAP_FAILED) {
+ if (file_map == MAP_FAILED) {
mmap_failed = 1;
- addr = umalloc(sb.st_size);
- uread(fd_map, addr, sb.st_size);
+ file_map = umalloc(sb.st_size);
+ uread(fd_map, file_map, sb.st_size);
+ }
+ close(fd_map);
+
+ file_end = file_map + sb.st_size;
+
+ return file_map;
+}
+
+static void write_file(const char *fname)
+{
+ char tmp_file[strlen(fname) + 4];
+ size_t n;
+
+ if (!file_updated)
+ return;
+
+ sprintf(tmp_file, "%s.rc", fname);
+
+ /*
+ * After reading the entire file into memory, delete it
+ * and write it back, to prevent weird side effects of modifying
+ * an object file in place.
+ */
+ fd_map = open(tmp_file, O_WRONLY | O_TRUNC | O_CREAT, sb.st_mode);
+ if (fd_map < 0) {
+ perror(fname);
+ fail_file();
+ }
+ n = write(fd_map, file_map, sb.st_size);
+ if (n != sb.st_size) {
+ perror("write");
+ fail_file();
+ }
+ if (file_append_size) {
+ n = write(fd_map, file_append, file_append_size);
+ if (n != file_append_size) {
+ perror("write");
+ fail_file();
+ }
+ }
+ close(fd_map);
+ if (rename(tmp_file, fname) < 0) {
+ perror(fname);
+ fail_file();
}
- return addr;
}
/* w8rev, w8nat, ...: Handle endianness. */
@@ -318,7 +404,6 @@ do_file(char const *const fname)
Elf32_Ehdr *const ehdr = mmap_file(fname);
unsigned int reltype = 0;
- ehdr_curr = ehdr;
w = w4nat;
w2 = w2nat;
w8 = w8nat;
@@ -441,6 +526,7 @@ do_file(char const *const fname)
}
} /* end switch */
+ write_file(fname);
cleanup();
}
@@ -493,11 +579,14 @@ main(int argc, char *argv[])
case SJ_SETJMP: /* normal sequence */
/* Avoid problems if early cleanup() */
fd_map = -1;
- ehdr_curr = NULL;
mmap_failed = 1;
+ file_map = NULL;
+ file_ptr = NULL;
+ file_updated = 0;
do_file(file);
break;
case SJ_FAIL: /* error in do_file or below */
+ fprintf(stderr, "%s: failed\n", file);
++n_error;
break;
case SJ_SUCCEED: /* premature success */
diff --git a/scripts/tags.sh b/scripts/tags.sh
index 8e5aee6..2628890 100755
--- a/scripts/tags.sh
+++ b/scripts/tags.sh
@@ -198,6 +198,8 @@ exuberant()
--regex-c++='/TASK_PFA_TEST\([^,]*,\s*([^)]*)\)/task_\1/' \
--regex-c++='/TASK_PFA_SET\([^,]*,\s*([^)]*)\)/task_set_\1/' \
--regex-c++='/TASK_PFA_CLEAR\([^,]*,\s*([^)]*)\)/task_clear_\1/'\
+ --regex-c++='/DEF_MMIO_(IN|OUT)_(X|D)\(([^,]*),\s*[^)]*\)/\3/' \
+ --regex-c++='/DEBUGGER_BOILERPLATE\(([^,]*)\)/\1/' \
--regex-c='/PCI_OP_READ\((\w*).*[1-4]\)/pci_bus_read_config_\1/' \
--regex-c='/PCI_OP_WRITE\((\w*).*[1-4]\)/pci_bus_write_config_\1/' \
--regex-c='/DEFINE_(MUTEX|SEMAPHORE|SPINLOCK)\((\w*)/\2/v/' \
diff --git a/security/integrity/iint.c b/security/integrity/iint.c
index 3d2f5b4..c2e3ccd 100644
--- a/security/integrity/iint.c
+++ b/security/integrity/iint.c
@@ -234,12 +234,13 @@ int __init integrity_read_file(const char *path, char **data)
}
rc = integrity_kernel_read(file, 0, buf, size);
- if (rc < 0)
- kfree(buf);
- else if (rc != size)
- rc = -EIO;
- else
+ if (rc == size) {
*data = buf;
+ } else {
+ kfree(buf);
+ if (rc >= 0)
+ rc = -EIO;
+ }
out:
fput(file);
return rc;
diff --git a/security/keys/encrypted-keys/encrypted.c b/security/keys/encrypted-keys/encrypted.c
index 927db9f..696ccfa 100644
--- a/security/keys/encrypted-keys/encrypted.c
+++ b/security/keys/encrypted-keys/encrypted.c
@@ -845,6 +845,8 @@ static int encrypted_update(struct key *key, struct key_preparsed_payload *prep)
size_t datalen = prep->datalen;
int ret = 0;
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+ return -ENOKEY;
if (datalen <= 0 || datalen > 32767 || !prep->data)
return -EINVAL;
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index fb111ea..1c3872a 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -751,16 +751,16 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
/* the key is probably readable - now try to read it */
can_read_key:
- ret = key_validate(key);
- if (ret == 0) {
- ret = -EOPNOTSUPP;
- if (key->type->read) {
- /* read the data with the semaphore held (since we
- * might sleep) */
- down_read(&key->sem);
+ ret = -EOPNOTSUPP;
+ if (key->type->read) {
+ /* Read the data with the semaphore held (since we might sleep)
+ * to protect against the key being updated or revoked.
+ */
+ down_read(&key->sem);
+ ret = key_validate(key);
+ if (ret == 0)
ret = key->type->read(key, buffer, buflen);
- up_read(&key->sem);
- }
+ up_read(&key->sem);
}
error2:
diff --git a/security/keys/trusted.c b/security/keys/trusted.c
index 903dace..16dec53 100644
--- a/security/keys/trusted.c
+++ b/security/keys/trusted.c
@@ -1007,13 +1007,16 @@ static void trusted_rcu_free(struct rcu_head *rcu)
*/
static int trusted_update(struct key *key, struct key_preparsed_payload *prep)
{
- struct trusted_key_payload *p = key->payload.data[0];
+ struct trusted_key_payload *p;
struct trusted_key_payload *new_p;
struct trusted_key_options *new_o;
size_t datalen = prep->datalen;
char *datablob;
int ret = 0;
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+ return -ENOKEY;
+ p = key->payload.data[0];
if (!p->migratable)
return -EPERM;
if (datalen <= 0 || datalen > 32767 || !prep->data)
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 28cb30f..8705d79 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -120,7 +120,10 @@ int user_update(struct key *key, struct key_preparsed_payload *prep)
if (ret == 0) {
/* attach the new data, displacing the old */
- zap = key->payload.data[0];
+ if (!test_bit(KEY_FLAG_NEGATIVE, &key->flags))
+ zap = key->payload.data[0];
+ else
+ zap = NULL;
rcu_assign_keypointer(key, upayload);
key->expiry = 0;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 9e591e5..d0cfaa9 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4933,7 +4933,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
int ifindex,
u16 family)
{
- struct sock *sk = skb->sk;
+ struct sock *sk = skb_to_full_sk(skb);
struct sk_security_struct *sksec;
struct common_audit_data ad;
struct lsm_network_audit net = {0,};
@@ -4988,7 +4988,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
if (!secmark_active && !peerlbl_active)
return NF_ACCEPT;
- sk = skb->sk;
+ sk = skb_to_full_sk(skb);
#ifdef CONFIG_XFRM
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
@@ -5033,8 +5033,6 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
u32 skb_sid;
struct sk_security_struct *sksec;
- if (sk->sk_state == TCP_NEW_SYN_RECV)
- sk = inet_reqsk(sk)->rsk_listener;
sksec = sk->sk_security;
if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
return NF_DROP;
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 0364120..1f989a5 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -245,7 +245,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
/* if this is a locally generated packet check to see if it is already
* being labeled by it's parent socket, if it is just exit */
- sk = skb->sk;
+ sk = skb_to_full_sk(skb);
if (sk != NULL) {
struct sk_security_struct *sksec = sk->sk_security;
if (sksec->nlbl_state != NLBL_REQSKB)
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c02da25..73c60ba 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -147,23 +147,16 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
ssize_t length;
int new_value;
- length = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;
+ return -ENOMEM;
/* No partial writes. */
- length = -EINVAL;
if (*ppos != 0)
- goto out;
-
- length = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
+ return -EINVAL;
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out;
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
@@ -186,7 +179,7 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
}
length = count;
out:
- free_page((unsigned long) page);
+ kfree(page);
return length;
}
#else
@@ -275,27 +268,20 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char *page = NULL;
+ char *page;
ssize_t length;
int new_value;
- length = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;
+ return -ENOMEM;
/* No partial writes. */
- length = -EINVAL;
if (*ppos != 0)
- goto out;
-
- length = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
+ return -EINVAL;
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out;
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
@@ -313,7 +299,7 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
length = count;
out:
- free_page((unsigned long) page);
+ kfree(page);
return length;
}
#else
@@ -611,31 +597,24 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
- char *page = NULL;
+ char *page;
ssize_t length;
unsigned int new_value;
length = task_has_security(current, SECURITY__SETCHECKREQPROT);
if (length)
- goto out;
+ return length;
- length = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;
+ return -ENOMEM;
/* No partial writes. */
- length = -EINVAL;
if (*ppos != 0)
- goto out;
-
- length = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
+ return -EINVAL;
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out;
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
length = -EINVAL;
if (sscanf(page, "%u", &new_value) != 1)
@@ -644,7 +623,7 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
selinux_checkreqprot = new_value ? 1 : 0;
length = count;
out:
- free_page((unsigned long) page);
+ kfree(page);
return length;
}
static const struct file_operations sel_checkreqprot_ops = {
@@ -1100,14 +1079,12 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (*ppos != 0)
goto out;
- length = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
-
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ page = NULL;
goto out;
+ }
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
@@ -1121,7 +1098,7 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
out:
mutex_unlock(&sel_mutex);
- free_page((unsigned long) page);
+ kfree(page);
return length;
}
@@ -1154,14 +1131,12 @@ static ssize_t sel_commit_bools_write(struct file *filep,
if (*ppos != 0)
goto out;
- length = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
-
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ page = NULL;
goto out;
+ }
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
@@ -1176,7 +1151,7 @@ static ssize_t sel_commit_bools_write(struct file *filep,
out:
mutex_unlock(&sel_mutex);
- free_page((unsigned long) page);
+ kfree(page);
return length;
}
@@ -1292,31 +1267,24 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
size_t count, loff_t *ppos)
{
- char *page = NULL;
+ char *page;
ssize_t ret;
int new_value;
ret = task_has_security(current, SECURITY__SETSECPARAM);
if (ret)
- goto out;
+ return ret;
- ret = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;
+ return -ENOMEM;
/* No partial writes. */
- ret = -EINVAL;
if (*ppos != 0)
- goto out;
-
- ret = -ENOMEM;
- page = (char *)get_zeroed_page(GFP_KERNEL);
- if (!page)
- goto out;
+ return -EINVAL;
- ret = -EFAULT;
- if (copy_from_user(page, buf, count))
- goto out;
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
ret = -EINVAL;
if (sscanf(page, "%u", &new_value) != 1)
@@ -1326,7 +1294,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
ret = count;
out:
- free_page((unsigned long)page);
+ kfree(page);
return ret;
}
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index 18643bf..456e1a9 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -638,7 +638,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
{
struct avtab_node *node;
- if (!ctab || !key || !avd || !xperms)
+ if (!ctab || !key || !avd)
return;
for (node = avtab_search_node(ctab, key); node;
@@ -657,7 +657,7 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) ==
(node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED)))
avd->auditallow |= node->datum.u.data;
- if ((node->key.specified & AVTAB_ENABLED) &&
+ if (xperms && (node->key.specified & AVTAB_ENABLED) &&
(node->key.specified & AVTAB_XPERMS))
services_compute_xperms_drivers(xperms, node);
}
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index ff81026..37fdd54 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1519,8 +1519,6 @@ static int smack_inode_getsecurity(const struct inode *inode,
* @inode: the object
* @buffer: where they go
* @buffer_size: size of buffer
- *
- * Returns 0 on success, -EINVAL otherwise
*/
static int smack_inode_listsecurity(struct inode *inode, char *buffer,
size_t buffer_size)
diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
index 6d1706c..aa6bf1b 100644
--- a/security/smack/smack_netfilter.c
+++ b/security/smack/smack_netfilter.c
@@ -17,6 +17,7 @@
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/netdevice.h>
+#include <net/inet_sock.h>
#include "smack.h"
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -25,11 +26,12 @@ static unsigned int smack_ipv6_output(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
+ struct sock *sk = skb_to_full_sk(skb);
struct socket_smack *ssp;
struct smack_known *skp;
- if (skb && skb->sk && skb->sk->sk_security) {
- ssp = skb->sk->sk_security;
+ if (sk && sk->sk_security) {
+ ssp = sk->sk_security;
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}
@@ -42,11 +44,12 @@ static unsigned int smack_ipv4_output(void *priv,
struct sk_buff *skb,
const struct nf_hook_state *state)
{
+ struct sock *sk = skb_to_full_sk(skb);
struct socket_smack *ssp;
struct smack_known *skp;
- if (skb && skb->sk && skb->sk->sk_security) {
- ssp = skb->sk->sk_security;
+ if (sk && sk->sk_security) {
+ ssp = sk->sk_security;
skp = ssp->smk_out;
skb->secmark = skp->smk_secid;
}
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index 94bd9e4..e249a66 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -497,14 +497,9 @@ static ssize_t smk_write_rules_list(struct file *file, const char __user *buf,
}
}
- data = kmalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto out;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
/*
* In case of parsing only part of user buf,
@@ -884,16 +879,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
(count < SMK_CIPSOMIN || count > SMK_CIPSOMAX))
return -EINVAL;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto unlockedout;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
- data[count] = '\0';
rule = data;
/*
* Only allow one writer at a time. Writes should be
@@ -946,7 +935,6 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
out:
mutex_unlock(&smack_cipso_lock);
-unlockedout:
kfree(data);
return rc;
}
@@ -1187,14 +1175,9 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
if (count < SMK_NETLBLADDRMIN)
return -EINVAL;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto free_data_out;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
smack = kzalloc(count + 1, GFP_KERNEL);
if (smack == NULL) {
@@ -1202,8 +1185,6 @@ static ssize_t smk_write_net4addr(struct file *file, const char __user *buf,
goto free_data_out;
}
- data[count] = '\0';
-
rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s",
&host[0], &host[1], &host[2], &host[3], &masks, smack);
if (rc != 6) {
@@ -1454,14 +1435,9 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
if (count < SMK_NETLBLADDRMIN)
return -EINVAL;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto free_data_out;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
smack = kzalloc(count + 1, GFP_KERNEL);
if (smack == NULL) {
@@ -1469,8 +1445,6 @@ static ssize_t smk_write_net6addr(struct file *file, const char __user *buf,
goto free_data_out;
}
- data[count] = '\0';
-
i = sscanf(data, "%x:%x:%x:%x:%x:%x:%x:%x/%u %s",
&scanned[0], &scanned[1], &scanned[2], &scanned[3],
&scanned[4], &scanned[5], &scanned[6], &scanned[7],
@@ -1865,14 +1839,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf,
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto out;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
skp = smk_import_entry(data, count);
if (IS_ERR(skp)) {
@@ -2041,14 +2010,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf,
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- kfree(data);
- return -EFAULT;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
rc = smk_parse_label_list(data, &list_tmp);
kfree(data);
@@ -2133,14 +2097,9 @@ static ssize_t smk_write_unconfined(struct file *file, const char __user *buf,
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- rc = -EFAULT;
- goto freeout;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
/*
* Clear the smack_unconfined on invalid label errors. This means
@@ -2696,19 +2655,15 @@ static ssize_t smk_write_syslog(struct file *file, const char __user *buf,
if (!smack_privileged(CAP_MAC_ADMIN))
return -EPERM;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
- if (copy_from_user(data, buf, count) != 0)
- rc = -EFAULT;
- else {
- skp = smk_import_entry(data, count);
- if (IS_ERR(skp))
- rc = PTR_ERR(skp);
- else
- smack_syslog_label = skp;
- }
+ skp = smk_import_entry(data, count);
+ if (IS_ERR(skp))
+ rc = PTR_ERR(skp);
+ else
+ smack_syslog_label = skp;
kfree(data);
return rc;
@@ -2798,14 +2753,9 @@ static ssize_t smk_write_relabel_self(struct file *file, const char __user *buf,
if (*ppos != 0)
return -EINVAL;
- data = kzalloc(count + 1, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- if (copy_from_user(data, buf, count) != 0) {
- kfree(data);
- return -EFAULT;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
rc = smk_parse_label_list(data, &list_tmp);
kfree(data);
diff --git a/security/tomoyo/securityfs_if.c b/security/tomoyo/securityfs_if.c
index 179a955..06ab41b1 100644
--- a/security/tomoyo/securityfs_if.c
+++ b/security/tomoyo/securityfs_if.c
@@ -43,13 +43,9 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
int error;
if (!count || count >= TOMOYO_EXEC_TMPSIZE - 10)
return -ENOMEM;
- data = kzalloc(count + 1, GFP_NOFS);
- if (!data)
- return -ENOMEM;
- if (copy_from_user(data, buf, count)) {
- error = -EFAULT;
- goto out;
- }
+ data = memdup_user_nul(buf, count);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
tomoyo_normalize_line(data);
if (tomoyo_correct_domain(data)) {
const int idx = tomoyo_read_lock();
@@ -87,7 +83,6 @@ static ssize_t tomoyo_write_self(struct file *file, const char __user *buf,
tomoyo_read_unlock(idx);
} else
error = -EINVAL;
-out:
kfree(data);
return error ? error : count;
}
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index bee0e5f..e92a6d9 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -38,6 +38,7 @@ config SND_OXFW
* Mackie(Loud) Tapco Link.Firewire
* Mackie(Loud) d.2 pro/d.4 pro
* Mackie(Loud) U.420/U.420d
+ * TASCAM FireOne
To compile this driver as a module, choose M here: the module
will be called snd-oxfw.
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
index 5d99436..0cda05c 100644
--- a/sound/firewire/dice/dice.c
+++ b/sound/firewire/dice/dice.c
@@ -12,9 +12,11 @@ MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_LICENSE("GPL v2");
#define OUI_WEISS 0x001c6a
+#define OUI_LOUD 0x000ff2
#define DICE_CATEGORY_ID 0x04
#define WEISS_CATEGORY_ID 0x00
+#define LOUD_CATEGORY_ID 0x10
static int dice_interface_check(struct fw_unit *unit)
{
@@ -57,6 +59,8 @@ static int dice_interface_check(struct fw_unit *unit)
}
if (vendor == OUI_WEISS)
category = WEISS_CATEGORY_ID;
+ else if (vendor == OUI_LOUD)
+ category = LOUD_CATEGORY_ID;
else
category = DICE_CATEGORY_ID;
if (device->config_rom[3] != ((vendor << 8) | category) ||
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig
index edfc1b8..656ce39 100644
--- a/sound/pci/Kconfig
+++ b/sound/pci/Kconfig
@@ -25,7 +25,7 @@ config SND_ALS300
select SND_PCM
select SND_AC97_CODEC
select SND_OPL3_LIB
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+
@@ -50,7 +50,7 @@ config SND_ALI5451
tristate "ALi M5451 PCI Audio Controller"
select SND_MPU401_UART
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for the integrated AC97 sound
device on motherboards using the ALi M5451 Audio Controller
@@ -155,7 +155,7 @@ config SND_AZT3328
select SND_PCM
select SND_RAWMIDI
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for Aztech AZF3328 (PCI168)
soundcards.
@@ -463,7 +463,7 @@ config SND_EMU10K1
select SND_HWDEP
select SND_RAWMIDI
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y to include support for Sound Blaster PCI 512, Live!,
Audigy and E-mu APS (partially supported) soundcards.
@@ -479,7 +479,7 @@ config SND_EMU10K1X
tristate "Emu10k1X (Dell OEM Version)"
select SND_AC97_CODEC
select SND_RAWMIDI
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for the Dell OEM version of the
Sound Blaster Live!.
@@ -513,7 +513,7 @@ config SND_ES1938
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Solo-1
(ES1938, ES1946, ES1969) chips.
@@ -525,7 +525,7 @@ config SND_ES1968
tristate "ESS ES1968/1978 (Maestro-1/2/2E)"
select SND_MPU401_UART
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro
1/2/2E chips.
@@ -612,7 +612,7 @@ config SND_ICE1712
select SND_MPU401_UART
select SND_AC97_CODEC
select BITREVERSE
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on the
ICE1712 (Envy24) chip.
@@ -700,7 +700,7 @@ config SND_LX6464ES
config SND_MAESTRO3
tristate "ESS Allegro/Maestro3"
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on ESS Maestro 3
(Allegro) chips.
@@ -806,7 +806,7 @@ config SND_SIS7019
tristate "SiS 7019 Audio Accelerator"
depends on X86_32
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for the SiS 7019 Audio Accelerator.
@@ -818,7 +818,7 @@ config SND_SONICVIBES
select SND_OPL3_LIB
select SND_MPU401_UART
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on the S3
SonicVibes chip.
@@ -830,7 +830,7 @@ config SND_TRIDENT
tristate "Trident 4D-Wave DX/NX; SiS 7018"
select SND_MPU401_UART
select SND_AC97_CODEC
- select ZONE_DMA
+ depends on ZONE_DMA
help
Say Y here to include support for soundcards based on Trident
4D-Wave DX/NX or SiS 7018 chips.
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c
index c7dc38d..5fcbb06 100644
--- a/sound/pci/ctxfi/ctamixer.c
+++ b/sound/pci/ctxfi/ctamixer.c
@@ -49,7 +49,7 @@ static int amixer_output_slot(const struct rsc *rsc)
return (amixer_index(rsc) << 4) + 0x4;
}
-static struct rsc_ops amixer_basic_rsc_ops = {
+static const struct rsc_ops amixer_basic_rsc_ops = {
.master = amixer_master,
.next_conj = amixer_next_conj,
.index = amixer_index,
@@ -186,7 +186,7 @@ static int amixer_setup(struct amixer *amixer, struct rsc *input,
return 0;
}
-static struct amixer_rsc_ops amixer_ops = {
+static const struct amixer_rsc_ops amixer_ops = {
.set_input = amixer_set_input,
.set_invalid_squash = amixer_set_invalid_squash,
.set_scale = amixer_set_y,
@@ -357,7 +357,7 @@ static int sum_output_slot(const struct rsc *rsc)
return (sum_index(rsc) << 4) + 0xc;
}
-static struct rsc_ops sum_basic_rsc_ops = {
+static const struct rsc_ops sum_basic_rsc_ops = {
.master = sum_master,
.next_conj = sum_next_conj,
.index = sum_index,
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h
index 72f42f2..2de18aa 100644
--- a/sound/pci/ctxfi/ctamixer.h
+++ b/sound/pci/ctxfi/ctamixer.h
@@ -58,7 +58,7 @@ struct amixer {
unsigned char idx[8];
struct rsc *input; /* pointer to a resource acting as source */
struct sum *sum; /* Put amixer output to this summation node */
- struct amixer_rsc_ops *ops; /* AMixer specific operations */
+ const struct amixer_rsc_ops *ops; /* AMixer specific operations */
};
struct amixer_rsc_ops {
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index 9b87dd2..7f089cb 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -83,21 +83,21 @@ static int daio_in_next_conj_20k2(struct rsc *rsc)
return rsc->conj += 0x100;
}
-static struct rsc_ops daio_out_rsc_ops = {
+static const struct rsc_ops daio_out_rsc_ops = {
.master = daio_master,
.next_conj = daio_out_next_conj,
.index = daio_index,
.output_slot = NULL,
};
-static struct rsc_ops daio_in_rsc_ops_20k1 = {
+static const struct rsc_ops daio_in_rsc_ops_20k1 = {
.master = daio_master,
.next_conj = daio_in_next_conj_20k1,
.index = NULL,
.output_slot = daio_index,
};
-static struct rsc_ops daio_in_rsc_ops_20k2 = {
+static const struct rsc_ops daio_in_rsc_ops_20k2 = {
.master = daio_master,
.next_conj = daio_in_next_conj_20k2,
.index = NULL,
@@ -263,7 +263,7 @@ static int dao_clear_right_input(struct dao *dao)
return 0;
}
-static struct dao_rsc_ops dao_ops = {
+static const struct dao_rsc_ops dao_ops = {
.set_spos = dao_spdif_set_spos,
.commit_write = dao_commit_write,
.get_spos = dao_spdif_get_spos,
@@ -318,7 +318,7 @@ static int dai_commit_write(struct dai *dai)
return 0;
}
-static struct dai_rsc_ops dai_ops = {
+static const struct dai_rsc_ops dai_ops = {
.set_srt_srcl = dai_set_srt_srcl,
.set_srt_srcr = dai_set_srt_srcr,
.set_srt_msr = dai_set_srt_msr,
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h
index 0ebbf35..a30be73 100644
--- a/sound/pci/ctxfi/ctdaio.h
+++ b/sound/pci/ctxfi/ctdaio.h
@@ -51,7 +51,7 @@ struct daio {
struct dao {
struct daio daio;
- struct dao_rsc_ops *ops; /* DAO specific operations */
+ const struct dao_rsc_ops *ops; /* DAO specific operations */
struct imapper **imappers;
struct daio_mgr *mgr;
struct hw *hw;
@@ -60,7 +60,7 @@ struct dao {
struct dai {
struct daio daio;
- struct dai_rsc_ops *ops; /* DAI specific operations */
+ const struct dai_rsc_ops *ops; /* DAI specific operations */
struct hw *hw;
void *ctrl_blk;
};
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c
index 1a97e40..c5124c3 100644
--- a/sound/pci/ctxfi/ctresource.c
+++ b/sound/pci/ctxfi/ctresource.c
@@ -127,7 +127,7 @@ static int rsc_master(struct rsc *rsc)
return rsc->conj = rsc->idx;
}
-static struct rsc_ops rsc_generic_ops = {
+static const struct rsc_ops rsc_generic_ops = {
.index = rsc_index,
.output_slot = audio_ring_slot,
.master = rsc_master,
diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h
index 9b746c3..736d9f7 100644
--- a/sound/pci/ctxfi/ctresource.h
+++ b/sound/pci/ctxfi/ctresource.h
@@ -39,7 +39,7 @@ struct rsc {
u32 msr:4; /* The Master Sample Rate a resource working on */
void *ctrl_blk; /* Chip specific control info block for a resource */
struct hw *hw; /* Chip specific object for hardware access means */
- struct rsc_ops *ops; /* Generic resource operations */
+ const struct rsc_ops *ops; /* Generic resource operations */
};
struct rsc_ops {
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c
index ec1f084..a5a72df 100644
--- a/sound/pci/ctxfi/ctsrc.c
+++ b/sound/pci/ctxfi/ctsrc.c
@@ -335,7 +335,7 @@ static int src_default_config_arcrw(struct src *src)
return 0;
}
-static struct src_rsc_ops src_rsc_ops = {
+static const struct src_rsc_ops src_rsc_ops = {
.set_state = src_set_state,
.set_bm = src_set_bm,
.set_sf = src_set_sf,
@@ -611,7 +611,7 @@ static int srcimp_index(const struct rsc *rsc)
return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj];
}
-static struct rsc_ops srcimp_basic_rsc_ops = {
+static const struct rsc_ops srcimp_basic_rsc_ops = {
.master = srcimp_master,
.next_conj = srcimp_next_conj,
.index = srcimp_index,
@@ -662,7 +662,7 @@ static int srcimp_unmap(struct srcimp *srcimp)
return 0;
}
-static struct srcimp_rsc_ops srcimp_ops = {
+static const struct srcimp_rsc_ops srcimp_ops = {
.map = srcimp_map,
.unmap = srcimp_unmap
};
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h
index da7573c..92944a0 100644
--- a/sound/pci/ctxfi/ctsrc.h
+++ b/sound/pci/ctxfi/ctsrc.h
@@ -48,7 +48,7 @@ struct src_rsc_ops;
struct src {
struct rsc rsc; /* Basic resource info */
struct src *intlv; /* Pointer to next interleaved SRC in a series */
- struct src_rsc_ops *ops; /* SRC specific operations */
+ const struct src_rsc_ops *ops; /* SRC specific operations */
/* Number of contiguous srcs for interleaved usage */
unsigned char multi;
unsigned char mode; /* Working mode of this SRC resource */
@@ -110,7 +110,7 @@ struct srcimp {
struct imapper *imappers;
unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */
struct srcimp_mgr *mgr;
- struct srcimp_rsc_ops *ops;
+ const struct srcimp_rsc_ops *ops;
};
struct srcimp_rsc_ops {
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index e0d9363..514f260 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -113,7 +113,7 @@
#include <sound/initval.h>
#ifdef CONFIG_SND_ES1968_RADIO
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
#endif
#define CARD_NAME "ESS Maestro1/2"
@@ -2605,7 +2605,7 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu
}
}
-static struct snd_tea575x_ops snd_es1968_tea_ops = {
+static const struct snd_tea575x_ops snd_es1968_tea_ops = {
.set_pins = snd_es1968_tea575x_set_pins,
.get_pins = snd_es1968_tea575x_get_pins,
.set_direction = snd_es1968_tea575x_set_direction,
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index 1fdd92b6..759295a 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -30,7 +30,7 @@
#include <sound/initval.h>
#ifdef CONFIG_SND_FM801_TEA575X_BOOL
-#include <media/tea575x.h>
+#include <media/drv-intf/tea575x.h>
#endif
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
@@ -815,7 +815,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output
fm801_writew(chip, GPIO_CTRL, reg);
}
-static struct snd_tea575x_ops snd_fm801_tea_ops = {
+static const struct snd_tea575x_ops snd_fm801_tea_ops = {
.set_pins = snd_fm801_tea575x_set_pins,
.get_pins = snd_fm801_tea575x_get_pins,
.set_direction = snd_fm801_tea575x_set_direction,
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 8a7fbdc..3b36582 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -312,6 +312,10 @@ enum {
(AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\
AZX_DCAPS_I915_POWERWELL)
+#define AZX_DCAPS_INTEL_BROXTON \
+ (AZX_DCAPS_INTEL_PCH | AZX_DCAPS_SEPARATE_STREAM_TAG |\
+ AZX_DCAPS_I915_POWERWELL)
+
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\
@@ -351,6 +355,8 @@ enum {
((pci)->device == 0x0d0c) || \
((pci)->device == 0x160c))
+#define IS_BROXTON(pci) ((pci)->device == 0x5a98)
+
static char *driver_short_names[] = {
[AZX_DRIVER_ICH] = "HDA Intel",
[AZX_DRIVER_PCH] = "HDA Intel PCH",
@@ -502,15 +508,36 @@ static void azx_init_pci(struct azx *chip)
}
}
+/*
+ * In BXT-P A0, HD-Audio DMA requests is later than expected,
+ * and makes an audio stream sensitive to system latencies when
+ * 24/32 bits are playing.
+ * Adjusting threshold of DMA fifo to force the DMA request
+ * sooner to improve latency tolerance at the expense of power.
+ */
+static void bxt_reduce_dma_latency(struct azx *chip)
+{
+ u32 val;
+
+ val = azx_readl(chip, SKL_EM4L);
+ val &= (0x3 << 20);
+ azx_writel(chip, SKL_EM4L, val);
+}
+
static void hda_intel_init_chip(struct azx *chip, bool full_reset)
{
struct hdac_bus *bus = azx_bus(chip);
+ struct pci_dev *pci = chip->pci;
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
snd_hdac_set_codec_wakeup(bus, true);
azx_init_chip(chip, full_reset);
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
snd_hdac_set_codec_wakeup(bus, false);
+
+ /* reduce dma latency to avoid noise */
+ if (IS_BROXTON(pci))
+ bxt_reduce_dma_latency(chip);
}
/* calculate runtime delay from LPIB */
@@ -927,6 +954,36 @@ static int azx_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP || SUPPORT_VGA_SWITCHEROO */
+#ifdef CONFIG_PM_SLEEP
+/* put codec down to D3 at hibernation for Intel SKL+;
+ * otherwise BIOS may still access the codec and screw up the driver
+ */
+#define IS_SKL(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0xa170)
+#define IS_SKL_LP(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x9d70)
+#define IS_BXT(pci) ((pci)->vendor == 0x8086 && (pci)->device == 0x5a98)
+#define IS_SKL_PLUS(pci) (IS_SKL(pci) || IS_SKL_LP(pci) || IS_BXT(pci))
+
+static int azx_freeze_noirq(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+
+ if (IS_SKL_PLUS(pci))
+ pci_set_power_state(pci, PCI_D3hot);
+
+ return 0;
+}
+
+static int azx_thaw_noirq(struct device *dev)
+{
+ struct pci_dev *pci = to_pci_dev(dev);
+
+ if (IS_SKL_PLUS(pci))
+ pci_set_power_state(pci, PCI_D0);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
#ifdef CONFIG_PM
static int azx_runtime_suspend(struct device *dev)
{
@@ -1036,6 +1093,10 @@ static int azx_runtime_idle(struct device *dev)
static const struct dev_pm_ops azx_pm = {
SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume)
+#ifdef CONFIG_PM_SLEEP
+ .freeze_noirq = azx_freeze_noirq,
+ .thaw_noirq = azx_thaw_noirq,
+#endif
SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle)
};
@@ -2124,6 +2185,9 @@ static const struct pci_device_id azx_ids[] = {
/* Sunrise Point-LP */
{ PCI_DEVICE(0x8086, 0x9d70),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_SKYLAKE },
+ /* Broxton-P(Apollolake) */
+ { PCI_DEVICE(0x8086, 0x5a98),
+ .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BROXTON },
/* Haswell */
{ PCI_DEVICE(0x8086, 0x0a0c),
.driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL },
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 366efbf..c945e25 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -383,7 +383,7 @@ static void hda_free_jack_priv(struct snd_jack *jack)
* This assigns a jack-detection kctl to the given pin. The kcontrol
* will have the given name and index.
*/
-static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
+int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, bool phantom_jack)
{
struct hda_jack_tbl *jack;
@@ -410,20 +410,6 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
-
-/**
- * snd_hda_jack_add_kctl - Add a jack kctl for the given pin
- * @codec: the HDA codec
- * @nid: pin NID
- * @name: the name string for the jack ctl
- *
- * This is a simple helper calling __snd_hda_jack_add_kctl().
- */
-int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
- const char *name)
-{
- return __snd_hda_jack_add_kctl(codec, nid, name, false);
-}
EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl);
static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
@@ -451,7 +437,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
if (phantom_jack)
/* Example final name: "Internal Mic Phantom Jack" */
strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
- err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
+ err = snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
if (err < 0)
return err;
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 387d309..858708a 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -82,7 +82,7 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
- const char *name);
+ const char *name, bool phantom_jack);
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index f8a12ca4..4ef2259 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -778,7 +778,8 @@ static const struct hda_pintbl alienware_pincfgs[] = {
};
static const struct snd_pci_quirk ca0132_quirks[] = {
- SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15", QUIRK_ALIENWARE),
+ SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
+ SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
{}
};
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
index c8b8ef5..ef19890 100644
--- a/sound/pci/hda/patch_conexant.c
+++ b/sound/pci/hda/patch_conexant.c
@@ -955,6 +955,7 @@ static int patch_conexant_auto(struct hda_codec *codec)
*/
static const struct hda_device_id snd_hda_id_conexant[] = {
+ HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
@@ -972,9 +973,9 @@ static const struct hda_device_id snd_hda_id_conexant[] = {
HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f1, "CX20721", patch_conexant_auto),
+ HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
- HDA_CODEC_ENTRY(0x14f150f3, "CX20723", patch_conexant_auto),
+ HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index f503a88..4b6fb66 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -50,8 +50,9 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
#define is_haswell(codec) ((codec)->core.vendor_id == 0x80862807)
#define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808)
#define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809)
+#define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a)
#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \
- || is_skylake(codec))
+ || is_skylake(codec) || is_broxton(codec))
#define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882)
#define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883)
@@ -2096,14 +2097,17 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx)
struct hdmi_spec *spec = codec->spec;
struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
int pcmdev = get_pcm_rec(spec, pin_idx)->device;
+ bool phantom_jack;
if (pcmdev > 0)
sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
- if (!is_jack_detectable(codec, per_pin->pin_nid))
+ phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid);
+ if (phantom_jack)
strncat(hdmi_str, " Phantom",
sizeof(hdmi_str) - strlen(hdmi_str) - 1);
- return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str);
+ return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str,
+ phantom_jack);
}
static int generic_hdmi_build_controls(struct hda_codec *codec)
@@ -2348,6 +2352,12 @@ static void intel_pin_eld_notify(void *audio_ptr, int port)
struct hda_codec *codec = audio_ptr;
int pin_nid = port + 0x04;
+ /* skip notification during system suspend (but not in runtime PM);
+ * the state will be updated at resume
+ */
+ if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0)
+ return;
+
check_presence_and_report(codec, pin_nid);
}
@@ -2374,7 +2384,8 @@ static int patch_generic_hdmi(struct hda_codec *codec)
* can cover the codec power request, and so need not set this flag.
* For previous platforms, there is no such power well feature.
*/
- if (is_valleyview_plus(codec) || is_skylake(codec))
+ if (is_valleyview_plus(codec) || is_skylake(codec) ||
+ is_broxton(codec))
codec->core.link_power_control = 1;
if (is_haswell_plus(codec) || is_valleyview_plus(codec)) {
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 2f7b065..3a89d82 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -67,6 +67,10 @@ enum {
ALC_HEADSET_TYPE_OMTP,
};
+enum {
+ ALC_KEY_MICMUTE_INDEX,
+};
+
struct alc_customize_define {
unsigned int sku_cfg;
unsigned char port_connectivity;
@@ -111,6 +115,7 @@ struct alc_spec {
void (*power_hook)(struct hda_codec *codec);
#endif
void (*shutup)(struct hda_codec *codec);
+ void (*reboot_notify)(struct hda_codec *codec);
int init_amp;
int codec_variant; /* flag for other variants */
@@ -122,6 +127,7 @@ struct alc_spec {
unsigned int pll_coef_idx, pll_coef_bit;
unsigned int coef0;
struct input_dev *kb_dev;
+ u8 alc_mute_keycode_map[1];
};
/*
@@ -773,6 +779,25 @@ static inline void alc_shutup(struct hda_codec *codec)
snd_hda_shutup_pins(codec);
}
+static void alc_reboot_notify(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (spec && spec->reboot_notify)
+ spec->reboot_notify(codec);
+ else
+ alc_shutup(codec);
+}
+
+/* power down codec to D3 at reboot/shutdown; set as reboot_notify ops */
+static void alc_d3_at_reboot(struct hda_codec *codec)
+{
+ snd_hda_codec_set_power_to_all(codec, codec->core.afg, AC_PWRST_D3);
+ snd_hda_codec_write(codec, codec->core.afg, 0,
+ AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+ msleep(10);
+}
+
#define alc_free snd_hda_gen_free
#ifdef CONFIG_PM
@@ -818,7 +843,7 @@ static const struct hda_codec_ops alc_patch_ops = {
.suspend = alc_suspend,
.check_power_status = snd_hda_gen_check_power_status,
#endif
- .reboot_notify = alc_shutup,
+ .reboot_notify = alc_reboot_notify,
};
@@ -1755,10 +1780,12 @@ enum {
ALC889_FIXUP_MBA11_VREF,
ALC889_FIXUP_MBA21_VREF,
ALC889_FIXUP_MP11_VREF,
+ ALC889_FIXUP_MP41_VREF,
ALC882_FIXUP_INV_DMIC,
ALC882_FIXUP_NO_PRIMARY_HP,
ALC887_FIXUP_ASUS_BASS,
ALC887_FIXUP_BASS_CHMAP,
+ ALC882_FIXUP_DISABLE_AAMIX,
};
static void alc889_fixup_coef(struct hda_codec *codec,
@@ -1842,7 +1869,7 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
struct alc_spec *spec = codec->spec;
- static hda_nid_t nids[2] = { 0x14, 0x15 };
+ static hda_nid_t nids[3] = { 0x14, 0x15, 0x19 };
int i;
if (action != HDA_FIXUP_ACT_INIT)
@@ -1920,6 +1947,8 @@ static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
static void alc_fixup_bass_chmap(struct hda_codec *codec,
const struct hda_fixup *fix, int action);
+static void alc_fixup_disable_aamix(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action);
static const struct hda_fixup alc882_fixups[] = {
[ALC882_FIXUP_ABIT_AW9D_MAX] = {
@@ -2130,6 +2159,12 @@ static const struct hda_fixup alc882_fixups[] = {
.chained = true,
.chain_id = ALC885_FIXUP_MACPRO_GPIO,
},
+ [ALC889_FIXUP_MP41_VREF] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc889_fixup_mbp_vref,
+ .chained = true,
+ .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+ },
[ALC882_FIXUP_INV_DMIC] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_inv_dmic,
@@ -2151,6 +2186,10 @@ static const struct hda_fixup alc882_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_bass_chmap,
},
+ [ALC882_FIXUP_DISABLE_AAMIX] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_disable_aamix,
+ },
};
static const struct snd_pci_quirk alc882_fixup_tbl[] = {
@@ -2208,7 +2247,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
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, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
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),
@@ -2218,6 +2257,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1458, 0xa182, "Gigabyte Z170X-UD3", ALC882_FIXUP_DISABLE_AAMIX),
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
@@ -3427,12 +3467,43 @@ static void gpio2_mic_hotkey_event(struct hda_codec *codec,
/* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
send both key on and key off event for every interrupt. */
- input_report_key(spec->kb_dev, KEY_MICMUTE, 1);
+ input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1);
input_sync(spec->kb_dev);
- input_report_key(spec->kb_dev, KEY_MICMUTE, 0);
+ input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0);
input_sync(spec->kb_dev);
}
+static int alc_register_micmute_input_device(struct hda_codec *codec)
+{
+ struct alc_spec *spec = codec->spec;
+ int i;
+
+ spec->kb_dev = input_allocate_device();
+ if (!spec->kb_dev) {
+ codec_err(codec, "Out of memory (input_allocate_device)\n");
+ return -ENOMEM;
+ }
+
+ spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE;
+
+ spec->kb_dev->name = "Microphone Mute Button";
+ spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+ spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]);
+ spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map);
+ spec->kb_dev->keycode = spec->alc_mute_keycode_map;
+ for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++)
+ set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit);
+
+ if (input_register_device(spec->kb_dev)) {
+ codec_err(codec, "input_register_device failed\n");
+ input_free_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -3450,20 +3521,8 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->kb_dev = input_allocate_device();
- if (!spec->kb_dev) {
- codec_err(codec, "Out of memory (input_allocate_device)\n");
- return;
- }
- spec->kb_dev->name = "Microphone Mute Button";
- spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
- spec->kb_dev->keybit[BIT_WORD(KEY_MICMUTE)] = BIT_MASK(KEY_MICMUTE);
- if (input_register_device(spec->kb_dev)) {
- codec_err(codec, "input_register_device failed\n");
- input_free_device(spec->kb_dev);
- spec->kb_dev = NULL;
+ if (alc_register_micmute_input_device(codec) != 0)
return;
- }
snd_hda_add_verbs(codec, gpio_init);
snd_hda_codec_write_cache(codec, codec->core.afg, 0,
@@ -3493,6 +3552,47 @@ static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
}
}
+static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ /* Line2 = mic mute hotkey
+ GPIO2 = mic mute LED */
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 },
+ {}
+ };
+
+ struct alc_spec *spec = codec->spec;
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ if (alc_register_micmute_input_device(codec) != 0)
+ return;
+
+ snd_hda_add_verbs(codec, gpio_init);
+ snd_hda_jack_detect_enable_callback(codec, 0x1b,
+ gpio2_mic_hotkey_event);
+
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+ spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mic_led_mask = 0x04;
+ return;
+ }
+
+ if (!spec->kb_dev)
+ return;
+
+ switch (action) {
+ case HDA_FIXUP_ACT_PROBE:
+ spec->init_amp = ALC_INIT_DEFAULT;
+ break;
+ case HDA_FIXUP_ACT_FREE:
+ input_unregister_device(spec->kb_dev);
+ spec->kb_dev = NULL;
+ }
+}
+
static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
{
@@ -4190,6 +4290,8 @@ static void alc_fixup_tpt440_dock(struct hda_codec *codec,
struct alc_spec *spec = codec->spec;
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->shutup = alc_no_shutup; /* reduce click noise */
+ spec->reboot_notify = alc_d3_at_reboot; /* reduce noise */
spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
codec->power_save_node = 0; /* avoid click noises */
snd_hda_apply_pincfgs(codec, pincfgs);
@@ -4570,6 +4672,7 @@ enum {
ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC292_FIXUP_TPT440_DOCK,
+ ALC292_FIXUP_TPT440,
ALC283_FIXUP_BXBT2807_MIC,
ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
ALC282_FIXUP_ASPIRE_V5_PINS,
@@ -4585,8 +4688,12 @@ enum {
ALC288_FIXUP_DISABLE_AAMIX,
ALC292_FIXUP_DELL_E7X,
ALC292_FIXUP_DISABLE_AAMIX,
+ ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
ALC275_FIXUP_DELL_XPS,
+ ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE,
+ ALC293_FIXUP_LENOVO_SPK_NOISE,
+ ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -5041,6 +5148,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
},
+ [ALC292_FIXUP_TPT440] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_disable_aamix,
+ .chained = true,
+ .chain_id = ALC292_FIXUP_TPT440_DOCK,
+ },
[ALC283_FIXUP_BXBT2807_MIC] = {
.type = HDA_FIXUP_PINS,
.v.pins = (const struct hda_pintbl[]) {
@@ -5140,6 +5253,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE
},
+ [ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_disable_aamix,
+ .chained = true,
+ .chain_id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
[ALC292_FIXUP_DELL_E7X] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc_fixup_dell_xps13,
@@ -5167,6 +5286,27 @@ static const struct hda_fixup alc269_fixups[] = {
{}
}
},
+ [ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE] = {
+ .type = HDA_FIXUP_VERBS,
+ .v.verbs = (const struct hda_verb[]) {
+ /* Disable pass-through path for FRONT 14h */
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x36},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x1737},
+ {}
+ },
+ .chained = true,
+ .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+ },
+ [ALC293_FIXUP_LENOVO_SPK_NOISE] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc_fixup_disable_aamix,
+ .chained = true,
+ .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+ },
+ [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -5180,8 +5320,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
+ SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
+ SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
@@ -5199,11 +5341,12 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
- SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
- SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
- SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
- SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
- SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC292_FIXUP_DISABLE_AAMIX),
+ SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+ SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+ SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+ SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+ SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+ SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -5302,15 +5445,18 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
- SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440),
SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
+ SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
@@ -5320,6 +5466,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
+ SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
@@ -5400,6 +5547,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
{.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
{.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
{.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
+ {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
{}
};
@@ -6386,6 +6534,7 @@ static const struct hda_fixup alc662_fixups[] = {
static const struct snd_pci_quirk alc662_fixup_tbl[] = {
SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
+ SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index 826122d..2c7c5eb 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -3110,6 +3110,29 @@ static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec,
spec->gpio_led = 0x08;
}
+static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin)
+{
+ unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+ /* count line-out, too, as BIOS sets often so */
+ return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE &&
+ (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
+ get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT);
+}
+
+static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin)
+{
+ unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+ /* It was changed in the BIOS to just satisfy MS DTM.
+ * Lets turn it back into slaved HP
+ */
+ pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) |
+ (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT);
+ pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) |
+ 0x1f;
+ snd_hda_codec_set_pincfg(codec, pin, pin_cfg);
+}
static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
const struct hda_fixup *fix, int action)
@@ -3119,22 +3142,12 @@ static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
if (action != HDA_FIXUP_ACT_PRE_PROBE)
return;
- if (hp_blike_system(codec->core.subsystem_id)) {
- unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f);
- if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
- get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER ||
- get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) {
- /* It was changed in the BIOS to just satisfy MS DTM.
- * Lets turn it back into slaved HP
- */
- pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE))
- | (AC_JACK_HP_OUT <<
- AC_DEFCFG_DEVICE_SHIFT);
- pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC
- | AC_DEFCFG_SEQUENCE)))
- | 0x1f;
- snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg);
- }
+ /* when both output A and F are assigned, these are supposedly
+ * dock and built-in headphones; fix both pin configs
+ */
+ if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) {
+ fixup_hp_headphone(codec, 0x0a);
+ fixup_hp_headphone(codec, 0x0f);
}
if (find_mute_led_cfg(codec, 1))
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 714df90..41c31db 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -741,10 +741,11 @@ snd_rme96_playback_setrate(struct rme96 *rme96,
{
/* change to/from double-speed: reset the DAC (if available) */
snd_rme96_reset_dac(rme96);
+ return 1; /* need to restore volume */
} else {
writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
+ return 0;
}
- return 0;
}
static int
@@ -980,6 +981,7 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
struct rme96 *rme96 = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
int err, rate, dummy;
+ bool apply_dac_volume = false;
runtime->dma_area = (void __force *)(rme96->iobase +
RME96_IO_PLAY_BUFFER);
@@ -993,24 +995,26 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
{
/* slave clock */
if ((int)params_rate(params) != rate) {
- spin_unlock_irq(&rme96->lock);
- return -EIO;
- }
- } else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) {
- spin_unlock_irq(&rme96->lock);
- return err;
- }
- if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) {
- spin_unlock_irq(&rme96->lock);
- return err;
+ err = -EIO;
+ goto error;
+ }
+ } else {
+ err = snd_rme96_playback_setrate(rme96, params_rate(params));
+ if (err < 0)
+ goto error;
+ apply_dac_volume = err > 0; /* need to restore volume later? */
}
+
+ err = snd_rme96_playback_setformat(rme96, params_format(params));
+ if (err < 0)
+ goto error;
snd_rme96_setframelog(rme96, params_channels(params), 1);
if (rme96->capture_periodsize != 0) {
if (params_period_size(params) << rme96->playback_frlog !=
rme96->capture_periodsize)
{
- spin_unlock_irq(&rme96->lock);
- return -EBUSY;
+ err = -EBUSY;
+ goto error;
}
}
rme96->playback_periodsize =
@@ -1021,9 +1025,16 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER);
}
+
+ err = 0;
+ error:
spin_unlock_irq(&rme96->lock);
-
- return 0;
+ if (apply_dac_volume) {
+ usleep_range(3000, 10000);
+ snd_rme96_apply_dac_volume(rme96);
+ }
+
+ return err;
}
static int
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 9929efc..93b4008 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -1023,24 +1023,18 @@ void arizona_init_dvfs(struct arizona_priv *priv)
}
EXPORT_SYMBOL_GPL(arizona_init_dvfs);
-static unsigned int arizona_sysclk_48k_rates[] = {
+static unsigned int arizona_opclk_ref_48k_rates[] = {
6144000,
12288000,
24576000,
49152000,
- 73728000,
- 98304000,
- 147456000,
};
-static unsigned int arizona_sysclk_44k1_rates[] = {
+static unsigned int arizona_opclk_ref_44k1_rates[] = {
5644800,
11289600,
22579200,
45158400,
- 67737600,
- 90316800,
- 135475200,
};
static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
@@ -1065,11 +1059,11 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk,
}
if (refclk % 8000)
- rates = arizona_sysclk_44k1_rates;
+ rates = arizona_opclk_ref_44k1_rates;
else
- rates = arizona_sysclk_48k_rates;
+ rates = arizona_opclk_ref_48k_rates;
- for (ref = 0; ref < ARRAY_SIZE(arizona_sysclk_48k_rates) &&
+ for (ref = 0; ref < ARRAY_SIZE(arizona_opclk_ref_48k_rates) &&
rates[ref] <= refclk; ref++) {
div = 1;
while (rates[ref] / div >= freq && div < 32) {
@@ -1543,7 +1537,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
bool reconfig;
unsigned int aif_tx_state, aif_rx_state;
- if (params_rate(params) % 8000)
+ if (params_rate(params) % 4000)
rates = &arizona_44k1_bclk_rates[0];
else
rates = &arizona_48k_bclk_rates[0];
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
index 969e337..afa6c5d 100644
--- a/sound/soc/codecs/es8328.c
+++ b/sound/soc/codecs/es8328.c
@@ -85,7 +85,15 @@ static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0);
static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0);
-static const int deemph_settings[] = { 0, 32000, 44100, 48000 };
+static const struct {
+ int rate;
+ unsigned int val;
+} deemph_settings[] = {
+ { 0, ES8328_DACCONTROL6_DEEMPH_OFF },
+ { 32000, ES8328_DACCONTROL6_DEEMPH_32k },
+ { 44100, ES8328_DACCONTROL6_DEEMPH_44_1k },
+ { 48000, ES8328_DACCONTROL6_DEEMPH_48k },
+};
static int es8328_set_deemph(struct snd_soc_codec *codec)
{
@@ -97,21 +105,22 @@ static int es8328_set_deemph(struct snd_soc_codec *codec)
* rate.
*/
if (es8328->deemph) {
- best = 1;
- for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) {
- if (abs(deemph_settings[i] - es8328->playback_fs) <
- abs(deemph_settings[best] - es8328->playback_fs))
+ best = 0;
+ for (i = 1; i < ARRAY_SIZE(deemph_settings); i++) {
+ if (abs(deemph_settings[i].rate - es8328->playback_fs) <
+ abs(deemph_settings[best].rate - es8328->playback_fs))
best = i;
}
- val = best << 1;
+ val = deemph_settings[best].val;
} else {
- val = 0;
+ val = ES8328_DACCONTROL6_DEEMPH_OFF;
}
dev_dbg(codec->dev, "Set deemphasis %d\n", val);
- return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val);
+ return snd_soc_update_bits(codec, ES8328_DACCONTROL6,
+ ES8328_DACCONTROL6_DEEMPH_MASK, val);
}
static int es8328_get_deemph(struct snd_kcontrol *kcontrol,
@@ -205,18 +214,18 @@ static const struct snd_kcontrol_new es8328_right_line_controls =
/* Left Mixer */
static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
- SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0),
- SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0),
- SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0),
- SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0),
+ SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0),
+ SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0),
};
/* Right Mixer */
static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
- SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0),
- SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0),
- SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0),
- SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0),
+ SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0),
+ SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0),
+ SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0),
};
static const char * const es8328_pga_sel[] = {
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h
index cb36afe..156c748 100644
--- a/sound/soc/codecs/es8328.h
+++ b/sound/soc/codecs/es8328.h
@@ -153,6 +153,7 @@ int es8328_probe(struct device *dev, struct regmap *regmap);
#define ES8328_DACCONTROL6_CLICKFREE (1 << 3)
#define ES8328_DACCONTROL6_DAC_INVR (1 << 4)
#define ES8328_DACCONTROL6_DAC_INVL (1 << 5)
+#define ES8328_DACCONTROL6_DEEMPH_MASK (3 << 6)
#define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6)
#define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6)
#define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6)
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c
index 7fc7b4e..c1b87c5 100644
--- a/sound/soc/codecs/nau8825.c
+++ b/sound/soc/codecs/nau8825.c
@@ -1271,6 +1271,36 @@ static int nau8825_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int nau8825_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nau8825 *nau8825 = dev_get_drvdata(dev);
+
+ disable_irq(client->irq);
+ regcache_cache_only(nau8825->regmap, true);
+ regcache_mark_dirty(nau8825->regmap);
+
+ return 0;
+}
+
+static int nau8825_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct nau8825 *nau8825 = dev_get_drvdata(dev);
+
+ regcache_cache_only(nau8825->regmap, false);
+ regcache_sync(nau8825->regmap);
+ enable_irq(client->irq);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops nau8825_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(nau8825_suspend, nau8825_resume)
+};
+
static const struct i2c_device_id nau8825_i2c_ids[] = {
{ "nau8825", 0 },
{ }
@@ -1297,6 +1327,7 @@ static struct i2c_driver nau8825_driver = {
.name = "nau8825",
.of_match_table = of_match_ptr(nau8825_of_ids),
.acpi_match_table = ACPI_PTR(nau8825_acpi_match),
+ .pm = &nau8825_pm,
},
.probe = nau8825_i2c_probe,
.remove = nau8825_i2c_remove,
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c
index aca479f..1dc68ab 100644
--- a/sound/soc/codecs/rl6231.c
+++ b/sound/soc/codecs/rl6231.c
@@ -80,8 +80,10 @@ int rl6231_calc_dmic_clk(int rate)
}
for (i = 0; i < ARRAY_SIZE(div); i++) {
- /* find divider that gives DMIC frequency below 3MHz */
- if (3000000 * div[i] >= rate)
+ if ((div[i] % 3) == 0)
+ continue;
+ /* find divider that gives DMIC frequency below 3.072MHz */
+ if (3072000 * div[i] >= rate)
return i;
}
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index 2813237..3e3c7f6 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -245,7 +245,7 @@ struct rt5645_priv {
struct snd_soc_jack *hp_jack;
struct snd_soc_jack *mic_jack;
struct snd_soc_jack *btn_jack;
- struct delayed_work jack_detect_work;
+ struct delayed_work jack_detect_work, rcclock_work;
struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)];
struct rt5645_eq_param_s *eq_param;
@@ -565,12 +565,33 @@ static int rt5645_hweq_put(struct snd_kcontrol *kcontrol,
.put = rt5645_hweq_put \
}
+static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component);
+ int ret;
+
+ cancel_delayed_work_sync(&rt5645->rcclock_work);
+
+ regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+ RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU);
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+
+ queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work,
+ msecs_to_jiffies(200));
+
+ return ret;
+}
+
static const struct snd_kcontrol_new rt5645_snd_controls[] = {
/* Speaker Output Volume */
SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL,
RT5645_VOL_L_SFT, RT5645_VOL_R_SFT, 1, 1),
- SOC_DOUBLE_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
- RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, out_vol_tlv),
+ SOC_DOUBLE_EXT_TLV("Speaker Playback Volume", RT5645_SPK_VOL,
+ RT5645_L_VOL_SFT, RT5645_R_VOL_SFT, 39, 1, snd_soc_get_volsw,
+ rt5645_spk_put_volsw, out_vol_tlv),
/* ClassD modulator Speaker Gain Ratio */
SOC_SINGLE_TLV("Speaker ClassD Playback Volume", RT5645_SPO_CLSD_RATIO,
@@ -1498,7 +1519,7 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on)
regmap_write(rt5645->regmap, RT5645_PR_BASE +
RT5645_MAMP_INT_REG2, 0xfc00);
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140);
- msleep(40);
+ msleep(70);
rt5645->hp_on = true;
} else {
/* depop parameters */
@@ -1646,9 +1667,13 @@ static int rt5645_spk_event(struct snd_soc_dapm_widget *w,
RT5645_PWR_CLS_D_L,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
RT5645_PWR_CLS_D_L);
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+ RT5645_DET_CLK_MASK, RT5645_DET_CLK_MODE1);
break;
case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT5645_GEN_CTRL3,
+ RT5645_DET_CLK_MASK, RT5645_DET_CLK_DIS);
snd_soc_write(codec, RT5645_EQ_CTRL2, 0);
snd_soc_update_bits(codec, RT5645_PWR_DIG1,
RT5645_PWR_CLS_D | RT5645_PWR_CLS_D_R |
@@ -3122,6 +3147,15 @@ static void rt5645_jack_detect_work(struct work_struct *work)
SND_JACK_BTN_2 | SND_JACK_BTN_3);
}
+static void rt5645_rcclock_work(struct work_struct *work)
+{
+ struct rt5645_priv *rt5645 =
+ container_of(work, struct rt5645_priv, rcclock_work.work);
+
+ regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+ RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PD);
+}
+
static irqreturn_t rt5645_irq(int irq, void *data)
{
struct rt5645_priv *rt5645 = data;
@@ -3348,6 +3382,27 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Reks"),
},
},
+ {
+ .ident = "Google Edgar",
+ .callback = strago_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"),
+ },
+ },
+ {
+ .ident = "Google Wizpig",
+ .callback = strago_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"),
+ },
+ },
+ {
+ .ident = "Google Terra",
+ .callback = strago_quirk_cb,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "Terra"),
+ },
+ },
{ }
};
@@ -3587,6 +3642,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+ INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work);
if (rt5645->i2c->irq) {
ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
@@ -3621,6 +3677,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
free_irq(i2c->irq, rt5645);
cancel_delayed_work_sync(&rt5645->jack_detect_work);
+ cancel_delayed_work_sync(&rt5645->rcclock_work);
snd_soc_unregister_codec(&i2c->dev);
regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 093e46d..205e071 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -2122,6 +2122,10 @@ enum {
/* General Control3 (0xfc) */
#define RT5645_JD_PSV_MODE (0x1 << 12)
#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11)
+#define RT5645_DET_CLK_MASK (0x3 << 9)
+#define RT5645_DET_CLK_DIS (0x0 << 9)
+#define RT5645_DET_CLK_MODE1 (0x1 << 9)
+#define RT5645_DET_CLK_MODE2 (0x2 << 9)
#define RT5645_MICINDET_MANU (0x1 << 7)
#define RT5645_RING2_SLEEVE_GND (0x1 << 5)
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index dc2b462..3f1b0f1 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -973,12 +973,12 @@
#define RT5670_SCLK_SRC_MCLK (0x0 << 14)
#define RT5670_SCLK_SRC_PLL1 (0x1 << 14)
#define RT5670_SCLK_SRC_RCCLK (0x2 << 14) /* 15MHz */
-#define RT5670_PLL1_SRC_MASK (0x3 << 12)
-#define RT5670_PLL1_SRC_SFT 12
-#define RT5670_PLL1_SRC_MCLK (0x0 << 12)
-#define RT5670_PLL1_SRC_BCLK1 (0x1 << 12)
-#define RT5670_PLL1_SRC_BCLK2 (0x2 << 12)
-#define RT5670_PLL1_SRC_BCLK3 (0x3 << 12)
+#define RT5670_PLL1_SRC_MASK (0x7 << 11)
+#define RT5670_PLL1_SRC_SFT 11
+#define RT5670_PLL1_SRC_MCLK (0x0 << 11)
+#define RT5670_PLL1_SRC_BCLK1 (0x1 << 11)
+#define RT5670_PLL1_SRC_BCLK2 (0x2 << 11)
+#define RT5670_PLL1_SRC_BCLK3 (0x3 << 11)
#define RT5670_PLL1_PD_MASK (0x1 << 3)
#define RT5670_PLL1_PD_SFT 3
#define RT5670_PLL1_PD_1 (0x0 << 3)
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index b4cd7e3..69d987a 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -1386,90 +1386,90 @@ static const struct snd_kcontrol_new rt5677_dac_r_mix[] = {
};
static const struct snd_kcontrol_new rt5677_sto1_dac_l_mix[] = {
- SOC_DAPM_SINGLE("ST L Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_ST_DAC1_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC1_L_STO_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC2_L_STO_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC1_R_STO_L_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_sto1_dac_r_mix[] = {
- SOC_DAPM_SINGLE("ST R Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_ST_DAC1_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC1_R_STO_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC2_R_STO_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_STO1_DAC_MIXER,
RT5677_M_DAC1_L_STO_R_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_mono_dac_l_mix[] = {
- SOC_DAPM_SINGLE("ST L Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("ST L Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_ST_DAC2_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 L Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC1_L_MONO_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC2_L_MONO_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC2_R_MONO_L_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_mono_dac_r_mix[] = {
- SOC_DAPM_SINGLE("ST R Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("ST R Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_ST_DAC2_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC1 R Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC1_R_MONO_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 R Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC2_R_MONO_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC2 L Switch", RT5677_MONO_DAC_MIXER,
RT5677_M_DAC2_L_MONO_R_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_dd1_l_mix[] = {
- SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD1_MIXER,
RT5677_M_STO_L_DD1_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD1_MIXER,
RT5677_M_MONO_L_DD1_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
RT5677_M_DAC3_L_DD1_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
RT5677_M_DAC3_R_DD1_L_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_dd1_r_mix[] = {
- SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD1_MIXER,
RT5677_M_STO_R_DD1_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD1_MIXER,
RT5677_M_MONO_R_DD1_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC3 R Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC3 R Switch", RT5677_DD1_MIXER,
RT5677_M_DAC3_R_DD1_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC3 L Switch", RT5677_DD1_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC3 L Switch", RT5677_DD1_MIXER,
RT5677_M_DAC3_L_DD1_R_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_dd2_l_mix[] = {
- SOC_DAPM_SINGLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix L Switch", RT5677_DD2_MIXER,
RT5677_M_STO_L_DD2_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix L Switch", RT5677_DD2_MIXER,
RT5677_M_MONO_L_DD2_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
RT5677_M_DAC4_L_DD2_L_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
RT5677_M_DAC4_R_DD2_L_SFT, 1, 1),
};
static const struct snd_kcontrol_new rt5677_dd2_r_mix[] = {
- SOC_DAPM_SINGLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Sto DAC Mix R Switch", RT5677_DD2_MIXER,
RT5677_M_STO_R_DD2_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("Mono DAC Mix R Switch", RT5677_DD2_MIXER,
RT5677_M_MONO_R_DD2_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC4 R Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC4 R Switch", RT5677_DD2_MIXER,
RT5677_M_DAC4_R_DD2_R_SFT, 1, 1),
- SOC_DAPM_SINGLE("DAC4 L Switch", RT5677_DD2_MIXER,
+ SOC_DAPM_SINGLE_AUTODISABLE("DAC4 L Switch", RT5677_DD2_MIXER,
RT5677_M_DAC4_L_DD2_R_SFT, 1, 1),
};
@@ -2596,6 +2596,21 @@ static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5677_filter_power_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ msleep(50);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
0, rt5677_set_pll1_event, SND_SOC_DAPM_PRE_PMU |
@@ -3072,19 +3087,26 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
/* DAC Mixer */
SND_SOC_DAPM_SUPPLY("dac stereo1 filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_S1F_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_S1F_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono2 left filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M2F_L_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M2F_L_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono2 right filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M2F_R_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M2F_R_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono3 left filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M3F_L_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M3F_L_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono3 right filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M3F_R_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M3F_R_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono4 left filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M4F_L_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M4F_L_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_SUPPLY("dac mono4 right filter", RT5677_PWR_DIG2,
- RT5677_PWR_DAC_M4F_R_BIT, 0, NULL, 0),
+ RT5677_PWR_DAC_M4F_R_BIT, 0, rt5677_filter_power_event,
+ SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0,
rt5677_sto1_dac_l_mix, ARRAY_SIZE(rt5677_sto1_dac_l_mix)),
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index f540f82..08b4046 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -189,6 +189,7 @@ static int power_vag_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU:
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP);
+ msleep(400);
break;
case SND_SOC_DAPM_PRE_PMD:
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 0563753..5380798 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -229,7 +229,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8960_LINVOL, WM8960_RINVOL,
SOC_DOUBLE_R("Capture Volume ZC Switch", WM8960_LINVOL, WM8960_RINVOL,
6, 1, 0),
SOC_DOUBLE_R("Capture Switch", WM8960_LINVOL, WM8960_RINVOL,
- 7, 1, 0),
+ 7, 1, 1),
SOC_SINGLE_TLV("Right Input Boost Mixer RINPUT3 Volume",
WM8960_INBMIX1, 4, 7, 0, lineinboost_tlv),
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 39ebd7b..a7e7978 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -365,8 +365,8 @@ static const struct reg_default wm8962_reg[] = {
{ 16924, 0x0059 }, /* R16924 - HDBASS_PG_1 */
{ 16925, 0x999A }, /* R16925 - HDBASS_PG_0 */
- { 17048, 0x0083 }, /* R17408 - HPF_C_1 */
- { 17049, 0x98AD }, /* R17409 - HPF_C_0 */
+ { 17408, 0x0083 }, /* R17408 - HPF_C_1 */
+ { 17409, 0x98AD }, /* R17409 - HPF_C_0 */
{ 17920, 0x007F }, /* R17920 - ADCL_RETUNE_C1_1 */
{ 17921, 0xFFFF }, /* R17921 - ADCL_RETUNE_C1_0 */
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 0a60677..4c29bd2 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -574,6 +574,7 @@ static const struct regmap_config wm8974_regmap = {
.max_register = WM8974_MONOMIX,
.reg_defaults = wm8974_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(wm8974_reg_defaults),
+ .cache_type = REGCACHE_FLAT,
};
static int wm8974_probe(struct snd_soc_codec *codec)
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 4495a40..2ccb8bc 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -223,8 +223,8 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp)
/* wait for XDATA to be cleared */
cnt = 0;
- while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
- ~XRDATA) && (cnt < 100000))
+ while ((mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & XRDATA) &&
+ (cnt < 100000))
cnt++;
/* Release TX state machine */
@@ -681,8 +681,8 @@ static int davinci_mcasp_set_tdm_slot(struct snd_soc_dai *dai,
}
mcasp->tdm_slots = slots;
- mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = rx_mask;
- mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = tx_mask;
+ mcasp->tdm_mask[SNDRV_PCM_STREAM_PLAYBACK] = tx_mask;
+ mcasp->tdm_mask[SNDRV_PCM_STREAM_CAPTURE] = rx_mask;
mcasp->slot_width = slot_width;
return davinci_mcasp_set_ch_constraints(mcasp);
@@ -908,6 +908,14 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
FSRMOD(total_slots), FSRMOD(0x1FF));
+ /*
+ * If McASP is set to be TX/RX synchronous and the playback is
+ * not running already we need to configure the TX slots in
+ * order to have correct FSX on the bus
+ */
+ if (mcasp_is_synchronous(mcasp) && !mcasp->channels)
+ mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
+ FSXMOD(total_slots), FSXMOD(0x1FF));
}
return 0;
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 19c302b..14dfdee 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -283,6 +283,8 @@ config SND_SOC_IMX_MC13783
config SND_SOC_FSL_ASOC_CARD
tristate "Generic ASoC Sound Card with ASRC support"
depends on OF && I2C
+ # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m:
+ depends on SND_AC97_CODEC || SND_AC97_CODEC=n
select SND_SOC_IMX_AUDMUX
select SND_SOC_IMX_PCM_DMA
select SND_SOC_FSL_ESAI
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index a4435f5..08b460b 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -454,7 +454,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
* Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx.
* Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx.
*/
- regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0);
+ regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC,
+ sai->synchronous[TX] ? FSL_SAI_CR2_SYNC : 0);
regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC,
sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0);
@@ -504,6 +505,24 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd,
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
FSL_SAI_CSR_FR, FSL_SAI_CSR_FR);
+
+ /*
+ * For sai master mode, after several open/close sai,
+ * there will be no frame clock, and can't recover
+ * anymore. Add software reset to fix this issue.
+ * This is a hardware bug, and will be fix in the
+ * next sai version.
+ */
+ if (!sai->is_slave_mode) {
+ /* Software Reset for both Tx and Rx */
+ regmap_write(sai->regmap,
+ FSL_SAI_TCSR, FSL_SAI_CSR_SR);
+ regmap_write(sai->regmap,
+ FSL_SAI_RCSR, FSL_SAI_CSR_SR);
+ /* Clear SR bit to finish the reset */
+ regmap_write(sai->regmap, FSL_SAI_TCSR, 0);
+ regmap_write(sai->regmap, FSL_SAI_RCSR, 0);
+ }
}
break;
default:
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index 7b778ab..d430ef5 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -144,7 +144,7 @@ config SND_SOC_INTEL_SKYLAKE
config SND_SOC_INTEL_SKL_RT286_MACH
tristate "ASoC Audio driver for SKL with RT286 I2S mode"
- depends on X86 && ACPI
+ depends on X86 && ACPI && I2C
select SND_SOC_INTEL_SST
select SND_SOC_INTEL_SKYLAKE
select SND_SOC_RT286
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index a7854c8..ad4d0f8 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -1248,5 +1248,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus)
skl->resource.max_mcps = SKL_MAX_MCPS;
skl->resource.max_mem = SKL_FW_MAX_MEM;
+ skl->tplg = fw;
+
return 0;
}
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c
index 5319529..caa69c4 100644
--- a/sound/soc/intel/skylake/skl.c
+++ b/sound/soc/intel/skylake/skl.c
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
+#include <linux/firmware.h>
#include <sound/pcm.h>
#include "skl.h"
@@ -520,6 +521,9 @@ static void skl_remove(struct pci_dev *pci)
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
struct skl *skl = ebus_to_skl(ebus);
+ if (skl->tplg)
+ release_firmware(skl->tplg);
+
if (pci_dev_run_wake(pci))
pm_runtime_get_noresume(&pci->dev);
pci_dev_put(pci);
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h
index dd2e79a..a0709e3 100644
--- a/sound/soc/intel/skylake/skl.h
+++ b/sound/soc/intel/skylake/skl.h
@@ -68,6 +68,8 @@ struct skl {
struct skl_dsp_resource resource;
struct list_head ppl_list;
struct list_head dapm_path_list;
+
+ const struct firmware *tplg;
};
#define skl_to_ebus(s) (&(s)->ebus)
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c
index a38a302..5a806da 100644
--- a/sound/soc/rockchip/rockchip_spdif.c
+++ b/sound/soc/rockchip/rockchip_spdif.c
@@ -152,8 +152,10 @@ static int rk_spdif_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = regmap_update_bits(spdif->regmap, SPDIF_DMACR,
- SPDIF_DMACR_TDE_ENABLE,
- SPDIF_DMACR_TDE_ENABLE);
+ SPDIF_DMACR_TDE_ENABLE |
+ SPDIF_DMACR_TDL_MASK,
+ SPDIF_DMACR_TDE_ENABLE |
+ SPDIF_DMACR_TDL(16));
if (ret != 0)
return ret;
@@ -280,7 +282,7 @@ static int rk_spdif_probe(struct platform_device *pdev)
int ret;
match = of_match_node(rk_spdif_match, np);
- if ((int) match->data == RK_SPDIF_RK3288) {
+ if (match->data == (void *)RK_SPDIF_RK3288) {
struct regmap *grf;
grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
diff --git a/sound/soc/rockchip/rockchip_spdif.h b/sound/soc/rockchip/rockchip_spdif.h
index 07f86a2..3ef1277 100644
--- a/sound/soc/rockchip/rockchip_spdif.h
+++ b/sound/soc/rockchip/rockchip_spdif.h
@@ -28,9 +28,9 @@
#define SPDIF_CFGR_VDW(x) (x << SPDIF_CFGR_VDW_SHIFT)
#define SDPIF_CFGR_VDW_MASK (0xf << SPDIF_CFGR_VDW_SHIFT)
-#define SPDIF_CFGR_VDW_16 SPDIF_CFGR_VDW(0x00)
-#define SPDIF_CFGR_VDW_20 SPDIF_CFGR_VDW(0x01)
-#define SPDIF_CFGR_VDW_24 SPDIF_CFGR_VDW(0x10)
+#define SPDIF_CFGR_VDW_16 SPDIF_CFGR_VDW(0x0)
+#define SPDIF_CFGR_VDW_20 SPDIF_CFGR_VDW(0x1)
+#define SPDIF_CFGR_VDW_24 SPDIF_CFGR_VDW(0x2)
/*
* DMACR
@@ -42,7 +42,7 @@
#define SPDIF_DMACR_TDL_SHIFT 0
#define SPDIF_DMACR_TDL(x) ((x) << SPDIF_DMACR_TDL_SHIFT)
-#define SPDIF_DMACR_TDL_MASK (0x1f << SDPIF_DMACR_TDL_SHIFT)
+#define SPDIF_DMACR_TDL_MASK (0x1f << SPDIF_DMACR_TDL_SHIFT)
/*
* XFER
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index 76da762..edcf4cc 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -235,7 +235,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8),
RSND_GEN_S_REG(SCU_SYS_INT_EN0, 0x1cc),
RSND_GEN_S_REG(SCU_SYS_STATUS1, 0x1d0),
- RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1c4),
+ RSND_GEN_S_REG(SCU_SYS_INT_EN1, 0x1d4),
RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40),
RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40),
RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40),
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 261b502..68b439e 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -923,6 +923,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
struct snd_soc_pcm_runtime *rtd)
{
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret;
@@ -937,6 +938,12 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod,
return 0;
/*
+ * SRC In doesn't work if DVC was enabled
+ */
+ if (dvc && !rsnd_io_is_play(io))
+ return 0;
+
+ /*
* enable sync convert
*/
ret = rsnd_kctrl_new_s(mod, io, rtd,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 24b0960..a1305f8 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -795,12 +795,12 @@ static void soc_resume_deferred(struct work_struct *work)
dev_dbg(card->dev, "ASoC: resume work completed\n");
- /* userspace can access us now we are back as we were before */
- snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
-
/* Recheck all endpoints too, their state is affected by suspend */
dapm_mark_endpoints_dirty(card);
snd_soc_dapm_sync(&card->dapm);
+
+ /* userspace can access us now we are back as we were before */
+ snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
}
/* powers up audio subsystem after a suspend */
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index 016eba1..7d00942 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -2293,6 +2293,12 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w)
kfree(w);
}
+void snd_soc_dapm_reset_cache(struct snd_soc_dapm_context *dapm)
+{
+ dapm->path_sink_cache.widget = NULL;
+ dapm->path_source_cache.widget = NULL;
+}
+
/* free all dapm widgets and resources */
static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
{
@@ -2303,6 +2309,7 @@ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm)
continue;
snd_soc_dapm_free_widget(w);
}
+ snd_soc_dapm_reset_cache(dapm);
}
static struct snd_soc_dapm_widget *dapm_find_widget(
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
index ecd38e5..2f67ba6 100644
--- a/sound/soc/soc-ops.c
+++ b/sound/soc/soc-ops.c
@@ -404,7 +404,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
/**
* snd_soc_put_volsw_sx - double mixer set callback
* @kcontrol: mixer control
- * @uinfo: control element information
+ * @ucontrol: control element information
*
* Callback to set the value of a double mixer control that spans 2 registers.
*
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 8d7ec80..6963ba2 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -531,7 +531,7 @@ static int soc_tplg_kcontrol_bind_io(struct snd_soc_tplg_ctl_hdr *hdr,
/* TLV bytes controls need standard kcontrol info handler,
* TLV callback and extended put/get handlers.
*/
- k->info = snd_soc_bytes_info;
+ k->info = snd_soc_bytes_info_ext;
k->tlv.c = snd_soc_bytes_tlv_callback;
ext_ops = tplg->bytes_ext_ops;
@@ -1805,6 +1805,7 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
snd_soc_tplg_widget_remove(w);
snd_soc_dapm_free_widget(w);
}
+ snd_soc_dapm_reset_cache(dapm);
}
EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all);
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c
index 843f037..5c2bc53 100644
--- a/sound/soc/sti/uniperif_player.c
+++ b/sound/soc/sti/uniperif_player.c
@@ -669,6 +669,7 @@ static int uni_player_startup(struct snd_pcm_substream *substream,
{
struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai);
struct uniperif *player = priv->dai_data.uni;
+ player->substream = substream;
player->clk_adj = 0;
@@ -950,6 +951,8 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream,
if (player->state != UNIPERIF_STATE_STOPPED)
/* Stop the player */
uni_player_stop(player);
+
+ player->substream = NULL;
}
static int uni_player_parse_dt_clk_glue(struct platform_device *pdev,
@@ -989,7 +992,7 @@ static int uni_player_parse_dt(struct platform_device *pdev,
if (!info)
return -ENOMEM;
- if (of_property_read_u32(pnode, "version", &player->ver) ||
+ if (of_property_read_u32(pnode, "st,version", &player->ver) ||
player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
dev_err(dev, "Unknown uniperipheral version ");
return -EINVAL;
@@ -998,13 +1001,13 @@ static int uni_player_parse_dt(struct platform_device *pdev,
if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0)
info->underflow_enabled = 1;
- if (of_property_read_u32(pnode, "uniperiph-id", &info->id)) {
+ if (of_property_read_u32(pnode, "st,uniperiph-id", &info->id)) {
dev_err(dev, "uniperipheral id not defined");
return -EINVAL;
}
/* Read the device mode property */
- if (of_property_read_string(pnode, "mode", &mode)) {
+ if (of_property_read_string(pnode, "st,mode", &mode)) {
dev_err(dev, "uniperipheral mode not defined");
return -EINVAL;
}
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c
index f791239..8a0eb20 100644
--- a/sound/soc/sti/uniperif_reader.c
+++ b/sound/soc/sti/uniperif_reader.c
@@ -316,7 +316,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev,
if (!info)
return -ENOMEM;
- if (of_property_read_u32(node, "version", &reader->ver) ||
+ if (of_property_read_u32(node, "st,version", &reader->ver) ||
reader->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) {
dev_err(&pdev->dev, "Unknown uniperipheral version ");
return -EINVAL;
@@ -346,7 +346,6 @@ int uni_reader_init(struct platform_device *pdev,
reader->hw = &uni_reader_pcm_hw;
reader->dai_ops = &uni_reader_dai_ops;
- dev_err(reader->dev, "%s: enter\n", __func__);
ret = uni_reader_parse_dt(pdev, reader);
if (ret < 0) {
dev_err(reader->dev, "Failed to parse DeviceTree");
diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c
index bcbf4da..1bb896d 100644
--- a/sound/soc/sunxi/sun4i-codec.c
+++ b/sound/soc/sunxi/sun4i-codec.c
@@ -2,6 +2,7 @@
* Copyright 2014 Emilio López <emilio@elopez.com.ar>
* Copyright 2014 Jon Smirl <jonsmirl@gmail.com>
* Copyright 2015 Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Copyright 2015 Adam Sampson <ats@offog.org>
*
* Based on the Allwinner SDK driver, released under the GPL.
*
@@ -404,7 +405,7 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mute =
static DECLARE_TLV_DB_SCALE(sun4i_codec_pa_volume_scale, -6300, 100, 1);
static const struct snd_kcontrol_new sun4i_codec_widgets[] = {
- SOC_SINGLE_TLV("PA Volume", SUN4I_CODEC_DAC_ACTL,
+ SOC_SINGLE_TLV("Power Amplifier Volume", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_PA_VOL, 0x3F, 0,
sun4i_codec_pa_volume_scale),
};
@@ -452,12 +453,12 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL,
SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0),
- /* Pre-Amplifier */
- SND_SOC_DAPM_MIXER("Pre-Amplifier", SUN4I_CODEC_ADC_ACTL,
+ /* Power Amplifier */
+ SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL,
SUN4I_CODEC_ADC_ACTL_PA_EN, 0,
sun4i_codec_pa_mixer_controls,
ARRAY_SIZE(sun4i_codec_pa_mixer_controls)),
- SND_SOC_DAPM_SWITCH("Pre-Amplifier Mute", SND_SOC_NOPM, 0, 0,
+ SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0,
&sun4i_codec_pa_mute),
SND_SOC_DAPM_OUTPUT("HP Right"),
@@ -480,16 +481,16 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = {
{ "Left Mixer", NULL, "Mixer Enable" },
{ "Left Mixer", "Left DAC Playback Switch", "Left DAC" },
- /* Pre-Amplifier Mixer Routes */
- { "Pre-Amplifier", "Mixer Playback Switch", "Left Mixer" },
- { "Pre-Amplifier", "Mixer Playback Switch", "Right Mixer" },
- { "Pre-Amplifier", "DAC Playback Switch", "Left DAC" },
- { "Pre-Amplifier", "DAC Playback Switch", "Right DAC" },
+ /* Power Amplifier Routes */
+ { "Power Amplifier", "Mixer Playback Switch", "Left Mixer" },
+ { "Power Amplifier", "Mixer Playback Switch", "Right Mixer" },
+ { "Power Amplifier", "DAC Playback Switch", "Left DAC" },
+ { "Power Amplifier", "DAC Playback Switch", "Right DAC" },
- /* PA -> HP path */
- { "Pre-Amplifier Mute", "Switch", "Pre-Amplifier" },
- { "HP Right", NULL, "Pre-Amplifier Mute" },
- { "HP Left", NULL, "Pre-Amplifier Mute" },
+ /* Headphone Output Routes */
+ { "Power Amplifier Mute", "Switch", "Power Amplifier" },
+ { "HP Right", NULL, "Power Amplifier Mute" },
+ { "HP Left", NULL, "Power Amplifier Mute" },
};
static struct snd_soc_codec_driver sun4i_codec_codec = {
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 11e953a..99b73c6 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -655,7 +655,7 @@ static void cleanup_oss_soundcore(void)
static int __init init_oss_soundcore(void)
{
if (preclaim_oss &&
- register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) == -1) {
+ register_chrdev(SOUND_MAJOR, "sound", &soundcore_fops) < 0) {
printk(KERN_ERR "soundcore: sound device already in use.\n");
return -EBUSY;
}
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 7661616..5b4c58c 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -174,6 +174,8 @@ struct snd_usb_midi_in_endpoint {
u8 running_status_length;
} ports[0x10];
u8 seen_f5;
+ bool in_sysex;
+ u8 last_cin;
u8 error_resubmit;
int current_port;
};
@@ -468,6 +470,39 @@ static void snd_usbmidi_maudio_broken_running_status_input(
}
/*
+ * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4
+ * but the previously seen CIN, but still with three data bytes.
+ */
+static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
+ uint8_t *buffer, int buffer_length)
+{
+ unsigned int i, cin, length;
+
+ for (i = 0; i + 3 < buffer_length; i += 4) {
+ if (buffer[i] == 0 && i > 0)
+ break;
+ cin = buffer[i] & 0x0f;
+ if (ep->in_sysex &&
+ cin == ep->last_cin &&
+ (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0)
+ cin = 0x4;
+#if 0
+ if (buffer[i + 1] == 0x90) {
+ /*
+ * Either a corrupted running status or a real note-on
+ * message; impossible to detect reliably.
+ */
+ }
+#endif
+ length = snd_usbmidi_cin_length[cin];
+ snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length);
+ ep->in_sysex = cin == 0x4;
+ if (!ep->in_sysex)
+ ep->last_cin = cin;
+ }
+}
+
+/*
* CME protocol: like the standard protocol, but SysEx commands are sent as a
* single USB packet preceded by a 0x0F byte.
*/
@@ -660,6 +695,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
.output_packet = snd_usbmidi_output_standard_packet,
};
+static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+ .input = ch345_broken_sysex_input,
+ .output = snd_usbmidi_standard_output,
+ .output_packet = snd_usbmidi_output_standard_packet,
+};
+
/*
* AKAI MPD16 protocol:
*
@@ -1341,6 +1382,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi *umidi,
* Various chips declare a packet size larger than 4 bytes, but
* do not actually work with larger packets:
*/
+ case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */
case USB_ID(0x0a92, 0x1020): /* ESI M4U */
case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */
case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */
@@ -2378,6 +2420,10 @@ int snd_usbmidi_create(struct snd_card *card,
err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
break;
+ case QUIRK_MIDI_CH345:
+ umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops;
+ err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+ break;
default:
dev_err(&umidi->dev->dev, "invalid quirk type %d\n",
quirk->type);
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index f494dce..4f85757 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -1354,6 +1354,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
}
}
+ snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl);
+
range = (cval->max - cval->min) / cval->res;
/*
* Are there devices with volume range more than 255? I use a bit more
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index 6a803ef..ddca654 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -348,13 +348,6 @@ static struct usbmix_name_map bose_companion5_map[] = {
{ 0 } /* terminator */
};
-/* Dragonfly DAC 1.2, the dB conversion factor is 1 instead of 256 */
-static struct usbmix_dB_map dragonfly_1_2_dB = {0, 5000};
-static struct usbmix_name_map dragonfly_1_2_map[] = {
- { 7, NULL, .dB = &dragonfly_1_2_dB },
- { 0 } /* terminator */
-};
-
/*
* Control map entries
*/
@@ -470,11 +463,6 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.id = USB_ID(0x05a7, 0x1020),
.map = bose_companion5_map,
},
- {
- /* Dragonfly DAC 1.2 */
- .id = USB_ID(0x21b4, 0x0081),
- .map = dragonfly_1_2_map,
- },
{ 0 } /* terminator */
};
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index fe91184..0ce888d 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -37,6 +37,7 @@
#include <sound/control.h>
#include <sound/hwdep.h>
#include <sound/info.h>
+#include <sound/tlv.h>
#include "usbaudio.h"
#include "mixer.h"
@@ -1825,3 +1826,39 @@ void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
}
}
+static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
+{
+ /* Approximation using 10 ranges based on output measurement on hw v1.2.
+ * This seems close to the cubic mapping e.g. alsamixer uses. */
+ static const DECLARE_TLV_DB_RANGE(scale,
+ 0, 1, TLV_DB_MINMAX_ITEM(-5300, -4970),
+ 2, 5, TLV_DB_MINMAX_ITEM(-4710, -4160),
+ 6, 7, TLV_DB_MINMAX_ITEM(-3884, -3710),
+ 8, 14, TLV_DB_MINMAX_ITEM(-3443, -2560),
+ 15, 16, TLV_DB_MINMAX_ITEM(-2475, -2324),
+ 17, 19, TLV_DB_MINMAX_ITEM(-2228, -2031),
+ 20, 26, TLV_DB_MINMAX_ITEM(-1910, -1393),
+ 27, 31, TLV_DB_MINMAX_ITEM(-1322, -1032),
+ 32, 40, TLV_DB_MINMAX_ITEM(-968, -490),
+ 41, 50, TLV_DB_MINMAX_ITEM(-441, 0),
+ );
+
+ usb_audio_info(mixer->chip, "applying DragonFly dB scale quirk\n");
+ kctl->tlv.p = scale;
+ kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+ kctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
+}
+
+void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
+ struct usb_mixer_elem_info *cval, int unitid,
+ struct snd_kcontrol *kctl)
+{
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x21b4, 0x0081): /* AudioQuest DragonFly */
+ if (unitid == 7 && cval->min == 0 && cval->max == 50)
+ snd_dragonfly_quirk_db_scale(mixer, kctl);
+ break;
+ }
+}
+
diff --git a/sound/usb/mixer_quirks.h b/sound/usb/mixer_quirks.h
index bdbfab0..177c329 100644
--- a/sound/usb/mixer_quirks.h
+++ b/sound/usb/mixer_quirks.h
@@ -9,5 +9,9 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
int unitid);
+void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
+ struct usb_mixer_elem_info *cval, int unitid,
+ struct snd_kcontrol *kctl);
+
#endif /* SND_USB_MIXER_QUIRKS_H */
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 1a1e2e4..c60a776 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2829,6 +2829,17 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.idProduct = 0x1020,
},
+/* QinHeng devices */
+{
+ USB_DEVICE(0x1a86, 0x752d),
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .vendor_name = "QinHeng",
+ .product_name = "CH345",
+ .ifnum = 1,
+ .type = QUIRK_MIDI_CH345
+ }
+},
+
/* KeithMcMillen Stringport */
{
USB_DEVICE(0x1f38, 0x0001),
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 4897ea1..b6c0c8e 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -538,6 +538,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_MIDI_CME] = create_any_midi_quirk,
[QUIRK_MIDI_AKAI] = create_any_midi_quirk,
[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
+ [QUIRK_MIDI_CH345] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
@@ -1124,6 +1125,7 @@ bool snd_usb_get_sample_rate_quirk(struct snd_usb_audio *chip)
case USB_ID(0x045E, 0x0779): /* MS Lifecam HD-3000 */
case USB_ID(0x04D8, 0xFEEA): /* Benchmark DAC1 Pre */
case USB_ID(0x074D, 0x3553): /* Outlaw RR2150 (Micronas UAC3553B) */
+ case USB_ID(0x21B4, 0x0081): /* AudioQuest DragonFly */
return true;
}
return false;
@@ -1274,6 +1276,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */
case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */
+ case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */
if (fp->altsetting == 3)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 15a1271..b665d85 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -95,6 +95,7 @@ enum quirk_type {
QUIRK_MIDI_AKAI,
QUIRK_MIDI_US122L,
QUIRK_MIDI_FTDI,
+ QUIRK_MIDI_CH345,
QUIRK_AUDIO_STANDARD_INTERFACE,
QUIRK_AUDIO_FIXED_ENDPOINT,
QUIRK_AUDIO_EDIROL_UAXX,
diff --git a/tools/Makefile b/tools/Makefile
index d6f307d..0ba0df3 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -32,6 +32,10 @@ help:
@echo ' from the kernel command line to build and install one of'
@echo ' the tools above'
@echo ''
+ @echo ' $$ make tools/all'
+ @echo ''
+ @echo ' builds all tools.'
+ @echo ''
@echo ' $$ make tools/install'
@echo ''
@echo ' installs all tools.'
@@ -77,6 +81,11 @@ tmon: FORCE
freefall: FORCE
$(call descend,laptop/$@)
+all: acpi cgroup cpupower hv firewire lguest \
+ perf selftests turbostat usb \
+ virtio vm net x86_energy_perf_policy \
+ tmon freefall
+
acpi_install:
$(call descend,power/$(@:_install=),install)
@@ -87,7 +96,7 @@ cgroup_install firewire_install hv_install lguest_install perf_install usb_insta
$(call descend,$(@:_install=),install)
selftests_install:
- $(call descend,testing/$(@:_clean=),install)
+ $(call descend,testing/$(@:_install=),install)
turbostat_install x86_energy_perf_policy_install:
$(call descend,power/x86/$(@:_install=),install)
@@ -101,7 +110,7 @@ freefall_install:
install: acpi_install cgroup_install cpupower_install hv_install firewire_install lguest_install \
perf_install selftests_install turbostat_install usb_install \
virtio_install vm_install net_install x86_energy_perf_policy_install \
- tmon freefall_install
+ tmon_install freefall_install
acpi_clean:
$(call descend,power/acpi,clean)
diff --git a/tools/build/Makefile b/tools/build/Makefile
index a930362..0d5a0e3 100644
--- a/tools/build/Makefile
+++ b/tools/build/Makefile
@@ -25,7 +25,7 @@ export Q srctree CC LD
MAKEFLAGS := --no-print-directory
build := -f $(srctree)/tools/build/Makefile.build dir=. obj
-all: fixdep
+all: $(OUTPUT)fixdep
clean:
$(call QUIET_CLEAN, fixdep)
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature
index 37ff4c9..02db3cd 100644
--- a/tools/build/Makefile.feature
+++ b/tools/build/Makefile.feature
@@ -7,7 +7,7 @@ endif
feature_check = $(eval $(feature_check_code))
define feature_check_code
- feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
+ feature-$(1) := $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS) $(FEATURE_CHECK_CFLAGS-$(1))" LDFLAGS="$(LDFLAGS) $(FEATURE_CHECK_LDFLAGS-$(1))" -C $(feature_dir) $(OUTPUT_FEATURES)test-$1.bin >/dev/null 2>/dev/null && echo 1 || echo 0)
endef
feature_set = $(eval $(feature_set_code))
@@ -101,7 +101,6 @@ ifeq ($(feature-all), 1)
#
$(foreach feat,$(FEATURE_TESTS),$(call feature_set,$(feat)))
else
- $(shell $(MAKE) OUTPUT=$(OUTPUT_FEATURES) CFLAGS="$(EXTRA_CFLAGS)" LDFLAGS=$(LDFLAGS) -i -j -C $(feature_dir) $(addsuffix .bin,$(FEATURE_TESTS)) >/dev/null 2>&1)
$(foreach feat,$(FEATURE_TESTS),$(call feature_check,$(feat)))
endif
@@ -123,13 +122,31 @@ define feature_print_text_code
MSG = $(shell printf '...%30s: %s' $(1) $(2))
endef
+#
+# generates feature value assignment for name, like:
+# $(call feature_assign,dwarf) == feature-dwarf=1
+#
+feature_assign = feature-$(1)=$(feature-$(1))
+
FEATURE_DUMP_FILENAME = $(OUTPUT)FEATURE-DUMP$(FEATURE_USER)
-FEATURE_DUMP := $(foreach feat,$(FEATURE_DISPLAY),feature-$(feat)($(feature-$(feat))))
-FEATURE_DUMP_FILE := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
+FEATURE_DUMP := $(shell touch $(FEATURE_DUMP_FILENAME); cat $(FEATURE_DUMP_FILENAME))
-ifeq ($(dwarf-post-unwind),1)
- FEATURE_DUMP += dwarf-post-unwind($(dwarf-post-unwind-text))
-endif
+feature_dump_check = $(eval $(feature_dump_check_code))
+define feature_dump_check_code
+ ifeq ($(findstring $(1),$(FEATURE_DUMP)),)
+ $(2) := 1
+ endif
+endef
+
+#
+# First check if any test from FEATURE_DISPLAY
+# and set feature_display := 1 if it does
+$(foreach feat,$(FEATURE_DISPLAY),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_display))
+
+#
+# Now also check if any other test changed,
+# so we force FEATURE-DUMP generation
+$(foreach feat,$(FEATURE_TESTS),$(call feature_dump_check,$(call feature_assign,$(feat)),feature_dump_changed))
# The $(feature_display) controls the default detection message
# output. It's set if:
@@ -138,13 +155,13 @@ endif
# - one of the $(FEATURE_DISPLAY) is not detected
# - VF is enabled
-ifneq ("$(FEATURE_DUMP)","$(FEATURE_DUMP_FILE)")
- $(shell echo "$(FEATURE_DUMP)" > $(FEATURE_DUMP_FILENAME))
- feature_display := 1
+ifeq ($(feature_dump_changed),1)
+ $(shell rm -f $(FEATURE_DUMP_FILENAME))
+ $(foreach feat,$(FEATURE_TESTS),$(shell echo "$(call feature_assign,$(feat))" >> $(FEATURE_DUMP_FILENAME)))
endif
feature_display_check = $(eval $(feature_check_display_code))
-define feature_display_check_code
+define feature_check_display_code
ifneq ($(feature-$(1)), 1)
feature_display := 1
endif
@@ -161,11 +178,6 @@ ifeq ($(feature_display),1)
$(info )
$(info Auto-detecting system features:)
$(foreach feat,$(FEATURE_DISPLAY),$(call feature_print_status,$(feat),))
-
- ifeq ($(dwarf-post-unwind),1)
- $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
- endif
-
ifneq ($(feature_verbose),1)
$(info )
endif
diff --git a/tools/build/Makefile.include b/tools/build/Makefile.include
index 4e09ad6..be630be 100644
--- a/tools/build/Makefile.include
+++ b/tools/build/Makefile.include
@@ -4,7 +4,7 @@ ifdef CROSS_COMPILE
fixdep:
else
fixdep:
- $(Q)$(MAKE) -C $(srctree)/tools/build fixdep
+ $(Q)$(MAKE) -C $(srctree)/tools/build CFLAGS= LDFLAGS= $(OUTPUT)fixdep
endif
.PHONY: fixdep
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index cea04ce9..bf8f035 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -1,4 +1,3 @@
-
FILES= \
test-all.bin \
test-backtrace.bin \
@@ -38,38 +37,40 @@ FILES= \
test-bpf.bin \
test-get_cpuid.bin
+FILES := $(addprefix $(OUTPUT),$(FILES))
+
CC := $(CROSS_COMPILE)gcc -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
all: $(FILES)
-__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
- BUILD = $(__BUILD) > $(OUTPUT)$(@:.bin=.make.output) 2>&1
+__BUILD = $(CC) $(CFLAGS) -Wall -Werror -o $@ $(patsubst %.bin,%.c,$(@F)) $(LDFLAGS)
+ BUILD = $(__BUILD) > $(@:.bin=.make.output) 2>&1
###############################
-test-all.bin:
+$(OUTPUT)test-all.bin:
$(BUILD) -fstack-protector-all -O2 -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz -llzma
-test-hello.bin:
+$(OUTPUT)test-hello.bin:
$(BUILD)
-test-pthread-attr-setaffinity-np.bin:
+$(OUTPUT)test-pthread-attr-setaffinity-np.bin:
$(BUILD) -D_GNU_SOURCE -lpthread
-test-stackprotector-all.bin:
+$(OUTPUT)test-stackprotector-all.bin:
$(BUILD) -fstack-protector-all
-test-fortify-source.bin:
+$(OUTPUT)test-fortify-source.bin:
$(BUILD) -O2 -D_FORTIFY_SOURCE=2
-test-bionic.bin:
+$(OUTPUT)test-bionic.bin:
$(BUILD)
-test-libelf.bin:
+$(OUTPUT)test-libelf.bin:
$(BUILD) -lelf
-test-glibc.bin:
+$(OUTPUT)test-glibc.bin:
$(BUILD)
DWARFLIBS := -ldw
@@ -77,37 +78,37 @@ ifeq ($(findstring -static,${LDFLAGS}),-static)
DWARFLIBS += -lelf -lebl -lz -llzma -lbz2
endif
-test-dwarf.bin:
+$(OUTPUT)test-dwarf.bin:
$(BUILD) $(DWARFLIBS)
-test-libelf-mmap.bin:
+$(OUTPUT)test-libelf-mmap.bin:
$(BUILD) -lelf
-test-libelf-getphdrnum.bin:
+$(OUTPUT)test-libelf-getphdrnum.bin:
$(BUILD) -lelf
-test-libnuma.bin:
+$(OUTPUT)test-libnuma.bin:
$(BUILD) -lnuma
-test-numa_num_possible_cpus.bin:
+$(OUTPUT)test-numa_num_possible_cpus.bin:
$(BUILD) -lnuma
-test-libunwind.bin:
+$(OUTPUT)test-libunwind.bin:
$(BUILD) -lelf
-test-libunwind-debug-frame.bin:
+$(OUTPUT)test-libunwind-debug-frame.bin:
$(BUILD) -lelf
-test-libaudit.bin:
+$(OUTPUT)test-libaudit.bin:
$(BUILD) -laudit
-test-libslang.bin:
+$(OUTPUT)test-libslang.bin:
$(BUILD) -I/usr/include/slang -lslang
-test-gtk2.bin:
+$(OUTPUT)test-gtk2.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
-test-gtk2-infobar.bin:
+$(OUTPUT)test-gtk2-infobar.bin:
$(BUILD) $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null)
grep-libs = $(filter -l%,$(1))
@@ -119,63 +120,63 @@ PERL_EMBED_LIBADD = $(call grep-libs,$(PERL_EMBED_LDOPTS))
PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null`
FLAGS_PERL_EMBED=$(PERL_EMBED_CCOPTS) $(PERL_EMBED_LDOPTS)
-test-libperl.bin:
+$(OUTPUT)test-libperl.bin:
$(BUILD) $(FLAGS_PERL_EMBED)
-test-libpython.bin:
+$(OUTPUT)test-libpython.bin:
$(BUILD)
-test-libpython-version.bin:
+$(OUTPUT)test-libpython-version.bin:
$(BUILD)
-test-libbfd.bin:
+$(OUTPUT)test-libbfd.bin:
$(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl
-test-liberty.bin:
- $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
+$(OUTPUT)test-liberty.bin:
+ $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty
-test-liberty-z.bin:
- $(CC) $(CFLAGS) -Wall -Werror -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
+$(OUTPUT)test-liberty-z.bin:
+ $(CC) $(CFLAGS) -Wall -Werror -o $@ test-libbfd.c -DPACKAGE='"perf"' $(LDFLAGS) -lbfd -ldl -liberty -lz
-test-cplus-demangle.bin:
+$(OUTPUT)test-cplus-demangle.bin:
$(BUILD) -liberty
-test-backtrace.bin:
+$(OUTPUT)test-backtrace.bin:
$(BUILD)
-test-timerfd.bin:
+$(OUTPUT)test-timerfd.bin:
$(BUILD)
-test-libdw-dwarf-unwind.bin:
+$(OUTPUT)test-libdw-dwarf-unwind.bin:
$(BUILD) # -ldw provided by $(FEATURE_CHECK_LDFLAGS-libdw-dwarf-unwind)
-test-libbabeltrace.bin:
+$(OUTPUT)test-libbabeltrace.bin:
$(BUILD) # -lbabeltrace provided by $(FEATURE_CHECK_LDFLAGS-libbabeltrace)
-test-sync-compare-and-swap.bin:
+$(OUTPUT)test-sync-compare-and-swap.bin:
$(BUILD)
-test-compile-32.bin:
- $(CC) -m32 -o $(OUTPUT)$@ test-compile.c
+$(OUTPUT)test-compile-32.bin:
+ $(CC) -m32 -o $@ test-compile.c
-test-compile-x32.bin:
- $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+$(OUTPUT)test-compile-x32.bin:
+ $(CC) -mx32 -o $@ test-compile.c
-test-zlib.bin:
+$(OUTPUT)test-zlib.bin:
$(BUILD) -lz
-test-lzma.bin:
+$(OUTPUT)test-lzma.bin:
$(BUILD) -llzma
-test-get_cpuid.bin:
+$(OUTPUT)test-get_cpuid.bin:
$(BUILD)
-test-bpf.bin:
+$(OUTPUT)test-bpf.bin:
$(BUILD)
--include *.d
+-include $(OUTPUT)*.d
###############################
clean:
- rm -f $(FILES) *.d $(FILES:.bin=.make.output)
+ rm -f $(FILES) $(OUTPUT)*.d $(FILES:.bin=.make.output)
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/include/linux/bitmap.h
index 40bd214..28f5493 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/include/linux/bitmap.h
@@ -11,6 +11,8 @@ int __bitmap_weight(const unsigned long *bitmap, int bits);
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, int bits);
+#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
+
#define BITMAP_LAST_WORD_MASK(nbits) \
( \
((nbits) % BITS_PER_LONG) ? \
diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h
index 76b014c..a017f15 100644
--- a/tools/include/linux/list.h
+++ b/tools/include/linux/list.h
@@ -1,3 +1,4 @@
+#include <linux/compiler.h>
#include <linux/kernel.h>
#include <linux/types.h>
diff --git a/tools/include/linux/string.h b/tools/include/linux/string.h
new file mode 100644
index 0000000..e26223f
--- /dev/null
+++ b/tools/include/linux/string.h
@@ -0,0 +1,15 @@
+#ifndef _TOOLS_LINUX_STRING_H_
+#define _TOOLS_LINUX_STRING_H_
+
+
+#include <linux/types.h> /* for size_t */
+
+void *memdup(const void *src, size_t len);
+
+int strtobool(const char *s, bool *res);
+
+#ifndef __UCLIBC__
+extern size_t strlcpy(char *dest, const char *src, size_t size);
+#endif
+
+#endif /* _LINUX_STRING_H_ */
diff --git a/tools/perf/util/bitmap.c b/tools/lib/bitmap.c
index 0a1adc1..0a1adc1 100644
--- a/tools/perf/util/bitmap.c
+++ b/tools/lib/bitmap.c
diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore
index 812aeed..f81e549 100644
--- a/tools/lib/bpf/.gitignore
+++ b/tools/lib/bpf/.gitignore
@@ -1,2 +1,2 @@
libbpf_version.h
-FEATURE-DUMP
+FEATURE-DUMP.libbpf
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile
index fc9af57..919b717 100644
--- a/tools/lib/bpf/Makefile
+++ b/tools/lib/bpf/Makefile
@@ -71,7 +71,21 @@ FEATURE_DISPLAY = libelf bpf
INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi
FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES)
+check_feat := 1
+NON_CHECK_FEAT_TARGETS := clean TAGS tags cscope help
+ifdef MAKECMDGOALS
+ifeq ($(filter-out $(NON_CHECK_FEAT_TARGETS),$(MAKECMDGOALS)),)
+ check_feat := 0
+endif
+endif
+
+ifeq ($(check_feat),1)
+ifeq ($(FEATURES_DUMP),)
include $(srctree)/tools/build/Makefile.feature
+else
+include $(FEATURES_DUMP)
+endif
+endif
export prefix libdir src obj
@@ -180,7 +194,7 @@ config-clean:
clean:
$(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \
$(RM) LIBBPF-CFLAGS
- $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP
+ $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP.libbpf
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c
index a633105..5bdc6ea 100644
--- a/tools/lib/bpf/bpf.c
+++ b/tools/lib/bpf/bpf.c
@@ -83,3 +83,17 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
log_buf[0] = 0;
return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr));
}
+
+int bpf_map_update_elem(int fd, void *key, void *value,
+ u64 flags)
+{
+ union bpf_attr attr;
+
+ bzero(&attr, sizeof(attr));
+ attr.map_fd = fd;
+ attr.key = ptr_to_u64(key);
+ attr.value = ptr_to_u64(value);
+ attr.flags = flags;
+
+ return sys_bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
+}
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h
index 854b736..a764655 100644
--- a/tools/lib/bpf/bpf.h
+++ b/tools/lib/bpf/bpf.h
@@ -20,4 +20,6 @@ int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns,
u32 kern_version, char *log_buf,
size_t log_buf_sz);
+int bpf_map_update_elem(int fd, void *key, void *value,
+ u64 flags);
#endif
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4252fc2..8334a5a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -61,6 +61,60 @@ void libbpf_set_print(libbpf_print_fn_t warn,
__pr_debug = debug;
}
+#define STRERR_BUFSIZE 128
+
+#define ERRNO_OFFSET(e) ((e) - __LIBBPF_ERRNO__START)
+#define ERRCODE_OFFSET(c) ERRNO_OFFSET(LIBBPF_ERRNO__##c)
+#define NR_ERRNO (__LIBBPF_ERRNO__END - __LIBBPF_ERRNO__START)
+
+static const char *libbpf_strerror_table[NR_ERRNO] = {
+ [ERRCODE_OFFSET(LIBELF)] = "Something wrong in libelf",
+ [ERRCODE_OFFSET(FORMAT)] = "BPF object format invalid",
+ [ERRCODE_OFFSET(KVERSION)] = "'version' section incorrect or lost",
+ [ERRCODE_OFFSET(ENDIAN)] = "Endian missmatch",
+ [ERRCODE_OFFSET(INTERNAL)] = "Internal error in libbpf",
+ [ERRCODE_OFFSET(RELOC)] = "Relocation failed",
+ [ERRCODE_OFFSET(VERIFY)] = "Kernel verifier blocks program loading",
+ [ERRCODE_OFFSET(PROG2BIG)] = "Program too big",
+ [ERRCODE_OFFSET(KVER)] = "Incorrect kernel version",
+};
+
+int libbpf_strerror(int err, char *buf, size_t size)
+{
+ if (!buf || !size)
+ return -1;
+
+ err = err > 0 ? err : -err;
+
+ if (err < __LIBBPF_ERRNO__START) {
+ int ret;
+
+ ret = strerror_r(err, buf, size);
+ buf[size - 1] = '\0';
+ return ret;
+ }
+
+ if (err < __LIBBPF_ERRNO__END) {
+ const char *msg;
+
+ msg = libbpf_strerror_table[ERRNO_OFFSET(err)];
+ snprintf(buf, size, "%s", msg);
+ buf[size - 1] = '\0';
+ return 0;
+ }
+
+ snprintf(buf, size, "Unknown libbpf error %d", err);
+ buf[size - 1] = '\0';
+ return -1;
+}
+
+#define CHECK_ERR(action, err, out) do { \
+ err = action; \
+ if (err) \
+ goto out; \
+} while(0)
+
+
/* Copied from tools/perf/util/util.h */
#ifndef zfree
# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
@@ -98,29 +152,36 @@ struct bpf_program {
} *reloc_desc;
int nr_reloc;
- int fd;
+ struct {
+ int nr;
+ int *fds;
+ } instances;
+ bpf_program_prep_t preprocessor;
struct bpf_object *obj;
void *priv;
bpf_program_clear_priv_t clear_priv;
};
+struct bpf_map {
+ int fd;
+ char *name;
+ struct bpf_map_def def;
+ void *priv;
+ bpf_map_clear_priv_t clear_priv;
+};
+
static LIST_HEAD(bpf_objects_list);
struct bpf_object {
char license[64];
u32 kern_version;
- void *maps_buf;
- size_t maps_buf_sz;
struct bpf_program *programs;
size_t nr_programs;
- int *map_fds;
- /*
- * This field is required because maps_buf will be freed and
- * maps_buf_sz will be set to 0 after loaded.
- */
- size_t nr_map_fds;
+ struct bpf_map *maps;
+ size_t nr_maps;
+
bool loaded;
/*
@@ -134,6 +195,7 @@ struct bpf_object {
Elf *elf;
GElf_Ehdr ehdr;
Elf_Data *symbols;
+ size_t strtabidx;
struct {
GElf_Shdr shdr;
Elf_Data *data;
@@ -152,10 +214,25 @@ struct bpf_object {
static void bpf_program__unload(struct bpf_program *prog)
{
+ int i;
+
if (!prog)
return;
- zclose(prog->fd);
+ /*
+ * If the object is opened but the program was never loaded,
+ * it is possible that prog->instances.nr == -1.
+ */
+ if (prog->instances.nr > 0) {
+ for (i = 0; i < prog->instances.nr; i++)
+ zclose(prog->instances.fds[i]);
+ } else if (prog->instances.nr != -1) {
+ pr_warning("Internal error: instances.nr is %d\n",
+ prog->instances.nr);
+ }
+
+ prog->instances.nr = -1;
+ zfree(&prog->instances.fds);
}
static void bpf_program__exit(struct bpf_program *prog)
@@ -206,7 +283,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
memcpy(prog->insns, data,
prog->insns_cnt * sizeof(struct bpf_insn));
prog->idx = idx;
- prog->fd = -1;
+ prog->instances.fds = NULL;
+ prog->instances.nr = -1;
return 0;
errout:
@@ -258,7 +336,7 @@ static struct bpf_object *bpf_object__new(const char *path,
obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
if (!obj) {
pr_warning("alloc memory failed for %s\n", path);
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
strcpy(obj->path, path);
@@ -305,7 +383,7 @@ static int bpf_object__elf_init(struct bpf_object *obj)
if (obj_elf_valid(obj)) {
pr_warning("elf init: internal error\n");
- return -EEXIST;
+ return -LIBBPF_ERRNO__LIBELF;
}
if (obj->efile.obj_buf_sz > 0) {
@@ -331,14 +409,14 @@ static int bpf_object__elf_init(struct bpf_object *obj)
if (!obj->efile.elf) {
pr_warning("failed to open %s as ELF file\n",
obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__LIBELF;
goto errout;
}
if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
pr_warning("failed to get EHDR from %s\n",
obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__FORMAT;
goto errout;
}
ep = &obj->efile.ehdr;
@@ -346,7 +424,7 @@ static int bpf_object__elf_init(struct bpf_object *obj)
if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
pr_warning("%s is not an eBPF object file\n",
obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__FORMAT;
goto errout;
}
@@ -374,14 +452,14 @@ bpf_object__check_endianness(struct bpf_object *obj)
goto mismatch;
break;
default:
- return -EINVAL;
+ return -LIBBPF_ERRNO__ENDIAN;
}
return 0;
mismatch:
pr_warning("Error: endianness mismatch.\n");
- return -EINVAL;
+ return -LIBBPF_ERRNO__ENDIAN;
}
static int
@@ -402,7 +480,7 @@ bpf_object__init_kversion(struct bpf_object *obj,
if (size != sizeof(kver)) {
pr_warning("invalid kver section in %s\n", obj->path);
- return -EINVAL;
+ return -LIBBPF_ERRNO__FORMAT;
}
memcpy(&kver, data, sizeof(kver));
obj->kern_version = kver;
@@ -415,21 +493,77 @@ static int
bpf_object__init_maps(struct bpf_object *obj, void *data,
size_t size)
{
- if (size == 0) {
+ size_t nr_maps;
+ int i;
+
+ nr_maps = size / sizeof(struct bpf_map_def);
+ if (!data || !nr_maps) {
pr_debug("%s doesn't need map definition\n",
obj->path);
return 0;
}
- obj->maps_buf = malloc(size);
- if (!obj->maps_buf) {
- pr_warning("malloc maps failed: %s\n", obj->path);
+ pr_debug("maps in %s: %zd bytes\n", obj->path, size);
+
+ obj->maps = calloc(nr_maps, sizeof(obj->maps[0]));
+ if (!obj->maps) {
+ pr_warning("alloc maps for object failed\n");
return -ENOMEM;
}
+ obj->nr_maps = nr_maps;
- obj->maps_buf_sz = size;
- memcpy(obj->maps_buf, data, size);
- pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size);
+ for (i = 0; i < nr_maps; i++) {
+ struct bpf_map_def *def = &obj->maps[i].def;
+
+ /*
+ * fill all fd with -1 so won't close incorrect
+ * fd (fd=0 is stdin) when failure (zclose won't close
+ * negative fd)).
+ */
+ obj->maps[i].fd = -1;
+
+ /* Save map definition into obj->maps */
+ *def = ((struct bpf_map_def *)data)[i];
+ }
+ return 0;
+}
+
+static int
+bpf_object__init_maps_name(struct bpf_object *obj, int maps_shndx)
+{
+ int i;
+ Elf_Data *symbols = obj->efile.symbols;
+
+ if (!symbols || maps_shndx < 0)
+ return -EINVAL;
+
+ for (i = 0; i < symbols->d_size / sizeof(GElf_Sym); i++) {
+ GElf_Sym sym;
+ size_t map_idx;
+ const char *map_name;
+
+ if (!gelf_getsym(symbols, i, &sym))
+ continue;
+ if (sym.st_shndx != maps_shndx)
+ continue;
+
+ map_name = elf_strptr(obj->efile.elf,
+ obj->efile.strtabidx,
+ sym.st_name);
+ map_idx = sym.st_value / sizeof(struct bpf_map_def);
+ if (map_idx >= obj->nr_maps) {
+ pr_warning("index of map \"%s\" is buggy: %zu > %zu\n",
+ map_name, map_idx, obj->nr_maps);
+ continue;
+ }
+ obj->maps[map_idx].name = strdup(map_name);
+ if (!obj->maps[map_idx].name) {
+ pr_warning("failed to alloc map name\n");
+ return -ENOMEM;
+ }
+ pr_debug("map %zu is \"%s\"\n", map_idx,
+ obj->maps[map_idx].name);
+ }
return 0;
}
@@ -438,13 +572,13 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
Elf *elf = obj->efile.elf;
GElf_Ehdr *ep = &obj->efile.ehdr;
Elf_Scn *scn = NULL;
- int idx = 0, err = 0;
+ int idx = 0, err = 0, maps_shndx = -1;
/* Elf is corrupted/truncated, avoid calling elf_strptr. */
if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) {
pr_warning("failed to get e_shstrndx from %s\n",
obj->path);
- return -EINVAL;
+ return -LIBBPF_ERRNO__FORMAT;
}
while ((scn = elf_nextscn(elf, scn)) != NULL) {
@@ -456,7 +590,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
if (gelf_getshdr(scn, &sh) != &sh) {
pr_warning("failed to get section header from %s\n",
obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__FORMAT;
goto out;
}
@@ -464,7 +598,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
if (!name) {
pr_warning("failed to get section name from %s\n",
obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__FORMAT;
goto out;
}
@@ -472,7 +606,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
if (!data) {
pr_warning("failed to get section data from %s(%s)\n",
name, obj->path);
- err = -EINVAL;
+ err = -LIBBPF_ERRNO__FORMAT;
goto out;
}
pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n",
@@ -488,23 +622,27 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
err = bpf_object__init_kversion(obj,
data->d_buf,
data->d_size);
- else if (strcmp(name, "maps") == 0)
+ else if (strcmp(name, "maps") == 0) {
err = bpf_object__init_maps(obj, data->d_buf,
data->d_size);
- else if (sh.sh_type == SHT_SYMTAB) {
+ maps_shndx = idx;
+ } else if (sh.sh_type == SHT_SYMTAB) {
if (obj->efile.symbols) {
pr_warning("bpf: multiple SYMTAB in %s\n",
obj->path);
- err = -EEXIST;
- } else
+ err = -LIBBPF_ERRNO__FORMAT;
+ } else {
obj->efile.symbols = data;
+ obj->efile.strtabidx = sh.sh_link;
+ }
} else if ((sh.sh_type == SHT_PROGBITS) &&
(sh.sh_flags & SHF_EXECINSTR) &&
(data->d_size > 0)) {
err = bpf_object__add_program(obj, data->d_buf,
data->d_size, name, idx);
if (err) {
- char errmsg[128];
+ char errmsg[STRERR_BUFSIZE];
+
strerror_r(-err, errmsg, sizeof(errmsg));
pr_warning("failed to alloc program %s (%s): %s",
name, obj->path, errmsg);
@@ -531,6 +669,13 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
if (err)
goto out;
}
+
+ if (!obj->efile.strtabidx || obj->efile.strtabidx >= idx) {
+ pr_warning("Corrupted ELF file: index of strtab invalid\n");
+ return LIBBPF_ERRNO__FORMAT;
+ }
+ if (maps_shndx >= 0)
+ err = bpf_object__init_maps_name(obj, maps_shndx);
out:
return err;
}
@@ -576,7 +721,7 @@ bpf_program__collect_reloc(struct bpf_program *prog,
if (!gelf_getrel(data, i, &rel)) {
pr_warning("relocation: failed to get %d reloc\n", i);
- return -EINVAL;
+ return -LIBBPF_ERRNO__FORMAT;
}
insn_idx = rel.r_offset / sizeof(struct bpf_insn);
@@ -587,20 +732,20 @@ bpf_program__collect_reloc(struct bpf_program *prog,
&sym)) {
pr_warning("relocation: symbol %"PRIx64" not found\n",
GELF_R_SYM(rel.r_info));
- return -EINVAL;
+ return -LIBBPF_ERRNO__FORMAT;
}
if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
insn_idx, insns[insn_idx].code);
- return -EINVAL;
+ return -LIBBPF_ERRNO__RELOC;
}
map_idx = sym.st_value / sizeof(struct bpf_map_def);
if (map_idx >= nr_maps) {
pr_warning("bpf relocation: map_idx %d large than %d\n",
(int)map_idx, (int)nr_maps - 1);
- return -EINVAL;
+ return -LIBBPF_ERRNO__RELOC;
}
prog->reloc_desc[i].insn_idx = insn_idx;
@@ -613,37 +758,15 @@ static int
bpf_object__create_maps(struct bpf_object *obj)
{
unsigned int i;
- size_t nr_maps;
- int *pfd;
- nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def);
- if (!obj->maps_buf || !nr_maps) {
- pr_debug("don't need create maps for %s\n",
- obj->path);
- return 0;
- }
+ for (i = 0; i < obj->nr_maps; i++) {
+ struct bpf_map_def *def = &obj->maps[i].def;
+ int *pfd = &obj->maps[i].fd;
- obj->map_fds = malloc(sizeof(int) * nr_maps);
- if (!obj->map_fds) {
- pr_warning("realloc perf_bpf_map_fds failed\n");
- return -ENOMEM;
- }
- obj->nr_map_fds = nr_maps;
-
- /* fill all fd with -1 */
- memset(obj->map_fds, -1, sizeof(int) * nr_maps);
-
- pfd = obj->map_fds;
- for (i = 0; i < nr_maps; i++) {
- struct bpf_map_def def;
-
- def = *(struct bpf_map_def *)(obj->maps_buf +
- i * sizeof(struct bpf_map_def));
-
- *pfd = bpf_create_map(def.type,
- def.key_size,
- def.value_size,
- def.max_entries);
+ *pfd = bpf_create_map(def->type,
+ def->key_size,
+ def->value_size,
+ def->max_entries);
if (*pfd < 0) {
size_t j;
int err = *pfd;
@@ -651,22 +774,17 @@ bpf_object__create_maps(struct bpf_object *obj)
pr_warning("failed to create map: %s\n",
strerror(errno));
for (j = 0; j < i; j++)
- zclose(obj->map_fds[j]);
- obj->nr_map_fds = 0;
- zfree(&obj->map_fds);
+ zclose(obj->maps[j].fd);
return err;
}
pr_debug("create map: fd=%d\n", *pfd);
- pfd++;
}
- zfree(&obj->maps_buf);
- obj->maps_buf_sz = 0;
return 0;
}
static int
-bpf_program__relocate(struct bpf_program *prog, int *map_fds)
+bpf_program__relocate(struct bpf_program *prog, struct bpf_object *obj)
{
int i;
@@ -683,10 +801,10 @@ bpf_program__relocate(struct bpf_program *prog, int *map_fds)
if (insn_idx >= (int)prog->insns_cnt) {
pr_warning("relocation out of range: '%s'\n",
prog->section_name);
- return -ERANGE;
+ return -LIBBPF_ERRNO__RELOC;
}
insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
- insns[insn_idx].imm = map_fds[map_idx];
+ insns[insn_idx].imm = obj->maps[map_idx].fd;
}
zfree(&prog->reloc_desc);
@@ -705,7 +823,7 @@ bpf_object__relocate(struct bpf_object *obj)
for (i = 0; i < obj->nr_programs; i++) {
prog = &obj->programs[i];
- err = bpf_program__relocate(prog, obj->map_fds);
+ err = bpf_program__relocate(prog, obj);
if (err) {
pr_warning("failed to relocate '%s'\n",
prog->section_name);
@@ -721,7 +839,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
if (!obj_elf_valid(obj)) {
pr_warning("Internal error: elf object is closed\n");
- return -EINVAL;
+ return -LIBBPF_ERRNO__INTERNAL;
}
for (i = 0; i < obj->efile.nr_reloc; i++) {
@@ -729,26 +847,25 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
Elf_Data *data = obj->efile.reloc[i].data;
int idx = shdr->sh_info;
struct bpf_program *prog;
- size_t nr_maps = obj->maps_buf_sz /
- sizeof(struct bpf_map_def);
+ size_t nr_maps = obj->nr_maps;
if (shdr->sh_type != SHT_REL) {
pr_warning("internal error at %d\n", __LINE__);
- return -EINVAL;
+ return -LIBBPF_ERRNO__INTERNAL;
}
prog = bpf_object__find_prog_by_idx(obj, idx);
if (!prog) {
pr_warning("relocation failed: no %d section\n",
idx);
- return -ENOENT;
+ return -LIBBPF_ERRNO__RELOC;
}
err = bpf_program__collect_reloc(prog, nr_maps,
shdr, data,
obj->efile.symbols);
if (err)
- return -EINVAL;
+ return err;
}
return 0;
}
@@ -777,13 +894,23 @@ load_program(struct bpf_insn *insns, int insns_cnt,
goto out;
}
- ret = -EINVAL;
+ ret = -LIBBPF_ERRNO__LOAD;
pr_warning("load bpf program failed: %s\n", strerror(errno));
- if (log_buf) {
+ if (log_buf && log_buf[0] != '\0') {
+ ret = -LIBBPF_ERRNO__VERIFY;
pr_warning("-- BEGIN DUMP LOG ---\n");
pr_warning("\n%s\n", log_buf);
pr_warning("-- END LOG --\n");
+ } else {
+ if (insns_cnt >= BPF_MAXINSNS) {
+ pr_warning("Program too large (%d insns), at most %d insns\n",
+ insns_cnt, BPF_MAXINSNS);
+ ret = -LIBBPF_ERRNO__PROG2BIG;
+ } else if (log_buf) {
+ pr_warning("log buffer is empty\n");
+ ret = -LIBBPF_ERRNO__KVER;
+ }
}
out:
@@ -795,13 +922,73 @@ static int
bpf_program__load(struct bpf_program *prog,
char *license, u32 kern_version)
{
- int err, fd;
+ int err = 0, fd, i;
- err = load_program(prog->insns, prog->insns_cnt,
- license, kern_version, &fd);
- if (!err)
- prog->fd = fd;
+ if (prog->instances.nr < 0 || !prog->instances.fds) {
+ if (prog->preprocessor) {
+ pr_warning("Internal error: can't load program '%s'\n",
+ prog->section_name);
+ return -LIBBPF_ERRNO__INTERNAL;
+ }
+
+ prog->instances.fds = malloc(sizeof(int));
+ if (!prog->instances.fds) {
+ pr_warning("Not enough memory for BPF fds\n");
+ return -ENOMEM;
+ }
+ prog->instances.nr = 1;
+ prog->instances.fds[0] = -1;
+ }
+
+ if (!prog->preprocessor) {
+ if (prog->instances.nr != 1) {
+ pr_warning("Program '%s' is inconsistent: nr(%d) != 1\n",
+ prog->section_name, prog->instances.nr);
+ }
+ err = load_program(prog->insns, prog->insns_cnt,
+ license, kern_version, &fd);
+ if (!err)
+ prog->instances.fds[0] = fd;
+ goto out;
+ }
+
+ for (i = 0; i < prog->instances.nr; i++) {
+ struct bpf_prog_prep_result result;
+ bpf_program_prep_t preprocessor = prog->preprocessor;
+
+ bzero(&result, sizeof(result));
+ err = preprocessor(prog, i, prog->insns,
+ prog->insns_cnt, &result);
+ if (err) {
+ pr_warning("Preprocessing the %dth instance of program '%s' failed\n",
+ i, prog->section_name);
+ goto out;
+ }
+
+ if (!result.new_insn_ptr || !result.new_insn_cnt) {
+ pr_debug("Skip loading the %dth instance of program '%s'\n",
+ i, prog->section_name);
+ prog->instances.fds[i] = -1;
+ if (result.pfd)
+ *result.pfd = -1;
+ continue;
+ }
+
+ err = load_program(result.new_insn_ptr,
+ result.new_insn_cnt,
+ license, kern_version, &fd);
+
+ if (err) {
+ pr_warning("Loading the %dth instance of program '%s' failed\n",
+ i, prog->section_name);
+ goto out;
+ }
+ if (result.pfd)
+ *result.pfd = fd;
+ prog->instances.fds[i] = fd;
+ }
+out:
if (err)
pr_warning("failed to load program '%s'\n",
prog->section_name);
@@ -831,7 +1018,7 @@ static int bpf_object__validate(struct bpf_object *obj)
if (obj->kern_version == 0) {
pr_warning("%s doesn't provide kernel version\n",
obj->path);
- return -EINVAL;
+ return -LIBBPF_ERRNO__KVERSION;
}
return 0;
}
@@ -840,32 +1027,28 @@ static struct bpf_object *
__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
{
struct bpf_object *obj;
+ int err;
if (elf_version(EV_CURRENT) == EV_NONE) {
pr_warning("failed to init libelf for %s\n", path);
- return NULL;
+ return ERR_PTR(-LIBBPF_ERRNO__LIBELF);
}
obj = bpf_object__new(path, obj_buf, obj_buf_sz);
- if (!obj)
- return NULL;
+ if (IS_ERR(obj))
+ return obj;
- if (bpf_object__elf_init(obj))
- goto out;
- if (bpf_object__check_endianness(obj))
- goto out;
- if (bpf_object__elf_collect(obj))
- goto out;
- if (bpf_object__collect_reloc(obj))
- goto out;
- if (bpf_object__validate(obj))
- goto out;
+ CHECK_ERR(bpf_object__elf_init(obj), err, out);
+ CHECK_ERR(bpf_object__check_endianness(obj), err, out);
+ CHECK_ERR(bpf_object__elf_collect(obj), err, out);
+ CHECK_ERR(bpf_object__collect_reloc(obj), err, out);
+ CHECK_ERR(bpf_object__validate(obj), err, out);
bpf_object__elf_finish(obj);
return obj;
out:
bpf_object__close(obj);
- return NULL;
+ return ERR_PTR(err);
}
struct bpf_object *bpf_object__open(const char *path)
@@ -909,10 +1092,8 @@ int bpf_object__unload(struct bpf_object *obj)
if (!obj)
return -EINVAL;
- for (i = 0; i < obj->nr_map_fds; i++)
- zclose(obj->map_fds[i]);
- zfree(&obj->map_fds);
- obj->nr_map_fds = 0;
+ for (i = 0; i < obj->nr_maps; i++)
+ zclose(obj->maps[i].fd);
for (i = 0; i < obj->nr_programs; i++)
bpf_program__unload(&obj->programs[i]);
@@ -922,6 +1103,8 @@ int bpf_object__unload(struct bpf_object *obj)
int bpf_object__load(struct bpf_object *obj)
{
+ int err;
+
if (!obj)
return -EINVAL;
@@ -931,18 +1114,16 @@ int bpf_object__load(struct bpf_object *obj)
}
obj->loaded = true;
- if (bpf_object__create_maps(obj))
- goto out;
- if (bpf_object__relocate(obj))
- goto out;
- if (bpf_object__load_progs(obj))
- goto out;
+
+ CHECK_ERR(bpf_object__create_maps(obj), err, out);
+ CHECK_ERR(bpf_object__relocate(obj), err, out);
+ CHECK_ERR(bpf_object__load_progs(obj), err, out);
return 0;
out:
bpf_object__unload(obj);
pr_warning("failed to load object '%s'\n", obj->path);
- return -EINVAL;
+ return err;
}
void bpf_object__close(struct bpf_object *obj)
@@ -955,7 +1136,16 @@ void bpf_object__close(struct bpf_object *obj)
bpf_object__elf_finish(obj);
bpf_object__unload(obj);
- zfree(&obj->maps_buf);
+ for (i = 0; i < obj->nr_maps; i++) {
+ zfree(&obj->maps[i].name);
+ if (obj->maps[i].clear_priv)
+ obj->maps[i].clear_priv(&obj->maps[i],
+ obj->maps[i].priv);
+ obj->maps[i].priv = NULL;
+ obj->maps[i].clear_priv = NULL;
+ }
+ zfree(&obj->maps);
+ obj->nr_maps = 0;
if (obj->programs && obj->nr_programs) {
for (i = 0; i < obj->nr_programs; i++)
@@ -990,10 +1180,18 @@ const char *
bpf_object__get_name(struct bpf_object *obj)
{
if (!obj)
- return NULL;
+ return ERR_PTR(-EINVAL);
return obj->path;
}
+unsigned int
+bpf_object__get_kversion(struct bpf_object *obj)
+{
+ if (!obj)
+ return 0;
+ return obj->kern_version;
+}
+
struct bpf_program *
bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
{
@@ -1034,16 +1232,16 @@ int bpf_program__get_private(struct bpf_program *prog, void **ppriv)
return 0;
}
-const char *bpf_program__title(struct bpf_program *prog, bool dup)
+const char *bpf_program__title(struct bpf_program *prog, bool needs_copy)
{
const char *title;
title = prog->section_name;
- if (dup) {
+ if (needs_copy) {
title = strdup(title);
if (!title) {
pr_warning("failed to strdup program title\n");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
}
@@ -1052,5 +1250,142 @@ const char *bpf_program__title(struct bpf_program *prog, bool dup)
int bpf_program__fd(struct bpf_program *prog)
{
- return prog->fd;
+ return bpf_program__nth_fd(prog, 0);
+}
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instances,
+ bpf_program_prep_t prep)
+{
+ int *instances_fds;
+
+ if (nr_instances <= 0 || !prep)
+ return -EINVAL;
+
+ if (prog->instances.nr > 0 || prog->instances.fds) {
+ pr_warning("Can't set pre-processor after loading\n");
+ return -EINVAL;
+ }
+
+ instances_fds = malloc(sizeof(int) * nr_instances);
+ if (!instances_fds) {
+ pr_warning("alloc memory failed for fds\n");
+ return -ENOMEM;
+ }
+
+ /* fill all fd with -1 */
+ memset(instances_fds, -1, sizeof(int) * nr_instances);
+
+ prog->instances.nr = nr_instances;
+ prog->instances.fds = instances_fds;
+ prog->preprocessor = prep;
+ return 0;
+}
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n)
+{
+ int fd;
+
+ if (n >= prog->instances.nr || n < 0) {
+ pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+ n, prog->section_name, prog->instances.nr);
+ return -EINVAL;
+ }
+
+ fd = prog->instances.fds[n];
+ if (fd < 0) {
+ pr_warning("%dth instance of program '%s' is invalid\n",
+ n, prog->section_name);
+ return -ENOENT;
+ }
+
+ return fd;
+}
+
+int bpf_map__get_fd(struct bpf_map *map)
+{
+ if (!map)
+ return -EINVAL;
+
+ return map->fd;
+}
+
+int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef)
+{
+ if (!map || !pdef)
+ return -EINVAL;
+
+ *pdef = map->def;
+ return 0;
+}
+
+const char *bpf_map__get_name(struct bpf_map *map)
+{
+ if (!map)
+ return NULL;
+ return map->name;
+}
+
+int bpf_map__set_private(struct bpf_map *map, void *priv,
+ bpf_map_clear_priv_t clear_priv)
+{
+ if (!map)
+ return -EINVAL;
+
+ if (map->priv) {
+ if (map->clear_priv)
+ map->clear_priv(map, map->priv);
+ }
+
+ map->priv = priv;
+ map->clear_priv = clear_priv;
+ return 0;
+}
+
+int bpf_map__get_private(struct bpf_map *map, void **ppriv)
+{
+ if (!map)
+ return -EINVAL;
+
+ if (ppriv)
+ *ppriv = map->priv;
+ return 0;
+}
+
+struct bpf_map *
+bpf_map__next(struct bpf_map *prev, struct bpf_object *obj)
+{
+ size_t idx;
+ struct bpf_map *s, *e;
+
+ if (!obj || !obj->maps)
+ return NULL;
+
+ s = obj->maps;
+ e = obj->maps + obj->nr_maps;
+
+ if (prev == NULL)
+ return s;
+
+ if ((prev < s) || (prev >= e)) {
+ pr_warning("error in %s: map handler doesn't belong to object\n",
+ __func__);
+ return NULL;
+ }
+
+ idx = (prev - obj->maps) + 1;
+ if (idx >= obj->nr_maps)
+ return NULL;
+ return &obj->maps[idx];
+}
+
+struct bpf_map *
+bpf_object__get_map_by_name(struct bpf_object *obj, const char *name)
+{
+ struct bpf_map *pos;
+
+ bpf_map__for_each(pos, obj) {
+ if (pos->name && !strcmp(pos->name, name))
+ return pos;
+ }
+ return NULL;
}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index f16170c..a51594c 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -10,6 +10,26 @@
#include <stdio.h>
#include <stdbool.h>
+#include <linux/err.h>
+
+enum libbpf_errno {
+ __LIBBPF_ERRNO__START = 4000,
+
+ /* Something wrong in libelf */
+ LIBBPF_ERRNO__LIBELF = __LIBBPF_ERRNO__START,
+ LIBBPF_ERRNO__FORMAT, /* BPF object format invalid */
+ LIBBPF_ERRNO__KVERSION, /* Incorrect or no 'version' section */
+ LIBBPF_ERRNO__ENDIAN, /* Endian missmatch */
+ LIBBPF_ERRNO__INTERNAL, /* Internal error in libbpf */
+ LIBBPF_ERRNO__RELOC, /* Relocation failed */
+ LIBBPF_ERRNO__LOAD, /* Load program failure for unknown reason */
+ LIBBPF_ERRNO__VERIFY, /* Kernel verifier blocks program loading */
+ LIBBPF_ERRNO__PROG2BIG, /* Program too big */
+ LIBBPF_ERRNO__KVER, /* Incorrect kernel version */
+ __LIBBPF_ERRNO__END,
+};
+
+int libbpf_strerror(int err, char *buf, size_t size);
/*
* In include/linux/compiler-gcc.h, __printf is defined. However
@@ -36,6 +56,7 @@ void bpf_object__close(struct bpf_object *object);
int bpf_object__load(struct bpf_object *obj);
int bpf_object__unload(struct bpf_object *obj);
const char *bpf_object__get_name(struct bpf_object *obj);
+unsigned int bpf_object__get_kversion(struct bpf_object *obj);
struct bpf_object *bpf_object__next(struct bpf_object *prev);
#define bpf_object__for_each_safe(pos, tmp) \
@@ -63,10 +84,74 @@ int bpf_program__set_private(struct bpf_program *prog, void *priv,
int bpf_program__get_private(struct bpf_program *prog,
void **ppriv);
-const char *bpf_program__title(struct bpf_program *prog, bool dup);
+const char *bpf_program__title(struct bpf_program *prog, bool needs_copy);
int bpf_program__fd(struct bpf_program *prog);
+struct bpf_insn;
+
+/*
+ * Libbpf allows callers to adjust BPF programs before being loaded
+ * into kernel. One program in an object file can be transform into
+ * multiple variants to be attached to different code.
+ *
+ * bpf_program_prep_t, bpf_program__set_prep and bpf_program__nth_fd
+ * are APIs for this propose.
+ *
+ * - bpf_program_prep_t:
+ * It defines 'preprocessor', which is a caller defined function
+ * passed to libbpf through bpf_program__set_prep(), and will be
+ * called before program is loaded. The processor should adjust
+ * the program one time for each instances according to the number
+ * passed to it.
+ *
+ * - bpf_program__set_prep:
+ * Attachs a preprocessor to a BPF program. The number of instances
+ * whould be created is also passed through this function.
+ *
+ * - bpf_program__nth_fd:
+ * After the program is loaded, get resuling fds from bpf program for
+ * each instances.
+ *
+ * If bpf_program__set_prep() is not used, the program whould be loaded
+ * without adjustment during bpf_object__load(). The program has only
+ * one instance. In this case bpf_program__fd(prog) is equal to
+ * bpf_program__nth_fd(prog, 0).
+ */
+
+struct bpf_prog_prep_result {
+ /*
+ * If not NULL, load new instruction array.
+ * If set to NULL, don't load this instance.
+ */
+ struct bpf_insn *new_insn_ptr;
+ int new_insn_cnt;
+
+ /* If not NULL, result fd is set to it */
+ int *pfd;
+};
+
+/*
+ * Parameters of bpf_program_prep_t:
+ * - prog: The bpf_program being loaded.
+ * - n: Index of instance being generated.
+ * - insns: BPF instructions array.
+ * - insns_cnt:Number of instructions in insns.
+ * - res: Output parameter, result of transformation.
+ *
+ * Return value:
+ * - Zero: pre-processing success.
+ * - Non-zero: pre-processing, stop loading.
+ */
+typedef int (*bpf_program_prep_t)(struct bpf_program *prog, int n,
+ struct bpf_insn *insns, int insns_cnt,
+ struct bpf_prog_prep_result *res);
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+ bpf_program_prep_t prep);
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n);
+
/*
* We don't need __attribute__((packed)) now since it is
* unnecessary for 'bpf_map_def' because they are all aligned.
@@ -80,4 +165,28 @@ struct bpf_map_def {
unsigned int max_entries;
};
+/*
+ * There is another 'struct bpf_map' in include/linux/map.h. However,
+ * it is not a uapi header so no need to consider name clash.
+ */
+struct bpf_map;
+struct bpf_map *
+bpf_object__get_map_by_name(struct bpf_object *obj, const char *name);
+
+struct bpf_map *
+bpf_map__next(struct bpf_map *map, struct bpf_object *obj);
+#define bpf_map__for_each(pos, obj) \
+ for ((pos) = bpf_map__next(NULL, (obj)); \
+ (pos) != NULL; \
+ (pos) = bpf_map__next((pos), (obj)))
+
+int bpf_map__get_fd(struct bpf_map *map);
+int bpf_map__get_def(struct bpf_map *map, struct bpf_map_def *pdef);
+const char *bpf_map__get_name(struct bpf_map *map);
+
+typedef void (*bpf_map_clear_priv_t)(struct bpf_map *, void *);
+int bpf_map__set_private(struct bpf_map *map, void *priv,
+ bpf_map_clear_priv_t clear_priv);
+int bpf_map__get_private(struct bpf_map *map, void **ppriv);
+
#endif
diff --git a/tools/lib/find_bit.c b/tools/lib/find_bit.c
new file mode 100644
index 0000000..9122a9e
--- /dev/null
+++ b/tools/lib/find_bit.c
@@ -0,0 +1,84 @@
+/* bit search implementation
+ *
+ * Copied from lib/find_bit.c to tools/lib/find_bit.c
+ *
+ * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * Copyright (C) 2008 IBM Corporation
+ * 'find_last_bit' is written by Rusty Russell <rusty@rustcorp.com.au>
+ * (Inspired by David Howell's find_next_bit implementation)
+ *
+ * Rewritten by Yury Norov <yury.norov@gmail.com> to decrease
+ * size and improve performance, 2015.
+ *
+ * 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/bitops.h>
+#include <linux/bitmap.h>
+#include <linux/kernel.h>
+
+#if !defined(find_next_bit)
+
+/*
+ * This is a common helper function for find_next_bit and
+ * find_next_zero_bit. The difference is the "invert" argument, which
+ * is XORed with each fetched word before searching it for one bits.
+ */
+static unsigned long _find_next_bit(const unsigned long *addr,
+ unsigned long nbits, unsigned long start, unsigned long invert)
+{
+ unsigned long tmp;
+
+ if (!nbits || start >= nbits)
+ return nbits;
+
+ tmp = addr[start / BITS_PER_LONG] ^ invert;
+
+ /* Handle 1st word. */
+ tmp &= BITMAP_FIRST_WORD_MASK(start);
+ start = round_down(start, BITS_PER_LONG);
+
+ while (!tmp) {
+ start += BITS_PER_LONG;
+ if (start >= nbits)
+ return nbits;
+
+ tmp = addr[start / BITS_PER_LONG] ^ invert;
+ }
+
+ return min(start + __ffs(tmp), nbits);
+}
+#endif
+
+#ifndef find_next_bit
+/*
+ * Find the next set bit in a memory region.
+ */
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
+{
+ return _find_next_bit(addr, size, offset, 0UL);
+}
+#endif
+
+#ifndef find_first_bit
+/*
+ * Find the first set bit in a memory region.
+ */
+unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
+{
+ unsigned long idx;
+
+ for (idx = 0; idx * BITS_PER_LONG < size; idx++) {
+ if (addr[idx])
+ return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size);
+ }
+
+ return size;
+}
+#endif
diff --git a/tools/lib/lockdep/common.c b/tools/lib/lockdep/common.c
index 8ef602f..9be6633 100644
--- a/tools/lib/lockdep/common.c
+++ b/tools/lib/lockdep/common.c
@@ -18,7 +18,7 @@ __attribute__((constructor)) static void liblockdep_init(void)
__attribute__((destructor)) static void liblockdep_exit(void)
{
- debug_check_no_locks_held(&current_obj);
+ debug_check_no_locks_held();
}
struct task_struct *__curr(void)
diff --git a/tools/lib/lockdep/include/liblockdep/common.h b/tools/lib/lockdep/include/liblockdep/common.h
index 0bda630..a60c14b 100644
--- a/tools/lib/lockdep/include/liblockdep/common.h
+++ b/tools/lib/lockdep/include/liblockdep/common.h
@@ -43,6 +43,8 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
struct lockdep_map *nest_lock, unsigned long ip);
void lock_release(struct lockdep_map *lock, int nested,
unsigned long ip);
+extern void debug_check_no_locks_freed(const void *from, unsigned long len);
+extern void lockdep_init(void);
#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
{ .name = (_name), .key = (void *)(_key), }
diff --git a/tools/lib/lockdep/uinclude/linux/compiler.h b/tools/lib/lockdep/uinclude/linux/compiler.h
index 7ac838a..6386dc3 100644
--- a/tools/lib/lockdep/uinclude/linux/compiler.h
+++ b/tools/lib/lockdep/uinclude/linux/compiler.h
@@ -3,5 +3,7 @@
#define __used __attribute__((__unused__))
#define unlikely
+#define WRITE_ONCE(x, val) x=(val)
+#define RCU_INIT_POINTER(p, v) p=(v)
#endif
diff --git a/tools/lib/lockdep/uinclude/linux/lockdep.h b/tools/lib/lockdep/uinclude/linux/lockdep.h
index c1552c2..c808c7d 100644
--- a/tools/lib/lockdep/uinclude/linux/lockdep.h
+++ b/tools/lib/lockdep/uinclude/linux/lockdep.h
@@ -6,7 +6,7 @@
#include <string.h>
#include <limits.h>
#include <linux/utsname.h>
-
+#include <linux/compiler.h>
#define MAX_LOCK_DEPTH 2000UL
@@ -54,5 +54,6 @@ static struct new_utsname *init_utsname(void)
#define static_obj(x) 1
#define debug_show_all_locks()
+extern void debug_check_no_locks_held(void);
#endif
diff --git a/tools/lib/string.c b/tools/lib/string.c
new file mode 100644
index 0000000..bd239bc
--- /dev/null
+++ b/tools/lib/string.c
@@ -0,0 +1,89 @@
+/*
+ * linux/tools/lib/string.c
+ *
+ * Copied from linux/lib/string.c, where it is:
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * More specifically, the first copied function was strtobool, which
+ * was introduced by:
+ *
+ * d0f1fed29e6e ("Add a strtobool function matching semantics of existing in kernel equivalents")
+ * Author: Jonathan Cameron <jic23@cam.ac.uk>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/string.h>
+#include <linux/compiler.h>
+
+/**
+ * memdup - duplicate region of memory
+ *
+ * @src: memory region to duplicate
+ * @len: memory region length
+ */
+void *memdup(const void *src, size_t len)
+{
+ void *p = malloc(len);
+
+ if (p)
+ memcpy(p, src, len);
+
+ return p;
+}
+
+/**
+ * strtobool - convert common user inputs into boolean values
+ * @s: input string
+ * @res: result
+ *
+ * This routine returns 0 iff the first character is one of 'Yy1Nn0'.
+ * Otherwise it will return -EINVAL. Value pointed to by res is
+ * updated upon finding a match.
+ */
+int strtobool(const char *s, bool *res)
+{
+ switch (s[0]) {
+ case 'y':
+ case 'Y':
+ case '1':
+ *res = true;
+ break;
+ case 'n':
+ case 'N':
+ case '0':
+ *res = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * strlcpy - Copy a C-string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ *
+ * If libc has strlcpy() then that version will override this
+ * implementation:
+ */
+size_t __weak strlcpy(char *dest, const char *src, size_t size)
+{
+ size_t ret = strlen(src);
+
+ if (size) {
+ size_t len = (ret >= size) ? size - 1 : ret;
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ }
+ return ret;
+}
diff --git a/tools/lib/subcmd/Build b/tools/lib/subcmd/Build
new file mode 100644
index 0000000..ee31288
--- /dev/null
+++ b/tools/lib/subcmd/Build
@@ -0,0 +1,7 @@
+libsubcmd-y += exec-cmd.o
+libsubcmd-y += help.o
+libsubcmd-y += pager.o
+libsubcmd-y += parse-options.o
+libsubcmd-y += run-command.o
+libsubcmd-y += sigchain.o
+libsubcmd-y += subcmd-config.o
diff --git a/tools/lib/subcmd/Makefile b/tools/lib/subcmd/Makefile
new file mode 100644
index 0000000..629cf8c
--- /dev/null
+++ b/tools/lib/subcmd/Makefile
@@ -0,0 +1,48 @@
+include ../../scripts/Makefile.include
+include ../../perf/config/utilities.mak # QUIET_CLEAN
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(shell pwd)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+#$(info Determined 'srctree' to be $(srctree))
+endif
+
+CC = $(CROSS_COMPILE)gcc
+AR = $(CROSS_COMPILE)ar
+RM = rm -f
+
+MAKEFLAGS += --no-print-directory
+
+LIBFILE = $(OUTPUT)libsubcmd.a
+
+CFLAGS := $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
+CFLAGS += -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fPIC
+CFLAGS += -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+
+CFLAGS += -I$(srctree)/tools/include/
+CFLAGS += -I$(srctree)/include/uapi
+CFLAGS += -I$(srctree)/include
+
+SUBCMD_IN := $(OUTPUT)libsubcmd-in.o
+
+all:
+
+export srctree OUTPUT CC LD CFLAGS V
+include $(srctree)/tools/build/Makefile.include
+
+all: fixdep $(LIBFILE)
+
+$(SUBCMD_IN): FORCE
+ @$(MAKE) $(build)=libsubcmd
+
+$(LIBFILE): $(SUBCMD_IN)
+ $(QUIET_AR)$(RM) $@ && $(AR) rcs $@ $(SUBCMD_IN)
+
+clean:
+ $(call QUIET_CLEAN, libsubcmd) $(RM) $(LIBFILE); \
+ find $(if $(OUTPUT),$(OUTPUT),.) -name \*.o -or -name \*.o.cmd -or -name \*.o.d | xargs $(RM)
+
+FORCE:
+
+.PHONY: clean FORCE
diff --git a/tools/lib/subcmd/exec-cmd.c b/tools/lib/subcmd/exec-cmd.c
new file mode 100644
index 0000000..1ae833a
--- /dev/null
+++ b/tools/lib/subcmd/exec-cmd.c
@@ -0,0 +1,209 @@
+#include <linux/compiler.h>
+#include <linux/string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "subcmd-util.h"
+#include "exec-cmd.h"
+#include "subcmd-config.h"
+
+#define MAX_ARGS 32
+#define PATH_MAX 4096
+
+static const char *argv_exec_path;
+static const char *argv0_path;
+
+void exec_cmd_init(const char *exec_name, const char *prefix,
+ const char *exec_path, const char *exec_path_env)
+{
+ subcmd_config.exec_name = exec_name;
+ subcmd_config.prefix = prefix;
+ subcmd_config.exec_path = exec_path;
+ subcmd_config.exec_path_env = exec_path_env;
+}
+
+#define is_dir_sep(c) ((c) == '/')
+
+static int is_absolute_path(const char *path)
+{
+ return path[0] == '/';
+}
+
+static const char *get_pwd_cwd(void)
+{
+ static char cwd[PATH_MAX + 1];
+ char *pwd;
+ struct stat cwd_stat, pwd_stat;
+ if (getcwd(cwd, PATH_MAX) == NULL)
+ return NULL;
+ pwd = getenv("PWD");
+ if (pwd && strcmp(pwd, cwd)) {
+ stat(cwd, &cwd_stat);
+ if (!stat(pwd, &pwd_stat) &&
+ pwd_stat.st_dev == cwd_stat.st_dev &&
+ pwd_stat.st_ino == cwd_stat.st_ino) {
+ strlcpy(cwd, pwd, PATH_MAX);
+ }
+ }
+ return cwd;
+}
+
+static const char *make_nonrelative_path(const char *path)
+{
+ static char buf[PATH_MAX + 1];
+
+ if (is_absolute_path(path)) {
+ if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
+ die("Too long path: %.*s", 60, path);
+ } else {
+ const char *cwd = get_pwd_cwd();
+ if (!cwd)
+ die("Cannot determine the current working directory");
+ if (snprintf(buf, PATH_MAX, "%s/%s", cwd, path) >= PATH_MAX)
+ die("Too long path: %.*s", 60, path);
+ }
+ return buf;
+}
+
+char *system_path(const char *path)
+{
+ char *buf = NULL;
+
+ if (is_absolute_path(path))
+ return strdup(path);
+
+ astrcatf(&buf, "%s/%s", subcmd_config.prefix, path);
+
+ return buf;
+}
+
+const char *extract_argv0_path(const char *argv0)
+{
+ const char *slash;
+
+ if (!argv0 || !*argv0)
+ return NULL;
+ slash = argv0 + strlen(argv0);
+
+ while (argv0 <= slash && !is_dir_sep(*slash))
+ slash--;
+
+ if (slash >= argv0) {
+ argv0_path = strndup(argv0, slash - argv0);
+ return argv0_path ? slash + 1 : NULL;
+ }
+
+ return argv0;
+}
+
+void set_argv_exec_path(const char *exec_path)
+{
+ argv_exec_path = exec_path;
+ /*
+ * Propagate this setting to external programs.
+ */
+ setenv(subcmd_config.exec_path_env, exec_path, 1);
+}
+
+
+/* Returns the highest-priority location to look for subprograms. */
+char *get_argv_exec_path(void)
+{
+ char *env;
+
+ if (argv_exec_path)
+ return strdup(argv_exec_path);
+
+ env = getenv(subcmd_config.exec_path_env);
+ if (env && *env)
+ return strdup(env);
+
+ return system_path(subcmd_config.exec_path);
+}
+
+static void add_path(char **out, const char *path)
+{
+ if (path && *path) {
+ if (is_absolute_path(path))
+ astrcat(out, path);
+ else
+ astrcat(out, make_nonrelative_path(path));
+
+ astrcat(out, ":");
+ }
+}
+
+void setup_path(void)
+{
+ const char *old_path = getenv("PATH");
+ char *new_path = NULL;
+ char *tmp = get_argv_exec_path();
+
+ add_path(&new_path, tmp);
+ add_path(&new_path, argv0_path);
+ free(tmp);
+
+ if (old_path)
+ astrcat(&new_path, old_path);
+ else
+ astrcat(&new_path, "/usr/local/bin:/usr/bin:/bin");
+
+ setenv("PATH", new_path, 1);
+
+ free(new_path);
+}
+
+static const char **prepare_exec_cmd(const char **argv)
+{
+ int argc;
+ const char **nargv;
+
+ for (argc = 0; argv[argc]; argc++)
+ ; /* just counting */
+ nargv = malloc(sizeof(*nargv) * (argc + 2));
+
+ nargv[0] = subcmd_config.exec_name;
+ for (argc = 0; argv[argc]; argc++)
+ nargv[argc + 1] = argv[argc];
+ nargv[argc + 1] = NULL;
+ return nargv;
+}
+
+int execv_cmd(const char **argv) {
+ const char **nargv = prepare_exec_cmd(argv);
+
+ /* execvp() can only ever return if it fails */
+ execvp(subcmd_config.exec_name, (char **)nargv);
+
+ free(nargv);
+ return -1;
+}
+
+
+int execl_cmd(const char *cmd,...)
+{
+ int argc;
+ const char *argv[MAX_ARGS + 1];
+ const char *arg;
+ va_list param;
+
+ va_start(param, cmd);
+ argv[0] = cmd;
+ argc = 1;
+ while (argc < MAX_ARGS) {
+ arg = argv[argc++] = va_arg(param, char *);
+ if (!arg)
+ break;
+ }
+ va_end(param);
+ if (MAX_ARGS <= argc) {
+ fprintf(stderr, " Error: too many args to run %s\n", cmd);
+ return -1;
+ }
+
+ argv[argc] = NULL;
+ return execv_cmd(argv);
+}
diff --git a/tools/lib/subcmd/exec-cmd.h b/tools/lib/subcmd/exec-cmd.h
new file mode 100644
index 0000000..5d08bda
--- /dev/null
+++ b/tools/lib/subcmd/exec-cmd.h
@@ -0,0 +1,16 @@
+#ifndef __SUBCMD_EXEC_CMD_H
+#define __SUBCMD_EXEC_CMD_H
+
+extern void exec_cmd_init(const char *exec_name, const char *prefix,
+ const char *exec_path, const char *exec_path_env);
+
+extern void set_argv_exec_path(const char *exec_path);
+extern const char *extract_argv0_path(const char *path);
+extern void setup_path(void);
+extern int execv_cmd(const char **argv); /* NULL terminated */
+extern int execl_cmd(const char *cmd, ...);
+/* get_argv_exec_path and system_path return malloc'd string, caller must free it */
+extern char *get_argv_exec_path(void);
+extern char *system_path(const char *path);
+
+#endif /* __SUBCMD_EXEC_CMD_H */
diff --git a/tools/perf/util/help.c b/tools/lib/subcmd/help.c
index 86c37c4..e228c3c 100644
--- a/tools/perf/util/help.c
+++ b/tools/lib/subcmd/help.c
@@ -1,9 +1,15 @@
-#include "cache.h"
-#include "../builtin.h"
-#include "exec_cmd.h"
-#include "levenshtein.h"
-#include "help.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "subcmd-util.h"
+#include "help.h"
+#include "exec-cmd.h"
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
{
@@ -17,7 +23,7 @@ void add_cmdname(struct cmdnames *cmds, const char *name, size_t len)
cmds->names[cmds->cnt++] = ent;
}
-static void clean_cmdnames(struct cmdnames *cmds)
+void clean_cmdnames(struct cmdnames *cmds)
{
unsigned int i;
@@ -28,14 +34,14 @@ static void clean_cmdnames(struct cmdnames *cmds)
cmds->alloc = 0;
}
-static int cmdname_compare(const void *a_, const void *b_)
+int cmdname_compare(const void *a_, const void *b_)
{
struct cmdname *a = *(struct cmdname **)a_;
struct cmdname *b = *(struct cmdname **)b_;
return strcmp(a->name, b->name);
}
-static void uniq(struct cmdnames *cmds)
+void uniq(struct cmdnames *cmds)
{
unsigned int i, j;
@@ -71,6 +77,28 @@ void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes)
cmds->cnt = cj;
}
+static void get_term_dimensions(struct winsize *ws)
+{
+ char *s = getenv("LINES");
+
+ if (s != NULL) {
+ ws->ws_row = atoi(s);
+ s = getenv("COLUMNS");
+ if (s != NULL) {
+ ws->ws_col = atoi(s);
+ if (ws->ws_row && ws->ws_col)
+ return;
+ }
+ }
+#ifdef TIOCGWINSZ
+ if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+ ws->ws_row && ws->ws_col)
+ return;
+#endif
+ ws->ws_row = 25;
+ ws->ws_col = 80;
+}
+
static void pretty_print_string_list(struct cmdnames *cmds, int longest)
{
int cols = 1, rows;
@@ -114,6 +142,14 @@ static int is_executable(const char *name)
return st.st_mode & S_IXUSR;
}
+static int has_extension(const char *filename, const char *ext)
+{
+ size_t len = strlen(filename);
+ size_t extlen = strlen(ext);
+
+ return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
+}
+
static void list_commands_in_dir(struct cmdnames *cmds,
const char *path,
const char *prefix)
@@ -121,8 +157,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
int prefix_len;
DIR *dir = opendir(path);
struct dirent *de;
- struct strbuf buf = STRBUF_INIT;
- int len;
+ char *buf = NULL;
if (!dir)
return;
@@ -130,8 +165,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
prefix = "perf-";
prefix_len = strlen(prefix);
- strbuf_addf(&buf, "%s/", path);
- len = buf.len;
+ astrcatf(&buf, "%s/", path);
while ((de = readdir(dir)) != NULL) {
int entlen;
@@ -139,9 +173,8 @@ static void list_commands_in_dir(struct cmdnames *cmds,
if (prefixcmp(de->d_name, prefix))
continue;
- strbuf_setlen(&buf, len);
- strbuf_addstr(&buf, de->d_name);
- if (!is_executable(buf.buf))
+ astrcat(&buf, de->d_name);
+ if (!is_executable(buf))
continue;
entlen = strlen(de->d_name) - prefix_len;
@@ -151,7 +184,7 @@ static void list_commands_in_dir(struct cmdnames *cmds,
add_cmdname(cmds, de->d_name + prefix_len, entlen);
}
closedir(dir);
- strbuf_release(&buf);
+ free(buf);
}
void load_command_list(const char *prefix,
@@ -159,7 +192,7 @@ void load_command_list(const char *prefix,
struct cmdnames *other_cmds)
{
const char *env_path = getenv("PATH");
- const char *exec_path = perf_exec_path();
+ char *exec_path = get_argv_exec_path();
if (exec_path) {
list_commands_in_dir(main_cmds, exec_path, prefix);
@@ -172,7 +205,7 @@ void load_command_list(const char *prefix,
char *paths, *path, *colon;
path = paths = strdup(env_path);
while (1) {
- if ((colon = strchr(path, PATH_SEP)))
+ if ((colon = strchr(path, ':')))
*colon = 0;
if (!exec_path || strcmp(path, exec_path))
list_commands_in_dir(other_cmds, path, prefix);
@@ -187,6 +220,7 @@ void load_command_list(const char *prefix,
sizeof(*other_cmds->names), cmdname_compare);
uniq(other_cmds);
}
+ free(exec_path);
exclude_cmds(other_cmds, main_cmds);
}
@@ -203,13 +237,14 @@ void list_commands(const char *title, struct cmdnames *main_cmds,
longest = other_cmds->names[i]->len;
if (main_cmds->cnt) {
- const char *exec_path = perf_exec_path();
+ char *exec_path = get_argv_exec_path();
printf("available %s in '%s'\n", title, exec_path);
printf("----------------");
mput_char('-', strlen(title) + strlen(exec_path));
putchar('\n');
pretty_print_string_list(main_cmds, longest);
putchar('\n');
+ free(exec_path);
}
if (other_cmds->cnt) {
@@ -231,109 +266,3 @@ int is_in_cmdlist(struct cmdnames *c, const char *s)
return 1;
return 0;
}
-
-static int autocorrect;
-static struct cmdnames aliases;
-
-static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
-{
- if (!strcmp(var, "help.autocorrect"))
- autocorrect = perf_config_int(var,value);
- /* Also use aliases for command lookup */
- if (!prefixcmp(var, "alias."))
- add_cmdname(&aliases, var + 6, strlen(var + 6));
-
- return perf_default_config(var, value, cb);
-}
-
-static int levenshtein_compare(const void *p1, const void *p2)
-{
- const struct cmdname *const *c1 = p1, *const *c2 = p2;
- const char *s1 = (*c1)->name, *s2 = (*c2)->name;
- int l1 = (*c1)->len;
- int l2 = (*c2)->len;
- return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
-}
-
-static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
-{
- unsigned int i;
-
- ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
-
- for (i = 0; i < old->cnt; i++)
- cmds->names[cmds->cnt++] = old->names[i];
- zfree(&old->names);
- old->cnt = 0;
-}
-
-const char *help_unknown_cmd(const char *cmd)
-{
- unsigned int i, n = 0, best_similarity = 0;
- struct cmdnames main_cmds, other_cmds;
-
- memset(&main_cmds, 0, sizeof(main_cmds));
- memset(&other_cmds, 0, sizeof(main_cmds));
- memset(&aliases, 0, sizeof(aliases));
-
- perf_config(perf_unknown_cmd_config, NULL);
-
- load_command_list("perf-", &main_cmds, &other_cmds);
-
- add_cmd_list(&main_cmds, &aliases);
- add_cmd_list(&main_cmds, &other_cmds);
- qsort(main_cmds.names, main_cmds.cnt,
- sizeof(main_cmds.names), cmdname_compare);
- uniq(&main_cmds);
-
- if (main_cmds.cnt) {
- /* This reuses cmdname->len for similarity index */
- for (i = 0; i < main_cmds.cnt; ++i)
- main_cmds.names[i]->len =
- levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
-
- qsort(main_cmds.names, main_cmds.cnt,
- sizeof(*main_cmds.names), levenshtein_compare);
-
- best_similarity = main_cmds.names[0]->len;
- n = 1;
- while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
- ++n;
- }
-
- if (autocorrect && n == 1) {
- const char *assumed = main_cmds.names[0]->name;
-
- main_cmds.names[0] = NULL;
- clean_cmdnames(&main_cmds);
- fprintf(stderr, "WARNING: You called a perf program named '%s', "
- "which does not exist.\n"
- "Continuing under the assumption that you meant '%s'\n",
- cmd, assumed);
- if (autocorrect > 0) {
- fprintf(stderr, "in %0.1f seconds automatically...\n",
- (float)autocorrect/10.0);
- poll(NULL, 0, autocorrect * 100);
- }
- return assumed;
- }
-
- fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
-
- if (main_cmds.cnt && best_similarity < 6) {
- fprintf(stderr, "\nDid you mean %s?\n",
- n < 2 ? "this": "one of these");
-
- for (i = 0; i < n; i++)
- fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
- }
-
- exit(1);
-}
-
-int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
- const char *prefix __maybe_unused)
-{
- printf("perf version %s\n", perf_version_string);
- return 0;
-}
diff --git a/tools/perf/util/help.h b/tools/lib/subcmd/help.h
index 7f5c6de..e145a02 100644
--- a/tools/perf/util/help.h
+++ b/tools/lib/subcmd/help.h
@@ -1,12 +1,14 @@
-#ifndef __PERF_HELP_H
-#define __PERF_HELP_H
+#ifndef __SUBCMD_HELP_H
+#define __SUBCMD_HELP_H
+
+#include <sys/types.h>
struct cmdnames {
size_t alloc;
size_t cnt;
struct cmdname {
size_t len; /* also used for similarity index in help.c */
- char name[FLEX_ARRAY];
+ char name[];
} **names;
};
@@ -20,10 +22,13 @@ void load_command_list(const char *prefix,
struct cmdnames *main_cmds,
struct cmdnames *other_cmds);
void add_cmdname(struct cmdnames *cmds, const char *name, size_t len);
+void clean_cmdnames(struct cmdnames *cmds);
+int cmdname_compare(const void *a, const void *b);
+void uniq(struct cmdnames *cmds);
/* Here we require that excludes is a sorted list. */
void exclude_cmds(struct cmdnames *cmds, struct cmdnames *excludes);
int is_in_cmdlist(struct cmdnames *c, const char *s);
void list_commands(const char *title, struct cmdnames *main_cmds,
struct cmdnames *other_cmds);
-#endif /* __PERF_HELP_H */
+#endif /* __SUBCMD_HELP_H */
diff --git a/tools/perf/util/pager.c b/tools/lib/subcmd/pager.c
index 53ef006..d50f3b58 100644
--- a/tools/perf/util/pager.c
+++ b/tools/lib/subcmd/pager.c
@@ -1,6 +1,12 @@
-#include "cache.h"
+#include <sys/select.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "pager.h"
#include "run-command.h"
#include "sigchain.h"
+#include "subcmd-config.h"
/*
* This is split up from the rest of git so that we can do
@@ -9,6 +15,11 @@
static int spawned_pager;
+void pager_init(const char *pager_env)
+{
+ subcmd_config.pager_env = pager_env;
+}
+
static void pager_preexec(void)
{
/*
@@ -46,7 +57,7 @@ static void wait_for_pager_signal(int signo)
void setup_pager(void)
{
- const char *pager = getenv("PERF_PAGER");
+ const char *pager = getenv(subcmd_config.pager_env);
if (!isatty(1))
return;
@@ -85,11 +96,5 @@ void setup_pager(void)
int pager_in_use(void)
{
- const char *env;
-
- if (spawned_pager)
- return 1;
-
- env = getenv("PERF_PAGER_IN_USE");
- return env ? perf_config_bool("PERF_PAGER_IN_USE", env) : 0;
+ return spawned_pager;
}
diff --git a/tools/lib/subcmd/pager.h b/tools/lib/subcmd/pager.h
new file mode 100644
index 0000000..8b83714
--- /dev/null
+++ b/tools/lib/subcmd/pager.h
@@ -0,0 +1,9 @@
+#ifndef __SUBCMD_PAGER_H
+#define __SUBCMD_PAGER_H
+
+extern void pager_init(const char *pager_env);
+
+extern void setup_pager(void);
+extern int pager_in_use(void);
+
+#endif /* __SUBCMD_PAGER_H */
diff --git a/tools/perf/util/parse-options.c b/tools/lib/subcmd/parse-options.c
index 9fca092..981bb44 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/lib/subcmd/parse-options.c
@@ -1,37 +1,66 @@
-#include "util.h"
+#include <linux/compiler.h>
+#include <linux/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include "subcmd-util.h"
#include "parse-options.h"
-#include "cache.h"
-#include "header.h"
-#include <linux/string.h>
+#include "subcmd-config.h"
+#include "pager.h"
#define OPT_SHORT 1
#define OPT_UNSET 2
-static struct strbuf error_buf = STRBUF_INIT;
+char *error_buf;
static int opterror(const struct option *opt, const char *reason, int flags)
{
if (flags & OPT_SHORT)
- return error("switch `%c' %s", opt->short_name, reason);
- if (flags & OPT_UNSET)
- return error("option `no-%s' %s", opt->long_name, reason);
- return error("option `%s' %s", opt->long_name, reason);
+ fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
+ else if (flags & OPT_UNSET)
+ fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
+ else
+ fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
+
+ return -1;
+}
+
+static const char *skip_prefix(const char *str, const char *prefix)
+{
+ size_t len = strlen(prefix);
+ return strncmp(str, prefix, len) ? NULL : str + len;
+}
+
+static void optwarning(const struct option *opt, const char *reason, int flags)
+{
+ if (flags & OPT_SHORT)
+ fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
+ else if (flags & OPT_UNSET)
+ fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
+ else
+ fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
}
static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
int flags, const char **arg)
{
+ const char *res;
+
if (p->opt) {
- *arg = p->opt;
+ res = p->opt;
p->opt = NULL;
} else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
**(p->argv + 1) == '-')) {
- *arg = (const char *)opt->defval;
+ res = (const char *)opt->defval;
} else if (p->argc > 1) {
p->argc--;
- *arg = *++p->argv;
+ res = *++p->argv;
} else
return opterror(opt, "requires a value", flags);
+ if (arg)
+ *arg = res;
return 0;
}
@@ -55,11 +84,11 @@ static int get_value(struct parse_opt_ctx_t *p,
if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
p->excl_opt->long_name == NULL) {
- scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
- p->excl_opt->short_name);
+ snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
+ p->excl_opt->short_name);
} else {
- scnprintf(msg, sizeof(msg), "cannot be used with %s",
- p->excl_opt->long_name);
+ snprintf(msg, sizeof(msg), "cannot be used with %s",
+ p->excl_opt->long_name);
}
opterror(opt, msg, flags);
return -3;
@@ -91,6 +120,64 @@ static int get_value(struct parse_opt_ctx_t *p,
}
}
+ if (opt->flags & PARSE_OPT_NOBUILD) {
+ char reason[128];
+ bool noarg = false;
+
+ err = snprintf(reason, sizeof(reason),
+ opt->flags & PARSE_OPT_CANSKIP ?
+ "is being ignored because %s " :
+ "is not available because %s",
+ opt->build_opt);
+ reason[sizeof(reason) - 1] = '\0';
+
+ if (err < 0)
+ strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
+ "is being ignored" :
+ "is not available",
+ sizeof(reason));
+
+ if (!(opt->flags & PARSE_OPT_CANSKIP))
+ return opterror(opt, reason, flags);
+
+ err = 0;
+ if (unset)
+ noarg = true;
+ if (opt->flags & PARSE_OPT_NOARG)
+ noarg = true;
+ if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
+ noarg = true;
+
+ switch (opt->type) {
+ case OPTION_BOOLEAN:
+ case OPTION_INCR:
+ case OPTION_BIT:
+ case OPTION_SET_UINT:
+ case OPTION_SET_PTR:
+ case OPTION_END:
+ case OPTION_ARGUMENT:
+ case OPTION_GROUP:
+ noarg = true;
+ break;
+ case OPTION_CALLBACK:
+ case OPTION_STRING:
+ case OPTION_INTEGER:
+ case OPTION_UINTEGER:
+ case OPTION_LONG:
+ case OPTION_U64:
+ default:
+ break;
+ }
+
+ if (!noarg)
+ err = get_arg(p, opt, flags, NULL);
+ if (err)
+ return err;
+
+ optwarning(opt, reason, flags);
+ return 0;
+ }
+
switch (opt->type) {
case OPTION_BIT:
if (unset)
@@ -327,14 +414,16 @@ match:
return get_value(p, options, flags);
}
- if (ambiguous_option)
- return error("Ambiguous option: %s "
- "(could be --%s%s or --%s%s)",
- arg,
- (ambiguous_flags & OPT_UNSET) ? "no-" : "",
- ambiguous_option->long_name,
- (abbrev_flags & OPT_UNSET) ? "no-" : "",
- abbrev_option->long_name);
+ if (ambiguous_option) {
+ fprintf(stderr,
+ " Error: Ambiguous option: %s (could be --%s%s or --%s%s)",
+ arg,
+ (ambiguous_flags & OPT_UNSET) ? "no-" : "",
+ ambiguous_option->long_name,
+ (abbrev_flags & OPT_UNSET) ? "no-" : "",
+ abbrev_option->long_name);
+ return -1;
+ }
if (abbrev_option)
return get_value(p, abbrev_option, abbrev_flags);
return -2;
@@ -346,7 +435,7 @@ static void check_typos(const char *arg, const struct option *options)
return;
if (!prefixcmp(arg, "no-")) {
- error ("did you mean `--%s` (with two dashes ?)", arg);
+ fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
exit(129);
}
@@ -354,14 +443,14 @@ static void check_typos(const char *arg, const struct option *options)
if (!options->long_name)
continue;
if (!prefixcmp(options->long_name, arg)) {
- error ("did you mean `--%s` (with two dashes ?)", arg);
+ fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)", arg);
exit(129);
}
}
}
-void parse_options_start(struct parse_opt_ctx_t *ctx,
- int argc, const char **argv, int flags)
+static void parse_options_start(struct parse_opt_ctx_t *ctx,
+ int argc, const char **argv, int flags)
{
memset(ctx, 0, sizeof(*ctx));
ctx->argc = argc - 1;
@@ -378,9 +467,9 @@ static int usage_with_options_internal(const char * const *,
const struct option *, int,
struct parse_opt_ctx_t *);
-int parse_options_step(struct parse_opt_ctx_t *ctx,
- const struct option *options,
- const char * const usagestr[])
+static int parse_options_step(struct parse_opt_ctx_t *ctx,
+ const struct option *options,
+ const char * const usagestr[])
{
int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
int excl_short_opt = 1;
@@ -489,7 +578,7 @@ exclusive:
return PARSE_OPT_HELP;
}
-int parse_options_end(struct parse_opt_ctx_t *ctx)
+static int parse_options_end(struct parse_opt_ctx_t *ctx)
{
memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
ctx->out[ctx->cpidx + ctx->argc] = NULL;
@@ -501,22 +590,20 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
{
struct parse_opt_ctx_t ctx;
- perf_env__set_cmdline(&perf_env, argc, argv);
-
/* build usage string if it's not provided */
if (subcommands && !usagestr[0]) {
- struct strbuf buf = STRBUF_INIT;
+ char *buf = NULL;
+
+ astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
- strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
for (int i = 0; subcommands[i]; i++) {
if (i)
- strbuf_addstr(&buf, "|");
- strbuf_addstr(&buf, subcommands[i]);
+ astrcat(&buf, "|");
+ astrcat(&buf, subcommands[i]);
}
- strbuf_addstr(&buf, "}");
+ astrcat(&buf, "}");
- usagestr[0] = strdup(buf.buf);
- strbuf_release(&buf);
+ usagestr[0] = buf;
}
parse_options_start(&ctx, argc, argv, flags);
@@ -541,13 +628,11 @@ int parse_options_subcommand(int argc, const char **argv, const struct option *o
putchar('\n');
exit(130);
default: /* PARSE_OPT_UNKNOWN */
- if (ctx.argv[0][1] == '-') {
- strbuf_addf(&error_buf, "unknown option `%s'",
- ctx.argv[0] + 2);
- } else {
- strbuf_addf(&error_buf, "unknown switch `%c'",
- *ctx.opt);
- }
+ if (ctx.argv[0][1] == '-')
+ astrcatf(&error_buf, "unknown option `%s'",
+ ctx.argv[0] + 2);
+ else
+ astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
usage_with_options(usagestr, options);
}
@@ -647,6 +732,10 @@ static void print_option_help(const struct option *opts, int full)
pad = USAGE_OPTS_WIDTH;
}
fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
+ if (opts->flags & PARSE_OPT_NOBUILD)
+ fprintf(stderr, "%*s(not built-in because %s)\n",
+ USAGE_OPTS_WIDTH + USAGE_GAP, "",
+ opts->build_opt);
}
static int option__cmp(const void *va, const void *vb)
@@ -672,16 +761,18 @@ static int option__cmp(const void *va, const void *vb)
static struct option *options__order(const struct option *opts)
{
- int nr_opts = 0;
+ int nr_opts = 0, len;
const struct option *o = opts;
struct option *ordered;
for (o = opts; o->type != OPTION_END; o++)
++nr_opts;
- ordered = memdup(opts, sizeof(*o) * (nr_opts + 1));
- if (ordered == NULL)
+ len = sizeof(*o) * (nr_opts + 1);
+ ordered = malloc(len);
+ if (!ordered)
goto out;
+ memcpy(ordered, opts, len);
qsort(ordered, nr_opts, sizeof(*o), option__cmp);
out:
@@ -719,9 +810,9 @@ static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx
return false;
}
-int usage_with_options_internal(const char * const *usagestr,
- const struct option *opts, int full,
- struct parse_opt_ctx_t *ctx)
+static int usage_with_options_internal(const char * const *usagestr,
+ const struct option *opts, int full,
+ struct parse_opt_ctx_t *ctx)
{
struct option *ordered;
@@ -730,9 +821,9 @@ int usage_with_options_internal(const char * const *usagestr,
setup_pager();
- if (strbuf_avail(&error_buf)) {
- fprintf(stderr, " Error: %s\n", error_buf.buf);
- strbuf_release(&error_buf);
+ if (error_buf) {
+ fprintf(stderr, " Error: %s\n", error_buf);
+ zfree(&error_buf);
}
fprintf(stderr, "\n Usage: %s\n", *usagestr++);
@@ -768,7 +859,6 @@ int usage_with_options_internal(const char * const *usagestr,
void usage_with_options(const char * const *usagestr,
const struct option *opts)
{
- exit_browser(false);
usage_with_options_internal(usagestr, opts, 0, NULL);
exit(129);
}
@@ -777,13 +867,15 @@ void usage_with_options_msg(const char * const *usagestr,
const struct option *opts, const char *fmt, ...)
{
va_list ap;
-
- exit_browser(false);
+ char *tmp = error_buf;
va_start(ap, fmt);
- strbuf_addv(&error_buf, fmt, ap);
+ if (vasprintf(&error_buf, fmt, ap) == -1)
+ die("vasprintf failed");
va_end(ap);
+ free(tmp);
+
usage_with_options_internal(usagestr, opts, 0, NULL);
exit(129);
}
@@ -853,15 +945,39 @@ int parse_opt_verbosity_cb(const struct option *opt,
return 0;
}
-void set_option_flag(struct option *opts, int shortopt, const char *longopt,
- int flag)
+static struct option *
+find_option(struct option *opts, int shortopt, const char *longopt)
{
for (; opts->type != OPTION_END; opts++) {
if ((shortopt && opts->short_name == shortopt) ||
(opts->long_name && longopt &&
- !strcmp(opts->long_name, longopt))) {
- opts->flags |= flag;
- break;
- }
+ !strcmp(opts->long_name, longopt)))
+ return opts;
}
+ return NULL;
+}
+
+void set_option_flag(struct option *opts, int shortopt, const char *longopt,
+ int flag)
+{
+ struct option *opt = find_option(opts, shortopt, longopt);
+
+ if (opt)
+ opt->flags |= flag;
+ return;
+}
+
+void set_option_nobuild(struct option *opts, int shortopt,
+ const char *longopt,
+ const char *build_opt,
+ bool can_skip)
+{
+ struct option *opt = find_option(opts, shortopt, longopt);
+
+ if (!opt)
+ return;
+
+ opt->flags |= PARSE_OPT_NOBUILD;
+ opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
+ opt->build_opt = build_opt;
}
diff --git a/tools/perf/util/parse-options.h b/tools/lib/subcmd/parse-options.h
index a8e407b..13a2cc1 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/lib/subcmd/parse-options.h
@@ -1,8 +1,8 @@
-#ifndef __PERF_PARSE_OPTIONS_H
-#define __PERF_PARSE_OPTIONS_H
+#ifndef __SUBCMD_PARSE_OPTIONS_H
+#define __SUBCMD_PARSE_OPTIONS_H
-#include <linux/kernel.h>
#include <stdbool.h>
+#include <stdint.h>
enum parse_opt_type {
/* special types */
@@ -41,6 +41,8 @@ enum parse_opt_option_flags {
PARSE_OPT_DISABLED = 32,
PARSE_OPT_EXCLUSIVE = 64,
PARSE_OPT_NOEMPTY = 128,
+ PARSE_OPT_NOBUILD = 256,
+ PARSE_OPT_CANSKIP = 512,
};
struct option;
@@ -96,6 +98,7 @@ struct option {
void *value;
const char *argh;
const char *help;
+ const char *build_opt;
int flags;
parse_opt_cb *callback;
@@ -149,6 +152,9 @@ struct option {
/* parse_options() will filter out the processed options and leave the
* non-option argments in argv[].
* Returns the number of arguments left in argv[].
+ *
+ * NOTE: parse_options() and parse_options_subcommand() may call exit() in the
+ * case of an error (or for 'special' options like --list-cmds or --list-opts).
*/
extern int parse_options(int argc, const char **argv,
const struct option *options,
@@ -195,15 +201,6 @@ extern int parse_options_usage(const char * const *usagestr,
const char *optstr,
bool short_opt);
-extern void parse_options_start(struct parse_opt_ctx_t *ctx,
- int argc, const char **argv, int flags);
-
-extern int parse_options_step(struct parse_opt_ctx_t *ctx,
- const struct option *options,
- const char * const usagestr[]);
-
-extern int parse_options_end(struct parse_opt_ctx_t *ctx);
-
/*----- some often used options -----*/
extern int parse_opt_abbrev_cb(const struct option *, const char *, int);
@@ -226,4 +223,7 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern const char *parse_options_fix_filename(const char *prefix, const char *file);
void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
-#endif /* __PERF_PARSE_OPTIONS_H */
+void set_option_nobuild(struct option *opts, int shortopt, const char *longopt,
+ const char *build_opt, bool can_skip);
+
+#endif /* __SUBCMD_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/run-command.c b/tools/lib/subcmd/run-command.c
index 34622b5..f4f6c9e 100644
--- a/tools/perf/util/run-command.c
+++ b/tools/lib/subcmd/run-command.c
@@ -1,7 +1,15 @@
-#include "cache.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include "subcmd-util.h"
#include "run-command.h"
-#include "exec_cmd.h"
-#include "debug.h"
+#include "exec-cmd.h"
+
+#define STRERR_BUFSIZE 128
static inline void close_pair(int fd[2])
{
@@ -112,8 +120,8 @@ int start_command(struct child_process *cmd)
}
if (cmd->preexec_cb)
cmd->preexec_cb();
- if (cmd->perf_cmd) {
- execv_perf_cmd(cmd->argv);
+ if (cmd->exec_cmd) {
+ execv_cmd(cmd->argv);
} else {
execvp(cmd->argv[0], (char *const*) cmd->argv);
}
@@ -164,8 +172,8 @@ static int wait_or_whine(pid_t pid)
if (waiting < 0) {
if (errno == EINTR)
continue;
- error("waitpid failed (%s)",
- strerror_r(errno, sbuf, sizeof(sbuf)));
+ fprintf(stderr, " Error: waitpid failed (%s)",
+ strerror_r(errno, sbuf, sizeof(sbuf)));
return -ERR_RUN_COMMAND_WAITPID;
}
if (waiting != pid)
@@ -207,7 +215,7 @@ static void prepare_run_command_v_opt(struct child_process *cmd,
memset(cmd, 0, sizeof(*cmd));
cmd->argv = argv;
cmd->no_stdin = opt & RUN_COMMAND_NO_STDIN ? 1 : 0;
- cmd->perf_cmd = opt & RUN_PERF_CMD ? 1 : 0;
+ cmd->exec_cmd = opt & RUN_EXEC_CMD ? 1 : 0;
cmd->stdout_to_stderr = opt & RUN_COMMAND_STDOUT_TO_STDERR ? 1 : 0;
}
diff --git a/tools/perf/util/run-command.h b/tools/lib/subcmd/run-command.h
index 1ef264d..fe2befe 100644
--- a/tools/perf/util/run-command.h
+++ b/tools/lib/subcmd/run-command.h
@@ -1,5 +1,7 @@
-#ifndef __PERF_RUN_COMMAND_H
-#define __PERF_RUN_COMMAND_H
+#ifndef __SUBCMD_RUN_COMMAND_H
+#define __SUBCMD_RUN_COMMAND_H
+
+#include <unistd.h>
enum {
ERR_RUN_COMMAND_FORK = 10000,
@@ -41,7 +43,7 @@ struct child_process {
unsigned no_stdin:1;
unsigned no_stdout:1;
unsigned no_stderr:1;
- unsigned perf_cmd:1; /* if this is to be perf sub-command */
+ unsigned exec_cmd:1; /* if this is to be external sub-command */
unsigned stdout_to_stderr:1;
void (*preexec_cb)(void);
};
@@ -51,8 +53,8 @@ int finish_command(struct child_process *);
int run_command(struct child_process *);
#define RUN_COMMAND_NO_STDIN 1
-#define RUN_PERF_CMD 2 /*If this is to be perf sub-command */
+#define RUN_EXEC_CMD 2 /*If this is to be external sub-command */
#define RUN_COMMAND_STDOUT_TO_STDERR 4
int run_command_v_opt(const char **argv, int opt);
-#endif /* __PERF_RUN_COMMAND_H */
+#endif /* __SUBCMD_RUN_COMMAND_H */
diff --git a/tools/perf/util/sigchain.c b/tools/lib/subcmd/sigchain.c
index ba785e9..3537c34 100644
--- a/tools/perf/util/sigchain.c
+++ b/tools/lib/subcmd/sigchain.c
@@ -1,5 +1,6 @@
+#include <signal.h>
+#include "subcmd-util.h"
#include "sigchain.h"
-#include "cache.h"
#define SIGCHAIN_MAX_SIGNALS 32
diff --git a/tools/perf/util/sigchain.h b/tools/lib/subcmd/sigchain.h
index 959d64e..0c919f2 100644
--- a/tools/perf/util/sigchain.h
+++ b/tools/lib/subcmd/sigchain.h
@@ -1,5 +1,5 @@
-#ifndef __PERF_SIGCHAIN_H
-#define __PERF_SIGCHAIN_H
+#ifndef __SUBCMD_SIGCHAIN_H
+#define __SUBCMD_SIGCHAIN_H
typedef void (*sigchain_fun)(int);
@@ -7,4 +7,4 @@ int sigchain_pop(int sig);
void sigchain_push_common(sigchain_fun f);
-#endif /* __PERF_SIGCHAIN_H */
+#endif /* __SUBCMD_SIGCHAIN_H */
diff --git a/tools/lib/subcmd/subcmd-config.c b/tools/lib/subcmd/subcmd-config.c
new file mode 100644
index 0000000..d017c72
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-config.c
@@ -0,0 +1,11 @@
+#include "subcmd-config.h"
+
+#define UNDEFINED "SUBCMD_HAS_NOT_BEEN_INITIALIZED"
+
+struct subcmd_config subcmd_config = {
+ .exec_name = UNDEFINED,
+ .prefix = UNDEFINED,
+ .exec_path = UNDEFINED,
+ .exec_path_env = UNDEFINED,
+ .pager_env = UNDEFINED,
+};
diff --git a/tools/lib/subcmd/subcmd-config.h b/tools/lib/subcmd/subcmd-config.h
new file mode 100644
index 0000000..cc85140
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-config.h
@@ -0,0 +1,14 @@
+#ifndef __PERF_SUBCMD_CONFIG_H
+#define __PERF_SUBCMD_CONFIG_H
+
+struct subcmd_config {
+ const char *exec_name;
+ const char *prefix;
+ const char *exec_path;
+ const char *exec_path_env;
+ const char *pager_env;
+};
+
+extern struct subcmd_config subcmd_config;
+
+#endif /* __PERF_SUBCMD_CONFIG_H */
diff --git a/tools/lib/subcmd/subcmd-util.h b/tools/lib/subcmd/subcmd-util.h
new file mode 100644
index 0000000..fc2e45d
--- /dev/null
+++ b/tools/lib/subcmd/subcmd-util.h
@@ -0,0 +1,91 @@
+#ifndef __SUBCMD_UTIL_H
+#define __SUBCMD_UTIL_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#define NORETURN __attribute__((__noreturn__))
+
+static inline void report(const char *prefix, const char *err, va_list params)
+{
+ char msg[1024];
+ vsnprintf(msg, sizeof(msg), err, params);
+ fprintf(stderr, " %s%s\n", prefix, msg);
+}
+
+static NORETURN inline void die(const char *err, ...)
+{
+ va_list params;
+
+ va_start(params, err);
+ report(" Fatal: ", err, params);
+ exit(128);
+ va_end(params);
+}
+
+#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+
+#define alloc_nr(x) (((x)+16)*3/2)
+
+/*
+ * Realloc the buffer pointed at by variable 'x' so that it can hold
+ * at least 'nr' entries; the number of entries currently allocated
+ * is 'alloc', using the standard growing factor alloc_nr() macro.
+ *
+ * DO NOT USE any expression with side-effect for 'x' or 'alloc'.
+ */
+#define ALLOC_GROW(x, nr, alloc) \
+ do { \
+ if ((nr) > alloc) { \
+ if (alloc_nr(alloc) < (nr)) \
+ alloc = (nr); \
+ else \
+ alloc = alloc_nr(alloc); \
+ x = xrealloc((x), alloc * sizeof(*(x))); \
+ } \
+ } while(0)
+
+static inline void *xrealloc(void *ptr, size_t size)
+{
+ void *ret = realloc(ptr, size);
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+ if (!ret) {
+ ret = realloc(ptr, size);
+ if (!ret && !size)
+ ret = realloc(ptr, 1);
+ if (!ret)
+ die("Out of memory, realloc failed");
+ }
+ return ret;
+}
+
+#define astrcatf(out, fmt, ...) \
+({ \
+ char *tmp = *(out); \
+ if (asprintf((out), "%s" fmt, tmp ?: "", ## __VA_ARGS__) == -1) \
+ die("asprintf failed"); \
+ free(tmp); \
+})
+
+static inline void astrcat(char **out, const char *add)
+{
+ char *tmp = *out;
+
+ if (asprintf(out, "%s%s", tmp ?: "", add) == -1)
+ die("asprintf failed");
+
+ free(tmp);
+}
+
+static inline int prefixcmp(const char *str, const char *prefix)
+{
+ for (; ; str++, prefix++)
+ if (!*prefix)
+ return 0;
+ else if (*str != *prefix)
+ return (unsigned char)*prefix - (unsigned char)*str;
+}
+
+#endif /* __SUBCMD_UTIL_H */
diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c
index 2a912df..ea69ce3 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -4735,73 +4735,80 @@ static int is_printable_array(char *p, unsigned int len)
return 1;
}
-static void print_event_fields(struct trace_seq *s, void *data,
- int size __maybe_unused,
- struct event_format *event)
+void pevent_print_field(struct trace_seq *s, void *data,
+ struct format_field *field)
{
- struct format_field *field;
unsigned long long val;
unsigned int offset, len, i;
-
- field = event->format.fields;
- while (field) {
- trace_seq_printf(s, " %s=", field->name);
- if (field->flags & FIELD_IS_ARRAY) {
- offset = field->offset;
- len = field->size;
- if (field->flags & FIELD_IS_DYNAMIC) {
- val = pevent_read_number(event->pevent, data + offset, len);
- offset = val;
- len = offset >> 16;
- offset &= 0xffff;
- }
- if (field->flags & FIELD_IS_STRING &&
- is_printable_array(data + offset, len)) {
- trace_seq_printf(s, "%s", (char *)data + offset);
- } else {
- trace_seq_puts(s, "ARRAY[");
- for (i = 0; i < len; i++) {
- if (i)
- trace_seq_puts(s, ", ");
- trace_seq_printf(s, "%02x",
- *((unsigned char *)data + offset + i));
- }
- trace_seq_putc(s, ']');
- field->flags &= ~FIELD_IS_STRING;
- }
+ struct pevent *pevent = field->event->pevent;
+
+ if (field->flags & FIELD_IS_ARRAY) {
+ offset = field->offset;
+ len = field->size;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ val = pevent_read_number(pevent, data + offset, len);
+ offset = val;
+ len = offset >> 16;
+ offset &= 0xffff;
+ }
+ if (field->flags & FIELD_IS_STRING &&
+ is_printable_array(data + offset, len)) {
+ trace_seq_printf(s, "%s", (char *)data + offset);
} else {
- val = pevent_read_number(event->pevent, data + field->offset,
- field->size);
- if (field->flags & FIELD_IS_POINTER) {
- trace_seq_printf(s, "0x%llx", val);
- } else if (field->flags & FIELD_IS_SIGNED) {
- switch (field->size) {
- case 4:
- /*
- * If field is long then print it in hex.
- * A long usually stores pointers.
- */
- if (field->flags & FIELD_IS_LONG)
- trace_seq_printf(s, "0x%x", (int)val);
- else
- trace_seq_printf(s, "%d", (int)val);
- break;
- case 2:
- trace_seq_printf(s, "%2d", (short)val);
- break;
- case 1:
- trace_seq_printf(s, "%1d", (char)val);
- break;
- default:
- trace_seq_printf(s, "%lld", val);
- }
- } else {
+ trace_seq_puts(s, "ARRAY[");
+ for (i = 0; i < len; i++) {
+ if (i)
+ trace_seq_puts(s, ", ");
+ trace_seq_printf(s, "%02x",
+ *((unsigned char *)data + offset + i));
+ }
+ trace_seq_putc(s, ']');
+ field->flags &= ~FIELD_IS_STRING;
+ }
+ } else {
+ val = pevent_read_number(pevent, data + field->offset,
+ field->size);
+ if (field->flags & FIELD_IS_POINTER) {
+ trace_seq_printf(s, "0x%llx", val);
+ } else if (field->flags & FIELD_IS_SIGNED) {
+ switch (field->size) {
+ case 4:
+ /*
+ * If field is long then print it in hex.
+ * A long usually stores pointers.
+ */
if (field->flags & FIELD_IS_LONG)
- trace_seq_printf(s, "0x%llx", val);
+ trace_seq_printf(s, "0x%x", (int)val);
else
- trace_seq_printf(s, "%llu", val);
+ trace_seq_printf(s, "%d", (int)val);
+ break;
+ case 2:
+ trace_seq_printf(s, "%2d", (short)val);
+ break;
+ case 1:
+ trace_seq_printf(s, "%1d", (char)val);
+ break;
+ default:
+ trace_seq_printf(s, "%lld", val);
}
+ } else {
+ if (field->flags & FIELD_IS_LONG)
+ trace_seq_printf(s, "0x%llx", val);
+ else
+ trace_seq_printf(s, "%llu", val);
}
+ }
+}
+
+void pevent_print_fields(struct trace_seq *s, void *data,
+ int size __maybe_unused, struct event_format *event)
+{
+ struct format_field *field;
+
+ field = event->format.fields;
+ while (field) {
+ trace_seq_printf(s, " %s=", field->name);
+ pevent_print_field(s, data, field);
field = field->next;
}
}
@@ -4827,7 +4834,7 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
if (event->flags & EVENT_FL_FAILED) {
trace_seq_printf(s, "[FAILED TO PARSE]");
- print_event_fields(s, data, size, event);
+ pevent_print_fields(s, data, size, event);
return;
}
@@ -4968,13 +4975,12 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
sizeof(long) != 8) {
char *p;
- ls = 2;
/* make %l into %ll */
- p = strchr(format, 'l');
- if (p)
+ if (ls == 1 && (p = strchr(format, 'l')))
memmove(p+1, p, strlen(p)+1);
else if (strcmp(format, "%p") == 0)
strcpy(format, "0x%llx");
+ ls = 2;
}
switch (ls) {
case -2:
@@ -5302,7 +5308,7 @@ void pevent_event_info(struct trace_seq *s, struct event_format *event,
int print_pretty = 1;
if (event->pevent->print_raw || (event->flags & EVENT_FL_PRINTRAW))
- print_event_fields(s, record->data, record->size, event);
+ pevent_print_fields(s, record->data, record->size, event);
else {
if (event->handler && !(event->flags & EVENT_FL_NOHANDLE))
diff --git a/tools/lib/traceevent/event-parse.h b/tools/lib/traceevent/event-parse.h
index 6fc83c7..706d9bc 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -705,6 +705,10 @@ struct cmdline *pevent_data_pid_from_comm(struct pevent *pevent, const char *com
struct cmdline *next);
int pevent_cmdline_pid(struct pevent *pevent, struct cmdline *cmdline);
+void pevent_print_field(struct trace_seq *s, void *data,
+ struct format_field *field);
+void pevent_print_fields(struct trace_seq *s, void *data,
+ int size __maybe_unused, struct event_format *event);
void pevent_event_info(struct trace_seq *s, struct event_format *event,
struct pevent_record *record);
int pevent_strerror(struct pevent *pevent, enum pevent_errno errnum,
diff --git a/tools/lib/util/find_next_bit.c b/tools/lib/util/find_next_bit.c
deleted file mode 100644
index 41b44f6..0000000
--- a/tools/lib/util/find_next_bit.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/* find_next_bit.c: fallback find next bit implementation
- *
- * Copied from lib/find_next_bit.c to tools/lib/next_bit.c
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/bitops.h>
-#include <asm/types.h>
-#include <asm/byteorder.h>
-
-#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
-
-#ifndef find_next_bit
-/*
- * Find the next set bit in a memory region.
- */
-unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- const unsigned long *p = addr + BITOP_WORD(offset);
- unsigned long result = offset & ~(BITS_PER_LONG-1);
- unsigned long tmp;
-
- if (offset >= size)
- return size;
- size -= result;
- offset %= BITS_PER_LONG;
- if (offset) {
- tmp = *(p++);
- tmp &= (~0UL << offset);
- if (size < BITS_PER_LONG)
- goto found_first;
- if (tmp)
- goto found_middle;
- size -= BITS_PER_LONG;
- result += BITS_PER_LONG;
- }
- while (size & ~(BITS_PER_LONG-1)) {
- if ((tmp = *(p++)))
- goto found_middle;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
- tmp = *p;
-
-found_first:
- tmp &= (~0UL >> (BITS_PER_LONG - size));
- if (tmp == 0UL) /* Are any bits set? */
- return result + size; /* Nope. */
-found_middle:
- return result + __ffs(tmp);
-}
-#endif
-
-#ifndef find_first_bit
-/*
- * Find the first set bit in a memory region.
- */
-unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
-{
- const unsigned long *p = addr;
- unsigned long result = 0;
- unsigned long tmp;
-
- while (size & ~(BITS_PER_LONG-1)) {
- if ((tmp = *(p++)))
- goto found;
- result += BITS_PER_LONG;
- size -= BITS_PER_LONG;
- }
- if (!size)
- return result;
-
- tmp = (*p) & (~0UL >> (BITS_PER_LONG - size));
- if (tmp == 0UL) /* Are any bits set? */
- return result + size; /* Nope. */
-found:
- return result + __ffs(tmp);
-}
-#endif
diff --git a/tools/net/Makefile b/tools/net/Makefile
index ee577ea..ddf8880 100644
--- a/tools/net/Makefile
+++ b/tools/net/Makefile
@@ -4,6 +4,9 @@ CC = gcc
LEX = flex
YACC = bison
+CFLAGS += -Wall -O2
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include
+
%.yacc.c: %.y
$(YACC) -o $@ -d $<
@@ -12,15 +15,13 @@ YACC = bison
all : bpf_jit_disasm bpf_dbg bpf_asm
-bpf_jit_disasm : CFLAGS = -Wall -O2 -DPACKAGE='bpf_jit_disasm'
+bpf_jit_disasm : CFLAGS += -DPACKAGE='bpf_jit_disasm'
bpf_jit_disasm : LDLIBS = -lopcodes -lbfd -ldl
bpf_jit_disasm : bpf_jit_disasm.o
-bpf_dbg : CFLAGS = -Wall -O2
bpf_dbg : LDLIBS = -lreadline
bpf_dbg : bpf_dbg.o
-bpf_asm : CFLAGS = -Wall -O2 -I.
bpf_asm : LDLIBS =
bpf_asm : bpf_asm.o bpf_exp.yacc.o bpf_exp.lex.o
bpf_exp.lex.o : bpf_exp.yacc.c
diff --git a/tools/perf/Build b/tools/perf/Build
index 7223745..6b67e6f 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -1,5 +1,6 @@
perf-y += builtin-bench.o
perf-y += builtin-annotate.o
+perf-y += builtin-config.o
perf-y += builtin-diff.o
perf-y += builtin-evlist.o
perf-y += builtin-help.o
@@ -19,6 +20,7 @@ perf-y += builtin-kvm.o
perf-y += builtin-inject.o
perf-y += builtin-mem.o
perf-y += builtin-data.o
+perf-y += builtin-version.o
perf-$(CONFIG_AUDIT) += builtin-trace.o
perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -34,8 +36,12 @@ paths += -DPERF_MAN_PATH="BUILD_STR($(mandir_SQ))"
CFLAGS_builtin-help.o += $(paths)
CFLAGS_builtin-timechart.o += $(paths)
-CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" -include $(OUTPUT)PERF-VERSION-FILE
+CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \
+ -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" \
+ -DPREFIX="BUILD_STR($(prefix_SQ))" \
+ -include $(OUTPUT)PERF-VERSION-FILE
CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
+CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
libperf-y += util/
libperf-y += arch/
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
new file mode 100644
index 0000000..b9ca1e3
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,103 @@
+perf-config(1)
+==============
+
+NAME
+----
+perf-config - Get and set variables in a configuration file.
+
+SYNOPSIS
+--------
+[verse]
+'perf config' -l | --list
+
+DESCRIPTION
+-----------
+You can manage variables in a configuration file with this command.
+
+OPTIONS
+-------
+
+-l::
+--list::
+ Show current config variables, name and value, for all sections.
+
+CONFIGURATION FILE
+------------------
+
+The perf configuration file contains many variables to change various
+aspects of each of its tools, including output, disk usage, etc.
+The '$HOME/.perfconfig' file is used to store a per-user configuration.
+The file '$(sysconfdir)/perfconfig' can be used to
+store a system-wide default configuration.
+
+Syntax
+~~~~~~
+
+The file consist of sections. A section starts with its name
+surrounded by square brackets and continues till the next section
+begins. Each variable must be in a section, and have the form
+'name = value', for example:
+
+ [section]
+ name1 = value1
+ name2 = value2
+
+Section names are case sensitive and can contain any characters except
+newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
+respectively). Section headers can't span multiple lines.
+
+Example
+~~~~~~~
+
+Given a $HOME/.perfconfig like this:
+
+#
+# This is the config file, and
+# a '#' and ';' character indicates a comment
+#
+
+ [colors]
+ # Color variables
+ top = red, default
+ medium = green, default
+ normal = lightgray, default
+ selected = white, lightgray
+ code = blue, default
+ addr = magenta, default
+ root = white, blue
+
+ [tui]
+ # Defaults if linked with libslang
+ report = on
+ annotate = on
+ top = on
+
+ [buildid]
+ # Default, disable using /dev/null
+ dir = ~/.debug
+
+ [annotate]
+ # Defaults
+ hide_src_code = false
+ use_offset = true
+ jump_arrows = true
+ show_nr_jumps = false
+
+ [help]
+ # Format can be man, info, web or html
+ format = man
+ autocorrect = 0
+
+ [ui]
+ show-headers = true
+
+ [call-graph]
+ # fp (framepointer), dwarf
+ record-mode = fp
+ print-type = graph
+ order = caller
+ sort-key = function
+
+SEE ALSO
+--------
+linkperf:perf[1]
diff --git a/tools/perf/Documentation/perf-evlist.txt b/tools/perf/Documentation/perf-evlist.txt
index 1ceb370..6f7200f 100644
--- a/tools/perf/Documentation/perf-evlist.txt
+++ b/tools/perf/Documentation/perf-evlist.txt
@@ -32,6 +32,9 @@ OPTIONS
--group::
Show event group information.
+--trace-fields::
+ Show tracepoint field names.
+
SEE ALSO
--------
linkperf:perf-record[1], linkperf:perf-list[1],
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index e630a7d..3a1a32f 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -207,11 +207,23 @@ comma-separated list with no space: 0,1. Ranges of CPUs are specified with -: 0-
In per-thread mode with inheritance mode on (default), samples are captured only when
the thread executes on the designated CPUs. Default is to monitor all CPUs.
+-B::
+--no-buildid::
+Do not save the build ids of binaries in the perf.data files. This skips
+post processing after recording, which sometimes makes the final step in
+the recording process to take a long time, as it needs to process all
+events looking for mmap records. The downside is that it can misresolve
+symbols if the workload binaries used when recording get locally rebuilt
+or upgraded, because the only key available in this case is the
+pathname. You can also set the "record.build-id" config variable to
+'skip to have this behaviour permanently.
+
-N::
--no-buildid-cache::
Do not update the buildid cache. This saves some overhead in situations
where the information in the perf.data file (which includes buildids)
-is sufficient.
+is sufficient. You can also set the "record.build-id" config variable to
+'no-cache' to have the same effect.
-G name,...::
--cgroup name,...::
@@ -314,11 +326,17 @@ This option sets the time out limit. The default value is 500 ms.
Record context switch events i.e. events of type PERF_RECORD_SWITCH or
PERF_RECORD_SWITCH_CPU_WIDE.
---clang-path::
+--clang-path=PATH::
Path to clang binary to use for compiling BPF scriptlets.
+(enabled when BPF support is on)
---clang-opt::
+--clang-opt=OPTIONS::
Options passed to clang when compiling BPF scriptlets.
+(enabled when BPF support is on)
+
+--vmlinux=PATH::
+Specify vmlinux path which has debuginfo.
+(enabled when BPF prologue is on)
SEE ALSO
--------
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 5ce8da1..8a301f6 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,30 @@ OPTIONS
And default sort keys are changed to comm, dso_from, symbol_from, dso_to
and symbol_to, see '--branch-stack'.
+ If the data file has tracepoint event(s), following (dynamic) sort keys
+ are also available:
+ trace, trace_fields, [<event>.]<field>[/raw]
+
+ - trace: pretty printed trace output in a single column
+ - trace_fields: fields in tracepoints in separate columns
+ - <field name>: optional event and field name for a specific field
+
+ The last form consists of event and field names. If event name is
+ omitted, it searches all events for matching field name. The matched
+ field will be shown only for the event has the field. The event name
+ supports substring match so user doesn't need to specify full subsystem
+ and event name everytime. For example, 'sched:sched_switch' event can
+ be shortened to 'switch' as long as it's not ambiguous. Also event can
+ be specified by its index (starting from 1) preceded by the '%'.
+ So '%1' is the first event, '%2' is the second, and so on.
+
+ The field name can have '/raw' suffix which disables pretty printing
+ and shows raw field value like hex numbers. The --raw-trace option
+ has the same effect for all dynamic sort keys.
+
+ The default sort keys are changed to 'trace' if all events in the data
+ file are tracepoint.
+
-F::
--fields=::
Specify output field - multiple keys can be specified in CSV format.
@@ -170,17 +194,18 @@ OPTIONS
Dump raw trace in ASCII.
-g::
---call-graph=<print_type,threshold[,print_limit],order,sort_key,branch>::
+--call-graph=<print_type,threshold[,print_limit],order,sort_key[,branch],value>::
Display call chains using type, min percent threshold, print limit,
- call order, sort key and branch. Note that ordering of parameters is not
- fixed so any parement can be given in an arbitraty order. One exception
- is the print_limit which should be preceded by threshold.
+ call order, sort key, optional branch and value. Note that ordering of
+ parameters is not fixed so any parement can be given in an arbitraty order.
+ One exception is the print_limit which should be preceded by threshold.
print_type can be either:
- flat: single column, linear exposure of call chains.
- graph: use a graph tree, displaying absolute overhead rates. (default)
- fractal: like graph, but displays relative rates. Each branch of
the tree is considered as a new profiled object.
+ - folded: call chains are displayed in a line, separated by semicolons
- none: disable call chain display.
threshold is a percentage value which specifies a minimum percent to be
@@ -204,6 +229,11 @@ OPTIONS
- branch: include last branch information in callgraph when available.
Usually more convenient to use --branch-history for this.
+ value can be:
+ - percent: diplay overhead percent (default)
+ - period: display event period
+ - count: display event count
+
--children::
Accumulate callchain of children to parent entry so that then can
show up in the output. The output will have a new "Children" column
@@ -365,6 +395,9 @@ include::itrace.txt[]
--socket-filter::
Only report the samples on the processor socket that match with this filter
+--raw-trace::
+ When displaying traceevent output, do not use print fmt or plugins.
+
include::callchain-overhead-calculation.txt[]
SEE ALSO
diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt
index 4e074a6..52ef7a9 100644
--- a/tools/perf/Documentation/perf-stat.txt
+++ b/tools/perf/Documentation/perf-stat.txt
@@ -10,6 +10,8 @@ SYNOPSIS
[verse]
'perf stat' [-e <EVENT> | --event=EVENT] [-a] <command>
'perf stat' [-e <EVENT> | --event=EVENT] [-a] -- <command> [<options>]
+'perf stat' [-e <EVENT> | --event=EVENT] [-a] record [-o file] -- <command> [<options>]
+'perf stat' report [-i file]
DESCRIPTION
-----------
@@ -22,6 +24,11 @@ OPTIONS
<command>...::
Any command you can specify in a shell.
+record::
+ See STAT RECORD.
+
+report::
+ See STAT REPORT.
-e::
--event=::
@@ -159,6 +166,33 @@ filter out the startup phase of the program, which is often very different.
Print statistics of transactional execution if supported.
+STAT RECORD
+-----------
+Stores stat data into perf data file.
+
+-o file::
+--output file::
+Output file name.
+
+STAT REPORT
+-----------
+Reads and reports stat data from perf data file.
+
+-i file::
+--input file::
+Input file name.
+
+--per-socket::
+Aggregate counts per processor socket for system-wide mode measurements.
+
+--per-core::
+Aggregate counts per physical processor for system-wide mode measurements.
+
+-A::
+--no-aggr::
+Do not aggregate counts across all monitored CPUs.
+
+
EXAMPLES
--------
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt
index 556cec0..b0e60e1 100644
--- a/tools/perf/Documentation/perf-top.txt
+++ b/tools/perf/Documentation/perf-top.txt
@@ -230,6 +230,9 @@ Default is to monitor all CPUS.
The various filters must be specified as a comma separated list: --branch-filter any_ret,u,k
Note that this feature may not be available on all processors.
+--raw-trace::
+ When displaying traceevent output, do not use print fmt or plugins.
+
INTERACTIVE PROMPTING KEYS
--------------------------
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt
index 7ea0786..13293de 100644
--- a/tools/perf/Documentation/perf-trace.txt
+++ b/tools/perf/Documentation/perf-trace.txt
@@ -62,7 +62,6 @@ OPTIONS
--verbose=::
Verbosity level.
--i::
--no-inherit::
Child tasks do not inherit counters.
diff --git a/tools/perf/Documentation/tips.txt b/tools/perf/Documentation/tips.txt
new file mode 100644
index 0000000..a1c10e3
--- /dev/null
+++ b/tools/perf/Documentation/tips.txt
@@ -0,0 +1,14 @@
+For a higher level overview, try: perf report --sort comm,dso
+Sample related events with: perf record -e '{cycles,instructions}:S'
+Compare performance results with: perf diff [<old file> <new file>]
+Boolean options have negative forms, e.g.: perf report --no-children
+Customize output of perf script with: perf script -F event,ip,sym
+Generate a script for your data: perf script -g <lang>
+Save output of perf stat using: perf stat record <target workload>
+Create an archive with symtabs to analyse on other machine: perf archive
+Search options using a keyword: perf report -h <keyword>
+Use parent filter to see specific call path: perf report -p <regex>
+List events using substring match: perf list <keyword>
+To see list of saved events and attributes: perf evlist -v
+Use --symfs <dir> if your symbol files are in non-standard locations
+To see callchains in a more compact form: perf report -g folded
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 39c38cb..ddf922f 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -1,6 +1,7 @@
tools/perf
tools/arch/alpha/include/asm/barrier.h
tools/arch/arm/include/asm/barrier.h
+tools/arch/arm64/include/asm/barrier.h
tools/arch/ia64/include/asm/barrier.h
tools/arch/mips/include/asm/barrier.h
tools/arch/powerpc/include/asm/barrier.h
@@ -20,14 +21,17 @@ tools/lib/traceevent
tools/lib/bpf
tools/lib/api
tools/lib/bpf
+tools/lib/subcmd
tools/lib/hweight.c
tools/lib/rbtree.c
+tools/lib/string.c
tools/lib/symbol/kallsyms.c
tools/lib/symbol/kallsyms.h
-tools/lib/util/find_next_bit.c
+tools/lib/find_bit.c
tools/include/asm/atomic.h
tools/include/asm/barrier.h
tools/include/asm/bug.h
+tools/include/asm-generic/atomic-gcc.h
tools/include/asm-generic/barrier.h
tools/include/asm-generic/bitops/arch_hweight.h
tools/include/asm-generic/bitops/atomic.h
@@ -50,6 +54,7 @@ tools/include/linux/log2.h
tools/include/linux/poison.h
tools/include/linux/rbtree.h
tools/include/linux/rbtree_augmented.h
+tools/include/linux/string.h
tools/include/linux/types.h
tools/include/linux/err.h
include/asm-generic/bitops/arch_hweight.h
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 480546d..dcd9a70 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -78,7 +78,7 @@ clean:
# The build-test target is not really parallel, don't print the jobs info:
#
build-test:
- @$(MAKE) -f tests/make --no-print-directory
+ @$(MAKE) SHUF=1 -f tests/make --no-print-directory
#
# All other targets get passed through:
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 0d19d54..0a22407 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -145,9 +145,10 @@ BISON = bison
STRIP = strip
AWK = awk
-LIB_DIR = $(srctree)/tools/lib/api/
+LIB_DIR = $(srctree)/tools/lib/api/
TRACE_EVENT_DIR = $(srctree)/tools/lib/traceevent/
-BPF_DIR = $(srctree)/tools/lib/bpf/
+BPF_DIR = $(srctree)/tools/lib/bpf/
+SUBCMD_DIR = $(srctree)/tools/lib/subcmd/
# include config/Makefile by default and rule out
# non-config cases
@@ -184,15 +185,17 @@ strip-libs = $(filter-out -l%,$(1))
ifneq ($(OUTPUT),)
TE_PATH=$(OUTPUT)
BPF_PATH=$(OUTPUT)
+ SUBCMD_PATH=$(OUTPUT)
ifneq ($(subdir),)
- LIB_PATH=$(OUTPUT)/../lib/api/
+ API_PATH=$(OUTPUT)/../lib/api/
else
- LIB_PATH=$(OUTPUT)
+ API_PATH=$(OUTPUT)
endif
else
TE_PATH=$(TRACE_EVENT_DIR)
- LIB_PATH=$(LIB_DIR)
+ API_PATH=$(LIB_DIR)
BPF_PATH=$(BPF_DIR)
+ SUBCMD_PATH=$(SUBCMD_DIR)
endif
LIBTRACEEVENT = $(TE_PATH)libtraceevent.a
@@ -201,11 +204,13 @@ export LIBTRACEEVENT
LIBTRACEEVENT_DYNAMIC_LIST = $(TE_PATH)libtraceevent-dynamic-list
LIBTRACEEVENT_DYNAMIC_LIST_LDFLAGS = -Xlinker --dynamic-list=$(LIBTRACEEVENT_DYNAMIC_LIST)
-LIBAPI = $(LIB_PATH)libapi.a
+LIBAPI = $(API_PATH)libapi.a
export LIBAPI
LIBBPF = $(BPF_PATH)libbpf.a
+LIBSUBCMD = $(SUBCMD_PATH)libsubcmd.a
+
# python extension build directories
PYTHON_EXTBUILD := $(OUTPUT)python_ext_build/
PYTHON_EXTBUILD_LIB := $(PYTHON_EXTBUILD)lib/
@@ -257,7 +262,7 @@ export PERL_PATH
LIB_FILE=$(OUTPUT)libperf.a
-PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT)
+PERFLIBS = $(LIB_FILE) $(LIBAPI) $(LIBTRACEEVENT) $(LIBSUBCMD)
ifndef NO_LIBBPF
PERFLIBS += $(LIBBPF)
endif
@@ -420,7 +425,7 @@ $(LIBTRACEEVENT)-clean:
$(call QUIET_CLEAN, libtraceevent)
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) O=$(OUTPUT) clean >/dev/null
-install-traceevent-plugins: $(LIBTRACEEVENT)
+install-traceevent-plugins: libtraceevent_plugins
$(Q)$(MAKE) -C $(TRACE_EVENT_DIR) $(LIBTRACEEVENT_FLAGS) O=$(OUTPUT) install_plugins
$(LIBAPI): fixdep FORCE
@@ -431,12 +436,19 @@ $(LIBAPI)-clean:
$(Q)$(MAKE) -C $(LIB_DIR) O=$(OUTPUT) clean >/dev/null
$(LIBBPF): fixdep FORCE
- $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a
+ $(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) $(OUTPUT)libbpf.a FEATURES_DUMP=$(realpath $(OUTPUT)FEATURE-DUMP)
$(LIBBPF)-clean:
$(call QUIET_CLEAN, libbpf)
$(Q)$(MAKE) -C $(BPF_DIR) O=$(OUTPUT) clean >/dev/null
+$(LIBSUBCMD): fixdep FORCE
+ $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) $(OUTPUT)libsubcmd.a
+
+$(LIBSUBCMD)-clean:
+ $(call QUIET_CLEAN, libsubcmd)
+ $(Q)$(MAKE) -C $(SUBCMD_DIR) O=$(OUTPUT) clean
+
help:
@echo 'Perf make targets:'
@echo ' doc - make *all* documentation (see below)'
@@ -476,7 +488,7 @@ INSTALL_DOC_TARGETS += quick-install-doc quick-install-man quick-install-html
$(DOC_TARGETS):
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) $(@:doc=all)
-TAG_FOLDERS= . ../lib/traceevent ../lib/api ../lib/symbol ../include ../lib/bpf
+TAG_FOLDERS= . ../lib ../include
TAG_FILES= ../../include/uapi/linux/perf_event.h
TAGS:
@@ -555,6 +567,9 @@ endif
$(call QUIET_INSTALL, perf_completion-script) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d'; \
$(INSTALL) perf-completion.sh '$(DESTDIR_SQ)$(sysconfdir_SQ)/bash_completion.d/perf'
+ $(call QUIET_INSTALL, perf-tip) \
+ $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(tip_instdir_SQ)'; \
+ $(INSTALL) Documentation/tips.txt -t '$(DESTDIR_SQ)$(tip_instdir_SQ)'
install-tests: all install-gtk
$(call QUIET_INSTALL, tests) \
@@ -582,15 +597,16 @@ $(INSTALL_DOC_TARGETS):
#
config-clean:
$(call QUIET_CLEAN, config)
- $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null
+ $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null
-clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean config-clean
+clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS)
- $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
+ $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete
$(Q)$(RM) $(OUTPUT).config-detected
$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
- $(OUTPUT)util/intel-pt-decoder/inat-tables.c
+ $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
+ $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(python-clean)
diff --git a/tools/perf/arch/x86/include/arch-tests.h b/tools/perf/arch/x86/include/arch-tests.h
index 7ed00f4..b48de2f 100644
--- a/tools/perf/arch/x86/include/arch-tests.h
+++ b/tools/perf/arch/x86/include/arch-tests.h
@@ -2,10 +2,10 @@
#define ARCH_TESTS_H
/* Tests */
-int test__rdpmc(void);
-int test__perf_time_to_tsc(void);
-int test__insn_x86(void);
-int test__intel_cqm_count_nmi_context(void);
+int test__rdpmc(int subtest);
+int test__perf_time_to_tsc(int subtest);
+int test__insn_x86(int subtest);
+int test__intel_cqm_count_nmi_context(int subtest);
#ifdef HAVE_DWARF_UNWIND_SUPPORT
struct thread;
diff --git a/tools/perf/arch/x86/tests/insn-x86.c b/tools/perf/arch/x86/tests/insn-x86.c
index b6115df..08d9b2bc 100644
--- a/tools/perf/arch/x86/tests/insn-x86.c
+++ b/tools/perf/arch/x86/tests/insn-x86.c
@@ -171,7 +171,7 @@ static int test_data_set(struct test_data *dat_set, int x86_64)
* verbose (-v) option to see all the instructions and whether or not they
* decoded successfuly.
*/
-int test__insn_x86(void)
+int test__insn_x86(int subtest __maybe_unused)
{
int ret = 0;
diff --git a/tools/perf/arch/x86/tests/intel-cqm.c b/tools/perf/arch/x86/tests/intel-cqm.c
index d28c1b6..3e89ba8 100644
--- a/tools/perf/arch/x86/tests/intel-cqm.c
+++ b/tools/perf/arch/x86/tests/intel-cqm.c
@@ -33,7 +33,7 @@ static pid_t spawn(void)
* the last read counter value to avoid triggering a WARN_ON_ONCE() in
* smp_call_function_many() caused by sending IPIs from NMI context.
*/
-int test__intel_cqm_count_nmi_context(void)
+int test__intel_cqm_count_nmi_context(int subtest __maybe_unused)
{
struct perf_evlist *evlist = NULL;
struct perf_evsel *evsel = NULL;
@@ -54,7 +54,7 @@ int test__intel_cqm_count_nmi_context(void)
ret = parse_events(evlist, "intel_cqm/llc_occupancy/", NULL);
if (ret) {
- pr_debug("parse_events failed\n");
+ pr_debug("parse_events failed, is \"intel_cqm/llc_occupancy/\" available?\n");
err = TEST_SKIP;
goto out;
}
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
index 658cd20..9d29ee2 100644
--- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c
+++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c
@@ -35,13 +35,12 @@
* %0 is returned, otherwise %-1 is returned. If TSC conversion is not
* supported then then the test passes but " (not supported)" is printed.
*/
-int test__perf_time_to_tsc(void)
+int test__perf_time_to_tsc(int subtest __maybe_unused)
{
struct record_opts opts = {
.mmap_pages = UINT_MAX,
.user_freq = UINT_MAX,
.user_interval = ULLONG_MAX,
- .freq = 4000,
.target = {
.uses_mmap = true,
},
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c
index e768821..7bb0d13 100644
--- a/tools/perf/arch/x86/tests/rdpmc.c
+++ b/tools/perf/arch/x86/tests/rdpmc.c
@@ -149,7 +149,7 @@ out_close:
return 0;
}
-int test__rdpmc(void)
+int test__rdpmc(int subtest __maybe_unused)
{
int status = 0;
int wret = 0;
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index ff63649..4659703 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -5,6 +5,7 @@ libperf-y += kvm-stat.o
libperf-y += perf_regs.o
libperf-$(CONFIG_DWARF) += dwarf-regs.o
+libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o
libperf-$(CONFIG_LIBUNWIND) += unwind-libunwind.o
libperf-$(CONFIG_LIBDW_DWARF_UNWIND) += unwind-libdw.o
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c
index 9b94ce5..8d8150f 100644
--- a/tools/perf/arch/x86/util/intel-bts.c
+++ b/tools/perf/arch/x86/util/intel-bts.c
@@ -327,7 +327,7 @@ static int intel_bts_snapshot_start(struct auxtrace_record *itr)
evlist__for_each(btsr->evlist, evsel) {
if (evsel->attr.type == btsr->intel_bts_pmu->type)
- return perf_evlist__disable_event(btsr->evlist, evsel);
+ return perf_evsel__disable(evsel);
}
return -EINVAL;
}
@@ -340,7 +340,7 @@ static int intel_bts_snapshot_finish(struct auxtrace_record *itr)
evlist__for_each(btsr->evlist, evsel) {
if (evsel->attr.type == btsr->intel_bts_pmu->type)
- return perf_evlist__enable_event(btsr->evlist, evsel);
+ return perf_evsel__enable(evsel);
}
return -EINVAL;
}
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c
index b02af06..f05daac 100644
--- a/tools/perf/arch/x86/util/intel-pt.c
+++ b/tools/perf/arch/x86/util/intel-pt.c
@@ -26,7 +26,7 @@
#include "../../util/evlist.h"
#include "../../util/evsel.h"
#include "../../util/cpumap.h"
-#include "../../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../../util/parse-events.h"
#include "../../util/pmu.h"
#include "../../util/debug.h"
@@ -725,7 +725,7 @@ static int intel_pt_snapshot_start(struct auxtrace_record *itr)
evlist__for_each(ptr->evlist, evsel) {
if (evsel->attr.type == ptr->intel_pt_pmu->type)
- return perf_evlist__disable_event(ptr->evlist, evsel);
+ return perf_evsel__disable(evsel);
}
return -EINVAL;
}
@@ -738,7 +738,7 @@ static int intel_pt_snapshot_finish(struct auxtrace_record *itr)
evlist__for_each(ptr->evlist, evsel) {
if (evsel->attr.type == ptr->intel_pt_pmu->type)
- return perf_evlist__enable_event(ptr->evlist, evsel);
+ return perf_evsel__enable(evsel);
}
return -EINVAL;
}
diff --git a/tools/perf/bench/futex-hash.c b/tools/perf/bench/futex-hash.c
index fc9bebd..0999ac5 100644
--- a/tools/perf/bench/futex-hash.c
+++ b/tools/perf/bench/futex-hash.c
@@ -11,7 +11,7 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "bench.h"
#include "futex.h"
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c
index bc6a16a..6a18ce2 100644
--- a/tools/perf/bench/futex-lock-pi.c
+++ b/tools/perf/bench/futex-lock-pi.c
@@ -5,7 +5,7 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "bench.h"
#include "futex.h"
diff --git a/tools/perf/bench/futex-requeue.c b/tools/perf/bench/futex-requeue.c
index ad0d9b5..7182386 100644
--- a/tools/perf/bench/futex-requeue.c
+++ b/tools/perf/bench/futex-requeue.c
@@ -11,7 +11,7 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "bench.h"
#include "futex.h"
diff --git a/tools/perf/bench/futex-wake-parallel.c b/tools/perf/bench/futex-wake-parallel.c
index 6d8c9fa..91aaf2a 100644
--- a/tools/perf/bench/futex-wake-parallel.c
+++ b/tools/perf/bench/futex-wake-parallel.c
@@ -10,7 +10,7 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "bench.h"
#include "futex.h"
diff --git a/tools/perf/bench/futex-wake.c b/tools/perf/bench/futex-wake.c
index e5e41d3..f416bd7 100644
--- a/tools/perf/bench/futex-wake.c
+++ b/tools/perf/bench/futex-wake.c
@@ -11,7 +11,7 @@
#include "../perf.h"
#include "../util/util.h"
#include "../util/stat.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "bench.h"
#include "futex.h"
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c
index 9419b94..a91aa85 100644
--- a/tools/perf/bench/mem-functions.c
+++ b/tools/perf/bench/mem-functions.c
@@ -8,7 +8,7 @@
#include "../perf.h"
#include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/header.h"
#include "../util/cloexec.h"
#include "bench.h"
diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c
index 492df27..5049d63 100644
--- a/tools/perf/bench/numa.c
+++ b/tools/perf/bench/numa.c
@@ -7,7 +7,7 @@
#include "../perf.h"
#include "../builtin.h"
#include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../util/cloexec.h"
#include "bench.h"
diff --git a/tools/perf/bench/sched-messaging.c b/tools/perf/bench/sched-messaging.c
index d4ff1b5..bfaf950 100644
--- a/tools/perf/bench/sched-messaging.c
+++ b/tools/perf/bench/sched-messaging.c
@@ -11,7 +11,7 @@
#include "../perf.h"
#include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../builtin.h"
#include "bench.h"
diff --git a/tools/perf/bench/sched-pipe.c b/tools/perf/bench/sched-pipe.c
index 005cc28..1dc2d13 100644
--- a/tools/perf/bench/sched-pipe.c
+++ b/tools/perf/bench/sched-pipe.c
@@ -10,7 +10,7 @@
*/
#include "../perf.h"
#include "../util/util.h"
-#include "../util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "../builtin.h"
#include "bench.h"
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 2bf9b3f..cc5c126 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -21,7 +21,7 @@
#include "util/evsel.h"
#include "util/annotate.h"
#include "util/event.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/thread.h"
#include "util/sort.h"
@@ -47,7 +47,7 @@ struct perf_annotate {
};
static int perf_evsel__add_sample(struct perf_evsel *evsel,
- struct perf_sample *sample __maybe_unused,
+ struct perf_sample *sample,
struct addr_location *al,
struct perf_annotate *ann)
{
@@ -72,7 +72,10 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel,
return 0;
}
- he = __hists__add_entry(hists, al, NULL, NULL, NULL, 1, 1, 0, true);
+ sample->period = 1;
+ sample->weight = 1;
+
+ he = __hists__add_entry(hists, al, NULL, NULL, NULL, sample, true);
if (he == NULL)
return -ENOMEM;
@@ -343,18 +346,19 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
return ret;
argc = parse_options(argc, argv, options, annotate_usage, 0);
+ if (argc) {
+ /*
+ * Special case: if there's an argument left then assume that
+ * it's a symbol filter:
+ */
+ if (argc > 1)
+ usage_with_options(annotate_usage, options);
- if (annotate.use_stdio)
- use_browser = 0;
- else if (annotate.use_tui)
- use_browser = 1;
- else if (annotate.use_gtk)
- use_browser = 2;
+ annotate.sym_hist_filter = argv[0];
+ }
file.path = input_name;
- setup_browser(true);
-
annotate.session = perf_session__new(&file, false, &annotate.tool);
if (annotate.session == NULL)
return -1;
@@ -366,19 +370,17 @@ int cmd_annotate(int argc, const char **argv, const char *prefix __maybe_unused)
if (ret < 0)
goto out_delete;
- if (setup_sorting() < 0)
+ if (setup_sorting(NULL) < 0)
usage_with_options(annotate_usage, options);
- if (argc) {
- /*
- * Special case: if there's an argument left then assume that
- * it's a symbol filter:
- */
- if (argc > 1)
- usage_with_options(annotate_usage, options);
+ if (annotate.use_stdio)
+ use_browser = 0;
+ else if (annotate.use_tui)
+ use_browser = 1;
+ else if (annotate.use_gtk)
+ use_browser = 2;
- annotate.sym_hist_filter = argv[0];
- }
+ setup_browser(true);
ret = __cmd_annotate(&annotate);
diff --git a/tools/perf/builtin-bench.c b/tools/perf/builtin-bench.c
index b17aed3..a1cddc6 100644
--- a/tools/perf/builtin-bench.c
+++ b/tools/perf/builtin-bench.c
@@ -16,7 +16,7 @@
*/
#include "perf.h"
#include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "builtin.h"
#include "bench/bench.h"
diff --git a/tools/perf/builtin-buildid-cache.c b/tools/perf/builtin-buildid-cache.c
index 7b8450c..d93bff7 100644
--- a/tools/perf/builtin-buildid-cache.c
+++ b/tools/perf/builtin-buildid-cache.c
@@ -16,7 +16,7 @@
#include "util/cache.h"
#include "util/debug.h"
#include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/strlist.h"
#include "util/build-id.h"
#include "util/session.h"
diff --git a/tools/perf/builtin-buildid-list.c b/tools/perf/builtin-buildid-list.c
index 918b4de..5e914ee 100644
--- a/tools/perf/builtin-buildid-list.c
+++ b/tools/perf/builtin-buildid-list.c
@@ -12,7 +12,7 @@
#include "util/build-id.h"
#include "util/cache.h"
#include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/session.h"
#include "util/symbol.h"
#include "util/data.h"
@@ -110,7 +110,7 @@ int cmd_buildid_list(int argc, const char **argv,
setup_pager();
if (show_kernel)
- return sysfs__fprintf_build_id(stdout);
+ return !(sysfs__fprintf_build_id(stdout) > 0);
return perf_session__list_build_ids(force, with_hits);
}
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 0000000..f04e804
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,66 @@
+/*
+ * builtin-config.c
+ *
+ * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
+ *
+ */
+#include "builtin.h"
+
+#include "perf.h"
+
+#include "util/cache.h"
+#include <subcmd/parse-options.h>
+#include "util/util.h"
+#include "util/debug.h"
+
+static const char * const config_usage[] = {
+ "perf config [options]",
+ NULL
+};
+
+enum actions {
+ ACTION_LIST = 1
+} actions;
+
+static struct option config_options[] = {
+ OPT_SET_UINT('l', "list", &actions,
+ "show current config variables", ACTION_LIST),
+ OPT_END()
+};
+
+static int show_config(const char *key, const char *value,
+ void *cb __maybe_unused)
+{
+ if (value)
+ printf("%s=%s\n", key, value);
+ else
+ printf("%s\n", key);
+
+ return 0;
+}
+
+int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+ int ret = 0;
+
+ argc = parse_options(argc, argv, config_options, config_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ switch (actions) {
+ case ACTION_LIST:
+ if (argc) {
+ pr_err("Error: takes no arguments\n");
+ parse_options_usage(config_usage, config_options, "l", 1);
+ } else {
+ ret = perf_config(show_config, NULL);
+ if (ret < 0)
+ pr_err("Nothing configured, "
+ "please check your ~/.perfconfig file\n");
+ }
+ break;
+ default:
+ usage_with_options(config_usage, config_options);
+ }
+
+ return ret;
+}
diff --git a/tools/perf/builtin-data.c b/tools/perf/builtin-data.c
index d6525bc..b97bc15 100644
--- a/tools/perf/builtin-data.c
+++ b/tools/perf/builtin-data.c
@@ -2,7 +2,7 @@
#include "builtin.h"
#include "perf.h"
#include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "data-convert-bt.h"
typedef int (*data_cmd_fn_t)(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 0b180a8..36ccc2b 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -311,11 +311,11 @@ static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
}
static int hists__add_entry(struct hists *hists,
- struct addr_location *al, u64 period,
- u64 weight, u64 transaction)
+ struct addr_location *al,
+ struct perf_sample *sample)
{
- if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
- transaction, true) != NULL)
+ if (__hists__add_entry(hists, al, NULL, NULL, NULL,
+ sample, true) != NULL)
return 0;
return -ENOMEM;
}
@@ -336,8 +336,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
return -1;
}
- if (hists__add_entry(hists, &al, sample->period,
- sample->weight, sample->transaction)) {
+ if (hists__add_entry(hists, &al, sample)) {
pr_warning("problem incrementing symbol period, skipping event\n");
goto out_put;
}
@@ -1208,7 +1207,7 @@ static int ui_init(void)
BUG_ON(1);
}
- list_add(&fmt->sort_list, &perf_hpp__sort_list);
+ perf_hpp__register_sort_field(fmt);
return 0;
}
@@ -1280,7 +1279,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
sort__mode = SORT_MODE__DIFF;
- if (setup_sorting() < 0)
+ if (setup_sorting(NULL) < 0)
usage_with_options(diff_usage, options);
setup_pager();
diff --git a/tools/perf/builtin-evlist.c b/tools/perf/builtin-evlist.c
index f4d6251..8a31f51 100644
--- a/tools/perf/builtin-evlist.c
+++ b/tools/perf/builtin-evlist.c
@@ -12,7 +12,7 @@
#include "util/evlist.h"
#include "util/evsel.h"
#include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/session.h"
#include "util/data.h"
#include "util/debug.h"
@@ -26,14 +26,22 @@ static int __cmd_evlist(const char *file_name, struct perf_attr_details *details
.mode = PERF_DATA_MODE_READ,
.force = details->force,
};
+ bool has_tracepoint = false;
session = perf_session__new(&file, 0, NULL);
if (session == NULL)
return -1;
- evlist__for_each(session->evlist, pos)
+ evlist__for_each(session->evlist, pos) {
perf_evsel__fprintf(pos, details, stdout);
+ if (pos->attr.type == PERF_TYPE_TRACEPOINT)
+ has_tracepoint = true;
+ }
+
+ if (has_tracepoint && !details->trace_fields)
+ printf("# Tip: use 'perf evlist --trace-fields' to show fields for tracepoint events\n");
+
perf_session__delete(session);
return 0;
}
@@ -49,6 +57,7 @@ int cmd_evlist(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN('g', "group", &details.event_group,
"Show event group information"),
OPT_BOOLEAN('f', "force", &details.force, "don't complain, do it"),
+ OPT_BOOLEAN(0, "trace-fields", &details.trace_fields, "Show tracepoint fields"),
OPT_END()
};
const char * const evlist_usage[] = {
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index a7d588b..96c1a4c 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -6,11 +6,11 @@
#include "perf.h"
#include "util/cache.h"
#include "builtin.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "common-cmds.h"
-#include "util/parse-options.h"
-#include "util/run-command.h"
-#include "util/help.h"
+#include <subcmd/parse-options.h>
+#include <subcmd/run-command.h>
+#include <subcmd/help.h>
#include "util/debug.h"
static struct man_viewer_list {
@@ -407,7 +407,7 @@ static int get_html_page_path(struct strbuf *page_path, const char *page)
#ifndef open_html
static void open_html(const char *path)
{
- execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
+ execl_cmd("web--browse", "-c", "help.browser", path, NULL);
}
#endif
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 0a945d2..0022e02 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -18,7 +18,7 @@
#include "util/data.h"
#include "util/auxtrace.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include <linux/list.h>
@@ -675,6 +675,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.fork = perf_event__repipe,
.exit = perf_event__repipe,
.lost = perf_event__repipe,
+ .lost_samples = perf_event__repipe,
.aux = perf_event__repipe,
.itrace_start = perf_event__repipe,
.context_switch = perf_event__repipe,
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 93ce665..1180105 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -12,7 +12,7 @@
#include "util/tool.h"
#include "util/callchain.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/trace-event.h"
#include "util/data.h"
#include "util/cpumap.h"
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index dd94b4c..4418d92 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -10,7 +10,7 @@
#include "util/header.h"
#include "util/session.h"
#include "util/intlist.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/trace-event.h"
#include "util/debug.h"
#include "util/tool.h"
@@ -1351,7 +1351,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
disable_buildid_cache();
use_browser = 0;
- setup_browser(false);
if (argc) {
argc = parse_options(argc, argv, live_options,
@@ -1409,8 +1408,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm,
err = kvm_events_live_report(kvm);
out:
- exit_browser(0);
-
if (kvm->session)
perf_session__delete(kvm->session);
kvm->session = NULL;
diff --git a/tools/perf/builtin-list.c b/tools/perf/builtin-list.c
index bf679e2..5e22db4 100644
--- a/tools/perf/builtin-list.c
+++ b/tools/perf/builtin-list.c
@@ -14,7 +14,7 @@
#include "util/parse-events.h"
#include "util/cache.h"
#include "util/pmu.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
int cmd_list(int argc, const char **argv, const char *prefix __maybe_unused)
{
diff --git a/tools/perf/builtin-lock.c b/tools/perf/builtin-lock.c
index de16aae..ce3bfb4 100644
--- a/tools/perf/builtin-lock.c
+++ b/tools/perf/builtin-lock.c
@@ -9,7 +9,7 @@
#include "util/thread.h"
#include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/trace-event.h"
#include "util/debug.h"
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c
index 80170aa..3901700 100644
--- a/tools/perf/builtin-mem.c
+++ b/tools/perf/builtin-mem.c
@@ -1,7 +1,7 @@
#include "builtin.h"
#include "perf.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/trace-event.h"
#include "util/tool.h"
#include "util/session.h"
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 132afc9..9af859b 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -37,7 +37,7 @@
#include "util/strfilter.h"
#include "util/symbol.h"
#include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/probe-finder.h"
#include "util/probe-event.h"
#include "util/probe-file.h"
@@ -249,6 +249,9 @@ static int opt_show_vars(const struct option *opt,
return ret;
}
+#else
+# define opt_show_lines NULL
+# define opt_show_vars NULL
#endif
static int opt_add_probe_event(const struct option *opt,
const char *str, int unset __maybe_unused)
@@ -473,7 +476,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
opt_add_probe_event),
OPT_BOOLEAN('f', "force", &probe_conf.force_add, "forcibly add events"
" with existing name"),
-#ifdef HAVE_DWARF_SUPPORT
OPT_CALLBACK('L', "line", NULL,
"FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
"Show source code lines.", opt_show_lines),
@@ -490,7 +492,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
"directory", "path to kernel source"),
OPT_BOOLEAN('\0', "no-inlines", &probe_conf.no_inlines,
"Don't search inlined functions"),
-#endif
OPT__DRY_RUN(&probe_event_dry_run),
OPT_INTEGER('\0', "max-probes", &probe_conf.max_probes,
"Set how many probe points can be found for a probe."),
@@ -521,6 +522,16 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
#ifdef HAVE_DWARF_SUPPORT
set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
+#else
+# define set_nobuild(s, l, c) set_option_nobuild(options, s, l, "NO_DWARF=1", c)
+ set_nobuild('L', "line", false);
+ set_nobuild('V', "vars", false);
+ set_nobuild('\0', "externs", false);
+ set_nobuild('\0', "range", false);
+ set_nobuild('k', "vmlinux", true);
+ set_nobuild('s', "source", true);
+ set_nobuild('\0', "no-inlines", true);
+# undef set_nobuild
#endif
set_option_flag(options, 'F', "funcs", PARSE_OPT_EXCLUSIVE);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 199fc31..dc4e0ad 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -11,7 +11,7 @@
#include "util/build-id.h"
#include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/callchain.h"
@@ -452,6 +452,8 @@ static void record__init_features(struct record *rec)
if (!rec->opts.full_auxtrace)
perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+
+ perf_header__clear_feat(&session->header, HEADER_STAT);
}
static volatile int workload_exec_errno;
@@ -813,8 +815,12 @@ int record_parse_callchain_opt(const struct option *opt,
}
ret = parse_callchain_record_opt(arg, &callchain_param);
- if (!ret)
+ if (!ret) {
+ /* Enable data address sampling for DWARF unwind. */
+ if (callchain_param.record_mode == CALLCHAIN_DWARF)
+ record->sample_address = true;
callchain_debug();
+ }
return ret;
}
@@ -837,6 +843,19 @@ int record_callchain_opt(const struct option *opt,
static int perf_record_config(const char *var, const char *value, void *cb)
{
+ struct record *rec = cb;
+
+ if (!strcmp(var, "record.build-id")) {
+ if (!strcmp(value, "cache"))
+ rec->no_buildid_cache = false;
+ else if (!strcmp(value, "no-cache"))
+ rec->no_buildid_cache = true;
+ else if (!strcmp(value, "skip"))
+ rec->no_buildid = true;
+ else
+ return -1;
+ return 0;
+ }
if (!strcmp(var, "record.call-graph"))
var = "call-graph.record-mode"; /* fall-through */
@@ -1113,12 +1132,12 @@ struct option __record_options[] = {
"per thread proc mmap processing timeout in ms"),
OPT_BOOLEAN(0, "switch-events", &record.opts.record_switch_events,
"Record context switch events"),
-#ifdef HAVE_LIBBPF_SUPPORT
OPT_STRING(0, "clang-path", &llvm_param.clang_path, "clang path",
"clang binary to use for compiling BPF scriptlets"),
OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
"options passed to clang when compiling BPF scriptlets"),
-#endif
+ OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
+ "file", "vmlinux pathname"),
OPT_END()
};
@@ -1130,6 +1149,27 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
struct record *rec = &record;
char errbuf[BUFSIZ];
+#ifndef HAVE_LIBBPF_SUPPORT
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, "NO_LIBBPF=1", c)
+ set_nobuild('\0', "clang-path", true);
+ set_nobuild('\0', "clang-opt", true);
+# undef set_nobuild
+#endif
+
+#ifndef HAVE_BPF_PROLOGUE
+# if !defined (HAVE_DWARF_SUPPORT)
+# define REASON "NO_DWARF=1"
+# elif !defined (HAVE_LIBBPF_SUPPORT)
+# define REASON "NO_LIBBPF=1"
+# else
+# define REASON "this architecture doesn't support BPF prologue"
+# endif
+# define set_nobuild(s, l, c) set_option_nobuild(record_options, s, l, REASON, c)
+ set_nobuild('\0', "vmlinux", true);
+# undef set_nobuild
+# undef REASON
+#endif
+
rec->evlist = perf_evlist__new();
if (rec->evlist == NULL)
return -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 2853ad2..d5a42ee 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -27,7 +27,7 @@
#include "util/session.h"
#include "util/tool.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/thread.h"
@@ -44,8 +44,7 @@
struct report {
struct perf_tool tool;
struct perf_session *session;
- bool force, use_tui, use_gtk, use_stdio;
- bool hide_unresolved;
+ bool use_tui, use_gtk, use_stdio;
bool dont_use_callchains;
bool show_full_info;
bool show_threads;
@@ -146,7 +145,7 @@ static int process_sample_event(struct perf_tool *tool,
struct hist_entry_iter iter = {
.evsel = evsel,
.sample = sample,
- .hide_unresolved = rep->hide_unresolved,
+ .hide_unresolved = symbol_conf.hide_unresolved,
.add_entry_cb = hist_iter__report_callback,
};
int ret = 0;
@@ -157,7 +156,7 @@ static int process_sample_event(struct perf_tool *tool,
return -1;
}
- if (rep->hide_unresolved && al.sym == NULL)
+ if (symbol_conf.hide_unresolved && al.sym == NULL)
goto out_put;
if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
@@ -434,7 +433,7 @@ static int report__browse_hists(struct report *rep)
int ret;
struct perf_session *session = rep->session;
struct perf_evlist *evlist = session->evlist;
- const char *help = "For a higher level overview, try: perf report --sort comm,dso";
+ const char *help = perf_tip(TIPDIR);
switch (use_browser) {
case 1:
@@ -514,20 +513,26 @@ static int __cmd_report(struct report *rep)
if (rep->cpu_list) {
ret = perf_session__cpu_bitmap(session, rep->cpu_list,
rep->cpu_bitmap);
- if (ret)
+ if (ret) {
+ ui__error("failed to set cpu bitmap\n");
return ret;
+ }
}
if (rep->show_threads)
perf_read_values_init(&rep->show_threads_values);
ret = report__setup_sample_type(rep);
- if (ret)
+ if (ret) {
+ /* report__setup_sample_type() already showed error message */
return ret;
+ }
ret = perf_session__process_events(session);
- if (ret)
+ if (ret) {
+ ui__error("failed to process sample\n");
return ret;
+ }
report__warn_kptr_restrict(rep);
@@ -625,7 +630,7 @@ parse_percent_limit(const struct option *opt, const char *str,
return 0;
}
-#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function"
+#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent"
const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n"
CALLCHAIN_REPORT_HELP
@@ -678,7 +683,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"file", "vmlinux pathname"),
OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
"file", "kallsyms pathname"),
- OPT_BOOLEAN('f', "force", &report.force, "don't complain, do it"),
+ OPT_BOOLEAN('f', "force", &symbol_conf.force, "don't complain, do it"),
OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
"load module symbols - WARNING: use only with -k and LIVE kernel"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
@@ -708,7 +713,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
"Only display entries with parent-match"),
OPT_CALLBACK_DEFAULT('g', "call-graph", &report,
- "print_type,threshold[,print_limit],order,sort_key[,branch]",
+ "print_type,threshold[,print_limit],order,sort_key[,branch],value",
report_callchain_help, &report_parse_callchain_opt,
callchain_default_opt),
OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
@@ -740,7 +745,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
"separator for columns, no spaces will be added between "
"columns '.' is reserved."),
- OPT_BOOLEAN('U', "hide-unresolved", &report.hide_unresolved,
+ OPT_BOOLEAN('U', "hide-unresolved", &symbol_conf.hide_unresolved,
"Only display entries resolved to a symbol"),
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"),
@@ -783,6 +788,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"Show callgraph from reference event"),
OPT_INTEGER(0, "socket-filter", &report.socket_filter,
"only show processor socket that match with this filter"),
+ OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
+ "Show raw trace event output (do not use print fmt or plugins)"),
OPT_END()
};
struct perf_data_file file = {
@@ -796,6 +803,16 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
perf_config(report__config, &report);
argc = parse_options(argc, argv, options, report_usage, 0);
+ if (argc) {
+ /*
+ * Special case: if there's an argument left then assume that
+ * it's a symbol filter:
+ */
+ if (argc > 1)
+ usage_with_options(report_usage, options);
+
+ report.symbol_filter_str = argv[0];
+ }
if (symbol_conf.vmlinux_name &&
access(symbol_conf.vmlinux_name, R_OK)) {
@@ -832,7 +849,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
}
file.path = input_name;
- file.force = report.force;
+ file.force = symbol_conf.force;
repeat:
session = perf_session__new(&file, false, &report.tool);
@@ -882,7 +899,7 @@ repeat:
symbol_conf.cumulate_callchain = false;
}
- if (setup_sorting() < 0) {
+ if (setup_sorting(session->evlist) < 0) {
if (sort_order)
parse_options_usage(report_usage, options, "s", 1);
if (field_order)
@@ -941,17 +958,6 @@ repeat:
if (symbol__init(&session->header.env) < 0)
goto error;
- if (argc) {
- /*
- * Special case: if there's an argument left then assume that
- * it's a symbol filter:
- */
- if (argc > 1)
- usage_with_options(report_usage, options);
-
- report.symbol_filter_str = argv[0];
- }
-
sort__setup_elide(stdout);
ret = __cmd_report(&report);
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index 0ee6d90..871b55ae 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -12,7 +12,7 @@
#include "util/tool.h"
#include "util/cloexec.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/trace-event.h"
#include "util/debug.h"
@@ -1203,12 +1203,13 @@ static void output_lat_thread(struct perf_sched *sched, struct work_atoms *work_
static int pid_cmp(struct work_atoms *l, struct work_atoms *r)
{
+ if (l->thread == r->thread)
+ return 0;
if (l->thread->tid < r->thread->tid)
return -1;
if (l->thread->tid > r->thread->tid)
return 1;
-
- return 0;
+ return (int)(l->thread - r->thread);
}
static int avg_cmp(struct work_atoms *l, struct work_atoms *r)
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 72b5deb..c691214 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -3,9 +3,9 @@
#include "perf.h"
#include "util/cache.h"
#include "util/debug.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/perf_regs.h"
#include "util/session.h"
#include "util/tool.h"
@@ -18,7 +18,11 @@
#include "util/sort.h"
#include "util/data.h"
#include "util/auxtrace.h"
+#include "util/cpumap.h"
+#include "util/thread_map.h"
+#include "util/stat.h"
#include <linux/bitmap.h>
+#include "asm/bug.h"
static char const *script_name;
static char const *generate_script_lang;
@@ -32,6 +36,7 @@ static bool print_flags;
static bool nanosecs;
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
+static struct perf_stat_config stat_config;
unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH;
@@ -130,6 +135,18 @@ static struct {
.invalid_fields = PERF_OUTPUT_TRACE,
},
+
+ [PERF_TYPE_BREAKPOINT] = {
+ .user_set = false,
+
+ .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID |
+ PERF_OUTPUT_CPU | PERF_OUTPUT_TIME |
+ PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP |
+ PERF_OUTPUT_SYM | PERF_OUTPUT_DSO |
+ PERF_OUTPUT_PERIOD,
+
+ .invalid_fields = PERF_OUTPUT_TRACE,
+ },
};
static bool output_set_by_user(void)
@@ -204,6 +221,9 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel,
struct perf_event_attr *attr = &evsel->attr;
bool allow_user_set;
+ if (perf_header__has_feat(&session->header, HEADER_STAT))
+ return 0;
+
allow_user_set = perf_header__has_feat(&session->header,
HEADER_AUXTRACE);
@@ -588,8 +608,35 @@ static void print_sample_flags(u32 flags)
printf(" %-4s ", str);
}
-static void process_event(union perf_event *event, struct perf_sample *sample,
- struct perf_evsel *evsel, struct addr_location *al)
+struct perf_script {
+ struct perf_tool tool;
+ struct perf_session *session;
+ bool show_task_events;
+ bool show_mmap_events;
+ bool show_switch_events;
+ bool allocated;
+ struct cpu_map *cpus;
+ struct thread_map *threads;
+ int name_width;
+};
+
+static int perf_evlist__max_name_len(struct perf_evlist *evlist)
+{
+ struct perf_evsel *evsel;
+ int max = 0;
+
+ evlist__for_each(evlist, evsel) {
+ int len = strlen(perf_evsel__name(evsel));
+
+ max = MAX(len, max);
+ }
+
+ return max;
+}
+
+static void process_event(struct perf_script *script, union perf_event *event,
+ struct perf_sample *sample, struct perf_evsel *evsel,
+ struct addr_location *al)
{
struct thread *thread = al->thread;
struct perf_event_attr *attr = &evsel->attr;
@@ -604,7 +651,12 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
if (PRINT_FIELD(EVNAME)) {
const char *evname = perf_evsel__name(evsel);
- printf("%s: ", evname ? evname : "[unknown]");
+
+ if (!script->name_width)
+ script->name_width = perf_evlist__max_name_len(script->session->evlist);
+
+ printf("%*s: ", script->name_width,
+ evname ? evname : "[unknown]");
}
if (print_flags)
@@ -643,65 +695,81 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
printf("\n");
}
-static int default_start_script(const char *script __maybe_unused,
- int argc __maybe_unused,
- const char **argv __maybe_unused)
-{
- return 0;
-}
+static struct scripting_ops *scripting_ops;
-static int default_flush_script(void)
+static void __process_stat(struct perf_evsel *counter, u64 tstamp)
{
- return 0;
+ int nthreads = thread_map__nr(counter->threads);
+ int ncpus = perf_evsel__nr_cpus(counter);
+ int cpu, thread;
+ static int header_printed;
+
+ if (counter->system_wide)
+ nthreads = 1;
+
+ if (!header_printed) {
+ printf("%3s %8s %15s %15s %15s %15s %s\n",
+ "CPU", "THREAD", "VAL", "ENA", "RUN", "TIME", "EVENT");
+ header_printed = 1;
+ }
+
+ for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ struct perf_counts_values *counts;
+
+ counts = perf_counts(counter->counts, cpu, thread);
+
+ printf("%3d %8d %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %15" PRIu64 " %s\n",
+ counter->cpus->map[cpu],
+ thread_map__pid(counter->threads, thread),
+ counts->val,
+ counts->ena,
+ counts->run,
+ tstamp,
+ perf_evsel__name(counter));
+ }
+ }
}
-static int default_stop_script(void)
+static void process_stat(struct perf_evsel *counter, u64 tstamp)
{
- return 0;
+ if (scripting_ops && scripting_ops->process_stat)
+ scripting_ops->process_stat(&stat_config, counter, tstamp);
+ else
+ __process_stat(counter, tstamp);
}
-static int default_generate_script(struct pevent *pevent __maybe_unused,
- const char *outfile __maybe_unused)
+static void process_stat_interval(u64 tstamp)
{
- return 0;
+ if (scripting_ops && scripting_ops->process_stat_interval)
+ scripting_ops->process_stat_interval(tstamp);
}
-static struct scripting_ops default_scripting_ops = {
- .start_script = default_start_script,
- .flush_script = default_flush_script,
- .stop_script = default_stop_script,
- .process_event = process_event,
- .generate_script = default_generate_script,
-};
-
-static struct scripting_ops *scripting_ops;
-
static void setup_scripting(void)
{
setup_perl_scripting();
setup_python_scripting();
-
- scripting_ops = &default_scripting_ops;
}
static int flush_scripting(void)
{
- return scripting_ops->flush_script();
+ return scripting_ops ? scripting_ops->flush_script() : 0;
}
static int cleanup_scripting(void)
{
pr_debug("\nperf script stopped\n");
- return scripting_ops->stop_script();
+ return scripting_ops ? scripting_ops->stop_script() : 0;
}
-static int process_sample_event(struct perf_tool *tool __maybe_unused,
+static int process_sample_event(struct perf_tool *tool,
union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct machine *machine)
{
+ struct perf_script *scr = container_of(tool, struct perf_script, tool);
struct addr_location al;
if (debug_mode) {
@@ -727,20 +795,16 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,
if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
goto out_put;
- scripting_ops->process_event(event, sample, evsel, &al);
+ if (scripting_ops)
+ scripting_ops->process_event(event, sample, evsel, &al);
+ else
+ process_event(scr, event, sample, evsel, &al);
+
out_put:
addr_location__put(&al);
return 0;
}
-struct perf_script {
- struct perf_tool tool;
- struct perf_session *session;
- bool show_task_events;
- bool show_mmap_events;
- bool show_switch_events;
-};
-
static int process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist)
{
@@ -1156,6 +1220,8 @@ static int parse_output_fields(const struct option *opt __maybe_unused,
type = PERF_TYPE_TRACEPOINT;
else if (!strcmp(str, "raw"))
type = PERF_TYPE_RAW;
+ else if (!strcmp(str, "break"))
+ type = PERF_TYPE_BREAKPOINT;
else {
fprintf(stderr, "Invalid event type in field string.\n");
rc = -EINVAL;
@@ -1421,7 +1487,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused,
char first_half[BUFSIZ];
char *script_root;
- snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+ snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
scripts_dir = opendir(scripts_path);
if (!scripts_dir)
@@ -1542,7 +1608,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array)
if (!session)
return -1;
- snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+ snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
scripts_dir = opendir(scripts_path);
if (!scripts_dir) {
@@ -1600,7 +1666,7 @@ static char *get_script_path(const char *script_root, const char *suffix)
char lang_path[MAXPATHLEN];
char *__script_root;
- snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
+ snprintf(scripts_path, MAXPATHLEN, "%s/scripts", get_argv_exec_path());
scripts_dir = opendir(scripts_path);
if (!scripts_dir)
@@ -1695,6 +1761,87 @@ static void script__setup_sample_type(struct perf_script *script)
}
}
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct stat_round_event *round = &event->stat_round;
+ struct perf_evsel *counter;
+
+ evlist__for_each(session->evlist, counter) {
+ perf_stat_process_counter(&stat_config, counter);
+ process_stat(counter, round->time);
+ }
+
+ process_stat_interval(round->time);
+ return 0;
+}
+
+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ perf_event__read_stat_config(&stat_config, &event->stat_config);
+ return 0;
+}
+
+static int set_maps(struct perf_script *script)
+{
+ struct perf_evlist *evlist = script->session->evlist;
+
+ if (!script->cpus || !script->threads)
+ return 0;
+
+ if (WARN_ONCE(script->allocated, "stats double allocation\n"))
+ return -EINVAL;
+
+ perf_evlist__set_maps(evlist, script->cpus, script->threads);
+
+ if (perf_evlist__alloc_stats(evlist, true))
+ return -ENOMEM;
+
+ script->allocated = true;
+ return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+ if (script->threads) {
+ pr_warning("Extra thread map event, ignoring.\n");
+ return 0;
+ }
+
+ script->threads = thread_map__new_event(&event->thread_map);
+ if (!script->threads)
+ return -ENOMEM;
+
+ return set_maps(script);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_script *script = container_of(tool, struct perf_script, tool);
+
+ if (script->cpus) {
+ pr_warning("Extra cpu map event, ignoring.\n");
+ return 0;
+ }
+
+ script->cpus = cpu_map__new_data(&event->cpu_map.data);
+ if (!script->cpus)
+ return -ENOMEM;
+
+ return set_maps(script);
+}
+
int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
{
bool show_full_info = false;
@@ -1723,6 +1870,11 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
.auxtrace_info = perf_event__process_auxtrace_info,
.auxtrace = perf_event__process_auxtrace,
.auxtrace_error = perf_event__process_auxtrace_error,
+ .stat = perf_event__process_stat_event,
+ .stat_round = process_stat_round_event,
+ .stat_config = process_stat_config_event,
+ .thread_map = process_thread_map_event,
+ .cpu_map = process_cpu_map_event,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
@@ -1836,7 +1988,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
scripting_max_stack = itrace_synth_opts.callchain_sz;
/* make sure PERF_EXEC_PATH is set for scripts */
- perf_set_argv_exec_path(perf_exec_path());
+ set_argv_exec_path(get_argv_exec_path());
if (argc && !script_name && !rec_script_path && !rep_script_path) {
int live_pipe[2];
@@ -2076,6 +2228,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused)
flush_scripting();
out_delete:
+ perf_evlist__free_stats(session->evlist);
perf_session__delete(session);
if (script_started)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 2f438f7..7f56824 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -45,7 +45,7 @@
#include "builtin.h"
#include "util/cgroup.h"
#include "util/util.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/pmu.h"
#include "util/event.h"
@@ -59,6 +59,9 @@
#include "util/thread.h"
#include "util/thread_map.h"
#include "util/counts.h"
+#include "util/session.h"
+#include "util/tool.h"
+#include "asm/bug.h"
#include <stdlib.h>
#include <sys/prctl.h>
@@ -122,6 +125,24 @@ static bool forever = false;
static struct timespec ref_time;
static struct cpu_map *aggr_map;
static aggr_get_id_t aggr_get_id;
+static bool append_file;
+static const char *output_name;
+static int output_fd;
+
+struct perf_stat {
+ bool record;
+ struct perf_data_file file;
+ struct perf_session *session;
+ u64 bytes_written;
+ struct perf_tool tool;
+ bool maps_allocated;
+ struct cpu_map *cpus;
+ struct thread_map *threads;
+ enum aggr_mode aggr_mode;
+};
+
+static struct perf_stat perf_stat;
+#define STAT_RECORD perf_stat.record
static volatile int done = 0;
@@ -158,15 +179,43 @@ static int create_perf_stat_counter(struct perf_evsel *evsel)
attr->inherit = !no_inherit;
- if (target__has_cpu(&target))
- return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
+ /*
+ * Some events get initialized with sample_(period/type) set,
+ * like tracepoints. Clear it up for counting.
+ */
+ attr->sample_period = 0;
+
+ /*
+ * But set sample_type to PERF_SAMPLE_IDENTIFIER, which should be harmless
+ * while avoiding that older tools show confusing messages.
+ *
+ * However for pipe sessions we need to keep it zero,
+ * because script's perf_evsel__check_attr is triggered
+ * by attr->sample_type != 0, and we can't run it on
+ * stat sessions.
+ */
+ if (!(STAT_RECORD && perf_stat.file.is_pipe))
+ attr->sample_type = PERF_SAMPLE_IDENTIFIER;
- if (!target__has_task(&target) && perf_evsel__is_group_leader(evsel)) {
+ /*
+ * Disabling all counters initially, they will be enabled
+ * either manually by us or by kernel via enable_on_exec
+ * set later.
+ */
+ if (perf_evsel__is_group_leader(evsel)) {
attr->disabled = 1;
- if (!initial_delay)
+
+ /*
+ * In case of initial_delay we enable tracee
+ * events manually.
+ */
+ if (target__none(&target) && !initial_delay)
attr->enable_on_exec = 1;
}
+ if (target__has_cpu(&target))
+ return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
+
return perf_evsel__open_per_thread(evsel, evsel_list->threads);
}
@@ -182,6 +231,42 @@ static inline int nsec_counter(struct perf_evsel *evsel)
return 0;
}
+static int process_synthesized_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ if (perf_data_file__write(&perf_stat.file, event, event->header.size) < 0) {
+ pr_err("failed to write perf data, error: %m\n");
+ return -1;
+ }
+
+ perf_stat.bytes_written += event->header.size;
+ return 0;
+}
+
+static int write_stat_round_event(u64 tm, u64 type)
+{
+ return perf_event__synthesize_stat_round(NULL, tm, type,
+ process_synthesized_event,
+ NULL);
+}
+
+#define WRITE_STAT_ROUND_EVENT(time, interval) \
+ write_stat_round_event(time, PERF_STAT_ROUND_TYPE__ ## interval)
+
+#define SID(e, x, y) xyarray__entry(e->sample_id, x, y)
+
+static int
+perf_evsel__write_stat_event(struct perf_evsel *counter, u32 cpu, u32 thread,
+ struct perf_counts_values *count)
+{
+ struct perf_sample_id *sid = SID(counter, cpu, thread);
+
+ return perf_event__synthesize_stat(NULL, cpu, thread, sid->id, count,
+ process_synthesized_event, NULL);
+}
+
/*
* Read out the results of a single counter:
* do not aggregate counts across CPUs in system-wide mode
@@ -205,6 +290,13 @@ static int read_counter(struct perf_evsel *counter)
count = perf_counts(counter->counts, cpu, thread);
if (perf_evsel__read(counter, cpu, thread, count))
return -1;
+
+ if (STAT_RECORD) {
+ if (perf_evsel__write_stat_event(counter, cpu, thread, count)) {
+ pr_err("failed to write stat event\n");
+ return -1;
+ }
+ }
}
}
@@ -238,21 +330,26 @@ static void process_interval(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
diff_timespec(&rs, &ts, &ref_time);
+ if (STAT_RECORD) {
+ if (WRITE_STAT_ROUND_EVENT(rs.tv_sec * NSECS_PER_SEC + rs.tv_nsec, INTERVAL))
+ pr_err("failed to write stat round event\n");
+ }
+
print_counters(&rs, 0, NULL);
}
-static void handle_initial_delay(void)
+static void enable_counters(void)
{
- struct perf_evsel *counter;
-
- if (initial_delay) {
- const int ncpus = cpu_map__nr(evsel_list->cpus),
- nthreads = thread_map__nr(evsel_list->threads);
-
+ if (initial_delay)
usleep(initial_delay * 1000);
- evlist__for_each(evsel_list, counter)
- perf_evsel__enable(counter, ncpus, nthreads);
- }
+
+ /*
+ * We need to enable counters only if:
+ * - we don't have tracee (attaching to task or cpu)
+ * - we have initial delay configured
+ */
+ if (!target__none(&target) || initial_delay)
+ perf_evlist__enable(evsel_list);
}
static volatile int workload_exec_errno;
@@ -268,6 +365,135 @@ static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *inf
workload_exec_errno = info->si_value.sival_int;
}
+static bool has_unit(struct perf_evsel *counter)
+{
+ return counter->unit && *counter->unit;
+}
+
+static bool has_scale(struct perf_evsel *counter)
+{
+ return counter->scale != 1;
+}
+
+static int perf_stat_synthesize_config(bool is_pipe)
+{
+ struct perf_evsel *counter;
+ int err;
+
+ if (is_pipe) {
+ err = perf_event__synthesize_attrs(NULL, perf_stat.session,
+ process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize attrs.\n");
+ return err;
+ }
+ }
+
+ /*
+ * Synthesize other events stuff not carried within
+ * attr event - unit, scale, name
+ */
+ evlist__for_each(evsel_list, counter) {
+ if (!counter->supported)
+ continue;
+
+ /*
+ * Synthesize unit and scale only if it's defined.
+ */
+ if (has_unit(counter)) {
+ err = perf_event__synthesize_event_update_unit(NULL, counter, process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize evsel unit.\n");
+ return err;
+ }
+ }
+
+ if (has_scale(counter)) {
+ err = perf_event__synthesize_event_update_scale(NULL, counter, process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize evsel scale.\n");
+ return err;
+ }
+ }
+
+ if (counter->own_cpus) {
+ err = perf_event__synthesize_event_update_cpus(NULL, counter, process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize evsel scale.\n");
+ return err;
+ }
+ }
+
+ /*
+ * Name is needed only for pipe output,
+ * perf.data carries event names.
+ */
+ if (is_pipe) {
+ err = perf_event__synthesize_event_update_name(NULL, counter, process_synthesized_event);
+ if (err < 0) {
+ pr_err("Couldn't synthesize evsel name.\n");
+ return err;
+ }
+ }
+ }
+
+ err = perf_event__synthesize_thread_map2(NULL, evsel_list->threads,
+ process_synthesized_event,
+ NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize thread map.\n");
+ return err;
+ }
+
+ err = perf_event__synthesize_cpu_map(NULL, evsel_list->cpus,
+ process_synthesized_event, NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize thread map.\n");
+ return err;
+ }
+
+ err = perf_event__synthesize_stat_config(NULL, &stat_config,
+ process_synthesized_event, NULL);
+ if (err < 0) {
+ pr_err("Couldn't synthesize config.\n");
+ return err;
+ }
+
+ return 0;
+}
+
+#define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
+
+static int __store_counter_ids(struct perf_evsel *counter,
+ struct cpu_map *cpus,
+ struct thread_map *threads)
+{
+ int cpu, thread;
+
+ for (cpu = 0; cpu < cpus->nr; cpu++) {
+ for (thread = 0; thread < threads->nr; thread++) {
+ int fd = FD(counter, cpu, thread);
+
+ if (perf_evlist__id_add_fd(evsel_list, counter,
+ cpu, thread, fd) < 0)
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int store_counter_ids(struct perf_evsel *counter)
+{
+ struct cpu_map *cpus = counter->cpus;
+ struct thread_map *threads = counter->threads;
+
+ if (perf_evsel__alloc_id(counter, cpus->nr, threads->nr))
+ return -ENOMEM;
+
+ return __store_counter_ids(counter, cpus, threads);
+}
+
static int __run_perf_stat(int argc, const char **argv)
{
int interval = stat_config.interval;
@@ -278,6 +504,7 @@ static int __run_perf_stat(int argc, const char **argv)
size_t l;
int status = 0;
const bool forks = (argc > 0);
+ bool is_pipe = STAT_RECORD ? perf_stat.file.is_pipe : false;
if (interval) {
ts.tv_sec = interval / 1000;
@@ -288,7 +515,7 @@ static int __run_perf_stat(int argc, const char **argv)
}
if (forks) {
- if (perf_evlist__prepare_workload(evsel_list, &target, argv, false,
+ if (perf_evlist__prepare_workload(evsel_list, &target, argv, is_pipe,
workload_exec_failed_signal) < 0) {
perror("failed to prepare workload");
return -1;
@@ -332,6 +559,9 @@ static int __run_perf_stat(int argc, const char **argv)
l = strlen(counter->unit);
if (l > unit_width)
unit_width = l;
+
+ if (STAT_RECORD && store_counter_ids(counter))
+ return -1;
}
if (perf_evlist__apply_filters(evsel_list, &counter)) {
@@ -341,6 +571,24 @@ static int __run_perf_stat(int argc, const char **argv)
return -1;
}
+ if (STAT_RECORD) {
+ int err, fd = perf_data_file__fd(&perf_stat.file);
+
+ if (is_pipe) {
+ err = perf_header__write_pipe(perf_data_file__fd(&perf_stat.file));
+ } else {
+ err = perf_session__write_header(perf_stat.session, evsel_list,
+ fd, false);
+ }
+
+ if (err < 0)
+ return err;
+
+ err = perf_stat_synthesize_config(is_pipe);
+ if (err < 0)
+ return err;
+ }
+
/*
* Enable counters and exec the command:
*/
@@ -349,7 +597,7 @@ static int __run_perf_stat(int argc, const char **argv)
if (forks) {
perf_evlist__start_workload(evsel_list);
- handle_initial_delay();
+ enable_counters();
if (interval) {
while (!waitpid(child_pid, &status, WNOHANG)) {
@@ -368,7 +616,7 @@ static int __run_perf_stat(int argc, const char **argv)
if (WIFSIGNALED(status))
psignal(WTERMSIG(status), argv[0]);
} else {
- handle_initial_delay();
+ enable_counters();
while (!done) {
nanosleep(&ts, NULL);
if (interval)
@@ -513,15 +761,6 @@ static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
-
- if (csv_output || stat_config.interval)
- return;
-
- if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK))
- fprintf(output, " # %8.3f CPUs utilized ",
- avg / avg_stats(&walltime_nsecs_stats));
- else
- fprintf(output, " ");
}
static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
@@ -529,7 +768,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
FILE *output = stat_config.output;
double sc = evsel->scale;
const char *fmt;
- int cpu = cpu_map__id_to_cpu(id);
if (csv_output) {
fmt = sc != 1.0 ? "%.2f%s" : "%.0f%s";
@@ -542,9 +780,6 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
aggr_printout(evsel, id, nr);
- if (stat_config.aggr_mode == AGGR_GLOBAL)
- cpu = 0;
-
fprintf(output, fmt, avg, csv_sep);
if (evsel->unit)
@@ -556,12 +791,24 @@ static void abs_printout(int id, int nr, struct perf_evsel *evsel, double avg)
if (evsel->cgrp)
fprintf(output, "%s%s", csv_sep, evsel->cgrp->name);
+}
- if (csv_output || stat_config.interval)
- return;
+static void printout(int id, int nr, struct perf_evsel *counter, double uval)
+{
+ int cpu = cpu_map__id_to_cpu(id);
+
+ if (stat_config.aggr_mode == AGGR_GLOBAL)
+ cpu = 0;
- perf_stat__print_shadow_stats(output, evsel, avg, cpu,
- stat_config.aggr_mode);
+ if (nsec_counter(counter))
+ nsec_printout(id, nr, counter, uval);
+ else
+ abs_printout(id, nr, counter, uval);
+
+ if (!csv_output && !stat_config.interval)
+ perf_stat__print_shadow_stats(stat_config.output, counter,
+ uval, cpu,
+ stat_config.aggr_mode);
}
static void print_aggr(char *prefix)
@@ -617,12 +864,7 @@ static void print_aggr(char *prefix)
continue;
}
uval = val * counter->scale;
-
- if (nsec_counter(counter))
- nsec_printout(id, nr, counter, uval);
- else
- abs_printout(id, nr, counter, uval);
-
+ printout(id, nr, counter, uval);
if (!csv_output)
print_noise(counter, 1.0);
@@ -653,11 +895,7 @@ static void print_aggr_thread(struct perf_evsel *counter, char *prefix)
fprintf(output, "%s", prefix);
uval = val * counter->scale;
-
- if (nsec_counter(counter))
- nsec_printout(thread, 0, counter, uval);
- else
- abs_printout(thread, 0, counter, uval);
+ printout(thread, 0, counter, uval);
if (!csv_output)
print_noise(counter, 1.0);
@@ -707,11 +945,7 @@ static void print_counter_aggr(struct perf_evsel *counter, char *prefix)
}
uval = avg * counter->scale;
-
- if (nsec_counter(counter))
- nsec_printout(-1, 0, counter, uval);
- else
- abs_printout(-1, 0, counter, uval);
+ printout(-1, 0, counter, uval);
print_noise(counter, avg);
@@ -764,12 +998,7 @@ static void print_counter(struct perf_evsel *counter, char *prefix)
}
uval = val * counter->scale;
-
- if (nsec_counter(counter))
- nsec_printout(cpu, 0, counter, uval);
- else
- abs_printout(cpu, 0, counter, uval);
-
+ printout(cpu, 0, counter, uval);
if (!csv_output)
print_noise(counter, 1.0);
print_running(run, ena);
@@ -826,8 +1055,8 @@ static void print_header(int argc, const char **argv)
else if (target.cpu_list)
fprintf(output, "\'CPU(s) %s", target.cpu_list);
else if (!target__has_task(&target)) {
- fprintf(output, "\'%s", argv[0]);
- for (i = 1; i < argc; i++)
+ fprintf(output, "\'%s", argv ? argv[0] : "pipe");
+ for (i = 1; argv && (i < argc); i++)
fprintf(output, " %s", argv[i]);
} else if (target.pid)
fprintf(output, "process id \'%s", target.pid);
@@ -863,6 +1092,10 @@ static void print_counters(struct timespec *ts, int argc, const char **argv)
struct perf_evsel *counter;
char buf[64], *prefix = NULL;
+ /* Do not print anything if we record to the pipe. */
+ if (STAT_RECORD && perf_stat.file.is_pipe)
+ return;
+
if (interval)
print_interval(prefix = buf, ts);
else
@@ -946,6 +1179,67 @@ static int stat__set_big_num(const struct option *opt __maybe_unused,
return 0;
}
+static const struct option stat_options[] = {
+ OPT_BOOLEAN('T', "transaction", &transaction_run,
+ "hardware transaction statistics"),
+ OPT_CALLBACK('e', "event", &evsel_list, "event",
+ "event selector. use 'perf list' to list available events",
+ parse_events_option),
+ OPT_CALLBACK(0, "filter", &evsel_list, "filter",
+ "event filter", parse_filter),
+ OPT_BOOLEAN('i', "no-inherit", &no_inherit,
+ "child tasks do not inherit counters"),
+ OPT_STRING('p', "pid", &target.pid, "pid",
+ "stat events on existing process id"),
+ OPT_STRING('t', "tid", &target.tid, "tid",
+ "stat events on existing thread id"),
+ OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
+ "system-wide collection from all CPUs"),
+ OPT_BOOLEAN('g', "group", &group,
+ "put the counters into a counter group"),
+ OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
+ OPT_INCR('v', "verbose", &verbose,
+ "be more verbose (show counter open errors, etc)"),
+ OPT_INTEGER('r', "repeat", &run_count,
+ "repeat command and print average + stddev (max: 100, forever: 0)"),
+ OPT_BOOLEAN('n', "null", &null_run,
+ "null run - dont start any counters"),
+ OPT_INCR('d', "detailed", &detailed_run,
+ "detailed run - start a lot of events"),
+ OPT_BOOLEAN('S', "sync", &sync_run,
+ "call sync() before starting a run"),
+ OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
+ "print large numbers with thousands\' separators",
+ stat__set_big_num),
+ OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
+ "list of cpus to monitor in system-wide"),
+ OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
+ "disable CPU count aggregation", AGGR_NONE),
+ OPT_STRING('x', "field-separator", &csv_sep, "separator",
+ "print counts with custom separator"),
+ OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
+ "monitor event in cgroup name only", parse_cgroups),
+ OPT_STRING('o', "output", &output_name, "file", "output file name"),
+ OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
+ OPT_INTEGER(0, "log-fd", &output_fd,
+ "log output to fd, instead of stderr"),
+ OPT_STRING(0, "pre", &pre_cmd, "command",
+ "command to run prior to the measured command"),
+ OPT_STRING(0, "post", &post_cmd, "command",
+ "command to run after to the measured command"),
+ OPT_UINTEGER('I', "interval-print", &stat_config.interval,
+ "print counts at regular interval in ms (>= 10)"),
+ OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
+ "aggregate counts per processor socket", AGGR_SOCKET),
+ OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
+ "aggregate counts per physical processor core", AGGR_CORE),
+ OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
+ "aggregate counts per thread", AGGR_THREAD),
+ OPT_UINTEGER('D', "delay", &initial_delay,
+ "ms to wait before starting measurement after program start"),
+ OPT_END()
+};
+
static int perf_stat__get_socket(struct cpu_map *map, int cpu)
{
return cpu_map__get_socket(map, cpu, NULL);
@@ -1032,6 +1326,109 @@ static int perf_stat_init_aggr_mode(void)
return cpus_aggr_map ? 0 : -ENOMEM;
}
+static void perf_stat__exit_aggr_mode(void)
+{
+ cpu_map__put(aggr_map);
+ cpu_map__put(cpus_aggr_map);
+ aggr_map = NULL;
+ cpus_aggr_map = NULL;
+}
+
+static inline int perf_env__get_cpu(struct perf_env *env, struct cpu_map *map, int idx)
+{
+ int cpu;
+
+ if (idx > map->nr)
+ return -1;
+
+ cpu = map->map[idx];
+
+ if (cpu >= env->nr_cpus_online)
+ return -1;
+
+ return cpu;
+}
+
+static int perf_env__get_socket(struct cpu_map *map, int idx, void *data)
+{
+ struct perf_env *env = data;
+ int cpu = perf_env__get_cpu(env, map, idx);
+
+ return cpu == -1 ? -1 : env->cpu[cpu].socket_id;
+}
+
+static int perf_env__get_core(struct cpu_map *map, int idx, void *data)
+{
+ struct perf_env *env = data;
+ int core = -1, cpu = perf_env__get_cpu(env, map, idx);
+
+ if (cpu != -1) {
+ int socket_id = env->cpu[cpu].socket_id;
+
+ /*
+ * Encode socket in upper 16 bits
+ * core_id is relative to socket, and
+ * we need a global id. So we combine
+ * socket + core id.
+ */
+ core = (socket_id << 16) | (env->cpu[cpu].core_id & 0xffff);
+ }
+
+ return core;
+}
+
+static int perf_env__build_socket_map(struct perf_env *env, struct cpu_map *cpus,
+ struct cpu_map **sockp)
+{
+ return cpu_map__build_map(cpus, sockp, perf_env__get_socket, env);
+}
+
+static int perf_env__build_core_map(struct perf_env *env, struct cpu_map *cpus,
+ struct cpu_map **corep)
+{
+ return cpu_map__build_map(cpus, corep, perf_env__get_core, env);
+}
+
+static int perf_stat__get_socket_file(struct cpu_map *map, int idx)
+{
+ return perf_env__get_socket(map, idx, &perf_stat.session->header.env);
+}
+
+static int perf_stat__get_core_file(struct cpu_map *map, int idx)
+{
+ return perf_env__get_core(map, idx, &perf_stat.session->header.env);
+}
+
+static int perf_stat_init_aggr_mode_file(struct perf_stat *st)
+{
+ struct perf_env *env = &st->session->header.env;
+
+ switch (stat_config.aggr_mode) {
+ case AGGR_SOCKET:
+ if (perf_env__build_socket_map(env, evsel_list->cpus, &aggr_map)) {
+ perror("cannot build socket map");
+ return -1;
+ }
+ aggr_get_id = perf_stat__get_socket_file;
+ break;
+ case AGGR_CORE:
+ if (perf_env__build_core_map(env, evsel_list->cpus, &aggr_map)) {
+ perror("cannot build core map");
+ return -1;
+ }
+ aggr_get_id = perf_stat__get_core_file;
+ break;
+ case AGGR_NONE:
+ case AGGR_GLOBAL:
+ case AGGR_THREAD:
+ case AGGR_UNSET:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
/*
* Add default attributes, if there were no attributes specified or
* if -d/--detailed, -d -d or -d -d -d is used:
@@ -1191,71 +1588,227 @@ static int add_default_attributes(void)
return perf_evlist__add_default_attrs(evsel_list, very_very_detailed_attrs);
}
-int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
+static const char * const recort_usage[] = {
+ "perf stat record [<options>]",
+ NULL,
+};
+
+static void init_features(struct perf_session *session)
+{
+ int feat;
+
+ for (feat = HEADER_FIRST_FEATURE; feat < HEADER_LAST_FEATURE; feat++)
+ perf_header__set_feat(&session->header, feat);
+
+ perf_header__clear_feat(&session->header, HEADER_BUILD_ID);
+ perf_header__clear_feat(&session->header, HEADER_TRACING_DATA);
+ perf_header__clear_feat(&session->header, HEADER_BRANCH_STACK);
+ perf_header__clear_feat(&session->header, HEADER_AUXTRACE);
+}
+
+static int __cmd_record(int argc, const char **argv)
+{
+ struct perf_session *session;
+ struct perf_data_file *file = &perf_stat.file;
+
+ argc = parse_options(argc, argv, stat_options, record_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (output_name)
+ file->path = output_name;
+
+ if (run_count != 1 || forever) {
+ pr_err("Cannot use -r option with perf stat record.\n");
+ return -1;
+ }
+
+ session = perf_session__new(file, false, NULL);
+ if (session == NULL) {
+ pr_err("Perf session creation failed.\n");
+ return -1;
+ }
+
+ init_features(session);
+
+ session->evlist = evsel_list;
+ perf_stat.session = session;
+ perf_stat.record = true;
+ return argc;
+}
+
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct stat_round_event *round = &event->stat_round;
+ struct perf_evsel *counter;
+ struct timespec tsh, *ts = NULL;
+ const char **argv = session->header.env.cmdline_argv;
+ int argc = session->header.env.nr_cmdline;
+
+ evlist__for_each(evsel_list, counter)
+ perf_stat_process_counter(&stat_config, counter);
+
+ if (round->type == PERF_STAT_ROUND_TYPE__FINAL)
+ update_stats(&walltime_nsecs_stats, round->time);
+
+ if (stat_config.interval && round->time) {
+ tsh.tv_sec = round->time / NSECS_PER_SEC;
+ tsh.tv_nsec = round->time % NSECS_PER_SEC;
+ ts = &tsh;
+ }
+
+ print_counters(ts, argc, argv);
+ return 0;
+}
+
+static
+int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+
+ perf_event__read_stat_config(&stat_config, &event->stat_config);
+
+ if (cpu_map__empty(st->cpus)) {
+ if (st->aggr_mode != AGGR_UNSET)
+ pr_warning("warning: processing task data, aggregation mode not set\n");
+ return 0;
+ }
+
+ if (st->aggr_mode != AGGR_UNSET)
+ stat_config.aggr_mode = st->aggr_mode;
+
+ if (perf_stat.file.is_pipe)
+ perf_stat_init_aggr_mode();
+ else
+ perf_stat_init_aggr_mode_file(st);
+
+ return 0;
+}
+
+static int set_maps(struct perf_stat *st)
+{
+ if (!st->cpus || !st->threads)
+ return 0;
+
+ if (WARN_ONCE(st->maps_allocated, "stats double allocation\n"))
+ return -EINVAL;
+
+ perf_evlist__set_maps(evsel_list, st->cpus, st->threads);
+
+ if (perf_evlist__alloc_stats(evsel_list, true))
+ return -ENOMEM;
+
+ st->maps_allocated = true;
+ return 0;
+}
+
+static
+int process_thread_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
{
- bool append_file = false;
- int output_fd = 0;
- const char *output_name = NULL;
+ struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+
+ if (st->threads) {
+ pr_warning("Extra thread map event, ignoring.\n");
+ return 0;
+ }
+
+ st->threads = thread_map__new_event(&event->thread_map);
+ if (!st->threads)
+ return -ENOMEM;
+
+ return set_maps(st);
+}
+
+static
+int process_cpu_map_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session __maybe_unused)
+{
+ struct perf_stat *st = container_of(tool, struct perf_stat, tool);
+ struct cpu_map *cpus;
+
+ if (st->cpus) {
+ pr_warning("Extra cpu map event, ignoring.\n");
+ return 0;
+ }
+
+ cpus = cpu_map__new_data(&event->cpu_map.data);
+ if (!cpus)
+ return -ENOMEM;
+
+ st->cpus = cpus;
+ return set_maps(st);
+}
+
+static const char * const report_usage[] = {
+ "perf stat report [<options>]",
+ NULL,
+};
+
+static struct perf_stat perf_stat = {
+ .tool = {
+ .attr = perf_event__process_attr,
+ .event_update = perf_event__process_event_update,
+ .thread_map = process_thread_map_event,
+ .cpu_map = process_cpu_map_event,
+ .stat_config = process_stat_config_event,
+ .stat = perf_event__process_stat_event,
+ .stat_round = process_stat_round_event,
+ },
+ .aggr_mode = AGGR_UNSET,
+};
+
+static int __cmd_report(int argc, const char **argv)
+{
+ struct perf_session *session;
const struct option options[] = {
- OPT_BOOLEAN('T', "transaction", &transaction_run,
- "hardware transaction statistics"),
- OPT_CALLBACK('e', "event", &evsel_list, "event",
- "event selector. use 'perf list' to list available events",
- parse_events_option),
- OPT_CALLBACK(0, "filter", &evsel_list, "filter",
- "event filter", parse_filter),
- OPT_BOOLEAN('i', "no-inherit", &no_inherit,
- "child tasks do not inherit counters"),
- OPT_STRING('p', "pid", &target.pid, "pid",
- "stat events on existing process id"),
- OPT_STRING('t', "tid", &target.tid, "tid",
- "stat events on existing thread id"),
- OPT_BOOLEAN('a', "all-cpus", &target.system_wide,
- "system-wide collection from all CPUs"),
- OPT_BOOLEAN('g', "group", &group,
- "put the counters into a counter group"),
- OPT_BOOLEAN('c', "scale", &stat_config.scale, "scale/normalize counters"),
- OPT_INCR('v', "verbose", &verbose,
- "be more verbose (show counter open errors, etc)"),
- OPT_INTEGER('r', "repeat", &run_count,
- "repeat command and print average + stddev (max: 100, forever: 0)"),
- OPT_BOOLEAN('n', "null", &null_run,
- "null run - dont start any counters"),
- OPT_INCR('d', "detailed", &detailed_run,
- "detailed run - start a lot of events"),
- OPT_BOOLEAN('S', "sync", &sync_run,
- "call sync() before starting a run"),
- OPT_CALLBACK_NOOPT('B', "big-num", NULL, NULL,
- "print large numbers with thousands\' separators",
- stat__set_big_num),
- OPT_STRING('C', "cpu", &target.cpu_list, "cpu",
- "list of cpus to monitor in system-wide"),
- OPT_SET_UINT('A', "no-aggr", &stat_config.aggr_mode,
- "disable CPU count aggregation", AGGR_NONE),
- OPT_STRING('x', "field-separator", &csv_sep, "separator",
- "print counts with custom separator"),
- OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
- "monitor event in cgroup name only", parse_cgroups),
- OPT_STRING('o', "output", &output_name, "file", "output file name"),
- OPT_BOOLEAN(0, "append", &append_file, "append to the output file"),
- OPT_INTEGER(0, "log-fd", &output_fd,
- "log output to fd, instead of stderr"),
- OPT_STRING(0, "pre", &pre_cmd, "command",
- "command to run prior to the measured command"),
- OPT_STRING(0, "post", &post_cmd, "command",
- "command to run after to the measured command"),
- OPT_UINTEGER('I', "interval-print", &stat_config.interval,
- "print counts at regular interval in ms (>= 10)"),
- OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode,
+ OPT_STRING('i', "input", &input_name, "file", "input file name"),
+ OPT_SET_UINT(0, "per-socket", &perf_stat.aggr_mode,
"aggregate counts per processor socket", AGGR_SOCKET),
- OPT_SET_UINT(0, "per-core", &stat_config.aggr_mode,
+ OPT_SET_UINT(0, "per-core", &perf_stat.aggr_mode,
"aggregate counts per physical processor core", AGGR_CORE),
- OPT_SET_UINT(0, "per-thread", &stat_config.aggr_mode,
- "aggregate counts per thread", AGGR_THREAD),
- OPT_UINTEGER('D', "delay", &initial_delay,
- "ms to wait before starting measurement after program start"),
+ OPT_SET_UINT('A', "no-aggr", &perf_stat.aggr_mode,
+ "disable CPU count aggregation", AGGR_NONE),
OPT_END()
};
+ struct stat st;
+ int ret;
+
+ argc = parse_options(argc, argv, options, report_usage, 0);
+
+ if (!input_name || !strlen(input_name)) {
+ if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
+ input_name = "-";
+ else
+ input_name = "perf.data";
+ }
+
+ perf_stat.file.path = input_name;
+ perf_stat.file.mode = PERF_DATA_MODE_READ;
+
+ session = perf_session__new(&perf_stat.file, false, &perf_stat.tool);
+ if (session == NULL)
+ return -1;
+
+ perf_stat.session = session;
+ stat_config.output = stderr;
+ evsel_list = session->evlist;
+
+ ret = perf_session__process_events(session);
+ if (ret)
+ return ret;
+
+ perf_session__delete(session);
+ return 0;
+}
+
+int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
+{
const char * const stat_usage[] = {
"perf stat [<options>] [<command>]",
NULL
@@ -1264,6 +1817,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
const char *mode;
FILE *output = stderr;
unsigned int interval;
+ const char * const stat_subcommands[] = { "record", "report" };
setlocale(LC_ALL, "");
@@ -1271,24 +1825,42 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (evsel_list == NULL)
return -ENOMEM;
- argc = parse_options(argc, argv, options, stat_usage,
- PARSE_OPT_STOP_AT_NON_OPTION);
+ argc = parse_options_subcommand(argc, argv, stat_options, stat_subcommands,
+ (const char **) stat_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ if (csv_sep) {
+ csv_output = true;
+ if (!strcmp(csv_sep, "\\t"))
+ csv_sep = "\t";
+ } else
+ csv_sep = DEFAULT_SEPARATOR;
+
+ if (argc && !strncmp(argv[0], "rec", 3)) {
+ argc = __cmd_record(argc, argv);
+ if (argc < 0)
+ return -1;
+ } else if (argc && !strncmp(argv[0], "rep", 3))
+ return __cmd_report(argc, argv);
interval = stat_config.interval;
- if (output_name && strcmp(output_name, "-"))
+ /*
+ * For record command the -o is already taken care of.
+ */
+ if (!STAT_RECORD && output_name && strcmp(output_name, "-"))
output = NULL;
if (output_name && output_fd) {
fprintf(stderr, "cannot use both --output and --log-fd\n");
- parse_options_usage(stat_usage, options, "o", 1);
- parse_options_usage(NULL, options, "log-fd", 0);
+ parse_options_usage(stat_usage, stat_options, "o", 1);
+ parse_options_usage(NULL, stat_options, "log-fd", 0);
goto out;
}
if (output_fd < 0) {
fprintf(stderr, "argument to --log-fd must be a > 0\n");
- parse_options_usage(stat_usage, options, "log-fd", 0);
+ parse_options_usage(stat_usage, stat_options, "log-fd", 0);
goto out;
}
@@ -1314,13 +1886,6 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
stat_config.output = output;
- if (csv_sep) {
- csv_output = true;
- if (!strcmp(csv_sep, "\\t"))
- csv_sep = "\t";
- } else
- csv_sep = DEFAULT_SEPARATOR;
-
/*
* let the spreadsheet do the pretty-printing
*/
@@ -1328,8 +1893,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
/* User explicitly passed -B? */
if (big_num_opt == 1) {
fprintf(stderr, "-B option not supported with -x\n");
- parse_options_usage(stat_usage, options, "B", 1);
- parse_options_usage(NULL, options, "x", 1);
+ parse_options_usage(stat_usage, stat_options, "B", 1);
+ parse_options_usage(NULL, stat_options, "x", 1);
goto out;
} else /* Nope, so disable big number formatting */
big_num = false;
@@ -1337,11 +1902,11 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
big_num = false;
if (!argc && target__none(&target))
- usage_with_options(stat_usage, options);
+ usage_with_options(stat_usage, stat_options);
if (run_count < 0) {
pr_err("Run count must be a positive number\n");
- parse_options_usage(stat_usage, options, "r", 1);
+ parse_options_usage(stat_usage, stat_options, "r", 1);
goto out;
} else if (run_count == 0) {
forever = true;
@@ -1351,8 +1916,8 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if ((stat_config.aggr_mode == AGGR_THREAD) && !target__has_task(&target)) {
fprintf(stderr, "The --per-thread option is only available "
"when monitoring via -p -t options.\n");
- parse_options_usage(NULL, options, "p", 1);
- parse_options_usage(NULL, options, "t", 1);
+ parse_options_usage(NULL, stat_options, "p", 1);
+ parse_options_usage(NULL, stat_options, "t", 1);
goto out;
}
@@ -1366,9 +1931,9 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
fprintf(stderr, "both cgroup and no-aggregation "
"modes only available in system-wide mode\n");
- parse_options_usage(stat_usage, options, "G", 1);
- parse_options_usage(NULL, options, "A", 1);
- parse_options_usage(NULL, options, "a", 1);
+ parse_options_usage(stat_usage, stat_options, "G", 1);
+ parse_options_usage(NULL, stat_options, "A", 1);
+ parse_options_usage(NULL, stat_options, "a", 1);
goto out;
}
@@ -1380,12 +1945,12 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (perf_evlist__create_maps(evsel_list, &target) < 0) {
if (target__has_task(&target)) {
pr_err("Problems finding threads of monitor\n");
- parse_options_usage(stat_usage, options, "p", 1);
- parse_options_usage(NULL, options, "t", 1);
+ parse_options_usage(stat_usage, stat_options, "p", 1);
+ parse_options_usage(NULL, stat_options, "t", 1);
} else if (target__has_cpu(&target)) {
perror("failed to parse CPUs map");
- parse_options_usage(stat_usage, options, "C", 1);
- parse_options_usage(NULL, options, "a", 1);
+ parse_options_usage(stat_usage, stat_options, "C", 1);
+ parse_options_usage(NULL, stat_options, "a", 1);
}
goto out;
}
@@ -1400,7 +1965,7 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (interval && interval < 100) {
if (interval < 10) {
pr_err("print interval must be >= 10ms\n");
- parse_options_usage(stat_usage, options, "I", 1);
+ parse_options_usage(stat_usage, stat_options, "I", 1);
goto out;
} else
pr_warning("print interval < 100ms. "
@@ -1443,6 +2008,42 @@ int cmd_stat(int argc, const char **argv, const char *prefix __maybe_unused)
if (!forever && status != -1 && !interval)
print_counters(NULL, argc, argv);
+ if (STAT_RECORD) {
+ /*
+ * We synthesize the kernel mmap record just so that older tools
+ * don't emit warnings about not being able to resolve symbols
+ * due to /proc/sys/kernel/kptr_restrict settings and instear provide
+ * a saner message about no samples being in the perf.data file.
+ *
+ * This also serves to suppress a warning about f_header.data.size == 0
+ * in header.c at the moment 'perf stat record' gets introduced, which
+ * is not really needed once we start adding the stat specific PERF_RECORD_
+ * records, but the need to suppress the kptr_restrict messages in older
+ * tools remain -acme
+ */
+ int fd = perf_data_file__fd(&perf_stat.file);
+ int err = perf_event__synthesize_kernel_mmap((void *)&perf_stat,
+ process_synthesized_event,
+ &perf_stat.session->machines.host);
+ if (err) {
+ pr_warning("Couldn't synthesize the kernel mmap record, harmless, "
+ "older tools may produce warnings about this file\n.");
+ }
+
+ if (!interval) {
+ if (WRITE_STAT_ROUND_EVENT(walltime_nsecs_stats.max, FINAL))
+ pr_err("failed to write stat round event\n");
+ }
+
+ if (!perf_stat.file.is_pipe) {
+ perf_stat.session->header.data_size += perf_stat.bytes_written;
+ perf_session__write_header(perf_stat.session, evsel_list, fd, true);
+ }
+
+ perf_session__delete(perf_stat.session);
+ }
+
+ perf_stat__exit_aggr_mode();
perf_evlist__free_stats(evsel_list);
out:
perf_evlist__delete(evsel_list);
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 30e5962..bd7a775 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -30,7 +30,7 @@
#include "perf.h"
#include "util/header.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/event.h"
#include "util/session.h"
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 7e2e72e..bf01cbb 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -34,7 +34,7 @@
#include "util/top.h"
#include "util/util.h"
#include <linux/rbtree.h>
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-events.h"
#include "util/cpumap.h"
#include "util/xyarray.h"
@@ -175,42 +175,40 @@ static void perf_top__record_precise_ip(struct perf_top *top,
int counter, u64 ip)
{
struct annotation *notes;
- struct symbol *sym;
+ struct symbol *sym = he->ms.sym;
int err = 0;
- if (he == NULL || he->ms.sym == NULL ||
- ((top->sym_filter_entry == NULL ||
- top->sym_filter_entry->ms.sym != he->ms.sym) && use_browser != 1))
+ if (sym == NULL || (use_browser == 0 &&
+ (top->sym_filter_entry == NULL ||
+ top->sym_filter_entry->ms.sym != sym)))
return;
- sym = he->ms.sym;
notes = symbol__annotation(sym);
if (pthread_mutex_trylock(&notes->lock))
return;
- ip = he->ms.map->map_ip(he->ms.map, ip);
-
- if (ui__has_annotation())
- err = hist_entry__inc_addr_samples(he, counter, ip);
+ err = hist_entry__inc_addr_samples(he, counter, ip);
pthread_mutex_unlock(&notes->lock);
- /*
- * This function is now called with he->hists->lock held.
- * Release it before going to sleep.
- */
- pthread_mutex_unlock(&he->hists->lock);
+ if (unlikely(err)) {
+ /*
+ * This function is now called with he->hists->lock held.
+ * Release it before going to sleep.
+ */
+ pthread_mutex_unlock(&he->hists->lock);
+
+ if (err == -ERANGE && !he->ms.map->erange_warned)
+ ui__warn_map_erange(he->ms.map, sym, ip);
+ else if (err == -ENOMEM) {
+ pr_err("Not enough memory for annotating '%s' symbol!\n",
+ sym->name);
+ sleep(1);
+ }
- if (err == -ERANGE && !he->ms.map->erange_warned)
- ui__warn_map_erange(he->ms.map, sym, ip);
- else if (err == -ENOMEM) {
- pr_err("Not enough memory for annotating '%s' symbol!\n",
- sym->name);
- sleep(1);
+ pthread_mutex_lock(&he->hists->lock);
}
-
- pthread_mutex_lock(&he->hists->lock);
}
static void perf_top__show_details(struct perf_top *top)
@@ -687,14 +685,8 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter,
struct hist_entry *he = iter->he;
struct perf_evsel *evsel = iter->evsel;
- if (sort__has_sym && single) {
- u64 ip = al->addr;
-
- if (al->map)
- ip = al->map->unmap_ip(al->map, ip);
-
- perf_top__record_precise_ip(top, he, evsel->idx, ip);
- }
+ if (sort__has_sym && single)
+ perf_top__record_precise_ip(top, he, evsel->idx, al->addr);
hist__account_cycles(iter->sample->branch_stack, al, iter->sample,
!(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY));
@@ -964,7 +956,7 @@ static int __cmd_top(struct perf_top *top)
if (ret)
goto out_delete;
- if (perf_session__register_idle_thread(top->session) == NULL)
+ if (perf_session__register_idle_thread(top->session) < 0)
goto out_delete;
machine__synthesize_threads(&top->session->machines.host, &opts->target,
@@ -1218,6 +1210,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_CALLBACK('j', "branch-filter", &opts->branch_stack,
"branch filter mask", "branch stack filter modes",
parse_branch_stack),
+ OPT_BOOLEAN(0, "raw-trace", &symbol_conf.raw_trace,
+ "Show raw trace event output (do not use print fmt or plugins)"),
OPT_END()
};
const char * const top_usage[] = {
@@ -1239,11 +1233,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc)
usage_with_options(top_usage, options);
+ if (!top.evlist->nr_entries &&
+ perf_evlist__add_default(top.evlist) < 0) {
+ pr_err("Not enough memory for event selector list\n");
+ goto out_delete_evlist;
+ }
+
sort__mode = SORT_MODE__TOP;
/* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
- if (setup_sorting() < 0) {
+ if (setup_sorting(top.evlist) < 0) {
if (sort_order)
parse_options_usage(top_usage, options, "s", 1);
if (field_order)
@@ -1279,12 +1279,9 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (target__none(target))
target->system_wide = true;
- if (perf_evlist__create_maps(top.evlist, target) < 0)
- usage_with_options(top_usage, options);
-
- if (!top.evlist->nr_entries &&
- perf_evlist__add_default(top.evlist) < 0) {
- ui__error("Not enough memory for event selector list\n");
+ if (perf_evlist__create_maps(top.evlist, target) < 0) {
+ ui__error("Couldn't create thread/CPU maps: %s\n",
+ errno == ENOENT ? "No such process" : strerror_r(errno, errbuf, sizeof(errbuf)));
goto out_delete_evlist;
}
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index c783d8f..20916dd 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -22,11 +22,11 @@
#include "util/color.h"
#include "util/debug.h"
#include "util/evlist.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "util/machine.h"
#include "util/session.h"
#include "util/thread.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/strlist.h"
#include "util/intlist.h"
#include "util/thread_map.h"
diff --git a/tools/perf/builtin-version.c b/tools/perf/builtin-version.c
new file mode 100644
index 0000000..9b10cda
--- /dev/null
+++ b/tools/perf/builtin-version.c
@@ -0,0 +1,10 @@
+#include "util/util.h"
+#include "builtin.h"
+#include "perf.h"
+
+int cmd_version(int argc __maybe_unused, const char **argv __maybe_unused,
+ const char *prefix __maybe_unused)
+{
+ printf("perf version %s\n", perf_version_string);
+ return 0;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad2..3f871b5 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_bench(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
+extern int cmd_config(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
extern int cmd_evlist(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8..ab5cbaa 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common
perf-data mainporcelain common
perf-diff mainporcelain common
+perf-config mainporcelain common
perf-evlist mainporcelain common
perf-inject mainporcelain common
perf-kmem mainporcelain common
@@ -25,4 +26,4 @@ perf-stat mainporcelain common
perf-test mainporcelain common
perf-timechart mainporcelain common
perf-top mainporcelain common
-perf-trace mainporcelain common
+perf-trace mainporcelain audit
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index de89ec5..254d06e 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -135,8 +135,6 @@ endif
ifeq ($(DEBUG),0)
CFLAGS += -O6
-else
- CFLAGS += $(call cc-option,-Og,-O0)
endif
ifdef PARSER_DEBUG
@@ -318,6 +316,18 @@ ifndef NO_LIBELF
CFLAGS += -DHAVE_LIBBPF_SUPPORT
$(call detected,CONFIG_LIBBPF)
endif
+
+ ifndef NO_DWARF
+ ifdef PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET
+ CFLAGS += -DHAVE_BPF_PROLOGUE
+ $(call detected,CONFIG_BPF_PROLOGUE)
+ else
+ msg := $(warning BPF prologue is not supported by architecture $(ARCH), missing regs_query_register_offset());
+ endif
+ else
+ msg := $(warning DWARF support is off, BPF prologue is disabled);
+ endif
+
endif # NO_LIBBPF
endif # NO_LIBELF
@@ -681,6 +691,7 @@ sharedir = $(prefix)/share
template_dir = share/perf-core/templates
STRACE_GROUPS_DIR = share/perf-core/strace/groups
htmldir = share/doc/perf-doc
+tipdir = share/doc/perf-tip
ifeq ($(prefix),/usr)
sysconfdir = /etc
ETC_PERFCONFIG = $(sysconfdir)/perfconfig
@@ -707,6 +718,7 @@ infodir_SQ = $(subst ','\'',$(infodir))
perfexecdir_SQ = $(subst ','\'',$(perfexecdir))
template_dir_SQ = $(subst ','\'',$(template_dir))
htmldir_SQ = $(subst ','\'',$(htmldir))
+tipdir_SQ = $(subst ','\'',$(tipdir))
prefix_SQ = $(subst ','\'',$(prefix))
sysconfdir_SQ = $(subst ','\'',$(sysconfdir))
libdir_SQ = $(subst ','\'',$(libdir))
@@ -714,12 +726,15 @@ libdir_SQ = $(subst ','\'',$(libdir))
ifneq ($(filter /%,$(firstword $(perfexecdir))),)
perfexec_instdir = $(perfexecdir)
STRACE_GROUPS_INSTDIR = $(STRACE_GROUPS_DIR)
+tip_instdir = $(tipdir)
else
perfexec_instdir = $(prefix)/$(perfexecdir)
STRACE_GROUPS_INSTDIR = $(prefix)/$(STRACE_GROUPS_DIR)
+tip_instdir = $(prefix)/$(tipdir)
endif
perfexec_instdir_SQ = $(subst ','\'',$(perfexec_instdir))
STRACE_GROUPS_INSTDIR_SQ = $(subst ','\'',$(STRACE_GROUPS_INSTDIR))
+tip_instdir_SQ = $(subst ','\'',$(tip_instdir))
# If we install to $(HOME) we keep the traceevent default:
# $(HOME)/.traceevent/plugins
@@ -741,6 +756,10 @@ ifeq ($(VF),1)
$(call print_var,sysconfdir)
$(call print_var,LIBUNWIND_DIR)
$(call print_var,LIBDW_DIR)
+
+ ifeq ($(dwarf-post-unwind),1)
+ $(call feature_print_text,"DWARF post unwind library", $(dwarf-post-unwind-text))
+ endif
$(info )
endif
@@ -756,6 +775,7 @@ $(call detected_var,ETC_PERFCONFIG_SQ)
$(call detected_var,STRACE_GROUPS_DIR_SQ)
$(call detected_var,prefix_SQ)
$(call detected_var,perfexecdir_SQ)
+$(call detected_var,tipdir_SQ)
$(call detected_var,LIBDIR)
$(call detected_var,GTK_CFLAGS)
$(call detected_var,PERL_EMBED_CCOPTS)
diff --git a/tools/perf/config/utilities.mak b/tools/perf/config/utilities.mak
index 0ebef09..c16ce83 100644
--- a/tools/perf/config/utilities.mak
+++ b/tools/perf/config/utilities.mak
@@ -177,22 +177,3 @@ $(if $($(1)),$(call _ge_attempt,$($(1)),$(1)),$(call _ge_attempt,$(2)))
endef
_ge_attempt = $(if $(get-executable),$(get-executable),$(call _gea_err,$(2)))
_gea_err = $(if $(1),$(error Please set '$(1)' appropriately))
-
-# try-run
-# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise)
-# Exit code chooses option. "$$TMP" is can be used as temporary file and
-# is automatically cleaned up.
-try-run = $(shell set -e; \
- TMP="$(TMPOUT).$$$$.tmp"; \
- TMPO="$(TMPOUT).$$$$.o"; \
- if ($(1)) >/dev/null 2>&1; \
- then echo "$(2)"; \
- else echo "$(3)"; \
- fi; \
- rm -f "$$TMP" "$$TMPO")
-
-# cc-option
-# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
-
-cc-option = $(call try-run,\
- $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2))
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 3d4c7c0..a929618 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -9,16 +9,18 @@
#include "builtin.h"
#include "util/env.h"
-#include "util/exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "util/cache.h"
#include "util/quote.h"
-#include "util/run-command.h"
+#include <subcmd/run-command.h>
#include "util/parse-events.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/bpf-loader.h"
#include "util/debug.h"
#include <api/fs/tracing_path.h>
#include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
const char perf_usage_string[] =
"perf [--version] [--help] [OPTIONS] COMMAND [ARGS]";
@@ -39,6 +41,7 @@ struct cmd_struct {
static struct cmd_struct commands[] = {
{ "buildid-cache", cmd_buildid_cache, 0 },
{ "buildid-list", cmd_buildid_list, 0 },
+ { "config", cmd_config, 0 },
{ "diff", cmd_diff, 0 },
{ "evlist", cmd_evlist, 0 },
{ "help", cmd_help, 0 },
@@ -118,7 +121,7 @@ static void commit_pager_choice(void)
{
switch (use_pager) {
case 0:
- setenv("PERF_PAGER", "cat", 1);
+ setenv(PERF_PAGER_ENVIRONMENT, "cat", 1);
break;
case 1:
/* setup_pager(); */
@@ -182,9 +185,9 @@ static int handle_options(const char ***argv, int *argc, int *envchanged)
if (!prefixcmp(cmd, CMD_EXEC_PATH)) {
cmd += strlen(CMD_EXEC_PATH);
if (*cmd == '=')
- perf_set_argv_exec_path(cmd + 1);
+ set_argv_exec_path(cmd + 1);
else {
- puts(perf_exec_path());
+ puts(get_argv_exec_path());
exit(0);
}
} else if (!strcmp(cmd, "--html-path")) {
@@ -383,6 +386,7 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
use_pager = 1;
commit_pager_choice();
+ perf_env__set_cmdline(&perf_env, argc, argv);
status = p->fn(argc, argv, prefix);
exit_browser(status);
perf_env__exit(&perf_env);
@@ -528,14 +532,20 @@ int main(int argc, const char **argv)
const char *cmd;
char sbuf[STRERR_BUFSIZE];
+ /* libsubcmd init */
+ exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT);
+ pager_init(PERF_PAGER_ENVIRONMENT);
+
/* The page_size is placed in util object. */
page_size = sysconf(_SC_PAGE_SIZE);
cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
- cmd = perf_extract_argv0_path(argv[0]);
+ cmd = extract_argv0_path(argv[0]);
if (!cmd)
cmd = "perf-help";
+ srandom(time(NULL));
+
/* get debugfs/tracefs mount point from /proc/mounts */
tracing_path_mount();
diff --git a/tools/perf/scripts/python/stat-cpi.py b/tools/perf/scripts/python/stat-cpi.py
new file mode 100644
index 0000000..8b60f34
--- /dev/null
+++ b/tools/perf/scripts/python/stat-cpi.py
@@ -0,0 +1,77 @@
+#!/usr/bin/env python
+
+data = {}
+times = []
+threads = []
+cpus = []
+
+def get_key(time, event, cpu, thread):
+ return "%d-%s-%d-%d" % (time, event, cpu, thread)
+
+def store_key(time, cpu, thread):
+ if (time not in times):
+ times.append(time)
+
+ if (cpu not in cpus):
+ cpus.append(cpu)
+
+ if (thread not in threads):
+ threads.append(thread)
+
+def store(time, event, cpu, thread, val, ena, run):
+ #print "event %s cpu %d, thread %d, time %d, val %d, ena %d, run %d" % \
+ # (event, cpu, thread, time, val, ena, run)
+
+ store_key(time, cpu, thread)
+ key = get_key(time, event, cpu, thread)
+ data[key] = [ val, ena, run]
+
+def get(time, event, cpu, thread):
+ key = get_key(time, event, cpu, thread)
+ return data[key][0]
+
+def stat__cycles_k(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_k(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles_u(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions_u(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__cycles(cpu, thread, time, val, ena, run):
+ store(time, "cycles", cpu, thread, val, ena, run);
+
+def stat__instructions(cpu, thread, time, val, ena, run):
+ store(time, "instructions", cpu, thread, val, ena, run);
+
+def stat__interval(time):
+ for cpu in cpus:
+ for thread in threads:
+ cyc = get(time, "cycles", cpu, thread)
+ ins = get(time, "instructions", cpu, thread)
+ cpi = 0
+
+ if ins != 0:
+ cpi = cyc/float(ins)
+
+ print "%15f: cpu %d, thread %d -> cpi %f (%d/%d)" % (time/(float(1000000000)), cpu, thread, cpi, cyc, ins)
+
+def trace_end():
+ pass
+# XXX trace_end callback could be used as an alternative place
+# to compute same values as in the script above:
+#
+# for time in times:
+# for cpu in cpus:
+# for thread in threads:
+# cyc = get(time, "cycles", cpu, thread)
+# ins = get(time, "instructions", cpu, thread)
+#
+# if ins != 0:
+# cpi = cyc/float(ins)
+#
+# print "time %.9f, cpu %d, thread %d -> cpi %f" % (time/(float(1000000000)), cpu, thread, cpi)
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
new file mode 100644
index 0000000..bf016c4
--- /dev/null
+++ b/tools/perf/tests/.gitignore
@@ -0,0 +1,3 @@
+llvm-src-base.c
+llvm-src-kbuild.c
+llvm-src-prologue.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 50de225..614899b 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,8 +31,33 @@ perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
-perf-y += llvm.o
+perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
+perf-y += bpf.o
perf-y += topology.o
+perf-y += cpumap.o
+perf-y += stat.o
+perf-y += event_update.o
+
+$(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
+ $(call rule_mkdir)
+ $(Q)echo '#include <tests/llvm.h>' > $@
+ $(Q)echo 'const char test_llvm__bpf_base_prog[] =' >> $@
+ $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+ $(Q)echo ';' >> $@
+
+$(OUTPUT)tests/llvm-src-kbuild.c: tests/bpf-script-test-kbuild.c tests/Build
+ $(call rule_mkdir)
+ $(Q)echo '#include <tests/llvm.h>' > $@
+ $(Q)echo 'const char test_llvm__bpf_test_kbuild_prog[] =' >> $@
+ $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+ $(Q)echo ';' >> $@
+
+$(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
+ $(call rule_mkdir)
+ $(Q)echo '#include <tests/llvm.h>' > $@
+ $(Q)echo 'const char test_llvm__bpf_test_prologue_prog[] =' >> $@
+ $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+ $(Q)echo ';' >> $@
ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
diff --git a/tools/perf/tests/attr.c b/tools/perf/tests/attr.c
index 2dfc9ad..28d1605 100644
--- a/tools/perf/tests/attr.c
+++ b/tools/perf/tests/attr.c
@@ -24,7 +24,7 @@
#include <linux/kernel.h>
#include "../perf.h"
#include "util.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "tests.h"
#define ENV "PERF_TEST_ATTR"
@@ -153,7 +153,7 @@ static int run_dir(const char *d, const char *perf)
return system(cmd);
}
-int test__attr(void)
+int test__attr(int subtest __maybe_unused)
{
struct stat st;
char path_perf[PATH_MAX];
@@ -164,13 +164,12 @@ int test__attr(void)
return run_dir("./tests", "./perf");
/* Then installed path. */
- snprintf(path_dir, PATH_MAX, "%s/tests", perf_exec_path());
+ snprintf(path_dir, PATH_MAX, "%s/tests", get_argv_exec_path());
snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
if (!lstat(path_dir, &st) &&
!lstat(path_perf, &st))
return run_dir(path_dir, path_perf);
- fprintf(stderr, " (omitted)");
- return 0;
+ return TEST_SKIP;
}
diff --git a/tools/perf/tests/bp_signal.c b/tools/perf/tests/bp_signal.c
index a02b035..fb80c9e 100644
--- a/tools/perf/tests/bp_signal.c
+++ b/tools/perf/tests/bp_signal.c
@@ -111,7 +111,7 @@ static long long bp_count(int fd)
return count;
}
-int test__bp_signal(void)
+int test__bp_signal(int subtest __maybe_unused)
{
struct sigaction sa;
long long count1, count2;
diff --git a/tools/perf/tests/bp_signal_overflow.c b/tools/perf/tests/bp_signal_overflow.c
index e765377..89f92fa 100644
--- a/tools/perf/tests/bp_signal_overflow.c
+++ b/tools/perf/tests/bp_signal_overflow.c
@@ -58,7 +58,7 @@ static long long bp_count(int fd)
#define EXECUTIONS 10000
#define THRESHOLD 100
-int test__bp_signal_overflow(void)
+int test__bp_signal_overflow(int subtest __maybe_unused)
{
struct perf_event_attr pe;
struct sigaction sa;
diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
index 410a70b..0ec9c2c 100644
--- a/tools/perf/tests/bpf-script-example.c
+++ b/tools/perf/tests/bpf-script-example.c
@@ -1,3 +1,7 @@
+/*
+ * bpf-script-example.c
+ * Test basic LLVM building
+ */
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
diff --git a/tools/perf/tests/bpf-script-test-kbuild.c b/tools/perf/tests/bpf-script-test-kbuild.c
new file mode 100644
index 0000000..3626924
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-kbuild.c
@@ -0,0 +1,21 @@
+/*
+ * bpf-script-test-kbuild.c
+ * Test include from kernel header
+ */
+#ifndef LINUX_VERSION_CODE
+# error Need LINUX_VERSION_CODE
+# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
+#endif
+#define SEC(NAME) __attribute__((section(NAME), used))
+
+#include <uapi/linux/fs.h>
+#include <uapi/asm/ptrace.h>
+
+SEC("func=vfs_llseek")
+int bpf_func__vfs_llseek(void *ctx)
+{
+ return 0;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf-script-test-prologue.c b/tools/perf/tests/bpf-script-test-prologue.c
new file mode 100644
index 0000000..7230e62
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-prologue.c
@@ -0,0 +1,35 @@
+/*
+ * bpf-script-test-prologue.c
+ * Test BPF prologue
+ */
+#ifndef LINUX_VERSION_CODE
+# error Need LINUX_VERSION_CODE
+# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
+#endif
+#define SEC(NAME) __attribute__((section(NAME), used))
+
+#include <uapi/linux/fs.h>
+
+#define FMODE_READ 0x1
+#define FMODE_WRITE 0x2
+
+static void (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
+ (void *) 6;
+
+SEC("func=null_lseek file->f_mode offset orig")
+int bpf_func__null_lseek(void *ctx, int err, unsigned long f_mode,
+ unsigned long offset, unsigned long orig)
+{
+ if (err)
+ return 0;
+ if (f_mode & FMODE_WRITE)
+ return 0;
+ if (offset & 1)
+ return 0;
+ if (orig == SEEK_CUR)
+ return 0;
+ return 1;
+}
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
new file mode 100644
index 0000000..33689a0
--- /dev/null
+++ b/tools/perf/tests/bpf.c
@@ -0,0 +1,262 @@
+#include <stdio.h>
+#include <sys/epoll.h>
+#include <util/bpf-loader.h>
+#include <util/evlist.h>
+#include "tests.h"
+#include "llvm.h"
+#include "debug.h"
+#define NR_ITERS 111
+
+#ifdef HAVE_LIBBPF_SUPPORT
+
+static int epoll_pwait_loop(void)
+{
+ int i;
+
+ /* Should fail NR_ITERS times */
+ for (i = 0; i < NR_ITERS; i++)
+ epoll_pwait(-(i + 1), NULL, 0, 0, NULL);
+ return 0;
+}
+
+#ifdef HAVE_BPF_PROLOGUE
+
+static int llseek_loop(void)
+{
+ int fds[2], i;
+
+ fds[0] = open("/dev/null", O_RDONLY);
+ fds[1] = open("/dev/null", O_RDWR);
+
+ if (fds[0] < 0 || fds[1] < 0)
+ return -1;
+
+ for (i = 0; i < NR_ITERS; i++) {
+ lseek(fds[i % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+ lseek(fds[(i + 1) % 2], i, (i / 2) % 2 ? SEEK_CUR : SEEK_SET);
+ }
+ close(fds[0]);
+ close(fds[1]);
+ return 0;
+}
+
+#endif
+
+static struct {
+ enum test_llvm__testcase prog_id;
+ const char *desc;
+ const char *name;
+ const char *msg_compile_fail;
+ const char *msg_load_fail;
+ int (*target_func)(void);
+ int expect_result;
+} bpf_testcase_table[] = {
+ {
+ LLVM_TESTCASE_BASE,
+ "Test basic BPF filtering",
+ "[basic_bpf_test]",
+ "fix 'perf test LLVM' first",
+ "load bpf object failed",
+ &epoll_pwait_loop,
+ (NR_ITERS + 1) / 2,
+ },
+#ifdef HAVE_BPF_PROLOGUE
+ {
+ LLVM_TESTCASE_BPF_PROLOGUE,
+ "Test BPF prologue generation",
+ "[bpf_prologue_test]",
+ "fix kbuild first",
+ "check your vmlinux setting?",
+ &llseek_loop,
+ (NR_ITERS + 1) / 4,
+ },
+#endif
+};
+
+static int do_test(struct bpf_object *obj, int (*func)(void),
+ int expect)
+{
+ struct record_opts opts = {
+ .target = {
+ .uid = UINT_MAX,
+ .uses_mmap = true,
+ },
+ .freq = 0,
+ .mmap_pages = 256,
+ .default_interval = 1,
+ };
+
+ char pid[16];
+ char sbuf[STRERR_BUFSIZE];
+ struct perf_evlist *evlist;
+ int i, ret = TEST_FAIL, err = 0, count = 0;
+
+ struct parse_events_evlist parse_evlist;
+ struct parse_events_error parse_error;
+
+ bzero(&parse_error, sizeof(parse_error));
+ bzero(&parse_evlist, sizeof(parse_evlist));
+ parse_evlist.error = &parse_error;
+ INIT_LIST_HEAD(&parse_evlist.list);
+
+ err = parse_events_load_bpf_obj(&parse_evlist, &parse_evlist.list, obj);
+ if (err || list_empty(&parse_evlist.list)) {
+ pr_debug("Failed to add events selected by BPF\n");
+ return TEST_FAIL;
+ }
+
+ snprintf(pid, sizeof(pid), "%d", getpid());
+ pid[sizeof(pid) - 1] = '\0';
+ opts.target.tid = opts.target.pid = pid;
+
+ /* Instead of perf_evlist__new_default, don't add default events */
+ evlist = perf_evlist__new();
+ if (!evlist) {
+ pr_debug("No ehough memory to create evlist\n");
+ return TEST_FAIL;
+ }
+
+ err = perf_evlist__create_maps(evlist, &opts.target);
+ if (err < 0) {
+ pr_debug("Not enough memory to create thread/cpu maps\n");
+ goto out_delete_evlist;
+ }
+
+ perf_evlist__splice_list_tail(evlist, &parse_evlist.list);
+ evlist->nr_groups = parse_evlist.nr_groups;
+
+ perf_evlist__config(evlist, &opts);
+
+ err = perf_evlist__open(evlist);
+ if (err < 0) {
+ pr_debug("perf_evlist__open: %s\n",
+ strerror_r(errno, sbuf, sizeof(sbuf)));
+ goto out_delete_evlist;
+ }
+
+ err = perf_evlist__mmap(evlist, opts.mmap_pages, false);
+ if (err < 0) {
+ pr_debug("perf_evlist__mmap: %s\n",
+ strerror_r(errno, sbuf, sizeof(sbuf)));
+ goto out_delete_evlist;
+ }
+
+ perf_evlist__enable(evlist);
+ (*func)();
+ perf_evlist__disable(evlist);
+
+ for (i = 0; i < evlist->nr_mmaps; i++) {
+ union perf_event *event;
+
+ while ((event = perf_evlist__mmap_read(evlist, i)) != NULL) {
+ const u32 type = event->header.type;
+
+ if (type == PERF_RECORD_SAMPLE)
+ count ++;
+ }
+ }
+
+ if (count != expect) {
+ pr_debug("BPF filter result incorrect\n");
+ goto out_delete_evlist;
+ }
+
+ ret = TEST_OK;
+
+out_delete_evlist:
+ perf_evlist__delete(evlist);
+ return ret;
+}
+
+static struct bpf_object *
+prepare_bpf(void *obj_buf, size_t obj_buf_sz, const char *name)
+{
+ struct bpf_object *obj;
+
+ obj = bpf__prepare_load_buffer(obj_buf, obj_buf_sz, name);
+ if (IS_ERR(obj)) {
+ pr_debug("Compile BPF program failed.\n");
+ return NULL;
+ }
+ return obj;
+}
+
+static int __test__bpf(int idx)
+{
+ int ret;
+ void *obj_buf;
+ size_t obj_buf_sz;
+ struct bpf_object *obj;
+
+ ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+ bpf_testcase_table[idx].prog_id,
+ true);
+ if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
+ pr_debug("Unable to get BPF object, %s\n",
+ bpf_testcase_table[idx].msg_compile_fail);
+ if (idx == 0)
+ return TEST_SKIP;
+ else
+ return TEST_FAIL;
+ }
+
+ obj = prepare_bpf(obj_buf, obj_buf_sz,
+ bpf_testcase_table[idx].name);
+ if (!obj) {
+ ret = TEST_FAIL;
+ goto out;
+ }
+
+ ret = do_test(obj,
+ bpf_testcase_table[idx].target_func,
+ bpf_testcase_table[idx].expect_result);
+out:
+ bpf__clear();
+ return ret;
+}
+
+int test__bpf_subtest_get_nr(void)
+{
+ return (int)ARRAY_SIZE(bpf_testcase_table);
+}
+
+const char *test__bpf_subtest_get_desc(int i)
+{
+ if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
+ return NULL;
+ return bpf_testcase_table[i].desc;
+}
+
+int test__bpf(int i)
+{
+ int err;
+
+ if (i < 0 || i >= (int)ARRAY_SIZE(bpf_testcase_table))
+ return TEST_FAIL;
+
+ if (geteuid() != 0) {
+ pr_debug("Only root can run BPF test\n");
+ return TEST_SKIP;
+ }
+
+ err = __test__bpf(i);
+ return err;
+}
+
+#else
+int test__bpf_subtest_get_nr(void)
+{
+ return 0;
+}
+
+const char *test__bpf_subtest_get_desc(int i __maybe_unused)
+{
+ return NULL;
+}
+
+int test__bpf(int i __maybe_unused)
+{
+ pr_debug("Skip BPF test because BPF support is not compiled\n");
+ return TEST_SKIP;
+}
+#endif
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 66f72d3..f2b1dca 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -11,7 +11,7 @@
#include "tests.h"
#include "debug.h"
#include "color.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "symbol.h"
struct test __weak arch_tests[] = {
@@ -160,12 +160,50 @@ static struct test generic_tests[] = {
{
.desc = "Test LLVM searching and compiling",
.func = test__llvm,
+ .subtest = {
+ .skip_if_fail = true,
+ .get_nr = test__llvm_subtest_get_nr,
+ .get_desc = test__llvm_subtest_get_desc,
+ },
},
{
.desc = "Test topology in session",
.func = test_session_topology,
},
{
+ .desc = "Test BPF filter",
+ .func = test__bpf,
+ .subtest = {
+ .skip_if_fail = true,
+ .get_nr = test__bpf_subtest_get_nr,
+ .get_desc = test__bpf_subtest_get_desc,
+ },
+ },
+ {
+ .desc = "Test thread map synthesize",
+ .func = test__thread_map_synthesize,
+ },
+ {
+ .desc = "Test cpu map synthesize",
+ .func = test__cpu_map_synthesize,
+ },
+ {
+ .desc = "Test stat config synthesize",
+ .func = test__synthesize_stat_config,
+ },
+ {
+ .desc = "Test stat synthesize",
+ .func = test__synthesize_stat,
+ },
+ {
+ .desc = "Test stat round synthesize",
+ .func = test__synthesize_stat_round,
+ },
+ {
+ .desc = "Test attr update synthesize",
+ .func = test__event_update,
+ },
+ {
.func = NULL,
},
};
@@ -192,14 +230,14 @@ static bool perf_test__matches(struct test *test, int curr, int argc, const char
continue;
}
- if (strstr(test->desc, argv[i]))
+ if (strcasestr(test->desc, argv[i]))
return true;
}
return false;
}
-static int run_test(struct test *test)
+static int run_test(struct test *test, int subtest)
{
int status, err = -1, child = fork();
char sbuf[STRERR_BUFSIZE];
@@ -212,7 +250,22 @@ static int run_test(struct test *test)
if (!child) {
pr_debug("test child forked, pid %d\n", getpid());
- err = test->func();
+ if (!verbose) {
+ int nullfd = open("/dev/null", O_WRONLY);
+ if (nullfd >= 0) {
+ close(STDERR_FILENO);
+ close(STDOUT_FILENO);
+
+ dup2(nullfd, STDOUT_FILENO);
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ close(nullfd);
+ }
+ } else {
+ signal(SIGSEGV, sighandler_dump_stack);
+ signal(SIGFPE, sighandler_dump_stack);
+ }
+
+ err = test->func(subtest);
exit(err);
}
@@ -233,6 +286,40 @@ static int run_test(struct test *test)
for (j = 0; j < ARRAY_SIZE(tests); j++) \
for (t = &tests[j][0]; t->func; t++)
+static int test_and_print(struct test *t, bool force_skip, int subtest)
+{
+ int err;
+
+ if (!force_skip) {
+ pr_debug("\n--- start ---\n");
+ err = run_test(t, subtest);
+ pr_debug("---- end ----\n");
+ } else {
+ pr_debug("\n--- force skipped ---\n");
+ err = TEST_SKIP;
+ }
+
+ if (!t->subtest.get_nr)
+ pr_debug("%s:", t->desc);
+ else
+ pr_debug("%s subtest %d:", t->desc, subtest);
+
+ switch (err) {
+ case TEST_OK:
+ pr_info(" Ok\n");
+ break;
+ case TEST_SKIP:
+ color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
+ break;
+ case TEST_FAIL:
+ default:
+ color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
+ break;
+ }
+
+ return err;
+}
+
static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
{
struct test *t;
@@ -260,21 +347,43 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
continue;
}
- pr_debug("\n--- start ---\n");
- err = run_test(t);
- pr_debug("---- end ----\n%s:", t->desc);
-
- switch (err) {
- case TEST_OK:
- pr_info(" Ok\n");
- break;
- case TEST_SKIP:
- color_fprintf(stderr, PERF_COLOR_YELLOW, " Skip\n");
- break;
- case TEST_FAIL:
- default:
- color_fprintf(stderr, PERF_COLOR_RED, " FAILED!\n");
- break;
+ if (!t->subtest.get_nr) {
+ test_and_print(t, false, -1);
+ } else {
+ int subn = t->subtest.get_nr();
+ /*
+ * minus 2 to align with normal testcases.
+ * For subtest we print additional '.x' in number.
+ * for example:
+ *
+ * 35: Test LLVM searching and compiling :
+ * 35.1: Basic BPF llvm compiling test : Ok
+ */
+ int subw = width > 2 ? width - 2 : width;
+ bool skip = false;
+ int subi;
+
+ if (subn <= 0) {
+ color_fprintf(stderr, PERF_COLOR_YELLOW,
+ " Skip (not compiled in)\n");
+ continue;
+ }
+ pr_info("\n");
+
+ for (subi = 0; subi < subn; subi++) {
+ int len = strlen(t->subtest.get_desc(subi));
+
+ if (subw < len)
+ subw = len;
+ }
+
+ for (subi = 0; subi < subn; subi++) {
+ pr_info("%2d.%1d: %-*s:", i, subi + 1, subw,
+ t->subtest.get_desc(subi));
+ err = test_and_print(t, skip, subi);
+ if (err != TEST_OK && t->subtest.skip_if_fail)
+ skip = true;
+ }
}
}
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 49b1959..313a48c 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -433,7 +433,6 @@ enum {
static int do_test_code_reading(bool try_kcore)
{
- struct machines machines;
struct machine *machine;
struct thread *thread;
struct record_opts opts = {
@@ -459,8 +458,7 @@ static int do_test_code_reading(bool try_kcore)
pid = getpid();
- machines__init(&machines);
- machine = &machines.host;
+ machine = machine__new_host();
ret = machine__create_kernel_maps(machine);
if (ret < 0) {
@@ -549,6 +547,13 @@ static int do_test_code_reading(bool try_kcore)
if (ret < 0) {
if (!excl_kernel) {
excl_kernel = true;
+ /*
+ * Both cpus and threads are now owned by evlist
+ * and will be freed by following perf_evlist__set_maps
+ * call. Getting refference to keep them alive.
+ */
+ cpu_map__get(cpus);
+ thread_map__get(threads);
perf_evlist__set_maps(evlist, NULL, NULL);
perf_evlist__delete(evlist);
evlist = NULL;
@@ -594,14 +599,13 @@ out_err:
cpu_map__put(cpus);
thread_map__put(threads);
}
- machines__destroy_kernel_maps(&machines);
machine__delete_threads(machine);
- machines__exit(&machines);
+ machine__delete(machine);
return err;
}
-int test__code_reading(void)
+int test__code_reading(int subtest __maybe_unused)
{
int ret;
@@ -613,16 +617,16 @@ int test__code_reading(void)
case TEST_CODE_READING_OK:
return 0;
case TEST_CODE_READING_NO_VMLINUX:
- fprintf(stderr, " (no vmlinux)");
+ pr_debug("no vmlinux\n");
return 0;
case TEST_CODE_READING_NO_KCORE:
- fprintf(stderr, " (no kcore)");
+ pr_debug("no kcore\n");
return 0;
case TEST_CODE_READING_NO_ACCESS:
- fprintf(stderr, " (no access)");
+ pr_debug("no access\n");
return 0;
case TEST_CODE_READING_NO_KERNEL_OBJ:
- fprintf(stderr, " (no kernel obj)");
+ pr_debug("no kernel obj\n");
return 0;
default:
return -1;
diff --git a/tools/perf/tests/cpumap.c b/tools/perf/tests/cpumap.c
new file mode 100644
index 0000000..4cb6418
--- /dev/null
+++ b/tools/perf/tests/cpumap.c
@@ -0,0 +1,88 @@
+#include "tests.h"
+#include "cpumap.h"
+
+static int process_event_mask(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct cpu_map_event *map_event = &event->cpu_map;
+ struct cpu_map_mask *mask;
+ struct cpu_map_data *data;
+ struct cpu_map *map;
+ int i;
+
+ data = &map_event->data;
+
+ TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__MASK);
+
+ mask = (struct cpu_map_mask *)data->data;
+
+ TEST_ASSERT_VAL("wrong nr", mask->nr == 1);
+
+ for (i = 0; i < 20; i++) {
+ TEST_ASSERT_VAL("wrong cpu", test_bit(i, mask->mask));
+ }
+
+ map = cpu_map__new_data(data);
+ TEST_ASSERT_VAL("wrong nr", map->nr == 20);
+
+ for (i = 0; i < 20; i++) {
+ TEST_ASSERT_VAL("wrong cpu", map->map[i] == i);
+ }
+
+ cpu_map__put(map);
+ return 0;
+}
+
+static int process_event_cpus(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct cpu_map_event *map_event = &event->cpu_map;
+ struct cpu_map_entries *cpus;
+ struct cpu_map_data *data;
+ struct cpu_map *map;
+
+ data = &map_event->data;
+
+ TEST_ASSERT_VAL("wrong type", data->type == PERF_CPU_MAP__CPUS);
+
+ cpus = (struct cpu_map_entries *)data->data;
+
+ TEST_ASSERT_VAL("wrong nr", cpus->nr == 2);
+ TEST_ASSERT_VAL("wrong cpu", cpus->cpu[0] == 1);
+ TEST_ASSERT_VAL("wrong cpu", cpus->cpu[1] == 256);
+
+ map = cpu_map__new_data(data);
+ TEST_ASSERT_VAL("wrong nr", map->nr == 2);
+ TEST_ASSERT_VAL("wrong cpu", map->map[0] == 1);
+ TEST_ASSERT_VAL("wrong cpu", map->map[1] == 256);
+ TEST_ASSERT_VAL("wrong refcnt", atomic_read(&map->refcnt) == 1);
+ cpu_map__put(map);
+ return 0;
+}
+
+
+int test__cpu_map_synthesize(int subtest __maybe_unused)
+{
+ struct cpu_map *cpus;
+
+ /* This one is better stores in mask. */
+ cpus = cpu_map__new("0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19");
+
+ TEST_ASSERT_VAL("failed to synthesize map",
+ !perf_event__synthesize_cpu_map(NULL, cpus, process_event_mask, NULL));
+
+ cpu_map__put(cpus);
+
+ /* This one is better stores in cpu values. */
+ cpus = cpu_map__new("1,256");
+
+ TEST_ASSERT_VAL("failed to synthesize map",
+ !perf_event__synthesize_cpu_map(NULL, cpus, process_event_cpus, NULL));
+
+ cpu_map__put(cpus);
+ return 0;
+}
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c
index a218aea..dc673ff 100644
--- a/tools/perf/tests/dso-data.c
+++ b/tools/perf/tests/dso-data.c
@@ -110,7 +110,7 @@ static int dso__data_fd(struct dso *dso, struct machine *machine)
return fd;
}
-int test__dso_data(void)
+int test__dso_data(int subtest __maybe_unused)
{
struct machine machine;
struct dso *dso;
@@ -245,7 +245,7 @@ static int set_fd_limit(int n)
return setrlimit(RLIMIT_NOFILE, &rlim);
}
-int test__dso_data_cache(void)
+int test__dso_data_cache(int subtest __maybe_unused)
{
struct machine machine;
long nr_end, nr = open_files_cnt();
@@ -302,7 +302,7 @@ int test__dso_data_cache(void)
return 0;
}
-int test__dso_data_reopen(void)
+int test__dso_data_reopen(int subtest __maybe_unused)
{
struct machine machine;
long nr_end, nr = open_files_cnt();
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index 0722179..1c5c022 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -51,6 +51,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
"krava_1",
"test__dwarf_unwind"
};
+ /*
+ * The funcs[MAX_STACK] array index, based on the
+ * callchain order setup.
+ */
+ int idx = callchain_param.order == ORDER_CALLER ?
+ MAX_STACK - *cnt - 1 : *cnt;
if (*cnt >= MAX_STACK) {
pr_debug("failed: crossed the max stack value %d\n", MAX_STACK);
@@ -63,8 +69,10 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
return -1;
}
- pr_debug("got: %s 0x%" PRIx64 "\n", symbol, entry->ip);
- return strcmp((const char *) symbol, funcs[(*cnt)++]);
+ (*cnt)++;
+ pr_debug("got: %s 0x%" PRIx64 ", expecting %s\n",
+ symbol, entry->ip, funcs[idx]);
+ return strcmp((const char *) symbol, funcs[idx]);
}
__attribute__ ((noinline))
@@ -105,8 +113,16 @@ static int compare(void *p1, void *p2)
/* Any possible value should be 'thread' */
struct thread *thread = *(struct thread **)p1;
- if (global_unwind_retval == -INT_MAX)
+ if (global_unwind_retval == -INT_MAX) {
+ /* Call unwinder twice for both callchain orders. */
+ callchain_param.order = ORDER_CALLER;
+
global_unwind_retval = unwind_thread(thread);
+ if (!global_unwind_retval) {
+ callchain_param.order = ORDER_CALLEE;
+ global_unwind_retval = unwind_thread(thread);
+ }
+ }
return p1 - p2;
}
@@ -142,21 +158,23 @@ static int krava_1(struct thread *thread)
return krava_2(thread);
}
-int test__dwarf_unwind(void)
+int test__dwarf_unwind(int subtest __maybe_unused)
{
- struct machines machines;
struct machine *machine;
struct thread *thread;
int err = -1;
- machines__init(&machines);
-
- machine = machines__find(&machines, HOST_KERNEL_ID);
+ machine = machine__new_host();
if (!machine) {
pr_err("Could not get machine\n");
return -1;
}
+ if (machine__create_kernel_maps(machine)) {
+ pr_err("Failed to create kernel maps\n");
+ return -1;
+ }
+
callchain_param.record_mode = CALLCHAIN_DWARF;
if (init_live_machine(machine)) {
@@ -178,7 +196,6 @@ int test__dwarf_unwind(void)
out:
machine__delete_threads(machine);
- machine__exit(machine);
- machines__exit(&machines);
+ machine__delete(machine);
return err;
}
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c
new file mode 100644
index 0000000..012eab5
--- /dev/null
+++ b/tools/perf/tests/event_update.c
@@ -0,0 +1,117 @@
+#include <linux/compiler.h>
+#include "evlist.h"
+#include "evsel.h"
+#include "machine.h"
+#include "tests.h"
+#include "debug.h"
+
+static int process_event_unit(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct event_update_event *ev = (struct event_update_event *) event;
+
+ TEST_ASSERT_VAL("wrong id", ev->id == 123);
+ TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__UNIT);
+ TEST_ASSERT_VAL("wrong unit", !strcmp(ev->data, "KRAVA"));
+ return 0;
+}
+
+static int process_event_scale(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct event_update_event *ev = (struct event_update_event *) event;
+ struct event_update_event_scale *ev_data;
+
+ ev_data = (struct event_update_event_scale *) ev->data;
+
+ TEST_ASSERT_VAL("wrong id", ev->id == 123);
+ TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE);
+ TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123);
+ return 0;
+}
+
+struct event_name {
+ struct perf_tool tool;
+ const char *name;
+};
+
+static int process_event_name(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct event_name *tmp = container_of(tool, struct event_name, tool);
+ struct event_update_event *ev = (struct event_update_event*) event;
+
+ TEST_ASSERT_VAL("wrong id", ev->id == 123);
+ TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__NAME);
+ TEST_ASSERT_VAL("wrong name", !strcmp(ev->data, tmp->name));
+ return 0;
+}
+
+static int process_event_cpus(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct event_update_event *ev = (struct event_update_event*) event;
+ struct event_update_event_cpus *ev_data;
+ struct cpu_map *map;
+
+ ev_data = (struct event_update_event_cpus*) ev->data;
+
+ map = cpu_map__new_data(&ev_data->cpus);
+
+ TEST_ASSERT_VAL("wrong id", ev->id == 123);
+ TEST_ASSERT_VAL("wrong type", ev->type == PERF_EVENT_UPDATE__CPUS);
+ TEST_ASSERT_VAL("wrong cpus", map->nr == 3);
+ TEST_ASSERT_VAL("wrong cpus", map->map[0] == 1);
+ TEST_ASSERT_VAL("wrong cpus", map->map[1] == 2);
+ TEST_ASSERT_VAL("wrong cpus", map->map[2] == 3);
+ cpu_map__put(map);
+ return 0;
+}
+
+int test__event_update(int subtest __maybe_unused)
+{
+ struct perf_evlist *evlist;
+ struct perf_evsel *evsel;
+ struct event_name tmp;
+
+ evlist = perf_evlist__new_default();
+ TEST_ASSERT_VAL("failed to get evlist", evlist);
+
+ evsel = perf_evlist__first(evlist);
+
+ TEST_ASSERT_VAL("failed to allos ids",
+ !perf_evsel__alloc_id(evsel, 1, 1));
+
+ perf_evlist__id_add(evlist, evsel, 0, 0, 123);
+
+ evsel->unit = strdup("KRAVA");
+
+ TEST_ASSERT_VAL("failed to synthesize attr update unit",
+ !perf_event__synthesize_event_update_unit(NULL, evsel, process_event_unit));
+
+ evsel->scale = 0.123;
+
+ TEST_ASSERT_VAL("failed to synthesize attr update scale",
+ !perf_event__synthesize_event_update_scale(NULL, evsel, process_event_scale));
+
+ tmp.name = perf_evsel__name(evsel);
+
+ TEST_ASSERT_VAL("failed to synthesize attr update name",
+ !perf_event__synthesize_event_update_name(&tmp.tool, evsel, process_event_name));
+
+ evsel->own_cpus = cpu_map__new("1,2,3");
+
+ TEST_ASSERT_VAL("failed to synthesize attr update cpus",
+ !perf_event__synthesize_event_update_cpus(&tmp.tool, evsel, process_event_cpus));
+
+ cpu_map__put(evsel->own_cpus);
+ return 0;
+}
diff --git a/tools/perf/tests/evsel-roundtrip-name.c b/tools/perf/tests/evsel-roundtrip-name.c
index 3fa7159..2de4a4f 100644
--- a/tools/perf/tests/evsel-roundtrip-name.c
+++ b/tools/perf/tests/evsel-roundtrip-name.c
@@ -95,7 +95,7 @@ out_delete_evlist:
#define perf_evsel__name_array_test(names) \
__perf_evsel__name_array_test(names, ARRAY_SIZE(names))
-int test__perf_evsel__roundtrip_name_test(void)
+int test__perf_evsel__roundtrip_name_test(int subtest __maybe_unused)
{
int err = 0, ret = 0;
@@ -103,7 +103,8 @@ int test__perf_evsel__roundtrip_name_test(void)
if (err)
ret = err;
- err = perf_evsel__name_array_test(perf_evsel__sw_names);
+ err = __perf_evsel__name_array_test(perf_evsel__sw_names,
+ PERF_COUNT_SW_DUMMY + 1);
if (err)
ret = err;
diff --git a/tools/perf/tests/evsel-tp-sched.c b/tools/perf/tests/evsel-tp-sched.c
index 790e413..1984b3b 100644
--- a/tools/perf/tests/evsel-tp-sched.c
+++ b/tools/perf/tests/evsel-tp-sched.c
@@ -32,7 +32,7 @@ static int perf_evsel__test_field(struct perf_evsel *evsel, const char *name,
return ret;
}
-int test__perf_evsel__tp_sched_test(void)
+int test__perf_evsel__tp_sched_test(int subtest __maybe_unused)
{
struct perf_evsel *evsel = perf_evsel__newtp("sched", "sched_switch");
int ret = 0;
diff --git a/tools/perf/tests/fdarray.c b/tools/perf/tests/fdarray.c
index d24b837..c809463 100644
--- a/tools/perf/tests/fdarray.c
+++ b/tools/perf/tests/fdarray.c
@@ -25,7 +25,7 @@ static int fdarray__fprintf_prefix(struct fdarray *fda, const char *prefix, FILE
return printed + fdarray__fprintf(fda, fp);
}
-int test__fdarray__filter(void)
+int test__fdarray__filter(int subtest __maybe_unused)
{
int nr_fds, expected_fd[2], fd, err = TEST_FAIL;
struct fdarray *fda = fdarray__new(5, 5);
@@ -103,7 +103,7 @@ out:
return err;
}
-int test__fdarray__add(void)
+int test__fdarray__add(int subtest __maybe_unused)
{
int err = TEST_FAIL;
struct fdarray *fda = fdarray__new(2, 2);
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c
index ce80b27..bcfd081 100644
--- a/tools/perf/tests/hists_common.c
+++ b/tools/perf/tests/hists_common.c
@@ -87,6 +87,11 @@ struct machine *setup_fake_machine(struct machines *machines)
return NULL;
}
+ if (machine__create_kernel_maps(machine)) {
+ pr_debug("Cannot create kernel maps\n");
+ return NULL;
+ }
+
for (i = 0; i < ARRAY_SIZE(fake_threads); i++) {
struct thread *thread;
@@ -150,7 +155,6 @@ struct machine *setup_fake_machine(struct machines *machines)
out:
pr_debug("Not enough memory for machine setup\n");
machine__delete_threads(machine);
- machine__delete(machine);
return NULL;
}
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 7ed7370..e360892 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -281,7 +281,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.cumulate_callchain = false;
perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
- setup_sorting();
+ setup_sorting(NULL);
callchain_register_param(&callchain_param);
err = add_hist_entries(hists, machine);
@@ -428,7 +428,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.cumulate_callchain = false;
perf_evsel__set_sample_bit(evsel, CALLCHAIN);
- setup_sorting();
+ setup_sorting(NULL);
callchain_register_param(&callchain_param);
err = add_hist_entries(hists, machine);
@@ -486,7 +486,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.cumulate_callchain = true;
perf_evsel__reset_sample_bit(evsel, CALLCHAIN);
- setup_sorting();
+ setup_sorting(NULL);
callchain_register_param(&callchain_param);
err = add_hist_entries(hists, machine);
@@ -670,7 +670,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
symbol_conf.cumulate_callchain = true;
perf_evsel__set_sample_bit(evsel, CALLCHAIN);
- setup_sorting();
+ setup_sorting(NULL);
callchain_register_param(&callchain_param);
err = add_hist_entries(hists, machine);
@@ -686,7 +686,7 @@ out:
return err;
}
-int test__hists_cumulate(void)
+int test__hists_cumulate(int subtest __maybe_unused)
{
int err = TEST_FAIL;
struct machines machines;
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 818acf8..2a784be 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -104,7 +104,7 @@ out:
return TEST_FAIL;
}
-int test__hists_filter(void)
+int test__hists_filter(int subtest __maybe_unused)
{
int err = TEST_FAIL;
struct machines machines;
@@ -122,7 +122,7 @@ int test__hists_filter(void)
goto out;
/* default sort order (comm,dso,sym) will be used */
- if (setup_sorting() < 0)
+ if (setup_sorting(NULL) < 0)
goto out;
machines__init(&machines);
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index 8c102b0..c764d69 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -64,7 +64,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
struct perf_evsel *evsel;
struct addr_location al;
struct hist_entry *he;
- struct perf_sample sample = { .period = 1, };
+ struct perf_sample sample = { .period = 1, .weight = 1, };
size_t i = 0, k;
/*
@@ -90,7 +90,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
goto out;
he = __hists__add_entry(hists, &al, NULL,
- NULL, NULL, 1, 1, 0, true);
+ NULL, NULL, &sample, true);
if (he == NULL) {
addr_location__put(&al);
goto out;
@@ -116,7 +116,7 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
goto out;
he = __hists__add_entry(hists, &al, NULL,
- NULL, NULL, 1, 1, 0, true);
+ NULL, NULL, &sample, true);
if (he == NULL) {
addr_location__put(&al);
goto out;
@@ -274,7 +274,7 @@ static int validate_link(struct hists *leader, struct hists *other)
return __validate_link(leader, 0) || __validate_link(other, 1);
}
-int test__hists_link(void)
+int test__hists_link(int subtest __maybe_unused)
{
int err = -1;
struct hists *hists, *first_hists;
@@ -294,7 +294,7 @@ int test__hists_link(void)
goto out;
/* default sort order (comm,dso,sym) will be used */
- if (setup_sorting() < 0)
+ if (setup_sorting(NULL) < 0)
goto out;
machines__init(&machines);
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index adbebc8..ebe6cd4 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -134,7 +134,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
field_order = NULL;
sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
- setup_sorting();
+ setup_sorting(NULL);
/*
* expected output:
@@ -236,7 +236,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
field_order = "overhead,cpu";
sort_order = "pid";
- setup_sorting();
+ setup_sorting(NULL);
/*
* expected output:
@@ -292,7 +292,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
field_order = "comm,overhead,dso";
sort_order = NULL;
- setup_sorting();
+ setup_sorting(NULL);
/*
* expected output:
@@ -366,7 +366,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
field_order = "dso,sym,comm,overhead,dso";
sort_order = "sym";
- setup_sorting();
+ setup_sorting(NULL);
/*
* expected output:
@@ -468,7 +468,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
field_order = "cpu,pid,comm,dso,sym";
sort_order = "dso,pid";
- setup_sorting();
+ setup_sorting(NULL);
/*
* expected output:
@@ -576,7 +576,7 @@ out:
return err;
}
-int test__hists_output(void)
+int test__hists_output(int subtest __maybe_unused)
{
int err = TEST_FAIL;
struct machines machines;
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c
index 4d4b983..ddb78fa 100644
--- a/tools/perf/tests/keep-tracking.c
+++ b/tools/perf/tests/keep-tracking.c
@@ -49,13 +49,12 @@ static int find_comm(struct perf_evlist *evlist, const char *comm)
* when an event is disabled but a dummy software event is not disabled. If the
* test passes %0 is returned, otherwise %-1 is returned.
*/
-int test__keep_tracking(void)
+int test__keep_tracking(int subtest __maybe_unused)
{
struct record_opts opts = {
.mmap_pages = UINT_MAX,
.user_freq = UINT_MAX,
.user_interval = ULLONG_MAX,
- .freq = 4000,
.target = {
.uses_mmap = true,
},
@@ -90,8 +89,8 @@ int test__keep_tracking(void)
evsel->attr.enable_on_exec = 0;
if (perf_evlist__open(evlist) < 0) {
- fprintf(stderr, " (not supported)");
- err = 0;
+ pr_debug("Unable to open dummy and cycles event\n");
+ err = TEST_SKIP;
goto out_err;
}
@@ -124,7 +123,7 @@ int test__keep_tracking(void)
evsel = perf_evlist__last(evlist);
- CHECK__(perf_evlist__disable_event(evlist, evsel));
+ CHECK__(perf_evsel__disable(evsel));
comm = "Test COMM 2";
CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0));
diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c
index 08c433b..d2af781 100644
--- a/tools/perf/tests/kmod-path.c
+++ b/tools/perf/tests/kmod-path.c
@@ -49,7 +49,7 @@ static int test_is_kernel_module(const char *path, int cpumode, bool expect)
#define M(path, c, e) \
TEST_ASSERT_VAL("failed", !test_is_kernel_module(path, c, e))
-int test__kmod_path__parse(void)
+int test__kmod_path__parse(int subtest __maybe_unused)
{
/* path alloc_name alloc_ext kmod comp name ext */
T("/xxxx/xxxx/x-x.ko", true , true , true, false, "[x_x]", NULL);
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 52d5597..06f45c1 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -2,6 +2,7 @@
#include <bpf/libbpf.h>
#include <util/llvm-utils.h>
#include <util/cache.h>
+#include "llvm.h"
#include "tests.h"
#include "debug.h"
@@ -11,42 +12,62 @@ static int perf_config_cb(const char *var, const char *val,
return perf_default_config(var, val, arg);
}
-/*
- * Randomly give it a "version" section since we don't really load it
- * into kernel
- */
-static const char test_bpf_prog[] =
- "__attribute__((section(\"do_fork\"), used)) "
- "int fork(void *ctx) {return 0;} "
- "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
- "int _version __attribute__((section(\"version\"), used)) = 0x40100;";
-
#ifdef HAVE_LIBBPF_SUPPORT
static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
{
struct bpf_object *obj;
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL);
- if (!obj)
- return -1;
+ if (IS_ERR(obj))
+ return TEST_FAIL;
bpf_object__close(obj);
- return 0;
+ return TEST_OK;
}
#else
static int test__bpf_parsing(void *obj_buf __maybe_unused,
size_t obj_buf_sz __maybe_unused)
{
- fprintf(stderr, " (skip bpf parsing)");
- return 0;
+ pr_debug("Skip bpf parsing\n");
+ return TEST_OK;
}
#endif
-int test__llvm(void)
+static struct {
+ const char *source;
+ const char *desc;
+} bpf_source_table[__LLVM_TESTCASE_MAX] = {
+ [LLVM_TESTCASE_BASE] = {
+ .source = test_llvm__bpf_base_prog,
+ .desc = "Basic BPF llvm compiling test",
+ },
+ [LLVM_TESTCASE_KBUILD] = {
+ .source = test_llvm__bpf_test_kbuild_prog,
+ .desc = "Test kbuild searching",
+ },
+ [LLVM_TESTCASE_BPF_PROLOGUE] = {
+ .source = test_llvm__bpf_test_prologue_prog,
+ .desc = "Compile source for BPF prologue generation test",
+ },
+};
+
+
+int
+test_llvm__fetch_bpf_obj(void **p_obj_buf,
+ size_t *p_obj_buf_sz,
+ enum test_llvm__testcase idx,
+ bool force)
{
- char *tmpl_new, *clang_opt_new;
- void *obj_buf;
- size_t obj_buf_sz;
- int err, old_verbose;
+ const char *source;
+ const char *desc;
+ const char *tmpl_old, *clang_opt_old;
+ char *tmpl_new = NULL, *clang_opt_new = NULL;
+ int err, old_verbose, ret = TEST_FAIL;
+
+ if (idx >= __LLVM_TESTCASE_MAX)
+ return TEST_FAIL;
+
+ source = bpf_source_table[idx].source;
+ desc = bpf_source_table[idx].desc;
perf_config(perf_config_cb, NULL);
@@ -54,45 +75,95 @@ int test__llvm(void)
* Skip this test if user's .perfconfig doesn't set [llvm] section
* and clang is not found in $PATH, and this is not perf test -v
*/
- if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) {
- fprintf(stderr, " (no clang, try 'perf test -v LLVM')");
+ if (!force && (verbose == 0 &&
+ !llvm_param.user_set_param &&
+ llvm__search_clang())) {
+ pr_debug("No clang and no verbosive, skip this test\n");
return TEST_SKIP;
}
- old_verbose = verbose;
/*
* llvm is verbosity when error. Suppress all error output if
* not 'perf test -v'.
*/
+ old_verbose = verbose;
if (verbose == 0)
verbose = -1;
+ *p_obj_buf = NULL;
+ *p_obj_buf_sz = 0;
+
if (!llvm_param.clang_bpf_cmd_template)
- return -1;
+ goto out;
if (!llvm_param.clang_opt)
llvm_param.clang_opt = strdup("");
- err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog,
- llvm_param.clang_bpf_cmd_template);
+ err = asprintf(&tmpl_new, "echo '%s' | %s%s", source,
+ llvm_param.clang_bpf_cmd_template,
+ old_verbose ? "" : " 2>/dev/null");
if (err < 0)
- return -1;
+ goto out;
err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
if (err < 0)
- return -1;
+ goto out;
+ tmpl_old = llvm_param.clang_bpf_cmd_template;
llvm_param.clang_bpf_cmd_template = tmpl_new;
+ clang_opt_old = llvm_param.clang_opt;
llvm_param.clang_opt = clang_opt_new;
- err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
+
+ err = llvm__compile_bpf("-", p_obj_buf, p_obj_buf_sz);
+
+ llvm_param.clang_bpf_cmd_template = tmpl_old;
+ llvm_param.clang_opt = clang_opt_old;
verbose = old_verbose;
- if (err) {
- if (!verbose)
- fprintf(stderr, " (use -v to see error message)");
- return -1;
- }
+ if (err)
+ goto out;
+
+ ret = TEST_OK;
+out:
+ free(tmpl_new);
+ free(clang_opt_new);
+ if (ret != TEST_OK)
+ pr_debug("Failed to compile test case: '%s'\n", desc);
+ return ret;
+}
- err = test__bpf_parsing(obj_buf, obj_buf_sz);
+int test__llvm(int subtest)
+{
+ int ret;
+ void *obj_buf = NULL;
+ size_t obj_buf_sz = 0;
+
+ if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
+ return TEST_FAIL;
+
+ ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
+ subtest, false);
+
+ if (ret == TEST_OK) {
+ ret = test__bpf_parsing(obj_buf, obj_buf_sz);
+ if (ret != TEST_OK) {
+ pr_debug("Failed to parse test case '%s'\n",
+ bpf_source_table[subtest].desc);
+ }
+ }
free(obj_buf);
- return err;
+
+ return ret;
+}
+
+int test__llvm_subtest_get_nr(void)
+{
+ return __LLVM_TESTCASE_MAX;
+}
+
+const char *test__llvm_subtest_get_desc(int subtest)
+{
+ if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
+ return NULL;
+
+ return bpf_source_table[subtest].desc;
}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 0000000..5150b4d
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,20 @@
+#ifndef PERF_TEST_LLVM_H
+#define PERF_TEST_LLVM_H
+
+#include <stddef.h> /* for size_t */
+#include <stdbool.h> /* for bool */
+
+extern const char test_llvm__bpf_base_prog[];
+extern const char test_llvm__bpf_test_kbuild_prog[];
+extern const char test_llvm__bpf_test_prologue_prog[];
+
+enum test_llvm__testcase {
+ LLVM_TESTCASE_BASE,
+ LLVM_TESTCASE_KBUILD,
+ LLVM_TESTCASE_BPF_PROLOGUE,
+ __LLVM_TESTCASE_MAX,
+};
+
+int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
+ enum test_llvm__testcase index, bool force);
+#endif
diff --git a/tools/perf/tests/make b/tools/perf/tests/make
index 2cbd0c6..c1fbb8e 100644
--- a/tools/perf/tests/make
+++ b/tools/perf/tests/make
@@ -221,6 +221,11 @@ test_O = $(if $(test_$1),$(test_$1),$(test_default_O))
all:
+ifdef SHUF
+run := $(shell shuf -e $(run))
+run_O := $(shell shuf -e $(run_O))
+endif
+
ifdef DEBUG
d := $(info run $(run))
d := $(info run_O $(run_O))
@@ -254,7 +259,8 @@ $(run_O):
tarpkg:
@cmd="$(PERF)/tests/perf-targz-src-pkg $(PERF)"; \
echo "- $@: $$cmd" && echo $$cmd > $@ && \
- ( eval $$cmd ) >> $@ 2>&1
+ ( eval $$cmd ) >> $@ 2>&1 && \
+ rm -f $@
make_kernelsrc:
@echo "- make -C <kernelsrc> tools/perf"
diff --git a/tools/perf/tests/mmap-basic.c b/tools/perf/tests/mmap-basic.c
index 4495493..359e98f 100644
--- a/tools/perf/tests/mmap-basic.c
+++ b/tools/perf/tests/mmap-basic.c
@@ -16,7 +16,7 @@
* Then it checks if the number of syscalls reported as perf events by
* the kernel corresponds to the number of syscalls made.
*/
-int test__basic_mmap(void)
+int test__basic_mmap(int subtest __maybe_unused)
{
int err = -1;
union perf_event *event;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 145050e..0c5ce44 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -149,7 +149,6 @@ static int synth_process(struct machine *machine)
static int mmap_events(synth_cb synth)
{
- struct machines machines;
struct machine *machine;
int err, i;
@@ -162,8 +161,7 @@ static int mmap_events(synth_cb synth)
*/
TEST_ASSERT_VAL("failed to create threads", !threads_create());
- machines__init(&machines);
- machine = &machines.host;
+ machine = machine__new_host();
dump_trace = verbose > 1 ? 1 : 0;
@@ -203,7 +201,7 @@ static int mmap_events(synth_cb synth)
}
machine__delete_threads(machine);
- machines__exit(&machines);
+ machine__delete(machine);
return err;
}
@@ -221,7 +219,7 @@ static int mmap_events(synth_cb synth)
*
* by using all thread objects.
*/
-int test__mmap_thread_lookup(void)
+int test__mmap_thread_lookup(int subtest __maybe_unused)
{
/* perf_event__synthesize_threads synthesize */
TEST_ASSERT_VAL("failed with sythesizing all",
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c
index 2006485..53c2273 100644
--- a/tools/perf/tests/openat-syscall-all-cpus.c
+++ b/tools/perf/tests/openat-syscall-all-cpus.c
@@ -7,7 +7,7 @@
#include "debug.h"
#include "stat.h"
-int test__openat_syscall_event_on_all_cpus(void)
+int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused)
{
int err = -1, fd, cpu;
struct cpu_map *cpus;
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c
index 5e811cd..eb99a105 100644
--- a/tools/perf/tests/openat-syscall-tp-fields.c
+++ b/tools/perf/tests/openat-syscall-tp-fields.c
@@ -6,7 +6,7 @@
#include "tests.h"
#include "debug.h"
-int test__syscall_openat_tp_fields(void)
+int test__syscall_openat_tp_fields(int subtest __maybe_unused)
{
struct record_opts opts = {
.target = {
diff --git a/tools/perf/tests/openat-syscall.c b/tools/perf/tests/openat-syscall.c
index 033b547..1184f9b 100644
--- a/tools/perf/tests/openat-syscall.c
+++ b/tools/perf/tests/openat-syscall.c
@@ -5,7 +5,7 @@
#include "debug.h"
#include "tests.h"
-int test__openat_syscall_event(void)
+int test__openat_syscall_event(int subtest __maybe_unused)
{
int err = -1, fd;
struct perf_evsel *evsel;
diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c
index 636d7b4..abe8849 100644
--- a/tools/perf/tests/parse-events.c
+++ b/tools/perf/tests/parse-events.c
@@ -1765,7 +1765,7 @@ static void debug_warn(const char *warn, va_list params)
fprintf(stderr, " Warning: %s\n", msg);
}
-int test__parse_events(void)
+int test__parse_events(int subtest __maybe_unused)
{
int ret1, ret2 = 0;
diff --git a/tools/perf/tests/parse-no-sample-id-all.c b/tools/perf/tests/parse-no-sample-id-all.c
index 2c63ea6..294c76b 100644
--- a/tools/perf/tests/parse-no-sample-id-all.c
+++ b/tools/perf/tests/parse-no-sample-id-all.c
@@ -67,7 +67,7 @@ struct test_attr_event {
*
* Return: %0 on success, %-1 if the test fails.
*/
-int test__parse_no_sample_id_all(void)
+int test__parse_no_sample_id_all(int subtest __maybe_unused)
{
int err;
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c
index 7a228a2..1cc78ce 100644
--- a/tools/perf/tests/perf-record.c
+++ b/tools/perf/tests/perf-record.c
@@ -32,7 +32,7 @@ realloc:
return cpu;
}
-int test__PERF_RECORD(void)
+int test__PERF_RECORD(int subtest __maybe_unused)
{
struct record_opts opts = {
.target = {
@@ -40,12 +40,11 @@ int test__PERF_RECORD(void)
.uses_mmap = true,
},
.no_buffering = true,
- .freq = 10,
.mmap_pages = 256,
};
cpu_set_t cpu_mask;
size_t cpu_mask_size = sizeof(cpu_mask);
- struct perf_evlist *evlist = perf_evlist__new_default();
+ struct perf_evlist *evlist = perf_evlist__new_dummy();
struct perf_evsel *evsel;
struct perf_sample sample;
const char *cmd = "sleep";
@@ -61,6 +60,9 @@ int test__PERF_RECORD(void)
int total_events = 0, nr_events[PERF_RECORD_MAX] = { 0, };
char sbuf[STRERR_BUFSIZE];
+ if (evlist == NULL) /* Fallback for kernels lacking PERF_COUNT_SW_DUMMY */
+ evlist = perf_evlist__new_default();
+
if (evlist == NULL || argv == NULL) {
pr_debug("Not enough memory to create evlist\n");
goto out;
diff --git a/tools/perf/tests/pmu.c b/tools/perf/tests/pmu.c
index faa04e9..1e2ba26 100644
--- a/tools/perf/tests/pmu.c
+++ b/tools/perf/tests/pmu.c
@@ -133,7 +133,7 @@ static struct list_head *test_terms_list(void)
return &terms;
}
-int test__pmu(void)
+int test__pmu(int subtest __maybe_unused)
{
char *format = test_format_dir_get();
LIST_HEAD(formats);
diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c
index 7760277..7a52834 100644
--- a/tools/perf/tests/python-use.c
+++ b/tools/perf/tests/python-use.c
@@ -4,11 +4,12 @@
#include <stdio.h>
#include <stdlib.h>
+#include <linux/compiler.h>
#include "tests.h"
extern int verbose;
-int test__python_use(void)
+int test__python_use(int subtest __maybe_unused)
{
char *cmd;
int ret;
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index 30c0218..5f23710 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -290,7 +290,7 @@ out_free:
* checks sample format bits separately and together. If the test passes %0 is
* returned, otherwise %-1 is returned.
*/
-int test__sample_parsing(void)
+int test__sample_parsing(int subtest __maybe_unused)
{
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
u64 sample_type;
diff --git a/tools/perf/tests/stat.c b/tools/perf/tests/stat.c
new file mode 100644
index 0000000..6a20ff2
--- /dev/null
+++ b/tools/perf/tests/stat.c
@@ -0,0 +1,111 @@
+#include <linux/compiler.h>
+#include "event.h"
+#include "tests.h"
+#include "stat.h"
+#include "counts.h"
+#include "debug.h"
+
+static bool has_term(struct stat_config_event *config,
+ u64 tag, u64 val)
+{
+ unsigned i;
+
+ for (i = 0; i < config->nr; i++) {
+ if ((config->data[i].tag == tag) &&
+ (config->data[i].val == val))
+ return true;
+ }
+
+ return false;
+}
+
+static int process_stat_config_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_config_event *config = &event->stat_config;
+ struct perf_stat_config stat_config;
+
+#define HAS(term, val) \
+ has_term(config, PERF_STAT_CONFIG_TERM__##term, val)
+
+ TEST_ASSERT_VAL("wrong nr", config->nr == PERF_STAT_CONFIG_TERM__MAX);
+ TEST_ASSERT_VAL("wrong aggr_mode", HAS(AGGR_MODE, AGGR_CORE));
+ TEST_ASSERT_VAL("wrong scale", HAS(SCALE, 1));
+ TEST_ASSERT_VAL("wrong interval", HAS(INTERVAL, 1));
+
+#undef HAS
+
+ perf_event__read_stat_config(&stat_config, config);
+
+ TEST_ASSERT_VAL("wrong aggr_mode", stat_config.aggr_mode == AGGR_CORE);
+ TEST_ASSERT_VAL("wrong scale", stat_config.scale == 1);
+ TEST_ASSERT_VAL("wrong interval", stat_config.interval == 1);
+ return 0;
+}
+
+int test__synthesize_stat_config(int subtest __maybe_unused)
+{
+ struct perf_stat_config stat_config = {
+ .aggr_mode = AGGR_CORE,
+ .scale = 1,
+ .interval = 1,
+ };
+
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat_config(NULL, &stat_config, process_stat_config_event, NULL));
+
+ return 0;
+}
+
+static int process_stat_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_event *st = &event->stat;
+
+ TEST_ASSERT_VAL("wrong cpu", st->cpu == 1);
+ TEST_ASSERT_VAL("wrong thread", st->thread == 2);
+ TEST_ASSERT_VAL("wrong id", st->id == 3);
+ TEST_ASSERT_VAL("wrong val", st->val == 100);
+ TEST_ASSERT_VAL("wrong run", st->ena == 200);
+ TEST_ASSERT_VAL("wrong ena", st->run == 300);
+ return 0;
+}
+
+int test__synthesize_stat(int subtest __maybe_unused)
+{
+ struct perf_counts_values count;
+
+ count.val = 100;
+ count.ena = 200;
+ count.run = 300;
+
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat(NULL, 1, 2, 3, &count, process_stat_event, NULL));
+
+ return 0;
+}
+
+static int process_stat_round_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct stat_round_event *stat_round = &event->stat_round;
+
+ TEST_ASSERT_VAL("wrong time", stat_round->time == 0xdeadbeef);
+ TEST_ASSERT_VAL("wrong type", stat_round->type == PERF_STAT_ROUND_TYPE__INTERVAL);
+ return 0;
+}
+
+int test__synthesize_stat_round(int subtest __maybe_unused)
+{
+ TEST_ASSERT_VAL("failed to synthesize stat_config",
+ !perf_event__synthesize_stat_round(NULL, 0xdeadbeef, PERF_STAT_ROUND_TYPE__INTERVAL,
+ process_stat_round_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/tests/sw-clock.c b/tools/perf/tests/sw-clock.c
index 5b83f56..36e8ce1 100644
--- a/tools/perf/tests/sw-clock.c
+++ b/tools/perf/tests/sw-clock.c
@@ -122,7 +122,7 @@ out_delete_evlist:
return err;
}
-int test__sw_clock_freq(void)
+int test__sw_clock_freq(int subtest __maybe_unused)
{
int ret;
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c
index e698742..ebd8016 100644
--- a/tools/perf/tests/switch-tracking.c
+++ b/tools/perf/tests/switch-tracking.c
@@ -305,7 +305,7 @@ out_free_nodes:
* evsel->system_wide and evsel->tracking flags (respectively) with other events
* sometimes enabled or disabled.
*/
-int test__switch_tracking(void)
+int test__switch_tracking(int subtest __maybe_unused)
{
const char *sched_switch = "sched:sched_switch";
struct switch_tracking switch_tracking = { .tids = NULL, };
@@ -366,7 +366,7 @@ int test__switch_tracking(void)
/* Third event */
if (!perf_evlist__can_select_event(evlist, sched_switch)) {
- fprintf(stderr, " (no sched_switch)");
+ pr_debug("No sched_switch\n");
err = 0;
goto out;
}
@@ -442,7 +442,7 @@ int test__switch_tracking(void)
}
if (perf_evlist__open(evlist) < 0) {
- fprintf(stderr, " (not supported)");
+ pr_debug("Not supported\n");
err = 0;
goto out;
}
@@ -455,7 +455,7 @@ int test__switch_tracking(void)
perf_evlist__enable(evlist);
- err = perf_evlist__disable_event(evlist, cpu_clocks_evsel);
+ err = perf_evsel__disable(cpu_clocks_evsel);
if (err) {
pr_debug("perf_evlist__disable_event failed!\n");
goto out_err;
@@ -474,7 +474,7 @@ int test__switch_tracking(void)
goto out_err;
}
- err = perf_evlist__disable_event(evlist, cycles_evsel);
+ err = perf_evsel__disable(cycles_evsel);
if (err) {
pr_debug("perf_evlist__disable_event failed!\n");
goto out_err;
@@ -500,7 +500,7 @@ int test__switch_tracking(void)
goto out_err;
}
- err = perf_evlist__enable_event(evlist, cycles_evsel);
+ err = perf_evsel__enable(cycles_evsel);
if (err) {
pr_debug("perf_evlist__disable_event failed!\n");
goto out_err;
diff --git a/tools/perf/tests/task-exit.c b/tools/perf/tests/task-exit.c
index add1638..2dfff7a 100644
--- a/tools/perf/tests/task-exit.c
+++ b/tools/perf/tests/task-exit.c
@@ -31,7 +31,7 @@ static void workload_exec_failed_signal(int signo __maybe_unused,
* if the number of exit event reported by the kernel is 1 or not
* in order to check the kernel returns correct number of event.
*/
-int test__task_exit(void)
+int test__task_exit(int subtest __maybe_unused)
{
int err = -1;
union perf_event *event;
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index c804869..82b2b5e 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -1,6 +1,8 @@
#ifndef TESTS_H
#define TESTS_H
+#include <stdbool.h>
+
#define TEST_ASSERT_VAL(text, cond) \
do { \
if (!(cond)) { \
@@ -26,47 +28,63 @@ enum {
struct test {
const char *desc;
- int (*func)(void);
+ int (*func)(int subtest);
+ struct {
+ bool skip_if_fail;
+ int (*get_nr)(void);
+ const char *(*get_desc)(int subtest);
+ } subtest;
};
/* Tests */
-int test__vmlinux_matches_kallsyms(void);
-int test__openat_syscall_event(void);
-int test__openat_syscall_event_on_all_cpus(void);
-int test__basic_mmap(void);
-int test__PERF_RECORD(void);
-int test__perf_evsel__roundtrip_name_test(void);
-int test__perf_evsel__tp_sched_test(void);
-int test__syscall_openat_tp_fields(void);
-int test__pmu(void);
-int test__attr(void);
-int test__dso_data(void);
-int test__dso_data_cache(void);
-int test__dso_data_reopen(void);
-int test__parse_events(void);
-int test__hists_link(void);
-int test__python_use(void);
-int test__bp_signal(void);
-int test__bp_signal_overflow(void);
-int test__task_exit(void);
-int test__sw_clock_freq(void);
-int test__code_reading(void);
-int test__sample_parsing(void);
-int test__keep_tracking(void);
-int test__parse_no_sample_id_all(void);
-int test__dwarf_unwind(void);
-int test__hists_filter(void);
-int test__mmap_thread_lookup(void);
-int test__thread_mg_share(void);
-int test__hists_output(void);
-int test__hists_cumulate(void);
-int test__switch_tracking(void);
-int test__fdarray__filter(void);
-int test__fdarray__add(void);
-int test__kmod_path__parse(void);
-int test__thread_map(void);
-int test__llvm(void);
-int test_session_topology(void);
+int test__vmlinux_matches_kallsyms(int subtest);
+int test__openat_syscall_event(int subtest);
+int test__openat_syscall_event_on_all_cpus(int subtest);
+int test__basic_mmap(int subtest);
+int test__PERF_RECORD(int subtest);
+int test__perf_evsel__roundtrip_name_test(int subtest);
+int test__perf_evsel__tp_sched_test(int subtest);
+int test__syscall_openat_tp_fields(int subtest);
+int test__pmu(int subtest);
+int test__attr(int subtest);
+int test__dso_data(int subtest);
+int test__dso_data_cache(int subtest);
+int test__dso_data_reopen(int subtest);
+int test__parse_events(int subtest);
+int test__hists_link(int subtest);
+int test__python_use(int subtest);
+int test__bp_signal(int subtest);
+int test__bp_signal_overflow(int subtest);
+int test__task_exit(int subtest);
+int test__sw_clock_freq(int subtest);
+int test__code_reading(int subtest);
+int test__sample_parsing(int subtest);
+int test__keep_tracking(int subtest);
+int test__parse_no_sample_id_all(int subtest);
+int test__dwarf_unwind(int subtest);
+int test__hists_filter(int subtest);
+int test__mmap_thread_lookup(int subtest);
+int test__thread_mg_share(int subtest);
+int test__hists_output(int subtest);
+int test__hists_cumulate(int subtest);
+int test__switch_tracking(int subtest);
+int test__fdarray__filter(int subtest);
+int test__fdarray__add(int subtest);
+int test__kmod_path__parse(int subtest);
+int test__thread_map(int subtest);
+int test__llvm(int subtest);
+const char *test__llvm_subtest_get_desc(int subtest);
+int test__llvm_subtest_get_nr(void);
+int test__bpf(int subtest);
+const char *test__bpf_subtest_get_desc(int subtest);
+int test__bpf_subtest_get_nr(void);
+int test_session_topology(int subtest);
+int test__thread_map_synthesize(int subtest);
+int test__cpu_map_synthesize(int subtest);
+int test__synthesize_stat_config(int subtest);
+int test__synthesize_stat(int subtest);
+int test__synthesize_stat_round(int subtest);
+int test__event_update(int subtest);
#if defined(__arm__) || defined(__aarch64__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT
diff --git a/tools/perf/tests/thread-map.c b/tools/perf/tests/thread-map.c
index 138a0e3..fccde84 100644
--- a/tools/perf/tests/thread-map.c
+++ b/tools/perf/tests/thread-map.c
@@ -4,7 +4,7 @@
#include "thread_map.h"
#include "debug.h"
-int test__thread_map(void)
+int test__thread_map(int subtest __maybe_unused)
{
struct thread_map *map;
@@ -40,3 +40,46 @@ int test__thread_map(void)
thread_map__put(map);
return 0;
}
+
+static int process_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_sample *sample __maybe_unused,
+ struct machine *machine __maybe_unused)
+{
+ struct thread_map_event *map = &event->thread_map;
+ struct thread_map *threads;
+
+ TEST_ASSERT_VAL("wrong nr", map->nr == 1);
+ TEST_ASSERT_VAL("wrong pid", map->entries[0].pid == (u64) getpid());
+ TEST_ASSERT_VAL("wrong comm", !strcmp(map->entries[0].comm, "perf"));
+
+ threads = thread_map__new_event(&event->thread_map);
+ TEST_ASSERT_VAL("failed to alloc map", threads);
+
+ TEST_ASSERT_VAL("wrong nr", threads->nr == 1);
+ TEST_ASSERT_VAL("wrong pid",
+ thread_map__pid(threads, 0) == getpid());
+ TEST_ASSERT_VAL("wrong comm",
+ thread_map__comm(threads, 0) &&
+ !strcmp(thread_map__comm(threads, 0), "perf"));
+ TEST_ASSERT_VAL("wrong refcnt",
+ atomic_read(&threads->refcnt) == 1);
+ thread_map__put(threads);
+ return 0;
+}
+
+int test__thread_map_synthesize(int subtest __maybe_unused)
+{
+ struct thread_map *threads;
+
+ /* test map on current pid */
+ threads = thread_map__new_by_pid(getpid());
+ TEST_ASSERT_VAL("failed to alloc map", threads);
+
+ thread_map__read_comms(threads);
+
+ TEST_ASSERT_VAL("failed to synthesize map",
+ !perf_event__synthesize_thread_map2(NULL, threads, process_event, NULL));
+
+ return 0;
+}
diff --git a/tools/perf/tests/thread-mg-share.c b/tools/perf/tests/thread-mg-share.c
index 01fabb1..188b631 100644
--- a/tools/perf/tests/thread-mg-share.c
+++ b/tools/perf/tests/thread-mg-share.c
@@ -4,7 +4,7 @@
#include "map.h"
#include "debug.h"
-int test__thread_mg_share(void)
+int test__thread_mg_share(int subtest __maybe_unused)
{
struct machines machines;
struct machine *machine;
diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c
index f5bb096..98fe69a 100644
--- a/tools/perf/tests/topology.c
+++ b/tools/perf/tests/topology.c
@@ -84,7 +84,7 @@ static int check_cpu_topology(char *path, struct cpu_map *map)
return 0;
}
-int test_session_topology(void)
+int test_session_topology(int subtest __maybe_unused)
{
char path[PATH_MAX];
struct cpu_map *map;
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c
index d677e01..f0bfc9e 100644
--- a/tools/perf/tests/vmlinux-kallsyms.c
+++ b/tools/perf/tests/vmlinux-kallsyms.c
@@ -18,7 +18,7 @@ static int vmlinux_matches_kallsyms_filter(struct map *map __maybe_unused,
#define UM(x) kallsyms_map->unmap_ip(kallsyms_map, (x))
-int test__vmlinux_matches_kallsyms(void)
+int test__vmlinux_matches_kallsyms(int subtest __maybe_unused)
{
int err = -1;
struct rb_node *nd;
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c
index e9703c0..d372021 100644
--- a/tools/perf/ui/browser.c
+++ b/tools/perf/ui/browser.c
@@ -528,7 +528,7 @@ static struct ui_browser_colorset {
.colorset = HE_COLORSET_SELECTED,
.name = "selected",
.fg = "black",
- .bg = "lightgray",
+ .bg = "yellow",
},
{
.colorset = HE_COLORSET_CODE,
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index e5afb89..901d481 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -178,12 +178,51 @@ static int callchain_node__count_rows_rb_tree(struct callchain_node *node)
return n;
}
+static int callchain_node__count_flat_rows(struct callchain_node *node)
+{
+ struct callchain_list *chain;
+ char folded_sign = 0;
+ int n = 0;
+
+ list_for_each_entry(chain, &node->parent_val, list) {
+ if (!folded_sign) {
+ /* only check first chain list entry */
+ folded_sign = callchain_list__folded(chain);
+ if (folded_sign == '+')
+ return 1;
+ }
+ n++;
+ }
+
+ list_for_each_entry(chain, &node->val, list) {
+ if (!folded_sign) {
+ /* node->parent_val list might be empty */
+ folded_sign = callchain_list__folded(chain);
+ if (folded_sign == '+')
+ return 1;
+ }
+ n++;
+ }
+
+ return n;
+}
+
+static int callchain_node__count_folded_rows(struct callchain_node *node __maybe_unused)
+{
+ return 1;
+}
+
static int callchain_node__count_rows(struct callchain_node *node)
{
struct callchain_list *chain;
bool unfolded = false;
int n = 0;
+ if (callchain_param.mode == CHAIN_FLAT)
+ return callchain_node__count_flat_rows(node);
+ else if (callchain_param.mode == CHAIN_FOLDED)
+ return callchain_node__count_folded_rows(node);
+
list_for_each_entry(chain, &node->val, list) {
++n;
unfolded = chain->unfolded;
@@ -263,7 +302,7 @@ static void callchain_node__init_have_children(struct callchain_node *node,
chain = list_entry(node->val.next, struct callchain_list, list);
chain->has_children = has_sibling;
- if (!list_empty(&node->val)) {
+ if (node->val.next != node->val.prev) {
chain = list_entry(node->val.prev, struct callchain_list, list);
chain->has_children = !RB_EMPTY_ROOT(&node->rb_root);
}
@@ -279,6 +318,9 @@ static void callchain__init_have_children(struct rb_root *root)
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
callchain_node__init_have_children(node, has_sibling);
+ if (callchain_param.mode == CHAIN_FLAT ||
+ callchain_param.mode == CHAIN_FOLDED)
+ callchain_node__make_parent_list(node);
}
}
@@ -298,6 +340,9 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
struct callchain_list *cl = container_of(ms, struct callchain_list, ms);
bool has_children;
+ if (!he || !ms)
+ return false;
+
if (ms == &he->ms)
has_children = hist_entry__toggle_fold(he);
else
@@ -574,6 +619,231 @@ static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_u
#define LEVEL_OFFSET_STEP 3
+static int hist_browser__show_callchain_list(struct hist_browser *browser,
+ struct callchain_node *node,
+ struct callchain_list *chain,
+ unsigned short row, u64 total,
+ bool need_percent, int offset,
+ print_callchain_entry_fn print,
+ struct callchain_print_arg *arg)
+{
+ char bf[1024], *alloc_str;
+ const char *str;
+
+ if (arg->row_offset != 0) {
+ arg->row_offset--;
+ return 0;
+ }
+
+ alloc_str = NULL;
+ str = callchain_list__sym_name(chain, bf, sizeof(bf),
+ browser->show_dso);
+
+ if (need_percent) {
+ char buf[64];
+
+ callchain_node__scnprintf_value(node, buf, sizeof(buf),
+ total);
+
+ if (asprintf(&alloc_str, "%s %s", buf, str) < 0)
+ str = "Not enough memory!";
+ else
+ str = alloc_str;
+ }
+
+ print(browser, chain, str, offset, row, arg);
+
+ free(alloc_str);
+ return 1;
+}
+
+static int hist_browser__show_callchain_flat(struct hist_browser *browser,
+ struct rb_root *root,
+ unsigned short row, u64 total,
+ print_callchain_entry_fn print,
+ struct callchain_print_arg *arg,
+ check_output_full_fn is_output_full)
+{
+ struct rb_node *node;
+ int first_row = row, offset = LEVEL_OFFSET_STEP;
+ bool need_percent;
+
+ node = rb_first(root);
+ need_percent = node && rb_next(node);
+
+ while (node) {
+ struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+ struct rb_node *next = rb_next(node);
+ struct callchain_list *chain;
+ char folded_sign = ' ';
+ int first = true;
+ int extra_offset = 0;
+
+ list_for_each_entry(chain, &child->parent_val, list) {
+ bool was_first = first;
+
+ if (first)
+ first = false;
+ else if (need_percent)
+ extra_offset = LEVEL_OFFSET_STEP;
+
+ folded_sign = callchain_list__folded(chain);
+
+ row += hist_browser__show_callchain_list(browser, child,
+ chain, row, total,
+ was_first && need_percent,
+ offset + extra_offset,
+ print, arg);
+
+ if (is_output_full(browser, row))
+ goto out;
+
+ if (folded_sign == '+')
+ goto next;
+ }
+
+ list_for_each_entry(chain, &child->val, list) {
+ bool was_first = first;
+
+ if (first)
+ first = false;
+ else if (need_percent)
+ extra_offset = LEVEL_OFFSET_STEP;
+
+ folded_sign = callchain_list__folded(chain);
+
+ row += hist_browser__show_callchain_list(browser, child,
+ chain, row, total,
+ was_first && need_percent,
+ offset + extra_offset,
+ print, arg);
+
+ if (is_output_full(browser, row))
+ goto out;
+
+ if (folded_sign == '+')
+ break;
+ }
+
+next:
+ if (is_output_full(browser, row))
+ break;
+ node = next;
+ }
+out:
+ return row - first_row;
+}
+
+static char *hist_browser__folded_callchain_str(struct hist_browser *browser,
+ struct callchain_list *chain,
+ char *value_str, char *old_str)
+{
+ char bf[1024];
+ const char *str;
+ char *new;
+
+ str = callchain_list__sym_name(chain, bf, sizeof(bf),
+ browser->show_dso);
+ if (old_str) {
+ if (asprintf(&new, "%s%s%s", old_str,
+ symbol_conf.field_sep ?: ";", str) < 0)
+ new = NULL;
+ } else {
+ if (value_str) {
+ if (asprintf(&new, "%s %s", value_str, str) < 0)
+ new = NULL;
+ } else {
+ if (asprintf(&new, "%s", str) < 0)
+ new = NULL;
+ }
+ }
+ return new;
+}
+
+static int hist_browser__show_callchain_folded(struct hist_browser *browser,
+ struct rb_root *root,
+ unsigned short row, u64 total,
+ print_callchain_entry_fn print,
+ struct callchain_print_arg *arg,
+ check_output_full_fn is_output_full)
+{
+ struct rb_node *node;
+ int first_row = row, offset = LEVEL_OFFSET_STEP;
+ bool need_percent;
+
+ node = rb_first(root);
+ need_percent = node && rb_next(node);
+
+ while (node) {
+ struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
+ struct rb_node *next = rb_next(node);
+ struct callchain_list *chain, *first_chain = NULL;
+ int first = true;
+ char *value_str = NULL, *value_str_alloc = NULL;
+ char *chain_str = NULL, *chain_str_alloc = NULL;
+
+ if (arg->row_offset != 0) {
+ arg->row_offset--;
+ goto next;
+ }
+
+ if (need_percent) {
+ char buf[64];
+
+ callchain_node__scnprintf_value(child, buf, sizeof(buf), total);
+ if (asprintf(&value_str, "%s", buf) < 0) {
+ value_str = (char *)"<...>";
+ goto do_print;
+ }
+ value_str_alloc = value_str;
+ }
+
+ list_for_each_entry(chain, &child->parent_val, list) {
+ chain_str = hist_browser__folded_callchain_str(browser,
+ chain, value_str, chain_str);
+ if (first) {
+ first = false;
+ first_chain = chain;
+ }
+
+ if (chain_str == NULL) {
+ chain_str = (char *)"Not enough memory!";
+ goto do_print;
+ }
+
+ chain_str_alloc = chain_str;
+ }
+
+ list_for_each_entry(chain, &child->val, list) {
+ chain_str = hist_browser__folded_callchain_str(browser,
+ chain, value_str, chain_str);
+ if (first) {
+ first = false;
+ first_chain = chain;
+ }
+
+ if (chain_str == NULL) {
+ chain_str = (char *)"Not enough memory!";
+ goto do_print;
+ }
+
+ chain_str_alloc = chain_str;
+ }
+
+do_print:
+ print(browser, first_chain, chain_str, offset, row++, arg);
+ free(value_str_alloc);
+ free(chain_str_alloc);
+
+next:
+ if (is_output_full(browser, row))
+ break;
+ node = next;
+ }
+
+ return row - first_row;
+}
+
static int hist_browser__show_callchain(struct hist_browser *browser,
struct rb_root *root, int level,
unsigned short row, u64 total,
@@ -592,15 +862,12 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
struct rb_node *next = rb_next(node);
- u64 cumul = callchain_cumul_hits(child);
struct callchain_list *chain;
char folded_sign = ' ';
int first = true;
int extra_offset = 0;
list_for_each_entry(chain, &child->val, list) {
- char bf[1024], *alloc_str;
- const char *str;
bool was_first = first;
if (first)
@@ -609,31 +876,16 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
extra_offset = LEVEL_OFFSET_STEP;
folded_sign = callchain_list__folded(chain);
- if (arg->row_offset != 0) {
- arg->row_offset--;
- goto do_next;
- }
-
- alloc_str = NULL;
- str = callchain_list__sym_name(chain, bf, sizeof(bf),
- browser->show_dso);
-
- if (was_first && need_percent) {
- double percent = cumul * 100.0 / total;
- if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
- str = "Not enough memory!";
- else
- str = alloc_str;
- }
-
- print(browser, chain, str, offset + extra_offset, row, arg);
+ row += hist_browser__show_callchain_list(browser, child,
+ chain, row, total,
+ was_first && need_percent,
+ offset + extra_offset,
+ print, arg);
- free(alloc_str);
-
- if (is_output_full(browser, ++row))
+ if (is_output_full(browser, row))
goto out;
-do_next:
+
if (folded_sign == '+')
break;
}
@@ -789,7 +1041,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
hist_browser__gotorc(browser, row, 0);
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
+ if (perf_hpp__should_skip(fmt, entry->hists) ||
+ column++ < browser->b.horiz_scroll)
continue;
if (current_entry && browser->b.navkeypressed) {
@@ -844,10 +1097,22 @@ static int hist_browser__show_entry(struct hist_browser *browser,
total = entry->stat.period;
}
- printed += hist_browser__show_callchain(browser,
+ if (callchain_param.mode == CHAIN_FLAT) {
+ printed += hist_browser__show_callchain_flat(browser,
+ &entry->sorted_chain, row, total,
+ hist_browser__show_callchain_entry, &arg,
+ hist_browser__check_output_full);
+ } else if (callchain_param.mode == CHAIN_FOLDED) {
+ printed += hist_browser__show_callchain_folded(browser,
+ &entry->sorted_chain, row, total,
+ hist_browser__show_callchain_entry, &arg,
+ hist_browser__check_output_full);
+ } else {
+ printed += hist_browser__show_callchain(browser,
&entry->sorted_chain, 1, row, total,
hist_browser__show_callchain_entry, &arg,
hist_browser__check_output_full);
+ }
if (arg.is_current_entry)
browser->he_selection = entry;
@@ -880,7 +1145,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
}
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt) || column++ < browser->b.horiz_scroll)
+ if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
continue;
ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists));
@@ -928,6 +1193,8 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
}
ui_browser__hists_init_top(browser);
+ hb->he_selection = NULL;
+ hb->selection = NULL;
for (nd = browser->top; nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1033,6 +1300,9 @@ static void ui_browser__hists_seek(struct ui_browser *browser,
* and stop when we printed enough lines to fill the screen.
*/
do_offset:
+ if (!nd)
+ return;
+
if (offset > 0) {
do {
h = rb_entry(nd, struct hist_entry, rb_node);
@@ -1145,7 +1415,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
printed += fprintf(fp, "%c ", folded_sign);
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, he->hists))
continue;
if (!first) {
@@ -1430,7 +1700,6 @@ close_file_and_continue:
struct popup_action {
struct thread *thread;
- struct dso *dso;
struct map_symbol ms;
int socket;
@@ -1565,7 +1834,6 @@ add_dso_opt(struct hist_browser *browser, struct popup_action *act,
return 0;
act->ms.map = map;
- act->dso = map->dso;
act->fn = do_zoom_dso;
return 1;
}
@@ -1796,10 +2064,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
SLang_reset_tty();
SLang_init_tty(0, 0, 0);
- if (min_pcnt) {
+ if (min_pcnt)
browser->min_pcnt = min_pcnt;
- hist_browser__update_nr_entries(browser);
- }
+ hist_browser__update_nr_entries(browser);
browser->pstack = pstack__new(3);
if (browser->pstack == NULL)
@@ -1827,7 +2094,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
while (1) {
struct thread *thread = NULL;
- struct dso *dso = NULL;
struct map *map = NULL;
int choice = 0;
int socked_id = -1;
@@ -1839,8 +2105,6 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (browser->he_selection != NULL) {
thread = hist_browser__selected_thread(browser);
map = browser->selection->map;
- if (map)
- dso = map->dso;
socked_id = browser->he_selection->socket;
}
switch (key) {
@@ -1874,7 +2138,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
hist_browser__dump(browser);
continue;
case 'd':
- actions->dso = dso;
+ actions->ms.map = map;
do_zoom_dso(browser, actions);
continue;
case 'V':
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 4b3585e..0f8dcfd 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -89,8 +89,8 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_acc;
}
-static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
- GtkTreeIter *parent, int col, u64 total)
+static void perf_gtk__add_callchain_flat(struct rb_root *root, GtkTreeStore *store,
+ GtkTreeIter *parent, int col, u64 total)
{
struct rb_node *nd;
bool has_single_node = (rb_first(root) == rb_last(root));
@@ -100,13 +100,132 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
struct callchain_list *chain;
GtkTreeIter iter, new_parent;
bool need_new_parent;
- double percent;
- u64 hits, child_total;
node = rb_entry(nd, struct callchain_node, rb_node);
- hits = callchain_cumul_hits(node);
- percent = 100.0 * hits / total;
+ new_parent = *parent;
+ need_new_parent = !has_single_node;
+
+ callchain_node__make_parent_list(node);
+
+ list_for_each_entry(chain, &node->parent_val, list) {
+ char buf[128];
+
+ gtk_tree_store_append(store, &iter, &new_parent);
+
+ callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+ gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+ callchain_list__sym_name(chain, buf, sizeof(buf), false);
+ gtk_tree_store_set(store, &iter, col, buf, -1);
+
+ if (need_new_parent) {
+ /*
+ * Only show the top-most symbol in a callchain
+ * if it's not the only callchain.
+ */
+ new_parent = iter;
+ need_new_parent = false;
+ }
+ }
+
+ list_for_each_entry(chain, &node->val, list) {
+ char buf[128];
+
+ gtk_tree_store_append(store, &iter, &new_parent);
+
+ callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+ gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+ callchain_list__sym_name(chain, buf, sizeof(buf), false);
+ gtk_tree_store_set(store, &iter, col, buf, -1);
+
+ if (need_new_parent) {
+ /*
+ * Only show the top-most symbol in a callchain
+ * if it's not the only callchain.
+ */
+ new_parent = iter;
+ need_new_parent = false;
+ }
+ }
+ }
+}
+
+static void perf_gtk__add_callchain_folded(struct rb_root *root, GtkTreeStore *store,
+ GtkTreeIter *parent, int col, u64 total)
+{
+ struct rb_node *nd;
+
+ for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+ struct callchain_node *node;
+ struct callchain_list *chain;
+ GtkTreeIter iter;
+ char buf[64];
+ char *str, *str_alloc = NULL;
+ bool first = true;
+
+ node = rb_entry(nd, struct callchain_node, rb_node);
+
+ callchain_node__make_parent_list(node);
+
+ list_for_each_entry(chain, &node->parent_val, list) {
+ char name[1024];
+
+ callchain_list__sym_name(chain, name, sizeof(name), false);
+
+ if (asprintf(&str, "%s%s%s",
+ first ? "" : str_alloc,
+ first ? "" : symbol_conf.field_sep ?: "; ",
+ name) < 0)
+ return;
+
+ first = false;
+ free(str_alloc);
+ str_alloc = str;
+ }
+
+ list_for_each_entry(chain, &node->val, list) {
+ char name[1024];
+
+ callchain_list__sym_name(chain, name, sizeof(name), false);
+
+ if (asprintf(&str, "%s%s%s",
+ first ? "" : str_alloc,
+ first ? "" : symbol_conf.field_sep ?: "; ",
+ name) < 0)
+ return;
+
+ first = false;
+ free(str_alloc);
+ str_alloc = str;
+ }
+
+ gtk_tree_store_append(store, &iter, parent);
+
+ callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
+ gtk_tree_store_set(store, &iter, 0, buf, -1);
+
+ gtk_tree_store_set(store, &iter, col, str, -1);
+
+ free(str_alloc);
+ }
+}
+
+static void perf_gtk__add_callchain_graph(struct rb_root *root, GtkTreeStore *store,
+ GtkTreeIter *parent, int col, u64 total)
+{
+ struct rb_node *nd;
+ bool has_single_node = (rb_first(root) == rb_last(root));
+
+ for (nd = rb_first(root); nd; nd = rb_next(nd)) {
+ struct callchain_node *node;
+ struct callchain_list *chain;
+ GtkTreeIter iter, new_parent;
+ bool need_new_parent;
+ u64 child_total;
+
+ node = rb_entry(nd, struct callchain_node, rb_node);
new_parent = *parent;
need_new_parent = !has_single_node && (node->val_nr > 1);
@@ -116,7 +235,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
gtk_tree_store_append(store, &iter, &new_parent);
- scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
+ callchain_node__scnprintf_value(node, buf, sizeof(buf), total);
gtk_tree_store_set(store, &iter, 0, buf, -1);
callchain_list__sym_name(chain, buf, sizeof(buf), false);
@@ -138,11 +257,22 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
child_total = total;
/* Now 'iter' contains info of the last callchain_list */
- perf_gtk__add_callchain(&node->rb_root, store, &iter, col,
- child_total);
+ perf_gtk__add_callchain_graph(&node->rb_root, store, &iter, col,
+ child_total);
}
}
+static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
+ GtkTreeIter *parent, int col, u64 total)
+{
+ if (callchain_param.mode == CHAIN_FLAT)
+ perf_gtk__add_callchain_flat(root, store, parent, col, total);
+ else if (callchain_param.mode == CHAIN_FOLDED)
+ perf_gtk__add_callchain_folded(root, store, parent, col, total);
+ else
+ perf_gtk__add_callchain_graph(root, store, parent, col, total);
+}
+
static void on_row_activated(GtkTreeView *view, GtkTreePath *path,
GtkTreeViewColumn *col __maybe_unused,
gpointer user_data __maybe_unused)
@@ -188,7 +318,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, hists))
continue;
/*
@@ -238,7 +368,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, h->hists))
continue;
if (fmt->color)
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index 5029ba2..bf2a66e 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -443,7 +443,6 @@ LIST_HEAD(perf_hpp__sort_list);
void perf_hpp__init(void)
{
- struct list_head *list;
int i;
for (i = 0; i < PERF_HPP__MAX_INDEX; i++) {
@@ -484,17 +483,6 @@ void perf_hpp__init(void)
if (symbol_conf.show_total_period)
hpp_dimension__add_output(PERF_HPP__PERIOD);
-
- /* prepend overhead field for backward compatiblity. */
- list = &perf_hpp__format[PERF_HPP__OVERHEAD].sort_list;
- if (list_empty(list))
- list_add(list, &perf_hpp__sort_list);
-
- if (symbol_conf.cumulate_callchain) {
- list = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC].sort_list;
- if (list_empty(list))
- list_add(list, &perf_hpp__sort_list);
- }
}
void perf_hpp__column_register(struct perf_hpp_fmt *format)
@@ -619,7 +607,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
struct perf_hpp dummy_hpp;
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, hists))
continue;
if (first)
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index dfcbc90..387110d 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -34,10 +34,10 @@ static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask,
return ret;
}
-static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
+static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_node *node,
+ struct callchain_list *chain,
int depth, int depth_mask, int period,
- u64 total_samples, u64 hits,
- int left_margin)
+ u64 total_samples, int left_margin)
{
int i;
size_t ret = 0;
@@ -50,10 +50,9 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
else
ret += fprintf(fp, " ");
if (!period && i == depth - 1) {
- double percent;
-
- percent = hits * 100.0 / total_samples;
- ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent);
+ ret += fprintf(fp, "--");
+ ret += callchain_node__fprintf_value(node, fp, total_samples);
+ ret += fprintf(fp, "--");
} else
ret += fprintf(fp, "%s", " ");
}
@@ -82,13 +81,14 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
int depth_mask, int left_margin)
{
struct rb_node *node, *next;
- struct callchain_node *child;
+ struct callchain_node *child = NULL;
struct callchain_list *chain;
int new_depth_mask = depth_mask;
u64 remaining;
size_t ret = 0;
int i;
uint entries_printed = 0;
+ int cumul_count = 0;
remaining = total_samples;
@@ -100,6 +100,7 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
child = rb_entry(node, struct callchain_node, rb_node);
cumul = callchain_cumul_hits(child);
remaining -= cumul;
+ cumul_count += callchain_cumul_counts(child);
/*
* The depth mask manages the output of pipes that show
@@ -120,10 +121,9 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
left_margin);
i = 0;
list_for_each_entry(chain, &child->val, list) {
- ret += ipchain__fprintf_graph(fp, chain, depth,
+ ret += ipchain__fprintf_graph(fp, child, chain, depth,
new_depth_mask, i++,
total_samples,
- cumul,
left_margin);
}
@@ -143,14 +143,23 @@ static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root,
if (callchain_param.mode == CHAIN_GRAPH_REL &&
remaining && remaining != total_samples) {
+ struct callchain_node rem_node = {
+ .hit = remaining,
+ };
if (!rem_sq_bracket)
return ret;
+ if (callchain_param.value == CCVAL_COUNT && child && child->parent) {
+ rem_node.count = child->parent->children_count - cumul_count;
+ if (rem_node.count <= 0)
+ return ret;
+ }
+
new_depth_mask &= ~(1 << (depth - 1));
- ret += ipchain__fprintf_graph(fp, &rem_hits, depth,
+ ret += ipchain__fprintf_graph(fp, &rem_node, &rem_hits, depth,
new_depth_mask, 0, total_samples,
- remaining, left_margin);
+ left_margin);
}
return ret;
@@ -243,12 +252,11 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
struct rb_node *rb_node = rb_first(tree);
while (rb_node) {
- double percent;
-
chain = rb_entry(rb_node, struct callchain_node, rb_node);
- percent = chain->hit * 100.0 / total_samples;
- ret = percent_color_fprintf(fp, " %6.2f%%\n", percent);
+ ret += fprintf(fp, " ");
+ ret += callchain_node__fprintf_value(chain, fp, total_samples);
+ ret += fprintf(fp, "\n");
ret += __callchain__fprintf_flat(fp, chain, total_samples);
ret += fprintf(fp, "\n");
if (++entries_printed == callchain_param.print_limit)
@@ -260,6 +268,57 @@ static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *tree,
return ret;
}
+static size_t __callchain__fprintf_folded(FILE *fp, struct callchain_node *node)
+{
+ const char *sep = symbol_conf.field_sep ?: ";";
+ struct callchain_list *chain;
+ size_t ret = 0;
+ char bf[1024];
+ bool first;
+
+ if (!node)
+ return 0;
+
+ ret += __callchain__fprintf_folded(fp, node->parent);
+
+ first = (ret == 0);
+ list_for_each_entry(chain, &node->val, list) {
+ if (chain->ip >= PERF_CONTEXT_MAX)
+ continue;
+ ret += fprintf(fp, "%s%s", first ? "" : sep,
+ callchain_list__sym_name(chain,
+ bf, sizeof(bf), false));
+ first = false;
+ }
+
+ return ret;
+}
+
+static size_t callchain__fprintf_folded(FILE *fp, struct rb_root *tree,
+ u64 total_samples)
+{
+ size_t ret = 0;
+ u32 entries_printed = 0;
+ struct callchain_node *chain;
+ struct rb_node *rb_node = rb_first(tree);
+
+ while (rb_node) {
+
+ chain = rb_entry(rb_node, struct callchain_node, rb_node);
+
+ ret += callchain_node__fprintf_value(chain, fp, total_samples);
+ ret += fprintf(fp, " ");
+ ret += __callchain__fprintf_folded(fp, chain);
+ ret += fprintf(fp, "\n");
+ if (++entries_printed == callchain_param.print_limit)
+ break;
+
+ rb_node = rb_next(rb_node);
+ }
+
+ return ret;
+}
+
static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
u64 total_samples, int left_margin,
FILE *fp)
@@ -278,6 +337,9 @@ static size_t hist_entry_callchain__fprintf(struct hist_entry *he,
case CHAIN_FLAT:
return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples);
break;
+ case CHAIN_FOLDED:
+ return callchain__fprintf_folded(fp, &he->sorted_chain, total_samples);
+ break;
case CHAIN_NONE:
break;
default:
@@ -323,7 +385,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
return 0;
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, he->hists))
continue;
/*
@@ -402,7 +464,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "# ");
perf_hpp__for_each_format(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, hists))
continue;
if (!first)
@@ -428,7 +490,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
perf_hpp__for_each_format(fmt) {
unsigned int i;
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, hists))
continue;
if (!first)
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 591b3fe..5eec53a 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -6,24 +6,20 @@ libperf-y += config.o
libperf-y += ctype.o
libperf-y += db-export.o
libperf-y += env.o
-libperf-y += environment.o
libperf-y += event.o
libperf-y += evlist.o
libperf-y += evsel.o
-libperf-y += exec_cmd.o
-libperf-y += find_next_bit.o
-libperf-y += help.o
+libperf-y += find_bit.o
libperf-y += kallsyms.o
libperf-y += levenshtein.o
libperf-y += llvm-utils.o
-libperf-y += parse-options.o
libperf-y += parse-events.o
libperf-y += perf_regs.o
libperf-y += path.o
libperf-y += rbtree.o
+libperf-y += libstring.o
libperf-y += bitmap.o
libperf-y += hweight.o
-libperf-y += run-command.o
libperf-y += quote.o
libperf-y += strbuf.o
libperf-y += string.o
@@ -32,11 +28,9 @@ libperf-y += strfilter.o
libperf-y += top.o
libperf-y += usage.o
libperf-y += wrapper.o
-libperf-y += sigchain.o
libperf-y += dso.o
libperf-y += symbol.o
libperf-y += color.o
-libperf-y += pager.o
libperf-y += header.o
libperf-y += callchain.o
libperf-y += values.o
@@ -86,8 +80,11 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt.o
libperf-$(CONFIG_AUXTRACE) += intel-bts.o
libperf-y += parse-branch-options.o
libperf-y += parse-regs-options.o
+libperf-y += term.o
+libperf-y += help-unknown-cmd.o
libperf-$(CONFIG_LIBBPF) += bpf-loader.o
+libperf-$(CONFIG_BPF_PROLOGUE) += bpf-prologue.o
libperf-$(CONFIG_LIBELF) += symbol-elf.o
libperf-$(CONFIG_LIBELF) += probe-file.o
libperf-$(CONFIG_LIBELF) += probe-event.o
@@ -110,7 +107,6 @@ libperf-$(CONFIG_ZLIB) += zlib.o
libperf-$(CONFIG_LZMA) += lzma.o
CFLAGS_config.o += -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
-CFLAGS_exec_cmd.o += -DPERF_EXEC_PATH="BUILD_STR($(perfexecdir_SQ))" -DPREFIX="BUILD_STR($(prefix_SQ))"
$(OUTPUT)util/parse-events-flex.c: util/parse-events.l $(OUTPUT)util/parse-events-bison.c
$(call rule_mkdir)
@@ -136,8 +132,10 @@ CFLAGS_pmu-bison.o += -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -w
$(OUTPUT)util/parse-events.o: $(OUTPUT)util/parse-events-flex.c $(OUTPUT)util/parse-events-bison.c
$(OUTPUT)util/pmu.o: $(OUTPUT)util/pmu-flex.c $(OUTPUT)util/pmu-bison.c
-CFLAGS_find_next_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_bitmap.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_find_bit.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
CFLAGS_rbtree.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
+CFLAGS_libstring.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
CFLAGS_hweight.o += -Wno-unused-parameter -DETC_PERFCONFIG="BUILD_STR($(ETC_PERFCONFIG_SQ))"
CFLAGS_parse-events.o += -Wno-redundant-decls
@@ -145,7 +143,11 @@ $(OUTPUT)util/kallsyms.o: ../lib/symbol/kallsyms.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
-$(OUTPUT)util/find_next_bit.o: ../lib/util/find_next_bit.c FORCE
+$(OUTPUT)util/bitmap.o: ../lib/bitmap.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cc_o_c)
+
+$(OUTPUT)util/find_bit.o: ../lib/find_bit.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
@@ -153,6 +155,10 @@ $(OUTPUT)util/rbtree.o: ../lib/rbtree.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
+$(OUTPUT)util/libstring.o: ../lib/string.c FORCE
+ $(call rule_mkdir)
+ $(call if_changed_dep,cc_o_c)
+
$(OUTPUT)util/hweight.o: ../lib/hweight.c FORCE
$(call rule_mkdir)
$(call if_changed_dep,cc_o_c)
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 0fc8d7a..b795b69 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -65,6 +65,11 @@ static int call__parse(struct ins_operands *ops)
name++;
+#ifdef __arm__
+ if (strchr(name, '+'))
+ return -1;
+#endif
+
tok = strchr(name, '>');
if (tok == NULL)
return -1;
@@ -246,7 +251,11 @@ static int mov__parse(struct ins_operands *ops)
return -1;
target = ++s;
+#ifdef __arm__
+ comment = strchr(s, ';');
+#else
comment = strchr(s, '#');
+#endif
if (comment != NULL)
s = comment - 1;
@@ -354,6 +363,20 @@ static struct ins instructions[] = {
{ .name = "addq", .ops = &mov_ops, },
{ .name = "addw", .ops = &mov_ops, },
{ .name = "and", .ops = &mov_ops, },
+#ifdef __arm__
+ { .name = "b", .ops = &jump_ops, }, // might also be a call
+ { .name = "bcc", .ops = &jump_ops, },
+ { .name = "bcs", .ops = &jump_ops, },
+ { .name = "beq", .ops = &jump_ops, },
+ { .name = "bge", .ops = &jump_ops, },
+ { .name = "bgt", .ops = &jump_ops, },
+ { .name = "bhi", .ops = &jump_ops, },
+ { .name = "bl", .ops = &call_ops, },
+ { .name = "blt", .ops = &jump_ops, },
+ { .name = "bls", .ops = &jump_ops, },
+ { .name = "blx", .ops = &call_ops, },
+ { .name = "bne", .ops = &jump_ops, },
+#endif
{ .name = "bts", .ops = &mov_ops, },
{ .name = "call", .ops = &call_ops, },
{ .name = "callq", .ops = &call_ops, },
@@ -1084,6 +1107,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
struct kcore_extract kce;
bool delete_extract = false;
int lineno = 0;
+ int nline;
if (filename)
symbol__join_symfs(symfs_filename, filename);
@@ -1179,6 +1203,9 @@ fallback:
ret = decompress_to_file(m.ext, symfs_filename, fd);
+ if (ret)
+ pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
+
free(m.ext);
close(fd);
@@ -1204,13 +1231,25 @@ fallback:
pr_debug("Executing: %s\n", command);
file = popen(command, "r");
- if (!file)
+ if (!file) {
+ pr_err("Failure running %s\n", command);
+ /*
+ * If we were using debug info should retry with
+ * original binary.
+ */
goto out_remove_tmp;
+ }
- while (!feof(file))
+ nline = 0;
+ while (!feof(file)) {
if (symbol__parse_objdump_line(sym, map, file, privsize,
&lineno) < 0)
break;
+ nline++;
+ }
+
+ if (nline == 0)
+ pr_err("No output from %s\n", command);
/*
* kallsyms does not have symbol sizes so there may a nop at the end.
@@ -1604,6 +1643,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map,
len = symbol__size(sym);
if (print_lines) {
+ srcline_full_filename = full_paths;
symbol__get_source_line(sym, map, evsel, &source_line, len);
print_summary(&source_line, dso->long_name);
}
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
index 7f10430a..360fda0 100644
--- a/tools/perf/util/auxtrace.c
+++ b/tools/perf/util/auxtrace.c
@@ -45,7 +45,7 @@
#include "event.h"
#include "session.h"
#include "debug.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "intel-pt.h"
#include "intel-bts.h"
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index ba6f752..540a7ef 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -5,11 +5,15 @@
* Copyright (C) 2015 Huawei Inc.
*/
+#include <linux/bpf.h>
#include <bpf/libbpf.h>
#include <linux/err.h>
+#include <linux/string.h>
#include "perf.h"
#include "debug.h"
#include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "llvm-utils.h"
#include "probe-event.h"
#include "probe-finder.h" // for MAX_PROBES
#include "llvm-utils.h"
@@ -26,18 +30,44 @@ static int libbpf_##name(const char *fmt, ...) \
return ret; \
}
-DEFINE_PRINT_FN(warning, 0)
-DEFINE_PRINT_FN(info, 0)
+DEFINE_PRINT_FN(warning, 1)
+DEFINE_PRINT_FN(info, 1)
DEFINE_PRINT_FN(debug, 1)
struct bpf_prog_priv {
struct perf_probe_event pev;
+ bool need_prologue;
+ struct bpf_insn *insns_buf;
+ int nr_types;
+ int *type_mapping;
};
+static bool libbpf_initialized;
+
+struct bpf_object *
+bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
+{
+ struct bpf_object *obj;
+
+ if (!libbpf_initialized) {
+ libbpf_set_print(libbpf_warning,
+ libbpf_info,
+ libbpf_debug);
+ libbpf_initialized = true;
+ }
+
+ obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, name);
+ if (IS_ERR(obj)) {
+ pr_debug("bpf: failed to load buffer\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ return obj;
+}
+
struct bpf_object *bpf__prepare_load(const char *filename, bool source)
{
struct bpf_object *obj;
- static bool libbpf_initialized;
if (!libbpf_initialized) {
libbpf_set_print(libbpf_warning,
@@ -53,15 +83,15 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
if (err)
- return ERR_PTR(err);
+ return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
free(obj_buf);
} else
obj = bpf_object__open(filename);
- if (!obj) {
+ if (IS_ERR(obj)) {
pr_debug("bpf: failed to load %s\n", filename);
- return ERR_PTR(-EINVAL);
+ return obj;
}
return obj;
@@ -84,10 +114,178 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
struct bpf_prog_priv *priv = _priv;
cleanup_perf_probe_events(&priv->pev, 1);
+ zfree(&priv->insns_buf);
+ zfree(&priv->type_mapping);
free(priv);
}
static int
+prog_config__exec(const char *value, struct perf_probe_event *pev)
+{
+ pev->uprobes = true;
+ pev->target = strdup(value);
+ if (!pev->target)
+ return -ENOMEM;
+ return 0;
+}
+
+static int
+prog_config__module(const char *value, struct perf_probe_event *pev)
+{
+ pev->uprobes = false;
+ pev->target = strdup(value);
+ if (!pev->target)
+ return -ENOMEM;
+ return 0;
+}
+
+static int
+prog_config__bool(const char *value, bool *pbool, bool invert)
+{
+ int err;
+ bool bool_value;
+
+ if (!pbool)
+ return -EINVAL;
+
+ err = strtobool(value, &bool_value);
+ if (err)
+ return err;
+
+ *pbool = invert ? !bool_value : bool_value;
+ return 0;
+}
+
+static int
+prog_config__inlines(const char *value,
+ struct perf_probe_event *pev __maybe_unused)
+{
+ return prog_config__bool(value, &probe_conf.no_inlines, true);
+}
+
+static int
+prog_config__force(const char *value,
+ struct perf_probe_event *pev __maybe_unused)
+{
+ return prog_config__bool(value, &probe_conf.force_add, false);
+}
+
+static struct {
+ const char *key;
+ const char *usage;
+ const char *desc;
+ int (*func)(const char *, struct perf_probe_event *);
+} bpf_prog_config_terms[] = {
+ {
+ .key = "exec",
+ .usage = "exec=<full path of file>",
+ .desc = "Set uprobe target",
+ .func = prog_config__exec,
+ },
+ {
+ .key = "module",
+ .usage = "module=<module name> ",
+ .desc = "Set kprobe module",
+ .func = prog_config__module,
+ },
+ {
+ .key = "inlines",
+ .usage = "inlines=[yes|no] ",
+ .desc = "Probe at inline symbol",
+ .func = prog_config__inlines,
+ },
+ {
+ .key = "force",
+ .usage = "force=[yes|no] ",
+ .desc = "Forcibly add events with existing name",
+ .func = prog_config__force,
+ },
+};
+
+static int
+do_prog_config(const char *key, const char *value,
+ struct perf_probe_event *pev)
+{
+ unsigned int i;
+
+ pr_debug("config bpf program: %s=%s\n", key, value);
+ for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
+ if (strcmp(key, bpf_prog_config_terms[i].key) == 0)
+ return bpf_prog_config_terms[i].func(value, pev);
+
+ pr_debug("BPF: ERROR: invalid program config option: %s=%s\n",
+ key, value);
+
+ pr_debug("\nHint: Valid options are:\n");
+ for (i = 0; i < ARRAY_SIZE(bpf_prog_config_terms); i++)
+ pr_debug("\t%s:\t%s\n", bpf_prog_config_terms[i].usage,
+ bpf_prog_config_terms[i].desc);
+ pr_debug("\n");
+
+ return -BPF_LOADER_ERRNO__PROGCONF_TERM;
+}
+
+static const char *
+parse_prog_config_kvpair(const char *config_str, struct perf_probe_event *pev)
+{
+ char *text = strdup(config_str);
+ char *sep, *line;
+ const char *main_str = NULL;
+ int err = 0;
+
+ if (!text) {
+ pr_debug("No enough memory: dup config_str failed\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ line = text;
+ while ((sep = strchr(line, ';'))) {
+ char *equ;
+
+ *sep = '\0';
+ equ = strchr(line, '=');
+ if (!equ) {
+ pr_warning("WARNING: invalid config in BPF object: %s\n",
+ line);
+ pr_warning("\tShould be 'key=value'.\n");
+ goto nextline;
+ }
+ *equ = '\0';
+
+ err = do_prog_config(line, equ + 1, pev);
+ if (err)
+ break;
+nextline:
+ line = sep + 1;
+ }
+
+ if (!err)
+ main_str = config_str + (line - text);
+ free(text);
+
+ return err ? ERR_PTR(err) : main_str;
+}
+
+static int
+parse_prog_config(const char *config_str, struct perf_probe_event *pev)
+{
+ int err;
+ const char *main_str = parse_prog_config_kvpair(config_str, pev);
+
+ if (IS_ERR(main_str))
+ return PTR_ERR(main_str);
+
+ err = parse_perf_probe_command(main_str, pev);
+ if (err < 0) {
+ pr_debug("bpf: '%s' is not a valid config string\n",
+ config_str);
+ /* parse failed, don't need clear pev. */
+ return -BPF_LOADER_ERRNO__CONFIG;
+ }
+ return 0;
+}
+
+static int
config_bpf_program(struct bpf_program *prog)
{
struct perf_probe_event *pev = NULL;
@@ -95,10 +293,14 @@ config_bpf_program(struct bpf_program *prog)
const char *config_str;
int err;
+ /* Initialize per-program probing setting */
+ probe_conf.no_inlines = false;
+ probe_conf.force_add = false;
+
config_str = bpf_program__title(prog, false);
- if (!config_str) {
+ if (IS_ERR(config_str)) {
pr_debug("bpf: unable to get title for program\n");
- return -EINVAL;
+ return PTR_ERR(config_str);
}
priv = calloc(sizeof(*priv), 1);
@@ -109,18 +311,14 @@ config_bpf_program(struct bpf_program *prog)
pev = &priv->pev;
pr_debug("bpf: config program '%s'\n", config_str);
- err = parse_perf_probe_command(config_str, pev);
- if (err < 0) {
- pr_debug("bpf: '%s' is not a valid config string\n",
- config_str);
- err = -EINVAL;
+ err = parse_prog_config(config_str, pev);
+ if (err)
goto errout;
- }
if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
pr_debug("bpf: '%s': group for event is set and not '%s'.\n",
config_str, PERF_BPF_PROBE_GROUP);
- err = -EINVAL;
+ err = -BPF_LOADER_ERRNO__GROUP;
goto errout;
} else if (!pev->group)
pev->group = strdup(PERF_BPF_PROBE_GROUP);
@@ -132,9 +330,9 @@ config_bpf_program(struct bpf_program *prog)
}
if (!pev->event) {
- pr_debug("bpf: '%s': event name is missing\n",
+ pr_debug("bpf: '%s': event name is missing. Section name should be 'key=value'\n",
config_str);
- err = -EINVAL;
+ err = -BPF_LOADER_ERRNO__EVENTNAME;
goto errout;
}
pr_debug("bpf: config '%s' is ok\n", config_str);
@@ -175,6 +373,220 @@ static int bpf__prepare_probe(void)
return err;
}
+static int
+preproc_gen_prologue(struct bpf_program *prog, int n,
+ struct bpf_insn *orig_insns, int orig_insns_cnt,
+ struct bpf_prog_prep_result *res)
+{
+ struct probe_trace_event *tev;
+ struct perf_probe_event *pev;
+ struct bpf_prog_priv *priv;
+ struct bpf_insn *buf;
+ size_t prologue_cnt = 0;
+ int i, err;
+
+ err = bpf_program__get_private(prog, (void **)&priv);
+ if (err || !priv)
+ goto errout;
+
+ pev = &priv->pev;
+
+ if (n < 0 || n >= priv->nr_types)
+ goto errout;
+
+ /* Find a tev belongs to that type */
+ for (i = 0; i < pev->ntevs; i++) {
+ if (priv->type_mapping[i] == n)
+ break;
+ }
+
+ if (i >= pev->ntevs) {
+ pr_debug("Internal error: prologue type %d not found\n", n);
+ return -BPF_LOADER_ERRNO__PROLOGUE;
+ }
+
+ tev = &pev->tevs[i];
+
+ buf = priv->insns_buf;
+ err = bpf__gen_prologue(tev->args, tev->nargs,
+ buf, &prologue_cnt,
+ BPF_MAXINSNS - orig_insns_cnt);
+ if (err) {
+ const char *title;
+
+ title = bpf_program__title(prog, false);
+ if (!title)
+ title = "[unknown]";
+
+ pr_debug("Failed to generate prologue for program %s\n",
+ title);
+ return err;
+ }
+
+ memcpy(&buf[prologue_cnt], orig_insns,
+ sizeof(struct bpf_insn) * orig_insns_cnt);
+
+ res->new_insn_ptr = buf;
+ res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
+ res->pfd = NULL;
+ return 0;
+
+errout:
+ pr_debug("Internal error in preproc_gen_prologue\n");
+ return -BPF_LOADER_ERRNO__PROLOGUE;
+}
+
+/*
+ * compare_tev_args is reflexive, transitive and antisymmetric.
+ * I can proof it but this margin is too narrow to contain.
+ */
+static int compare_tev_args(const void *ptev1, const void *ptev2)
+{
+ int i, ret;
+ const struct probe_trace_event *tev1 =
+ *(const struct probe_trace_event **)ptev1;
+ const struct probe_trace_event *tev2 =
+ *(const struct probe_trace_event **)ptev2;
+
+ ret = tev2->nargs - tev1->nargs;
+ if (ret)
+ return ret;
+
+ for (i = 0; i < tev1->nargs; i++) {
+ struct probe_trace_arg *arg1, *arg2;
+ struct probe_trace_arg_ref *ref1, *ref2;
+
+ arg1 = &tev1->args[i];
+ arg2 = &tev2->args[i];
+
+ ret = strcmp(arg1->value, arg2->value);
+ if (ret)
+ return ret;
+
+ ref1 = arg1->ref;
+ ref2 = arg2->ref;
+
+ while (ref1 && ref2) {
+ ret = ref2->offset - ref1->offset;
+ if (ret)
+ return ret;
+
+ ref1 = ref1->next;
+ ref2 = ref2->next;
+ }
+
+ if (ref1 || ref2)
+ return ref2 ? 1 : -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Assign a type number to each tevs in a pev.
+ * mapping is an array with same slots as tevs in that pev.
+ * nr_types will be set to number of types.
+ */
+static int map_prologue(struct perf_probe_event *pev, int *mapping,
+ int *nr_types)
+{
+ int i, type = 0;
+ struct probe_trace_event **ptevs;
+
+ size_t array_sz = sizeof(*ptevs) * pev->ntevs;
+
+ ptevs = malloc(array_sz);
+ if (!ptevs) {
+ pr_debug("No ehough memory: alloc ptevs failed\n");
+ return -ENOMEM;
+ }
+
+ pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
+ for (i = 0; i < pev->ntevs; i++)
+ ptevs[i] = &pev->tevs[i];
+
+ qsort(ptevs, pev->ntevs, sizeof(*ptevs),
+ compare_tev_args);
+
+ for (i = 0; i < pev->ntevs; i++) {
+ int n;
+
+ n = ptevs[i] - pev->tevs;
+ if (i == 0) {
+ mapping[n] = type;
+ pr_debug("mapping[%d]=%d\n", n, type);
+ continue;
+ }
+
+ if (compare_tev_args(ptevs + i, ptevs + i - 1) == 0)
+ mapping[n] = type;
+ else
+ mapping[n] = ++type;
+
+ pr_debug("mapping[%d]=%d\n", n, mapping[n]);
+ }
+ free(ptevs);
+ *nr_types = type + 1;
+
+ return 0;
+}
+
+static int hook_load_preprocessor(struct bpf_program *prog)
+{
+ struct perf_probe_event *pev;
+ struct bpf_prog_priv *priv;
+ bool need_prologue = false;
+ int err, i;
+
+ err = bpf_program__get_private(prog, (void **)&priv);
+ if (err || !priv) {
+ pr_debug("Internal error when hook preprocessor\n");
+ return -BPF_LOADER_ERRNO__INTERNAL;
+ }
+
+ pev = &priv->pev;
+ for (i = 0; i < pev->ntevs; i++) {
+ struct probe_trace_event *tev = &pev->tevs[i];
+
+ if (tev->nargs > 0) {
+ need_prologue = true;
+ break;
+ }
+ }
+
+ /*
+ * Since all tevs don't have argument, we don't need generate
+ * prologue.
+ */
+ if (!need_prologue) {
+ priv->need_prologue = false;
+ return 0;
+ }
+
+ priv->need_prologue = true;
+ priv->insns_buf = malloc(sizeof(struct bpf_insn) * BPF_MAXINSNS);
+ if (!priv->insns_buf) {
+ pr_debug("No enough memory: alloc insns_buf failed\n");
+ return -ENOMEM;
+ }
+
+ priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
+ if (!priv->type_mapping) {
+ pr_debug("No enough memory: alloc type_mapping failed\n");
+ return -ENOMEM;
+ }
+ memset(priv->type_mapping, -1,
+ sizeof(int) * pev->ntevs);
+
+ err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
+ if (err)
+ return err;
+
+ err = bpf_program__set_prep(prog, priv->nr_types,
+ preproc_gen_prologue);
+ return err;
+}
+
int bpf__probe(struct bpf_object *obj)
{
int err = 0;
@@ -209,6 +621,18 @@ int bpf__probe(struct bpf_object *obj)
pr_debug("bpf_probe: failed to apply perf probe events");
goto out;
}
+
+ /*
+ * After probing, let's consider prologue, which
+ * adds program fetcher to BPF programs.
+ *
+ * hook_load_preprocessorr() hooks pre-processor
+ * to bpf_program, let it generate prologue
+ * dynamically during loading.
+ */
+ err = hook_load_preprocessor(prog);
+ if (err)
+ goto out;
}
out:
return err < 0 ? err : 0;
@@ -285,14 +709,21 @@ int bpf__foreach_tev(struct bpf_object *obj,
(void **)&priv);
if (err || !priv) {
pr_debug("bpf: failed to get private field\n");
- return -EINVAL;
+ return -BPF_LOADER_ERRNO__INTERNAL;
}
pev = &priv->pev;
for (i = 0; i < pev->ntevs; i++) {
tev = &pev->tevs[i];
- fd = bpf_program__fd(prog);
+ if (priv->need_prologue) {
+ int type = priv->type_mapping[i];
+
+ fd = bpf_program__nth_fd(prog, type);
+ } else {
+ fd = bpf_program__fd(prog);
+ }
+
if (fd < 0) {
pr_debug("bpf: failed to get file descriptor\n");
return fd;
@@ -308,13 +739,61 @@ int bpf__foreach_tev(struct bpf_object *obj,
return 0;
}
+#define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START)
+#define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c)
+#define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START)
+
+static const char *bpf_loader_strerror_table[NR_ERRNO] = {
+ [ERRCODE_OFFSET(CONFIG)] = "Invalid config string",
+ [ERRCODE_OFFSET(GROUP)] = "Invalid group name",
+ [ERRCODE_OFFSET(EVENTNAME)] = "No event name found in config string",
+ [ERRCODE_OFFSET(INTERNAL)] = "BPF loader internal error",
+ [ERRCODE_OFFSET(COMPILE)] = "Error when compiling BPF scriptlet",
+ [ERRCODE_OFFSET(PROGCONF_TERM)] = "Invalid program config term in config string",
+ [ERRCODE_OFFSET(PROLOGUE)] = "Failed to generate prologue",
+ [ERRCODE_OFFSET(PROLOGUE2BIG)] = "Prologue too big for program",
+ [ERRCODE_OFFSET(PROLOGUEOOB)] = "Offset out of bound for prologue",
+};
+
+static int
+bpf_loader_strerror(int err, char *buf, size_t size)
+{
+ char sbuf[STRERR_BUFSIZE];
+ const char *msg;
+
+ if (!buf || !size)
+ return -1;
+
+ err = err > 0 ? err : -err;
+
+ if (err >= __LIBBPF_ERRNO__START)
+ return libbpf_strerror(err, buf, size);
+
+ if (err >= __BPF_LOADER_ERRNO__START && err < __BPF_LOADER_ERRNO__END) {
+ msg = bpf_loader_strerror_table[ERRNO_OFFSET(err)];
+ snprintf(buf, size, "%s", msg);
+ buf[size - 1] = '\0';
+ return 0;
+ }
+
+ if (err >= __BPF_LOADER_ERRNO__END)
+ snprintf(buf, size, "Unknown bpf loader error %d", err);
+ else
+ snprintf(buf, size, "%s",
+ strerror_r(err, sbuf, sizeof(sbuf)));
+
+ buf[size - 1] = '\0';
+ return -1;
+}
+
#define bpf__strerror_head(err, buf, size) \
char sbuf[STRERR_BUFSIZE], *emsg;\
if (!size)\
return 0;\
if (err < 0)\
err = -err;\
- emsg = strerror_r(err, sbuf, sizeof(sbuf));\
+ bpf_loader_strerror(err, sbuf, sizeof(sbuf));\
+ emsg = sbuf;\
switch (err) {\
default:\
scnprintf(buf, size, "%s", emsg);\
@@ -330,23 +809,66 @@ int bpf__foreach_tev(struct bpf_object *obj,
}\
buf[size - 1] = '\0';
+int bpf__strerror_prepare_load(const char *filename, bool source,
+ int err, char *buf, size_t size)
+{
+ size_t n;
+ int ret;
+
+ n = snprintf(buf, size, "Failed to load %s%s: ",
+ filename, source ? " from source" : "");
+ if (n >= size) {
+ buf[size - 1] = '\0';
+ return 0;
+ }
+ buf += n;
+ size -= n;
+
+ ret = bpf_loader_strerror(err, buf, size);
+ buf[size - 1] = '\0';
+ return ret;
+}
+
int bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
int err, char *buf, size_t size)
{
bpf__strerror_head(err, buf, size);
- bpf__strerror_entry(EEXIST, "Probe point exist. Try use 'perf probe -d \"*\"'");
- bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0\n");
- bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file\n");
+ case BPF_LOADER_ERRNO__PROGCONF_TERM: {
+ scnprintf(buf, size, "%s (add -v to see detail)", emsg);
+ break;
+ }
+ bpf__strerror_entry(EEXIST, "Probe point exist. Try 'perf probe -d \"*\"' and set 'force=yes'");
+ bpf__strerror_entry(EACCES, "You need to be root");
+ bpf__strerror_entry(EPERM, "You need to be root, and /proc/sys/kernel/kptr_restrict should be 0");
+ bpf__strerror_entry(ENOENT, "You need to check probing points in BPF file");
bpf__strerror_end(buf, size);
return 0;
}
-int bpf__strerror_load(struct bpf_object *obj __maybe_unused,
+int bpf__strerror_load(struct bpf_object *obj,
int err, char *buf, size_t size)
{
bpf__strerror_head(err, buf, size);
- bpf__strerror_entry(EINVAL, "%s: Are you root and runing a CONFIG_BPF_SYSCALL kernel?",
- emsg)
+ case LIBBPF_ERRNO__KVER: {
+ unsigned int obj_kver = bpf_object__get_kversion(obj);
+ unsigned int real_kver;
+
+ if (fetch_kernel_version(&real_kver, NULL, 0)) {
+ scnprintf(buf, size, "Unable to fetch kernel version");
+ break;
+ }
+
+ if (obj_kver != real_kver) {
+ scnprintf(buf, size,
+ "'version' ("KVER_FMT") doesn't match running kernel ("KVER_FMT")",
+ KVER_PARAM(obj_kver),
+ KVER_PARAM(real_kver));
+ break;
+ }
+
+ scnprintf(buf, size, "Failed to load program for unknown reason");
+ break;
+ }
bpf__strerror_end(buf, size);
return 0;
}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index ccd8d7f..6fdc045 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,9 +8,25 @@
#include <linux/compiler.h>
#include <linux/err.h>
#include <string.h>
+#include <bpf/libbpf.h>
#include "probe-event.h"
#include "debug.h"
+enum bpf_loader_errno {
+ __BPF_LOADER_ERRNO__START = __LIBBPF_ERRNO__START - 100,
+ /* Invalid config string */
+ BPF_LOADER_ERRNO__CONFIG = __BPF_LOADER_ERRNO__START,
+ BPF_LOADER_ERRNO__GROUP, /* Invalid group name */
+ BPF_LOADER_ERRNO__EVENTNAME, /* Event name is missing */
+ BPF_LOADER_ERRNO__INTERNAL, /* BPF loader internal error */
+ BPF_LOADER_ERRNO__COMPILE, /* Error when compiling BPF scriptlet */
+ BPF_LOADER_ERRNO__PROGCONF_TERM,/* Invalid program config term in config string */
+ BPF_LOADER_ERRNO__PROLOGUE, /* Failed to generate prologue */
+ BPF_LOADER_ERRNO__PROLOGUE2BIG, /* Prologue too big for program */
+ BPF_LOADER_ERRNO__PROLOGUEOOB, /* Offset out of bound for prologue */
+ __BPF_LOADER_ERRNO__END,
+};
+
struct bpf_object;
#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
@@ -19,6 +35,11 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
#ifdef HAVE_LIBBPF_SUPPORT
struct bpf_object *bpf__prepare_load(const char *filename, bool source);
+int bpf__strerror_prepare_load(const char *filename, bool source,
+ int err, char *buf, size_t size);
+
+struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
+ const char *name);
void bpf__clear(void);
@@ -41,6 +62,13 @@ bpf__prepare_load(const char *filename __maybe_unused,
return ERR_PTR(-ENOTSUP);
}
+static inline struct bpf_object *
+bpf__prepare_load_buffer(void *obj_buf __maybe_unused,
+ size_t obj_buf_sz __maybe_unused)
+{
+ return ERR_PTR(-ENOTSUP);
+}
+
static inline void bpf__clear(void) { }
static inline int bpf__probe(struct bpf_object *obj __maybe_unused) { return 0;}
@@ -67,6 +95,15 @@ __bpf_strerror(char *buf, size_t size)
return 0;
}
+static inline
+int bpf__strerror_prepare_load(const char *filename __maybe_unused,
+ bool source __maybe_unused,
+ int err __maybe_unused,
+ char *buf, size_t size)
+{
+ return __bpf_strerror(buf, size);
+}
+
static inline int
bpf__strerror_probe(struct bpf_object *obj __maybe_unused,
int err __maybe_unused,
diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c
new file mode 100644
index 0000000..6cdbee1
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.c
@@ -0,0 +1,455 @@
+/*
+ * bpf-prologue.c
+ *
+ * Copyright (C) 2015 He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015 Huawei Inc.
+ */
+
+#include <bpf/libbpf.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "probe-finder.h"
+#include <dwarf-regs.h>
+#include <linux/filter.h>
+
+#define BPF_REG_SIZE 8
+
+#define JMP_TO_ERROR_CODE -1
+#define JMP_TO_SUCCESS_CODE -2
+#define JMP_TO_USER_CODE -3
+
+struct bpf_insn_pos {
+ struct bpf_insn *begin;
+ struct bpf_insn *end;
+ struct bpf_insn *pos;
+};
+
+static inline int
+pos_get_cnt(struct bpf_insn_pos *pos)
+{
+ return pos->pos - pos->begin;
+}
+
+static int
+append_insn(struct bpf_insn new_insn, struct bpf_insn_pos *pos)
+{
+ if (!pos->pos)
+ return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+
+ if (pos->pos + 1 >= pos->end) {
+ pr_err("bpf prologue: prologue too long\n");
+ pos->pos = NULL;
+ return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+ }
+
+ *(pos->pos)++ = new_insn;
+ return 0;
+}
+
+static int
+check_pos(struct bpf_insn_pos *pos)
+{
+ if (!pos->pos || pos->pos >= pos->end)
+ return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+ return 0;
+}
+
+/* Give it a shorter name */
+#define ins(i, p) append_insn((i), (p))
+
+/*
+ * Give a register name (in 'reg'), generate instruction to
+ * load register into an eBPF register rd:
+ * 'ldd target_reg, offset(ctx_reg)', where:
+ * ctx_reg is pre initialized to pointer of 'struct pt_regs'.
+ */
+static int
+gen_ldx_reg_from_ctx(struct bpf_insn_pos *pos, int ctx_reg,
+ const char *reg, int target_reg)
+{
+ int offset = regs_query_register_offset(reg);
+
+ if (offset < 0) {
+ pr_err("bpf: prologue: failed to get register %s\n",
+ reg);
+ return offset;
+ }
+ ins(BPF_LDX_MEM(BPF_DW, target_reg, ctx_reg, offset), pos);
+
+ return check_pos(pos);
+}
+
+/*
+ * Generate a BPF_FUNC_probe_read function call.
+ *
+ * src_base_addr_reg is a register holding base address,
+ * dst_addr_reg is a register holding dest address (on stack),
+ * result is:
+ *
+ * *[dst_addr_reg] = *([src_base_addr_reg] + offset)
+ *
+ * Arguments of BPF_FUNC_probe_read:
+ * ARG1: ptr to stack (dest)
+ * ARG2: size (8)
+ * ARG3: unsafe ptr (src)
+ */
+static int
+gen_read_mem(struct bpf_insn_pos *pos,
+ int src_base_addr_reg,
+ int dst_addr_reg,
+ long offset)
+{
+ /* mov arg3, src_base_addr_reg */
+ if (src_base_addr_reg != BPF_REG_ARG3)
+ ins(BPF_MOV64_REG(BPF_REG_ARG3, src_base_addr_reg), pos);
+ /* add arg3, #offset */
+ if (offset)
+ ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_ARG3, offset), pos);
+
+ /* mov arg2, #reg_size */
+ ins(BPF_ALU64_IMM(BPF_MOV, BPF_REG_ARG2, BPF_REG_SIZE), pos);
+
+ /* mov arg1, dst_addr_reg */
+ if (dst_addr_reg != BPF_REG_ARG1)
+ ins(BPF_MOV64_REG(BPF_REG_ARG1, dst_addr_reg), pos);
+
+ /* Call probe_read */
+ ins(BPF_EMIT_CALL(BPF_FUNC_probe_read), pos);
+ /*
+ * Error processing: if read fail, goto error code,
+ * will be relocated. Target should be the start of
+ * error processing code.
+ */
+ ins(BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, JMP_TO_ERROR_CODE),
+ pos);
+
+ return check_pos(pos);
+}
+
+/*
+ * Each arg should be bare register. Fetch and save them into argument
+ * registers (r3 - r5).
+ *
+ * BPF_REG_1 should have been initialized with pointer to
+ * 'struct pt_regs'.
+ */
+static int
+gen_prologue_fastpath(struct bpf_insn_pos *pos,
+ struct probe_trace_arg *args, int nargs)
+{
+ int i, err = 0;
+
+ for (i = 0; i < nargs; i++) {
+ err = gen_ldx_reg_from_ctx(pos, BPF_REG_1, args[i].value,
+ BPF_PROLOGUE_START_ARG_REG + i);
+ if (err)
+ goto errout;
+ }
+
+ return check_pos(pos);
+errout:
+ return err;
+}
+
+/*
+ * Slow path:
+ * At least one argument has the form of 'offset($rx)'.
+ *
+ * Following code first stores them into stack, then loads all of then
+ * to r2 - r5.
+ * Before final loading, the final result should be:
+ *
+ * low address
+ * BPF_REG_FP - 24 ARG3
+ * BPF_REG_FP - 16 ARG2
+ * BPF_REG_FP - 8 ARG1
+ * BPF_REG_FP
+ * high address
+ *
+ * For each argument (described as: offn(...off2(off1(reg)))),
+ * generates following code:
+ *
+ * r7 <- fp
+ * r7 <- r7 - stack_offset // Ideal code should initialize r7 using
+ * // fp before generating args. However,
+ * // eBPF won't regard r7 as stack pointer
+ * // if it is generated by minus 8 from
+ * // another stack pointer except fp.
+ * // This is why we have to set r7
+ * // to fp for each variable.
+ * r3 <- value of 'reg'-> generated using gen_ldx_reg_from_ctx()
+ * (r7) <- r3 // skip following instructions for bare reg
+ * r3 <- r3 + off1 . // skip if off1 == 0
+ * r2 <- 8 \
+ * r1 <- r7 |-> generated by gen_read_mem()
+ * call probe_read /
+ * jnei r0, 0, err ./
+ * r3 <- (r7)
+ * r3 <- r3 + off2 . // skip if off2 == 0
+ * r2 <- 8 \ // r2 may be broken by probe_read, so set again
+ * r1 <- r7 |-> generated by gen_read_mem()
+ * call probe_read /
+ * jnei r0, 0, err ./
+ * ...
+ */
+static int
+gen_prologue_slowpath(struct bpf_insn_pos *pos,
+ struct probe_trace_arg *args, int nargs)
+{
+ int err, i;
+
+ for (i = 0; i < nargs; i++) {
+ struct probe_trace_arg *arg = &args[i];
+ const char *reg = arg->value;
+ struct probe_trace_arg_ref *ref = NULL;
+ int stack_offset = (i + 1) * -8;
+
+ pr_debug("prologue: fetch arg %d, base reg is %s\n",
+ i, reg);
+
+ /* value of base register is stored into ARG3 */
+ err = gen_ldx_reg_from_ctx(pos, BPF_REG_CTX, reg,
+ BPF_REG_ARG3);
+ if (err) {
+ pr_err("prologue: failed to get offset of register %s\n",
+ reg);
+ goto errout;
+ }
+
+ /* Make r7 the stack pointer. */
+ ins(BPF_MOV64_REG(BPF_REG_7, BPF_REG_FP), pos);
+ /* r7 += -8 */
+ ins(BPF_ALU64_IMM(BPF_ADD, BPF_REG_7, stack_offset), pos);
+ /*
+ * Store r3 (base register) onto stack
+ * Ensure fp[offset] is set.
+ * fp is the only valid base register when storing
+ * into stack. We are not allowed to use r7 as base
+ * register here.
+ */
+ ins(BPF_STX_MEM(BPF_DW, BPF_REG_FP, BPF_REG_ARG3,
+ stack_offset), pos);
+
+ ref = arg->ref;
+ while (ref) {
+ pr_debug("prologue: arg %d: offset %ld\n",
+ i, ref->offset);
+ err = gen_read_mem(pos, BPF_REG_3, BPF_REG_7,
+ ref->offset);
+ if (err) {
+ pr_err("prologue: failed to generate probe_read function call\n");
+ goto errout;
+ }
+
+ ref = ref->next;
+ /*
+ * Load previous result into ARG3. Use
+ * BPF_REG_FP instead of r7 because verifier
+ * allows FP based addressing only.
+ */
+ if (ref)
+ ins(BPF_LDX_MEM(BPF_DW, BPF_REG_ARG3,
+ BPF_REG_FP, stack_offset), pos);
+ }
+ }
+
+ /* Final pass: read to registers */
+ for (i = 0; i < nargs; i++)
+ ins(BPF_LDX_MEM(BPF_DW, BPF_PROLOGUE_START_ARG_REG + i,
+ BPF_REG_FP, -BPF_REG_SIZE * (i + 1)), pos);
+
+ ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_SUCCESS_CODE), pos);
+
+ return check_pos(pos);
+errout:
+ return err;
+}
+
+static int
+prologue_relocate(struct bpf_insn_pos *pos, struct bpf_insn *error_code,
+ struct bpf_insn *success_code, struct bpf_insn *user_code)
+{
+ struct bpf_insn *insn;
+
+ if (check_pos(pos))
+ return -BPF_LOADER_ERRNO__PROLOGUE2BIG;
+
+ for (insn = pos->begin; insn < pos->pos; insn++) {
+ struct bpf_insn *target;
+ u8 class = BPF_CLASS(insn->code);
+ u8 opcode;
+
+ if (class != BPF_JMP)
+ continue;
+ opcode = BPF_OP(insn->code);
+ if (opcode == BPF_CALL)
+ continue;
+
+ switch (insn->off) {
+ case JMP_TO_ERROR_CODE:
+ target = error_code;
+ break;
+ case JMP_TO_SUCCESS_CODE:
+ target = success_code;
+ break;
+ case JMP_TO_USER_CODE:
+ target = user_code;
+ break;
+ default:
+ pr_err("bpf prologue: internal error: relocation failed\n");
+ return -BPF_LOADER_ERRNO__PROLOGUE;
+ }
+
+ insn->off = target - (insn + 1);
+ }
+ return 0;
+}
+
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+ struct bpf_insn *new_prog, size_t *new_cnt,
+ size_t cnt_space)
+{
+ struct bpf_insn *success_code = NULL;
+ struct bpf_insn *error_code = NULL;
+ struct bpf_insn *user_code = NULL;
+ struct bpf_insn_pos pos;
+ bool fastpath = true;
+ int err = 0, i;
+
+ if (!new_prog || !new_cnt)
+ return -EINVAL;
+
+ if (cnt_space > BPF_MAXINSNS)
+ cnt_space = BPF_MAXINSNS;
+
+ pos.begin = new_prog;
+ pos.end = new_prog + cnt_space;
+ pos.pos = new_prog;
+
+ if (!nargs) {
+ ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0),
+ &pos);
+
+ if (check_pos(&pos))
+ goto errout;
+
+ *new_cnt = pos_get_cnt(&pos);
+ return 0;
+ }
+
+ if (nargs > BPF_PROLOGUE_MAX_ARGS) {
+ pr_warning("bpf: prologue: %d arguments are dropped\n",
+ nargs - BPF_PROLOGUE_MAX_ARGS);
+ nargs = BPF_PROLOGUE_MAX_ARGS;
+ }
+
+ /* First pass: validation */
+ for (i = 0; i < nargs; i++) {
+ struct probe_trace_arg_ref *ref = args[i].ref;
+
+ if (args[i].value[0] == '@') {
+ /* TODO: fetch global variable */
+ pr_err("bpf: prologue: global %s%+ld not support\n",
+ args[i].value, ref ? ref->offset : 0);
+ return -ENOTSUP;
+ }
+
+ while (ref) {
+ /* fastpath is true if all args has ref == NULL */
+ fastpath = false;
+
+ /*
+ * Instruction encodes immediate value using
+ * s32, ref->offset is long. On systems which
+ * can't fill long in s32, refuse to process if
+ * ref->offset too large (or small).
+ */
+#ifdef __LP64__
+#define OFFSET_MAX ((1LL << 31) - 1)
+#define OFFSET_MIN ((1LL << 31) * -1)
+ if (ref->offset > OFFSET_MAX ||
+ ref->offset < OFFSET_MIN) {
+ pr_err("bpf: prologue: offset out of bound: %ld\n",
+ ref->offset);
+ return -BPF_LOADER_ERRNO__PROLOGUEOOB;
+ }
+#endif
+ ref = ref->next;
+ }
+ }
+ pr_debug("prologue: pass validation\n");
+
+ if (fastpath) {
+ /* If all variables are registers... */
+ pr_debug("prologue: fast path\n");
+ err = gen_prologue_fastpath(&pos, args, nargs);
+ if (err)
+ goto errout;
+ } else {
+ pr_debug("prologue: slow path\n");
+
+ /* Initialization: move ctx to a callee saved register. */
+ ins(BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1), &pos);
+
+ err = gen_prologue_slowpath(&pos, args, nargs);
+ if (err)
+ goto errout;
+ /*
+ * start of ERROR_CODE (only slow pass needs error code)
+ * mov r2 <- 1 // r2 is error number
+ * mov r3 <- 0 // r3, r4... should be touched or
+ * // verifier would complain
+ * mov r4 <- 0
+ * ...
+ * goto usercode
+ */
+ error_code = pos.pos;
+ ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 1),
+ &pos);
+
+ for (i = 0; i < nargs; i++)
+ ins(BPF_ALU64_IMM(BPF_MOV,
+ BPF_PROLOGUE_START_ARG_REG + i,
+ 0),
+ &pos);
+ ins(BPF_JMP_IMM(BPF_JA, BPF_REG_0, 0, JMP_TO_USER_CODE),
+ &pos);
+ }
+
+ /*
+ * start of SUCCESS_CODE:
+ * mov r2 <- 0
+ * goto usercode // skip
+ */
+ success_code = pos.pos;
+ ins(BPF_ALU64_IMM(BPF_MOV, BPF_PROLOGUE_FETCH_RESULT_REG, 0), &pos);
+
+ /*
+ * start of USER_CODE:
+ * Restore ctx to r1
+ */
+ user_code = pos.pos;
+ if (!fastpath) {
+ /*
+ * Only slow path needs restoring of ctx. In fast path,
+ * register are loaded directly from r1.
+ */
+ ins(BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX), &pos);
+ err = prologue_relocate(&pos, error_code, success_code,
+ user_code);
+ if (err)
+ goto errout;
+ }
+
+ err = check_pos(&pos);
+ if (err)
+ goto errout;
+
+ *new_cnt = pos_get_cnt(&pos);
+ return 0;
+errout:
+ return err;
+}
diff --git a/tools/perf/util/bpf-prologue.h b/tools/perf/util/bpf-prologue.h
new file mode 100644
index 0000000..d94cbea
--- /dev/null
+++ b/tools/perf/util/bpf-prologue.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015, He Kuang <hekuang@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ */
+#ifndef __BPF_PROLOGUE_H
+#define __BPF_PROLOGUE_H
+
+#include <linux/compiler.h>
+#include <linux/filter.h>
+#include "probe-event.h"
+
+#define BPF_PROLOGUE_MAX_ARGS 3
+#define BPF_PROLOGUE_START_ARG_REG BPF_REG_3
+#define BPF_PROLOGUE_FETCH_RESULT_REG BPF_REG_2
+
+#ifdef HAVE_BPF_PROLOGUE
+int bpf__gen_prologue(struct probe_trace_arg *args, int nargs,
+ struct bpf_insn *new_prog, size_t *new_cnt,
+ size_t cnt_space);
+#else
+static inline int
+bpf__gen_prologue(struct probe_trace_arg *args __maybe_unused,
+ int nargs __maybe_unused,
+ struct bpf_insn *new_prog __maybe_unused,
+ size_t *new_cnt,
+ size_t cnt_space __maybe_unused)
+{
+ if (!new_cnt)
+ return -EINVAL;
+ *new_cnt = 0;
+ return -ENOTSUP;
+}
+#endif
+#endif /* __BPF_PROLOGUE_H */
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index d909459..6a7e273 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -76,6 +76,7 @@ struct perf_tool build_id__mark_dso_hit_ops = {
.exit = perf_event__exit_del_thread,
.attr = perf_event__process_attr,
.build_id = perf_event__process_build_id,
+ .ordered_events = true,
};
int build_id__sprintf(const u8 *build_id, int len, char *bf)
@@ -90,7 +91,7 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf)
bid += 2;
}
- return raw - build_id;
+ return (bid - bf) + 1;
}
int sysfs__sprintf_build_id(const char *root_dir, char *sbuild_id)
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index c861373..07b5d63 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -4,9 +4,12 @@
#include <stdbool.h>
#include "util.h"
#include "strbuf.h"
+#include <subcmd/pager.h>
#include "../perf.h"
#include "../ui/ui.h"
+#include <linux/string.h>
+
#define CMD_EXEC_PATH "--exec-path"
#define CMD_PERF_DIR "--perf-dir="
#define CMD_WORK_TREE "--work-tree="
@@ -18,6 +21,7 @@
#define DEFAULT_PERF_DIR_ENVIRONMENT ".perf"
#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
+#define PERF_PAGER_ENVIRONMENT "PERF_PAGER"
typedef int (*config_fn_t)(const char *, const char *, void *);
extern int perf_default_config(const char *, const char *, void *);
@@ -28,11 +32,6 @@ extern int perf_config_bool(const char *, const char *);
extern int config_error_nonbool(const char *);
extern const char *perf_config_dirname(const char *, const char *);
-/* pager.c */
-extern void setup_pager(void);
-extern int pager_in_use(void);
-extern int pager_use_color;
-
char *alias_lookup(const char *alias);
int split_cmdline(char *cmdline, const char ***argv);
@@ -71,9 +70,4 @@ extern char *perf_path(const char *fmt, ...) __attribute__((format (printf, 1, 2
extern char *perf_pathdup(const char *fmt, ...)
__attribute__((format (printf, 1, 2)));
-#ifndef __UCLIBC__
-/* Matches the libc/libbsd function attribute so we declare this unconditionally: */
-extern size_t strlcpy(char *dest, const char *src, size_t size);
-#endif
-
#endif /* __PERF_CACHE_H */
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index 735ad48..53c43eb 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -44,6 +44,10 @@ static int parse_callchain_mode(const char *value)
callchain_param.mode = CHAIN_GRAPH_REL;
return 0;
}
+ if (!strncmp(value, "folded", strlen(value))) {
+ callchain_param.mode = CHAIN_FOLDED;
+ return 0;
+ }
return -1;
}
@@ -79,6 +83,23 @@ static int parse_callchain_sort_key(const char *value)
return -1;
}
+static int parse_callchain_value(const char *value)
+{
+ if (!strncmp(value, "percent", strlen(value))) {
+ callchain_param.value = CCVAL_PERCENT;
+ return 0;
+ }
+ if (!strncmp(value, "period", strlen(value))) {
+ callchain_param.value = CCVAL_PERIOD;
+ return 0;
+ }
+ if (!strncmp(value, "count", strlen(value))) {
+ callchain_param.value = CCVAL_COUNT;
+ return 0;
+ }
+ return -1;
+}
+
static int
__parse_callchain_report_opt(const char *arg, bool allow_record_opt)
{
@@ -102,7 +123,8 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt)
if (!parse_callchain_mode(tok) ||
!parse_callchain_order(tok) ||
- !parse_callchain_sort_key(tok)) {
+ !parse_callchain_sort_key(tok) ||
+ !parse_callchain_value(tok)) {
/* parsing ok - move on to the next */
try_stack_size = false;
goto next;
@@ -218,6 +240,7 @@ rb_insert_callchain(struct rb_root *root, struct callchain_node *chain,
switch (mode) {
case CHAIN_FLAT:
+ case CHAIN_FOLDED:
if (rnode->hit < chain->hit)
p = &(*p)->rb_left;
else
@@ -267,6 +290,7 @@ static void
sort_chain_flat(struct rb_root *rb_root, struct callchain_root *root,
u64 min_hit, struct callchain_param *param __maybe_unused)
{
+ *rb_root = RB_ROOT;
__sort_chain_flat(rb_root, &root->node, min_hit);
}
@@ -338,6 +362,7 @@ int callchain_register_param(struct callchain_param *param)
param->sort = sort_chain_graph_rel;
break;
case CHAIN_FLAT:
+ case CHAIN_FOLDED:
param->sort = sort_chain_flat;
break;
case CHAIN_NONE:
@@ -363,6 +388,7 @@ create_child(struct callchain_node *parent, bool inherit_children)
}
new->parent = parent;
INIT_LIST_HEAD(&new->val);
+ INIT_LIST_HEAD(&new->parent_val);
if (inherit_children) {
struct rb_node *n;
@@ -431,6 +457,8 @@ add_child(struct callchain_node *parent,
new->children_hit = 0;
new->hit = period;
+ new->children_count = 0;
+ new->count = 1;
return new;
}
@@ -478,6 +506,9 @@ split_add_child(struct callchain_node *parent,
parent->children_hit = callchain_cumul_hits(new);
new->val_nr = parent->val_nr - idx_local;
parent->val_nr = idx_local;
+ new->count = parent->count;
+ new->children_count = parent->children_count;
+ parent->children_count = callchain_cumul_counts(new);
/* create a new child for the new branch if any */
if (idx_total < cursor->nr) {
@@ -488,6 +519,8 @@ split_add_child(struct callchain_node *parent,
parent->hit = 0;
parent->children_hit += period;
+ parent->count = 0;
+ parent->children_count += 1;
node = callchain_cursor_current(cursor);
new = add_child(parent, cursor, period);
@@ -510,6 +543,7 @@ split_add_child(struct callchain_node *parent,
rb_insert_color(&new->rb_node_in, &parent->rb_root_in);
} else {
parent->hit = period;
+ parent->count = 1;
}
}
@@ -556,6 +590,7 @@ append_chain_children(struct callchain_node *root,
inc_children_hit:
root->children_hit += period;
+ root->children_count++;
}
static int
@@ -608,6 +643,7 @@ append_chain(struct callchain_node *root,
/* we match 100% of the path, increment the hit */
if (matches == root->val_nr && cursor->pos == cursor->nr) {
root->hit += period;
+ root->count++;
return 0;
}
@@ -799,12 +835,72 @@ char *callchain_list__sym_name(struct callchain_list *cl,
return bf;
}
+char *callchain_node__scnprintf_value(struct callchain_node *node,
+ char *bf, size_t bfsize, u64 total)
+{
+ double percent = 0.0;
+ u64 period = callchain_cumul_hits(node);
+ unsigned count = callchain_cumul_counts(node);
+
+ if (callchain_param.mode == CHAIN_FOLDED) {
+ period = node->hit;
+ count = node->count;
+ }
+
+ switch (callchain_param.value) {
+ case CCVAL_PERIOD:
+ scnprintf(bf, bfsize, "%"PRIu64, period);
+ break;
+ case CCVAL_COUNT:
+ scnprintf(bf, bfsize, "%u", count);
+ break;
+ case CCVAL_PERCENT:
+ default:
+ if (total)
+ percent = period * 100.0 / total;
+ scnprintf(bf, bfsize, "%.2f%%", percent);
+ break;
+ }
+ return bf;
+}
+
+int callchain_node__fprintf_value(struct callchain_node *node,
+ FILE *fp, u64 total)
+{
+ double percent = 0.0;
+ u64 period = callchain_cumul_hits(node);
+ unsigned count = callchain_cumul_counts(node);
+
+ if (callchain_param.mode == CHAIN_FOLDED) {
+ period = node->hit;
+ count = node->count;
+ }
+
+ switch (callchain_param.value) {
+ case CCVAL_PERIOD:
+ return fprintf(fp, "%"PRIu64, period);
+ case CCVAL_COUNT:
+ return fprintf(fp, "%u", count);
+ case CCVAL_PERCENT:
+ default:
+ if (total)
+ percent = period * 100.0 / total;
+ return percent_color_fprintf(fp, "%.2f%%", percent);
+ }
+ return 0;
+}
+
static void free_callchain_node(struct callchain_node *node)
{
struct callchain_list *list, *tmp;
struct callchain_node *child;
struct rb_node *n;
+ list_for_each_entry_safe(list, tmp, &node->parent_val, list) {
+ list_del(&list->list);
+ free(list);
+ }
+
list_for_each_entry_safe(list, tmp, &node->val, list) {
list_del(&list->list);
free(list);
@@ -828,3 +924,69 @@ void free_callchain(struct callchain_root *root)
free_callchain_node(&root->node);
}
+
+static u64 decay_callchain_node(struct callchain_node *node)
+{
+ struct callchain_node *child;
+ struct rb_node *n;
+ u64 child_hits = 0;
+
+ n = rb_first(&node->rb_root_in);
+ while (n) {
+ child = container_of(n, struct callchain_node, rb_node_in);
+
+ child_hits += decay_callchain_node(child);
+ n = rb_next(n);
+ }
+
+ node->hit = (node->hit * 7) / 8;
+ node->children_hit = child_hits;
+
+ return node->hit;
+}
+
+void decay_callchain(struct callchain_root *root)
+{
+ if (!symbol_conf.use_callchain)
+ return;
+
+ decay_callchain_node(&root->node);
+}
+
+int callchain_node__make_parent_list(struct callchain_node *node)
+{
+ struct callchain_node *parent = node->parent;
+ struct callchain_list *chain, *new;
+ LIST_HEAD(head);
+
+ while (parent) {
+ list_for_each_entry_reverse(chain, &parent->val, list) {
+ new = malloc(sizeof(*new));
+ if (new == NULL)
+ goto out;
+ *new = *chain;
+ new->has_children = false;
+ list_add_tail(&new->list, &head);
+ }
+ parent = parent->parent;
+ }
+
+ list_for_each_entry_safe_reverse(chain, new, &head, list)
+ list_move_tail(&chain->list, &node->parent_val);
+
+ if (!list_empty(&node->parent_val)) {
+ chain = list_first_entry(&node->parent_val, struct callchain_list, list);
+ chain->has_children = rb_prev(&node->rb_node) || rb_next(&node->rb_node);
+
+ chain = list_first_entry(&node->val, struct callchain_list, list);
+ chain->has_children = false;
+ }
+ return 0;
+
+out:
+ list_for_each_entry_safe(chain, new, &head, list) {
+ list_del(&chain->list);
+ free(chain);
+ }
+ return -ENOMEM;
+}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index fce8161..18dd222 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -24,12 +24,13 @@
#define CALLCHAIN_RECORD_HELP CALLCHAIN_HELP RECORD_MODE_HELP RECORD_SIZE_HELP
#define CALLCHAIN_REPORT_HELP \
- HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|none)\n" \
+ HELP_PAD "print_type:\tcall graph printing style (graph|flat|fractal|folded|none)\n" \
HELP_PAD "threshold:\tminimum call graph inclusion threshold (<percent>)\n" \
HELP_PAD "print_limit:\tmaximum number of call graph entry (<number>)\n" \
HELP_PAD "order:\t\tcall graph order (caller|callee)\n" \
HELP_PAD "sort_key:\tcall graph sort key (function|address)\n" \
- HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n"
+ HELP_PAD "branch:\t\tinclude last branch info to call graph (branch)\n" \
+ HELP_PAD "value:\t\tcall graph value (percent|period|count)\n"
enum perf_call_graph_mode {
CALLCHAIN_NONE,
@@ -43,7 +44,8 @@ enum chain_mode {
CHAIN_NONE,
CHAIN_FLAT,
CHAIN_GRAPH_ABS,
- CHAIN_GRAPH_REL
+ CHAIN_GRAPH_REL,
+ CHAIN_FOLDED,
};
enum chain_order {
@@ -54,11 +56,14 @@ enum chain_order {
struct callchain_node {
struct callchain_node *parent;
struct list_head val;
+ struct list_head parent_val;
struct rb_node rb_node_in; /* to insert nodes in an rbtree */
struct rb_node rb_node; /* to sort nodes in an output tree */
struct rb_root rb_root_in; /* input tree of children */
struct rb_root rb_root; /* sorted output tree of children */
unsigned int val_nr;
+ unsigned int count;
+ unsigned int children_count;
u64 hit;
u64 children_hit;
};
@@ -78,6 +83,12 @@ enum chain_key {
CCKEY_ADDRESS
};
+enum chain_value {
+ CCVAL_PERCENT,
+ CCVAL_PERIOD,
+ CCVAL_COUNT,
+};
+
struct callchain_param {
bool enabled;
enum perf_call_graph_mode record_mode;
@@ -90,6 +101,7 @@ struct callchain_param {
bool order_set;
enum chain_key key;
bool branch_callstack;
+ enum chain_value value;
};
extern struct callchain_param callchain_param;
@@ -131,6 +143,7 @@ extern __thread struct callchain_cursor callchain_cursor;
static inline void callchain_init(struct callchain_root *root)
{
INIT_LIST_HEAD(&root->node.val);
+ INIT_LIST_HEAD(&root->node.parent_val);
root->node.parent = NULL;
root->node.hit = 0;
@@ -144,6 +157,11 @@ static inline u64 callchain_cumul_hits(struct callchain_node *node)
return node->hit + node->children_hit;
}
+static inline unsigned callchain_cumul_counts(struct callchain_node *node)
+{
+ return node->count + node->children_count;
+}
+
int callchain_register_param(struct callchain_param *param);
int callchain_append(struct callchain_root *root,
struct callchain_cursor *cursor,
@@ -229,7 +247,13 @@ static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
char *callchain_list__sym_name(struct callchain_list *cl,
char *bf, size_t bfsize, bool show_dso);
+char *callchain_node__scnprintf_value(struct callchain_node *node,
+ char *bf, size_t bfsize, u64 total);
+int callchain_node__fprintf_value(struct callchain_node *node,
+ FILE *fp, u64 total);
void free_callchain(struct callchain_root *root);
+void decay_callchain(struct callchain_root *root);
+int callchain_node__make_parent_list(struct callchain_node *node);
#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c
index 32e12ecf..90aa1b4 100644
--- a/tools/perf/util/cgroup.c
+++ b/tools/perf/util/cgroup.c
@@ -1,6 +1,6 @@
#include "util.h"
#include "../perf.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "evsel.h"
#include "cgroup.h"
#include "evlist.h"
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index 9b95654..e5fb88b 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -24,7 +24,7 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
auto_color:
if (stdout_is_tty < 0)
stdout_is_tty = isatty(1);
- if (stdout_is_tty || (pager_in_use() && pager_use_color)) {
+ if (stdout_is_tty || pager_in_use()) {
char *term = getenv("TERM");
if (term && strcmp(term, "dumb"))
return 1;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 2e452ac..d3e12e3 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -10,7 +10,7 @@
*/
#include "util.h"
#include "cache.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "util/hist.h" /* perf_hist_config */
#include "util/llvm-utils.h" /* perf_llvm_config */
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c
index 10af1e7..fa93509 100644
--- a/tools/perf/util/cpumap.c
+++ b/tools/perf/util/cpumap.c
@@ -5,6 +5,7 @@
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
+#include <linux/bitmap.h>
#include "asm/bug.h"
static struct cpu_map *cpu_map__default_new(void)
@@ -179,6 +180,56 @@ out:
return cpus;
}
+static struct cpu_map *cpu_map__from_entries(struct cpu_map_entries *cpus)
+{
+ struct cpu_map *map;
+
+ map = cpu_map__empty_new(cpus->nr);
+ if (map) {
+ unsigned i;
+
+ for (i = 0; i < cpus->nr; i++) {
+ /*
+ * Special treatment for -1, which is not real cpu number,
+ * and we need to use (int) -1 to initialize map[i],
+ * otherwise it would become 65535.
+ */
+ if (cpus->cpu[i] == (u16) -1)
+ map->map[i] = -1;
+ else
+ map->map[i] = (int) cpus->cpu[i];
+ }
+ }
+
+ return map;
+}
+
+static struct cpu_map *cpu_map__from_mask(struct cpu_map_mask *mask)
+{
+ struct cpu_map *map;
+ int nr, nbits = mask->nr * mask->long_size * BITS_PER_BYTE;
+
+ nr = bitmap_weight(mask->mask, nbits);
+
+ map = cpu_map__empty_new(nr);
+ if (map) {
+ int cpu, i = 0;
+
+ for_each_set_bit(cpu, mask->mask, nbits)
+ map->map[i++] = cpu;
+ }
+ return map;
+
+}
+
+struct cpu_map *cpu_map__new_data(struct cpu_map_data *data)
+{
+ if (data->type == PERF_CPU_MAP__CPUS)
+ return cpu_map__from_entries((struct cpu_map_entries *)data->data);
+ else
+ return cpu_map__from_mask((struct cpu_map_mask *)data->data);
+}
+
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp)
{
int i;
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h
index 85f7772..71c41b9 100644
--- a/tools/perf/util/cpumap.h
+++ b/tools/perf/util/cpumap.h
@@ -17,6 +17,7 @@ struct cpu_map {
struct cpu_map *cpu_map__new(const char *cpu_list);
struct cpu_map *cpu_map__empty_new(int nr);
struct cpu_map *cpu_map__dummy_new(void);
+struct cpu_map *cpu_map__new_data(struct cpu_map_data *data);
struct cpu_map *cpu_map__read(FILE *file);
size_t cpu_map__fprintf(struct cpu_map *map, FILE *fp);
int cpu_map__get_socket_id(int cpu);
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index 5bfc119..34cd1e4 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -63,6 +63,7 @@ struct ctf_writer {
struct bt_ctf_field_type *s32;
struct bt_ctf_field_type *u32;
struct bt_ctf_field_type *string;
+ struct bt_ctf_field_type *u32_hex;
struct bt_ctf_field_type *u64_hex;
};
struct bt_ctf_field_type *array[6];
@@ -982,6 +983,7 @@ do { \
CREATE_INT_TYPE(cw->data.u64, 64, false, false);
CREATE_INT_TYPE(cw->data.s32, 32, true, false);
CREATE_INT_TYPE(cw->data.u32, 32, false, false);
+ CREATE_INT_TYPE(cw->data.u32_hex, 32, false, true);
CREATE_INT_TYPE(cw->data.u64_hex, 64, false, true);
cw->data.string = bt_ctf_field_type_string_create();
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 7c0c083..e8e9a9d 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -933,6 +933,7 @@ static struct dso *__dso__findlink_by_longname(struct rb_root *root,
/* Add new node and rebalance tree */
rb_link_node(&dso->rb_node, parent, p);
rb_insert_color(&dso->rb_node, root);
+ dso->root = root;
}
return NULL;
}
@@ -945,15 +946,30 @@ static inline struct dso *__dso__find_by_longname(struct rb_root *root,
void dso__set_long_name(struct dso *dso, const char *name, bool name_allocated)
{
+ struct rb_root *root = dso->root;
+
if (name == NULL)
return;
if (dso->long_name_allocated)
free((char *)dso->long_name);
+ if (root) {
+ rb_erase(&dso->rb_node, root);
+ /*
+ * __dso__findlink_by_longname() isn't guaranteed to add it
+ * back, so a clean removal is required here.
+ */
+ RB_CLEAR_NODE(&dso->rb_node);
+ dso->root = NULL;
+ }
+
dso->long_name = name;
dso->long_name_len = strlen(name);
dso->long_name_allocated = name_allocated;
+
+ if (root)
+ __dso__findlink_by_longname(root, dso, NULL);
}
void dso__set_short_name(struct dso *dso, const char *name, bool name_allocated)
@@ -1046,6 +1062,7 @@ struct dso *dso__new(const char *name)
dso->kernel = DSO_TYPE_USER;
dso->needs_swap = DSO_SWAP__UNSET;
RB_CLEAR_NODE(&dso->rb_node);
+ dso->root = NULL;
INIT_LIST_HEAD(&dso->node);
INIT_LIST_HEAD(&dso->data.open_entry);
pthread_mutex_init(&dso->lock, NULL);
@@ -1226,6 +1243,8 @@ struct dso *__dsos__addnew(struct dsos *dsos, const char *name)
if (dso != NULL) {
__dsos__add(dsos, dso);
dso__set_basename(dso);
+ /* Put dso here because __dsos_add already got it */
+ dso__put(dso);
}
return dso;
}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index fc8db9c..45ec4d0 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -135,6 +135,7 @@ struct dso {
pthread_mutex_t lock;
struct list_head node;
struct rb_node rb_node; /* rbtree node sorted by long name */
+ struct rb_root *root; /* root of rbtree that rb_node is in */
struct rb_root symbols[MAP__NR_TYPES];
struct rb_root symbol_names[MAP__NR_TYPES];
struct {
diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c
index 6af4f7c..7dd5939 100644
--- a/tools/perf/util/env.c
+++ b/tools/perf/util/env.c
@@ -25,15 +25,6 @@ int perf_env__set_cmdline(struct perf_env *env, int argc, const char *argv[])
{
int i;
- /*
- * If env->cmdline_argv has already been set, do not override it. This allows
- * a command to set the cmdline, parse args and then call another
- * builtin function that implements a command -- e.g, cmd_kvm calling
- * cmd_record.
- */
- if (env->cmdline_argv != NULL)
- return 0;
-
/* do not include NULL termination */
env->cmdline_argv = calloc(argc, sizeof(char *));
if (env->cmdline_argv == NULL)
diff --git a/tools/perf/util/environment.c b/tools/perf/util/environment.c
deleted file mode 100644
index 7405123..0000000
--- a/tools/perf/util/environment.c
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
- * We put all the perf config variables in this same object
- * file, so that programs can link against the config parser
- * without having to link against all the rest of perf.
- */
-#include "cache.h"
-
-int pager_use_color = 1;
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 8b10621..cd61bb1 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -10,6 +10,8 @@
#include "thread.h"
#include "thread_map.h"
#include "symbol/kallsyms.h"
+#include "asm/bug.h"
+#include "stat.h"
static const char *perf_event__names[] = {
[0] = "TOTAL",
@@ -37,6 +39,12 @@ static const char *perf_event__names[] = {
[PERF_RECORD_AUXTRACE_INFO] = "AUXTRACE_INFO",
[PERF_RECORD_AUXTRACE] = "AUXTRACE",
[PERF_RECORD_AUXTRACE_ERROR] = "AUXTRACE_ERROR",
+ [PERF_RECORD_THREAD_MAP] = "THREAD_MAP",
+ [PERF_RECORD_CPU_MAP] = "CPU_MAP",
+ [PERF_RECORD_STAT_CONFIG] = "STAT_CONFIG",
+ [PERF_RECORD_STAT] = "STAT",
+ [PERF_RECORD_STAT_ROUND] = "STAT_ROUND",
+ [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE",
};
const char *perf_event__name(unsigned int id)
@@ -699,6 +707,274 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
return err;
}
+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+ struct thread_map *threads,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ union perf_event *event;
+ int i, err, size;
+
+ size = sizeof(event->thread_map);
+ size += threads->nr * sizeof(event->thread_map.entries[0]);
+
+ event = zalloc(size);
+ if (!event)
+ return -ENOMEM;
+
+ event->header.type = PERF_RECORD_THREAD_MAP;
+ event->header.size = size;
+ event->thread_map.nr = threads->nr;
+
+ for (i = 0; i < threads->nr; i++) {
+ struct thread_map_event_entry *entry = &event->thread_map.entries[i];
+ char *comm = thread_map__comm(threads, i);
+
+ if (!comm)
+ comm = (char *) "";
+
+ entry->pid = thread_map__pid(threads, i);
+ strncpy((char *) &entry->comm, comm, sizeof(entry->comm));
+ }
+
+ err = process(tool, event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
+static void synthesize_cpus(struct cpu_map_entries *cpus,
+ struct cpu_map *map)
+{
+ int i;
+
+ cpus->nr = map->nr;
+
+ for (i = 0; i < map->nr; i++)
+ cpus->cpu[i] = map->map[i];
+}
+
+static void synthesize_mask(struct cpu_map_mask *mask,
+ struct cpu_map *map, int max)
+{
+ int i;
+
+ mask->nr = BITS_TO_LONGS(max);
+ mask->long_size = sizeof(long);
+
+ for (i = 0; i < map->nr; i++)
+ set_bit(map->map[i], mask->mask);
+}
+
+static size_t cpus_size(struct cpu_map *map)
+{
+ return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16);
+}
+
+static size_t mask_size(struct cpu_map *map, int *max)
+{
+ int i;
+
+ *max = 0;
+
+ for (i = 0; i < map->nr; i++) {
+ /* bit possition of the cpu is + 1 */
+ int bit = map->map[i] + 1;
+
+ if (bit > *max)
+ *max = bit;
+ }
+
+ return sizeof(struct cpu_map_mask) + BITS_TO_LONGS(*max) * sizeof(long);
+}
+
+void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max)
+{
+ size_t size_cpus, size_mask;
+ bool is_dummy = cpu_map__empty(map);
+
+ /*
+ * Both array and mask data have variable size based
+ * on the number of cpus and their actual values.
+ * The size of the 'struct cpu_map_data' is:
+ *
+ * array = size of 'struct cpu_map_entries' +
+ * number of cpus * sizeof(u64)
+ *
+ * mask = size of 'struct cpu_map_mask' +
+ * maximum cpu bit converted to size of longs
+ *
+ * and finaly + the size of 'struct cpu_map_data'.
+ */
+ size_cpus = cpus_size(map);
+ size_mask = mask_size(map, max);
+
+ if (is_dummy || (size_cpus < size_mask)) {
+ *size += size_cpus;
+ *type = PERF_CPU_MAP__CPUS;
+ } else {
+ *size += size_mask;
+ *type = PERF_CPU_MAP__MASK;
+ }
+
+ *size += sizeof(struct cpu_map_data);
+ return zalloc(*size);
+}
+
+void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
+ u16 type, int max)
+{
+ data->type = type;
+
+ switch (type) {
+ case PERF_CPU_MAP__CPUS:
+ synthesize_cpus((struct cpu_map_entries *) data->data, map);
+ break;
+ case PERF_CPU_MAP__MASK:
+ synthesize_mask((struct cpu_map_mask *) data->data, map, max);
+ default:
+ break;
+ };
+}
+
+static struct cpu_map_event* cpu_map_event__new(struct cpu_map *map)
+{
+ size_t size = sizeof(struct cpu_map_event);
+ struct cpu_map_event *event;
+ int max;
+ u16 type;
+
+ event = cpu_map_data__alloc(map, &size, &type, &max);
+ if (!event)
+ return NULL;
+
+ event->header.type = PERF_RECORD_CPU_MAP;
+ event->header.size = size;
+ event->data.type = type;
+
+ cpu_map_data__synthesize(&event->data, map, type, max);
+ return event;
+}
+
+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+ struct cpu_map *map,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct cpu_map_event *event;
+ int err;
+
+ event = cpu_map_event__new(map);
+ if (!event)
+ return -ENOMEM;
+
+ err = process(tool, (union perf_event *) event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+ struct perf_stat_config *config,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_config_event *event;
+ int size, i = 0, err;
+
+ size = sizeof(*event);
+ size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
+
+ event = zalloc(size);
+ if (!event)
+ return -ENOMEM;
+
+ event->header.type = PERF_RECORD_STAT_CONFIG;
+ event->header.size = size;
+ event->nr = PERF_STAT_CONFIG_TERM__MAX;
+
+#define ADD(__term, __val) \
+ event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \
+ event->data[i].val = __val; \
+ i++;
+
+ ADD(AGGR_MODE, config->aggr_mode)
+ ADD(INTERVAL, config->interval)
+ ADD(SCALE, config->scale)
+
+ WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
+ "stat config terms unbalanced\n");
+#undef ADD
+
+ err = process(tool, (union perf_event *) event, NULL, machine);
+
+ free(event);
+ return err;
+}
+
+int perf_event__synthesize_stat(struct perf_tool *tool,
+ u32 cpu, u32 thread, u64 id,
+ struct perf_counts_values *count,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_event event;
+
+ event.header.type = PERF_RECORD_STAT;
+ event.header.size = sizeof(event);
+ event.header.misc = 0;
+
+ event.id = id;
+ event.cpu = cpu;
+ event.thread = thread;
+ event.val = count->val;
+ event.ena = count->ena;
+ event.run = count->run;
+
+ return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+ u64 evtime, u64 type,
+ perf_event__handler_t process,
+ struct machine *machine)
+{
+ struct stat_round_event event;
+
+ event.header.type = PERF_RECORD_STAT_ROUND;
+ event.header.size = sizeof(event);
+ event.header.misc = 0;
+
+ event.time = evtime;
+ event.type = type;
+
+ return process(tool, (union perf_event *) &event, NULL, machine);
+}
+
+void perf_event__read_stat_config(struct perf_stat_config *config,
+ struct stat_config_event *event)
+{
+ unsigned i;
+
+ for (i = 0; i < event->nr; i++) {
+
+ switch (event->data[i].tag) {
+#define CASE(__term, __val) \
+ case PERF_STAT_CONFIG_TERM__##__term: \
+ config->__val = event->data[i].val; \
+ break;
+
+ CASE(AGGR_MODE, aggr_mode)
+ CASE(SCALE, scale)
+ CASE(INTERVAL, interval)
+#undef CASE
+ default:
+ pr_warning("unknown stat config term %" PRIu64 "\n",
+ event->data[i].tag);
+ }
+ }
+}
+
size_t perf_event__fprintf_comm(union perf_event *event, FILE *fp)
{
const char *s;
@@ -783,6 +1059,38 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp)
event->mmap2.filename);
}
+size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp)
+{
+ struct thread_map *threads = thread_map__new_event(&event->thread_map);
+ size_t ret;
+
+ ret = fprintf(fp, " nr: ");
+
+ if (threads)
+ ret += thread_map__fprintf(threads, fp);
+ else
+ ret += fprintf(fp, "failed to get threads from event\n");
+
+ thread_map__put(threads);
+ return ret;
+}
+
+size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp)
+{
+ struct cpu_map *cpus = cpu_map__new_data(&event->cpu_map.data);
+ size_t ret;
+
+ ret = fprintf(fp, " nr: ");
+
+ if (cpus)
+ ret += cpu_map__fprintf(cpus, fp);
+ else
+ ret += fprintf(fp, "failed to get cpumap from event\n");
+
+ cpu_map__put(cpus);
+ return ret;
+}
+
int perf_event__process_mmap(struct perf_tool *tool __maybe_unused,
union perf_event *event,
struct perf_sample *sample,
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index a0dbcbd..b7ffb7e 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -226,6 +226,12 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_AUXTRACE_INFO = 70,
PERF_RECORD_AUXTRACE = 71,
PERF_RECORD_AUXTRACE_ERROR = 72,
+ PERF_RECORD_THREAD_MAP = 73,
+ PERF_RECORD_CPU_MAP = 74,
+ PERF_RECORD_STAT_CONFIG = 75,
+ PERF_RECORD_STAT = 76,
+ PERF_RECORD_STAT_ROUND = 77,
+ PERF_RECORD_EVENT_UPDATE = 78,
PERF_RECORD_HEADER_MAX
};
@@ -270,12 +276,61 @@ struct events_stats {
u32 nr_proc_map_timeout;
};
+enum {
+ PERF_CPU_MAP__CPUS = 0,
+ PERF_CPU_MAP__MASK = 1,
+};
+
+struct cpu_map_entries {
+ u16 nr;
+ u16 cpu[];
+};
+
+struct cpu_map_mask {
+ u16 nr;
+ u16 long_size;
+ unsigned long mask[];
+};
+
+struct cpu_map_data {
+ u16 type;
+ char data[];
+};
+
+struct cpu_map_event {
+ struct perf_event_header header;
+ struct cpu_map_data data;
+};
+
struct attr_event {
struct perf_event_header header;
struct perf_event_attr attr;
u64 id[];
};
+enum {
+ PERF_EVENT_UPDATE__UNIT = 0,
+ PERF_EVENT_UPDATE__SCALE = 1,
+ PERF_EVENT_UPDATE__NAME = 2,
+ PERF_EVENT_UPDATE__CPUS = 3,
+};
+
+struct event_update_event_cpus {
+ struct cpu_map_data cpus;
+};
+
+struct event_update_event_scale {
+ double scale;
+};
+
+struct event_update_event {
+ struct perf_event_header header;
+ u64 type;
+ u64 id;
+
+ char data[];
+};
+
#define MAX_EVENT_NAME 64
struct perf_trace_event_type {
@@ -356,6 +411,63 @@ struct context_switch_event {
u32 next_prev_tid;
};
+struct thread_map_event_entry {
+ u64 pid;
+ char comm[16];
+};
+
+struct thread_map_event {
+ struct perf_event_header header;
+ u64 nr;
+ struct thread_map_event_entry entries[];
+};
+
+enum {
+ PERF_STAT_CONFIG_TERM__AGGR_MODE = 0,
+ PERF_STAT_CONFIG_TERM__INTERVAL = 1,
+ PERF_STAT_CONFIG_TERM__SCALE = 2,
+ PERF_STAT_CONFIG_TERM__MAX = 3,
+};
+
+struct stat_config_event_entry {
+ u64 tag;
+ u64 val;
+};
+
+struct stat_config_event {
+ struct perf_event_header header;
+ u64 nr;
+ struct stat_config_event_entry data[];
+};
+
+struct stat_event {
+ struct perf_event_header header;
+
+ u64 id;
+ u32 cpu;
+ u32 thread;
+
+ union {
+ struct {
+ u64 val;
+ u64 ena;
+ u64 run;
+ };
+ u64 values[3];
+ };
+};
+
+enum {
+ PERF_STAT_ROUND_TYPE__INTERVAL = 0,
+ PERF_STAT_ROUND_TYPE__FINAL = 1,
+};
+
+struct stat_round_event {
+ struct perf_event_header header;
+ u64 type;
+ u64 time;
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -368,6 +480,7 @@ union perf_event {
struct throttle_event throttle;
struct sample_event sample;
struct attr_event attr;
+ struct event_update_event event_update;
struct event_type_event event_type;
struct tracing_data_event tracing_data;
struct build_id_event build_id;
@@ -378,12 +491,20 @@ union perf_event {
struct aux_event aux;
struct itrace_start_event itrace_start;
struct context_switch_event context_switch;
+ struct thread_map_event thread_map;
+ struct cpu_map_event cpu_map;
+ struct stat_config_event stat_config;
+ struct stat_event stat;
+ struct stat_round_event stat_round;
};
void perf_event__print_totals(void);
struct perf_tool;
struct thread_map;
+struct cpu_map;
+struct perf_stat_config;
+struct perf_counts_values;
typedef int (*perf_event__handler_t)(struct perf_tool *tool,
union perf_event *event,
@@ -395,6 +516,14 @@ int perf_event__synthesize_thread_map(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine, bool mmap_data,
unsigned int proc_map_timeout);
+int perf_event__synthesize_thread_map2(struct perf_tool *tool,
+ struct thread_map *threads,
+ perf_event__handler_t process,
+ struct machine *machine);
+int perf_event__synthesize_cpu_map(struct perf_tool *tool,
+ struct cpu_map *cpus,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_threads(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine, bool mmap_data,
@@ -402,7 +531,21 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
-
+int perf_event__synthesize_stat_config(struct perf_tool *tool,
+ struct perf_stat_config *config,
+ perf_event__handler_t process,
+ struct machine *machine);
+void perf_event__read_stat_config(struct perf_stat_config *config,
+ struct stat_config_event *event);
+int perf_event__synthesize_stat(struct perf_tool *tool,
+ u32 cpu, u32 thread, u64 id,
+ struct perf_counts_values *count,
+ perf_event__handler_t process,
+ struct machine *machine);
+int perf_event__synthesize_stat_round(struct perf_tool *tool,
+ u64 time, u64 type,
+ perf_event__handler_t process,
+ struct machine *machine);
int perf_event__synthesize_modules(struct perf_tool *tool,
perf_event__handler_t process,
struct machine *machine);
@@ -499,9 +642,14 @@ size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_aux(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_itrace_start(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_switch(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_thread_map(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp);
u64 kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name);
+void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
+void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
+ u16 type, int max);
#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index d139219..d81f13d 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -18,7 +18,7 @@
#include <unistd.h>
#include "parse-events.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include <sys/mman.h>
@@ -68,6 +68,18 @@ struct perf_evlist *perf_evlist__new_default(void)
return evlist;
}
+struct perf_evlist *perf_evlist__new_dummy(void)
+{
+ struct perf_evlist *evlist = perf_evlist__new();
+
+ if (evlist && perf_evlist__add_dummy(evlist)) {
+ perf_evlist__delete(evlist);
+ evlist = NULL;
+ }
+
+ return evlist;
+}
+
/**
* perf_evlist__set_id_pos - set the positions of event ids.
* @evlist: selected event list
@@ -248,6 +260,22 @@ error:
return -ENOMEM;
}
+int perf_evlist__add_dummy(struct perf_evlist *evlist)
+{
+ struct perf_event_attr attr = {
+ .type = PERF_TYPE_SOFTWARE,
+ .config = PERF_COUNT_SW_DUMMY,
+ .size = sizeof(attr), /* to capture ABI version */
+ };
+ struct perf_evsel *evsel = perf_evsel__new(&attr);
+
+ if (evsel == NULL)
+ return -ENOMEM;
+
+ perf_evlist__add(evlist, evsel);
+ return 0;
+}
+
static int perf_evlist__add_attrs(struct perf_evlist *evlist,
struct perf_event_attr *attrs, size_t nr_attrs)
{
@@ -336,20 +364,12 @@ static int perf_evlist__nr_threads(struct perf_evlist *evlist,
void perf_evlist__disable(struct perf_evlist *evlist)
{
- int cpu, thread;
struct perf_evsel *pos;
- int nr_cpus = cpu_map__nr(evlist->cpus);
- int nr_threads;
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- evlist__for_each(evlist, pos) {
- if (!perf_evsel__is_group_leader(pos) || !pos->fd)
- continue;
- nr_threads = perf_evlist__nr_threads(evlist, pos);
- for (thread = 0; thread < nr_threads; thread++)
- ioctl(FD(pos, cpu, thread),
- PERF_EVENT_IOC_DISABLE, 0);
- }
+ evlist__for_each(evlist, pos) {
+ if (!perf_evsel__is_group_leader(pos) || !pos->fd)
+ continue;
+ perf_evsel__disable(pos);
}
evlist->enabled = false;
@@ -357,20 +377,12 @@ void perf_evlist__disable(struct perf_evlist *evlist)
void perf_evlist__enable(struct perf_evlist *evlist)
{
- int cpu, thread;
struct perf_evsel *pos;
- int nr_cpus = cpu_map__nr(evlist->cpus);
- int nr_threads;
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- evlist__for_each(evlist, pos) {
- if (!perf_evsel__is_group_leader(pos) || !pos->fd)
- continue;
- nr_threads = perf_evlist__nr_threads(evlist, pos);
- for (thread = 0; thread < nr_threads; thread++)
- ioctl(FD(pos, cpu, thread),
- PERF_EVENT_IOC_ENABLE, 0);
- }
+ evlist__for_each(evlist, pos) {
+ if (!perf_evsel__is_group_leader(pos) || !pos->fd)
+ continue;
+ perf_evsel__enable(pos);
}
evlist->enabled = true;
@@ -381,48 +393,6 @@ void perf_evlist__toggle_enable(struct perf_evlist *evlist)
(evlist->enabled ? perf_evlist__disable : perf_evlist__enable)(evlist);
}
-int perf_evlist__disable_event(struct perf_evlist *evlist,
- struct perf_evsel *evsel)
-{
- int cpu, thread, err;
- int nr_cpus = cpu_map__nr(evlist->cpus);
- int nr_threads = perf_evlist__nr_threads(evlist, evsel);
-
- if (!evsel->fd)
- return 0;
-
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- for (thread = 0; thread < nr_threads; thread++) {
- err = ioctl(FD(evsel, cpu, thread),
- PERF_EVENT_IOC_DISABLE, 0);
- if (err)
- return err;
- }
- }
- return 0;
-}
-
-int perf_evlist__enable_event(struct perf_evlist *evlist,
- struct perf_evsel *evsel)
-{
- int cpu, thread, err;
- int nr_cpus = cpu_map__nr(evlist->cpus);
- int nr_threads = perf_evlist__nr_threads(evlist, evsel);
-
- if (!evsel->fd)
- return -EINVAL;
-
- for (cpu = 0; cpu < nr_cpus; cpu++) {
- for (thread = 0; thread < nr_threads; thread++) {
- err = ioctl(FD(evsel, cpu, thread),
- PERF_EVENT_IOC_ENABLE, 0);
- if (err)
- return err;
- }
- }
- return 0;
-}
-
static int perf_evlist__enable_event_cpu(struct perf_evlist *evlist,
struct perf_evsel *evsel, int cpu)
{
@@ -550,9 +520,9 @@ void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
evsel->id[evsel->ids++] = id;
}
-static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
- struct perf_evsel *evsel,
- int cpu, int thread, int fd)
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ int cpu, int thread, int fd)
{
u64 read_data[4] = { 0, };
int id_idx = 1; /* The first entry is the counter value */
@@ -1486,7 +1456,7 @@ int perf_evlist__open(struct perf_evlist *evlist)
perf_evlist__update_id_pos(evlist);
evlist__for_each(evlist, evsel) {
- err = perf_evsel__open(evsel, evlist->cpus, evlist->threads);
+ err = perf_evsel__open(evsel, evsel->cpus, evsel->threads);
if (err < 0)
goto out_err;
}
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index a459fe7..7c4d9a2 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -67,6 +67,7 @@ struct perf_evsel_str_handler {
struct perf_evlist *perf_evlist__new(void);
struct perf_evlist *perf_evlist__new_default(void);
+struct perf_evlist *perf_evlist__new_dummy(void);
void perf_evlist__init(struct perf_evlist *evlist, struct cpu_map *cpus,
struct thread_map *threads);
void perf_evlist__exit(struct perf_evlist *evlist);
@@ -81,6 +82,8 @@ int __perf_evlist__add_default_attrs(struct perf_evlist *evlist,
#define perf_evlist__add_default_attrs(evlist, array) \
__perf_evlist__add_default_attrs(evlist, array, ARRAY_SIZE(array))
+int perf_evlist__add_dummy(struct perf_evlist *evlist);
+
int perf_evlist__add_newtp(struct perf_evlist *evlist,
const char *sys, const char *name, void *handler);
@@ -97,6 +100,9 @@ perf_evlist__find_tracepoint_by_name(struct perf_evlist *evlist,
void perf_evlist__id_add(struct perf_evlist *evlist, struct perf_evsel *evsel,
int cpu, int thread, u64 id);
+int perf_evlist__id_add_fd(struct perf_evlist *evlist,
+ struct perf_evsel *evsel,
+ int cpu, int thread, int fd);
int perf_evlist__add_pollfd(struct perf_evlist *evlist, int fd);
int perf_evlist__alloc_pollfd(struct perf_evlist *evlist);
@@ -149,10 +155,6 @@ void perf_evlist__disable(struct perf_evlist *evlist);
void perf_evlist__enable(struct perf_evlist *evlist);
void perf_evlist__toggle_enable(struct perf_evlist *evlist);
-int perf_evlist__disable_event(struct perf_evlist *evlist,
- struct perf_evsel *evsel);
-int perf_evlist__enable_event(struct perf_evlist *evlist,
- struct perf_evsel *evsel);
int perf_evlist__enable_event_idx(struct perf_evlist *evlist,
struct perf_evsel *evsel, int idx);
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 397fb4e..cdbaf9b 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -36,6 +36,7 @@ static struct {
bool cloexec;
bool clockid;
bool clockid_wrong;
+ bool lbr_flags;
} perf_missing_features;
static clockid_t clockid;
@@ -574,7 +575,9 @@ perf_evsel__config_callgraph(struct perf_evsel *evsel,
} else {
perf_evsel__set_sample_bit(evsel, BRANCH_STACK);
attr->branch_sample_type = PERF_SAMPLE_BRANCH_USER |
- PERF_SAMPLE_BRANCH_CALL_STACK;
+ PERF_SAMPLE_BRANCH_CALL_STACK |
+ PERF_SAMPLE_BRANCH_NO_CYCLES |
+ PERF_SAMPLE_BRANCH_NO_FLAGS;
}
} else
pr_warning("Cannot use LBR callstack with branch stack. "
@@ -981,13 +984,26 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
return -1;
}
-int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads)
+int perf_evsel__enable(struct perf_evsel *evsel)
{
+ int nthreads = thread_map__nr(evsel->threads);
+ int ncpus = cpu_map__nr(evsel->cpus);
+
return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
PERF_EVENT_IOC_ENABLE,
0);
}
+int perf_evsel__disable(struct perf_evsel *evsel)
+{
+ int nthreads = thread_map__nr(evsel->threads);
+ int ncpus = cpu_map__nr(evsel->cpus);
+
+ return perf_evsel__run_ioctl(evsel, ncpus, nthreads,
+ PERF_EVENT_IOC_DISABLE,
+ 0);
+}
+
int perf_evsel__alloc_id(struct perf_evsel *evsel, int ncpus, int nthreads)
{
if (ncpus == 0 || nthreads == 0)
@@ -1192,6 +1208,7 @@ static void __p_sample_type(char *buf, size_t size, u64 value)
bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
bit_name(IDENTIFIER), bit_name(REGS_INTR), bit_name(DATA_SRC),
+ bit_name(WEIGHT),
{ .name = NULL, }
};
#undef bit_name
@@ -1323,6 +1340,9 @@ fallback_missing_features:
evsel->attr.mmap2 = 0;
if (perf_missing_features.exclude_guest)
evsel->attr.exclude_guest = evsel->attr.exclude_host = 0;
+ if (perf_missing_features.lbr_flags)
+ evsel->attr.branch_sample_type &= ~(PERF_SAMPLE_BRANCH_NO_FLAGS |
+ PERF_SAMPLE_BRANCH_NO_CYCLES);
retry_sample_id:
if (perf_missing_features.sample_id_all)
evsel->attr.sample_id_all = 0;
@@ -1441,6 +1461,12 @@ try_fallback:
} else if (!perf_missing_features.sample_id_all) {
perf_missing_features.sample_id_all = true;
goto retry_sample_id;
+ } else if (!perf_missing_features.lbr_flags &&
+ (evsel->attr.branch_sample_type &
+ (PERF_SAMPLE_BRANCH_NO_CYCLES |
+ PERF_SAMPLE_BRANCH_NO_FLAGS))) {
+ perf_missing_features.lbr_flags = true;
+ goto fallback_missing_features;
}
out_close:
@@ -2272,6 +2298,29 @@ int perf_evsel__fprintf(struct perf_evsel *evsel,
printed += comma_fprintf(fp, &first, " %s=%" PRIu64,
term, (u64)evsel->attr.sample_freq);
}
+
+ if (details->trace_fields) {
+ struct format_field *field;
+
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+ printed += comma_fprintf(fp, &first, " (not a tracepoint)");
+ goto out;
+ }
+
+ field = evsel->tp_format->format.fields;
+ if (field == NULL) {
+ printed += comma_fprintf(fp, &first, " (no trace field)");
+ goto out;
+ }
+
+ printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name);
+
+ field = field->next;
+ while (field) {
+ printed += comma_fprintf(fp, &first, "%s", field->name);
+ field = field->next;
+ }
+ }
out:
fputc('\n', fp);
return ++printed;
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 0e49bd7..8e75434 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -227,7 +227,8 @@ int perf_evsel__append_filter(struct perf_evsel *evsel,
const char *op, const char *filter);
int perf_evsel__apply_filter(struct perf_evsel *evsel, int ncpus, int nthreads,
const char *filter);
-int perf_evsel__enable(struct perf_evsel *evsel, int ncpus, int nthreads);
+int perf_evsel__enable(struct perf_evsel *evsel);
+int perf_evsel__disable(struct perf_evsel *evsel);
int perf_evsel__open_per_cpu(struct perf_evsel *evsel,
struct cpu_map *cpus);
@@ -368,6 +369,7 @@ struct perf_attr_details {
bool verbose;
bool event_group;
bool force;
+ bool trace_fields;
};
int perf_evsel__fprintf(struct perf_evsel *evsel,
diff --git a/tools/perf/util/exec_cmd.c b/tools/perf/util/exec_cmd.c
deleted file mode 100644
index 7adf4ad..0000000
--- a/tools/perf/util/exec_cmd.c
+++ /dev/null
@@ -1,148 +0,0 @@
-#include "cache.h"
-#include "exec_cmd.h"
-#include "quote.h"
-
-#include <string.h>
-
-#define MAX_ARGS 32
-
-static const char *argv_exec_path;
-static const char *argv0_path;
-
-const char *system_path(const char *path)
-{
- static const char *prefix = PREFIX;
- struct strbuf d = STRBUF_INIT;
-
- if (is_absolute_path(path))
- return path;
-
- strbuf_addf(&d, "%s/%s", prefix, path);
- path = strbuf_detach(&d, NULL);
- return path;
-}
-
-const char *perf_extract_argv0_path(const char *argv0)
-{
- const char *slash;
-
- if (!argv0 || !*argv0)
- return NULL;
- slash = argv0 + strlen(argv0);
-
- while (argv0 <= slash && !is_dir_sep(*slash))
- slash--;
-
- if (slash >= argv0) {
- argv0_path = strndup(argv0, slash - argv0);
- return argv0_path ? slash + 1 : NULL;
- }
-
- return argv0;
-}
-
-void perf_set_argv_exec_path(const char *exec_path)
-{
- argv_exec_path = exec_path;
- /*
- * Propagate this setting to external programs.
- */
- setenv(EXEC_PATH_ENVIRONMENT, exec_path, 1);
-}
-
-
-/* Returns the highest-priority, location to look for perf programs. */
-const char *perf_exec_path(void)
-{
- const char *env;
-
- if (argv_exec_path)
- return argv_exec_path;
-
- env = getenv(EXEC_PATH_ENVIRONMENT);
- if (env && *env) {
- return env;
- }
-
- return system_path(PERF_EXEC_PATH);
-}
-
-static void add_path(struct strbuf *out, const char *path)
-{
- if (path && *path) {
- if (is_absolute_path(path))
- strbuf_addstr(out, path);
- else
- strbuf_addstr(out, make_nonrelative_path(path));
-
- strbuf_addch(out, PATH_SEP);
- }
-}
-
-void setup_path(void)
-{
- const char *old_path = getenv("PATH");
- struct strbuf new_path = STRBUF_INIT;
-
- add_path(&new_path, perf_exec_path());
- add_path(&new_path, argv0_path);
-
- if (old_path)
- strbuf_addstr(&new_path, old_path);
- else
- strbuf_addstr(&new_path, "/usr/local/bin:/usr/bin:/bin");
-
- setenv("PATH", new_path.buf, 1);
-
- strbuf_release(&new_path);
-}
-
-static const char **prepare_perf_cmd(const char **argv)
-{
- int argc;
- const char **nargv;
-
- for (argc = 0; argv[argc]; argc++)
- ; /* just counting */
- nargv = malloc(sizeof(*nargv) * (argc + 2));
-
- nargv[0] = "perf";
- for (argc = 0; argv[argc]; argc++)
- nargv[argc + 1] = argv[argc];
- nargv[argc + 1] = NULL;
- return nargv;
-}
-
-int execv_perf_cmd(const char **argv) {
- const char **nargv = prepare_perf_cmd(argv);
-
- /* execvp() can only ever return if it fails */
- execvp("perf", (char **)nargv);
-
- free(nargv);
- return -1;
-}
-
-
-int execl_perf_cmd(const char *cmd,...)
-{
- int argc;
- const char *argv[MAX_ARGS + 1];
- const char *arg;
- va_list param;
-
- va_start(param, cmd);
- argv[0] = cmd;
- argc = 1;
- while (argc < MAX_ARGS) {
- arg = argv[argc++] = va_arg(param, char *);
- if (!arg)
- break;
- }
- va_end(param);
- if (MAX_ARGS <= argc)
- return error("too many args to run %s", cmd);
-
- argv[argc] = NULL;
- return execv_perf_cmd(argv);
-}
diff --git a/tools/perf/util/exec_cmd.h b/tools/perf/util/exec_cmd.h
deleted file mode 100644
index bc4b915..0000000
--- a/tools/perf/util/exec_cmd.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __PERF_EXEC_CMD_H
-#define __PERF_EXEC_CMD_H
-
-extern void perf_set_argv_exec_path(const char *exec_path);
-extern const char *perf_extract_argv0_path(const char *path);
-extern const char *perf_exec_path(void);
-extern void setup_path(void);
-extern int execv_perf_cmd(const char **argv); /* NULL terminated */
-extern int execl_perf_cmd(const char *cmd, ...);
-extern const char *system_path(const char *path);
-
-#endif /* __PERF_EXEC_CMD_H */
diff --git a/tools/perf/util/generate-cmdlist.sh b/tools/perf/util/generate-cmdlist.sh
index 36a885d..0ac2037 100755
--- a/tools/perf/util/generate-cmdlist.sh
+++ b/tools/perf/util/generate-cmdlist.sh
@@ -36,4 +36,19 @@ do
}' "Documentation/perf-$cmd.txt"
done
echo "#endif /* HAVE_LIBELF_SUPPORT */"
+
+echo "#ifdef HAVE_LIBAUDIT_SUPPORT"
+sed -n -e 's/^perf-\([^ ]*\)[ ].* audit*/\1/p' command-list.txt |
+sort |
+while read cmd
+do
+ sed -n '
+ /^NAME/,/perf-'"$cmd"'/H
+ ${
+ x
+ s/.*perf-'"$cmd"' - \(.*\)/ {"'"$cmd"'", "\1"},/
+ p
+ }' "Documentation/perf-$cmd.txt"
+done
+echo "#endif /* HAVE_LIBELF_SUPPORT */"
echo "};"
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4383800..f50b723 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -724,7 +724,7 @@ static int write_numa_topology(int fd, struct perf_header *h __maybe_unused,
done:
free(buf);
fclose(fp);
- free(node_map);
+ cpu_map__put(node_map);
return ret;
}
@@ -868,6 +868,13 @@ static int write_auxtrace(int fd, struct perf_header *h,
return err;
}
+static int write_stat(int fd __maybe_unused,
+ struct perf_header *h __maybe_unused,
+ struct perf_evlist *evlist __maybe_unused)
+{
+ return 0;
+}
+
static void print_hostname(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -1159,6 +1166,12 @@ static void print_auxtrace(struct perf_header *ph __maybe_unused,
fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
}
+static void print_stat(struct perf_header *ph __maybe_unused,
+ int fd __maybe_unused, FILE *fp)
+{
+ fprintf(fp, "# contains stat data\n");
+}
+
static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
FILE *fp)
{
@@ -1948,6 +1961,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
FEAT_OPP(HEADER_PMU_MAPPINGS, pmu_mappings),
FEAT_OPP(HEADER_GROUP_DESC, group_desc),
FEAT_OPP(HEADER_AUXTRACE, auxtrace),
+ FEAT_OPA(HEADER_STAT, stat),
};
struct header_print_data {
@@ -2686,6 +2700,152 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
return err;
}
+static struct event_update_event *
+event_update_event__new(size_t size, u64 type, u64 id)
+{
+ struct event_update_event *ev;
+
+ size += sizeof(*ev);
+ size = PERF_ALIGN(size, sizeof(u64));
+
+ ev = zalloc(size);
+ if (ev) {
+ ev->header.type = PERF_RECORD_EVENT_UPDATE;
+ ev->header.size = (u16)size;
+ ev->type = type;
+ ev->id = id;
+ }
+ return ev;
+}
+
+int
+perf_event__synthesize_event_update_unit(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process)
+{
+ struct event_update_event *ev;
+ size_t size = strlen(evsel->unit);
+ int err;
+
+ ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->id[0]);
+ if (ev == NULL)
+ return -ENOMEM;
+
+ strncpy(ev->data, evsel->unit, size);
+ err = process(tool, (union perf_event *)ev, NULL, NULL);
+ free(ev);
+ return err;
+}
+
+int
+perf_event__synthesize_event_update_scale(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process)
+{
+ struct event_update_event *ev;
+ struct event_update_event_scale *ev_data;
+ int err;
+
+ ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->id[0]);
+ if (ev == NULL)
+ return -ENOMEM;
+
+ ev_data = (struct event_update_event_scale *) ev->data;
+ ev_data->scale = evsel->scale;
+ err = process(tool, (union perf_event*) ev, NULL, NULL);
+ free(ev);
+ return err;
+}
+
+int
+perf_event__synthesize_event_update_name(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process)
+{
+ struct event_update_event *ev;
+ size_t len = strlen(evsel->name);
+ int err;
+
+ ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->id[0]);
+ if (ev == NULL)
+ return -ENOMEM;
+
+ strncpy(ev->data, evsel->name, len);
+ err = process(tool, (union perf_event*) ev, NULL, NULL);
+ free(ev);
+ return err;
+}
+
+int
+perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process)
+{
+ size_t size = sizeof(struct event_update_event);
+ struct event_update_event *ev;
+ int max, err;
+ u16 type;
+
+ if (!evsel->own_cpus)
+ return 0;
+
+ ev = cpu_map_data__alloc(evsel->own_cpus, &size, &type, &max);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->header.type = PERF_RECORD_EVENT_UPDATE;
+ ev->header.size = (u16)size;
+ ev->type = PERF_EVENT_UPDATE__CPUS;
+ ev->id = evsel->id[0];
+
+ cpu_map_data__synthesize((struct cpu_map_data *) ev->data,
+ evsel->own_cpus,
+ type, max);
+
+ err = process(tool, (union perf_event*) ev, NULL, NULL);
+ free(ev);
+ return err;
+}
+
+size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
+{
+ struct event_update_event *ev = &event->event_update;
+ struct event_update_event_scale *ev_scale;
+ struct event_update_event_cpus *ev_cpus;
+ struct cpu_map *map;
+ size_t ret;
+
+ ret = fprintf(fp, "\n... id: %" PRIu64 "\n", ev->id);
+
+ switch (ev->type) {
+ case PERF_EVENT_UPDATE__SCALE:
+ ev_scale = (struct event_update_event_scale *) ev->data;
+ ret += fprintf(fp, "... scale: %f\n", ev_scale->scale);
+ break;
+ case PERF_EVENT_UPDATE__UNIT:
+ ret += fprintf(fp, "... unit: %s\n", ev->data);
+ break;
+ case PERF_EVENT_UPDATE__NAME:
+ ret += fprintf(fp, "... name: %s\n", ev->data);
+ break;
+ case PERF_EVENT_UPDATE__CPUS:
+ ev_cpus = (struct event_update_event_cpus *) ev->data;
+ ret += fprintf(fp, "... ");
+
+ map = cpu_map__new_data(&ev_cpus->cpus);
+ if (map)
+ ret += cpu_map__fprintf(map, fp);
+ else
+ ret += fprintf(fp, "failed to get cpus\n");
+ break;
+ default:
+ ret += fprintf(fp, "... unknown type\n");
+ break;
+ }
+
+ return ret;
+}
+
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process)
@@ -2745,6 +2905,51 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused,
return 0;
}
+int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_evlist **pevlist)
+{
+ struct event_update_event *ev = &event->event_update;
+ struct event_update_event_scale *ev_scale;
+ struct event_update_event_cpus *ev_cpus;
+ struct perf_evlist *evlist;
+ struct perf_evsel *evsel;
+ struct cpu_map *map;
+
+ if (!pevlist || *pevlist == NULL)
+ return -EINVAL;
+
+ evlist = *pevlist;
+
+ evsel = perf_evlist__id2evsel(evlist, ev->id);
+ if (evsel == NULL)
+ return -EINVAL;
+
+ switch (ev->type) {
+ case PERF_EVENT_UPDATE__UNIT:
+ evsel->unit = strdup(ev->data);
+ break;
+ case PERF_EVENT_UPDATE__NAME:
+ evsel->name = strdup(ev->data);
+ break;
+ case PERF_EVENT_UPDATE__SCALE:
+ ev_scale = (struct event_update_event_scale *) ev->data;
+ evsel->scale = ev_scale->scale;
+ case PERF_EVENT_UPDATE__CPUS:
+ ev_cpus = (struct event_update_event_cpus *) ev->data;
+
+ map = cpu_map__new_data(&ev_cpus->cpus);
+ if (map)
+ evsel->own_cpus = map;
+ else
+ pr_err("failed to get event_update cpus\n");
+ default:
+ break;
+ }
+
+ return 0;
+}
+
int perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd,
struct perf_evlist *evlist,
perf_event__handler_t process)
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 05f27cb..cff9892 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -31,6 +31,7 @@ enum {
HEADER_PMU_MAPPINGS,
HEADER_GROUP_DESC,
HEADER_AUXTRACE,
+ HEADER_STAT,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
@@ -105,8 +106,24 @@ int perf_event__synthesize_attr(struct perf_tool *tool,
int perf_event__synthesize_attrs(struct perf_tool *tool,
struct perf_session *session,
perf_event__handler_t process);
+int perf_event__synthesize_event_update_unit(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process);
+int perf_event__synthesize_event_update_scale(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process);
+int perf_event__synthesize_event_update_name(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process);
+int perf_event__synthesize_event_update_cpus(struct perf_tool *tool,
+ struct perf_evsel *evsel,
+ perf_event__handler_t process);
int perf_event__process_attr(struct perf_tool *tool, union perf_event *event,
struct perf_evlist **pevlist);
+int perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_evlist **pevlist);
+size_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp);
int perf_event__synthesize_tracing_data(struct perf_tool *tool,
int fd, struct perf_evlist *evlist,
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
new file mode 100644
index 0000000..dc1e41c
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -0,0 +1,103 @@
+#include "cache.h"
+#include <subcmd/help.h>
+#include "../builtin.h"
+#include "levenshtein.h"
+
+static int autocorrect;
+static struct cmdnames aliases;
+
+static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
+{
+ if (!strcmp(var, "help.autocorrect"))
+ autocorrect = perf_config_int(var,value);
+ /* Also use aliases for command lookup */
+ if (!prefixcmp(var, "alias."))
+ add_cmdname(&aliases, var + 6, strlen(var + 6));
+
+ return perf_default_config(var, value, cb);
+}
+
+static int levenshtein_compare(const void *p1, const void *p2)
+{
+ const struct cmdname *const *c1 = p1, *const *c2 = p2;
+ const char *s1 = (*c1)->name, *s2 = (*c2)->name;
+ int l1 = (*c1)->len;
+ int l2 = (*c2)->len;
+ return l1 != l2 ? l1 - l2 : strcmp(s1, s2);
+}
+
+static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old)
+{
+ unsigned int i;
+
+ ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc);
+
+ for (i = 0; i < old->cnt; i++)
+ cmds->names[cmds->cnt++] = old->names[i];
+ zfree(&old->names);
+ old->cnt = 0;
+}
+
+const char *help_unknown_cmd(const char *cmd)
+{
+ unsigned int i, n = 0, best_similarity = 0;
+ struct cmdnames main_cmds, other_cmds;
+
+ memset(&main_cmds, 0, sizeof(main_cmds));
+ memset(&other_cmds, 0, sizeof(main_cmds));
+ memset(&aliases, 0, sizeof(aliases));
+
+ perf_config(perf_unknown_cmd_config, NULL);
+
+ load_command_list("perf-", &main_cmds, &other_cmds);
+
+ add_cmd_list(&main_cmds, &aliases);
+ add_cmd_list(&main_cmds, &other_cmds);
+ qsort(main_cmds.names, main_cmds.cnt,
+ sizeof(main_cmds.names), cmdname_compare);
+ uniq(&main_cmds);
+
+ if (main_cmds.cnt) {
+ /* This reuses cmdname->len for similarity index */
+ for (i = 0; i < main_cmds.cnt; ++i)
+ main_cmds.names[i]->len =
+ levenshtein(cmd, main_cmds.names[i]->name, 0, 2, 1, 4);
+
+ qsort(main_cmds.names, main_cmds.cnt,
+ sizeof(*main_cmds.names), levenshtein_compare);
+
+ best_similarity = main_cmds.names[0]->len;
+ n = 1;
+ while (n < main_cmds.cnt && best_similarity == main_cmds.names[n]->len)
+ ++n;
+ }
+
+ if (autocorrect && n == 1) {
+ const char *assumed = main_cmds.names[0]->name;
+
+ main_cmds.names[0] = NULL;
+ clean_cmdnames(&main_cmds);
+ fprintf(stderr, "WARNING: You called a perf program named '%s', "
+ "which does not exist.\n"
+ "Continuing under the assumption that you meant '%s'\n",
+ cmd, assumed);
+ if (autocorrect > 0) {
+ fprintf(stderr, "in %0.1f seconds automatically...\n",
+ (float)autocorrect/10.0);
+ poll(NULL, 0, autocorrect * 100);
+ }
+ return assumed;
+ }
+
+ fprintf(stderr, "perf: '%s' is not a perf-command. See 'perf --help'.\n", cmd);
+
+ if (main_cmds.cnt && best_similarity < 6) {
+ fprintf(stderr, "\nDid you mean %s?\n",
+ n < 2 ? "this": "one of these");
+
+ for (i = 0; i < n; i++)
+ fprintf(stderr, "\t%s\n", main_cmds.names[i]->name);
+ }
+
+ exit(1);
+}
diff --git a/tools/perf/util/help-unknown-cmd.h b/tools/perf/util/help-unknown-cmd.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tools/perf/util/help-unknown-cmd.h
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 4fd37d6..c226303 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -254,6 +254,7 @@ static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
he_stat__decay(&he->stat);
if (symbol_conf.cumulate_callchain)
he_stat__decay(he->stat_acc);
+ decay_callchain(he->callchain);
diff = prev_period - he->stat.period;
@@ -270,6 +271,8 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
if (sort__need_collapse)
rb_erase(&he->rb_node_in, &hists->entries_collapsed);
+ else
+ rb_erase(&he->rb_node_in, hists->entries_in);
--hists->nr_entries;
if (!he->filtered)
@@ -367,6 +370,25 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
if (symbol_conf.use_callchain)
callchain_init(he->callchain);
+ if (he->raw_data) {
+ he->raw_data = memdup(he->raw_data, he->raw_size);
+
+ if (he->raw_data == NULL) {
+ map__put(he->ms.map);
+ if (he->branch_info) {
+ map__put(he->branch_info->from.map);
+ map__put(he->branch_info->to.map);
+ free(he->branch_info);
+ }
+ if (he->mem_info) {
+ map__put(he->mem_info->iaddr.map);
+ map__put(he->mem_info->daddr.map);
+ }
+ free(he->stat_acc);
+ free(he);
+ return NULL;
+ }
+ }
INIT_LIST_HEAD(&he->pairs.node);
thread__get(he->thread);
}
@@ -459,7 +481,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
struct symbol *sym_parent,
struct branch_info *bi,
struct mem_info *mi,
- u64 period, u64 weight, u64 transaction,
+ struct perf_sample *sample,
bool sample_self)
{
struct hist_entry entry = {
@@ -476,15 +498,17 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
.level = al->level,
.stat = {
.nr_events = 1,
- .period = period,
- .weight = weight,
+ .period = sample->period,
+ .weight = sample->weight,
},
.parent = sym_parent,
.filtered = symbol__parent_filter(sym_parent) | al->filtered,
.hists = hists,
.branch_info = bi,
.mem_info = mi,
- .transaction = transaction,
+ .transaction = sample->transaction,
+ .raw_data = sample->raw_data,
+ .raw_size = sample->raw_size,
};
return hists__findnew_entry(hists, &entry, al, sample_self);
@@ -524,12 +548,13 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
u64 cost;
struct mem_info *mi = iter->priv;
struct hists *hists = evsel__hists(iter->evsel);
+ struct perf_sample *sample = iter->sample;
struct hist_entry *he;
if (mi == NULL)
return -EINVAL;
- cost = iter->sample->weight;
+ cost = sample->weight;
if (!cost)
cost = 1;
@@ -540,8 +565,10 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
* and this is indirectly achieved by passing period=weight here
* and the he_stat__add_period() function.
*/
+ sample->period = cost;
+
he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
- cost, cost, 0, true);
+ sample, true);
if (!he)
return -ENOMEM;
@@ -628,6 +655,7 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
struct branch_info *bi;
struct perf_evsel *evsel = iter->evsel;
struct hists *hists = evsel__hists(evsel);
+ struct perf_sample *sample = iter->sample;
struct hist_entry *he = NULL;
int i = iter->curr;
int err = 0;
@@ -641,9 +669,11 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
* The report shows the percentage of total branches captured
* and not events sampled. Thus we use a pseudo period of 1.
*/
+ sample->period = 1;
+ sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
+
he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
- 1, bi->flags.cycles ? bi->flags.cycles : 1,
- 0, true);
+ sample, true);
if (he == NULL)
return -ENOMEM;
@@ -680,8 +710,7 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
struct hist_entry *he;
he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
- sample->period, sample->weight,
- sample->transaction, true);
+ sample, true);
if (he == NULL)
return -ENOMEM;
@@ -742,8 +771,7 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
int err = 0;
he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
- sample->period, sample->weight,
- sample->transaction, true);
+ sample, true);
if (he == NULL)
return -ENOMEM;
@@ -795,6 +823,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
.sym = al->sym,
},
.parent = iter->parent,
+ .raw_data = sample->raw_data,
+ .raw_size = sample->raw_size,
};
int i;
struct callchain_cursor cursor;
@@ -816,8 +846,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
}
he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
- sample->period, sample->weight,
- sample->transaction, false);
+ sample, false);
if (he == NULL)
return -ENOMEM;
@@ -924,9 +953,6 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0;
perf_hpp__for_each_sort_list(fmt) {
- if (perf_hpp__should_skip(fmt))
- continue;
-
cmp = fmt->cmp(fmt, left, right);
if (cmp)
break;
@@ -942,9 +968,6 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0;
perf_hpp__for_each_sort_list(fmt) {
- if (perf_hpp__should_skip(fmt))
- continue;
-
cmp = fmt->collapse(fmt, left, right);
if (cmp)
break;
@@ -975,6 +998,8 @@ void hist_entry__delete(struct hist_entry *he)
if (he->srcfile && he->srcfile[0])
free(he->srcfile);
free_callchain(he->callchain);
+ free(he->trace_output);
+ free(he->raw_data);
free(he);
}
@@ -982,9 +1007,8 @@ void hist_entry__delete(struct hist_entry *he)
* collapse the histogram
*/
-static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
- struct rb_root *root,
- struct hist_entry *he)
+bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
+ struct rb_root *root, struct hist_entry *he)
{
struct rb_node **p = &root->rb_node;
struct rb_node *parent = NULL;
@@ -1024,7 +1048,7 @@ static bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
return true;
}
-static struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
+struct rb_root *hists__get_rotate_entries_in(struct hists *hists)
{
struct rb_root *root;
@@ -1088,7 +1112,7 @@ static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
int64_t cmp = 0;
perf_hpp__for_each_sort_list(fmt) {
- if (perf_hpp__should_skip(fmt))
+ if (perf_hpp__should_skip(fmt, a->hists))
continue;
cmp = fmt->sort(fmt, a, b);
@@ -1559,10 +1583,8 @@ int perf_hist_config(const char *var, const char *value)
return 0;
}
-static int hists_evsel__init(struct perf_evsel *evsel)
+int __hists__init(struct hists *hists)
{
- struct hists *hists = evsel__hists(evsel);
-
memset(hists, 0, sizeof(*hists));
hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
hists->entries_in = &hists->entries_in_array[0];
@@ -1573,6 +1595,43 @@ static int hists_evsel__init(struct perf_evsel *evsel)
return 0;
}
+static void hists__delete_remaining_entries(struct rb_root *root)
+{
+ struct rb_node *node;
+ struct hist_entry *he;
+
+ while (!RB_EMPTY_ROOT(root)) {
+ node = rb_first(root);
+ rb_erase(node, root);
+
+ he = rb_entry(node, struct hist_entry, rb_node_in);
+ hist_entry__delete(he);
+ }
+}
+
+static void hists__delete_all_entries(struct hists *hists)
+{
+ hists__delete_entries(hists);
+ hists__delete_remaining_entries(&hists->entries_in_array[0]);
+ hists__delete_remaining_entries(&hists->entries_in_array[1]);
+ hists__delete_remaining_entries(&hists->entries_collapsed);
+}
+
+static void hists_evsel__exit(struct perf_evsel *evsel)
+{
+ struct hists *hists = evsel__hists(evsel);
+
+ hists__delete_all_entries(hists);
+}
+
+static int hists_evsel__init(struct perf_evsel *evsel)
+{
+ struct hists *hists = evsel__hists(evsel);
+
+ __hists__init(hists);
+ return 0;
+}
+
/*
* XXX We probably need a hists_evsel__exit() to free the hist_entries
* stored in the rbtree...
@@ -1581,7 +1640,8 @@ static int hists_evsel__init(struct perf_evsel *evsel)
int hists__init(void)
{
int err = perf_evsel__object_config(sizeof(struct hists_evsel),
- hists_evsel__init, NULL);
+ hists_evsel__init,
+ hists_evsel__exit);
if (err)
fputs("FATAL ERROR: Couldn't setup hists class\n", stderr);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index a48a207..d4ec482 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -52,6 +52,7 @@ enum hist_column {
HISTC_MEM_IADDR_SYMBOL,
HISTC_TRANSACTION,
HISTC_CYCLES,
+ HISTC_TRACE,
HISTC_NR_COLS, /* Last entry */
};
@@ -114,8 +115,8 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
struct addr_location *al,
struct symbol *parent,
struct branch_info *bi,
- struct mem_info *mi, u64 period,
- u64 weight, u64 transaction,
+ struct mem_info *mi,
+ struct perf_sample *sample,
bool sample_self);
int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
int max_stack_depth, void *arg);
@@ -184,6 +185,11 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
}
int hists__init(void);
+int __hists__init(struct hists *hists);
+
+struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
+bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
+ struct rb_root *root, struct hist_entry *he);
struct perf_hpp {
char *buf;
@@ -261,10 +267,20 @@ void perf_hpp__append_sort_keys(void);
bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
+bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *format);
+bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
-static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format)
+static inline bool perf_hpp__should_skip(struct perf_hpp_fmt *format,
+ struct hists *hists)
{
- return format->elide;
+ if (format->elide)
+ return true;
+
+ if (perf_hpp__is_dynamic_entry(format) &&
+ !perf_hpp__defined_dynamic_entry(format, hists))
+ return true;
+
+ return false;
}
void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
diff --git a/tools/perf/util/include/linux/string.h b/tools/perf/util/include/linux/string.h
deleted file mode 100644
index 6f19c54..0000000
--- a/tools/perf/util/include/linux/string.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#include <string.h>
-
-void *memdup(const void *src, size_t len);
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
index 97f963a..81a2eb7 100644
--- a/tools/perf/util/intel-pt.c
+++ b/tools/perf/util/intel-pt.c
@@ -1744,7 +1744,7 @@ static void intel_pt_free(struct perf_session *session)
auxtrace_heap__free(&pt->heap);
intel_pt_free_events(session);
session->auxtrace = NULL;
- thread__delete(pt->unknown_thread);
+ thread__put(pt->unknown_thread);
free(pt);
}
@@ -2153,7 +2153,7 @@ int intel_pt_process_auxtrace_info(union perf_event *event,
return 0;
err_delete_thread:
- thread__delete(pt->unknown_thread);
+ thread__zput(pt->unknown_thread);
err_free_queues:
intel_pt_log_disable();
auxtrace_queues__free(&pt->queues);
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 4f6a478..00724d4 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -4,17 +4,18 @@
*/
#include <stdio.h>
-#include <sys/utsname.h>
#include "util.h"
#include "debug.h"
#include "llvm-utils.h"
#include "cache.h"
#define CLANG_BPF_CMD_DEFAULT_TEMPLATE \
- "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \
- "$KERNEL_INC_OPTIONS -Wno-unused-value " \
- "-Wno-pointer-sign -working-directory " \
- "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
+ "$CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS "\
+ "-DLINUX_VERSION_CODE=$LINUX_VERSION_CODE " \
+ "$CLANG_OPTIONS $KERNEL_INC_OPTIONS " \
+ "-Wno-unused-value -Wno-pointer-sign " \
+ "-working-directory $WORKING_DIR " \
+ "-c \"$CLANG_SOURCE\" -target bpf -O2 -o -"
struct llvm_param llvm_param = {
.clang_path = "clang",
@@ -214,18 +215,19 @@ static int detect_kbuild_dir(char **kbuild_dir)
const char *suffix_dir = "";
char *autoconf_path;
- struct utsname utsname;
int err;
if (!test_dir) {
- err = uname(&utsname);
- if (err) {
- pr_warning("uname failed: %s\n", strerror(errno));
+ /* _UTSNAME_LENGTH is 65 */
+ char release[128];
+
+ err = fetch_kernel_version(NULL, release,
+ sizeof(release));
+ if (err)
return -EINVAL;
- }
- test_dir = utsname.release;
+ test_dir = release;
prefix_dir = "/lib/modules/";
suffix_dir = "/build";
}
@@ -326,13 +328,15 @@ get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
int llvm__compile_bpf(const char *path, void **p_obj_buf,
size_t *p_obj_buf_sz)
{
- int err;
- char clang_path[PATH_MAX];
+ size_t obj_buf_sz;
+ void *obj_buf = NULL;
+ int err, nr_cpus_avail;
+ unsigned int kernel_version;
+ char linux_version_code_str[64];
const char *clang_opt = llvm_param.clang_opt;
- const char *template = llvm_param.clang_bpf_cmd_template;
+ char clang_path[PATH_MAX], nr_cpus_avail_str[64];
char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
- void *obj_buf = NULL;
- size_t obj_buf_sz;
+ const char *template = llvm_param.clang_bpf_cmd_template;
if (!template)
template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
@@ -354,6 +358,24 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
*/
get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
+ nr_cpus_avail = sysconf(_SC_NPROCESSORS_CONF);
+ if (nr_cpus_avail <= 0) {
+ pr_err(
+"WARNING:\tunable to get available CPUs in this system: %s\n"
+" \tUse 128 instead.\n", strerror(errno));
+ nr_cpus_avail = 128;
+ }
+ snprintf(nr_cpus_avail_str, sizeof(nr_cpus_avail_str), "%d",
+ nr_cpus_avail);
+
+ if (fetch_kernel_version(&kernel_version, NULL, 0))
+ kernel_version = 0;
+
+ snprintf(linux_version_code_str, sizeof(linux_version_code_str),
+ "0x%x", kernel_version);
+
+ force_set_env("NR_CPUS", nr_cpus_avail_str);
+ force_set_env("LINUX_VERSION_CODE", linux_version_code_str);
force_set_env("CLANG_EXEC", clang_path);
force_set_env("CLANG_OPTIONS", clang_opt);
force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 5ef90be..ad79297 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -25,6 +25,7 @@ static void dsos__init(struct dsos *dsos)
int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
{
+ memset(machine, 0, sizeof(*machine));
map_groups__init(&machine->kmaps, machine);
RB_CLEAR_NODE(&machine->rb_node);
dsos__init(&machine->dsos);
@@ -44,6 +45,8 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->comm_exec = false;
machine->kernel_start = 0;
+ memset(machine->vmlinux_maps, 0, sizeof(machine->vmlinux_maps));
+
machine->root_dir = strdup(root_dir);
if (machine->root_dir == NULL)
return -ENOMEM;
@@ -91,6 +94,7 @@ static void dsos__purge(struct dsos *dsos)
list_for_each_entry_safe(pos, n, &dsos->head, node) {
RB_CLEAR_NODE(&pos->rb_node);
+ pos->root = NULL;
list_del_init(&pos->node);
dso__put(pos);
}
@@ -121,6 +125,7 @@ void machine__delete_threads(struct machine *machine)
void machine__exit(struct machine *machine)
{
+ machine__destroy_kernel_maps(machine);
map_groups__exit(&machine->kmaps);
dsos__exit(&machine->dsos);
machine__exit_vdso(machine);
@@ -347,13 +352,18 @@ static void machine__update_thread_pid(struct machine *machine,
}
th->mg = map_groups__get(leader->mg);
-
+out_put:
+ thread__put(leader);
return;
-
out_err:
pr_err("Failed to join map groups for %d:%d\n", th->pid_, th->tid);
+ goto out_put;
}
+/*
+ * Caller must eventually drop thread->refcnt returned with a successfull
+ * lookup/new thread inserted.
+ */
static struct thread *____machine__findnew_thread(struct machine *machine,
pid_t pid, pid_t tid,
bool create)
@@ -371,7 +381,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
if (th != NULL) {
if (th->tid == tid) {
machine__update_thread_pid(machine, th, pid);
- return th;
+ return thread__get(th);
}
machine->last_match = NULL;
@@ -384,7 +394,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
if (th->tid == tid) {
machine->last_match = th;
machine__update_thread_pid(machine, th, pid);
- return th;
+ return thread__get(th);
}
if (tid < th->tid)
@@ -412,7 +422,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine,
if (thread__init_map_groups(th, machine)) {
rb_erase_init(&th->rb_node, &machine->threads);
RB_CLEAR_NODE(&th->rb_node);
- thread__delete(th);
+ thread__put(th);
return NULL;
}
/*
@@ -436,7 +446,7 @@ struct thread *machine__findnew_thread(struct machine *machine, pid_t pid,
struct thread *th;
pthread_rwlock_wrlock(&machine->threads_lock);
- th = thread__get(__machine__findnew_thread(machine, pid, tid));
+ th = __machine__findnew_thread(machine, pid, tid);
pthread_rwlock_unlock(&machine->threads_lock);
return th;
}
@@ -446,7 +456,7 @@ struct thread *machine__find_thread(struct machine *machine, pid_t pid,
{
struct thread *th;
pthread_rwlock_rdlock(&machine->threads_lock);
- th = thread__get(____machine__findnew_thread(machine, pid, tid, false));
+ th = ____machine__findnew_thread(machine, pid, tid, false);
pthread_rwlock_unlock(&machine->threads_lock);
return th;
}
@@ -559,11 +569,29 @@ int machine__process_switch_event(struct machine *machine __maybe_unused,
return 0;
}
+static void dso__adjust_kmod_long_name(struct dso *dso, const char *filename)
+{
+ const char *dup_filename;
+
+ if (!filename || !dso || !dso->long_name)
+ return;
+ if (dso->long_name[0] != '[')
+ return;
+ if (!strchr(filename, '/'))
+ return;
+
+ dup_filename = strdup(filename);
+ if (!dup_filename)
+ return;
+
+ dso__set_long_name(dso, dup_filename, true);
+}
+
struct map *machine__findnew_module_map(struct machine *machine, u64 start,
const char *filename)
{
struct map *map = NULL;
- struct dso *dso;
+ struct dso *dso = NULL;
struct kmod_path m;
if (kmod_path__parse_name(&m, filename))
@@ -571,8 +599,15 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
map = map_groups__find_by_name(&machine->kmaps, MAP__FUNCTION,
m.name);
- if (map)
+ if (map) {
+ /*
+ * If the map's dso is an offline module, give dso__load()
+ * a chance to find the file path of that module by fixing
+ * long_name.
+ */
+ dso__adjust_kmod_long_name(map->dso, filename);
goto out;
+ }
dso = machine__findnew_module_dso(machine, &m, filename);
if (dso == NULL)
@@ -584,7 +619,11 @@ struct map *machine__findnew_module_map(struct machine *machine, u64 start,
map_groups__insert(&machine->kmaps, map);
+ /* Put the map here because map_groups__insert alread got it */
+ map__put(map);
out:
+ /* put the dso here, corresponding to machine__findnew_module_dso */
+ dso__put(dso);
free(m.name);
return map;
}
@@ -739,6 +778,9 @@ int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
enum map_type type;
u64 start = machine__get_running_kernel_start(machine, NULL);
+ /* In case of renewal the kernel map, destroy previous one */
+ machine__destroy_kernel_maps(machine);
+
for (type = 0; type < MAP__NR_TYPES; ++type) {
struct kmap *kmap;
struct map *map;
@@ -787,6 +829,7 @@ void machine__destroy_kernel_maps(struct machine *machine)
kmap->ref_reloc_sym = NULL;
}
+ map__put(machine->vmlinux_maps[type]);
machine->vmlinux_maps[type] = NULL;
}
}
@@ -1083,11 +1126,14 @@ int machine__create_kernel_maps(struct machine *machine)
struct dso *kernel = machine__get_kernel(machine);
const char *name;
u64 addr = machine__get_running_kernel_start(machine, &name);
- if (!addr)
+ int ret;
+
+ if (!addr || kernel == NULL)
return -1;
- if (kernel == NULL ||
- __machine__create_kernel_maps(machine, kernel) < 0)
+ ret = __machine__create_kernel_maps(machine, kernel);
+ dso__put(kernel);
+ if (ret < 0)
return -1;
if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
@@ -1608,6 +1654,8 @@ static int add_callchain_ip(struct thread *thread,
}
}
+ if (symbol_conf.hide_unresolved && al.sym == NULL)
+ return 0;
return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
}
@@ -1862,6 +1910,9 @@ check_calls:
static int unwind_entry(struct unwind_entry *entry, void *arg)
{
struct callchain_cursor *cursor = arg;
+
+ if (symbol_conf.hide_unresolved && entry->sym == NULL)
+ return 0;
return callchain_cursor_append(cursor, entry->ip,
entry->map, entry->sym);
}
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 4e38c39..171b6d1 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -26,8 +26,8 @@ const char *map_type__name[MAP__NR_TYPES] = {
static inline int is_anon_memory(const char *filename)
{
return !strcmp(filename, "//anon") ||
- !strcmp(filename, "/dev/zero (deleted)") ||
- !strcmp(filename, "/anon_hugepage (deleted)");
+ !strncmp(filename, "/dev/zero", sizeof("/dev/zero") - 1) ||
+ !strncmp(filename, "/anon_hugepage", sizeof("/anon_hugepage") - 1);
}
static inline int is_no_dso_memory(const char *filename)
@@ -644,6 +644,12 @@ size_t map_groups__fprintf(struct map_groups *mg, FILE *fp)
return printed;
}
+static void __map_groups__insert(struct map_groups *mg, struct map *map)
+{
+ __maps__insert(&mg->maps[map->type], map);
+ map->groups = mg;
+}
+
static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp)
{
struct rb_root *root;
@@ -682,9 +688,10 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
}
before->end = map->start;
- __maps__insert(maps, before);
+ __map_groups__insert(pos->groups, before);
if (verbose >= 2)
map__fprintf(before, fp);
+ map__put(before);
}
if (map->end < pos->end) {
@@ -696,9 +703,10 @@ static int maps__fixup_overlappings(struct maps *maps, struct map *map, FILE *fp
}
after->start = map->end;
- __maps__insert(maps, after);
+ __map_groups__insert(pos->groups, after);
if (verbose >= 2)
map__fprintf(after, fp);
+ map__put(after);
}
put_map:
map__put(pos);
@@ -736,6 +744,7 @@ int map_groups__clone(struct map_groups *mg,
if (new == NULL)
goto out_unlock;
map_groups__insert(mg, new);
+ map__put(new);
}
err = 0;
diff --git a/tools/perf/util/parse-branch-options.c b/tools/perf/util/parse-branch-options.c
index 355eecf..afc088d 100644
--- a/tools/perf/util/parse-branch-options.c
+++ b/tools/perf/util/parse-branch-options.c
@@ -1,7 +1,7 @@
#include "perf.h"
#include "util/util.h"
#include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-branch-options.h"
#define BRANCH_OPT(n, m) \
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index bee6058..4f7b0ef 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -4,9 +4,9 @@
#include "../perf.h"
#include "evlist.h"
#include "evsel.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "parse-events.h"
-#include "exec_cmd.h"
+#include <subcmd/exec-cmd.h>
#include "string.h"
#include "symbol.h"
#include "cache.h"
@@ -124,6 +124,10 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = {
.symbol = "dummy",
.alias = "",
},
+ [PERF_COUNT_SW_BPF_OUTPUT] = {
+ .symbol = "bpf-output",
+ .alias = "",
+ },
};
#define __PERF_EVENT_FIELD(config, name) \
@@ -632,19 +636,20 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
struct bpf_object *obj;
obj = bpf__prepare_load(bpf_file_name, source);
- if (IS_ERR(obj) || !obj) {
+ if (IS_ERR(obj)) {
char errbuf[BUFSIZ];
int err;
- err = obj ? PTR_ERR(obj) : -EINVAL;
+ err = PTR_ERR(obj);
if (err == -ENOTSUP)
snprintf(errbuf, sizeof(errbuf),
"BPF support is not compiled");
else
- snprintf(errbuf, sizeof(errbuf),
- "BPF object file '%s' is invalid",
- bpf_file_name);
+ bpf__strerror_prepare_load(bpf_file_name,
+ source,
+ -err, errbuf,
+ sizeof(errbuf));
data->error->help = strdup("(add -v to see detail)");
data->error->str = strdup(errbuf);
@@ -1878,7 +1883,7 @@ restart:
for (i = 0; i < max; i++, syms++) {
- if (event_glob != NULL &&
+ if (event_glob != NULL && syms->symbol != NULL &&
!(strglobmatch(syms->symbol, event_glob) ||
(syms->alias && strglobmatch(syms->alias, event_glob))))
continue;
diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c
index 4f2c1c2..646ecf7 100644
--- a/tools/perf/util/parse-regs-options.c
+++ b/tools/perf/util/parse-regs-options.c
@@ -1,7 +1,7 @@
#include "perf.h"
#include "util/util.h"
#include "util/debug.h"
-#include "util/parse-options.h"
+#include <subcmd/parse-options.h>
#include "util/parse-regs-options.h"
int
diff --git a/tools/perf/util/path.c b/tools/perf/util/path.c
index 5d13cb4..3654d96 100644
--- a/tools/perf/util/path.c
+++ b/tools/perf/util/path.c
@@ -22,24 +22,6 @@ static const char *get_perf_dir(void)
return ".";
}
-/*
- * If libc has strlcpy() then that version will override this
- * implementation:
- */
-size_t __weak strlcpy(char *dest, const char *src, size_t size)
-{
- size_t ret = strlen(src);
-
- if (size) {
- size_t len = (ret >= size) ? size - 1 : ret;
-
- memcpy(dest, src, len);
- dest[len] = '\0';
- }
-
- return ret;
-}
-
static char *get_pathname(void)
{
static char pathname_array[4][PATH_MAX];
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e4b173d..b597bcc 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -220,6 +220,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name,
alias->scale = 1.0;
alias->unit[0] = '\0';
alias->per_pkg = false;
+ alias->snapshot = false;
ret = parse_events_terms(&alias->terms, val);
if (ret) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index b51a8bf..93996ec 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1895,9 +1895,8 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
sym = map__find_symbol(map, addr, NULL);
} else {
if (tp->symbol && !addr) {
- ret = kernel_get_symbol_address_by_name(tp->symbol,
- &addr, true, false);
- if (ret < 0)
+ if (kernel_get_symbol_address_by_name(tp->symbol,
+ &addr, true, false) < 0)
goto out;
}
if (addr) {
@@ -1905,6 +1904,7 @@ static int find_perf_probe_point_from_map(struct probe_trace_point *tp,
sym = __find_kernel_function(addr, &map);
}
}
+
if (!sym)
goto out;
@@ -2326,8 +2326,11 @@ static int get_new_event_name(char *buf, size_t len, const char *base,
goto out;
if (!allow_suffix) {
- pr_warning("Error: event \"%s\" already exists. "
- "(Use -f to force duplicates.)\n", buf);
+ pr_warning("Error: event \"%s\" already exists.\n"
+ " Hint: Remove existing event by 'perf probe -d'\n"
+ " or force duplicates by 'perf probe -f'\n"
+ " or set 'force=yes' in BPF source.\n",
+ buf);
ret = -EEXIST;
goto out;
}
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index 89dbeb9..e3b3b92 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -138,6 +138,9 @@ struct strlist *probe_file__get_rawlist(int fd)
char *p;
struct strlist *sl;
+ if (fd < 0)
+ return NULL;
+
sl = strlist__new(NULL, NULL);
fp = fdopen(dup(fd), "r");
@@ -271,6 +274,9 @@ int probe_file__get_events(int fd, struct strfilter *filter,
const char *p;
int ret = -ENOENT;
+ if (!plist)
+ return -EINVAL;
+
namelist = __probe_file__get_namelist(fd, true);
if (!namelist)
return -ENOENT;
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index bd8f03d..2be10fb 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -654,6 +654,7 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwfl_Module *mod,
static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
{
Dwarf_Attribute fb_attr;
+ Dwarf_Frame *frame = NULL;
size_t nops;
int ret;
@@ -686,11 +687,11 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
#if _ELFUTILS_PREREQ(0, 142)
} else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa &&
pf->cfi != NULL) {
- Dwarf_Frame *frame;
if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 ||
dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) {
pr_warning("Failed to get call frame on 0x%jx\n",
(uintmax_t)pf->addr);
+ free(frame);
return -ENOENT;
}
#endif
@@ -699,7 +700,8 @@ static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
/* Call finder's callback handler */
ret = pf->callback(sc_die, pf);
- /* *pf->fb_ops will be cached in libdw. Don't free it. */
+ /* Since *pf->fb_ops can be a part of frame. we should free it here. */
+ free(frame);
pf->fb_ops = NULL;
return ret;
@@ -1183,7 +1185,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
container_of(pf, struct trace_event_finder, pf);
struct perf_probe_point *pp = &pf->pev->point;
struct probe_trace_event *tev;
- struct perf_probe_arg *args;
+ struct perf_probe_arg *args = NULL;
int ret, i;
/* Check number of tevs */
@@ -1198,19 +1200,23 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
ret = convert_to_trace_point(&pf->sp_die, tf->mod, pf->addr,
pp->retprobe, pp->function, &tev->point);
if (ret < 0)
- return ret;
+ goto end;
tev->point.realname = strdup(dwarf_diename(sc_die));
- if (!tev->point.realname)
- return -ENOMEM;
+ if (!tev->point.realname) {
+ ret = -ENOMEM;
+ goto end;
+ }
pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
tev->point.offset);
/* Expand special probe argument if exist */
args = zalloc(sizeof(struct perf_probe_arg) * MAX_PROBE_ARGS);
- if (args == NULL)
- return -ENOMEM;
+ if (args == NULL) {
+ ret = -ENOMEM;
+ goto end;
+ }
ret = expand_probe_args(sc_die, pf, args);
if (ret < 0)
@@ -1234,6 +1240,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
}
end:
+ if (ret) {
+ clear_probe_trace_event(tev);
+ tf->ntevs--;
+ }
free(args);
return ret;
}
@@ -1246,7 +1256,7 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
struct trace_event_finder tf = {
.pf = {.pev = pev, .callback = add_probe_trace_event},
.max_tevs = probe_conf.max_probes, .mod = dbg->mod};
- int ret;
+ int ret, i;
/* Allocate result tevs array */
*tevs = zalloc(sizeof(struct probe_trace_event) * tf.max_tevs);
@@ -1258,6 +1268,8 @@ int debuginfo__find_trace_events(struct debuginfo *dbg,
ret = debuginfo__find_probes(dbg, &tf.pf);
if (ret < 0) {
+ for (i = 0; i < tf.ntevs; i++)
+ clear_probe_trace_event(&tf.tevs[i]);
zfree(tevs);
return ret;
}
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources
index 51be28b..8162ba0 100644
--- a/tools/perf/util/python-ext-sources
+++ b/tools/perf/util/python-ext-sources
@@ -10,6 +10,8 @@ util/ctype.c
util/evlist.c
util/evsel.c
util/cpumap.c
+../lib/bitmap.c
+../lib/find_bit.c
../lib/hweight.c
util/thread_map.c
util/util.c
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index a8e825f..d72fafc 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -41,6 +41,9 @@
#include "../thread-stack.h"
#include "../trace-event.h"
#include "../machine.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "stat.h"
PyMODINIT_FUNC initperf_trace_context(void);
@@ -859,6 +862,104 @@ static void python_process_event(union perf_event *event,
}
}
+static void get_handler_name(char *str, size_t size,
+ struct perf_evsel *evsel)
+{
+ char *p = str;
+
+ scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
+
+ while ((p = strchr(p, ':'))) {
+ *p = '_';
+ p++;
+ }
+}
+
+static void
+process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp,
+ struct perf_counts_values *count)
+{
+ PyObject *handler, *t;
+ static char handler_name[256];
+ int n = 0;
+
+ t = PyTuple_New(MAX_FIELDS);
+ if (!t)
+ Py_FatalError("couldn't create Python tuple");
+
+ get_handler_name(handler_name, sizeof(handler_name),
+ counter);
+
+ handler = get_handler(handler_name);
+ if (!handler) {
+ pr_debug("can't find python handler %s\n", handler_name);
+ return;
+ }
+
+ PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
+ PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
+
+ tuple_set_u64(t, n++, tstamp);
+ tuple_set_u64(t, n++, count->val);
+ tuple_set_u64(t, n++, count->ena);
+ tuple_set_u64(t, n++, count->run);
+
+ if (_PyTuple_Resize(&t, n) == -1)
+ Py_FatalError("error resizing Python tuple");
+
+ call_object(handler, t, handler_name);
+
+ Py_DECREF(t);
+}
+
+static void python_process_stat(struct perf_stat_config *config,
+ struct perf_evsel *counter, u64 tstamp)
+{
+ struct thread_map *threads = counter->threads;
+ struct cpu_map *cpus = counter->cpus;
+ int cpu, thread;
+
+ if (config->aggr_mode == AGGR_GLOBAL) {
+ process_stat(counter, -1, -1, tstamp,
+ &counter->counts->aggr);
+ return;
+ }
+
+ for (thread = 0; thread < threads->nr; thread++) {
+ for (cpu = 0; cpu < cpus->nr; cpu++) {
+ process_stat(counter, cpus->map[cpu],
+ thread_map__pid(threads, thread), tstamp,
+ perf_counts(counter->counts, cpu, thread));
+ }
+ }
+}
+
+static void python_process_stat_interval(u64 tstamp)
+{
+ PyObject *handler, *t;
+ static const char handler_name[] = "stat__interval";
+ int n = 0;
+
+ t = PyTuple_New(MAX_FIELDS);
+ if (!t)
+ Py_FatalError("couldn't create Python tuple");
+
+ handler = get_handler(handler_name);
+ if (!handler) {
+ pr_debug("can't find python handler %s\n", handler_name);
+ return;
+ }
+
+ tuple_set_u64(t, n++, tstamp);
+
+ if (_PyTuple_Resize(&t, n) == -1)
+ Py_FatalError("error resizing Python tuple");
+
+ call_object(handler, t, handler_name);
+
+ Py_DECREF(t);
+}
+
static int run_start_sub(void)
{
main_module = PyImport_AddModule("__main__");
@@ -1201,10 +1302,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
}
struct scripting_ops python_scripting_ops = {
- .name = "Python",
- .start_script = python_start_script,
- .flush_script = python_flush_script,
- .stop_script = python_stop_script,
- .process_event = python_process_event,
- .generate_script = python_generate_script,
+ .name = "Python",
+ .start_script = python_start_script,
+ .flush_script = python_flush_script,
+ .stop_script = python_stop_script,
+ .process_event = python_process_event,
+ .process_stat = python_process_stat,
+ .process_stat_interval = python_process_stat_interval,
+ .generate_script = python_generate_script,
};
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 428149b..d5636ba 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -17,6 +17,7 @@
#include "asm/bug.h"
#include "auxtrace.h"
#include "thread-stack.h"
+#include "stat.h"
static int perf_session__deliver_event(struct perf_session *session,
union perf_event *event,
@@ -29,25 +30,28 @@ static int perf_session__open(struct perf_session *session)
struct perf_data_file *file = session->file;
if (perf_session__read_header(session) < 0) {
- pr_err("incompatible file format (rerun with -v to learn more)");
+ pr_err("incompatible file format (rerun with -v to learn more)\n");
return -1;
}
if (perf_data_file__is_pipe(file))
return 0;
+ if (perf_header__has_feat(&session->header, HEADER_STAT))
+ return 0;
+
if (!perf_evlist__valid_sample_type(session->evlist)) {
- pr_err("non matching sample_type");
+ pr_err("non matching sample_type\n");
return -1;
}
if (!perf_evlist__valid_sample_id_all(session->evlist)) {
- pr_err("non matching sample_id_all");
+ pr_err("non matching sample_id_all\n");
return -1;
}
if (!perf_evlist__valid_read_format(session->evlist)) {
- pr_err("non matching read_format");
+ pr_err("non matching read_format\n");
return -1;
}
@@ -205,6 +209,18 @@ static int process_event_synth_attr_stub(struct perf_tool *tool __maybe_unused,
return 0;
}
+static int process_event_synth_event_update_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_evlist **pevlist
+ __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_event_update(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
static int process_event_sample_stub(struct perf_tool *tool __maybe_unused,
union perf_event *event __maybe_unused,
struct perf_sample *sample __maybe_unused,
@@ -296,6 +312,67 @@ int process_event_auxtrace_error_stub(struct perf_tool *tool __maybe_unused,
return 0;
}
+
+static
+int process_event_thread_map_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_thread_map(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
+static
+int process_event_cpu_map_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_cpu_map(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
+static
+int process_event_stat_config_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *session __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_stat_config(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
+static int process_stat_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *perf_session
+ __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_stat(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
+static int process_stat_round_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *perf_session
+ __maybe_unused)
+{
+ if (dump_trace)
+ perf_event__fprintf_stat_round(event, stdout);
+
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -328,6 +405,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->unthrottle = process_event_stub;
if (tool->attr == NULL)
tool->attr = process_event_synth_attr_stub;
+ if (tool->event_update == NULL)
+ tool->event_update = process_event_synth_event_update_stub;
if (tool->tracing_data == NULL)
tool->tracing_data = process_event_synth_tracing_data_stub;
if (tool->build_id == NULL)
@@ -346,6 +425,16 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
tool->auxtrace = process_event_auxtrace_stub;
if (tool->auxtrace_error == NULL)
tool->auxtrace_error = process_event_auxtrace_error_stub;
+ if (tool->thread_map == NULL)
+ tool->thread_map = process_event_thread_map_stub;
+ if (tool->cpu_map == NULL)
+ tool->cpu_map = process_event_cpu_map_stub;
+ if (tool->stat_config == NULL)
+ tool->stat_config = process_event_stat_config_stub;
+ if (tool->stat == NULL)
+ tool->stat = process_stat_stub;
+ if (tool->stat_round == NULL)
+ tool->stat_round = process_stat_round_stub;
}
static void swap_sample_id_all(union perf_event *event, void *data)
@@ -569,6 +658,13 @@ static void perf_event__hdr_attr_swap(union perf_event *event,
mem_bswap_64(event->attr.id, size);
}
+static void perf_event__event_update_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ event->event_update.type = bswap_64(event->event_update.type);
+ event->event_update.id = bswap_64(event->event_update.id);
+}
+
static void perf_event__event_type_swap(union perf_event *event,
bool sample_id_all __maybe_unused)
{
@@ -616,6 +712,81 @@ static void perf_event__auxtrace_error_swap(union perf_event *event,
event->auxtrace_error.ip = bswap_64(event->auxtrace_error.ip);
}
+static void perf_event__thread_map_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ unsigned i;
+
+ event->thread_map.nr = bswap_64(event->thread_map.nr);
+
+ for (i = 0; i < event->thread_map.nr; i++)
+ event->thread_map.entries[i].pid = bswap_64(event->thread_map.entries[i].pid);
+}
+
+static void perf_event__cpu_map_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ struct cpu_map_data *data = &event->cpu_map.data;
+ struct cpu_map_entries *cpus;
+ struct cpu_map_mask *mask;
+ unsigned i;
+
+ data->type = bswap_64(data->type);
+
+ switch (data->type) {
+ case PERF_CPU_MAP__CPUS:
+ cpus = (struct cpu_map_entries *)data->data;
+
+ cpus->nr = bswap_16(cpus->nr);
+
+ for (i = 0; i < cpus->nr; i++)
+ cpus->cpu[i] = bswap_16(cpus->cpu[i]);
+ break;
+ case PERF_CPU_MAP__MASK:
+ mask = (struct cpu_map_mask *) data->data;
+
+ mask->nr = bswap_16(mask->nr);
+ mask->long_size = bswap_16(mask->long_size);
+
+ switch (mask->long_size) {
+ case 4: mem_bswap_32(&mask->mask, mask->nr); break;
+ case 8: mem_bswap_64(&mask->mask, mask->nr); break;
+ default:
+ pr_err("cpu_map swap: unsupported long size\n");
+ }
+ default:
+ break;
+ }
+}
+
+static void perf_event__stat_config_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ u64 size;
+
+ size = event->stat_config.nr * sizeof(event->stat_config.data[0]);
+ size += 1; /* nr item itself */
+ mem_bswap_64(&event->stat_config.nr, size);
+}
+
+static void perf_event__stat_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ event->stat.id = bswap_64(event->stat.id);
+ event->stat.thread = bswap_32(event->stat.thread);
+ event->stat.cpu = bswap_32(event->stat.cpu);
+ event->stat.val = bswap_64(event->stat.val);
+ event->stat.ena = bswap_64(event->stat.ena);
+ event->stat.run = bswap_64(event->stat.run);
+}
+
+static void perf_event__stat_round_swap(union perf_event *event,
+ bool sample_id_all __maybe_unused)
+{
+ event->stat_round.type = bswap_64(event->stat_round.type);
+ event->stat_round.time = bswap_64(event->stat_round.time);
+}
+
typedef void (*perf_event__swap_op)(union perf_event *event,
bool sample_id_all);
@@ -643,6 +814,12 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_AUXTRACE_INFO] = perf_event__auxtrace_info_swap,
[PERF_RECORD_AUXTRACE] = perf_event__auxtrace_swap,
[PERF_RECORD_AUXTRACE_ERROR] = perf_event__auxtrace_error_swap,
+ [PERF_RECORD_THREAD_MAP] = perf_event__thread_map_swap,
+ [PERF_RECORD_CPU_MAP] = perf_event__cpu_map_swap,
+ [PERF_RECORD_STAT_CONFIG] = perf_event__stat_config_swap,
+ [PERF_RECORD_STAT] = perf_event__stat_swap,
+ [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap,
+ [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};
@@ -1154,6 +1331,8 @@ static s64 perf_session__process_user_event(struct perf_session *session,
perf_session__set_comm_exec(session);
}
return err;
+ case PERF_RECORD_EVENT_UPDATE:
+ return tool->event_update(tool, event, &session->evlist);
case PERF_RECORD_HEADER_EVENT_TYPE:
/*
* Depreceated, but we need to handle it for sake
@@ -1179,6 +1358,16 @@ static s64 perf_session__process_user_event(struct perf_session *session,
case PERF_RECORD_AUXTRACE_ERROR:
perf_session__auxtrace_error_inc(session, event);
return tool->auxtrace_error(tool, event, session);
+ case PERF_RECORD_THREAD_MAP:
+ return tool->thread_map(tool, event, session);
+ case PERF_RECORD_CPU_MAP:
+ return tool->cpu_map(tool, event, session);
+ case PERF_RECORD_STAT_CONFIG:
+ return tool->stat_config(tool, event, session);
+ case PERF_RECORD_STAT:
+ return tool->stat(tool, event, session);
+ case PERF_RECORD_STAT_ROUND:
+ return tool->stat_round(tool, event, session);
default:
return -EINVAL;
}
@@ -1311,17 +1500,20 @@ struct thread *perf_session__findnew(struct perf_session *session, pid_t pid)
return machine__findnew_thread(&session->machines.host, -1, pid);
}
-struct thread *perf_session__register_idle_thread(struct perf_session *session)
+int perf_session__register_idle_thread(struct perf_session *session)
{
struct thread *thread;
+ int err = 0;
thread = machine__findnew_thread(&session->machines.host, 0, 0);
if (thread == NULL || thread__set_comm(thread, "swapper", 0)) {
pr_err("problem inserting idle task.\n");
- thread = NULL;
+ err = -1;
}
- return thread;
+ /* machine__findnew_thread() got the thread, so put it */
+ thread__put(thread);
+ return err;
}
static void perf_session__warn_about_errors(const struct perf_session *session)
@@ -1676,7 +1868,7 @@ int perf_session__process_events(struct perf_session *session)
u64 size = perf_data_file__size(session->file);
int err;
- if (perf_session__register_idle_thread(session) == NULL)
+ if (perf_session__register_idle_thread(session) < 0)
return -ENOMEM;
if (!perf_data_file__is_pipe(session->file))
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 3e900c0..5f792e3 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -89,7 +89,7 @@ struct machine *perf_session__findnew_machine(struct perf_session *session, pid_
}
struct thread *perf_session__findnew(struct perf_session *session, pid_t pid);
-struct thread *perf_session__register_idle_thread(struct perf_session *session);
+int perf_session__register_idle_thread(struct perf_session *session);
size_t perf_session__fprintf(struct perf_session *session, FILE *fp);
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 2d8ccd4..ec72234 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -4,6 +4,8 @@
#include "comm.h"
#include "symbol.h"
#include "evsel.h"
+#include "evlist.h"
+#include <traceevent/event-parse.h>
regex_t parent_regex;
const char default_parent_pattern[] = "^sys_|^do_page_fault";
@@ -13,6 +15,7 @@ const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cy
const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
const char default_top_sort_order[] = "dso,symbol";
const char default_diff_sort_order[] = "dso,symbol";
+const char default_tracepoint_sort_order[] = "trace";
const char *sort_order;
const char *field_order;
regex_t ignore_callees_regex;
@@ -443,6 +446,70 @@ struct sort_entry sort_socket = {
.se_width_idx = HISTC_SOCKET,
};
+/* --sort trace */
+
+static char *get_trace_output(struct hist_entry *he)
+{
+ struct trace_seq seq;
+ struct perf_evsel *evsel;
+ struct pevent_record rec = {
+ .data = he->raw_data,
+ .size = he->raw_size,
+ };
+
+ evsel = hists_to_evsel(he->hists);
+
+ trace_seq_init(&seq);
+ if (symbol_conf.raw_trace) {
+ pevent_print_fields(&seq, he->raw_data, he->raw_size,
+ evsel->tp_format);
+ } else {
+ pevent_event_info(&seq, evsel->tp_format, &rec);
+ }
+ return seq.buffer;
+}
+
+static int64_t
+sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+ struct perf_evsel *evsel;
+
+ evsel = hists_to_evsel(left->hists);
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+ return 0;
+
+ if (left->trace_output == NULL)
+ left->trace_output = get_trace_output(left);
+ if (right->trace_output == NULL)
+ right->trace_output = get_trace_output(right);
+
+ hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output));
+ hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output));
+
+ return strcmp(right->trace_output, left->trace_output);
+}
+
+static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
+ size_t size, unsigned int width)
+{
+ struct perf_evsel *evsel;
+
+ evsel = hists_to_evsel(he->hists);
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+ return scnprintf(bf, size, "%-*.*s", width, width, "N/A");
+
+ if (he->trace_output == NULL)
+ he->trace_output = get_trace_output(he);
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output);
+}
+
+struct sort_entry sort_trace = {
+ .se_header = "Trace output",
+ .se_cmp = sort__trace_cmp,
+ .se_snprintf = hist_entry__trace_snprintf,
+ .se_width_idx = HISTC_TRACE,
+};
+
/* sort keys for branch stacks */
static int64_t
@@ -1312,6 +1379,7 @@ static struct sort_dimension common_sort_dimensions[] = {
DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
DIM(SORT_TRANSACTION, "transaction", sort_transaction),
+ DIM(SORT_TRACE, "trace", sort_trace),
};
#undef DIM
@@ -1529,6 +1597,455 @@ static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
return 0;
}
+struct hpp_dynamic_entry {
+ struct perf_hpp_fmt hpp;
+ struct perf_evsel *evsel;
+ struct format_field *field;
+ unsigned dynamic_len;
+ bool raw_trace;
+};
+
+static int hde_width(struct hpp_dynamic_entry *hde)
+{
+ if (!hde->hpp.len) {
+ int len = hde->dynamic_len;
+ int namelen = strlen(hde->field->name);
+ int fieldlen = hde->field->size;
+
+ if (namelen > len)
+ len = namelen;
+
+ if (!(hde->field->flags & FIELD_IS_STRING)) {
+ /* length for print hex numbers */
+ fieldlen = hde->field->size * 2 + 2;
+ }
+ if (fieldlen > len)
+ len = fieldlen;
+
+ hde->hpp.len = len;
+ }
+ return hde->hpp.len;
+}
+
+static void update_dynamic_len(struct hpp_dynamic_entry *hde,
+ struct hist_entry *he)
+{
+ char *str, *pos;
+ struct format_field *field = hde->field;
+ size_t namelen;
+ bool last = false;
+
+ if (hde->raw_trace)
+ return;
+
+ /* parse pretty print result and update max length */
+ if (!he->trace_output)
+ he->trace_output = get_trace_output(he);
+
+ namelen = strlen(field->name);
+ str = he->trace_output;
+
+ while (str) {
+ pos = strchr(str, ' ');
+ if (pos == NULL) {
+ last = true;
+ pos = str + strlen(str);
+ }
+
+ if (!strncmp(str, field->name, namelen)) {
+ size_t len;
+
+ str += namelen + 1;
+ len = pos - str;
+
+ if (len > hde->dynamic_len)
+ hde->dynamic_len = len;
+ break;
+ }
+
+ if (last)
+ str = NULL;
+ else
+ str = pos + 1;
+ }
+}
+
+static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct perf_evsel *evsel __maybe_unused)
+{
+ struct hpp_dynamic_entry *hde;
+ size_t len = fmt->user_len;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+ if (!len)
+ len = hde_width(hde);
+
+ return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
+}
+
+static int __sort__hde_width(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp __maybe_unused,
+ struct perf_evsel *evsel __maybe_unused)
+{
+ struct hpp_dynamic_entry *hde;
+ size_t len = fmt->user_len;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+ if (!len)
+ len = hde_width(hde);
+
+ return len;
+}
+
+bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
+{
+ struct hpp_dynamic_entry *hde;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+ return hists_to_evsel(hists) == hde->evsel;
+}
+
+static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
+ struct hist_entry *he)
+{
+ struct hpp_dynamic_entry *hde;
+ size_t len = fmt->user_len;
+ char *str, *pos;
+ struct format_field *field;
+ size_t namelen;
+ bool last = false;
+ int ret;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+ if (!len)
+ len = hde_width(hde);
+
+ if (hde->raw_trace)
+ goto raw_field;
+
+ field = hde->field;
+ namelen = strlen(field->name);
+ str = he->trace_output;
+
+ while (str) {
+ pos = strchr(str, ' ');
+ if (pos == NULL) {
+ last = true;
+ pos = str + strlen(str);
+ }
+
+ if (!strncmp(str, field->name, namelen)) {
+ str += namelen + 1;
+ str = strndup(str, pos - str);
+
+ if (str == NULL)
+ return scnprintf(hpp->buf, hpp->size,
+ "%*.*s", len, len, "ERROR");
+ break;
+ }
+
+ if (last)
+ str = NULL;
+ else
+ str = pos + 1;
+ }
+
+ if (str == NULL) {
+ struct trace_seq seq;
+raw_field:
+ trace_seq_init(&seq);
+ pevent_print_field(&seq, he->raw_data, hde->field);
+ str = seq.buffer;
+ }
+
+ ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
+ free(str);
+ return ret;
+}
+
+static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
+ struct hist_entry *a, struct hist_entry *b)
+{
+ struct hpp_dynamic_entry *hde;
+ struct format_field *field;
+ unsigned offset, size;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+
+ field = hde->field;
+ if (field->flags & FIELD_IS_DYNAMIC) {
+ unsigned long long dyn;
+
+ pevent_read_number_field(field, a->raw_data, &dyn);
+ offset = dyn & 0xffff;
+ size = (dyn >> 16) & 0xffff;
+
+ /* record max width for output */
+ if (size > hde->dynamic_len)
+ hde->dynamic_len = size;
+ } else {
+ offset = field->offset;
+ size = field->size;
+
+ update_dynamic_len(hde, a);
+ update_dynamic_len(hde, b);
+ }
+
+ return memcmp(a->raw_data + offset, b->raw_data + offset, size);
+}
+
+bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
+{
+ return fmt->cmp == __sort__hde_cmp;
+}
+
+static struct hpp_dynamic_entry *
+__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
+{
+ struct hpp_dynamic_entry *hde;
+
+ hde = malloc(sizeof(*hde));
+ if (hde == NULL) {
+ pr_debug("Memory allocation failed\n");
+ return NULL;
+ }
+
+ hde->evsel = evsel;
+ hde->field = field;
+ hde->dynamic_len = 0;
+
+ hde->hpp.name = field->name;
+ hde->hpp.header = __sort__hde_header;
+ hde->hpp.width = __sort__hde_width;
+ hde->hpp.entry = __sort__hde_entry;
+ hde->hpp.color = NULL;
+
+ hde->hpp.cmp = __sort__hde_cmp;
+ hde->hpp.collapse = __sort__hde_cmp;
+ hde->hpp.sort = __sort__hde_cmp;
+
+ INIT_LIST_HEAD(&hde->hpp.list);
+ INIT_LIST_HEAD(&hde->hpp.sort_list);
+ hde->hpp.elide = false;
+ hde->hpp.len = 0;
+ hde->hpp.user_len = 0;
+
+ return hde;
+}
+
+static int parse_field_name(char *str, char **event, char **field, char **opt)
+{
+ char *event_name, *field_name, *opt_name;
+
+ event_name = str;
+ field_name = strchr(str, '.');
+
+ if (field_name) {
+ *field_name++ = '\0';
+ } else {
+ event_name = NULL;
+ field_name = str;
+ }
+
+ opt_name = strchr(field_name, '/');
+ if (opt_name)
+ *opt_name++ = '\0';
+
+ *event = event_name;
+ *field = field_name;
+ *opt = opt_name;
+
+ return 0;
+}
+
+/* find match evsel using a given event name. The event name can be:
+ * 1. '%' + event index (e.g. '%1' for first event)
+ * 2. full event name (e.g. sched:sched_switch)
+ * 3. partial event name (should not contain ':')
+ */
+static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
+{
+ struct perf_evsel *evsel = NULL;
+ struct perf_evsel *pos;
+ bool full_name;
+
+ /* case 1 */
+ if (event_name[0] == '%') {
+ int nr = strtol(event_name+1, NULL, 0);
+
+ if (nr > evlist->nr_entries)
+ return NULL;
+
+ evsel = perf_evlist__first(evlist);
+ while (--nr > 0)
+ evsel = perf_evsel__next(evsel);
+
+ return evsel;
+ }
+
+ full_name = !!strchr(event_name, ':');
+ evlist__for_each(evlist, pos) {
+ /* case 2 */
+ if (full_name && !strcmp(pos->name, event_name))
+ return pos;
+ /* case 3 */
+ if (!full_name && strstr(pos->name, event_name)) {
+ if (evsel) {
+ pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
+ event_name, evsel->name, pos->name);
+ return NULL;
+ }
+ evsel = pos;
+ }
+ }
+
+ return evsel;
+}
+
+static int __dynamic_dimension__add(struct perf_evsel *evsel,
+ struct format_field *field,
+ bool raw_trace)
+{
+ struct hpp_dynamic_entry *hde;
+
+ hde = __alloc_dynamic_entry(evsel, field);
+ if (hde == NULL)
+ return -ENOMEM;
+
+ hde->raw_trace = raw_trace;
+
+ perf_hpp__register_sort_field(&hde->hpp);
+ return 0;
+}
+
+static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace)
+{
+ int ret;
+ struct format_field *field;
+
+ field = evsel->tp_format->format.fields;
+ while (field) {
+ ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ if (ret < 0)
+ return ret;
+
+ field = field->next;
+ }
+ return 0;
+}
+
+static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace)
+{
+ int ret;
+ struct perf_evsel *evsel;
+
+ evlist__for_each(evlist, evsel) {
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+ continue;
+
+ ret = add_evsel_fields(evsel, raw_trace);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static int add_all_matching_fields(struct perf_evlist *evlist,
+ char *field_name, bool raw_trace)
+{
+ int ret = -ESRCH;
+ struct perf_evsel *evsel;
+ struct format_field *field;
+
+ evlist__for_each(evlist, evsel) {
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+ continue;
+
+ field = pevent_find_any_field(evsel->tp_format, field_name);
+ if (field == NULL)
+ continue;
+
+ ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ if (ret < 0)
+ break;
+ }
+ return ret;
+}
+
+static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok)
+{
+ char *str, *event_name, *field_name, *opt_name;
+ struct perf_evsel *evsel;
+ struct format_field *field;
+ bool raw_trace = symbol_conf.raw_trace;
+ int ret = 0;
+
+ if (evlist == NULL)
+ return -ENOENT;
+
+ str = strdup(tok);
+ if (str == NULL)
+ return -ENOMEM;
+
+ if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (opt_name) {
+ if (strcmp(opt_name, "raw")) {
+ pr_debug("unsupported field option %s\n", opt_name);
+ ret = -EINVAL;
+ goto out;
+ }
+ raw_trace = true;
+ }
+
+ if (!strcmp(field_name, "trace_fields")) {
+ ret = add_all_dynamic_fields(evlist, raw_trace);
+ goto out;
+ }
+
+ if (event_name == NULL) {
+ ret = add_all_matching_fields(evlist, field_name, raw_trace);
+ goto out;
+ }
+
+ evsel = find_evsel(evlist, event_name);
+ if (evsel == NULL) {
+ pr_debug("Cannot find event: %s\n", event_name);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+ pr_debug("%s is not a tracepoint event\n", event_name);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (!strcmp(field_name, "*")) {
+ ret = add_evsel_fields(evsel, raw_trace);
+ } else {
+ field = pevent_find_any_field(evsel->tp_format, field_name);
+ if (field == NULL) {
+ pr_debug("Cannot find event field for %s.%s\n",
+ event_name, field_name);
+ return -ENOENT;
+ }
+
+ ret = __dynamic_dimension__add(evsel, field, raw_trace);
+ }
+
+out:
+ free(str);
+ return ret;
+}
+
static int __sort_dimension__add(struct sort_dimension *sd)
{
if (sd->taken)
@@ -1583,7 +2100,8 @@ int hpp_dimension__add_output(unsigned col)
return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
}
-int sort_dimension__add(const char *tok)
+static int sort_dimension__add(const char *tok,
+ struct perf_evlist *evlist __maybe_unused)
{
unsigned int i;
@@ -1664,10 +2182,13 @@ int sort_dimension__add(const char *tok)
return 0;
}
+ if (!add_dynamic_entry(evlist, tok))
+ return 0;
+
return -ESRCH;
}
-static const char *get_default_sort_order(void)
+static const char *get_default_sort_order(struct perf_evlist *evlist)
{
const char *default_sort_orders[] = {
default_sort_order,
@@ -1675,14 +2196,33 @@ static const char *get_default_sort_order(void)
default_mem_sort_order,
default_top_sort_order,
default_diff_sort_order,
+ default_tracepoint_sort_order,
};
+ bool use_trace = true;
+ struct perf_evsel *evsel;
BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
+ if (evlist == NULL)
+ goto out_no_evlist;
+
+ evlist__for_each(evlist, evsel) {
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
+ use_trace = false;
+ break;
+ }
+ }
+
+ if (use_trace) {
+ sort__mode = SORT_MODE__TRACEPOINT;
+ if (symbol_conf.raw_trace)
+ return "trace_fields";
+ }
+out_no_evlist:
return default_sort_orders[sort__mode];
}
-static int setup_sort_order(void)
+static int setup_sort_order(struct perf_evlist *evlist)
{
char *new_sort_order;
@@ -1703,7 +2243,7 @@ static int setup_sort_order(void)
* because it's checked over the rest of the code.
*/
if (asprintf(&new_sort_order, "%s,%s",
- get_default_sort_order(), sort_order + 1) < 0) {
+ get_default_sort_order(evlist), sort_order + 1) < 0) {
error("Not enough memory to set up --sort");
return -ENOMEM;
}
@@ -1712,13 +2252,41 @@ static int setup_sort_order(void)
return 0;
}
-static int __setup_sorting(void)
+/*
+ * Adds 'pre,' prefix into 'str' is 'pre' is
+ * not already part of 'str'.
+ */
+static char *prefix_if_not_in(const char *pre, char *str)
+{
+ char *n;
+
+ if (!str || strstr(str, pre))
+ return str;
+
+ if (asprintf(&n, "%s,%s", pre, str) < 0)
+ return NULL;
+
+ free(str);
+ return n;
+}
+
+static char *setup_overhead(char *keys)
+{
+ keys = prefix_if_not_in("overhead", keys);
+
+ if (symbol_conf.cumulate_callchain)
+ keys = prefix_if_not_in("overhead_children", keys);
+
+ return keys;
+}
+
+static int __setup_sorting(struct perf_evlist *evlist)
{
char *tmp, *tok, *str;
const char *sort_keys;
int ret = 0;
- ret = setup_sort_order();
+ ret = setup_sort_order(evlist);
if (ret)
return ret;
@@ -1732,7 +2300,7 @@ static int __setup_sorting(void)
return 0;
}
- sort_keys = get_default_sort_order();
+ sort_keys = get_default_sort_order(evlist);
}
str = strdup(sort_keys);
@@ -1741,9 +2309,20 @@ static int __setup_sorting(void)
return -ENOMEM;
}
+ /*
+ * Prepend overhead fields for backward compatibility.
+ */
+ if (!is_strict_order(field_order)) {
+ str = setup_overhead(str);
+ if (str == NULL) {
+ error("Not enough memory to setup overhead keys");
+ return -ENOMEM;
+ }
+ }
+
for (tok = strtok_r(str, ", ", &tmp);
tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = sort_dimension__add(tok);
+ ret = sort_dimension__add(tok, evlist);
if (ret == -EINVAL) {
error("Invalid --sort key: `%s'", tok);
break;
@@ -1954,16 +2533,16 @@ out:
return ret;
}
-int setup_sorting(void)
+int setup_sorting(struct perf_evlist *evlist)
{
int err;
- err = __setup_sorting();
+ err = __setup_sorting(evlist);
if (err < 0)
return err;
if (parent_pattern != default_parent_pattern) {
- err = sort_dimension__add("parent");
+ err = sort_dimension__add("parent", evlist);
if (err < 0)
return err;
}
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3122885..687bbb12 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -18,7 +18,7 @@
#include "debug.h"
#include "header.h"
-#include "parse-options.h"
+#include <subcmd/parse-options.h>
#include "parse-events.h"
#include "hist.h"
#include "thread.h"
@@ -122,6 +122,9 @@ struct hist_entry {
struct branch_info *branch_info;
struct hists *hists;
struct mem_info *mem_info;
+ void *raw_data;
+ u32 raw_size;
+ void *trace_output;
struct callchain_root callchain[0]; /* must be last member */
};
@@ -164,6 +167,7 @@ enum sort_mode {
SORT_MODE__MEMORY,
SORT_MODE__TOP,
SORT_MODE__DIFF,
+ SORT_MODE__TRACEPOINT,
};
enum sort_type {
@@ -180,6 +184,7 @@ enum sort_type {
SORT_LOCAL_WEIGHT,
SORT_GLOBAL_WEIGHT,
SORT_TRANSACTION,
+ SORT_TRACE,
/* branch stack specific sort keys */
__SORT_BRANCH_STACK,
@@ -209,8 +214,6 @@ enum sort_type {
*/
struct sort_entry {
- struct list_head list;
-
const char *se_header;
int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
@@ -224,10 +227,11 @@ struct sort_entry {
extern struct sort_entry sort_thread;
extern struct list_head hist_entry__sort_list;
-int setup_sorting(void);
+struct perf_evlist;
+struct pevent;
+int setup_sorting(struct perf_evlist *evlist);
int setup_output_field(void);
void reset_output_field(void);
-extern int sort_dimension__add(const char *);
void sort__setup_elide(FILE *fp);
void perf_hpp__set_elide(int idx, bool elide);
diff --git a/tools/perf/util/stat-shadow.c b/tools/perf/util/stat-shadow.c
index 2a5d8d7..6ac0314 100644
--- a/tools/perf/util/stat-shadow.c
+++ b/tools/perf/util/stat-shadow.c
@@ -413,6 +413,11 @@ void perf_stat__print_shadow_stats(FILE *out, struct perf_evsel *evsel,
ratio = total / avg;
fprintf(out, " # %8.0f cycles / elision ", ratio);
+ } else if (perf_evsel__match(evsel, SOFTWARE, SW_TASK_CLOCK)) {
+ if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
+ fprintf(out, " # %8.3f CPUs utilized ", avg / ratio);
+ else
+ fprintf(out, " ");
} else if (runtime_nsecs_stats[cpu].n != 0) {
char unit = 'M';
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c
index 2d9d830..2f901d1 100644
--- a/tools/perf/util/stat.c
+++ b/tools/perf/util/stat.c
@@ -341,3 +341,65 @@ int perf_stat_process_counter(struct perf_stat_config *config,
return 0;
}
+
+int perf_event__process_stat_event(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct perf_counts_values count;
+ struct stat_event *st = &event->stat;
+ struct perf_evsel *counter;
+
+ count.val = st->val;
+ count.ena = st->ena;
+ count.run = st->run;
+
+ counter = perf_evlist__id2evsel(session->evlist, st->id);
+ if (!counter) {
+ pr_err("Failed to resolve counter for stat event.\n");
+ return -EINVAL;
+ }
+
+ *perf_counts(counter->counts, st->cpu, st->thread) = count;
+ counter->supported = true;
+ return 0;
+}
+
+size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp)
+{
+ struct stat_event *st = (struct stat_event *) event;
+ size_t ret;
+
+ ret = fprintf(fp, "\n... id %" PRIu64 ", cpu %d, thread %d\n",
+ st->id, st->cpu, st->thread);
+ ret += fprintf(fp, "... value %" PRIu64 ", enabled %" PRIu64 ", running %" PRIu64 "\n",
+ st->val, st->ena, st->run);
+
+ return ret;
+}
+
+size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp)
+{
+ struct stat_round_event *rd = (struct stat_round_event *)event;
+ size_t ret;
+
+ ret = fprintf(fp, "\n... time %" PRIu64 ", type %s\n", rd->time,
+ rd->type == PERF_STAT_ROUND_TYPE__FINAL ? "FINAL" : "INTERVAL");
+
+ return ret;
+}
+
+size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp)
+{
+ struct perf_stat_config sc;
+ size_t ret;
+
+ perf_event__read_stat_config(&sc, &event->stat_config);
+
+ ret = fprintf(fp, "\n");
+ ret += fprintf(fp, "... aggr_mode %d\n", sc.aggr_mode);
+ ret += fprintf(fp, "... scale %d\n", sc.scale);
+ ret += fprintf(fp, "... interval %u\n", sc.interval);
+
+ return ret;
+}
diff --git a/tools/perf/util/stat.h b/tools/perf/util/stat.h
index da1d11c..086f4e1 100644
--- a/tools/perf/util/stat.h
+++ b/tools/perf/util/stat.h
@@ -90,4 +90,14 @@ void perf_evlist__reset_stats(struct perf_evlist *evlist);
int perf_stat_process_counter(struct perf_stat_config *config,
struct perf_evsel *counter);
+struct perf_tool;
+union perf_event;
+struct perf_session;
+int perf_event__process_stat_event(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_session *session);
+
+size_t perf_event__fprintf_stat(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_stat_round(union perf_event *event, FILE *fp);
+size_t perf_event__fprintf_stat_config(union perf_event *event, FILE *fp);
#endif
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index fc8781d..7f7e072 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -342,22 +342,6 @@ char *rtrim(char *s)
return s;
}
-/**
- * memdup - duplicate region of memory
- * @src: memory region to duplicate
- * @len: memory region length
- */
-void *memdup(const void *src, size_t len)
-{
- void *p;
-
- p = malloc(len);
- if (p)
- memcpy(p, src, len);
-
- return p;
-}
-
char *asprintf_expr_inout_ints(const char *var, bool in, size_t nints, int *ints)
{
/*
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 475d88d..562b8eb 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -1026,8 +1026,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
curr_dso->long_name_len = dso->long_name_len;
curr_map = map__new2(start, curr_dso,
map->type);
+ dso__put(curr_dso);
if (curr_map == NULL) {
- dso__put(curr_dso);
goto out_elf_end;
}
if (adjust_kernel_syms) {
@@ -1042,7 +1042,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
}
curr_dso->symtab_type = dso->symtab_type;
map_groups__insert(kmaps, curr_map);
+ /*
+ * Add it before we drop the referece to curr_map,
+ * i.e. while we still are sure to have a reference
+ * to this DSO via curr_map->dso.
+ */
dsos__add(&map->groups->machine->dsos, curr_dso);
+ /* kmaps already got it */
+ map__put(curr_map);
dso__set_loaded(curr_dso, map->type);
} else
curr_dso = curr_map->dso;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index b4cc766..3b2de6e 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -39,6 +39,7 @@ struct symbol_conf symbol_conf = {
.cumulate_callchain = true,
.show_hist_headers = true,
.symfs = "",
+ .event_group = true,
};
static enum dso_binary_type binary_type_symtab[] = {
@@ -654,19 +655,24 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
struct map_groups *kmaps = map__kmaps(map);
struct map *curr_map;
struct symbol *pos;
- int count = 0, moved = 0;
+ int count = 0;
+ struct rb_root old_root = dso->symbols[map->type];
struct rb_root *root = &dso->symbols[map->type];
struct rb_node *next = rb_first(root);
if (!kmaps)
return -1;
+ *root = RB_ROOT;
+
while (next) {
char *module;
pos = rb_entry(next, struct symbol, rb_node);
next = rb_next(&pos->rb_node);
+ rb_erase_init(&pos->rb_node, &old_root);
+
module = strchr(pos->name, '\t');
if (module)
*module = '\0';
@@ -674,28 +680,21 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
curr_map = map_groups__find(kmaps, map->type, pos->start);
if (!curr_map || (filter && filter(curr_map, pos))) {
- rb_erase_init(&pos->rb_node, root);
symbol__delete(pos);
- } else {
- pos->start -= curr_map->start - curr_map->pgoff;
- if (pos->end)
- pos->end -= curr_map->start - curr_map->pgoff;
- if (curr_map->dso != map->dso) {
- rb_erase_init(&pos->rb_node, root);
- symbols__insert(
- &curr_map->dso->symbols[curr_map->type],
- pos);
- ++moved;
- } else {
- ++count;
- }
+ continue;
}
+
+ pos->start -= curr_map->start - curr_map->pgoff;
+ if (pos->end)
+ pos->end -= curr_map->start - curr_map->pgoff;
+ symbols__insert(&curr_map->dso->symbols[curr_map->type], pos);
+ ++count;
}
/* Symbols have been adjusted */
dso->adjust_symbols = 1;
- return count + moved;
+ return count;
}
/*
@@ -1438,9 +1437,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (lstat(dso->name, &st) < 0)
goto out;
- if (st.st_uid && (st.st_uid != geteuid())) {
+ if (!symbol_conf.force && st.st_uid && (st.st_uid != geteuid())) {
pr_warning("File %s not owned by current user or root, "
- "ignoring it.\n", dso->name);
+ "ignoring it (use -f to override).\n", dso->name);
goto out;
}
@@ -1862,24 +1861,44 @@ static void vmlinux_path__exit(void)
zfree(&vmlinux_path);
}
+static const char * const vmlinux_paths[] = {
+ "vmlinux",
+ "/boot/vmlinux"
+};
+
+static const char * const vmlinux_paths_upd[] = {
+ "/boot/vmlinux-%s",
+ "/usr/lib/debug/boot/vmlinux-%s",
+ "/lib/modules/%s/build/vmlinux",
+ "/usr/lib/debug/lib/modules/%s/vmlinux",
+ "/usr/lib/debug/boot/vmlinux-%s.debug"
+};
+
+static int vmlinux_path__add(const char *new_entry)
+{
+ vmlinux_path[vmlinux_path__nr_entries] = strdup(new_entry);
+ if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
+ return -1;
+ ++vmlinux_path__nr_entries;
+
+ return 0;
+}
+
static int vmlinux_path__init(struct perf_env *env)
{
struct utsname uts;
char bf[PATH_MAX];
char *kernel_version;
+ unsigned int i;
- vmlinux_path = malloc(sizeof(char *) * 6);
+ vmlinux_path = malloc(sizeof(char *) * (ARRAY_SIZE(vmlinux_paths) +
+ ARRAY_SIZE(vmlinux_paths_upd)));
if (vmlinux_path == NULL)
return -1;
- vmlinux_path[vmlinux_path__nr_entries] = strdup("vmlinux");
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- vmlinux_path[vmlinux_path__nr_entries] = strdup("/boot/vmlinux");
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
+ for (i = 0; i < ARRAY_SIZE(vmlinux_paths); i++)
+ if (vmlinux_path__add(vmlinux_paths[i]) < 0)
+ goto out_fail;
/* only try kernel version if no symfs was given */
if (symbol_conf.symfs[0] != 0)
@@ -1894,28 +1913,11 @@ static int vmlinux_path__init(struct perf_env *env)
kernel_version = uts.release;
}
- snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", kernel_version);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/usr/lib/debug/boot/vmlinux-%s",
- kernel_version);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/lib/modules/%s/build/vmlinux", kernel_version);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
- snprintf(bf, sizeof(bf), "/usr/lib/debug/lib/modules/%s/vmlinux",
- kernel_version);
- vmlinux_path[vmlinux_path__nr_entries] = strdup(bf);
- if (vmlinux_path[vmlinux_path__nr_entries] == NULL)
- goto out_fail;
- ++vmlinux_path__nr_entries;
+ for (i = 0; i < ARRAY_SIZE(vmlinux_paths_upd); i++) {
+ snprintf(bf, sizeof(bf), vmlinux_paths_upd[i], kernel_version);
+ if (vmlinux_path__add(bf) < 0)
+ goto out_fail;
+ }
return 0;
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 40073c6..ccd1caa 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -84,6 +84,7 @@ struct symbol_conf {
unsigned short priv_size;
unsigned short nr_events;
bool try_vmlinux_path,
+ force,
ignore_vmlinux,
ignore_vmlinux_buildid,
show_kernel_path,
@@ -107,7 +108,9 @@ struct symbol_conf {
show_hist_headers,
branch_callstack,
has_filter,
- show_ref_callgraph;
+ show_ref_callgraph,
+ hide_unresolved,
+ raw_trace;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
diff --git a/tools/perf/util/term.c b/tools/perf/util/term.c
new file mode 100644
index 0000000..90b47d8
--- /dev/null
+++ b/tools/perf/util/term.c
@@ -0,0 +1,35 @@
+#include "util.h"
+
+void get_term_dimensions(struct winsize *ws)
+{
+ char *s = getenv("LINES");
+
+ if (s != NULL) {
+ ws->ws_row = atoi(s);
+ s = getenv("COLUMNS");
+ if (s != NULL) {
+ ws->ws_col = atoi(s);
+ if (ws->ws_row && ws->ws_col)
+ return;
+ }
+ }
+#ifdef TIOCGWINSZ
+ if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
+ ws->ws_row && ws->ws_col)
+ return;
+#endif
+ ws->ws_row = 25;
+ ws->ws_col = 80;
+}
+
+void set_term_quiet_input(struct termios *old)
+{
+ struct termios tc;
+
+ tcgetattr(0, old);
+ tc = *old;
+ tc.c_lflag &= ~(ICANON | ECHO);
+ tc.c_cc[VMIN] = 0;
+ tc.c_cc[VTIME] = 0;
+ tcsetattr(0, TCSANOW, &tc);
+}
diff --git a/tools/perf/util/term.h b/tools/perf/util/term.h
new file mode 100644
index 0000000..2c06a61
--- /dev/null
+++ b/tools/perf/util/term.h
@@ -0,0 +1,10 @@
+#ifndef __PERF_TERM_H
+#define __PERF_TERM_H
+
+struct termios;
+struct winsize;
+
+void get_term_dimensions(struct winsize *ws);
+void set_term_quiet_input(struct termios *old);
+
+#endif /* __PERF_TERM_H */
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index 0a9ae80..dfd00c6 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -19,8 +19,10 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
thread->mg = map_groups__new(machine);
} else {
leader = __machine__findnew_thread(machine, pid, pid);
- if (leader)
+ if (leader) {
thread->mg = map_groups__get(leader->mg);
+ thread__put(leader);
+ }
}
return thread->mg ? 0 : -1;
@@ -53,7 +55,7 @@ struct thread *thread__new(pid_t pid, pid_t tid)
goto err_thread;
list_add(&comm->list, &thread->comm_list);
- atomic_set(&thread->refcnt, 0);
+ atomic_set(&thread->refcnt, 1);
RB_CLEAR_NODE(&thread->rb_node);
}
@@ -95,6 +97,10 @@ struct thread *thread__get(struct thread *thread)
void thread__put(struct thread *thread)
{
if (thread && atomic_dec_and_test(&thread->refcnt)) {
+ /*
+ * Remove it from the dead_threads list, as last reference
+ * is gone.
+ */
list_del_init(&thread->node);
thread__delete(thread);
}
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c
index 6ec3c5c..08afc690 100644
--- a/tools/perf/util/thread_map.c
+++ b/tools/perf/util/thread_map.c
@@ -13,6 +13,7 @@
#include "thread_map.h"
#include "util.h"
#include "debug.h"
+#include "event.h"
/* Skip "." and ".." directories */
static int filter(const struct dirent *dir)
@@ -304,6 +305,7 @@ out:
out_free_threads:
zfree(&threads);
+ strlist__delete(slist);
goto out;
}
@@ -408,3 +410,29 @@ void thread_map__read_comms(struct thread_map *threads)
for (i = 0; i < threads->nr; ++i)
comm_init(threads, i);
}
+
+static void thread_map__copy_event(struct thread_map *threads,
+ struct thread_map_event *event)
+{
+ unsigned i;
+
+ threads->nr = (int) event->nr;
+
+ for (i = 0; i < event->nr; i++) {
+ thread_map__set_pid(threads, i, (pid_t) event->entries[i].pid);
+ threads->map[i].comm = strndup(event->entries[i].comm, 16);
+ }
+
+ atomic_set(&threads->refcnt, 1);
+}
+
+struct thread_map *thread_map__new_event(struct thread_map_event *event)
+{
+ struct thread_map *threads;
+
+ threads = thread_map__alloc(event->nr);
+ if (threads)
+ thread_map__copy_event(threads, event);
+
+ return threads;
+}
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h
index af679d8..85e4c7c 100644
--- a/tools/perf/util/thread_map.h
+++ b/tools/perf/util/thread_map.h
@@ -16,11 +16,14 @@ struct thread_map {
struct thread_map_data map[];
};
+struct thread_map_event;
+
struct thread_map *thread_map__new_dummy(void);
struct thread_map *thread_map__new_by_pid(pid_t pid);
struct thread_map *thread_map__new_by_tid(pid_t tid);
struct thread_map *thread_map__new_by_uid(uid_t uid);
struct thread_map *thread_map__new(pid_t pid, pid_t tid, uid_t uid);
+struct thread_map *thread_map__new_event(struct thread_map_event *event);
struct thread_map *thread_map__get(struct thread_map *map);
void thread_map__put(struct thread_map *map);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index cab8cc2..55de4cf 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -50,12 +50,18 @@ struct perf_tool {
throttle,
unthrottle;
event_attr_op attr;
+ event_attr_op event_update;
event_op2 tracing_data;
event_oe finished_round;
event_op2 build_id,
id_index,
auxtrace_info,
- auxtrace_error;
+ auxtrace_error,
+ thread_map,
+ cpu_map,
+ stat_config,
+ stat,
+ stat_round;
event_op3 auxtrace;
bool ordered_events;
bool ordering_requires_timestamps;
diff --git a/tools/perf/util/trace-event.h b/tools/perf/util/trace-event.h
index b85ee55..bce5b1d 100644
--- a/tools/perf/util/trace-event.h
+++ b/tools/perf/util/trace-event.h
@@ -65,6 +65,7 @@ int tracing_data_put(struct tracing_data *tdata);
struct addr_location;
struct perf_session;
+struct perf_stat_config;
struct scripting_ops {
const char *name;
@@ -75,6 +76,9 @@ struct scripting_ops {
struct perf_sample *sample,
struct perf_evsel *evsel,
struct addr_location *al);
+ void (*process_stat)(struct perf_stat_config *config,
+ struct perf_evsel *evsel, u64 tstamp);
+ void (*process_stat_interval)(u64 tstamp);
int (*generate_script) (struct pevent *pevent, const char *outfile);
};
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 2dcfe9a..cf5e250 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include "event.h"
#include "perf_regs.h"
+#include "callchain.h"
static char *debuginfo_path;
@@ -52,25 +53,28 @@ static int report_module(u64 ip, struct unwind_info *ui)
return __report_module(&al, ip, ui);
}
+/*
+ * Store all entries within entries array,
+ * we will process it after we finish unwind.
+ */
static int entry(u64 ip, struct unwind_info *ui)
{
- struct unwind_entry e;
+ struct unwind_entry *e = &ui->entries[ui->idx++];
struct addr_location al;
if (__report_module(&al, ip, ui))
return -1;
- e.ip = ip;
- e.map = al.map;
- e.sym = al.sym;
+ e->ip = ip;
+ e->map = al.map;
+ e->sym = al.sym;
pr_debug("unwind: %s:ip = 0x%" PRIx64 " (0x%" PRIx64 ")\n",
al.sym ? al.sym->name : "''",
ip,
al.map ? al.map->map_ip(al.map, ip) : (u64) 0);
-
- return ui->cb(&e, ui->arg);
+ return 0;
}
static pid_t next_thread(Dwfl *dwfl, void *arg, void **thread_argp)
@@ -92,6 +96,16 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, addr, &al);
if (!al.map) {
+ /*
+ * We've seen cases (softice) where DWARF unwinder went
+ * through non executable mmaps, which we need to lookup
+ * in MAP__VARIABLE tree.
+ */
+ thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+ MAP__VARIABLE, addr, &al);
+ }
+
+ if (!al.map) {
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
return -1;
}
@@ -168,7 +182,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct perf_sample *data,
int max_stack)
{
- struct unwind_info ui = {
+ struct unwind_info *ui, ui_buf = {
.sample = data,
.thread = thread,
.machine = thread->mg->machine,
@@ -177,35 +191,54 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
.max_stack = max_stack,
};
Dwarf_Word ip;
- int err = -EINVAL;
+ int err = -EINVAL, i;
if (!data->user_regs.regs)
return -EINVAL;
- ui.dwfl = dwfl_begin(&offline_callbacks);
- if (!ui.dwfl)
+ ui = zalloc(sizeof(ui_buf) + sizeof(ui_buf.entries[0]) * max_stack);
+ if (!ui)
+ return -ENOMEM;
+
+ *ui = ui_buf;
+
+ ui->dwfl = dwfl_begin(&offline_callbacks);
+ if (!ui->dwfl)
goto out;
err = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
if (err)
goto out;
- err = report_module(ip, &ui);
+ err = report_module(ip, ui);
if (err)
goto out;
- if (!dwfl_attach_state(ui.dwfl, EM_NONE, thread->tid, &callbacks, &ui))
+ if (!dwfl_attach_state(ui->dwfl, EM_NONE, thread->tid, &callbacks, ui))
goto out;
- err = dwfl_getthread_frames(ui.dwfl, thread->tid, frame_callback, &ui);
+ err = dwfl_getthread_frames(ui->dwfl, thread->tid, frame_callback, ui);
- if (err && !ui.max_stack)
+ if (err && !ui->max_stack)
err = 0;
+ /*
+ * Display what we got based on the order setup.
+ */
+ for (i = 0; i < ui->idx && !err; i++) {
+ int j = i;
+
+ if (callchain_param.order == ORDER_CALLER)
+ j = ui->idx - i - 1;
+
+ err = ui->entries[j].ip ? ui->cb(&ui->entries[j], ui->arg) : 0;
+ }
+
out:
if (err)
pr_debug("unwind: failed with '%s'\n", dwfl_errmsg(-1));
- dwfl_end(ui.dwfl);
+ dwfl_end(ui->dwfl);
+ free(ui);
return 0;
}
diff --git a/tools/perf/util/unwind-libdw.h b/tools/perf/util/unwind-libdw.h
index 417a142..5832866 100644
--- a/tools/perf/util/unwind-libdw.h
+++ b/tools/perf/util/unwind-libdw.h
@@ -16,6 +16,8 @@ struct unwind_info {
unwind_entry_cb_t cb;
void *arg;
int max_stack;
+ int idx;
+ struct unwind_entry entries[];
};
#endif /* __PERF_UNWIND_LIBDW_H */
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index c83832b..ee7e372 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -319,6 +319,15 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al);
+ if (!al.map) {
+ /*
+ * We've seen cases (softice) where DWARF unwinder went
+ * through non executable mmaps, which we need to lookup
+ * in MAP__VARIABLE tree.
+ */
+ thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
+ MAP__VARIABLE, ip, &al);
+ }
return al.map;
}
@@ -416,20 +425,19 @@ get_proc_name(unw_addr_space_t __maybe_unused as,
static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
unw_word_t *data)
{
- struct addr_location al;
+ struct map *map;
ssize_t size;
- thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
- MAP__FUNCTION, addr, &al);
- if (!al.map) {
+ map = find_map(addr, ui);
+ if (!map) {
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
return -1;
}
- if (!al.map->dso)
+ if (!map->dso)
return -1;
- size = dso__data_read_addr(al.map->dso, al.map, ui->machine,
+ size = dso__data_read_addr(map->dso, map, ui->machine,
addr, (u8 *) data, sizeof(*data));
return !(size == sizeof(*data));
@@ -614,23 +622,48 @@ void unwind__finish_access(struct thread *thread)
static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
void *arg, int max_stack)
{
+ u64 val;
+ unw_word_t ips[max_stack];
unw_addr_space_t addr_space;
unw_cursor_t c;
- int ret;
-
- addr_space = thread__priv(ui->thread);
- if (addr_space == NULL)
- return -1;
+ int ret, i = 0;
- ret = unw_init_remote(&c, addr_space, ui);
+ ret = perf_reg_value(&val, &ui->sample->user_regs, PERF_REG_IP);
if (ret)
- display_error(ret);
+ return ret;
- while (!ret && (unw_step(&c) > 0) && max_stack--) {
- unw_word_t ip;
+ ips[i++] = (unw_word_t) val;
- unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = ip ? entry(ip, ui->thread, cb, arg) : 0;
+ /*
+ * If we need more than one entry, do the DWARF
+ * unwind itself.
+ */
+ if (max_stack - 1 > 0) {
+ addr_space = thread__priv(ui->thread);
+ if (addr_space == NULL)
+ return -1;
+
+ ret = unw_init_remote(&c, addr_space, ui);
+ if (ret)
+ display_error(ret);
+
+ while (!ret && (unw_step(&c) > 0) && i < max_stack) {
+ unw_get_reg(&c, UNW_REG_IP, &ips[i]);
+ ++i;
+ }
+
+ max_stack = i;
+ }
+
+ /*
+ * Display what we got based on the order setup.
+ */
+ for (i = 0; i < max_stack && !ret; i++) {
+ int j = i;
+
+ if (callchain_param.order == ORDER_CALLER)
+ j = max_stack - i - 1;
+ ret = ips[j] ? entry(ips[j], ui->thread, cb, arg) : 0;
}
return ret;
@@ -640,24 +673,17 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack)
{
- u64 ip;
struct unwind_info ui = {
.sample = data,
.thread = thread,
.machine = thread->mg->machine,
};
- int ret;
if (!data->user_regs.regs)
return -EINVAL;
- ret = perf_reg_value(&ip, &data->user_regs, PERF_REG_IP);
- if (ret)
- return ret;
-
- ret = entry(ip, thread, cb, arg);
- if (ret)
- return -ENOMEM;
+ if (max_stack <= 0)
+ return -EINVAL;
- return --max_stack > 0 ? get_entries(&ui, cb, arg, max_stack) : 0;
+ return get_entries(&ui, cb, arg, max_stack);
}
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c
index cd12c25..88b8f8d 100644
--- a/tools/perf/util/util.c
+++ b/tools/perf/util/util.c
@@ -3,6 +3,7 @@
#include "debug.h"
#include <api/fs/fs.h>
#include <sys/mman.h>
+#include <sys/utsname.h>
#ifdef HAVE_BACKTRACE_SUPPORT
#include <execinfo.h>
#endif
@@ -15,12 +16,15 @@
#include <linux/kernel.h>
#include <unistd.h>
#include "callchain.h"
+#include "strlist.h"
+#include <subcmd/exec-cmd.h>
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_ABS,
.min_percent = 0.5,
.order = ORDER_CALLEE,
- .key = CCKEY_FUNCTION
+ .key = CCKEY_FUNCTION,
+ .value = CCVAL_PERCENT,
};
/*
@@ -350,41 +354,8 @@ void sighandler_dump_stack(int sig)
{
psignal(sig, "perf");
dump_stack();
- exit(sig);
-}
-
-void get_term_dimensions(struct winsize *ws)
-{
- char *s = getenv("LINES");
-
- if (s != NULL) {
- ws->ws_row = atoi(s);
- s = getenv("COLUMNS");
- if (s != NULL) {
- ws->ws_col = atoi(s);
- if (ws->ws_row && ws->ws_col)
- return;
- }
- }
-#ifdef TIOCGWINSZ
- if (ioctl(1, TIOCGWINSZ, ws) == 0 &&
- ws->ws_row && ws->ws_col)
- return;
-#endif
- ws->ws_row = 25;
- ws->ws_col = 80;
-}
-
-void set_term_quiet_input(struct termios *old)
-{
- struct termios tc;
-
- tcgetattr(0, old);
- tc = *old;
- tc.c_lflag &= ~(ICANON | ECHO);
- tc.c_cc[VMIN] = 0;
- tc.c_cc[VTIME] = 0;
- tcsetattr(0, TCSANOW, &tc);
+ signal(sig, SIG_DFL);
+ raise(sig);
}
int parse_nsec_time(const char *str, u64 *ptime)
@@ -665,3 +636,57 @@ bool find_process(const char *name)
closedir(dir);
return ret ? false : true;
}
+
+int
+fetch_kernel_version(unsigned int *puint, char *str,
+ size_t str_size)
+{
+ struct utsname utsname;
+ int version, patchlevel, sublevel, err;
+
+ if (uname(&utsname))
+ return -1;
+
+ if (str && str_size) {
+ strncpy(str, utsname.release, str_size);
+ str[str_size - 1] = '\0';
+ }
+
+ err = sscanf(utsname.release, "%d.%d.%d",
+ &version, &patchlevel, &sublevel);
+
+ if (err != 3) {
+ pr_debug("Unablt to get kernel version from uname '%s'\n",
+ utsname.release);
+ return -1;
+ }
+
+ if (puint)
+ *puint = (version << 16) + (patchlevel << 8) + sublevel;
+ return 0;
+}
+
+const char *perf_tip(const char *dirpath)
+{
+ struct strlist *tips;
+ struct str_node *node;
+ char *tip = NULL;
+ struct strlist_config conf = {
+ .dirname = system_path(dirpath) ,
+ };
+
+ tips = strlist__new("tips.txt", &conf);
+ if (tips == NULL || strlist__nr_entries(tips) == 1) {
+ tip = (char *)"Cannot find tips.txt file";
+ goto out;
+ }
+
+ node = strlist__entry(tips, random() % strlist__nr_entries(tips));
+ if (asprintf(&tip, "Tip: %s", node->s) < 0)
+ tip = (char *)"Tip: get more memory! ;-)";
+
+out:
+ strlist__delete(tips);
+
+ return tip;
+}
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 4cfb913..fe915e6 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -53,6 +53,7 @@
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
+#include <term.h>
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
@@ -150,12 +151,6 @@ extern void set_warning_routine(void (*routine)(const char *err, va_list params)
extern int prefixcmp(const char *str, const char *prefix);
extern void set_buildid_dir(const char *dir);
-static inline const char *skip_prefix(const char *str, const char *prefix)
-{
- size_t len = strlen(prefix);
- return strncmp(str, prefix, len) ? NULL : str + len;
-}
-
#ifdef __GLIBC_PREREQ
#if __GLIBC_PREREQ(2, 1)
#define HAVE_STRCHRNUL
@@ -186,14 +181,6 @@ static inline void *zalloc(size_t size)
#define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
-static inline int has_extension(const char *filename, const char *ext)
-{
- size_t len = strlen(filename);
- size_t extlen = strlen(ext);
-
- return len > extlen && !memcmp(filename + len - extlen, ext, extlen);
-}
-
/* Sane ctype - no locale, and works with signed chars */
#undef isascii
#undef isspace
@@ -282,9 +269,6 @@ void sighandler_dump_stack(int sig);
extern unsigned int page_size;
extern int cacheline_size;
-void get_term_dimensions(struct winsize *ws);
-void set_term_quiet_input(struct termios *old);
-
struct parse_tag {
char tag;
int mult;
@@ -350,4 +334,14 @@ static inline char *asprintf_expr_not_in_ints(const char *var, size_t nints, int
int get_stack_size(const char *str, unsigned long *_size);
+int fetch_kernel_version(unsigned int *puint,
+ char *str, size_t str_sz);
+#define KVER_VERSION(x) (((x) >> 16) & 0xff)
+#define KVER_PATCHLEVEL(x) (((x) >> 8) & 0xff)
+#define KVER_SUBLEVEL(x) ((x) & 0xff)
+#define KVER_FMT "%d.%d.%d"
+#define KVER_PARAM(x) KVER_VERSION(x), KVER_PATCHLEVEL(x), KVER_SUBLEVEL(x)
+
+const char *perf_tip(const char *dirpath);
+
#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/power/cpupower/debug/i386/dump_psb.c b/tools/power/cpupower/debug/i386/dump_psb.c
index 8d6a475..2c768cf 100644
--- a/tools/power/cpupower/debug/i386/dump_psb.c
+++ b/tools/power/cpupower/debug/i386/dump_psb.c
@@ -134,7 +134,7 @@ next_one:
}
static struct option info_opts[] = {
- {.name = "numpst", .has_arg=no_argument, .flag=NULL, .val='n'},
+ {"numpst", no_argument, NULL, 'n'},
};
void print_help(void)
diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1
index 3e6799d..580c4e3 100644
--- a/tools/power/cpupower/man/cpupower-idle-set.1
+++ b/tools/power/cpupower/man/cpupower-idle-set.1
@@ -20,7 +20,9 @@ Disable a specific processor sleep state.
Enable a specific processor sleep state.
.TP
\fB\-D\fR \fB\-\-disable-by-latency\fR <LATENCY>
-Disable all idle states with a equal or higher latency than <LATENCY>
+Disable all idle states with a equal or higher latency than <LATENCY>.
+
+Enable all idle states with a latency lower than <LATENCY>.
.TP
\fB\-E\fR \fB\-\-enable-all\fR
Enable all idle states if not enabled already.
diff --git a/tools/power/cpupower/utils/cpufreq-info.c b/tools/power/cpupower/utils/cpufreq-info.c
index b4b90a9..0e67643 100644
--- a/tools/power/cpupower/utils/cpufreq-info.c
+++ b/tools/power/cpupower/utils/cpufreq-info.c
@@ -536,21 +536,21 @@ static int get_latency(unsigned int cpu, unsigned int human)
}
static struct option info_opts[] = {
- { .name = "debug", .has_arg = no_argument, .flag = NULL, .val = 'e'},
- { .name = "boost", .has_arg = no_argument, .flag = NULL, .val = 'b'},
- { .name = "freq", .has_arg = no_argument, .flag = NULL, .val = 'f'},
- { .name = "hwfreq", .has_arg = no_argument, .flag = NULL, .val = 'w'},
- { .name = "hwlimits", .has_arg = no_argument, .flag = NULL, .val = 'l'},
- { .name = "driver", .has_arg = no_argument, .flag = NULL, .val = 'd'},
- { .name = "policy", .has_arg = no_argument, .flag = NULL, .val = 'p'},
- { .name = "governors", .has_arg = no_argument, .flag = NULL, .val = 'g'},
- { .name = "related-cpus", .has_arg = no_argument, .flag = NULL, .val = 'r'},
- { .name = "affected-cpus",.has_arg = no_argument, .flag = NULL, .val = 'a'},
- { .name = "stats", .has_arg = no_argument, .flag = NULL, .val = 's'},
- { .name = "latency", .has_arg = no_argument, .flag = NULL, .val = 'y'},
- { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
- { .name = "human", .has_arg = no_argument, .flag = NULL, .val = 'm'},
- { .name = "no-rounding", .has_arg = no_argument, .flag = NULL, .val = 'n'},
+ {"debug", no_argument, NULL, 'e'},
+ {"boost", no_argument, NULL, 'b'},
+ {"freq", no_argument, NULL, 'f'},
+ {"hwfreq", no_argument, NULL, 'w'},
+ {"hwlimits", no_argument, NULL, 'l'},
+ {"driver", no_argument, NULL, 'd'},
+ {"policy", no_argument, NULL, 'p'},
+ {"governors", no_argument, NULL, 'g'},
+ {"related-cpus", no_argument, NULL, 'r'},
+ {"affected-cpus", no_argument, NULL, 'a'},
+ {"stats", no_argument, NULL, 's'},
+ {"latency", no_argument, NULL, 'y'},
+ {"proc", no_argument, NULL, 'o'},
+ {"human", no_argument, NULL, 'm'},
+ {"no-rounding", no_argument, NULL, 'n'},
{ },
};
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c
index 4e21357..0fbd1a2 100644
--- a/tools/power/cpupower/utils/cpufreq-set.c
+++ b/tools/power/cpupower/utils/cpufreq-set.c
@@ -22,11 +22,11 @@
#define NORM_FREQ_LEN 32
static struct option set_opts[] = {
- { .name = "min", .has_arg = required_argument, .flag = NULL, .val = 'd'},
- { .name = "max", .has_arg = required_argument, .flag = NULL, .val = 'u'},
- { .name = "governor", .has_arg = required_argument, .flag = NULL, .val = 'g'},
- { .name = "freq", .has_arg = required_argument, .flag = NULL, .val = 'f'},
- { .name = "related", .has_arg = no_argument, .flag = NULL, .val='r'},
+ {"min", required_argument, NULL, 'd'},
+ {"max", required_argument, NULL, 'u'},
+ {"governor", required_argument, NULL, 'g'},
+ {"freq", required_argument, NULL, 'f'},
+ {"related", no_argument, NULL, 'r'},
{ },
};
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 75e66de..750c1d8 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -126,8 +126,8 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
}
static struct option info_opts[] = {
- { .name = "silent", .has_arg = no_argument, .flag = NULL, .val = 's'},
- { .name = "proc", .has_arg = no_argument, .flag = NULL, .val = 'o'},
+ {"silent", no_argument, NULL, 's'},
+ {"proc", no_argument, NULL, 'o'},
{ },
};
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c
index d45d8d7..d6b6ae4 100644
--- a/tools/power/cpupower/utils/cpuidle-set.c
+++ b/tools/power/cpupower/utils/cpuidle-set.c
@@ -13,15 +13,11 @@
#include "helpers/sysfs.h"
static struct option info_opts[] = {
- { .name = "disable",
- .has_arg = required_argument, .flag = NULL, .val = 'd'},
- { .name = "enable",
- .has_arg = required_argument, .flag = NULL, .val = 'e'},
- { .name = "disable-by-latency",
- .has_arg = required_argument, .flag = NULL, .val = 'D'},
- { .name = "enable-all",
- .has_arg = no_argument, .flag = NULL, .val = 'E'},
- { },
+ {"disable", required_argument, NULL, 'd'},
+ {"enable", required_argument, NULL, 'e'},
+ {"disable-by-latency", required_argument, NULL, 'D'},
+ {"enable-all", no_argument, NULL, 'E'},
+ { },
};
@@ -148,14 +144,21 @@ int cmd_idle_set(int argc, char **argv)
(cpu, idlestate);
state_latency = sysfs_get_idlestate_latency
(cpu, idlestate);
- printf("CPU: %u - idlestate %u - state_latency: %llu - latency: %llu\n",
- cpu, idlestate, state_latency, latency);
- if (disabled == 1 || latency > state_latency)
+ if (disabled == 1) {
+ if (latency > state_latency){
+ ret = sysfs_idlestate_disable
+ (cpu, idlestate, 0);
+ if (ret == 0)
+ printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu);
+ }
continue;
- ret = sysfs_idlestate_disable
- (cpu, idlestate, 1);
- if (ret == 0)
+ }
+ if (latency <= state_latency){
+ ret = sysfs_idlestate_disable
+ (cpu, idlestate, 1);
+ if (ret == 0)
printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu);
+ }
}
break;
case 'E':
diff --git a/tools/power/cpupower/utils/cpupower-info.c b/tools/power/cpupower/utils/cpupower-info.c
index 136d979..10299f2 100644
--- a/tools/power/cpupower/utils/cpupower-info.c
+++ b/tools/power/cpupower/utils/cpupower-info.c
@@ -17,8 +17,8 @@
#include "helpers/sysfs.h"
static struct option set_opts[] = {
- { .name = "perf-bias", .has_arg = optional_argument, .flag = NULL, .val = 'b'},
- { },
+ {"perf-bias", optional_argument, NULL, 'b'},
+ { },
};
static void print_wrong_arg_exit(void)
diff --git a/tools/power/cpupower/utils/cpupower-set.c b/tools/power/cpupower/utils/cpupower-set.c
index 573c75f..3e6f374 100644
--- a/tools/power/cpupower/utils/cpupower-set.c
+++ b/tools/power/cpupower/utils/cpupower-set.c
@@ -18,7 +18,7 @@
#include "helpers/bitmask.h"
static struct option set_opts[] = {
- { .name = "perf-bias", .has_arg = required_argument, .flag = NULL, .val = 'b'},
+ {"perf-bias", required_argument, NULL, 'b'},
{ },
};
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c
index cea398c..9cbb7fd 100644
--- a/tools/power/cpupower/utils/helpers/topology.c
+++ b/tools/power/cpupower/utils/helpers/topology.c
@@ -73,18 +73,22 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
for (cpu = 0; cpu < cpus; cpu++) {
cpu_top->core_info[cpu].cpu = cpu;
cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu);
- if (!cpu_top->core_info[cpu].is_online)
- continue;
if(sysfs_topology_read_file(
cpu,
"physical_package_id",
- &(cpu_top->core_info[cpu].pkg)) < 0)
- return -1;
+ &(cpu_top->core_info[cpu].pkg)) < 0) {
+ cpu_top->core_info[cpu].pkg = -1;
+ cpu_top->core_info[cpu].core = -1;
+ continue;
+ }
if(sysfs_topology_read_file(
cpu,
"core_id",
- &(cpu_top->core_info[cpu].core)) < 0)
- return -1;
+ &(cpu_top->core_info[cpu].core)) < 0) {
+ cpu_top->core_info[cpu].pkg = -1;
+ cpu_top->core_info[cpu].core = -1;
+ continue;
+ }
}
qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info),
@@ -95,12 +99,15 @@ int get_cpu_topology(struct cpupower_topology *cpu_top)
done by pkg value. */
last_pkg = cpu_top->core_info[0].pkg;
for(cpu = 1; cpu < cpus; cpu++) {
- if(cpu_top->core_info[cpu].pkg != last_pkg) {
+ if (cpu_top->core_info[cpu].pkg != last_pkg &&
+ cpu_top->core_info[cpu].pkg != -1) {
+
last_pkg = cpu_top->core_info[cpu].pkg;
cpu_top->pkgs++;
}
}
- cpu_top->pkgs++;
+ if (!cpu_top->core_info[0].pkg == -1)
+ cpu_top->pkgs++;
/* Intel's cores count is not consecutively numbered, there may
* be a core_id of 3, but none of 2. Assume there always is 0
diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
index c4bae92..05f953f 100644
--- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
+++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c
@@ -143,6 +143,9 @@ void print_results(int topology_depth, int cpu)
/* Be careful CPUs may got resorted for pkg value do not just use cpu */
if (!bitmask_isbitset(cpus_chosen, cpu_top.core_info[cpu].cpu))
return;
+ if (!cpu_top.core_info[cpu].is_online &&
+ cpu_top.core_info[cpu].pkg == -1)
+ return;
if (topology_depth > 2)
printf("%4d|", cpu_top.core_info[cpu].pkg);
@@ -191,7 +194,8 @@ void print_results(int topology_depth, int cpu)
* It's up to the monitor plug-in to check .is_online, this one
* is just for additional info.
*/
- if (!cpu_top.core_info[cpu].is_online) {
+ if (!cpu_top.core_info[cpu].is_online &&
+ cpu_top.core_info[cpu].pkg != -1) {
printf(_(" *is offline\n"));
return;
} else
@@ -388,6 +392,9 @@ int cmd_monitor(int argc, char **argv)
return EXIT_FAILURE;
}
+ if (!cpu_top.core_info[0].is_online)
+ printf("WARNING: at least one cpu is offline\n");
+
/* Default is: monitor all CPUs */
if (bitmask_isallclear(cpus_chosen))
bitmask_setall(cpus_chosen);
diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c
index bde0ef1..0dac7e0 100644
--- a/tools/power/x86/turbostat/turbostat.c
+++ b/tools/power/x86/turbostat/turbostat.c
@@ -75,6 +75,7 @@ unsigned int aperf_mperf_multiplier = 1;
int do_smi;
double bclk;
double base_hz;
+unsigned int has_base_hz;
double tsc_tweak = 1.0;
unsigned int show_pkg;
unsigned int show_core;
@@ -96,6 +97,7 @@ unsigned int do_ring_perf_limit_reasons;
unsigned int crystal_hz;
unsigned long long tsc_hz;
int base_cpu;
+double discover_bclk(unsigned int family, unsigned int model);
#define RAPL_PKG (1 << 0)
/* 0x610 MSR_PKG_POWER_LIMIT */
@@ -511,9 +513,13 @@ int format_counters(struct thread_data *t, struct core_data *c,
}
/* Bzy_MHz */
- if (has_aperf)
- outp += sprintf(outp, "%8.0f",
- 1.0 * t->tsc * tsc_tweak / units * t->aperf / t->mperf / interval_float);
+ if (has_aperf) {
+ if (has_base_hz)
+ outp += sprintf(outp, "%8.0f", base_hz / units * t->aperf / t->mperf);
+ else
+ outp += sprintf(outp, "%8.0f",
+ 1.0 * t->tsc / units * t->aperf / t->mperf / interval_float);
+ }
/* TSC_MHz */
outp += sprintf(outp, "%8.0f", 1.0 * t->tsc/units/interval_float);
@@ -1158,12 +1164,6 @@ int phi_pkg_cstate_limits[16] = {PCL__0, PCL__2, PCL_6N, PCL_6R, PCLRSV, PCLRSV,
static void
calculate_tsc_tweak()
{
- unsigned long long msr;
- unsigned int base_ratio;
-
- get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr);
- base_ratio = (msr >> 8) & 0xFF;
- base_hz = base_ratio * bclk * 1000000;
tsc_tweak = base_hz / tsc_hz;
}
@@ -1173,9 +1173,9 @@ dump_nhm_platform_info(void)
unsigned long long msr;
unsigned int ratio;
- get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr);
+ get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
- fprintf(stderr, "cpu%d: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
+ fprintf(stderr, "cpu%d: MSR_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr);
ratio = (msr >> 40) & 0xFF;
fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n",
@@ -1440,7 +1440,7 @@ dump_config_tdp(void)
get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr);
fprintf(stderr, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr);
- fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xEF);
+ fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0x7F);
fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1);
fprintf(stderr, ")\n");
}
@@ -1807,7 +1807,7 @@ void check_permissions()
*
* MSR_SMI_COUNT 0x00000034
*
- * MSR_NHM_PLATFORM_INFO 0x000000ce
+ * MSR_PLATFORM_INFO 0x000000ce
* MSR_NHM_SNB_PKG_CST_CFG_CTL 0x000000e2
*
* MSR_PKG_C3_RESIDENCY 0x000003f8
@@ -1821,6 +1821,7 @@ void check_permissions()
int probe_nhm_msrs(unsigned int family, unsigned int model)
{
unsigned long long msr;
+ unsigned int base_ratio;
int *pkg_cstate_limits;
if (!genuine_intel)
@@ -1829,6 +1830,8 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
if (family != 6)
return 0;
+ bclk = discover_bclk(family, model);
+
switch (model) {
case 0x1A: /* Core i7, Xeon 5500 series - Bloomfield, Gainstown NHM-EP */
case 0x1E: /* Core i7 and i5 Processor - Clarksfield, Lynnfield, Jasper Forest */
@@ -1871,9 +1874,13 @@ int probe_nhm_msrs(unsigned int family, unsigned int model)
return 0;
}
get_msr(base_cpu, MSR_NHM_SNB_PKG_CST_CFG_CTL, &msr);
-
pkg_cstate_limit = pkg_cstate_limits[msr & 0xF];
+ get_msr(base_cpu, MSR_PLATFORM_INFO, &msr);
+ base_ratio = (msr >> 8) & 0xFF;
+
+ base_hz = base_ratio * bclk * 1000000;
+ has_base_hz = 1;
return 1;
}
int has_nhm_turbo_ratio_limit(unsigned int family, unsigned int model)
@@ -2780,7 +2787,6 @@ void process_cpuid()
do_skl_residency = has_skl_msrs(family, model);
do_slm_cstates = is_slm(family, model);
do_knl_cstates = is_knl(family, model);
- bclk = discover_bclk(family, model);
rapl_probe(family, model);
perf_limit_reasons_probe(family, model);
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c
index 021e6f9..51cf825 100644
--- a/tools/testing/nvdimm/test/nfit.c
+++ b/tools/testing/nvdimm/test/nfit.c
@@ -17,8 +17,10 @@
#include <linux/vmalloc.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/ndctl.h>
#include <linux/sizes.h>
+#include <linux/list.h>
#include <linux/slab.h>
#include <nfit.h>
#include <nd.h>
@@ -44,6 +46,15 @@
* +------+ | blk5.0 | pm1.0 | 3 region5
* +-------------------------+----------+-+-------+
*
+ * +--+---+
+ * | cpu1 |
+ * +--+---+ (Hotplug DIMM)
+ * | +----------------------------------------------+
+ * +--+---+ | blk6.0/pm7.0 | 4 region6/7
+ * | imc0 +--+----------------------------------------------+
+ * +------+
+ *
+ *
* *) In this layout we have four dimms and two memory controllers in one
* socket. Each unique interface (BLK or PMEM) to DPA space
* is identified by a region device with a dynamically assigned id.
@@ -85,8 +96,8 @@
* reference an NVDIMM.
*/
enum {
- NUM_PM = 2,
- NUM_DCR = 4,
+ NUM_PM = 3,
+ NUM_DCR = 5,
NUM_BDW = NUM_DCR,
NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW,
NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */,
@@ -115,6 +126,7 @@ static u32 handle[NUM_DCR] = {
[1] = NFIT_DIMM_HANDLE(0, 0, 0, 0, 1),
[2] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 0),
[3] = NFIT_DIMM_HANDLE(0, 0, 1, 0, 1),
+ [4] = NFIT_DIMM_HANDLE(0, 1, 0, 0, 0),
};
struct nfit_test {
@@ -138,6 +150,7 @@ struct nfit_test {
dma_addr_t *dcr_dma;
int (*alloc)(struct nfit_test *t);
void (*setup)(struct nfit_test *t);
+ int setup_hotplug;
};
static struct nfit_test *to_nfit_test(struct device *dev)
@@ -407,8 +420,7 @@ static struct nfit_test_resource *nfit_test_lookup(resource_size_t addr)
static int nfit_test0_alloc(struct nfit_test *t)
{
- size_t nfit_size = sizeof(struct acpi_table_nfit)
- + sizeof(struct acpi_nfit_system_address) * NUM_SPA
+ size_t nfit_size = sizeof(struct acpi_nfit_system_address) * NUM_SPA
+ sizeof(struct acpi_nfit_memory_map) * NUM_MEM
+ sizeof(struct acpi_nfit_control_region) * NUM_DCR
+ sizeof(struct acpi_nfit_data_region) * NUM_BDW
@@ -428,6 +440,10 @@ static int nfit_test0_alloc(struct nfit_test *t)
if (!t->spa_set[1])
return -ENOMEM;
+ t->spa_set[2] = test_alloc_coherent(t, SPA0_SIZE, &t->spa_set_dma[2]);
+ if (!t->spa_set[2])
+ return -ENOMEM;
+
for (i = 0; i < NUM_DCR; i++) {
t->dimm[i] = test_alloc(t, DIMM_SIZE, &t->dimm_dma[i]);
if (!t->dimm[i])
@@ -454,8 +470,7 @@ static int nfit_test0_alloc(struct nfit_test *t)
static int nfit_test1_alloc(struct nfit_test *t)
{
- size_t nfit_size = sizeof(struct acpi_table_nfit)
- + sizeof(struct acpi_nfit_system_address)
+ size_t nfit_size = sizeof(struct acpi_nfit_system_address)
+ sizeof(struct acpi_nfit_memory_map)
+ sizeof(struct acpi_nfit_control_region);
@@ -471,39 +486,24 @@ static int nfit_test1_alloc(struct nfit_test *t)
return 0;
}
-static void nfit_test_init_header(struct acpi_table_nfit *nfit, size_t size)
-{
- memcpy(nfit->header.signature, ACPI_SIG_NFIT, 4);
- nfit->header.length = size;
- nfit->header.revision = 1;
- memcpy(nfit->header.oem_id, "LIBND", 6);
- memcpy(nfit->header.oem_table_id, "TEST", 5);
- nfit->header.oem_revision = 1;
- memcpy(nfit->header.asl_compiler_id, "TST", 4);
- nfit->header.asl_compiler_revision = 1;
-}
-
static void nfit_test0_setup(struct nfit_test *t)
{
struct nvdimm_bus_descriptor *nd_desc;
struct acpi_nfit_desc *acpi_desc;
struct acpi_nfit_memory_map *memdev;
void *nfit_buf = t->nfit_buf;
- size_t size = t->nfit_size;
struct acpi_nfit_system_address *spa;
struct acpi_nfit_control_region *dcr;
struct acpi_nfit_data_region *bdw;
struct acpi_nfit_flush_address *flush;
unsigned int offset;
- nfit_test_init_header(nfit_buf, size);
-
/*
* spa0 (interleave first half of dimm0 and dimm1, note storage
* does not actually alias the related block-data-window
* regions)
*/
- spa = nfit_buf + sizeof(struct acpi_table_nfit);
+ spa = nfit_buf;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -516,7 +516,7 @@ static void nfit_test0_setup(struct nfit_test *t)
* does not actually alias the related block-data-window
* regions)
*/
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa);
+ spa = nfit_buf + sizeof(*spa);
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
@@ -525,7 +525,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = SPA1_SIZE;
/* spa2 (dcr0) dimm0 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 2;
+ spa = nfit_buf + sizeof(*spa) * 2;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -534,7 +534,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DCR_SIZE;
/* spa3 (dcr1) dimm1 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 3;
+ spa = nfit_buf + sizeof(*spa) * 3;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -543,7 +543,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DCR_SIZE;
/* spa4 (dcr2) dimm2 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 4;
+ spa = nfit_buf + sizeof(*spa) * 4;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -552,7 +552,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DCR_SIZE;
/* spa5 (dcr3) dimm3 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 5;
+ spa = nfit_buf + sizeof(*spa) * 5;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
@@ -561,7 +561,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DCR_SIZE;
/* spa6 (bdw for dcr0) dimm0 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 6;
+ spa = nfit_buf + sizeof(*spa) * 6;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -570,7 +570,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DIMM_SIZE;
/* spa7 (bdw for dcr1) dimm1 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 7;
+ spa = nfit_buf + sizeof(*spa) * 7;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -579,7 +579,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DIMM_SIZE;
/* spa8 (bdw for dcr2) dimm2 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 8;
+ spa = nfit_buf + sizeof(*spa) * 8;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -588,7 +588,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->length = DIMM_SIZE;
/* spa9 (bdw for dcr3) dimm3 */
- spa = nfit_buf + sizeof(struct acpi_table_nfit) + sizeof(*spa) * 9;
+ spa = nfit_buf + sizeof(*spa) * 9;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
spa->header.length = sizeof(*spa);
memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
@@ -596,7 +596,7 @@ static void nfit_test0_setup(struct nfit_test *t)
spa->address = t->dimm_dma[3];
spa->length = DIMM_SIZE;
- offset = sizeof(struct acpi_table_nfit) + sizeof(*spa) * 10;
+ offset = sizeof(*spa) * 10;
/* mem-region0 (spa0, dimm0) */
memdev = nfit_buf + offset;
memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
@@ -950,6 +950,126 @@ static void nfit_test0_setup(struct nfit_test *t)
flush->hint_count = 1;
flush->hint_address[0] = t->flush_dma[3];
+ if (t->setup_hotplug) {
+ offset = offset + sizeof(struct acpi_nfit_flush_address) * 4;
+ /* dcr-descriptor4 */
+ dcr = nfit_buf + offset;
+ dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION;
+ dcr->header.length = sizeof(struct acpi_nfit_control_region);
+ dcr->region_index = 4+1;
+ dcr->vendor_id = 0xabcd;
+ dcr->device_id = 0;
+ dcr->revision_id = 1;
+ dcr->serial_number = ~handle[4];
+ dcr->windows = 1;
+ dcr->window_size = DCR_SIZE;
+ dcr->command_offset = 0;
+ dcr->command_size = 8;
+ dcr->status_offset = 8;
+ dcr->status_size = 4;
+
+ offset = offset + sizeof(struct acpi_nfit_control_region);
+ /* bdw4 (spa/dcr4, dimm4) */
+ bdw = nfit_buf + offset;
+ bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION;
+ bdw->header.length = sizeof(struct acpi_nfit_data_region);
+ bdw->region_index = 4+1;
+ bdw->windows = 1;
+ bdw->offset = 0;
+ bdw->size = BDW_SIZE;
+ bdw->capacity = DIMM_SIZE;
+ bdw->start_address = 0;
+
+ offset = offset + sizeof(struct acpi_nfit_data_region);
+ /* spa10 (dcr4) dimm4 */
+ spa = nfit_buf + offset;
+ spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+ spa->header.length = sizeof(*spa);
+ memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16);
+ spa->range_index = 10+1;
+ spa->address = t->dcr_dma[4];
+ spa->length = DCR_SIZE;
+
+ /*
+ * spa11 (single-dimm interleave for hotplug, note storage
+ * does not actually alias the related block-data-window
+ * regions)
+ */
+ spa = nfit_buf + offset + sizeof(*spa);
+ spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+ spa->header.length = sizeof(*spa);
+ memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16);
+ spa->range_index = 11+1;
+ spa->address = t->spa_set_dma[2];
+ spa->length = SPA0_SIZE;
+
+ /* spa12 (bdw for dcr4) dimm4 */
+ spa = nfit_buf + offset + sizeof(*spa) * 2;
+ spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
+ spa->header.length = sizeof(*spa);
+ memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16);
+ spa->range_index = 12+1;
+ spa->address = t->dimm_dma[4];
+ spa->length = DIMM_SIZE;
+
+ offset = offset + sizeof(*spa) * 3;
+ /* mem-region14 (spa/dcr4, dimm4) */
+ memdev = nfit_buf + offset;
+ memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+ memdev->header.length = sizeof(*memdev);
+ memdev->device_handle = handle[4];
+ memdev->physical_id = 4;
+ memdev->region_id = 0;
+ memdev->range_index = 10+1;
+ memdev->region_index = 4+1;
+ memdev->region_size = 0;
+ memdev->region_offset = 0;
+ memdev->address = 0;
+ memdev->interleave_index = 0;
+ memdev->interleave_ways = 1;
+
+ /* mem-region15 (spa0, dimm4) */
+ memdev = nfit_buf + offset +
+ sizeof(struct acpi_nfit_memory_map);
+ memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+ memdev->header.length = sizeof(*memdev);
+ memdev->device_handle = handle[4];
+ memdev->physical_id = 4;
+ memdev->region_id = 0;
+ memdev->range_index = 11+1;
+ memdev->region_index = 4+1;
+ memdev->region_size = SPA0_SIZE;
+ memdev->region_offset = t->spa_set_dma[2];
+ memdev->address = 0;
+ memdev->interleave_index = 0;
+ memdev->interleave_ways = 1;
+
+ /* mem-region16 (spa/dcr4, dimm4) */
+ memdev = nfit_buf + offset +
+ sizeof(struct acpi_nfit_memory_map) * 2;
+ memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP;
+ memdev->header.length = sizeof(*memdev);
+ memdev->device_handle = handle[4];
+ memdev->physical_id = 4;
+ memdev->region_id = 0;
+ memdev->range_index = 12+1;
+ memdev->region_index = 4+1;
+ memdev->region_size = 0;
+ memdev->region_offset = 0;
+ memdev->address = 0;
+ memdev->interleave_index = 0;
+ memdev->interleave_ways = 1;
+
+ offset = offset + sizeof(struct acpi_nfit_memory_map) * 3;
+ /* flush3 (dimm4) */
+ flush = nfit_buf + offset;
+ flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS;
+ flush->header.length = sizeof(struct acpi_nfit_flush_address);
+ flush->device_handle = handle[4];
+ flush->hint_count = 1;
+ flush->hint_address[0] = t->flush_dma[4];
+ }
+
acpi_desc = &t->acpi_desc;
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
@@ -963,15 +1083,13 @@ static void nfit_test0_setup(struct nfit_test *t)
static void nfit_test1_setup(struct nfit_test *t)
{
- size_t size = t->nfit_size, offset;
+ size_t offset;
void *nfit_buf = t->nfit_buf;
struct acpi_nfit_memory_map *memdev;
struct acpi_nfit_control_region *dcr;
struct acpi_nfit_system_address *spa;
- nfit_test_init_header(nfit_buf, size);
-
- offset = sizeof(struct acpi_table_nfit);
+ offset = 0;
/* spa0 (flat range with no bdw aliasing) */
spa = nfit_buf + offset;
spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS;
@@ -998,7 +1116,7 @@ static void nfit_test1_setup(struct nfit_test *t)
memdev->interleave_ways = 1;
memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED
| ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED
- | ACPI_NFIT_MEM_ARMED;
+ | ACPI_NFIT_MEM_NOT_ARMED;
offset += sizeof(*memdev);
/* dcr-descriptor0 */
@@ -1108,6 +1226,29 @@ static int nfit_test_probe(struct platform_device *pdev)
if (!acpi_desc->nvdimm_bus)
return -ENXIO;
+ INIT_LIST_HEAD(&acpi_desc->spa_maps);
+ INIT_LIST_HEAD(&acpi_desc->spas);
+ INIT_LIST_HEAD(&acpi_desc->dcrs);
+ INIT_LIST_HEAD(&acpi_desc->bdws);
+ INIT_LIST_HEAD(&acpi_desc->idts);
+ INIT_LIST_HEAD(&acpi_desc->flushes);
+ INIT_LIST_HEAD(&acpi_desc->memdevs);
+ INIT_LIST_HEAD(&acpi_desc->dimms);
+ mutex_init(&acpi_desc->spa_map_mutex);
+ mutex_init(&acpi_desc->init_mutex);
+
+ rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
+ if (rc) {
+ nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
+ return rc;
+ }
+
+ if (nfit_test->setup != nfit_test0_setup)
+ return 0;
+
+ nfit_test->setup_hotplug = 1;
+ nfit_test->setup(nfit_test);
+
rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_size);
if (rc) {
nvdimm_bus_unregister(acpi_desc->nvdimm_bus);
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 4b4957b..c8edff6 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -14,6 +14,7 @@ TARGETS += mount
TARGETS += mqueue
TARGETS += net
TARGETS += powerpc
+TARGETS += pstore
TARGETS += ptrace
TARGETS += seccomp
TARGETS += size
@@ -66,6 +67,9 @@ clean_hotplug:
make -C $$TARGET clean; \
done;
+run_pstore_crash:
+ make -C pstore run_crash
+
INSTALL_PATH ?= install
INSTALL_PATH := $(abspath $(INSTALL_PATH))
ALL_SCRIPT := $(INSTALL_PATH)/run_kselftest.sh
diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile
index d27108b..c0d9570 100644
--- a/tools/testing/selftests/breakpoints/Makefile
+++ b/tools/testing/selftests/breakpoints/Makefile
@@ -6,7 +6,7 @@ ifeq ($(ARCH),x86)
TEST_PROGS := breakpoint_test
endif
-all:
+all: $(TEST_PROGS)
include ../lib.mk
diff --git a/tools/testing/selftests/efivarfs/.gitignore b/tools/testing/selftests/efivarfs/.gitignore
new file mode 100644
index 0000000..3361849
--- /dev/null
+++ b/tools/testing/selftests/efivarfs/.gitignore
@@ -0,0 +1,2 @@
+create-read
+open-unlink
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
index a5a4262..c3843ed 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo p:myevent do_fork > kprobe_events
+echo p:myevent _do_fork > kprobe_events
grep myevent kprobe_events
test -d events/kprobes/myevent
echo > kprobe_events
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
index d8c7bb6..74507db 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo p:myevent do_fork > kprobe_events
+echo p:myevent _do_fork > kprobe_events
test -d events/kprobes/myevent
echo 1 > events/kprobes/myevent/enable
echo > kprobe_events && exit 1 # this must fail
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
index c45ee27..64949d4 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo 'p:testprobe do_fork $stack $stack0 +0($stack)' > kprobe_events
+echo 'p:testprobe _do_fork $stack $stack0 +0($stack)' > kprobe_events
grep testprobe kprobe_events
test -d events/kprobes/testprobe
echo 1 > events/kprobes/testprobe/enable
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
index ab41d2b..d6f2f49 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
@@ -6,31 +6,31 @@ grep function available_tracers || exit_unsupported # this is configurable
# prepare
echo nop > current_tracer
-echo do_fork > set_ftrace_filter
+echo _do_fork > set_ftrace_filter
echo 0 > events/enable
echo > kprobe_events
-echo 'p:testprobe do_fork' > kprobe_events
+echo 'p:testprobe _do_fork' > kprobe_events
# kprobe on / ftrace off
echo 1 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
grep testprobe trace
-! grep 'do_fork <-' trace
+! grep '_do_fork <-' trace
# kprobe on / ftrace on
echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe off / ftrace on
echo 0 > events/kprobes/testprobe/enable
echo > trace
( echo "forked")
! grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe on / ftrace on
echo 1 > events/kprobes/testprobe/enable
@@ -38,14 +38,14 @@ echo function > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-grep 'do_fork <-' trace
+grep '_do_fork <-' trace
# kprobe on / ftrace off
echo nop > current_tracer
echo > trace
( echo "forked")
grep testprobe trace
-! grep 'do_fork <-' trace
+! grep '_do_fork <-' trace
# cleanup
echo nop > current_tracer
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
index 3171798..0d09546 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -5,7 +5,7 @@
echo 0 > events/enable
echo > kprobe_events
-echo 'r:testprobe2 do_fork $retval' > kprobe_events
+echo 'r:testprobe2 _do_fork $retval' > kprobe_events
grep testprobe2 kprobe_events
test -d events/kprobes/testprobe2
echo 1 > events/kprobes/testprobe2/enable
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README
index 3224a04..0558bb9 100644
--- a/tools/testing/selftests/futex/README
+++ b/tools/testing/selftests/futex/README
@@ -27,7 +27,7 @@ o The build system shall remain as simple as possible, avoiding any archive or
o Where possible, any helper functions or other package-wide code shall be
implemented in header files, avoiding the need to compile intermediate object
files.
-o External dependendencies shall remain as minimal as possible. Currently gcc
+o External dependencies shall remain as minimal as possible. Currently gcc
and glibc are the only dependencies.
o Tests return 0 for success and < 0 for failure.
diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile
index 3e7eb79..fd396ac 100644
--- a/tools/testing/selftests/memfd/Makefile
+++ b/tools/testing/selftests/memfd/Makefile
@@ -4,16 +4,16 @@ CFLAGS += -I../../../../include/uapi/
CFLAGS += -I../../../../include/
CFLAGS += -I../../../../usr/include/
-all:
- $(CC) $(CFLAGS) memfd_test.c -o memfd_test
-
TEST_PROGS := memfd_test
+all: $(TEST_PROGS)
+
include ../lib.mk
-build_fuse:
- $(CC) $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
- $(CC) $(CFLAGS) fuse_test.c -o fuse_test
+build_fuse: fuse_mnt fuse_test
+
+fuse_mnt.o: CFLAGS += $(shell pkg-config fuse --cflags)
+fuse_mnt: LDFLAGS += $(shell pkg-config fuse --libs)
run_fuse: build_fuse
@./run_fuse_test.sh || echo "fuse_test: [FAIL]"
diff --git a/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c
index 0b9eafb..2654689 100644
--- a/tools/testing/selftests/memfd/memfd_test.c
+++ b/tools/testing/selftests/memfd/memfd_test.c
@@ -15,10 +15,11 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/wait.h>
#include <unistd.h>
#define MFD_DEF_SIZE 8192
-#define STACK_SIZE 65535
+#define STACK_SIZE 65536
static int sys_memfd_create(const char *name,
unsigned int flags)
diff --git a/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh
index 69b930e..69b930e 100644..100755
--- a/tools/testing/selftests/memfd/run_fuse_test.sh
+++ b/tools/testing/selftests/memfd/run_fuse_test.sh
diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c
index 9c1a5d35..e0a74bd 100644
--- a/tools/testing/selftests/mqueue/mq_open_tests.c
+++ b/tools/testing/selftests/mqueue/mq_open_tests.c
@@ -31,6 +31,7 @@
#include <sys/resource.h>
#include <sys/stat.h>
#include <mqueue.h>
+#include <error.h>
static char *usage =
"Usage:\n"
diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c
index 8519e9e..8188f72 100644
--- a/tools/testing/selftests/mqueue/mq_perf_tests.c
+++ b/tools/testing/selftests/mqueue/mq_perf_tests.c
@@ -37,6 +37,7 @@
#include <sys/stat.h>
#include <mqueue.h>
#include <popt.h>
+#include <error.h>
static char *usage =
"Usage:\n"
diff --git a/tools/testing/selftests/pstore/Makefile b/tools/testing/selftests/pstore/Makefile
new file mode 100644
index 0000000..bd7abe2
--- /dev/null
+++ b/tools/testing/selftests/pstore/Makefile
@@ -0,0 +1,15 @@
+# Makefile for pstore selftests.
+# Expects pstore backend is registered.
+
+all:
+
+TEST_PROGS := pstore_tests pstore_post_reboot_tests
+TEST_FILES := common_tests pstore_crash_test
+
+include ../lib.mk
+
+run_crash:
+ @sh pstore_crash_test || { echo "pstore_crash_test: [FAIL]"; exit 1; }
+
+clean:
+ rm -rf logs/* *uuid
diff --git a/tools/testing/selftests/pstore/common_tests b/tools/testing/selftests/pstore/common_tests
new file mode 100755
index 0000000..3ea64d7
--- /dev/null
+++ b/tools/testing/selftests/pstore/common_tests
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+# common_tests - Shell script commonly used by pstore test scripts
+#
+# Copyright (C) Hitachi Ltd., 2015
+# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+# Utilities
+errexit() { # message
+ echo "Error: $1" 1>&2
+ exit 1
+}
+
+absdir() { # file_path
+ (cd `dirname $1`; pwd)
+}
+
+show_result() { # result_value
+ if [ $1 -eq 0 ]; then
+ prlog "ok"
+ else
+ prlog "FAIL"
+ rc=1
+ fi
+}
+
+check_files_exist() { # type of pstorefs file
+ if [ -e ${1}-${backend}-0 ]; then
+ prlog "ok"
+ for f in `ls ${1}-${backend}-*`; do
+ prlog -e "\t${f}"
+ done
+ else
+ prlog "FAIL"
+ rc=1
+ fi
+}
+
+operate_files() { # tested value, files, operation
+ if [ $1 -eq 0 ]; then
+ prlog
+ for f in $2; do
+ prlog -ne "\t${f} ... "
+ # execute operation
+ $3 $f
+ show_result $?
+ done
+ else
+ prlog " ... FAIL"
+ rc=1
+ fi
+}
+
+# Parameters
+TEST_STRING_PATTERN="Testing pstore: uuid="
+UUID=`cat /proc/sys/kernel/random/uuid`
+TOP_DIR=`absdir $0`
+LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`_${UUID}/
+REBOOT_FLAG=$TOP_DIR/reboot_flag
+
+# Preparing logs
+LOG_FILE=$LOG_DIR/`basename $0`.log
+mkdir -p $LOG_DIR || errexit "Failed to make a log directory: $LOG_DIR"
+date > $LOG_FILE
+prlog() { # messages
+ /bin/echo "$@" | tee -a $LOG_FILE
+}
+
+# Starting tests
+rc=0
+prlog "=== Pstore unit tests (`basename $0`) ==="
+prlog "UUID="$UUID
+
+prlog -n "Checking pstore backend is registered ... "
+backend=`cat /sys/module/pstore/parameters/backend`
+show_result $?
+prlog -e "\tbackend=${backend}"
+prlog -e "\tcmdline=`cat /proc/cmdline`"
+if [ $rc -ne 0 ]; then
+ exit 1
+fi
diff --git a/tools/testing/selftests/pstore/pstore_crash_test b/tools/testing/selftests/pstore/pstore_crash_test
new file mode 100755
index 0000000..1a4afe5
--- /dev/null
+++ b/tools/testing/selftests/pstore/pstore_crash_test
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# pstore_crash_test - Pstore test shell script which causes crash and reboot
+#
+# Copyright (C) Hitachi Ltd., 2015
+# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+# exit if pstore backend is not registered
+. ./common_tests
+
+prlog "Causing kernel crash ..."
+
+# enable all functions triggered by sysrq
+echo 1 > /proc/sys/kernel/sysrq
+# setting to reboot in 3 seconds after panic
+echo 3 > /proc/sys/kernel/panic
+
+# save uuid file by different name because next test execution will replace it.
+mv $TOP_DIR/uuid $TOP_DIR/prev_uuid
+
+# create a file as reboot flag
+touch $REBOOT_FLAG
+sync
+
+# cause crash
+# Note: If you use kdump and want to see kmesg-* files after reboot, you should
+# specify 'crash_kexec_post_notifiers' in 1st kernel's cmdline.
+echo c > /proc/sysrq-trigger
diff --git a/tools/testing/selftests/pstore/pstore_post_reboot_tests b/tools/testing/selftests/pstore/pstore_post_reboot_tests
new file mode 100755
index 0000000..6ccb154
--- /dev/null
+++ b/tools/testing/selftests/pstore/pstore_post_reboot_tests
@@ -0,0 +1,77 @@
+#!/bin/sh
+
+# pstore_post_reboot_tests - Check pstore's behavior after crash/reboot
+#
+# Copyright (C) Hitachi Ltd., 2015
+# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+. ./common_tests
+
+if [ -e $REBOOT_FLAG ]; then
+ rm $REBOOT_FLAG
+else
+ prlog "pstore_crash_test has not been executed yet. we skip further tests."
+ exit 0
+fi
+
+prlog -n "Mounting pstore filesystem ... "
+mount_info=`grep pstore /proc/mounts`
+if [ $? -eq 0 ]; then
+ mount_point=`echo ${mount_info} | cut -d' ' -f2 | head -n1`
+ prlog "ok"
+else
+ mount none /sys/fs/pstore -t pstore
+ if [ $? -eq 0 ]; then
+ mount_point=`grep pstore /proc/mounts | cut -d' ' -f2 | head -n1`
+ prlog "ok"
+ else
+ prlog "FAIL"
+ exit 1
+ fi
+fi
+
+cd ${mount_point}
+
+prlog -n "Checking dmesg files exist in pstore filesystem ... "
+check_files_exist dmesg
+
+prlog -n "Checking console files exist in pstore filesystem ... "
+check_files_exist console
+
+prlog -n "Checking pmsg files exist in pstore filesystem ... "
+check_files_exist pmsg
+
+prlog -n "Checking dmesg files contain oops end marker"
+grep_end_trace() {
+ grep -q "\---\[ end trace" $1
+}
+files=`ls dmesg-${backend}-*`
+operate_files $? "$files" grep_end_trace
+
+prlog -n "Checking console file contains oops end marker ... "
+grep -q "\---\[ end trace" console-${backend}-0
+show_result $?
+
+prlog -n "Checking pmsg file properly keeps the content written before crash ... "
+prev_uuid=`cat $TOP_DIR/prev_uuid`
+if [ $? -eq 0 ]; then
+ nr_matched=`grep -c "$TEST_STRING_PATTERN" pmsg-${backend}-0`
+ if [ $nr_matched -eq 1 ]; then
+ grep -q "$TEST_STRING_PATTERN"$prev_uuid pmsg-${backend}-0
+ show_result $?
+ else
+ prlog "FAIL"
+ rc=1
+ fi
+else
+ prlog "FAIL"
+ rc=1
+fi
+
+prlog -n "Removing all files in pstore filesystem "
+files=`ls *-${backend}-*`
+operate_files $? "$files" rm
+
+exit $rc
diff --git a/tools/testing/selftests/pstore/pstore_tests b/tools/testing/selftests/pstore/pstore_tests
new file mode 100755
index 0000000..f25d2a3
--- /dev/null
+++ b/tools/testing/selftests/pstore/pstore_tests
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# pstore_tests - Check pstore's behavior before crash/reboot
+#
+# Copyright (C) Hitachi Ltd., 2015
+# Written by Hiraku Toyooka <hiraku.toyooka.gu@hitachi.com>
+#
+# Released under the terms of the GPL v2.
+
+. ./common_tests
+
+prlog -n "Checking pstore console is registered ... "
+dmesg | grep -q "console \[pstore"
+show_result $?
+
+prlog -n "Checking /dev/pmsg0 exists ... "
+test -e /dev/pmsg0
+show_result $?
+
+prlog -n "Writing unique string to /dev/pmsg0 ... "
+if [ -e "/dev/pmsg0" ]; then
+ echo "${TEST_STRING_PATTERN}""$UUID" > /dev/pmsg0
+ show_result $?
+ echo "$UUID" > $TOP_DIR/uuid
+else
+ prlog "FAIL"
+ rc=1
+fi
+
+exit $rc
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index 5236e07..0f80eef 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -38,8 +38,6 @@
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-grace=120
-
T=/tmp/kvm-test-1-run.sh.$$
trap 'rm -rf $T' 0
touch $T
@@ -152,7 +150,7 @@ fi
qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`"
# Generate architecture-specific and interaction-specific qemu arguments
-qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`"
+qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$resdir/console.log"`"
# Generate qemu -append arguments
qemu_append="`identify_qemu_append "$QEMU"`"
@@ -168,7 +166,7 @@ then
touch $resdir/buildonly
exit 0
fi
-echo "NOTE: $QEMU either did not run or was interactive" > $builddir/console.log
+echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log
echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
qemu_pid=$!
@@ -214,7 +212,7 @@ then
else
break
fi
- if test $kruntime -ge $((seconds + grace))
+ if test $kruntime -ge $((seconds + $TORTURE_SHUTDOWN_GRACE))
then
echo "!!! PID $qemu_pid hung at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1
kill -KILL $qemu_pid
@@ -224,6 +222,5 @@ then
done
fi
-cp $builddir/console.log $resdir
parse-torture.sh $resdir/console.log $title
parse-console.sh $resdir/console.log $title
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index f648360..4a43176 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -42,6 +42,7 @@ TORTURE_DEFCONFIG=defconfig
TORTURE_BOOT_IMAGE=""
TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD
TORTURE_KMAKE_ARG=""
+TORTURE_SHUTDOWN_GRACE=180
TORTURE_SUITE=rcu
resdir=""
configs=""
@@ -149,6 +150,11 @@ do
resdir=$2
shift
;;
+ --shutdown-grace)
+ checkarg --shutdown-grace "(seconds)" "$#" "$2" '^[0-9]*$' '^error'
+ TORTURE_SHUTDOWN_GRACE=$2
+ shift
+ ;;
--torture)
checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--'
TORTURE_SUITE=$2
@@ -266,6 +272,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG
TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD
TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE
TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC
+TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE
TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE
if ! test -e $resdir
then
@@ -307,10 +314,10 @@ awk < $T/cfgcpu.pack \
}
# Dump out the scripting required to run one test batch.
-function dump(first, pastlast)
+function dump(first, pastlast, batchnum)
{
- print "echo ----Start batch: `date`";
- print "echo ----Start batch: `date` >> " rd "/log";
+ print "echo ----Start batch " batchnum ": `date`";
+ print "echo ----Start batch " batchnum ": `date` >> " rd "/log";
jn=1
for (j = first; j < pastlast; j++) {
builddir=KVM "/b" jn
@@ -371,25 +378,28 @@ END {
njobs = i;
nc = ncpus;
first = 0;
+ batchnum = 1;
# Each pass through the following loop considers one test.
for (i = 0; i < njobs; i++) {
if (ncpus == 0) {
# Sequential test specified, each test its own batch.
- dump(i, i + 1);
+ dump(i, i + 1, batchnum);
first = i;
+ batchnum++;
} else if (nc < cpus[i] && i != 0) {
# Out of CPUs, dump out a batch.
- dump(first, i);
+ dump(first, i, batchnum);
first = i;
nc = ncpus;
+ batchnum++;
}
# Account for the CPUs needed by the current test.
nc -= cpus[i];
}
# Dump the last batch.
if (ncpus != 0)
- dump(first, i);
+ dump(first, i, batchnum);
}' >> $T/script
cat << ___EOF___ >> $T/script
diff --git a/tools/testing/selftests/rcutorture/bin/parse-console.sh b/tools/testing/selftests/rcutorture/bin/parse-console.sh
index d8f35cf..844787a 100755
--- a/tools/testing/selftests/rcutorture/bin/parse-console.sh
+++ b/tools/testing/selftests/rcutorture/bin/parse-console.sh
@@ -24,9 +24,6 @@
#
# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-T=/tmp/abat-chk-badness.sh.$$
-trap 'rm -f $T' 0
-
file="$1"
title="$2"
@@ -36,9 +33,41 @@ if grep -Pq '\x00' < $file
then
print_warning Console output contains nul bytes, old qemu still running?
fi
-egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T
-if test -s $T
+egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:|detected stalls on CPUs/tasks:|Stall ended before state dump start' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $1.diags
+if test -s $1.diags
then
print_warning Assertion failure in $file $title
- cat $T
+ # cat $1.diags
+ summary=""
+ n_badness=`grep -c Badness $1`
+ if test "$n_badness" -ne 0
+ then
+ summary="$summary Badness: $n_badness"
+ fi
+ n_warn=`grep -v 'Warning: unable to open an initial console' $1 | egrep -c 'WARNING:|Warn'`
+ if test "$n_warn" -ne 0
+ then
+ summary="$summary Warnings: $n_warn"
+ fi
+ n_bugs=`egrep -c 'BUG|Oops:' $1`
+ if test "$n_bugs" -ne 0
+ then
+ summary="$summary Bugs: $n_bugs"
+ fi
+ n_calltrace=`grep -c 'Call Trace:' $1`
+ if test "$n_calltrace" -ne 0
+ then
+ summary="$summary Call Traces: $n_calltrace"
+ fi
+ n_lockdep=`grep -c =========== $1`
+ if test "$n_badness" -ne 0
+ then
+ summary="$summary lockdep: $n_badness"
+ fi
+ n_stalls=`egrep -c 'detected stalls on CPUs/tasks:|Stall ended before state dump start' $1`
+ if test "$n_stalls" -ne 0
+ then
+ summary="$summary Stalls: $n_stalls"
+ fi
+ print_warning Summary: $summary
fi
diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
index 9ef33a7..24396ae 100644
--- a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
+++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
@@ -20,7 +20,6 @@ CONFIG_PROVE_RCU
CONFIG_NO_HZ_FULL_SYSIDLE
CONFIG_RCU_NOCB_CPU
-CONFIG_RCU_USER_QS
Meaningless for TINY_RCU.
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index 657f3a0..4e2b189 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
@@ -72,10 +72,6 @@ CONFIG_RCU_TORTURE_TEST_RUNNABLE
Always used in KVM testing.
-CONFIG_RCU_USER_QS
-
- Redundant with CONFIG_NO_HZ_FULL.
-
CONFIG_PREEMPT_RCU
CONFIG_TREE_RCU
diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c
index 770f47a..b9453b8 100644
--- a/tools/testing/selftests/seccomp/seccomp_bpf.c
+++ b/tools/testing/selftests/seccomp/seccomp_bpf.c
@@ -19,15 +19,19 @@
#include <linux/prctl.h>
#include <linux/ptrace.h>
#include <linux/seccomp.h>
-#include <poll.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
+#include <time.h>
#include <linux/elf.h>
#include <sys/uio.h>
+#include <sys/utsname.h>
+#include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/times.h>
#define _GNU_SOURCE
#include <unistd.h>
@@ -428,14 +432,16 @@ TEST_SIGNAL(KILL_one, SIGSYS)
TEST_SIGNAL(KILL_one_arg_one, SIGSYS)
{
+ void *fatal_address;
struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
offsetof(struct seccomp_data, nr)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
/* Only both with lower 32-bit for now. */
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
+ (unsigned long)&fatal_address, 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
@@ -445,7 +451,8 @@ TEST_SIGNAL(KILL_one_arg_one, SIGSYS)
};
long ret;
pid_t parent = getppid();
- pid_t pid = getpid();
+ struct tms timebuf;
+ clock_t clock = times(&timebuf);
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
ASSERT_EQ(0, ret);
@@ -454,17 +461,22 @@ TEST_SIGNAL(KILL_one_arg_one, SIGSYS)
ASSERT_EQ(0, ret);
EXPECT_EQ(parent, syscall(__NR_getppid));
- EXPECT_EQ(pid, syscall(__NR_getpid));
- /* getpid() should never return. */
- EXPECT_EQ(0, syscall(__NR_getpid, 0x0C0FFEE));
+ EXPECT_LE(clock, syscall(__NR_times, &timebuf));
+ /* times() should never return. */
+ EXPECT_EQ(0, syscall(__NR_times, &fatal_address));
}
TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
{
+#ifndef __NR_mmap2
+ int sysno = __NR_mmap;
+#else
+ int sysno = __NR_mmap2;
+#endif
struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
offsetof(struct seccomp_data, nr)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
/* Only both with lower 32-bit for now. */
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)),
@@ -478,7 +490,11 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
};
long ret;
pid_t parent = getppid();
- pid_t pid = getpid();
+ int fd;
+ void *map1, *map2;
+ int page_size = sysconf(_SC_PAGESIZE);
+
+ ASSERT_LT(0, page_size);
ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
ASSERT_EQ(0, ret);
@@ -486,10 +502,22 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS)
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
ASSERT_EQ(0, ret);
+ fd = open("/dev/zero", O_RDONLY);
+ ASSERT_NE(-1, fd);
+
EXPECT_EQ(parent, syscall(__NR_getppid));
- EXPECT_EQ(pid, syscall(__NR_getpid));
- /* getpid() should never return. */
- EXPECT_EQ(0, syscall(__NR_getpid, 1, 2, 3, 4, 5, 0x0C0FFEE));
+ map1 = (void *)syscall(sysno,
+ NULL, page_size, PROT_READ, MAP_PRIVATE, fd, page_size);
+ EXPECT_NE(MAP_FAILED, map1);
+ /* mmap2() should never return. */
+ map2 = (void *)syscall(sysno,
+ NULL, page_size, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
+ EXPECT_EQ(MAP_FAILED, map2);
+
+ /* The test failed, so clean up the resources. */
+ munmap(map1, page_size);
+ munmap(map2, page_size);
+ close(fd);
}
/* TODO(wad) add 64-bit versus 32-bit arg tests. */
@@ -1218,11 +1246,24 @@ TEST_F(TRACE_poke, getpid_runs_normally)
# error "Do not know how to find your architecture's registers and syscalls"
#endif
+/* Use PTRACE_GETREGS and PTRACE_SETREGS when available. This is useful for
+ * architectures without HAVE_ARCH_TRACEHOOK (e.g. User-mode Linux).
+ */
+#if defined(__x86_64__) || defined(__i386__)
+#define HAVE_GETREGS
+#endif
+
/* Architecture-specific syscall fetching routine. */
int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
{
- struct iovec iov;
ARCH_REGS regs;
+#ifdef HAVE_GETREGS
+ EXPECT_EQ(0, ptrace(PTRACE_GETREGS, tracee, 0, &regs)) {
+ TH_LOG("PTRACE_GETREGS failed");
+ return -1;
+ }
+#else
+ struct iovec iov;
iov.iov_base = &regs;
iov.iov_len = sizeof(regs);
@@ -1230,6 +1271,7 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
TH_LOG("PTRACE_GETREGSET failed");
return -1;
}
+#endif
return regs.SYSCALL_NUM;
}
@@ -1238,17 +1280,20 @@ int get_syscall(struct __test_metadata *_metadata, pid_t tracee)
void change_syscall(struct __test_metadata *_metadata,
pid_t tracee, int syscall)
{
- struct iovec iov;
int ret;
ARCH_REGS regs;
-
+#ifdef HAVE_GETREGS
+ ret = ptrace(PTRACE_GETREGS, tracee, 0, &regs);
+#else
+ struct iovec iov;
iov.iov_base = &regs;
iov.iov_len = sizeof(regs);
ret = ptrace(PTRACE_GETREGSET, tracee, NT_PRSTATUS, &iov);
+#endif
EXPECT_EQ(0, ret);
-#if defined(__x86_64__) || defined(__i386__) || defined(__aarch64__) || \
- defined(__powerpc__) || defined(__s390__)
+#if defined(__x86_64__) || defined(__i386__) || defined(__powerpc__) || \
+ defined(__s390__)
{
regs.SYSCALL_NUM = syscall;
}
@@ -1262,6 +1307,18 @@ void change_syscall(struct __test_metadata *_metadata,
EXPECT_EQ(0, ret);
}
+#elif defined(__aarch64__)
+# ifndef NT_ARM_SYSTEM_CALL
+# define NT_ARM_SYSTEM_CALL 0x404
+# endif
+ {
+ iov.iov_base = &syscall;
+ iov.iov_len = sizeof(syscall);
+ ret = ptrace(PTRACE_SETREGSET, tracee, NT_ARM_SYSTEM_CALL,
+ &iov);
+ EXPECT_EQ(0, ret);
+ }
+
#else
ASSERT_EQ(1, 0) {
TH_LOG("How is the syscall changed on this architecture?");
@@ -1272,7 +1329,13 @@ void change_syscall(struct __test_metadata *_metadata,
if (syscall == -1)
regs.SYSCALL_RET = 1;
+#ifdef HAVE_GETREGS
+ ret = ptrace(PTRACE_SETREGS, tracee, 0, &regs);
+#else
+ iov.iov_base = &regs;
+ iov.iov_len = sizeof(regs);
ret = ptrace(PTRACE_SETREGSET, tracee, NT_PRSTATUS, &iov);
+#endif
EXPECT_EQ(0, ret);
}
@@ -2005,20 +2068,25 @@ TEST(syscall_restart)
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_read, 5, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_exit, 4, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_rt_sigreturn, 3, 0),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_poll, 4, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_nanosleep, 4, 0),
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_restart_syscall, 4, 0),
/* Allow __NR_write for easy logging. */
BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_write, 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
- BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100), /* poll */
- BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200), /* restart */
+ /* The nanosleep jump target. */
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x100),
+ /* The restart_syscall jump target. */
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE|0x200),
};
struct sock_fprog prog = {
.len = (unsigned short)ARRAY_SIZE(filter),
.filter = filter,
};
+#if defined(__arm__)
+ struct utsname utsbuf;
+#endif
ASSERT_EQ(0, pipe(pipefd));
@@ -2027,10 +2095,7 @@ TEST(syscall_restart)
if (child_pid == 0) {
/* Child uses EXPECT not ASSERT to deliver status correctly. */
char buf = ' ';
- struct pollfd fds = {
- .fd = pipefd[0],
- .events = POLLIN,
- };
+ struct timespec timeout = { };
/* Attach parent as tracer and stop. */
EXPECT_EQ(0, ptrace(PTRACE_TRACEME));
@@ -2054,10 +2119,11 @@ TEST(syscall_restart)
TH_LOG("Failed to get sync data from read()");
}
- /* Start poll to be interrupted. */
+ /* Start nanosleep to be interrupted. */
+ timeout.tv_sec = 1;
errno = 0;
- EXPECT_EQ(1, poll(&fds, 1, -1)) {
- TH_LOG("Call to poll() failed (errno %d)", errno);
+ EXPECT_EQ(0, nanosleep(&timeout, NULL)) {
+ TH_LOG("Call to nanosleep() failed (errno %d)", errno);
}
/* Read final sync from parent. */
@@ -2082,14 +2148,14 @@ TEST(syscall_restart)
ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
ASSERT_EQ(1, write(pipefd[1], ".", 1));
- /* Wait for poll() to start. */
+ /* Wait for nanosleep() to start. */
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
ASSERT_EQ(true, WIFSTOPPED(status));
ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
ASSERT_EQ(0x100, msg);
- EXPECT_EQ(__NR_poll, get_syscall(_metadata, child_pid));
+ EXPECT_EQ(__NR_nanosleep, get_syscall(_metadata, child_pid));
/* Might as well check siginfo for sanity while we're here. */
ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
@@ -2100,7 +2166,7 @@ TEST(syscall_restart)
/* Verify signal delivery came from child (seccomp-triggered). */
EXPECT_EQ(child_pid, info.si_pid);
- /* Interrupt poll with SIGSTOP (which we'll need to handle). */
+ /* Interrupt nanosleep with SIGSTOP (which we'll need to handle). */
ASSERT_EQ(0, kill(child_pid, SIGSTOP));
ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
@@ -2110,7 +2176,7 @@ TEST(syscall_restart)
ASSERT_EQ(0, ptrace(PTRACE_GETSIGINFO, child_pid, NULL, &info));
EXPECT_EQ(getpid(), info.si_pid);
- /* Restart poll with SIGCONT, which triggers restart_syscall. */
+ /* Restart nanosleep with SIGCONT, which triggers restart_syscall. */
ASSERT_EQ(0, kill(child_pid, SIGCONT));
ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
@@ -2124,16 +2190,25 @@ TEST(syscall_restart)
ASSERT_EQ(SIGTRAP, WSTOPSIG(status));
ASSERT_EQ(PTRACE_EVENT_SECCOMP, (status >> 16));
ASSERT_EQ(0, ptrace(PTRACE_GETEVENTMSG, child_pid, NULL, &msg));
+
ASSERT_EQ(0x200, msg);
ret = get_syscall(_metadata, child_pid);
#if defined(__arm__)
- /* FIXME: ARM does not expose true syscall in registers. */
- EXPECT_EQ(__NR_poll, ret);
-#else
- EXPECT_EQ(__NR_restart_syscall, ret);
+ /*
+ * FIXME:
+ * - native ARM registers do NOT expose true syscall.
+ * - compat ARM registers on ARM64 DO expose true syscall.
+ */
+ ASSERT_EQ(0, uname(&utsbuf));
+ if (strncmp(utsbuf.machine, "arm", 3) == 0) {
+ EXPECT_EQ(__NR_nanosleep, ret);
+ } else
#endif
+ {
+ EXPECT_EQ(__NR_restart_syscall, ret);
+ }
- /* Write again to end poll. */
+ /* Write again to end test. */
ASSERT_EQ(0, ptrace(PTRACE_CONT, child_pid, NULL, 0));
ASSERT_EQ(1, write(pipefd[1], "!", 1));
EXPECT_EQ(0, close(pipefd[1]));
diff --git a/tools/testing/selftests/static_keys/test_static_keys.sh b/tools/testing/selftests/static_keys/test_static_keys.sh
index 1261e3f..1261e3f 100644..100755
--- a/tools/testing/selftests/static_keys/test_static_keys.sh
+++ b/tools/testing/selftests/static_keys/test_static_keys.sh
diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c
index 627ec74..fd88e30 100644
--- a/tools/testing/selftests/timers/clocksource-switch.c
+++ b/tools/testing/selftests/timers/clocksource-switch.c
@@ -97,7 +97,7 @@ int get_cur_clocksource(char *buf, size_t size)
int change_clocksource(char *clocksource)
{
int fd;
- size_t size;
+ ssize_t size;
fd = open("/sys/devices/system/clocksource/clocksource0/current_clocksource", O_WRONLY);
diff --git a/tools/testing/selftests/timers/nanosleep.c b/tools/testing/selftests/timers/nanosleep.c
index 8a3c29d..ff942ff 100644
--- a/tools/testing/selftests/timers/nanosleep.c
+++ b/tools/testing/selftests/timers/nanosleep.c
@@ -19,6 +19,7 @@
* GNU General Public License for more details.
*/
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c
index 4431994..02ca5e0 100644
--- a/tools/testing/selftests/vm/mlock2-tests.c
+++ b/tools/testing/selftests/vm/mlock2-tests.c
@@ -1,3 +1,4 @@
+#define _GNU_SOURCE
#include <sys/mman.h>
#include <stdint.h>
#include <stdio.h>
@@ -276,8 +277,8 @@ out:
return ret;
}
-#define PRESENT_BIT 0x8000000000000000
-#define PFN_MASK 0x007FFFFFFFFFFFFF
+#define PRESENT_BIT 0x8000000000000000ULL
+#define PFN_MASK 0x007FFFFFFFFFFFFFULL
#define UNEVICTABLE_BIT (1UL << 18)
static int lock_check(char *map)
diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests
index 2df21b3..e11968b 100755
--- a/tools/testing/selftests/vm/run_vmtests
+++ b/tools/testing/selftests/vm/run_vmtests
@@ -20,13 +20,26 @@ done < /proc/meminfo
if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then
nr_hugepgs=`cat /proc/sys/vm/nr_hugepages`
needpgs=`expr $needmem / $pgsize`
- if [ $freepgs -lt $needpgs ]; then
+ tries=2
+ while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do
lackpgs=$(( $needpgs - $freepgs ))
+ echo 3 > /proc/sys/vm/drop_caches
echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages
if [ $? -ne 0 ]; then
echo "Please run this test as root"
exit 1
fi
+ while read name size unit; do
+ if [ "$name" = "HugePages_Free:" ]; then
+ freepgs=$size
+ fi
+ done < /proc/meminfo
+ tries=$((tries - 1))
+ done
+ if [ $freepgs -lt $needpgs ]; then
+ printf "Not enough huge pages available (%d < %d)\n" \
+ $freepgs $needpgs
+ exit 1
fi
else
echo "no hugetlbfs support in kernel?"
diff --git a/tools/thermal/tmon/Makefile b/tools/thermal/tmon/Makefile
index 2e83dd3..3a961e9 100644
--- a/tools/thermal/tmon/Makefile
+++ b/tools/thermal/tmon/Makefile
@@ -22,6 +22,9 @@ TMON_LIBS += $(shell pkg-config --libs $(STATIC) panelw ncursesw 2> /dev/null ||
pkg-config --libs $(STATIC) panel ncurses 2> /dev/null || \
echo -lpanel -lncurses)
+CFLAGS += $(shell pkg-config --cflags $(STATIC) panelw ncursesw 2> /dev/null || \
+ pkg-config --cflags $(STATIC) panel ncurses 2> /dev/null)
+
OBJS = tmon.o tui.o sysfs.o pid.o
OBJS +=
diff --git a/tools/virtio/linux/kernel.h b/tools/virtio/linux/kernel.h
index 0a3da64..4db7d56 100644
--- a/tools/virtio/linux/kernel.h
+++ b/tools/virtio/linux/kernel.h
@@ -110,4 +110,10 @@ static inline void free_page(unsigned long addr)
(void) (&_min1 == &_min2); \
_min1 < _min2 ? _min1 : _min2; })
+/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
+#define list_add_tail(a, b) do {} while (0)
+#define list_del(a) do {} while (0)
+#define list_for_each_entry(a, b, c) while (0)
+/* end of stubs */
+
#endif /* KERNEL_H */
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index a3e0701..ee125e7 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -3,12 +3,6 @@
#include <linux/scatterlist.h>
#include <linux/kernel.h>
-/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
-#define list_add_tail(a, b) do {} while (0)
-#define list_del(a) do {} while (0)
-#define list_for_each_entry(a, b, c) while (0)
-/* end of stubs */
-
struct virtio_device {
void *dev;
u64 features;
diff --git a/tools/virtio/linux/virtio_config.h b/tools/virtio/linux/virtio_config.h
index 806d683..57a6964 100644
--- a/tools/virtio/linux/virtio_config.h
+++ b/tools/virtio/linux/virtio_config.h
@@ -40,33 +40,39 @@ static inline void __virtio_clear_bit(struct virtio_device *vdev,
#define virtio_has_feature(dev, feature) \
(__virtio_test_bit((dev), feature))
+static inline bool virtio_is_little_endian(struct virtio_device *vdev)
+{
+ return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+ virtio_legacy_is_little_endian();
+}
+
+/* Memory accessors */
static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
{
- return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __virtio16_to_cpu(virtio_is_little_endian(vdev), val);
}
static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
{
- return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __cpu_to_virtio16(virtio_is_little_endian(vdev), val);
}
static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
{
- return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __virtio32_to_cpu(virtio_is_little_endian(vdev), val);
}
static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
{
- return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __cpu_to_virtio32(virtio_is_little_endian(vdev), val);
}
static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
{
- return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __virtio64_to_cpu(virtio_is_little_endian(vdev), val);
}
static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
{
- return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+ return __cpu_to_virtio64(virtio_is_little_endian(vdev), val);
}
-
diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c
index bcf5ec7..5a60162 100644
--- a/tools/vm/page-types.c
+++ b/tools/vm/page-types.c
@@ -128,6 +128,7 @@ static const char * const page_flag_names[] = {
[KPF_THP] = "t:thp",
[KPF_BALLOON] = "o:balloon",
[KPF_ZERO_PAGE] = "z:zero_page",
+ [KPF_IDLE] = "i:idle_page",
[KPF_RESERVED] = "r:reserved",
[KPF_MLOCKED] = "m:mlocked",
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 21a0ab2..69bca18 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -221,17 +221,23 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
kvm_timer_update_state(vcpu);
/*
- * If we enter the guest with the virtual input level to the VGIC
- * asserted, then we have already told the VGIC what we need to, and
- * we don't need to exit from the guest until the guest deactivates
- * the already injected interrupt, so therefore we should set the
- * hardware active state to prevent unnecessary exits from the guest.
- *
- * Conversely, if the virtual input level is deasserted, then always
- * clear the hardware active state to ensure that hardware interrupts
- * from the timer triggers a guest exit.
- */
- if (timer->irq.level)
+ * If we enter the guest with the virtual input level to the VGIC
+ * asserted, then we have already told the VGIC what we need to, and
+ * we don't need to exit from the guest until the guest deactivates
+ * the already injected interrupt, so therefore we should set the
+ * hardware active state to prevent unnecessary exits from the guest.
+ *
+ * Also, if we enter the guest with the virtual timer interrupt active,
+ * then it must be active on the physical distributor, because we set
+ * the HW bit and the guest must be able to deactivate the virtual and
+ * physical interrupt at the same time.
+ *
+ * Conversely, if the virtual input level is deasserted and the virtual
+ * interrupt is not active, then always clear the hardware active state
+ * to ensure that hardware interrupts from the timer triggers a guest
+ * exit.
+ */
+ if (timer->irq.level || kvm_vgic_map_is_active(vcpu, timer->map))
phys_active = true;
else
phys_active = false;
diff --git a/virt/kvm/arm/vgic-v3.c b/virt/kvm/arm/vgic-v3.c
index 487d635..453eafd 100644
--- a/virt/kvm/arm/vgic-v3.c
+++ b/virt/kvm/arm/vgic-v3.c
@@ -28,6 +28,7 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_arm.h>
+#include <asm/kvm_asm.h>
#include <asm/kvm_mmu.h>
/* These are for GICv2 emulation only */
@@ -36,18 +37,12 @@
#define GICH_LR_PHYSID_CPUID (7UL << GICH_LR_PHYSID_CPUID_SHIFT)
#define ICH_LR_VIRTUALID_MASK (BIT_ULL(32) - 1)
-/*
- * LRs are stored in reverse order in memory. make sure we index them
- * correctly.
- */
-#define LR_INDEX(lr) (VGIC_V3_MAX_LRS - 1 - lr)
-
static u32 ich_vtr_el2;
static struct vgic_lr vgic_v3_get_lr(const struct kvm_vcpu *vcpu, int lr)
{
struct vgic_lr lr_desc;
- u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)];
+ u64 val = vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)];
if (vcpu->kvm->arch.vgic.vgic_model == KVM_DEV_TYPE_ARM_VGIC_V3)
lr_desc.irq = val & ICH_LR_VIRTUALID_MASK;
@@ -111,7 +106,7 @@ static void vgic_v3_set_lr(struct kvm_vcpu *vcpu, int lr,
lr_val |= ((u64)lr_desc.hwirq) << ICH_LR_PHYS_ID_SHIFT;
}
- vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[LR_INDEX(lr)] = lr_val;
+ vcpu->arch.vgic_cpu.vgic_v3.vgic_lr[VGIC_V3_LR_INDEX(lr)] = lr_val;
if (!(lr_desc.state & LR_STATE_MASK))
vcpu->arch.vgic_cpu.vgic_v3.vgic_elrsr |= (1U << lr);
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 5335383..043032c 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -878,7 +878,7 @@ static int vgic_handle_mmio_write(struct kvm_vcpu *vcpu,
true);
}
-struct kvm_io_device_ops vgic_io_ops = {
+static struct kvm_io_device_ops vgic_io_ops = {
.read = vgic_handle_mmio_read,
.write = vgic_handle_mmio_write,
};
@@ -1096,6 +1096,27 @@ static void vgic_retire_lr(int lr_nr, struct kvm_vcpu *vcpu)
vgic_set_lr(vcpu, lr_nr, vlr);
}
+static bool dist_active_irq(struct kvm_vcpu *vcpu)
+{
+ struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
+
+ return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
+}
+
+bool kvm_vgic_map_is_active(struct kvm_vcpu *vcpu, struct irq_phys_map *map)
+{
+ int i;
+
+ for (i = 0; i < vcpu->arch.vgic_cpu.nr_lr; i++) {
+ struct vgic_lr vlr = vgic_get_lr(vcpu, i);
+
+ if (vlr.irq == map->virt_irq && vlr.state & LR_STATE_ACTIVE)
+ return true;
+ }
+
+ return vgic_irq_is_active(vcpu, map->virt_irq);
+}
+
/*
* An interrupt may have been disabled after being made pending on the
* CPU interface (the classic case is a timer running while we're
@@ -1248,7 +1269,7 @@ static void __kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu)
* may have been serviced from another vcpu. In all cases,
* move along.
*/
- if (!kvm_vgic_vcpu_pending_irq(vcpu) && !kvm_vgic_vcpu_active_irq(vcpu))
+ if (!kvm_vgic_vcpu_pending_irq(vcpu) && !dist_active_irq(vcpu))
goto epilog;
/* SGIs */
@@ -1396,25 +1417,13 @@ static bool vgic_process_maintenance(struct kvm_vcpu *vcpu)
static bool vgic_sync_hwirq(struct kvm_vcpu *vcpu, int lr, struct vgic_lr vlr)
{
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
- struct irq_phys_map *map;
- bool phys_active;
bool level_pending;
- int ret;
if (!(vlr.state & LR_HW))
return false;
- map = vgic_irq_map_search(vcpu, vlr.irq);
- BUG_ON(!map);
-
- ret = irq_get_irqchip_state(map->irq,
- IRQCHIP_STATE_ACTIVE,
- &phys_active);
-
- WARN_ON(ret);
-
- if (phys_active)
- return 0;
+ if (vlr.state & LR_STATE_ACTIVE)
+ return false;
spin_lock(&dist->lock);
level_pending = process_queued_irq(vcpu, lr, vlr);
@@ -1479,17 +1488,6 @@ int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu)
return test_bit(vcpu->vcpu_id, dist->irq_pending_on_cpu);
}
-int kvm_vgic_vcpu_active_irq(struct kvm_vcpu *vcpu)
-{
- struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
-
- if (!irqchip_in_kernel(vcpu->kvm))
- return 0;
-
- return test_bit(vcpu->vcpu_id, dist->irq_active_on_cpu);
-}
-
-
void vgic_kick_vcpus(struct kvm *kvm)
{
struct kvm_vcpu *vcpu;
diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c
index 77d42be..3531599 100644
--- a/virt/kvm/async_pf.c
+++ b/virt/kvm/async_pf.c
@@ -57,8 +57,7 @@ int kvm_async_pf_init(void)
void kvm_async_pf_deinit(void)
{
- if (async_pf_cache)
- kmem_cache_destroy(async_pf_cache);
+ kmem_cache_destroy(async_pf_cache);
async_pf_cache = NULL;
}
diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c
index f0b08a2..fe84e1a 100644
--- a/virt/kvm/irqchip.c
+++ b/virt/kvm/irqchip.c
@@ -166,6 +166,10 @@ out:
return r;
}
+void __attribute__((weak)) kvm_arch_irq_routing_update(struct kvm *kvm)
+{
+}
+
int kvm_set_irq_routing(struct kvm *kvm,
const struct kvm_irq_routing_entry *ue,
unsigned nr,
@@ -219,9 +223,10 @@ int kvm_set_irq_routing(struct kvm *kvm,
old = kvm->irq_routing;
rcu_assign_pointer(kvm->irq_routing, new);
kvm_irq_routing_update(kvm);
+ kvm_arch_irq_routing_update(kvm);
mutex_unlock(&kvm->irq_lock);
- kvm_arch_irq_routing_update(kvm);
+ kvm_arch_post_irq_routing_update(kvm);
synchronize_srcu_expedited(&kvm->irq_srcu);
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 484079e..314c777 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -206,16 +206,6 @@ void kvm_reload_remote_mmus(struct kvm *kvm)
kvm_make_all_cpus_request(kvm, KVM_REQ_MMU_RELOAD);
}
-void kvm_make_mclock_inprogress_request(struct kvm *kvm)
-{
- kvm_make_all_cpus_request(kvm, KVM_REQ_MCLOCK_INPROGRESS);
-}
-
-void kvm_make_scan_ioapic_request(struct kvm *kvm)
-{
- kvm_make_all_cpus_request(kvm, KVM_REQ_SCAN_IOAPIC);
-}
-
int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id)
{
struct page *page;
@@ -1164,15 +1154,15 @@ struct kvm_memory_slot *kvm_vcpu_gfn_to_memslot(struct kvm_vcpu *vcpu, gfn_t gfn
return __gfn_to_memslot(kvm_vcpu_memslots(vcpu), gfn);
}
-int kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
+bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn)
{
struct kvm_memory_slot *memslot = gfn_to_memslot(kvm, gfn);
if (!memslot || memslot->id >= KVM_USER_MEM_SLOTS ||
memslot->flags & KVM_MEMSLOT_INVALID)
- return 0;
+ return false;
- return 1;
+ return true;
}
EXPORT_SYMBOL_GPL(kvm_is_visible_gfn);
@@ -2257,7 +2247,7 @@ static int create_vcpu_fd(struct kvm_vcpu *vcpu)
static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
{
int r;
- struct kvm_vcpu *vcpu, *v;
+ struct kvm_vcpu *vcpu;
if (id >= KVM_MAX_VCPUS)
return -EINVAL;
@@ -2281,12 +2271,10 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, u32 id)
r = -EINVAL;
goto unlock_vcpu_destroy;
}
-
- kvm_for_each_vcpu(r, v, kvm)
- if (v->vcpu_id == id) {
- r = -EEXIST;
- goto unlock_vcpu_destroy;
- }
+ if (kvm_get_vcpu_by_id(kvm, id)) {
+ r = -EEXIST;
+ goto unlock_vcpu_destroy;
+ }
BUG_ON(kvm->vcpus[atomic_read(&kvm->online_vcpus)]);
@@ -3449,10 +3437,9 @@ static int kvm_init_debug(void)
goto out;
for (p = debugfs_entries; p->name; ++p) {
- p->dentry = debugfs_create_file(p->name, 0444, kvm_debugfs_dir,
- (void *)(long)p->offset,
- stat_fops[p->kind]);
- if (p->dentry == NULL)
+ if (!debugfs_create_file(p->name, 0444, kvm_debugfs_dir,
+ (void *)(long)p->offset,
+ stat_fops[p->kind]))
goto out_dir;
}
@@ -3464,15 +3451,6 @@ out:
return r;
}
-static void kvm_exit_debug(void)
-{
- struct kvm_stats_debugfs_item *p;
-
- for (p = debugfs_entries; p->name; ++p)
- debugfs_remove(p->dentry);
- debugfs_remove(kvm_debugfs_dir);
-}
-
static int kvm_suspend(void)
{
if (kvm_usage_count)
@@ -3630,7 +3608,7 @@ EXPORT_SYMBOL_GPL(kvm_init);
void kvm_exit(void)
{
- kvm_exit_debug();
+ debugfs_remove_recursive(kvm_debugfs_dir);
misc_deregister(&kvm_dev);
kmem_cache_destroy(kvm_vcpu_cache);
kvm_async_pf_deinit();